diff --git a/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.cs b/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.cs
index a4d8c9c..cb47009 100644
--- a/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.cs
+++ b/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.cs
@@ -1,4 +1,5 @@
-using Microsoft.EntityFrameworkCore.Migrations;
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
@@ -10,20 +11,61 @@ namespace Platform.Infrastructure.Migrations
///
protected override void Up(MigrationBuilder migrationBuilder)
{
- migrationBuilder.AddColumn(
- name: "code",
- table: "menus",
- type: "character varying(100)",
- maxLength: 100,
- nullable: false,
- defaultValue: "",
- comment: "菜单编码,点号分层(system / system.user),全局唯一");
+ // 历史库的 menus 表由旧版本(PascalCase 列名)创建,与当前 EF 模型(snake_case)
+ // 完全不匹配,且数据为旧业务残留(点单台/租号监控等,path 在当前前端不存在)。
+ // 菜单是配置型数据,这里 DROP 旧表并按当前 snake_case 模型重建,由 SeedMenusAsync 重新播种。
+ migrationBuilder.Sql("DROP TABLE IF EXISTS menus;");
+
+ migrationBuilder.CreateTable(
+ name: "menus",
+ columns: table => new
+ {
+ id = table.Column(type: "uuid", nullable: false, comment: "菜单ID"),
+ name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false, comment: "菜单名称(路由name)"),
+ path = table.Column(type: "character varying(200)", maxLength: 200, nullable: false, comment: "路由路径"),
+ component = table.Column(type: "character varying(200)", maxLength: 200, nullable: true, comment: "前端组件路径"),
+ redirect = table.Column(type: "character varying(200)", maxLength: 200, nullable: true, comment: "重定向路径"),
+ parent_id = table.Column(type: "uuid", nullable: true, comment: "父菜单ID,null表示顶级菜单"),
+ title = table.Column(type: "character varying(100)", maxLength: 100, nullable: false, comment: "菜单显示标题"),
+ code = table.Column(type: "character varying(100)", maxLength: 100, nullable: false, comment: "菜单编码,点号分层(system / system.user),全局唯一"),
+ icon = table.Column(type: "character varying(100)", maxLength: 100, nullable: true, comment: "菜单图标"),
+ active_icon = table.Column(type: "character varying(100)", maxLength: 100, nullable: true, comment: "菜单激活状态图标"),
+ order = table.Column(type: "integer", nullable: false, comment: "排序序号,值越小越靠前"),
+ hide_in_menu = table.Column(type: "boolean", nullable: false, comment: "是否在菜单中隐藏"),
+ keep_alive = table.Column(type: "boolean", nullable: true, comment: "是否缓存页面状态"),
+ affix_tab = table.Column(type: "boolean", nullable: true, comment: "是否固定标签页"),
+ link = table.Column(type: "character varying(500)", maxLength: 500, nullable: true, comment: "外链地址"),
+ no_basic_layout = table.Column(type: "boolean", nullable: false, comment: "是否不使用基础布局"),
+ menu_visible_with_forbidden = table.Column(type: "boolean", nullable: false, comment: "无权限时是否仍显示菜单"),
+ authority = table.Column(type: "character varying(200)", maxLength: 200, nullable: true, comment: "允许访问的角色名,逗号分隔,为空表示所有已认证用户可访问"),
+ created_by = table.Column(type: "character varying(100)", maxLength: 100, nullable: false, comment: "创建人"),
+ created_at = table.Column(type: "timestamp with time zone", nullable: false, comment: "创建时间"),
+ updated_by = table.Column(type: "character varying(100)", maxLength: 100, nullable: false, comment: "更新人"),
+ updated_at = table.Column(type: "timestamp with time zone", nullable: false, comment: "更新时间"),
+ is_deleted = table.Column(type: "boolean", nullable: false, defaultValue: false, comment: "是否已软删除"),
+ operator_ip = table.Column(type: "character varying(50)", maxLength: 50, nullable: false, comment: "操作者IP地址")
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_menus", x => x.id);
+ table.ForeignKey(
+ name: "fk_menus_menus_parent_id",
+ column: x => x.parent_id,
+ principalTable: "menus",
+ principalColumn: "id",
+ onDelete: ReferentialAction.Cascade);
+ });
migrationBuilder.CreateIndex(
name: "ix_menus_code",
table: "menus",
column: "code",
unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "ix_menus_parent_id",
+ table: "menus",
+ column: "parent_id");
}
///