diff --git a/packages/services/conversation-service/src/adapters/inbound/admin-evaluation-rule.controller.ts b/packages/services/conversation-service/src/adapters/inbound/admin-evaluation-rule.controller.ts index 4c5ec61..bda9845 100644 --- a/packages/services/conversation-service/src/adapters/inbound/admin-evaluation-rule.controller.ts +++ b/packages/services/conversation-service/src/adapters/inbound/admin-evaluation-rule.controller.ts @@ -7,6 +7,9 @@ * 2. 开关规则 * 3. 测试规则(dry-run) * 4. 清除规则缓存 + * + * ⚠️ 路由顺序重要:静态路由(test, cache)必须在动态路由(:id)之前声明, + * 否则 NestJS 会把 "test"/"cache" 当作 :id 参数匹配。 */ import { @@ -71,6 +74,45 @@ export class AdminEvaluationRuleController { } } + // ─── 静态路由(必须在 :id 之前) ───────────────────────── + + // POST /conversations/admin/evaluation-rules/test + @Post('test') + async testEvaluation( + @Headers('authorization') auth: string, + @Body() dto: TestEvaluationDto, + ) { + const admin = this.verifyAdmin(auth); + const tenantId = admin.tenantId || null; + + if (!dto.stage || !dto.responseText) { + throw new BadRequestException('stage and responseText are required'); + } + + const result = await this.evaluationGate.evaluate(tenantId, { + stage: dto.stage, + collectedInfo: dto.collectedInfo || null, + assessmentResult: dto.assessmentResult || null, + responseText: dto.responseText, + turnCount: dto.turnCount || 1, + messageCount: dto.messageCount || 1, + hasConverted: false, + agentsUsed: [], + }); + + return { success: true, data: result }; + } + + // DELETE /conversations/admin/evaluation-rules/cache + @Delete('cache') + async clearCache(@Headers('authorization') auth: string) { + this.verifyAdmin(auth); + this.evaluationGate.clearCache(); + return { success: true, message: 'Cache cleared' }; + } + + // ─── 集合路由 ────────────────────────────────────────── + // GET /conversations/admin/evaluation-rules @Get() async listRules( @@ -97,22 +139,6 @@ export class AdminEvaluationRuleController { }; } - // GET /conversations/admin/evaluation-rules/:id - @Get(':id') - async getRule( - @Headers('authorization') auth: string, - @Param('id') id: string, - ) { - this.verifyAdmin(auth); - - const rule = await this.repo.findById(id); - if (!rule) { - return { success: false, error: 'Rule not found' }; - } - - return { success: true, data: this.toResponse(rule) }; - } - // POST /conversations/admin/evaluation-rules @Post() @HttpCode(HttpStatus.CREATED) @@ -156,6 +182,24 @@ export class AdminEvaluationRuleController { return { success: true, data: this.toResponse(saved) }; } + // ─── 动态路由(:id 在静态路由之后) ─────────────────────── + + // GET /conversations/admin/evaluation-rules/:id + @Get(':id') + async getRule( + @Headers('authorization') auth: string, + @Param('id') id: string, + ) { + this.verifyAdmin(auth); + + const rule = await this.repo.findById(id); + if (!rule) { + return { success: false, error: 'Rule not found' }; + } + + return { success: true, data: this.toResponse(rule) }; + } + // PUT /conversations/admin/evaluation-rules/:id @Put(':id') async updateRule( @@ -233,40 +277,7 @@ export class AdminEvaluationRuleController { return { success: true, data: this.toResponse(updated) }; } - // POST /conversations/admin/evaluation-rules/test - @Post('test') - async testEvaluation( - @Headers('authorization') auth: string, - @Body() dto: TestEvaluationDto, - ) { - const admin = this.verifyAdmin(auth); - const tenantId = admin.tenantId || null; - - if (!dto.stage || !dto.responseText) { - throw new BadRequestException('stage and responseText are required'); - } - - const result = await this.evaluationGate.evaluate(tenantId, { - stage: dto.stage, - collectedInfo: dto.collectedInfo || null, - assessmentResult: dto.assessmentResult || null, - responseText: dto.responseText, - turnCount: dto.turnCount || 1, - messageCount: dto.messageCount || 1, - hasConverted: false, - agentsUsed: [], - }); - - return { success: true, data: result }; - } - - // DELETE /conversations/admin/evaluation-rules/cache - @Delete('cache') - async clearCache(@Headers('authorization') auth: string) { - this.verifyAdmin(auth); - this.evaluationGate.clearCache(); - return { success: true, message: 'Cache cleared' }; - } + // ─── 私有方法 ───────────────────────────────────────── private toResponse(rule: EvaluationRuleEntity) { return { diff --git a/packages/services/conversation-service/src/conversation/conversation.module.ts b/packages/services/conversation-service/src/conversation/conversation.module.ts index d677f47..fce4a67 100644 --- a/packages/services/conversation-service/src/conversation/conversation.module.ts +++ b/packages/services/conversation-service/src/conversation/conversation.module.ts @@ -20,7 +20,7 @@ import { ConversationGateway } from '../adapters/inbound/conversation.gateway'; @Module({ imports: [TypeOrmModule.forFeature([ConversationORM, MessageORM, TokenUsageORM, AgentExecutionORM])], - controllers: [ConversationController, InternalConversationController, AdminConversationController, AdminMcpController, AdminEvaluationRuleController], + controllers: [ConversationController, InternalConversationController, AdminMcpController, AdminEvaluationRuleController, AdminConversationController], providers: [ ConversationService, ConversationGateway,