Merge remote-tracking branch 'origin/dev' into dev
commit
22879cb170
|
@ -2,4 +2,5 @@
|
||||||
# python manage.py makemigrations
|
# python manage.py makemigrations
|
||||||
# python manage.py migrate
|
# python manage.py migrate
|
||||||
# python manage.py init -y
|
# python manage.py init -y
|
||||||
gunicorn -c gunicorn_conf.py application.asgi:application
|
#gunicorn -c gunicorn_conf.py application.asgi:application
|
||||||
|
uvicorn application.asgi:application --port 8000 --host 0.0.0.0 --workers 4
|
||||||
|
|
|
@ -318,29 +318,29 @@ class FileList(CoreModel):
|
||||||
# 保存到File model中
|
# 保存到File model中
|
||||||
instance = FileList()
|
instance = FileList()
|
||||||
instance.name = file_name
|
instance.name = file_name
|
||||||
instance.engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") or 'local'
|
instance.engine = dispatch.get_system_config_values("file_storage.file_engine") or 'local'
|
||||||
instance.file_url = os.path.join(file_path, file_name)
|
instance.file_url = os.path.join(file_path, file_name)
|
||||||
instance.mime_type = mime_type
|
instance.mime_type = mime_type
|
||||||
instance.creator = request.user
|
instance.creator = request.user
|
||||||
instance.modifier = request.user.id
|
instance.modifier = request.user.id
|
||||||
instance.dept_belong_id = request.user.dept_id
|
instance.dept_belong_id = request.user.dept_id
|
||||||
|
|
||||||
file_backup = dispatch.get_system_config_values("fileStorageConfig.file_backup")
|
file_backup = dispatch.get_system_config_values("file_storage.file_backup")
|
||||||
file_engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") or 'local'
|
file_engine = dispatch.get_system_config_values("file_storage.file_engine") or 'local'
|
||||||
if file_backup:
|
if file_backup:
|
||||||
instance.url = os.path.join(file_path.replace('media/', ''), file_name)
|
instance.url = os.path.join(file_path.replace('media/', ''), file_name)
|
||||||
if file_engine == 'oss':
|
if file_engine == 'oss':
|
||||||
from dvadmin_cloud_storage.views.aliyun import ali_oss_upload
|
from dvadmin_cloud_storage.views.aliyun import ali_oss_upload
|
||||||
file = File(open(os.path.join(BASE_DIR, file_path, file_name)))
|
with open(os.path.join(BASE_DIR, file_path, file_name), 'rb') as file:
|
||||||
file_path = ali_oss_upload(file)
|
file_path = ali_oss_upload(file, file_name=os.path.join(file_path.replace('media/', ''), file_name))
|
||||||
if file_path:
|
if file_path:
|
||||||
instance.file_url = file_path
|
instance.file_url = file_path
|
||||||
else:
|
else:
|
||||||
raise ValueError("上传失败")
|
raise ValueError("上传失败")
|
||||||
elif file_engine == 'cos':
|
elif file_engine == 'cos':
|
||||||
from dvadmin_cloud_storage.views.tencent import tencent_cos_upload
|
from dvadmin_cloud_storage.views.tencent import tencent_cos_upload
|
||||||
file = File(open(os.path.join(BASE_DIR, file_path, file_name)))
|
with open(os.path.join(BASE_DIR, file_path, file_name), 'rb') as file:
|
||||||
file_path = tencent_cos_upload(file)
|
file_path = tencent_cos_upload(file, file_name=os.path.join(file_path.replace('media/', ''), file_name))
|
||||||
if file_path:
|
if file_path:
|
||||||
instance.file_url = file_path
|
instance.file_url = file_path
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -215,38 +215,39 @@ class DataVViewSet(GenericViewSet):
|
||||||
CHINA_PROVINCES = [
|
CHINA_PROVINCES = [
|
||||||
{'name': '北京', 'code': '110000'},
|
{'name': '北京', 'code': '110000'},
|
||||||
{'name': '天津', 'code': '120000'},
|
{'name': '天津', 'code': '120000'},
|
||||||
{'name': '河北', 'code': '130000'},
|
{'name': '河北省', 'code': '130000'},
|
||||||
{'name': '山西', 'code': '140000'},
|
{'name': '山西省', 'code': '140000'},
|
||||||
{'name': '内蒙古', 'code': '150000'},
|
{'name': '内蒙古', 'code': '150000'},
|
||||||
{'name': '辽宁', 'code': '210000'},
|
{'name': '辽宁省', 'code': '210000'},
|
||||||
{'name': '吉林', 'code': '220000'},
|
{'name': '吉林省', 'code': '220000'},
|
||||||
{'name': '黑龙江', 'code': '230000'},
|
{'name': '黑龙江省', 'code': '230000'},
|
||||||
{'name': '上海', 'code': '310000'},
|
{'name': '上海', 'code': '310000'},
|
||||||
{'name': '江苏', 'code': '320000'},
|
{'name': '江苏省', 'code': '320000'},
|
||||||
{'name': '浙江', 'code': '330000'},
|
{'name': '浙江省', 'code': '330000'},
|
||||||
{'name': '安徽', 'code': '340000'},
|
{'name': '安徽省', 'code': '340000'},
|
||||||
{'name': '福建', 'code': '350000'},
|
{'name': '福建省', 'code': '350000'},
|
||||||
{'name': '江西', 'code': '360000'},
|
{'name': '江西省', 'code': '360000'},
|
||||||
{'name': '山东', 'code': '370000'},
|
{'name': '山东省', 'code': '370000'},
|
||||||
{'name': '河南', 'code': '410000'},
|
{'name': '河南省', 'code': '410000'},
|
||||||
{'name': '湖北', 'code': '420000'},
|
{'name': '湖北省', 'code': '420000'},
|
||||||
{'name': '湖南', 'code': '430000'},
|
{'name': '湖南省', 'code': '430000'},
|
||||||
{'name': '广东', 'code': '440000'},
|
{'name': '广东省', 'code': '440000'},
|
||||||
{'name': '广西', 'code': '450000'},
|
{'name': '广西', 'code': '450000'},
|
||||||
{'name': '海南', 'code': '460000'},
|
{'name': '海南省', 'code': '460000'},
|
||||||
{'name': '重庆', 'code': '500000'},
|
{'name': '重庆', 'code': '500000'},
|
||||||
{'name': '四川', 'code': '510000'},
|
{'name': '四川省', 'code': '510000'},
|
||||||
{'name': '贵州', 'code': '520000'},
|
{'name': '贵州省', 'code': '520000'},
|
||||||
{'name': '云南', 'code': '530000'},
|
{'name': '云南省', 'code': '530000'},
|
||||||
{'name': '西藏', 'code': '540000'},
|
{'name': '西藏', 'code': '540000'},
|
||||||
{'name': '陕西', 'code': '610000'},
|
{'name': '陕西省', 'code': '610000'},
|
||||||
{'name': '甘肃', 'code': '620000'},
|
{'name': '甘肃省', 'code': '620000'},
|
||||||
{'name': '青海', 'code': '630000'},
|
{'name': '青海省', 'code': '630000'},
|
||||||
{'name': '宁夏', 'code': '640000'},
|
{'name': '宁夏', 'code': '640000'},
|
||||||
{'name': '新疆', 'code': '650000'},
|
{'name': '新疆', 'code': '650000'},
|
||||||
{'name': '台湾', 'code': '710000'},
|
{'name': '台湾', 'code': '710000'},
|
||||||
{'name': '香港', 'code': '810000'},
|
{'name': '香港', 'code': '810000'},
|
||||||
{'name': '澳门', 'code': '820000'},
|
{'name': '澳门', 'code': '820000'},
|
||||||
|
{'name': '钓鱼岛', 'code': '900000'},
|
||||||
{'name': '未知区域', 'code': '000000'},
|
{'name': '未知区域', 'code': '000000'},
|
||||||
]
|
]
|
||||||
provinces = [x['name'] for x in CHINA_PROVINCES]
|
provinces = [x['name'] for x in CHINA_PROVINCES]
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
|
import base64
|
||||||
import datetime
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
from pathlib import PurePosixPath
|
||||||
|
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from application.settings import BASE_DIR
|
from application.settings import BASE_DIR
|
||||||
from application import dispatch
|
from application import dispatch, settings
|
||||||
from dvadmin.system.models import FileList
|
from dvadmin.system.models import FileList, media_file_name
|
||||||
from dvadmin.system.views.ueditor_settings import ueditor_upload_settings, ueditor_settings
|
from dvadmin.system.views.ueditor_settings import ueditor_upload_settings, ueditor_settings
|
||||||
|
from dvadmin.utils.json_response import DetailResponse
|
||||||
from dvadmin.utils.serializers import CustomModelSerializer
|
from dvadmin.utils.serializers import CustomModelSerializer
|
||||||
from dvadmin.utils.string_util import format_bytes
|
from dvadmin.utils.string_util import format_bytes
|
||||||
from dvadmin.utils.viewset import CustomModelViewSet
|
from dvadmin.utils.viewset import CustomModelViewSet
|
||||||
|
@ -21,6 +24,16 @@ class FileSerializer(CustomModelSerializer):
|
||||||
url = serializers.SerializerMethodField(read_only=True)
|
url = serializers.SerializerMethodField(read_only=True)
|
||||||
|
|
||||||
def get_url(self, instance):
|
def get_url(self, instance):
|
||||||
|
if self.request.query_params.get('prefix'):
|
||||||
|
if settings.ENVIRONMENT in ['local']:
|
||||||
|
prefix = 'http://127.0.0.1:8000'
|
||||||
|
elif settings.ENVIRONMENT in ['test']:
|
||||||
|
prefix = 'http://{host}/api'.format(host=self.request.get_host())
|
||||||
|
else:
|
||||||
|
prefix = 'https://{host}/api'.format(host=self.request.get_host())
|
||||||
|
if instance.file_url:
|
||||||
|
return instance.file_url if instance.file_url.startswith('http') else f"{prefix}/{instance.file_url}"
|
||||||
|
return (f'{prefix}/media/{str(instance.url)}')
|
||||||
return instance.file_url or (f'media/{str(instance.url)}')
|
return instance.file_url or (f'media/{str(instance.url)}')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -28,8 +41,8 @@ class FileSerializer(CustomModelSerializer):
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
file_engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") or 'local'
|
file_engine = dispatch.get_system_config_values("file_storage.file_engine") or 'local'
|
||||||
file_backup = dispatch.get_system_config_values("fileStorageConfig.file_backup")
|
file_backup = dispatch.get_system_config_values("file_storage.file_backup")
|
||||||
file = self.initial_data.get('file')
|
file = self.initial_data.get('file')
|
||||||
file_size = file.size
|
file_size = file.size
|
||||||
validated_data['name'] = file.name
|
validated_data['name'] = file.name
|
||||||
|
@ -44,14 +57,18 @@ class FileSerializer(CustomModelSerializer):
|
||||||
validated_data['url'] = file
|
validated_data['url'] = file
|
||||||
if file_engine == 'oss':
|
if file_engine == 'oss':
|
||||||
from dvadmin_cloud_storage.views.aliyun import ali_oss_upload
|
from dvadmin_cloud_storage.views.aliyun import ali_oss_upload
|
||||||
file_path = ali_oss_upload(file)
|
h = validated_data['md5sum']
|
||||||
|
basename, ext = os.path.splitext(file.name)
|
||||||
|
file_path = ali_oss_upload(file, file_name=PurePosixPath("files", h[:1], h[1:2], h + ext.lower()))
|
||||||
if file_path:
|
if file_path:
|
||||||
validated_data['file_url'] = file_path
|
validated_data['file_url'] = file_path
|
||||||
else:
|
else:
|
||||||
raise ValueError("上传失败")
|
raise ValueError("上传失败")
|
||||||
elif file_engine == 'cos':
|
elif file_engine == 'cos':
|
||||||
from dvadmin_cloud_storage.views.tencent import tencent_cos_upload
|
from dvadmin_cloud_storage.views.tencent import tencent_cos_upload
|
||||||
file_path = tencent_cos_upload(file)
|
h = validated_data['md5sum']
|
||||||
|
basename, ext = os.path.splitext(file.name)
|
||||||
|
file_path = tencent_cos_upload(file, file_name=PurePosixPath("files", h[:1], h[1:2], h + ext.lower()))
|
||||||
if file_path:
|
if file_path:
|
||||||
validated_data['file_url'] = file_path
|
validated_data['file_url'] = file_path
|
||||||
else:
|
else:
|
||||||
|
@ -83,6 +100,12 @@ class FileViewSet(CustomModelViewSet):
|
||||||
filter_fields = ['name', ]
|
filter_fields = ['name', ]
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
serializer = self.get_serializer(data=request.data, request=request)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
self.perform_create(serializer)
|
||||||
|
return DetailResponse(data=serializer.data, msg="新增成功")
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
@action(methods=["GET", "POST"], detail=False, permission_classes=[])
|
@action(methods=["GET", "POST"], detail=False, permission_classes=[])
|
||||||
def ueditor(self, request):
|
def ueditor(self, request):
|
||||||
|
@ -138,16 +161,17 @@ class FileViewSet(CustomModelViewSet):
|
||||||
# 涂鸦功能上传处理
|
# 涂鸦功能上传处理
|
||||||
def save_scrawl_file(self, request, file_path, file_name):
|
def save_scrawl_file(self, request, file_path, file_name):
|
||||||
import base64
|
import base64
|
||||||
|
instance = None
|
||||||
try:
|
try:
|
||||||
content = request.data.get(ueditor_upload_settings.get("scrawlFieldName", "upfile"))
|
content = request.data.get(ueditor_upload_settings.get("scrawlFieldName", "upfile"))
|
||||||
f = open(os.path.join(BASE_DIR, file_path, file_name), 'wb')
|
f = open(os.path.join(BASE_DIR, file_path, file_name), 'wb')
|
||||||
f.write(base64.b64decode(content))
|
f.write(base64.b64decode(content))
|
||||||
f.close()
|
f.close()
|
||||||
state = "SUCCESS"
|
state = "SUCCESS"
|
||||||
FileList.save_file(request, file_path, file_name,mime_type='image/png')
|
instance = FileList.save_file(request, file_path, file_name, mime_type='image/png')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
state = f"写入图片文件错误:{e}"
|
state = f"写入图片文件错误:{e}"
|
||||||
return state
|
return state, instance
|
||||||
|
|
||||||
def upload_file(self, request):
|
def upload_file(self, request):
|
||||||
"""上传文件"""
|
"""上传文件"""
|
||||||
|
@ -213,20 +237,21 @@ class FileViewSet(CustomModelViewSet):
|
||||||
# 取得输出文件的路径
|
# 取得输出文件的路径
|
||||||
format_file_name, output_path = self.get_output_path(path_format_var)
|
format_file_name, output_path = self.get_output_path(path_format_var)
|
||||||
# 所有检测完成后写入文件
|
# 所有检测完成后写入文件
|
||||||
|
file_instance = None
|
||||||
if state == "SUCCESS":
|
if state == "SUCCESS":
|
||||||
if action == "uploadscrawl":
|
if action == "uploadscrawl":
|
||||||
state = self.save_scrawl_file(request, file_path=output_path,
|
state, file_instance = self.save_scrawl_file(request, file_path=output_path,
|
||||||
file_name=format_file_name)
|
file_name=format_file_name)
|
||||||
else:
|
else:
|
||||||
file = request.FILES.get(upload_field_name, None)
|
file = request.FILES.get(upload_field_name, None)
|
||||||
# 保存到文件中,如果保存错误,需要返回ERROR
|
# 保存到文件中,如果保存错误,需要返回ERROR
|
||||||
state = self.save_upload_file(file, os.path.join(BASE_DIR, output_path, format_file_name))
|
state = self.save_upload_file(file, os.path.join(BASE_DIR, output_path, format_file_name))
|
||||||
# 保存到附件管理中
|
# 保存到附件管理中
|
||||||
FileList.save_file(request, output_path, format_file_name, mime_type=file.content_type)
|
file_instance = FileList.save_file(request, output_path, format_file_name, mime_type=file.content_type)
|
||||||
|
|
||||||
# 返回数据
|
# 返回数据
|
||||||
return_info = {
|
return_info = {
|
||||||
'url': os.path.join(output_path, format_file_name), # 保存后的文件名称
|
'url': file_instance.file_url if file_instance else os.path.join(output_path, format_file_name), # 保存后的文件名称
|
||||||
'original': upload_file_name, # 原始文件名
|
'original': upload_file_name, # 原始文件名
|
||||||
'type': upload_original_ext,
|
'type': upload_original_ext,
|
||||||
'state': state, # 上传状态,成功时返回SUCCESS,其他任何值将原样返回至图片上传框中
|
'state': state, # 上传状态,成功时返回SUCCESS,其他任何值将原样返回至图片上传框中
|
||||||
|
|
|
@ -249,16 +249,16 @@ class UserViewSet(CustomModelViewSet):
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
create_serializer_class = UserCreateSerializer
|
create_serializer_class = UserCreateSerializer
|
||||||
update_serializer_class = UserUpdateSerializer
|
update_serializer_class = UserUpdateSerializer
|
||||||
# filter_fields = ["name", "username", "gender", "is_active", "dept", "user_type"]
|
filter_fields = ["^name", "~username", "^mobile", "is_active", "dept", "user_type", "$dept__name"]
|
||||||
filter_fields = {
|
# filter_fields = {
|
||||||
"name": ["icontains"],
|
# "name": ["icontains"],
|
||||||
"mobile": ["icontains"],
|
# "mobile": ["iregex"],
|
||||||
"username": ["icontains"],
|
# "username": ["icontains"],
|
||||||
"gender": ["icontains"],
|
# "is_active": ["icontains"],
|
||||||
"is_active": ["icontains"],
|
# "dept": ["exact"],
|
||||||
"dept": ["exact"],
|
# "user_type": ["exact"],
|
||||||
"user_type": ["exact"],
|
# "dept__name": ["icontains"],
|
||||||
}
|
# }
|
||||||
search_fields = ["username", "name", "gender", "dept__name", "role__name"]
|
search_fields = ["username", "name", "gender", "dept__name", "role__name"]
|
||||||
# 导出
|
# 导出
|
||||||
export_field_label = {
|
export_field_label = {
|
||||||
|
|
|
@ -150,6 +150,7 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
"$": "iregex",
|
"$": "iregex",
|
||||||
"~": "icontains",
|
"~": "icontains",
|
||||||
}
|
}
|
||||||
|
filter_fields = "__all__"
|
||||||
|
|
||||||
def construct_search(self, field_name, lookup_expr=None):
|
def construct_search(self, field_name, lookup_expr=None):
|
||||||
lookup = self.lookup_prefixes.get(field_name[0])
|
lookup = self.lookup_prefixes.get(field_name[0])
|
||||||
|
@ -157,14 +158,16 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
field_name = field_name[1:]
|
field_name = field_name[1:]
|
||||||
else:
|
else:
|
||||||
lookup = lookup_expr
|
lookup = lookup_expr
|
||||||
|
if lookup:
|
||||||
if field_name.endswith(lookup):
|
if field_name.endswith(lookup):
|
||||||
return field_name
|
return field_name
|
||||||
return LOOKUP_SEP.join([field_name, lookup])
|
return LOOKUP_SEP.join([field_name, lookup])
|
||||||
|
return field_name
|
||||||
|
|
||||||
def find_filter_lookups(self, orm_lookups, search_term_key):
|
def find_filter_lookups(self, orm_lookups, search_term_key):
|
||||||
for lookup in orm_lookups:
|
for lookup in orm_lookups:
|
||||||
# if lookup.find(search_term_key) >= 0:
|
# if lookup.find(search_term_key) >= 0:
|
||||||
new_lookup = lookup.split("__")[0]
|
new_lookup = LOOKUP_SEP.join(lookup.split(LOOKUP_SEP)[:-1]) if len(lookup.split(LOOKUP_SEP)) > 1 else lookup
|
||||||
# 修复条件搜索错误 bug
|
# 修复条件搜索错误 bug
|
||||||
if new_lookup == search_term_key:
|
if new_lookup == search_term_key:
|
||||||
return lookup
|
return lookup
|
||||||
|
@ -189,7 +192,13 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
utils.deprecate(
|
utils.deprecate(
|
||||||
"`%s.filter_fields` attribute should be renamed `filterset_fields`." % view.__class__.__name__
|
"`%s.filter_fields` attribute should be renamed `filterset_fields`." % view.__class__.__name__
|
||||||
)
|
)
|
||||||
filterset_fields = getattr(view, "filter_fields", None)
|
self.filter_fields = getattr(view, "filter_fields", None)
|
||||||
|
if isinstance(self.filter_fields, (list, tuple)):
|
||||||
|
filterset_fields = [
|
||||||
|
field[1:] if field[0] in self.lookup_prefixes.keys() else field for field in self.filter_fields
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
filterset_fields = self.filter_fields
|
||||||
|
|
||||||
if filterset_class:
|
if filterset_class:
|
||||||
filterset_model = filterset_class._meta.model
|
filterset_model = filterset_class._meta.model
|
||||||
|
@ -327,18 +336,22 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
return queryset
|
return queryset
|
||||||
if filterset.__class__.__name__ == "AutoFilterSet":
|
if filterset.__class__.__name__ == "AutoFilterSet":
|
||||||
queryset = filterset.queryset
|
queryset = filterset.queryset
|
||||||
orm_lookups = []
|
filter_fields = filterset.filters if self.filter_fields == "__all__" else self.filter_fields
|
||||||
for search_field in filterset.filters:
|
orm_lookup_dict = dict(
|
||||||
if isinstance(filterset.filters[search_field], CharFilter):
|
zip(
|
||||||
orm_lookups.append(
|
[field for field in filter_fields],
|
||||||
self.construct_search(six.text_type(search_field), filterset.filters[search_field].lookup_expr)
|
[filterset.filters[lookup].lookup_expr for lookup in filterset.filters.keys()],
|
||||||
)
|
)
|
||||||
else:
|
)
|
||||||
orm_lookups.append(search_field)
|
orm_lookups = [
|
||||||
|
self.construct_search(lookup, lookup_expr) for lookup, lookup_expr in orm_lookup_dict.items()
|
||||||
|
]
|
||||||
|
# print(orm_lookups)
|
||||||
conditions = []
|
conditions = []
|
||||||
queries = []
|
queries = []
|
||||||
for search_term_key in filterset.data.keys():
|
for search_term_key in filterset.data.keys():
|
||||||
orm_lookup = self.find_filter_lookups(orm_lookups, search_term_key)
|
orm_lookup = self.find_filter_lookups(orm_lookups, search_term_key)
|
||||||
|
# print(search_term_key, orm_lookup)
|
||||||
if not orm_lookup:
|
if not orm_lookup:
|
||||||
continue
|
continue
|
||||||
query = Q(**{orm_lookup: filterset.data[search_term_key]})
|
query = Q(**{orm_lookup: filterset.data[search_term_key]})
|
||||||
|
|
|
@ -118,7 +118,6 @@ class SoftDeleteModel(models.Model):
|
||||||
]
|
]
|
||||||
relations["self"] = f"{tree_model_field[0]}_id" if len(tree_model_field) == 1 else None
|
relations["self"] = f"{tree_model_field[0]}_id" if len(tree_model_field) == 1 else None
|
||||||
relations["foreign"] = related_fields
|
relations["foreign"] = related_fields
|
||||||
print(f"{relations=}", flush=True)
|
|
||||||
return relations
|
return relations
|
||||||
|
|
||||||
def _is_cascade(self, relation):
|
def _is_cascade(self, relation):
|
||||||
|
|
|
@ -3,7 +3,7 @@ certifi==2021.5.30
|
||||||
chardet==4.0.0
|
chardet==4.0.0
|
||||||
coreapi==2.3.3
|
coreapi==2.3.3
|
||||||
coreschema==0.0.4
|
coreschema==0.0.4
|
||||||
Django==3.2.12
|
Django==3.2.19
|
||||||
django-comment-migrate==0.1.7
|
django-comment-migrate==0.1.7
|
||||||
django-cors-headers==3.10.1
|
django-cors-headers==3.10.1
|
||||||
django-filter==22.1
|
django-filter==22.1
|
||||||
|
@ -11,8 +11,8 @@ django-ranged-response==0.2.0
|
||||||
django-redis==5.2.0
|
django-redis==5.2.0
|
||||||
django-restql==0.15.3
|
django-restql==0.15.3
|
||||||
django-simple-captcha==0.5.17
|
django-simple-captcha==0.5.17
|
||||||
django-tenants==3.4.8
|
django-tenants==3.5.0
|
||||||
django-timezone-field==4.2.3
|
django-timezone-field==5.0
|
||||||
djangorestframework==3.14.0
|
djangorestframework==3.14.0
|
||||||
djangorestframework-simplejwt==5.2.2
|
djangorestframework-simplejwt==5.2.2
|
||||||
packaging==23.0
|
packaging==23.0
|
||||||
|
@ -29,7 +29,7 @@ pyparsing==2.4.7
|
||||||
pyPEG2==2.15.2
|
pyPEG2==2.15.2
|
||||||
pypinyin==0.48.0
|
pypinyin==0.48.0
|
||||||
pytz==2021.1
|
pytz==2021.1
|
||||||
requests==2.28.2
|
requests==2.28.0
|
||||||
ruamel.yaml==0.17.10
|
ruamel.yaml==0.17.10
|
||||||
ruamel.yaml.clib==0.2.4
|
ruamel.yaml.clib==0.2.4
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
|
|
|
@ -6,4 +6,6 @@ VUE_APP_TITLE=企业级后台管理系统
|
||||||
VUE_APP_PM_ENABLED = true
|
VUE_APP_PM_ENABLED = true
|
||||||
# 后端接口地址及端口(域名)
|
# 后端接口地址及端口(域名)
|
||||||
VUE_APP_API = "http://127.0.0.1:8000"
|
VUE_APP_API = "http://127.0.0.1:8000"
|
||||||
|
VUE_APP_VERSION = '2.0.4'
|
||||||
|
# 文件存储引擎
|
||||||
|
VUE_APP_FILE_ENGINE = 'local' # oss、cos、local
|
||||||
|
|
|
@ -13,3 +13,5 @@ VUE_APP_SCOURCE_LINK=FALSE
|
||||||
VUE_APP_PUBLIC_PATH=/
|
VUE_APP_PUBLIC_PATH=/
|
||||||
# 启用权限管理
|
# 启用权限管理
|
||||||
VUE_APP_PM_ENABLED = true
|
VUE_APP_PM_ENABLED = true
|
||||||
|
# 文件存储引擎
|
||||||
|
VUE_APP_FILE_ENGINE = 'local' # oss、cos、local
|
||||||
|
|
|
@ -13,3 +13,5 @@ VUE_APP_SCOURCE_LINK=FALSE
|
||||||
VUE_APP_PUBLIC_PATH=/
|
VUE_APP_PUBLIC_PATH=/
|
||||||
# 启用权限管理
|
# 启用权限管理
|
||||||
VUE_APP_PM_ENABLED = true
|
VUE_APP_PM_ENABLED = true
|
||||||
|
# 文件存储引擎
|
||||||
|
VUE_APP_FILE_ENGINE = 'local' # oss、cos、local
|
||||||
|
|
|
@ -56,6 +56,9 @@
|
||||||
<div style="text-align: center" v-if="_elProps.listType === 'avatar'">
|
<div style="text-align: center" v-if="_elProps.listType === 'avatar'">
|
||||||
<img style="max-width: 100%;" :src="dialogImageUrl" alt="">
|
<img style="max-width: 100%;" :src="dialogImageUrl" alt="">
|
||||||
</div>
|
</div>
|
||||||
|
<div style="text-align: center" v-else-if="_elProps.listType === 'picture-card'">
|
||||||
|
<img style="max-width: 100%;" :src="dialogImageUrl" alt="">
|
||||||
|
</div>
|
||||||
<div style="text-align: center" v-else>
|
<div style="text-align: center" v-else>
|
||||||
<div id="player" v-if="dialogVisible">
|
<div id="player" v-if="dialogVisible">
|
||||||
<div class="player-container">
|
<div class="player-container">
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<el-row style="margin-bottom: 0" :gutter="5" v-for="(field, index) in currentForm.data" :key="index">
|
<el-row style="margin-bottom: 0" :gutter="5" v-for="(field, index) in currentForm.data" :key="index">
|
||||||
<el-col :span="elProps.index.span" v-if="elProps.index">
|
<el-col :span="elProps.index.span" v-if="elProps.index">
|
||||||
<div style="text-align: center">
|
<div style="text-align: center">
|
||||||
{{index+1}}
|
{{ index + 1 }}
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="elProps.fields[key].span" v-for="(_,key) in elProps.fields" :key="key">
|
<el-col :span="elProps.fields[key].span" v-for="(_,key) in elProps.fields" :key="key">
|
||||||
|
@ -34,20 +34,23 @@
|
||||||
:value="item.value">
|
:value="item.value">
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-input-number style="width: 100%" v-else-if="elProps.fields[key].type === 'number'" controls-position="right" v-model="field[key]"></el-input-number>
|
<el-input-number style="width: 100%" v-else-if="elProps.fields[key].type === 'number'"
|
||||||
<div v-else-if="elProps.fields[key].type === 'image'" style="height: 30px;width: 30px;">
|
controls-position="right" v-model="field[key]"></el-input-number>
|
||||||
<d2p-file-uploader v-model="field[key]" :elProps="elProps.fields[key].elProps || { listType: 'picture-card', accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif', limit: 1 }"></d2p-file-uploader>
|
<div class="d2p-images" v-else-if="elProps.fields[key].type === 'image'">
|
||||||
|
<d2p-file-uploader v-model="field[key]"
|
||||||
|
:elProps="elProps.fields[key].elProps || { listType: 'picture-card', accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif', limit: 1 }"></d2p-file-uploader>
|
||||||
</div>
|
</div>
|
||||||
<!-- 富文本 -->
|
<!-- 富文本 -->
|
||||||
<span v-else-if="elProps.fields[key].type === 'ueditor'">
|
<span v-else-if="elProps.fields[key].type === 'ueditor'">
|
||||||
<values-popover v-model="field[key]" :elProps="{ type: 'ueditor' }" @previewClick="previewClick(index,key)"></values-popover>
|
<values-popover v-model="field[key]" :elProps="{ type: 'ueditor' }"
|
||||||
|
@previewClick="previewClick(index,key)"></values-popover>
|
||||||
</span>
|
</span>
|
||||||
<!-- 多对多 -->
|
<!-- 多对多 -->
|
||||||
<span v-else-if="elProps.fields[key].type === 'many_to_many'">
|
<span v-else-if="elProps.fields[key].type === 'many_to_many'">
|
||||||
<values-popover
|
<values-popover
|
||||||
v-model="field[key]"
|
v-model="field[key]"
|
||||||
:dict="elProps.fields[key].dict"
|
:dict="elProps.fields[key].dict"
|
||||||
:elProps="{ type: elProps.fields[key].value?.type || 'strList', rowKey: elProps.fields[key].value?.rowKey || 'title', label: elProps.value?.title || '答复选项内容' }"
|
:elProps="{ type: elProps.fields[key].value?.type || 'manyToMany', rowKey: elProps.fields[key].value?.rowKey || 'title', label: elProps.value?.title || '答复选项内容' }"
|
||||||
@listClick="manyToManyClick(index,key)">
|
@listClick="manyToManyClick(index,key)">
|
||||||
</values-popover>
|
</values-popover>
|
||||||
</span>
|
</span>
|
||||||
|
@ -56,8 +59,10 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="4">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button @click.prevent="topDomain(index)" :disabled="index === 0" type="primary" circle icon="el-icon-top"></el-button>
|
<el-button @click.prevent="topDomain(index)" :disabled="index === 0" type="primary" circle
|
||||||
<el-button @click.prevent="bottomDomain(index)" :disabled="index === currentForm.data.length - 1" type="primary" circle icon="el-icon-bottom"></el-button>
|
icon="el-icon-top"></el-button>
|
||||||
|
<el-button @click.prevent="bottomDomain(index)" :disabled="index === currentForm.data.length - 1"
|
||||||
|
type="primary" circle icon="el-icon-bottom"></el-button>
|
||||||
<el-button @click.prevent="removeDomain(index)" type="danger" circle icon="el-icon-delete"></el-button>
|
<el-button @click.prevent="removeDomain(index)" type="danger" circle icon="el-icon-delete"></el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -102,6 +107,7 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import util from '@/libs/util.js'
|
import util from '@/libs/util.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'foreignKeyCrudForm',
|
name: 'foreignKeyCrudForm',
|
||||||
model: {
|
model: {
|
||||||
|
@ -213,21 +219,21 @@ export default {
|
||||||
ueditorConfig: {
|
ueditorConfig: {
|
||||||
serverUrl: util.baseURL() + 'api/system/file/ueditor/',
|
serverUrl: util.baseURL() + 'api/system/file/ueditor/',
|
||||||
headers: { Authorization: 'JWT ' + util.cookies.get('token') },
|
headers: { Authorization: 'JWT ' + util.cookies.get('token') },
|
||||||
imageUrlPrefix: util.baseURL(),
|
imageUrlPrefix: util.baseFileURL(),
|
||||||
// 涂鸦图片上传
|
// 涂鸦图片上传
|
||||||
scrawlUrlPrefix: util.baseURL(),
|
scrawlUrlPrefix: util.baseFileURL(),
|
||||||
// 截图工具上传
|
// 截图工具上传
|
||||||
snapscreenUrlPrefix: util.baseURL(),
|
snapscreenUrlPrefix: util.baseFileURL(),
|
||||||
// 抓取远程图片路径前缀
|
// 抓取远程图片路径前缀
|
||||||
catcherUrlPrefix: util.baseURL(),
|
catcherUrlPrefix: util.baseFileURL(),
|
||||||
// 视频访问路径前缀
|
// 视频访问路径前缀
|
||||||
videoUrlPrefix: util.baseURL(),
|
videoUrlPrefix: util.baseFileURL(),
|
||||||
// 文件访问路径前缀
|
// 文件访问路径前缀
|
||||||
fileUrlPrefix: util.baseURL(),
|
fileUrlPrefix: util.baseFileURL(),
|
||||||
// 列出指定目录下的图片
|
// 列出指定目录下的图片
|
||||||
imageManagerUrlPrefix: util.baseURL(),
|
imageManagerUrlPrefix: util.baseFileURL(),
|
||||||
// 列出指定目录下的文件
|
// 列出指定目录下的文件
|
||||||
fileManagerUrlPrefix: util.baseURL()
|
fileManagerUrlPrefix: util.baseFileURL()
|
||||||
// 传入ueditor的配置
|
// 传入ueditor的配置
|
||||||
// 文档参考: http://fex.baidu.com/ueditor/#start-config
|
// 文档参考: http://fex.baidu.com/ueditor/#start-config
|
||||||
},
|
},
|
||||||
|
@ -346,8 +352,37 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style lang="scss">
|
||||||
::v-deep .d2p-file-uploader .el-upload--picture-card{
|
.d2p-images {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
|
||||||
|
.el-upload-list__item-thumbnail {
|
||||||
|
height: 60px !important;
|
||||||
|
width: 60px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-upload-list__item {
|
||||||
|
width: 60px !important;
|
||||||
|
height: 60px !important;
|
||||||
|
line-height: 0 !important;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 60px !important;
|
||||||
|
width: 60px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-upload-list__item-actions {
|
||||||
|
height: 60px !important;
|
||||||
|
width: 60px !important;
|
||||||
|
line-height: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
::v-deep .d2p-file-uploader .el-upload--picture-card {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="#999">
|
||||||
|
<path opacity=".25" d="M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4"/>
|
||||||
|
<path d="M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z">
|
||||||
|
<animateTransform attributeName="transform" type="rotate" from="0 16 16" to="360 16 16" dur="0.8s" repeatCount="indefinite" />
|
||||||
|
</path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 422 B |
|
@ -40,7 +40,18 @@
|
||||||
<el-table-column fixed type="index" label="#" width="50"/>
|
<el-table-column fixed type="index" label="#" width="50"/>
|
||||||
<span v-for="(item,index) in _elProps.tableConfig.columns" :key="index" >
|
<span v-for="(item,index) in _elProps.tableConfig.columns" :key="index" >
|
||||||
<el-table-column :prop="item.prop" :label="item.label" :width="item.width"
|
<el-table-column :prop="item.prop" :label="item.label" :width="item.width"
|
||||||
v-if="item.show !== false"/>
|
v-if="item.show !== false">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span v-if="item.type === 'image'">
|
||||||
|
<el-image :src="baseURL + scope.row[item.prop]" style="height: 30px;width: 30px;">
|
||||||
|
<div slot="placeholder" class="image-slot">
|
||||||
|
<img src="./loading-spin.svg">
|
||||||
|
</div>
|
||||||
|
</el-image>
|
||||||
|
</span>
|
||||||
|
<span v-else>{{ scope.row[item.prop] }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</span>
|
</span>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-pagination style="margin-top: 10px;max-width: 200px" background
|
<el-pagination style="margin-top: 10px;max-width: 200px" background
|
||||||
|
@ -80,6 +91,7 @@
|
||||||
import { request } from '@/api/service'
|
import { request } from '@/api/service'
|
||||||
import XEUtils from 'xe-utils'
|
import XEUtils from 'xe-utils'
|
||||||
import { d2CrudPlus } from 'd2-crud-plus'
|
import { d2CrudPlus } from 'd2-crud-plus'
|
||||||
|
import util from '@/libs/util'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'selector-table-input',
|
name: 'selector-table-input',
|
||||||
|
@ -147,7 +159,8 @@ export default {
|
||||||
search: null,
|
search: null,
|
||||||
tableData: [],
|
tableData: [],
|
||||||
multipleSelection: [],
|
multipleSelection: [],
|
||||||
collapseTags: false
|
collapseTags: false,
|
||||||
|
baseURL: util.baseURL()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -306,7 +306,7 @@ export default {
|
||||||
},
|
},
|
||||||
itemClosed (item) {
|
itemClosed (item) {
|
||||||
const newNodes = lodash.without(this.selected, item)
|
const newNodes = lodash.without(this.selected, item)
|
||||||
console.log('new value', item, newNodes)
|
// console.log('new value', item, newNodes)
|
||||||
this.$set(this, 'selected', newNodes)
|
this.$set(this, 'selected', newNodes)
|
||||||
this.doValueInputChanged(newNodes)
|
this.doValueInputChanged(newNodes)
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,6 +36,30 @@
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="elProps.type === 'manyToMany'">
|
||||||
|
<el-popover
|
||||||
|
placement="right"
|
||||||
|
width="300"
|
||||||
|
trigger="hover"
|
||||||
|
v-if="value.length > 0"
|
||||||
|
@show="showEvents"
|
||||||
|
@hide="show=false">
|
||||||
|
<el-descriptions class="margin-top" :column="1" size="mini" border>
|
||||||
|
<el-descriptions-item v-for="(item,index) in value" :key="index" labelStyle="width: 60px;">
|
||||||
|
<template slot="label">
|
||||||
|
选项{{ index + 1 }}
|
||||||
|
</template>
|
||||||
|
{{ item[dict.label] }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<el-button type="primary" plain size="mini" slot="reference" @click="listClick"><span> {{ value.length }} {{ elProps.unit }}</span>
|
||||||
|
</el-button>
|
||||||
|
</el-popover>
|
||||||
|
<el-button v-else type="primary" plain size="mini" slot="reference" @click="listClick"><span> {{
|
||||||
|
value.length
|
||||||
|
}} {{ elProps.unit }}</span>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
<div v-else-if="elProps.type === 'ueditor'">
|
<div v-else-if="elProps.type === 'ueditor'">
|
||||||
<el-popover
|
<el-popover
|
||||||
placement="right"
|
placement="right"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import util from '@/libs/util.js'
|
import util from '@/libs/util.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
'image-uploader': {
|
'image-uploader': {
|
||||||
form: { component: { name: 'd2p-file-uploader', props: { elProps: { listType: 'picture-card', accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif' } } } },
|
form: { component: { name: 'd2p-file-uploader', props: { elProps: { listType: 'picture-card', accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif' } } } },
|
||||||
|
@ -244,21 +245,21 @@ export default {
|
||||||
config: {
|
config: {
|
||||||
serverUrl: util.baseURL() + 'api/system/file/ueditor/',
|
serverUrl: util.baseURL() + 'api/system/file/ueditor/',
|
||||||
headers: { Authorization: 'JWT ' + util.cookies.get('token') },
|
headers: { Authorization: 'JWT ' + util.cookies.get('token') },
|
||||||
imageUrlPrefix: util.baseURL(),
|
imageUrlPrefix: util.baseFileURL(),
|
||||||
// 涂鸦图片上传
|
// 涂鸦图片上传
|
||||||
scrawlUrlPrefix: util.baseURL(),
|
scrawlUrlPrefix: util.baseFileURL(),
|
||||||
// 截图工具上传
|
// 截图工具上传
|
||||||
snapscreenUrlPrefix: util.baseURL(),
|
snapscreenUrlPrefix: util.baseFileURL(),
|
||||||
// 抓取远程图片路径前缀
|
// 抓取远程图片路径前缀
|
||||||
catcherUrlPrefix: util.baseURL(),
|
catcherUrlPrefix: util.baseFileURL(),
|
||||||
// 视频访问路径前缀
|
// 视频访问路径前缀
|
||||||
videoUrlPrefix: util.baseURL(),
|
videoUrlPrefix: util.baseFileURL(),
|
||||||
// 文件访问路径前缀
|
// 文件访问路径前缀
|
||||||
fileUrlPrefix: util.baseURL(),
|
fileUrlPrefix: util.baseFileURL(),
|
||||||
// 列出指定目录下的图片
|
// 列出指定目录下的图片
|
||||||
imageManagerUrlPrefix: util.baseURL(),
|
imageManagerUrlPrefix: util.baseFileURL(),
|
||||||
// 列出指定目录下的文件
|
// 列出指定目录下的文件
|
||||||
fileManagerUrlPrefix: util.baseURL()
|
fileManagerUrlPrefix: util.baseFileURL()
|
||||||
// 传入ueditor的配置
|
// 传入ueditor的配置
|
||||||
// 文档参考: http://fex.baidu.com/ueditor/#start-config
|
// 文档参考: http://fex.baidu.com/ueditor/#start-config
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ import db from './util.db'
|
||||||
import log from './util.log'
|
import log from './util.log'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import filterParams from './util.params'
|
import filterParams from './util.params'
|
||||||
|
|
||||||
const util = {
|
const util = {
|
||||||
cookies,
|
cookies,
|
||||||
db,
|
db,
|
||||||
|
@ -63,6 +62,12 @@ util.baseURL = function () {
|
||||||
return baseURL
|
return baseURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
util.baseFileURL = function () {
|
||||||
|
if (process.env.VUE_APP_FILE_ENGINE && (process.env.VUE_APP_FILE_ENGINE === 'oss' || process.env.VUE_APP_FILE_ENGINE === 'cos')) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return util.baseURL()
|
||||||
|
}
|
||||||
util.wsBaseURL = function () {
|
util.wsBaseURL = function () {
|
||||||
var baseURL = process.env.VUE_APP_API
|
var baseURL = process.env.VUE_APP_API
|
||||||
var param = baseURL.split('/')[3] || ''
|
var param = baseURL.split('/')[3] || ''
|
||||||
|
|
|
@ -56,11 +56,11 @@ router.beforeEach(async (to, from, next) => {
|
||||||
})
|
})
|
||||||
await store.dispatch('d2admin/user/set', res.data, { root: true })
|
await store.dispatch('d2admin/user/set', res.data, { root: true })
|
||||||
await store.dispatch('d2admin/account/load')
|
await store.dispatch('d2admin/account/load')
|
||||||
await store.dispatch('d2admin/permission/load', routes)
|
|
||||||
store.dispatch('d2admin/dept/load')
|
|
||||||
store.dispatch('d2admin/settings/init')
|
store.dispatch('d2admin/settings/init')
|
||||||
}
|
}
|
||||||
if (!store.state.d2admin.menu || store.state.d2admin.menu.aside.length === 0) {
|
if (!store.state.d2admin.menu || store.state.d2admin.menu.aside.length === 0) {
|
||||||
|
await store.dispatch('d2admin/permission/load', routes)
|
||||||
|
await store.dispatch('d2admin/dept/load')
|
||||||
// 动态添加路由
|
// 动态添加路由
|
||||||
getMenu().then(ret => {
|
getMenu().then(ret => {
|
||||||
// 校验路由是否有效
|
// 校验路由是否有效
|
||||||
|
@ -87,8 +87,11 @@ router.beforeEach(async (to, from, next) => {
|
||||||
} else {
|
} else {
|
||||||
const childrenPath = window.qiankunActiveRule || []
|
const childrenPath = window.qiankunActiveRule || []
|
||||||
if (to.name) {
|
if (to.name) {
|
||||||
|
if (to.meta.openInNewWindow && (from.query.newWindow && to.query.newWindow !== '1' || from.path === '/')) {
|
||||||
|
to.query.newWindow = '1'
|
||||||
|
}
|
||||||
// 有 name 属性,说明是主应用的路由
|
// 有 name 属性,说明是主应用的路由
|
||||||
if (to.meta.openInNewWindow && !to.query.newWindow) {
|
if (to.meta.openInNewWindow && !to.query.newWindow && !from.query.newWindow && from.path !== '/') {
|
||||||
// 在新窗口中打开路由
|
// 在新窗口中打开路由
|
||||||
const { href } = router.resolve({
|
const { href } = router.resolve({
|
||||||
path: to.path + '?newWindow=1'
|
path: to.path + '?newWindow=1'
|
||||||
|
|
|
@ -97,6 +97,11 @@ export const crudOptions = (vm) => {
|
||||||
// label: 'name', // 数据字典中label字段的属性名
|
// label: 'name', // 数据字典中label字段的属性名
|
||||||
// children: 'children' // 数据字典中children字段的属性名
|
// children: 'children' // 数据字典中children字段的属性名
|
||||||
// },
|
// },
|
||||||
|
valueResolve (row, key) {
|
||||||
|
if (row.pcode === null) {
|
||||||
|
row.pcode = undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
form: {
|
form: {
|
||||||
component: {
|
component: {
|
||||||
showAllLevels: false, // 仅显示最后一级
|
showAllLevels: false, // 仅显示最后一级
|
||||||
|
|
|
@ -82,7 +82,9 @@ export const crudOptions = (vm) => {
|
||||||
},
|
},
|
||||||
type: 'select',
|
type: 'select',
|
||||||
dict: {
|
dict: {
|
||||||
data: vm.dictionary('system_button')
|
data: vm.dictionary('system_button'),
|
||||||
|
label: 'label',
|
||||||
|
value: 'label'
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
rules: [ // 表单校验规则
|
rules: [ // 表单校验规则
|
||||||
|
@ -107,7 +109,7 @@ export const crudOptions = (vm) => {
|
||||||
// console.log('component.dictOptions', component.dictOptions)
|
// console.log('component.dictOptions', component.dictOptions)
|
||||||
const obj = component.dictOptions.find(item => {
|
const obj = component.dictOptions.find(item => {
|
||||||
// console.log(item.label, value)
|
// console.log(item.label, value)
|
||||||
return item.value === value
|
return item.label === value
|
||||||
})
|
})
|
||||||
if (obj && obj.value) {
|
if (obj && obj.value) {
|
||||||
form.name = obj.label
|
form.name = obj.label
|
||||||
|
|
|
@ -92,6 +92,23 @@ export const crudOptions = (vm) => {
|
||||||
disabled: true
|
disabled: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '部门名称',
|
||||||
|
key: 'dept__name',
|
||||||
|
treeNode: true, // 设置为树形列
|
||||||
|
search: {
|
||||||
|
disabled: false,
|
||||||
|
component: {
|
||||||
|
props: {
|
||||||
|
clearable: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
show: false,
|
||||||
|
form: {
|
||||||
|
disabled: true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '账号',
|
title: '账号',
|
||||||
key: 'username',
|
key: 'username',
|
||||||
|
@ -174,7 +191,7 @@ export const crudOptions = (vm) => {
|
||||||
title: '部门',
|
title: '部门',
|
||||||
key: 'dept',
|
key: 'dept',
|
||||||
search: {
|
search: {
|
||||||
disabled: true
|
disabled: false
|
||||||
},
|
},
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
type: 'tree-selector',
|
type: 'tree-selector',
|
||||||
|
|
Loading…
Reference in New Issue