feat: add backend rule group and permission support
This commit is contained in:
@@ -0,0 +1,405 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Migrate legacy users from docauditai into leaudit_platform.
|
||||
|
||||
Default mode is dry-run. Use --apply to write data.
|
||||
|
||||
What gets migrated:
|
||||
- sso_users
|
||||
- user_role
|
||||
|
||||
What gets reused:
|
||||
- target roles already seeded in leaudit_platform
|
||||
|
||||
Rules:
|
||||
- preserve legacy user id when inserting into the new database
|
||||
- map missing legacy roles to `common`
|
||||
- normalize area with trim and alias mapping
|
||||
- never overwrite target area with empty value
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import os
|
||||
from collections import Counter, defaultdict
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import asyncpg
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
APP_TOML = ROOT / "app.toml"
|
||||
|
||||
ALLOWED_ROLE_KEYS = {"provincial_admin", "admin", "common", "super_admin"}
|
||||
DEFAULT_ROLE_KEY = "common"
|
||||
AREA_ALIASES = {
|
||||
"省": "省局",
|
||||
"省厅": "省局",
|
||||
"省公司": "省局",
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class LegacyUser:
|
||||
id: int
|
||||
sub: str
|
||||
username: str
|
||||
nick_name: str
|
||||
phone_number: str | None
|
||||
email: str | None
|
||||
ou_id: str
|
||||
ou_name: str
|
||||
status: int
|
||||
is_leader: bool
|
||||
created_at: Any
|
||||
updated_at: Any
|
||||
deleted_at: Any
|
||||
password: str | None
|
||||
try_count: int | None
|
||||
try_login_time: Any
|
||||
area: str | None
|
||||
mq_person_uuid: str | None
|
||||
mq_account_uuid: str | None
|
||||
mq_synced_at: Any
|
||||
tenant_name: str | None
|
||||
dep_short_name: str | None
|
||||
dep_name: str | None
|
||||
|
||||
|
||||
def load_target_dsn() -> str:
|
||||
try:
|
||||
import tomllib
|
||||
except ImportError: # pragma: no cover
|
||||
import tomli as tomllib
|
||||
|
||||
with APP_TOML.open("rb") as fh:
|
||||
config = tomllib.load(fh)
|
||||
db = config["DB"]
|
||||
return (
|
||||
f"postgresql://{db['USER']}:{db['PASSWORD']}"
|
||||
f"@{db['HOST']}:{db['PORT']}/{db['NAME']}"
|
||||
)
|
||||
|
||||
|
||||
def build_legacy_dsn(args: argparse.Namespace) -> str:
|
||||
return (
|
||||
f"postgresql://{args.legacy_user}:{args.legacy_password}"
|
||||
f"@{args.legacy_host}:{args.legacy_port}/{args.legacy_db}"
|
||||
)
|
||||
|
||||
|
||||
def normalize_area(value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
normalized = value.strip()
|
||||
if not normalized:
|
||||
return None
|
||||
return AREA_ALIASES.get(normalized, normalized)
|
||||
|
||||
|
||||
def choose_roles(role_keys: list[str]) -> list[str]:
|
||||
cleaned: list[str] = []
|
||||
for role_key in role_keys:
|
||||
if role_key in ALLOWED_ROLE_KEYS:
|
||||
cleaned.append(role_key)
|
||||
if not cleaned:
|
||||
cleaned = [DEFAULT_ROLE_KEY]
|
||||
return sorted(set(cleaned))
|
||||
|
||||
|
||||
async def fetch_legacy_users(conn: asyncpg.Connection) -> dict[int, LegacyUser]:
|
||||
rows = await conn.fetch(
|
||||
"""
|
||||
SELECT id, sub, username, nick_name, phone_number, email,
|
||||
ou_id, ou_name, status, is_leader, created_at, updated_at,
|
||||
deleted_at, password, try_count, try_login_time, area,
|
||||
mq_person_uuid, mq_account_uuid, mq_synced_at,
|
||||
tenant_name, dep_short_name, dep_name
|
||||
FROM sso_users
|
||||
ORDER BY id
|
||||
"""
|
||||
)
|
||||
return {
|
||||
row["id"]: LegacyUser(**dict(row))
|
||||
for row in rows
|
||||
}
|
||||
|
||||
|
||||
async def fetch_legacy_user_roles(conn: asyncpg.Connection) -> dict[int, list[str]]:
|
||||
rows = await conn.fetch(
|
||||
"""
|
||||
SELECT ur.user_id, r.role_key
|
||||
FROM user_role ur
|
||||
JOIN roles r ON r.id = ur.role_id
|
||||
ORDER BY ur.user_id, r.id
|
||||
"""
|
||||
)
|
||||
result: dict[int, list[str]] = defaultdict(list)
|
||||
for row in rows:
|
||||
result[row["user_id"]].append(row["role_key"])
|
||||
return result
|
||||
|
||||
|
||||
async def fetch_target_roles(conn: asyncpg.Connection) -> dict[str, int]:
|
||||
rows = await conn.fetch("SELECT id, role_key FROM roles ORDER BY id")
|
||||
return {row["role_key"]: row["id"] for row in rows}
|
||||
|
||||
|
||||
async def fetch_target_users(conn: asyncpg.Connection) -> tuple[dict[str, dict[str, Any]], dict[int, dict[str, Any]]]:
|
||||
rows = await conn.fetch("SELECT id, sub, area FROM sso_users")
|
||||
normalized = [dict(row) for row in rows]
|
||||
by_sub = {row["sub"]: row for row in normalized}
|
||||
by_id = {row["id"]: row for row in normalized}
|
||||
return by_sub, by_id
|
||||
|
||||
|
||||
async def ensure_target_ready(conn: asyncpg.Connection) -> None:
|
||||
missing = []
|
||||
for table_name in (
|
||||
"sso_users",
|
||||
"roles",
|
||||
"user_role",
|
||||
"permissions",
|
||||
"role_permissions",
|
||||
"sys_routes",
|
||||
"role_route",
|
||||
):
|
||||
exists = await conn.fetchval(
|
||||
"""
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public' AND table_name = $1
|
||||
)
|
||||
""",
|
||||
table_name,
|
||||
)
|
||||
if not exists:
|
||||
missing.append(table_name)
|
||||
if missing:
|
||||
raise RuntimeError(f"target database is missing required tables: {', '.join(missing)}")
|
||||
|
||||
|
||||
async def upsert_user(conn: asyncpg.Connection, user: LegacyUser, existing_sub_row: dict[str, Any] | None) -> int:
|
||||
area = normalize_area(user.area)
|
||||
if existing_sub_row:
|
||||
await conn.execute(
|
||||
"""
|
||||
UPDATE sso_users
|
||||
SET username = $2,
|
||||
nick_name = $3,
|
||||
phone_number = $4,
|
||||
email = $5,
|
||||
ou_id = $6,
|
||||
ou_name = $7,
|
||||
status = $8,
|
||||
is_leader = $9,
|
||||
updated_at = $10,
|
||||
deleted_at = $11,
|
||||
password = $12,
|
||||
try_count = $13,
|
||||
try_login_time = $14,
|
||||
area = COALESCE($15, area),
|
||||
mq_person_uuid = $16,
|
||||
mq_account_uuid = $17,
|
||||
mq_synced_at = $18,
|
||||
tenant_name = $19,
|
||||
dep_short_name = $20,
|
||||
dep_name = $21
|
||||
WHERE sub = $1
|
||||
""",
|
||||
user.sub,
|
||||
user.username,
|
||||
user.nick_name,
|
||||
user.phone_number,
|
||||
user.email,
|
||||
user.ou_id,
|
||||
user.ou_name,
|
||||
user.status,
|
||||
user.is_leader,
|
||||
user.updated_at,
|
||||
user.deleted_at,
|
||||
user.password,
|
||||
user.try_count,
|
||||
user.try_login_time,
|
||||
area,
|
||||
user.mq_person_uuid,
|
||||
user.mq_account_uuid,
|
||||
user.mq_synced_at,
|
||||
user.tenant_name,
|
||||
user.dep_short_name,
|
||||
user.dep_name,
|
||||
)
|
||||
return int(existing_sub_row["id"])
|
||||
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO sso_users (
|
||||
id, sub, username, nick_name, phone_number, email, ou_id, ou_name,
|
||||
status, is_leader, created_at, updated_at, deleted_at, password,
|
||||
try_count, try_login_time, area, mq_person_uuid, mq_account_uuid,
|
||||
mq_synced_at, tenant_name, dep_short_name, dep_name
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8,
|
||||
$9, $10, $11, $12, $13, $14,
|
||||
$15, $16, $17, $18, $19,
|
||||
$20, $21, $22, $23
|
||||
)
|
||||
""",
|
||||
user.id,
|
||||
user.sub,
|
||||
user.username,
|
||||
user.nick_name,
|
||||
user.phone_number,
|
||||
user.email,
|
||||
user.ou_id,
|
||||
user.ou_name,
|
||||
user.status,
|
||||
user.is_leader,
|
||||
user.created_at,
|
||||
user.updated_at,
|
||||
user.deleted_at,
|
||||
user.password,
|
||||
user.try_count,
|
||||
user.try_login_time,
|
||||
area,
|
||||
user.mq_person_uuid,
|
||||
user.mq_account_uuid,
|
||||
user.mq_synced_at,
|
||||
user.tenant_name,
|
||||
user.dep_short_name,
|
||||
user.dep_name,
|
||||
)
|
||||
return user.id
|
||||
|
||||
|
||||
async def assign_roles(
|
||||
conn: asyncpg.Connection,
|
||||
target_user_id: int,
|
||||
role_keys: list[str],
|
||||
role_key_to_id: dict[str, int],
|
||||
) -> None:
|
||||
for role_key in role_keys:
|
||||
role_id = role_key_to_id.get(role_key)
|
||||
if role_id is None:
|
||||
raise RuntimeError(f"target role not found: {role_key}")
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO user_role (user_id, role_id, created_at, updated_at)
|
||||
VALUES ($1, $2, NOW(), NOW())
|
||||
ON CONFLICT (user_id, role_id) DO NOTHING
|
||||
""",
|
||||
target_user_id,
|
||||
role_id,
|
||||
)
|
||||
|
||||
|
||||
async def sync_user_sequence(conn: asyncpg.Connection) -> None:
|
||||
await conn.execute(
|
||||
"""
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('sso_users', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM sso_users), 1),
|
||||
true
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
async def main_async(args: argparse.Namespace) -> int:
|
||||
legacy_conn = await asyncpg.connect(build_legacy_dsn(args))
|
||||
target_conn = await asyncpg.connect(load_target_dsn())
|
||||
try:
|
||||
await ensure_target_ready(target_conn)
|
||||
|
||||
legacy_users = await fetch_legacy_users(legacy_conn)
|
||||
legacy_user_roles = await fetch_legacy_user_roles(legacy_conn)
|
||||
target_role_map = await fetch_target_roles(target_conn)
|
||||
target_by_sub, target_by_id = await fetch_target_users(target_conn)
|
||||
|
||||
missing_target_roles = sorted(set(ALLOWED_ROLE_KEYS) - set(target_role_map))
|
||||
if missing_target_roles:
|
||||
raise RuntimeError(
|
||||
"target database is missing seeded roles: " + ", ".join(missing_target_roles)
|
||||
)
|
||||
|
||||
summary = Counter()
|
||||
role_summary = Counter()
|
||||
id_conflicts: list[tuple[int, str, int, str]] = []
|
||||
|
||||
async def process_all() -> None:
|
||||
for user_id, user in legacy_users.items():
|
||||
source_roles = legacy_user_roles.get(user_id, [])
|
||||
desired_roles = choose_roles(source_roles)
|
||||
role_summary.update(desired_roles)
|
||||
if not source_roles:
|
||||
summary["default_common_role"] += 1
|
||||
|
||||
existing_sub_row = target_by_sub.get(user.sub)
|
||||
existing_id_row = target_by_id.get(user.id)
|
||||
if existing_id_row and (existing_sub_row is None or existing_sub_row["sub"] != user.sub):
|
||||
id_conflicts.append((user.id, user.sub, int(existing_id_row["id"]), existing_id_row["sub"]))
|
||||
summary["id_conflict"] += 1
|
||||
continue
|
||||
|
||||
if existing_sub_row:
|
||||
summary["update_user"] += 1
|
||||
else:
|
||||
summary["insert_user"] += 1
|
||||
|
||||
if args.apply:
|
||||
target_user_id = await upsert_user(target_conn, user, existing_sub_row)
|
||||
await assign_roles(target_conn, target_user_id, desired_roles, target_role_map)
|
||||
target_by_sub[user.sub] = {"id": target_user_id, "sub": user.sub, "area": normalize_area(user.area)}
|
||||
target_by_id[user.id] = {"id": target_user_id, "sub": user.sub, "area": normalize_area(user.area)}
|
||||
|
||||
if args.apply:
|
||||
async with target_conn.transaction():
|
||||
await process_all()
|
||||
await sync_user_sequence(target_conn)
|
||||
else:
|
||||
await process_all()
|
||||
|
||||
print("=== Migration Summary ===")
|
||||
print(f"mode: {'APPLY' if args.apply else 'DRY_RUN'}")
|
||||
print(f"legacy_users_total: {len(legacy_users)}")
|
||||
for key in sorted(summary):
|
||||
print(f"{key}: {summary[key]}")
|
||||
print("role_assignment_plan:")
|
||||
for role_key, count in sorted(role_summary.items()):
|
||||
print(f" {role_key}: {count}")
|
||||
print(f"id_conflicts: {len(id_conflicts)}")
|
||||
if id_conflicts:
|
||||
print("sample_id_conflicts:")
|
||||
for conflict in id_conflicts[:20]:
|
||||
print(f" legacy_id={conflict[0]} legacy_sub={conflict[1]} target_id={conflict[2]} target_sub={conflict[3]}")
|
||||
|
||||
if not args.apply:
|
||||
print("dry-run complete; rerun with --apply to write data")
|
||||
return 0
|
||||
finally:
|
||||
await legacy_conn.close()
|
||||
await target_conn.close()
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Migrate legacy users into leaudit_platform")
|
||||
parser.add_argument("--legacy-host", default=os.getenv("LEGACY_DB_HOST", "172.16.0.81"))
|
||||
parser.add_argument("--legacy-port", type=int, default=int(os.getenv("LEGACY_DB_PORT", "54302")))
|
||||
parser.add_argument("--legacy-db", default=os.getenv("LEGACY_DB_NAME", "docauditai"))
|
||||
parser.add_argument("--legacy-user", default=os.getenv("LEGACY_DB_USER", "docauditai_admin"))
|
||||
parser.add_argument("--legacy-password", default=os.getenv("LEGACY_DB_PASSWORD", "zhfw*123*"))
|
||||
parser.add_argument("--apply", action="store_true", help="write data into target database")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
return asyncio.run(main_async(args))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,462 @@
|
||||
-- 评查点分组正式迁移脚本(业务大类根版本)
|
||||
-- 目标:
|
||||
-- 一级分组 = 业务大类(合同 / 行政卷宗 / 后续新增业务)
|
||||
-- 二级分组 = 具体业务类型
|
||||
-- 规则集 = 挂在二级分组下
|
||||
-- 入口模块 = 绑定一级分组
|
||||
--
|
||||
-- 重要说明:
|
||||
-- 1. 本脚本面向当前真实库结构:
|
||||
-- - 已存在旧一级根(一级=具体文档类型)
|
||||
-- - 已存在新一级业务根 root.contract / root.casefile
|
||||
-- - 已存在默认二级分组 *.default / 通用
|
||||
-- 2. 执行前必须先跑:
|
||||
-- scripts/precheck_rule_group_migration.sql
|
||||
-- 3. 必须先备份:
|
||||
-- leaudit_evaluation_point_groups
|
||||
-- leaudit_rule_group_bindings
|
||||
-- leaudit_rule_type_bindings
|
||||
-- leaudit_document_types
|
||||
-- 4. 本脚本不会立刻删除旧一级根,只做结构补齐 + 绑定迁移 + 汇总重建。
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- =========================================================
|
||||
-- 0. 补齐结构:一级分组入口模块字段
|
||||
-- =========================================================
|
||||
ALTER TABLE leaudit_evaluation_point_groups
|
||||
ADD COLUMN IF NOT EXISTS entry_module_id BIGINT NULL REFERENCES leaudit_entry_modules(id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_leaudit_ep_groups_entry_module
|
||||
ON leaudit_evaluation_point_groups(entry_module_id);
|
||||
|
||||
-- =========================================================
|
||||
-- 1. 保证一级业务大类根存在,并统一编码
|
||||
-- 当前统一使用:
|
||||
-- root.contract -> 合同
|
||||
-- root.casefile -> 行政卷宗
|
||||
-- =========================================================
|
||||
WITH root_candidates AS (
|
||||
SELECT
|
||||
'root.contract'::varchar AS code,
|
||||
'合同'::varchar AS name,
|
||||
'合同业务大类'::text AS description,
|
||||
1::bigint AS entry_module_id,
|
||||
10::int AS sort_order
|
||||
UNION ALL
|
||||
SELECT
|
||||
'root.casefile'::varchar,
|
||||
'行政卷宗'::varchar,
|
||||
'行政卷宗业务大类'::text,
|
||||
2::bigint,
|
||||
20::int
|
||||
),
|
||||
upsert_roots AS (
|
||||
INSERT INTO leaudit_evaluation_point_groups (
|
||||
pid,
|
||||
code,
|
||||
name,
|
||||
description,
|
||||
document_type_id,
|
||||
entry_module_id,
|
||||
sort_order,
|
||||
is_enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT
|
||||
0,
|
||||
rc.code,
|
||||
rc.name,
|
||||
rc.description,
|
||||
NULL,
|
||||
rc.entry_module_id,
|
||||
rc.sort_order,
|
||||
TRUE,
|
||||
NOW(),
|
||||
NOW()
|
||||
FROM root_candidates rc
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND COALESCE(g.pid, 0) = 0
|
||||
AND LOWER(g.code) = LOWER(rc.code)
|
||||
)
|
||||
RETURNING id, code
|
||||
)
|
||||
SELECT COUNT(*) AS inserted_root_count FROM upsert_roots;
|
||||
|
||||
UPDATE leaudit_evaluation_point_groups
|
||||
SET
|
||||
name = '合同',
|
||||
description = '合同业务大类',
|
||||
entry_module_id = 1,
|
||||
sort_order = 10,
|
||||
updated_at = NOW()
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) = 0
|
||||
AND LOWER(code) = LOWER('root.contract');
|
||||
|
||||
UPDATE leaudit_evaluation_point_groups
|
||||
SET
|
||||
name = '行政卷宗',
|
||||
description = '行政卷宗业务大类',
|
||||
entry_module_id = 2,
|
||||
sort_order = 20,
|
||||
updated_at = NOW()
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) = 0
|
||||
AND LOWER(code) = LOWER('root.casefile');
|
||||
|
||||
-- =========================================================
|
||||
-- 2. 优先把旧一级根直接下沉为目标二级分组
|
||||
-- 这样可复用现有 code,避免唯一索引冲突
|
||||
-- =========================================================
|
||||
WITH target_root_map AS (
|
||||
SELECT
|
||||
dt.id AS document_type_id,
|
||||
CASE
|
||||
WHEN dt.entry_module_id = 1 THEN (
|
||||
SELECT id FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL AND COALESCE(pid, 0) = 0 AND code = 'root.contract'
|
||||
LIMIT 1
|
||||
)
|
||||
WHEN dt.entry_module_id = 2 THEN (
|
||||
SELECT id FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL AND COALESCE(pid, 0) = 0 AND code = 'root.casefile'
|
||||
LIMIT 1
|
||||
)
|
||||
ELSE NULL
|
||||
END AS new_root_id
|
||||
FROM leaudit_document_types dt
|
||||
WHERE dt.deleted_at IS NULL
|
||||
),
|
||||
reparented_old_roots AS (
|
||||
UPDATE leaudit_evaluation_point_groups g
|
||||
SET
|
||||
pid = trm.new_root_id,
|
||||
entry_module_id = NULL,
|
||||
updated_at = NOW()
|
||||
FROM target_root_map trm
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND COALESCE(g.pid, 0) = 0
|
||||
AND g.document_type_id = trm.document_type_id
|
||||
AND trm.new_root_id IS NOT NULL
|
||||
RETURNING g.id, g.document_type_id
|
||||
)
|
||||
SELECT COUNT(*) AS reparented_old_root_count FROM reparented_old_roots;
|
||||
|
||||
-- =========================================================
|
||||
-- 3. 如果某个文档类型没有旧一级根,再补建新的目标二级分组
|
||||
-- =========================================================
|
||||
WITH mapped_doc_types AS (
|
||||
SELECT
|
||||
dt.id AS document_type_id,
|
||||
dt.code AS document_type_code,
|
||||
dt.name AS document_type_name,
|
||||
dt.description,
|
||||
dt.entry_module_id,
|
||||
dt.sort_order,
|
||||
dt.is_enabled,
|
||||
CASE
|
||||
WHEN dt.entry_module_id = 1 THEN (
|
||||
SELECT id FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL AND COALESCE(pid, 0) = 0 AND code = 'root.contract'
|
||||
LIMIT 1
|
||||
)
|
||||
WHEN dt.entry_module_id = 2 THEN (
|
||||
SELECT id FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL AND COALESCE(pid, 0) = 0 AND code = 'root.casefile'
|
||||
LIMIT 1
|
||||
)
|
||||
ELSE NULL
|
||||
END AS root_group_id
|
||||
FROM leaudit_document_types dt
|
||||
WHERE dt.deleted_at IS NULL
|
||||
),
|
||||
insert_children AS (
|
||||
INSERT INTO leaudit_evaluation_point_groups (
|
||||
pid,
|
||||
code,
|
||||
name,
|
||||
description,
|
||||
document_type_id,
|
||||
entry_module_id,
|
||||
sort_order,
|
||||
is_enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT
|
||||
m.root_group_id,
|
||||
m.document_type_code,
|
||||
m.document_type_name,
|
||||
COALESCE(m.description, m.document_type_name || '二级分组'),
|
||||
m.document_type_id,
|
||||
NULL,
|
||||
COALESCE(m.sort_order, 0),
|
||||
COALESCE(m.is_enabled, TRUE),
|
||||
NOW(),
|
||||
NOW()
|
||||
FROM mapped_doc_types m
|
||||
WHERE m.root_group_id IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
JOIN leaudit_evaluation_point_groups root
|
||||
ON root.id = g.pid
|
||||
AND root.deleted_at IS NULL
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND COALESCE(g.pid, 0) <> 0
|
||||
AND g.document_type_id = m.document_type_id
|
||||
AND root.document_type_id IS NULL
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND LOWER(g.code) = LOWER(m.document_type_code)
|
||||
)
|
||||
RETURNING id, document_type_id
|
||||
)
|
||||
SELECT COUNT(*) AS inserted_child_count FROM insert_children;
|
||||
|
||||
-- =========================================================
|
||||
-- 4. 将旧一级根上的规则绑定迁到目标二级分组
|
||||
-- =========================================================
|
||||
WITH old_roots AS (
|
||||
SELECT id AS old_group_id, document_type_id
|
||||
FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) = 0
|
||||
AND document_type_id IS NOT NULL
|
||||
),
|
||||
target_children AS (
|
||||
SELECT child.id AS new_group_id, child.document_type_id
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
JOIN leaudit_evaluation_point_groups root
|
||||
ON root.id = child.pid
|
||||
AND root.deleted_at IS NULL
|
||||
AND root.document_type_id IS NULL
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND COALESCE(child.pid, 0) <> 0
|
||||
AND child.document_type_id IS NOT NULL
|
||||
),
|
||||
move_pairs AS (
|
||||
SELECT old_roots.old_group_id, target_children.new_group_id
|
||||
FROM old_roots
|
||||
JOIN target_children
|
||||
ON target_children.document_type_id = old_roots.document_type_id
|
||||
),
|
||||
updated_bindings AS (
|
||||
UPDATE leaudit_rule_group_bindings rgb
|
||||
SET group_id = mp.new_group_id,
|
||||
updated_at = NOW()
|
||||
FROM move_pairs mp
|
||||
WHERE rgb.group_id = mp.old_group_id
|
||||
AND rgb.deleted_at IS NULL
|
||||
RETURNING rgb.id
|
||||
)
|
||||
SELECT COUNT(*) AS moved_old_root_binding_count FROM updated_bindings;
|
||||
|
||||
-- =========================================================
|
||||
-- 5. 将旧默认子级上的规则绑定迁到目标二级分组
|
||||
-- 注意:只迁“父级仍是旧一级根”的默认子级
|
||||
-- =========================================================
|
||||
WITH old_default_children AS (
|
||||
SELECT
|
||||
child.id AS old_group_id,
|
||||
child.document_type_id
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
JOIN leaudit_evaluation_point_groups parent
|
||||
ON parent.id = child.pid
|
||||
AND parent.deleted_at IS NULL
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND COALESCE(child.pid, 0) <> 0
|
||||
AND parent.document_type_id IS NOT NULL
|
||||
AND (
|
||||
child.name = '通用'
|
||||
OR child.code LIKE '%.default'
|
||||
)
|
||||
),
|
||||
target_children AS (
|
||||
SELECT child.id AS new_group_id, child.document_type_id
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
JOIN leaudit_evaluation_point_groups root
|
||||
ON root.id = child.pid
|
||||
AND root.deleted_at IS NULL
|
||||
AND root.document_type_id IS NULL
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND COALESCE(child.pid, 0) <> 0
|
||||
AND child.document_type_id IS NOT NULL
|
||||
),
|
||||
move_pairs AS (
|
||||
SELECT old_default_children.old_group_id, target_children.new_group_id
|
||||
FROM old_default_children
|
||||
JOIN target_children
|
||||
ON target_children.document_type_id = old_default_children.document_type_id
|
||||
),
|
||||
updated_bindings AS (
|
||||
UPDATE leaudit_rule_group_bindings rgb
|
||||
SET group_id = mp.new_group_id,
|
||||
updated_at = NOW()
|
||||
FROM move_pairs mp
|
||||
WHERE rgb.group_id = mp.old_group_id
|
||||
AND rgb.deleted_at IS NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_rule_group_bindings existing
|
||||
WHERE existing.deleted_at IS NULL
|
||||
AND existing.group_id = mp.new_group_id
|
||||
AND existing.rule_set_id = rgb.rule_set_id
|
||||
)
|
||||
RETURNING rgb.id
|
||||
),
|
||||
soft_deleted_duplicates AS (
|
||||
UPDATE leaudit_rule_group_bindings rgb
|
||||
SET deleted_at = NOW(),
|
||||
updated_at = NOW(),
|
||||
note = COALESCE(rgb.note, '') || ' [soft-deleted after business-root migration: duplicate with target child binding]'
|
||||
FROM move_pairs mp
|
||||
WHERE rgb.group_id = mp.old_group_id
|
||||
AND rgb.deleted_at IS NULL
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_rule_group_bindings existing
|
||||
WHERE existing.deleted_at IS NULL
|
||||
AND existing.group_id = mp.new_group_id
|
||||
AND existing.rule_set_id = rgb.rule_set_id
|
||||
)
|
||||
RETURNING rgb.id
|
||||
)
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM updated_bindings) AS moved_default_child_binding_count,
|
||||
(SELECT COUNT(*) FROM soft_deleted_duplicates) AS soft_deleted_duplicate_default_binding_count;
|
||||
|
||||
-- =========================================================
|
||||
-- 6. 去重修复:避免迁移后同一二级分组重复绑定同一规则集
|
||||
-- 保留 priority 更高、id 更小的一条
|
||||
-- =========================================================
|
||||
WITH ranked AS (
|
||||
SELECT
|
||||
id,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY group_id, rule_set_id
|
||||
ORDER BY priority DESC, id ASC
|
||||
) AS rn
|
||||
FROM leaudit_rule_group_bindings
|
||||
WHERE deleted_at IS NULL
|
||||
),
|
||||
soft_deleted AS (
|
||||
UPDATE leaudit_rule_group_bindings rgb
|
||||
SET deleted_at = NOW(),
|
||||
updated_at = NOW()
|
||||
FROM ranked r
|
||||
WHERE rgb.id = r.id
|
||||
AND r.rn > 1
|
||||
RETURNING rgb.id
|
||||
)
|
||||
SELECT COUNT(*) AS deduped_binding_count FROM soft_deleted;
|
||||
|
||||
-- =========================================================
|
||||
-- 7. 清理迁移后已空置的旧默认子级
|
||||
-- 条件:
|
||||
-- - 自身无有效规则绑定
|
||||
-- - 自身是“通用 / *.default”
|
||||
-- - 父级已是具体业务类型节点
|
||||
-- =========================================================
|
||||
WITH empty_default_children AS (
|
||||
SELECT child.id
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
JOIN leaudit_evaluation_point_groups parent
|
||||
ON parent.id = child.pid
|
||||
AND parent.deleted_at IS NULL
|
||||
LEFT JOIN leaudit_rule_group_bindings rgb
|
||||
ON rgb.group_id = child.id
|
||||
AND rgb.deleted_at IS NULL
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND COALESCE(child.pid, 0) <> 0
|
||||
AND parent.document_type_id IS NOT NULL
|
||||
AND (
|
||||
child.name = '通用'
|
||||
OR child.code LIKE '%.default'
|
||||
)
|
||||
GROUP BY child.id
|
||||
HAVING COUNT(rgb.id) = 0
|
||||
),
|
||||
soft_deleted_groups AS (
|
||||
UPDATE leaudit_evaluation_point_groups g
|
||||
SET deleted_at = NOW(),
|
||||
updated_at = NOW()
|
||||
FROM empty_default_children edc
|
||||
WHERE g.id = edc.id
|
||||
RETURNING g.id
|
||||
)
|
||||
SELECT COUNT(*) AS soft_deleted_empty_default_group_count FROM soft_deleted_groups;
|
||||
|
||||
-- =========================================================
|
||||
-- 8. 重建文档类型汇总绑定表
|
||||
-- =========================================================
|
||||
UPDATE leaudit_rule_type_bindings
|
||||
SET deleted_at = NOW(),
|
||||
updated_at = NOW()
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
INSERT INTO leaudit_rule_type_bindings (
|
||||
doc_type_id,
|
||||
doc_type_code,
|
||||
rule_set_id,
|
||||
binding_mode,
|
||||
priority,
|
||||
is_active,
|
||||
note,
|
||||
created_at,
|
||||
updated_at,
|
||||
region
|
||||
)
|
||||
SELECT DISTINCT ON (child.document_type_id, rgb.rule_set_id)
|
||||
child.document_type_id,
|
||||
dt.code,
|
||||
rgb.rule_set_id,
|
||||
'explicit',
|
||||
100,
|
||||
TRUE,
|
||||
're-built from second-level group bindings after business-root migration',
|
||||
NOW(),
|
||||
NOW(),
|
||||
'default'
|
||||
FROM leaudit_rule_group_bindings rgb
|
||||
JOIN leaudit_evaluation_point_groups child
|
||||
ON child.id = rgb.group_id
|
||||
AND child.deleted_at IS NULL
|
||||
AND COALESCE(child.pid, 0) <> 0
|
||||
JOIN leaudit_evaluation_point_groups root
|
||||
ON root.id = child.pid
|
||||
AND root.deleted_at IS NULL
|
||||
AND root.document_type_id IS NULL
|
||||
JOIN leaudit_document_types dt
|
||||
ON dt.id = child.document_type_id
|
||||
WHERE rgb.deleted_at IS NULL
|
||||
AND rgb.is_active = TRUE
|
||||
ORDER BY child.document_type_id, rgb.rule_set_id, rgb.priority DESC, rgb.id ASC;
|
||||
|
||||
-- =========================================================
|
||||
-- 9. 迁移后输出检查摘要
|
||||
-- =========================================================
|
||||
SELECT
|
||||
root.code AS root_code,
|
||||
root.name AS root_name,
|
||||
root.entry_module_id,
|
||||
COUNT(child.id) AS child_count
|
||||
FROM leaudit_evaluation_point_groups root
|
||||
LEFT JOIN leaudit_evaluation_point_groups child
|
||||
ON child.pid = root.id
|
||||
AND child.deleted_at IS NULL
|
||||
WHERE root.deleted_at IS NULL
|
||||
AND COALESCE(root.pid, 0) = 0
|
||||
AND root.document_type_id IS NULL
|
||||
GROUP BY root.id, root.code, root.name, root.entry_module_id
|
||||
ORDER BY root.sort_order, root.id;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,303 @@
|
||||
-- 已废弃:文件名保留仅为兼容历史引用,请改用:
|
||||
-- scripts/migrate_rule_groups_to_business_roots.sql
|
||||
--
|
||||
-- 评查点分组迁移草案(产品新口径)
|
||||
-- 目标结构:
|
||||
-- 一级分组 = 业务大类(如:合同、卷宗、后续新增业务)
|
||||
-- 二级分组 = 具体业务类型(如:建设工程合同、处罚-一般程序)
|
||||
-- 规则集 = 挂在二级分组下
|
||||
-- 一级分组 = 可绑定入口模块
|
||||
--
|
||||
-- 注意:
|
||||
-- 1. 本脚本当前仅作为迁移草案保存,尚未执行。
|
||||
-- 2. 正式执行前必须先在测试库完成全量演练。
|
||||
-- 3. 其中“合同 / 卷宗”的划分需要先由业务确认哪些 document_type 归属哪个一级分组。
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 0) 预留一级分组的入口模块字段。
|
||||
ALTER TABLE leaudit_evaluation_point_groups
|
||||
ADD COLUMN IF NOT EXISTS entry_module_id BIGINT NULL REFERENCES leaudit_entry_modules(id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_leaudit_ep_groups_entry_module
|
||||
ON leaudit_evaluation_point_groups(entry_module_id);
|
||||
|
||||
-- 1) 建立目标一级分组(当前先按已知口径建立“合同 / 卷宗”两个大类)。
|
||||
-- 后续若有新业务,只需继续插入新的一级分组即可。
|
||||
WITH root_candidates AS (
|
||||
SELECT
|
||||
'biz.contract'::varchar AS code,
|
||||
'合同'::varchar AS name,
|
||||
'合同业务大类'::text AS description,
|
||||
1::bigint AS entry_module_id,
|
||||
10::int AS sort_order
|
||||
UNION ALL
|
||||
SELECT
|
||||
'biz.case'::varchar,
|
||||
'卷宗'::varchar,
|
||||
'卷宗业务大类'::text,
|
||||
2::bigint,
|
||||
20::int
|
||||
),
|
||||
inserted_roots AS (
|
||||
INSERT INTO leaudit_evaluation_point_groups (
|
||||
pid,
|
||||
code,
|
||||
name,
|
||||
description,
|
||||
document_type_id,
|
||||
entry_module_id,
|
||||
sort_order,
|
||||
is_enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT
|
||||
0,
|
||||
rc.code,
|
||||
rc.name,
|
||||
rc.description,
|
||||
NULL,
|
||||
rc.entry_module_id,
|
||||
rc.sort_order,
|
||||
TRUE,
|
||||
NOW(),
|
||||
NOW()
|
||||
FROM root_candidates rc
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND COALESCE(g.pid, 0) = 0
|
||||
AND LOWER(g.code) = LOWER(rc.code)
|
||||
)
|
||||
RETURNING id, code, name
|
||||
)
|
||||
SELECT COUNT(*) AS inserted_root_count FROM inserted_roots;
|
||||
|
||||
-- 2) 建立 document_type -> 一级分组 的映射。
|
||||
-- 这里先按入口模块粗分:
|
||||
-- 合同管理 -> 合同
|
||||
-- 案卷智能评查 -> 卷宗
|
||||
-- 后续若出现其他入口,需在这里继续补 mapping。
|
||||
WITH root_map AS (
|
||||
SELECT id, code, name, entry_module_id
|
||||
FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) = 0
|
||||
AND code IN ('biz.contract', 'biz.case')
|
||||
),
|
||||
doc_type_root_mapping AS (
|
||||
SELECT
|
||||
dt.id AS document_type_id,
|
||||
dt.code AS document_type_code,
|
||||
dt.name AS document_type_name,
|
||||
dt.entry_module_id,
|
||||
CASE
|
||||
WHEN dt.entry_module_id = 1 THEN (SELECT id FROM root_map WHERE code = 'biz.contract' LIMIT 1)
|
||||
WHEN dt.entry_module_id = 2 THEN (SELECT id FROM root_map WHERE code = 'biz.case' LIMIT 1)
|
||||
ELSE NULL
|
||||
END AS root_group_id
|
||||
FROM leaudit_document_types dt
|
||||
WHERE dt.deleted_at IS NULL
|
||||
)
|
||||
SELECT *
|
||||
FROM doc_type_root_mapping
|
||||
ORDER BY document_type_id;
|
||||
|
||||
-- 3) 为每个 document_type 建立新的二级分组(挂到一级分组下)。
|
||||
WITH doc_type_root_mapping AS (
|
||||
SELECT
|
||||
dt.id AS document_type_id,
|
||||
dt.code AS document_type_code,
|
||||
dt.name AS document_type_name,
|
||||
dt.description,
|
||||
dt.entry_module_id,
|
||||
dt.sort_order,
|
||||
dt.is_enabled,
|
||||
CASE
|
||||
WHEN dt.entry_module_id = 1 THEN (
|
||||
SELECT id FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL AND COALESCE(pid, 0) = 0 AND code = 'biz.contract'
|
||||
LIMIT 1
|
||||
)
|
||||
WHEN dt.entry_module_id = 2 THEN (
|
||||
SELECT id FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL AND COALESCE(pid, 0) = 0 AND code = 'biz.case'
|
||||
LIMIT 1
|
||||
)
|
||||
ELSE NULL
|
||||
END AS root_group_id
|
||||
FROM leaudit_document_types dt
|
||||
WHERE dt.deleted_at IS NULL
|
||||
),
|
||||
inserted_children AS (
|
||||
INSERT INTO leaudit_evaluation_point_groups (
|
||||
pid,
|
||||
code,
|
||||
name,
|
||||
description,
|
||||
document_type_id,
|
||||
entry_module_id,
|
||||
sort_order,
|
||||
is_enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT
|
||||
m.root_group_id,
|
||||
m.document_type_code,
|
||||
m.document_type_name,
|
||||
COALESCE(m.description, m.document_type_name || '二级分组'),
|
||||
m.document_type_id,
|
||||
NULL,
|
||||
COALESCE(m.sort_order, 0),
|
||||
COALESCE(m.is_enabled, TRUE),
|
||||
NOW(),
|
||||
NOW()
|
||||
FROM doc_type_root_mapping m
|
||||
WHERE m.root_group_id IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND COALESCE(g.pid, 0) <> 0
|
||||
AND g.document_type_id = m.document_type_id
|
||||
)
|
||||
RETURNING id, pid, document_type_id, code, name
|
||||
)
|
||||
SELECT COUNT(*) AS inserted_child_count FROM inserted_children;
|
||||
|
||||
-- 4) 将旧“一级=具体文档类型”的规则绑定迁到新二级分组。
|
||||
-- 迁移策略:
|
||||
-- - 若旧一级或其唯一默认子级已绑定规则集,则全部搬到新的二级分组上
|
||||
-- - 旧数据本身不立刻硬删除,先留待人工复核
|
||||
WITH old_doc_type_roots AS (
|
||||
SELECT
|
||||
g.id AS old_group_id,
|
||||
g.document_type_id
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND COALESCE(g.pid, 0) = 0
|
||||
AND g.document_type_id IS NOT NULL
|
||||
),
|
||||
new_children AS (
|
||||
SELECT
|
||||
g.id AS new_group_id,
|
||||
g.document_type_id
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND COALESCE(g.pid, 0) <> 0
|
||||
AND g.document_type_id IS NOT NULL
|
||||
),
|
||||
move_pairs AS (
|
||||
SELECT
|
||||
old.old_group_id,
|
||||
child.new_group_id,
|
||||
old.document_type_id
|
||||
FROM old_doc_type_roots old
|
||||
JOIN new_children child
|
||||
ON child.document_type_id = old.document_type_id
|
||||
),
|
||||
root_binding_updates AS (
|
||||
UPDATE leaudit_rule_group_bindings rgb
|
||||
SET group_id = mp.new_group_id,
|
||||
updated_at = NOW()
|
||||
FROM move_pairs mp
|
||||
WHERE rgb.group_id = mp.old_group_id
|
||||
AND rgb.deleted_at IS NULL
|
||||
RETURNING rgb.id
|
||||
)
|
||||
SELECT COUNT(*) AS moved_root_binding_count FROM root_binding_updates;
|
||||
|
||||
-- 5) 将旧默认子级(如 *.default / 通用)上的绑定也迁到新二级分组。
|
||||
WITH old_default_children AS (
|
||||
SELECT
|
||||
child.id AS old_group_id,
|
||||
child.document_type_id
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
JOIN leaudit_evaluation_point_groups parent
|
||||
ON parent.id = child.pid
|
||||
AND parent.deleted_at IS NULL
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND COALESCE(child.pid, 0) <> 0
|
||||
AND parent.document_type_id IS NOT NULL
|
||||
AND child.document_type_id = parent.document_type_id
|
||||
AND (
|
||||
child.name = '通用'
|
||||
OR child.code LIKE '%.default'
|
||||
)
|
||||
),
|
||||
new_children AS (
|
||||
SELECT
|
||||
g.id AS new_group_id,
|
||||
g.document_type_id
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
JOIN leaudit_evaluation_point_groups root
|
||||
ON root.id = g.pid
|
||||
AND root.deleted_at IS NULL
|
||||
AND root.document_type_id IS NULL
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND COALESCE(g.pid, 0) <> 0
|
||||
AND g.document_type_id IS NOT NULL
|
||||
),
|
||||
move_pairs AS (
|
||||
SELECT
|
||||
old.old_group_id,
|
||||
child.new_group_id
|
||||
FROM old_default_children old
|
||||
JOIN new_children child
|
||||
ON child.document_type_id = old.document_type_id
|
||||
),
|
||||
default_binding_updates AS (
|
||||
UPDATE leaudit_rule_group_bindings rgb
|
||||
SET group_id = mp.new_group_id,
|
||||
updated_at = NOW()
|
||||
FROM move_pairs mp
|
||||
WHERE rgb.group_id = mp.old_group_id
|
||||
AND rgb.deleted_at IS NULL
|
||||
RETURNING rgb.id
|
||||
)
|
||||
SELECT COUNT(*) AS moved_default_binding_count FROM default_binding_updates;
|
||||
|
||||
-- 6) 重建文档类型汇总绑定,确保文档类型页仍可看到汇总规则集。
|
||||
UPDATE leaudit_rule_type_bindings
|
||||
SET deleted_at = NOW(),
|
||||
updated_at = NOW()
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
INSERT INTO leaudit_rule_type_bindings (
|
||||
doc_type_id,
|
||||
doc_type_code,
|
||||
rule_set_id,
|
||||
binding_mode,
|
||||
priority,
|
||||
is_active,
|
||||
note,
|
||||
created_at,
|
||||
updated_at,
|
||||
region
|
||||
)
|
||||
SELECT DISTINCT ON (c.document_type_id, rgb.rule_set_id)
|
||||
c.document_type_id,
|
||||
dt.code,
|
||||
rgb.rule_set_id,
|
||||
'explicit',
|
||||
100,
|
||||
TRUE,
|
||||
're-built from second-level group bindings after root/category migration',
|
||||
NOW(),
|
||||
NOW(),
|
||||
'default'
|
||||
FROM leaudit_rule_group_bindings rgb
|
||||
JOIN leaudit_evaluation_point_groups c
|
||||
ON c.id = rgb.group_id
|
||||
AND c.deleted_at IS NULL
|
||||
AND COALESCE(c.pid, 0) <> 0
|
||||
JOIN leaudit_document_types dt
|
||||
ON dt.id = c.document_type_id
|
||||
WHERE rgb.deleted_at IS NULL
|
||||
AND rgb.is_active = TRUE
|
||||
ORDER BY c.document_type_id, rgb.rule_set_id, rgb.priority DESC, rgb.id ASC;
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,270 @@
|
||||
-- 评查点分组正式迁移前巡检脚本
|
||||
-- 用途:
|
||||
-- 1. 在测试库 / 正式库执行前,先盘点当前分组树、规则集绑定和入口映射风险
|
||||
-- 2. 本脚本只做查询,不修改任何数据
|
||||
--
|
||||
-- 推荐执行方式:
|
||||
-- psql "$DATABASE_URL" -f scripts/precheck_rule_group_migration.sql
|
||||
|
||||
-- =========================================================
|
||||
-- 0. 文档类型与入口模块映射总览
|
||||
-- =========================================================
|
||||
SELECT
|
||||
dt.id,
|
||||
dt.code,
|
||||
dt.name,
|
||||
dt.entry_module_id,
|
||||
em.name AS entry_module_name,
|
||||
dt.sort_order,
|
||||
dt.is_enabled
|
||||
FROM leaudit_document_types dt
|
||||
LEFT JOIN leaudit_entry_modules em
|
||||
ON em.id = dt.entry_module_id
|
||||
WHERE dt.deleted_at IS NULL
|
||||
ORDER BY dt.sort_order, dt.id;
|
||||
|
||||
-- =========================================================
|
||||
-- 1. 旧一级根检查:一级直接挂具体文档类型
|
||||
-- =========================================================
|
||||
SELECT
|
||||
id,
|
||||
code,
|
||||
name,
|
||||
document_type_id,
|
||||
entry_module_id,
|
||||
sort_order,
|
||||
is_enabled
|
||||
FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) = 0
|
||||
AND document_type_id IS NOT NULL
|
||||
ORDER BY id;
|
||||
|
||||
-- =========================================================
|
||||
-- 2. 新一级业务大类根检查:一级不直接挂文档类型
|
||||
-- =========================================================
|
||||
SELECT
|
||||
id,
|
||||
code,
|
||||
name,
|
||||
entry_module_id,
|
||||
sort_order,
|
||||
is_enabled
|
||||
FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) = 0
|
||||
AND document_type_id IS NULL
|
||||
ORDER BY sort_order, id;
|
||||
|
||||
-- =========================================================
|
||||
-- 3. 二级分组全量清单
|
||||
-- =========================================================
|
||||
SELECT
|
||||
child.id,
|
||||
child.pid,
|
||||
parent.name AS parent_name,
|
||||
child.code,
|
||||
child.name,
|
||||
child.document_type_id,
|
||||
dt.name AS document_type_name,
|
||||
COALESCE(child.entry_module_id, parent.entry_module_id, dt.entry_module_id) AS resolved_entry_module_id,
|
||||
em.name AS resolved_entry_module_name,
|
||||
child.sort_order,
|
||||
child.is_enabled
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
LEFT JOIN leaudit_evaluation_point_groups parent
|
||||
ON parent.id = child.pid
|
||||
AND parent.deleted_at IS NULL
|
||||
LEFT JOIN leaudit_document_types dt
|
||||
ON dt.id = child.document_type_id
|
||||
LEFT JOIN leaudit_entry_modules em
|
||||
ON em.id = COALESCE(child.entry_module_id, parent.entry_module_id, dt.entry_module_id)
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND COALESCE(child.pid, 0) <> 0
|
||||
ORDER BY child.pid, child.sort_order, child.id;
|
||||
|
||||
-- =========================================================
|
||||
-- 4. 二级分组唯一性检查:同一文档类型是否被多个二级分组承接
|
||||
-- =========================================================
|
||||
SELECT
|
||||
document_type_id,
|
||||
COUNT(*) AS child_count,
|
||||
STRING_AGG(name, ' / ' ORDER BY id) AS child_names
|
||||
FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) <> 0
|
||||
AND document_type_id IS NOT NULL
|
||||
GROUP BY document_type_id
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY document_type_id;
|
||||
|
||||
-- =========================================================
|
||||
-- 5. 旧默认子级检查:通用 / *.default
|
||||
-- =========================================================
|
||||
SELECT
|
||||
child.id,
|
||||
child.pid,
|
||||
parent.name AS parent_name,
|
||||
child.name,
|
||||
child.code,
|
||||
child.document_type_id
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
JOIN leaudit_evaluation_point_groups parent
|
||||
ON parent.id = child.pid
|
||||
AND parent.deleted_at IS NULL
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND COALESCE(child.pid, 0) <> 0
|
||||
AND (
|
||||
child.name = '通用'
|
||||
OR child.code LIKE '%.default'
|
||||
)
|
||||
ORDER BY child.id;
|
||||
|
||||
-- =========================================================
|
||||
-- 6. 规则集绑定全量清单:按分组树展开
|
||||
-- =========================================================
|
||||
SELECT
|
||||
rgb.id AS binding_id,
|
||||
rgb.group_id,
|
||||
root.id AS root_id,
|
||||
root.name AS root_name,
|
||||
child.id AS child_id,
|
||||
child.name AS child_name,
|
||||
child.document_type_id,
|
||||
dt.name AS document_type_name,
|
||||
rgb.rule_set_id,
|
||||
rs.rule_name,
|
||||
rs.rule_type,
|
||||
rgb.priority,
|
||||
rgb.is_active,
|
||||
rgb.note
|
||||
FROM leaudit_rule_group_bindings rgb
|
||||
JOIN leaudit_evaluation_point_groups child
|
||||
ON child.id = rgb.group_id
|
||||
AND child.deleted_at IS NULL
|
||||
LEFT JOIN leaudit_evaluation_point_groups root
|
||||
ON root.id = child.pid
|
||||
AND root.deleted_at IS NULL
|
||||
LEFT JOIN leaudit_document_types dt
|
||||
ON dt.id = child.document_type_id
|
||||
LEFT JOIN leaudit_rule_sets rs
|
||||
ON rs.id = rgb.rule_set_id
|
||||
WHERE rgb.deleted_at IS NULL
|
||||
ORDER BY root.id, child.id, rgb.priority DESC, rgb.id;
|
||||
|
||||
-- =========================================================
|
||||
-- 7. 规则集重复挂载检查:旧一级根与默认子级是否同时挂了同一规则集
|
||||
-- =========================================================
|
||||
WITH target_groups AS (
|
||||
SELECT
|
||||
g.id,
|
||||
g.document_type_id,
|
||||
g.name,
|
||||
g.code,
|
||||
CASE
|
||||
WHEN COALESCE(g.pid, 0) = 0 THEN 'old_root'
|
||||
WHEN g.name = '通用' OR g.code LIKE '%.default' THEN 'default_child'
|
||||
ELSE 'other_child'
|
||||
END AS group_kind
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND g.document_type_id IS NOT NULL
|
||||
)
|
||||
SELECT
|
||||
tg.document_type_id,
|
||||
rgb.rule_set_id,
|
||||
COUNT(*) AS binding_count,
|
||||
STRING_AGG(tg.group_kind || ':' || tg.name, ' / ' ORDER BY tg.id) AS group_sources
|
||||
FROM leaudit_rule_group_bindings rgb
|
||||
JOIN target_groups tg
|
||||
ON tg.id = rgb.group_id
|
||||
WHERE rgb.deleted_at IS NULL
|
||||
GROUP BY tg.document_type_id, rgb.rule_set_id
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY tg.document_type_id, rgb.rule_set_id;
|
||||
|
||||
-- =========================================================
|
||||
-- 8. 文档类型汇总绑定表现状:leaudit_rule_type_bindings
|
||||
-- =========================================================
|
||||
SELECT
|
||||
rtb.id,
|
||||
rtb.doc_type_id,
|
||||
dt.name AS document_type_name,
|
||||
rtb.doc_type_code,
|
||||
rtb.rule_set_id,
|
||||
rs.rule_name,
|
||||
rs.rule_type,
|
||||
rtb.binding_mode,
|
||||
rtb.priority,
|
||||
rtb.is_active,
|
||||
rtb.note
|
||||
FROM leaudit_rule_type_bindings rtb
|
||||
LEFT JOIN leaudit_document_types dt
|
||||
ON dt.id = rtb.doc_type_id
|
||||
LEFT JOIN leaudit_rule_sets rs
|
||||
ON rs.id = rtb.rule_set_id
|
||||
WHERE rtb.deleted_at IS NULL
|
||||
ORDER BY rtb.doc_type_id, rtb.priority DESC, rtb.id;
|
||||
|
||||
-- =========================================================
|
||||
-- 9. 规则集可运行性检查:版本占位
|
||||
-- =========================================================
|
||||
SELECT
|
||||
rs.id,
|
||||
rs.rule_name,
|
||||
rs.rule_type,
|
||||
rs.current_version_id,
|
||||
NULL::bigint AS fallback_version_id,
|
||||
rs.status
|
||||
FROM leaudit_rule_sets rs
|
||||
WHERE rs.deleted_at IS NULL
|
||||
ORDER BY rs.id;
|
||||
|
||||
-- =========================================================
|
||||
-- 10. 文档类型缺失入口模块检查
|
||||
-- =========================================================
|
||||
SELECT
|
||||
dt.id,
|
||||
dt.code,
|
||||
dt.name
|
||||
FROM leaudit_document_types dt
|
||||
WHERE dt.deleted_at IS NULL
|
||||
AND dt.entry_module_id IS NULL
|
||||
ORDER BY dt.id;
|
||||
|
||||
-- =========================================================
|
||||
-- 11. 一级根缺失入口模块检查
|
||||
-- =========================================================
|
||||
SELECT
|
||||
id,
|
||||
code,
|
||||
name
|
||||
FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) = 0
|
||||
AND document_type_id IS NULL
|
||||
AND entry_module_id IS NULL
|
||||
ORDER BY id;
|
||||
|
||||
-- =========================================================
|
||||
-- 12. 新链路下无法命中规则集的二级分组检查
|
||||
-- =========================================================
|
||||
SELECT
|
||||
child.id,
|
||||
child.name,
|
||||
child.code,
|
||||
child.document_type_id,
|
||||
dt.name AS document_type_name,
|
||||
COUNT(rgb.id) AS binding_count
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
LEFT JOIN leaudit_rule_group_bindings rgb
|
||||
ON rgb.group_id = child.id
|
||||
AND rgb.deleted_at IS NULL
|
||||
AND rgb.is_active = TRUE
|
||||
LEFT JOIN leaudit_document_types dt
|
||||
ON dt.id = child.document_type_id
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND COALESCE(child.pid, 0) <> 0
|
||||
GROUP BY child.id, child.name, child.code, child.document_type_id, dt.name
|
||||
HAVING COUNT(rgb.id) = 0
|
||||
ORDER BY child.id;
|
||||
@@ -0,0 +1,91 @@
|
||||
BEGIN;
|
||||
|
||||
WITH rules_route AS (
|
||||
SELECT id
|
||||
FROM sys_routes
|
||||
WHERE route_path = '/rules'
|
||||
AND deleted_at IS NULL
|
||||
LIMIT 1
|
||||
)
|
||||
INSERT INTO permissions (
|
||||
permission_key,
|
||||
module,
|
||||
resource,
|
||||
action,
|
||||
description,
|
||||
display_name,
|
||||
permission_type,
|
||||
is_system,
|
||||
metadata,
|
||||
created_at,
|
||||
updated_at,
|
||||
sort_order,
|
||||
route_id,
|
||||
api_path,
|
||||
api_method
|
||||
)
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT 'evaluation_point:list:read', 'evaluation_point', 'list', 'read', '查看评查点列表', '评查点列表', 'API', TRUE, '{}'::jsonb, NOW(), NOW(), 51, (SELECT id FROM rules_route), '/api/v3/evaluation-points', 'GET'
|
||||
UNION ALL
|
||||
SELECT 'evaluation_point:detail:read', 'evaluation_point', 'detail', 'read', '查看评查点详情', '评查点详情', 'API', TRUE, '{}'::jsonb, NOW(), NOW(), 52, (SELECT id FROM rules_route), '/api/v3/evaluation-points/{id}', 'GET'
|
||||
UNION ALL
|
||||
SELECT 'evaluation_point:create:write', 'evaluation_point', 'create', 'write', '创建评查点', '创建评查点', 'API', TRUE, '{}'::jsonb, NOW(), NOW(), 53, (SELECT id FROM rules_route), '/api/v3/evaluation-points', 'POST'
|
||||
UNION ALL
|
||||
SELECT 'evaluation_point:update:write', 'evaluation_point', 'update', 'write', '更新评查点', '更新评查点', 'API', TRUE, '{}'::jsonb, NOW(), NOW(), 54, (SELECT id FROM rules_route), '/api/v3/evaluation-points/{id}', 'PUT'
|
||||
UNION ALL
|
||||
SELECT 'evaluation_point:delete:delete', 'evaluation_point', 'delete', 'delete', '删除评查点', '删除评查点', 'API', TRUE, '{}'::jsonb, NOW(), NOW(), 55, (SELECT id FROM rules_route), '/api/v3/evaluation-points/{id}', 'DELETE'
|
||||
) AS seed
|
||||
ON CONFLICT (permission_key)
|
||||
DO UPDATE SET
|
||||
module = EXCLUDED.module,
|
||||
resource = EXCLUDED.resource,
|
||||
action = EXCLUDED.action,
|
||||
description = EXCLUDED.description,
|
||||
display_name = EXCLUDED.display_name,
|
||||
permission_type = EXCLUDED.permission_type,
|
||||
is_system = EXCLUDED.is_system,
|
||||
metadata = EXCLUDED.metadata,
|
||||
updated_at = NOW(),
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
route_id = EXCLUDED.route_id,
|
||||
api_path = EXCLUDED.api_path,
|
||||
api_method = EXCLUDED.api_method;
|
||||
|
||||
WITH permission_ids AS (
|
||||
SELECT id
|
||||
FROM permissions
|
||||
WHERE permission_key IN (
|
||||
'evaluation_point:list:read',
|
||||
'evaluation_point:detail:read',
|
||||
'evaluation_point:create:write',
|
||||
'evaluation_point:update:write',
|
||||
'evaluation_point:delete:delete'
|
||||
)
|
||||
), admin_roles AS (
|
||||
SELECT id,
|
||||
CASE
|
||||
WHEN role_key = 'admin' THEN 'DEPT'
|
||||
ELSE 'ALL'
|
||||
END AS data_scope
|
||||
FROM roles
|
||||
WHERE role_key IN ('super_admin', 'provincial_admin', 'admin')
|
||||
)
|
||||
INSERT INTO role_permissions (
|
||||
role_id,
|
||||
permission_id,
|
||||
grant_type,
|
||||
data_scope,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT admin_roles.id, permission_ids.id, 'GRANT', admin_roles.data_scope, NOW(), NOW()
|
||||
FROM admin_roles
|
||||
CROSS JOIN permission_ids
|
||||
ON CONFLICT (role_id, permission_id)
|
||||
DO UPDATE SET
|
||||
grant_type = EXCLUDED.grant_type,
|
||||
data_scope = EXCLUDED.data_scope,
|
||||
updated_at = NOW();
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,177 @@
|
||||
BEGIN;
|
||||
|
||||
-- 补齐当前前端真实菜单树里仍需要暴露的模块路由:
|
||||
-- 1. AI 对话
|
||||
-- 2. 合同管理(搜索/列表)
|
||||
-- 3. 交叉评查
|
||||
WITH upsert_routes AS (
|
||||
INSERT INTO sys_routes (
|
||||
route_path,
|
||||
route_name,
|
||||
component,
|
||||
parent_id,
|
||||
route_title,
|
||||
icon,
|
||||
sort_order,
|
||||
is_hidden,
|
||||
is_cache,
|
||||
meta,
|
||||
status,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at
|
||||
)
|
||||
VALUES
|
||||
('/chat-with-llm', 'chat-with-llm', 'chat-with-llm', NULL, 'AI对话', 'ri-chat-smile-2-line', 20, FALSE, TRUE, '{"group":"assistant"}'::jsonb, 0, NOW(), NOW(), NULL),
|
||||
('/contract-template', 'contract-template', 'contract-template', NULL, '合同管理', 'ri-file-search-line', 50, FALSE, TRUE, '{"group":"contract"}'::jsonb, 0, NOW(), NOW(), NULL),
|
||||
('/cross-checking', 'cross-checking', 'cross-checking', NULL, '交叉评查', 'ri-color-filter-line', 70, FALSE, TRUE, '{"group":"cross-review"}'::jsonb, 0, NOW(), NOW(), NULL)
|
||||
ON CONFLICT (route_path) WHERE deleted_at IS NULL
|
||||
DO UPDATE SET
|
||||
route_name = EXCLUDED.route_name,
|
||||
component = EXCLUDED.component,
|
||||
route_title = EXCLUDED.route_title,
|
||||
icon = EXCLUDED.icon,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
is_hidden = EXCLUDED.is_hidden,
|
||||
is_cache = EXCLUDED.is_cache,
|
||||
meta = EXCLUDED.meta,
|
||||
status = 0,
|
||||
updated_at = NOW(),
|
||||
deleted_at = NULL
|
||||
RETURNING id, route_path
|
||||
),
|
||||
all_root_routes AS (
|
||||
SELECT id, route_path
|
||||
FROM sys_routes
|
||||
WHERE deleted_at IS NULL
|
||||
AND route_path IN ('/chat-with-llm', '/contract-template', '/cross-checking')
|
||||
),
|
||||
template_root AS (
|
||||
SELECT id FROM all_root_routes WHERE route_path = '/contract-template'
|
||||
),
|
||||
cross_root AS (
|
||||
SELECT id FROM all_root_routes WHERE route_path = '/cross-checking'
|
||||
)
|
||||
INSERT INTO sys_routes (
|
||||
route_path,
|
||||
route_name,
|
||||
component,
|
||||
parent_id,
|
||||
route_title,
|
||||
icon,
|
||||
sort_order,
|
||||
is_hidden,
|
||||
is_cache,
|
||||
meta,
|
||||
status,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at
|
||||
)
|
||||
VALUES
|
||||
('/contract-template/search', 'contract-template.search', 'contract-template.search', (SELECT id FROM template_root), '模板搜索', 'ri-search-line', 1, FALSE, TRUE, '{"group":"contract"}'::jsonb, 0, NOW(), NOW(), NULL),
|
||||
('/contract-template/list', 'contract-template.list', 'contract-template.list', (SELECT id FROM template_root), '模板列表', 'ri-folder-line', 2, FALSE, TRUE, '{"group":"contract"}'::jsonb, 0, NOW(), NOW(), NULL),
|
||||
('/cross-checking/upload', 'cross-checking.upload', 'cross-checking.upload', (SELECT id FROM cross_root), '创建任务', 'ri-upload-cloud-line', 1, FALSE, TRUE, '{"group":"cross-review"}'::jsonb, 0, NOW(), NOW(), NULL),
|
||||
('/cross-checking/result', 'cross-checking.result', 'cross-checking.result', (SELECT id FROM cross_root), '评查结果', 'ri-file-list-3-line', 2, FALSE, TRUE, '{"group":"cross-review"}'::jsonb, 0, NOW(), NOW(), NULL)
|
||||
ON CONFLICT (route_path) WHERE deleted_at IS NULL
|
||||
DO UPDATE SET
|
||||
route_name = EXCLUDED.route_name,
|
||||
component = EXCLUDED.component,
|
||||
parent_id = EXCLUDED.parent_id,
|
||||
route_title = EXCLUDED.route_title,
|
||||
icon = EXCLUDED.icon,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
is_hidden = EXCLUDED.is_hidden,
|
||||
is_cache = EXCLUDED.is_cache,
|
||||
meta = EXCLUDED.meta,
|
||||
status = 0,
|
||||
updated_at = NOW(),
|
||||
deleted_at = NULL;
|
||||
|
||||
-- 修正旧环境已存在记录的父子关系与显示名,避免菜单被拆成多个平级项
|
||||
UPDATE sys_routes AS child
|
||||
SET
|
||||
parent_id = root.id,
|
||||
route_title = CASE
|
||||
WHEN child.route_path = '/contract-template/search' THEN '模板搜索'
|
||||
WHEN child.route_path = '/contract-template/list' THEN '模板列表'
|
||||
WHEN child.route_path = '/cross-checking/upload' THEN '创建任务'
|
||||
WHEN child.route_path = '/cross-checking/result' THEN '评查结果'
|
||||
ELSE child.route_title
|
||||
END,
|
||||
updated_at = NOW()
|
||||
FROM sys_routes root
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND root.deleted_at IS NULL
|
||||
AND (
|
||||
(child.route_path IN ('/contract-template/search', '/contract-template/list') AND root.route_path = '/contract-template')
|
||||
OR (child.route_path IN ('/cross-checking/upload', '/cross-checking/result') AND root.route_path = '/cross-checking')
|
||||
);
|
||||
|
||||
UPDATE sys_routes
|
||||
SET route_title = CASE
|
||||
WHEN route_path = '/contract-template' THEN '合同管理'
|
||||
WHEN route_path = '/contract-template/search' THEN '模板搜索'
|
||||
WHEN route_path = '/contract-template/list' THEN '模板列表'
|
||||
ELSE route_title
|
||||
END,
|
||||
updated_at = NOW()
|
||||
WHERE deleted_at IS NULL
|
||||
AND route_path IN ('/contract-template', '/contract-template/search', '/contract-template/list');
|
||||
|
||||
WITH role_map AS (
|
||||
SELECT id, role_key
|
||||
FROM roles
|
||||
WHERE role_key IN ('super_admin', 'provincial_admin', 'admin')
|
||||
),
|
||||
route_map AS (
|
||||
SELECT id, route_path
|
||||
FROM sys_routes
|
||||
WHERE deleted_at IS NULL
|
||||
AND route_path IN (
|
||||
'/chat-with-llm',
|
||||
'/contract-template',
|
||||
'/contract-template/search',
|
||||
'/contract-template/list',
|
||||
'/cross-checking',
|
||||
'/cross-checking/upload',
|
||||
'/cross-checking/result'
|
||||
)
|
||||
),
|
||||
seed(role_key, route_path, permission, status) AS (
|
||||
VALUES
|
||||
('super_admin', '/chat-with-llm', 'RW', 1),
|
||||
('super_admin', '/contract-template', 'RW', 1),
|
||||
('super_admin', '/contract-template/search', 'RW', 1),
|
||||
('super_admin', '/contract-template/list', 'RW', 1),
|
||||
('super_admin', '/cross-checking', 'RW', 1),
|
||||
('super_admin', '/cross-checking/upload', 'RW', 1),
|
||||
('super_admin', '/cross-checking/result', 'RW', 1),
|
||||
|
||||
('provincial_admin', '/chat-with-llm', 'RW', 1),
|
||||
('provincial_admin', '/contract-template', 'RW', 1),
|
||||
('provincial_admin', '/contract-template/search', 'RW', 1),
|
||||
('provincial_admin', '/contract-template/list', 'RW', 1),
|
||||
('provincial_admin', '/cross-checking', 'RW', 1),
|
||||
('provincial_admin', '/cross-checking/upload', 'RW', 1),
|
||||
('provincial_admin', '/cross-checking/result', 'RW', 1),
|
||||
|
||||
('admin', '/chat-with-llm', 'RW', 1),
|
||||
('admin', '/contract-template', 'RW', 1),
|
||||
('admin', '/contract-template/search', 'RW', 1),
|
||||
('admin', '/contract-template/list', 'RW', 1),
|
||||
('admin', '/cross-checking', 'RW', 1),
|
||||
('admin', '/cross-checking/upload', 'RW', 1),
|
||||
('admin', '/cross-checking/result', 'RW', 1)
|
||||
)
|
||||
INSERT INTO role_route (role_id, route_id, permission, status, created_at, updated_at)
|
||||
SELECT rm.id, tm.id, s.permission, s.status, NOW(), NOW()
|
||||
FROM seed s
|
||||
JOIN role_map rm ON rm.role_key = s.role_key
|
||||
JOIN route_map tm ON tm.route_path = s.route_path
|
||||
ON CONFLICT (role_id, route_id) DO UPDATE SET
|
||||
permission = EXCLUDED.permission,
|
||||
status = EXCLUDED.status,
|
||||
updated_at = NOW();
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,161 @@
|
||||
-- ============================================================================
|
||||
-- 首页入口模块初始化脚本(按老系统真实语义迁移)
|
||||
-- 用途:
|
||||
-- 1. 初始化首页入口模块
|
||||
-- 2. 绑定现有 leaudit_document_types.entry_module_id
|
||||
-- 3. 对齐老系统“入口模块表只存业务入口 + 图片路径,跳转由前端硬编码”的实际情况
|
||||
--
|
||||
-- 当前新系统落地策略:
|
||||
-- - leaudit_entry_modules.path = 前端跳转路由
|
||||
-- - leaudit_entry_modules.icon_path = 入口图标路径
|
||||
--
|
||||
-- 老系统真实数据来源(docauditai):
|
||||
-- 1. 合同管理
|
||||
-- - 图片:documents/mz/static/img/entry_module_1.png
|
||||
-- - 文档类型:HT
|
||||
-- - 实际跳转:/contract-template/search
|
||||
-- 2. 案卷智能评查
|
||||
-- - 图片:documents/mz/static/img/entry_module_2.png
|
||||
-- - 文档类型:XZXK, XZCF
|
||||
-- - 实际跳转:/home
|
||||
-- 3. 内部公文
|
||||
-- - 图片:documents/mz/static/img/entry_module_15.png
|
||||
-- - 文档类型:NBGW
|
||||
-- - 实际跳转:/home
|
||||
--
|
||||
-- 另外补齐老前端硬编码入口:
|
||||
-- 4. 智慧法务助手 -> /chat-with-llm/chat
|
||||
-- 5. 交叉评查 -> /cross-checking
|
||||
-- ============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
INSERT INTO leaudit_entry_modules (
|
||||
name,
|
||||
description,
|
||||
path,
|
||||
icon_path,
|
||||
areas,
|
||||
sort_order,
|
||||
is_enabled,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
'合同管理',
|
||||
'合同管理入口模块',
|
||||
'/contract-template/search',
|
||||
'documents/mz/static/img/entry_module_1.png',
|
||||
'[
|
||||
{"area":"梅州","enabled":true,"sort_order":1},
|
||||
{"area":"云浮","enabled":true,"sort_order":2},
|
||||
{"area":"揭阳","enabled":true,"sort_order":3},
|
||||
{"area":"潮州","enabled":true,"sort_order":4},
|
||||
{"area":"省局","enabled":true,"sort_order":5}
|
||||
]'::jsonb,
|
||||
10,
|
||||
TRUE,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP,
|
||||
NULL
|
||||
),
|
||||
(
|
||||
'案卷智能评查',
|
||||
'案卷类型的入口模块',
|
||||
'/home',
|
||||
'documents/mz/static/img/entry_module_2.png',
|
||||
'[
|
||||
{"area":"梅州","enabled":true,"sort_order":1},
|
||||
{"area":"揭阳","enabled":true,"sort_order":2},
|
||||
{"area":"云浮","enabled":true,"sort_order":3},
|
||||
{"area":"潮州","enabled":true,"sort_order":4},
|
||||
{"area":"省局","enabled":true,"sort_order":5}
|
||||
]'::jsonb,
|
||||
20,
|
||||
TRUE,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP,
|
||||
NULL
|
||||
),
|
||||
(
|
||||
'内部公文',
|
||||
'内部公文',
|
||||
'/home',
|
||||
'documents/mz/static/img/entry_module_15.png',
|
||||
'[
|
||||
{"area":"潮州","enabled":true,"sort_order":1},
|
||||
{"area":"省局","enabled":true,"sort_order":2},
|
||||
{"area":"揭阳","enabled":true,"sort_order":3},
|
||||
{"area":"梅州","enabled":true,"sort_order":4},
|
||||
{"area":"云浮","enabled":true,"sort_order":5}
|
||||
]'::jsonb,
|
||||
30,
|
||||
TRUE,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP,
|
||||
NULL
|
||||
),
|
||||
(
|
||||
'智慧法务助手',
|
||||
'大模型法务助手入口',
|
||||
'/chat-with-llm/chat',
|
||||
'/images/icon_assistant.png',
|
||||
NULL,
|
||||
40,
|
||||
TRUE,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP,
|
||||
NULL
|
||||
),
|
||||
(
|
||||
'交叉评查',
|
||||
'交叉评查任务入口',
|
||||
'/cross-checking',
|
||||
'/images/icon_cross@2x.png',
|
||||
NULL,
|
||||
50,
|
||||
TRUE,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP,
|
||||
NULL
|
||||
)
|
||||
ON CONFLICT (name) DO UPDATE
|
||||
SET
|
||||
description = EXCLUDED.description,
|
||||
path = EXCLUDED.path,
|
||||
icon_path = EXCLUDED.icon_path,
|
||||
areas = EXCLUDED.areas,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
is_enabled = EXCLUDED.is_enabled,
|
||||
updated_at = CURRENT_TIMESTAMP,
|
||||
deleted_at = NULL;
|
||||
|
||||
WITH module_map AS (
|
||||
SELECT id, name
|
||||
FROM leaudit_entry_modules
|
||||
WHERE deleted_at IS NULL
|
||||
)
|
||||
UPDATE leaudit_document_types dt
|
||||
SET
|
||||
entry_module_id = mm.id,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
FROM module_map mm
|
||||
WHERE dt.deleted_at IS NULL
|
||||
AND (
|
||||
(
|
||||
mm.name = '合同管理'
|
||||
AND dt.code LIKE 'contract.%'
|
||||
)
|
||||
OR (
|
||||
mm.name = '案卷智能评查'
|
||||
AND dt.code LIKE '行政卷宗.%'
|
||||
)
|
||||
OR (
|
||||
mm.name = '内部公文'
|
||||
AND dt.code IN ('NBGW', 'internal.document')
|
||||
)
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,163 @@
|
||||
BEGIN;
|
||||
|
||||
WITH settings_route AS (
|
||||
SELECT id FROM sys_routes WHERE route_path = '/settings' AND deleted_at IS NULL LIMIT 1
|
||||
), upsert_route AS (
|
||||
INSERT INTO sys_routes (
|
||||
route_path,
|
||||
route_name,
|
||||
component,
|
||||
parent_id,
|
||||
route_title,
|
||||
icon,
|
||||
sort_order,
|
||||
is_hidden,
|
||||
is_cache,
|
||||
meta,
|
||||
status,
|
||||
created_at,
|
||||
updated_at,
|
||||
deleted_at
|
||||
)
|
||||
SELECT
|
||||
'/rule-groups',
|
||||
'rule-groups',
|
||||
'rule-groups',
|
||||
settings_route.id,
|
||||
'评查点分组',
|
||||
'ri-folder-open-line',
|
||||
4,
|
||||
FALSE,
|
||||
TRUE,
|
||||
'{"group": "settings"}'::jsonb,
|
||||
0,
|
||||
NOW(),
|
||||
NOW(),
|
||||
NULL
|
||||
FROM settings_route
|
||||
ON CONFLICT (route_path) WHERE deleted_at IS NULL
|
||||
DO UPDATE SET
|
||||
route_name = EXCLUDED.route_name,
|
||||
component = EXCLUDED.component,
|
||||
parent_id = EXCLUDED.parent_id,
|
||||
route_title = EXCLUDED.route_title,
|
||||
icon = EXCLUDED.icon,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
is_hidden = EXCLUDED.is_hidden,
|
||||
is_cache = EXCLUDED.is_cache,
|
||||
meta = EXCLUDED.meta,
|
||||
status = 0,
|
||||
updated_at = NOW(),
|
||||
deleted_at = NULL
|
||||
RETURNING id
|
||||
), target_route AS (
|
||||
SELECT id FROM upsert_route
|
||||
UNION ALL
|
||||
SELECT id FROM sys_routes WHERE route_path = '/rule-groups' AND deleted_at IS NULL LIMIT 1
|
||||
)
|
||||
INSERT INTO permissions (
|
||||
permission_key,
|
||||
module,
|
||||
resource,
|
||||
action,
|
||||
description,
|
||||
display_name,
|
||||
permission_type,
|
||||
is_system,
|
||||
metadata,
|
||||
created_at,
|
||||
updated_at,
|
||||
sort_order,
|
||||
route_id,
|
||||
api_path,
|
||||
api_method
|
||||
)
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT 'evaluation_group:list:read', 'evaluation_group', 'list', 'read', '查看评查点分组列表', '查看评查点分组列表', 'API', FALSE, '{}'::jsonb, NOW(), NOW(), 1, (SELECT id FROM target_route LIMIT 1), '/api/v3/evaluation-point-groups', 'GET'
|
||||
UNION ALL
|
||||
SELECT 'evaluation_group:detail:read', 'evaluation_group', 'detail', 'read', '查看评查点分组详情', '查看评查点分组详情', 'API', FALSE, '{}'::jsonb, NOW(), NOW(), 2, (SELECT id FROM target_route LIMIT 1), '/api/v3/evaluation-point-groups/{id}', 'GET'
|
||||
UNION ALL
|
||||
SELECT 'evaluation_group:create:write','evaluation_group', 'create', 'write', '创建评查点分组', '创建评查点分组', 'API', FALSE, '{}'::jsonb, NOW(), NOW(), 3, (SELECT id FROM target_route LIMIT 1), '/api/v3/evaluation-point-groups', 'POST'
|
||||
UNION ALL
|
||||
SELECT 'evaluation_group:update:write','evaluation_group', 'update', 'write', '更新评查点分组', '更新评查点分组', 'API', FALSE, '{}'::jsonb, NOW(), NOW(), 4, (SELECT id FROM target_route LIMIT 1), '/api/v3/evaluation-point-groups/{id}', 'PUT'
|
||||
UNION ALL
|
||||
SELECT 'evaluation_group:delete:delete','evaluation_group','delete', 'delete', '删除评查点分组', '删除评查点分组', 'API', FALSE, '{}'::jsonb, NOW(), NOW(), 5, (SELECT id FROM target_route LIMIT 1), '/api/v3/evaluation-point-groups/{id}', 'DELETE'
|
||||
UNION ALL
|
||||
SELECT 'evaluation_group:batch:write', 'evaluation_group', 'batch', 'write', '批量操作评查点分组', '批量操作评查点分组', 'API', FALSE, '{}'::jsonb, NOW(), NOW(), 6, (SELECT id FROM target_route LIMIT 1), '/api/v3/evaluation-point-groups/batch/status', 'PATCH'
|
||||
) AS seed
|
||||
ON CONFLICT (permission_key)
|
||||
DO UPDATE SET
|
||||
module = EXCLUDED.module,
|
||||
resource = EXCLUDED.resource,
|
||||
action = EXCLUDED.action,
|
||||
description = EXCLUDED.description,
|
||||
display_name = EXCLUDED.display_name,
|
||||
permission_type = EXCLUDED.permission_type,
|
||||
metadata = EXCLUDED.metadata,
|
||||
updated_at = NOW(),
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
route_id = EXCLUDED.route_id,
|
||||
api_path = EXCLUDED.api_path,
|
||||
api_method = EXCLUDED.api_method;
|
||||
|
||||
WITH permission_ids AS (
|
||||
SELECT id, permission_key
|
||||
FROM permissions
|
||||
WHERE permission_key IN (
|
||||
'evaluation_group:list:read',
|
||||
'evaluation_group:detail:read',
|
||||
'evaluation_group:create:write',
|
||||
'evaluation_group:update:write',
|
||||
'evaluation_group:delete:delete',
|
||||
'evaluation_group:batch:write'
|
||||
)
|
||||
), admin_roles AS (
|
||||
SELECT id
|
||||
FROM roles
|
||||
WHERE role_key IN ('super_admin', 'provincial_admin', 'admin')
|
||||
), route_id AS (
|
||||
SELECT id FROM sys_routes WHERE route_path = '/rule-groups' AND deleted_at IS NULL LIMIT 1
|
||||
)
|
||||
INSERT INTO role_permissions (
|
||||
role_id,
|
||||
permission_id,
|
||||
grant_type,
|
||||
data_scope,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT admin_roles.id, permission_ids.id, 'GRANT', 'ALL', NOW(), NOW()
|
||||
FROM admin_roles
|
||||
CROSS JOIN permission_ids
|
||||
ON CONFLICT (role_id, permission_id)
|
||||
DO UPDATE SET
|
||||
grant_type = EXCLUDED.grant_type,
|
||||
data_scope = EXCLUDED.data_scope,
|
||||
updated_at = NOW();
|
||||
|
||||
WITH admin_roles AS (
|
||||
SELECT id
|
||||
FROM roles
|
||||
WHERE role_key IN ('super_admin', 'provincial_admin', 'admin')
|
||||
), route_id AS (
|
||||
SELECT id FROM sys_routes WHERE route_path = '/rule-groups' AND deleted_at IS NULL LIMIT 1
|
||||
)
|
||||
INSERT INTO role_route (
|
||||
role_id,
|
||||
route_id,
|
||||
permission,
|
||||
created_at,
|
||||
updated_at,
|
||||
status
|
||||
)
|
||||
SELECT admin_roles.id, route_id.id, 'RW', NOW(), NOW(), 1
|
||||
FROM admin_roles
|
||||
CROSS JOIN route_id
|
||||
ON CONFLICT (role_id, route_id)
|
||||
DO UPDATE SET
|
||||
permission = EXCLUDED.permission,
|
||||
updated_at = NOW(),
|
||||
status = 1;
|
||||
|
||||
COMMIT;
|
||||
@@ -38,7 +38,14 @@ VALUES
|
||||
('/rules/sets', 'rules.sets', 'rules/sets', NULL, '规则集管理', 'yaml', 31, FALSE, TRUE, '{"group":"rules"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/system', 'system', 'Layout', NULL, '系统管理', 'setting', 90, FALSE, TRUE, '{"group":"system"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/system/users', 'system.users', 'system/users', NULL, '用户管理', 'user', 91, FALSE, TRUE, '{"group":"system"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/system/roles', 'system.roles', 'system/roles', NULL, '角色权限', 'shield', 92, FALSE, TRUE, '{"group":"system"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL)
|
||||
('/system/roles', 'system.roles', 'system/roles', NULL, '角色权限', 'shield', 92, FALSE, TRUE, '{"group":"system"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/chat-with-llm', 'chat-with-llm', 'chat-with-llm', NULL, 'AI对话', 'chat', 15, FALSE, TRUE, '{"group":"assistant"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/contract-template', 'contract-template', 'contract-template', NULL, '合同管理', 'file-search', 40, FALSE, TRUE, '{"group":"contract"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/contract-template/search', 'contract-template.search', 'contract-template/search', NULL, '模板搜索', 'search', 41, FALSE, TRUE, '{"group":"contract"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/contract-template/list', 'contract-template.list', 'contract-template/list', NULL, '模板列表', 'folder', 42, FALSE, TRUE, '{"group":"contract"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/cross-checking', 'cross-checking', 'cross-checking', NULL, '交叉评查', 'flow', 60, FALSE, TRUE, '{"group":"cross-review"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/cross-checking/upload', 'cross-checking.upload', 'cross-checking/upload', NULL, '创建任务', 'upload', 61, FALSE, TRUE, '{"group":"cross-review"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||
('/cross-checking/result', 'cross-checking.result', 'cross-checking/result', NULL, '评查结果', 'table', 62, FALSE, TRUE, '{"group":"cross-review"}'::jsonb, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- --------------------------------------------------------------------------
|
||||
@@ -73,6 +80,11 @@ VALUES
|
||||
('rules:binding_create:write', 'rules', 'binding_create', 'write', '创建规则绑定', '创建规则绑定', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 48, NULL, '/api/rule-sets/{rule_type}/bindings', 'POST', NULL),
|
||||
('rules:binding_update:write', 'rules', 'binding_update', 'write', '更新规则绑定', '更新规则绑定', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 49, NULL, '/api/rule-sets/bindings/{binding_id}', 'PUT', NULL),
|
||||
('rules:binding_delete:delete', 'rules', 'binding_delete', 'delete', '删除规则绑定', '删除规则绑定', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 50, NULL, '/api/rule-sets/bindings/{binding_id}', 'DELETE', NULL),
|
||||
('evaluation_point:list:read', 'evaluation_point', 'list', 'read', '查看评查点列表', '评查点列表', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 51, NULL, '/api/v3/evaluation-points', 'GET', NULL),
|
||||
('evaluation_point:detail:read', 'evaluation_point', 'detail', 'read', '查看评查点详情', '评查点详情', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 52, NULL, '/api/v3/evaluation-points/{id}', 'GET', NULL),
|
||||
('evaluation_point:create:write', 'evaluation_point', 'create', 'write', '创建评查点', '创建评查点', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 53, NULL, '/api/v3/evaluation-points', 'POST', NULL),
|
||||
('evaluation_point:update:write', 'evaluation_point', 'update', 'write', '更新评查点', '更新评查点', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 54, NULL, '/api/v3/evaluation-points/{id}', 'PUT', NULL),
|
||||
('evaluation_point:delete:delete', 'evaluation_point', 'delete', 'delete', '删除评查点', '删除评查点', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 55, NULL, '/api/v3/evaluation-points/{id}', 'DELETE', NULL),
|
||||
|
||||
('users:list:read', 'users', 'list', 'read', '查看用户列表', '用户列表', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 60, NULL, '/api/users/list', 'GET', NULL),
|
||||
('users:create:write', 'users', 'create', 'write', '创建用户', '创建用户', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 61, NULL, '/api/users', 'POST', NULL),
|
||||
@@ -115,6 +127,13 @@ seed(role_key, route_path, permission, status) AS (
|
||||
('super_admin', '/audit/runs', 'RW', 1),
|
||||
('super_admin', '/rules', 'RW', 1),
|
||||
('super_admin', '/rules/sets', 'RW', 1),
|
||||
('super_admin', '/chat-with-llm', 'RW', 1),
|
||||
('super_admin', '/contract-template', 'RW', 1),
|
||||
('super_admin', '/contract-template/search', 'RW', 1),
|
||||
('super_admin', '/contract-template/list', 'RW', 1),
|
||||
('super_admin', '/cross-checking', 'RW', 1),
|
||||
('super_admin', '/cross-checking/upload', 'RW', 1),
|
||||
('super_admin', '/cross-checking/result', 'RW', 1),
|
||||
('super_admin', '/system', 'RW', 1),
|
||||
('super_admin', '/system/users', 'RW', 1),
|
||||
('super_admin', '/system/roles', 'RW', 1),
|
||||
@@ -125,6 +144,13 @@ seed(role_key, route_path, permission, status) AS (
|
||||
('provincial_admin', '/audit/runs', 'RW', 1),
|
||||
('provincial_admin', '/rules', 'RW', 1),
|
||||
('provincial_admin', '/rules/sets', 'RW', 1),
|
||||
('provincial_admin', '/chat-with-llm', 'RW', 1),
|
||||
('provincial_admin', '/contract-template', 'RW', 1),
|
||||
('provincial_admin', '/contract-template/search', 'RW', 1),
|
||||
('provincial_admin', '/contract-template/list', 'RW', 1),
|
||||
('provincial_admin', '/cross-checking', 'RW', 1),
|
||||
('provincial_admin', '/cross-checking/upload', 'RW', 1),
|
||||
('provincial_admin', '/cross-checking/result', 'RW', 1),
|
||||
('provincial_admin', '/system', 'RW', 1),
|
||||
('provincial_admin', '/system/users', 'RW', 1),
|
||||
('provincial_admin', '/system/roles', 'RW', 1),
|
||||
@@ -135,6 +161,13 @@ seed(role_key, route_path, permission, status) AS (
|
||||
('admin', '/audit/runs', 'RW', 1),
|
||||
('admin', '/rules', 'RW', 1),
|
||||
('admin', '/rules/sets', 'RW', 1),
|
||||
('admin', '/chat-with-llm', 'RW', 1),
|
||||
('admin', '/contract-template', 'RW', 1),
|
||||
('admin', '/contract-template/search', 'RW', 1),
|
||||
('admin', '/contract-template/list', 'RW', 1),
|
||||
('admin', '/cross-checking', 'RW', 1),
|
||||
('admin', '/cross-checking/upload', 'RW', 1),
|
||||
('admin', '/cross-checking/result', 'RW', 1),
|
||||
('admin', '/system', 'RW', 1),
|
||||
('admin', '/system/users', 'RW', 1),
|
||||
|
||||
@@ -184,6 +217,11 @@ seed(role_key, permission_key, grant_type, data_scope) AS (
|
||||
('super_admin', 'rules:binding_create:write', 'GRANT', 'ALL'),
|
||||
('super_admin', 'rules:binding_update:write', 'GRANT', 'ALL'),
|
||||
('super_admin', 'rules:binding_delete:delete', 'GRANT', 'ALL'),
|
||||
('super_admin', 'evaluation_point:list:read', 'GRANT', 'ALL'),
|
||||
('super_admin', 'evaluation_point:detail:read', 'GRANT', 'ALL'),
|
||||
('super_admin', 'evaluation_point:create:write', 'GRANT', 'ALL'),
|
||||
('super_admin', 'evaluation_point:update:write', 'GRANT', 'ALL'),
|
||||
('super_admin', 'evaluation_point:delete:delete', 'GRANT', 'ALL'),
|
||||
('super_admin', 'users:list:read', 'GRANT', 'ALL'),
|
||||
('super_admin', 'users:create:write', 'GRANT', 'ALL'),
|
||||
('super_admin', 'users:update:write', 'GRANT', 'ALL'),
|
||||
@@ -215,6 +253,11 @@ seed(role_key, permission_key, grant_type, data_scope) AS (
|
||||
('provincial_admin', 'rules:binding_create:write', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'rules:binding_update:write', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'rules:binding_delete:delete', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'evaluation_point:list:read', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'evaluation_point:detail:read', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'evaluation_point:create:write', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'evaluation_point:update:write', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'evaluation_point:delete:delete', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'users:list:read', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'users:create:write', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'users:update:write', 'GRANT', 'ALL'),
|
||||
@@ -242,6 +285,11 @@ seed(role_key, permission_key, grant_type, data_scope) AS (
|
||||
('admin', 'rules:binding_list:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:binding_create:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'rules:binding_update:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'evaluation_point:list:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'evaluation_point:detail:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'evaluation_point:create:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'evaluation_point:update:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'evaluation_point:delete:delete', 'GRANT', 'DEPT'),
|
||||
('admin', 'users:list:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'users:update:write', 'GRANT', 'DEPT'),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user