import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' import { fileURLToPath } from 'node:url' import path from 'node:path' import { parse as parseSfc } from '@vue/compiler-sfc' import { dataProcessDisplayStatus } from '../src/utils/dataProcessStatus.js' const scriptDir = path.dirname(fileURLToPath(import.meta.url)) const sourceRoot = path.resolve(scriptDir, '../src') const viewPath = path.join(sourceRoot, 'views/data-process/DataProcessListView.vue') const [source, apiSource] = await Promise.all([ readFile(viewPath, 'utf8'), readFile(path.join(sourceRoot, 'api/modules/dataProcess.ts'), 'utf8'), ]) const { descriptor, errors } = parseSfc(source, { filename: viewPath }) assert.equal(errors.length, 0, `数据处理任务列表模板无法解析:${errors[0]}`) assert.ok(descriptor.template?.content.trim(), '数据处理任务列表缺少可渲染模板') assert.match(source, /:data="dataList"/, '任务表格必须直接展示完整任务数据') assert.doesNotMatch(source, /activeTab|filteredDataList/, '不应保留状态切换筛选逻辑') assert.doesNotMatch(source, /全部任务|处理中|已完成/, '不应保留状态切换按钮文案') assert.doesNotMatch(source, /capsule-tabs|capsule-tab-item/, '不应保留状态切换专用样式') assert.ok(source.includes("getDataProcessTasks({ page: 1, page_size: 200"), '列表没有通过真实 API 分页加载任务') assert.match(source, /usePolling\([\s\S]*?\(\) => loadData\(true\)[\s\S]*?3000/, '列表没有静默轮询运行中任务') assert.match( source, /item\.status === 'running'[\s\S]*?item\.preview_status === 'running'[\s\S]*?item\.preview_status === 'queued'[\s\S]*?startPolling\(\)[\s\S]*?stopPolling\(\)/, '列表轮询没有同时覆盖后台生成与后台切分', ) assert.doesNotMatch(source, /toolbar-extra|refreshData|refreshing|fa-refresh/, '列表不应显示手动刷新按钮') assert.ok(source.includes('ElMessageBox.confirm('), '删除任务前缺少二次确认') assert.ok(source.includes('await deleteDataProcessTask(row.id)'), '删除操作没有调用真实 API') assert.ok(!source.includes('TODO: 接入真实接口'), '列表仍包含本地 Mock 任务') assert.ok(source.includes('const dataList = ref([])'), '任务列表必须以空数组初始化并等待真实 API 数据') assert.match(source, /label="文档数量"[\s\S]*?documentCountLabel\(row as DataProcessTask\)/, '任务列表没有展示真实文档数量') assert.match(source, /function documentCountLabel\(task: DataProcessTask\)[\s\S]*?`\$\{safeCount\(task\.source_file_count\)\} 个`/, '文档数量没有使用 source_file_count 或缺少单位') assert.match(source, /label="生成个数"[\s\S]*?generatedCountLabel\(row as DataProcessTask\)/, '任务列表没有展示真实生成数量') assert.match(source, /function generatedCountLabel\(task: DataProcessTask\)[\s\S]*?`\$\{safeCount\(task\.output_count\)\} 条`/, '生成数量没有使用 output_count 或缺少单位') assert.doesNotMatch(source, /label="源数据集"|label="输出数据集"/, '任务列表仍使用旧的数据集列标题') assert.match(source, /import \{ dataProcessDisplayStatus \} from '@\/utils\/dataProcessStatus\.js'/, '任务列表没有复用数据处理六态映射') assert.match(source, /dataProcessDisplayStatus\(row as DataProcessTask\)\.type[\s\S]*?dataProcessDisplayStatus\(row as DataProcessTask\)\.label/, '任务列表状态标签没有使用公共映射') const statusCases = [ [{ status: 'pending' }, { label: '待生成', type: 'info' }], [{ status: 'pending', preview_status: 'queued' }, { label: '切分中', type: 'primary' }], [{ status: 'pending', preview_status: 'running' }, { label: '切分中', type: 'primary' }], [{ status: 'running' }, { label: '生成中', type: 'primary' }], [{ status: 'completed', results_confirmed: false }, { label: '待确认', type: 'warning' }], [{ status: 'completed' }, { label: '已生成', type: 'warning' }], [{ status: 'completed', output_datasets: [{ id: 'old-train' }] }, { label: '已生成', type: 'warning' }], [{ status: 'completed', output_dataset_id: 'current-train' }, { label: '已发布', type: 'success' }], [{ status: 'failed' }, { label: '生成失败', type: 'danger' }], [{ status: 'stopped' }, { label: '已停止', type: 'info' }], ] for (const [task, expected] of statusCases) { assert.deepEqual(dataProcessDisplayStatus(task), expected, `任务六态映射错误:${task.status}`) } assert.match(source, /task\.status === 'completed' && task\.results_confirmed !== false[\s\S]*?'data-process-detail'[\s\S]*?'data-process-workflow'/, '详情入口没有区分已确认详情与未完成工作流') assert.doesNotMatch(source, /stopDataProcess|\/stop\b|停止生成|停止任务/, '列表不应暴露删除以外的任务终止入口') assert.match(apiSource, /export (?:async )?function getDataProcessTasks/, 'API 模块缺少任务列表方法') assert.match(apiSource, /export const deleteDataProcessTask/, 'API 模块缺少任务删除方法') assert.ok(apiSource.includes("get>('/data-process', params)"), '任务列表 API 路径或分页契约不正确') assert.ok(apiSource.includes('`/data-process/${encodeURIComponent(taskId)}`'), '任务详情资源路径没有安全编码任务 ID') console.log('数据处理任务列表真实 API 回归检查通过')