基本重构完成
This commit is contained in:
@@ -48,7 +48,7 @@ Page({
|
||||
// 原「需要空腹的项目,就诊当天请勿进食进水」是替医院下医嘱;
|
||||
// 要求来源交回医院,与 id 4「请提前了解…要求」同口径
|
||||
'部分检查要求空腹(禁食禁水),请以医院的检查前通知为准',
|
||||
'提前与陪诊师确认医院、院区与集合地点'
|
||||
'提前与陪诊师确认医院、院区、集合地点与时间'
|
||||
],
|
||||
// 温馨提示:通用提醒,不涉及具体退款或收费规则
|
||||
tips: [
|
||||
@@ -59,7 +59,7 @@ Page({
|
||||
// 8.2 不应签署具有法律效力的医疗文书
|
||||
'具有法律效力的医疗文书(手术、麻醉、特殊检查知情同意书等)需您本人或家属签署,陪诊师不代签',
|
||||
// 全站统一时限,与服务页 notices、协议第 2 节一致(原「请尽早联系客服调整」没给时限,等于缺公示)
|
||||
'如需改期或取消,请至少提前4小时联系客服'
|
||||
'如需改期或取消,请至少提前1天联系客服'
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
+60
-52
@@ -16,9 +16,11 @@ Page({
|
||||
totalPrice: '0.00',
|
||||
showOrderPopup: false,
|
||||
profiles: [], // 已保存的就诊人
|
||||
selectedProfileId: '', // 当前选中的就诊人档案 ID,为空表示手动填写
|
||||
patientName: '',
|
||||
patientPhone: '',
|
||||
selectedProfileId: '', // 必填:订单必须关联就诊人档案
|
||||
patientName: '', // 只读展示,来自所选档案
|
||||
patientPhone: '', // 只读展示,来自所选档案
|
||||
// 选中档案的全部信息,下单时整体写入订单 patient 快照
|
||||
selectedPatient: null,
|
||||
// 默认北京:取值必须与 provinces[0] 完全一致('北京市' 而非 '北京'),
|
||||
// 否则 picker 的 value=0 与显示文案会对不上
|
||||
province: '北京市',
|
||||
@@ -99,11 +101,12 @@ Page({
|
||||
return
|
||||
}
|
||||
|
||||
const user = app.globalData.user
|
||||
// 订单必须关联健康档案,就诊人不再手输:打开弹窗时清空,等用户选择就诊人后带入
|
||||
this.setData({
|
||||
patientName: user.profile?.name || '',
|
||||
patientPhone: user.profile?.mobile || '',
|
||||
patientName: '',
|
||||
patientPhone: '',
|
||||
selectedProfileId: '',
|
||||
selectedPatient: null,
|
||||
showOrderPopup: true
|
||||
})
|
||||
|
||||
@@ -120,11 +123,21 @@ Page({
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const list = ((res.data && res.data.list) || []).map((item) => ({
|
||||
_id: item._id,
|
||||
name: item.profile?.name || '',
|
||||
mobile: item.profile?.mobile || ''
|
||||
}))
|
||||
// 档案是 profile + health 两层嵌套,这里拍平成选人后可直接带入的字段
|
||||
const list = ((res.data && res.data.list) || []).map((item) => {
|
||||
const profile = item.profile || {}
|
||||
const health = item.health || {}
|
||||
return {
|
||||
_id: item._id,
|
||||
name: profile.name || '',
|
||||
mobile: profile.mobile || '',
|
||||
sex: profile.sex || '',
|
||||
birth: profile.birth || '',
|
||||
weight: health.weight || 0,
|
||||
height: health.height || 0,
|
||||
idnumber: profile.idnumber || ''
|
||||
}
|
||||
})
|
||||
this.setData({
|
||||
profiles: list
|
||||
})
|
||||
@@ -134,7 +147,7 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// 选择就诊人:自动带入姓名与联系电话
|
||||
// 选择就诊人:姓名/电话回填展示,其余字段存入 selectedPatient 供下单使用
|
||||
onSelectProfile(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
const profile = this.data.profiles.find((item) => item._id === id)
|
||||
@@ -144,8 +157,16 @@ Page({
|
||||
|
||||
this.setData({
|
||||
selectedProfileId: id,
|
||||
// patientName / patientPhone 只用于弹窗内只读展示
|
||||
patientName: profile.name,
|
||||
patientPhone: profile.mobile
|
||||
patientPhone: profile.mobile,
|
||||
// 订单 patient 快照的唯一来源:所选档案的名单字段(体征与证件号不进快照)
|
||||
selectedPatient: {
|
||||
name: profile.name,
|
||||
mobile: profile.mobile,
|
||||
sex: profile.sex,
|
||||
birth: profile.birth
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -162,21 +183,6 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// 手动修改姓名/电话后,不再与所选档案对应,清空选择避免存档信息不一致
|
||||
onPatientNameChange(e) {
|
||||
this.setData({
|
||||
patientName: e.detail.value,
|
||||
selectedProfileId: ''
|
||||
})
|
||||
},
|
||||
|
||||
onPatientPhoneChange(e) {
|
||||
this.setData({
|
||||
patientPhone: e.detail.value,
|
||||
selectedProfileId: ''
|
||||
})
|
||||
},
|
||||
|
||||
onProvinceChange(e) {
|
||||
const index = e.detail.value
|
||||
const province = this.data.provinces[index]
|
||||
@@ -228,8 +234,8 @@ Page({
|
||||
submitOrder() {
|
||||
const {
|
||||
service,
|
||||
patientName,
|
||||
patientPhone,
|
||||
selectedProfileId,
|
||||
selectedPatient,
|
||||
province,
|
||||
hospital,
|
||||
department,
|
||||
@@ -239,16 +245,10 @@ Page({
|
||||
remark
|
||||
} = this.data
|
||||
|
||||
if (!patientName.trim()) {
|
||||
// 订单必须关联就诊人:没有档案就没有 patient 快照,不允许下单
|
||||
if (!selectedProfileId || !selectedPatient) {
|
||||
wx.showToast({
|
||||
title: '请输入就诊人姓名',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!patientPhone.trim()) {
|
||||
wx.showToast({
|
||||
title: '请输入联系电话',
|
||||
title: '请选择就诊人',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -283,9 +283,9 @@ Page({
|
||||
}
|
||||
|
||||
const phoneRegex = /^1[3-9]\d{9}$/
|
||||
if (!phoneRegex.test(patientPhone.trim())) {
|
||||
if (!phoneRegex.test(selectedPatient.mobile.trim())) {
|
||||
wx.showToast({
|
||||
title: '请输入正确的手机号',
|
||||
title: '就诊人手机号有误,请到就诊人档案修改',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -297,12 +297,22 @@ Page({
|
||||
if (gender == '男') sex = 'male'
|
||||
else if (gender == '女') sex = 'female'
|
||||
|
||||
// 就诊人快照只取名单字段(schema 口径:name/mobile/sex/birth);
|
||||
// sex 是 male/female 枚举,空值不写该字段
|
||||
const patient = {
|
||||
name: selectedPatient.name.trim(),
|
||||
mobile: selectedPatient.mobile.trim(),
|
||||
birth: selectedPatient.birth || ''
|
||||
}
|
||||
if (selectedPatient.sex) {
|
||||
patient.sex = selectedPatient.sex
|
||||
}
|
||||
|
||||
const orderData = {
|
||||
userId: user._id,
|
||||
patient: {
|
||||
name: patientName.trim(),
|
||||
mobile: patientPhone.trim(),
|
||||
},
|
||||
// 订单与就诊人档案的关联,必填(patient 只是下单当刻的快照)
|
||||
healthProfileId: selectedProfileId,
|
||||
patient: patient,
|
||||
escort: {
|
||||
serviceId: service.id,
|
||||
serviceName: service.title,
|
||||
@@ -325,11 +335,6 @@ Page({
|
||||
}
|
||||
}
|
||||
|
||||
// 选择了已保存的就诊人时,一并记录档案 ID
|
||||
if (this.data.selectedProfileId) {
|
||||
orderData.healthProfileId = this.data.selectedProfileId
|
||||
}
|
||||
|
||||
wx.showLoading({
|
||||
title: '提交中...'
|
||||
})
|
||||
@@ -346,7 +351,8 @@ Page({
|
||||
showOrderPopup: false
|
||||
})
|
||||
this.resetForm()
|
||||
wx.navigateTo({url: '/pages/escort/recordlist?tab=pending'})
|
||||
// 下单成功回到记录页,直接落到「进行中的」:新单是待确认,属未完成档
|
||||
wx.navigateTo({url: '/pages/escort/recordlist?tab=ongoing'})
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: data.msg || '下单失败',
|
||||
@@ -369,6 +375,7 @@ Page({
|
||||
selectedProfileId: '',
|
||||
patientName: '',
|
||||
patientPhone: '',
|
||||
selectedPatient: null,
|
||||
// 重置后仍回到默认北京,与 data 初值保持一致
|
||||
province: '北京市',
|
||||
provinceIndex: 0,
|
||||
@@ -376,7 +383,8 @@ Page({
|
||||
department: '',
|
||||
appointmentDate: '',
|
||||
appointmentTime: '',
|
||||
gender: '',
|
||||
// 重置后回到默认「不限」,与 data 初值(gender: '不限' / genderIndex: 0)保持一致
|
||||
gender: '不限',
|
||||
genderIndex: 0,
|
||||
remark: ''
|
||||
})
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 选择就诊人:从已保存的就诊人一键带入姓名与电话 -->
|
||||
<!-- 选择就诊人:订单必须关联健康档案,就诊人信息全部由此带入 -->
|
||||
<view class="order-row column">
|
||||
<text class="order-label">选择就诊人</text>
|
||||
<scroll-view class="patient-scroll" scroll-x wx:if="{{profiles.length > 0}}">
|
||||
@@ -112,16 +112,16 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 就诊人姓名 -->
|
||||
<!-- 就诊人姓名/电话:只读,与所选档案严格一致(要改就去「编辑就诊人」) -->
|
||||
<view class="order-row">
|
||||
<text class="order-label">就诊人姓名</text>
|
||||
<input class="order-input" value="{{patientName}}" placeholder="请输入就诊人姓名" placeholder-class="input-placeholder" bindinput="onPatientNameChange" />
|
||||
<text class="order-value {{patientName ? '' : 'placeholder'}}">{{patientName || '请先选择就诊人'}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 就诊人电话 -->
|
||||
<view class="order-row">
|
||||
<text class="order-label">联系电话</text>
|
||||
<input class="order-input" value="{{patientPhone}}" placeholder="请输入联系电话" placeholder-class="input-placeholder" type="number" bindinput="onPatientPhoneChange" />
|
||||
<text class="order-value {{patientPhone ? '' : 'placeholder'}}">{{patientPhone || '请先选择就诊人'}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 就诊省份 -->
|
||||
|
||||
@@ -462,6 +462,22 @@ page {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* 只读值(就诊人姓名/电话):与 .order-input 同形,仅去掉输入框语义 */
|
||||
.order-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 24rpx;
|
||||
text-align: right;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.order-value.placeholder {
|
||||
color: var(--muted);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* picker 需要占满剩余宽度,值才能靠右对齐 */
|
||||
.order-picker {
|
||||
flex: 1;
|
||||
|
||||
+253
-91
@@ -3,18 +3,22 @@ const API = require('../../utils/api.js')
|
||||
// 状态配色遵循 doc/DESIGN.md §三:四档状态色 + 状态说明文字,
|
||||
// 颜色只做强化,文字才是信息。待确认与已确认同属「等待」阶段,共用待服务档
|
||||
const STATUS_MAP = {
|
||||
pending: { text: '待确认', color: '#0F766E', bg: '#ECF7F4', border: '#C7E5DF', desc: '您的订单已提交,等待陪诊员确认' },
|
||||
confirmed: { text: '已确认', color: '#0F766E', bg: '#ECF7F4', border: '#C7E5DF', desc: '订单已确认,陪诊员将准时为您服务' },
|
||||
// 待确认是唯一「等用户自己决定」的阶段(底栏此时一定有「取消订单」),
|
||||
// 说明文字因此带上可执行动作,靠文字而不是靠再叠一层色块来提请注意
|
||||
pending: { text: '待确认', color: '#0F766E', bg: '#ECF7F4', border: '#C7E5DF', desc: '订单已提交,等待陪诊师确认;确认前可取消' },
|
||||
confirmed: { text: '已确认', color: '#0F766E', bg: '#ECF7F4', border: '#C7E5DF', desc: '订单已确认,陪诊师将准时为您服务' },
|
||||
in_progress: { text: '进行中', color: '#B8520A', bg: '#FFF4E8', border: '#FFE0C2', desc: '陪诊服务正在进行中' },
|
||||
completed: { text: '已完成', color: '#1F7A4D', bg: '#EAF6EE', border: '#CDE9D7', desc: '陪诊服务已完成,感谢您的使用' },
|
||||
cancelled: { text: '已取消', color: '#B4231A', bg: '#FCF0EE', border: '#F2D6D1', desc: '该订单已取消' }
|
||||
}
|
||||
|
||||
// 支付状态:已支付走「已完成」档;未支付 / 部分支付复用主色浅档提示待处理;
|
||||
// 已退款走中性档(--muted 字 + --sep 描边 + 透明底)
|
||||
// 支付状态胶囊:未支付 / 部分支付复用主色浅档提示待处理;已退款走中性档(--muted 字 + --sep 描边 + 透明底);
|
||||
// 已支付不显示胶囊(支付完成是常态,不需要状态强调),paid 档仅为映射兜底保留。
|
||||
// hint 是未付清时的出口指引:全站没有线上支付入口,只能引导走客服;
|
||||
// 部分支付要说清是「补齐」而不是「完成支付」,否则用户会以为要再付一次全款
|
||||
const PAYMENT_STATUS_MAP = {
|
||||
unpaid: { text: '未支付', color: '#B8520A', bg: '#FFF4E8', border: '#FFE0C2' },
|
||||
partial: { text: '部分支付', color: '#B8520A', bg: '#FFF4E8', border: '#FFE0C2' },
|
||||
unpaid: { text: '未支付', color: '#B8520A', bg: '#FFF4E8', border: '#FFE0C2', hint: '请联系客服完成支付' },
|
||||
partial: { text: '部分支付', color: '#B8520A', bg: '#FFF4E8', border: '#FFE0C2', hint: '请联系客服补齐剩余费用' },
|
||||
paid: { text: '已支付', color: '#1F7A4D', bg: '#EAF6EE', border: '#CDE9D7' },
|
||||
refunded: { text: '已退款', color: '#6F655C', bg: 'transparent', border: '#E5DACC' }
|
||||
}
|
||||
@@ -30,22 +34,26 @@ const SEX_REQUIREMENT_MAP = {
|
||||
female: '女'
|
||||
}
|
||||
|
||||
const WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
||||
|
||||
Page({
|
||||
data: {
|
||||
recordId: '',
|
||||
record: {},
|
||||
loading: true,
|
||||
editing: false,
|
||||
// 编辑全部收进底部弹窗:页面只读,表单只活在弹窗里,两个弹窗各自一个开关
|
||||
showNotePopup: false,
|
||||
editPatientNote: '',
|
||||
editingPatient: false,
|
||||
editPatient: {},
|
||||
// 医院预约信息编辑弹窗:省份列表与下单页(itemdetail.js)保持同一份口径
|
||||
showHospitalPopup: false,
|
||||
provinces: ['北京市', '天津市', '河北省', '山西省', '内蒙古自治区', '辽宁省', '吉林省', '黑龙江省', '上海市', '江苏省', '浙江省', '安徽省', '福建省', '江西省', '山东省', '河南省', '湖北省', '湖南省', '广东省', '广西壮族自治区', '海南省', '重庆市', '四川省', '贵州省', '云南省', '西藏自治区', '陕西省', '甘肃省', '青海省', '宁夏回族自治区', '新疆维吾尔自治区', '台湾省', '香港特别行政区', '澳门特别行政区'],
|
||||
editHospital: {},
|
||||
showCancelPopup: false,
|
||||
cancelReason: '',
|
||||
cancelReasons: [
|
||||
'临时有事,无法前往',
|
||||
'病情好转,无需陪诊',
|
||||
'医院停诊/改期',
|
||||
'陪诊员无法到达',
|
||||
'陪诊师无法到达',
|
||||
'其他原因'
|
||||
]
|
||||
},
|
||||
@@ -58,9 +66,9 @@ Page({
|
||||
return
|
||||
}
|
||||
this.setData({ recordId: id })
|
||||
this.loadRecord(id)
|
||||
},
|
||||
|
||||
// onShow 在首次渲染时紧跟 onLoad 触发,加载只放在这里,避免进页面发两次请求
|
||||
onShow() {
|
||||
if (this.data.recordId) {
|
||||
this.loadRecord(this.data.recordId)
|
||||
@@ -75,13 +83,17 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
// 渲染到位判据是 record._id(WXML 用它守内容),本方法只负责取数
|
||||
loadRecord(id) {
|
||||
this.setData({ loading: true })
|
||||
return API.escort.getRecordById(id)
|
||||
.then((res) => {
|
||||
if (res.code === 0 && res.data) {
|
||||
const record = this.formatRecord(res.data.record)
|
||||
this.setData({ record })
|
||||
// 订单关联了健康档案时,就诊人信息以档案最新数据为准
|
||||
if (record.healthProfileId) {
|
||||
this.loadProfileSnapshot(record.healthProfileId)
|
||||
}
|
||||
} else {
|
||||
wx.showToast({ title: res.msg || '加载失败', icon: 'none' })
|
||||
}
|
||||
@@ -89,60 +101,178 @@ Page({
|
||||
.catch(() => {
|
||||
wx.showToast({ title: '网络请求失败', icon: 'none' })
|
||||
})
|
||||
.finally(() => {
|
||||
this.setData({ loading: false })
|
||||
},
|
||||
|
||||
// 用档案最新信息覆盖订单里的 patient 快照:
|
||||
// 订单必须关联就诊人,档案才是信息源;读取失败(如档案已删除)时保留快照兜底
|
||||
loadProfileSnapshot(profileId) {
|
||||
return API.healthProfile.getMyProfileById(profileId)
|
||||
.then((res) => {
|
||||
if (res.code !== 0 || !res.data) {
|
||||
return
|
||||
}
|
||||
const detail = res.data.profile || {}
|
||||
const profile = detail.profile || {}
|
||||
const health = detail.health || {}
|
||||
// 与 formatRecord 同一批就诊人字段:档案加载完成后覆盖订单快照,
|
||||
// 摘要行与首字牌因此需要一起重算
|
||||
const patient = {
|
||||
name: profile.name || '',
|
||||
sexText: SEX_MAP[profile.sex] || '',
|
||||
age: this.calcAge(profile.birth),
|
||||
weight: health.weight || 0,
|
||||
height: health.height || 0,
|
||||
mobile: profile.mobile || '',
|
||||
idnumber: profile.idnumber || ''
|
||||
}
|
||||
this.setData({
|
||||
'record.patientName': patient.name,
|
||||
'record.patientAge': patient.age,
|
||||
'record.patientWeight': patient.weight,
|
||||
'record.patientHeight': patient.height,
|
||||
'record.patientMobile': patient.mobile,
|
||||
'record.patientIdnumber': patient.idnumber,
|
||||
'record.patientInitial': patient.name.charAt(0),
|
||||
'record.patientMeta': this.buildPatientMeta(patient)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('获取就诊人档案失败,展示订单快照', err)
|
||||
})
|
||||
},
|
||||
|
||||
formatRecord(item) {
|
||||
const statusInfo = STATUS_MAP[item.status] || STATUS_MAP.pending
|
||||
const paymentInfo = PAYMENT_STATUS_MAP[item.payment?.status] || PAYMENT_STATUS_MAP.unpaid
|
||||
const status = item.status
|
||||
const paymentStatus = item.payment?.status || 'unpaid'
|
||||
const statusInfo = STATUS_MAP[status] || STATUS_MAP.pending
|
||||
const paymentInfo = PAYMENT_STATUS_MAP[paymentStatus] || PAYMENT_STATUS_MAP.unpaid
|
||||
|
||||
// 底栏与「修改」入口的口径在这里算一次,WXML 只读结果,不再重复一串状态判断。
|
||||
// 删除收窄为「未支付 且 未进入服务阶段」:进行中的订单已产生服务成本,不允许直接删
|
||||
const canCancel = status === 'pending' || status === 'confirmed'
|
||||
const canDelete = paymentStatus === 'unpaid'
|
||||
&& (status === 'pending' || status === 'confirmed' || status === 'cancelled')
|
||||
const canComplete = status === 'completed'
|
||||
const canRebook = status === 'completed' || status === 'cancelled'
|
||||
// 终态单据只读:医院预约与陪诊需求不允许回改(就诊人「修改」改的是档案,不在此列)
|
||||
const canEditOrder = status !== 'completed' && status !== 'cancelled'
|
||||
|
||||
// 就诊人字段先落到局部变量:摘要行(patientMeta)与首字牌(patientInitial)
|
||||
// 都从同一批值派生,口径不在 WXML 与 JS 两处各写一份
|
||||
const patient = {
|
||||
name: item.patient?.name || '',
|
||||
sexText: SEX_MAP[item.patient?.sex] || '',
|
||||
age: this.calcAge(item.patient?.birth),
|
||||
weight: item.patient?.weight || 0,
|
||||
height: item.patient?.height || 0,
|
||||
mobile: item.patient?.mobile || '',
|
||||
idnumber: item.patient?.idnumber || ''
|
||||
}
|
||||
|
||||
// 预约时间派生:日期行(带星期)、时间行(时段 + 陪诊时长)
|
||||
const scheduleMeta = this.buildScheduleMeta(item.schedule || {})
|
||||
|
||||
return {
|
||||
_id: item._id,
|
||||
patientName: item.patient?.name || '',
|
||||
patientSexText: SEX_MAP[item.patient?.sex] || '',
|
||||
patientBirth: item.patient?.birth || '',
|
||||
patientAge: this.calcAge(item.patient?.birth),
|
||||
patientWeight: item.patient?.weight || 0,
|
||||
patientHeight: item.patient?.height || 0,
|
||||
patientMobile: item.patient?.mobile || '',
|
||||
patientIdnumber: item.patient?.idnumber || '',
|
||||
healthProfileId: item.healthProfileId || '',
|
||||
patientName: patient.name,
|
||||
patientAge: patient.age,
|
||||
patientMobile: patient.mobile,
|
||||
patientIdnumber: patient.idnumber,
|
||||
patientInitial: patient.name.charAt(0),
|
||||
patientMeta: this.buildPatientMeta(patient),
|
||||
hospitalProvince: item.hospital?.province || '',
|
||||
hospitalName: item.hospital?.name || '',
|
||||
hospitalAddress: item.hospital?.address || '',
|
||||
hospitalMeta: this.buildHospitalMeta(item.hospital || {}),
|
||||
// 以下三个原始字段不进展示(展示走 hospitalMeta),是编辑弹窗的表单回填源
|
||||
hospitalDepartment: item.hospital?.department || '',
|
||||
hospitalDoctor: item.hospital?.doctor || '',
|
||||
medicalRecordNo: item.hospital?.medicalRecordNo || '',
|
||||
// scheduleDate 保留 YYYY-MM-DD 原格式:编辑弹窗的 date picker 直接喂它
|
||||
scheduleDate: item.schedule?.date ? this.formatDate(item.schedule.date) : '',
|
||||
scheduleStartTime: item.schedule?.startTime || '',
|
||||
scheduleEndTime: item.schedule?.endTime || '',
|
||||
scheduleDuration: item.schedule?.duration || 0,
|
||||
scheduleDateText: scheduleMeta.dateText,
|
||||
scheduleTimeText: scheduleMeta.timeText,
|
||||
escortServiceName: item.escort?.serviceName || '',
|
||||
attendantName: item.attendant?.name || '',
|
||||
attendantMobile: item.attendant?.mobile || '',
|
||||
sexRequirementText: SEX_REQUIREMENT_MAP[item.escort?.sexRequirement] || '',
|
||||
totalFee: (item.payment?.totalFee || 0).toFixed(2),
|
||||
paidFee: (item.payment?.paidFee || 0).toFixed(2),
|
||||
paymentStatus: item.payment?.status || 'unpaid',
|
||||
paymentStatus,
|
||||
paymentStatusText: paymentInfo.text,
|
||||
paymentStatusColor: paymentInfo.color,
|
||||
paymentStatusBg: paymentInfo.bg,
|
||||
paymentStatusBorder: paymentInfo.border,
|
||||
paymentHint: paymentInfo.hint || '',
|
||||
patientNote: item.notes?.patientNote || '',
|
||||
escortNote: item.notes?.escortNote || '',
|
||||
medicalSummary: item.notes?.medicalSummary || '',
|
||||
status: item.status,
|
||||
status,
|
||||
statusText: statusInfo.text,
|
||||
statusColor: statusInfo.color,
|
||||
statusBg: statusInfo.bg,
|
||||
statusBorder: statusInfo.border,
|
||||
statusDesc: statusInfo.desc,
|
||||
canCancel,
|
||||
canDelete,
|
||||
canComplete,
|
||||
canRebook,
|
||||
canEditOrder,
|
||||
// 底栏只在确实有按钮时出现,避免无动作状态空留一条白栏
|
||||
showBottomBar: canCancel || canDelete || canComplete || canRebook,
|
||||
createTime: item.meta?.createtime ? this.formatDateTime(item.meta.createtime) : '',
|
||||
updateTime: item.meta?.updatetime ? this.formatDateTime(item.meta.updatetime) : ''
|
||||
}
|
||||
},
|
||||
|
||||
// 就诊人摘要行的字段序列:空值整项剔除,WXML 只负责在项之间插竖线,
|
||||
// 不靠一串 && 条件去猜哪条分隔线该出现(避免留下孤立的分隔线)
|
||||
buildPatientMeta(patient) {
|
||||
const list = []
|
||||
if (patient.sexText) list.push(patient.sexText)
|
||||
if (patient.age) list.push(`${patient.age}岁`)
|
||||
if (patient.height) list.push(`身高 ${patient.height}cm`)
|
||||
if (patient.weight) list.push(`体重 ${patient.weight}kg`)
|
||||
return list
|
||||
},
|
||||
|
||||
// 医院元信息行:科室 / 医生 / 病历号,与就诊人摘要同一套插线逻辑;
|
||||
// 省份不进元信息行,由 hospitalProvince 单独提到卡内右上角
|
||||
buildHospitalMeta(hospital) {
|
||||
const list = []
|
||||
if (hospital.department) list.push(hospital.department)
|
||||
if (hospital.doctor) list.push(hospital.doctor)
|
||||
if (hospital.medicalRecordNo) list.push(`病历号 ${hospital.medicalRecordNo}`)
|
||||
return list
|
||||
},
|
||||
|
||||
// 预约时间派生:日期行(带星期)、时间行(时段 + 陪诊时长);
|
||||
// 日期无效或缺失时返回空串,由 WXML 走兜底文案
|
||||
buildScheduleMeta(schedule) {
|
||||
const result = { dateText: '', timeText: '' }
|
||||
if (schedule.date) {
|
||||
const d = new Date(schedule.date)
|
||||
if (!isNaN(d.getTime())) {
|
||||
result.dateText = `${d.getFullYear()}年${d.getMonth() + 1}月${d.getDate()}日 ${WEEKDAYS[d.getDay()]}`
|
||||
}
|
||||
}
|
||||
const start = schedule.startTime || ''
|
||||
const end = schedule.endTime || ''
|
||||
let timeText = start && end ? `${start} - ${end}` : (start ? `${start} 开始` : '')
|
||||
const duration = schedule.duration || 0
|
||||
if (timeText && duration > 0) {
|
||||
const hours = Math.floor(duration / 60)
|
||||
const minutes = duration % 60
|
||||
const durationText = hours > 0
|
||||
? (minutes > 0 ? `${hours}小时${minutes}分钟` : `${hours}小时`)
|
||||
: `${minutes}分钟`
|
||||
timeText = `${timeText} · 陪诊${durationText}`
|
||||
}
|
||||
result.timeText = timeText
|
||||
return result
|
||||
},
|
||||
|
||||
// 根据出生年月(YYYY-MM-DD)计算年龄
|
||||
calcAge(birth) {
|
||||
if (!birth) return 0
|
||||
@@ -179,19 +309,11 @@ Page({
|
||||
wx.makePhoneCall({ phoneNumber: mobile })
|
||||
},
|
||||
|
||||
onCallService() {
|
||||
wx.makePhoneCall({ phoneNumber: '18618162956' })
|
||||
},
|
||||
|
||||
onCallAttendant() {
|
||||
const mobile = this.data.record.attendantMobile
|
||||
if (!mobile || mobile === '--') return
|
||||
wx.makePhoneCall({ phoneNumber: mobile })
|
||||
},
|
||||
// ===== 陪诊需求编辑(底部弹窗) =====
|
||||
|
||||
onEditPatientNote() {
|
||||
this.setData({
|
||||
editing: true,
|
||||
showNotePopup: true,
|
||||
editPatientNote: this.data.record.patientNote || ''
|
||||
})
|
||||
},
|
||||
@@ -201,7 +323,7 @@ Page({
|
||||
},
|
||||
|
||||
onCancelEdit() {
|
||||
this.setData({ editing: false })
|
||||
this.setData({ showNotePopup: false })
|
||||
},
|
||||
|
||||
onSavePatientNote() {
|
||||
@@ -215,7 +337,7 @@ Page({
|
||||
if (res.code === 0) {
|
||||
wx.showToast({ title: '保存成功', icon: 'success' })
|
||||
this.setData({
|
||||
editing: false,
|
||||
showNotePopup: false,
|
||||
'record.patientNote': note
|
||||
})
|
||||
} else {
|
||||
@@ -228,74 +350,108 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
onEditPatientInfo() {
|
||||
const record = this.data.record
|
||||
const now = new Date()
|
||||
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
|
||||
// ===== 医院预约信息编辑(底部弹窗) =====
|
||||
|
||||
// 打开弹窗:用当前展示值填充表单(scheduleDate 已是 YYYY-MM-DD,可直接喂给 date picker)
|
||||
onEditHospital() {
|
||||
const r = this.data.record
|
||||
const provinceIndex = Math.max(0, this.data.provinces.indexOf(r.hospitalProvince))
|
||||
this.setData({
|
||||
today,
|
||||
editingPatient: true,
|
||||
editPatient: {
|
||||
name: record.patientName || '',
|
||||
sex: record.patientSexText === '男' ? 'male' : record.patientSexText === '女' ? 'female' : '',
|
||||
birth: record.patientBirth || '',
|
||||
weight: record.patientWeight ? String(record.patientWeight) : '',
|
||||
height: record.patientHeight ? String(record.patientHeight) : '',
|
||||
mobile: record.patientMobile || '',
|
||||
idnumber: record.patientIdnumber || ''
|
||||
showHospitalPopup: true,
|
||||
editHospital: {
|
||||
province: r.hospitalProvince || '',
|
||||
provinceIndex,
|
||||
name: r.hospitalName || '',
|
||||
address: r.hospitalAddress || '',
|
||||
department: r.hospitalDepartment || '',
|
||||
doctor: r.hospitalDoctor || '',
|
||||
medicalRecordNo: r.medicalRecordNo || '',
|
||||
scheduleDate: r.scheduleDate || '',
|
||||
startTime: r.scheduleStartTime || '',
|
||||
endTime: r.scheduleEndTime || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onPatientBirthChange(e) {
|
||||
this.setData({ 'editPatient.birth': e.detail.value })
|
||||
},
|
||||
|
||||
onPatientInfoInput(e) {
|
||||
// 文本字段统一走 data-field 分发,省掉每字段一个 handler
|
||||
onHospitalFieldInput(e) {
|
||||
const field = e.currentTarget.dataset.field
|
||||
const value = e.detail.value
|
||||
this.setData({ [`editHospital.${field}`]: e.detail.value })
|
||||
},
|
||||
|
||||
onProvinceChange(e) {
|
||||
const index = Number(e.detail.value)
|
||||
this.setData({
|
||||
[`editPatient.${field}`]: value
|
||||
'editHospital.provinceIndex': index,
|
||||
'editHospital.province': this.data.provinces[index]
|
||||
})
|
||||
},
|
||||
|
||||
onPatientSexChange(e) {
|
||||
const value = e.currentTarget.dataset.value
|
||||
this.setData({
|
||||
'editPatient.sex': value
|
||||
})
|
||||
onScheduleDateChange(e) {
|
||||
this.setData({ 'editHospital.scheduleDate': e.detail.value })
|
||||
},
|
||||
|
||||
onCancelEditPatientInfo() {
|
||||
this.setData({ editingPatient: false })
|
||||
onStartTimeChange(e) {
|
||||
this.setData({ 'editHospital.startTime': e.detail.value })
|
||||
},
|
||||
|
||||
onSavePatientInfo() {
|
||||
const patient = this.data.editPatient
|
||||
if (!patient.name.trim()) {
|
||||
wx.showToast({ title: '请输入姓名', icon: 'none' })
|
||||
onEndTimeChange(e) {
|
||||
this.setData({ 'editHospital.endTime': e.detail.value })
|
||||
},
|
||||
|
||||
// 起止时间都在时重算陪诊时长(分钟);结束不晚于开始视为无效,拦在保存前
|
||||
calcDuration(startTime, endTime) {
|
||||
if (!startTime || !endTime) return null
|
||||
const [sh, sm] = startTime.split(':').map(Number)
|
||||
const [eh, em] = endTime.split(':').map(Number)
|
||||
const diff = eh * 60 + em - (sh * 60 + sm)
|
||||
return diff > 0 ? diff : -1
|
||||
},
|
||||
|
||||
onCancelHospitalEdit() {
|
||||
this.setData({ showHospitalPopup: false })
|
||||
},
|
||||
|
||||
onSaveHospital() {
|
||||
const form = this.data.editHospital
|
||||
if (!form.name || !form.name.trim()) {
|
||||
wx.showToast({ title: '请输入就诊医院', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!patient.mobile.trim()) {
|
||||
wx.showToast({ title: '请输入联系电话', icon: 'none' })
|
||||
if (!form.scheduleDate) {
|
||||
wx.showToast({ title: '请选择预约日期', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const duration = this.calcDuration(form.startTime, form.endTime)
|
||||
if (duration === -1) {
|
||||
wx.showToast({ title: '结束时间需晚于开始时间', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
const update = {
|
||||
'hospital.province': form.province || '',
|
||||
'hospital.name': form.name.trim(),
|
||||
'hospital.address': (form.address || '').trim(),
|
||||
'hospital.department': (form.department || '').trim(),
|
||||
'hospital.doctor': (form.doctor || '').trim(),
|
||||
'hospital.medicalRecordNo': (form.medicalRecordNo || '').trim(),
|
||||
// schedule.date 后端是 Date 类型,mongoose 会把 YYYY-MM-DD 字符串自动转换
|
||||
'schedule.date': form.scheduleDate,
|
||||
'schedule.startTime': form.startTime || '',
|
||||
'schedule.endTime': form.endTime || ''
|
||||
}
|
||||
if (duration !== null) {
|
||||
update['schedule.duration'] = duration
|
||||
}
|
||||
|
||||
wx.showLoading({ title: '保存中...' })
|
||||
API.escort.updateRecord(this.data.recordId, {
|
||||
'patient.name': patient.name.trim(),
|
||||
'patient.sex': patient.sex,
|
||||
'patient.birth': patient.birth || '',
|
||||
'patient.weight': parseFloat(patient.weight) || 0,
|
||||
'patient.height': parseFloat(patient.height) || 0,
|
||||
'patient.mobile': patient.mobile.trim(),
|
||||
'patient.idnumber': patient.idnumber.trim()
|
||||
})
|
||||
API.escort.updateRecord(this.data.recordId, update)
|
||||
.then((res) => {
|
||||
wx.hideLoading()
|
||||
if (res.code === 0) {
|
||||
wx.showToast({ title: '保存成功', icon: 'success' })
|
||||
this.setData({ editingPatient: false })
|
||||
this.setData({ showHospitalPopup: false })
|
||||
// 重新拉取,保证 formatRecord 出的展示字段(日历牌、时长)与库内一致
|
||||
this.loadRecord(this.data.recordId)
|
||||
} else {
|
||||
wx.showToast({ title: res.msg || '保存失败', icon: 'none' })
|
||||
@@ -307,6 +463,17 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// 就诊人信息统一在健康档案里维护,这里只负责跳转
|
||||
onEditProfile() {
|
||||
const profileId = this.data.record.healthProfileId
|
||||
if (!profileId) {
|
||||
return
|
||||
}
|
||||
wx.navigateTo({
|
||||
url: `/pages/health/profileedit?id=${profileId}`
|
||||
})
|
||||
},
|
||||
|
||||
onCancelOrder() {
|
||||
this.setData({
|
||||
showCancelPopup: true,
|
||||
@@ -349,10 +516,6 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
onPayOrder() {
|
||||
wx.showToast({ title: '支付功能开发中', icon: 'none' })
|
||||
},
|
||||
|
||||
onConfirmComplete() {
|
||||
wx.showModal({
|
||||
title: '确认完成',
|
||||
@@ -412,7 +575,6 @@ Page({
|
||||
},
|
||||
|
||||
onRebook() {
|
||||
const serviceId = this.data.record.escortServiceName
|
||||
wx.navigateTo({
|
||||
url: `/pages/escort/itemlist`
|
||||
})
|
||||
|
||||
+268
-204
@@ -1,8 +1,10 @@
|
||||
<view class="page-bg">
|
||||
<view class="container">
|
||||
<!-- 数据到位前不渲染内容:record 初始是 {},直接铺开会先闪一帧
|
||||
「就诊医院待补充 / ¥0.00 / 暂无备注信息」的假数据,用 _id 作到位判据 -->
|
||||
<view class="container" wx:if="{{record._id}}">
|
||||
|
||||
<!-- 状态头:短横色标 + 状态胶囊 + 状态说明。
|
||||
状态色只包住胶囊文字本身(DESIGN.md §三),去掉旧版渐变横幅与大色块 -->
|
||||
<!-- 状态头:短横色标 + 状态胶囊 + 状态说明,是本页的「单据抬头」,不走卡片。
|
||||
状态色只包住胶囊文字本身(DESIGN.md §三),不做整块主色面板 -->
|
||||
<view class="page-header">
|
||||
<view class="header-accent"></view>
|
||||
<view class="status-row">
|
||||
@@ -10,193 +12,107 @@
|
||||
class="status-chip status-chip-lg"
|
||||
style="background: {{record.statusBg}}; color: {{record.statusColor}}; border-color: {{record.statusBorder}};"
|
||||
>{{record.statusText}}</view>
|
||||
<text class="header-subtitle">{{record.statusDesc}}</text>
|
||||
</view>
|
||||
<text class="header-subtitle">{{record.statusDesc}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 就诊人信息 -->
|
||||
<!-- 全页信息架构:抬头之下五张同构白卡(就诊人 / 医院预约 / 需求与症状 / 服务与费用 / 订单),
|
||||
标题在纸面上、内容在白卡里——同一层级只用一种载体。
|
||||
页面本身纯展示(不铺「标签左/值右」的表单行),所有修改都收进底部弹窗:
|
||||
卡片回答「是什么」,弹窗回答「改成什么」,两种语境不混在同一版面里 -->
|
||||
|
||||
<!-- 就诊人信息:订单关联健康档案,就诊人信息以档案为准,
|
||||
因此「修改」直接去档案页,不在订单侧另开一套编辑(同一意图只保留一个入口) -->
|
||||
<view class="section">
|
||||
<view class="section-head">
|
||||
<view class="section-bar"></view>
|
||||
<text class="section-title">就诊人信息</text>
|
||||
<view class="section-link" wx:if="{{!editingPatient}}" bindtap="onEditPatientInfo">
|
||||
<view class="section-link" wx:if="{{record.healthProfileId}}" bindtap="onEditProfile">
|
||||
<text class="section-link-text">修改</text>
|
||||
<t-icon name="edit" size="26rpx" color="#9B4508" />
|
||||
<t-icon name="edit" size="26rpx" color="#6F655C" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<block wx:if="{{!editingPatient}}">
|
||||
<view class="info-row">
|
||||
<text class="info-label">姓名</text>
|
||||
<text class="info-value">{{record.patientName || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">性别</text>
|
||||
<text class="info-value">{{record.patientSexText || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">年龄</text>
|
||||
<text class="info-value">{{record.patientAge ? record.patientAge + '岁' : '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">体重</text>
|
||||
<text class="info-value">{{record.patientWeight ? record.patientWeight + 'kg' : '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">身高</text>
|
||||
<text class="info-value">{{record.patientHeight ? record.patientHeight + 'cm' : '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">联系电话</text>
|
||||
<text class="info-value info-link" bindtap="onCallPatient">{{record.patientMobile || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row" wx:if="{{record.patientIdnumber}}">
|
||||
<text class="info-label">身份证号</text>
|
||||
<text class="info-value">{{record.patientIdnumber}}</text>
|
||||
</view>
|
||||
</block>
|
||||
<!-- 身份牌:首字牌定位「是谁」,姓名、体征元信息、证件号收进首字牌右侧纵列;
|
||||
发丝线之下只留一个动作(拨打) -->
|
||||
<view class="card patient-card">
|
||||
<view class="patient-head">
|
||||
<!-- 首字牌沿用「浅橙衬底承载标识」:有姓名取姓氏首字,无则退到 user 图标 -->
|
||||
<view class="patient-mark">
|
||||
<text wx:if="{{record.patientInitial}}" class="patient-mark-text">{{record.patientInitial}}</text>
|
||||
<t-icon wx:else name="user" size="44rpx" color="#9B4508" />
|
||||
</view>
|
||||
<view class="patient-info">
|
||||
<text class="patient-name">{{record.patientName || '--'}}</text>
|
||||
|
||||
<block wx:else>
|
||||
<view class="edit-row">
|
||||
<text class="edit-label">姓名</text>
|
||||
<input class="edit-input" value="{{editPatient.name}}" placeholder="请输入姓名" placeholder-class="input-placeholder" data-field="name" bindinput="onPatientInfoInput" />
|
||||
</view>
|
||||
<view class="edit-row">
|
||||
<text class="edit-label">性别</text>
|
||||
<view class="edit-radio-group">
|
||||
<view class="edit-radio {{editPatient.sex === 'male' ? 'active' : ''}}" data-value="male" bindtap="onPatientSexChange">男</view>
|
||||
<view class="edit-radio {{editPatient.sex === 'female' ? 'active' : ''}}" data-value="female" bindtap="onPatientSexChange">女</view>
|
||||
<!-- 体征行:空值已在 JS 里整项剔除,这里只按序插竖线 -->
|
||||
<view class="meta-list patient-meta-row" wx:if="{{record.patientMeta.length > 0}}">
|
||||
<block wx:for="{{record.patientMeta}}" wx:key="*this">
|
||||
<view class="meta-sep" wx:if="{{index > 0}}"></view>
|
||||
<text class="meta-item">{{item}}</text>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<text class="patient-id" wx:if="{{record.patientIdnumber}}">身份证号 {{record.patientIdnumber}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="edit-row">
|
||||
<text class="edit-label">出生年月</text>
|
||||
<picker class="edit-picker" mode="date" value="{{editPatient.birth}}" end="{{today}}" bindchange="onPatientBirthChange">
|
||||
<view class="edit-input {{editPatient.birth ? '' : 'placeholder'}}">{{editPatient.birth || '请选择'}}</view>
|
||||
</picker>
|
||||
|
||||
<!-- 发丝线之上是「是谁」,之下是唯一动作:整行可点拨打 -->
|
||||
<view class="patient-contact" bindtap="onCallPatient">
|
||||
<t-icon name="call" size="30rpx" color="#9B4508" />
|
||||
<text class="patient-contact-text">{{record.patientMobile || '--'}}</text>
|
||||
</view>
|
||||
<view class="edit-row">
|
||||
<text class="edit-label">体重(kg)</text>
|
||||
<input class="edit-input" type="digit" value="{{editPatient.weight}}" placeholder="请输入" placeholder-class="input-placeholder" data-field="weight" bindinput="onPatientInfoInput" />
|
||||
</view>
|
||||
<view class="edit-row">
|
||||
<text class="edit-label">身高(cm)</text>
|
||||
<input class="edit-input" type="digit" value="{{editPatient.height}}" placeholder="请输入" placeholder-class="input-placeholder" data-field="height" bindinput="onPatientInfoInput" />
|
||||
</view>
|
||||
<view class="edit-row">
|
||||
<text class="edit-label">联系电话</text>
|
||||
<input class="edit-input" type="number" value="{{editPatient.mobile}}" placeholder="请输入" placeholder-class="input-placeholder" data-field="mobile" bindinput="onPatientInfoInput" />
|
||||
</view>
|
||||
<view class="edit-row">
|
||||
<text class="edit-label">身份证号</text>
|
||||
<input class="edit-input" value="{{editPatient.idnumber}}" placeholder="请输入" placeholder-class="input-placeholder" data-field="idnumber" bindinput="onPatientInfoInput" />
|
||||
</view>
|
||||
<view class="edit-actions">
|
||||
<view class="btn btn-ghost" bindtap="onCancelEditPatientInfo">取消</view>
|
||||
<view class="btn btn-primary" bindtap="onSavePatientInfo">保存</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 医院预约信息 -->
|
||||
<!-- 医院预约信息:医院名为标题,省份提到标题行右上角,科室/医生/病历号收进元信息行;
|
||||
预约时间收在卡末发丝线之下——日期左、时段与时长右,一行排开。修改走底部弹窗 -->
|
||||
<view class="section">
|
||||
<view class="section-head">
|
||||
<view class="section-bar"></view>
|
||||
<text class="section-title">医院预约信息</text>
|
||||
<view class="section-link" wx:if="{{record.canEditOrder}}" bindtap="onEditHospital">
|
||||
<text class="section-link-text">修改</text>
|
||||
<t-icon name="edit" size="26rpx" color="#6F655C" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">就诊省份</text>
|
||||
<text class="info-value">{{record.hospitalProvince || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">就诊医院</text>
|
||||
<text class="info-value">{{record.hospitalName || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row" wx:if="{{record.hospitalAddress}}">
|
||||
<text class="info-label">医院地址</text>
|
||||
<text class="info-value">{{record.hospitalAddress}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">就诊科室</text>
|
||||
<text class="info-value">{{record.hospitalDepartment || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row" wx:if="{{record.hospitalDoctor}}">
|
||||
<text class="info-label">就诊医生</text>
|
||||
<text class="info-value">{{record.hospitalDoctor}}</text>
|
||||
</view>
|
||||
<view class="info-row" wx:if="{{record.medicalRecordNo}}">
|
||||
<text class="info-label">病历号</text>
|
||||
<text class="info-value">{{record.medicalRecordNo}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">预约日期</text>
|
||||
<text class="info-value">{{record.scheduleDate || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">预约时间</text>
|
||||
<text class="info-value">{{record.scheduleStartTime || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row" wx:if="{{record.scheduleEndTime}}">
|
||||
<text class="info-label">结束时间</text>
|
||||
<text class="info-value">{{record.scheduleEndTime}}</text>
|
||||
</view>
|
||||
<view class="info-row" wx:if="{{record.scheduleDuration}}">
|
||||
<text class="info-label">陪诊时长</text>
|
||||
<text class="info-value">{{record.scheduleDuration}}分钟</text>
|
||||
|
||||
<view class="card hospital-card">
|
||||
<!-- 省份提到右上角,与医院名同一行:名称是主信息,省份降为右侧小字标签 -->
|
||||
<view class="hospital-head">
|
||||
<text class="hospital-name {{!record.hospitalName ? 'is-empty' : ''}}">{{record.hospitalName || '就诊医院待补充'}}</text>
|
||||
<text class="hospital-province" wx:if="{{record.hospitalProvince}}">{{record.hospitalProvince}}</text>
|
||||
</view>
|
||||
|
||||
<view class="meta-list hospital-meta" wx:if="{{record.hospitalMeta.length > 0}}">
|
||||
<block wx:for="{{record.hospitalMeta}}" wx:key="*this">
|
||||
<view class="meta-sep" wx:if="{{index > 0}}"></view>
|
||||
<text class="meta-item">{{item}}</text>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<text class="hospital-address" wx:if="{{record.hospitalAddress}}">{{record.hospitalAddress}}</text>
|
||||
|
||||
<!-- 预约时间条:日期(带星期)在左、时段与陪诊时长在右,一行排开;空值有兜底文案 -->
|
||||
<view class="schedule-row">
|
||||
<text class="schedule-date {{!record.scheduleDateText ? 'is-empty' : ''}}">{{record.scheduleDateText || '预约日期待定'}}</text>
|
||||
<text class="schedule-time" wx:if="{{record.scheduleTimeText}}">{{record.scheduleTimeText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 陪诊服务 -->
|
||||
<view class="section">
|
||||
<view class="section-head">
|
||||
<view class="section-bar"></view>
|
||||
<text class="section-title">陪诊服务</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">服务类型</text>
|
||||
<text class="info-value">{{record.escortServiceName || '陪诊服务'}}</text>
|
||||
</view>
|
||||
<view class="info-row" wx:if="{{record.sexRequirementText}}">
|
||||
<text class="info-label">性别要求</text>
|
||||
<text class="info-value">{{record.sexRequirementText}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">陪诊员</text>
|
||||
<text class="info-value">{{record.attendantName || '待分配'}}</text>
|
||||
</view>
|
||||
<view class="info-row" wx:if="{{record.attendantMobile}}">
|
||||
<text class="info-label">陪诊员电话</text>
|
||||
<text class="info-value info-link" bindtap="onCallAttendant">{{record.attendantMobile}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 陪诊需求与症状 -->
|
||||
<!-- 陪诊需求与症状:纯文本块展示,修改走底部弹窗(textarea 在弹窗里) -->
|
||||
<view class="section">
|
||||
<view class="section-head">
|
||||
<view class="section-bar"></view>
|
||||
<text class="section-title">陪诊需求与症状</text>
|
||||
<view class="section-link" wx:if="{{!editing}}" bindtap="onEditPatientNote">
|
||||
<view class="section-link" wx:if="{{record.canEditOrder}}" bindtap="onEditPatientNote">
|
||||
<text class="section-link-text">修改</text>
|
||||
<t-icon name="edit" size="26rpx" color="#9B4508" />
|
||||
<t-icon name="edit" size="26rpx" color="#6F655C" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<block wx:if="{{editing}}">
|
||||
<textarea
|
||||
class="note-textarea"
|
||||
value="{{editPatientNote}}"
|
||||
placeholder="请输入陪诊需求或症状描述"
|
||||
maxlength="500"
|
||||
placeholder-class="input-placeholder"
|
||||
bindinput="onPatientNoteInput"
|
||||
focus="{{editing}}"
|
||||
/>
|
||||
<view class="edit-actions">
|
||||
<view class="btn btn-ghost" bindtap="onCancelEdit">取消</view>
|
||||
<view class="btn btn-primary" bindtap="onSavePatientNote">保存</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<block wx:else>
|
||||
<view class="card">
|
||||
<view class="note-block" wx:if="{{record.patientNote}}">
|
||||
<text class="note-text">{{record.patientNote}}</text>
|
||||
</view>
|
||||
@@ -211,88 +127,236 @@
|
||||
<view class="note-empty" wx:if="{{!record.patientNote && !record.escortNote && !record.medicalSummary}}">
|
||||
<text class="note-empty-text">暂无备注信息</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 费用信息 -->
|
||||
<!-- 服务与费用:服务名称为主、支付状态胶囊收尾同行(仅待处理时显示,已付清不出现);
|
||||
费用行用字号差做层级(金额是全卡唯一的大字号焦点),不铺清单行;
|
||||
未付清时在费用行下补一句客服指引(全站没有线上支付入口,本页给不出可点的动作)。
|
||||
位置收在末尾:前面各块回答「服务什么」(人 → 去哪 → 要什么),
|
||||
费用与订单号同属「账与单」,连排在最后 -->
|
||||
<view class="section">
|
||||
<view class="section-head">
|
||||
<view class="section-bar"></view>
|
||||
<text class="section-title">费用信息</text>
|
||||
<text class="section-title">服务与费用</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">服务费用</text>
|
||||
<text class="info-value fee-value">¥{{record.totalFee}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">已支付</text>
|
||||
<text class="info-value">¥{{record.paidFee}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">支付状态</text>
|
||||
<view
|
||||
class="status-chip"
|
||||
style="background: {{record.paymentStatusBg}}; color: {{record.paymentStatusColor}}; border-color: {{record.paymentStatusBorder}};"
|
||||
>{{record.paymentStatusText}}</view>
|
||||
<view class="card service-card">
|
||||
<view class="service-head">
|
||||
<text class="service-name">{{record.escortServiceName || '陪诊服务'}}</text>
|
||||
<!-- 支付完成(paid)是常态不显示胶囊;只有待处理(未支付/部分支付/已退款)才提示 -->
|
||||
<view
|
||||
class="status-chip"
|
||||
wx:if="{{record.paymentStatus !== 'paid'}}"
|
||||
style="background: {{record.paymentStatusBg}}; color: {{record.paymentStatusColor}}; border-color: {{record.paymentStatusBorder}};"
|
||||
>{{record.paymentStatusText}}</view>
|
||||
</view>
|
||||
<view class="meta-list service-meta" wx:if="{{record.sexRequirementText}}">
|
||||
<text class="meta-item">陪诊师性别要求 {{record.sexRequirementText}}</text>
|
||||
</view>
|
||||
<view class="fee-row">
|
||||
<view class="fee-main">
|
||||
<text class="fee-label">服务费用</text>
|
||||
<text class="fee-amount">¥{{record.totalFee}}</text>
|
||||
</view>
|
||||
<text class="fee-paid">已支付 ¥{{record.paidFee}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 未付清时的出口指引:全站没有线上支付入口,只能引到客服;
|
||||
收在费用行之下——「已支付 ¥0.00」之后正是用户想问「怎么付」的位置 -->
|
||||
<text class="pay-hint" wx:if="{{record.paymentHint}}">{{record.paymentHint}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<!-- 订单信息:只留编号与时间,订单状态在抬头已出现一次,不重复 -->
|
||||
<view class="section">
|
||||
<view class="section-head">
|
||||
<view class="section-bar"></view>
|
||||
<text class="section-title">订单信息</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">订单编号</text>
|
||||
<text class="info-value order-id">{{record._id || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">订单状态</text>
|
||||
<view
|
||||
class="status-chip"
|
||||
style="background: {{record.statusBg}}; color: {{record.statusColor}}; border-color: {{record.statusBorder}};"
|
||||
>{{record.statusText}}</view>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">创建时间</text>
|
||||
<text class="info-value">{{record.createTime || '--'}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">更新时间</text>
|
||||
<text class="info-value">{{record.updateTime || '--'}}</text>
|
||||
<view class="card order-card">
|
||||
<text class="order-no">订单编号 {{record._id || '--'}}</text>
|
||||
<view class="meta-list order-meta">
|
||||
<text class="meta-item">创建于 {{record.createTime || '--'}}</text>
|
||||
<view class="meta-sep"></view>
|
||||
<text class="meta-item">更新于 {{record.updateTime || '--'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部占位 -->
|
||||
<view class="bottom-placeholder"></view>
|
||||
<!-- 底部占位:只为垫开固定底栏,底栏不出现时不留这段空 -->
|
||||
<view class="bottom-placeholder" wx:if="{{record.showBottomBar}}"></view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作栏:同类实心块只保留一处——
|
||||
再次预约为「已完成」时让位给「确认完成」,为「已取消」时自己成为主操作(§2.1) -->
|
||||
<view class="bottom-bar">
|
||||
再次预约为「已完成」时让位给「确认完成」,为「已取消」时自己成为主操作(§2.1)。
|
||||
四种动作都为假时整条栏不出现:进行中且已支付这类状态没有动作可给,不留空白栏 -->
|
||||
<view class="bottom-bar" wx:if="{{record.showBottomBar}}">
|
||||
<view
|
||||
class="action-btn action-ghost"
|
||||
wx:if="{{record.status === 'pending' || record.status === 'confirmed'}}"
|
||||
wx:if="{{record.canCancel}}"
|
||||
bindtap="onCancelOrder"
|
||||
>取消订单</view>
|
||||
<view
|
||||
class="action-btn action-ghost"
|
||||
wx:if="{{record.paymentStatus === 'unpaid' && record.status !== 'completed'}}"
|
||||
class="action-btn action-ghost action-danger"
|
||||
wx:if="{{record.canDelete}}"
|
||||
bindtap="onDeleteOrder"
|
||||
>删除订单</view>
|
||||
<view
|
||||
class="action-btn action-primary"
|
||||
wx:if="{{record.status === 'completed'}}"
|
||||
wx:if="{{record.canComplete}}"
|
||||
bindtap="onConfirmComplete"
|
||||
>确认完成</view>
|
||||
<view
|
||||
class="action-btn {{record.status === 'cancelled' ? 'action-primary' : 'action-ghost'}}"
|
||||
wx:if="{{record.status === 'completed' || record.status === 'cancelled'}}"
|
||||
wx:if="{{record.canRebook}}"
|
||||
bindtap="onRebook"
|
||||
>再次预约</view>
|
||||
</view>
|
||||
|
||||
<!-- 医院预约信息编辑弹窗:页面内嵌表单全部收进这里。
|
||||
弹窗比取消弹窗高(popup-tall),表单行可滚动 -->
|
||||
<view class="popup-mask {{showHospitalPopup ? 'show' : ''}}" bindtap="onCancelHospitalEdit"></view>
|
||||
<view class="popup-content popup-tall {{showHospitalPopup ? 'show' : ''}}">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">修改医院预约信息</text>
|
||||
<view class="popup-close" bindtap="onCancelHospitalEdit">
|
||||
<t-icon name="close" size="40rpx" color="#6F655C" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<view class="form-row">
|
||||
<text class="form-label">就诊省份</text>
|
||||
<picker
|
||||
class="form-picker"
|
||||
mode="selector"
|
||||
range="{{provinces}}"
|
||||
value="{{editHospital.provinceIndex}}"
|
||||
bindchange="onProvinceChange"
|
||||
>
|
||||
<view class="form-picker-value">{{editHospital.province || '请选择省份'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">就诊医院</text>
|
||||
<input
|
||||
class="form-input"
|
||||
value="{{editHospital.name}}"
|
||||
placeholder="请输入医院名称"
|
||||
placeholder-class="input-placeholder"
|
||||
bindinput="onHospitalFieldInput"
|
||||
data-field="name"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">医院地址</text>
|
||||
<input
|
||||
class="form-input"
|
||||
value="{{editHospital.address}}"
|
||||
placeholder="请输入医院地址"
|
||||
placeholder-class="input-placeholder"
|
||||
bindinput="onHospitalFieldInput"
|
||||
data-field="address"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">就诊科室</text>
|
||||
<input
|
||||
class="form-input"
|
||||
value="{{editHospital.department}}"
|
||||
placeholder="请输入就诊科室"
|
||||
placeholder-class="input-placeholder"
|
||||
bindinput="onHospitalFieldInput"
|
||||
data-field="department"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">就诊医生</text>
|
||||
<input
|
||||
class="form-input"
|
||||
value="{{editHospital.doctor}}"
|
||||
placeholder="请输入就诊医生"
|
||||
placeholder-class="input-placeholder"
|
||||
bindinput="onHospitalFieldInput"
|
||||
data-field="doctor"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">病历号</text>
|
||||
<input
|
||||
class="form-input"
|
||||
value="{{editHospital.medicalRecordNo}}"
|
||||
placeholder="请输入病历号"
|
||||
placeholder-class="input-placeholder"
|
||||
bindinput="onHospitalFieldInput"
|
||||
data-field="medicalRecordNo"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">预约日期</text>
|
||||
<picker
|
||||
class="form-picker"
|
||||
mode="date"
|
||||
value="{{editHospital.scheduleDate}}"
|
||||
bindchange="onScheduleDateChange"
|
||||
>
|
||||
<view class="form-picker-value">{{editHospital.scheduleDate || '请选择日期'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">开始时间</text>
|
||||
<picker
|
||||
class="form-picker"
|
||||
mode="time"
|
||||
value="{{editHospital.startTime}}"
|
||||
bindchange="onStartTimeChange"
|
||||
>
|
||||
<view class="form-picker-value">{{editHospital.startTime || '请选择时间'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-row">
|
||||
<text class="form-label">结束时间</text>
|
||||
<picker
|
||||
class="form-picker"
|
||||
mode="time"
|
||||
value="{{editHospital.endTime}}"
|
||||
bindchange="onEndTimeChange"
|
||||
>
|
||||
<view class="form-picker-value">{{editHospital.endTime || '请选择时间'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-footer">
|
||||
<view class="popup-btn popup-btn-ghost" bindtap="onCancelHospitalEdit">取消</view>
|
||||
<view class="popup-btn popup-btn-primary" bindtap="onSaveHospital">保存</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 陪诊需求编辑弹窗 -->
|
||||
<view class="popup-mask {{showNotePopup ? 'show' : ''}}" bindtap="onCancelEdit"></view>
|
||||
<view class="popup-content {{showNotePopup ? 'show' : ''}}">
|
||||
<view class="popup-header">
|
||||
<text class="popup-title">修改陪诊需求</text>
|
||||
<view class="popup-close" bindtap="onCancelEdit">
|
||||
<t-icon name="close" size="40rpx" color="#6F655C" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<textarea
|
||||
class="note-textarea"
|
||||
value="{{editPatientNote}}"
|
||||
placeholder="请输入陪诊需求或症状描述"
|
||||
maxlength="500"
|
||||
placeholder-class="input-placeholder"
|
||||
bindinput="onPatientNoteInput"
|
||||
focus="{{showNotePopup}}"
|
||||
/>
|
||||
</view>
|
||||
<view class="popup-footer">
|
||||
<view class="popup-btn popup-btn-ghost" bindtap="onCancelEdit">取消</view>
|
||||
<view class="popup-btn popup-btn-primary" bindtap="onSavePatientNote">保存</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 取消订单弹窗 -->
|
||||
<view class="popup-mask {{showCancelPopup ? 'show' : ''}}" bindtap="onCloseCancelPopup"></view>
|
||||
<view class="popup-content {{showCancelPopup ? 'show' : ''}}">
|
||||
@@ -303,7 +367,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<text class="cancel-tip">确定要取消该陪诊订单吗?取消后陪诊员将收到通知。</text>
|
||||
<text class="cancel-tip">确定要取消该陪诊订单吗?取消后陪诊师将收到通知。</text>
|
||||
<view class="cancel-reason-list">
|
||||
<view
|
||||
class="cancel-reason-item {{cancelReason === item ? 'active' : ''}}"
|
||||
@@ -324,4 +388,4 @@
|
||||
<view class="popup-btn popup-btn-primary" bindtap="onConfirmCancel">确认取消</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
+357
-152
@@ -1,12 +1,17 @@
|
||||
/* pages/escort/recorddetail.wxss
|
||||
设计方向:本页是一张陪诊订单的详情,按「状态 → 就诊人 → 医院 → 服务 → 需求 → 费用 → 订单」的顺序铺开。
|
||||
- 配色并入全站暖橙体系(doc/DESIGN.md):令牌来自 app.wxss,本页不再留副本;
|
||||
设计方向:本页是一张陪诊订单的详情,按「状态抬头 → 就诊人 → 医院预约 → 需求与症状 → 服务与费用 → 订单」铺开。
|
||||
- 配色并入全站暖橙体系(doc/DESIGN.md):令牌来自 app.wxss,本页不留副本;
|
||||
状态色只用 §三 四档,旧版渐变横幅与金色体系全部移除
|
||||
- 头部:短横色标 + 状态胶囊 + 状态说明(内页规范,不做整块主色面板)
|
||||
- 分区:发丝线切分,标题走统一的 8×34rpx 单竖条 .section-bar
|
||||
- 表单:标签 --muted + 值 --ink 700;选中项走浅橙底 + 实心橙描边
|
||||
- 按钮:底栏主操作实心胶囊,其余为空心胶囊;同类实心块全页只保留一处(§2.1)
|
||||
- 字号阶梯:34 分节标题 / 28 正文 · 表单 / 26 标签 / 24 元信息,最小 24rpx(12px) */
|
||||
- 抬头:短横色标 + 状态胶囊 + 状态说明,是唯一的非卡片区(内页规范,不做整块主色面板);
|
||||
下方用 2rpx --line 通栏发丝线收口,靠字号两档差(32 胶囊 / 26 说明)与留白立住,不套第二套容器
|
||||
- 分区:标题在纸面上(8×32rpx 单竖条),内容统一收进同一种白卡
|
||||
(§2.3:2rpx --line + 中性阴影 --shadow-card;圆角本页取 24rpx 为例外,见下方 .card 注释)
|
||||
- 展示去表单化:不铺「标签左/值右」清单行,层级由结构给出——
|
||||
就诊人用首字牌、医院预约用预约时间条、费用用字号差;元信息一律竖线分隔行
|
||||
- 编辑全部收进底部弹窗:页面只读,表单只活在弹窗里
|
||||
- 按钮:底栏与弹窗的主操作实心胶囊、其余空心胶囊,同类实心块全页只保留一处(§2.1)
|
||||
- 字号阶梯:40 首字牌 / 32 分节标题 · 卡片主名 · 金额 · 状态胶囊 / 28 服务名 · 备注正文 · 预约日期
|
||||
/ 26 次强 · 「修改」入口 · 预约时段 · 订单号 / 24 元信息 · 已支付 · 支付指引,最小 24rpx(12px) */
|
||||
page {
|
||||
background-color: var(--paper);
|
||||
|
||||
@@ -23,9 +28,15 @@ page {
|
||||
padding: 0 32rpx 40rpx;
|
||||
}
|
||||
|
||||
/* ===== 头部状态 ===== */
|
||||
/* ===== 抬头状态 ===== */
|
||||
.page-header {
|
||||
padding-top: 32rpx;
|
||||
/* 抬头自成一区,靠空间 + 一条线立住,不引入第二套容器语言:
|
||||
上方留白 40rpx(比卡间距 48rpx 略紧,让抬头贴住顶栏而非浮在中间);
|
||||
左右负 margin 抵消 .container 的 32rpx 内距,使下方发丝线通栏顶到屏幕两侧,
|
||||
同时用 padding 把色标与胶囊重新拉回卡片同一条左对齐线 */
|
||||
margin: 0 -32rpx;
|
||||
padding: 40rpx 32rpx 28rpx;
|
||||
border-bottom: 2rpx solid var(--line);
|
||||
}
|
||||
|
||||
.header-accent {
|
||||
@@ -37,6 +48,8 @@ page {
|
||||
|
||||
.status-row {
|
||||
margin-top: 22rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 状态胶囊:底色 + 描边 + 字色三件套,颜色只做强化,文字才是信息(§三) */
|
||||
@@ -55,42 +68,46 @@ page {
|
||||
|
||||
.status-chip-lg {
|
||||
padding: 8rpx 22rpx;
|
||||
font-size: 28rpx;
|
||||
/* 28rpx 抬到 32rpx:与分节标题、卡片主名同档。
|
||||
同字号下胶囊靠状态底色 + 2rpx 描边 + 内距压过裸字标题,
|
||||
层级才回到「单据抬头 > 卡片标题」,不再是从前抬头比它统领的内容还小 */
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.header-subtitle {
|
||||
display: block;
|
||||
margin-top: 14rpx;
|
||||
font-size: 28rpx;
|
||||
margin-left: 20rpx;
|
||||
/* 28rpx 降到 26rpx:说明退到「次强」档,与 32rpx 的胶囊拉开一档差,
|
||||
抬头内部才有焦点;此前两者同为 28rpx,只靠字重区分,谁都不是主角 */
|
||||
font-size: 26rpx;
|
||||
color: var(--muted);
|
||||
line-height: 1.6;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* ===== 分区:发丝线 + 单竖条标题 ===== */
|
||||
/* ===== 分区:纸面留白分隔,标题在纸面上、内容在白卡里 ===== */
|
||||
.section {
|
||||
margin-top: 44rpx;
|
||||
padding-top: 30rpx;
|
||||
border-top: 2rpx solid var(--line);
|
||||
margin-top: 48rpx;
|
||||
}
|
||||
|
||||
.section-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.section-bar {
|
||||
flex-shrink: 0;
|
||||
width: 8rpx;
|
||||
height: 34rpx;
|
||||
/* 色标高度跟随标题字号,缩字号时同步收,保持「短横 + 标题」的等高一档 */
|
||||
height: 32rpx;
|
||||
border-radius: 4rpx;
|
||||
background: var(--brand-strong);
|
||||
}
|
||||
|
||||
/* 34rpx 降一档到 32rpx:与 attendantdetail / agreement / about 的分区标题同一档,
|
||||
不新增字号档位(DESIGN.md 字号阶梯) */
|
||||
.section-title {
|
||||
margin-left: 16rpx;
|
||||
font-size: 34rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
letter-spacing: 1rpx;
|
||||
@@ -108,166 +125,294 @@ page {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* 「修改」降为中性字:全页三处入口若都用暖橙,会和所在行的标题抢注意力,
|
||||
一个分组标题下不该有两个同权重焦点。入口靠位置(标题行右端)和热区成立,
|
||||
不靠颜色——颜色留给底栏主按钮 */
|
||||
.section-link-text {
|
||||
margin-right: 4rpx;
|
||||
font-size: 24rpx;
|
||||
color: var(--brand-ink);
|
||||
}
|
||||
|
||||
/* ===== 信息行(只读) ===== */
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
padding: 18rpx 0;
|
||||
border-bottom: 2rpx solid var(--line);
|
||||
}
|
||||
|
||||
.info-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
flex-shrink: 0;
|
||||
/* 26rpx 与图标同档:入口降为中性的同时留一点体量,
|
||||
避免和卡片正文(26rpx)拉开层级后又退到看不清 */
|
||||
font-size: 26rpx;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.info-value {
|
||||
/* ===== 白卡:全页唯一的容器语言(§2.3 主规则) =====
|
||||
2rpx --line 发丝边、中性阴影 --shadow-card;
|
||||
卡内首尾留白由卡片自己的 padding 给。
|
||||
本页例外(已登记):圆角取 24rpx 而非 §2.3 的 28rpx——
|
||||
与卡内首字牌(24rpx)同档,圆角家族内部不倒挂;
|
||||
注意全站其余九页的白卡仍是 28rpx,从订单列表切进本页时卡片会略方一点 */
|
||||
.card {
|
||||
box-sizing: border-box;
|
||||
margin-top: 16rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
background: var(--white);
|
||||
border: 2rpx solid var(--line);
|
||||
border-radius: 24rpx;
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
/* ===== 通用元信息行:竖线分隔,空值已在 JS 整项剔除 ===== */
|
||||
.meta-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
font-size: 24rpx;
|
||||
color: var(--muted);
|
||||
letter-spacing: 1rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 元信息竖线:2rpx×20rpx,取 --sep(比 --line 深一档,白卡与纸面上都看得见) */
|
||||
.meta-sep {
|
||||
flex-shrink: 0;
|
||||
width: 2rpx;
|
||||
height: 20rpx;
|
||||
margin: 0 14rpx;
|
||||
background: var(--sep);
|
||||
}
|
||||
|
||||
/* ===== 就诊人卡:首字牌 + 元信息行 + 发丝线下的拨打动作 ===== */
|
||||
.patient-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 首字牌:浅橙衬底 + --brand-line 描边,与陪诊师列表的兜底头像同源 */
|
||||
.patient-mark {
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border: 2rpx solid var(--brand-line);
|
||||
border-radius: 24rpx;
|
||||
background: var(--brand-soft);
|
||||
}
|
||||
|
||||
.patient-mark-text {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: var(--brand-ink);
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* 首字牌右侧纵列:姓名 / 体征元信息 / 证件号自上而下 */
|
||||
.patient-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 24rpx;
|
||||
text-align: right;
|
||||
font-size: 28rpx;
|
||||
color: var(--ink-2);
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
/* 姓名 32rpx/700:低于区块标题 34rpx 一档,不与标题争层级 */
|
||||
.patient-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.patient-meta-row {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
/* 身份证 18 位,折行而不是撑破卡片 */
|
||||
.patient-id {
|
||||
display: block;
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: var(--muted);
|
||||
letter-spacing: 1rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.info-link {
|
||||
/* 发丝线之上是「是谁」,之下是「怎么联系」;整行即热区 */
|
||||
.patient-contact {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 22rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 2rpx solid var(--line);
|
||||
}
|
||||
|
||||
.patient-contact-text {
|
||||
margin-left: 10rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: var(--brand-ink);
|
||||
font-weight: 700;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.fee-value {
|
||||
.patient-contact:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* ===== 医院预约卡:日历牌是全卡视觉锚点 ===== */
|
||||
.hospital-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.hospital-name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
letter-spacing: 1rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.hospital-name.is-empty {
|
||||
font-weight: 400;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.hospital-province {
|
||||
margin-left: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: var(--muted);
|
||||
letter-spacing: 1rpx;
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.hospital-meta {
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.hospital-address {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: var(--muted);
|
||||
letter-spacing: 1rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 预约时间条:发丝线之上是「去哪看」,之下是「什么时候看」——日期左、时段右 */
|
||||
.schedule-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
margin-top: 22rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 2rpx solid var(--line);
|
||||
}
|
||||
|
||||
.schedule-date {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.schedule-date.is-empty {
|
||||
font-weight: 400;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.schedule-time {
|
||||
margin-left: 20rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: var(--brand-ink);
|
||||
letter-spacing: 1rpx;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ===== 服务与费用卡:金额是全卡唯一的大字号焦点 ===== */
|
||||
.service-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.service-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.service-meta {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.fee-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
margin-top: 18rpx;
|
||||
padding-top: 18rpx;
|
||||
border-top: 2rpx solid var(--line);
|
||||
}
|
||||
|
||||
.fee-main {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.fee-label {
|
||||
font-size: 26rpx;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.fee-amount {
|
||||
margin-left: 16rpx;
|
||||
/* 34rpx 降一档到 32rpx,与分区标题同一档,不新增字号档位;
|
||||
仍明显高于标签(26rpx)与「已支付」(24rpx),保住金额在卡内的大字号焦点地位 */
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: var(--brand-strong);
|
||||
font-weight: 700;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.order-id {
|
||||
.fee-paid {
|
||||
font-size: 24rpx;
|
||||
color: var(--muted);
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
/* ===== 表单行(编辑态) ===== */
|
||||
.edit-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 2rpx solid var(--line);
|
||||
}
|
||||
|
||||
.edit-label {
|
||||
flex-shrink: 0;
|
||||
font-size: 28rpx;
|
||||
/* 未付清时的出口指引:与元信息同一档(24rpx / --muted),只做说明不做按钮——
|
||||
付款动作发生在客服侧,本页给不出可点的东西,硬做描边按钮会是空动作 */
|
||||
.pay-hint {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
font-size: 24rpx;
|
||||
color: var(--muted);
|
||||
letter-spacing: 1rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.edit-picker {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
/* 选择器内层已由 .edit-picker 让出间距,内层值不再重复缩进 */
|
||||
.edit-picker .edit-input {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.edit-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 24rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.edit-input.placeholder {
|
||||
font-weight: 400;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.input-placeholder {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.edit-radio-group {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
/* 选中项:浅橙底 + 实心橙描边(表单选中语言) */
|
||||
.edit-radio {
|
||||
padding: 8rpx 28rpx;
|
||||
border: 2rpx solid var(--line);
|
||||
border-radius: 999rpx;
|
||||
/* ===== 订单卡:编号为主,时间收进元信息行 ===== */
|
||||
.order-no {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
color: var(--muted);
|
||||
background: transparent;
|
||||
color: var(--ink-2);
|
||||
letter-spacing: 1rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.edit-radio.active {
|
||||
background: var(--brand-soft);
|
||||
border-color: var(--brand-strong);
|
||||
color: var(--brand-ink);
|
||||
font-weight: 700;
|
||||
.order-meta {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
/* ===== 按键:空心胶囊 / 实心胶囊 ===== */
|
||||
.edit-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 16rpx;
|
||||
margin-top: 28rpx;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16rpx 44rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
border: 3rpx solid var(--sep);
|
||||
color: var(--muted);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--brand-strong);
|
||||
color: var(--white);
|
||||
font-weight: 700;
|
||||
box-shadow: var(--shadow-cta);
|
||||
}
|
||||
|
||||
/* ===== 备注 ===== */
|
||||
/* ===== 备注(只读文本块) ===== */
|
||||
.note-block {
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
.note-block:first-child {
|
||||
margin-top: 6rpx;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.note-label {
|
||||
@@ -286,8 +431,7 @@ page {
|
||||
}
|
||||
|
||||
.note-empty {
|
||||
margin-top: 6rpx;
|
||||
padding: 24rpx 0;
|
||||
padding: 6rpx 0;
|
||||
}
|
||||
|
||||
.note-empty-text {
|
||||
@@ -295,11 +439,52 @@ page {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ===== 表单行:只活在编辑弹窗里 =====
|
||||
行结构仍是「标签左、值右、发丝线分隔」,但它是弹窗内的输入语境,不是页面展示语言 */
|
||||
.form-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 72rpx;
|
||||
padding: 12rpx 0;
|
||||
border-bottom: 2rpx solid var(--line);
|
||||
}
|
||||
|
||||
.form-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
flex-shrink: 0;
|
||||
font-size: 26rpx;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.form-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: var(--ink);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.form-picker {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
.form-picker-value {
|
||||
font-size: 28rpx;
|
||||
color: var(--ink);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.note-textarea {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
min-height: 200rpx;
|
||||
margin-top: 6rpx;
|
||||
padding: 24rpx;
|
||||
border: 2rpx solid var(--line);
|
||||
border-radius: 16rpx;
|
||||
@@ -309,6 +494,10 @@ page {
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.input-placeholder {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ===== 底部占位与操作栏 ===== */
|
||||
.bottom-placeholder {
|
||||
height: 160rpx;
|
||||
@@ -322,7 +511,6 @@ page {
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16rpx;
|
||||
padding: 20rpx 32rpx;
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
@@ -331,7 +519,10 @@ page {
|
||||
box-shadow: var(--shadow-bar);
|
||||
}
|
||||
|
||||
/* 按钮等宽铺满:与同页弹窗脚(.popup-btn 的 flex:1)同一套排布,
|
||||
热区也更大;单个按钮时即整条通栏主操作 */
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -351,6 +542,12 @@ page {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 破坏性动作:只换字色为状态色「已取消」档(#B4231A 已在色板内,不新增色相),
|
||||
与并排的取消订单区分开——删除不可恢复,确认弹窗也已走同色 */
|
||||
.action-danger {
|
||||
color: #B4231A;
|
||||
}
|
||||
|
||||
.action-primary {
|
||||
background: var(--brand-strong);
|
||||
color: var(--white);
|
||||
@@ -358,7 +555,7 @@ page {
|
||||
box-shadow: var(--shadow-cta);
|
||||
}
|
||||
|
||||
/* ===== 取消订单弹窗 ===== */
|
||||
/* ===== 底部弹窗(编辑与取消共用一套骨架) ===== */
|
||||
.popup-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
@@ -392,6 +589,11 @@ page {
|
||||
transition: transform 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* 医院预约编辑有 9 行表单,弹窗加高 */
|
||||
.popup-content.popup-tall {
|
||||
max-height: 86vh;
|
||||
}
|
||||
|
||||
.popup-content.show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
@@ -400,6 +602,7 @@ page {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-shrink: 0;
|
||||
padding: 28rpx 32rpx;
|
||||
border-bottom: 2rpx solid var(--line);
|
||||
}
|
||||
@@ -422,9 +625,10 @@ page {
|
||||
.popup-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 28rpx 32rpx;
|
||||
padding: 20rpx 32rpx 28rpx;
|
||||
}
|
||||
|
||||
/* ===== 取消订单弹窗内的原因单选 ===== */
|
||||
.cancel-tip {
|
||||
font-size: 28rpx;
|
||||
color: var(--muted);
|
||||
@@ -481,6 +685,7 @@ page {
|
||||
.popup-footer {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
flex-shrink: 0;
|
||||
padding: 20rpx 32rpx;
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
border-top: 2rpx solid var(--line);
|
||||
@@ -510,4 +715,4 @@ page {
|
||||
background: var(--brand-strong);
|
||||
color: var(--white);
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
+28
-35
@@ -10,6 +10,11 @@ const STATUS_MAP = {
|
||||
cancelled: { text: '已取消', color: '#B4231A', bg: '#FCF0EE', border: '#F2D6D1' }
|
||||
}
|
||||
|
||||
// 「进行中的」= 未完成全部:待确认 / 已确认 / 进行中 都还没结束,
|
||||
// 只是处在预约的不同阶段;只有已完成、已取消才算结束。
|
||||
// 全局筛选只分「全部预约 / 进行中的」两档,卡片上的状态胶囊仍按 STATUS_MAP 逐档显示
|
||||
const ONGOING_STATUSES = ['pending', 'confirmed', 'in_progress']
|
||||
|
||||
const TYPE_MAP = {
|
||||
outpatient: '门诊陪诊',
|
||||
inpatient: '住院陪诊',
|
||||
@@ -41,24 +46,23 @@ Page({
|
||||
hasMore: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
statusFilter: '',
|
||||
// 供筛选条 scroll-into-view 使用,滑动切换后把选中胶囊滚入可视区
|
||||
tabIntoView: '',
|
||||
// 默认落在左格「进行中的」:用户进记录页首先要看的是手上还没结束的单子
|
||||
statusFilter: 'ongoing',
|
||||
// 跟手位移(px)与拖动标记:拖动中内容随手左右移动,松手后弹回
|
||||
dragX: 0,
|
||||
dragging: false,
|
||||
// 两段等宽:左 = 进行中的,右 = 全部预约;顺序即 index 顺序,滑动切换按 index 递增递减
|
||||
statusTabs: [
|
||||
{ value: '', label: '全部', count: 0 },
|
||||
{ value: 'pending', label: '待确认', count: 0 },
|
||||
{ value: 'confirmed', label: '已确认', count: 0 },
|
||||
{ value: 'in_progress', label: '进行中', count: 0 },
|
||||
{ value: 'completed', label: '已完成', count: 0 }
|
||||
{ value: 'ongoing', label: '进行中的', count: 0 },
|
||||
{ value: '', label: '全部预约', count: 0 }
|
||||
]
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
const tab = options.tab || ''
|
||||
this.setData({ statusFilter: tab })
|
||||
// tab 来自 URL,只接受当前两档内的值,避免旧参数(如 tab=pending)把列表筛空
|
||||
const tab = options.tab || this.data.statusFilter
|
||||
const valid = this.data.statusTabs.some(item => item.value === tab)
|
||||
this.setData({ statusFilter: valid ? tab : this.data.statusFilter })
|
||||
this.loadRecords(true)
|
||||
},
|
||||
|
||||
@@ -96,20 +100,14 @@ Page({
|
||||
pageSize: this.data.pageSize
|
||||
}
|
||||
|
||||
if (this.data.statusFilter) {
|
||||
//params.status = this.data.statusFilter
|
||||
}
|
||||
|
||||
return API.escort.getMyRecords(params)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
let list = res.data.records || []
|
||||
let formatted = list.map(item => this.formatRecord(item))
|
||||
// 计数按当前页全量算,再按筛选档裁剪展示,保证两档的角标口径一致
|
||||
const statusTabs = this.computeStatusCounts(formatted, this.data.statusTabs)
|
||||
// 根据this.data.formatted
|
||||
if (this.data.statusFilter) {
|
||||
formatted = formatted.filter(item => item.status === this.data.statusFilter)
|
||||
}
|
||||
formatted = formatted.filter(item => this.matchStatusFilter(item, this.data.statusFilter))
|
||||
this.setData({
|
||||
records: reset ? formatted : this.data.records.concat(formatted),
|
||||
page,
|
||||
@@ -128,19 +126,17 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// 两档筛选的唯一判定处:'' = 全部预约,'ongoing' = 未完成的三种状态
|
||||
matchStatusFilter(record, filter) {
|
||||
if (!filter) return true
|
||||
if (filter === 'ongoing') return ONGOING_STATUSES.indexOf(record.status) > -1
|
||||
return record.status === filter
|
||||
},
|
||||
|
||||
computeStatusCounts(records, tabs) {
|
||||
tabs.forEach(tab => {
|
||||
tab.count = 0
|
||||
})
|
||||
tabs[0].count = records.length
|
||||
records.forEach(item => {
|
||||
tabs.forEach(tab => {
|
||||
if (tab.value === item.status) {
|
||||
tab.count++
|
||||
}
|
||||
})
|
||||
})
|
||||
return tabs
|
||||
return tabs.map(tab => Object.assign({}, tab, {
|
||||
count: records.filter(item => this.matchStatusFilter(item, tab.value)).length
|
||||
}))
|
||||
},
|
||||
|
||||
formatRecord(item) {
|
||||
@@ -187,14 +183,11 @@ Page({
|
||||
this.switchStatusTab(Number(e.currentTarget.dataset.index))
|
||||
},
|
||||
|
||||
// 统一的状态页切换入口:点胶囊与左右滑动都走这里
|
||||
// 统一的状态页切换入口:点分段与左右滑动都走这里
|
||||
switchStatusTab(index) {
|
||||
const tab = this.data.statusTabs[index]
|
||||
if (!tab || tab.value === this.data.statusFilter) return
|
||||
this.setData({
|
||||
statusFilter: tab.value,
|
||||
tabIntoView: `tab-${index}`
|
||||
})
|
||||
this.setData({ statusFilter: tab.value })
|
||||
this.loadRecords(true)
|
||||
},
|
||||
|
||||
|
||||
@@ -1,32 +1,24 @@
|
||||
<view class="page-bg">
|
||||
|
||||
<!-- 状态筛选:吸顶横滑胶囊。
|
||||
选中态 = 浅橙底 + 2rpx 实心橙描边 + 暖橙字(全页唯一「选中」语言);
|
||||
未选中 = 纸面安静胶囊(透明底 + 发丝边 + --muted 字)。
|
||||
胶囊必须带文字标签,颜色只做强化(DESIGN.md §四.8) -->
|
||||
<!-- 状态筛选:吸顶两段式分段控件。
|
||||
只有两档,横滑胶囊没有意义(两根胶囊横着摆会显得松散、且左右都不占满),
|
||||
改为等宽两段:一个白底胶囊容器(发丝边 + 紧阴影)内分两格,
|
||||
选中格 = 浅橙底 + 暖橙字(全页唯一「选中」语言),未选中格 = --muted 字。
|
||||
选中格不再单独描边——容器已有发丝边,内层再描一圈会出现双描边;
|
||||
两段必须带文字标签,颜色只做强化(DESIGN.md §四.8) -->
|
||||
<view class="tabs-bar">
|
||||
<!-- scroll-into-view 让左右滑动切换后,选中胶囊自动滚入可视区 -->
|
||||
<scroll-view
|
||||
class="tabs-scroll"
|
||||
scroll-x
|
||||
scroll-with-animation
|
||||
scroll-into-view="{{tabIntoView}}"
|
||||
show-scrollbar="{{false}}"
|
||||
>
|
||||
<view class="tabs">
|
||||
<view
|
||||
id="tab-{{index}}"
|
||||
class="tab {{statusFilter === item.value ? 'active' : ''}}"
|
||||
wx:for="{{statusTabs}}"
|
||||
wx:key="value"
|
||||
data-index="{{index}}"
|
||||
bindtap="onTabChange"
|
||||
>
|
||||
<text class="tab-label">{{item.label}}</text>
|
||||
<text class="tab-count" wx:if="{{item.count > 0}}">{{item.count}}</text>
|
||||
</view>
|
||||
<view class="seg">
|
||||
<view
|
||||
class="seg-item {{statusFilter === item.value ? 'active' : ''}}"
|
||||
wx:for="{{statusTabs}}"
|
||||
wx:key="label"
|
||||
data-index="{{index}}"
|
||||
bindtap="onTabChange"
|
||||
>
|
||||
<text class="seg-label">{{item.label}}</text>
|
||||
<text class="seg-count" wx:if="{{item.count > 0}}">{{item.count}}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 记录区承载左右滑动手势:横向拖动时内容跟手平移做反馈,纵向滑动仍交给页面滚动 -->
|
||||
@@ -96,11 +88,12 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<!-- 空状态:两档口径不同,文案跟着当前档走,
|
||||
避免「进行中的」为空时误报成「您还没有预约陪诊服务」 -->
|
||||
<view class="empty-state" wx:if="{{!loading && records.length === 0}}">
|
||||
<t-icon name="file-unknown" size="120rpx" color="#A79C92" />
|
||||
<text class="empty-text">暂无陪诊记录</text>
|
||||
<text class="empty-subtext">您还没有预约陪诊服务</text>
|
||||
<text class="empty-text">{{statusFilter ? '暂无进行中的预约' : '暂无陪诊记录'}}</text>
|
||||
<text class="empty-subtext">{{statusFilter ? '已结束的预约可在「全部预约」里查看' : '您还没有预约陪诊服务'}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 加载中 -->
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
设计方向:本页是「一单一卡」的预约记录表,扫读优先。
|
||||
- 配色并入全站暖橙体系(doc/DESIGN.md):令牌来自 app.wxss,本页不再留副本;
|
||||
状态色只用 §三 四档,旧的金色体系与全部渐变已移除
|
||||
- 顶部筛选做成吸顶横滑胶囊:选中态 = 浅橙底 + 2rpx 实心橙描边 + 暖橙字,
|
||||
未选中 = 纸面安静胶囊;胶囊带文字标签,颜色只做强化(§四.8)
|
||||
- 顶部筛选做成吸顶两段式分段控件(只有「进行中的 / 全部预约」两档):
|
||||
白底胶囊容器(发丝边 + 紧阴影)内两格等宽,选中格 = 浅橙底 + 暖橙字,
|
||||
未选中格 = --muted 字;两格带文字标签,颜色只做强化(§四.8)
|
||||
- 卡面走「白底 + 发丝边 + 紧阴影」(中性 --shadow-card,28rpx 圆角),
|
||||
与首页、清单页同一套白面语言
|
||||
- 卡内四段:类型 + 状态 → 时间 → 就诊信息 → 费用 + 支付状态;
|
||||
长文本(需求、陪诊记录)交给详情页,保证每张卡一眼看完
|
||||
- 形状锁定:卡 28rpx、状态胶囊 10rpx、筛选胶囊 999rpx
|
||||
- 形状锁定:卡 28rpx、状态胶囊 10rpx、分段控件 999rpx
|
||||
- 左右滑动切换状态页:记录区横向拖动时跟手平移(有阻尼与上限),
|
||||
松手弹回;拖动中关过渡保即时响应,松手后由过渡做回弹
|
||||
- 字号阶梯:费用 34 / 类型 30 / 就诊信息 28 / 时间 · 胶囊 24(rpx),
|
||||
@@ -33,59 +34,66 @@ page {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
/* ===== 顶部筛选:吸顶横滑 ===== */
|
||||
/* ===== 顶部筛选:吸顶两段式分段控件 ===== */
|
||||
.tabs-bar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
padding: 20rpx 0 12rpx;
|
||||
padding: 20rpx 32rpx 16rpx;
|
||||
background: var(--paper);
|
||||
}
|
||||
|
||||
.tabs-scroll {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
padding: 12rpx 26rpx;
|
||||
/* 容器走白面语言:白底 + 发丝边 + 紧阴影,与下方记录卡同源,
|
||||
让筛选条从纸面上拎起来,不再是一排浮在纸面上的空心胶囊 */
|
||||
.seg {
|
||||
display: flex;
|
||||
padding: 6rpx;
|
||||
border: 2rpx solid var(--line);
|
||||
border-radius: 999rpx;
|
||||
background: transparent;
|
||||
transition: background-color 0.15s ease;
|
||||
background: var(--white);
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
.tab:active {
|
||||
/* 两格等宽:容器内距各 32rpx 后可用宽 622rpx,一格 305rpx,
|
||||
四字标签(28rpx)+ 角标横向只占约 150rpx,居中后左右留白充足 */
|
||||
.seg-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
padding: 14rpx 0;
|
||||
border-radius: 999rpx;
|
||||
/* 只过渡颜色:选中格靠底色块平移切换,不做位移动画(两格等宽无需滑块) */
|
||||
transition: background-color 0.18s ease;
|
||||
}
|
||||
|
||||
.seg-item:active {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.tab-label {
|
||||
font-size: 26rpx;
|
||||
.seg-label {
|
||||
font-size: 28rpx;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.tab-count {
|
||||
margin-left: 6rpx;
|
||||
.seg-count {
|
||||
margin-left: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* 选中:浅橙底 + 实心橙描边 + 暖橙字(浅橙底 5.96:1,过 AA) */
|
||||
.tab.active {
|
||||
/* 选中:浅橙底 + 暖橙字(浅橙底 5.96:1,过 AA)。
|
||||
内层不描边——容器已有发丝边,再描一圈会成双描边 */
|
||||
.seg-item.active {
|
||||
background: var(--brand-soft);
|
||||
border-color: var(--brand-strong);
|
||||
}
|
||||
|
||||
.tab.active .tab-label,
|
||||
.tab.active .tab-count {
|
||||
.seg-item.active .seg-label {
|
||||
color: var(--brand-ink);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.seg-item.active .seg-count {
|
||||
color: var(--brand-ink);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user