Merge remote-tracking branch 'origin/dev' into dev

pull/102/MERGE
猿小天 2023-08-11 20:47:56 +08:00
commit 22879cb170
23 changed files with 275 additions and 116 deletions

View File

@ -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

View File

@ -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:

View File

@ -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]

View File

@ -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,其他任何值将原样返回至图片上传框中

View File

@ -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 = {

View File

@ -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]})

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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">

View File

@ -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;
}

View File

@ -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

View File

@ -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: {

View File

@ -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)
},

View File

@ -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"

View File

@ -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
}

View File

@ -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] || ''

View File

@ -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'

View File

@ -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, // 仅显示最后一级

View File

@ -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

View File

@ -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',