智慧水务管理系统 - 精河县供水工程综合管理平台

智慧水务管理系统 — 详细设计规格书

版本: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)

-- 部门表
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)

-- 设备模型定义
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)

-- 超级表:设备遥测时序数据
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)

-- 用水户档案
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 报装管理表

-- 报装申请
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 客服与微信网厅

-- 知识库
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 工单管理

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 巡检系统

-- 巡检区域
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 供水生产管理

-- 能耗记录
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 报警管理

-- 报警规则
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 配置中心

-- 系统配置
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 <token>
  → 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} 注销应用

数据权限策略

// 数据权限注解
@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 + 模板 日报周报推送

通知模板表

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 协议适配

适配器接口

public interface DeviceAdapter {
    String getProtocol();                          // "MQTT"/"Modbus"/"CoAP"/"HTTP"
    void onMessage(byte[] payload);                // 处理设备上行数据
    void sendCommand(String deviceSn, Command cmd); // 发送下行指令
    DeviceInfo parseDeviceInfo(byte[] payload);    // 解析设备注册信息
}

AdapterFactory

@Component
public class AdapterFactory {
    private final Map<String, DeviceAdapter> 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)

// 统一设备上报格式
{
  "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 配置

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 自动部署

跨系统编排

// Webhook 回调机制
@Component
public class ProcessWebhookService {
    // 流程节点执行完成后回调外部系统
    public void fireEvent(String processInstanceId, String activityId) {
        // 查询该节点的 Webhook 配置 → HTTP POST 回调
    }
}

第4章 数据引擎

4.1 实时数据采集

对应 Issue:#41 实时流数据采集

Kafka Consumer 设计

@KafkaListener(topics = "iot.raw.#{__listener.topicPattern}")
public void consumeIotData(ConsumerRecord<String, String> 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 数据治理

水利数据对象标准映射表

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)

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 账单生成+多支付渠道

阶梯水价计算公式

// 以居民用水为例 (三阶梯):
// 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<PriceTier> 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 巡检配置

路线设计

{
  "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 统计分析

统计维度

-- 每日汇总 (由 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 离线缓存策略

巡检场景(山区/偏远站点可能无网络):

// 使用 Hive 本地存储
Future<void> syncTaskData() async {
    if (await hasNetwork()) {
        var tasks = await patrolService.fetchTasks();
        await hiveBox.put('tasks', tasks);
    }
}
// 离线巡检:数据暂存本地,网络恢复后自动上传
Future<void> 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 也列入对照表,方便追溯。