anhuiqiang hai 6 horas
pai
achega
ddbb36315d

+ 3 - 0
server/src/feishu/entities/feishu-bot.entity.ts

@@ -17,6 +17,9 @@ export class FeishuBot {
   @Column({ name: 'user_id' })
   userId: string;
 
+  @Column({ name: 'tenant_id', nullable: true })
+  tenantId: string;
+
   @ManyToOne(() => User, { onDelete: 'CASCADE' })
   @JoinColumn({ name: 'user_id' })
   user: User;

+ 9 - 2
server/src/feishu/feishu.controller.ts

@@ -36,7 +36,10 @@ export class FeishuController {
   @Get('bots')
   @UseGuards(CombinedAuthGuard)
   async listBots(@Request() req) {
-    const bots = await this.feishuService.getUserBots(req.user.id);
+    const bots = await this.feishuService.getUserBots(
+      req.user.id,
+      req.user.tenantId,
+    );
     return bots.map((bot) => ({
       id: bot.id,
       appId: bot.appId,
@@ -52,7 +55,11 @@ export class FeishuController {
   @Post('bots')
   @UseGuards(CombinedAuthGuard)
   async createBot(@Request() req, @Body() dto: CreateFeishuBotDto) {
-    const bot = await this.feishuService.createBot(req.user.id, dto);
+    const bot = await this.feishuService.createBot(
+      req.user.id,
+      req.user.tenantId,
+      dto,
+    );
     return {
       id: bot.id,
       appId: bot.appId,

+ 49 - 20
server/src/feishu/feishu.service.ts

@@ -17,6 +17,8 @@ import { ModelType } from '../types';
 import { FeishuWsManager } from './feishu-ws.manager';
 import { ConnectionStatus } from './dto/ws-status.dto';
 import { FeishuAssessmentService } from './services/feishu-assessment.service';
+import { tenantStore } from '../tenant/tenant.store';
+import { i18nStore } from '../i18n/i18n.store';
 
 @Injectable()
 export class FeishuService implements OnModuleInit {
@@ -42,11 +44,13 @@ export class FeishuService implements OnModuleInit {
     this.wsManager.setFeishuService(this);
   }
 
-  // ─── Bot CRUD ────────────────────────────────────────────────────────────────
-
-  async createBot(userId: string, dto: CreateFeishuBotDto): Promise<FeishuBot> {
+  async createBot(
+    userId: string,
+    tenantId: string,
+    dto: CreateFeishuBotDto,
+  ): Promise<FeishuBot> {
     const existing = await this.botRepository.findOne({
-      where: { userId, appId: dto.appId },
+      where: { userId, appId: dto.appId, tenantId },
     });
 
     if (existing) {
@@ -54,13 +58,13 @@ export class FeishuService implements OnModuleInit {
       return this.botRepository.save(existing);
     }
 
-    const bot = this.botRepository.create({ userId, ...dto });
+    const bot = this.botRepository.create({ userId, tenantId, ...dto });
     return this.botRepository.save(bot);
   }
 
-  async getUserBots(userId: string): Promise<FeishuBot[]> {
+  async getUserBots(userId: string, tenantId: string): Promise<FeishuBot[]> {
     return this.botRepository.find({
-      where: { userId },
+      where: { userId, tenantId },
       relations: ['user'],
     });
   }
@@ -301,18 +305,41 @@ export class FeishuService implements OnModuleInit {
       }
     }
 
+    // Get bot owner context
+    const userId = bot.userId;
+    const tenantId = bot.tenantId || 'default';
+
+    // We still fetch the user for language preference, but tenant/user IDs are from bot
+    const user = await this.userService.findOneById(userId);
+    const language = user?.userSetting?.language || 'zh';
+
     try {
-      // Check if message is an assessment command
-      if (this.isAssessmentCommand(userText)) {
-        this.logger.log(
-          `Routing assessment command [${messageId}] for bot ${bot.appId}`,
-        );
-        // Delegate to assessment service
-        await this.feishuAssessmentService.handleCommand(bot, openId, userText);
-      } else {
-        // Delegate to standard RAG pipeline
-        await this.processChatMessage(bot, openId, messageId, userText, true);
-      }
+      // Establish context for all downstream services and TypeORM subscribers
+      await tenantStore.run({ tenantId, userId }, async () => {
+        await i18nStore.run({ language }, async () => {
+          // Check if message is an assessment command
+          if (this.isAssessmentCommand(userText)) {
+            this.logger.log(
+              `Routing assessment command [${messageId}] for bot ${bot.appId}`,
+            );
+            // Delegate to assessment service (will run in the same context)
+            await this.feishuAssessmentService.handleCommand(
+              bot,
+              openId,
+              userText,
+            );
+          } else {
+            // Delegate to standard RAG pipeline (will run in the same context)
+            await this.processChatMessage(
+              bot,
+              openId,
+              messageId,
+              userText,
+              true,
+            );
+          }
+        });
+      });
     } catch (error) {
       this.logger.error(
         `Message routing failed [${messageId}]: ${error.message}`,
@@ -366,10 +393,12 @@ export class FeishuService implements OnModuleInit {
       }
     }
 
-    // Get user from bot owner
+    // Get bot owner context
     const userId = bot.userId;
+    const tenantId = bot.tenantId || 'default';
+
+    // Fetch user for language preference
     const user = await this.userService.findOneById(userId);
-    const tenantId = user?.tenantId || 'default';
     const language = user?.userSetting?.language || 'zh';
 
     // Get the user's default LLM model

+ 9 - 6
server/src/feishu/services/feishu-assessment.service.ts

@@ -7,6 +7,8 @@ import { FeishuService } from '../feishu.service';
 import { AssessmentService } from '../../assessment/assessment.service';
 import { AssessmentCommandParser } from './assessment-command.parser';
 import { AssessmentCommandType } from '../dto/assessment-command.dto';
+import { i18nStore } from '../../i18n/i18n.store';
+import { DEFAULT_LANGUAGE } from '../../common/constants';
 
 @Injectable()
 export class FeishuAssessmentService {
@@ -137,12 +139,12 @@ export class FeishuAssessmentService {
     );
 
     try {
-      // 创建测评会话
+      const language = i18nStore.getStore()?.language || 'zh';
       const session = await this.assessmentService.startSession(
         bot.userId,
         knowledgeBaseId,
-        bot.user?.tenantId || 'default',
-        'zh',
+        bot.tenantId || 'default',
+        language,
         templateId,
       );
 
@@ -239,12 +241,12 @@ export class FeishuAssessmentService {
     );
 
     try {
-      // 提交答案到测评服务
+      const language = i18nStore.getStore()?.language || 'zh';
       const result = await this.assessmentService.submitAnswer(
         session.assessmentSessionId,
         bot.userId,
         answer,
-        'zh',
+        language,
       );
 
       this.logger.log(
@@ -443,7 +445,8 @@ export class FeishuAssessmentService {
    * 发送帮助信息
    */
   async sendHelp(bot: FeishuBot, openId: string): Promise<void> {
-    const helpText = this.commandParser.getHelpText('zh');
+    const language = i18nStore.getStore()?.language || 'zh';
+    const helpText = this.commandParser.getHelpText(language);
     await this.feishuService.sendTextMessage(bot, 'open_id', openId, helpText);
   }