重构 admin 初始化:改为 JSON 配置,增加导入导出功能
This commit is contained in:
+215
-561
@@ -1,575 +1,229 @@
|
||||
import click
|
||||
import json
|
||||
import datetime
|
||||
|
||||
import os
|
||||
from flask.cli import AppGroup
|
||||
|
||||
from applications.extensions import db
|
||||
from applications.models import User, Role, Dept, Power
|
||||
|
||||
admin_cli = AppGroup("admin")
|
||||
# 1. 定义命令组
|
||||
admin_cli = AppGroup("admin", help="系统数据管理:包括初始化、导入和导出")
|
||||
|
||||
now_time = datetime.datetime.now()
|
||||
userdata = [
|
||||
User(
|
||||
id=1,
|
||||
username='admin',
|
||||
password_hash='pbkdf2:sha256:150000$raM7mDSr$58fe069c3eac01531fc8af85e6fc200655dd2588090530084d182e6ec9d52c85',
|
||||
create_at=now_time,
|
||||
enable=1,
|
||||
realname='超级管理',
|
||||
remark='要是不能把握时机,就要终身蹭蹬,一事无成!',
|
||||
avatar='/static/system/admin/images/avatar.jpg',
|
||||
dept_id=1,
|
||||
),
|
||||
User(
|
||||
id=2,
|
||||
username='test',
|
||||
password_hash='pbkdf2:sha256:150000$cRS8bYNh$adb57e64d929863cf159f924f74d0634f1fecc46dba749f1bfaca03da6d2e3ac',
|
||||
create_at=now_time,
|
||||
enable=1,
|
||||
realname='测试',
|
||||
remark='要是不能把握时机,就要终身蹭蹬,一事无成!',
|
||||
avatar='/static/system/admin/images/avatar.jpg',
|
||||
dept_id=1,
|
||||
),
|
||||
User(
|
||||
id='3',
|
||||
username='wind',
|
||||
password_hash='pbkdf2:sha256:150000$skME1obT$6a2c20cd29f89d7d2f21d9e373a7e3445f70ebce3ef1c3a555e42a7d17170b37',
|
||||
create_at=now_time,
|
||||
enable=1,
|
||||
realname='风',
|
||||
remark='要是不能把握时机,就要终身蹭蹬,一事无成!',
|
||||
avatar='/static/system/admin/images/avatar.jpg',
|
||||
dept_id=7,
|
||||
),
|
||||
]
|
||||
roledata = [
|
||||
Role(
|
||||
id=1,
|
||||
code='admin',
|
||||
name='管理员',
|
||||
enable=1,
|
||||
details='管理员',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
),
|
||||
Role(
|
||||
id=2,
|
||||
code='common',
|
||||
name='普通用户',
|
||||
enable=1,
|
||||
details='只有查看,没有增删改权限',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
)
|
||||
]
|
||||
deptdata = [
|
||||
Dept(
|
||||
id=1,
|
||||
parent_id=0,
|
||||
dept_name='总公司',
|
||||
sort=1,
|
||||
leader='就眠仪式',
|
||||
phone='12312345679',
|
||||
email='123qq.com',
|
||||
status=1,
|
||||
remark='这是总公司',
|
||||
create_at=now_time
|
||||
),
|
||||
Dept(
|
||||
id=4,
|
||||
parent_id=1,
|
||||
dept_name='济南分公司',
|
||||
sort=2,
|
||||
leader='就眠仪式',
|
||||
phone='12312345679',
|
||||
email='123qq.com',
|
||||
status=1,
|
||||
remark='这是济南',
|
||||
create_at=now_time
|
||||
|
||||
),
|
||||
Dept(
|
||||
id=5,
|
||||
parent_id=1,
|
||||
dept_name='唐山分公司',
|
||||
sort=4,
|
||||
leader='mkg',
|
||||
phone='12312345679',
|
||||
email='123qq.com',
|
||||
status=1,
|
||||
remark='这是唐山',
|
||||
create_at=now_time
|
||||
|
||||
),
|
||||
Dept(
|
||||
id=7,
|
||||
parent_id=4,
|
||||
dept_name='济南分公司开发部',
|
||||
sort=5,
|
||||
leader='就眠仪式',
|
||||
phone='12312345679',
|
||||
email='123qq.com',
|
||||
status=1,
|
||||
remark='测试',
|
||||
create_at=now_time
|
||||
|
||||
),
|
||||
Dept(
|
||||
id=8,
|
||||
parent_id=5,
|
||||
dept_name='唐山测试部',
|
||||
sort=5,
|
||||
leader='mkg',
|
||||
phone='12312345679',
|
||||
email='123qq.com',
|
||||
status=1,
|
||||
remark='测试部',
|
||||
create_at=now_time
|
||||
|
||||
)
|
||||
]
|
||||
powerdata = [
|
||||
Power(
|
||||
id=1,
|
||||
name='系统管理',
|
||||
type='0',
|
||||
code='',
|
||||
url=None,
|
||||
open_type=None,
|
||||
parent_id='0',
|
||||
icon='layui-icon layui-icon-set-fill',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=3,
|
||||
name='用户管理',
|
||||
type='1',
|
||||
code='system:user:main',
|
||||
url='/system/user/',
|
||||
open_type='_iframe',
|
||||
parent_id='1',
|
||||
icon='layui-icon layui-icon layui-icon layui-icon layui-icon-rate',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=4,
|
||||
name='权限管理',
|
||||
type='1',
|
||||
code='system:power:main',
|
||||
url='/system/power/',
|
||||
open_type='_iframe',
|
||||
parent_id='1',
|
||||
icon=None,
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=9,
|
||||
name='角色管理',
|
||||
type='1',
|
||||
code='system:role:main',
|
||||
url='/system/role/',
|
||||
open_type='_iframe',
|
||||
parent_id='1',
|
||||
icon='layui-icon layui-icon-username',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=12,
|
||||
name='系统监控',
|
||||
type='1',
|
||||
code='system:monitor:main',
|
||||
url='/system/monitor/',
|
||||
open_type='_iframe',
|
||||
parent_id='1',
|
||||
icon='layui-icon layui-icon-vercode',
|
||||
sort=5,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=13,
|
||||
name='日志管理',
|
||||
type='1',
|
||||
code='system:log:main',
|
||||
url='/system/log/',
|
||||
open_type='_iframe',
|
||||
parent_id='1',
|
||||
icon='layui-icon layui-icon-read',
|
||||
sort=4,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=17,
|
||||
name='文件管理',
|
||||
type='0',
|
||||
code='',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='0',
|
||||
icon='layui-icon layui-icon-camera',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=18,
|
||||
name='图片上传',
|
||||
type='1',
|
||||
code='system:file:main',
|
||||
url='/system/file/',
|
||||
open_type='_iframe',
|
||||
parent_id='17',
|
||||
icon='layui-icon layui-icon-camera',
|
||||
sort=5,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=21,
|
||||
name='权限增加',
|
||||
type='2',
|
||||
code='system:power:add',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='4',
|
||||
icon='layui-icon layui-icon-add-circle',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=22,
|
||||
name='用户增加',
|
||||
type='2',
|
||||
code='system:user:add',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='3',
|
||||
icon='layui-icon layui-icon-add-circle',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=23,
|
||||
name='用户编辑',
|
||||
type='2',
|
||||
code='system:user:edit',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='3',
|
||||
icon='layui-icon layui-icon-rate',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=24,
|
||||
name='用户删除',
|
||||
type='2',
|
||||
code='system:user:remove',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='3',
|
||||
icon='',
|
||||
sort=3,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=25,
|
||||
name='权限编辑',
|
||||
type='2',
|
||||
code='system:power:edit',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='4',
|
||||
icon='',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=26,
|
||||
name='权限删除',
|
||||
type='2',
|
||||
code='system:power:remove',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='4',
|
||||
icon='',
|
||||
sort=3,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=27,
|
||||
name='用户增加',
|
||||
type='2',
|
||||
code='system:role:add',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='9',
|
||||
icon='',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=28,
|
||||
name='角色编辑',
|
||||
type='2',
|
||||
code='system:role:edit',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='9',
|
||||
icon='',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=29,
|
||||
name='角色删除',
|
||||
type='2',
|
||||
code='system:role:remove',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='9',
|
||||
icon='',
|
||||
sort=3,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=30,
|
||||
name='角色授权',
|
||||
type='2',
|
||||
code='system:role:power',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='9',
|
||||
icon='',
|
||||
sort=4,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=31,
|
||||
name='图片增加',
|
||||
type='2',
|
||||
code='system:file:add',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='18',
|
||||
icon='',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=32,
|
||||
name='图片删除',
|
||||
type='2',
|
||||
code='system:file:delete',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='18',
|
||||
icon='',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=44,
|
||||
name='数据字典',
|
||||
type='1',
|
||||
code='system:dict:main',
|
||||
url='/system/dict/',
|
||||
open_type='_iframe',
|
||||
parent_id='1',
|
||||
icon='layui-icon layui-icon-console',
|
||||
sort=6,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=45,
|
||||
name='字典增加',
|
||||
type='2',
|
||||
code='system:dict:add',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='44',
|
||||
icon='',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=46,
|
||||
name='字典修改',
|
||||
type='2',
|
||||
code='system:dict:edit',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='44',
|
||||
icon='',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=47,
|
||||
name='字典删除',
|
||||
type='2',
|
||||
code='system:dict:remove',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='44',
|
||||
icon='',
|
||||
sort=3,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=48,
|
||||
name='部门管理',
|
||||
type='1',
|
||||
code='system:dept:main',
|
||||
url='/system/dept/',
|
||||
open_type='_iframe',
|
||||
parent_id='1',
|
||||
icon='layui-icon layui-icon-group',
|
||||
sort=3,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=49,
|
||||
name='部门增加',
|
||||
type='2',
|
||||
code='system:dept:add',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='48',
|
||||
icon='',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=50,
|
||||
name='部门编辑',
|
||||
type='2',
|
||||
code='system:dept:edit',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='48',
|
||||
icon='',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=51,
|
||||
name='部门删除',
|
||||
type='2',
|
||||
code='system:dept:remove',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='48',
|
||||
icon='',
|
||||
sort=3,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=57,
|
||||
name='邮件管理',
|
||||
type='1',
|
||||
code='system:mail:main',
|
||||
url='/system/mail/',
|
||||
open_type='_iframe',
|
||||
parent_id='1',
|
||||
icon='layui-icon ',
|
||||
sort=7,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=58,
|
||||
name='邮件发送',
|
||||
type='2',
|
||||
code='system:mail:add',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='57',
|
||||
icon='layui-icon layui-icon-ok-circle',
|
||||
sort=1,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
), Power(
|
||||
id=59,
|
||||
name='邮件删除',
|
||||
type='2',
|
||||
code='system:mail:remove',
|
||||
url='',
|
||||
open_type='',
|
||||
parent_id='57',
|
||||
icon='',
|
||||
sort=2,
|
||||
create_time=now_time,
|
||||
enable=1,
|
||||
|
||||
)
|
||||
|
||||
]
|
||||
# 2. 定义数据存储的文件夹名称
|
||||
DATA_DIR = "app_data"
|
||||
|
||||
|
||||
def add_user_role():
|
||||
admin_role = Role.query.filter_by(id=1).first()
|
||||
admin_user = User.query.filter_by(id=1).first()
|
||||
admin_user.role.append(admin_role)
|
||||
test_role = Role.query.filter_by(id=2).first()
|
||||
test_user = User.query.filter_by(id=2).first()
|
||||
test_user.role.append(test_role)
|
||||
# --- 辅助工具类 ---
|
||||
class DateEncoder(json.JSONEncoder):
|
||||
def default(self, obj):
|
||||
if isinstance(obj, datetime.datetime):
|
||||
return obj.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
|
||||
def parse_time(item):
|
||||
"""辅助函数:尝试将字典中的时间字符串转换为 datetime 对象"""
|
||||
for k, v in item.items():
|
||||
if k in ['create_at', 'create_time', 'update_at'] and isinstance(v, str):
|
||||
try:
|
||||
item[k] = datetime.datetime.strptime(v, '%Y-%m-%d %H:%M:%S')
|
||||
except ValueError:
|
||||
pass
|
||||
return item
|
||||
|
||||
|
||||
def model_to_dict(obj):
|
||||
"""将 SQLAlchemy 模型对象转换为字典"""
|
||||
data = {}
|
||||
for c in obj.__table__.columns:
|
||||
val = getattr(obj, c.name)
|
||||
data[c.name] = val
|
||||
return data
|
||||
|
||||
|
||||
def ensure_dir_exists():
|
||||
"""
|
||||
确保数据文件夹存在。
|
||||
修改:路径基于当前脚本文件的位置,而不是执行命令的位置。
|
||||
"""
|
||||
# 获取当前脚本(admin_cli.py)所在的目录
|
||||
current_script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# 拼接得到 app_data 的绝对路径
|
||||
base_path = os.path.join(current_script_dir, DATA_DIR)
|
||||
|
||||
if not os.path.exists(base_path):
|
||||
os.makedirs(base_path)
|
||||
return base_path
|
||||
|
||||
|
||||
# --- 核心逻辑:导入数据 ---
|
||||
def import_logic(file_path, is_force):
|
||||
"""具体的导入逻辑封装"""
|
||||
if not os.path.exists(file_path):
|
||||
click.echo(f"错误: 找不到文件 {file_path}")
|
||||
return False
|
||||
|
||||
click.echo(f"正在读取文件: {file_path}")
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
raw_data = json.load(f)
|
||||
|
||||
if is_force:
|
||||
click.echo("警告: 正在清空旧数据...")
|
||||
try:
|
||||
db.session.query(User).delete()
|
||||
db.session.query(Role).delete()
|
||||
db.session.query(Power).delete()
|
||||
db.session.query(Dept).delete()
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
click.echo(f"清空数据失败: {str(e)}")
|
||||
return False
|
||||
|
||||
try:
|
||||
# 1. 导入部门
|
||||
count_dept = 0
|
||||
for item in raw_data.get("depts", []):
|
||||
item = parse_time(item)
|
||||
if not Dept.query.get(item['id']):
|
||||
db.session.add(Dept(**item))
|
||||
count_dept += 1
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def add_role_power():
|
||||
admin_powers = Power.query.filter(Power.id.in_([1, 3, 4, 9, 12, 13, 17, 18, 44, 48])).all()
|
||||
admin_user = Role.query.filter_by(id=2).first()
|
||||
for i in admin_powers:
|
||||
admin_user.power.append(i)
|
||||
# 2. 导入权限
|
||||
count_power = 0
|
||||
for item in raw_data.get("powers", []):
|
||||
item = parse_time(item)
|
||||
if not Power.query.get(item['id']):
|
||||
db.session.add(Power(**item))
|
||||
count_power += 1
|
||||
db.session.commit()
|
||||
|
||||
# 3. 导入角色
|
||||
count_role = 0
|
||||
for item in raw_data.get("roles", []):
|
||||
item = parse_time(item)
|
||||
power_ids = item.pop('power_ids', [])
|
||||
|
||||
@admin_cli.command("init")
|
||||
def init_db():
|
||||
db.session.add_all(userdata)
|
||||
print("加载系统必须用户数据")
|
||||
db.session.add_all(roledata)
|
||||
print("加载系统必须角色数据")
|
||||
db.session.add_all(deptdata)
|
||||
print("加载系统必须部门数据")
|
||||
db.session.add_all(powerdata)
|
||||
print("加载系统必须权限数据")
|
||||
role = Role.query.get(item['id'])
|
||||
if not role:
|
||||
role = Role(**item)
|
||||
db.session.add(role)
|
||||
count_role += 1
|
||||
|
||||
if power_ids:
|
||||
powers = Power.query.filter(Power.id.in_(power_ids)).all()
|
||||
role.power = powers
|
||||
db.session.commit()
|
||||
print("基础数据存入")
|
||||
add_user_role()
|
||||
print("用户角色数据存入")
|
||||
add_role_power()
|
||||
print("角色权限数据存入")
|
||||
print("数据初始化完成,请使用run脚本运行")
|
||||
|
||||
# 4. 导入用户
|
||||
count_user = 0
|
||||
for item in raw_data.get("users", []):
|
||||
item = parse_time(item)
|
||||
role_ids = item.pop('role_ids', [])
|
||||
|
||||
user = User.query.get(item['id'])
|
||||
if not user:
|
||||
user = User(**item)
|
||||
db.session.add(user)
|
||||
count_user += 1
|
||||
|
||||
if role_ids:
|
||||
roles = Role.query.filter(Role.id.in_(role_ids)).all()
|
||||
user.role = roles
|
||||
db.session.commit()
|
||||
|
||||
click.echo(f"导入成功! 新增: 部门{count_dept}, 权限{count_power}, 角色{count_role}, 用户{count_user}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
click.echo(f"导入失败,已回滚。错误信息: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
# --- 命令:init (系统初始化) ---
|
||||
@admin_cli.command("init", help="系统初始化:读取 app_data/init.json 并导入数据库")
|
||||
@click.option('--force', is_flag=True, help='是否强制清空旧数据再导入')
|
||||
def init_db(force):
|
||||
"""
|
||||
系统初始化命令。
|
||||
默认读取当前脚本同级目录下 app_data/init.json 文件。
|
||||
"""
|
||||
base_path = ensure_dir_exists()
|
||||
target_file = os.path.join(base_path, 'init.json')
|
||||
|
||||
if not os.path.exists(target_file):
|
||||
click.echo(f"错误:在 {base_path} 目录下未找到 init.json 文件。")
|
||||
click.echo(f"请先将基础数据文件放入该位置,或运行 export 生成。")
|
||||
return
|
||||
|
||||
import_logic(target_file, force)
|
||||
|
||||
|
||||
# --- 命令:export (导出) ---
|
||||
@admin_cli.command("export", help="导出数据:将数据库数据保存为 JSON 文件")
|
||||
@click.option('--name', default=None, help='指定导出文件名,不带后缀。如果不填则使用时间戳。')
|
||||
def export_data(name):
|
||||
"""
|
||||
导出数据到当前脚本同级目录下的 app_data 文件夹。
|
||||
"""
|
||||
base_path = ensure_dir_exists()
|
||||
|
||||
if name:
|
||||
filename = f"{name}.json"
|
||||
else:
|
||||
now_str = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
filename = f"data_{now_str}.json"
|
||||
|
||||
file_path = os.path.join(base_path, filename)
|
||||
click.echo(f"准备导出数据到: {file_path} ...")
|
||||
|
||||
data = {
|
||||
"depts": [],
|
||||
"powers": [],
|
||||
"roles": [],
|
||||
"users": []
|
||||
}
|
||||
|
||||
# 1. 导出部门
|
||||
data["depts"] = [model_to_dict(d) for d in Dept.query.order_by(Dept.id).all()]
|
||||
# 2. 导出权限
|
||||
data["powers"] = [model_to_dict(p) for p in Power.query.order_by(Power.id).all()]
|
||||
# 3. 导出角色
|
||||
roles = Role.query.order_by(Role.id).all()
|
||||
for r in roles:
|
||||
r_dict = model_to_dict(r)
|
||||
r_dict['power_ids'] = [p.id for p in r.power]
|
||||
data["roles"].append(r_dict)
|
||||
# 4. 导出用户
|
||||
users = User.query.order_by(User.id).all()
|
||||
for u in users:
|
||||
u_dict = model_to_dict(u)
|
||||
u_dict['role_ids'] = [r.id for r in u.role]
|
||||
data["users"].append(u_dict)
|
||||
|
||||
try:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, cls=DateEncoder, ensure_ascii=False, indent=4)
|
||||
click.echo(f"导出成功!")
|
||||
except Exception as e:
|
||||
click.echo(f"导出失败: {str(e)}")
|
||||
|
||||
|
||||
# --- 命令:import (指定文件导入) ---
|
||||
@admin_cli.command("import", help="导入数据:从指定的 JSON 文件恢复数据")
|
||||
@click.option('--file', required=True, help='要导入的文件名 (需包含路径或位于 app_data 下)')
|
||||
@click.option('--force', is_flag=True, help='是否强制清空旧数据')
|
||||
def import_data(file, force):
|
||||
"""
|
||||
从指定文件导入数据。
|
||||
"""
|
||||
# 如果用户只提供了文件名,没有路径,则假设在 app_data 目录下
|
||||
if not os.path.dirname(file):
|
||||
file_path = os.path.join(ensure_dir_exists(), file)
|
||||
else:
|
||||
file_path = file
|
||||
|
||||
import_logic(file_path, force)
|
||||
@@ -0,0 +1,529 @@
|
||||
{
|
||||
"depts": [
|
||||
{
|
||||
"id": 1,
|
||||
"parent_id": 0,
|
||||
"dept_name": "总公司",
|
||||
"sort": 1,
|
||||
"leader": "就眠仪式",
|
||||
"phone": "12312345679",
|
||||
"email": "123qq.com",
|
||||
"status": 1,
|
||||
"remark": "这是总公司",
|
||||
"create_at": "2023-01-01 10:00:00"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"parent_id": 1,
|
||||
"dept_name": "济南分公司",
|
||||
"sort": 2,
|
||||
"leader": "就眠仪式",
|
||||
"phone": "12312345679",
|
||||
"email": "123qq.com",
|
||||
"status": 1,
|
||||
"remark": "这是济南",
|
||||
"create_at": "2023-01-01 10:00:00"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"parent_id": 1,
|
||||
"dept_name": "唐山分公司",
|
||||
"sort": 4,
|
||||
"leader": "mkg",
|
||||
"phone": "12312345679",
|
||||
"email": "123qq.com",
|
||||
"status": 1,
|
||||
"remark": "这是唐山",
|
||||
"create_at": "2023-01-01 10:00:00"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"parent_id": 4,
|
||||
"dept_name": "济南分公司开发部",
|
||||
"sort": 5,
|
||||
"leader": "就眠仪式",
|
||||
"phone": "12312345679",
|
||||
"email": "123qq.com",
|
||||
"status": 1,
|
||||
"remark": "测试",
|
||||
"create_at": "2023-01-01 10:00:00"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"parent_id": 5,
|
||||
"dept_name": "唐山测试部",
|
||||
"sort": 5,
|
||||
"leader": "mkg",
|
||||
"phone": "12312345679",
|
||||
"email": "123qq.com",
|
||||
"status": 1,
|
||||
"remark": "测试部",
|
||||
"create_at": "2023-01-01 10:00:00"
|
||||
}
|
||||
],
|
||||
"powers": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "系统管理",
|
||||
"type": "0",
|
||||
"code": "",
|
||||
"url": null,
|
||||
"open_type": null,
|
||||
"parent_id": "0",
|
||||
"icon": "layui-icon layui-icon-set-fill",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "用户管理",
|
||||
"type": "1",
|
||||
"code": "system:user:main",
|
||||
"url": "/system/user/",
|
||||
"open_type": "_iframe",
|
||||
"parent_id": "1",
|
||||
"icon": "layui-icon layui-icon layui-icon layui-icon layui-icon-rate",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "权限管理",
|
||||
"type": "1",
|
||||
"code": "system:power:main",
|
||||
"url": "/system/power/",
|
||||
"open_type": "_iframe",
|
||||
"parent_id": "1",
|
||||
"icon": null,
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "角色管理",
|
||||
"type": "1",
|
||||
"code": "system:role:main",
|
||||
"url": "/system/role/",
|
||||
"open_type": "_iframe",
|
||||
"parent_id": "1",
|
||||
"icon": "layui-icon layui-icon-username",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "系统监控",
|
||||
"type": "1",
|
||||
"code": "system:monitor:main",
|
||||
"url": "/system/monitor/",
|
||||
"open_type": "_iframe",
|
||||
"parent_id": "1",
|
||||
"icon": "layui-icon layui-icon-vercode",
|
||||
"sort": 5,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "日志管理",
|
||||
"type": "1",
|
||||
"code": "system:log:main",
|
||||
"url": "/system/log/",
|
||||
"open_type": "_iframe",
|
||||
"parent_id": "1",
|
||||
"icon": "layui-icon layui-icon-read",
|
||||
"sort": 4,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"name": "文件管理",
|
||||
"type": "0",
|
||||
"code": "",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "0",
|
||||
"icon": "layui-icon layui-icon-camera",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"name": "图片上传",
|
||||
"type": "1",
|
||||
"code": "system:file:main",
|
||||
"url": "/system/file/",
|
||||
"open_type": "_iframe",
|
||||
"parent_id": "17",
|
||||
"icon": "layui-icon layui-icon-camera",
|
||||
"sort": 5,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"name": "权限增加",
|
||||
"type": "2",
|
||||
"code": "system:power:add",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "4",
|
||||
"icon": "layui-icon layui-icon-add-circle",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"name": "用户增加",
|
||||
"type": "2",
|
||||
"code": "system:user:add",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "3",
|
||||
"icon": "layui-icon layui-icon-add-circle",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 23,
|
||||
"name": "用户编辑",
|
||||
"type": "2",
|
||||
"code": "system:user:edit",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "3",
|
||||
"icon": "layui-icon layui-icon-rate",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 24,
|
||||
"name": "用户删除",
|
||||
"type": "2",
|
||||
"code": "system:user:remove",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "3",
|
||||
"icon": "",
|
||||
"sort": 3,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"name": "权限编辑",
|
||||
"type": "2",
|
||||
"code": "system:power:edit",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "4",
|
||||
"icon": "",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 26,
|
||||
"name": "权限删除",
|
||||
"type": "2",
|
||||
"code": "system:power:remove",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "4",
|
||||
"icon": "",
|
||||
"sort": 3,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 27,
|
||||
"name": "用户增加",
|
||||
"type": "2",
|
||||
"code": "system:role:add",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "9",
|
||||
"icon": "",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 28,
|
||||
"name": "角色编辑",
|
||||
"type": "2",
|
||||
"code": "system:role:edit",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "9",
|
||||
"icon": "",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 29,
|
||||
"name": "角色删除",
|
||||
"type": "2",
|
||||
"code": "system:role:remove",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "9",
|
||||
"icon": "",
|
||||
"sort": 3,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"name": "角色授权",
|
||||
"type": "2",
|
||||
"code": "system:role:power",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "9",
|
||||
"icon": "",
|
||||
"sort": 4,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 31,
|
||||
"name": "图片增加",
|
||||
"type": "2",
|
||||
"code": "system:file:add",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "18",
|
||||
"icon": "",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 32,
|
||||
"name": "图片删除",
|
||||
"type": "2",
|
||||
"code": "system:file:delete",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "18",
|
||||
"icon": "",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 44,
|
||||
"name": "数据字典",
|
||||
"type": "1",
|
||||
"code": "system:dict:main",
|
||||
"url": "/system/dict/",
|
||||
"open_type": "_iframe",
|
||||
"parent_id": "1",
|
||||
"icon": "layui-icon layui-icon-console",
|
||||
"sort": 6,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 45,
|
||||
"name": "字典增加",
|
||||
"type": "2",
|
||||
"code": "system:dict:add",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "44",
|
||||
"icon": "",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 46,
|
||||
"name": "字典修改",
|
||||
"type": "2",
|
||||
"code": "system:dict:edit",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "44",
|
||||
"icon": "",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 47,
|
||||
"name": "字典删除",
|
||||
"type": "2",
|
||||
"code": "system:dict:remove",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "44",
|
||||
"icon": "",
|
||||
"sort": 3,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 48,
|
||||
"name": "部门管理",
|
||||
"type": "1",
|
||||
"code": "system:dept:main",
|
||||
"url": "/system/dept/",
|
||||
"open_type": "_iframe",
|
||||
"parent_id": "1",
|
||||
"icon": "layui-icon layui-icon-group",
|
||||
"sort": 3,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 49,
|
||||
"name": "部门增加",
|
||||
"type": "2",
|
||||
"code": "system:dept:add",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "48",
|
||||
"icon": "",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 50,
|
||||
"name": "部门编辑",
|
||||
"type": "2",
|
||||
"code": "system:dept:edit",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "48",
|
||||
"icon": "",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 51,
|
||||
"name": "部门删除",
|
||||
"type": "2",
|
||||
"code": "system:dept:remove",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "48",
|
||||
"icon": "",
|
||||
"sort": 3,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 57,
|
||||
"name": "邮件管理",
|
||||
"type": "1",
|
||||
"code": "system:mail:main",
|
||||
"url": "/system/mail/",
|
||||
"open_type": "_iframe",
|
||||
"parent_id": "1",
|
||||
"icon": "layui-icon ",
|
||||
"sort": 7,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 58,
|
||||
"name": "邮件发送",
|
||||
"type": "2",
|
||||
"code": "system:mail:add",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "57",
|
||||
"icon": "layui-icon layui-icon-ok-circle",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
},
|
||||
{
|
||||
"id": 59,
|
||||
"name": "邮件删除",
|
||||
"type": "2",
|
||||
"code": "system:mail:remove",
|
||||
"url": "",
|
||||
"open_type": "",
|
||||
"parent_id": "57",
|
||||
"icon": "",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"enable": 1
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
{
|
||||
"id": 1,
|
||||
"code": "admin",
|
||||
"name": "管理员",
|
||||
"enable": 1,
|
||||
"details": "管理员",
|
||||
"sort": 1,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"power_ids": []
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"code": "common",
|
||||
"name": "普通用户",
|
||||
"enable": 1,
|
||||
"details": "只有查看,没有增删改权限",
|
||||
"sort": 2,
|
||||
"create_time": "2023-01-01 10:00:00",
|
||||
"power_ids": [1, 3, 4, 9, 12, 13, 17, 18, 44, 48]
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"password_hash": "pbkdf2:sha256:150000$raM7mDSr$58fe069c3eac01531fc8af85e6fc200655dd2588090530084d182e6ec9d52c85",
|
||||
"create_at": "2023-01-01 10:00:00",
|
||||
"enable": 1,
|
||||
"realname": "超级管理",
|
||||
"remark": "要是不能把握时机,就要终身蹭蹬,一事无成!",
|
||||
"avatar": "/static/system/admin/images/avatar.jpg",
|
||||
"dept_id": 1,
|
||||
"role_ids": [1]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"username": "test",
|
||||
"password_hash": "pbkdf2:sha256:150000$cRS8bYNh$adb57e64d929863cf159f924f74d0634f1fecc46dba749f1bfaca03da6d2e3ac",
|
||||
"create_at": "2023-01-01 10:00:00",
|
||||
"enable": 1,
|
||||
"realname": "测试",
|
||||
"remark": "要是不能把握时机,就要终身蹭蹬,一事无成!",
|
||||
"avatar": "/static/system/admin/images/avatar.jpg",
|
||||
"dept_id": 1,
|
||||
"role_ids": [2]
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"username": "wind",
|
||||
"password_hash": "pbkdf2:sha256:150000$skME1obT$6a2c20cd29f89d7d2f21d9e373a7e3445f70ebce3ef1c3a555e42a7d17170b37",
|
||||
"create_at": "2023-01-01 10:00:00",
|
||||
"enable": 1,
|
||||
"realname": "风",
|
||||
"remark": "要是不能把握时机,就要终身蹭蹬,一事无成!",
|
||||
"avatar": "/static/system/admin/images/avatar.jpg",
|
||||
"dept_id": 7,
|
||||
"role_ids": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user