From 10fa36198311b0492142a14f25fc48fbd68e0ebc Mon Sep 17 00:00:00 2001 From: jacy <18049821889@163.com> Date: Fri, 7 Aug 2026 13:25:55 +0800 Subject: [PATCH] feat(v3.4.15): admin delivery track drawer and mini-user store list polish Co-authored-by: Cursor --- .../src/components/OrderTrackDrawer.tsx | 185 ++++++++++++++++++ apps/admin-web/src/pages/DeliveriesPage.tsx | 63 +++++- apps/admin-web/src/pages/OrdersPage.tsx | 25 ++- apps/mini-user/package.json | 2 +- .../src/assets/icons/store-open-badge.png | Bin 0 -> 3167 bytes apps/mini-user/src/lib/client-version.ts | 2 +- apps/mini-user/src/pages/stores/index.tsx | 58 +++--- apps/mini-user/src/styles/stores.css | 129 ++++++------ .../system-config/system-config.registry.ts | 2 +- .../modules/ops/admin-orders.controller.ts | 6 + .../src/modules/ops/admin-orders.service.ts | 9 + 杜康好客-v3-PRD.md | 1 + 杜康好客-v3-现状对照.md | 2 + 杜康好客-v3.4.15-mini-user门店列表优化.md | 26 +++ 14 files changed, 404 insertions(+), 106 deletions(-) create mode 100644 apps/admin-web/src/components/OrderTrackDrawer.tsx create mode 100644 apps/mini-user/src/assets/icons/store-open-badge.png create mode 100644 杜康好客-v3.4.15-mini-user门店列表优化.md diff --git a/apps/admin-web/src/components/OrderTrackDrawer.tsx b/apps/admin-web/src/components/OrderTrackDrawer.tsx new file mode 100644 index 0000000..af37671 --- /dev/null +++ b/apps/admin-web/src/components/OrderTrackDrawer.tsx @@ -0,0 +1,185 @@ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { + Button, + Descriptions, + Drawer, + Empty, + Image, + Space, + Spin, + Timeline, + Typography, + message, +} from 'antd'; +import type { OrderTrackDto, OrderTrackNodeDto } from '@dukang/shared-types'; +import { isXfxProviderCode } from '@dukang/shared-types'; +import { request } from '../lib/api'; +import { DELIVERY_PROVIDER_LABELS, fmtTime } from '../lib/constants'; + +type Props = { + open: boolean; + orderId: string | null; + orderNo?: string | null; + orderStatus?: string | null; + onClose: () => void; +}; + +function providerLabel(provider?: string | null, company?: string | null) { + if (company) return company; + if (!provider) return '—'; + if (DELIVERY_PROVIDER_LABELS[provider]) return DELIVERY_PROVIDER_LABELS[provider]; + if (isXfxProviderCode(provider)) return '小飞侠'; + return provider; +} + +function sortOldestFirst(nodes: OrderTrackNodeDto[]) { + return [...nodes].sort((a, b) => { + const ta = new Date(a.createTime).getTime(); + const tb = new Date(b.createTime).getTime(); + if (Number.isNaN(ta) && Number.isNaN(tb)) return 0; + if (Number.isNaN(ta)) return 1; + if (Number.isNaN(tb)) return -1; + return ta - tb; + }); +} + +export default function OrderTrackDrawer({ + open, + orderId, + orderNo, + orderStatus, + onClose, +}: Props) { + const [loading, setLoading] = useState(false); + const [track, setTrack] = useState(null); + + const load = useCallback(async () => { + if (!orderId) return; + setLoading(true); + try { + const data = await request(`/admin/orders/${orderId}/track`); + setTrack(data); + } catch (e) { + setTrack(null); + message.error(e instanceof Error ? e.message : '加载路由失败'); + } finally { + setLoading(false); + } + }, [orderId]); + + useEffect(() => { + if (!open || !orderId) { + setTrack(null); + return; + } + void load(); + }, [open, orderId, load]); + + const nodes = useMemo( + () => (track?.nodes?.length ? sortOldestFirst(track.nodes) : []), + [track?.nodes], + ); + const timelineComplete = ['PENDING_RECEIVE', 'DELIVERED', 'COMPLETED'].includes( + orderStatus || '', + ); + + return ( + void load()} loading={loading} disabled={!orderId}> + 刷新 + + } + > + + {(orderNo || track?.trackingNo || track?.provider) && ( + + {orderNo ? {orderNo} : null} + + {providerLabel(track?.provider, track?.logisticsCompany)} + + {track?.trackingNo || '—'} + {track?.manualQueryUrl ? ( + + + 打开物流查询 + + + ) : null} + {track?.estimatedArrival?.arriveTime ? ( + + {fmtTime(track.estimatedArrival.arriveTime)} + {track.estimatedArrival.siteName + ? `(${track.estimatedArrival.siteName})` + : ''} + + ) : null} + + )} + + {track?.signPhotoUrls && track.signPhotoUrls.length > 0 ? ( +
+ + 签收照片 + + + + {track.signPhotoUrls.map((url) => ( + + ))} + + +
+ ) : null} + + + 物流动态 + + {nodes.length > 0 ? ( + { + const isLatest = index === nodes.length - 1; + return { + color: isLatest ? (timelineComplete ? 'green' : 'blue') : 'gray', + children: ( +
+ {node.statusName ? ( + + {node.statusName} + + ) : null} + + {node.trackInfo || '—'} + + + {fmtTime(node.createTime)} + +
+ ), + }; + })} + /> + ) : ( + + )} +
+
+ ); +} diff --git a/apps/admin-web/src/pages/DeliveriesPage.tsx b/apps/admin-web/src/pages/DeliveriesPage.tsx index a9ce9dc..75e11e2 100644 --- a/apps/admin-web/src/pages/DeliveriesPage.tsx +++ b/apps/admin-web/src/pages/DeliveriesPage.tsx @@ -3,13 +3,26 @@ import { Button, Descriptions, Drawer, Form, Input, Space, Table, Typography, message, } from 'antd'; import type { ColumnsType } from 'antd/es/table'; +import OrderTrackDrawer from '../components/OrderTrackDrawer'; import { request } from '../lib/api'; import { ORDER_STATUS_LABELS, fmtTime } from '../lib/constants'; import { useAdminList } from '../lib/useAdminList'; type Row = { - id: string; provider: string; trackingNo: string | null; providerOrderNo: string | null; updatedAt: string; - order?: { orderNo: string; status: string; receiverName: string; receiverPhone: string; deliveryType: string }; + id: string; + orderId: string; + provider: string; + trackingNo: string | null; + providerOrderNo: string | null; + updatedAt: string; + order?: { + id: string; + orderNo: string; + status: string; + receiverName: string; + receiverPhone: string; + deliveryType: string; + }; }; export default function DeliveriesPage() { @@ -29,6 +42,22 @@ export default function DeliveriesPage() { ); const [detail, setDetail] = useState(null); const [drawerOpen, setDrawerOpen] = useState(false); + const [trackOpen, setTrackOpen] = useState(false); + const [trackOrderId, setTrackOrderId] = useState(null); + const [trackOrderNo, setTrackOrderNo] = useState(null); + const [trackOrderStatus, setTrackOrderStatus] = useState(null); + + function openTrack(row: Row) { + const orderId = row.orderId || row.order?.id; + if (!orderId) { + message.warning('缺少关联订单,无法查询路由'); + return; + } + setTrackOrderId(orderId); + setTrackOrderNo(row.order?.orderNo ?? null); + setTrackOrderStatus(row.order?.status ?? null); + setTrackOpen(true); + } const columns: ColumnsType = [ { title: '订单号', dataIndex: ['order', 'orderNo'], width: 170 }, @@ -39,14 +68,17 @@ export default function DeliveriesPage() { { title: '收货人', dataIndex: ['order', 'receiverName'], width: 90 }, { title: '更新', dataIndex: 'updatedAt', width: 160, render: fmtTime }, { - title: '操作', width: 80, + title: '操作', width: 140, render: (_, row) => ( - + + + + ), }, ]; @@ -87,9 +119,22 @@ export default function DeliveriesPage() { + )} + setTrackOpen(false)} + /> ); } diff --git a/apps/admin-web/src/pages/OrdersPage.tsx b/apps/admin-web/src/pages/OrdersPage.tsx index 750ef83..20efeda 100644 --- a/apps/admin-web/src/pages/OrdersPage.tsx +++ b/apps/admin-web/src/pages/OrdersPage.tsx @@ -30,6 +30,7 @@ import { } from '../lib/constants'; import { FULFILLMENT_HOLD_REASON_LABELS } from '@dukang/shared-types'; import ProxyOrderModal from '../components/ProxyOrderModal'; +import OrderTrackDrawer from '../components/OrderTrackDrawer'; type ShipDefaults = { provider: string; @@ -186,6 +187,7 @@ export default function OrdersPage() { const [shipMode, setShipMode] = useState('EXPRESS'); const [warehouses, setWarehouses] = useState([]); const [proxyOpen, setProxyOpen] = useState(false); + const [trackOpen, setTrackOpen] = useState(false); const canDeleteOrders = (profile?.permissionKeys ?? []).includes('orders_delete'); const canProxyOrder = (profile?.permissionKeys ?? []).includes('orders'); @@ -859,7 +861,20 @@ export default function OrdersPage() { {detail.delivery && ( - + + 配送 + + + } + style={{ marginTop: 16 }} + > {detail.delivery.logisticsCompany || DELIVERY_PROVIDER_LABELS[detail.delivery.provider] || @@ -1232,6 +1247,14 @@ export default function OrdersPage() { void openDetail(order.id); }} /> + + setTrackOpen(false)} + /> ); } diff --git a/apps/mini-user/package.json b/apps/mini-user/package.json index fdce274..f547e24 100644 --- a/apps/mini-user/package.json +++ b/apps/mini-user/package.json @@ -1,6 +1,6 @@ { "name": "@dukang/mini-user", - "version": "3.4.14", + "version": "3.4.15", "private": true, "description": "杜康好客 · C 端用户微信小程序(Taro)", "scripts": { diff --git a/apps/mini-user/src/assets/icons/store-open-badge.png b/apps/mini-user/src/assets/icons/store-open-badge.png new file mode 100644 index 0000000000000000000000000000000000000000..b168b142eead5a8709085e9c5424059a6baee59e GIT binary patch literal 3167 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 D8ci*V literal 0 HcmV?d00001 diff --git a/apps/mini-user/src/lib/client-version.ts b/apps/mini-user/src/lib/client-version.ts index 1e83a3b..0b3b679 100644 --- a/apps/mini-user/src/lib/client-version.ts +++ b/apps/mini-user/src/lib/client-version.ts @@ -2,7 +2,7 @@ import Taro from '@tarojs/taro'; import { fetchClientConfig } from './pay-wechat'; /** 与 package.json version 同步,供服务端 minClientVersion 比对 */ -export const APP_VERSION = '3.4.14'; +export const APP_VERSION = '3.4.15'; export const APP_VERSION_LABEL = `v${APP_VERSION}`; diff --git a/apps/mini-user/src/pages/stores/index.tsx b/apps/mini-user/src/pages/stores/index.tsx index 5a52db0..d8657de 100644 --- a/apps/mini-user/src/pages/stores/index.tsx +++ b/apps/mini-user/src/pages/stores/index.tsx @@ -40,6 +40,7 @@ import { toWeappShareMessage, toWeappShareTimeline, } from '../../lib/wechat-share'; +import openBadgeImg from '../../assets/icons/store-open-badge.png'; type Store = { id: string; @@ -341,12 +342,12 @@ export default function StoresPage() { } } - function hoursLines(store: Store): string[] { + function hoursText(store: Store): string { const parts: string[] = []; if (store.openTime && store.closeTime) parts.push(`${store.openTime}-${store.closeTime}`); if (store.openTime2 && store.closeTime2) parts.push(`${store.openTime2}-${store.closeTime2}`); if (!parts.length) parts.push('10:00-22:00'); - return parts.map((p, i) => (i === 0 ? `营业时间: ${p}` : p)); + return `营业时间: ${parts.join(' ')}`; } const sharePayload = useMemo( @@ -421,45 +422,38 @@ export default function StoresPage() { className="store-card" onClick={() => Taro.navigateTo({ url: `/pages/store-detail/index?id=${s.id}` })} > - {s.coverUrl ? ( - - ) : ( - - )} + + {s.coverUrl ? ( + + ) : ( + + )} + + - {/* 第1行:标题 + 距离 */} + {/* 第1行:标题(截断无省略号,顶到最右) */} - - {s.name} + {s.name} + + {/* 第2行:地址(最多两行)+ 距离 */} + + + {s.address || (s.district ? `${s.district}` : '地址待完善')} {formatDistanceMeters(s.distanceMeters)} - {/* 第2行:营业时间(多段各占一行,居左) */} - - {hoursLines(s).map((line) => ( - - {line} - - ))} - - {/* 第3行:地址(最多两行)+ 去核销 */} - - - {s.address || (s.district ? `${s.district}` : '地址待完善')} - - { - e.stopPropagation(); - Taro.navigateTo({ url: '/pages/redeem/index' }); - }} - > - 去核销 - + {/* 第3行:营业时间(同行) */} + + {hoursText(s)} + ))} diff --git a/apps/mini-user/src/styles/stores.css b/apps/mini-user/src/styles/stores.css index 5a7497a..4be38b1 100644 --- a/apps/mini-user/src/styles/stores.css +++ b/apps/mini-user/src/styles/stores.css @@ -144,12 +144,12 @@ padding: 4px var(--space-page) 16px; } -/* 左图右文 */ +/* 左图 + 中间文案 + 右侧箭头 */ .store-card { display: flex; flex-direction: row; - align-items: flex-start; - gap: 12px; + align-items: center; + gap: 10px; padding: 12px; box-sizing: border-box; background: var(--color-card); @@ -158,11 +158,19 @@ margin-bottom: 12px; } -.store-card-cover { +.store-card-cover-wrap { + position: relative; flex-shrink: 0; width: 96px; height: 96px; border-radius: 8px; + overflow: hidden; +} + +.store-card-cover { + width: 100%; + height: 100%; + border-radius: 8px; background: var(--color-surface-container); display: block; } @@ -171,6 +179,16 @@ background: var(--color-surface-container); } +.store-card-open-badge { + position: absolute; + top: 0; + right: 0; + width: 44px; + height: 44px; + pointer-events: none; + z-index: 1; +} + .store-card-body { flex: 1; min-width: 0; @@ -184,19 +202,19 @@ .store-card-row { display: flex; - align-items: center; + align-items: flex-start; min-width: 0; overflow: hidden; } -/* 第1行:加粗标题(单行截断)+ 右对齐距离 */ +/* 第1行:加粗标题(单行截断,不显示 …,宽度顶到最右) */ .store-card-row--head { - gap: 8px; height: 22px; + align-items: center; } .store-card-name { - flex: 1; + width: 100%; min-width: 0; font-family: var(--font-headline); font-size: 15px; @@ -204,53 +222,23 @@ line-height: 22px; color: #1a1a1a; overflow: hidden; - text-overflow: ellipsis; + text-overflow: clip; white-space: nowrap; } -.store-card-distance { - flex-shrink: 0; - max-width: 40%; - font-size: 12px; - font-weight: 400; - line-height: 22px; - color: #999; - text-align: right; - white-space: nowrap; -} - -/* 第2行:营业时间独自居左;多段各占一行 */ -.store-card-hours { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 2px; - min-width: 0; -} - -.store-card-hours-line { - font-size: 11px; - font-weight: 400; - line-height: 16px; - color: #999; - text-align: left; -} - -/* 第3行:地址最多两行截断 + 右对齐去核销;与按钮垂直居中 */ -.store-card-row--foot { +/* 第2行:地址最多两行 + 右对齐距离 */ +.store-card-row--mid { gap: 8px; - min-height: 28px; - align-items: center; - overflow: visible; + align-items: flex-start; } .store-card-address { flex: 1; min-width: 0; - font-size: 9px; + font-size: 11px; font-weight: 400; - line-height: 14px; - max-height: 28px; + line-height: 16px; + max-height: 32px; color: #999; text-align: left; white-space: normal; @@ -260,25 +248,44 @@ -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; - text-overflow: ellipsis; } -.store-card-cta { +.store-card-distance { flex-shrink: 0; - display: flex; - align-items: center; - justify-content: center; - padding: 0 14px; - height: 26px; - border-radius: 999px; - background: var(--color-heritage-red, #a61d24); - box-sizing: border-box; -} - -.store-card-cta-text { + max-width: 40%; + padding-top: 1px; font-size: 12px; - font-weight: 600; - line-height: 26px; - color: #fff; + font-weight: 400; + line-height: 16px; + color: #999; + text-align: right; white-space: nowrap; } + +/* 第3行:营业时间同行 */ +.store-card-row--hours { + align-items: center; +} + +.store-card-hours { + width: 100%; + min-width: 0; + font-size: 11px; + font-weight: 400; + line-height: 16px; + color: #999; + overflow: hidden; + text-overflow: clip; + white-space: nowrap; +} + +.store-card-arrow { + flex-shrink: 0; + align-self: center; + width: 16px; + font-size: 20px; + font-weight: 300; + line-height: 1; + color: #ccc; + text-align: center; +} diff --git a/server/dukang-api/src/common/system-config/system-config.registry.ts b/server/dukang-api/src/common/system-config/system-config.registry.ts index 11f2ad9..6bd424b 100644 --- a/server/dukang-api/src/common/system-config/system-config.registry.ts +++ b/server/dukang-api/src/common/system-config/system-config.registry.ts @@ -142,7 +142,7 @@ export const SYSTEM_CONFIG_FIELDS: SystemConfigFieldMeta[] = [ group: G.wechat_mini, type: 'string', requiresRestart: false, - placeholder: '3.4.14', + placeholder: '3.4.15', description: 'semver 格式;客户端低于此版本时提示更新', }, { diff --git a/server/dukang-api/src/modules/ops/admin-orders.controller.ts b/server/dukang-api/src/modules/ops/admin-orders.controller.ts index cc8d729..6364143 100644 --- a/server/dukang-api/src/modules/ops/admin-orders.controller.ts +++ b/server/dukang-api/src/modules/ops/admin-orders.controller.ts @@ -38,6 +38,12 @@ export class AdminOrdersController { return this.ordersService.getShipDefaults(); } + /** 物流路由(小飞侠实时轨迹,对齐 C 端 GET /trade/orders/:id/track) */ + @Get(':id/track') + track(@Param('id') id: string) { + return this.ordersService.getOrderTrack(BigInt(id)); + } + @Get(':id') detail(@Param('id') id: string) { return this.ordersService.detail(BigInt(id)); diff --git a/server/dukang-api/src/modules/ops/admin-orders.service.ts b/server/dukang-api/src/modules/ops/admin-orders.service.ts index 51cc7f1..f7bc2f9 100644 --- a/server/dukang-api/src/modules/ops/admin-orders.service.ts +++ b/server/dukang-api/src/modules/ops/admin-orders.service.ts @@ -63,6 +63,15 @@ export class AdminOrdersService { return serializeBigInt({ items, total, page, pageSize }); } + async getOrderTrack(id: bigint) { + const order = await this.prisma.order.findUnique({ + where: { id }, + select: { id: true }, + }); + if (!order) throw new NotFoundException('订单不存在'); + return serializeBigInt(await this.fulfillmentService.getOrderTrack(id)); + } + async detail(id: bigint) { const order = await this.prisma.order.findUnique({ where: { id }, diff --git a/杜康好客-v3-PRD.md b/杜康好客-v3-PRD.md index 1f47a55..557ef51 100644 --- a/杜康好客-v3-PRD.md +++ b/杜康好客-v3-PRD.md @@ -20,6 +20,7 @@ | 3.4.12 | 08-04 | 退款回滚/财务/批量任务·工单/套餐 imageUrl | [`v3.4.12`](./杜康好客-v3.4.12-工单迭代开发文档.md) | | 3.4.13 | 08-05 | metrics/核销详情/版本联动 PUBLISHED/mini 体验/H5 OAuth | [`v3.4.13`](./杜康好客-v3.4.13-体验优化开发文档.md) | | 3.4.14 | 08-06 | mini-user 门头/套餐详情;**微信小程序配置可配 Logo·客服·H5·Mock码** | [`v3.4.14`](./杜康好客-v3.4.14-mini-user门店体验开发文档.md) | +| 3.4.15 | 08-06 | mini-user 门店列表卡片:去核销改箭头、地址/距离/营业时间重排、营业中角标 | [`v3.4.15`](./杜康好客-v3.4.15-mini-user门店列表优化.md) | --- diff --git a/杜康好客-v3-现状对照.md b/杜康好客-v3-现状对照.md index d2541d9..77500a8 100644 --- a/杜康好客-v3-现状对照.md +++ b/杜康好客-v3-现状对照.md @@ -56,11 +56,13 @@ | 3.4.12 | [`工单迭代`](./杜康好客-v3.4.12-工单迭代开发文档.md) | ✅ | | 3.4.13 | [`体验优化`](./杜康好客-v3.4.13-体验优化开发文档.md) | ✅ 生产 | | 3.4.14 | [`mini-user 门店体验 + 小程序可配置`](./杜康好客-v3.4.14-mini-user门店体验开发文档.md) | 🔶 开发中 | +| 3.4.15 | [`mini-user 门店列表优化`](./杜康好客-v3.4.15-mini-user门店列表优化.md) | 🔶 开发中 | ## 5. 变更记录 | 日期 | 说明 | |------|------| +| 2026-08-06 | v3.4.15 mini-user 门店列表卡片优化(开发中) | | 2026-08-06 | v3.4.14 mini-user 门头/套餐详情(开发中) | | 2026-08-05 | v3.4.13 | | 2026-08-04 | v3.4.11 / v3.4.12 | diff --git a/杜康好客-v3.4.15-mini-user门店列表优化.md b/杜康好客-v3.4.15-mini-user门店列表优化.md new file mode 100644 index 0000000..252070e --- /dev/null +++ b/杜康好客-v3.4.15-mini-user门店列表优化.md @@ -0,0 +1,26 @@ +# 杜康好客 · v3.4.15 mini-user 门店列表卡片优化 + +> **2026-08-06** · **开发中** · mini-user `3.4.15` · **未发版** + +## 更新内容 + +- 门店列表卡片去掉「去核销」按钮,整卡最右侧改为小箭头(进入详情) +- 第 1 行:门店名单行截断(不显示省略号),宽度顶到文案区最右 +- 第 2 行:地址最多两行;右侧显示距离 +- 第 3 行:营业时间同行展示(多段时段空格拼接) +- 店铺封面右上角叠加斜角「营业中」标签图 + +## 范围 + +| 项 | 交付 | +|----|------| +| 门店列表卡片 | 布局与交互如上 | +| 版本号 | `mini-user` `3.4.15`(`APP_VERSION` / package.json) | + +## ACC + +- [ ] 列表项无「去核销」按钮;右侧有 › 箭头;点击整卡进详情 +- [ ] 长店名单行截断且无 `…`;标题行无距离 +- [ ] 地址 ≤2 行,距离在第二行右侧 +- [ ] 营业时间单行;双时段同行显示 +- [ ] 封面右上角可见「营业中」斜角标签