This commit is contained in:
2026-09-24 16:25:22 +08:00
commit 7428184f01
1198 changed files with 314515 additions and 0 deletions
+147
View File
@@ -0,0 +1,147 @@
<template>
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="通讯录" @right-click="onSearch">
<template v-slot:right>
<x-icon name="search-line" color="#6B7280" font-size="34rpx"></x-icon>
</template>
<view class="hr-body">
<!-- ============ 分组列表:指挥调度 / 协作医院 / 本队同事 ============ -->
<view v-for="(g, gi) in groups" :key="gi">
<hr-sec :title="g.title" :first="gi == 0"></hr-sec>
<!-- 卡片内每行:左侧头像/机构图标 + 姓名与号码 + 呼叫按钮 -->
<hr-card padding="4rpx 26rpx">
<view v-for="(c, ci) in g.items" :key="ci"
:class="ci == g.items.length - 1 ? 'hr-lrow hr-lrow-last' : 'hr-lrow'" @click="onCall(c)">
<view class="ct-blk" :style="blkStyle(c)">
<!-- 机构(医院 / 协作单位)用图标,个人用姓名首字 -->
<x-icon v-if="!c.useAvatar" name="hospital-line" color="#2563EB"
font-size="30rpx"></x-icon>
<text v-else class="ct-blk-t">{{ blkText(c) }}</text>
</view>
<view class="hr-lmain">
<text class="hr-lmain-b">{{ c.name }}</text>
<text class="hr-lmain-s">{{ c.phone }}</text>
</view>
<x-icon name="phone-fill" color="#2563EB" font-size="32rpx"></x-icon>
</view>
</hr-card>
</view>
<view style="height:14px"></view>
</view>
</hr-page>
</template>
<script lang="uts" setup>
import { contactGroups } from '@/mock/index.uts'
import { HrContact, HrContactGroup } from '@/mock/types.uts'
/**
* s28 通讯录
* 与设计稿一致:按「指挥调度 / 协作医院 / 本队同事」三段分组,
* 每组 = 小节标题 + 卡片列表行(头像 + 姓名 + 号码 + 呼叫)。
* 数据全部来自 mock/index.uts,换接口只改取数处。
*/
const groups : HrContactGroup[] = contactGroups
/** 头像文字:优先用数据里的字母头,缺省回落到姓名首字 */
function blkText(c : HrContact) : string {
if (c.avatar != '') { return c.avatar }
if (c.name.length > 0) { return c.name.substring(0, 1) }
return '医'
}
/**
* 头像底色。uvue 不支持复合类选择器(.ct-blk.ct-blk-gn),
* 因此主题色用内联样式下发;机构块固定浅蓝底。
*/
function blkStyle(c : HrContact) : string {
if (!c.useAvatar) { return 'background-color:#EFF6FF;' }
if (c.theme == 'gn') { return 'background-color:#059669;' }
if (c.theme == 'ag') { return 'background-color:#D97706;' }
if (c.theme == 'rd') { return 'background-color:#DC2626;' }
if (c.theme == 'gy') { return 'background-color:#94A3B8;' }
return 'background-color:#2563EB;'
}
/** 只保留数字字符(0-9 */
function digitsOnly(s : string) : string {
const table = '0123456789'
let out = ''
for (let i = 0; i < s.length; i++) {
const ch = s.charAt(i)
if (table.indexOf(ch) > -1) { out += ch }
}
return out
}
/**
* 从「值班室 8801 · 手机 138****2201」这类文案里取出可拨号码。
* 规则:按「·」分段,取「标签 号码」中的号码部分,
* 纯数字(不含 * 掩码)、长度≥4 才算号码;「工号 1248」这类直接跳过。
*/
function extractPhone(text : string) : string {
const parts = text.split('·')
for (let i = 0; i < parts.length; i++) {
const seg = parts[i].trim()
const idx = seg.indexOf(' ')
const label = idx >= 0 ? seg.substring(0, idx) : ''
const raw = idx >= 0 ? seg.substring(idx + 1) : seg
if (label.indexOf('工号') > -1) { continue }
const digits = digitsOnly(raw)
const compact = raw.replaceAll(' ', '').replaceAll('-', '')
if (digits.length >= 4 && digits.length == compact.length) { return digits }
}
return ''
}
// ⚠ UTS 不提升函数声明:extractPhone / digitsOnly 必须写在 onCall 之前
function onCall(c : HrContact) : void {
const digits = extractPhone(c.phone)
if (digits == '') {
uni.showToast({ title: '暂无可用号码', icon: 'none' })
return
}
uni.showModal({
title: c.name,
content: `呼叫 ${digits}`,
confirmText: '呼叫',
success: (res) => {
if (!res.confirm) { return }
// #ifdef APP
uni.makePhoneCall({ phoneNumber: digits })
// #endif
// #ifndef APP
uni.showToast({ title: '已复制号码 ' + digits, icon: 'none' })
uni.setClipboardData({ data: digits })
// #endif
}
})
}
function onSearch() : void {
uni.showToast({ title: '搜索联系人 / 医院', icon: 'none' })
}
</script>
<style>
/* 头像 / 机构图标块:设计稿 .avt.sm / .lic30~32px */
.ct-blk {
width: 64rpx;
height: 64rpx;
border-radius: 18rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-right: 20rpx;
}
.ct-blk-t {
font-size: 25rpx;
font-weight: bold;
color: #FFFFFF;
}
</style>