diff --git a/src/controller/order.controller.ts b/src/controller/order.controller.ts index 1f51d86..a11cf6d 100644 --- a/src/controller/order.controller.ts +++ b/src/controller/order.controller.ts @@ -2,6 +2,7 @@ import { Body, Controller, Del, + Files, Get, Inject, Param, @@ -27,7 +28,6 @@ import { } from '../dto/order.dto'; import { User } from '../decorator/user.decorator'; import { ErpOrderStatus } from '../enums/base.enum'; - @Controller('/order') export class OrderController { @Inject() @@ -264,4 +264,21 @@ export class OrderController { return errorResponse(error?.message || '导出失败'); } } + + + // 导入产品(CSV 文件) + @ApiOkResponse() + @Post('/import') + async importWintopay(@Files() files: any) { + try { + // 条件判断:确保存在文件 + const file = files?.[0]; + if (!file) return errorResponse('未接收到上传文件'); + + const result = await this.orderService.importWintopayTable(file); + return successResponse(result); + } catch (error) { + return errorResponse(error?.message || error); + } + } } diff --git a/src/service/order.service.ts b/src/service/order.service.ts index 5cde38a..94963bb 100644 --- a/src/service/order.service.ts +++ b/src/service/order.service.ts @@ -1,5 +1,6 @@ import { Inject, Logger, Provide } from '@midwayjs/core'; import { WPService } from './wp.service'; +import * as xlsx from 'xlsx'; import { Order } from '../entity/order.entity'; import { In, Like, Repository } from 'typeorm'; import { InjectEntityModel, TypeORMDataSourceManager } from '@midwayjs/typeorm'; @@ -32,7 +33,7 @@ import { UpdateStockDTO } from '../dto/stock.dto'; import { StockService } from './stock.service'; import { OrderItemOriginal } from '../entity/order_item_original.entity'; import { SiteApiService } from './site-api.service'; -import { SyncOperationResult } from '../dto/api.dto'; +import { BatchErrorItem, SyncOperationResult,BatchOperationResult } from '../dto/api.dto'; import * as fs from 'fs'; import * as path from 'path'; @@ -2579,8 +2580,8 @@ export class OrderService { * 导出数据为CSV格式 * @param {any[]} data 数据数组 * @param {Object} options 配置选项 - * @param {string} [options.type='string'] 输出类型:'string' | 'buffer' - * @param {string} [options.fileName] 文件名(仅当需要写入文件时使用) + * @param {string} [options.type='string'] 输出类型:'string' | 'buffer' + * @param {string} [options.fileName] 文件名(仅当需要写入文件时使用) * @param {boolean} [options.writeFile=false] 是否写入文件 * @returns {string|Buffer} 根据type返回字符串或Buffer */ @@ -2728,4 +2729,58 @@ export class OrderService { return result; } + + + + // 从 CSV 导入产品;存在则更新,不存在则创建 + async importWintopayTable(file: any): Promise { + let created = 0; + let updated = 0; + const errors: BatchErrorItem[] = []; + const records = await this.getRecordsFromTable(file); +created++ +updated++ + + return { total: records.length, processed: records.length - errors.length, created: 0, updated: 0, errors }; + } + + async getRecordsFromTable(file: any) { + // 解析文件(使用 xlsx 包自动识别文件类型并解析) + try { + let buffer: Buffer; + + // 处理文件输入,获取 buffer + if (Buffer.isBuffer(file)) { + buffer = file; + } + else if (file?.data) { + if (typeof file.data === 'string') { + buffer = fs.readFileSync(file.data); + } else { + buffer = file.data; + } + } else { + throw new Error('无效的文件输入'); + } + + let records: any[] = [] + // xlsx 包会自动根据文件内容识别文件类型(CSV 或 XLSX) + // 添加codepage: 65001以确保正确处理UTF-8编码的中文 + const workbook = xlsx.read(buffer, { type: 'buffer', codepage: 65001 }); + // 获取第一个工作表 + const worksheet = workbook.Sheets[workbook.SheetNames[0]]; + // 将工作表转换为 JSON 数组 + records = xlsx.utils.sheet_to_json(worksheet); + + console.log('Parsed records count:', records.length); + if (records.length > 0) { + console.log('First record keys:', Object.keys(records[0])); + } + return records; + } catch (e: any) { + throw new Error(`文件解析失败:${e?.message || e}`); + } + + + } }