"""add cookie manager menus 「Cookie管理」一级菜单 + 二级「登录用户」/「登录网站」及各权限点, 此前只在本地库里手工 INSERT 过,从未随迁移分发。 由于 data/ 目录被 .gitignore 排除、部署环境数据库是独立 volume, 只同步代码无法带上这些菜单行,导致线上后台看不到 Cookie 管理模块。 本迁移以幂等方式补齐: - 记录不存在 → 插入 - 已存在但 open_type 为空 → 补齐为 _iframe(兼容早期手工插入的数据) 不依赖数据库方言的 UPSERT 语法,SQLite / MySQL 均可执行。 Revision ID: d4e5f6a7b8c9 Revises: b2c3d4e5f6a7 """ from alembic import op import sqlalchemy as sa import datetime # revision identifiers, used by Alembic. revision = 'd4e5f6a7b8c9' down_revision = 'b2c3d4e5f6a7' branch_labels = None depends_on = None # (id, name, type, code, url, open_type, parent_id, icon, sort, enable) MENUS = [ (76, 'Cookie管理', '0', '', '', '', 0, 'layui-icon layui-icon-ear-phone', 5, 1), (77, '登录用户', '1', 'system:cookie-user:main', '/system/cookie-user/', '_iframe', 76, 'layui-icon layui-icon-username', 1, 1), (78, '登录用户新增', '2', 'system:cookie-user:add', '', '', 77, '', 1, 1), (79, '登录用户编辑', '2', 'system:cookie-user:edit', '', '', 77, '', 2, 1), (80, '登录用户删除', '2', 'system:cookie-user:remove', '', '', 77, '', 3, 1), (81, '登录网站', '1', 'system:cookie-site:main', '/system/cookie-site/', '_iframe', 76, 'layui-icon layui-icon-web', 2, 1), (82, '登录网站新增', '2', 'system:cookie-site:add', '', '', 81, '', 1, 1), (83, '登录网站编辑', '2', 'system:cookie-site:edit', '', '', 81, '', 2, 1), (84, '登录网站删除', '2', 'system:cookie-site:remove', '', '', 81, '', 3, 1), ] def upgrade(): conn = op.get_bind() now = datetime.datetime.now() for mid, name, mtype, code, url, open_type, parent_id, icon, sort, enable in MENUS: row = conn.execute( sa.text("SELECT id, open_type FROM admin_power WHERE id = :id"), {"id": mid}, ).fetchone() if row is None: conn.execute( sa.text( "INSERT INTO admin_power " "(id, name, type, code, url, open_type, parent_id, icon, sort, " " enable, create_time, update_time) " "VALUES (:id, :name, :type, :code, :url, :open_type, :parent_id, " " :icon, :sort, :enable, :ct, :ut)" ), { "id": mid, "name": name, "type": mtype, "code": code, "url": url, "open_type": open_type, "parent_id": parent_id, "icon": icon, "sort": sort, "enable": enable, "ct": now, "ut": now, }, ) elif not row[1] and open_type: # 历史数据:菜单已存在但打开方式为空,补齐 _iframe conn.execute( sa.text("UPDATE admin_power SET open_type = :ot WHERE id = :id"), {"ot": open_type, "id": mid}, ) def downgrade(): conn = op.get_bind() ids = [m[0] for m in MENUS] # 先清角色-权限关联,避免外键/脏数据残留 conn.execute( sa.text("DELETE FROM admin_role_power WHERE power_id IN :ids").bindparams( sa.bindparam("ids", expanding=True) ), {"ids": ids}, ) conn.execute( sa.text("DELETE FROM admin_power WHERE id IN :ids").bindparams( sa.bindparam("ids", expanding=True) ), {"ids": ids}, )