feat: update audit platform workspace
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
-- 入口模块菜单模板、功能清单、文档入口归属迁移脚本
|
||||
-- 目标:
|
||||
-- 1. 入口模块用 menu_profile/features 控制左侧菜单,不再靠名称包含“合同/公文”判断。
|
||||
-- 2. 文档记录补 entry_module_id,后续列表、上传、统计、质量校验可以按入口模块过滤。
|
||||
-- 3. 二级分组增加父级内文档类型唯一约束,避免规则命中不稳定。
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE leaudit_entry_modules
|
||||
ADD COLUMN IF NOT EXISTS menu_profile VARCHAR(64) NOT NULL DEFAULT 'document_review',
|
||||
ADD COLUMN IF NOT EXISTS features JSONB NOT NULL DEFAULT '[]'::jsonb;
|
||||
|
||||
ALTER TABLE leaudit_documents
|
||||
ADD COLUMN IF NOT EXISTS entry_module_id BIGINT NULL REFERENCES leaudit_entry_modules(id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_leaudit_entry_modules_menu_profile
|
||||
ON leaudit_entry_modules(menu_profile)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_leaudit_documents_entry_module_id
|
||||
ON leaudit_documents(entry_module_id);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_leaudit_ep_groups_parent_doc_type_active
|
||||
ON leaudit_evaluation_point_groups(pid, document_type_id)
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) <> 0
|
||||
AND document_type_id IS NOT NULL;
|
||||
|
||||
UPDATE leaudit_entry_modules
|
||||
SET
|
||||
menu_profile = CASE
|
||||
WHEN path IN ('/govdoc/audits', '/govdoc', '/govdoc-audit') THEN 'govdoc'
|
||||
WHEN path IN ('/contract-template', '/contract-template/list', '/contract-template/search') THEN 'contract'
|
||||
ELSE COALESCE(NULLIF(menu_profile, ''), 'document_review')
|
||||
END,
|
||||
features = CASE
|
||||
WHEN path IN ('/govdoc/audits', '/govdoc', '/govdoc-audit')
|
||||
THEN '["home","govdoc_audits","govdoc_upload","rule_groups"]'::jsonb
|
||||
WHEN path IN ('/contract-template', '/contract-template/list', '/contract-template/search')
|
||||
THEN '["home","documents","upload","rules","contract_template_search","contract_template_list"]'::jsonb
|
||||
WHEN features IS NULL OR features = '[]'::jsonb
|
||||
THEN '["home","documents","upload","rules","rule_groups"]'::jsonb
|
||||
ELSE features
|
||||
END
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
UPDATE leaudit_documents d
|
||||
SET entry_module_id = COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id)
|
||||
FROM leaudit_document_types dt
|
||||
LEFT JOIN leaudit_evaluation_point_groups g ON g.id = d.group_id
|
||||
LEFT JOIN leaudit_evaluation_point_groups parent ON parent.id = g.pid
|
||||
WHERE d.type_id = dt.id
|
||||
AND d.entry_module_id IS NULL;
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- 验证入口模块菜单字段:
|
||||
-- SELECT id, name, path, menu_profile, features
|
||||
-- FROM leaudit_entry_modules
|
||||
-- WHERE deleted_at IS NULL
|
||||
-- ORDER BY sort_order, id;
|
||||
|
||||
-- 验证仍未回填入口模块归属的文档:
|
||||
-- SELECT COUNT(*) AS documents_without_entry_module
|
||||
-- FROM leaudit_documents
|
||||
-- WHERE deleted_at IS NULL
|
||||
-- AND entry_module_id IS NULL;
|
||||
@@ -0,0 +1,66 @@
|
||||
-- ============================================================================
|
||||
-- 入口模块管理权限收口:仅系统超级管理员维护入口模块
|
||||
-- 说明:
|
||||
-- 1. 不在代码里硬编码角色名,运行时仍然只认 RBAC 权限点。
|
||||
-- 2. 本脚本只调整默认 RBAC 数据,把 admin / provincial_admin 的入口模块管理能力移除。
|
||||
-- 3. 若后续确需给某个角色开放入口模块管理,请通过角色权限页面重新分配。
|
||||
-- 4. 可重复执行。
|
||||
-- ============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 保证系统超级管理员拥有入口模块路由。
|
||||
INSERT INTO role_route (role_id, route_id, permission, status, created_at, updated_at)
|
||||
SELECT r.id, sr.id, 'RW', 1, NOW(), NOW()
|
||||
FROM roles r
|
||||
JOIN sys_routes sr ON sr.route_path = '/entry-modules' AND sr.deleted_at IS NULL
|
||||
WHERE r.role_key = 'super_admin'
|
||||
ON CONFLICT (role_id, route_id) DO UPDATE SET
|
||||
permission = EXCLUDED.permission,
|
||||
status = EXCLUDED.status,
|
||||
updated_at = NOW();
|
||||
|
||||
-- 保证系统超级管理员拥有入口模块全部权限点。
|
||||
INSERT INTO role_permissions (role_id, permission_id, grant_type, data_scope, created_at, updated_at)
|
||||
SELECT r.id, p.id, 'GRANT', 'ALL', NOW(), NOW()
|
||||
FROM roles r
|
||||
JOIN permissions p ON p.permission_key LIKE 'entry_module:%'
|
||||
WHERE r.role_key = 'super_admin'
|
||||
ON CONFLICT (role_id, permission_id) DO UPDATE SET
|
||||
grant_type = EXCLUDED.grant_type,
|
||||
data_scope = EXCLUDED.data_scope,
|
||||
updated_at = NOW();
|
||||
|
||||
-- 移除地区管理员 / 旧省级管理员的入口模块权限点。
|
||||
DELETE FROM role_permissions rp
|
||||
USING roles r, permissions p
|
||||
WHERE rp.role_id = r.id
|
||||
AND rp.permission_id = p.id
|
||||
AND r.role_key IN ('admin', 'provincial_admin')
|
||||
AND p.permission_key LIKE 'entry_module:%';
|
||||
|
||||
-- 移除地区管理员 / 旧省级管理员的入口模块管理菜单。
|
||||
DELETE FROM role_route rr
|
||||
USING roles r, sys_routes sr
|
||||
WHERE rr.role_id = r.id
|
||||
AND rr.route_id = sr.id
|
||||
AND r.role_key IN ('admin', 'provincial_admin')
|
||||
AND sr.route_path = '/entry-modules';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- 验证结果:应只看到 super_admin 拥有入口模块权限。
|
||||
SELECT r.role_key, p.permission_key
|
||||
FROM roles r
|
||||
JOIN role_permissions rp ON rp.role_id = r.id
|
||||
JOIN permissions p ON p.id = rp.permission_id
|
||||
WHERE p.permission_key LIKE 'entry_module:%'
|
||||
ORDER BY r.role_key, p.permission_key;
|
||||
|
||||
-- 验证结果:admin / provincial_admin 不应再拥有 /entry-modules 路由。
|
||||
SELECT r.role_key, sr.route_path, rr.permission, rr.status
|
||||
FROM roles r
|
||||
JOIN role_route rr ON rr.role_id = r.id
|
||||
JOIN sys_routes sr ON sr.id = rr.route_id
|
||||
WHERE sr.route_path = '/entry-modules'
|
||||
ORDER BY r.role_key;
|
||||
@@ -0,0 +1,145 @@
|
||||
-- 修复入口模块归属历史数据
|
||||
-- 执行目标:
|
||||
-- 1. 回填可通过业务类型/规则分组明确推导的 leaudit_documents.entry_module_id。
|
||||
-- 2. 回填可通过子业务类型明确推导的一级/二级业务分组 entry_module_id。
|
||||
-- 3. 软删除无文档、无规则绑定的 Playwright/test 残留规则分组。
|
||||
-- 4. 补齐正式案卷入口的默认功能菜单。
|
||||
--
|
||||
-- 安全边界:
|
||||
-- 1. 不处理无法推导的旧公文示例。
|
||||
-- 2. 不把数据强行塞到 entry_module_id=1。
|
||||
-- 3. 不物理删除数据,只做软删除或确定性回填。
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1. 回填历史文档 entry_module_id:只处理能推导到“未删除入口模块”的文档。
|
||||
WITH resolved_documents AS (
|
||||
SELECT
|
||||
d.id,
|
||||
COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id) AS resolved_entry_module_id
|
||||
FROM leaudit_documents d
|
||||
LEFT JOIN leaudit_document_types dt
|
||||
ON dt.id = d.type_id
|
||||
LEFT JOIN leaudit_evaluation_point_groups g
|
||||
ON g.id = d.group_id
|
||||
LEFT JOIN leaudit_evaluation_point_groups parent
|
||||
ON parent.id = g.pid
|
||||
JOIN leaudit_entry_modules em
|
||||
ON em.id = COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id)
|
||||
AND em.deleted_at IS NULL
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND d.entry_module_id IS NULL
|
||||
AND COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id) IS NOT NULL
|
||||
)
|
||||
UPDATE leaudit_documents d
|
||||
SET entry_module_id = rd.resolved_entry_module_id,
|
||||
updated_at = NOW()
|
||||
FROM resolved_documents rd
|
||||
WHERE d.id = rd.id;
|
||||
|
||||
-- 2. 回填一级业务大类 entry_module_id:只处理所有子业务类型都指向同一个未删除入口模块的一级分组。
|
||||
WITH resolvable_roots AS (
|
||||
SELECT
|
||||
root.id AS root_id,
|
||||
MIN(child_dt.entry_module_id) AS resolved_entry_module_id
|
||||
FROM leaudit_evaluation_point_groups root
|
||||
JOIN leaudit_evaluation_point_groups child
|
||||
ON child.pid = root.id
|
||||
AND child.deleted_at IS NULL
|
||||
JOIN leaudit_document_types child_dt
|
||||
ON child_dt.id = child.document_type_id
|
||||
AND child_dt.deleted_at IS NULL
|
||||
JOIN leaudit_entry_modules em
|
||||
ON em.id = child_dt.entry_module_id
|
||||
AND em.deleted_at IS NULL
|
||||
WHERE root.deleted_at IS NULL
|
||||
AND COALESCE(root.pid, 0) = 0
|
||||
AND root.entry_module_id IS NULL
|
||||
GROUP BY root.id
|
||||
HAVING COUNT(DISTINCT child_dt.entry_module_id) = 1
|
||||
)
|
||||
UPDATE leaudit_evaluation_point_groups root
|
||||
SET entry_module_id = rr.resolved_entry_module_id,
|
||||
updated_at = NOW()
|
||||
FROM resolvable_roots rr
|
||||
WHERE root.id = rr.root_id;
|
||||
|
||||
-- 3. 二级业务类型继承父级入口模块:只处理父级已明确归属、子级为空的记录。
|
||||
UPDATE leaudit_evaluation_point_groups child
|
||||
SET entry_module_id = parent.entry_module_id,
|
||||
updated_at = NOW()
|
||||
FROM leaudit_evaluation_point_groups parent
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND parent.deleted_at IS NULL
|
||||
AND child.pid = parent.id
|
||||
AND COALESCE(parent.pid, 0) = 0
|
||||
AND parent.entry_module_id IS NOT NULL
|
||||
AND child.entry_module_id IS NULL;
|
||||
|
||||
-- 4. 软删除无引用的测试残留规则分组。
|
||||
WITH candidate_groups AS (
|
||||
SELECT g.id
|
||||
FROM leaudit_evaluation_point_groups g
|
||||
WHERE g.deleted_at IS NULL
|
||||
AND (
|
||||
g.code = 'testmzceshi'
|
||||
OR g.code LIKE 'pw.%'
|
||||
)
|
||||
),
|
||||
safe_groups AS (
|
||||
SELECT cg.id
|
||||
FROM candidate_groups cg
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_documents d
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND d.group_id = cg.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_rule_group_bindings b
|
||||
WHERE b.deleted_at IS NULL
|
||||
AND b.group_id = cg.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
JOIN leaudit_documents d
|
||||
ON d.group_id = child.id
|
||||
AND d.deleted_at IS NULL
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND child.pid = cg.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_evaluation_point_groups child
|
||||
JOIN leaudit_rule_group_bindings b
|
||||
ON b.group_id = child.id
|
||||
AND b.deleted_at IS NULL
|
||||
WHERE child.deleted_at IS NULL
|
||||
AND child.pid = cg.id
|
||||
)
|
||||
)
|
||||
UPDATE leaudit_evaluation_point_groups g
|
||||
SET deleted_at = NOW(),
|
||||
updated_at = NOW()
|
||||
FROM safe_groups sg
|
||||
WHERE g.id = sg.id;
|
||||
|
||||
-- 5. 补齐案卷智能评查的通用文档评查功能菜单。
|
||||
UPDATE leaudit_entry_modules
|
||||
SET features = '["home", "documents", "upload", "rules", "rule_groups"]'::jsonb,
|
||||
updated_at = NOW()
|
||||
WHERE deleted_at IS NULL
|
||||
AND id = 2
|
||||
AND name = '案卷智能评查'
|
||||
AND (
|
||||
features IS NULL
|
||||
OR jsonb_typeof(features) <> 'array'
|
||||
OR jsonb_array_length(features) = 0
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- 执行后建议立即运行:
|
||||
-- psql "$DATABASE_URL" -f scripts/创建sql/verify_entry_module_menu_profile.sql
|
||||
@@ -0,0 +1,15 @@
|
||||
-- 回填旧公文示例文档入口归属
|
||||
-- 这 3 条是旧 govdoc 链路数据,只补 entry_module_id,不伪造 type_id/group_id。
|
||||
|
||||
BEGIN;
|
||||
|
||||
UPDATE leaudit_documents
|
||||
SET entry_module_id = 3,
|
||||
updated_at = NOW()
|
||||
WHERE id IN (46, 47, 48)
|
||||
AND deleted_at IS NULL
|
||||
AND entry_module_id IS NULL
|
||||
AND engine_type = 'govdoc'
|
||||
AND review_scope = 'govdoc';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,36 @@
|
||||
-- 企查查企业主体信息缓存表。
|
||||
|
||||
CREATE TABLE IF NOT EXISTS qcc_company_info (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
search_key VARCHAR(200) NOT NULL,
|
||||
credit_code VARCHAR(64),
|
||||
company_name VARCHAR(255),
|
||||
enterprise JSONB,
|
||||
dishonesty JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_qcc_company_search_key
|
||||
ON qcc_company_info (search_key)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_qcc_company_credit_code
|
||||
ON qcc_company_info (credit_code)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_qcc_company_name
|
||||
ON qcc_company_info (company_name)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_qcc_company_created_at
|
||||
ON qcc_company_info (created_at)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
COMMENT ON TABLE qcc_company_info IS '企查查企业主体信息缓存表';
|
||||
COMMENT ON COLUMN qcc_company_info.search_key IS '原始查询关键词';
|
||||
COMMENT ON COLUMN qcc_company_info.credit_code IS '统一社会信用代码';
|
||||
COMMENT ON COLUMN qcc_company_info.company_name IS '企业名称';
|
||||
COMMENT ON COLUMN qcc_company_info.enterprise IS '企查查工商信息原始响应 Result';
|
||||
COMMENT ON COLUMN qcc_company_info.dishonesty IS '企查查失信核查原始响应 Result';
|
||||
@@ -6,7 +6,7 @@
|
||||
-- 3. 兼容历史库中 entry_modules 时间字段命名差异
|
||||
--
|
||||
-- 说明:
|
||||
-- - 当前模块入口统一收口到 /govdoc/list,与模块路由 seed 保持一致。
|
||||
-- - 当前模块入口统一收口到 /govdoc/audits,与前端真实列表路由保持一致。
|
||||
-- - 若后续前端改成其他入口页,请同步更新本脚本中的 v_target_path。
|
||||
-- - 页面访问权限与左侧菜单路由仍依赖 sys_routes / role_route,
|
||||
-- 这部分建议由配套脚本 seed_govdoc_routes.sql 单独维护。
|
||||
@@ -18,7 +18,7 @@ DO $$
|
||||
DECLARE
|
||||
v_name text := '内部公文';
|
||||
v_description text := '内部公文处理与格式审查入口';
|
||||
v_target_path text := '/govdoc/list';
|
||||
v_target_path text := '/govdoc/audits';
|
||||
v_icon_path text := 'documents/mz/static/img/entry_module_3.png';
|
||||
v_sort_order integer := 30;
|
||||
v_areas jsonb := '[
|
||||
|
||||
@@ -103,16 +103,16 @@ VALUES
|
||||
NULL
|
||||
),
|
||||
(
|
||||
'/govdoc/list',
|
||||
'govdoc.list',
|
||||
'govdoc.list',
|
||||
'/govdoc/audits',
|
||||
'govdoc.audits',
|
||||
'govdoc.audits',
|
||||
(SELECT id FROM root_route),
|
||||
'公文列表',
|
||||
'ri-file-list-3-line',
|
||||
2,
|
||||
FALSE,
|
||||
TRUE,
|
||||
'{"group":"govdoc","module":"govdoc","page":"list"}'::jsonb,
|
||||
'{"group":"govdoc","module":"govdoc","page":"audits"}'::jsonb,
|
||||
0,
|
||||
NOW(),
|
||||
NOW(),
|
||||
@@ -187,7 +187,7 @@ SET
|
||||
parent_id = root.id,
|
||||
route_title = CASE
|
||||
WHEN child.route_path = '/govdoc/upload' THEN '上传公文'
|
||||
WHEN child.route_path = '/govdoc/list' THEN '公文列表'
|
||||
WHEN child.route_path = '/govdoc/audits' THEN '公文列表'
|
||||
WHEN child.route_path = '/govdoc/detail' THEN '公文详情'
|
||||
WHEN child.route_path = '/govdoc/rules' THEN '规则配置'
|
||||
WHEN child.route_path = '/govdoc/settings' THEN '模块配置'
|
||||
@@ -204,7 +204,7 @@ WHERE child.deleted_at IS NULL
|
||||
AND root.route_path = '/govdoc'
|
||||
AND child.route_path IN (
|
||||
'/govdoc/upload',
|
||||
'/govdoc/list',
|
||||
'/govdoc/audits',
|
||||
'/govdoc/detail',
|
||||
'/govdoc/rules',
|
||||
'/govdoc/settings'
|
||||
@@ -229,7 +229,7 @@ route_map AS (
|
||||
AND route_path IN (
|
||||
'/govdoc',
|
||||
'/govdoc/upload',
|
||||
'/govdoc/list',
|
||||
'/govdoc/audits',
|
||||
'/govdoc/detail',
|
||||
'/govdoc/rules',
|
||||
'/govdoc/settings'
|
||||
@@ -239,27 +239,27 @@ seed(role_key, route_path, permission, status) AS (
|
||||
VALUES
|
||||
('super_admin', '/govdoc', 'RW', 1),
|
||||
('super_admin', '/govdoc/upload', 'RW', 1),
|
||||
('super_admin', '/govdoc/list', 'RW', 1),
|
||||
('super_admin', '/govdoc/audits', 'RW', 1),
|
||||
('super_admin', '/govdoc/detail', 'RW', 1),
|
||||
('super_admin', '/govdoc/rules', 'RW', 1),
|
||||
('super_admin', '/govdoc/settings', 'RW', 1),
|
||||
|
||||
('provincial_admin', '/govdoc', 'RW', 1),
|
||||
('provincial_admin', '/govdoc/upload', 'RW', 1),
|
||||
('provincial_admin', '/govdoc/list', 'RW', 1),
|
||||
('provincial_admin', '/govdoc/audits', 'RW', 1),
|
||||
('provincial_admin', '/govdoc/detail', 'RW', 1),
|
||||
('provincial_admin', '/govdoc/rules', 'RW', 1),
|
||||
('provincial_admin', '/govdoc/settings', 'RW', 1),
|
||||
|
||||
('admin', '/govdoc', 'RW', 1),
|
||||
('admin', '/govdoc/upload', 'RW', 1),
|
||||
('admin', '/govdoc/list', 'RW', 1),
|
||||
('admin', '/govdoc/audits', 'RW', 1),
|
||||
('admin', '/govdoc/detail', 'RW', 1),
|
||||
('admin', '/govdoc/rules', 'R', 1),
|
||||
|
||||
('common', '/govdoc', 'R', 1),
|
||||
('common', '/govdoc/upload', 'R', 1),
|
||||
('common', '/govdoc/list', 'R', 1),
|
||||
('common', '/govdoc/audits', 'R', 1),
|
||||
('common', '/govdoc/detail', 'R', 1),
|
||||
('common', '/govdoc/rules', 'R', 1)
|
||||
)
|
||||
|
||||
@@ -91,11 +91,6 @@ VALUES
|
||||
('rules:binding_create:write', 'rules', 'binding_create', 'write', '创建规则绑定', '创建规则绑定', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 49, 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, 50, 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, 51, 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, 52, 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, 53, 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, 54, 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, 55, 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, 56, NULL, '/api/v3/evaluation-points/{id}', 'DELETE', NULL),
|
||||
('cross_review:task:create', 'cross_review', 'task', 'create', '创建交叉评查任务', '创建交叉评查任务', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 57, NULL, '/api/v3/cross-review/tasks', 'POST', NULL),
|
||||
('cross_review:task:read', 'cross_review', 'task', 'read', '查看交叉评查任务', '查看交叉评查任务', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 58, NULL, '/api/v3/cross-review/tasks/query', 'POST', NULL),
|
||||
('cross_review:progress:view', 'cross_review', 'progress', 'view', '查看交叉评查任务进度', '查看交叉评查任务进度', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 59, NULL, '/api/v3/cross-review/tasks/{task_id}/progress', 'GET', NULL),
|
||||
@@ -124,7 +119,9 @@ VALUES
|
||||
('rag:conversation:delete', 'rag', 'conversation', 'delete', '删除 RAG 会话', '删除 RAG 会话', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 89, NULL, '/api/v3/rag/chat/conversations/{ConversationId}', 'DELETE', NULL),
|
||||
('rag:message:feedback', 'rag', 'message', 'feedback', '反馈 RAG 消息', '反馈 RAG 消息', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 90, NULL, '/api/v3/rag/chat/messages/{MessageId}/feedback', 'POST', NULL),
|
||||
('rag:dataset:read', 'rag', 'dataset', 'read', '查看 RAG 知识库', '查看 RAG 知识库', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 91, NULL, '/api/v3/rag/datasets/my', 'GET', NULL),
|
||||
('document:document:update', 'document', 'document', 'update', '修改文档基本信息', '修改文档', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 92, NULL, '/api/documents/edit', 'POST', NULL)
|
||||
('document:document:update', 'document', 'document', 'update', '修改文档基本信息', '修改文档', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 92, NULL, '/api/documents/edit', 'POST', NULL),
|
||||
('qichacha:company:query', 'qichacha', 'company', 'query', '查询企业主体信息', '查询企业主体信息', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 93, NULL, '/api/v2/qichacha/company', 'POST', NULL),
|
||||
('qichacha:status:read', 'qichacha', 'status', 'read', '查看企业主体缓存状态', '查看企业主体缓存状态', 'API', TRUE, NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL, NULL, 94, NULL, '/api/v2/qichacha/status', 'GET', NULL)
|
||||
ON CONFLICT (permission_key) DO UPDATE SET
|
||||
module = EXCLUDED.module,
|
||||
resource = EXCLUDED.resource,
|
||||
@@ -245,11 +242,6 @@ 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', 'cross_review:task:create', 'GRANT', 'ALL'),
|
||||
('super_admin', 'cross_review:task:read', 'GRANT', 'ALL'),
|
||||
('super_admin', 'cross_review:progress:view', 'GRANT', 'ALL'),
|
||||
@@ -276,6 +268,8 @@ seed(role_key, permission_key, grant_type, data_scope) AS (
|
||||
('super_admin', 'rbac:permissions:read', 'GRANT', 'ALL'),
|
||||
('super_admin', 'rbac:role_permissions:write', 'GRANT', 'ALL'),
|
||||
('super_admin', 'rbac:role_routes:write', 'GRANT', 'ALL'),
|
||||
('super_admin', 'qichacha:company:query', 'GRANT', 'ALL'),
|
||||
('super_admin', 'qichacha:status:read', 'GRANT', 'ALL'),
|
||||
|
||||
('provincial_admin', 'auth:me:read', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'documents:upload:write', 'GRANT', 'ALL'),
|
||||
@@ -298,11 +292,6 @@ 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', 'cross_review:task:create', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'cross_review:task:read', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'cross_review:progress:view', 'GRANT', 'ALL'),
|
||||
@@ -329,6 +318,8 @@ seed(role_key, permission_key, grant_type, data_scope) AS (
|
||||
('provincial_admin', 'rbac:permissions:read', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'rbac:role_permissions:write', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'rbac:role_routes:write', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'qichacha:company:query', 'GRANT', 'ALL'),
|
||||
('provincial_admin', 'qichacha:status:read', 'GRANT', 'ALL'),
|
||||
|
||||
('admin', 'auth:me:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'documents:upload:write', 'GRANT', 'DEPT'),
|
||||
@@ -360,11 +351,6 @@ seed(role_key, permission_key, grant_type, data_scope) AS (
|
||||
('admin', 'cross_review:proposal:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'cross_review:proposal:delete', 'GRANT', 'DEPT'),
|
||||
('admin', 'cross_review:proposal:vote', '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', 'rag:app:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'rag:chat:use', 'GRANT', 'DEPT'),
|
||||
('admin', 'rag:conversation:read', 'GRANT', 'DEPT'),
|
||||
@@ -374,6 +360,7 @@ seed(role_key, permission_key, grant_type, data_scope) AS (
|
||||
('admin', 'rag:dataset:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'users:list:read', 'GRANT', 'DEPT'),
|
||||
('admin', 'users:update:write', 'GRANT', 'DEPT'),
|
||||
('admin', 'qichacha:company:query', 'GRANT', 'DEPT'),
|
||||
|
||||
('common', 'auth:me:read', 'GRANT', 'SELF'),
|
||||
('common', 'documents:upload:write', 'GRANT', 'SELF'),
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
-- 入口模块菜单模板、多租户可见性、文档归属巡检脚本
|
||||
-- 用途:
|
||||
-- 1. 检查 entry_module_menu_profile_migration.sql 是否补齐字段、索引、默认值。
|
||||
-- 2. 检查入口模块 features/menu_profile 是否存在非法值或空配置。
|
||||
-- 3. 检查文档 entry_module_id 回填情况和二级分组重复风险。
|
||||
-- 4. 本脚本只查询,不修改数据。
|
||||
--
|
||||
-- 推荐执行方式:
|
||||
-- psql "$DATABASE_URL" -f scripts/创建sql/verify_entry_module_menu_profile.sql
|
||||
|
||||
-- =========================================================
|
||||
-- 1. 必要字段检查
|
||||
-- =========================================================
|
||||
SELECT
|
||||
table_name,
|
||||
column_name,
|
||||
data_type,
|
||||
is_nullable,
|
||||
column_default
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = current_schema()
|
||||
AND (
|
||||
(table_name = 'leaudit_entry_modules' AND column_name IN ('menu_profile', 'features'))
|
||||
OR (table_name = 'leaudit_documents' AND column_name = 'entry_module_id')
|
||||
)
|
||||
ORDER BY table_name, column_name;
|
||||
|
||||
-- =========================================================
|
||||
-- 2. 必要索引检查
|
||||
-- =========================================================
|
||||
SELECT
|
||||
schemaname,
|
||||
tablename,
|
||||
indexname,
|
||||
indexdef
|
||||
FROM pg_indexes
|
||||
WHERE schemaname = current_schema()
|
||||
AND indexname IN (
|
||||
'idx_leaudit_entry_modules_menu_profile',
|
||||
'idx_leaudit_documents_entry_module_id',
|
||||
'uq_leaudit_ep_groups_parent_doc_type_active'
|
||||
)
|
||||
ORDER BY indexname;
|
||||
|
||||
-- =========================================================
|
||||
-- 3. 入口模块菜单配置总览
|
||||
-- =========================================================
|
||||
SELECT
|
||||
em.id,
|
||||
em.name,
|
||||
em.path,
|
||||
em.menu_profile,
|
||||
em.features,
|
||||
em.is_enabled,
|
||||
COALESCE(
|
||||
STRING_AGG(emt.tenant_code, ', ' ORDER BY emt.tenant_code)
|
||||
FILTER (WHERE emt.is_enabled IS TRUE),
|
||||
''
|
||||
) AS enabled_tenants
|
||||
FROM leaudit_entry_modules em
|
||||
LEFT JOIN leaudit_entry_module_tenants emt
|
||||
ON emt.entry_module_id = em.id
|
||||
WHERE em.deleted_at IS NULL
|
||||
GROUP BY em.id, em.name, em.path, em.menu_profile, em.features, em.is_enabled
|
||||
ORDER BY em.sort_order, em.id;
|
||||
|
||||
-- =========================================================
|
||||
-- 4. 非法 menu_profile 检查:结果应为空
|
||||
-- =========================================================
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
path,
|
||||
menu_profile
|
||||
FROM leaudit_entry_modules
|
||||
WHERE deleted_at IS NULL
|
||||
AND menu_profile NOT IN ('document_review', 'contract', 'govdoc', 'cross_checking', 'custom')
|
||||
ORDER BY id;
|
||||
|
||||
-- =========================================================
|
||||
-- 5. 空 features 检查:结果应为空或只包含刻意关闭菜单的入口
|
||||
-- =========================================================
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
path,
|
||||
menu_profile,
|
||||
features
|
||||
FROM leaudit_entry_modules
|
||||
WHERE deleted_at IS NULL
|
||||
AND (
|
||||
features IS NULL
|
||||
OR jsonb_typeof(features) <> 'array'
|
||||
OR jsonb_array_length(features) = 0
|
||||
)
|
||||
ORDER BY id;
|
||||
|
||||
-- =========================================================
|
||||
-- 6. 非法 feature 编码检查:结果应为空
|
||||
-- =========================================================
|
||||
SELECT
|
||||
em.id,
|
||||
em.name,
|
||||
em.menu_profile,
|
||||
invalid_feature.feature
|
||||
FROM leaudit_entry_modules em
|
||||
CROSS JOIN LATERAL jsonb_array_elements_text(em.features) AS invalid_feature(feature)
|
||||
WHERE em.deleted_at IS NULL
|
||||
AND invalid_feature.feature NOT IN (
|
||||
'home',
|
||||
'documents',
|
||||
'upload',
|
||||
'rules',
|
||||
'rule_groups',
|
||||
'contract_template_search',
|
||||
'contract_template_list',
|
||||
'govdoc_audits',
|
||||
'govdoc_upload',
|
||||
'cross_checking',
|
||||
'cross_checking_upload',
|
||||
'cross_checking_list',
|
||||
'usage_stats'
|
||||
)
|
||||
ORDER BY em.id, invalid_feature.feature;
|
||||
|
||||
-- =========================================================
|
||||
-- 7. 文档归属缺失检查
|
||||
-- =========================================================
|
||||
SELECT
|
||||
COUNT(*) AS documents_without_entry_module
|
||||
FROM leaudit_documents
|
||||
WHERE deleted_at IS NULL
|
||||
AND entry_module_id IS NULL;
|
||||
|
||||
SELECT
|
||||
d.id,
|
||||
d.normalized_name AS document_name,
|
||||
d.type_id,
|
||||
dt.name AS document_type_name,
|
||||
d.group_id,
|
||||
g.name AS group_name,
|
||||
d.tenant_code,
|
||||
d.created_at
|
||||
FROM leaudit_documents d
|
||||
LEFT JOIN leaudit_document_types dt
|
||||
ON dt.id = d.type_id
|
||||
LEFT JOIN leaudit_evaluation_point_groups g
|
||||
ON g.id = d.group_id
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND d.entry_module_id IS NULL
|
||||
ORDER BY d.created_at DESC NULLS LAST, d.id DESC
|
||||
LIMIT 50;
|
||||
|
||||
-- =========================================================
|
||||
-- 8. 文档 entry_module_id 与分组/文档类型推导不一致检查
|
||||
-- =========================================================
|
||||
SELECT
|
||||
d.id,
|
||||
d.normalized_name AS document_name,
|
||||
d.entry_module_id AS document_entry_module_id,
|
||||
COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id) AS resolved_entry_module_id,
|
||||
d.type_id,
|
||||
d.group_id,
|
||||
d.tenant_code
|
||||
FROM leaudit_documents d
|
||||
LEFT JOIN leaudit_document_types dt
|
||||
ON dt.id = d.type_id
|
||||
LEFT JOIN leaudit_evaluation_point_groups g
|
||||
ON g.id = d.group_id
|
||||
LEFT JOIN leaudit_evaluation_point_groups parent
|
||||
ON parent.id = g.pid
|
||||
WHERE d.deleted_at IS NULL
|
||||
AND d.entry_module_id IS NOT NULL
|
||||
AND COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id) IS NOT NULL
|
||||
AND d.entry_module_id <> COALESCE(g.entry_module_id, parent.entry_module_id, dt.entry_module_id)
|
||||
ORDER BY d.id DESC
|
||||
LIMIT 100;
|
||||
|
||||
-- =========================================================
|
||||
-- 9. 重复二级分组检查:结果应为空
|
||||
-- =========================================================
|
||||
SELECT
|
||||
pid,
|
||||
document_type_id,
|
||||
COUNT(*) AS duplicated_count,
|
||||
STRING_AGG(id::text || ':' || name, ' / ' ORDER BY id) AS groups
|
||||
FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) <> 0
|
||||
AND document_type_id IS NOT NULL
|
||||
GROUP BY pid, document_type_id
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY duplicated_count DESC, pid, document_type_id;
|
||||
|
||||
-- =========================================================
|
||||
-- 10. 一级分组缺入口模块检查:兼容期允许存在,但新链路应逐步清零
|
||||
-- =========================================================
|
||||
SELECT
|
||||
id,
|
||||
code,
|
||||
name,
|
||||
document_type_id,
|
||||
sort_order,
|
||||
is_enabled
|
||||
FROM leaudit_evaluation_point_groups
|
||||
WHERE deleted_at IS NULL
|
||||
AND COALESCE(pid, 0) = 0
|
||||
AND entry_module_id IS NULL
|
||||
ORDER BY sort_order, id;
|
||||
Reference in New Issue
Block a user