2026-07-10 16:45:55 +08:00
|
|
|
<script setup lang="ts">
|
2026-07-23 15:10:13 +08:00
|
|
|
import { onMounted, ref } from 'vue'
|
2026-07-10 16:45:55 +08:00
|
|
|
import { useRouter } from 'vue-router'
|
2026-07-23 15:10:13 +08:00
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
2026-07-10 16:45:55 +08:00
|
|
|
import DataTablePage from '@/components/DataTablePage.vue'
|
2026-07-23 15:10:13 +08:00
|
|
|
import { deleteDataProcessTask, getDataProcessTasks } from '@/api/modules/dataProcess'
|
|
|
|
|
import type { DataProcessTask, DataProcessType } from '@/types/dataProcess'
|
2026-07-10 16:45:55 +08:00
|
|
|
|
2026-07-27 09:50:26 +08:00
|
|
|
type TaskStatusTagType = 'success' | 'warning' | 'info' | 'danger' | 'primary'
|
|
|
|
|
|
2026-07-23 15:10:13 +08:00
|
|
|
const processTypeMap: Record<DataProcessType, string> = {
|
2026-07-13 11:47:33 +08:00
|
|
|
structured: '结构化数据',
|
|
|
|
|
unstructured: '非结构化数据',
|
|
|
|
|
external: '外来数据源拉取',
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-10 16:45:55 +08:00
|
|
|
const router = useRouter()
|
2026-07-23 15:10:13 +08:00
|
|
|
const dataList = ref<DataProcessTask[]>([])
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
const deletingId = ref<string | number | null>(null)
|
|
|
|
|
const loadError = ref('')
|
2026-07-10 16:45:55 +08:00
|
|
|
|
2026-07-23 15:10:13 +08:00
|
|
|
async function loadData(silent = false) {
|
|
|
|
|
if (!silent) loading.value = true
|
|
|
|
|
loadError.value = ''
|
|
|
|
|
try {
|
|
|
|
|
const response = await getDataProcessTasks({ page: 1, page_size: 200 })
|
|
|
|
|
dataList.value = response.items
|
|
|
|
|
} catch {
|
|
|
|
|
loadError.value = '数据处理任务加载失败,请稍后重试。'
|
|
|
|
|
} finally {
|
|
|
|
|
if (!silent) loading.value = false
|
|
|
|
|
}
|
2026-07-10 16:45:55 +08:00
|
|
|
}
|
|
|
|
|
|
2026-07-13 11:04:55 +08:00
|
|
|
/** 查看任务详情 */
|
|
|
|
|
function viewDetail(row: unknown) {
|
|
|
|
|
const taskId = (row as { id: string | number }).id
|
|
|
|
|
router.push({ name: 'data-process-detail', params: { id: taskId } })
|
2026-07-10 16:45:55 +08:00
|
|
|
}
|
|
|
|
|
|
2026-07-23 15:10:13 +08:00
|
|
|
/** 删除由后端再次校验任务状态以及发布锁。 */
|
|
|
|
|
async function handleDelete(row: DataProcessTask) {
|
|
|
|
|
try {
|
|
|
|
|
await ElMessageBox.confirm(
|
|
|
|
|
`确定删除数据处理任务“${row.name}”吗?删除后无法恢复。`,
|
|
|
|
|
'确认删除',
|
|
|
|
|
{
|
|
|
|
|
type: 'warning',
|
|
|
|
|
confirmButtonText: '删除',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
confirmButtonClass: 'el-button--danger',
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
} catch {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deletingId.value = row.id
|
|
|
|
|
try {
|
|
|
|
|
await deleteDataProcessTask(row.id)
|
|
|
|
|
dataList.value = dataList.value.filter((item) => item.id !== row.id)
|
|
|
|
|
ElMessage.success('数据处理任务已删除')
|
|
|
|
|
} catch {
|
|
|
|
|
// 统一请求层已展示后端返回的失败原因。
|
|
|
|
|
} finally {
|
|
|
|
|
deletingId.value = null
|
|
|
|
|
}
|
2026-07-10 16:45:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatDateTime(value?: string) {
|
|
|
|
|
if (!value) return '-'
|
2026-07-23 15:10:13 +08:00
|
|
|
const date = new Date(value)
|
|
|
|
|
return Number.isNaN(date.getTime()) ? value : date.toLocaleString('zh-CN', { hour12: false })
|
2026-07-10 16:45:55 +08:00
|
|
|
}
|
2026-07-23 15:10:13 +08:00
|
|
|
|
2026-07-27 09:50:26 +08:00
|
|
|
function safeCount(value: unknown) {
|
|
|
|
|
const count = Number(value)
|
|
|
|
|
return Number.isFinite(count) ? Math.max(0, Math.trunc(count)) : 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function documentCountLabel(task: DataProcessTask) {
|
|
|
|
|
return `${safeCount(task.source_file_count)} 个`
|
2026-07-23 15:10:13 +08:00
|
|
|
}
|
|
|
|
|
|
2026-07-27 09:50:26 +08:00
|
|
|
function generatedCountLabel(task: DataProcessTask) {
|
|
|
|
|
return `${safeCount(task.output_count)} 条`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 将当前轮生成状态与发布指针合并为用户可理解的列表状态。 */
|
|
|
|
|
function taskDisplayStatus(task: DataProcessTask): { label: string; type: TaskStatusTagType } {
|
|
|
|
|
if (task.status === 'running') return { label: '生成中', type: 'primary' }
|
|
|
|
|
if (task.status === 'completed') {
|
|
|
|
|
return task.output_dataset_id
|
|
|
|
|
? { label: '已发布', type: 'success' }
|
|
|
|
|
: { label: '已生成', type: 'warning' }
|
|
|
|
|
}
|
|
|
|
|
if (task.status === 'failed') return { label: '生成失败', type: 'danger' }
|
|
|
|
|
if (task.status === 'stopped') return { label: '已停止', type: 'info' }
|
|
|
|
|
return { label: '待生成', type: 'info' }
|
2026-07-23 15:10:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(loadData)
|
2026-07-10 16:45:55 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div class="data-process-page" style="height: 100%;">
|
|
|
|
|
<DataTablePage
|
|
|
|
|
title=""
|
2026-07-10 23:57:07 +08:00
|
|
|
:data="dataList"
|
2026-07-23 15:10:13 +08:00
|
|
|
:loading="loading"
|
2026-07-10 16:45:55 +08:00
|
|
|
searchable
|
|
|
|
|
:search-fields="['name']"
|
2026-07-13 16:39:16 +08:00
|
|
|
create-text="新建数据处理"
|
2026-07-10 16:45:55 +08:00
|
|
|
create-to="/data-process/create"
|
|
|
|
|
row-key="id"
|
|
|
|
|
:page-size="10"
|
2026-07-23 15:10:13 +08:00
|
|
|
:empty-text="loadError || '暂无数据处理任务'"
|
2026-07-10 16:45:55 +08:00
|
|
|
>
|
|
|
|
|
<template #columns>
|
2026-07-11 10:39:54 +08:00
|
|
|
<el-table-column label="任务ID" prop="id" align="center" width="100" />
|
2026-07-10 16:45:55 +08:00
|
|
|
<el-table-column label="任务名称" prop="name" align="center" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="任务状态" align="center" width="110">
|
|
|
|
|
<template #default="{ row }">
|
2026-07-27 09:50:26 +08:00
|
|
|
<el-tag
|
|
|
|
|
:type="taskDisplayStatus(row as DataProcessTask).type"
|
|
|
|
|
size="small"
|
|
|
|
|
effect="light"
|
|
|
|
|
>{{ taskDisplayStatus(row as DataProcessTask).label }}</el-tag>
|
2026-07-10 16:45:55 +08:00
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="处理类型" align="center" width="140">
|
2026-07-13 11:47:33 +08:00
|
|
|
<template #default="{ row }">
|
|
|
|
|
<el-tag v-if="row.process_type" size="small" type="info" effect="plain">
|
2026-07-23 15:10:13 +08:00
|
|
|
{{ processTypeMap[row.process_type as DataProcessType] || row.process_type }}
|
2026-07-13 11:47:33 +08:00
|
|
|
</el-tag>
|
|
|
|
|
<span v-else>-</span>
|
|
|
|
|
</template>
|
2026-07-10 16:45:55 +08:00
|
|
|
</el-table-column>
|
2026-07-27 09:50:26 +08:00
|
|
|
<el-table-column label="文档数量" align="center" width="120">
|
|
|
|
|
<template #default="{ row }">{{ documentCountLabel(row as DataProcessTask) }}</template>
|
2026-07-10 16:45:55 +08:00
|
|
|
</el-table-column>
|
2026-07-27 09:50:26 +08:00
|
|
|
<el-table-column label="生成个数" align="center" width="120">
|
|
|
|
|
<template #default="{ row }">{{ generatedCountLabel(row as DataProcessTask) }}</template>
|
2026-07-10 16:45:55 +08:00
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="创建时间" align="center" width="190">
|
2026-07-23 15:10:13 +08:00
|
|
|
<template #default="{ row }">{{ formatDateTime(row.create_time || row.created_at) }}</template>
|
2026-07-10 16:45:55 +08:00
|
|
|
</el-table-column>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<template #actions="{ row }">
|
|
|
|
|
<div class="action-buttons">
|
|
|
|
|
<el-button type="primary" link size="small" @click="viewDetail(row)">
|
|
|
|
|
<i class="fa fa-file-text-o" style="margin-right: 4px" />详情
|
|
|
|
|
</el-button>
|
2026-07-23 15:10:13 +08:00
|
|
|
<el-button
|
|
|
|
|
type="danger"
|
|
|
|
|
link
|
|
|
|
|
size="small"
|
|
|
|
|
:loading="deletingId === row.id"
|
|
|
|
|
@click="handleDelete(row as DataProcessTask)"
|
|
|
|
|
>
|
2026-07-10 16:45:55 +08:00
|
|
|
<i class="fa fa-trash-o" style="margin-right: 4px" />删除
|
|
|
|
|
</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</DataTablePage>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
.action-buttons {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|