diff --git a/.gitignore b/.gitignore index 3e90094574b35fa7cd337afaec812c0ce05a4340..e906f4b3711649e9818020f536e1a2921e5e35a5 100644 --- a/.gitignore +++ b/.gitignore @@ -114,6 +114,10 @@ dmypy.json # Pyre type checker .pyre/ +# pipenv +.pipenv +.pipfile + # idea .idea/ diff --git a/applications/__init__.py b/applications/__init__.py index af5bb8e42654ca58101c80d7654ca961369e95c3..89651a14ef799e0f2c60a0363df4797a8d61a0a9 100644 --- a/applications/__init__.py +++ b/applications/__init__.py @@ -2,7 +2,7 @@ import os from flask import Flask from applications.common.script import init_script from applications.config import BaseConfig -from applications.extensions import init_plugs +from applications.extensions import init_plugs,init_template_func from applications.view import init_bps @@ -20,4 +20,7 @@ def create_app(): # 注册命令 init_script(app) + # 注册全局模板函数 + init_template_func(app) + return app diff --git a/applications/common/script/admin.py b/applications/common/script/admin.py index 35c9cffae456fa61b3f663bab30814a384fe7409..3bfe2a82c875dab1e6cc1dad43e072bf9c2347c6 100644 --- a/applications/common/script/admin.py +++ b/applications/common/script/admin.py @@ -1,9 +1,10 @@ -import datetime +import datetime,click from flask.cli import AppGroup from applications.extensions import db -from applications.models import User, Role, Dept, Power +from applications.models import User, Role, RoleGroup, Dept, Power + admin_cli = AppGroup("admin") @@ -51,6 +52,7 @@ roledata = [ enable=1, details='管理员', sort=1, + group_id="1", create_time=now_time, ), Role( @@ -60,8 +62,16 @@ roledata = [ enable=1, details='只有查看,没有增删改权限', sort=2, + group_id="1", create_time=now_time, + ), + RoleGroup( + id=1, + name="默认分组", + sort=1, + create_time =now_time, ) + ] deptdata = [ Dept( @@ -556,6 +566,14 @@ def add_role_power(): db.session.commit() + +@admin_cli.command("drop") +def init_db(): + click.confirm('此操作或删除所有数据表,确认继续?', abort=True) + db.drop_all() + click.echo('数据表删除完毕') + + @admin_cli.command("init") def init_db(): db.session.add_all(userdata) diff --git a/applications/common/utils/http.py b/applications/common/utils/http.py index 680df5fc336e3a1895816ef2d7f24a79a9cca291..b2e740a5ecba7c7b42e1405393b2bc855b923029 100644 --- a/applications/common/utils/http.py +++ b/applications/common/utils/http.py @@ -22,3 +22,12 @@ def table_api(msg: str = "", count=0, data=None, limit=10): } return jsonify(res) + +def data_api(msg: str = "成功", data=None, success=True ): + """ 动态数据渲染响应 """ + res = { + 'msg': msg, + 'data': data, + "success": success + } + return jsonify(res) diff --git a/applications/config.py b/applications/config.py index ed79ce14a028a78d00e2a4ef98a9561c41eebd8c..e82f44acd80566ea6dc924caa595a77021afa90a 100644 --- a/applications/config.py +++ b/applications/config.py @@ -1,5 +1,5 @@ import logging -# from urllib.parse import quote_plus as urlquote +from urllib.parse import quote_plus as urlquote class BaseConfig: @@ -35,15 +35,15 @@ class BaseConfig: SECRET_KEY = "pear-system-flask" # mysql 配置 - # MYSQL_USERNAME = "root" - # MYSQL_PASSWORD = "123456" - # MYSQL_HOST = "127.0.0.1" - # MYSQL_PORT = 3306 - # MYSQL_DATABASE = "PearAdminFlask" + MYSQL_USERNAME = "root" + MYSQL_PASSWORD = "Yp2231610" + MYSQL_HOST = "127.0.0.1" + MYSQL_PORT = 3306 + MYSQL_DATABASE = "PearAdminFlask1" # 数据库的配置信息 - SQLALCHEMY_DATABASE_URI = 'sqlite:///../pear.db' - # SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{urlquote(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}?charset=utf8mb4" + # SQLALCHEMY_DATABASE_URI = 'sqlite:///../pear.db' + SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{urlquote(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}?charset=utf8mb4" # 默认日志等级 LOG_LEVEL = logging.WARN diff --git a/applications/extensions/__init__.py b/applications/extensions/__init__.py index 7a1a3788039c74513bafa1c1e5b306d62197c3d9..18418d280bc04fbe0124660510cc626c62694f46 100644 --- a/applications/extensions/__init__.py +++ b/applications/extensions/__init__.py @@ -7,7 +7,7 @@ from .init_error_views import init_error_views from .init_mail import init_mail, mail as flask_mail from .init_upload import init_upload from .init_migrate import init_migrate - +from .init_template_func import init_template_func def init_plugs(app: Flask) -> None: init_login_manager(app) @@ -16,4 +16,5 @@ def init_plugs(app: Flask) -> None: init_error_views(app) init_mail(app) init_upload(app) - init_migrate(app) \ No newline at end of file + init_migrate(app) + init_template_func(app) \ No newline at end of file diff --git a/applications/extensions/init_template_func.py b/applications/extensions/init_template_func.py new file mode 100644 index 0000000000000000000000000000000000000000..2979d8bdbc90a251525accf08f97b8e4ff24ea30 --- /dev/null +++ b/applications/extensions/init_template_func.py @@ -0,0 +1,47 @@ +from datetime import datetime +import datetime as datetimeO +def init(app): + @app.template_global() + def getDatetimeSplit(d): + if d: + dt=datetime.strptime(d,"%Y-%m-%dT%H:%M:%S") + return [dt.year,dt.month,dt.day,dt.hour,dt.minute,dt.second] + else: + return None + @app.template_global() + def getDateSplit(d): + if d: + dt=datetime.strptime(d,"%Y-%m-%d") + return [dt.year,dt.month,dt.day] + else: + return None + @app.template_global() + def _len(d): + return len(d) + @app.template_global() + def _toString(d): + return str(d) + @app.template_global() + def _enumerate(d): + return enumerate(d) + @app.template_global() + def _strftime(d,formatStr='%Y-%m-%d'): + if "T" in d : + dt = datetime.strptime(d, "%Y-%m-%dT%H:%M:%S") + else: + dt=datetime.strptime(d,"%Y-%m-%d") + return dt.strftime(formatStr) + + @app.template_global() + def _timedelta(d,days=0,hours=0,minutes=0,seconds=0,formatStr='%Y-%m-%d'): + dt= datetime.strptime(d,formatStr) + dt=dt+ datetimeO.timedelta(days=days,hours=hours,minutes=minutes,seconds=seconds) + return datetime.strftime(dt,formatStr) + + @app.template_global() + def _round(n,d): + return round(n,d) + + +def init_template_func(app): + init(app) diff --git a/applications/models/__init__.py b/applications/models/__init__.py index d94b26539de13d4ef34542987f64fd1d72d236a3..fdd3713dd83de964015ff6f10778456cf91f71c9 100644 --- a/applications/models/__init__.py +++ b/applications/models/__init__.py @@ -3,7 +3,7 @@ from .admin_dict import DictType, DictData from .admin_log import AdminLog from .admin_photo import Photo from .admin_power import Power -from .admin_role import Role +from .admin_role import Role,RoleGroup from .admin_role_power import role_power from .admin_user import User from .admin_user_role import user_role diff --git a/applications/models/admin_role.py b/applications/models/admin_role.py index 718a5d2929a592229afcf34647129959f221b3f8..b880031ebf55b6dc0c3b616b2c83437e67471021 100644 --- a/applications/models/admin_role.py +++ b/applications/models/admin_role.py @@ -14,3 +14,15 @@ class Role(db.Model): create_time = db.Column(db.DateTime, default=datetime.datetime.now, comment='创建时间') update_time = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='更新时间') power = db.relationship('Power', secondary="admin_role_power", backref=db.backref('role')) + group_id = db.Column(db.Integer, db.ForeignKey('admin_role_group.id')) + group=db.relationship("RoleGroup", back_populates="roles") + +class RoleGroup(db.Model): + __tablename__ = 'admin_role_group' + id = db.Column(db.Integer, primary_key=True, comment='角色分组ID') + name = db.Column(db.String(255), comment='角色分组名称') + remark = db.Column(db.String(255), comment='备注') + sort = db.Column(db.Integer, comment='排序') + create_time = db.Column(db.DateTime, default=datetime.datetime.now, comment='创建时间') + update_time = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='更新时间') + roles = db.relationship('Role', back_populates="group") \ No newline at end of file diff --git a/applications/schemas/__init__.py b/applications/schemas/__init__.py index 56aa9d0b0aeb1964054bdee9d789753eef865c54..704cd382d5062eb5cb382d9e53649653e9244831 100644 --- a/applications/schemas/__init__.py +++ b/applications/schemas/__init__.py @@ -1,5 +1,5 @@ -from .admin_role import RoleOutSchema +from .admin_role import RoleOutSchema,RoleGroupSchema from .admin_power import PowerOutSchema, PowerOutSchema2 from .admin_dict import DictDataOutSchema, DictTypeOutSchema from .admin_dept import DeptSchema diff --git a/applications/schemas/admin_role.py b/applications/schemas/admin_role.py index bf6c819e3d4a2810d9c16baf5fbef3ea88f6fb52..04eaf5c75136bf23d2184eec7c296df535e58815 100644 --- a/applications/schemas/admin_role.py +++ b/applications/schemas/admin_role.py @@ -1,12 +1,37 @@ from flask_marshmallow.sqla import SQLAlchemyAutoSchema - +from applications.extensions import ma +from applications.extensions.init_sqlalchemy import db +from marshmallow import fields from applications.models import Role -class RoleOutSchema(SQLAlchemyAutoSchema): - class Meta: - model = Role # table = models.Album.__table__ - # include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理 - include_fk = True # 序列化阶段是否也一并返回主键 - # fields= ["id","name"] # 启动的字段列表 - # exclude = ["id","name"] # 排除字段列表 +# class RoleOutSchema(SQLAlchemyAutoSchema): + # class Meta: + # model = Role # table = models.Album.__table__ + # include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理 + # include_fk = True # 序列化阶段是否也一并返回主键 + # sqla_session=db.session + # # fields= ["id","name"] # 启动的字段列表 + # # exclude = ["id","name"] # 排除字段列表 + +class RoleOutSchema(ma.Schema): + id = fields.Integer() + name = fields.Str() + code = fields.Str() + enable=fields.Integer() + remark = fields.Str() + details = fields.Str() + sort = fields.Integer() + create_time = fields.DateTime() + update_time = fields.DateTime() + group=fields.Nested(lambda:RoleGroupSchema()) + +# 用户models的序列化类 +class RoleGroupSchema(ma.Schema): + id = fields.Integer() + name = fields.Str() + remark = fields.Str() + sort = fields.Integer() + create_time = fields.DateTime() + update_time = fields.DateTime() + # roles = fields.Nested(lambda: RoleOutSchema()) diff --git a/applications/view/system/role.py b/applications/view/system/role.py index 54b9f813a301f0ace90d6b6d507ead5cd7e22519..15cab534f2311399987778c3747956bc22a5857b 100644 --- a/applications/view/system/role.py +++ b/applications/view/system/role.py @@ -5,9 +5,10 @@ from applications.common.curd import model_to_dicts, enable_status, disable_stat from applications.common.utils.http import table_api, success_api, fail_api from applications.common.utils.rights import authorize from applications.common.utils.validate import str_escape +from sqlalchemy import func from applications.extensions import db -from applications.models import Role, Power, User -from applications.schemas import RoleOutSchema, PowerOutSchema2 +from applications.models import Role, RoleGroup, Power, User +from applications.schemas import RoleOutSchema, PowerOutSchema2,RoleGroupSchema bp = Blueprint('role', __name__, url_prefix='/role') @@ -37,7 +38,9 @@ def table(): @bp.get('/add') @authorize("system:role:add", log=True) def add(): - return render_template('system/role/add.html') + roleGroups=RoleGroup.query.order_by(RoleGroup.id.asc()).all() + selectDic=[{"name":roleGroup.name,"value":roleGroup.id} for roleGroup in roleGroups] + return render_template('system/role/add.html',selectDic=selectDic) # 角色增加 @@ -49,13 +52,15 @@ def save(): enable = str_escape(req.get("enable")) roleCode = str_escape(req.get("roleCode")) roleName = str_escape(req.get("roleName")) + groupId = str_escape(req.get("groupId")) sort = str_escape(req.get("sort")) role = Role( details=details, enable=enable, code=roleCode, name=roleName, - sort=sort + sort=sort, + group_id=groupId ) db.session.add(role) db.session.commit() @@ -114,8 +119,10 @@ def save_role_power(): @bp.get('/edit/') @authorize("system:role:edit", log=True) def edit(id): - r = get_one_by_id(model=Role, id=id) - return render_template('system/role/edit.html', role=r) + role = get_one_by_id(model=Role, id=id) + roleGroups=RoleGroup.query.order_by(RoleGroup.id.asc()).all() + selectDic=[{"name":roleGroup.name,"value":roleGroup.id} for roleGroup in roleGroups] + return render_template('system/role/edit.html', role=role,selectDic=selectDic) # 更新角色 @@ -178,3 +185,89 @@ def remove(id): if not r: return fail_api(msg="角色删除失败") return success_api(msg="角色删除成功") + + +# 角色分组管理 +@bp.get('/group') +@authorize("system:role:add", log=True) +def group(): + obj=RoleGroup.query.with_entities(func.max(RoleGroup.sort)).first() + if obj: + print(obj) + maxSort=obj[0]+1 + else: + maxSort=1 + return render_template('system/role/group.html',sort=maxSort) + +# 角色分组管理 +@bp.get('/group/data') +@authorize("system:role:add", log=True) +def groupData(): + roleGroups = RoleGroup.query.filter().layui_paginate() + return table_api(data=RoleGroupSchema(many=True).dump(roleGroups), count=roleGroups.total) + +# 角色分组编辑 +@bp.put('/group/update') +@authorize("system:role:edit", log=True) +def groupUpdate(): + req_json = request.get_json(force=True) + id = req_json.get("id") + + roleGroup=get_one_by_id(RoleGroup,id) + + if roleGroup.name=="默认分组": + return fail_api(msg="默认分组不允许修改") + data = { + "name": str_escape(req_json.get("name")), + "sort": str_escape(req_json.get("sort")), + "remark": str_escape(req_json.get("remark")) + } + print(req_json) + role = RoleGroup.query.filter_by(id=id).update(data) + db.session.commit() + if not role: + return fail_api(msg="更新角色分组失败") + return success_api(msg="更新角色分组成功") + + +# 角色分组增加 +@bp.post('/group/save') +@authorize("system:role:add", log=True) +def groupSave(): + req = request.get_json(force=True) + name = str_escape(req.get("name")) + sort = str_escape(req.get("sort")) + remark = str_escape(req.get("remark")) + + roleGroup = RoleGroup.query.filter_by(name="name").first() + if roleGroup: + return fail_api(msg="改分组名称已存在!") + + roleGroup = RoleGroup( + name=name, + sort=sort, + remark=remark, + ) + db.session.add(roleGroup) + db.session.commit() + return success_api(msg="成功") + +# 角色分组删除 +@bp.delete('/group/remove/') +@authorize("system:role:remove", log=True) +def groupRemove(id): + + roleGroup = RoleGroup.query.filter_by(id=id).first() + if roleGroup.name=="默认分组": + return fail_api(msg="默认分组不能删除!") + + roleGroupDefault = RoleGroup.query.filter_by(name="默认分组").first() + if len(roleGroup.roles)>0: + roleGroupDefault.roles=roleGroupDefault.roles+roleGroup.roles + r=RoleGroup.query.filter_by(id=id).delete() + db.session.commit() + if not r: + return fail_api(msg="角色分组删除失败") + return success_api(msg="角色分组删除成功") + + diff --git a/applications/view/system/user.py b/applications/view/system/user.py index e0f93458702e12f8e62ce987fc67f0560291acb0..bb556b1c5bf8f79d070a663cc72f2932ea59a018 100644 --- a/applications/view/system/user.py +++ b/applications/view/system/user.py @@ -8,7 +8,7 @@ from applications.common.utils.http import table_api, fail_api, success_api from applications.common.utils.rights import authorize from applications.common.utils.validate import str_escape from applications.extensions import db -from applications.models import Role, Dept +from applications.models import Role,RoleGroup,Dept from applications.models import User, AdminLog bp = Blueprint('user', __name__, url_prefix='/user') @@ -111,13 +111,15 @@ def delete(id): @authorize("system:user:edit", log=True) def edit(id): user = curd.get_one_by_id(User, id) - roles = Role.query.all() + + roles = Role.query.order_by(Role.group_id.asc()).all() checked_roles = [] for r in user.role: checked_roles.append(r.id) return render_template('system/user/edit.html', user=user, roles=roles, checked_roles=checked_roles) + # 编辑用户 @bp.put('/update') @authorize("system:user:edit", log=True) diff --git a/templates/macros/input.html b/templates/macros/input.html new file mode 100644 index 0000000000000000000000000000000000000000..1f4ca19ba89470527da70251b11b51e9c0d4aad4 --- /dev/null +++ b/templates/macros/input.html @@ -0,0 +1,15 @@ + +{#下拉列表 模板#} +{% macro selectField(name,selectDic,defaultKey,isRequire=False) %} + +{% endmacro %} + diff --git a/templates/system/role/add.html b/templates/system/role/add.html index 86c76df61d47ef735d0d77ca804e05758d22c8a1..2b7667455487e812a0235f12ef787aeec193d91a 100644 --- a/templates/system/role/add.html +++ b/templates/system/role/add.html @@ -1,3 +1,4 @@ +{%from "macros/input.html" import selectField%} @@ -22,6 +23,12 @@ class="layui-input"> +
+ +
+ {{selectField("groupId",selectDic,"默认分组",True)}} +
+
@@ -42,6 +49,8 @@
+ + diff --git a/templates/system/role/edit.html b/templates/system/role/edit.html index c8402845a649f2ba0a1fa77057c1198169912d8e..df5a95f1bb101534fc673ae67c6834ffbab35996 100644 --- a/templates/system/role/edit.html +++ b/templates/system/role/edit.html @@ -1,3 +1,4 @@ +{%from "macros/input.html" import selectField%} @@ -29,6 +30,12 @@ autocomplete="off" placeholder="请输入标题" class="layui-input"> +
+ +
+ {{selectField("groupId",selectDic,role.group.name,True)}} +
+
diff --git a/templates/system/role/group.html b/templates/system/role/group.html new file mode 100644 index 0000000000000000000000000000000000000000..d484e33f9686e5ddf9613469d664df6ef0dfcb30 --- /dev/null +++ b/templates/system/role/group.html @@ -0,0 +1,160 @@ + + + + 角色分组管理 + {% include 'system/common/header.html' %} + + + + +
+
+
+
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+
+
+
+
+ + + + + +{% include 'system/common/footer.html' %} + + + \ No newline at end of file diff --git a/templates/system/role/main.html b/templates/system/role/main.html index 850cecdb9a0f77e12ae2e769d90f1bc8de2d253c..6237260afde3e69779874b3d3abfc8e8df228f70 100644 --- a/templates/system/role/main.html +++ b/templates/system/role/main.html @@ -41,6 +41,11 @@ 新增 + + {% endif %} @@ -66,6 +71,10 @@ + + {% include 'system/common/footer.html' %}