feat(components): 新增表单上传组件

This commit is contained in:
xlsea 2025-06-10 22:00:28 +08:00
parent da1c16e023
commit 03c8a7f5b7
5 changed files with 64 additions and 50 deletions

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, useAttrs, watch } from 'vue'; import { useAttrs } from 'vue';
import type { UploadFileInfo, UploadProps } from 'naive-ui'; import type { UploadFileInfo, UploadProps } from 'naive-ui';
import { fetchBatchDeleteOss } from '@/service/api/system/oss'; import { fetchBatchDeleteOss } from '@/service/api/system/oss';
import { getToken } from '@/store/modules/auth/shared'; import { getToken } from '@/store/modules/auth/shared';
@ -34,19 +34,9 @@ const props = withDefaults(defineProps<Props>(), {
const attrs: UploadProps = useAttrs(); const attrs: UploadProps = useAttrs();
let fileNum = 0; let fileNum = 0;
const fileList = ref<UploadFileInfo[]>([]); const fileList = defineModel<UploadFileInfo[]>('fileList', {
default: () => []
const needRelaodData = ref(false);
defineExpose({
needRelaodData
}); });
watch(
() => fileList.value,
newValue => {
needRelaodData.value = newValue.length > 0;
}
);
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';
const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy); const { baseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
@ -119,11 +109,12 @@ function handleError(options: { file: UploadFileInfo; event?: ProgressEvent }) {
async function handleRemove(file: UploadFileInfo) { async function handleRemove(file: UploadFileInfo) {
if (file.status !== 'finished') { if (file.status !== 'finished') {
return; return false;
} }
const { error } = await fetchBatchDeleteOss([file.id]); const { error } = await fetchBatchDeleteOss([file.id]);
if (error) return; if (error) return false;
window.$message?.success('删除成功'); window.$message?.success('删除成功');
return true;
} }
</script> </script>

View File

@ -0,0 +1,46 @@
<script setup lang="ts">
import { onMounted, ref, useAttrs, watch } from 'vue';
import type { UploadFileInfo } from 'naive-ui';
import { fetchGetOssListByIds } from '@/service/api/system/oss';
import { isNotNull } from '@/utils/common';
import FileUpload from '@/components/custom/file-upload.vue';
defineOptions({
name: 'OssUpload'
});
const attrs = useAttrs();
const value = defineModel<string>('value', { default: '' });
const fileList = ref<UploadFileInfo[]>([]);
onMounted(async () => {
fileList.value = [];
const ossIds = value.value.split(',')?.filter(item => isNotNull(item));
if (ossIds.length > 0) {
const { error, data } = await fetchGetOssListByIds(ossIds);
if (error) return;
fileList.value = data.map(item => ({
id: String(item.ossId),
url: item.url,
name: item.originalName,
status: 'finished'
}));
}
});
watch(
fileList,
val => {
value.value = val.map(item => item.id).join(',');
},
{ deep: true }
);
</script>
<template>
<FileUpload v-bind="attrs" v-model:file-list="fileList" />
</template>
<style scoped></style>

View File

@ -1,4 +1,3 @@
import type { AxiosRequestConfig, GenericAbortSignal } from 'axios';
import { request } from '@/service/request'; import { request } from '@/service/request';
/** 获取文件管理列表 */ /** 获取文件管理列表 */
@ -18,36 +17,10 @@ export function fetchBatchDeleteOss(ossIds: CommonType.IdType[]) {
}); });
} }
/** Axios上传进度事件 */ // 查询OSS对象基于id串
export type AxiosProgressEvent = AxiosRequestConfig['onUploadProgress']; export function fetchGetOssListByIds(ossIds: CommonType.IdType[]) {
return request<Api.System.Oss[]>({
/** 默认上传结果 */ url: `/resource/oss/listByIds/${ossIds.join(',')}`,
export interface UploadResult { method: 'get'
url: string;
fileName: string;
ossId: string;
}
export interface UploadApiOptions {
onUploadProgress?: AxiosProgressEvent;
signal?: GenericAbortSignal;
}
/** 上传文件接口 */
export function uploadApi(file: File | Blob, options?: UploadApiOptions) {
const { onUploadProgress, signal } = options ?? {};
const formData = new FormData();
formData.append('file', file);
return request<UploadResult>({
url: '/resource/oss/upload',
method: 'post',
data: formData,
onUploadProgress,
headers: {
'Content-Type': 'multipart/form-data'
},
signal
}); });
} }

View File

@ -129,6 +129,7 @@ declare module 'vue' {
NUpload: typeof import('naive-ui')['NUpload'] NUpload: typeof import('naive-ui')['NUpload']
NUploadDragger: typeof import('naive-ui')['NUploadDragger'] NUploadDragger: typeof import('naive-ui')['NUploadDragger']
NWatermark: typeof import('naive-ui')['NWatermark'] NWatermark: typeof import('naive-ui')['NWatermark']
OssUpload: typeof import('./../components/custom/oss-upload.vue')['default']
PinToggler: typeof import('./../components/common/pin-toggler.vue')['default'] PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
PostSelect: typeof import('./../components/custom/post-select.vue')['default'] PostSelect: typeof import('./../components/custom/post-select.vue')['default']
ReloadButton: typeof import('./../components/common/reload-button.vue')['default'] ReloadButton: typeof import('./../components/common/reload-button.vue')['default']

View File

@ -1,11 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import type { UploadFileInfo } from 'naive-ui';
import FileUpload from '@/components/custom/file-upload.vue'; import FileUpload from '@/components/custom/file-upload.vue';
defineOptions({ defineOptions({
name: 'OssUploadModal' name: 'OssUploadModal'
}); });
const fileUploadRef = ref<InstanceType<typeof FileUpload> | null>(null);
interface Props { interface Props {
uploadType: 'file' | 'image'; uploadType: 'file' | 'image';
} }
@ -26,6 +27,8 @@ const accept = computed(() => {
return props.uploadType === 'file' ? '.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.pdf' : '.jpg,.jpeg,.png,.gif,.bmp,.webp'; return props.uploadType === 'file' ? '.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.pdf' : '.jpg,.jpeg,.png,.gif,.bmp,.webp';
}); });
const fileList = ref<UploadFileInfo[]>([]);
function handleUpdateModelWhenUpload() {} function handleUpdateModelWhenUpload() {}
function closeDrawer() { function closeDrawer() {
@ -34,7 +37,7 @@ function closeDrawer() {
function handleClose() { function handleClose() {
closeDrawer(); closeDrawer();
if (fileUploadRef.value?.needRelaodData) { if (fileList.value?.length > 0) {
emit('close'); emit('close');
} }
} }
@ -56,7 +59,7 @@ watch(visible, () => {
:bordered="false" :bordered="false"
@after-leave="handleClose" @after-leave="handleClose"
> >
<FileUpload ref="fileUploadRef" :upload-type="uploadType" :accept="accept" /> <FileUpload v-model:file-list="fileList" :upload-type="uploadType" :accept="accept" />
</NModal> </NModal>
</template> </template>