Compare commits
8 Commits
14089eb64c
...
87f6229d49
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87f6229d49 | ||
|
|
c66dc2ecf8 | ||
|
|
9ac8707921 | ||
|
|
3222e03cea | ||
|
|
4364c71bf9 | ||
|
|
752cfc28a1 | ||
|
|
82d3130188 | ||
|
|
9ef1c3baa2 |
35
.env.example
Normal file
35
.env.example
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# ERP System Configuration
|
||||||
|
ERP_URL=https://your-erp-system.com
|
||||||
|
ERP_USERNAME=your_username
|
||||||
|
ERP_PASSWORD=your_password
|
||||||
|
|
||||||
|
# Additional ERP Settings
|
||||||
|
ERP_HEADLESS=true
|
||||||
|
ERP_IGNORE_HTTPS_ERRORS=true
|
||||||
|
ERP_AUTO_CLOSE_BROWSER=true
|
||||||
|
|
||||||
|
# Database Configuration - SQL Server
|
||||||
|
SQL_SERVER_HOST=localhost
|
||||||
|
SQL_SERVER_PORT=1433
|
||||||
|
SQL_SERVER_DATABASE=erp_db
|
||||||
|
SQL_SERVER_USERNAME=sa
|
||||||
|
SQL_SERVER_PASSWORD=your_password
|
||||||
|
|
||||||
|
MYSQL_HOST=localhost
|
||||||
|
MYSQL_PORT=3306
|
||||||
|
MYSQL_DATABASE=erp_db
|
||||||
|
MYSQL_USERNAME=root
|
||||||
|
MYSQL_PASSWORD=your_password
|
||||||
|
|
||||||
|
# Application Settings
|
||||||
|
LOG_LEVEL=info
|
||||||
|
DOWNLOAD_DIR=./downloads
|
||||||
|
TEMP_DIR=./temp
|
||||||
|
|
||||||
|
# Legacy configurations (if needed)
|
||||||
|
DB_SQLSERVER_DRIVER=ODBC Driver 18 for SQL Server
|
||||||
|
DB_TRUST_SERVER_CERTIFICATE=yes
|
||||||
|
DB_TYPE=mysql
|
||||||
|
DB_MYSQL_HOST=192.168.31.83
|
||||||
|
DB_MYSQL_PORT=3306
|
||||||
|
DB_MYSQL_CHARSET=utf8mb4
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -6,4 +6,6 @@ out
|
|||||||
*.log*
|
*.log*
|
||||||
|
|
||||||
#AI Agent
|
#AI Agent
|
||||||
.claude
|
.claude
|
||||||
|
|
||||||
|
.env
|
||||||
12338
package-lock.json
generated
Normal file
12338
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
package.json
23
package.json
@@ -18,20 +18,34 @@
|
|||||||
"build:unpack": "npm run build && electron-builder --dir",
|
"build:unpack": "npm run build && electron-builder --dir",
|
||||||
"build:win": "npm run build && electron-builder --win",
|
"build:win": "npm run build && electron-builder --win",
|
||||||
"build:mac": "electron-vite build && electron-builder --mac",
|
"build:mac": "electron-vite build && electron-builder --mac",
|
||||||
"build:linux": "electron-vite build && electron-builder --linux"
|
"build:linux": "electron-vite build && electron-builder --linux",
|
||||||
|
"test": "vitest",
|
||||||
|
"test:run": "vitest run",
|
||||||
|
"test:coverage": "vitest run --coverage"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron-toolkit/preload": "^3.0.2",
|
"@electron-toolkit/preload": "^3.0.2",
|
||||||
"@electron-toolkit/utils": "^4.0.0"
|
"@electron-toolkit/utils": "^4.0.0",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
|
"dotenv": "^17.3.1",
|
||||||
|
"exceljs": "^4.4.0",
|
||||||
|
"mssql": "^12.2.0",
|
||||||
|
"mysql2": "^3.18.2",
|
||||||
|
"playwright": "^1.58.2",
|
||||||
|
"uuid": "^13.0.0",
|
||||||
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
|
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
|
||||||
"@electron-toolkit/eslint-config-ts": "^3.1.0",
|
"@electron-toolkit/eslint-config-ts": "^3.1.0",
|
||||||
"@electron-toolkit/tsconfig": "^2.0.0",
|
"@electron-toolkit/tsconfig": "^2.0.0",
|
||||||
"@types/node": "^22.19.1",
|
"@playwright/test": "^1.58.2",
|
||||||
|
"@types/node": "^22.19.13",
|
||||||
"@types/react": "^19.2.7",
|
"@types/react": "^19.2.7",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
|
"@types/uuid": "^10.0.0",
|
||||||
"@vitejs/plugin-react": "^5.1.1",
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
|
"@vitest/coverage-v8": "^4.0.18",
|
||||||
"electron": "^39.2.6",
|
"electron": "^39.2.6",
|
||||||
"electron-builder": "^26.0.12",
|
"electron-builder": "^26.0.12",
|
||||||
"electron-vite": "^5.0.0",
|
"electron-vite": "^5.0.0",
|
||||||
@@ -43,6 +57,7 @@
|
|||||||
"react": "^19.2.1",
|
"react": "^19.2.1",
|
||||||
"react-dom": "^19.2.1",
|
"react-dom": "^19.2.1",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vite": "^7.2.6"
|
"vite": "^7.2.6",
|
||||||
|
"vitest": "^4.0.18"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/main/services/erp/locators.ts
Normal file
44
src/main/services/erp/locators.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* ERP Page Element Locators
|
||||||
|
* Reference: playwrite/utils/ discrete_material_plan_extractor.py
|
||||||
|
* Reference: playwrite/utils/ discrete_material_plan_cleaner.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const ERP_LOCATORS = {
|
||||||
|
// Login Page
|
||||||
|
login: {
|
||||||
|
usernameInput: '#username',
|
||||||
|
passwordInput: '#password',
|
||||||
|
submitButton: 'button[type="submit"]',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Main Frame
|
||||||
|
main: {
|
||||||
|
mainIframe: '#mainiframe',
|
||||||
|
loadingOverlay: '.loading-overlay',
|
||||||
|
contentFrame: '#contentframe',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Extractor (Data Export) Page
|
||||||
|
extractor: {
|
||||||
|
orderNumberInput: 'input[name="orderNumber"]',
|
||||||
|
queryButton: 'button:has-text("查询")',
|
||||||
|
exportButton: 'button:has-text("导出")',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Cleaner (Material Delete) Page
|
||||||
|
cleaner: {
|
||||||
|
orderNumberInput: 'input[name="orderNumber"]',
|
||||||
|
materialGrid: 'table.material-grid tbody tr',
|
||||||
|
saveButton: 'button:has-text("保存")',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Common Elements
|
||||||
|
common: {
|
||||||
|
successMessage: '.message.success',
|
||||||
|
errorMessage: '.message.error',
|
||||||
|
confirmDialog: '.confirm-dialog',
|
||||||
|
confirmButton: 'button:has-text("确定")',
|
||||||
|
cancelButton: 'button:has-text("取消")',
|
||||||
|
},
|
||||||
|
};
|
||||||
21
src/main/types/cleaner.types.ts
Normal file
21
src/main/types/cleaner.types.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export interface CleanerInput {
|
||||||
|
orderNumbers: string[];
|
||||||
|
materialCodes: string[];
|
||||||
|
dryRun: boolean;
|
||||||
|
onProgress?: (message: string, progress: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CleanerResult {
|
||||||
|
ordersProcessed: number;
|
||||||
|
materialsDeleted: number;
|
||||||
|
materialsSkipped: number;
|
||||||
|
errors: string[];
|
||||||
|
details: OrderCleanDetail[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderCleanDetail {
|
||||||
|
orderNumber: string;
|
||||||
|
materialsDeleted: number;
|
||||||
|
materialsSkipped: number;
|
||||||
|
errors: string[];
|
||||||
|
}
|
||||||
16
src/main/types/erp.types.ts
Normal file
16
src/main/types/erp.types.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export interface ErpConfig {
|
||||||
|
url: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ErpSession {
|
||||||
|
browser: import('playwright').Browser;
|
||||||
|
context: import('playwright').BrowserContext;
|
||||||
|
page: import('playwright').Page;
|
||||||
|
isLoggedIn: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProgressCallback {
|
||||||
|
(message: string, progress?: number): void;
|
||||||
|
}
|
||||||
17
src/main/types/extractor.types.ts
Normal file
17
src/main/types/extractor.types.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
export interface ExtractorInput {
|
||||||
|
orderNumbers: string[];
|
||||||
|
batchSize?: number;
|
||||||
|
onProgress?: (message: string, progress: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExtractorResult {
|
||||||
|
downloadedFiles: string[];
|
||||||
|
mergedFile: string | null;
|
||||||
|
recordCount: number;
|
||||||
|
errors: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderInfo {
|
||||||
|
orderNumber: string;
|
||||||
|
productionId: string;
|
||||||
|
}
|
||||||
15
tests/setup.ts
Normal file
15
tests/setup.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { beforeAll, afterAll } from 'vitest';
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
|
// Load environment variables
|
||||||
|
dotenv.config({ path: '.env' });
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
// Global test setup
|
||||||
|
console.log('Test suite starting...');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
// Global test teardown
|
||||||
|
console.log('Test suite completed.');
|
||||||
|
});
|
||||||
26
tests/unit/locators.test.ts
Normal file
26
tests/unit/locators.test.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { ERP_LOCATORS } from '../../src/main/services/erp/locators';
|
||||||
|
|
||||||
|
describe('ERP Locators', () => {
|
||||||
|
it('should have login page locators defined', () => {
|
||||||
|
expect(ERP_LOCATORS.login.usernameInput).toBeDefined();
|
||||||
|
expect(ERP_LOCATORS.login.passwordInput).toBeDefined();
|
||||||
|
expect(ERP_LOCATORS.login.submitButton).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have main frame locator', () => {
|
||||||
|
expect(ERP_LOCATORS.main.mainIframe).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have extractor page locators', () => {
|
||||||
|
expect(ERP_LOCATORS.extractor.orderNumberInput).toBeDefined();
|
||||||
|
expect(ERP_LOCATORS.extractor.queryButton).toBeDefined();
|
||||||
|
expect(ERP_LOCATORS.extractor.exportButton).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have cleaner page locators', () => {
|
||||||
|
expect(ERP_LOCATORS.cleaner.orderNumberInput).toBeDefined();
|
||||||
|
expect(ERP_LOCATORS.cleaner.materialGrid).toBeDefined();
|
||||||
|
expect(ERP_LOCATORS.cleaner.saveButton).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
14
vitest.config.ts
Normal file
14
vitest.config.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'node',
|
||||||
|
include: ['tests/**/*.{test,spec}.{ts,tsx}'],
|
||||||
|
exclude: ['node_modules', 'dist', 'out'],
|
||||||
|
coverage: {
|
||||||
|
provider: 'v8',
|
||||||
|
reporter: ['text', 'json', 'html'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user