Files
order_site/apps/frontend/src/views/admin/message-deliveries/AdminMessageDeliveriesView.vue
T

278 lines
9.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, 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)
}
</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>