fix(数据权限): 修复 GUID 种子/SqlQuery 映射并补充诊断修复 SQL
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c442833d9c
commit
ad367998d2
62
sql/diagnose_data_perm_bad_guids.sql
Normal file
62
sql/diagnose_data_perm_bad_guids.sql
Normal file
@ -0,0 +1,62 @@
|
||||
-- 数据权限表:诊断 CHAR(36) 非法 GUID
|
||||
-- 症状:GET /rbac/data-perm/template/list → Could not parse CHAR(36) value as Guid: 1
|
||||
-- 或其它 data-perm 接口同类报错
|
||||
--
|
||||
-- ⚠️ 在 API 实际连接的 RBAC 库执行(与 user/role/menu 同库)
|
||||
|
||||
SET @GUID_RE = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';
|
||||
|
||||
SELECT 'data_perm_template bad Id' AS section, t.`Id`, t.`Name`, t.`Code`, t.`CreateUserId`
|
||||
FROM `data_perm_template` t
|
||||
WHERE t.`Id` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'data_perm_template_item bad Id/TemplateId' AS section, i.`Id`, i.`TemplateId`, i.`DimensionType`
|
||||
FROM `data_perm_template_item` i
|
||||
WHERE i.`Id` NOT REGEXP @GUID_RE
|
||||
OR i.`TemplateId` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'data_resource bad Id' AS section, r.`Id`, r.`Code`, r.`Name`
|
||||
FROM `data_resource` r
|
||||
WHERE r.`Id` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'data_perm_field_mask bad Id' AS section, f.`Id`, f.`DataResourceCode`, f.`FieldName`
|
||||
FROM `data_perm_field_mask` f
|
||||
WHERE f.`Id` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'user_org_perm bad Id/UserId/OrganizationId' AS section, p.`Id`, p.`UserId`, p.`OrganizationId`
|
||||
FROM `user_org_perm` p
|
||||
WHERE p.`Id` NOT REGEXP @GUID_RE
|
||||
OR p.`UserId` NOT REGEXP @GUID_RE
|
||||
OR p.`OrganizationId` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'role_org_perm bad Id/RoleId/OrganizationId' AS section, p.`Id`, p.`RoleId`, p.`OrganizationId`
|
||||
FROM `role_org_perm` p
|
||||
WHERE p.`Id` NOT REGEXP @GUID_RE
|
||||
OR p.`RoleId` NOT REGEXP @GUID_RE
|
||||
OR p.`OrganizationId` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'user_data_scope bad Id/UserId' AS section, p.`Id`, p.`UserId`, p.`DataResourceCode`
|
||||
FROM `user_data_scope` p
|
||||
WHERE p.`Id` NOT REGEXP @GUID_RE
|
||||
OR p.`UserId` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'role_data_scope bad Id/RoleId' AS section, p.`Id`, p.`RoleId`, p.`DataResourceCode`
|
||||
FROM `role_data_scope` p
|
||||
WHERE p.`Id` NOT REGEXP @GUID_RE
|
||||
OR p.`RoleId` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'data_perm_change_log bad TargetId' AS section, l.`Id`, l.`TargetType`, l.`TargetId`, l.`Action`
|
||||
FROM `data_perm_change_log` l
|
||||
WHERE l.`TargetId` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'data_perm_access_log bad UserId' AS section, l.`Id`, l.`UserId`, l.`DataResourceCode`, l.`ApiPath`
|
||||
FROM `data_perm_access_log` l
|
||||
WHERE l.`UserId` NOT REGEXP @GUID_RE;
|
||||
|
||||
-- 常见脏值快捷统计
|
||||
SELECT 'template Id=1' AS hint, COUNT(*) AS cnt FROM `data_perm_template` WHERE TRIM(`Id`) IN ('0', '1', '2');
|
||||
SELECT 'template_item Id=1' AS hint, COUNT(*) AS cnt FROM `data_perm_template_item` WHERE TRIM(`Id`) IN ('0', '1', '2');
|
||||
SELECT 'template dp prefix' AS hint, COUNT(*) AS cnt FROM `data_perm_template` WHERE `Id` LIKE 'dp%';
|
||||
SELECT 'template dr prefix' AS hint, COUNT(*) AS cnt FROM `data_perm_template` WHERE `Id` LIKE 'dr%';
|
||||
SELECT 'data_resource dr000001 prefix' AS hint, COUNT(*) AS cnt FROM `data_resource` WHERE `Id` LIKE 'dr000001-%';
|
||||
SELECT 'field_mask fm000001 prefix' AS hint, COUNT(*) AS cnt FROM `data_perm_field_mask` WHERE `Id` LIKE 'fm000001-%';
|
||||
@ -6,5 +6,5 @@ SET
|
||||
`Route` = '/system/dataPerm/audit',
|
||||
`Component` = 'views/system/dataPerm/audit/index',
|
||||
`UpdateTime` = NOW()
|
||||
WHERE `Id` = 'dp100001-0000-4000-8000-000000000004'
|
||||
WHERE `Id` = 'da100001-0000-4000-8000-000000000004'
|
||||
OR (`Route` = '/system/dataPerm/accessLog' AND `PermissionCode` = 'Rbac.DataPerm.Audit');
|
||||
|
||||
25
sql/fix_data_perm_menu_invalid_guids.sql
Normal file
25
sql/fix_data_perm_menu_invalid_guids.sql
Normal file
@ -0,0 +1,25 @@
|
||||
-- 修复 menu 表非法 GUID(Id/PId 含非十六进制字符,如 dp100001 中的 p)
|
||||
-- 症状:登录 / get-menu-tree → Could not parse CHAR(36) value as Guid: dp100001-...
|
||||
-- GUID 仅允许 0-9、a-f
|
||||
--
|
||||
-- ⚠️ 在 RBAC 库执行
|
||||
|
||||
SELECT 'before fix' AS stage, `Id`, `PId`, `Name`, `Route`, `PermissionCode`
|
||||
FROM `menu`
|
||||
WHERE `Id` LIKE 'dp100001-%'
|
||||
OR `PId` LIKE 'dp100001-%';
|
||||
|
||||
-- 先改子节点 PId,再改 Id
|
||||
UPDATE `menu`
|
||||
SET `PId` = REPLACE(`PId`, 'dp100001-', 'da100001-')
|
||||
WHERE `PId` LIKE 'dp100001-%';
|
||||
|
||||
UPDATE `menu`
|
||||
SET `Id` = REPLACE(`Id`, 'dp100001-', 'da100001-')
|
||||
WHERE `Id` LIKE 'dp100001-%';
|
||||
|
||||
SELECT 'after fix (should be empty)' AS stage, `Id`, `PId`, `Name`, `Route`
|
||||
FROM `menu`
|
||||
WHERE `Id` LIKE 'dp100001-%'
|
||||
OR `PId` LIKE 'dp100001-%'
|
||||
OR (`Id` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');
|
||||
32
sql/fix_data_perm_role_permission_bad_guids.sql
Normal file
32
sql/fix_data_perm_role_permission_bad_guids.sql
Normal file
@ -0,0 +1,32 @@
|
||||
-- 修复 role_permission.CreateUserId = '0' 导致登录失败
|
||||
-- 症状:POST /rbac/auth/login → Could not parse CHAR(36) value as Guid: 0
|
||||
-- 原因:seed_data_perm_rbac_menu.sql 曾写入 CreateUserId = 0
|
||||
--
|
||||
-- ⚠️ 在 RBAC 库(fake_simple_admin 或 API 连接的 RBAC 库)执行
|
||||
|
||||
SET @ADMIN_USER_ID = (
|
||||
SELECT `Id` FROM `user`
|
||||
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
|
||||
LIMIT 1
|
||||
);
|
||||
SET @ADMIN_USER_ID = IFNULL(
|
||||
@ADMIN_USER_ID,
|
||||
(SELECT `Id` FROM `user` WHERE `IsDeleted` = 0 OR `IsDeleted` IS NULL ORDER BY `CreateTime` LIMIT 1)
|
||||
);
|
||||
|
||||
SELECT @ADMIN_USER_ID AS admin_user_id_used;
|
||||
|
||||
SELECT 'before fix' AS stage, rp.`Id`, rp.`RoleId`, rp.`PermissionCode`, rp.`CreateUserId`
|
||||
FROM `role_permission` rp
|
||||
WHERE CAST(rp.`CreateUserId` AS CHAR) = '0'
|
||||
OR (rp.`CreateUserId` IS NOT NULL AND rp.`CreateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');
|
||||
|
||||
UPDATE `role_permission`
|
||||
SET `CreateUserId` = @ADMIN_USER_ID
|
||||
WHERE CAST(`CreateUserId` AS CHAR) = '0'
|
||||
OR (`CreateUserId` IS NOT NULL AND `CreateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');
|
||||
|
||||
SELECT 'after fix (should be empty)' AS stage, rp.`Id`, rp.`RoleId`, rp.`PermissionCode`, rp.`CreateUserId`
|
||||
FROM `role_permission` rp
|
||||
WHERE CAST(rp.`CreateUserId` AS CHAR) = '0'
|
||||
OR (rp.`CreateUserId` IS NOT NULL AND rp.`CreateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');
|
||||
101
sql/fix_data_perm_template_bad_guids.sql
Normal file
101
sql/fix_data_perm_template_bad_guids.sql
Normal file
@ -0,0 +1,101 @@
|
||||
-- 修复 data_perm_* 表非法 GUID(如 Id='1'、dp/dr 前缀含非 hex 字符)
|
||||
-- 症状:GET /rbac/data-perm/template/list → Could not parse CHAR(36) value as Guid: 1
|
||||
--
|
||||
-- ⚠️ 在 RBAC 库执行;执行前先跑 diagnose_data_perm_bad_guids.sql 确认脏数据
|
||||
-- 若库中从未跑过 install_data_permission.sql,请先执行该脚本再跑本修复
|
||||
|
||||
SET @GUID_RE = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';
|
||||
|
||||
SELECT 'before fix — bad template rows' AS stage, t.`Id`, t.`Name`, t.`Code`
|
||||
FROM `data_perm_template` t
|
||||
WHERE t.`Id` NOT REGEXP @GUID_RE;
|
||||
|
||||
-- 1) 旧种子前缀 dp/dr → da(与 install_data_permission.sql 一致)
|
||||
UPDATE `data_perm_template_item`
|
||||
SET `TemplateId` = REPLACE(`TemplateId`, 'dp000001-', 'da000001-')
|
||||
WHERE `TemplateId` LIKE 'dp000001-%';
|
||||
|
||||
UPDATE `data_perm_template_item`
|
||||
SET `Id` = REPLACE(`Id`, 'dp200001-', 'da200001-')
|
||||
WHERE `Id` LIKE 'dp200001-%';
|
||||
|
||||
UPDATE `data_perm_template_item`
|
||||
SET `Id` = REPLACE(`Id`, 'dr200001-', 'da200001-')
|
||||
WHERE `Id` LIKE 'dr200001-%';
|
||||
|
||||
UPDATE `data_perm_template`
|
||||
SET `Id` = REPLACE(`Id`, 'dp000001-', 'da000001-')
|
||||
WHERE `Id` LIKE 'dp000001-%';
|
||||
|
||||
UPDATE `data_perm_template`
|
||||
SET `Id` = REPLACE(`Id`, 'dr000001-', 'da000001-')
|
||||
WHERE `Id` LIKE 'dr000001-%';
|
||||
|
||||
UPDATE `data_resource`
|
||||
SET `Id` = REPLACE(`Id`, 'dr000001-', 'da300001-')
|
||||
WHERE `Id` LIKE 'dr000001-%';
|
||||
|
||||
UPDATE `data_resource`
|
||||
SET `Id` = REPLACE(`Id`, 'dr300001-', 'da300001-')
|
||||
WHERE `Id` LIKE 'dr300001-%';
|
||||
|
||||
UPDATE `data_resource`
|
||||
SET `Id` = REPLACE(`Id`, 'dp300001-', 'da300001-')
|
||||
WHERE `Id` LIKE 'dp300001-%';
|
||||
|
||||
UPDATE `data_perm_field_mask`
|
||||
SET `Id` = REPLACE(`Id`, 'fm000001-', 'fa000001-')
|
||||
WHERE `Id` LIKE 'fm000001-%';
|
||||
|
||||
-- 2) 删除无法自动映射的脏模板
|
||||
DELETE FROM `data_perm_template_item`
|
||||
WHERE `TemplateId` IN (
|
||||
SELECT `Id` FROM (
|
||||
SELECT `Id` FROM `data_perm_template` WHERE TRIM(`Id`) NOT REGEXP @GUID_RE
|
||||
) AS bad_tpl
|
||||
);
|
||||
|
||||
DELETE FROM `data_perm_template`
|
||||
WHERE TRIM(`Id`) NOT REGEXP @GUID_RE;
|
||||
|
||||
-- 3) 重新插入内置模板(与 install_data_permission.sql §12 一致,可重复执行)
|
||||
INSERT INTO `data_perm_template` (`Id`, `Name`, `Code`, `Description`, `RoleCode`, `IsBuiltIn`, `CreateUserId`, `CreateTime`) VALUES
|
||||
('da000001-0000-4000-8000-000000000001', '普通销售', 'SalesStaff', '个人级+指定产品线+密级1-2', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000002', '销售主管', 'SalesSupervisor', '部门级+全部产品线+密级1-3', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000003', '分公司经理', 'BranchManager', '组织树级+密级1-3', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000004', '总部产品经理', 'ProductManager', '全局级+单产品线+密级1-2', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000005', '财务专员', 'FinanceStaff', '组织树级+密级含3-4', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000006', '客服专员', 'CsStaff', '个人级+密级1-2', NULL, 1, 0, NOW())
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`Name` = VALUES(`Name`),
|
||||
`Description` = VALUES(`Description`),
|
||||
`IsBuiltIn` = VALUES(`IsBuiltIn`);
|
||||
|
||||
INSERT INTO `data_perm_template_item` (`Id`, `TemplateId`, `DimensionType`, `ItemContent`, `SortOrder`) VALUES
|
||||
('da200001-0000-4000-8000-000000000011', 'da000001-0000-4000-8000-000000000001', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000012', 'da000001-0000-4000-8000-000000000001', 'secret', '{"secretLevels":[1,2]}', 2),
|
||||
('da200001-0000-4000-8000-000000000021', 'da000001-0000-4000-8000-000000000002', 'data_scope', '{"dataScope":3,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000022', 'da000001-0000-4000-8000-000000000002', 'secret', '{"secretLevels":[1,2,3]}', 2),
|
||||
('da200001-0000-4000-8000-000000000031', 'da000001-0000-4000-8000-000000000003', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000032', 'da000001-0000-4000-8000-000000000003', 'secret', '{"secretLevels":[1,2,3]}', 2),
|
||||
('da200001-0000-4000-8000-000000000041', 'da000001-0000-4000-8000-000000000004', 'data_scope', '{"dataScope":5,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000042', 'da000001-0000-4000-8000-000000000004', 'secret', '{"secretLevels":[1,2]}', 2),
|
||||
('da200001-0000-4000-8000-000000000051', 'da000001-0000-4000-8000-000000000005', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000052', 'da000001-0000-4000-8000-000000000005', 'secret', '{"secretLevels":[1,2,3,4]}', 2),
|
||||
('da200001-0000-4000-8000-000000000061', 'da000001-0000-4000-8000-000000000006', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000062', 'da000001-0000-4000-8000-000000000006', 'secret', '{"secretLevels":[1,2]}', 2)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`ItemContent` = VALUES(`ItemContent`),
|
||||
`SortOrder` = VALUES(`SortOrder`);
|
||||
|
||||
SELECT 'after fix — bad template' AS stage, t.`Id`, t.`Name`, t.`Code`
|
||||
FROM `data_perm_template` t
|
||||
WHERE t.`Id` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'after fix — bad data_resource' AS stage, r.`Id`, r.`Code`, r.`Name`
|
||||
FROM `data_resource` r
|
||||
WHERE r.`Id` NOT REGEXP @GUID_RE;
|
||||
|
||||
SELECT 'after fix — bad field_mask' AS stage, f.`Id`, f.`DataResourceCode`, f.`FieldName`
|
||||
FROM `data_perm_field_mask` f
|
||||
WHERE f.`Id` NOT REGEXP @GUID_RE;
|
||||
@ -285,11 +285,11 @@ CREATE TABLE IF NOT EXISTS `data_perm_access_log` (
|
||||
-- 11. 种子:数据资源注册
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO `data_resource` (`Id`, `Code`, `Name`, `Description`, `MainTable`, `OrgField`, `OwnerField`, `SortOrder`) VALUES
|
||||
('dr000001-0000-4000-8000-000000000001', 'Order', '订单', '运营后台订单查询', 't_order', 'OrganizationId', 'CreateUserId', 10),
|
||||
('dr000001-0000-4000-8000-000000000002', 'Customer', '客户', '客户资料列表', 't_customer', 'OrganizationId', 'Salesman', 20),
|
||||
('dr000001-0000-4000-8000-000000000003', 'Recharge', '充值', '充值审核列表', 't_recharge_record', NULL, 'CreateUserId', 30),
|
||||
('dr000001-0000-4000-8000-000000000004', 'ChannelProduct', '销售产品', '渠道产品配置', 't_sales_product', NULL, NULL, 40),
|
||||
('dr000001-0000-4000-8000-000000000005', 'Xhs', '小红书', '小红书模块', NULL, NULL, NULL, 50)
|
||||
('da300001-0000-4000-8000-000000000001', 'Order', '订单', '运营后台订单查询', 't_order', 'OrganizationId', 'CreateUserId', 10),
|
||||
('da300001-0000-4000-8000-000000000002', 'Customer', '客户', '客户资料列表', 't_customer', 'OrganizationId', 'Salesman', 20),
|
||||
('da300001-0000-4000-8000-000000000003', 'Recharge', '充值', '充值审核列表', 't_recharge_record', NULL, 'CreateUserId', 30),
|
||||
('da300001-0000-4000-8000-000000000004', 'ChannelProduct', '销售产品', '渠道产品配置', 't_sales_product', NULL, NULL, 40),
|
||||
('da300001-0000-4000-8000-000000000005', 'Xhs', '小红书', '小红书模块', NULL, NULL, NULL, 50)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`Name` = VALUES(`Name`),
|
||||
`Description` = VALUES(`Description`),
|
||||
@ -301,35 +301,35 @@ ON DUPLICATE KEY UPDATE
|
||||
-- 12. 种子:内置权限模板(明细需按环境组织 Id 调整后再 apply)
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO `data_perm_template` (`Id`, `Name`, `Code`, `Description`, `RoleCode`, `IsBuiltIn`, `CreateUserId`, `CreateTime`) VALUES
|
||||
('dp000001-0000-4000-8000-000000000001', '普通销售', 'SalesStaff', '个人级+指定产品线+密级1-2', NULL, 1, 0, NOW()),
|
||||
('dp000001-0000-4000-8000-000000000002', '销售主管', 'SalesSupervisor', '部门级+全部产品线+密级1-3', NULL, 1, 0, NOW()),
|
||||
('dp000001-0000-4000-8000-000000000003', '分公司经理', 'BranchManager', '组织树级+密级1-3', NULL, 1, 0, NOW()),
|
||||
('dp000001-0000-4000-8000-000000000004', '总部产品经理', 'ProductManager', '全局级+单产品线+密级1-2', NULL, 1, 0, NOW()),
|
||||
('dp000001-0000-4000-8000-000000000005', '财务专员', 'FinanceStaff', '组织树级+密级含3-4', NULL, 1, 0, NOW()),
|
||||
('dp000001-0000-4000-8000-000000000006', '客服专员', 'CsStaff', '个人级+密级1-2', NULL, 1, 0, NOW())
|
||||
('da000001-0000-4000-8000-000000000001', '普通销售', 'SalesStaff', '个人级+指定产品线+密级1-2', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000002', '销售主管', 'SalesSupervisor', '部门级+全部产品线+密级1-3', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000003', '分公司经理', 'BranchManager', '组织树级+密级1-3', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000004', '总部产品经理', 'ProductManager', '全局级+单产品线+密级1-2', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000005', '财务专员', 'FinanceStaff', '组织树级+密级含3-4', NULL, 1, 0, NOW()),
|
||||
('da000001-0000-4000-8000-000000000006', '客服专员', 'CsStaff', '个人级+密级1-2', NULL, 1, 0, NOW())
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`Name` = VALUES(`Name`),
|
||||
`Description` = VALUES(`Description`);
|
||||
|
||||
INSERT INTO `data_perm_template_item` (`Id`, `TemplateId`, `DimensionType`, `ItemContent`, `SortOrder`) VALUES
|
||||
-- 普通销售
|
||||
('dp200001-0000-4000-8000-000000000011', 'dp000001-0000-4000-8000-000000000001', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
|
||||
('dp200001-0000-4000-8000-000000000012', 'dp000001-0000-4000-8000-000000000001', 'secret', '{"secretLevels":[1,2]}', 2),
|
||||
('da200001-0000-4000-8000-000000000011', 'da000001-0000-4000-8000-000000000001', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000012', 'da000001-0000-4000-8000-000000000001', 'secret', '{"secretLevels":[1,2]}', 2),
|
||||
-- 销售主管
|
||||
('dp200001-0000-4000-8000-000000000021', 'dp000001-0000-4000-8000-000000000002', 'data_scope', '{"dataScope":3,"dataResourceCode":null}', 1),
|
||||
('dp200001-0000-4000-8000-000000000022', 'dp000001-0000-4000-8000-000000000002', 'secret', '{"secretLevels":[1,2,3]}', 2),
|
||||
('da200001-0000-4000-8000-000000000021', 'da000001-0000-4000-8000-000000000002', 'data_scope', '{"dataScope":3,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000022', 'da000001-0000-4000-8000-000000000002', 'secret', '{"secretLevels":[1,2,3]}', 2),
|
||||
-- 分公司经理
|
||||
('dp200001-0000-4000-8000-000000000031', 'dp000001-0000-4000-8000-000000000003', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
|
||||
('dp200001-0000-4000-8000-000000000032', 'dp000001-0000-4000-8000-000000000003', 'secret', '{"secretLevels":[1,2,3]}', 2),
|
||||
('da200001-0000-4000-8000-000000000031', 'da000001-0000-4000-8000-000000000003', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000032', 'da000001-0000-4000-8000-000000000003', 'secret', '{"secretLevels":[1,2,3]}', 2),
|
||||
-- 总部产品经理
|
||||
('dp200001-0000-4000-8000-000000000041', 'dp000001-0000-4000-8000-000000000004', 'data_scope', '{"dataScope":5,"dataResourceCode":null}', 1),
|
||||
('dp200001-0000-4000-8000-000000000042', 'dp000001-0000-4000-8000-000000000004', 'secret', '{"secretLevels":[1,2]}', 2),
|
||||
('da200001-0000-4000-8000-000000000041', 'da000001-0000-4000-8000-000000000004', 'data_scope', '{"dataScope":5,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000042', 'da000001-0000-4000-8000-000000000004', 'secret', '{"secretLevels":[1,2]}', 2),
|
||||
-- 财务专员
|
||||
('dp200001-0000-4000-8000-000000000051', 'dp000001-0000-4000-8000-000000000005', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
|
||||
('dp200001-0000-4000-8000-000000000052', 'dp000001-0000-4000-8000-000000000005', 'secret', '{"secretLevels":[1,2,3,4]}', 2),
|
||||
('da200001-0000-4000-8000-000000000051', 'da000001-0000-4000-8000-000000000005', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000052', 'da000001-0000-4000-8000-000000000005', 'secret', '{"secretLevels":[1,2,3,4]}', 2),
|
||||
-- 客服专员
|
||||
('dp200001-0000-4000-8000-000000000061', 'dp000001-0000-4000-8000-000000000006', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
|
||||
('dp200001-0000-4000-8000-000000000062', 'dp000001-0000-4000-8000-000000000006', 'secret', '{"secretLevels":[1,2]}', 2)
|
||||
('da200001-0000-4000-8000-000000000061', 'da000001-0000-4000-8000-000000000006', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
|
||||
('da200001-0000-4000-8000-000000000062', 'da000001-0000-4000-8000-000000000006', 'secret', '{"secretLevels":[1,2]}', 2)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`ItemContent` = VALUES(`ItemContent`),
|
||||
`SortOrder` = VALUES(`SortOrder`);
|
||||
@ -338,12 +338,12 @@ ON DUPLICATE KEY UPDATE
|
||||
-- 13. 种子:字段脱敏(Customer / Order)
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO `data_perm_field_mask` (`Id`, `DataResourceCode`, `FieldName`, `SecretLevel`, `MaskType`, `MaskPattern`) VALUES
|
||||
('fm000001-0000-4000-8000-000000000001', 'Customer', 'Phone', 4, 'partial', 'phone'),
|
||||
('fm000001-0000-4000-8000-000000000002', 'Customer', 'Email', 4, 'partial', 'email'),
|
||||
('fm000001-0000-4000-8000-000000000003', 'Customer', 'Password', 1, 'hide', NULL),
|
||||
('fm000001-0000-4000-8000-000000000004', 'Order', 'PayableAmount', 3, 'hide', NULL),
|
||||
('fm000001-0000-4000-8000-000000000005', 'Order', 'CostAmount', 3, 'hide', NULL),
|
||||
('fm000001-0000-4000-8000-000000000006', 'Order', 'ProfitAmount', 4, 'hide', NULL)
|
||||
('fa000001-0000-4000-8000-000000000001', 'Customer', 'Phone', 4, 'partial', 'phone'),
|
||||
('fa000001-0000-4000-8000-000000000002', 'Customer', 'Email', 4, 'partial', 'email'),
|
||||
('fa000001-0000-4000-8000-000000000003', 'Customer', 'Password', 1, 'hide', NULL),
|
||||
('fa000001-0000-4000-8000-000000000004', 'Order', 'PayableAmount', 3, 'hide', NULL),
|
||||
('fa000001-0000-4000-8000-000000000005', 'Order', 'CostAmount', 3, 'hide', NULL),
|
||||
('fa000001-0000-4000-8000-000000000006', 'Order', 'ProfitAmount', 4, 'hide', NULL)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`SecretLevel` = VALUES(`SecretLevel`),
|
||||
`MaskType` = VALUES(`MaskType`);
|
||||
|
||||
@ -26,7 +26,7 @@ INSERT INTO `menu` (
|
||||
`ConcurrencyStamp`, `CreateUserId`, `CreateTime`, `UpdateUserId`, `UpdateTime`
|
||||
) VALUES
|
||||
(
|
||||
'dp100001-0000-4000-8000-000000000001',
|
||||
'da100001-0000-4000-8000-000000000001',
|
||||
@SYSTEM_PID,
|
||||
'数据权限',
|
||||
'Rbac.DataPerm',
|
||||
@ -39,8 +39,8 @@ INSERT INTO `menu` (
|
||||
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
|
||||
),
|
||||
(
|
||||
'dp100001-0000-4000-8000-000000000002',
|
||||
'dp100001-0000-4000-8000-000000000001',
|
||||
'da100001-0000-4000-8000-000000000002',
|
||||
'da100001-0000-4000-8000-000000000001',
|
||||
'用户数据权限',
|
||||
'Rbac.DataPerm.Query',
|
||||
1,
|
||||
@ -52,8 +52,8 @@ INSERT INTO `menu` (
|
||||
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
|
||||
),
|
||||
(
|
||||
'dp100001-0000-4000-8000-000000000003',
|
||||
'dp100001-0000-4000-8000-000000000001',
|
||||
'da100001-0000-4000-8000-000000000003',
|
||||
'da100001-0000-4000-8000-000000000001',
|
||||
'权限模板',
|
||||
'Rbac.DataPerm.Template',
|
||||
1,
|
||||
@ -65,8 +65,8 @@ INSERT INTO `menu` (
|
||||
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
|
||||
),
|
||||
(
|
||||
'dp100001-0000-4000-8000-000000000004',
|
||||
'dp100001-0000-4000-8000-000000000001',
|
||||
'da100001-0000-4000-8000-000000000004',
|
||||
'da100001-0000-4000-8000-000000000001',
|
||||
'访问审计',
|
||||
'Rbac.DataPerm.Audit',
|
||||
1,
|
||||
@ -78,8 +78,8 @@ INSERT INTO `menu` (
|
||||
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
|
||||
),
|
||||
(
|
||||
'dp100001-0000-4000-8000-000000000005',
|
||||
'dp100001-0000-4000-8000-000000000002',
|
||||
'da100001-0000-4000-8000-000000000005',
|
||||
'da100001-0000-4000-8000-000000000002',
|
||||
'保存用户权限',
|
||||
'Rbac.DataPerm.Update',
|
||||
2,
|
||||
@ -100,7 +100,7 @@ ON DUPLICATE KEY UPDATE
|
||||
|
||||
-- 超管角色分配数据权限(若存在 Admin 角色)
|
||||
INSERT INTO `role_permission` (`Id`, `RoleId`, `PermissionCode`, `CreateUserId`, `CreateTime`)
|
||||
SELECT UUID(), r.`Id`, p.`Code`, 0, NOW()
|
||||
SELECT UUID(), r.`Id`, p.`Code`, @ADMIN_USER_ID, NOW()
|
||||
FROM `role` r
|
||||
CROSS JOIN (
|
||||
SELECT 'Rbac.DataPerm' AS Code UNION ALL
|
||||
|
||||
@ -499,8 +499,18 @@ public class DataPermStore(FakeRbacDbContext dbContext, DataPermContextCache cac
|
||||
LIMIT {pageSize} OFFSET {offset}
|
||||
""";
|
||||
|
||||
var items = await dbContext.Database.SqlQueryRaw<ChangeLogItemDto>(listSql, args.ToArray())
|
||||
var rows = await dbContext.Database.SqlQueryRaw<ChangeLogRow>(listSql, args.ToArray())
|
||||
.ToListAsync(cancellationToken);
|
||||
var items = rows.Select(x => new ChangeLogItemDto
|
||||
{
|
||||
Id = x.Id,
|
||||
TargetType = x.TargetType,
|
||||
TargetId = x.TargetId.ToString(),
|
||||
Action = x.Action,
|
||||
OperatorUserId = x.OperatorUserId?.ToString(),
|
||||
OperatorMapId = x.OperatorMapId,
|
||||
CreateTime = x.CreateTime
|
||||
}).ToList();
|
||||
|
||||
return new DataPermPagedResult<ChangeLogItemDto> { Total = total, Items = items };
|
||||
}
|
||||
@ -560,8 +570,21 @@ public class DataPermStore(FakeRbacDbContext dbContext, DataPermContextCache cac
|
||||
LIMIT {pageSize} OFFSET {offset}
|
||||
""";
|
||||
|
||||
var items = await dbContext.Database.SqlQueryRaw<AccessLogItemDto>(listSql).ToListAsync(cancellationToken);
|
||||
return new DataPermPagedResult<AccessLogItemDto> { Total = total, Items = items };
|
||||
var items = await dbContext.Database.SqlQueryRaw<AccessLogRow>(listSql)
|
||||
.ToListAsync(cancellationToken);
|
||||
return new DataPermPagedResult<AccessLogItemDto>
|
||||
{
|
||||
Total = total,
|
||||
Items = items.Select(x => new AccessLogItemDto
|
||||
{
|
||||
Id = x.Id,
|
||||
UserId = x.UserId.ToString(),
|
||||
DataResourceCode = x.DataResourceCode,
|
||||
ApiPath = x.ApiPath,
|
||||
RowCount = x.RowCount,
|
||||
CreateTime = x.CreateTime
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<DataPermPagedResult<DataPermTemplateListItemDto>> GetTemplateListAsync(
|
||||
@ -594,12 +617,18 @@ public class DataPermStore(FakeRbacDbContext dbContext, DataPermContextCache cac
|
||||
LIMIT {pageSize} OFFSET {offset}
|
||||
""";
|
||||
|
||||
var items = await dbContext.Database.SqlQueryRaw<DataPermTemplateListItemDto>(sql, args.ToArray())
|
||||
var rows = await dbContext.Database.SqlQueryRaw<TemplateListRow>(sql, args.ToArray())
|
||||
.ToListAsync(cancellationToken);
|
||||
foreach (var item in items)
|
||||
var items = rows.Select(x => new DataPermTemplateListItemDto
|
||||
{
|
||||
item.IsBuiltIn = item.IsBuiltIn;
|
||||
}
|
||||
Id = x.Id.ToString(),
|
||||
Name = x.Name,
|
||||
Code = x.Code,
|
||||
Description = x.Description,
|
||||
RoleCode = x.RoleCode,
|
||||
IsBuiltIn = x.IsBuiltIn != 0,
|
||||
ItemCount = x.ItemCount
|
||||
}).ToList();
|
||||
|
||||
return new DataPermPagedResult<DataPermTemplateListItemDto> { Total = total, Items = items };
|
||||
}
|
||||
@ -614,7 +643,7 @@ public class DataPermStore(FakeRbacDbContext dbContext, DataPermContextCache cac
|
||||
LIMIT 1
|
||||
""";
|
||||
|
||||
var header = await dbContext.Database.SqlQueryRaw<DataPermTemplateDetailDto>(headerSql, templateId.ToString())
|
||||
var headerRow = await dbContext.Database.SqlQueryRaw<TemplateHeaderRow>(headerSql, templateId.ToString())
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
?? throw new BusinessException("模板不存在");
|
||||
|
||||
@ -628,13 +657,22 @@ public class DataPermStore(FakeRbacDbContext dbContext, DataPermContextCache cac
|
||||
var itemRows = await dbContext.Database.SqlQueryRaw<TemplateItemRow>(itemSql, templateId.ToString())
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
header.Items = itemRows.Select(x => new DataPermTemplateItemDto
|
||||
var header = new DataPermTemplateDetailDto
|
||||
{
|
||||
Id = headerRow.Id.ToString(),
|
||||
Name = headerRow.Name,
|
||||
Code = headerRow.Code,
|
||||
Description = headerRow.Description,
|
||||
RoleCode = headerRow.RoleCode,
|
||||
IsBuiltIn = headerRow.IsBuiltIn != 0,
|
||||
Items = itemRows.Select(x => new DataPermTemplateItemDto
|
||||
{
|
||||
Id = x.Id.ToString(),
|
||||
DimensionType = x.DimensionType,
|
||||
ItemContent = JsonSerializer.Deserialize<Dictionary<string, object?>>(x.ItemContentJson, JsonOptions) ?? [],
|
||||
SortOrder = x.SortOrder
|
||||
}).ToList();
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
return header;
|
||||
}
|
||||
@ -856,6 +894,70 @@ public class DataPermStore(FakeRbacDbContext dbContext, DataPermContextCache cac
|
||||
public string FilterContentJson { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
private sealed class ChangeLogRow
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public string TargetType { get; set; } = string.Empty;
|
||||
|
||||
public Guid TargetId { get; set; }
|
||||
|
||||
public string Action { get; set; } = string.Empty;
|
||||
|
||||
public Guid? OperatorUserId { get; set; }
|
||||
|
||||
public int? OperatorMapId { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
|
||||
private sealed class AccessLogRow
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
public string DataResourceCode { get; set; } = string.Empty;
|
||||
|
||||
public string ApiPath { get; set; } = string.Empty;
|
||||
|
||||
public int? RowCount { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
|
||||
private sealed class TemplateListRow
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public string? RoleCode { get; set; }
|
||||
|
||||
public int IsBuiltIn { get; set; }
|
||||
|
||||
public int ItemCount { get; set; }
|
||||
}
|
||||
|
||||
private sealed class TemplateHeaderRow
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public string? RoleCode { get; set; }
|
||||
|
||||
public int IsBuiltIn { get; set; }
|
||||
}
|
||||
|
||||
private sealed class TemplateItemRow
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user