调整:提升业务菜单为一级目录

This commit is contained in:
焦龙言
2026-07-27 20:30:18 +08:00
parent 9a9c57578d
commit 619f3d5d63
3 changed files with 60 additions and 29 deletions
@@ -264,9 +264,9 @@ comment on table sys_menu is '菜单权限表';
-- 初始化-菜单信息表数据 -- 初始化-菜单信息表数据
-- ---------------------------- -- ----------------------------
-- 一级菜单 -- 一级菜单
insert into sys_menu values(1, '系统管理', 0, '1', 'system', null, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', current_timestamp, '', null, '系统管理目录'); insert into sys_menu values(1, '系统管理', 0, '4', 'system', null, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', current_timestamp, '', null, '系统管理目录');
insert into sys_menu values(2, '系统监控', 0, '2', 'monitor', null, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', current_timestamp, '', null, '系统监控目录'); insert into sys_menu values(2, '系统监控', 0, '5', 'monitor', null, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', current_timestamp, '', null, '系统监控目录');
insert into sys_menu values(3, '系统工具', 0, '3', 'tool', null, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', current_timestamp, '', null, '系统工具目录'); insert into sys_menu values(3, '系统工具', 0, '6', 'tool', null, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', current_timestamp, '', null, '系统工具目录');
-- 二级菜单 -- 二级菜单
insert into sys_menu values(100, '用户管理', 1, '1', 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', current_timestamp, '', null, '用户管理菜单'); insert into sys_menu values(100, '用户管理', 1, '1', 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', current_timestamp, '', null, '用户管理菜单');
insert into sys_menu values(101, '角色管理', 1, '2', 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', current_timestamp, '', null, '角色管理菜单'); insert into sys_menu values(101, '角色管理', 1, '2', 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', current_timestamp, '', null, '角色管理菜单');
@@ -1446,12 +1446,12 @@ create table biz_pallet_inventory (
); );
-- ---------------------------- -- ----------------------------
-- 初始化-托盘业务菜单和权限 -- 初始化-托盘业务一级菜单和权限
-- ---------------------------- -- ----------------------------
insert into sys_menu values insert into sys_menu values
(121, '基础资料维护', 1, '10', 'businessMaster', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', current_timestamp, '', null, ''), (121, '基础资料维护', 0, '1', 'businessMaster', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', current_timestamp, '', null, ''),
(122, '业务管理', 1, '11', 'businessOperation', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', current_timestamp, '', null, ''), (122, '业务管理', 0, '2', 'businessOperation', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', current_timestamp, '', null, ''),
(123, '报表查询', 1, '12', 'businessReport', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', current_timestamp, '', null, ''), (123, '报表查询', 0, '3', 'businessReport', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', current_timestamp, '', null, ''),
(502, '菌种资料', 121, '1', 'strain', 'master/strain/index', '', '', 1, 0, 'C', '0', '0', 'master:strain:list', '#', 'admin', current_timestamp, '', null, ''), (502, '菌种资料', 121, '1', 'strain', 'master/strain/index', '', '', 1, 0, 'C', '0', '0', 'master:strain:list', '#', 'admin', current_timestamp, '', null, ''),
(503, '客户资料', 121, '2', 'customer', 'master/customer/index', '', '', 1, 0, 'C', '0', '0', 'master:customer:list', '#', 'admin', current_timestamp, '', null, ''), (503, '客户资料', 121, '2', 'customer', 'master/customer/index', '', '', 1, 0, 'C', '0', '0', 'master:customer:list', '#', 'admin', current_timestamp, '', null, ''),
(504, '客户现场', 121, '3', 'site', 'master/site/index', '', '', 1, 0, 'C', '0', '0', 'master:site:list', '#', 'admin', current_timestamp, '', null, ''), (504, '客户现场', 121, '3', 'site', 'master/site/index', '', '', 1, 0, 'C', '0', '0', 'master:site:list', '#', 'admin', current_timestamp, '', null, ''),
@@ -181,9 +181,9 @@ create table sys_menu (
-- 初始化-菜单信息表数据 -- 初始化-菜单信息表数据
-- ---------------------------- -- ----------------------------
-- 一级菜单 -- 一级菜单
insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', sysdate(), '', null, '系统管理目录'); insert into sys_menu values('1', '系统管理', '0', '4', 'system', null, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', sysdate(), '', null, '系统管理目录');
insert into sys_menu values('2', '系统监控', '0', '2', 'monitor', null, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', sysdate(), '', null, '系统监控目录'); insert into sys_menu values('2', '系统监控', '0', '5', 'monitor', null, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', sysdate(), '', null, '系统监控目录');
insert into sys_menu values('3', '系统工具', '0', '3', 'tool', null, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', sysdate(), '', null, '系统工具目录'); insert into sys_menu values('3', '系统工具', '0', '6', 'tool', null, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', sysdate(), '', null, '系统工具目录');
-- 二级菜单 -- 二级菜单
insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', sysdate(), '', null, '用户管理菜单'); insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', sysdate(), '', null, '用户管理菜单');
insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', sysdate(), '', null, '角色管理菜单'); insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', sysdate(), '', null, '角色管理菜单');
@@ -282,10 +282,10 @@ insert into sys_menu values('1058', '导入代码', '116', '4', '#', '', '', '',
insert into sys_menu values('1059', '预览代码', '116', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, ''); insert into sys_menu values('1059', '预览代码', '116', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1060', '生成代码', '116', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', sysdate(), '', null, ''); insert into sys_menu values('1060', '生成代码', '116', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', sysdate(), '', null, '');
-- 托盘业务目录 -- 托盘业务一级目录
insert into sys_menu values('121', '基础资料维护', '1', '10', 'businessMaster', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', sysdate(), '', null, '基础资料维护目录'); insert into sys_menu values('121', '基础资料维护', '0', '1', 'businessMaster', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', sysdate(), '', null, '基础资料维护目录');
insert into sys_menu values('122', '业务管理', '1', '11', 'businessOperation', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', sysdate(), '', null, '业务管理目录'); insert into sys_menu values('122', '业务管理', '0', '2', 'businessOperation', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', sysdate(), '', null, '业务管理目录');
insert into sys_menu values('123', '报表查询', '1', '12', 'businessReport', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', sysdate(), '', null, '报表查询目录'); insert into sys_menu values('123', '报表查询', '0', '3', 'businessReport', null, '', '', 1, 0, 'M', '0', '0', '', '#', 'admin', sysdate(), '', null, '报表查询目录');
-- 托盘业务页面 -- 托盘业务页面
insert into sys_menu values('502', '菌种资料', '121', '1', 'strain', 'master/strain/index', '', '', 1, 0, 'C', '0', '0', 'master:strain:list', '#', 'admin', sysdate(), '', null, '菌种资料菜单'); insert into sys_menu values('502', '菌种资料', '121', '1', 'strain', 'master/strain/index', '', '', 1, 0, 'C', '0', '0', 'master:strain:list', '#', 'admin', sysdate(), '', null, '菌种资料菜单');
@@ -6,6 +6,7 @@ from pathlib import Path
SQL_ROOT = Path(__file__).resolve().parents[2] / 'sql' SQL_ROOT = Path(__file__).resolve().parents[2] / 'sql'
INITIALIZERS = ('shierfeng-fastapi.sql', 'shierfeng-fastapi-pg.sql') INITIALIZERS = ('shierfeng-fastapi.sql', 'shierfeng-fastapi-pg.sql')
PATCH_PATH = SQL_ROOT / 'patches/20260724_pallet_workflow_mysql.sql' PATCH_PATH = SQL_ROOT / 'patches/20260724_pallet_workflow_mysql.sql'
MENU_PROMOTION_PATCH_PATH = SQL_ROOT / 'patches/20260727_promote_business_menus_mysql.sql'
SYS_MENU_VALUE_COUNT = 20 SYS_MENU_VALUE_COUNT = 20
SYS_MENU_PERMS_INDEX = 13 SYS_MENU_PERMS_INDEX = 13
REMOVED_AI_DICT_CODES = set(range(33, 70)) REMOVED_AI_DICT_CODES = set(range(33, 70))
@@ -492,9 +493,9 @@ EXPECTED_BUTTON_PERMISSIONS = frozenset(
) )
EXPECTED_PERMISSIONS = EXPECTED_PAGE_PERMISSIONS | EXPECTED_BUTTON_PERMISSIONS EXPECTED_PERMISSIONS = EXPECTED_PAGE_PERMISSIONS | EXPECTED_BUTTON_PERMISSIONS
BUSINESS_MENU_SPECS = """ BUSINESS_MENU_SPECS = """
121|1|基础资料维护|businessMaster||10||<NULL> 121|0|基础资料维护|businessMaster||1||<NULL>
122|1|业务管理|businessOperation||11||<NULL> 122|0|业务管理|businessOperation||2||<NULL>
123|1|报表查询|businessReport||12||<NULL> 123|0|报表查询|businessReport||3||<NULL>
502|121|菌种资料|strain||1|master:strain:list|master/strain/index 502|121|菌种资料|strain||1|master:strain:list|master/strain/index
503|121|客户资料|customer||2|master:customer:list|master/customer/index 503|121|客户资料|customer||2|master:customer:list|master/customer/index
504|121|客户现场|site||3|master:site:list|master/site/index 504|121|客户现场|site||3|master:site:list|master/site/index
@@ -576,6 +577,20 @@ def _expected_business_menu_fields() -> dict[int, tuple]:
EXPECTED_BUSINESS_MENU_FIELDS = _expected_business_menu_fields() EXPECTED_BUSINESS_MENU_FIELDS = _expected_business_menu_fields()
LEGACY_PATCH_BUSINESS_MENU_FIELDS = EXPECTED_BUSINESS_MENU_FIELDS | {
121: (1, '基础资料维护', 'businessMaster', '', 10, '', None),
122: (1, '业务管理', 'businessOperation', '', 11, '', None),
123: (1, '报表查询', 'businessReport', '', 12, '', None),
}
EXPECTED_TOP_LEVEL_MENU_POSITIONS = {
121: ('基础资料维护', 0, 1),
122: ('业务管理', 0, 2),
123: ('报表查询', 0, 3),
1: ('系统管理', 0, 4),
2: ('系统监控', 0, 5),
3: ('系统工具', 0, 6),
}
MENU_PROMOTION_IDS = set(EXPECTED_TOP_LEVEL_MENU_POSITIONS)
BUSINESS_MENU_IDS = set(range(121, 124)) | set(range(502, 519)) | set(range(1065, 1109)) BUSINESS_MENU_IDS = set(range(121, 124)) | set(range(502, 519)) | set(range(1065, 1109))
MYSQL_MENU_STABLE_COLUMNS = ( MYSQL_MENU_STABLE_COLUMNS = (
'menu_name', 'menu_name',
@@ -842,16 +857,24 @@ def _is_postgres_naive_timestamp_with_default_precision(definition: str) -> bool
) )
def _business_menu_rows(sql: str) -> dict[int, list]: def _menu_rows(sql: str, menu_ids: set[int]) -> dict[int, list]:
rows = _insert_rows(sql, 'sys_menu') rows = _insert_rows(sql, 'sys_menu')
selected = [row for row in rows if row and str(row[0]).isdigit() and int(row[0]) in BUSINESS_MENU_IDS] selected = [row for row in rows if row and str(row[0]).isdigit() and int(row[0]) in menu_ids]
counts = {menu_id: sum(int(row[0]) == menu_id for row in selected) for menu_id in BUSINESS_MENU_IDS} counts = {menu_id: sum(int(row[0]) == menu_id for row in selected) for menu_id in menu_ids}
if set(counts) != BUSINESS_MENU_IDS or any(count != 1 for count in counts.values()): if set(counts) != menu_ids or any(count != 1 for count in counts.values()):
raise AssertionError(f'business menu row counts differ: {counts}') raise AssertionError(f'menu row counts differ: {counts}')
return {int(row[0]): row for row in selected} return {int(row[0]): row for row in selected}
def _assert_business_menu_fields(test_case: unittest.TestCase, sql: str) -> None: def _business_menu_rows(sql: str) -> dict[int, list]:
return _menu_rows(sql, BUSINESS_MENU_IDS)
def _assert_business_menu_fields(
test_case: unittest.TestCase,
sql: str,
expected_fields: dict[int, tuple] = EXPECTED_BUSINESS_MENU_FIELDS,
) -> None:
rows = _business_menu_rows(sql) rows = _business_menu_rows(sql)
invalid_widths = {menu_id: len(row) for menu_id, row in rows.items() if len(row) != SYS_MENU_VALUE_COUNT} invalid_widths = {menu_id: len(row) for menu_id, row in rows.items() if len(row) != SYS_MENU_VALUE_COUNT}
test_case.assertEqual({}, invalid_widths) test_case.assertEqual({}, invalid_widths)
@@ -867,7 +890,7 @@ def _assert_business_menu_fields(test_case: unittest.TestCase, sql: str) -> None
) )
for menu_id, row in rows.items() for menu_id, row in rows.items()
} }
test_case.assertEqual(EXPECTED_BUSINESS_MENU_FIELDS, actual) test_case.assertEqual(expected_fields, actual)
def _assert_business_permission_inventory(test_case: unittest.TestCase, sql: str) -> None: def _assert_business_permission_inventory(test_case: unittest.TestCase, sql: str) -> None:
@@ -944,15 +967,15 @@ class SqlContractTest(unittest.TestCase):
rows = _business_menu_rows(sql) rows = _business_menu_rows(sql)
self.assertTrue(all(len(row) == SYS_MENU_VALUE_COUNT for row in rows.values())) self.assertTrue(all(len(row) == SYS_MENU_VALUE_COUNT for row in rows.values()))
self.assertEqual( self.assertEqual(
('基础资料维护', '1', '10', 'businessMaster', 'M', ''), ('基础资料维护', '0', '1', 'businessMaster', 'M', ''),
tuple(rows[121][index] for index in (1, 2, 3, 4, 10, 13)), tuple(rows[121][index] for index in (1, 2, 3, 4, 10, 13)),
) )
self.assertEqual( self.assertEqual(
('业务管理', '1', '11', 'businessOperation', 'M', ''), ('业务管理', '0', '2', 'businessOperation', 'M', ''),
tuple(rows[122][index] for index in (1, 2, 3, 4, 10, 13)), tuple(rows[122][index] for index in (1, 2, 3, 4, 10, 13)),
) )
self.assertEqual( self.assertEqual(
('报表查询', '1', '12', 'businessReport', 'M', ''), ('报表查询', '0', '3', 'businessReport', 'M', ''),
tuple(rows[123][index] for index in (1, 2, 3, 4, 10, 13)), tuple(rows[123][index] for index in (1, 2, 3, 4, 10, 13)),
) )
for menu_id in (121, 122, 123): for menu_id in (121, 122, 123):
@@ -975,6 +998,14 @@ class SqlContractTest(unittest.TestCase):
tuple(row[index] for index in (4, 5, 6, 7, 8, 9, 10, 11, 12)), tuple(row[index] for index in (4, 5, 6, 7, 8, 9, 10, 11, 12)),
) )
def test_initializers_define_expected_top_level_menu_order(self) -> None:
for filename in INITIALIZERS:
with self.subTest(filename=filename):
sql = (SQL_ROOT / filename).read_text(encoding='utf-8')
rows = _menu_rows(sql, MENU_PROMOTION_IDS)
actual = {menu_id: (row[1], int(row[2]), int(row[3])) for menu_id, row in rows.items()}
self.assertEqual(EXPECTED_TOP_LEVEL_MENU_POSITIONS, actual)
def test_business_permission_inventory_rejects_duplicate_permission(self) -> None: def test_business_permission_inventory_rejects_duplicate_permission(self) -> None:
sql = (SQL_ROOT / INITIALIZERS[0]).read_text(encoding='utf-8') sql = (SQL_ROOT / INITIALIZERS[0]).read_text(encoding='utf-8')
sql += """ sql += """
@@ -1135,11 +1166,11 @@ class SqlContractTest(unittest.TestCase):
self.assertEqual(EXPECTED_UNIQUE_KEYS[table], unique_keys) self.assertEqual(EXPECTED_UNIQUE_KEYS[table], unique_keys)
self.assertEqual(EXPECTED_FOREIGN_KEYS[table], foreign_keys) self.assertEqual(EXPECTED_FOREIGN_KEYS[table], foreign_keys)
self.assertEqual(EXPECTED_CHECKS[table], checks) self.assertEqual(EXPECTED_CHECKS[table], checks)
_assert_business_menu_fields(self, raw) _assert_business_menu_fields(self, raw, LEGACY_PATCH_BUSINESS_MENU_FIELDS)
_assert_business_permission_inventory(self, raw) _assert_business_permission_inventory(self, raw)
patch_rows = _business_menu_rows(raw) patch_rows = _business_menu_rows(raw)
mysql_rows = _business_menu_rows((SQL_ROOT / 'shierfeng-fastapi.sql').read_text(encoding='utf-8')) mysql_rows = _business_menu_rows((SQL_ROOT / 'shierfeng-fastapi.sql').read_text(encoding='utf-8'))
compared_indexes = tuple(range(15)) compared_indexes = (0, 1, *range(4, 15))
self.assertEqual( self.assertEqual(
{menu_id: tuple(row[index] for index in compared_indexes) for menu_id, row in mysql_rows.items()}, {menu_id: tuple(row[index] for index in compared_indexes) for menu_id, row in mysql_rows.items()},
{menu_id: tuple(row[index] for index in compared_indexes) for menu_id, row in patch_rows.items()}, {menu_id: tuple(row[index] for index in compared_indexes) for menu_id, row in patch_rows.items()},