perf: 优化上传组件

This commit is contained in:
TsMask
2023-09-25 10:39:28 +08:00
parent 0bc2be52ef
commit 3525d7567e
4 changed files with 232 additions and 252 deletions

View File

@@ -1,186 +0,0 @@
<script setup lang="ts">
import { reactive } from 'vue';
import { message } from 'ant-design-vue/lib';
import { FileType } from 'ant-design-vue/lib/upload/interface';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import { ResultType } from '@/plugins/http-fetch';
const emit = defineEmits(['close', 'update:visible']);
const props = defineProps({
/**窗口标题 */
title: {
type: String,
default: '标题',
},
/**是否弹出显示,必传 */
visible: {
type: Boolean,
required: true,
},
/**文件上传函数方法,必传 */
uploadFileMethod: {
type: Function,
required: true,
},
/**下载模板函数方法 */
downloadTemplateMethod: {
type: Function,
default: undefined,
},
/**显示更新已存在数据勾选项 */
showUpdateSupport: {
type: Boolean,
default: false,
},
/**允许上传的文件拓展类型,默认 .xls、.xlsx */
fileExt: {
type: Array<string>,
default: ['.xls', '.xlsx'],
},
/**上传文件大小单位MB默认 10 */
fileSize: {
type: Number,
default: 10,
},
});
/**上传状态 */
let updateState = reactive({
/**是否更新已经存在的数据 */
updateSupport: false,
/**是否上传中 */
loading: false,
/**是否已上传文件 */
isUpload: false,
/**上传结果信息 */
msg: '',
});
/**重置上传状态 */
function fnResetUpdateState() {
updateState = Object.assign(updateState, {
updateSupport: false,
loading: false,
isUpload: false,
msg: '',
});
message.destroy();
}
/**上传前检查或转换压缩 */
function fnBeforeUpload(file: FileType) {
if (updateState.loading) return false;
const isAllowType = props.fileExt.some(v => file.name.endsWith(v));
if (!isAllowType) {
message.error(`只支持上传文件格式 ${props.fileExt.join('、')}`, 3);
}
const isLtM = file.size / 1024 / 1024 < props.fileSize;
if (!isLtM) {
message.error(`上传文件大小必须小于 ${props.fileSize}MB`, 3);
}
return isAllowType && isLtM;
}
/**上传请求发出 */
function fnUpload(up: UploadRequestOption) {
if (typeof props.uploadFileMethod !== 'function') return;
message.loading({ content: '正在上传并解析数据...', key: props.title });
updateState.loading = true;
let formData = new FormData();
formData.append('file', up.file);
formData.append('updateSupport', `${updateState.updateSupport}`);
props
.uploadFileMethod(formData)
.then((res: ResultType) => {
updateState.loading = false;
updateState.isUpload = true;
if(res.msg){
updateState.msg = res.msg.replaceAll(/<br\/>+/g, '\r');
}
})
.catch((err: { code: number; msg: string }) => {
message.error({
content: `上传失败 ${err.msg}`,
key: props.title,
duration: 3,
});
});
}
/**弹框确认按钮事件 */
function fnModalOk() {
emit('update:visible', false);
emit('close', updateState.isUpload);
fnResetUpdateState();
}
/**弹框取消按钮事件 */
function fnModalCancel() {
emit('update:visible', false);
emit('close', updateState.isUpload);
fnResetUpdateState();
}
</script>
<template>
<a-modal
width="500px"
:title="props.title"
:visible="props.visible"
:keyboard="false"
:mask-closable="false"
@ok="fnModalOk"
@cancel="fnModalCancel"
>
<a-space :size="8" direction="vertical" style="width: 100%">
<a-upload-dragger
:disabled="updateState.loading"
:accept="fileExt.join(',')"
name="file"
:max-count="1"
:show-upload-list="false"
:before-upload="fnBeforeUpload"
:custom-request="fnUpload"
>
<p class="ant-upload-drag-icon">
<inbox-outlined></inbox-outlined>
</p>
<p class="ant-upload-text">点击选择或将文件拖入边框区域进行上传</p>
<p class="ant-upload-hint">
仅允许导入
{{ props.fileExt.join('、') }}
格式文件上传文件大小
{{ props.fileSize }}
MB
</p>
</a-upload-dragger>
<a-row :gutter="18" justify="space-between" align="middle">
<a-col :span="12">
<a-checkbox
v-model:checked="updateState.updateSupport"
v-if="showUpdateSupport"
>
是否更新已经存在的数据
</a-checkbox>
</a-col>
<a-col :span="6">
<a-button
type="link"
title="下载模板"
@click="downloadTemplateMethod()"
v-if="downloadTemplateMethod"
>
下载模板
</a-button>
</a-col>
</a-row>
<a-textarea
:disabled="true"
:hidden="updateState.msg.length < 1"
:value="updateState.msg"
:auto-size="{ minRows: 2, maxRows: 8 }"
/>
</a-space>
</a-modal>
</template>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,111 @@
<script setup lang="ts">
import { message } from 'ant-design-vue/lib';
import { FileType } from 'ant-design-vue/lib/upload/interface';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
const emit = defineEmits(['upload', 'close', 'update:visible']);
const props = defineProps({
/**窗口标题 */
title: {
type: String,
default: '标题',
},
/**是否上传中 */
loading: {
type: Boolean,
default: false,
},
/**是否弹出显示,必传 */
visible: {
type: Boolean,
required: true,
},
/**允许上传的文件拓展类型,默认任意,可指定['.xls', '.xlsx'] */
ext: {
type: Array<string>,
default: [],
},
/**上传文件大小单位MB默认不限制可指定10 */
size: {
type: Number,
default: 0,
},
});
/**弹框关闭事件 */
function fnModalClose() {
if(props.loading) return
emit('close');
}
/**上传前检查或转换压缩 */
function fnBeforeUpload(file: FileType) {
if (props.loading) return false;
// 检查文件大小
if (props.size > 0) {
const fileSize = file.size;
const isLtM = fileSize / 1024 / 1024 < props.size;
if (!isLtM) {
message.error(`上传文件大小必须小于 ${props.size}MB`, 3);
return false;
}
}
// 检查后缀
if (props.ext.length > 0) {
const fileName = file.name;
const isAllowType = props.ext.some(v => fileName.endsWith(v));
if (!isAllowType) {
message.error(`只支持上传文件格式 ${props.ext.join('、')}`, 3);
return false;
}
}
return true;
}
/**上传请求发出 */
function fnUpload(up: UploadRequestOption) {
emit('upload', up.file)
}
</script>
<template>
<a-modal
width="500px"
:title="props.title"
:visible="props.visible"
:keyboard="false"
:mask-closable="false"
:confirm-loading="props.loading"
:footer="null"
@cancel="fnModalClose"
>
<a-space :size="8" direction="vertical" style="width: 100%">
<a-upload-dragger
:disabled="props.loading"
:accept="props.ext.join(',')"
name="file"
:max-count="1"
:show-upload-list="false"
:before-upload="fnBeforeUpload"
:custom-request="fnUpload"
>
<p class="ant-upload-drag-icon">
<inbox-outlined></inbox-outlined>
</p>
<p class="ant-upload-text">点击选择或将文件拖入边框区域进行上传</p>
<p class="ant-upload-hint">
<div v-if="props.size > 0">
允许上传文件大小 {{ props.size }} MB
</div>
<div v-if="props.ext.length > 0">
允许导入
{{ props.ext.join('') }}
格式文件
</div>
</p>
</a-upload-dragger>
<slot></slot>
</a-space>
</a-modal>
</template>
<style lang="less" scoped></style>

View File

@@ -6,7 +6,7 @@ import { message, Modal, Form, notification } from 'ant-design-vue/lib';
import { SizeType } from 'ant-design-vue/lib/config-provider';
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
import { ColumnsType } from 'ant-design-vue/lib/table';
import UploadImport from '@/components/UploadImport/index.vue';
import UploadModal from '@/components/UploadModal/index.vue';
import {
listAuth,
getAuth,
@@ -22,7 +22,6 @@ import useNeInfoStore from '@/store/modules/neinfo';
import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { saveAs } from 'file-saver';
import { formItemProps } from 'ant-design-vue/lib/form';
const { t } = useI18n();
const route = useRoute();
@@ -186,7 +185,7 @@ let modalState: ModalStateType = reactive({
visibleByBatchDel: false,
title: 'UDM鉴权用户',
from: {
id:'',
id: '',
imsi: '',
amf: '',
ki: '',
@@ -237,18 +236,18 @@ const modalStateBatchFrom = Form.useForm(
})
);
/**对话框内批量删除表单属性和校验规则 */
const modalStateBatchDelFrom = Form.useForm(
modalState.BatchDelForm,
reactive({
num: [{ required: true, message: '放号数不能为空' },
{ min: 1, max: 100, message: '放号数必须小于等于100' }],
num: [
{ required: true, message: '放号数不能为空' },
{ min: 1, max: 100, message: '放号数必须小于等于100' },
],
imsi: [{ required: true, message: 'IMSI不能为空' }],
})
);
/**
* 对话框弹出显示为 新增或者修改
* @param noticeId 网元id, 不传为新增
@@ -347,7 +346,7 @@ function fnBatchModalOk() {
const from = toRaw(modalState.BatchForm);
const neID = queryParams.neId || '-';
// const result = from.id ? updateAuth(from) : addAuth(neID, from);
from.neID=neID;
from.neID = neID;
const result = batchAuth(from);
const hide = message.loading({ content: t('common.loading') });
result
@@ -500,39 +499,54 @@ type ModalUploadImportStateType = {
visible: boolean;
/**标题 */
title: string;
/**导入模板下载触发 */
templateDownload: boolean;
/**是否上传中 */
loading: boolean;
/**上传结果信息 */
msg: string;
};
/**对话框表格信息导入对象信息状态 */
let modalUploadImportState: ModalUploadImportStateType = reactive({
let uploadImportState: ModalUploadImportStateType = reactive({
visible: false,
title: '数据导入',
templateDownload: false,
loading: false,
msg: '',
});
/**
* 对话框表格信息导入确认执行函数
* @param isUpload 是否已上传文件
*/
function fnModalUploadImportClose(isUpload: boolean) {
if (isUpload) {
fnGetList();
}
}
/**对话框表格信息导入弹出窗口 */
function fnModalImportOpen() {
modalUploadImportState.visible = true;
function fnModalUploadImportOpen() {
uploadImportState.msg = '';
uploadImportState.loading = false;
uploadImportState.visible = true;
}
/**列表导入数据 */
async function fnModalImportData(data: FormData) {
/**对话框表格信息导入关闭窗口 */
function fnModalUploadImportClose() {
uploadImportState.visible = false;
fnGetList();
}
/**对话框表格信息导入上传 */
function fnModalUploadImportUpload(file: File) {
let formData = new FormData();
formData.append('file', file);
const neID = queryParams.neId;
if (!neID) {
return Promise.reject('未知网元');
}
return importAuthData(neID, data);
const hide = message.loading('正在上传...', 0);
uploadImportState.loading = true;
importAuthData(neID, formData)
.then(res => {
uploadImportState.msg = res.msg;
})
.catch((err: { code: number; msg: string }) => {
message.error(`上传失败 ${err.msg}`);
})
.finally(() => {
hide();
uploadImportState.loading = false;
});
}
onMounted(() => {
@@ -635,7 +649,12 @@ onMounted(() => {
</template>
{{ t('views.neUser.auth.batchAddText') }}
</a-button>
<a-button type="primary" danger ghost @click.prevent="fnModalVisibleByBatch(0)">
<a-button
type="primary"
danger
ghost
@click.prevent="fnModalVisibleByBatch(0)"
>
<template #icon>
<DeleteOutlined />
</template>
@@ -659,7 +678,7 @@ onMounted(() => {
</a-button>
</a-popconfirm>
<a-button type="dashed" @click.prevent="fnModalImportOpen">
<a-button type="dashed" @click.prevent="fnModalUploadImportOpen">
<template #icon><ImportOutlined /></template>
{{ t('views.neUser.auth.import') }}
</a-button>
@@ -785,7 +804,8 @@ onMounted(() => {
:label-col="{ span: 7 }"
>
<a-row :gutter="16">
<a-col :lg="12" :md="12" :xs="24"> {{ modalState.from }}
<a-col :lg="12" :md="12" :xs="24">
{{ modalState.from }}
<a-form-item
label="IMSI"
name="imsi"
@@ -793,7 +813,7 @@ onMounted(() => {
>
<a-input
v-model:value="modalState.from.imsi"
:disabled="modalState.from.id!=''"
:disabled="modalState.from.id != ''"
allow-clear
placeholder="请输入IMSI"
>
@@ -985,14 +1005,24 @@ onMounted(() => {
</a-modal>
<!-- 上传导入表格数据文件框 -->
<UploadImport
:title="modalUploadImportState.title"
v-model:visible="modalUploadImportState.visible"
:file-size="5"
:file-ext="['.csv', '.txt']"
:upload-file-method="fnModalImportData"
<UploadModal
:title="uploadImportState.title"
:loading="uploadImportState.loading"
@upload="fnModalUploadImportUpload"
@close="fnModalUploadImportClose"
/>
v-model:visible="uploadImportState.visible"
:ext="['.csv', '.txt']"
:size="5"
>
<template #default>
<a-textarea
:disabled="true"
:hidden="!uploadImportState.msg"
:value="uploadImportState.msg"
:auto-size="{ minRows: 2, maxRows: 8 }"
/>
</template>
</UploadModal>
</PageContainer>
</template>

View File

@@ -6,7 +6,7 @@ import { message, Modal, Form, notification } from 'ant-design-vue/lib';
import { SizeType } from 'ant-design-vue/lib/config-provider';
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
import { ColumnsType } from 'ant-design-vue/lib/table';
import UploadImport from '@/components/UploadImport/index.vue';
import UploadModal from '@/components/UploadModal/index.vue';
import {
loadSub,
listSub,
@@ -463,39 +463,54 @@ type ModalUploadImportStateType = {
visible: boolean;
/**标题 */
title: string;
/**导入模板下载触发 */
templateDownload: boolean;
/**是否上传中 */
loading: boolean;
/**上传结果信息 */
msg: string;
};
/**对话框表格信息导入对象信息状态 */
let modalUploadImportState: ModalUploadImportStateType = reactive({
let uploadImportState: ModalUploadImportStateType = reactive({
visible: false,
title: '数据导入',
templateDownload: false,
loading: false,
msg: '',
});
/**
* 对话框表格信息导入确认执行函数
* @param isUpload 是否已上传文件
*/
function fnModalUploadImportClose(isUpload: boolean) {
if (isUpload) {
fnGetList();
}
}
/**对话框表格信息导入弹出窗口 */
function fnModalImportOpen() {
modalUploadImportState.visible = true;
function fnModalUploadImportOpen() {
uploadImportState.msg = '';
uploadImportState.loading = false;
uploadImportState.visible = true;
}
/**列表导入数据 */
async function fnModalImportData(data: FormData) {
/**对话框表格信息导入关闭窗口 */
function fnModalUploadImportClose() {
uploadImportState.visible = false;
fnGetList();
}
/**对话框表格信息导入上传 */
function fnModalUploadImportUpload(file: File) {
let formData = new FormData();
formData.append('file', file);
const neID = queryParams.neId;
if (!neID) {
return Promise.reject('未知网元');
}
return importSubData(neID, data);
const hide = message.loading('正在上传...', 0);
uploadImportState.loading = true;
importSubData(neID, formData)
.then(res => {
uploadImportState.msg = res.msg;
})
.catch((err: { code: number; msg: string }) => {
message.error(`上传失败 ${err.msg}`);
})
.finally(() => {
hide();
uploadImportState.loading = false;
});
}
onMounted(() => {
@@ -621,7 +636,7 @@ onMounted(() => {
</a-button>
</a-popconfirm>
<a-button type="dashed" @click.prevent="fnModalImportOpen">
<a-button type="dashed" @click.prevent="fnModalUploadImportOpen">
<template #icon>
<ImportOutlined />
</template>
@@ -1074,14 +1089,24 @@ onMounted(() => {
</a-modal>
<!-- 上传导入表格数据文件框 -->
<UploadImport
:title="modalUploadImportState.title"
v-model:visible="modalUploadImportState.visible"
:file-size="5"
:file-ext="['.csv', '.txt']"
:upload-file-method="fnModalImportData"
<UploadModal
:title="uploadImportState.title"
:loading="uploadImportState.loading"
@upload="fnModalUploadImportUpload"
@close="fnModalUploadImportClose"
/>
v-model:visible="uploadImportState.visible"
:ext="['.csv', '.txt']"
:size="5"
>
<template #default>
<a-textarea
:disabled="true"
:hidden="!uploadImportState.msg"
:value="uploadImportState.msg"
:auto-size="{ minRows: 2, maxRows: 8 }"
/>
</template>
</UploadModal>
</PageContainer>
</template>