<script lang="ts" setup>
|
import type { FormSchema } from '@jnpf/ui/form';
|
|
import { computed, nextTick, reactive, toRefs } from 'vue';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { BasicForm, useForm } from '@jnpf/ui/form';
|
import { BasicModal, useModalInner } from '@jnpf/ui/modal';
|
import { formValidate } from '@jnpf/utils';
|
|
import { getDataReportSelector } from '#/api/onlineDev/dataReport';
|
import { getDataVSelector } from '#/api/onlineDev/dataV';
|
import { getPortalSelector } from '#/api/onlineDev/portal';
|
import { getReportSelector } from '#/api/onlineDev/report';
|
import { getVisualDevSelector } from '#/api/onlineDev/visualDev';
|
import { create, getInfo, getMenuSelector, update } from '#/api/system/menu';
|
import { getDictionaryType } from '#/api/systemData/dictionary';
|
import { getTreeList as getFlowSelector } from '#/api/workFlow/template';
|
import { $t } from '#/locales';
|
import { useBaseStore } from '#/store';
|
import { colorPredefine } from '#/utils/constants';
|
|
interface State {
|
id: string;
|
category: string;
|
dataForm: any;
|
featureWebData: any[];
|
sysFormData: any[];
|
dictionaryData: any[];
|
dataReportData: any[];
|
reportData: any[];
|
screenData: any[];
|
portalData: any[];
|
flowData: any[];
|
tempData: any[];
|
moduleIdKey: number;
|
}
|
|
const emit = defineEmits(['register', 'reload']);
|
const state = reactive<State>({
|
id: '',
|
category: '',
|
dataForm: {
|
type: '',
|
linkTarget: '',
|
propertyJson: {
|
moduleId: '',
|
iconBackgroundColor: '',
|
isTree: 0,
|
},
|
},
|
featureWebData: [],
|
sysFormData: [],
|
dictionaryData: [],
|
dataReportData: [],
|
reportData: [],
|
screenData: [],
|
portalData: [],
|
flowData: [],
|
tempData: [],
|
moduleIdKey: 0,
|
});
|
const { dataForm, tempData, moduleIdKey } = toRefs(state);
|
const appTypeData: any[] = [
|
{ id: 1, fullName: '目录' },
|
{ id: 11, fullName: '表单回传' },
|
// { id: 2, fullName: '页面' },
|
{ id: 3, fullName: '在线表单' },
|
{ id: 9, fullName: '流程' },
|
{ id: 10, fullName: '报表' },
|
{ id: 5, fullName: '报表(原)' },
|
{ id: 8, fullName: '门户' },
|
{ id: 7, fullName: '外链' },
|
];
|
const typeData: any[] = [
|
{ id: 1, fullName: '目录' },
|
{ id: 11, fullName: '表单回传' },
|
{ id: 2, fullName: '页面' },
|
{ id: 3, fullName: '在线表单' },
|
{ id: 9, fullName: '流程' },
|
{ id: 4, fullName: '字典' },
|
{ id: 10, fullName: '报表' },
|
{ id: 5, fullName: '报表(原)' },
|
{ id: 6, fullName: '大屏' },
|
{ id: 8, fullName: '门户' },
|
{ id: 7, fullName: '外链' },
|
];
|
const schemas: FormSchema[] = [
|
{
|
field: 'parentId',
|
label: '上级',
|
component: 'TreeSelect',
|
componentProps: { placeholder: '请选择', onChange: onParentIdChange },
|
rules: [{ required: true, message: '必填', trigger: 'change' }],
|
},
|
{
|
field: 'fullName',
|
label: '名称',
|
component: 'Input',
|
componentProps: { placeholder: '请输入', maxlength: 50 },
|
rules: [{ required: true, message: '必填', trigger: 'blur' }],
|
},
|
{
|
field: 'enCode',
|
label: '编码',
|
component: 'Input',
|
componentProps: { placeholder: '请输入', maxlength: 50 },
|
rules: [
|
{ required: true, message: '必填', trigger: 'blur' },
|
{ validator: formValidate('enCode', '只能输入英文、数字和小数点且小数点不能放在首尾'), trigger: 'blur' },
|
],
|
},
|
{
|
field: 'icon',
|
label: '图标',
|
component: 'Input',
|
slot: 'icon',
|
componentProps: { placeholder: '请选择' },
|
rules: [{ required: true, message: '必填', trigger: 'change' }],
|
},
|
{
|
field: 'type',
|
label: '类型',
|
component: 'Select',
|
componentProps: {
|
placeholder: '请选择',
|
onChange: onTypeChange,
|
},
|
rules: [{ required: true, trigger: 'change', message: '必填', type: 'number' }],
|
},
|
{
|
ifShow: ({ values }) =>
|
values.type && (![1, 6, 7].includes(values.type) || (values.type == 7 && state.dataForm.linkTarget == '_self')) && state.category == 'Web',
|
field: 'urlAddress',
|
label: '路由地址',
|
component: 'Input',
|
componentProps: { placeholder: '请输入', addonBefore: '/' },
|
rules: [{ required: true, message: '必填', trigger: 'blur' }],
|
},
|
{
|
ifShow: ({ values }) => values.type == 2 || values.type == 7,
|
field: 'pageAddress',
|
label: '页面地址',
|
component: 'Input',
|
slot: 'pageAddress',
|
componentProps: { placeholder: '请输入' },
|
rules: [{ required: true, message: '必填', trigger: 'blur' }],
|
},
|
{
|
ifShow: ({ values }) => [3, 4, 5, 6, 8, 9, 10, 11].includes(values.type),
|
field: 'moduleId',
|
label: '关联',
|
component: 'TreeSelect',
|
slot: 'moduleId',
|
rules: [{ required: true, message: '必填', trigger: 'change' }],
|
},
|
{
|
field: 'sortCode',
|
label: '排序',
|
component: 'InputNumber',
|
defaultValue: 0,
|
componentProps: { min: '0', max: '999999', placeholder: '请输入' },
|
},
|
{
|
field: 'enabledMark',
|
label: '状态',
|
component: 'Switch',
|
defaultValue: 1,
|
},
|
{
|
field: 'description',
|
label: '说明',
|
component: 'Textarea',
|
componentProps: { rows: 4, placeholder: '请输入' },
|
},
|
];
|
const { createMessage } = useMessage();
|
const baseStore = useBaseStore();
|
const [registerForm, { setFieldsValue, validate, clearValidate, resetFields, updateSchema, getFieldsValue }] = useForm({ labelWidth: 90, schemas });
|
const [registerModal, { closeModal, changeLoading, changeOkLoading }] = useModalInner(init);
|
|
const getTitle = computed(() => (state.id ? $t('common.editText') : $t('common.addText')));
|
|
function init(data) {
|
resetFields();
|
state.id = data.id;
|
state.category = data.category;
|
state.featureWebData = [];
|
state.sysFormData = [];
|
state.dictionaryData = [];
|
state.dataReportData = [];
|
state.reportData = [];
|
state.screenData = [];
|
state.portalData = [];
|
state.flowData = [];
|
setFieldsValue({ pageAddress: '' });
|
const typeDataList = data.isSystem ? typeData.filter((o) => [1, 2, 7].includes(o.id)) : typeData.filter((o) => o.id != 2);
|
updateSchema({ field: 'type', componentProps: { options: state.category === 'App' ? appTypeData : typeDataList } });
|
getMenuSelectorList(state.category, state.id);
|
if (data.parentId) setFieldsValue({ parentId: data.parentId });
|
if (state.id) {
|
changeLoading(true);
|
getInfo(state.id).then((res) => {
|
const data = res.data;
|
const propertyJson = data.propertyJson ? JSON.parse(data.propertyJson) : null;
|
data.propertyJson = propertyJson || { moduleId: '', iconBackgroundColor: '' };
|
data.moduleId = data.propertyJson.moduleId;
|
const menuType = data.type;
|
if ([2, 3, 4, 9].includes(menuType)) {
|
data.isButtonAuthorize = 1;
|
data.isColumnAuthorize = 1;
|
data.isFormAuthorize = 1;
|
data.isDataAuthorize = 1;
|
}
|
data.oldPageAddress = res.data.pageAddress;
|
handleHelp(data.type);
|
switchType(menuType);
|
state.dataForm = data;
|
setFieldsValue(data);
|
changeLoading(false);
|
});
|
}
|
}
|
async function handleSubmit() {
|
const values = await validate();
|
if (!values) return;
|
changeOkLoading(true);
|
const menuEnCode = values.enCode.replace('.', '');
|
const moduleId = values.moduleId;
|
state.dataForm.propertyJson.moduleId = moduleId;
|
if (state.category === 'Web') {
|
if (values.type == 3 || values.type == 9) values.pageAddress = `model/${menuEnCode}`; // 表单、流程
|
if (values.type == 4) values.pageAddress = `dictionary/${menuEnCode}`; // 字典
|
if (values.type == 5) values.pageAddress = `dataReport/${menuEnCode}`; // 报表(原)
|
if (values.type == 10) values.pageAddress = `report/${menuEnCode}`; // 报表
|
if (values.type == 6) values.pageAddress = `dataScreen/${menuEnCode}`; // 大屏
|
if (values.type == 8) values.pageAddress = `portal/${menuEnCode}`; // 门户
|
} else {
|
if (values.type == 3 || values.type == 9) values.pageAddress = `/pages/apply/dynamicModel/index?id=${moduleId}`;
|
if (values.type == 5 || values.type == 10 || values.type == 8) values.pageAddress = menuEnCode;
|
values.urlAddress = values.pageAddress;
|
}
|
const query = {
|
...state.dataForm,
|
...values,
|
category: state.category,
|
propertyJson: JSON.stringify(state.dataForm.propertyJson),
|
linkTarget: state.dataForm.linkTarget,
|
id: state.id,
|
};
|
const formMethod = state.id ? update : create;
|
formMethod(query)
|
.then((res) => {
|
createMessage.success(res.msg);
|
changeOkLoading(false);
|
closeModal();
|
setTimeout(() => {
|
emit('reload');
|
}, 100);
|
})
|
.catch(() => {
|
changeOkLoading(false);
|
});
|
}
|
function onTypeChange(val) {
|
// 重置关联下拉框的值及链接处理
|
setFieldsValue({ moduleId: '' });
|
clearValidate();
|
state.moduleIdKey = Date.now();
|
const menuId = state.id;
|
if (menuId) {
|
state.dataForm.pageAddress = '';
|
setFieldsValue({ pageAddress: '' });
|
}
|
if ([2, 3, 4, 9, 11].includes(val)) {
|
state.dataForm.isButtonAuthorize = 1;
|
state.dataForm.isColumnAuthorize = 1;
|
state.dataForm.isFormAuthorize = 1;
|
state.dataForm.isDataAuthorize = 1;
|
} else {
|
state.dataForm.isButtonAuthorize = 0;
|
state.dataForm.isColumnAuthorize = 0;
|
state.dataForm.isFormAuthorize = 0;
|
state.dataForm.isDataAuthorize = 0;
|
}
|
state.dataForm.linkTarget = val == 6 ? '_blank' : '_self';
|
handleHelp(val);
|
switchType(val);
|
}
|
function handleHelp(val) {
|
updateSchema([{ field: 'pageAddress', helpMessage: val === 7 ? '地址以http://或https://为开头' : '' }]);
|
}
|
function onParentIdChange(val) {
|
if (state.category !== 'App') return;
|
const values = getFieldsValue();
|
let tempData: any[] = [];
|
if (val === '-1') {
|
tempData = appTypeData.filter((o) => o.id == 1);
|
if (values.type && values.type != 1) setFieldsValue({ type: '' });
|
} else {
|
tempData = appTypeData;
|
}
|
updateSchema({ field: 'type', componentProps: { options: tempData } });
|
}
|
function onModuleIdChange(_val, item) {
|
const values = getFieldsValue();
|
if ([3, 11].includes(values.type)) state.dataForm.propertyJson.webType = item.webType;
|
if (values.type == 4) state.dataForm.propertyJson.isTree = item.isTree;
|
if (values.type == 11) setFieldsValue({ pageAddress: state.category === 'Web' ? item.webAddress : item.appAddress });
|
}
|
function getMenuSelectorList(category, id = '0') {
|
getMenuSelector({ category }, id).then((res) => {
|
const topItem = {
|
fullName: '顶级节点',
|
hasChildren: true,
|
id: '-1',
|
children: res.data.list,
|
};
|
updateSchema({ field: 'parentId', componentProps: { options: [topItem] } });
|
});
|
}
|
function switchType(val) {
|
if (val == 3) fetchFeatureList();
|
if (val == 4) fetchDictionaryType();
|
if (val == 5) fetchDataReportList();
|
if (val == 10) fetchReportList();
|
if (val == 6) fetchDataVList();
|
if (val == 8) fetchPortalList();
|
if (val == 9) fetchFlowList();
|
if (val == 11) fetchSysFormList();
|
}
|
function fetchFeatureList() {
|
if (!state.featureWebData.length) {
|
getVisualDevSelector({ type: 1, isRelease: 1 }).then((res) => {
|
state.featureWebData = res.data.list;
|
state.tempData = state.featureWebData;
|
});
|
return;
|
}
|
state.tempData = state.featureWebData;
|
}
|
function fetchSysFormList() {
|
if (!state.sysFormData.length) {
|
getVisualDevSelector({ type: 2, isRelease: 1 }).then((res) => {
|
state.sysFormData = res.data.list;
|
state.tempData = state.sysFormData;
|
});
|
return;
|
}
|
state.tempData = state.sysFormData;
|
}
|
function fetchDictionaryType() {
|
if (!state.dictionaryData.length) {
|
getDictionaryType().then((res) => {
|
state.dictionaryData = res.data.list;
|
state.tempData = state.dictionaryData;
|
});
|
return;
|
}
|
state.tempData = state.dictionaryData;
|
}
|
async function fetchDataReportList() {
|
if (!state.dataReportData.length) {
|
const data = (await baseStore.getDictionaryData('businessType')) as any;
|
const ReportSortTypeList = data;
|
getDataReportSelector().then((res) => {
|
const dataReportData = res.data.list;
|
state.dataReportData = ReportSortTypeList;
|
nextTick(() => {
|
for (let i = 0; i < state.dataReportData.length; i++) {
|
const child = dataReportData.filter((o) => state.dataReportData[i].id === o.categoryId);
|
state.dataReportData[i].children = child;
|
state.dataReportData[i].hasChildren = !!child?.length;
|
}
|
state.dataReportData = state.dataReportData.filter((o) => o.children.length);
|
state.tempData = state.dataReportData;
|
});
|
});
|
return;
|
}
|
state.tempData = state.dataReportData;
|
}
|
async function fetchReportList() {
|
if (!state.reportData.length) {
|
getReportSelector().then((res) => {
|
state.reportData = res.data.list;
|
state.tempData = state.reportData;
|
});
|
return;
|
}
|
state.tempData = state.reportData;
|
}
|
function fetchDataVList() {
|
if (!state.screenData.length) {
|
getDataVSelector().then((res) => {
|
state.screenData = res.data.list;
|
state.tempData = state.screenData;
|
});
|
return;
|
}
|
state.tempData = state.screenData;
|
}
|
function fetchPortalList() {
|
if (!state.portalData.length) {
|
getPortalSelector().then((res) => {
|
state.portalData = res.data.list.filter((o) => o.children && o.children.length);
|
state.tempData = state.portalData;
|
});
|
return;
|
}
|
state.tempData = state.portalData;
|
}
|
function fetchFlowList() {
|
if (!state.flowData.length) {
|
getFlowSelector('2').then((res) => {
|
state.flowData = res.data.list.filter((o) => o.children && o.children.length);
|
state.tempData = state.flowData;
|
});
|
return;
|
}
|
state.tempData = state.flowData;
|
}
|
</script>
|
<template>
|
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" destroy-on-close>
|
<BasicForm @register="registerForm">
|
<template #icon="{ model, field }">
|
<a-row type="flex">
|
<div class="mr-[10px] flex-1">
|
<jnpf-icon-picker v-model:value="model[field]" placeholder="请选择" />
|
</div>
|
<a-form-item-rest>
|
<jnpf-color-picker v-model:value="dataForm.propertyJson.iconBackgroundColor" size="small" :predefine="colorPredefine" />
|
</a-form-item-rest>
|
</a-row>
|
</template>
|
<template #pageAddress="{ model, field }">
|
<a-input v-model:value="model[field]" placeholder="请输入">
|
<template #addonBefore v-if="state.category === 'Web' && model.type == 2">@/views/</template>
|
<template #addonAfter v-if="state.category === 'Web' && model.type == 7">
|
<a-select v-model:value="dataForm.linkTarget" class="!w-[80px]">
|
<a-select-option value="_self">_self</a-select-option>
|
<a-select-option value="_blank">_blank</a-select-option>
|
</a-select>
|
</template>
|
</a-input>
|
</template>
|
<template #moduleId="{ model, field }">
|
<JnpfTreeSelect v-model:value="model[field]" last-level :options="tempData" placeholder="请选择关联" @change="onModuleIdChange" :key="moduleIdKey" />
|
</template>
|
</BasicForm>
|
</BasicModal>
|
</template>
|