diff --git a/novalon-manage-web/package-lock.json b/novalon-manage-web/package-lock.json index 24566db..1d529e2 100644 --- a/novalon-manage-web/package-lock.json +++ b/novalon-manage-web/package-lock.json @@ -45,6 +45,7 @@ "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.4.26", "jsdom": "^27.4.0", + "less": "^4.6.4", "prettier": "^3.1.1", "terser": "^5.46.1", "typescript": "^5.9.3", @@ -5360,6 +5361,22 @@ "url": "https://opencollective.com/express" } }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/copy-to-clipboard": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", @@ -6011,6 +6028,20 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, "node_modules/es-abstract": { "version": "1.24.2", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", @@ -7052,6 +7083,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -7294,6 +7333,20 @@ "node": ">= 4" } }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/immutable": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", @@ -7837,6 +7890,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -8098,6 +8164,58 @@ "node": ">=0.10.0" } }, + "node_modules/less": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/less/-/less-4.6.4.tgz", + "integrity": "sha512-OJmO5+HxZLLw0RLzkqaNHzcgEAQG7C0y3aMbwtCzIUFZsLMNNq/1IdAdHEycQ58CwUO3jPTHmoN+tE5I7FQxNg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "copy-anything": "^3.0.5", + "parse-node-version": "^1.0.1" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -8364,6 +8482,20 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -8508,6 +8640,24 @@ "dev": true, "license": "MIT" }, + "node_modules/needle": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.5.0.tgz", + "integrity": "sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", @@ -8762,6 +8912,16 @@ "node": ">=6" } }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", @@ -8877,6 +9037,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/playwright": { "version": "1.58.2", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", @@ -9069,6 +9240,14 @@ "node": ">=10" } }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -10571,6 +10750,17 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "optional": true, + "engines": { + "node": ">=11.0.0" + } + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", diff --git a/novalon-manage-web/package.json b/novalon-manage-web/package.json index 18ae42f..b506da3 100644 --- a/novalon-manage-web/package.json +++ b/novalon-manage-web/package.json @@ -71,6 +71,7 @@ "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.4.26", "jsdom": "^27.4.0", + "less": "^4.6.4", "prettier": "^3.1.1", "terser": "^5.46.1", "typescript": "^5.9.3", diff --git a/novalon-manage-web/playwright.config.ts b/novalon-manage-web/playwright.config.ts index e606c23..7fc9c51 100644 --- a/novalon-manage-web/playwright.config.ts +++ b/novalon-manage-web/playwright.config.ts @@ -6,7 +6,7 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const isHeadless = process.env.PLAYWRIGHT_HEADLESS === 'true' || process.env.CI === 'true'; -const baseURL = process.env.TEST_BASE_URL || process.env.VITE_BASE_URL || 'http://localhost:3002'; +const baseURL = process.env.TEST_BASE_URL || process.env.VITE_BASE_URL || 'http://localhost:5174'; export default defineConfig({ testDir: './e2e', @@ -106,11 +106,26 @@ export default defineConfig({ } }, }, + { + name: 'uat', + testDir: './e2e/uat', + testMatch: /.*\.spec\.ts/, + use: { + ...devices['Desktop Chrome'], + launchOptions: { + args: [ + '--disable-blink-features=AutomationControlled', + '--disable-dev-shm-usage', + '--no-sandbox' + ] + } + }, + }, ], webServer: { command: 'npm run dev', - url: 'http://localhost:3002', + url: 'http://localhost:5174', reuseExistingServer: !process.env.CI, timeout: 180000, stdout: 'pipe', diff --git a/novalon-manage-web/src/hooks/useAntV.ts b/novalon-manage-web/src/hooks/useAntV.ts index 563737a..5e37d16 100644 --- a/novalon-manage-web/src/hooks/useAntV.ts +++ b/novalon-manage-web/src/hooks/useAntV.ts @@ -11,7 +11,7 @@ export function useAntV(ChartClass: new (container: HTMLElement, options?: an const initChart = useCallback( (container: HTMLDivElement) => { if (chartRef.current) { - ;(chartRef.current as any).destroy?.() + (chartRef.current as any).destroy?.() } containerRef.current = container chartRef.current = new ChartClass(container, options) @@ -21,14 +21,14 @@ export function useAntV(ChartClass: new (container: HTMLElement, options?: an const updateData = useCallback((data: any[]) => { if (chartRef.current && typeof (chartRef.current as any).changeData === 'function') { - ;(chartRef.current as any).changeData(data) + (chartRef.current as any).changeData(data) } }, []) useEffect(() => { return () => { if (antvOptions?.autoDestroy !== false && chartRef.current) { - ;(chartRef.current as any).destroy?.() + (chartRef.current as any).destroy?.() chartRef.current = null } } diff --git a/novalon-manage-web/src/pages/dashboard/index.tsx b/novalon-manage-web/src/pages/dashboard/index.tsx index 31276da..8f99201 100644 --- a/novalon-manage-web/src/pages/dashboard/index.tsx +++ b/novalon-manage-web/src/pages/dashboard/index.tsx @@ -25,10 +25,6 @@ export default function Dashboard() { const [loading, setLoading] = useState(true) const chartRef = useRef(null) - useEffect(() => { - loadDashboard() - }, []) - async function loadDashboard() { try { const [users, roles, opLogs, exLogs] = await Promise.all([ @@ -50,6 +46,10 @@ export default function Dashboard() { } } + useEffect(() => { + loadDashboard() + }, []) + if (loading) { return } diff --git a/novalon-manage-web/src/pages/file/index.tsx b/novalon-manage-web/src/pages/file/index.tsx index 28f99f5..8a22d2b 100644 --- a/novalon-manage-web/src/pages/file/index.tsx +++ b/novalon-manage-web/src/pages/file/index.tsx @@ -42,12 +42,12 @@ export default function FileManagement() { const columns: ColumnsType = [ { title: '文件名', dataIndex: 'fileName', key: 'fileName' }, { title: '类型', dataIndex: 'fileType', key: 'fileType', render: (v: string) => {v} }, - { title: '大小', dataIndex: 'fileSize', key: 'fileSize', render: (v: number) => `${(v / 1024).toFixed(1)} KB` }, - { title: '上传者', dataIndex: 'uploadedBy', key: 'uploadedBy' }, + { title: '大小', dataIndex: 'fileSize', key: 'fileSize', render: (v: string) => `${(Number(v) / 1024).toFixed(1)} KB` }, + { title: '上传者', dataIndex: 'createBy', key: 'createBy' }, { title: '上传时间', dataIndex: 'createdAt', key: 'createdAt' }, { title: '操作', key: 'action', render: (_, record) => ( - {record.mimeType?.startsWith('image/') && } + {record.fileType?.startsWith('image/') && } handleDelete(record.id)}>