使用element ui

This commit is contained in:
yml
2026-05-21 20:16:27 +08:00
parent be7b057034
commit a39d43c4d6
39 changed files with 1380 additions and 1644 deletions
@@ -9,21 +9,12 @@
word-break: break-all;
}
.info-card,
.hero-card,
.error-copy {
padding: 18px;
border-radius: var(--radius-lg);
background: var(--bg-surface);
border: 1px solid var(--border-default);
}
.info-card p {
.section-card p {
margin: 10px 0 0;
color: var(--text-primary);
}
.info-card h3 {
.section-card h3 {
margin: 0 0 var(--space-3);
color: var(--text-primary);
}
@@ -110,10 +101,6 @@
align-items: center;
}
.error-copy {
color: var(--color-danger);
}
.action-row {
display: flex;
flex-wrap: wrap;
@@ -147,23 +134,6 @@
margin-bottom: 0;
}
.data-table {
width: 100%;
border-collapse: collapse;
}
.data-table th,
.data-table td {
padding: var(--space-3) 10px;
text-align: left;
border-bottom: 1px solid var(--border-default);
}
.data-table th {
width: 160px;
color: var(--text-secondary);
}
.status-stack {
display: flex;
flex-wrap: wrap;
@@ -252,11 +222,16 @@
gap: 14px;
}
.field-block {
display: grid;
gap: var(--space-2);
color: var(--text-primary);
font-weight: 600;
.admin-panel :deep(.el-form-item) {
margin-bottom: 0;
}
.admin-panel :deep(.el-form-item__label) {
color: var(--text-secondary);
font-size: var(--text-xs);
font-weight: 700;
line-height: 1.4;
margin-bottom: 6px;
}
.manual-hint {
@@ -65,7 +65,7 @@ onMounted(loadDetail)
<section class="admin-panel">
<AdminPageHeader title="任务详情" description="查看任务全量信息并执行人工操作。" />
<p v-if="errorMessage" class="error-copy">{{ errorMessage }}</p>
<el-alert v-if="errorMessage" :title="errorMessage" type="error" show-icon :closable="false" />
<el-skeleton v-if="loading" :rows="6" animated />
@@ -83,16 +83,52 @@ onMounted(loadDetail)
:action-loading="actionLoading"
:can-manage-task-lifecycle="canManageTaskLifecycle"
:can-close-tasks="canCloseTasks"
@retry="runAction(() => retryAdminTask(detail!.task.taskId), '任务已重试', `确认重试任务 ${detail!.task.taskNo} 吗?`)"
@regenerate-claim-link="runAction(() => regenerateAdminTaskClaimLink(detail!.task.taskId), '领取链接已重新生成', `确认重新生成任务 ${detail!.task.taskNo} 的领取链接吗?旧链接会失效。`)"
@confirm-role="runAction(() => confirmAdminTaskAssistedRole(detail!.task.taskId), '角色已确认', `确认以客服身份锁定任务 ${detail!.task.taskNo} 当前识别到的角色信息吗?`)"
@support-redeem="runAction(() => redeemAdminTaskAssisted(detail!.task.taskId), '兑换任务已启动', `确认开始执行任务 ${detail!.task.taskNo} 的自动兑换吗?`)"
@retry="
runAction(
() => retryAdminTask(detail!.task.taskId),
'任务已重试',
`确认重试任务 ${detail!.task.taskNo} 吗?`,
)
"
@regenerate-claim-link="
runAction(
() => regenerateAdminTaskClaimLink(detail!.task.taskId),
'领取链接已重新生成',
`确认重新生成任务 ${detail!.task.taskNo} 的领取链接吗?旧链接会失效。`,
)
"
@confirm-role="
runAction(
() => confirmAdminTaskAssistedRole(detail!.task.taskId),
'角色已确认',
`确认以客服身份锁定任务 ${detail!.task.taskNo} 当前识别到的角色信息吗?`,
)
"
@support-redeem="
runAction(
() => redeemAdminTaskAssisted(detail!.task.taskId),
'兑换任务已启动',
`确认开始执行任务 ${detail!.task.taskNo} 的自动兑换吗?`,
)
"
@prepare-kuaishou-cloud="submitKuaishouCloudPrepare"
@dispatch-kuaishou-cloud="submitKuaishouCloudDispatch"
@return-kuaishou-cloud="submitKuaishouCloudReturnNumber"
@mark-manual-review="runAction(() => markAdminTaskManualReview(detail!.task.taskId), '任务已转人工处理', `确认将任务 ${detail!.task.taskNo} 转为人工处理吗?`)"
@mark-manual-review="
runAction(
() => markAdminTaskManualReview(detail!.task.taskId),
'任务已转人工处理',
`确认将任务 ${detail!.task.taskNo} 转为人工处理吗?`,
)
"
@submit-manual-dispatch="submitManualDispatch"
@close-task="runAction(() => closeAdminTask(detail!.task.taskId), '任务已关闭', `确认关闭任务 ${detail!.task.taskNo} 吗?关闭后不会自动继续推进。`)"
@close-task="
runAction(
() => closeAdminTask(detail!.task.taskId),
'任务已关闭',
`确认关闭任务 ${detail!.task.taskNo} 吗?关闭后不会自动继续推进。`,
)
"
/>
<AdminTaskInfoSection
@@ -123,17 +159,20 @@ onMounted(loadDetail)
:auto-delivery-summary="resolveTaskAutoDeliverySummary(detail)"
/>
<AdminTaskRedeemResolutionSection
v-if="detail.redeemResolution"
:detail="detail"
/>
<AdminTaskRedeemResolutionSection v-if="detail.redeemResolution" :detail="detail" />
<AdminTaskInventoryBindingsSection
v-if="!isKuaishouCloudTask"
:detail="detail"
:can-view-sensitive-task-data="canViewSensitiveTaskData"
:action-loading="actionLoading"
@release-binding="runAction(() => releaseAdminTaskInventoryBinding(detail!.task.taskId, $event), '库存绑定已释放', `确认释放该库存绑定吗?`)"
@release-binding="
runAction(
() => releaseAdminTaskInventoryBinding(detail!.task.taskId, $event),
'库存绑定已释放',
`确认释放该库存绑定吗?`,
)
"
/>
<AdminTaskManualDispatchSection
@@ -146,10 +185,7 @@ onMounted(loadDetail)
@submit="submitManualDispatch"
/>
<AdminTaskEventsSection
v-if="detail.events.length > 0"
:detail="detail"
/>
<AdminTaskEventsSection v-if="detail.events.length > 0" :detail="detail" />
<AdminTaskScreenshotSection
v-if="detail.screenshotUrl"
@@ -159,7 +195,6 @@ onMounted(loadDetail)
</template>
<el-empty v-else description="任务不存在或已被删除" />
</section>
</template>
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref } from "vue";
import { onMounted, ref } from "vue";
import { useAdminAction } from "@/composables/useAdminAction";
import { useAdminListPage } from "@/composables/useAdminListPage";
@@ -130,6 +130,10 @@ function resetFilters() {
dateTo.value = "";
void loadTasks(1);
}
onMounted(() => {
void loadTasks(1);
});
</script>
<template>
@@ -14,30 +14,28 @@ defineProps<Props>()
</script>
<template>
<section class="info-card">
<el-card shadow="never" class="section-card">
<h3>咸鱼自动发货</h3>
<p class="section-copy">
这里展示这条任务最近一次触发咸鱼自动发货的状态原因和接口回执摘要
</p>
<p class="section-copy">这里展示这条任务最近一次触发咸鱼自动发货的状态原因和接口回执摘要</p>
<div class="redeem-summary-grid">
<article class="redeem-summary-card">
<el-card shadow="never" class="redeem-summary-card">
<span>当前状态</span>
<div class="auto-delivery-tag-line">
<AdminStatusTag :status="autoDeliveryStatus" />
</div>
</article>
<article class="redeem-summary-card">
</el-card>
<el-card shadow="never" class="redeem-summary-card">
<span>触发来源</span>
<strong>{{
formatAutoDeliveryTrigger(detail.task.agisoAutoDelivery?.trigger || '')
}}</strong>
</article>
<article class="redeem-summary-card">
</el-card>
<el-card shadow="never" class="redeem-summary-card">
<span>最近执行</span>
<strong>{{ formatAdminDateTime(detail.task.agisoAutoDelivery?.updatedAt) }}</strong>
</article>
<article class="redeem-summary-card">
</el-card>
<el-card shadow="never" class="redeem-summary-card">
<span>接口回执</span>
<strong>
{{
@@ -47,7 +45,7 @@ defineProps<Props>()
: '-')
}}
</strong>
</article>
</el-card>
</div>
<div class="auto-delivery-note">
@@ -62,7 +60,7 @@ defineProps<Props>()
请求 ID{{ detail.task.agisoAutoDelivery.requestId }}
</p>
</div>
</section>
</el-card>
</template>
<style scoped src="../AdminTaskDetail.css"></style>
@@ -11,24 +11,26 @@ defineProps<Props>()
</script>
<template>
<section class="info-card">
<el-card shadow="never" class="section-card">
<h3>任务事件</h3>
<table class="data-table">
<tbody>
<tr v-for="event in detail.events" :key="event.eventId">
<th>{{ formatTaskEventType(event.eventType) }}</th>
<td>
<div class="event-copy">
{{ formatTaskEventPayload(event.payload) }}
</div>
<div class="event-time">
{{ formatAdminDateTime(event.createdAt) }}
</div>
</td>
</tr>
</tbody>
</table>
</section>
<el-table :data="detail.events" size="small">
<el-table-column label="事件" width="180">
<template #default="{ row: event }">
{{ formatTaskEventType(event.eventType) }}
</template>
</el-table-column>
<el-table-column label="内容">
<template #default="{ row: event }">
<div class="event-copy">
{{ formatTaskEventPayload(event.payload) }}
</div>
<div class="event-time">
{{ formatAdminDateTime(event.createdAt) }}
</div>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
<style scoped src="../AdminTaskDetail.css"></style>
@@ -17,7 +17,11 @@ defineProps<Props>()
<template>
<!-- Kuaishou Cloud hero card -->
<section v-if="isKuaishouCloudTask && detail.kuaishouCloudFulfillment" class="hero-card">
<el-card
v-if="isKuaishouCloudTask && detail.kuaishouCloudFulfillment"
shadow="never"
class="section-card hero-card"
>
<div class="hero-copy">
<span class="hero-eyebrow">{{ detail.task.executorKey || 'task' }}</span>
<h2>{{ detail.task.taskNo }}</h2>
@@ -29,14 +33,15 @@ defineProps<Props>()
</p>
</div>
<div class="hero-meta-grid">
<article
<el-card
v-for="card in summaryCards"
:key="card.label"
shadow="never"
:class="['hero-metric', `hero-metric--${card.tone}`]"
>
<span>{{ card.label }}</span>
<strong>{{ card.value }}</strong>
</article>
</el-card>
</div>
<div class="hero-inline">
<span>系统绑定 <AdminStatusTag :status="detail.task.systemBindingStatus" /></span>
@@ -51,10 +56,10 @@ defineProps<Props>()
<span>客户领取页</span>
<strong>已失效</strong>
</div>
</section>
</el-card>
<!-- Simple info card for other task types -->
<section v-else class="info-card">
<el-card v-else shadow="never" class="section-card">
<h2>{{ detail.task.taskNo }}</h2>
<p>
状态<AdminStatusTag :status="detail.task.status" /> · 订单{{
@@ -80,7 +85,7 @@ defineProps<Props>()
<a class="claim-link" :href="claimUrl" target="_blank" rel="noreferrer">{{ claimUrl }}</a>
</p>
<p v-else-if="claimLinkInvalid">领取链接已失效</p>
</section>
</el-card>
</template>
<style scoped src="../AdminTaskDetail.css"></style>
@@ -14,106 +14,74 @@ defineProps<Props>()
</script>
<template>
<section class="info-card">
<el-card shadow="never" class="section-card">
<h3>任务信息</h3>
<table class="data-table">
<tbody>
<tr>
<th>商品</th>
<td>{{ detail.orderItem?.skuName || '-' }}</td>
</tr>
<tr>
<th>SKU</th>
<td>{{ detail.orderItem?.skuCode || '-' }}</td>
</tr>
<tr>
<th>任务执行器</th>
<td>{{ detail.task.executorKey || '-' }}</td>
</tr>
<tr>
<th>履约状态</th>
<td>
<AdminStatusTag :status="detail.task.deliveryStatus || ''" />
</td>
</tr>
<tr>
<th>结果代码</th>
<td>{{ detail.task.resultCode || '-' }}</td>
</tr>
<tr>
<th>结果说明</th>
<td>{{ detail.task.resultMessage || '-' }}</td>
</tr>
<tr v-if="canViewSensitiveTaskData">
<th>库存凭据</th>
<td>{{ detail.inventory?.displayValue || '-' }}</td>
</tr>
<tr v-if="canViewSensitiveTaskData">
<th>凭据类型</th>
<td>{{ detail.inventory?.credentialType || '-' }}</td>
</tr>
<tr v-if="canViewSensitiveTaskData">
<th>库存状态</th>
<td>
<AdminStatusTag :status="detail.inventory?.status || ''" />
</td>
</tr>
<tr v-if="canViewSensitiveTaskData">
<th>Claim Token</th>
<td>{{ detail.claimToken?.token || '-' }}</td>
</tr>
<tr v-else>
<th>库存 / Token</th>
<td>客服账号不可查看库存凭据与原始领取 Token</td>
</tr>
<tr>
<th>Token 状态</th>
<td>
<AdminStatusTag :status="detail.claimToken?.status || ''" />
</td>
</tr>
<tr>
<th>Token 过期</th>
<td>{{ formatAdminDateTime(detail.claimToken?.expiredAt) }}</td>
</tr>
<tr>
<th>领取链接</th>
<td>
<a
v-if="claimUrl"
class="claim-link"
:href="claimUrl"
target="_blank"
rel="noreferrer"
>{{ claimUrl }}</a
>
<span v-else-if="claimLinkInvalid">已失效</span>
<span v-else>-</span>
</td>
</tr>
<tr>
<th>浏览器会话</th>
<td>{{ detail.task.browserSessionId || '-' }}</td>
</tr>
<tr>
<th>用户打开链接</th>
<td>{{ formatAdminDateTime(detail.task.claimedAt) }}</td>
</tr>
<tr>
<th>用户提交绑定</th>
<td>{{ formatAdminDateTime(detail.task.roleConfirmedAt) }}</td>
</tr>
<tr>
<th>完整绑定成功</th>
<td>{{ formatAdminDateTime(detail.task.redeemedAt) }}</td>
</tr>
<tr>
<th>截图路径</th>
<td>{{ detail.task.screenshotPath || '-' }}</td>
</tr>
</tbody>
</table>
</section>
<el-descriptions :column="2" border>
<el-descriptions-item label="商品">{{
detail.orderItem?.skuName || '-'
}}</el-descriptions-item>
<el-descriptions-item label="SKU">{{
detail.orderItem?.skuCode || '-'
}}</el-descriptions-item>
<el-descriptions-item label="任务执行器">
{{ detail.task.executorKey || '-' }}
</el-descriptions-item>
<el-descriptions-item label="履约状态">
<AdminStatusTag :status="detail.task.deliveryStatus || ''" />
</el-descriptions-item>
<el-descriptions-item label="结果代码">{{
detail.task.resultCode || '-'
}}</el-descriptions-item>
<el-descriptions-item label="结果说明">
{{ detail.task.resultMessage || '-' }}
</el-descriptions-item>
<template v-if="canViewSensitiveTaskData">
<el-descriptions-item label="库存凭据">
{{ detail.inventory?.displayValue || '-' }}
</el-descriptions-item>
<el-descriptions-item label="凭据类型">
{{ detail.inventory?.credentialType || '-' }}
</el-descriptions-item>
<el-descriptions-item label="库存状态">
<AdminStatusTag :status="detail.inventory?.status || ''" />
</el-descriptions-item>
<el-descriptions-item label="Claim Token">
{{ detail.claimToken?.token || '-' }}
</el-descriptions-item>
</template>
<el-descriptions-item v-else label="库存 / Token" :span="2">
客服账号不可查看库存凭据与原始领取 Token
</el-descriptions-item>
<el-descriptions-item label="Token 状态">
<AdminStatusTag :status="detail.claimToken?.status || ''" />
</el-descriptions-item>
<el-descriptions-item label="Token 过期">
{{ formatAdminDateTime(detail.claimToken?.expiredAt) }}
</el-descriptions-item>
<el-descriptions-item label="领取链接" :span="2">
<a v-if="claimUrl" class="claim-link" :href="claimUrl" target="_blank" rel="noreferrer">{{
claimUrl
}}</a>
<span v-else-if="claimLinkInvalid">已失效</span>
<span v-else>-</span>
</el-descriptions-item>
<el-descriptions-item label="浏览器会话">
{{ detail.task.browserSessionId || '-' }}
</el-descriptions-item>
<el-descriptions-item label="用户打开链接">
{{ formatAdminDateTime(detail.task.claimedAt) }}
</el-descriptions-item>
<el-descriptions-item label="用户提交绑定">
{{ formatAdminDateTime(detail.task.roleConfirmedAt) }}
</el-descriptions-item>
<el-descriptions-item label="完整绑定成功">
{{ formatAdminDateTime(detail.task.redeemedAt) }}
</el-descriptions-item>
<el-descriptions-item label="截图路径" :span="2">
{{ detail.task.screenshotPath || '-' }}
</el-descriptions-item>
</el-descriptions>
</el-card>
</template>
<style scoped src="../AdminTaskDetail.css"></style>
@@ -18,82 +18,81 @@ const emit = defineEmits<{
</script>
<template>
<section class="info-card">
<el-card shadow="never" class="section-card">
<h3>库存绑定</h3>
<p class="section-copy">
这里展示任务当前和历史绑定过的库存项便于核对多库存任务的真实履约轨迹
</p>
<table class="data-table">
<thead>
<tr>
<th>绑定</th>
<th>角色</th>
<th>库存项</th>
<th>状态</th>
<th>凭据内容</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-if="detail.inventoryBindings.length === 0">
<td colspan="7" class="table-empty">当前任务还没有库存绑定记录</td>
</tr>
<tr v-for="binding in detail.inventoryBindings" :key="binding.bindingId">
<td>
<div>#{{ binding.bindingId }}</div>
<div v-if="binding.isPrimary" class="binding-primary">主库存项</div>
</td>
<td>
<div>{{ binding.roleKey || '-' }}</div>
<div class="binding-meta">数量 {{ binding.quantity }}</div>
</td>
<td>
<div>ID {{ binding.inventoryItemId }}</div>
<div>{{ binding.skuCode || '-' }}</div>
<div class="binding-meta">
{{ binding.credentialType || '-' }} ·
{{ binding.batchNo || '无批次' }}
</div>
</td>
<td>
<div class="status-stack">
<AdminStatusTag :status="binding.bindingStatus" />
<AdminStatusTag :status="binding.inventoryStatus" />
</div>
<div v-if="binding.invalidReason" class="binding-meta">
{{
binding.inventoryStatus === 'invalid'
? '作废原因'
: binding.inventoryStatus === 'consumed'
? '消耗原因'
: '处理原因'
}}{{ binding.invalidReason }}
</div>
</td>
<td>
{{ canViewSensitiveTaskData ? binding.displayValue || '-' : '客服不可见' }}
</td>
<td>
<div>绑定 {{ formatAdminDateTime(binding.createdAt) }}</div>
<div class="binding-meta">消费 {{ formatAdminDateTime(binding.consumedAt) }}</div>
<div class="binding-meta">释放 {{ formatAdminDateTime(binding.releasedAt) }}</div>
</td>
<td>
<el-button
v-if="hasAdminRole('admin') && binding.canRelease"
:loading="actionLoading"
link
@click="emit('releaseBinding', binding.bindingId)"
>
释放绑定
</el-button>
<span v-else class="binding-meta">-</span>
</td>
</tr>
</tbody>
</table>
</section>
<el-table :data="detail.inventoryBindings" size="small">
<el-table-column label="绑定" width="100">
<template #default="{ row: binding }">
<div>#{{ binding.bindingId }}</div>
<div v-if="binding.isPrimary" class="binding-primary">主库存项</div>
</template>
</el-table-column>
<el-table-column label="角色" min-width="120">
<template #default="{ row: binding }">
<div>{{ binding.roleKey || '-' }}</div>
<div class="binding-meta">数量 {{ binding.quantity }}</div>
</template>
</el-table-column>
<el-table-column label="库存项" min-width="180">
<template #default="{ row: binding }">
<div>ID {{ binding.inventoryItemId }}</div>
<div>{{ binding.skuCode || '-' }}</div>
<div class="binding-meta">
{{ binding.credentialType || '-' }} ·
{{ binding.batchNo || '无批次' }}
</div>
</template>
</el-table-column>
<el-table-column label="状态" min-width="160">
<template #default="{ row: binding }">
<div class="status-stack">
<AdminStatusTag :status="binding.bindingStatus" />
<AdminStatusTag :status="binding.inventoryStatus" />
</div>
<div v-if="binding.invalidReason" class="binding-meta">
{{
binding.inventoryStatus === 'invalid'
? '作废原因'
: binding.inventoryStatus === 'consumed'
? '消耗原因'
: '处理原因'
}}{{ binding.invalidReason }}
</div>
</template>
</el-table-column>
<el-table-column label="凭据内容" min-width="180">
<template #default="{ row: binding }">
{{ canViewSensitiveTaskData ? binding.displayValue || '-' : '客服不可见' }}
</template>
</el-table-column>
<el-table-column label="时间" min-width="180">
<template #default="{ row: binding }">
<div>绑定 {{ formatAdminDateTime(binding.createdAt) }}</div>
<div class="binding-meta">消费 {{ formatAdminDateTime(binding.consumedAt) }}</div>
<div class="binding-meta">释放 {{ formatAdminDateTime(binding.releasedAt) }}</div>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template #default="{ row: binding }">
<el-button
v-if="hasAdminRole('admin') && binding.canRelease"
:loading="actionLoading"
link
@click="emit('releaseBinding', binding.bindingId)"
>
释放绑定
</el-button>
<span v-else class="binding-meta">-</span>
</template>
</el-table-column>
<template #empty>
<el-empty description="当前任务还没有库存绑定记录" :image-size="60" />
</template>
</el-table>
</el-card>
</template>
<style scoped src="../AdminTaskDetail.css"></style>
@@ -37,7 +37,7 @@ const emit = defineEmits<{
</script>
<template>
<section class="info-card flow-card">
<el-card shadow="never" class="section-card flow-card">
<div class="flow-card-head">
<div>
<h3>快手 Cloud 履约面板</h3>
@@ -74,34 +74,34 @@ const emit = defineEmits<{
</div>
<div class="redeem-summary-grid">
<article class="redeem-summary-card">
<el-card shadow="never" class="redeem-summary-card">
<span>准备状态</span>
<div class="auto-delivery-tag-line">
<AdminStatusTag :status="flow.binding.prepareStatus" />
</div>
</article>
<article class="redeem-summary-card">
</el-card>
<el-card shadow="never" class="redeem-summary-card">
<span>发货状态</span>
<div class="auto-delivery-tag-line">
<AdminStatusTag :status="flow.dispatch.status" />
</div>
</article>
<article class="redeem-summary-card">
</el-card>
<el-card shadow="never" class="redeem-summary-card">
<span>退号状态</span>
<div class="auto-delivery-tag-line">
<AdminStatusTag :status="flow.returnNumber.status" />
</div>
</article>
<article class="redeem-summary-card">
</el-card>
<el-card shadow="never" class="redeem-summary-card">
<span>当前任务状态</span>
<div class="auto-delivery-tag-line">
<AdminStatusTag :status="detail.task.status" />
</div>
</article>
</el-card>
</div>
<div class="kuaishou-focus-grid">
<article class="flow-block flow-block--spotlight">
<el-card shadow="never" class="flow-block flow-block--spotlight">
<div class="spotlight-head">
<div>
<h4>角色信息</h4>
@@ -145,9 +145,9 @@ const emit = defineEmits<{
<strong>{{ entry.value }}</strong>
</div>
</div>
</article>
</el-card>
<article class="flow-block flow-block--checklist">
<el-card shadow="never" class="flow-block flow-block--checklist">
<h4>流程检查</h4>
<p class="flow-copy">
客服可以先看这里快速判断卡在哪一步再决定是刷新角色准备资源发货还是退号
@@ -161,7 +161,7 @@ const emit = defineEmits<{
<strong>{{ item.detail }}</strong>
</div>
</div>
</article>
</el-card>
</div>
<el-collapse :model-value="collapsePanels" class="flow-collapse">
@@ -302,7 +302,7 @@ const emit = defineEmits<{
</div>
</el-collapse-item>
</el-collapse>
</section>
</el-card>
</template>
<style scoped src="../AdminTaskDetail.css"></style>
@@ -25,11 +25,10 @@ function updateField(field: keyof ManualDispatchForm, value: string) {
</script>
<template>
<section class="info-card">
<el-card shadow="never" class="section-card">
<h3>人工履约回写</h3>
<div class="manual-grid">
<label class="field-block">
<span>外部流水 / 单号</span>
<el-form label-position="top" class="manual-grid">
<el-form-item label="外部流水 / 单号">
<el-input
:model-value="form.deliveryReference"
:disabled="!canManageTaskLifecycle"
@@ -37,9 +36,8 @@ function updateField(field: keyof ManualDispatchForm, value: string) {
placeholder="例如快递单号、平台消息回执号"
@update:model-value="updateField('deliveryReference', $event)"
/>
</label>
<label class="field-block">
<span>已交付内容</span>
</el-form-item>
<el-form-item label="已交付内容">
<el-input
:model-value="form.deliveredCredential"
:disabled="!canManageTaskLifecycle"
@@ -49,9 +47,8 @@ function updateField(field: keyof ManualDispatchForm, value: string) {
:rows="3"
@update:model-value="updateField('deliveredCredential', $event)"
/>
</label>
<label class="field-block">
<span>处理备注</span>
</el-form-item>
<el-form-item label="处理备注">
<el-input
:model-value="form.resultMessage"
:disabled="!canManageTaskLifecycle"
@@ -61,25 +58,35 @@ function updateField(field: keyof ManualDispatchForm, value: string) {
:rows="4"
@update:model-value="updateField('resultMessage', $event)"
/>
</label>
</div>
<p class="manual-hint">回写后会直接更新任务终态不再走旧式领取链接流程</p>
<div v-if="detail.manualDispatch" class="manual-summary">
<p>
最近回写<AdminStatusTag
:status="detail.manualDispatch.outcome || detail.task.deliveryStatus"
/>
</el-form-item>
</el-form>
<el-alert
title="回写后会直接更新任务终态,不再走旧式领取链接流程。"
type="info"
show-icon
:closable="false"
class="mt-4"
/>
<el-descriptions v-if="detail.manualDispatch" :column="2" border class="manual-summary">
<el-descriptions-item label="最近回写">
<AdminStatusTag :status="detail.manualDispatch.outcome || detail.task.deliveryStatus" />
· {{ formatAdminDateTime(detail.manualDispatch.completedAt) }}
</p>
<p>
处理人{{ detail.manualDispatch.completedBy?.username || '-' }} /
</el-descriptions-item>
<el-descriptions-item label="处理人">
{{ detail.manualDispatch.completedBy?.username || '-' }} /
{{ detail.manualDispatch.completedBy?.role || '-' }}
</p>
<p>流水号{{ detail.manualDispatch.deliveryReference || '-' }}</p>
<p>交付内容{{ detail.manualDispatch.deliveredCredential || '-' }}</p>
<p>备注{{ detail.manualDispatch.resultMessage || '-' }}</p>
</div>
</section>
</el-descriptions-item>
<el-descriptions-item label="流水号">
{{ detail.manualDispatch.deliveryReference || '-' }}
</el-descriptions-item>
<el-descriptions-item label="交付内容">
{{ detail.manualDispatch.deliveredCredential || '-' }}
</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">
{{ detail.manualDispatch.resultMessage || '-' }}
</el-descriptions-item>
</el-descriptions>
</el-card>
</template>
<style scoped src="../AdminTaskDetail.css"></style>
@@ -11,33 +11,34 @@ defineProps<Props>()
</script>
<template>
<section class="info-card">
<el-card shadow="never" class="section-card">
<h3>兑换重试链路</h3>
<p class="section-copy">
这里记录自动兑换时每次使用过的 CDK判定结果以及是否切换到了新的同类型凭据
</p>
<div class="redeem-summary-grid">
<article class="redeem-summary-card">
<el-card shadow="never" class="redeem-summary-card">
<span>处理结果</span>
<strong>{{ formatRedeemResolutionStatus(detail.redeemResolution!.status) }}</strong>
</article>
<article class="redeem-summary-card">
</el-card>
<el-card shadow="never" class="redeem-summary-card">
<span>任务收口状态</span>
<strong>{{ detail.redeemResolution!.taskStatus || detail.task.status || '-' }}</strong>
</article>
<article class="redeem-summary-card">
</el-card>
<el-card shadow="never" class="redeem-summary-card">
<span>更换新码次数</span>
<strong>{{ detail.redeemResolution!.replacementCount }}</strong>
</article>
<article class="redeem-summary-card">
</el-card>
<el-card shadow="never" class="redeem-summary-card">
<span>完成时间</span>
<strong>{{ formatAdminDateTime(detail.redeemResolution!.finishedAt) }}</strong>
</article>
</el-card>
</div>
<div v-if="detail.redeemResolution!.attempts.length > 0" class="redeem-attempts">
<article
<el-card
shadow="never"
v-for="attempt in detail.redeemResolution!.attempts"
:key="`${attempt.attempt}-${attempt.inventoryItemId || 'na'}`"
class="redeem-attempt-card"
@@ -67,9 +68,9 @@ defineProps<Props>()
<p class="redeem-attempt-copy">
{{ attempt.resultMessage || '-' }}
</p>
</article>
</el-card>
</div>
</section>
</el-card>
</template>
<style scoped src="../AdminTaskDetail.css"></style>
@@ -8,15 +8,10 @@ defineProps<Props>()
</script>
<template>
<section class="info-card">
<el-card shadow="never" class="section-card">
<h3>{{ sectionTitle }}</h3>
<p v-if="!screenshotPreviewUrl" class="screenshot-empty">截图加载中或当前不可读取</p>
<a
v-else
class="screenshot-link"
:href="screenshotPreviewUrl"
target="_blank"
rel="noreferrer"
<a v-else class="screenshot-link" :href="screenshotPreviewUrl" target="_blank" rel="noreferrer"
>打开原图</a
>
<img
@@ -25,7 +20,7 @@ defineProps<Props>()
:src="screenshotPreviewUrl"
:alt="sectionTitle"
/>
</section>
</el-card>
</template>
<style scoped src="../AdminTaskDetail.css"></style>