This commit is contained in:
吴红兵
2025-12-02 10:37:49 +08:00
commit 1f645dad3e
1183 changed files with 147673 additions and 0 deletions

View File

@@ -0,0 +1,180 @@
<template>
<div class="layout-padding">
<el-container>
<el-header style="background: white">
<flow-design-header :currFlowForm="props.currFlowForm" @handleDesignFlow="methods.handleDesignFlow"
@syncCurrFlowForm="methods.syncCurrFlowForm"
@publish="methods.publishFlow"></flow-design-header>
</el-header>
<div style="min-width: 980px;">
<form-design :currFlowForm="props.currFlowForm" ref="formDesign" v-show="methods.showFormDesign()"/>
<form-def-perm :currFlowForm="props.currFlowForm" ref="formDefPerm" v-show="methods.showFormDefPerm()"/>
</div>
<div id="initClientHeight">
<form-setting :currFlowForm="props.currFlowForm" ref="formSetting" v-show="props.currFlowForm.active === 'formSetting'"/>
<flow-design :currFlowForm="props.currFlowForm" ref="flowDesign" v-show="props.currFlowForm.active === 'flowDesign'"/>
</div>
</el-container>
</div>
</template>
<script setup lang="ts" name="FlowFormDesign">
import {useI18n} from "vue-i18n"
import {useMessageBox} from "/@/hooks/message";
import {notifyLeft, validateRunFlowId} from "/@/flow";
import {confirmCancelAndClose, formWidgetDesignHeight, handleUpgradeVersion} from "/@/flow/utils";
import {DIC_PROP} from "../../support/dict-prop";
const {t} = useI18n();
const {proxy} = getCurrentInstance();
// 引入组件
const FlowDesignHeader = defineAsyncComponent(() => import('./header.vue'));
const FormDesign = defineAsyncComponent(() => import('../form-create/designer.vue'));
const FlowDesign = defineAsyncComponent(() => import('/@/views/jsonflow/flow-design/index.vue'));
const FormSetting = defineAsyncComponent(() => import('./setting.vue'));
const FormDefPerm = defineAsyncComponent(() => import('/@/views/jsonflow/form-option/form-def-perm.vue'));
const $emit = defineEmits(['handleDesignFlow']);
const props = defineProps({
currFlowForm: {
type: Object,
default: null,
}
});
const methods = {
handleDesignFlow(bool) {
$emit("handleDesignFlow", bool);
},
initClientHeight() {
nextTick(() => {
let browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
formWidgetDesignHeight(browserHeight);
})
},
showFormDesign() {
return props.currFlowForm.active === 'formDesign' && props.currFlowForm.type !== DIC_PROP.FORM_TYPE[1].value
},
showFormDefPerm() {
return props.currFlowForm.active === 'formDesign' && props.currFlowForm.type === DIC_PROP.FORM_TYPE[1].value
},
initCurrFlowInfo(active) {
nextTick(() => {
window._jfOperate.reAutoInitNodes();
methods.syncCurrFlowInfo(active)
})
},
syncCurrFlowInfo(active, isInit?) {
let attrs = methods.refsFlowDataAttrs();
if (active !== 'flowDesign' || isInit) {
attrs.flowKey = props.currFlowForm.flowKey
attrs.groupName = props.currFlowForm.groupName
attrs.flowName = props.currFlowForm.formName
} else {
if (attrs.flowKey) {
props.currFlowForm.defFlowId = attrs.id
props.currFlowForm.flowKey = attrs.flowKey
props.currFlowForm.groupName = attrs.groupName
props.currFlowForm.formName = attrs.flowName
}
}
validateRunFlowId(props, attrs)
},
syncCurrFormInfo(callback?) {
if (props.currFlowForm.type !== DIC_PROP.FORM_TYPE[1].value) {
proxy.$refs.formDefPerm.syncCurrFormInfo(true)
// 保存表单信息
proxy.$refs.formDesign.handleSubmit(() => {
if (callback) callback()
});
} else {
proxy.$refs.formDefPerm.syncCurrFormInfo(false)
props.currFlowForm.formInfo = null
}
},
refsFlowDataAttrs() {
// 每次取最新
return proxy.$refs.flowDesign.flowData.attrs;
},
async syncCurrFlowForm(menu?, active?, callback?) {
let preSave = await proxy.$refs.formSetting.validatePreSave();
if (callback) callback(preSave)
if (!preSave) return
if (active === 'formDesign') methods.syncCurrFormInfo();
let defFlowId = props.currFlowForm.defFlowId;
let flowInstId = props.currFlowForm.flowInstId;
if (menu === 'flowDesign') {
let attrs = methods.refsFlowDataAttrs();
if (defFlowId && !attrs.flowKey) {
// 切换到才初始化
proxy.$refs.flowDesign.initFlow(defFlowId, flowInstId, () => {
methods.syncCurrFlowInfo(menu, true)
});
} else methods.initCurrFlowInfo(active)
} else if (active === 'flowDesign'){
methods.syncCurrFlowInfo(active)
}
},
async publishFlow(menu, callback, status, version) {
if (version === true) {
try {
if (props.currFlowForm.isNew) {
notifyLeft('当前设计版本已最新, 请确认是否已保存')
return
}
await useMessageBox().confirm('是否确定升级版本?');
} catch {
return;
}
await handleUpgradeVersion(props)
// 升级流程信息
proxy.$refs.flowDesign.initNewFlow(() => {
methods.syncCurrFlowInfo('flowDesign')
let confirmObj = {text: "发布流程", callback: () => { methods.publishFlow(menu, callback, '1', null) }}
let cancelObj = {text: "暂存流程", callback: () => { methods.publishFlow(menu, callback, '-1', null) }}
confirmCancelAndClose(confirmObj, cancelObj, '流程设计升级版本成功! 是否立即暂存或发布?')
}, true);
return
}
methods.syncCurrFormInfo(callback);
// 校验表单设计
let otherSave = await proxy.$refs.formSetting.validateOtherSave();
if (!otherSave) return
// 保存流程信息
props.currFlowForm.flowDesigning = true
proxy.$refs.flowDesign.publishFlow(() => {
methods.syncCurrFlowInfo('flowDesign')
methods.submitFormSetting(callback, status)
if (callback) callback()
}, status);
},
async submitFormSetting(callback, status) {
// 保存字段信息
if (props.currFlowForm.type === DIC_PROP.FORM_TYPE[1].value) {
await proxy.$refs.formDefPerm.handleSubmit(() => {
props.currFlowForm.formDesign = true
if (callback) callback()
});
}
await proxy.$refs.formSetting.handleSubmit(() => {
if (callback) callback()
}, status)
}
}
// 监听双向绑定
watch(
() => props.currFlowForm.id,
(val) => {
methods.initClientHeight()
}
);
onMounted(() => {
methods.initClientHeight();
});
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,312 @@
<template>
<el-dialog :title="title" v-model="visible" width="80%"
:close-on-click-modal="false" draggable>
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="130px" v-loading="loading" :disabled="operType === 'view'">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.flowKey')" prop="flowKey">
<el-input v-model="form.flowKey" :placeholder="t('flowApplication.inputFlowKeyTip')" clearable/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.formName')" prop="formName">
<el-input v-model="form.formName" :placeholder="t('flowApplication.inputFormNameTip')" maxlength="20" show-word-limit clearable/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.icon')" prop="icon">
<IconSelector :placeholder="$t('flowApplication.inputIconTip')" v-model="form.icon" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.groupName')" prop="groupName">
<el-select v-model="form.groupName" :placeholder="t('flowApplication.inputGroupNameTip')" style="width: 80%!important;"
clearable filterable allowCreate defaultFirstOption>
<el-option v-for="(item, index) in dicData.groupName" :key="index" :label="item.groupName" :value="item.groupName"></el-option>
</el-select>
<el-button
type="primary" size="small" round style="margin-left: 10px"
@click="handleAddGroupName"
>新增分组
</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.type')" prop="type">
<el-select v-model="form.type" :placeholder="t('flowApplication.inputTypeTip')" clearable filterable>
<el-option v-for="(item, index) in DIC_PROP.FORM_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" v-if="form.type === DIC_PROP.FORM_TYPE[1].value">
<el-form-item :label="t('tabsOption.path')" prop="path">
<el-input v-model="form.path" :placeholder="t('tabsOption.inputPathTip')" clearable>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.tableName')" prop="tableName">
<el-tooltip content="若自行调用接口保存表单数据,则此处需为空" placement="top">
<el-select v-model="form.tableName" :placeholder="t('flowApplication.inputTableNameTip')" clearable filterable>
<el-option v-for="(item, index) in dicData.tableName" :key="index" :label="item.tableName" :value="item.tableName"></el-option>
</el-select>
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.permission')" prop="permission">
<el-tooltip content="请输入角色名称进行模糊搜索,默认所有人都可以发起该流程" placement="top">
<el-select v-model="form.permission" :placeholder="t('flowApplication.inputPermissionTip')" clearable filterable multiple
remote :remote-method="remoteMethod" :reserve-keyword="false">
<el-option v-for="(item, index) in dicData.permission" :key="index" :label="item.roleName" :value="item.roleId"></el-option>
</el-select>
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.subTableName')" prop="subTableName">
<el-tooltip content="当存在多个关联子表时,多个子表名称名顺序与《关联子表属性》顺序一一对应" placement="top">
<el-select v-model="form.subTableName" :placeholder="t('flowApplication.inputSubTableNameTip')"
@change="changeSubTableName" clearable filterable multiple>
<el-option v-for="(item, index) in dicData.tableName" :key="index" :label="item.tableName" :value="item.tableName"></el-option>
</el-select>
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" v-if="!validateNull(form.subTableName)">
<el-tooltip content="当关联子表名称存在时可配置子表中关联【主表主键】的列名如main_id" placement="top">
<el-form-item :label="t('flowApplication.subMainField')" prop="subMainField">
<el-input v-model="form.subMainField" :placeholder="t('flowApplication.inputSubMainFieldTip')"></el-input>
</el-form-item>
</el-tooltip>
</el-col>
<el-col :span="12" class="mb20" v-if="!validateNull(form.subTableName)">
<el-tooltip content="当关联子表名称存在时可配置主表中关联【子表集合数据】的属性名如subFormList。多个子表属性名以逗号分割与《关联子表名称》顺序一一对应" placement="top">
<el-form-item :label="t('flowApplication.mainSubProp')" prop="mainSubProp">
<el-input v-model="form.mainSubProp" :placeholder="t('flowApplication.inputMainSubPropTip')"></el-input>
</el-form-item>
</el-tooltip>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.remark')" prop="remark">
<el-input v-model="form.remark" type="textarea" :placeholder="t('flowApplication.inputRemarkTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.sort')" prop="sort">
<el-input-number :min="1" :max="1000" v-model="form.sort" :placeholder="t('flowApplication.inputSortTip')"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('tabsOption.isActive')" prop="isActive">
<el-radio-group v-model="form.isActive">
<el-radio v-for="(item, index) in DIC_PROP.YES_OR_NO" :key="index" :label="item.value" >
{{ getLabelByLanguage(item) }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('tabsOption.isAutoAudit')" prop="isAutoAudit">
<el-radio-group v-model="form.isAutoAudit">
<el-radio v-for="(item, index) in DIC_PROP.YES_OR_NO" :key="index" :label="item.value" >
{{ getLabelByLanguage(item) }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('flowApplication.status')" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="(item, index) in DIC_PROP.TEMP_STATUS" :key="index" :label="item.value" >
{{ getLabelByLanguage(item) }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer v-if="operType !== 'view'">
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="FlowApplicationDialog">
import {useMessage, useMessageBox} from "/@/hooks/message";
import { getObj, addObj, putObj } from '/@/api/order/flow-application'
import { useI18n } from "vue-i18n"
import {rule, validateNull} from '/@/utils/validate';
import {
onFormLoadedUrl,
onLoadDicUrl,
onUpdateDicData,
remoteMethodByKey
} from "/@/flow/components/convert-name/convert";
import {notifyLeft} from "/@/flow";
import {setPropsNull} from "../../support/common";
import {DIC_PROP} from "../../support/dict-prop";
import {validateFormTypeSave, vueKey} from "/@/api/order/order-key-vue";
const emit = defineEmits(['refresh']);
const { t } = useI18n();
// 引入组件
const IconSelector = defineAsyncComponent(() => import('/@/components/IconSelector/index.vue'));
// 定义变量内容
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
const operType = ref(false);
const title = ref('');
// 定义字典
const dicData = reactive({});
const onLoad = onLoadDicUrl({key: "groupName"}, {key: "tableName"});
const onUpdate = onUpdateDicData({key: "groupName"});
const onFormLoaded = onFormLoadedUrl({key: "permission"});
onMounted(() => {
onLoad(dicData);
});
// 提交表单数据
const form = reactive({
flowKey: '',
icon: '',
formName: '',
groupName: '',
tableName: '',
permission: '',
remark: '',
status: '-1',
isActive: '1',
isAutoAudit: '0',
sort: 1,
});
// 定义校验规则
const dataRules = ref({
flowKey: [{required: true, message: '流程KEY不能为空', trigger: 'blur'}],
icon: [{required: true, message: '表单图标不能为空', trigger: 'blur'}],
formName: [{required: true, message: '表单名称不能为空', trigger: 'blur'}],
groupName: [{required: true, message: '分组名称不能为空', trigger: 'blur'}],
isActive: [{required: true, message: '默认展示不能为空', trigger: 'blur'}],
isAutoAudit: [{required: true, message: '提交时自动审批不能为空', trigger: 'blur'}],
sort: [{required: true, message: '排序值不能为空', trigger: 'blur'}],
type: [{required: true, message: '表单类型不能为空', trigger: 'blur'}],
status: [{required: true, message: '状态不能为空', trigger: 'blur'}],
})
// 打开弹窗
const openDialog = (type: string, id: string) => {
visible.value = true
operType.value = type;
setPropsNull(form, 'id', 'flowKey', 'defFlowId')
if (type === 'add') {
title.value = t('common.addBtn');
} else if (type === 'edit') {
title.value = t('common.editBtn');
} else if (type === 'view') {
title.value = t('common.viewBtn');
}
// 重置表单数据
nextTick(() => {
dataFormRef.value?.resetFields();
// 获取FlowApplication信息
if (id) {
form.id = id
getFlowApplicationData(id)
}
});
};
function handleAddGroupName() {
useMessageBox().prompt("请输入新的分组名称")
.then(({ value }) => {
form.groupName = value
onUpdate(dicData, form);
})
}
function changeSubTableName() {
form.subMainField = null
form.mainSubProp = null
}
function remoteMethod(query: string) {
remoteMethodByKey(query, onLoad, dicData, 'roleName', "permission")
}
// 提交
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) return false;
if (form.type === DIC_PROP.FORM_TYPE[1].value) {
if (!form.path) {
notifyLeft('当前表单类型为系统表单【PC端路径】不能为空', 'warning')
return false
}
}
if(!validateNull(form.subTableName)) {
if (!form.subMainField || !form.mainSubProp) {
notifyLeft('请填写 关联主表列名 或者 关联子表属性', 'warning')
return false
}
}
let isDesign = form.type !== DIC_PROP.FORM_TYPE[1].value;
if (isDesign && !form.formInfo) {
notifyLeft('当前表单类型为设计表单,请先完善第二项设计的表单内容', 'warning')
return false
}
validateFormTypeSave(form)
try {
loading.value = true;
form.id ? await putObj(form) : await addObj(form);
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
// 初始化表单数据
const getFlowApplicationData = (id: string) => {
// 获取数据
loading.value = true
getObj(id).then((res: any) => {
Object.assign(form, res.data)
onFormLoaded(dicData, form);
}).finally(() => {
loading.value = false
})
};
// 暴露变量
defineExpose({
openDialog
});
</script>

View File

@@ -0,0 +1,177 @@
<template>
<div>
<div class="header">
<el-tabs v-model="form.active" @tab-click="methods.activeMenu">
<el-tab-pane label="① 表单设置" name="formSetting"></el-tab-pane>
<el-tab-pane label="② 表单设计" name="formDesign"></el-tab-pane>
<el-tab-pane label="③ 流程设计" name="flowDesign"></el-tab-pane>
</el-tabs>
<div class="btn-publish" v-if="form.active !== 'flowDesign'">
<el-button icon="CaretRight" type="primary" @click="methods.activeMenu({paneName: form.active === 'formSetting' ? 'formDesign' : 'flowDesign'})">下一步
</el-button>
</div>
<div class="btn-publish" v-if="form.active === 'flowDesign'">
<template v-if="!validateRunFlow(props)">
<el-button icon="Upload" type="primary" @click="methods.publish(null, true)">升版本
</el-button>
<el-button icon="CirclePlus" type="primary" @click="methods.publish('-1')">暂存
</el-button>
</template>
<el-button icon="Promotion" type="primary" @click="methods.publish('1')">发布
</el-button>
</div>
<div class="btn-back">
<el-button @click="methods.exitFlowForm" icon="Back" circle></el-button>
<span style="margin-left: 20px;">
<i :class="props.currFlowForm.icon"></i>
<span>{{props.currFlowForm.formName }} V{{ props.currFlowForm.version }}
</span>
</span>
</div>
</div>
</div>
</template>
<script setup lang="ts" name="FlowDesignHeader">
import {useI18n} from "vue-i18n"
import {useMessageBox} from "/@/hooks/message";
import {notifyLeft} from "/@/flow";
import {validateNull} from "/@/utils/validate";
const {t} = useI18n();
const {proxy} = getCurrentInstance();
const $emit = defineEmits(["handleDesignFlow", "syncCurrFlowForm", "publish"]);
const props = defineProps({
currFlowForm: {
type: Object,
default: null,
}
});
const form = reactive({
active: "formSetting",
interval: {},
intervalTime: 2
});
const methods = {
publish(status, version) {
$emit('publish', form.active, () => {
props.currFlowForm[form.active] = true
}, status, version)
},
async exitFlowForm() {
let text = ''
// 判断是否都保存
if (props.currFlowForm.formSetting !== true) text += '【表单设置】,'
if (props.currFlowForm.formDesign !== true) text += '【表单设计】,'
if (props.currFlowForm.flowDesign !== true) text += '【流程设计】'
if (!text) {
$emit("handleDesignFlow", false);
return
}
try {
await useMessageBox().confirm(text + '未保存,是否继续退出?');
} catch {
return;
}
$emit("handleDesignFlow", false);
},
activeMenu(tab) {
let menu = tab.paneName
let active = form.active;
// 判断是否在操作中
if (props.currFlowForm.flowDesigning === true) {
if (!validateNull(form.interval)) clearInterval(form.interval);
let intervalTime = 0;
form.interval = setInterval(() => {
methods.validateFlowDesigning(menu, active, intervalTime)
intervalTime++;
}, 1000);
return true
}
methods.doActiveMenu(menu, active);
},
validateFlowDesigning(menu, active, intervalTime = 0){
notifyLeft('流程设计操作中,请稍后', 'warning')
if (intervalTime >= form.intervalTime) {
props.currFlowForm.flowDesigning = false
}
if (props.currFlowForm.flowDesigning === true) return
methods.doActiveMenu(menu, active)
clearInterval(form.interval);
},
doActiveMenu(menu, active){
$emit("syncCurrFlowForm", menu, active, (preSave)=>{
if (!preSave) menu = active
props.currFlowForm[menu] = false;
form.active = menu;
props.currFlowForm.active = menu;
});
},
// 关闭提示
listenPage() {
window.onbeforeunload = function (e) {
e = e || window.event;
if (e) {
e.returnValue = "关闭提示";
}
return "关闭提示";
};
}
}
onMounted(() => {
methods.listenPage();
});
</script>
<style lang="scss" scoped>
.header {
min-width: 980px;
.el-tabs {
position: absolute;
top: 15px;
z-index: 999;
display: flex;
justify-content: center;
width: 100%;
}
.btn-publish {
position: absolute;
top: 20px;
z-index: 1000;
right: 40px !important;
i {
margin-right: 6px;
}
button {
width: 74px;
height: 28px;
border-radius: 15px;
}
}
.btn-back {
position: absolute;
top: 20px;
z-index: 1000;
left: 20px !important;
font-size: 18px;
i {
margin-right: 6px;
}
button {
width: 44px;
height: 28px;
border-radius: 15px;
}
}
}
</style>

View File

@@ -0,0 +1,377 @@
<template>
<div>
<el-form ref="dataFormRef" :model="props.currFlowForm" :rules="dataRules" label-width="150px"
v-loading="loading"
label-position="left"
:disabled="operType === 'view'">
<el-row :gutter="24">
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.flowKey')" prop="flowKey">
<el-input v-model="props.currFlowForm.flowKey" clearable
:placeholder="t('flowApplication.inputFlowKeyTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.formName')" prop="formName">
<el-input v-model="props.currFlowForm.formName" maxlength="20" show-word-limit clearable
:placeholder="t('flowApplication.inputFormNameTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.icon')" prop="icon">
<IconSelector :placeholder="$t('flowApplication.inputIconTip')"
v-model="props.currFlowForm.icon"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.groupName')" prop="groupName">
<el-select v-model="props.currFlowForm.groupName" style="width: 83%!important;"
:placeholder="t('flowApplication.inputGroupNameTip')"
clearable filterable allowCreate defaultFirstOption>
<el-option v-for="(item, index) in dicData.groupName" :key="index" :label="item.groupName"
:value="item.groupName"></el-option>
</el-select>
<el-button
type="primary" size="small" round style="margin-left: 10px"
@click="handleAddGroupName"
>新增分组
</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.type')" prop="type">
<el-select v-model="props.currFlowForm.type" :disabled="!!validateRunFlow(props)"
:placeholder="t('flowApplication.inputTypeTip')" clearable filterable>
<el-option v-for="(item, index) in DIC_PROP.FORM_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" :offset="6" v-if="props.currFlowForm.type === DIC_PROP.FORM_TYPE[1].value">
<el-tooltip content="当表单设计的页面为空时可配置本地自定义主表单Vue页面路径" placement="top">
<el-form-item :label="t('tabsOption.path')" prop="path">
<el-input v-model="props.currFlowForm.path" :placeholder="t('tabsOption.inputPathTip')" clearable>
</el-input>
</el-form-item>
</el-tooltip>
</el-col>
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.tableName')" prop="tableName">
<el-tooltip content="若自行调用接口保存表单数据,则此处需为空" placement="top">
<el-select v-model="props.currFlowForm.tableName" @clear="props.currFlowForm.tableName = null"
:placeholder="t('flowApplication.inputTableNameTip')" style="width: 83%!important;"
clearable filterable>
<el-option v-for="(item, index) in dicData.tableName" :key="index" :label="item.tableName"
:value="item.tableName"></el-option>
</el-select>
</el-tooltip>
<el-button
type="primary" size="small" round style="margin-left: 10px"
@click="addUpdateTableName()"
>{{ props.currFlowForm.tableName ? '修改表' : '新增表'}}
</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" :offset="6" v-if="!validateRunFlow(props)">
<el-form-item :label="t('flowApplication.permission')" prop="permission">
<el-tooltip content="请输入角色名称进行模糊搜索,默认所有人都可以发起该流程" placement="top">
<el-select v-model="props.currFlowForm.permission" :placeholder="t('flowApplication.inputPermissionTip')"
clearable filterable multiple
remote :remote-method="remoteMethod" :reserve-keyword="false">
<el-option v-for="(item, index) in dicData.permission" :key="index" :label="item.roleName"
:value="item.roleId"></el-option>
</el-select>
</el-tooltip>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.subTableName')" prop="subTableName">
<el-tooltip content="当存在多个关联子表时,多个子表名称名顺序与《关联子表属性》顺序一一对应" placement="top">
<el-select v-model="props.currFlowForm.subTableName" :placeholder="t('flowApplication.inputSubTableNameTip')" style="width: 83%!important;"
@change="changeSubTableName" clearable filterable multiple>
<el-option v-for="(item, index) in dicData.tableName" :key="index"
:label="item.tableName" :value="item.tableName">
<span> {{ item.tableName }} </span>
<span style="float: right; color: #409EFF" @click="addUpdateTableName(item.tableName, true)"> 点击修改 </span>
</el-option>
</el-select>
</el-tooltip>
<el-button
type="primary" size="small" round style="margin-left: 10px"
@click="addUpdateTableName(null, true)"
>新增子表
</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" :offset="6" v-if="!validateNull(props.currFlowForm.subTableName)">
<el-tooltip content="当关联子表名称存在时可配置子表中关联【主表主键】的列名如main_id" placement="top">
<el-form-item :label="t('flowApplication.subMainField')" prop="subMainField">
<el-input v-model="props.currFlowForm.subMainField" :placeholder="t('flowApplication.inputSubMainFieldTip')"></el-input>
</el-form-item>
</el-tooltip>
</el-col>
<el-col :span="12" class="mb20" :offset="6" v-if="!validateNull(props.currFlowForm.subTableName)">
<el-tooltip content="当关联子表名称存在时可配置主表中关联【子表集合数据】的属性名如subFormList。多个子表属性名以逗号分割注意与《关联子表名称》顺序一一对应" placement="top">
<el-form-item :label="t('flowApplication.mainSubProp')" prop="mainSubProp">
<el-input v-model="props.currFlowForm.mainSubProp" :placeholder="t('flowApplication.inputMainSubPropTip')"></el-input>
</el-form-item>
</el-tooltip>
</el-col>
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.remark')" prop="remark">
<el-input v-model="props.currFlowForm.remark" type="textarea" :placeholder="t('flowApplication.inputRemarkTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.sort')" prop="sort">
<el-input-number :min="1" :max="1000" v-model="props.currFlowForm.sort"
:placeholder="t('flowApplication.inputSortTip')"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" v-if="!validateRunFlow(props)" :offset="6">
<el-tooltip content="在审批时默认展示的第1个页面。当存在多个默认展示页面时优先展示排序值最小的" placement="top">
<el-form-item :label="t('tabsOption.isActive')" prop="isActive">
<el-radio-group v-model="props.currFlowForm.isActive">
<el-radio v-for="(item, index) in DIC_PROP.YES_OR_NO" :key="index" :label="item.value" >
{{ getLabelByLanguage(item) }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-tooltip>
</el-col>
<el-col :span="12" class="mb20" v-if="!validateRunFlow(props)" :offset="6">
<el-tooltip content="在审批时不会显示审批按钮,在页面点提交按钮会自动流转到下一步" placement="top">
<el-form-item :label="t('tabsOption.isAutoAudit')" prop="isAutoAudit">
<el-radio-group v-model="props.currFlowForm.isAutoAudit">
<el-radio v-for="(item, index) in DIC_PROP.YES_OR_NO" :key="index" :label="item.value" >
{{ getLabelByLanguage(item) }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-tooltip>
</el-col>
<el-col :span="12" class="mb20" :offset="6">
<el-form-item :label="t('flowApplication.status')" prop="status">
<el-radio-group v-model="props.currFlowForm.status">
<el-radio v-for="(item, index) in DIC_PROP.TEMP_STATUS" :key="index" :label="item.value">
{{ getLabelByLanguage(item) }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 编辑新增 -->
<create-table ref="createTableRef" @refreshDone="createTableDone" />
</div>
</template>
<script setup lang="ts" name="FlowApplicationForm">
import {useMessage, useMessageBox} from "/@/hooks/message";
import * as runApplication from "/@/api/order/run-application";
import * as flowApplication from "/@/api/order/flow-application";
import other from '/@/utils/other';
import {notifyLeft, stringifyWithFunctions, validateRunFlow} from "/@/flow";
import {useI18n} from "vue-i18n"
import {
onFormLoadedUrl,
onLoadDicUrl,
onUpdateDicData,
remoteMethodByKey
} from "/@/flow/components/convert-name/convert";
import {validateNull} from "/@/utils/validate";
import {DIC_PROP} from "../../support/dict-prop";
import {validateFormTypeSave, vueKey} from "/@/api/order/order-key-vue";
import {PROP_CONST} from "../../support/prop-const";
const {t} = useI18n();
const {proxy} = getCurrentInstance();
const props = defineProps({
currFlowForm: {
type: Object,
default: null,
}
});
// 引入组件
const IconSelector = defineAsyncComponent(() => import('/@/components/IconSelector/index.vue'));
const CreateTable = defineAsyncComponent(() => import('/@/views/order/create-table/form.vue'));
// 定义变量内容
const dataFormRef = ref();
const loading = ref(false);
const operType = ref(false);
// 定义字典
const dicData = reactive({});
const onLoad = onLoadDicUrl({key: "groupName"}, {key: "tableName"});
const onFormLoaded = onFormLoadedUrl({key: "permission"});
const onUpdate = onUpdateDicData({key: "groupName"});
onMounted(async () => {
await onLoad(dicData);
await onFormLoaded(dicData, props.currFlowForm);
let isNoGroupName = !props.currFlowForm.groupName && dicData.groupName.length > 0;
if (isNoGroupName) {
props.currFlowForm.groupName = dicData.groupName[0].groupName
}
});
const data = reactive({subTableName: null, updateSubTableName: null, isSubTableName: false});
// 定义校验规则
const dataRules = ref({
flowKey: [{required: true, message: '流程KEY不能为空', trigger: 'blur'}],
icon: [{required: true, message: '表单图标不能为空', trigger: 'blur'}],
type: [{required: true, message: '表单类型不能为空', trigger: 'blur'}],
formName: [{required: true, message: '表单名称不能为空', trigger: 'blur'}],
groupName: [{required: true, message: '分组名称不能为空', trigger: 'blur'}],
status: [{required: true, message: '状态不能为空', trigger: 'blur'}],
})
function handleAddGroupName() {
useMessageBox().prompt("请输入新的分组名称")
.then(({ value }) => {
props.currFlowForm.groupName = value
onUpdate(dicData, props.currFlowForm);
})
}
function changeSubTableName() {
if (data.isSubTableName) {
if (data.subTableName) props.currFlowForm.subTableName = data.subTableName
return
}
if (!validateNull(props.currFlowForm.subTableName)) {
return
}
props.currFlowForm.subMainField = null
props.currFlowForm.mainSubProp = null
}
function addUpdateTableName(subTableName?, isSubTableName?) {
data.isSubTableName = isSubTableName
if (isSubTableName && subTableName) {
data.subTableName = props.currFlowForm.subTableName
data.updateSubTableName = subTableName
}
let tableName = isSubTableName ? subTableName : props.currFlowForm.tableName;
if (tableName) {
if (tableName === PROP_CONST.COMMON.tableName) {
notifyLeft('当前表为系统表,请勿修改', 'warning')
} else {
let find = dicData.tableName.find(f => f.tableName === tableName);
proxy.$refs.createTableRef.openDialog('edit', find.id)
}
} else {
proxy.$refs.createTableRef.openDialog('add')
}
}
function createTableDone(tableName, operType, isOnSubmit) {
if (data.isSubTableName) {
if (isOnSubmit && operType === 'edit' && data.updateSubTableName !== tableName){
let includes = props.currFlowForm.subTableName.includes(data.updateSubTableName);
if (includes) {
// 修改表名
let findIndex = props.currFlowForm.subTableName.findIndex(f => f === data.updateSubTableName);
props.currFlowForm.subTableName.splice(findIndex, 1, tableName)
}
} else if (isOnSubmit && operType === 'add'){
props.currFlowForm.subTableName.push(tableName)
}
data.isSubTableName = false
data.updateSubTableName = null
data.subTableName = null
} else if (isOnSubmit){
props.currFlowForm.tableName = tableName
}
if (!isOnSubmit) return
const onLoad = onLoadDicUrl({key: "tableName"});
onLoad(dicData)
}
async function validatePreSave() {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) {
notifyLeft('请先完善表单设置内容', 'warning')
return false;
}
let isSys = props.currFlowForm.type === DIC_PROP.FORM_TYPE[1].value;
if (isSys && !props.currFlowForm.path) {
notifyLeft('当前表单类型为系统表单【PC端路径】不能为空', 'warning')
return false
}
if(!validateNull(props.currFlowForm.subTableName)) {
if (!props.currFlowForm.subMainField || !props.currFlowForm.mainSubProp) {
notifyLeft('请填写 关联主表列名 或者 关联子表属性', 'warning')
return false
}
}
return true
}
function validateOtherSave() {
let isDesign = props.currFlowForm.type !== DIC_PROP.FORM_TYPE[1].value;
if (isDesign && !props.currFlowForm.formInfo) {
notifyLeft('当前表单类型为设计表单,请先完善第二项设计的表单内容', 'warning')
return false
}
return true
}
function remoteMethod(query: string) {
remoteMethodByKey(query, onLoad, dicData, 'roleName', "permission")
}
const handleSubmit = async (callback, status) => {
if (status) {
props.currFlowForm.status = status
}
let preSave = await validatePreSave();
if (!preSave) return
if (!validateOtherSave()) return
let formJson = other.deepClone(props.currFlowForm)
formJson.formInfo = stringifyWithFunctions(formJson.formInfo)
validateFormTypeSave(formJson)
try {
loading.value = true;
// 判断是否为低代码
if (validateRunFlow(props) && props.currFlowForm.tableName) {
await runApplication.putObjNoStatus(formJson)
} else {
await flowApplication.addObj(formJson);
}
props.currFlowForm.formSetting = true
notifyLeft('当前表单设置保存成功')
if (callback) callback()
} catch (err: any) {
useMessage().error(err);
} finally {
loading.value = false;
}
}
// 暴露变量
defineExpose({
handleSubmit, validatePreSave, validateOtherSave
});
</script>