详情对话框:异常明细补充后端已支持的范围筛选,执行时间行 在批次未开始时隐藏(原先显示「— → —」);核验结果提示与 页首警告统一 show-icon;删除已声明未消费的 receipt_line_kinds 类型字段(方向信息已在 receipt_kinds 名称内)。 Co-Authored-By: Claude Code <noreply@anthropic.com>
87 lines
4.7 KiB
Vue
87 lines
4.7 KiB
Vue
<script setup lang="ts">
|
|
import { ref, watch } from 'vue'
|
|
import * as api from '@/api/tplus'
|
|
import AppPagination from '@/components/table/AppPagination.vue'
|
|
import { usePagedList } from '@/composables/usePagedList'
|
|
import { handledError } from '@/utils/error'
|
|
import { formatDateTime } from '@/utils/format'
|
|
import AuditResult from './AuditResult.vue'
|
|
import { entities, scopeLabel, statuses } from './labels'
|
|
|
|
const number = defineModel<string | null>({ required: true })
|
|
const detail = ref<api.TPlusDetail | null>(null)
|
|
const loading = ref(false)
|
|
const failed = ref(false)
|
|
const errorEntityType = ref<api.EntityType>()
|
|
let sequence = 0
|
|
const { records, total, pageNum, pageSize, loading: errorsLoading, search, onPageChange, onSizeChange } =
|
|
usePagedList<api.TPlusError, api.ErrorQuery>(
|
|
(query) => api.listErrors(number.value!, query),
|
|
() => ({ entity_type: errorEntityType.value }),
|
|
)
|
|
|
|
async function load(): Promise<void> {
|
|
const current = ++sequence
|
|
const key = number.value
|
|
if (!key) return
|
|
detail.value = null
|
|
loading.value = true
|
|
failed.value = false
|
|
try {
|
|
const result = await api.getBatch(key)
|
|
if (current !== sequence) return
|
|
detail.value = result
|
|
if (result.failed_record_count) await search()
|
|
} catch (error) {
|
|
handledError(error)
|
|
if (current === sequence) failed.value = true
|
|
} finally { if (current === sequence) loading.value = false }
|
|
}
|
|
watch(number, (value) => { if (value) void load(); else sequence++ })
|
|
</script>
|
|
|
|
<template>
|
|
<el-dialog :model-value="!!number" title="T+ 任务详情" width="min(880px, 96vw)" @update:model-value="number = null">
|
|
<div v-loading="loading" class="detail-body">
|
|
<el-alert v-if="failed" type="error" title="详情加载失败,请重试" :closable="false"><el-button link @click="load">重新加载</el-button></el-alert>
|
|
<template v-if="detail">
|
|
<p class="cell-code batch-number">{{ detail.batch_no }}</p>
|
|
<el-descriptions :column="1" border>
|
|
<el-descriptions-item label="状态">{{ statuses[detail.status] }}</el-descriptions-item>
|
|
<el-descriptions-item label="范围">{{ scopeLabel(detail) }}</el-descriptions-item>
|
|
<el-descriptions-item label="创建时间">{{ formatDateTime(detail.create_time) }}</el-descriptions-item>
|
|
<el-descriptions-item v-if="detail.started_at" label="执行时间">{{ formatDateTime(detail.started_at) }} → {{ formatDateTime(detail.finished_at) }}</el-descriptions-item>
|
|
<el-descriptions-item v-if="detail.parent_batch_no" label="原批次">{{ detail.parent_batch_no }}</el-descriptions-item>
|
|
<el-descriptions-item label="数量">源记录 {{ detail.source_record_count.toLocaleString() }},新增 {{ detail.staged_record_count.toLocaleString() }},重复跳过 {{ detail.skipped_record_count.toLocaleString() }},异常 {{ detail.failed_record_count.toLocaleString() }}</el-descriptions-item>
|
|
</el-descriptions>
|
|
<p v-if="detail.status === 'QUEUED'" role="status">任务等待读取服务处理,可稍后刷新查看。</p>
|
|
<p v-if="detail.error_summary" role="alert">{{ detail.error_summary }}</p>
|
|
<AuditResult v-if="detail.audit_result" :report="detail.audit_result" />
|
|
<section v-if="detail.failed_record_count" class="errors-section" aria-label="异常明细">
|
|
<h3>异常明细</h3>
|
|
<el-select v-model="errorEntityType" clearable placeholder="全部范围" aria-label="异常范围" @change="search">
|
|
<el-option v-for="item in entities" :key="item.value" :label="item.label" :value="item.value" />
|
|
</el-select>
|
|
<el-table v-loading="errorsLoading" :data="records" empty-text="暂无异常记录">
|
|
<el-table-column label="范围" width="100"><template #default="{ row }">{{ entities.find((item) => item.value === row.entity_type)?.label ?? '任务' }}</template></el-table-column>
|
|
<el-table-column prop="source_id" label="源 ID" width="90" />
|
|
<el-table-column prop="error_message" label="异常说明" min-width="240" />
|
|
<el-table-column prop="retry_count" label="已重试" width="80" />
|
|
</el-table>
|
|
<div class="pager-scroll"><AppPagination :total="total" :page-num="pageNum" :page-size="pageSize" @page-change="onPageChange" @size-change="onSizeChange" /></div>
|
|
</section>
|
|
</template>
|
|
</div>
|
|
<template #footer><el-button @click="number = null">关闭</el-button><el-button :loading="loading" @click="load">刷新详情</el-button></template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.detail-body { min-height: 120px; }
|
|
.batch-number { overflow-wrap: anywhere; }
|
|
.errors-section { margin-top: 24px; }
|
|
.errors-section .el-select { width: 160px; margin-bottom: 12px; }
|
|
h3 { font-size: 14px; }
|
|
.pager-scroll { overflow-x: auto; }
|
|
</style>
|