diff --git a/AGENTS.md b/AGENTS.md index d4655cf..1cbfbe0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ - 本项目是入驻企业及其成员使用的客户工作台,所有业务数据都处于企业租户上下文中。 - 当前范围包括注册、业务总览、企业资料、企业成员、企业角色与权限、头程订单、客户资金账户、客户财务账单查询与客户确认,以及海外仓贴标、转运、废弃和退货换标自助服务。 -- 用户可见的“平台—客户”层级语义读取 `../../docs/平台客户层级与权限契约.md`;涉及海外 API、海外 Token 或跨区域事件时读取 `../../docs/统一认证与服务通信契约.md`。本文件中的 `tenant` 仅表示服务端隔离上下文,不扩展用户可见产品层级。 +- 用户可见的“平台—客户”层级语义读取 `../../docs/平台客户层级与权限契约.md`;涉及统一 API、Token、会话撤销或可靠事件时按需读取 `../../docs/统一认证与服务通信契约.md` 对应章节。本文件中的 `tenant` 仅表示服务端隔离上下文,不扩展用户可见产品层级。 - 不在本项目实现平台内部运营管理、品牌官网、仓库 PDA 作业或仅属于原生移动端的能力。 ## 技术基线 diff --git a/src/modules/dashboard/views/DashboardView.vue b/src/modules/dashboard/views/DashboardView.vue index 4884d89..21d97b3 100644 --- a/src/modules/dashboard/views/DashboardView.vue +++ b/src/modules/dashboard/views/DashboardView.vue @@ -1,6 +1,6 @@ @@ -28,7 +30,7 @@ const primaryActions = computed(() => [ {{ action.title }}{{ action.description }} - 开始下单 + {{ action.actionLabel ?? '开始下单' }}

当前账号暂无常用业务权限,请通过已授权菜单办理业务,或联系企业管理员。

@@ -46,7 +48,7 @@ const primaryActions = computed(() => [ .business-intro { padding-top: 0; } .business-intro h1 { margin: 0; color: #172033; font-size: 27px; font-weight: 750; letter-spacing: -.5px; line-height: 1.3; } .business-intro p { margin: 5px 0 0; color: #7a8495; font-size: 13px; line-height: 1.55; } -.quick-actions { display: grid; grid-template-columns: repeat(6, minmax(188px, 1fr)); gap: 10px; overflow-x: auto; padding: 0 0 6px; scroll-snap-type: x proximity; scrollbar-color: #bdc9dc transparent; scrollbar-width: thin; } +.quick-actions { display: grid; grid-template-columns: repeat(8, minmax(150px, 1fr)); gap: 10px; overflow-x: auto; padding: 0 0 6px; scroll-snap-type: x proximity; scrollbar-color: #bdc9dc transparent; scrollbar-width: thin; } .quick-actions::-webkit-scrollbar { height: 7px; } .quick-actions::-webkit-scrollbar-thumb { border-radius: 999px; background: #bdc9dc; } .quick-actions::-webkit-scrollbar-track { background: transparent; } @@ -60,6 +62,8 @@ const primaryActions = computed(() => [ .quick-action--cyan { --action-a: #0891b2; --action-b: #0e7490; --action-soft: rgba(8, 145, 178, .18); } .quick-action--orange { --action-a: #f59e0b; --action-b: #dc6b12; --action-soft: rgba(245, 158, 11, .2); } .quick-action--rose { --action-a: #e11d48; --action-b: #be185d; --action-soft: rgba(225, 29, 72, .17); } +.quick-action--teal { --action-a: #0f766e; --action-b: #0e7490; --action-soft: rgba(15, 118, 110, .18); } +.quick-action--brown { --action-a: #b45309; --action-b: #c2410c; --action-soft: rgba(180, 83, 9, .18); } .quick-action:hover { border-color: color-mix(in srgb, var(--action-a) 35%, transparent); box-shadow: 0 24px 54px rgba(15, 23, 42, .14), 0 0 0 1px color-mix(in srgb, var(--action-a) 16%, transparent); transform: translateY(-9px); } .quick-action:hover::before { transform: scale(1.25); } .quick-action:hover::after { right: 12%; left: 12%; opacity: 1; transform: scaleX(1); } @@ -93,8 +97,8 @@ const primaryActions = computed(() => [ @keyframes action-enter { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: translateY(0); } } @keyframes featured-aura { 0%, 100% { opacity: .86; transform: translate3d(0, 0, 0) scale(1); } 50% { opacity: 1; transform: translate3d(-10px, 9px, 0) scale(1.08); } } @keyframes featured-shine { 0%, 55% { left: -55%; opacity: 0; } 65% { opacity: 1; } 88%, 100% { left: 125%; opacity: 0; } } -@container dashboard-content (max-width: 1180px) { .quick-actions { grid-template-columns: repeat(6, minmax(178px, 1fr)); } } +@container dashboard-content (max-width: 1180px) { .quick-actions { grid-template-columns: repeat(8, minmax(178px, 1fr)); } } @media (max-width: 720px) { .client-dashboard { padding: 0; gap: 16px; } .business-intro h1 { font-size: 25px; } .quick-actions { grid-template-columns: repeat(2, minmax(150px, 1fr)); } } -@media (max-width: 420px) { .quick-actions { grid-template-columns: repeat(6, minmax(168px, 1fr)); } } +@media (max-width: 420px) { .quick-actions { grid-template-columns: repeat(8, minmax(168px, 1fr)); } } @media (prefers-reduced-motion: reduce) { .client-dashboard, .quick-action, .quick-action--featured::before, .quick-action--featured .action-enter::before { animation: none; } .quick-action, .quick-action::before, .quick-action::after, .action-icon, .action-enter svg { transition: none; } } diff --git a/src/modules/overseas-warehouse/api/returnInventory.ts b/src/modules/overseas-warehouse/api/returnInventory.ts index 440900d..f0d9415 100644 --- a/src/modules/overseas-warehouse/api/returnInventory.ts +++ b/src/modules/overseas-warehouse/api/returnInventory.ts @@ -54,6 +54,11 @@ export interface ReturnPackingPreview { skus: Array<{ skuCode: string; productNameZh?: string; availableQuantity: number }> } +export interface ReturnPackingPlan { + planNo: string; customerId: string; overseasWarehouseId: string; returnNos: string[]; mode: string; status: string + boxes: Array<{ boxNo?: number; items: Array<{ skuCode: string; quantity: number }>; length: number; width: number; height: number; weight: number }>; remark?: string +} + export function getReturnPackingPreview(returnNo?: string) { return apiRequest({ method: 'GET', url: '/pda/v1/last-leg/return-inventory/packing/orders', params: { returnNo: returnNo || undefined } }) } @@ -66,3 +71,11 @@ export function mergeReturnInventory(payload: { method: 'POST', url: '/pda/v1/last-leg/return-inventory/cartons/merge', data: payload, }) } + +export function listReturnPackingPlans(params: Record = {}) { + return apiRequest>({ method: 'GET', url: '/merchant/v1/last-leg/return-packing-plans', params }) +} + +export function createReturnPackingPlan(payload: { returnNos: string[]; mode: string; boxes: ReturnPackingPlan['boxes']; remark?: string; idempotencyKey: string }) { + return apiRequest({ method: 'POST', url: '/merchant/v1/last-leg/return-packing-plans', data: payload }) +} diff --git a/src/modules/overseas-warehouse/api/returnOrders.ts b/src/modules/overseas-warehouse/api/returnOrders.ts index c8b7233..e6cda49 100644 --- a/src/modules/overseas-warehouse/api/returnOrders.ts +++ b/src/modules/overseas-warehouse/api/returnOrders.ts @@ -14,10 +14,12 @@ export interface ReturnReceipt { receivedQuantity: number; operatorName?: string; signedAt: string; unitType: 'PALLET' | 'BOX' | 'PARCEL'; unitCode?: string; boxCount: number items: Array<{ skuCode: string; productNameZh?: string; quantity: number; boxCount: number }>; cartonMark?: string; printableHtml?: string labels?: Array<{ cartonMark: string; printableHtml: string }> + labelRepairRequired?: boolean } export interface ReturnPallet { palletCode: string; unitType: 'PALLET' | 'BOX'; unitCode: string; skuTypes: number; totalQuantity: number; totalBoxCount: number; items: Array<{ skuCode: string; productNameZh?: string; quantity: number; boxCount: number }> } export interface ReturnPhoto { fileId: number; fileName: string; contentType: string; sizeBytes: number } -export interface ReturnOrderDetail { order: ReturnOrderSummary; remark?: string; items: ReturnOrderItem[]; receipts: ReturnReceipt[]; pallets: ReturnPallet[]; photos: ReturnPhoto[] } +export interface ReturnPackingDetail { sourceCartonMark: string; targetCartonMark: string; returnNo: string; skuCode: string; quantity: number; createdAt: string } +export interface ReturnOrderDetail { order: ReturnOrderSummary; remark?: string; items: ReturnOrderItem[]; receipts: ReturnReceipt[]; pallets: ReturnPallet[]; photos: ReturnPhoto[]; packingDetails?: ReturnPackingDetail[] } export interface ReturnOrderCreate { overseasWarehouseId: string; warehouseContactName: string; warehouseContactPhone: string; customerReferenceNo?: string; remark?: string; needRelabel: boolean; idempotencyKey: string items: Array<{ skuCode: string; productNameZh?: string; expectedQuantity: number }> diff --git a/src/modules/overseas-warehouse/views/ReturnInventoryView.vue b/src/modules/overseas-warehouse/views/ReturnInventoryView.vue index f82c6e1..d506bce 100644 --- a/src/modules/overseas-warehouse/views/ReturnInventoryView.vue +++ b/src/modules/overseas-warehouse/views/ReturnInventoryView.vue @@ -1,12 +1,13 @@