-- PostgreSQL + PostGIS 数据库完整 DDL 建表脚本
-- 生成时间: 2026-06-15
-- 作者: bot_dev1 (基于 Issue #18 任务)

-- ========= 部门管理 =========
CREATE TABLE sys_dept (
    id BIGSERIAL PRIMARY KEY,
    parent_id BIGINT,
    dept_name VARCHAR(100) NOT NULL,
    dept_type VARCHAR(20),  -- water_bureau(水利局)/water_company(水务公司)/ops(运维)
    sort_order INT DEFAULT 0,
    status SMALLINT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 用户权限体系
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,
    real_name VARCHAR(50),
    phone VARCHAR(20),
    email VARCHAR(100),
    role_type VARCHAR(30),  -- admin/leader/manager/operator/tech
    status SMALLINT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 角色表
CREATE TABLE sys_role (
    id BIGSERIAL PRIMARY KEY,
    role_name VARCHAR(50) UNIQUE,
    role_key VARCHAR(50) UNIQUE,  -- admin/supervisor/biz_manager/field_ops/tech_maintain
    data_scope VARCHAR(20),       -- ALL/DEPT/SELF
    description VARCHAR(200),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 角色-用户关联
CREATE TABLE sys_user_role (
    user_id BIGINT REFERENCES sys_user(id),
    role_id BIGINT REFERENCES sys_role(id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (user_id, role_id)
);

-- 菜单管理
CREATE TABLE sys_menu (
    id BIGSERIAL PRIMARY KEY,
    parent_id BIGINT,
    menu_name VARCHAR(50) NOT NULL,
    menu_key VARCHAR(50) UNIQUE NOT NULL,
    menu_type VARCHAR(20),      -- directory/menu/button
    path VARCHAR(200),
    component VARCHAR(200),
    perms VARCHAR(100),
    icon VARCHAR(100),
    sort_order INT DEFAULT 0,
    visible SMALLINT DEFAULT 1,
    status SMALLINT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 角色-菜单关联
CREATE TABLE sys_role_menu (
    role_id BIGINT REFERENCES sys_role(id),
    menu_id BIGINT REFERENCES sys_menu(id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (role_id, menu_id)
);

-- ========= 物联网设备管理 =========
-- 设备模型定义
CREATE TABLE iot_device_model (
    id BIGSERIAL PRIMARY KEY,
    model_key VARCHAR(50) UNIQUE,
    model_name VARCHAR(100),
    vendor VARCHAR(100),
    protocol VARCHAR(20),           -- MQTT/Modbus/CoAP/HTTP
    properties JSONB,               -- 属性定义
    commands JSONB,                 -- 支持指令
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 设备实例
CREATE TABLE iot_device (
    id BIGSERIAL PRIMARY KEY,
    device_sn VARCHAR(100) UNIQUE,
    device_name VARCHAR(200),
    model_id BIGINT REFERENCES iot_device_model(id),
    device_type VARCHAR(30),        -- flow_meter/pressure/valve/water_quality/level
    position_type VARCHAR(20),      -- water_plant/pressure_station/pipe_network/village
    loc_lng DECIMAL(11,8),          -- 经度
    loc_lat DECIMAL(11,8),          -- 纬度
    geom GEOMETRY(Point, 4326),     -- PostGIS 空间坐标
    area VARCHAR(50),               -- 所属片区
    station_id BIGINT,              -- 所属站点
    status VARCHAR(20),             -- online/offline/maintenance/fault
    last_report_time TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 设备遥测数据缓存
CREATE TABLE iot_telemetry_cache (
    id BIGSERIAL PRIMARY KEY,
    device_sn VARCHAR(100) NOT NULL,
    metric_key VARCHAR(50) NOT NULL,
    metric_value DECIMAL(20,4),
    quality SMALLINT DEFAULT 0,      -- 0:正常 1:可疑 2:错误
    ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 设备心跳记录
CREATE TABLE iot_device_heartbeat (
    id BIGSERIAL PRIMARY KEY,
    device_sn VARCHAR(100) NOT NULL,
    online_status VARCHAR(10),      -- online/offline
    battery_level DECIMAL(5,2),
    signal_strength SMALLINT,
    ip_address VARCHAR(50),
    heartbeat_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 设备固件管理
CREATE TABLE iot_firmware (
    id BIGSERIAL PRIMARY KEY,
    firmware_name VARCHAR(100),
    version VARCHAR(50),
    device_type VARCHAR(30),
    file_url VARCHAR(500),
    file_size BIGINT,
    md5_checksum VARCHAR(32),
    changelog TEXT,
    status VARCHAR(20),             -- draft/published/rejected
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 设备固件升级记录
CREATE TABLE iot_firmware_upgrade (
    id BIGSERIAL PRIMARY KEY,
    device_sn VARCHAR(100),
    firmware_id BIGINT REFERENCES iot_firmware(id),
    status VARCHAR(20),             -- pending/downloading/installed/failed
    progress DECIMAL(5,2),          -- 0-100
    error_message TEXT,
    upgrade_time TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- ========= 营业收费 =========
-- 用水户
CREATE TABLE rev_customer (
    id BIGSERIAL PRIMARY KEY,
    customer_no VARCHAR(30) UNIQUE,     -- 户号
    customer_name VARCHAR(100) NOT NULL,
    customer_type VARCHAR(20),          -- residential/business/enterprise/institution
    area VARCHAR(50),
    address VARCHAR(300),
    phone VARCHAR(20),
    id_card VARCHAR(18),
    contract_no VARCHAR(50),
    status VARCHAR(20) DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 水表档案
CREATE TABLE rev_meter (
    id BIGSERIAL PRIMARY KEY,
    meter_no VARCHAR(50) UNIQUE,
    customer_id BIGINT REFERENCES rev_customer(id),
    device_id BIGINT REFERENCES iot_device(id),
    caliber VARCHAR(10),                          -- DN15/DN20/DN40...
    meter_type VARCHAR(20),                       -- mechanical/ultrasonic/electromagnetic
    initial_reading DECIMAL(10,2),
    install_date DATE,
    status VARCHAR(20),                           -- active/dismantled/scrapped/repaired
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 抄表计划
CREATE TABLE rev_reading_schedule (
    id BIGSERIAL PRIMARY KEY,
    meter_id BIGINT REFERENCES rev_meter(id),
    reading_date DATE,
    reading_type VARCHAR(20),          -- manual/remote/estimate
    assignee_id BIGINT REFERENCES sys_user(id),
    status VARCHAR(20),                -- pending/in_progress/completed
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 抄表记录
CREATE TABLE rev_reading (
    id BIGSERIAL PRIMARY KEY,
    meter_id BIGINT REFERENCES rev_meter(id),
    reading_date DATE,
    prev_reading DECIMAL(10,2),
    curr_reading DECIMAL(10,2),
    consumption DECIMAL(10,2),       -- 用水量
    read_type VARCHAR(20),           -- manual/remote/estimate
    reader_id BIGINT REFERENCES sys_user(id),
    photo_url VARCHAR(500),
    gps_lng DECIMAL(11,8),
    gps_lat DECIMAL(11,8),
    verified SMALLINT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 水费标准
CREATE TABLE rev_water_rate (
    id BIGSERIAL PRIMARY KEY,
    rate_name VARCHAR(100),
    customer_type VARCHAR(20),      -- residential/business/enterprise/institution
    step_threshold JSONB,          -- 阶梯阈值
    step_rates JSONB,              -- 阶梯价格
    start_date DATE,
    end_date DATE,
    status SMALLINT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 水费账单
CREATE TABLE rev_bill (
    id BIGSERIAL PRIMARY KEY,
    customer_id BIGINT REFERENCES rev_customer(id),
    bill_period VARCHAR(10),         -- 2026-06
    consumption DECIMAL(10,2),
    water_fee DECIMAL(10,2),
    sewage_fee DECIMAL(10,2),
    total_fee DECIMAL(10,2),
    paid_fee DECIMAL(10,2) DEFAULT 0,
    status VARCHAR(20),              -- pending/partial/paid/overdue
    due_date DATE,
    paid_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 收费记录
CREATE TABLE rev_payment (
    id BIGSERIAL PRIMARY KEY,
    bill_id BIGINT REFERENCES rev_bill(id),
    payment_no VARCHAR(50) UNIQUE,
    payment_type VARCHAR(20),       -- cash/alipay/wechat/bank_transfer
    amount DECIMAL(10,2),
    payment_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    operator_id BIGINT REFERENCES sys_user(id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- ========= 巡检系统 =========
-- 巡检路线
CREATE TABLE patrol_route (
    id BIGSERIAL PRIMARY KEY,
    route_name VARCHAR(100) NOT NULL,
    area VARCHAR(50),
    route_points JSONB,                -- 巡检点信息
    estim_duration INT,                -- 预计时长(分钟)
    status SMALLINT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 巡检任务
CREATE TABLE patrol_task (
    id BIGSERIAL PRIMARY KEY,
    route_id BIGINT REFERENCES patrol_route(id),
    assignee_id BIGINT REFERENCES sys_user(id),
    task_date DATE,
    plan_start TIME,
    plan_end TIME,
    actual_start TIMESTAMP,
    actual_end TIMESTAMP,
    status VARCHAR(20),               -- pending/in_progress/completed/expired
    distance DECIMAL(8,2),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 巡检记录
CREATE TABLE patrol_record (
    id BIGSERIAL PRIMARY KEY,
    task_id BIGINT REFERENCES patrol_task(id),
    point_seq INT,
    device_id BIGINT REFERENCES iot_device(id),
    check_items JSONB,                 -- 检查项结果
    gps_lng DECIMAL(11,8),
    gps_lat DECIMAL(11,8),
    record_time TIMESTAMP,
    photo_url VARCHAR(500),
    remark TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 巡检标准
CREATE TABLE patrol_standard (
    id BIGSERIAL PRIMARY KEY,
    standard_name VARCHAR(100),
    device_type VARCHAR(30),
    check_items JSONB,                -- 检查项配置
    scoring_rules JSONB,              -- 评分规则
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- ========= 报警管理 =========
-- 报警规则
CREATE TABLE alert_rule (
    id BIGSERIAL PRIMARY KEY,
    rule_name VARCHAR(100) NOT NULL,
    device_type VARCHAR(30),
    metric_key VARCHAR(50),
    alert_level VARCHAR(10),           -- info/warning/critical/emergency
    condition_expr VARCHAR(200),       -- 条件表达式
    threshold_value VARCHAR(50),
    debounce_sec INT DEFAULT 300,      -- 去重窗口(秒)
    notify_scheme_id BIGINT,
    enabled SMALLINT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 报警事件
CREATE TABLE alert_event (
    id BIGSERIAL PRIMARY KEY,
    rule_id BIGINT REFERENCES alert_rule(id),
    device_id BIGINT REFERENCES iot_device(id),
    device_sn VARCHAR(100),
    metric_key VARCHAR(50),
    metric_value DECIMAL(20,4),
    threshold VARCHAR(50),
    alert_level VARCHAR(10),
    message TEXT,
    confirmed_by BIGINT REFERENCES sys_user(id),
    confirmed_at TIMESTAMP,
    dispatched SMALLINT DEFAULT 0,     -- 是否已派单
    resolved_at TIMESTAMP,
    resolved_by BIGINT REFERENCES sys_user(id),
    resolution TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 报警处理记录
CREATE TABLE alert_handle_record (
    id BIGSERIAL PRIMARY KEY,
    alert_id BIGINT REFERENCES alert_event(id),
    handler_id BIGINT REFERENCES sys_user(id),
    action_type VARCHAR(20),           -- acknowledge/resolve/transfer
    action_content TEXT,
    handle_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 通知方案
CREATE TABLE alert_notify_scheme (
    id BIGSERIAL PRIMARY KEY,
    scheme_name VARCHAR(100),
    channels JSONB,                   -- 通知渠道配置
    recipients JSONB,                  -- 接收人配置
    conditions JSONB,                  -- 触发条件
    status SMALLINT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- ========= 操作日志 =========
-- 系统操作日志
CREATE TABLE sys_operation_log (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT REFERENCES sys_user(id),
    operation_type VARCHAR(50),
    operation_name VARCHAR(100),
    target_type VARCHAR(50),
    target_id BIGINT,
    request_method VARCHAR(10),
    request_url VARCHAR(500),
    request_params TEXT,
    response_data TEXT,
    ip_address VARCHAR(50),
    user_agent TEXT,
    execution_time BIGINT,            -- 执行时间(毫秒)
    status SMALLINT,                   -- 0:失败 1:成功
    error_message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- ========= 系统配置 =========
-- 系统参数配置
CREATE TABLE sys_config (
    id BIGSERIAL PRIMARY KEY,
    config_key VARCHAR(100) UNIQUE,
    config_name VARCHAR(100),
    config_value TEXT,
    config_type VARCHAR(20),         -- string/number/json
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 数据字典
CREATE TABLE sys_dict (
    id BIGSERIAL PRIMARY KEY,
    dict_type VARCHAR(100),
    dict_code VARCHAR(50),
    dict_label VARCHAR(100),
    dict_value VARCHAR(100),
    sort_order INT DEFAULT 0,
    status SMALLINT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- ========= 索引创建 =========
-- 用户权限相关索引
CREATE INDEX idx_sys_user_username ON sys_user(username);
CREATE INDEX idx_sys_user_dept ON sys_user(dept_id);
CREATE INDEX idx_sys_user_role ON sys_user(role_type);

-- 物联网设备相关索引
CREATE INDEX idx_iot_device_sn ON iot_device(device_sn);
CREATE INDEX idx_iot_device_status ON iot_device(status);
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_geom ON iot_device USING GIST(geom);

CREATE INDEX idx_iot_telemetry_cache_sn ON iot_telemetry_cache(device_sn);
CREATE INDEX idx_iot_telemetry_cache_metric ON iot_telemetry_cache(metric_key);
CREATE INDEX idx_iot_telemetry_cache_ts ON iot_telemetry_cache(ts);

-- 营业收费相关索引
CREATE INDEX idx_rev_customer_no ON rev_customer(customer_no);
CREATE INDEX idx_rev_customer_type ON rev_customer(customer_type);
CREATE INDEX idx_rev_meter_no ON rev_meter(meter_no);
CREATE INDEX idx_rev_meter_customer ON rev_meter(customer_id);
CREATE INDEX idx_rev_bill_period ON rev_bill(bill_period);
CREATE INDEX idx_rev_bill_customer ON rev_bill(customer_id);

-- 巡检系统索引
CREATE INDEX idx_patrol_route_area ON patrol_route(area);
CREATE INDEX idx_patrol_task_date ON patrol_task(task_date);
CREATE INDEX idx_patrol_task_status ON patrol_task(status);
CREATE INDEX idx_patrol_task_assignee ON patrol_task(assignee_id);

-- 报警管理索引
CREATE INDEX idx_alert_rule_device ON alert_rule(device_type);
CREATE INDEX idx_alert_rule_enabled ON alert_rule(enabled);
CREATE INDEX idx_alert_event_device ON alert_event(device_sn);
CREATE INDEX idx_alert_event_level ON alert_event(alert_level);
CREATE INDEX idx_alert_event_status ON alert_event(dispatched);

-- 操作日志索引
CREATE INDEX idx_sys_oplog_user ON sys_operation_log(user_id);
CREATE INDEX idx_sys_oplog_time ON sys_operation_log(created_at);
CREATE INDEX idx_sys_oplog_type ON sys_operation_log(operation_type);

-- 系统配置索引
CREATE INDEX idx_sys_config_key ON sys_config(config_key);

-- 数据字典索引
CREATE INDEX idx_sys_dict_type ON sys_dict(dict_type);
CREATE INDEX idx_sys_dict_code ON sys_dict(dict_code);

-- ========= 触发器 =========
-- 更新时间自动触发器
CREATE OR REPLACE FUNCTION update_timestamp()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 为相关表添加触发器
CREATE TRIGGER trg_sys_user_update BEFORE UPDATE ON sys_user FOR EACH ROW EXECUTE FUNCTION update_timestamp();
CREATE TRIGGER trg_iot_device_update BEFORE UPDATE ON iot_device FOR EACH ROW EXECUTE FUNCTION update_timestamp();
CREATE TRIGGER trg_rev_customer_update BEFORE UPDATE ON rev_customer FOR EACH ROW EXECUTE FUNCTION update_timestamp();
CREATE TRIGGER trg_rev_meter_update BEFORE UPDATE ON rev_meter FOR EACH ROW EXECUTE FUNCTION update_timestamp();
CREATE TRIGGER trg_rev_bill_update BEFORE UPDATE ON rev_bill FOR EACH ROW EXECUTE FUNCTION update_timestamp();
CREATE TRIGGER trg_alert_rule_update BEFORE UPDATE ON alert_rule FOR EACH ROW EXECUTE FUNCTION update_timestamp();
CREATE TRIGGER trg_alert_event_update BEFORE UPDATE ON alert_event FOR EACH ROW EXECUTE FUNCTION update_timestamp();

-- 序列初始化
SELECT setval('sys_user_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_user));
SELECT setval('sys_role_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_role));
SELECT setval('sys_menu_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_menu));
SELECT setval('iot_device_id_seq', (SELECT COALESCE(MAX(id), 1) FROM iot_device));
SELECT setval('rev_customer_id_seq', (SELECT COALESCE(MAX(id), 1) FROM rev_customer));
SELECT setval('rev_meter_id_seq', (SELECT COALESCE(MAX(id), 1) FROM rev_meter));