增加线条、并行网关、包含网关节点及对应属性面板。流程发起列表页,流程发起页面
parent
3a1aa488bb
commit
52f1233354
|
|
@ -0,0 +1,16 @@
|
|||
// WFDelegate 流程模版基本信息
|
||||
import { defHttp } from '@/utils/http/axios';
|
||||
import {DetailParams} from './model/wfSchemeInfoModel'
|
||||
|
||||
enum Api {
|
||||
// 创建流程
|
||||
LoadMyUserList = '/api/WFDelegate/LoadMyUserList',
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: getLoadMyUserList
|
||||
*/
|
||||
export function getLoadMyUserList(params?: DetailParams) {
|
||||
return defHttp.get({ url: Api.LoadMyUserList, params });
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
// WFProcess 流程模版基本信息
|
||||
import { defHttp } from '@/utils/http/axios';
|
||||
import {CreateParams} from './model/WFProcessModel'
|
||||
|
||||
enum Api {
|
||||
// 创建流程
|
||||
Create = '/api/WFProcess/Create',
|
||||
SaveDraft='/api/WFProcess/SaveDraft'
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 创建流程
|
||||
*/
|
||||
export function create( params?:CreateParams) {
|
||||
return defHttp.post(
|
||||
{
|
||||
url: Api.Create,
|
||||
params,
|
||||
},
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @description: 保存草稿
|
||||
*/
|
||||
export function saveDraft( params?:CreateParams) {
|
||||
return defHttp.post(
|
||||
{
|
||||
url: Api.SaveDraft,
|
||||
params,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -14,6 +14,8 @@ import {SchemeListParams,GetSchemeModel,AddParams,
|
|||
// 流程模板详细信息
|
||||
LoadHistoryPage= '/api/WFScheme/LoadPage',
|
||||
UpdateScheme='/api/WFSchemeInfo/UpdateScheme',
|
||||
// 获取自定义流程列表(流程发起页)
|
||||
GetInfoList='/api/WFSchemeInfo/GetInfoList'
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -59,3 +61,10 @@ export function updateScheme(params:SchemeParams){
|
|||
return defHttp.post({ url: Api.UpdateScheme + "?id=" + params.id +"&schemeId="+params.schemeId});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: getInfoList 获取流程自定义列表
|
||||
*/
|
||||
export function getInfoList(params) {
|
||||
return defHttp.get({ url: Api.GetInfoList, params });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* @description: 创建流程参数
|
||||
*/
|
||||
export interface CreateParams {
|
||||
processId: string,
|
||||
schemeCode: string,
|
||||
title: string,
|
||||
userId: string,
|
||||
toUserId: string,
|
||||
nextUsers: {
|
||||
additionalProp1: string,
|
||||
additionalProp2: string,
|
||||
additionalProp3: string
|
||||
},
|
||||
des: string,
|
||||
code: string,
|
||||
name: string,
|
||||
stampImg: string,
|
||||
stampPassWord: string,
|
||||
nextId: string
|
||||
}
|
||||
|
|
@ -2,22 +2,39 @@
|
|||
<div :class="prefixCls" :style="{ width: `${props.width}px` }">
|
||||
<a-tabs v-model:activeKey="configActiveName">
|
||||
<a-tab-pane :tab="data.wfNodeName" key="1">
|
||||
<!-- 开始节点 -->
|
||||
<start-event-option ref="startRef" :element="data.currentWfNode" :schemeCode="props.schemeCode"
|
||||
:pageView="props.pageView" :pageType="props.pageType"
|
||||
:class="data.currentWfNode.type=='bpmn:StartEvent' ? '' : 'hidden'"></start-event-option>
|
||||
<!-- 审核节点 -->
|
||||
<user-task-option ref="taskRef" :element="data.currentWfNode" :schemeCode="props.schemeCode"
|
||||
:pageView="props.pageView" :pageType="props.pageType"
|
||||
:class="data.currentWfNode.type=='bpmn:Task' ? '' : 'hidden'">
|
||||
</user-task-option>
|
||||
<!-- 结束节点 -->
|
||||
<end-event-option ref="endRef" :element="data.currentWfNode" :schemeCode="props.schemeCode"
|
||||
:class="data.currentWfNode.type=='bpmn:EndEvent' ? '' : 'hidden'"></end-event-option>
|
||||
<!-- 子流程 -->
|
||||
<subprocess-option ref="subprocessRef" :element="data.currentWfNode" :schemeCode="props.schemeCode"
|
||||
:pageView="props.pageView" :pageType="props.pageType"
|
||||
:class="data.currentWfNode.type=='bpmn:SubProcess' ? '' : 'hidden'"></subprocess-option>
|
||||
<!-- 排他网关 -->
|
||||
<exclusive-gateway-option ref="exclusiveGatewayRef" :element="data.currentWfNode" :schemeCode="props.schemeCode"
|
||||
:pageView="props.pageView" :pageType="props.pageType"
|
||||
:class="data.currentWfNode.type=='bpmn:ExclusiveGateway' ? '' : 'hidden'">
|
||||
</exclusive-gateway-option>
|
||||
<!-- 并行网关 -->
|
||||
<parallel-gateway-option ref="parallelGatewayRef" :element="data.currentWfNode" :schemeCode="props.schemeCode"
|
||||
:pageView="props.pageView" :pageType="props.pageType"
|
||||
:class="data.currentWfNode.type=='bpmn:ParallelGateway' ? '' : 'hidden'">
|
||||
</parallel-gateway-option>
|
||||
<!-- 包容网关 -->
|
||||
<!-- "bpmn:InclusiveGateway" -->
|
||||
<inclusive-gateway-option ref="inclusiveGatewayRef" :element="data.currentWfNode" :schemeCode="props.schemeCode"
|
||||
:pageView="props.pageView" :pageType="props.pageType"
|
||||
:class="data.currentWfNode.type=='bpmn:InclusiveGateway' ? '' : 'hidden'">
|
||||
</inclusive-gateway-option>
|
||||
<!-- 线条 -->
|
||||
<myline-option ref="mylineRef" :element="data.currentWfNode" :schemeCode="props.schemeCode"
|
||||
:pageView="props.pageView" :pageType="props.pageType" :wfData="data.wfData" :flowRef="data.flowRef"
|
||||
:class="data.currentWfNode.type=='bpmn:SequenceFlow' ? '' : 'hidden'">
|
||||
|
|
@ -55,10 +72,12 @@
|
|||
import userTaskOption from './userTask/index.vue'
|
||||
// 结束节点
|
||||
import endEventOption from './endEvent/index.vue'
|
||||
// 网关和
|
||||
import gatewayAndOption from './config/gatewayAnd.vue'
|
||||
// 并行网关
|
||||
import parallelGatewayOption from './parallelGateway/index.vue'
|
||||
// 排他网关
|
||||
import exclusiveGatewayOption from './exclusiveGateway/index.vue'
|
||||
// 包容网关
|
||||
import inclusiveGatewayOption from './inclusiveGateway/index.vue'
|
||||
// 网关Xor
|
||||
import gatewayXorOption from './config/gatewayXor.vue'
|
||||
// 脚本任务
|
||||
|
|
@ -97,12 +116,14 @@
|
|||
const endRef = ref < any > ()
|
||||
const subprocessRef = ref < any > ()
|
||||
const exclusiveGatewayRef = ref < any > ()
|
||||
const parallelGatewayRef = ref < any > ()
|
||||
const inclusiveGatewayRef = ref < any > ()
|
||||
const configActiveName = ref('2')
|
||||
const data = reactive({
|
||||
currentWfNode: undefined,
|
||||
wfNodeName: "",
|
||||
wfData:[],
|
||||
flowRef:{}
|
||||
wfData: [],
|
||||
flowRef: {}
|
||||
})
|
||||
watch(
|
||||
() => props.element,
|
||||
|
|
@ -153,6 +174,20 @@
|
|||
type: newVal.type
|
||||
}
|
||||
break;
|
||||
case 'ParallelGateway':
|
||||
data.wfNodeName = "并行网关"
|
||||
data.currentWfNode = {
|
||||
id: newVal.id,
|
||||
type: newVal.type
|
||||
}
|
||||
break;
|
||||
case 'InclusiveGateway':
|
||||
data.wfNodeName = "包含网关"
|
||||
data.currentWfNode = {
|
||||
id: newVal.id,
|
||||
type: newVal.type
|
||||
}
|
||||
break;
|
||||
case 'SequenceFlow':
|
||||
data.wfNodeName = "线条"
|
||||
data.currentWfNode = {
|
||||
|
|
@ -160,9 +195,9 @@
|
|||
type: newVal.type
|
||||
}
|
||||
// 获取线条两头的节点id
|
||||
data.flowRef={
|
||||
from:newVal.businessObject.sourceRef.id,
|
||||
to:newVal.businessObject.targetRef.id,
|
||||
data.flowRef = {
|
||||
from: newVal.businessObject.sourceRef.id,
|
||||
to: newVal.businessObject.targetRef.id,
|
||||
}
|
||||
// 获取排他网关和审核节点的数据,为选择流转条件使用
|
||||
getWfData()
|
||||
|
|
@ -320,6 +355,16 @@
|
|||
if (gatewayInclusiveFrom != undefined) {
|
||||
wfData.push(gatewayInclusiveFrom)
|
||||
}
|
||||
// 并排网关
|
||||
let parallelGatewayFrom = await !(parallelGatewayRef.value) ? {} : parallelGatewayRef.value.getForm();
|
||||
if (parallelGatewayFrom != undefined) {
|
||||
wfData.push(parallelGatewayFrom)
|
||||
}
|
||||
// 包含网关
|
||||
let inclusiveGatewayFrom = await !(inclusiveGatewayRef.value) ? {} : inclusiveGatewayRef.value.getForm();
|
||||
if (inclusiveGatewayFrom != undefined) {
|
||||
wfData.push(inclusiveGatewayFrom)
|
||||
}
|
||||
// 3.流程节点信息
|
||||
wfData.forEach(node => {
|
||||
if (node.type == 'myline' && !node.isInit) {
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
<!-- 开始节点配置 -->
|
||||
<template>
|
||||
<el-form
|
||||
class="l-form-config"
|
||||
label-width="88px"
|
||||
label-position="left"
|
||||
size="mini"
|
||||
>
|
||||
<el-form-item label="节点标识">
|
||||
<el-input v-model="node.id" readonly ></el-input>
|
||||
</el-form-item>
|
||||
<div style="padding:0 16px;">
|
||||
<el-alert
|
||||
title="并行网关说明"
|
||||
type="info"
|
||||
description="并行网关会等待所有分支汇入才往下执行,所有出口分支都会被执行"
|
||||
show-icon
|
||||
:closable="false"
|
||||
>
|
||||
</el-alert>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name:'gateway-and-option',
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
node(){
|
||||
return this.wfdesign.currentWfNode;
|
||||
}
|
||||
},
|
||||
inject: ["wfdesign"]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
<script lang="ts" setup>
|
||||
import conditionFormula from './src/conditionFormula.vue'
|
||||
import conditionSql from './src/conditionSql.vue'
|
||||
import { getDetail } from '@/api/sys/WFSchemeInfo'
|
||||
import { reactive, ref, onMounted, nextTick, unref, h, watch, defineProps } from 'vue';
|
||||
const labelCol = { span: 7 };
|
||||
const wrapperCol = { span: 17 };
|
||||
|
|
@ -89,6 +90,8 @@
|
|||
|
||||
editRow: null,
|
||||
rowIndex: 0,
|
||||
componentDisabled: props.pageType == 'detail' ? true : false
|
||||
|
||||
})
|
||||
function getNode() {
|
||||
var content = JSON.parse(props.pageView)
|
||||
|
|
@ -104,7 +107,6 @@
|
|||
let wfData = scheme.wfData
|
||||
wfData.forEach(element => {
|
||||
if (element.id == node.value.id) {
|
||||
console.log(node)
|
||||
node.value = element
|
||||
}
|
||||
});
|
||||
|
|
@ -139,8 +141,9 @@
|
|||
async function handleFormulaOk() {
|
||||
conditionFormulaRef.value.validateForm()
|
||||
let obj = conditionFormulaRef.value.getForm()
|
||||
console.log(obj.name)
|
||||
if (obj.name != '') {
|
||||
if (obj.name == '' || obj.dbCode == '' || obj.sql == '') {
|
||||
data.formulaVisible = true;
|
||||
}else{
|
||||
data.formulaVisible = false;
|
||||
}
|
||||
|
||||
|
|
@ -148,6 +151,13 @@
|
|||
function handleSqlOk() {
|
||||
console.log(conditionSqlRef.value.getForm())
|
||||
// this.sqlVisible = false;
|
||||
conditionSqlRef.value.validateForm()
|
||||
let obj = conditionSqlRef.value.getForm()
|
||||
if (obj.name == '' || obj.table == '' || obj.value == '' || obj.rfield == '' || obj.cfield == '' || obj.compareType == '') {
|
||||
data.formulaVisible = true;
|
||||
}else{
|
||||
data.formulaVisible = false;
|
||||
}
|
||||
}
|
||||
function getForm() {
|
||||
return node.value
|
||||
|
|
|
|||
|
|
@ -124,12 +124,11 @@
|
|||
function validateForm() {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then((values) => {
|
||||
return formData.value
|
||||
.then(async (values) => {
|
||||
return true
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
return {}
|
||||
.catch(async (error) => {
|
||||
return false
|
||||
});
|
||||
}
|
||||
function setForm(data) {
|
||||
|
|
|
|||
|
|
@ -43,23 +43,27 @@
|
|||
]
|
||||
},
|
||||
})
|
||||
async function getForm() {
|
||||
let res = await formRef.value
|
||||
// 校验表单
|
||||
function validateForm() {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then((values) => {
|
||||
return formData.value
|
||||
.then(async (values) => {
|
||||
return true
|
||||
})
|
||||
.catch((error: ValidateErrorEntity<FormState>) => {
|
||||
return {}
|
||||
.catch(async (error) => {
|
||||
return false
|
||||
});
|
||||
return res;
|
||||
}
|
||||
function getForm() {
|
||||
return formData.value
|
||||
}
|
||||
defineExpose({
|
||||
getForm
|
||||
getForm,
|
||||
validateForm
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.l-from-body{
|
||||
.l-from-body {
|
||||
padding: 10px 30px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
<template>
|
||||
<div class="user-task">
|
||||
<a-form ref="formRef" :rules="rules" :model="node" labelAlign="left" :label-col="labelCol"
|
||||
:wrapper-col="wrapperCol" :disabled="data.componentDisabled">
|
||||
<a-form-item label="节点标识">
|
||||
<a-input v-model:value="node.id" placeholder="请输入" readonly />
|
||||
</a-form-item>
|
||||
<a-alert message="包容网关说明"
|
||||
description="包容网关会等待所有分支汇入才往下执行,出口分支能执行多条(条件为true)" type="info"
|
||||
show-icon />
|
||||
<a-space>
|
||||
<a-radio-group>
|
||||
<a-radio-button value="1" @click="handleFormulaClick">公式</a-radio-button>
|
||||
<a-radio-button value="2" @click="handleSQlClick">sql语句</a-radio-button>
|
||||
</a-radio-group>
|
||||
<a-button danger :size="size" @click="handleClearClick">清空</a-button>
|
||||
</a-space>
|
||||
<a-table :columns="data.columns" :data-source="node.conditions" bordered :pagination="false">
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="['name', 'type'].includes(column.dataIndex)">
|
||||
<div>
|
||||
{{ text }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'">
|
||||
<a-button>编辑</a-button>
|
||||
<a-button danger @click='onDelete(record.name,false)'>删除</a-button>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-form>
|
||||
<a-modal width="40%" v-model:open="data.formulaVisible" title="添加公式条件" @ok="handleFormulaOk">
|
||||
<conditionFormula ref="conditionFormulaRef"></conditionFormula>
|
||||
</a-modal>
|
||||
<a-modal width="40%" v-model:open="data.sqlVisible" title="添加sql条件" @ok="handleSqlOk">
|
||||
<conditionSql ref="conditionSqlRef"></conditionSql>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import conditionFormula from '../exclusiveGateway/src/conditionFormula.vue'
|
||||
import conditionSql from '../exclusiveGateway/src/conditionSql.vue'
|
||||
import { getDetail } from '@/api/sys/WFSchemeInfo'
|
||||
import { reactive, ref, onMounted, nextTick, unref, h, watch, defineProps } from 'vue';
|
||||
const labelCol = { span: 7 };
|
||||
const wrapperCol = { span: 17 };
|
||||
const conditionFormulaRef = ref < any > ()
|
||||
const conditionSqlRef = ref < any > ()
|
||||
const props = defineProps({
|
||||
element: Object,
|
||||
schemeCode: String,
|
||||
pageType: String,
|
||||
pageView: String,
|
||||
})
|
||||
const node = ref({
|
||||
conditions: [],
|
||||
id: ''
|
||||
})
|
||||
watch(
|
||||
() => props.element,
|
||||
(newVal, oldVal) => {
|
||||
console.log(newVal)
|
||||
if (newVal.type == "bpmn:ExclusiveGateway") {
|
||||
node.value.id = newVal.id
|
||||
node.value.type = newVal.type
|
||||
if (props.pageType == 'detail') {
|
||||
getNode()
|
||||
}
|
||||
if (props.schemeCode) {
|
||||
getDetailInfo()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const data = reactive({
|
||||
tableBtns: [
|
||||
{ prop: 'Edit', label: '编辑' },
|
||||
{ prop: 'Delete', label: '删除' }
|
||||
],
|
||||
columns: [
|
||||
{ title: '类型', dataIndex: 'type' },
|
||||
{ title: '名称', dataIndex: 'name' },
|
||||
],
|
||||
tableData: [],
|
||||
|
||||
formulaVisible: false,
|
||||
sqlVisible: false,
|
||||
|
||||
editRow: null,
|
||||
rowIndex: 0,
|
||||
componentDisabled: props.pageType == 'detail' ? true : false
|
||||
|
||||
})
|
||||
function getNode() {
|
||||
var content = JSON.parse(props.pageView)
|
||||
content.wfData.forEach(element => {
|
||||
if (element.id == node.value.id) {
|
||||
node.value = element
|
||||
}
|
||||
});
|
||||
}
|
||||
async function getDetailInfo() {
|
||||
let data = await getDetail({ code: props.schemeCode })
|
||||
let scheme = JSON.parse(data.scheme.content);
|
||||
let wfData = scheme.wfData
|
||||
wfData.forEach(element => {
|
||||
if (element.id == node.value.id) {
|
||||
node.value = element
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
onMounted(() => {
|
||||
if (props.schemeCode) {
|
||||
getDetailInfo()
|
||||
}
|
||||
if (props.pageType == 'detail') {
|
||||
getNode()
|
||||
}
|
||||
})
|
||||
function typeFormat(type) {
|
||||
switch (type) {
|
||||
case '1':
|
||||
return '表达式'
|
||||
case '2':
|
||||
return 'sql语句'
|
||||
}
|
||||
}
|
||||
|
||||
function handleFormulaClick() {
|
||||
data.formulaVisible = true;
|
||||
}
|
||||
function handleSQlClick() {
|
||||
data.sqlVisible = true;
|
||||
}
|
||||
function handleClearClick() {
|
||||
node.conditions = [];
|
||||
}
|
||||
async function handleFormulaOk() {
|
||||
conditionFormulaRef.value.validateForm()
|
||||
let obj = conditionFormulaRef.value.getForm()
|
||||
if (obj.name == '' || obj.dbCode == '' || obj.sql == '') {
|
||||
data.formulaVisible = true;
|
||||
}else{
|
||||
data.formulaVisible = false;
|
||||
}
|
||||
|
||||
}
|
||||
function handleSqlOk() {
|
||||
console.log(conditionSqlRef.value.getForm())
|
||||
// this.sqlVisible = false;
|
||||
conditionSqlRef.value.validateForm()
|
||||
let obj = conditionSqlRef.value.getForm()
|
||||
if (obj.name == '' || obj.table == '' || obj.value == '' || obj.rfield == '' || obj.cfield == '' || obj.compareType == '') {
|
||||
data.formulaVisible = true;
|
||||
}else{
|
||||
data.formulaVisible = false;
|
||||
}
|
||||
}
|
||||
function getForm() {
|
||||
return node.value
|
||||
}
|
||||
defineExpose({
|
||||
getForm
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
::v-deep .ant-alert-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-wrapper {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<!-- 开始节点配置 -->
|
||||
<template>
|
||||
<div class="user-task">
|
||||
<a-form ref="formRef" :rules="rules" :model="node" labelAlign="left" :label-col="labelCol"
|
||||
:wrapper-col="wrapperCol" :disabled="data.componentDisabled">
|
||||
<a-form-item label="节点标识">
|
||||
<a-input v-model:value="node.id" placeholder="请输入" readonly />
|
||||
</a-form-item>
|
||||
<a-alert message="并行网关说明"
|
||||
description="并行网关会等待所有分支汇入才往下执行,所有出口分支都会被执行" type="info"
|
||||
show-icon />
|
||||
</a-form>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted, nextTick, unref, h, watch, defineProps } from 'vue';
|
||||
import { getDetail } from '@/api/sys/WFSchemeInfo'
|
||||
const labelCol = { span: 7 };
|
||||
const wrapperCol = { span: 17 };
|
||||
const props = defineProps({
|
||||
element: Object,
|
||||
schemeCode: String,
|
||||
pageType: String,
|
||||
pageView: String,
|
||||
})
|
||||
const node = ref({
|
||||
id: ''
|
||||
})
|
||||
watch(
|
||||
() => props.element,
|
||||
(newVal, oldVal) => {
|
||||
console.log(newVal)
|
||||
if (newVal.type == "bpmn:ParallelGateway") {
|
||||
node.value.id = newVal.id
|
||||
node.value.type = newVal.type
|
||||
if (props.pageType == 'detail') {
|
||||
getNode()
|
||||
}
|
||||
if (props.schemeCode) {
|
||||
getDetailInfo()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const data = reactive({
|
||||
componentDisabled: props.pageType == 'detail' ? true : false
|
||||
})
|
||||
function getNode() {
|
||||
var content = JSON.parse(props.pageView)
|
||||
content.wfData.forEach(element => {
|
||||
if (element.id == node.value.id) {
|
||||
node.value = element
|
||||
}
|
||||
});
|
||||
}
|
||||
async function getDetailInfo() {
|
||||
let data = await getDetail({ code: props.schemeCode })
|
||||
let scheme = JSON.parse(data.scheme.content);
|
||||
let wfData = scheme.wfData
|
||||
wfData.forEach(element => {
|
||||
if (element.id == node.value.id) {
|
||||
node.value = element
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
onMounted(() => {
|
||||
if (props.schemeCode) {
|
||||
getDetailInfo()
|
||||
}
|
||||
if (props.pageType == 'detail') {
|
||||
getNode()
|
||||
}
|
||||
})
|
||||
function getForm() {
|
||||
return node.value
|
||||
}
|
||||
defineExpose({
|
||||
getForm
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
::v-deep .ant-alert-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
::v-deep .ant-table-wrapper {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -218,6 +218,14 @@
|
|||
node.value.authFields = node.value.authFields.filter(item => item.field !== key);
|
||||
}
|
||||
function getForm() {
|
||||
if(node.value.messageType != ""){
|
||||
if(node.value.messageType.length > 1){
|
||||
node.value.messageType = node.value.messageType.join(',')
|
||||
|
||||
}else{
|
||||
node.value.messageType = node.value.messageType[0]
|
||||
}
|
||||
}
|
||||
return node.value
|
||||
}
|
||||
defineExpose({
|
||||
|
|
|
|||
|
|
@ -334,7 +334,6 @@
|
|||
let wfData = scheme.wfData
|
||||
wfData.forEach(element => {
|
||||
if (element.id == node.value.id) {
|
||||
console.log(node)
|
||||
node.value = element
|
||||
}
|
||||
});
|
||||
|
|
@ -420,6 +419,11 @@
|
|||
}
|
||||
function getForm() {
|
||||
if (node.value.id != '') {
|
||||
if (node.value.overtimeMessageType.length > 1) {
|
||||
node.value.overtimeMessageType = node.value.overtimeMessageType.join(',')
|
||||
} else {
|
||||
node.value.overtimeMessageType = node.value.overtimeMessageType[0]
|
||||
}
|
||||
return node.value
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
<template>
|
||||
<div class="my-process-designer">
|
||||
<div class="my-process-designer__header">
|
||||
<slot name="control-header"></slot>
|
||||
<template v-if="!$slots['control-header']">
|
||||
<div slot="content">
|
||||
<a-space>
|
||||
<a-tooltip placement="bottom" class="ml-2" title="缩小视图">
|
||||
<a-button :disabled="data.defaultZoom <= 0.3" :icon="h(ZoomOutOutlined)" @click="processZoomOut()"></a-button>
|
||||
</a-tooltip>
|
||||
<a-button>{{ Math.floor(data.defaultZoom * 10 * 10) + "%" }}</a-button>
|
||||
<a-tooltip placement="bottom" title="放大视图">
|
||||
<a-button :disabled="data.defaultZoom >= 3.9" :icon="h(ZoomInOutlined)" @click="processZoomIn()"></a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-process-designer__container">
|
||||
<div class="my-process-designer__canvas" ref="bpmn-canvas" id="view"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import '@/components/ProcessDesigner/package/theme/index.scss';
|
||||
import { h, ref, provide, reactive, onMounted, defineProps, computed, defineEmits, onBeforeMount, watch } from 'vue';
|
||||
import { SaveOutlined, ZoomOutOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
|
||||
import BpmnViewer from 'bpmn-js/lib/Viewer'
|
||||
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
|
||||
const data = reactive({
|
||||
bpmnModeler: null,
|
||||
defaultZoom: 1,
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
xml: String
|
||||
})
|
||||
watch(
|
||||
() => props.xml,
|
||||
(newVal, oldVal) => {
|
||||
createDiagram(newVal)
|
||||
}
|
||||
)
|
||||
onMounted(() => {
|
||||
initBpmnModeler()
|
||||
createDiagram(props.xml)
|
||||
})
|
||||
function initBpmnModeler() {
|
||||
if (data.bpmnModerler) return
|
||||
const containerEl = document.getElementById('view')
|
||||
data.bpmnModerler && data.bpmnModerler.destroy() // 避免缓存
|
||||
data.bpmnModerler = new BpmnViewer({
|
||||
container: containerEl,
|
||||
additionalModules: [
|
||||
// 移动整个画布
|
||||
MoveCanvasModule
|
||||
],
|
||||
})
|
||||
}
|
||||
async function createDiagram(xml) {
|
||||
const viewer = data.bpmnModerler
|
||||
try {
|
||||
const result = await data.bpmnModerler.importXML(xml)
|
||||
const { warnings } = result
|
||||
if (warnings && warnings.length) {
|
||||
warnings.forEach(warn => console.warn(warn))
|
||||
}
|
||||
const canvas = viewer.get('canvas')
|
||||
canvas.zoom('fit-viewport')
|
||||
} catch (err) {
|
||||
console.log(err.message, err.warnings)
|
||||
}
|
||||
}
|
||||
function processZoomIn(zoomStep = 0.1) {
|
||||
let newZoom = Math.floor(data.defaultZoom * 100 + zoomStep * 100) / 100;
|
||||
if (newZoom > 4) {
|
||||
throw new Error("[Process Designer Warn ]: The zoom ratio cannot be greater than 4");
|
||||
}
|
||||
data.defaultZoom = newZoom;
|
||||
data.bpmnModerler.get("canvas").zoom(data.defaultZoom);
|
||||
}
|
||||
function processZoomOut(zoomStep = 0.1) {
|
||||
let newZoom = Math.floor(data.defaultZoom * 100 - zoomStep * 100) / 100;
|
||||
if (newZoom < 0.2) {
|
||||
throw new Error("[Process Designer Warn ]: The zoom ratio cannot be less than 0.2");
|
||||
}
|
||||
data.defaultZoom = newZoom;
|
||||
data.bpmnModerler.get("canvas").zoom(data.defaultZoom);
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.my-process-designer{
|
||||
width: 100%;
|
||||
}
|
||||
::v-deep .bjs-container a {
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -178,6 +178,7 @@
|
|||
"vxeTable": "VxeTable"
|
||||
},
|
||||
"workflow":{
|
||||
"scheme_preview":"流程模板设计"
|
||||
"scheme_preview":"流程模板设计",
|
||||
"create_preview":"流程发起"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const dashboard: AppRouteModule = {
|
|||
},
|
||||
{
|
||||
path: 'scheme_preview/:id',
|
||||
name: 'AccountDetail',
|
||||
name: 'SchemePreview',
|
||||
meta: {
|
||||
hideMenu: true,
|
||||
title: t('routes.demo.workflow.scheme_preview'),
|
||||
|
|
@ -35,6 +35,18 @@ const dashboard: AppRouteModule = {
|
|||
},
|
||||
component: () => import('@/views/demo/workflow/scheme/preview.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create_preview/:id',
|
||||
name: 'CreatePreview',
|
||||
meta: {
|
||||
hideMenu: true,
|
||||
title: t('routes.demo.workflow.create_preview'),
|
||||
ignoreKeepAlive: true,
|
||||
showMenu: false,
|
||||
currentActiveMenu: '/workflow/create',
|
||||
},
|
||||
component: () => import('@/views/demo/workflow/create/preview.vue'),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,21 @@ const hexList: string[] = [];
|
|||
for (let i = 0; i <= 15; i++) {
|
||||
hexList[i] = i.toString(16);
|
||||
}
|
||||
|
||||
export function buildGUID(): string {
|
||||
let guid = '';
|
||||
for (let i = 1; i <= 36; i++) {
|
||||
if (i === 9 || i === 14 || i === 19 || i === 24) {
|
||||
guid += '-';
|
||||
} else if (i === 15) {
|
||||
guid += 4;
|
||||
} else if (i === 20) {
|
||||
guid += hexList[(Math.random() * 4) | 8];
|
||||
} else {
|
||||
guid += hexList[(Math.random() * 16) | 0];
|
||||
}
|
||||
}
|
||||
return guid;
|
||||
}
|
||||
export function buildUUID(): string {
|
||||
let uuid = '';
|
||||
for (let i = 1; i <= 36; i++) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,105 @@
|
|||
<template>
|
||||
流程发起
|
||||
<PageWrapper :class="prefixCls">
|
||||
<div :class="`${prefixCls}__content`" v-for="item in cardList">
|
||||
<div :class="`${prefixCls}__list-title`">{{item.category}}【{{item.data.length}}】</div>
|
||||
<List>
|
||||
<Row :gutter="16">
|
||||
<template v-for="itemchild in item.data" :key="item.id">
|
||||
<Col :span="6">
|
||||
<List.Item>
|
||||
<Card :hoverable="true" :class="`${prefixCls}__card`" @click="launch(itemchild.code)">
|
||||
<div :class="`${prefixCls}__card-title`">
|
||||
<Icon class="icon" v-if="itemchild.icon" :icon="itemchild.icon" :color="itemchild.color" />
|
||||
{{ itemchild.name }}
|
||||
</div>
|
||||
</Card>
|
||||
</List.Item>
|
||||
</Col>
|
||||
</template>
|
||||
</Row>
|
||||
</List>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import Icon from '@/components/Icon/Icon.vue';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import { Card, Row, Col, List } from 'ant-design-vue';
|
||||
import { getInfoList } from '@/api/sys/WFSchemeInfo.ts'
|
||||
import { useGo } from '@/hooks/web/usePage';
|
||||
const go = useGo();
|
||||
const prefixCls = 'list-card';
|
||||
let cardList = ref()
|
||||
function launch(code){
|
||||
console.log(code)
|
||||
go('/dashboard/create_preview/add?code='+code);
|
||||
}
|
||||
async function getList() {
|
||||
let data = await getInfoList()
|
||||
let newArr = {}
|
||||
data.map(item => {
|
||||
newArr[item.category] = newArr[item.category] || []; //给category(可自行更换字段如name、sex等,根据自己的数据结构和需求)后加一个[]中括号
|
||||
newArr[item.category].push(item); //将所有的item列放入到对应的category中
|
||||
})
|
||||
let list = [];
|
||||
Object.keys(newArr).forEach(v => {
|
||||
let obj = {};
|
||||
obj.category = v;
|
||||
obj.data = newArr[v]
|
||||
list.push(obj);
|
||||
})
|
||||
cardList.value = list
|
||||
}
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.list-card {
|
||||
background-color: @component-background;
|
||||
|
||||
&__list-title {
|
||||
cursor: default;
|
||||
height: 32px;
|
||||
line-height: 17px;
|
||||
padding-top: 16px;
|
||||
color: @text-color-base;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&__card {
|
||||
width: 100%;
|
||||
margin-bottom: -8px;
|
||||
|
||||
.ant-card-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
margin-bottom: 5px;
|
||||
color: @text-color-base;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
|
||||
.icon {
|
||||
margin-top: -5px;
|
||||
margin-right: 10px;
|
||||
font-size: 38px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-detail {
|
||||
padding-top: 10px;
|
||||
padding-left: 30px;
|
||||
color: @text-color-secondary;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ant-list-item {
|
||||
padding: 12px 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
<template>
|
||||
<PageWrapper :class="prefixCls">
|
||||
<div class="btn-box">
|
||||
<a-button type="primary" :icon="h(SendOutlined)" @click="handleCreateFlow" class="ml-2">发起流程 </a-button>
|
||||
<a-button type="primary" :icon="h(SaveOutlined)" @click="handleSaveDraft" class="ml-2">保存草稿 </a-button>
|
||||
<a-button type="primary" :icon="h(CloseCircleOutlined)" @click="closePreview" class="ml-2" danger>关闭 </a-button>
|
||||
</div>
|
||||
<a-tabs v-model:activeKey="activeName">
|
||||
<a-tab-pane key="form" tab="表单信息">
|
||||
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="flow" tab="流程信息" force-render>
|
||||
<div class="process-design" :style="'display: flex; height:' + designerData.height">
|
||||
<process-viewer :key="`designer-${code}`" :xml="flowContent" />
|
||||
<div class="form-box"
|
||||
v-if="designerData.isCustmerTitle || (designerData.delegateUsers && designerData.delegateUsers.length >0)">
|
||||
<a-form ref="formRef" :model="formData" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-form-item ref="title" label="流程标题" name="title" v-if="designerData.isCustmerTitle">
|
||||
<a-input v-model:value="formData.title" />
|
||||
</a-form-item>
|
||||
<a-form-item label="流程发起人" name="userId"
|
||||
v-if="designerData.delegateUsers && designerData.delegateUsers.length >0">
|
||||
<a-select v-model:value="formData.userId" placeholder="请选择" :options="delegateUsers"></a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
|
||||
</PageWrapper>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, ref, provide, reactive, onMounted, defineProps, computed, defineEmits, onBeforeMount } from 'vue';
|
||||
import ProcessViewer from '@/components/ProcessViewer/index.vue';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
|
||||
import { SendOutlined, SaveOutlined, CloseCircleOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
|
||||
import { getDetail } from '@/api/sys/WFSchemeInfo'
|
||||
import { create ,saveDraft} from '@/api/sys/WFProcess'
|
||||
import { getLoadMyUserList } from '@/api/sys/WFDelegate'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { buildGUID } from '@/utils/uuid';
|
||||
|
||||
const userStore = useUserStore();
|
||||
console.log()
|
||||
const userInfo = userStore.getUserInfo
|
||||
const prefixCls = 'preview-box'
|
||||
const tabStore = useMultipleTabStore();
|
||||
const router = useRouter();
|
||||
const content = ref('')
|
||||
const flowContent = ref('')
|
||||
const route = useRoute()
|
||||
const code = route.query.code
|
||||
const designerOpen = ref(false)
|
||||
const formRef = ref();
|
||||
const labelCol = { span: 7 };
|
||||
const wrapperCol = { span: 13 };
|
||||
|
||||
const designerData = reactive({
|
||||
loading: false,
|
||||
xmlString: '',
|
||||
controlForm: {
|
||||
prefix: 'flowable',
|
||||
},
|
||||
height: document.documentElement.clientHeight - 230.5 + "px;",
|
||||
midVisible: false,
|
||||
isCustmerTitle: false,
|
||||
nodeUsers: [],
|
||||
selectUsersVisible: false,
|
||||
|
||||
isDraft: false,
|
||||
delegateUsers: []
|
||||
})
|
||||
const activeName = ref('flow')
|
||||
const modelDesigner = ref < any > ()
|
||||
|
||||
const formData = reactive({
|
||||
userId: '',
|
||||
title: ''
|
||||
})
|
||||
const rules = reactive({
|
||||
title: [
|
||||
{ required: true, message: '请选择流程标题', trigger: 'blur' }
|
||||
],
|
||||
userId: [
|
||||
{ required: true, message: '请选择流程发起人', trigger: 'blur' }
|
||||
],
|
||||
})
|
||||
async function getDetailInfo() {
|
||||
let data = await getDetail({ code: code })
|
||||
flowContent.value = data.scheme.flowContent
|
||||
formData.userId = userInfo.account
|
||||
let content = JSON.parse(data.scheme.content)
|
||||
let wfData = content.wfData
|
||||
const currentNode = wfData.find(t => t.type == "bpmn:StartEvent")
|
||||
console.log(currentNode)
|
||||
designerData.isCustmerTitle = currentNode.isCustmerTitle
|
||||
}
|
||||
async function getDelegateUsers() {
|
||||
const data = await getLoadMyUserList({
|
||||
code: code
|
||||
})
|
||||
console.log(data)
|
||||
designerData.delegateUsers = data
|
||||
}
|
||||
async function handleSaveDraft() {
|
||||
|
||||
}
|
||||
async function handleCreateFlow() {
|
||||
var querys = {
|
||||
schemeCode: designerData.isDraft ? '' : code,
|
||||
userId: formData.userId,
|
||||
title: formData.title,
|
||||
processId: buildGUID()
|
||||
|
||||
}
|
||||
if (!designerData.isDraft) {
|
||||
await saveDraft(querys)
|
||||
querys.schemeCode = ''
|
||||
designerData.isDraft = true
|
||||
}
|
||||
console.log(querys)
|
||||
const data = await create(querys)
|
||||
closePreview()
|
||||
}
|
||||
|
||||
function closePreview() {
|
||||
if (!code) {
|
||||
tabStore.closeTabByKey('/dashboard/create_preview/add', router);
|
||||
} else {
|
||||
// /dashboard/create_preview/add?code=测试1
|
||||
tabStore.closeTabByKey('/dashboard/create_preview/add?code=' + code, router);
|
||||
}
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
getDetailInfo()
|
||||
getDelegateUsers()
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.preview-box {
|
||||
background-color: @component-background;
|
||||
|
||||
.btn-box {
|
||||
padding: 10px;
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 480px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
</BasicDrawer>
|
||||
<a-modal width="90%" height="80%" v-model:open="postOpen" title="流程模板预览" @ok="postHandleOk">
|
||||
<process-designer :key="designerOpen" style="border:1px solid rgba(0, 0, 0, 0.1);" ref="modelDesigner"
|
||||
v-loading="designerData.loading" :schemeCode="schemeCode" :pageFlow="flowContent" :pageView="content" :pageType="'detail'"
|
||||
v-loading="designerData.loading" :pageFlow="flowContent" :pageView="content" :pageType="'detail'"
|
||||
@save="onSaveDesigner" />
|
||||
</a-modal>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue