import { adminCardInfoCurdOption } from '../../../src/modules/card/controller/admin/info'; import { adminCardCasesCurdOption } from '../../../src/modules/card/controller/admin/cases'; import { adminCardArticleCurdOption } from '../../../src/modules/card/controller/admin/article'; import { adminCardBentoCurdOption } from '../../../src/modules/card/controller/admin/bento'; import { adminCardLocaleCurdOption } from '../../../src/modules/card/controller/admin/locale'; import { AdminCrmLeadController } from '../../../src/modules/crm/controller/admin/lead'; import { AdminCrmRadarController } from '../../../src/modules/crm/controller/admin/radar'; import { adminNfcDeviceCurdOption } from '../../../src/modules/nfc/controller/admin/device'; import { adminNfcRuleCurdOption } from '../../../src/modules/nfc/controller/admin/rule'; import { adminAiKnowledgeCurdOption } from '../../../src/modules/ai/controller/admin/knowledge'; import { adminAiGlossaryCurdOption } from '../../../src/modules/ai/controller/admin/glossary'; import { adminAiConciergeCurdOption } from '../../../src/modules/ai/controller/admin/concierge'; import { adminTeamBrandCurdOption } from '../../../src/modules/team/controller/admin/brand'; import { adminTeamDomainCurdOption } from '../../../src/modules/team/controller/admin/domain'; import { BaseAuditLogController } from '../../../src/modules/base/controller/admin/audit'; import { AiConciergeService } from '../../../src/modules/ai/service/concierge'; import { getClassMetadata, CONTROLLER_KEY } from '@midwayjs/core'; describe('Admin Controllers & Services SQL Column Matching', () => { describe('1. Controller pageQueryOp SQL 列名必须与 MySQL 物理表字段一致', () => { it('Card Info pageQueryOp 应使用 update_time 与 theme_code', () => { expect(adminCardInfoCurdOption.pageQueryOp.addOrderBy).toEqual({ update_time: 'desc' }); expect(adminCardInfoCurdOption.pageQueryOp.fieldEq).toEqual( expect.arrayContaining(['a.status', { column: 'a.theme_code', requestParam: 'themeCode' }]) ); }); it('Card Cases pageQueryOp 应使用 sort_order 与 card_id', () => { expect(adminCardCasesCurdOption.pageQueryOp.addOrderBy).toEqual({ sort_order: 'asc' }); expect(adminCardCasesCurdOption.pageQueryOp.fieldEq).toEqual( expect.arrayContaining([{ column: 'a.card_id', requestParam: 'cardId' }]) ); }); it('Card Article pageQueryOp 应使用 update_time, card_id 与 is_published', () => { expect(adminCardArticleCurdOption.pageQueryOp.addOrderBy).toEqual({ update_time: 'desc' }); expect(adminCardArticleCurdOption.pageQueryOp.fieldEq).toEqual( expect.arrayContaining([ { column: 'a.card_id', requestParam: 'cardId' }, { column: 'a.is_published', requestParam: 'isPublished' }, ]) ); }); it('Card Bento pageQueryOp 应使用 sort_order 与 card_id', () => { expect(adminCardBentoCurdOption.pageQueryOp.addOrderBy).toEqual({ sort_order: 'asc' }); expect(adminCardBentoCurdOption.pageQueryOp.fieldEq).toEqual( expect.arrayContaining([{ column: 'a.card_id', requestParam: 'cardId' }, 'a.type', 'a.status']) ); }); it('Card Locale pageQueryOp 应使用 card_id', () => { expect(adminCardLocaleCurdOption.pageQueryOp.fieldEq).toEqual( expect.arrayContaining([{ column: 'a.card_id', requestParam: 'cardId' }, 'a.locale']) ); }); it('CRM Lead pageQueryOp 应使用 create_time 与 card_id', () => { const option = getClassMetadata(CONTROLLER_KEY, AdminCrmLeadController).curdOption; expect(option.pageQueryOp.addOrderBy).toEqual({ create_time: 'desc' }); expect(option.pageQueryOp.fieldEq).toEqual( expect.arrayContaining(['a.status', 'a.source', { column: 'a.card_id', requestParam: 'cardId' }]) ); }); it('CRM Radar pageQueryOp 应使用 visitor_id 与 card_id, touch_type', () => { const option = getClassMetadata(CONTROLLER_KEY, AdminCrmRadarController).curdOption; expect(option.pageQueryOp.keyWordLikeFields).toEqual( expect.arrayContaining(['a.country', 'a.city', 'a.visitor_id', 'a.ip']) ); expect(option.pageQueryOp.fieldEq).toEqual( expect.arrayContaining([ { column: 'a.card_id', requestParam: 'cardId' }, { column: 'a.touch_type', requestParam: 'touchType' }, 'a.country', ]) ); }); it('NFC Device pageQueryOp 应使用 update_time, batch_no, card_id, scene_mode', () => { expect(adminNfcDeviceCurdOption.pageQueryOp.addOrderBy).toEqual({ update_time: 'desc' }); expect(adminNfcDeviceCurdOption.pageQueryOp.keyWordLikeFields).toEqual( expect.arrayContaining(['a.uid', 'a.batch_no']) ); expect(adminNfcDeviceCurdOption.pageQueryOp.fieldEq).toEqual( expect.arrayContaining([ 'a.status', 'a.material', { column: 'a.card_id', requestParam: 'cardId' }, { column: 'a.scene_mode', requestParam: 'sceneMode' }, ]) ); }); it('NFC Rule pageQueryOp 应使用 update_time, device_id, scene_mode, country_code', () => { expect((adminNfcRuleCurdOption.pageQueryOp as any).addOrderBy).toEqual({ update_time: 'desc' }); expect((adminNfcRuleCurdOption.pageQueryOp as any).fieldEq).toEqual( expect.arrayContaining([ { column: 'a.device_id', requestParam: 'deviceId' }, 'a.enabled', { column: 'a.scene_mode', requestParam: 'sceneMode' }, { column: 'a.country_code', requestParam: 'countryCode' }, ]) ); }); it('AI Knowledge pageQueryOp 应使用 update_time 与 card_id', () => { expect(adminAiKnowledgeCurdOption.pageQueryOp.addOrderBy).toEqual({ update_time: 'desc' }); expect(adminAiKnowledgeCurdOption.pageQueryOp.fieldEq).toEqual( expect.arrayContaining([{ column: 'a.card_id', requestParam: 'cardId' }, 'a.locale']) ); }); it('AI Glossary pageQueryOp 应使用 update_time, source_term, target_term, source_lang, target_lang', () => { expect(adminAiGlossaryCurdOption.pageQueryOp.addOrderBy).toEqual({ update_time: 'desc' }); expect(adminAiGlossaryCurdOption.pageQueryOp.keyWordLikeFields).toEqual( expect.arrayContaining(['a.source_term', 'a.target_term', 'a.notes']) ); expect(adminAiGlossaryCurdOption.pageQueryOp.fieldEq).toEqual( expect.arrayContaining([ { column: 'a.source_lang', requestParam: 'sourceLang' }, { column: 'a.target_lang', requestParam: 'targetLang' }, 'a.domain', ]) ); }); it('AI Concierge pageQueryOp 应使用 update_time, card_id, persona_type, is_enabled', () => { expect((adminAiConciergeCurdOption.pageQueryOp as any).addOrderBy).toEqual({ update_time: 'desc' }); expect((adminAiConciergeCurdOption.pageQueryOp as any).fieldEq).toEqual( expect.arrayContaining([ { column: 'a.card_id', requestParam: 'cardId' }, { column: 'a.persona_type', requestParam: 'personaType' }, { column: 'a.is_enabled', requestParam: 'isEnabled' }, ]) ); }); it('Team Brand pageQueryOp 应使用 update_time 与 company_name', () => { expect(adminTeamBrandCurdOption.pageQueryOp.addOrderBy).toEqual({ update_time: 'desc' }); expect(adminTeamBrandCurdOption.pageQueryOp.keyWordLikeFields).toEqual( expect.arrayContaining(['a.company_name']) ); }); it('Team Domain pageQueryOp 应使用 update_time, custom_domain 与 ssl_status', () => { expect(adminTeamDomainCurdOption.pageQueryOp.addOrderBy).toEqual({ update_time: 'desc' }); expect(adminTeamDomainCurdOption.pageQueryOp.keyWordLikeFields).toEqual( expect.arrayContaining(['a.custom_domain']) ); expect(adminTeamDomainCurdOption.pageQueryOp.fieldEq).toEqual( expect.arrayContaining([{ column: 'a.ssl_status', requestParam: 'sslStatus' }]) ); }); it('Base Audit Log pageQueryOp 应使用 create_time 与 operator_name', () => { const option = getClassMetadata(CONTROLLER_KEY, BaseAuditLogController).curdOption; expect(option.pageQueryOp.addOrderBy).toEqual({ create_time: 'desc' }); expect(option.pageQueryOp.keyWordLikeFields).toEqual( expect.arrayContaining(['a.operator_name', 'a.action', 'a.module', 'a.ip']) ); }); }); describe('2. AiConciergeService 健壮入参处理 (防止 NaN 导致的 SQL 语法异常)', () => { let service: AiConciergeService; let mockFindOneBy: jest.Mock; beforeEach(() => { service = new AiConciergeService(); mockFindOneBy = jest.fn(); service.aiConciergeEntity = { findOneBy: mockFindOneBy, } as any; }); it('getByCardId 支持对象入参 { cardId: 1 } 并正确提取数值', async () => { mockFindOneBy.mockResolvedValueOnce({ id: 10, cardId: 1, personaType: 'trade_expert', welcomeMsg: 'Hello', }); const result = await service.getByCardId({ cardId: 1 } as any); expect(mockFindOneBy).toHaveBeenCalledWith({ cardId: 1 }); expect(result.cardId).toBe(1); }); it('getByCardId 遇非法 cardId 应降级返回默认预设,禁止传递 NaN 给数据库', async () => { const result = await service.getByCardId({ cardId: NaN } as any); expect(mockFindOneBy).not.toHaveBeenCalled(); expect(result.personaType).toBe('trade_expert'); expect(result.cardId).toBe(1); }); }); });