init
This commit is contained in:
27
src/views/workflow/process/nodes/AddBranchNode.vue
Normal file
27
src/views/workflow/process/nodes/AddBranchNode.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<el-button v-if="mode === 'design'" size="small" round class="add-branch-btn-el" @click="emit('addBranch')">{{value}}</el-button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {defineEmits,defineProps,computed} from "vue";
|
||||
const emit = defineEmits()
|
||||
const props = defineProps({
|
||||
value:{
|
||||
type:String,
|
||||
default: ""
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
|
||||
const viewer = computed(() => {
|
||||
return false;
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
200
src/views/workflow/process/nodes/ApprovalNode.vue
Normal file
200
src/views/workflow/process/nodes/ApprovalNode.vue
Normal file
@@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<node :title="config.name" :show-error="showError" :content="content"
|
||||
:show-avatar="config.props.assignedType === 'ASSIGN_USER'" :user-info="assignedUser"
|
||||
:error-info="errorInfo"
|
||||
:select-user="selectUser"
|
||||
:mode="mode"
|
||||
@selected="emit('selected')" @delNode="emit('delNode')" @insertNode="type => emit('insertNode', type)"
|
||||
placeholder="请设置审批人" :header-bgc="headerBgc" :header-icon="Stamp"/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Node from './Node.vue'
|
||||
import {computed, defineExpose} from 'vue'
|
||||
import {Stamp} from '@element-plus/icons-vue'
|
||||
const emit = defineEmits(['insertNode', 'selected', 'delNode'])
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
|
||||
const showError = ref(false)
|
||||
const errorInfo = ref('')
|
||||
|
||||
|
||||
const selectUser = computed(() => {
|
||||
return {
|
||||
show: props.config.props.assignedType === 'SELF_SELECT',
|
||||
multiple: props.config.props.selfSelect.multiple
|
||||
};
|
||||
})
|
||||
|
||||
const assignedUser = computed(() => {
|
||||
if (props.config.props.assignedType === 'SELF_SELECT') {
|
||||
props.config.props.assignedUser = []
|
||||
}
|
||||
return props.config.props.assignedUser;
|
||||
})
|
||||
|
||||
const headerBgc = computed(() => {
|
||||
if (props.mode === 'design' || props.mode === 'view') {
|
||||
return '#ff943e'
|
||||
} else {
|
||||
return props.config.props.headerBgc
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const content = computed(() => {
|
||||
const config = props.config.props
|
||||
switch (config.assignedType) {
|
||||
case "ASSIGN_USER":
|
||||
if (config.assignedUser.length > 0) {
|
||||
let texts = []
|
||||
config.assignedUser.forEach(org => texts.push(org.name))
|
||||
return String(texts).replaceAll(',', '、')
|
||||
} else {
|
||||
return '请指定审批人'
|
||||
}
|
||||
case "SELF":
|
||||
return '发起人自己'
|
||||
case "SELF_SELECT":
|
||||
return config.selfSelect.multiple ? '发起人自选多人' : '发起人自选一人'
|
||||
case "LEADER_TOP":
|
||||
return '多级主管依次审批'
|
||||
case "LEADER":
|
||||
return config.leader.level > 1 ? '发起人的第 ' + config.leader.level + ' 级主管' : '发起人的直接主管'
|
||||
case "FORM_USER":
|
||||
if (!config.formUser || config.formUser === '') {
|
||||
return '表单内联系人(未选择)'
|
||||
} else {
|
||||
// let text = getFormItemById(config.formUser)
|
||||
if (text && text.title) {
|
||||
return `表单(${text.title})内的人员`
|
||||
} else {
|
||||
return '该表单已被移除😥'
|
||||
}
|
||||
}
|
||||
case "ROLE":
|
||||
if (config.roleList.length > 0) {
|
||||
return config.roleList.map(role => {
|
||||
return role.roleName;
|
||||
}).join("、")
|
||||
} else {
|
||||
return '指定角色(未设置)'
|
||||
}
|
||||
default:
|
||||
return '未知设置项😥'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
//校验数据配置的合法性
|
||||
const validate = (err) => {
|
||||
try {
|
||||
console.log(props.config.props.assignedType)
|
||||
switch (props.config.props.assignedType) {
|
||||
case "ASSIGN_USER":
|
||||
showError.value = !validate_ASSIGN_USER(err);
|
||||
break;
|
||||
case "SELF":
|
||||
showError.value = !validate_SELF(err);
|
||||
break;
|
||||
case "SELF_SELECT":
|
||||
showError.value = !validate_SELF_SELECT(err);
|
||||
console.log(showError.value);
|
||||
break;
|
||||
case "LEADER_TOP":
|
||||
showError.value = !validate_LEADER_TOP(err);
|
||||
break;
|
||||
case "LEADER":
|
||||
showError.value = !validate_LEADER(err);
|
||||
break;
|
||||
case "FORM_USER":
|
||||
showError.value = !validate_FORM_USER(err);
|
||||
break;
|
||||
case "ROLE":
|
||||
showError.value = !validate_ROLE(err);
|
||||
break;
|
||||
default:
|
||||
showError.value = true
|
||||
err.push("未知设置项😥")
|
||||
break;
|
||||
}
|
||||
if (props.config.props.nobody.handler === 'TO_USER' && props.config.props.nobody.assignedUser.length === 0) {
|
||||
errorInfo.value = '审批人为空时, 转交给指定人员:【请指定一个具体的人】'
|
||||
err.push('审批人为空时, 转交给指定人员:【请指定一个具体的人】')
|
||||
showError.value = true
|
||||
}
|
||||
return showError
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const validate_ASSIGN_USER = (err) => {
|
||||
if (props.config.props.assignedUser.length > 0) {
|
||||
return true;
|
||||
} else {
|
||||
errorInfo.value = '请指定审批人员'
|
||||
err.push(`${props.config.name} 未指定审批人员`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
const validate_SELF_SELECT = (err) => {
|
||||
// if (!this.viewer) {
|
||||
// return true
|
||||
// }
|
||||
// let userInfo = this.$store.state.selectUserMap.get(this.config.id);
|
||||
// if (undefined !== userInfo && Array.isArray(userInfo) && userInfo.length > 0) {
|
||||
// return true;
|
||||
// }
|
||||
errorInfo.value = '请指定审批人员'
|
||||
err.push(`${props.config.name} 未指定审批人员`)
|
||||
return false;
|
||||
}
|
||||
const validate_LEADER_TOP = (err) => {
|
||||
return true;
|
||||
}
|
||||
const validate_LEADER = (err) => {
|
||||
return true;
|
||||
}
|
||||
const validate_ROLE = (err) => {
|
||||
if (props.config.props.roleList.length <= 0) {
|
||||
errorInfo.value = '请指定负责审批的系统角色'
|
||||
err.push(`${props.config.name} 未指定审批角色`)
|
||||
return false
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const validate_SELF = (err) => {
|
||||
return true;
|
||||
}
|
||||
const validate_FORM_USER = (err) => {
|
||||
if (props.config.props.formUser === '') {
|
||||
errorInfo.value = '请指定表单中的人员组件'
|
||||
err.push(`${props.config.name} 审批人为表单中人员,但未指定`)
|
||||
return false
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const validate_REFUSE = (err) => {
|
||||
return true;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
validate
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
75
src/views/workflow/process/nodes/CcNode.vue
Normal file
75
src/views/workflow/process/nodes/CcNode.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<node :title="config.name" :show-error="showError" :select-user="selectUser" :mode="mode" :content="content" :node-id="config.id"
|
||||
:error-info="errorInfo" :show-avatar="true" :user-info="config.props.assignedUser"
|
||||
@selected="emit('selected')" @delNode="emit('delNode')" @insertNode="type => emit('insertNode', type)"
|
||||
placeholder="请设置抄送人" :header-bgc="headerBgc" :header-icon="Promotion"/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Node from './Node.vue'
|
||||
import {defineProps, defineEmits, computed, defineExpose} from "vue";
|
||||
const emit = defineEmits(['insertNode', 'selected', 'delNode'])
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
const showError = ref(false)
|
||||
const errorInfo = ref('')
|
||||
import {Promotion} from '@element-plus/icons-vue'
|
||||
|
||||
const headerBgc = computed(() => {
|
||||
if (props.mode === 'design' || props.mode === 'view') {
|
||||
return '#3296fa'
|
||||
} else {
|
||||
return props.config.props.headerBgc
|
||||
}
|
||||
})
|
||||
|
||||
const selectUser = computed(() => {
|
||||
return {
|
||||
show: props.config.props.assignedType !== 'ASSIGN_USER' && props.config.props.shouldAdd,
|
||||
multiple: true
|
||||
};
|
||||
})
|
||||
|
||||
const content = computed(() => {
|
||||
if (props.config.props.shouldAdd) {
|
||||
return '由发起人指定'
|
||||
} else if (props.config.props.assignedUser.length > 0) {
|
||||
let texts = []
|
||||
props.config.props.assignedUser.forEach(org => texts.push(org.name))
|
||||
return String(texts).replaceAll(',', '、')
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})
|
||||
//校验数据配置的合法性
|
||||
const validate = (err) => {
|
||||
showError.value = false
|
||||
if (props.config.props.shouldAdd) {
|
||||
showError.value = false
|
||||
} else if (props.config.props.assignedUser.length === 0) {
|
||||
showError.value = true
|
||||
errorInfo.value = '请选择需要抄送的人员'
|
||||
}
|
||||
if (showError.value) {
|
||||
err.push(`抄送节点 ${props.config.name} 未设置抄送人`)
|
||||
}
|
||||
return !showError.value
|
||||
}
|
||||
defineExpose({
|
||||
validate
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
195
src/views/workflow/process/nodes/ConcurrentNode.vue
Normal file
195
src/views/workflow/process/nodes/ConcurrentNode.vue
Normal file
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<div class="node">
|
||||
<!-- 并行分支选择后右侧出现操作面板,占时不需要 <div class="node-body" @click="emit('selected')">-->
|
||||
<div v-if="designState" class="node-body" @click="emit('selected')">
|
||||
<div class="node-body-left" @click.stop="emit('leftMove')" v-if="level > 1">
|
||||
<el-icon>
|
||||
<ArrowLeftBold/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="node-body-main">
|
||||
<div class="node-body-main-header">
|
||||
<span class="title">
|
||||
<el-icon :size="15">
|
||||
<Operation/>
|
||||
</el-icon>
|
||||
<ellipsis class="name" hover-tip :content="config.name ? config.name:('并行任务' + level)"/>
|
||||
</span>
|
||||
<span class="option">
|
||||
<el-tooltip effect="dark" content="复制分支" placement="top">
|
||||
<el-icon @click.stop="emit('copy')" :size="20">
|
||||
<CopyDocument/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-icon @click.stop="emit('delNode')" :size="20">
|
||||
<CloseBold/>
|
||||
</el-icon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="node-body-main-content">
|
||||
<span>并行任务(同时进行)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node-body-right" @click.stop="emit('rightMove')" v-if="level < size && designState ">
|
||||
<el-icon>
|
||||
<ArrowRightBold/>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node-footer">
|
||||
<div class="btn" :style="(designState ? '' : 'height:0px')">
|
||||
<insert-button v-if="designState" @insertNode="type => emit('insertNode', type)"></insert-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!--并行节点-->
|
||||
<script setup>
|
||||
import InsertButton from '../common/InsertButton.vue'
|
||||
import {Operation, ArrowRightBold, ArrowLeftBold, CopyDocument, CloseBold, Warning} from '@element-plus/icons-vue'
|
||||
import Ellipsis from '../common/Ellipsis.vue'
|
||||
import {defineProps, defineEmits} from "vue";
|
||||
|
||||
const emit = defineEmits(['insertNode'])
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
level: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
//条件数
|
||||
size: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
const designState = computed(()=>{
|
||||
return props.mode === 'design'
|
||||
})
|
||||
const designStart = () => {
|
||||
// return this.$store.state.diagramMode === 'design'
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
.node {
|
||||
padding: 30px 55px 0;
|
||||
//width: 220px;
|
||||
width: 320px;
|
||||
|
||||
.node-body {
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
min-height: 80px;
|
||||
max-height: 120px;
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
background-color: white;
|
||||
box-shadow: 0px 0px 5px 0px #d8d8d8;
|
||||
|
||||
&:hover {
|
||||
.node-body-left, .node-body-right {
|
||||
i {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
|
||||
.node-body-main {
|
||||
.option {
|
||||
display: inline-block !important;
|
||||
}
|
||||
}
|
||||
|
||||
box-shadow: 0px 0px 3px 0px;
|
||||
}
|
||||
|
||||
.node-body-left, .node-body-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #ececec;
|
||||
}
|
||||
}
|
||||
|
||||
.node-body-left {
|
||||
color: #888888;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.node-body-right {
|
||||
color: #888888;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.node-body-main {
|
||||
position: absolute;
|
||||
width: 188px;
|
||||
left: 17px;
|
||||
display: inline-block;
|
||||
|
||||
.node-body-main-header {
|
||||
padding: 10px 0px 5px;
|
||||
font-size: xx-small;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
color: #718dff;
|
||||
|
||||
.name {
|
||||
display: inline-block;
|
||||
height: 14px;
|
||||
width: 130px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.option {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
display: none;
|
||||
font-size: medium;
|
||||
|
||||
i {
|
||||
color: #888888;
|
||||
padding: 0 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.node-body-main-content {
|
||||
padding: 6px;
|
||||
color: #656363;
|
||||
font-size: 14px;
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 55%;
|
||||
right: 10px;
|
||||
font-size: medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
299
src/views/workflow/process/nodes/ConditionNode.vue
Normal file
299
src/views/workflow/process/nodes/ConditionNode.vue
Normal file
@@ -0,0 +1,299 @@
|
||||
<template>
|
||||
<div :class="{'node': true, 'node-error-state': showError}">
|
||||
<div :class="{'node-body': true, 'error': showError}">
|
||||
<div class="node-body-left" @click="emit('leftMove')" v-if="level > 1 && designState">
|
||||
<el-icon>
|
||||
<ArrowLeftBold/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="node-body-main" @click="emit('selected')">
|
||||
<div class="node-body-main-header">
|
||||
<ellipsis class="title" hover-tip :content="config.name ? config.name : ('条件' + level)"/>
|
||||
<span class="level">优先级{{ level }}</span>
|
||||
<span class="option" v-if="designState">
|
||||
<el-tooltip effect="dark" content="复制条件" placement="top">
|
||||
<el-icon @click.stop="emit('copy')" :size="20">
|
||||
<CopyDocument/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-icon @click.stop="emit('delNode')" :size="20">
|
||||
<CloseBold/>
|
||||
</el-icon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="node-body-main-content">
|
||||
<span class="placeholder" v-if="(content || '').trim() === ''">{{ placeholder }}</span>
|
||||
<ellipsis hoverTip :row="4" :content="content" v-else/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node-body-right" @click="emit('rightMove')" v-if="level < size && designState">
|
||||
<el-icon>
|
||||
<ArrowRightBold/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="node-error" v-if="showError">
|
||||
<el-tooltip effect="dark" :content="errorInfo" placement="top-start">
|
||||
<el-icon>
|
||||
<Warning/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node-footer">
|
||||
<div class="btn">
|
||||
<insert-button v-if="designState" @insertNode="type => emit('insertNode', type)"></insert-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import InsertButton from '../common/InsertButton.vue'
|
||||
import Ellipsis from '../common/Ellipsis.vue'
|
||||
import {ValueType} from '@/views/workflow/form/ComponentsConfigExport.js'
|
||||
import {ArrowRightBold,ArrowLeftBold,CopyDocument,CloseBold,Warning} from '@element-plus/icons-vue'
|
||||
import {defineProps, defineEmits, defineExpose} from "vue";
|
||||
const emit = defineEmits()
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
//索引位置
|
||||
level: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
//条件数
|
||||
size: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
|
||||
const groupNames = ref(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']);
|
||||
const placeholder = ref('请设置条件');
|
||||
const errorInfo = ref('');
|
||||
const showError = ref(false);
|
||||
const content = computed(() => {
|
||||
const groups = props.config.props.groups
|
||||
let confitions = []
|
||||
groups.forEach(group => {
|
||||
let subConditions = []
|
||||
group.conditions.forEach(subCondition => {
|
||||
let subConditionStr = ''
|
||||
switch (subCondition.valueType) {
|
||||
case ValueType.dept:
|
||||
case ValueType.user:
|
||||
subConditionStr = `${subCondition.title}属于[${String(subCondition.value.map(u => u.name)).replaceAll(',', '. ')}]之一`
|
||||
break;
|
||||
case ValueType.number:
|
||||
case ValueType.string:
|
||||
subConditionStr = getOrdinaryConditionContent(subCondition)
|
||||
break;
|
||||
}
|
||||
subConditions.push(subConditionStr)
|
||||
})
|
||||
//根据子条件关系构建描述
|
||||
let subConditionsStr = String(subConditions)
|
||||
.replaceAll(',', subConditions.length > 1 ?
|
||||
(group.groupType === 'AND' ? ') 且 (' : ') 或 (') :
|
||||
(group.groupType === 'AND' ? ' 且 ' : ' 或 '))
|
||||
confitions.push(subConditions.length > 1 ? `(${subConditionsStr})` : subConditionsStr)
|
||||
})
|
||||
//构建最终描述
|
||||
return String(confitions).replaceAll(',', (props.config.props.groupsType === 'AND' ? ' 且 ' : ' 或 '))
|
||||
})
|
||||
|
||||
const designState = computed(()=>{
|
||||
return props.mode === 'design'
|
||||
})
|
||||
|
||||
|
||||
const getDefault = (val, df) => {
|
||||
return val && val !== '' ? val : df;
|
||||
}
|
||||
|
||||
|
||||
const getOrdinaryConditionContent = (subCondition) => {
|
||||
switch (subCondition.compare) {
|
||||
case 'IN':
|
||||
return `${subCondition.title}为[${String(subCondition.value).replaceAll(',', '、')}]中之一`
|
||||
case 'B':
|
||||
return `${subCondition.value[0]} < ${subCondition.title} < ${subCondition.value[1]}`
|
||||
case 'AB':
|
||||
return `${subCondition.value[0]} ≤ ${subCondition.title} < ${subCondition.value[1]}`
|
||||
case 'BA':
|
||||
return `${subCondition.value[0]} < ${subCondition.title} ≤ ${subCondition.value[1]}`
|
||||
case 'ABA':
|
||||
return `${subCondition.value[0]} ≤ ${subCondition.title} ≤ ${subCondition.value[1]}`
|
||||
case '<=':
|
||||
return `${subCondition.title} ≤ ${getDefault(subCondition.value[0], ' ?')}`
|
||||
case '>=':
|
||||
return `${subCondition.title} ≥ ${getDefault(subCondition.value[0], ' ?')}`
|
||||
default:
|
||||
return `${subCondition.title}${subCondition.compare}${getDefault(subCondition.value[0], ' ?')}`
|
||||
}
|
||||
}
|
||||
|
||||
//校验数据配置的合法性
|
||||
const validate = (err) => {
|
||||
const defineProps = props.config.props
|
||||
if (defineProps.groups.length <= 0){
|
||||
showError.value = true
|
||||
errorInfo.value = '请设置分支条件'
|
||||
err.push(`${defineProps.config.name} 未设置条件`)
|
||||
}else {
|
||||
for (let i = 0; i < defineProps.groups.length; i++) {
|
||||
if (defineProps.groups[i].cids.length === 0){
|
||||
showError.value = true
|
||||
errorInfo.value = `请设置条件组${groupNames.value[i]}内的条件`
|
||||
err.push(`条件 ${props.config.name} 条件组${groupNames.value[i]}内未设置条件`)
|
||||
break
|
||||
}else {
|
||||
let conditions = defineProps.groups[i].conditions
|
||||
for (let ci = 0; ci < conditions.length; ci++) {
|
||||
let subc = conditions[ci]
|
||||
showError.value = subc.value.length === 0;
|
||||
if (showError.value){
|
||||
errorInfo.value = `请完善条件组${groupNames.value[i]}内的${subc.title}条件`
|
||||
err.push(`条件 ${props.config.name} 条件组${groupNames.value[i]}内${subc.title}条件未完善`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return !showError.value
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
validate
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.node {
|
||||
padding: 30px 55px 0;
|
||||
//width: 220px;
|
||||
width: 320px;
|
||||
|
||||
.node-body {
|
||||
cursor: pointer;
|
||||
min-height: 80px;
|
||||
max-height: 120px;
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
background-color: white;
|
||||
box-shadow: 0px 0px 5px 0px #d8d8d8;
|
||||
|
||||
&:hover {
|
||||
.node-body-left, .node-body-right {
|
||||
i {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
|
||||
.node-body-main {
|
||||
.level {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.option {
|
||||
display: inline-block !important;
|
||||
}
|
||||
}
|
||||
|
||||
box-shadow: 0px 0px 3px 0px;
|
||||
}
|
||||
|
||||
.node-body-left, .node-body-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #ececec;
|
||||
}
|
||||
}
|
||||
|
||||
.node-body-left {
|
||||
color: #888888;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.node-body-right {
|
||||
color: #888888;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.node-body-main {
|
||||
//position: absolute;
|
||||
width: 188px;
|
||||
margin-left: 17px;
|
||||
display: inline-block;
|
||||
|
||||
.node-body-main-header {
|
||||
padding: 10px 0px 5px;
|
||||
font-size: xx-small;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
color: #15bca3;
|
||||
display: inline-block;
|
||||
height: 14px;
|
||||
width: 125px;
|
||||
}
|
||||
|
||||
.level {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.option {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
display: none;
|
||||
font-size: medium;
|
||||
|
||||
i {
|
||||
color: #888888;
|
||||
padding: 0 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.node-body-main-content {
|
||||
padding: 6px;
|
||||
color: #656363;
|
||||
font-size: 14px;
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 55%;
|
||||
right: 10px;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #8c8c8c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
86
src/views/workflow/process/nodes/DelayNode.vue
Normal file
86
src/views/workflow/process/nodes/DelayNode.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<node :title="config.name" :mode="mode" :show-error="showError" :content="content" :error-info="errorInfo"
|
||||
@selected="emit('selected')" @delNode="emit('delNode')" @insertNode="type => emit('insertNode', type)"
|
||||
placeholder="请设置延时时间" :header-bgc="headerBgc" :header-icon="Clock"/>
|
||||
</template>
|
||||
<!--延时器节点-->
|
||||
<script setup>
|
||||
import Node from './Node.vue'
|
||||
import {defineProps, defineEmits, computed, defineExpose} from "vue";
|
||||
const emit = defineEmits()
|
||||
import {Clock} from '@element-plus/icons-vue'
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const showError = ref(false)
|
||||
const errorInfo = ref('')
|
||||
|
||||
|
||||
const headerBgc = computed(() => {
|
||||
if (props.mode === 'design' || props.mode === 'view') {
|
||||
return '#f25643'
|
||||
} else {
|
||||
return props.config.props.headerBgc
|
||||
}
|
||||
})
|
||||
|
||||
const content = computed(() => {
|
||||
if (props.config.props.type === 'FIXED') {
|
||||
return `等待 ${props.config.props.time} ${getName(props.config.props.unit)}`
|
||||
} else if (props.config.props.type === 'AUTO') {
|
||||
return `至当天 ${props.config.props.dateTime}`
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})
|
||||
//校验数据配置的合法性
|
||||
const validate = (err) => {
|
||||
showError.value = false
|
||||
try {
|
||||
if (props.config.props.type === "AUTO") {
|
||||
if ((props.config.props.dateTime || "") === "") {
|
||||
showError.value = true
|
||||
errorInfo.value = "请选择时间点"
|
||||
}
|
||||
} else {
|
||||
if (props.config.props.time <= 0) {
|
||||
showError.value = true
|
||||
errorInfo.value = "请设置延时时长"
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
showError.value = true
|
||||
errorInfo.value = "配置出现问题"
|
||||
}
|
||||
if (showError) {
|
||||
err.push(`${props.config.name} 未设置延时规则`)
|
||||
}
|
||||
return !showError
|
||||
}
|
||||
const getName = (unit) => {
|
||||
switch (unit) {
|
||||
case 'D':
|
||||
return '天';
|
||||
case 'H':
|
||||
return '小时';
|
||||
case 'M':
|
||||
return '分钟';
|
||||
default:
|
||||
return '未知';
|
||||
}
|
||||
}
|
||||
defineExpose({
|
||||
validate
|
||||
})
|
||||
</script>
|
||||
20
src/views/workflow/process/nodes/EmptyNode.vue
Normal file
20
src/views/workflow/process/nodes/EmptyNode.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<node :show="false" :mode="mode" @insertNode="type => emit('insertNode', type)"/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Node from './Node.vue'
|
||||
import {defineEmits,defineProps} from "vue";
|
||||
|
||||
const emit = defineEmits()
|
||||
const props = defineProps({
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
20
src/views/workflow/process/nodes/MergeNode.vue
Normal file
20
src/views/workflow/process/nodes/MergeNode.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<node :show="false" :merge="true" :mode="mode" @insertNode="type => emit('insertNode', type)"/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Node from './Node.vue'
|
||||
import {defineEmits, defineProps} from "vue";
|
||||
const emit = defineEmits()
|
||||
|
||||
const props = defineProps({
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
269
src/views/workflow/process/nodes/Node.vue
Normal file
269
src/views/workflow/process/nodes/Node.vue
Normal file
@@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<div :class="{'node': true, 'root': isRoot || !show, 'node-error-state': showError}">
|
||||
<div v-if="show" @click="emit('selected')" :class="{'node-body': true, 'error': showError}">
|
||||
<div class="node-body-header" :style="{'background-color': headerBgc}">
|
||||
<el-icon v-if="headerIcon" size="15">
|
||||
<component :is="headerIcon"/>
|
||||
</el-icon>
|
||||
<ellipsis class="name" hover-tip :content="title"/>
|
||||
<el-icon v-if="!isRoot && designState" size="15" style="float:right;" @click="emit('delNode')">
|
||||
<Close/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="node-body-content">
|
||||
<el-icon v-if="leftIcon">
|
||||
<component :is="leftIcon"/>
|
||||
</el-icon>
|
||||
<template v-if="selectUser.show && mode === 'view'">
|
||||
<div class="avatar_button">
|
||||
<avatar-ellipsis :row="3" v-if="userInfo.length > 0" :user-info="userInfo"/>
|
||||
<el-button type="primary" :icon="Plus" circle/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="showAvatar">
|
||||
<span class="placeholder" v-if="userInfo.length === 0">{{ placeholder }}</span>
|
||||
<avatar-ellipsis :row="3" :user-info="userInfo" v-else/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="placeholder" v-if="(content || '').trim() === ''">{{ placeholder }}</span>
|
||||
<ellipsis :row="3" :content="content" v-else/>
|
||||
</template>
|
||||
</div>
|
||||
<div class="node-error" v-if="showError">
|
||||
<el-tooltip effect="dark" :content="errorInfo" placement="top-start">
|
||||
<el-icon><Warning /></el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="node-footer">
|
||||
<div v-if="merge" class="branch-merge">
|
||||
<img data-v-1e7b1da5=""
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAABXlJREFUeF7tmm2IVGUUx3/nLkQUqxmkpAVhSPUllZX8EEGhvVgZQWCU6wcpsqi2mXtnoaBwoqLCufeO9oJYUJQiFZWlZPQCfYiIXkylstTyS1oWWeYWCe6cuLsz7t3r3Ll3du6907oz35bnPM9z/r895zznmWeECf6RCa6fDoBOBExwAp0UmOAB0CmCnRTopECbCZi2nivK1CMD7FpXlH+ydqctKZBz9QyjwkqFG4HzfKK/0gpvl/ulmBWIzAHkVmlRDFY2EihwwLFkRhYQxgzAtHW2CpcBc4CpOsg26eK7yVPYVFwu/9ZzPufq2VLhQBxhAk85lvSF2Y5l/3prjQlAvqR3IjwJTKqz6DeGssQuyLfBsbyjz6PcFgeAZyOwzLFk/QnrjHH/RACYtj6ncHuUCDWYXs7Lz367XEn3inB+1NzauMLGsiW3+u1b2b9lAH22LuiCD2IJED5yTbmiZpt3dAbKT7Hmjhjtdi25oPZnK/uH7dtUCpi2vqVwQ1wRWuHhWkW3StpTEb6IO3fIThhwTemuzWll/0QA5G39FTgrtghhs2vKELA7inra6d38HXvusOEnriWXHo+iFvZvGUDfap3VdYzdzQgIHmd5W7cBc2Ovoax1C3KXZ5/E/i3VgCQciNMD+J1Ug55yXjxo7QfgOdFKCvjyeL/C9MgoEBa5przrt0ti/+C+mRVB/8amrWsU7m2Ql/c5lqwJjre9CDZ1DMFnriXzw0SatvZW4FqBW6o2vwGvCGxyLPmw3rym9g8cwy0XQV8Ix2qEgH0C1ziWNCyceVu1uvZrriVLGqVGsainHO7mRyDynlCvEWupCI7Kxcat6BFg+OwW9ohyfSMIcQF44v/sZovAlRH1I7QVTwyAt1Cjy8hfh9hYvepGQogDoI74HYbSXzHwusTYl7FEAURVcdPWN+NAiAJQTzzCda4p+6N8iDPe1CkQZ8FAtY+E0AhA2uKHszTlT1QkhAHIQnwmAKr1IjQS6gHISnxmABpBCALIUnymAMIgKHxf6wMmH6E3cNTtSLLgZXoKNOgAR6UDyqyq7esKk3znfOriM48AXzc5AmGE1EFgWvXPTMS3DcAJ6TA6XDIT31YAoRCEc5JqcuKc8Kn3AVFO+E4BryvJVHzbI8BzwAdgi2vJ4ihgSY//nyIg8jqctPi2RYBp61wV5qsyR2BFVdhBhBe0wtdisNU15VAagoNrZh4BOVsfFcVCODVUoLBn6E2hIBvShpApgLyt3nvhRXFFCWxwLOmNaz8Wu8wA5G31ntQWNOukwD2OJc80Oy+ufSYAciVdJsJLcZ0K2nV1MbuUk51jnd9oXuoACmW9eHCQj49/T+j3RtiJslPgFxXmoVxe11nhPdeUq8clANPWPoXVQef9D6e1saEHVINHUBYF7Q1lnl2QL5OGkHoE5G19GRhVyBQ+L1tyST0xoa/Iygq3IOvGI4BdwIWjHBeecE15IExM3tYfgJmBOetcU2o9Q2IcsoiAw8Gf0qhyU7kgb4QCcPRTlNGvSspmtzD81J7kJ30AJX0fYeHo2seLjiXLG0TA78CZ/nGFB8uWPJakeG+t9AE4+jjK/XGLWtgTusBix5It4w5ArqRLRTjhl14IW40KD/kre66ki0R4p57IrgozS/2yb9wByDvqhbKX07Xv/oIavMfOP6pFb0pdgcqrbkFuTlp8JingbRIaBfEUHUOYltbtMPUaUNNo2rpeYWk8zSNWqvSmeSvMDIAnybT1boWnY0I4aigL7YJ4bXRqn0wBeCqG7gYVVqFcFapKWXt0gP5nizKQmvLqwpkDqAkaanmhB4MelOkI27XCDjHY7pqyN23htfXbBiArgVH7dABEETrZxzsRcLL/h6P0/Qc1qphfvB2K3wAAAABJRU5ErkJggg=="
|
||||
alt="">
|
||||
</div>
|
||||
<div class="btn">
|
||||
<insert-button v-if="designState" @insertNode="type => emit('insertNode', type)"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <user-picker v-if="selectUser.show" title="请选择系统用户" :multiple="selectUser.multiple" ref="userPicker"-->
|
||||
<!-- :selected="_userInfo"-->
|
||||
<!-- @ok="selectedUser"/>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import InsertButton from '../common/InsertButton.vue'
|
||||
import Ellipsis from '../common/Ellipsis.vue'
|
||||
import AvatarEllipsis from '../common/AvatarEllipsis.vue'
|
||||
import {defineProps,defineEmits} from "vue";
|
||||
const emit = defineEmits(['insertNode'])
|
||||
import {Close,Warning,Plus} from '@element-plus/icons-vue'
|
||||
const props = defineProps({
|
||||
//是否为根节点
|
||||
isRoot: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
nodeId:{
|
||||
type:String,
|
||||
default:()=>{
|
||||
return "";
|
||||
}
|
||||
},
|
||||
//是否显示节点体
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
//是否显示节点体
|
||||
merge: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//节点内容区域文字
|
||||
content: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
//节点内容区域文字
|
||||
userInfo: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
//节点内容区域文字
|
||||
showAvatar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
selectUser: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
show: false,
|
||||
multiple: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: "标题"
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请设置"
|
||||
},
|
||||
//节点体左侧图标
|
||||
leftIcon: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
//头部图标
|
||||
headerIcon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
//头部背景色
|
||||
headerBgc: {
|
||||
type: String,
|
||||
default: '#576a95'
|
||||
},
|
||||
//是否显示错误状态
|
||||
showError: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
errorInfo: {
|
||||
type: String,
|
||||
default: '无信息'
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
|
||||
const designState = computed(()=>{
|
||||
return props.mode === 'design'
|
||||
})
|
||||
|
||||
|
||||
const init = () => {
|
||||
// let userInfo = this.$store.state.selectUserMap.get(this.nodeId);
|
||||
// if (userInfo){
|
||||
// let userInfoList = []
|
||||
// for (let val of userInfo) {
|
||||
// let userInfo = {
|
||||
// id: val.id,
|
||||
// name: val.name,
|
||||
// avatar: val.avatar,
|
||||
// }
|
||||
// userInfoList.push(userInfo)
|
||||
// }
|
||||
// // this._userInfo = userInfoList
|
||||
// }
|
||||
}
|
||||
|
||||
init()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.root {
|
||||
&:before {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.node {
|
||||
padding: 0 50px;
|
||||
//width: 220px;
|
||||
width: 320px;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 50%;
|
||||
-webkit-transform: translateX(-50%);
|
||||
transform: translateX(-50%);
|
||||
width: 0;
|
||||
border-style: solid;
|
||||
border-width: 8px 6px 4px;
|
||||
border-color: #CACACA transparent transparent;
|
||||
background: #F5F5F7;
|
||||
}
|
||||
|
||||
.node-body {
|
||||
cursor: pointer;
|
||||
min-height: 63px;
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
background-color: white;
|
||||
box-shadow: 0px 0px 5px 0px #d8d8d8;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0px 0px 3px 0px;
|
||||
|
||||
.node-body-header {
|
||||
.el-icon-close {
|
||||
display: inline;
|
||||
font-size: medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.node-body-header {
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
padding: 5px 15px;
|
||||
color: white;
|
||||
font-size: xx-small;
|
||||
|
||||
.el-icon-close {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.name {
|
||||
height: 14px;
|
||||
width: 150px;
|
||||
display: inline-block
|
||||
}
|
||||
}
|
||||
|
||||
.node-body-content {
|
||||
padding: 18px;
|
||||
color: #656363;
|
||||
font-size: 14px;
|
||||
|
||||
.avatar_button {
|
||||
//float: left;
|
||||
display: flex;
|
||||
//flex: 1;
|
||||
flex-wrap: wrap;
|
||||
button {
|
||||
margin-top: 3px;
|
||||
height: 40px;
|
||||
//flex-shrink: 0;
|
||||
//flex-grow: 0;
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 55%;
|
||||
right: 5px;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #8c8c8c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
3
src/views/workflow/process/nodes/ProcessEndNode.vue
Normal file
3
src/views/workflow/process/nodes/ProcessEndNode.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
流程结束
|
||||
</template>
|
||||
48
src/views/workflow/process/nodes/RootNode.vue
Normal file
48
src/views/workflow/process/nodes/RootNode.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<node title="发起人" :is-root="true" :mode="mode" :content="content" show-avatar :user-info="config.props.assignedUser"
|
||||
@selected="emit('selected')" @insertNode="type => emit('insertNode', type)"
|
||||
placeholder="所有人" :header-bgc="config.props.headerBgc" :header-icon="UserFilled"/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Node from './Node.vue'
|
||||
import {UserFilled} from '@element-plus/icons-vue'
|
||||
import {defineExpose, defineProps} from "vue";
|
||||
const emit = defineEmits(['insertNode','selected'])
|
||||
|
||||
const props = defineProps({
|
||||
config:{
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const content = computed(() => {
|
||||
if (props.config.props.assignedUser.length > 0){
|
||||
let texts = []
|
||||
props.config.props.assignedUser.forEach(org => texts.push(org.name))
|
||||
return String(texts).replaceAll(',', '、')
|
||||
} else {
|
||||
return '所有人'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const validate = () => {
|
||||
console.log("调用成功")
|
||||
return []
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
validate
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
96
src/views/workflow/process/nodes/TriggerNode.vue
Normal file
96
src/views/workflow/process/nodes/TriggerNode.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<node :title="config.name" :mode="mode" :show-error="showError" :content="content" :error-info="errorInfo"
|
||||
@selected="emit('selected')" @delNode="emit('delNode')" @insertNode="type => emit('insertNode', type)"
|
||||
placeholder="请设置触发器" :header-bgc="headerBgc" :header-icon="SetUp"/>
|
||||
</template>
|
||||
<!--触发器节点-->
|
||||
<script setup>
|
||||
import Node from './Node.vue'
|
||||
const emit = defineEmits()
|
||||
import {defineProps, defineEmits, defineExpose} from "vue";
|
||||
import {SetUp} from '@element-plus/icons-vue'
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'design'
|
||||
}
|
||||
})
|
||||
const showError = ref(false)
|
||||
const errorInfo = ref('')
|
||||
const viewer = computed(() => {
|
||||
return false;
|
||||
})
|
||||
const preview = computed(() => {
|
||||
return false;
|
||||
})
|
||||
|
||||
const headerBgc = computed(() => {
|
||||
return '#47bc82'
|
||||
// if (preview || !viewer) {
|
||||
// return '#ff943e'
|
||||
// } else {
|
||||
// return props.config.props.headerBgc
|
||||
// }
|
||||
})
|
||||
const content = computed(() => {
|
||||
return '请设置触发器'
|
||||
})
|
||||
//校验数据配置的合法性
|
||||
const validate = (err) => {
|
||||
showError.value = false
|
||||
if (props.config.props.type === 'WEBHOOK') {
|
||||
if (isNotEmpty(props.config.props.http.url)) {
|
||||
showError.value = false
|
||||
} else {
|
||||
showError.value = true
|
||||
errorInfo.value = '请设置WEBHOOK的URL地址'
|
||||
}
|
||||
if (restfulCheck(props.config.props.http.url)) {
|
||||
showError.value = false
|
||||
} else {
|
||||
showError.value = true
|
||||
errorInfo.value = 'WEBHOOK的URL地址不符合RESTful标准'
|
||||
}
|
||||
} else if (props.config.props.type === 'EMAIL') {
|
||||
if (!isNotEmpty(props.config.props.email.subject)
|
||||
|| props.config.props.email.to.length === 0
|
||||
|| !isNotEmpty(props.config.props.email.content)) {
|
||||
showError.value = true
|
||||
errorInfo.value = '请设置邮件发送配置'
|
||||
} else {
|
||||
showError.value = false
|
||||
}
|
||||
}
|
||||
if (showError) {
|
||||
err.push(`${props.config.name} 触发动作未设置完善`)
|
||||
}
|
||||
return !showError
|
||||
}
|
||||
//url规范性检查
|
||||
const isNotEmpty = (obj) => {
|
||||
return (obj !== undefined && obj !== null && obj !== '' && obj !== 'null')
|
||||
}
|
||||
const restfulCheck = (url) => {
|
||||
const httpProtocolPattern = /^http:/;
|
||||
const httpsProtocolPattern = /^https:/;
|
||||
const restfulUrlPattern = /\/\w+\/\w+(\/\{[^}]+\})*/;
|
||||
if (httpProtocolPattern.test(url) || httpsProtocolPattern.test(url)) {
|
||||
return restfulUrlPattern.test(url);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
defineExpose({
|
||||
validate
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user