diff --git a/package-lock.json b/package-lock.json index f9c205e..2cb4ab4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,6 @@ "lucide-react": "^0.575.0", "mssql": "^12.2.0", "mysql2": "^3.18.2", - "playwright": "^1.58.2", "reflect-metadata": "^0.2.2", "typeorm": "^0.3.28", "uuid": "^13.0.0", @@ -47,6 +46,7 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", + "playwright": "^1.58.2", "postcss": "^8.5.6", "prettier": "^3.7.4", "react": "^19.2.1", @@ -105,7 +105,6 @@ "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz", "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==", "license": "MIT", - "peer": true, "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", @@ -167,7 +166,6 @@ "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz", "integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==", "license": "MIT", - "peer": true, "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.10.0", @@ -359,7 +357,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -1128,6 +1125,7 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, + "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -1149,6 +1147,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -1165,6 +1164,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -1179,6 +1179,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -3053,7 +3054,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz", "integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -3076,7 +3076,6 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -3185,7 +3184,6 @@ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", @@ -3619,7 +3617,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3652,7 +3649,6 @@ "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4400,7 +4396,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5105,7 +5100,8 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -5464,7 +5460,6 @@ "integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", @@ -5691,7 +5686,6 @@ "integrity": "sha512-Rz5QvP1pTqoU1DPRrG3EeX2oWBtS3uRmd6Z/wzZsb2e/iIUsrT+XcBaAhFr4FW48gDc8uP2wYVyY5Aamha/5Zg==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^22.7.7", @@ -5880,6 +5874,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -5900,6 +5895,7 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -6228,7 +6224,6 @@ "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6289,7 +6284,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -10061,7 +10055,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -10073,6 +10066,7 @@ "version": "1.58.2", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "dev": true, "license": "Apache-2.0", "dependencies": { "playwright-core": "1.58.2" @@ -10091,6 +10085,7 @@ "version": "1.58.2", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -10142,7 +10137,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -10166,6 +10160,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -10183,6 +10178,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -10203,7 +10199,6 @@ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -10336,7 +10331,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -11624,6 +11618,7 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -12141,7 +12136,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12376,7 +12370,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -12923,7 +12916,6 @@ "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", @@ -13132,7 +13124,6 @@ "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", "license": "MIT", - "peer": true, "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.8", @@ -13370,7 +13361,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 204c647..6e927f3 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "lucide-react": "^0.575.0", "mssql": "^12.2.0", "mysql2": "^3.18.2", - "playwright": "^1.58.2", "reflect-metadata": "^0.2.2", "typeorm": "^0.3.28", "uuid": "^13.0.0", @@ -65,6 +64,7 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", + "playwright": "^1.58.2", "postcss": "^8.5.6", "prettier": "^3.7.4", "react": "^19.2.1", diff --git a/src/main/.env.backup b/src/main/.env.backup new file mode 100644 index 0000000..052a4e9 --- /dev/null +++ b/src/main/.env.backup @@ -0,0 +1,78 @@ +# =========================== +# ERP 系统配置 +# =========================== +ERP_URL=https://68.11.34.30:8082/ +ERP_USERNAME= +ERP_PASSWORD= +ERP_HEADLESS=true +ERP_IGNORE_HTTPS_ERRORS=true +ERP_AUTO_CLOSE_BROWSER=true + +# =========================== +# 数据库配置 - SQL Server +# =========================== +# DB_TYPE=sqlserver +# DB_SERVER= +# DB_NAME=BLD_DB +# DB_USERNAME=remote_user +# DB_PASSWORD= +DB_SQLSERVER_DRIVER=ODBC Driver 18 for SQL Server +DB_TRUST_SERVER_CERTIFICATE=yes + +# =========================== +# 数据库配置 - MySQL (切换时使用) +# =========================== +DB_TYPE=mysql +DB_NAME=BLD_DB +DB_USERNAME=remote_user +DB_PASSWORD= +DB_MYSQL_HOST=192.168.31.83 +DB_MYSQL_PORT=3306 +DB_MYSQL_CHARSET=utf8mb4 + +# 订单号解析表配置 +# 表名:包含 productionID 和 生产订单号 映射关系的表 +DB_TABLE_NAME=productionContractData_26年压力表合同数据 +# 字段名:总排号 (对应 productionID) +DB_FIELD_PRODUCTION_ID=总排号 +# 字段名:生产订单号 (对应生产订单号) +DB_FIELD_ORDER_NUMBER=生产订单号 + +# =========================== +# 路径配置 +# =========================== +PATH_DATA_DIR=D:/python/playwrite/data/ +PATH_PRODUCTION_ID_FILE=ProductionID.txt +PATH_DEFAULT_OUTPUT=离散备料计划维护_合并.xlsx +PATH_VALIDATION_OUTPUT=物料状态校验结果.xlsx + +# =========================== +# 数据提取配置 +# =========================== +EXTRACTION_BATCH_SIZE=100 +EXTRACTION_VERBOSE=true +EXTRACTION_AUTO_CONVERT=true +EXTRACTION_MERGE_BATCHES=true +EXTRACTION_ENABLE_DB_PERSISTENCE=true + +# =========================== +# 校验配置 +# =========================== +VALIDATION_DATA_SOURCE=database_full +VALIDATION_USE_DATABASE=true +VALIDATION_BATCH_SIZE=2000 +VALIDATION_ENABLE_CRUD=false +VALIDATION_DEFAULT_MANAGER= +VALIDATION_MATCH_MODE=substring + +# =========================== +# UI 配置 +# =========================== +UI_FONT_FAMILY=Microsoft YaHei UI +UI_FONT_SIZE=10 +UI_PRODUCTION_ID_INPUT_WIDTH=20 + +# =========================== +# 执行配置 +# =========================== +EXECUTION_DRYRUN=false \ No newline at end of file diff --git a/src/renderer/src/components/ui/LogPanel.tsx b/src/renderer/src/components/ui/LogPanel.tsx new file mode 100644 index 0000000..51809dc --- /dev/null +++ b/src/renderer/src/components/ui/LogPanel.tsx @@ -0,0 +1,67 @@ +import React, { useEffect, useRef } from 'react' +import { Terminal } from 'lucide-react' +import type { LogEntry, LogLevel, ExtractorProgress } from '../../hooks/useExtractor' + +interface LogPanelProps { + logs: LogEntry[] + progress: ExtractorProgress | null + onClear: () => void +} + +const getLogColor = (level: LogLevel): string => { + switch (level) { + case 'error': + return 'text-red-400' + case 'warning': + return 'text-amber-400' + case 'success': + return 'text-emerald-400' + case 'system': + return 'text-blue-400' + default: + return 'text-slate-400' + } +} + +const LogPanel: React.FC = ({ logs, progress, onClear }) => { + const logsEndRef = useRef(null) + + useEffect(() => { + logsEndRef.current?.scrollIntoView({ behavior: 'smooth' }) + }, [logs]) + + return ( +
+
+
+ + 执行日志 +
+
+ 进度: {progress?.progress || 0}% + +
+
+
+ {logs.length === 0 ? ( +
等待执行...
+ ) : ( + logs.map((log, index) => ( +
+ [{log.timestamp}]{' '} + [{log.level.toUpperCase()}] {log.message} +
+ )) + )} +
+
+
+ ) +} + +export default LogPanel diff --git a/src/renderer/src/hooks/useExtractor.ts b/src/renderer/src/hooks/useExtractor.ts index 0bf54e0..c123a5b 100644 --- a/src/renderer/src/hooks/useExtractor.ts +++ b/src/renderer/src/hooks/useExtractor.ts @@ -1,77 +1,94 @@ -/** - * IPC Hook for Extractor operations - * - * Provides a React-friendly interface for extractor IPC calls - * with loading state, error handling, and data management. - */ +import { useState, useEffect } from 'react' -import { useState, useCallback } from 'react' - -// Types based on the extractor types -interface ExtractorInput { - orderNumbers: string[] - batchSize?: number +export interface ExtractorProgress { + message: string + progress: number } -interface ExtractorResult { - data: Record[] - errors: string[] +export type LogLevel = 'info' | 'success' | 'warning' | 'error' | 'system' + +export interface LogEntry { + timestamp: string + level: LogLevel + message: string } -interface UseExtractorState { - loading: boolean - data: ExtractorResult | null - error: string | null -} +export function useExtractor() { + const [isRunning, setIsRunning] = useState(false) + const [progress, setProgress] = useState(null) + const [error, setError] = useState(null) + const [logs, setLogs] = useState([]) -interface UseExtractorReturn extends UseExtractorState { - execute: (input: ExtractorInput) => Promise - reset: () => void -} + const addLog = (level: LogLevel, message: string) => { + const timestamp = new Date().toLocaleTimeString('zh-CN', { hour12: false }) + setLogs((prev) => [...prev, { timestamp, level, message }]) + } -/** - * Hook for executing extractor operations - */ -export function useExtractor(): UseExtractorReturn { - const [state, setState] = useState({ - loading: false, - data: null, - error: null - }) + useEffect(() => { + if (progress) { + addLog('info', progress.message) + } + }, [progress]) - const execute = useCallback(async (input: ExtractorInput): Promise => { - setState({ loading: true, data: null, error: null }) + const clearLogs = () => { + setLogs([]) + } + + const startExtraction = async (orderNumbers: string) => { + if (!orderNumbers.trim()) { + setError('请输入至少一个订单号') + return + } + + setIsRunning(true) + setProgress(null) + setError(null) + setLogs([]) + + addLog('system', '提取引擎启动,准备执行...') try { - const result = (await window.electron.ipcRenderer.invoke('extractor:run', input)) as { - success: boolean - data?: ExtractorResult - error?: string - } + const orderNumberList = orderNumbers + .split('\n') + .map((line) => line.trim()) + .filter((line) => line.length > 0) - if (result.success && result.data) { - setState({ loading: false, data: result.data, error: null }) - return result.data + await window.electron.validation.setSharedProductionIds(orderNumberList) + addLog('info', `已存储 ${orderNumberList.length} 个订单号用于跨模块共享`) + + const response = await window.electron.extractor.runExtractor({ + orderNumbers: orderNumberList + }) + + if (response.success && response.data) { + addLog( + 'success', + `提取完成:下载 ${response.data.downloadedFiles.length} 个文件,共 ${response.data.recordCount} 条记录` + ) + if (response.data.errors.length > 0) { + addLog('warning', `存在 ${response.data.errors.length} 个错误`) + } } else { - setState({ loading: false, data: null, error: result.error || 'Unknown error' }) - return null + setError(response.error || '提取失败') + addLog('error', response.error || '提取失败') } - } catch (error) { - const message = error instanceof Error ? error.message : 'Unknown error' - setState({ loading: false, data: null, error: message }) - return null + } catch (err) { + const errMsg = err instanceof Error ? err.message : '发生未知错误' + setError(errMsg) + addLog('error', errMsg) + } finally { + setIsRunning(false) + setProgress(null) } - }, []) - - const reset = useCallback(() => { - setState({ loading: false, data: null, error: null }) - }, []) + } return { - ...state, - execute, - reset + isRunning, + progress, + error, + logs, + startExtraction, + clearLogs, + setError } } - -export default useExtractor diff --git a/src/renderer/src/pages/ExtractorPage.tsx b/src/renderer/src/pages/ExtractorPage.tsx index fdb840b..dc9b788 100644 --- a/src/renderer/src/pages/ExtractorPage.tsx +++ b/src/renderer/src/pages/ExtractorPage.tsx @@ -1,44 +1,23 @@ -import React, { useState, useEffect, useRef } from 'react' -import { Download, Play, Terminal } from 'lucide-react' +import React, { useState, useEffect } from 'react' +import { Download, Play } from 'lucide-react' import OrderNumberInput from '../components/OrderNumberInput' - -interface ExtractorProgress { - message: string - progress: number -} - -type LogLevel = 'info' | 'success' | 'warning' | 'error' | 'system' - -interface LogEntry { - timestamp: string - level: LogLevel - message: string -} - -const getLogColor = (level: LogLevel): string => { - switch (level) { - case 'error': - return 'text-red-400' - case 'warning': - return 'text-amber-400' - case 'success': - return 'text-emerald-400' - case 'system': - return 'text-blue-400' - default: - return 'text-slate-400' - } -} +import { useExtractor } from '../hooks/useExtractor' +import LogPanel from '../components/ui/LogPanel' const ExtractorPage: React.FC = () => { const [orderNumbers, setOrderNumbers] = useState(() => { return sessionStorage.getItem('extractor_orderNumbers') || '' }) - const [isRunning, setIsRunning] = useState(false) - const [progress, setProgress] = useState(null) - const [error, setError] = useState(null) - const [logs, setLogs] = useState([]) - const logsEndRef = useRef(null) + + const { + isRunning, + progress, + error, + logs, + startExtraction, + clearLogs, + setError + } = useExtractor() useEffect(() => { sessionStorage.setItem('extractor_orderNumbers', orderNumbers) @@ -51,74 +30,14 @@ const ExtractorPage: React.FC = () => { } }, [orderNumbers]) - useEffect(() => { - logsEndRef.current?.scrollIntoView({ behavior: 'smooth' }) - }, [logs]) - - const addLog = (level: LogLevel, message: string) => { - const timestamp = new Date().toLocaleTimeString('zh-CN', { hour12: false }) - setLogs((prev) => [...prev, { timestamp, level, message }]) + const handleExtract = () => { + startExtraction(orderNumbers) } - const handleExtract = async () => { - if (!orderNumbers.trim()) { - setError('请输入至少一个订单号') - return - } - - setIsRunning(true) - setProgress(null) - setError(null) - setLogs([]) - - addLog('system', '提取引擎启动,准备执行...') - - try { - const orderNumberList = orderNumbers - .split('\n') - .map((line) => line.trim()) - .filter((line) => line.length > 0) - - await window.electron.validation.setSharedProductionIds(orderNumberList) - addLog('info', `已存储 ${orderNumberList.length} 个订单号用于跨模块共享`) - - const response = await window.electron.extractor.runExtractor({ - orderNumbers: orderNumberList - }) - - if (response.success && response.data) { - addLog( - 'success', - `提取完成:下载 ${response.data.downloadedFiles.length} 个文件,共 ${response.data.recordCount} 条记录` - ) - if (response.data.errors.length > 0) { - addLog('warning', `存在 ${response.data.errors.length} 个错误`) - } - } else { - setError(response.error || '提取失败') - addLog('error', response.error || '提取失败') - } - } catch (err) { - const errMsg = err instanceof Error ? err.message : '发生未知错误' - setError(errMsg) - addLog('error', errMsg) - } finally { - setIsRunning(false) - setProgress(null) - } - } - - useEffect(() => { - if (progress) { - addLog('info', progress.message) - } - }, [progress]) - const handleReset = () => { setOrderNumbers('') setError(null) - setProgress(null) - setLogs([]) + clearLogs() } return ( @@ -163,36 +82,7 @@ const ExtractorPage: React.FC = () => {
-
-
-
- - 执行日志 -
-
- 进度: {progress?.progress || 0}% - -
-
-
- {logs.length === 0 ? ( -
等待执行...
- ) : ( - logs.map((log, index) => ( -
- [{log.timestamp}]{' '} - [{log.level.toUpperCase()}] {log.message} -
- )) - )} -
-
-
+
)