2
0
Эх сурвалжийг харах

♻️ refactor(api): 重构飞鹅打印客户端API路径处理

- 新增 `apiUrl` 工具函数统一处理API路径,确保路径以斜杠开头
- 将所有硬编码的API端点路径替换为使用 `apiUrl` 函数生成
- 更新默认的 `baseURL` 从 `/api` 改为 `/api/v1/feie`,以符合新的API版本和模块化路由结构
- 同步更新所有相关组件(PrinterManagement, PrintTaskQuery, PrintConfigManagement)和钩子(useFeiePrinter)的默认 `baseURL`

✨ feat(config): 新增打印配置管理服务与路由

- 新增 `ConfigService` 服务类,提供打印配置的CRUD操作
- 在 `feie.routes.ts` 中新增 `/config` 和 `/config/:configKey` 路由,用于获取和更新租户的打印配置
- 新增 `FeieConfigMt` 实体对应的 `config.service.ts` 文件,包含配置类型推断和描述映射功能
- 更新 `services/index.ts` 文件,导出新增的 `ConfigService`
yourname 1 сар өмнө
parent
commit
1ac9d723ac

+ 27 - 22
packages/feie-printer-management-ui-mt/src/api/feiePrinterClient.ts

@@ -18,6 +18,13 @@ import {
   ApiResponse
 } from '../types/feiePrinter';
 
+/**
+ * 生成API路径(不包含baseURL)
+ */
+function apiUrl(path: string): string {
+  return path.startsWith('/') ? path : `/${path}`;
+}
+
 /**
  * 飞鹅打印API客户端配置
  */
@@ -64,7 +71,7 @@ export class FeiePrinterClient {
    * 查询打印机列表
    */
   async getPrinters(params?: PrinterQueryParams): Promise<PrinterListResponse> {
-    const response = await this.client.get<ApiResponse<PrinterListResponse>>('/api/feie/printers', {
+    const response = await this.client.get<ApiResponse<PrinterListResponse>>(apiUrl('/printers'), {
       params
     });
     if (!response.data.success) {
@@ -77,7 +84,7 @@ export class FeiePrinterClient {
    * 添加打印机
    */
   async addPrinter(request: CreatePrinterRequest): Promise<FeiePrinter> {
-    const response = await this.client.post<ApiResponse<FeiePrinter>>('/api/feie/printers', request);
+    const response = await this.client.post<ApiResponse<FeiePrinter>>(apiUrl(`/printers`), request);
     if (!response.data.success) {
       throw new Error(response.data.message || '添加打印机失败');
     }
@@ -88,7 +95,7 @@ export class FeiePrinterClient {
    * 获取打印机详情
    */
   async getPrinter(printerSn: string): Promise<FeiePrinter> {
-    const response = await this.client.get<ApiResponse<FeiePrinter>>(`/api/feie/printers/${printerSn}`);
+    const response = await this.client.get<ApiResponse<FeiePrinter>>(apiUrl(`/printers/${printerSn}`));
     if (!response.data.success) {
       throw new Error(response.data.message || '获取打印机详情失败');
     }
@@ -99,7 +106,7 @@ export class FeiePrinterClient {
    * 更新打印机
    */
   async updatePrinter(printerSn: string, request: UpdatePrinterRequest): Promise<FeiePrinter> {
-    const response = await this.client.put<ApiResponse<FeiePrinter>>(`/api/feie/printers/${printerSn}`, request);
+    const response = await this.client.put<ApiResponse<FeiePrinter>>(apiUrl(`/printers/${printerSn}`), request);
     if (!response.data.success) {
       throw new Error(response.data.message || '更新打印机失败');
     }
@@ -110,7 +117,7 @@ export class FeiePrinterClient {
    * 删除打印机
    */
   async deletePrinter(printerSn: string): Promise<void> {
-    const response = await this.client.delete<ApiResponse<void>>(`/api/feie/printers/${printerSn}`);
+    const response = await this.client.delete<ApiResponse<void>>(apiUrl(`/printers/${printerSn}`));
     if (!response.data.success) {
       throw new Error(response.data.message || '删除打印机失败');
     }
@@ -121,7 +128,7 @@ export class FeiePrinterClient {
    */
   async getPrinterStatus(printerSn: string): Promise<{ status: string; lastCheck: string }> {
     const response = await this.client.get<ApiResponse<{ status: string; lastCheck: string }>>(
-      `/api/feie/printers/${printerSn}/status`
+      apiUrl(`/printers/${printerSn}/status`)
     );
     if (!response.data.success) {
       throw new Error(response.data.message || '获取打印机状态失败');
@@ -134,7 +141,7 @@ export class FeiePrinterClient {
    */
   async setDefaultPrinter(printerSn: string): Promise<FeiePrinter> {
     const response = await this.client.post<ApiResponse<FeiePrinter>>(
-      `/api/feie/printers/${printerSn}/set-default`
+      apiUrl(`/printers/${printerSn}/set-default`)
     );
     if (!response.data.success) {
       throw new Error(response.data.message || '设置默认打印机失败');
@@ -148,7 +155,7 @@ export class FeiePrinterClient {
    * 查询打印任务列表
    */
   async getPrintTasks(params?: PrintTaskQueryParams): Promise<PrintTaskListResponse> {
-    const response = await this.client.get<ApiResponse<PrintTaskListResponse>>('/api/feie/tasks', {
+    const response = await this.client.get<ApiResponse<PrintTaskListResponse>>(apiUrl('/tasks'), {
       params
     });
     if (!response.data.success) {
@@ -161,7 +168,7 @@ export class FeiePrinterClient {
    * 获取打印任务详情
    */
   async getPrintTask(taskId: string): Promise<FeiePrintTask> {
-    const response = await this.client.get<ApiResponse<FeiePrintTask>>(`/api/feie/tasks/${taskId}`);
+    const response = await this.client.get<ApiResponse<FeiePrintTask>>(apiUrl(`/tasks/${taskId}`));
     if (!response.data.success) {
       throw new Error(response.data.message || '获取打印任务详情失败');
     }
@@ -172,7 +179,7 @@ export class FeiePrinterClient {
    * 提交打印任务
    */
   async submitPrintTask(request: SubmitPrintTaskRequest): Promise<SubmitPrintTaskResponse> {
-    const response = await this.client.post<ApiResponse<SubmitPrintTaskResponse>>('/api/feie/tasks', request);
+    const response = await this.client.post<ApiResponse<SubmitPrintTaskResponse>>(apiUrl('/tasks'), request);
     if (!response.data.success) {
       throw new Error(response.data.message || '提交打印任务失败');
     }
@@ -184,7 +191,7 @@ export class FeiePrinterClient {
    */
   async getPrintTaskStatus(taskId: string): Promise<{ status: string; lastUpdate: string }> {
     const response = await this.client.get<ApiResponse<{ status: string; lastUpdate: string }>>(
-      `/api/feie/tasks/${taskId}/status`
+      apiUrl(`/tasks/${taskId}/status`)
     );
     if (!response.data.success) {
       throw new Error(response.data.message || '获取打印任务状态失败');
@@ -197,7 +204,7 @@ export class FeiePrinterClient {
    */
   async cancelPrintTask(request: CancelPrintTaskRequest): Promise<FeiePrintTask> {
     const response = await this.client.post<ApiResponse<FeiePrintTask>>(
-      `/api/feie/tasks/${request.taskId}/cancel`,
+      apiUrl(`/tasks/${request.taskId}/cancel`),
       { reason: request.reason }
     );
     if (!response.data.success) {
@@ -211,7 +218,7 @@ export class FeiePrinterClient {
    */
   async retryPrintTask(request: RetryPrintTaskRequest): Promise<FeiePrintTask> {
     const response = await this.client.post<ApiResponse<FeiePrintTask>>(
-      `/api/feie/tasks/${request.taskId}/retry`
+      apiUrl(`/tasks/${request.taskId}/retry`)
     );
     if (!response.data.success) {
       throw new Error(response.data.message || '重试打印任务失败');
@@ -225,7 +232,7 @@ export class FeiePrinterClient {
    * 查询打印配置列表
    */
   async getPrintConfigs(): Promise<ConfigListResponse> {
-    const response = await this.client.get<ApiResponse<ConfigListResponse>>('/api/feie/config');
+    const response = await this.client.get<ApiResponse<ConfigListResponse>>(apiUrl('/config'));
     if (!response.data.success) {
       throw new Error(response.data.message || '获取打印配置列表失败');
     }
@@ -237,7 +244,7 @@ export class FeiePrinterClient {
    */
   async updatePrintConfig(configKey: string, request: UpdateConfigRequest): Promise<FeieConfig> {
     const response = await this.client.put<ApiResponse<FeieConfig>>(
-      `/api/feie/config/${configKey}`,
+      apiUrl(`/config/${configKey}`),
       request
     );
     if (!response.data.success) {
@@ -253,8 +260,7 @@ export class FeiePrinterClient {
    */
   async getSchedulerStatus(): Promise<{ running: boolean; lastRun: string; nextRun: string }> {
     const response = await this.client.get<ApiResponse<{ running: boolean; lastRun: string; nextRun: string }>>(
-      '/api/feie/scheduler/status'
-    );
+      apiUrl('/scheduler/status'));
     if (!response.data.success) {
       throw new Error(response.data.message || '获取调度器状态失败');
     }
@@ -265,7 +271,7 @@ export class FeiePrinterClient {
    * 启动调度器
    */
   async startScheduler(): Promise<void> {
-    const response = await this.client.post<ApiResponse<void>>('/api/feie/scheduler/start');
+    const response = await this.client.post<ApiResponse<void>>(apiUrl('/scheduler/start'));
     if (!response.data.success) {
       throw new Error(response.data.message || '启动调度器失败');
     }
@@ -275,7 +281,7 @@ export class FeiePrinterClient {
    * 停止调度器
    */
   async stopScheduler(): Promise<void> {
-    const response = await this.client.post<ApiResponse<void>>('/api/feie/scheduler/stop');
+    const response = await this.client.post<ApiResponse<void>>(apiUrl('/scheduler/stop'));
     if (!response.data.success) {
       throw new Error(response.data.message || '停止调度器失败');
     }
@@ -286,8 +292,7 @@ export class FeiePrinterClient {
    */
   async getSchedulerHealth(): Promise<{ healthy: boolean; message: string; timestamp: string }> {
     const response = await this.client.get<ApiResponse<{ healthy: boolean; message: string; timestamp: string }>>(
-      '/api/feie/scheduler/health'
-    );
+      apiUrl('/scheduler/health'));
     if (!response.data.success) {
       throw new Error(response.data.message || '获取调度器健康状态失败');
     }
@@ -298,7 +303,7 @@ export class FeiePrinterClient {
 /**
  * 创建默认的飞鹅打印API客户端
  */
-export function createFeiePrinterClient(baseURL: string = '/api'): FeiePrinterClient {
+export function createFeiePrinterClient(baseURL: string = '/api/v1/feie'): FeiePrinterClient {
   return new FeiePrinterClient({
     baseURL,
     timeout: 10000

+ 1 - 1
packages/feie-printer-management-ui-mt/src/components/PrintConfigManagement.tsx

@@ -245,7 +245,7 @@ interface PrintConfigManagementProps {
  * 提供打印配置的查询、编辑和管理功能
  */
 export const PrintConfigManagement: React.FC<PrintConfigManagementProps> = ({
-  baseURL = '/api',
+  baseURL = '/api/v1/feie',
   tenantId,
   authToken
 }) => {

+ 1 - 1
packages/feie-printer-management-ui-mt/src/components/PrintTaskQuery.tsx

@@ -121,7 +121,7 @@ interface PrintTaskQueryProps {
  * 提供打印任务的查询、详情查看、重试、取消等功能
  */
 export const PrintTaskQuery: React.FC<PrintTaskQueryProps> = ({
-  baseURL = '/api',
+  baseURL = '/api/v1/feie',
   tenantId,
   authToken,
   pageSize = 10

+ 1 - 1
packages/feie-printer-management-ui-mt/src/components/PrinterManagement.tsx

@@ -136,7 +136,7 @@ interface PrinterManagementProps {
  * 提供打印机的添加、查询、删除、状态管理等功能
  */
 export const PrinterManagement: React.FC<PrinterManagementProps> = ({
-  baseURL = '/api',
+  baseURL = '/api/v1/feie',
   tenantId,
   authToken,
   pageSize = 10

+ 1 - 1
packages/feie-printer-management-ui-mt/src/hooks/useFeiePrinter.ts

@@ -29,7 +29,7 @@ interface UseFeiePrinterOptions {
  * 创建飞鹅打印客户端实例
  */
 const useFeieClient = (options: UseFeiePrinterOptions) => {
-  const { baseURL = '/api', tenantId, authToken } = options;
+  const { baseURL = '/api/v1/feie', tenantId, authToken } = options;
   const client = createFeiePrinterClient(baseURL);
 
   if (authToken) {

+ 35 - 0
packages/feie-printer-module-mt/src/routes/feie.routes.ts

@@ -4,6 +4,7 @@ import { AuthContext } from '@d8d/shared-types';
 import { PrinterService } from '../services/printer.service';
 import { PrintTaskService } from '../services/print-task.service';
 import { DelaySchedulerService } from '../services/delay-scheduler.service';
+import { ConfigService } from '../services/config.service';
 import { FeieApiConfig } from '../types/feie.types';
 
 /**
@@ -83,6 +84,7 @@ export function createFeieRoutes(dataSource: DataSource) {
     timeout: 10000,
     maxRetries: 3
   });
+  const configService = new ConfigService(dataSource);
 
   // 打印机管理路由
   app.get('/printers', async (c) => {
@@ -246,6 +248,39 @@ export function createFeieRoutes(dataSource: DataSource) {
     return c.json({ success: true, data: health });
   });
 
+  // 打印配置管理路由
+  app.get('/config', async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+
+    try {
+      const configs = await configService.getPrintConfigs(tenantId);
+      return c.json({ success: true, data: configs });
+    } catch (error) {
+      console.error(`[租户${tenantId}] 获取打印配置失败:`, error);
+      return c.json({ success: false, message: '获取打印配置失败' }, 500);
+    }
+  });
+
+  app.put('/config/:configKey', async (c) => {
+    const user = c.get('user');
+    const tenantId = user?.tenantId || 1;
+    const configKey = c.req.param('configKey');
+    const body = await c.req.json();
+
+    if (!body.configValue) {
+      return c.json({ success: false, message: '配置值不能为空' }, 400);
+    }
+
+    try {
+      const config = await configService.updatePrintConfig(tenantId, configKey, body.configValue);
+      return c.json({ success: true, data: config });
+    } catch (error) {
+      console.error(`[租户${tenantId}] 更新配置失败,key: ${configKey}:`, error);
+      return c.json({ success: false, message: '更新配置失败' }, 500);
+    }
+  });
+
   return app;
 }
 

+ 131 - 0
packages/feie-printer-module-mt/src/services/config.service.ts

@@ -0,0 +1,131 @@
+import { DataSource, Repository } from 'typeorm';
+import { FeieConfigMt } from '../entities/feie-config.mt.entity';
+
+/**
+ * 打印配置服务
+ */
+export class ConfigService {
+  private configRepository: Repository<FeieConfigMt>;
+
+  constructor(dataSource: DataSource) {
+    this.configRepository = dataSource.getRepository(FeieConfigMt);
+  }
+
+  /**
+   * 获取租户的所有打印配置
+   */
+  async getPrintConfigs(tenantId: number): Promise<FeieConfigMt[]> {
+    try {
+      const configs = await this.configRepository.find({
+        where: { tenantId },
+        order: { configKey: 'ASC' }
+      });
+
+      // 如果没有配置,返回空数组
+      return configs || [];
+    } catch (error) {
+      console.error(`[租户${tenantId}] 获取打印配置失败:`, error);
+      throw new Error('获取打印配置失败');
+    }
+  }
+
+  /**
+   * 获取单个配置项
+   */
+  async getPrintConfig(tenantId: number, configKey: string): Promise<FeieConfigMt | null> {
+    try {
+      const config = await this.configRepository.findOne({
+        where: { tenantId, configKey }
+      });
+
+      return config || null;
+    } catch (error) {
+      console.error(`[租户${tenantId}] 获取配置项失败,key: ${configKey}:`, error);
+      throw new Error('获取配置项失败');
+    }
+  }
+
+  /**
+   * 更新打印配置
+   */
+  async updatePrintConfig(
+    tenantId: number,
+    configKey: string,
+    configValue: string
+  ): Promise<FeieConfigMt> {
+    try {
+      // 查找现有配置
+      let config = await this.configRepository.findOne({
+        where: { tenantId, configKey }
+      });
+
+      if (config) {
+        // 更新现有配置
+        config.configValue = configValue;
+        config.updatedAt = new Date();
+        await this.configRepository.save(config);
+      } else {
+        // 创建新配置
+        config = this.configRepository.create({
+          tenantId,
+          configKey,
+          configValue,
+          configType: this.guessConfigType(configValue),
+          description: this.getConfigDescription(configKey)
+        });
+        await this.configRepository.save(config);
+      }
+
+      return config;
+    } catch (error) {
+      console.error(`[租户${tenantId}] 更新配置失败,key: ${configKey}:`, error);
+      throw new Error('更新配置失败');
+    }
+  }
+
+  /**
+   * 根据配置值猜测配置类型
+   */
+  private guessConfigType(configValue: string): string {
+    // 尝试解析为JSON
+    try {
+      JSON.parse(configValue);
+      return 'JSON';
+    } catch {
+      // 不是JSON
+    }
+
+    // 检查是否为布尔值
+    if (configValue.toLowerCase() === 'true' || configValue.toLowerCase() === 'false') {
+      return 'BOOLEAN';
+    }
+
+    // 检查是否为数字
+    if (!isNaN(Number(configValue)) && configValue.trim() !== '') {
+      return 'NUMBER';
+    }
+
+    // 默认为字符串
+    return 'STRING';
+  }
+
+  /**
+   * 获取配置项描述
+   */
+  private getConfigDescription(configKey: string): string {
+    const descriptions: Record<string, string> = {
+      'feie.enabled': '是否启用飞鹅打印功能',
+      'feie.default_printer_sn': '默认使用的打印机序列号',
+      'feie.auto_print_on_payment': '订单支付成功后是否自动打印小票',
+      'feie.auto_print_on_shipping': '订单发货时是否自动打印发货单',
+      'feie.anti_refund_delay': '支付成功后等待确认无退款的时间(秒)',
+      'feie.retry_max_count': '打印失败时的最大重试次数',
+      'feie.retry_interval': '打印失败后重试的间隔时间(秒)',
+      'feie.task_timeout': '打印任务的最大执行时间(秒)',
+      'feie.receipt_template': '小票打印的模板内容',
+      'feie.shipping_template': '发货单打印的模板内容'
+    };
+
+    return descriptions[configKey] || '打印配置项';
+  }
+}

+ 1 - 0
packages/feie-printer-module-mt/src/services/index.ts

@@ -3,3 +3,4 @@ export * from './printer.service';
 export * from './print-task.service';
 export * from './delay-scheduler.service';
 export * from './print-trigger.service';
+export * from './config.service';