using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using TakeoutSaaS.Infrastructure.Identity.Persistence;
#nullable disable
namespace TakeoutSaaS.Infrastructure.Migrations.IdentityDb;
///
/// 写入成本管理菜单与权限定义。
///
[DbContext(typeof(IdentityDbContext))]
[Migration("20260305013000_SeedFinanceCostMenuAndPermissions")]
public sealed class SeedFinanceCostMenuAndPermissions : Migration
{
///
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(
"""
DO $$
DECLARE
v_parent_permission_id bigint;
v_view_permission_id bigint;
v_manage_permission_id bigint;
v_parent_menu_id bigint;
v_cost_menu_id bigint;
v_permission_seed_base bigint := 840100000000000000;
v_menu_seed_base bigint := 850100000000000000;
BEGIN
-- 1. 确保财务权限分组存在。
SELECT "Id"
INTO v_parent_permission_id
FROM public.permissions
WHERE "Code" = 'group:tenant:finance'
ORDER BY "Id"
LIMIT 1;
IF v_parent_permission_id IS NULL THEN
v_parent_permission_id := v_permission_seed_base + 1;
INSERT INTO public.permissions (
"Id", "Name", "Code", "Description",
"CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy",
"ParentId", "SortOrder", "Type", "Portal")
VALUES (
v_parent_permission_id, '财务中心', 'group:tenant:finance', '财务中心权限分组',
NOW(), NULL, NULL,
NULL, NULL, NULL,
0, 5000, 'group', 1)
ON CONFLICT ("Code") DO NOTHING;
END IF;
-- 2. Upsert 成本管理查看权限。
INSERT INTO public.permissions (
"Id", "Name", "Code", "Description",
"CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy",
"ParentId", "SortOrder", "Type", "Portal")
VALUES (
v_permission_seed_base + 11, '成本管理查看', 'tenant:finance:cost:view', '查看成本录入与成本分析',
NOW(), NULL, NULL,
NULL, NULL, NULL,
v_parent_permission_id, 5110, 'leaf', 1)
ON CONFLICT ("Code") DO UPDATE
SET "Name" = EXCLUDED."Name",
"Description" = EXCLUDED."Description",
"ParentId" = EXCLUDED."ParentId",
"SortOrder" = EXCLUDED."SortOrder",
"Type" = EXCLUDED."Type",
"Portal" = EXCLUDED."Portal",
"DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW();
-- 3. Upsert 成本管理维护权限。
INSERT INTO public.permissions (
"Id", "Name", "Code", "Description",
"CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy",
"ParentId", "SortOrder", "Type", "Portal")
VALUES (
v_permission_seed_base + 12, '成本管理维护', 'tenant:finance:cost:manage', '维护成本录入明细与保存数据',
NOW(), NULL, NULL,
NULL, NULL, NULL,
v_parent_permission_id, 5120, 'leaf', 1)
ON CONFLICT ("Code") DO UPDATE
SET "Name" = EXCLUDED."Name",
"Description" = EXCLUDED."Description",
"ParentId" = EXCLUDED."ParentId",
"SortOrder" = EXCLUDED."SortOrder",
"Type" = EXCLUDED."Type",
"Portal" = EXCLUDED."Portal",
"DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW();
-- 4. 回填权限 ID。
SELECT "Id" INTO v_view_permission_id FROM public.permissions WHERE "Code" = 'tenant:finance:cost:view' LIMIT 1;
SELECT "Id" INTO v_manage_permission_id FROM public.permissions WHERE "Code" = 'tenant:finance:cost:manage' LIMIT 1;
-- 5. 确保租户端财务父菜单存在。
SELECT "Id"
INTO v_parent_menu_id
FROM public.menu_definitions
WHERE "Portal" = 1 AND "Path" = '/finance' AND "DeletedAt" IS NULL
ORDER BY "Id"
LIMIT 1;
IF v_parent_menu_id IS NULL THEN
v_parent_menu_id := v_menu_seed_base + 1;
INSERT INTO public.menu_definitions (
"Id", "ParentId", "Name", "Path", "Component", "Title", "Icon",
"IsIframe", "Link", "KeepAlive", "SortOrder",
"RequiredPermissions", "MetaPermissions", "MetaRoles", "AuthListJson",
"CreatedAt", "UpdatedAt", "DeletedAt", "CreatedBy", "UpdatedBy", "DeletedBy", "Portal")
VALUES (
v_parent_menu_id, 0, 'Finance', '/finance', 'BasicLayout', '财务中心', 'lucide:wallet',
FALSE, NULL, FALSE, 500,
'', '', '', NULL,
NOW(), NULL, NULL, NULL, NULL, NULL, 1)
ON CONFLICT ("Id") DO NOTHING;
END IF;
-- 6. Upsert 成本管理菜单。
SELECT "Id"
INTO v_cost_menu_id
FROM public.menu_definitions
WHERE "Portal" = 1
AND ("Path" = '/finance/cost' OR ("Path" = 'cost' AND "Component" = '/finance/cost/index'))
ORDER BY "DeletedAt" NULLS FIRST, "Id"
LIMIT 1;
IF v_cost_menu_id IS NULL THEN
v_cost_menu_id := v_menu_seed_base + 11;
INSERT INTO public.menu_definitions (
"Id", "ParentId", "Name", "Path", "Component", "Title", "Icon",
"IsIframe", "Link", "KeepAlive", "SortOrder",
"RequiredPermissions", "MetaPermissions", "MetaRoles", "AuthListJson",
"CreatedAt", "UpdatedAt", "DeletedAt", "CreatedBy", "UpdatedBy", "DeletedBy", "Portal")
VALUES (
v_cost_menu_id, v_parent_menu_id, 'CostManagement', '/finance/cost', '/finance/cost/index', '成本管理', 'lucide:circle-dollar-sign',
FALSE, NULL, TRUE, 520,
'tenant:finance:cost:view', 'tenant:finance:cost:view,tenant:finance:cost:manage', '', NULL,
NOW(), NULL, NULL, NULL, NULL, NULL, 1)
ON CONFLICT ("Id") DO NOTHING;
ELSE
UPDATE public.menu_definitions
SET "ParentId" = v_parent_menu_id,
"Name" = 'CostManagement',
"Path" = '/finance/cost',
"Component" = '/finance/cost/index',
"Title" = '成本管理',
"Icon" = 'lucide:circle-dollar-sign',
"IsIframe" = FALSE,
"Link" = NULL,
"KeepAlive" = TRUE,
"SortOrder" = 520,
"RequiredPermissions" = 'tenant:finance:cost:view',
"MetaPermissions" = 'tenant:finance:cost:view,tenant:finance:cost:manage',
"MetaRoles" = '',
"DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW(),
"Portal" = 1
WHERE "Id" = v_cost_menu_id;
END IF;
-- 7. 为 tenant-admin 角色授予成本权限。
INSERT INTO public.role_permissions (
"Id", "RoleId", "PermissionId", "CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy", "TenantId", "Portal")
SELECT
ABS(HASHTEXTEXTENDED('tenant-admin:cost:' || role."Id"::text || ':' || permission_id::text, 0)),
role."Id",
permission_id,
NOW(), NULL, NULL,
NULL, NULL, NULL,
role."TenantId",
1
FROM public.roles role
CROSS JOIN LATERAL (
SELECT UNNEST(ARRAY[v_view_permission_id, v_manage_permission_id]) AS permission_id
) item
WHERE role."Code" = 'tenant-admin'
AND role."DeletedAt" IS NULL
AND item.permission_id IS NOT NULL
ON CONFLICT ("RoleId", "PermissionId") DO UPDATE
SET "DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW(),
"Portal" = 1;
-- 8. 为 tenant-admin 角色模板授予成本权限。
INSERT INTO public.role_template_permissions (
"Id", "RoleTemplateId", "PermissionCode",
"CreatedAt", "UpdatedAt", "DeletedAt",
"CreatedBy", "UpdatedBy", "DeletedBy")
SELECT
ABS(HASHTEXTEXTENDED('template-cost:' || template."Id"::text || ':' || item.permission_code, 0)),
template."Id",
item.permission_code,
NOW(), NULL, NULL,
NULL, NULL, NULL
FROM public.role_templates template
CROSS JOIN LATERAL (
SELECT UNNEST(ARRAY['tenant:finance:cost:view', 'tenant:finance:cost:manage']) AS permission_code
) item
WHERE template."TemplateCode" = 'tenant-admin'
AND template."DeletedAt" IS NULL
ON CONFLICT ("RoleTemplateId", "PermissionCode") DO UPDATE
SET "DeletedAt" = NULL,
"DeletedBy" = NULL,
"UpdatedAt" = NOW();
END $$;
""");
}
///
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(
"""
DO $$
BEGIN
DELETE FROM public.role_permissions
WHERE "PermissionId" IN (
SELECT "Id"
FROM public.permissions
WHERE "Code" IN ('tenant:finance:cost:view', 'tenant:finance:cost:manage'));
DELETE FROM public.role_template_permissions
WHERE "PermissionCode" IN ('tenant:finance:cost:view', 'tenant:finance:cost:manage');
DELETE FROM public.menu_definitions
WHERE "Portal" = 1 AND "Path" = '/finance/cost';
DELETE FROM public.permissions
WHERE "Code" IN ('tenant:finance:cost:view', 'tenant:finance:cost:manage');
END $$;
""");
}
}