Imported from zsc79/water_show (
AGENTS.md). Install upstream withnpx skills add zsc79/water_show. Copyright stays with the author.
AGENTS.md
本文件是本仓库后续开发、改造、排障时必须遵循的项目级规范。所有自动化代理和开发者在修改代码前,应先阅读本文件;业务生成或实现细节与本文件冲突时,以本文件为准。
项目概况
- 项目基于若依前后端分离框架 RuoYi-Vue,后端为 Spring Boot 多 Maven 模块,前端为 Vue 2 + Element UI 管理后台。
- 根 Maven 工程版本为
3.9.2,Java 版本为17。 - 后端模块:
ruoyi-admin:启动入口与 Web 入口。ruoyi-common:通用工具、注解、基础实体。ruoyi-framework:安全、配置、框架能力。ruoyi-system:系统、用户、角色、菜单、字典等若依原生模块。ruoyi-quartz:定时任务。ruoyi-generator:代码生成。ruoyi-water-data:水务数据与展示业务模块。
- 前端模块为
ruoyi-ui,使用若依原有 Vue 管理后台结构。 ruoyi-water-data内除水务业务外,还包含:com.ruoyi.watershow:水厂总览、运行时序、地图、五厂示范区、流量展示、二维工艺流程与活动动态等大屏接口。com.ruoyi.ai:AI 助手、知识库文档解析、向量索引与 RAG 检索。
python-services为独立 FastAPI 流量分析/预测服务,由 Java 后端代理调用;前端不直接访问该服务。- 根目录
docker-compose.yml提供 MySQL、Redis、Java 后端、Python 服务和 Nginx 前端的本地容器化部署。
基本原则
- 不重写若依已有的登录、认证、权限、角色、菜单、字典、分页、日志、导入导出机制。
- 新增功能必须接入若依原生权限体系、菜单体系、字典体系和日志体系。
- Controller、Service、Mapper、XML、实体类、前端 API、Vue 页面必须沿用项目已有命名、包路径、返回结构和交互风格。
- 不生成脱离若依体系的独立写法;优先参考同模块中已有实现。
- 修改前先检索相关代码,确认现有模式;不要凭空新增不一致的抽象。
- 不回滚或覆盖用户已有改动;只处理当前任务范围内文件。
后端开发规范
包路径与分层
- 水务数据业务优先放在
ruoyi-water-data/src/main/java/com/ruoyi/waterdata。 - 水务展示/大屏类能力优先放在
ruoyi-water-data/src/main/java/com/ruoyi/watershow。 - AI 助手与知识库能力放在
ruoyi-water-data/src/main/java/com/ruoyi/ai,不得散落到waterdata或watershow包。 - Mapper XML 放在
ruoyi-water-data/src/main/resources/mapper/waterdata、mapper/watershow、mapper/ai或对应业务目录。 - 按若依分层组织:
domainmapperserviceservice/implweb/controller
Controller
- Controller 必须继承
BaseController。 - 核心接口必须使用
@PreAuthorize("@ss.hasPermi('权限标识')")。 - 权限标识统一为
模块:业务对象:操作,例如water:device:list。 - 常用操作:
list:列表查询query:详情查询add:新增edit:修改remove:删除export:导出
- 新增、修改、删除、导出接口必须加
@Log注解。 - 列表接口使用
startPage()和getDataTable(list)。 - 返回结果使用
AjaxResult。 - 新增、修改、删除使用
toAjax()。 - 导出使用
ExcelUtil。 - 删除接口支持批量删除。
- 典型路由约定:
- 列表:
@GetMapping("/list") - 详情:
@GetMapping("/{id}") - 新增:
@PostMapping - 修改:
@PutMapping - 删除:
@DeleteMapping("/{ids}") - 导出:
@PostMapping("/export")
- 列表:
Service 与数据一致性
- 本项目数据库表不依赖物理外键,不能因此忽略业务关联。
- 关联字段如
tenant_id、area_id、water_plant_id、user_id、dept_id、customer_id、device_id、pipeline_id等,必须在 Service 层做存在性与业务归属校验。 - 删除主表数据前必须检查是否存在子表或业务引用。
- 存在关联数据时必须阻止删除,并返回明确错误信息。
- 禁止依赖数据库外键级联删除;数据一致性由代码保证。
- 必须包含必要参数校验,避免空指针。
- 信息不足时,先说明缺失信息,并基于合理假设实现可修改版本;不要写伪代码或省略关键逻辑。
数据权限
- 涉及
create_by、dept_id、user_id、area_id、tenant_id、water_plant_id等隔离字段时,必须考虑若依数据权限。 - 涉及部门、用户隔离的数据查询,优先参考现有模块使用
@DataScope等若依原生机制。 - 不自行实现一套角色判断;不同角色可见数据应优先通过若依角色、菜单、数据权限机制实现。
AI 助手与知识库
- AI 前端位于
ruoyi-ui/src/views/ai、API 位于ruoyi-ui/src/api/ai;后端统一通过com.ruoyi.ai调用模型服务,禁止前端直接携带模型密钥请求第三方接口。 - 百炼/OpenAI 兼容接口密钥使用环境变量
OPENAI_API_KEY;Docker 环境通过忽略文件.env.docker中的APP_OPENAI_API_KEY注入。真实密钥禁止写入application.yml、.env.docker.example、前端环境文件或测试代码。 - 知识库表结构与菜单初始化参考
sql/ai_knowledge.sql;Controller 权限继续使用ai:knowledge:list/query/add/edit/remove,上传、重建索引、删除必须保留日志审计。 - 当前知识库支持 PDF、DOCX、MD、TXT;扫描版或加密 PDF 暂不支持。扩展格式时应同步修改解析器、文件校验、前端提示和测试。
- RAG 参数统一从
ai.rag和ai.bailian配置读取;不要在 Service 中重复硬编码分块大小、重叠量、召回数、阈值、模型名或向量维度。 - 知识库索引包含文件落盘、文本解析、分块、向量生成和数据库持久化。修改流程时必须考虑失败状态、重复内容、重新索引、原文件缺失和文档删除后的文件清理。
- AI 回答应明确区分知识库依据与通用模型回答;涉及设备参数、操作规程和维修步骤时,不得伪造知识库中不存在的结论。
前端开发规范
- 前端代码位于
ruoyi-ui。 - API 文件放在
ruoyi-ui/src/api/...,页面放在ruoyi-ui/src/views/...。 - 使用若依已有
request封装、权限指令、分页参数、导出下载方式和表单模式。 - 按钮显示必须使用
v-hasPermi,并与后端权限标识一一对应。 - 不能只做前端权限控制;后端接口必须同步校验权限。
- 页面结构、按钮、查询区、表格、弹窗、分页、导入导出交互优先参考同目录已有页面。
- 使用 Element UI 与 Vue 2 Options API 风格,避免引入新的前端框架范式。
水务展示、大屏与地图
- 水务展示页面放在
ruoyi-ui/src/views/water/show,统一通过ruoyi-ui/src/api/water/show.js调用/water/show/**后端接口;可复用样式优先维护在同目录共享样式文件中。 water/show下的总览、地图、趋势和场景页属于只读展示,不强制套用业务 CRUD 页的左侧区域树,但必须保留租户、水厂或展示场景上下文,不能越权展示其他租户数据。- 水厂运行接口存在历史数据与模拟数据两种模式。前端和文档必须明确标识模拟数据,禁止把模拟刷新描述为真实设备实时采集。
- ECharts、轮询定时器、窗口事件和第三方地图实例必须在
beforeDestroy/deactivated中正确停止或释放,并在activated时按需恢复,避免 keep-alive 页面重复请求和内存泄漏。 - 高德地图统一通过
ruoyi-ui/src/utils/amap.js加载,不要在页面重复插入 SDK。Web Key 使用VUE_APP_AMAP_KEY;安全密钥只放在被忽略的本地环境文件或通过生产 Nginx/_AMapService代理注入。 - 王家坪地图当前使用独立展示地址与兜底中心点,不应擅自改为读取业务表中的不完整经纬度;调整定位策略前先参考
docs/wangjiaping-plant-map.md。
五厂联动示范区
- 示范区页面固定为
ruoyi-ui/src/views/water/show/demonstration/index.vue,后端只读入口为GET /water/show/demonstration,权限为water:show:demonstration。 - 五厂基础档案必须读取
water_plant_base,不得新增展示专用水厂表或在页面硬编码一套脱离水厂管理的数据。种子与修复脚本统一维护在sql/water_demonstration_area.sql。 - 示范区识别目录固定采用“行政区编号 + 水厂名称”:长寿中法水厂、垫江高安水厂、开州城南正理自来水厂、云阳第一水厂(四方井)、奉节王家坪水厂。调整名称时必须同步考虑已有档案迁移和重复检查。
- 经纬度统一使用 GCJ-02 并成对保存到
water_plant_base.longitude/latitude,保留六位小数。页面可在坐标缺失时按数据库地址临时定位,但只读展示接口和地图页面禁止反向修改数据库。 - 第一阶段只有王家坪水厂可请求
/water/show/plant/operation和/water/show/plant/activity。另外四厂只能展示真实基础档案与“建设中”,禁止生成虚假指标、告警、设备或工单数据。 - 选中王家坪时运行数据每 2 秒、活动事件每 5 秒刷新;切换到其他水厂、页面
deactivated或销毁时必须立即停止相应轮询和地图动画。
王家坪工艺流程与模拟运行数据
- 工艺流程页固定为
ruoyi-ui/src/views/water/show/processFlow/index.vue,使用 Vue 2、Element UI 和原生 SVG 实现,不应另建一套脱离现有展示模块的组态应用。 - 工艺流程、水厂运行总览和指标趋势统一复用
GET /water/show/plant/operation。模拟模式必须明确携带mode=simulation并显示“模拟实时”标识;禁止为单个页面另建第二套模拟数据接口。 - 模拟快照每 2 秒更新,只用于界面展示和短期趋势;不得把每 2 秒快照写入 MySQL。告警、工单及其状态时间点才是需要持久化的业务数据。
- 正常模拟值必须始终处于页面规则定义的安全范围。随机数据不得自行生成持久化告警;只有带权限的人工故障注入才能进入告警闭环。
- 可控模拟故障的唯一后端目录为
com.ruoyi.waterdata.domain.ProcessFaultDefinition。新增或调整故障时,告警创建、模拟范围、阈值方向、单位、工单类型、维修地址和影响节点必须共同读取或对应此目录,禁止在多个 Service 中分别硬编码互相冲突的定义。 - 当前支持的故障编码及指标编码:
outlet_turbidity_high->outlet_turbidity:出厂水浊度超标。outlet_chlorine_low->outlet_residual_chlorine:出厂水余氯偏低。filter_differential_pressure_high->filter_differential_pressure_a~filter_differential_pressure_d:指定滤池压差过高。supply_pressure_low->supply_pressure:送水泵出口压力偏低。
- 滤池故障必须显式选择
filter-a~filter-d;其他故障禁止携带targetUnitId。指标编码、SVG 高亮节点、告警内容和工单地址必须指向同一条滤池线路。 - 同一水厂一次只允许一个
open、confirmed或recovered的未关闭模拟故障。注入前必须在事务中锁定水厂记录再检查活动告警,不能只依赖前端禁用按钮或单 JVM 内存锁防重复。 - 模拟缓存键必须包含缓存版本、租户、水厂、周期,以及活动故障的
alarmId + metricCode;改变字段结构或生成逻辑时升级版本,避免复用旧类型快照。 activeIncidents是工艺页告警状态、节点高亮和当前故障值的统一来源。必须区分数据库保存的“触发时值”和当前模拟快照的“当前值”,不得假设二者每 2 秒完全相同。- 新增工艺节点或指标时,应同步检查
process-config.js、SVG 状态规则、详情 Drawer、趋势字段、数据总览跳转及设备管理跳转,字段缺失时仍应显示灰色未知状态而非伪造正常值。 - 工艺页和水厂总览存在轮询。
deactivated/beforeDestroy必须停止轮询并释放 ECharts、窗口事件,activated时再恢复,避免 keep-alive 后出现重复请求。
告警—工单—处理—恢复闭环
- 模拟故障必须复用现有
alarm_record、repair_work_order、告警管理和报修工单,不得另建一套演示专用告警表或工单表。 - 模拟告警固定使用
source_type = scada、source_id = waterPlantId,页面通过water_alarm_source_type字典显示“自动监控”;数据库仍保存稳定英文编码。 - 告警状态只允许
open -> confirmed -> recovered -> closed。确认、自动恢复和关闭必须走专用 Service 状态转换方法;普通编辑接口不得直接修改状态及确认、恢复、关闭时间。 - 告警转工单前必须已经确认,并校验告警、租户、区域、水厂以及维修人员归属。维修人员必须是该水厂启用的“运行维护班”人员。
- 告警工单通过
repair_work_order.source_alarm_id关联;source_event_id继续只关联abnormal_event,两类来源编号禁止混用。一条告警最多生成一条工单,重复转单请求应返回已有工单。 - 告警来源工单创建后直接进入
dispatched。工单通用状态机为reported -> dispatched -> processing -> completed -> closed;开始处理、完成和关闭必须走专用接口,完成时必须填写维修过程和处理结果。 - 工单变为
completed后,模拟运行数据立即恢复安全范围;完成时间连续满 10 秒后,由ProcessAlarmRecoveryScheduler将关联活动告警自动改为recovered,最后仍需人工关闭告警并归档工单。 - 已关联工单的告警不得删除,来源为告警的工单不得直接删除;不能通过普通编辑绕过状态机。所有约束必须在后端再次校验,前端按钮隐藏不能替代权限和状态校验。
- 工艺故障转单类型必须由统一故障目录决定:浊度和余氯使用
water_quality(水质处置),滤池压差使用filter_maintenance(滤池维护),送水压力使用pump(泵站设备)。 - 闭环按钮权限固定与前后端一致:
water:process:simulate:模拟故障注入与未转单故障重置。water:alarm:confirm、water:alarm:workorder、water:alarm:close:告警确认、转工单、关闭。water:workorder:dispatch、water:workorder:process、water:workorder:complete、water:workorder:close:工单状态操作。
- 水厂活动动态统一通过
GET /water/show/plant/activity返回真实告警和工单状态事件;不得用当前告警数量或水质采样时间拼装虚假时间线。 - 从工艺页、告警或工单相互跳转时,路由中的
alarmId、workOrderId仅用于排序、滚动和短暂高亮目标行,不得把列表过滤成只剩一条记录。页面在 keep-alive 激活和直接路由进入时都要恢复定位。
字典与枚举展示
业务字段若以英文编码或短编码入库,如 municipal、running、Y、N,必须通过若依数据字典转中文展示。
- 字典数据维护在
sys_dict_type与sys_dict_data。 dict_type为类型编码,dict_value必须与数据库存值一致,dict_label为中文说明。- 新增
water_*字典时,必须同时维护:sql/water_dict.sqlsql/_write_water_dict.py
- 执行字典 SQL 后,需要在若依后台“系统管理 -> 字典管理”刷新缓存,或重启服务。
- 前端页面需要在
export default中声明dicts: ['xxx_dict_type']。 - 表格展示编码字段时使用
<dict-tag :options="dict.type.xxx" :value="scope.row.field" />。 - 下拉框、单选等使用
v-for="d in dict.type.xxx",选项值与库中存值一致。 - 后端 Excel 导出需要中文标签时,实体
@Excel使用dictType = "字典类型"。 - 禁止用
readConverterExp = "英文=英文"冒充字典翻译。 - 可复用若依内置字典时优先复用,如
sys_yes_no、sys_normal_disable。
数据库与 SQL 协作规范
- 当前真实数据库结构以
sql/db_schema_current.sql为主要参考来源。 sql/ry_20260417.sql与sql/quartz.sql是若依/Quartz 自带基线脚本,只用于理解若依原生表结构与初始菜单、字典、定时任务表;新增业务功能时不得随意改写这两个基线文件。- 仓库内其他历史 SQL 可能存在阶段性污染或过期内容。设计新增功能、改表、菜单、字典、初始化数据前,必须优先读取
sql/db_schema_current.sql,再结合现有 Java/XML/Vue 实现判断真实字段和业务关系。 - 如果
sql/db_schema_current.sql与代码实现冲突,应明确指出冲突点,并优先向用户确认真实数据库现状;不要盲目按污染脚本继续开发。 - 功能迁移脚本(例如
sql/ai_knowledge.sql、sql/water_plant_operation_timeseries.sql、sql/water_alarm_workorder_link.sql)存在于仓库,不代表已在真实数据库执行。使用相关字段或权限前必须确认用户已执行脚本;确认落库后应同步更新sql/db_schema_current.sql快照。 - 涉及数据库结构变更时,不直接连接或修改数据库;应输出可由用户在 Navicat/IDEA 数据库工具中执行的 SQL。
- 输出 SQL 时必须区分:
- 表结构变更:
CREATE TABLE、ALTER TABLE、索引、字段注释。 - 菜单权限数据:
sys_menu相关插入或更新。 - 字典数据:
sys_dict_type、sys_dict_data相关插入或更新。 - 初始化或迁移数据:业务表
INSERT、UPDATE、数据修复脚本。
- 表结构变更:
- SQL 应尽量可重复执行或具备执行前检查思路;涉及已有数据迁移、删除、覆盖时必须明确风险。
- 本项目不依赖物理外键。新增表可以按现有库风格建立普通索引和唯一索引,但业务引用完整性必须由 Service 层校验。
- 新增水务业务表优先包含能支撑上下文过滤的字段,如
tenant_id、area_id、water_plant_id,并按查询场景建立索引。 - 菜单和按钮权限 SQL 必须与后端
@PreAuthorize、前端v-hasPermi保持一致。 - 新增字典 SQL 必须同步维护
sql/water_dict.sql与sql/_write_water_dict.py,避免后续重新生成时丢失。 - 告警—工单闭环字段、按钮权限和增量字典统一维护在幂等脚本
sql/water_alarm_workorder_link.sql。新增闭环故障不得再创建相互覆盖的临时迁移脚本。 - 用户执行 SQL 后,如涉及字典,需在若依后台“系统管理 -> 字典管理”刷新缓存或重启服务;如涉及菜单权限,需重新登录或刷新路由权限缓存。
水务数据模块强制规范
凡属于“水务数据”菜单下的业务子模块,必须采用与现有水厂、设备、管线等页面一致的“左侧区域树 + 右侧业务区”模式,并体现“行政区划 + 水厂”两级上下文。
前端布局
- 页面根容器使用
tree-sidebar-manage-wrap。 - 左侧使用
TreePanel,标题通常为“区域”。 - 右侧使用
tree-sidebar-content与content-inner。 - 样式遵循
ruoyi-ui/src/assets/styles/ruoyi.scss中树侧栏规范。 - 可参考:
ruoyi-ui/src/views/water/plant/index.vueruoyi-ui/src/views/water/device/index.vueruoyi-ui/src/views/water/pipeline/index.vueruoyi-ui/src/views/water/workorder/index.vue
区域树接口与语义
- 子模块提供
GET /water/{子模块}/areaTree。 - 后端返回
ISysAreaService.selectAreaTreeWithPlants(tenantId)形态的合并树。 - 合并树由
sys_area行政区划和water_plant_base水厂叶子组成。 - 水厂叶子节点带
plantWaterPlantId。 - 纯行政区划下拉使用
areaTreeAdmin或等价接口,不得混入水厂叶子。
树筛选行为
- 点击行政区划节点:列表查询携带
areaId,按该区域及子区域范围过滤,并清空waterPlantId。 - 点击水厂叶子节点:列表查询携带
waterPlantId,按水厂精确过滤,并清空areaId。 - 重置查询必须同时清空树选中态、
areaId、waterPlantId等树相关参数。 - 新增时:
- 若当前选中水厂,表单预填
waterPlantId,并通过syncFormAreaIdFromWaterPlant或等价逻辑带出areaId。 - 若当前只选中行政区,表单预填
areaId。
- 若当前选中水厂,表单预填
- 业务数据必须能追溯到租户、行政区和水厂上下文。
后端过滤
- 列表 Mapper/Service 对
areaId与waterPlantId的过滤必须与树点击语义一致。 - 禁止再依赖废弃的“厂区
sys_area自动造点”作为树筛选主路径。 - 列表、导出、统计默认理解为在左侧树所选范围内执行。
- 不得把水务数据子模块主界面做成与树无关的全表浏览;特殊全局需求需单独评审。
流量分析与 Python 服务规范
python-services使用 FastAPI 提供流量看板、历史、汇总、预测和最新值接口,入口为python-services/main.py,依赖统一维护在python-services/requirements.txt。- 调用链保持为“Vue -> 若依 Java 后端 -> Python 服务”。Java 通过
water.forecast-service.base-url访问 Python,并向前端暴露/water/show/flow/dashboard、/forecast、/live;不要让 Vue 绕过若依权限直接调用 8000 端口。 - Python 服务只负责分析、预测和展示数据加工,不承接若依认证、菜单权限或核心业务数据维护。
- 更新 CSV、模型文件或预测算法时,应记录数据时间范围、字段含义、训练方式与模型版本,避免无来源地覆盖
flow_data和saved_models。 - 水厂运行时序导入按
docs/water-plant-operation-timeseries-import.md与对应 SQL 执行;禁止由代码代理直接连接数据库替用户导入或清空正式数据。
Docker 与配置安全
- 本地完整部署以根目录
docker-compose.yml为准,服务包括mysql、redis、backend、python-service、frontend。 .env.docker保存本机密码、模型密钥和高德安全密钥,必须保持 Git 忽略;.env.docker.example只能保留空值、占位值或无敏感性的开发默认值。- 修改端口、服务名、健康检查、数据卷或 Nginx 代理时,要同步检查
docker-compose.yml、各模块Dockerfile、ruoyi-ui/nginx.conf.template与docs/docker-local.md。 - 上传目录、MySQL/Redis 数据和日志通过命名卷持久化。重建容器不等于允许删除卷;不得执行
docker compose down -v,除非用户明确要求清空数据并理解风险。 - 不要把 Docker 内部主机名(如
mysql、redis、python-service)硬编码为本地非容器环境默认值,优先使用现有 Spring 环境变量覆盖机制。
生成新模块时的输出结构
需要生成新业务模块代码或方案时,按以下顺序说明或落地:
- 数据库表设计检查建议
- 权限标识设计
- 菜单配置建议
- 后端实体类
- Mapper 接口
- Mapper XML
- Service 接口
- ServiceImpl 实现类
- Controller
- 前端 API 文件
- 前端 Vue 页面
- 若依后台需要配置的菜单与按钮权限
- 代码注意事项
常用命令
- 后端编译:
mvn clean package -DskipTests - 后端按模块编译:
mvn -pl ruoyi-water-data -am package -DskipTests - 水务模块测试:
mvn -pl ruoyi-water-data -am test - 后端启动:从
ruoyi-admin启动com.ruoyi.RuoYiApplication - 前端开发:在
ruoyi-ui执行npm run dev - 前端生产构建:在
ruoyi-ui执行npm run build:prod - Python 服务开发:在
python-services安装requirements.txt后执行python main.py - Docker 本地部署:
docker compose --env-file .env.docker up -d --build - Docker 查看状态:
docker compose --env-file .env.docker ps - Docker 查看服务日志:
docker compose --env-file .env.docker logs --tail=200 backend python-service frontend
执行验证命令前先判断依赖是否已安装、命令是否会访问网络。网络受限时,不要擅自改用不透明的替代方式。
修改自检清单
- 是否复用了若依原生认证、权限、菜单、字典、分页、日志、导入导出能力?
- Controller 权限、前端
v-hasPermi、菜单按钮权限是否一致? - 新增/修改/删除/导出是否有
@Log? - 列表、详情、新增、修改、删除、导出接口是否符合若依风格?
- Service 层是否校验关联数据存在性与删除约束?
- 涉及编码字段时,前端展示与 Excel 导出是否使用字典?
- 水务数据页面是否使用区域树和
areaId/waterPlantId上下文? - 水务展示页面是否正确区分历史/模拟数据并释放图表、定时器和地图资源?
- 普通模拟数据是否始终安全,故障定义是否统一来自
ProcessFaultDefinition,Redis 缓存是否按故障隔离? - 模拟故障是否遵守单故障约束,滤池目标是否在指标、节点、告警和工单之间保持一致?
- 告警与工单是否只能按状态机流转,完成工单后是否立即恢复指标并在 10 秒后自动恢复告警?
- 跨页面路由定位是否展示完整列表且只高亮目标记录,而不是错误地按目标 ID 过滤?
- AI、数据库、高德和 Docker 密钥是否只通过环境变量或被忽略的本地文件提供?
- AI 知识库变更是否同步覆盖解析、索引、权限、日志、失败状态和测试?
- 流量页面是否继续通过 Java 代理调用 Python 服务,而不是前端直连?
- 是否维护了必要 SQL、字典脚本和发布说明?
- 是否运行了与改动范围匹配的编译、测试或前端构建?
