Răsfoiți Sursa

📝 docs(example): 新增创建特定打印机示例文档

- 添加 example-create-printer.md 文档,展示如何使用 FeieTestDataFactory 和 FeieTestFactory 创建特定打印机
- 提供详细的代码示例和参数说明,便于开发者在测试中使用

♻️ refactor(printers): 统一打印机状态和类型枚举值

- 将打印机状态从 ONLINE/OFFLINE 改为 ACTIVE/INACTIVE,更符合业务语义
- 将打印机类型从 RECEIPT/LABEL 改为 58mm/80mm,与实际打印机规格对齐
- 在详情、列表、设置默认和更新接口中统一使用新的枚举值

✨ feat(printers): 添加日期字段序列化支持

- 在打印机详情、列表、设置默认和更新接口中,将 Date 对象转换为 ISO 字符串格式
- 确保 API 响应中的 createdAt 和 updatedAt 字段为字符串类型,提高客户端兼容性

♻️ refactor(tasks): 扩展打印任务状态枚举和字段

- 将打印任务状态枚举扩展为 PENDING/DELAYED/PRINTING/SUCCESS/FAILED/CANCELLED
- 在任务列表响应中添加 id、retryCount、maxRetries、scheduledAt、printedAt、cancelledAt 字段
- 添加日期字段序列化支持,转换所有 Date 对象为 ISO 字符串格式

🐛 fix(config): 修正飞鹅配置表名引用

- 将 system_config_mt 表名修正为 feie_config_mt,与实际表结构保持一致
- 更新测试数据工厂中的默认配置值,使用真实的测试账号信息

✨ feat(tests): 添加特定打印机创建方法

- 在 FeieTestFactory 和 FeieTestDataFactory 中添加 createSpecificTestPrinter 方法
- 支持通过指定打印机序列号和密钥创建特定打印机,便于测试场景使用
yourname 1 lună în urmă
părinte
comite
725238b4b8

+ 102 - 0
packages/feie-printer-module-mt/example-create-printer.md

@@ -0,0 +1,102 @@
+# 创建特定打印机示例
+
+## 方法1:使用 FeieTestDataFactory
+
+```typescript
+import { FeieTestDataFactory } from './tests/utils/test-data-factory';
+import { DataSource } from 'typeorm';
+
+// 假设已有 dataSource
+const dataSource: DataSource = ...;
+
+// 创建特定打印机
+const printer = await FeieTestDataFactory.createSpecificTestPrinter(
+  dataSource,
+  1, // tenantId
+  "924744594", // printer_sn
+  "mjLsQXUs", // printer_key
+  1 // isDefault (设置为默认打印机)
+);
+
+console.log('创建的打印机:', {
+  id: printer.id,
+  tenantId: printer.tenantId,
+  printerSn: printer.printerSn,
+  printerKey: printer.printerKey,
+  printerName: printer.printerName,
+  printerType: printer.printerType,
+  printerStatus: printer.printerStatus,
+  isDefault: printer.isDefault
+});
+```
+
+## 方法2:使用 FeieTestFactory
+
+```typescript
+import { FeieTestFactory } from './tests/factories/feie-test-factory';
+import { DataSource } from 'typeorm';
+
+// 假设已有 dataSource
+const dataSource: DataSource = ...;
+
+// 创建工厂实例
+const factory = new FeieTestFactory(dataSource);
+
+// 创建特定打印机
+const printer = await factory.createSpecificTestPrinter(
+  1, // tenantId
+  "924744594", // printer_sn
+  "mjLsQXUs", // printer_key
+  1 // isDefault (设置为默认打印机)
+);
+
+console.log('创建的打印机:', {
+  id: printer.id,
+  tenantId: printer.tenantId,
+  printerSn: printer.printerSn,
+  printerKey: printer.printerKey,
+  printerName: printer.printerName,
+  printerType: printer.printerType,
+  printerStatus: printer.printerStatus,
+  isDefault: printer.isDefault
+});
+```
+
+## 打印机参数说明
+
+| 参数 | 值 | 说明 |
+|------|-----|------|
+| printer_sn | 924744594 | 打印机序列号 |
+| printer_key | mjLsQXUs | 打印机密钥 |
+| isDefault | 1 | 设置为默认打印机 |
+| printerName | 自动生成 "打印机 924744594" | 打印机名称 |
+| printerType | "58mm" | 打印机类型 |
+| printerStatus | "ACTIVE" | 打印机状态 |
+
+## 在测试中使用
+
+```typescript
+// 在集成测试中创建测试数据
+describe('打印机API测试', () => {
+  let dataSource: DataSource;
+  let testPrinter: FeiePrinterMt;
+
+  beforeAll(async () => {
+    // 初始化数据源
+    dataSource = await createTestDataSource();
+
+    // 创建特定打印机
+    testPrinter = await FeieTestDataFactory.createSpecificTestPrinter(
+      dataSource,
+      1,
+      "924744594",
+      "mjLsQXUs",
+      1
+    );
+  });
+
+  it('应该能获取默认打印机', async () => {
+    // 测试逻辑...
+  });
+});
+```

+ 10 - 3
packages/feie-printer-module-mt/src/routes/printers/detail.mt.ts

@@ -20,8 +20,8 @@ const PrinterDetailResponseSchema = z.object({
     printerSn: z.string(),
     printerName: z.string().nullable(),
     printerKey: z.string(),
-    printerType: z.enum(['RECEIPT', 'LABEL']),
-    printerStatus: z.enum(['ONLINE', 'OFFLINE', 'ERROR']),
+    printerType: z.enum(['58mm', '80mm']),
+    printerStatus: z.enum(['ACTIVE', 'INACTIVE', 'ERROR']),
     isDefault: z.number(),
     createdAt: z.string(),
     updatedAt: z.string()
@@ -82,10 +82,17 @@ const app = new OpenAPIHono<AuthContext>()
       return c.json({ success: false, message: '打印机不存在' }, 404);
     }
 
+    // 转换Date对象为ISO字符串
+    const transformedPrinter = {
+      ...printer,
+      createdAt: printer.createdAt.toISOString(),
+      updatedAt: printer.updatedAt.toISOString()
+    };
+
     // 验证响应格式
     const validatedResponse = await parseWithAwait(PrinterDetailResponseSchema, {
       success: true,
-      data: printer
+      data: transformedPrinter
     });
 
     return c.json(validatedResponse, 200);

+ 12 - 5
packages/feie-printer-module-mt/src/routes/printers/list.mt.ts

@@ -11,8 +11,8 @@ const PrinterListQuerySchema = z.object({
   page: z.string().optional().transform(val => val ? parseInt(val, 10) : 1),
   pageSize: z.string().optional().transform(val => val ? parseInt(val, 10) : 10),
   search: z.string().optional(),
-  status: z.enum(['ONLINE', 'OFFLINE', 'ERROR', 'ALL']).optional().default('ALL'),
-  printerType: z.enum(['RECEIPT', 'LABEL', 'ALL']).optional().default('ALL'),
+  status: z.enum(['ACTIVE', 'INACTIVE', 'ERROR', 'ALL']).optional().default('ALL'),
+  printerType: z.enum(['58mm', '80mm', 'ALL']).optional().default('ALL'),
   isDefault: z.enum(['true', 'false']).optional().transform(val => val === 'true')
 });
 
@@ -26,8 +26,8 @@ const PrinterListResponseSchema = z.object({
       printerSn: z.string(),
       printerName: z.string().nullable(),
       printerKey: z.string(),
-      printerType: z.enum(['RECEIPT', 'LABEL']),
-      printerStatus: z.enum(['ONLINE', 'OFFLINE', 'ERROR']),
+      printerType: z.enum(['58mm', '80mm']),
+      printerStatus: z.enum(['ACTIVE', 'INACTIVE', 'ERROR']),
       isDefault: z.number(),
       createdAt: z.string(),
       updatedAt: z.string()
@@ -120,11 +120,18 @@ const app = new OpenAPIHono<AuthContext>()
 
     console.debug(`返回打印机列表,总数: ${total}, 分页: ${page}/${Math.ceil(total/pageSize)}, 数量: ${paginatedPrinters.length}`);
 
+    // 转换Date对象为ISO字符串
+    const transformedPrinters = paginatedPrinters.map(printer => ({
+      ...printer,
+      createdAt: printer.createdAt.toISOString(),
+      updatedAt: printer.updatedAt.toISOString()
+    }));
+
     // 验证响应格式
     const validatedResponse = await parseWithAwait(PrinterListResponseSchema, {
       success: true,
       data: {
-        data: paginatedPrinters,
+        data: transformedPrinters,
         total,
         page,
         pageSize

+ 10 - 3
packages/feie-printer-module-mt/src/routes/printers/set-default.mt.ts

@@ -20,8 +20,8 @@ const SetDefaultPrinterResponseSchema = z.object({
     printerSn: z.string(),
     printerName: z.string().nullable(),
     printerKey: z.string(),
-    printerType: z.enum(['RECEIPT', 'LABEL']),
-    printerStatus: z.enum(['ONLINE', 'OFFLINE', 'ERROR']),
+    printerType: z.enum(['58mm', '80mm']),
+    printerStatus: z.enum(['ACTIVE', 'INACTIVE', 'ERROR']),
     isDefault: z.number(),
     createdAt: z.string(),
     updatedAt: z.string()
@@ -77,10 +77,17 @@ const app = new OpenAPIHono<AuthContext>()
       const printerService = new PrinterService(AppDataSource, feieConfig);
       const printer = await printerService.setDefaultPrinter(tenantId, printerSn);
 
+      // 转换Date对象为ISO字符串
+      const transformedPrinter = {
+        ...printer,
+        createdAt: printer.createdAt.toISOString(),
+        updatedAt: printer.updatedAt.toISOString()
+      };
+
       // 验证响应格式
       const validatedResponse = await parseWithAwait(SetDefaultPrinterResponseSchema, {
         success: true,
-        data: printer
+        data: transformedPrinter
       });
 
       return c.json(validatedResponse, 200);

+ 9 - 2
packages/feie-printer-module-mt/src/routes/printers/update.mt.ts

@@ -29,7 +29,7 @@ const PrinterUpdateResponseSchema = z.object({
     printerName: z.string().nullable(),
     printerKey: z.string(),
     printerType: z.enum(['58mm', '80mm']),
-    printerStatus: z.enum(['ONLINE', 'OFFLINE', 'ERROR']),
+    printerStatus: z.enum(['ACTIVE', 'INACTIVE', 'ERROR']),
     isDefault: z.number(),
     createdAt: z.string(),
     updatedAt: z.string()
@@ -92,10 +92,17 @@ const app = new OpenAPIHono<AuthContext>()
       const printerService = new PrinterService(AppDataSource, feieConfig);
       const printer = await printerService.updatePrinter(tenantId, printerSn, body);
 
+      // 转换Date对象为ISO字符串
+      const transformedPrinter = {
+        ...printer,
+        createdAt: printer.createdAt.toISOString(),
+        updatedAt: printer.updatedAt.toISOString()
+      };
+
       // 验证响应格式
       const validatedResponse = await parseWithAwait(PrinterUpdateResponseSchema, {
         success: true,
-        data: printer
+        data: transformedPrinter
       });
 
       return c.json(validatedResponse, 200);

+ 18 - 4
packages/feie-printer-module-mt/src/routes/tasks/list.mt.ts

@@ -14,7 +14,7 @@ const PrintTaskListQuerySchema = z.object({
   orderId: z.string().optional().transform(val => val ? parseInt(val, 10) : undefined),
   printerSn: z.string().optional(),
   printType: z.enum(['RECEIPT', 'SHIPPING', 'ORDER', 'ALL']).optional().default('ALL').transform(val => val === 'ALL' ? undefined : val as PrintType),
-  status: z.enum(['PENDING', 'PROCESSING', 'SUCCESS', 'FAILED', 'CANCELLED', 'ALL']).optional().default('ALL').transform(val => val === 'ALL' ? undefined : val as PrintStatus),
+  status: z.enum(['PENDING', 'DELAYED', 'PRINTING', 'SUCCESS', 'FAILED', 'CANCELLED', 'ALL']).optional().default('ALL').transform(val => val === 'ALL' ? undefined : val as PrintStatus),
   startDate: z.string().optional().transform(val => val ? new Date(val) : undefined),
   endDate: z.string().optional().transform(val => val ? new Date(val) : undefined),
   search: z.string().optional()
@@ -25,16 +25,20 @@ const PrintTaskListResponseSchema = z.object({
   success: z.boolean(),
   data: z.object({
     data: z.array(z.object({
+      id: z.number(),
       taskId: z.string(),
       tenantId: z.number(),
       printerSn: z.string(),
       orderId: z.number().nullable(),
       printType: z.nativeEnum(PrintType),
       content: z.string(),
-      copies: z.number(),
-      priority: z.enum(['HIGH', 'NORMAL', 'LOW']),
       printStatus: z.nativeEnum(PrintStatus),
       errorMessage: z.string().nullable(),
+      retryCount: z.number(),
+      maxRetries: z.number(),
+      scheduledAt: z.string().nullable(),
+      printedAt: z.string().nullable(),
+      cancelledAt: z.string().nullable(),
       createdAt: z.string(),
       updatedAt: z.string()
     })),
@@ -101,11 +105,21 @@ const app = new OpenAPIHono<AuthContext>()
       const printTaskService = new PrintTaskService(AppDataSource, feieConfig);
       const result = await printTaskService.getPrintTasks(tenantId, filters, page, limit);
 
+      // 转换Date对象为ISO字符串
+      const transformedTasks = result.tasks.map(task => ({
+        ...task,
+        createdAt: task.createdAt.toISOString(),
+        updatedAt: task.updatedAt.toISOString(),
+        scheduledAt: task.scheduledAt ? task.scheduledAt.toISOString() : null,
+        printedAt: task.printedAt ? task.printedAt.toISOString() : null,
+        cancelledAt: task.cancelledAt ? task.cancelledAt.toISOString() : null
+      }));
+
       // 验证响应格式
       const response = {
         success: true as const,
         data: {
-          data: result.tasks,
+          data: transformedTasks,
           total: result.total,
           page,
           pageSize: limit

+ 2 - 2
packages/feie-printer-module-mt/src/routes/utils/feie-config.util.ts

@@ -8,7 +8,7 @@ export async function getFeieApiConfig(tenantId: number, dataSource: DataSource)
   try {
     console.debug(`开始获取租户 ${tenantId} 的飞鹅API配置`);
 
-    // 从 system_config_mt 表获取飞鹅API配置
+    // 从 feie_config_mt 表获取飞鹅API配置
     const configKeys = [
       'feie.api.user',      // 飞鹅API用户
       'feie.api.ukey',      // 飞鹅API密钥
@@ -18,7 +18,7 @@ export async function getFeieApiConfig(tenantId: number, dataSource: DataSource)
     ];
 
     // 直接查询数据库
-    const configRepository = dataSource.getRepository('system_config_mt');
+    const configRepository = dataSource.getRepository('feie_config_mt');
     console.debug(`查询数据库,租户ID: ${tenantId}, 配置键: ${configKeys.join(', ')}`);
 
     const configs = await configRepository.find({

+ 24 - 1
packages/feie-printer-module-mt/tests/factories/feie-test-factory.ts

@@ -1,6 +1,5 @@
 import { DataSource } from 'typeorm';
 import { UserEntityMt } from '@d8d/user-module-mt';
-import { FileMt } from '@d8d/file-module-mt';
 import { FeiePrinterMt, FeiePrintTaskMt, FeieConfigMt } from '../../src/entities';
 
 export class FeieTestFactory {
@@ -44,6 +43,30 @@ export class FeieTestFactory {
     return await printerRepository.save(printer);
   }
 
+  /**
+   * 创建特定序列号的测试打印机(用于特定测试场景)
+   */
+  async createSpecificTestPrinter(
+    tenantId: number = 1,
+    printerSn: string,
+    printerKey: string,
+    isDefault: number = 1,
+    overrides: Partial<FeiePrinterMt> = {}
+  ): Promise<FeiePrinterMt> {
+    const printerRepository = this.dataSource.getRepository(FeiePrinterMt);
+    const printer = printerRepository.create({
+      tenantId,
+      printerSn,
+      printerKey,
+      printerName: `打印机 ${printerSn}`,
+      printerType: '58mm',
+      printerStatus: 'ACTIVE',
+      isDefault,
+      ...overrides
+    });
+    return await printerRepository.save(printer);
+  }
+
   /**
    * 创建测试打印任务
    */

+ 29 - 2
packages/feie-printer-module-mt/tests/utils/test-data-factory.ts

@@ -53,6 +53,33 @@ export class FeieTestDataFactory {
     return await printerRepository.save(printer);
   }
 
+  /**
+   * 创建特定序列号的测试打印机(用于特定测试场景)
+   */
+  static async createSpecificTestPrinter(
+    dataSource: DataSource,
+    tenantId: number,
+    printerSn: string,
+    printerKey: string,
+    isDefault: number = 1,
+    overrides: Partial<FeiePrinterMt> = {}
+  ): Promise<FeiePrinterMt> {
+    const printerRepository = dataSource.getRepository(FeiePrinterMt);
+
+    const printer = printerRepository.create({
+      tenantId,
+      printerSn,
+      printerKey,
+      printerName: `打印机 ${printerSn}`,
+      printerType: '58mm',
+      printerStatus: 'ACTIVE',
+      isDefault,
+      ...overrides
+    });
+
+    return await printerRepository.save(printer);
+  }
+
   /**
    * 创建测试打印任务
    */
@@ -102,14 +129,14 @@ export class FeieTestDataFactory {
       {
         tenantId,
         configKey: 'feie.api.user',
-        configValue: 'test_user',
+        configValue: '2638601246@qq.com',
         configType: 'STRING',
         description: '飞鹅API用户'
       },
       {
         tenantId,
         configKey: 'feie.api.ukey',
-        configValue: 'test_ukey',
+        configValue: 'tAwVmIEv48zcIu2Y',
         configType: 'STRING',
         description: '飞鹅API密钥'
       },