From a554fee36e01c06e1d0ed907506d61832a9c22ca Mon Sep 17 00:00:00 2001 From: yml2213 Date: Thu, 14 May 2026 21:17:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=A2=E5=8D=95=E5=88=97?= =?UTF-8?q?=E8=A1=A8ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/admin/AdminStatusTag.vue | 13 +- .../src/views/admin/AdminOrdersView.vue | 259 +++++++++++------- 2 files changed, 165 insertions(+), 107 deletions(-) diff --git a/apps/frontend/src/components/admin/AdminStatusTag.vue b/apps/frontend/src/components/admin/AdminStatusTag.vue index b036a90e..0b7abc63 100644 --- a/apps/frontend/src/components/admin/AdminStatusTag.vue +++ b/apps/frontend/src/components/admin/AdminStatusTag.vue @@ -1,9 +1,12 @@ diff --git a/apps/frontend/src/views/admin/AdminOrdersView.vue b/apps/frontend/src/views/admin/AdminOrdersView.vue index 53140d3d..d122c00c 100644 --- a/apps/frontend/src/views/admin/AdminOrdersView.vue +++ b/apps/frontend/src/views/admin/AdminOrdersView.vue @@ -13,8 +13,7 @@ const errorMessage = ref('') const platformOrderId = ref('') const payStatus = ref('') const skuCode = ref('') -const dateFrom = ref('') -const dateTo = ref('') +const dateRange = ref([]) const items = ref([]) const pagination = ref({ page: 1, @@ -26,6 +25,7 @@ const summary = computed(() => ({ paidCount: items.value.filter((item) => item.payStatus === 'paid').length, refundedCount: items.value.filter((item) => item.payStatus === 'refunded').length, bindingReadyCount: items.value.filter((item) => item.completedBindingTaskCount > 0).length, + issueCount: items.value.filter((item) => hasOrderIssue(item)).length, })) async function loadOrders(page = pagination.value.page) { @@ -39,8 +39,8 @@ async function loadOrders(page = pagination.value.page) { platformOrderId: platformOrderId.value.trim(), payStatus: payStatus.value.trim(), skuCode: skuCode.value.trim(), - dateFrom: dateFrom.value.trim(), - dateTo: dateTo.value.trim(), + dateFrom: dateRange.value[0] || '', + dateTo: dateRange.value[1] || '', }) items.value = response.data.items pagination.value = response.data.pagination @@ -55,8 +55,7 @@ function resetFilters() { platformOrderId.value = '' payStatus.value = '' skuCode.value = '' - dateFrom.value = '' - dateTo.value = '' + dateRange.value = [] void loadOrders(1) } @@ -85,6 +84,25 @@ function resolveBindingSummary(item: AdminOrderListItem) { return `共 ${item.totalBindingCount} 条 · 预占 ${item.reservedBindingCount} · 已消耗 ${item.consumedBindingCount} · 已释放 ${item.releasedBindingCount}` } +function hasOrderIssue(item: AdminOrderListItem) { + return ['refunded', 'failed', 'unpaid'].includes(item.payStatus) + || item.systemBindingStatus === 'binding_exception' + || item.userBindingStatus === 'binding_exception' +} + +function resolveFollowUpText(item: AdminOrderListItem) { + if (item.userBindingStatus === 'binding_exception' || item.systemBindingStatus === 'binding_exception') return '绑定异常' + if (item.completedBindingTaskCount <= 0) return '等待完整绑定' + if (item.systemBoundTaskCount < item.taskCount) return '系统绑定未完成' + return '链路正常' +} + +function resolveFollowUpTone(item: AdminOrderListItem) { + if (hasOrderIssue(item)) return 'danger' + if (item.completedBindingTaskCount <= 0 || item.systemBoundTaskCount < item.taskCount) return 'warning' + return 'success' +} + onMounted(loadOrders) @@ -104,11 +122,15 @@ onMounted(loadOrders) - - - -
- 订单信息、支付状态、绑定完成度和金额时间已拆成独立信息块,更方便排查。 +
重置 查询 @@ -117,22 +139,12 @@ onMounted(loadOrders) -
- - 当前页已支付 - {{ summary.paidCount }} - 已完成付款,可继续跟进交付 - - - 当前页已退款 - {{ summary.refundedCount }} - 需要重点确认订单状态和任务收口 - - - 当前页有完整绑定 - {{ summary.bindingReadyCount }} - 至少有 1 个任务已完成完整绑定 - +
+ 当前页 + 已支付 {{ summary.paidCount }} + 已退款 {{ summary.refundedCount }} + 完整绑定 {{ summary.bindingReadyCount }} + 需关注 {{ summary.issueCount }}
@@ -162,21 +174,23 @@ onMounted(loadOrders) 买家 {{ resolveBuyerLabel(item) }}
- +
+ + 详情 +
-
-
+
+
{{ resolveBuyerLabel(item) }} 联系方式 {{ resolveContactLabel(item) }} 店铺 {{ resolveShopLabel(item) }} - 更新时间 {{ formatAdminDateTime(item.updatedAt) }}
-
+
{{ resolveItemSummary(item) }} @@ -185,26 +199,27 @@ onMounted(loadOrders)
-
- +
+
- - - - + + + +
-
+
{{ item.totalAmount }} {{ item.currency }} 支付 {{ formatAdminDateTime(item.paidAt) }} 创建 {{ formatAdminDateTime(item.createdAt) }} + 更新 {{ formatAdminDateTime(item.updatedAt) }}
-
+
@@ -253,61 +268,55 @@ onMounted(loadOrders) .filter-grid { display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-template-columns: minmax(220px, 1.1fr) minmax(170px, 0.8fr) minmax(220px, 1fr) minmax(280px, 1.2fr) auto; gap: var(--space-3); -} - -.filter-actions { - display: flex; align-items: center; - justify-content: space-between; - gap: var(--space-3); - margin-top: var(--space-3); } -.filter-hint { color: var(--text-secondary); font-size: var(--text-xs); } +.date-range-filter { width: 100%; } .filter-buttons { display: flex; gap: 10px; flex-shrink: 0; } -.summary-grid { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: var(--space-3); +.summary-strip { + display: flex; + align-items: center; + gap: var(--space-2); + min-height: 46px; + padding: 8px 12px; margin-top: var(--space-4); + border: 1px solid var(--border-default); + border-radius: var(--radius-lg); + background: rgba(255, 255, 255, 0.74); + box-shadow: var(--shadow-sm); + flex-wrap: wrap; } -.summary-card { - position: relative; - overflow: hidden; -} - -.summary-card::after { - content: ''; - position: absolute; - inset: auto -26px -26px auto; - width: 96px; - height: 96px; - border-radius: var(--radius-full); - opacity: 0.14; -} - -.summary-card--success::after { background: var(--color-success); } -.summary-card--danger::after { background: var(--color-danger); } -.summary-card--primary::after { background: var(--color-primary); } - -.summary-label { +.summary-title { color: var(--text-secondary); font-size: var(--text-xs); font-weight: 700; - letter-spacing: 0.04em; + margin-right: 2px; } -.summary-value { - font-size: var(--text-3xl); - line-height: 1; - color: var(--text-primary); +.summary-metric { + display: inline-flex; + align-items: center; + gap: 5px; + min-height: 28px; + padding: 0 10px; + border-radius: var(--radius-full); + border: 1px solid transparent; + color: var(--text-secondary); + background: #f8fafc; + font-size: var(--text-xs); + font-weight: 700; } -.summary-meta { color: var(--text-muted); font-size: var(--text-xs); } +.summary-metric strong { color: var(--text-primary); font-size: var(--text-base); line-height: 1; } +.summary-metric[data-tone='success'] { color: var(--color-success-dark); background: var(--color-success-light); border-color: #bbf7d0; } +.summary-metric[data-tone='danger'] { color: var(--color-danger-dark); background: var(--color-danger-light); border-color: #fecaca; } +.summary-metric[data-tone='primary'] { color: var(--color-primary-dark); background: var(--color-primary-light); border-color: #bfdbfe; } +.summary-metric[data-tone='warning'] { color: var(--color-warning-dark); background: var(--color-warning-light); border-color: #fed7aa; } +.summary-metric[data-tone='muted'] { color: var(--text-secondary); background: #f8fafc; border-color: var(--border-default); } .table-card { margin-top: var(--space-4); overflow: visible; } @@ -319,16 +328,22 @@ onMounted(loadOrders) .order-card { display: grid; - gap: 14px; - padding: 14px; - border-radius: var(--radius-lg); - background: linear-gradient(180deg, rgba(248, 251, 255, 0.98) 0%, #ffffff 100%); + gap: 12px; + padding: 12px 14px; + border-radius: var(--radius-md); + background: rgba(255, 255, 255, 0.84); border: 1px solid var(--border-default); + transition: border-color 0.16s ease, box-shadow 0.16s ease; +} + +.order-card:hover { + border-color: var(--border-hover); + box-shadow: var(--shadow-sm); } .order-card-top { display: flex; - align-items: flex-start; + align-items: center; justify-content: space-between; gap: var(--space-3); } @@ -351,12 +366,35 @@ onMounted(loadOrders) .order-meta-row { display: flex; flex-wrap: wrap; gap: var(--space-2); } +.order-top-actions { + display: flex; + align-items: center; + gap: var(--space-2); + flex-shrink: 0; +} + +.detail-link { + display: inline-flex; + align-items: center; + min-height: 26px; + padding: 0 10px; + border-radius: var(--radius-full); + border: 1px solid var(--border-default); + color: var(--color-primary-dark); + background: var(--color-primary-light); + font-size: var(--text-xs); + font-weight: 700; + text-decoration: none; +} + +.detail-link:hover { border-color: var(--border-hover); background: #dbeafe; } + .compact-chip { display: inline-flex; align-items: center; - min-height: 28px; - max-width: 100%; - padding: 0 10px; + min-height: 24px; + max-width: 240px; + padding: 0 9px; border-radius: var(--radius-full); background: #f4f7fb; border: 1px solid var(--border-default); @@ -367,21 +405,21 @@ onMounted(loadOrders) .compact-chip--muted { color: var(--text-muted); } -.order-grid { +.order-row-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(205px, 1fr)); - gap: var(--space-3); + grid-template-columns: minmax(150px, 0.95fr) minmax(190px, 1.25fr) minmax(230px, 1.35fr) minmax(170px, 1fr) minmax(150px, 0.9fr); + column-gap: var(--space-4); + row-gap: var(--space-3); min-width: 0; + align-items: start; } -.order-section { +.order-field { display: grid; - gap: var(--space-2); + gap: 6px; min-width: 0; - padding: var(--space-3); - border-radius: 14px; - background: rgba(255, 255, 255, 0.78); - border: 1px solid var(--border-default); + padding-top: 10px; + border-top: 1px solid rgba(86, 108, 138, 0.1); } .section-label { @@ -398,14 +436,16 @@ onMounted(loadOrders) .amount-text { white-space: nowrap; } .status-stack { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; } +.status-stack :deep(.el-tag) { max-width: 100%; } .task-progress-inline { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); } -.progress-chip { +.progress-chip, +.follow-up-chip { display: inline-flex; align-items: center; - min-height: 28px; - padding: 0 10px; + min-height: 26px; + padding: 0 9px; border-radius: var(--radius-full); font-size: var(--text-xs); font-weight: 700; @@ -416,19 +456,30 @@ onMounted(loadOrders) .progress-chip[data-tone='success'] { color: #0f766e; background: var(--color-success-light); border-color: #a6f4c5; } .progress-chip[data-tone='primary'] { color: var(--color-primary-dark); background: var(--color-primary-light); border-color: #b2ddff; } .progress-chip[data-tone='warning'] { color: #b54708; background: var(--color-warning-light); border-color: #fedf89; } +.follow-up-chip[data-tone='success'] { color: #0f766e; background: var(--color-success-light); border-color: #a6f4c5; } +.follow-up-chip[data-tone='warning'] { color: #b54708; background: var(--color-warning-light); border-color: #fedf89; } +.follow-up-chip[data-tone='danger'] { color: var(--color-danger-dark); background: var(--color-danger-light); border-color: #fecaca; } -@media (max-width: 1200px) { .filter-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } } +@media (max-width: 1200px) { + .filter-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .date-range-filter { grid-column: span 2; } + .filter-buttons { justify-content: flex-end; } + .order-row-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } +} @media (max-width: 900px) { .filter-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .filter-actions { flex-direction: column; align-items: flex-start; } + .date-range-filter { grid-column: span 2; } + .filter-buttons { justify-content: flex-start; } + .order-row-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @media (max-width: 640px) { - .filter-grid, - .summary-grid { grid-template-columns: 1fr; } + .filter-grid { grid-template-columns: 1fr; } + .date-range-filter { grid-column: auto; } .filter-buttons { width: 100%; } .filter-buttons :deep(.el-button) { flex: 1 1 auto; } .order-card-top { flex-direction: column; align-items: flex-start; } + .order-top-actions { width: 100%; justify-content: space-between; } + .order-row-grid { grid-template-columns: 1fr; } .order-no { font-size: 18px; } }