完善文件上传
This commit is contained in:
parent
b16a495cf1
commit
9a9420f423
@ -54,5 +54,6 @@
|
|||||||
"exportFailed": "Data export failed",
|
"exportFailed": "Data export failed",
|
||||||
"getDataFailed": "Failed to get data",
|
"getDataFailed": "Failed to get data",
|
||||||
"PhoneNumberFormatError": "PhoneNumber Format Error",
|
"PhoneNumberFormatError": "PhoneNumber Format Error",
|
||||||
"IoTPlatform": "IoTPlatform"
|
"IoTPlatform": "IoTPlatform",
|
||||||
|
"note": "note"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,5 +55,6 @@
|
|||||||
"getDataFailed": "获取数据失败",
|
"getDataFailed": "获取数据失败",
|
||||||
"IsEnabled": "是否启用",
|
"IsEnabled": "是否启用",
|
||||||
"PhoneNumberFormatError": "手机号码格式错误",
|
"PhoneNumberFormatError": "手机号码格式错误",
|
||||||
"IoTPlatform": "物联网平台"
|
"IoTPlatform": "物联网平台",
|
||||||
|
"note": "备注"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,26 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { createIconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import { useVbenForm } from '#/adapter/form';
|
import { useVbenForm } from '#/adapter/form';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { addFormSchema } from './schema';
|
import { addFormSchema } from './schema';
|
||||||
|
import { postFilesUpload } from '#/api-client/index';
|
||||||
|
|
||||||
const emit = defineEmits(['reload']);
|
const emit = defineEmits(['reload']);
|
||||||
|
|
||||||
|
// 创建上传图标
|
||||||
|
const UploadIcon = createIconifyIcon('mdi:upload');
|
||||||
|
const FolderIcon = createIconifyIcon('mdi:folder');
|
||||||
|
|
||||||
|
// 文件列表状态
|
||||||
|
const fileList = ref<any[]>([]);
|
||||||
|
const uploading = ref(false);
|
||||||
|
const fileInput = ref<HTMLInputElement>();
|
||||||
|
|
||||||
const [Form, formApi] = useVbenForm({
|
const [Form, formApi] = useVbenForm({
|
||||||
// 所有表单项共用,可单独在表单内覆盖
|
// 所有表单项共用,可单独在表单内覆盖
|
||||||
commonConfig: {
|
commonConfig: {
|
||||||
@ -22,18 +36,277 @@ const [Form, formApi] = useVbenForm({
|
|||||||
schema: addFormSchema,
|
schema: addFormSchema,
|
||||||
wrapperClass: 'grid-cols-1',
|
wrapperClass: 'grid-cols-1',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 处理文件变化
|
||||||
|
const handleFileChange = (info: any) => {
|
||||||
|
console.log('File change:', info);
|
||||||
|
console.log('File list before:', fileList.value);
|
||||||
|
fileList.value = info.fileList;
|
||||||
|
console.log('File list after:', fileList.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 文件上传前的验证
|
||||||
|
const beforeUpload = (file: File) => {
|
||||||
|
// 这里可以添加文件大小、类型等验证
|
||||||
|
const isLt10M = file.size / 1024 / 1024 < 10;
|
||||||
|
if (!isLt10M) {
|
||||||
|
message.error('文件大小不能超过10MB!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true; // 允许文件选择,但不自动上传
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除文件
|
||||||
|
const handleRemove = (file: any) => {
|
||||||
|
const index = fileList.value.indexOf(file);
|
||||||
|
const newFileList = fileList.value.slice();
|
||||||
|
newFileList.splice(index, 1);
|
||||||
|
fileList.value = newFileList;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 触发文件选择
|
||||||
|
const triggerFileInput = () => {
|
||||||
|
fileInput.value?.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理文件输入变化
|
||||||
|
const handleFileInputChange = (event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
if (target.files) {
|
||||||
|
const newFiles = Array.from(target.files).map(file => ({
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
type: file.type,
|
||||||
|
originFileObj: file
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 验证文件大小(10MB限制)
|
||||||
|
const validFiles = newFiles.filter(file => {
|
||||||
|
const isLt10M = file.size / 1024 / 1024 < 10;
|
||||||
|
if (!isLt10M) {
|
||||||
|
message.error(`文件 ${file.name} 大小超过10MB限制`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
fileList.value = [...fileList.value, ...validFiles];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理拖拽
|
||||||
|
const handleDrop = (e: DragEvent) => {
|
||||||
|
console.log('Drop event:', e);
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (e.dataTransfer?.files) {
|
||||||
|
const newFiles = Array.from(e.dataTransfer.files).map(file => ({
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
type: file.type,
|
||||||
|
originFileObj: file
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 验证文件大小(10MB限制)
|
||||||
|
const validFiles = newFiles.filter(file => {
|
||||||
|
const isLt10M = file.size / 1024 / 1024 < 10;
|
||||||
|
if (!isLt10M) {
|
||||||
|
message.error(`文件 ${file.name} 大小超过10MB限制`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
fileList.value = [...fileList.value, ...validFiles];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除文件
|
||||||
|
const removeFile = (index: number) => {
|
||||||
|
fileList.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 格式化文件大小
|
||||||
|
const formatFileSize = (bytes: number) => {
|
||||||
|
if (bytes === 0) return '0 B';
|
||||||
|
const k = 1024;
|
||||||
|
const sizes = ['B', 'KB', 'MB', 'GB'];
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 手动上传文件
|
||||||
|
const handleUpload = async () => {
|
||||||
|
if (fileList.value.length === 0) {
|
||||||
|
message.warning('请选择要上传的文件');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploading.value = true;
|
||||||
|
try {
|
||||||
|
// 获取表单数据
|
||||||
|
const formValues = await formApi.getValues();
|
||||||
|
console.log('Form values:', formValues);
|
||||||
|
console.log('File list:', fileList.value);
|
||||||
|
|
||||||
|
// 创建一个FormData对象,包含所有文件
|
||||||
|
const uploadFormData = new FormData();
|
||||||
|
|
||||||
|
// 添加所有文件到FormData
|
||||||
|
fileList.value.forEach((fileInfo, index) => {
|
||||||
|
if (fileInfo.originFileObj) {
|
||||||
|
console.log(`Adding file ${index}:`, fileInfo.name, fileInfo.originFileObj);
|
||||||
|
uploadFormData.append('files', fileInfo.originFileObj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加表单其他数据(如果有的话)
|
||||||
|
if (formValues) {
|
||||||
|
Object.keys(formValues).forEach(key => {
|
||||||
|
if (formValues[key] !== undefined && formValues[key] !== null) {
|
||||||
|
console.log(`Adding form field ${key}:`, formValues[key]);
|
||||||
|
uploadFormData.append(key, formValues[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印FormData内容(调试用)
|
||||||
|
for (let [key, value] of uploadFormData.entries()) {
|
||||||
|
console.log(`FormData entry: ${key} =`, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传文件
|
||||||
|
const result = await postFilesUpload({
|
||||||
|
body: uploadFormData as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Upload result:', result);
|
||||||
|
|
||||||
|
// 检查上传结果
|
||||||
|
if (result.status === 204 || result.status === 200) {
|
||||||
|
message.success(`文件上传成功!共上传 ${fileList.value.length} 个文件`);
|
||||||
|
emit('reload');
|
||||||
|
modalApi.close();
|
||||||
|
} else {
|
||||||
|
message.error('文件上传失败,请重试');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Upload error:', error);
|
||||||
|
message.error('文件上传失败');
|
||||||
|
} finally {
|
||||||
|
uploading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
onCancel() {
|
onCancel() {
|
||||||
|
fileList.value = [];
|
||||||
modalApi.close();
|
modalApi.close();
|
||||||
},
|
},
|
||||||
async onConfirm() {
|
async onConfirm() {
|
||||||
emit('reload');
|
await handleUpload();
|
||||||
modalApi.close();
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Modal :title="$t('common.upload')">
|
<Modal :title="$t('common.upload')" :confirm-loading="uploading">
|
||||||
<Form />
|
<Form />
|
||||||
|
<div class="mt-4">
|
||||||
|
<div class="upload-area" @click="triggerFileInput" @drop="handleDrop" @dragover.prevent>
|
||||||
|
<input
|
||||||
|
ref="fileInput"
|
||||||
|
type="file"
|
||||||
|
multiple
|
||||||
|
accept="*/*"
|
||||||
|
style="display: none"
|
||||||
|
@change="handleFileInputChange"
|
||||||
|
/>
|
||||||
|
<div class="ant-upload-drag-container">
|
||||||
|
<p class="ant-upload-drag-icon">
|
||||||
|
<FolderIcon />
|
||||||
|
</p>
|
||||||
|
<p class="ant-upload-text">点击或拖拽文件到此区域上传</p>
|
||||||
|
<p class="ant-upload-hint">
|
||||||
|
支持单个或批量上传,严禁上传公司数据或其他敏感文件
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 显示已选择的文件列表 -->
|
||||||
|
<div v-if="fileList.length > 0" class="mt-4">
|
||||||
|
<h4>已选择的文件:</h4>
|
||||||
|
<div v-for="(file, index) in fileList" :key="index" class="file-item">
|
||||||
|
<div class="file-info">
|
||||||
|
<span class="file-name">{{ file.name }}</span>
|
||||||
|
<span class="file-size">{{ formatFileSize(file.size) }}</span>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="ant-btn ant-btn-link ant-btn-sm" @click="removeFile(index)">删除</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ant-upload-drag-container {
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border: 2px dashed #d9d9d9;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #fafafa;
|
||||||
|
transition: border-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload-drag-container:hover {
|
||||||
|
border-color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload-drag-icon {
|
||||||
|
font-size: 48px;
|
||||||
|
color: #999;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload-text {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload-hint {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-area {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-size {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -10,6 +10,9 @@ import { postFilesDelete } from '#/api-client/index';
|
|||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const querySchema = computed(() => [
|
export const querySchema = computed(() => [
|
||||||
{
|
{
|
||||||
component: 'RangePicker',
|
component: 'RangePicker',
|
||||||
@ -66,33 +69,13 @@ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
export const addFormSchema = computed(() => [
|
export const addFormSchema = computed(() => [
|
||||||
|
// 文件上传现在在AddModal中处理
|
||||||
{
|
{
|
||||||
component: 'Upload',
|
component: 'Input',
|
||||||
fieldName: 'files',
|
fieldName: 'note',
|
||||||
label: $t('abp.file.file'),
|
label: $t('common.note'),
|
||||||
componentProps: () => {
|
componentProps: {
|
||||||
return {
|
placeholder: '请输入备注信息',
|
||||||
listType: 'picture-card',
|
|
||||||
autoUpload: true,
|
|
||||||
multiple: true,
|
|
||||||
name: 'files',
|
|
||||||
action: `${import.meta.env.VITE_APP_API_ADDRESS}/Files/Upload?access_token=${
|
|
||||||
userStore.userInfo?.token
|
|
||||||
}`,
|
|
||||||
onPreview: () => {},
|
|
||||||
onRemove: async (file: any) => {
|
|
||||||
await postFilesDelete({
|
|
||||||
body: {
|
|
||||||
id: file.response[0].id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
renderComponentContent: () => {
|
|
||||||
return {
|
|
||||||
default: () => 'Upload',
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user