feat(scada): add project monitoring replay
This commit is contained in:
@@ -19,13 +19,18 @@ CREATE TABLE IF NOT EXISTS projects (
|
||||
gs_workspace VARCHAR(100) UNIQUE NOT NULL,
|
||||
map_extent JSONB,
|
||||
map_config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
settings JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
status VARCHAR(20) DEFAULT 'active' NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
CONSTRAINT projects_status_check CHECK (status IN ('active', 'inactive', 'archived'))
|
||||
CONSTRAINT projects_status_check CHECK (status IN ('active', 'inactive', 'archived')),
|
||||
CONSTRAINT projects_settings_object_check CHECK (jsonb_typeof(settings) = 'object')
|
||||
);
|
||||
|
||||
ALTER TABLE projects ADD COLUMN IF NOT EXISTS map_config JSONB NOT NULL DEFAULT '{}'::jsonb;
|
||||
ALTER TABLE projects ADD COLUMN IF NOT EXISTS settings JSONB NOT NULL DEFAULT '{}'::jsonb;
|
||||
COMMENT ON COLUMN projects.settings IS
|
||||
'项目级通用配置(JSON 对象,不存放密钥);scada_monitoring_interval_seconds 为监测任务间隔秒数。';
|
||||
COMMENT ON COLUMN projects.map_config IS
|
||||
'项目级地图配置(JSON);place_search 保存地名搜索启用状态、服务商、行政区编码及区域名称;保留既有图例与坐标参考配置。';
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
BEGIN;
|
||||
DO $$ BEGIN
|
||||
IF current_database() NOT IN ('tjwater_v2', 'tjwater2_v2') THEN
|
||||
RAISE EXCEPTION '031_scada_replays requires an explicitly verified SCADA demo project';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS peripheral_sample.scada_replays (
|
||||
project_id uuid NOT NULL,
|
||||
replay_id uuid NOT NULL,
|
||||
request_id uuid NOT NULL,
|
||||
status text NOT NULL CHECK (status IN ('ready','paused','completed','stopped','failed')),
|
||||
document jsonb NOT NULL,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (project_id,replay_id),
|
||||
UNIQUE (project_id,request_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS scada_replays_status_idx
|
||||
ON peripheral_sample.scada_replays(project_id,status,created_at DESC);
|
||||
CREATE TABLE IF NOT EXISTS peripheral_sample.scada_replay_batches (
|
||||
project_id uuid NOT NULL,
|
||||
replay_id uuid NOT NULL,
|
||||
sequence bigint NOT NULL,
|
||||
stage text NOT NULL CHECK(stage IN ('selected','clean_prepared','cleaned','detected')),
|
||||
document jsonb NOT NULL,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY(project_id,replay_id,sequence),
|
||||
FOREIGN KEY(project_id,replay_id) REFERENCES peripheral_sample.scada_replays(project_id,replay_id)
|
||||
);
|
||||
COMMENT ON TABLE peripheral_sample.scada_replays IS 'SCADA 演示回放的权威控制状态与处理检查点,不保存正式原始观测';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replays.project_id IS '经认证与路由校验的所属项目';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replays.replay_id IS '独立回放身份,不等同 Agent 执行编号';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replays.request_id IS '创建请求的稳定幂等编号';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replays.status IS '供领取和约束使用的 document.status 查询投影';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replays.document IS '冻结配置、设备快照、时钟、检查点、规则状态和命令回执';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replays.created_at IS '实际创建时间';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replays.updated_at IS '实际控制或进度更新时间';
|
||||
COMMENT ON TABLE peripheral_sample.scada_replay_batches IS 'SCADA raw 引用、清洗输出及检测阶段的恢复凭证,禁止重写 raw';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replay_batches.project_id IS '所属项目';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replay_batches.replay_id IS '所属回放';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replay_batches.sequence IS '回放内单调批次序号';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replay_batches.stage IS '已提交处理阶段';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replay_batches.document IS '观测键、raw 摘要、确定的清洗结果与检测事件';
|
||||
COMMENT ON COLUMN peripheral_sample.scada_replay_batches.created_at IS '实际登记批次时间';
|
||||
COMMIT;
|
||||
@@ -0,0 +1,54 @@
|
||||
BEGIN;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF to_regclass('public.project_databases') IS NULL
|
||||
OR to_regclass('public.user_project_membership') IS NULL THEN
|
||||
RAISE EXCEPTION '033_metadata_project_settings must run in the project metadata database';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
ALTER TABLE public.projects
|
||||
ADD COLUMN IF NOT EXISTS settings jsonb NOT NULL DEFAULT '{}'::jsonb;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint
|
||||
WHERE conrelid = 'public.projects'::regclass
|
||||
AND conname = 'projects_settings_object_check'
|
||||
) THEN
|
||||
ALTER TABLE public.projects
|
||||
ADD CONSTRAINT projects_settings_object_check
|
||||
CHECK (jsonb_typeof(settings) = 'object');
|
||||
END IF;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'public' AND table_name = 'projects'
|
||||
AND column_name = 'scada_monitoring_interval_seconds'
|
||||
) THEN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM public.projects
|
||||
WHERE scada_monitoring_interval_seconds IS NOT NULL
|
||||
AND settings ? 'scada_monitoring_interval_seconds'
|
||||
AND settings->'scada_monitoring_interval_seconds'
|
||||
IS DISTINCT FROM to_jsonb(scada_monitoring_interval_seconds)
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Conflicting SCADA monitoring intervals; resolve before migration';
|
||||
END IF;
|
||||
|
||||
UPDATE public.projects
|
||||
SET settings = settings || jsonb_build_object(
|
||||
'scada_monitoring_interval_seconds', scada_monitoring_interval_seconds
|
||||
)
|
||||
WHERE scada_monitoring_interval_seconds IS NOT NULL;
|
||||
|
||||
ALTER TABLE public.projects DROP COLUMN scada_monitoring_interval_seconds;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
COMMENT ON COLUMN public.projects.settings IS
|
||||
'项目级通用配置(JSON 对象,不存放密钥);scada_monitoring_interval_seconds 为监测任务间隔秒数。';
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user