This commit is contained in:
lik
2026-06-04 09:14:50 +08:00
parent c121ebdb94
commit 535827b17b
19 changed files with 1648 additions and 251 deletions

View File

@@ -120,4 +120,9 @@
</view>
</view>
</view>
<!-- AI声明 -->
<view class="ai-disclaimer">
<text>本服务为AI生成内容结果仅供参考。</text>
</view>
</view>

View File

@@ -275,4 +275,17 @@
.send-btn.active {
background: linear-gradient(135deg, #FF9B33 0%, #FF7A33 100%);
}
/* AI声明 */
.ai-disclaimer {
padding: 12rpx 24rpx;
padding-bottom: calc(12rpx + env(safe-area-inset-bottom));
text-align: center;
background-color: #F5F5F5;
}
.ai-disclaimer text {
font-size: 22rpx;
color: #CCCCCC;
}

View File

@@ -237,15 +237,13 @@ Page({
escort: {
serviceId: service.id,
serviceName: service.title,
sexRequirement: sex
},
hospital: {
province: province,
name: hospital.trim(),
department: department.trim(),
},
attendant: {
sex: sex,
},
schedule: {
date: appointmentDate,
startTime: appointmentTime
@@ -274,6 +272,7 @@ Page({
showOrderPopup: false
})
this.resetForm()
wx.navigateTo({url: '/pages/escort/recordlist?tab=pending'})
} else {
wx.showToast({
title: data.msg || '下单失败',

View File

@@ -0,0 +1,396 @@
const API = require('../../utils/api.js')
const STATUS_MAP = {
pending: { text: '待确认', color: '#F59E0B', bg: '#FEF3C7', gradient: 'linear-gradient(135deg, #F59E0B 0%, #D97706 100%)', icon: 'time', desc: '您的订单已提交,等待确认中' },
confirmed: { text: '已确认', color: '#3B82F6', bg: '#DBEAFE', gradient: 'linear-gradient(135deg, #3B82F6 0%, #2563EB 100%)', icon: 'check-circle', desc: '订单已确认,陪诊员将准时为您服务' },
in_progress: { text: '进行中', color: '#8B5CF6', bg: '#EDE9FE', gradient: 'linear-gradient(135deg, #8B5CF6 0%, #7C3AED 100%)', icon: 'play-circle', desc: '陪诊服务正在进行中' },
completed: { text: '已完成', color: '#10B981', bg: '#D1FAE5', gradient: 'linear-gradient(135deg, #10B981 0%, #059669 100%)', icon: 'check-circle-filled', desc: '陪诊服务已完成,感谢您的使用' },
cancelled: { text: '已取消', color: '#6B7280', bg: '#F3F4F6', gradient: 'linear-gradient(135deg, #9CA3AF 0%, #6B7280 100%)', icon: 'close-circle', desc: '该订单已取消' }
}
const PAYMENT_STATUS_MAP = {
unpaid: { text: '未支付', color: '#F59E0B', bg: '#FEF3C7' },
partial: { text: '部分支付', color: '#F59E0B', bg: '#FEF3C7' },
paid: { text: '已支付', color: '#10B981', bg: '#D1FAE5' },
refunded: { text: '已退款', color: '#6B7280', bg: '#F3F4F6' }
}
const SEX_MAP = {
male: '男',
female: '女'
}
const ATTENDANT_SEX_MAP = {
none: '不限',
male: '男',
female: '女'
}
Page({
data: {
recordId: '',
record: {},
loading: true,
editing: false,
editPatientNote: '',
editingPatient: false,
editPatient: {},
showCancelPopup: false,
cancelReason: '',
cancelReasons: [
'临时有事,无法前往',
'病情好转,无需陪诊',
'医院停诊/改期',
'陪诊员无法到达',
'其他原因'
]
},
onLoad(options) {
const id = options.id
if (!id) {
wx.showToast({ title: '参数错误', icon: 'none' })
setTimeout(() => wx.navigateBack(), 1500)
return
}
this.setData({ recordId: id })
this.loadRecord(id)
},
onShow() {
if (this.data.recordId) {
this.loadRecord(this.data.recordId)
}
},
onPullDownRefresh() {
if (this.data.recordId) {
this.loadRecord(this.data.recordId).finally(() => {
wx.stopPullDownRefresh()
})
}
},
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 })
} else {
wx.showToast({ title: res.msg || '加载失败', icon: 'none' })
}
})
.catch(() => {
wx.showToast({ title: '网络请求失败', icon: 'none' })
})
.finally(() => {
this.setData({ loading: false })
})
},
formatRecord(item) {
const statusInfo = STATUS_MAP[item.status] || STATUS_MAP.pending
const paymentInfo = PAYMENT_STATUS_MAP[item.payment?.status] || PAYMENT_STATUS_MAP.unpaid
return {
_id: item._id,
patientName: item.patient?.name || '',
patientSexText: SEX_MAP[item.patient?.sex] || '',
patientAge: item.patient?.age || 0,
patientWeight: item.patient?.weight || 0,
patientHeight: item.patient?.height || 0,
patientMobile: item.patient?.mobile || '',
patientIdnumber: item.patient?.idnumber || '',
hospitalProvince: item.hospital?.province || '',
hospitalName: item.hospital?.name || '',
hospitalAddress: item.hospital?.address || '',
hospitalDepartment: item.hospital?.department || '',
hospitalDoctor: item.hospital?.doctor || '',
medicalRecordNo: item.hospital?.medicalRecordNo || '',
scheduleDate: item.schedule?.date ? this.formatDate(item.schedule.date) : '',
scheduleStartTime: item.schedule?.startTime || '',
scheduleEndTime: item.schedule?.endTime || '',
scheduleDuration: item.schedule?.duration || 0,
escortServiceName: item.escort?.serviceName || '',
attendantName: item.attendant?.name || '',
attendantSexText: ATTENDANT_SEX_MAP[item.escort?.sexRequirement] || '',
totalFee: (item.payment?.totalFee || 0).toFixed(2),
paidFee: (item.payment?.paidFee || 0).toFixed(2),
paymentStatus: item.payment?.status || 'unpaid',
paymentStatusText: paymentInfo.text,
paymentStatusColor: paymentInfo.color,
paymentStatusBg: paymentInfo.bg,
patientNote: item.notes?.patientNote || '',
escortNote: item.notes?.escortNote || '',
medicalSummary: item.notes?.medicalSummary || '',
status: item.status,
statusText: statusInfo.text,
statusColor: statusInfo.color,
statusBg: statusInfo.bg,
statusGradient: statusInfo.gradient,
statusIcon: statusInfo.icon,
statusDesc: statusInfo.desc,
createTime: item.meta?.createtime ? this.formatDateTime(item.meta.createtime) : '',
updateTime: item.meta?.updatetime ? this.formatDateTime(item.meta.updatetime) : ''
}
},
formatDate(dateStr) {
const d = new Date(dateStr)
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
formatDateTime(dateStr) {
const d = new Date(dateStr)
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
const hour = String(d.getHours()).padStart(2, '0')
const minute = String(d.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hour}:${minute}`
},
onCallPatient() {
const mobile = this.data.record.patientMobile
if (!mobile || mobile === '--') return
wx.makePhoneCall({ phoneNumber: mobile })
},
onCallService() {
wx.makePhoneCall({ phoneNumber: '18618162956' })
},
onEditPatientNote() {
this.setData({
editing: true,
editPatientNote: this.data.record.patientNote || ''
})
},
onPatientNoteInput(e) {
this.setData({ editPatientNote: e.detail.value })
},
onCancelEdit() {
this.setData({ editing: false })
},
onSavePatientNote() {
const note = this.data.editPatientNote.trim()
wx.showLoading({ title: '保存中...' })
API.escort.updateRecord(this.data.recordId, {
'notes.patientNote': note
})
.then((res) => {
wx.hideLoading()
if (res.code === 0) {
wx.showToast({ title: '保存成功', icon: 'success' })
this.setData({
editing: false,
'record.patientNote': note
})
} else {
wx.showToast({ title: res.msg || '保存失败', icon: 'none' })
}
})
.catch(() => {
wx.hideLoading()
wx.showToast({ title: '网络请求失败', icon: 'none' })
})
},
onEditPatientInfo() {
const record = this.data.record
this.setData({
editingPatient: true,
editPatient: {
name: record.patientName || '',
sex: record.patientSexText === '男' ? 'male' : record.patientSexText === '女' ? 'female' : '',
age: record.patientAge ? String(record.patientAge) : '',
weight: record.patientWeight ? String(record.patientWeight) : '',
height: record.patientHeight ? String(record.patientHeight) : '',
mobile: record.patientMobile || '',
idnumber: record.patientIdnumber || ''
}
})
},
onPatientInfoInput(e) {
const field = e.currentTarget.dataset.field
const value = e.detail.value
this.setData({
[`editPatient.${field}`]: value
})
},
onPatientSexChange(e) {
const value = e.currentTarget.dataset.value
this.setData({
'editPatient.sex': value
})
},
onCancelEditPatientInfo() {
this.setData({ editingPatient: false })
},
onSavePatientInfo() {
const patient = this.data.editPatient
if (!patient.name.trim()) {
wx.showToast({ title: '请输入姓名', icon: 'none' })
return
}
if (!patient.mobile.trim()) {
wx.showToast({ title: '请输入联系电话', icon: 'none' })
return
}
wx.showLoading({ title: '保存中...' })
API.escort.updateRecord(this.data.recordId, {
'patient.name': patient.name.trim(),
'patient.sex': patient.sex,
'patient.age': parseInt(patient.age) || 0,
'patient.weight': parseFloat(patient.weight) || 0,
'patient.height': parseFloat(patient.height) || 0,
'patient.mobile': patient.mobile.trim(),
'patient.idnumber': patient.idnumber.trim()
})
.then((res) => {
wx.hideLoading()
if (res.code === 0) {
wx.showToast({ title: '保存成功', icon: 'success' })
this.setData({ editingPatient: false })
this.loadRecord(this.data.recordId)
} else {
wx.showToast({ title: res.msg || '保存失败', icon: 'none' })
}
})
.catch(() => {
wx.hideLoading()
wx.showToast({ title: '网络请求失败', icon: 'none' })
})
},
onCancelOrder() {
this.setData({
showCancelPopup: true,
cancelReason: ''
})
},
onCloseCancelPopup() {
this.setData({ showCancelPopup: false })
},
onSelectCancelReason(e) {
this.setData({ cancelReason: e.currentTarget.dataset.reason })
},
onConfirmCancel() {
if (!this.data.cancelReason) {
wx.showToast({ title: '请选择取消原因', icon: 'none' })
return
}
wx.showLoading({ title: '处理中...' })
API.escort.updateStatus(this.data.recordId, {
status: 'cancelled',
reason: this.data.cancelReason
})
.then((res) => {
wx.hideLoading()
if (res.code === 0) {
wx.showToast({ title: '订单已取消', icon: 'success' })
this.setData({ showCancelPopup: false })
this.loadRecord(this.data.recordId)
} else {
wx.showToast({ title: res.msg || '操作失败', icon: 'none' })
}
})
.catch(() => {
wx.hideLoading()
wx.showToast({ title: '网络请求失败', icon: 'none' })
})
},
onPayOrder() {
wx.showToast({ title: '支付功能开发中', icon: 'none' })
},
onConfirmComplete() {
wx.showModal({
title: '确认完成',
content: '确认陪诊服务已完成?',
confirmColor: '#6B8E7B',
success: (res) => {
if (res.confirm) {
wx.showLoading({ title: '处理中...' })
API.escort.updateStatus(this.data.recordId, {
status: 'completed'
})
.then((res) => {
wx.hideLoading()
if (res.code === 0) {
wx.showToast({ title: '已确认完成', icon: 'success' })
this.loadRecord(this.data.recordId)
} else {
wx.showToast({ title: res.msg || '操作失败', icon: 'none' })
}
})
.catch(() => {
wx.hideLoading()
wx.showToast({ title: '网络请求失败', icon: 'none' })
})
}
}
})
},
onDeleteOrder() {
wx.showModal({
title: '删除订单',
content: '确定要删除该订单吗?删除后不可恢复。',
confirmColor: '#EF4444',
success: (res) => {
if (res.confirm) {
wx.showLoading({ title: '删除中...' })
API.escort.deleteRecord(this.data.recordId)
.then((res) => {
wx.hideLoading()
if (res.code === 0) {
wx.showToast({ title: '删除成功', icon: 'success' })
setTimeout(() => {
wx.navigateBack()
}, 1500)
} else {
wx.showToast({ title: res.msg || '删除失败', icon: 'none' })
}
})
.catch(() => {
wx.hideLoading()
wx.showToast({ title: '网络请求失败', icon: 'none' })
})
}
}
})
},
onRebook() {
const serviceId = this.data.record.escortServiceName
wx.navigateTo({
url: `/pages/escort/itemlist`
})
},
onShareAppMessage() {
return {
title: '暖橙陪诊 - 专业陪诊服务',
path: '/pages/home/index'
}
}
})

View File

@@ -0,0 +1,6 @@
{
"navigationBarTitleText": "陪诊记录详情",
"usingComponents": {},
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark"
}

View File

@@ -0,0 +1,319 @@
<view class="container">
<!-- 状态头部 -->
<view class="status-header" style="background: {{record.statusGradient}};">
<view class="status-main">
<text class="status-text">{{record.statusText}}</text>
<text class="status-desc">{{record.statusDesc}}</text>
</view>
<view class="status-icon-wrap">
<t-icon name="{{record.statusIcon}}" size="80rpx" color="rgba(255,255,255,0.6)" />
</view>
</view>
<!-- 就诊人信息 -->
<view class="detail-card">
<view class="card-title">
<t-icon name="user" class="card-icon" size="36rpx" />
<text>就诊人信息</text>
<view class="card-edit-btn" bindtap="onEditPatientInfo" wx:if="{{!editingPatient}}">
<t-icon name="edit" size="28rpx" color="#D4A853" />
<text class="edit-text">修改</text>
</view>
</view>
<view 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 phone" 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>
</view>
<view wx:if="{{editingPatient}}">
<view class="edit-row">
<text class="edit-label">姓名</text>
<input class="edit-input" value="{{editPatient.name}}" 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-field="sex" data-value="male" bindtap="onPatientSexChange">男</view>
<view class="edit-radio {{editPatient.sex === 'female' ? 'active' : ''}}" data-field="sex" data-value="female" bindtap="onPatientSexChange">女</view>
</view>
</view>
<view class="edit-row">
<text class="edit-label">年龄</text>
<input class="edit-input" type="number" value="{{editPatient.age}}" placeholder="请输入年龄" data-field="age" bindinput="onPatientInfoInput" />
</view>
<view class="edit-row">
<text class="edit-label">体重(kg)</text>
<input class="edit-input" type="digit" value="{{editPatient.weight}}" 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="请输入身高" 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="请输入联系电话" data-field="mobile" bindinput="onPatientInfoInput" />
</view>
<view class="edit-row">
<text class="edit-label">身份证号</text>
<input class="edit-input" value="{{editPatient.idnumber}}" placeholder="请输入身份证号" data-field="idnumber" bindinput="onPatientInfoInput" />
</view>
<view class="edit-actions">
<button class="edit-btn cancel" bindtap="onCancelEditPatientInfo">取消</button>
<button class="edit-btn confirm" bindtap="onSavePatientInfo">保存</button>
</view>
</view>
</view>
<!-- 医院预约信息 -->
<view class="detail-card">
<view class="card-title">
<t-icon name="hospital" class="card-icon" size="36rpx" />
<text>医院预约信息</text>
</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>
</view>
<!-- 陪诊服务信息 -->
<view class="detail-card">
<view class="card-title">
<t-icon name="service" class="card-icon" size="36rpx" />
<text>陪诊服务</text>
</view>
<view class="info-row">
<text class="info-label">服务类型</text>
<text class="info-value">{{record.escortServiceName || '陪诊服务'}}</text>
</view>
<view class="info-row">
<text class="info-label">性别要求</text>
<text class="info-value">{{record.escortSexRequirementText}}</text>
</view>
<view class="info-row">
<text class="info-label">陪诊员</text>
<text class="info-value">{{record.attendantName}}</text>
</view>
<view class="info-row">
<text class="info-label">陪诊员性别</text>
<text class="info-value">{{record.attendantSexText}}</text>
</view>
<view class="info-row">
<text class="info-label">陪诊员电话</text>
<text class="info-value phone" bindtap="onCallAttendant">{{record.attendantMobile}}</text>
</view>
</view>
<!-- 陪诊需求 / 症状描述 -->
<view class="detail-card">
<view class="card-title">
<t-icon name="edit-1" class="card-icon" size="36rpx" />
<text>陪诊需求与症状</text>
<view class="card-edit-btn" bindtap="onEditPatientNote" wx:if="{{!editing}}">
<t-icon name="edit" size="28rpx" color="#D4A853" />
<text class="edit-text">修改</text>
</view>
</view>
<view class="note-section" wx:if="{{record.patientNote || editing}}">
<textarea
wx:if="{{editing}}"
class="note-textarea"
value="{{editPatientNote}}"
placeholder="请输入陪诊需求或症状描述"
maxlength="500"
placeholder-class="input-placeholder"
bindinput="onPatientNoteInput"
focus="{{editing}}"
/>
<text wx:else class="note-content">{{record.patientNote || '暂无备注'}}</text>
<view class="note-actions" wx:if="{{editing}}">
<button class="note-btn cancel" bindtap="onCancelEdit">取消</button>
<button class="note-btn confirm" bindtap="onSavePatientNote">保存</button>
</view>
</view>
<view class="note-section" wx:if="{{record.escortNote}}">
<text class="note-label">陪诊记录</text>
<text class="note-content">{{record.escortNote}}</text>
</view>
<view class="note-section" wx:if="{{record.medicalSummary}}">
<text class="note-label">就诊摘要</text>
<text class="note-content">{{record.medicalSummary}}</text>
</view>
<view class="empty-note" wx:if="{{!record.patientNote && !record.escortNote && !record.medicalSummary && !editing}}">
<text class="empty-note-text">暂无备注信息,点击添加</text>
<view class="add-note-btn" bindtap="onEditPatientNote">
<t-icon name="add" size="28rpx" color="#D4A853" />
</view>
</view>
</view>
<!-- 费用信息 -->
<view class="detail-card">
<view class="card-title">
<t-icon name="wallet" class="card-icon" size="36rpx" />
<text>费用信息</text>
</view>
<view class="info-row">
<text class="info-label">服务费用</text>
<text class="info-value fee">¥{{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="payment-badge" style="color: {{record.paymentStatusColor}}; background: {{record.paymentStatusBg}};">
{{record.paymentStatusText}}
</view>
</view>
</view>
<!-- 订单信息 -->
<view class="detail-card">
<view class="card-title">
<t-icon name="order" class="card-icon" size="36rpx" />
<text>订单信息</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-badge-small" style="color: {{record.statusColor}}; background: {{record.statusBg}};">
{{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>
</view>
<!-- 底部占位 -->
<view class="bottom-placeholder"></view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<view class="bottom-right">
<view
class="action-btn cancel-btn"
wx:if="{{record.status === 'pending' || record.status === 'confirmed'}}"
bindtap="onCancelOrder"
>取消订单</view>
<view
class="action-btn cancel-btn"
wx:if="{{record.paymentStatus === 'unpaid' && record.status !== 'completed'}}"
bindtap="onDeleteOrder"
>删除订单</view>
<view
class="action-btn confirm-btn"
wx:if="{{record.status === 'completed'}}"
bindtap="onConfirmComplete"
>确认完成</view>
<view
class="action-btn rebook-btn"
wx:if="{{record.status === 'completed' || record.status === 'cancelled'}}"
bindtap="onRebook"
>再次预约</view>
</view>
</view>
<!-- 取消订单弹窗 -->
<view class="popup-mask {{showCancelPopup ? 'show' : ''}}" bindtap="onCloseCancelPopup"></view>
<view class="popup-content {{showCancelPopup ? 'show' : ''}}">
<view class="popup-header">
<text class="popup-title">取消订单</text>
<view class="popup-close" bindtap="onCloseCancelPopup">
<t-icon name="close" size="40rpx" />
</view>
</view>
<view class="popup-body">
<text class="cancel-tip">确定要取消该陪诊订单吗?取消后陪诊员将收到通知。</text>
<view class="cancel-reason-list">
<view
class="cancel-reason-item {{cancelReason === item ? 'active' : ''}}"
wx:for="{{cancelReasons}}"
wx:key="*this"
data-reason="{{item}}"
bindtap="onSelectCancelReason"
>
<view class="reason-radio">
<view class="reason-radio-inner" wx:if="{{cancelReason === item}}"></view>
</view>
<text class="reason-text">{{item}}</text>
</view>
</view>
</view>
<view class="popup-footer">
<button class="popup-cancel-btn" bindtap="onCloseCancelPopup">再想想</button>
<button class="popup-confirm-btn" bindtap="onConfirmCancel">确认取消</button>
</view>
</view>
</view>

View File

@@ -0,0 +1,575 @@
page {
background-color: #FAF6F1;
}
.container {
min-height: 100vh;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
/* 状态头部 */
.status-header {
padding: 48rpx 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-radius: 0 0 32rpx 32rpx;
}
.status-main {
display: flex;
flex-direction: column;
gap: 12rpx;
}
.status-text {
font-size: 40rpx;
font-weight: 700;
color: #FFFFFF;
}
.status-desc {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
.status-icon-wrap {
opacity: 0.6;
}
/* 详情卡片 */
.detail-card {
background: #FFFFFF;
margin: 24rpx 24rpx 0;
border-radius: 20rpx;
padding: 32rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
}
.card-title {
display: flex;
align-items: center;
font-size: 32rpx;
font-weight: 600;
color: #1F2937;
margin-bottom: 24rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #F3F4F6;
}
.card-icon {
color: #D4A853;
margin-right: 12rpx;
}
.card-edit-btn {
display: flex;
align-items: center;
gap: 6rpx;
margin-left: auto;
}
/* 信息行 */
.info-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16rpx 0;
}
.info-row + .info-row {
border-top: 1rpx solid #F9FAFB;
}
.info-label {
font-size: 26rpx;
color: #9CA3AF;
flex-shrink: 0;
}
.info-value {
font-size: 26rpx;
color: #374151;
text-align: right;
flex: 1;
margin-left: 24rpx;
word-break: break-all;
}
.info-value.phone {
color: #D4A853;
}
.info-value.fee {
color: #D4A853;
font-weight: 700;
font-size: 30rpx;
}
.info-value.order-id {
font-size: 24rpx;
color: #6B7280;
font-family: monospace;
}
/* 支付状态徽标 */
.payment-badge {
font-size: 24rpx;
font-weight: 600;
padding: 6rpx 16rpx;
border-radius: 8rpx;
}
/* 订单状态小徽标 */
.status-badge-small {
font-size: 24rpx;
font-weight: 600;
padding: 6rpx 16rpx;
border-radius: 8rpx;
}
/* 备注区域 */
.note-section {
margin-bottom: 24rpx;
}
.note-section:last-child {
margin-bottom: 0;
}
.note-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12rpx;
}
.note-label {
font-size: 26rpx;
color: #6B7280;
font-weight: 500;
margin-bottom: 8rpx;
display: block;
}
.note-edit-btn {
display: flex;
align-items: center;
gap: 6rpx;
}
.edit-text {
font-size: 24rpx;
color: #D4A853;
}
.note-content {
font-size: 28rpx;
color: #374151;
line-height: 1.7;
background: #F9FAFB;
padding: 20rpx;
border-radius: 12rpx;
display: block;
}
.note-textarea {
width: 100%;
min-height: 200rpx;
background: #F9FAFB;
border-radius: 12rpx;
padding: 20rpx;
font-size: 28rpx;
color: #1F2937;
box-sizing: border-box;
line-height: 1.7;
}
.input-placeholder {
color: #9CA3AF;
}
.note-actions {
display: flex;
justify-content: flex-end;
gap: 16rpx;
margin-top: 16rpx;
}
.note-btn {
font-size: 26rpx;
padding: 12rpx 32rpx;
border-radius: 12rpx;
border: none;
line-height: 1.5;
}
.note-btn.cancel {
background: #F3F4F6;
color: #6B7280;
}
.note-btn.confirm {
background: linear-gradient(135deg, #D4A853 0%, #D4A853 100%);
color: #FFFFFF;
font-weight: 600;
}
.note-btn::after {
border: none;
}
/* 编辑行 */
.edit-row {
display: flex;
align-items: center;
padding: 16rpx 0;
border-top: 1rpx solid #F9FAFB;
}
.edit-label {
font-size: 26rpx;
color: #9CA3AF;
flex-shrink: 0;
width: 160rpx;
}
.edit-input {
flex: 1;
font-size: 26rpx;
color: #374151;
text-align: right;
margin-left: 24rpx;
height: 56rpx;
line-height: 56rpx;
}
.edit-radio-group {
flex: 1;
display: flex;
justify-content: flex-end;
gap: 24rpx;
margin-left: 24rpx;
}
.edit-radio {
font-size: 26rpx;
color: #6B7280;
padding: 8rpx 24rpx;
border-radius: 8rpx;
border: 1rpx solid #E5E7EB;
background: #FFFFFF;
}
.edit-radio.active {
color: #D4A853;
border-color: #D4A853;
background: #FEF3C7;
}
.edit-actions {
display: flex;
justify-content: flex-end;
gap: 16rpx;
margin-top: 24rpx;
padding-top: 16rpx;
border-top: 1rpx solid #F3F4F6;
}
.edit-btn {
font-size: 26rpx;
padding: 12rpx 32rpx;
border-radius: 12rpx;
border: none;
line-height: 1.5;
}
.edit-btn.cancel {
background: #F3F4F6;
color: #6B7280;
}
.edit-btn.confirm {
background: linear-gradient(135deg, #D4A853 0%, #D4A853 100%);
color: #FFFFFF;
font-weight: 600;
}
.edit-btn::after {
border: none;
}
/* 空备注 */
.empty-note {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 20rpx;
background: #F9FAFB;
border-radius: 12rpx;
}
.empty-note-text {
font-size: 26rpx;
color: #9CA3AF;
}
.add-note-btn {
display: flex;
align-items: center;
justify-content: center;
width: 56rpx;
height: 56rpx;
background: #FEF3C7;
border-radius: 50%;
}
/* 底部占位 */
.bottom-placeholder {
height: 160rpx;
}
/* 底部操作栏 */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #FFFFFF;
padding: 20rpx 32rpx;
padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.06);
z-index: 100;
}
.bottom-left {
display: flex;
align-items: center;
gap: 32rpx;
}
.action-icon-btn {
display: flex;
flex-direction: column;
align-items: center;
gap: 4rpx;
}
.action-icon-label {
font-size: 20rpx;
color: #6B7280;
}
.bottom-right {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 16rpx;
flex: 1;
flex-wrap: nowrap;
}
.action-btn {
font-size: 26rpx;
font-weight: 600;
padding: 16rpx 20rpx;
border-radius: 16rpx;
line-height: 1.5;
min-width: 0;
white-space: nowrap;
text-align: center;
}
.cancel-btn {
background: #F3F4F6;
color: #6B7280;
}
.pay-btn {
background: linear-gradient(135deg, #D4A853 0%, #D4A853 100%);
color: #FFFFFF;
}
.confirm-btn {
background: linear-gradient(135deg, #6B8E7B 0%, #6B8E7B 100%);
color: #FFFFFF;
}
.rebook-btn {
background: linear-gradient(135deg, #6B8E7B 0%, #6B8E7B 100%);
color: #FFFFFF;
}
/* 弹窗遮罩 */
.popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 200;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s, visibility 0.3s;
}
.popup-mask.show {
opacity: 1;
visibility: visible;
}
/* 弹窗内容 */
.popup-content {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #FFFFFF;
border-radius: 24rpx 24rpx 0 0;
z-index: 201;
transform: translateY(100%);
transition: transform 0.3s ease-out;
display: flex;
flex-direction: column;
max-height: 70vh;
}
.popup-content.show {
transform: translateY(0);
}
.popup-header {
display: flex;
align-items: center;
justify-content: center;
padding: 32rpx;
position: relative;
border-bottom: 1rpx solid #F3F4F6;
flex-shrink: 0;
}
.popup-title {
font-size: 32rpx;
font-weight: 600;
color: #1F2937;
}
.popup-close {
position: absolute;
right: 32rpx;
top: 50%;
transform: translateY(-50%);
color: #9CA3AF;
}
.popup-body {
flex: 1;
overflow-y: auto;
padding: 32rpx;
}
.popup-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24rpx;
padding: 24rpx 32rpx;
padding-bottom: calc(24rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
border-top: 1rpx solid #F3F4F6;
background: #FFFFFF;
flex-shrink: 0;
}
.popup-cancel-btn {
flex: 1;
background: #F3F4F6;
color: #6B7280;
font-size: 30rpx;
font-weight: 600;
padding: 24rpx 0;
border-radius: 20rpx;
border: none;
line-height: 1.5;
}
.popup-cancel-btn::after {
border: none;
}
.popup-confirm-btn {
flex: 1;
background: linear-gradient(135deg, #EF4444 0%, #EF4444 100%);
color: #FFFFFF;
font-size: 30rpx;
font-weight: 600;
padding: 24rpx 0;
border-radius: 20rpx;
border: none;
line-height: 1.5;
}
.popup-confirm-btn::after {
border: none;
}
/* 取消原因 */
.cancel-tip {
font-size: 28rpx;
color: #6B7280;
line-height: 1.6;
margin-bottom: 24rpx;
}
.cancel-reason-list {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.cancel-reason-item {
display: flex;
align-items: center;
gap: 16rpx;
padding: 20rpx 16rpx;
border-radius: 12rpx;
transition: background 0.2s;
}
.cancel-reason-item.active {
background: #FEF3C7;
}
.reason-radio {
width: 36rpx;
height: 36rpx;
border: 3rpx solid #D1D5DB;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: border-color 0.2s;
}
.cancel-reason-item.active .reason-radio {
border-color: #D4A853;
}
.reason-radio-inner {
width: 20rpx;
height: 20rpx;
background: #D4A853;
border-radius: 50%;
}
.reason-text {
font-size: 28rpx;
color: #374151;
}

View File

@@ -2,7 +2,7 @@ const API = require('../../utils/api.js')
const STATUS_MAP = {
pending: { text: '待确认', color: '#F59E0B', bg: '#FEF3C7' },
confirmed: { text: '已确认', color: '#3B82F6', bg: '#DBEAFE' },
confirmed: { text: '待就诊', color: '#3B82F6', bg: '#DBEAFE' },
in_progress: { text: '进行中', color: '#8B5CF6', bg: '#EDE9FE' },
completed: { text: '已完成', color: '#10B981', bg: '#D1FAE5' },
cancelled: { text: '已取消', color: '#6B7280', bg: '#F3F4F6' }
@@ -17,6 +17,13 @@ const TYPE_MAP = {
other: '其他'
}
const PAYMENT_STATUS_MAP = {
unpaid: { text: '未支付', color: '#F59E0B', bg: '#FEF3C7' },
paid: { text: '已支付', color: '#3B82F6', bg: '#DBEAFE' },
refunding: { text: '退款中', color: '#F59E0B', bg: '#FEF3C7' },
refunded: { text: '已退款', color: '#6B7280', bg: '#F3F4F6' }
}
Page({
data: {
records: [],
@@ -26,15 +33,17 @@ Page({
pageSize: 10,
statusFilter: '',
statusTabs: [
{ value: '', label: '全部' },
{ value: 'pending', label: '待确认' },
{ value: 'confirmed', label: '已确认' },
{ value: 'in_progress', label: '进行中' },
{ value: 'completed', label: '已完成' }
{ 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 }
]
},
onLoad() {
onLoad(options) {
const tab = options.tab || ''
this.setData({ statusFilter: tab })
this.loadRecords(true)
},
@@ -71,8 +80,9 @@ Page({
page,
pageSize: this.data.pageSize
}
if (this.data.statusFilter) {
params.status = this.data.statusFilter
//params.status = this.data.statusFilter
}
return API.escort.getMyRecords(params)
@@ -80,10 +90,12 @@ Page({
if (res.code === 0) {
const list = res.data.records || []
const formatted = list.map(item => this.formatRecord(item))
this.data.statusTabs = this.computeStatusCounts(formatted, this.data.statusTabs)
this.setData({
records: reset ? formatted : this.data.records.concat(formatted),
page,
hasMore: list.length >= this.data.pageSize
hasMore: list.length >= this.data.pageSize,
statusTabs: this.data.statusTabs
})
} else {
wx.showToast({ title: res.msg || '加载失败', icon: 'none' })
@@ -97,13 +109,29 @@ Page({
})
},
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
},
formatRecord(item) {
const statusInfo = STATUS_MAP[item.escort?.status] || STATUS_MAP.pending
const statusInfo = STATUS_MAP[item.status] || STATUS_MAP.pending
const typeText = TYPE_MAP[item.escort?.type] || '陪诊服务'
const fee = item.payment?.totalFee || 0
const appointmentTime = item.schedule?.date
? this.formatDateTime(item.schedule.date) + item.schedule.startTime
: '--'
const paymentStatusInfo = PAYMENT_STATUS_MAP[item.payment?.status] || PAYMENT_STATUS_MAP.unpaid
return {
_id: item._id,
@@ -112,13 +140,17 @@ Page({
hospital: item.hospital?.name || '--',
department: item.hospital?.department || '--',
typeText,
status: item.escort?.status,
status: item.status,
statusText: statusInfo.text,
statusColor: statusInfo.color,
statusBg: statusInfo.bg,
appointmentTime,
fee: fee.toFixed(2),
escortNote: item.notes?.escortNote || ''
patientNote: item.notes?.patientNote || '',
escortNote: item.notes?.escortNote || '',
paymentStatusText: paymentStatusInfo.text,
paymentStatusColor: paymentStatusInfo.color,
paymentStatusBg: paymentStatusInfo.bg
}
},
@@ -139,7 +171,7 @@ Page({
onTapRecord(e) {
const id = e.currentTarget.dataset.id
wx.navigateTo({
url: `/pages/mine/escort_record_detail/escort_record_detail?id=${id}`
url: `/pages/escort/recorddetail?id=${id}`
})
},

View File

@@ -8,7 +8,7 @@
data-value="{{item.value}}"
bindtap="onTabChange"
>
{{item.label}}
{{item.label}}<text class="tab-count" wx:if="{{item.count > 0}}">({{item.count}})</text>
</view>
</view>
@@ -43,8 +43,20 @@
<text class="info-value">{{item.department}}</text>
</view>
<view class="info-row">
<text class="info-label">就诊人</text>
<text class="info-value">{{item.patientName}} {{item.patientMobile}}</text>
<text class="info-label">就诊人姓名</text>
<text class="info-value">{{item.patientName}}</text>
</view>
<view class="info-row">
<text class="info-label">电话</text>
<text class="info-value">{{item.patientMobile}}</text>
</view>
<view class="info-row">
<text class="info-label">就诊需求</text>
<text class="info-value">{{item.patientNote}}</text>
</view>
<view class="info-row">
<text class="info-label">陪诊说明</text>
<text class="info-value">{{item.escortNote}}</text>
</view>
</view>
@@ -54,8 +66,8 @@
<text class="fee-label">费用:</text>
<text class="fee-value">¥{{item.fee}}</text>
</view>
<view class="arrow">
<t-icon name="chevron-right" size="32rpx" color="#9CA3AF" />
<view class="status-badge" style="color: {{item.paymentStatusColor}}; background: {{item.paymentStatusBg}};">
{{item.paymentStatusText}}
</view>
</view>
</view>

View File

@@ -11,7 +11,7 @@ page {
.status-tabs {
display: flex;
align-items: center;
gap: 16rpx;
gap: 4rpx;
padding: 24rpx 32rpx;
background: #FFFFFF;
position: sticky;
@@ -140,10 +140,7 @@ page {
font-weight: 700;
}
.arrow {
display: flex;
align-items: center;
}
/* 空状态 */
.empty-state {

View File

@@ -1,23 +1,21 @@
Page({
data: {
escortServices: [
{ id: 1, name: '陪诊', icon: 'heart', url: '', type: '' },
{ id: 2, name: '代问诊', icon: 'chat-heart', url: '', type: '' },
{ id: 3, name: '代预约', icon: 'draft', url: '', type: '' },
{ id: 4, name: '其他助诊', icon: 'cooperate', url: '', type: '' },
{ id: 1, name: '陪诊', icon: 'heart', iconColor: '#E11D48', bgColor: '#FFF1F2' },
{ id: 2, name: '代问诊', icon: 'chat-heart', iconColor: '#EA580C', bgColor: '#FFF7ED' },
{ id: 3, name: '代办理', icon: 'fact-check', iconColor: '#059669', bgColor: '#ECFDF5' },
{ id: 8, name: '其他助诊', icon: 'app', iconColor: '#2563EB', bgColor: '#EFF6FF' }
],
otherServices: [
{ id: 1, name: '代探望', icon: 'apple', url: '', type: '' },
{ id: 2, name: '企业陪诊', icon: 'city-8', url: '', type: '' },
{ id: 3, name: '陪诊师入驻', icon: 'usergroup', url: '', type: '' },
{ id: 4, name: '商务合作', icon: 'command', url: '', type: '' },
{ id: 1, name: '代探望', icon: 'apple', url: '', type: '', iconColor: '#7C3AED', bgColor: '#F5F3FF' },
{ id: 2, name: '企业陪诊', icon: 'city-8', url: '', type: '', iconColor: '#D97706', bgColor: '#FFFBEB' },
{ id: 3, name: '陪诊师入驻', icon: 'usergroup', url: '', type: '', iconColor: '#4F46E5', bgColor: '#EEF2FF' },
{ id: 4, name: '商务合作', icon: 'command', url: '', type: '', iconColor: '#0D9488', bgColor: '#F0FDFA' },
],
tools: [
{ id: 1, name: '医院电话', icon: 'call', url: 'pages/hospital/contact', type: 'page' },
{ id: 2, name: '科室排行', icon: 'ai-coordinate-system', url: 'pages/hospital/ranking', type: 'page' },
{ id: 3, name: '医保备案', icon: 'system-code', url: '#小程序://异地备案/FfXUvTLmNptZx5E', type: 'wxapp' },
{ id: 4, name: '医疗影像', icon: 'film-1', url: '', type: '' }
]
{ id: 1, name: '预约记录', icon: 'assignment', url: 'pages/escort/recordlist', type: 'page', iconColor: '#0891B2', bgColor: '#ECFEFF' },
{ id: 2, name: '健康档案', icon: 'attach', url: '', type: '', iconColor: '#DB2777', bgColor: '#FDF2F8' }
]
},
async onLoad() {
@@ -52,7 +50,7 @@ Page({
const item = e.currentTarget.dataset.item;
if (!item || !item.type || !item.url) {
wx.showToast({
title: '建设中, 请电话联系!',
title: '建设中...',
icon: 'none'
});
return;
@@ -72,7 +70,7 @@ Page({
break;
default:
wx.showToast({
title: '建设中, 请电话联系!',
title: '建设中...',
icon: 'none'
});
}

View File

@@ -1,95 +1,110 @@
<view class="container">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="nav-logo">
<image class="logo-icon" src="/images/home-yellow.png" mode="aspectFit"></image>
<text class="logo-text">暖橙陪诊</text>
</view>
</view>
<view class="page-bg">
<view class="container">
<!-- Banner区域 -->
<view class="banner-section">
<view class="banner-card">
<image class="banner-bg" src="/images/banner.jpg" mode="aspectFill"></image>
<view class="banner-text">
<text class="banner-title">专业陪诊</text>
<text class="banner-subtitle"></text>
<text class="banner-en">让就医更简单,让客户更安心</text>
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="nav-logo">
<image class="logo-icon" src="/images/home-yellow.png" mode="aspectFit"></image>
<text class="logo-text">暖橙陪诊</text>
</view>
</view>
</view>
<!-- 服务卡片 -->
<view class="service-cards">
<view class="service-card" bindtap="goToAiChat">
<image class="card-img" src="/images/ai-yellow.png" mode="aspectFit"></image>
<view class="card-info">
<text class="card-title">客服咨询</text>
<text class="card-en">AI Customer service</text>
</view>
</view>
<view class="service-card vip" bindtap="goToContact">
<view class="card-info">
<text class="card-title">联系我们</text>
<text class="card-en">Contact us anytime</text>
</view>
<image class="card-img" src="/images/call.png" mode="aspectFit"></image>
</view>
</view>
<!-- 助诊服务 -->
<view class="assist-section">
<view class="section-header">
<view class="section-title-wrap">
<t-icon name="system-3" class="section-icon" size="40rpx"/>
<text class="section-title">助诊服务</text>
</view>
<text class="section-more" bindtap="goToServiceList">全部 >></text>
</view>
<view class="assist-grid">
<view class="assist-item" wx:for="{{ escortServices }}" wx:key="id" bindtap="goToAssistDetail" data-id="{{ item.id }}">
<view class="assist-icon-circle">
<t-icon name="{{ item.icon }}" class="assist-icon" />
<!-- Banner区域 -->
<view class="banner-section">
<view class="banner-card">
<image class="banner-bg" src="/images/banner.jpg" mode="aspectFill"></image>
<view class="banner-overlay"></view>
<view class="banner-text">
<text class="banner-title">专业陪诊</text>
<text class="banner-en">让就医更简单,让客户更安心</text>
</view>
<text class="assist-name">{{ item.name }}</text>
</view>
</view>
</view>
<!-- 就诊工具 -->
<view class="tool-section">
<view class="section-header">
<view class="section-title-wrap">
<t-icon name="tools" class="section-icon" size="40rpx"/>
<text class="section-title">就医工具</text>
<!-- 服务卡片 -->
<view class="service-cards">
<view class="service-card" bindtap="goToAiChat">
<view class="card-content">
<view class="card-badge">AI</view>
<text class="card-title">客服咨询</text>
<text class="card-en">Customer Service</text>
</view>
<view class="card-icon-wrap">
<image class="card-img" src="/images/ai-yellow.png" mode="aspectFit"></image>
</view>
</view>
<view class="service-card vip" bindtap="goToContact">
<view class="card-content">
<view class="card-badge vip-badge">24H</view>
<text class="card-title">联系我们</text>
<text class="card-en">Contact Us</text>
</view>
<view class="card-icon-wrap vip-icon-wrap">
<image class="card-img" src="/images/call.png" mode="aspectFit"></image>
</view>
</view>
</view>
<view class="assist-grid">
<view class="assist-item" wx:for="{{ tools }}" wx:key="id" bindtap="goToOtherServicesDetail" data-item="{{ item }}">
<view class="assist-icon-circle">
<t-icon name="{{ item.icon }}" class="assist-icon" />
<!-- 助诊服务 -->
<view class="section-card">
<view class="section-header">
<view class="section-title-wrap">
<view class="section-accent"></view>
<text class="section-title">助诊服务</text>
</view>
<view class="section-more" bindtap="goToServiceList">
<text>全部</text>
<t-icon name="chevron-right" size="24rpx" class="more-icon"/>
</view>
</view>
<view class="assist-grid">
<view class="assist-item" wx:for="{{ escortServices }}" wx:key="id" bindtap="goToAssistDetail" data-id="{{ item.id }}">
<view class="assist-icon-circle" style="background: {{ item.bgColor }}; border-color: {{ item.bgColor }};">
<t-icon name="{{ item.icon }}" class="assist-icon" size="44rpx" color="{{ item.iconColor }}" />
</view>
<text class="assist-name">{{ item.name }}</text>
</view>
</view>
</view>
<!-- 其他业务 -->
<view class="section-card">
<view class="section-header">
<view class="section-title-wrap">
<view class="section-accent"></view>
<text class="section-title">其他业务</text>
</view>
</view>
<view class="assist-grid">
<view class="assist-item" wx:for="{{ otherServices }}" wx:key="id" bindtap="goToOtherServicesDetail" data-item="{{ item }}">
<view class="assist-icon-circle" style="background: {{ item.bgColor }}; border-color: {{ item.bgColor }};">
<t-icon name="{{ item.icon }}" class="assist-icon" size="44rpx" color="{{ item.iconColor }}" />
</view>
<text class="assist-name">{{ item.name }}</text>
</view>
</view>
</view>
<!-- 其他业务 -->
<view class="other-section">
<view class="section-header">
<view class="section-title-wrap">
<t-icon name="indicator" class="section-icon" size="40rpx"/>
<text class="section-title">其他业务</text>
</view>
</view>
<view class="assist-grid">
<view class="assist-item" wx:for="{{ otherServices }}" wx:key="id" bindtap="goToOtherServicesDetail" data-item="{{ item }}">
<view class="assist-icon-circle">
<t-icon name="{{ item.icon }}" class="assist-icon" />
</view>
<text class="assist-name">{{ item.name }}</text>
</view>
</view>
</view>
<!-- 我的 -->
<view class="section-card">
<view class="section-header">
<view class="section-title-wrap">
<view class="section-accent"></view>
<text class="section-title">我的信息</text>
</view>
</view>
<view class="assist-grid">
<view class="assist-item" wx:for="{{ tools }}" wx:key="id" bindtap="goToOtherServicesDetail" data-item="{{ item }}">
<view class="assist-icon-circle" style="background: {{ item.bgColor }}; border-color: {{ item.bgColor }};">
<t-icon name="{{ item.icon }}" class="assist-icon" size="44rpx" color="{{ item.iconColor }}" />
</view>
<text class="assist-name">{{ item.name }}</text>
</view>
</view>
</view>
<!-- 底部留白 -->
<view class="footer-space"></view>
</view>
</view>

View File

@@ -1,10 +1,14 @@
page {
background-color: #F5F7F6;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
.container {
.page-bg {
min-height: 100vh;
background: #F3F4F6;
}
.container {
padding: 0 22rpx 22rpx;
}
/* 顶部导航栏 */
@@ -12,8 +16,7 @@ page {
display: flex;
align-items: center;
justify-content: space-between;
padding: 120rpx 32rpx 20rpx 32rpx;
background: #FFFFFF;
padding: 120rpx 0 24rpx;
}
.nav-logo {
@@ -22,181 +25,173 @@ page {
}
.logo-icon {
width: 56rpx;
height: 56rpx;
border-radius: 16rpx;
background: #FFFFFF;
padding: 4rpx;
width: 52rpx;
height: 52rpx;
border-radius: 14rpx;
}
.logo-text {
font-size: 36rpx;
font-weight: 700;
color: #1F2937;
margin-left: 16rpx;
}
.nav-actions {
display: flex;
align-items: center;
gap: 20rpx;
}
.nav-more {
display: flex;
align-items: center;
gap: 6rpx;
}
.nav-more .dot {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: #1F2937;
}
.nav-circle {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 4rpx solid #1F2937;
font-size: 32rpx;
font-weight: 600;
color: rgba(249, 115, 22, 0.8);
margin-left: 14rpx;
letter-spacing: 2rpx;
}
/* Banner区域 */
.banner-section {
padding: 24rpx 32rpx;
background: #FFFFFF;
margin-top: 8rpx;
}
.banner-card {
background: #FFFFFF;
border-radius: 24rpx;
padding: 20rpx 32rpx;
position: relative;
border-radius: 28rpx;
overflow: hidden;
height: 320rpx;
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
overflow: hidden;
min-height: 280rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.08);
}
.banner-bg {
position: absolute;
top: 0;
right: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.banner-text {
flex: 1;
.banner-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, rgba(249, 115, 22, 0.8) 0%, rgba(251, 146, 60, 0.5) 50%, rgba(251, 191, 36, 0.15) 100%);
z-index: 2;
}
.banner-text {
position: relative;
z-index: 3;
padding: 0 40rpx;
display: flex;
flex-direction: column;
}
.banner-title {
font-size: 52rpx;
font-weight: 800;
color: #D4A853;
letter-spacing: 4rpx;
line-height: 1.2;
}
.banner-subtitle {
font-size: 52rpx;
font-weight: 800;
color: #2D6A4F;
letter-spacing: 4rpx;
font-size: 50rpx;
font-weight: 600;
color: #FFFFFF;
letter-spacing: 6rpx;
line-height: 1.2;
text-shadow: 0 4rpx 16rpx rgba(234, 88, 12, 0.3);
}
.banner-en {
font-size: 26rpx;
color: #6B8E7B;
letter-spacing: 6rpx;
font-size: 24rpx;
color: rgba(255, 255, 255, 0.95);
letter-spacing: 4rpx;
margin-top: 16rpx;
font-weight: 500;
}
/* 服务卡片 */
.service-cards {
display: flex;
gap: 20rpx;
padding: 36rpx 32rpx;
margin-top: 18rpx;
background: #FFFFFF;
margin-top: 28rpx;
}
.service-card {
flex: 1;
background: #FFFFFF;
border-radius: 24rpx;
padding: 24rpx;
padding: 28rpx 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
border: 2rpx solid #F0F0F0;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
transition: transform 0.2s ease;
}
.card-img {
width: 90rpx;
height: 90rpx;
.service-card:active {
transform: scale(0.98);
}
.card-info {
.card-content {
display: flex;
flex-direction: column;
flex: 1;
margin-left: 16rpx;
}
.service-card.vip .card-info {
margin-left: 0;
margin-right: 16rpx;
.card-badge {
align-self: flex-start;
background: #FEF3C7;
color: #D97706;
font-size: 20rpx;
font-weight: 700;
padding: 4rpx 14rpx;
border-radius: 8rpx;
margin-bottom: 14rpx;
letter-spacing: 1rpx;
}
.vip-badge {
background: #DBEAFE;
color: #2563EB;
}
.card-title {
font-size: 30rpx;
font-weight: 700;
color: #1F2937;
margin-bottom: 8rpx;
color: #111827;
margin-bottom: 6rpx;
}
.card-en {
font-size: 20rpx;
color: #9CA3AF;
line-height: 1.3;
font-weight: 400;
}
/* 助诊服务 */
.assist-section {
background: #FFFFFF;
padding: 50rpx 32rpx;
margin-top: 20rpx;
.card-icon-wrap {
width: 88rpx;
height: 88rpx;
border-radius: 22rpx;
background: #FEF9C3;
display: flex;
align-items: center;
justify-content: center;
margin-left: 16rpx;
flex-shrink: 0;
}
.other-section {
background: #FFFFFF;
padding: 50rpx 32rpx;
margin-top: 20rpx;
.vip-icon-wrap {
background: #DBEAFE;
}
.tool-section {
.card-img {
width: 52rpx;
height: 52rpx;
}
/* 通用区块卡片 */
.section-card {
background: #FFFFFF;
padding: 50rpx 32rpx;
margin-top: 20rpx;
border-radius: 24rpx;
padding: 32rpx 28rpx;
margin-top: 24rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32rpx;
padding: 0rpx 30rpx;
margin-bottom: 24rpx;
}
.section-title-wrap {
@@ -204,22 +199,35 @@ page {
align-items: center;
}
.section-icon {
margin-right: 12rpx;
color: #D4A853;
.section-accent {
width: 6rpx;
height: 32rpx;
background: #F59E0B;
border-radius: 4rpx;
margin-right: 14rpx;
}
.section-title {
font-size: 34rpx;
font-size: 32rpx;
font-weight: 700;
color: #1F2937;
color: #111827;
letter-spacing: 2rpx;
}
.section-more {
display: flex;
align-items: center;
font-size: 26rpx;
color: #2D6A4F;
color: #6B7280;
font-weight: 500;
}
.more-icon {
margin-left: 4rpx;
color: #9CA3AF;
}
/* 网格 */
.assist-grid {
display: flex;
flex-wrap: wrap;
@@ -231,26 +239,35 @@ page {
flex-direction: column;
align-items: center;
padding: 20rpx 0;
transition: transform 0.15s ease;
}
.assist-item:active {
transform: scale(0.95);
}
.assist-icon-circle {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
border: 2rpx solid #E8F0EC;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
background: #FFFFFF;
background: #F9FAFB;
border: 2rpx solid #F3F4F6;
}
.assist-icon {
font-size: 44rpx;
color: #4B5563;
}
.assist-name {
font-size: 28rpx;
color: #6B7280;
font-weight: 400;
color: #4B5563;
font-weight: 500;
}
.footer-space {
height: 40rpx;
}

View File

@@ -53,7 +53,7 @@ page {
.subtitle {
display: block;
font-size: 24rpx;
color: #9CA3AF;
color: #6B8E7B;
margin-top: 6rpx;
}
@@ -62,7 +62,7 @@ page {
.empty {
text-align: center;
padding: 80rpx 24rpx;
color: #9CA3AF;
color: #6B7280;
font-size: 26rpx;
}
@@ -76,11 +76,10 @@ page {
align-items: center;
justify-content: space-between;
background: #FFFFFF;
border-radius: 16rpx;
border-radius: 20rpx;
padding: 20rpx 24rpx;
margin-bottom: 12rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.04);
border: 1rpx solid #F0F0F0;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
}
.info {
@@ -111,7 +110,7 @@ page {
align-items: center;
gap: 8rpx;
padding: 8rpx 14rpx;
background: #F5F7F6;
background: #FAFAFA;
border-radius: 8rpx;
width: fit-content;
}

View File

@@ -1,6 +1,6 @@
/* pages/hospital/ranking.wxss */
page {
background: linear-gradient(180deg, #E8F5E9 0%, #F1F8F2 30%, #F5FAF6 100%);
background-color: #F5F7F6;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
@@ -24,7 +24,7 @@ page {
.header-note {
font-size: 24rpx;
color: #9CA3AF;
color: #6B8E7B;
margin-top: 8rpx;
display: block;
}
@@ -40,7 +40,7 @@ page {
background: #FFFFFF;
border-radius: 40rpx;
padding: 16rpx 24rpx;
box-shadow: 0 2rpx 12rpx rgba(45, 106, 79, 0.08);
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
}
.search-input {
@@ -52,7 +52,7 @@ page {
}
.search-input::placeholder {
color: #9CA3AF;
color: #6B7280;
}
.search-clear {
@@ -65,7 +65,7 @@ page {
justify-content: center;
padding: 0 32rpx;
margin-top: 8rpx;
border-bottom: 1rpx solid rgba(45, 106, 79, 0.08);
border-bottom: 1rpx solid #F3F4F6;
}
.tab-item {
@@ -92,7 +92,7 @@ page {
transform: translateX(-50%);
width: 48rpx;
height: 4rpx;
background: linear-gradient(90deg, #2D6A4F 0%, #40916C 100%);
background: #2D6A4F;
border-radius: 2rpx;
}
@@ -111,7 +111,7 @@ page {
background: #FFFFFF;
border-radius: 20rpx;
margin-bottom: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(45, 106, 79, 0.08);
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
overflow: hidden;
}
@@ -216,7 +216,7 @@ page {
/* 医院详情展开 */
.hospital-detail {
padding: 0 24rpx 24rpx 24rpx;
border-top: 1rpx solid rgba(45, 106, 79, 0.06);
border-top: 1rpx solid #F3F4F6;
}
.detail-title {
@@ -273,7 +273,7 @@ page {
.dept-filter {
width: 200rpx;
background: #FFFFFF;
border-right: 1rpx solid rgba(45, 106, 79, 0.06);
border-right: 1rpx solid #F3F4F6;
}
.dept-sidebar {
@@ -321,7 +321,7 @@ page {
.dept-ranking-subtitle {
font-size: 24rpx;
color: #9CA3AF;
color: #6B8E7B;
margin-top: 4rpx;
display: block;
}
@@ -330,7 +330,7 @@ page {
.top10-list {
background: #FFFFFF;
border-radius: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(45, 106, 79, 0.08);
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
overflow: hidden;
}
@@ -338,7 +338,7 @@ page {
display: flex;
align-items: center;
padding: 20rpx 24rpx;
border-bottom: 1rpx solid rgba(45, 106, 79, 0.04);
border-bottom: 1rpx solid #F3F4F6;
}
.top10-item:last-child {
@@ -399,7 +399,7 @@ page {
.top10-score {
font-size: 24rpx;
color: #9CA3AF;
color: #6B7280;
margin-top: 4rpx;
display: block;
}
@@ -410,7 +410,7 @@ page {
background: #FFFFFF;
border-radius: 20rpx;
padding: 20rpx 24rpx;
box-shadow: 0 4rpx 16rpx rgba(45, 106, 79, 0.08);
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
}
.nominated-title {
@@ -445,6 +445,6 @@ page {
.empty-text {
font-size: 28rpx;
color: #9CA3AF;
color: #6B7280;
margin-top: 24rpx;
}