From d4e43e28e890b041021553571219b99453d3b225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com> Date: Tue, 2 Jan 2024 13:50:43 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E6=96=B0=E5=8A=9F=E8=83=BD:=20=E5=B0=81?= =?UTF-8?q?=E8=A3=85=E6=97=B6=E9=97=B4=E8=8C=83=E5=9B=B4=E7=9A=84=E6=90=9C?= =?UTF-8?q?=E7=B4=A2,=E7=A4=BA=E4=BE=8B=E5=9C=A8=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/utils/filters.py | 5 +- backend/dvadmin/utils/viewset.py | 17 +++- web/src/utils/commonCrud.ts | 105 +++++++++++++++++++-- web/src/views/system/log/loginLog/crud.tsx | 6 ++ 4 files changed, 124 insertions(+), 9 deletions(-) diff --git a/backend/dvadmin/utils/filters.py b/backend/dvadmin/utils/filters.py index 13ab42f..72915a8 100644 --- a/backend/dvadmin/utils/filters.py +++ b/backend/dvadmin/utils/filters.py @@ -14,13 +14,14 @@ from functools import reduce import six from django.db.models import Q, F from django.db.models.constants import LOOKUP_SEP -from django_filters import utils -from django_filters.filters import CharFilter +from django_filters import utils, FilterSet +from django_filters.filters import CharFilter, DateTimeFromToRangeFilter from django_filters.rest_framework import DjangoFilterBackend from django_filters.utils import get_model_field from rest_framework.filters import BaseFilterBackend from dvadmin.system.models import Dept, ApiWhiteList, RoleMenuButtonPermission +from dvadmin.utils.models import CoreModel def get_dept(dept_id: int, dept_all_list=None, dept_list=None): diff --git a/backend/dvadmin/utils/viewset.py b/backend/dvadmin/utils/viewset.py index a20b9be..b95dc09 100644 --- a/backend/dvadmin/utils/viewset.py +++ b/backend/dvadmin/utils/viewset.py @@ -7,6 +7,8 @@ @Remark: 自定义视图集 """ from django.db import transaction +from django_filters import DateTimeFromToRangeFilter +from django_filters.rest_framework import FilterSet from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema from rest_framework.decorators import action @@ -16,11 +18,23 @@ from dvadmin.utils.filters import DataLevelPermissionsFilter from dvadmin.utils.import_export_mixin import ExportSerializerMixin, ImportSerializerMixin 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.utils.models import get_custom_app_models, CoreModel from dvadmin.system.models import FieldPermission, MenuField from django_restql.mixins import QueryArgumentsMixin +class CoreModelFliterSet(FilterSet): + """ + 封装一个时间范围过滤器: + 使用方式: + {'create_datetime_after': '2024-01-01 8:00', 'create_datetime_before': '2024-01-05 10:00'} + """ + create_datetime = DateTimeFromToRangeFilter() + update_datetime = DateTimeFromToRangeFilter() + class Meta: + model = None + fields = "__all__" + class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMixin, QueryArgumentsMixin): """ 自定义的ModelViewSet: @@ -38,6 +52,7 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi filter_fields = '__all__' search_fields = () extra_filter_class = [DataLevelPermissionsFilter] + filterset_class = CoreModelFliterSet permission_classes = [CustomPermission] import_field_dict = {} export_field_label = {} diff --git a/web/src/utils/commonCrud.ts b/web/src/utils/commonCrud.ts index dd977b8..426f6af 100644 --- a/web/src/utils/commonCrud.ts +++ b/web/src/utils/commonCrud.ts @@ -1,6 +1,7 @@ -import { dict } from "@fast-crud/fast-crud"; +import {dict} from "@fast-crud/fast-crud"; import {shallowRef} from 'vue' import deptFormat from "/@/components/dept-format/index.vue"; + export const commonCrudConfig = (options = { create_datetime: { form: false, @@ -51,7 +52,7 @@ export const commonCrudConfig = (options = { align: 'center', width: 300, show: options.dept_belong_id?.table || false, - component:{ + component: { name: shallowRef(deptFormat), vModel: "modelValue", } @@ -62,7 +63,7 @@ export const commonCrudConfig = (options = { multiple: false, clearable: true, props: { - checkStrictly:true, + checkStrictly: true, props: { // 为什么这里要写两层props // 因为props属性名与fs的动态渲染的props命名冲突,所以要多写一层 @@ -132,7 +133,53 @@ export const commonCrudConfig = (options = { title: '更新时间', type: 'datetime', search: { - show: options.update_datetime?.search || false + show: options.update_datetime?.search || false, + col: {span: 8}, + component: { + type: 'datetimerange', + props: { + 'start-placeholder': '开始时间', + 'end-placeholder': '结束时间', + 'value-format': 'YYYY-MM-DD HH:mm:ss', + 'picker-options': { + shortcuts: [{ + text: '最近一周', + onClick(picker) { + const end = new Date(); + const start = new Date(); + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); + picker.$emit('pick', [start, end]); + } + }, { + text: '最近一个月', + onClick(picker) { + const end = new Date(); + const start = new Date(); + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); + picker.$emit('pick', [start, end]); + } + }, { + text: '最近三个月', + onClick(picker) { + const end = new Date(); + const start = new Date(); + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); + picker.$emit('pick', [start, end]); + } + }] + } + } + }, + valueResolve(context: any) { + const {key, value} = context + //value解析,就是把组件的值转化为后台所需要的值 + //在form表单点击保存按钮后,提交到后台之前执行转化 + if (value) { + context.form.update_datetime_after = value[0] + context.form.update_datetime_before = value[1] + } + // ↑↑↑↑↑ 注意这里是form,不是row + } }, column: { width: 160, @@ -149,14 +196,60 @@ export const commonCrudConfig = (options = { title: '创建时间', type: 'datetime', search: { - show: options.create_datetime?.search || false + show: options.create_datetime?.search || false, + col: {span: 8}, + component: { + type: 'datetimerange', + props: { + 'start-placeholder': '开始时间', + 'end-placeholder': '结束时间', + 'value-format': 'YYYY-MM-DD HH:mm:ss', + 'picker-options': { + shortcuts: [{ + text: '最近一周', + onClick(picker) { + const end = new Date(); + const start = new Date(); + start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); + picker.$emit('pick', [start, end]); + } + }, { + text: '最近一个月', + onClick(picker) { + const end = new Date(); + const start = new Date(); + start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); + picker.$emit('pick', [start, end]); + } + }, { + text: '最近三个月', + onClick(picker) { + const end = new Date(); + const start = new Date(); + start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); + picker.$emit('pick', [start, end]); + } + }] + } + } + }, + valueResolve(context: any) { + const {key, value} = context + //value解析,就是把组件的值转化为后台所需要的值 + //在form表单点击保存按钮后,提交到后台之前执行转化 + if (value) { + context.form.create_datetime_after = value[0] + context.form.create_datetime_before = value[1] + } + // ↑↑↑↑↑ 注意这里是form,不是row + } }, column: { width: 160, show: options.create_datetime?.table || false, }, form: { - show: false, + show: false }, viewForm: { show: true diff --git a/web/src/views/system/log/loginLog/crud.tsx b/web/src/views/system/log/loginLog/crud.tsx index e8a50be..a3fd92c 100644 --- a/web/src/views/system/log/loginLog/crud.tsx +++ b/web/src/views/system/log/loginLog/crud.tsx @@ -1,5 +1,6 @@ import * as api from './api'; import { UserPageQuery, AddReq, DelReq, EditReq, CreateCrudOptionsProps, CreateCrudOptionsRet, dict } from '@fast-crud/fast-crud'; +import {commonCrudConfig} from "/@/utils/commonCrud"; export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet { const pageRequest = async (query: UserPageQuery) => { @@ -325,6 +326,11 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp }, }, }, + ...commonCrudConfig({ + create_datetime: { + search: true + } + }) }, }, }; From 63453450ad9f91eebf8e27b881e80d4232a48015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com> Date: Tue, 2 Jan 2024 14:39:16 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8DBUG:=20=E5=BD=93dept=5F?= =?UTF-8?q?belong=5Fid=E4=B8=BAnull=E6=97=B6,=E8=A7=A6=E5=8F=91=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/utils/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/dvadmin/utils/serializers.py b/backend/dvadmin/utils/serializers.py index 698d9ee..5dd9527 100644 --- a/backend/dvadmin/utils/serializers.py +++ b/backend/dvadmin/utils/serializers.py @@ -26,7 +26,7 @@ class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer): # 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖 modifier_field_id = "modifier" modifier_name = serializers.SerializerMethodField(read_only=True) - dept_belong_id = serializers.IntegerField(required=False, default=None) + dept_belong_id = serializers.IntegerField(required=False, allow_null=True) def get_modifier_name(self, instance): if not hasattr(instance, "modifier"): From 0b554f36691f85d990fe7041d24bdcce8cf7bb74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com> Date: Tue, 2 Jan 2024 22:10:57 +0800 Subject: [PATCH 03/15] =?UTF-8?q?feat:=20=E9=BB=98=E8=AE=A4=E9=9B=86?= =?UTF-8?q?=E6=88=90celery=E4=B8=8Eredis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/conf/env.example.py | 16 ++--- backend/requirements.txt | 1 + docker-compose.yml | 130 +++++++++++++++++------------------- 3 files changed, 72 insertions(+), 75 deletions(-) diff --git a/backend/conf/env.example.py b/backend/conf/env.example.py index 03e8c1b..f20a698 100644 --- a/backend/conf/env.example.py +++ b/backend/conf/env.example.py @@ -7,12 +7,12 @@ from application.settings import BASE_DIR # ================================================= # # 数据库 ENGINE ,默认演示使用 sqlite3 数据库,正式环境建议使用 mysql 数据库 # sqlite3 设置 -DATABASE_ENGINE = "django.db.backends.sqlite3" -DATABASE_NAME = os.path.join(BASE_DIR, "db.sqlite3") +# DATABASE_ENGINE = "django.db.backends.sqlite3" +# DATABASE_NAME = os.path.join(BASE_DIR, "db.sqlite3") # 使用mysql时,改为此配置 -# DATABASE_ENGINE = "django.db.backends.mysql" -# DATABASE_NAME = 'django-vue-admin' # mysql 时使用 +DATABASE_ENGINE = "django.db.backends.mysql" +DATABASE_NAME = 'django-vue3-admin' # mysql 时使用 # 数据库地址 改为自己数据库地址 DATABASE_HOST = "127.0.0.1" @@ -21,16 +21,16 @@ DATABASE_PORT = 3306 # # 数据库用户名 DATABASE_USER = "root" # # 数据库密码 -DATABASE_PASSWORD = "123456" +DATABASE_PASSWORD = "DVADMIN3" # 表前缀 TABLE_PREFIX = "dvadmin_" # ================================================= # # ******** redis配置,无redis 可不进行配置 ******** # # ================================================= # -# REDIS_PASSWORD = '' -# REDIS_HOST = '127.0.0.1' -# REDIS_URL = f'redis://:{REDIS_PASSWORD or ""}@{REDIS_HOST}:6380' +REDIS_PASSWORD = 'DVADMIN3' +REDIS_HOST = '127.0.0.1' +REDIS_URL = f'redis://:{REDIS_PASSWORD or ""}@{REDIS_HOST}:6379' # ================================================= # # ****************** 功能 启停 ******************* # # ================================================= # diff --git a/backend/requirements.txt b/backend/requirements.txt index 95b96f8..4824df6 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -28,3 +28,4 @@ uvicorn==0.23.2 gunicorn==21.2.0 gevent==23.9.1 Pillow==10.1.0 +dvadmin-celery==1.0.5 diff --git a/docker-compose.yml b/docker-compose.yml index 13d8033..c08a0ef 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,6 +13,7 @@ services: - ./docker_env/nginx/my.conf:/etc/nginx/conf.d/my.conf expose: - "8080" + restart: always networks: network: ipv4_address: 177.10.0.11 @@ -23,9 +24,8 @@ services: dockerfile: ./docker_env/django/Dockerfile container_name: dvadmin3-django working_dir: /backend -# 打开mysql 时,打开此选项 -# depends_on: -# - dvadmin3-mysql + depends_on: + - dvadmin3-mysql environment: PYTHONUNBUFFERED: 1 DATABASE_HOST: dvadmin3-mysql @@ -42,74 +42,70 @@ services: network: ipv4_address: 177.10.0.12 -# dvadmin3-mysql: -# image: mysql:5.7 -# container_name: dvadmin3-mysql -# #使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限 -# #设置为true,不然数据卷可能挂载不了,启动不起 -## privileged: true -# restart: always -# ports: -# - "3306:3306" -# environment: -# MYSQL_ROOT_PASSWORD: "123456" -# MYSQL_DATABASE: "dvadmin3_pro" -# TZ: Asia/Shanghai -# command: -# --wait_timeout=31536000 -# --interactive_timeout=31536000 -# --max_connections=1000 -# --default-authentication-plugin=mysql_native_password -# volumes: -# - "./docker_env/mysql/data:/var/lib/mysql" -# - "./docker_env/mysql/conf.d:/etc/mysql/conf.d" -# - "./docker_env/mysql/logs:/logs" -# networks: -# network: -# ipv4_address: 177.10.0.13 + dvadmin3-mysql: + image: mysql:8.0 + container_name: dvadmin3-mysql + privileged: true + restart: always + ports: + - "3306:3306" + environment: + MYSQL_ROOT_PASSWORD: "DVADMIN3" + MYSQL_DATABASE: "django-vue3-admin" + TZ: Asia/Shanghai + command: + --wait_timeout=31536000 + --interactive_timeout=31536000 + --max_connections=1000 + --default-authentication-plugin=mysql_native_password + volumes: + - "./docker_env/mysql/data:/var/lib/mysql" + - "./docker_env/mysql/conf.d:/etc/mysql/conf.d" + - "./docker_env/mysql/logs:/logs" + networks: + network: + ipv4_address: 177.10.0.13 -# 如果使用celery 插件,请自行打开此注释 -# dvadmin3-celery: -# build: -# context: . -# dockerfile: ./docker_env/celery/Dockerfile -# # image: django:2.2 -# container_name: dvadmin3-celery -# working_dir: /backend -# depends_on: -# - dvadmin3-mysql -# environment: -# PYTHONUNBUFFERED: 1 -# DATABASE_HOST: dvadmin3-mysql -# TZ: Asia/Shanghai -# volumes: -# - ./backend:/backend -# - ./logs/log:/var/log -# restart: always -# networks: -# network: -# ipv4_address: 177.10.0.14 + dvadmin3-celery: + build: + context: . + dockerfile: ./docker_env/celery/Dockerfile + container_name: dvadmin3-celery + working_dir: /backend + depends_on: + - dvadmin3-mysql + environment: + PYTHONUNBUFFERED: 1 + DATABASE_HOST: dvadmin3-mysql + TZ: Asia/Shanghai + volumes: + - ./backend:/backend + - ./logs/log:/var/log + restart: always + networks: + network: + ipv4_address: 177.10.0.14 -# dvadmin3-redis: -# image: redis:6.2.6-alpine # 指定服务镜像,最好是与之前下载的redis配置文件保持一致 -# container_name: dvadmin3-redis # 容器名称 -# restart: on-failure # 重启方式 -# environment: -# - TZ=Asia/Shanghai # 设置时区 -# volumes: # 配置数据卷 -# - ./docker_env/redis/data:/data -# - ./docker_env/redis/redis.conf:/etc/redis/redis.conf -# ports: # 映射端口 -# - "6379:6379" -# sysctls: # 设置容器中的内核参数 -# - net.core.somaxconn=1024 -# command: /bin/sh -c "echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf && redis-server /etc/redis/redis.conf --appendonly yes" # 指定配置文件并开启持久化 -# privileged: true # 使用该参数,container内的root拥有真正的root权限。否则,container内的root只是外部的一个普通用户权限 -# networks: -# network: -# ipv4_address: 177.10.0.15 + dvadmin3-redis: + image: redis:6.2.6-alpine # 指定服务镜像,最好是与之前下载的redis配置文件保持一致 + container_name: dvadmin3-redis # 容器名称 + restart: always + environment: + - TZ=Asia/Shanghai # 设置时区 + volumes: # 配置数据卷 + - ./docker_env/redis/data:/data + - ./docker_env/redis/redis.conf:/etc/redis/redis.conf + ports: # 映射端口 + - "6379:6379" + sysctls: # 设置容器中的内核参数 + - net.core.somaxconn=1024 + command: /bin/sh -c "echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf && redis-server /etc/redis/redis.conf --appendonly yes --requirepass DVADMIN3" # 指定配置文件并开启持久化 + privileged: true # 使用该参数,container内的root拥有真正的root权限。否则,container内的root只是外部的一个普通用户权限 + networks: + network: + ipv4_address: 177.10.0.15 networks: From 97737c3ef167c6e4c43fa435a2ab764da3d9bfe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BC=BA?= <1206709430@qq.com> Date: Tue, 2 Jan 2024 23:17:39 +0800 Subject: [PATCH 04/15] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0docker=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E4=B8=80=E9=94=AE=E5=90=AF=E5=8A=A8=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/application/settings.py | 2 +- backend/conf/env.example.py | 2 +- docker_env/django/Dockerfile | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/application/settings.py b/backend/application/settings.py index 7f8e7d5..70446c1 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -404,7 +404,7 @@ PLUGINS_URL_PATTERNS = [] # ********** 一键导入插件配置开始 ********** # 例如: # from dvadmin_upgrade_center.settings import * # 升级中心 -# from dvadmin_celery.settings import * # celery 异步任务 +from dvadmin_celery.settings import * # celery 异步任务 # from dvadmin_third.settings import * # 第三方用户管理 # from dvadmin_ak_sk.settings import * # 秘钥管理管理 # from dvadmin_tenants.settings import * # 租户管理 diff --git a/backend/conf/env.example.py b/backend/conf/env.example.py index f20a698..bf015db 100644 --- a/backend/conf/env.example.py +++ b/backend/conf/env.example.py @@ -15,7 +15,7 @@ DATABASE_ENGINE = "django.db.backends.mysql" DATABASE_NAME = 'django-vue3-admin' # mysql 时使用 # 数据库地址 改为自己数据库地址 -DATABASE_HOST = "127.0.0.1" +DATABASE_HOST = '127.0.0.1' # # 数据库端口 DATABASE_PORT = 3306 # # 数据库用户名 diff --git a/docker_env/django/Dockerfile b/docker_env/django/Dockerfile index 3f8c93c..7acd383 100644 --- a/docker_env/django/Dockerfile +++ b/docker_env/django/Dockerfile @@ -1,6 +1,9 @@ FROM registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/dvadmin3-base-backend:latest WORKDIR /backend COPY ./backend/ . +RUN ls ./conf/ RUN awk 'BEGIN { cmd="cp -i ./conf/env.example.py ./conf/env.py "; print "n" |cmd; }' +RUN sed -i "s|DATABASE_HOST = "127.0.0.1"|DATABASE_HOST = '177.10.0.1'|g" ./conf/env.py +RUN sed -i "s|REDIS_HOST = '127.0.0.1'|REDIS_HOST = '177.10.0.1'|g" ./conf/env.py RUN python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ -r requirements.txt CMD ["/backend/docker_start.sh"] From 5510a18280a8a54418a9614e542d2b9498056b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com> Date: Wed, 3 Jan 2024 23:23:13 +0800 Subject: [PATCH 05/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8DBUG:=20=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E8=BF=87=E6=BB=A4=E5=99=A8=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=E6=97=A0=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/utils/viewset.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/dvadmin/utils/viewset.py b/backend/dvadmin/utils/viewset.py index b95dc09..2cd6145 100644 --- a/backend/dvadmin/utils/viewset.py +++ b/backend/dvadmin/utils/viewset.py @@ -52,7 +52,6 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi filter_fields = '__all__' search_fields = () extra_filter_class = [DataLevelPermissionsFilter] - filterset_class = CoreModelFliterSet permission_classes = [CustomPermission] import_field_dict = {} export_field_label = {} From 6f5bbb045db2e38c9702b4b03b6a89fc6e800666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com> Date: Thu, 4 Jan 2024 16:53:12 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8DBUG:=20=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E8=BF=87=E6=BB=A4=E5=99=A8=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=E6=97=A0=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/utils/filters.py | 30 ++++++++++++++++++++++++++++++ backend/dvadmin/utils/viewset.py | 16 ++-------------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/backend/dvadmin/utils/filters.py b/backend/dvadmin/utils/filters.py index 72915a8..cb61630 100644 --- a/backend/dvadmin/utils/filters.py +++ b/backend/dvadmin/utils/filters.py @@ -23,6 +23,36 @@ from rest_framework.filters import BaseFilterBackend from dvadmin.system.models import Dept, ApiWhiteList, RoleMenuButtonPermission from dvadmin.utils.models import CoreModel +class CoreModelFilterBankend(BaseFilterBackend): + """ + 自定义时间范围过滤器 + """ + def filter_queryset(self, request, queryset, view): + create_datetime_after = request.query_params.get('create_datetime_after', None) + create_datetime_before = request.query_params.get('create_datetime_before', None) + update_datetime_after = request.query_params.get('update_datetime_after', None) + update_datetime_before = request.query_params.get('update_datetime_after', None) + if any([create_datetime_after, create_datetime_before, update_datetime_after, update_datetime_before]): + create_filter = Q() + if create_datetime_after and create_datetime_before: + create_filter &= Q(create_datetime__gte=create_datetime_after) & Q(create_datetime__lte=create_datetime_before) + elif create_datetime_after: + create_filter &= Q(create_datetime__gte=create_datetime_after) + elif create_datetime_before: + create_filter &= Q(create_datetime__lte=create_datetime_before) + + # 更新时间范围过滤条件 + update_filter = Q() + if update_datetime_after and update_datetime_before: + update_filter &= Q(update_datetime__gte=update_datetime_after) & Q(update_datetime__lte=update_datetime_before) + elif update_datetime_after: + update_filter &= Q(update_datetime__gte=update_datetime_after) + elif update_datetime_before: + update_filter &= Q(update_datetime__lte=update_datetime_before) + # 结合两个时间范围过滤条件 + queryset = queryset.filter(create_filter & update_filter) + return queryset + return queryset def get_dept(dept_id: int, dept_all_list=None, dept_list=None): """ diff --git a/backend/dvadmin/utils/viewset.py b/backend/dvadmin/utils/viewset.py index 2cd6145..b85007a 100644 --- a/backend/dvadmin/utils/viewset.py +++ b/backend/dvadmin/utils/viewset.py @@ -14,7 +14,7 @@ from drf_yasg.utils import swagger_auto_schema from rest_framework.decorators import action from rest_framework.viewsets import ModelViewSet -from dvadmin.utils.filters import DataLevelPermissionsFilter +from dvadmin.utils.filters import DataLevelPermissionsFilter, CoreModelFilterBankend from dvadmin.utils.import_export_mixin import ExportSerializerMixin, ImportSerializerMixin from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse from dvadmin.utils.permission import CustomPermission @@ -23,18 +23,6 @@ from dvadmin.system.models import FieldPermission, MenuField from django_restql.mixins import QueryArgumentsMixin -class CoreModelFliterSet(FilterSet): - """ - 封装一个时间范围过滤器: - 使用方式: - {'create_datetime_after': '2024-01-01 8:00', 'create_datetime_before': '2024-01-05 10:00'} - """ - create_datetime = DateTimeFromToRangeFilter() - update_datetime = DateTimeFromToRangeFilter() - class Meta: - model = None - fields = "__all__" - class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMixin, QueryArgumentsMixin): """ 自定义的ModelViewSet: @@ -51,7 +39,7 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi update_serializer_class = None filter_fields = '__all__' search_fields = () - extra_filter_class = [DataLevelPermissionsFilter] + extra_filter_class = [CoreModelFilterBankend,DataLevelPermissionsFilter] permission_classes = [CustomPermission] import_field_dict = {} export_field_label = {} From 6798fca3625c2195d9292cdb4cf30454f1f57c22 Mon Sep 17 00:00:00 2001 From: H0nGzA1 <2505811377@qq.com> Date: Thu, 4 Jan 2024 19:49:40 +0800 Subject: [PATCH 07/15] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E9=A1=B5=E8=83=8C=E6=99=AFlogo=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/application/settings.py | 2 +- web/.env.development | 2 +- web/package.json | 1 + web/src/layout/logo/index.vue | 27 ++++++++++---- web/src/views/system/login/index.vue | 56 +++++++++++++++++++--------- 5 files changed, 62 insertions(+), 26 deletions(-) diff --git a/backend/application/settings.py b/backend/application/settings.py index 70446c1..7f8e7d5 100644 --- a/backend/application/settings.py +++ b/backend/application/settings.py @@ -404,7 +404,7 @@ PLUGINS_URL_PATTERNS = [] # ********** 一键导入插件配置开始 ********** # 例如: # from dvadmin_upgrade_center.settings import * # 升级中心 -from dvadmin_celery.settings import * # celery 异步任务 +# from dvadmin_celery.settings import * # celery 异步任务 # from dvadmin_third.settings import * # 第三方用户管理 # from dvadmin_ak_sk.settings import * # 秘钥管理管理 # from dvadmin_tenants.settings import * # 租户管理 diff --git a/web/.env.development b/web/.env.development index dc36b29..1c3ca5d 100644 --- a/web/.env.development +++ b/web/.env.development @@ -2,7 +2,7 @@ ENV = 'development' # 本地环境接口地址 -VITE_API_URL = 'http://127.0.0.1:8001' +VITE_API_URL = 'http://127.0.0.1:8000' # 是否启用按钮权限 VITE_PM_ENABLED = true diff --git a/web/package.json b/web/package.json index 28b837f..8a3be3f 100644 --- a/web/package.json +++ b/web/package.json @@ -14,6 +14,7 @@ "@fast-crud/fast-extends": "^1.19.2", "@fast-crud/ui-element": "^1.19.2", "@fast-crud/ui-interface": "^1.19.2", + "@types/lodash": "^4.14.202", "@vitejs/plugin-vue-jsx": "^3.0.0", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.12", diff --git a/web/src/layout/logo/index.vue b/web/src/layout/logo/index.vue index d71010c..99bf7da 100644 --- a/web/src/layout/logo/index.vue +++ b/web/src/layout/logo/index.vue @@ -1,10 +1,10 @@ @@ -13,8 +13,8 @@ import { computed } from 'vue'; import { storeToRefs } from 'pinia'; import { useThemeConfig } from '/@/stores/themeConfig'; import logoMini from '/@/assets/logo-mini.svg'; -import {SystemConfigStore} from "/@/stores/systemConfig"; - +import { SystemConfigStore } from "/@/stores/systemConfig"; +import _ from "lodash"; // 定义变量内容 const storesThemeConfig = useThemeConfig(); const { themeConfig } = storeToRefs(storesThemeConfig); @@ -31,11 +31,18 @@ const onThemeConfigChange = () => { }; const systemConfigStore = SystemConfigStore() -const {systemConfig} = storeToRefs(systemConfigStore) -const getSystemConfig = computed(()=>{ - return systemConfig.value +const { systemConfig } = storeToRefs(systemConfigStore) +const getSystemConfig = computed(() => { + return systemConfig.value }) +const siteLogo = computed(() => { + if (!_.isEmpty(getSystemConfig.value['login.site_logo'])) { + return getSystemConfig.value['login.site_logo'] + } + return logoMini +}); + diff --git a/web/src/views/system/demo/index.vue b/web/src/views/system/demo/index.vue index 4f7b7ec..4e71a9c 100644 --- a/web/src/views/system/demo/index.vue +++ b/web/src/views/system/demo/index.vue @@ -1,13 +1,80 @@ - - - From 85805e0d4b8561c5df0449938e3451da10c74225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com> Date: Fri, 16 Feb 2024 22:41:15 +0800 Subject: [PATCH 12/15] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=98=E5=8C=96:=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=A7=92=E8=89=B2=E6=8E=88=E6=9D=83=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E8=8E=B7=E5=8F=96=E6=8E=88=E6=9D=83=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/dvadmin/system/tests.py | 55 +++++++++++++++++++ .../views/role_menu_button_permission.py | 38 ++++++++++++- 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/backend/dvadmin/system/tests.py b/backend/dvadmin/system/tests.py index 2e9cb5f..866d09d 100644 --- a/backend/dvadmin/system/tests.py +++ b/backend/dvadmin/system/tests.py @@ -1 +1,56 @@ +from functools import wraps + +from django.db.models import Func, F, OuterRef, Exists from django.test import TestCase +import django +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings") +django.setup() +from dvadmin.system.models import Menu, RoleMenuPermission, RoleMenuButtonPermission, MenuButton + + +import time + +def timing_decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + start_time = time.time() + result = func(*args, **kwargs) + end_time = time.time() + run_time = end_time - start_time + print(f"{func.__name__} ran in {run_time:.6f} seconds") + return result + return wrapper + +@timing_decorator +def getMenu(): + data = [] + queryset = Menu.objects.filter(status=1, is_catalog=False).values('name', 'id') + for item in queryset: + parent_list = Menu.get_all_parent(item['id']) + names = [d["name"] for d in parent_list] + completeName = "/".join(names) + isCheck = RoleMenuPermission.objects.filter( + menu__id=item['id'], + role__id=1, + ).exists() + mbCheck = RoleMenuButtonPermission.objects.filter( + menu_button = OuterRef("pk"), + role__id=1, + ) + btns = MenuButton.objects.filter( + menu__id=item['id'], + ).annotate(isCheck=Exists(mbCheck)).values('id', 'name', 'value', 'isCheck',data_range=F('menu_button_permission__data_range')) + # print(b) + dicts = { + 'name': completeName, + 'id': item['id'], + 'isCheck': isCheck, + 'btns':btns + } + print(dicts) + data.append(dicts) + # print(data) + +if __name__ == '__main__': + getMenu() \ No newline at end of file diff --git a/backend/dvadmin/system/views/role_menu_button_permission.py b/backend/dvadmin/system/views/role_menu_button_permission.py index 6f77931..745daee 100644 --- a/backend/dvadmin/system/views/role_menu_button_permission.py +++ b/backend/dvadmin/system/views/role_menu_button_permission.py @@ -171,14 +171,46 @@ class RoleMenuButtonPermissionViewSet(CustomModelViewSet): if role is None: return ErrorResponse(msg="未获取到角色信息") is_superuser = request.user.is_superuser + # if is_superuser: + # queryset = Menu.objects.filter(status=1,is_catalog=False).values('name', 'id').all() + # else: + # role_id = request.user.role.values_list('id', flat=True) + # menu_list = RoleMenuPermission.objects.filter(role__in=role_id).values_list('id',flat=True) + # queryset = Menu.objects.filter(status=1, is_catalog=False,id__in=menu_list).values('name', 'id').all() + # serializer = RoleMenuPermissionSerializer(queryset,many=True,request=request) + # data = serializer.data + # return DetailResponse(data=data) + data = [] if is_superuser: queryset = Menu.objects.filter(status=1,is_catalog=False).values('name', 'id').all() else: role_id = request.user.role.values_list('id', flat=True) menu_list = RoleMenuPermission.objects.filter(role__in=role_id).values_list('id',flat=True) - queryset = Menu.objects.filter(status=1, is_catalog=False,id__in=menu_list).values('name', 'id').all() - serializer = RoleMenuPermissionSerializer(queryset,many=True,request=request) - data = serializer.data + queryset = Menu.objects.filter(status=1, is_catalog=False,id__in=menu_list).values('name', 'id') + for item in queryset: + parent_list = Menu.get_all_parent(item['id']) + names = [d["name"] for d in parent_list] + completeName = "/".join(names) + isCheck = RoleMenuPermission.objects.filter( + menu__id=item['id'], + role__id=role, + ).exists() + mbCheck = RoleMenuButtonPermission.objects.filter( + menu_button=OuterRef("pk"), + role__id=role, + ) + btns = MenuButton.objects.filter( + menu__id=item['id'], + ).annotate(isCheck=Exists(mbCheck)).values('id', 'name', 'value', 'isCheck', + data_range=F('menu_button_permission__data_range')) + dicts = { + 'name': completeName, + 'id': item['id'], + 'isCheck': isCheck, + 'btns': btns, + + } + data.append(dicts) return DetailResponse(data=data) @action(methods=['PUT'], detail=True, permission_classes=[IsAuthenticated]) From 26bbf67da8c0b9dab6ce4329ebcdc61e7f51194a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com> Date: Sun, 25 Feb 2024 15:03:07 +0800 Subject: [PATCH 13/15] =?UTF-8?q?=E6=96=B0=E5=8A=9F=E8=83=BD:=20=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E6=8E=88=E6=9D=83=E5=AD=97=E6=AE=B5=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/views/system/role/components/PermissionComNew/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/views/system/role/components/PermissionComNew/index.vue b/web/src/views/system/role/components/PermissionComNew/index.vue index 9819291..a76a154 100644 --- a/web/src/views/system/role/components/PermissionComNew/index.vue +++ b/web/src/views/system/role/components/PermissionComNew/index.vue @@ -49,7 +49,7 @@ -
+

对这些数据有以下字段权限