diff --git a/handler/employee.js b/handler/employee.js new file mode 100644 index 0000000..de31ba4 --- /dev/null +++ b/handler/employee.js @@ -0,0 +1,76 @@ +import { DBModel } from "../models/index.js"; +import ResponseUtil from "../utils/responseUtil.js"; + +/** + * 陪诊师公示:面向 C 端患者的公开信息展示 + * + * 依据 GB/T 47801—2026 4.2.1.5「陪同人员信息公示机制」组织字段: + * 基本信息 —— 培训记录、服务年限、累计服务次数 + * 专业技能 —— 擅长服务场景、特殊技能(语言) + * + * 两条红线: + * 1. 白名单式输出,绝不返回手机号 / 身份证号 / 证书编号原文; + * 「资质已核验」只对外给布尔值,不给编号 + * 2. 不输出评分。attendantInfo.rating 是默认 5.0 的裸值, + * 后端尚无评价数据来源,公示它等于无依据背书 + */ +class HandlerEmployee { + // 姓名脱敏:只留姓 + 「陪诊师」,不给全名,降低私下联系(跳单)的可能 + static maskName(name) { + const trimmed = String(name || "").trim(); + if (!trimmed) return "陪诊师"; + return trimmed.slice(0, 1) + "陪诊师"; + } + + // 白名单式脱敏:逐字段挑选,避免 employee 文档整体外泄 + static toPublicAttendant(employee) { + const profile = employee.profile || {}; + const work = employee.work || {}; + const info = employee.attendantInfo || {}; + + return { + id: employee._id, + name: HandlerEmployee.maskName(profile.name), + avatar: profile.avatar || "", + sex: profile.sex || "", + workYears: work.workYears || 0, + qualificationVerified: !!work.qualification, + specialties: info.specialties || [], + serviceAreas: info.serviceAreas || [], + languages: info.languages || [], + orderCount: info.orderCount || 0, + introduction: employee.introduction || "", + }; + } + + // 公开的陪诊师列表。 + // 与 /service、/agreement 等公示类资源一致,不加 requireAuth—— + // 公示信息本身不敏感,且避免登录态异常导致页面空白 + async getAttendants(ctx) { + try { + const page = parseInt(ctx.request.query.page) || 1; + const pageSize = parseInt(ctx.request.query.pageSize) || 50; + + // 只取在职陪诊员。 + // 排序不按 attendantInfo.rating(无可信来源),改按服务年限 / 累计接单数 + const list = await DBModel.Employee.find({ + role: "attendant", + status: "active", + }) + .sort({ "work.workYears": -1, "attendantInfo.orderCount": -1 }) + .skip((page - 1) * pageSize) + .limit(pageSize) + .exec(); + + return ResponseUtil.success( + ctx, + { attendants: list.map(HandlerEmployee.toPublicAttendant) }, + "查询成功" + ); + } catch (err) { + return ResponseUtil.internalError(ctx, err.message); + } + } +} + +export { HandlerEmployee }; \ No newline at end of file diff --git a/handler/health_profile.js b/handler/health_profile.js index 1fef5b7..0d67499 100644 --- a/handler/health_profile.js +++ b/handler/health_profile.js @@ -40,6 +40,114 @@ class HandlerHealthProfile { } } + // 查询"我的"健康档案列表:强制以登录用户身份查询,忽略请求中的 userId + async getMyProfiles(ctx) { + try { + const { page = 1, pageSize = 20, name, mobile, sortBy } = ctx.request.query; + const userId = ctx.state.user?._id; + + const result = await DBModel.HealthProfile.findProfiles({ + page: parseInt(page), + pageSize: parseInt(pageSize), + userId, + name, + mobile, + sortBy, + }); + + return ResponseUtil.success(ctx, result, "查询成功"); + } catch (err) { + return ResponseUtil.internalError(ctx, err.message); + } + } + + // 查询"我的"单个健康档案:非本人档案一律按不存在处理 + async getMyProfileById(ctx) { + try { + const { id } = ctx.params; + if (!id) { + return ResponseUtil.badRequest(ctx, "缺少档案ID"); + } + + const profile = await HandlerHealthProfile.findOwnProfile(ctx, id); + if (!profile) { + return ResponseUtil.notFound(ctx, "健康档案不存在"); + } + + return ResponseUtil.success(ctx, { profile }, "查询成功"); + } catch (err) { + return ResponseUtil.internalError(ctx, err.message); + } + } + + // 新增"我的"健康档案:userId 以 token 为准,避免写到他人名下 + async createMyProfile(ctx) { + try { + const body = HandlerHealthProfile.pickFields(ctx.request.body); + body.userId = ctx.state.user?._id; + + const newProfile = await DBModel.HealthProfile.createProfile(body); + return ResponseUtil.success(ctx, { profile: newProfile }, "创建成功"); + } catch (err) { + return ResponseUtil.internalError(ctx, err.message); + } + } + + // 更新"我的"健康档案:先校验归属,再更新 + // 注意:入参使用 "profile.name" 这类点号路径, + // 因为 schema 在更新姓名时会额外写入 "profile.pinyin",与整体替换 profile 对象会冲突 + async updateMyProfile(ctx) { + try { + const { id } = ctx.params; + if (!id) { + return ResponseUtil.badRequest(ctx, "缺少档案ID"); + } + + const profile = await HandlerHealthProfile.findOwnProfile(ctx, id); + if (!profile) { + return ResponseUtil.notFound(ctx, "健康档案不存在"); + } + + const update = HandlerHealthProfile.pickFields(ctx.request.body); + delete update.userId; // 不允许通过请求转移档案归属 + + const updatedProfile = await DBModel.HealthProfile.updateProfileById(id, update); + return ResponseUtil.success(ctx, { profile: updatedProfile }, "更新成功"); + } catch (err) { + return ResponseUtil.internalError(ctx, err.message); + } + } + + // 删除"我的"健康档案:先校验归属,再删除 + async deleteMyProfile(ctx) { + try { + const { id } = ctx.params; + if (!id) { + return ResponseUtil.badRequest(ctx, "缺少档案ID"); + } + + const profile = await HandlerHealthProfile.findOwnProfile(ctx, id); + if (!profile) { + return ResponseUtil.notFound(ctx, "健康档案不存在"); + } + + await DBModel.HealthProfile.deleteProfileById(id); + return ResponseUtil.success(ctx, { profile }, "删除成功"); + } catch (err) { + return ResponseUtil.internalError(ctx, err.message); + } + } + + // 按 id 查找档案并校验归属,非本人档案返回 null + static async findOwnProfile(ctx, id) { + const profile = await DBModel.HealthProfile.findProfileById(id); + const userId = ctx.state.user?._id; + if (!profile || String(profile.userId) !== String(userId)) { + return null; + } + return profile; + } + async getProfileById(ctx) { try { const { id } = ctx.params; diff --git a/resource/agreement.js b/resource/agreement.js index 09c4fcc..586d5cb 100644 --- a/resource/agreement.js +++ b/resource/agreement.js @@ -37,7 +37,7 @@ const agreement = { title: "服务范围", type: "list", items: [ - "包含:诊前问询、提醒、建档取号、代缴费用、排队候诊、问诊沟通、代取药品、解读医嘱、回寄物品。", + "包含:诊前问询、提醒、建档取号、代缴费用、排队候诊、问诊沟通、代取药品、记录并转达医嘱、回寄物品。", "不包含:急诊就医、插队加号、医院陪护、急诊留观陪护。" ] }, diff --git a/resource/services.js b/resource/services.js index 3299d3d..d4a796e 100644 --- a/resource/services.js +++ b/resource/services.js @@ -2,76 +2,88 @@ const services = [ { id: 1, title: '全天陪诊', - subtitle: '八小时服务/次,专业陪诊师全程陪同', + // 时段用「—」+「、」:括号内不断句,读起来是一个整体;列表页说明句按原文整段展示 + subtitle: '八小时服务/次(早8点—中午12点、下午1点—晚上5点),专业陪诊师全程陪同就医。', price: '500.00', image: '/images/pz1.jpg', icon: 'user-business', tag: '', - description: '全天陪诊服务提供8小时的专业陪诊服务,陪诊师将全程陪同您完成就医流程。包括挂号、候诊、就诊、检查、取药等环节的协助与引导。我们的陪诊师均经过专业培训,熟悉各大医院流程,能够有效缩短就医时间,提升就医体验。', + // 只讲服务对象,不重复 subtitle 已写的时长与陪同方式(详情页两段紧挨着显示) + // 三类人群对应 GB/T 47801—2026 3.3 服务对象的「行动、认知、地域差异」三种成因; + // 原「需要专业指导」会被读成医疗指导,触及 8.2「不应提供医疗建议」 + description: '主要服务行动不便、认知或沟通不便、异地就医不熟悉医院的用户。就诊项目较多、耗时长的情况,建议选择本服务。', flow: [{ - title: '在线预约', - desc: '选择服务类型,填写就诊信息,提交订单' + title: '预约', + desc: '在线预约、电话预约、微信预约。电话或微信见联系我们页面' }, { - title: '电话确认', - desc: '客服人员将在30分钟内与您电话确认订单详情' - }, - { - title: '分配陪诊师', - desc: '根据您的就诊医院和时间,匹配专业陪诊师' + // 9.3.1.1 服务前应确认家属陪同、行动能力与特殊需求、服务人员信息、应急联系人 + // 科室限定「由您确定」,避免被读成 8.2 第4条「代替服务对象选择治疗方案」 + title: '沟通信息', + desc: '与陪诊师确认就诊医院、就诊时间、就诊人信息、行动能力与特殊需求' }, { title: '支付费用', desc: '通过微信支付服务费用' }, { - title: '医院集合', - desc: '陪诊师按约定时间在医院指定地点与您会合' + title: '准备资料', + desc: '根据您要陪诊的项目,准备必要的资料,如身份证、就诊卡、检查报告、问诊诉求等' }, { title: '全程陪诊', desc: '陪诊师协助完成挂号、就诊、检查、取药等流程' }, { + // 9.3.3 服务后:清点材料并逐项签收(9.3.3.1)、告知后续材料领取方式(9.3.3.2)、 + // 提醒遵医嘱(9.3.3.3)、对服务过程作记录和总结(9.3.3.4) title: '服务完成', - desc: '确认服务完成,可对陪诊师进行评价' + desc: '清点病历、检查报告、药品等材料,确认本次就诊所有项目已完成。提醒后续就诊时间、注意事项与医嘱。' } ], notices: [ - '服务时长为8小时,超出时间按每小时50元计费', + '服务时长为8小时,超出时间按每小时80元计费', '请提前1天预约', - '如需取消订单,请提前联系客服', - '服务不包含挂号费、检查费、药费等医疗费用', + // 9.1.1 应提供服务变更手续,故「改期」与「取消」合并为一条 + '如需改期或取消订单,请提前联系客服', + '服务费不包含挂号费、检查费、药费等医疗费用', + // 8.2 不应签署具有法律效力的医疗文书:陪同现场最容易被要求「帮忙签个字」, + // 尤其患者是老人或家属不在场时,所以把边界写死,不留解释空间 + '具有法律效力的医疗文书(手术、麻醉、特殊检查知情同意书等)需您本人或家属签署,陪诊师不代签', + // 9.1.1 与 9.2.3 要求告知投诉渠道 + '如对服务有疑问或建议,可在「联系我们」页面反馈' ] }, { id: 2, title: '半天陪诊', - subtitle: '四小时服务/次,适合简单就诊', + // 时段写成「上午8点—中午12点 或 下午1点—晚上5点」:一是与 id 1 全天陪诊的两个半天完全对齐 + // (全天 8 小时就是这两段之和);二是「不包含夜间」由时段本身说清,不必反向声明。 + // 列表页说明句直接放这段 subtitle 原文(会折两行,属预期) + subtitle: '四小时服务/次(上午8点—中午12点 或 下午1点—晚上5点),专业陪诊师全程陪同就医。', price: '300.00', image: '/images/pz1.jpg', icon: 'usergroup', tag: '热门', - description: '半天陪诊服务提供4小时的专业陪诊服务,适合就诊流程相对简单的客户。陪诊师将协助您完成挂号、就诊、简单检查及取药等环节,让您的就医过程更加顺畅。', + // 服务对象句与 id 1 一致(同属陪同就医,对象成因相同);首句用「项目较少、半天内完成」 + // 与 id 1 的「项目较多、耗时长」形成对照,避免两个详情页读起来没有区分度 + description: '适合就诊项目较少、预计半天内能完成的情况。主要服务行动不便、认知或沟通不便、异地就医不熟悉医院的用户。', + // 流程与 id 1 逐字相同,国标条目注释只在 id 1 保留一处,避免两处维护同一段说明 flow: [{ - title: '在线预约', - desc: '选择服务类型,填写就诊信息,提交订单' + title: '预约', + desc: '在线预约、电话预约、微信预约。电话或微信见联系我们页面' }, { - title: '电话确认', - desc: '客服人员将在30分钟内与您电话确认订单详情' - }, - { - title: '分配陪诊师', - desc: '根据您的就诊医院和时间,匹配专业陪诊师' + title: '沟通信息', + desc: '与陪诊师确认就诊医院、就诊时间、就诊人信息、行动能力与特殊需求' }, { title: '支付费用', desc: '通过微信支付服务费用' }, { - title: '医院集合', - desc: '陪诊师按约定时间在医院指定地点与您会合' + title: '准备资料', + desc: '根据您要陪诊的项目,准备必要的资料,如身份证、就诊卡、检查报告、问诊诉求等' }, { title: '全程陪诊', @@ -79,59 +91,92 @@ const services = [ }, { title: '服务完成', - desc: '确认服务完成,可对陪诊师进行评价' + desc: '清点病历、检查报告、药品等材料,确认本次就诊所有项目已完成。提醒后续就诊时间、注意事项与医嘱。' } ], notices: [ - '服务时长为4小时,超出时间按每小时50元计费', - '请提前1天预约,紧急订单需额外支付加急费', - '如需取消订单,请提前4小时联系客服', - '服务不包含挂号费、检查费、药费等医疗费用' + // 全站超时统一 80 元/h(原 50 元/h);本项自身均价 300/4h=75 元/h,超时单价略高于均价 + '服务时长为4小时,超出时间按每小时80元计费', + // 原「紧急订单需额外支付加急费」只有收费名目没有金额,4.2.4.2 要求收费标准须公示, + // 故不公示未定金额,改为指向客服确认 + '请提前1天预约,紧急订单请联系客服确认', + // 9.1.1 应提供服务变更手续,与 id 1 同样把「改期」并入取消一条 + '如需改期或取消订单,请提前4小时联系客服', + '服务费不包含挂号费、检查费、药费等医疗费用', + // 8.2 同 id 1:法律效力医疗文书不代签,注释只在 id 1 保留一份 + '具有法律效力的医疗文书(手术、麻醉、特殊检查知情同意书等)需您本人或家属签署,陪诊师不代签', + // 9.1.1 与 9.2.3 要求告知投诉渠道 + '如对服务有疑问或建议,可在「联系我们」页面反馈' ] }, { id: 3, + // 患者不到场的场景。国标里没有「代问诊」这个动作,最接近的是 7.1.4「协助医患沟通」 + // 与 8.1「记录医嘱」,所以动作词一律落在「陈述病情、转达诉求、记录医嘱、转达医嘱」上。 + // 原「详细记录医生的诊断意见和用药建议」会被读成 8.2「判读检查结果、提供医疗建议」, + // 且与本项 notices 里「不提供医疗建议」自相矛盾,故统一为「如实记录医嘱并转达」 title: '代问诊', - subtitle: '代您到医院与医生进行问诊', - price: '260.00', + // 补「记录并转达」这一对动作,与 description、flow 同一口径 + subtitle: '陪诊师代您向医生陈述病情、记录并转达医嘱,无需亲自到场。', + price: '280.00', image: '/images/wz1.jpg', icon: 'heart', tag: '', - description: '代问诊服务适用于无法亲自到医院的客户。我们的陪诊师将携带您的病历资料,代您与医生进行面诊,详细记录医生的诊断意见和用药建议,并及时反馈给您。', + // 4.2.2.2 收集与使用服务对象信息须经授权同意,本项全程由他人代为出行,前提必须写明; + // 末句对应 8.2 第 4 条「不应代替服务对象或其家属选择或同意治疗方案」 + description: '代问诊服务适用于无法亲自到医院的用户。经您同意并授权后,陪诊师携带您的病历资料,代您向医生陈述病情、转达就诊诉求,如实记录医嘱并完整转达给您。涉及检查、用药与治疗方案的选择,由医生直接与您或家人沟通,陪诊师不代为决定。', flow: [{ - title: '在线预约', - desc: '选择代问诊服务,填写就诊信息和病史' + title: '预约', + desc: '在线预约、电话预约、微信预约。电话或微信见联系我们页面' }, { - title: '资料准备', - desc: '将病历、检查报告等资料拍照上传或快递给陪诊师' - }, - { - title: '电话确认', - desc: '客服确认资料完整性和就诊需求' + title: '沟通信息', + desc: '与陪诊师确认就诊医院、就诊时间、就诊人信息、行动能力与特殊需求' }, { title: '支付费用', desc: '通过微信支付服务费用' }, { + title: '准备资料', + desc: '根据您要陪诊的项目,准备必要的资料,如身份证、就诊卡、检查报告、问诊诉求等' + }, + { + // 8.1「记录医嘱」+ 8.2 不得选择性传递:写明「如实、完整」; + // 「需要时」替代原「可能随时」——是否需电话由就诊现场决定,不是随时打扰 title: '代问诊', - desc: '陪诊师携带资料到医院代您问诊' + desc: '陪诊师携带您的病历资料,代您向医生陈述病情、转达就诊诉求,如实记录医嘱并完整转达给您。需要时,可安排您与医生电话沟通。' }, { - title: '结果反馈', - desc: '陪诊师将医生诊断意见和用药建议详细反馈给您' + // 不新造「单独的取药费用」这类未公示费项(9.1.1 收费须公示、9.2.5 额外费用须事先说明), + // 改为指向已有服务:检查走「检查预约」(id 4),取药走「取药快递」(id 8),费用以对应服务页为准 + title: '后续事项', + desc: '如医生开具检查,可另行预约「检查预约」服务办理;如需取药,可另行预约「取药快递」服务代取并邮寄。相关费用以对应服务页面为准。' }, { + // 9.3.3 服务后:清点材料并逐项签收(9.3.3.1)、提醒遵医嘱(9.3.3.3) title: '服务完成', - desc: '确认服务完成,可对陪诊师进行评价' + desc: '清点病历、检查报告、药品等材料,确认本次就诊所有项目已完成。提醒后续就诊时间、注意事项与医嘱。' } ], notices: [ + '请提前1天预约', + // 8.1 开头与 4.2.2.2:代为沟通的前提是本人授权同意 + '需经您同意并授权后,陪诊师方可代您与医生沟通', '请确保提供的病历资料真实完整', - '代问诊不包含挂号费和药费', + // 8.2 第 4 条:不代做治疗决定;与 description、flow 同一口径 + '陪诊师仅如实记录并转达医嘱,不提供医疗建议,也不代为选择检查、用药或治疗方案', + // 8.2 不应签署具有法律效力的医疗文书。本项患者不到场,代签风险最大, + // 故除「不代签」外再给出动作:现场要求签字时先联系您本人,由您或家属决定 + '具有法律效力的医疗文书(知情同意书等)需您本人或家属签署;现场要求签字时,陪诊师会先联系您,不代为签署', '部分医院可能要求患者本人到场,请提前确认', - '陪诊师会详细记录医嘱,但不提供医疗建议' + '能否与医生电话沟通以就诊现场安排为准;如无法沟通,陪诊师会完整记录医嘱并转达给您', + // 句式与 id 1/2 统一 + '服务费不包含挂号费、检查费、药费等医疗费用', + // 9.1.1 应提供服务变更手续 + '如需改期或取消订单,请提前联系客服', + // 9.1.1 与 9.2.3 要求告知投诉渠道 + '如对服务有疑问或建议,可在「联系我们」页面反馈' ] }, { @@ -142,161 +187,220 @@ const services = [ image: '/images/qbg1.jpg', icon: 'chart-bar', tag: '', - description: '检查预约服务帮助您预约各类医学检查,包括核磁共振(MRI)、CT、彩超、胃镜等。我们熟悉各大医院的预约流程,能够帮您快速预约到合适的检查时间,避免长时间等待。', + // 去「我们」(全站统一用「陪诊师」),并补服务对象句,结构对齐 id 1/2/7; + // 原名「核磁共振(MRI)」与副标题的「磁共振」是同一项检查的两个名字,统一为「磁共振(MRI)」; + // 原文首句「检查预约服务帮助您预约…」是把标题复述一遍,改为直接说可约项目 + description: '主要服务不便多次往返医院或异地就医的用户。可预约磁共振(MRI)、CT、彩超、胃镜等各类医学检查,大部分医院的这些检查开单当天排不上号,陪诊师会为您预约到合适的检查时间,避免长时间等待。', + // 这项只做一件事:按医生开的单子代约一个检查时间,所以流程比 id 1 全程陪诊还短。 + // 原 7 步(在线预约/资料审核/支付费用/预约办理/确认通知/现场协助/服务完成)里有三处冗余: + // 「资料审核」就是「沟通信息」要交的资料;「确认通知」是「预约办理」的后半截; + // 「现场协助」是转卖别的服务,不属于本项流程,移到 notices + // 全站统一称「陪诊师」:id 1/2/3/7 原本就这么写,id 4/5/6/8 原文写「工作人员」, + // 同一角色两个称呼指同一个人,已全部统一(含 id 8 的 description 与 flow) flow: [{ - title: '在线预约', - desc: '选择检查预约服务,填写检查类型和期望时间' + title: '预约', + desc: '在线预约、电话预约、微信预约。电话或微信见联系我们页面' }, { - title: '资料审核', - desc: '上传医生开具的检查申请单' + // 这一步只干一件事:把检查申请单拿到手——已有单就上传,没有就先挂号、再去找医生开单。 + // 「行动能力与特殊需求」是陪同类服务的项,代办预约不涉及,故删。 + // 「请先挂号」由您自己完成(挂号含选科选医,属 8.2 第4条红线),陪诊师只做挂号之后的陪同开单; + // 检查项目由医生根据病情确定,陪诊师不代为选择 + title: '沟通信息', + desc: '与陪诊师确认就诊医院、就诊人信息、检查项目与期望时间,并上传医生开具的检查申请单。尚未开单的,请您先挂号,由陪诊师协助您找医生开具检查申请单。' }, { title: '支付费用', desc: '通过微信支付服务费用' }, { + // 原「预约办理」+「确认通知」合为一步 title: '预约办理', - desc: '工作人员代为联系医院预约检查时间' - }, - { - title: '确认通知', - desc: '将预约成功的具体时间通知您' - }, - { - title: '现场协助', - desc: '如需,可额外购买陪诊服务协助检查' + desc: '陪诊师代为联系医院预约检查时间,并把预约到的具体时间通知您' }, { + // 原话「确认服务完成」是复述标题的空话,改成交代检查前准备才有内容 title: '服务完成', - desc: '确认服务完成' + desc: '确认预约结果已通知到您,并交代该项检查的注意事项与准备要求。' } ], notices: [ - '需要提供医生开具的检查申请单', + '请提前1天预约', + // 与流程第 2 步同口径:不是"必须先有单"——没有现成的单也能办,前提是您先挂号 + '检查申请单需由医生开具,尚未开单的请先挂号,由陪诊师协助您找医生开单', '部分检查项目有特殊的身体准备要求,请提前了解', - '预约成功后如需改期,请提前24小时联系', - '服务费用不包含检查费用' + // 8.2 不应签署具有法律效力的医疗文书:增强检查、胃镜等检查本身要签知情同意书, + // 本项只代约时间,签字环节仍需本人或家属到场 + '具有法律效力的医疗文书(检查知情同意书等)需您本人或家属签署,陪诊师不代签', + // 原流程里「现场协助:如需,可额外购买陪诊服务协助检查」移到此处: + // 它是另一项服务的入口,不是本项流程的一环;写明具体服务名,避免浮现未公示的「陪诊服务」费项 + '检查当天如需有人陪同,可另行预约「半天陪诊」或「全天陪诊」服务', + // 9.1.1 应提供服务变更手续,与 id 1/2/3/5 统一为「改期或取消」(原只写改期、未提客服) + '如需改期或取消订单,请提前24小时联系客服', + // 流程里出现「挂号」后,排除项必须带上挂号费,否则会被读成 200 元含挂号 + '服务费不包含挂号费、检查费用,相关费用请在就诊医院现场缴纳', + // 9.1.1 与 9.2.3 要求告知投诉渠道 + '如对服务有疑问或建议,可在「联系我们」页面反馈' ] }, { id: 5, + // 代办类:只跑手续,不参与诊疗决策。8.2 禁止「签署具有法律效力的医疗文书」, + // 故入院登记、知情同意书等一律写明需本人或家属签署,陪诊师不代签 title: '出入院代办', - subtitle: '出入院手续代办', - price: '280.00', + // 原「出入院手续代办」比标题只多两个字,等于把标题复读一遍;按 id 1/2/4 的做法, + // 副标题要给出标题没有的信息,这里给的是「代办事项清单」 + subtitle: '入院登记、医保手续、出院结算,均可代为办理', + price: '300.00', image: '/images/yy.jpg', icon: 'user-checked', tag: '', - description: '出入院代办服务帮助您办理医院的入院和出院手续。包括床位预约、入院登记、医保手续办理、出院结算等,让您或家人能够更专注于治疗本身。', + // 4.2.2.2 办理出入院要收集身份证、医保卡信息,须经授权同意;首句补服务对象, + // 与 id 1/2/3/4 一致;原末句「让您或家人能够更专注于治疗本身」是宣传腔,删 + description: '经您授权同意后,陪诊师代您办理入院登记、医保手续、出院结算等出入院手续。', + // 步骤名与顺序对齐 id 1/2/3(预约 → 沟通信息 → 支付费用 → 准备资料 → 服务动作 → 服务完成); + // 原 7 步里的「结果反馈」与「服务完成:确认服务完成」是同一件事的两头,合为一步 flow: [{ - title: '在线预约', - desc: '选择出入院代办服务,填写相关信息' + title: '预约', + desc: '在线预约、电话预约、微信预约。电话或微信见联系我们页面' }, { - title: '资料准备', - desc: '准备身份证、医保卡、押金等相关资料' - }, - { - title: '电话确认', - desc: '客服确认代办事项和所需资料' + // 原名「电话确认」,与 id 1-4 的「沟通信息」是同一件事,统一命名; + // 执行人由「客服」改为「陪诊师」——服务执行人一律用陪诊师,客服只管订单变更与投诉 + title: '沟通信息', + desc: '与陪诊师确认入院或出院、就诊医院与科室、代办事项和所需资料' }, { title: '支付费用', desc: '通过微信支付服务费用' }, { + // 原「准备身份证、医保卡、押金等相关资料」把押金当成资料;押金是钱,不是材料 + title: '准备资料', + desc: '准备身份证、医保卡等证件,并按医院要求备好住院押金' + }, + { + // 与 notices 的「不代签法律效力文书」同口径,在流程里再说一次,避免只看流程的用户漏掉 title: '代办服务', - desc: '工作人员代为办理出入院手续' - }, - { - title: '结果反馈', - desc: '将办理结果和相关单据反馈给您' + desc: '陪诊师代为办理入院登记、医保手续、出院结算等手续;需您本人或家属签署的文书不代签' }, { + // 原「结果反馈」+「服务完成(空话)」合为一步,并交代交付物,才对得起一个收尾步骤 title: '服务完成', - desc: '确认服务完成' + desc: '将办理结果、出院小结及相关单据交付给您,确认本次代办完成。' } ], notices: [ - '需要提供患者身份证、医保卡等证件', - '入院代办需提前了解医院床位情况', - '服务费用不包含住院押金和医疗费用', - '部分手续可能需要患者本人签字' + '请提前1天预约', + // 4.2.2.2 授权同意 + '需经您授权同意后,陪诊师方可代您办理出入院手续', + '请提供患者身份证、医保卡等证件', + '入院代办需提前确认医院床位情况', + // 句式与 id 1/2/3 统一,并把钱交给谁写清 + '服务费不包含住院押金和医疗费用,押金与住院费请在医院缴纳', + // 8.2:具有法律效力的医疗文书不代签;比原「部分手续可能需要患者本人签字」说死了边界 + '具有法律效力的医疗文书(如入院登记、知情同意书等)需您本人或家属签署,陪诊师不代签', + // 9.1.1 应提供服务变更手续 + '如需改期或取消订单,请提前联系客服', + // 9.1.1 与 9.2.3 要求告知投诉渠道 + '如对服务有疑问或建议,可在「联系我们」页面反馈' ] }, { id: 6, title: '跑腿服务', - subtitle: '送资料/代排队/买药/取报告等一小时陪诊服务', + // 原文「…等一小时陪诊服务」把跑腿说成陪诊,与列表页把它归入「就医代办」组自相矛盾; + // 本项是按次计时的代办,故直接写出时长「2小时/次」(列表页规格签同步改为 2小时/次) + subtitle: '送资料/代排队/买药/取报告等,2小时/次', price: '160.00', image: '/images/pt.jpg', icon: 'usergroup', tag: '', - description: '跑腿服务提供各类医院相关代办事项,包括代排队、代买药、代取报告、代送标本等。适合工作繁忙或行动不便的客户,让您足不出户即可完成医院相关事务。', + // 称谓由「客户」改为「用户」,与 id 1-5/7/8 统一;补服务对象句,结构对齐 id 1/2/7; + // 原末句「让您足不出户即可完成医院相关事务」是宣传腔,且与首句同义,删 + description: '主要服务工作繁忙不便请假、或行动不便的用户。可代办代排队、代买药、代取报告、代送标本等医院相关事项,本人不必到场。', + // 步骤名与 id 1-8 对齐:「在线预约」→「预约」、「电话确认」→「沟通信息」、 + // 「材料交接」→「准备资料」(原顺序本身正确,只改名); + // 执行人由「客服」改为「陪诊师」——服务执行人一律用陪诊师,客服只管订单变更与投诉 flow: [{ - title: '在线预约', - desc: '选择跑腿服务,填写具体代办事项' + title: '预约', + desc: '在线预约、电话预约、微信预约。电话或微信见联系我们页面' }, { - title: '电话确认', - desc: '客服确认代办细节和所需材料' + title: '沟通信息', + desc: '与陪诊师确认代办事项、办理地点与所需材料' }, { title: '支付费用', desc: '通过微信支付服务费用' }, { - title: '材料交接', + title: '准备资料', desc: '通过快递或约定地点交接所需材料' }, { title: '代办服务', - desc: '工作人员按约定完成代办事项' + desc: '陪诊师按约定完成代办事项' }, { title: '结果交付', - desc: '将办理结果通过快递或约定方式交付' + desc: '将办理结果或代取物品通过快递或约定方式交付给您' }, { + // 原话「确认服务完成」是复述标题的空话,按 9.3.3 交代签收与后续 title: '服务完成', - desc: '确认服务完成' + desc: '您收到材料或结果后请及时核对,确认无误即服务完成;如有疑问可联系陪诊师处理。' } ], notices: [ + '请提前1天预约', + // 4.2.2.2:代办要用到您的证件与材料,前提是授权同意,与 id 3/5/8 同口径 + '需经您同意并授权后,陪诊师方可持您的证件和材料代您办理', '请详细说明代办事项和特殊要求', '需要提供办理所需的相关证件和材料', - '服务时长为1小时,超出按每小时50元计费', - '服务费用不包含药品费、检查费等费用' + // 时长由 1 小时改为 2 小时,与副标题一致;本项自身均价 160/2h=80 元/h,与超时单价齐平 + '服务时长为2小时,超出时间按每小时80元计费', + // 句式与 id 1-8 统一(原「服务费用不包含…」) + '服务费不包含药品费、检查费等医疗费用', + // 9.1.1 应提供服务变更手续 + '如需改期或取消订单,请提前联系客服', + // 9.1.1 与 9.2.3 要求告知投诉渠道 + '如对服务有疑问或建议,可在「联系我们」页面反馈' ] }, { id: 7, - title: 'VIP 5次 半天陪诊', - subtitle: '五次半天陪诊服务,每次四小时,更优惠', - price: '1350.00', + title: '夜间陪诊', + subtitle: '四小时服务/次,夜间时段专业陪同', + price: '500.00', image: '/images/pz1.jpg', - icon: 'usergroup', - tag: '优惠套餐', - description: '5次半天陪诊套餐为您提供5次、每次4小时的专业陪诊服务,适合需要长期或多次就诊的客户。相比单次购买更加优惠,让您在需要陪诊时随时可用,无需重复下单。', + icon: 'user-business', + tag: '', + // 称谓由「客户」改为「用户」,与 id 1-5 统一;结构对齐 id 1(服务对象句 + 适用情形句), + // 原句把 flow 里的环节又叙述一遍,且「让夜间就医也能更省心」是宣传腔,一并删 + description: '主要服务行动不便、认知或沟通不便、异地就医不熟悉医院的用户。夜间就诊、不便独自前往或家属不便陪同时,建议选择本服务。', + // 步骤名与 id 1-5 对齐:「在线预约」→「预约」、「电话确认」→「沟通信息」; + // 执行人由「客服人员」改为「陪诊师」——服务执行人一律用陪诊师,客服只管订单变更与投诉。 + // 「分配陪诊师」保留:夜间排班需要匹配值班陪诊师,是用户关心的一步,id 1/2 没有 flow: [{ - title: '在线预约', - desc: '选择5次半天陪诊套餐,填写就诊信息,提交订单' + title: '预约', + desc: '在线预约、电话预约、微信预约。电话或微信见联系我们页面' }, { - title: '电话确认', - desc: '客服人员将在30分钟内与您电话确认订单详情' + title: '沟通信息', + desc: '与陪诊师确认就诊医院、就诊时间、就诊人信息、行动能力与特殊需求' + }, + { + title: '分配陪诊师', + desc: '根据您的就诊医院和时间,匹配专业陪诊师' }, { title: '支付费用', desc: '通过微信支付服务费用' }, { - title: '套餐激活', - desc: '确认订单后,5次陪诊服务正式激活' - }, - { - title: '预约单次服务', - desc: '每次就诊前,提前联系客服预约当次陪诊服务' + title: '医院集合', + desc: '陪诊师按约定时间在医院指定地点与您会合' }, { title: '全程陪诊', @@ -304,66 +408,82 @@ const services = [ }, { title: '服务完成', - desc: '确认服务完成,可对陪诊师进行评价' + desc: '清点病历、检查报告、药品等材料,确认本次就诊所有项目已完成。提醒后续就诊时间、注意事项与医嘱。' } ], notices: [ - '套餐包含5次半天陪诊服务,每次4小时', - '每次就诊前请提前1天联系客服预约', - '套餐有效期为购买之日起12个月', - '服务不包含挂号费、检查费、药费等医疗费用', - '套餐不可退款,但可转让给直系亲属使用' + // 全站超时统一 80 元/h(原 150 元/h,曾与全天/半天不一致) + '服务时长为4小时,超出时间按每小时80元计费', + '夜间就诊请提前1天预约', + // 9.1.1 应提供服务变更手续,与 id 1/2/3/5 统一为「改期或取消」(原只有取消) + '如需改期或取消订单,请提前4小时联系客服', + // 8.2 同 id 1:夜间就诊多由家属陪同,法律效力医疗文书仍须本人或家属签署 + '具有法律效力的医疗文书(手术、麻醉、特殊检查知情同意书等)需您本人或家属签署,陪诊师不代签', + // 句式与 id 1-5 统一(原「服务不包含」少一个「费」) + '服务费不包含挂号费、检查费、药费等医疗费用', + // 9.1.1 与 9.2.3 要求告知投诉渠道(原缺);页面名与全站一致,用「联系我们」 + '如对服务有疑问或建议,可在「联系我们」页面反馈' ] }, { id: 8, - title: 'VIP 5次代买药', - subtitle: '五次代买药服务,更优惠', - price: '680.00', + // 国标 8.1 明确列有「代取药品」,属允许开展的动作,不涉及诊疗决策 + title: '取药快递', + subtitle: '代取药品,快递寄送到家', + price: '160.00', image: '/images/pt.jpg', icon: 'usergroup', - tag: '优惠套餐', - description: '5次代买药套餐为您提供5次专业代买药服务,适合需要长期服药或多次购药的客户。相比单次购买更加优惠,让您在需要购药时随时可用,无需重复下单。', + tag: '', + // 称谓由「客户」改为「用户」、去「我们」,与 id 1-5/7 统一; + // 结构对齐 id 1/2/7(服务对象句 + 适用情形句),原句又把 flow 叙述了一遍 + description: '主要服务不便出门或异地取药的用户。经您同意并授权后,陪诊师携带您的取药凭证代取药品,妥善包装后通过快递寄送到家。', + // 「在线预约」→「预约」、「电话确认」→「沟通信息」,与 id 1-7 对齐; + // 原「材料交接」排在「支付费用」之前且与 id 6 位置相反,改为全站统一的「准备资料」并回到支付之后; + // 执行人由「客服」改为「陪诊师」——服务执行人一律用陪诊师,客服只管订单变更与投诉 flow: [{ - title: '在线预约', - desc: '选择5次代买药套餐,填写购药信息,提交订单' + title: '预约', + desc: '在线预约、电话预约、微信预约。电话或微信见联系我们页面' }, { - title: '电话确认', - desc: '客服人员将在30分钟内与您电话确认订单详情' + title: '沟通信息', + desc: '与陪诊师确认取药医院或药店、就诊人信息、药品信息与收货地址' }, { title: '支付费用', desc: '通过微信支付服务费用' }, { - title: '套餐激活', - desc: '确认订单后,5次代买药服务正式激活' + title: '准备资料', + desc: '提供就诊卡、处方或取药单等取药凭证' }, { - title: '预约单次服务', - desc: '每次购药前,提前联系客服预约当次代买药服务' + title: '代取药品', + desc: '陪诊师按约定到医院或药店代为取药,并核对药品名称与数量' }, { - title: '代买药', - desc: '工作人员按约定到医院或药店代为购买药品' - }, - { - title: '药品交付', - desc: '将购买的药品通过快递或约定方式交付给您' + title: '快递寄出', + desc: '将药品妥善包装后通过快递寄出,并把快递单号告知您' }, { + // 原话「确认服务完成」是复述标题的空话,按 9.3.3 交代签收与后续 title: '服务完成', - desc: '确认服务完成' + desc: '您收到药品后请及时核对,确认无误即服务完成;如有疑问可联系陪诊师处理。' } ], notices: [ - '套餐包含5次代买药服务', - '每次购药前请提前1天联系客服预约', - '套餐有效期为购买之日起12个月', - '药品费用需另行支付,不包含在套餐价格内', - '套餐不可退款,但可转让给直系亲属使用', - '需提供医生处方或既往购药记录' + '请提前1天预约', + // 4.2.2.2:取药要用到您的就诊卡与处方,属代办个人信息,前提是授权同意 + '需经您同意并授权后,陪诊师方可持您的取药凭证代为取药', + '请提供就诊卡、处方或取药单等取药凭证', + '请提供准确的收货地址,并保持电话畅通以便签收', + // 句式与 id 1-7 统一;快递费因距离而异,4.2.4.2 要求收费须公示, + // 故不写死金额,改为寄出前先与您确认 + '服务费不包含药品费用,药品费请按医院或药店实际收费缴纳', + '快递费按实际收取,具体金额会在寄出前与您确认', + // 9.1.1 应提供服务变更手续 + '如需改期或取消订单,请提前联系客服', + // 9.1.1 与 9.2.3 要求告知投诉渠道 + '如对服务有疑问或建议,可在「联系我们」页面反馈' ] } ] diff --git a/routes/index.js b/routes/index.js index 2ce55b2..f5308e7 100644 --- a/routes/index.js +++ b/routes/index.js @@ -2,6 +2,7 @@ import Router from "koa-router"; import { HandlerEscortRecord } from "../handler/escort_record.js"; import { HandlerHealthProfile } from "../handler/health_profile.js"; import { HandlerResource } from "../handler/resource.js"; +import { HandlerEmployee } from "../handler/employee.js"; import ResponseUtil from "../utils/responseUtil.js"; import { getUserByToken } from "../utils/user_service.js"; @@ -40,6 +41,7 @@ function registerRoutes(app) { const handlerEscortRecord = new HandlerEscortRecord(); const handlerHealthProfile = new HandlerHealthProfile(); const handlerResource = new HandlerResource(); + const handlerEmployee = new HandlerEmployee(); // 敏感数据路由需要登录后访问 router.get("/escort-record/my", requireAuth, handlerEscortRecord.getMyRecords.bind(handlerEscortRecord)); @@ -51,6 +53,13 @@ function registerRoutes(app) { router.patch("/escort-record/:id/status", requireAuth, handlerEscortRecord.updateStatus.bind(handlerEscortRecord)); router.delete("/escort-record/:id", requireAuth, handlerEscortRecord.deleteRecord.bind(handlerEscortRecord)); + // C 端"我的健康档案":userId 一律取自 token,必须注册在 /health-profile/:id 之前 + router.get("/health-profile/mine", requireAuth, handlerHealthProfile.getMyProfiles.bind(handlerHealthProfile)); + router.post("/health-profile/mine", requireAuth, handlerHealthProfile.createMyProfile.bind(handlerHealthProfile)); + router.get("/health-profile/mine/:id", requireAuth, handlerHealthProfile.getMyProfileById.bind(handlerHealthProfile)); + router.put("/health-profile/mine/:id", requireAuth, handlerHealthProfile.updateMyProfile.bind(handlerHealthProfile)); + router.delete("/health-profile/mine/:id", requireAuth, handlerHealthProfile.deleteMyProfile.bind(handlerHealthProfile)); + router.get("/health-profile", requireAuth, handlerHealthProfile.getProfiles.bind(handlerHealthProfile)); router.get("/health-profile/:id", requireAuth, handlerHealthProfile.getProfileById.bind(handlerHealthProfile)); router.post("/health-profile", requireAuth, handlerHealthProfile.createProfile.bind(handlerHealthProfile)); @@ -64,6 +73,10 @@ function registerRoutes(app) { router.get("/department-rankings", handlerResource.getDepartmentRankings.bind(handlerResource)); router.get("/ai-quick-questions", handlerResource.getAiQuickQuestions.bind(handlerResource)); + // 陪诊师公示(公开):面向 C 端患者展示陪同人员信息。 + // 与上面的 /service、/agreement 一样属公示类资源,不加 requireAuth + router.get("/attendant", handlerEmployee.getAttendants.bind(handlerEmployee)); + app.use(router.routes()); app.use(router.allowedMethods());