Преглед изворни кода

Merge remote-tracking branch 'upstream/mini-multi-tenant-mall' into mini-multi-tenant-mall

yourname пре 2 месеци
родитељ
комит
b121e224b0
62 измењених фајлова са 3264 додато и 269 уклоњено
  1. 4 1
      .claude/settings.local.json
  2. 3 0
      mini/.env.development
  3. 1 1
      mini/project.config.json
  4. 2 2
      mini/src/api.ts
  5. 7 10
      mini/src/pages/address-edit/index.tsx
  6. 2 1
      mini/src/pages/login/wechat-login.tsx
  7. 1 1
      mini/src/pages/order-submit/index.tsx
  8. 2 1
      mini/src/utils/auth.tsx
  9. 8 3
      packages/core-module-mt/auth-module-mt/src/routes/mini-login.route.mt.ts
  10. 28 7
      packages/core-module-mt/auth-module-mt/src/services/mini-auth.service.mt.ts
  11. 146 0
      packages/core-module-mt/auth-module-mt/tests/integration/system-config-integration.test.ts
  12. 37 1
      packages/core-module-mt/package.json
  13. 18 0
      packages/core-module-mt/system-config-module-mt/src/constants/config-keys.constants.mt.ts
  14. 1 0
      packages/core-module-mt/system-config-module-mt/src/constants/index.mt.ts
  15. 1 0
      packages/core-module-mt/system-config-module-mt/src/entities/index.mt.ts
  16. 36 0
      packages/core-module-mt/system-config-module-mt/src/entities/system-config.entity.mt.ts
  17. 22 0
      packages/core-module-mt/system-config-module-mt/src/index.mt.ts
  18. 27 0
      packages/core-module-mt/system-config-module-mt/src/routes/system-config.routes.mt.ts
  19. 1 0
      packages/core-module-mt/system-config-module-mt/src/schemas/index.mt.ts
  20. 72 0
      packages/core-module-mt/system-config-module-mt/src/schemas/system-config.schema.mt.ts
  21. 1 0
      packages/core-module-mt/system-config-module-mt/src/services/index.mt.ts
  22. 211 0
      packages/core-module-mt/system-config-module-mt/src/services/system-config.service.mt.ts
  23. 303 0
      packages/core-module-mt/system-config-module-mt/tests/integration/system-config-redis-cache.integration.test.ts
  24. 319 0
      packages/core-module-mt/system-config-module-mt/tests/integration/system-config.routes.integration.test.ts
  25. 61 0
      packages/core-module-mt/system-config-module-mt/tests/utils/integration-test-db.ts
  26. 3 1
      packages/core-module-mt/tsconfig.json
  27. 3 3
      packages/core-module-mt/user-module-mt/src/routes/user.routes.mt.ts
  28. 2 1
      packages/core-module-mt/vitest.config.ts
  29. 29 23
      packages/geo-areas-mt/src/api/areas/index.mt.ts
  30. 124 10
      packages/geo-areas-mt/tests/integration/areas.integration.test.ts
  31. 0 8
      packages/geo-areas-mt/tests/utils/test-query-factory.ts
  32. 1 0
      packages/mini-payment-mt/package.json
  33. 0 15
      packages/mini-payment-mt/src/routes/payment.routes.ts
  34. 113 40
      packages/mini-payment-mt/src/services/payment.mt.service.ts
  35. 221 0
      packages/mini-payment-mt/tests/integration/system-config-integration.test.ts
  36. 0 63
      packages/orders-module-mt/src/routes/create-order.mt.ts
  37. 1 1
      packages/orders-module-mt/src/routes/index.ts
  38. 60 0
      packages/orders-module-mt/src/routes/user/create-order.mt.ts
  39. 8 2
      packages/orders-module-mt/src/routes/user/orders.mt.ts
  40. 1 0
      packages/server/package.json
  41. 41 30
      packages/server/src/index.ts
  42. 94 0
      packages/shared-utils/src/utils/redis.util.ts
  43. 43 0
      packages/system-config-management-ui-mt/eslint.config.js
  44. 92 0
      packages/system-config-management-ui-mt/package.json
  45. 5 0
      packages/system-config-management-ui-mt/src/api/index.ts
  46. 44 0
      packages/system-config-management-ui-mt/src/api/systemConfigClient.ts
  47. 525 0
      packages/system-config-management-ui-mt/src/components/SystemConfigManagement.tsx
  48. 1 0
      packages/system-config-management-ui-mt/src/components/index.ts
  49. 18 0
      packages/system-config-management-ui-mt/src/index.ts
  50. 8 0
      packages/system-config-management-ui-mt/src/types/index.ts
  51. 19 0
      packages/system-config-management-ui-mt/src/types/systemConfig.ts
  52. 303 0
      packages/system-config-management-ui-mt/tests/integration/system-config-management.integration.test.tsx
  53. 14 0
      packages/system-config-management-ui-mt/tests/setup.ts
  54. 36 0
      packages/system-config-management-ui-mt/tsconfig.json
  55. 24 0
      packages/system-config-management-ui-mt/vitest.config.ts
  56. 100 0
      pnpm-lock.yaml
  57. 1 0
      web/package.json
  58. 3 7
      web/src/client/admin/api_init.ts
  59. 5 5
      web/src/client/admin/menu.tsx
  60. 7 1
      web/src/client/admin/routes.tsx
  61. 0 30
      web/src/client/tenant/api_init.ts
  62. 1 1
      web/src/client/tenant/routes.tsx

+ 4 - 1
.claude/settings.local.json

@@ -48,8 +48,11 @@
       "Bash(pnpm test:integration:*)",
       "Bash(pnpm --filter:*)",
       "Bash(tree:*)",
+      "Bash(mv:*)",
+      "Bash(rm:*)",
+      "Bash(git add:*)",
       "Bash(git commit:*)",
-      "Bash(pnpm build:weapp:*)"
+      "Bash(pnpm typecheck:*)"
     ],
     "deny": [],
     "ask": []

+ 3 - 0
mini/.env.development

@@ -5,3 +5,6 @@
 # 需换成当前项目的
 TARO_APP_API_BASE_URL=https://d8d-ai-vscode-8080-186-175-template-6-group.r.d8d.fun
 TARO_APP_API_VERSION=v1
+
+# 租户ID
+TARO_APP_TENANT_ID=1

+ 1 - 1
mini/project.config.json

@@ -2,7 +2,7 @@
   "miniprogramRoot": "./dist",
   "projectname": "mini",
   "description": "",
-  "appid": "wx6765e6b2fe06378c",
+  "appid": "wx224c7b7d5e4ed130",
   "setting": {
     "urlCheck": false,
     "es6": false,

+ 2 - 2
mini/src/api.ts

@@ -7,7 +7,7 @@ import type {
   GoodsCategoryRoutes,
   DeliveryAddressRoutes,
   OrderRoutes,
-  OrderGoodsRoutes,
+  // OrderGoodsRoutes,
   MerchantRoutes,
   AreaRoutes,
   AdvertisementRoutes
@@ -25,7 +25,7 @@ export const goodsClient = rpcClient<GoodsRoutes>().api.v1.goods
 export const goodsCategoryClient = rpcClient<GoodsCategoryRoutes>().api.v1['goods-categories']
 export const deliveryAddressClient = rpcClient<DeliveryAddressRoutes>().api.v1['delivery-addresses']
 export const orderClient = rpcClient<OrderRoutes>().api.v1.orders
-export const orderGoodsClient = rpcClient<OrderGoodsRoutes>().api.v1['orders-goods']
+// export const orderGoodsClient = rpcClient<OrderGoodsRoutes>().api.v1['orders-goods']
 export const merchantClient = rpcClient<MerchantRoutes>().api.v1.merchants
 
 // 系统相关客户端

+ 7 - 10
mini/src/pages/address-edit/index.tsx

@@ -16,9 +16,6 @@ import { Switch } from '@/components/ui/switch'
 import { useAuth } from '@/utils/auth'
 import { CitySelector } from '@/components/ui/city-selector'
 
-type Address = InferResponseType<typeof deliveryAddressClient[':id']['$get'], 200>
-type CreateAddressRequest = InferRequestType<typeof deliveryAddressClient.$post>['json']
-type UpdateAddressRequest = InferRequestType<typeof deliveryAddressClient[':id']['$put']>['json']
 
 const addressSchema = z.object({
   name: z.string().min(1, '请输入收货人姓名'),
@@ -26,6 +23,7 @@ const addressSchema = z.object({
   province: z.number().positive('请选择省份'),
   city: z.number().positive('请选择城市'),
   district: z.number().positive('请选择区县'),
+  town: z.number().optional(),
   address: z.string().min(1, '请输入详细地址'),
   isDefault: z.boolean().optional()
 })
@@ -70,6 +68,7 @@ export default function AddressEditPage() {
       province: 0,
       city: 0,
       district: 0,
+      town: 0,
       address: '',
       isDefault: false
     }
@@ -84,6 +83,7 @@ export default function AddressEditPage() {
         province: address.receiverProvince,
         city: address.receiverCity,
         district: address.receiverDistrict,
+        town: address.receiverTown || 0,
         address: address.address,
         isDefault: address.isDefault === 1
       })
@@ -99,6 +99,7 @@ export default function AddressEditPage() {
         receiverProvince: data.province,
         receiverCity: data.city,
         receiverDistrict: data.district,
+        receiverTown: data.town || 0,
         address: data.address,
         userId: user?.id,
         isDefault: data.isDefault ? 1 : 0
@@ -135,12 +136,6 @@ export default function AddressEditPage() {
     }
   })
 
-  // 处理地区变化
-  const handleCityChange = (provinceId: number, cityId: number, districtId: number) => {
-    form.setValue('province', provinceId)
-    form.setValue('city', cityId)
-    form.setValue('district', districtId)
-  }
 
   const onSubmit = (data: AddressFormData) => {
     saveAddressMutation.mutate(data)
@@ -192,9 +187,11 @@ export default function AddressEditPage() {
                       provinceValue={form.watch('province')}
                       cityValue={form.watch('city')}
                       districtValue={form.watch('district')}
+                      townValue={form.watch('town')}
                       onProvinceChange={(value) => form.setValue('province', value)}
                       onCityChange={(value) => form.setValue('city', value)}
                       onDistrictChange={(value) => form.setValue('district', value)}
+                      onTownChange={(value) => form.setValue('town', value)}
                       showLabels={false}
                     />
                   </View>
@@ -237,7 +234,7 @@ export default function AddressEditPage() {
 
               <Button
                 className="w-full"
-                onClick={form.handleSubmit(onSubmit, (errors) => console.debug('表单验证错误:', errors))}
+                onClick={() => form.handleSubmit(onSubmit, (errors) => console.debug('表单验证错误:', errors))()}
                 disabled={saveAddressMutation.isPending}
               >
                 {saveAddressMutation.isPending ? '保存中...' : '保存地址'}

+ 2 - 1
mini/src/pages/login/wechat-login.tsx

@@ -67,7 +67,8 @@ export default function WechatLogin() {
       const response = await authClient['mini-login'].$post({
         json: {
           code: loginRes.code,
-          userInfo: userProfile.userInfo
+          userInfo: userProfile.userInfo,
+          tenantId: Number(process.env.TARO_APP_TENANT_ID) || 1
         }
       })
 

+ 1 - 1
mini/src/pages/order-submit/index.tsx

@@ -67,7 +67,7 @@ export default function OrderSubmitPage() {
       }
 
       const response = await orderClient['create-order']['$post']({ json: orderData })
-      if (response.status !== 200) {
+      if (response.status !== 201) {
         throw new Error('创建订单失败')
       }
       return response.json()

+ 2 - 1
mini/src/utils/auth.tsx

@@ -66,8 +66,9 @@ export const AuthProvider: React.FC<PropsWithChildren> = ({ children }) => {
         // 使用小程序code进行静默登录
         const response = await authClient['mini-login'].$post({
           json: {
-            code: loginRes.code
+            code: loginRes.code,
             // 静默登录不请求用户信息
+            tenantId: Number(process.env.TARO_APP_TENANT_ID) || 1
           }
         })
 

+ 8 - 3
packages/core-module-mt/auth-module-mt/src/routes/mini-login.route.mt.ts

@@ -6,6 +6,11 @@ import { ErrorSchema } from '@d8d/shared-utils';
 import { UserEntityMt } from '@d8d/core-module-mt/user-module-mt';
 import { MiniLoginSchema, MiniLoginResponseSchema } from '../schemas/index.mt';
 
+// 扩展MiniLoginSchema以支持租户ID
+const MiniLoginWithTenantSchema = MiniLoginSchema.extend({
+  tenantId: z.number().optional()
+});
+
 
 const miniLoginRoute = createRoute({
   method: 'post',
@@ -14,7 +19,7 @@ const miniLoginRoute = createRoute({
     body: {
       content: {
         'application/json': {
-          schema: MiniLoginSchema
+          schema: MiniLoginWithTenantSchema
         }
       }
     }
@@ -52,9 +57,9 @@ const app = new OpenAPIHono().openapi(miniLoginRoute, async (c) => {
     // 在路由处理函数内部初始化服务
     const miniAuthService = new MiniAuthService(AppDataSource);
 
-    const { code, userInfo } = c.req.valid('json');
+    const { code, userInfo, tenantId } = c.req.valid('json');
 
-    const result = await miniAuthService.miniLogin(code);
+    const result = await miniAuthService.miniLogin(code, tenantId);
 
     // 如果有用户信息,更新用户资料
     if (userInfo) {

+ 28 - 7
packages/core-module-mt/auth-module-mt/src/services/mini-auth.service.mt.ts

@@ -1,6 +1,7 @@
 import { DataSource, Repository } from 'typeorm';
 import { UserEntityMt } from '@d8d/core-module-mt/user-module-mt';
 import { FileServiceMt } from '@d8d/core-module-mt/file-module-mt';
+import { SystemConfigServiceMt } from '@d8d/core-module-mt/system-config-module-mt';
 import { JWTUtil, redisUtil } from '@d8d/shared-utils';
 import axios from 'axios';
 import process from 'node:process'
@@ -8,15 +9,17 @@ import process from 'node:process'
 export class MiniAuthService {
   private userRepository: Repository<UserEntityMt>;
   private fileService: FileServiceMt;
+  private systemConfigService: SystemConfigServiceMt;
 
   constructor(dataSource: DataSource) {
     this.userRepository = dataSource.getRepository(UserEntityMt);
     this.fileService = new FileServiceMt(dataSource);
+    this.systemConfigService = new SystemConfigServiceMt(dataSource);
   }
 
-  async miniLogin(code: string): Promise<{ token: string; user: UserEntityMt; isNewUser: boolean }> {
+  async miniLogin(code: string, tenantId?: number): Promise<{ token: string; user: UserEntityMt; isNewUser: boolean }> {
     // 1. 通过code获取openid和session_key
-    const openidInfo = await this.getOpenIdByCode(code);
+    const openidInfo = await this.getOpenIdByCode(code, tenantId);
 
     // 2. 查找或创建用户
     let user = await this.userRepository.findOne({
@@ -27,7 +30,7 @@ export class MiniAuthService {
 
     if (!user) {
       // 自动注册新用户
-      user = await this.createMiniUser(openidInfo);
+      user = await this.createMiniUser(openidInfo, tenantId);
       isNewUser = true;
     }
 
@@ -66,9 +69,26 @@ export class MiniAuthService {
     return await this.userRepository.save(user);
   }
 
-  private async getOpenIdByCode(code: string): Promise<{ openid: string; unionid?: string; session_key: string }> {
-    const appId = process.env.WX_MINI_APP_ID;
-    const appSecret = process.env.WX_MINI_APP_SECRET;
+  private async getOpenIdByCode(code: string, tenantId?: number): Promise<{ openid: string; unionid?: string; session_key: string }> {
+    // 优先从系统配置获取,如果配置不存在则回退到环境变量
+    let appId: string | null = null;
+    let appSecret: string | null = null;
+
+    if (tenantId !== undefined) {
+      // 从系统配置获取
+      const configKeys = ['wx.mini.app.id', 'wx.mini.app.secret'];
+      const configs = await this.systemConfigService.getConfigsByKeys(configKeys, tenantId);
+      appId = configs['wx.mini.app.id'];
+      appSecret = configs['wx.mini.app.secret'];
+    }
+
+    // 如果系统配置中没有找到,回退到环境变量
+    if (!appId) {
+      appId = process.env.WX_MINI_APP_ID || null;
+    }
+    if (!appSecret) {
+      appSecret = process.env.WX_MINI_APP_SECRET || null;
+    }
 
     if (!appId || !appSecret) {
       throw new Error('微信小程序配置缺失');
@@ -96,8 +116,9 @@ export class MiniAuthService {
     }
   }
 
-  private async createMiniUser(openidInfo: { openid: string; unionid?: string }): Promise<UserEntityMt> {
+  private async createMiniUser(openidInfo: { openid: string; unionid?: string }, tenantId?: number): Promise<UserEntityMt> {
     const user = this.userRepository.create({
+      tenantId: tenantId || 1, // 默认租户ID为1,如果未提供
       username: `wx_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
       password: '', // 小程序用户不需要密码
       openid: openidInfo.openid,

+ 146 - 0
packages/core-module-mt/auth-module-mt/tests/integration/system-config-integration.test.ts

@@ -0,0 +1,146 @@
+import { describe, it, expect, beforeEach, afterEach } from 'vitest';
+import {
+  IntegrationTestDatabase,
+  setupIntegrationDatabaseHooksWithEntities
+} from '@d8d/shared-test-util';
+import { MiniAuthService } from '../../src/services/index.mt';
+import { SystemConfigServiceMt } from '@d8d/core-module-mt/system-config-module-mt';
+import { SystemConfigMt } from '@d8d/core-module-mt/system-config-module-mt';
+import { UserEntityMt, RoleMt } from '@d8d/core-module-mt/user-module-mt';
+import { FileMt } from '@d8d/core-module-mt/file-module-mt';
+
+// 设置集成测试钩子
+setupIntegrationDatabaseHooksWithEntities([SystemConfigMt, UserEntityMt, RoleMt, FileMt])
+
+/**
+ * 认证模块系统配置集成测试
+ * 验证MiniAuthService与SystemConfigServiceMt的集成
+ */
+describe('认证模块系统配置集成测试', () => {
+  let miniAuthService: MiniAuthService;
+  let systemConfigService: SystemConfigServiceMt;
+  const testTenantId = 1;
+
+  beforeEach(async () => {
+    // 获取数据源
+    const dataSource = await IntegrationTestDatabase.getDataSource();
+    if (!dataSource) throw new Error('Database not initialized');
+
+    miniAuthService = new MiniAuthService(dataSource);
+    systemConfigService = new SystemConfigServiceMt(dataSource);
+
+    // 清理测试配置
+    await systemConfigService.deleteConfig('wx.mini.app.id', testTenantId);
+    await systemConfigService.deleteConfig('wx.mini.app.secret', testTenantId);
+  });
+
+  afterEach(async () => {
+    // 清理测试配置
+    await systemConfigService.deleteConfig('wx.mini.app.id', testTenantId);
+    await systemConfigService.deleteConfig('wx.mini.app.secret', testTenantId);
+  });
+
+  describe('系统配置读取功能', () => {
+    it('应该从系统配置获取小程序AppID和Secret', async () => {
+      // 设置测试配置
+      await systemConfigService.setConfig('wx.mini.app.id', 'test-app-id', testTenantId, '测试小程序AppID');
+      await systemConfigService.setConfig('wx.mini.app.secret', 'test-app-secret', testTenantId, '测试小程序AppSecret');
+
+      // 验证配置读取
+      const appId = await systemConfigService.getConfigByKey('wx.mini.app.id', testTenantId);
+      const appSecret = await systemConfigService.getConfigByKey('wx.mini.app.secret', testTenantId);
+
+      expect(appId).toBe('test-app-id');
+      expect(appSecret).toBe('test-app-secret');
+    });
+
+    it('应该支持批量获取配置', async () => {
+      // 设置测试配置
+      await systemConfigService.setConfig('wx.mini.app.id', 'test-app-id', testTenantId, '测试小程序AppID');
+      await systemConfigService.setConfig('wx.mini.app.secret', 'test-app-secret', testTenantId, '测试小程序AppSecret');
+
+      // 批量获取配置
+      const configs = await systemConfigService.getConfigsByKeys(
+        ['wx.mini.app.id', 'wx.mini.app.secret'],
+        testTenantId
+      );
+
+      expect(configs['wx.mini.app.id']).toBe('test-app-id');
+      expect(configs['wx.mini.app.secret']).toBe('test-app-secret');
+    });
+  });
+
+  describe('租户配置隔离', () => {
+    const tenant1Id = 1;
+    const tenant2Id = 2;
+
+    it('应该支持不同租户的独立配置', async () => {
+      // 为租户1设置配置
+      await systemConfigService.setConfig('wx.mini.app.id', 'tenant1-app-id', tenant1Id, '租户1小程序AppID');
+      await systemConfigService.setConfig('wx.mini.app.secret', 'tenant1-app-secret', tenant1Id, '租户1小程序AppSecret');
+
+      // 为租户2设置不同的配置
+      await systemConfigService.setConfig('wx.mini.app.id', 'tenant2-app-id', tenant2Id, '租户2小程序AppID');
+      await systemConfigService.setConfig('wx.mini.app.secret', 'tenant2-app-secret', tenant2Id, '租户2小程序AppSecret');
+
+      // 验证租户1的配置
+      const tenant1AppId = await systemConfigService.getConfigByKey('wx.mini.app.id', tenant1Id);
+      const tenant1AppSecret = await systemConfigService.getConfigByKey('wx.mini.app.secret', tenant1Id);
+
+      // 验证租户2的配置
+      const tenant2AppId = await systemConfigService.getConfigByKey('wx.mini.app.id', tenant2Id);
+      const tenant2AppSecret = await systemConfigService.getConfigByKey('wx.mini.app.secret', tenant2Id);
+
+      expect(tenant1AppId).toBe('tenant1-app-id');
+      expect(tenant1AppSecret).toBe('tenant1-app-secret');
+      expect(tenant2AppId).toBe('tenant2-app-id');
+      expect(tenant2AppSecret).toBe('tenant2-app-secret');
+
+      // 验证配置隔离
+      expect(tenant1AppId).not.toBe(tenant2AppId);
+      expect(tenant1AppSecret).not.toBe(tenant2AppSecret);
+    });
+  });
+
+  describe('配置缓存功能', () => {
+    it('应该支持配置缓存', async () => {
+      // 设置配置
+      await systemConfigService.setConfig('wx.mini.app.id', 'cached-app-id', testTenantId, '缓存测试小程序AppID');
+
+      // 第一次读取(应该写入缓存)
+      const firstRead = await systemConfigService.getConfigByKey('wx.mini.app.id', testTenantId);
+      expect(firstRead).toBe('cached-app-id');
+
+      // 第二次读取(应该从缓存读取)
+      const secondRead = await systemConfigService.getConfigByKey('wx.mini.app.id', testTenantId);
+      expect(secondRead).toBe('cached-app-id');
+    });
+
+    it('应该支持空值缓存', async () => {
+      // 读取不存在的配置(应该设置空值缓存)
+      const nonExistentConfig = await systemConfigService.getConfigByKey('non.existent.key', testTenantId);
+      expect(nonExistentConfig).toBeNull();
+
+      // 再次读取(应该从空值缓存返回)
+      const cachedRead = await systemConfigService.getConfigByKey('non.existent.key', testTenantId);
+      expect(cachedRead).toBeNull();
+    });
+  });
+
+  describe('MiniAuthService集成', () => {
+    it('应该正确注入SystemConfigServiceMt依赖', () => {
+      // 验证服务实例化
+      expect(miniAuthService).toBeDefined();
+      expect(miniAuthService).toBeInstanceOf(MiniAuthService);
+    });
+
+    it('应该支持租户ID参数', async () => {
+      // 验证miniLogin方法支持tenantId参数
+      const method = miniAuthService.miniLogin;
+      expect(typeof method).toBe('function');
+
+      // 验证方法签名包含tenantId参数
+      expect(method.length).toBeGreaterThanOrEqual(1);
+    });
+  });
+});

+ 37 - 1
packages/core-module-mt/package.json

@@ -93,6 +93,41 @@
       "types": "./file-module-mt/src/routes/index.ts",
       "import": "./file-module-mt/src/routes/index.ts",
       "require": "./file-module-mt/src/routes/index.ts"
+    },
+    "./system-config-module-mt": {
+      "types": "./system-config-module-mt/src/index.mt.ts",
+      "import": "./system-config-module-mt/src/index.mt.ts",
+      "require": "./system-config-module-mt/src/index.mt.ts"
+    },
+    "./system-config-module-mt/entities": {
+      "types": "./system-config-module-mt/src/entities/index.mt.ts",
+      "import": "./system-config-module-mt/src/entities/index.mt.ts",
+      "require": "./system-config-module-mt/src/entities/index.mt.ts"
+    },
+    "./system-config-module-mt/services": {
+      "types": "./system-config-module-mt/src/services/index.mt.ts",
+      "import": "./system-config-module-mt/src/services/index.mt.ts",
+      "require": "./system-config-module-mt/src/services/index.mt.ts"
+    },
+    "./system-config-module-mt/schemas": {
+      "types": "./system-config-module-mt/src/schemas/index.mt.ts",
+      "import": "./system-config-module-mt/src/schemas/index.mt.ts",
+      "require": "./system-config-module-mt/src/schemas/index.mt.ts"
+    },
+    "./system-config-module-mt/schemas/*": {
+      "types": "./system-config-module-mt/src/schemas/*",
+      "import": "./system-config-module-mt/src/schemas/*",
+      "require": "./system-config-module-mt/src/schemas/*"
+    },
+    "./system-config-module-mt/routes": {
+      "types": "./system-config-module-mt/src/routes/index.mt.ts",
+      "import": "./system-config-module-mt/src/routes/index.mt.ts",
+      "require": "./system-config-module-mt/src/routes/index.mt.ts"
+    },
+    "./system-config-module-mt/constants": {
+      "types": "./system-config-module-mt/src/constants/index.mt.ts",
+      "import": "./system-config-module-mt/src/constants/index.mt.ts",
+      "require": "./system-config-module-mt/src/constants/index.mt.ts"
     }
   },
   "scripts": {
@@ -132,6 +167,7 @@
   "files": [
     "user-module-mt/src",
     "auth-module-mt/src",
-    "file-module-mt/src"
+    "file-module-mt/src",
+    "system-config-module-mt/src"
   ]
 }

+ 18 - 0
packages/core-module-mt/system-config-module-mt/src/constants/config-keys.constants.mt.ts

@@ -0,0 +1,18 @@
+/**
+ * 系统配置键常量定义
+ * 用于认证和支付模块的系统配置集成
+ */
+
+export const CONFIG_KEYS = {
+  // 微信小程序认证配置
+  WX_MINI_APP_ID: 'wx.mini.app.id',
+  WX_MINI_APP_SECRET: 'wx.mini.app.secret',
+
+  // 微信支付配置
+  WX_PAYMENT_MERCHANT_ID: 'wx.payment.merchant.id',
+  WX_PAYMENT_V3_KEY: 'wx.payment.v3.key',
+  WX_PAYMENT_CERT_SERIAL_NO: 'wx.payment.cert.serial.no',
+  WX_PAYMENT_PUBLIC_KEY: 'wx.payment.public.key',
+  WX_PAYMENT_PRIVATE_KEY: 'wx.payment.private.key',
+  WX_PAYMENT_NOTIFY_URL: 'wx.payment.notify.url',
+} as const;

+ 1 - 0
packages/core-module-mt/system-config-module-mt/src/constants/index.mt.ts

@@ -0,0 +1 @@
+export { CONFIG_KEYS } from './config-keys.constants.mt';

+ 1 - 0
packages/core-module-mt/system-config-module-mt/src/entities/index.mt.ts

@@ -0,0 +1 @@
+export { SystemConfigMt } from './system-config.entity.mt';

+ 36 - 0
packages/core-module-mt/system-config-module-mt/src/entities/system-config.entity.mt.ts

@@ -0,0 +1,36 @@
+import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
+
+@Entity('system_config_mt')
+export class SystemConfigMt {
+  @PrimaryGeneratedColumn({ name: 'id', type: 'int', unsigned: true })
+  id!: number;
+
+  @Column({ name: 'tenant_id', type: 'int', unsigned: true, comment: '租户ID' })
+  tenantId!: number;
+
+  @Column({ name: 'config_key', type: 'varchar', length: 255, comment: '配置键' })
+  configKey!: string;
+
+  @Column({ name: 'config_value', type: 'text', comment: '配置值' })
+  configValue!: string;
+
+  @Column({ name: 'description', type: 'text', nullable: true, comment: '配置描述' })
+  description!: string | null;
+
+  @Column({ name: 'created_by', type: 'int', unsigned: true, nullable: true, comment: '创建用户ID' })
+  createdBy!: number | null;
+
+  @Column({ name: 'updated_by', type: 'int', unsigned: true, nullable: true, comment: '更新用户ID' })
+  updatedBy!: number | null;
+
+  @Column({ name: 'created_at', type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
+  createdAt!: Date;
+
+  @Column({
+    name: 'updated_at',
+    type: 'timestamp',
+    default: () => 'CURRENT_TIMESTAMP',
+    onUpdate: 'CURRENT_TIMESTAMP'
+  })
+  updatedAt!: Date;
+}

+ 22 - 0
packages/core-module-mt/system-config-module-mt/src/index.mt.ts

@@ -0,0 +1,22 @@
+// 实体导出
+export { SystemConfigMt } from './entities/system-config.entity.mt';
+
+// Schema导出
+export {
+  SystemConfigSchema,
+  CreateSystemConfigSchema,
+  UpdateSystemConfigSchema,
+  SystemConfigListSchema
+} from './schemas/system-config.schema.mt';
+
+// 服务导出
+export { SystemConfigServiceMt } from './services/system-config.service.mt';
+
+// 路由导出
+export { systemConfigRoutesMt } from './routes/system-config.routes.mt';
+
+// 类型导出
+export type { SystemConfigMt as SystemConfigEntity } from './entities/system-config.entity.mt';
+
+// 常量导出
+export { CONFIG_KEYS } from './constants/config-keys.constants.mt';

+ 27 - 0
packages/core-module-mt/system-config-module-mt/src/routes/system-config.routes.mt.ts

@@ -0,0 +1,27 @@
+import { OpenAPIHono } from '@hono/zod-openapi';
+import { createCrudRoutes } from '@d8d/shared-crud';
+import { SystemConfigMt } from '../entities/system-config.entity.mt';
+import { SystemConfigSchema, CreateSystemConfigSchema, UpdateSystemConfigSchema } from '../schemas/system-config.schema.mt';
+import { authMiddleware } from '../../../auth-module-mt/src/middleware/index.mt';
+
+const systemConfigCrudRoutes = createCrudRoutes({
+  entity: SystemConfigMt,
+  createSchema: CreateSystemConfigSchema,
+  updateSchema: UpdateSystemConfigSchema,
+  getSchema: SystemConfigSchema,
+  listSchema: SystemConfigSchema,
+  searchFields: ['configKey', 'description'],
+  middleware: [authMiddleware],
+  tenantOptions: {
+    enabled: true,
+    tenantIdField: 'tenantId',
+    autoExtractFromContext: true
+  }
+});
+
+// 创建路由实例
+const systemConfigRoutesMt = new OpenAPIHono()
+  .route('/', systemConfigCrudRoutes);
+
+export { systemConfigRoutesMt };
+export default systemConfigRoutesMt;

+ 1 - 0
packages/core-module-mt/system-config-module-mt/src/schemas/index.mt.ts

@@ -0,0 +1 @@
+export * from './system-config.schema.mt';

+ 72 - 0
packages/core-module-mt/system-config-module-mt/src/schemas/system-config.schema.mt.ts

@@ -0,0 +1,72 @@
+import { z } from '@hono/zod-openapi';
+
+export const SystemConfigSchema = z.object({
+  id: z.number().int().positive().openapi({
+    description: '系统配置ID',
+    example: 1
+  }),
+  tenantId: z.number().int().positive().openapi({
+    description: '租户ID',
+    example: 1
+  }),
+  configKey: z.string().min(1).max(255).openapi({
+    description: '配置键',
+    example: 'app.login.enabled'
+  }),
+  configValue: z.string().openapi({
+    description: '配置值',
+    example: 'true'
+  }),
+  description: z.string().nullable().openapi({
+    description: '配置描述',
+    example: '控制小程序登录功能是否开启'
+  }),
+  createdBy: z.number().int().positive().nullable().openapi({
+    description: '创建用户ID',
+    example: 1
+  }),
+  updatedBy: z.number().int().positive().nullable().openapi({
+    description: '更新用户ID',
+    example: 1
+  }),
+  createdAt: z.coerce.date().openapi({
+    description: '创建时间',
+    example: '2023-01-15T10:30:00Z'
+  }),
+  updatedAt: z.coerce.date().openapi({
+    description: '更新时间',
+    example: '2023-01-16T14:20:00Z'
+  })
+});
+
+export const CreateSystemConfigSchema = z.object({
+  configKey: z.string().min(1).max(255).openapi({
+    description: '配置键',
+    example: 'app.login.enabled'
+  }),
+  configValue: z.string().openapi({
+    description: '配置值',
+    example: 'true'
+  }),
+  description: z.string().nullable().optional().openapi({
+    description: '配置描述',
+    example: '控制小程序登录功能是否开启'
+  })
+});
+
+export const UpdateSystemConfigSchema = z.object({
+  configKey: z.string().min(1).max(255).optional().openapi({
+    description: '配置键',
+    example: 'app.login.enabled'
+  }),
+  configValue: z.string().optional().openapi({
+    description: '配置值',
+    example: 'false'
+  }),
+  description: z.string().nullable().optional().openapi({
+    description: '配置描述',
+    example: '控制小程序登录功能是否开启'
+  })
+});
+
+export const SystemConfigListSchema = z.array(SystemConfigSchema);

+ 1 - 0
packages/core-module-mt/system-config-module-mt/src/services/index.mt.ts

@@ -0,0 +1 @@
+export { SystemConfigServiceMt } from './system-config.service.mt';

+ 211 - 0
packages/core-module-mt/system-config-module-mt/src/services/system-config.service.mt.ts

@@ -0,0 +1,211 @@
+import { GenericCrudService } from '@d8d/shared-crud';
+import { DataSource, In } from 'typeorm';
+import { SystemConfigMt } from '../entities/system-config.entity.mt';
+import { redisUtil } from '@d8d/shared-utils';
+
+export class SystemConfigServiceMt extends GenericCrudService<SystemConfigMt> {
+  constructor(dataSource: DataSource) {
+    super(dataSource, SystemConfigMt, {
+      tenantOptions: {
+        enabled: true,
+        tenantIdField: 'tenantId',
+        autoExtractFromContext: true
+      },
+      userTracking: {
+        createdByField: 'createdBy',
+        updatedByField: 'updatedBy'
+      }
+    });
+  }
+
+  /**
+   * 根据配置键获取配置值(带缓存)
+   */
+  async getConfigByKey(configKey: string, tenantId: number): Promise<string | null> {
+    // 1. 先尝试从缓存获取
+    const cachedValue = await redisUtil.getSystemConfig(tenantId, configKey);
+
+    // 2. 如果缓存命中且不是空值缓存
+    if (cachedValue !== null && !redisUtil.isNullValue(cachedValue)) {
+      return cachedValue;
+    }
+
+    // 3. 如果是空值缓存,直接返回null
+    if (cachedValue !== null && redisUtil.isNullValue(cachedValue)) {
+      return null;
+    }
+
+    // 4. 缓存未命中,查询数据库
+    const config = await this.repository.findOne({
+      where: { configKey, tenantId }
+    });
+    const configValue = config?.configValue || null;
+
+    // 5. 将结果写入缓存
+    if (configValue !== null) {
+      // 正常值,缓存1小时
+      await redisUtil.setSystemConfig(tenantId, configKey, configValue, 3600);
+    } else {
+      // 空值,缓存5分钟防止缓存穿透
+      await redisUtil.setNullSystemConfig(tenantId, configKey, 300);
+    }
+
+    return configValue;
+  }
+
+  /**
+   * 根据配置键获取配置值,如果不存在则返回默认值
+   */
+  async getConfigByKeyWithDefault(configKey: string, defaultValue: string, tenantId: number): Promise<string> {
+    const value = await this.getConfigByKey(configKey, tenantId);
+    return value || defaultValue;
+  }
+
+  /**
+   * 批量获取配置(带缓存)
+   */
+  async getConfigsByKeys(configKeys: string[], tenantId: number): Promise<Record<string, string>> {
+    // 1. 先尝试从缓存批量获取
+    const cachedValues = await redisUtil.getSystemConfigs(tenantId, configKeys);
+
+    const result: Record<string, string> = {};
+    const missingKeys: string[] = [];
+
+    // 2. 处理缓存命中的键
+    configKeys.forEach(key => {
+      const cachedValue = cachedValues[key];
+      if (cachedValue !== null && !redisUtil.isNullValue(cachedValue)) {
+        result[key] = cachedValue;
+      } else if (cachedValue === null) {
+        // 缓存未命中,需要查询数据库
+        missingKeys.push(key);
+      }
+      // 如果是空值缓存,不添加到结果中(保持为undefined)
+    });
+
+    // 3. 如果有未命中的键,查询数据库
+    if (missingKeys.length > 0) {
+      const configs = await this.repository.find({
+        where: {
+          configKey: In(missingKeys),
+          tenantId
+        }
+      });
+      const dbValues: Record<string, string> = {};
+
+      configs.forEach(config => {
+        if (config.configValue !== null) {
+          dbValues[config.configKey] = config.configValue;
+        }
+      });
+
+      // 4. 处理数据库查询结果并更新缓存
+      const cachePromises: Promise<void>[] = [];
+      missingKeys.forEach(key => {
+        const dbValue = dbValues[key];
+        if (dbValue !== undefined) {
+          // 数据库中有值,添加到结果并缓存
+          result[key] = dbValue;
+          cachePromises.push(redisUtil.setSystemConfig(tenantId, key, dbValue, 3600));
+        } else {
+          // 数据库中无值,设置空值缓存
+          cachePromises.push(redisUtil.setNullSystemConfig(tenantId, key, 300));
+        }
+      });
+
+      // 等待所有缓存操作完成
+      if (cachePromises.length > 0) {
+        await Promise.all(cachePromises);
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * 设置配置值,如果配置键不存在则创建,存在则更新
+   */
+  async setConfig(configKey: string, configValue: string, tenantId: number, description?: string): Promise<SystemConfigMt> {
+    const existingConfig = await this.repository.findOne({
+      where: { configKey, tenantId }
+    });
+
+    if (existingConfig) {
+      // 更新现有配置
+      const updatedConfig = await this.update(existingConfig.id, {
+        configValue,
+        description: description || existingConfig.description
+      });
+
+      // 清除相关缓存
+      await redisUtil.deleteSystemConfig(tenantId, configKey);
+
+      return updatedConfig!;
+    } else {
+      // 创建新配置
+      const newConfig = await this.create({
+        configKey,
+        configValue,
+        description,
+        tenantId
+      } as SystemConfigMt);
+
+      // 清除相关缓存(如果之前有空值缓存)
+      await redisUtil.deleteSystemConfig(tenantId, configKey);
+
+      return newConfig!;
+    }
+  }
+
+  /**
+   * 获取租户的所有配置
+   */
+  async getAllConfigs(tenantId: number): Promise<SystemConfigMt[]> {
+    return await this.repository.find({ where: { tenantId } });
+  }
+
+  /**
+   * 删除配置
+   */
+  async deleteConfig(configKey: string, tenantId: number): Promise<boolean> {
+    const config = await this.repository.findOne({
+      where: { configKey, tenantId }
+    });
+    if (!config) {
+      return false;
+    }
+
+    await this.delete(config.id);
+
+    // 清除相关缓存
+    await redisUtil.deleteSystemConfig(tenantId, configKey);
+
+    return true;
+  }
+
+  /**
+   * 重写update方法,在更新时清除缓存
+   */
+  async update(id: number, data: Partial<SystemConfigMt>): Promise<SystemConfigMt | null> {
+    const updatedConfig = await super.update(id, data);
+
+    if (updatedConfig) {
+      // 清除相关缓存
+      const effectiveTenantId = updatedConfig.tenantId ?? 0;
+      await redisUtil.deleteSystemConfig(effectiveTenantId, updatedConfig.configKey);
+    }
+
+    return updatedConfig;
+  }
+
+  /**
+   * 缓存预热 - 预加载常用配置到缓存
+   */
+  async warmUpCache(tenantId: number, configKeys?: string[]): Promise<void> {
+    // 如果没有指定配置键,预加载所有配置
+    const keysToWarm = configKeys || ['app.login.enabled', 'app.payment.enabled', 'app.notification.enabled'];
+
+    // 批量获取配置并缓存
+    await this.getConfigsByKeys(keysToWarm, tenantId);
+  }
+}

+ 303 - 0
packages/core-module-mt/system-config-module-mt/tests/integration/system-config-redis-cache.integration.test.ts

@@ -0,0 +1,303 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { testClient } from 'hono/testing';
+import {
+  IntegrationTestDatabase,
+  setupIntegrationDatabaseHooksWithEntities
+} from '@d8d/shared-test-util';
+import { systemConfigRoutesMt } from '../../src/routes/system-config.routes.mt';
+import { SystemConfigMt } from '../../src/entities/system-config.entity.mt';
+import { SystemConfigServiceMt } from '../../src/services/system-config.service.mt';
+import { UserEntityMt, RoleMt } from '@d8d/core-module-mt/user-module-mt';
+import { FileMt } from '@d8d/core-module-mt/file-module-mt';
+import { TestDataFactory } from '../utils/integration-test-db';
+import { AuthService } from '@d8d/core-module-mt/auth-module-mt';
+import { UserServiceMt } from '@d8d/core-module-mt/user-module-mt';
+import { redisUtil } from '@d8d/shared-utils';
+
+// 设置集成测试钩子
+setupIntegrationDatabaseHooksWithEntities([SystemConfigMt, UserEntityMt, RoleMt, FileMt])
+
+describe('系统配置Redis缓存集成测试', () => {
+  let client: ReturnType<typeof testClient<typeof systemConfigRoutesMt>>;
+  let authService: AuthService;
+  let userService: UserServiceMt;
+  let systemConfigService: SystemConfigServiceMt;
+  let testToken: string;
+  let testUser: any;
+
+  beforeEach(async () => {
+    // 创建测试客户端
+    client = testClient(systemConfigRoutesMt);
+
+    // 获取数据源
+    const dataSource = await IntegrationTestDatabase.getDataSource();
+    if (!dataSource) throw new Error('Database not initialized');
+
+    // 初始化服务
+    userService = new UserServiceMt(dataSource);
+    authService = new AuthService(userService);
+    systemConfigService = new SystemConfigServiceMt(dataSource);
+
+    // 创建测试用户并生成token
+    testUser = await TestDataFactory.createTestUser(dataSource, {
+      username: 'testuser_rediscache',
+      password: 'TestPassword123!',
+      email: 'testuser_rediscache@example.com'
+    });
+
+    // 生成测试用户的token
+    testToken = authService.generateToken(testUser);
+
+    // 清除测试前的缓存
+    await redisUtil.clearTenantSystemConfigs(testUser.tenantId);
+  });
+
+  describe('缓存命中测试', () => {
+    it('应该从缓存中获取配置值', async () => {
+      // 先创建配置
+      const config = await systemConfigService.create({
+        configKey: 'app.cache.test',
+        configValue: 'cached-value',
+        description: '缓存测试配置',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      // 第一次查询 - 应该从数据库获取并写入缓存
+      const firstResult = await systemConfigService.getConfigByKey('app.cache.test', testUser.tenantId);
+      expect(firstResult).toBe('cached-value');
+
+      // 验证缓存已写入
+      const cachedValue = await redisUtil.getSystemConfig(testUser.tenantId, 'app.cache.test');
+      expect(cachedValue).toBe('cached-value');
+
+      // 第二次查询 - 应该从缓存获取
+      const secondResult = await systemConfigService.getConfigByKey('app.cache.test', testUser.tenantId);
+      expect(secondResult).toBe('cached-value');
+    });
+
+    it('应该批量从缓存中获取配置值', async () => {
+      // 创建多个配置
+      await systemConfigService.create({
+        configKey: 'app.feature1.enabled',
+        configValue: 'true',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      await systemConfigService.create({
+        configKey: 'app.feature2.enabled',
+        configValue: 'false',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      // 第一次批量查询 - 应该从数据库获取并写入缓存
+      const firstResult = await systemConfigService.getConfigsByKeys(
+        ['app.feature1.enabled', 'app.feature2.enabled'],
+        testUser.tenantId
+      );
+      expect(firstResult['app.feature1.enabled']).toBe('true');
+      expect(firstResult['app.feature2.enabled']).toBe('false');
+
+      // 验证缓存已写入
+      const cachedValues = await redisUtil.getSystemConfigs(testUser.tenantId, ['app.feature1.enabled', 'app.feature2.enabled']);
+      expect(cachedValues['app.feature1.enabled']).toBe('true');
+      expect(cachedValues['app.feature2.enabled']).toBe('false');
+
+      // 第二次批量查询 - 应该从缓存获取
+      const secondResult = await systemConfigService.getConfigsByKeys(
+        ['app.feature1.enabled', 'app.feature2.enabled'],
+        testUser.tenantId
+      );
+      expect(secondResult['app.feature1.enabled']).toBe('true');
+      expect(secondResult['app.feature2.enabled']).toBe('false');
+    });
+  });
+
+  describe('缓存失效测试', () => {
+    it('应该在配置更新时清除缓存', async () => {
+      // 创建配置
+      const config = await systemConfigService.create({
+        configKey: 'app.update.test',
+        configValue: 'initial-value',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      // 查询一次以填充缓存
+      await systemConfigService.getConfigByKey('app.update.test', testUser.tenantId);
+
+      // 验证缓存已写入
+      let cachedValue = await redisUtil.getSystemConfig(testUser.tenantId, 'app.update.test');
+      expect(cachedValue).toBe('initial-value');
+
+      // 更新配置
+      await systemConfigService.setConfig('app.update.test', 'updated-value', testUser.tenantId, '更新后的描述');
+
+      // 验证缓存已清除
+      cachedValue = await redisUtil.getSystemConfig(testUser.tenantId, 'app.update.test');
+      expect(cachedValue).toBeNull();
+
+      // 再次查询应该从数据库获取新值
+      const result = await systemConfigService.getConfigByKey('app.update.test', testUser.tenantId);
+      expect(result).toBe('updated-value');
+    });
+
+    it('应该在配置删除时清除缓存', async () => {
+      // 创建配置
+      const config = await systemConfigService.create({
+        configKey: 'app.delete.test',
+        configValue: 'to-be-deleted',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      // 查询一次以填充缓存
+      await systemConfigService.getConfigByKey('app.delete.test', testUser.tenantId);
+
+      // 验证缓存已写入
+      let cachedValue = await redisUtil.getSystemConfig(testUser.tenantId, 'app.delete.test');
+      expect(cachedValue).toBe('to-be-deleted');
+
+      // 删除配置
+      await systemConfigService.deleteConfig('app.delete.test', testUser.tenantId);
+
+      // 验证缓存已清除
+      cachedValue = await redisUtil.getSystemConfig(testUser.tenantId, 'app.delete.test');
+      expect(cachedValue).toBeNull();
+    });
+  });
+
+  describe('缓存穿透保护测试', () => {
+    it('应该防止缓存穿透攻击', async () => {
+      const nonExistentKey = 'app.nonexistent.config';
+
+      // 第一次查询不存在的配置
+      const firstResult = await systemConfigService.getConfigByKey(nonExistentKey, testUser.tenantId);
+      expect(firstResult).toBeNull();
+
+      // 验证空值缓存已设置
+      const cachedValue = await redisUtil.getSystemConfig(testUser.tenantId, nonExistentKey);
+      expect(redisUtil.isNullValue(cachedValue)).toBe(true);
+
+      // 第二次查询应该从空值缓存返回null
+      const secondResult = await systemConfigService.getConfigByKey(nonExistentKey, testUser.tenantId);
+      expect(secondResult).toBeNull();
+    });
+
+    it('应该在批量查询中防止缓存穿透', async () => {
+      const existentKey = 'app.existent.config';
+      const nonExistentKey = 'app.nonexistent.config';
+
+      // 创建一个存在的配置
+      await systemConfigService.create({
+        configKey: existentKey,
+        configValue: 'existent-value',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      // 批量查询包含存在和不存在的配置
+      const result = await systemConfigService.getConfigsByKeys(
+        [existentKey, nonExistentKey],
+        testUser.tenantId
+      );
+
+      expect(result[existentKey]).toBe('existent-value');
+      expect(result[nonExistentKey]).toBeUndefined();
+
+      // 验证空值缓存已设置
+      const cachedValues = await redisUtil.getSystemConfigs(testUser.tenantId, [existentKey, nonExistentKey]);
+      expect(cachedValues[existentKey]).toBe('existent-value');
+      expect(redisUtil.isNullValue(cachedValues[nonExistentKey])).toBe(true);
+    });
+  });
+
+  describe('多租户缓存隔离测试', () => {
+    let tenant1User: any;
+    let tenant2User: any;
+
+    beforeEach(async () => {
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      if (!dataSource) throw new Error('Database not initialized');
+
+      // 创建租户1的用户
+      tenant1User = await TestDataFactory.createTestUser(dataSource, {
+        username: 'tenant1_user_cache',
+        password: 'TestPassword123!',
+        email: 'tenant1_cache@example.com',
+        tenantId: 1
+      });
+
+      // 创建租户2的用户
+      tenant2User = await TestDataFactory.createTestUser(dataSource, {
+        username: 'tenant2_user_cache',
+        password: 'TestPassword123!',
+        email: 'tenant2_cache@example.com',
+        tenantId: 2
+      });
+
+      // 清除测试前的缓存
+      await redisUtil.clearTenantSystemConfigs(1);
+      await redisUtil.clearTenantSystemConfigs(2);
+    });
+
+    it('应该按租户隔离缓存', async () => {
+      const sharedConfigKey = 'app.shared.config';
+
+      // 为租户1创建配置
+      await systemConfigService.create({
+        configKey: sharedConfigKey,
+        configValue: 'tenant1-value',
+        tenantId: 1
+      } as SystemConfigMt);
+
+      // 为租户2创建配置
+      await systemConfigService.create({
+        configKey: sharedConfigKey,
+        configValue: 'tenant2-value',
+        tenantId: 2
+      } as SystemConfigMt);
+
+      // 查询租户1的配置
+      const tenant1Result = await systemConfigService.getConfigByKey(sharedConfigKey, 1);
+      expect(tenant1Result).toBe('tenant1-value');
+
+      // 查询租户2的配置
+      const tenant2Result = await systemConfigService.getConfigByKey(sharedConfigKey, 2);
+      expect(tenant2Result).toBe('tenant2-value');
+
+      // 验证缓存隔离
+      const tenant1Cached = await redisUtil.getSystemConfig(1, sharedConfigKey);
+      const tenant2Cached = await redisUtil.getSystemConfig(2, sharedConfigKey);
+      expect(tenant1Cached).toBe('tenant1-value');
+      expect(tenant2Cached).toBe('tenant2-value');
+    });
+  });
+
+  describe('缓存预热测试', () => {
+    it('应该成功预热缓存', async () => {
+      // 创建一些常用配置
+      await systemConfigService.create({
+        configKey: 'app.login.enabled',
+        configValue: 'true',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      await systemConfigService.create({
+        configKey: 'app.payment.enabled',
+        configValue: 'false',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      // 预热缓存
+      await systemConfigService.warmUpCache(testUser.tenantId);
+
+      // 验证缓存已预热
+      const cachedValues = await redisUtil.getSystemConfigs(testUser.tenantId, [
+        'app.login.enabled',
+        'app.payment.enabled',
+        'app.notification.enabled'
+      ]);
+
+      expect(cachedValues['app.login.enabled']).toBe('true');
+      expect(cachedValues['app.payment.enabled']).toBe('false');
+      expect(redisUtil.isNullValue(cachedValues['app.notification.enabled'])).toBe(true);
+    });
+  });
+});

+ 319 - 0
packages/core-module-mt/system-config-module-mt/tests/integration/system-config.routes.integration.test.ts

@@ -0,0 +1,319 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { testClient } from 'hono/testing';
+import {
+  IntegrationTestDatabase,
+  setupIntegrationDatabaseHooksWithEntities
+} from '@d8d/shared-test-util';
+import { systemConfigRoutesMt } from '../../src/routes/system-config.routes.mt';
+import { SystemConfigMt } from '../../src/entities/system-config.entity.mt';
+import { SystemConfigServiceMt } from '../../src/services/system-config.service.mt';
+import { UserEntityMt, RoleMt } from '@d8d/core-module-mt/user-module-mt';
+import { FileMt } from '@d8d/core-module-mt/file-module-mt';
+import { TestDataFactory } from '../utils/integration-test-db';
+import { AuthService } from '@d8d/core-module-mt/auth-module-mt';
+import { UserServiceMt } from '@d8d/core-module-mt/user-module-mt';
+
+// 设置集成测试钩子
+setupIntegrationDatabaseHooksWithEntities([SystemConfigMt, UserEntityMt, RoleMt, FileMt])
+
+describe('系统配置路由API集成测试 (使用hono/testing)', () => {
+  let client: ReturnType<typeof testClient<typeof systemConfigRoutesMt>>;
+  let authService: AuthService;
+  let userService: UserServiceMt;
+  let testToken: string;
+  let testUser: any;
+
+  beforeEach(async () => {
+    // 创建测试客户端
+    client = testClient(systemConfigRoutesMt);
+
+    // 获取数据源
+    const dataSource = await IntegrationTestDatabase.getDataSource();
+    if (!dataSource) throw new Error('Database not initialized');
+
+    // 初始化服务
+    userService = new UserServiceMt(dataSource);
+    authService = new AuthService(userService);
+
+    // 创建测试用户并生成token
+    testUser = await TestDataFactory.createTestUser(dataSource, {
+      username: 'testuser_systemconfig',
+      password: 'TestPassword123!',
+      email: 'testuser_systemconfig@example.com'
+    });
+
+    // 生成测试用户的token
+    testToken = authService.generateToken(testUser);
+  });
+
+  describe('CRUD Operations', () => {
+    it('应该成功创建系统配置', async () => {
+      const configData = {
+        configKey: 'app.login.enabled',
+        configValue: 'true',
+        description: '控制小程序登录功能是否开启'
+      };
+
+      const response = await client.index.$post({
+        json: configData
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
+      });
+
+      expect(response.status).toBe(201);
+      const result = await response.json();
+      if ('configKey' in result) {
+        expect(result.configKey).toBe(configData.configKey);
+        expect(result.configValue).toBe(configData.configValue);
+      }
+    });
+
+    it('应该根据ID获取系统配置', async () => {
+      // 先创建配置
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      if (!dataSource) throw new Error('Database not initialized');
+
+      const systemConfigService = new SystemConfigServiceMt(dataSource);
+      const config = await systemConfigService.create({
+        configKey: 'app.payment.enabled',
+        configValue: 'true',
+        description: '控制支付功能是否开启',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      const response = await client[':id'].$get({
+        param: { id: config.id }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
+      });
+
+      expect(response.status).toBe(200);
+      const result = await response.json();
+      if ('id' in result) {
+        expect(result.id).toBe(config.id);
+        expect(result.configKey).toBe(config.configKey);
+      }
+    });
+
+    it('应该更新系统配置', async () => {
+      // 先创建配置
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      if (!dataSource) throw new Error('Database not initialized');
+
+      const systemConfigService = new SystemConfigServiceMt(dataSource);
+      const config = await systemConfigService.create({
+        configKey: 'app.notification.enabled',
+        configValue: 'true',
+        description: '控制通知功能是否开启',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      const updateData = {
+        configValue: 'false',
+        description: '通知功能已关闭'
+      };
+
+      const response = await client[':id'].$put({
+        param: { id: config.id },
+        json: updateData
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
+      });
+
+      expect(response.status).toBe(200);
+      const result = await response.json();
+      if ('configValue' in result) {
+        expect(result.configValue).toBe(updateData.configValue);
+        expect(result.description).toBe(updateData.description);
+      }
+    });
+
+    it('应该删除系统配置', async () => {
+      // 先创建配置
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      if (!dataSource) throw new Error('Database not initialized');
+
+      const systemConfigService = new SystemConfigServiceMt(dataSource);
+      const config = await systemConfigService.create({
+        configKey: 'app.analytics.enabled',
+        configValue: 'true',
+        description: '控制分析功能是否开启',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      const response = await client[':id'].$delete({
+        param: { id: config.id }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
+      });
+
+      expect(response.status).toBe(204);
+
+      // 验证配置已被删除
+      const deletedConfig = await systemConfigService.getById(config.id);
+      expect(deletedConfig).toBeNull();
+    });
+
+    it('应该列出系统配置列表', async () => {
+      // 创建多个配置
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      if (!dataSource) throw new Error('Database not initialized');
+
+      const systemConfigService = new SystemConfigServiceMt(dataSource);
+      await systemConfigService.create({
+        configKey: 'app.feature1.enabled',
+        configValue: 'true',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      await systemConfigService.create({
+        configKey: 'app.feature2.enabled',
+        configValue: 'false',
+        tenantId: testUser.tenantId
+      } as SystemConfigMt);
+
+      const response = await client.index.$get({
+        query: {}
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
+      });
+
+      expect(response.status).toBe(200);
+      const result = await response.json();
+      if ('data' in result) {
+        expect(result.data).toHaveLength(2);
+      }
+    });
+  });
+
+  describe('Multi-tenant Isolation', () => {
+    let tenant1User: any;
+    let tenant2User: any;
+    let tenant1Token: string;
+    let tenant2Token: string;
+
+    beforeEach(async () => {
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      if (!dataSource) throw new Error('Database not initialized');
+
+      // 创建租户1的用户
+      tenant1User = await TestDataFactory.createTestUser(dataSource, {
+        username: 'tenant1_user_systemconfig',
+        password: 'TestPassword123!',
+        email: 'tenant1_systemconfig@example.com',
+        tenantId: 1
+      });
+
+      // 创建租户2的用户
+      tenant2User = await TestDataFactory.createTestUser(dataSource, {
+        username: 'tenant2_user_systemconfig',
+        password: 'TestPassword123!',
+        email: 'tenant2_systemconfig@example.com',
+        tenantId: 2
+      });
+
+      // 生成租户用户的token
+      tenant1Token = authService.generateToken(tenant1User);
+      tenant2Token = authService.generateToken(tenant2User);
+    });
+
+    it('应该按租户隔离配置', async () => {
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      if (!dataSource) throw new Error('Database not initialized');
+
+      const systemConfigService = new SystemConfigServiceMt(dataSource);
+
+      // 为租户1创建配置
+      await systemConfigService.create({
+        configKey: 'app.shared.config',
+        configValue: 'tenant1-value',
+        tenantId: 1
+      } as SystemConfigMt);
+
+      // 为租户2创建配置
+      await systemConfigService.create({
+        configKey: 'app.shared.config',
+        configValue: 'tenant2-value',
+        tenantId: 2
+      } as SystemConfigMt);
+
+      // 查询租户1的配置
+      const response1 = await client.index.$get({
+        query: {}
+      }, {
+        headers: {
+          'Authorization': `Bearer ${tenant1Token}`
+        }
+      });
+
+      expect(response1.status).toBe(200);
+      const result1 = await response1.json();
+      if ('data' in result1) {
+        expect(result1.data).toHaveLength(1);
+        expect(result1.data[0].configValue).toBe('tenant1-value');
+      }
+
+      // 查询租户2的配置
+      const response2 = await client.index.$get({
+        query: {}
+      }, {
+        headers: {
+          'Authorization': `Bearer ${tenant2Token}`
+        }
+      });
+
+      expect(response2.status).toBe(200);
+      const result2 = await response2.json();
+      if ('data' in result2) {
+        expect(result2.data).toHaveLength(1);
+        expect(result2.data[0].configValue).toBe('tenant2-value');
+      }
+    });
+  });
+
+  describe('Data Validation', () => {
+    it('应该验证必填字段', async () => {
+      const invalidData = {
+        configKey: '', // 空字符串
+        configValue: 'true'
+      };
+
+      const response = await client.index.$post({
+        json: invalidData
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
+      });
+
+      expect(response.status).toBe(400);
+    });
+
+    it('应该验证字段长度', async () => {
+      const invalidData = {
+        configKey: 'a'.repeat(256), // 超过255字符
+        configValue: 'true'
+      };
+
+      const response = await client.index.$post({
+        json: invalidData
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
+      });
+
+      expect(response.status).toBe(400);
+    });
+  });
+});

+ 61 - 0
packages/core-module-mt/system-config-module-mt/tests/utils/integration-test-db.ts

@@ -0,0 +1,61 @@
+import { DataSource } from 'typeorm';
+import { SystemConfigMt } from '../../src/entities/system-config.entity.mt';
+import { UserEntityMt } from '@d8d/core-module-mt/user-module-mt';
+
+/**
+ * 测试数据工厂类
+ */
+export class TestDataFactory {
+  /**
+   * 创建测试系统配置数据
+   */
+  static createSystemConfigData(overrides: Partial<SystemConfigMt> = {}): Partial<SystemConfigMt> {
+    const timestamp = Date.now();
+    return {
+      configKey: `app.test.config.${timestamp}`,
+      configValue: 'true',
+      description: `Test system config ${timestamp}`,
+      tenantId: 1, // 为多租户系统配置设置默认租户ID
+      ...overrides
+    };
+  }
+
+  /**
+   * 创建测试用户数据
+   */
+  static createUserData(overrides: Partial<UserEntityMt> = {}): Partial<UserEntityMt> {
+    const timestamp = Date.now();
+    return {
+      username: `testuser_${timestamp}`,
+      password: 'TestPassword123!',
+      email: `test_${timestamp}@example.com`,
+      phone: `138${timestamp.toString().slice(-8)}`,
+      nickname: `Test User ${timestamp}`,
+      name: `Test Name ${timestamp}`,
+      isDisabled: 0,
+      isDeleted: 0,
+      tenantId: 1, // 为多租户用户设置默认租户ID
+      ...overrides
+    };
+  }
+
+  /**
+   * 在数据库中创建测试系统配置
+   */
+  static async createTestSystemConfig(dataSource: DataSource, overrides: Partial<SystemConfigMt> = {}): Promise<SystemConfigMt> {
+    const configData = this.createSystemConfigData(overrides);
+    const systemConfigRepository = dataSource.getRepository(SystemConfigMt);
+    const systemConfig = systemConfigRepository.create(configData);
+    return await systemConfigRepository.save(systemConfig);
+  }
+
+  /**
+   * 在数据库中创建测试用户
+   */
+  static async createTestUser(dataSource: DataSource, overrides: Partial<UserEntityMt> = {}): Promise<UserEntityMt> {
+    const userData = this.createUserData(overrides);
+    const userRepository = dataSource.getRepository(UserEntityMt);
+    const user = userRepository.create(userData);
+    return await userRepository.save(user);
+  }
+}

+ 3 - 1
packages/core-module-mt/tsconfig.json

@@ -11,7 +11,9 @@
     "auth-module-mt/src/**/*",
     "auth-module-mt/tests/**/*",
     "file-module-mt/src/**/*",
-    "file-module-mt/tests/**/*"
+    "file-module-mt/tests/**/*",
+    "system-config-module-mt/src/**/*",
+    "system-config-module-mt/tests/**/*"
   ],
   "exclude": [
     "node_modules",

+ 3 - 3
packages/core-module-mt/user-module-mt/src/routes/user.routes.mt.ts

@@ -1,7 +1,7 @@
 import { OpenAPIHono } from '@hono/zod-openapi';
 import { createCrudRoutes } from '@d8d/shared-crud';
 import { UserEntityMt } from '../entities/user.entity.mt';
-import { UserSchemaMt, CreateUserDtoMt, UpdateUserDtoMt } from '../schemas/user.schema.mt';
+import { CreateUserDtoMt, UpdateUserDtoMt, UserResponseSchemaMt } from '../schemas/user.schema.mt';
 import customRoutesMt from './custom.routes.mt';
 import { authMiddleware } from '@d8d/core-module-mt/auth-module-mt';
 
@@ -10,8 +10,8 @@ const userCrudRoutesMt = createCrudRoutes({
   entity: UserEntityMt,
   createSchema: CreateUserDtoMt,
   updateSchema: UpdateUserDtoMt,
-  getSchema: UserSchemaMt,
-  listSchema: UserSchemaMt,
+  getSchema: UserResponseSchemaMt,
+  listSchema: UserResponseSchemaMt,
   searchFields: ['username', 'nickname', 'phone', 'email'],
   relations: ['roles', 'avatarFile'],
   middleware: [authMiddleware],

+ 2 - 1
packages/core-module-mt/vitest.config.ts

@@ -7,7 +7,8 @@ export default defineConfig({
     include: [
       'user-module-mt/tests/**/*.test.ts',
       'auth-module-mt/tests/**/*.test.ts',
-      'file-module-mt/tests/**/*.test.ts'
+      'file-module-mt/tests/**/*.test.ts',
+      'system-config-module-mt/tests/**/*.test.ts'
     ],
     coverage: {
       provider: 'v8',

+ 29 - 23
packages/geo-areas-mt/src/api/areas/index.mt.ts

@@ -3,13 +3,11 @@ import { z } from '@hono/zod-openapi';
 import { AreaServiceMt } from '../../modules/areas/area.service.mt';
 import { AreaLevel } from '../../modules/areas/area.entity.mt';
 import { AppDataSource } from '@d8d/shared-utils';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AuthContext } from '@d8d/shared-types';
 
 // 省份查询参数Schema(多租户)
 const getProvincesSchema = z.object({
-  tenantId: z.coerce.number<number>().int().positive('租户ID必须为正整数').openapi({
-    example: 1,
-    description: '租户ID'
-  }),
   page: z.coerce.number<number>().int().min(1).default(1).openapi({
     example: 1,
     description: '页码'
@@ -22,10 +20,6 @@ const getProvincesSchema = z.object({
 
 // 城市查询参数Schema(多租户)
 const getCitiesSchema = z.object({
-  tenantId: z.coerce.number<number>().int().positive('租户ID必须为正整数').openapi({
-    example: 1,
-    description: '租户ID'
-  }),
   provinceId: z.coerce.number<number>().int().positive('省份ID必须为正整数').openapi({
     example: 1,
     description: '省份ID'
@@ -42,10 +36,6 @@ const getCitiesSchema = z.object({
 
 // 区县查询参数Schema(多租户)
 const getDistrictsSchema = z.object({
-  tenantId: z.coerce.number<number>().int().positive('租户ID必须为正整数').openapi({
-    example: 1,
-    description: '租户ID'
-  }),
   cityId: z.coerce.number<number>().int().positive('城市ID必须为正整数').openapi({
     example: 34,
     description: '城市ID'
@@ -62,10 +52,6 @@ const getDistrictsSchema = z.object({
 
 // 街道查询参数Schema(多租户)
 const getTownsSchema = z.object({
-  tenantId: z.coerce.number<number>().int().positive('租户ID必须为正整数').openapi({
-    example: 1,
-    description: '租户ID'
-  }),
   districtId: z.coerce.number<number>().int().positive('区县ID必须为正整数').openapi({
     example: 3401,
     description: '区县ID'
@@ -163,6 +149,7 @@ const errorSchema = z.object({
 const getProvincesRoute = createRoute({
   method: 'get',
   path: '/provinces',
+  middleware: [ authMiddleware ],
   request: {
     query: getProvincesSchema
   },
@@ -173,6 +160,10 @@ const getProvincesRoute = createRoute({
         'application/json': { schema: provincesResponseSchema }
       }
     },
+    401: {
+      description: '认证失败',
+      content: { 'application/json': { schema: errorSchema } }
+    },
     500: {
       description: '获取省份列表失败',
       content: { 'application/json': { schema: errorSchema } }
@@ -184,6 +175,7 @@ const getProvincesRoute = createRoute({
 const getCitiesRoute = createRoute({
   method: 'get',
   path: '/cities',
+  middleware: [ authMiddleware ],
   request: {
     query: getCitiesSchema
   },
@@ -198,6 +190,10 @@ const getCitiesRoute = createRoute({
       description: '参数错误',
       content: { 'application/json': { schema: errorSchema } }
     },
+    401: {
+      description: '认证失败',
+      content: { 'application/json': { schema: errorSchema } }
+    },
     500: {
       description: '获取城市列表失败',
       content: { 'application/json': { schema: errorSchema } }
@@ -209,6 +205,7 @@ const getCitiesRoute = createRoute({
 const getDistrictsRoute = createRoute({
   method: 'get',
   path: '/districts',
+  middleware: [ authMiddleware ],
   request: {
     query: getDistrictsSchema
   },
@@ -223,6 +220,10 @@ const getDistrictsRoute = createRoute({
       description: '参数错误',
       content: { 'application/json': { schema: errorSchema } }
     },
+    401: {
+      description: '认证失败',
+      content: { 'application/json': { schema: errorSchema } }
+    },
     500: {
       description: '获取区县列表失败',
       content: { 'application/json': { schema: errorSchema } }
@@ -234,6 +235,7 @@ const getDistrictsRoute = createRoute({
 const getTownsRoute = createRoute({
   method: 'get',
   path: '/towns',
+  middleware: [ authMiddleware ],
   request: {
     query: getTownsSchema
   },
@@ -255,10 +257,11 @@ const getTownsRoute = createRoute({
   }
 });
 
-const app = new OpenAPIHono()
+const app = new OpenAPIHono<AuthContext>()
   .openapi(getProvincesRoute, async (c) => {
     try {
-      const { tenantId, page, pageSize } = c.req.valid('query');
+      const { page, pageSize } = c.req.valid('query');
+      const tenantId = c.get('tenantId')!;
       const areaService = new AreaServiceMt(AppDataSource);
 
       // 使用高效查询方法获取指定租户的省份数据
@@ -292,7 +295,8 @@ const app = new OpenAPIHono()
   })
   .openapi(getCitiesRoute, async (c) => {
     try {
-      const { tenantId, provinceId, page, pageSize } = c.req.valid('query');
+      const { provinceId, page, pageSize } = c.req.valid('query');
+      const tenantId = c.get('tenantId')!;
       const areaService = new AreaServiceMt(AppDataSource);
 
       // 使用高效查询方法获取指定租户和省份下的城市数据
@@ -326,11 +330,12 @@ const app = new OpenAPIHono()
   })
   .openapi(getDistrictsRoute, async (c) => {
     try {
-      const { tenantId, cityId, page, pageSize } = c.req.valid('query');
+      const { cityId, page, pageSize } = c.req.valid('query');
+      const tenantId = c.get('tenantId')!;
       const areaService = new AreaServiceMt(AppDataSource);
 
       // 使用高效查询方法获取指定租户和城市下的区县数据
-      const districts = await areaService.getAreasByLevelAndParent(tenantId, AreaLevel.DISTRICT, cityId);
+      const districts = await areaService.getAreasByLevelAndParent(tenantId, AreaLevel.DISTRICT, cityId!);
 
       // 分页
       const startIndex = (page - 1) * pageSize;
@@ -360,11 +365,12 @@ const app = new OpenAPIHono()
   })
   .openapi(getTownsRoute, async (c) => {
     try {
-      const { tenantId, districtId, page, pageSize } = c.req.valid('query');
+      const { districtId, page, pageSize } = c.req.valid('query');
+      const tenantId = c.get('tenantId')!;
       const areaService = new AreaServiceMt(AppDataSource);
 
       // 使用高效查询方法获取指定租户和区县下的街道数据
-      const towns = await areaService.getAreasByLevelAndParent(tenantId, AreaLevel.TOWN, districtId);
+      const towns = await areaService.getAreasByLevelAndParent(tenantId, AreaLevel.TOWN, districtId!);
 
       // 分页
       const startIndex = (page - 1) * pageSize;

+ 124 - 10
packages/geo-areas-mt/tests/integration/areas.integration.test.ts

@@ -10,6 +10,10 @@ import { AreaEntityMt, AreaLevel } from '../../src/modules/areas/area.entity.mt'
 import { DisabledStatus } from '@d8d/shared-types';
 import { TestDataFactory } from '../utils/test-data-factory';
 import { TestQueryFactory } from '../utils/test-query-factory';
+import { AuthService } from '@d8d/auth-module-mt';
+import { UserServiceMt } from '@d8d/user-module-mt';
+import { UserEntityMt, RoleMt } from '@d8d/user-module-mt';
+import { FileMt } from '@d8d/file-module-mt';
 
 // 定义响应类型
 interface SuccessResponse {
@@ -42,18 +46,39 @@ interface ErrorResponse {
 }
 
 // 设置集成测试钩子
-setupIntegrationDatabaseHooksWithEntities([AreaEntityMt])
+setupIntegrationDatabaseHooksWithEntities([AreaEntityMt, UserEntityMt, FileMt, RoleMt])
 
 describe('区域API集成测试', () => {
   let client: ReturnType<typeof testClient<typeof areasRoutesMt>>;
+  let authService: AuthService;
+  let userService: UserServiceMt;
+  let testToken: string;
+  let testUser: any;
   let testAreas: AreaEntityMt[];
 
   beforeEach(async () => {
     // 创建测试客户端
     client = testClient(areasRoutesMt);
 
-    // 创建测试数据
+    // 获取数据源
     const dataSource = await IntegrationTestDatabase.getDataSource();
+    if (!dataSource) throw new Error('Database not initialized');
+
+    // 初始化服务
+    userService = new UserServiceMt(dataSource);
+    authService = new AuthService(userService);
+
+    // 创建测试用户并生成token
+    testUser = await TestDataFactory.createTestUser(dataSource, {
+      username: 'testuser_areas',
+      password: 'TestPassword123!',
+      email: 'testuser_areas@example.com'
+    });
+
+    // 生成测试用户的token
+    testToken = authService.generateToken(testUser);
+
+    // 创建测试数据
 
     // 创建启用状态的省份(租户1)
     const province1 = await TestDataFactory.createTestArea(dataSource, {
@@ -164,6 +189,10 @@ describe('区域API集成测试', () => {
     it('应该成功获取启用状态的省份列表', async () => {
       const response = await client.provinces.$get({
         query: TestQueryFactory.createProvincesQuery()
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -198,6 +227,10 @@ describe('区域API集成测试', () => {
     it('应该正确处理分页参数', async () => {
       const response = await client.provinces.$get({
         query: TestQueryFactory.createPaginationQuery(1, 2)
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -221,6 +254,10 @@ describe('区域API集成测试', () => {
     it('应该成功获取指定省份下启用状态的城市列表', async () => {
       const response = await client.cities.$get({
         query: TestQueryFactory.createCitiesQuery(testAreas[0].id)
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -252,6 +289,10 @@ describe('区域API集成测试', () => {
     it('应该处理不存在的省份ID', async () => {
       const response = await client.cities.$get({
         query: TestQueryFactory.createCitiesQuery(999)
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -267,6 +308,10 @@ describe('区域API集成测试', () => {
     it('应该验证省份ID参数', async () => {
       const response = await client.cities.$get({
         query: TestQueryFactory.createCitiesQuery(0)
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       // 参数验证应该返回400错误
@@ -282,6 +327,10 @@ describe('区域API集成测试', () => {
 
       const response = await client.districts.$get({
         query: TestQueryFactory.createDistrictsQuery(chaoyangCity!.id)
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -312,6 +361,10 @@ describe('区域API集成测试', () => {
     it('应该处理不存在的城市ID', async () => {
       const response = await client.districts.$get({
         query: TestQueryFactory.createDistrictsQuery(999)
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);
@@ -327,6 +380,10 @@ describe('区域API集成测试', () => {
     it('应该验证城市ID参数', async () => {
       const response = await client.districts.$get({
         query: TestQueryFactory.createDistrictsQuery(0)
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       // 参数验证应该返回400错误
@@ -339,6 +396,10 @@ describe('区域API集成测试', () => {
       // 测试省份API
       const provincesResponse = await client.provinces.$get({
         query: TestQueryFactory.createProvincesQuery()
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
       IntegrationTestAssertions.expectStatus(provincesResponse, 200);
       const provincesData = await provincesResponse.json();
@@ -353,6 +414,10 @@ describe('区域API集成测试', () => {
       // 测试城市API
       const citiesResponse = await client.cities.$get({
         query: TestQueryFactory.createCitiesQuery(testAreas[0].id)
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
       IntegrationTestAssertions.expectStatus(citiesResponse, 200);
       const citiesData = await citiesResponse.json();
@@ -368,6 +433,10 @@ describe('区域API集成测试', () => {
       const chaoyangCity = testAreas.find(area => area.name === '朝阳区' && area.level === AreaLevel.CITY);
       const districtsResponse = await client.districts.$get({
         query: TestQueryFactory.createDistrictsQuery(chaoyangCity!.id)
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
       IntegrationTestAssertions.expectStatus(districtsResponse, 200);
       const districtsData = await districtsResponse.json();
@@ -382,10 +451,24 @@ describe('区域API集成测试', () => {
   });
 
   describe('租户数据隔离测试', () => {
+    let tenant2Token: string;
+    let tenant2User: any;
+
     beforeEach(async () => {
       // 为租户2创建测试数据
       const dataSource = await IntegrationTestDatabase.getDataSource();
 
+      // 创建租户2的用户
+      tenant2User = await TestDataFactory.createTestUser(dataSource, {
+        username: 'testuser_tenant2',
+        password: 'TestPassword123!',
+        email: 'testuser_tenant2@example.com',
+        tenantId: 2
+      });
+
+      // 生成租户2用户的token
+      tenant2Token = authService.generateToken(tenant2User);
+
       // 租户2的省份
       await TestDataFactory.createTestArea(dataSource, {
         name: '租户2-北京市',
@@ -407,6 +490,10 @@ describe('区域API集成测试', () => {
       // 测试租户1的数据
       const response1 = await client.provinces.$get({
         query: TestQueryFactory.createProvincesQuery()
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response1, 200);
@@ -425,7 +512,11 @@ describe('区域API集成测试', () => {
 
       // 测试租户2的数据
       const response2 = await client.provinces.$get({
-        query: { tenantId: 2, page: 1, pageSize: 50 }
+        query: { page: 1, pageSize: 50 }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${tenant2Token}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response2, 200);
@@ -447,6 +538,10 @@ describe('区域API集成测试', () => {
       // 租户1查询省份
       const response1 = await client.provinces.$get({
         query: TestQueryFactory.createProvincesQuery()
+      }, {
+        headers: {
+          'Authorization': `Bearer ${testToken}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response1, 200);
@@ -454,7 +549,11 @@ describe('区域API集成测试', () => {
 
       // 租户2查询省份
       const response2 = await client.provinces.$get({
-        query: { tenantId: 2, page: 1, pageSize: 50 }
+        query: { page: 1, pageSize: 50 }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${tenant2Token}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response2, 200);
@@ -478,19 +577,34 @@ describe('区域API集成测试', () => {
       }
     });
 
-    it('应该验证tenantId参数', async () => {
-      // 测试缺少tenantId参数 - 明确排除tenantId
+    it('应该验证认证令牌', async () => {
+      // 测试缺少认证令牌
       const response = await client.provinces.$get({
-        query: { page: 1, pageSize: 50 } as any // 不包含tenantId,使用any绕过类型检查
+        query: { page: 1, pageSize: 50 }
       });
 
-      // 应该返回400错误,因为缺少必需的tenantId参数
-      IntegrationTestAssertions.expectStatus(response, 400);
+      // 应该返回401错误,因为缺少认证
+      IntegrationTestAssertions.expectStatus(response, 401);
     });
 
     it('应该处理不存在的租户ID', async () => {
+      // 创建不存在的租户用户
+      const dataSource = await IntegrationTestDatabase.getDataSource();
+      const nonExistentTenantUser = await TestDataFactory.createTestUser(dataSource, {
+        username: 'testuser_nonexistent',
+        password: 'TestPassword123!',
+        email: 'testuser_nonexistent@example.com',
+        tenantId: 999 // 不存在的租户ID
+      });
+
+      const nonExistentTenantToken = authService.generateToken(nonExistentTenantUser);
+
       const response = await client.provinces.$get({
-        query: { tenantId: 999, page: 1, pageSize: 50 }
+        query: { page: 1, pageSize: 50 }
+      }, {
+        headers: {
+          'Authorization': `Bearer ${nonExistentTenantToken}`
+        }
       });
 
       IntegrationTestAssertions.expectStatus(response, 200);

+ 0 - 8
packages/geo-areas-mt/tests/utils/test-query-factory.ts

@@ -7,7 +7,6 @@ export class TestQueryFactory {
    */
   static createProvincesQuery(overrides: any = {}): any {
     return {
-      tenantId: 1,
       page: 1,
       pageSize: 50,
       ...overrides
@@ -19,7 +18,6 @@ export class TestQueryFactory {
    */
   static createCitiesQuery(provinceId: number, overrides: any = {}): any {
     return {
-      tenantId: 1,
       provinceId,
       page: 1,
       pageSize: 50,
@@ -32,7 +30,6 @@ export class TestQueryFactory {
    */
   static createDistrictsQuery(cityId: number, overrides: any = {}): any {
     return {
-      tenantId: 1,
       cityId,
       page: 1,
       pageSize: 50,
@@ -45,7 +42,6 @@ export class TestQueryFactory {
    */
   static createTreeQuery(overrides: any = {}): any {
     return {
-      tenantId: 1,
       ...overrides
     };
   }
@@ -55,7 +51,6 @@ export class TestQueryFactory {
    */
   static createTreeByLevelQuery(level: number, overrides: any = {}): any {
     return {
-      tenantId: 1,
       ...overrides
     };
   }
@@ -65,7 +60,6 @@ export class TestQueryFactory {
    */
   static createSubTreeQuery(id: number, overrides: any = {}): any {
     return {
-      tenantId: 1,
       ...overrides
     };
   }
@@ -75,7 +69,6 @@ export class TestQueryFactory {
    */
   static createAreaPathQuery(id: number, overrides: any = {}): any {
     return {
-      tenantId: 1,
       ...overrides
     };
   }
@@ -85,7 +78,6 @@ export class TestQueryFactory {
    */
   static createPaginationQuery(page: number = 1, pageSize: number = 50, overrides: any = {}): any {
     return {
-      tenantId: 1,
       page,
       pageSize,
       ...overrides

+ 1 - 0
packages/mini-payment-mt/package.json

@@ -51,6 +51,7 @@
     "@d8d/user-module-mt": "workspace:*",
     "@d8d/auth-module-mt": "workspace:*",
     "@d8d/file-module-mt": "workspace:*",
+    "@d8d/core-module-mt": "workspace:*",
     "@hono/zod-openapi": "^1.0.2",
     "typeorm": "^0.3.20",
     "wechatpay-node-v3": "2.1.8",

+ 0 - 15
packages/mini-payment-mt/src/routes/payment.routes.ts

@@ -1,15 +0,0 @@
-import { OpenAPIHono } from '@hono/zod-openapi';
-import createPaymentRoute from './payment/create.js';
-import paymentCallbackRoute from './payment/callback.js';
-import paymentStatusRoute from './payment/status.js';
-
-// 支付模块主路由
-export const PaymentRoutes = new OpenAPIHono()
-  .route('/payment', createPaymentRoute)
-  .route('/payment/callback', paymentCallbackRoute)
-  .route('/payment/status', paymentStatusRoute);
-
-// 导出路由配置,用于集成到主应用
-export const paymentRoutesExport = {
-  '/api/v1': PaymentRoutes
-};

+ 113 - 40
packages/mini-payment-mt/src/services/payment.mt.service.ts

@@ -5,6 +5,7 @@ import { PaymentMtEntity } from '../entities/payment.mt.entity.js';
 import { PaymentStatus } from '../entities/payment.types.js';
 import { PaymentCreateResponse } from '../entities/payment.types.js';
 import { GenericCrudService } from '@d8d/shared-crud';
+import { SystemConfigServiceMt } from '@d8d/core-module-mt/system-config-module-mt';
 
 /**
  * 微信支付服务 - 多租户版本
@@ -12,10 +13,7 @@ import { GenericCrudService } from '@d8d/shared-crud';
  */
 export class PaymentMtService extends GenericCrudService<PaymentMtEntity> {
   private readonly wxPay: WxPay;
-  private readonly merchantId: string;
-  private readonly appId: string;
-  private readonly v3Key: string;
-  private readonly notifyUrl: string;
+  private readonly systemConfigService: SystemConfigServiceMt;
 
   constructor(
     dataSource: DataSource
@@ -24,32 +22,84 @@ export class PaymentMtService extends GenericCrudService<PaymentMtEntity> {
       tenantOptions: { enabled: true, tenantIdField: 'tenantId' }
     });
 
-    // 从环境变量获取支付配置
-    this.merchantId = process.env.WECHAT_MERCHANT_ID || '';
-    this.appId = process.env.WX_MINI_APP_ID || '';
-    this.v3Key = process.env.WECHAT_V3_KEY || '';
-    this.notifyUrl = process.env.WECHAT_PAY_NOTIFY_URL || '';
-    const certSerialNo = process.env.WECHAT_MERCHANT_CERT_SERIAL_NO || '';
+    this.systemConfigService = new SystemConfigServiceMt(dataSource);
 
-    if (!this.merchantId || !this.appId || !this.v3Key || !certSerialNo) {
-      throw new Error('微信支付配置不完整,请检查环境变量');
-    }
+    // 微信支付SDK将在需要时动态初始化
+    this.wxPay = null as any;
+  }
 
-    // 处理证书字符串,将 \n 转换为实际换行符
-    const publicKey = (process.env.WECHAT_PUBLIC_KEY || '').replace(/\\n/g, '\n');
-    const privateKey = (process.env.WECHAT_PRIVATE_KEY || '').replace(/\\n/g, '\n');
+  /**
+   * 初始化微信支付SDK实例
+   */
+  private async initializeWxPay(tenantId: number): Promise<void> {
+    const config = await this.getPaymentConfig(tenantId);
 
     // 初始化微信支付SDK
     this.wxPay = new WxPay({
-      appid: this.appId,
-      mchid: this.merchantId,
-      publicKey: Buffer.from(publicKey),
-      privateKey: Buffer.from(privateKey),
-      key: this.v3Key,
-      serial_no: certSerialNo
+      appid: config.appId,
+      mchid: config.merchantId,
+      publicKey: Buffer.from(config.publicKey),
+      privateKey: Buffer.from(config.privateKey),
+      key: config.v3Key,
+      serial_no: config.certSerialNo
     });
   }
 
+  /**
+   * 获取支付配置(优先从系统配置获取,回退到环境变量)
+   */
+  private async getPaymentConfig(tenantId: number): Promise<{
+    merchantId: string;
+    appId: string;
+    v3Key: string;
+    notifyUrl: string;
+    certSerialNo: string;
+    publicKey: string;
+    privateKey: string;
+  }> {
+    // 配置键定义
+    const configKeys = [
+      'wx.payment.merchant.id',
+      'wx.mini.app.id',
+      'wx.payment.v3.key',
+      'wx.payment.notify.url',
+      'wx.payment.cert.serial.no',
+      'wx.payment.public.key',
+      'wx.payment.private.key'
+    ];
+
+    // 优先从系统配置获取
+    const configs = await this.systemConfigService.getConfigsByKeys(configKeys, tenantId);
+
+    // 获取配置值,如果系统配置中没有则回退到环境变量
+    const merchantId = configs['wx.payment.merchant.id'] || process.env.WECHAT_MERCHANT_ID || '';
+    const appId = configs['wx.mini.app.id'] || process.env.WX_MINI_APP_ID || '';
+    const v3Key = configs['wx.payment.v3.key'] || process.env.WECHAT_V3_KEY || '';
+    const notifyUrl = configs['wx.payment.notify.url'] || process.env.WECHAT_PAY_NOTIFY_URL || '';
+    const certSerialNo = configs['wx.payment.cert.serial.no'] || process.env.WECHAT_MERCHANT_CERT_SERIAL_NO || '';
+    let publicKey = configs['wx.payment.public.key'] || process.env.WECHAT_PUBLIC_KEY || '';
+    let privateKey = configs['wx.payment.private.key'] || process.env.WECHAT_PRIVATE_KEY || '';
+
+    // 处理证书字符串,将 \n 转换为实际换行符
+    publicKey = publicKey.replace(/\\n/g, '\n');
+    privateKey = privateKey.replace(/\\n/g, '\n');
+
+    // 验证配置完整性
+    if (!merchantId || !appId || !v3Key || !certSerialNo || !publicKey || !privateKey) {
+      throw new Error('微信支付配置不完整,请检查系统配置或环境变量');
+    }
+
+    return {
+      merchantId,
+      appId,
+      v3Key,
+      notifyUrl,
+      certSerialNo,
+      publicKey,
+      privateKey
+    };
+  }
+
   /**
    * 创建微信支付订单
    * @param externalOrderId 外部订单ID
@@ -86,16 +136,22 @@ export class PaymentMtService extends GenericCrudService<PaymentMtEntity> {
     }
 
     try {
+      // 重新初始化微信支付SDK
+      await this.initializeWxPay(tenantId);
+
+      // 获取支付配置
+      const config = await this.getPaymentConfig(tenantId);
+
       // 创建商户订单号
       const outTradeNo = `PAYMENT_${externalOrderId}_${Date.now()}`;
 
       // 使用微信支付SDK创建JSAPI支付
       const result = await this.wxPay.transactions_jsapi({
-        appid: this.appId,
-        mchid: this.merchantId,
+        appid: config.appId,
+        mchid: config.merchantId,
         description,
         out_trade_no: outTradeNo,
-        notify_url: this.notifyUrl,
+        notify_url: config.notifyUrl,
         amount: {
           total: totalAmount,
         },
@@ -152,6 +208,25 @@ export class PaymentMtService extends GenericCrudService<PaymentMtEntity> {
       rawBody
     });
 
+    // 首先从回调数据中获取商户订单号
+    const outTradeNo = callbackData.out_trade_no;
+    if (!outTradeNo) {
+      throw new Error('回调数据中缺少商户订单号');
+    }
+
+    // 从数据库中查找支付记录以获取租户ID
+    const paymentRepository = this.dataSource.getRepository(PaymentMtEntity);
+    const payment = await paymentRepository.findOne({
+      where: { outTradeNo }
+    });
+
+    if (!payment) {
+      throw new Error('支付记录不存在');
+    }
+
+    // 重新初始化微信支付SDK
+    await this.initializeWxPay(payment.tenantId);
+
     // 验证回调签名
     const isValid = await this.wxPay.verifySign({
       timestamp: headers['wechatpay-timestamp'],
@@ -185,16 +260,6 @@ export class PaymentMtService extends GenericCrudService<PaymentMtEntity> {
       parsedData = decryptedData;
     }
 
-    const paymentRepository = this.dataSource.getRepository(PaymentMtEntity);
-    const outTradeNo = parsedData.out_trade_no;
-    const payment = await paymentRepository.findOne({
-      where: { outTradeNo }
-    });
-
-    if (!payment) {
-      throw new Error('支付记录不存在');
-    }
-
     // 根据回调结果更新支付状态
     if (parsedData.trade_state === 'SUCCESS') {
       payment.paymentStatus = PaymentStatus.PAID;
@@ -241,11 +306,15 @@ export class PaymentMtService extends GenericCrudService<PaymentMtEntity> {
   /**
    * 生成回调签名(用于测试)
    */
-  generateCallbackSignature(
+  async generateCallbackSignature(
     timestamp: string,
     nonce: string,
-    callbackData: any
-  ): string {
+    callbackData: any,
+    tenantId: number
+  ): Promise<string> {
+    // 初始化微信支付SDK
+    await this.initializeWxPay(tenantId);
+
     return this.wxPay.getSignature(
       'POST',
       nonce,
@@ -258,10 +327,14 @@ export class PaymentMtService extends GenericCrudService<PaymentMtEntity> {
   /**
    * 获取微信支付平台证书(用于测试)
    */
-  async getPlatformCertificates(): Promise<any> {
+  async getPlatformCertificates(tenantId: number): Promise<any> {
     try {
+      // 重新初始化微信支付SDK
+      await this.initializeWxPay(tenantId);
+
       console.debug('开始获取微信支付平台证书...');
-      const certificates = await this.wxPay.get_certificates(this.v3Key);
+      const config = await this.getPaymentConfig(tenantId);
+      const certificates = await this.wxPay.get_certificates(config.v3Key);
       console.debug('获取平台证书成功:', certificates);
       return certificates;
     } catch (error) {

+ 221 - 0
packages/mini-payment-mt/tests/integration/system-config-integration.test.ts

@@ -0,0 +1,221 @@
+import { describe, it, expect, beforeEach, afterEach } from 'vitest';
+import {
+  IntegrationTestDatabase,
+  setupIntegrationDatabaseHooksWithEntities
+} from '@d8d/shared-test-util';
+import { PaymentMtService } from '../../src/services/payment.mt.service';
+import { SystemConfigServiceMt } from '@d8d/core-module-mt/system-config-module-mt';
+import { SystemConfigMt } from '@d8d/core-module-mt/system-config-module-mt';
+import { UserEntityMt, RoleMt } from '@d8d/core-module-mt/user-module-mt';
+import { FileMt } from '@d8d/core-module-mt/file-module-mt';
+
+// 设置集成测试钩子
+setupIntegrationDatabaseHooksWithEntities([SystemConfigMt, UserEntityMt, RoleMt, FileMt])
+
+/**
+ * 支付模块系统配置集成测试
+ * 验证PaymentMtService与SystemConfigServiceMt的集成
+ */
+describe('支付模块系统配置集成测试', () => {
+  let paymentMtService: PaymentMtService;
+  let systemConfigService: SystemConfigServiceMt;
+  const testTenantId = 1;
+
+  beforeEach(async () => {
+    // 获取数据源
+    const dataSource = await IntegrationTestDatabase.getDataSource();
+    if (!dataSource) throw new Error('Database not initialized');
+
+    paymentMtService = new PaymentMtService(dataSource);
+    systemConfigService = new SystemConfigServiceMt(dataSource);
+
+    // 清理测试配置
+    await cleanupTestConfigs(testTenantId);
+  });
+
+  afterEach(async () => {
+    // 清理测试配置
+    await cleanupTestConfigs(testTenantId);
+  });
+
+  async function cleanupTestConfigs(tenantId: number) {
+    if (!systemConfigService) return;
+
+    const configKeys = [
+      'wx.payment.merchant.id',
+      'wx.mini.app.id',
+      'wx.payment.v3.key',
+      'wx.payment.notify.url',
+      'wx.payment.cert.serial.no',
+      'wx.payment.public.key',
+      'wx.payment.private.key'
+    ];
+
+    for (const key of configKeys) {
+      try {
+        await systemConfigService.deleteConfig(key, tenantId);
+      } catch (error) {
+        // 忽略删除失败的情况
+      }
+    }
+  }
+
+  async function setupCompletePaymentConfig(tenantId: number, tenantPrefix: string) {
+    await systemConfigService.setConfig('wx.payment.merchant.id', `${tenantPrefix}-merchant-id`, tenantId, `${tenantPrefix}商户ID`);
+    await systemConfigService.setConfig('wx.mini.app.id', `${tenantPrefix}-app-id`, tenantId, `${tenantPrefix}小程序AppID`);
+    await systemConfigService.setConfig('wx.payment.v3.key', `${tenantPrefix}-v3-key`, tenantId, `${tenantPrefix}V3密钥`);
+    await systemConfigService.setConfig('wx.payment.notify.url', `${tenantPrefix}-notify-url`, tenantId, `${tenantPrefix}回调URL`);
+    await systemConfigService.setConfig('wx.payment.cert.serial.no', `${tenantPrefix}-cert-serial`, tenantId, `${tenantPrefix}证书序列号`);
+    await systemConfigService.setConfig('wx.payment.public.key', `${tenantPrefix}-public-key`, tenantId, `${tenantPrefix}公钥`);
+    await systemConfigService.setConfig('wx.payment.private.key', `${tenantPrefix}-private-key`, tenantId, `${tenantPrefix}私钥`);
+  }
+
+  describe('系统配置读取功能', () => {
+    it('应该从系统配置获取支付配置', async () => {
+      // 设置测试支付配置
+      await systemConfigService.setConfig('wx.payment.merchant.id', 'test-merchant-id', testTenantId, '测试商户ID');
+      await systemConfigService.setConfig('wx.mini.app.id', 'test-app-id', testTenantId, '测试小程序AppID');
+      await systemConfigService.setConfig('wx.payment.v3.key', 'test-v3-key', testTenantId, '测试V3密钥');
+      await systemConfigService.setConfig('wx.payment.notify.url', 'https://test.com/notify', testTenantId, '测试回调URL');
+      await systemConfigService.setConfig('wx.payment.cert.serial.no', 'test-serial-no', testTenantId, '测试证书序列号');
+      await systemConfigService.setConfig('wx.payment.public.key', 'test-public-key', testTenantId, '测试公钥');
+      await systemConfigService.setConfig('wx.payment.private.key', 'test-private-key', testTenantId, '测试私钥');
+
+      // 验证配置读取
+      const config = await paymentMtService['getPaymentConfig'](testTenantId);
+
+      expect(config.merchantId).toBe('test-merchant-id');
+      expect(config.appId).toBe('test-app-id');
+      expect(config.v3Key).toBe('test-v3-key');
+      expect(config.notifyUrl).toBe('https://test.com/notify');
+      expect(config.certSerialNo).toBe('test-serial-no');
+      expect(config.publicKey).toBe('test-public-key');
+      expect(config.privateKey).toBe('test-private-key');
+    });
+
+    it('应该支持批量获取支付配置', async () => {
+      // 设置测试配置
+      await systemConfigService.setConfig('wx.payment.merchant.id', 'test-merchant-id', testTenantId, '测试商户ID');
+      await systemConfigService.setConfig('wx.mini.app.id', 'test-app-id', testTenantId, '测试小程序AppID');
+
+      // 批量获取配置
+      const configs = await systemConfigService.getConfigsByKeys(
+        ['wx.payment.merchant.id', 'wx.mini.app.id'],
+        testTenantId
+      );
+
+      expect(configs['wx.payment.merchant.id']).toBe('test-merchant-id');
+      expect(configs['wx.mini.app.id']).toBe('test-app-id');
+    });
+  });
+
+  describe('租户配置隔离', () => {
+    const tenant1Id = 1;
+    const tenant2Id = 2;
+
+    it('应该支持不同租户的独立支付配置', async () => {
+      // 为租户1设置完整的支付配置
+      await setupCompletePaymentConfig(tenant1Id, 'tenant1');
+
+      // 为租户2设置不同的完整支付配置
+      await setupCompletePaymentConfig(tenant2Id, 'tenant2');
+
+      // 验证租户1的配置
+      const tenant1Config = await paymentMtService['getPaymentConfig'](tenant1Id);
+
+      // 验证租户2的配置
+      const tenant2Config = await paymentMtService['getPaymentConfig'](tenant2Id);
+
+      expect(tenant1Config.merchantId).toBe('tenant1-merchant-id');
+      expect(tenant1Config.appId).toBe('tenant1-app-id');
+      expect(tenant2Config.merchantId).toBe('tenant2-merchant-id');
+      expect(tenant2Config.appId).toBe('tenant2-app-id');
+
+      // 验证配置隔离
+      expect(tenant1Config.merchantId).not.toBe(tenant2Config.merchantId);
+      expect(tenant1Config.appId).not.toBe(tenant2Config.appId);
+    });
+  });
+
+  describe('配置回退机制', () => {
+    it('应该在系统配置不存在时回退到环境变量', async () => {
+      // 不设置系统配置,依赖环境变量
+      // 注意:这里假设环境变量已设置,实际测试时需要确保环境变量存在
+
+      try {
+        const config = await paymentMtService['getPaymentConfig'](testTenantId);
+        // 如果环境变量存在,应该能获取到配置
+        expect(config).toBeDefined();
+      } catch (error) {
+        // 如果环境变量不存在,应该抛出配置不完整的错误
+        expect(error).toBeInstanceOf(Error);
+        expect((error as Error).message).toContain('微信支付配置不完整');
+      }
+    });
+
+    it('应该优先使用系统配置', async () => {
+      // 设置完整的系统配置
+      await setupCompletePaymentConfig(testTenantId, 'system');
+
+      // 获取配置,应该优先使用系统配置
+      const config = await paymentMtService['getPaymentConfig'](testTenantId);
+
+      // 验证所有配置都来自系统配置
+      expect(config.merchantId).toBe('system-merchant-id');
+      expect(config.appId).toBe('system-app-id');
+      expect(config.v3Key).toBe('system-v3-key');
+    });
+  });
+
+  describe('PaymentMtService集成', () => {
+    it('应该正确注入SystemConfigServiceMt依赖', () => {
+      // 验证服务实例化
+      expect(paymentMtService).toBeDefined();
+      expect(paymentMtService).toBeInstanceOf(PaymentMtService);
+    });
+
+    it('应该支持动态配置初始化', async () => {
+      // 验证initializeWxPay方法存在
+      const initializeMethod = paymentMtService['initializeWxPay'];
+      expect(typeof initializeMethod).toBe('function');
+
+      // 验证getPaymentConfig方法存在
+      const getConfigMethod = paymentMtService['getPaymentConfig'];
+      expect(typeof getConfigMethod).toBe('function');
+    });
+
+    it('应该支持租户ID参数', async () => {
+      // 验证createPayment方法支持tenantId参数
+      const method = paymentMtService.createPayment;
+      expect(typeof method).toBe('function');
+
+      // 验证方法签名包含tenantId参数
+      expect(method.length).toBeGreaterThanOrEqual(6);
+    });
+  });
+
+  describe('配置验证', () => {
+    it('应该验证配置完整性', async () => {
+      // 不设置任何配置,应该抛出配置不完整的错误
+      await expect(paymentMtService['getPaymentConfig'](testTenantId))
+        .rejects
+        .toThrow('微信支付配置不完整');
+    });
+
+    it('应该处理证书字符串格式', async () => {
+      // 设置完整的支付配置,包含包含转义字符的证书
+      await setupCompletePaymentConfig(testTenantId, 'cert-test');
+
+      // 覆盖证书配置为包含转义字符的格式
+      await systemConfigService.setConfig('wx.payment.public.key', 'test\\npublic\\nkey', testTenantId, '测试公钥');
+      await systemConfigService.setConfig('wx.payment.private.key', 'test\\nprivate\\nkey', testTenantId, '测试私钥');
+
+      // 获取配置并验证格式处理
+      const config = await paymentMtService['getPaymentConfig'](testTenantId);
+
+      // 验证转义字符被正确处理
+      expect(config.publicKey).toBe('test\npublic\nkey');
+      expect(config.privateKey).toBe('test\nprivate\nkey');
+    });
+  });
+});

+ 0 - 63
packages/orders-module-mt/src/routes/create-order.mt.ts

@@ -1,63 +0,0 @@
-import { OpenAPIHono } from '@hono/zod-openapi';
-import { authMiddleware } from '@d8d/auth-module-mt';
-import { AppDataSource } from '@d8d/shared-utils';
-import { AuthContext } from '@d8d/shared-types';
-import { OrderMtService } from '../services';
-import { CreateOrderRequestDto, CreateOrderResponseDto } from '../schemas/create-order.schema';
-
-const createOrderRoutes = new OpenAPIHono<AuthContext>();
-
-// 应用认证中间件
-createOrderRoutes.use('*', authMiddleware);
-
-// 创建订单路由
-createOrderRoutes.openapi(
-  {
-    method: 'post',
-    path: '/',
-    request: {
-      body: {
-        content: {
-          'application/json': {
-            schema: CreateOrderRequestDto
-          }
-        }
-      }
-    },
-    responses: {
-      200: {
-        description: '订单创建成功',
-        content: {
-          'application/json': {
-            schema: CreateOrderResponseDto
-          }
-        }
-      },
-      400: {
-        description: '请求参数错误'
-      },
-      500: {
-        description: '服务器内部错误'
-      }
-    }
-  },
-  async (c) => {
-    const data = c.req.valid('json');
-    const user = c.get('user');
-
-    try {
-      const orderService = new OrderMtService(AppDataSource);
-      const result = await orderService.createOrder(data, user.id, user.tenantId);
-
-      return c.json(result, 201);
-    } catch (error) {
-      console.error('创建订单失败:', error);
-      return c.json(
-        { error: error instanceof Error ? error.message : '创建订单失败' },
-        500
-      );
-    }
-  }
-);
-
-export default createOrderRoutes;

+ 1 - 1
packages/orders-module-mt/src/routes/index.ts

@@ -7,4 +7,4 @@ export { default as userOrderRoutes } from './user/orders.mt';
 export { default as userOrderItemsRoutes } from './user/order-items.mt';
 export { default as userRefundsRoutes } from './user/refunds.mt';
 
-export { default as createOrderRoutes } from './create-order.mt';
+export { default as createOrderRoutes } from './user/create-order.mt';

+ 60 - 0
packages/orders-module-mt/src/routes/user/create-order.mt.ts

@@ -0,0 +1,60 @@
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
+import { authMiddleware } from '@d8d/auth-module-mt';
+import { AppDataSource } from '@d8d/shared-utils';
+import { AuthContext } from '@d8d/shared-types';
+import { OrderMtService } from '../../services';
+import { CreateOrderRequestDto, CreateOrderResponseDto } from '../../schemas/create-order.schema';
+
+const createOrderRoute = createRoute({
+  method: 'post',
+  path: '/create-order',
+  middleware: [authMiddleware],
+  request: {
+    body: {
+      content: {
+        'application/json': {
+          schema: CreateOrderRequestDto
+        }
+      }
+    }
+  },
+  responses: {
+    201: {
+      description: '订单创建成功',
+      content: {
+        'application/json': {
+          schema: CreateOrderResponseDto
+        }
+      }
+    },
+    400: {
+      description: '请求参数错误'
+    },
+    500: {
+      description: '服务器内部错误'
+    }
+  }
+})
+
+const createOrderRoutes = new OpenAPIHono<AuthContext>()
+  // 创建订单路由
+  .openapi( createOrderRoute, async (c) => {
+      const data = c.req.valid('json');
+      const user = c.get('user');
+
+      try {
+        const orderService = new OrderMtService(AppDataSource);
+        const result = await orderService.createOrder(data, user.id, user.tenantId);
+
+        return c.json(result, 201);
+      } catch (error) {
+        console.error('创建订单失败:', error);
+        return c.json(
+          { error: error instanceof Error ? error.message : '创建订单失败' },
+          500
+        );
+      }
+    }
+  );
+
+export default createOrderRoutes;

+ 8 - 2
packages/orders-module-mt/src/routes/user/orders.mt.ts

@@ -3,9 +3,11 @@ import { OrderMt } from '../../entities/order.mt.entity';
 import { OrderSchema, OrderListSchema } from '../../schemas/order.mt.schema';
 import { UserCreateOrderDto, UserUpdateOrderDto } from '../../schemas/user-order.mt.schema';
 import { authMiddleware } from '@d8d/auth-module-mt';
+import { OpenAPIHono } from '@hono/zod-openapi';
+import createOrderRoutes from './create-order.mt';
 
 // 多租户用户订单路由 - 有数据权限限制,只能访问自己的订单
-const userOrderRoutes = createCrudRoutes({
+const userOrderCrudRoutes = createCrudRoutes({
   entity: OrderMt,
   createSchema: UserCreateOrderDto,
   updateSchema: UserUpdateOrderDto,
@@ -14,6 +16,7 @@ const userOrderRoutes = createCrudRoutes({
   searchFields: ['orderNo', 'userPhone', 'recevierName'],
   relations: ['user', 'merchant', 'supplier', 'deliveryAddress'],
   middleware: [authMiddleware],
+  readOnly: true,
   userTracking: {
     createdByField: 'createdBy',
     updatedByField: 'updatedBy'
@@ -27,5 +30,8 @@ const userOrderRoutes = createCrudRoutes({
     tenantIdField: 'tenantId'
   }
 });
-
+const userOrderRoutes = new OpenAPIHono()
+  .route('/', createOrderRoutes)
+  .route('/', userOrderCrudRoutes)
+  
 export default userOrderRoutes;

+ 1 - 0
packages/server/package.json

@@ -46,6 +46,7 @@
     "@d8d/merchant-module-mt": "workspace:*",
     "@d8d/orders-module-mt": "workspace:*",
     "@d8d/supplier-module-mt": "workspace:*",
+    "@d8d/core-module-mt": "workspace:*",
     "axios": "^1.12.2",
     "bcrypt": "^6.0.0",
     "debug": "^4.4.3",

+ 41 - 30
packages/server/src/index.ts

@@ -1,9 +1,9 @@
 import { OpenAPIHono } from '@hono/zod-openapi'
 import { swaggerUI } from '@hono/swagger-ui'
 import { errorHandler, initializeDataSource } from '@d8d/shared-utils'
-import { userRoutesMt as userModuleRoutes, roleRoutesMt as roleModuleRoutes } from '@d8d/user-module-mt'
-import { authRoutes as authModuleRoutes } from '@d8d/auth-module-mt'
-import { fileRoutesMt as fileModuleRoutes } from '@d8d/file-module-mt'
+import { userRoutesMt as userModuleRoutes, roleRoutesMt as roleModuleRoutes } from '@d8d/core-module-mt/user-module-mt'
+import { authRoutes as authModuleRoutes } from '@d8d/core-module-mt/auth-module-mt'
+import { fileRoutesMt as fileModuleRoutes } from '@d8d/core-module-mt/file-module-mt'
 import { tenantRoutes } from '@d8d/tenant-module-mt'
 import { AuthContext } from '@d8d/shared-types'
 import { AppDataSource } from '@d8d/shared-utils'
@@ -22,23 +22,6 @@ import { MerchantMt } from '@d8d/merchant-module-mt'
 import { OrderMt, OrderGoodsMt, OrderRefundMt } from '@d8d/orders-module-mt'
 import { SupplierMt } from '@d8d/supplier-module-mt'
 
-if(!AppDataSource || !AppDataSource.isInitialized) {
-  initializeDataSource([
-    // 已实现的包实体
-    UserEntityMt, RoleMt, FileMt,
-    TenantEntityMt,
-    AreaEntityMt, PaymentMtEntity,
-    Advertisement, AdvertisementType,
-    DeliveryAddressMt,
-    GoodsMt, GoodsCategoryMt,
-    MerchantMt,
-    OrderMt, OrderGoodsMt, OrderRefundMt,
-    SupplierMt
-  ])
-  await AppDataSource.initialize();
-  console.log('数据库初始化完成')
-}
-
 const app = new Hono();
 const api = new OpenAPIHono<AuthContext>()
 
@@ -50,10 +33,27 @@ api.use('/api/v1/*', async (_, next) => {
   await next()
 })
 
-// // 数据库初始化中间件
-// api.use('/api/v1/*', async (c, next) => {
-//   await next();
-// })
+// 数据库初始化中间件
+api.use('/api/v1/*', async (c, next) => {
+  if(!AppDataSource || !AppDataSource.isInitialized) {
+    initializeDataSource([
+      // 已实现的包实体
+      UserEntityMt, RoleMt, FileMt,
+      TenantEntityMt,
+      AreaEntityMt, PaymentMtEntity,
+      Advertisement, AdvertisementType,
+      DeliveryAddressMt,
+      GoodsMt, GoodsCategoryMt,
+      MerchantMt,
+      OrderMt, OrderGoodsMt, OrderRefundMt,
+      SupplierMt, SystemConfigMt
+    ])
+    await AppDataSource.initialize();
+    console.log('数据库初始化完成')
+  }
+  
+  await next();
+})
 
 // 注册Bearer认证方案
 api.openAPIRegistry.registerComponent('securitySchemes','bearerAuth',{
@@ -138,9 +138,12 @@ import { advertisementRoutes, advertisementTypeRoutes } from '@d8d/advertisement
 import { userDeliveryAddressRoutesMt as userDeliveryAddressRoutes, adminDeliveryAddressRoutesMt as adminDeliveryAddressRoutes } from '@d8d/delivery-address-module-mt'
 import { adminGoodsCategoriesRoutesMt as adminGoodsCategoriesRoutes, adminGoodsRoutesMt as adminGoodsRoutes } from '@d8d/goods-module-mt'
 import { userMerchantRoutes as merchantRoutes } from '@d8d/merchant-module-mt'
-import { userOrderRoutes, userOrderItemsRoutes, userRefundsRoutes } from '@d8d/orders-module-mt'
+import { 
+  userOrderRoutes, 
+  // userOrderItemsRoutes, userRefundsRoutes, 
+  adminOrderRoutes, adminOrderItemsRoutes, adminRefundsRoutes } from '@d8d/orders-module-mt'
 import { userSupplierRoutes } from '@d8d/supplier-module-mt'
-
+import { SystemConfigMt, systemConfigRoutesMt } from '@d8d/core-module-mt/system-config-module-mt'
 
 // 注册已实现的包路由
 export const areaApiRoutes = api.route('/api/v1/areas', areasRoutesMt)
@@ -154,9 +157,14 @@ export const goodsCategoryApiRoutes = api.route('/api/v1/goods-categories', admi
 export const goodsApiRoutes = api.route('/api/v1/goods', adminGoodsRoutes)
 export const merchantApiRoutes = api.route('/api/v1/merchants', merchantRoutes)
 export const orderApiRoutes = api.route('/api/v1/orders', userOrderRoutes)
-export const orderGoodsApiRoutes = api.route('/api/v1/orders-goods', userOrderItemsRoutes)
-export const orderRefundApiRoutes = api.route('/api/v1/orders-refund', userRefundsRoutes)
+// export const orderGoodsApiRoutes = api.route('/api/v1/orders-goods', userOrderItemsRoutes)
+// export const orderRefundApiRoutes = api.route('/api/v1/orders-refund', userRefundsRoutes)
+
+export const adminOrderApiRoutes = api.route('/api/v1/admin/orders', adminOrderRoutes)
+export const adminOrderGoodsApiRoutes = api.route('/api/v1/admin/orders-goods', adminOrderItemsRoutes)
+export const adminOrderRefundApiRoutes = api.route('/api/v1/admin/orders-refund', adminRefundsRoutes)
 export const supplierApiRoutes = api.route('/api/v1/suppliers', userSupplierRoutes)
+export const adminSystemConfigApiRoutes = api.route('/api/v1/admin/system-configs', systemConfigRoutesMt)
 
 
 export type AuthRoutes = typeof authRoutes
@@ -172,8 +180,11 @@ export type MerchantRoutes = typeof merchantApiRoutes
 export type DeliveryAddressRoutes = typeof deliveryAddressApiRoutes
 export type AdminDeliveryAddressRoutes = typeof adminDeliveryAddressApiRoutes
 export type OrderRoutes = typeof orderApiRoutes
-export type OrderGoodsRoutes = typeof orderGoodsApiRoutes
-export type OrderRefundRoutes = typeof orderRefundApiRoutes
+// export type OrderGoodsRoutes = typeof orderGoodsApiRoutes
+// export type OrderRefundRoutes = typeof orderRefundApiRoutes
+export type AdminOrderRoutes = typeof adminOrderApiRoutes
+export type AdminOrderGoodsRoutes = typeof adminOrderGoodsApiRoutes
+export type AdminOrderRefundRoutes = typeof adminOrderRefundApiRoutes
 export type AreaRoutes = typeof areaApiRoutes
 export type AdminAreaRoutes = typeof adminAreaApiRoutes
 

+ 94 - 0
packages/shared-utils/src/utils/redis.util.ts

@@ -59,6 +59,100 @@ class RedisUtil {
     const sessionKey = await this.getSessionKey(userId);
     return !!sessionKey;
   }
+
+  /**
+   * 设置系统配置缓存
+   */
+  async setSystemConfig(tenantId: number, configKey: string, configValue: string, ttlSeconds: number = 3600): Promise<void> {
+    const client = await this.connect();
+    const key = `system_config:${tenantId}:${configKey}`;
+    await client.set(key, configValue, {
+      EX: ttlSeconds // 默认1小时过期
+    });
+  }
+
+  /**
+   * 获取系统配置缓存
+   */
+  async getSystemConfig(tenantId: number, configKey: string): Promise<string | null> {
+    const client = await this.connect();
+    const key = `system_config:${tenantId}:${configKey}`;
+    return await client.get(key);
+  }
+
+  /**
+   * 删除系统配置缓存
+   */
+  async deleteSystemConfig(tenantId: number, configKey: string): Promise<void> {
+    const client = await this.connect();
+    const key = `system_config:${tenantId}:${configKey}`;
+    await client.del(key);
+  }
+
+  /**
+   * 批量获取系统配置缓存
+   */
+  async getSystemConfigs(tenantId: number, configKeys: string[]): Promise<Record<string, string | null>> {
+    const client = await this.connect();
+    const keys = configKeys.map(key => `system_config:${tenantId}:${key}`);
+    const values = await client.mGet(keys);
+
+    const result: Record<string, string | null> = {};
+    configKeys.forEach((key, index) => {
+      result[key] = values[index];
+    });
+
+    return result;
+  }
+
+  /**
+   * 设置空值缓存(防止缓存穿透)
+   */
+  async setNullSystemConfig(tenantId: number, configKey: string, ttlSeconds: number = 300): Promise<void> {
+    const client = await this.connect();
+    const key = `system_config:${tenantId}:${configKey}`;
+    await client.set(key, '__NULL__', {
+      EX: ttlSeconds // 默认5分钟过期
+    });
+  }
+
+  /**
+   * 检查是否为空值缓存
+   */
+  isNullValue(value: string | null): boolean {
+    return value === '__NULL__';
+  }
+
+  /**
+   * 清除租户的所有系统配置缓存
+   */
+  async clearTenantSystemConfigs(tenantId: number): Promise<void> {
+    const client = await this.connect();
+    const pattern = `system_config:${tenantId}:*`;
+
+    // 使用SCAN命令遍历匹配的键并删除
+    let cursor = 0;
+    do {
+      const result = await client.scan(cursor, {
+        MATCH: pattern,
+        COUNT: 100
+      });
+
+      cursor = result.cursor;
+      const keys = result.keys;
+
+      if (keys.length > 0) {
+        await client.del(keys);
+      }
+    } while (cursor !== 0);
+  }
+
+  /**
+   * 格式化系统配置缓存键
+   */
+  formatSystemConfigKey(tenantId: number, configKey: string): string {
+    return `system_config:${tenantId}:${configKey}`;
+  }
 }
 
 export const redisUtil = RedisUtil.getInstance();

+ 43 - 0
packages/system-config-management-ui-mt/eslint.config.js

@@ -0,0 +1,43 @@
+import js from '@eslint/js';
+import tseslint from '@typescript-eslint/eslint-plugin';
+import tsparser from '@typescript-eslint/parser';
+import reactPlugin from 'eslint-plugin-react';
+import reactHooks from 'eslint-plugin-react-hooks';
+
+export default [
+  {
+    files: ['**/*.{js,jsx,ts,tsx}'],
+    languageOptions: {
+      parser: tsparser,
+      ecmaVersion: 'latest',
+      sourceType: 'module',
+      parserOptions: {
+        ecmaFeatures: {
+          jsx: true
+        }
+      }
+    },
+    plugins: {
+      '@typescript-eslint': tseslint,
+      'react': reactPlugin,
+      'react-hooks': reactHooks
+    },
+    rules: {
+      ...js.configs.recommended.rules,
+      ...tseslint.configs.recommended.rules,
+      ...reactPlugin.configs.recommended.rules,
+      ...reactHooks.configs.recommended.rules,
+      'react/react-in-jsx-scope': 'off',
+      '@typescript-eslint/no-unused-vars': ['error', {
+        argsIgnorePattern: '^_',
+        varsIgnorePattern: '^_'
+      }],
+      '@typescript-eslint/no-explicit-any': 'warn'
+    },
+    settings: {
+      react: {
+        version: 'detect'
+      }
+    }
+  }
+];

+ 92 - 0
packages/system-config-management-ui-mt/package.json

@@ -0,0 +1,92 @@
+{
+  "name": "@d8d/system-config-management-ui-mt",
+  "version": "1.0.0",
+  "description": "多租户系统配置管理界面包 - 提供多租户环境下系统配置管理的完整前端界面,包括配置项CRUD操作、租户筛选、小程序和支付参数配置等功能",
+  "type": "module",
+  "main": "src/index.ts",
+  "types": "src/index.ts",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "import": "./src/index.ts",
+      "require": "./src/index.ts"
+    },
+    "./components": {
+      "types": "./src/components/index.ts",
+      "import": "./src/components/index.ts",
+      "require": "./src/components/index.ts"
+    },
+    "./hooks": {
+      "types": "./src/hooks/index.ts",
+      "import": "./src/hooks/index.ts",
+      "require": "./src/hooks/index.ts"
+    },
+    "./api": {
+      "types": "./src/api/index.ts",
+      "import": "./src/api/index.ts",
+      "require": "./src/api/index.ts"
+    }
+  },
+  "files": [
+    "src"
+  ],
+  "scripts": {
+    "build": "unbuild",
+    "dev": "tsc --watch",
+    "test": "vitest run",
+    "test:watch": "vitest",
+    "test:coverage": "vitest run --coverage",
+    "lint": "eslint src --ext .ts,.tsx",
+    "typecheck": "tsc --noEmit"
+  },
+  "dependencies": {
+    "@d8d/shared-types": "workspace:*",
+    "@d8d/shared-ui-components": "workspace:*",
+    "@d8d/core-module-mt": "workspace:*",
+    "@hookform/resolvers": "^5.2.1",
+    "@tanstack/react-query": "^5.90.9",
+    "class-variance-authority": "^0.7.1",
+    "clsx": "^2.1.1",
+    "date-fns": "^4.1.0",
+    "hono": "^4.8.5",
+    "lucide-react": "^0.536.0",
+    "react": "^19.1.0",
+    "react-dom": "^19.1.0",
+    "react-hook-form": "^7.61.1",
+    "sonner": "^2.0.7",
+    "tailwind-merge": "^3.3.1",
+    "zod": "^4.0.15"
+  },
+  "devDependencies": {
+    "@testing-library/jest-dom": "^6.8.0",
+    "@testing-library/react": "^16.3.0",
+    "@testing-library/user-event": "^14.6.1",
+    "@types/node": "^22.10.2",
+    "@types/react": "^19.2.2",
+    "@types/react-dom": "^19.2.3",
+    "@typescript-eslint/eslint-plugin": "^8.18.1",
+    "@typescript-eslint/parser": "^8.18.1",
+    "eslint": "^9.17.0",
+    "jsdom": "^26.0.0",
+    "typescript": "^5.8.3",
+    "unbuild": "^3.4.0",
+    "vitest": "^4.0.9"
+  },
+  "peerDependencies": {
+    "react": "^19.1.0",
+    "react-dom": "^19.1.0"
+  },
+  "keywords": [
+    "system-config",
+    "configuration",
+    "management",
+    "admin",
+    "ui",
+    "react",
+    "crud",
+    "multi-tenant",
+    "mt"
+  ],
+  "author": "D8D Team",
+  "license": "MIT"
+}

+ 5 - 0
packages/system-config-management-ui-mt/src/api/index.ts

@@ -0,0 +1,5 @@
+export {
+  SystemConfigClientManager,
+  systemConfigClientManager,
+  systemConfigClient
+} from './systemConfigClient';

+ 44 - 0
packages/system-config-management-ui-mt/src/api/systemConfigClient.ts

@@ -0,0 +1,44 @@
+import { systemConfigRoutesMt } from '@d8d/core-module-mt/system-config-module-mt';
+import { rpcClient } from '@d8d/shared-ui-components/utils/hc'
+
+export class SystemConfigClientManager {
+  private static instance: SystemConfigClientManager;
+  private client: ReturnType<typeof rpcClient<typeof systemConfigRoutesMt>> | null = null;
+
+  private constructor() {}
+
+  public static getInstance(): SystemConfigClientManager {
+    if (!SystemConfigClientManager.instance) {
+      SystemConfigClientManager.instance = new SystemConfigClientManager();
+    }
+    return SystemConfigClientManager.instance;
+  }
+
+  // 初始化客户端
+  public init(baseUrl: string = '/'): ReturnType<typeof rpcClient<typeof systemConfigRoutesMt>> {
+    return this.client = rpcClient<typeof systemConfigRoutesMt>(baseUrl);
+  }
+
+  // 获取客户端实例
+  public get(): ReturnType<typeof rpcClient<typeof systemConfigRoutesMt>> {
+    if (!this.client) {
+      return this.init()
+    }
+    return this.client;
+  }
+
+  // 重置客户端(用于测试或重新初始化)
+  public reset(): void {
+    this.client = null;
+  }
+}
+
+// 导出单例实例
+const systemConfigClientManager = SystemConfigClientManager.getInstance();
+
+// 导出默认客户端实例(延迟初始化)
+export const systemConfigClient = systemConfigClientManager.get()
+
+export {
+  systemConfigClientManager
+}

+ 525 - 0
packages/system-config-management-ui-mt/src/components/SystemConfigManagement.tsx

@@ -0,0 +1,525 @@
+import React, { useState } from 'react';
+import { useQuery, useMutation } from '@tanstack/react-query';
+import { Plus, Edit, Trash2, Search } from 'lucide-react';
+import { format } from 'date-fns';
+import { Input } from '@d8d/shared-ui-components/components/ui/input';
+import { Textarea } from '@d8d/shared-ui-components/components/ui/textarea';
+import { Button } from '@d8d/shared-ui-components/components/ui/button';
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@d8d/shared-ui-components/components/ui/card';
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@d8d/shared-ui-components/components/ui/table';
+import { Skeleton } from '@d8d/shared-ui-components/components/ui/skeleton';
+import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@d8d/shared-ui-components/components/ui/dialog';
+import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@d8d/shared-ui-components/components/ui/form';
+import { useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { toast } from 'sonner';
+import { DataTablePagination } from '@d8d/shared-ui-components/components/admin/DataTablePagination';
+import { systemConfigClientManager } from '../api/systemConfigClient';
+import { CreateSystemConfigSchema, UpdateSystemConfigSchema } from '@d8d/core-module-mt/system-config-module-mt/schemas';
+import type { SystemConfigFormData, SystemConfigSearchParams, CreateSystemConfigRequest, UpdateSystemConfigRequest, SystemConfigResponse } from '../types';
+
+type CreateRequest = CreateSystemConfigRequest;
+type UpdateRequest = UpdateSystemConfigRequest;
+
+const createFormSchema = CreateSystemConfigSchema;
+const updateFormSchema = UpdateSystemConfigSchema;
+
+export const SystemConfigManagement: React.FC = () => {
+  const [searchParams, setSearchParams] = useState<SystemConfigSearchParams>({ page: 1, limit: 10, search: '' });
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  const [editingSystemConfig, setEditingSystemConfig] = useState<SystemConfigResponse | null>(null);
+  const [isCreateForm, setIsCreateForm] = useState(true);
+  const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
+  const [systemConfigToDelete, setSystemConfigToDelete] = useState<number | null>(null);
+
+  // 表单实例
+  const createForm = useForm({
+    resolver: zodResolver(createFormSchema),
+    defaultValues: {
+      configKey: '',
+      configValue: '',
+      description: ''
+    }
+  });
+
+  const updateForm = useForm({
+    resolver: zodResolver(updateFormSchema),
+    defaultValues: {}
+  });
+
+  // 数据查询
+  const { data, isLoading, refetch } = useQuery({
+    queryKey: ['system-configs', searchParams],
+    queryFn: async () => {
+      const res = await systemConfigClientManager.get().index.$get({
+        query: {
+          page: searchParams.page,
+          pageSize: searchParams.limit,
+          keyword: searchParams.search
+        }
+      });
+      if (res.status !== 200) throw new Error('获取系统配置列表失败');
+      return await res.json();
+    }
+  });
+
+  // 创建系统配置
+  const createMutation = useMutation({
+    mutationFn: async (data: CreateRequest) => {
+      const res = await systemConfigClientManager.get().index.$post({ json: data });
+      if (res.status !== 201) throw new Error('创建系统配置失败');
+      return await res.json();
+    },
+    onSuccess: () => {
+      toast.success('系统配置创建成功');
+      setIsModalOpen(false);
+      createForm.reset();
+      refetch();
+    },
+    onError: (error) => {
+      toast.error(error instanceof Error ? error.message : '创建系统配置失败');
+    }
+  });
+
+  // 更新系统配置
+  const updateMutation = useMutation({
+    mutationFn: async ({ id, data }: { id: number; data: UpdateRequest }) => {
+      const res = await systemConfigClientManager.get()[':id']['$put']({
+        param: { id },
+        json: data
+      });
+      if (res.status !== 200) throw new Error('更新系统配置失败');
+      return await res.json();
+    },
+    onSuccess: () => {
+      toast.success('系统配置更新成功');
+      setIsModalOpen(false);
+      setEditingSystemConfig(null);
+      refetch();
+    },
+    onError: (error) => {
+      toast.error(error instanceof Error ? error.message : '更新系统配置失败');
+    }
+  });
+
+  // 删除系统配置
+  const deleteMutation = useMutation({
+    mutationFn: async (id: number) => {
+      const res = await systemConfigClientManager.get()[':id']['$delete']({
+        param: { id }
+      });
+      if (res.status !== 204) throw new Error('删除系统配置失败');
+      return await res.json();
+    },
+    onSuccess: () => {
+      toast.success('系统配置删除成功');
+      setDeleteDialogOpen(false);
+      setSystemConfigToDelete(null);
+      refetch();
+    },
+    onError: (error) => {
+      toast.error(error instanceof Error ? error.message : '删除系统配置失败');
+    }
+  });
+
+  // 处理搜索
+  const handleSearch = (e: React.FormEvent) => {
+    e.preventDefault();
+    setSearchParams((prev: SystemConfigSearchParams) => ({ ...prev, page: 1 }));
+    refetch();
+  };
+
+  // 处理创建系统配置
+  const handleCreateSystemConfig = () => {
+    setIsCreateForm(true);
+    setEditingSystemConfig(null);
+    createForm.reset();
+    setIsModalOpen(true);
+  };
+
+  // 处理编辑系统配置
+  const handleEditSystemConfig = (systemConfig: SystemConfigResponse) => {
+    setIsCreateForm(false);
+    setEditingSystemConfig(systemConfig);
+    updateForm.reset({
+      configKey: systemConfig.configKey || undefined,
+      configValue: systemConfig.configValue || undefined,
+      description: systemConfig.description || undefined
+    });
+    setIsModalOpen(true);
+  };
+
+  // 处理删除系统配置
+  const handleDeleteSystemConfig = (id: number) => {
+    setSystemConfigToDelete(id);
+    setDeleteDialogOpen(true);
+  };
+
+  // 确认删除
+  const confirmDelete = () => {
+    if (systemConfigToDelete) {
+      deleteMutation.mutate(systemConfigToDelete);
+    }
+  };
+
+  // 处理创建表单提交
+  const handleCreateSubmit = async (data: SystemConfigFormData) => {
+    try {
+      await createMutation.mutateAsync(data);
+    } catch (error) {
+      throw error;
+    }
+  };
+
+  // 处理编辑表单提交
+  const handleUpdateSubmit = async (data: any) => {
+    if (!editingSystemConfig) return;
+
+    try {
+      await updateMutation.mutateAsync({
+        id: editingSystemConfig.id,
+        data
+      });
+    } catch (error) {
+      throw error;
+    }
+  };
+
+  return (
+    <div className="space-y-4">
+      <div className="flex justify-between items-center">
+        <h1 className="text-2xl font-bold">系统配置管理</h1>
+        <Button onClick={handleCreateSystemConfig}>
+          <Plus className="mr-2 h-4 w-4" />
+          创建配置
+        </Button>
+      </div>
+
+      <Card>
+        <CardHeader>
+          <CardTitle>系统配置列表</CardTitle>
+          <CardDescription>管理系统所有配置项,包括小程序配置、支付参数等</CardDescription>
+        </CardHeader>
+        <CardContent>
+          <div className="mb-4">
+            <form onSubmit={handleSearch} className="flex gap-2">
+              <div className="relative flex-1 max-w-sm">
+                <Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
+                <Input
+                  placeholder="搜索配置键或描述..."
+                  value={searchParams.search}
+                  onChange={(e) => setSearchParams((prev: SystemConfigSearchParams) => ({ ...prev, search: e.target.value }))}
+                  className="pl-8"
+                  data-testid="search-input"
+                />
+              </div>
+              <Button type="submit" variant="outline">
+                搜索
+              </Button>
+            </form>
+          </div>
+
+          <div className="rounded-md border">
+            <div className="relative w-full overflow-x-auto">
+              <Table>
+                <TableHeader>
+                  <TableRow>
+                    <TableHead>ID</TableHead>
+                    <TableHead>配置键</TableHead>
+                    <TableHead>配置值</TableHead>
+                    <TableHead>描述</TableHead>
+                    <TableHead>创建时间</TableHead>
+                    <TableHead>更新时间</TableHead>
+                    <TableHead className="text-right">操作</TableHead>
+                  </TableRow>
+                </TableHeader>
+                <TableBody>
+                  {isLoading ? (
+                    Array.from({ length: 5 }).map((_, index) => (
+                      <TableRow key={index}>
+                        <TableCell>
+                          <Skeleton className="h-4 w-8" />
+                        </TableCell>
+                        <TableCell>
+                          <Skeleton className="h-4 w-12" />
+                        </TableCell>
+                        <TableCell>
+                          <Skeleton className="h-4 w-32" />
+                        </TableCell>
+                        <TableCell>
+                          <Skeleton className="h-4 w-40" />
+                        </TableCell>
+                        <TableCell>
+                          <Skeleton className="h-4 w-24" />
+                        </TableCell>
+                        <TableCell>
+                          <Skeleton className="h-4 w-24" />
+                        </TableCell>
+                        <TableCell>
+                          <Skeleton className="h-4 w-24" />
+                        </TableCell>
+                        <TableCell>
+                          <div className="flex justify-end gap-2">
+                            <Skeleton className="h-8 w-8 rounded" />
+                            <Skeleton className="h-8 w-8 rounded" />
+                          </div>
+                        </TableCell>
+                      </TableRow>
+                    ))
+                  ) : data?.data && data.data.length > 0 ? (
+                    data.data.map((systemConfig) => (
+                      <TableRow key={systemConfig.id}>
+                        <TableCell>{systemConfig.id}</TableCell>
+                        <TableCell>
+                          <code className="text-xs bg-muted px-1 rounded">{systemConfig.configKey}</code>
+                        </TableCell>
+                        <TableCell>
+                          <div className="max-w-xs truncate">
+                            {systemConfig.configValue}
+                          </div>
+                        </TableCell>
+                        <TableCell>
+                          {systemConfig.description || '-'}
+                        </TableCell>
+                        <TableCell>
+                          {systemConfig.createdAt ? format(new Date(systemConfig.createdAt), 'yyyy-MM-dd HH:mm') : '-'}
+                        </TableCell>
+                        <TableCell>
+                          {systemConfig.updatedAt ? format(new Date(systemConfig.updatedAt), 'yyyy-MM-dd HH:mm') : '-'}
+                        </TableCell>
+                        <TableCell className="text-right">
+                          <div className="flex justify-end gap-2">
+                            <Button
+                              variant="ghost"
+                              size="icon"
+                              onClick={() => handleEditSystemConfig(systemConfig)}
+                              data-testid={`edit-button-${systemConfig.id}`}
+                            >
+                              <Edit className="h-4 w-4" />
+                            </Button>
+                            <Button
+                              variant="ghost"
+                              size="icon"
+                              onClick={() => handleDeleteSystemConfig(systemConfig.id)}
+                              data-testid={`delete-button-${systemConfig.id}`}
+                            >
+                              <Trash2 className="h-4 w-4" />
+                            </Button>
+                          </div>
+                        </TableCell>
+                      </TableRow>
+                    ))
+                  ) : (
+                    <TableRow>
+                      <TableCell colSpan={8} className="text-center py-8">
+                        <p className="text-muted-foreground">暂无系统配置数据</p>
+                      </TableCell>
+                    </TableRow>
+                  )}
+                </TableBody>
+              </Table>
+            </div>
+          </div>
+
+          <DataTablePagination
+            currentPage={searchParams.page}
+            pageSize={searchParams.limit}
+            totalCount={data?.pagination.total || 0}
+            onPageChange={(page, limit) => setSearchParams((prev: SystemConfigSearchParams) => ({ ...prev, page, limit }))}
+          />
+        </CardContent>
+      </Card>
+
+      {/* 创建/编辑对话框 */}
+      <Dialog open={isModalOpen} onOpenChange={setIsModalOpen}>
+        <DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto">
+          <DialogHeader>
+            <DialogTitle>{isCreateForm ? '创建系统配置' : '编辑系统配置'}</DialogTitle>
+            <DialogDescription>
+              {isCreateForm ? '创建一个新的系统配置项' : '编辑现有系统配置信息'}
+            </DialogDescription>
+          </DialogHeader>
+
+          {isCreateForm ? (
+            // 创建表单(独立渲染)
+            <Form {...createForm}>
+              <form onSubmit={createForm.handleSubmit(handleCreateSubmit)} className="space-y-4">
+                <FormField
+                  control={createForm.control}
+                  name="configKey"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel className="flex items-center">
+                        配置键 <span className="text-red-500 ml-1">*</span>
+                      </FormLabel>
+                      <FormControl>
+                        <Input
+                          placeholder="请输入配置键,如:app.login.enabled"
+                          {...field}
+                          data-testid="config-key-input"
+                        />
+                      </FormControl>
+                      <FormDescription>配置项的唯一标识,使用点分隔符命名,如:app.login.enabled</FormDescription>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+
+                <FormField
+                  control={createForm.control}
+                  name="configValue"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel className="flex items-center">
+                        配置值 <span className="text-red-500 ml-1">*</span>
+                      </FormLabel>
+                      <FormControl>
+                        <Textarea
+                          placeholder="请输入配置值"
+                          {...field}
+                          data-testid="config-value-input"
+                        />
+                      </FormControl>
+                      <FormDescription>配置项的具体值,可以是字符串、数字或布尔值</FormDescription>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+
+                <FormField
+                  control={createForm.control}
+                  name="description"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>配置描述</FormLabel>
+                      <FormControl>
+                        <Textarea
+                          placeholder="请输入配置描述"
+                          {...field}
+                          data-testid="description-input"
+                        />
+                      </FormControl>
+                      <FormDescription>配置项的详细说明和用途描述</FormDescription>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+
+                <DialogFooter>
+                  <Button type="button" variant="outline" onClick={() => setIsModalOpen(false)}>
+                    取消
+                  </Button>
+                  <Button type="submit" disabled={createMutation.isPending} data-testid="create-submit-button">
+                    创建
+                  </Button>
+                </DialogFooter>
+              </form>
+            </Form>
+          ) : (
+            // 编辑表单(独立渲染)
+            <Form {...updateForm}>
+              <form onSubmit={updateForm.handleSubmit(handleUpdateSubmit)} className="space-y-4">
+                <FormField
+                  control={updateForm.control}
+                  name="configKey"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel className="flex items-center">
+                        配置键 <span className="text-red-500 ml-1">*</span>
+                      </FormLabel>
+                      <FormControl>
+                        <Input
+                          placeholder="请输入配置键"
+                          {...field}
+                          data-testid="config-key-input"
+                        />
+                      </FormControl>
+                      <FormDescription>配置项的唯一标识,使用点分隔符命名</FormDescription>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+
+                <FormField
+                  control={updateForm.control}
+                  name="configValue"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel className="flex items-center">
+                        配置值 <span className="text-red-500 ml-1">*</span>
+                      </FormLabel>
+                      <FormControl>
+                        <Textarea
+                          placeholder="请输入配置值"
+                          {...field}
+                          data-testid="config-value-input"
+                        />
+                      </FormControl>
+                      <FormDescription>配置项的具体值,可以是字符串、数字或布尔值</FormDescription>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+
+                <FormField
+                  control={updateForm.control}
+                  name="description"
+                  render={({ field }) => (
+                    <FormItem>
+                      <FormLabel>配置描述</FormLabel>
+                      <FormControl>
+                        <Textarea
+                          placeholder="请输入配置描述"
+                          {...field}
+                          data-testid="description-input"
+                        />
+                      </FormControl>
+                      <FormDescription>配置项的详细说明和用途描述</FormDescription>
+                      <FormMessage />
+                    </FormItem>
+                  )}
+                />
+
+                <DialogFooter>
+                  <Button type="button" variant="outline" onClick={() => setIsModalOpen(false)}>
+                    取消
+                  </Button>
+                  <Button type="submit" disabled={updateMutation.isPending} data-testid="update-submit-button">
+                    更新
+                  </Button>
+                </DialogFooter>
+              </form>
+            </Form>
+          )}
+        </DialogContent>
+      </Dialog>
+
+      {/* 删除确认对话框 */}
+      <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
+        <DialogContent>
+          <DialogHeader>
+            <DialogTitle>确认删除</DialogTitle>
+            <DialogDescription>
+              确定要删除这个系统配置吗?此操作无法撤销。
+            </DialogDescription>
+          </DialogHeader>
+          <DialogFooter>
+            <Button variant="outline" onClick={() => setDeleteDialogOpen(false)}>
+              取消
+            </Button>
+            <Button
+              variant="destructive"
+              onClick={confirmDelete}
+              disabled={deleteMutation.isPending}
+              data-testid="confirm-delete-button"
+            >
+              {deleteMutation.isPending ? '删除中...' : '删除'}
+            </Button>
+          </DialogFooter>
+        </DialogContent>
+      </Dialog>
+    </div>
+  );
+};
+
+export default SystemConfigManagement;

+ 1 - 0
packages/system-config-management-ui-mt/src/components/index.ts

@@ -0,0 +1 @@
+export { default as SystemConfigManagement } from './SystemConfigManagement';

+ 18 - 0
packages/system-config-management-ui-mt/src/index.ts

@@ -0,0 +1,18 @@
+// 主包导出入口
+
+export { SystemConfigManagement } from './components';
+
+export {
+  SystemConfigClientManager,
+  systemConfigClientManager,
+  systemConfigClient
+} from './api';
+
+export type {
+  CreateSystemConfigRequest,
+  UpdateSystemConfigRequest,
+  SystemConfigResponse,
+  SystemConfigListResponse,
+  SystemConfigFormData,
+  SystemConfigSearchParams
+} from './types';

+ 8 - 0
packages/system-config-management-ui-mt/src/types/index.ts

@@ -0,0 +1,8 @@
+export type {
+  CreateSystemConfigRequest,
+  UpdateSystemConfigRequest,
+  SystemConfigResponse,
+  SystemConfigListResponse,
+  SystemConfigFormData,
+  SystemConfigSearchParams
+} from './systemConfig';

+ 19 - 0
packages/system-config-management-ui-mt/src/types/systemConfig.ts

@@ -0,0 +1,19 @@
+import type { InferRequestType, InferResponseType } from 'hono/client';
+import { systemConfigClient } from '../api/systemConfigClient';
+
+export type CreateSystemConfigRequest = InferRequestType<typeof systemConfigClient.index.$post>['json'];
+export type UpdateSystemConfigRequest = InferRequestType<typeof systemConfigClient[':id']['$put']>['json'];
+export type SystemConfigResponse = InferResponseType<typeof systemConfigClient.index.$get, 200>['data'][0];
+export type SystemConfigListResponse = InferResponseType<typeof systemConfigClient.index.$get, 200>;
+
+export interface SystemConfigFormData {
+  configKey: string;
+  configValue: string;
+  description?: string | null;
+}
+
+export interface SystemConfigSearchParams {
+  page: number;
+  limit: number;
+  search: string;
+}

+ 303 - 0
packages/system-config-management-ui-mt/tests/integration/system-config-management.integration.test.tsx

@@ -0,0 +1,303 @@
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { SystemConfigManagement } from '../../src/components/SystemConfigManagement';
+import { systemConfigClientManager } from '../../src/api/systemConfigClient';
+
+// 完整的mock响应对象
+const createMockResponse = (status: number, data?: any) => ({
+  status,
+  ok: status >= 200 && status < 300,
+  body: null,
+  bodyUsed: false,
+  statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : status === 204 ? 'No Content' : 'Error',
+  headers: new Headers(),
+  url: '',
+  redirected: false,
+  type: 'basic' as ResponseType,
+  json: async () => data || {},
+  text: async () => '',
+  blob: async () => new Blob(),
+  arrayBuffer: async () => new ArrayBuffer(0),
+  formData: async () => new FormData(),
+  clone: function() { return this; }
+});
+
+// Mock API client
+vi.mock('../../src/api/systemConfigClient', () => {
+  const mockSystemConfigClient = {
+    index: {
+      $get: vi.fn(() => Promise.resolve(createMockResponse(200, {
+        data: [
+          {
+            id: 1,
+            configKey: 'wx.mini.app.id',
+            configValue: 'wx1234567890',
+            description: '微信小程序AppID',
+            tenantId: 1,
+            createdBy: 1,
+            updatedBy: 1,
+            createdAt: '2024-01-01T00:00:00Z',
+            updatedAt: '2024-01-01T00:00:00Z'
+          }
+        ],
+        pagination: {
+          page: 1,
+          pageSize: 10,
+          total: 1,
+          totalPages: 1
+        }
+      }))),
+      $post: vi.fn(() => Promise.resolve(createMockResponse(201, { id: 2, configKey: 'wx.mini.app.secret', configValue: 'secret123' }))),
+    },
+    ':id': {
+      $put: vi.fn(() => Promise.resolve(createMockResponse(200, { id: 1, configKey: 'wx.mini.app.id', configValue: 'updated_value' }))),
+      $delete: vi.fn(() => Promise.resolve(createMockResponse(204))),
+    },
+  };
+
+  const mockSystemConfigClientManager = {
+    get: vi.fn(() => mockSystemConfigClient),
+  };
+
+  return {
+    systemConfigClientManager: mockSystemConfigClientManager,
+    systemConfigClient: mockSystemConfigClient,
+  };
+});
+
+// Mock toast
+vi.mock('sonner', () => ({
+  toast: {
+    success: vi.fn(() => {}),
+    error: vi.fn(() => {}),
+  },
+}));
+
+const createTestQueryClient = () =>
+  new QueryClient({
+    defaultOptions: {
+      queries: {
+        retry: false,
+      },
+    },
+  });
+
+const renderWithProviders = (component: React.ReactElement) => {
+  const queryClient = createTestQueryClient();
+  return render(
+    <QueryClientProvider client={queryClient}>
+      {component as any}
+    </QueryClientProvider>
+  );
+};
+
+describe('系统配置管理集成测试', () => {
+  beforeEach(() => {
+    vi.clearAllMocks();
+  });
+
+  it('应该完成完整的系统配置CRUD流程', async () => {
+    const mockSystemConfigs = {
+      data: [
+        {
+          id: 1,
+          configKey: 'wx.mini.app.id',
+          configValue: 'wx1234567890',
+          description: '微信小程序AppID',
+          tenantId: 1,
+          createdBy: 1,
+          updatedBy: 1,
+          createdAt: '2024-01-01T00:00:00Z',
+          updatedAt: '2024-01-01T00:00:00Z'
+        },
+      ],
+      pagination: {
+        total: 1,
+        page: 1,
+        pageSize: 10,
+      },
+    };
+
+    const { toast } = await import('sonner');
+
+    // Mock initial system config list
+    const client = systemConfigClientManager.get();
+    (client.index.$get as any).mockResolvedValue({
+      ...createMockResponse(200),
+      json: async () => mockSystemConfigs
+    });
+
+    renderWithProviders(<SystemConfigManagement />);
+
+    // Wait for initial data to load
+    await waitFor(() => {
+      expect(screen.getByText('wx.mini.app.id')).toBeInTheDocument();
+    });
+
+    // Test create system config
+    const createButton = screen.getByText('创建配置');
+    fireEvent.click(createButton);
+
+    // Fill create form
+    const configKeyInput = screen.getByTestId('config-key-input');
+    const configValueInput = screen.getByTestId('config-value-input');
+    const descriptionInput = screen.getByTestId('description-input');
+
+    fireEvent.change(configKeyInput, { target: { value: 'wx.mini.app.secret' } });
+    fireEvent.change(configValueInput, { target: { value: 'secret123' } });
+    fireEvent.change(descriptionInput, { target: { value: '微信小程序AppSecret' } });
+
+    // Mock successful creation
+    (client.index.$post as any).mockResolvedValue(createMockResponse(201, {
+      id: 2,
+      configKey: 'wx.mini.app.secret',
+      configValue: 'secret123'
+    }));
+
+    const submitButton = screen.getByTestId('create-submit-button');
+    fireEvent.click(submitButton);
+
+    await waitFor(() => {
+      expect(client.index.$post).toHaveBeenCalledWith({
+        json: {
+          configKey: 'wx.mini.app.secret',
+          configValue: 'secret123',
+          description: '微信小程序AppSecret'
+        },
+      });
+      expect(toast.success).toHaveBeenCalledWith('系统配置创建成功');
+    });
+
+    // Test edit system config
+    const editButton = screen.getByTestId('edit-button-1');
+    fireEvent.click(editButton);
+
+    // Verify edit form is populated
+    await waitFor(() => {
+      expect(screen.getByDisplayValue('wx.mini.app.id')).toBeInTheDocument();
+    });
+
+    // Update system config
+    const updateConfigValueInput = screen.getByDisplayValue('wx1234567890');
+    fireEvent.change(updateConfigValueInput, { target: { value: 'updated_value' } });
+
+    // Mock successful update
+    (client[':id']['$put'] as any).mockResolvedValue(createMockResponse(200));
+
+    const updateButton = screen.getByTestId('update-submit-button');
+    fireEvent.click(updateButton);
+
+    await waitFor(() => {
+      expect(client[':id']['$put']).toHaveBeenCalledWith({
+        param: { id: 1 },
+        json: {
+          configKey: 'wx.mini.app.id',
+          configValue: 'updated_value',
+          description: '微信小程序AppID'
+        },
+      });
+      expect(toast.success).toHaveBeenCalledWith('系统配置更新成功');
+    });
+
+    // Test delete system config
+    const deleteButton = screen.getByTestId('delete-button-1');
+    fireEvent.click(deleteButton);
+
+    // Confirm deletion
+    expect(screen.getByText('确认删除')).toBeInTheDocument();
+
+    // Mock successful deletion
+    (client[':id']['$delete'] as any).mockResolvedValue({
+      status: 204,
+      ok: true,
+      body: null,
+      bodyUsed: false,
+      statusText: 'No Content',
+      headers: new Headers(),
+      url: '',
+      redirected: false,
+      type: 'basic' as ResponseType,
+      json: async () => ({}),
+      text: async () => '',
+      blob: async () => new Blob(),
+      arrayBuffer: async () => new ArrayBuffer(0),
+      formData: async () => new FormData(),
+      clone: function() { return this; }
+    });
+
+    const confirmDeleteButton = screen.getByTestId('confirm-delete-button');
+    fireEvent.click(confirmDeleteButton);
+
+    await waitFor(() => {
+      expect(client[':id']['$delete']).toHaveBeenCalledWith({
+        param: { id: 1 },
+      });
+      expect(toast.success).toHaveBeenCalledWith('系统配置删除成功');
+    });
+  });
+
+  it('应该优雅处理API错误', async () => {
+    const client = systemConfigClientManager.get();
+    const { toast } = await import('sonner');
+
+    // Mock API error
+    (client.index.$get as any).mockRejectedValue(new Error('API Error'));
+
+    renderWithProviders(<SystemConfigManagement />);
+
+    // Should handle error without crashing
+    await waitFor(() => {
+      expect(screen.getByText('系统配置管理')).toBeInTheDocument();
+    });
+
+    // Test create system config error
+    const createButton = screen.getByText('创建配置');
+    fireEvent.click(createButton);
+
+    const configKeyInput = screen.getByTestId('config-key-input');
+    const configValueInput = screen.getByTestId('config-value-input');
+
+    fireEvent.change(configKeyInput, { target: { value: 'wx.mini.app.id' } });
+    fireEvent.change(configValueInput, { target: { value: 'test_value' } });
+
+    // Mock creation error
+    (client.index.$post as any).mockRejectedValue(new Error('Creation failed'));
+
+    const submitButton = screen.getByTestId('create-submit-button');
+    fireEvent.click(submitButton);
+
+    await waitFor(() => {
+      expect(toast.error).toHaveBeenCalledWith('Creation failed');
+    });
+  });
+
+  it('应该处理搜索功能', async () => {
+    const client = systemConfigClientManager.get();
+    const mockSystemConfigs = {
+      data: [],
+      pagination: { total: 0, page: 1, pageSize: 10 },
+    };
+
+    (client.index.$get as any).mockResolvedValue(createMockResponse(200, mockSystemConfigs));
+
+    renderWithProviders(<SystemConfigManagement />);
+
+    // Test search
+    const searchInput = screen.getByTestId('search-input');
+    fireEvent.change(searchInput, { target: { value: '微信' } });
+
+    const searchButton = screen.getByText('搜索');
+    fireEvent.click(searchButton);
+
+    await waitFor(() => {
+      expect(client.index.$get).toHaveBeenCalledWith({
+        query: {
+          page: 1,
+          pageSize: 10,
+          keyword: '微信',
+        },
+      });
+    });
+  });
+});

+ 14 - 0
packages/system-config-management-ui-mt/tests/setup.ts

@@ -0,0 +1,14 @@
+import '@testing-library/jest-dom';
+import { vi } from 'vitest';
+
+
+
+// Mock sonner
+vi.mock('sonner', () => ({
+  toast: {
+    success: vi.fn(),
+    error: vi.fn(),
+    warning: vi.fn(),
+    info: vi.fn()
+  }
+}));

+ 36 - 0
packages/system-config-management-ui-mt/tsconfig.json

@@ -0,0 +1,36 @@
+{
+  "compilerOptions": {
+    "target": "ES2022",
+    "lib": ["ES2022", "DOM", "DOM.Iterable"],
+    "module": "ESNext",
+    "skipLibCheck": true,
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true,
+    "jsx": "react-jsx",
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "noFallthroughCasesInSwitch": true,
+    "experimentalDecorators": true,
+    "emitDecoratorMetadata": true,
+    "declaration": true,
+    "declarationMap": true,
+    "sourceMap": true,
+    "outDir": "./dist",
+    "baseUrl": ".",
+    "paths": {
+      "@/*": ["./src/*"]
+    }
+  },
+  "include": [
+    "src/**/*",
+    "tests/**/*"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist"
+  ]
+}

+ 24 - 0
packages/system-config-management-ui-mt/vitest.config.ts

@@ -0,0 +1,24 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+  test: {
+    globals: true,
+    environment: 'jsdom',
+    setupFiles: ['./tests/setup.ts'],
+    coverage: {
+      provider: 'v8',
+      reporter: ['text', 'json', 'html'],
+      exclude: [
+        'node_modules/',
+        'tests/',
+        '**/*.d.ts',
+        '**/*.config.*'
+      ]
+    }
+  },
+  resolve: {
+    alias: {
+      '@': './src'
+    }
+  }
+});

+ 100 - 0
pnpm-lock.yaml

@@ -2866,6 +2866,9 @@ importers:
       '@d8d/auth-module-mt':
         specifier: workspace:*
         version: link:../auth-module-mt
+      '@d8d/core-module-mt':
+        specifier: workspace:*
+        version: link:../core-module-mt
       '@d8d/file-module-mt':
         specifier: workspace:*
         version: link:../file-module-mt
@@ -3264,6 +3267,9 @@ importers:
       '@d8d/auth-module-mt':
         specifier: workspace:*
         version: link:../auth-module-mt
+      '@d8d/core-module-mt':
+        specifier: workspace:*
+        version: link:../core-module-mt
       '@d8d/delivery-address-module-mt':
         specifier: workspace:*
         version: link:../delivery-address-module-mt
@@ -3997,6 +4003,97 @@ importers:
         specifier: ^3.2.4
         version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.1)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(sass@1.94.1)(stylus@0.64.0)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
 
+  packages/system-config-management-ui-mt:
+    dependencies:
+      '@d8d/core-module-mt':
+        specifier: workspace:*
+        version: link:../core-module-mt
+      '@d8d/shared-types':
+        specifier: workspace:*
+        version: link:../shared-types
+      '@d8d/shared-ui-components':
+        specifier: workspace:*
+        version: link:../shared-ui-components
+      '@hookform/resolvers':
+        specifier: ^5.2.1
+        version: 5.2.2(react-hook-form@7.65.0(react@19.2.0))
+      '@tanstack/react-query':
+        specifier: ^5.90.9
+        version: 5.90.9(react@19.2.0)
+      class-variance-authority:
+        specifier: ^0.7.1
+        version: 0.7.1
+      clsx:
+        specifier: ^2.1.1
+        version: 2.1.1
+      date-fns:
+        specifier: ^4.1.0
+        version: 4.1.0
+      hono:
+        specifier: ^4.8.5
+        version: 4.8.5
+      lucide-react:
+        specifier: ^0.536.0
+        version: 0.536.0(react@19.2.0)
+      react:
+        specifier: ^19.1.0
+        version: 19.2.0
+      react-dom:
+        specifier: ^19.1.0
+        version: 19.2.0(react@19.2.0)
+      react-hook-form:
+        specifier: ^7.61.1
+        version: 7.65.0(react@19.2.0)
+      sonner:
+        specifier: ^2.0.7
+        version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+      tailwind-merge:
+        specifier: ^3.3.1
+        version: 3.3.1
+      zod:
+        specifier: ^4.0.15
+        version: 4.1.12
+    devDependencies:
+      '@testing-library/jest-dom':
+        specifier: ^6.8.0
+        version: 6.9.1
+      '@testing-library/react':
+        specifier: ^16.3.0
+        version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+      '@testing-library/user-event':
+        specifier: ^14.6.1
+        version: 14.6.1(@testing-library/dom@10.4.1)
+      '@types/node':
+        specifier: ^22.10.2
+        version: 22.19.0
+      '@types/react':
+        specifier: ^19.2.2
+        version: 19.2.2
+      '@types/react-dom':
+        specifier: ^19.2.3
+        version: 19.2.3(@types/react@19.2.2)
+      '@typescript-eslint/eslint-plugin':
+        specifier: ^8.18.1
+        version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3)
+      '@typescript-eslint/parser':
+        specifier: ^8.18.1
+        version: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3)
+      eslint:
+        specifier: ^9.17.0
+        version: 9.38.0(jiti@2.6.1)
+      jsdom:
+        specifier: ^26.0.0
+        version: 26.1.0
+      typescript:
+        specifier: ^5.8.3
+        version: 5.8.3
+      unbuild:
+        specifier: ^3.4.0
+        version: 3.6.1(sass@1.93.2)(typescript@5.8.3)(vue@3.5.22(typescript@5.8.3))
+      vitest:
+        specifier: ^4.0.9
+        version: 4.0.9(@types/debug@4.1.12)(@types/node@22.19.0)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(sass@1.93.2)(stylus@0.64.0)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)
+
   packages/tenant-management-ui:
     dependencies:
       '@d8d/shared-ui-components':
@@ -4494,6 +4591,9 @@ importers:
       '@d8d/supplier-module':
         specifier: workspace:*
         version: link:../packages/supplier-module
+      '@d8d/system-config-management-ui-mt':
+        specifier: workspace:*
+        version: link:../packages/system-config-management-ui-mt
       '@d8d/tenant-management-ui':
         specifier: workspace:*
         version: link:../packages/tenant-management-ui

+ 1 - 0
web/package.json

@@ -62,6 +62,7 @@
     "@d8d/goods-category-management-ui-mt": "workspace:*",
     "@d8d/delivery-address-management-ui-mt": "workspace:*",
     "@d8d/advertisement-management-ui-mt": "workspace:*",
+    "@d8d/system-config-management-ui-mt": "workspace:*",
     "@d8d/tenant-management-ui": "workspace:*",
     "@d8d/user-module": "workspace:*",
     "@heroicons/react": "^2.2.0",

+ 3 - 7
web/src/client/admin/api_init.ts

@@ -11,6 +11,7 @@ import { goodsClientManager } from '@d8d/goods-management-ui-mt/api';
 import { goodsCategoryClientManager } from '@d8d/goods-category-management-ui-mt/api';
 import { deliveryAddressClientManager } from '@d8d/delivery-address-management-ui-mt/api';
 import { advertisementClientManager } from '@d8d/advertisement-management-ui-mt/api';
+import { systemConfigClientManager } from '@d8d/system-config-management-ui-mt/api';
 
 
 // 初始化所有多租户API客户端
@@ -20,15 +21,10 @@ fileClientManager.init('/api/v1/files');
 areaClientManager.init('/api/v1/admin/areas');
 supplierClientManager.init('/api/v1/suppliers');
 merchantClientManager.init('/api/v1/merchants');
-orderClientManager.init('/api/v1/orders');
+orderClientManager.init('/api/v1/admin/orders');
 advertisementTypeClientManager.init('/api/v1/advertisement-types');
 goodsClientManager.init('/api/v1/goods');
 goodsCategoryClientManager.init('/api/v1/goods-categories');
 deliveryAddressClientManager.init('/api/v1/admin/delivery-addresses');
 advertisementClientManager.init('/api/v1/advertisements');
-
-
-// 租户管理UI包API客户端初始化
-import { tenantClientManager } from '@d8d/tenant-management-ui';
-// 初始化租户管理API客户端
-tenantClientManager.init('/api/v1/tenants');
+systemConfigClientManager.init('/api/v1/admin/system-configs');

+ 5 - 5
web/src/client/admin/menu.tsx

@@ -17,7 +17,7 @@ import {
   UserCheck,
   CreditCard,
   TrendingUp,
-  MapPin
+  MapPin,
 } from 'lucide-react';
 
 export interface MenuItem {
@@ -226,11 +226,11 @@ export const useMenu = () => {
     //   ]
     // },
     {
-      key: 'settings',
-      label: '系统置',
+      key: 'system-configs',
+      label: '系统置',
       icon: <Settings className="h-4 w-4" />,
-      path: '/admin/settings',
-      permission: 'settings:manage'
+      path: '/admin/system-configs',
+      permission: 'system-config:manage'
     },
   ];
 

+ 7 - 1
web/src/client/admin/routes.tsx

@@ -19,8 +19,9 @@ import { GoodsManagement } from '@d8d/goods-management-ui-mt';
 import { GoodsCategoryManagement } from '@d8d/goods-category-management-ui-mt';
 import { DeliveryAddressManagement } from '@d8d/delivery-address-management-ui-mt';
 import { AdvertisementManagement } from '@d8d/advertisement-management-ui-mt';
+import { SystemConfigManagement } from '@d8d/system-config-management-ui-mt';
 
-import "@/client/admin/api_init"
+import "./api_init"
 
 export const router = createBrowserRouter([
   {
@@ -108,6 +109,11 @@ export const router = createBrowserRouter([
         element: <OrderManagement />,
         errorElement: <ErrorPage />
       },
+      {
+        path: 'system-configs',
+        element: <SystemConfigManagement />,
+        errorElement: <ErrorPage />
+      },
       {
         path: '*',
         element: <NotFoundPage />,

+ 0 - 30
web/src/client/tenant/api_init.ts

@@ -1,33 +1,3 @@
-// 多租户UI包API客户端初始化
-import { userClientManager } from '@d8d/user-management-ui-mt/api';
-import { authClientManager } from '@d8d/auth-management-ui-mt/api';
-import { fileClientManager } from '@d8d/file-management-ui-mt/api';
-import { areaClientManager } from '@d8d/area-management-ui-mt/api';
-import { supplierClientManager } from '@d8d/supplier-management-ui-mt/api';
-import { merchantClientManager } from '@d8d/merchant-management-ui-mt/api';
-import { orderClientManager } from '@d8d/order-management-ui-mt/api';
-import { advertisementTypeClientManager } from '@d8d/advertisement-type-management-ui-mt/api';
-import { goodsClientManager } from '@d8d/goods-management-ui-mt/api';
-import { goodsCategoryClientManager } from '@d8d/goods-category-management-ui-mt/api';
-import { deliveryAddressClientManager } from '@d8d/delivery-address-management-ui-mt/api';
-import { advertisementClientManager } from '@d8d/advertisement-management-ui-mt/api';
-
-
-// 初始化所有多租户API客户端
-userClientManager.init('/api/v1/users');
-authClientManager.init('/api/v1/auth');
-fileClientManager.init('/api/v1/files');
-areaClientManager.init('/api/v1/admin/areas');
-supplierClientManager.init('/api/v1/suppliers');
-merchantClientManager.init('/api/v1/merchants');
-orderClientManager.init('/api/v1/orders');
-advertisementTypeClientManager.init('/api/v1/advertisement-types');
-goodsClientManager.init('/api/v1/goods');
-goodsCategoryClientManager.init('/api/v1/goods-categories');
-deliveryAddressClientManager.init('/api/v1/admin/delivery-addresses');
-advertisementClientManager.init('/api/v1/advertisements');
-
-
 // 租户管理UI包API客户端初始化
 import { tenantClientManager } from '@d8d/tenant-management-ui';
 // 初始化租户管理API客户端

+ 1 - 1
web/src/client/tenant/routes.tsx

@@ -9,7 +9,7 @@ import { TenantLoginPage } from '@d8d/tenant-management-ui';
 // 租户管理UI包导入
 import { TenantsPage, TenantConfigPage } from '@d8d/tenant-management-ui';
 
-import "@/client/tenant/api_init"
+import "./api_init"
 
 export const router = createBrowserRouter([
   {