From 03ef6c681a608c43b0c9054caa51478d88d58dbb Mon Sep 17 00:00:00 2001 From: losepure <651009587@qq,com> Date: Wed, 6 Sep 2023 21:38:26 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E4=B8=BA=E7=94=A8=E6=88=B7=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7=E7=BB=84=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E4=BB=A5=E4=BE=BF=E5=9C=A8=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E8=BE=83=E5=A4=9A=E6=97=B6=E6=9B=B4=E6=B8=85=E6=99=B0=E7=9A=84?= =?UTF-8?q?=E5=88=86=E7=B1=BB=E5=92=8C=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 + applications/__init__.py | 5 +- applications/common/script/admin.py | 22 ++- applications/common/utils/http.py | 9 + applications/config.py | 16 +- applications/extensions/__init__.py | 5 +- applications/extensions/init_template_func.py | 47 +++++ applications/models/__init__.py | 2 +- applications/models/admin_role.py | 12 ++ applications/schemas/__init__.py | 2 +- applications/schemas/admin_role.py | 41 ++++- applications/view/system/role.py | 105 +++++++++++- applications/view/system/user.py | 6 +- templates/macros/input.html | 15 ++ templates/system/role/add.html | 9 + templates/system/role/edit.html | 7 + templates/system/role/group.html | 160 ++++++++++++++++++ templates/system/role/main.html | 28 ++- templates/system/user/add.html | 27 ++- templates/system/user/edit.html | 23 ++- 20 files changed, 501 insertions(+), 44 deletions(-) create mode 100644 applications/extensions/init_template_func.py create mode 100644 templates/macros/input.html create mode 100644 templates/system/role/group.html diff --git a/.gitignore b/.gitignore index 3e90094..e906f4b 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 af5bb8e..89651a1 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 35c9cff..3bfe2a8 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 680df5f..b2e740a 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 ed79ce1..e82f44a 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 7a1a378..18418d2 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 0000000..2979d8b --- /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 d94b265..fdd3713 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 718a5d2..b880031 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 56aa9d0..704cd38 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 bf6c819..04eaf5c 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 54b9f81..15cab53 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 e0f9345..bb556b1 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 0000000..1f4ca19 --- /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 86c76df..2b76674 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 c840284..df5a95f 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 0000000..d484e33 --- /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 850cecd..6237260 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' %}