This commit is contained in:
lik
2026-06-14 11:46:10 +08:00
parent 894a9881d7
commit f8f7afceb8
14 changed files with 1340 additions and 509 deletions

View File

@@ -4,7 +4,8 @@
"pages/ai/index", "pages/ai/index",
"pages/set/index", "pages/set/index",
"pages/order/index", "pages/order/index",
"pages/customer/index" "pages/customer/index",
"pages/order/orderDetail"
], ],
"usingComponents": { "usingComponents": {
"t-toast": "tdesign-miniprogram/toast/toast" "t-toast": "tdesign-miniprogram/toast/toast"

View File

@@ -3,6 +3,7 @@ const API = require('../../utils/api.js')
Page({ Page({
data: { data: {
today: '',
todayCount: 0, todayCount: 0,
pendingCount: 0, pendingCount: 0,
completedCount: 0, completedCount: 0,
@@ -10,9 +11,7 @@ Page({
{ icon: '/images/icon_order.png', name: '订单管理', url: '/pages/order/index' }, { icon: '/images/icon_order.png', name: '订单管理', url: '/pages/order/index' },
{ icon: '/images/icon_patient.png', name: '患者管理', url: '/pages/patient/index' }, { icon: '/images/icon_patient.png', name: '患者管理', url: '/pages/patient/index' },
{ icon: '/images/icon_escort.png', name: '陪诊员管理', url: '/pages/escort/index' }, { icon: '/images/icon_escort.png', name: '陪诊员管理', url: '/pages/escort/index' },
{ icon: '/images/icon_schedule.png', name: '排班管理', url: '/pages/schedule/index' }, { icon: '/images/icon_schedule.png', name: '排班管理', url: '/pages/schedule/index' }
{ icon: '/images/icon_stats.png', name: '数据统计', url: '/pages/stats/index' },
{ icon: '/images/icon_setting.png', name: '系统设置', url: '/pages/setting/index' }
], ],
todayOrders: [], todayOrders: [],
statusMap: { statusMap: {
@@ -38,6 +37,9 @@ Page({
}, },
onLoad(options) { onLoad(options) {
const now = new Date();
const today = now.toISOString().substring(0, 10);
this.setData({ today });
this.getTodayOrders(); this.getTodayOrders();
this.getStats(); this.getStats();
}, },

View File

@@ -1,3 +1,4 @@
{ {
"navigationBarTitleText": "暖橙陪诊",
"usingComponents": {} "usingComponents": {}
} }

View File

@@ -1,28 +1,44 @@
<!--pages/home/index.wxml--> <!--pages/home/index.wxml-->
<view class="container"> <view class="page">
<!-- 顶部统计卡片 --> <!-- 顶部问候 -->
<view class="stats-section"> <view class="header">
<view class="stats-card"> <view class="greeting">
<text class="stats-num">{{todayCount}}</text> <text class="greeting-text">您好,管理员</text>
<text class="stats-label">今日订单</text> <text class="greeting-sub">今天是 {{today}}</text>
</view>
<view class="stats-card">
<text class="stats-num">{{pendingCount}}</text>
<text class="stats-label">待处理</text>
</view>
<view class="stats-card">
<text class="stats-num">{{completedCount}}</text>
<text class="stats-label">已完成</text>
</view> </view>
</view> </view>
<!-- 功能菜单 --> <!-- 数据统计 -->
<view class="menu-section"> <view class="stats-container">
<view class="section-title">功能菜单</view> <view class="stats-grid">
<view class="stat-card">
<view class="stat-value">{{todayCount}}</view>
<view class="stat-label">新增用户</view>
</view>
<view class="stat-card">
<view class="stat-value">{{todayCount}}</view>
<view class="stat-label">新增预约</view>
</view>
<view class="stat-card">
<view class="stat-value">{{pendingCount}}</view>
<view class="stat-label">待处理</view>
</view>
<view class="stat-card">
<view class="stat-value">{{completedCount}}</view>
<view class="stat-label">已完成</view>
</view>
</view>
</view>
<!-- 功能入口 -->
<view class="section">
<view class="section-header">
<text class="section-title">快捷入口</text>
</view>
<view class="menu-grid"> <view class="menu-grid">
<view class="menu-item" wx:for="{{menuList}}" wx:key="index" bindtap="navigateTo" data-url="{{item.url}}"> <view class="menu-card" wx:for="{{menuList}}" wx:key="index" bindtap="navigateTo" data-url="{{item.url}}">
<view class="menu-icon"> <view class="menu-icon-wrap">
<text class="icon-text">{{item.name[0]}}</text> <text class="menu-icon-text">{{item.name[0]}}</text>
</view> </view>
<text class="menu-name">{{item.name}}</text> <text class="menu-name">{{item.name}}</text>
</view> </view>
@@ -30,40 +46,52 @@
</view> </view>
<!-- 今日订单 --> <!-- 今日订单 -->
<view class="order-section"> <view class="section">
<view class="section-header"> <view class="section-header">
<text class="section-title">今日订单</text> <text class="section-title">今日订单</text>
<text class="view-all" bindtap="viewAllOrders">查看全部 ></text> <view class="view-all" bindtap="viewAllOrders">
<text>全部</text>
<text class="arrow">→</text>
</view>
</view> </view>
<view class="order-list">
<view class="order-item" wx:for="{{todayOrders}}" wx:key="_id"> <view class="order-list" wx:if="{{todayOrders.length > 0}}">
<view class="order-header"> <view class="order-card" wx:for="{{todayOrders}}" wx:key="_id">
<text class="order-id">{{item._id}}</text> <view class="order-top">
<text class="order-status status-{{item.status}}">{{statusMap[item.status] || item.status}}</text> <text class="order-no">#{{item._id}}</text>
<view class="status-tag status-{{item.status}}">
<text>{{statusMap[item.status] || item.status}}</text>
</view>
</view> </view>
<view class="order-info">
<view class="info-row"> <view class="order-body">
<text class="info-label">患者</text> <view class="order-row">
<text class="info-value">{{item.patient.name}}</text> <text class="row-label">患者</text>
<text class="row-value">{{item.patient.name}}</text>
</view> </view>
<view class="info-row"> <view class="order-row">
<text class="info-label">医院</text> <text class="row-label">医院</text>
<text class="info-value">{{item.hospital.name}} · {{item.hospital.department}}</text> <text class="row-value">{{item.hospital.name}} · {{item.hospital.department}}</text>
</view> </view>
<view class="info-row"> <view class="order-row">
<text class="info-label">时间</text> <text class="row-label">时间</text>
<text class="info-value">{{item.schedule.date}}</text> <text class="row-value">{{item.schedule.date}}</text>
</view> </view>
<view class="info-row"> <view class="order-row">
<text class="info-label">服务</text> <text class="row-label">服务</text>
<text class="info-value">{{item.escort.serviceName}}</text> <text class="row-value">{{item.escort.serviceName}}</text>
</view>
<view class="info-row">
<text class="info-label">费用</text>
<text class="info-value fee-value">¥{{item.payment.totalFee}}</text>
</view> </view>
</view> </view>
<view class="order-footer">
<text class="fee-label">服务费用</text>
<text class="fee-value">¥{{item.payment.totalFee}}</text>
</view>
</view> </view>
</view> </view>
<view class="empty-state" wx:else>
<text class="empty-text">暂无今日订单</text>
</view>
</view> </view>
</view> </view>

View File

@@ -1,106 +1,106 @@
/* pages/home/index.wxss */ /* pages/home/index.wxss */
.container {
padding: 20rpx; .page {
background-color: #f5f6fa;
min-height: 100vh; min-height: 100vh;
background: #f7f8fc;
padding-bottom: 40rpx;
} }
/* 统计卡片 */ /* === 顶部问候 === */
.stats-section { .header {
display: flex; background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
justify-content: space-between; padding: 60rpx 40rpx 80rpx;
margin-bottom: 20rpx; position: relative;
overflow: hidden;
} }
.stats-card { .header::after {
flex: 1; content: '';
background: #fff; position: absolute;
border-radius: 16rpx; top: -60rpx;
padding: 30rpx 0; right: -40rpx;
margin: 0 10rpx; width: 280rpx;
text-align: center; height: 280rpx;
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04); border-radius: 50%;
background: rgba(255, 255, 255, 0.03);
} }
.stats-card:first-child { .header::before {
margin-left: 0; content: '';
position: absolute;
bottom: -100rpx;
right: 80rpx;
width: 200rpx;
height: 200rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.02);
} }
.stats-card:last-child { .greeting {
margin-right: 0; position: relative;
z-index: 1;
} }
.stats-num { .greeting-text {
display: block; display: block;
font-size: 48rpx; font-size: 44rpx;
font-weight: 600; font-weight: 700;
color: #2c3e50; color: #ffffff;
margin-bottom: 8rpx; letter-spacing: 2rpx;
}
.stats-label {
display: block;
font-size: 26rpx;
color: #7f8c8d;
}
/* 功能菜单 */
.menu-section {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
}
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #2c3e50;
margin-bottom: 24rpx;
}
.menu-grid {
display: flex;
flex-wrap: wrap;
}
.menu-item {
width: 25%;
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 0;
}
.menu-icon {
width: 88rpx;
height: 88rpx;
background: #e8f4fd;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12rpx; margin-bottom: 12rpx;
} }
.icon-text { .greeting-sub {
font-size: 36rpx; display: block;
color: #3498db;
font-weight: 600;
}
.menu-name {
font-size: 26rpx; font-size: 26rpx;
color: #555; color: rgba(255, 255, 255, 0.5);
font-weight: 300;
letter-spacing: 1rpx;
} }
/* 今日订单 */ /* === 数据统计 === */
.order-section { .stats-container {
background: #fff; margin: -40rpx 30rpx 0;
border-radius: 16rpx; position: relative;
padding: 30rpx; z-index: 2;
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04); }
.stats-grid {
display: flex;
gap: 16rpx;
}
.stat-card {
flex: 1;
background: #ffffff;
border-radius: 20rpx;
padding: 28rpx 16rpx;
text-align: center;
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.06);
transition: transform 0.2s;
}
.stat-value {
display: block;
font-size: 48rpx;
font-weight: 700;
color: #1a1a2e;
line-height: 1.2;
margin-bottom: 8rpx;
font-family: 'DIN Alternate', 'Helvetica Neue', sans-serif;
}
.stat-label {
display: block;
font-size: 22rpx;
color: #a0a3bd;
font-weight: 400;
letter-spacing: 1rpx;
}
/* === 通用 Section === */
.section {
margin: 32rpx 30rpx 0;
} }
.section-header { .section-header {
@@ -110,99 +110,183 @@
margin-bottom: 24rpx; margin-bottom: 24rpx;
} }
.section-header .section-title { .section-title {
margin-bottom: 0; font-size: 32rpx;
font-weight: 700;
color: #1a1a2e;
letter-spacing: 1rpx;
} }
.view-all { .view-all {
font-size: 26rpx; display: flex;
color: #3498db; align-items: center;
gap: 6rpx;
font-size: 24rpx;
color: #a0a3bd;
} }
.view-all .arrow {
font-size: 28rpx;
color: #a0a3bd;
}
/* === 功能菜单 === */
.menu-grid {
display: flex;
gap: 16rpx;
}
.menu-card {
flex: 1;
background: #ffffff;
border-radius: 20rpx;
padding: 32rpx 0;
display: flex;
flex-direction: column;
align-items: center;
gap: 16rpx;
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.04);
}
.menu-icon-wrap {
width: 80rpx;
height: 80rpx;
border-radius: 20rpx;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
}
.menu-icon-text {
font-size: 32rpx;
font-weight: 700;
color: #ffffff;
}
.menu-name {
font-size: 24rpx;
color: #5a5d7a;
font-weight: 500;
}
/* === 订单列表 === */
.order-list { .order-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 20rpx; gap: 20rpx;
} }
.order-item { .order-card {
background: #f8f9fa; background: #ffffff;
border-radius: 12rpx; border-radius: 20rpx;
padding: 24rpx; padding: 28rpx 32rpx;
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.04);
} }
.order-header { .order-top {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 16rpx; padding-bottom: 20rpx;
border-bottom: 1rpx solid #f0f1f5;
} }
.order-id { .order-no {
font-size: 26rpx;
color: #7f8c8d;
}
.order-status {
font-size: 24rpx; font-size: 24rpx;
padding: 4rpx 16rpx; color: #a0a3bd;
border-radius: 8rpx; font-weight: 500;
font-family: 'DIN Alternate', 'Helvetica Neue', monospace;
}
.status-tag {
font-size: 22rpx;
padding: 6rpx 20rpx;
border-radius: 30rpx;
font-weight: 500;
} }
.status-pending { .status-pending {
background: #fff3e0; background: #fff8e6;
color: #f39c12; color: #e6a23c;
}
.status-in_progress {
background: #e8f5e9;
color: #27ae60;
} }
.status-confirmed { .status-confirmed {
background: #e3f2fd; background: #ecf5ff;
color: #2980b9; color: #409eff;
} }
.status-pending { .status-in_progress {
background: #fff3e0; background: #f0f9eb;
color: #f39c12; color: #67c23a;
} }
.status-completed { .status-completed {
background: #f3e5f5; background: #f4f0ff;
color: #8e44ad; color: #7c5cfc;
} }
.status-cancelled { .status-cancelled {
background: #fafafa; background: #f5f5f5;
color: #95a5a6; color: #b0b0b0;
} }
.order-info { .order-body {
padding: 20rpx 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10rpx; gap: 14rpx;
} }
.info-row { .order-row {
display: flex; display: flex;
align-items: center; align-items: baseline;
} }
.info-label { .row-label {
font-size: 26rpx; font-size: 24rpx;
color: #95a5a6; color: #a0a3bd;
width: 80rpx; width: 72rpx;
flex-shrink: 0; flex-shrink: 0;
} }
.info-value { .row-value {
font-size: 28rpx; font-size: 26rpx;
color: #2c3e50; color: #3a3d5c;
flex: 1;
}
.order-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 20rpx;
border-top: 1rpx solid #f0f1f5;
}
.fee-label {
font-size: 24rpx;
color: #a0a3bd;
} }
.fee-value { .fee-value {
color: #e74c3c; font-size: 34rpx;
font-weight: 600; font-weight: 700;
color: #1a1a2e;
font-family: 'DIN Alternate', 'Helvetica Neue', sans-serif;
}
/* === 空状态 === */
.empty-state {
background: #ffffff;
border-radius: 20rpx;
padding: 80rpx 0;
text-align: center;
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.04);
}
.empty-text {
font-size: 28rpx;
color: #c0c3d4;
font-weight: 400;
} }

View File

@@ -152,6 +152,7 @@ Page({
return orders.map(order => ({ return orders.map(order => ({
...order, ...order,
statusText: STATUS_MAP[order.status]?.text || order.status, statusText: STATUS_MAP[order.status]?.text || order.status,
patientFirstChar: (order.patient?.name || '?')[0],
schedule: { schedule: {
...order.schedule, ...order.schedule,
dateText: this.formatDate(order.schedule?.date) dateText: this.formatDate(order.schedule?.date)
@@ -250,7 +251,7 @@ Page({
onOrderDetail(e) { onOrderDetail(e) {
const id = e.currentTarget.dataset.id; const id = e.currentTarget.dataset.id;
wx.navigateTo({ wx.navigateTo({
url: `/pages/order/detail?id=${id}` url: `/pages/order/orderDetail?id=${id}`
}); });
}, },
@@ -275,7 +276,7 @@ Page({
if (action === 'detail') { if (action === 'detail') {
wx.navigateTo({ wx.navigateTo({
url: `/pages/order/detail?id=${id}` url: `/pages/order/orderDetail?id=${id}`
}); });
return; return;
} }

View File

@@ -1,42 +1,88 @@
/* pages/order/index.less */ /* pages/order/index.less */
// 颜色变量 - 参考图浅色社交风格 @bg: #f7f8fc;
@bg-primary: #f5f6fa; @card: #ffffff;
@bg-secondary: #ffffff; @dark: #1a1a2e;
@bg-card: #ffffff; @text: #3a3d5c;
@accent-primary: #4c6ef5; @muted: #a0a3bd;
@accent-secondary: #6b7aff; @border: #f0f1f5;
@accent-gradient-start: #4c6ef5; @accent: #667eea;
@accent-gradient-end: #748ffc; @accent-end: #764ba2;
@text-primary: #1a1a2e;
@text-secondary: #6b7280; @pending: #e6a23c;
@text-muted: #9ca3af; @confirmed: #409eff;
@border-color: #e5e7eb; @in-progress: #67c23a;
@status-pending: #f59f00; @completed: #7c5cfc;
@status-confirmed: #4c6ef5; @cancelled: #b0b0b0;
@status-in-progress: #20c997;
@status-completed: #51cf66;
@status-cancelled: #ff6b6b;
@divider-color: #f3f4f6;
page { page {
background-color: @bg-primary; background-color: @bg;
color: @text-primary;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
} }
.order-page { .page {
min-height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100vh; background: @bg;
background-color: @bg-primary;
} }
// ========== 筛选区域 ========== /* === 顶部 === */
.filter-section { .header {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
padding: 60rpx 40rpx 70rpx;
position: relative;
overflow: hidden;
&::after {
content: '';
position: absolute;
top: -80rpx;
right: -60rpx;
width: 280rpx;
height: 280rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.03);
}
&::before {
content: '';
position: absolute;
bottom: -120rpx;
left: -80rpx;
width: 200rpx;
height: 200rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.02);
}
}
.header-content {
position: relative;
z-index: 1;
}
.header-title {
display: block;
font-size: 44rpx;
font-weight: 700;
color: #fff;
letter-spacing: 2rpx;
margin-bottom: 12rpx;
}
.header-sub {
display: block;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.5);
font-weight: 300;
letter-spacing: 1rpx;
}
/* === 筛选栏 === */
.filter-bar {
background: @card;
padding: 20rpx 0; padding: 20rpx 0;
background-color: @bg-secondary; border-bottom: 1rpx solid @border;
border-bottom: 1rpx solid @border-color;
} }
.filter-scroll { .filter-scroll {
@@ -46,69 +92,61 @@ page {
.filter-list { .filter-list {
display: inline-flex; display: inline-flex;
padding: 0 24rpx; padding: 0 24rpx;
gap: 20rpx; gap: 16rpx;
} }
.filter-item { .filter-tag {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
padding: 16rpx 32rpx; padding: 12rpx 28rpx;
background-color: @bg-primary; background: @bg;
border-radius: 32rpx; border-radius: 28rpx;
border: 1rpx solid @border-color; font-size: 24rpx;
transition: all 0.3s ease; color: @muted;
border: 1rpx solid transparent;
transition: all 0.25s;
&.active { &.active {
background: linear-gradient(135deg, @accent-gradient-start, @accent-gradient-end); background: linear-gradient(135deg, @accent, @accent-end);
color: #fff;
border-color: transparent; border-color: transparent;
box-shadow: 0 4rpx 16rpx rgba(76, 110, 245, 0.25); box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.3);
.filter-text { .filter-count {
color: #ffffff; background: rgba(255, 255, 255, 0.25);
font-weight: 600; color: #fff;
}
.filter-badge {
background-color: #ffffff;
color: @accent-primary;
} }
} }
} }
.filter-text { .filter-count {
font-size: 26rpx;
color: @text-secondary;
line-height: 1;
}
.filter-badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 32rpx; min-width: 32rpx;
height: 32rpx; height: 32rpx;
padding: 0 8rpx; padding: 0 8rpx;
margin-left: 8rpx; margin-left: 8rpx;
background-color: @status-cancelled; background: rgba(0, 0, 0, 0.06);
border-radius: 16rpx; border-radius: 16rpx;
font-size: 20rpx; font-size: 20rpx;
color: #ffffff; color: @muted;
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: 600; font-weight: 600;
} }
// ========== 订单列表区域 ========== /* === 列表区域 === */
.order-list { .list-area {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
.order-scroll { .list-scroll {
height: 100%; height: 100%;
padding: 0 24rpx; padding: 0 24rpx;
} }
.loading-container, .loading-box,
.empty-container { .empty-box {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -116,239 +154,197 @@ page {
} }
.loading-text { .loading-text {
color: @text-secondary !important; color: @muted !important;
font-size: 26rpx !important; font-size: 26rpx !important;
} }
.empty-text { .empty-text {
color: @text-secondary !important; color: @muted !important;
font-size: 28rpx !important; font-size: 28rpx !important;
} }
.empty-action { .empty-btn {
margin-top: 30rpx; margin-top: 24rpx;
padding: 16rpx 48rpx; padding: 14rpx 48rpx;
background: linear-gradient(135deg, @accent-gradient-start, @accent-gradient-end); background: linear-gradient(135deg, @accent, @accent-end);
color: #ffffff; color: #fff;
font-size: 28rpx; font-size: 26rpx;
border-radius: 32rpx; border-radius: 28rpx;
display: inline-block; display: inline-block;
} }
// ========== 订单卡片 ========== /* === 订单卡片 === */
.order-cards { .card-list {
padding: 24rpx 0 40rpx; padding: 24rpx 0 40rpx;
} }
.order-card { .order-card {
margin-bottom: 24rpx; margin-bottom: 20rpx;
background-color: @bg-card; background: @card;
border-radius: 24rpx; border-radius: 20rpx;
border: 1rpx solid @border-color; box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.04);
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
overflow: hidden; overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.2s ease;
&:active { &:active {
transform: scale(0.98); opacity: 0.92;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
} }
} }
.card-header { .card-top {
display: flex; display: flex;
justify-content: flex-end;
align-items: center; align-items: center;
justify-content: space-between; padding: 20rpx 28rpx 0;
padding: 28rpx 28rpx 20rpx;
} }
.order-id { .order-no {
display: flex;
align-items: center;
gap: 10rpx;
}
.order-id-text {
font-size: 24rpx; font-size: 24rpx;
color: @text-muted; color: @muted;
font-weight: 500;
font-family: 'DIN Alternate', 'Helvetica Neue', monospace;
}
.status-badge {
font-size: 22rpx;
padding: 6rpx 20rpx;
border-radius: 24rpx;
font-weight: 500; font-weight: 500;
} }
.status-tag { .status-pending {
display: inline-flex; background: #fff8e6;
align-items: center; color: @pending;
padding: 8rpx 18rpx;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: 600;
&.pending {
background-color: rgba(245, 159, 0, 0.1);
color: @status-pending;
}
&.confirmed {
background-color: rgba(76, 110, 245, 0.1);
color: @accent-primary;
}
&.in_progress {
background-color: rgba(32, 201, 151, 0.1);
color: @status-in-progress;
}
&.completed {
background-color: rgba(81, 207, 102, 0.1);
color: @status-completed;
}
&.cancelled {
background-color: rgba(255, 107, 107, 0.1);
color: @status-cancelled;
}
} }
// ========== 卡片主体 ========== .status-confirmed {
.card-body { background: #ecf5ff;
color: @confirmed;
}
.status-in_progress {
background: #f0f9eb;
color: @in-progress;
}
.status-completed {
background: #f4f0ff;
color: @completed;
}
.status-cancelled {
background: #f5f5f5;
color: @cancelled;
}
/* === 卡片主体 === */
.card-main {
padding: 0 28rpx; padding: 0 28rpx;
} }
.patient-row { .patient-line {
margin-bottom: 20rpx;
}
.patient-info {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 24rpx; gap: 20rpx;
margin-bottom: 16rpx;
} }
.patient-avatar { .patient-avatar {
width: 80rpx; width: 72rpx;
height: 80rpx; height: 72rpx;
background: linear-gradient(135deg, @accent-gradient-start, @accent-gradient-end);
border-radius: 50%; border-radius: 50%;
background: linear-gradient(135deg, @accent, @accent-end);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-shrink: 0; flex-shrink: 0;
box-shadow: 0 4rpx 12rpx rgba(76, 110, 245, 0.25);
} }
.avatar-text { .avatar-char {
font-size: 30rpx; font-size: 28rpx;
font-weight: 600; font-weight: 700;
color: #ffffff; color: #fff;
} }
.patient-detail { .patient-meta {
flex: 1; flex: 1;
display: flex;
flex-direction: column;
gap: 8rpx;
} }
.patient-name-row { .patient-name-row {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 14rpx; gap: 12rpx;
margin-bottom: 4rpx;
} }
.patient-name { .patient-name {
font-size: 32rpx; font-size: 30rpx;
font-weight: 600; font-weight: 600;
color: @text-primary; color: @dark;
} }
.patient-gender { .patient-sex {
font-size: 22rpx; font-size: 20rpx;
padding: 4rpx 12rpx; padding: 2rpx 10rpx;
border-radius: 10rpx; border-radius: 8rpx;
background-color: rgba(76, 110, 245, 0.1);
color: @accent-primary;
font-weight: 500; font-weight: 500;
&.male { &.male {
background-color: rgba(76, 110, 245, 0.1); background: rgba(102, 126, 234, 0.1);
color: @accent-primary; color: @accent;
} }
&.female { &.female {
background-color: rgba(255, 107, 107, 0.1); background: rgba(234, 102, 150, 0.1);
color: @status-cancelled; color: #ea6696;
} }
} }
.patient-age { .patient-age {
font-size: 24rpx; font-size: 22rpx;
color: @text-secondary; color: @muted;
font-weight: 500;
} }
.patient-phone { .patient-phone {
font-size: 24rpx; font-size: 24rpx;
color: @text-muted; color: @muted;
} }
.info-divider { .divider {
height: 1rpx; height: 1rpx;
background-color: @divider-color; background: @border;
margin: 20rpx 0; margin: 16rpx 0;
} }
.info-item { .info-line {
display: flex; display: flex;
align-items: flex-start; align-items: baseline;
gap: 14rpx; margin-bottom: 12rpx;
margin-bottom: 14rpx;
} }
.info-content { .line-label {
display: flex;
flex-direction: column;
gap: 6rpx;
}
.hospital-name {
font-size: 28rpx;
color: @text-primary;
font-weight: 500;
}
.department-name {
font-size: 24rpx; font-size: 24rpx;
color: @text-secondary; color: @muted;
width: 64rpx;
flex-shrink: 0;
} }
.service-name { .line-value {
font-size: 26rpx; font-size: 26rpx;
color: @text-secondary; color: @text;
font-weight: 500; flex: 1;
} }
.time-text { /* === 卡片底部 === */
font-size: 26rpx; .card-bottom {
color: @text-secondary;
font-weight: 500;
}
.attendant-name {
font-size: 26rpx;
color: @text-secondary;
font-weight: 500;
}
// ========== 卡片底部 ==========
.card-footer {
display: flex; display: flex;
align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 24rpx 28rpx 28rpx; align-items: center;
margin-top: 12rpx; padding: 20rpx 28rpx 24rpx;
border-top: 1rpx solid @divider-color; margin-top: 8rpx;
border-top: 1rpx solid @border;
} }
.fee-section { .fee-area {
display: flex; display: flex;
align-items: baseline; align-items: baseline;
gap: 8rpx; gap: 8rpx;
@@ -356,61 +352,54 @@ page {
.fee-label { .fee-label {
font-size: 24rpx; font-size: 24rpx;
color: @text-muted; color: @muted;
} }
.fee-value { .fee-amount {
font-size: 38rpx; font-size: 36rpx;
font-weight: 700; font-weight: 700;
color: @status-pending; color: @dark;
font-family: 'DIN Alternate', 'Helvetica Neue', sans-serif;
} }
.action-buttons { .action-area {
display: flex; display: flex;
gap: 16rpx; gap: 14rpx;
} }
.btn { .action-btn {
display: inline-flex; padding: 14rpx 32rpx;
align-items: center; border-radius: 24rpx;
justify-content: center; font-size: 24rpx;
padding: 16rpx 36rpx;
border-radius: 28rpx;
font-size: 26rpx;
font-weight: 500; font-weight: 500;
transition: all 0.2s ease; transition: all 0.2s;
&:active { &:active {
transform: scale(0.95); transform: scale(0.95);
opacity: 0.9;
} }
} }
.btn-primary { .btn-solid {
background: linear-gradient(135deg, @accent-gradient-start, @accent-gradient-end); background: linear-gradient(135deg, @accent, @accent-end);
color: #ffffff; color: #fff;
box-shadow: 0 4rpx 16rpx rgba(76, 110, 245, 0.25); box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.25);
} }
.btn-secondary { .btn-ghost {
background-color: @bg-primary; background: @bg;
color: @text-secondary; color: @muted;
border: 1rpx solid @border-color; border: 1rpx solid @border;
&:active {
background-color: rgba(76, 110, 245, 0.05);
}
} }
// ========== 加载更多 ========== /* === 加载更多 === */
.load-more { .load-more {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 40rpx 20rpx; padding: 32rpx 20rpx;
} }
.no-more { .no-more {
font-size: 24rpx; font-size: 24rpx;
color: @text-muted; color: @muted;
} }

View File

@@ -1,166 +1,143 @@
<!--pages/order/index.wxml--> <!--pages/order/index.wxml-->
<view class="order-page"> <view class="page">
<!-- 顶部标题 -->
<view class="header">
<view class="header-content">
<text class="header-title">订单管理</text>
<text class="header-sub">共 {{stats.total}} 个订单</text>
</view>
</view>
<!-- 状态筛选标签 --> <!-- 状态筛选 -->
<view class="filter-section"> <view class="filter-bar">
<scroll-view class="filter-scroll" scroll-x enhanced show-scrollbar="{{false}}"> <scroll-view class="filter-scroll" scroll-x enhanced show-scrollbar="{{false}}">
<view class="filter-list"> <view class="filter-list">
<view <view
class="filter-item {{currentStatus === item.value ? 'active' : ''}}" class="filter-tag {{currentStatus === item.value ? 'active' : ''}}"
wx:for="{{statusFilters}}" wx:for="{{statusFilters}}"
wx:key="value" wx:key="value"
data-status="{{item.value}}" data-status="{{item.value}}"
bindtap="onStatusChange" bindtap="onStatusChange"
> >
<text class="filter-text">{{item.label}}</text> <text>{{item.label}}</text>
<view class="filter-badge" wx:if="{{item.count > 0}}">{{item.count}}</view> <text class="filter-count" wx:if="{{item.count > 0}}">{{item.count}}</text>
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
<!-- 订单列表 --> <!-- 订单列表 -->
<view class="order-list"> <view class="list-area">
<scroll-view <scroll-view
scroll-y scroll-y
class="order-scroll" class="list-scroll"
refresher-enabled refresher-enabled
refresher-triggered="{{isRefreshing}}" refresher-triggered="{{isRefreshing}}"
bindrefresherrefresh="onPullDownRefresh" bindrefresherrefresh="onPullDownRefresh"
bindscrolltolower="onReachBottom" bindscrolltolower="onReachBottom"
> >
<!-- 加载中 --> <!-- 加载中 -->
<view class="loading-container" wx:if="{{isLoading && orderList.length === 0}}"> <view class="loading-box" wx:if="{{isLoading && orderList.length === 0}}">
<t-loading theme="spinner" size="40rpx" text="加载中..." t-class-text="loading-text" /> <t-loading theme="spinner" size="40rpx" text="加载中..." t-class-text="loading-text" />
</view> </view>
<!-- 空状态 --> <!-- 空状态 -->
<view class="empty-container" wx:elif="{{!isLoading && orderList.length === 0}}"> <view class="empty-box" wx:elif="{{!isLoading && orderList.length === 0}}">
<t-empty icon="file" description="暂无订单数据" t-class-description="empty-text"> <t-empty icon="file" description="暂无订单" t-class-description="empty-text">
<view slot="action"> <view slot="action">
<view class="empty-action" bindtap="loadOrderList">刷新试试</view> <view class="empty-btn" bindtap="loadOrderList">刷新</view>
</view> </view>
</t-empty> </t-empty>
</view> </view>
<!-- 订单卡片列表 --> <!-- 卡片列表 -->
<view class="order-cards" wx:else> <view class="card-list" wx:else>
<view <view
class="order-card {{item.status}}" class="order-card"
wx:for="{{orderList}}" wx:for="{{orderList}}"
wx:key="_id" wx:key="_id"
data-id="{{item._id}}" data-id="{{item._id}}"
bindtap="onOrderDetail" bindtap="onOrderDetail"
> >
<!-- 卡片头部 --> <!-- 卡片头部 -->
<view class="card-header"> <view class="card-top">
<view class="order-id"> <view class="status-badge status-{{item.status}}">
<t-icon name="file" size="28rpx" color="#6b7aff" />
<text class="order-id-text">订单 {{item.orderNo || item._id}}</text>
</view>
<view class="status-tag {{item.status}}">
<text>{{item.statusText}}</text> <text>{{item.statusText}}</text>
</view> </view>
</view> </view>
<!-- 患者信息 --> <!-- 患者信息 -->
<view class="card-body"> <view class="card-main">
<view class="patient-row"> <view class="patient-line">
<view class="patient-info"> <view class="patient-avatar">
<view class="patient-avatar"> <text class="avatar-char">{{item.patientFirstChar}}</text>
<text class="avatar-text">{{item.patient.name ? item.patient.name[0] : '患'}}</text> </view>
</view> <view class="patient-meta">
<view class="patient-detail"> <view class="patient-name-row">
<view class="patient-name-row"> <text class="patient-name">{{item.patient.name || '未知患者'}}</text>
<text class="patient-name">{{item.patient.name || '未知患者'}}</text> <text class="patient-sex {{item.patient.sex}}">{{item.patient.sex === 'male' ? '男' : item.patient.sex === 'female' ? '女' : ''}}</text>
<text class="patient-gender {{item.patient.sex}}">{{item.patient.sex === 'male' ? '男' : item.patient.sex === 'female' ? '女' : '未知'}}</text> <text class="patient-age" wx:if="{{item.patient.age}}">{{item.patient.age}}</text>
<text class="patient-age" wx:if="{{item.patient.age}}">{{item.patient.age}}岁</text>
</view>
<text class="patient-phone">{{item.patient.mobile || '暂无电话'}}</text>
</view> </view>
<text class="patient-phone">{{item.patient.mobile || '暂无电话'}}</text>
</view> </view>
</view> </view>
<view class="info-divider"></view> <view class="divider"></view>
<!-- 医院信息 --> <!-- 就诊信息 -->
<view class="hospital-row"> <view class="info-line">
<view class="info-item"> <text class="line-label">医院</text>
<t-icon name="location" size="26rpx" color="#8b9bff" /> <text class="line-value">{{item.hospital.name || '未知医院'}}{{item.hospital.department ? ' · ' + item.hospital.department : ''}}</text>
<view class="info-content">
<text class="hospital-name">{{item.hospital.name || '未知医院'}}</text>
<text class="department-name" wx:if="{{item.hospital.department}}">{{item.hospital.department}}</text>
</view>
</view>
</view> </view>
<view class="info-line" wx:if="{{item.escort.serviceName}}">
<!-- 陪诊服务 --> <text class="line-label">服务</text>
<view class="service-row" wx:if="{{item.escort.serviceName}}"> <text class="line-value">{{item.escort.serviceName}}</text>
<view class="info-item">
<t-icon name="service" size="26rpx" color="#8b9bff" />
<text class="service-name">{{item.escort.serviceName}}</text>
</view>
</view> </view>
<view class="info-line">
<!-- 预约时间 --> <text class="line-label">时间</text>
<view class="time-row"> <text class="line-value">{{item.schedule.dateText}} {{item.schedule.startTime || ''}}</text>
<view class="info-item">
<t-icon name="time" size="26rpx" color="#8b9bff" />
<text class="time-text">{{item.schedule.dateText}} {{item.schedule.startTime || ''}}</text>
</view>
</view> </view>
<view class="info-line" wx:if="{{item.attendant.name}}">
<!-- 陪诊员信息 --> <text class="line-label">陪诊</text>
<view class="attendant-row" wx:if="{{item.attendant.name}}"> <text class="line-value">{{item.attendant.name}}</text>
<view class="info-item">
<t-icon name="user" size="26rpx" color="#8b9bff" />
<text class="attendant-name">陪诊员:{{item.attendant.name}}</text>
</view>
</view> </view>
</view> </view>
<!-- 卡片底部 --> <!-- 卡片底部 -->
<view class="card-footer"> <view class="card-bottom">
<view class="fee-section"> <view class="fee-area">
<text class="fee-label">服务费用</text> <text class="fee-label">费用</text>
<text class="fee-value">¥{{item.payment.totalFee || 0}}</text> <text class="fee-amount">¥{{item.payment.totalFee || 0}}</text>
</view> </view>
<view class="action-buttons"> <view class="action-area">
<view <view
class="btn btn-secondary" class="action-btn btn-ghost"
wx:if="{{item.status === 'pending'}}" wx:if="{{item.status === 'pending'}}"
data-id="{{item._id}}" data-id="{{item._id}}"
data-action="cancel" data-action="cancel"
catchtap="onOrderAction" catchtap="onOrderAction"
>取消</view> >取消</view>
<view <view
class="btn btn-primary" class="action-btn btn-solid"
wx:if="{{item.status === 'pending'}}" wx:if="{{item.status === 'pending'}}"
data-id="{{item._id}}" data-id="{{item._id}}"
data-action="confirm" data-action="confirm"
catchtap="onOrderAction" catchtap="onOrderAction"
>确认</view> >确认</view>
<view <view
class="btn btn-primary" class="action-btn btn-solid"
wx:if="{{item.status === 'confirmed'}}" wx:if="{{item.status === 'confirmed'}}"
data-id="{{item._id}}" data-id="{{item._id}}"
data-action="start" data-action="start"
catchtap="onOrderAction" catchtap="onOrderAction"
>开始服务</view> >开始服务</view>
<view <view
class="btn btn-primary" class="action-btn btn-solid"
wx:if="{{item.status === 'in_progress'}}" wx:if="{{item.status === 'in_progress'}}"
data-id="{{item._id}}" data-id="{{item._id}}"
data-action="complete" data-action="complete"
catchtap="onOrderAction" catchtap="onOrderAction"
>完成</view> >完成</view>
<view
class="btn btn-secondary"
wx:if="{{item.status === 'completed' || item.status === 'cancelled'}}"
data-id="{{item._id}}"
data-action="detail"
catchtap="onOrderAction"
>查看详情</view>
</view> </view>
</view> </view>
</view> </view>

232
pages/order/orderDetail.js Normal file
View File

@@ -0,0 +1,232 @@
// pages/order/orderDetail.js
const API = require('../../utils/api.js')
const STATUS_MAP = {
pending: '待确认',
confirmed: '已确认',
in_progress: '进行中',
completed: '已完成',
cancelled: '已取消'
}
const STATUS_DESC_MAP = {
pending: '订单已创建,等待确认',
confirmed: '订单已确认,等待服务',
in_progress: '陪诊服务正在进行',
completed: '陪诊服务已完成',
cancelled: '订单已取消'
}
const PAYMENT_STATUS_MAP = {
unpaid: '未支付',
partial: '部分支付',
paid: '已支付',
refunded: '已退款'
}
function formatDate(timestamp) {
if (!timestamp) return ''
const date = new Date(timestamp)
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, '0')
const d = String(date.getDate()).padStart(2, '0')
return y + '-' + m + '-' + d
}
function formatTime(timestamp) {
if (!timestamp) return ''
const date = new Date(timestamp)
const h = String(date.getHours()).padStart(2, '0')
const min = String(date.getMinutes()).padStart(2, '0')
return h + ':' + min
}
function formatDateTime(timestamp) {
if (!timestamp) return ''
return formatDate(timestamp) + ' ' + formatTime(timestamp)
}
Page({
data: {
orderId: '',
loaded: false,
// 订单数据
order: null,
// 格式化后的显示字段
statusText: '',
statusDesc: '',
patientFirstChar: '',
attendantFirstChar: '',
scheduleDateText: '',
scheduleStartTimeText: '',
scheduleEndTimeText: '',
createtimeText: '',
updatetimeText: '',
paymentStatusText: '',
patientSexText: '',
attendantSexText: '',
sexRequirementText: '',
// 操作按钮配置
showConfirmBtn: false,
showCancelBtn: false,
showStartBtn: false,
showCompleteBtn: false
},
onLoad(options) {
const id = options.id || ''
this.setData({ orderId: id })
if (id) {
this.loadOrderDetail(id)
}
},
onPullDownRefresh() {
if (this.data.orderId) {
this.loadOrderDetail(this.data.orderId).then(() => {
wx.stopPullDownRefresh()
})
} else {
wx.stopPullDownRefresh()
}
},
async loadOrderDetail(id) {
wx.showLoading({ title: '加载中...' })
try {
const res = await API.escort.getRecordById(id)
wx.hideLoading()
if (res.code !== 0) {
wx.showToast({ title: res.message || '加载失败', icon: 'none' })
return
}
const order = res.data || {}
this.applyOrderData(order)
} catch (err) {
wx.hideLoading()
console.error('加载订单详情失败', err)
wx.showToast({ title: '网络错误', icon: 'none' })
}
},
applyOrderData(order) {
const status = order.status || 'pending'
const patient = order.patient || {}
const attendant = order.attendant || {}
const schedule = order.schedule || {}
const payment = order.payment || {}
const escort = order.escort || {}
const meta = order.meta || {}
this.setData({
loaded: true,
order: order,
statusText: STATUS_MAP[status] || status,
statusDesc: STATUS_DESC_MAP[status] || '',
patientFirstChar: (patient.name || '?')[0],
attendantFirstChar: (attendant.name || '?')[0],
scheduleDateText: formatDate(schedule.date),
scheduleStartTimeText: schedule.startTime || '',
scheduleEndTimeText: schedule.endTime || '',
createtimeText: formatDateTime(meta.createtime),
updatetimeText: formatDateTime(meta.updatetime),
paymentStatusText: PAYMENT_STATUS_MAP[payment.status] || payment.status || '未支付',
patientSexText: patient.sex === 'male' ? '男' : patient.sex === 'female' ? '女' : '',
attendantSexText: attendant.sex === 'male' ? '男' : attendant.sex === 'female' ? '女' : '',
sexRequirementText: escort.sexRequirement === 'male' ? '要求男陪诊' : escort.sexRequirement === 'female' ? '要求女陪诊' : '不限',
// 操作按钮
showConfirmBtn: status === 'pending',
showCancelBtn: status === 'pending',
showStartBtn: status === 'confirmed',
showCompleteBtn: status === 'in_progress'
})
},
// 拨打电话
callPhone(e) {
const phone = e.currentTarget.dataset.phone
if (!phone) {
wx.showToast({ title: '暂无电话', icon: 'none' })
return
}
wx.makePhoneCall({ phoneNumber: phone })
},
// 确认订单
onConfirm() {
wx.showModal({
title: '确认订单',
content: '确认接受此订单?',
confirmColor: '#4c6ef5',
success: (res) => {
if (res.confirm) {
this.updateStatus('confirmed')
}
}
})
},
// 取消订单
onCancel() {
wx.showModal({
title: '取消订单',
content: '确定要取消此订单?',
confirmColor: '#ff6b6b',
success: (res) => {
if (res.confirm) {
this.updateStatus('cancelled')
}
}
})
},
// 开始服务
onStart() {
wx.showModal({
title: '开始服务',
content: '确认开始陪诊服务?',
confirmColor: '#4c6ef5',
success: (res) => {
if (res.confirm) {
this.updateStatus('in_progress')
}
}
})
},
// 完成服务
onComplete() {
wx.showModal({
title: '完成服务',
content: '确认陪诊服务已完成?',
confirmColor: '#4c6ef5',
success: (res) => {
if (res.confirm) {
this.updateStatus('completed')
}
}
})
},
async updateStatus(newStatus) {
wx.showLoading({ title: '处理中...' })
try {
const res = await API.escort.updateStatus(this.data.orderId, { status: newStatus })
wx.hideLoading()
if (res.code !== 0) {
wx.showToast({ title: res.message || '操作失败', icon: 'none' })
return
}
wx.showToast({ title: '操作成功', icon: 'success' })
this.loadOrderDetail(this.data.orderId)
} catch (err) {
wx.hideLoading()
console.error('更新状态失败', err)
wx.showToast({ title: '网络错误', icon: 'none' })
}
}
})

View File

@@ -0,0 +1,6 @@
{
"navigationBarTitleText": "订单详情",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"usingComponents": {}
}

View File

@@ -0,0 +1,202 @@
<!--pages/order/orderDetail.wxml-->
<view class="detail-page">
<!-- 加载中 -->
<view class="loading-box" wx:if="{{!loaded}}">
<text class="loading-text">加载中...</text>
</view>
<block wx:if="{{loaded && order}}">
<!-- 顶部状态栏 -->
<view class="status-header status-{{order.status}}">
<view class="status-content">
<text class="status-text">{{statusText}}</text>
<text class="status-desc">{{statusDesc}}</text>
</view>
</view>
<!-- 患者信息 -->
<view class="info-section">
<text class="section-title">患者信息</text>
<view class="info-card">
<view class="patient-header">
<view class="patient-avatar">
<text class="avatar-text">{{patientFirstChar}}</text>
</view>
<view class="patient-info">
<view class="patient-name-row">
<text class="patient-name">{{order.patient.name || '未知患者'}}</text>
<text class="patient-sex {{order.patient.sex}}" wx:if="{{patientSexText}}">{{patientSexText}}</text>
<text class="patient-age" wx:if="{{order.patient.age}}">{{order.patient.age}}岁</text>
</view>
<view class="patient-phone" data-phone="{{order.patient.mobile}}" bindtap="callPhone">
<text>{{order.patient.mobile || '暂无电话'}}</text>
<text class="call-icon" wx:if="{{order.patient.mobile}}"> 拨打</text>
</view>
</view>
</view>
<view class="divider"></view>
<view class="info-row" wx:if="{{order.patient.weight}}">
<text class="info-label">体重</text>
<text class="info-value">{{order.patient.weight}}kg</text>
</view>
<view class="info-row" wx:if="{{order.patient.height}}">
<text class="info-label">身高</text>
<text class="info-value">{{order.patient.height}}cm</text>
</view>
<view class="info-row" wx:if="{{order.patient.idnumber}}">
<text class="info-label">身份证号</text>
<text class="info-value">{{order.patient.idnumber}}</text>
</view>
</view>
</view>
<!-- 就诊信息 -->
<view class="info-section">
<text class="section-title">就诊信息</text>
<view class="info-card">
<view class="info-row">
<text class="info-label">医院</text>
<text class="info-value">{{order.hospital.name || '未知医院'}}</text>
</view>
<view class="info-row" wx:if="{{order.hospital.province}}">
<text class="info-label">地区</text>
<text class="info-value">{{order.hospital.province}}</text>
</view>
<view class="info-row" wx:if="{{order.hospital.address}}">
<text class="info-label">地址</text>
<text class="info-value">{{order.hospital.address}}</text>
</view>
<view class="info-row" wx:if="{{order.hospital.department}}">
<text class="info-label">科室</text>
<text class="info-value">{{order.hospital.department}}</text>
</view>
<view class="info-row" wx:if="{{order.hospital.doctor}}">
<text class="info-label">医生</text>
<text class="info-value">{{order.hospital.doctor}}</text>
</view>
<view class="info-row" wx:if="{{order.hospital.medicalRecordNo}}">
<text class="info-label">病历号</text>
<text class="info-value">{{order.hospital.medicalRecordNo}}</text>
</view>
</view>
</view>
<!-- 服务信息 -->
<view class="info-section">
<text class="section-title">服务信息</text>
<view class="info-card">
<view class="info-row" wx:if="{{order.escort.serviceName}}">
<text class="info-label">服务类型</text>
<text class="info-value">{{order.escort.serviceName}}</text>
</view>
<view class="info-row">
<text class="info-label">性别要求</text>
<text class="info-value">{{sexRequirementText}}</text>
</view>
<view class="info-row">
<text class="info-label">预约日期</text>
<text class="info-value">{{scheduleDateText}}</text>
</view>
<view class="info-row" wx:if="{{scheduleStartTimeText}}">
<text class="info-label">开始时间</text>
<text class="info-value">{{scheduleStartTimeText}}</text>
</view>
<view class="info-row" wx:if="{{scheduleEndTimeText}}">
<text class="info-label">结束时间</text>
<text class="info-value">{{scheduleEndTimeText}}</text>
</view>
<view class="info-row" wx:if="{{order.schedule.duration}}">
<text class="info-label">服务时长</text>
<text class="info-value">{{order.schedule.duration}}分钟</text>
</view>
</view>
</view>
<!-- 陪诊员信息 -->
<view class="info-section" wx:if="{{order.attendant.name}}">
<text class="section-title">陪诊员</text>
<view class="info-card">
<view class="attendant-header">
<view class="attendant-avatar">
<text class="avatar-text">{{attendantFirstChar}}</text>
</view>
<view class="attendant-info">
<view class="attendant-name-row">
<text class="attendant-name">{{order.attendant.name}}</text>
<text class="patient-sex male" wx:if="{{attendantSexText}}">{{attendantSexText}}</text>
</view>
<view class="attendant-phone" data-phone="{{order.attendant.mobile}}" bindtap="callPhone">
<text>{{order.attendant.mobile || '暂无电话'}}</text>
<text class="call-icon" wx:if="{{order.attendant.mobile}}"> 拨打</text>
</view>
</view>
</view>
</view>
</view>
<!-- 费用信息 -->
<view class="info-section">
<text class="section-title">费用信息</text>
<view class="info-card">
<view class="info-row">
<text class="info-label">服务费用</text>
<text class="info-value fee-value">¥{{order.payment.totalFee || 0}}</text>
</view>
<view class="info-row" wx:if="{{order.payment.paidFee}}">
<text class="info-label">已支付</text>
<text class="info-value">¥{{order.payment.paidFee}}</text>
</view>
<view class="info-row">
<text class="info-label">支付状态</text>
<text class="info-value">{{paymentStatusText}}</text>
</view>
</view>
</view>
<!-- 备注信息 -->
<view class="info-section" wx:if="{{order.notes.patientNote || order.notes.escortNote || order.notes.medicalSummary}}">
<text class="section-title">备注信息</text>
<view class="info-card">
<view class="note-block" wx:if="{{order.notes.patientNote}}">
<text class="note-label">患者备注</text>
<text class="note-content">{{order.notes.patientNote}}</text>
</view>
<view class="note-block" wx:if="{{order.notes.escortNote}}">
<text class="note-label">陪诊记录</text>
<text class="note-content">{{order.notes.escortNote}}</text>
</view>
<view class="note-block" wx:if="{{order.notes.medicalSummary}}">
<text class="note-label">就诊摘要</text>
<text class="note-content">{{order.notes.medicalSummary}}</text>
</view>
</view>
</view>
<!-- 订单信息 -->
<view class="info-section">
<text class="section-title">订单信息</text>
<view class="info-card">
<view class="info-row">
<text class="info-label">订单编号</text>
<text class="info-value">{{order._id}}</text>
</view>
<view class="info-row" wx:if="{{createtimeText}}">
<text class="info-label">创建时间</text>
<text class="info-value">{{createtimeText}}</text>
</view>
<view class="info-row" wx:if="{{updatetimeText}}">
<text class="info-label">更新时间</text>
<text class="info-value">{{updatetimeText}}</text>
</view>
</view>
</view>
<!-- 底部操作 -->
<view class="bottom-actions" wx:if="{{showConfirmBtn || showCancelBtn || showStartBtn || showCompleteBtn}}">
<view class="action-btn btn-ghost" wx:if="{{showCancelBtn}}" bindtap="onCancel">取消订单</view>
<view class="action-btn btn-solid" wx:if="{{showConfirmBtn}}" bindtap="onConfirm">确认订单</view>
<view class="action-btn btn-solid" wx:if="{{showStartBtn}}" bindtap="onStart">开始服务</view>
<view class="action-btn btn-solid" wx:if="{{showCompleteBtn}}" bindtap="onComplete">完成服务</view>
</view>
</block>
</view>

View File

@@ -0,0 +1,309 @@
/* pages/order/orderDetail.wxss */
page {
background-color: #f7f8fc;
}
.detail-page {
min-height: 100vh;
background: #f7f8fc;
padding-bottom: 120rpx;
}
.loading-box {
display: flex;
align-items: center;
justify-content: center;
padding: 200rpx 0;
}
.loading-text {
font-size: 28rpx;
color: #a0a3bd;
}
/* === 顶部状态栏 === */
.status-header {
padding: 60rpx 40rpx 80rpx;
position: relative;
overflow: hidden;
}
.status-header::after {
content: '';
position: absolute;
top: -60rpx;
right: -40rpx;
width: 240rpx;
height: 240rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.03);
}
.status-header.status-pending {
background: linear-gradient(135deg, #e6a23c 0%, #f5b041 100%);
}
.status-header.status-confirmed {
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
}
.status-header.status-in_progress {
background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
}
.status-header.status-completed {
background: linear-gradient(135deg, #7c5cfc 0%, #9b7dff 100%);
}
.status-header.status-cancelled {
background: linear-gradient(135deg, #b0b0b0 0%, #c0c0c0 100%);
}
.status-content {
position: relative;
z-index: 1;
}
.status-text {
display: block;
font-size: 44rpx;
font-weight: 700;
color: #fff;
letter-spacing: 2rpx;
margin-bottom: 12rpx;
}
.status-desc {
display: block;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.7);
font-weight: 300;
}
/* === 信息区块 === */
.info-section {
margin: 24rpx 24rpx 0;
}
.section-title {
font-size: 30rpx;
font-weight: 700;
color: #1a1a2e;
margin-bottom: 16rpx;
letter-spacing: 1rpx;
}
.info-card {
background: #ffffff;
border-radius: 20rpx;
padding: 28rpx;
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.04);
}
.info-row {
display: flex;
align-items: baseline;
margin-bottom: 16rpx;
}
.info-row:last-child {
margin-bottom: 0;
}
.info-label {
font-size: 24rpx;
color: #a0a3bd;
width: 140rpx;
flex-shrink: 0;
}
.info-value {
font-size: 26rpx;
color: #3a3d5c;
flex: 1;
}
/* === 患者信息 === */
.patient-header {
display: flex;
align-items: center;
gap: 20rpx;
margin-bottom: 16rpx;
}
.patient-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.avatar-text {
font-size: 32rpx;
font-weight: 700;
color: #fff;
}
.patient-info {
flex: 1;
}
.patient-name-row {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 6rpx;
}
.patient-name {
font-size: 32rpx;
font-weight: 600;
color: #1a1a2e;
}
.patient-sex {
font-size: 22rpx;
padding: 4rpx 12rpx;
border-radius: 10rpx;
font-weight: 500;
}
.patient-sex.male {
background: rgba(102, 126, 234, 0.1);
color: #667eea;
}
.patient-sex.female {
background: rgba(234, 102, 150, 0.1);
color: #ea6696;
}
.patient-age {
font-size: 24rpx;
color: #a0a3bd;
}
.patient-phone {
font-size: 24rpx;
color: #a0a3bd;
}
.call-icon {
color: #667eea;
font-weight: 500;
}
.divider {
height: 1rpx;
background: #f0f1f5;
margin: 16rpx 0;
}
/* === 陪诊员信息 === */
.attendant-header {
display: flex;
align-items: center;
gap: 20rpx;
}
.attendant-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.attendant-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 6rpx;
}
.attendant-name {
font-size: 30rpx;
font-weight: 600;
color: #1a1a2e;
}
.attendant-phone {
font-size: 24rpx;
color: #a0a3bd;
}
/* === 费用信息 === */
.fee-value {
font-size: 32rpx;
font-weight: 700;
color: #1a1a2e;
font-family: 'DIN Alternate', 'Helvetica Neue', sans-serif;
}
/* === 备注信息 === */
.note-block {
margin-bottom: 20rpx;
}
.note-block:last-child {
margin-bottom: 0;
}
.note-label {
display: block;
font-size: 24rpx;
color: #a0a3bd;
margin-bottom: 8rpx;
font-weight: 500;
}
.note-content {
display: block;
font-size: 26rpx;
color: #3a3d5c;
line-height: 1.6;
}
/* === 底部操作 === */
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #ffffff;
padding: 24rpx 32rpx;
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.06);
display: flex;
gap: 20rpx;
z-index: 100;
}
.action-btn {
flex: 1;
padding: 24rpx 0;
border-radius: 28rpx;
font-size: 28rpx;
font-weight: 600;
text-align: center;
}
.btn-solid {
background: linear-gradient(135deg, #667eea, #764ba2);
color: #fff;
box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.3);
}
.btn-ghost {
background: #f7f8fc;
color: #a0a3bd;
border: 1rpx solid #f0f1f5;
}

View File

@@ -1,6 +1,6 @@
{ {
"libVersion": "3.16.1", "libVersion": "3.16.1",
"projectname": "wxapp_admin", "projectname": "wxapp_escort_admin",
"condition": {}, "condition": {},
"setting": { "setting": {
"urlCheck": false, "urlCheck": false,

View File

@@ -1,7 +1,7 @@
class Request { class Request {
constructor(baseURL = 'https://api.huashengtec.com') { constructor(baseURL = 'https://api.huashengtec.com') {
//constructor(baseURL = 'http://127.0.0.1:9004') { //constructor(baseURL = 'http://127.0.0.1:9010') {
this.baseURL = baseURL this.baseURL = baseURL
} }
@@ -13,7 +13,6 @@ class Request {
const token = app?.globalData?.user?.security?.token || '' const token = app?.globalData?.user?.security?.token || ''
data.appId = 'wxapp-escort-admin' data.appId = 'wxapp-escort-admin'
data.token = token
wx.request({ wx.request({
url: url.startsWith('http') ? url : `${this.baseURL}${url}`, url: url.startsWith('http') ? url : `${this.baseURL}${url}`,