优化了订单展示
This commit is contained in:
@@ -80,16 +80,25 @@ export interface AdminDashboardSummary {
|
||||
|
||||
export interface AdminOrderListItem {
|
||||
orderId: number
|
||||
provider: string
|
||||
platform: string
|
||||
shopId: string
|
||||
shopName: string
|
||||
platformOrderId: string
|
||||
orderStatus: string
|
||||
payStatus: string
|
||||
buyerId: string
|
||||
buyerName: string
|
||||
receiverContact: string
|
||||
totalAmount: string
|
||||
totalAmountFen: number
|
||||
currency: string
|
||||
paidAt: string | null
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
itemCount: number
|
||||
totalQuantity: number
|
||||
itemSummary: string
|
||||
taskCount: number
|
||||
systemBindingStatus: string
|
||||
userBindingStatus: string
|
||||
@@ -139,7 +148,10 @@ export interface AdminTaskActionResponse {
|
||||
export interface AdminOrderDetail {
|
||||
order: {
|
||||
orderId: number
|
||||
provider: string
|
||||
platform: string
|
||||
shopId: string
|
||||
shopName: string
|
||||
platformOrderId: string
|
||||
orderStatus: string
|
||||
payStatus: string
|
||||
@@ -187,7 +199,10 @@ export interface AdminOrderDetail {
|
||||
}>
|
||||
webhookEvents: Array<{
|
||||
eventId: number
|
||||
provider: string
|
||||
platform: string
|
||||
shopId: string
|
||||
shopName: string
|
||||
eventType: string
|
||||
eventKey: string
|
||||
signatureValid: boolean
|
||||
|
||||
@@ -23,6 +23,19 @@ onMounted(async () => {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
|
||||
function formatJsonBlock(value: Record<string, unknown>) {
|
||||
return JSON.stringify(value || {}, null, 2)
|
||||
}
|
||||
|
||||
function formatSpecSummary(spec: Record<string, unknown>) {
|
||||
const entries = Object.entries(spec || {})
|
||||
.filter(([, value]) => value !== null && value !== undefined && String(value).trim() !== '')
|
||||
.slice(0, 4)
|
||||
.map(([key, value]) => `${key}: ${String(value)}`)
|
||||
|
||||
return entries.length > 0 ? entries.join(' | ') : '-'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -39,16 +52,49 @@ onMounted(async () => {
|
||||
|
||||
<template v-else-if="detail">
|
||||
<section class="info-card">
|
||||
<h2>{{ detail.order.platformOrderId }}</h2>
|
||||
<p>支付状态:<AdminStatusTag :status="detail.order.payStatus" /> · 订单状态:<AdminStatusTag :status="detail.order.orderStatus" /></p>
|
||||
<p>
|
||||
系统绑定:<AdminStatusTag :status="detail.order.bindingSummary.systemBindingStatus" />
|
||||
· 完整绑定:<AdminStatusTag :status="detail.order.bindingSummary.userBindingStatus" />
|
||||
</p>
|
||||
<p>
|
||||
任务进度:{{ detail.order.bindingSummary.completedBindingTaskCount }}/{{ detail.order.bindingSummary.totalTaskCount }} 完整绑定
|
||||
· {{ detail.order.bindingSummary.systemBoundTaskCount }}/{{ detail.order.bindingSummary.totalTaskCount }} 系统绑定
|
||||
</p>
|
||||
<div class="info-card-header">
|
||||
<div>
|
||||
<h2>{{ detail.order.platformOrderId }}</h2>
|
||||
<p class="subtitle">{{ detail.order.platform }} / {{ detail.order.shopName || detail.order.shopId || '未识别店铺' }}</p>
|
||||
</div>
|
||||
<div class="status-stack">
|
||||
<AdminStatusTag :status="detail.order.payStatus" />
|
||||
<AdminStatusTag :status="detail.order.orderStatus" />
|
||||
<AdminStatusTag :status="detail.order.bindingSummary.systemBindingStatus" />
|
||||
<AdminStatusTag :status="detail.order.bindingSummary.userBindingStatus" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-grid">
|
||||
<article class="info-tile">
|
||||
<span>订单金额</span>
|
||||
<strong>{{ detail.order.totalAmount }} {{ detail.order.currency }}</strong>
|
||||
<small>支付时间:{{ formatAdminDateTime(detail.order.paidAt) }}</small>
|
||||
</article>
|
||||
<article class="info-tile">
|
||||
<span>买家信息</span>
|
||||
<strong>{{ detail.order.buyerName || '-' }}</strong>
|
||||
<small>ID:{{ detail.order.buyerId || '-' }}</small>
|
||||
</article>
|
||||
<article class="info-tile">
|
||||
<span>联系方式</span>
|
||||
<strong>{{ detail.order.receiverContact || '-' }}</strong>
|
||||
<small>店铺:{{ detail.order.shopName || detail.order.shopId || '-' }}</small>
|
||||
</article>
|
||||
<article class="info-tile">
|
||||
<span>任务进度</span>
|
||||
<strong>{{ detail.order.bindingSummary.completedBindingTaskCount }}/{{ detail.order.bindingSummary.totalTaskCount }} 完整绑定</strong>
|
||||
<small>{{ detail.order.bindingSummary.systemBoundTaskCount }}/{{ detail.order.bindingSummary.totalTaskCount }} 系统绑定</small>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<table class="meta-table">
|
||||
<tbody>
|
||||
<tr><th>内部订单 ID</th><td>{{ detail.order.orderId }}</td><th>提供方</th><td>{{ detail.order.provider }}</td></tr>
|
||||
<tr><th>平台</th><td>{{ detail.order.platform }}</td><th>店铺 ID</th><td>{{ detail.order.shopId || '-' }}</td></tr>
|
||||
<tr><th>创建时间</th><td>{{ formatAdminDateTime(detail.order.createdAt) }}</td><th>更新时间</th><td>{{ formatAdminDateTime(detail.order.updatedAt) }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="table-card">
|
||||
@@ -58,14 +104,18 @@ onMounted(async () => {
|
||||
<tr>
|
||||
<th>SKU</th>
|
||||
<th>商品</th>
|
||||
<th>发放方式</th>
|
||||
<th>数量</th>
|
||||
<th>规格摘要</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in detail.items" :key="item.orderItemId">
|
||||
<td>{{ item.skuCode }}</td>
|
||||
<td>{{ item.skuName }}</td>
|
||||
<td>{{ item.deliveryMode }}</td>
|
||||
<td>{{ item.quantity }}</td>
|
||||
<td>{{ formatSpecSummary(item.spec) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -80,6 +130,7 @@ onMounted(async () => {
|
||||
<th>状态</th>
|
||||
<th>系统绑定</th>
|
||||
<th>完整绑定</th>
|
||||
<th>登录方式</th>
|
||||
<th>错误</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -91,6 +142,7 @@ onMounted(async () => {
|
||||
<td><AdminStatusTag :status="task.status" /></td>
|
||||
<td><AdminStatusTag :status="task.systemBindingStatus" /></td>
|
||||
<td><AdminStatusTag :status="task.userBindingStatus" /></td>
|
||||
<td>{{ task.loginType || '-' }}</td>
|
||||
<td>{{ task.lastError || '-' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -104,6 +156,7 @@ onMounted(async () => {
|
||||
<tr>
|
||||
<th>事件 ID</th>
|
||||
<th>类型</th>
|
||||
<th>平台 / 店铺</th>
|
||||
<th>验签</th>
|
||||
<th>处理</th>
|
||||
<th>时间</th>
|
||||
@@ -115,16 +168,25 @@ onMounted(async () => {
|
||||
<RouterLink :to="`/admin/webhook-events/${event.eventId}`">{{ event.eventId }}</RouterLink>
|
||||
</td>
|
||||
<td>{{ formatAdminWebhookEventType(event.eventType) }}</td>
|
||||
<td>{{ event.platform }} / {{ event.shopName || event.shopId || '-' }}</td>
|
||||
<td><AdminStatusTag :status="event.signatureValid ? 'success' : 'failed'" /></td>
|
||||
<td><AdminStatusTag :status="event.processed ? 'success' : 'failed'" /></td>
|
||||
<td>{{ formatAdminDateTime(event.createdAt) }}</td>
|
||||
</tr>
|
||||
<tr v-if="detail.webhookEvents.length === 0">
|
||||
<td colspan="5">当前订单还没有关联的 webhook 记录。</td>
|
||||
<td colspan="6">当前订单还没有关联的 webhook 记录。</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="table-card">
|
||||
<h3>原始载荷</h3>
|
||||
<details class="payload-box">
|
||||
<summary>展开查看原始订单 JSON</summary>
|
||||
<pre>{{ formatJsonBlock(detail.order.rawPayload) }}</pre>
|
||||
</details>
|
||||
</section>
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
@@ -137,6 +199,85 @@ onMounted(async () => {
|
||||
padding: 18px; border-radius: 20px; background: rgba(255,255,255,.94); border: 1px solid rgba(86,108,138,.1);
|
||||
}
|
||||
.error-copy { color: #b42318; }
|
||||
.info-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.info-card-header h2 {
|
||||
margin: 0;
|
||||
color: #1d3555;
|
||||
}
|
||||
.subtitle {
|
||||
margin: 8px 0 0;
|
||||
color: #64748b;
|
||||
}
|
||||
.status-stack {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.info-tile {
|
||||
padding: 14px 16px;
|
||||
border-radius: 16px;
|
||||
background: linear-gradient(180deg, rgba(247, 250, 255, 0.98), rgba(241, 245, 249, 0.92));
|
||||
border: 1px solid rgba(86,108,138,.08);
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
.info-tile span,
|
||||
.info-tile small {
|
||||
color: #64748b;
|
||||
}
|
||||
.info-tile strong {
|
||||
color: #1d3555;
|
||||
}
|
||||
.meta-table,
|
||||
.data-table { width: 100%; border-collapse: collapse; }
|
||||
.data-table th,.data-table td { padding: 12px 10px; text-align: left; border-bottom: 1px solid rgba(86,108,138,.08); }
|
||||
.meta-table th,
|
||||
.meta-table td,
|
||||
.data-table th,
|
||||
.data-table td { padding: 12px 10px; text-align: left; border-bottom: 1px solid rgba(86,108,138,.08); }
|
||||
.meta-table th,
|
||||
.data-table th { color: #64748b; width: 120px; }
|
||||
.payload-box summary {
|
||||
cursor: pointer;
|
||||
color: #1d4ed8;
|
||||
font-weight: 600;
|
||||
}
|
||||
.payload-box pre {
|
||||
margin: 12px 0 0;
|
||||
padding: 14px;
|
||||
overflow: auto;
|
||||
border-radius: 16px;
|
||||
background: #0f172a;
|
||||
color: #dbeafe;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.info-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.info-card-header {
|
||||
flex-direction: column;
|
||||
}
|
||||
.status-stack {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.info-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -46,6 +46,22 @@ async function loadOrders(page = pagination.value.page) {
|
||||
}
|
||||
|
||||
onMounted(loadOrders)
|
||||
|
||||
function resolveBuyerLabel(item: AdminOrderListItem) {
|
||||
return item.buyerName || item.buyerId || '未识别'
|
||||
}
|
||||
|
||||
function resolveContactLabel(item: AdminOrderListItem) {
|
||||
return item.receiverContact || '未提供'
|
||||
}
|
||||
|
||||
function resolveShopLabel(item: AdminOrderListItem) {
|
||||
return item.shopName || item.shopId || '未识别店铺'
|
||||
}
|
||||
|
||||
function resolveItemSummary(item: AdminOrderListItem) {
|
||||
return item.itemSummary || '未识别商品'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -80,20 +96,35 @@ onMounted(loadOrders)
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>订单号</th>
|
||||
<th>平台</th>
|
||||
<th>订单信息</th>
|
||||
<th>平台 / 店铺</th>
|
||||
<th>商品摘要</th>
|
||||
<th>订单进度</th>
|
||||
<th>金额</th>
|
||||
<th>金额 / 时间</th>
|
||||
<th>任务进度</th>
|
||||
<th>创建时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in items" :key="item.orderId">
|
||||
<td>
|
||||
<RouterLink :to="`/admin/orders/${item.orderId}`">{{ item.platformOrderId }}</RouterLink>
|
||||
<div class="cell-stack">
|
||||
<RouterLink :to="`/admin/orders/${item.orderId}`" class="primary-link">{{ item.platformOrderId }}</RouterLink>
|
||||
<span class="cell-main">{{ resolveBuyerLabel(item) }}</span>
|
||||
<span class="cell-sub">联系方式:{{ resolveContactLabel(item) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<span class="cell-main">{{ item.platform }}</span>
|
||||
<span class="cell-sub">{{ resolveShopLabel(item) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<span class="cell-main">{{ resolveItemSummary(item) }}</span>
|
||||
<span class="cell-sub">{{ item.itemCount }} 项,合计 {{ item.totalQuantity }} 件</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ item.platform }}</td>
|
||||
<td>
|
||||
<div class="status-stack">
|
||||
<AdminStatusTag :status="item.payStatus" />
|
||||
@@ -102,7 +133,13 @@ onMounted(loadOrders)
|
||||
<AdminStatusTag :status="item.userBindingStatus" />
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ item.totalAmount }} {{ item.currency }}</td>
|
||||
<td>
|
||||
<div class="cell-stack">
|
||||
<span class="cell-main amount-text">{{ item.totalAmount }} {{ item.currency }}</span>
|
||||
<span class="cell-sub">支付:{{ formatAdminDateTime(item.paidAt) }}</span>
|
||||
<span class="cell-sub">创建:{{ formatAdminDateTime(item.createdAt) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="progress-stack">
|
||||
<span
|
||||
@@ -119,7 +156,6 @@ onMounted(loadOrders)
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ formatAdminDateTime(item.createdAt) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -142,6 +178,26 @@ onMounted(loadOrders)
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cell-stack {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.primary-link,
|
||||
.cell-main {
|
||||
font-weight: 600;
|
||||
color: #1d3555;
|
||||
}
|
||||
|
||||
.cell-sub {
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.amount-text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.progress-stack {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
Reference in New Issue
Block a user