依据:
AI诊断(兽医、机构)功能需求.md(v1.1);关联在线接诊(兽医)技术方案.md(v1.1)、在线接诊(兽医)功能需求.md
本文档版本:1.6(biz_consult_user使用用户表,见 §3.0)
| 项 | 说明 |
|---|---|
| 整体 | RuoYi v3.9.2(springboot2 分支)单体后端 + 若依 Vue2 管理端 + 移动端 |
| 运行时 | JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| 数据库 | MySQL 5.7.39,InnoDB,utf8mb4 |
| 问诊 IM 表 | 复用 biz_consult_session、biz_consult_message(与在线接诊共用,见 §2);另增 biz_consult_user 记录提问人首次/末次使用时间(§3.0) |
| 近实时 | 复用 Redis Pub/Sub consult:push + STOMP(与在线接诊 §5.1 一致);提问落库即推;AI 回复落库后推,≤ 1 秒 |
| 文件 | POST /common/upload;消息存 URL |
| AI 能力(对话框) | 管理端/移动端 直连或经本服务转发 GET /v1/models、POST /v1/chat/completions(com.ruoyi.web.kb.controller.KbOpenAiProxyController,配置 ruoyi.kb);详见 doc/大模型/大模型网关转发接口说明.md、前端方案 §4 |
| AI 能力(服务端兜底) | ConsultAiGateway:仅当落库请求 未带 aiReplyContent 时由服务端调模型;超时 60s、非流式整段回复 |
| 后台准入 | 若依菜单 + diseaseTreatment:aiOnlineConsult:* 权限;不校验 biz_medical_resource 绑定 |
| 预约/接诊 | 不关联 biz_service_appointment、在线接诊接口 |
后端分层(AI 诊断)
| 层 | 职责 |
|---|---|
Controller |
后台 .../onlineConsult/ai;移动端 .../app/consult/ai |
Service |
列表/新建/消息/提问;调用 AI 生成回复;hide |
ConsultAiGateway |
文本/图片调用模型;视频/语音返回固定引导文案 |
Mapper + XML |
扩展 BizConsultSessionMapper(consult_type=2 查询);BizConsultUserMapper(§3.0) |
support |
复用 ConsultSessionRules、ConsultThreeMonthsWindow、ConsultMessagePreview、VetConsultValidation;新增 AiConsultValidation |
代码包:com.ruoyi.web.modules.diagnosis(与在线接诊、医疗资源同域)
大模型转发包:com.ruoyi.web.kb(与知识库共用 ruoyi.kb,见 §1.2)
DDL:sql/biz_consult_session.sql、sql/biz_consult_message.sql(会话/消息,与在线接诊共用);sql/biz_consult_user.sql(AI 诊断使用用户,§3.0)
/v1)与知识库同属大模型网关体系,实现类不在 diagnosis 包而在 kb 包:
| 对外路径 | 实现 | 用途 |
|---|---|---|
GET /v1/models |
KbOpenAiProxyController → KbOpenAiProxyServiceImpl |
模型列表(原样转发上游) |
POST /v1/chat/completions |
同上;stream:false JSON,stream:true SSE |
管理端 AI 诊断、移动端 AI 助手 对话框问答 |
| 项 | 说明 |
|---|---|
| 鉴权(本服务) | 须若依登录 Token(KbOpenAiProxyController 无 @Anonymous);未登录 401 |
| 鉴权(上游) | 服务端 ruoyi.kb.api-key 访问上游,不使用客户端 Authorization |
| 配置 | ruoyi.kb(scheme/host/port/api-key/stream-read-timeout-ms) |
| 与业务接口关系 | 会话 CRUD、消息落库仍走 .../onlineConsult/ai/**、.../app/consult/ai/**;前端大模型返回后 POST .../message 带 aiReplyContent,不再走 ConsultAiGateway |
| 设计/测试 | doc/大模型/大模型网关转发接口说明.md、doc/大模型/大模型网关转发测试用例.md |
consult_type 隔离)consult_type |
模块 | receiver_provider_id |
vet_visible 语义(本期) |
|---|---|---|---|
1 |
在线接诊(兽医) | 兽医 biz_medical_resource.id |
牧民删除后对兽医不可见 |
2 |
AI 诊断 | 必须为 NULL | 复用字段:提问人删除后对本人列表不可见(0) |
3 |
专家问诊(预留) | 专家资源 ID | 待定 |
禁止:AI 列表/消息 SQL 出现 consult_type=1;接诊 SQL 出现 consult_type=2。
| 能力 | 在线接诊(兽医) | AI 诊断(本文档) |
|---|---|---|
| Base Path | /diseaseTreatment/onlineConsult/vet |
/diseaseTreatment/onlineConsult/ai |
| 角色 | 兽医(100) | 兽医(100)+ 机构(102 等) |
| 列表筛选 | askerName、contentKeyword |
contentKeyword 仅 |
| 新建会话 | 无 | POST /session |
| 发送 | 人 → 人 | 人 → AI 服务 → AI 消息入库 |
| 列表标题字段 | askerName |
sessionTitle |
| 移动端 Path | /app/onlineConsult |
/app/consult/ai |
提问/AI 回复落库 → 更新 last_message_*
→ Redis consult:push
→ STOMP /topic/consult/ai/{askerUserId}
Payload 同在线接诊 §4.2(senderRole:1 提问人,3 AI 助手)。
| 复用项 | 说明 |
|---|---|
biz_consult_* 表 |
同表异 consult_type |
ConsultMessagePreview |
摘要 50 字 / [图片] 等 |
ConsultThreeMonthsWindow |
3 个月自然日 |
ConsultRedisPushService |
推送 |
BizConsultMessageMapper |
消息插入、分页查询 |
VetConsultValidation.validateSendBody |
发送体校验(AI 模块复用) |
独立实现:BizAiOnlineConsultServiceImpl、BizAiOnlineConsultController、ConsultAiGateway、selectAiSessionList 等 Mapper 方法。
无表关联、无接口校验。
会话/消息在共用表上按 consult_type=2 读写;另增 AI 诊断使用用户 表记录提问人首次/末次使用时间。
biz_consult_user(AI 诊断使用用户)| 字段 | 类型 | 说明 |
|---|---|---|
user_id |
bigint(20) |
主键;与提问人 asker_user_id 一致 |
first_use_time |
datetime |
开始使用 AI 诊断时间 |
last_use_time |
datetime |
最后一次使用 AI 诊断时间 |
写入规则
| 时机 | 行为 |
|---|---|
POST .../session 新建会话 |
若 user_id 不存在则 INSERT,first_use_time、last_use_time 均为当前时间 |
更新 biz_consult_session.last_message_time |
同步 UPDATE 对应 asker_user_id 的 last_use_time(与 last_message_time 一致) |
DDL:sql/biz_consult_user.sql。
biz_consult_session(AI 会话写入约定)| 字段 | AI 会话取值 |
|---|---|
consult_type |
2 |
asker_user_id / asker_name |
当前登录用户 |
receiver_user_id |
NULL |
receiver_provider_id |
NULL(禁止写入兽医/机构资源 ID) |
receiver_name |
NULL |
session_title |
新建时 「新会话」;首条有效文本提问后更新为摘要(≤50 字) |
real_session_id |
varchar(64),可为空;大模型网关 session_id,由 POST .../message 写入/更新,供多轮 session_id 回传 |
last_message_time / last_message_preview |
每次提问或 AI 回复后更新 |
vet_visible |
默认 1;提问人 hide 后置 0 |
索引使用:idx_asker (consult_type, asker_user_id, last_message_time)。
多会话:同一 asker_user_id 可有多行 consult_type=2(不使用 uk_vet_session 限制 AI;该唯一键仅对 receiver_provider_id 非空的兽医会话生效)。
biz_consult_messagesender_role |
含义 |
|---|---|
| 1 | 提问人(兽医/机构/牧民) |
| 3 | AI 助手(sender_user_id=0,sender_name=AI助手) |
在线接诊使用的 2(接诊兽医)在 AI 会话中不出现。
| 字段 | 说明 |
|---|---|
ai_category |
varchar(32),可为空;仅 提问人消息(sender_role=1)写入;AI 回复为 NULL。纯数字时须为 1~4(与 AiConsultConstants 分类一致),亦可存业务编码字符串 |
cost_time |
bigint,可为空;大模型对话耗时(毫秒),仅 AI 消息(sender_role=3)写入;来自 /v1/chat/completions 响应头 X-COST |
asker_ip |
varchar(128),可为空;提问人所属 IP,仅 AI 诊断提问人消息(sender_role=1)写入;由 IpUtils.getIpAddr() 从当前 HTTP 请求解析 |
| 项 | 说明 |
|---|---|
| Quartz | aiConsultDiseaseWarningTask.scanAndWarn;cron 建议 0 0/30 * * * ?(每 30 分钟);SQL 见 sql/biz_sys_job_ai_consult_disease_warning.sql |
| 统计 | 当月(Asia/Shanghai,send_time 从月初至当前)biz_consult_message ⋈ biz_consult_session(consult_type=2),条件:sender_role<>3、sender_user_id<>0、ai_category=yak-disease(固定),按 asker_ip 计数 |
| 阈值 | diagnosis.ai-consult-disease-warning.threshold(默认 3) |
| 地区 | 对达阈值 IP 调用太平洋 IP 库解析区县,展示为 pasture_name(如「巴青区」) |
| 落库 | biz_yak_disease_warning:warning_type=5,data_source=ai_consult_analysis;同月同 pasture_name 已存在则 更新 alert_message/alert_time,否则 插入 |
| 文案 | {区名}本月截止当前时间AI问诊记录集中({N}条),触发疫病预警。 |
已有库迁移:sql/biz_consult_user.sql(或 sql/alter_rename_biz_diagnosis_user_to_biz_consult_user.sql);sql/alter_biz_consult_session_real_session_id.sql、sql/alter_biz_consult_message_ai_category.sql、sql/alter_biz_consult_message_cost_time.sql、sql/alter_biz_consult_message_asker_ip.sql。
默认列表(searchMode=false):
-- 时间字段见 §3.5 推荐 SQL(COALESCE 或创建时写入 last_message_time)
WHERE consult_type = 2
AND asker_user_id = #{askerUserId}
AND vet_visible = 1
AND COALESCE(last_message_time, create_time) >= #{threeMonthsAgo}
ORDER BY COALESCE(last_message_time, create_time) DESC
搜索(searchMode=true):
vet_visible = 1;不限制 3 个月。contentKeyword 非空时匹配 session_title、last_message_preview、消息文本子查询(含 AI 回复文本)。| # | 约定项 | 实现要点 |
|---|---|---|
| 1 | 3 个月窗 | ConsultThreeMonthsWindow.calcThreeMonthsAgo(),Asia/Shanghai |
| 2 | 搜索/重置 | 仅 searchMode=true 超窗;空关键字 →「请输入筛选条件」 |
| 3 | 摘要 | ConsultMessagePreview.build |
| 4 | 首问标题 | 首条 msg_type=1 提问成功后 update session_title |
| 5 | 消息分页 | 未传 beforeId 取最新 50 条,响应升序 |
| 6 | 隐藏 | updateSessionVisible → vet_visible=0;管理端/移动端 POST .../hide,仅 asker_user_id=当前用户 |
| 7 | AI 超时 | ConsultAiGateway 调用 60s 超时,失败不插入 AI 消息 |
| 8 | 非流式 | 模型返回整段文本后一次 insert + 推送 |
| # | 约定项 | 本期实现 |
|---|---|---|
| 1 | 空会话进列表 | POST /session 创建时同步写入 last_message_time = create_time(或列表 SQL 使用 COALESCE(last_message_time, create_time) 参与 3 个月过滤与排序),保证「新会话」立即出现在默认列表 |
| 2 | HTTP 读超时 | POST .../message 同步等待 AI 最长 60s;Tomcat/网关 read timeout ≥ 65s,避免先于 AI 调用返回 504 |
| 3 | 视频/语音固定回复 | ConsultAiGateway 常量文案(写入 AI 消息):已收到视频,请补充文字描述症状。 / 已收到语音,请补充文字描述。 |
| 4 | 图片识图失败 | 模型不可用或识图失败时,仍插入一条 AI 文本消息(sender_role=3),内容为:图片识别暂不可用,请补充文字描述症状。;不仅返回 HTTP 错误而无 AI 气泡 |
| 5 | 移动端搜索 | GET /app/consult/ai/session/list 支持与后台相同参数:contentKeyword、searchMode(规则同 §3.3) |
| 6 | AI 上下文 | 本期 单轮:每次仅将当前提问(文本或图片 URL + 可选说明)送模型;不带历史多轮上下文(多轮对话产品化另迭代) |
| 7 | 同会话并发 | 同一会话在 AI 处理中(服务端标记或分布式锁)拒绝第二次 POST .../message,返回「AI 正在回复中,请稍候」 |
| 8 | 免责声明 | POST /session 与首次 GET /session/list 响应附带字段 disclaimer(常量,与功能需求 §5.4 #6 一致);前端必须展示 |
| 9 | vet_visible 口径 |
以本文档 §2.1 为准:AI 会话复用该字段表示提问人列表可见;在线接诊技术方案中「AI 不适用」表述作废 |
列表 SQL 推荐(含空会话):
WHERE consult_type = 2
AND asker_user_id = #{askerUserId}
AND vet_visible = 1
AND COALESCE(last_message_time, create_time) >= #{threeMonthsAgo}
ORDER BY COALESCE(last_message_time, create_time) DESC
统一响应:AjaxResult / TableDataInfo。
权限(示例):diseaseTreatment:aiOnlineConsult:list|query|send|add|remove
Base Path:/diseaseTreatment/onlineConsult/ai
准入:登录 + 接口权限;列表/新建按 asker_user_id = 当前用户 隔离,不调用 VetProviderResolver / OrgProviderResolver 校验医疗资源绑定。
| # | 说明 | Method | URI | 权限 | 要点 |
| --- | --- | --- | --- | --- |
| 4.1 | 历史会话列表 | GET | /session/list | ...:list | Query:pageNum、pageSize(默认 20)、contentKeyword、searchMode;asker_user_id 服务端注入 |
| 4.2 | 新增会话 | POST | /session | ...:add | 创建 consult_type=2 空会话;session_title=新会话;last_message_time=create_time(§3.5 #1);返回 sessionId、disclaimer |
| 4.3 | 历史消息 | GET | /session/{sessionId}/messages | ...:query | 校验 consult_type=2 + asker_user_id + vet_visible=1;beforeId、pageSize(默认 50) |
| 4.4 | 提问(触发 AI) | POST | /session/{sessionId}/message | ...:send | Body:msgType、content、mediaDuration?、aiReplyContent?、realSessionId?、aiCategory?、costTime?(毫秒,来自 X-COST);落库时更新 last_message_* 与 update_time;流程见 §5 |
| 4.5 | 隐藏会话 | POST | /session/{sessionId}/hide | ...:remove | 管理端隐藏 AI 诊断会话;vet_visible=0;仅本人会话;隐藏后列表/消息/提问不可用 |
rows[] 字段sessionId、sessionTitle、lastMessagePreview、lastMessageTime、realSessionId(大模型网关会话 ID,可为空)。
rows[] / 推送字段messageId、sessionId、senderRole(1 提问人 / 3 AI)、senderName、msgType、content、mediaDuration、aiCategory(可为空)、askerIp(可为空,仅提问人消息)、sendTime。
服务端调 ConsultAiGateway(无 aiReplyContent)
{
"msgType": 1,
"content": "牛不吃草、精神沉郁,请问可能原因?"
}
前端大模型直连后落库(推荐)
{
"msgType": 1,
"content": "牛不吃草、精神沉郁,请问可能原因?",
"aiReplyContent": "可能原因包括…",
"realSessionId": "gateway-session-001",
"aiCategory": "2",
"costTime": 1523
}
| Body 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
msgType |
int | Y | 1 文本 2 图 3 视频 4 语音 |
content |
string | 条件 | 文本或媒体 URL |
mediaDuration |
int | N | 音视频秒数 |
aiReplyContent |
string | N | 非空时服务端仅落库,不调 ConsultAiGateway |
realSessionId |
string | N | 大模型 session_id;写入 biz_consult_session.real_session_id(别名 real_session_id、session_id、llmSessionId) |
aiCategory |
string | N | 写入提问人消息 ai_category(别名 ai_category、category);最长 32 |
costTime |
long | N | 写入 AI 消息 cost_time(别名 cost_time、xCost);毫秒,来自大模型响应头 X-COST |
提问成功 data
{
"userMessage": { "id": 1, "senderRole": 1, "aiCategory": "2", "...": "..." },
"aiMessage": { "id": 2, "senderRole": 3, "...": "..." },
"realSessionId": "gateway-session-001"
}
msg 示例)| 场景 | 文案 |
|---|---|
| 越权会话 | 无权查看该会话 |
| 会话不可见 | 会话不存在或已删除 |
| 搜索为空 | 请输入筛选条件 |
| 文本为空 | 请输入消息内容 |
| 媒体为空 | 请上传文件 |
| 文件不合规 | 文件格式或大小不符合要求 |
| AI 超时 | AI 回复超时,请稍后重试 |
| AI 失败 | AI 回复失败,请稍后重试 |
| AI 处理中 | AI 正在回复中,请稍候 |
| AI 提问分类无效 | AI提问分类无效 / AI提问分类长度不能超过32个字符 |
1. 校验会话归属(type=2, asker=当前用户, vet_visible=1)
2. 若会话 AI 处理中 → 拒绝(§3.5 #7)
3. 校验 Body(VetConsultValidation、AiConsultValidation.validateAiCategory)
4. 若 Body.realSessionId 非空 → 更新 biz_consult_session.real_session_id
5. 标记会话 processing=1(内存/Redis 锁)
6. INSERT 提问消息(sender_role=1,含 ai_category 若有)
7. 更新 session.last_message_*(提问侧摘要)
8. 推送 NEW_MESSAGE(提问)→ 前端立即展示
9a. 若 aiReplyContent 非空:直接作为 AI 文本,跳过 ConsultAiGateway(前端直连大模型落库通道)
9b. 否则调用 ConsultAiGateway(≤60s,单轮 §3.5 #6):
- msg_type=1:文本问答
- msg_type=2:图文;失败 → §3.5 #4 固定 AI 文案仍入库
- msg_type=3/4:§3.5 #3 固定引导文案入库
10. 成功:INSERT AI 消息(sender_role=3,ai_category=NULL)
11. 更新 session.last_message_*;首问更新 session_title
12. 推送 NEW_MESSAGE(AI 回复,落库后 ≤1s)
13. 释放 processing;响应 data:{ userMessage, aiMessage, realSessionId? }
14. 网关硬失败(非图片软失败且无 aiReplyContent):不写 AI 消息;HTTP 错误 + §4.4 文案
| 项 | 约定 |
|---|---|
| HTTP | POST .../message 同步阻塞等待 AI,最长 60s;读超时 ≥65s(§3.5 #2) |
| 响应体 | 成功时返回 userMessage + aiMessage;前端发送后即可展示提问,等待态文案「AI 正在思考…」 |
| 推送 | AI 消息落库后 ≤1s 经 /topic/consult/ai/{userId} 推送(与 HTTP 响应双通道,以先到者刷新为准) |
| 非流式 | 不做 SSE/逐字;整段 content 一次入库(§3.5 #6、功能需求 §5.4 #10) |
| 免责声明 | disclaimer 由 POST /session、GET /session/list 返回,前端必须展示(§3.5 #8) |
Base Path:/app/consult/ai
鉴权:登录 Token;不要求绑定医疗资源(牧民可用)。
| # | 说明 | Method | URI | 要点 |
|---|---|---|---|---|
| M1 | 新建会话 | POST | /session |
Body 可选 category:1~4;返回 sessionId、promptTemplate、disclaimer;last_message_time=create_time |
| M2 | 会话列表 | GET | /session/list |
asker_user_id=当前用户;contentKeyword、searchMode(§3.5 #5);分页;默认 3 个月 |
| M3 | 历史消息 | GET | /session/{id}/messages |
同 4.3 |
| M4 | 提问 | POST | /session/{id}/message |
同 4.4 |
| M5 | 隐藏会话 | POST | /session/{id}/hide |
vet_visible=0;管理端列表同步不展示 |
快捷入口(§5.4 #4):M1 + category → 新建会话(不复用当前会话)+ 返回模板字符串,由客户端填入输入框。
模板示例(服务端常量)
| category | 预填模板(示例) |
|---|---|
| 1 | 想了解一些养殖技巧,我的情况是: |
| 2 | 想咨询疾病诊疗问题,症状描述: |
| 3 | 想了解用药指导,具体情况: |
| 4 | 想咨询设备操作问题,设备/现象: |
与在线接诊技术方案 §5.1、§5.2 一致;订阅主题为 /topic/consult/ai/{userId}。
| 菜单名 | 权限标识 | 路由 component |
|---|---|---|
| AI 诊断(兽医、机构) | diseaseTreatment:aiOnlineConsult:list |
diseaseTreatment/onlineConsult/ai/index |
按钮:query、send、add(新建会话)、remove(隐藏会话)。角色 100、102(机构,以平台为准)。权限 SQL:sql/biz_ai_online_consult_remove_perm.sql。
| 项 | 说明 |
|---|---|
| 越权 | sessionId 操作必须 consult_type=2 且 asker_user_id=当前用户 |
| AI 会话创建 | receiver_* 全 NULL;insert 后 session_title=新会话 |
| 后台准入 | 权限注解;无医疗资源绑定校验 |
| 与接诊隔离 | Mapper 方法命名区分 selectAi* / selectVet* |
| 配置项 | application.yml:consult.ai.endpoint、apiKey、timeoutMs=60000(示例键名) |
建议新增类
AiConsultValidation(搜索空条件等)ConsultAiGateway / ConsultAiGatewayImplIBizAiOnlineConsultService / BizAiOnlineConsultServiceImplBizAiOnlineConsultControllerBizAppAiConsultControllerBizConsultSessionMapper.selectAiSessionList / insertAiSession / selectAiSessionByIdAndAsker(XML 补充)可继续复用在线接诊已实现的
ConsultSessionRules、ConsultRedisPushService、BizConsultMessageMapper| 编号 | 场景 | 通过标准 |
|---|---|---|
| AI-01 | 新建会话 | 后台 POST /session 返回新 sessionId;列表出现「新会话」 |
| AI-02 | 提问与回复 | 发送文本后 ≤60s 内返回 AI 消息;落库后 ≤1s 界面可见 |
| AI-03 | 默认/搜索 | 同在线接诊 AC-02、AC-03(consult_type=2) |
| AI-04 | 隐藏 | 移动端/管理端 hide 后列表无该会话 |
| AI-05 | 隔离 | 接诊列表无 AI 会话;AI 列表无接诊会话 |
| AI-06 | 机构/兽医 | 具备权限即可 list/create,不要求绑定医疗资源 |
| AI-07 | 视频/语音 | 上传后 AI 回复为引导补文字文案,非解析内容 |
| AI-08 | 快捷入口 | 点「疾病诊疗」等 → 新会话 + 预填模板 |
| AI-09 | 空会话列表 | POST /session 后未提问,左侧仍可见「新会话」 |
| AI-10 | 处理中拒发 | AI 未返回前再次发送 →「AI 正在回复中,请稍候」 |
| AI-11 | 图片失败 | 识图失败仍有 AI 引导气泡(§3.5 #4) |
selectAiSessionList 等(consult_type=2)ConsultAiGateway + 配置BizAiOnlineConsultServiceImpl + 后台 ControllerBizAppAiConsultController(M1~M5)| 版本 | 说明 |
|---|---|
| 1.0 | 初稿:共用 bizconsult*;consult_type=2;后台/移动端接口;AI 回复流程与 60s 超时;关联在线接诊 v1.1;vet_visible 复用为列表可见 |
| 1.1 | 评审补充:§3.5 空会话列表、HTTP 超时、固定文案、图片软失败、移动端搜索、单轮上下文、处理中拒发、免责声明必返;§5.1 双通道;验收 AI-09~11 |
| 1.2 | 补充 §1.2:KbOpenAiProxyController 转发 /v1/models、/v1/chat/completions;区分对话框直连/转发与 ConsultAiGateway 兜底 |
| 1.3 | §1.2:/v1/** 须若依 Token,取消匿名访问 |
| 1.4 | 管理端 §4.5 POST /session/{id}/hide 隐藏 AI 诊断会话;权限 ...:remove |
| 1.5 | §3.1 biz_consult_session.real_session_id;§3.2 biz_consult_message.ai_category(varchar32);§4.3 落库 Body/响应字段;§5 前端 aiReplyContent 落库通道 |
| 1.6 | §3.0 biz_consult_user(原 biz_diagnosis_user):新建会话写入首次用户、更新 last_message_time 同步 last_use_time |
| 1.7 | 表名统一为 biz_consult_user;Java BizConsultUser / BizConsultUserMapper |