初始化

This commit is contained in:
2026-02-22 18:56:10 +08:00
commit 26677972a6
3112 changed files with 255972 additions and 0 deletions

View File

@@ -0,0 +1,158 @@
<script setup lang="ts">
import type { UploadFile } from 'element-plus';
import { onMounted, ref } from 'vue';
import { downloadFileFromBlob } from '@easyflow/utils';
import {
ElButton,
ElDialog,
ElMessage,
ElMessageBox,
ElUpload,
} from 'element-plus';
import { api } from '#/api/request';
import uploadIcon from '#/assets/datacenter/upload.png';
import { $t } from '#/locales';
const props = withDefaults(defineProps<BatchImportModalProps>(), {
title: 'title',
});
const emit = defineEmits(['reload']);
export interface BatchImportModalProps {
tableId: any;
title?: string;
}
// vue
onMounted(() => {});
defineExpose({
openDialog,
});
// variables
const dialogVisible = ref(false);
const downloadLoading = ref(false);
const fileList = ref<any[]>([]);
const currentFile = ref<File | null>();
const btnLoading = ref(false);
// functions
function openDialog() {
dialogVisible.value = true;
}
function closeDialog() {
fileList.value = [];
currentFile.value = null;
dialogVisible.value = false;
}
function onFileChange(uploadFile: UploadFile) {
currentFile.value = uploadFile.raw;
return false;
}
function downloadTemplate() {
downloadLoading.value = true;
api
.download(`/api/v1/datacenterTable/getTemplate?tableId=${props.tableId}`)
.then((res) => {
downloadLoading.value = false;
downloadFileFromBlob({
fileName: 'template.xlsx',
source: res,
});
});
}
function handleUpload() {
if (!currentFile.value) {
ElMessage.warning($t('datacenterTable.uploadDesc'));
return;
}
const formData = new FormData();
formData.append('file', currentFile.value);
formData.append('tableId', props.tableId);
btnLoading.value = true;
api.postFile('/api/v1/datacenterTable/importData', formData).then((res) => {
btnLoading.value = false;
if (res.errorCode === 0) {
const arr: any[] = res.data.errorRows;
let html = '';
for (const element of arr) {
html += `<p>${JSON.stringify(element)}</p><br>`;
}
closeDialog();
ElMessageBox.alert(
`<strong>${$t('datacenterTable.totalNum')}</strong>${res.data.totalCount}
<strong>${$t('datacenterTable.successNum')}</strong>${res.data.successCount}
<strong>${$t('datacenterTable.failNum')}</strong>${res.data.errorCount}<br>
<strong>${$t('datacenterTable.failList')}</strong>${html}`,
$t('datacenterTable.importComplete'),
{
confirmButtonText: $t('message.ok'),
dangerouslyUseHTMLString: true,
callback: () => {
emit('reload');
},
},
);
}
});
}
</script>
<template>
<ElDialog
v-model="dialogVisible"
draggable
:title="props.title"
:before-close="closeDialog"
:close-on-click-modal="false"
>
<ElUpload
:file-list="fileList"
drag
action="#"
accept=".xlsx,.xls,.csv"
:auto-upload="false"
:on-change="onFileChange"
:limit="1"
>
<div class="flex flex-col items-center">
<img alt="" :src="uploadIcon" class="h-12 w-12" />
<div class="text-base font-medium">
{{ $t('datacenterTable.uploadTitle') }}
</div>
<div class="desc text-[13px]">
{{ $t('datacenterTable.uploadDesc') }}
</div>
</div>
</ElUpload>
<ElButton
:disabled="downloadLoading"
type="primary"
link
@click="downloadTemplate"
>
{{ $t('datacenterTable.downloadTemplate') }}
</ElButton>
<template #footer>
<div class="dialog-footer">
<ElButton @click="closeDialog">
{{ $t('button.cancel') }}
</ElButton>
<ElButton
:disabled="btnLoading"
:loading="btnLoading"
type="primary"
@click="handleUpload"
>
{{ $t('button.confirm') }}
</ElButton>
</div>
</template>
</ElDialog>
</template>
<style scoped>
.desc {
color: var(--el-text-color-secondary);
}
</style>

View File

@@ -0,0 +1,272 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import { $t } from '@easyflow/locales';
import {
ArrowLeft,
Delete,
MoreFilled,
Plus,
Upload,
} from '@element-plus/icons-vue';
import {
ElButton,
ElDropdown,
ElDropdownItem,
ElDropdownMenu,
ElIcon,
ElImage,
ElMessage,
ElMessageBox,
ElTable,
ElTableColumn,
} from 'element-plus';
import { api } from '#/api/request';
import tableIcon from '#/assets/datacenter/table2x.png';
import PageData from '#/components/page/PageData.vue';
import PageSide from '#/components/page/PageSide.vue';
import { router } from '#/router';
import { useDictStore } from '#/store';
import BatchImportModal from '#/views/datacenter/BatchImportModal.vue';
import RecordModal from '#/views/datacenter/RecordModal.vue';
const pageDataRef = ref();
const route = useRoute();
const tableId = ref(route.query.tableId);
onMounted(() => {
initDict();
getDetailInfo(tableId.value);
getHeaders(tableId.value);
});
const detailInfo = ref<any>({});
const fieldList = ref<any[]>([]);
const headers = ref<any[]>([]);
const activeMenu = ref('2');
const recordModal = ref();
const batchImportModal = ref();
const dictStore = useDictStore();
const categoryData = [
{ key: '2', name: $t('datacenterTable.data') },
{ key: '1', name: $t('datacenterTable.structure') },
];
function initDict() {
dictStore.fetchDictionary('fieldType');
dictStore.fetchDictionary('yesOrNo');
}
function getDetailInfo(id: any) {
api.get(`/api/v1/datacenterTable/detailInfo?tableId=${id}`).then((res) => {
detailInfo.value = res.data;
fieldList.value = res.data.fields;
});
}
function getHeaders(id: any) {
api.get(`/api/v1/datacenterTable/getHeaders?tableId=${id}`).then((res) => {
headers.value = res.data;
});
}
function showDialog(row: any) {
recordModal.value.openDialog({ ...row });
}
function remove(row: any) {
ElMessageBox.confirm($t('message.deleteAlert'), $t('message.noticeTitle'), {
confirmButtonText: $t('message.ok'),
cancelButtonText: $t('message.cancel'),
type: 'warning',
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
instance.confirmButtonLoading = true;
api
.post(
`/api/v1/datacenterTable/removeValue`,
{},
{
params: {
tableId: tableId.value,
id: row.id,
},
},
)
.then((res) => {
instance.confirmButtonLoading = false;
if (res.errorCode === 0) {
ElMessage.success(res.message);
refresh();
done();
}
})
.catch(() => {
instance.confirmButtonLoading = false;
});
} else {
done();
}
},
}).catch(() => {});
}
function refresh() {
pageDataRef.value.setQuery({});
}
function openImportModal() {
batchImportModal.value.openDialog();
}
function changeTab(category: any) {
activeMenu.value = category.key;
if (category.key === '2' && pageDataRef.value) {
refresh();
}
}
</script>
<template>
<div class="bg-background-deep flex h-full flex-col gap-6 p-6">
<BatchImportModal
:table-id="tableId"
:title="$t('button.batchImport')"
ref="batchImportModal"
@reload="refresh"
/>
<RecordModal
ref="recordModal"
:form-items="headers"
:table-id="tableId"
@reload="refresh"
/>
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<ElIcon class="cursor-pointer" @click="router.back()">
<ArrowLeft />
</ElIcon>
<div class="flex items-center gap-3">
<ElImage :src="tableIcon" class="h-9 w-9 rounded-full" />
<div class="flex flex-col gap-1.5">
<div class="text-base font-medium">{{ detailInfo.tableName }}</div>
<div class="desc text-sm">{{ detailInfo.tableDesc }}</div>
</div>
</div>
</div>
<div class="flex items-center" v-if="activeMenu === '2'">
<ElButton type="primary" @click="showDialog({})">
<ElIcon class="mr-1">
<Plus />
</ElIcon>
{{ $t('button.addLine') }}
</ElButton>
<ElButton type="primary" @click="openImportModal">
<ElIcon class="mr-1">
<Upload />
</ElIcon>
{{ $t('button.batchImport') }}
</ElButton>
</div>
</div>
<div class="flex h-full max-h-[calc(100vh-191px)] gap-3">
<PageSide
label-key="name"
value-key="key"
:menus="categoryData"
default-selected="2"
@change="changeTab"
/>
<div
class="bg-background border-border flex-1 overflow-auto rounded-lg border p-5"
>
<ElTable v-show="activeMenu === '1'" :data="fieldList">
<ElTableColumn
prop="fieldName"
:label="$t('datacenterTableFields.fieldName')"
/>
<ElTableColumn
prop="fieldDesc"
:label="$t('datacenterTableFields.fieldDesc')"
/>
<ElTableColumn
prop="fieldType"
:label="$t('datacenterTableFields.fieldType')"
>
<template #default="{ row }">
{{ dictStore.getDictLabel('fieldType', row.fieldType) }}
</template>
</ElTableColumn>
<ElTableColumn
prop="required"
:label="$t('datacenterTableFields.required')"
>
<template #default="{ row }">
{{ dictStore.getDictLabel('yesOrNo', row.required) }}
</template>
</ElTableColumn>
</ElTable>
<PageData
v-show="activeMenu === '2'"
ref="pageDataRef"
page-url="/api/v1/datacenterTable/getPageData"
:extra-query-params="{ tableId }"
:page-size="10"
>
<template #default="{ pageList }">
<ElTable :data="pageList">
<ElTableColumn
v-for="item in headers"
:key="item.key"
:prop="item.key"
:label="item.title"
>
<template #default="{ row }">
<div v-if="item.fieldType === 5">
{{
1 === row[item.key] ? $t('common.yes') : $t('common.no')
}}
</div>
<div v-else-if="item.fieldType === 4">
{{ parseFloat(row[item.key]) }}
</div>
<div v-else>{{ row[item.key] }}</div>
</template>
</ElTableColumn>
<ElTableColumn
:label="$t('common.handle')"
width="90"
align="right"
>
<template #default="{ row }">
<div class="flex items-center gap-3">
<ElButton link type="primary" @click="showDialog(row)">
{{ $t('button.edit') }}
</ElButton>
<ElDropdown>
<ElButton link :icon="MoreFilled" />
<template #dropdown>
<ElDropdownMenu>
<ElDropdownItem @click="remove(row)">
<ElButton link :icon="Delete" type="danger">
{{ $t('button.delete') }}
</ElButton>
</ElDropdownItem>
</ElDropdownMenu>
</template>
</ElDropdown>
</div>
</template>
</ElTableColumn>
</ElTable>
</template>
</PageData>
</div>
</div>
</div>
</template>
<style scoped>
.desc {
color: #75808d;
}
</style>

View File

@@ -0,0 +1,175 @@
<script setup lang="ts">
import type { FormInstance } from 'element-plus';
import { markRaw, onMounted, ref } from 'vue';
import { Delete, MoreFilled, Plus } from '@element-plus/icons-vue';
import {
ElButton,
ElDropdown,
ElDropdownItem,
ElDropdownMenu,
ElMessage,
ElMessageBox,
ElTable,
ElTableColumn,
} from 'element-plus';
import { api } from '#/api/request';
import HeaderSearch from '#/components/headerSearch/HeaderSearch.vue';
import PageData from '#/components/page/PageData.vue';
import { $t } from '#/locales';
import { router } from '#/router';
import { useDictStore } from '#/store';
import DatacenterTableModal from './DatacenterTableModal.vue';
onMounted(() => {
initDict();
});
const pageDataRef = ref();
const saveDialog = ref();
const dictStore = useDictStore();
const headerButtons = [
{
key: 'create',
text: $t('button.add'),
icon: markRaw(Plus),
type: 'primary',
data: { action: 'create' },
permission: '/api/v1/datacenterTable/save',
},
];
function initDict() {
dictStore.fetchDictionary('dataStatus');
}
const handleSearch = (params: string) => {
pageDataRef.value.setQuery({ tableName: params, isQueryOr: true });
};
function reset(formEl?: FormInstance) {
formEl?.resetFields();
pageDataRef.value.setQuery({});
}
function showDialog(row: any) {
saveDialog.value.openDialog({ ...row });
}
function remove(row: any) {
ElMessageBox.confirm($t('message.deleteAlert'), $t('message.noticeTitle'), {
confirmButtonText: $t('message.ok'),
cancelButtonText: $t('message.cancel'),
type: 'warning',
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
instance.confirmButtonLoading = true;
api
.get(`/api/v1/datacenterTable/removeTable?tableId=${row.id}`)
.then((res) => {
instance.confirmButtonLoading = false;
if (res.errorCode === 0) {
ElMessage.success(res.message);
reset();
done();
}
})
.catch(() => {
instance.confirmButtonLoading = false;
});
} else {
done();
}
},
}).catch(() => {});
}
function toDetailPage(row: any) {
router.push({
name: 'TableDetail',
query: {
tableId: row.id,
},
});
}
</script>
<template>
<div class="flex h-full flex-col gap-6 p-6">
<DatacenterTableModal ref="saveDialog" @reload="reset" />
<HeaderSearch
:buttons="headerButtons"
@search="handleSearch"
@button-click="showDialog({})"
/>
<div class="bg-background border-border flex-1 rounded-lg border p-5">
<PageData
ref="pageDataRef"
page-url="/api/v1/datacenterTable/page"
:page-size="10"
>
<template #default="{ pageList }">
<ElTable :data="pageList" border>
<ElTableColumn
prop="tableName"
:label="$t('datacenterTable.tableName')"
>
<template #default="{ row }">
{{ row.tableName }}
</template>
</ElTableColumn>
<ElTableColumn
prop="tableDesc"
:label="$t('datacenterTable.tableDesc')"
>
<template #default="{ row }">
{{ row.tableDesc }}
</template>
</ElTableColumn>
<ElTableColumn
prop="created"
:label="$t('datacenterTable.created')"
>
<template #default="{ row }">
{{ row.created }}
</template>
</ElTableColumn>
<ElTableColumn
:label="$t('common.handle')"
width="140"
align="right"
>
<template #default="{ row }">
<div class="flex items-center gap-3">
<div class="flex items-center">
<ElButton link type="primary" @click="toDetailPage(row)">
{{ $t('button.view') }}
</ElButton>
<ElButton link type="primary" @click="showDialog(row)">
{{ $t('button.edit') }}
</ElButton>
</div>
<ElDropdown>
<ElButton link :icon="MoreFilled" />
<template #dropdown>
<ElDropdownMenu>
<ElDropdownItem @click="remove(row)">
<ElButton link :icon="Delete" type="danger">
{{ $t('button.delete') }}
</ElButton>
</ElDropdownItem>
</ElDropdownMenu>
</template>
</ElDropdown>
</div>
</template>
</ElTableColumn>
</ElTable>
</template>
</PageData>
</div>
</div>
</template>
<style scoped></style>

View File

@@ -0,0 +1,280 @@
<script setup lang="ts">
import type { FormInstance } from 'element-plus';
import { onMounted, ref, watch } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import {
ElButton,
ElDialog,
ElForm,
ElFormItem,
ElIcon,
ElInput,
ElMessage,
ElMessageBox,
ElOption,
ElSelect,
ElTable,
ElTableColumn,
} from 'element-plus';
import { api } from '#/api/request';
import { $t } from '#/locales';
const emit = defineEmits(['reload']);
// vue
onMounted(() => {
getFieldType();
getYesOrNo();
});
defineExpose({
openDialog,
});
const saveForm = ref<FormInstance>();
// variables
const dialogVisible = ref(false);
const isAdd = ref(true);
const entity = ref<any>({
deptId: '',
tableName: '',
tableDesc: '',
actualTable: '',
status: '',
options: '',
});
const btnLoading = ref(false);
const rules = ref({
tableName: [
{ required: true, message: $t('message.required'), trigger: 'blur' },
{
pattern: /^[a-z][a-z0-9_]*$/,
message: $t('datacenterTable.nameRegx'),
},
],
fields: [
{
required: true,
validator: (_: any, value: any, callback: any) => {
if (!value || value.length === 0) {
callback(new Error($t('datacenterTable.noFieldError')));
} else {
// 检查字段数组中的fieldName和fieldDesc字段
value.forEach((field: any) => {
if (!field.fieldName || !field.fieldDesc) {
callback(new Error($t('datacenterTable.fieldInfoError')));
}
if (!/^[a-z][a-z0-9_]*$/.test(field.fieldName)) {
callback(new Error($t('datacenterTable.nameRegx')));
}
});
callback();
}
},
trigger: 'blur',
},
],
});
const fieldsData = ref();
const removeFields = ref<any[]>([]);
const loadFields = ref(false);
const fieldTypes = ref<any>([]);
const yesOrNoDict = ref<any>([]);
watch(
() => fieldsData.value,
(newVal) => {
entity.value.fields = newVal;
},
{ deep: true },
);
// functions
function getDetailInfo(tableId: any) {
loadFields.value = true;
api
.get(`/api/v1/datacenterTable/detailInfo?tableId=${tableId}`)
.then((res) => {
loadFields.value = false;
fieldsData.value = res.data.fields;
});
}
function openDialog(row: any) {
fieldsData.value = [];
removeFields.value = [];
if (row.id) {
getDetailInfo(row.id);
isAdd.value = false;
}
entity.value = row;
dialogVisible.value = true;
}
function save() {
saveForm.value?.validate((valid) => {
if (valid) {
if (fieldsData.value.length === 0) {
ElMessage.error($t('message.required'));
return;
}
const obj = {
...entity.value,
fields: [...fieldsData.value, ...removeFields.value],
};
btnLoading.value = true;
api
.post('/api/v1/datacenterTable/saveTable', obj)
.then((res) => {
btnLoading.value = false;
if (res.errorCode === 0) {
ElMessage.success(res.message);
emit('reload');
closeDialog();
}
})
.catch(() => {
btnLoading.value = false;
});
}
});
}
function closeDialog() {
saveForm.value?.resetFields();
isAdd.value = true;
entity.value = {};
dialogVisible.value = false;
}
function addField() {
fieldsData.value.push({
fieldName: '',
fieldDesc: '',
fieldType: 1,
required: 0,
handleDelete: false,
rowKey: Date.now().toString(),
});
}
function deleteField(row: any, $index: number) {
ElMessageBox.confirm($t('message.deleteAlert'), $t('message.noticeTitle'), {
confirmButtonText: $t('message.ok'),
cancelButtonText: $t('message.cancel'),
type: 'warning',
beforeClose: (action, _, done) => {
if (action === 'confirm') {
if (row.id) {
row.handleDelete = true;
removeFields.value.push(row);
}
fieldsData.value.splice($index, 1);
done();
} else {
done();
}
},
}).catch(() => {});
}
function getFieldType() {
api.get('/api/v1/dict/items/fieldType').then((res) => {
fieldTypes.value = res.data;
});
}
function getYesOrNo() {
api.get('/api/v1/dict/items/yesOrNo').then((res) => {
yesOrNoDict.value = res.data;
});
}
</script>
<template>
<ElDialog
v-model="dialogVisible"
draggable
:title="isAdd ? $t('button.add') : $t('button.edit')"
:before-close="closeDialog"
:close-on-click-modal="false"
width="800px"
>
<ElForm
label-width="100px"
ref="saveForm"
:model="entity"
status-icon
:rules="rules"
>
<ElFormItem prop="tableName" :label="$t('datacenterTable.tableName')">
<ElInput :disabled="!isAdd" v-model.trim="entity.tableName" />
</ElFormItem>
<ElFormItem prop="tableDesc" :label="$t('datacenterTable.tableDesc')">
<ElInput v-model.trim="entity.tableDesc" />
</ElFormItem>
<ElFormItem prop="fields" label-width="0">
<div v-loading="loadFields" class="w-full">
<ElTable :data="fieldsData">
<ElTableColumn :label="$t('datacenterTable.fieldName')">
<template #default="{ row }">
<ElInput v-model.trim="row.fieldName" />
</template>
</ElTableColumn>
<ElTableColumn :label="$t('datacenterTable.fieldDesc')">
<template #default="{ row }">
<ElInput v-model.trim="row.fieldDesc" />
</template>
</ElTableColumn>
<ElTableColumn :label="$t('datacenterTable.fieldType')">
<template #default="{ row }">
<ElSelect v-model.trim="row.fieldType" :disabled="!!row.id">
<ElOption
v-for="item in fieldTypes"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElSelect>
</template>
</ElTableColumn>
<ElTableColumn :label="$t('datacenterTable.required')">
<template #default="{ row }">
<ElSelect v-model.trim="row.required">
<ElOption
v-for="item in yesOrNoDict"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElSelect>
</template>
</ElTableColumn>
<ElTableColumn :label="$t('common.handle')" width="80">
<template #default="{ row, $index }">
<ElButton link type="danger" @click="deleteField(row, $index)">
{{ $t('button.delete') }}
</ElButton>
</template>
</ElTableColumn>
</ElTable>
<div class="mt-3">
<ElButton plain type="primary" @click="addField">
<ElIcon class="mr-1">
<Plus />
</ElIcon>
{{ $t('button.add') }}
</ElButton>
</div>
</div>
</ElFormItem>
</ElForm>
<template #footer>
<ElButton @click="closeDialog">
{{ $t('button.cancel') }}
</ElButton>
<ElButton
type="primary"
@click="save"
:loading="btnLoading"
:disabled="btnLoading"
>
{{ $t('button.save') }}
</ElButton>
</template>
</ElDialog>
</template>
<style scoped></style>

View File

@@ -0,0 +1,154 @@
<script setup lang="ts">
import type { FormInstance } from 'element-plus';
import { onMounted, ref } from 'vue';
import {
ElButton,
ElDatePicker,
ElDialog,
ElForm,
ElFormItem,
ElInput,
ElInputNumber,
ElMessage,
} from 'element-plus';
import { api } from '#/api/request';
import DictSelect from '#/components/dict/DictSelect.vue';
import { $t } from '#/locales';
const props = withDefaults(defineProps<RecordModalProps>(), {});
const emit = defineEmits(['reload']);
// vue
export interface RecordModalProps {
formItems: any[];
tableId: any;
}
onMounted(() => {});
defineExpose({
openDialog,
});
const saveForm = ref<FormInstance>();
// variables
const dialogVisible = ref(false);
const isAdd = ref(true);
const entity = ref<any>({});
const btnLoading = ref(false);
const rules = ref({});
// functions
function openDialog(row: any) {
if (row.id) {
isAdd.value = false;
}
entity.value = row;
dialogVisible.value = true;
}
function save() {
saveForm.value?.validate((valid) => {
if (valid) {
const data: Record<string, any> = {};
for (const formItem of props.formItems) {
data[formItem.key] = entity.value[formItem.key];
}
data.tableId = props.tableId;
data.id = entity.value.id;
btnLoading.value = true;
api
.postForm('/api/v1/datacenterTable/saveValue', data)
.then((res) => {
btnLoading.value = false;
if (res.errorCode === 0) {
ElMessage.success(res.message);
emit('reload');
closeDialog();
}
})
.catch(() => {
btnLoading.value = false;
});
}
});
}
function closeDialog() {
saveForm.value?.resetFields();
isAdd.value = true;
entity.value = {};
dialogVisible.value = false;
}
</script>
<template>
<ElDialog
v-model="dialogVisible"
draggable
:title="isAdd ? $t('button.add') : $t('button.edit')"
:before-close="closeDialog"
:close-on-click-modal="false"
width="800px"
>
<ElForm
label-width="100px"
ref="saveForm"
:model="entity"
status-icon
:rules="rules"
>
<ElFormItem
v-for="item in props.formItems"
:rules="
item.required
? [
{
required: true,
message: `${item.title}${$t('message.notEmpty')}`,
},
]
: []
"
:key="item.key"
:prop="item.key"
:label="item.title"
>
<ElInput v-if="item.fieldType === 1" v-model.trim="entity[item.key]" />
<ElInputNumber
v-if="item.fieldType === 2"
v-model.number="entity[item.key]"
:precision="0"
/>
<ElDatePicker
v-if="item.fieldType === 3"
v-model="entity[item.key]"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
/>
<ElInputNumber
v-if="item.fieldType === 4"
v-model="entity[item.key]"
:precision="2"
/>
<DictSelect
v-if="item.fieldType === 5"
v-model="entity[item.key]"
dict-code="yesOrNo"
/>
</ElFormItem>
</ElForm>
<template #footer>
<ElButton @click="closeDialog">
{{ $t('button.cancel') }}
</ElButton>
<ElButton
type="primary"
@click="save"
:loading="btnLoading"
:disabled="btnLoading"
>
{{ $t('button.save') }}
</ElButton>
</template>
</ElDialog>
</template>
<style scoped></style>