upload project source code

This commit is contained in:
2026-04-30 18:49:43 +08:00
commit 9b394ba682
2277 changed files with 660945 additions and 0 deletions

View File

@@ -0,0 +1,250 @@
# -*- coding: utf-8 -*-
"""
一次性初始化:会员功能菜单(目录 + 页面菜单 + 按钮权限点)
推荐用法(在已配置好 env/.env.dev 或运行环境变量的情况下):
python -m app.scripts.init_yifan_membership_menus
该脚本是幂等的:重复执行会跳过已存在的菜单/按钮。
"""
from __future__ import annotations
import asyncio
import sqlalchemy as sa
from app.core.database import async_db_session
from app.api.v1.module_system.auth.schema import AuthSchema
from app.api.v1.module_system.menu.crud import MenuCRUD
from app.api.v1.module_system.menu.schema import MenuCreateSchema
from app.core.logger import log
# 关键:预先导入 RoleModel避免 MenuModel 关系解析失败
# MenuModel.roles -> "RoleModel"(字符串引用),若未导入会导致 mapper 初始化报错
from app.api.v1.module_system.role.model import RoleModel, RoleMenusModel # noqa: F401
from app.api.v1.module_system.position.model import PositionModel # noqa: F401
from app.api.v1.module_system.dept.model import DeptModel # noqa: F401
from app.api.v1.module_system.user.model import UserModel, UserRolesModel # noqa: F401
# 固定父节点(用户提供):壹梵后台管理
ROOT_PARENT_ID = 131
async def _create_if_not_exists(auth: AuthSchema, data: dict, *, unique_by: dict) -> int:
"""
幂等创建菜单:
- unique_by: 用于判重的字段(如 {"route_path": "/x", "type": 2} 或 {"permission": "...", "type": 3}
"""
crud = MenuCRUD(auth)
# 禁用默认预加载,避免在脚本上下文触发复杂关系初始化
exists = await crud.get(preload=[], **unique_by)
if exists:
return exists.id
created = await crud.create(data=MenuCreateSchema(**data))
return created.id
async def init_yifan_membership_menus(parent_id: int = ROOT_PARENT_ID) -> dict:
"""
初始化会员功能菜单(挂到 parent_id 下)。
返回创建结果的 id 汇总。
"""
async with async_db_session() as session:
async with session.begin():
# 0) 运行前检查sys_menu 是否存在(否则无法初始化菜单)
conn = await session.connection()
insp = sa.inspect(conn.sync_connection)
if not insp.has_table("sys_menu"):
raise RuntimeError(
"当前数据库缺少表 sys_menu无法初始化菜单。请先初始化数据库结构运行项目初始化/迁移脚本),"
"确保 sys_menu/sys_role/sys_user 等核心表已创建。"
)
auth = AuthSchema(db=session, check_data_scope=False, user=None)
# 1) 创建父目录会员功能type=1
membership_dir = {
"name": "yifan_membership",
"type": 1,
"icon": "menu",
"order": 10,
"permission": None,
"route_name": "YifanMembership",
"route_path": "/yifan/membership",
"component_path": None,
"redirect": "/yifan/membership/members",
"parent_id": parent_id,
"keep_alive": True,
"hidden": False,
"always_show": True,
"title": "会员功能",
"params": [],
"affix": False,
"status": "0",
"description": "脚本自动创建",
}
PARENT_ID = await _create_if_not_exists(
auth,
membership_dir,
unique_by={"route_path": "/yifan/membership", "type": 1},
)
# 2) 三个页面菜单type=2
discount_menu = {
"name": "yifan_membership_discount",
"type": 2,
"icon": "setting",
"order": 1,
"permission": "module_yifan:yifan_membership_discount:query",
"route_name": "YifanMembershipDiscount",
"route_path": "/yifan/membership/discount",
"component_path": "module_yifan/yifan_membership_discount/index",
"redirect": "",
"parent_id": PARENT_ID,
"keep_alive": True,
"hidden": False,
"always_show": False,
"title": "会员折扣设置",
"params": [],
"affix": False,
"status": "0",
"description": "脚本自动创建",
}
DISCOUNT_MENU_ID = await _create_if_not_exists(
auth,
discount_menu,
unique_by={"route_path": "/yifan/membership/discount", "type": 2},
)
member_menu = {
"name": "yifan_membership_member",
"type": 2,
"icon": "user",
"order": 2,
"permission": "module_yifan:yifan_membership_member:query",
"route_name": "YifanMembershipMember",
"route_path": "/yifan/membership/members",
"component_path": "module_yifan/yifan_membership_member/index",
"redirect": "",
"parent_id": PARENT_ID,
"keep_alive": True,
"hidden": False,
"always_show": False,
"title": "会员列表",
"params": [],
"affix": False,
"status": "0",
"description": "脚本自动创建",
}
MEMBER_MENU_ID = await _create_if_not_exists(
auth,
member_menu,
unique_by={"route_path": "/yifan/membership/members", "type": 2},
)
user_center_menu = {
"name": "yifan_membership_user_center",
"type": 2,
"icon": "user",
"order": 3,
"permission": "module_yifan:yifan_membership_user_center:query",
"route_name": "YifanMembershipUserCenter",
"route_path": "/yifan/membership/user-center",
"component_path": "module_yifan/yifan_membership_user_center/index",
"redirect": "",
"parent_id": PARENT_ID,
"keep_alive": True,
"hidden": False,
"always_show": False,
"title": "用户中心(会员权益)",
"params": [],
"affix": False,
"status": "0",
"description": "脚本自动创建",
}
USER_CENTER_MENU_ID = await _create_if_not_exists(
auth,
user_center_menu,
unique_by={"route_path": "/yifan/membership/user-center", "type": 2},
)
# 3) 按钮权限点type=3挂到对应页面菜单下
discount_btn = {
"name": "修改折扣",
"type": 3,
"icon": None,
"order": 1,
"permission": "module_yifan:yifan_membership_discount:update",
"route_name": None,
"route_path": None,
"component_path": None,
"redirect": "",
"parent_id": DISCOUNT_MENU_ID,
"keep_alive": False,
"hidden": True,
"always_show": False,
"title": "修改折扣",
"params": [],
"affix": False,
"status": "0",
"description": "脚本自动创建",
}
DISCOUNT_UPDATE_BTN_ID = await _create_if_not_exists(
auth,
discount_btn,
unique_by={"permission": "module_yifan:yifan_membership_discount:update", "type": 3},
)
quota_btn = {
"name": "名额调整",
"type": 3,
"icon": None,
"order": 1,
"permission": "module_yifan:yifan_membership_member:quota_adjust",
"route_name": None,
"route_path": None,
"component_path": None,
"redirect": "",
"parent_id": MEMBER_MENU_ID,
"keep_alive": False,
"hidden": True,
"always_show": False,
"title": "名额调整",
"params": [],
"affix": False,
"status": "0",
"description": "脚本自动创建",
}
MEMBER_QUOTA_BTN_ID = await _create_if_not_exists(
auth,
quota_btn,
unique_by={"permission": "module_yifan:yifan_membership_member:quota_adjust", "type": 3},
)
await session.commit()
return {
"parent_dir_id": PARENT_ID,
"discount_menu_id": DISCOUNT_MENU_ID,
"member_menu_id": MEMBER_MENU_ID,
"user_center_menu_id": USER_CENTER_MENU_ID,
"discount_update_button_id": DISCOUNT_UPDATE_BTN_ID,
"member_quota_adjust_button_id": MEMBER_QUOTA_BTN_ID,
}
async def _amain() -> None:
result = await init_yifan_membership_menus()
log.info(f"✅ 会员功能菜单初始化完成: {result}")
def main() -> None:
asyncio.run(_amain())
if __name__ == "__main__":
main()