diff --git a/backend/del_migrations.py b/backend/del_migrations.py index 75122486b6b69f4adf362adb63b93b025dfcf436..d649e051d6f6294f61630d7ef54c06e83519969d 100644 --- a/backend/del_migrations.py +++ b/backend/del_migrations.py @@ -4,7 +4,7 @@ import os exclude = ["venv"] # 需要排除的文件目录 for root, dirs, files in os.walk('.'): - dirs[:] = [d for d in set(dirs) - set(exclude)] + dirs[:] = list(set(dirs) - set(exclude)) if 'migrations' in dirs: dir = dirs[dirs.index('migrations')] for root_j, dirs_j, files_j in os.walk(os.path.join(root, dir)): diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py index 978085df5c0d6b51cb75312eb1e33f5974430e54..392a08eb678dec51710ef2db24c4d7ad1772a6d0 100644 --- a/backend/dvadmin/system/models.py +++ b/backend/dvadmin/system/models.py @@ -289,8 +289,7 @@ class Dictionary(CoreModel): (7, "images"), ) label = models.CharField(max_length=100, blank=True, null=True, verbose_name="字典名称", help_text="字典名称") - value = models.CharField(max_length=200, blank=True, null=True, verbose_name="字典编号", - help_text="字典编号/实际值") + value = models.CharField(max_length=200, blank=True, null=True, verbose_name="字典编号",help_text="字典编号/实际值") parent = models.ForeignKey( to="self", related_name="sublist", @@ -359,7 +358,11 @@ def media_file_name(instance, filename): class FileList(CoreModel): name = models.CharField(max_length=200, null=True, blank=True, verbose_name="名称", help_text="名称") - url = models.FileField(upload_to=media_file_name) + url = models.FileField(upload_to=media_file_name, null=True, blank=True,) + file_url = models.CharField(max_length=255, blank=True, verbose_name="文件地址", help_text="文件地址") + engine = models.CharField(max_length=100, default='local', blank=True, verbose_name="引擎", help_text="引擎") + mime_type = models.CharField(max_length=100, blank=True, verbose_name="Mime类型", help_text="Mime类型") + size = models.CharField(max_length=36, blank=True, verbose_name="文件大小", help_text="文件大小") md5sum = models.CharField(max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5") def save(self, *args, **kwargs): @@ -368,6 +371,11 @@ class FileList(CoreModel): for chunk in self.url.chunks(): md5.update(chunk) self.md5sum = md5.hexdigest() + if not self.size: + self.size = self.url.size + if not self.file_url: + url = media_file_name(self,self.name) + self.file_url = f'media/{url}' super(FileList, self).save(*args, **kwargs) class Meta: diff --git a/backend/dvadmin/system/views/dictionary.py b/backend/dvadmin/system/views/dictionary.py index 0dcc47ca2630b5b5b7f3a58015434e8e7f555e5d..46c2a9c606bdefc97f65231b30b6b33efdccd832 100644 --- a/backend/dvadmin/system/views/dictionary.py +++ b/backend/dvadmin/system/views/dictionary.py @@ -34,6 +34,19 @@ class DictionaryCreateUpdateSerializer(CustomModelSerializer): """ 字典管理 创建/更新时的列化器 """ + value = serializers.CharField(max_length=100) + + def validate_value(self, value): + """ + 在父级的字典编号验证重复性 + """ + initial_data = self.initial_data + parent = initial_data.get('parent',None) + if parent is None: + unique = Dictionary.objects.filter(value=value).exists() + if unique: + raise serializers.ValidationError("字典编号不能重复") + return value class Meta: model = Dictionary @@ -51,20 +64,24 @@ class DictionaryViewSet(CustomModelViewSet): """ queryset = Dictionary.objects.all() serializer_class = DictionarySerializer + create_serializer_class = DictionaryCreateUpdateSerializer extra_filter_class = [] search_fields = ['label'] def get_queryset(self): - params = self.request.query_params - parent = params.get('parent', None) - if params: - if parent: - queryset = self.queryset.filter(status=1, parent=parent) + if self.action =='list': + params = self.request.query_params + parent = params.get('parent', None) + if params: + if parent: + queryset = self.queryset.filter(parent=parent) + else: + queryset = self.queryset.filter(parent__isnull=True) else: - queryset = self.queryset.filter(status=1, parent__isnull=True) + queryset = self.queryset.filter(parent__isnull=True) + return queryset else: - queryset = self.queryset.filter(status=1, parent__isnull=True) - return queryset + return self.queryset class InitDictionaryViewSet(APIView): diff --git a/backend/dvadmin/system/views/file_list.py b/backend/dvadmin/system/views/file_list.py index e079884681a811d77ed426c74687c193d72a6cc4..c122f03fc4107bbe42848e6e36546620f2c1f46f 100644 --- a/backend/dvadmin/system/views/file_list.py +++ b/backend/dvadmin/system/views/file_list.py @@ -1,5 +1,12 @@ +import hashlib +import mimetypes + from rest_framework import serializers +from rest_framework.decorators import action + +from application import dispatch from dvadmin.system.models import FileList +from dvadmin.utils.json_response import DetailResponse from dvadmin.utils.serializers import CustomModelSerializer from dvadmin.utils.viewset import CustomModelViewSet @@ -8,15 +15,52 @@ class FileSerializer(CustomModelSerializer): url = serializers.SerializerMethodField(read_only=True) def get_url(self, instance): - return f'media/{str(instance.url)}' + # return 'media/' + str(instance.url) + return instance.file_url or (f'media/{str(instance.url)}') class Meta: model = FileList fields = "__all__" def create(self, validated_data): - validated_data['name'] = str(self.initial_data.get('file')) - validated_data['url'] = self.initial_data.get('file') + file_engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") or 'local' + file_backup = dispatch.get_system_config_values("fileStorageConfig.file_backup") + file = self.initial_data.get('file') + file_size = file.size + validated_data['name'] = str(file) + validated_data['size'] = file_size + md5 = hashlib.md5() + for chunk in file.chunks(): + md5.update(chunk) + validated_data['md5sum'] = md5.hexdigest() + validated_data['engine'] = file_engine + validated_data['mime_type'] = file.content_type + if file_backup: + validated_data['url'] = file + if file_engine == 'oss': + from dvadmin_cloud_storage.views.aliyun import ali_oss_upload + file_path = ali_oss_upload(file) + 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) + if file_path: + validated_data['file_url'] = file_path + else: + raise ValueError("上传失败") + else: + validated_data['url'] = file + # 审计字段 + try: + request_user = self.request.user + validated_data['dept_belong_id'] = request_user.dept.id + validated_data['creator'] = request_user.id + validated_data['modifier'] = request_user.id + except: + pass return super().create(validated_data) @@ -32,4 +76,4 @@ class FileViewSet(CustomModelViewSet): queryset = FileList.objects.all() serializer_class = FileSerializer filter_fields = ['name', ] - permission_classes = [] + permission_classes = [] \ No newline at end of file diff --git a/backend/dvadmin/system/views/menu_button.py b/backend/dvadmin/system/views/menu_button.py index 74e38a621b8f0fc622dd50a4e750505bc058e749..94a65efb1f429cbbe07cd1dd01ef42724dfcccd1 100644 --- a/backend/dvadmin/system/views/menu_button.py +++ b/backend/dvadmin/system/views/menu_button.py @@ -23,7 +23,7 @@ class MenuButtonSerializer(CustomModelSerializer): class Meta: model = MenuButton - fields = ['id', 'name', 'value', 'api', 'method'] + fields = ['id', 'name', 'value', 'api', 'method','menu'] read_only_fields = ["id"] diff --git a/backend/dvadmin/system/views/user.py b/backend/dvadmin/system/views/user.py index 7db25e730e9662b5eae23855c907165e1396a448..21516d7a82a0cc747e208d21e313713c0bd0f7d8 100644 --- a/backend/dvadmin/system/views/user.py +++ b/backend/dvadmin/system/views/user.py @@ -196,10 +196,11 @@ class ExportUserProfileSerializer(CustomModelSerializer): class UserProfileImportSerializer(CustomModelSerializer): + password = serializers.CharField(read_only=True, required=False) def save(self, **kwargs): data = super().save(**kwargs) password = hashlib.new( - "md5", str(self.initial_data.get("password", "")).encode(encoding="UTF-8") + "md5", str(self.initial_data.get("password", "admin123456")).encode(encoding="UTF-8") ).hexdigest() data.set_password(password) data.save() @@ -264,7 +265,6 @@ class UserViewSet(CustomModelViewSet): "data": {"启用": True, "禁用": False}, } }, - "password": "登录密码", "dept": {"title": "部门", "choices": {"queryset": Dept.objects.filter(status=True), "values_name": "name"}}, "role": {"title": "角色", "choices": {"queryset": Role.objects.filter(status=True), "values_name": "name"}}, } diff --git a/docker_env/nginx/my.conf b/docker_env/nginx/my.conf index 94fe805e744b5b5455a56f14710d64a525bf5627..30fa2108d1ae318b5841bfb237d389444a241ad1 100644 --- a/docker_env/nginx/my.conf +++ b/docker_env/nginx/my.conf @@ -28,6 +28,6 @@ server { proxy_send_timeout 600s; real_ip_header X-Forwarded-For; rewrite ^/api/(.*)$ /$1 break; #重写 - proxy_pass http://178.10.0.12:8000/; # 设置代理服务器的协议和地址 + proxy_pass http://177.8.0.12:8000/; # 设置代理服务器的协议和地址 } } diff --git a/web/.env.production b/web/.env.production index 70cd18d579ea1b477f8fd6956eed1b8dcaaf5dab..998aa5e15fe3f7cd5a3765c4c1b82dd2a629b2f0 100644 --- a/web/.env.production +++ b/web/.env.production @@ -2,7 +2,7 @@ ENV = 'production' # 线上环境接口地址 -VITE_API_URL = '' +VITE_API_URL = '/api' # docker-compose部署不需要修改,nginx容器自动代理了这个地址 # 是否启用按钮权限 VITE_PM_ENABLED = true diff --git a/web/package.json b/web/package.json index 4349cde8648a36bbca061ff9b058bce7c0b54ef4..345af77ca283cd8d7dd8cc813c37868988b1809a 100644 --- a/web/package.json +++ b/web/package.json @@ -10,10 +10,10 @@ }, "dependencies": { "@element-plus/icons-vue": "^2.0.10", - "@fast-crud/fast-crud": "^1.11.10", - "@fast-crud/fast-extends": "^1.11.10", - "@fast-crud/ui-element": "^1.11.10", - "@fast-crud/ui-interface": "^1.11.9", + "@fast-crud/fast-crud": "^1.13.2", + "@fast-crud/fast-extends": "^1.13.2", + "@fast-crud/ui-element": "^1.13.2", + "@fast-crud/ui-interface": "^1.13.2", "@vitejs/plugin-vue-jsx": "^3.0.0", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.12", diff --git a/web/src/components/importExcel/index.vue b/web/src/components/importExcel/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..7ac6341e828508eda126a7ca6f3b37d9a865000d --- /dev/null +++ b/web/src/components/importExcel/index.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/web/src/settings.ts b/web/src/settings.ts index 588a6a058d1eb260556e63c1b6de2620278da85d..b43526eb571a2474527e161d52751449aa98e9e5 100644 --- a/web/src/settings.ts +++ b/web/src/settings.ts @@ -7,8 +7,9 @@ import { setLogger } from '@fast-crud/fast-crud'; import ui from '@fast-crud/ui-element'; import { request } from '/@/utils/service'; //扩展包 -import { FsExtendsEditor } from '@fast-crud/fast-extends'; +import { FsExtendsEditor,FsExtendsUploader } from '@fast-crud/fast-extends'; import '@fast-crud/fast-extends/dist/style.css'; +import { successMessage, successNotification } from '/@/utils/message'; export default { async install(app: any, options: any) { // 先安装ui @@ -18,7 +19,10 @@ export default { //i18n, //i18n配置,可选,默认使用中文,具体用法请看demo里的 src/i18n/index.js 文件 // 此处配置公共的dictRequest(字典请求) async dictRequest({ dict }: any) { - return await request({ url: dict.url, params: dict.params || {} }); //根据dict的url,异步返回一个字典数组 + //根据dict的url,异步返回一个字典数组 + return await request({ url: dict.url, params: dict.params || {} }).then((res:any)=>{ + return res.data + }); }, //公共crud配置 commonOptions() { @@ -40,6 +44,14 @@ export default { return { records: res.data, currentPage: res.page, pageSize: res.limit, total: res.total }; }, }, + form: { + afterSubmit(ctx: any) { + // 增加crud提示 + if (ctx.res.code == 2000) { + successNotification(ctx.res.msg); + } + }, + }, /* search: { layout: 'multi-line', collapse: true, @@ -63,6 +75,39 @@ export default { width: 300, }, }); + // 文件上传 + app.use(FsExtendsUploader, { + defaultType: "form", + form: { + action: `/api/system/file/`, + name: "file", + withCredentials: false, + uploadRequest: async ({ action, file, onProgress }) => { + // @ts-ignore + const data = new FormData(); + data.append("file", file); + return await request({ + url: action, + method: "post", + timeout: 60000, + headers: { + "Content-Type": "multipart/form-data" + }, + data, + onUploadProgress: (p) => { + onProgress({ percent: Math.round((p.loaded / p.total) * 100) }); + } + }); + }, + successHandle(ret) { + // 上传完成后的结果处理, 此处应返回格式为{url:xxx,key:xxx} + return { + url: getBaseURL() + ret.data.url, + key: ret.data.id + }; + } + } + }) setLogger({ level: 'error' }); // 设置自动染色 const dictComponentList = ['dict-cascader', 'dict-checkbox', 'dict-radio', 'dict-select', 'dict-switch', 'dict-tree']; diff --git a/web/src/utils/baseUrl.ts b/web/src/utils/baseUrl.ts index 617e9f9ec2965477ca3fdaee8c0b03cbc6556f31..c22daa83ff86972834bad25c1d701ebb6f56787b 100644 --- a/web/src/utils/baseUrl.ts +++ b/web/src/utils/baseUrl.ts @@ -1,61 +1,67 @@ +import { pluginsAll } from '/@/views/plugins/index'; + /** * @description 校验是否为租户模式。租户模式把域名替换成 域名 加端口 */ export const getBaseURL = function () { - var baseURL = import.meta.env.VITE_API_URL as any - var param = baseURL.split('/')[3] || '' - if (window.pluginsAll && window.pluginsAll.indexOf('dvadmin-tenants-web') !== -1 && (!param || baseURL.startsWith('/'))) { - // 1.把127.0.0.1 替换成和前端一样域名 - // 2.把 ip 地址替换成和前端一样域名 - // 3.把 /api 或其他类似的替换成和前端一样域名 - // document.domain - var host = baseURL.split('/')[2] - if (host) { - var prot = baseURL.split(':')[2] || 80 - if (prot === 80 || prot === 443) { - host = document.domain - } else { - host = document.domain + ':' + prot - } - baseURL = baseURL.split('/')[0] + '//' + baseURL.split('/')[1] + host + '/' + param - } else { - baseURL = location.protocol + '//' + location.hostname + (location.port ? ':' : '') + location.port + baseURL - } - } - if (!baseURL.endsWith('/')) { - baseURL += '/' - } - return baseURL -} + var baseURL = import.meta.env.VITE_API_URL as any; + var param = baseURL.split('/')[3] || ''; + // @ts-ignore + if (pluginsAll && pluginsAll.indexOf('dvadmin3-tenants-web') !== -1 && (!param || baseURL.startsWith('/'))) { + // 1.把127.0.0.1 替换成和前端一样域名 + // 2.把 ip 地址替换成和前端一样域名 + // 3.把 /api 或其他类似的替换成和前端一样域名 + // document.domain + + var host = baseURL.split('/')[2]; + if (host) { + var port = baseURL.split(':')[2] || 80; + if (port === 80 || port === 443) { + host = document.domain; + } else { + host = document.domain + ':' + port; + } + baseURL = baseURL.split('/')[0] + '//' + baseURL.split('/')[1] + host + '/' + param; + } else { + baseURL = location.protocol + '//' + location.hostname + (location.port ? ':' : '') + location.port + baseURL; + } + } + if (!baseURL.endsWith('/')) { + baseURL += '/'; + } + return baseURL; +}; export const getWsBaseURL = function () { - let baseURL = import.meta.env.VITE_API_URL as any - let param = baseURL.split('/')[3] || '' - if (window.pluginsAll && window.pluginsAll.indexOf('dvadmin-tenants-web') !== -1 && (!param || baseURL.startsWith('/'))) { - // 1.把127.0.0.1 替换成和前端一样域名 - // 2.把 ip 地址替换成和前端一样域名 - // 3.把 /api 或其他类似的替换成和前端一样域名 - // document.domain - var host = baseURL.split('/')[2] - if (host) { - var prot = baseURL.split(':')[2] || 80 - if (prot === 80 || prot === 443) { - host = document.domain - } else { - host = document.domain + ':' + prot - } - baseURL = baseURL.split('/')[0] + '//' + baseURL.split('/')[1] + host + '/' + param - } else { - baseURL = location.protocol + '//' + location.hostname + (location.port ? ':' : '') + location.port + baseURL - } - } else if (param !== '' || baseURL.startsWith('/')) { - baseURL = (location.protocol === 'https:' ? 'wss://' : 'ws://') + location.hostname + (location.port ? ':' : '') + location.port + baseURL - } - if (!baseURL.endsWith('/')) { - baseURL += '/' - } - if (baseURL.startsWith('http')) { // https 也默认会被替换成 wss - baseURL = baseURL.replace('http', 'ws') - } - return baseURL -} + let baseURL = import.meta.env.VITE_API_URL as any; + let param = baseURL.split('/')[3] || ''; + // @ts-ignore + if (pluginsAll && pluginsAll.indexOf('dvadmin3-tenants-web') !== -1 && (!param || baseURL.startsWith('/'))) { + // 1.把127.0.0.1 替换成和前端一样域名 + // 2.把 ip 地址替换成和前端一样域名 + // 3.把 /api 或其他类似的替换成和前端一样域名 + // document.domain + var host = baseURL.split('/')[2]; + if (host) { + var port = baseURL.split(':')[2] || 80; + if (port === 80 || port === 443) { + host = document.domain; + } else { + host = document.domain + ':' + port; + } + baseURL = baseURL.split('/')[0] + '//' + baseURL.split('/')[1] + host + '/' + param; + } else { + baseURL = location.protocol + '//' + location.hostname + (location.port ? ':' : '') + location.port + baseURL; + } + } else if (param !== '' || baseURL.startsWith('/')) { + baseURL = (location.protocol === 'https:' ? 'wss://' : 'ws://') + location.hostname + (location.port ? ':' : '') + location.port + baseURL; + } + if (!baseURL.endsWith('/')) { + baseURL += '/'; + } + if (baseURL.startsWith('http')) { + // https 也默认会被替换成 wss + baseURL = baseURL.replace('http', 'ws'); + } + return baseURL; +}; diff --git a/web/src/utils/message.ts b/web/src/utils/message.ts index 0e3bc4b133884b7c48e025c8d4fa896946e65538..a022c0ba5b4ff7c06f0804e3632fce85871c0497 100644 --- a/web/src/utils/message.ts +++ b/web/src/utils/message.ts @@ -1,10 +1,10 @@ -import { ElMessage, MessageOptions } from 'element-plus'; +import { ElMessage, ElNotification, MessageOptions } from 'element-plus'; export function message(message: string, option?: MessageOptions) { ElMessage({ message, ...option }); } export function successMessage(message: string, option?: MessageOptions) { - ElMessage({ message, ...option, type: 'success' }); + ElMessage({ message, type: 'success' }); } export function warningMessage(message: string, option?: MessageOptions) { ElMessage({ message, ...option, type: 'warning' }); @@ -15,3 +15,19 @@ export function errorMessage(message: string, option?: MessageOptions) { export function infoMessage(message: string, option?: MessageOptions) { ElMessage({ message, ...option, type: 'info' }); } + +export function notification(message: string) { + ElNotification({ message }); +} +export function successNotification(message: string) { + ElNotification({ message, type: 'success' }); +} +export function warningNotification(message: string) { + ElNotification({ message, type: 'warning' }); +} +export function errorNotification(message: string) { + ElNotification({ message, type: 'error' }); +} +export function infoNotification(message: string) { + ElNotification({ message, type: 'info' }); +} diff --git a/web/src/utils/service.ts b/web/src/utils/service.ts index c3b46446fcfbe4f02ab0b09219eba8c3a22b9cfb..5694dbccae5d0f7caa944dc9d7a4fb2b173f146d 100644 --- a/web/src/utils/service.ts +++ b/web/src/utils/service.ts @@ -1,7 +1,7 @@ import axios from 'axios'; import { get } from 'lodash-es'; -import { ElMessage, ElMessageBox } from 'element-plus' -import type { Action } from 'element-plus' +import { ElMessage, ElMessageBox } from 'element-plus'; +import type { Action } from 'element-plus'; // @ts-ignore import { errorLog, errorCreate } from './tools.ts'; @@ -9,6 +9,7 @@ import { errorLog, errorCreate } from './tools.ts'; // import { useUserStore } from "../store/modules/user"; import { Local, Session } from '/@/utils/storage'; import qs from 'qs'; +import { getBaseURL } from './baseUrl'; /** * @description 创建请求实例 */ @@ -17,16 +18,19 @@ function createService() { const service = axios.create({ timeout: 20000, headers: { - 'Content-Type': 'application/json;charset=utf-8' + 'Content-Type': 'application/json;charset=utf-8', }, paramsSerializer: { serialize(params) { - return qs.stringify(params, { indices: false,encoder: (val:string) => { + return qs.stringify(params, { + indices: false, + encoder: (val: string) => { if (typeof val === 'boolean') { return val ? 1 : 0; } return val; - } }); + }, + }); }, }, }); @@ -76,7 +80,7 @@ function createService() { callback: (action: Action) => { window.location.reload(); }, - }) + }); errorCreate(`${dataAxios.msg}: ${response.config.url}`); break; case 2000: @@ -86,6 +90,9 @@ function createService() { return dataAxios; } return dataAxios; + case 4000: + errorCreate(`${dataAxios.msg}: ${response.config.url}`); + return Promise.reject(dataAxios.msg); default: // 不是正确的 code errorCreate(`${dataAxios.msg}: ${response.config.url}`); @@ -108,7 +115,7 @@ function createService() { callback: (action: Action) => { window.location.reload(); }, - }) + }); break; case 403: error.message = '拒绝访问'; @@ -162,7 +169,7 @@ function createRequestFunction(service: any) { 'Content-Type': get(config, 'headers.Content-Type', 'application/json'), }, timeout: 5000, - baseURL: import.meta.env.VITE_API_URL as any, + baseURL: getBaseURL(), data: {}, }; @@ -183,3 +190,34 @@ export const request = createRequestFunction(service); // 用于模拟网络请求的实例和请求方法 export const serviceForMock = createService(); export const requestForMock = createRequestFunction(serviceForMock); + +/** + * 下载文件 + * @param url + * @param params + * @param method + * @param filename + */ +export const downloadFile = function ({url,params,method,filename = '文件导出'}:any) { + request({ + url: url, + method: method, + params: params, + responseType: 'blob' + // headers: {Accept: 'application/vnd.openxmlformats-officedocument'} + }).then((res:any) => { + const xlsxName = window.decodeURI(res.headers['content-disposition'].split('=')[1]) + const fileName = xlsxName || `${filename}.xlsx` + if (res) { + const blob = new Blob([res.data], { type: 'charset=utf-8' }) + const elink = document.createElement('a') + elink.download = fileName + elink.style.display = 'none' + elink.href = URL.createObjectURL(blob) + document.body.appendChild(elink) + elink.click() + URL.revokeObjectURL(elink.href) // 释放URL 对象0 + document.body.removeChild(elink) + } + }) +} diff --git a/web/src/views/plugins/index.ts b/web/src/views/plugins/index.ts index fe9b889c5ee795855ba37a5f64f479a48e3607eb..7ba8bf9e3e32686bc51b1c9f80357432fa80ab22 100644 --- a/web/src/views/plugins/index.ts +++ b/web/src/views/plugins/index.ts @@ -1,5 +1,5 @@ import { defineAsyncComponent, AsyncComponentLoader } from 'vue'; - +export let pluginsAll: any = []; // 扫描插件目录并注册插件 export const scanAndInstallPlugins = (app: any) => { const components = import.meta.glob('./**/*.vue'); @@ -11,5 +11,6 @@ export const scanAndInstallPlugins = (app: any) => { const pluginsName = key.match(/\/([^\/]*)\//)?.[1]; pluginNames.add(pluginsName); } - console.log('已发现插件:', Array.from(pluginNames)); + pluginsAll = Array.from(pluginNames); + console.log('已发现插件:', pluginsAll); }; diff --git a/web/src/views/system/config/components/addContent.vue b/web/src/views/system/config/components/addContent.vue index 6284a181f176c0551fdf904ef96f3ab9ef504340..e7e9e4d0545fe35bc85ffed9023dc959b5791bdc 100644 --- a/web/src/views/system/config/components/addContent.vue +++ b/web/src/views/system/config/components/addContent.vue @@ -40,7 +40,7 @@ - 立即创建 + 立即创建 @@ -49,7 +49,7 @@ diff --git a/web/src/views/system/fileList/index.vue b/web/src/views/system/fileList/index.vue index 58c03316c8be3c9304c9b633e9dec79ca1a8e7de..ae24dcf19a5a6b5c519c5f8f32211c14ec32f3f2 100644 --- a/web/src/views/system/fileList/index.vue +++ b/web/src/views/system/fileList/index.vue @@ -1,18 +1,152 @@ + diff --git a/web/src/views/system/log/loginLog/api.ts b/web/src/views/system/log/loginLog/api.ts index 71575dd2c236a0a9cd853e932757ec265df5188e..defefc49441777cb5a1c1768fdd3fd7d7a6718f8 100644 --- a/web/src/views/system/log/loginLog/api.ts +++ b/web/src/views/system/log/loginLog/api.ts @@ -6,7 +6,7 @@ export function GetList(query: UserPageQuery) { return request({ url: apiPrefix, method: 'get', - data: query, + params: query, }); } export function GetObj(id: InfoReq) { diff --git a/web/src/views/system/login/component/account.vue b/web/src/views/system/login/component/account.vue index 585cf4c117841869fb1c7b7a3d1dcdc3e10609f2..908f77d1bfc2f0a2a64254430b8e4bee5e46c800 100644 --- a/web/src/views/system/login/component/account.vue +++ b/web/src/views/system/login/component/account.vue @@ -12,7 +12,6 @@ :type="isShowPassword ? 'text' : 'password'" :placeholder="$t('message.account.accountPlaceholder2')" v-model="ruleForm.password" - autocomplete="off" > @@ -110,7 +87,7 @@