""" 业务字典数据初始化脚本 ============================================================= 幂等写入业务字典(dict + dict_item):按字典编码(code)判重, 已存在则跳过、不覆盖现有数据;适合全新安装或现有库增量补齐。 字典格式(code/name/note/items),字典排序与字典项排序由列表顺序自动生成: DICT_SEED = [ { "code": "gender", "name": "性别", "note": "用户性别", "items": [ {"value": "1", "name": "男"}, {"value": "2", "name": "女"}, ], }, ] 注意:code 必须与业务代码中 get_dict_map / get_dict_label / serialize_maps 引用的编码一致(见 src/common/utils/dict_util.py),改 code 需同步改业务引用。 用法: python scripts/seed_dict.py # 使用 .env 中的数据库配置 python scripts/seed_dict.py --dry-run # 只打印将写入的字典,不落库 """ import argparse import os import sys sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src")) # Windows 控制台默认 GBK(cp936):把 stdout/stderr 切到 UTF-8,避免中文打印乱码/崩溃 if sys.stdout and hasattr(sys.stdout, 'reconfigure'): sys.stdout.reconfigure(encoding='utf-8') sys.stderr.reconfigure(encoding='utf-8') # 业务字典种子数据 DICT_SEED = [ { "code": "gender", "name": "性别", "note": "用户性别", "items": [ {"value": "1", "name": "男"}, {"value": "2", "name": "女"}, {"value": "3", "name": "保密"}, ], }, { "code": "dept_type", "name": "部门类型", "note": "部门层级类型", "items": [ {"value": "1", "name": "公司"}, {"value": "2", "name": "子公司"}, {"value": "3", "name": "部门"}, {"value": "4", "name": "小组"}, ], }, { "code": "article_status", "name": "文章状态", "note": "文章上下架状态", "items": [ {"value": "0", "name": "正常"}, {"value": "1", "name": "下架"}, ], }, { "code": "notice_source", "name": "通知来源", "note": "通知公告来源", "items": [ {"value": "1", "name": "官方平台"}, {"value": "2", "name": "开源中国"}, {"value": "3", "name": "CSDN官方"}, {"value": "4", "name": "新浪微博"}, ], }, { "code": "log_type", "name": "日志类型", "note": "登录日志类型", "items": [ {"value": "1", "name": "登录"}, {"value": "2", "name": "退出"}, ], }, { "code": "login_source", "name": "登录来源", "note": "登录入口来源", "items": [ {"value": "0", "name": "后台"}, {"value": "1", "name": "前台"}, ], }, { "code": "login_status", "name": "登录状态", "note": "登录日志状态", "items": [ {"value": "0", "name": "正常"}, {"value": "1", "name": "异常"}, ], }, { "code": "operation_source", "name": "操作日志来源", "note": "操作日志来源", "items": [ {"value": "0", "name": "后台"}, {"value": "1", "name": "前台"}, ], }, { "code": "operation_status", "name": "操作日志状态", "note": "操作日志状态", "items": [ {"value": "0", "name": "正常"}, {"value": "1", "name": "异常"}, ], }, { "code": "param_type", "name": "参数类型", "note": "参数分类", "items": [ {"value": "0", "name": "系统"}, {"value": "1", "name": "业务"}, ], }, { "code": "param_status", "name": "参数状态", "note": "参数启用状态", "items": [ {"value": "1", "name": "正常"}, {"value": "2", "name": "禁用"}, ], }, { "code": "job_status", "name": "任务状态", "note": "定时任务状态", "items": [ {"value": "0", "name": "未发布"}, {"value": "1", "name": "运行中"}, {"value": "2", "name": "暂停"}, {"value": "3", "name": "删除"}, ], }, { "code": "job_execute_policy", "name": "执行策略", "note": "任务失败执行策略", "items": [ {"value": "1", "name": "立即执行"}, {"value": "2", "name": "执行一次"}, {"value": "3", "name": "放弃执行"}, ], }, { "code": "job_log_status", "name": "任务日志状态", "note": "任务执行结果状态", "items": [ {"value": "0", "name": "正常"}, {"value": "1", "name": "失败"}, ], }, { "code": "link_type", "name": "友链类型", "note": "友链分类", "items": [ {"value": "1", "name": "友情链接"}, {"value": "2", "name": "合作伙伴"}, ], }, { "code": "link_platform", "name": "友链投放平台", "note": "友链投放平台", "items": [ {"value": "1", "name": "PC站"}, {"value": "2", "name": "WAP站"}, {"value": "3", "name": "微信小程序"}, {"value": "4", "name": "APP应用"}, ], }, { "code": "link_form", "name": "友链形式", "note": "友链展示形式", "items": [ {"value": "1", "name": "文字链接"}, {"value": "2", "name": "图片链接"}, ], }, { "code": "city_level", "name": "城市级别", "note": "行政区划级别", "items": [ {"value": "1", "name": "省份"}, {"value": "2", "name": "城市"}, {"value": "3", "name": "县区"}, {"value": "4", "name": "街道"}, ], }, { "code": "config_item_type", "name": "配置项类型", "note": "配置项输入控件类型", "items": [ {"value": "text", "name": "单行文本"}, {"value": "textarea", "name": "多行文本"}, {"value": "ueditor", "name": "富文本编辑器"}, {"value": "date", "name": "日期"}, {"value": "datetime", "name": "时间"}, {"value": "number", "name": "数字"}, {"value": "select", "name": "下拉框"}, {"value": "radio", "name": "单选框"}, {"value": "checkbox", "name": "复选框"}, {"value": "image", "name": "单张图片"}, {"value": "images", "name": "多张图片"}, {"value": "password", "name": "密码"}, {"value": "icon", "name": "字体图标"}, {"value": "file", "name": "单个文件"}, {"value": "files", "name": "多个文件"}, {"value": "hidden", "name": "隐藏"}, {"value": "readonly", "name": "只读文本"}, ], }, ] def main(): parser = argparse.ArgumentParser(description="初始化业务字典数据") parser.add_argument("--dry-run", action="store_true", help="仅打印计划,不写库") args = parser.parse_args() from core.database import SessionLocal from modules.dictionary.dict.models import Dict from modules.dictionary.dict_item.models import DictItem db = SessionLocal() added = skipped = 0 try: for idx, d in enumerate(DICT_SEED): code = d["code"] exists = db.query(Dict).filter(Dict.code == code, Dict.is_delete == 0).first() if exists: skipped += 1 continue if args.dry_run: print(f"[DRY-RUN] 将新增字典: {code}({d['name']},{len(d['items'])} 项)") continue dict_obj = Dict(name=d["name"], code=code, sort=(idx + 1) * 5, note=d.get("note", "")) db.add(dict_obj) db.flush() # 获取自增 id 供字典项外键引用 for i, item in enumerate(d["items"]): db.add(DictItem( name=item["name"], value=item["value"], dict_id=dict_obj.id, sort=(i + 1) * 5, note='', )) added += 1 db.commit() if not args.dry_run: print(f"done: added={added} dicts, skipped={skipped}(已存在)") except Exception: db.rollback() raise finally: db.close() if __name__ == "__main__": main()