style: apply Prettier formatting across codebase
Apply consistent code formatting using Prettier to improve code readability and maintain style consistency throughout the project. Co-Authored-By: Claude (glm-5) <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
# Implementation Plan: Auto-import Extracted Data to Database
|
# Implementation Plan: Auto-import Extracted Data to Database
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Implement automatic database import after ERP data extraction completes. The merged Excel file will be read and written to the `dbo_DiscreteMaterialPlanData` table.
|
Implement automatic database import after ERP data extraction completes. The merged Excel file will be read and written to the `dbo_DiscreteMaterialPlanData` table.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- **Trigger**: Automatic after extraction completes
|
- **Trigger**: Automatic after extraction completes
|
||||||
- **Delete Strategy**: Batch delete by `SourceNumber` before insert
|
- **Delete Strategy**: Batch delete by `SourceNumber` before insert
|
||||||
- **Batch Insert**: 1000 records per batch
|
- **Batch Insert**: 1000 records per batch
|
||||||
@@ -34,7 +36,7 @@ ExtractorService
|
|||||||
## Field Mapping
|
## Field Mapping
|
||||||
|
|
||||||
| Excel Header | Database Column | Notes |
|
| Excel Header | Database Column | Notes |
|
||||||
|-------------|-----------------|-------|
|
| ------------ | ------------------------ | ---------------- |
|
||||||
| 工厂 | Factory | |
|
| 工厂 | Factory | |
|
||||||
| 备料状态 | MaterialStatus | |
|
| 备料状态 | MaterialStatus | |
|
||||||
| 备料计划单号 | PlanNumber | |
|
| 备料计划单号 | PlanNumber | |
|
||||||
@@ -70,23 +72,30 @@ ExtractorService
|
|||||||
## Files to Create/Modify
|
## Files to Create/Modify
|
||||||
|
|
||||||
### 1. NEW: `src/main/services/database/data-importer.ts`
|
### 1. NEW: `src/main/services/database/data-importer.ts`
|
||||||
|
|
||||||
Main import service with:
|
Main import service with:
|
||||||
|
|
||||||
- `importFromExcel(filePath)` - Main entry point
|
- `importFromExcel(filePath)` - Main entry point
|
||||||
- `readExcelFile(filePath)` - Parse Excel using ExcelJS
|
- `readExcelFile(filePath)` - Parse Excel using ExcelJS
|
||||||
- Map Excel columns to database fields
|
- Map Excel columns to database fields
|
||||||
- Return records and unique SourceNumbers
|
- Return records and unique SourceNumbers
|
||||||
|
|
||||||
### 2. MODIFY: `src/main/services/database/discrete-material-plan-dao.ts`
|
### 2. MODIFY: `src/main/services/database/discrete-material-plan-dao.ts`
|
||||||
|
|
||||||
Add methods:
|
Add methods:
|
||||||
|
|
||||||
- `deleteBySourceNumbers(sourceNumbers: string[])` - Batch delete
|
- `deleteBySourceNumbers(sourceNumbers: string[])` - Batch delete
|
||||||
- `batchInsert(records: MaterialPlanRecord[], batchSize: number)` - Batch insert
|
- `batchInsert(records: MaterialPlanRecord[], batchSize: number)` - Batch insert
|
||||||
|
|
||||||
### 3. MODIFY: `src/main/services/erp/extractor.ts`
|
### 3. MODIFY: `src/main/services/erp/extractor.ts`
|
||||||
|
|
||||||
- After successful merge, call `importToDatabase(mergedFile)`
|
- After successful merge, call `importToDatabase(mergedFile)`
|
||||||
- Add import results to `ExtractorResult`
|
- Add import results to `ExtractorResult`
|
||||||
|
|
||||||
### 4. MODIFY: `src/main/types/extractor.types.ts`
|
### 4. MODIFY: `src/main/types/extractor.types.ts`
|
||||||
|
|
||||||
Add types:
|
Add types:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export interface ImportResult {
|
export interface ImportResult {
|
||||||
success: boolean
|
success: boolean
|
||||||
@@ -102,6 +111,7 @@ export interface ExtractorResult {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 5. MODIFY: `src/renderer/src/pages/ExtractorPage.tsx`
|
### 5. MODIFY: `src/renderer/src/pages/ExtractorPage.tsx`
|
||||||
|
|
||||||
- Display import results
|
- Display import results
|
||||||
- Show records deleted/imported counts
|
- Show records deleted/imported counts
|
||||||
|
|
||||||
@@ -114,6 +124,7 @@ export interface ExtractorResult {
|
|||||||
5. Update UI
|
5. Update UI
|
||||||
|
|
||||||
## Testing Plan
|
## Testing Plan
|
||||||
|
|
||||||
1. Unit test DAO methods
|
1. Unit test DAO methods
|
||||||
2. Integration test with sample Excel file
|
2. Integration test with sample Excel file
|
||||||
3. E2E test extraction → import flow
|
3. E2E test extraction → import flow
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
* This script modifies the ID column to be AUTO_INCREMENT while preserving data
|
* This script modifies the ID column to be AUTO_INCREMENT while preserving data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const mysql = require('mysql2/promise');
|
const mysql = require('mysql2/promise')
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const config = {
|
const config = {
|
||||||
@@ -13,17 +13,17 @@ async function main() {
|
|||||||
user: 'remote_user',
|
user: 'remote_user',
|
||||||
password: '3.1415926Beeke',
|
password: '3.1415926Beeke',
|
||||||
database: 'BLD_DB'
|
database: 'BLD_DB'
|
||||||
};
|
}
|
||||||
|
|
||||||
let connection;
|
let connection
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('Connecting to MySQL...');
|
console.log('Connecting to MySQL...')
|
||||||
connection = await mysql.createConnection(config);
|
connection = await mysql.createConnection(config)
|
||||||
console.log('Connected successfully!\n');
|
console.log('Connected successfully!\n')
|
||||||
|
|
||||||
// Step 1: Check current table structure
|
// Step 1: Check current table structure
|
||||||
console.log('=== Step 1: Current table structure ===');
|
console.log('=== Step 1: Current table structure ===')
|
||||||
const [columns] = await connection.execute(`
|
const [columns] = await connection.execute(`
|
||||||
SELECT
|
SELECT
|
||||||
COLUMN_NAME,
|
COLUMN_NAME,
|
||||||
@@ -39,40 +39,38 @@ async function main() {
|
|||||||
AND TABLE_SCHEMA = DATABASE()
|
AND TABLE_SCHEMA = DATABASE()
|
||||||
ORDER BY
|
ORDER BY
|
||||||
ORDINAL_POSITION
|
ORDINAL_POSITION
|
||||||
`);
|
`)
|
||||||
console.table(columns);
|
console.table(columns)
|
||||||
|
|
||||||
// Step 2: Count records before modification
|
// Step 2: Count records before modification
|
||||||
console.log('\n=== Step 2: Record count before modification ===');
|
console.log('\n=== Step 2: Record count before modification ===')
|
||||||
const [countBefore] = await connection.execute(
|
const [countBefore] = await connection.execute(
|
||||||
'SELECT COUNT(*) AS total FROM dbo_MaterialsTypeToBeDeleted'
|
'SELECT COUNT(*) AS total FROM dbo_MaterialsTypeToBeDeleted'
|
||||||
);
|
)
|
||||||
console.log(`Total records: ${countBefore[0].total}`);
|
console.log(`Total records: ${countBefore[0].total}`)
|
||||||
|
|
||||||
// Step 3: Show sample data
|
// Step 3: Show sample data
|
||||||
console.log('\n=== Step 3: Sample data ===');
|
console.log('\n=== Step 3: Sample data ===')
|
||||||
const [sample] = await connection.execute(
|
const [sample] = await connection.execute('SELECT * FROM dbo_MaterialsTypeToBeDeleted LIMIT 5')
|
||||||
'SELECT * FROM dbo_MaterialsTypeToBeDeleted LIMIT 5'
|
console.table(sample)
|
||||||
);
|
|
||||||
console.table(sample);
|
|
||||||
|
|
||||||
// Step 4: Check if ID is already AUTO_INCREMENT
|
// Step 4: Check if ID is already AUTO_INCREMENT
|
||||||
const idColumn = columns.find((col) => col.COLUMN_NAME === 'ID');
|
const idColumn = columns.find((col) => col.COLUMN_NAME === 'ID')
|
||||||
if (idColumn && idColumn.EXTRA.includes('auto_increment')) {
|
if (idColumn && idColumn.EXTRA.includes('auto_increment')) {
|
||||||
console.log('\n=== ID is already AUTO_INCREMENT! No modification needed. ===');
|
console.log('\n=== ID is already AUTO_INCREMENT! No modification needed. ===')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: Modify the ID column
|
// Step 5: Modify the ID column
|
||||||
console.log('\n=== Step 4: Modifying ID column to AUTO_INCREMENT ===');
|
console.log('\n=== Step 4: Modifying ID column to AUTO_INCREMENT ===')
|
||||||
await connection.execute(`
|
await connection.execute(`
|
||||||
ALTER TABLE dbo_MaterialsTypeToBeDeleted
|
ALTER TABLE dbo_MaterialsTypeToBeDeleted
|
||||||
MODIFY COLUMN ID INT NOT NULL AUTO_INCREMENT
|
MODIFY COLUMN ID INT NOT NULL AUTO_INCREMENT
|
||||||
`);
|
`)
|
||||||
console.log('Modification completed successfully!\n');
|
console.log('Modification completed successfully!\n')
|
||||||
|
|
||||||
// Step 6: Verify the change
|
// Step 6: Verify the change
|
||||||
console.log('=== Step 5: Verify modification ===');
|
console.log('=== Step 5: Verify modification ===')
|
||||||
const [columnsAfter] = await connection.execute(`
|
const [columnsAfter] = await connection.execute(`
|
||||||
SELECT
|
SELECT
|
||||||
COLUMN_NAME,
|
COLUMN_NAME,
|
||||||
@@ -86,32 +84,32 @@ async function main() {
|
|||||||
TABLE_NAME = 'dbo_MaterialsTypeToBeDeleted'
|
TABLE_NAME = 'dbo_MaterialsTypeToBeDeleted'
|
||||||
AND TABLE_SCHEMA = DATABASE()
|
AND TABLE_SCHEMA = DATABASE()
|
||||||
AND COLUMN_NAME = 'ID'
|
AND COLUMN_NAME = 'ID'
|
||||||
`);
|
`)
|
||||||
console.table(columnsAfter);
|
console.table(columnsAfter)
|
||||||
|
|
||||||
// Step 7: Verify data is still intact
|
// Step 7: Verify data is still intact
|
||||||
console.log('\n=== Step 6: Verify data integrity ===');
|
console.log('\n=== Step 6: Verify data integrity ===')
|
||||||
const [countAfter] = await connection.execute(
|
const [countAfter] = await connection.execute(
|
||||||
'SELECT COUNT(*) AS total FROM dbo_MaterialsTypeToBeDeleted'
|
'SELECT COUNT(*) AS total FROM dbo_MaterialsTypeToBeDeleted'
|
||||||
);
|
)
|
||||||
console.log(`Total records after modification: ${countAfter[0].total}`);
|
console.log(`Total records after modification: ${countAfter[0].total}`)
|
||||||
|
|
||||||
if (countBefore[0].total === countAfter[0].total) {
|
if (countBefore[0].total === countAfter[0].total) {
|
||||||
console.log('\n✅ SUCCESS: All data preserved, AUTO_INCREMENT added to ID column!');
|
console.log('\n✅ SUCCESS: All data preserved, AUTO_INCREMENT added to ID column!')
|
||||||
} else {
|
} else {
|
||||||
console.log('\n⚠️ WARNING: Record count changed! Please check data.');
|
console.log('\n⚠️ WARNING: Record count changed! Please check data.')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('\n❌ Error:', error.message);
|
console.error('\n❌ Error:', error.message)
|
||||||
if (error.code) {
|
if (error.code) {
|
||||||
console.error('Error code:', error.code);
|
console.error('Error code:', error.code)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (connection) {
|
if (connection) {
|
||||||
await connection.end();
|
await connection.end()
|
||||||
console.log('\nConnection closed.');
|
console.log('\nConnection closed.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main()
|
||||||
|
|||||||
@@ -19,34 +19,34 @@ const log = createLogger('DataImportService')
|
|||||||
* Excel column header to database field mapping
|
* Excel column header to database field mapping
|
||||||
*/
|
*/
|
||||||
const EXCEL_TO_DB_MAPPING: Record<string, keyof MaterialPlanRecord> = {
|
const EXCEL_TO_DB_MAPPING: Record<string, keyof MaterialPlanRecord> = {
|
||||||
'工厂': 'factory',
|
工厂: 'factory',
|
||||||
'备料状态': 'materialStatus',
|
备料状态: 'materialStatus',
|
||||||
'备料计划单号': 'planNumber',
|
备料计划单号: 'planNumber',
|
||||||
'来源单号': 'sourceNumber',
|
来源单号: 'sourceNumber',
|
||||||
'备料类型': 'materialType',
|
备料类型: 'materialType',
|
||||||
'产品编码': 'productCode',
|
产品编码: 'productCode',
|
||||||
'产品名称': 'productName',
|
产品名称: 'productName',
|
||||||
'产品计划数量': 'productPlanQuantity',
|
产品计划数量: 'productPlanQuantity',
|
||||||
'产品单位': 'productUnit',
|
产品单位: 'productUnit',
|
||||||
'用料部门': 'useDepartment',
|
用料部门: 'useDepartment',
|
||||||
'备注': 'remark',
|
备注: 'remark',
|
||||||
'制单人': 'creator',
|
制单人: 'creator',
|
||||||
'制单日期': 'createDate',
|
制单日期: 'createDate',
|
||||||
'审批人': 'approver',
|
审批人: 'approver',
|
||||||
'审批日期': 'approveDate',
|
审批日期: 'approveDate',
|
||||||
'序号': 'sequenceNumber',
|
序号: 'sequenceNumber',
|
||||||
'材料编码': 'materialCode',
|
材料编码: 'materialCode',
|
||||||
'材料名称': 'materialName',
|
材料名称: 'materialName',
|
||||||
'规格': 'specification',
|
规格: 'specification',
|
||||||
'型号': 'model',
|
型号: 'model',
|
||||||
'图号': 'drawingNumber',
|
图号: 'drawingNumber',
|
||||||
'物料材质': 'materialQuality',
|
物料材质: 'materialQuality',
|
||||||
'计划数量': 'planQuantity',
|
计划数量: 'planQuantity',
|
||||||
'单位': 'unit',
|
单位: 'unit',
|
||||||
'需用日期': 'requiredDate',
|
需用日期: 'requiredDate',
|
||||||
'发料仓库': 'warehouse',
|
发料仓库: 'warehouse',
|
||||||
'单位用量': 'unitUsage',
|
单位用量: 'unitUsage',
|
||||||
'累计出库数量': 'cumulativeOutputQuantity'
|
累计出库数量: 'cumulativeOutputQuantity'
|
||||||
// Note: '打印人', '打印日期' are skipped (not in DB)
|
// Note: '打印人', '打印日期' are skipped (not in DB)
|
||||||
// Note: 'BOMVersion' is skipped (not in Excel)
|
// Note: 'BOMVersion' is skipped (not in Excel)
|
||||||
}
|
}
|
||||||
@@ -275,11 +275,7 @@ export class DataImportService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle date fields
|
// Handle date fields
|
||||||
const dateFields: (keyof MaterialPlanRecord)[] = [
|
const dateFields: (keyof MaterialPlanRecord)[] = ['createDate', 'approveDate', 'requiredDate']
|
||||||
'createDate',
|
|
||||||
'approveDate',
|
|
||||||
'requiredDate'
|
|
||||||
]
|
|
||||||
|
|
||||||
if (dateFields.includes(fieldName)) {
|
if (dateFields.includes(fieldName)) {
|
||||||
// ExcelJS returns date as Date object if recognized
|
// ExcelJS returns date as Date object if recognized
|
||||||
|
|||||||
@@ -227,7 +227,10 @@ const ExtractorPage: React.FC = () => {
|
|||||||
{result?.importResult && (
|
{result?.importResult && (
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6 flex flex-col gap-4">
|
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6 flex flex-col gap-4">
|
||||||
<h3 className="font-semibold text-lg border-b pb-2 flex items-center gap-2">
|
<h3 className="font-semibold text-lg border-b pb-2 flex items-center gap-2">
|
||||||
<Database size={20} className={result.importResult.success ? 'text-emerald-600' : 'text-red-500'} />
|
<Database
|
||||||
|
size={20}
|
||||||
|
className={result.importResult.success ? 'text-emerald-600' : 'text-red-500'}
|
||||||
|
/>
|
||||||
<span className={result.importResult.success ? 'text-emerald-600' : 'text-red-500'}>
|
<span className={result.importResult.success ? 'text-emerald-600' : 'text-red-500'}>
|
||||||
数据库写入结果
|
数据库写入结果
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user