From c543ebaf8b9762f0345495439fd9b91fcb6375c2 Mon Sep 17 00:00:00 2001 From: 18631081161 <2088094923@qq.com> Date: Sat, 28 Mar 2026 17:16:01 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=8A=E5=A4=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/src/layout/AdminLayout.vue | 6 +- admin/src/router/index.js | 6 + admin/src/views/ChatRecords.vue | 354 ++++++++++++++++++++++++++++ admin/src/views/Users.vue | 16 +- miniapp/pages/delivery/delivery.vue | 2 +- miniapp/pages/food/food-order.vue | 2 +- miniapp/pages/help/help.vue | 18 +- miniapp/pages/message/chat.vue | 46 +++- miniapp/pages/message/message.vue | 11 +- miniapp/pages/mine/mine.vue | 18 +- miniapp/pages/order/my-orders.vue | 24 +- miniapp/pages/order/my-taken.vue | 7 +- miniapp/pages/pickup/pickup.vue | 2 +- miniapp/pages/purchase/purchase.vue | 16 +- miniapp/utils/im.js | 26 +- server/Program.cs | 102 +++++++- server/Services/TencentIMService.cs | 35 ++- 17 files changed, 636 insertions(+), 55 deletions(-) create mode 100644 admin/src/views/ChatRecords.vue diff --git a/admin/src/layout/AdminLayout.vue b/admin/src/layout/AdminLayout.vue index ff2bc81..9675598 100644 --- a/admin/src/layout/AdminLayout.vue +++ b/admin/src/layout/AdminLayout.vue @@ -58,6 +58,10 @@ 提现管理 + + + 聊天记录 + 配置管理 @@ -99,7 +103,7 @@ import { ref } from 'vue' import { useRouter } from 'vue-router' import { ElMessageBox } from 'element-plus' -import { Monitor, Fold, Expand, ArrowDown, Picture, Grid, Shop, Stamp, User, UserFilled, Star, Bell, List, Setting, Money } from '@element-plus/icons-vue' +import { Monitor, Fold, Expand, ArrowDown, Picture, Grid, Shop, Stamp, User, UserFilled, Star, Bell, List, Setting, Money, ChatDotSquare } from '@element-plus/icons-vue' const router = useRouter() const isCollapse = ref(false) diff --git a/admin/src/router/index.js b/admin/src/router/index.js index a1c7f18..c5a437c 100644 --- a/admin/src/router/index.js +++ b/admin/src/router/index.js @@ -84,6 +84,12 @@ const routes = [ component: () => import('../views/Withdrawals.vue'), meta: { title: '提现管理' } }, + { + path: 'chat-records', + name: 'ChatRecords', + component: () => import('../views/ChatRecords.vue'), + meta: { title: '聊天记录' } + }, { path: 'config', name: 'Config', diff --git a/admin/src/views/ChatRecords.vue b/admin/src/views/ChatRecords.vue new file mode 100644 index 0000000..9d8d3ee --- /dev/null +++ b/admin/src/views/ChatRecords.vue @@ -0,0 +1,354 @@ + + + + 聊天记录 + + + + + + + + + 查询 + + + + + + + {{ typeLabel(row.orderType) }} + + + + {{ statusLabel(row.status) }} + + + + + + + {{ (row.ownerNickname || '?')[0] }} + + {{ row.ownerNickname }} + + + + + + + + {{ (row.runnerNickname || '?')[0] }} + + {{ row.runnerNickname }} + + + + + + {{ formatTime(row.createdAt) }} + + + + 查看聊天 + + + + + + + + 暂无聊天记录 + + + + {{ msg.timeLabel }} + + + + {{ msg.text }} + + + + + {{ (msg.nickname || '?')[0] }} + + + {{ msg.nickname }} + + + {{ msg.text }} + + + + + + + + + + + + + + + diff --git a/admin/src/views/Users.vue b/admin/src/views/Users.vue index e315eee..a1cf934 100644 --- a/admin/src/views/Users.vue +++ b/admin/src/views/Users.vue @@ -20,16 +20,17 @@ - + - + + + {{ (row.nickname || '?')[0] }} + + - - {{ row.phone || '-' }} - {{ getRoleLabel(row.role) }} @@ -103,12 +104,13 @@ async function toggleBan(row, isBanned) { } function getRoleLabel(role) { - const map = { User: '普通用户', Admin: '管理员' } + const map = { User: '普通用户', Runner: '跑腿', Admin: '管理员' } return map[role] || role } function getRoleType(role) { - return role === 'Admin' ? 'warning' : '' + const map = { Admin: 'warning', Runner: 'success' } + return map[role] || '' } function formatTime(str) { diff --git a/miniapp/pages/delivery/delivery.vue b/miniapp/pages/delivery/delivery.vue index 9a7cdbd..341d23a 100644 --- a/miniapp/pages/delivery/delivery.vue +++ b/miniapp/pages/delivery/delivery.vue @@ -178,7 +178,7 @@ export default { }) if (result.paymentParams) await this.wxPay(result.paymentParams) uni.showToast({ title: '下单成功', icon: 'success' }) - setTimeout(() => { uni.navigateBack() }, 1500) + setTimeout(() => { uni.switchTab({ url: '/pages/index/index' }) }, 1500) } catch (e) {} finally { this.submitting = false } }, wxPay(params) { diff --git a/miniapp/pages/food/food-order.vue b/miniapp/pages/food/food-order.vue index de1935d..af6dfae 100644 --- a/miniapp/pages/food/food-order.vue +++ b/miniapp/pages/food/food-order.vue @@ -182,7 +182,7 @@ export default { this.cartStore.clearCart() uni.showToast({ title: '下单成功', icon: 'success' }) setTimeout(() => { - uni.navigateBack({ delta: 2 }) + uni.switchTab({ url: '/pages/index/index' }) }, 1500) } catch (e) { // 错误已在 request 中处理 diff --git a/miniapp/pages/help/help.vue b/miniapp/pages/help/help.vue index e57b76b..3b0846f 100644 --- a/miniapp/pages/help/help.vue +++ b/miniapp/pages/help/help.vue @@ -50,7 +50,7 @@ 4.跑腿佣金 - 佣金先由平台保管,接单方完成订单后才会收到佣金 @@ -217,14 +217,14 @@ commission, totalAmount: goodsAmount + commission }) - if (result.paymentParams) await this.wxPay(result.paymentParams) - uni.showToast({ - title: '下单成功', - icon: 'success' - }) - setTimeout(() => { - uni.navigateBack() - }, 1500) + if (result.paymentParams) await this.wxPay(result.paymentParams) + uni.showToast({ + title: '下单成功', + icon: 'success' + }) + setTimeout(() => { + uni.switchTab({ url: '/pages/index/index' }) + }, 1500) } catch (e) {} finally { this.submitting = false } diff --git a/miniapp/pages/message/chat.vue b/miniapp/pages/message/chat.vue index 1bc3b69..b01abae 100644 --- a/miniapp/pages/message/chat.vue +++ b/miniapp/pages/message/chat.vue @@ -224,6 +224,7 @@ return { orderId: null, orderInfo: {}, + lastOrderStatus: null, chatMessages: [], inputText: '', scrollTop: 0, @@ -282,9 +283,10 @@ offNewMessage() }, onShow() { - // 如果 orderId 存在但 orderInfo 为空,重新加载 if (this.orderId && !this.orderInfo.id) { this.loadOrderInfo() + } else if (this.orderId && this.lastOrderStatus) { + this.checkOrderStatusChange() } }, methods: { @@ -297,6 +299,9 @@ const res = await getOrderDetail(this.orderId); console.log('[聊天] 订单详情:', res) this.orderInfo = res || {} + if (!this.lastOrderStatus) { + this.lastOrderStatus = this.orderInfo.status + } } catch (e) { console.error('[聊天] 加载订单详情失败:', e) } @@ -540,6 +545,45 @@ }) } }, + async checkOrderStatusChange() { + const oldStatus = this.lastOrderStatus + try { + await this.loadOrderInfo() + } catch (e) { + return + } + const newStatus = this.orderInfo.status + if (!oldStatus || oldStatus === newStatus) return + this.lastOrderStatus = newStatus + + const statusMessages = { + 'InProgress→WaitConfirm': '跑腿已提交完成,等待单主确认', + 'WaitConfirm→Completed': '单主已确认,订单已完成', + 'WaitConfirm→InProgress': '单主已拒绝完成,订单继续进行' + } + const key = `${oldStatus}→${newStatus}` + const msg = statusMessages[key] + if (!msg) return + + this.chatMessages.push({ + id: `sys_status_${Date.now()}`, + type: 'system', + content: msg + }) + this.scrollToBottom() + + if (this.imReady && this.targetImUserId) { + try { + await sendCustomMessage(this.targetImUserId, { + bizType: 'order-status', + action: key, + description: msg + }, this.orderId) + } catch (e) { + console.error('[聊天] 发送状态通知失败:', e) + } + } + }, onCompleteOrder() { this.showMorePanel = false uni.navigateTo({ diff --git a/miniapp/pages/message/message.vue b/miniapp/pages/message/message.vue index be7de8b..7907e52 100644 --- a/miniapp/pages/message/message.vue +++ b/miniapp/pages/message/message.vue @@ -55,7 +55,7 @@ - {{ item.targetNickname || '用户' }} + {{ displayNickname(item) }} {{ formatTime(item.lastTime) }} {{ getOrderLabel(item) }} @@ -152,6 +152,15 @@ export default { }) }, + /** 显示昵称,过滤掉 IM 用户ID 格式 */ + displayNickname(item) { + const nick = item.targetNickname + if (!nick || /^user_\d+$/.test(nick)) { + return item.targetUserId ? `用户${item.targetUserId}` : '用户' + } + return nick + }, + /** 获取订单摘要标签 */ getOrderLabel(item) { const typeMap = { Pickup: '代取', Delivery: '代送', Help: '万能帮', Purchase: '代购', Food: '美食街' } diff --git a/miniapp/pages/mine/mine.vue b/miniapp/pages/mine/mine.vue index e627592..5094929 100644 --- a/miniapp/pages/mine/mine.vue +++ b/miniapp/pages/mine/mine.vue @@ -25,12 +25,12 @@ - + 进行中 {{ stats.orderOngoing }} - + 已完成 {{ stats.orderCompleted }} @@ -44,12 +44,12 @@ - + 进行中 {{ stats.takenOngoing }} - + 已完成 {{ stats.takenCompleted }} @@ -149,8 +149,14 @@ export default { uni.navigateTo({ url: '/pages/login/login' }) } }, - goMyOrders() { uni.navigateTo({ url: '/pages/order/my-orders' }) }, - goMyTaken() { uni.navigateTo({ url: '/pages/order/my-taken' }) }, + goMyOrders(status) { + const query = status ? `?status=${status}` : '' + uni.navigateTo({ url: '/pages/order/my-orders' + query }) + }, + goMyTaken(status) { + const query = status ? `?status=${status}` : '' + uni.navigateTo({ url: '/pages/order/my-taken' + query }) + }, goQrcode() { uni.navigateTo({ url: '/pages/config/qrcode' }) }, goCertification() { uni.navigateTo({ url: '/pages/runner/certification' }) }, goEarnings() { uni.navigateTo({ url: '/pages/mine/earnings' }) }, diff --git a/miniapp/pages/order/my-orders.vue b/miniapp/pages/order/my-orders.vue index 8236946..a40363c 100644 --- a/miniapp/pages/order/my-orders.vue +++ b/miniapp/pages/order/my-orders.vue @@ -171,6 +171,7 @@