# 智慧水务管理系统 — 详细设计规格书 > 版本:v2.0 | 日期:2026-06-14 | 作者:bot_pm > 基于:requirements.md (需求) + architecture.md (架构) > 用途:直接指导开发实现,每个 Issue 标注对应章节 --- ## 第1章 项目框架与基础设施 ### 1.1 Maven 模块结构 ``` water-management-system/ ├── pom.xml # 父 POM (Spring Boot 3.x + Cloud Alibaba 2024.x) ├── wm-common/ # 公共模块 │ └── src/main/java/com/water/common/ │ ├── core/ │ │ ├── result/R.java # 统一响应 │ │ ├── exception/BizException.java # 业务异常 │ │ ├── exception/GlobalExceptionHandler.java │ │ └── constant/ErrorCode.java # 错误码枚举 │ ├── web/ │ │ ├── config/WebMvcConfig.java │ │ └── interceptor/AuthInterceptor.java │ └── util/ │ ├── FileUtil.java │ ├── CaptchaUtil.java │ └── DictUtil.java ├── wm-base/ # 基础服务 (8081) │ └── src/main/java/com/water/base/ │ ├── controller/ # UserController, RoleController, DeptController... │ ├── service/ # UserService, RoleService, DeptService... │ ├── mapper/ # MyBatis-Plus Mapper │ └── entity/ # SysUser, SysRole, SysDept, SysMenu, SysLog... ├── wm-gateway/ # API 网关 (8080) │ └── src/main/resources/ │ └── application.yml # Spring Cloud Gateway 路由配置 ├── wm-iot/ # 物联网平台 (8082) ├── wm-data-engine/ # 数据引擎 (8083) ├── wm-bpm/ # 流程引擎 (8084) ├── wm-production/ # 供水生产管理 (8085) ├── wm-revenue/ # 营业收费 (8086) ├── wm-patrol/ # 巡检管理 (8087) ├── wm-bi/ # 大数据分析 (8088) ├── wm-notify/ # 消息通知 (8089) ├── wm-job/ # 定时任务 (8090) ├── frontend/ # Vue3 前端 │ └── src/ │ ├── api/ # 接口封装 │ ├── views/ # 页面 │ ├── router/ # 路由 │ ├── stores/ # Pinia │ └── components/ # 公共组件 ├── mobile/ # Flutter APP │ └── lib/ │ ├── pages/ │ ├── services/ │ ├── models/ │ └── widgets/ ├── db/ │ ├── postgresql/ # PostgreSQL DDL 脚本 │ ├── tdengine/ # TDengine 建库脚本 │ └── seed/ # 种子数据 ├── docker/ # Docker Compose └── docs/ # 文档 ``` **对应 Issue**:#17 项目框架搭建 ### 1.2 数据库完整 DDL > **对应 Issue**:#18 数据库设计 #### 1.2.1 系统管理表 (wm-base) ```sql -- 部门表 CREATE TABLE sys_dept ( id BIGSERIAL PRIMARY KEY, parent_id BIGINT DEFAULT 0, dept_name VARCHAR(100) NOT NULL, dept_type VARCHAR(30) DEFAULT 'water_company', -- water_bureau/water_company/ops sort_order INT DEFAULT 0, status SMALLINT DEFAULT 1, -- 1启用 0停用 created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); COMMENT ON TABLE sys_dept IS '部门组织架构表'; COMMENT ON COLUMN sys_dept.dept_type IS 'water_bureau(水利局)/water_company(水务公司)/ops(运维单位)'; -- 用户表 CREATE TABLE sys_user ( id BIGSERIAL PRIMARY KEY, dept_id BIGINT REFERENCES sys_dept(id), username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, -- BCrypt 加密 real_name VARCHAR(50), phone VARCHAR(20), email VARCHAR(100), role_type VARCHAR(30) DEFAULT 'operator', -- admin/leader/manager/operator/tech status SMALLINT DEFAULT 1, -- 1启用 0停用 last_login_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); COMMENT ON TABLE sys_user IS '系统用户表'; COMMENT ON COLUMN sys_user.role_type IS 'admin(系统管理员)/leader(分管领导)/manager(业务管理)/operator(现场运维)/tech(技术维护)'; -- 角色表 CREATE TABLE sys_role ( id BIGSERIAL PRIMARY KEY, role_name VARCHAR(50) UNIQUE NOT NULL, role_key VARCHAR(50) UNIQUE NOT NULL, -- admin/supervisor/biz_manager/field_ops/tech_maintain data_scope VARCHAR(20) DEFAULT 'DEPT', -- ALL/DEPT/SELF description VARCHAR(200), status SMALLINT DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- 角色-菜单权限 CREATE TABLE sys_role_menu ( role_id BIGINT REFERENCES sys_role(id), menu_id BIGINT REFERENCES sys_menu(id), PRIMARY KEY (role_id, menu_id) ); -- 用户-角色关联 (多角色) CREATE TABLE sys_user_role ( user_id BIGINT REFERENCES sys_user(id), role_id BIGINT REFERENCES sys_role(id), PRIMARY KEY (user_id, role_id) ); -- 菜单表 CREATE TABLE sys_menu ( id BIGSERIAL PRIMARY KEY, parent_id BIGINT DEFAULT 0, menu_name VARCHAR(50) NOT NULL, menu_type VARCHAR(20) DEFAULT 'menu', -- menu/button path VARCHAR(200), -- 前端路由 component VARCHAR(200), -- 前端组件 icon VARCHAR(100), permission VARCHAR(100), -- 权限标识 e.g. production:alert:confirm sort_order INT DEFAULT 0, visible SMALLINT DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 操作日志表 CREATE TABLE sys_log ( id BIGSERIAL PRIMARY KEY, user_id BIGINT, username VARCHAR(50), operation VARCHAR(100), -- 操作类型 e.g. LOGIN/DELETE/UPDATE method VARCHAR(200), -- 请求方法 params TEXT, -- 请求参数 JSON ip VARCHAR(50), duration_ms INT, -- 执行耗时 status SMALLINT DEFAULT 1, -- 1成功 0失败 error_msg TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_sys_log_user_id ON sys_log(user_id); CREATE INDEX idx_sys_log_created_at ON sys_log(created_at); ``` #### 1.2.2 物联网设备表 (wm-iot) ```sql -- 设备模型定义 CREATE TABLE iot_device_model ( id BIGSERIAL PRIMARY KEY, model_key VARCHAR(50) UNIQUE NOT NULL, -- e.g. water_meter_dn15 model_name VARCHAR(100) NOT NULL, -- DN15远传水表 vendor VARCHAR(100), -- 厂商名称 protocol VARCHAR(30) NOT NULL, -- MQTT/Modbus/CoAP/HTTP properties JSONB NOT NULL DEFAULT '[]', -- [{key, name, unit, data_type, range_min, range_max}] commands JSONB DEFAULT '[]', -- [{key, name, params:[{key,type,required}]}] created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- 协议适配器配置 CREATE TABLE iot_protocol_adapter ( id BIGSERIAL PRIMARY KEY, adapter_key VARCHAR(30) UNIQUE NOT NULL, -- mqtt/modbus/coap/http adapter_name VARCHAR(50) NOT NULL, config JSONB NOT NULL DEFAULT '{}', -- 连接参数 e.g. {host, port, keepalive} enabled SMALLINT DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 设备实例 CREATE TABLE iot_device ( id BIGSERIAL PRIMARY KEY, device_sn VARCHAR(100) UNIQUE NOT NULL, -- 设备序列号 device_name VARCHAR(200) NOT NULL, model_id BIGINT REFERENCES iot_device_model(id), device_type VARCHAR(30) NOT NULL, -- flow_meter/pressure/valve/water_quality/level position_type VARCHAR(30), -- water_plant/pressure_station/pipe_network/village area VARCHAR(50) NOT NULL, -- 一体化水厂/精芒片区/八家户片区/托里片区/大镇阿合其/托托片区 station_id BIGINT, -- 所属站点 loc_lng DOUBLE PRECISION, -- 经度 loc_lat DOUBLE PRECISION, -- 纬度 geom GEOMETRY(Point, 4326), -- PostGIS 空间坐标 status VARCHAR(20) DEFAULT 'offline', -- online/offline/maintenance/fault firmware_ver VARCHAR(30), last_report_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_iot_device_area ON iot_device(area); CREATE INDEX idx_iot_device_type ON iot_device(device_type); CREATE INDEX idx_iot_device_status ON iot_device(status); CREATE INDEX idx_iot_device_geom ON iot_device USING GIST(geom); -- 设备遥测数据 (实时缓存表,最终入TDengine) CREATE TABLE iot_device_telemetry ( id BIGSERIAL PRIMARY KEY, device_id BIGINT REFERENCES iot_device(id), device_sn VARCHAR(100) NOT NULL, metric_key VARCHAR(50) NOT NULL, -- flow_rate/pressure/turbidity/ph/chlorine/level... metric_value DOUBLE PRECISION, reported_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_iot_telemetry_device ON iot_device_telemetry(device_sn, metric_key, reported_at); -- 设备影子 (Redis 为主,PostgreSQL 为灾备持久化) CREATE TABLE iot_device_shadow ( id BIGSERIAL PRIMARY KEY, device_sn VARCHAR(100) UNIQUE NOT NULL, reported_state JSONB DEFAULT '{}', -- 设备上报的最新状态 desired_state JSONB DEFAULT '{}', -- 期望状态(待下发) version BIGINT DEFAULT 1, -- 乐观锁版本号 updated_at TIMESTAMPTZ DEFAULT NOW() ); -- OTA 固件版本 CREATE TABLE iot_firmware ( id BIGSERIAL PRIMARY KEY, model_key VARCHAR(50) NOT NULL, version VARCHAR(30) NOT NULL, file_url VARCHAR(500) NOT NULL, -- MinIO 存储路径 file_size BIGINT, checksum VARCHAR(64), -- SHA256 changelog TEXT, status VARCHAR(20) DEFAULT 'draft', -- draft/published/deprecated created_at TIMESTAMPTZ DEFAULT NOW() ); -- OTA 升级任务 CREATE TABLE iot_ota_task ( id BIGSERIAL PRIMARY KEY, firmware_id BIGINT REFERENCES iot_firmware(id), device_sn VARCHAR(100) NOT NULL, status VARCHAR(20) DEFAULT 'pending', -- pending/downloading/installing/success/failed progress SMALLINT DEFAULT 0, -- 0-100 error_msg TEXT, started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); ``` #### 1.2.3 时序数据库 (TDengine) ```sql -- 超级表:设备遥测时序数据 CREATE STABLE iot_telemetry ( ts TIMESTAMP, device_sn NCHAR(100), metric_key NCHAR(50), metric_value DOUBLE, quality TINYINT -- 数据质量 0异常 1正常 ) TAGS ( device_type NCHAR(30), area NCHAR(50) ); -- 按设备类型创建子表 CREATE TABLE flow_meter_data USING iot_telemetry TAGS('flow_meter', 'default'); CREATE TABLE pressure_data USING iot_telemetry TAGS('pressure', 'default'); CREATE TABLE level_data USING iot_telemetry TAGS('level', 'default'); CREATE TABLE water_quality_data USING iot_telemetry TAGS('water_quality', 'default'); CREATE TABLE valve_status_data USING iot_telemetry TAGS('valve', 'default'); -- 小时级聚合表 CREATE TABLE iot_telemetry_hourly ( ts TIMESTAMP, device_sn NCHAR(100), metric_key NCHAR(50), avg_value DOUBLE, min_value DOUBLE, max_value DOUBLE, sample_count INT ) TAGS ( device_type NCHAR(30), area NCHAR(50) ); ``` #### 1.2.4 营业收费表 (wm-revenue) ```sql -- 用水户档案 CREATE TABLE rev_customer ( id BIGSERIAL PRIMARY KEY, customer_no VARCHAR(30) UNIQUE NOT NULL, -- 户号 customer_name VARCHAR(100) NOT NULL, customer_type VARCHAR(20) NOT NULL, -- residential/business/enterprise/institution area VARCHAR(50) NOT NULL, address VARCHAR(300), phone VARCHAR(20), id_card VARCHAR(18), contract_no VARCHAR(50), status VARCHAR(20) DEFAULT 'active', -- active/inactive/cancelled created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_rev_customer_area ON rev_customer(area); CREATE INDEX idx_rev_customer_type ON rev_customer(customer_type); -- 水表档案 (全生命周期) CREATE TABLE rev_meter ( id BIGSERIAL PRIMARY KEY, meter_no VARCHAR(50) UNIQUE NOT NULL, customer_id BIGINT REFERENCES rev_customer(id), device_id BIGINT, -- 关联IoT设备(远传表) caliber VARCHAR(10) NOT NULL, -- DN15/DN20/DN40/DN50/DN80/DN100... meter_type VARCHAR(20) NOT NULL, -- mechanical/ultrasonic/electromagnetic/remote initial_reading DECIMAL(12,3), install_date DATE, warranty_expire DATE, status VARCHAR(20) DEFAULT 'in_stock', -- in_stock/installed/dismantled/scrapped/repairing/repaired prev_status VARCHAR(20), -- 前状态(用于拆换追溯) status_changed_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); COMMENT ON TABLE rev_meter IS '水表全生命周期档案表'; CREATE INDEX idx_rev_meter_customer ON rev_meter(customer_id); CREATE INDEX idx_rev_meter_status ON rev_meter(status); -- 水表操作流水 (入库/出库/安装/拆换/报废/翻新/校表) CREATE TABLE rev_meter_log ( id BIGSERIAL PRIMARY KEY, meter_id BIGINT REFERENCES rev_meter(id), operation VARCHAR(20) NOT NULL, -- stock_in/stock_out/install/dismantle/swap/scrap/renovate/calibrate old_reading DECIMAL(12,3), new_reading DECIMAL(12,3), old_meter_no VARCHAR(50), -- 换表时的旧表编号 new_meter_no VARCHAR(50), -- 换表时的新表编号 operator_id BIGINT, remark TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 抄表记录 CREATE TABLE rev_reading ( id BIGSERIAL PRIMARY KEY, meter_id BIGINT REFERENCES rev_meter(id), reading_date DATE NOT NULL, prev_reading DECIMAL(12,3), curr_reading DECIMAL(12,3), consumption DECIMAL(12,3), -- 用水量 = curr - prev read_type VARCHAR(20) NOT NULL, -- manual/remote/estimate reader_id BIGINT, photo_url VARCHAR(500), verified SMALLINT DEFAULT 0, -- 0未核实 1已核实 2异常 created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_rev_reading_date ON rev_reading(reading_date); CREATE INDEX idx_rev_reading_meter ON rev_reading(meter_id, reading_date); -- 水费账单 CREATE TABLE rev_bill ( id BIGSERIAL PRIMARY KEY, customer_id BIGINT REFERENCES rev_customer(id), meter_id BIGINT REFERENCES rev_meter(id), bill_no VARCHAR(50) UNIQUE NOT NULL, bill_period VARCHAR(10) NOT NULL, -- 2026-06 consumption DECIMAL(12,3), water_fee DECIMAL(12,2), sewage_fee DECIMAL(12,2), other_fee DECIMAL(12,2) DEFAULT 0, total_fee DECIMAL(12,2), paid_fee DECIMAL(12,2) DEFAULT 0, status VARCHAR(20) DEFAULT 'pending', -- pending/partial/paid/overdue/cancelled due_date DATE, paid_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_rev_bill_customer ON rev_bill(customer_id, bill_period); CREATE INDEX idx_rev_bill_status ON rev_bill(status); -- 支付记录 CREATE TABLE rev_payment ( id BIGSERIAL PRIMARY KEY, bill_id BIGINT REFERENCES rev_bill(id), pay_no VARCHAR(100) UNIQUE, -- 第三方支付单号 pay_channel VARCHAR(20) NOT NULL, -- counter/pos/alipay/wechat pay_amount DECIMAL(12,2) NOT NULL, pay_status VARCHAR(20) DEFAULT 'processing', -- processing/success/failed/refunded pay_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 电子发票 CREATE TABLE rev_invoice ( id BIGSERIAL PRIMARY KEY, bill_id BIGINT REFERENCES rev_bill(id), invoice_no VARCHAR(50) UNIQUE NOT NULL, invoice_type VARCHAR(20) DEFAULT 'electronic', -- paper/electronic/vat amount DECIMAL(12,2) NOT NULL, tax_amount DECIMAL(12,2) DEFAULT 0, status VARCHAR(20) DEFAULT 'issued', -- issued/voided/red_invoiced issued_at TIMESTAMPTZ DEFAULT NOW(), voided_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 应收应付账务 CREATE TABLE rev_account ( id BIGSERIAL PRIMARY KEY, customer_id BIGINT REFERENCES rev_customer(id), account_type VARCHAR(20) NOT NULL, -- receivable/payable amount DECIMAL(12,2) NOT NULL, balance DECIMAL(12,2) NOT NULL, period VARCHAR(10), status VARCHAR(20) DEFAULT 'open', -- open/partial/closing/closed created_at TIMESTAMPTZ DEFAULT NOW() ); -- 水价阶梯配置 CREATE TABLE rev_water_price ( id BIGSERIAL PRIMARY KEY, customer_type VARCHAR(20) NOT NULL, -- residential/business/enterprise tier SMALLINT NOT NULL, -- 1/2/3 min_usage DECIMAL(12,3), -- 下限(m³) max_usage DECIMAL(12,3), -- 上限(m³) NULL=无上限 unit_price DECIMAL(8,4) NOT NULL, -- 水价(元/m³) sewage_price DECIMAL(8,4) DEFAULT 0, -- 污水处理费 effective_date DATE NOT NULL, expired_date DATE, created_at TIMESTAMPTZ DEFAULT NOW() ); ``` #### 1.2.5 报装管理表 ```sql -- 报装申请 CREATE TABLE rev_install ( id BIGSERIAL PRIMARY KEY, app_no VARCHAR(30) UNIQUE NOT NULL, -- 申请编号 applicant_name VARCHAR(50) NOT NULL, applicant_phone VARCHAR(20) NOT NULL, customer_type VARCHAR(20) NOT NULL, area VARCHAR(50), address VARCHAR(300), caliber VARCHAR(10), -- 申请管径 usage_type VARCHAR(30), -- 生活/商业/工业/消防 status VARCHAR(20) DEFAULT 'pre_accept', -- pre_accept/ site_survey/ engineering/ dispatched/ constructing/ completed/ cancelled survey_result TEXT, -- 现场踏勘结论 designer_id BIGINT, -- 设计人员 constructor_id BIGINT, -- 施工人员 completed_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_rev_install_status ON rev_install(status); ``` #### 1.2.6 客服与微信网厅 ```sql -- 知识库 CREATE TABLE cs_kb_article ( id BIGSERIAL PRIMARY KEY, title VARCHAR(200) NOT NULL, category VARCHAR(50) NOT NULL, -- policy/guide/common_qa/water_knowledge content TEXT NOT NULL, -- Markdown tags VARCHAR(500), -- 逗号分隔 view_count INT DEFAULT 0, like_count INT DEFAULT 0, status SMALLINT DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_cs_kb_category ON cs_kb_article(category); -- 公告板 CREATE TABLE cs_announcement ( id BIGSERIAL PRIMARY KEY, title VARCHAR(200) NOT NULL, ann_type VARCHAR(30) NOT NULL, -- water_outage/water_quality/service/notice/news content TEXT NOT NULL, target_scope VARCHAR(50) DEFAULT 'all', -- all/{area} publish_status VARCHAR(20) DEFAULT 'draft', -- draft/published/revoked published_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 微信支付订单 CREATE TABLE rev_wx_pay_order ( id BIGSERIAL PRIMARY KEY, bill_id BIGINT REFERENCES rev_bill(id), wx_order_no VARCHAR(100) UNIQUE, wx_transaction_id VARCHAR(100), amount DECIMAL(12,2) NOT NULL, status VARCHAR(20) DEFAULT 'created', -- created/paying/paid/refunding/refunded/closed paid_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); -- FAQ CREATE TABLE cs_faq ( id BIGSERIAL PRIMARY KEY, question VARCHAR(500) NOT NULL, answer TEXT NOT NULL, category VARCHAR(50), keywords VARCHAR(300), priority INT DEFAULT 0, view_count INT DEFAULT 0, created_at TIMESTAMPTZ DEFAULT NOW() ); ``` #### 1.2.7 工单管理 ```sql CREATE TABLE wo_template ( id BIGSERIAL PRIMARY KEY, template_name VARCHAR(100) NOT NULL, wo_type VARCHAR(30) NOT NULL, -- repair/alert/meter_change/quality/scheduling form_schema JSONB DEFAULT '{}', -- 表单字段定义 flow_def_key VARCHAR(100), -- 流程定义KEY created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE TABLE wo_order ( id BIGSERIAL PRIMARY KEY, wo_no VARCHAR(30) UNIQUE NOT NULL, template_id BIGINT REFERENCES wo_template(id), wo_type VARCHAR(30) NOT NULL, title VARCHAR(200) NOT NULL, description TEXT, priority VARCHAR(10) DEFAULT 'normal', -- low/normal/high/urgent source VARCHAR(30), -- manual/alert_rules/patrol/scheduling source_ref_id BIGINT, -- 来源关联ID (报警/巡检/Schedule) assignee_id BIGINT, creator_id BIGINT, status VARCHAR(20) DEFAULT 'created', -- created/assigned/processing/completed/closed resolved_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_wo_status ON wo_order(status); CREATE INDEX idx_wo_assignee ON wo_order(assignee_id); -- 工单处理记录 CREATE TABLE wo_process_log ( id BIGSERIAL PRIMARY KEY, wo_id BIGINT REFERENCES wo_order(id), action VARCHAR(30) NOT NULL, -- create/assign/accept/process/complete/close/reject operator_id BIGINT, comment TEXT, attachments JSONB DEFAULT '[]', -- [{url, name, type}] created_at TIMESTAMPTZ DEFAULT NOW() ); ``` #### 1.2.8 巡检系统 ```sql -- 巡检区域 CREATE TABLE patrol_area ( id BIGSERIAL PRIMARY KEY, area_name VARCHAR(100) NOT NULL, area_code VARCHAR(30) UNIQUE, parent_id BIGINT DEFAULT 0, sort_order INT DEFAULT 0, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 巡检路线 CREATE TABLE patrol_route ( id BIGSERIAL PRIMARY KEY, route_name VARCHAR(100) NOT NULL, area_id BIGINT REFERENCES patrol_area(id), checkpoints JSONB NOT NULL, -- [{seq, name, lng, lat, device_ids:[], check_items:[{item,standard}]}] estim_duration INT, -- 预计时长(分钟) status SMALLINT DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 巡检表单模板 CREATE TABLE patrol_form_template ( id BIGSERIAL PRIMARY KEY, template_name VARCHAR(100) NOT NULL, category VARCHAR(30), -- device/water_quality/safety/hygiene items JSONB NOT NULL, -- [{item, type(text/photo/number/select), required, options}] created_at TIMESTAMPTZ DEFAULT NOW() ); -- 巡检任务 CREATE TABLE patrol_task ( id BIGSERIAL PRIMARY KEY, route_id BIGINT REFERENCES patrol_route(id), assignee_id BIGINT, plan_date DATE NOT NULL, plan_start TIME, plan_end TIME, actual_start TIMESTAMPTZ, actual_end TIMESTAMPTZ, status VARCHAR(20) DEFAULT 'pending', -- pending/in_progress/completed/expired distance DECIMAL(8,2), -- 实际里程(km) created_at TIMESTAMPTZ DEFAULT NOW() ); -- GPS轨迹点 CREATE TABLE patrol_gps_track ( id BIGSERIAL PRIMARY KEY, task_id BIGINT REFERENCES patrol_task(id), lng DOUBLE PRECISION NOT NULL, lat DOUBLE PRECISION NOT NULL, altitude DOUBLE PRECISION, accuracy DOUBLE PRECISION, recorded_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_patrol_gps_task ON patrol_gps_track(task_id, recorded_at); -- 巡检记录 CREATE TABLE patrol_record ( id BIGSERIAL PRIMARY KEY, task_id BIGINT REFERENCES patrol_task(id), checkpoint_seq INT NOT NULL, -- 路线第几个检查点 device_id BIGINT, form_data JSONB NOT NULL, -- [{item, result, value, photo_url, remark}] gps_lng DOUBLE PRECISION, gps_lat DOUBLE PRECISION, recorded_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- 巡检问题上报 CREATE TABLE patrol_issue ( id BIGSERIAL PRIMARY KEY, task_id BIGINT REFERENCES patrol_task(id), patrol_record_id BIGINT REFERENCES patrol_record(id), issue_type VARCHAR(30) NOT NULL, -- device_fault/leak/quality/safety/other severity VARCHAR(10) DEFAULT 'normal', -- normal/important/urgent description TEXT NOT NULL, photo_urls TEXT, -- JSON数组 voice_url VARCHAR(500), wo_id BIGINT REFERENCES wo_order(id), -- 生成工单ID status VARCHAR(20) DEFAULT 'reported', -- reported/assigned/processing/resolved resolved_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 巡检统计缓存表 CREATE TABLE patrol_stats_daily ( id BIGSERIAL PRIMARY KEY, stat_date DATE NOT NULL, assignee_id BIGINT, area_id BIGINT, task_count INT DEFAULT 0, completed_count INT DEFAULT 0, total_distance DECIMAL(8,2), total_duration INT, -- 分钟 issue_count INT DEFAULT 0, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE UNIQUE INDEX idx_patrol_stats_uk ON patrol_stats_daily(stat_date, assignee_id, area_id); ``` #### 1.2.9 供水生产管理 ```sql -- 能耗记录 CREATE TABLE prod_energy ( id BIGSERIAL PRIMARY KEY, energy_type VARCHAR(20) NOT NULL, -- electricity/water_consumption station_id BIGINT, metric_value DOUBLE PRECISION, unit VARCHAR(10) DEFAULT 'kWh', recorded_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 药耗记录 CREATE TABLE prod_chemical ( id BIGSERIAL PRIMARY KEY, chemical_type VARCHAR(30) NOT NULL, -- coagulant/disinfectant/flocculant station_id BIGINT, dosage_rate DOUBLE PRECISION, -- 投加速率 consumption DOUBLE PRECISION, -- 消耗量(kg) recorded_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 水质检测点位 CREATE TABLE prod_quality_point ( id BIGSERIAL PRIMARY KEY, point_name VARCHAR(100) NOT NULL, point_type VARCHAR(30) NOT NULL, -- source/plant/pipe_end/network area VARCHAR(50), water_plant VARCHAR(100), location VARCHAR(200), sample_freq VARCHAR(20), -- daily/weekly/monthly status SMALLINT DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 水质检测记录 CREATE TABLE prod_quality_record ( id BIGSERIAL PRIMARY KEY, point_id BIGINT REFERENCES prod_quality_point(id), test_date DATE NOT NULL, test_type VARCHAR(20) DEFAULT 'manual', -- manual/auto turbidity DOUBLE PRECISION, -- NTU ph DOUBLE PRECISION, residual_cl DOUBLE PRECISION, -- 余氯 mg/L cod_mn DOUBLE PRECISION, -- 高锰酸盐指数 coliform INT, -- 总大肠菌群 qualified SMALLINT, -- 合格判定 (GB5749-2022) tester_id BIGINT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 调度指令 CREATE TABLE prod_dispatch_cmd ( id BIGSERIAL PRIMARY KEY, cmd_no VARCHAR(30) UNIQUE NOT NULL, cmd_type VARCHAR(30) NOT NULL, -- valve_control/pump_start/flow_adjust/alert_response cmd_content TEXT NOT NULL, target_device VARCHAR(100), priority VARCHAR(10) DEFAULT 'normal', issuer_id BIGINT, issued_at TIMESTAMPTZ DEFAULT NOW(), deadline TIMESTAMPTZ, status VARCHAR(20) DEFAULT 'issued', -- issued/received/executing/completed/rejected executed_by BIGINT, executed_at TIMESTAMPTZ, result TEXT ); -- 应急推演方案 CREATE TABLE prod_emergency_plan ( id BIGSERIAL PRIMARY KEY, plan_name VARCHAR(100) NOT NULL, scenario VARCHAR(30) NOT NULL, -- pipe_burst/water_quality/fire_supply/equipment_fault steps JSONB NOT NULL, -- [{seq, action, target, duration, responsible_role}] status SMALLINT DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 值班表 CREATE TABLE prod_duty_schedule ( id BIGSERIAL PRIMARY KEY, schedule_date DATE NOT NULL, shift VARCHAR(20) DEFAULT 'day', -- day/night user_id BIGINT, dept_id BIGINT, phone VARCHAR(20), status VARCHAR(20) DEFAULT 'on_duty', handover_note TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); ``` #### 1.2.10 报警管理 ```sql -- 报警规则 CREATE TABLE alert_rule ( id BIGSERIAL PRIMARY KEY, rule_name VARCHAR(100) NOT NULL, device_type VARCHAR(30), metric_key VARCHAR(50) NOT NULL, alert_level VARCHAR(10) NOT NULL, -- info/warning/critical/emergency condition_expr VARCHAR(200) NOT NULL, -- "> 0.5" 或 "ABS_DELTA > 10" 或 "<= 0.2" threshold_value VARCHAR(50), debounce_sec INT DEFAULT 300, -- 去重窗口(秒) notify_scheme JSONB DEFAULT '{"sms":false,"push":true,"ws":true}', enabled SMALLINT DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW() ); -- 报警事件 CREATE TABLE alert_event ( id BIGSERIAL PRIMARY KEY, rule_id BIGINT REFERENCES alert_rule(id), device_id BIGINT, device_sn VARCHAR(100), metric_key VARCHAR(50), metric_value DOUBLE PRECISION, threshold VARCHAR(50), alert_level VARCHAR(10), message VARCHAR(500), area VARCHAR(50), confirmed_by BIGINT, confirmed_at TIMESTAMPTZ, dispatched SMALLINT DEFAULT 0, -- 是否生成工单 resolved_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_alert_level ON alert_event(alert_level, created_at); CREATE INDEX idx_alert_device ON alert_event(device_sn, created_at); ``` #### 1.2.11 配置中心 ```sql -- 系统配置 CREATE TABLE sys_config ( id BIGSERIAL PRIMARY KEY, config_key VARCHAR(100) UNIQUE NOT NULL, config_value TEXT NOT NULL, config_type VARCHAR(30) DEFAULT 'string', -- string/number/json/bool description VARCHAR(300), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- 阈值配置 CREATE TABLE sys_threshold ( id BIGSERIAL PRIMARY KEY, metric_key VARCHAR(50) NOT NULL, area VARCHAR(50) DEFAULT 'all', min_value DOUBLE PRECISION, max_value DOUBLE PRECISION, unit VARCHAR(20), description VARCHAR(200), created_at TIMESTAMPTZ DEFAULT NOW() ); -- 文档管理 CREATE TABLE sys_document ( id BIGSERIAL PRIMARY KEY, doc_name VARCHAR(200) NOT NULL, doc_category VARCHAR(50), -- manual/report/standard/other file_url VARCHAR(500) NOT NULL, file_size BIGINT, file_type VARCHAR(20), version INT DEFAULT 1, tags VARCHAR(300), uploader_id BIGINT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_sys_doc_category ON sys_document(doc_category); ``` ### 1.3 认证授权系统设计 > **对应 Issue**:#19 认证授权系统 **职责边界**:提供统一认证(登录/JWT签发/Token校验/刷新)、RBAC角色权限管理、数据权限(按片区/部门隔离)。 #### 认证流程 ``` 用户 → POST /api/auth/login {username, password} → Sa-Token 校验密码 (BCrypt) → 签发 JWT (含 userId, roleKeys[]) → 返回 {token, refreshToken, userInfo} 后续请求 → Header: Authorization: Bearer → Sa-Token 拦截器校验 → @SaCheckPermission 注解校验菜单权限 → AOP 切面注入数据权限 scope → SQL 自动拼接 WHERE area IN (...) ``` #### API 端点 | 方法 | 路径 | 说明 | |------|------|------| | POST | /api/auth/login | 用户名密码登录,返回 JWT | | POST | /api/auth/refresh | 刷新 Token | | POST | /api/auth/logout | 退出登录 | | GET | /api/auth/current | 获取当前用户信息+权限列表 | | POST | /api/oauth2/token | OAuth2 Token端点 | | POST | /api/oauth2/authorize | OAuth2 授权端点 | | POST | /api/sso/clients | 注册 SSO 客户端应用 | | GET | /api/sso/clients | 查询已注册应用列表 | | DELETE | /api/sso/clients/{id} | 注销应用 | #### 数据权限策略 ```java // 数据权限注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DataScope { String column() default "area"; // 需要过滤的字段 String deptColumn() default "dept_id"; } // SQL 拦截器自动拼接: AND area IN (用户的片区列表) ``` **模块依赖**: - 依赖:wm-base(用户/角色表) - 提供:给所有微服务提供 JWT 认证 + 数据权限 ### 1.4 GIS 引擎集成 > **对应 Issue**:#21 GIS引擎集成 **部署架构**: ``` GeoServer 2.25 (Tomcat) ├── Workspace: water_supply │ ├── DataStore: postgis_water (连接 PostgreSQL) │ ├── Layer: iot_device (监测点位 WMS) │ ├── Layer: pipeline (管网矢量 WMS) │ ├── Layer: dma_zones (DMA 分区面 WMS) │ └── Layer group: 综合管网图 └── Cache: GeoWebCache (WMTS 瓦片加速) ``` **前端分层**: ``` Leaflet (2D) ├── 底图: 高德/天地图 WMTS ├── 管网图层: GeoServer WMS ├── 监测点位: GeoJSON 动态图层 (轮询 30s) │ ├── Marker: 流量/压力/液位/水质/阀门 (不同图标+颜色) │ └── Popup: 实时数据面板 ├── 热力图: leaflet.heat (点位密度) ├── DMA 分区: GeoJSON 面图层 (漏损率颜色) └── 轨迹回放: Leaflet.MovingMarker (巡检GPS) ``` **关键 API**: | 方法 | 路径 | 说明 | |------|------|------| | GET | /api/gis/points | 获取监测点位列表 (含坐标/类型/实时值) | | GET | /api/gis/points/heatmap | 获取热力图数据 | | GET | /api/gis/pipelines | 获取管网数据 | | GET | /api/gis/spatial-query | 矩形/圆形空间查询 | | GET | /api/gis/wms-proxy/** | GeoServer WMS 代理 | **模块依赖**: - 依赖:wm-iot(设备坐标数据)、PostGIS 扩展 - 提供:给供水生产(地图监测)、巡检(路线/GPS轨迹)、DMA(分区面图层) ### 1.5 IoT 设备接入层 > **对应 Issue**:#22 IoT接入层 **EMQX 配置要点**: ``` # emqx.conf listener.tcp.external = 1883 listener.ssl.external = 8883 # 设备认证 listener.tcp.external.enable_authn = true # HTTP 回调认证 auth.http.auth_req.url = "http://wm-iot:8082/api/iot/auth/device" # Kafka 桥接 bridges.kafka.iot_raw.servers = "kafka:9092" bridges.kafka.iot_raw.topic = "iot.raw.${device_type}" ``` **Kafka Topic 规划**: | Topic | 用途 | 分区数 | 保留时间 | |-------|------|:---:|:---:| | iot.raw.flow_meter | 流量计原始数据 | 6 | 7d | | iot.raw.pressure | 压力传感器原始数据 | 3 | 7d | | iot.raw.water_quality | 水质传感器原始数据 | 3 | 7d | | iot.raw.level | 液位计原始数据 | 3 | 7d | | iot.raw.valve | 阀门状态数据 | 3 | 7d | | iot.cmd.downlink | 下行指令 | 3 | 1d | | iot.event.online | 设备上下线事件 | 1 | 30d | | iot.event.alarm | 报警事件 | 3 | 90d | **API 端点**: | 方法 | 路径 | 说明 | |------|------|------| | POST | /api/iot/device | 注册设备 | | GET | /api/iot/device | 设备列表(分页/按类型/片区/状态过滤) | | GET | /api/iot/device/{sn} | 设备详情 | | PUT | /api/iot/device/{sn} | 更新设备信息 | | DELETE | /api/iot/device/{sn} | 注销设备 | | POST | /api/iot/device/{sn}/cmd | 下发指令 | | GET | /api/iot/telemetry/{sn} | 查询设备实时遥测数据 | ### 1.6 消息通知模块 > **对应 Issue**:#26 消息通知模块 **多渠道策略**: | 渠道 | 技术 | 适用场景 | |------|------|----------| | WebSocket | Spring WebSocket + STOMP | 实时报警弹窗、网页端通知 | | APP 推送 | 极光推送 (JPush) | 移动端报警、待办提醒 | | 短信 | 阿里云 SMS | 紧急报警、停水通知 | | 邮件 | JavaMail + 模板 | 日报周报推送 | **通知模板表**: ```sql CREATE TABLE notify_template ( id BIGSERIAL PRIMARY KEY, template_code VARCHAR(50) UNIQUE NOT NULL, template_name VARCHAR(100), channels VARCHAR(50) DEFAULT 'ws', -- ws,sms,push,email 逗号分隔 title_tpl VARCHAR(200), content_tpl TEXT NOT NULL, -- 支持变量 ${device_sn} ${metric_key} ${value} created_at TIMESTAMPTZ DEFAULT NOW() ); ``` --- ## 第2章 物联网平台 ### 2.1 多协议适配器 > **对应 Issue**:#28 MQTT 协议适配器 + 设备注册/发现, #29 Modbus/CoAP/HTTP 协议适配 **适配器接口**: ```java public interface DeviceAdapter { String getProtocol(); // "MQTT"/"Modbus"/"CoAP"/"HTTP" void onMessage(byte[] payload); // 处理设备上行数据 void sendCommand(String deviceSn, Command cmd); // 发送下行指令 DeviceInfo parseDeviceInfo(byte[] payload); // 解析设备注册信息 } ``` **AdapterFactory**: ```java @Component public class AdapterFactory { private final Map adapters = new HashMap<>(); public void register(String protocol, DeviceAdapter adapter) { ... } public DeviceAdapter get(String protocol) { ... } } ``` **MQTT 适配器核心逻辑**: ``` 订阅 iot.raw.* → 解析 JSON payload → DeviceModelMapper.convert() → 写入 Kafka (iot.raw.{device_type}) → 写入 Redis (最新值缓存) → 判断报警规则 → 触发报警 ``` **数据格式转换(DeviceModelMapper)**: ```java // 统一设备上报格式 { "deviceSn": "FLOW_001", "ts": 1718340000000, "metrics": [ {"key": "flow_rate", "value": 12.5, "unit": "m³/h"}, {"key": "total_flow", "value": 15230.8, "unit": "m³"} ] } ``` ### 2.2 设备影子服务 > **对应 Issue**:#30 设备影子服务 + OTA 固件升级 **Redis 存储结构**: ``` Key: shadow:{deviceSn} Value: { "reported": {"flow_rate": 12.5, "status": "online"}, "desired": {"report_interval": 60}, "version": 5, "lastSync": 1718340000000 } ``` **影子同步流程**: ``` 设备上报 → adapter.onMessage() → Redis: shadow.{sn}.reported = 最新状态 → 检查 desired 是否有待下发指令 → 下发 → 指令下发后 → iot.cmd.downlink → EMQX → 设备 设备离线 → 指令缓存到 Redis desired 设备上线 → 拉取 desired → 逐条下发 → 确认后清除 ``` ### 2.3 IoT 前端页面 > **对应 Issue**:#31 设备管理前端页面 **路由**: ``` /iot/devices → DeviceListView.vue (表格+筛选) /iot/devices/:sn → DeviceDetailView.vue (详情+遥测图表) /iot/devices/map → DeviceMapView.vue (GIS地图叠加) /iot/ota → FirmwareListView.vue (固件管理) ``` **DeviceListView** 组件树: ``` DeviceListView ├── SearchBar (片区下拉/设备类型下拉/状态多选/关键词输入) ├── DeviceTable (分页表格) │ └── columns: SN/名称/类型/片区/状态/最后上报时间/操作 └── DeviceFormDialog (新增/编辑 弹窗) ``` --- ## 第3章 流程引擎 > **对应 Issue**:#32 BPM流程核心, #33 BPMN.js设计器, #34 流程统计, #35 跨系统编排 ### 3.1 Camunda 集成 **职责边界**:基于 Camunda 7 提供 BPMN 2.0 流程引擎,封装流程定义、启动、任务处理 API。 **Camunda 配置**: ```yaml camunda.bpm: admin-user: id: admin password: ${CAMUNDA_PASSWORD} database: type: postgres history-level: full auto-deployment-enabled: true deployment-resource-pattern: classpath:/processes/*.bpmn ``` **API 端点**: | 方法 | 路径 | 说明 | |------|------|------| | POST | /api/bpm/process/deploy | 部署 BPMN 流程定义 | | POST | /api/bpm/process/start | 启动流程实例 | | GET | /api/bpm/task/todo | 查询待办任务 (分页/筛选) | | GET | /api/bpm/task/done | 查询已办任务 | | POST | /api/bpm/task/{taskId}/approve | 审批通过 | | POST | /api/bpm/task/{taskId}/reject | 驳回 | | POST | /api/bpm/task/{taskId}/transfer | 转办 | | POST | /api/bpm/task/{taskId}/delegate | 委派 | | POST | /api/bpm/task/{taskId}/add-sign | 加签 | | GET | /api/bpm/instance/{id}/diagram | 获取流程进度图 | | GET | /api/bpm/stats/efficiency | 流程效率统计 | | GET | /api/bpm/stats/bottleneck | 瓶颈节点分析 | **BPMN.js 设计器集成**: ``` 前端: bpmn-js (BPMN 2.0 建模器) ├── 自定义属性面板 (扩展 assignee/candidateGroups/deadline) ├── 流程模板保存/加载 (bpmn XML → 后端存储) └── 模板发布 → Camunda 自动部署 ``` **跨系统编排**: ```java // Webhook 回调机制 @Component public class ProcessWebhookService { // 流程节点执行完成后回调外部系统 public void fireEvent(String processInstanceId, String activityId) { // 查询该节点的 Webhook 配置 → HTTP POST 回调 } } ``` --- ## 第4章 数据引擎 ### 4.1 实时数据采集 > **对应 Issue**:#41 实时流数据采集 **Kafka Consumer 设计**: ```java @KafkaListener(topics = "iot.raw.#{__listener.topicPattern}") public void consumeIotData(ConsumerRecord record) { TelemetryData data = parseMessage(record.value()); // 1. 写入 TDengine (批量写入 1000条/5秒) tdengineBuffer.add(data); // 2. 写入 Redis (最新值) redisTemplate.opsForHash().put("telemetry:latest", data.getDeviceSn()+":"+data.getMetricKey(), data); // 3. 触发报警规则检查 alertChecker.check(data); } ``` ### 4.2 数据接入层 > **对应 Issue**:#42 数据接入层 **多种接入方式**: | 方式 | 端点 | 说明 | |------|------|------| | REST Push | POST /api/data/ingest/rest | 第三方系统推送 JSON | | WebSocket | ws://host/data/ws | 实时数据流双向通信 | | 批量导入 | POST /api/data/ingest/batch | CSV/Excel 文件上传解析 | | 数据库直连 | JDBC Source Connector | 定时拉取外部数据库 | **批量导入处理**: ``` 上传文件 → 格式校验(文件头/列映射) → 数据预览(前100行) → 用户确认映射 → 异步处理(Spring @Async) → 逐行校验(水利标准字段映射) → 写入 TDengine/PostgreSQL → 返回处理结果(成功X条/失败Y条) ``` ### 4.3 数据存储层 > **对应 Issue**:#43 数据存储层 **TDengine 存储策略**: - 原始数据:保留 90 天 (iot_telemetry) - 小时聚合:保留 3 年 (iot_telemetry_hourly) - 日聚合:保留 10 年 (iot_telemetry_daily) **MinIO 存储策略**: - 文件按 `{bucket}/{yyyy}/{MM}/{dd}/{uuid}.{ext}` 命名 - 视频录像:保留 30 天 (lifecycle policy) - 照片附件:保留 1 年 - 固件文件:永久保留 ### 4.4 数据治理 > **对应 Issue**:#44 数据治理 **水利数据对象标准映射表**: ```sql CREATE TABLE data_field_mapping ( id BIGSERIAL PRIMARY KEY, source_field VARCHAR(100) NOT NULL, -- 原始字段名 source_system VARCHAR(50), -- 来源系统 target_field VARCHAR(100) NOT NULL, -- 标准字段名 data_type VARCHAR(20), -- VARCHAR/INT/DOUBLE/DATE unit VARCHAR(20), transform_rule VARCHAR(200), -- 转换规则 (e.g. *1000, DATE_FORMAT) created_at TIMESTAMPTZ DEFAULT NOW() ); ``` **清洗规则链**: ``` 原始数据 → 空值检查(填充/丢弃)→ 异常值检测(IQR/3σ) → 格式转换 → 去重(时间窗口内) → 质量评分(0-100) → 入仓 ``` --- ## 第5章 供水生产管理 ### 5.1 生产总览大屏 > **对应 Issue**:#61 总览大屏 **数据聚合 API**: ``` GET /api/production/dashboard/summary?area={area} Response: { "area": "一体化水厂", "todayInflow": 15230.5, // m³ "todayOutflow": 14890.2, "yesterdayTotalSupply": 31000.0, "sourceWaterQuality": { "turbidity": 3.2, "ph": 7.8 }, "treatedWaterQuality": { "turbidity": 0.3, "residualCl": 0.5, "qualified": true }, "activeAlerts": [...], "deviceStats": { "total": 156, "online": 142, "fault": 3 }, "energy": { "electricity": 1250.5, "waterUse": 320.0 }, "chemical": { "coagulant": 85.2, "disinfectant": 12.5 } } ``` **前端 ECharts 组件**: ``` DashboardView.vue ├── AreaSelector (片区下拉,系统管理员看全部) ├── SummaryCards (4个数字卡片: 进水/出水/昨日供水/设备在线率) ├── WaterInOutChart (进出水量趋势折线图,24h) ├── WaterQualityChart (水质指标仪表盘) ├── AlertList (实时报警滚动列表) ├── DeviceStatusPie (设备状态饼图) ├── EnergyBar (能耗柱状图) └── ChemicalBar (药耗柱状图) ``` ### 5.2 在线监测列表 > **对应 Issue**:#62 在线监测列表 **路由**:`/production/monitor` ``` MonitorListView.vue ├── FilterPanel │ ├── 片区 (select: 6个片区) │ ├── 位置类型 (select: 水厂/调压站/管网/村队) │ ├── 设备类型 (select: 全部/流量计/压力/液位/水质/阀门) │ ├── 状态 (checkbox: 在线/离线/故障) │ └── 关键词搜索 ├── MonitorTable │ └── columns: 站点名称/片区/位置类型/设备SN/实时值(Multi-metric)/采集时间/状态 ├── ExportButton (导出 Excel) └── AutoRefresh (5s/10s/30s 切换) ``` ### 5.3 视频监控与 AI > **对应 Issue**:#63 视频监控+AI闯入检测 **视频流接入**: ``` 摄像头(RTSP/GB28181) → NVR/视频平台 → RTSP 流地址 → wm-production 代理 → 前端 HLS/WebRTC 播放 ``` **AI 闯入检测**: ``` 视频帧 → YOLOv8 推理 → 人员检测 → 闯入区域判断 → 触发 Alert (level=emergency) → WebSocket 实时弹窗 → 录制 30s 视频快照 → MinIO 存储 ``` ### 5.4 GIS 地图展示 > **对应 Issue**:#64 GIS地图展示 **点位分类展示**: ``` 图层: ├── 流量计 (蓝色水滴) ├── 压力传感器 (绿色圆形) ├── 液位计 (青色三角形) ├── 水质传感器 (紫色菱形) ├── 阀门 (红色方形: 开/绿: 关) └── 管网 (蓝色线条 → WMS 瓦片) ``` ### 5.5 水质管控 > **对应 Issue**:#65 药剂投加监控, #66 水质检测台账 **全工艺监控参数**: ``` 混凝: 进水浊度 → 絮凝剂投加速率 沉淀: 沉淀池液位、出水浊度 过滤: 滤池液位、过滤速度 消毒: 消毒剂投加速率 → 出厂水余氯 ``` **合格判定 (GB5749-2022)**: ```java public boolean isQualified(QualityRecord record) { return record.getTurbidity() <= 1.0 // NTU && record.getPh() >= 6.5 && record.getPh() <= 8.5 && record.getResidualCl() >= 0.3 // mg/L && record.getColiform() == 0; } ``` ### 5.6 调度工作台 > **对应 Issue**:#68 值班管理, #69 调度指令, #70 应急推演 **值班流程图**: ``` 排班(按月) → 值班开始 → 实时监测+指令处理 → 交接班(记录日志) → 值班结束 ``` **应急推演四场景**: 1. 爆管模拟:选择管线位置 → 分析阀门关闭策略 → 生成受影响区域 → 应急供水方案 2. 水质异常:选择污染源 → 扩散范围模拟 → 排放/关闭方案 3. 设备故障:选择设备 → 切换备用方案 4. 停水预案:区域选择 → 影响用户统计 → 通知方案 ### 5.7 报警管理 > **对应 Issue**:#65(含药剂报警), #67(报警管理中心) **报警生命周期**: ``` 规则命中 → 创建 Alert(去重检查) → WebSocket推送 + APP推送 → 未确认(持续提醒) → 确认 → 派单(生成工单) → 处理 → 恢复 → 归档 ``` ### 5.8 系统管理 > **对应 Issue**:#74 系统管理 **路由**: ``` /system/roles → 角色管理 (CRUD + 权限分配树) /system/users → 用户管理 (CRUD + 角色分配) /system/depts → 部门管理 (树形表格 + 拖拽排序) /system/menus → 菜单管理 (树形表格) /system/logs → 日志查看 (搜索 + 导出) /system/dict → 字典管理 (CRUD) ``` --- ## 第6章 营业收费 ### 6.1 营收统一管理 > **对应 Issue**:#46 SSO 单点登录, #47 平台运维审计 + 用户授权 **OAuth2 授权码流程**: ``` 用户访问客户端 → 重定向 /oauth2/authorize → 登录 → 授权确认 → 回调 redirect_uri?code=xxx → 客户端换取 access_token → POST /oauth2/token {grant_type: authorization_code, code, client_id, client_secret} → {access_token, refresh_token, expires_in} ``` ### 6.2 报装管理系统 > **对应 Issue**:#48 报装核心流程, #49 报装查询统计 **状态机**: ``` pre_accept → site_survey → engineering → dispatched → constructing → completed ↘ 驳回 → pre_accept (重新提交) ``` **报装首页概览 API**: ``` GET /api/revenue/install/overview → { total, pending, inProgress, completedThisMonth, avgDays } ``` ### 6.3 抄表与收费 > **对应 Issue**:#50 抄表管理, #51 账单生成+多支付渠道 **阶梯水价计算公式**: ```java // 以居民用水为例 (三阶梯): // Tier 1: 0-15 m³ → 2.80 元/m³ // Tier 2: 15-25 m³ → 4.20 元/m³ // Tier 3: > 25 m³ → 8.40 元/m³ BigDecimal calcWaterFee(BigDecimal usage, String customerType) { List tiers = priceService.getTiers(customerType); BigDecimal fee = BigDecimal.ZERO; BigDecimal remaining = usage; for (PriceTier tier : tiers) { BigDecimal tierUsage = min(remaining, tier.getRange()); fee = fee.add(tierUsage.multiply(tier.getUnitPrice())); remaining = remaining.subtract(tierUsage); if (remaining.compareTo(BigDecimal.ZERO) <= 0) break; } return fee; } ``` **支付渠道集成**: | 渠道 | 接口 | 回调 | |------|------|------| | 支付宝 | /api/revenue/payment/alipay/create | /api/revenue/payment/alipay/notify | | 微信支付 | /api/revenue/payment/wechat/create | /api/revenue/payment/wechat/notify | | 柜台 | /api/revenue/payment/counter/pay | 无需回调 | | POS | /api/revenue/payment/pos/pay | 无需回调 | ### 6.4 表务管理 > **对应 Issue**:#53 表务管理 **水表全生命周期状态机**: ``` 采购入库(in_stock) → 安装出库 → 已安装(installed) → 暂拆(dismantled) → 复接(installed) → 故障换表 - 旧表(scrapped) + 新表(installed) → 周期换表 - 旧表(scrapped/renovated) + 新表(installed) → 销户撤表(scrapped) 已安装 → 校表(calibrating) → 已校表 → 重新安装 或 报废 ``` **12 个操作**:入库、出库、安装、暂拆、复接、故障换表、周期换表、销户撤表、新表交回、旧表交回、报废、翻新。 ### 6.5 集抄系统 > **对应 Issue**:#58 远传集抄, #59 DMA分区计量+漏损分析 **批量抄表**: ``` 定时任务 (每日0点) → MQTT 批量抄表指令 → 远传水表响应 → Kafka → 数据引擎解析 → 写入 rev_reading → 标记异常读数 (负值/突变/零值超过N天) → 生成核查工单 ``` **DMA 分区漏损分析**: ``` DMA 入口流量计 - Σ(分区内所有户表) = 漏损量 夜间最小流量法 (02:00-04:00) → 排除正常用水 → 估算物理漏损 ECharts: ├── 分区漏损率柱状图 ├── 漏损量趋势折线 (日/周/月) ├── 夜间最小流量趋势 (7天) └── 供售水量对比 (桑基图 or 并排柱状) ``` ### 6.6 工单管理 > **对应 Issue**:#60 工单管理 **工单流转**: ``` 创建(手动/报警触发/巡检上报) → 分派(按片区/技能) → 接受 → 处理中 → 处理完成(填写结果+拍照) → 审核 → 关闭 → 驳回 → 处理中 ``` **跨模块联动**: - 报警中心 → 自动创建报警工单 - 巡检问题上报 → 自动创建巡检工单 - 设备故障 → 自动创建维修工单 - BPM 流程引擎 → 复杂审批流程 --- ## 第7章 巡检管理系统 > **对应 Issue**:#75 巡检路线+任务, #76 巡检执行+GPS, #77 问题上报+工单, #78 统计分析 ### 7.1 巡检配置 **路线设计**: ```json { "routeName": "托里片区巡检路线A", "area": "托里片区", "checkpoints": [ {"seq": 1, "name": "托里水厂进水口", "lng": 82.123, "lat": 44.567, "deviceIds": [101,102], "checkItems": [{"item":"流量计读数","standard":"正常范围"}, {"item":"管道外观","standard":"无泄漏"}]} ] } ``` ### 7.2 巡检执行 **GPS 轨迹记录策略**: - 巡检开始 → 启动 GPS 采集 (每 10s 上报一次坐标) - 到达检查点 → 系统自动判断 (距离 < 30m) - 填写检查项 → 拍照 → 签字确认 - 异常 → 问题上报 (拍照+文字+语音) - 巡检结束 → 停止 GPS → 计算总里程 ### 7.3 统计分析 **统计维度**: ```sql -- 每日汇总 (由 cron 凌晨执行) INSERT INTO patrol_stats_daily SELECT CURRENT_DATE, assignee_id, area_id, COUNT(*), SUM(CASE WHEN status='completed' THEN 1 ELSE 0 END), SUM(distance), SUM(EXTRACT(EPOCH FROM actual_end - actual_start)/60), (SELECT COUNT(*) FROM patrol_issue WHERE task_id IN (...)) FROM patrol_task WHERE plan_date = CURRENT_DATE - 1 GROUP BY assignee_id, area_id ``` **统计 API**: ``` GET /api/patrol/stats/completion-rate?start=2026-06-01&end=2026-06-14 GET /api/patrol/stats/mileage?assigneeId={id}&month=2026-06 GET /api/patrol/stats/attendance?month=2026-06 GET /api/patrol/stats/issues?category=device_fault&start=2026-06-01 GET /api/patrol/rank?type=mileage&start=2026-06-01&end=2026-06-14&limit=20 ``` --- ## 第8章 移动APP > **对应 Issue**:#79 Flutter统一入口, #80 供水管理移动端, #81 巡检+营收移动端 ### 8.1 Flutter 项目结构 ``` mobile/lib/ ├── main.dart # App入口,路由配置 ├── app.dart # MaterialApp + Provider 注入 ├── pages/ │ ├── login/login_page.dart # 统一登录页 (SSO) │ ├── home/home_page.dart # 三合一底部导航首页 │ ├── production/ # 供水管理 │ │ ├── monitor_page.dart # 实时监测列表 │ │ ├── alert_page.dart # 报警列表 │ │ └── dispatch_page.dart # 调度指令 │ ├── patrol/ # 巡检 │ │ ├── task_list_page.dart # 任务列表 │ │ ├── patrol_page.dart # 巡检执行 (GPS+拍照) │ │ ├── gps_track_page.dart # 轨迹查看 │ │ └── issue_report_page.dart # 问题上报 │ └── revenue/ # 营收 │ ├── meter_read_page.dart # 移动抄表 │ ├── bill_query_page.dart # 账单查询 │ └── install_progress_page.dart # 报装进度 ├── services/ # API 服务层 │ ├── auth_service.dart │ ├── production_service.dart │ ├── patrol_service.dart │ └── revenue_service.dart ├── models/ # 数据模型 └── widgets/ # 公共组件 ``` ### 8.2 底部 Tab 导航 ``` 供水管理 | 巡检 | 营收 🏭 🔍 💰 ``` ### 8.3 离线缓存策略 巡检场景(山区/偏远站点可能无网络): ```dart // 使用 Hive 本地存储 Future syncTaskData() async { if (await hasNetwork()) { var tasks = await patrolService.fetchTasks(); await hiveBox.put('tasks', tasks); } } // 离线巡检:数据暂存本地,网络恢复后自动上传 Future reportIssue(Issue issue) async { if (await hasNetwork()) { await patrolService.reportIssue(issue); } else { await offlineBox.add(issue.toJson()); } } ``` --- ## 第9章 大数据分析 > **对应 Issue**:#36 ETL管道, #37 BI看板, #38 运营仪表盘, #39 需水量预测, #40 报告生成 ### 9.1 ETL 数据管道 **Flink 流式处理**: ``` Kafka(iot.raw.*) → Flink 作业 → 数据解析 → 异常过滤 → 聚合(1min窗口) → Sink: TDengine (时序) + PostgreSQL (汇总) ``` ### 9.2 BI 看板集成 **推荐方案**:Apache Superset 嵌入 ``` 前端 iframe 嵌入 Superset Dashboard (SSO token 透传) ├── 供水运营总览 ├── 营收分析 ├── 巡检统计 └── 自定义 SQL 查询 ``` ### 9.3 专供水专题大屏 **大屏布局 (1920×1080)**: ``` ┌─────────────────────────────────────────────────────┐ │ 精河县智慧水务综合管理平台 2026-06-14 14:30 │ ├──────────┬──────────┬──────────┬──────────────────────┤ │ 今日进水 │ 今日出水 │ 昨日供水 │ 设备在线率 │ ├──────────┴──────────┴──────────┴──────────────────────┤ │ 进出水量趋势 (折线图) │ 供水区域 GIS 地图 │ │ │ (监测点位+报警闪烁) │ ├───────────────────────────┤ │ │ 水质达标率 (仪表盘) │ │ │ 报警分布 (饼图) │ │ │ 能耗药耗 (柱状图) │ │ ├──────────────────────────────────────────────────────┤ │ 实时报警滚动 | 巡检任务统计 | 营收总额统计 │ └──────────────────────────────────────────────────────┘ ``` ### 9.4 需水量预测 **模型选择**: - 短期 (24h):ARIMA 时间序列 (数据量要求低,可快速部署) - 长期 (月):LSTM 神经网络 (需积累 > 12个月历史数据后启用) **API**: ``` GET /api/bi/predict/water-demand?area={area}&hours=24 Response: [{ts, predicted, lowerBound, upperBound}, ...] ``` --- ## 文档版本 | 版本 | 日期 | 修订内容 | 修订人 | |------|------|----------|--------| | v2.0 | 2026-06-14 | 详细设计规格书,含全部模块DB/API/组件/数据流 | bot_pm | --- ## 附录:Issue ↔ 章节对照表 | Issue # | 标题 | 设计文档章节 | |:---:|------|------| | 17 | 项目框架搭建 | §1.1 Maven模块结构 | | 18 | 数据库设计 | §1.2 数据库完整DDL | | 19 | 认证授权系统 | §1.3 认证授权系统设计 | | 20 | 通用模块 | §1.1 wm-common + §1.3 统一响应 | | 21 | GIS引擎集成 | §1.4 GIS引擎集成 | | 22 | IoT设备接入层 | §1.5 IoT设备接入层 | | 23 | 前端框架搭建 | §1.1 frontend/ 结构 + §5.1 组件树 | | 24 | Flutter移动端框架 | §8.1 Flutter项目结构 | | 25 | DevOps | §1.1 docker/ + §1.2 技术栈 | | 26 | 消息通知模块 | §1.6 消息通知模块 | | 28 | MQTT协议适配器 | §2.1 多协议适配器 | | 29 | Modbus/CoAP/HTTP适配 | §2.1 AdapterFactory | | 30 | 设备影子+OTA | §2.2 设备影子服务 | | 31 | 设备管理前端 | §2.3 IoT前端页面 | | 32 | BPM流程引擎核心 | §3.1 Camunda集成 | | 33 | BPMN.js设计器 | §3.1 BPMN.js集成 | | 34 | BPM统计评估 | §3.1 API端点 (stats) | | 35 | BPM跨系统编排 | §3.1 Webhook回调 | | 36 | ETL数据管道 | §9.1 ETL数据管道 | | 37 | BI看板 | §9.2 BI看板集成 | | 38 | 运营仪表盘+大屏 | §9.3 供水专题大屏 | | 39 | 需水量预测 | §9.4 需水量预测 | | 40 | 报告生成 | §9.4 报告生成 | | 41 | 实时流数据采集 | §4.1 实时数据采集 | | 42 | 数据接入层 | §4.2 数据接入层 | | 43 | 数据存储层 | §4.3 数据存储层 | | 44 | 数据治理 | §4.4 数据治理 | | 46 | SSO单点登录 | §6.1 营收统一管理 | | 48 | 报装核心流程 | §6.2 报装管理系统 | | 49 | 报装查询统计 | §6.2 状态机+概览 | | 50 | 抄表管理 | §6.3 抄表与收费 | | 51 | 账单+多支付 | §6.3 阶梯水价+支付 | | 53 | 表务管理 | §6.4 表务管理 | | 54 | 客服工作台 | §1.2.6 cs_kb_article | | 56 | 微信网厅前端 | §1.2.6 rev_wx_pay_order | | 58 | 远传集抄 | §6.5 批量抄表 | | 60 | 工单管理 | §6.6 工单管理 | | 61 | 总览大屏 | §5.1 生产总览大屏 | | 62 | 在线监测列表 | §5.2 在线监测列表 | | 63 | 视频监控+AI | §5.3 视频监控与AI | | 64 | GIS地图展示 | §5.4 GIS地图展示 | | 65 | 药剂投加监控 | §5.5 水质管控 | | 66 | 水质检测台账 | §5.5 合格判定 | | 68 | 值班管理 | §5.6 调度工作台 | | 69 | 调度指令 | §5.6 指令台账 | | 70 | 应急推演 | §5.6 应急推演四场景 | | 74 | 系统管理 | §5.8 系统管理 | | 75 | 巡检路线+任务 | §7.1 巡检配置 | | 76 | 巡检执行+GPS | §7.2 巡检执行 | | 77 | 问题上报+工单 | §1.2.8 patrol_issue | | 78 | 统计分析 | §7.3 统计分析 | | 79 | Flutter统一入口 | §8.2 底部Tab导航 | | 80 | 供水管理移动端 | §8.1 production/ 页面 | | 81 | 巡检+营收移动端 | §8.1 patrol/ + revenue/ | > 📌 已关闭 Issue 也列入对照表,方便追溯。