feat: 优化数据中枢 Excel 连接创建交互
- 在新增连接中完成 Excel 上传并自动填写连接名称 - 限制上传格式并提供空表和无表头错误反馈 - 移除旧导入入口和无效测试连接操作
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import type { FormInstance, UploadFile, UploadInstance } from 'element-plus';
|
||||
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
@@ -7,20 +7,31 @@ import { EasyFlowFormModal } from '@easyflow/common-ui';
|
||||
|
||||
import { EasyFlowButton } from '@easyflow-core/shadcn-ui';
|
||||
|
||||
import { CircleCheckFilled, CircleCloseFilled } from '@element-plus/icons-vue';
|
||||
import {
|
||||
CircleCheckFilled,
|
||||
CircleCloseFilled,
|
||||
UploadFilled,
|
||||
} from '@element-plus/icons-vue';
|
||||
import {
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElIcon,
|
||||
ElInput,
|
||||
ElMessage,
|
||||
ElOption,
|
||||
ElSelect,
|
||||
ElUpload,
|
||||
} from 'element-plus';
|
||||
|
||||
import {
|
||||
sourceTypeLabels,
|
||||
sourceTypeOptions,
|
||||
} from '../composables/datacenter-constants';
|
||||
import {
|
||||
EXCEL_FILE_ACCEPT,
|
||||
isSupportedExcelFileName,
|
||||
sourceNameFromExcelFileName,
|
||||
} from '../composables/datacenter-excel-upload';
|
||||
import { useSourceForm } from '../composables/use-source-form';
|
||||
import SourceBrandIcon from './SourceBrandIcon.vue';
|
||||
|
||||
@@ -31,13 +42,17 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
save: [form: Record<string, any>];
|
||||
save: [form: Record<string, any>, excelFile?: File];
|
||||
test: [form: Record<string, any>];
|
||||
'update:visible': [value: boolean];
|
||||
}>();
|
||||
const formRef = ref<FormInstance>();
|
||||
const excelUploadRef = ref<UploadInstance>();
|
||||
const testResult = ref<any>(null);
|
||||
const showAdvanced = ref(false);
|
||||
const pendingExcelFile = ref<File | null>(null);
|
||||
const excelFileError = ref('');
|
||||
const lastGeneratedSourceName = ref('');
|
||||
|
||||
const {
|
||||
form,
|
||||
@@ -60,10 +75,24 @@ const testButtonClass = computed(() => ({
|
||||
const selectedSourceTypeLabel = computed(
|
||||
() => sourceTypeLabels[form.sourceType] || form.sourceType,
|
||||
);
|
||||
const isExcelCreate = computed(() => form.sourceType === 'EXCEL' && !form.id);
|
||||
const confirmDisabled = computed(
|
||||
() =>
|
||||
isExcelCreate.value &&
|
||||
(!pendingExcelFile.value || !String(form.sourceName || '').trim()),
|
||||
);
|
||||
|
||||
function resetExcelFile() {
|
||||
excelUploadRef.value?.clearFiles();
|
||||
pendingExcelFile.value = null;
|
||||
excelFileError.value = '';
|
||||
lastGeneratedSourceName.value = '';
|
||||
}
|
||||
|
||||
function resetDialogState() {
|
||||
testResult.value = null;
|
||||
showAdvanced.value = false;
|
||||
resetExcelFile();
|
||||
}
|
||||
|
||||
function open(row?: any) {
|
||||
@@ -78,8 +107,16 @@ function close() {
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
if (isExcelCreate.value && !pendingExcelFile.value) {
|
||||
excelFileError.value = '请选择需要导入的 Excel 文件';
|
||||
return;
|
||||
}
|
||||
await formRef.value?.validate();
|
||||
emit('save', { ...form });
|
||||
emit(
|
||||
'save',
|
||||
{ ...form },
|
||||
isExcelCreate.value ? pendingExcelFile.value || undefined : undefined,
|
||||
);
|
||||
}
|
||||
|
||||
async function handleTest() {
|
||||
@@ -96,6 +133,33 @@ function setTestResult(result: any) {
|
||||
testResult.value = result;
|
||||
}
|
||||
|
||||
function handleUploadChange(file: UploadFile) {
|
||||
if (!isSupportedExcelFileName(file.name)) {
|
||||
excelUploadRef.value?.clearFiles();
|
||||
pendingExcelFile.value = null;
|
||||
excelFileError.value = '仅支持 .xls 和 .xlsx 格式的 Excel 文件';
|
||||
ElMessage.warning(excelFileError.value);
|
||||
return;
|
||||
}
|
||||
|
||||
const generatedSourceName = sourceNameFromExcelFileName(file.name);
|
||||
if (
|
||||
!String(form.sourceName || '').trim() ||
|
||||
form.sourceName === lastGeneratedSourceName.value
|
||||
) {
|
||||
form.sourceName = generatedSourceName;
|
||||
formRef.value?.clearValidate('sourceName');
|
||||
}
|
||||
lastGeneratedSourceName.value = generatedSourceName;
|
||||
pendingExcelFile.value = file.raw || null;
|
||||
excelFileError.value = '';
|
||||
}
|
||||
|
||||
function handleUploadRemove() {
|
||||
pendingExcelFile.value = null;
|
||||
excelFileError.value = '';
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [
|
||||
form.sourceName,
|
||||
@@ -117,6 +181,15 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => form.sourceType,
|
||||
(_sourceType, previousSourceType) => {
|
||||
if (previousSourceType && previousSourceType !== form.sourceType) {
|
||||
resetExcelFile();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
defineExpose({ close, open, setTestResult });
|
||||
</script>
|
||||
|
||||
@@ -125,6 +198,7 @@ defineExpose({ close, open, setTestResult });
|
||||
:open="visible"
|
||||
:title="modalTitle"
|
||||
:before-close="handleBeforeClose"
|
||||
:confirm-disabled="confirmDisabled"
|
||||
:confirm-loading="saving"
|
||||
confirm-text="保存"
|
||||
:submitting="saving"
|
||||
@@ -141,13 +215,19 @@ defineExpose({ close, open, setTestResult });
|
||||
>
|
||||
<div class="form-grid">
|
||||
<ElFormItem label="连接名称" prop="sourceName">
|
||||
<ElInput v-model="form.sourceName" placeholder="例如:华东 MySQL" />
|
||||
<ElInput
|
||||
v-model="form.sourceName"
|
||||
maxlength="100"
|
||||
:placeholder="
|
||||
isExcelCreate ? '选择文件后自动填写' : '例如:华东 MySQL'
|
||||
"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="连接类型" prop="sourceType">
|
||||
<ElSelect
|
||||
v-model="form.sourceType"
|
||||
class="w-full"
|
||||
:disabled="Boolean(form.builtinFlag)"
|
||||
:disabled="Boolean(form.builtinFlag || form.id)"
|
||||
>
|
||||
<template #label>
|
||||
<span class="source-type-select-label">
|
||||
@@ -174,6 +254,35 @@ defineExpose({ close, open, setTestResult });
|
||||
</ElFormItem>
|
||||
</div>
|
||||
|
||||
<ElFormItem
|
||||
v-if="isExcelCreate"
|
||||
label="表格文件"
|
||||
required
|
||||
:error="excelFileError"
|
||||
class="excel-file-field"
|
||||
>
|
||||
<ElUpload
|
||||
ref="excelUploadRef"
|
||||
class="excel-upload"
|
||||
drag
|
||||
:accept="EXCEL_FILE_ACCEPT"
|
||||
:auto-upload="false"
|
||||
:show-file-list="true"
|
||||
:limit="1"
|
||||
:disabled="saving"
|
||||
:on-change="handleUploadChange"
|
||||
:on-remove="handleUploadRemove"
|
||||
>
|
||||
<ElIcon class="excel-upload__icon">
|
||||
<UploadFilled />
|
||||
</ElIcon>
|
||||
<div class="excel-upload__title">拖拽或点击选择 Excel 文件</div>
|
||||
<div class="excel-upload__description">
|
||||
仅支持 .xls、.xlsx;工作表首行需包含表头
|
||||
</div>
|
||||
</ElUpload>
|
||||
</ElFormItem>
|
||||
|
||||
<template v-if="supportsExternalConnection">
|
||||
<div class="form-grid">
|
||||
<ElFormItem label="主机">
|
||||
@@ -242,6 +351,7 @@ defineExpose({ close, open, setTestResult });
|
||||
|
||||
<template #footer-extra>
|
||||
<EasyFlowButton
|
||||
v-if="supportsExternalConnection"
|
||||
variant="outline"
|
||||
:loading="testing"
|
||||
:disabled="saving"
|
||||
@@ -308,6 +418,62 @@ defineExpose({ close, open, setTestResult });
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.excel-file-field {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.excel-upload {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.excel-upload :deep(.el-upload) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.excel-upload :deep(.el-upload-dragger) {
|
||||
width: 100%;
|
||||
padding: 24px;
|
||||
background: hsl(var(--surface-subtle) / 72%);
|
||||
border-color: hsl(var(--border) / 76%);
|
||||
border-radius: var(--radius-panel);
|
||||
transition:
|
||||
background-color 0.16s,
|
||||
border-color 0.16s;
|
||||
}
|
||||
|
||||
.excel-upload :deep(.el-upload-dragger:hover),
|
||||
.excel-upload :deep(.el-upload-dragger:focus-visible) {
|
||||
background: hsl(var(--primary) / 5%);
|
||||
border-color: hsl(var(--primary) / 56%);
|
||||
}
|
||||
|
||||
.excel-upload__icon {
|
||||
margin-bottom: 8px;
|
||||
font-size: 28px;
|
||||
color: hsl(var(--primary));
|
||||
}
|
||||
|
||||
.excel-upload__title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: hsl(var(--foreground));
|
||||
}
|
||||
|
||||
.excel-upload__description {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
.excel-upload :deep(.el-upload-list) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.excel-upload :deep(.el-upload-list__item) {
|
||||
border-radius: var(--radius-control);
|
||||
}
|
||||
|
||||
.toggle-advanced {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user