<script setup lang="ts">
|
import { computed, ref, watch, nextTick, onMounted } from 'vue';
|
import { Modal, message, FormItem } from 'ant-design-vue';
|
import { $t } from '@vben/locales';
|
import { useVbenForm } from '#/adapter/form';
|
import { drawerSchema } from './data';
|
import FcDesigner from '@form-create/designer';
|
import { menuList } from '../../../api/system/menu';
|
import { listToTree, addFullName, getPopupContainer } from '@vben/utils';
|
import { pageAdd, pageUpdate, pageInfo } from '#/api/tool/page-designer';
|
|
interface ModalProps {
|
id?: number | string;
|
update: boolean;
|
}
|
|
const emit = defineEmits<{ reload: [] }>();
|
|
const isUpdate = ref(false);
|
const title = computed(() => {
|
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
});
|
|
const [BasicForm, formApi] = useVbenForm({
|
commonConfig: {
|
componentProps: {
|
class: 'w-full',
|
},
|
formItemClass: 'col-span-1',
|
labelWidth: 90,
|
},
|
schema: drawerSchema(),
|
showDefaultActions: false,
|
wrapperClass: 'grid-cols-5',
|
});
|
|
const designer = ref();
|
const selectedFields = ref([]); // 多选框选中的字段key
|
const fieldOptions = ref([]); // 设计区所有字段
|
const modalVisible = ref(false);
|
const modalLoading = ref(false);
|
const currentEditId = ref<string | number>(''); // 当前编辑的ID
|
|
// 打开弹窗
|
const open = async (params: ModalProps = { update: false }) => {
|
try {
|
modalVisible.value = true;
|
modalLoading.value = true;
|
isUpdate.value = params.update;
|
currentEditId.value = params.id || ''; // 保存当前编辑的ID
|
await setupPageSelect();
|
|
if (params.id) {
|
await formApi.setFieldValue('menuId', params.id);
|
if (params.update) {
|
// 获取详情数据
|
const record = await pageInfo(params.id);
|
console.log('编辑数据:', record);
|
|
// 设置基础表单数据
|
await formApi.setValues({
|
name: record.name,
|
menuId: record.menuId || record.parentId || params.id, // 优先使用menuId,其次parentId
|
status: record.status,
|
remark: record.remark,
|
actionsFunc: record.actionsFunc ? JSON.parse(record.actionsFunc) : ['add', 'edit', 'delete', 'query']
|
});
|
|
// 加载表单设计数据
|
if (record.formJson) {
|
try {
|
const formRule = JSON.parse(record.formJson);
|
console.log('设计器规则:', formRule);
|
designer.value.setRule(formRule);
|
|
// 更新字段选项
|
await nextTick();
|
updateFieldOptions();
|
|
// 恢复选中的字段
|
if (record.showColumn) {
|
selectedFields.value = JSON.parse(record.showColumn);
|
console.log('恢复选中字段:', selectedFields.value);
|
}
|
} catch (e) {
|
console.error('加载表单设计数据失败:', e);
|
message.error('加载表单设计数据失败');
|
}
|
}
|
}
|
} else {
|
// 新增时重置数据
|
designer.value?.setRule([]);
|
selectedFields.value = [];
|
await formApi.resetForm();
|
}
|
} catch (error) {
|
console.error('打开弹窗失败:', error);
|
message.error('加载数据失败');
|
} finally {
|
modalLoading.value = false;
|
}
|
};
|
const close = () => {
|
modalVisible.value = false;
|
};
|
|
defineExpose({ open, close });
|
|
async function setupPageSelect() {
|
// 获取菜单数据
|
const menuArray = await menuList();
|
// 过滤掉按钮类型
|
const filteredList = menuArray.filter(item => item.menuType !== 'F' && item.menuType !== 'C');
|
// 支持i18n
|
filteredList.forEach(item => { item.menuName = $t(item.menuName); });
|
// 转为树结构
|
const menuTree = listToTree(filteredList, { id: 'menuId', pid: 'parentId' });
|
// 加根节点
|
const fullMenuTree = [
|
{
|
menuId: 0,
|
menuName: $t('menu.root'),
|
children: menuTree,
|
},
|
];
|
// 生成全路径名
|
addFullName(fullMenuTree, 'menuName', ' / ');
|
|
formApi.updateSchema([
|
{
|
componentProps: {
|
fieldNames: {
|
label: 'menuName',
|
value: 'menuId',
|
children: 'children'
|
},
|
getPopupContainer,
|
listHeight: 300,
|
showSearch: true,
|
treeData: fullMenuTree,
|
treeDefaultExpandAll: false,
|
treeDefaultExpandedKeys: [0],
|
treeLine: { showLeafIcon: false },
|
treeNodeFilterProp: 'menuName',
|
treeNodeLabelProp: 'fullName',
|
},
|
fieldName: 'menuId',
|
},
|
]);
|
}
|
|
|
// 同步所有字段到选中状态
|
const syncAllFields = () => {
|
// 获取表单组件的规则描述
|
const formDesc = designer.value?.getFormDescription?.();
|
console.log('表单组件描述:', formDesc);
|
|
if (!formDesc || !Array.isArray(formDesc)) {
|
message.warning('暂无设计数据');
|
return;
|
}
|
|
// 提取字段信息
|
const allFields = formDesc
|
.filter(item => item && item.field && item.title)
|
.map(item => ({
|
title: item.title,
|
field: item.field
|
}));
|
|
console.log('提取的字段:', allFields);
|
|
if (allFields.length === 0) {
|
message.warning('未找到可用字段');
|
return;
|
}
|
|
// 更新字段选项
|
fieldOptions.value = allFields.map(item => ({
|
label: item.title,
|
value: item.field
|
}));
|
|
// 选中所有字段
|
selectedFields.value = allFields.map(item => item.field);
|
message.success(`已同步 ${allFields.length} 个字段`);
|
};
|
|
// 处理设计器变化
|
const handleDesignerChange = () => {
|
console.log('设计器内容变化');
|
nextTick(() => {
|
updateFieldOptions();
|
});
|
};
|
|
// 当设计器内容变化时更新字段选项
|
const updateFieldOptions = () => {
|
console.log('updateFieldOptions');
|
console.log('designer.value', designer.value);
|
|
// 获取表单组件的规则描述
|
const formDesc = designer.value?.getFormDescription?.();
|
if (!formDesc || !Array.isArray(formDesc)) return;
|
|
const fields = formDesc
|
.filter(item => item && item.field && item.title)
|
.map(item => ({
|
title: item.title,
|
field: item.field
|
}));
|
|
fieldOptions.value = fields.map(item => ({
|
label: item.title,
|
value: item.field
|
}));
|
|
console.log('更新后的字段选项:', fieldOptions.value);
|
};
|
|
// 监听设计器内容变化
|
watch(() => modalVisible.value, (val) => {
|
if (val) {
|
nextTick(() => updateFieldOptions());
|
}
|
});
|
|
async function handleOk() {
|
try {
|
modalLoading.value = true;
|
const { valid } = await formApi.validate();
|
if (!valid) {
|
return;
|
}
|
const data = await formApi.getValues();
|
|
// 如果是编辑模式,添加id字段
|
if (isUpdate.value) {
|
data.id = currentEditId.value;
|
}
|
|
// 获取表单设计 JSON
|
data.formJson = designer.value.getJson();
|
// 添加选中的字段
|
data.showColumn = JSON.stringify(selectedFields.value);
|
// 转换启用功能为JSON字符串
|
data.actionsFunc = JSON.stringify(data.actionsFunc);
|
|
// 同步一次字段多选
|
updateFieldOptions();
|
await (isUpdate.value ? pageUpdate(data) : pageAdd(data));
|
emit('reload');
|
close();
|
message.success('保存成功');
|
} catch (error) {
|
console.error(error);
|
} finally {
|
modalLoading.value = false;
|
}
|
}
|
|
function handleCancel() {
|
close();
|
}
|
</script>
|
|
<template>
|
<a-modal
|
v-model:open="modalVisible"
|
:title="title"
|
:width="'80vw'"
|
:confirm-loading="modalLoading"
|
@ok="handleOk"
|
@cancel="handleCancel"
|
:bodyStyle="{ padding: '24px', minHeight: '60vh' }"
|
destroyOnClose
|
wrapClassName="page-designer-modal"
|
>
|
<template #closeIcon>
|
<span></span>
|
</template>
|
<BasicForm />
|
<div style="margin-top: 16px;">
|
<FcDesigner
|
ref="designer"
|
@update="handleDesignerChange"
|
@change="handleDesignerChange"
|
@add-rule="handleDesignerChange"
|
@remove-rule="handleDesignerChange"
|
|
/>
|
<div style="margin-top: 8px; display: flex; justify-content: flex-end;">
|
<a-button type="primary" ghost @click="syncAllFields">
|
同步设计字段到表格
|
</a-button>
|
</div>
|
</div>
|
<FormItem label="表格字段" style="margin-top: 24px;">
|
<a-checkbox-group
|
v-model:value="selectedFields"
|
:options="fieldOptions"
|
style="width:100%;display:flex;flex-wrap:wrap;gap:8px"
|
/>
|
</FormItem>
|
<template #empty>
|
<div style="padding: 32px 0; color: #999; text-align: center;">
|
暂无数据
|
</div>
|
</template>
|
</a-modal>
|
</template>
|
|
<style scoped>
|
.page-designer-modal .ant-modal {
|
max-width: 1200px;
|
}
|
|
|
</style>
|