Pre Merge pull request !5 from NicholasLD/fileupload-fix
This commit is contained in:
commit
eb8abd9599
@ -1,7 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, useAttrs, watch } from 'vue';
|
import { computed, ref, useAttrs, watch } from 'vue';
|
||||||
import type { UploadFileInfo, UploadProps } from 'naive-ui';
|
import type { UploadFileInfo, UploadProps } from 'naive-ui';
|
||||||
import { fetchBatchDeleteOss } from '@/service/api/system/oss';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
import { fetchBatchDeleteOss, listByIds } from '@/service/api/system/oss';
|
||||||
import { getToken } from '@/store/modules/auth/shared';
|
import { getToken } from '@/store/modules/auth/shared';
|
||||||
import { getServiceBaseURL } from '@/utils/service';
|
import { getServiceBaseURL } from '@/utils/service';
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ interface Props {
|
|||||||
accept?: string;
|
accept?: string;
|
||||||
fileSize?: number;
|
fileSize?: number;
|
||||||
uploadType?: 'file' | 'image';
|
uploadType?: 'file' | 'image';
|
||||||
|
modelValue?: string | string[] | any[]; // 用于回显
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
@ -26,26 +28,70 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
defaultUpload: true,
|
defaultUpload: true,
|
||||||
showTip: true,
|
showTip: true,
|
||||||
max: 5,
|
max: 5,
|
||||||
accept: '.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.pdf',
|
accept: '',
|
||||||
fileSize: 5,
|
fileSize: 5,
|
||||||
uploadType: 'file'
|
uploadType: 'file',
|
||||||
|
modelValue: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
const attrs: UploadProps = useAttrs();
|
const attrs: UploadProps = useAttrs();
|
||||||
|
|
||||||
|
const accept = computed(() => {
|
||||||
|
return props.uploadType === 'file' ? '.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.pdf' : '.jpg,.jpeg,.png,.gif,.bmp,.webp';
|
||||||
|
});
|
||||||
|
|
||||||
let fileNum = 0;
|
let fileNum = 0;
|
||||||
const fileList = ref<UploadFileInfo[]>([]);
|
const fileList = ref<UploadFileInfo[]>([]);
|
||||||
|
|
||||||
const needRelaodData = ref(false);
|
const needRelaodData = ref(false);
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:modelValue', value: string): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
needRelaodData
|
needRelaodData
|
||||||
});
|
});
|
||||||
watch(
|
watch(
|
||||||
() => fileList.value,
|
() => props.modelValue,
|
||||||
newValue => {
|
async (newValue: string | any[] | string[]) => {
|
||||||
needRelaodData.value = newValue.length > 0;
|
if (!newValue) {
|
||||||
|
fileList.value = [];
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let list: UploadFileInfo[] = [];
|
||||||
|
|
||||||
|
if (Array.isArray(newValue)) {
|
||||||
|
list = newValue as UploadFileInfo[];
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const res = await listByIds(newValue);
|
||||||
|
list = res.data;
|
||||||
|
} catch (error) {
|
||||||
|
list = [];
|
||||||
|
throw new Error(`获取文件列表失败: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileList.value = list.map((item: any) => {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
return {
|
||||||
|
id: item,
|
||||||
|
name: item,
|
||||||
|
url: item,
|
||||||
|
status: 'finished'
|
||||||
|
} as UploadFileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: String(item.ossId),
|
||||||
|
name: item.fileName,
|
||||||
|
url: item.url,
|
||||||
|
status: 'finished'
|
||||||
|
} as UploadFileInfo;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
||||||
@ -56,7 +102,12 @@ const headers: Record<string, string> = {
|
|||||||
clientid: import.meta.env.VITE_APP_CLIENT_ID!
|
clientid: import.meta.env.VITE_APP_CLIENT_ID!
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 拷贝一份当前的FileList
|
||||||
|
let currentFileList: UploadFileInfo[] = [];
|
||||||
|
|
||||||
function beforeUpload(options: { file: UploadFileInfo; fileList: UploadFileInfo[] }) {
|
function beforeUpload(options: { file: UploadFileInfo; fileList: UploadFileInfo[] }) {
|
||||||
|
currentFileList = cloneDeep(fileList.value);
|
||||||
|
|
||||||
fileNum += 1;
|
fileNum += 1;
|
||||||
const { file } = options;
|
const { file } = options;
|
||||||
|
|
||||||
@ -70,6 +121,12 @@ function beforeUpload(options: { file: UploadFileInfo; fileList: UploadFileInfo[
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (accept.value && !file.name.match(new RegExp(accept.value.replace(/\./g, '\\.').replace(/,/g, '|')))) {
|
||||||
|
window.$message?.error(`文件格式不正确, 请上传 ${accept.value} 格式文件!`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 校检文件名是否包含特殊字符
|
// 校检文件名是否包含特殊字符
|
||||||
if (file.name.includes(',')) {
|
if (file.name.includes(',')) {
|
||||||
window.$message?.error('文件名不正确,不能包含英文逗号!');
|
window.$message?.error('文件名不正确,不能包含英文逗号!');
|
||||||
@ -92,23 +149,54 @@ function isErrorState(xhr: XMLHttpRequest) {
|
|||||||
return response.code !== 200;
|
return response.code !== 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 对象转成指定字符串分隔
|
||||||
|
const listToString = (list: any[]) => {
|
||||||
|
let strs = '';
|
||||||
|
const separator = ',';
|
||||||
|
for (const i in list) {
|
||||||
|
if (undefined !== list[i].id && list[i].url?.indexOf('blob:') !== 0) {
|
||||||
|
strs += list[i].id + separator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strs !== '' ? strs.substring(0, strs.length - 1) : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 上传中的文件列表
|
||||||
|
const uploadingFiles = ref<any[]>([]);
|
||||||
|
|
||||||
function handleFinish(options: { file: UploadFileInfo; event?: ProgressEvent }) {
|
function handleFinish(options: { file: UploadFileInfo; event?: ProgressEvent }) {
|
||||||
fileNum -= 1;
|
fileNum -= 1;
|
||||||
const { file, event } = options;
|
const { file } = options;
|
||||||
// @ts-expect-error Ignore type errors
|
|
||||||
const responseText = event?.target?.responseText;
|
// 标记当前文件上传完成
|
||||||
const response = JSON.parse(responseText);
|
const target = event?.target as XMLHttpRequest;
|
||||||
const oss: Api.System.Oss = response.data;
|
const responseText = target?.responseText;
|
||||||
fileList.value.find(item => item.id === file.id)!.id = String(oss.ossId);
|
const uploadFileResp = JSON.parse(responseText).data;
|
||||||
file.id = String(oss.ossId);
|
|
||||||
file.url = oss.url;
|
uploadingFiles.value.push({
|
||||||
file.name = oss.fileName;
|
id: uploadFileResp.ossId,
|
||||||
|
name: uploadFileResp.fileName,
|
||||||
|
url: uploadFileResp.url
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查是否所有文件都上传完成
|
||||||
if (fileNum === 0) {
|
if (fileNum === 0) {
|
||||||
|
// 所有文件上传完成,执行批量查询
|
||||||
|
handleAllFilesUploaded();
|
||||||
window.$message?.success('上传成功');
|
window.$message?.success('上传成功');
|
||||||
}
|
}
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleAllFilesUploaded() {
|
||||||
|
fileList.value = [...currentFileList, ...uploadingFiles.value];
|
||||||
|
uploadingFiles.value = [];
|
||||||
|
const fileIds = listToString(fileList.value);
|
||||||
|
emit('update:modelValue', fileIds);
|
||||||
|
needRelaodData.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
function handleError(options: { file: UploadFileInfo; event?: ProgressEvent }) {
|
function handleError(options: { file: UploadFileInfo; event?: ProgressEvent }) {
|
||||||
const { event } = options;
|
const { event } = options;
|
||||||
// @ts-expect-error Ignore type errors
|
// @ts-expect-error Ignore type errors
|
||||||
@ -121,8 +209,13 @@ async function handleRemove(file: UploadFileInfo) {
|
|||||||
if (file.status !== 'finished') {
|
if (file.status !== 'finished') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
fileList.value = fileList.value.filter(item => item.id !== file.id);
|
||||||
|
const fileIds = listToString(fileList.value);
|
||||||
|
emit('update:modelValue', fileIds);
|
||||||
|
needRelaodData.value = true;
|
||||||
const { error } = await fetchBatchDeleteOss([file.id]);
|
const { error } = await fetchBatchDeleteOss([file.id]);
|
||||||
if (error) return;
|
if (error) return;
|
||||||
|
|
||||||
window.$message?.success('删除成功');
|
window.$message?.success('删除成功');
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -10,6 +10,14 @@ export function fetchGetOssList(params?: Api.System.OssSearchParams) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询OSS对象基于id串
|
||||||
|
export function listByIds(ossId: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/resource/oss/listByIds/${ossId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** 批量删除文件管理 */
|
/** 批量删除文件管理 */
|
||||||
export function fetchBatchDeleteOss(ossIds: CommonType.IdType[]) {
|
export function fetchBatchDeleteOss(ossIds: CommonType.IdType[]) {
|
||||||
return request<boolean>({
|
return request<boolean>({
|
||||||
|
Loading…
Reference in New Issue
Block a user