diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 9c53772040050d34c20ea9ea6485bbd7208e3ca5..0000000000000000000000000000000000000000 Binary files a/.DS_Store and /dev/null differ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..23f5a477460a5d0bd42276f6531bb4b5e786c269 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Django-Vue3-Admin 更新日志 + +## 正式发布v3.0.0版本 +### 1.新增:列权限管理与授权; +### 2.新增:代码新版本发布后,进行升级提醒; +### 3.优化:角色管理中按钮权限的操作; +### 4.优化:websocket 连接状态显示; +### 5.优化:初始化获取系统配置与字典配置,进行动态渲染登录页面; +### 6.修复:登录页面中系统配置不生效问题; +### 7.其他优化 \ No newline at end of file diff --git a/README.en.md b/README.en.md index c1c742bfc9170de4ffa17c7f0ccc9523c98fe621..684b078eb1d213ab351f5ea0ba81337719db4d8c 100644 --- a/README.en.md +++ b/README.en.md @@ -1,14 +1,14 @@ # Django-Vue3-Admin -[![img](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitee.com/liqianglog/django-vue-admin/blob/master/LICENSE) [![img](https://img.shields.io/badge/python-%3E=3.7.x-green.svg)](https://python.org/) [![PyPI - Django Version badge](https://img.shields.io/badge/django%20versions-3.2-blue)](https://docs.djangoproject.com/zh-hans/3.2/) [![img](https://img.shields.io/badge/node-%3E%3D%2012.0.0-brightgreen)](https://nodejs.org/zh-cn/) [![img](https://gitee.com/liqianglog/django-vue-admin/badge/star.svg?theme=dark)](https://gitee.com/liqianglog/django-vue-admin) +[![img](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitee.com/huge-dream/django-vue3-admin/blob/master/LICENSE) [![img](https://img.shields.io/badge/python-%3E=3.7.x-green.svg)](https://python.org/) [![PyPI - Django Version badge](https://img.shields.io/badge/django%20versions-3.2-blue)](https://docs.djangoproject.com/zh-hans/3.2/) [![img](https://img.shields.io/badge/node-%3E%3D%2012.0.0-brightgreen)](https://nodejs.org/zh-cn/) [![img](https://gitee.com/huge-dream/django-vue3-admin/badge/star.svg?theme=dark)](https://gitee.com/huge-dream/django-vue3-admin) [preview](https://demo.dvadmin.com) | [Official website document](https://www.django-vue-admin.com) | [qq group](https://qm.qq.com/cgi-bin/qm/qr?k=fOdnHhC8DJlRHGYSnyhoB8P5rgogA6Vs&jump_from=webapi) | [community](https://bbs.django-vue-admin.com) | [plugins market](https://bbs.django-vue-admin.com/plugMarket.html) | [Github](https://github.com/liqianglog/django-vue-admin) 💡 **「About」** -We are a group of young people who love Code. In this hot era, we hope to calm down and bring some of our colors and colors through code. +It is a completely open-source rapid development platform, provided free for personal use and authorized for group use. +Django-Vue3-Admin is a comprehensive basic development platform based on the RBAC (Role-Based Access Control) model for permission control, with column-level granularity. It follows a frontend-backend separation architecture, with Django and Django Rest Framework used for the backend, and Vue3, Composition API, TypeScript, Vite, and Element Plus used for the frontend. -Because of love, so embrace the future ## framework introduction @@ -18,12 +18,13 @@ Because of love, so embrace the future * 👭The backend uses the Python language Django framework as well as the powerful[Django REST Framework](https://pypi.org/project/djangorestframework)。 * 👫Permission authentication use[Django REST Framework SimpleJWT](https://pypi.org/project/djangorestframework-simplejwt),Supports the multi-terminal authentication system. * 👬Support loading dynamic permission menu, multi - way easy permission control. -* 💏 Special thanks: [vue-next-admin](https://lyt-top.gitee.io/vue-next-admin-doc-preview/). -* 💡 💏 Special thanks:[jetbrains](https://www.jetbrains.com/) To provide a free IntelliJ IDEA license for this open source project. +* 👬Enhanced Column Permission Control, with granularity down to each column. +* 💏Special thanks: [vue-next-admin](https://lyt-top.gitee.io/vue-next-admin-doc-preview/). +* 💡Special thanks:[jetbrains](https://www.jetbrains.com/) To provide a free IntelliJ IDEA license for this open source project. ## Online experience -👩‍👧‍👦👩‍👧‍👦 demo address:[http://demo.django-vue-admin.com](http://demo.django-vue-admin.com) +👩‍👧‍👦👩‍👧‍👦 demo address:[https://demo.dvadmin.com](https://demo.dvadmin.com) * demo account:superadmin @@ -39,57 +40,61 @@ Because of love, so embrace the future ## source code url: -gitee(Main push):[https://gitee.com/liqianglog/django-vue-admin](https://gitee.com/liqianglog/django-vue-admin)👩‍👦‍👦 +gitee(Main push):[https://gitee.com/huge-dream/django-vue3-admin](https://gitee.com/huge-dream/django-vue3-admin)👩‍👦‍👦 -github:[https://github.com/liqianglog/django-vue-admin](https://github.com/liqianglog/django-vue-admin)👩‍👦‍👦 +github:[https://github.com/huge-dream/django-vue3-admin](https://github.com/huge-dream/django-vue3-admin)👩‍👦‍👦 ## core function -1. 👨‍⚕️ Menu management: Configure the system menu, operation permissions, button permissions, back-end interface permissions, etc. -2. 🧑‍⚕️ Department management: Configure the system organization (company, department, role). -3. 👩‍⚕️ Role management: role menu permission allocation, data permission allocation, set roles according to the department for data range permission division. -4. 🧑‍🎓 Rights Specifies the rights of the authorization role. -5. 👨‍🎓 User management: The user is the system operator, this function mainly completes the system user configuration. -6. 👬 Interface whitelist: specifies the interface that does not need permission verification. -7. 🧑‍🔧 Dictionary management: Maintenance of some fixed data frequently used in the system. -8. 🧑‍🔧 Regional management: to manage provinces, cities, counties and regions. -9. 📁 Attachment management: Unified management of all files and pictures on the platform. -10. 🗓 ️operation logs: log and query the system normal operation; Log and query system exception information. -11.🔌 [plugins market] () : based on the Django framework - Vue - Admin application and plug-in development. +1. 👨‍⚕️Menu Management: Configure system menus, operation permissions, button permission flags, backend interface permissions, etc. +2. 🧑‍⚕️Department Management: Configure system organizational structure (company, department, role). +3. 👩‍⚕️Role Management: Role menu permission assignment, data permission assignment, set role-based data scope permissions by department. +4. 🧑‍🎓Button Permission Control: Authorize role-specific button permissions and interface permissions, enabling authorization of data scope for each interface. +5. 🧑‍🎓Field Column Permission Control: Authorize page field display permissions, specifically for the display permissions of a certain column. +6. 👨‍🎓User Management: Users are system operators, and this function is mainly used for system user configuration. +7. 👬API Whitelist: Configure interfaces that do not require permission verification. +8. 🧑‍🔧Dictionary Management: Maintain frequently used and relatively fixed data in the system. +9. 🧑‍🔧Region Management: Manage provinces, cities, counties, and districts. +10. 📁File Management: Unified management of all files, images, etc., on the platform. +11. 🗓️Operation Logs: Record and query logs for normal system operations and exceptional system information. +12. 🔌[Plugin Market](https://bbs.django-vue-admin.com/plugMarket.html): Applications and plugins developed based on the Django-Vue-Admin framework. ## plugins market 🔌 -* Celery Asynchronous task:[dvadmin-celery](https://gitee.com/huge-dream/dvadmin-celery) -* Upgrade center backend:[dvadmin-upgrade-center](https://gitee.com/huge-dream/dvadmin-upgrade-center) -* Upgrade center front:[dvadmin-upgrade-center-web](https://gitee.com/huge-dream/dvadmin-upgrade-center-web) +Updating... + +## Repository Branch Explanation 💈 +Main Branch: master (stable version) +Development Branch: develop ## before start project you need: ~~~ -Python >= 3.8.0 -nodejs >= 14.0 -Mysql >= 5.7.0 (Optional. The default database is sqlite3. 8.0 is recommended) -Redis(Optional, the latest edition) +Python >= 3.11.0 (Minimum version 3.9+) +Node.js >= 16.0 +Mysql >= 8.0 (Optional, default database: SQLite3, supports 5.7+, recommended version: 8.0) +Redis (Optional, latest version) ~~~ ## frontend♝ ```bash # clone code -git clone https://gitee.com/liqianglog/django-vue-admin.git +git clone https://gitee.com/huge-dream/django-vue3-admin.git # enter code dir cd web # install dependence -npm install --registry=https://registry.npm.taobao.org +npm install yarn +yarn install --registry=https://registry.npm.taobao.org # Start service -npm run dev +yarn run dev # Visit http://localhost:8080 in your browser # Parameters such as boot port can be configured in the #.env.development file # Build the production environment -# npm run build +# yarn run build ``` ## backend💈 @@ -111,8 +116,8 @@ npm run dev python3 manage.py init_area 8. start backend python3 manage.py runserver 0.0.0.0:8000 -or daphne : - daphne -b 0.0.0.0 -p 8000 application.asgi:application +or uvicorn : + uvicorn application.asgi:application --port 8000 --host 0.0.0.0 --workers 8 ~~~ ### visit backend swagger @@ -120,12 +125,12 @@ or daphne : * visit url:[http://localhost:8080](http://localhost:8080) (The default address is this one. If you want to change it, follow the configuration file) * account:`superadmin` password:`admin123456` -### docker-compose +### docker-compose ~~~shell docker-compose up -d # Initialize backend data (first execution only) -docker exec -ti dvadmin-django bash +docker exec -ti dvadmin3-django bash python manage.py makemigrations python manage.py migrate python manage.py init_area @@ -147,22 +152,24 @@ docker-compose up -d --build ## Demo screenshot✅ -![image-01](https://images.gitee.com/uploads/images/2022/0530/234137_b58c8f98_5074988.png) +![image-01](https://foruda.gitee.com/images/1701348994587355489/1bc749e7_5074988.png) + +![image-02](https://foruda.gitee.com/images/1701349037811908960/80d361db_5074988.png) + +![image-03](https://foruda.gitee.com/images/1701349224478845203/954f0a7b_5074988.png) -![image-02](https://images.gitee.com/uploads/images/2022/0530/234240_39834603_5074988.png) +![image-04](https://foruda.gitee.com/images/1701349248928658877/64926724_5074988.png) -![image-03](https://images.gitee.com/uploads/images/2022/0530/234339_35e728a0_5074988.png) +![image-05](https://foruda.gitee.com/images/1701349259068943299/1306ba40_5074988.png) -![image-04](https://images.gitee.com/uploads/images/2022/0530/234426_957036b0_5074988.png) +![image-06](https://foruda.gitee.com/images/1701349294894429495/e3b3a8cf_5074988.png) -![image-05](https://images.gitee.com/uploads/images/2022/0530/234458_898be492_5074988.png) +![image-07](https://foruda.gitee.com/images/1701350432536247561/3b26685e_5074988.png) -![image-06](https://images.gitee.com/uploads/images/2022/0530/234521_35b40076_5074988.png) +![image-08](https://foruda.gitee.com/images/1701350455264771992/b364c57f_5074988.png) -![image-07](https://images.gitee.com/uploads/images/2022/0530/234615_c2325639_5074988.png) +![image-09](https://foruda.gitee.com/images/1701350479266000753/e4e4f7c5_5074988.png) -![image-08](https://images.gitee.com/uploads/images/2022/0530/234639_1ed6cc93_5074988.png) +![image-10](https://foruda.gitee.com/images/1701350501421625746/f8dd215e_5074988.png) -![image-09](https://images.gitee.com/uploads/images/2022/0530/234815_cea2c53f_5074988.png) -![image-10](https://images.gitee.com/uploads/images/2022/0530/234840_5f3e5f53_5074988.png) diff --git a/README.md b/README.md index 08f6d418378f0b3fb5365fa8679c9f8df525a436..511caf92bc050712fbee51b29e0275d10a5b31a8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![img](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitee.com/liqianglog/django-vue-admin/blob/master/LICENSE) [![img](https://img.shields.io/badge/python-%3E=3.7.x-green.svg)](https://python.org/) [![PyPI - Django Version badge](https://img.shields.io/badge/django%20versions-3.2-blue)](https://docs.djangoproject.com/zh-hans/3.2/) [![img](https://img.shields.io/badge/node-%3E%3D%2012.0.0-brightgreen)](https://nodejs.org/zh-cn/) [![img](https://gitee.com/liqianglog/django-vue-admin/badge/star.svg?theme=dark)](https://gitee.com/liqianglog/django-vue-admin) -[预 览](https://demo.dvadmin.com) | [官网文档](https://www.django-vue-admin.com) | [群聊](https://qm.qq.com/cgi-bin/qm/qr?k=fOdnHhC8DJlRHGYSnyhoB8P5rgogA6Vs&jump_from=webapi) | [社区](https://bbs.django-vue-admin.com) | [插件市场](https://bbs.django-vue-admin.com/plugMarket.html) | [Github](https://github.com/liqianglog/django-vue-admin) +[预 览](https://demo.dvadmin.com) | [官网文档](https://www.django-vue-admin.com) | [群聊](https://qm.qq.com/cgi-bin/qm/qr?k=fOdnHhC8DJlRHGYSnyhoB8P5rgogA6Vs&jump_from=webapi) | [社区](https://bbs.django-vue-admin.com) | [插件市场](https://bbs.django-vue-admin.com/plugMarket.html) | [Github](https://github.com/liqianglog/django-vue-admin) @@ -10,11 +10,14 @@ 我们是一群热爱代码的青年,在这个炙热的时代下,我们希望静下心来通过Code带来一点我们的色彩和颜色。 -因为热爱,所以拥抱未来 +因为热爱,所以拥抱未来! + ## 平台简介 -💡 [django-vue3-admin](https://gitee.com/huge-dream/django-vue3-admin.git) 是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 +💡 [django-vue3-admin](https://gitee.com/huge-dream/django-vue3-admin.git) 是一套全部开源的快速开发平台,毫无保留给个人免费使用、团体授权使用。 + django-vue3-admin 基于RBAC模型的权限控制的一整套基础开发平台,权限粒度达到列级别,前后端分离,后端采用django + django-rest-framework,前端采用基于 vue3 + CompositionAPI + typescript + vite + element plus + @@ -22,20 +25,29 @@ * 👭后端采用 Python 语言 Django 框架以及强大的 [Django REST Framework](https://pypi.org/project/djangorestframework)。 * 👫权限认证使用[Django REST Framework SimpleJWT](https://pypi.org/project/djangorestframework-simplejwt),支持多终端认证系统。 * 👬支持加载动态权限菜单,多方式轻松权限控制。 +* 👬全新的列权限管控,粒度细化到每一列。 * 💏特别鸣谢:[vue-next-admin](https://lyt-top.gitee.io/vue-next-admin-doc-preview/)。 -* 💡 特别感谢[jetbrains](https://www.jetbrains.com/) 为本开源项目提供免费的 IntelliJ IDEA 授权。 +* 💡特别感谢[jetbrains](https://www.jetbrains.com/) 为本开源项目提供免费的 IntelliJ IDEA 授权。 + +#### 🏭 环境支持 + +| Edge | Firefox | Chrome | Safari | +| --------- | ------------ | ----------- | ----------- | +| Edge ≥ 79 | Firefox ≥ 78 | Chrome ≥ 64 | Safari ≥ 12 | + +> 由于 Vue3 不再支持 IE11,故而 ElementPlus 也不支持 IE11 及之前版本。 ## 在线体验 -👩‍👧‍👦演示地址:[http://demo.django-vue-admin.com](http://demo.django-vue-admin.com) +👩‍👧‍👦演示地址:[https://demo.dvadmin.com](https://demo.dvadmin.com) -- 账号:superadmin +- 账号:superadmin - 密码:admin123456 -👩‍👦‍👦文档地址:[https://django-vue-admin.com](https://django-vue-admin.com) +👩‍👦‍👦文档地址:[coding](https://dvadmin-private.coding.net/share/km/cec69f3d-30fe-47d5-bd97-e9e851f0b776/K-2) @@ -46,7 +58,8 @@ - 插件市场:[戳我](https://bbs.django-vue-admin.com/plugMarket.html)👩‍👦‍👦 - django-vue-admin交流01群(已满):812482043 [点击链接加入群聊](https://qm.qq.com/cgi-bin/qm/qr?k=aJVwjDvH-Es4MPJQuoO32N0SucK22TE5&jump_from=webapi) -- django-vue-admin交流02群:687252418 [点击链接加入群聊](https://qm.qq.com/cgi-bin/qm/qr?k=4jJN4IjWGfxJ8YJXbb_gTsuWjR34WLdc&jump_from=webapi) +- django-vue-admin交流02群(已满):687252418 [点击链接加入群聊](https://qm.qq.com/cgi-bin/qm/qr?k=4jJN4IjWGfxJ8YJXbb_gTsuWjR34WLdc&jump_from=webapi) +- django-vue-admin交流03群:442108213 [点击链接加入群聊](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=wsm5oSz3K8dElBYUDtLTcQSEPhINFkl8&authKey=M6sbER0z59ZakgBr5erFeZyFZU15CI52bErNZa%2FxSvvGIuVAbY0N5866v89hm%2FK4&noverify=0&group_code=442108213) - 二维码 @@ -54,10 +67,9 @@ ## 源码地址 -gitee地址(主推):[https://gitee.com/liqianglog/django-vue-admin](https://gitee.com/liqianglog/django-vue-admin)👩‍👦‍👦 - -github地址:[https://github.com/liqianglog/django-vue-admin](https://github.com/liqianglog/django-vue-admin)👩‍👦‍👦 +gitee地址(主推):[https://gitee.com/huge-dream/django-vue3-admin](https://gitee.com/huge-dream/django-vue3-admin)👩‍👦‍👦 +github地址:[https://github.com/huge-dream/django-vue3-admin](https://github.com/huge-dream/django-vue3-admin)👩‍👦‍👦 ## 内置功能 @@ -65,47 +77,51 @@ github地址:[https://github.com/liqianglog/django-vue-admin](https://github.c 1. 👨‍⚕️菜单管理:配置系统菜单,操作权限,按钮权限标识、后端接口权限等。 2. 🧑‍⚕️部门管理:配置系统组织机构(公司、部门、角色)。 3. 👩‍⚕️角色管理:角色菜单权限分配、数据权限分配、设置角色按部门进行数据范围权限划分。 -4. 🧑‍🎓权限权限:授权角色的权限范围。 -5. 👨‍🎓用户管理:用户是系统操作者,该功能主要完成系统用户配置。 -6. 👬接口白名单:配置不需要进行权限校验的接口。 -7. 🧑‍🔧字典管理:对系统中经常使用的一些较为固定的数据进行维护。 -8. 🧑‍🔧地区管理:对省市县区域进行管理。 -9. 📁附件管理:对平台上所有文件、图片等进行统一管理。 -10. 🗓️操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 -11. 🔌[插件市场 ](https://bbs.django-vue-admin.com/plugMarket.html):基于Django-Vue-Admin框架开发的应用和插件。 +4. 🧑‍🎓按钮权限控制:授权角色的按钮权限和接口权限,可做到每一个接口都能授权数据范围。 +5. 🧑‍🎓字段列权限控制:授权页面的字段显示权限,具体到某一列的显示权限。 +7. 👨‍🎓用户管理:用户是系统操作者,该功能主要完成系统用户配置。 +8. 👬接口白名单:配置不需要进行权限校验的接口。 +9. 🧑‍🔧字典管理:对系统中经常使用的一些较为固定的数据进行维护。 +10. 🧑‍🔧地区管理:对省市县区域进行管理。 +11. 📁附件管理:对平台上所有文件、图片等进行统一管理。 +12. 🗓️操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +13. 🔌[插件市场 ](https://bbs.django-vue-admin.com/plugMarket.html):基于Django-Vue-Admin框架开发的应用和插件。 ## 插件市场 🔌 +更新中... + +## 仓库分支说明 💈 +主分支:master(稳定版本) +开发分支:develop -- Celery异步任务:[dvadmin-celery](https://gitee.com/huge-dream/dvadmin-celery) -- 升级中心后端:[dvadmin-upgrade-center](https://gitee.com/huge-dream/dvadmin-upgrade-center) -- 升级中心前端:[dvadmin-upgrade-center-web](https://gitee.com/huge-dream/dvadmin-upgrade-center-web) ## 准备工作 ~~~ -Python >= 3.8.0 (推荐3.8+版本) -nodejs >= 14.0 (推荐最新) -Mysql >= 5.7.0 (可选,默认数据库sqlite3,推荐8.0版本) -Redis(可选,最新版) +Python >= 3.11.0 (最低3.9+版本) +nodejs >= 16.0 +Mysql >= 8.0 (可选,默认数据库sqlite3,支持5.7+,推荐8.0版本) +Redis (可选,最新版) ~~~ ## 前端♝ ```bash # 克隆项目 -git clone https://gitee.com/liqianglog/django-vue-admin.git +git clone https://gitee.com/huge-dream/django-vue3-admin.git # 进入项目目录 cd web # 安装依赖 -npm install --registry=https://registry.npm.taobao.org +npm install yarn +yarn install --registry=https://registry.npm.taobao.org # 启动服务 -npm run dev +yarn build # 浏览器访问 http://localhost:8080 # .env.development 文件中可配置启动端口等参数 # 构建生产环境 -# npm run build +# yarn run build ``` @@ -129,9 +145,11 @@ npm run dev python3 manage.py init_area 8. 启动项目 python3 manage.py runserver 0.0.0.0:8000 -或使用 daphne : - daphne -b 0.0.0.0 -p 8000 application.asgi:application +或使用 uvicorn : + uvicorn application.asgi:application --port 8000 --host 0.0.0.0 --workers 8 ~~~ +## 开发建议 +前后端backend与web各自单独一个窗口打开进行开发 ### 访问项目 @@ -148,7 +166,7 @@ npm run dev # 先安装docker-compose (自行百度安装),执行此命令等待安装,如有使用celery插件请打开docker-compose.yml中celery 部分注释 docker-compose up -d # 初始化后端数据(第一次执行即可) -docker exec -ti dvadmin-django bash +docker exec -ti dvadmin3-django bash python manage.py makemigrations python manage.py migrate python manage.py init_area @@ -172,25 +190,25 @@ docker-compose up -d --build ## 演示图✅ -![image-01](https://images.gitee.com/uploads/images/2022/0530/234137_b58c8f98_5074988.png) +![image-01](https://foruda.gitee.com/images/1701348994587355489/1bc749e7_5074988.png) -![image-02](https://images.gitee.com/uploads/images/2022/0530/234240_39834603_5074988.png) +![image-02](https://foruda.gitee.com/images/1701349037811908960/80d361db_5074988.png) -![image-03](https://images.gitee.com/uploads/images/2022/0530/234339_35e728a0_5074988.png) +![image-03](https://foruda.gitee.com/images/1701349224478845203/954f0a7b_5074988.png) -![image-04](https://images.gitee.com/uploads/images/2022/0530/234426_957036b0_5074988.png) +![image-04](https://foruda.gitee.com/images/1701349248928658877/64926724_5074988.png) -![image-05](https://images.gitee.com/uploads/images/2022/0530/234458_898be492_5074988.png) +![image-05](https://foruda.gitee.com/images/1701349259068943299/1306ba40_5074988.png) -![image-06](https://images.gitee.com/uploads/images/2022/0530/234521_35b40076_5074988.png) +![image-06](https://foruda.gitee.com/images/1701349294894429495/e3b3a8cf_5074988.png) -![image-07](https://images.gitee.com/uploads/images/2022/0530/234615_c2325639_5074988.png) +![image-07](https://foruda.gitee.com/images/1701350432536247561/3b26685e_5074988.png) -![image-08](https://images.gitee.com/uploads/images/2022/0530/234639_1ed6cc93_5074988.png) +![image-08](https://foruda.gitee.com/images/1701350455264771992/b364c57f_5074988.png) -![image-09](https://images.gitee.com/uploads/images/2022/0530/234815_cea2c53f_5074988.png) +![image-09](https://foruda.gitee.com/images/1701350479266000753/e4e4f7c5_5074988.png) -![image-10](https://images.gitee.com/uploads/images/2022/0530/234840_5f3e5f53_5074988.png) +![image-10](https://foruda.gitee.com/images/1701350501421625746/f8dd215e_5074988.png) diff --git a/backend/.gitignore b/backend/.gitignore index a09ea3d722966ef85655d86accf4b880ecec0ea1..6c50cc968f99592116ca575d38654a3694d906e5 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -98,3 +98,4 @@ media/ __pypackages__/ package-lock.json gunicorn.pid +!plugins/__init__.py diff --git a/backend/application/settings.py b/backend/application/settings.py index b311baef0a5f12e00aa5f9bdf0580265b8b0a1e5..590c144420ec844521a5b803426e6214a352e8da 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -15,8 +15,6 @@ import sys from pathlib import Path from datetime import timedelta -from conf.env import * - # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -24,6 +22,8 @@ BASE_DIR = Path(__file__).resolve().parent.parent # ******************** 动态配置 ******************** # # ================================================= # +from conf.env import * + # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ @@ -43,7 +43,8 @@ sys.path.insert(0, os.path.join(PLUGINS_PATH)) DEBUG = locals().get("DEBUG", True) ALLOWED_HOSTS = locals().get("ALLOWED_HOSTS", ["*"]) -# Application definition +# 列权限需要排除的App应用 +COLUMN_EXCLUDE_APPS = ['channels', 'captcha'] + locals().get("COLUMN_EXCLUDE_APPS", []) INSTALLED_APPS = [ "django.contrib.auth", @@ -57,8 +58,8 @@ INSTALLED_APPS = [ "corsheaders", # 注册跨域app "drf_yasg", "captcha", - 'channels', - *locals().get("CUSTOM_APPS", []), # 所有项目里写的app需要在env.py文件里的CUSTOM_APPS中 + "channels", + "dvadmin.system", ] MIDDLEWARE = [ diff --git a/backend/application/websocketConfig.py b/backend/application/websocketConfig.py index c36d97a15a2acb4fe4cddf6fd39304e2847ec7f4..ab2cd64f3635556b69b56e8d28b663959ddb8f5a 100644 --- a/backend/application/websocketConfig.py +++ b/backend/application/websocketConfig.py @@ -73,7 +73,7 @@ class DvadminWebSocket(AsyncJsonWebsocketConsumer): unread_count = await _get_message_unread(self.user_id) if unread_count == 0: # 发送连接成功 - await self.send_json(set_message('system', 'SYSTEM', '连接成功')) + await self.send_json(set_message('system', 'SYSTEM', '您已上线')) else: await self.send_json( set_message('system', 'SYSTEM', "请查看您的未读消息~", diff --git a/backend/conf/env.example.py b/backend/conf/env.example.py index 117e200cbba7c94131257ad7594bc822d2a1c3a8..03e8c1b4cf9066f94c4d7835bca58b904d20a96c 100644 --- a/backend/conf/env.example.py +++ b/backend/conf/env.example.py @@ -44,8 +44,5 @@ LOGIN_NO_CAPTCHA_AUTH = True # ================================================= # ALLOWED_HOSTS = ["*"] -CUSTOM_APPS = [ - "dvadmin.system", -] -# daphne启动命令 -#daphne application.asgi:application -b 0.0.0.0 -p 8000 +# 列权限中排除App应用 +COLUMN_EXCLUDE_APPS = [] diff --git a/backend/dvadmin/system/fixtures/initSerializer.py b/backend/dvadmin/system/fixtures/initSerializer.py index fc701bc7c7e76d7c7666889b0c7a09e50634e551..0b139c1af9b0b28e0d1d00bb2ca7e9775f348eab 100644 --- a/backend/dvadmin/system/fixtures/initSerializer.py +++ b/backend/dvadmin/system/fixtures/initSerializer.py @@ -9,7 +9,7 @@ django.setup() from dvadmin.system.models import ( Role, Dept, Users, Menu, MenuButton, ApiWhiteList, Dictionary, SystemConfig, - RoleMenuPermission, RoleMenuButtonPermission + RoleMenuPermission, RoleMenuButtonPermission, MenuField ) from dvadmin.utils.serializers import CustomModelSerializer @@ -53,6 +53,16 @@ class MenuButtonInitSerializer(CustomModelSerializer): read_only_fields = ["id"] +class MenuFieldInitSerializer(CustomModelSerializer): + """ + 初始化列权限-序列化器 + """ + + class Meta: + model = MenuField + fields = ['id', 'menu','field_name','title','model'] + read_only_fields = ["id"] + class MenuInitSerializer(CustomModelSerializer): """ 递归深度获取数信息(用于生成初始化json文件) @@ -60,7 +70,7 @@ class MenuInitSerializer(CustomModelSerializer): name = serializers.CharField(required=False) children = serializers.SerializerMethodField() menu_button = serializers.SerializerMethodField() - + menu_field = serializers.SerializerMethodField() def get_children(self, obj: Menu): data = [] instance = Menu.objects.filter(parent_id=obj.id) @@ -76,10 +86,18 @@ class MenuInitSerializer(CustomModelSerializer): data = list(instance.values('name', 'value', 'api', 'method')) return data + def get_menu_field(self, obj: Menu): + data = [] + instance = obj.menufield_set.order_by('field_name') + if instance: + data = list(instance.values('field_name', 'title','model')) + return data + def save(self, **kwargs): instance = super().save(**kwargs) children = self.initial_data.get('children') menu_button = self.initial_data.get('menu_button') + menu_field = self.initial_data.get('menu_field') # 菜单表 if children: for menu_data in children: @@ -108,12 +126,24 @@ class MenuInitSerializer(CustomModelSerializer): serializer = MenuButtonInitSerializer(instance_obj, data=menu_button_data, request=self.request) serializer.is_valid(raise_exception=True) serializer.save() + # 列权限 + if menu_field: + for field_data in menu_field: + field_data['menu'] = instance.id + filter_data = { + 'menu':field_data['menu'], + 'field_name':field_data['field_name'] + } + instance_obj = MenuField.objects.filter(**filter_data).first() + serializer = MenuFieldInitSerializer(instance_obj, data=field_data, request=self.request) + serializer.is_valid(raise_exception=True) + serializer.save() return instance class Meta: model = Menu fields = ['name', 'icon', 'sort', 'is_link', 'is_catalog', 'web_path', 'component', 'component_name', 'status', - 'cache', 'visible', 'parent', 'children', 'menu_button', 'creator', 'dept_belong_id'] + 'cache', 'visible', 'parent', 'children', 'menu_button','menu_field', 'creator', 'dept_belong_id'] extra_kwargs = { 'creator': {'write_only': True}, 'dept_belong_id': {'write_only': True} @@ -128,7 +158,7 @@ class RoleInitSerializer(CustomModelSerializer): class Meta: model = Role - fields = ['name', 'key', 'sort', 'status', 'admin', + fields = ['name', 'key', 'sort', 'status', 'creator', 'dept_belong_id'] read_only_fields = ["id"] extra_kwargs = { diff --git a/backend/dvadmin/system/fixtures/init_menu.json b/backend/dvadmin/system/fixtures/init_menu.json index 9d514fe5473763e96b5ee0989ef64bfae298ab94..425887234ac2af9b6d904e786b969173c8e27729 100644 --- a/backend/dvadmin/system/fixtures/init_menu.json +++ b/backend/dvadmin/system/fixtures/init_menu.json @@ -11,6 +11,7 @@ "status": true, "cache": false, "visible": true, + "parent": null, "children": [ { "name": "菜单管理", @@ -24,6 +25,7 @@ "status": true, "cache": false, "visible": true, + "parent": 1, "children": [], "menu_button": [ { @@ -38,24 +40,6 @@ "api": "/api/system/menu/{id}/", "method": 0 }, - { - "name": "新增", - "value": "menu:Create", - "api": "/api/system/menu/", - "method": 1 - }, - { - "name": "编辑", - "value": "menu:Update", - "api": "/api/system/menu/{id}/", - "method": 2 - }, - { - "name": "删除", - "value": "menu:Delete", - "api": "/api/system/menu/{id}/", - "method": 3 - }, { "name": "查询所有", "value": "menu:SearchAll", @@ -68,6 +52,24 @@ "api": "/api/system/menu/web_router/", "method": 0 }, + { + "name": "查询按钮权限", + "value": "btn:Search", + "api": "/api/system/menu_button/", + "method": 0 + }, + { + "name": "查询列权限", + "value": "column:Search", + "api": "/api/system/column/", + "method": 0 + }, + { + "name": "新增", + "value": "menu:Create", + "api": "/api/system/menu/", + "method": 1 + }, { "name": "上移", "value": "menu:MoveUp", @@ -79,48 +81,63 @@ "value": "menu:MoveDown", "api": "/api/system/menu/mode_down/", "method": 1 - } - ] - }, - { - "name": "菜单按钮", - "icon": "dot-circle-o", - "sort": 2, - "is_link": false, - "is_catalog": false, - "web_path": "/menuButton", - "component": "system/menuButton/index", - "component_name": "menuButton", - "status": true, - "cache": false, - "visible": false, - "children": [], - "menu_button": [ + }, { - "name": "查询", - "value": "menu_button:Search", + "name": "新增按钮权限", + "value": "btn:Create", "api": "/api/system/menu_button/", - "method": 0 + "method": 1 }, { - "name": "新增", - "value": "menu_button:Create", - "api": "/api/system/menu_button/", + "name": "新增列权限", + "value": "column:Create", + "api": "/api/system/column/", + "method": 1 + }, + { + "name": "自动匹配列权限", + "value": "column:Match", + "api": "/api/system/column/auto_match_fields/", "method": 1 }, { "name": "编辑", - "value": "menu_button:Update", + "value": "menu:Update", + "api": "/api/system/menu/{id}/", + "method": 2 + }, + { + "name": "修改按钮权限", + "value": "btn:Update", "api": "/api/system/menu_button/{id}/", "method": 2 }, + { + "name": "编辑列权限", + "value": "column:Update", + "api": "/api/system/column/{id}/", + "method": 2 + }, { "name": "删除", - "value": "menu_button:Delete", + "value": "menu:Delete", + "api": "/api/system/menu/{id}/", + "method": 3 + }, + { + "name": "删除按钮权限", + "value": "btn:Delete", "api": "/api/system/menu_button/{id}/", "method": 3 + }, + { + "name": "删除列权限", + "value": "column:Delete", + "api": "/api/system/column/{id}/", + "method": 3 } - ] + ], + "menu_field": [] }, { "name": "部门管理", @@ -134,6 +151,7 @@ "status": true, "cache": false, "visible": true, + "parent": 1, "children": [], "menu_button": [ { @@ -148,24 +166,6 @@ "api": "/api/system/dept/{id}/", "method": 0 }, - { - "name": "新增", - "value": "dept:Create", - "api": "/api/system/dept/", - "method": 1 - }, - { - "name": "编辑", - "value": "dept:Update", - "api": "/api/system/dept/{id}/", - "method": 2 - }, - { - "name": "删除", - "value": "dept:Delete", - "api": "/api/system/dept/{id}/", - "method": 3 - }, { "name": "查询所有", "value": "dept:SearchAll", @@ -178,6 +178,18 @@ "api": "/api/system/dept/dept_lazy_tree/", "method": 0 }, + { + "name": "头信息", + "value": "dept:HeaderInfo", + "api": "/api/system/dept/dept_info/", + "method": 0 + }, + { + "name": "新增", + "value": "dept:Create", + "api": "/api/system/dept/", + "method": 1 + }, { "name": "上移", "value": "dept:MoveUp", @@ -191,12 +203,19 @@ "method": 1 }, { - "name": "头信息", - "value": "dept:HeaderInfo", - "api": "/api/system/dept/dept_info/", - "method": 0 + "name": "编辑", + "value": "dept:Update", + "api": "/api/system/dept/{id}/", + "method": 2 + }, + { + "name": "删除", + "value": "dept:Delete", + "api": "/api/system/dept/{id}/", + "method": 3 } - ] + ], + "menu_field": [] }, { "name": "角色管理", @@ -210,6 +229,7 @@ "status": true, "cache": false, "visible": true, + "parent": 1, "children": [], "menu_button": [ { @@ -224,6 +244,12 @@ "api": "/api/system/role/{id}/", "method": 0 }, + { + "name": "权限配置", + "value": "role:Permission", + "api": "/api/system/role/{id}/", + "method": 0 + }, { "name": "新增", "value": "role:Create", @@ -248,63 +274,62 @@ "api": "/api/system/role/{id}/", "method": 3 } - ] - }, - { - "name": "列管理", - "icon": "iconfont icon-bolangneng", - "sort": 5, - "is_link": false, - "is_catalog": false, - "web_path": "/columns", - "component": "system/columns/index", - "component_name": "columns", - "status": true, - "cache": false, - "visible": true, - "children": [], - "menu_button": [ + ], + "menu_field": [ { - "name": "查询", - "value": "column:Search", - "api": "/api/system/column/", - "method": 0 + "field_name": "create_datetime", + "title": "创建时间", + "model": "Role" }, { - "name": "详情", - "value": "column:Retrieve", - "api": "/api/system/column/{id}/", - "method": 0 + "field_name": "creator", + "title": "创建人", + "model": "Role" }, { - "name": "新增", - "value": "column:Create", - "api": "/api/system/column/", - "method": 1 + "field_name": "dept_belong_id", + "title": "数据归属部门", + "model": "Role" }, { - "name": "编辑", - "value": "column:Update", - "api": "/api/system/column/{id}/", - "method": 2 + "field_name": "description", + "title": "描述", + "model": "Role" }, { - "name": "删除", - "value": "column:Delete", - "api": "/api/system/column/{id}/", - "method": 3 + "field_name": "id", + "title": "Id", + "model": "Role" }, { - "name": "所有模型表", - "value": "column:AllModel", - "api": "/api/system/column/get_models/", - "method": 0 + "field_name": "key", + "title": "权限字符", + "model": "Role" }, { - "name": "自动匹配所有字段", - "value": "column:AutoMatch", - "api": "/api/system/column/auto_match_fields/", - "method": 1 + "field_name": "modifier", + "title": "修改人", + "model": "Role" + }, + { + "field_name": "name", + "title": "角色名称", + "model": "Role" + }, + { + "field_name": "sort", + "title": "角色顺序", + "model": "Role" + }, + { + "field_name": "status", + "title": "角色状态", + "model": "Role" + }, + { + "field_name": "update_datetime", + "title": "修改时间", + "model": "Role" } ] }, @@ -320,6 +345,7 @@ "status": true, "cache": false, "visible": true, + "parent": 1, "children": [], "menu_button": [ { @@ -376,6 +402,83 @@ "api": "/api/system/user/{id}/", "method": 3 } + ], + "menu_field": [ + { + "field_name": "avatar", + "title": "头像", + "model": "Users" + }, + { + "field_name": "create_datetime", + "title": "创建时间", + "model": "Users" + }, + { + "field_name": "creator", + "title": "创建人", + "model": "Users" + }, + { + "field_name": "dept", + "title": "所属部门", + "model": "Users" + }, + { + "field_name": "dept_belong_id", + "title": "数据归属部门", + "model": "Users" + }, + { + "field_name": "description", + "title": "描述", + "model": "Users" + }, + { + "field_name": "email", + "title": "邮箱", + "model": "Users" + }, + { + "field_name": "gender", + "title": "性别", + "model": "Users" + }, + { + "field_name": "id", + "title": "Id", + "model": "Users" + }, + { + "field_name": "mobile", + "title": "电话", + "model": "Users" + }, + { + "field_name": "modifier", + "title": "修改人", + "model": "Users" + }, + { + "field_name": "name", + "title": "姓名", + "model": "Users" + }, + { + "field_name": "update_datetime", + "title": "修改时间", + "model": "Users" + }, + { + "field_name": "username", + "title": "用户账号", + "model": "Users" + }, + { + "field_name": "user_type", + "title": "用户类型", + "model": "Users" + } ] }, { @@ -390,6 +493,7 @@ "status": true, "cache": false, "visible": true, + "parent": 1, "children": [], "menu_button": [ { @@ -422,6 +526,58 @@ "api": "/api/system/menu/{id}/", "method": 3 } + ], + "menu_field": [ + { + "field_name": "content", + "title": "内容", + "model": "MessageCenter" + }, + { + "field_name": "create_datetime", + "title": "创建时间", + "model": "MessageCenter" + }, + { + "field_name": "creator", + "title": "创建人", + "model": "MessageCenter" + }, + { + "field_name": "dept_belong_id", + "title": "数据归属部门", + "model": "MessageCenter" + }, + { + "field_name": "description", + "title": "描述", + "model": "MessageCenter" + }, + { + "field_name": "id", + "title": "Id", + "model": "MessageCenter" + }, + { + "field_name": "modifier", + "title": "修改人", + "model": "MessageCenter" + }, + { + "field_name": "target_type", + "title": "目标类型", + "model": "MessageCenter" + }, + { + "field_name": "title", + "title": "标题", + "model": "MessageCenter" + }, + { + "field_name": "update_datetime", + "title": "修改时间", + "model": "MessageCenter" + } ] }, { @@ -436,6 +592,7 @@ "status": true, "cache": false, "visible": true, + "parent": 1, "children": [], "menu_button": [ { @@ -468,10 +625,63 @@ "api": "/api/system/api_white_list/{id}/", "method": 3 } + ], + "menu_field": [ + { + "field_name": "create_datetime", + "title": "创建时间", + "model": "ApiWhiteList" + }, + { + "field_name": "creator", + "title": "创建人", + "model": "ApiWhiteList" + }, + { + "field_name": "dept_belong_id", + "title": "数据归属部门", + "model": "ApiWhiteList" + }, + { + "field_name": "description", + "title": "描述", + "model": "ApiWhiteList" + }, + { + "field_name": "enable_datasource", + "title": "激活数据权限", + "model": "ApiWhiteList" + }, + { + "field_name": "id", + "title": "Id", + "model": "ApiWhiteList" + }, + { + "field_name": "method", + "title": "接口请求方法", + "model": "ApiWhiteList" + }, + { + "field_name": "modifier", + "title": "修改人", + "model": "ApiWhiteList" + }, + { + "field_name": "update_datetime", + "title": "修改时间", + "model": "ApiWhiteList" + }, + { + "field_name": "url", + "title": "url", + "model": "ApiWhiteList" + } ] } ], - "menu_button": [] + "menu_button": [], + "menu_field": [] }, { "name": "常规配置", @@ -485,6 +695,7 @@ "status": true, "cache": false, "visible": true, + "parent": null, "children": [ { "name": "系统配置", @@ -498,6 +709,7 @@ "status": true, "cache": false, "visible": true, + "parent": 10, "children": [], "menu_button": [ { @@ -530,7 +742,8 @@ "api": "/api/system/system_config/{id}/", "method": 3 } - ] + ], + "menu_field": [] }, { "name": "字典管理", @@ -544,6 +757,7 @@ "status": true, "cache": false, "visible": true, + "parent": 10, "children": [], "menu_button": [ { @@ -576,6 +790,88 @@ "api": "/api/system/dictionary/{id}/", "method": 3 } + ], + "menu_field": [ + { + "field_name": "color", + "title": "颜色", + "model": "Dictionary" + }, + { + "field_name": "create_datetime", + "title": "创建时间", + "model": "Dictionary" + }, + { + "field_name": "creator", + "title": "创建人", + "model": "Dictionary" + }, + { + "field_name": "dept_belong_id", + "title": "数据归属部门", + "model": "Dictionary" + }, + { + "field_name": "description", + "title": "描述", + "model": "Dictionary" + }, + { + "field_name": "id", + "title": "Id", + "model": "Dictionary" + }, + { + "field_name": "is_value", + "title": "是否为value值", + "model": "Dictionary" + }, + { + "field_name": "label", + "title": "字典名称", + "model": "Dictionary" + }, + { + "field_name": "modifier", + "title": "修改人", + "model": "Dictionary" + }, + { + "field_name": "parent", + "title": "父级", + "model": "Dictionary" + }, + { + "field_name": "remark", + "title": "备注", + "model": "Dictionary" + }, + { + "field_name": "sort", + "title": "显示排序", + "model": "Dictionary" + }, + { + "field_name": "status", + "title": "状态", + "model": "Dictionary" + }, + { + "field_name": "type", + "title": "数据值类型", + "model": "Dictionary" + }, + { + "field_name": "update_datetime", + "title": "修改时间", + "model": "Dictionary" + }, + { + "field_name": "value", + "title": "字典编号", + "model": "Dictionary" + } ] }, { @@ -590,6 +886,7 @@ "status": true, "cache": false, "visible": true, + "parent": 10, "children": [], "menu_button": [ { @@ -622,6 +919,78 @@ "api": "/api/system/area/{id}/", "method": 3 } + ], + "menu_field": [ + { + "field_name": "code", + "title": "地区编码", + "model": "Area" + }, + { + "field_name": "create_datetime", + "title": "创建时间", + "model": "Area" + }, + { + "field_name": "creator", + "title": "创建人", + "model": "Area" + }, + { + "field_name": "dept_belong_id", + "title": "数据归属部门", + "model": "Area" + }, + { + "field_name": "description", + "title": "描述", + "model": "Area" + }, + { + "field_name": "enable", + "title": "是否启用", + "model": "Area" + }, + { + "field_name": "id", + "title": "Id", + "model": "Area" + }, + { + "field_name": "initials", + "title": "首字母", + "model": "Area" + }, + { + "field_name": "level", + "title": "地区层级(1省份 2城市 3区县 4乡级)", + "model": "Area" + }, + { + "field_name": "modifier", + "title": "修改人", + "model": "Area" + }, + { + "field_name": "name", + "title": "名称", + "model": "Area" + }, + { + "field_name": "pcode", + "title": "父地区编码", + "model": "Area" + }, + { + "field_name": "pinyin", + "title": "拼音", + "model": "Area" + }, + { + "field_name": "update_datetime", + "title": "修改时间", + "model": "Area" + } ] }, { @@ -636,6 +1005,7 @@ "status": true, "cache": false, "visible": true, + "parent": 10, "children": [], "menu_button": [ { @@ -662,10 +1032,83 @@ "api": "/api/system/file/{id}/", "method": 3 } + ], + "menu_field": [ + { + "field_name": "create_datetime", + "title": "创建时间", + "model": "FileList" + }, + { + "field_name": "creator", + "title": "创建人", + "model": "FileList" + }, + { + "field_name": "dept_belong_id", + "title": "数据归属部门", + "model": "FileList" + }, + { + "field_name": "description", + "title": "描述", + "model": "FileList" + }, + { + "field_name": "engine", + "title": "引擎", + "model": "FileList" + }, + { + "field_name": "file_url", + "title": "文件地址", + "model": "FileList" + }, + { + "field_name": "id", + "title": "Id", + "model": "FileList" + }, + { + "field_name": "md5sum", + "title": "文件md5", + "model": "FileList" + }, + { + "field_name": "mime_type", + "title": "Mime类型", + "model": "FileList" + }, + { + "field_name": "modifier", + "title": "修改人", + "model": "FileList" + }, + { + "field_name": "name", + "title": "名称", + "model": "FileList" + }, + { + "field_name": "size", + "title": "文件大小", + "model": "FileList" + }, + { + "field_name": "update_datetime", + "title": "修改时间", + "model": "FileList" + }, + { + "field_name": "url", + "title": "url", + "model": "FileList" + } ] } ], - "menu_button": [] + "menu_button": [], + "menu_field": [] }, { "name": "日志管理", @@ -679,6 +1122,7 @@ "status": true, "cache": false, "visible": true, + "parent": null, "children": [ { "name": "登录日志", @@ -692,6 +1136,7 @@ "status": true, "cache": false, "visible": true, + "parent": 15, "children": [], "menu_button": [ { @@ -706,6 +1151,128 @@ "api": "/api/system/login_log/{id}/", "method": 0 } + ], + "menu_field": [ + { + "field_name": "agent", + "title": "agent信息", + "model": "LoginLog" + }, + { + "field_name": "area_code", + "title": "区域代码", + "model": "LoginLog" + }, + { + "field_name": "browser", + "title": "浏览器名", + "model": "LoginLog" + }, + { + "field_name": "city", + "title": "城市", + "model": "LoginLog" + }, + { + "field_name": "continent", + "title": "州", + "model": "LoginLog" + }, + { + "field_name": "country", + "title": "国家", + "model": "LoginLog" + }, + { + "field_name": "country_code", + "title": "简称", + "model": "LoginLog" + }, + { + "field_name": "country_english", + "title": "英文全称", + "model": "LoginLog" + }, + { + "field_name": "create_datetime", + "title": "创建时间", + "model": "LoginLog" + }, + { + "field_name": "creator", + "title": "创建人", + "model": "LoginLog" + }, + { + "field_name": "dept_belong_id", + "title": "数据归属部门", + "model": "LoginLog" + }, + { + "field_name": "description", + "title": "描述", + "model": "LoginLog" + }, + { + "field_name": "district", + "title": "县区", + "model": "LoginLog" + }, + { + "field_name": "id", + "title": "Id", + "model": "LoginLog" + }, + { + "field_name": "ip", + "title": "登录ip", + "model": "LoginLog" + }, + { + "field_name": "isp", + "title": "运营商", + "model": "LoginLog" + }, + { + "field_name": "latitude", + "title": "纬度", + "model": "LoginLog" + }, + { + "field_name": "login_type", + "title": "登录类型", + "model": "LoginLog" + }, + { + "field_name": "longitude", + "title": "经度", + "model": "LoginLog" + }, + { + "field_name": "modifier", + "title": "修改人", + "model": "LoginLog" + }, + { + "field_name": "os", + "title": "操作系统", + "model": "LoginLog" + }, + { + "field_name": "province", + "title": "省份", + "model": "LoginLog" + }, + { + "field_name": "update_datetime", + "title": "修改时间", + "model": "LoginLog" + }, + { + "field_name": "username", + "title": "登录用户名", + "model": "LoginLog" + } ] }, { @@ -720,6 +1287,7 @@ "status": true, "cache": false, "visible": true, + "parent": 15, "children": [], "menu_button": [ { @@ -734,9 +1302,102 @@ "api": "/api/system/operation_log/", "method": 0 } + ], + "menu_field": [ + { + "field_name": "create_datetime", + "title": "创建时间", + "model": "OperationLog" + }, + { + "field_name": "creator", + "title": "创建人", + "model": "OperationLog" + }, + { + "field_name": "dept_belong_id", + "title": "数据归属部门", + "model": "OperationLog" + }, + { + "field_name": "description", + "title": "描述", + "model": "OperationLog" + }, + { + "field_name": "id", + "title": "Id", + "model": "OperationLog" + }, + { + "field_name": "json_result", + "title": "返回信息", + "model": "OperationLog" + }, + { + "field_name": "modifier", + "title": "修改人", + "model": "OperationLog" + }, + { + "field_name": "request_body", + "title": "请求参数", + "model": "OperationLog" + }, + { + "field_name": "request_browser", + "title": "请求浏览器", + "model": "OperationLog" + }, + { + "field_name": "request_ip", + "title": "请求ip地址", + "model": "OperationLog" + }, + { + "field_name": "request_method", + "title": "请求方式", + "model": "OperationLog" + }, + { + "field_name": "request_modular", + "title": "请求模块", + "model": "OperationLog" + }, + { + "field_name": "request_msg", + "title": "操作说明", + "model": "OperationLog" + }, + { + "field_name": "request_os", + "title": "操作系统", + "model": "OperationLog" + }, + { + "field_name": "request_path", + "title": "请求地址", + "model": "OperationLog" + }, + { + "field_name": "response_code", + "title": "响应状态码", + "model": "OperationLog" + }, + { + "field_name": "status", + "title": "响应状态", + "model": "OperationLog" + }, + { + "field_name": "update_datetime", + "title": "修改时间", + "model": "OperationLog" + } ] } ], - "menu_button": [] + "menu_button": [], + "menu_field": [] } ] \ No newline at end of file diff --git a/backend/dvadmin/system/fixtures/init_role.json b/backend/dvadmin/system/fixtures/init_role.json index 6fb63fe1059d4ba12e4ca8cef39bd9f5cbb94f5d..f1678e57f0ba2692a0e003e1a77ebcc6f40febaa 100644 --- a/backend/dvadmin/system/fixtures/init_role.json +++ b/backend/dvadmin/system/fixtures/init_role.json @@ -4,7 +4,6 @@ "key": "admin", "sort": 1, "status": true, - "admin": true, "remark": null }, { @@ -12,7 +11,6 @@ "key": "public", "sort": 2, "status": true, - "admin": true, "remark": null } ] diff --git a/backend/dvadmin/system/fixtures/init_systemconfig.json b/backend/dvadmin/system/fixtures/init_systemconfig.json index ed4c967b3d111be182027e6f92b5d38e563bc2d8..c2326aae44b236ddf85902b38903482a440516b8 100644 --- a/backend/dvadmin/system/fixtures/init_systemconfig.json +++ b/backend/dvadmin/system/fixtures/init_systemconfig.json @@ -65,6 +65,20 @@ "placeholder": null, "setting": null, "children": [ + { + "parent": 1, + "title": "网站标题", + "key": "site_title", + "value": "Dvadmin", + "sort": 1, + "status": true, + "data_options": null, + "form_item_type": 0, + "rule": [], + "placeholder": "请输入网站标题", + "setting": null, + "children": [] + }, { "parent": 1, "title": "网站名称", @@ -116,7 +130,7 @@ "parent": 1, "title": "版权信息", "key": "copyright", - "value": "2021-2022 django-vue-admin.com 版权所有", + "value": "2021-2024 django-vue-admin.com 版权所有", "sort": 4, "status": true, "data_options": null, diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py index ed728ea7bbec9c16384f2f01e840d749486d4dea..ea7224d5fd1565af4cd0a0af875928071544332f 100644 --- a/backend/dvadmin/system/models.py +++ b/backend/dvadmin/system/models.py @@ -13,7 +13,6 @@ class Role(CoreModel): key = models.CharField(max_length=64, unique=True, verbose_name="权限字符", help_text="权限字符") sort = models.IntegerField(default=1, verbose_name="角色顺序", help_text="角色顺序") status = models.BooleanField(default=True, verbose_name="角色状态", help_text="角色状态") - admin = models.BooleanField(default=False, verbose_name="是否为admin", help_text="是否为admin") class Meta: db_table = table_prefix + "system_role" @@ -179,21 +178,27 @@ class Menu(CoreModel): verbose_name_plural = verbose_name ordering = ("sort",) - -class Columns(CoreModel): - role = models.ForeignKey(to='Role', on_delete=models.CASCADE, verbose_name='角色', db_constraint=False) - app = models.CharField(max_length=64, verbose_name='应用名') +class MenuField(CoreModel): model = models.CharField(max_length=64, verbose_name='表名') menu = models.ForeignKey(to='Menu', on_delete=models.CASCADE, verbose_name='菜单', db_constraint=False) field_name = models.CharField(max_length=64, verbose_name='模型表字段名') title = models.CharField(max_length=64, verbose_name='字段显示名') + class Meta: + db_table = table_prefix + "system_menu_field" + verbose_name = "菜单字段表" + verbose_name_plural = verbose_name + ordering = ("id",) + +class FieldPermission(CoreModel): + role = models.ForeignKey(to='Role', on_delete=models.CASCADE, verbose_name='角色', db_constraint=False) + field = models.ForeignKey(to='MenuField', on_delete=models.CASCADE,related_name='menu_field', verbose_name='字段', db_constraint=False) is_query = models.BooleanField(default=1, verbose_name='是否可查询') is_create = models.BooleanField(default=1, verbose_name='是否可创建') is_update = models.BooleanField(default=1, verbose_name='是否可更新') class Meta: - db_table = table_prefix + "system_columns" - verbose_name = "列权限表" + db_table = table_prefix + "system_field_permission" + verbose_name = "字段权限表" verbose_name_plural = verbose_name ordering = ("id",) diff --git a/backend/dvadmin/system/urls.py b/backend/dvadmin/system/urls.py index 4e11c04921f4975f53d3955df322558f5e539b52..512c399949aff38db4447ec727d9e024192790f6 100644 --- a/backend/dvadmin/system/urls.py +++ b/backend/dvadmin/system/urls.py @@ -16,7 +16,7 @@ from dvadmin.system.views.role_menu import RoleMenuPermissionViewSet from dvadmin.system.views.role_menu_button_permission import RoleMenuButtonPermissionViewSet from dvadmin.system.views.system_config import SystemConfigViewSet from dvadmin.system.views.user import UserViewSet -from dvadmin.system.views.column import ColumnViewSet +from dvadmin.system.views.menu_field import MenuFieldViewSet system_url = routers.SimpleRouter() system_url.register(r'menu', MenuViewSet) @@ -33,7 +33,7 @@ system_url.register(r'system_config', SystemConfigViewSet) system_url.register(r'message_center', MessageCenterViewSet) system_url.register(r'role_menu_button_permission', RoleMenuButtonPermissionViewSet) system_url.register(r'role_menu_permission', RoleMenuPermissionViewSet) -system_url.register(r'column', ColumnViewSet) +system_url.register(r'column', MenuFieldViewSet) urlpatterns = [ diff --git a/backend/dvadmin/system/views/menu.py b/backend/dvadmin/system/views/menu.py index 68996462949e517144a1e2d264f9931d514a60c6..7ac3c40cdc4680d536d4488141633c675ddc137f 100644 --- a/backend/dvadmin/system/views/menu.py +++ b/backend/dvadmin/system/views/menu.py @@ -119,8 +119,7 @@ class MenuViewSet(CustomModelViewSet): def web_router(self, request): """用于前端获取当前角色的路由""" user = request.user - is_admin = user.role.values_list('admin', flat=True) - if user.is_superuser or True in is_admin: + if user.is_superuser: queryset = self.queryset.filter(status=1) else: role_list = user.role.values_list('id', flat=True) diff --git a/backend/dvadmin/system/views/menu_button.py b/backend/dvadmin/system/views/menu_button.py index 94a65efb1f429cbbe07cd1dd01ef42724dfcccd1..4473d4737acd574cb05d21e8b8350324948b299a 100644 --- a/backend/dvadmin/system/views/menu_button.py +++ b/backend/dvadmin/system/views/menu_button.py @@ -11,7 +11,7 @@ from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from dvadmin.system.models import MenuButton, RoleMenuButtonPermission -from dvadmin.utils.json_response import DetailResponse +from dvadmin.utils.json_response import DetailResponse, SuccessResponse from dvadmin.utils.serializers import CustomModelSerializer from dvadmin.utils.viewset import CustomModelViewSet @@ -49,12 +49,24 @@ class MenuButtonViewSet(CustomModelViewSet): retrieve:单例 destroy:删除 """ - queryset = MenuButton.objects.all() + queryset = MenuButton.objects.order_by('create_datetime') serializer_class = MenuButtonSerializer create_serializer_class = MenuButtonCreateUpdateSerializer update_serializer_class = MenuButtonCreateUpdateSerializer extra_filter_class = [] + def list(self, request, *args, **kwargs): + """ + 重写list方法 + :param request: + :param args: + :param kwargs: + :return: + """ + queryset = self.filter_queryset(self.get_queryset()) + serializer = self.get_serializer(queryset, many=True, request=request) + return SuccessResponse(serializer.data,msg="获取成功") + @action(methods=['get'],detail=False,permission_classes=[IsAuthenticated]) def menu_button_all_permission(self,request): """ @@ -63,8 +75,7 @@ class MenuButtonViewSet(CustomModelViewSet): :return: """ is_superuser = request.user.is_superuser - is_admin = request.user.role.values_list('admin', flat=True) - if is_superuser or True in is_admin: + if is_superuser: queryset = MenuButton.objects.values_list('value',flat=True) else: role_id = request.user.role.values_list('id', flat=True) diff --git a/backend/dvadmin/system/views/column.py b/backend/dvadmin/system/views/menu_field.py similarity index 57% rename from backend/dvadmin/system/views/column.py rename to backend/dvadmin/system/views/menu_field.py index a23d27cdb8d7e65ef876f5d5d18ef6704b8281bb..8f6cd1aee6c80fc3d5da719dd62aed0b9d9c873b 100644 --- a/backend/dvadmin/system/views/column.py +++ b/backend/dvadmin/system/views/menu_field.py @@ -1,57 +1,51 @@ # -*- coding: utf-8 -*- +from django.apps import apps from rest_framework import serializers from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated -from dvadmin.system.models import Columns, Role +from dvadmin.system.models import Role, MenuField from dvadmin.utils.models import get_custom_app_models from dvadmin.utils.viewset import CustomModelViewSet from dvadmin.utils.serializers import CustomModelSerializer from dvadmin.utils.json_response import DetailResponse, ErrorResponse, SuccessResponse -class ColumnSerializer(CustomModelSerializer): +class MenuFieldSerializer(CustomModelSerializer): """ 列权限序列化器 """ class Meta: - model = Columns + model = MenuField fields = '__all__' read_only_fields = ['id'] -class ColumnViewSet(CustomModelViewSet): +class MenuFieldViewSet(CustomModelViewSet): """ 列权限视图集 """ - queryset = Columns.objects.all() - serializer_class = ColumnSerializer + queryset = MenuField.objects.all() + serializer_class = MenuFieldSerializer def list(self, request, *args, **kwargs): - role_id = request.query_params.get('role') - app_name = request.query_params.get('app') - model_name = request.query_params.get('model') menu = request.query_params.get('menu') - if not role_id or not model_name or not app_name or not menu: + if not menu: return SuccessResponse([]) - queryset = self.filter_queryset(self.get_queryset().filter(role_id=role_id, model=model_name, app=app_name,menu_id=menu)) - page = self.paginate_queryset(queryset) - if page is not None: - serializer = self.get_serializer(page, many=True, request=request) - return self.get_paginated_response(serializer.data) + queryset = self.filter_queryset(self.get_queryset().filter(menu=menu)) serializer = self.get_serializer(queryset, many=True, request=request) return SuccessResponse(data=serializer.data, msg="获取成功") def create(self, request, *args, **kwargs): payload = request.data - for model in get_custom_app_models(payload.get('app')): - if payload.get('model') == model['model']: + for model in apps.get_models(): + if payload.get('model') == model.__name__: break else: return ErrorResponse(msg='模型表不存在') - if Columns.objects.filter(app=model['app'], model=model['model'], field_name=payload.get('field_name')).exists(): + if MenuField.objects.filter(menu=payload.get('menu'),model=model.__name__, field_name=payload.get('field_name')).exists(): return ErrorResponse(msg='‘%s’ 字段权限已有,不可重复创建' % payload.get('title')) return super().create(request, *args, **kwargs) @@ -60,34 +54,31 @@ class ColumnViewSet(CustomModelViewSet): def get_models(self, request): """获取所有项目app下的model""" res = [] - for app in get_custom_app_models(): - for model in app: - res.append({ - 'app': model['app'], - 'title': model['verbose'], - 'key': model['model'] - }) + for model in get_custom_app_models(): + res.append({ + 'app': model['app'], + 'title': model['verbose'], + 'key': model['model'] + }) return DetailResponse(res) @action(methods=['POST'], detail=False, permission_classes=[IsAuthenticated]) def auto_match_fields(self, request): """自动匹配已有的字段""" - role_id = request.data.get('role') - app_name = request.data.get('app') + menu_id = request.data.get('menu') model_name = request.data.get('model') - if not role_id or not model_name or not app_name: - return DetailResponse([], msg='无操作') - for model in get_custom_app_models(app_name): + if not menu_id or not model_name: + return ErrorResponse( msg='参数错误') + for model in get_custom_app_models(): if model['model'] != model_name: continue for field in model['fields']: - if Columns.objects.filter( - role_id=role_id, app=app_name, model=model_name, field_name=field['name'] + if MenuField.objects.filter( + menu_id=menu_id, model=model_name, field_name=field['name'] ).exists(): continue data = { - 'role': role_id, - 'app': app_name, + 'menu': menu_id, 'model': model_name, 'field_name': field['name'], 'title': str(field['title']), diff --git a/backend/dvadmin/system/views/role_menu_button_permission.py b/backend/dvadmin/system/views/role_menu_button_permission.py index 109b27be7fa08994aafefd7c4bf2cc1d6f25d141..a8865cab2f60ae872aa487181d761973191e9a95 100644 --- a/backend/dvadmin/system/views/role_menu_button_permission.py +++ b/backend/dvadmin/system/views/role_menu_button_permission.py @@ -11,7 +11,8 @@ from rest_framework import serializers from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated -from dvadmin.system.models import RoleMenuButtonPermission, Menu, MenuButton, Dept, RoleMenuPermission, Columns +from dvadmin.system.models import RoleMenuButtonPermission, Menu, MenuButton, Dept, RoleMenuPermission, FieldPermission, \ + MenuField from dvadmin.system.views.menu import MenuSerializer from dvadmin.utils.json_response import DetailResponse, ErrorResponse from dvadmin.utils.serializers import CustomModelSerializer @@ -71,12 +72,41 @@ class RoleButtonPermissionSerializer(CustomModelSerializer): model = MenuButton fields = ['id','name','value','isCheck','data_range'] -class RoleColumnsSerializer(CustomModelSerializer): +class RoleFieldPermissionSerializer(CustomModelSerializer): class Meta: - model = Columns + model = FieldPermission fields = "__all__" +class RoleMenuFieldSerializer(CustomModelSerializer): + is_query = serializers.SerializerMethodField() + is_create = serializers.SerializerMethodField() + is_update = serializers.SerializerMethodField() + + def get_is_query(self, instance): + params = self.request.query_params + queryset = instance.menu_field.filter(role=params.get('role')).first() + if queryset: + return queryset.is_query + return False + + def get_is_create(self, instance): + params = self.request.query_params + queryset = instance.menu_field.filter(role=params.get('role')).first() + if queryset: + return queryset.is_create + return False + + def get_is_update(self, instance): + params = self.request.query_params + queryset = instance.menu_field.filter(role=params.get('role')).first() + if queryset: + return queryset.is_update + return False + class Meta: + model = MenuField + fields = ['id','field_name','title','is_query','is_create','is_update'] + class RoleMenuPermissionSerializer(CustomModelSerializer): """ @@ -99,9 +129,8 @@ class RoleMenuPermissionSerializer(CustomModelSerializer): return serializer.data def get_columns(self, instance): - params = self.request.query_params - col_list = Columns.objects.filter(role__id=params.get('role'),menu__id=instance['id']) - serializer = RoleColumnsSerializer(col_list,many=True,request=self.request) + col_list = MenuField.objects.filter(menu=instance['id']) + serializer = RoleMenuFieldSerializer(col_list,many=True,request=self.request) return serializer.data @@ -165,10 +194,11 @@ class RoleMenuButtonPermissionViewSet(CustomModelViewSet): RoleMenuPermission.objects.create(role_id=pk, menu_id=menu.get('id')) for btn in menu.get('btns'): if btn.get('isCheck'): - instance = RoleMenuButtonPermission.objects.create(role_id=pk, menu_button_id=btn.get('id'),data_range=btn.get('data_range')) + data_range = btn.get('data_range',0) or 0 + instance = RoleMenuButtonPermission.objects.create(role_id=pk, menu_button_id=btn.get('id'),data_range=data_range) instance.dept.set(btn.get('dept',[])) for col in menu.get('columns'): - Columns.objects.filter(id=col.get('id')).update(is_query=col.get('is_query'),is_create=col.get('is_create'),is_update=col.get('is_update')) + FieldPermission.objects.update_or_create(role_id=pk,field_id=col.get('id'),is_query=col.get('is_query'),is_create=col.get('is_create'),is_update=col.get('is_update')) return DetailResponse(msg="授权成功") diff --git a/backend/dvadmin/system/views/user.py b/backend/dvadmin/system/views/user.py index 1d71c4e385fda8157be52165c3cd4e83df74a0e0..8f4a57c99373f140d7b1fe221c1e0dc2f33febae 100644 --- a/backend/dvadmin/system/views/user.py +++ b/backend/dvadmin/system/views/user.py @@ -352,6 +352,8 @@ class UserViewSet(CustomModelViewSet): """ 密码重置 """ + if not self.request.user.is_superuser: + return ErrorResponse(msg="只允许超级管理员对其进行密码重置") instance = Users.objects.filter(id=pk).first() data = request.data new_pwd = data.get("newPassword") diff --git a/backend/dvadmin/utils/field_permission.py b/backend/dvadmin/utils/field_permission.py index 939381bd9fd00ead96ca00fbd48607e1b63c0038..20b4cb95310b7951531ac48f22ae58b833591ada 100644 --- a/backend/dvadmin/utils/field_permission.py +++ b/backend/dvadmin/utils/field_permission.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- +from django.db.models import F from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated -from dvadmin.system.models import Columns +from dvadmin.system.models import FieldPermission, MenuField from dvadmin.utils.json_response import DetailResponse from dvadmin.utils.models import get_custom_app_models @@ -14,25 +15,24 @@ class FieldPermissionMixin: 获取字段权限 """ finded = False - for app in get_custom_app_models(): - for model in app: - if model['object'] is self.serializer_class.Meta.model: - finded = True - break + for model in get_custom_app_models(): + if model['object'] is self.serializer_class.Meta.model: + finded = True + break if finded: break if finded is False: return [] - roles = request.user.role.values_list('id', flat=True) user = request.user if user.is_superuser==1: - data = Columns.objects.filter(app=model['app'], model=model['model']).values('field_name', 'is_create', 'is_query', 'is_update') + data = MenuField.objects.filter( model=model['model']).values('field_name') for item in data: item['is_create'] = True item['is_query'] = True item['is_update'] = True else: - data= Columns.objects.filter( - app=model['app'], model=model['model'],role__in=roles - ).values('field_name', 'is_create', 'is_query', 'is_update') + roles = request.user.role.values_list('id', flat=True) + data= FieldPermission.objects.filter( + field__model=model['model'],role__in=roles + ).values( 'is_create', 'is_query', 'is_update',field_name=F('field__field_name')) return DetailResponse(data=data) \ No newline at end of file diff --git a/backend/dvadmin/utils/filters.py b/backend/dvadmin/utils/filters.py index dbd921fa3c3fd1cba3a8de8c6b9b58e4d1f109ba..06dba2e7ba351d511c3f8297029289d1f5c4ccf1 100644 --- a/backend/dvadmin/utils/filters.py +++ b/backend/dvadmin/utils/filters.py @@ -121,13 +121,12 @@ class DataLevelPermissionsFilter(BaseFilterBackend): role__status=1, menu_button__api=re_api, menu_button__method=method).values( - 'data_range', - role_admin=F('role__admin') + 'data_range' ) dataScope_list = [] # 权限范围列表 for ele in role_permission_list: # 判断用户是否为超级管理员角色/如果拥有[全部数据权限]则返回所有数据 - if ele.get("data_range") == 3 or ele.get("role_admin") == True: + if ele.get("data_range") == 3: return queryset dataScope_list.append(ele.get("data_range")) dataScope_list = list(set(dataScope_list)) diff --git a/backend/dvadmin/utils/models.py b/backend/dvadmin/utils/models.py index 4ec619d563b9a9595fe062479a41cf520ba37228..fb0c2ba70a5035c540634a773fe25815246e50d6 100644 --- a/backend/dvadmin/utils/models.py +++ b/backend/dvadmin/utils/models.py @@ -13,6 +13,7 @@ from django.db import models from django.conf import settings from application import settings + table_prefix = settings.TABLE_PREFIX # 数据库表名前缀 @@ -71,10 +72,13 @@ class CoreModel(models.Model): id = models.BigAutoField(primary_key=True, help_text="Id", verbose_name="Id") description = models.CharField(max_length=255, verbose_name="描述", null=True, blank=True, help_text="描述") creator = models.ForeignKey(to=settings.AUTH_USER_MODEL, related_query_name='creator_query', null=True, - verbose_name='创建人', help_text="创建人", on_delete=models.SET_NULL, db_constraint=False) + verbose_name='创建人', help_text="创建人", on_delete=models.SET_NULL, + db_constraint=False) modifier = models.CharField(max_length=255, null=True, blank=True, help_text="修改人", verbose_name="修改人") - dept_belong_id = models.CharField(max_length=255, help_text="数据归属部门", null=True, blank=True, verbose_name="数据归属部门") - update_datetime = models.DateTimeField(auto_now=True, null=True, blank=True, help_text="修改时间", verbose_name="修改时间") + dept_belong_id = models.CharField(max_length=255, help_text="数据归属部门", null=True, blank=True, + verbose_name="数据归属部门") + update_datetime = models.DateTimeField(auto_now=True, null=True, blank=True, help_text="修改时间", + verbose_name="修改时间") create_datetime = models.DateTimeField(auto_now_add=True, null=True, blank=True, help_text="创建时间", verbose_name="创建时间") @@ -136,10 +140,23 @@ def get_model_from_app(app_name): def get_custom_app_models(app_name=None): - """获取所有项目写的app里的models""" + """ + 获取所有项目下的app里的models + """ if app_name: return get_model_from_app(app_name) + all_apps = apps.get_app_configs() res = [] - for app in settings.CUSTOM_APPS: - res.append(get_model_from_app(app)) + for app in all_apps: + if app.name.startswith('django'): + continue + if app.name in settings.COLUMN_EXCLUDE_APPS: + continue + try: + all_models = get_model_from_app(app.name) + if all_models: + for model in all_models: + res.append(model) + except Exception as e: + pass return res diff --git a/backend/dvadmin/utils/pagination.py b/backend/dvadmin/utils/pagination.py index 52bf143dc579cedc7c2fec0e2e11b7a68028443e..5e80e57d46cd33d1eebe41dbb51186317e239f00 100644 --- a/backend/dvadmin/utils/pagination.py +++ b/backend/dvadmin/utils/pagination.py @@ -79,6 +79,5 @@ class CustomPagination(PageNumberPagination): ('total', total), ('is_next', is_next), ('is_previous', is_previous), - ('data', data), - ('permission', self.request.permission_fields) + ('data', data) ])) diff --git a/backend/dvadmin/utils/viewset.py b/backend/dvadmin/utils/viewset.py index a46200323cf32d646f87663d5be43369845b6dae..a20b9be261cd2f08afd929a262a7e41bf063686c 100644 --- a/backend/dvadmin/utils/viewset.py +++ b/backend/dvadmin/utils/viewset.py @@ -17,7 +17,7 @@ from dvadmin.utils.import_export_mixin import ExportSerializerMixin, ImportSeria from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse from dvadmin.utils.permission import CustomPermission from dvadmin.utils.models import get_custom_app_models -from dvadmin.system.models import Columns +from dvadmin.system.models import FieldPermission, MenuField from django_restql.mixins import QueryArgumentsMixin @@ -64,7 +64,7 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi serializer_class = self.get_serializer_class() kwargs.setdefault('context', self.get_serializer_context()) # 全部以可见字段为准 - can_see = self.get_column_permission(serializer_class) + can_see = self.get_menu_field(serializer_class) # 排除掉序列化器级的字段 # sub_set = set(serializer_class._declared_fields.keys()) - set(can_see) # for field in sub_set: @@ -79,21 +79,17 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi else: return serializer_class(*args, **kwargs) - def get_column_permission(self, serializer_class): - """获取列权限""" + def get_menu_field(self, serializer_class): + """获取字段权限""" finded = False - for app in get_custom_app_models(): - for model in app: - if model['object'] is serializer_class.Meta.model: - finded = True - break - if finded: + for model in get_custom_app_models(): + if model['object'] is serializer_class.Meta.model: + finded = True break if finded is False: return [] - return Columns.objects.filter( - app=model['app'], model=model['model'] - ).values('field_name', 'is_create', 'is_query', 'is_update') + return MenuField.objects.filter(model=model['model'] + ).values('field_name', 'title') def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data, request=request) diff --git a/backend/requirements.txt b/backend/requirements.txt index b6b068d7fd8a6d9529a941515cdc6778736dbc32..d433efbd107e13f7278b5b74ab936e30e7beee8b 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,31 +1,30 @@ -Django==4.1.5 +Django==4.2.7 django-comment-migrate==0.1.7 -django-cors-headers==3.13.0 -django-filter==21.1 +django-cors-headers==4.3.0 +django-filter==23.3 django-ranged-response==0.2.0 djangorestframework==3.14.0 django-restql==0.15.3 -django-simple-captcha==0.5.17 -django-timezone-field==5.0 -djangorestframework-simplejwt==5.2.2 -drf-yasg==1.21.4 -mysqlclient==2.1.1 -pypinyin==0.48.0 -ua-parser==0.16.1 -pyparsing==3.0.9 -openpyxl==3.0.10 -requests==2.28.2 -typing-extensions==4.4.0 -smmap==5.0.0 -tzlocal==4.1 +django-simple-captcha==0.5.20 +django-timezone-field==6.0.1 +djangorestframework-simplejwt==5.3.0 +drf-yasg==1.21.7 +mysqlclient==2.2.0 +pypinyin==0.49.0 +ua-parser==0.18.0 +pyparsing==3.1.1 +openpyxl==3.1.2 +requests==2.31.0 +typing-extensions==4.8.0 +tzlocal==5.1 channels==4.0.0 -channels-redis==4.0.0 -websockets==10.4 +channels-redis==4.1.0 +websockets==11.0.3 user-agents==2.2.0 six==1.16.0 -whitenoise==6.3.0 -psycopg2==2.9.5 -uvicorn==0.21.1 -gunicorn==20.1.0 -gevent==22.10.2 -Pillow==8.3.2 +whitenoise==6.6.0 +psycopg2==2.9.9 +uvicorn==0.23.2 +gunicorn==21.2.0 +gevent==23.9.1 +Pillow==10.1.0 diff --git a/docker_env/nginx/my.conf b/docker_env/nginx/my.conf index 30fa2108d1ae318b5841bfb237d389444a241ad1..e1db0b7a229c3b791965485007f4e35707fae6ea 100644 --- a/docker_env/nginx/my.conf +++ b/docker_env/nginx/my.conf @@ -28,6 +28,6 @@ server { proxy_send_timeout 600s; real_ip_header X-Forwarded-For; rewrite ^/api/(.*)$ /$1 break; #重写 - proxy_pass http://177.8.0.12:8000/; # 设置代理服务器的协议和地址 + proxy_pass http://177.10.0.12:8000/; # 设置代理服务器的协议和地址 } } diff --git a/docker_env/web/Dockerfile b/docker_env/web/Dockerfile index 7f7fc2b521e80845fbbd24964d5ca6f156b1b1a0..9d465d10089f2effa97b5bab1bb26c92b6558578 100644 --- a/docker_env/web/Dockerfile +++ b/docker_env/web/Dockerfile @@ -1,7 +1,7 @@ FROM registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/dvadmin3-base-web:16.19-alpine WORKDIR /web/ COPY web/. . -RUN yarn install +RUN yarn install --registry=https://registry.npm.taobao.org RUN yarn build FROM nginx:alpine diff --git a/web/.env.development b/web/.env.development index 1c3ca5db362e1f7935aded834e08f0a46ed640a6..dc36b291b2cdf3991de42c0cb05648f397f5e173 100644 --- a/web/.env.development +++ b/web/.env.development @@ -2,7 +2,7 @@ ENV = 'development' # 本地环境接口地址 -VITE_API_URL = 'http://127.0.0.1:8000' +VITE_API_URL = 'http://127.0.0.1:8001' # 是否启用按钮权限 VITE_PM_ENABLED = true diff --git a/web/README.en.md b/web/README.en.md new file mode 100644 index 0000000000000000000000000000000000000000..d8ca1721cdac7a15babc14971e4bca7634009e93 --- /dev/null +++ b/web/README.en.md @@ -0,0 +1,168 @@ +# Django-Vue3-Admin + +[![img](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitee.com/huge-dream/django-vue3-admin/blob/master/LICENSE) [![img](https://img.shields.io/badge/python-%3E=3.7.x-green.svg)](https://python.org/) [![PyPI - Django Version badge](https://img.shields.io/badge/django%20versions-3.2-blue)](https://docs.djangoproject.com/zh-hans/3.2/) [![img](https://img.shields.io/badge/node-%3E%3D%2012.0.0-brightgreen)](https://nodejs.org/zh-cn/) [![img](https://gitee.com/huge-dream/django-vue3-admin/badge/star.svg?theme=dark)](https://gitee.com/huge-dream/django-vue3-admin) + +[preview](https://demo.dvadmin.com) | [Official website document](https://www.django-vue-admin.com) | [qq group](https://qm.qq.com/cgi-bin/qm/qr?k=fOdnHhC8DJlRHGYSnyhoB8P5rgogA6Vs&jump_from=webapi) | [community](https://bbs.django-vue-admin.com) | [plugins market](https://bbs.django-vue-admin.com/plugMarket.html) | [Github](https://github.com/liqianglog/django-vue-admin) + +💡 **「About」** + +We are a group of young people who love Code. In this hot era, we hope to calm down and bring some of our colors and colors through code. + +Because of love, so embrace the future + +## framework introduction + +💡 [django-vue3-admin](https://gitee.com/huge-dream/django-vue3-admin.git) Is a set of all open source rapid development platform, no reservation for individuals and enterprises free use. + +* 🧑‍🤝‍🧑Front-end adoption Vue3+TS+pinia+fastcrud。 +* 👭The backend uses the Python language Django framework as well as the powerful[Django REST Framework](https://pypi.org/project/djangorestframework)。 +* 👫Permission authentication use[Django REST Framework SimpleJWT](https://pypi.org/project/djangorestframework-simplejwt),Supports the multi-terminal authentication system. +* 👬Support loading dynamic permission menu, multi - way easy permission control. +* 💏 Special thanks: [vue-next-admin](https://lyt-top.gitee.io/vue-next-admin-doc-preview/). +* 💡 💏 Special thanks:[jetbrains](https://www.jetbrains.com/) To provide a free IntelliJ IDEA license for this open source project. + +## Online experience + +👩‍👧‍👦👩‍👧‍👦 demo address:[https://demo.dvadmin.com](https://demo.dvadmin.com) + +* demo account:superadmin + +* demo password:admin123456 + +👩‍👦‍👦docs:[https://django-vue-admin.com](https://django-vue-admin.com) + +## communication + +* Communication community:[click here](https://bbs.django-vue-admin.com)👩‍👦‍👦 + +* plugins market:[click here](https://bbs.django-vue-admin.com/plugMarket.html)👩‍👦‍👦 + +## source code url: + +gitee(Main push):[https://gitee.com/huge-dream/django-vue3-admin](https://gitee.com/huge-dream/django-vue3-admin)👩‍👦‍👦 + +github:no data + +## core function + +1. 👨‍⚕️ Menu management: Configure the system menu, operation permissions, button permissions, back-end interface permissions, etc. +2. 🧑‍⚕️ Department management: Configure the system organization (company, department, role). +3. 👩‍⚕️ Role management: role menu permission allocation, data permission allocation, set roles according to the department for data range permission division. +4. 🧑‍🎓 Rights Specifies the rights of the authorization role. +5. 👨‍🎓 User management: The user is the system operator, this function mainly completes the system user configuration. +6. 👬 Interface whitelist: specifies the interface that does not need permission verification. +7. 🧑‍🔧 Dictionary management: Maintenance of some fixed data frequently used in the system. +8. 🧑‍🔧 Regional management: to manage provinces, cities, counties and regions. +9. 📁 Attachment management: Unified management of all files and pictures on the platform. +10. 🗓 ️operation logs: log and query the system normal operation; Log and query system exception information. + 11.🔌 [plugins market] () : based on the Django framework - Vue - Admin application and plug-in development. + +## plugins market 🔌 + +* Celery Asynchronous task:[dvadmin-celery](https://gitee.com/huge-dream/dvadmin-celery) +* Upgrade center backend:[dvadmin-upgrade-center](https://gitee.com/huge-dream/dvadmin-upgrade-center) +* Upgrade center front:[dvadmin-upgrade-center-web](https://gitee.com/huge-dream/dvadmin-upgrade-center-web) + +## before start project you need: + +~~~ +Python >= 3.8.0 +nodejs >= 14.0 +Mysql >= 5.7.0 (Optional. The default database is sqlite3. 8.0 is recommended) +Redis(Optional, the latest edition) +~~~ + +## frontend♝ + +```bash +# clone code +git clone https://gitee.com/huge-dream/django-vue3-admin.git + +# enter code dir +cd web + +# install dependence +npm install --registry=https://registry.npm.taobao.org + +# Start service +npm run dev +# Visit http://localhost:8080 in your browser +# Parameters such as boot port can be configured in the #.env.development file +# Build the production environment +# npm run build +``` + +## backend💈 + +~~~bash +1. enter code dir cd backend +2. copy ./conf/env.example.py to ./conf dir,rename as env.py +3. in env.py configure database information + mysql database recommended version: 8.0 + mysql database character set: utf8mb4 +4. install pip dependence + pip3 install -r requirements.txt +5. Execute the migration command: + python3 manage.py makemigrations + python3 manage.py migrate +6. Initialization data + python3 manage.py init +7. Initialize provincial, municipal and county data: + python3 manage.py init_area +8. start backend + python3 manage.py runserver 0.0.0.0:8000 +or daphne : + daphne -b 0.0.0.0 -p 8000 application.asgi:application +~~~ + +### visit backend swagger + +* visit url:[http://localhost:8080](http://localhost:8080) (The default address is this one. If you want to change it, follow the configuration file) +* account:`superadmin` password:`admin123456` + +### docker-compose + +~~~shell +docker-compose up -d +# Initialize backend data (first execution only) +docker exec -ti dvadmin-django bash +python manage.py makemigrations +python manage.py migrate +python manage.py init_area +python manage.py init +exit + +frontend url:http://127.0.0.1:8080 +backend url:http://127.0.0.1:8080/api +# Change 127.0.0.1 to your own public ip address on the server +account:`superadmin` password:`admin123456` + +# docker-compose stop +docker-compose down +# docker-compose restart +docker-compose restart +# docker-compose on start build +docker-compose up -d --build +~~~ + +## Demo screenshot✅ + +![image-01](https://images.gitee.com/uploads/images/2022/0530/234137_b58c8f98_5074988.png) + +![image-02](https://images.gitee.com/uploads/images/2022/0530/234240_39834603_5074988.png) + +![image-03](https://images.gitee.com/uploads/images/2022/0530/234339_35e728a0_5074988.png) + +![image-04](https://images.gitee.com/uploads/images/2022/0530/234426_957036b0_5074988.png) + +![image-05](https://images.gitee.com/uploads/images/2022/0530/234458_898be492_5074988.png) + +![image-06](https://images.gitee.com/uploads/images/2022/0530/234521_35b40076_5074988.png) + +![image-07](https://images.gitee.com/uploads/images/2022/0530/234615_c2325639_5074988.png) + +![image-08](https://images.gitee.com/uploads/images/2022/0530/234639_1ed6cc93_5074988.png) + +![image-09](https://images.gitee.com/uploads/images/2022/0530/234815_cea2c53f_5074988.png) + +![image-10](https://images.gitee.com/uploads/images/2022/0530/234840_5f3e5f53_5074988.png) diff --git a/web/README.md b/web/README.md index 99cc0ce3f2b28f600ce637cdac0e15ed76c6fd6d..e70cc71da1995900a70d45a53017b86fde915a0c 100644 --- a/web/README.md +++ b/web/README.md @@ -1,8 +1,32 @@ -
django-vue3-admin:web
+# Django-Vue3-Admin -#### 🌈 介绍 +[![img](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitee.com/liqianglog/django-vue-admin/blob/master/LICENSE) [![img](https://img.shields.io/badge/python-%3E=3.7.x-green.svg)](https://python.org/) [![PyPI - Django Version badge](https://img.shields.io/badge/django%20versions-3.2-blue)](https://docs.djangoproject.com/zh-hans/3.2/) [![img](https://img.shields.io/badge/node-%3E%3D%2012.0.0-brightgreen)](https://nodejs.org/zh-cn/) [![img](https://gitee.com/liqianglog/django-vue-admin/badge/star.svg?theme=dark)](https://gitee.com/liqianglog/django-vue-admin) -django-vue3-admin,基于 vue3 + CompositionAPI + typescript + vite + element plus, 是一款全栈,快速,开源的后台管理系统! +[预 览](https://demo.dvadmin.com) | [官网文档](https://www.django-vue-admin.com) | [群聊](https://qm.qq.com/cgi-bin/qm/qr?k=fOdnHhC8DJlRHGYSnyhoB8P5rgogA6Vs&jump_from=webapi) | [社区](https://bbs.django-vue-admin.com) | [插件市场](https://bbs.django-vue-admin.com/plugMarket.html) | [Github](https://github.com/liqianglog/django-vue-admin) + + + +💡 **「关于」** + +我们是一群热爱代码的青年,在这个炙热的时代下,我们希望静下心来通过Code带来一点我们的色彩和颜色。 + +因为热爱,所以拥抱未来! + + +## 平台简介 + +💡 [django-vue3-admin](https://gitee.com/huge-dream/django-vue3-admin.git) 是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 + django-vue3-admin 基于 vue3 + CompositionAPI + typescript + vite + element plus, 是一款全栈,快速,开源的后台管理系统! + + + + +* 🧑‍🤝‍🧑前端采用 Vue3+TS+pinia+fastcrud(感谢[vue-next-admin](https://lyt-top.gitee.io/vue-next-admin-doc-preview/)) +* 👭后端采用 Python 语言 Django 框架以及强大的 [Django REST Framework](https://pypi.org/project/djangorestframework)。 +* 👫权限认证使用[Django REST Framework SimpleJWT](https://pypi.org/project/djangorestframework-simplejwt),支持多终端认证系统。 +* 👬支持加载动态权限菜单,多方式轻松权限控制。 +* 💏特别鸣谢:[vue-next-admin](https://lyt-top.gitee.io/vue-next-admin-doc-preview/)。 +* 💡 特别感谢[jetbrains](https://www.jetbrains.com/) 为本开源项目提供免费的 IntelliJ IDEA 授权。 #### 🏭 环境支持 @@ -12,21 +36,173 @@ django-vue3-admin,基于 vue3 + CompositionAPI + typescript + vite + element p > 由于 Vue3 不再支持 IE11,故而 ElementPlus 也不支持 IE11 及之前版本。 -#### ⚡ 使用说明 -建议使用 yarn,yarn 是一个类似于npm的包管理器 node 版本 > 16 + +## 在线体验 + +👩‍👧‍👦演示地址:[https://demo.dvadmin.com](https://demo.dvadmin.com) + +- 账号:superadmin + +- 密码:admin123456 + +👩‍👦‍👦文档地址:[coding](https://dvadmin-private.coding.net/share/km/cec69f3d-30fe-47d5-bd97-e9e851f0b776/K-2) + + + +## 交流 + +- 交流社区:[戳我](https://bbs.django-vue-admin.com)👩‍👦‍👦 + +- 插件市场:[戳我](https://bbs.django-vue-admin.com/plugMarket.html)👩‍👦‍👦 + +- django-vue-admin交流01群(已满):812482043 [点击链接加入群聊](https://qm.qq.com/cgi-bin/qm/qr?k=aJVwjDvH-Es4MPJQuoO32N0SucK22TE5&jump_from=webapi) +- django-vue-admin交流02群(已满):687252418 [点击链接加入群聊](https://qm.qq.com/cgi-bin/qm/qr?k=4jJN4IjWGfxJ8YJXbb_gTsuWjR34WLdc&jump_from=webapi) +- django-vue-admin交流03群:442108213 [点击链接加入群聊](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=wsm5oSz3K8dElBYUDtLTcQSEPhINFkl8&authKey=M6sbER0z59ZakgBr5erFeZyFZU15CI52bErNZa%2FxSvvGIuVAbY0N5866v89hm%2FK4&noverify=0&group_code=442108213) + +- 二维码 + + + +## 源码地址 + +gitee地址(主推):[https://gitee.com/huge-dream/django-vue3-admin](https://gitee.com/huge-dream/django-vue3-admin)👩‍👦‍👦 + +github地址:暂无 + + +## 内置功能 + +1. 👨‍⚕️菜单管理:配置系统菜单,操作权限,按钮权限标识、后端接口权限等。 +2. 🧑‍⚕️部门管理:配置系统组织机构(公司、部门、角色)。 +3. 👩‍⚕️角色管理:角色菜单权限分配、数据权限分配、设置角色按部门进行数据范围权限划分。 +4. 🧑‍🎓按钮权限权限:授权角色的按钮权限和接口权限,可做到每一个接口都能授权数据范围。 +5. 🧑‍🎓字段权限权限:授权页面的字段显示权限。 +5. 👨‍🎓用户管理:用户是系统操作者,该功能主要完成系统用户配置。 +6. 👬接口白名单:配置不需要进行权限校验的接口。 +7. 🧑‍🔧字典管理:对系统中经常使用的一些较为固定的数据进行维护。 +8. 🧑‍🔧地区管理:对省市县区域进行管理。 +9. 📁附件管理:对平台上所有文件、图片等进行统一管理。 +10. 🗓️操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +11. 🔌[插件市场 ](https://bbs.django-vue-admin.com/plugMarket.html):基于Django-Vue-Admin框架开发的应用和插件。 + +## 插件市场 🔌 + +- Celery异步任务:[dvadmin-celery](https://gitee.com/huge-dream/dvadmin-celery) +- 升级中心后端:[dvadmin-upgrade-center](https://gitee.com/huge-dream/dvadmin-upgrade-center) +- 升级中心前端:[dvadmin-upgrade-center-web](https://gitee.com/huge-dream/dvadmin-upgrade-center-web) + +## 准备工作 +~~~ +Python >= 3.8.0 (推荐3.8+版本) +nodejs >= 14.0 (推荐最新) +Mysql >= 5.7.0 (可选,默认数据库sqlite3,推荐8.0版本) +Redis(可选,最新版) +~~~ + +## 前端♝ ```bash +# 克隆项目 +git clone https://gitee.com/huge-dream/django-vue3-admin.git -# 进入项目 -cd django-vue-admin/web +# 进入项目目录 +cd web # 安装依赖 -yarn install +npm install --registry=https://registry.npm.taobao.org + +# 启动服务 +npm run dev +# 浏览器访问 http://localhost:8080 +# .env.development 文件中可配置启动端口等参数 +# 构建生产环境 +# npm run build +``` + + + +## 后端💈 + +~~~bash +1. 进入项目目录 cd backend +2. 在项目根目录中,复制 ./conf/env.example.py 文件为一份新的到 ./conf 文件夹下,并重命名为 env.py +3. 在 env.py 中配置数据库信息 + mysql数据库版本建议:8.0 + mysql数据库字符集:utf8mb4 +4. 安装依赖环境 + pip3 install -r requirements.txt +5. 执行迁移命令: + python3 manage.py makemigrations + python3 manage.py migrate +6. 初始化数据 + python3 manage.py init +7. 初始化省市县数据: + python3 manage.py init_area +8. 启动项目 + python3 manage.py runserver 0.0.0.0:8000 +或使用 daphne : + daphne -b 0.0.0.0 -p 8000 application.asgi:application +~~~ + +### 访问项目 + +- 访问地址:[http://localhost:8080](http://localhost:8080) (默认为此地址,如有修改请按照配置文件) +- 账号:`superadmin` 密码:`admin123456` + + + + + +### docker-compose 运行 + +~~~shell +# 先安装docker-compose (自行百度安装),执行此命令等待安装,如有使用celery插件请打开docker-compose.yml中celery 部分注释 +docker-compose up -d +# 初始化后端数据(第一次执行即可) +docker exec -ti dvadmin-django bash +python manage.py makemigrations +python manage.py migrate +python manage.py init_area +python manage.py init +exit + +前端地址:http://127.0.0.1:8080 +后端地址:http://127.0.0.1:8080/api +# 在服务器上请把127.0.0.1 换成自己公网ip +账号:superadmin 密码:admin123456 + +# docker-compose 停止 +docker-compose down +# docker-compose 重启 +docker-compose restart +# docker-compose 启动时重新进行 build +docker-compose up -d --build +~~~ + + + +## 演示图✅ + +![image-01](https://images.gitee.com/uploads/images/2022/0530/234137_b58c8f98_5074988.png) + +![image-02](https://images.gitee.com/uploads/images/2022/0530/234240_39834603_5074988.png) + +![image-03](https://images.gitee.com/uploads/images/2022/0530/234339_35e728a0_5074988.png) + +![image-04](https://images.gitee.com/uploads/images/2022/0530/234426_957036b0_5074988.png) + +![image-05](https://images.gitee.com/uploads/images/2022/0530/234458_898be492_5074988.png) + +![image-06](https://images.gitee.com/uploads/images/2022/0530/234521_35b40076_5074988.png) + +![image-07](https://images.gitee.com/uploads/images/2022/0530/234615_c2325639_5074988.png) + +![image-08](https://images.gitee.com/uploads/images/2022/0530/234639_1ed6cc93_5074988.png) + +![image-09](https://images.gitee.com/uploads/images/2022/0530/234815_cea2c53f_5074988.png) + +![image-10](https://images.gitee.com/uploads/images/2022/0530/234840_5f3e5f53_5074988.png) + -# 运行项目 -yarn dev -# 打包发布 -yarn build -``` \ No newline at end of file diff --git a/web/index.html b/web/index.html index 2fcf37bc45ab08406632f696d1623800b9cf3aa0..9515e84b71affad9064130809ddf03581b3cf9cc 100644 --- a/web/index.html +++ b/web/index.html @@ -10,23 +10,22 @@ /> - django-vue3-admin + django-vue-admin -
- - - +
+ + diff --git a/web/package.json b/web/package.json index 6bb8ef90dee8d9b3744800be17f07d9b5f78a5fc..28b837f96ccccb1fa78ffe53995a7f3a04974eca 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "django-vue3-admin", - "version": "1.0.0", - "description": "django-vue3-admin,基于 vue3 + CompositionAPI + typescript + vite + element plus, 是一款全栈,快速,开源的后台管理系统!", + "version": "3.0.0", + "description": "是一套全部开源的快速开发平台,毫无保留给个人免费使用、团体授权使用。\n django-vue3-admin 基于RBAC模型的权限控制的一整套基础开发平台,权限粒度达到列级别,前后端分离,后端采用django + django-rest-framework,前端采用基于 vue3 + CompositionAPI + typescript + vite + element plus", "license": "MIT", "scripts": { "dev": "vite --force", @@ -10,10 +10,10 @@ }, "dependencies": { "@element-plus/icons-vue": "^2.0.10", - "@fast-crud/fast-crud": "^1.14.7", - "@fast-crud/fast-extends": "^1.14.7", - "@fast-crud/ui-element": "^1.14.7", - "@fast-crud/ui-interface": "^1.14.7", + "@fast-crud/fast-crud": "^1.19.2", + "@fast-crud/fast-extends": "^1.19.2", + "@fast-crud/ui-element": "^1.19.2", + "@fast-crud/ui-interface": "^1.19.2", "@vitejs/plugin-vue-jsx": "^3.0.0", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.12", @@ -44,6 +44,7 @@ "splitpanes": "^3.1.5", "tailwindcss": "^3.2.7", "ts-md5": "^1.3.1", + "upgrade": "^1.1.0", "vue": "^3.2.45", "vue-clipboard3": "^2.0.0", "vue-cropper": "^1.0.8", @@ -61,7 +62,7 @@ "@typescript-eslint/parser": "^5.46.0", "@vitejs/plugin-vue": "^4.0.0", "@vue/compiler-sfc": "^3.2.45", - "eslint": "^8.29.0", + "eslint": "^8.54.0", "eslint-plugin-vue": "^9.8.0", "prettier": "^2.8.1", "sass": "^1.56.2", diff --git a/web/src/App.vue b/web/src/App.vue index ec824fa431e9452586f5ebbc0efbb0779b0f050e..caa36ca0cc69e69473ad6dba6e0d31746846eba9 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -59,12 +59,6 @@ onBeforeMount(() => { setIntroduction.cssCdn(); // 设置批量第三方 js setIntroduction.jsCdn(); - //websockt 模块 - try { - //websocket.init(wsReceive) - } catch (e) { - console.log('websocket错误'); - } }); // 页面加载时 onMounted(() => { @@ -93,6 +87,14 @@ watch( () => route.path, () => { other.useTitle(); + if (!websocket.websocket) { + //websockt 模块 + try { + websocket.init(wsReceive) + } catch (e) { + console.log('websocket错误'); + } + } }, { deep: true, diff --git a/web/src/assets/img/headerImage.png b/web/src/assets/img/headerImage.png new file mode 100644 index 0000000000000000000000000000000000000000..d3eb252d438ae5228742ca42639018f440513111 Binary files /dev/null and b/web/src/assets/img/headerImage.png differ diff --git a/web/src/i18n/lang/en.ts b/web/src/i18n/lang/en.ts index 3b6541b602d658a0fd2dc97c881516d204e8ae6b..72189758777db976c1bd2c33d8ee89fce885f827 100644 --- a/web/src/i18n/lang/en.ts +++ b/web/src/i18n/lang/en.ts @@ -1,123 +1,131 @@ // 定义内容 export default { - router: { - home: 'home', - system: 'system', - systemMenu: 'systemMenu', - systemRole: 'systemRole', - systemUser: 'systemUser', - systemDept: 'systemDept', - systemDic: 'systemDic', - limits: 'limits', - limitsFrontEnd: 'FrontEnd', - limitsFrontEndPage: 'FrontEndPage', - limitsFrontEndBtn: 'FrontEndBtn', - limitsBackEnd: 'BackEnd', - limitsBackEndEndPage: 'BackEndEndPage', - personal: 'personal', - }, - staticRoutes: { - signIn: 'signIn', - notFound: 'notFound', - noPower: 'noPower', - }, - user: { - title0: 'Component size', - title1: 'Language switching', - title2: 'Menu search', - title3: 'Layout configuration', - title4: 'news', - title5: 'Full screen on', - title6: 'Full screen off', - dropdownLarge: 'large', - dropdownDefault: 'default', - dropdownSmall: 'small', - dropdown1: 'home page', - dropdown2: 'Personal Center', - dropdown3: '404', - dropdown4: '401', - dropdown5: 'Log out', - dropdown6: 'Code warehouse', - searchPlaceholder: 'Menu search: support Chinese, routing path', - newTitle: 'notice', - newBtn: 'All read', - newGo: 'Go to the notification center', - newDesc: 'No notice', - logOutTitle: 'Tips', - logOutMessage: 'This operation will log out. Do you want to continue?', - logOutConfirm: 'determine', - logOutCancel: 'cancel', - logOutExit: 'Exiting', - }, - tagsView: { - refresh: 'refresh', - close: 'close', - closeOther: 'closeOther', - closeAll: 'closeAll', - fullscreen: 'fullscreen', - closeFullscreen: 'closeFullscreen', - }, - notFound: { - foundTitle: 'Wrong address input, please re-enter the address~', - foundMsg: 'You can check the web address first, and then re-enter or give us feedback.', - foundBtn: 'Back to home page', - }, - noAccess: { - accessTitle: 'You are not authorized to operate~', - accessMsg: 'Contact information: add QQ group discussion 665452019', - accessBtn: 'Reauthorization', - }, - layout: { - configTitle: 'Layout configuration', - oneTitle: 'Global Themes', - twoTopTitle: 'top bar set up', - twoMenuTitle: 'Menu set up', - twoColumnsTitle: 'Columns set up', - twoTopBar: 'Top bar background', - twoTopBarColor: 'Top bar default font color', - twoIsTopBarColorGradual: 'Top bar gradient', - twoMenuBar: 'Menu background', - twoMenuBarColor: 'Menu default font color', - twoIsMenuBarColorGradual: 'Menu gradient', - twoColumnsMenuBar: 'Column menu background', - twoColumnsMenuBarColor: 'Default font color bar menu', - twoIsColumnsMenuBarColorGradual: 'Column gradient', - threeTitle: 'Interface settings', - threeIsCollapse: 'Menu horizontal collapse', - threeIsUniqueOpened: 'Menu accordion', - threeIsFixedHeader: 'Fixed header', - threeIsClassicSplitMenu: 'Classic layout split menu', - threeIsLockScreen: 'Open the lock screen', - threeLockScreenTime: 'screen locking(s/s)', - fourTitle: 'Interface display', - fourIsShowLogo: 'Sidebar logo', - fourIsBreadcrumb: 'Open breadcrumb', - fourIsBreadcrumbIcon: 'Open breadcrumb icon', - fourIsTagsview: 'Open tagsview', - fourIsTagsviewIcon: 'Open tagsview Icon', - fourIsCacheTagsView: 'Enable tagsview cache', - fourIsSortableTagsView: 'Enable tagsview drag', - fourIsShareTagsView: 'Enable tagsview sharing', - fourIsFooter: 'Open footer', - fourIsGrayscale: 'Grey model', - fourIsInvert: 'Color weak mode', - fourIsDark: 'Dark Mode', - fourIsWartermark: 'Turn on watermark', - fourWartermarkText: 'Watermark copy', - fiveTitle: 'Other settings', - fiveTagsStyle: 'Tagsview style', - fiveAnimation: 'page animation', - fiveColumnsAsideStyle: 'Column style', - fiveColumnsAsideLayout: 'Column layout', - sixTitle: 'Layout switch', - sixDefaults: 'One', - sixClassic: 'Two', - sixTransverse: 'Three', - sixColumns: 'Four', - tipText: 'Click the button below to copy the layout configuration to `/src/stores/themeConfig.ts` It has been modified in.', - copyText: 'replication configuration', - resetText: 'restore default', - copyTextSuccess: 'Copy succeeded!', - copyTextError: 'Copy failed!', - }, + router: { + home: 'home', + system: 'system', + systemMenu: 'systemMenu', + systemRole: 'systemRole', + systemUser: 'systemUser', + systemDept: 'systemDept', + systemDic: 'systemDic', + limits: 'limits', + limitsFrontEnd: 'FrontEnd', + limitsFrontEndPage: 'FrontEndPage', + limitsFrontEndBtn: 'FrontEndBtn', + limitsBackEnd: 'BackEnd', + limitsBackEndEndPage: 'BackEndEndPage', + personal: 'personal', + }, + staticRoutes: { + signIn: 'signIn', + notFound: 'notFound', + noPower: 'noPower', + }, + user: { + title0: 'Component size', + title1: 'Language switching', + title2: 'Menu search', + title3: 'Layout configuration', + title4: 'news', + title5: 'Full screen on', + title6: 'Full screen off', + dropdownLarge: 'large', + dropdownDefault: 'default', + dropdownSmall: 'small', + dropdown1: 'home page', + dropdown2: 'Personal Center', + dropdown3: '404', + dropdown4: '401', + dropdown5: 'Log out', + dropdown6: 'Code warehouse', + searchPlaceholder: 'Menu search: support Chinese, routing path', + newTitle: 'notice', + newBtn: 'All read', + newGo: 'Go to the notification center', + newDesc: 'No notice', + logOutTitle: 'Tips', + logOutMessage: 'This operation will log out. Do you want to continue?', + logOutConfirm: 'determine', + logOutCancel: 'cancel', + logOutExit: 'Exiting', + }, + tagsView: { + refresh: 'refresh', + close: 'close', + closeOther: 'closeOther', + closeAll: 'closeAll', + fullscreen: 'fullscreen', + closeFullscreen: 'closeFullscreen', + }, + notFound: { + foundTitle: 'Wrong address input, please re-enter the address~', + foundMsg: 'You can check the web address first, and then re-enter or give us feedback.', + foundBtn: 'Back to home page', + }, + noAccess: { + accessTitle: 'You are not authorized to operate~', + accessMsg: 'Contact information: add QQ group discussion 665452019', + accessBtn: 'Reauthorization', + }, + layout: { + configTitle: 'Layout configuration', + oneTitle: 'Global Themes', + twoTopTitle: 'top bar set up', + twoMenuTitle: 'Menu set up', + twoColumnsTitle: 'Columns set up', + twoTopBar: 'Top bar background', + twoTopBarColor: 'Top bar default font color', + twoIsTopBarColorGradual: 'Top bar gradient', + twoMenuBar: 'Menu background', + twoMenuBarColor: 'Menu default font color', + twoIsMenuBarColorGradual: 'Menu gradient', + twoColumnsMenuBar: 'Column menu background', + twoColumnsMenuBarColor: 'Default font color bar menu', + twoIsColumnsMenuBarColorGradual: 'Column gradient', + threeTitle: 'Interface settings', + threeIsCollapse: 'Menu horizontal collapse', + threeIsUniqueOpened: 'Menu accordion', + threeIsFixedHeader: 'Fixed header', + threeIsClassicSplitMenu: 'Classic layout split menu', + threeIsLockScreen: 'Open the lock screen', + threeLockScreenTime: 'screen locking(s/s)', + fourTitle: 'Interface display', + fourIsShowLogo: 'Sidebar logo', + fourIsBreadcrumb: 'Open breadcrumb', + fourIsBreadcrumbIcon: 'Open breadcrumb icon', + fourIsTagsview: 'Open tagsview', + fourIsTagsviewIcon: 'Open tagsview Icon', + fourIsCacheTagsView: 'Enable tagsview cache', + fourIsSortableTagsView: 'Enable tagsview drag', + fourIsShareTagsView: 'Enable tagsview sharing', + fourIsFooter: 'Open footer', + fourIsGrayscale: 'Grey model', + fourIsInvert: 'Color weak mode', + fourIsDark: 'Dark Mode', + fourIsWartermark: 'Turn on watermark', + fourWartermarkText: 'Watermark copy', + fiveTitle: 'Other settings', + fiveTagsStyle: 'Tagsview style', + fiveAnimation: 'page animation', + fiveColumnsAsideStyle: 'Column style', + fiveColumnsAsideLayout: 'Column layout', + sixTitle: 'Layout switch', + sixDefaults: 'One', + sixClassic: 'Two', + sixTransverse: 'Three', + sixColumns: 'Four', + tipText: 'Click the button below to copy the layout configuration to `/src/stores/themeConfig.ts` It has been modified in.', + copyText: 'replication configuration', + resetText: 'restore default', + copyTextSuccess: 'Copy succeeded!', + copyTextError: 'Copy failed!', + }, + upgrade: { + title: 'New version upgrade', + msg: 'It\'s a new version. Update it now!Don\'t worry, update quickly oh!', + desc: 'Tip: The update restores the default configuration', + btnOne: 'Cruel refusal', + btnTwo: 'Update now', + btnTwoLoading: 'updating', + }, }; diff --git a/web/src/i18n/lang/zh-cn.ts b/web/src/i18n/lang/zh-cn.ts index 567cb9aaf15e643b5e9b91bbcf3e0b929928af5f..6289a39193f31230628593cafb87108982f667c7 100644 --- a/web/src/i18n/lang/zh-cn.ts +++ b/web/src/i18n/lang/zh-cn.ts @@ -1,134 +1,146 @@ // 定义内容 export default { - router: { - home: '首页', - system: '系统管理', - config: '常规配置', - log: '日志管理', - /* 常规配置 */ - configSystem: '系统配置', - configDict: '字典管理', - configArea: '地区管理', - configFile: '附件管理', - /* 系统管理 */ - systemMenu: '菜单管理', - systemRole: '角色管理', - systemUser: '用户管理', - systemDept: '部门管理', - /* 日志管理 */ - loginLog: '登录日志', - operationLog: '操作日志', - systemApiWhiteList: '接口白名单', - limits: '权限管理', - limitsFrontEnd: '前端控制', - limitsFrontEndPage: '页面权限', - limitsFrontEndBtn: '按钮权限', - limitsBackEnd: '后端控制', - limitsBackEndEndPage: '页面权限', - personal: '个人中心', - }, - staticRoutes: { - signIn: '登录', - notFound: '找不到此页面', - noPower: '没有权限', - }, - user: { - title0: '组件大小', - title1: '语言切换', - title2: '菜单搜索', - title3: '布局配置', - title4: '消息', - title5: '开全屏', - title6: '关全屏', - dropdownLarge: '大型', - dropdownDefault: '默认', - dropdownSmall: '小型', - dropdown1: '首页', - dropdown2: '个人中心', - dropdown3: '404', - dropdown4: '401', - dropdown5: '退出登录', - dropdown6: '代码仓库', - searchPlaceholder: '菜单搜索:支持中文、路由路径', - newTitle: '通知', - newBtn: '全部已读', - newGo: '前往通知中心', - newDesc: '暂无通知', - logOutTitle: '提示', - logOutMessage: '此操作将退出登录, 是否继续?', - logOutConfirm: '确定', - logOutCancel: '取消', - logOutExit: '退出中', - }, - tagsView: { - refresh: '刷新', - close: '关闭', - closeOther: '关闭其它', - closeAll: '全部关闭', - fullscreen: '当前页全屏', - closeFullscreen: '关闭全屏', - }, - notFound: { - foundTitle: '地址输入错误,请重新输入地址~', - foundMsg: '您可以先检查网址,然后重新输入或给我们反馈问题。', - foundBtn: '返回首页', - }, - noAccess: { - accessTitle: '您未被授权,没有操作权限~', - accessMsg: '联系方式:加QQ群探讨 665452019', - accessBtn: '重新授权', - }, - layout: { - configTitle: '布局配置', - oneTitle: '全局主题', - twoTopTitle: '顶栏设置', - twoMenuTitle: '菜单设置', - twoColumnsTitle: '分栏设置', - twoTopBar: '顶栏背景', - twoTopBarColor: '顶栏默认字体颜色', - twoIsTopBarColorGradual: '顶栏背景渐变', - twoMenuBar: '菜单背景', - twoMenuBarColor: '菜单默认字体颜色', - twoIsMenuBarColorGradual: '菜单背景渐变', - twoColumnsMenuBar: '分栏菜单背景', - twoColumnsMenuBarColor: '分栏菜单默认字体颜色', - twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变', - threeTitle: '界面设置', - threeIsCollapse: '菜单水平折叠', - threeIsUniqueOpened: '菜单手风琴', - threeIsFixedHeader: '固定 Header', - threeIsClassicSplitMenu: '经典布局分割菜单', - threeIsLockScreen: '开启锁屏', - threeLockScreenTime: '自动锁屏(s/秒)', - fourTitle: '界面显示', - fourIsShowLogo: '侧边栏 Logo', - fourIsBreadcrumb: '开启 Breadcrumb', - fourIsBreadcrumbIcon: '开启 Breadcrumb 图标', - fourIsTagsview: '开启 Tagsview', - fourIsTagsviewIcon: '开启 Tagsview 图标', - fourIsCacheTagsView: '开启 TagsView 缓存', - fourIsSortableTagsView: '开启 TagsView 拖拽', - fourIsShareTagsView: '开启 TagsView 共用', - fourIsFooter: '开启 Footer', - fourIsGrayscale: '灰色模式', - fourIsInvert: '色弱模式', - fourIsDark: '深色模式', - fourIsWartermark: '开启水印', - fourWartermarkText: '水印文案', - fiveTitle: '其它设置', - fiveTagsStyle: 'Tagsview 风格', - fiveAnimation: '主页面切换动画', - fiveColumnsAsideStyle: '分栏高亮风格', - fiveColumnsAsideLayout: '分栏布局风格', - sixTitle: '布局切换', - sixDefaults: '默认', - sixClassic: '经典', - sixTransverse: '横向', - sixColumns: '分栏', - tipText: '点击下方按钮,复制布局配置去 `src/stores/themeConfig.ts` 中修改。', - copyText: '一键复制配置', - resetText: '一键恢复默认', - copyTextSuccess: '复制成功!', - copyTextError: '复制失败!', - }, + router: { + home: '首页', + system: '系统管理', + config: '常规配置', + log: '日志管理', + /* 常规配置 */ + configSystem: '系统配置', + configDict: '字典管理', + configArea: '地区管理', + configFile: '附件管理', + /* 系统管理 */ + systemMenu: '菜单管理', + systemRole: '角色管理', + systemUser: '用户管理', + systemDept: '部门管理', + /* 日志管理 */ + loginLog: '登录日志', + operationLog: '操作日志', + systemApiWhiteList: '接口白名单', + limits: '权限管理', + limitsFrontEnd: '前端控制', + limitsFrontEndPage: '页面权限', + limitsFrontEndBtn: '按钮权限', + limitsBackEnd: '后端控制', + limitsBackEndEndPage: '页面权限', + personal: '个人中心', + }, + staticRoutes: { + signIn: '登录', + notFound: '找不到此页面', + noPower: '没有权限', + }, + user: { + title0: '组件大小', + title1: '语言切换', + title2: '菜单搜索', + title3: '布局配置', + title4: '消息', + title5: '开全屏', + title6: '关全屏', + retry: '重试上线', + onlinePrompt: '当前离线状态,是否重试上线?', + dropdownLarge: '大型', + dropdownDefault: '默认', + dropdownSmall: '小型', + dropdown1: '首页', + dropdown2: '个人中心', + dropdown3: '404', + dropdown4: '401', + dropdown5: '退出登录', + dropdown6: '代码仓库', + searchPlaceholder: '菜单搜索:支持中文、路由路径', + newTitle: '通知', + newBtn: '全部已读', + newGo: '前往通知中心', + newDesc: '暂无通知', + logOutTitle: '提示', + logOutMessage: '此操作将退出登录, 是否继续?', + logOutConfirm: '确定', + logOutCancel: '取消', + logOutExit: '退出中', + }, + tagsView: { + refresh: '刷新', + close: '关闭', + closeOther: '关闭其它', + closeAll: '全部关闭', + fullscreen: '当前页全屏', + closeFullscreen: '关闭全屏', + }, + notFound: { + foundTitle: '地址输入错误,请重新输入地址~', + foundMsg: '您可以先检查网址,然后重新输入或给我们反馈问题。', + foundBtn: '返回首页', + }, + noAccess: { + accessTitle: '您未被授权,没有操作权限~', + accessMsg: '请联系管理员', + accessBtn: '重新授权', + }, + layout: { + configTitle: '布局配置', + oneTitle: '全局主题', + twoTopTitle: '顶栏设置', + twoMenuTitle: '菜单设置', + twoColumnsTitle: '分栏设置', + twoTopBar: '顶栏背景', + twoTopBarColor: '顶栏默认字体颜色', + twoIsTopBarColorGradual: '顶栏背景渐变', + twoMenuBar: '菜单背景', + twoMenuBarColor: '菜单默认字体颜色', + twoMenuBarActiveColor: '菜单高亮背景色', + twoIsMenuBarColorGradual: '菜单背景渐变', + twoColumnsMenuBar: '分栏菜单背景', + twoColumnsMenuBarColor: '分栏菜单默认字体颜色', + twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变', + twoIsColumnsMenuHoverPreload: '分栏菜单滑鼠悬停预加载', + threeTitle: '界面设置', + threeIsCollapse: '菜单水平折叠', + threeIsUniqueOpened: '菜单手风琴', + threeIsFixedHeader: '固定 Header', + threeIsClassicSplitMenu: '经典布局分割菜单', + threeIsLockScreen: '开启锁屏', + threeLockScreenTime: '自动锁屏(s/秒)', + fourTitle: '界面显示', + fourIsShowLogo: '侧边栏 Logo', + fourIsBreadcrumb: '开启 Breadcrumb', + fourIsBreadcrumbIcon: '开启 Breadcrumb 图标', + fourIsTagsview: '开启 Tagsview', + fourIsTagsviewIcon: '开启 Tagsview 图标', + fourIsCacheTagsView: '开启 TagsView 缓存', + fourIsSortableTagsView: '开启 TagsView 拖拽', + fourIsShareTagsView: '开启 TagsView 共用', + fourIsFooter: '开启 Footer', + fourIsGrayscale: '灰色模式', + fourIsInvert: '色弱模式', + fourIsDark: '深色模式', + fourIsWartermark: '开启水印', + fourWartermarkText: '水印文案', + fiveTitle: '其它设置', + fiveTagsStyle: 'Tagsview 风格', + fiveAnimation: '主页面切换动画', + fiveColumnsAsideStyle: '分栏高亮风格', + fiveColumnsAsideLayout: '分栏布局风格', + sixTitle: '布局切换', + sixDefaults: '默认', + sixClassic: '经典', + sixTransverse: '横向', + sixColumns: '分栏', + tipText: '点击下方按钮,复制布局配置去 `src/stores/themeConfig.ts` 中修改。', + copyText: '一键复制配置', + resetText: '一键恢复默认', + copyTextSuccess: '复制成功!', + copyTextError: '复制失败!', + }, + upgrade: { + title: '新版本升级', + msg: '新版本来啦,马上更新尝鲜吧!不用担心,更新很快的哦!', + desc: '提示:更新会还原默认配寘', + btnOne: '残忍拒绝', + btnTwo: '马上更新', + btnTwoLoading: '更新中', + }, }; diff --git a/web/src/i18n/lang/zh-tw.ts b/web/src/i18n/lang/zh-tw.ts index 35e406fe76783f17bee56c662aec6b3f5efbb338..ea0016445080f8d2ae752c9f6f54e68ee3dc5be0 100644 --- a/web/src/i18n/lang/zh-tw.ts +++ b/web/src/i18n/lang/zh-tw.ts @@ -123,7 +123,7 @@ export default { }, noAccess: { accessTitle: '您未被授權,沒有操作許可權~', - accessMsg: '聯繫方式:加QQ群探討665452019', + accessMsg: '請聯系管理員', accessBtn: '重新授權', }, layout: { diff --git a/web/src/i18n/pages/login/zh-cn.ts b/web/src/i18n/pages/login/zh-cn.ts index 61f994d2d244fdc182bbf6785fa3eb8b933fabb9..6ab9813aa1e51a68b70d35a8b83c0fb2e47c67b9 100644 --- a/web/src/i18n/pages/login/zh-cn.ts +++ b/web/src/i18n/pages/login/zh-cn.ts @@ -1,7 +1,7 @@ // 定义内容 export default { label: { - one1: '用户名登录', + one1: '账号密码登录', two2: '手机号登录', }, link: { diff --git a/web/src/layout/component/main.vue b/web/src/layout/component/main.vue index fd3f59993b7dd5a98cb8d051bea528f5bfd963e6..9250d1e6a8328638426eeecac1c8a2a24b5f6e4c 100644 --- a/web/src/layout/component/main.vue +++ b/web/src/layout/component/main.vue @@ -4,7 +4,7 @@ - + diff --git a/web/src/layout/footer/index.vue b/web/src/layout/footer/index.vue index 526cd8fc95eb8110dda03dd7daf12d827b491bba..67e6e5c07b00a4a9be9f1c42449528f7a3892a22 100644 --- a/web/src/layout/footer/index.vue +++ b/web/src/layout/footer/index.vue @@ -1,8 +1,7 @@ diff --git a/web/src/layout/navBars/breadcrumb/user.vue b/web/src/layout/navBars/breadcrumb/user.vue index a762c37aa7450099407001abf4293d9e8de437ac..61793c974ad275979387c36293f24ad9dcc3d931 100644 --- a/web/src/layout/navBars/breadcrumb/user.vue +++ b/web/src/layout/navBars/breadcrumb/user.vue @@ -57,9 +57,33 @@ :class="!state.isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'" > +
+ + + + + +
- + + + + + {{ userInfos.username === '' ? 'common' : userInfos.username }} @@ -79,7 +103,7 @@ diff --git a/web/src/main.ts b/web/src/main.ts index cb435568a7fdcdce1bb47eaa2f6fe252732d2b79..f735d7f7f0006e2292edfcde21b6f99854eca85e 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -14,7 +14,7 @@ import piniaPersist from 'pinia-plugin-persist'; // @ts-ignore import fastCrud from './settings.ts'; import pinia from './stores'; -import permission from '/@/plugin/permission/index'; +import {RegisterPermission} from '/@/plugin/permission/index'; // @ts-ignore import eIconPicker, { iconList, analyzingIconForIconfont } from 'e-icon-picker'; import 'e-icon-picker/icon/default-icon/symbol.js'; //基本彩色图标库 @@ -54,7 +54,6 @@ other.elSvg(app); app.use(VXETable) -app.use(permission); app.use(pinia).use(router).use(ElementPlus, { i18n: i18n.global.t }).use(i18n).use(VueGridLayout).use(fastCrud).mount('#app'); app.config.globalProperties.mittBus = mitt(); diff --git a/web/src/plugin/permission/index.ts b/web/src/plugin/permission/index.ts index b519bd07e617dbbddc9d95c4f13ed33636be4656..a40941e415c6a01b46302ea54ee31e3efe60acbb 100644 --- a/web/src/plugin/permission/index.ts +++ b/web/src/plugin/permission/index.ts @@ -1,10 +1,6 @@ import permissionDirective from './directive.permission' import permissionFunc from './func.permission' -const install = function (app:any) { +export const RegisterPermission = function (app:any) { app.directive('permission', permissionDirective) app.provide('$hasPermissions',permissionFunc.hasPermissions) } - -export default { - install -} diff --git a/web/src/stores/btnPermission.ts b/web/src/stores/btnPermission.ts new file mode 100644 index 0000000000000000000000000000000000000000..2879628907c5e6e01148377a809bc52d6fee814b --- /dev/null +++ b/web/src/stores/btnPermission.ts @@ -0,0 +1,26 @@ +import {defineStore} from "pinia"; +import {DictionaryStates} from "/@/stores/interface"; +import {request} from "/@/utils/service"; + +export const BtnPermissionStore = defineStore('BtnPermission', { + state: (): DictionaryStates => ({ + data: [] + }), + actions: { + async getBtnPermissionStore() { + request({ + url: '/api/system/menu_button/menu_button_all_permission/', + method: 'get', + }).then((ret: { + data: [] + }) => { + // 转换数据格式并保存到pinia + let dataList = ret.data + this.data=dataList + }) + }, + }, + persist: { + enabled: true, + }, +}); diff --git a/web/src/stores/interface/index.ts b/web/src/stores/interface/index.ts index 98d016bb478e129768bb95457393afd3e9eb82f5..6d2c775dbb0a429ee6520fba98cc365ddba79c72 100644 --- a/web/src/stores/interface/index.ts +++ b/web/src/stores/interface/index.ts @@ -19,6 +19,7 @@ export interface UserInfosState { } export interface UserInfosStates { userInfos: UserInfosState; + isSocketOpen: boolean } // 路由缓存列表 diff --git a/web/src/stores/userInfo.ts b/web/src/stores/userInfo.ts index 4bef2a90fff6d4090ffca05f5f675795ca924fb8..9be64a8b474062ee9f478a1bf893fb2e2fb9de72 100644 --- a/web/src/stores/userInfo.ts +++ b/web/src/stores/userInfo.ts @@ -26,6 +26,7 @@ export const useUserInfo = defineStore('userInfo', { }, ], }, + isSocketOpen: false }), actions: { async updateUserInfos() { @@ -57,6 +58,9 @@ export const useUserInfo = defineStore('userInfo', { Session.set('userInfo', this.userInfos); } }, + async setWebSocketState(socketState: boolean) { + this.isSocketOpen = socketState; + }, async getApiUserInfo() { return request({ url: '/api/system/user/user_info/', diff --git a/web/src/utils/authDirective.ts b/web/src/utils/authDirective.ts index 5971e64fa6d8475154cc881d9f55596c64b8512f..44a8871f92e7c9fb8bd0b737b8d5978a45ee1a6a 100644 --- a/web/src/utils/authDirective.ts +++ b/web/src/utils/authDirective.ts @@ -1,7 +1,6 @@ import type { App } from 'vue'; -import { useUserInfo } from '/@/stores/userInfo'; import { judementSameArr } from '/@/utils/arrayOperation'; - +import {BtnPermissionStore} from "/@/stores/btnPermission"; /** * 用户权限指令 * @directive 单个权限验证(v-auth="xxx") @@ -12,16 +11,16 @@ export function authDirective(app: App) { // 单个权限验证(v-auth="xxx") app.directive('auth', { mounted(el, binding) { - const stores = useUserInfo(); - if (!stores.userInfos.authBtnList.some((v: string) => v === binding.value)) el.parentNode.removeChild(el); + const stores = BtnPermissionStore(); + if (!stores.data.some((v: string) => v === binding.value)) el.parentNode.removeChild(el); }, }); // 多个权限验证,满足一个则显示(v-auths="[xxx,xxx]") app.directive('auths', { mounted(el, binding) { let flag = false; - const stores = useUserInfo(); - stores.userInfos.authBtnList.map((val: string) => { + const stores = BtnPermissionStore(); + stores.data.map((val: string) => { binding.value.map((v: string) => { if (val === v) flag = true; }); @@ -32,8 +31,8 @@ export function authDirective(app: App) { // 多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]") app.directive('auth-all', { mounted(el, binding) { - const stores = useUserInfo(); - const flag = judementSameArr(binding.value, stores.userInfos.authBtnList); + const stores = BtnPermissionStore(); + const flag = judementSameArr(binding.value, stores.data); if (!flag) el.parentNode.removeChild(el); }, }); diff --git a/web/src/utils/authFunction.ts b/web/src/utils/authFunction.ts index 84c0ab468572b85c6889b3bdf37e0853096c6f20..c328520fc14bd3d4ed8a129de384a58e31cfe58d 100644 --- a/web/src/utils/authFunction.ts +++ b/web/src/utils/authFunction.ts @@ -1,14 +1,13 @@ -import { useUserInfo } from '/@/stores/userInfo'; import { judementSameArr } from '/@/utils/arrayOperation'; - +import {BtnPermissionStore} from "/@/stores/btnPermission"; /** * 单个权限验证 * @param value 权限值 * @returns 有权限,返回 `true`,反之则反 */ export function auth(value: string): boolean { - const stores = useUserInfo(); - return stores.userInfos.authBtnList.some((v: string) => v === value); + const stores = BtnPermissionStore(); + return stores.data.some((v: string) => v === value); } /** @@ -18,8 +17,8 @@ export function auth(value: string): boolean { */ export function auths(value: Array): boolean { let flag = false; - const stores = useUserInfo(); - stores.userInfos.authBtnList.map((val: string) => { + const stores = BtnPermissionStore(); + stores.data.map((val: string) => { value.map((v: string) => { if (val === v) flag = true; }); @@ -33,6 +32,6 @@ export function auths(value: Array): boolean { * @returns 有权限,返回 `true`,反之则反 */ export function authAll(value: Array): boolean { - const stores = useUserInfo(); - return judementSameArr(value, stores.userInfos.authBtnList); + const stores = BtnPermissionStore(); + return judementSameArr(value, stores.data); } diff --git a/web/src/utils/setIconfont.ts b/web/src/utils/setIconfont.ts index aa471044ffab1efb785c90949d39445f74adeefa..baa096933886702a6ff39a80ff969b839f03d013 100644 --- a/web/src/utils/setIconfont.ts +++ b/web/src/utils/setIconfont.ts @@ -2,7 +2,6 @@ const cssCdnUrlList: Array = [ '//at.alicdn.com/t/font_2298093_y6u00apwst.css', '//at.alicdn.com/t/c/font_3882322_9ah7y8m9175.css', //dvadmin3项目用icon - '//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css', ]; // 第三方 js url const jsCdnUrlList: Array = []; diff --git a/web/src/utils/websocket.ts b/web/src/utils/websocket.ts index 987273e8860be22e03ed953368048ea2d4bca503..2fabadbda2407a2b2937012f868a23aae208c018 100644 --- a/web/src/utils/websocket.ts +++ b/web/src/utils/websocket.ts @@ -3,7 +3,7 @@ import {Session} from "/@/utils/storage"; import {getWsBaseURL} from "/@/utils/baseUrl"; // @ts-ignore import socket from '@/types/api/socket' - +import {useUserInfo} from "/@/stores/userInfo"; const websocket: socket = { websocket: null, connectURL: getWsBaseURL(), @@ -42,6 +42,7 @@ const websocket: socket = { } websocket.websocket.onclose = (e: any) => { websocket.socket_open = false + useUserInfo().setWebSocketState(websocket.socket_open); // 需要重新连接 if (websocket.is_reonnect) { websocket.reconnect_timer = setTimeout(() => { @@ -49,6 +50,8 @@ const websocket: socket = { if (websocket.reconnect_current > websocket.reconnect_count) { clearTimeout(websocket.reconnect_timer) websocket.is_reonnect = false + websocket.socket_open = false + useUserInfo().setWebSocketState(websocket.socket_open); return } // 记录重连次数 @@ -60,6 +63,7 @@ const websocket: socket = { // 连接成功 websocket.websocket.onopen = function () { websocket.socket_open = true + useUserInfo().setWebSocketState(websocket.socket_open); websocket.is_reonnect = true // 开启心跳 websocket.heartbeat() @@ -85,17 +89,21 @@ const websocket: socket = { callback && callback() } else { clearInterval(websocket.hearbeat_timer) - message({ - type: 'warning', - message: 'socket链接已断开', - duration: 1000, - }) + // message({ + // type: 'warning', + // message: 'socket链接已断开', + // duration: 1000, + // }) + websocket.socket_open = false + useUserInfo().setWebSocketState(websocket.socket_open); } }, close: () => { websocket.is_reonnect = false websocket.websocket.close() websocket.websocket = null; + websocket.socket_open = false + useUserInfo().setWebSocketState(websocket.socket_open); }, /** * 重新连接 diff --git a/web/src/views/system/areas/crud.tsx b/web/src/views/system/areas/crud.tsx index edf6935369868ae348f619c380c17bf3253fdf61..01d1860253220ac98200c98e4a6446c79a5daab5 100644 --- a/web/src/views/system/areas/crud.tsx +++ b/web/src/views/system/areas/crud.tsx @@ -1,225 +1,244 @@ import * as api from './api'; -import { dict, UserPageQuery, AddReq, DelReq, EditReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud'; -import { dictionary } from '/@/utils/dictionary'; -import { successMessage } from '/@/utils/message'; +import { + dict, + UserPageQuery, + AddReq, + DelReq, + EditReq, + compute, + CreateCrudOptionsProps, + CreateCrudOptionsRet +} from '@fast-crud/fast-crud'; +import {dictionary} from '/@/utils/dictionary'; +import {successMessage} from '/@/utils/message'; +import {auth} from "/@/utils/authFunction"; -export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet { - const pageRequest = async (query: UserPageQuery) => { - return await api.GetList(query); - }; - const editRequest = async ({ form, row }: EditReq) => { - form.id = row.id; - return await api.UpdateObj(form); - }; - const delRequest = async ({ row }: DelReq) => { - return await api.DelObj(row.id); - }; - const addRequest = async ({ form }: AddReq) => { - return await api.AddObj(form); - }; +export const createCrudOptions = function ({crudExpose}: CreateCrudOptionsProps): CreateCrudOptionsRet { + const pageRequest = async (query: UserPageQuery) => { + return await api.GetList(query); + }; + const editRequest = async ({form, row}: EditReq) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({row}: DelReq) => { + return await api.DelObj(row.id); + }; + const addRequest = async ({form}: AddReq) => { + return await api.AddObj(form); + }; - /** - * 懒加载 - * @param row - * @returns {Promise} - */ - const loadContentMethod = (tree: any, treeNode: any, resolve: Function) => { - pageRequest({ pcode: tree.code }).then((res: APIResponseData) => { - resolve(res.data); - }); - }; + /** + * 懒加载 + * @param row + * @returns {Promise} + */ + const loadContentMethod = (tree: any, treeNode: any, resolve: Function) => { + pageRequest({pcode: tree.code}).then((res: APIResponseData) => { + resolve(res.data); + }); + }; - return { - crudOptions: { - request: { - pageRequest, - addRequest, - editRequest, - delRequest, - }, - rowHandle: { - //固定右侧 - fixed: 'right', - width: 200, - buttons: { - view: { - show: false, - }, - edit: { - iconRight: 'Edit', - type: 'text', - }, - remove: { - iconRight: 'Delete', - type: 'text', - }, - }, - }, - pagination: { - show: false, - }, - table: { - rowKey: 'id', - lazy: true, - load: loadContentMethod, - treeProps: { children: 'children', hasChildren: 'hasChild' }, - }, - columns: { - _index: { - title: '序号', - form: { show: false }, - column: { - type: 'index', - align: 'center', - width: '70px', - columnSetDisabled: true, //禁止在列设置中选择 - }, - }, - // pcode: { - // title: '父级地区', - // show: false, - // search: { - // show: true, - // }, - // type: 'dict-tree', - // form: { - // component: { - // showAllLevels: false, // 仅显示最后一级 - // props: { - // elProps: { - // clearable: true, - // showAllLevels: false, // 仅显示最后一级 - // props: { - // checkStrictly: true, // 可以不需要选到最后一级 - // emitPath: false, - // clearable: true, - // }, - // }, - // }, - // }, - // }, - // }, - name: { - title: '名称', - search: { - show: true, - }, - treeNode: true, - type: 'input', - column:{ - minWidth: 120, - }, - form: { - rules: [ - // 表单校验规则 - { required: true, message: '名称必填项' }, - ], - component: { - placeholder: '请输入名称', - }, - }, - }, - code: { - title: '地区编码', - search: { - show: true, - }, - type: 'input', - column:{ - minWidth: 90, - }, - form: { - rules: [ - // 表单校验规则 - { required: true, message: '地区编码必填项' }, - ], - component: { - placeholder: '请输入地区编码', - }, - }, - }, - pinyin: { - title: '拼音', - search: { - disabled: true, - }, - type: 'input', - column:{ - minWidth: 120, - }, - form: { - rules: [ - // 表单校验规则 - { required: true, message: '拼音必填项' }, - ], - component: { - placeholder: '请输入拼音', - }, - }, - }, - level: { - title: '地区层级', - search: { - disabled: true, - }, - type: 'input', - column:{ - minWidth: 100, - }, - form: { - disabled: false, - rules: [ - // 表单校验规则 - { required: true, message: '拼音必填项' }, - ], - component: { - placeholder: '请输入拼音', - }, - }, - }, - initials: { - title: '首字母', - column:{ - minWidth: 100, - }, - form: { - rules: [ - // 表单校验规则 - { required: true, message: '首字母必填项' }, - ], + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest, + }, + actionbar: { + buttons: { + add: { + show: auth('area:Create'), + } + } + }, + rowHandle: { + //固定右侧 + fixed: 'right', + width: 200, + buttons: { + view: { + show: false, + }, + edit: { + iconRight: 'Edit', + type: 'text', + show: auth('area:Update') + }, + remove: { + iconRight: 'Delete', + type: 'text', + show: auth('area:Delete') + }, + }, + }, + pagination: { + show: false, + }, + table: { + rowKey: 'id', + lazy: true, + load: loadContentMethod, + treeProps: {children: 'children', hasChildren: 'hasChild'}, + }, + columns: { + _index: { + title: '序号', + form: {show: false}, + column: { + type: 'index', + align: 'center', + width: '70px', + columnSetDisabled: true, //禁止在列设置中选择 + }, + }, + // pcode: { + // title: '父级地区', + // show: false, + // search: { + // show: true, + // }, + // type: 'dict-tree', + // form: { + // component: { + // showAllLevels: false, // 仅显示最后一级 + // props: { + // elProps: { + // clearable: true, + // showAllLevels: false, // 仅显示最后一级 + // props: { + // checkStrictly: true, // 可以不需要选到最后一级 + // emitPath: false, + // clearable: true, + // }, + // }, + // }, + // }, + // }, + // }, + name: { + title: '名称', + search: { + show: true, + }, + treeNode: true, + type: 'input', + column: { + minWidth: 120, + }, + form: { + rules: [ + // 表单校验规则 + {required: true, message: '名称必填项'}, + ], + component: { + placeholder: '请输入名称', + }, + }, + }, + code: { + title: '地区编码', + search: { + show: true, + }, + type: 'input', + column: { + minWidth: 90, + }, + form: { + rules: [ + // 表单校验规则 + {required: true, message: '地区编码必填项'}, + ], + component: { + placeholder: '请输入地区编码', + }, + }, + }, + pinyin: { + title: '拼音', + search: { + disabled: true, + }, + type: 'input', + column: { + minWidth: 120, + }, + form: { + rules: [ + // 表单校验规则 + {required: true, message: '拼音必填项'}, + ], + component: { + placeholder: '请输入拼音', + }, + }, + }, + level: { + title: '地区层级', + search: { + disabled: true, + }, + type: 'input', + column: { + minWidth: 100, + }, + form: { + disabled: false, + rules: [ + // 表单校验规则 + {required: true, message: '拼音必填项'}, + ], + component: { + placeholder: '请输入拼音', + }, + }, + }, + initials: { + title: '首字母', + column: { + minWidth: 100, + }, + form: { + rules: [ + // 表单校验规则 + {required: true, message: '首字母必填项'}, + ], - component: { - placeholder: '请输入首字母', - }, - }, - }, - enable: { - title: '是否启用', - search: { - show: true, - }, - type: 'dict-radio', - column: { - minWidth:90, - component: { - name: 'fs-dict-switch', - activeText: '', - inactiveText: '', - style: '--el-switch-on-color: var(--el-color-primary); --el-switch-off-color: #dcdfe6', - onChange: compute((context) => { - return () => { - api.UpdateObj(context.row).then((res: APIResponseData) => { - successMessage(res.msg as string); - }); - }; - }), - }, - }, - dict: dict({ - data: dictionary('button_status_bool'), - }), - }, - }, - }, - }; + component: { + placeholder: '请输入首字母', + }, + }, + }, + enable: { + title: '是否启用', + search: { + show: true, + }, + type: 'dict-radio', + column: { + minWidth: 90, + component: { + name: 'fs-dict-switch', + activeText: '', + inactiveText: '', + style: '--el-switch-on-color: var(--el-color-primary); --el-switch-off-color: #dcdfe6', + onChange: compute((context) => { + return () => { + api.UpdateObj(context.row).then((res: APIResponseData) => { + successMessage(res.msg as string); + }); + }; + }), + }, + }, + dict: dict({ + data: dictionary('button_status_bool'), + }), + }, + }, + }, + }; }; diff --git a/web/src/views/system/columns/index.vue b/web/src/views/system/columns/index.vue index cd7722e12ab29248f97f57ef5e9647f1e9b91ce7..21a781711f093a951fa73e0ed422186eb594cdd3 100644 --- a/web/src/views/system/columns/index.vue +++ b/web/src/views/system/columns/index.vue @@ -1,17 +1,17 @@ + + +
+ + +
+ +
+ + diff --git a/web/src/views/system/menu/components/MenuTreeCom/index.vue b/web/src/views/system/menu/components/MenuTreeCom/index.vue index 82363f5f66418ea408263c80506ce4b7821eddb5..91a9988e14dbaed3e52d814803931b924bcca079 100644 --- a/web/src/views/system/menu/components/MenuTreeCom/index.vue +++ b/web/src/views/system/menu/components/MenuTreeCom/index.vue @@ -41,31 +41,31 @@
- + - + - + - + - + diff --git a/web/src/views/system/menu/index.vue b/web/src/views/system/menu/index.vue index 97e26c3d56c509c513d0b5573c24b486bd3ba786..0637a3fe74daa0acff451f1dac15cc5f850da890 100644 --- a/web/src/views/system/menu/index.vue +++ b/web/src/views/system/menu/index.vue @@ -14,9 +14,19 @@ - + + +
+ +
+
+ +
+ +
+
+
+
@@ -39,6 +49,7 @@ import { ElMessageBox } from 'element-plus'; import MenuTreeCom from './components/MenuTreeCom/index.vue'; import MenuButtonCom from './components/MenuButtonCom/index.vue'; import MenuFormCom from './components/MenuFormCom/index.vue'; +import MenuFieldCom from './components/MenuFieldCom/index.vue'; import { GetList, DelObj } from './api'; import { successNotification } from '/@/utils/message'; import { APIResponseData, MenuTreeItemType } from './types'; @@ -49,7 +60,7 @@ let drawerVisible = ref(false); let drawerFormData = ref>({}); let menuTreeRef = ref | null>(null); let menuButtonRef = ref | null>(null); - +let menuFieldRef = ref | null>(null); const getData = () => { GetList({}).then((ret: APIResponseData) => { const responseData = ret.data; @@ -67,6 +78,7 @@ const getData = () => { */ const handleTreeClick = (record: MenuTreeItemType) => { menuButtonRef.value?.handleRefreshTable(record); + menuFieldRef.value?.handleRefreshTable(record) }; /** diff --git a/web/src/views/system/messageCenter/crud.tsx b/web/src/views/system/messageCenter/crud.tsx index aebef1e8f30dfb37a8e02ff6d7d271acb32aedfb..f77626e9e5b9331ba33bc9688d97544ba2ab6387 100644 --- a/web/src/views/system/messageCenter/crud.tsx +++ b/web/src/views/system/messageCenter/crud.tsx @@ -3,7 +3,7 @@ import { dict, useCompute, PageQuery, AddReq, DelReq, EditReq, CrudExpose, CrudO import tableSelector from '/@/components/tableSelector/index.vue'; import {shallowRef, computed, ref, inject} from 'vue'; import manyToMany from '/@/components/manyToMany/index.vue'; - +import {auth} from '/@/utils/authFunction' const { compute } = useCompute(); interface CreateCrudOptionsTypes { @@ -36,8 +36,6 @@ export const createCrudOptions = function ({ crudExpose, tabActivted }: { crudEx return tabActivted.value === 'receive'; }); - //权限判定 - const hasPermissions = inject("$hasPermissions") return { crudOptions: { @@ -47,6 +45,15 @@ export const createCrudOptions = function ({ crudExpose, tabActivted }: { crudEx editRequest, delRequest, }, + actionbar:{ + buttons:{ + add:{ + show:computed(() =>{ + return tabActivted.value !== 'receive' && auth('messageCenter:Create'); + }) + }, + } + }, rowHandle: { fixed:'right', width:150, @@ -58,7 +65,7 @@ export const createCrudOptions = function ({ crudExpose, tabActivted }: { crudEx text:"查看", type:'text', iconRight:'View', - show:hasPermissions("messageCenter:Search"), + show:auth("messageCenter:Search"), click({ index, row }) { crudExpose.openView({ index, row }); if (tabActivted.value === 'receive') { @@ -70,7 +77,7 @@ export const createCrudOptions = function ({ crudExpose, tabActivted }: { crudEx remove: { iconRight: 'Delete', type: 'text', - show:hasPermissions('messageCenter:Delete') + show:auth('messageCenter:Delete') }, }, }, diff --git a/web/src/views/system/role/components/PermissionCom/api.ts b/web/src/views/system/role/components/PermissionCom/api.ts deleted file mode 100644 index 8e9abaad1f409666409d60c073f83c08e1500b4e..0000000000000000000000000000000000000000 --- a/web/src/views/system/role/components/PermissionCom/api.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { request } from "/@/utils/service"; - -/** - * 获取角色所拥有的菜单 - * @param params - */ -export function GetMenu(params:any) { - return request({ - url: '/api/system/role_menu_button_permission/role_get_menu/', - method: 'get', - params:params - }); -} - -/*** - * 新增权限 - * @param data - * @constructor - */ -export function SaveMenuPermission(data:any) { - return request({ - url: '/api/system/role_menu_permission/save_auth/', - method: 'post', - data:data - }); -} - - -/** - * 获取菜单下的按钮 - * @param params - * @constructor - */ -export function GetMenuButton(params:any) { - return request({ - url: '/api/system/role_menu_button_permission/role_menu_get_button/', - method: 'get', - params:params - }); -} - - -/*** - * 根据角色获取已授权的菜单 - * @param params - * @constructor - */ -export function role_to_menu (params:any={}) { - return request({ - url: '/api/system/role_menu_button_permission/role_to_menu/', - method: 'get', - params: params - }) -} - -/*** - * 根据角色获取数据权限范围 - * @constructor - */ -export function GetDataScope (params:any={}) { - return request({ - url: '/api/system/role_menu_button_permission/data_scope/', - method: 'get', - params: params - }) -} - -/*** - * 获取权限部门 - * @constructor - */ -export function GetDataScopeDept (params:any) { - return request({ - url: '/api/system/role_menu_button_permission/role_to_dept_all/', - method: 'get', - params: params - }) -} - -/*** - * 新增权限 - * @param data - * @constructor - */ -export function CreatePermission(data:any) { - return request({ - url: '/api/system/role_menu_button_permission/', - method: 'post', - data:data - }); -} - -/*** - * 根据菜单获取菜单下按钮 - * @param params - */ -export function getObj(params:any) { - return request({ - url: '/api/system/role_menu_button_permission/menu_to_button/', - method: 'get', - params:params - }); -} - -/** - * 删除按钮权限 - * @param data - * @constructor - */ -export function DeletePermission(data:any) { - return request({ - url: `/api/system/role_menu_button_permission/${data.id}/`, - method: 'delete', - data:{} - }); -} - diff --git a/web/src/views/system/role/components/PermissionCom/index.vue b/web/src/views/system/role/components/PermissionCom/index.vue deleted file mode 100644 index e1912266b6d1e3ea190b78ab4dd8306e67fa1860..0000000000000000000000000000000000000000 --- a/web/src/views/system/role/components/PermissionCom/index.vue +++ /dev/null @@ -1,350 +0,0 @@ - - - - - diff --git a/web/src/views/system/role/components/PermissionComCopy/api.ts b/web/src/views/system/role/components/PermissionComCopy/api.ts deleted file mode 100644 index 9d4c59002cc095c9283a62a2eda31b4408cb0e1b..0000000000000000000000000000000000000000 --- a/web/src/views/system/role/components/PermissionComCopy/api.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { request } from "/@/utils/service"; - -export function getDataPermissionRange() { - return request({ - url: '/api/system/role_menu_button_permission/data_scope/', - method: 'get', - }) -} -export function getDataPermissionDept() { - return request({ - url: '/api/system/role_menu_button_permission/role_to_dept_all/', - method: 'get' - }) -} - -export function getDataPermissionMenu() { - return request({ - url: '/api/system/role_menu_button_permission/get_role_permissions/', - method: 'get' - }) -} \ No newline at end of file diff --git a/web/src/views/system/role/components/PermissionComCopy/index.vue b/web/src/views/system/role/components/PermissionComCopy/index.vue deleted file mode 100644 index 1d08e995c366499118129356c25507ba79bf287e..0000000000000000000000000000000000000000 --- a/web/src/views/system/role/components/PermissionComCopy/index.vue +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - diff --git a/web/src/views/system/role/components/PermissionComCopy/types.ts b/web/src/views/system/role/components/PermissionComCopy/types.ts deleted file mode 100644 index 6abb63da191e0c29ddcca95e730e85e61c8d50b0..0000000000000000000000000000000000000000 --- a/web/src/views/system/role/components/PermissionComCopy/types.ts +++ /dev/null @@ -1,20 +0,0 @@ -export interface DataPermissionRangeType { - label: string; - value: number; -} - -export interface CustomDataPermissionDeptType { - id: number; - name: string; - patent: number; - children: CustomDataPermissionDeptType[] -} - -export interface CustomDataPermissionMenuType { - id: number; - name: string; - is_catalog: boolean; - menuPermission: { id: number; name: string; value: string }[] | null; - columns: { id: number; name: string; title: string }[] | null; - children: CustomDataPermissionMenuType[] -} \ No newline at end of file diff --git a/web/src/views/system/role/components/PermissionComNew/index.vue b/web/src/views/system/role/components/PermissionComNew/index.vue index 0e5d159ffb59b25168c86edb987963ecadceb457..1d7a80fde174fd4e7c586f073b84b09aaf707763 100644 --- a/web/src/views/system/role/components/PermissionComNew/index.vue +++ b/web/src/views/system/role/components/PermissionComNew/index.vue @@ -1,6 +1,8 @@