增加单个上传和多个上传
This commit is contained in:
@@ -95,6 +95,64 @@
|
|||||||
/>
|
/>
|
||||||
<!-- 开关 -->
|
<!-- 开关 -->
|
||||||
<el-switch v-else-if="fieldItem.type === 'switch'" v-model="dynamicFormValues[fieldItem.field]" />
|
<el-switch v-else-if="fieldItem.type === 'switch'" v-model="dynamicFormValues[fieldItem.field]" />
|
||||||
|
<!-- 单个文件上传 -->
|
||||||
|
<div v-else-if="fieldItem.type === 'upload'" class="field-upload-wrapper">
|
||||||
|
<el-upload
|
||||||
|
:key="`field-upload-${fieldItem.field}-${getFieldUploadKey(fieldItem.field)}`"
|
||||||
|
:auto-upload="false"
|
||||||
|
:on-change="(file: any) => handleFieldUpload(fieldItem.field, file, 'upload')"
|
||||||
|
:file-list="[]"
|
||||||
|
:limit="1"
|
||||||
|
:show-file-list="false"
|
||||||
|
class="field-upload"
|
||||||
|
>
|
||||||
|
<el-button size="small" type="primary" :disabled="getFieldFileList(fieldItem.field).length >= 1">
|
||||||
|
选择文件
|
||||||
|
</el-button>
|
||||||
|
</el-upload>
|
||||||
|
<!-- 手动显示已上传成功的文件列表 -->
|
||||||
|
<div v-if="getFieldFileList(fieldItem.field).length > 0" class="uploaded-files-list">
|
||||||
|
<div v-for="(uploadedFile, fileIdx) in getFieldFileList(fieldItem.field)" :key="fileIdx" class="uploaded-file-item">
|
||||||
|
<span class="file-name">{{ uploadedFile.name }}</span>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
@click="removeFieldFile(fieldItem.field, fileIdx, 'upload')"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 多个文件上传 -->
|
||||||
|
<div v-else-if="fieldItem.type === 'uploadMultiple'" class="field-upload-wrapper">
|
||||||
|
<el-upload
|
||||||
|
:key="`field-upload-${fieldItem.field}-${getFieldUploadKey(fieldItem.field)}`"
|
||||||
|
:auto-upload="false"
|
||||||
|
:multiple="true"
|
||||||
|
:on-change="(file: any) => handleFieldUpload(fieldItem.field, file, 'uploadMultiple')"
|
||||||
|
:file-list="[]"
|
||||||
|
:show-file-list="false"
|
||||||
|
class="field-upload"
|
||||||
|
>
|
||||||
|
<el-button size="small" type="primary">选择文件</el-button>
|
||||||
|
</el-upload>
|
||||||
|
<!-- 手动显示已上传成功的文件列表 -->
|
||||||
|
<div v-if="getFieldFileList(fieldItem.field).length > 0" class="uploaded-files-list">
|
||||||
|
<div v-for="(uploadedFile, fileIdx) in getFieldFileList(fieldItem.field)" :key="fileIdx" class="uploaded-file-item">
|
||||||
|
<span class="file-name">{{ uploadedFile.name }}</span>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
@click="removeFieldFile(fieldItem.field, fileIdx, 'uploadMultiple')"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 键值对输入(HTTP节点的headers和body) -->
|
<!-- 键值对输入(HTTP节点的headers和body) -->
|
||||||
<div v-else-if="fieldItem.type === 'keyValue'" class="key-value-input-wrapper">
|
<div v-else-if="fieldItem.type === 'keyValue'" class="key-value-input-wrapper">
|
||||||
<div
|
<div
|
||||||
@@ -199,11 +257,50 @@
|
|||||||
<el-option label="数字" value="number" />
|
<el-option label="数字" value="number" />
|
||||||
<el-option label="多行文本" value="textarea" />
|
<el-option label="多行文本" value="textarea" />
|
||||||
<el-option label="开关" value="switch" />
|
<el-option label="开关" value="switch" />
|
||||||
|
<el-option label="单个上传" value="upload" />
|
||||||
|
<el-option label="多个上传" value="uploadMultiple" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-checkbox v-model="customField.required" class="custom-field-required">必填</el-checkbox>
|
<el-checkbox v-model="customField.required" class="custom-field-required">必填</el-checkbox>
|
||||||
<el-button type="danger" link @click="removeCustomField(index)">删除</el-button>
|
<el-button type="danger" link @click="removeCustomField(index)">删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-input v-model="customField.value" placeholder="默认值" class="custom-field-value-full" />
|
<!-- 文件上传类型显示上传组件 -->
|
||||||
|
<div v-if="customField.type === 'upload' || customField.type === 'uploadMultiple'" class="custom-field-upload-wrapper">
|
||||||
|
<el-upload
|
||||||
|
:key="`custom-upload-${index}-${customField.uploadKey || 0}`"
|
||||||
|
:auto-upload="false"
|
||||||
|
:multiple="customField.type === 'uploadMultiple'"
|
||||||
|
:on-change="(file: any) => handleCustomFieldUpload(index, file, customField.type)"
|
||||||
|
:file-list="[]"
|
||||||
|
:limit="customField.type === 'upload' ? 1 : undefined"
|
||||||
|
:show-file-list="false"
|
||||||
|
class="custom-field-upload"
|
||||||
|
>
|
||||||
|
<el-button size="small" type="primary" :disabled="customField.type === 'upload' && getCustomFieldFileList(index).length >= 1">
|
||||||
|
选择文件
|
||||||
|
</el-button>
|
||||||
|
</el-upload>
|
||||||
|
<!-- 手动显示已上传成功的文件列表 -->
|
||||||
|
<div v-if="getCustomFieldFileList(index).length > 0" class="uploaded-files-list">
|
||||||
|
<div v-for="(uploadedFile, fileIdx) in getCustomFieldFileList(index)" :key="fileIdx" class="uploaded-file-item">
|
||||||
|
<span class="file-name">{{ uploadedFile.name }}</span>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
@click="removeCustomFieldFile(index, fileIdx, customField.type)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 非文件上传类型显示默认值输入框 -->
|
||||||
|
<el-input
|
||||||
|
v-else
|
||||||
|
v-model="customField.value"
|
||||||
|
placeholder="默认值"
|
||||||
|
class="custom-field-value-full"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" link class="w100" @click="addCustomField">+ 添加自定义字段</el-button>
|
<el-button type="primary" link class="w100" @click="addCustomField">+ 添加自定义字段</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -1718,12 +1815,108 @@ const getSelectOptions = (fieldItem: NodeLibraryFormItem) => {
|
|||||||
};
|
};
|
||||||
// 添加自定义字段
|
// 添加自定义字段
|
||||||
const addCustomField = () => {
|
const addCustomField = () => {
|
||||||
customFields.value.push({ label: '', value: '', type: 'input', required: false });
|
customFields.value.push({ label: '', value: '', type: 'input', required: false, fileList: [], uploadKey: 0 });
|
||||||
};
|
};
|
||||||
// 删除自定义字段
|
// 删除自定义字段
|
||||||
const removeCustomField = (index: number) => {
|
const removeCustomField = (index: number) => {
|
||||||
customFields.value.splice(index, 1);
|
customFields.value.splice(index, 1);
|
||||||
};
|
};
|
||||||
|
// 获取自定义字段的文件列表
|
||||||
|
const getCustomFieldFileList = (index: number) => {
|
||||||
|
const field = customFields.value[index];
|
||||||
|
if (!field || !field.fileList) return [];
|
||||||
|
return field.fileList;
|
||||||
|
};
|
||||||
|
// 处理自定义字段文件上传
|
||||||
|
const handleCustomFieldUpload = async (index: number, file: any, type: string) => {
|
||||||
|
const field = customFields.value[index];
|
||||||
|
if (!field) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 上传文件到OSS
|
||||||
|
const uploadRes = await uploadFile(file.raw);
|
||||||
|
|
||||||
|
// 检查上传是否成功
|
||||||
|
if (!uploadRes || !uploadRes.data || !uploadRes.data.fileURL) {
|
||||||
|
throw new Error('上传失败:未返回文件URL');
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileUrl = uploadRes.data.fileAddressPrefix
|
||||||
|
? `${uploadRes.data.fileAddressPrefix}${uploadRes.data.fileURL}`
|
||||||
|
: uploadRes.data.fileURL;
|
||||||
|
|
||||||
|
// 初始化 fileList
|
||||||
|
if (!field.fileList) {
|
||||||
|
field.fileList = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据类型处理
|
||||||
|
if (type === 'upload') {
|
||||||
|
// 单个上传:替换现有文件
|
||||||
|
field.fileList = [{ name: file.name, url: fileUrl }];
|
||||||
|
field.value = fileUrl;
|
||||||
|
} else if (type === 'uploadMultiple') {
|
||||||
|
// 多个上传:添加到数组
|
||||||
|
field.fileList.push({ name: file.name, url: fileUrl });
|
||||||
|
|
||||||
|
// 解析现有的 value
|
||||||
|
let urls: string[] = [];
|
||||||
|
if (field.value) {
|
||||||
|
try {
|
||||||
|
urls = JSON.parse(field.value);
|
||||||
|
if (!Array.isArray(urls)) {
|
||||||
|
urls = [field.value];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
urls = field.value ? [field.value] : [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加新的 URL
|
||||||
|
urls.push(fileUrl);
|
||||||
|
field.value = JSON.stringify(urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessage.success('文件上传成功');
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.message || '文件上传失败');
|
||||||
|
console.error('Upload error:', error);
|
||||||
|
// 上传失败时,递增 uploadKey 来重置上传组件
|
||||||
|
field.uploadKey = (field.uploadKey || 0) + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 删除自定义字段的文件
|
||||||
|
const removeCustomFieldFile = (index: number, fileIdx: number, type: string) => {
|
||||||
|
const field = customFields.value[index];
|
||||||
|
if (!field || !field.fileList) return;
|
||||||
|
|
||||||
|
// 删除文件
|
||||||
|
field.fileList.splice(fileIdx, 1);
|
||||||
|
|
||||||
|
// 更新 value
|
||||||
|
if (type === 'upload') {
|
||||||
|
// 单个上传:清空 value
|
||||||
|
field.value = '';
|
||||||
|
} else if (type === 'uploadMultiple') {
|
||||||
|
// 多个上传:从数组中删除对应的 URL
|
||||||
|
try {
|
||||||
|
let urls: string[] = [];
|
||||||
|
if (field.value) {
|
||||||
|
urls = JSON.parse(field.value);
|
||||||
|
if (!Array.isArray(urls)) {
|
||||||
|
urls = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
urls.splice(fileIdx, 1);
|
||||||
|
field.value = urls.length > 0 ? JSON.stringify(urls) : '';
|
||||||
|
} catch (e) {
|
||||||
|
field.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递增 uploadKey 来重置上传组件
|
||||||
|
field.uploadKey = (field.uploadKey || 0) + 1;
|
||||||
|
};
|
||||||
// 获取键值对数组
|
// 获取键值对数组
|
||||||
const getKeyValuePairs = (field: string) => {
|
const getKeyValuePairs = (field: string) => {
|
||||||
const value = dynamicFormValues[field];
|
const value = dynamicFormValues[field];
|
||||||
@@ -1789,6 +1982,104 @@ const updateKeyValueFieldFromPairs = (field: string, pairs: Array<{ key: string;
|
|||||||
// 保存为JSON字符串
|
// 保存为JSON字符串
|
||||||
dynamicFormValues[field] = Object.keys(obj).length > 0 ? JSON.stringify(obj) : '';
|
dynamicFormValues[field] = Object.keys(obj).length > 0 ? JSON.stringify(obj) : '';
|
||||||
};
|
};
|
||||||
|
// 存储字段的文件列表
|
||||||
|
const fieldFileLists = reactive<Record<string, any[]>>({});
|
||||||
|
// 存储字段的上传key(用于重置上传组件)
|
||||||
|
const fieldUploadKeys = reactive<Record<string, number>>({});
|
||||||
|
// 获取字段的文件列表
|
||||||
|
const getFieldFileList = (field: string) => {
|
||||||
|
return fieldFileLists[field] || [];
|
||||||
|
};
|
||||||
|
// 获取字段的上传key
|
||||||
|
const getFieldUploadKey = (field: string) => {
|
||||||
|
return fieldUploadKeys[field] || 0;
|
||||||
|
};
|
||||||
|
// 处理字段文件上传
|
||||||
|
const handleFieldUpload = async (field: string, file: any, type: string) => {
|
||||||
|
try {
|
||||||
|
// 上传文件到OSS
|
||||||
|
const uploadRes = await uploadFile(file.raw);
|
||||||
|
|
||||||
|
// 检查上传是否成功
|
||||||
|
if (!uploadRes || !uploadRes.data || !uploadRes.data.fileURL) {
|
||||||
|
throw new Error('上传失败:未返回文件URL');
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileUrl = uploadRes.data.fileAddressPrefix
|
||||||
|
? `${uploadRes.data.fileAddressPrefix}${uploadRes.data.fileURL}`
|
||||||
|
: uploadRes.data.fileURL;
|
||||||
|
|
||||||
|
// 初始化文件列表
|
||||||
|
if (!fieldFileLists[field]) {
|
||||||
|
fieldFileLists[field] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据类型处理
|
||||||
|
if (type === 'upload') {
|
||||||
|
// 单个上传:替换现有文件
|
||||||
|
fieldFileLists[field] = [{ name: file.name, url: fileUrl }];
|
||||||
|
dynamicFormValues[field] = fileUrl;
|
||||||
|
} else if (type === 'uploadMultiple') {
|
||||||
|
// 多个上传:添加到数组
|
||||||
|
fieldFileLists[field].push({ name: file.name, url: fileUrl });
|
||||||
|
|
||||||
|
// 解析现有的 value
|
||||||
|
let urls: string[] = [];
|
||||||
|
if (dynamicFormValues[field]) {
|
||||||
|
try {
|
||||||
|
urls = JSON.parse(dynamicFormValues[field]);
|
||||||
|
if (!Array.isArray(urls)) {
|
||||||
|
urls = [dynamicFormValues[field]];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
urls = dynamicFormValues[field] ? [dynamicFormValues[field]] : [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加新的 URL
|
||||||
|
urls.push(fileUrl);
|
||||||
|
dynamicFormValues[field] = JSON.stringify(urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessage.success('文件上传成功');
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.message || '文件上传失败');
|
||||||
|
console.error('Upload error:', error);
|
||||||
|
// 上传失败时,递增 uploadKey 来重置上传组件
|
||||||
|
fieldUploadKeys[field] = (fieldUploadKeys[field] || 0) + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 删除字段的文件
|
||||||
|
const removeFieldFile = (field: string, fileIdx: number, type: string) => {
|
||||||
|
if (!fieldFileLists[field]) return;
|
||||||
|
|
||||||
|
// 删除文件
|
||||||
|
fieldFileLists[field].splice(fileIdx, 1);
|
||||||
|
|
||||||
|
// 更新 value
|
||||||
|
if (type === 'upload') {
|
||||||
|
// 单个上传:清空 value
|
||||||
|
dynamicFormValues[field] = '';
|
||||||
|
} else if (type === 'uploadMultiple') {
|
||||||
|
// 多个上传:从数组中删除对应的 URL
|
||||||
|
try {
|
||||||
|
let urls: string[] = [];
|
||||||
|
if (dynamicFormValues[field]) {
|
||||||
|
urls = JSON.parse(dynamicFormValues[field]);
|
||||||
|
if (!Array.isArray(urls)) {
|
||||||
|
urls = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
urls.splice(fileIdx, 1);
|
||||||
|
dynamicFormValues[field] = urls.length > 0 ? JSON.stringify(urls) : '';
|
||||||
|
} catch (e) {
|
||||||
|
dynamicFormValues[field] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递增 uploadKey 来重置上传组件
|
||||||
|
fieldUploadKeys[field] = (fieldUploadKeys[field] || 0) + 1;
|
||||||
|
};
|
||||||
// 判断是否可以添加自定义字段(排除判断节点、开始节点、HTTP节点等)
|
// 判断是否可以添加自定义字段(排除判断节点、开始节点、HTTP节点等)
|
||||||
const canAddCustomFields = (element: SelectedState | null) => {
|
const canAddCustomFields = (element: SelectedState | null) => {
|
||||||
if (!element || element.kind !== 'node') return false;
|
if (!element || element.kind !== 'node') return false;
|
||||||
@@ -3149,6 +3440,44 @@ onBeforeUnmount(() => {
|
|||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
.custom-field-upload-wrapper,
|
||||||
|
.field-upload-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.uploaded-files-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px;
|
||||||
|
background: #f9fafb;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.uploaded-file-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 6px 10px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.uploaded-file-item:hover {
|
||||||
|
border-color: #cbd5e1;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
.uploaded-file-item .file-name {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #374151;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
.input-source-list {
|
.input-source-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Reference in New Issue
Block a user