feat: 新增多角色系统(派单/分润/推广/区域)

- 后端:RlzDispatch/Profit/Promotion/Region 控制器、服务、Mapper、领域模型
- 权限:MethodSecurityConfig + PermissionInterceptor
- 管理后台:派单/分润/推广/区域 页面与 API
- Android 陪护端:派单/运营/退款 Fragment 及布局
- 小程序:推广员子包、派单/运营/退款/检索子包、自定义 tabBar
- 文档:多角色系统方案、角色权限矩阵、用户操作手册等

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
renjianbo
2026-10-12 00:09:45 +08:00
parent 7562a5f20c
commit 805ed0298b
170 changed files with 8876 additions and 705 deletions

View File

@@ -1,4 +1,4 @@
// 服务图标名称 -> 本地 PNG 文件名的映射(以防 DB icon 字段为空或名称不匹配)
// 服务图标名称 -> 本地 PNG 文件名的映射
var iconNameMap = {
'全面陪诊': '全程陪诊',
'提前约号': '诊前约号',
@@ -23,64 +23,205 @@ var app = getApp();
const { request } = require('../../utils/request')
Page({
data: {
// Patient mode
hospitalData: [],
bannerdata: [
"home-banner",
"home-banner",
"home-banner"
],
bannerdata: ["home-banner", "home-banner", "home-banner"],
itemView: [],
firstLoad: true
firstLoad: true,
// Caregiver mode
userType: '',
cgOrders: [],
cgPageNum: 1,
cgHasMore: true,
cgLoading: false,
// Promoter mode
proStats: { inviteCount: 0, teamCount: 0, totalCommission: '0', settledCommission: '0', pendingCommission: '0', orderCount: 0, promotionCode: '' },
proLoading: false,
// Work mode (dispatcher/CS/ops)
workOrders: [],
workLoading: false
},
/**
* 诊前约号、代办买药、取送结果、出入院办理、就医陪诊、园内护理
*/
itemClick(options) {
onLoad: function(options) {
// Check for promotion code from share link
if (options && options.promotionCode) {
this.bindPromotion(options.promotionCode);
}
},
if (wx.getStorageSync('phone') == '') {
wx.setStorageSync('uidFlag', false);
console.log('请登录')
this.isdenglu()
onShow() {
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({ selected: 0 });
}
var userType = app.globalData.userType || 'C';
var roleChanged = this.data.userType !== userType;
this.setData({ userType: userType });
if (this.data.firstLoad || roleChanged) {
this.setData({ firstLoad: false });
this.loadRoleContent();
}
},
onPullDownRefresh() {
this.loadRoleContent().finally(function() { wx.stopPullDownRefresh(); });
},
onReachBottom() {
if (this.data.userType === 'B' && this.data.cgHasMore && !this.data.cgLoading) {
this.loadCgOrders();
}
},
// Load content based on role
loadRoleContent() {
var ut = this.data.userType;
if (ut === 'B') {
this.loadCgOrders();
} else if (ut === '06') {
this.loadPromoterStats();
} else if (ut === '03' || ut === '04' || ut === '05') {
this.loadWorkPending();
} else {
let item = JSON.stringify(options.currentTarget.dataset.item);
wx.navigateTo({
// url: "/pages/peizhen/peizhendetail?servername=" + options.currentTarget.dataset.id,
url: "/pages/peizhen/peizhendetail?item=" + item,
this.getServiceTypes();
this.getHospitalList();
}
},
// === Promoter: Load dashboard stats ===
async loadPromoterStats() {
this.setData({ proLoading: true });
try {
var res = await request({ url: '/system/promotion/myStats', method: 'GET', loading: false });
if (res.code === 200 && res.data) {
this.setData({ proStats: res.data });
}
} catch (e) {}
this.setData({ proLoading: false });
},
goProTeam() { wx.navigateTo({ url: '/subPackages/pages-promoter/team/team' }); },
goProCommission() { wx.navigateTo({ url: '/subPackages/pages-promoter/commission/commission' }); },
goProShare() { wx.navigateTo({ url: '/subPackages/pages-promoter/share/share' }); },
// === Work mode: Load pending tasks (03/04/05) ===
async loadWorkPending() {
this.setData({ workLoading: true });
try {
// Load status=0 (pending) orders for dispatchers, status=5 (refund) for CS
var status = this.data.userType === '04' ? '5' : '0';
var res = await request({
url: '/system/view/list',
method: 'GET',
data: { pageNum: 1, pageSize: 10, status: status },
loading: false
});
}
if (res.code === 200) {
this.setData({ workOrders: (res.rows || res.data || []) });
}
} catch (e) {}
this.setData({ workLoading: false });
},
goService() {
wx.switchTab({ url: '/pages/service/service' })
goWorkDispatch() { wx.navigateTo({ url: '/subPackages/pages-work/dispatch/dispatch' }); },
goWorkRefund() { wx.navigateTo({ url: '/subPackages/pages-work/refund/refund' }); },
goWorkSearch() { wx.navigateTo({ url: '/subPackages/pages-work/search/search' }); },
goWorkOps() { wx.navigateTo({ url: '/subPackages/pages-work/ops/ops' }); },
// === Bind promotion code from share link ===
bindPromotion(code) {
// Store promotion code for use during registration
wx.setStorageSync('promotionCode', code);
},
go_peizhen() {
if (wx.getStorageSync('phone') == '') {
wx.setStorageSync('uidFlag', false);
console.log('请登录')
this.isdenglu()
} else {
wx.navigateTo({
url: '/pages/peizhen/peizhen',
})
}
// === Caregiver: Load pending orders (status=0) ===
async loadCgOrders() {
if (this.data.cgLoading) return;
this.setData({ cgLoading: true });
try {
var res = await request({
url: '/system/view/list',
method: 'GET',
data: { pageNum: this.data.cgPageNum, pageSize: 20, status: '0' },
loading: false
});
if (res.code === 200) {
var list = res.rows || res.data || [];
if (this.data.cgPageNum === 1) {
this.setData({ cgOrders: list, cgHasMore: list.length >= 20, cgPageNum: 2 });
} else {
this.setData({
cgOrders: this.data.cgOrders.concat(list),
cgHasMore: list.length >= 20,
cgPageNum: this.data.cgPageNum + 1
});
}
}
} catch (e) {}
this.setData({ cgLoading: false });
},
go_peihu() {
if (wx.getStorageSync('phone') == '') {
wx.setStorageSync('uidFlag', false);
console.log('请登录')
this.isdenglu()
} else {
wx.navigateTo({
url: '/pages/peihu/peihu?' + "hospitalId=" + "",
})
}
// === Caregiver: Refuse order ===
refuseOrder(e) {
var item = e.currentTarget.dataset.item;
var that = this;
wx.showModal({
title: '确认拒单',
content: '确定拒绝订单 ' + (item.yuliu1 || '#' + item.orderId) + ' ?',
success: function(res) {
if (res.confirm) that.doRefuse(item);
}
});
},
//获取服务类型列表(从后台动态加载,最多显示8个热门推荐)
async doRefuse(item) {
try {
var res = await request({
url: '/system/view/refuseOrder',
method: 'POST',
data: { orderId: item.orderId },
loading: true,
loadingText: '处理中...'
});
if (res.code === 200) {
wx.showToast({ title: '已拒绝', icon: 'success' });
var orders = this.data.cgOrders.filter(function(o) { return o.orderId !== item.orderId; });
this.setData({ cgOrders: orders });
}
} catch (e) {}
},
// === Caregiver: Accept order ===
acceptOrder(e) {
var item = e.currentTarget.dataset.item;
var that = this;
wx.showModal({
title: '确认接单',
content: '确认接受订单 ' + (item.yuliu1 || '#' + item.orderId) + ' ?',
success: function(res) {
if (res.confirm) that.doAccept(item);
}
});
},
async doAccept(item) {
try {
var res = await request({
url: '/system/view/acceptOrderYes',
method: 'POST',
data: { orderId: item.orderId },
loading: true,
loadingText: '接单中...'
});
if (res.code === 200) {
wx.showToast({ title: '接单成功', icon: 'success' });
var orders = this.data.cgOrders.filter(function(o) { return o.orderId !== item.orderId; });
this.setData({ cgOrders: orders });
}
} catch (e) {}
},
// === Patient: service type list ===
getServiceTypes: function () {
var that = this;
request({
@@ -88,7 +229,7 @@ Page({
method: 'GET',
data: { category: '2' },
loading: false
}).then(res => {
}).then(function(res) {
var services = res.data || [];
if (services.length) {
var mapped = services.slice(0, 8).map(function (s) {
@@ -99,22 +240,22 @@ Page({
describe: s.description || '',
ordertype: s.typeCode
}
})
that.setData({ itemView: mapped })
});
that.setData({ itemView: mapped });
}
}).catch(function() {
wx.showToast({ title: '加载服务失败', icon: 'none' })
})
wx.showToast({ title: '加载服务失败', icon: 'none' });
});
},
//获取医院列表
// === Patient: hospital list ===
getHospitalList: function () {
var that = this;
request({
url: '/system/hospital/list',
method: 'GET',
loading: false
}).then(res => {
}).then(function(res) {
var hospitals = res.rows || res.data || [];
if (hospitals.length) {
var mapped = hospitals.map(function (h) {
@@ -127,91 +268,67 @@ Page({
skiled: h.hospitalDesc || '',
address: h.address || '',
img: imgUrl
}
})
that.setData({ hospitalData: mapped })
};
});
that.setData({ hospitalData: mapped });
}
}).catch(function() {
wx.showToast({ title: '加载医院失败', icon: 'none' })
})
wx.showToast({ title: '加载医院失败', icon: 'none' });
});
},
/**
* 医院列表
*/
listItemTap(options) {
// console.log(options.currentTarget.dataset.id),
// === Shared: item click handlers ===
itemClick(options) {
if (wx.getStorageSync('phone') == '') {
wx.setStorageSync('uidFlag', false);
console.log('请登录')
this.isdenglu()
this.isdenglu();
} else {
wx.navigateTo({
url: '/pages/peihu/peihu?' + "hospitalId=" + options.currentTarget.dataset.id,
})
var item = JSON.stringify(options.currentTarget.dataset.item);
wx.navigateTo({ url: "/pages/peizhen/peizhendetail?item=" + item });
}
},
goService() {
wx.switchTab({ url: '/pages/service/service' });
},
go_peizhen() {
if (wx.getStorageSync('phone') == '') {
wx.setStorageSync('uidFlag', false);
this.isdenglu();
} else {
wx.navigateTo({ url: '/pages/peizhen/peizhen' });
}
},
go_peihu() {
if (wx.getStorageSync('phone') == '') {
wx.setStorageSync('uidFlag', false);
this.isdenglu();
} else {
wx.navigateTo({ url: '/pages/peihu/peihu?hospitalId=' });
}
},
listItemTap(options) {
if (wx.getStorageSync('phone') == '') {
wx.setStorageSync('uidFlag', false);
this.isdenglu();
} else {
wx.navigateTo({ url: '/pages/peihu/peihu?hospitalId=' + options.currentTarget.dataset.id });
}
},
//是否登录
isdenglu() {
wx.showModal({
title: '提示',
content: '请先登录',
success(res) {
if (res.confirm) {
console.log('用户点击确定')
wx.switchTab({
url: '/pages/my/my'
})
} else if (res.cancel) {
console.log('用户点击取消')
}
success: function(res) {
if (res.confirm) wx.switchTab({ url: '/pages/my/my' });
}
})
});
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
if (this.data.firstLoad) {
this.setData({ firstLoad: false })
this.getServiceTypes()
this.getHospitalList()
}
},
onPullDownRefresh() {
this.getServiceTypes()
this.getHospitalList()
wx.stopPullDownRefresh()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
onReady: function() {},
onShareAppMessage: function() {}
});

View File

@@ -1,4 +1,105 @@
<view class="content">
<!-- ===== Promoter View (06) ===== -->
<view wx:if="{{userType === '06'}}" class="container">
<view class="top-banner">
<view class="banner-title">推广数据看板</view>
<view class="banner-code">邀请码:{{proStats.promotionCode || '暂无'}}</view>
</view>
<view class="stats-grid">
<view class="stat-card">
<view class="stat-num">{{proStats.inviteCount || 0}}</view>
<view class="stat-label">直接邀请</view>
</view>
<view class="stat-card">
<view class="stat-num">{{proStats.teamCount || 0}}</view>
<view class="stat-label">团队总人数</view>
</view>
<view class="stat-card" bindtap="goProCommission">
<view class="stat-num gold">¥{{proStats.totalCommission || '0'}}</view>
<view class="stat-label">佣金总额</view>
</view>
<view class="stat-card">
<view class="stat-num">{{proStats.orderCount || 0}}</view>
<view class="stat-label">推广订单</view>
</view>
</view>
<view class="action-grid">
<view class="action-item" bindtap="goProTeam">
<text>👥 我的团队</text>
</view>
<view class="action-item" bindtap="goProCommission">
<text>💰 佣金明细</text>
</view>
<view class="action-item" bindtap="goProShare">
<text>📤 分享推广</text>
</view>
</view>
<view wx:if="{{proLoading}}" class="loading">加载中...</view>
</view>
<!-- ===== Work View (03=运营 04=客服 05=调度) ===== -->
<view wx:if="{{userType === '03' || userType === '04' || userType === '05'}}" class="container">
<view class="cg-header">
<text class="cg-header-title">{{userType === '05' ? '待派单' : userType === '04' ? '退款申请' : '待处理'}}</text>
</view>
<block wx:for="{{workOrders}}" wx:key="orderId">
<view class="cg-card">
<view class="cg-row">
<text class="cg-order-no">{{item.yuliu1 || '订单#' + item.orderId}}</text>
<text class="cg-amount">¥{{item.yuguMoney || item.orderMoney}}</text>
</view>
<view class="cg-row sub">
<text class="cg-meta">{{item.createTime}}</text>
<text class="cg-status">{{item.status === '0' ? '待接单' : item.status === '5' ? '退款中' : ''}}</text>
</view>
</view>
</block>
<view wx:if="{{!workLoading && workOrders.length === 0}}" class="empty">暂无待处理项</view>
<view wx:if="{{workLoading}}" class="loading">加载中...</view>
<view class="action-grid">
<view wx:if="{{userType === '05'}}" class="action-item" bindtap="goWorkDispatch">
<text>📋 全部派单</text>
</view>
<view wx:if="{{userType === '04'}}" class="action-item" bindtap="goWorkRefund">
<text>📋 退款审核</text>
</view>
<view wx:if="{{userType === '03'}}" class="action-item" bindtap="goWorkOps">
<text>📊 运营看板</text>
</view>
<view class="action-item" bindtap="goWorkSearch">
<text>🔍 订单搜索</text>
</view>
</view>
</view>
<!-- ===== Caregiver View (B role) ===== -->
<view wx:if="{{userType === 'B'}}" class="cg-container">
<view class="cg-header">
<text class="cg-header-title">待接单</text>
<text class="cg-header-sub">可接的陪诊/陪护订单</text>
</view>
<block wx:for="{{cgOrders}}" wx:key="orderId">
<view class="cg-card">
<view class="cg-row">
<text class="cg-order-no">{{item.yuliu1 || '订单#' + item.orderId}}</text>
<text class="cg-amount">¥{{item.yuguMoney || item.orderMoney}}</text>
</view>
<view class="cg-row sub">
<text class="cg-meta">{{item.hospitalName || ''}} | {{item.serviceName || item.yuliu2 || ''}}</text>
</view>
<view class="cg-row sub">
<text class="cg-time">{{item.createTime}}</text>
<view class="cg-accept-btn" catchtap="acceptOrder" data-item="{{item}}">接单</view>
<view class="cg-refuse-btn" catchtap="refuseOrder" data-item="{{item}}">拒单</view>
</view>
</view>
</block>
<view wx:if="{{!cgLoading && cgOrders.length === 0}}" class="empty">暂无待接订单</view>
<view wx:if="{{cgLoading}}" class="loading">加载中...</view>
<view wx:if="{{!cgHasMore && cgOrders.length > 0}}" class="end">— 已加载全部 —</view>
</view>
<!-- ===== Patient View (C, 00, default) ===== -->
<view wx:if="{{userType !== 'B' && userType !== '06' && userType !== '03' && userType !== '04' && userType !== '05'}}" class="content">
<view class="head-view">
<image src="../image/home/home-head.png" mode="aspectFill"></image>
</view>
@@ -20,7 +121,7 @@
<block wx:for="{{itemView}}" wx:key="id">
<view class="item-list" bindtap="itemClick" data-id="{{item.title}}" data-item="{{item}}">
<view class="item-image">
<image src="{{item.icon.indexOf('http') === 0 ? item.icon : '../image/home/' + item.icon + '.png'}}" mode="aspectFit"></image>
<image src="{{item.icon && item.icon.indexOf('http') === 0 ? item.icon : (item.icon ? '../image/home/' + item.icon + '.png' : '/pages/image/empty.png')}}" mode="aspectFit"></image>
</view>
<view class="item-title">
<text>{{item.title}}</text>
@@ -70,4 +171,4 @@
</view>
</block>
</view>
</view>
</view>

View File

@@ -226,4 +226,42 @@
.section-more{
font-size: 24rpx;
color: #999;
}
}
/* === Caregiver style === */
.cg-container { min-height: 100vh; background: #F5F5F5; padding-bottom: 40rpx; }
.cg-header { background: #fff; padding: 32rpx 40rpx; margin-bottom: 16rpx; }
.cg-header-title { font-size: 36rpx; font-weight: bold; color: #333; display: block; }
.cg-header-sub { font-size: 24rpx; color: #999; margin-top: 8rpx; }
.cg-card { background: #fff; margin: 12rpx 0 0 0; padding: 24rpx 32rpx; }
.cg-row { display: flex; justify-content: space-between; align-items: center; }
.cg-row.sub { margin-top: 8rpx; }
.cg-order-no { font-size: 28rpx; font-weight: 600; color: #333; }
.cg-amount { font-size: 30rpx; font-weight: 700; color: #E6A23C; }
.cg-meta { font-size: 24rpx; color: #999; }
.cg-time { font-size: 22rpx; color: #C0C4CC; }
.cg-accept-btn { background: #1890FF; color: #fff; font-size: 24rpx; padding: 8rpx 28rpx; border-radius: 24rpx; }
.cg-refuse-btn { background: #fff; color: #999; font-size: 24rpx; padding: 8rpx 20rpx; border-radius: 24rpx; border: 1rpx solid #ddd; margin-right: 12rpx; }
.cg-btn-group { display: flex; align-items: center; }
.loading { text-align: center; padding: 40rpx; color: #999; }
.empty { text-align: center; padding: 120rpx 0; color: #999; font-size: 28rpx; }
.end { text-align: center; padding: 32rpx; color: #C0C4CC; font-size: 24rpx; }
/* === Multi-role shared styles === */
.container { padding: 0 0 40rpx 0; background: #F5F5F5; min-height: 100vh; }
.top-banner { background: linear-gradient(135deg, #FF6A6A, #FF8F1F); color: #fff; padding: 48rpx 32rpx 40rpx; }
.banner-title { font-size: 36rpx; font-weight: 800; }
.banner-code { font-size: 24rpx; margin-top: 8rpx; opacity: 0.85; }
.stats-grid { display: flex; flex-wrap: wrap; margin: -20rpx 24rpx 0; }
.stat-card { width: 44%; margin: 8rpx 3%; background: #fff; border-radius: 16rpx; padding: 28rpx 24rpx; text-align: center; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
.stat-num { font-size: 40rpx; font-weight: 800; color: #333; }
.stat-num.gold { color: #FF8F1F; }
.stat-num.red { color: #F56C6C; }
.stat-label { font-size: 22rpx; color: #999; margin-top: 8rpx; }
.action-grid { display: flex; margin: 24rpx 32rpx; }
.action-item { flex: 1; background: #fff; border-radius: 16rpx; padding: 32rpx 0; text-align: center; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); font-size: 26rpx; color: #333; }
.action-item + .action-item { margin-left: 16rpx; }
.cg-status { font-size: 22rpx; padding: 4rpx 16rpx; border-radius: 16rpx; background: #409EFF; color: #fff; }

View File

@@ -19,7 +19,7 @@
<view class="order-list" style="margin-top: 160rpx;" wx:if="{{lists.length}}">
<view wx:for="{{lists}}" wx:key="{{index}}" wx:for-item="item">
<view wx:for="{{lists}}" wx:key="index" wx:for-item="item">
<view class="recommend" bindtap="mechanism" data-id="{{item.id}}">
<view class="red-image">
<image src="{{item.wechat_logo}}"></image>

View File

@@ -11,7 +11,11 @@ Page({
userInfo: null,
balance: '0.00',
isAuth: false,
authName: ''
authName: '',
userType: 'C',
roleLabel: '患者',
// 首次登录身份选择
showIdentityPicker: false
},
onLoad: function () {
@@ -19,6 +23,10 @@ Page({
},
onShow: function () {
// 更新自定义 TabBar 选中态并刷新 tabs(角色可能已切换)
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({ selected: 3 });
}
if (!this.data.uidFlag) {
this.getLogin()
} else {
@@ -53,7 +61,23 @@ Page({
isAuth: d.attestation === '1',
authName: d.name || ''
});
// 同步头像/昵称到缓存
// 同步角色信息:仅首次登录或后端角色与本地一致时同步
// 若用户通过"切换"手动选择了角色,则保留用户选择不被后端覆盖
var backendType = d.userType || 'C';
var localType = wx.getStorageSync('userType');
var switchable = app.globalData.ROLE_SWITCHABLE || ['C', '06', 'B'];
// 本地有手动切换且后端角色不同 → 保留本地
if (localType && localType !== backendType && switchable.indexOf(localType) >= 0) {
var ut = localType;
} else {
var ut = backendType;
app.globalData.userType = ut;
wx.setStorageSync('userType', ut);
}
this.setData({
userType: ut,
roleLabel: app.globalData.ROLE_LABELS[ut] || '患者'
});
if (d.nickName) wx.setStorageSync('nickName', d.nickName);
}
} catch (e) {}
@@ -91,36 +115,62 @@ Page({
wx.showToast({ title: '登录成功', icon: 'success' })
// 同步登录信息
this.syncLogin()
// 拉取用户信息
this.loadUserInfo()
// 返回上一页,若无法返回则到首页
var pages = getCurrentPages()
if (pages.length > 1) {
wx.navigateBack()
// 首次登录 → 弹出身份选择;已有身份 → 直接加载
var existingType = wx.getStorageSync('userType');
if (existingType) {
this.loadUserInfo();
this._navigateAfterLogin();
} else {
wx.switchTab({ url: '/pages/index/index' })
// 延迟弹出,等 toast 显示后
var that = this;
setTimeout(function() { that.setData({ showIdentityPicker: true }); }, 800);
}
} catch (e) {
this.setData({ logging: false })
}
},
// 同步登录信息
syncLogin() {
request({
url: '/member/logintwo',
method: 'POST',
loading: false,
showError: false,
data: {
uid: wx.getStorageSync('uid'),
phone: wx.getStorageSync('phone'),
token: wx.getStorageSync('token')
}
})
_navigateAfterLogin() {
var pages = getCurrentPages();
if (pages.length > 1) {
wx.navigateBack();
} else {
wx.switchTab({ url: '/pages/index/index' });
}
},
// 身份选择:点击选项
selectIdentity(e) {
var role = e.currentTarget.dataset.role;
if (!role) return;
app.globalData.userType = role;
wx.setStorageSync('userType', role);
this.setData({
userType: role,
roleLabel: app.globalData.ROLE_LABELS[role] || role,
showIdentityPicker: false
});
// 尝试同步到后端
this._syncRoleToBackend(role);
// 刷新 TabBar 和用户信息
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().updateTabs();
}
this.loadUserInfo();
var that = this;
setTimeout(function() { that._navigateAfterLogin(); }, 300);
},
async _syncRoleToBackend(role) {
try {
await request({
url: '/system/user/updateUserType',
method: 'PUT',
data: { userType: role },
loading: false,
showError: false
});
} catch (e) {}
},
// 我的钱包
@@ -134,8 +184,50 @@ Page({
},
// 联系客服
callService() {
wx.makePhoneCall({ phoneNumber: '4001234567' })
async callService() {
try {
var res = await request({
url: '/system/config/configKey/platform.servicePhone',
method: 'GET',
loading: false,
showError: false
});
var phone = (res.code === 200 && res.data) ? res.data : '400-123-4567';
wx.makePhoneCall({ phoneNumber: phone });
} catch (e) {
wx.makePhoneCall({ phoneNumber: '400-123-4567' });
}
},
// 角色切换(自助切换:患者/陪诊师/推广员)
showRoleSwitch() {
var that = this;
var currentRole = app.globalData.userType || 'C';
var switchableList = app.globalData.ROLE_SWITCHABLE || ['C', '06', 'B'];
var items = switchableList.map(function(r) {
return (r === currentRole ? '✓ ' : '') + (app.globalData.ROLE_LABELS[r] || r);
});
wx.showActionSheet({
itemList: items,
success: function(res) {
var newRole = switchableList[res.tapIndex];
if (newRole && newRole !== currentRole) {
app.globalData.userType = newRole;
wx.setStorageSync('userType', newRole);
that.setData({
userType: newRole,
roleLabel: app.globalData.ROLE_LABELS[newRole] || newRole
});
// 刷新 TabBar
if (typeof that.getTabBar === 'function' && that.getTabBar()) {
that.getTabBar().updateTabs();
}
wx.showToast({ title: '已切换为' + (app.globalData.ROLE_LABELS[newRole] || newRole), icon: 'none' });
// 跳回首页刷新
setTimeout(function() { wx.switchTab({ url: '/pages/index/index' }); }, 500);
}
}
});
},
// 关于

View File

@@ -1,3 +1,28 @@
<!-- 首次登录身份选择弹窗 -->
<view wx:if="{{showIdentityPicker}}" class="identity-mask">
<view class="identity-dialog">
<view class="identity-title">选择您的身份</view>
<view class="identity-sub">首次注册,请选择您需要的服务身份</view>
<view class="identity-options">
<view class="identity-option" data-role="C" bindtap="selectIdentity">
<view class="io-icon">🏥</view>
<view class="io-name">我需要陪诊服务</view>
<view class="io-desc">浏览医院、下单预约陪诊</view>
</view>
<view class="identity-option" data-role="B" bindtap="selectIdentity">
<view class="io-icon">💼</view>
<view class="io-name">我提供陪诊服务</view>
<view class="io-desc">接单赚钱,需实名认证</view>
</view>
<view class="identity-option" data-role="06" bindtap="selectIdentity">
<view class="io-icon">📣</view>
<view class="io-name">我推广赚佣金</view>
<view class="io-desc">邀请好友下单,赚推广佣金</view>
</view>
</view>
</view>
</view>
<van-nav-bar
title="个人中心"
left-text=""
@@ -28,6 +53,13 @@
</view>
</view>
<!-- 身份标识 -->
<view class="role-tag-row">
<text class="role-label">当前身份:</text>
<text class="role-value">{{roleLabel}}</text>
<text class="role-switch-btn" bindtap="showRoleSwitch">切换 ></text>
</view>
<!-- 余额卡片 -->
<view class="balance-card" bindtap="goWallet">
<view class="balance-label">账户余额(元)</view>

View File

@@ -62,6 +62,38 @@
color: #FF9800;
}
/* 角色标识 */
.role-tag-row {
display: flex;
align-items: center;
margin: 0 32rpx 0 32rpx;
padding: 16rpx 24rpx;
background: #F0F7FF;
border-radius: 12rpx;
border: 1rpx solid #D6E9FF;
}
.role-label {
font-size: 24rpx;
color: #666;
}
.role-value {
font-size: 26rpx;
font-weight: 600;
color: #1890FF;
margin-left: 8rpx;
}
.role-switch-btn {
margin-left: auto;
font-size: 22rpx;
color: #1890FF;
padding: 4rpx 12rpx;
border: 1rpx solid #1890FF;
border-radius: 8rpx;
}
/* 余额卡片 */
.balance-card {
margin: 24rpx 32rpx;
@@ -141,3 +173,78 @@
.login-btn::after {
border: none;
}
/* 首次登录身份选择弹窗 */
.identity-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.identity-dialog {
width: 620rpx;
background: #fff;
border-radius: 24rpx;
padding: 48rpx 40rpx 40rpx;
box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.15);
}
.identity-title {
font-size: 36rpx;
font-weight: 700;
color: #333;
text-align: center;
margin-bottom: 12rpx;
}
.identity-sub {
font-size: 24rpx;
color: #999;
text-align: center;
margin-bottom: 36rpx;
}
.identity-options {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.identity-option {
display: flex;
flex-direction: column;
align-items: center;
padding: 32rpx 24rpx;
border: 2rpx solid #E8E8E8;
border-radius: 16rpx;
transition: all 0.2s;
}
.identity-option:active {
border-color: #1890FF;
background: #F0F7FF;
}
.io-icon {
font-size: 48rpx;
margin-bottom: 12rpx;
}
.io-name {
font-size: 30rpx;
font-weight: 600;
color: #333;
margin-bottom: 8rpx;
}
.io-desc {
font-size: 22rpx;
color: #999;
}

View File

@@ -6,6 +6,7 @@ Page({
* 页面的初始数据
*/
data: {
height: '',
dingdan_msg:false,
order_id:0,
goods_id:'',
@@ -54,6 +55,7 @@ Page({
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.setData(getApp().getNavBarHeight());
console.log(options.type)
console.log(options.id)
if(options.type==2){

View File

@@ -3,5 +3,6 @@
"van-nav-bar":"/miniprogram/miniprogram_npm/@vant/weapp/nav-bar/index",
"van-uploader": "/miniprogram/miniprogram_npm/@vant/weapp/uploader/index"
},
"navigationBarTitleText": "订单详情"
"navigationBarTitleText": "订单详情",
"navigationStyle": "custom"
}

View File

@@ -1,4 +1,12 @@
<van-nav-bar
title="订单详情"
left-text=""
left-arrow
bind:click-left="onClickLeft"
style="position:fixed;left:0;top:0;width:100%;z-index:2;"
/>
<view style="margin-top:{{height}}px;">
<view style=" height:340rpx;position: relative;background: #ffffff;margin-top:8rpx;">
<view style="height:66rpx;padding: 0 24rpx;">
<text class="time_msg"></text>
@@ -60,8 +68,5 @@
</view>
</view>
</view>

View File

@@ -6,6 +6,7 @@ Page({
* 页面的初始数据
*/
data: {
height: '',
resp:{
"erro": 0,
"msg": "查询成功",
@@ -52,44 +53,21 @@ Page({
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.setData(getApp().getNavBarHeight());
this.setData({
type:options.type
})
if(options.type==1){
wx.setNavigationBarTitle({
title: '我的关注'
})
wx.setNavigationBarTitle({ title: '我的关注' })
this.getCollection();
}
if(options.type==2){
wx.setNavigationBarTitle({
title: '我的拼团'
})
wx.setNavigationBarTitle({ title: '我的拼团' })
this.getCollage()
}
if(options.type==3){
wx.setNavigationBarTitle({
title: '我的砍价'
})
wx.setNavigationBarTitle({ title: '我的砍价' })
}
this.setData({
menuButtonInfo: wx.getMenuButtonBoundingClientRect()
})
console.log(this.data.menuButtonInfo)
const { top, width, height, right } = this.data.menuButtonInfo
wx.getSystemInfo({
success: (res) => {
const { statusBarHeight } = res
const margin = top - statusBarHeight
this.setData({
navHeight: (height + statusBarHeight + (margin * 2) + 15),
searchMarginTop: statusBarHeight + margin, // 状态栏 + 胶囊按钮边距
searchHeight: height, // 与胶囊按钮同高
searchWidth: right - width // 胶囊按钮右边坐标 - 胶囊按钮宽度 = 按钮左边可使用宽度
})
},
})
},
/**

View File

@@ -1,4 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "我的关注"
"usingComponents": {
"van-nav-bar":"/miniprogram/miniprogram_npm/@vant/weapp/nav-bar/index"
},
"navigationBarTitleText": "我的关注",
"navigationStyle": "custom"
}

View File

@@ -1,6 +1,14 @@
<view>
<van-nav-bar
title="{{type==1 ? '我的关注' : (type==2 ? '我的拼团' : '我的砍价')}}"
left-text=""
left-arrow
bind:click-left="back"
style="position:fixed;left:0;top:0;width:100%;z-index:2;"
/>
<view style="margin-top:{{height}}px;">
<view class="order-list" wx:if="{{order_list.length}}">
<view wx:for="{{order_list}}" wx:key="{{index}}" wx:for-item="item">
<view wx:for="{{order_list}}" wx:key="index" wx:for-item="item">
<view class="Group" bindtap="activity" data-id="{{item.order_id}}">
<view class="Group-image">
<image src="../image/userimg.png"></image>
@@ -22,4 +30,5 @@
</view>
</view>
</view>
</view>
</view>

View File

@@ -1,7 +1,6 @@
var app = getApp();
const { request } = require('../../utils/request')
// 处理订单列表中的图片路径
function processOrderList(list) {
return list.map(function(item) {
item.userbAvatar = app.fixImageUrl(item.userbAvatar) || '/pages/image/userimg.png';
@@ -11,131 +10,200 @@ function processOrderList(list) {
Page({
data: {
// Patient mode
order_list: [],
nav_type: 1,
all: true,
height: '',
url: app.globalData.url,
statusType: ["全部", "待接单", "已接单", "服务中", "待支付", "已完成","已取消"],
status: ["", "0", "1", "2", "3","4","-2"],
statusType: ["全部", "待接单", "已接单", "服务中", "待支付", "已完成", "已取消", "申请退款", "已退款", "已结算"],
status: ["", "0", "1", "2", "3", "4", "-2", "5", "7", "8"],
currentType: 0,
tabClass: ["", "", "", "", "", "", ""],
pageNum: 1,
hasMore: true,
firstLoad: true,
loading: false
},
statusTap: function (e) {
var curType = e.currentTarget.dataset.index;
this.setData({
currentType: curType,
pageNum: 1,
order_list: []
});
this.getOrderList();
},
onClickLeft() {
wx.navigateBack()
loading: false,
// Caregiver mode
userType: '',
cgOrders: [],
cgPageNum: 1,
cgHasMore: true,
cgLoading: false,
// Promoter mode
comRecords: [],
comLoading: false,
// Worker mode
workRevenue: [],
workLoading: false,
workHasMore: true
},
onLoad: function (options) {
this.setData(getApp().getNavBarHeight());
},
onShow: function () {
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({ selected: 2 });
}
var userType = app.globalData.userType || 'C';
var roleChanged = this.data.userType !== userType;
this.setData({ userType: userType });
if (this.data.firstLoad || roleChanged) {
this.setData({ firstLoad: false });
this.loadRoleContent();
}
},
onPullDownRefresh: function () {
this.loadRoleContent().finally(function() { wx.stopPullDownRefresh(); });
},
onReachBottom: function () {
if (this.data.userType === 'B') {
if (this.data.cgHasMore && !this.data.cgLoading) this.loadCgOrders();
} else if ((this.data.userType === '03' || this.data.userType === '04' || this.data.userType === '05') && this.data.workHasMore && !this.data.workLoading) {
this.loadWorkRevenue();
} else {
if (this.data.hasMore && !this.data.loading) this.getOrderList();
}
},
loadRoleContent() {
var ut = this.data.userType;
if (ut === 'B') {
this.setData({ cgPageNum: 1, cgOrders: [] });
this.loadCgOrders();
} else if (ut === '06') {
this.loadCommission();
} else if (ut === '03' || ut === '04' || ut === '05') {
this.loadWorkRevenue();
} else {
this.setData({ pageNum: 1, order_list: [] });
this.getOrderList();
}
},
// === Promoter: Load commission records ===
async loadCommission() {
this.setData({ comLoading: true });
try {
var res = await request({ url: '/system/promotion/myCommission', method: 'GET', loading: false });
if (res.code === 200) {
this.setData({ comRecords: res.data || [] });
}
} catch (e) {}
this.setData({ comLoading: false });
},
goWithdraw() {
wx.navigateTo({ url: '/shopping/pages/withdrawal/withdrawal' });
},
// === Worker: Load revenue overview ===
async loadWorkRevenue() {
this.setData({ workLoading: true });
try {
var res = await request({
url: '/system/profit/list',
method: 'GET',
data: { pageNum: 1, pageSize: 20 },
loading: false
});
if (res.code === 200) {
var list = res.rows || res.data || [];
this.setData({ workRevenue: list });
}
} catch (e) {}
this.setData({ workLoading: false });
},
goWorkOrderDetail(e) {
var item = JSON.stringify(e.currentTarget.dataset.item);
wx.navigateTo({ url: '/pages/orderdetail/orderdetail?item=' + item });
},
// === Caregiver: Load completed orders (status=4,8) ===
async loadCgOrders() {
if (this.data.cgLoading) return;
this.setData({ cgLoading: true });
try {
var uid = wx.getStorageSync('uid');
// Load completed orders: 已完成(4), 已结算(8)
var results = await Promise.all([
request({ url: '/system/view/list', method: 'GET', data: { pageNum: 1, pageSize: 20, status: '4', userbId: uid }, loading: false }),
request({ url: '/system/view/list', method: 'GET', data: { pageNum: 1, pageSize: 20, status: '8', userbId: uid }, loading: false })
]);
var allList = [];
results.forEach(function(r) {
if (r.code === 200) {
var list = r.rows || r.data || [];
allList = allList.concat(list);
}
});
allList.sort(function(a, b) { return (b.createTime || '').localeCompare(a.createTime || ''); });
this.setData({ cgOrders: allList, cgHasMore: false, cgPageNum: 1 });
} catch (e) {}
this.setData({ cgLoading: false });
},
goCgDetail(e) {
var item = JSON.stringify(e.currentTarget.dataset.item);
wx.navigateTo({ url: '/pages/orderdetail/orderdetail?item=' + item });
},
// === Patient: order list methods ===
statusTap: function (e) {
var curType = e.currentTarget.dataset.index;
this.setData({ currentType: curType, pageNum: 1, order_list: [] });
this.getOrderList();
},
onClickLeft() { wx.navigateBack(); },
itemclick(e) {
if (e.currentTarget.dataset.item != 0) {
let item = JSON.stringify(e.currentTarget.dataset.item);
wx.navigateTo({
url: "/pages/orderdetail/orderdetail?item=" + item,
});
var item = JSON.stringify(e.currentTarget.dataset.item);
wx.navigateTo({ url: "/pages/orderdetail/orderdetail?item=" + item });
}
},
go_pay(e) {
if (e.currentTarget.dataset.item != 0) {
let item = JSON.stringify(e.currentTarget.dataset.item);
wx.navigateTo({
url: "/pages/orderdetail/orderdetail?item=" + item,
});
}
},
onShow: function () {
if (this.data.firstLoad) {
this.setData({ firstLoad: false })
this.getOrderList()
}
},
onPullDownRefresh: function () {
this.setData({ pageNum: 1 })
this.refreshList().finally(() => wx.stopPullDownRefresh())
},
onReachBottom: function () {
if (this.data.hasMore && !this.data.loading) {
this.getOrderList()
var item = JSON.stringify(e.currentTarget.dataset.item);
wx.navigateTo({ url: "/pages/orderdetail/orderdetail?item=" + item });
}
},
async refreshList() {
this.setData({ loading: true })
this.setData({ loading: true });
try {
var res = await request({
url: '/system/view/list',
method: 'GET',
loading: false,
data: {
pageNum: 1,
pageSize: 30,
status: this.data.status[this.data.currentType],
usercId: wx.getStorageSync('uid')
}
})
url: '/system/view/list', method: 'GET', loading: false,
data: { pageNum: 1, pageSize: 30, status: this.data.status[this.data.currentType], usercId: wx.getStorageSync('uid') }
});
var list = processOrderList(res.rows || res.data || []);
this.setData({
order_list: list,
pageNum: 2,
hasMore: list.length >= 30
})
} catch (e) {
wx.showToast({ title: '加载失败', icon: 'none' })
}
this.setData({ loading: false })
this.setData({ order_list: list, pageNum: 2, hasMore: list.length >= 30 });
} catch (e) { wx.showToast({ title: '加载失败', icon: 'none' }); }
this.setData({ loading: false });
},
async getOrderList() {
if (this.data.loading) return
this.setData({ loading: true })
if (this.data.loading) return;
this.setData({ loading: true });
try {
var res = await request({
url: '/system/view/list',
method: 'GET',
loading: this.data.pageNum === 1,
data: {
pageNum: this.data.pageNum,
pageSize: 30,
status: this.data.status[this.data.currentType],
usercId: wx.getStorageSync('uid')
}
})
url: '/system/view/list', method: 'GET', loading: this.data.pageNum === 1,
data: { pageNum: this.data.pageNum, pageSize: 30, status: this.data.status[this.data.currentType], usercId: wx.getStorageSync('uid') }
});
var newList = processOrderList(res.rows || res.data || []);
if (this.data.pageNum === 1) {
this.setData({
order_list: newList,
pageNum: 2,
hasMore: newList.length >= 30
})
this.setData({ order_list: newList, pageNum: 2, hasMore: newList.length >= 30 });
} else {
this.setData({
order_list: this.data.order_list.concat(newList),
pageNum: this.data.pageNum + 1,
hasMore: newList.length >= 30
})
this.setData({ order_list: this.data.order_list.concat(newList), pageNum: this.data.pageNum + 1, hasMore: newList.length >= 30 });
}
} catch (e) {}
this.setData({ loading: false })
},
})
this.setData({ loading: false });
}
});

View File

@@ -1,51 +1,121 @@
<van-nav-bar title="我的订单" left-text="" right-text="" bind:click-left="onClickLeft" bind:click-right="onClickRight" style=" position: fixed;left: 0;top: 0;width: 100%;z-index: 2;" />
<view class="status-box" style="margin-top: {{height}}px;">
<view bindtap="statusTap" class="status-label {{index == currentType ? 'active' : ''}}" wx:for-items="{{statusType}}" wx:key="{{index}}" data-index="{{index}}">
{{item}}
<view class="{{tabClass[index]}}"></view>
<!-- ===== Promoter View (06): 佣金明细 ===== -->
<view wx:if="{{userType === '06'}}" class="container">
<view class="summary-bar">
<text class="summary-label">推广佣金明细</text>
<text class="withdraw-btn" bindtap="goWithdraw">提现</text>
</view>
</view>
<view class="no-order" style="margin-top: {{height}}px;" wx:if="{{!order_list.length}}">
<image style="width: 200rpx;height: 200rpx;" src="/pages/image/empty.png" class="no-order-img"></image>
<view class="text">暂无订单</view>
</view>
<!-- 全部 -->
<view wx:if="{{nav_type==1||all}}">
<view class="order-list" wx:if="{{order_list.length}}">
<view wx:for="{{order_list}}" data-index="{{index}}" data-status="{{item.status}}" data-item="{{item}}" wx:for-item="item" bindtap="itemclick" class="flex-item">
<view style=" padding: 0 24rpx;height:366rpx;position: relative;background: #ffffff;">
<view style="height:66rpx;">
<text class="time_msg">订单号:{{item.orderNumber}}</text>
<!-- 订单状态:-2:已取消 -1:拒绝接单 0:待接单 1:已接单 2:服务中 3:待支付 4:已完成 5申请退款 6退款中 7已退款 8:已结算 -->
<view wx:if="{{item.status==-2}}" class="status_msg">{{"已取消"}}</view>
<view wx:if="{{item.status==-1}}" class="status_msg">{{"拒绝接单"}}</view>
<view wx:if="{{item.status==0}}" class="status_msg">{{"待接单"}}</view>
<view wx:if="{{item.status==1}}" class="status_msg">{{"已接单"}}</view>
<view wx:if="{{item.status==2}}" class="status_msg">{{"服务中"}}</view>
<view wx:if="{{item.status==3}}" class="status_msg">{{"待支付"}}</view>
<view wx:if="{{item.status==4}}" class="status_msg">{{"已完成"}}</view>
<view wx:if="{{item.status==5}}" class="status_msg">{{"申请退款"}}</view>
<view wx:if="{{item.status==6}}" class="status_msg">{{"退款中"}}</view>
<view wx:if="{{item.status==7}}" class="status_msg">{{"已退款"}}</view>
<view wx:if="{{item.status==8}}" class="status_msg">{{"已结算"}}</view>
<view wx:if="{{comLoading}}" class="loading">加载中...</view>
<block wx:for="{{comRecords}}" wx:key="id">
<view class="record-card">
<view class="record-row">
<view class="record-type">
<text class="type-tag">{{item.profitType === 'promotion_l1' ? '一级' : item.profitType === 'promotion_l2' ? '二级' : item.profitType === 'promotion_l3' ? '三级' : '推广'}}</text>
<text class="order-id">订单 #{{item.orderId}}</text>
</view>
<text class="record-amount">¥{{item.amount || '0'}}</text>
</view>
<view class="record-row sub">
<text class="record-rate">比例 {{item.rate || '0'}}%</text>
<text class="record-status {{item.status === '1' ? 'settled' : item.status === '7' ? 'reversed' : 'pending'}}">{{item.status === '1' ? '已结算' : item.status === '7' ? '已退回' : '待结算'}}</text>
</view>
<view wx:if="{{item.createTime}}" class="record-time">{{item.createTime}}</view>
</view>
</block>
<view wx:if="{{!comLoading && comRecords.length === 0}}" class="empty">暂无佣金记录</view>
</view>
<view style="height: 1rpx;background: #ECECEC;"></view>
<view class="details_box">
<!-- ===== Worker View (03/04/05): 收益明细 ===== -->
<view wx:if="{{userType === '03' || userType === '04' || userType === '05'}}" class="container">
<view class="cg-header"><text class="cg-header-title">收益明细</text></view>
<view wx:if="{{workLoading}}" class="loading">加载中...</view>
<block wx:for="{{workRevenue}}" wx:key="id">
<view class="cg-card" bindtap="goWorkOrderDetail" data-item="{{item}}">
<view class="cg-row">
<text class="cg-order-no">订单 #{{item.orderId}}</text>
<text class="cg-amount" style="color:#67C23A;">¥{{item.amount || '0'}}</text>
</view>
<view class="cg-row sub">
<text class="cg-meta">{{item.profitType === 'dispatch_fee' ? '调度费' : item.profitType === 'ops_flow' ? '运营流水' : item.profitType}}</text>
<text class="cg-status">{{item.status === '0' ? '未结算' : item.status === '1' ? '已结算' : item.status}}</text>
</view>
<view wx:if="{{item.createTime}}" class="cg-time">{{item.createTime}}</view>
</view>
</block>
<view wx:if="{{!workLoading && workRevenue.length === 0}}" class="empty">暂无收益记录</view>
<view wx:if="{{!workHasMore && workRevenue.length > 0}}" class="end">— 已加载全部 —</view>
</view>
<image src="{{item.userbAvatar}}" class="Group-image"></image>
<view style="margin-left: 31rpx;margin-top: 40rpx;">
<view class="title">{{item.userbName}}</view>
<view class="detail_number">{{item.serviceTime}}天</view>
<view class="money">实付款:<text style="font-size: 30rpx;color: #FF8F1F;font-family: PingFang SC;font-weight: bold;">¥{{item.yuguMoney}}元</text></view>
<!-- ===== Caregiver View (B role): 已完成订单 ===== -->
<view wx:if="{{userType === 'B'}}" class="cg-container">
<view class="cg-header">
<text class="cg-header-title">已完成</text>
<text class="cg-header-sub">已完成的陪诊/陪护订单</text>
</view>
<block wx:for="{{cgOrders}}" wx:key="orderId">
<view class="cg-card" bindtap="goCgDetail" data-item="{{item}}">
<view class="cg-row">
<text class="cg-order-no">{{item.yuliu1 || '订单#' + item.orderId}}</text>
<text class="cg-amount">¥{{item.yuguMoney || item.orderMoney}}</text>
</view>
<view class="cg-row sub">
<text class="cg-meta">患者ID: {{item.cId || '--'}} | {{item.hospitalName || ''}}</text>
</view>
<view class="cg-row sub">
<text class="cg-time">{{item.createTime}}</text>
<text class="cg-status {{item.status === '4' ? 's-done' : 's-settled'}}">{{item.status === '4' ? '已完成' : item.status === '8' ? '已结算' : item.status}}</text>
</view>
</view>
</block>
<view wx:if="{{!cgLoading && cgOrders.length === 0}}" class="empty">暂无已完成订单</view>
<view wx:if="{{cgLoading}}" class="loading">加载中...</view>
<view wx:if="{{!cgHasMore && cgOrders.length > 0}}" class="end">— 已加载全部 —</view>
</view>
<!-- ===== Patient View (C, 00, default) ===== -->
<view wx:if="{{userType !== 'B' && userType !== '06' && userType !== '03' && userType !== '04' && userType !== '05'}}">
<van-nav-bar title="我的订单" left-text="" right-text="" bind:click-left="onClickLeft" bind:click-right="onClickRight" style=" position: fixed;left: 0;top: 0;width: 100%;z-index: 2;" />
<view class="status-box" style="margin-top: {{height}}px;">
<view bindtap="statusTap" class="status-label {{index == currentType ? 'active' : ''}}" wx:for-items="{{statusType}}" wx:key="index" data-index="{{index}}">
{{item}}
<view class="{{tabClass[index]}}"></view>
</view>
</view>
<view class="no-order" style="margin-top: {{height}}px;" wx:if="{{!order_list.length}}">
<image style="width: 200rpx;height: 200rpx;" src="/pages/image/empty.png" class="no-order-img"></image>
<view class="text">暂无订单</view>
</view>
<view wx:if="{{nav_type==1||all}}">
<view class="order-list" wx:if="{{order_list.length}}">
<view wx:for="{{order_list}}" wx:key="orderId" data-index="{{index}}" data-status="{{item.status}}" data-item="{{item}}" wx:for-item="item" bindtap="itemclick" class="flex-item">
<view style=" padding: 0 24rpx;height:366rpx;position: relative;background: #ffffff;">
<view style="height:66rpx;">
<text class="time_msg">订单号:{{item.orderNumber}}</text>
<view wx:if="{{item.status==-2}}" class="status_msg">{{"已取消"}}</view>
<view wx:if="{{item.status==-1}}" class="status_msg">{{"拒绝接单"}}</view>
<view wx:if="{{item.status==0}}" class="status_msg">{{"待接单"}}</view>
<view wx:if="{{item.status==1}}" class="status_msg">{{"已接单"}}</view>
<view wx:if="{{item.status==2}}" class="status_msg">{{"服务中"}}</view>
<view wx:if="{{item.status==3}}" class="status_msg">{{"待支付"}}</view>
<view wx:if="{{item.status==4}}" class="status_msg">{{"已完成"}}</view>
<view wx:if="{{item.status==5}}" class="status_msg">{{"申请退款"}}</view>
<view wx:if="{{item.status==6}}" class="status_msg">{{"退款中"}}</view>
<view wx:if="{{item.status==7}}" class="status_msg">{{"已退款"}}</view>
<view wx:if="{{item.status==8}}" class="status_msg">{{"已结算"}}</view>
</view>
<view style="height: 1rpx;background: #ECECEC;"></view>
<view class="details_box">
<image src="{{item.userbAvatar}}" class="Group-image"></image>
<view style="margin-left: 31rpx;margin-top: 40rpx;">
<view class="title">{{item.userbName}}</view>
<view class="detail_number">{{item.serviceTime}}天</view>
<view class="money">实付款:<text style="font-size: 30rpx;color: #FF8F1F;font-family: PingFang SC;font-weight: bold;">¥{{item.yuguMoney}}元</text></view>
</view>
<view class="detail_btn" bindtap="go_pay" data-id="{{item.order_id}}" wx:if="{{item.status==3}}" data-item="{{item}}">去付款</view>
</view>
<view class="detail_btn" bindtap="go_pay" data-id="{{item.order_id}}" wx:if="{{item.status==3}}" data-item="{{item}}">去付款</view>
<!-- <view class="detail_btn" bindtap="go_Qcode" data-id="{{item.order_id}}" wx:if="{{item.status==1}}">查看二维码</view> -->
</view>
</view>
</view>
</view>
</view>
</view>

View File

@@ -190,5 +190,41 @@ padding: 0 31rpx;
height: 128rpx;
margin: 74rpx 40rpx 84rpx 40rpx;
}
/* === Caregiver style === */
.cg-container { min-height: 100vh; background: #F5F5F5; padding-bottom: 40rpx; }
.cg-header { background: #fff; padding: 32rpx 40rpx; margin-bottom: 16rpx; }
.cg-header-title { font-size: 36rpx; font-weight: bold; color: #333; display: block; }
.cg-header-sub { font-size: 24rpx; color: #999; margin-top: 8rpx; }
.cg-card { background: #fff; margin: 12rpx 0 0 0; padding: 24rpx 32rpx; }
.cg-row { display: flex; justify-content: space-between; align-items: center; }
.cg-row.sub { margin-top: 8rpx; }
.cg-order-no { font-size: 28rpx; font-weight: 600; color: #333; }
.cg-amount { font-size: 30rpx; font-weight: 700; color: #E6A23C; }
.cg-meta { font-size: 24rpx; color: #999; }
.cg-time { font-size: 22rpx; color: #C0C4CC; }
.cg-status { font-size: 22rpx; padding: 4rpx 12rpx; border-radius: 8rpx; }
.cg-status.s-done { background: #E8F5E9; color: #4CAF50; }
.cg-status.s-settled { background: #E3F2FD; color: #2196F3; }
.loading { text-align: center; padding: 40rpx; color: #999; }
.empty { text-align: center; padding: 120rpx 0; color: #999; font-size: 28rpx; }
.end { text-align: center; padding: 32rpx; color: #C0C4CC; font-size: 24rpx; }
/* === Multi-role shared styles === */
.container { padding: 0 0 40rpx 0; background: #F5F5F5; min-height: 100vh; }
.summary-bar { display: flex; justify-content: space-between; align-items: center; padding: 24rpx 32rpx; background: #fff; margin-bottom: 12rpx; }
.summary-label { font-size: 30rpx; font-weight: bold; color: #333; }
.withdraw-btn { background: #FF8F1F; color: #fff; font-size: 24rpx; padding: 8rpx 24rpx; border-radius: 24rpx; }
.record-card { background: #fff; margin: 12rpx 0 0 0; padding: 24rpx 32rpx; }
.record-row { display: flex; justify-content: space-between; align-items: center; }
.record-row.sub { margin-top: 8rpx; }
.record-type { display: flex; align-items: center; }
.type-tag { font-size: 22rpx; background: #FFF3E0; color: #FF9800; padding: 2rpx 12rpx; border-radius: 4rpx; margin-right: 12rpx; }
.order-id { font-size: 24rpx; color: #999; }
.record-amount { font-size: 30rpx; font-weight: 700; color: #67C23A; }
.record-rate { font-size: 22rpx; color: #999; }
.record-status { font-size: 22rpx; padding: 2rpx 12rpx; border-radius: 4rpx; }
.record-status.settled { background: #E8F5E9; color: #4CAF50; }
.record-status.reversed { background: #FFEBEE; color: #F44336; }
.record-status.pending { background: #FFF3E0; color: #FF9800; }
.record-time { font-size: 22rpx; color: #C0C4CC; margin-top: 4rpx; }

View File

@@ -60,7 +60,7 @@ Page({
}).then(res => {
var list = res.data || [];
list = list.map(function(item) {
item.facePic = app.fixImageUrl(item.facePic);
item.facePic = app.fixImageUrl(item.facePic || item.avatar) || '/pages/image/userimg.png';
return item;
});
that.setData({ special_offer: list })

View File

@@ -21,18 +21,18 @@
<view class="tejiashangpin">
<view class="Discount" wx:if="{{special_offer.length}}">
<view wx:for="{{special_offer}}" wx:key="{{index}}" wx:for-item="item" class="flex-item bc_green" style='display:flex;background-color: white;margin-right: 10rpx;margin-bottom: 24rpx;'>
<view wx:for="{{special_offer}}" wx:key="index" wx:for-item="item" class="flex-item bc_green" style='display:flex;background-color: white;margin-right: 10rpx;margin-bottom: 24rpx;'>
<view class="Group" bindtap="details" data-item="{{item}}">
<view class="Group-image">
<image src="{{item.facePic}}"></image>
<image src="{{item.facePic || item.avatar || '/pages/image/userimg.png'}}" mode="aspectFill"></image>
</view>
<view class="content">
<view style="display: flex; flex-direction:row;align-items : flex-end;">
<view class="title1">{{item.nickName}}</view>
<view class="title2">({{"陪护"}})</view>
<view wx:if="{{item.sex==1}}" class="title3">{{"男"}}</view>
<view wx:if="{{item.sex==0}}" class="title3">{{"女"}}</view>
<view wx:if="{{item.sex==0}}" class="title3">男</view>
<view wx:if="{{item.sex==1}}" class="title3">女</view>
<view class="title4">{{item.experience}}经验</view>
</view>
<view class="tejia">

View File

@@ -59,7 +59,7 @@ Page({
if (services.length) {
var mapped = services.map(function (s) {
return {
icon: s.icon || s.name,
icon: s.icon || '',
title: s.name,
price: s.price,
describe: s.description || '',

View File

@@ -21,10 +21,10 @@
<view class="contar">
<view class="tejiashangpin">
<view class="Discount" wx:if="{{itemView.length}}">
<view wx:for="{{itemView}}" wx:key="{{index}}" wx:for-item="item" class="flex-item bc_green" style='display:flex;background-color: white;margin-right: 10rpx;margin-bottom: 24rpx;'>
<view wx:for="{{itemView}}" wx:key="index" wx:for-item="item" class="flex-item bc_green" style='display:flex;background-color: white;margin-right: 10rpx;margin-bottom: 24rpx;'>
<view class="Group" bindtap="details" data-item="{{item}}">
<view class="Group-image">
<image src="{{item.icon.indexOf('http') === 0 ? item.icon : '../image/home/' + item.icon + '.png'}}"></image>
<image src="{{item.icon && item.icon.indexOf('http') === 0 ? item.icon : (item.icon ? '../image/home/' + item.icon + '.png' : '/pages/image/empty.png')}}"></image>
</view>
<view class="content">
<view style="display: flex; flex-direction:row;align-items : flex-end;">

View File

@@ -6,7 +6,7 @@
<view style='display:flex;background-color: white;'>
<view class="Group">
<view class="Group-image">
<image src="{{item.icon.indexOf('http') === 0 ? item.icon : '../image/home/' + item.icon + '.png'}}"></image>
<image src="{{item.icon && item.icon.indexOf('http') === 0 ? item.icon : (item.icon ? '../image/home/' + item.icon + '.png' : '/pages/image/empty.png')}}"></image>
</view>
<view class="content">
<view style="display: flex; flex-direction:row;align-items : flex-end;">

View File

@@ -6,6 +6,7 @@ Page({
* 页面的初始数据
*/
data: {
height: '',
resp:{
"erro": 0,
"infro": {
@@ -83,6 +84,7 @@ Page({
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.setData(getApp().getNavBarHeight());
console.log(options.type)
console.log(options.id)
//详情显示

View File

@@ -3,5 +3,6 @@
"van-nav-bar":"/miniprogram/miniprogram_npm/@vant/weapp/nav-bar/index",
"van-uploader": "/miniprogram/miniprogram_npm/@vant/weapp/uploader/index"
},
"navigationBarTitleText": "订单详情"
"navigationBarTitleText": "退款详情",
"navigationStyle": "custom"
}

View File

@@ -1,4 +1,12 @@
<van-nav-bar
title="退款详情"
left-text=""
left-arrow
bind:click-left="onClickLeft"
style="position:fixed;left:0;top:0;width:100%;z-index:2;"
/>
<view style="margin-top:{{height}}px;">
<view style=" height:340rpx;position: relative;background: #ffffff;margin-top:8rpx;">
<view style="height:66rpx;padding: 0 24rpx;">
<text class="time_msg"></text>
@@ -137,6 +145,7 @@
</scroll-view>
<!-- <button type="primary" plain="true" style="margin-bottom:20rpx" bindtap="isok">完成</button> -->
</view>
</view>

View File

@@ -1,87 +1,239 @@
// 服务模块
var app = getApp();
const { request } = require('../../utils/request')
Page({
data: {
// Patient mode
servicesPeizhen: [],
servicesPeihu: [],
activeTab: 0,
firstLoad: true
firstLoad: true,
// Caregiver mode
userType: '',
cgOrders: [],
cgPageNum: 1,
cgHasMore: true,
cgLoading: false,
// Promoter mode
teamMembers: [],
teamLoading: false,
// Worker mode
workOrders: [],
workLoading: false,
workPageNum: 1,
workHasMore: true
},
onShow() {
if (this.data.firstLoad) {
this.setData({ firstLoad: false })
this.loadServices()
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({ selected: 1 });
}
var userType = app.globalData.userType || 'C';
var roleChanged = this.data.userType !== userType;
this.setData({ userType: userType });
if (this.data.firstLoad || roleChanged) {
this.setData({ firstLoad: false });
this.loadRoleContent();
}
},
onPullDownRefresh() {
this.loadServices().finally(() => wx.stopPullDownRefresh())
this.loadRoleContent().finally(function() { wx.stopPullDownRefresh(); });
},
onReachBottom() {
if (this.data.userType === 'B' && this.data.cgHasMore && !this.data.cgLoading) {
this.loadCgOrders();
} else if ((this.data.userType === '03' || this.data.userType === '04' || this.data.userType === '05') && this.data.workHasMore && !this.data.workLoading) {
this.loadWorkOrders();
}
},
loadRoleContent() {
var ut = this.data.userType;
if (ut === 'B') {
this.setData({ cgPageNum: 1, cgOrders: [] });
this.loadCgOrders();
} else if (ut === '06') {
this.loadTeam();
} else if (ut === '03' || ut === '04' || ut === '05') {
this.setData({ workPageNum: 1, workOrders: [] });
this.loadWorkOrders();
} else {
this.loadServices();
}
},
// === Promoter: Load team ===
async loadTeam() {
this.setData({ teamLoading: true });
try {
var res = await request({ url: '/system/promotion/team', method: 'GET', loading: false });
if (res.code === 200) {
this.setData({ teamMembers: res.data || [] });
}
} catch (e) {}
this.setData({ teamLoading: false });
},
// === Worker (03/04/05): Load all orders ===
async loadWorkOrders() {
if (this.data.workLoading) return;
this.setData({ workLoading: true });
try {
var res = await request({
url: '/system/view/list',
method: 'GET',
data: { pageNum: this.data.workPageNum, pageSize: 20 },
loading: false
});
if (res.code === 200) {
var list = res.rows || res.data || [];
if (this.data.workPageNum === 1) {
this.setData({ workOrders: list, workHasMore: list.length >= 20, workPageNum: 2 });
} else {
this.setData({
workOrders: this.data.workOrders.concat(list),
workHasMore: list.length >= 20,
workPageNum: this.data.workPageNum + 1
});
}
}
} catch (e) {}
this.setData({ workLoading: false });
},
goWorkDetail(e) {
var item = JSON.stringify(e.currentTarget.dataset.item);
wx.navigateTo({ url: '/pages/orderdetail/orderdetail?item=' + item });
},
// === Caregiver: Load in-progress orders (status=1,2,3) ===
async loadCgOrders() {
if (this.data.cgLoading) return;
this.setData({ cgLoading: true });
try {
var uid = wx.getStorageSync('uid');
// Load in-progress orders: 已接单(1), 服务中(2), 待支付(3)
var results = await Promise.all([
request({ url: '/system/view/list', method: 'GET', data: { pageNum: 1, pageSize: 20, status: '1', userbId: uid }, loading: false }),
request({ url: '/system/view/list', method: 'GET', data: { pageNum: 1, pageSize: 20, status: '2', userbId: uid }, loading: false }),
request({ url: '/system/view/list', method: 'GET', data: { pageNum: 1, pageSize: 20, status: '3', userbId: uid }, loading: false })
]);
var allList = [];
results.forEach(function(r) {
if (r.code === 200) {
var list = r.rows || r.data || [];
allList = allList.concat(list);
}
});
// sort by createTime desc
allList.sort(function(a, b) { return (b.createTime || '').localeCompare(a.createTime || ''); });
this.setData({ cgOrders: allList, cgHasMore: false, cgPageNum: 1 });
} catch (e) {}
this.setData({ cgLoading: false });
},
// === Caregiver: Navigate to order detail ===
goCgDetail(e) {
var item = JSON.stringify(e.currentTarget.dataset.item);
wx.navigateTo({ url: '/pages/orderdetail/orderdetail?item=' + item });
},
// === Caregiver: Start service (status 1→2) ===
startService(e) {
var item = e.currentTarget.dataset.item;
var that = this;
wx.showModal({
title: '确认开始服务',
content: '确认到达医院并开始为 ' + (item.yuliu1 || '订单#' + item.orderId) + ' 服务?',
success: function(res) { if (res.confirm) that.doStartService(item); }
});
},
async doStartService(item) {
try {
var res = await request({
url: '/system/view/startServiceWithOrder',
method: 'POST',
data: { orderId: item.orderId },
loading: true,
loadingText: '处理中...'
});
if (res.code === 200) {
wx.showToast({ title: '已开始服务', icon: 'success' });
this.setData({ firstLoad: true });
this.onShow();
}
} catch (e) {}
},
// === Caregiver: Complete service (status 2→3) ===
completeService(e) {
var item = e.currentTarget.dataset.item;
var that = this;
wx.showModal({
title: '确认完成服务',
content: '确认完成 ' + (item.yuliu1 || '订单#' + item.orderId) + ' 的服务?完成后将等待患者付款。',
success: function(res) { if (res.confirm) that.doCompleteService(item); }
});
},
async doCompleteService(item) {
try {
var res = await request({
url: '/system/view/completeOrder',
method: 'POST',
data: { orderId: item.orderId },
loading: true,
loadingText: '处理中...'
});
if (res.code === 200) {
wx.showToast({ title: '服务已完成', icon: 'success' });
this.setData({ firstLoad: true });
this.onShow();
}
} catch (e) {}
},
getCgStatusLabel: function(s) {
return getApp().getStatusLabel(s);
},
// === Patient: Load services ===
async loadServices() {
try {
// 同时加载陪诊和陪护服务
var [res1, res2] = await Promise.all([
request({ url: '/system/serviceType/enabled', data: { category: '2' }, loading: true, loadingText: '加载服务...' }),
request({ url: '/system/serviceType/enabled', data: { category: '1' }, loading: false })
])
var res1 = await request({ url: '/system/serviceType/enabled', data: { category: '2' }, loading: true, loadingText: '加载服务...' });
var res2 = await request({ url: '/system/serviceType/enabled', data: { category: '1' }, loading: false });
this.setData({
servicesPeizhen: (res1.data || []).map(function(s) {
return {
id: s.id,
name: s.name,
title: s.name,
price: s.price,
desc: s.description,
describe: s.description,
icon: s.icon,
ordertype: s.typeCode,
typeCode: s.typeCode
}
return { id: s.id, name: s.name, title: s.name, price: s.price, desc: s.description, describe: s.description, icon: s.icon, ordertype: s.typeCode, typeCode: s.typeCode };
}),
servicesPeihu: (res2.data || []).map(function(s) {
return {
id: s.id,
name: s.name,
title: s.name,
price: s.price,
desc: s.description,
describe: s.description,
icon: s.icon,
ordertype: s.typeCode,
typeCode: s.typeCode,
nickName: s.name,
introduce: s.description
}
return { id: s.id, name: s.name, title: s.name, price: s.price, desc: s.description, describe: s.description, icon: s.icon, ordertype: s.typeCode, typeCode: s.typeCode, nickName: s.name, introduce: s.description };
})
})
});
} catch (e) {}
},
switchTab(e) {
this.setData({ activeTab: e.currentTarget.dataset.index })
this.setData({ activeTab: e.currentTarget.dataset.index });
},
// 点击服务-跳转下单页
onServiceTap(e) {
if (wx.getStorageSync('phone') == '') {
wx.showModal({
title: '提示',
content: '请先登录',
success(res) {
if (res.confirm) wx.switchTab({ url: '/pages/my/my' })
}
})
return
success: function(res) { if (res.confirm) wx.switchTab({ url: '/pages/my/my' }); }
});
return;
}
var item = JSON.stringify(e.currentTarget.dataset.item)
var item = JSON.stringify(e.currentTarget.dataset.item);
if (this.data.activeTab === 0) {
wx.navigateTo({ url: '/pages/peizhen/peizhendetail?item=' + item })
wx.navigateTo({ url: '/pages/peizhen/peizhendetail?item=' + item });
} else {
wx.navigateTo({ url: '/shopping/pages/goddess/goddess?item=' + item })
wx.navigateTo({ url: '/shopping/pages/goddess/goddess?item=' + item });
}
}
})
});

View File

@@ -1,11 +1,83 @@
<view class="page">
<!-- 顶部标题 -->
<!-- ===== Promoter View (06): 我的团队 ===== -->
<view wx:if="{{userType === '06'}}" class="container">
<view class="header"><text class="title">我的团队</text><text class="count">共{{teamMembers.length}}人</text></view>
<view wx:if="{{teamLoading}}" class="loading">加载中...</view>
<block wx:for="{{teamMembers}}" wx:key="userId">
<view class="member-card">
<view class="member-info">
<view class="member-name">{{item.nickName || '用户' + item.userId}}</view>
<view class="member-phone">{{item.phonenumber}}</view>
</view>
<view class="member-stats">
<view class="member-stat"><text class="ms-num">{{item.inviteCount || 0}}</text><text class="ms-label">邀请</text></view>
<view class="member-stat"><text class="ms-num gold">¥{{item.commission || '0'}}</text><text class="ms-label">佣金贡献</text></view>
<view class="member-stat"><text class="ms-label">L{{item.level}}</text></view>
</view>
</view>
</block>
<view wx:if="{{!teamLoading && teamMembers.length === 0}}" class="empty">暂无团队成员</view>
</view>
<!-- ===== Worker View (03/04/05): 全部订单 ===== -->
<view wx:if="{{userType === '03' || userType === '04' || userType === '05'}}" class="container">
<view class="cg-header"><text class="cg-header-title">全部订单</text></view>
<block wx:for="{{workOrders}}" wx:key="orderId">
<view class="cg-card" bindtap="goWorkDetail" data-item="{{item}}">
<view class="cg-row">
<text class="cg-order-no">{{item.yuliu1 || '订单#' + item.orderId}}</text>
<text class="cg-amount">¥{{item.yuguMoney || item.orderMoney}}</text>
</view>
<view class="cg-row sub">
<text class="cg-meta">患者ID: {{item.cId || '--'}} | 陪诊师ID: {{item.bId || '--'}}</text>
</view>
<view class="cg-row sub">
<text class="cg-time">{{item.createTime}}</text>
<text class="cg-status">{{item.status === '0' ? '待接单' : item.status === '1' ? '已接单' : item.status === '2' ? '服务中' : item.status === '4' ? '已完成' : item.status === '5' ? '退款中' : item.status === '7' ? '已退款' : item.status === '8' ? '已结算' : item.status}}</text>
</view>
</view>
</block>
<view wx:if="{{!workLoading && workOrders.length === 0}}" class="empty">暂无订单</view>
<view wx:if="{{workLoading}}" class="loading">加载中...</view>
<view wx:if="{{!workHasMore && workOrders.length > 0}}" class="end">— 已加载全部 —</view>
</view>
<!-- ===== Caregiver View (B role): 进行中订单 ===== -->
<view wx:if="{{userType === 'B'}}" class="cg-container">
<view class="cg-header">
<text class="cg-header-title">进行中</text>
<text class="cg-header-sub">正在服务的订单</text>
</view>
<block wx:for="{{cgOrders}}" wx:key="orderId">
<view class="cg-card" bindtap="goCgDetail" data-item="{{item}}">
<view class="cg-row">
<text class="cg-order-no">{{item.yuliu1 || '订单#' + item.orderId}}</text>
<text class="cg-amount">¥{{item.yuguMoney || item.orderMoney}}</text>
</view>
<view class="cg-row sub">
<text class="cg-meta">患者ID: {{item.cId || '--'}} | {{item.hospitalName || ''}}</text>
</view>
<view class="cg-row sub">
<text class="cg-time">{{item.createTime}}</text>
<text class="cg-status {{item.status === '1' ? 's-accepted' : item.status === '2' ? 's-serving' : 's-pay'}}">{{item.status === '1' ? '已接单' : item.status === '2' ? '服务中' : item.status === '3' ? '待支付' : item.status}}</text>
</view>
<view class="cg-row actions" wx:if="{{item.status === '1' || item.status === '2'}}">
<view wx:if="{{item.status === '1'}}" class="cg-start-btn" catchtap="startService" data-item="{{item}}">开始服务</view>
<view wx:if="{{item.status === '2'}}" class="cg-done-btn" catchtap="completeService" data-item="{{item}}">完成服务</view>
</view>
</view>
</block>
<view wx:if="{{!cgLoading && cgOrders.length === 0}}" class="empty">暂无进行中订单</view>
<view wx:if="{{cgLoading}}" class="loading">加载中...</view>
<view wx:if="{{!cgHasMore && cgOrders.length > 0}}" class="end">— 已加载全部 —</view>
</view>
<!-- ===== Patient View (C, 00, default) ===== -->
<view wx:if="{{userType !== 'B' && userType !== '06' && userType !== '03' && userType !== '04' && userType !== '05'}}" class="page">
<view class="header">
<view class="header-title">全部服务</view>
<view class="header-sub">专业陪诊陪护,全程无忧</view>
</view>
<!-- 分类切换 -->
<view class="tab-bar">
<view class="tab-item {{activeTab === 0 ? 'active' : ''}}" bindtap="switchTab" data-index="{{0}}">
<text>就医陪诊</text>
@@ -17,13 +89,12 @@
</view>
</view>
<!-- 陪诊服务 -->
<view class="service-list" wx:if="{{activeTab === 0}}">
<block wx:for="{{servicesPeizhen}}" wx:key="id">
<view class="service-card" bindtap="onServiceTap" data-item="{{item}}">
<view class="card-left">
<view class="card-icon">
<image src="{{item.icon && item.icon.indexOf('http') === 0 ? item.icon : '../image/home/' + (item.icon || 'empty') + '.png'}}" mode="aspectFit"></image>
<image src="{{item.icon && item.icon.indexOf('http') === 0 ? item.icon : (item.icon ? '../image/home/' + item.icon + '.png' : '/pages/image/empty.png')}}" mode="aspectFit"></image>
</view>
</view>
<view class="card-body">
@@ -42,13 +113,12 @@
</view>
</view>
<!-- 陪护服务 -->
<view class="service-list" wx:if="{{activeTab === 1}}">
<block wx:for="{{servicesPeihu}}" wx:key="id">
<view class="service-card" bindtap="onServiceTap" data-item="{{item}}">
<view class="card-left">
<view class="card-icon">
<image src="{{item.icon && item.icon.indexOf('http') === 0 ? item.icon : '../image/home/' + (item.icon || 'empty') + '.png'}}" mode="aspectFit"></image>
<image src="{{item.icon && item.icon.indexOf('http') === 0 ? item.icon : (item.icon ? '../image/home/' + item.icon + '.png' : '/pages/image/empty.png')}}" mode="aspectFit"></image>
</view>
</view>
<view class="card-body">

View File

@@ -132,3 +132,47 @@
color: #999;
font-size: 28rpx;
}
/* === Caregiver style === */
.cg-container { min-height: 100vh; background: #F5F5F5; padding-bottom: 40rpx; }
.cg-header { background: #fff; padding: 32rpx 40rpx; margin-bottom: 16rpx; }
.cg-header-title { font-size: 36rpx; font-weight: bold; color: #333; display: block; }
.cg-header-sub { font-size: 24rpx; color: #999; margin-top: 8rpx; }
.cg-card { background: #fff; margin: 12rpx 0 0 0; padding: 24rpx 32rpx; }
.cg-row { display: flex; justify-content: space-between; align-items: center; }
.cg-row.sub { margin-top: 8rpx; }
.cg-order-no { font-size: 28rpx; font-weight: 600; color: #333; }
.cg-amount { font-size: 30rpx; font-weight: 700; color: #E6A23C; }
.cg-meta { font-size: 24rpx; color: #999; }
.cg-time { font-size: 22rpx; color: #C0C4CC; }
.cg-status { font-size: 22rpx; padding: 4rpx 12rpx; border-radius: 8rpx; }
.cg-status.s-accepted { background: #FFF3E0; color: #FF9800; }
.cg-status.s-serving { background: #E3F2FD; color: #2196F3; }
.cg-status.s-pay { background: #FCE4EC; color: #E91E63; }
.loading { text-align: center; padding: 40rpx; color: #999; }
.empty { text-align: center; padding: 120rpx 0; color: #999; font-size: 28rpx; }
.end { text-align: center; padding: 32rpx; color: #C0C4CC; font-size: 24rpx; }
/* === Multi-role shared styles === */
.container { padding: 0 0 40rpx 0; background: #F5F5F5; min-height: 100vh; }
.header { background: #fff; padding: 32rpx 40rpx; margin-bottom: 16rpx; display: flex; justify-content: space-between; align-items: center; }
.title { font-size: 36rpx; font-weight: bold; color: #333; }
.count { font-size: 24rpx; color: #999; }
.member-card { background: #fff; margin: 12rpx 0 0 0; padding: 24rpx 32rpx; }
.member-info { display: flex; align-items: center; }
.member-name { font-size: 28rpx; font-weight: 600; color: #333; }
.member-phone { font-size: 24rpx; color: #999; margin-left: 16rpx; }
.member-stats { display: flex; margin-top: 12rpx; }
.member-stat { text-align: center; margin-right: 32rpx; }
.ms-num { font-size: 28rpx; font-weight: 700; color: #333; display: block; }
.ms-num.gold { color: #FF8F1F; }
.ms-label { font-size: 20rpx; color: #999; }
.cg-row.actions { margin-top: 16rpx; padding-top: 16rpx; border-top: 1rpx solid #F0F0F0; justify-content: flex-end; }
.cg-start-btn { background: #67C23A; color: #fff; font-size: 24rpx; padding: 8rpx 28rpx; border-radius: 24rpx; }
.cg-done-btn { background: #FF8F1F; color: #fff; font-size: 24rpx; padding: 8rpx 28rpx; border-radius: 24rpx; }
.cg-status { font-size: 22rpx; padding: 4rpx 12rpx; border-radius: 8rpx; background: #409EFF; color: #fff; }
.cg-status.s-done { background: #E8F5E9; color: #4CAF50; }
.cg-status.s-settled { background: #E0F2F1; color: #009688; }

View File

@@ -42,24 +42,28 @@ Page({
getGoodsList: function () {
var that = this;
return request({
url: '/app/Goddesswechat/getCapitalDetails',
method: 'POST',
url: '/system/detail/list',
method: 'GET',
loading: true,
data: {
uid: wx.getStorageSync('uid'),
token: wx.getStorageSync('token'),
page: String(this.data.page),
page_size: 10,
pageNum: this.data.page,
pageSize: 10,
}
}).then(res => {
if (res.code === 200 || res.erro === 0) {
var list = res.detail || res.data || [];
if (res.code === 200) {
var list = (res.rows || []).map(function(item) {
return {
id: item.id,
type: item.type === '1' ? 1 : -1,
time: item.createTime || '',
money: item.jine || '0.00'
};
});
if (that.data.page === 1) {
that.setData({ order_list: list })
} else {
that.setData({ order_list: that.data.order_list.concat(list) })
}
that.setData({ page: that.data.page + 1 })
}
}).catch(function() {
wx.showToast({ title: '加载失败', icon: 'none' })

View File

@@ -2,6 +2,5 @@
"usingComponents": {
"van-nav-bar":"/miniprogram/miniprogram_npm/@vant/weapp/nav-bar/index"
},
"navigationBarTitleText": "我的钱包",
"navigationStyle": "custom"
"navigationBarTitleText": "我的钱包"
}

View File

@@ -8,7 +8,7 @@
<view style="margin-top:{{height}}px;">
<view class="order-list" wx:if="{{order_list.length}}">
<view wx:for="{{order_list}}" wx:key="{{index}}" wx:for-item="item">
<view wx:for="{{order_list}}" wx:key="index" wx:for-item="item">
<view class="Group" bindtap="activity" data-id="{{item.id}}">
<view style="margin-left: 34rpx;">
<view wx:if="{{item.type==1}}" class="title1">退款到账</view>
@@ -25,4 +25,9 @@
<image style="width:200rpx;height:200rpx;" src="/pages/image/empty.png"></image>
<view style="color:#999;font-size:28rpx;margin-top:20rpx;">暂无交易记录</view>
</view>
</view>

View File

@@ -1,116 +1,73 @@
/* pages/activity/activity.wxss */
.Group {
height: 120rpx;
display: flex;
border-bottom: 1px solid #f5f5f5;
align-items: center;
}
.Group-image image {
width: 100%;
height: 100%;
}
.title1 {
font-size: 28rpx;
color: #3D3D3D;
}
.title2 {
font-size: 26rpx;
color: #A8A8A8;
margin-top: 8rpx;
}
.content .title2 .house {
width: 28rpx;
height: 28rpx;
margin-right: 7rpx;
margin-top: 5rpx;
}
.content .title2 .house image {
width: 100%;
height: 100%;
}
.Price1 {
display: flex;
font-size: 28rpx;
color: #FF4A4A;
line-height: 42rpx;
margin-right: 17rpx;
}
.content .Price .Price2 {
font-size: 24rpx;
color: #CBCBCB;
line-height: 41rpx;
margin-right: 23rpx;
text-decoration:line-through;
}
.content .Price .Price3 {
width: 51rpx;
height: 21rpx;
font-size: 15rpx;
color: #E75D4D;
border: 1px solid #E75D4D;
border-radius: 4rpx;
text-align: center;
line-height: 18rpx;
margin-top: 10rpx;
}
.order-list{
width: 100%;
}
height: 120rpx;
display: flex;
border-bottom: 1px solid #f5f5f5;
align-items: center;
}
.Group-image image {
width: 100%;
height: 100%;
}
/* _______________________________________ */
view {
box-sizing: border-box;
overflow: hidden;
}
.custom-bar {
/* background-color: #aaa; */
position: fixed;
left: 0;
top: 0;
width: 100%;
}
.custom-bar__wrapper {
padding: 0 10rpx;
display: flex;
justify-content: center;
align-items: center;
}
.search-group {
width: 100%;
height: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
border-radius: 60rpx;
/* padding: 0 10rpx; */
padding-left: 25rpx;
background: #F5F5F5;
}
.search-group > input {
font-size: 25rpx;
width: 800rpx;
}
.search-group > image {
height: 32rpx;
width: 32rpx;
margin-right: 20rpx
}
.title1 {
font-size: 28rpx;
color: #3D3D3D;
}
.title2 {
font-size: 26rpx;
color: #A8A8A8;
margin-top: 8rpx;
}
.content .title2 .house {
width: 28rpx;
height: 28rpx;
margin-right: 7rpx;
margin-top: 5rpx;
}
.content .title2 .house image {
width: 100%;
height: 100%;
}
.Price1 {
display: flex;
font-size: 28rpx;
color: #FF4A4A;
line-height: 42rpx;
margin-right: 17rpx;
}
.content .Price .Price2 {
font-size: 24rpx;
color: #CBCBCB;
line-height: 41rpx;
margin-right: 23rpx;
text-decoration:line-through;
}
.content .Price .Price3 {
width: 51rpx;
height: 21rpx;
font-size: 15rpx;
color: #E75D4D;
border: 1px solid #E75D4D;
border-radius: 4rpx;
text-align: center;
line-height: 18rpx;
margin-top: 10rpx;
}
.order-list{
width: 100%;
}