大屏 — 畜牧资源统计 — 技术方案
依据:同目录 大屏畜牧资源功能需求.md v1.4。核心总览取农村三资与畜牧产品产量;其余区块为 AI 诊断既有表。本模块为大屏只读看板;不统计移动端「畜牧资源」资讯视图 v_livestock_resource。
1. 技术架构
| 项 |
说明 |
| 后端 |
RuoYi v3.9.2(springboot2 分支):JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| 数据库 |
MySQL 5.7.39,InnoDB,utf8mb4 |
| 前端 |
ruoyi-screen 畜牧资源专题页(/livestock-resources);切换 statYear 拉取看板主数据(本期单接口) |
| 代码包 |
com.ruoyi.web.modules.screen(LivestockResourceScreenController / ILivestockResourceScreenService / vo / support) |
分层:Controller → ILivestockResourceScreenService(口径编排、statDate/statDateTime)→ LivestockResourceScreenMapper(只读 SQL)+ LivestockResourceScreenSupport(7 日/24 小时补点、分类归一、占比、分档、关键词)。
| 场景 |
行为 |
进入 / 切换 statYear |
调用 §3.1 |
| 数据权限 |
全县聚合;不按提问人/机构过滤 |
统计日 statDate |
复用 HomeScreenSupport.resolveStatDate(Y):Y=当前年 → 今日(Asia/Shanghai);历史年 → Y-12-31 |
统计时刻 statDateTime |
请求时 LocalDateTime.now(Asia/Shanghai);响应回显用 |
| 年内上界 |
会话 create_time;AI 消息 create_time ≤ statDate 23:59:59(当前年) |
| 「今日」四项 |
仅当 Y = 当前自然年时按 statDate 自然日统计;否则固定 0 |
| 用户结构 |
biz_consult_user 全表快照,不随 Y 变 |
| 7 日 / 分时 |
7 日以 statDate 滚动;分时为 距 statDateTime 最近 24 整点小时,与 Y 无关 |
| 已隐藏会话 |
不过滤 vet_visible(对齐功能需求 §2.18#2) |
| 性能 |
默认实时聚合;可选 §2.3 缓存表 |
依赖表(只读)
| 表 |
用途 |
biz_consult_session |
AI 会话数、用户去重、7 日/24 小时会话、分档分母 |
biz_consult_message |
提问量(AI 回复)、耗时、分类、状态、关键词语料 |
biz_consult_user |
新老用户结构 |
biz_rural_three_assets |
核心总览 + 农村三资区块:经营性/非经营性/固定资产 |
biz_livestock_product_output |
核心总览 + 产量月度趋势 |
biz_vaccination_data |
核心总览 + 疫苗接种区块 |
biz_three_assets_problem_report |
三资具体问题上报按等级 |
biz_medical_resource |
核心总览:兽医人数 |
biz_tech_service_personnel |
核心总览:科技特派员、农业事业单位 |
业务常量(与 ConsultSessionRules / AiConsultConstants 一致)
| 常量 |
值 |
consult_type AI 问诊 |
2 |
sender_role 提问人 / AI |
1 / 3 |
AI 消息 sender_user_id |
0 |
msg_type 文本 |
1 |
| 提问分类编码 |
1~4(养殖技巧/疾病诊疗/用药指导/设备操作) |
2. 数据库设计
2.1 本模块业务表
无新增业务台账表。 DDL:sql/biz_consult_session.sql、sql/biz_consult_message.sql、sql/biz_consult_user.sql。
当前问诊表无 del_flag;纳入条件为:consult_type=2 的会话及其消息。已隐藏(vet_visible=0)仍统计。
2.2 时间边界(公共参数)
记 statYear = Y,statDate、statDateTime 见 §1。
| 边界 |
表达式 |
| 年区间起 |
Y-01-01 00:00:00 |
年区间止(会话 create_time、AI 消息 create_time) |
statDate 23:59:59 |
| 统计日区间 |
statDate 00:00:00 ~ statDate 23:59:59 |
| 近 7 日 |
[statDate − 6 日 00:00:00, statDate 23:59:59] |
| 最近 24 小时 |
[floor(statDateTime 到整点) − 23 小时, floor(statDateTime 到整点) + 59 分 59 秒];SQL 按 DATE_FORMAT(create_time,'%Y%m%d%H') 分组 |
会话别名(下文):s = biz_consult_session,条件 s.consult_type = 2。
AI 消息别名:m_ai = biz_consult_message,m_ai.sender_role = 3 AND m_ai.sender_user_id = 0,且 EXISTS 关联 s.id = m_ai.session_id。
提问人消息别名:m_ask = biz_consult_message,m_ask.sender_role = 1,且关联 AI 会话 s。
2.3 可选表 biz_livestock_resource_screen_cache(性能优化)
非本期必建。
| 字段 |
类型 |
说明 |
id |
bigint(20) |
主键 |
stat_year |
int(11) |
统计年份 |
payload_json |
mediumtext |
§3.1 响应 JSON |
expire_time |
datetime |
过期时间 |
create_time |
datetime |
写入时间 |
索引:UNIQUE uk_stat_year (stat_year)。TTL 1~5 分钟。
2.4 查询口径(按表)
2.4.1 核心总览
| 指标 |
数据源与 SQL 要点 |
与 statYear |
| 经营性固定资产(万元) |
biz_rural_three_assets:SUM(operating_fixed_assets),全县各村 |
不随 Y 变 |
| 非经营性固定资产(万元) |
同上:SUM(non_operating_fixed_assets) |
不随 Y 变 |
| 肉产量(万吨) |
biz_livestock_product_output:所选年 最大 stat_month 全县 SUM(meat_output) |
随 Y |
| 奶产量(万吨) |
同上:SUM(milk_output) |
随 Y |
| 免疫率(%) |
biz_vaccination_data:所选年最大月 (SUM(实免)/SUM(应免))×100,2 位小数;应免和为 0 → 0.00 |
随 Y |
| 兽医(人) |
biz_medical_resource:resource_type='004001' 且 del_flag='0' 计数 |
不随 Y 变 |
| 科技特派员(人) |
biz_tech_service_personnel.envoy_total_count(单例 id=1) |
不随 Y 变 |
| 农业事业单位(人) |
同上 agri_total_count |
不随 Y 变 |
无填报月或无行时对应产量/免疫率为 0;固定资产/人员无行时为 0。
2.4.2 近 7 日活跃度
| 维度 |
SQL 要点 |
| 会话数/日 |
DATE(s.create_time) 分组,COUNT(s.id) |
| 提问量/日 |
DATE(m_ai.create_time) 分组,COUNT(m_ai.id) |
应用层:固定输出 7 个点(statDate−6 … statDate),缺日补 0。
2.4.3 用户结构 biz_consult_user
| 类型 |
条件 |
| 新用户 |
DATEDIFF(last_use_time, first_use_time) <= 180 |
| 老用户 |
> 180 |
COUNT(*) 各一类;占比 = 人数 / (新+老),不加 Y 条件。
2.4.4 提问分类 / 模型调用 / 热点榜(同源)
| 项 |
条件 |
| 统计行 |
m_ai(sender_role=3、sender_user_id=0),create_time ∈ 年区间 |
| 分类键 |
同会话内 send_time ≤ m_ai.send_time 的最近提问人消息 ai_category;空 → UNCAT |
| 条数 |
GROUP BY 分类键 COUNT(*);MAX(m_ai.create_time) 供热点二次排序 |
| 占比 |
分类 AI 回复条数 / 当年全部 AI 回复 × 100 |
| 热点 Top5 |
条数降序;同分按 lastEventTime 降序;取 5 |
2.4.5 分时使用热度(最近 24 小时)
| 维度 |
SQL 要点 |
| 会话 |
s.create_time ∈ 24h 窗口,GROUP BY DATE_FORMAT(create_time,'%Y%m%d%H') |
| 提问量 |
m_ai.create_time ∈ 24h 窗口,同上分组 |
应用层:固定 24 桶(锚点整点向前 23 小时);bucketStart=HH:mm;bucketDateTime=yyyy-MM-dd HH:mm;hourlyHeat.windowEnd = 锚点整点 yyyy-MM-dd HH:mm。
2.4.6 单次会话提问数量分布
子查询:按 session_id 统计年内 m_ai 条数 reply_cnt,再分档:
| 档位 code |
reply_cnt |
LIGHT |
1~2 |
NORMAL |
3~4 |
ACTIVE |
5~10 |
DEEP |
>10 |
COUNT(session_id) / 年内会话总数 → 占比;四档固定返回,无数据为 0。
2.4.7 会话状态分布
| 状态 |
条件 |
OK 正常应答 |
m_ai.cost_time IS NOT NULL(含 0) |
FAIL 调用失败 |
m_ai.cost_time IS NULL |
年内 COUNT(*) 及占比;两者之和 = 年内 AI 消息总数。
2.4.8 高频关键词
| 项 |
条件 |
| 语料 |
m_ask.msg_type = 1,m_ask.content 非空,m_ask.send_time ∈ 年区间 |
| 处理 |
LivestockResourceScreenSupport.extractTopKeywords(texts, 30):分词 + 停用词(application.yml 可配路径或内置短表) |
2.5 索引建议(既有表)
| 表 |
建议 |
biz_consult_session |
(consult_type, create_time)、(consult_type, update_time) |
biz_consult_message |
(session_id, sender_role, create_time)、(create_time, sender_role) |
2.6 Mapper 方法(建议)
| Mapper |
方法 |
说明 |
LivestockResourceScreenMapper |
selectOverview(...) |
总览 8 项(可拆 2~3 条 SQL) |
|
selectDailySessionCounts(start, end) |
7 日会话 |
|
selectDailyAiReplyCounts(start, end) |
7 日提问量 |
|
selectUserStructure() |
新老用户 |
|
selectAskerCategoryCounts(yearStart, yearEnd) |
AI 回复按分类键聚合 |
|
selectAiReplyTotal(yearStart, yearEnd) |
分类占比分母(年内 AI 回复总数) |
|
selectHourlySessionCounts(windowStart, windowEnd) |
最近 24h 会话 |
|
selectHourlyAiReplyCounts(windowStart, windowEnd) |
最近 24h 提问量 |
|
selectSessionReplyBuckets(yearStart, yearEnd) |
四档会话数 |
|
selectYearSessionTotal(yearStart, yearEnd) |
年内会话总数 |
|
selectAiReplyStatusCounts(yearStart, yearEnd) |
正常/失败 |
|
selectTextAskerContents(yearStart, yearEnd) |
关键词语料 |
|
selectDistinctSessionYears() |
可选年份下拉 |
XML:mapper/screen/LivestockResourceScreenMapper.xml。
3. 接口设计
统一响应:AjaxResult(code / msg / data)。
Base Path:/bigScreen/livestockResource
权限标识(示例):bigScreen:livestockResource:query
| # |
说明 |
Method |
URI |
| 3.1 |
看板主数据(十区块合一) |
GET |
/bigScreen/livestockResource/dashboard |
前端:进入页 / 切换 statYear / 刷新 → 仅 3.1。
3.1 看板主数据
Query
| 参数 |
类型 |
必填 |
说明 |
statYear |
string |
Y |
四位年份;非法 → 业务异常(AchievementReportValidation.parseStatYear) |
forceRefresh |
boolean |
N |
默认 false;true 时跳过 §2.3 缓存 |
响应 data(顶层)
| 字段 |
类型 |
说明 |
statYear |
int |
回显 |
statDate |
string |
yyyy-MM-dd |
statDateTime |
string |
yyyy-MM-dd HH:mm:ss,24h 窗口终点 |
availableYears |
int[] |
biz_consult_session 在 consult_type=2 下 YEAR(create_time) 并集 + 当前年,降序 |
overview |
object |
核心总览 §3.1.1 |
ruralThreeAssets |
object |
农村三资数据 |
problemReportShare |
object |
三资问题上报按等级 |
productOutputTrend |
object |
畜牧产品产量月度趋势 |
vaccinationOverview |
object |
疫苗接种免疫率 |
appointment |
object |
线下服务预约:三项台账人数/机构数(不随年);monthlyStacked 为所选年 1~最大月预约次数 |
techEnvoyStructure |
object |
科技特派员:党员/其他、男/女占比与人数 |
agriUnitStructure |
object |
农业事业单位:员级/初级/中级/高级/管理级人数 |
agriClassroom |
object |
农技课堂(自首页迁入) |
trainingTrend |
object |
实战培训报名:所选年 1~库中最大月;monthly[].statYear/month/activityCount/enrolledCount |
已屏蔽(不再返回): activityTrend、userStructure、categoryShare、modelCallAnalysis、hourlyHeat、sessionReplyDistribution、replyStatusDistribution、hotTopics、topKeywords。
3.1.1 overview
| 字段 |
类型 |
说明 |
operatingFixedAssets |
decimal |
经营性固定资产(万元),2 位小数 |
nonOperatingFixedAssets |
decimal |
非经营性固定资产(万元),2 位小数 |
meatOutput |
decimal |
肉产量(万吨),所选年最大填报月全县合计,4 位小数 |
milkOutput |
decimal |
奶产量(万吨),同上 |
immunityRate |
decimal |
免疫率(%),所选年最大填报月 (实免和/应免和)×100,2 位小数 |
vetCount |
long |
兽医人数(004001 且未删除) |
techEnvoyCount |
long |
科技特派员总人数 |
agriUnitCount |
long |
农业事业单位总人数 |
3.1.1a ruralThreeAssets
| 字段 |
类型 |
说明 |
operatingFixedAssets / nonOperatingFixedAssets / fixedAssets |
decimal |
全县合计(万元),2 位小数;不随年变 |
3.1.1b problemReportShare
| 字段 |
类型 |
说明 |
totalCount |
long |
所选年上报总次数 |
items[] |
array |
levelCode/levelName/count/ratio(一般/重点/重大) |
3.1.1c productOutputTrend
| 字段 |
类型 |
说明 |
maxMonth |
int|null |
所选年最大填报月 |
monthlySeries[] |
array |
1~N:month/meatOutput/milkOutput(万吨,4 位) |
3.1.1d vaccinationOverview
| 字段 |
类型 |
说明 |
statMonth |
int|null |
最大填报月 |
immunityRate |
decimal |
免疫率 %,2 位 |
shouldVaccinateCount / actualVaccinateCount |
long |
应免/实免合计 |
3.1.1e appointment
| 字段 |
类型 |
说明 |
annualVetCount |
int |
兽医人员数:biz_medical_resource resource_type=004001 且 del_flag=0;不随年变 |
annualExpertCount |
int |
专家人员数:biz_tech_resource resource_type=004005 且 del_flag=0;不随年变 |
annualOrgCount |
int |
诊疗机构数:biz_medical_resource resource_type=004003 且 del_flag=0;不随年变 |
monthlyStacked[] |
array |
所选年 1~最大月:statYear/month/vetCount/expertCount/orgCount(预约次数,排除 status 2/3) |
3.1.2 activityTrend
| 字段 |
类型 |
说明 |
dailySeries |
array |
固定 7 条 |
dailySeries[]:
| 字段 |
说明 |
date |
yyyy-MM-dd |
sessionCount |
会话数 |
questionCount |
提问量(AI 回复) |
3.1.3 userStructure
| 字段 |
类型 |
说明 |
newUserCount |
long |
新用户 |
oldUserCount |
long |
老用户 |
newUserRatio |
decimal |
占比 0~100 |
oldUserRatio |
decimal |
占比 0~100 |
3.1.4 categoryShare
| 字段 |
类型 |
说明 |
totalAskerMessages |
long |
分母:年内全部 AI 回复(字段名沿用,与提问人无关) |
items |
array |
分类项 |
items[]:categoryCode、categoryName、count、ratio(0~100,1 位小数)。固定含 1~4 + UNCAT(未分类),无数据 count=0。
3.1.5 modelCallAnalysis[]
与 categoryShare.items 同源(可复用引用):categoryCode、categoryName、count。展示为柱状图时前端取 count。
3.1.6 hourlyHeat
| 字段 |
类型 |
说明 |
windowEnd |
string |
锚点整点 yyyy-MM-dd HH:mm |
hourlySeries |
array |
固定 24 条 |
hourlySeries[]:bucketStart(HH:mm)、bucketDateTime(yyyy-MM-dd HH:mm,悬停)、sessionCount、questionCount。
3.1.7 sessionReplyDistribution[]
固定 4 条。
| 字段 |
说明 |
bandCode |
LIGHT / NORMAL / ACTIVE / DEEP |
bandName |
轻度 / 一般 / 活跃 / 深度 |
sessionCount |
会话数 |
ratio |
占年内会话总数 % |
3.1.8 replyStatusDistribution
| 字段 |
说明 |
totalAiReplies |
年内 AI 回复总数 |
items |
固定 2 条:OK(正常应答)、FAIL(调用失败),含 count、ratio |
3.1.9 hotTopics[]
最多 5 条:categoryCode、categoryName、count、ratio,按 ratio 或 count 降序。
3.1.10 topKeywords[]
最多 30 条:keyword、count。
响应示例(节选)
{
"statYear": 2026,
"statDate": "2026-05-20",
"statDateTime": "2026-05-20 15:30:00",
"overview": {
"operatingFixedAssets": 100.50,
"nonOperatingFixedAssets": 200.25,
"meatOutput": 1.2000,
"milkOutput": 3.4000,
"immunityRate": 90.00,
"vetCount": 15,
"techEnvoyCount": 30,
"agriUnitCount": 40
},
"activityTrend": {
"dailySeries": [
{ "date": "2026-05-14", "sessionCount": 3, "questionCount": 10 }
]
},
"categoryShare": {
"totalAskerMessages": 500,
"items": [
{ "categoryCode": "2", "categoryName": "疾病诊疗", "count": 200, "ratio": 40.0 }
]
}
}
服务端逻辑(摘要)
1. year = parseStatYear(statYear)
2. statDate = resolveStatDate(year); statDateTime = now(Shanghai)
3. yearStart/end, dayStart/end, sevenStart, window24Start = Support.bounds(...)
4. overview = 三资 SUM + 所选年产量最大月 SUM(meat/milk)
5. activityTrend = Mapper 7日 + buildDailySeries(7, statDate)
6. userStructure = Mapper 新老 + ratio
7. category = Mapper 分类 + total;categoryShare/modelCall/hotTopics = Support.buildCategoryViews(...)
8. hourlyHeat = Mapper 24h + buildHourlySeries(24, statDateTime)
9. sessionReplyDistribution = Mapper 分档 + ratio
10. replyStatusDistribution = Mapper OK/FAIL + ratio
11. topKeywords = Support.extractTopKeywords(Mapper 文本语料, 30)
12. availableYears = distinct session years ∪ current year
13. return AjaxResult.success(vo)
4. 菜单与权限(示例)
| 类型 |
名称 |
权限标识 |
| 菜单 |
大屏畜牧资源 |
bigScreen:livestockResource:query |
SQL 示例:sql/big_screen_livestock_resource_perm.sql(挂载「大屏」父菜单下)。
5. 交付清单
6. 修订记录
| 版本 |
日期 |
说明 |
| 1.11 |
2026-07-24 |
看板屏蔽 AI 问诊九区块:活跃度/用户结构/分类/模型调用/分时/会话分布/状态/热门/关键词 |
| 1.10 |
2026-07-24 |
线下服务预约三项汇总改为资源台账:兽医 004001、机构 004003、专家 004005 |
| 1.9 |
2026-07-24 |
线下服务预约月度改为所选年 1~最大月 |
| 1.8 |
2026-07-24 |
实战培训报名改为所选年 1~最大月;前端横轴仅月、悬停显年月 |
| 1.7 |
2026-07-24 |
迁入线下预约/农技课堂/实战培训;新增科技特派员双层结构、农业事业单位职级柱图 |
| 1.6 |
2026-07-24 |
新增农村三资/问题上报/产量趋势/疫苗接种四区块 |
| 1.5 |
2026-07-24 |
核心总览扩展为 8 项:增免疫率、兽医、科技特派员、农业事业单位 |
| 1.4 |
2026-07-24 |
核心总览改为三资固定资产 + 所选年最大月肉/奶产量 |
| 1.0 |
2026-05-20 |
初稿:无新表;单接口十区块;对齐 大屏畜牧资源功能需求.md v1.1 |
| 1.2 |
2026-05-20 |
对齐草稿:今日活跃 update_time、日新增双时间、AI 回复+分类归因、统计日 0~23 时分、create_time 消息归属 |