- 移除所有废弃的旧首页配置模块,包括destinationHero、demand相关、HomeExperience、vehicleService等表结构与代码,新增数据库迁移删除遗留表 - 重构管理端后台布局为标准RuoYi风格,新增Sidebar、Navbar、SettingsDrawer等组件,替换旧的过渡菜单实现 - 调整移动端响应断点为768px,更新布局相关测试用例,新增布局组件测试 - 删除OperationsTools发布/重置页面,移除/tools菜单入口,清理对应的API调用与测试代码 - 重构玩法模块编辑器:替换旧的图片手动输入框为图片上传组件,移除冗余的取消按钮 - 新增线索查询offset参数支持,完善查询参数处理逻辑 - 优化rbac菜单构建逻辑,新增可见性控制参数 - 修正管家编辑器提示文案,优化系统资源编辑器表单初始化逻辑 - 清理小程序端废弃的体验推荐组件与相关测试代码 - 更新文档与种子脚本,匹配新的API契约与使用说明
97 lines
3.0 KiB
Python
97 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from sqlalchemy import delete, select
|
|
from sqlalchemy.orm import Session
|
|
from .auth import hash_password
|
|
from .content import HERO_SLIDES, VEHICLE_OPTIONS
|
|
from .database import Base, SessionLocal, engine
|
|
from .models import (
|
|
AdminUser,
|
|
HeroSlide,
|
|
MediaAsset,
|
|
VehicleOption,
|
|
)
|
|
def create_media(db: Session, url: str | None, group: str, name: str | None = None) -> None:
|
|
if not url:
|
|
return
|
|
media = db.scalar(select(MediaAsset).where(MediaAsset.url == url))
|
|
if media is None:
|
|
media = next((item for item in db.new if isinstance(item, MediaAsset) and item.url == url), None)
|
|
if media:
|
|
media.group = group
|
|
media.name = name
|
|
else:
|
|
db.add(MediaAsset(url=url, group=group, name=name))
|
|
|
|
|
|
def seed_initial_content(db: Session) -> dict:
|
|
for model in [VehicleOption, HeroSlide, MediaAsset]:
|
|
db.execute(delete(model))
|
|
db.flush()
|
|
|
|
for index, slide in enumerate(HERO_SLIDES):
|
|
create_media(db, slide["image"], "hero", slide["title"])
|
|
db.add(
|
|
HeroSlide(
|
|
title=slide["title"],
|
|
kicker=slide["kicker"],
|
|
actionLabel=slide["action"],
|
|
image=slide["image"],
|
|
sortOrder=index,
|
|
)
|
|
)
|
|
|
|
for index, option in enumerate(VEHICLE_OPTIONS):
|
|
create_media(db, option["image"], "vehicle-option", option["title"])
|
|
db.add(
|
|
VehicleOption(
|
|
title=option["title"],
|
|
description=option.get("description"),
|
|
image=option.get("image"),
|
|
sortOrder=index,
|
|
)
|
|
)
|
|
|
|
return {
|
|
"heroSlides": len(HERO_SLIDES),
|
|
"vehicleOptions": len(VEHICLE_OPTIONS),
|
|
}
|
|
|
|
|
|
def seed_database(reset: bool) -> dict:
|
|
Base.metadata.create_all(bind=engine)
|
|
with SessionLocal() as db:
|
|
user = db.scalar(select(AdminUser).where(AdminUser.email == "admin@example.com"))
|
|
if user:
|
|
user.passwordHash = hash_password("ChangeMe123!")
|
|
user.isActive = True
|
|
user.name = "后台管理员"
|
|
user.role = "super_admin"
|
|
else:
|
|
db.add(
|
|
AdminUser(
|
|
email="admin@example.com",
|
|
name="后台管理员",
|
|
passwordHash=hash_password("ChangeMe123!"),
|
|
role="super_admin",
|
|
)
|
|
)
|
|
result = seed_initial_content(db) if reset else {"seeded": False}
|
|
db.commit()
|
|
return result
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="Seed WonderQ Admin database")
|
|
parser.add_argument("--no-reset", action="store_true", help="Only ensure admin user exists")
|
|
args = parser.parse_args()
|
|
result = seed_database(reset=not args.no_reset)
|
|
print(f"Seed complete. Admin login: admin@example.com / ChangeMe123!")
|
|
print(json.dumps(result, ensure_ascii=False))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|