Explorar o código

✨ feat(routes): 新增飞鹅打印模块多租户路由

- 新增打印任务相关路由【detail.mt.ts, status.mt.ts, cancel.mt.ts, retry.mt.ts】
- 新增调度器管理路由【status.mt.ts, start.mt.ts, stop.mt.ts, health.mt.ts, trigger.mt.ts】
- 新增打印配置管理路由【list.mt.ts, update.mt.ts】
- 在主路由文件【feie.mt.routes.ts】中注册所有新增路由
yourname hai 1 mes
pai
achega
fe39122eba

+ 79 - 0
packages/feie-printer-module-mt/src/routes/config/list.mt.ts

@@ -0,0 +1,79 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { ConfigService } from '../../services/config.service';
+
+// 打印配置列表响应Schema
+const PrintConfigListResponseSchema = z.object({
+  success: z.boolean(),
+  data: z.object({
+    data: z.array(z.object({
+      id: z.number(),
+      tenantId: z.number(),
+      configKey: z.string(),
+      configValue: z.string(),
+      configType: z.enum(['STRING', 'JSON', 'BOOLEAN', 'NUMBER']),
+      description: z.string().nullable(),
+      createdAt: z.string(),
+      updatedAt: z.string()
+    }))
+  })
+});
+
+// 打印配置列表路由定义
+const printConfigListRoute = createRoute({
+  method: 'get',
+  path: '/',
+  middleware: [authMiddleware],
+  responses: {
+    200: {
+      description: '打印配置列表获取成功',
+      content: { 'application/json': { schema: PrintConfigListResponseSchema } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(printConfigListRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+
+    try {
+      const configService = new ConfigService(AppDataSource);
+      const configs = await configService.getPrintConfigs(tenantId);
+
+      // 将 FeieConfigMt 转换为前端需要的格式
+      const transformedConfigs = configs.map(config => ({
+        id: config.id,
+        tenantId: config.tenantId,
+        configKey: config.configKey,
+        configValue: config.configValue || '',
+        configType: config.configType,
+        description: config.description || null,
+        createdAt: config.createdAt.toISOString(),
+        updatedAt: config.updatedAt.toISOString()
+      }));
+
+      return c.json({
+        success: true,
+        data: {
+          data: transformedConfigs
+        }
+      }, 200);
+    } catch (error) {
+      console.error(`[租户${tenantId}] 获取打印配置失败:`, error);
+      return c.json({ success: false, message: '获取打印配置失败' }, 500);
+    }
+  });
+
+export default app;

+ 103 - 0
packages/feie-printer-module-mt/src/routes/config/update.mt.ts

@@ -0,0 +1,103 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { ConfigService } from '../../services/config.service';
+
+// 更新打印配置参数Schema
+const UpdatePrintConfigParamsSchema = z.object({
+  configKey: z.string().min(1, '配置键不能为空')
+});
+
+// 更新打印配置请求体Schema
+const UpdatePrintConfigBodySchema = z.object({
+  configValue: z.string().min(1, '配置值不能为空')
+});
+
+// 更新打印配置响应Schema
+const UpdatePrintConfigResponseSchema = z.object({
+  success: z.boolean(),
+  data: z.object({
+    id: z.number(),
+    tenantId: z.number(),
+    configKey: z.string(),
+    configValue: z.string(),
+    configType: z.enum(['STRING', 'JSON', 'BOOLEAN', 'NUMBER']),
+    description: z.string().nullable(),
+    createdAt: z.string(),
+    updatedAt: z.string()
+  })
+});
+
+// 更新打印配置路由定义
+const updatePrintConfigRoute = createRoute({
+  method: 'put',
+  path: '/:configKey',
+  middleware: [authMiddleware],
+  request: {
+    params: UpdatePrintConfigParamsSchema,
+    body: {
+      content: {
+        'application/json': { schema: UpdatePrintConfigBodySchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '打印配置更新成功',
+      content: { 'application/json': { schema: UpdatePrintConfigResponseSchema } }
+    },
+    400: {
+      description: '请求参数错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(updatePrintConfigRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+    const { configKey } = c.req.valid('param');
+    const { configValue } = c.req.valid('json');
+
+    if (!configValue) {
+      return c.json({ success: false, message: '配置值不能为空' }, 400);
+    }
+
+    try {
+      const configService = new ConfigService(AppDataSource);
+      const config = await configService.updatePrintConfig(tenantId, configKey, configValue);
+
+      // 将 FeieConfigMt 转换为前端需要的格式
+      const transformedConfig = {
+        id: config.id,
+        tenantId: config.tenantId,
+        configKey: config.configKey,
+        configValue: config.configValue || '',
+        configType: config.configType,
+        description: config.description || null,
+        createdAt: config.createdAt.toISOString(),
+        updatedAt: config.updatedAt.toISOString()
+      };
+
+      return c.json({
+        success: true,
+        data: transformedConfig
+      });
+    } catch (error) {
+      console.error(`[租户${tenantId}] 更新配置失败,key: ${configKey}:`, error);
+      return c.json({ success: false, message: '更新配置失败' }, 500);
+    }
+  });
+
+export default app;

+ 23 - 1
packages/feie-printer-module-mt/src/routes/feie.mt.routes.ts

@@ -8,6 +8,17 @@ import printerStatusRoute from './printers/status.mt';
 import printerSetDefaultRoute from './printers/set-default.mt';
 import printTaskCreateRoute from './tasks/create.mt';
 import printTaskListRoute from './tasks/list.mt';
+import printTaskDetailRoute from './tasks/detail.mt';
+import printTaskStatusRoute from './tasks/status.mt';
+import printTaskCancelRoute from './tasks/cancel.mt';
+import printTaskRetryRoute from './tasks/retry.mt';
+import schedulerStatusRoute from './scheduler/status.mt';
+import schedulerStartRoute from './scheduler/start.mt';
+import schedulerStopRoute from './scheduler/stop.mt';
+import schedulerHealthRoute from './scheduler/health.mt';
+import schedulerTriggerRoute from './scheduler/trigger.mt';
+import printConfigListRoute from './config/list.mt';
+import printConfigUpdateRoute from './config/update.mt';
 
 // 飞鹅打印模块主路由 - 多租户版本
 export const FeieMtRoutes = new OpenAPIHono()
@@ -19,7 +30,18 @@ export const FeieMtRoutes = new OpenAPIHono()
   .route('/printers', printerStatusRoute)
   .route('/printers', printerSetDefaultRoute)
   .route('/tasks', printTaskCreateRoute)
-  .route('/tasks', printTaskListRoute);
+  .route('/tasks', printTaskListRoute)
+  .route('/tasks', printTaskDetailRoute)
+  .route('/tasks', printTaskStatusRoute)
+  .route('/tasks', printTaskCancelRoute)
+  .route('/tasks', printTaskRetryRoute)
+  .route('/scheduler', schedulerStatusRoute)
+  .route('/scheduler', schedulerStartRoute)
+  .route('/scheduler', schedulerStopRoute)
+  .route('/scheduler', schedulerHealthRoute)
+  .route('/scheduler', schedulerTriggerRoute)
+  .route('/config', printConfigListRoute)
+  .route('/config', printConfigUpdateRoute);
 
 // 导出路由配置,用于集成到主应用
 export const feieMtRoutesExport = {

+ 69 - 0
packages/feie-printer-module-mt/src/routes/scheduler/health.mt.ts

@@ -0,0 +1,69 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { DelaySchedulerService } from '../../services/delay-scheduler.service';
+
+// 调度器健康检查响应Schema
+const SchedulerHealthResponseSchema = z.object({
+  success: z.boolean(),
+  data: z.object({
+    isHealthy: z.boolean(),
+    status: z.string(),
+    lastCheckTime: z.string(),
+    errors: z.array(z.string()).optional(),
+    tenantId: z.number()
+  })
+});
+
+// 调度器健康检查路由定义
+const schedulerHealthRoute = createRoute({
+  method: 'get',
+  path: '/health',
+  middleware: [authMiddleware],
+  responses: {
+    200: {
+      description: '调度器健康检查成功',
+      content: { 'application/json': { schema: SchedulerHealthResponseSchema } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(schedulerHealthRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+
+    // 创建租户特定的调度器实例
+    const delaySchedulerService = new DelaySchedulerService(AppDataSource, {
+      baseUrl: 'https://api.feieyun.cn/Api/Open/',
+      user: '',
+      ukey: '',
+      timeout: 10000,
+      maxRetries: 3
+    }, tenantId);
+
+    const health = await delaySchedulerService.healthCheck();
+
+    return c.json({
+      success: true,
+      data: {
+        isHealthy: health.isHealthy,
+        status: health.status,
+        lastCheckTime: health.lastCheckTime.toISOString(),
+        errors: health.errors,
+        tenantId: health.tenantId
+      }
+    });
+  });
+
+export default app;

+ 57 - 0
packages/feie-printer-module-mt/src/routes/scheduler/start.mt.ts

@@ -0,0 +1,57 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { DelaySchedulerService } from '../../services/delay-scheduler.service';
+
+// 启动调度器响应Schema
+const StartSchedulerResponseSchema = z.object({
+  success: z.boolean(),
+  message: z.string()
+});
+
+// 启动调度器路由定义
+const startSchedulerRoute = createRoute({
+  method: 'post',
+  path: '/start',
+  middleware: [authMiddleware],
+  responses: {
+    200: {
+      description: '调度器启动成功',
+      content: { 'application/json': { schema: StartSchedulerResponseSchema } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(startSchedulerRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+
+    // 创建租户特定的调度器实例
+    const delaySchedulerService = new DelaySchedulerService(AppDataSource, {
+      baseUrl: 'https://api.feieyun.cn/Api/Open/',
+      user: '',
+      ukey: '',
+      timeout: 10000,
+      maxRetries: 3
+    }, tenantId);
+
+    await delaySchedulerService.start();
+
+    return c.json({
+      success: true,
+      message: '调度器已启动'
+    });
+  });
+
+export default app;

+ 73 - 0
packages/feie-printer-module-mt/src/routes/scheduler/status.mt.ts

@@ -0,0 +1,73 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { DelaySchedulerService } from '../../services/delay-scheduler.service';
+
+// 调度器状态响应Schema
+const SchedulerStatusResponseSchema = z.object({
+  success: z.boolean(),
+  data: z.object({
+    isRunning: z.boolean(),
+    lastRunTime: z.string().nullable(),
+    nextRunTime: z.string().nullable(),
+    processedTasks: z.number(),
+    failedTasks: z.number(),
+    pendingTasks: z.number(),
+    tenantId: z.number()
+  })
+});
+
+// 调度器状态路由定义
+const schedulerStatusRoute = createRoute({
+  method: 'get',
+  path: '/status',
+  middleware: [authMiddleware],
+  responses: {
+    200: {
+      description: '调度器状态获取成功',
+      content: { 'application/json': { schema: SchedulerStatusResponseSchema } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(schedulerStatusRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+
+    // 创建租户特定的调度器实例
+    const delaySchedulerService = new DelaySchedulerService(AppDataSource, {
+      baseUrl: 'https://api.feieyun.cn/Api/Open/',
+      user: '',
+      ukey: '',
+      timeout: 10000,
+      maxRetries: 3
+    }, tenantId);
+
+    const status = delaySchedulerService.getStatus();
+
+    return c.json({
+      success: true,
+      data: {
+        isRunning: status.isRunning,
+        lastRunTime: status.lastRunTime ? status.lastRunTime.toISOString() : null,
+        nextRunTime: status.nextRunTime ? status.nextRunTime.toISOString() : null,
+        processedTasks: status.processedTasks,
+        failedTasks: status.failedTasks,
+        pendingTasks: status.pendingTasks,
+        tenantId: status.tenantId
+      }
+    });
+  });
+
+export default app;

+ 57 - 0
packages/feie-printer-module-mt/src/routes/scheduler/stop.mt.ts

@@ -0,0 +1,57 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { DelaySchedulerService } from '../../services/delay-scheduler.service';
+
+// 停止调度器响应Schema
+const StopSchedulerResponseSchema = z.object({
+  success: z.boolean(),
+  message: z.string()
+});
+
+// 停止调度器路由定义
+const stopSchedulerRoute = createRoute({
+  method: 'post',
+  path: '/stop',
+  middleware: [authMiddleware],
+  responses: {
+    200: {
+      description: '调度器停止成功',
+      content: { 'application/json': { schema: StopSchedulerResponseSchema } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(stopSchedulerRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+
+    // 创建租户特定的调度器实例
+    const delaySchedulerService = new DelaySchedulerService(AppDataSource, {
+      baseUrl: 'https://api.feieyun.cn/Api/Open/',
+      user: '',
+      ukey: '',
+      timeout: 10000,
+      maxRetries: 3
+    }, tenantId);
+
+    await delaySchedulerService.stop();
+
+    return c.json({
+      success: true,
+      message: '调度器已停止'
+    });
+  });
+
+export default app;

+ 69 - 0
packages/feie-printer-module-mt/src/routes/scheduler/trigger.mt.ts

@@ -0,0 +1,69 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { DelaySchedulerService } from '../../services/delay-scheduler.service';
+
+// 手动触发调度器响应Schema
+const TriggerSchedulerResponseSchema = z.object({
+  success: z.boolean(),
+  data: z.object({
+    processedTasks: z.number(),
+    successfulTasks: z.number(),
+    failedTasks: z.number(),
+    executionTime: z.number(),
+    tenantId: z.number()
+  })
+});
+
+// 手动触发调度器路由定义
+const triggerSchedulerRoute = createRoute({
+  method: 'post',
+  path: '/trigger',
+  middleware: [authMiddleware],
+  responses: {
+    200: {
+      description: '调度器手动触发成功',
+      content: { 'application/json': { schema: TriggerSchedulerResponseSchema } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(triggerSchedulerRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+
+    // 创建租户特定的调度器实例
+    const delaySchedulerService = new DelaySchedulerService(AppDataSource, {
+      baseUrl: 'https://api.feieyun.cn/Api/Open/',
+      user: '',
+      ukey: '',
+      timeout: 10000,
+      maxRetries: 3
+    }, tenantId);
+
+    const result = await delaySchedulerService.triggerManualProcess();
+
+    return c.json({
+      success: result.success,
+      data: {
+        processedTasks: result.processedTasks,
+        successfulTasks: result.successfulTasks,
+        failedTasks: result.failedTasks,
+        executionTime: result.executionTime,
+        tenantId: result.tenantId
+      }
+    });
+  });
+
+export default app;

+ 103 - 0
packages/feie-printer-module-mt/src/routes/tasks/cancel.mt.ts

@@ -0,0 +1,103 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { PrintTaskService } from '../../services/print-task.service';
+
+// 取消打印任务参数Schema
+const CancelPrintTaskParamsSchema = z.object({
+  taskId: z.string().min(1, '任务ID不能为空')
+});
+
+// 取消打印任务请求体Schema
+const CancelPrintTaskBodySchema = z.object({
+  reason: z.enum(['REFUND', 'MANUAL', 'TIMEOUT']).optional().default('MANUAL')
+});
+
+// 取消打印任务响应Schema
+const CancelPrintTaskResponseSchema = z.object({
+  success: z.boolean(),
+  data: z.object({
+    id: z.number(),
+    tenantId: z.number(),
+    taskId: z.string(),
+    printStatus: z.enum(['PENDING', 'DELAYED', 'PRINTING', 'SUCCESS', 'FAILED', 'CANCELLED']),
+    cancelReason: z.string().nullable(),
+    cancelledAt: z.string().nullable(),
+    updatedAt: z.string()
+  })
+});
+
+// 取消打印任务路由定义
+const cancelPrintTaskRoute = createRoute({
+  method: 'post',
+  path: '/:taskId/cancel',
+  middleware: [authMiddleware],
+  request: {
+    params: CancelPrintTaskParamsSchema,
+    body: {
+      content: {
+        'application/json': { schema: CancelPrintTaskBodySchema }
+      }
+    }
+  },
+  responses: {
+    200: {
+      description: '打印任务取消成功',
+      content: { 'application/json': { schema: CancelPrintTaskResponseSchema } }
+    },
+    404: {
+      description: '打印任务不存在',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(cancelPrintTaskRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+    const { taskId } = c.req.valid('param');
+    const { reason } = c.req.valid('json');
+
+    try {
+      // 创建打印任务服务实例(使用默认配置,因为只需要更新数据库)
+      const printTaskService = new PrintTaskService(AppDataSource, {
+        baseUrl: 'https://api.feieyun.cn/Api/Open/',
+        user: '',
+        ukey: '',
+        timeout: 10000,
+        maxRetries: 3
+      });
+
+      const task = await printTaskService.cancelPrintTask(tenantId, taskId, reason);
+
+      return c.json({
+        success: true,
+        data: {
+          id: task.id,
+          tenantId: task.tenantId,
+          taskId: task.taskId,
+          printStatus: task.printStatus,
+          cancelReason: task.cancelReason,
+          cancelledAt: task.cancelledAt ? task.cancelledAt.toISOString() : null,
+          updatedAt: task.updatedAt.toISOString()
+        }
+      });
+    } catch (error) {
+      console.error(`[租户${tenantId}] 取消打印任务失败,任务ID: ${taskId}:`, error);
+      const errorMessage = error instanceof Error ? error.message : '取消打印任务失败';
+      return c.json({ success: false, message: errorMessage }, 500);
+    }
+  });
+
+export default app;

+ 112 - 0
packages/feie-printer-module-mt/src/routes/tasks/detail.mt.ts

@@ -0,0 +1,112 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { PrintTaskService } from '../../services/print-task.service';
+
+// 打印任务详情参数Schema
+const PrintTaskDetailParamsSchema = z.object({
+  taskId: z.string().min(1, '任务ID不能为空')
+});
+
+// 打印任务详情响应Schema
+const PrintTaskDetailResponseSchema = z.object({
+  success: z.boolean(),
+  data: z.object({
+    id: z.number(),
+    tenantId: z.number(),
+    taskId: z.string(),
+    orderId: z.number().nullable(),
+    printerSn: z.string(),
+    content: z.string(),
+    printType: z.enum(['RECEIPT', 'SHIPPING', 'ORDER']),
+    printStatus: z.enum(['PENDING', 'DELAYED', 'PRINTING', 'SUCCESS', 'FAILED', 'CANCELLED']),
+    errorMessage: z.string().nullable(),
+    retryCount: z.number(),
+    maxRetries: z.number(),
+    scheduledAt: z.string().nullable(),
+    printedAt: z.string().nullable(),
+    cancelledAt: z.string().nullable(),
+    cancelReason: z.string().nullable(),
+    createdAt: z.string(),
+    updatedAt: z.string()
+  })
+});
+
+// 打印任务详情路由定义
+const printTaskDetailRoute = createRoute({
+  method: 'get',
+  path: '/:taskId',
+  middleware: [authMiddleware],
+  request: {
+    params: PrintTaskDetailParamsSchema
+  },
+  responses: {
+    200: {
+      description: '打印任务详情获取成功',
+      content: { 'application/json': { schema: PrintTaskDetailResponseSchema } }
+    },
+    404: {
+      description: '打印任务不存在',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(printTaskDetailRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+    const { taskId } = c.req.valid('param');
+
+    // 创建打印任务服务实例(使用默认配置,因为只需要查询数据库)
+    const printTaskService = new PrintTaskService(AppDataSource, {
+      baseUrl: 'https://api.feieyun.cn/Api/Open/',
+      user: '',
+      ukey: '',
+      timeout: 10000,
+      maxRetries: 3
+    });
+
+    const task = await printTaskService.repository.findOne({
+      where: { tenantId, taskId } as any
+    });
+
+    if (!task) {
+      return c.json({ success: false, message: '打印任务不存在' }, 404);
+    }
+
+    return c.json({
+      success: true,
+      data: {
+        id: task.id,
+        tenantId: task.tenantId,
+        taskId: task.taskId,
+        orderId: task.orderId,
+        printerSn: task.printerSn,
+        content: task.content,
+        printType: task.printType,
+        printStatus: task.printStatus,
+        errorMessage: task.errorMessage,
+        retryCount: task.retryCount,
+        maxRetries: task.maxRetries,
+        scheduledAt: task.scheduledAt ? task.scheduledAt.toISOString() : null,
+        printedAt: task.printedAt ? task.printedAt.toISOString() : null,
+        cancelledAt: task.cancelledAt ? task.cancelledAt.toISOString() : null,
+        cancelReason: task.cancelReason,
+        createdAt: task.createdAt.toISOString(),
+        updatedAt: task.updatedAt.toISOString()
+      }
+    });
+  });
+
+export default app;

+ 96 - 0
packages/feie-printer-module-mt/src/routes/tasks/retry.mt.ts

@@ -0,0 +1,96 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { PrintTaskService } from '../../services/print-task.service';
+import { getFeieApiConfig } from '../utils/feie-config.util';
+
+// 重试打印任务参数Schema
+const RetryPrintTaskParamsSchema = z.object({
+  taskId: z.string().min(1, '任务ID不能为空')
+});
+
+// 重试打印任务响应Schema
+const RetryPrintTaskResponseSchema = z.object({
+  success: z.boolean(),
+  data: z.object({
+    id: z.number(),
+    tenantId: z.number(),
+    taskId: z.string(),
+    printStatus: z.enum(['PENDING', 'DELAYED', 'PRINTING', 'SUCCESS', 'FAILED', 'CANCELLED']),
+    retryCount: z.number(),
+    errorMessage: z.string().nullable(),
+    updatedAt: z.string()
+  })
+});
+
+// 重试打印任务路由定义
+const retryPrintTaskRoute = createRoute({
+  method: 'post',
+  path: '/:taskId/retry',
+  middleware: [authMiddleware],
+  request: {
+    params: RetryPrintTaskParamsSchema
+  },
+  responses: {
+    200: {
+      description: '打印任务重试成功',
+      content: { 'application/json': { schema: RetryPrintTaskResponseSchema } }
+    },
+    400: {
+      description: '配置错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    },
+    404: {
+      description: '打印任务不存在',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(retryPrintTaskRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+    const { taskId } = c.req.valid('param');
+
+    try {
+      // 获取飞鹅API配置
+      const feieConfig = await getFeieApiConfig(tenantId, AppDataSource);
+      if (!feieConfig) {
+        return c.json({ success: false, message: '飞鹅API配置未找到或配置不完整' }, 400);
+      }
+
+      // 创建带配置的打印任务服务实例
+      const printTaskService = new PrintTaskService(AppDataSource, feieConfig);
+      const task = await printTaskService.retryPrintTask(tenantId, taskId);
+
+      return c.json({
+        success: true,
+        data: {
+          id: task.id,
+          tenantId: task.tenantId,
+          taskId: task.taskId,
+          printStatus: task.printStatus,
+          retryCount: task.retryCount,
+          errorMessage: task.errorMessage,
+          updatedAt: task.updatedAt.toISOString()
+        }
+      });
+    } catch (error) {
+      console.error(`[租户${tenantId}] 重试打印任务失败,任务ID: ${taskId}:`, error);
+      const errorMessage = error instanceof Error ? error.message : '重试打印任务失败';
+      return c.json({ success: false, message: errorMessage }, 500);
+    }
+  });
+
+export default app;

+ 96 - 0
packages/feie-printer-module-mt/src/routes/tasks/status.mt.ts

@@ -0,0 +1,96 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { z } from 'zod';
+import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
+import { PrintTaskService } from '../../services/print-task.service';
+import { getFeieApiConfig } from '../utils/feie-config.util';
+
+// 打印任务状态参数Schema
+const PrintTaskStatusParamsSchema = z.object({
+  taskId: z.string().min(1, '任务ID不能为空')
+});
+
+// 打印任务状态响应Schema
+const PrintTaskStatusResponseSchema = z.object({
+  success: z.boolean(),
+  data: z.object({
+    taskId: z.string(),
+    printStatus: z.enum(['PENDING', 'DELAYED', 'PRINTING', 'SUCCESS', 'FAILED', 'CANCELLED']),
+    feieStatus: z.string().optional(),
+    errorMessage: z.string().nullable(),
+    retryCount: z.number(),
+    printedAt: z.string().nullable(),
+    lastCheckedAt: z.string().optional()
+  })
+});
+
+// 打印任务状态路由定义
+const printTaskStatusRoute = createRoute({
+  method: 'get',
+  path: '/:taskId/status',
+  middleware: [authMiddleware],
+  request: {
+    params: PrintTaskStatusParamsSchema
+  },
+  responses: {
+    200: {
+      description: '打印任务状态获取成功',
+      content: { 'application/json': { schema: PrintTaskStatusResponseSchema } }
+    },
+    400: {
+      description: '配置错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    },
+    404: {
+      description: '打印任务不存在',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    },
+    401: {
+      description: '未授权',
+      content: { 'application/json': { schema: z.object({ message: z.string() }) } }
+    },
+    500: {
+      description: '服务器错误',
+      content: { 'application/json': { schema: z.object({ success: z.boolean(), message: z.string() }) } }
+    }
+  }
+});
+
+const app = new OpenAPIHono<AuthContext>()
+  .openapi(printTaskStatusRoute, async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+    const { taskId } = c.req.valid('param');
+
+    try {
+      // 获取飞鹅API配置
+      const feieConfig = await getFeieApiConfig(tenantId, AppDataSource);
+      if (!feieConfig) {
+        return c.json({ success: false, message: '飞鹅API配置未找到或配置不完整' }, 400);
+      }
+
+      // 创建带配置的打印任务服务实例
+      const printTaskService = new PrintTaskService(AppDataSource, feieConfig);
+      const status = await printTaskService.getPrintTaskStatus(tenantId, taskId);
+
+      return c.json({
+        success: true,
+        data: {
+          taskId: status.taskId,
+          printStatus: status.printStatus,
+          feieStatus: status.feieStatus,
+          errorMessage: status.errorMessage,
+          retryCount: status.retryCount,
+          printedAt: status.printedAt ? status.printedAt.toISOString() : null,
+          lastCheckedAt: status.lastCheckedAt ? status.lastCheckedAt.toISOString() : undefined
+        }
+      });
+    } catch (error) {
+      console.error(`[租户${tenantId}] 获取打印任务状态失败,任务ID: ${taskId}:`, error);
+      const errorMessage = error instanceof Error ? error.message : '获取打印任务状态失败';
+      return c.json({ success: false, message: errorMessage }, 500);
+    }
+  });
+
+export default app;