const API = require('../../utils/api.js') // 由 YYYY-MM-DD 生日换算周岁。 // 后端只下发到「日」、不含时分秒——公示场景要的是"多大",不是哪一天生的。 // 生日缺失 / 非法 / 算出不合常理(负数或 >120),一律返回 0,模板按 0 隐藏该项 function calcAge(birthday) { if (!birthday) { return 0 } // 把 '-' 换成 '/' 再解析:小程序 iOS 对 'YYYY-MM-DD HH:mm:ss' 这类格式 // 会得到 Invalid Date,'/' 分隔是各端都稳的写法 const birth = new Date(String(birthday).replace(/-/g, '/')) if (Number.isNaN(birth.getTime())) { return 0 } const today = new Date() let age = today.getFullYear() - birth.getFullYear() // 今年生日还没到,减一岁 const monthDiff = today.getMonth() - birth.getMonth() if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) { age -= 1 } // 上限 120 是给运营手抖填错年份兜底,否则页面上会出现"年龄 226 岁" if (!Number.isFinite(age) || age < 0 || age > 120) { return 0 } return age } // 陪诊师详情:数据来自后端公开接口 /health/attendant/:id // 与列表页是同一份白名单数据(不含手机号 / 身份证号 / 证书编号原文), // 差别在于详情页按 GB/T 47801—2026 4.2.1.5 把公示项补全: // 不截断擅长场景,并额外展示个人简介、健康证明有效期、培训记录与过往服务评价 // (培训记录是数组、评价要多一次聚合查询,所以只在详情里带) Page({ data: { loading: true, // null 表示查不到(ID 非法、已离职或已下架),模板据此渲染空态 attendant: null, specialtyTags: [], trainings: [], areaText: '', langText: '' }, onLoad(options) { const id = options.id if (!id) { this.setData({ loading: false }) return } this.loadAttendant(id) }, loadAttendant(id) { API.escort.getAttendantById(id) .then((res) => { const item = res.code === 0 && res.data && res.data.attendant if (!item) { this.setData({ loading: false }) return } const name = item.name || '' const healthCertificate = item.healthCertificate || {} const review = item.review || {} // 健康证明按国标只公示「有效期」,文案分有效 / 已过期两种; // 运营没登到期日就整行不显示(不给"有效"的默认结论) let healthCertificateText = '' if (healthCertificate.expireDate) { healthCertificateText = healthCertificate.valid ? `有效期内(至 ${healthCertificate.expireDate})` : `已过期(${healthCertificate.expireDate})` } const attendant = { id: item.id, name, avatar: item.avatar || '', // 头像兜底用的首字:姓名已脱敏为「姓 + 陪诊师」,取第一个字即可 initial: name.slice(0, 1), // 后端 sex 为空串表示未登记,模板据此隐藏该行 sexText: item.sex === 'male' ? '男' : item.sex === 'female' ? '女' : '', // 周岁由本页现算,未登记生日时为 0,模板据 0 隐藏该行 age: calcAge(item.birthday), workYears: item.workYears || 0, orderCount: item.orderCount || 0, qualificationVerified: !!item.qualificationVerified, healthCertificateText, introduction: item.introduction || '', reviewCount: review.count || 0, // 评价条数未达后端阈值时 score 为 null,模板据此显示"暂不显示评分" reviewScore: typeof review.score === 'number' ? review.score : null } this.setData({ loading: false, attendant, // 详情页展示全部擅长场景,不再像列表页截断到 3 个 specialtyTags: item.specialties || [], trainings: item.trainings || [], // 数组在 WXML 里不能直接拼展示,这里先转成文本 areaText: (item.serviceAreas || []).join(' / '), langText: (item.languages || []).join(' / ') }) // 标题用脱敏名,比「陪诊师详情」更有信息量 if (name) { wx.setNavigationBarTitle({ title: name }) } }) .catch((err) => { console.log('获取陪诊师详情失败', err) this.setData({ loading: false }) }) }, onShareAppMessage() { const { attendant } = this.data if (!attendant) { return { title: '暖橙陪诊 · 陪诊师团队', path: '/pages/attendant/attendantlist' } } return { title: `暖橙陪诊 · ${attendant.name}`, path: `/pages/attendant/attendantdetail?id=${attendant.id}` } }, // 朋友圈只能分享当前页,陪诊师 id 只能靠 query 带上; // 详情还没回来(attendant 为 null)时不带 query,好友打开是列表页口径的空态 onShareTimeline() { const { attendant } = this.data if (!attendant) { return { title: '暖橙陪诊 · 陪诊师团队' } } return { title: `暖橙陪诊 · ${attendant.name}`, query: `id=${attendant.id}` } } })