feat: CellData 容量处理集成改进与前端处理进度优化

This commit is contained in:
2026-06-25 14:27:15 +08:00
parent 1f9074eb41
commit 5a5c08d823
5 changed files with 74 additions and 4 deletions
+16 -1
View File
@@ -151,7 +151,7 @@ def _run_remote_processing(
state.history_manager.update(task_id, file_count=download_result.file_count)
refresh_cell_data(app_config, work_dir, logger)
_try_refresh_cell_data(app_config, work_dir, logger)
if app_config.warehouse_type == "metrix":
started = time.time()
@@ -210,6 +210,21 @@ def _run_remote_processing(
on_finish(task_id, final_status)
def _try_refresh_cell_data(app_config: AppConfig, work_dir: Path, logger: ProcessLogger) -> None:
if not app_config.cell_data.remote_data.enabled:
return
logger.set_stage("cell_data")
logger.info("── CellData 更新 ──")
try:
result = refresh_cell_data(app_config, work_dir, logger)
logger.success(
f"CellData 更新完成:{result.imported_rows} 行"
f"(解析 {result.parsed_rows},跳过 {result.skipped_rows})"
)
except Exception as exc:
logger.warning(f"CellData 更新失败,继续容量处理: {exc}")
def _format_bytes(size: int) -> str:
value = float(size)
for unit in ("B", "KB", "MB", "GB"):
+16 -1
View File
@@ -169,7 +169,7 @@ def _task_finished(task_id: str) -> bool:
def _run_processing(task_id: str, work_dir: Path, logger: ProcessLogger, app_config: AppConfig) -> None:
try:
refresh_cell_data(app_config, work_dir, logger)
_try_refresh_cell_data(app_config, work_dir, logger)
if app_config.warehouse_type == "metrix":
import time
@@ -214,3 +214,18 @@ def _run_processing(task_id: str, work_dir: Path, logger: ProcessLogger, app_con
finally:
apply_history_retention_safely()
state.reset_task_lock()
def _try_refresh_cell_data(app_config: AppConfig, work_dir: Path, logger: ProcessLogger) -> None:
if not app_config.cell_data.remote_data.enabled:
return
logger.set_stage("cell_data")
logger.info("── CellData 更新 ──")
try:
result = refresh_cell_data(app_config, work_dir, logger)
logger.success(
f"CellData 更新完成:{result.imported_rows} 行"
f"(解析 {result.parsed_rows},跳过 {result.skipped_rows})"
)
except Exception as exc:
logger.warning(f"CellData 更新失败,继续容量处理: {exc}")
+8
View File
@@ -846,3 +846,11 @@
- `/api/remote/test`、`/api/config/cell-data/remote/test`、`/api/config/cell-data/mysql/test` 改为同步路由函数,保持响应结构不变,但让 FastAPI 在线程池中执行 FTP/SFTP、Metrix 平台 HTTP 与 MySQL 连接测试,避免慢连接或超时阻塞事件循环。
- 验证:`.venv\Scripts\python.exe -m compileall -q app` 通过;`frontend` `npm run build` 通过;构建产物已清理。
## 2026-06-25:CellData 容量处理集成改进与前端处理进度优化
- 容量处理集成:`tasks.py` 和 `remote.py` 中的 `refresh_cell_data()` 调用改为 `_try_refresh_cell_data()` 包装函数,CellData 数据源未启用时直接跳过,CellData 处理失败时记录警告但继续执行容量处理,不再因 CellData SFTP 连接失败或无数据等原因导致整个容量处理任务失败。
- CellData 阶段标识:容量处理流程中 CellData 更新阶段会设置独立的 `cell_data` stage,前端可显示"更新 CellData..."状态文案;CellData 完成后日志输出导入行数、解析行数和跳过行数摘要。
- 前端阶段标签:`stageLabels` 新增 `cell_data: '更新 CellData...'`;`importing` 标签从"上传数据中..."改为"导入数据中..."以避免与文件上传混淆。
- 前端结果摘要:CellData 独立处理或容量处理完成后,处理进度区域显示成功摘要(文件数、导入行数、跳过行数、耗时);`TaskStatus` 类型新增 `result?: CellDataResult` 字段。
- 验证:`python -m compileall -q app` 通过;`frontend` `npm run build`(vue-tsc)通过;构建产物已清理。
+26 -2
View File
@@ -213,6 +213,9 @@
<n-alert v-if="activeTask?.has_active" type="info" :bordered="false" class="task-alert">
当前任务:{{ activeTask.task_id }} / {{ currentStageText }}
</n-alert>
<n-alert v-if="taskStatus?.status === 'completed' && taskResultSummary" type="success" :bordered="false" class="task-alert">
{{ taskResultSummary }}
</n-alert>
<n-alert v-if="taskStatus?.error" type="error" :bordered="false" class="task-alert">
{{ taskStatus.error }}
</n-alert>
@@ -326,7 +329,7 @@ import {
} from '@vicons/ionicons5';
import { ApiRequestError, apiGet, apiPost, upload } from '../api/client';
import type { ActiveTask, ApiErrorDetail, LicenseStatus, TaskStatus } from '../types';
import type { ActiveTask, ApiErrorDetail, CellDataResult, LicenseStatus, TaskStatus } from '../types';
import { toColoredLogLines } from '../composables/logLines';
type FileStatus = 'pending' | 'uploading' | 'uploaded' | 'error';
@@ -380,6 +383,7 @@ let timer: number | undefined;
const stageLabels: Record<string, string> = {
license: '授权校验中...',
cell_data: '更新 CellData...',
locating: '定位数据中...',
downloading: '远程下载中...',
uploading: '上传文件中...',
@@ -387,7 +391,7 @@ const stageLabels: Record<string, string> = {
extracting: '解压数据中...',
converting: '转换 Excel 中...',
parsing: '解析数据中...',
importing: '上传数据中...',
importing: '导入数据中...',
scripting: '运行脚本中...',
completed: '处理完成',
failed: '处理失败'
@@ -420,6 +424,18 @@ const processStatusText = computed(() => {
if (taskStatus.value?.status === 'failed') return '处理失败';
return currentStageText.value;
});
const taskResultSummary = computed(() => {
const status = taskStatus.value;
if (!status || status.status !== 'completed') return '';
const parts: string[] = [];
if (status.result) {
parts.push(formatCellDataResult(status.result));
}
if (status.elapsed_time != null) {
parts.push(`耗时 ${status.elapsed_time.toFixed(1)}s`);
}
return parts.join(',');
});
watch(
() => taskStatus.value?.logs?.length ?? 0,
@@ -969,6 +985,14 @@ function fileStatusText(item: PickedFile): string {
return '等待上传';
}
function formatCellDataResult(result: CellDataResult): string {
const parts: string[] = [];
if (result.selected_files > 0) parts.push(`${result.selected_files} 个文件`);
parts.push(`导入 ${result.imported_rows} 行`);
if (result.skipped_rows > 0) parts.push(`跳过 ${result.skipped_rows} 行`);
return parts.join(',');
}
function formatBytes(size: number): string {
if (size === 0) return '0 B';
const units = ['B', 'KB', 'MB', 'GB'];
+8
View File
@@ -27,6 +27,13 @@ export interface LicenseStatus {
zip_count?: number;
}
export interface CellDataResult {
selected_files: number;
parsed_rows: number;
imported_rows: number;
skipped_rows: number;
}
export interface TaskStatus {
task_id: string;
status: 'pending' | 'processing' | 'completed' | 'failed' | string;
@@ -35,6 +42,7 @@ export interface TaskStatus {
elapsed_time?: number;
error?: string;
error_detail?: ApiErrorDetail;
result?: CellDataResult;
}
export interface ActiveTask {