清理旧消息和历史命名

This commit is contained in:
yml
2026-05-25 22:03:07 +08:00
parent e7aa194dde
commit 0caa38e690
41 changed files with 63 additions and 1044 deletions
-5
View File
@@ -62,11 +62,6 @@ const router = createRouter({
meta: { allowedRoles: ['admin', 'operator'] },
component: () => import('@/views/admin/inventory/AdminInventoryView.vue'),
},
{
path: 'message-deliveries',
component: () =>
import('@/views/admin/message-deliveries/AdminMessageDeliveriesView.vue'),
},
{
path: 'webhook-events',
meta: { allowedRoles: ['admin', 'operator'] },
@@ -6,5 +6,4 @@ export * from './platform-config'
export * from './orders'
export * from './tasks'
export * from './inventory'
export * from './message-deliveries'
export * from './webhook-events'
@@ -1,9 +0,0 @@
import { apiGet } from '@/lib/http'
import type { AdminMessageDeliveryListItem, AdminPagination } from '@/types/admin'
export function fetchAdminMessageDeliveries(params?: Record<string, unknown>) {
return apiGet<{ items: AdminMessageDeliveryListItem[]; pagination: AdminPagination }>(
'/api/v1/admin/message-deliveries',
params,
)
}
@@ -43,14 +43,6 @@ export function regenerateAdminTaskClaimLink(taskId: number | string) {
return apiPost<AdminTaskActionResponse>(`/api/v1/admin/tasks/${taskId}/regenerate-claim-link`, {})
}
export function confirmAdminTaskAssistedRole(taskId: number | string) {
return apiPost<AdminTaskActionResponse>(`/api/v1/admin/tasks/${taskId}/support-confirm-role`, {})
}
export function redeemAdminTaskAssisted(taskId: number | string) {
return apiPost<AdminTaskActionResponse>(`/api/v1/admin/tasks/${taskId}/support-redeem`, {})
}
export function closeAdminTask(taskId: number | string) {
return apiPost<AdminTaskActionResponse>(`/api/v1/admin/tasks/${taskId}/close`, {})
}
@@ -1,7 +1,7 @@
/* ============================================================
管理员列表页共享样式
引入: AdminOrdersView, AdminTasksView, AdminMessageDeliveriesView,
AdminWebhookEventsView, AdminUsersView, AdminInventoryView
引入: AdminOrdersView, AdminTasksView, AdminWebhookEventsView,
AdminUsersView, AdminInventoryView
各页面自行覆盖 grid-template-columns 等布局差异
============================================================ */
-3
View File
@@ -39,9 +39,6 @@ export type {
AdminWebhookReplayResponse,
} from './webhook-events'
// Message deliveries types
export type { AdminMessageDeliveryListItem } from './message-deliveries'
// Platform config types
export type {
AdminNotificationBarkRecipient,
@@ -1,24 +0,0 @@
export interface AdminMessageDeliveryListItem {
deliveryId: number
provider: string
platform: string
shopId: string
shopName: string
channel: string
orderId: number | null
taskId: number | null
taskNo: string
taskStatus: string
platformOrderId: string
recipientKey: string
messageContent: string
claimUrl: string
status: string
requestUrl: string
responseStatus: number
response: Record<string, unknown>
errorMessage: string
sentAt: string | null
createdAt: string
updatedAt: string
}
-2
View File
@@ -48,8 +48,6 @@ export interface AdminTaskOperations {
canRefreshKuaishouCloudRoleInfo: boolean
canDispatchKuaishouCloudFulfillment: boolean
canReturnKuaishouCloudFulfillment: boolean
canSupportConfirmRole: boolean
canSupportRedeem: boolean
canViewSensitiveTaskData: boolean
}
-7
View File
@@ -41,13 +41,6 @@ export const adminInventoryCredentialTypeOptions = [
{ label: '纯文本凭据', value: 'text_credential' },
]
export const adminMessageDeliveryStatusOptions = [
{ label: '全部状态', value: '' },
{ label: '发送成功', value: 'success' },
{ label: '发送失败', value: 'failed' },
{ label: '等待发送', value: 'pending' },
]
export const adminWebhookProcessedOptions = [
{ label: '全部', value: '' },
{ label: '处理成功', value: '1' },
@@ -148,7 +148,7 @@ export function useAdminInventory() {
function getCredentialTypeHint(value: string) {
const normalized = String(value || '').trim()
if (normalized === 'tencent_code')
return '当前腾讯自动领取链路会优先预占这一类兑换码,三角洲行动这类场景就使用这个类型。内部 SKU 支持中文、英文和数字混用。'
return '当前领取链路会优先预占这一类兑换码,快手云履约等场景可按内部 SKU 统一匹配。'
if (normalized === 'card_password') return '适合卡号 / 卡密一体的库存项。'
if (normalized === 'account_password') return '适合账号密码、账号令牌等组合凭据。'
if (normalized === 'activation_link') return '适合直接发链接的激活类库存。'
@@ -10,7 +10,6 @@ import {
Expand,
Fold,
List,
Message,
Setting,
SwitchButton,
Tickets,
@@ -62,8 +61,6 @@ const navItems = computed(() => {
items.push({ to: '/admin/inventory', label: '库存', icon: Box })
}
items.push({ to: '/admin/message-deliveries', label: '消息发送', icon: Message })
if (isAdmin.value || isOperator.value) {
items.push({ to: '/admin/webhook-events', label: 'Webhook', icon: Connection })
}
@@ -1,281 +0,0 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useAdminListPage } from '@/composables/useAdminListPage'
import AdminPageHeader from '@/components/admin/AdminPageHeader.vue'
import AdminStatusTag from '@/components/admin/AdminStatusTag.vue'
import { fetchAdminMessageDeliveries } from '@/services/admin'
import type { AdminMessageDeliveryListItem } from '@/types/admin'
import { formatAdminDateTime } from '@/utils/admin-time'
import { adminMessageDeliveryStatusOptions } from '@/utils/admin-options'
const provider = ref('agiso')
const platform = ref('xianyu')
const status = ref('')
const shopId = ref('')
const platformOrderId = ref('')
const taskNo = ref('')
const dateFrom = ref('')
const dateTo = ref('')
const {
loading,
errorMessage,
items,
pagination,
loadPage: loadMessageDeliveries,
} = useAdminListPage<AdminMessageDeliveryListItem>({
defaultErrorMessage: '读取消息发送记录失败',
fetchPage: (page, pageSize) =>
fetchAdminMessageDeliveries({
page,
pageSize,
provider: provider.value.trim(),
platform: platform.value.trim(),
status: status.value.trim(),
shopId: shopId.value.trim(),
platformOrderId: platformOrderId.value.trim(),
taskNo: taskNo.value.trim(),
dateFrom: dateFrom.value.trim(),
dateTo: dateTo.value.trim(),
}),
})
const summary = computed(() => ({
successCount: items.value.filter((item) => item.status === 'success').length,
failedCount: items.value.filter((item) => item.status === 'failed').length,
pendingCount: items.value.filter((item) => item.status === 'pending').length,
}))
function resetFilters() {
provider.value = 'agiso'
platform.value = 'xianyu'
status.value = ''
shopId.value = ''
platformOrderId.value = ''
taskNo.value = ''
dateFrom.value = ''
dateTo.value = ''
void loadMessageDeliveries(1)
}
onMounted(() => {
void loadMessageDeliveries(1)
})
</script>
<template>
<div class="deliveries-page list-page">
<AdminPageHeader
title="消息发送记录"
description="查看领取链接消息是否真正发出、平台返回了什么、失败原因是什么。"
>
<template #extra>
<span class="total-badge"> {{ pagination.total }} 条记录</span>
</template>
</AdminPageHeader>
<!-- 筛选 -->
<el-card shadow="never" class="section-card">
<template #header>
<div class="card-header">
<span class="card-title">筛选消息</span>
<span class="card-desc">按服务商平台发送状态店铺等条件筛选</span>
</div>
</template>
<div class="filter-grid">
<el-input
v-model="provider"
class="filter-control"
placeholder="服务商,如 agiso"
clearable
@keyup.enter="loadMessageDeliveries(1)"
/>
<el-input
v-model="platform"
class="filter-control"
placeholder="业务平台,如 xianyu"
clearable
@keyup.enter="loadMessageDeliveries(1)"
/>
<el-select v-model="status" class="filter-control" placeholder="发送状态" clearable>
<el-option
v-for="opt in adminMessageDeliveryStatusOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
<el-input
v-model="shopId"
class="filter-control"
placeholder="店铺 ID(精确匹配)"
clearable
@keyup.enter="loadMessageDeliveries(1)"
/>
<el-input
v-model="platformOrderId"
class="filter-control"
placeholder="平台订单号"
clearable
@keyup.enter="loadMessageDeliveries(1)"
/>
<el-input
v-model="taskNo"
class="filter-control"
placeholder="任务编号"
clearable
@keyup.enter="loadMessageDeliveries(1)"
/>
<el-date-picker
v-model="dateFrom"
class="filter-control"
type="date"
placeholder="开始日期"
value-format="YYYY-MM-DD"
/>
<el-date-picker
v-model="dateTo"
class="filter-control"
type="date"
placeholder="结束日期"
value-format="YYYY-MM-DD"
/>
<div class="filter-buttons">
<el-button round @click="resetFilters">重置</el-button>
<el-button round type="primary" @click="loadMessageDeliveries(1)">查询</el-button>
</div>
</div>
</el-card>
<!-- 摘要 -->
<div v-if="!loading && items.length > 0" class="summary-strip">
<span class="summary-title">当前页</span>
<span class="summary-metric" data-tone="success"
>发送成功 <strong>{{ summary.successCount }}</strong></span
>
<span class="summary-metric" data-tone="danger"
>发送失败 <strong>{{ summary.failedCount }}</strong></span
>
<span class="summary-metric" data-tone="warning"
>等待中 <strong>{{ summary.pendingCount }}</strong></span
>
</div>
<el-alert
v-if="errorMessage"
:title="errorMessage"
type="error"
show-icon
:closable="false"
class="mt-4"
/>
<!-- 列表 -->
<el-card
shadow="never"
class="section-card"
v-loading="loading"
element-loading-text="消息发送记录加载中"
>
<template v-if="items.length === 0 && !loading">
<el-empty description="当前筛选下还没有消息发送记录。" :image-size="60" />
</template>
<template v-else>
<div class="orders-toolbar table-toolbar">
<strong>发送明细</strong>
<span> {{ pagination.page }} 当前展示 {{ items.length }} </span>
</div>
<el-table :data="items" stripe size="small" class="orders-table data-table">
<el-table-column label="消息ID" width="100">
<template #default="{ row }">
<span class="order-no id-link">#{{ row.deliveryId }}</span>
</template>
</el-table-column>
<el-table-column label="接收者" min-width="160">
<template #default="{ row }">
<div class="cell-stack">
<span class="cell-title">{{
row.recipientKey || row.shopName || row.shopId || '-'
}}</span>
<span class="cell-subline">{{ row.shopName || row.shopId || '-' }}</span>
</div>
</template>
</el-table-column>
<el-table-column label="消息类型" min-width="140">
<template #default="{ row }">
<div class="cell-stack">
<span class="cell-title">{{ row.channel || '-' }}</span>
<div class="cell-meta-row">
<span class="compact-chip">{{ row.provider || '-' }}</span>
<span class="compact-chip">{{ row.platform || '-' }}</span>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="状态" width="100">
<template #default="{ row }">
<AdminStatusTag :status="row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" min-width="160">
<template #default="{ row }">
<div class="cell-stack">
<span class="cell-title">{{ formatAdminDateTime(row.createdAt) }}</span>
<span v-if="row.sentAt" class="cell-subline"
>发送 {{ formatAdminDateTime(row.sentAt) }}</span
>
</div>
</template>
</el-table-column>
<el-table-column label="操作" min-width="140">
<template #default="{ row }">
<div class="action-stack">
<a
v-if="row.claimUrl"
class="detail-link"
:href="row.claimUrl"
target="_blank"
rel="noreferrer"
>Claim 链接</a
>
<RouterLink
v-if="row.orderId"
class="detail-link"
:to="`/admin/orders/${row.orderId}`"
>订单 #{{ row.orderId }}</RouterLink
>
<RouterLink v-if="row.taskId" class="detail-link" :to="`/admin/tasks/${row.taskId}`"
>任务 {{ row.taskNo || row.taskId }}</RouterLink
>
<span v-if="!row.claimUrl && !row.orderId && !row.taskId" class="cell-subline"
>-</span
>
</div>
</template>
</el-table-column>
</el-table>
<el-pagination
v-if="pagination.total > 0"
v-model:current-page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
layout="total, prev, pager, next"
class="pagination-center"
@current-change="loadMessageDeliveries"
/>
</template>
</el-card>
</div>
</template>
<style scoped>
@import '../../../styles/admin-list-pages.css';
.filter-grid {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
</style>
@@ -3,9 +3,7 @@ import { onMounted } from 'vue'
import {
closeAdminTask,
confirmAdminTaskAssistedRole,
markAdminTaskManualReview,
redeemAdminTaskAssisted,
regenerateAdminTaskClaimLink,
releaseAdminTaskInventoryBinding,
retryAdminTask,
@@ -94,20 +92,6 @@ onMounted(loadDetail)
`确认重新生成任务 ${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"
@@ -13,8 +13,6 @@ defineProps<Props>()
const emit = defineEmits<{
retry: []
regenerateClaimLink: []
confirmRole: []
supportRedeem: []
prepareKuaishouCloud: []
dispatchKuaishouCloud: []
returnKuaishouCloud: []
@@ -45,24 +43,6 @@ const emit = defineEmits<{
>
重发链接
</el-button>
<el-button
v-if="detail.operations.canSupportConfirmRole"
:loading="actionLoading"
round
type="warning"
@click="emit('confirmRole')"
>
客服确认角色
</el-button>
<el-button
v-if="detail.operations.canSupportRedeem"
:loading="actionLoading"
round
type="success"
@click="emit('supportRedeem')"
>
客服开始兑换
</el-button>
<el-button
v-if="canManageTaskLifecycle && detail.operations.canPrepareKuaishouCloudFulfillment"
:loading="actionLoading"
@@ -152,14 +152,14 @@ onMounted(() => {
<el-input
v-model="provider"
class="filter-control"
placeholder="服务商,如 agiso"
placeholder="服务商,如 91kaquan"
clearable
@keyup.enter="applyFilters(1)"
/>
<el-input
v-model="platform"
class="filter-control"
placeholder="业务平台,如 xianyu / taobao"
placeholder="业务平台,如 kuaishou"
clearable
@keyup.enter="applyFilters(1)"
/>