Merge remote-tracking branch 'origin/dev' into dev
commit
22879cb170
|
@ -2,4 +2,5 @@
|
|||
# python manage.py makemigrations
|
||||
# python manage.py migrate
|
||||
# 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中
|
||||
instance = FileList()
|
||||
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.mime_type = mime_type
|
||||
instance.creator = request.user
|
||||
instance.modifier = request.user.id
|
||||
instance.dept_belong_id = request.user.dept_id
|
||||
|
||||
file_backup = dispatch.get_system_config_values("fileStorageConfig.file_backup")
|
||||
file_engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") or 'local'
|
||||
file_backup = dispatch.get_system_config_values("file_storage.file_backup")
|
||||
file_engine = dispatch.get_system_config_values("file_storage.file_engine") or 'local'
|
||||
if file_backup:
|
||||
instance.url = os.path.join(file_path.replace('media/', ''), file_name)
|
||||
if file_engine == 'oss':
|
||||
from dvadmin_cloud_storage.views.aliyun import ali_oss_upload
|
||||
file = File(open(os.path.join(BASE_DIR, file_path, file_name)))
|
||||
file_path = ali_oss_upload(file)
|
||||
with open(os.path.join(BASE_DIR, file_path, file_name), 'rb') as file:
|
||||
file_path = ali_oss_upload(file, file_name=os.path.join(file_path.replace('media/', ''), file_name))
|
||||
if file_path:
|
||||
instance.file_url = file_path
|
||||
else:
|
||||
raise ValueError("上传失败")
|
||||
elif file_engine == 'cos':
|
||||
from dvadmin_cloud_storage.views.tencent import tencent_cos_upload
|
||||
file = File(open(os.path.join(BASE_DIR, file_path, file_name)))
|
||||
file_path = tencent_cos_upload(file)
|
||||
with open(os.path.join(BASE_DIR, file_path, file_name), 'rb') as file:
|
||||
file_path = tencent_cos_upload(file, file_name=os.path.join(file_path.replace('media/', ''), file_name))
|
||||
if file_path:
|
||||
instance.file_url = file_path
|
||||
else:
|
||||
|
|
|
@ -215,38 +215,39 @@ class DataVViewSet(GenericViewSet):
|
|||
CHINA_PROVINCES = [
|
||||
{'name': '北京', 'code': '110000'},
|
||||
{'name': '天津', 'code': '120000'},
|
||||
{'name': '河北', 'code': '130000'},
|
||||
{'name': '山西', 'code': '140000'},
|
||||
{'name': '河北省', 'code': '130000'},
|
||||
{'name': '山西省', 'code': '140000'},
|
||||
{'name': '内蒙古', 'code': '150000'},
|
||||
{'name': '辽宁', 'code': '210000'},
|
||||
{'name': '吉林', 'code': '220000'},
|
||||
{'name': '黑龙江', 'code': '230000'},
|
||||
{'name': '辽宁省', 'code': '210000'},
|
||||
{'name': '吉林省', 'code': '220000'},
|
||||
{'name': '黑龙江省', 'code': '230000'},
|
||||
{'name': '上海', 'code': '310000'},
|
||||
{'name': '江苏', 'code': '320000'},
|
||||
{'name': '浙江', 'code': '330000'},
|
||||
{'name': '安徽', 'code': '340000'},
|
||||
{'name': '福建', 'code': '350000'},
|
||||
{'name': '江西', 'code': '360000'},
|
||||
{'name': '山东', 'code': '370000'},
|
||||
{'name': '河南', 'code': '410000'},
|
||||
{'name': '湖北', 'code': '420000'},
|
||||
{'name': '湖南', 'code': '430000'},
|
||||
{'name': '广东', 'code': '440000'},
|
||||
{'name': '江苏省', 'code': '320000'},
|
||||
{'name': '浙江省', 'code': '330000'},
|
||||
{'name': '安徽省', 'code': '340000'},
|
||||
{'name': '福建省', 'code': '350000'},
|
||||
{'name': '江西省', 'code': '360000'},
|
||||
{'name': '山东省', 'code': '370000'},
|
||||
{'name': '河南省', 'code': '410000'},
|
||||
{'name': '湖北省', 'code': '420000'},
|
||||
{'name': '湖南省', 'code': '430000'},
|
||||
{'name': '广东省', 'code': '440000'},
|
||||
{'name': '广西', 'code': '450000'},
|
||||
{'name': '海南', 'code': '460000'},
|
||||
{'name': '海南省', 'code': '460000'},
|
||||
{'name': '重庆', 'code': '500000'},
|
||||
{'name': '四川', 'code': '510000'},
|
||||
{'name': '贵州', 'code': '520000'},
|
||||
{'name': '云南', 'code': '530000'},
|
||||
{'name': '四川省', 'code': '510000'},
|
||||
{'name': '贵州省', 'code': '520000'},
|
||||
{'name': '云南省', 'code': '530000'},
|
||||
{'name': '西藏', 'code': '540000'},
|
||||
{'name': '陕西', 'code': '610000'},
|
||||
{'name': '甘肃', 'code': '620000'},
|
||||
{'name': '青海', 'code': '630000'},
|
||||
{'name': '陕西省', 'code': '610000'},
|
||||
{'name': '甘肃省', 'code': '620000'},
|
||||
{'name': '青海省', 'code': '630000'},
|
||||
{'name': '宁夏', 'code': '640000'},
|
||||
{'name': '新疆', 'code': '650000'},
|
||||
{'name': '台湾', 'code': '710000'},
|
||||
{'name': '香港', 'code': '810000'},
|
||||
{'name': '澳门', 'code': '820000'},
|
||||
{'name': '钓鱼岛', 'code': '900000'},
|
||||
{'name': '未知区域', 'code': '000000'},
|
||||
]
|
||||
provinces = [x['name'] for x in CHINA_PROVINCES]
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
import base64
|
||||
import datetime
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
from pathlib import PurePosixPath
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from rest_framework import serializers
|
||||
from rest_framework.decorators import action
|
||||
from application.settings import BASE_DIR
|
||||
from application import dispatch
|
||||
from dvadmin.system.models import FileList
|
||||
from application import dispatch, settings
|
||||
from dvadmin.system.models import FileList, media_file_name
|
||||
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.string_util import format_bytes
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
|
@ -21,6 +24,16 @@ class FileSerializer(CustomModelSerializer):
|
|||
url = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
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)}')
|
||||
|
||||
class Meta:
|
||||
|
@ -28,8 +41,8 @@ class FileSerializer(CustomModelSerializer):
|
|||
fields = "__all__"
|
||||
|
||||
def create(self, validated_data):
|
||||
file_engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") or 'local'
|
||||
file_backup = dispatch.get_system_config_values("fileStorageConfig.file_backup")
|
||||
file_engine = dispatch.get_system_config_values("file_storage.file_engine") or 'local'
|
||||
file_backup = dispatch.get_system_config_values("file_storage.file_backup")
|
||||
file = self.initial_data.get('file')
|
||||
file_size = file.size
|
||||
validated_data['name'] = file.name
|
||||
|
@ -44,14 +57,18 @@ class FileSerializer(CustomModelSerializer):
|
|||
validated_data['url'] = file
|
||||
if file_engine == 'oss':
|
||||
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:
|
||||
validated_data['file_url'] = file_path
|
||||
else:
|
||||
raise ValueError("上传失败")
|
||||
elif file_engine == 'cos':
|
||||
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:
|
||||
validated_data['file_url'] = file_path
|
||||
else:
|
||||
|
@ -83,6 +100,12 @@ class FileViewSet(CustomModelViewSet):
|
|||
filter_fields = ['name', ]
|
||||
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
|
||||
@action(methods=["GET", "POST"], detail=False, permission_classes=[])
|
||||
def ueditor(self, request):
|
||||
|
@ -138,16 +161,17 @@ class FileViewSet(CustomModelViewSet):
|
|||
# 涂鸦功能上传处理
|
||||
def save_scrawl_file(self, request, file_path, file_name):
|
||||
import base64
|
||||
instance = None
|
||||
try:
|
||||
content = request.data.get(ueditor_upload_settings.get("scrawlFieldName", "upfile"))
|
||||
f = open(os.path.join(BASE_DIR, file_path, file_name), 'wb')
|
||||
f.write(base64.b64decode(content))
|
||||
f.close()
|
||||
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:
|
||||
state = f"写入图片文件错误:{e}"
|
||||
return state
|
||||
return state, instance
|
||||
|
||||
def upload_file(self, request):
|
||||
"""上传文件"""
|
||||
|
@ -213,20 +237,21 @@ class FileViewSet(CustomModelViewSet):
|
|||
# 取得输出文件的路径
|
||||
format_file_name, output_path = self.get_output_path(path_format_var)
|
||||
# 所有检测完成后写入文件
|
||||
file_instance = None
|
||||
if state == "SUCCESS":
|
||||
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)
|
||||
else:
|
||||
file = request.FILES.get(upload_field_name, None)
|
||||
# 保存到文件中,如果保存错误,需要返回ERROR
|
||||
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 = {
|
||||
'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, # 原始文件名
|
||||
'type': upload_original_ext,
|
||||
'state': state, # 上传状态,成功时返回SUCCESS,其他任何值将原样返回至图片上传框中
|
||||
|
|
|
@ -249,16 +249,16 @@ class UserViewSet(CustomModelViewSet):
|
|||
serializer_class = UserSerializer
|
||||
create_serializer_class = UserCreateSerializer
|
||||
update_serializer_class = UserUpdateSerializer
|
||||
# filter_fields = ["name", "username", "gender", "is_active", "dept", "user_type"]
|
||||
filter_fields = {
|
||||
"name": ["icontains"],
|
||||
"mobile": ["icontains"],
|
||||
"username": ["icontains"],
|
||||
"gender": ["icontains"],
|
||||
"is_active": ["icontains"],
|
||||
"dept": ["exact"],
|
||||
"user_type": ["exact"],
|
||||
}
|
||||
filter_fields = ["^name", "~username", "^mobile", "is_active", "dept", "user_type", "$dept__name"]
|
||||
# filter_fields = {
|
||||
# "name": ["icontains"],
|
||||
# "mobile": ["iregex"],
|
||||
# "username": ["icontains"],
|
||||
# "is_active": ["icontains"],
|
||||
# "dept": ["exact"],
|
||||
# "user_type": ["exact"],
|
||||
# "dept__name": ["icontains"],
|
||||
# }
|
||||
search_fields = ["username", "name", "gender", "dept__name", "role__name"]
|
||||
# 导出
|
||||
export_field_label = {
|
||||
|
|
|
@ -150,6 +150,7 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||
"$": "iregex",
|
||||
"~": "icontains",
|
||||
}
|
||||
filter_fields = "__all__"
|
||||
|
||||
def construct_search(self, field_name, lookup_expr=None):
|
||||
lookup = self.lookup_prefixes.get(field_name[0])
|
||||
|
@ -157,14 +158,16 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||
field_name = field_name[1:]
|
||||
else:
|
||||
lookup = lookup_expr
|
||||
if lookup:
|
||||
if field_name.endswith(lookup):
|
||||
return field_name
|
||||
return LOOKUP_SEP.join([field_name, lookup])
|
||||
return field_name
|
||||
|
||||
def find_filter_lookups(self, orm_lookups, search_term_key):
|
||||
for lookup in orm_lookups:
|
||||
# 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
|
||||
if new_lookup == search_term_key:
|
||||
return lookup
|
||||
|
@ -189,7 +192,13 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||
utils.deprecate(
|
||||
"`%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:
|
||||
filterset_model = filterset_class._meta.model
|
||||
|
@ -327,18 +336,22 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||
return queryset
|
||||
if filterset.__class__.__name__ == "AutoFilterSet":
|
||||
queryset = filterset.queryset
|
||||
orm_lookups = []
|
||||
for search_field in filterset.filters:
|
||||
if isinstance(filterset.filters[search_field], CharFilter):
|
||||
orm_lookups.append(
|
||||
self.construct_search(six.text_type(search_field), filterset.filters[search_field].lookup_expr)
|
||||
filter_fields = filterset.filters if self.filter_fields == "__all__" else self.filter_fields
|
||||
orm_lookup_dict = dict(
|
||||
zip(
|
||||
[field for field in filter_fields],
|
||||
[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 = []
|
||||
queries = []
|
||||
for search_term_key in filterset.data.keys():
|
||||
orm_lookup = self.find_filter_lookups(orm_lookups, search_term_key)
|
||||
# print(search_term_key, orm_lookup)
|
||||
if not orm_lookup:
|
||||
continue
|
||||
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["foreign"] = related_fields
|
||||
print(f"{relations=}", flush=True)
|
||||
return relations
|
||||
|
||||
def _is_cascade(self, relation):
|
||||
|
|
|
@ -3,7 +3,7 @@ certifi==2021.5.30
|
|||
chardet==4.0.0
|
||||
coreapi==2.3.3
|
||||
coreschema==0.0.4
|
||||
Django==3.2.12
|
||||
Django==3.2.19
|
||||
django-comment-migrate==0.1.7
|
||||
django-cors-headers==3.10.1
|
||||
django-filter==22.1
|
||||
|
@ -11,8 +11,8 @@ django-ranged-response==0.2.0
|
|||
django-redis==5.2.0
|
||||
django-restql==0.15.3
|
||||
django-simple-captcha==0.5.17
|
||||
django-tenants==3.4.8
|
||||
django-timezone-field==4.2.3
|
||||
django-tenants==3.5.0
|
||||
django-timezone-field==5.0
|
||||
djangorestframework==3.14.0
|
||||
djangorestframework-simplejwt==5.2.2
|
||||
packaging==23.0
|
||||
|
@ -29,7 +29,7 @@ pyparsing==2.4.7
|
|||
pyPEG2==2.15.2
|
||||
pypinyin==0.48.0
|
||||
pytz==2021.1
|
||||
requests==2.28.2
|
||||
requests==2.28.0
|
||||
ruamel.yaml==0.17.10
|
||||
ruamel.yaml.clib==0.2.4
|
||||
six==1.16.0
|
||||
|
|
|
@ -6,4 +6,6 @@ VUE_APP_TITLE=企业级后台管理系统
|
|||
VUE_APP_PM_ENABLED = true
|
||||
# 后端接口地址及端口(域名)
|
||||
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_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_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'">
|
||||
<img style="max-width: 100%;" :src="dialogImageUrl" alt="">
|
||||
</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 id="player" v-if="dialogVisible">
|
||||
<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-col :span="elProps.index.span" v-if="elProps.index">
|
||||
<div style="text-align: center">
|
||||
{{index+1}}
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="elProps.fields[key].span" v-for="(_,key) in elProps.fields" :key="key">
|
||||
|
@ -34,20 +34,23 @@
|
|||
:value="item.value">
|
||||
</el-option>
|
||||
</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>
|
||||
<div v-else-if="elProps.fields[key].type === 'image'" style="height: 30px;width: 30px;">
|
||||
<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>
|
||||
<el-input-number style="width: 100%" v-else-if="elProps.fields[key].type === 'number'"
|
||||
controls-position="right" v-model="field[key]"></el-input-number>
|
||||
<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>
|
||||
<!-- 富文本 -->
|
||||
<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 v-else-if="elProps.fields[key].type === 'many_to_many'">
|
||||
<values-popover
|
||||
v-model="field[key]"
|
||||
: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)">
|
||||
</values-popover>
|
||||
</span>
|
||||
|
@ -56,8 +59,10 @@
|
|||
</el-col>
|
||||
<el-col :span="4">
|
||||
<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="bottomDomain(index)" :disabled="index === currentForm.data.length - 1" type="primary" circle icon="el-icon-bottom"></el-button>
|
||||
<el-button @click.prevent="topDomain(index)" :disabled="index === 0" type="primary" circle
|
||||
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-form-item>
|
||||
</el-col>
|
||||
|
@ -102,6 +107,7 @@
|
|||
</template>
|
||||
<script>
|
||||
import util from '@/libs/util.js'
|
||||
|
||||
export default {
|
||||
name: 'foreignKeyCrudForm',
|
||||
model: {
|
||||
|
@ -213,21 +219,21 @@ export default {
|
|||
ueditorConfig: {
|
||||
serverUrl: util.baseURL() + 'api/system/file/ueditor/',
|
||||
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的配置
|
||||
// 文档参考: http://fex.baidu.com/ueditor/#start-config
|
||||
},
|
||||
|
@ -346,8 +352,37 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
::v-deep .d2p-file-uploader .el-upload--picture-card{
|
||||
<style lang="scss">
|
||||
.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;
|
||||
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"/>
|
||||
<span v-for="(item,index) in _elProps.tableConfig.columns" :key="index" >
|
||||
<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>
|
||||
</el-table>
|
||||
<el-pagination style="margin-top: 10px;max-width: 200px" background
|
||||
|
@ -80,6 +91,7 @@
|
|||
import { request } from '@/api/service'
|
||||
import XEUtils from 'xe-utils'
|
||||
import { d2CrudPlus } from 'd2-crud-plus'
|
||||
import util from '@/libs/util'
|
||||
|
||||
export default {
|
||||
name: 'selector-table-input',
|
||||
|
@ -147,7 +159,8 @@ export default {
|
|||
search: null,
|
||||
tableData: [],
|
||||
multipleSelection: [],
|
||||
collapseTags: false
|
||||
collapseTags: false,
|
||||
baseURL: util.baseURL()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -306,7 +306,7 @@ export default {
|
|||
},
|
||||
itemClosed (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.doValueInputChanged(newNodes)
|
||||
},
|
||||
|
|
|
@ -36,6 +36,30 @@
|
|||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</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'">
|
||||
<el-popover
|
||||
placement="right"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import util from '@/libs/util.js'
|
||||
|
||||
export default {
|
||||
'image-uploader': {
|
||||
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: {
|
||||
serverUrl: util.baseURL() + 'api/system/file/ueditor/',
|
||||
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的配置
|
||||
// 文档参考: http://fex.baidu.com/ueditor/#start-config
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import db from './util.db'
|
|||
import log from './util.log'
|
||||
import dayjs from 'dayjs'
|
||||
import filterParams from './util.params'
|
||||
|
||||
const util = {
|
||||
cookies,
|
||||
db,
|
||||
|
@ -63,6 +62,12 @@ util.baseURL = function () {
|
|||
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 () {
|
||||
var baseURL = process.env.VUE_APP_API
|
||||
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/account/load')
|
||||
await store.dispatch('d2admin/permission/load', routes)
|
||||
store.dispatch('d2admin/dept/load')
|
||||
store.dispatch('d2admin/settings/init')
|
||||
}
|
||||
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 => {
|
||||
// 校验路由是否有效
|
||||
|
@ -87,8 +87,11 @@ router.beforeEach(async (to, from, next) => {
|
|||
} else {
|
||||
const childrenPath = window.qiankunActiveRule || []
|
||||
if (to.name) {
|
||||
if (to.meta.openInNewWindow && (from.query.newWindow && to.query.newWindow !== '1' || from.path === '/')) {
|
||||
to.query.newWindow = '1'
|
||||
}
|
||||
// 有 name 属性,说明是主应用的路由
|
||||
if (to.meta.openInNewWindow && !to.query.newWindow) {
|
||||
if (to.meta.openInNewWindow && !to.query.newWindow && !from.query.newWindow && from.path !== '/') {
|
||||
// 在新窗口中打开路由
|
||||
const { href } = router.resolve({
|
||||
path: to.path + '?newWindow=1'
|
||||
|
|
|
@ -97,6 +97,11 @@ export const crudOptions = (vm) => {
|
|||
// label: 'name', // 数据字典中label字段的属性名
|
||||
// children: 'children' // 数据字典中children字段的属性名
|
||||
// },
|
||||
valueResolve (row, key) {
|
||||
if (row.pcode === null) {
|
||||
row.pcode = undefined
|
||||
}
|
||||
},
|
||||
form: {
|
||||
component: {
|
||||
showAllLevels: false, // 仅显示最后一级
|
||||
|
|
|
@ -82,7 +82,9 @@ export const crudOptions = (vm) => {
|
|||
},
|
||||
type: 'select',
|
||||
dict: {
|
||||
data: vm.dictionary('system_button')
|
||||
data: vm.dictionary('system_button'),
|
||||
label: 'label',
|
||||
value: 'label'
|
||||
},
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
|
@ -107,7 +109,7 @@ export const crudOptions = (vm) => {
|
|||
// console.log('component.dictOptions', component.dictOptions)
|
||||
const obj = component.dictOptions.find(item => {
|
||||
// console.log(item.label, value)
|
||||
return item.value === value
|
||||
return item.label === value
|
||||
})
|
||||
if (obj && obj.value) {
|
||||
form.name = obj.label
|
||||
|
|
|
@ -92,6 +92,23 @@ export const crudOptions = (vm) => {
|
|||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '部门名称',
|
||||
key: 'dept__name',
|
||||
treeNode: true, // 设置为树形列
|
||||
search: {
|
||||
disabled: false,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
show: false,
|
||||
form: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '账号',
|
||||
key: 'username',
|
||||
|
@ -174,7 +191,7 @@ export const crudOptions = (vm) => {
|
|||
title: '部门',
|
||||
key: 'dept',
|
||||
search: {
|
||||
disabled: true
|
||||
disabled: false
|
||||
},
|
||||
minWidth: 140,
|
||||
type: 'tree-selector',
|
||||
|
|
Loading…
Reference in New Issue