工作流表单+模型代码提交
This commit is contained in:
@@ -1,43 +0,0 @@
|
||||
<template>
|
||||
<div class="snowy-color-picker" @click="forceResize">
|
||||
<color-picker v-bind="$attrs" format="hex" :pureColor="props.value" @update:pureColor="update" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ColorPicker } from 'vue3-colorpicker'
|
||||
import 'vue3-colorpicker/style.css'
|
||||
|
||||
const emit = defineEmits(['update:value'])
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String,
|
||||
default: '#1890ff'
|
||||
}
|
||||
})
|
||||
|
||||
const forceResize = () => {
|
||||
window.dispatchEvent(new Event('resize'))
|
||||
}
|
||||
|
||||
const update = (val) => {
|
||||
const currentColor = document.querySelector('.current-color')
|
||||
if (currentColor) {
|
||||
currentColor.textContent = val
|
||||
}
|
||||
emit('update:value', val)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.snowy-color-picker {
|
||||
.vc-color-wrap {
|
||||
width: auto;
|
||||
}
|
||||
.current-color {
|
||||
color: #fff;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
3
src/components/ContentWrap/index.ts
Normal file
3
src/components/ContentWrap/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import ContentWrap from './src/ContentWrap.vue'
|
||||
|
||||
export { ContentWrap }
|
||||
38
src/components/ContentWrap/src/ContentWrap.vue
Normal file
38
src/components/ContentWrap/src/ContentWrap.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<script lang='ts' setup>
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { QuestionFilled } from '@element-plus/icons-vue'
|
||||
|
||||
defineOptions({ name: 'ContentWrap' })
|
||||
|
||||
const { getPrefixCls } = useDesign()
|
||||
|
||||
const prefixCls = getPrefixCls('content-wrap')
|
||||
|
||||
defineProps({
|
||||
title: propTypes.string.def(''),
|
||||
message: propTypes.string.def('')
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElCard :class="[prefixCls, 'mb-15px']" shadow='never'>
|
||||
<template v-if='title' #header>
|
||||
<div class='flex items-center'>
|
||||
<span class='text-16px font-700'>{{ title }}</span>
|
||||
<ElTooltip v-if='message' effect='dark' placement='right'>
|
||||
<template #content>
|
||||
<div class='max-w-200px'>{{ message }}</div>
|
||||
</template>
|
||||
<QuestionFilled :size='14' class='ml-5px' />
|
||||
</ElTooltip>
|
||||
<div class='flex flex-grow pl-20px'>
|
||||
<slot name='header'></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</ElCard>
|
||||
</template>
|
||||
3
src/components/Dialog/index.ts
Normal file
3
src/components/Dialog/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import Dialog from './src/Dialog.vue'
|
||||
|
||||
export { Dialog }
|
||||
140
src/components/Dialog/src/Dialog.vue
Normal file
140
src/components/Dialog/src/Dialog.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<script lang="ts" setup>
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { isNumber } from '@/utils/is'
|
||||
defineOptions({ name: 'Dialog' })
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: propTypes.bool.def(false),
|
||||
title: propTypes.string.def('Dialog'),
|
||||
fullscreen: propTypes.bool.def(true),
|
||||
width: propTypes.oneOfType([String, Number]).def('40%'),
|
||||
scroll: propTypes.bool.def(false), // 是否开启滚动条。如果是的话,按照 maxHeight 设置最大高度
|
||||
maxHeight: propTypes.oneOfType([String, Number]).def('400px')
|
||||
})
|
||||
|
||||
const getBindValue = computed(() => {
|
||||
const delArr: string[] = ['fullscreen', 'title', 'maxHeight', 'appendToBody']
|
||||
const attrs = useAttrs()
|
||||
const obj = { ...attrs, ...props }
|
||||
for (const key in obj) {
|
||||
if (delArr.indexOf(key) !== -1) {
|
||||
delete obj[key]
|
||||
}
|
||||
}
|
||||
return obj
|
||||
})
|
||||
|
||||
const isFullscreen = ref(false)
|
||||
|
||||
const toggleFull = () => {
|
||||
isFullscreen.value = !unref(isFullscreen)
|
||||
}
|
||||
|
||||
const dialogHeight = ref(isNumber(props.maxHeight) ? `${props.maxHeight}px` : props.maxHeight)
|
||||
|
||||
watch(
|
||||
() => isFullscreen.value,
|
||||
async (val: boolean) => {
|
||||
await nextTick()
|
||||
if (val) {
|
||||
const windowHeight = document.documentElement.offsetHeight
|
||||
dialogHeight.value = `${windowHeight - 55 - 60 - (slots.footer ? 63 : 0)}px`
|
||||
} else {
|
||||
dialogHeight.value = isNumber(props.maxHeight) ? `${props.maxHeight}px` : props.maxHeight
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
const dialogStyle = computed(() => {
|
||||
return {
|
||||
height: unref(dialogHeight)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElDialog
|
||||
v-bind="getBindValue"
|
||||
:close-on-click-modal="true"
|
||||
:fullscreen="isFullscreen"
|
||||
:width="width"
|
||||
destroy-on-close
|
||||
lock-scroll
|
||||
draggable
|
||||
class="com-dialog"
|
||||
:show-close="false"
|
||||
>
|
||||
<template #header="{ close }">
|
||||
<div class="relative h-54px flex items-center justify-between pl-15px pr-15px">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
<div
|
||||
class="absolute right-15px top-[50%] h-54px flex translate-y-[-50%] items-center justify-between"
|
||||
>
|
||||
<Icon
|
||||
v-if="fullscreen"
|
||||
class="is-hover mr-10px cursor-pointer"
|
||||
:icon="isFullscreen ? 'radix-icons:exit-full-screen' : 'radix-icons:enter-full-screen'"
|
||||
color="var(--el-color-info)"
|
||||
hover-color="var(--el-color-primary)"
|
||||
@click="toggleFull"
|
||||
/>
|
||||
<Icon
|
||||
class="is-hover cursor-pointer"
|
||||
icon="ep:close"
|
||||
hover-color="var(--el-color-primary)"
|
||||
color="var(--el-color-info)"
|
||||
@click="close"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ElScrollbar v-if="scroll" :style="dialogStyle">
|
||||
<slot></slot>
|
||||
</ElScrollbar>
|
||||
<slot v-else></slot>
|
||||
<template v-if="slots.footer" #footer>
|
||||
<slot name="footer"></slot>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.com-dialog {
|
||||
.el-overlay-dialog {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.el-dialog {
|
||||
margin: 0 !important;
|
||||
|
||||
&__header {
|
||||
height: 54px;
|
||||
padding: 0;
|
||||
margin-right: 0 !important;
|
||||
border-bottom: 1px solid var(--el-border-color);
|
||||
}
|
||||
|
||||
&__body {
|
||||
padding: 15px !important;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
border-top: 1px solid var(--el-border-color);
|
||||
}
|
||||
|
||||
&__headerbtn {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
3
src/components/DictSelect/index.ts
Normal file
3
src/components/DictSelect/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import DictSelect from './src/DictSelect.vue'
|
||||
|
||||
export { DictSelect }
|
||||
46
src/components/DictSelect/src/DictSelect.vue
Normal file
46
src/components/DictSelect/src/DictSelect.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<!-- 数据字典 Select 选择器 -->
|
||||
<template>
|
||||
<el-select class="w-1/1" v-bind="attrs">
|
||||
<template v-if="valueType === 'int'">
|
||||
<el-option
|
||||
v-for="(dict, index) in getIntDictOptions(dictType)"
|
||||
:key="index"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="valueType === 'str'">
|
||||
<el-option
|
||||
v-for="(dict, index) in getStrDictOptions(dictType)"
|
||||
:key="index"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="valueType === 'bool'">
|
||||
<el-option
|
||||
v-for="(dict, index) in getBoolDictOptions(dictType)"
|
||||
:key="index"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</template>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getBoolDictOptions, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
||||
|
||||
// 接受父组件参数
|
||||
interface Props {
|
||||
dictType: string // 字典类型
|
||||
valueType: string // 字典值类型
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
dictType: '',
|
||||
valueType: 'str'
|
||||
})
|
||||
const attrs = useAttrs()
|
||||
defineOptions({ name: 'DictSelect' })
|
||||
</script>
|
||||
3
src/components/DictTag/index.ts
Normal file
3
src/components/DictTag/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import DictTag from './src/DictTag.vue'
|
||||
|
||||
export { DictTag }
|
||||
60
src/components/DictTag/src/DictTag.vue
Normal file
60
src/components/DictTag/src/DictTag.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<script lang="tsx">
|
||||
import { defineComponent, PropType, ref } from 'vue'
|
||||
import { isHexColor } from '@/utils/color'
|
||||
import { ElTag } from 'element-plus'
|
||||
import { DictDataType, getDictOptions } from '@/utils/dict'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DictTag',
|
||||
props: {
|
||||
type: {
|
||||
type: String as PropType<string>,
|
||||
required: true
|
||||
},
|
||||
value: {
|
||||
type: [String, Number, Boolean] as PropType<string | number | boolean>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const dictData = ref<DictDataType>()
|
||||
const getDictObj = (dictType: string, value: string) => {
|
||||
const dictOptions = getDictOptions(dictType)
|
||||
dictOptions.forEach((dict: DictDataType) => {
|
||||
if (dict.value === value) {
|
||||
if (dict.colorType + '' === 'primary' || dict.colorType + '' === 'default') {
|
||||
dict.colorType = ''
|
||||
}
|
||||
dictData.value = dict
|
||||
}
|
||||
})
|
||||
}
|
||||
const rederDictTag = () => {
|
||||
if (!props.type) {
|
||||
return null
|
||||
}
|
||||
// 解决自定义字典标签值为零时标签不渲染的问题
|
||||
if (props.value === undefined || props.value === null) {
|
||||
return null
|
||||
}
|
||||
getDictObj(props.type, props.value.toString())
|
||||
// 添加标签的文字颜色为白色,解决自定义背景颜色时标签文字看不清的问题
|
||||
return (
|
||||
<ElTag
|
||||
style={dictData.value?.cssClass ? 'color: #fff' : ''}
|
||||
type={dictData.value?.colorType}
|
||||
color={
|
||||
dictData.value?.cssClass && isHexColor(dictData.value?.cssClass)
|
||||
? dictData.value?.cssClass
|
||||
: ''
|
||||
}
|
||||
disableTransitions={true}
|
||||
>
|
||||
{dictData.value?.label}
|
||||
</ElTag>
|
||||
)
|
||||
}
|
||||
return () => rederDictTag()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
8
src/components/Editor/index.ts
Normal file
8
src/components/Editor/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import Editor from './src/Editor.vue'
|
||||
import { IDomEditor } from '@wangeditor/editor'
|
||||
|
||||
export interface EditorExpose {
|
||||
getEditorRef: () => Promise<IDomEditor>
|
||||
}
|
||||
|
||||
export { Editor }
|
||||
202
src/components/Editor/src/Editor.vue
Normal file
202
src/components/Editor/src/Editor.vue
Normal file
@@ -0,0 +1,202 @@
|
||||
<script lang="ts" setup>
|
||||
import { PropType } from 'vue'
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||
import { i18nChangeLanguage, IDomEditor, IEditorConfig } from '@wangeditor/editor'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { isNumber } from '@/utils/is'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useLocaleStore } from '@/stores/modules/locale'
|
||||
import { getAccessToken, getTenantId } from '@/utils/auth'
|
||||
|
||||
defineOptions({ name: 'Editor' })
|
||||
|
||||
type InsertFnType = (url: string, alt: string, href: string) => void
|
||||
|
||||
const localeStore = useLocaleStore()
|
||||
|
||||
const currentLocale = computed(() => localeStore.getCurrentLocale)
|
||||
|
||||
i18nChangeLanguage(unref(currentLocale).lang)
|
||||
|
||||
const props = defineProps({
|
||||
editorId: propTypes.string.def('wangeEditor-1'),
|
||||
height: propTypes.oneOfType([Number, String]).def('500px'),
|
||||
editorConfig: {
|
||||
type: Object as PropType<Partial<IEditorConfig>>,
|
||||
default: () => undefined
|
||||
},
|
||||
readonly: propTypes.bool.def(false),
|
||||
modelValue: propTypes.string.def('')
|
||||
})
|
||||
|
||||
const emit = defineEmits(['change', 'update:modelValue'])
|
||||
|
||||
// 编辑器实例,必须用 shallowRef
|
||||
const editorRef = shallowRef<IDomEditor>()
|
||||
|
||||
const valueHtml = ref('')
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: string) => {
|
||||
if (val === unref(valueHtml)) return
|
||||
valueHtml.value = val
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
// 监听
|
||||
watch(
|
||||
() => valueHtml.value,
|
||||
(val: string) => {
|
||||
emit('update:modelValue', val)
|
||||
}
|
||||
)
|
||||
|
||||
const handleCreated = (editor: IDomEditor) => {
|
||||
editorRef.value = editor
|
||||
}
|
||||
|
||||
// 编辑器配置
|
||||
const editorConfig = computed((): IEditorConfig => {
|
||||
return Object.assign(
|
||||
{
|
||||
placeholder: '请输入内容...',
|
||||
readOnly: props.readonly,
|
||||
customAlert: (s: string, t: string) => {
|
||||
switch (t) {
|
||||
case 'success':
|
||||
ElMessage.success(s)
|
||||
break
|
||||
case 'info':
|
||||
ElMessage.info(s)
|
||||
break
|
||||
case 'warning':
|
||||
ElMessage.warning(s)
|
||||
break
|
||||
case 'error':
|
||||
ElMessage.error(s)
|
||||
break
|
||||
default:
|
||||
ElMessage.info(s)
|
||||
break
|
||||
}
|
||||
},
|
||||
autoFocus: false,
|
||||
scroll: true,
|
||||
MENU_CONF: {
|
||||
['uploadImage']: {
|
||||
server: import.meta.env.VITE_UPLOAD_URL,
|
||||
// 单个文件的最大体积限制,默认为 2M
|
||||
maxFileSize: 5 * 1024 * 1024,
|
||||
// 最多可上传几个文件,默认为 100
|
||||
maxNumberOfFiles: 10,
|
||||
// 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
|
||||
allowedFileTypes: ['image/*'],
|
||||
|
||||
// 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
|
||||
meta: { updateSupport: 0 },
|
||||
// 将 meta 拼接到 url 参数中,默认 false
|
||||
metaWithUrl: true,
|
||||
|
||||
// 自定义增加 http header
|
||||
headers: {
|
||||
Accept: '*',
|
||||
Authorization: 'Bearer ' + getAccessToken(),
|
||||
'tenant-id': getTenantId()
|
||||
},
|
||||
|
||||
// 跨域是否传递 cookie ,默认为 false
|
||||
withCredentials: true,
|
||||
|
||||
// 超时时间,默认为 10 秒
|
||||
timeout: 5 * 1000, // 5 秒
|
||||
|
||||
// form-data fieldName,后端接口参数名称,默认值wangeditor-uploaded-image
|
||||
fieldName: 'file',
|
||||
|
||||
// 上传之前触发
|
||||
onBeforeUpload(file: File) {
|
||||
console.log(file)
|
||||
return file
|
||||
},
|
||||
// 上传进度的回调函数
|
||||
onProgress(progress: number) {
|
||||
// progress 是 0-100 的数字
|
||||
console.log('progress', progress)
|
||||
},
|
||||
onSuccess(file: File, res: any) {
|
||||
console.log('onSuccess', file, res)
|
||||
},
|
||||
onFailed(file: File, res: any) {
|
||||
alert(res.message)
|
||||
console.log('onFailed', file, res)
|
||||
},
|
||||
onError(file: File, err: any, res: any) {
|
||||
alert(err.message)
|
||||
console.error('onError', file, err, res)
|
||||
},
|
||||
// 自定义插入图片
|
||||
customInsert(res: any, insertFn: InsertFnType) {
|
||||
insertFn(res.data, 'image', res.data)
|
||||
}
|
||||
}
|
||||
},
|
||||
uploadImgShowBase64: true
|
||||
},
|
||||
props.editorConfig || {}
|
||||
)
|
||||
})
|
||||
|
||||
const editorStyle = computed(() => {
|
||||
return {
|
||||
height: isNumber(props.height) ? `${props.height}px` : props.height
|
||||
}
|
||||
})
|
||||
|
||||
// 回调函数
|
||||
const handleChange = (editor: IDomEditor) => {
|
||||
emit('change', editor)
|
||||
}
|
||||
|
||||
// 组件销毁时,及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
const editor = unref(editorRef.value)
|
||||
|
||||
// 销毁,并移除 editor
|
||||
editor?.destroy()
|
||||
})
|
||||
|
||||
const getEditorRef = async (): Promise<IDomEditor> => {
|
||||
await nextTick()
|
||||
return unref(editorRef.value) as IDomEditor
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
getEditorRef
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="border-1 border-solid border-[var(--tags-view-border-color)] z-10">
|
||||
<!-- 工具栏 -->
|
||||
<Toolbar
|
||||
:editor="editorRef"
|
||||
:editorId="editorId"
|
||||
class="border-0 b-b-1 border-solid border-[var(--tags-view-border-color)]"
|
||||
/>
|
||||
<!-- 编辑器 -->
|
||||
<Editor
|
||||
v-model="valueHtml"
|
||||
:defaultConfig="editorConfig"
|
||||
:editorId="editorId"
|
||||
:style="editorStyle"
|
||||
@on-change="handleChange"
|
||||
@on-created="handleCreated"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style src="@wangeditor/editor/dist/css/style.css"></style>
|
||||
3
src/components/FormCreate/index.ts
Normal file
3
src/components/FormCreate/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { useFormCreateDesigner } from './src/useFormCreateDesigner'
|
||||
|
||||
export { useFormCreateDesigner }
|
||||
15
src/components/FormCreate/src/config/index.ts
Normal file
15
src/components/FormCreate/src/config/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { useUploadFileRule } from './useUploadFileRule'
|
||||
import { useUploadImgRule } from './useUploadImgRule'
|
||||
import { useUploadImgsRule } from './useUploadImgsRule'
|
||||
import { useDictSelectRule } from './useDictSelectRule'
|
||||
import { useUserSelectRule } from './useUserSelectRule'
|
||||
import { useEditorRule } from './useEditorRule'
|
||||
|
||||
export {
|
||||
useUploadFileRule,
|
||||
useUploadImgRule,
|
||||
useUploadImgsRule,
|
||||
useDictSelectRule,
|
||||
useUserSelectRule,
|
||||
useEditorRule
|
||||
}
|
||||
71
src/components/FormCreate/src/config/selectRule.ts
Normal file
71
src/components/FormCreate/src/config/selectRule.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
const selectRule = [
|
||||
{ type: 'switch', field: 'multiple', title: '是否多选' },
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'disabled',
|
||||
title: '是否禁用'
|
||||
},
|
||||
{ type: 'switch', field: 'clearable', title: '是否可以清空选项' },
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'collapseTags',
|
||||
title: '多选时是否将选中值按文字的形式展示'
|
||||
},
|
||||
{
|
||||
type: 'inputNumber',
|
||||
field: 'multipleLimit',
|
||||
title: '多选时用户最多可以选择的项目数,为 0 则不限制',
|
||||
props: { min: 0 }
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
field: 'autocomplete',
|
||||
title: 'autocomplete 属性'
|
||||
},
|
||||
{ type: 'input', field: 'placeholder', title: '占位符' },
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'filterable',
|
||||
title: '是否可搜索'
|
||||
},
|
||||
{ type: 'switch', field: 'allowCreate', title: '是否允许用户创建新条目' },
|
||||
{
|
||||
type: 'input',
|
||||
field: 'noMatchText',
|
||||
title: '搜索条件无匹配时显示的文字'
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'remote',
|
||||
title: '其中的选项是否从服务器远程加载'
|
||||
},
|
||||
{
|
||||
type: 'Struct',
|
||||
field: 'remoteMethod',
|
||||
title: '自定义远程搜索方法'
|
||||
},
|
||||
{ type: 'input', field: 'noDataText', title: '选项为空时显示的文字' },
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'reserveKeyword',
|
||||
title: '多选且可搜索时,是否在选中一个选项后保留当前的搜索关键词'
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'defaultFirstOption',
|
||||
title: '在输入框按下回车,选择第一个匹配项'
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'popperAppendToBody',
|
||||
title: '是否将弹出框插入至 body 元素',
|
||||
value: true
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'automaticDropdown',
|
||||
title: '对于不可搜索的 Select,是否在输入框获得焦点后自动弹出选项菜单'
|
||||
}
|
||||
]
|
||||
|
||||
export default selectRule
|
||||
64
src/components/FormCreate/src/config/useDictSelectRule.ts
Normal file
64
src/components/FormCreate/src/config/useDictSelectRule.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { generateUUID } from '@/utils'
|
||||
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
|
||||
import selectRule from '@/components/FormCreate/src/config/selectRule'
|
||||
import { dictTypeListAll } from '@/api/system-boot/dictType'
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
|
||||
export const useDictSelectRule = () => {
|
||||
const label = '字典选择器'
|
||||
const name = 'DictSelect'
|
||||
const dictOptions = ref<{ label: string; value: string }[]>([]) // 字典类型下拉数据
|
||||
onMounted(async () => {
|
||||
let data: any = []
|
||||
await dictTypeListAll().then(res => {
|
||||
data = res.data
|
||||
})
|
||||
if (data.length === 0) {
|
||||
return
|
||||
}
|
||||
dictOptions.value =
|
||||
data.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
})) ?? []
|
||||
})
|
||||
return {
|
||||
icon: 'icon-select',
|
||||
label,
|
||||
name,
|
||||
rule() {
|
||||
return {
|
||||
type: name,
|
||||
field: generateUUID(),
|
||||
title: label,
|
||||
info: '',
|
||||
$required: false
|
||||
}
|
||||
},
|
||||
props(_, { t }) {
|
||||
return localeProps(t, name + '.props', [
|
||||
makeRequiredRule(),
|
||||
{
|
||||
type: 'select',
|
||||
field: 'dictType',
|
||||
title: '字典类型',
|
||||
value: '',
|
||||
options: dictOptions.value
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
field: 'valueType',
|
||||
title: '字典值类型',
|
||||
value: 'str',
|
||||
options: [
|
||||
{ label: '数字', value: 'int' },
|
||||
{ label: '字符串', value: 'str' },
|
||||
{ label: '布尔值', value: 'bool' }
|
||||
]
|
||||
},
|
||||
...selectRule
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/components/FormCreate/src/config/useEditorRule.ts
Normal file
32
src/components/FormCreate/src/config/useEditorRule.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { generateUUID } from '@/utils'
|
||||
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
|
||||
|
||||
export const useEditorRule = () => {
|
||||
const label = '富文本'
|
||||
const name = 'Editor'
|
||||
return {
|
||||
icon: 'icon-editor',
|
||||
label,
|
||||
name,
|
||||
rule() {
|
||||
return {
|
||||
type: name,
|
||||
field: generateUUID(),
|
||||
title: label,
|
||||
info: '',
|
||||
$required: false
|
||||
}
|
||||
},
|
||||
props(_, { t }) {
|
||||
return localeProps(t, name + '.props', [
|
||||
makeRequiredRule(),
|
||||
{
|
||||
type: 'input',
|
||||
field: 'height',
|
||||
title: '高度'
|
||||
},
|
||||
{ type: 'switch', field: 'readonly', title: '是否只读' }
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
80
src/components/FormCreate/src/config/useUploadFileRule.ts
Normal file
80
src/components/FormCreate/src/config/useUploadFileRule.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { generateUUID } from '@/utils'
|
||||
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
|
||||
|
||||
export const useUploadFileRule = () => {
|
||||
const label = '文件上传'
|
||||
const name = 'UploadFile'
|
||||
return {
|
||||
icon: 'icon-upload',
|
||||
label,
|
||||
name,
|
||||
rule() {
|
||||
return {
|
||||
type: name,
|
||||
field: generateUUID(),
|
||||
title: label,
|
||||
info: '',
|
||||
$required: false
|
||||
}
|
||||
},
|
||||
props(_, { t }) {
|
||||
return localeProps(t, name + '.props', [
|
||||
makeRequiredRule(),
|
||||
{
|
||||
type: 'select',
|
||||
field: 'fileType',
|
||||
title: '文件类型',
|
||||
value: ['doc', 'xls', 'ppt', 'txt', 'pdf'],
|
||||
options: [
|
||||
{ label: 'doc', value: 'doc' },
|
||||
{ label: 'xls', value: 'xls' },
|
||||
{ label: 'ppt', value: 'ppt' },
|
||||
{ label: 'txt', value: 'txt' },
|
||||
{ label: 'pdf', value: 'pdf' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'autoUpload',
|
||||
title: '是否在选取文件后立即进行上传',
|
||||
value: true
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'drag',
|
||||
title: '拖拽上传',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'isShowTip',
|
||||
title: '是否显示提示',
|
||||
value: true
|
||||
},
|
||||
{
|
||||
type: 'inputNumber',
|
||||
field: 'fileSize',
|
||||
title: '大小限制(MB)',
|
||||
value: 5,
|
||||
props: { min: 0 }
|
||||
},
|
||||
{
|
||||
type: 'inputNumber',
|
||||
field: 'limit',
|
||||
title: '数量限制',
|
||||
value: 5,
|
||||
props: { min: 0 }
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'disabled',
|
||||
title: '是否禁用',
|
||||
value: false
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/components/FormCreate/src/config/useUploadImgRule.ts
Normal file
89
src/components/FormCreate/src/config/useUploadImgRule.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { generateUUID } from '@/utils'
|
||||
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
|
||||
|
||||
export const useUploadImgRule = () => {
|
||||
const label = '单图上传'
|
||||
const name = 'UploadImg'
|
||||
return {
|
||||
icon: 'icon-upload',
|
||||
label,
|
||||
name,
|
||||
rule() {
|
||||
return {
|
||||
type: name,
|
||||
field: generateUUID(),
|
||||
title: label,
|
||||
info: '',
|
||||
$required: false
|
||||
}
|
||||
},
|
||||
props(_, { t }) {
|
||||
return localeProps(t, name + '.props', [
|
||||
makeRequiredRule(),
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'drag',
|
||||
title: '拖拽上传',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
field: 'fileType',
|
||||
title: '图片类型限制',
|
||||
value: ['image/jpeg', 'image/png', 'image/gif'],
|
||||
options: [
|
||||
{ label: 'image/apng', value: 'image/apng' },
|
||||
{ label: 'image/bmp', value: 'image/bmp' },
|
||||
{ label: 'image/gif', value: 'image/gif' },
|
||||
{ label: 'image/jpeg', value: 'image/jpeg' },
|
||||
{ label: 'image/pjpeg', value: 'image/pjpeg' },
|
||||
{ label: 'image/svg+xml', value: 'image/svg+xml' },
|
||||
{ label: 'image/tiff', value: 'image/tiff' },
|
||||
{ label: 'image/webp', value: 'image/webp' },
|
||||
{ label: 'image/x-icon', value: 'image/x-icon' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'inputNumber',
|
||||
field: 'fileSize',
|
||||
title: '大小限制(MB)',
|
||||
value: 5,
|
||||
props: { min: 0 }
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
field: 'height',
|
||||
title: '组件高度',
|
||||
value: '150px'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
field: 'width',
|
||||
title: '组件宽度',
|
||||
value: '150px'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
field: 'borderradius',
|
||||
title: '组件边框圆角',
|
||||
value: '8px'
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'disabled',
|
||||
title: '是否显示删除按钮',
|
||||
value: true
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'showBtnText',
|
||||
title: '是否显示按钮文字',
|
||||
value: true
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
84
src/components/FormCreate/src/config/useUploadImgsRule.ts
Normal file
84
src/components/FormCreate/src/config/useUploadImgsRule.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { generateUUID } from '@/utils'
|
||||
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
|
||||
|
||||
export const useUploadImgsRule = () => {
|
||||
const label = '多图上传'
|
||||
const name = 'UploadImgs'
|
||||
return {
|
||||
icon: 'icon-upload',
|
||||
label,
|
||||
name,
|
||||
rule() {
|
||||
return {
|
||||
type: name,
|
||||
field: generateUUID(),
|
||||
title: label,
|
||||
info: '',
|
||||
$required: false
|
||||
}
|
||||
},
|
||||
props(_, { t }) {
|
||||
return localeProps(t, name + '.props', [
|
||||
makeRequiredRule(),
|
||||
{
|
||||
type: 'switch',
|
||||
field: 'drag',
|
||||
title: '拖拽上传',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
field: 'fileType',
|
||||
title: '图片类型限制',
|
||||
value: ['image/jpeg', 'image/png', 'image/gif'],
|
||||
options: [
|
||||
{ label: 'image/apng', value: 'image/apng' },
|
||||
{ label: 'image/bmp', value: 'image/bmp' },
|
||||
{ label: 'image/gif', value: 'image/gif' },
|
||||
{ label: 'image/jpeg', value: 'image/jpeg' },
|
||||
{ label: 'image/pjpeg', value: 'image/pjpeg' },
|
||||
{ label: 'image/svg+xml', value: 'image/svg+xml' },
|
||||
{ label: 'image/tiff', value: 'image/tiff' },
|
||||
{ label: 'image/webp', value: 'image/webp' },
|
||||
{ label: 'image/x-icon', value: 'image/x-icon' }
|
||||
],
|
||||
props: {
|
||||
multiple: true
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'inputNumber',
|
||||
field: 'fileSize',
|
||||
title: '大小限制(MB)',
|
||||
value: 5,
|
||||
props: { min: 0 }
|
||||
},
|
||||
{
|
||||
type: 'inputNumber',
|
||||
field: 'limit',
|
||||
title: '数量限制',
|
||||
value: 5,
|
||||
props: { min: 0 }
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
field: 'height',
|
||||
title: '组件高度',
|
||||
value: '150px'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
field: 'width',
|
||||
title: '组件宽度',
|
||||
value: '150px'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
field: 'borderradius',
|
||||
title: '组件边框圆角',
|
||||
value: '8px'
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/components/FormCreate/src/config/useUserSelectRule.ts
Normal file
25
src/components/FormCreate/src/config/useUserSelectRule.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { generateUUID } from '@/utils'
|
||||
import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
|
||||
import selectRule from '@/components/FormCreate/src/config/selectRule'
|
||||
|
||||
export const useUserSelectRule = () => {
|
||||
const label = '用户选择器'
|
||||
const name = 'UserSelect'
|
||||
return {
|
||||
icon: 'icon-select',
|
||||
label,
|
||||
name,
|
||||
rule() {
|
||||
return {
|
||||
type: name,
|
||||
field: generateUUID(),
|
||||
title: label,
|
||||
info: '',
|
||||
$required: false
|
||||
}
|
||||
},
|
||||
props(_, { t }) {
|
||||
return localeProps(t, name + '.props', [makeRequiredRule(), ...selectRule])
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/components/FormCreate/src/useFormCreateDesigner.ts
Normal file
53
src/components/FormCreate/src/useFormCreateDesigner.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
useDictSelectRule,
|
||||
useEditorRule,
|
||||
useUploadFileRule,
|
||||
useUploadImgRule,
|
||||
useUploadImgsRule,
|
||||
useUserSelectRule
|
||||
} from './config'
|
||||
import { Ref } from 'vue'
|
||||
|
||||
/**
|
||||
* 表单设计器增强 hook
|
||||
* 新增
|
||||
* - 文件上传
|
||||
* - 单图上传
|
||||
* - 多图上传
|
||||
* - 字典选择器
|
||||
* - 系统用户选择器
|
||||
* - 富文本
|
||||
*/
|
||||
export const useFormCreateDesigner = (designer: Ref) => {
|
||||
const editorRule = useEditorRule()
|
||||
const uploadFileRule = useUploadFileRule()
|
||||
const uploadImgRule = useUploadImgRule()
|
||||
const uploadImgsRule = useUploadImgsRule()
|
||||
const dictSelectRule = useDictSelectRule()
|
||||
const userSelectRule = useUserSelectRule()
|
||||
|
||||
onMounted(() => {
|
||||
// 移除自带的上传组件规则,使用 uploadFileRule、uploadImgRule、uploadImgsRule 替代
|
||||
designer.value?.removeMenuItem('upload')
|
||||
// 移除自带的富文本组件规则,使用 editorRule 替代
|
||||
designer.value?.removeMenuItem('fc-editor')
|
||||
const components = [
|
||||
editorRule,
|
||||
uploadFileRule,
|
||||
uploadImgRule,
|
||||
uploadImgsRule,
|
||||
dictSelectRule,
|
||||
userSelectRule
|
||||
]
|
||||
components.forEach((component) => {
|
||||
// 插入组件规则
|
||||
designer.value?.addComponent(component)
|
||||
// 插入拖拽按钮到 `main` 分类下
|
||||
designer.value?.appendMenuItem('main', {
|
||||
icon: component.icon,
|
||||
name: component.name,
|
||||
label: component.label
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
79
src/components/FormCreate/src/utils/index.ts
Normal file
79
src/components/FormCreate/src/utils/index.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
// TODO puhui999: 借鉴一下 form-create-designer utils 方法 🤣 (导入不了只能先 copy 过来用下)
|
||||
export function makeRequiredRule() {
|
||||
return {
|
||||
type: 'Required',
|
||||
field: 'formCreate$required',
|
||||
title: '是否必填'
|
||||
}
|
||||
}
|
||||
|
||||
export const localeProps = (t, prefix, rules) => {
|
||||
return rules.map((rule) => {
|
||||
if (rule.field === 'formCreate$required') {
|
||||
rule.title = t('props.required') || rule.title
|
||||
} else if (rule.field && rule.field !== '_optionType') {
|
||||
rule.title = t('components.' + prefix + '.' + rule.field) || rule.title
|
||||
}
|
||||
return rule
|
||||
})
|
||||
}
|
||||
|
||||
export function upper(str) {
|
||||
return str.replace(str[0], str[0].toLocaleUpperCase())
|
||||
}
|
||||
|
||||
export function makeOptionsRule(t, to, userOptions) {
|
||||
console.log(userOptions[0])
|
||||
const options = [
|
||||
{ label: t('props.optionsType.struct'), value: 0 },
|
||||
{ label: t('props.optionsType.json'), value: 1 },
|
||||
{ label: '用户数据', value: 2 }
|
||||
]
|
||||
|
||||
const control = [
|
||||
{
|
||||
value: 0,
|
||||
rule: [
|
||||
{
|
||||
type: 'TableOptions',
|
||||
field: 'formCreate' + upper(to).replace('.', '>'),
|
||||
props: { defaultValue: [] }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
rule: [
|
||||
{
|
||||
type: 'Struct',
|
||||
field: 'formCreate' + upper(to).replace('.', '>'),
|
||||
props: { defaultValue: [] }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
rule: [
|
||||
{
|
||||
type: 'TableOptions',
|
||||
field: 'formCreate' + upper(to).replace('.', '>'),
|
||||
props: { modelValue: [] }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
options.splice(0, 0)
|
||||
control.push()
|
||||
|
||||
return {
|
||||
type: 'radio',
|
||||
title: t('props.options'),
|
||||
field: '_optionType',
|
||||
value: 0,
|
||||
options,
|
||||
props: {
|
||||
type: 'button'
|
||||
},
|
||||
control
|
||||
}
|
||||
}
|
||||
33
src/components/ImageViewer/index.ts
Normal file
33
src/components/ImageViewer/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import ImageViewer from './src/ImageViewer.vue'
|
||||
import { isClient } from '@/utils/is'
|
||||
import { createVNode, render, VNode } from 'vue'
|
||||
import { ImageViewerProps } from './src/types'
|
||||
|
||||
let instance: Nullable<VNode> = null
|
||||
|
||||
export function createImageViewer(options: ImageViewerProps) {
|
||||
if (!isClient) return
|
||||
const {
|
||||
urlList,
|
||||
initialIndex = 0,
|
||||
infinite = true,
|
||||
hideOnClickModal = false,
|
||||
teleported = false,
|
||||
zIndex = 2000,
|
||||
show = true
|
||||
} = options
|
||||
|
||||
const propsData: Partial<ImageViewerProps> = {}
|
||||
const container = document.createElement('div')
|
||||
propsData.urlList = urlList
|
||||
propsData.initialIndex = initialIndex
|
||||
propsData.infinite = infinite
|
||||
propsData.hideOnClickModal = hideOnClickModal
|
||||
propsData.teleported = teleported
|
||||
propsData.zIndex = zIndex
|
||||
propsData.show = show
|
||||
|
||||
document.body.appendChild(container)
|
||||
instance = createVNode(ImageViewer, propsData)
|
||||
render(instance, container)
|
||||
}
|
||||
35
src/components/ImageViewer/src/ImageViewer.vue
Normal file
35
src/components/ImageViewer/src/ImageViewer.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<script lang="ts" setup>
|
||||
import { PropType } from 'vue'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
|
||||
defineOptions({ name: 'ImageViewer' })
|
||||
|
||||
const props = defineProps({
|
||||
urlList: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: (): string[] => []
|
||||
},
|
||||
zIndex: propTypes.number.def(200),
|
||||
initialIndex: propTypes.number.def(0),
|
||||
infinite: propTypes.bool.def(true),
|
||||
hideOnClickModal: propTypes.bool.def(false),
|
||||
teleported: propTypes.bool.def(false),
|
||||
show: propTypes.bool.def(false)
|
||||
})
|
||||
|
||||
const getBindValue = computed(() => {
|
||||
const propsData: Recordable = { ...props }
|
||||
delete propsData.show
|
||||
return propsData
|
||||
})
|
||||
|
||||
const show = ref(props.show)
|
||||
|
||||
const close = () => {
|
||||
show.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElImageViewer v-if="show" v-bind="getBindValue" @close="close" />
|
||||
</template>
|
||||
9
src/components/ImageViewer/src/types.ts
Normal file
9
src/components/ImageViewer/src/types.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export interface ImageViewerProps {
|
||||
urlList?: string[]
|
||||
zIndex?: number
|
||||
initialIndex?: number
|
||||
infinite?: boolean
|
||||
hideOnClickModal?: boolean
|
||||
teleported?: boolean
|
||||
show?: boolean
|
||||
}
|
||||
111
src/components/RouterSearch/index.vue
Normal file
111
src/components/RouterSearch/index.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<ElDialog v-if="isModal" v-model="showSearch" :show-close="false" title="菜单搜索">
|
||||
<el-select
|
||||
filterable
|
||||
:reserve-keyword="false"
|
||||
remote
|
||||
placeholder="请输入菜单内容"
|
||||
:remote-method="remoteMethod"
|
||||
style="width: 100%"
|
||||
@change="handleChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</ElDialog>
|
||||
<div v-else class="custom-hover" @click.stop="showTopSearch = !showTopSearch">
|
||||
<Icon icon="ep:search" />
|
||||
<el-select
|
||||
filterable
|
||||
:reserve-keyword="false"
|
||||
remote
|
||||
placeholder="请输入菜单内容"
|
||||
:remote-method="remoteMethod"
|
||||
class="overflow-hidden transition-all-600"
|
||||
:class="showTopSearch ? '!w-220px ml2' : '!w-0'"
|
||||
@change="handleChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineProps({
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
const router = useRouter() // 路由对象
|
||||
const showSearch = ref(false) // 是否显示弹框
|
||||
const showTopSearch = ref(false) // 是否显示顶部搜索框
|
||||
const value: Ref = ref('') // 用户输入的值
|
||||
|
||||
const routers = router.getRoutes() // 路由对象
|
||||
const options = computed(() => {
|
||||
// 提示选项
|
||||
if (!value.value) {
|
||||
return []
|
||||
}
|
||||
const list = routers.filter((item: any) => {
|
||||
if (item.meta.title?.indexOf(value.value) > -1 || item.path.indexOf(value.value) > -1) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
return list.map((item) => {
|
||||
return {
|
||||
label: `${item.meta.title}${item.path}`,
|
||||
value: item.path
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
function remoteMethod(data) {
|
||||
// 这里可以执行相应的操作(例如打开搜索框等)
|
||||
value.value = data
|
||||
}
|
||||
|
||||
function handleChange(path) {
|
||||
router.push({ path })
|
||||
hiddenTopSearch()
|
||||
}
|
||||
|
||||
function hiddenTopSearch() {
|
||||
showTopSearch.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keydown', listenKey)
|
||||
window.addEventListener('click', hiddenTopSearch)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('keydown', listenKey)
|
||||
window.removeEventListener('click', hiddenTopSearch)
|
||||
})
|
||||
|
||||
// 监听 ctrl + k
|
||||
function listenKey(event) {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
|
||||
showSearch.value = !showSearch.value
|
||||
// 这里可以执行相应的操作(例如打开搜索框等)
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
openSearch: () => {
|
||||
showSearch.value = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,142 +0,0 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
title="移动端图标选择"
|
||||
:mask-closable="false"
|
||||
:width="800"
|
||||
:destroy-on-close="true"
|
||||
:footer="null"
|
||||
@cancel="onCancel"
|
||||
>
|
||||
<a-tabs v-model:activeKey="activeKey" tab-position="left" size="small" @change="paneChange">
|
||||
<a-tab-pane v-for="item in iconData" :key="item.key" :tab="item.name">
|
||||
<div v-if="item.iconItem.length > 1" class="xn-icon-select-radio">
|
||||
<a-radio-group v-model:value="iconItemDefault" @change="radioGroupChange">
|
||||
<a-radio-button v-for="iconItem in item.iconItem" :key="iconItem.key" :value="iconItem.key">{{
|
||||
iconItem.name
|
||||
}}</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
|
||||
<div :key="iconItemIns" v-for="iconItemIns in item.iconItem">
|
||||
<div v-if="iconItemIns.key === iconItemDefault" class="xn-icon-select-list">
|
||||
<ul>
|
||||
<li
|
||||
v-for="icon in iconItemIns.item"
|
||||
:key="icon"
|
||||
:class="icon === modelValue ? 'active' : ''"
|
||||
@click="selectIcon(icon.font_class)"
|
||||
>
|
||||
<span class="snowy xn-icons" :class="icon.font_class"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script>
|
||||
import config from '@/assets/icons/mobile'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
iconData: [],
|
||||
modelValue: '',
|
||||
activeKey: 'default',
|
||||
iconItemDefault: 'default'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.iconData.push(...config.icons)
|
||||
},
|
||||
methods: {
|
||||
// 打开
|
||||
showIconModal(value) {
|
||||
this.visible = true
|
||||
this.defaultSetting(value)
|
||||
},
|
||||
// 默认配置
|
||||
defaultSetting(value) {
|
||||
if (value) {
|
||||
this.modelValue = value
|
||||
// 判断展开哪个
|
||||
if (value.indexOf('-outlined') > -1 || value.indexOf('-filled') > -1 || value.indexOf('-two-tone') > -1) {
|
||||
this.activeKey = 'default'
|
||||
if (value.indexOf('-two-tone') > -1) {
|
||||
this.iconItemDefault = 'twotone'
|
||||
} else if (value.indexOf('-filled') > -1) {
|
||||
this.iconItemDefault = 'filled'
|
||||
}
|
||||
} else if (value.indexOf('-extend') > -1) {
|
||||
// 扩展列表
|
||||
this.activeKey = 'extend'
|
||||
// 如扩展其他顶部单选的情况,默认选中在这里配置,同时这里需要做判断
|
||||
// this.iconItemDefault = '您的json中配置的'
|
||||
}
|
||||
}
|
||||
},
|
||||
// 切换标签页,如果是切换到了没用额外的标签页的地方,我们将其置为默认
|
||||
paneChange(e) {
|
||||
if (e.indexOf('default') === -1) {
|
||||
this.iconItemDefault = 'default'
|
||||
}
|
||||
},
|
||||
// 切换icon风格
|
||||
radioGroupChange(e) {
|
||||
this.iconItemDefault = e.target.value
|
||||
},
|
||||
// 选择图标后关闭并返回
|
||||
selectIcon(value) {
|
||||
this.defaultValue = value
|
||||
this.visible = false
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
this.$emit('iconCallBack', this.defaultValue)
|
||||
},
|
||||
onCancel() {
|
||||
this.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.xn-icon-select-radio {
|
||||
padding-left: 5px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.xn-icons {
|
||||
font-size: 26px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.xn-icon-select-list {
|
||||
height: 360px;
|
||||
overflow: auto;
|
||||
}
|
||||
.xn-icon-select-list ul {
|
||||
li {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
padding: 18px;
|
||||
margin: 5px;
|
||||
border-radius: 2px;
|
||||
vertical-align: top;
|
||||
box-shadow: 0 0 0 1px var(--border-color-split);
|
||||
transition: all 0.1s;
|
||||
position: relative;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
cursor: pointer;
|
||||
color: #ffffff;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,143 +0,0 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
title="图标选择"
|
||||
:mask-closable="false"
|
||||
:width="800"
|
||||
:destroy-on-close="true"
|
||||
:footer="null"
|
||||
@cancel="onCancel"
|
||||
>
|
||||
<a-tabs v-model:activeKey="activeKey" tab-position="left" size="small" @change="paneChange">
|
||||
<a-tab-pane v-for="item in iconData" :key="item.key" :tab="item.name">
|
||||
<div v-if="item.iconItem.length > 1" class="xn-icon-select-radio">
|
||||
<a-radio-group v-model:value="iconItemDefault" @change="radioGroupChange">
|
||||
<a-radio-button v-for="iconItem in item.iconItem" :key="iconItem.key" :value="iconItem.key">{{
|
||||
iconItem.name
|
||||
}}</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
|
||||
<div :key="iconItemIns" v-for="iconItemIns in item.iconItem">
|
||||
<div v-if="iconItemIns.key === iconItemDefault" class="xn-icon-select-list">
|
||||
<ul>
|
||||
<li
|
||||
v-for="icon in iconItemIns.item"
|
||||
:key="icon"
|
||||
:class="icon === modelValue ? 'active' : ''"
|
||||
@click="selectIcon(icon)"
|
||||
>
|
||||
<component :is="icon" class="xn-icons" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from '@/config/iconSelect'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
iconData: [],
|
||||
modelValue: '',
|
||||
activeKey: 'default',
|
||||
iconItemDefault: 'default'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.iconData.push(...config.icons)
|
||||
},
|
||||
methods: {
|
||||
// 打开
|
||||
showIconModal(value) {
|
||||
this.visible = true
|
||||
this.defaultSetting(value)
|
||||
},
|
||||
// 默认配置
|
||||
defaultSetting(value) {
|
||||
if (value) {
|
||||
this.modelValue = value
|
||||
// 判断展开哪个
|
||||
if (value.indexOf('-outlined') > -1 || value.indexOf('-filled') > -1 || value.indexOf('-two-tone') > -1) {
|
||||
this.activeKey = 'default'
|
||||
if (value.indexOf('-two-tone') > -1) {
|
||||
this.iconItemDefault = 'twotone'
|
||||
} else if (value.indexOf('-filled') > -1) {
|
||||
this.iconItemDefault = 'filled'
|
||||
}
|
||||
} else if (value.indexOf('-extend') > -1) {
|
||||
// 扩展列表
|
||||
this.activeKey = 'extend'
|
||||
// 如扩展其他顶部单选的情况,默认选中在这里配置,同时这里需要做判断
|
||||
// this.iconItemDefault = '您的json中配置的'
|
||||
}
|
||||
}
|
||||
},
|
||||
// 切换标签页,如果是切换到了没用额外的标签页的地方,我们将其置为默认
|
||||
paneChange(e) {
|
||||
if (e.indexOf('default') === -1) {
|
||||
this.iconItemDefault = 'default'
|
||||
}
|
||||
},
|
||||
// 切换icon风格
|
||||
radioGroupChange(e) {
|
||||
this.iconItemDefault = e.target.value
|
||||
},
|
||||
// 选择图标后关闭并返回
|
||||
selectIcon(value) {
|
||||
this.defaultValue = value
|
||||
this.visible = false
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
this.$emit('iconCallBack', this.defaultValue)
|
||||
},
|
||||
onCancel() {
|
||||
this.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.xn-icon-select-radio {
|
||||
padding-left: 5px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.xn-icons {
|
||||
font-size: 26px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.xn-icon-select-list {
|
||||
height: 360px;
|
||||
overflow: auto;
|
||||
}
|
||||
.xn-icon-select-list ul {
|
||||
li {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
padding: 18px;
|
||||
margin: 5px;
|
||||
border-radius: 2px;
|
||||
vertical-align: top;
|
||||
box-shadow: 0 0 0 1px var(--border-color-split);
|
||||
transition: all 0.1s;
|
||||
position: relative;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
cursor: pointer;
|
||||
color: #ffffff;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,496 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="机构选择" :align-center="true" width="90%" style="height: 600px">
|
||||
<!-- :mask-closable="false"
|
||||
:destroy-on-close="true"
|
||||
@ok="handleOk"
|
||||
@cancel="handleClose" -->
|
||||
<div class="drawer_body">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="7">
|
||||
<el-card size="small" :loading="cardLoading" class="selectorTreeDiv">
|
||||
<el-tree
|
||||
v-if="treeData"
|
||||
v-model:expandedKeys="defaultExpandedKeys"
|
||||
:data="treeData"
|
||||
:field-names="treeFieldNames"
|
||||
:props="defaultProps"
|
||||
accordion
|
||||
:default-expand-all="true"
|
||||
@node-click="treeSelect"
|
||||
></el-tree>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<div class="table-operator" style="margin-bottom: 10px">
|
||||
<el-form
|
||||
ref="searchFormRef"
|
||||
name="advanced_search"
|
||||
class="ant-advanced-search-form"
|
||||
:model="searchFormState"
|
||||
>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item name="searchKey">
|
||||
<el-input
|
||||
v-model="searchFormState.searchKey"
|
||||
placeholder="请输入机构名"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-button type="primary" class="primarySele" @click="loadData()">查询</el-button>
|
||||
<el-button class="snowy-buttom-left" @click="() => reset()">重置</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="org-table">
|
||||
<div class="org_table_head">
|
||||
<p>待选择列表</p>
|
||||
<div class="org_table_head_add">
|
||||
添加当前数据
|
||||
</div>
|
||||
</div>
|
||||
<el-table
|
||||
ref="table"
|
||||
size="small"
|
||||
:columns="commons"
|
||||
:data="tableData"
|
||||
:expand-row-by-click="true"
|
||||
:loading="pageLoading"
|
||||
bordered
|
||||
:pagination="false"
|
||||
border
|
||||
stripe
|
||||
height="330"
|
||||
>
|
||||
<template #title>
|
||||
<span>待选择列表 {{ tableRecordNum }} 条</span>
|
||||
<div v-if="!radioModel" style="float: right">
|
||||
<el-button type="dashed" size="small" @click="addAllPageRecord">
|
||||
添加当前数据
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'category'">
|
||||
{{ $TOOL.dictTypeData('ORG_CATEGORY', record.category) }}
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<el-button type="dashed" size="small" @click="addRecord(record)">添加</el-button>
|
||||
</template>
|
||||
</template>
|
||||
<el-table-column prop="action" label="操作" width="80" align="center">
|
||||
<el-button type="dashed" size="small" @click="addRecord(record)">添加</el-button>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="机构名" />
|
||||
<el-table-column prop="type" label="分类"></el-table-column>
|
||||
</el-table>
|
||||
<div class="mt-2">
|
||||
<el-pagination
|
||||
v-if="!isEmpty(tableData)"
|
||||
v-model:current="current"
|
||||
v-model:page-size="pageSize"
|
||||
:total="total"
|
||||
size="small"
|
||||
showSizeChanger
|
||||
@change="paginationChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="org-table">
|
||||
<div class="org_table_heads">
|
||||
<p>待选择列表</p>
|
||||
<div class="org_table_head_delete">
|
||||
全部移除
|
||||
</div>
|
||||
</div>
|
||||
<el-table
|
||||
ref="selectedTable"
|
||||
size="small"
|
||||
:columns="selectedCommons"
|
||||
:data="selectedData"
|
||||
:expand-row-by-click="true"
|
||||
:loading="selectedTableListLoading"
|
||||
bordered
|
||||
border
|
||||
>
|
||||
<template #title>
|
||||
<span>已选择: {{ selectedData.length }}</span>
|
||||
<div v-if="!radioModel" style="float: right">
|
||||
<el-button type="dashed" danger size="small" @click="delAllRecord">
|
||||
全部移除
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<el-button type="dashed" danger size="small" @click="delRecord(record)">
|
||||
移除
|
||||
</el-button>
|
||||
</template>
|
||||
</template>
|
||||
<el-table-column prop="action" label="操作" width="80" align="center">
|
||||
<el-button type="dashed" size="small" @click="addRecord(record)">添加</el-button>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="机构名" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="visible = false">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup name="orgSelectorPlus">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { remove, isEmpty } from 'lodash-es'
|
||||
import { ref } from 'vue'
|
||||
// 弹窗是否打开
|
||||
const visible = ref(false)
|
||||
// 主表格common
|
||||
const commons = [
|
||||
{
|
||||
label: '操作',
|
||||
prop: 'action',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
label: '机构名',
|
||||
prop: 'name',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
label: '分类',
|
||||
prop: 'category'
|
||||
}
|
||||
]
|
||||
// 选中表格的表格common
|
||||
const selectedCommons = [
|
||||
{
|
||||
label: '操作',
|
||||
prop: 'action',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
label: '机构名',
|
||||
prop: 'name',
|
||||
ellipsis: true
|
||||
}
|
||||
]
|
||||
|
||||
// 主表格的ref 名称
|
||||
const table = ref()
|
||||
// 选中表格的ref 名称
|
||||
const selectedTable = ref()
|
||||
const tableRecordNum = ref()
|
||||
const searchFormState = ref({})
|
||||
const searchFormRef = ref()
|
||||
const cardLoading = ref(true)
|
||||
const pageLoading = ref(false)
|
||||
const selectedTableListLoading = ref(false)
|
||||
//树状图数据配置
|
||||
const defaultProps = {
|
||||
children: 'children',
|
||||
label: 'name'
|
||||
}
|
||||
// 替换treeNode 中 title,key,children
|
||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||
// 获取机构树数据
|
||||
const treeData = ref()
|
||||
// 默认展开二级树的节点id
|
||||
const defaultExpandedKeys = ref([])
|
||||
const emit = defineEmits({ onBack: null })
|
||||
const tableData = ref([])
|
||||
const selectedData = ref([])
|
||||
const recordIds = ref()
|
||||
const props = defineProps(['orgPageApi', 'orgTreeApi', 'radioModel', 'dataIsConverterFlw', 'checkedOrgListApi'])
|
||||
// 是否是单选
|
||||
const radioModel = props.radioModel || false
|
||||
// 数据是否转换成工作流格式
|
||||
const dataIsConverterFlw = props.dataIsConverterFlw || false
|
||||
// 分页相关
|
||||
const current = ref(0) // 当前页数
|
||||
const pageSize = ref(20) // 每页条数
|
||||
const total = ref(0) // 数据总数
|
||||
|
||||
// 打开弹框
|
||||
const showOrgPlusModal = ids => {
|
||||
visible.value = true
|
||||
if (dataIsConverterFlw) {
|
||||
ids = goDataConverter(ids)
|
||||
}
|
||||
recordIds.value = ids
|
||||
if (props.orgTreeApi) {
|
||||
// 获取机构树
|
||||
props.orgTreeApi().then(data => {
|
||||
cardLoading.value = false
|
||||
if (data !== null) {
|
||||
console.log(data, 'data,++++++++++++')
|
||||
treeData.value = data.data
|
||||
// 默认展开2级
|
||||
treeData.value.forEach(item => {
|
||||
// 因为0的顶级
|
||||
if (item.parentId === '0') {
|
||||
defaultExpandedKeys.value.push(item.id)
|
||||
// 取到下级ID
|
||||
if (item.children) {
|
||||
item.children.forEach(items => {
|
||||
defaultExpandedKeys.value.push(items.id)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
searchFormState.value.size = pageSize.value
|
||||
loadData()
|
||||
if (props.checkedOrgListApi) {
|
||||
if (isEmpty(recordIds.value)) {
|
||||
return
|
||||
}
|
||||
const param = {
|
||||
idList: recordIds.value
|
||||
}
|
||||
selectedTableListLoading.value = true
|
||||
props
|
||||
.checkedOrgListApi(param)
|
||||
.then(data => {
|
||||
selectedData.value = data
|
||||
})
|
||||
.finally(() => {
|
||||
selectedTableListLoading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
// 查询主表格数据
|
||||
const loadData = () => {
|
||||
pageLoading.value = true
|
||||
props
|
||||
.orgPageApi(searchFormState.value)
|
||||
.then(data => {
|
||||
current.value = data.current
|
||||
total.value = data.total
|
||||
// 重置、赋值
|
||||
tableData.value = []
|
||||
tableRecordNum.value = 0
|
||||
console.log(data, '999999999999')
|
||||
tableData.value = data.data.records
|
||||
if (data.records) {
|
||||
tableRecordNum.value = data.data.records.length
|
||||
} else {
|
||||
tableRecordNum.value = 0
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
pageLoading.value = false
|
||||
})
|
||||
}
|
||||
// pageSize改变回调分页事件
|
||||
const paginationChange = (page, pageSize) => {
|
||||
searchFormState.value.current = page
|
||||
searchFormState.value.size = pageSize
|
||||
loadData()
|
||||
}
|
||||
const judge = () => {
|
||||
if (radioModel && selectedData.value.length > 0) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
// 添加记录
|
||||
const addRecord = record => {
|
||||
if (!judge()) {
|
||||
message.warning('只可选择一条')
|
||||
return
|
||||
}
|
||||
const selectedRecord = selectedData.value.filter(item => item.id === record.id)
|
||||
if (selectedRecord.length === 0) {
|
||||
selectedData.value.push(record)
|
||||
} else {
|
||||
message.warning('该记录已存在')
|
||||
}
|
||||
}
|
||||
// 添加全部
|
||||
const addAllPageRecord = () => {
|
||||
let newArray = selectedData.value.concat(tableData.value)
|
||||
let list = []
|
||||
for (let item1 of newArray) {
|
||||
let flag = true
|
||||
for (let item2 of list) {
|
||||
if (item1.id === item2.id) {
|
||||
flag = false
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
list.push(item1)
|
||||
}
|
||||
}
|
||||
selectedData.value = list
|
||||
}
|
||||
// 删减记录
|
||||
const delRecord = record => {
|
||||
remove(selectedData.value, item => item.id === record.id)
|
||||
}
|
||||
// 删减记录
|
||||
const delAllRecord = () => {
|
||||
selectedData.value = []
|
||||
}
|
||||
// 点击树查询
|
||||
const treeSelect = selectedKeys => {
|
||||
console.log(selectedKeys.id, '111112222333')
|
||||
searchFormState.value.current = 0
|
||||
if (selectedKeys.id) {
|
||||
searchFormState.value.orgId = selectedKeys.id.toString()
|
||||
} else {
|
||||
// delete searchFormState.value.orgId
|
||||
delete searchFormState.value.orgId
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
// 确定
|
||||
const handleOk = () => {
|
||||
const value = []
|
||||
selectedData.value.forEach(item => {
|
||||
const obj = {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
category: item.category
|
||||
}
|
||||
value.push(obj)
|
||||
})
|
||||
// 判断是否做数据的转换为工作流需要的
|
||||
if (dataIsConverterFlw) {
|
||||
emit('onBack', outDataConverter(value))
|
||||
} else {
|
||||
emit('onBack', value)
|
||||
}
|
||||
handleClose()
|
||||
}
|
||||
// 重置
|
||||
const reset = () => {
|
||||
delete searchFormState.value.searchKey
|
||||
loadData()
|
||||
}
|
||||
const handleClose = () => {
|
||||
searchFormState.value = {}
|
||||
tableRecordNum.value = 0
|
||||
tableData.value = []
|
||||
current.value = 0
|
||||
pageSize.value = 20
|
||||
total.value = 0
|
||||
selectedData.value = []
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 数据进入后转换
|
||||
const goDataConverter = data => {
|
||||
const resultData = []
|
||||
if (data.length > 0) {
|
||||
const values = data[0].value.split(',')
|
||||
if (JSON.stringify(values) !== '[""]') {
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
resultData.push(values[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultData
|
||||
}
|
||||
// 数据出口转换器
|
||||
const outDataConverter = data => {
|
||||
const obj = {}
|
||||
let label = ''
|
||||
let value = ''
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data.length === i + 1) {
|
||||
label = label + data[i].name
|
||||
value = value + data[i].id
|
||||
} else {
|
||||
label = label + data[i].name + ','
|
||||
value = value + data[i].id + ','
|
||||
}
|
||||
}
|
||||
obj.key = 'ORG'
|
||||
obj.label = label
|
||||
obj.value = value
|
||||
obj.extJson = ''
|
||||
return obj
|
||||
}
|
||||
defineExpose({
|
||||
showOrgPlusModal
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.selectorTreeDiv {
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
}
|
||||
.cardTag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.primarySele {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.org-table {
|
||||
overflow: auto;
|
||||
max-height: 450px;
|
||||
}
|
||||
.drawer_body {
|
||||
width: 100%;
|
||||
height: 350px;
|
||||
}
|
||||
.dialog-footer{
|
||||
position:absolute;
|
||||
right:10px;
|
||||
bottom:10px;
|
||||
z-index:2005;
|
||||
}
|
||||
.org_table_head,.org_table_heads{
|
||||
width:100%;
|
||||
height: 40px;
|
||||
border: 1px solid #F0F0F0;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content: space-between;
|
||||
padding:0 10px;
|
||||
p{
|
||||
font-size: 12px;
|
||||
}
|
||||
.org_table_head_add,.org_table_head_delete{
|
||||
width:100px;
|
||||
height:24px;
|
||||
font-size: 12px;
|
||||
border:2px dashed #F0F0F0;
|
||||
border-radius:2px;
|
||||
cursor:pointer;
|
||||
display:flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.org_table_head_add:hover{
|
||||
border:2px dashed #3FA9FF;
|
||||
color:#3FA9FF;
|
||||
}
|
||||
.org_table_head_delete{
|
||||
width:72px;
|
||||
height:24px;
|
||||
border:2px dashed #FF4D4F;
|
||||
color:#FF4D4F;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,399 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="职位选择"
|
||||
:width="1000"
|
||||
:mask-closable="false"
|
||||
:destroy-on-close="true"
|
||||
@ok="handleOk"
|
||||
@cancel="handleClose"
|
||||
>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="7">
|
||||
<el-card size="small" :loading="cardLoading" class="selectorTreeDiv">
|
||||
<el-tree
|
||||
v-if="treeData"
|
||||
v-model:expandedKeys="defaultExpandedKeys"
|
||||
:tree-data="treeData"
|
||||
:field-names="treeFieldNames"
|
||||
@node-click="treeSelect"
|
||||
>
|
||||
</el-tree>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<div class="table-operator" style="margin-bottom: 10px">
|
||||
<el-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item name="searchKey">
|
||||
<el-input v-model:value="searchFormState.searchKey" placeholder="请输入职位名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-button type="primary" class="primarySele" @click="loadData()"> 查询 </el-button>
|
||||
<el-button class="snowy-buttom-left" @click="() => reset()"> 重置 </el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="pos-table">
|
||||
<el-table
|
||||
ref="table"
|
||||
size="small"
|
||||
:columns="commons"
|
||||
:datel="tableData"
|
||||
:expand-row-by-click="true"
|
||||
:loading="pageLoading"
|
||||
bordered
|
||||
:pagination="false"
|
||||
>
|
||||
<template #title>
|
||||
<span>待选择列表 {{ tableRecordNum }} 条</span>
|
||||
<div v-if="!radioModel" style="float: right">
|
||||
<el-button type="dashed" size="small" @click="addAllPageRecord">添加当前数据</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<el-button type="dashed" size="small" @click="addRecord(record)">添加</el-button>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'category'">
|
||||
{{ $TOOL.dictTypeData('POSITION_CATEGORY', record.category) }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table>
|
||||
<div class="mt-2">
|
||||
<el-pagination
|
||||
v-if="!isEmpty(tableData)"
|
||||
v-model:current="current"
|
||||
v-model:page-size="pageSize"
|
||||
:total="total"
|
||||
size="small"
|
||||
showSizeChanger
|
||||
@change="paginationChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="pos-table">
|
||||
<el-table
|
||||
ref="selectedTable"
|
||||
size="small"
|
||||
:columns="selectedCommons"
|
||||
:datel-source="selectedData"
|
||||
:expand-row-by-click="true"
|
||||
:loading="selectedTableListLoading"
|
||||
bordered
|
||||
>
|
||||
<template #title>
|
||||
<span>已选择: {{ selectedData.length }}</span>
|
||||
<div v-if="!radioModel" style="float: right">
|
||||
<el-button type="dashed" danger size="small" @click="delAllRecord">全部移除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<el-button type="dashed" danger size="small" @click="delRecord(record)">移除</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup name="posSelectorPlus">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { remove, isEmpty } from 'lodash-es'
|
||||
import { ref } from 'vue'
|
||||
// 弹窗是否打开
|
||||
const visible = ref(false)
|
||||
// 主表格common
|
||||
const commons = [
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '职位名',
|
||||
dataIndex: 'name',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '分类',
|
||||
dataIndex: 'category'
|
||||
}
|
||||
]
|
||||
// 选中表格的表格common
|
||||
const selectedCommons = [
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '职位名',
|
||||
dataIndex: 'name',
|
||||
ellipsis: true
|
||||
}
|
||||
]
|
||||
// 主表格的ref 名称
|
||||
const table = ref()
|
||||
// 选中表格的ref 名称
|
||||
const selectedTable = ref()
|
||||
const tableRecordNum = ref()
|
||||
const searchFormState = ref({})
|
||||
const searchFormRef = ref()
|
||||
const cardLoading = ref(true)
|
||||
const pageLoading = ref(false)
|
||||
const selectedTableListLoading = ref(false)
|
||||
// 替换treeNode 中 title,key,children
|
||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||
// 获取机构树数据
|
||||
const treeData = ref()
|
||||
// 默认展开二级树的节点id
|
||||
const defaultExpandedKeys = ref([])
|
||||
const emit = defineEmits({ onBack: null })
|
||||
const tableData = ref([])
|
||||
const selectedData = ref([])
|
||||
const recordIds = ref()
|
||||
const props = defineProps(['posPageApi', 'orgTreeApi', 'radioModel', 'dataIsConverterFlw', 'checkedPosListApi'])
|
||||
// 是否是单选
|
||||
const radioModel = props.radioModel || false
|
||||
// 数据是否转换成工作流格式
|
||||
const dataIsConverterFlw = props.dataIsConverterFlw || false
|
||||
// 分页相关
|
||||
const current = ref(0) // 当前页数
|
||||
const pageSize = ref(20) // 每页条数
|
||||
const total = ref(0) // 数据总数
|
||||
|
||||
// 打开弹框
|
||||
const showPosPlusModal = (ids) => {
|
||||
visible.value = true
|
||||
if (dataIsConverterFlw) {
|
||||
ids = goDataConverter(ids)
|
||||
}
|
||||
recordIds.value = ids
|
||||
// 获取机构树
|
||||
if (props.orgTreeApi) {
|
||||
// 获取机构树
|
||||
props.orgTreeApi().then((data) => {
|
||||
cardLoading.value = false
|
||||
if (data !== null) {
|
||||
treeData.value = data
|
||||
// 默认展开2级
|
||||
treeData.value.forEach((item) => {
|
||||
// 因为0的顶级
|
||||
if (item.parentId === '0') {
|
||||
defaultExpandedKeys.value.push(item.id)
|
||||
// 取到下级ID
|
||||
if (item.children) {
|
||||
item.children.forEach((items) => {
|
||||
defaultExpandedKeys.value.push(items.id)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
searchFormState.value.size = pageSize.value
|
||||
loadData()
|
||||
if (props.checkedPosListApi) {
|
||||
if (isEmpty(recordIds.value)) {
|
||||
return
|
||||
}
|
||||
const param = {
|
||||
idList: recordIds.value
|
||||
}
|
||||
selectedTableListLoading.value = true
|
||||
props
|
||||
.checkedPosListApi(param)
|
||||
.then((data) => {
|
||||
selectedData.value = data
|
||||
})
|
||||
.finally(() => {
|
||||
selectedTableListLoading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
// 查询主表格数据
|
||||
const loadData = () => {
|
||||
pageLoading.value = true
|
||||
props
|
||||
.posPageApi(searchFormState.value)
|
||||
.then((data) => {
|
||||
current.value = data.current
|
||||
total.value = data.total
|
||||
// 重置、赋值
|
||||
tableData.value = []
|
||||
tableRecordNum.value = 0
|
||||
tableData.value = data.records
|
||||
if (data.records) {
|
||||
tableRecordNum.value = data.records.length
|
||||
} else {
|
||||
tableRecordNum.value = 0
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
pageLoading.value = false
|
||||
})
|
||||
}
|
||||
// pageSize改变回调分页事件
|
||||
const paginationChange = (page, pageSize) => {
|
||||
searchFormState.value.current = page
|
||||
searchFormState.value.size = pageSize
|
||||
loadData()
|
||||
}
|
||||
const judge = () => {
|
||||
if (radioModel && selectedData.value.length > 0) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
// 添加记录
|
||||
const addRecord = (record) => {
|
||||
if (!judge()) {
|
||||
message.warning('只可选择一条')
|
||||
return
|
||||
}
|
||||
const selectedRecord = selectedData.value.filter((item) => item.id === record.id)
|
||||
if (selectedRecord.length === 0) {
|
||||
selectedData.value.push(record)
|
||||
} else {
|
||||
message.warning('该记录已存在')
|
||||
}
|
||||
}
|
||||
// 添加全部
|
||||
const addAllPageRecord = () => {
|
||||
let newArray = selectedData.value.concat(tableData.value)
|
||||
let list = []
|
||||
for (let item1 of newArray) {
|
||||
let flag = true
|
||||
for (let item2 of list) {
|
||||
if (item1.id === item2.id) {
|
||||
flag = false
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
list.push(item1)
|
||||
}
|
||||
}
|
||||
selectedData.value = list
|
||||
}
|
||||
// 删减记录
|
||||
const delRecord = (record) => {
|
||||
remove(selectedData.value, (item) => item.id === record.id)
|
||||
}
|
||||
// 删减记录
|
||||
const delAllRecord = () => {
|
||||
selectedData.value = []
|
||||
}
|
||||
// 点击树查询
|
||||
const treeSelect = (selectedKeys) => {
|
||||
searchFormState.value.current = 0
|
||||
if (selectedKeys.length > 0) {
|
||||
searchFormState.value.orgId = selectedKeys.toString()
|
||||
} else {
|
||||
delete searchFormState.value.orgId
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
// 确定
|
||||
const handleOk = () => {
|
||||
const value = []
|
||||
selectedData.value.forEach((item) => {
|
||||
const obj = {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
account: item.account
|
||||
}
|
||||
value.push(obj)
|
||||
})
|
||||
// 判断是否做数据的转换为工作流需要的
|
||||
if (dataIsConverterFlw) {
|
||||
emit('onBack', outDataConverter(value))
|
||||
} else {
|
||||
emit('onBack', value)
|
||||
}
|
||||
handleClose()
|
||||
}
|
||||
// 重置
|
||||
const reset = () => {
|
||||
delete searchFormState.value.searchKey
|
||||
loadData()
|
||||
}
|
||||
const handleClose = () => {
|
||||
searchFormState.value = {}
|
||||
tableRecordNum.value = 0
|
||||
tableData.value = []
|
||||
current.value = 0
|
||||
pageSize.value = 20
|
||||
total.value = 0
|
||||
selectedData.value = []
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 数据进入后转换
|
||||
const goDataConverter = (data) => {
|
||||
const resultData = []
|
||||
if (data.length > 0) {
|
||||
const values = data[0].value.split(',')
|
||||
if (JSON.stringify(values) !== '[""]') {
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
resultData.push(values[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultData
|
||||
}
|
||||
// 数据出口转换器
|
||||
const outDataConverter = (data) => {
|
||||
const obj = {}
|
||||
let label = ''
|
||||
let value = ''
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data.length === i + 1) {
|
||||
label = label + data[i].name
|
||||
value = value + data[i].id
|
||||
} else {
|
||||
label = label + data[i].name + ','
|
||||
value = value + data[i].id + ','
|
||||
}
|
||||
}
|
||||
obj.key = 'POSITION'
|
||||
obj.label = label
|
||||
obj.value = value
|
||||
obj.extJson = ''
|
||||
return obj
|
||||
}
|
||||
defineExpose({
|
||||
showPosPlusModal
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.selectorTreeDiv {
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
}
|
||||
.cardTag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.primarySele {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.pos-table {
|
||||
overflow: auto;
|
||||
max-height: 450px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,449 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="角色选择"
|
||||
:width="1000"
|
||||
:mask-closable="false"
|
||||
:destroy-on-close="true"
|
||||
@ok="handleOk"
|
||||
@cancel="handleClose"
|
||||
>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="7">
|
||||
<el-card size="small" :loading="cardLoading" class="selectorTreeDiv">
|
||||
<el-tree
|
||||
v-if="treeData"
|
||||
v-model:expandedKeys="defaultExpandedKeys"
|
||||
:data="treeData"
|
||||
:field-names="treeFieldNames"
|
||||
@select="treeSelect"
|
||||
>
|
||||
</el-tree>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<div class="table-operator" style="margin-bottom: 10px">
|
||||
<el-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item name="searchKey">
|
||||
<el-input v-model:value="searchFormState.searchKey" placeholder="请输入角色名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-button type="primary" class="primarySele" @click="loadData()"> 查询 </el-button>
|
||||
<el-button class="snowy-buttom-left" @click="() => reset()"> 重置 </el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="role-table">
|
||||
<el-table
|
||||
ref="table"
|
||||
size="small"
|
||||
:columns="commons"
|
||||
:data="tableData"
|
||||
:expand-row-by-click="true"
|
||||
:loading="pageLoading"
|
||||
bordered
|
||||
:pagination="false"
|
||||
>
|
||||
<template #title>
|
||||
<span>待选择列表 {{ tableRecordNum }} 条</span>
|
||||
<div v-if="!radioModel" style="float: right">
|
||||
<el-button type="dashed" size="small" @click="addAllPageRecord">添加当前数据</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<el-button type="dashed" size="small" @click="addRecord(record)">添加</el-button>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'category'">
|
||||
{{ $TOOL.dictTypeData('ROLE_CATEGORY', record.category) }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table>
|
||||
<div class="mt-2">
|
||||
<el-pagination
|
||||
v-if="!isEmpty(tableData)"
|
||||
v-model:current="current"
|
||||
v-model:page-size="pageSize"
|
||||
:total="total"
|
||||
size="small"
|
||||
showSizeChanger
|
||||
@change="paginationChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="role-table">
|
||||
<el-table
|
||||
ref="selectedTable"
|
||||
size="small"
|
||||
:columns="selectedCommons"
|
||||
:data-source="selectedData"
|
||||
:expand-row-by-click="true"
|
||||
:loading="selectedTableListLoading"
|
||||
bordered
|
||||
>
|
||||
<template #title>
|
||||
<span>已选择: {{ selectedData.length }}</span>
|
||||
<div v-if="!radioModel" style="float: right">
|
||||
<el-button type="dashed" danger size="small" @click="delAllRecord">全部移除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<el-button type="dashed" danger size="small" @click="delRecord(record)">移除</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup name="roleSelectorPlus">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { remove, isEmpty } from 'lodash-es'
|
||||
import { ref } from 'vue'
|
||||
// 弹窗是否打开
|
||||
const visible = ref(false)
|
||||
// 主表格common
|
||||
const commons = [
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '角色名',
|
||||
dataIndex: 'name',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '分类',
|
||||
dataIndex: 'category'
|
||||
}
|
||||
]
|
||||
// 选中表格的表格common
|
||||
const selectedCommons = [
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '角色名',
|
||||
dataIndex: 'name',
|
||||
ellipsis: true
|
||||
}
|
||||
]
|
||||
// 主表格的ref 名称
|
||||
const table = ref()
|
||||
// 选中表格的ref 名称
|
||||
const selectedTable = ref()
|
||||
const tableRecordNum = ref()
|
||||
const searchFormState = ref({})
|
||||
const searchFormRef = ref()
|
||||
const cardLoading = ref(true)
|
||||
const pageLoading = ref(false)
|
||||
const selectedTableListLoading = ref(false)
|
||||
// 替换treeNode 中 title,key,children
|
||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||
// 获取机构树数据
|
||||
const treeData = ref()
|
||||
// 默认展开二级树的节点id
|
||||
const defaultExpandedKeys = ref([])
|
||||
const emit = defineEmits({ onBack: null })
|
||||
const tableData = ref([])
|
||||
const selectedData = ref([])
|
||||
const recordIds = ref()
|
||||
const props = defineProps({
|
||||
rolePageApi: {
|
||||
type: Function
|
||||
},
|
||||
orgTreeApi: {
|
||||
type: Function
|
||||
},
|
||||
// 是否是单选
|
||||
radioModel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
},
|
||||
// 数据是否转换成工作流格式
|
||||
dataIsConverterFlw: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
},
|
||||
// 是否展示‘全局’这个节点
|
||||
roleGlobal: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
required: false
|
||||
},
|
||||
checkedRoleListApi: {
|
||||
type: Function
|
||||
}
|
||||
})
|
||||
// 是否是单选
|
||||
const radioModel = props.radioModel
|
||||
// 数据是否转换成工作流格式
|
||||
const dataIsConverterFlw = props.dataIsConverterFlw
|
||||
// 是否展示‘全局’这个节点
|
||||
const roleGlobal = props.roleGlobal
|
||||
// 分页相关
|
||||
const current = ref(0) // 当前页数
|
||||
const pageSize = ref(20) // 每页条数
|
||||
const total = ref(0) // 数据总数
|
||||
|
||||
// 打开弹框
|
||||
const showRolePlusModal = (ids) => {
|
||||
visible.value = true
|
||||
if (dataIsConverterFlw) {
|
||||
ids = goDataConverter(ids)
|
||||
}
|
||||
recordIds.value = ids
|
||||
if (props.orgTreeApi) {
|
||||
// 获取机构树
|
||||
props.orgTreeApi().then((data) => {
|
||||
cardLoading.value = false
|
||||
if (data !== null) {
|
||||
treeData.value = data
|
||||
// 树中插入全局角色类型
|
||||
if (roleGlobal) {
|
||||
const globalRoleType = [
|
||||
{
|
||||
id: 'GLOBAL',
|
||||
parentId: '-1',
|
||||
name: '全局'
|
||||
}
|
||||
]
|
||||
treeData.value = globalRoleType.concat(data)
|
||||
}
|
||||
// 默认展开2级
|
||||
treeData.value.forEach((item) => {
|
||||
// 因为0的顶级
|
||||
if (item.parentId === '0') {
|
||||
defaultExpandedKeys.value.push(item.id)
|
||||
// 取到下级ID
|
||||
if (item.children) {
|
||||
item.children.forEach((items) => {
|
||||
defaultExpandedKeys.value.push(items.id)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
searchFormState.value.size = pageSize.value
|
||||
loadData()
|
||||
if (props.checkedRoleListApi) {
|
||||
if (isEmpty(recordIds.value)) {
|
||||
return
|
||||
}
|
||||
const param = {
|
||||
idList: recordIds.value
|
||||
}
|
||||
selectedTableListLoading.value = true
|
||||
props
|
||||
.checkedRoleListApi(param)
|
||||
.then((data) => {
|
||||
selectedData.value = data
|
||||
})
|
||||
.finally(() => {
|
||||
selectedTableListLoading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
// 查询主表格数据
|
||||
const loadData = () => {
|
||||
// 如果不是用全局的,我们每次查询加上这个条件
|
||||
if (!roleGlobal) {
|
||||
searchFormState.value.category = 'ORG'
|
||||
}
|
||||
pageLoading.value = true
|
||||
props
|
||||
.rolePageApi(searchFormState.value)
|
||||
.then((data) => {
|
||||
current.value = data.current
|
||||
total.value = data.total
|
||||
// 重置、赋值
|
||||
tableData.value = []
|
||||
tableRecordNum.value = 0
|
||||
tableData.value = data.records
|
||||
if (data.records) {
|
||||
tableRecordNum.value = data.records.length
|
||||
} else {
|
||||
tableRecordNum.value = 0
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
pageLoading.value = false
|
||||
})
|
||||
}
|
||||
// pageSize改变回调分页事件
|
||||
const paginationChange = (page, pageSize) => {
|
||||
searchFormState.value.current = page
|
||||
searchFormState.value.size = pageSize
|
||||
loadData()
|
||||
}
|
||||
const judge = () => {
|
||||
if (radioModel && selectedData.value.length > 0) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
// 添加记录
|
||||
const addRecord = (record) => {
|
||||
if (!judge()) {
|
||||
message.warning('只可选择一条')
|
||||
return
|
||||
}
|
||||
const selectedRecord = selectedData.value.filter((item) => item.id === record.id)
|
||||
if (selectedRecord.length === 0) {
|
||||
selectedData.value.push(record)
|
||||
} else {
|
||||
message.warning('该记录已存在')
|
||||
}
|
||||
}
|
||||
// 添加全部
|
||||
const addAllPageRecord = () => {
|
||||
let newArray = selectedData.value.concat(tableData.value)
|
||||
let list = []
|
||||
for (let item1 of newArray) {
|
||||
let flag = true
|
||||
for (let item2 of list) {
|
||||
if (item1.id === item2.id) {
|
||||
flag = false
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
list.push(item1)
|
||||
}
|
||||
}
|
||||
selectedData.value = list
|
||||
}
|
||||
// 删减记录
|
||||
const delRecord = (record) => {
|
||||
remove(selectedData.value, (item) => item.id === record.id)
|
||||
}
|
||||
// 删减记录
|
||||
const delAllRecord = () => {
|
||||
selectedData.value = []
|
||||
}
|
||||
// 点击树查询
|
||||
const treeSelect = (selectedKeys) => {
|
||||
searchFormState.value.current = 0
|
||||
if (selectedKeys.length > 0) {
|
||||
if (selectedKeys[0] === 'GLOBAL') {
|
||||
searchFormState.value.category = selectedKeys[0]
|
||||
delete searchFormState.value.orgId
|
||||
} else {
|
||||
searchFormState.value.orgId = selectedKeys.toString()
|
||||
delete searchFormState.value.category
|
||||
}
|
||||
} else {
|
||||
delete searchFormState.value.category
|
||||
delete searchFormState.value.orgId
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
// 确定
|
||||
const handleOk = () => {
|
||||
const value = []
|
||||
selectedData.value.forEach((item) => {
|
||||
const obj = {
|
||||
id: item.id,
|
||||
name: item.name
|
||||
}
|
||||
value.push(obj)
|
||||
})
|
||||
// 判断是否做数据的转换为工作流需要的
|
||||
if (dataIsConverterFlw) {
|
||||
emit('onBack', outDataConverter(value))
|
||||
} else {
|
||||
emit('onBack', value)
|
||||
}
|
||||
handleClose()
|
||||
}
|
||||
// 重置
|
||||
const reset = () => {
|
||||
delete searchFormState.value.searchKey
|
||||
loadData()
|
||||
}
|
||||
const handleClose = () => {
|
||||
searchFormState.value = {}
|
||||
tableRecordNum.value = 0
|
||||
tableData.value = []
|
||||
current.value = 0
|
||||
pageSize.value = 20
|
||||
total.value = 0
|
||||
selectedData.value = []
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 数据进入后转换
|
||||
const goDataConverter = (data) => {
|
||||
const resultData = []
|
||||
if (data.length > 0) {
|
||||
const values = data[0].value.split(',')
|
||||
if (JSON.stringify(values) !== '[""]') {
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
resultData.push(values[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultData
|
||||
}
|
||||
// 数据出口转换器
|
||||
const outDataConverter = (data) => {
|
||||
const obj = {}
|
||||
let label = ''
|
||||
let value = ''
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data.length === i + 1) {
|
||||
label = label + data[i].name
|
||||
value = value + data[i].id
|
||||
} else {
|
||||
label = label + data[i].name + ','
|
||||
value = value + data[i].id + ','
|
||||
}
|
||||
}
|
||||
obj.key = 'ROLE'
|
||||
obj.label = label
|
||||
obj.value = value
|
||||
obj.extJson = ''
|
||||
return obj
|
||||
}
|
||||
defineExpose({
|
||||
showRolePlusModal
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.selectorTreeDiv {
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
}
|
||||
.cardTag {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.primarySele {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.role-table {
|
||||
overflow: auto;
|
||||
max-height: 450px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,401 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="用户选择"
|
||||
:width="1000"
|
||||
:mask-closable="false"
|
||||
:destroy-on-close="true"
|
||||
@ok="handleOk"
|
||||
@cancel="handleClose"
|
||||
:append-to-body="true"
|
||||
>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="7">
|
||||
<el-card size="small" :loading="cardLoading" class="selectorTreeDiv">
|
||||
<el-tree
|
||||
v-if="treeData"
|
||||
v-model:expandedKeys="defaultExpandedKeys"
|
||||
:data="treeData"
|
||||
:field-names="treeFieldNames"
|
||||
@node-click="treeSelect"
|
||||
>
|
||||
</el-tree>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<div class="table-operator" style="margin-bottom: 10px">
|
||||
<el-form ref="searchFormRef" name="advanced_search" class="ant-advanced-search-form" :model="searchFormState">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item name="searchKey">
|
||||
<el-input v-model:value="searchFormState.searchKey" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-button type="primary" class="primarySele" @click="loadData()"> 查询 </el-button>
|
||||
<el-button class="snowy-buttom-left" @click="reset()"> 重置 </el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="user-table">
|
||||
<el-table
|
||||
ref="table"
|
||||
size="small"
|
||||
:columns="commons"
|
||||
:data-source="tableData"
|
||||
:expand-row-by-click="true"
|
||||
:loading="pageLoading"
|
||||
bordered
|
||||
:pagination="false"
|
||||
>
|
||||
<template #title>
|
||||
<span>待选择列表 {{ tableRecordNum }} 条</span>
|
||||
<div v-if="!radioModel" style="float: right">
|
||||
<el-button type="dashed" size="small" @click="addAllPageRecord">添加当前数据</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<el-button type="dashed" size="small" @click="addRecord(record)">添加</el-button>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'category'">
|
||||
{{ $TOOL.dictTypeData('ROLE_CATEGORY', record.category) }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table>
|
||||
<div class="mt-2">
|
||||
<el-pagination
|
||||
v-if="!isEmpty(tableData)"
|
||||
v-model:current="current"
|
||||
v-model:page-size="pageSize"
|
||||
:total="total"
|
||||
size="small"
|
||||
showSizeChanger
|
||||
@change="paginationChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="user-table">
|
||||
<el-table
|
||||
ref="selectedTable"
|
||||
size="small"
|
||||
:columns="selectedCommons"
|
||||
:data-source="selectedData"
|
||||
:expand-row-by-click="true"
|
||||
:loading="selectedTableListLoading"
|
||||
bordered
|
||||
>
|
||||
<template #title>
|
||||
<span>已选择: {{ selectedData.length }}</span>
|
||||
<div v-if="!radioModel" style="float: right">
|
||||
<el-button type="dashed" danger size="small" @click="delAllRecord">全部移除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<el-button type="dashed" danger size="small" @click="delRecord(record)">移除</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup name="userSelectorPlus">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { remove, isEmpty } from 'lodash-es'
|
||||
import { ref } from 'vue'
|
||||
// 弹窗是否打开
|
||||
const visible = ref(false)
|
||||
// 主表格common
|
||||
const commons = [
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'name',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '账号',
|
||||
dataIndex: 'account'
|
||||
}
|
||||
]
|
||||
// 选中表格的表格common
|
||||
const selectedCommons = [
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'name',
|
||||
ellipsis: true
|
||||
}
|
||||
]
|
||||
// 主表格的ref 名称
|
||||
const table = ref()
|
||||
// 选中表格的ref 名称
|
||||
const selectedTable = ref()
|
||||
const tableRecordNum = ref()
|
||||
const searchFormState = ref({})
|
||||
const searchFormRef = ref()
|
||||
const cardLoading = ref(true)
|
||||
const pageLoading = ref(false)
|
||||
const selectedTableListLoading = ref(false)
|
||||
// 替换treeNode 中 title,key,children
|
||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||
// 获取机构树数据
|
||||
const treeData = ref()
|
||||
// 默认展开二级树的节点id
|
||||
const defaultExpandedKeys = ref([])
|
||||
const emit = defineEmits({ onBack: null })
|
||||
const tableData = ref([])
|
||||
const selectedData = ref([])
|
||||
const recordIds = ref()
|
||||
const props = defineProps(['radioModel', 'dataIsConverterFlw', 'orgTreeApi', 'userPageApi', 'checkedUserListApi'])
|
||||
// 是否是单选
|
||||
const radioModel = props.radioModel || false
|
||||
// 数据是否转换成工作流格式
|
||||
const dataIsConverterFlw = props.dataIsConverterFlw || false
|
||||
// 分页相关
|
||||
const current = ref(0) // 当前页数
|
||||
const pageSize = ref(20) // 每页条数
|
||||
const total = ref(0) // 数据总数
|
||||
|
||||
// 打开弹框
|
||||
const showUserPlusModal = (ids = []) => {
|
||||
visible.value = true
|
||||
if (dataIsConverterFlw) {
|
||||
ids = goDataConverter(ids)
|
||||
}
|
||||
recordIds.value = ids
|
||||
// 加载机构树
|
||||
if (props.orgTreeApi) {
|
||||
// 获取机构树
|
||||
props.orgTreeApi().then((data) => {
|
||||
cardLoading.value = false
|
||||
if (data !== null) {
|
||||
treeData.value = data.data
|
||||
// 默认展开2级
|
||||
treeData.value.forEach((item) => {
|
||||
// 因为0的顶级
|
||||
if (item.parentId === '0') {
|
||||
defaultExpandedKeys.value.push(item.id)
|
||||
// 取到下级ID
|
||||
if (item.children) {
|
||||
item.children.forEach((items) => {
|
||||
defaultExpandedKeys.value.push(items.id)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
searchFormState.value.size = pageSize.value
|
||||
loadData()
|
||||
if (props.checkedUserListApi) {
|
||||
if (isEmpty(recordIds.value)) {
|
||||
return
|
||||
}
|
||||
const param = {
|
||||
idList: recordIds.value
|
||||
}
|
||||
selectedTableListLoading.value = true
|
||||
props
|
||||
.checkedUserListApi(param)
|
||||
.then((data) => {
|
||||
selectedData.value = data
|
||||
})
|
||||
.finally(() => {
|
||||
selectedTableListLoading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
// 查询主表格数据
|
||||
const loadData = () => {
|
||||
pageLoading.value = true
|
||||
props
|
||||
.userPageApi(searchFormState.value)
|
||||
.then((data) => {
|
||||
current.value = data.current
|
||||
// pageSize.value = data.size
|
||||
total.value = data.total
|
||||
// 重置、赋值
|
||||
tableData.value = []
|
||||
tableRecordNum.value = 0
|
||||
tableData.value = data.records
|
||||
if (data.records) {
|
||||
tableRecordNum.value = data.records.length
|
||||
} else {
|
||||
tableRecordNum.value = 0
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
pageLoading.value = false
|
||||
})
|
||||
}
|
||||
// pageSize改变回调分页事件
|
||||
const paginationChange = (page, pageSize) => {
|
||||
searchFormState.value.current = page
|
||||
searchFormState.value.size = pageSize
|
||||
loadData()
|
||||
}
|
||||
const judge = () => {
|
||||
if (radioModel && selectedData.value.length > 0) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
// 添加记录
|
||||
const addRecord = (record) => {
|
||||
if (!judge()) {
|
||||
message.warning('只可选择一条')
|
||||
return
|
||||
}
|
||||
const selectedRecord = selectedData.value.filter((item) => item.id === record.id)
|
||||
if (selectedRecord.length === 0) {
|
||||
selectedData.value.push(record)
|
||||
} else {
|
||||
message.warning('该记录已存在')
|
||||
}
|
||||
}
|
||||
// 添加全部
|
||||
const addAllPageRecord = () => {
|
||||
let newArray = selectedData.value.concat(tableData.value)
|
||||
let list = []
|
||||
for (let item1 of newArray) {
|
||||
let flag = true
|
||||
for (let item2 of list) {
|
||||
if (item1.id === item2.id) {
|
||||
flag = false
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
list.push(item1)
|
||||
}
|
||||
}
|
||||
selectedData.value = list
|
||||
}
|
||||
// 删减记录
|
||||
const delRecord = (record) => {
|
||||
remove(selectedData.value, (item) => item.id === record.id)
|
||||
}
|
||||
// 删减记录
|
||||
const delAllRecord = () => {
|
||||
selectedData.value = []
|
||||
}
|
||||
// 点击树查询
|
||||
const treeSelect = (selectedKeys) => {
|
||||
searchFormState.value.current = 0
|
||||
if (selectedKeys.length > 0) {
|
||||
searchFormState.value.orgId = selectedKeys.toString()
|
||||
} else {
|
||||
delete searchFormState.value.orgId
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
// 确定
|
||||
const handleOk = () => {
|
||||
const value = []
|
||||
selectedData.value.forEach((item) => {
|
||||
const obj = {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
account: item.account
|
||||
}
|
||||
value.push(obj)
|
||||
})
|
||||
// 判断是否做数据的转换为工作流需要的
|
||||
if (dataIsConverterFlw) {
|
||||
emit('onBack', outDataConverter(value))
|
||||
} else {
|
||||
emit('onBack', value)
|
||||
}
|
||||
handleClose()
|
||||
}
|
||||
// 重置
|
||||
const reset = () => {
|
||||
delete searchFormState.value.searchKey
|
||||
loadData()
|
||||
}
|
||||
const handleClose = () => {
|
||||
searchFormState.value = {}
|
||||
tableRecordNum.value = 0
|
||||
tableData.value = []
|
||||
current.value = 0
|
||||
pageSize.value = 20
|
||||
total.value = 0
|
||||
selectedData.value = []
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 数据进入后转换
|
||||
const goDataConverter = (data) => {
|
||||
const resultData = []
|
||||
if (data.length > 0) {
|
||||
const values = data[0].value.split(',')
|
||||
if (JSON.stringify(values) !== '[""]') {
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
resultData.push(values[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultData
|
||||
}
|
||||
// 数据出口转换器
|
||||
const outDataConverter = (data) => {
|
||||
const obj = {}
|
||||
let label = ''
|
||||
let value = ''
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data.length === i + 1) {
|
||||
label = label + data[i].name
|
||||
value = value + data[i].id
|
||||
} else {
|
||||
label = label + data[i].name + ','
|
||||
value = value + data[i].id + ','
|
||||
}
|
||||
}
|
||||
obj.key = 'USER'
|
||||
obj.label = label
|
||||
obj.value = value
|
||||
obj.extJson = ''
|
||||
return obj
|
||||
}
|
||||
defineExpose({
|
||||
showUserPlusModal
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.selectorTreeDiv {
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
}
|
||||
.cardTag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.primarySele {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.user-table {
|
||||
overflow: auto;
|
||||
max-height: 450px;
|
||||
}
|
||||
</style>
|
||||
5
src/components/UploadFile/index.ts
Normal file
5
src/components/UploadFile/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import UploadImg from './src/UploadImg.vue'
|
||||
import UploadImgs from './src/UploadImgs.vue'
|
||||
import UploadFile from './src/UploadFile.vue'
|
||||
|
||||
export { UploadImg, UploadImgs, UploadFile }
|
||||
214
src/components/UploadFile/src/UploadFile.vue
Normal file
214
src/components/UploadFile/src/UploadFile.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<div class='upload-file'>
|
||||
<el-upload
|
||||
ref='uploadRef'
|
||||
v-model:file-list='fileList'
|
||||
:action='uploadUrl'
|
||||
:auto-upload='autoUpload'
|
||||
:before-upload='beforeUpload'
|
||||
:disabled='disabled'
|
||||
:drag='drag'
|
||||
:http-request='httpRequest'
|
||||
:limit='props.limit'
|
||||
:multiple='props.limit > 1'
|
||||
:on-error='excelUploadError'
|
||||
:on-exceed='handleExceed'
|
||||
:on-preview='handlePreview'
|
||||
:on-remove='handleRemove'
|
||||
:on-success='handleFileSuccess'
|
||||
:show-file-list='true'
|
||||
class='upload-file-uploader'
|
||||
name='file'
|
||||
>
|
||||
<el-button v-if='!disabled' type='primary'>
|
||||
<UploadFilled />
|
||||
选取文件
|
||||
</el-button>
|
||||
<template v-if='isShowTip && !disabled' #tip>
|
||||
<div style='font-size: 8px'>
|
||||
大小不超过 <b style='color: #f56c6c'>{{ fileSize }}MB</b>
|
||||
</div>
|
||||
<div style='font-size: 8px'>
|
||||
格式为 <b style='color: #f56c6c'>{{ fileType.join('/') }}</b> 的文件
|
||||
</div>
|
||||
</template>
|
||||
<template #file='row'>
|
||||
<div class='flex items-center'>
|
||||
<span>{{ row.file.name }}</span>
|
||||
<div class='ml-10px'>
|
||||
<el-link
|
||||
:href='row.file.url'
|
||||
:underline='false'
|
||||
download
|
||||
target='_blank'
|
||||
type='primary'
|
||||
>
|
||||
下载
|
||||
</el-link>
|
||||
</div>
|
||||
<div class='ml-10px'>
|
||||
<el-button link type='danger' @click='handleRemove(row.file)'> 删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</div>
|
||||
</template>
|
||||
<script lang='ts' setup>
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { UploadFilled } from '@element-plus/icons-vue'
|
||||
import type { UploadInstance, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus'
|
||||
import { isString } from '@/utils/is'
|
||||
import { useUpload } from '@/components/UploadFile/src/useUpload'
|
||||
import { UploadFile } from 'element-plus/es/components/upload/src/upload'
|
||||
|
||||
defineOptions({ name: 'UploadFile' })
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
|
||||
fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), // 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||
fileSize: propTypes.number.def(5), // 大小限制(MB)
|
||||
limit: propTypes.number.def(5), // 数量限制
|
||||
autoUpload: propTypes.bool.def(true), // 自动上传
|
||||
drag: propTypes.bool.def(false), // 拖拽上传
|
||||
isShowTip: propTypes.bool.def(true), // 是否显示提示
|
||||
disabled: propTypes.bool.def(false) // 是否禁用上传组件 ==> 非必传(默认为 false)
|
||||
})
|
||||
|
||||
// ========== 上传相关 ==========
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
const uploadList = ref<UploadUserFile[]>([])
|
||||
const fileList = ref<UploadUserFile[]>([])
|
||||
const uploadNumber = ref<number>(0)
|
||||
|
||||
const { uploadUrl, httpRequest } = useUpload()
|
||||
|
||||
// 文件上传之前判断
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (file: UploadRawFile) => {
|
||||
if (fileList.value.length >= props.limit) {
|
||||
message.error(`上传文件数量不能超过${props.limit}个!`)
|
||||
return false
|
||||
}
|
||||
let fileExtension = ''
|
||||
if (file.name.lastIndexOf('.') > -1) {
|
||||
fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
|
||||
}
|
||||
const isImg = props.fileType.some((type: string) => {
|
||||
if (file.type.indexOf(type) > -1) return true
|
||||
return !!(fileExtension && fileExtension.indexOf(type) > -1)
|
||||
})
|
||||
const isLimit = file.size < props.fileSize * 1024 * 1024
|
||||
if (!isImg) {
|
||||
message.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式!`)
|
||||
return false
|
||||
}
|
||||
if (!isLimit) {
|
||||
message.error(`上传文件大小不能超过${props.fileSize}MB!`)
|
||||
return false
|
||||
}
|
||||
message.success('正在上传文件,请稍候...')
|
||||
uploadNumber.value++
|
||||
}
|
||||
// 处理上传的文件发生变化
|
||||
// const handleFileChange = (uploadFile: UploadFile): void => {
|
||||
// uploadRef.value.data.path = uploadFile.name
|
||||
// }
|
||||
// 文件上传成功
|
||||
const handleFileSuccess: UploadProps['onSuccess'] = (res: any): void => {
|
||||
message.success('上传成功')
|
||||
// 删除自身
|
||||
const index = fileList.value.findIndex((item) => item.response?.data === res.data)
|
||||
fileList.value.splice(index, 1)
|
||||
uploadList.value.push({ name: res.data, url: res.data })
|
||||
if (uploadList.value.length == uploadNumber.value) {
|
||||
fileList.value.push(...uploadList.value)
|
||||
uploadList.value = []
|
||||
uploadNumber.value = 0
|
||||
emitUpdateModelValue()
|
||||
}
|
||||
}
|
||||
// 文件数超出提示
|
||||
const handleExceed: UploadProps['onExceed'] = (): void => {
|
||||
message.error(`上传文件数量不能超过${props.limit}个!`)
|
||||
}
|
||||
// 上传错误提示
|
||||
const excelUploadError: UploadProps['onError'] = (): void => {
|
||||
message.error('导入数据失败,请您重新上传!')
|
||||
}
|
||||
// 删除上传文件
|
||||
const handleRemove = (file: UploadFile) => {
|
||||
const index = fileList.value.map((f) => f.name).indexOf(file.name)
|
||||
if (index > -1) {
|
||||
fileList.value.splice(index, 1)
|
||||
emitUpdateModelValue()
|
||||
}
|
||||
}
|
||||
const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
|
||||
console.log(uploadFile)
|
||||
}
|
||||
|
||||
// 监听模型绑定值变动
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: string | string[]) => {
|
||||
if (!val) {
|
||||
fileList.value = [] // fix:处理掉缓存,表单重置后上传组件的内容并没有重置
|
||||
return
|
||||
}
|
||||
|
||||
fileList.value = [] // 保障数据为空
|
||||
// 情况1:字符串
|
||||
if (isString(val)) {
|
||||
fileList.value.push(
|
||||
...val.split(',').map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
|
||||
)
|
||||
return
|
||||
}
|
||||
// 情况2:数组
|
||||
fileList.value.push(
|
||||
...(val as string[]).map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
|
||||
)
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
// 发送文件链接列表更新
|
||||
const emitUpdateModelValue = () => {
|
||||
// 情况1:数组结果
|
||||
let result: string | string[] = fileList.value.map((file) => file.url!)
|
||||
// 情况2:逗号分隔的字符串
|
||||
if (props.limit === 1 || isString(props.modelValue)) {
|
||||
result = result.join(',')
|
||||
}
|
||||
emit('update:modelValue', result)
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
.upload-file-uploader {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
:deep(.upload-file-list .el-upload-list__item) {
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
line-height: 2;
|
||||
border: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
:deep(.el-upload-list__item-file-name) {
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
:deep(.upload-file-list .ele-upload-list__item-content) {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
:deep(.ele-upload-list__item-content-action .el-link) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
273
src/components/UploadFile/src/UploadImg.vue
Normal file
273
src/components/UploadFile/src/UploadImg.vue
Normal file
@@ -0,0 +1,273 @@
|
||||
<template>
|
||||
<div class='upload-box'>
|
||||
<el-upload
|
||||
:id='uuid'
|
||||
:accept="fileType.join(',')"
|
||||
:action='uploadUrl'
|
||||
:before-upload='beforeUpload'
|
||||
:class="['upload', drag ? 'no-border' : '']"
|
||||
:disabled='disabled'
|
||||
:drag='drag'
|
||||
:http-request='httpRequest'
|
||||
:multiple='false'
|
||||
:on-error='uploadError'
|
||||
:on-success='uploadSuccess'
|
||||
:show-file-list='false'
|
||||
>
|
||||
<template v-if='modelValue'>
|
||||
<img :src='modelValue' class='upload-image' />
|
||||
<div class='upload-handle' @click.stop>
|
||||
<div v-if='!disabled' class='handle-icon' @click='editImg'>
|
||||
<Edit />
|
||||
<span v-if='showBtnText'>{{ t('action.edit') }}</span>
|
||||
</div>
|
||||
<div class='handle-icon' @click='imagePreview(modelValue)'>
|
||||
<ZoomIn />
|
||||
<span v-if='showBtnText'>{{ t('action.detail') }}</span>
|
||||
</div>
|
||||
<div v-if='showDelete && !disabled' class='handle-icon' @click='deleteImg'>
|
||||
<Delete />
|
||||
<span v-if='showBtnText'>{{ t('action.del') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class='upload-empty'>
|
||||
<slot name='empty'>
|
||||
<Plus />
|
||||
<!-- <span>请上传图片</span> -->
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<div class='el-upload__tip'>
|
||||
<slot name='tip'></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup>
|
||||
import type { UploadProps } from 'element-plus'
|
||||
import { Plus,Edit,ZoomIn,Delete} from '@element-plus/icons-vue'
|
||||
import { generateUUID } from '@/utils'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { createImageViewer } from '@/components/ImageViewer'
|
||||
import { useUpload } from '@/components/UploadFile/src/useUpload'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useMessage } from '@/hooks/web/useMessage'
|
||||
|
||||
defineOptions({ name: 'UploadImg' })
|
||||
|
||||
type FileTypes =
|
||||
| 'image/apng'
|
||||
| 'image/bmp'
|
||||
| 'image/gif'
|
||||
| 'image/jpeg'
|
||||
| 'image/pjpeg'
|
||||
| 'image/png'
|
||||
| 'image/svg+xml'
|
||||
| 'image/tiff'
|
||||
| 'image/webp'
|
||||
| 'image/x-icon'
|
||||
|
||||
// 接受父组件参数
|
||||
const props = defineProps({
|
||||
modelValue: propTypes.string.def(''),
|
||||
drag: propTypes.bool.def(true), // 是否支持拖拽上传 ==> 非必传(默认为 true)
|
||||
disabled: propTypes.bool.def(false), // 是否禁用上传组件 ==> 非必传(默认为 false)
|
||||
fileSize: propTypes.number.def(5), // 图片大小限制 ==> 非必传(默认为 5M)
|
||||
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
|
||||
height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px)
|
||||
width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px)
|
||||
borderradius: propTypes.string.def('8px'), // 组件边框圆角 ==> 非必传(默认为 8px)
|
||||
showDelete: propTypes.bool.def(true), // 是否显示删除按钮
|
||||
showBtnText: propTypes.bool.def(true) // 是否显示按钮文字
|
||||
})
|
||||
const { t } = useI18n() // 国际化
|
||||
const message = useMessage() // 消息弹窗
|
||||
// 生成组件唯一id
|
||||
const uuid = ref('id-' + generateUUID())
|
||||
// 查看图片
|
||||
const imagePreview = (imgUrl: string) => {
|
||||
createImageViewer({
|
||||
zIndex: 9999999,
|
||||
urlList: [imgUrl]
|
||||
})
|
||||
}
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const deleteImg = () => {
|
||||
emit('update:modelValue', '')
|
||||
}
|
||||
|
||||
const { uploadUrl, httpRequest } = useUpload()
|
||||
|
||||
const editImg = () => {
|
||||
const dom = document.querySelector(`#${uuid.value} .el-upload__input`)
|
||||
dom && dom.dispatchEvent(new MouseEvent('click'))
|
||||
}
|
||||
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
|
||||
const imgType = props.fileType
|
||||
if (!imgType.includes(rawFile.type as FileTypes))
|
||||
message.notifyWarning('上传图片不符合所需的格式!')
|
||||
if (!imgSize) message.notifyWarning(`上传图片大小不能超过 ${props.fileSize}M!`)
|
||||
return imgType.includes(rawFile.type as FileTypes) && imgSize
|
||||
}
|
||||
|
||||
// 图片上传成功提示
|
||||
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
|
||||
message.success('上传成功')
|
||||
emit('update:modelValue', res.data)
|
||||
}
|
||||
|
||||
// 图片上传错误提示
|
||||
const uploadError = () => {
|
||||
message.notifyError('图片上传失败,请您重新上传!')
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
.is-error {
|
||||
.upload {
|
||||
:deep(.el-upload),
|
||||
:deep(.el-upload-dragger) {
|
||||
border: 1px dashed var(--el-color-danger) !important;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.disabled) {
|
||||
.el-upload,
|
||||
.el-upload-dragger {
|
||||
cursor: not-allowed !important;
|
||||
background: var(--el-disabled-bg-color);
|
||||
border: 1px dashed var(--el-border-color-darker) !important;
|
||||
|
||||
&:hover {
|
||||
border: 1px dashed var(--el-border-color-darker) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.upload-box {
|
||||
.no-border {
|
||||
:deep(.el-upload) {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.upload) {
|
||||
.el-upload {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: v-bind(width);
|
||||
height: v-bind(height);
|
||||
overflow: hidden;
|
||||
border: 1px dashed var(--el-border-color-darker);
|
||||
border-radius: v-bind(borderradius);
|
||||
transition: var(--el-transition-duration-fast);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
|
||||
.upload-handle {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload-dragger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
border: 1px dashed var(--el-border-color-darker);
|
||||
border-radius: v-bind(borderradius);
|
||||
|
||||
&:hover {
|
||||
border: 1px dashed var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload-dragger.is-dragover {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
border: 2px dashed var(--el-color-primary) !important;
|
||||
}
|
||||
|
||||
.upload-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.upload-empty {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
line-height: 30px;
|
||||
color: var(--el-color-info);
|
||||
|
||||
.el-icon {
|
||||
font-size: 28px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.upload-handle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
background: rgb(0 0 0 / 60%);
|
||||
opacity: 0;
|
||||
box-sizing: border-box;
|
||||
transition: var(--el-transition-duration-fast);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.handle-icon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 6%;
|
||||
color: aliceblue;
|
||||
|
||||
.el-icon {
|
||||
margin-bottom: 40%;
|
||||
font-size: 130%;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 85%;
|
||||
line-height: 85%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload__tip {
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
324
src/components/UploadFile/src/UploadImgs.vue
Normal file
324
src/components/UploadFile/src/UploadImgs.vue
Normal file
@@ -0,0 +1,324 @@
|
||||
<template>
|
||||
<div class='upload-box'>
|
||||
<el-upload
|
||||
v-model:file-list='fileList'
|
||||
:accept="fileType.join(',')"
|
||||
:action='uploadUrl'
|
||||
:before-upload='beforeUpload'
|
||||
:class="['upload', drag ? 'no-border' : '']"
|
||||
:disabled='disabled'
|
||||
:drag='drag'
|
||||
:http-request='httpRequest'
|
||||
:limit='limit'
|
||||
:multiple='true'
|
||||
:on-error='uploadError'
|
||||
:on-exceed='handleExceed'
|
||||
:on-success='uploadSuccess'
|
||||
list-type='picture-card'
|
||||
>
|
||||
<div class='upload-empty'>
|
||||
<slot name='empty'>
|
||||
<Plus />
|
||||
<!-- <span>请上传图片</span> -->
|
||||
</slot>
|
||||
</div>
|
||||
<template #file='{ file }'>
|
||||
<img :src='file.url' class='upload-image' />
|
||||
<div class='upload-handle' @click.stop>
|
||||
<div class='handle-icon' @click='handlePictureCardPreview(file)'>
|
||||
<ZoomIn />
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div v-if='!disabled' class='handle-icon' @click='handleRemove(file)'>
|
||||
<Delete />
|
||||
<span>删除</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<div class='el-upload__tip'>
|
||||
<slot name='tip'></slot>
|
||||
</div>
|
||||
<el-image-viewer
|
||||
v-if='imgViewVisible'
|
||||
:url-list='[viewImageUrl]'
|
||||
@close='imgViewVisible = false'
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script lang='ts' setup>
|
||||
import type { UploadFile, UploadProps, UploadUserFile } from 'element-plus'
|
||||
import { ElNotification } from 'element-plus'
|
||||
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { useUpload } from '@/components/UploadFile/src/useUpload'
|
||||
import { Plus, Edit, ZoomIn, Delete } from '@element-plus/icons-vue'
|
||||
|
||||
defineOptions({ name: 'UploadImgs' })
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
|
||||
type FileTypes =
|
||||
| 'image/apng'
|
||||
| 'image/bmp'
|
||||
| 'image/gif'
|
||||
| 'image/jpeg'
|
||||
| 'image/pjpeg'
|
||||
| 'image/png'
|
||||
| 'image/svg+xml'
|
||||
| 'image/tiff'
|
||||
| 'image/webp'
|
||||
| 'image/x-icon'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
|
||||
drag: propTypes.bool.def(true), // 是否支持拖拽上传 ==> 非必传(默认为 true)
|
||||
disabled: propTypes.bool.def(false), // 是否禁用上传组件 ==> 非必传(默认为 false)
|
||||
limit: propTypes.number.def(5), // 最大图片上传数 ==> 非必传(默认为 5张)
|
||||
fileSize: propTypes.number.def(5), // 图片大小限制 ==> 非必传(默认为 5M)
|
||||
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 图片类型限制 ==> 非必传(默认为 ["image/jpeg", "image/png", "image/gif"])
|
||||
height: propTypes.string.def('150px'), // 组件高度 ==> 非必传(默认为 150px)
|
||||
width: propTypes.string.def('150px'), // 组件宽度 ==> 非必传(默认为 150px)
|
||||
borderradius: propTypes.string.def('8px') // 组件边框圆角 ==> 非必传(默认为 8px)
|
||||
})
|
||||
|
||||
const { uploadUrl, httpRequest } = useUpload()
|
||||
|
||||
const fileList = ref<UploadUserFile[]>([])
|
||||
const uploadNumber = ref<number>(0)
|
||||
const uploadList = ref<UploadUserFile[]>([])
|
||||
/**
|
||||
* @description 文件上传之前判断
|
||||
* @param rawFile 上传的文件
|
||||
* */
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
|
||||
const imgType = props.fileType
|
||||
if (!imgType.includes(rawFile.type as FileTypes))
|
||||
ElNotification({
|
||||
title: '温馨提示',
|
||||
message: '上传图片不符合所需的格式!',
|
||||
type: 'warning'
|
||||
})
|
||||
if (!imgSize)
|
||||
ElNotification({
|
||||
title: '温馨提示',
|
||||
message: `上传图片大小不能超过 ${props.fileSize}M!`,
|
||||
type: 'warning'
|
||||
})
|
||||
uploadNumber.value++
|
||||
return imgType.includes(rawFile.type as FileTypes) && imgSize
|
||||
}
|
||||
|
||||
// 图片上传成功
|
||||
interface UploadEmits {
|
||||
(e: 'update:modelValue', value: string[]): void
|
||||
}
|
||||
|
||||
const emit = defineEmits<UploadEmits>()
|
||||
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
|
||||
message.success('上传成功')
|
||||
// 删除自身
|
||||
const index = fileList.value.findIndex((item) => item.response?.data === res.data)
|
||||
fileList.value.splice(index, 1)
|
||||
uploadList.value.push({ name: res.data, url: res.data })
|
||||
if (uploadList.value.length == uploadNumber.value) {
|
||||
fileList.value.push(...uploadList.value)
|
||||
uploadList.value = []
|
||||
uploadNumber.value = 0
|
||||
emitUpdateModelValue()
|
||||
}
|
||||
}
|
||||
|
||||
// 监听模型绑定值变动
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val: string | string[]) => {
|
||||
if (!val) {
|
||||
fileList.value = [] // fix:处理掉缓存,表单重置后上传组件的内容并没有重置
|
||||
return
|
||||
}
|
||||
|
||||
fileList.value = [] // 保障数据为空
|
||||
fileList.value.push(
|
||||
...(val as string[]).map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
|
||||
)
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
// 发送图片链接列表更新
|
||||
const emitUpdateModelValue = () => {
|
||||
let result: string[] = fileList.value.map((file) => file.url!)
|
||||
emit('update:modelValue', result)
|
||||
}
|
||||
// 删除图片
|
||||
const handleRemove = (uploadFile: UploadFile) => {
|
||||
fileList.value = fileList.value.filter(
|
||||
(item) => item.url !== uploadFile.url || item.name !== uploadFile.name
|
||||
)
|
||||
emit(
|
||||
'update:modelValue',
|
||||
fileList.value.map((file) => file.url!)
|
||||
)
|
||||
}
|
||||
|
||||
// 图片上传错误提示
|
||||
const uploadError = () => {
|
||||
ElNotification({
|
||||
title: '温馨提示',
|
||||
message: '图片上传失败,请您重新上传!',
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
|
||||
// 文件数超出提示
|
||||
const handleExceed = () => {
|
||||
ElNotification({
|
||||
title: '温馨提示',
|
||||
message: `当前最多只能上传 ${props.limit} 张图片,请移除后上传!`,
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
|
||||
// 图片预览
|
||||
const viewImageUrl = ref('')
|
||||
const imgViewVisible = ref(false)
|
||||
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
|
||||
viewImageUrl.value = uploadFile.url!
|
||||
imgViewVisible.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.is-error {
|
||||
.upload {
|
||||
:deep(.el-upload--picture-card),
|
||||
:deep(.el-upload-dragger) {
|
||||
border: 1px dashed var(--el-color-danger) !important;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.disabled) {
|
||||
.el-upload--picture-card,
|
||||
.el-upload-dragger {
|
||||
cursor: not-allowed;
|
||||
background: var(--el-disabled-bg-color) !important;
|
||||
border: 1px dashed var(--el-border-color-darker);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-border-color-darker) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.upload-box {
|
||||
.no-border {
|
||||
:deep(.el-upload--picture-card) {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.upload) {
|
||||
.el-upload-dragger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border: 1px dashed var(--el-border-color-darker);
|
||||
border-radius: v-bind(borderradius);
|
||||
|
||||
&:hover {
|
||||
border: 1px dashed var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload-dragger.is-dragover {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
border: 2px dashed var(--el-color-primary) !important;
|
||||
}
|
||||
|
||||
.el-upload-list__item,
|
||||
.el-upload--picture-card {
|
||||
width: v-bind(width);
|
||||
height: v-bind(height);
|
||||
background-color: transparent;
|
||||
border-radius: v-bind(borderradius);
|
||||
}
|
||||
|
||||
.upload-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.upload-handle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
background: rgb(0 0 0 / 60%);
|
||||
opacity: 0;
|
||||
box-sizing: border-box;
|
||||
transition: var(--el-transition-duration-fast);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.handle-icon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 6%;
|
||||
color: aliceblue;
|
||||
|
||||
.el-icon {
|
||||
margin-bottom: 15%;
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload-list__item {
|
||||
&:hover {
|
||||
.upload-handle {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.upload-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
line-height: 30px;
|
||||
color: var(--el-color-info);
|
||||
|
||||
.el-icon {
|
||||
font-size: 28px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload__tip {
|
||||
line-height: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
99
src/components/UploadFile/src/useUpload.ts
Normal file
99
src/components/UploadFile/src/useUpload.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
// import * as FileApi from '@/api/infra/file'
|
||||
import CryptoJS from 'crypto-js'
|
||||
import { UploadRawFile, UploadRequestOptions } from 'element-plus/es/components/upload/src/upload'
|
||||
import axios from 'axios'
|
||||
import { uploadFile } from '@/api/system-boot/file'
|
||||
|
||||
export const useUpload = () => {
|
||||
// 后端上传地址
|
||||
const uploadUrl = 'import.meta.env.VITE_UPLOAD_URL'
|
||||
// // 是否使用前端直连上传
|
||||
// const isClientUpload = UPLOAD_TYPE.CLIENT === import.meta.env.VITE_UPLOAD_TYPE
|
||||
const isClientUpload = false
|
||||
// 重写ElUpload上传方法
|
||||
const httpRequest = async (options: UploadRequestOptions) => {
|
||||
// 模式一:前端上传
|
||||
// if (isClientUpload) {
|
||||
// // 1.1 生成文件名称
|
||||
// const fileName = await generateFileName(options.file)
|
||||
// // 1.2 获取文件预签名地址
|
||||
// const presignedInfo = await FileApi.getFilePresignedUrl(fileName)
|
||||
// // 1.3 上传文件(不能使用 ElUpload 的 ajaxUpload 方法的原因:其使用的是 FormData 上传,Minio 不支持)
|
||||
// return axios.put(presignedInfo.uploadUrl, options.file, {
|
||||
// headers: {
|
||||
// 'Content-Type': options.file.type,
|
||||
// }
|
||||
// }).then(() => {
|
||||
// // 1.4. 记录文件信息到后端(异步)
|
||||
// createFile(presignedInfo, fileName, options.file)
|
||||
// // 通知成功,数据格式保持与后端上传的返回结果一致
|
||||
// return { data: presignedInfo.url }
|
||||
// })
|
||||
// } else {
|
||||
// 模式二:后端上传
|
||||
// 重写 el-upload httpRequest 文件上传成功会走成功的钩子,失败走失败的钩子
|
||||
return new Promise((resolve, reject) => {
|
||||
uploadFile({ file: options.file, path: 'backUpFile' })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
resolve(res)
|
||||
} else {
|
||||
reject(res)
|
||||
}
|
||||
})
|
||||
.catch((res) => {
|
||||
reject(res)
|
||||
})
|
||||
})
|
||||
// }
|
||||
}
|
||||
|
||||
return {
|
||||
uploadUrl,
|
||||
httpRequest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件信息
|
||||
* @param vo 文件预签名信息
|
||||
* @param name 文件名称
|
||||
* @param file 文件
|
||||
*/
|
||||
function createFile(vo: FileApi.FilePresignedUrlRespVO, name: string, file: UploadRawFile) {
|
||||
const fileVo = {
|
||||
configId: vo.configId,
|
||||
url: vo.url,
|
||||
path: name,
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
size: file.size
|
||||
}
|
||||
FileApi.createFile(fileVo)
|
||||
return fileVo
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文件名称(使用算法SHA256)
|
||||
* @param file 要上传的文件
|
||||
*/
|
||||
async function generateFileName(file: UploadRawFile) {
|
||||
// 读取文件内容
|
||||
const data = await file.arrayBuffer()
|
||||
const wordArray = CryptoJS.lib.WordArray.create(data)
|
||||
// 计算SHA256
|
||||
const sha256 = CryptoJS.SHA256(wordArray).toString()
|
||||
// 拼接后缀
|
||||
const ext = file.name.substring(file.name.lastIndexOf('.'))
|
||||
return `${sha256}${ext}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传类型
|
||||
*/
|
||||
enum UPLOAD_TYPE {
|
||||
// 客户端直接上传(只支持S3服务)
|
||||
CLIENT = 'client',
|
||||
// 客户端发送到后端上传
|
||||
SERVER = 'server'
|
||||
}
|
||||
4
src/components/XButton/index.ts
Normal file
4
src/components/XButton/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import XButton from './src/XButton.vue'
|
||||
import XTextButton from './src/XTextButton.vue'
|
||||
|
||||
export { XButton, XTextButton }
|
||||
50
src/components/XButton/src/XButton.vue
Normal file
50
src/components/XButton/src/XButton.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<script lang="ts" setup>
|
||||
import { PropType,computed,useAttrs } from 'vue'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
|
||||
defineOptions({ name: 'XButton' })
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: propTypes.bool.def(false),
|
||||
loading: propTypes.bool.def(false),
|
||||
preIcon: propTypes.string.def(''),
|
||||
postIcon: propTypes.string.def(''),
|
||||
title: propTypes.string.def(''),
|
||||
type: propTypes.oneOf(['', 'primary', 'success', 'warning', 'danger', 'info']).def(''),
|
||||
link: propTypes.bool.def(false),
|
||||
circle: propTypes.bool.def(false),
|
||||
round: propTypes.bool.def(false),
|
||||
plain: propTypes.bool.def(false),
|
||||
onClick: { type: Function as PropType<(...args) => any>, default: null }
|
||||
})
|
||||
const getBindValue = computed(() => {
|
||||
const delArr: string[] = ['title', 'preIcon', 'postIcon', 'onClick']
|
||||
const attrs = useAttrs()
|
||||
const obj = { ...attrs, ...props }
|
||||
for (const key in obj) {
|
||||
if (delArr.indexOf(key) !== -1) {
|
||||
delete obj[key]
|
||||
}
|
||||
}
|
||||
return obj
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-button v-bind="getBindValue" @click="onClick">
|
||||
<Icon v-if="preIcon" :icon="preIcon" class="mr-1px" />
|
||||
{{ title ? title : '' }}
|
||||
<Icon v-if="postIcon" :icon="postIcon" class="mr-1px" />
|
||||
</el-button>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-button.is-text) {
|
||||
padding: 8px 4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
:deep(.el-button.is-link) {
|
||||
padding: 8px 4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
</style>
|
||||
49
src/components/XButton/src/XTextButton.vue
Normal file
49
src/components/XButton/src/XTextButton.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<script lang="ts" setup>
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { PropType } from 'vue'
|
||||
|
||||
defineOptions({ name: 'XTextButton' })
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: propTypes.bool.def(false),
|
||||
loading: propTypes.bool.def(false),
|
||||
preIcon: propTypes.string.def(''),
|
||||
postIcon: propTypes.string.def(''),
|
||||
title: propTypes.string.def(''),
|
||||
type: propTypes.oneOf(['', 'primary', 'success', 'warning', 'danger', 'info']).def('primary'),
|
||||
circle: propTypes.bool.def(false),
|
||||
round: propTypes.bool.def(false),
|
||||
plain: propTypes.bool.def(false),
|
||||
onClick: { type: Function as PropType<(...args) => any>, default: null }
|
||||
})
|
||||
const getBindValue = computed(() => {
|
||||
const delArr: string[] = ['title', 'preIcon', 'postIcon', 'onClick']
|
||||
const attrs = useAttrs()
|
||||
const obj = { ...attrs, ...props }
|
||||
for (const key in obj) {
|
||||
if (delArr.indexOf(key) !== -1) {
|
||||
delete obj[key]
|
||||
}
|
||||
}
|
||||
return obj
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-button link v-bind="getBindValue" @click="onClick">
|
||||
<Icon v-if="preIcon" :icon="preIcon" class="mr-1px" />
|
||||
{{ title ? title : '' }}
|
||||
<Icon v-if="postIcon" :icon="postIcon" class="mr-1px" />
|
||||
</el-button>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-button.is-text) {
|
||||
padding: 8px 4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
:deep(.el-button.is-link) {
|
||||
padding: 8px 4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<start-events v-if="childNode.type === 'startEvent'" v-model="childNode" :currentActivityId="currentActivityId" />
|
||||
<start-tasks v-if="childNode.type === 'startTask'" v-model="childNode" :currentActivityId="currentActivityId" />
|
||||
<user-tasks v-if="childNode.type === 'userTask'" v-model="childNode" :currentActivityId="currentActivityId" />
|
||||
<service-tasks v-if="childNode.type === 'serviceTask'" v-model="childNode" :currentActivityId="currentActivityId" />
|
||||
<exclusive-gateways v-if="childNode.type === 'exclusiveGateway'" v-model="childNode" :currentActivityId="currentActivityId">
|
||||
<template #default="slot">
|
||||
<c-node-wrap v-if="slot.node" v-model="slot.node.childNode" :currentActivityId="currentActivityId" />
|
||||
</template>
|
||||
</exclusive-gateways>
|
||||
<parallel-gateways v-if="childNode.type === 'parallelGateway'" v-model="childNode" :currentActivityId="currentActivityId">
|
||||
<template #default="slot">
|
||||
<c-node-wrap v-if="slot.node" v-model="slot.node.childNode" :currentActivityId="currentActivityId" />
|
||||
</template>
|
||||
</parallel-gateways>
|
||||
<c-node-wrap v-if="childNode.childNode" v-model="childNode.childNode" :currentActivityId="currentActivityId" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import startEvents from './nodes/cStartEvent.vue'
|
||||
import startTasks from './nodes/cStartTask.vue'
|
||||
import userTasks from './nodes/cUserTask.vue'
|
||||
import exclusiveGateways from './nodes/cExclusiveGateway.vue'
|
||||
import parallelGateways from './nodes/cParallelGateway.vue'
|
||||
import serviceTasks from './nodes/cServiceTask.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
startEvents,
|
||||
startTasks,
|
||||
userTasks,
|
||||
exclusiveGateways,
|
||||
parallelGateways,
|
||||
serviceTasks
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
currentActivityId: { type: String, default: () => '' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue(val) {
|
||||
this.childNode = val
|
||||
},
|
||||
childNode(val) {
|
||||
this.$emit('update:modelValue', val)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,80 +0,0 @@
|
||||
<template>
|
||||
<div class="workflow-design">
|
||||
<div class="workflow-design-btns">
|
||||
<a-space>
|
||||
<a-tooltip>
|
||||
<template #title>放大</template>
|
||||
<a-button @click="handleZoom(true)" :disabled="zoom > 2">
|
||||
<template #icon><plus-outlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>缩小</template>
|
||||
<a-button @click="handleZoom(false)" :disabled="zoom < 1">
|
||||
<template #icon><minus-outlined /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</div>
|
||||
<div id="div1">
|
||||
<div class="box-scale" :style="style">
|
||||
<node-wrap-chart v-if="childNode" v-model="childNode.childNode" :currentActivityId="currentActivityId" />
|
||||
<div class="end-node">
|
||||
<div class="end-node-circle"></div>
|
||||
<div class="end-node-text">流程结束</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import nodeWrapChart from '@/components/XnWorkflow/chart/cNodeWrap.vue'
|
||||
import FullscreenPreviewHelper from './zoom_helper'
|
||||
|
||||
const FullScreenRightSpace = 20
|
||||
export default {
|
||||
components: {
|
||||
nodeWrapChart
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
currentActivityId: { type: String, default: () => '' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: this.modelValue,
|
||||
style: {},
|
||||
zoom: 1
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
modelValue(val) {
|
||||
this.childNode = val
|
||||
},
|
||||
childNode(val) {
|
||||
this.$emit('update:modelValue', val)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleGetStyle(zoom) {
|
||||
return FullscreenPreviewHelper.getZoomStyles(zoom, 1, 0, FullScreenRightSpace)
|
||||
},
|
||||
handleZoom(zoomIn) {
|
||||
const zoom = this.zoom
|
||||
const zoomData = FullscreenPreviewHelper.getZoomData(zoomIn, zoom)
|
||||
const style = this.handleGetStyle(zoomData.zoom)
|
||||
this.style = style
|
||||
this.zoom = zoomData.zoom
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../flowIndex.less';
|
||||
.workflow-design-btns {
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +0,0 @@
|
||||
<template>
|
||||
<div class="add-node-btn-box">
|
||||
<div class="add-node-btn"></div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,141 +0,0 @@
|
||||
<template>
|
||||
<div class="branch-wrap">
|
||||
<div class="branch-box-wrap">
|
||||
<div class="branch-box" style="margin-top: 0px">
|
||||
<div v-for="(item, index) in childNode.conditionNodeList" :key="index" class="col-box">
|
||||
<div class="condition-node">
|
||||
<div class="condition-node-box">
|
||||
<div class="auto-judge">
|
||||
<div class="title">
|
||||
<span class="node-title">{{ item.title }}</span>
|
||||
<span class="priority-title">优先级{{ item.properties.configInfo.priorityLevel }}</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span v-if="toText(childNode, index)">{{ toText(childNode, index) }}</span>
|
||||
<span v-else class="placeholder">请设置条件</span>
|
||||
</div>
|
||||
</div>
|
||||
<add-nodes v-model="item.childNode" />
|
||||
</div>
|
||||
</div>
|
||||
<slot v-if="item.childNode" :node="item"></slot>
|
||||
<div v-if="index == 0" class="top-left-cover-line"></div>
|
||||
<div v-if="index == 0" class="bottom-left-cover-line"></div>
|
||||
<div v-if="index == childNode.conditionNodeList.length - 1" class="top-right-cover-line"></div>
|
||||
<div v-if="index == childNode.conditionNodeList.length - 1" class="bottom-right-cover-line"></div>
|
||||
</div>
|
||||
</div>
|
||||
<add-nodes v-model="childNode.childNode" :parent-data="childNode" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addNodes from './cAddNode.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
addNodes
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
currentActivityId: { type: String, default: () => '' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {},
|
||||
index: 0,
|
||||
operatorList: [
|
||||
{
|
||||
label: '等于',
|
||||
value: '=='
|
||||
},
|
||||
{
|
||||
label: '不等于',
|
||||
value: '!='
|
||||
},
|
||||
{
|
||||
label: '大于',
|
||||
value: '>'
|
||||
},
|
||||
{
|
||||
label: '大于等于',
|
||||
value: '>='
|
||||
},
|
||||
{
|
||||
label: '小于',
|
||||
value: '<'
|
||||
},
|
||||
{
|
||||
label: '小于等于',
|
||||
value: '<='
|
||||
},
|
||||
{
|
||||
label: '包含',
|
||||
value: 'include'
|
||||
},
|
||||
{
|
||||
label: '不包含',
|
||||
value: 'notInclude'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
toText(childNode, index) {
|
||||
const conditionList = childNode.conditionNodeList[index].properties.conditionInfo
|
||||
const priorityLevel = childNode.conditionNodeList[index].properties.configInfo.priorityLevel
|
||||
const len = this.childNode.conditionNodeList.length
|
||||
const priorityLevelMax = this.childNode.conditionNodeList[len - 1].properties.configInfo.priorityLevel
|
||||
|
||||
if (JSON.stringify(conditionList) !== undefined && conditionList.length > 0) {
|
||||
let text = ''
|
||||
for (let i = 0; i < conditionList.length; i++) {
|
||||
for (let j = 0; j < conditionList[i].length; j++) {
|
||||
if (j + 1 !== conditionList[i].length) {
|
||||
text =
|
||||
text +
|
||||
conditionList[i][j].label +
|
||||
this.getOperatorLabel(conditionList[i][j].operator) +
|
||||
conditionList[i][j].value +
|
||||
' 且 '
|
||||
} else {
|
||||
text =
|
||||
text +
|
||||
conditionList[i][j].label +
|
||||
this.getOperatorLabel(conditionList[i][j].operator) +
|
||||
conditionList[i][j].value
|
||||
}
|
||||
}
|
||||
if (i + 1 !== conditionList.length) {
|
||||
text = text + ' 或 '
|
||||
}
|
||||
}
|
||||
return text
|
||||
} else if (conditionList.length === 0 && priorityLevel < priorityLevelMax) {
|
||||
return false
|
||||
} else {
|
||||
return '其他条件进入此流程'
|
||||
}
|
||||
},
|
||||
// 通过value 获取界面显示的label汉字
|
||||
getOperatorLabel(value) {
|
||||
return this.operatorList.find((item) => item.value === value).label
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped type="less">
|
||||
.workflow-design .condition-node {
|
||||
min-height: 200px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -1,50 +0,0 @@
|
||||
<template>
|
||||
<div class="branch-wrap">
|
||||
<div class="branch-box-wrap">
|
||||
<div class="branch-box">
|
||||
<div v-for="(item, index) in childNode.conditionNodeList" :key="index" class="col-box">
|
||||
<div class="condition-node">
|
||||
<div class="condition-node-box">
|
||||
<user-tasks v-model="childNode.conditionNodeList[index]" :currentActivityId="currentActivityId" />
|
||||
</div>
|
||||
</div>
|
||||
<slot v-if="item.childNode" :node="item"></slot>
|
||||
<div v-if="index == 0" class="top-left-cover-line"></div>
|
||||
<div v-if="index == 0" class="bottom-left-cover-line"></div>
|
||||
<div v-if="index == childNode.conditionNodeList.length - 1" class="top-right-cover-line"></div>
|
||||
<div v-if="index == childNode.conditionNodeList.length - 1" class="bottom-right-cover-line"></div>
|
||||
</div>
|
||||
</div>
|
||||
<add-nodes v-model="childNode.childNode" :parent-data="childNode" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addNodes from './cAddNode.vue'
|
||||
import userTasks from './cUserTask.vue'
|
||||
export default {
|
||||
components: {
|
||||
addNodes,
|
||||
userTasks
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
currentActivityId: { type: String, default: () => '' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {},
|
||||
index: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,80 +0,0 @@
|
||||
<template>
|
||||
<div class="node-wrap">
|
||||
<a-tooltip placement="left">
|
||||
<template #title v-if="childNode.properties && childNode.properties.commentList.length > 0">
|
||||
<div v-for="comment in childNode.properties.commentList" :key="comment.id">
|
||||
{{ comment.userName }}于{{ comment.approveTime }}
|
||||
<a-tag color="rgb(212, 212, 212)">{{ comment.operateText }}</a-tag
|
||||
>,意见:{{ comment.comment }}
|
||||
</div>
|
||||
</template>
|
||||
<div :class="childNode.properties && childNode.properties.commentList.length > 0 ? 'node-state-label' : ''">
|
||||
<div class="node-wrap-box">
|
||||
<div class="title" style="background: #3296fa">
|
||||
<send-outlined class="icon" />
|
||||
<span>{{ childNode.title }}</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span v-if="toText(childNode)">{{ toText(childNode) }}</span>
|
||||
<span v-else class="placeholder">未选择人员</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<add-nodes v-model="childNode.childNode" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addNodes from './cAddNode.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
addNodes
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
currentActivityId: { type: String, default: () => '' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
toText(childNode) {
|
||||
if (JSON.stringify(childNode) !== '{}') {
|
||||
const participateInfo = childNode.properties.participateInfo
|
||||
if (participateInfo.length > 0) {
|
||||
let resultArray = []
|
||||
if (participateInfo[0].label.indexOf(',') !== -1) {
|
||||
resultArray = participateInfo[0].label.split(',')
|
||||
} else {
|
||||
resultArray.push(participateInfo[0].label)
|
||||
}
|
||||
return resultArray.toString()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.node-state-label {
|
||||
padding: 1px;
|
||||
border: 3px solid rgb(24, 144, 255);
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,24 +0,0 @@
|
||||
<template>
|
||||
<div class="node-wrap"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,76 +0,0 @@
|
||||
<template>
|
||||
<div class="node-wrap">
|
||||
<a-tooltip placement="left">
|
||||
<template #title v-if="childNode.properties && childNode.properties.commentList.length > 0">
|
||||
<div v-for="comment in childNode.properties.commentList" :key="comment.id">
|
||||
{{ comment.userName }}于{{ comment.approveTime }}
|
||||
<a-tag color="rgb(212, 212, 212)">{{ comment.operateText }}</a-tag
|
||||
>,意见:{{ comment.comment }}
|
||||
</div>
|
||||
</template>
|
||||
<div :class="getClassName()">
|
||||
<div class="node-wrap-box start-node">
|
||||
<div class="title" style="background: #576a95">
|
||||
<user-outlined class="icon" />
|
||||
<span>{{ childNode.title }}</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span>{{ toText(childNode) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<add-nodes v-model="childNode.childNode" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addNodes from './cAddNode.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
addNodes
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
currentActivityId: { type: String, default: () => '' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
toText() {
|
||||
return '系统自动配置参与人'
|
||||
},
|
||||
getClassName() {
|
||||
if (this.childNode.id === this.currentActivityId) {
|
||||
return 'node-state-label-activity'
|
||||
} else {
|
||||
return this.childNode.properties && this.childNode.properties.commentList.length > 0 ? 'node-state-label' : ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.node-state-label {
|
||||
padding: 1px;
|
||||
border: 3px solid rgb(24, 144, 255);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.node-state-label-activity {
|
||||
padding: 1px;
|
||||
border: 3px dashed #00e97c;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,147 +0,0 @@
|
||||
<template>
|
||||
<div class="node-wrap">
|
||||
<a-tooltip placement="left">
|
||||
<template #title v-if="childNode.properties && childNode.properties.commentList.length > 0">
|
||||
<div v-for="comment in childNode.properties.commentList" :key="comment.id">
|
||||
{{ comment.userName }}于{{ comment.approveTime }}
|
||||
<a-tag color="rgb(212, 212, 212)">{{ comment.operateText }}</a-tag
|
||||
>,意见:{{ comment.comment }}
|
||||
</div>
|
||||
</template>
|
||||
<div :class="getClassName()">
|
||||
<div class="node-wrap-box">
|
||||
<div class="title" style="background: #ff943e">
|
||||
<user-outlined class="icon" />
|
||||
<span>{{ childNode.title }}</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span v-if="toText(childNode)">{{ toText(childNode) }}</span>
|
||||
<span v-else class="placeholder">未选择审批人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<add-nodes v-model="childNode.childNode" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addNodes from './cAddNode.vue'
|
||||
export default {
|
||||
components: {
|
||||
addNodes
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
currentActivityId: { type: String, default: () => '' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
toText(childNode) {
|
||||
if (JSON.stringify(childNode) !== '{}') {
|
||||
const strArray = this.toTag(childNode.properties.participateInfo[0])
|
||||
if (strArray.length > 0) {
|
||||
let value = ''
|
||||
// eslint-disable-next-line no-plusplus
|
||||
for (let i = 0; i < strArray.length; i++) {
|
||||
if (strArray.length === i + 1) {
|
||||
value = value + strArray[i]
|
||||
} else {
|
||||
value = value + strArray[i] + ','
|
||||
}
|
||||
}
|
||||
return value
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
toTag(participateInfo) {
|
||||
// eslint-disable-next-line no-undefined
|
||||
if (participateInfo === undefined) {
|
||||
return []
|
||||
}
|
||||
if (participateInfo.label === '') {
|
||||
return []
|
||||
} else {
|
||||
let resultArray = []
|
||||
if (participateInfo.label.indexOf(',') !== -1) {
|
||||
resultArray = participateInfo.label.split(',')
|
||||
} else {
|
||||
resultArray.push(participateInfo.label)
|
||||
}
|
||||
return resultArray
|
||||
}
|
||||
},
|
||||
getClassName() {
|
||||
if (this.childNode.properties && this.childNode.properties.commentList.length > 0) {
|
||||
if (this.childNode.properties.commentList.length === 1) {
|
||||
if (this.childNode.properties.commentList[0].operateType === 'PASS') {
|
||||
return 'node-state-label-pass'
|
||||
}
|
||||
if (this.childNode.properties.commentList[0].operateType === 'REJECT') {
|
||||
return 'node-state-label-reject'
|
||||
}
|
||||
if (this.childNode.properties.commentList[0].operateType === 'JUMP') {
|
||||
return 'node-state-label-jump'
|
||||
}
|
||||
if (this.childNode.properties.commentList[0].operateType === 'BACK') {
|
||||
return 'node-state-label-back'
|
||||
}
|
||||
}
|
||||
return 'node-state-label'
|
||||
} else {
|
||||
if (this.childNode.id === this.currentActivityId) {
|
||||
return 'node-state-label-activity'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.node-state-label {
|
||||
padding: 1px;
|
||||
border: 3px solid #1890ff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.node-state-label-pass {
|
||||
padding: 1px;
|
||||
border: 3px solid #52c41a;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.node-state-label-reject {
|
||||
padding: 1px;
|
||||
border: 3px solid #ff4d4f;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.node-state-label-jump {
|
||||
padding: 1px;
|
||||
border: 3px solid #bfbfbf;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.node-state-label-back {
|
||||
padding: 1px;
|
||||
border: 3px solid #bfbfbf;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.node-state-label-activity {
|
||||
padding: 1px;
|
||||
border: 3px dashed #00e97c;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,39 +0,0 @@
|
||||
const defaultZoomMargin = 360
|
||||
const perZoom = 0.25 // 每次放大缩小0.25倍
|
||||
|
||||
const ZoomHelper = {
|
||||
// 处理全屏放大的样式
|
||||
getZoomStyles(zoom, MinZoom = 1, ZoomMargin = defaultZoomMargin, rightSpace = 0) {
|
||||
const width = document.querySelector('.workflow-design').clientWidth
|
||||
let style = {}
|
||||
// 兼容Firefox浏览器的放大缩小
|
||||
if (zoom !== MinZoom) {
|
||||
style = {
|
||||
transform: `scale(${zoom})`,
|
||||
'transform-origin': '0 0',
|
||||
width: (width - ZoomMargin - rightSpace) / zoom + 'px'
|
||||
}
|
||||
}
|
||||
return style
|
||||
},
|
||||
// 获取最大的放大倍数
|
||||
getMaxZoom() {
|
||||
const width = window.innerWidth
|
||||
const mediumWidth = 1600
|
||||
const smallScreenScale = 2.5 // 小屏幕下附件放大3倍会有样式问题, 所以取2.5
|
||||
const bigScreenScale = 3 // 大于1600的最大倍数为3
|
||||
const maxZoom = width > mediumWidth ? bigScreenScale : smallScreenScale
|
||||
return maxZoom
|
||||
},
|
||||
// 获取点击放大缩小之后生成的最终的放大倍数和样式
|
||||
getZoomData(zoomIn, zoom) {
|
||||
const zoomResult = zoomIn ? zoom + perZoom : zoom - perZoom // 放大倍数加一次或者减少一次
|
||||
const zoomData = {
|
||||
style: this.getZoomStyles(zoomResult),
|
||||
zoom: zoomResult
|
||||
}
|
||||
return zoomData
|
||||
}
|
||||
}
|
||||
|
||||
export default ZoomHelper
|
||||
@@ -1,9 +0,0 @@
|
||||
审批中 蓝色 #1890FF
|
||||
已挂起 黄色 #FCC02E
|
||||
已完成 绿色 #52C41A
|
||||
已终止 黄色 #FF5A5A
|
||||
已撤回 灰色 #BFBFBF
|
||||
已拒绝 红色 #FF4D4F
|
||||
|
||||
同意 绿色 #52C41A
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
<template>
|
||||
<el-dialog v-model="dialogFormVisible" title="新增" width="500" :append-to-body="true">
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="140px" label-position="top">
|
||||
<el-form-item label="监听类型:" prop="listenerType">
|
||||
<el-select v-model="formData.listenerType" placeholder="请选择类型">
|
||||
<el-option
|
||||
v-for="item in listenerTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="JAVA监听器:" prop="javaClass">
|
||||
<el-select v-model="formData.javaClass" placeholder="请选择JAVA监听器">
|
||||
<el-option
|
||||
v-for="item in listenerValueArray"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="handleAdd">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, defineProps, defineEmits, watch } from 'vue'
|
||||
const dialogFormVisible = ref(true)
|
||||
const formLabelWidth = '140px'
|
||||
const props = defineProps({
|
||||
addFlag: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['close', 'addWacth'])
|
||||
watch(
|
||||
() => props.addFlag,
|
||||
(val, oldVal) => {
|
||||
console.log(val, oldVal)
|
||||
if (val) {
|
||||
dialogFormVisible.value = val
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
//必填规则
|
||||
const formRules = {
|
||||
listenerType: [{ required: true, message: '请选择监听类型', trigger: 'change' }],
|
||||
javaClass: [{ required: true, message: '请选择JAVA监听器', trigger: 'change' }]
|
||||
}
|
||||
//form
|
||||
const formData = reactive({
|
||||
listenerType: '',
|
||||
javaClass: ''
|
||||
})
|
||||
//监听类型数组
|
||||
const listenerTypeOptions = reactive([
|
||||
{
|
||||
label: '开始',
|
||||
value: '开始'
|
||||
},
|
||||
{
|
||||
label: '完成',
|
||||
value: '完成'
|
||||
},
|
||||
{
|
||||
label: '拒绝',
|
||||
value: '拒绝'
|
||||
},
|
||||
{
|
||||
label: '终止',
|
||||
value: '终止'
|
||||
},
|
||||
{
|
||||
label: '撤回',
|
||||
value: '撤回'
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
value: '删除'
|
||||
}
|
||||
])
|
||||
//java监听器数组
|
||||
const listenerValueArray = reactive([
|
||||
{
|
||||
label: 'vip.xiaonuo.flw.core.listener.FlwTestExecutionListener',
|
||||
value: 'vip.xiaonuo.flw.core.listener.FlwTestExecutionListener'
|
||||
}
|
||||
])
|
||||
//关闭
|
||||
async function handleClose() {
|
||||
emit('close')
|
||||
}
|
||||
//提交
|
||||
const formRef = ref(null)
|
||||
async function handleAdd() {
|
||||
formRef.value.validate(valid => {
|
||||
if (valid) {
|
||||
console.log(valid)
|
||||
emit("addWatch",formData);
|
||||
emit("close");
|
||||
} else {
|
||||
console.log('error submit!')
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
console.log()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dialog-footer {
|
||||
padding: 20px 15px !important;
|
||||
}
|
||||
.el-form {
|
||||
width: 96%;
|
||||
margin: 0 auto;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,92 +0,0 @@
|
||||
<template>
|
||||
<div class="drawers">
|
||||
<el-drawer
|
||||
v-model="drawerVisibile"
|
||||
title="全局属性"
|
||||
direction="rtl"
|
||||
size="50%"
|
||||
:before-close="handleClose"
|
||||
@closed="handleClose"
|
||||
>
|
||||
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane label="人员配置" name="0">
|
||||
<user v-if="activeName == 0"></user>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="基础配置" name="1">
|
||||
<basic v-if="activeName == 1"></basic>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="通知配置" name="2">
|
||||
<notice v-if="activeName == 2"></notice>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="表单预设" name="3">
|
||||
<formPreset v-if="activeName == 3"></formPreset>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="执行监听" name="4">
|
||||
<watchs v-if="activeName == 4"></watchs>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<template #footer>
|
||||
<div style="flex: auto" class="drawer_footer">
|
||||
<el-button type="primary" @click="handleConfirm">保存</el-button>
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import user from '../globalAttribute/user.vue'
|
||||
import basic from '../globalAttribute/basic.vue'
|
||||
import notice from '../globalAttribute/notice.vue'
|
||||
import formPreset from '../globalAttribute/formPreset.vue'
|
||||
import watchs from '../globalAttribute/watchs.vue'
|
||||
export default {
|
||||
components: {
|
||||
user,
|
||||
basic,
|
||||
notice,
|
||||
formPreset,
|
||||
watchs
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
drawerVisibile: true,
|
||||
activeName: '0'
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
handleClose() {
|
||||
this.$emit('updateDrawer')
|
||||
},
|
||||
handleClick(val) {
|
||||
console.log(val)
|
||||
},
|
||||
handleConfirm(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.drawers ::v-deep(.el-drawer__header) {
|
||||
margin-bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.drawers ::v-deep(.el-drawer__body){
|
||||
position:fixed;
|
||||
top:40px;
|
||||
left:50%;
|
||||
width:50%;
|
||||
}
|
||||
.drawer_footer{
|
||||
display: flex;
|
||||
width: 100px;
|
||||
justify-content: space-between;
|
||||
float: right;
|
||||
position:absolute;
|
||||
bottom: 20px;
|
||||
right:50px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,22 +0,0 @@
|
||||
<template>
|
||||
<div class="nav_title" :style="{ borderLeft: `4px solid ${borderColor}` }">
|
||||
<p><slot name="nav_name"></slot></p>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useConfig } from '@/stores/config'
|
||||
import { ref } from 'vue'
|
||||
const configStore = useConfig()
|
||||
const borderColor =configStore.getColorVal('elementUiPrimary')
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.nav_title {
|
||||
padding-left: 8px;
|
||||
margin-top: 10px;
|
||||
p {
|
||||
font-size: 15px;
|
||||
color: #212121;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,3 +0,0 @@
|
||||
<template>
|
||||
<a-result status="404" title="未找到表单" sub-title="对不起,该节点配置的自定义表单不存在,请联系管理员。" />
|
||||
</template>
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* 自定义表单导入
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2023-05-11 00:12:22
|
||||
*/
|
||||
const modules = import.meta.glob('/src/views/flw/customform/**/**.vue')
|
||||
const notFound = () => import(/* @vite-ignore */ `/src/components/XnWorkflow/customForm/404.vue`)
|
||||
|
||||
// 直接渲染组件
|
||||
export const loadComponent = (component) => {
|
||||
if (component) {
|
||||
const link = modules[`/src/views/flw/customform/${component}.vue`]
|
||||
return markRaw(defineAsyncComponent(link ? link : notFound))
|
||||
} else {
|
||||
return markRaw(defineAsyncComponent(notFound))
|
||||
}
|
||||
}
|
||||
|
||||
// 给出判断,如果使用的地方取到是404,那么他的下一步就不走了
|
||||
export const verdictComponent = (component) => {
|
||||
if (component) {
|
||||
const link = modules[`/src/views/flw/customform/${component}.vue`]
|
||||
return !!link
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,425 +0,0 @@
|
||||
.workflow-design {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
.workflow-design .box-scale {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 55px;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
min-width: min-content;
|
||||
}
|
||||
.nodeLegal {
|
||||
border: 2px solid red;
|
||||
border-radius: 1px;
|
||||
}
|
||||
.workflow-design {
|
||||
.node-wrap {
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
flex-flow: column wrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 0px 50px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.node-wrap-box {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 220px;
|
||||
min-height: 72px;
|
||||
flex-shrink: 0;
|
||||
background: var(--node-wrap-box-color);
|
||||
border-radius: 1px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.node-wrap-box::before {
|
||||
background: var(--auto-judge-before-color);
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 0px;
|
||||
border-style: solid;
|
||||
border-width: 8px 6px 4px;
|
||||
border-color: #cacaca transparent transparent;
|
||||
}
|
||||
.node-wrap-box.start-node:before {
|
||||
content: none;
|
||||
}
|
||||
.node-wrap-box .title {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
padding-left: 16px;
|
||||
padding-right: 30px;
|
||||
border-radius: 2px 2px 0 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.node-wrap-box .title .icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.node-wrap-box .title .close {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 10px;
|
||||
display: none;
|
||||
}
|
||||
.node-wrap-box .title .success {
|
||||
font-size: 20px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: -25px;
|
||||
display: block;
|
||||
color: #00bb00;
|
||||
}
|
||||
.node-wrap-box .content {
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
}
|
||||
.node-wrap-box .content .placeholder {
|
||||
color: red;
|
||||
}
|
||||
.node-wrap-box:hover .close {
|
||||
display: block;
|
||||
}
|
||||
.add-node-btn-box {
|
||||
width: 240px;
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.add-node-btn-box:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
z-index: -1;
|
||||
margin: auto;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background-color: rgb(202, 202, 202);
|
||||
}
|
||||
.add-node-btn {
|
||||
user-select: none;
|
||||
width: 240px;
|
||||
padding: 20px 0px 32px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.add-node-btn span {
|
||||
}
|
||||
.add-branch {
|
||||
justify-content: center;
|
||||
padding: 0px 10px;
|
||||
position: absolute;
|
||||
top: -16px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
transform-origin: center center;
|
||||
z-index: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
.branch-wrap {
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
}
|
||||
.branch-box-wrap {
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
align-items: center;
|
||||
min-height: 270px;
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.col-box {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
background: var(--component-background);
|
||||
}
|
||||
// 分支 上面横线
|
||||
.branch-box {
|
||||
display: flex;
|
||||
overflow: visible;
|
||||
min-height: 180px;
|
||||
height: auto;
|
||||
border-bottom: 2px solid #ccc;
|
||||
border-top: 2px solid #ccc;
|
||||
position: relative;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.branch-box .col-box::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
z-index: 0;
|
||||
margin: auto;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background-color: rgb(202, 202, 202);
|
||||
}
|
||||
.condition-node {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
min-height: 220px;
|
||||
}
|
||||
.condition-node-box {
|
||||
padding-top: 30px;
|
||||
padding-right: 50px;
|
||||
padding-left: 50px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.auto-judge {
|
||||
position: relative;
|
||||
width: 220px;
|
||||
min-height: 72px;
|
||||
background: var(--node-wrap-box-color);
|
||||
border-radius: 2px;
|
||||
padding: 15px 15px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
// 箭头框框
|
||||
.auto-judge::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 0px;
|
||||
border-style: solid;
|
||||
border-width: 8px 6px 4px;
|
||||
border-color: #cacaca transparent transparent;
|
||||
background: var(--auto-judge-before-color);
|
||||
}
|
||||
.auto-judge .title {
|
||||
line-height: 16px;
|
||||
}
|
||||
.auto-judge .title .node-title {
|
||||
color: #15bc83;
|
||||
}
|
||||
.auto-judge .title .close {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
color: #999;
|
||||
display: none;
|
||||
}
|
||||
.auto-judge .title .success {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
color: #999;
|
||||
display: block;
|
||||
}
|
||||
.auto-judge .title .priority-title {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
color: #999;
|
||||
}
|
||||
.auto-judge .content {
|
||||
position: relative;
|
||||
padding-top: 15px;
|
||||
}
|
||||
.auto-judge .content .placeholder {
|
||||
color: red;
|
||||
}
|
||||
.auto-judge:hover {
|
||||
.close {
|
||||
display: block;
|
||||
}
|
||||
.priority-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.top-left-cover-line,
|
||||
.top-right-cover-line {
|
||||
position: absolute;
|
||||
height: 3px;
|
||||
width: 50%;
|
||||
background-color: var(--component-background);
|
||||
top: -2px;
|
||||
}
|
||||
.bottom-left-cover-line,
|
||||
.bottom-right-cover-line {
|
||||
position: absolute;
|
||||
height: 3px;
|
||||
width: 50%;
|
||||
background-color: var(--component-background);
|
||||
bottom: -2px;
|
||||
}
|
||||
.top-left-cover-line {
|
||||
left: -1px;
|
||||
}
|
||||
.top-right-cover-line {
|
||||
right: -1px;
|
||||
}
|
||||
.bottom-left-cover-line {
|
||||
left: -1px;
|
||||
}
|
||||
.bottom-right-cover-line {
|
||||
right: -1px;
|
||||
}
|
||||
.end-node {
|
||||
border-radius: 50%;
|
||||
font-size: 14px;
|
||||
color: rgba(25, 31, 37, 0.4);
|
||||
text-align: left;
|
||||
}
|
||||
// 结束的小点点
|
||||
.end-node-circle {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin: auto;
|
||||
border-radius: 50%;
|
||||
background: #dbdcdc;
|
||||
}
|
||||
.end-node-text {
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.auto-judge:hover {
|
||||
.sort-left {
|
||||
display: flex;
|
||||
}
|
||||
.sort-right {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.auto-judge .sort-left {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.auto-judge .sort-right {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
right: 0;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.auto-judge .sort-left:hover,
|
||||
.auto-judge .sort-right:hover {
|
||||
background: var(--auto-judge-before-color);
|
||||
}
|
||||
.auto-judge:after {
|
||||
pointer-events: none;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
border-radius: 2px;
|
||||
transition: all 0.1s;
|
||||
}
|
||||
.auto-judge:hover:after {
|
||||
border: 1px solid #3296fa;
|
||||
box-shadow: 0 0 6px 0 rgba(50, 150, 250, 0.3);
|
||||
}
|
||||
.node-wrap-box:after {
|
||||
pointer-events: none;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
border-radius: 2px;
|
||||
transition: all 0.1s;
|
||||
}
|
||||
.node-wrap-box:hover:after {
|
||||
border: 1px solid #3296fa;
|
||||
box-shadow: 0 0 6px 0 rgba(50, 150, 250, 0.3);
|
||||
}
|
||||
}
|
||||
.tags-list {
|
||||
margin-top: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
.add-node-popover-body {
|
||||
height: 81px;
|
||||
}
|
||||
.add-node-popover-body li {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.add-node-popover-body li i {
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 38px;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.add-node-popover-body li i:hover {
|
||||
border: 1px solid #3296fa;
|
||||
background: #3296fa;
|
||||
color: #fff !important;
|
||||
}
|
||||
.add-node-popover-body li p {
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.node-wrap-drawer__title {
|
||||
padding-right: 40px;
|
||||
}
|
||||
.node-wrap-drawer__title label {
|
||||
cursor: pointer;
|
||||
}
|
||||
.node-wrap-drawer__title label:hover {
|
||||
border-bottom: 1px dashed #409eff;
|
||||
}
|
||||
.node-wrap-drawer__title .node-wrap-drawer-title-edit {
|
||||
color: #409eff;
|
||||
margin-left: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
<!-- 全局属性基础配置页面 -->
|
||||
<template>
|
||||
<div class="home">
|
||||
<navTitle>
|
||||
<template #nav_name>流程基础全局配置</template>
|
||||
</navTitle>
|
||||
<div class="basic_form">
|
||||
<el-form :model="form" label-width="auto" label-position="top">
|
||||
<div class="col">
|
||||
<el-form-item label="流水号">
|
||||
<el-col :span="12">
|
||||
<el-select
|
||||
style="width: 300px !important"
|
||||
v-model="form.region"
|
||||
placeholder="please select your zone"
|
||||
>
|
||||
<el-option label="Zone one" value="shanghai" />
|
||||
<el-option label="Zone two" value="beijing" />
|
||||
</el-select>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="打印模板">
|
||||
<el-col :span="12">
|
||||
<p style="width: 300px">自定义表单内提供打印方法</p>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<el-form-item label="标题模板">
|
||||
<div class="form_position_item">
|
||||
<el-input v-model="form.desc" type="textarea" />
|
||||
<el-button type="primary" size="small">
|
||||
置入字段
|
||||
<el-icon class="el-icon--right"><ArrowDownBold /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="摘要模板">
|
||||
<div class="form_position_item">
|
||||
<el-input v-model="form.desc" type="textarea" />
|
||||
<el-button type="primary" size="small">
|
||||
置入字段
|
||||
<el-icon class="el-icon--right"><ArrowDownBold /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开启自动去重">
|
||||
<el-switch v-model="form.delivery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="">
|
||||
<el-radio-group v-model="form.resource" class="radioGroup">
|
||||
<p><el-radio value="0">当审批人和发起人是同一个人,审批自动通过</el-radio></p>
|
||||
<p><el-radio value="1">当同一审批人在流程中连续多次出现时,自动去重</el-radio></p>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<div class="col">
|
||||
<el-form-item label="开启审批撤销">
|
||||
<el-switch v-model="form.delivery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开启意见必填">
|
||||
<el-switch v-model="form.delivery" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import navTitle from '../components/navTitle.vue'
|
||||
import { ArrowDownBold } from '@element-plus/icons-vue'
|
||||
import { ref } from 'vue'
|
||||
const form = ref({})
|
||||
form.value = {
|
||||
name: '',
|
||||
region: '',
|
||||
date1: '',
|
||||
date2: '',
|
||||
delivery: false,
|
||||
type: [],
|
||||
resource: '',
|
||||
desc: ''
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.home {
|
||||
width: 100%;
|
||||
height: calc(100vh - 170px);
|
||||
padding-top: 20px;
|
||||
overflow: auto;
|
||||
.basic_form {
|
||||
width:96%;
|
||||
padding-top: 10px;
|
||||
margin: 0 auto;
|
||||
.col {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.el-form-item {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
.form_position_item {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
position: relative;
|
||||
.el-input {
|
||||
height: 100%;
|
||||
}
|
||||
.el-button {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
z-index: 999;
|
||||
}
|
||||
}
|
||||
.radioGroup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,122 +0,0 @@
|
||||
<!-- 全局属性表单预设页面 -->
|
||||
<template>
|
||||
<div class="home">
|
||||
<navTitle>
|
||||
<template #nav_name>预设全局需要的表单</template>
|
||||
</navTitle>
|
||||
<div class="node_form">
|
||||
<el-form :model="form" label-width="auto" label-position="top">
|
||||
<el-form-item
|
||||
label="开始节点表单"
|
||||
name="processStartTaskFormUrl"
|
||||
:rules="[{ required: true, message: '请输入开始节点表单' }]"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.properties.configInfo.processStartTaskFormUrl"
|
||||
placeholder="请输入开始节点表单组件"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>src/views/flw/customform/</template>
|
||||
<template #append>.vue</template>
|
||||
<template #suffix>
|
||||
<el-button
|
||||
v-if="form.properties.configInfo.processStartTaskFormUrl"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="
|
||||
$refs.previewCustomFormRef.onOpen(
|
||||
form.properties.configInfo.processStartTaskFormUrl
|
||||
)
|
||||
"
|
||||
>
|
||||
预览
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="移动端开始节点表单"
|
||||
name="processStartTaskMobileFormUrl"
|
||||
:rules="[{ required: true, message: '请输入移动端开始节点表单', trigger: 'blur' }]"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.properties.configInfo.processStartTaskMobileFormUrl"
|
||||
placeholder="请输入移动端开始节点表单组件"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>pages/flw/customform/</template>
|
||||
<template #append>.vue</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="人员节点表单"
|
||||
name="processUserTaskFormUrl"
|
||||
:rules="[{ required: true, message: '请输入人员节点表单' }]"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.properties.configInfo.processUserTaskFormUrl"
|
||||
placeholder="请输入人员节点表单组件"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>src/views/flw/customform/</template>
|
||||
<template #append>.vue</template>
|
||||
<template #suffix>
|
||||
<el-button
|
||||
v-if="form.properties.configInfo.processUserTaskFormUrl"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="
|
||||
$refs.previewCustomFormRef.onOpen(form.properties.configInfo.processUserTaskFormUrl)
|
||||
"
|
||||
>
|
||||
预览
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="移动端人员节点表单"
|
||||
name="processUserTaskMobileFormUrl"
|
||||
:rules="[{ required: true, message: '请输入移动端人员节点表单' }]"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.properties.configInfo.processUserTaskMobileFormUrl"
|
||||
placeholder="请输入移动端人员节点表单组件"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>pages/flw/customform/</template>
|
||||
<template #append>.vue</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import navTitle from '../components/navTitle.vue'
|
||||
import { ref ,reactive} from 'vue'
|
||||
const form = ref({})
|
||||
form.value= {
|
||||
properties: {
|
||||
configInfo: {
|
||||
processStartTaskFormUrl: '', //开始节点表单
|
||||
processStartTaskMobileFormUrl: '', //移动端开始节点表单
|
||||
processUserTaskFormUrl: '', //人员节点表单
|
||||
processUserTaskMobileFormUrl: '' //移动端人员节点表单
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.home {
|
||||
width: 100%;
|
||||
height: calc(100vh - 170px);
|
||||
padding-top: 20px;
|
||||
overflow: auto;
|
||||
.node_form{
|
||||
width:96%;
|
||||
padding-top: 10px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,47 +0,0 @@
|
||||
<!-- 全局属性通知配置页面 -->
|
||||
<template>
|
||||
<div class="home">
|
||||
<div class="info">
|
||||
<navTitle>
|
||||
<template #nav_name>配置通知事项</template>
|
||||
</navTitle>
|
||||
</div>
|
||||
<div class="basic_form">
|
||||
<el-form :model="form" label-width="auto" label-position="top">
|
||||
<el-form-item label="开启退回通知">
|
||||
<el-switch v-model="form.delivery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开启待办通知">
|
||||
<el-switch v-model="form.delivery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开启抄送通知">
|
||||
<el-switch v-model="form.delivery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开启完成通知">
|
||||
<el-switch v-model="form.delivery" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import navTitle from '../components/navTitle.vue';
|
||||
import { ref } from 'vue'
|
||||
const form = ref({})
|
||||
form.value = {
|
||||
delivery: false,
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.home {
|
||||
width: 100%;
|
||||
height: calc(100vh - 100px);
|
||||
padding-top: 20px;
|
||||
overflow: auto;
|
||||
.basic_form {
|
||||
width:96%;
|
||||
padding-top: 10px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,105 +0,0 @@
|
||||
<!-- 全局属性人员配置页面 -->
|
||||
<template>
|
||||
<div class="home">
|
||||
<!-- 未选择任何类型的人员 -->
|
||||
<div class="nobody_info" v-if="checkUserList.length == 0">
|
||||
<p>未选择任何类型的人员配置,默认所有人均可参与此流程</p>
|
||||
</div>
|
||||
<navTitle>
|
||||
<template #nav_name>配置使用该流程的人员</template>
|
||||
</navTitle>
|
||||
<div class="info">
|
||||
<div class="info_item">
|
||||
<div class="info_item_top">
|
||||
<el-button type="primary">+ 选择机构</el-button>
|
||||
</div>
|
||||
<div class="info_item_bot">
|
||||
<div class="checked" v-for="(item, index) in 22">工会办公室{{ index+1 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info_item">
|
||||
<div class="info_item_top">
|
||||
<el-button type="primary">+ 选择角色</el-button>
|
||||
</div>
|
||||
<div class="info_item_bot">
|
||||
<div class="checked" v-for="(item, index) in 30">小诺科技有限公司{{ index+1 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info_item">
|
||||
<div class="info_item_top">
|
||||
<el-button type="primary">+ 选择用户</el-button>
|
||||
</div>
|
||||
<div class="info_item_bot">
|
||||
<div class="checked" v-for="(item, index) in 40">党群工作部{{ index+1 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { checkUser } from '@/api/user-boot/user'
|
||||
import navTitle from '../components/navTitle.vue'
|
||||
export default {
|
||||
components: {
|
||||
navTitle
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkUserList: []
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.home {
|
||||
width: 100%;
|
||||
height: calc(100vh - 170px);
|
||||
padding-top: 20px;
|
||||
overflow: auto;
|
||||
.nobody_info {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-color: #fffbe6;
|
||||
padding: 8px 15px;
|
||||
border-radius: 4px;
|
||||
border: 2px solid #ffe58f;
|
||||
p {
|
||||
font-size: 14px;
|
||||
font-variant: tabular-nums;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
.info_item {
|
||||
width: 100%;
|
||||
min-height: 80px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
.info_item_bot {
|
||||
height: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.checked {
|
||||
margin: 3px;
|
||||
padding: 0 7px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
white-space: nowrap;
|
||||
background: #FAFAFA;
|
||||
border: 1px solid #D9D9D9;
|
||||
border-radius: 2px;
|
||||
opacity: 1;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,66 +0,0 @@
|
||||
<!-- 全局属性执行监听页面 -->
|
||||
<template>
|
||||
<div class="home">
|
||||
<navTitle>
|
||||
<template #nav_name>配置要执行的监听</template>
|
||||
</navTitle>
|
||||
<div class="watchs_info">
|
||||
<el-button type="primary" :icon="Plus" size="small" @click="handleAdd">新增</el-button>
|
||||
<el-table :data="tableData" border style="width: 100%" height="400">
|
||||
<el-table-column align="left" prop="listenerType" label="名称" width="120" />
|
||||
<el-table-column align="left" prop="javaClass" label="JAVA监听器"/>
|
||||
<el-table-column align="left" fixed="right" label="操作" width="120">
|
||||
<template #default="scope">
|
||||
<el-button link type="danger" size="small" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 新增监听组件 -->
|
||||
<addWatch
|
||||
v-if="addFlag"
|
||||
v-model="addFlag"
|
||||
:addFlag="addFlag"
|
||||
@close="close"
|
||||
@addWatch="addTableData"
|
||||
></addWatch>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import navTitle from '../components/navTitle.vue'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import addWatch from '../components/addWatch.vue'
|
||||
let tableData = ref([])
|
||||
const addFlag = ref(false)
|
||||
async function handleAdd() {
|
||||
addFlag.value = true
|
||||
}
|
||||
const close = async () => {
|
||||
addFlag.value = false
|
||||
}
|
||||
//接收弹框新增数据
|
||||
function addTableData(val) {
|
||||
tableData.value = [...tableData.value, val]
|
||||
}
|
||||
//删除
|
||||
const handleDelete=(index,val)=>{
|
||||
tableData.value.splice(index,1)
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.home {
|
||||
width: 100%;
|
||||
height: calc(100vh - 100px);
|
||||
padding-top: 20px;
|
||||
.watchs_info {
|
||||
width: 96%;
|
||||
height: auto;
|
||||
margin-top: 10px;
|
||||
margin: 0 auto;
|
||||
.el-button {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,161 +0,0 @@
|
||||
<!--
|
||||
* @Descripttion: 仿钉钉流程设计器
|
||||
* @version: 1.2
|
||||
* @Author: sakuya
|
||||
* @Date: 2021年9月14日08:38:35
|
||||
* @LastEditors: yubaoshan
|
||||
* @LastEditTime: 2022年2月9日16:48:49
|
||||
-->
|
||||
<template>
|
||||
<div class="workflow-design">
|
||||
<!-- 配置流程全局属性 -->
|
||||
<div style="float: right; padding-right: 10px">
|
||||
<span v-if="!toDataLegal(childNode)" style="padding-right: 5px">
|
||||
<!-- <exclamation-circle-outlined style="color: red; font-size: 18px" />-->
|
||||
<!-- <Warning style="color: red; font-size: 18px"/>-->
|
||||
</span>
|
||||
<!-- <el-tooltip>-->
|
||||
<!-- <template #title></template>-->
|
||||
<!-- <el-button @click="$refs.process.showDrawer()">-->
|
||||
<!-- <template #icon>-->
|
||||
<!--<!– <setting-outlined />–>-->
|
||||
<!-- <Setting />-->
|
||||
<!-- </template>-->
|
||||
<!-- -->
|
||||
<!-- </el-button>-->
|
||||
<!-- </el-tooltip>-->
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" content="配置流程全局属性" placement="top-start">
|
||||
<el-button :icon="Setting" @click="drawerVisibile=true">
|
||||
全局配置
|
||||
<!-- <template #icon>
|
||||
<Setting />
|
||||
</template> -->
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="box-scale">
|
||||
<!-- 展示流程图组件 -->
|
||||
<!-- {{ childNode }}{{ modelValue }}444{{ childRecordData }}
|
||||
节点111{{ childNode }} -->
|
||||
<!-- {{ childRecordData }} -->
|
||||
<node-wrap
|
||||
v-if="childNode"
|
||||
v-model="childNode.childNode"
|
||||
:form-field-list-value="childFormFieldListValue"
|
||||
:record-data="childRecordData"
|
||||
:process-config-info="childNode.properties.configInfo"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
/>
|
||||
<!-- <nodeWrap v-if="childNode" v-model="childNode.childNode" :currentActivityId="currentActivityId" /> -->
|
||||
<div class="end-node">
|
||||
<div class="end-node-circle"></div>
|
||||
<div class="end-node-text">流程结束111</div>
|
||||
</div>
|
||||
</div>
|
||||
<process
|
||||
ref="process"
|
||||
v-model="childNode"
|
||||
:form-field-list-value="childFormFieldListValue"
|
||||
:record-data="childRecordData"
|
||||
:sn-template-array="snTemplateArray"
|
||||
:print-template-array="printTemplateArray"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:execution-listener-selector-for-custom-event-array="executionListenerSelectorForCustomEventArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
/>
|
||||
</div>
|
||||
<!-- 全局属性抽屉组件 -->
|
||||
<drawerTabs v-if="drawerVisibile" v-model="drawerVisibile" @updateDrawer="updateDrawer"></drawerTabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import nodeWrap from './nodeWrap.vue'
|
||||
import { Warning, Setting, Plus } from '@element-plus/icons-vue'
|
||||
import process from './process.vue'
|
||||
import drawerTabs from './components/drawerTabs.vue'
|
||||
export default {
|
||||
computed: {
|
||||
Plus() {
|
||||
return Plus
|
||||
},
|
||||
Setting(){
|
||||
return Setting
|
||||
},
|
||||
Setting(){
|
||||
return Warning
|
||||
}
|
||||
},
|
||||
components: {
|
||||
nodeWrap,
|
||||
Warning,
|
||||
Setting,
|
||||
process,
|
||||
drawerTabs
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
snTemplateArray: { type: Array, default: () => [] },
|
||||
printTemplateArray: { type: Array, default: () => [] },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
executionListenerSelectorForCustomEventArray: { type: Array, default: () => [] },
|
||||
listenerType: { type: String, default: () => 'default' },
|
||||
taskListenerArray: { type: Array, default: () => [] },
|
||||
selectorApiFunction: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
drawerVisibile: false,
|
||||
childNode: this.modelValue,
|
||||
childFormFieldListValue: this.formFieldListValue,
|
||||
childRecordData: this.recordData
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
|
||||
console.log(this);
|
||||
},
|
||||
watch: {
|
||||
modelValue(val) {
|
||||
console.log(val,"9999999");
|
||||
this.childNode = val
|
||||
},
|
||||
// 监听字段列表传输的相关动静
|
||||
formFieldListValue(val) {
|
||||
this.childFormFieldListValue = val
|
||||
},
|
||||
recordData(val) {
|
||||
this.childRecordData = val
|
||||
},
|
||||
childNode(val) {
|
||||
this.$emit('update:modelValue', val)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toDataLegal(childNode) {
|
||||
if (childNode === undefined) {
|
||||
return false
|
||||
} else {
|
||||
return childNode.dataLegal
|
||||
}
|
||||
},
|
||||
updateDrawer(){
|
||||
this.drawerVisibile=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import './flowIndex.less';
|
||||
.box-scale{
|
||||
width: 100%;
|
||||
height: calc(100vh - 150px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -1,120 +0,0 @@
|
||||
<template>
|
||||
<start-event v-if="childNode.type === 'startEvent'" v-model="childNode" />
|
||||
<start-task
|
||||
v-if="childNode.type === 'startTask'"
|
||||
v-model="childNode"
|
||||
:formFieldListValue="formFieldListValue"
|
||||
:recordData="recordData"
|
||||
:processConfigInfo="processConfigInfo"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
/>
|
||||
<user-task
|
||||
v-if="childNode.type === 'userTask'"
|
||||
v-model="childNode"
|
||||
:formFieldListValue="formFieldListValue"
|
||||
:recordData="recordData"
|
||||
:processConfigInfo="processConfigInfo"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
/>
|
||||
<service-task
|
||||
v-if="childNode.type === 'serviceTask'"
|
||||
v-model="childNode"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
:form-field-list-value="formFieldListValue"
|
||||
:record-data="recordData"
|
||||
/>
|
||||
<exclusive-gateway
|
||||
v-if="childNode.type === 'exclusiveGateway'"
|
||||
v-model="childNode"
|
||||
:form-field-list-value="formFieldListValue"
|
||||
:record-data="recordData"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
>
|
||||
<template #default="slot">
|
||||
<node-wrap
|
||||
v-if="slot.node"
|
||||
v-model="slot.node.childNode"
|
||||
:formFieldListValue="formFieldListValue"
|
||||
:recordData="recordData"
|
||||
:processConfigInfo="processConfigInfo"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
/>
|
||||
</template>
|
||||
</exclusive-gateway>
|
||||
<parallel-gateway
|
||||
v-if="childNode.type === 'parallelGateway'"
|
||||
v-model="childNode"
|
||||
:formFieldListValue="formFieldListValue"
|
||||
:recordData="recordData"
|
||||
:processConfigInfo="processConfigInfo"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
>
|
||||
<template #default="slot">
|
||||
<node-wrap
|
||||
v-if="slot.node"
|
||||
v-model="slot.node.childNode"
|
||||
:formFieldListValue="formFieldListValue"
|
||||
:recordData="recordData"
|
||||
:processConfigInfo="processConfigInfo"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
/>
|
||||
</template>
|
||||
</parallel-gateway>
|
||||
<node-wrap
|
||||
v-if="childNode.childNode"
|
||||
v-model="childNode.childNode"
|
||||
:formFieldListValue="formFieldListValue"
|
||||
:recordData="recordData"
|
||||
:processConfigInfo="processConfigInfo"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import StartEvent from './nodes/startEvent.vue'
|
||||
import StartTask from './nodes/startTask.vue'
|
||||
import UserTask from './nodes/userTask.vue'
|
||||
import ExclusiveGateway from './nodes/exclusiveGateway.vue'
|
||||
import ParallelGateway from './nodes/parallelGateway.vue'
|
||||
import ServiceTask from './nodes/serviceTask.vue'
|
||||
import {ref,watch} from 'vue'
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
processConfigInfo: { type: Object, default: () => {} },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
taskListenerArray: { type: Array, default: () => [] },
|
||||
selectorApiFunction: { type: Object, default: () => {} }
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
// 创建响应式引用
|
||||
const childNode = ref({})
|
||||
// 监听 props.modelValue 的变化,并同步到 childNode.value
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
childNode.value = newValue
|
||||
},
|
||||
{ immediate: true } // 立即执行一次监听器
|
||||
)
|
||||
// 监听 childNode.value 的变化,并发出自定义事件 update:modelValue
|
||||
watch(childNode, (newValue) => {
|
||||
emit('update:modelValue', newValue)
|
||||
})
|
||||
</script>
|
||||
@@ -1,273 +0,0 @@
|
||||
<!-- 添加节点组件 -->
|
||||
<template>
|
||||
<div class="add-node-btn-box">
|
||||
<div class="add-node-btn">
|
||||
<el-popover placement="right" :width="280" trigger="click">
|
||||
<template #reference>
|
||||
<el-button type="primary" circle @click="addNodeButton" :icon="Plus"></el-button>
|
||||
</template>
|
||||
<div class="button_info">
|
||||
<ul style="height: 80px">
|
||||
<li>
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
:icon="UserFilled"
|
||||
circle
|
||||
@click="addType('userTask')"
|
||||
></el-button>
|
||||
<p>审批节点</p>
|
||||
</li>
|
||||
<li>
|
||||
<el-button
|
||||
size="large"
|
||||
type="warning"
|
||||
:icon="Promotion"
|
||||
circle
|
||||
@click="addType('serviceTask')"
|
||||
></el-button>
|
||||
<p>抄送节点</p>
|
||||
</li>
|
||||
<li v-if="addExclusiveGateway">
|
||||
<el-button
|
||||
size="large"
|
||||
type="danger"
|
||||
:icon="Share"
|
||||
circle
|
||||
@click="addType('exclusiveGateway')"
|
||||
></el-button>
|
||||
<p>条件分支</p>
|
||||
</li>
|
||||
<li v-if="addParallelGateway">
|
||||
<el-button
|
||||
size="large"
|
||||
type="success"
|
||||
:icon="Operation"
|
||||
circle
|
||||
@click="addType('parallelGateway')"
|
||||
></el-button>
|
||||
<p>并行分支</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- <script>
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
const NodeTitleMap = {
|
||||
userTask: '审核人',
|
||||
serviceTask: '抄送人',
|
||||
exclusiveGateway: '条件路由',
|
||||
parallelGateway: '并行路由'
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
parentData: { type: Object, default: () => {} },
|
||||
nodeItem: { type: Object, default: () => {} }
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
data() {
|
||||
return {
|
||||
visible: true,
|
||||
addExclusiveGateway: true,
|
||||
addParallelGateway: true
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
addNodeButton() {
|
||||
// 他的上级是条件分支或并行分支,将其不在添加 // 控制节点下面
|
||||
if (!this.parentData) {
|
||||
this.disabledChildren()
|
||||
} else {
|
||||
if (this.parentData.type === 'exclusiveGateway' || this.parentData.type === 'parallelGateway') {
|
||||
this.addExclusiveGateway = false
|
||||
this.addParallelGateway = false
|
||||
}
|
||||
}
|
||||
},
|
||||
disabledChildren() {
|
||||
// 如果下级是条件分支或并行分支,将其不在添加 // 控制节点上面
|
||||
if (this.modelValue && this.modelValue.type) {
|
||||
if (this.modelValue.type === 'exclusiveGateway' || this.modelValue.type === 'parallelGateway') {
|
||||
this.addExclusiveGateway = false
|
||||
this.addParallelGateway = false
|
||||
}
|
||||
}
|
||||
// 不管其他的,如果是条件分支的项,那么他的下面无法添加条件
|
||||
if (this.nodeItem) {
|
||||
this.addExclusiveGateway = false
|
||||
}
|
||||
},
|
||||
getBaseCondition(type, title) {
|
||||
const condition = cloneDeep(config.nodeModel.node)
|
||||
condition.id = this.$TOOL.snowyUuid()
|
||||
condition.type = type
|
||||
condition.title = title
|
||||
return condition
|
||||
},
|
||||
addType(type) {
|
||||
const nodeModel = this.getBaseCondition(type, NodeTitleMap[type]) || {}
|
||||
nodeModel.childNode = this.modelValue
|
||||
if (type === 'userTask') {
|
||||
// 创建 configInfo
|
||||
const configInfo = cloneDeep(config.nodeConfigInfo.userTaskConfigInfo)
|
||||
nodeModel.properties.configInfo = configInfo
|
||||
} else if (type === 'exclusiveGateway') {
|
||||
nodeModel.dataLegal = true
|
||||
// 创建分支节点1
|
||||
const condition1 = this.getBaseCondition('sequenceFlow', '条件1')
|
||||
// 创建分支节点1 configInfo
|
||||
const condition1ConfigInfo1 = cloneDeep(config.nodeConfigInfo.conditionConfigInfo)
|
||||
condition1ConfigInfo1.priorityLevel = 1
|
||||
condition1.properties.configInfo = condition1ConfigInfo1
|
||||
// 创建分支节点2
|
||||
const condition2 = this.getBaseCondition('sequenceFlow', '条件2')
|
||||
// 创建分支节点2 configInfo
|
||||
const condition1ConfigInfo2 = cloneDeep(config.nodeConfigInfo.conditionConfigInfo)
|
||||
condition1ConfigInfo2.priorityLevel = 2
|
||||
condition2.properties.configInfo = condition1ConfigInfo2
|
||||
// 装进去
|
||||
nodeModel.conditionNodeList.push(condition1)
|
||||
nodeModel.conditionNodeList.push(condition2)
|
||||
} else if (type === 'parallelGateway') {
|
||||
// 创建主节点
|
||||
nodeModel.dataLegal = true
|
||||
// 创建分支节点1
|
||||
const condition1 = this.getBaseCondition('userTask', '审批人1')
|
||||
condition1.properties.configInfo = cloneDeep(config.nodeConfigInfo.userTaskConfigInfo)
|
||||
condition1.dataLegal = true
|
||||
// 创建分支节点2
|
||||
const condition2 = this.getBaseCondition('userTask', '审批人2')
|
||||
condition2.properties.configInfo = cloneDeep(config.nodeConfigInfo.userTaskConfigInfo)
|
||||
condition2.dataLegal = true
|
||||
// 装进去
|
||||
nodeModel.conditionNodeList.push(condition1)
|
||||
nodeModel.conditionNodeList.push(condition2)
|
||||
}
|
||||
this.visible = true
|
||||
this.$emit('update:modelValue', nodeModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script> -->
|
||||
|
||||
<script setup>
|
||||
import { Plus, UserFilled, Promotion, Share, Operation } from '@element-plus/icons-vue';
|
||||
import {ref,nextTick} from 'vue'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import tool from '@/utils/tool'
|
||||
const NodeTitleMap = {
|
||||
userTask: '审核人',
|
||||
serviceTask: '抄送人',
|
||||
exclusiveGateway: '条件路由',
|
||||
parallelGateway: '并行路由'
|
||||
}
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
parentData: { type: Object, default: () => {} },
|
||||
nodeItem: { type: Object, default: () => {} }
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const visible = ref(false)
|
||||
const addExclusiveGateway = ref(true)
|
||||
const addParallelGateway = ref(true)
|
||||
const addNodeButton = () => {
|
||||
// 他的上级是条件分支或并行分支,将其不在添加 // 控制节点下面
|
||||
if (!props.parentData) {
|
||||
disabledChildren()
|
||||
} else {
|
||||
if (props.parentData.type === 'exclusiveGateway' || props.parentData.type === 'parallelGateway') {
|
||||
addExclusiveGateway.value = false
|
||||
addParallelGateway.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
const disabledChildren = () => {
|
||||
// 如果下级是条件分支或并行分支,将其不在添加 // 控制节点上面
|
||||
if (props.modelValue && props.modelValue.type) {
|
||||
if (props.modelValue.type === 'exclusiveGateway' || props.modelValue.type === 'parallelGateway') {
|
||||
addExclusiveGateway.value = false
|
||||
addParallelGateway.value = false
|
||||
}
|
||||
}
|
||||
// 不管其他的,如果是条件分支的项,那么他的下面无法添加条件
|
||||
if (props.nodeItem) {
|
||||
addExclusiveGateway.value = false
|
||||
}
|
||||
}
|
||||
const getBaseCondition = (type, title) => {
|
||||
const condition = cloneDeep(config.nodeModel.node)
|
||||
condition.id = tool.snowyUuid()
|
||||
condition.type = type
|
||||
condition.title = title
|
||||
return condition
|
||||
}
|
||||
const addType = (type) => {
|
||||
const nodeModel = getBaseCondition(type, NodeTitleMap[type]) || {}
|
||||
nodeModel.childNode = props.modelValue
|
||||
if (type === 'userTask') {
|
||||
// 创建 configInfo
|
||||
nodeModel.properties.configInfo = cloneDeep(config.nodeConfigInfo.userTaskConfigInfo)
|
||||
} else if (type === 'exclusiveGateway') {
|
||||
nodeModel.dataLegal = true
|
||||
// 创建分支节点1
|
||||
const condition1 = getBaseCondition('sequenceFlow', '条件1')
|
||||
// 创建分支节点1 configInfo
|
||||
const condition1ConfigInfo1 = cloneDeep(config.nodeConfigInfo.conditionConfigInfo)
|
||||
condition1ConfigInfo1.priorityLevel = 1
|
||||
condition1.properties.configInfo = condition1ConfigInfo1
|
||||
// 创建分支节点2
|
||||
const condition2 = getBaseCondition('sequenceFlow', '条件2')
|
||||
// 创建分支节点2 configInfo
|
||||
const condition1ConfigInfo2 = cloneDeep(config.nodeConfigInfo.conditionConfigInfo)
|
||||
condition1ConfigInfo2.priorityLevel = 2
|
||||
condition2.properties.configInfo = condition1ConfigInfo2
|
||||
// 装进去
|
||||
nodeModel.conditionNodeList.push(condition1)
|
||||
nodeModel.conditionNodeList.push(condition2)
|
||||
} else if (type === 'parallelGateway') {
|
||||
// 创建主节点
|
||||
nodeModel.dataLegal = true
|
||||
// 创建分支节点1
|
||||
const condition1 = getBaseCondition('userTask', '审批人1')
|
||||
condition1.properties.configInfo = cloneDeep(config.nodeConfigInfo.userTaskConfigInfo)
|
||||
condition1.dataLegal = true
|
||||
// 创建分支节点2
|
||||
const condition2 = getBaseCondition('userTask', '审批人2')
|
||||
condition2.properties.configInfo = cloneDeep(config.nodeConfigInfo.userTaskConfigInfo)
|
||||
condition2.dataLegal = true
|
||||
// 装进去
|
||||
nodeModel.conditionNodeList.push(condition1)
|
||||
nodeModel.conditionNodeList.push(condition2)
|
||||
}
|
||||
visible.value = false
|
||||
emit('update:modelValue', nodeModel)
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.button_info{
|
||||
width:100%;
|
||||
ul{
|
||||
width:100%;
|
||||
display:flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
li{
|
||||
list-style: none;
|
||||
p{
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
font-weight: 800;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +0,0 @@
|
||||
<template>
|
||||
<div class="add-node-btn-box">
|
||||
<div class="add-node-btn"></div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,42 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="预览"
|
||||
:width="700"
|
||||
v-model="visible"
|
||||
:destroy-on-close="true"
|
||||
:footer-style="{ textAlign: 'right' }"
|
||||
:mask="false"
|
||||
:confirmLoading="confirmLoading"
|
||||
@ok="onSubmit"
|
||||
@cancel="onClose"
|
||||
>
|
||||
<component ref="customFormRef" :is="customFormsLayouts" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup name="previewCustomForm">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { loadComponent } from '../../customForm'
|
||||
import { ref } from 'vue'
|
||||
const visible = ref(false)
|
||||
const confirmLoading = ref(false)
|
||||
const customFormRef = ref()
|
||||
const customFormsLayouts = ref()
|
||||
const onOpen = url => {
|
||||
if (url) {
|
||||
visible.value = true
|
||||
customFormsLayouts.value = loadComponent(url)
|
||||
}
|
||||
}
|
||||
const onSubmit = () => {
|
||||
customFormRef.value.getData().then(value => {
|
||||
message.info(JSON.stringify(value))
|
||||
})
|
||||
}
|
||||
const onClose = () => {
|
||||
visible.value = false
|
||||
}
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
</script>
|
||||
@@ -1,22 +0,0 @@
|
||||
<template>
|
||||
<div class="nav_title" :style="{ borderLeft: `4px solid ${borderColor}` }">
|
||||
<p><slot name="nav_name"></slot></p>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useConfig } from '@/stores/config'
|
||||
import { ref } from 'vue'
|
||||
const configStore = useConfig()
|
||||
const borderColor =configStore.getColorVal('elementUiPrimary')
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.nav_title {
|
||||
padding-left: 8px;
|
||||
margin-top: 10px;
|
||||
p {
|
||||
font-size: 15px;
|
||||
color: #212121;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,581 +0,0 @@
|
||||
export default {
|
||||
// 模型结构,就是每个节点,都有的
|
||||
nodeModel: {
|
||||
// 节点
|
||||
node: {
|
||||
id: '', // 节点id
|
||||
title: '', // 节点名称
|
||||
type: '', // 节点类型
|
||||
dataLegal: false, // 信息是否完整
|
||||
// content:'', // 内容、备注
|
||||
properties: {
|
||||
configInfo: {}, // 除条件路由和分合流节点外均有
|
||||
conditionInfo: [], // 条件信息, 条件节点特有
|
||||
participateInfo: [], // 参与人信息,开始节点、审批节点、抄送节点才有
|
||||
buttonInfo: [], // 按钮信息, 开始节点、审批节点、抄送节点才有
|
||||
fieldInfo: [], // 字段信息, 开始节点、审批节点、抄送节点才有
|
||||
commentList: [], // 流转记录内容
|
||||
formInfo: [], // 自定义表单 发起、审批节点都有
|
||||
executionListenerInfo: [], // 执行监听器信息,所有节点都有
|
||||
taskListenerInfo: [] // 任务监听器信息(审批节点特有)
|
||||
// noticeInfo: [], // 通知信息, 开始节点、审批节点、抄送节点才有
|
||||
},
|
||||
childNode: {}, // 子节点
|
||||
conditionNodeList: [] // 条件子节点
|
||||
},
|
||||
// 通用按钮默认配置,不需要改动,除非自定义开发的时候,再加什么按钮
|
||||
buttonInfo: [
|
||||
{
|
||||
key: 'SAVE',
|
||||
label: '保存',
|
||||
value: 'HIDE',
|
||||
type: 'default',
|
||||
icon: 'save-outlined'
|
||||
},
|
||||
{
|
||||
key: 'SUBMIT',
|
||||
label: '提交',
|
||||
value: 'HIDE',
|
||||
type: 'primary',
|
||||
icon: 'check-circle-outlined'
|
||||
},
|
||||
{
|
||||
key: 'PASS',
|
||||
label: '同意',
|
||||
value: 'HIDE',
|
||||
type: 'primary',
|
||||
icon: 'check-outlined'
|
||||
},
|
||||
{
|
||||
key: 'REJECT',
|
||||
label: '拒绝',
|
||||
value: 'HIDE',
|
||||
type: 'danger',
|
||||
icon: 'close-outlined'
|
||||
},
|
||||
{
|
||||
key: 'BACK',
|
||||
label: '退回',
|
||||
value: 'HIDE',
|
||||
type: 'default',
|
||||
icon: 'rollback-outlined'
|
||||
},
|
||||
{
|
||||
key: 'JUMP',
|
||||
label: '跳转',
|
||||
value: 'HIDE',
|
||||
type: 'default',
|
||||
icon: 'ungroup-outlined'
|
||||
},
|
||||
{
|
||||
key: 'ADD_SIGN',
|
||||
label: '加签',
|
||||
value: 'HIDE',
|
||||
type: 'default',
|
||||
icon: 'tags-outlined'
|
||||
},
|
||||
{
|
||||
key: 'PRINT',
|
||||
label: '打印',
|
||||
value: 'HIDE',
|
||||
type: 'default',
|
||||
icon: 'printer-outlined'
|
||||
},
|
||||
{
|
||||
key: 'TURN',
|
||||
label: '转办',
|
||||
value: 'HIDE',
|
||||
type: 'default',
|
||||
icon: 'user-switch-outlined'
|
||||
}
|
||||
],
|
||||
fieldInfo: [],
|
||||
formInfo: [
|
||||
{
|
||||
key: 'FORM_URL',
|
||||
label: 'PC端表单组件',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
key: 'MOBILE_FORM_URL',
|
||||
label: '移动端表单组件',
|
||||
value: ''
|
||||
}
|
||||
],
|
||||
executionListenerInfo: [],
|
||||
taskListenerInfo: [],
|
||||
noticeInfo: []
|
||||
},
|
||||
|
||||
// 各个节点的configInfo,他们长的都不一样
|
||||
nodeConfigInfo: {
|
||||
// 全局配置
|
||||
processConfigInfo: {
|
||||
// 基础配置
|
||||
processSnTemplateId: undefined, // 流水号模板 id
|
||||
processPrintTemplateId: undefined, // 打印模板 id
|
||||
processTitleTemplate: 'initiator 的 processName - startTime', // 标题模板
|
||||
processAbstractTemplate: '', // 摘要模板
|
||||
processEnableAutoDistinct: false, // 开启自动去重
|
||||
processAutoDistinctType: 'SAMPLE', // 自动去重类型
|
||||
processEnableRevoke: true, // 开启审批撤销
|
||||
processEnableCommentRequired: false, // 开启意见必填
|
||||
// 通知配置
|
||||
processEnableBackNotice: false, // 开启退回通知
|
||||
processEnableTodoNotice: false, // 开启待办通知
|
||||
processEnableCopyNotice: false, // 开启抄送通知
|
||||
processEnableCompleteNotice: false, // 开启完成通知
|
||||
// 通知的方式
|
||||
processBackNoticeChannel: ['MSG'], // 退回通知渠道
|
||||
processTodoNoticeChannel: ['MSG'], // 待办通知渠道
|
||||
processCopyNoticeChannel: ['MSG'], // 抄送通知渠道
|
||||
processCompleteNoticeChannel: ['MSG'], // 完成通知渠道
|
||||
// 通知配置对应的模板
|
||||
processBackNoticeTemplate: '您于 startTime 发起的 processName 被退回', // 退回通知模板
|
||||
processTodoNoticeTemplate: '由 initiator 发起的 processName 需要您审批', // 待办通知模板
|
||||
processCopyNoticeTemplate: '您收到一条由 initiator 发起的 processName 的抄送', // 抄送通知模板
|
||||
processCompleteNoticeTemplate: '您于 startTime 发起的 processName 审批通过', // 完成通知模板
|
||||
// 全局自定义表单
|
||||
processStartTaskFormUrl: '', // 全局PC申请单
|
||||
processStartTaskMobileFormUrl: '', // 全局移动端申请单
|
||||
processUserTaskFormUrl: '', // 全局PC审批单
|
||||
processUserTaskMobileFormUrl: '' // 全局移动端审批单
|
||||
},
|
||||
// 审核节点配置
|
||||
userTaskConfigInfo: {
|
||||
userTaskType: 'ARTIFICIAL', // 任务节点类型
|
||||
userTaskRejectType: 'TO_START', // 审批退回类型
|
||||
userTaskMulApproveType: 'SEQUENTIAL', // 多人审批时类型
|
||||
userTaskEmptyApproveType: 'AUTO_COMPLETE', // 审批人为空时类型
|
||||
userTaskEmptyApproveUser: '', // 审批人为空时转交人id
|
||||
userTaskEmptyApproveUserArray: [] // 审批人为空时转交人包含name,用来前端回显,后端不解析
|
||||
},
|
||||
// 条件中默认的配置
|
||||
conditionConfigInfo: {
|
||||
priorityLevel: 1 // 优先级 默认1
|
||||
},
|
||||
// 抄送节点配置
|
||||
serviceTaseConfigInfo: {}
|
||||
},
|
||||
|
||||
// 按钮相关配置
|
||||
button: {
|
||||
// 发起人节点 默认选中按钮
|
||||
startTaskDefaultButtonkey: ['SAVE', 'SUBMIT'],
|
||||
// 发起人节点 默认不让选的按钮 // 这个节点屏蔽下面配置的
|
||||
startTaskNoCheckedButtonkey: ['PASS', 'PRINT', 'REJECT', 'BACK', 'ADD_SIGN', 'TURN', 'JUMP'],
|
||||
// 审批人节点 默认选中按钮
|
||||
userTaskDefaultButtonkey: ['PASS', 'REJECT'],
|
||||
// 审批节点 默认不让选的
|
||||
userTaskNoCheckedButtonkey: ['SUBMIT', 'SAVE'],
|
||||
// 抄送人节点 默认选中按钮
|
||||
serviceTaskDefaultButtonkey: ['SUBMIT']
|
||||
},
|
||||
// 字段相关配置
|
||||
field: {
|
||||
// 其他节点中字段对象数据模型
|
||||
fieldModel: {
|
||||
key: '',
|
||||
label: '',
|
||||
value: 'WRITE', // 默认
|
||||
required: false, // 必填
|
||||
extJson: '' // 额外扩展,暂无
|
||||
},
|
||||
// 审批节点中字段对象数据模型
|
||||
userTaskFieldModel: {
|
||||
key: '',
|
||||
label: '',
|
||||
value: 'READ', // 默认设为只读
|
||||
required: false, // 必填
|
||||
extJson: '' // 额外扩展,暂无
|
||||
},
|
||||
// 字段列表中的字典
|
||||
fieldRadioList: [
|
||||
{
|
||||
label: '可编辑',
|
||||
value: 'WRITE'
|
||||
},
|
||||
{
|
||||
label: '只读',
|
||||
value: 'READ'
|
||||
},
|
||||
{
|
||||
label: '隐藏',
|
||||
value: 'HIDE'
|
||||
}
|
||||
]
|
||||
},
|
||||
// 监听器配置,不同的地方不同的选项
|
||||
listener: {
|
||||
// 全局执行监听可以选择的
|
||||
processExecutionListenerInfo: [
|
||||
{
|
||||
key: 'START',
|
||||
label: '开始',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'END',
|
||||
label: '完成',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'REJECT',
|
||||
label: '拒绝',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'CLOSE',
|
||||
label: '终止',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'REVOKE',
|
||||
label: '撤回',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'DELETE',
|
||||
label: '删除',
|
||||
value: '',
|
||||
extJson: ''
|
||||
}
|
||||
],
|
||||
// 条件执行监听可以选择的
|
||||
exclusiveGatewayExecutionListenerInfo: [
|
||||
{
|
||||
key: 'TAKE',
|
||||
label: '到达',
|
||||
value: '',
|
||||
extJson: ''
|
||||
}
|
||||
],
|
||||
// 开始节点执行监听可选择的
|
||||
startTaskExecutionListenerInfo: [
|
||||
{
|
||||
key: 'START',
|
||||
label: '开始',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'END',
|
||||
label: '结束',
|
||||
value: '',
|
||||
extJson: ''
|
||||
}
|
||||
],
|
||||
// 审批节点执行监听可以选择的
|
||||
userTaskExecutionListenerInfo: [
|
||||
{
|
||||
key: 'START',
|
||||
label: '开始',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'END',
|
||||
label: '结束',
|
||||
value: '',
|
||||
extJson: ''
|
||||
}
|
||||
],
|
||||
// 抄送节点执行监听可以选择的
|
||||
serviceTaskExecutionListenerInfo: [
|
||||
{
|
||||
key: 'START',
|
||||
label: '开始',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'END',
|
||||
label: '结束',
|
||||
value: '',
|
||||
extJson: ''
|
||||
}
|
||||
],
|
||||
// 审批节点任务监听
|
||||
userTaskTaskListenerInfo: [
|
||||
{
|
||||
key: 'CREATE',
|
||||
label: '创建',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'ASSIGNMENT',
|
||||
label: '分配',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'COMPLETE',
|
||||
label: '完成',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'DELETE',
|
||||
label: '删除',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'UPDATE',
|
||||
label: '更新',
|
||||
value: '',
|
||||
extJson: ''
|
||||
},
|
||||
{
|
||||
key: 'TIMEOUT',
|
||||
label: '超时',
|
||||
value: '',
|
||||
extJson: ''
|
||||
}
|
||||
]
|
||||
},
|
||||
// 通知方式字典
|
||||
noticeInfoList: [
|
||||
{
|
||||
label: '短信',
|
||||
value: 'SMS'
|
||||
},
|
||||
{
|
||||
label: '邮件',
|
||||
value: 'EMAIL'
|
||||
},
|
||||
{
|
||||
label: '站内信',
|
||||
value: 'MSG'
|
||||
}
|
||||
],
|
||||
// 模板默认自带字段
|
||||
templateDefaultFields: [
|
||||
{
|
||||
label: '发起人',
|
||||
value: 'initiator'
|
||||
},
|
||||
{
|
||||
label: '流程名称',
|
||||
value: 'processName'
|
||||
},
|
||||
{
|
||||
label: '发起时间',
|
||||
value: 'startTime'
|
||||
},
|
||||
{
|
||||
label: '表单字段',
|
||||
value: 'disabled' // 这里表示在组件显示的时候就截至了,是下一梭子数组的标题哦
|
||||
}
|
||||
],
|
||||
// 审批节点
|
||||
userTaskConfig: {
|
||||
// 审批人员类型
|
||||
userSelectionTypeList: [
|
||||
{
|
||||
label: '机构',
|
||||
value: 'ORG'
|
||||
},
|
||||
{
|
||||
label: '角色',
|
||||
value: 'ROLE'
|
||||
},
|
||||
{
|
||||
label: '职位',
|
||||
value: 'POSITION'
|
||||
},
|
||||
{
|
||||
label: '部门主管',
|
||||
value: 'ORG_LEADER'
|
||||
},
|
||||
{
|
||||
label: '上级主管',
|
||||
value: 'SUPERVISOR'
|
||||
},
|
||||
{
|
||||
label: '表单内的人',
|
||||
value: 'FORM_USER'
|
||||
},
|
||||
{
|
||||
label: '表单内的人上级主管',
|
||||
value: 'FORM_USER_SUPERVISOR'
|
||||
},
|
||||
{
|
||||
label: '连续多级主管',
|
||||
value: 'MUL_LEVEL_SUPERVISOR'
|
||||
},
|
||||
{
|
||||
label: '表单内的人连续多级主管',
|
||||
value: 'FORM_USER_MUL_LEVEL_SUPERVISOR'
|
||||
},
|
||||
{
|
||||
label: '用户',
|
||||
value: 'USER'
|
||||
},
|
||||
{
|
||||
label: '发起人',
|
||||
value: 'INITIATOR'
|
||||
}
|
||||
],
|
||||
// 任务节点类型
|
||||
userTaskTypeList: [
|
||||
{
|
||||
label: '人工审批',
|
||||
value: 'ARTIFICIAL'
|
||||
},
|
||||
{
|
||||
label: '自动通过',
|
||||
value: 'COMPLETE'
|
||||
},
|
||||
{
|
||||
label: '自动拒绝',
|
||||
value: 'REJECT'
|
||||
}
|
||||
],
|
||||
// 审批退回类型
|
||||
userTaskRejectTypeList: [
|
||||
{
|
||||
label: '开始节点',
|
||||
value: 'TO_START'
|
||||
},
|
||||
{
|
||||
label: '自选节点',
|
||||
value: 'USER_SELECT'
|
||||
},
|
||||
{
|
||||
label: '自动结束',
|
||||
value: 'AUTO_END'
|
||||
}
|
||||
],
|
||||
// 多人审批时类型
|
||||
userTaskMulApproveTypeList: [
|
||||
{
|
||||
label: '依次审批',
|
||||
value: 'SEQUENTIAL'
|
||||
},
|
||||
{
|
||||
label: '会签(须所有审批人同意)',
|
||||
value: 'COUNTERSIGN'
|
||||
},
|
||||
{
|
||||
label: '或签(一名审批人同意或拒绝即可)',
|
||||
value: 'ORSIGN'
|
||||
}
|
||||
],
|
||||
// 审批人为空时类型
|
||||
userTaskEmptyApproveTypeList: [
|
||||
{
|
||||
label: '自动通过',
|
||||
value: 'AUTO_COMPLETE'
|
||||
},
|
||||
{
|
||||
label: '自动转交给某个人',
|
||||
value: 'AUTO_TURN'
|
||||
}
|
||||
],
|
||||
// 主管层级
|
||||
levelSupervisorList: [
|
||||
{
|
||||
label: '最高层主管',
|
||||
value: '-1'
|
||||
},
|
||||
{
|
||||
label: '直接主管',
|
||||
value: '1'
|
||||
},
|
||||
{
|
||||
label: '第2级主管',
|
||||
value: '2'
|
||||
},
|
||||
{
|
||||
label: '第3级主管',
|
||||
value: '3'
|
||||
},
|
||||
{
|
||||
label: '第4级主管',
|
||||
value: '4'
|
||||
},
|
||||
{
|
||||
label: '第5级主管',
|
||||
value: '5'
|
||||
},
|
||||
{
|
||||
label: '第6级主管',
|
||||
value: '6'
|
||||
},
|
||||
{
|
||||
label: '第7级主管',
|
||||
value: '7'
|
||||
},
|
||||
{
|
||||
label: '第8级主管',
|
||||
value: '8'
|
||||
},
|
||||
{
|
||||
label: '第9级主管',
|
||||
value: '9'
|
||||
},
|
||||
{
|
||||
label: '第10级主管',
|
||||
value: '10'
|
||||
}
|
||||
]
|
||||
},
|
||||
// 条件节点
|
||||
exclusiveGatewayConfig: {
|
||||
operatorList: [
|
||||
{
|
||||
label: '等于',
|
||||
value: '=='
|
||||
},
|
||||
{
|
||||
label: '不等于',
|
||||
value: '!='
|
||||
},
|
||||
{
|
||||
label: '大于',
|
||||
value: '>'
|
||||
},
|
||||
{
|
||||
label: '大于等于',
|
||||
value: '>='
|
||||
},
|
||||
{
|
||||
label: '小于',
|
||||
value: '<'
|
||||
},
|
||||
{
|
||||
label: '小于等于',
|
||||
value: '<='
|
||||
},
|
||||
{
|
||||
label: '包含',
|
||||
value: 'include'
|
||||
},
|
||||
{
|
||||
label: '不包含',
|
||||
value: 'notInclude'
|
||||
}
|
||||
]
|
||||
},
|
||||
// 抄送节点
|
||||
serviceTaskConfig: {
|
||||
// 抄送人员类型
|
||||
userSelectionTypeList: [
|
||||
{
|
||||
label: '用户',
|
||||
value: 'USER'
|
||||
},
|
||||
{
|
||||
label: '表单内的人',
|
||||
value: 'FORM_USER'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,794 +0,0 @@
|
||||
<template>
|
||||
<div class="branch-wrap">
|
||||
<div class="branch-box-wrap">
|
||||
<div class="branch-box">
|
||||
<el-button class="add-branch" type="primary" shape="round" @click="addTerm">添加条件</el-button>
|
||||
<div v-for="(item, index) in childNode.conditionNodeList" :key="index" class="col-box">
|
||||
<div class="condition-node">
|
||||
<div class="condition-node-box">
|
||||
<div class="auto-judge" @click="show(index)">
|
||||
<div v-if="index != 0" class="sort-left" @click.stop="arrTransfer(index, -1)">
|
||||
<left-outlined />
|
||||
</div>
|
||||
<div class="title">
|
||||
<span class="node-title">{{ item.title }}</span>
|
||||
<span class="priority-title">
|
||||
优先级{{ item.properties.configInfo.priorityLevel }}
|
||||
</span>
|
||||
<close-outlined class="close" @click.stop="delTerm(index)" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<span v-if="toText(childNode, index)">{{ toText(childNode, index) }}</span>
|
||||
<span v-else class="placeholder">请设置条件</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="index !== childNode.conditionNodeList.length - 1"
|
||||
class="sort-right"
|
||||
@click.stop="arrTransfer(index)"
|
||||
>
|
||||
<right-outlined />
|
||||
</div>
|
||||
</div>
|
||||
<add-node v-model="item.childNode" :node-item="item" />
|
||||
</div>
|
||||
</div>
|
||||
<slot v-if="item.childNode" :node="item" />
|
||||
<div v-if="index === 0" class="top-left-cover-line" />
|
||||
<div v-if="index === 0" class="bottom-left-cover-line" />
|
||||
<div v-if="index === childNode.conditionNodeList.length - 1" class="top-right-cover-line" />
|
||||
<div v-if="index === childNode.conditionNodeList.length - 1" class="bottom-right-cover-line" />
|
||||
</div>
|
||||
</div>
|
||||
<add-node v-model="childNode.childNode" :parent-data="childNode" />
|
||||
</div>
|
||||
|
||||
<formContainer
|
||||
v-model="drawer"
|
||||
:visible="visible"
|
||||
:destroy-on-close="true"
|
||||
:width="700"
|
||||
:body-style="{ 'padding-top': '0px' }"
|
||||
>
|
||||
<template #title>
|
||||
<div class="node-wrap-drawer__title">
|
||||
<label v-if="!isEditTitle" @click="editTitle">
|
||||
{{ form.title }}
|
||||
<edit-outlined class="node-wrap-drawer-title-edit" />
|
||||
</label>
|
||||
<el-input
|
||||
v-if="isEditTitle"
|
||||
ref="nodeTitle"
|
||||
v-model="form.title"
|
||||
allow-clear
|
||||
@blur="saveTitle"
|
||||
@keyup.enter="saveTitle"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
<el-tabs v-model="activeKey">
|
||||
<el-tab-pane name="1" label="条件配置" lazy>
|
||||
<el-form layout="vertical">
|
||||
<div v-show="!isNodeLegal(form)" style="margin-bottom: 10px">
|
||||
<el-alert message="请填写完成所有项!" type="error" />
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">配置要执行的条件</span>
|
||||
</div>
|
||||
<p style="margin-bottom: 2px">
|
||||
<el-button type="primary" round @click="addDynamicValidateForm" size="small">
|
||||
<plus-outlined />
|
||||
增加条件组
|
||||
</el-button>
|
||||
</p>
|
||||
<el-form-item v-for="(domain, index) in dynamicValidateForm" :key="index">
|
||||
<el-divider style="margin: 10px 0" />
|
||||
<el-row>
|
||||
<el-col :span="22">
|
||||
<el-table :datel-source="domain" size="small" :pagination="false">
|
||||
<el-table-column datel-index="field" title="条件字段" width="130">
|
||||
<template #default="{ record }">
|
||||
<el-select
|
||||
v-model:value="record.field"
|
||||
placeholder="请选择"
|
||||
v-if="recordData.formType === 'DESIGN'"
|
||||
>
|
||||
<el-select-option
|
||||
v-for="formField in fieldList"
|
||||
:key="formField.model"
|
||||
:value="formField.model"
|
||||
@click="record.label = formField.label"
|
||||
>
|
||||
{{ formField.label }}
|
||||
</el-select-option>
|
||||
</el-select>
|
||||
<el-input v-model:value="record.field" placeholder="条件" v-else />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column datel-index="label" title="描述">
|
||||
<template #default="{ record }">
|
||||
<el-input v-model:value="record.label" placeholder="描述" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column datel-index="operator" width="140">
|
||||
<template #title>
|
||||
<el-tooltip>
|
||||
<template #title>
|
||||
注:自定义表单模式下条件选择完全放开,中文字段不可以使用大于、大于等于、小于、小于等于!
|
||||
</template>
|
||||
<question-circle-outlined />
|
||||
运算符
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template #default="{ record }">
|
||||
<el-select v-model:value="record.operator" placeholder="请选择">
|
||||
<el-select-option value="==">等于</el-select-option>
|
||||
<el-select-option value="!=">不等于</el-select-option>
|
||||
<el-select-option value=">" v-if="isSelectOption(record)">
|
||||
大于
|
||||
</el-select-option>
|
||||
<el-select-option value=">=" v-if="isSelectOption(record)">
|
||||
大于等于
|
||||
</el-select-option>
|
||||
<el-select-option value="<" v-if="isSelectOption(record)">
|
||||
小于
|
||||
</el-select-option>
|
||||
<el-select-option value="<=" v-if="isSelectOption(record)">
|
||||
小于等于
|
||||
</el-select-option>
|
||||
<el-select-option
|
||||
value="include"
|
||||
v-if="!isSelectOption(record, 'include')"
|
||||
>
|
||||
包含
|
||||
</el-select-option>
|
||||
<el-select-option
|
||||
value="notInclude"
|
||||
v-if="!isSelectOption(record, 'notInclude')"
|
||||
>
|
||||
不包含
|
||||
</el-select-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column datel-index="value" width="100">
|
||||
<template #title>
|
||||
<el-tooltip>
|
||||
<template #title>
|
||||
中文字段需判断等于,值必须加入英文双引号
|
||||
</template>
|
||||
<question-circle-outlined />
|
||||
值
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template #default="{ record }">
|
||||
<el-input v-model:value="record.value" placeholder="值" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column datel-index="value" title="移除" width="55">
|
||||
<template #default="{ index }">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
danger
|
||||
ghost
|
||||
@click="deleteConditionList(index, domain)"
|
||||
>
|
||||
移除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button type="dashed" class="dashedButton" @click="addConditionList(index)">
|
||||
<PlusOutlined />
|
||||
增加条件
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="2" class="deleteIcon">
|
||||
<minus-circle-two-tone class="minusCircle" @click="delDomains(index)" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="2" label="执行监听" lazy>
|
||||
<prop-listener-info
|
||||
ref="propExecutionListenerInfoRef"
|
||||
:listenerValue="form.properties.executionListenerInfo"
|
||||
:defaultListenerList="executionListenerInfo"
|
||||
:listener-value-array="executionListenerArray"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button type="primary" style="margin-right: 8px" @click="save">保存</el-button>
|
||||
<el-button @click="drawer = false">取消</el-button>
|
||||
</template>
|
||||
</formContainer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- <script>
|
||||
import { cloneDeep, isEmpty } from 'lodash-es'
|
||||
import addNode from './addNode.vue'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import workFlowUtils from '@/components/XnWorkflow/nodes/utils/index'
|
||||
import PropListenerInfo from './prop/propListenerInfo.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
addNode,
|
||||
PropListenerInfo
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
taskListenerArray: { type: Array, default: () => [] }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {},
|
||||
drawer: false,
|
||||
isEditTitle: false,
|
||||
index: 0,
|
||||
form: {},
|
||||
dynamicValidateForm: [],
|
||||
fieldList: [],
|
||||
activeKey: '1',
|
||||
executionListenerInfo: cloneDeep(config.listener.exclusiveGatewayExecutionListenerInfo),
|
||||
operatorList: cloneDeep(config.exclusiveGatewayConfig.operatorList)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
// 把字段给掏出来
|
||||
this.fieldList = workFlowUtils.getListField(this.formFieldListValue).map((m) => {
|
||||
let type = m.type //slider rate number
|
||||
if (type === 'slider' || type === 'rate' || type === 'number') {
|
||||
m.type = 'number'
|
||||
}
|
||||
return {
|
||||
label: m.label,
|
||||
model: m.selectTable + '.' + m.model,
|
||||
type: m.type
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
show(index) {
|
||||
this.index = index
|
||||
this.form = {}
|
||||
this.form = cloneDeep(this.childNode.conditionNodeList[index])
|
||||
this.drawer = true
|
||||
this.dynamicValidateForm = this.form.properties.conditionInfo
|
||||
},
|
||||
editTitle() {
|
||||
this.isEditTitle = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.nodeTitle.focus()
|
||||
})
|
||||
},
|
||||
saveTitle() {
|
||||
this.isEditTitle = false
|
||||
},
|
||||
save() {
|
||||
this.form.properties.conditionInfo = this.dynamicValidateForm
|
||||
this.form.properties.executionListenerInfo = this.$refs.propExecutionListenerInfoRef.selectedListenerList()
|
||||
if (this.isNodeLegal(this.form)) {
|
||||
this.form.dataLegal = true
|
||||
this.childNode.conditionNodeList[this.index] = this.form
|
||||
this.setCalibration()
|
||||
this.$emit('update:modelValue', this.childNode)
|
||||
this.drawer = false
|
||||
} else {
|
||||
this.form.dataLegal = false
|
||||
}
|
||||
},
|
||||
isSelectOption(record, value) {
|
||||
if (this.recordData.formType === 'DESIGN') {
|
||||
if (record.field) {
|
||||
return this.fieldList.find((f) => f.model === record.field).type === 'number'
|
||||
}
|
||||
} else {
|
||||
if (value === 'include' || value === 'notInclude') {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
// 校验此条件是否通过
|
||||
isNodeLegal(data) {
|
||||
const priorityLevel = data&&data.propertie&&data.properties.configInfo&&data.properties.configInfo.priorityLevel?data.properties.configInfo.priorityLevel:{};
|
||||
const len = this.childNode&&this.childNode.conditionNodeList&&this.childNode.conditionNodeList.length?this.childNode.conditionNodeList.length:0;
|
||||
const priorityLevelMax = len!=0?this.childNode.conditionNodeList[len - 1].properties.configInfo.priorityLevel:0;
|
||||
// 如果往其他条件的分支中增加,那我们一视同仁
|
||||
if (priorityLevelMax === priorityLevel) {
|
||||
if (this.dynamicValidateForm.length > 0) {
|
||||
for (let i = 0; i < this.dynamicValidateForm.length; i++) {
|
||||
const obj = this.dynamicValidateForm[i]
|
||||
if (obj.length > 0) {
|
||||
return this.isNodeLegalItem()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return this.isNodeLegalItem()
|
||||
}
|
||||
},
|
||||
// 设置校验
|
||||
setCalibration() {
|
||||
// 在数据返回更新之前,我要顺手吧优先级最后的条件校验设置为 true,管他设没设
|
||||
for (let i = 0; i < this.childNode.conditionNodeList.length; i++) {
|
||||
let conditionNode = this.childNode.conditionNodeList[i]
|
||||
// 取到优先级
|
||||
const priorityLevel = conditionNode.properties.configInfo.priorityLevel
|
||||
// 如果是最高的
|
||||
if (priorityLevel === this.childNode.conditionNodeList.length) {
|
||||
// 给成通过,不管他的条件,本身优先级最后的就是其他条件进入,一般也不设
|
||||
conditionNode.dataLegal = true
|
||||
} else {
|
||||
// 其他地方的,判断是否有条件,无条件的统统给 false
|
||||
if (conditionNode.properties.conditionInfo.length === 0) {
|
||||
conditionNode.dataLegal = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
isNodeLegalItem() {
|
||||
let objNum = 0
|
||||
let successNum = 0
|
||||
if (this.dynamicValidateForm.length > 0) {
|
||||
for (let i = 0; i < this.dynamicValidateForm.length; i++) {
|
||||
const obj = this.dynamicValidateForm[i]
|
||||
let objNumItem = 0
|
||||
if (!isEmpty(obj)) {
|
||||
for (let a = 0; a < obj.length; a++) {
|
||||
objNumItem++
|
||||
if (this.isObjLegal(obj[a])) {
|
||||
successNum++
|
||||
}
|
||||
}
|
||||
objNum = objNum + objNumItem
|
||||
} else {
|
||||
objNum++
|
||||
}
|
||||
}
|
||||
}
|
||||
if (successNum !== 0) {
|
||||
if (objNum === successNum) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
// 校验对象中是否有空值
|
||||
isObjLegal(obj) {
|
||||
let a = 0
|
||||
for (let b in obj) {
|
||||
if (!obj[b]) {
|
||||
a++
|
||||
}
|
||||
}
|
||||
if (a === 1) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
// 增加条件组
|
||||
addDynamicValidateForm() {
|
||||
this.dynamicValidateForm.push([])
|
||||
},
|
||||
// 删除条件组
|
||||
delDomains(index) {
|
||||
this.dynamicValidateForm.splice(index, 1)
|
||||
},
|
||||
addTerm() {
|
||||
const len = this.childNode.conditionNodeList.length
|
||||
const priorityLevel = this.childNode.conditionNodeList[len - 1].properties.configInfo.priorityLevel
|
||||
// 创建分支节点 n
|
||||
const condition = cloneDeep(config.nodeModel.node)
|
||||
condition.id = this.$TOOL.snowyUuid()
|
||||
condition.type = 'sequenceFlow'
|
||||
condition.title = `条件${priorityLevel + 1}`
|
||||
// 创建分支节点2 configInfo
|
||||
const condition1ConfigInfo = cloneDeep(config.nodeConfigInfo.conditionConfigInfo)
|
||||
condition1ConfigInfo.priorityLevel = priorityLevel + 1
|
||||
|
||||
condition.properties.configInfo = condition1ConfigInfo
|
||||
this.childNode.conditionNodeList.push(condition)
|
||||
},
|
||||
delTerm(index) {
|
||||
this.childNode.conditionNodeList.splice(index, 1)
|
||||
if (this.childNode.conditionNodeList.length === 1) {
|
||||
if (this.childNode.childNode) {
|
||||
if (JSON.stringify(this.childNode.conditionNodeList[0].childNode) !== '{}') {
|
||||
this.reData(this.childNode.conditionNodeList[0].childNode, this.childNode.childNode)
|
||||
} else {
|
||||
this.childNode.conditionNodeList[0].childNode = this.childNode.childNode
|
||||
}
|
||||
}
|
||||
this.$emit('update:modelValue', this.childNode.conditionNodeList[0].childNode)
|
||||
}
|
||||
},
|
||||
reData(data, addData) {
|
||||
if (JSON.stringify(data) !== '{}') {
|
||||
data.childNode = addData
|
||||
} else {
|
||||
this.reData(data.childNode, addData)
|
||||
}
|
||||
},
|
||||
arrTransfer(index, type = 1) {
|
||||
this.childNode.conditionNodeList[index] = this.childNode.conditionNodeList.splice(
|
||||
index + type,
|
||||
1,
|
||||
this.childNode.conditionNodeList[index]
|
||||
)[0]
|
||||
this.childNode.conditionNodeList.map((item, index) => {
|
||||
item.properties.configInfo.priorityLevel = index + 1
|
||||
})
|
||||
this.setCalibration()
|
||||
this.$emit('update:modelValue', this.childNode)
|
||||
},
|
||||
addConditionList(index) {
|
||||
const domainsObj = {
|
||||
label: '',
|
||||
key: '',
|
||||
operator: '==',
|
||||
value: ''
|
||||
}
|
||||
this.dynamicValidateForm[index].push(domainsObj)
|
||||
},
|
||||
deleteConditionList(index, domain) {
|
||||
domain.splice(index, 1)
|
||||
},
|
||||
toText(childNode, index) {
|
||||
const conditionList = childNode.conditionNodeList[index].properties.conditionInfo
|
||||
const priorityLevel = childNode.conditionNodeList[index].properties.configInfo.priorityLevel
|
||||
const len = this.childNode.conditionNodeList.length
|
||||
const priorityLevelMax = this.childNode.conditionNodeList[len - 1].properties.configInfo.priorityLevel
|
||||
|
||||
if (JSON.stringify(conditionList) !== undefined && conditionList.length > 0) {
|
||||
let text = ''
|
||||
for (let i = 0; i < conditionList.length; i++) {
|
||||
for (let j = 0; j < conditionList[i].length; j++) {
|
||||
if (j + 1 !== conditionList[i].length) {
|
||||
text =
|
||||
text +
|
||||
conditionList[i][j].label +
|
||||
this.getOperatorLabel(conditionList[i][j].operator) +
|
||||
conditionList[i][j].value +
|
||||
' 且 '
|
||||
} else {
|
||||
text =
|
||||
text +
|
||||
conditionList[i][j].label +
|
||||
this.getOperatorLabel(conditionList[i][j].operator) +
|
||||
conditionList[i][j].value
|
||||
}
|
||||
}
|
||||
if (i + 1 !== conditionList.length) {
|
||||
text = text + ' 或 '
|
||||
}
|
||||
}
|
||||
return text
|
||||
} else if (conditionList.length === 0 && priorityLevel < priorityLevelMax) {
|
||||
return false
|
||||
} else {
|
||||
return '其他条件进入此流程'
|
||||
}
|
||||
},
|
||||
// 通过value 获取界面显示的label汉字
|
||||
getOperatorLabel(value) {
|
||||
return this.operatorList.find((item) => item.value === value).label
|
||||
}
|
||||
}
|
||||
}
|
||||
</script> -->
|
||||
<script setup>
|
||||
import { cloneDeep, isEmpty } from 'lodash-es'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import workFlowUtils from '@/components/XnWorkflow/nodes/utils/index'
|
||||
import tool from '@/utils/tool'
|
||||
import AddNode from './addNode.vue'
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import PropListenerInfo from './prop/propListenerInfo.vue'
|
||||
import formContainer from '@/components/formContainer/index.vue';
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
taskListenerArray: { type: Array, default: () => [] }
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const nodeTitleRef = ref()
|
||||
const propExecutionListenerInfoRef = ref()
|
||||
const childNode = ref({})
|
||||
const drawer = ref(false)
|
||||
const isEditTitle = ref(false)
|
||||
const index = ref(0)
|
||||
const form = ref({})
|
||||
const dynamicValidateForm = ref([])
|
||||
const fieldList = ref([])
|
||||
const activeKey = ref('1')
|
||||
const executionListenerInfo = cloneDeep(config.listener.exclusiveGatewayExecutionListenerInfo)
|
||||
const operatorList = cloneDeep(config.exclusiveGatewayConfig.operatorList)
|
||||
watch(props, newValue => {
|
||||
if (newValue.modelValue) {
|
||||
childNode.value = newValue.modelValue
|
||||
}
|
||||
})
|
||||
onMounted(() => {
|
||||
childNode.value = props.modelValue
|
||||
// 把字段给掏出来
|
||||
fieldList.value = workFlowUtils.getListField(props.formFieldListValue).map(m => {
|
||||
let type = m.type //slider rate number
|
||||
if (type === 'slider' || type === 'rate' || type === 'number') {
|
||||
m.type = 'number'
|
||||
}
|
||||
return {
|
||||
label: m.label,
|
||||
model: m.selectTable + '.' + m.model,
|
||||
type: m.type
|
||||
}
|
||||
})
|
||||
})
|
||||
const show = value => {
|
||||
index.value = value
|
||||
form.value = {}
|
||||
form.value = cloneDeep(childNode.value.conditionNodeList[value])
|
||||
drawer.value = true
|
||||
dynamicValidateForm.value = form.value.properties.conditionInfo
|
||||
}
|
||||
const editTitle = () => {
|
||||
isEditTitle.value = true
|
||||
nextTick(() => {
|
||||
nodeTitleRef.value.focus()
|
||||
})
|
||||
}
|
||||
const saveTitle = () => {
|
||||
isEditTitle.value = false
|
||||
}
|
||||
const save = () => {
|
||||
form.value.properties.conditionInfo = dynamicValidateForm.value
|
||||
form.value.properties.executionListenerInfo = propExecutionListenerInfoRef.value.selectedListenerList()
|
||||
if (isNodeLegal(form.value)) {
|
||||
form.value.dataLegal = true
|
||||
childNode.value.conditionNodeList[index.value] = form.value
|
||||
setCalibration()
|
||||
emit('update:modelValue', childNode)
|
||||
drawer.value = false
|
||||
} else {
|
||||
form.value.dataLegal = false
|
||||
}
|
||||
}
|
||||
const isSelectOption = (record, value) => {
|
||||
if (props.recordData.formType === 'DESIGN') {
|
||||
if (record.field) {
|
||||
return fieldList.value.find(f => f.model === record.field).type === 'number'
|
||||
}
|
||||
} else {
|
||||
if (value === 'include' || value === 'notInclude') {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
// 校验此条件是否通过
|
||||
const isNodeLegal = data => {
|
||||
const priorityLevel =
|
||||
data && data.properties && data.properties.configInfo && data.properties.configInfo.priorityLevel
|
||||
? data.properties.configInfo.priorityLevel
|
||||
: ''
|
||||
const len =
|
||||
childNode.value && childNode.value.conditionNodeList && childNode.value.conditionNodeList.length
|
||||
? childNode.value.conditionNodeList.length
|
||||
: 0
|
||||
const priorityLevelMax =
|
||||
len != 0 ? childNode.value.conditionNodeList[len - 1].properties.configInfo.priorityLevel : 0
|
||||
// 如果往其他条件的分支中增加,那我们一视同仁
|
||||
if (priorityLevelMax === priorityLevel) {
|
||||
if (dynamicValidateForm.value.length > 0) {
|
||||
for (let i = 0; i < dynamicValidateForm.value.length; i++) {
|
||||
const obj = dynamicValidateForm.value[i]
|
||||
if (obj.length > 0) {
|
||||
return isNodeLegalItem()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return isNodeLegalItem()
|
||||
}
|
||||
}
|
||||
// 设置校验
|
||||
const setCalibration = () => {
|
||||
// 在数据返回更新之前,我要顺手吧优先级最后的条件校验设置为 true,管他设没设
|
||||
for (let i = 0; i < childNode.value.conditionNodeList.length; i++) {
|
||||
let conditionNode = childNode.value.conditionNodeList[i]
|
||||
// 取到优先级
|
||||
const priorityLevel = conditionNode.properties.configInfo.priorityLevel
|
||||
// 如果是最高的
|
||||
if (priorityLevel === childNode.value.conditionNodeList.length) {
|
||||
// 给成通过,不管他的条件,本身优先级最后的就是其他条件进入,一般也不设
|
||||
conditionNode.dataLegal = true
|
||||
} else {
|
||||
// 其他地方的,判断是否有条件,无条件的统统给 false
|
||||
if (conditionNode.properties.conditionInfo.length === 0) {
|
||||
conditionNode.dataLegal = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const isNodeLegalItem = () => {
|
||||
let objNum = 0
|
||||
let successNum = 0
|
||||
if (dynamicValidateForm.value.length > 0) {
|
||||
for (let i = 0; i < dynamicValidateForm.value.length; i++) {
|
||||
const obj = dynamicValidateForm.value[i]
|
||||
let objNumItem = 0
|
||||
if (!isEmpty(obj)) {
|
||||
for (let a = 0; a < obj.length; a++) {
|
||||
objNumItem++
|
||||
if (isObjLegal(obj[a])) {
|
||||
successNum++
|
||||
}
|
||||
}
|
||||
objNum = objNum + objNumItem
|
||||
} else {
|
||||
objNum++
|
||||
}
|
||||
}
|
||||
}
|
||||
if (successNum !== 0) {
|
||||
if (objNum === successNum) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
// 校验对象中是否有空值
|
||||
const isObjLegal = obj => {
|
||||
let a = 0
|
||||
for (let b in obj) {
|
||||
if (!obj[b]) {
|
||||
a++
|
||||
}
|
||||
}
|
||||
return a === 1
|
||||
}
|
||||
// 增加条件组
|
||||
const addDynamicValidateForm = () => {
|
||||
dynamicValidateForm.value.push([])
|
||||
}
|
||||
// 删除条件组
|
||||
const delDomains = index => {
|
||||
dynamicValidateForm.value.splice(index, 1)
|
||||
}
|
||||
const addTerm = () => {
|
||||
const len = childNode.value.conditionNodeList.length
|
||||
const priorityLevel = childNode.value.conditionNodeList[len - 1].properties.configInfo.priorityLevel
|
||||
// 创建分支节点 n
|
||||
const condition = cloneDeep(config.nodeModel.node)
|
||||
condition.id = tool.snowyUuid()
|
||||
condition.type = 'sequenceFlow'
|
||||
condition.title = `条件${priorityLevel + 1}`
|
||||
// 创建分支节点2 configInfo
|
||||
const condition1ConfigInfo = cloneDeep(config.nodeConfigInfo.conditionConfigInfo)
|
||||
condition1ConfigInfo.priorityLevel = priorityLevel + 1
|
||||
condition.properties.configInfo = condition1ConfigInfo
|
||||
childNode.value.conditionNodeList.push(condition)
|
||||
}
|
||||
const delTerm = index => {
|
||||
childNode.value.conditionNodeList.splice(index, 1)
|
||||
if (childNode.value.conditionNodeList.length === 1) {
|
||||
if (childNode.value.childNode) {
|
||||
// 如果有子项
|
||||
if (!isEmpty(childNode.value.conditionNodeList[0].childNode)) {
|
||||
reData(childNode.value.conditionNodeList[0].childNode, childNode.value.childNode)
|
||||
} else {
|
||||
childNode.value.conditionNodeList[0].childNode = childNode.value.childNode
|
||||
}
|
||||
}
|
||||
emit('update:modelValue', childNode.value.conditionNodeList[0].childNode)
|
||||
}
|
||||
}
|
||||
const reData = (data, addData) => {
|
||||
if (!isEmpty(data)) {
|
||||
data.childNode = addData
|
||||
} else {
|
||||
reData(data.childNode, addData)
|
||||
}
|
||||
}
|
||||
const arrTransfer = (index, type = 1) => {
|
||||
childNode.value.conditionNodeList[index] = childNode.value.conditionNodeList.splice(
|
||||
index + type,
|
||||
1,
|
||||
childNode.value.conditionNodeList[index]
|
||||
)[0]
|
||||
childNode.value.conditionNodeList.map((item, index) => {
|
||||
item.properties.configInfo.priorityLevel = index + 1
|
||||
})
|
||||
setCalibration()
|
||||
emit('update:modelValue', childNode.value)
|
||||
}
|
||||
const addConditionList = index => {
|
||||
const domainsObj = {
|
||||
label: '',
|
||||
key: '',
|
||||
operator: '==',
|
||||
value: ''
|
||||
}
|
||||
dynamicValidateForm.value[index].push(domainsObj)
|
||||
}
|
||||
const deleteConditionList = (index, domain) => {
|
||||
domain.splice(index, 1)
|
||||
}
|
||||
const toText = (childNode, index) => {
|
||||
const conditionList = childNode.conditionNodeList[index].properties.conditionInfo
|
||||
const priorityLevel = childNode.conditionNodeList[index].properties.configInfo.priorityLevel
|
||||
const len = childNode.conditionNodeList.length
|
||||
const priorityLevelMax = childNode.conditionNodeList[len - 1].properties.configInfo.priorityLevel
|
||||
if (JSON.stringify(conditionList) !== undefined && conditionList.length > 0) {
|
||||
let text = ''
|
||||
for (let i = 0; i < conditionList.length; i++) {
|
||||
for (let j = 0; j < conditionList[i].length; j++) {
|
||||
if (j + 1 !== conditionList[i].length) {
|
||||
text =
|
||||
text +
|
||||
conditionList[i][j].label +
|
||||
getOperatorLabel(conditionList[i][j].operator) +
|
||||
conditionList[i][j].value +
|
||||
' 且 '
|
||||
} else {
|
||||
text =
|
||||
text +
|
||||
conditionList[i][j].label +
|
||||
getOperatorLabel(conditionList[i][j].operator) +
|
||||
conditionList[i][j].value
|
||||
}
|
||||
}
|
||||
if (i + 1 !== conditionList.length) {
|
||||
text = text + ' 或 '
|
||||
}
|
||||
}
|
||||
return text
|
||||
} else if (conditionList.length === 0 && priorityLevel < priorityLevelMax) {
|
||||
return false
|
||||
} else {
|
||||
return '其他条件进入此流程'
|
||||
}
|
||||
}
|
||||
// 通过value 获取界面显示的label汉字
|
||||
const getOperatorLabel = value => {
|
||||
return operatorList.find(item => item.value === value).label
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.deleteIcon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.minusCircle {
|
||||
font-size: 25px;
|
||||
}
|
||||
.dashedButton {
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,175 +0,0 @@
|
||||
<template>
|
||||
<div class="branch-wrap">
|
||||
<div class="branch-box-wrap">
|
||||
<div class="branch-box">
|
||||
<el-button class="add-branch" type="primary" shape="round" @click="addTerm">添加并行</el-button>
|
||||
<div v-for="(item, index) in childNode.conditionNodeList" :key="index" class="col-box">
|
||||
<div class="condition-node">
|
||||
<div class="condition-node-box">
|
||||
<user-task
|
||||
v-model="childNode.conditionNodeList[index]"
|
||||
:form-field-list-value="formFieldListValue"
|
||||
:recordData="recordData"
|
||||
:processConfigInfo="processConfigInfo"
|
||||
:execution-listener-array="executionListenerArray"
|
||||
:task-listener-array="taskListenerArray"
|
||||
:selector-api-function="selectorApiFunction"
|
||||
@deleteParalle="delTerm(index)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<slot v-if="item.childNode" :node="item" />
|
||||
<div v-if="index === 0" class="top-left-cover-line" />
|
||||
<div v-if="index === 0" class="bottom-left-cover-line" />
|
||||
<div v-if="index === childNode.conditionNodeList.length - 1" class="top-right-cover-line" />
|
||||
<div v-if="index === childNode.conditionNodeList.length - 1" class="bottom-right-cover-line" />
|
||||
</div>
|
||||
</div>
|
||||
<add-node v-model="childNode.childNode" :parent-data="childNode" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- <script>
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import addNode from './addNode.vue'
|
||||
import userTask from './userTask.vue'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
addNode,
|
||||
userTask
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
processConfigInfo: { type: Object, default: () => {} },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
taskListenerArray: { type: Array, default: () => [] },
|
||||
selectorApiFunction: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {},
|
||||
drawer: false,
|
||||
isEditTitle: false,
|
||||
index: 0,
|
||||
form: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
addTerm() {
|
||||
const len = this.childNode.conditionNodeList.length + 1
|
||||
// 创建主节点
|
||||
const nodeModel = cloneDeep(config.nodeModel.node)
|
||||
nodeModel.id = this.$TOOL.snowyUuid()
|
||||
nodeModel.type = 'userTask'
|
||||
;(nodeModel.title = `审批人${len}`),
|
||||
(nodeModel.priorityLevel = len),
|
||||
(nodeModel.conditionNodeList = []),
|
||||
(nodeModel.childNode = {})
|
||||
// 创建 configInfo
|
||||
const configInfo = cloneDeep(config.nodeConfigInfo.userTaskConfigInfo)
|
||||
nodeModel.properties.configInfo = configInfo
|
||||
|
||||
this.childNode.conditionNodeList.push(nodeModel)
|
||||
},
|
||||
delTerm(index) {
|
||||
this.childNode.conditionNodeList.splice(index, 1)
|
||||
if (this.childNode.conditionNodeList.length == 1) {
|
||||
if (this.childNode.childNode) {
|
||||
// 这是{}
|
||||
if (JSON.stringify(this.childNode.conditionNodeList[0].childNode) !== '{}') {
|
||||
this.reData(this.childNode.conditionNodeList[0].childNode, this.childNode.childNode)
|
||||
} else {
|
||||
this.childNode.conditionNodeList[0].childNode = this.childNode.childNode
|
||||
}
|
||||
}
|
||||
this.$emit('update:modelValue', this.childNode.conditionNodeList[0].childNode)
|
||||
}
|
||||
},
|
||||
reData(data, addData) {
|
||||
if (JSON.stringify(data) !== '{}') {
|
||||
data.childNode = addData
|
||||
} else {
|
||||
this.reData(data.childNode, addData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script> -->
|
||||
<script setup>
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import tool from '@/utils/tool'
|
||||
import AddNode from './addNode.vue'
|
||||
import UserTask from './userTask.vue'
|
||||
import {ref,watch,onMounted} from 'vue';
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
processConfigInfo: { type: Object, default: () => {} },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
taskListenerArray: { type: Array, default: () => [] },
|
||||
selectorApiFunction: { type: Object, default: () => {} }
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const childNode = ref({})
|
||||
const drawer = ref(false)
|
||||
const index = ref(0)
|
||||
const form = ref({})
|
||||
watch(props, (newValue) => {
|
||||
if (props.modelValue) {
|
||||
childNode.value = newValue.modelValue
|
||||
}
|
||||
})
|
||||
onMounted(() => {
|
||||
childNode.value = props.modelValue
|
||||
})
|
||||
const addTerm = () => {
|
||||
const len = childNode.value.conditionNodeList.length + 1
|
||||
// 创建主节点
|
||||
const nodeModel = cloneDeep(config.nodeModel.node)
|
||||
nodeModel.id = tool.snowyUuid()
|
||||
nodeModel.type = 'userTask'
|
||||
;(nodeModel.title = `审批人${len}`),
|
||||
(nodeModel.priorityLevel = len),
|
||||
(nodeModel.conditionNodeList = []),
|
||||
(nodeModel.childNode = {})
|
||||
// 创建 configInfo
|
||||
nodeModel.properties.configInfo = cloneDeep(config.nodeConfigInfo.userTaskConfigInfo)
|
||||
childNode.value.conditionNodeList.push(nodeModel)
|
||||
}
|
||||
const delTerm = (index) => {
|
||||
childNode.value.conditionNodeList.splice(index, 1)
|
||||
if (childNode.value.conditionNodeList.length === 1) {
|
||||
if (childNode.value.childNode) {
|
||||
// 这是{}
|
||||
if (JSON.stringify(childNode.value.conditionNodeList[0].childNode) !== '{}') {
|
||||
reData(childNode.value.conditionNodeList[0].childNode, childNode.value.childNode)
|
||||
} else {
|
||||
childNode.value.conditionNodeList[0].childNode = childNode.value.childNode
|
||||
}
|
||||
}
|
||||
emit('update:modelValue', childNode.value.conditionNodeList[0].childNode)
|
||||
}
|
||||
}
|
||||
const reData = (data, addData) => {
|
||||
if (JSON.stringify(data) !== '{}') {
|
||||
data.childNode = addData
|
||||
} else {
|
||||
reData(data.childNode, addData)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,117 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="表单人员选择"
|
||||
:mask-closable="false"
|
||||
:destroy-on-close="true"
|
||||
:width="600"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<div class="form-user-table">
|
||||
<el-table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:datel-source="dataSource"
|
||||
:row-key="record => record.model"
|
||||
:expand-row-by-click="true"
|
||||
:row-selection="{ selectedRowKeys: state.selectedRowKeys, onChange: onSelectChange, type: 'radio' }"
|
||||
:pagination="false"
|
||||
size="small"
|
||||
bordered
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup name="formUserSelector">
|
||||
import workFlowUtils from '@/components/XnWorkflow/nodes/utils/index'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ref, reactive } from 'vue'
|
||||
const visible = ref(false)
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '字段名',
|
||||
dataIndex: 'label'
|
||||
},
|
||||
{
|
||||
title: '字段',
|
||||
dataIndex: 'model'
|
||||
}
|
||||
]
|
||||
|
||||
// 定义emit事件
|
||||
const emit = defineEmits({ click: null })
|
||||
const props = defineProps(['formFieldList'])
|
||||
|
||||
const dataSource = ref([])
|
||||
dataSource.value = workFlowUtils
|
||||
.getListField(props.formFieldList)
|
||||
.filter(f => {
|
||||
// 判断如果是人员类型的,就让列表显示
|
||||
if (f.type === 'xnUserSelector') {
|
||||
return f
|
||||
}
|
||||
})
|
||||
.map(m => {
|
||||
return {
|
||||
label: m.label,
|
||||
model: m.model,
|
||||
field: m.model,
|
||||
type: m.type
|
||||
}
|
||||
})
|
||||
const selectedRowKeys = ref([])
|
||||
// 设置默认选中的
|
||||
const state = reactive({
|
||||
selectedRowKeys: selectedRowKeys.value,
|
||||
loading: false
|
||||
})
|
||||
const showFormUserModal = (data = '') => {
|
||||
if (dataSource.value.length === 0) {
|
||||
ElMessage({
|
||||
message: '表单内无人员可提供选择!',
|
||||
type: 'warning'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (dataSource.value.length === 1) {
|
||||
emit('click', dataSource.value[0])
|
||||
ElMessage({
|
||||
message: '表单内仅有一个人员选择,默认选中!',
|
||||
type: 'success'
|
||||
})
|
||||
} else {
|
||||
visible.value = true
|
||||
state.selectedRowKeys[0] = data
|
||||
}
|
||||
}
|
||||
// 点击复选框回调
|
||||
const onSelectChange = selectedRowKeys => {
|
||||
state.selectedRowKeys = selectedRowKeys
|
||||
}
|
||||
// 确定
|
||||
const handleOk = () => {
|
||||
const result = dataSource.value.filter(item => state.selectedRowKeys[0] === item.model)
|
||||
emit('click', result[0])
|
||||
visible.value = false
|
||||
state.selectedRowKeys = []
|
||||
}
|
||||
// 关闭
|
||||
const handleCancel = () => {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 抛出方法,让上个界面使用
|
||||
defineExpose({
|
||||
showFormUserModal
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.form-user-table {
|
||||
overflow: auto;
|
||||
max-height: 400px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,171 +0,0 @@
|
||||
<template>
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">参与者可以看见或操作哪些按钮</span>
|
||||
</div>
|
||||
<el-table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:datel-source="dataSource"
|
||||
:row-key="record => record.key"
|
||||
:expand-row-by-click="true"
|
||||
:row-selection="{
|
||||
selectedRowKeys: state.selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
getCheckboxProps: checkboxProps
|
||||
}"
|
||||
:pagination="false"
|
||||
:show-header="false"
|
||||
size="small"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'label'">
|
||||
<el-popover trigger="hover" placement="left">
|
||||
<template #content>
|
||||
<el-button :type="record.type" size="small">
|
||||
<template #icon>
|
||||
<component :is="record.icon" />
|
||||
</template>
|
||||
{{ record.label }}
|
||||
</el-button>
|
||||
<div v-if="record.key === 'SAVE'" style="width: 300px">
|
||||
”保存“按钮作用为发起节点保存操作,审批节点下无保存操作。
|
||||
</div>
|
||||
<div v-if="record.key === 'SUBMIT'" style="width: 300px">
|
||||
”提交“按钮作用为发起节点填写完申请单,提交流程到下一步。
|
||||
</div>
|
||||
<div v-if="record.key === 'REVOKE'" style="width: 300px">
|
||||
”撤回“按钮作用为发起节点发错内容,将其撤回。
|
||||
</div>
|
||||
<div v-if="record.key === 'PASS'" style="width: 300px">
|
||||
按钮作用为审批节点同意该审核之操作。
|
||||
</div>
|
||||
<div v-if="record.key === 'REJECT'" style="width: 300px">
|
||||
按钮作用为审批节点进行拒绝之操作。
|
||||
</div>
|
||||
<div v-if="record.key === 'BACK'" style="width: 300px">
|
||||
按钮作用为审批节点退回操作,可退回至任意节点。
|
||||
</div>
|
||||
<div v-if="record.key === 'ADD_SIGN'" style="width: 300px">按钮作用为审批节点加签操作。</div>
|
||||
<div v-if="record.key === 'TURN'" style="width: 300px">
|
||||
按钮作用为审批节点转给他人办理操作。
|
||||
</div>
|
||||
<div v-if="record.key === 'JUMP'" style="width: 300px">
|
||||
按钮作用为审批节点可跳转至任意节点操作。
|
||||
</div>
|
||||
<div v-if="record.key === 'PRINT'" style="width: 300px">
|
||||
按钮配置后,操作人到该节点可以进行管理员配置的全局打印模板,进行打印此流程进展的内容。
|
||||
</div>
|
||||
</template>
|
||||
<el-button size="small" :type="record.type">
|
||||
<template #icon>
|
||||
<component :is="record.icon" />
|
||||
</template>
|
||||
{{ record.label }}
|
||||
</el-button>
|
||||
</el-popover>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'newLabel'">
|
||||
<el-input v-model:value="record.newLabel" show-count :maxlength="10" />
|
||||
</template>
|
||||
</template>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script setup name="propButtonInfo">
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { ref, reactive } from 'vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'label',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'newLabel'
|
||||
}
|
||||
]
|
||||
const buttonInfo = cloneDeep(config.nodeModel.buttonInfo)
|
||||
|
||||
const props = defineProps(['buttonInfo', 'showButton', 'noChecked'])
|
||||
|
||||
const dataSource = ref([])
|
||||
const selectedRowKeys = ref([])
|
||||
// 将其回传的跟本组件的关联性切断
|
||||
selectedRowKeys.value = cloneDeep(props.showButton)
|
||||
|
||||
// 设置按钮选中及显示的
|
||||
const buttonInfoData = () => {
|
||||
buttonInfo.forEach(button => {
|
||||
if (props.buttonInfo.length > 0) {
|
||||
props.buttonInfo.forEach(item => {
|
||||
if (button.key === item.key) {
|
||||
button.newLabel = item.label
|
||||
button.value = item.value
|
||||
}
|
||||
})
|
||||
} else {
|
||||
button.newLabel = button.label
|
||||
}
|
||||
// 匹配选中的
|
||||
if (selectedRowKeys.value.length > 0) {
|
||||
selectedRowKeys.value.forEach(selectedRowKey => {
|
||||
if (button.value === 'SHOW') {
|
||||
// 已有的里面如果不包含这个已经被选中的
|
||||
if (selectedRowKeys.value.indexOf(button.key) === -1) {
|
||||
selectedRowKeys.value.push(button.key)
|
||||
}
|
||||
}
|
||||
if (selectedRowKey === button.key) {
|
||||
button.value = 'SHOW'
|
||||
}
|
||||
})
|
||||
} else if (button.value === 'SHOW') {
|
||||
if (selectedRowKeys.value.indexOf(button.key) === -1) {
|
||||
selectedRowKeys.value.push(button.key)
|
||||
}
|
||||
}
|
||||
})
|
||||
return buttonInfo
|
||||
}
|
||||
|
||||
dataSource.value = buttonInfoData()
|
||||
|
||||
// 设置默认选中的
|
||||
const state = reactive({
|
||||
selectedRowKeys: selectedRowKeys.value,
|
||||
loading: false
|
||||
})
|
||||
// 点击复选框回调
|
||||
const onSelectChange = selectedRowKeys => {
|
||||
state.selectedRowKeys = selectedRowKeys
|
||||
}
|
||||
// 设置选择框的默认属性配置,将其设置成不可取消,不可选中
|
||||
const checkboxProps = record => ({
|
||||
disabled:
|
||||
(record.value === 'SHOW' && props.showButton.indexOf(record.key) > -1) ||
|
||||
props.noChecked.indexOf(record.key) > -1
|
||||
})
|
||||
// 父界面需要调用获取参数
|
||||
const selectedButtonKeyList = () => {
|
||||
let resultData = cloneDeep(dataSource.value)
|
||||
resultData.forEach(dataItem => {
|
||||
if (state.selectedRowKeys.indexOf(dataItem.key) > -1) {
|
||||
dataItem.value = 'SHOW'
|
||||
} else {
|
||||
dataItem.value = 'HIDE'
|
||||
}
|
||||
if (dataItem.newLabel !== '') {
|
||||
dataItem.label = dataItem.newLabel
|
||||
}
|
||||
delete dataItem.newLabel
|
||||
})
|
||||
return resultData
|
||||
}
|
||||
// 抛出方法,让上个界面使用
|
||||
defineExpose({
|
||||
selectedButtonKeyList
|
||||
})
|
||||
</script>
|
||||
@@ -1,94 +0,0 @@
|
||||
propButtonInfo
|
||||
====
|
||||
|
||||
> 工作流中配置按钮选择器
|
||||
> eg: 发起人、审批人、通知人 这三个节点使用
|
||||
|
||||
该组件由 [俞宝山](https://www.xiaonuo.vip) 封装
|
||||
|
||||
|
||||
### 使用方式
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<prop-button-info ref="propButtonInfo" :buttonInfo="selectedButtonInfo" :showButton="startTaskDefaultButtonkey"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 配置的一些数据
|
||||
import config from '@/components/XnWorkflow/nodes/config/config';
|
||||
|
||||
// 这个数据就是下面说的,回显数据,选中的数据对象中show值为true
|
||||
const selectedButtonInfo = ref(
|
||||
[
|
||||
{
|
||||
key: 'SAVE',
|
||||
label: '保存',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
key: 'SUBMIT',
|
||||
label: '提交',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
key: 'REVOKE',
|
||||
label: '撤回',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
key: 'COMPLETE',
|
||||
label: '同意',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
key: 'REJECT',
|
||||
label: '驳回',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
key: 'PRINT',
|
||||
label: '打印',
|
||||
show: false,
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
// 某个节点调用此组件,不管三七二十一,这个是必须选中,而且不能取消的
|
||||
const startTaskDefaultButtonkey = ref(
|
||||
// 注意:使用静态配置中的数据,必须切断双向绑定,不能因为不切短改变原始数据
|
||||
JSON.parse(JSON.stringify(config.button.startTaskDefaultButtonkey))
|
||||
)
|
||||
|
||||
// 可以配置不让配置选择的按钮
|
||||
const startTaskNoCheckedButtonkey = ref(
|
||||
// 注意:使用静态配置中的数据,必须切断双向绑定,不能因为不切短改变原始数据
|
||||
JSON.parse(JSON.stringify(config.button.startTaskNoCheckedButtonkey))
|
||||
)
|
||||
|
||||
// 初始化我们调用这个组件的ref名称,Vue3 setup语法糖的写法,是这样的哦!
|
||||
const propButtonInfo = ref(null);
|
||||
|
||||
// 使用的界面调用这个方法,获得组件中选好的数据
|
||||
const getButtonInfoData = () => {
|
||||
console.log('result data :' + JSON.stringify(propButtonInfo.selectedButtonKeyList()))
|
||||
}
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
### 事件
|
||||
|
||||
| 名称 | 说明 | 类型 | 默认值 |
|
||||
| --------------------- | ----------------------------------- | ------ | ------ |
|
||||
| selectedButtonKeyList | 调用界面使用此方法获取组件中选中的数据 | Array | [] |
|
||||
|
||||
### 数据
|
||||
|
||||
| 名称 | 说明 | 类型 | 默认值 |
|
||||
| ---------- | ------------------------------------------------------------------------------------ | ------ | ------ |
|
||||
| buttonInfo | 传送数据为此模型节点中选中的按钮用show=true标识,示例:`selectedButtonInfo` | Array | [] |
|
||||
| showButton | 哪个节点调用,哪个节点设置他必选的,不能改变的按钮数据,示例:`startTaskDefaultButtonkey ` | Array | [] |
|
||||
| noChecked | 默认不让哪个按钮在本节点进行配置,示例:`startTaskNoCheckedButtonkey ` | Array | [] |
|
||||
@@ -1,142 +0,0 @@
|
||||
<template>
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">参与者可以看见或操作哪些字段</span>
|
||||
</div>
|
||||
<el-table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:datel-source="dataSource"
|
||||
:row-key="(record) => record.key"
|
||||
:expand-row-by-click="true"
|
||||
:pagination="false"
|
||||
:show-header="false"
|
||||
size="small"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'label'">
|
||||
<span v-if="record.required" style="color: red">* </span>
|
||||
<span v-else> </span>
|
||||
{{ record.label }}
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'value'">
|
||||
<el-radio-group v-model:value="record.value" :disabled="record.disabled">
|
||||
<el-radio :key="radio.value" v-for="radio in fieldRadioList" :value="radio.value">{{ radio.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
</template>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script setup name="propFieldInfo">
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import {ref} from 'vue'
|
||||
const columns = [
|
||||
{
|
||||
title: '表单字段',
|
||||
dataIndex: 'label',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'value'
|
||||
}
|
||||
]
|
||||
// 定义一个表单的已拖进去的组件列表,也就是我们要的字段列表
|
||||
const listField = ref([])
|
||||
|
||||
let fieldRadioList = JSON.parse(JSON.stringify(config.field.fieldRadioList))
|
||||
|
||||
// 接受到值
|
||||
const props = defineProps(['formFieldListValue', 'fieldInfo', 'defaultFieldModel'])
|
||||
|
||||
const dataSource = ref([])
|
||||
|
||||
const getListField = () => {
|
||||
listField.value = []
|
||||
// 递归遍历控件树
|
||||
const traverse = (array) => {
|
||||
array.forEach((element) => {
|
||||
if (element.type === 'grid' || element.type === 'tabs') {
|
||||
// 栅格布局 and 标签页
|
||||
element.columns.forEach((item) => {
|
||||
traverse(item.list)
|
||||
})
|
||||
} else if (element.type === 'card') {
|
||||
// 卡片布局 and 动态表格
|
||||
traverse(element.list)
|
||||
} else if (element.type === 'table') {
|
||||
// 表格布局
|
||||
element.trs.forEach((item) => {
|
||||
item.tds.forEach((val) => {
|
||||
traverse(val.list)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const type = element.type
|
||||
// 排除一些
|
||||
if ((type !== 'alert') & (type !== 'text') & (type !== 'divider') & (type !== 'html')) {
|
||||
// & (type !== 'batch')
|
||||
listField.value.push(element)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
traverse(props.formFieldListValue)
|
||||
}
|
||||
|
||||
if (props.formFieldListValue.length > 0) {
|
||||
getListField()
|
||||
// 数据转换至模型中
|
||||
listField.value.forEach((item) => {
|
||||
// 创建数据模型
|
||||
let dataModel = {}
|
||||
// 如果调用此组件的节点没配置它默认的选中按钮,那么就用通用的
|
||||
if (props.defaultFieldModel) {
|
||||
dataModel = JSON.parse(JSON.stringify(props.defaultFieldModel))
|
||||
} else {
|
||||
dataModel = JSON.parse(JSON.stringify(config.field.fieldModel))
|
||||
}
|
||||
dataModel.key = item.model
|
||||
// 假如有选中的值,我们将其回显
|
||||
if (props.fieldInfo.length > 0) {
|
||||
props.fieldInfo.forEach((field) => {
|
||||
if (field.key === item.model) {
|
||||
dataModel.value = field.value
|
||||
}
|
||||
})
|
||||
}
|
||||
if (item.rules) {
|
||||
dataModel.required = item.rules[0].required
|
||||
} else {
|
||||
dataModel.required = false
|
||||
}
|
||||
// 判断有没有从表单那边勾选了隐藏跟禁用
|
||||
if (item.options.hidden || item.options.disabled) {
|
||||
dataModel.disabled = true
|
||||
// 并且设置它选中的选项为隐藏活禁用
|
||||
if (item.options.disabled) {
|
||||
dataModel.value = 'READ' // 只读
|
||||
}
|
||||
// 如果设置了隐藏跟禁用,我们按隐藏来算
|
||||
if (item.options.hidden) {
|
||||
dataModel.value = 'HIDE' // 隐藏
|
||||
}
|
||||
} else {
|
||||
dataModel.disabled = false
|
||||
}
|
||||
dataModel.label = item.label
|
||||
dataSource.value.push(dataModel)
|
||||
})
|
||||
}
|
||||
// 父界面需要调用获取参数
|
||||
const selectedFieldList = () => {
|
||||
let resultData = JSON.parse(JSON.stringify(dataSource.value))
|
||||
return resultData
|
||||
}
|
||||
// 抛出方法,让上个界面使用
|
||||
defineExpose({
|
||||
selectedFieldList
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,127 +0,0 @@
|
||||
propFieldInfo
|
||||
====
|
||||
|
||||
> 工作流中配置字段选择器
|
||||
> eg: 发起人、审批人这两个节点使用
|
||||
|
||||
该组件由 [俞宝山](https://www.xiaonuo.vip) 封装
|
||||
|
||||
|
||||
### 使用方式
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<prop-field-info ref="propFieldInfo" :field-info="fieldInfo" :default-field-model="defaultFieldModel" :form-field-list-value="formFieldListValue"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
// 这个数据就是下面说的,回显数据,选中的数据对象中show值为true
|
||||
const fieldInfo = ref(
|
||||
{
|
||||
"key":"input_1653160767462",
|
||||
"label":"姓名",
|
||||
"value":"WRITE",
|
||||
"required":true,
|
||||
},
|
||||
{
|
||||
"key":"input_1653160770827",
|
||||
"label":"绰号",
|
||||
"value":"WRITE",
|
||||
"required":true,
|
||||
}
|
||||
)
|
||||
|
||||
// 这个是表单设计器选择后传过来的
|
||||
const formFieldListValue = ref(
|
||||
[
|
||||
{
|
||||
"type":"input",
|
||||
"label":"姓名",
|
||||
"icon":"icon-write",
|
||||
"options":{
|
||||
"type":"text",
|
||||
"width":"100%",
|
||||
"defaultValue":"",
|
||||
"placeholder":"请输入",
|
||||
"clearable":false,
|
||||
"maxLength":null,
|
||||
"addonBefore":"",
|
||||
"addonAfter":"",
|
||||
"hidden":false,
|
||||
"disabled":false
|
||||
},
|
||||
"model":"input_1653160767462",
|
||||
"key":"input_1653160767462",
|
||||
"help":"",
|
||||
"rules":[
|
||||
{
|
||||
"required":true,
|
||||
"message":"必填项"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type":"input",
|
||||
"label":"绰号",
|
||||
"icon":"icon-write",
|
||||
"options":{
|
||||
"type":"text",
|
||||
"width":"100%",
|
||||
"defaultValue":"",
|
||||
"placeholder":"请输入",
|
||||
"clearable":false,
|
||||
"maxLength":null,
|
||||
"addonBefore":"",
|
||||
"addonAfter":"",
|
||||
"hidden":false,
|
||||
"disabled":false
|
||||
},
|
||||
"model":"input_1653160770827",
|
||||
"key":"input_1653160770827",
|
||||
"help":"",
|
||||
"rules":[
|
||||
{
|
||||
"required":false,
|
||||
"message":"必填项"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
// 默认的节点选中
|
||||
const defaultFieldModel = ref({
|
||||
key: '',
|
||||
label: '',
|
||||
value: 'READ', // 默认设为只读
|
||||
required: false, // 必填
|
||||
extJson: '' // 额外扩展,暂无
|
||||
})
|
||||
|
||||
// 初始化我们调用这个组件的ref名称,Vue3 setup语法糖的写法,是这样的哦!
|
||||
const propFieldInfo = ref(null);
|
||||
|
||||
// 使用的界面调用这个方法,获得组件中选好的数据
|
||||
const selectedFieldList = () => {
|
||||
console.log('result data :' + JSON.stringify(propFieldInfo.selectedFieldList()))
|
||||
}
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
### 事件
|
||||
|
||||
| 名称 | 说明 | 类型 | 默认值 |
|
||||
| --------------------- | ----------------------------------- | ------ | ------ |
|
||||
| selectedFieldList | 调用界面使用此方法获取组件中选中的数据 | Array | [] |
|
||||
|
||||
### 数据
|
||||
|
||||
| 名称 | 说明 | 类型 | 默认值 |
|
||||
| ---------- | ------------------------------------------------------------------------------------ | ------ | ------ |
|
||||
| form-field-list-value | 表单设计器中拖拉拽过后的字段数据,示例:`formFieldListValue` | Array | [] |
|
||||
| field-info | 这个节点已经选好勾好的数据,回显的,示例:`fieldInfo ` | Array | [] |
|
||||
| default-field-model | 默认这个节点勾选的字段配置,示例:`defaultFieldModel ` | Array | [] |
|
||||
@@ -1,158 +0,0 @@
|
||||
<template>
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">配置要执行的监听</span>
|
||||
</div>
|
||||
<el-button type="primary" size="small" @click="addEditListener" class="mb-2">
|
||||
<template #icon>
|
||||
<!-- <plus-outlined/> -->
|
||||
</template>
|
||||
新增
|
||||
</el-button>
|
||||
<el-table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:datel-source="dataSource"
|
||||
:row-key="(record) => record.id"
|
||||
bordered
|
||||
:expand-row-by-click="true"
|
||||
:pagination="false"
|
||||
size="small"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'listenerType'">
|
||||
{{ listenerlabel(record.listenerType) }}
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<el-popconfirm title="确定要删除此监听吗?" @confirm="deleteListener(record)" placement="topRight">
|
||||
<el-button type="link" danger size="small">删除</el-button>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</template>
|
||||
</el-table>
|
||||
<el-dialog v-model="modalVisible" title="新增" @ok="handleOk" @cancel="handleCancel">
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
|
||||
<el-form-item label="监听类型:" name="listenerType">
|
||||
<el-select v-model:value="formData.listenerType" placeholder="请选择类型" :options="listenerTypeOptions" @change="listenerType" />
|
||||
</el-form-item>
|
||||
<el-form-item label="JAVA监听器:" name="javaClass">
|
||||
<el-select v-model:value="formData.javaClass" placeholder="请选择JAVA监听器" :options="listenerValueArray" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup name="PropListenerInfo">
|
||||
import { required } from '@/utils/formRules'
|
||||
import tool from '@/utils/tool'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const table = ref()
|
||||
const listenerValueArray = ref([])
|
||||
const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'listenerType',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: 'JAVA监听器',
|
||||
dataIndex: 'javaClass',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: 80
|
||||
}
|
||||
]
|
||||
const dataSource = ref([])
|
||||
const props = defineProps(['listenerValue', 'defaultListenerList', 'listenerValueArray', 'executionListenerSelectorForCustomEventArray', 'listenerType'])
|
||||
if (props.listenerValue && props.listenerValue.length > 0) {
|
||||
// 转换到列表
|
||||
props.listenerValue.forEach((item) => {
|
||||
const obj = {
|
||||
listenerType: item.key,
|
||||
javaClass: item.value,
|
||||
id: tool.snowyUuid()
|
||||
}
|
||||
dataSource.value.push(obj)
|
||||
})
|
||||
}
|
||||
// 加载
|
||||
if (props.listenerValueArray) {
|
||||
listenerValueArray.value = props.listenerValueArray
|
||||
}
|
||||
// 新增或编辑
|
||||
const addEditListener = () => {
|
||||
modalVisible.value = true
|
||||
}
|
||||
// 删除
|
||||
const deleteListener = (record) => {
|
||||
// 算了,什么也不说了,留下能用的
|
||||
dataSource.value = dataSource.value.filter((item) => item.id !== record.id)
|
||||
}
|
||||
// 转换监听数据
|
||||
const selectedListenerList = () => {
|
||||
return dataSource.value.map((item) => {
|
||||
return {
|
||||
key: item.listenerType,
|
||||
value: item.javaClass,
|
||||
label: listenerlabel(item.listenerType)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 通过key获得中文label
|
||||
const listenerlabel = (key) => {
|
||||
if (!props.defaultListenerList) {
|
||||
return '请重新打开'
|
||||
}
|
||||
return props.defaultListenerList.find((f) => f.key === key).label
|
||||
}
|
||||
// 小对话框
|
||||
const modalVisible = ref(false)
|
||||
const formRef = ref()
|
||||
const formData = ref({})
|
||||
const formRules = {
|
||||
listenerType: [required('请选择监听类型')],
|
||||
javaClass: [required('请选择JAVA监听器')]
|
||||
}
|
||||
const listenerTypeOptions = props.defaultListenerList.map((item) => {
|
||||
return {
|
||||
label: item.label,
|
||||
value: item.key
|
||||
}
|
||||
})
|
||||
// 选择器类型监听
|
||||
const listenerType = (value) => {
|
||||
// 只有在全局情况下,才会去加载这些自定义的类
|
||||
if (props.listenerType === 'global') {
|
||||
formData.value.javaClass = undefined
|
||||
listenerValueArray.value = []
|
||||
// 拒绝、终止、撤回、删除 这些类型的时候,加载自定义的到选择列表
|
||||
if (value === 'REJECT' || value === 'CLOSE' || value === 'REVOKE' || value === 'DELETE') {
|
||||
if (props.executionListenerSelectorForCustomEventArray) {
|
||||
listenerValueArray.value = props.executionListenerSelectorForCustomEventArray
|
||||
}
|
||||
} else {
|
||||
if (props.listenerValueArray) {
|
||||
listenerValueArray.value = props.listenerValueArray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const handleOk = () => {
|
||||
formRef.value.validate().then(() => {
|
||||
formData.value.id = tool.snowyUuid()
|
||||
dataSource.value.push(formData.value)
|
||||
handleCancel()
|
||||
})
|
||||
}
|
||||
const handleCancel = () => {
|
||||
formData.value = {}
|
||||
modalVisible.value = false
|
||||
}
|
||||
// 抛出方法,让上个界面使用
|
||||
defineExpose({
|
||||
selectedListenerList
|
||||
})
|
||||
</script>
|
||||
@@ -1,7 +0,0 @@
|
||||
<template></template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PropNoticeInfo'
|
||||
}
|
||||
</script>
|
||||
@@ -1,48 +0,0 @@
|
||||
<template>
|
||||
<el-tag v-for="tag in tagList()">{{ tag }}</el-tag
|
||||
><!-- 花里胡哨的颜色先去掉,用的时候拿到旁边就行 :color="randomColor()"-->
|
||||
</template>
|
||||
|
||||
<script setup name="propTag">
|
||||
// 颜色列表
|
||||
const colorList = ['pink', 'red', 'orange', 'green', 'cyan', 'blue', 'purple']
|
||||
// 获取随机颜色
|
||||
const randomColor = () => {
|
||||
return colorList[randomNum(0, colorList.length - 1)]
|
||||
}
|
||||
// 获取minNum到maxNum内的随机数
|
||||
const randomNum = (minNum, maxNum) => {
|
||||
switch (arguments.length) {
|
||||
case 1:
|
||||
return parseInt(Math.random() * minNum + 1, 10)
|
||||
break
|
||||
case 2:
|
||||
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10)
|
||||
break
|
||||
default:
|
||||
return 0
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const props = defineProps(['tagList'])
|
||||
// 将配置的参数转换为数组,显示tag标签
|
||||
const tagList = () => {
|
||||
const tag = props.tagList
|
||||
if (tag === undefined) {
|
||||
return []
|
||||
} else {
|
||||
if (!tag.label) {
|
||||
return
|
||||
}
|
||||
const str = tag.label
|
||||
let resultArray = []
|
||||
if (str.indexOf(',') !== -1) {
|
||||
resultArray = str.split(',')
|
||||
} else {
|
||||
resultArray.push(str)
|
||||
}
|
||||
return resultArray
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,221 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-input
|
||||
ref="smsInput"
|
||||
type="textarea"
|
||||
v-model:value="smsContent"
|
||||
:auto-size="{ minRows: 3, maxRows: 6 }"
|
||||
placeholder="请输入内容"
|
||||
@input.native="smsInput"
|
||||
@blur="inputBlur"
|
||||
@focus="focusHandler"
|
||||
@click.native="focusHandler"
|
||||
@keydown.up.down.left.right.native="focusHandler"
|
||||
@select.native="selectHandler"
|
||||
></el-input>
|
||||
<el-dropdown>
|
||||
<template #overlay>
|
||||
<el-menu>
|
||||
<el-menu-item
|
||||
v-for="fields in fieldInfoLisNew"
|
||||
:key="fields.value"
|
||||
:value="fields.value"
|
||||
:disabled="fields.value === 'disabled'"
|
||||
@click="insertFields(fields)"
|
||||
>{{ fields.label }}</el-menu-item
|
||||
>
|
||||
</el-menu>
|
||||
</template>
|
||||
<el-button size="small" type="primary" style="float: right; margin-top: -35px; margin-right: 10px">
|
||||
置入字段
|
||||
<!-- <DownOutlined /> -->
|
||||
</el-button>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
export default {
|
||||
name: 'TemplateGenerator',
|
||||
props: {
|
||||
// 表单数据
|
||||
fieldInfoLis: { type: Array, default: () => [] },
|
||||
// v-model数据
|
||||
inputValue: { type: String, default: () => '' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
smsContent: '',
|
||||
inputFocus: null,
|
||||
fieldInfoLisNew: [],
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
// 这里回显数据,并做转换
|
||||
mounted() {
|
||||
this.fieldInfoLisNew = [...JSON.parse(JSON.stringify(config.templateDefaultFields)), ...this.fieldInfoLis]
|
||||
this.smsContent = this.setInput(this.inputValue)
|
||||
},
|
||||
methods: {
|
||||
// 入数据转换
|
||||
setInput(value) {
|
||||
this.fieldInfoLisNew.forEach((field) => {
|
||||
let temp = ''
|
||||
if (value.indexOf(field.value) > -1) {
|
||||
temp = value.replace(new RegExp(field.value, 'g'), '[' + field.label + ']')
|
||||
}
|
||||
if (temp !== '') {
|
||||
value = temp
|
||||
}
|
||||
})
|
||||
return value
|
||||
},
|
||||
// 选中置入的
|
||||
insertFields(fields) {
|
||||
this.insertStr('[' + fields.label + ']')
|
||||
},
|
||||
// 插入元素
|
||||
insertStr(str) {
|
||||
let before = this.smsContent.slice(0, this.inputFocus)
|
||||
let after = this.smsContent.slice(this.inputFocus, this.smsContent.length)
|
||||
this.inputFocus = this.inputFocus + str.length
|
||||
this.smsContent = before + str + after
|
||||
this.$emit('update:inputValue', this.outValue(this.smsContent))
|
||||
},
|
||||
// 保存光标位置
|
||||
inputBlur(e) {
|
||||
this.inputFocus = e.target.selectionStart
|
||||
this.visible = false
|
||||
},
|
||||
// 删除元素剩余部分
|
||||
smsInput(e) {
|
||||
//deleteContentBackward==退格键 deleteContentForward==del键
|
||||
if (e.inputType === 'deleteContentBackward' || e.inputType === 'deleteContentForward') {
|
||||
let beforeIndex = 0
|
||||
let afterIndex = 0
|
||||
// 光标位置往前
|
||||
for (let i = e.target.selectionStart - 1; i >= 0; i--) {
|
||||
if (this.smsContent[i] === '[') {
|
||||
beforeIndex = i
|
||||
afterIndex = e.target.selectionStart
|
||||
break
|
||||
}
|
||||
if (this.smsContent[i] === ']') {
|
||||
break
|
||||
}
|
||||
}
|
||||
// 光标位置往后
|
||||
for (let i = e.target.selectionStart; i < this.smsContent.length; i++) {
|
||||
if (this.smsContent[i] === ']') {
|
||||
afterIndex = i + 1
|
||||
beforeIndex = e.target.selectionStart
|
||||
break
|
||||
}
|
||||
if (this.smsContent[i] === '[') {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (beforeIndex === 0 && afterIndex === 0) {
|
||||
this.$emit('update:inputValue', this.outValue(this.smsContent))
|
||||
return
|
||||
}
|
||||
let beforeStr = this.smsContent.slice(0, beforeIndex)
|
||||
let afterStr = this.smsContent.slice(afterIndex)
|
||||
this.smsContent = beforeStr + afterStr
|
||||
this.inputFocus = beforeStr.length
|
||||
this.$nextTick(() => {
|
||||
this.changeFocus(e.target, this.inputFocus, this.inputFocus)
|
||||
})
|
||||
}
|
||||
// this.$emit("smsText", this.smsContent);
|
||||
|
||||
this.$emit('update:inputValue', this.outValue(this.smsContent))
|
||||
},
|
||||
// 选择元素剩余部分
|
||||
selectHandler(e) {
|
||||
// 光标开始位置往前
|
||||
for (let i = e.target.selectionStart - 1; i >= 0; i--) {
|
||||
if (this.smsContent[i] === '[') {
|
||||
this.changeFocus(e.target, i, e.target.selectionEnd)
|
||||
break
|
||||
}
|
||||
if (this.smsContent[i] === ']') {
|
||||
break
|
||||
}
|
||||
}
|
||||
// 光标结束位置往后
|
||||
for (let i = e.target.selectionEnd; i < this.smsContent.length; i++) {
|
||||
if (this.smsContent[i] === ']') {
|
||||
this.changeFocus(e.target, e.target.selectionStart, i + 1)
|
||||
break
|
||||
}
|
||||
if (this.smsContent[i] === '[') {
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
// 焦点跳出元素内
|
||||
focusHandler(e) {
|
||||
setTimeout(() => {
|
||||
let selStart = e.target.selectionStart
|
||||
let beforeArrLength = this.smsContent.slice(0, selStart).split('[').length
|
||||
let afterArrLength = this.smsContent.slice(0, selStart).split(']').length
|
||||
//根据'['和']'生成两个数组 判断数组长度 是否相等 不相等就不成对就移动光标
|
||||
if (beforeArrLength !== afterArrLength) {
|
||||
let pos = this.smsContent.indexOf(']', selStart) + 1
|
||||
if (beforeArrLength > afterArrLength && e.code == 'ArrowLeft') {
|
||||
//按下按键左箭头
|
||||
pos = this.smsContent.lastIndexOf('[', selStart)
|
||||
}
|
||||
this.changeFocus(e.target, pos, pos)
|
||||
}
|
||||
}, 100)
|
||||
},
|
||||
// 修改光标位置
|
||||
changeFocus(target, start, end) {
|
||||
let range,
|
||||
el = target
|
||||
if (el.setSelectionRange) {
|
||||
el.setSelectionRange(start, end)
|
||||
} else {
|
||||
range = el.createTextRange()
|
||||
range.collapse(false)
|
||||
range.select()
|
||||
}
|
||||
},
|
||||
// 出口数据转换
|
||||
outValue(result) {
|
||||
let index = result.indexOf('[')
|
||||
let num = 0
|
||||
while (index !== -1) {
|
||||
num++
|
||||
index = result.indexOf('[', index + 1)
|
||||
}
|
||||
if (num > 0) {
|
||||
for (let i = 1; i <= num; i++) {
|
||||
let temp = ''
|
||||
this.fieldInfoLisNew.forEach((field) => {
|
||||
if (result.indexOf('[' + field.label + ']') > -1) {
|
||||
temp = result.replace('[' + field.label + ']', field.value)
|
||||
result = temp
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.insert-list p {
|
||||
text-align: center;
|
||||
}
|
||||
.insert-list div {
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
@@ -1,53 +0,0 @@
|
||||
templateGenerator
|
||||
====
|
||||
|
||||
> 模板编辑器
|
||||
> eg: 主要用于工作流中的各种模板,也可作为通知的
|
||||
|
||||
该组件由 [俞宝山](https://www.xiaonuo.vip) 封装
|
||||
|
||||
|
||||
### 使用方式
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<template-generator ref="templateGenerator" :fieldInfoLis="fieldInfoLis" v-model:inputValue="inputValue"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 初始化我们调用这个组件的dom名称,Vue3 setup语法糖的写法,是这样的哦!
|
||||
const templateGenerator = ref(null)
|
||||
|
||||
// 这个数据就是下面说的,置入字段下拉中选择的参数
|
||||
const fieldInfoLis = ref(
|
||||
[
|
||||
{
|
||||
label: '名称',
|
||||
value: 'name',
|
||||
},
|
||||
{
|
||||
label: '这有是啥',
|
||||
value: 'what',
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
// 组件回显数据
|
||||
const inputValue = ref('发起人name在几点积分通知了,内容为:what')
|
||||
|
||||
// 使用的界面调用这个方法,获得组件中选好的数据
|
||||
const selectedFieldList = () => {
|
||||
console.log('result data :' + JSON.stringify(templateGenerator.getValue()))
|
||||
}
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
### 数据
|
||||
|
||||
| 名称 | 说明 | 类型 | 默认值 |
|
||||
| ---------- | ------------------------------------------------------------------------------------ | ------ | ------ |
|
||||
| fieldInfoLis | 表单数据,下拉框中要选择的,示例:`fieldInfoLis` | Array | [] |
|
||||
| inputValue | 组件中要回显的数据,示例:`inputValue ` | String | '' |
|
||||
@@ -1,398 +0,0 @@
|
||||
<!-- 抄送人组件 -->
|
||||
<template>
|
||||
<div class="node-wrap">
|
||||
<div class="node-wrap-box" @click="show">
|
||||
<div class="title" style="background: #3296fa">
|
||||
<send-outlined class="icon" />
|
||||
<span>{{ childNode.title }}</span>
|
||||
<!-- <close-outlined class="close" /> -->
|
||||
<el-icon>
|
||||
<CloseBold @click="delNode()" />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span v-if="toText(childNode)">{{ toText(childNode) }}</span>
|
||||
<span v-else class="placeholder">请选择人员</span>
|
||||
</div>
|
||||
</div>
|
||||
<addNode v-model="childNode.childNode"></addNode>
|
||||
<formContainer
|
||||
v-model="drawer"
|
||||
:visibile="drawer"
|
||||
:destroy-on-close="true"
|
||||
:body-style="{ 'padding-top': '0px' }"
|
||||
>
|
||||
<template #title>
|
||||
<div class="node-wrap-drawer__title">
|
||||
<label v-if="!isEditTitle" @click="editTitle">
|
||||
{{ form.title }}
|
||||
<el-icon>
|
||||
<EditPen />
|
||||
</el-icon>
|
||||
<!-- <edit-outlined class="node-wrap-drawer-title-edit" /> -->
|
||||
</label>
|
||||
<el-input
|
||||
v-if="isEditTitle"
|
||||
ref="nodeTitle"
|
||||
v-model:value="form.title"
|
||||
allow-clear
|
||||
@blur="saveTitle"
|
||||
@keyup.enter="saveTitle"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div class="tab_container">
|
||||
<el-tabs v-model="activeKey">
|
||||
<el-tab-pane name="1" label="抄送配置" lazy>
|
||||
<el-form layout="vertical" :model="userTypeForm">
|
||||
<div v-show="nodeLegal" style="margin-bottom: 10px">
|
||||
<div class="please_choose">
|
||||
<p>请选择抄送人员!</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<navTitle><template #nav_name>选择要抄送的人员</template></navTitle>
|
||||
</div>
|
||||
<!-- 选择抄送人员 -->
|
||||
<el-radio-group v-model="userSelectionType" @input="changeRadio" style="width: 100%">
|
||||
<el-radio
|
||||
v-for="(item, index) in userSelectionTypeList"
|
||||
:value="item.value"
|
||||
:key="index"
|
||||
>
|
||||
<!-- @click="selectionClick(item.value)" -->
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-form-item v-if="userSelectionType === 'USER'">
|
||||
<el-button class="mt-2" type="primary" size="small" @click="openSelector">
|
||||
<template #icon>
|
||||
<el-icon>
|
||||
<Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
选择
|
||||
</el-button>
|
||||
<p />
|
||||
<prop-tag :tag-list="getTagList('USER')" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="recordData.formType === 'DESIGN' && userSelectionType === 'FORM_USER'">
|
||||
<div class="mt-2">
|
||||
<el-button type="primary" @click="openSelector" size="small">
|
||||
<template #icon>
|
||||
<el-icon>
|
||||
<Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
选择
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<prop-tag
|
||||
v-if="
|
||||
form.properties.participateInfo.length > 0 &&
|
||||
form.properties.participateInfo[0].value !== ''
|
||||
"
|
||||
:tag-list="form.properties.participateInfo[0]"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- 选择人员变量 -->
|
||||
<el-form-item
|
||||
class="mt-2"
|
||||
v-if="userSelectionType === 'FORM_USER'"
|
||||
name="formUser"
|
||||
:rules="[{ required: true, message: '请输入人员变量' }]">
|
||||
<!-- recordData.formType === 'DEFINE' && -->
|
||||
<!-- <template #label> -->
|
||||
<!-- <el-tooltip>
|
||||
<template #title></template>
|
||||
<question-circle-outlined />
|
||||
人员变量:
|
||||
</el-tooltip> -->
|
||||
<!-- </template> -->
|
||||
<el-tooltip
|
||||
content="单个字段可以采用:字段名,多个采用:字段名1,字段名2,字段名3"
|
||||
placement="top-start"
|
||||
>
|
||||
<span class="user_icon">?</span>
|
||||
<span style="width: 100px;display:block;float: left;">
|
||||
</span>人员变量:
|
||||
</el-tooltip>
|
||||
<el-input
|
||||
v-model="userTypeForm.formUser"
|
||||
clearable
|
||||
@input="customFormUser"
|
||||
@keyup.enter="customFormUser"
|
||||
placeholder="请输入人员变量"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="2" label="执行监听" lazy>
|
||||
<prop-listener-info
|
||||
ref="propExecutionListenerInfoRef"
|
||||
v-if="form && form.properties && form.properties.executionListenerInfo"
|
||||
:listener-value="form.properties.executionListenerInfo"
|
||||
:default-listener-list="executionListenerInfo"
|
||||
:listener-value-array="executionListenerArray"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button type="primary" style="margin-right: 8px" @click="save">保存</el-button>
|
||||
<el-button @click="drawer = false">取消</el-button>
|
||||
</template>
|
||||
</formContainer>
|
||||
<form-user-selector ref="formUserSelectorRef" :form-field-list="formFieldListValue" @click="userCallBack" />
|
||||
<user-selector-plus
|
||||
ref="userselectorPlus"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:user-page-api="selectorApiFunction.userPageApi"
|
||||
:checked-user-list-api="selectorApiFunction.checkedUserListApi"
|
||||
:datel-is-converter-flw="true"
|
||||
@onBack="userCallBack"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addNode from './addNode.vue'
|
||||
import userSelectorPlus from '@/components/Selector/userSelectorPlus.vue'
|
||||
import FormUserSelector from './prop/formUserSelector.vue'
|
||||
import propTag from './prop/propTag.vue'
|
||||
import { cloneDeep, isEmpty } from 'lodash-es'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import PropListenerInfo from './prop/propListenerInfo.vue'
|
||||
import { CloseBold, EditPen, Search ,InfoFilled} from '@element-plus/icons-vue'
|
||||
import formContainer from '@/components/formContainer/index.vue'
|
||||
import navTitle from '../components/navTitle.vue'
|
||||
export default {
|
||||
components: {
|
||||
FormUserSelector,
|
||||
addNode,
|
||||
userSelectorPlus,
|
||||
propTag,
|
||||
PropListenerInfo,
|
||||
formContainer,
|
||||
navTitle,
|
||||
CloseBold,
|
||||
EditPen,
|
||||
Search,
|
||||
InfoFilled
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
selectorApiFunction: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {},
|
||||
drawer: false,
|
||||
isEditTitle: false,
|
||||
activeKey: '1',
|
||||
form: {},
|
||||
nodeLegal: false,
|
||||
userTypeForm: {},
|
||||
executionListenerInfo: cloneDeep(config.listener.serviceTaskExecutionListenerInfo),
|
||||
// 用户选择类型
|
||||
userSelectionType: '',
|
||||
userSelectionTypeList: cloneDeep(config.serviceTaskConfig.userSelectionTypeList)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.form = {}
|
||||
this.form = cloneDeep(this.childNode)
|
||||
this.drawer = true
|
||||
if (!isEmpty(this.form.properties.participateInfo)) {
|
||||
this.userSelectionType = this.form.properties.participateInfo[0].key
|
||||
// 如果包含表单内的人
|
||||
const formUserObj = this.form.properties.participateInfo.find(f => f.key === 'FORM_USER')
|
||||
if (formUserObj) {
|
||||
this.userTypeForm.formUser = formUserObj.value
|
||||
}
|
||||
} else {
|
||||
this.userSelectionType = 'USER'
|
||||
this.userTypeForm = {}
|
||||
this.nodeLegal = true
|
||||
}
|
||||
},
|
||||
editTitle() {
|
||||
this.isEditTitle = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.nodeTitle.focus()
|
||||
})
|
||||
},
|
||||
saveTitle() {
|
||||
this.isEditTitle = false
|
||||
},
|
||||
save() {
|
||||
if (isEmpty(this.nodeLegal)) {
|
||||
this.form.properties.executionListenerInfo =
|
||||
this.$refs.propExecutionListenerInfoRef.selectedListenerList()
|
||||
this.form.dataLegal = true
|
||||
this.$emit('update:modelValue', this.form)
|
||||
this.drawer = false
|
||||
}
|
||||
},
|
||||
delNode() {
|
||||
this.$emit('update:modelValue', this.childNode.childNode)
|
||||
},
|
||||
selectHandle(data) {
|
||||
this.$refs.userselectorPlus.showUserPlusModal(data)
|
||||
},
|
||||
// 选择器回调
|
||||
userCallBack(value) {
|
||||
if (isEmpty(value.label)) {
|
||||
this.nodeLegal = true
|
||||
} else {
|
||||
this.nodeLegal = false
|
||||
}
|
||||
if (this.userSelectionType === 'USER') {
|
||||
this.form.properties.participateInfo[0] = value
|
||||
} else if (this.userSelectionType === 'FORM_USER') {
|
||||
this.form.properties.participateInfo = [
|
||||
{
|
||||
key: 'FORM_USER',
|
||||
label: this.userSelectionTypeList.filter(item => item.value === 'FORM_USER')[0].label,
|
||||
value: value.model
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
// 获取tag标签的内容
|
||||
getTagList(type) {
|
||||
const participateInfo = this.form.properties.participateInfo
|
||||
if (participateInfo.length > 0) {
|
||||
const obj = participateInfo.find(item => item.key === type)
|
||||
if (isEmpty(obj.label)) {
|
||||
return undefined
|
||||
} else {
|
||||
return obj
|
||||
}
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
},
|
||||
changeRadio() {
|
||||
console.log(this.userSelectionType, '99999')
|
||||
this.form.properties.participateInfo = []
|
||||
this.nodeLegal = true
|
||||
},
|
||||
// 选择抄送人员类型
|
||||
selectionClick(value) {
|
||||
this.form.properties.participateInfo = []
|
||||
this.userSelectionType = value
|
||||
this.nodeLegal = true
|
||||
},
|
||||
// 打开选择器
|
||||
openSelector() {
|
||||
let data = this.form.properties.participateInfo
|
||||
if (this.userSelectionType === 'USER') {
|
||||
this.$refs.userselectorPlus.showUserPlusModal(data)
|
||||
} else if (this.userSelectionType === 'FORM_USER') {
|
||||
this.$refs.formUserSelectorRef.showFormUserModal(data[0])
|
||||
}
|
||||
},
|
||||
// 监听自定义表单人员输入
|
||||
customFormUser() {
|
||||
// console.log(this.userTypeForm.formUser,"0000000");
|
||||
if (this.userTypeForm.formUser) {
|
||||
// this.form.properties.participateInfo = [
|
||||
// {
|
||||
// key: 'FORM_USER',
|
||||
// label: '表单内的人',
|
||||
// value: this.userTypeForm.formUser
|
||||
// }
|
||||
// ]
|
||||
this.nodeLegal = false
|
||||
} else {
|
||||
this.nodeLegal = true
|
||||
}
|
||||
},
|
||||
toText(childNode) {
|
||||
if (!isEmpty(childNode)) {
|
||||
const participateInfo = childNode.properties.participateInfo
|
||||
if (participateInfo.length > 0) {
|
||||
let resultArray = []
|
||||
if (participateInfo[0].label.indexOf(',') !== -1) {
|
||||
resultArray = participateInfo[0].label.split(',')
|
||||
} else {
|
||||
resultArray.push(participateInfo[0].label)
|
||||
}
|
||||
return resultArray.toString()
|
||||
} else {
|
||||
// return '未选择抄送人';
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.title {
|
||||
position: relative;
|
||||
.el-icon {
|
||||
float: right;
|
||||
position: absolute;
|
||||
right: 13px;
|
||||
top: 6px;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.node-wrap-box:hover {
|
||||
.el-icon {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.node-wrap-drawer__title {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.el-tab_container {
|
||||
width: 100%;
|
||||
}
|
||||
.please_choose {
|
||||
width: 96%;
|
||||
height: 40px;
|
||||
margin-top: 20px;
|
||||
background-color: #fff0f0;
|
||||
border: 2px solid #ffa39e;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 8px 15px;
|
||||
p {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
.el-radio-group {
|
||||
margin: 10px 0;
|
||||
}
|
||||
.user_icon{
|
||||
display: block;
|
||||
width:18px;
|
||||
height: 18px;
|
||||
border:1px solid #000;
|
||||
border-radius:50%;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,48 +0,0 @@
|
||||
<template>
|
||||
<div class="node-wrap" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {},
|
||||
// drawer: false,
|
||||
isEditTitle: false,
|
||||
form: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.form = JSON.parse(JSON.stringify(this.childNode))
|
||||
this.isEditTitle = false
|
||||
this.drawer = true
|
||||
},
|
||||
// editTitle() {
|
||||
// this.isEditTitle = true;
|
||||
// this.$nextTick(() => {
|
||||
// this.$refs.nodeTitle.focus();
|
||||
// });
|
||||
// },
|
||||
// saveTitle() {
|
||||
// this.isEditTitle = false;
|
||||
// },
|
||||
save() {
|
||||
this.form.id = this.$TOOL.snowyUuid()
|
||||
this.$emit('update:modelValue', this.form)
|
||||
this.drawer = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,251 +0,0 @@
|
||||
<template>
|
||||
<div class="node-wrap">
|
||||
<div class="node-wrap-box start-node" @click="show">
|
||||
<div class="title" style="background: #576a95">
|
||||
<!-- <user-outlined class="icon" /> -->
|
||||
<span>{{ childNode.title }}777111</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<span v-if="toText(childNode)">{{ toText(childNode) }}</span>
|
||||
<span v-else class="placeholder">请配置字段与按钮</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 添加节点 -->
|
||||
<addNode v-model="childNode.childNode" />
|
||||
<form_container v-model="drawer" :destroy-on-close="true" :width="700" :body-style="{ 'padding-top': '0px' }">
|
||||
<template #title>
|
||||
<div class="node-wrap-drawer__title">
|
||||
<label v-if="!isEditTitle" @click="editTitle">
|
||||
{{ form.title }}
|
||||
<!-- <edit-outlined class="node-wrap-drawer-title-edit" /> -->
|
||||
</label>
|
||||
<el-input
|
||||
v-if="isEditTitle"
|
||||
ref="nodeTitle"
|
||||
v-model:value="form.title"
|
||||
allow-clear
|
||||
@blur="saveTitle"
|
||||
@keyup.enter="saveTitle"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<el-container>
|
||||
<el-tabs v-model:activeKey="activeKey">
|
||||
<el-tab-pane name="1" label="按钮配置" lazy>
|
||||
<prop-button-info
|
||||
ref="propButtonInfo"
|
||||
:button-info="selectedButtonInfo"
|
||||
:show-button="startTaskDefaultButtonkey"
|
||||
:no-checked="startTaskNoCheckedButtonkey"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="2" label="字段配置" lazy v-if="recordData.formType === 'DESIGN'">
|
||||
<prop-field-info
|
||||
ref="propFieldInfo"
|
||||
:field-info="fieldInfo"
|
||||
:form-field-list-value="formFieldListValue"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="3" label="表单配置" lazy v-else>
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">参与者可以填写的表单</span>
|
||||
</div>
|
||||
<el-form ref="startTaskFormRef" :model="formData" layout="vertical">
|
||||
<el-form-item
|
||||
label="节点表单"
|
||||
name="FORM_URL"
|
||||
:rules="[{ required: true, message: '请输入节点表单组件地址' }]"
|
||||
>
|
||||
<el-input
|
||||
v-model:value="formData.FORM_URL"
|
||||
addon-before="src/views/flw/customform/"
|
||||
addon-after=".vue"
|
||||
placeholder="请输入节点表单组件地址"
|
||||
allow-clear
|
||||
>
|
||||
<template #suffix>
|
||||
<el-button
|
||||
v-if="formData.FORM_URL"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="$refs.previewCustomFormRef.onOpen(formData.FORM_URL)"
|
||||
>
|
||||
预览
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="移动端节点表单"
|
||||
name="MOBILE_FORM_URL"
|
||||
:rules="[{ required: true, message: '请输入移动端节点表单组件地址' }]"
|
||||
>
|
||||
<el-input
|
||||
v-model:value="formData.MOBILE_FORM_URL"
|
||||
addon-before="pages/flw/customform/"
|
||||
addon-after=".vue"
|
||||
placeholder="请输入移动端节点表单组件地址"
|
||||
allow-clear
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="4" label="执行监听" lazy>
|
||||
<prop-listener-info
|
||||
v-if="form.properties && form.properties.executionListenerInfo"
|
||||
ref="propExecutionListenerInfoRef"
|
||||
:listener-value="form.properties.executionListenerInfo"
|
||||
:default-listener-list="executionListenerInfo"
|
||||
:listener-value-array="executionListenerArray"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="5" label="节点监听" lazy>
|
||||
<prop-listener-info
|
||||
ref="propTaskListenerInfoRef"
|
||||
v-if="form.properties && form.properties.taskListenerInfo"
|
||||
:listener-value="form.properties.taskListenerInfo"
|
||||
:default-listener-list="taskListenerInfo"
|
||||
:listener-value-array="taskListenerArray"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-container>
|
||||
<template #footer>
|
||||
<el-button type="primary" style="margin-right: 8px" @click="save">保存</el-button>
|
||||
<el-button @click="drawer = false">取消111</el-button>
|
||||
</template>
|
||||
</form_container>
|
||||
<preview-custom-form ref="previewCustomFormRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import form_container from '../../../components/formContainer/index.vue'
|
||||
import addNode from './addNode.vue'
|
||||
import propButtonInfo from './prop/propButtonInfo.vue'
|
||||
import propFieldInfo from './prop/propFieldInfo.vue'
|
||||
import propListenerInfo from './prop/propListenerInfo.vue'
|
||||
import PreviewCustomForm from '@/components/XnWorkflow/nodes/common/previewCustomForm.vue'
|
||||
import { add } from 'xe-utils'
|
||||
export default {
|
||||
components: {
|
||||
addNode,
|
||||
propButtonInfo,
|
||||
propFieldInfo,
|
||||
propListenerInfo,
|
||||
PreviewCustomForm,
|
||||
form_container
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
processConfigInfo: { type: Object, default: () => {} },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
taskListenerArray: { type: Array, default: () => [] }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
childNode: {},
|
||||
drawer: false,
|
||||
isEditTitle: false,
|
||||
form: {},
|
||||
activeKey: '1',
|
||||
selectedButtonInfo: [],
|
||||
executionListenerInfo: cloneDeep(config.listener.startTaskExecutionListenerInfo),
|
||||
taskListenerInfo: cloneDeep(config.listener.userTaskTaskListenerInfo),
|
||||
startTaskDefaultButtonkey: cloneDeep(config.button.startTaskDefaultButtonkey),
|
||||
startTaskNoCheckedButtonkey: cloneDeep(config.button.startTaskNoCheckedButtonkey),
|
||||
fieldInfo: [],
|
||||
formData: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.form = cloneDeep(this.childNode)
|
||||
this.isEditTitle = false
|
||||
this.drawer = true
|
||||
this.selectedButtonInfo =
|
||||
this.form && this.form.propertie && this.form.properties.buttonInfo
|
||||
? this.form.properties.buttonInfo
|
||||
: {}
|
||||
this.fieldInfo = this.form.properties.fieldInfo
|
||||
// 初始化自定义表单字段值
|
||||
this.initFormInfo()
|
||||
},
|
||||
initFormInfo() {
|
||||
const processConfigInfo = cloneDeep(this.processConfigInfo)
|
||||
if (!this.form.properties.formInfo.find(f => f.key === 'FORM_URL')) {
|
||||
this.formData.FORM_URL = processConfigInfo.processStartTaskFormUrl
|
||||
} else {
|
||||
this.formData.FORM_URL = this.form.properties.formInfo.find(f => f.key === 'FORM_URL').value
|
||||
}
|
||||
if (!this.form.properties.formInfo.find(f => f.key === 'MOBILE_FORM_URL')) {
|
||||
this.formData.MOBILE_FORM_URL = processConfigInfo.processStartTaskMobileFormUrl
|
||||
} else {
|
||||
this.formData.MOBILE_FORM_URL = this.form.properties.formInfo.find(
|
||||
f => f.key === 'MOBILE_FORM_URL'
|
||||
).value
|
||||
}
|
||||
},
|
||||
editTitle() {
|
||||
this.isEditTitle = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.nodeTitle.focus()
|
||||
})
|
||||
},
|
||||
saveTitle() {
|
||||
this.isEditTitle = false
|
||||
},
|
||||
save() {
|
||||
this.form.id = this.$TOOL.snowyUuid()
|
||||
this.form.properties.buttonInfo = this.$refs.propButtonInfo.selectedButtonKeyList()
|
||||
this.form.properties.executionListenerInfo = this.$refs.propExecutionListenerInfoRef.selectedListenerList()
|
||||
this.form.properties.taskListenerInfo = this.$refs.propTaskListenerInfoRef.selectedListenerList()
|
||||
if (this.recordData.formType === 'DESIGN') {
|
||||
this.form.properties.fieldInfo = this.$refs.propFieldInfo.selectedFieldList()
|
||||
this.form.dataLegal = true
|
||||
this.$emit('update:modelValue', this.form)
|
||||
this.drawer = false
|
||||
} else {
|
||||
this.$refs.startTaskFormRef
|
||||
.validate()
|
||||
.then(values => {
|
||||
this.form.dataLegal = true
|
||||
this.form.properties.formInfo = cloneDeep(config.nodeModel.formInfo)
|
||||
this.form.properties.formInfo.find(f => f.key === 'FORM_URL').value = values.FORM_URL
|
||||
this.form.properties.formInfo.find(f => f.key === 'MOBILE_FORM_URL').value =
|
||||
values.MOBILE_FORM_URL
|
||||
this.$emit('update:modelValue', this.form)
|
||||
this.drawer = false
|
||||
})
|
||||
.catch(err => {})
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
toText(childNode) {
|
||||
if (childNode.dataLegal) {
|
||||
return '系统自动配置参与人'
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.font-span {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,790 +0,0 @@
|
||||
<template>
|
||||
<div class="node-wrap">
|
||||
<div class="node-wrap-box" @click="show">
|
||||
<div class="title" style="background: #ff943e">
|
||||
<user-outlined class="icon" />
|
||||
<span>{{ childNode.title }}</span>
|
||||
<close-outlined class="close" @click.stop="delNode()" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<span v-if="toText(childNode)">{{ toText(childNode) }}</span>
|
||||
<span v-else class="placeholder">请选择</span>
|
||||
</div>
|
||||
</div>
|
||||
<addNode v-model="childNode.childNode" />
|
||||
|
||||
<!-- 抽屉 -->
|
||||
<formContainer
|
||||
v-model:visible="drawer"
|
||||
:destroy-on-close="true"
|
||||
:width="700"
|
||||
:body-style="{ 'padding-top': '0px' }"
|
||||
>
|
||||
<template #title>
|
||||
<div class="node-wrap-drawer__title">
|
||||
<label v-if="!isEditTitle" @click="editTitle"
|
||||
>{{ form.title }}<edit-outlined class="node-wrap-drawer-title-edit"
|
||||
/></label>
|
||||
<el-input
|
||||
v-if="isEditTitle"
|
||||
ref="nodeTitle"
|
||||
v-model="form.title"
|
||||
allow-clear
|
||||
@blur="saveTitle"
|
||||
@keyup.enter="saveTitle"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<el-container>
|
||||
{{ activeKey }}
|
||||
<el-tabs v-model="activeKey">
|
||||
<el-tab-pane name="1" label="人员配置" lazy>
|
||||
<div v-show="!nodeLegal" style="margin-bottom: 10px">
|
||||
<el-alert message="请配置节点相关人员!" type="error" />
|
||||
</div>
|
||||
<el-form layout="vertical" :model="userTypeForm" ref="userTypeFormRef">
|
||||
<div class="mb-3">
|
||||
<span class="left-span-label">选择审批人员类型</span>
|
||||
</div>
|
||||
<el-radio-group v-model:value="userSelectionType" style="width: 100%">
|
||||
<el-row style="padding-bottom: 10px">
|
||||
<el-col :span="8">
|
||||
<el-radio value="ORG" @click="selectionClick('ORG')">机构</el-radio>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-radio value="ROLE" @click="selectionClick('ROLE')">角色</el-radio>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-radio value="POSITION" @click="selectionClick('POSITION')">职位</el-radio>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row style="padding-bottom: 10px">
|
||||
<el-col :span="8">
|
||||
<el-radio value="ORG_LEADER" @click="selectionClick('ORG_LEADER')">部门主管</el-radio>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-radio value="SUPERVISOR" @click="selectionClick('SUPERVISOR')">上级主管</el-radio>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-radio value="MUL_LEVEL_SUPERVISOR" @click="selectionClick('MUL_LEVEL_SUPERVISOR')"
|
||||
>连续多级主管</el-radio
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row style="padding-bottom: 10px">
|
||||
<el-col :span="8">
|
||||
<el-radio value="USER" @click="selectionClick('USER')">用户</el-radio>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-radio value="FORM_USER" @click="selectionClick('FORM_USER')">表单内的人</el-radio>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-radio value="FORM_USER_SUPERVISOR" @click="selectionClick('FORM_USER_SUPERVISOR')"
|
||||
>表单内的人上级主管</el-radio
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row style="padding-bottom: 10px">
|
||||
<el-col :span="8">
|
||||
<el-radio
|
||||
value="FORM_USER_MUL_LEVEL_SUPERVISOR"
|
||||
@click="selectionClick('FORM_USER_MUL_LEVEL_SUPERVISOR')"
|
||||
>表单内的人连续多级主管</el-radio
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-radio value="INITIATOR" @click="selectionClick('INITIATOR')">发起人</el-radio>
|
||||
</el-col>
|
||||
<el-col :span="8" />
|
||||
</el-row>
|
||||
</el-radio-group>
|
||||
<el-form-item
|
||||
class="mt-2"
|
||||
v-if="
|
||||
recordData.formType === 'DEFINE' &&
|
||||
(userSelectionType === 'FORM_USER' ||
|
||||
userSelectionType === 'FORM_USER_SUPERVISOR' ||
|
||||
userSelectionType === 'FORM_USER_MUL_LEVEL_SUPERVISOR')
|
||||
"
|
||||
name="formUser"
|
||||
:rules="[{ required: true, message: '请输入人员变量' }]"
|
||||
>
|
||||
<template #label>
|
||||
<el-tooltip>
|
||||
<template #title>单个字段可以采用:字段名,多个采用:字段名1,字段名2,字段名3</template>
|
||||
<question-circle-outlined />
|
||||
人员变量:
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-input
|
||||
style="width: 50%"
|
||||
v-model:value="userTypeForm.formUser"
|
||||
allow-clear
|
||||
@input="customFormUser"
|
||||
@keyup.enter="customFormUser"
|
||||
placeholder="请输入人员变量"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div v-if="seleType" class="mt-2">
|
||||
<el-button type="primary" @click="openSelector" size="small">
|
||||
<template #icon>
|
||||
<search-outlined />
|
||||
</template>
|
||||
选择
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<prop-tag
|
||||
v-if="form.properties&&form.properties.participateInfo&&form.properties.participateInfo.length > 0 && form.properties.participateInfo[0].value !== ''"
|
||||
:tag-list="form.properties.participateInfo[0]"
|
||||
/>
|
||||
</div>
|
||||
<el-form-item
|
||||
class="mt-2"
|
||||
v-if="
|
||||
userSelectionType === 'SUPERVISOR' ||
|
||||
userSelectionType === 'FORM_USER_SUPERVISOR' ||
|
||||
userSelectionType === 'MUL_LEVEL_SUPERVISOR' ||
|
||||
userSelectionType === 'FORM_USER_MUL_LEVEL_SUPERVISOR'
|
||||
"
|
||||
:label="
|
||||
userSelectionType === 'SUPERVISOR' || userSelectionType === 'FORM_USER_SUPERVISOR'
|
||||
? '上级主管级别'
|
||||
: '审批终点主管级别'
|
||||
"
|
||||
name="levelSupervisor"
|
||||
:rules="[{ required: true, message: '请选择主管级别' }]"
|
||||
>
|
||||
<el-select
|
||||
style="width: 50%"
|
||||
v-model:value="userTypeForm.levelSupervisor"
|
||||
placeholder="请选择主管级别"
|
||||
@change="levelSupervisorChange"
|
||||
:options="levelSupervisorList"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="2" label="审批配置" lazy>
|
||||
<span class="left-span-label">配置审批方式</span>
|
||||
<el-form label-position="top" layout="vertical" class="mt-2">
|
||||
<div v-show="!nodeLegal" style="margin-bottom: 10px">
|
||||
<el-alert message="请配置节点相关人员!" type="error" />
|
||||
</div>
|
||||
<el-form-item label="任务节点类型">
|
||||
<el-radio-group v-model:value="form.properties.configInfo.userTaskType">
|
||||
<el-radio
|
||||
v-for="userTaskType in userTaskTypeList"
|
||||
:key="userTaskType.value"
|
||||
:value="userTaskType.value"
|
||||
>{{ userTaskType.label }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="审批退回类型">
|
||||
<el-radio-group v-model:value="form.properties.configInfo.userTaskRejectType">
|
||||
<el-radio
|
||||
v-for="userTaskRejectType in userTaskRejectTypeList"
|
||||
:key="userTaskRejectType.value"
|
||||
:value="userTaskRejectType.value"
|
||||
>{{ userTaskRejectType.label }}
|
||||
</el-radio>
|
||||
<br />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="多人审批类型">
|
||||
<el-radio-group v-model:value="form.properties.configInfo.userTaskMulApproveType">
|
||||
<el-radio
|
||||
v-for="userTaskMulApproveType in userTaskMulApproveTypeList"
|
||||
:key="userTaskMulApproveType.value"
|
||||
:value="userTaskMulApproveType.value"
|
||||
>{{ userTaskMulApproveType.label }}
|
||||
</el-radio>
|
||||
<br />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="审批人员为空时">
|
||||
<el-radio-group v-model:value="form.properties.configInfo.userTaskEmptyApproveType">
|
||||
<el-radio
|
||||
v-for="userTaskEmptyApproveType in userTaskEmptyApproveTypeList"
|
||||
:key="userTaskEmptyApproveType.value"
|
||||
:value="userTaskEmptyApproveType.value"
|
||||
@change="userTaskEmptyApproveTypeChange"
|
||||
>{{ userTaskEmptyApproveType.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="form.properties.configInfo.userTaskEmptyApproveType === 'AUTO_TURN'"
|
||||
label="审批人为空时转交人"
|
||||
>
|
||||
<p><el-button type="primary" size="small" @click="seleApproveUser">选择人员</el-button></p>
|
||||
<el-tag
|
||||
v-if="form.properties.configInfo.userTaskEmptyApproveUserArray.length > 0"
|
||||
color="orange"
|
||||
closable
|
||||
@close="closeApproveUserTag"
|
||||
>
|
||||
{{ form.properties.configInfo.userTaskEmptyApproveUserArray[0].name }}</el-tag
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="3" label="按钮配置" lazy>
|
||||
<prop-button-info
|
||||
ref="propButtonInfo"
|
||||
:button-info="selectedButtonInfo"
|
||||
:show-button="defaultButtonkey"
|
||||
:no-checked="userTaskNoCheckedButtonkey"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="4" label="字段配置" lazy v-if="recordData.formType === 'DESIGN'">
|
||||
<prop-field-info
|
||||
ref="propFieldInfo"
|
||||
:field-info="fieldInfo"
|
||||
:default-field-model="defaultFieldModel"
|
||||
:form-field-list-value="formFieldListValue"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="5" label="表单配置" lazy v-else>
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">参与者可以使用的表单</span>
|
||||
</div>
|
||||
<el-form ref="userTaskFormRef" :model="formData" layout="vertical">
|
||||
<el-form-item
|
||||
label="节点表单"
|
||||
name="FORM_URL"
|
||||
:rules="[{ required: true, message: '请输入节点表单组件地址' }]"
|
||||
>
|
||||
<el-input
|
||||
v-model:value="formData.FORM_URL"
|
||||
addon-before="src/views/flw/customform/"
|
||||
addon-after=".vue"
|
||||
placeholder="请输入节点表单组件地址"
|
||||
allow-clear
|
||||
>
|
||||
<template #suffix>
|
||||
<el-button
|
||||
v-if="formData.FORM_URL"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="$refs.previewCustomFormRef.onOpen(formData.FORM_URL)"
|
||||
>
|
||||
预览
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="移动端节点表单"
|
||||
name="MOBILE_FORM_URL"
|
||||
:rules="[{ required: true, message: '请输入移动端节点表单组件地址' }]"
|
||||
>
|
||||
<el-input
|
||||
v-model:value="formData.MOBILE_FORM_URL"
|
||||
addon-before="pages/flw/customform/"
|
||||
addon-after=".vue"
|
||||
placeholder="请输入移动端节点表单组件地址"
|
||||
allow-clear
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="6" label="执行监听" lazy>
|
||||
<prop-listener-info
|
||||
ref="propExecutionListenerInfoRef"
|
||||
:listener-value="form.properties.executionListenerInfo"
|
||||
:default-listener-list="executionListenerInfo"
|
||||
:listener-value-array="executionListenerArray"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="7" label="节点监听" lazy>
|
||||
<prop-listener-info
|
||||
ref="propTaskListenerInfoRef"
|
||||
:listener-value="form.properties.taskListenerInfo"
|
||||
:default-listener-list="taskListenerInfo"
|
||||
:listener-value-array="taskListenerArray"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-container>
|
||||
<template #footer>
|
||||
<el-button type="primary" style="margin-right: 8px" @click="save">保存</el-button>
|
||||
<el-button @click="drawer = false">取消</el-button>
|
||||
</template>
|
||||
</formContainer>
|
||||
<role-selector-plus
|
||||
ref="roleselectorPlus"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:role-page-api="selectorApiFunction.rolePageApi"
|
||||
:checked-role-list-api="selectorApiFunction.checkedRoleListApi"
|
||||
:datel-is-converter-flw="true"
|
||||
@onBack="callBack"
|
||||
/>
|
||||
<user-selector-plus
|
||||
ref="userselectorPlus"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:user-page-api="selectorApiFunction.userPageApi"
|
||||
:checked-user-list-api="selectorApiFunction.checkedUserListApi"
|
||||
:datel-is-converter-flw="true"
|
||||
@onBack="callBack"
|
||||
/>
|
||||
<pos-selector-plus
|
||||
ref="posselectorPlus"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:pos-page-api="selectorApiFunction.posPageApi"
|
||||
:checked-pos-list-api="selectorApiFunction.checkedPosListApi"
|
||||
:datel-is-converter-flw="true"
|
||||
@onBack="callBack"
|
||||
/>
|
||||
<org-selector-plus
|
||||
ref="orgselectorPlus"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:org-page-api="selectorApiFunction.orgPageApi"
|
||||
:checked-org-list-api="selectorApiFunction.checkedOrgListApi"
|
||||
:datel-is-converter-flw="true"
|
||||
@onBack="callBack"
|
||||
/>
|
||||
<form-user-selector ref="formuserselector" :form-field-list="formFieldListValue" @click="formuserClick" />
|
||||
<user-selector-plus
|
||||
ref="userselectorApprove"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:user-page-api="selectorApiFunction.userPageApi"
|
||||
:checked-user-list-api="selectorApiFunction.checkedUserListApi"
|
||||
:radio-model="true"
|
||||
@onBack="callBackApprove"
|
||||
/>
|
||||
<preview-custom-form ref="previewCustomFormRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { cloneDeep, isEmpty } from 'lodash-es'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import addNode from './addNode.vue'
|
||||
import propButtonInfo from './prop/propButtonInfo.vue'
|
||||
import propFieldInfo from './prop/propFieldInfo.vue'
|
||||
import propListenerInfo from './prop/propListenerInfo.vue'
|
||||
import formUserSelector from './prop/formUserSelector.vue'
|
||||
import roleSelectorPlus from '@/components/Selector/roleSelectorPlus.vue'
|
||||
import userSelectorPlus from '@/components/Selector/userSelectorPlus.vue'
|
||||
import posSelectorPlus from '@/components/Selector/posSelectorPlus.vue'
|
||||
import orgSelectorPlus from '@/components/Selector/orgSelectorPlus.vue'
|
||||
import propTag from './prop/propTag.vue'
|
||||
import PreviewCustomForm from '@/components/XnWorkflow/nodes/common/previewCustomForm.vue'
|
||||
import formContainer from '@/components/formContainer/index.vue';
|
||||
export default {
|
||||
components: {
|
||||
addNode,
|
||||
propButtonInfo,
|
||||
propFieldInfo,
|
||||
propListenerInfo,
|
||||
formUserSelector,
|
||||
roleSelectorPlus,
|
||||
userSelectorPlus,
|
||||
posSelectorPlus,
|
||||
orgSelectorPlus,
|
||||
propTag,
|
||||
PreviewCustomForm,
|
||||
formContainer
|
||||
},
|
||||
// inject: ['select'],
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
processConfigInfo: { type: Object, default: () => {} },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
taskListenerArray: { type: Array, default: () => [] },
|
||||
selectorApiFunction: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
nodeLegal: false,
|
||||
childNode: {},
|
||||
drawer: false,
|
||||
isEditTitle: false,
|
||||
form: {},
|
||||
selectedButtonInfo: [],
|
||||
executionListenerInfo: cloneDeep(config.listener.userTaskExecutionListenerInfo),
|
||||
taskListenerInfo: cloneDeep(config.listener.userTaskTaskListenerInfo),
|
||||
activeKey: '1',
|
||||
defaultButtonkey: cloneDeep(config.button.userTaskDefaultButtonkey),
|
||||
userTaskNoCheckedButtonkey: cloneDeep(config.button.userTaskNoCheckedButtonkey),
|
||||
defaultFieldModel: cloneDeep(config.field.userTaskFieldModel),
|
||||
fieldInfo: [],
|
||||
tagList: [],
|
||||
seleType: false,
|
||||
// 新配置
|
||||
// 用户选择类型
|
||||
userSelectionType: '',
|
||||
userSelectionTypeList: cloneDeep(config.userTaskConfig.userSelectionTypeList),
|
||||
// 主管级别
|
||||
levelSupervisorList: cloneDeep(config.userTaskConfig.levelSupervisorList),
|
||||
// 任务节点类型
|
||||
userTaskTypeList: cloneDeep(config.userTaskConfig.userTaskTypeList),
|
||||
// 审批退回类型
|
||||
userTaskRejectTypeList: cloneDeep(config.userTaskConfig.userTaskRejectTypeList),
|
||||
// 多人审批时类型
|
||||
userTaskMulApproveTypeList: cloneDeep(config.userTaskConfig.userTaskMulApproveTypeList),
|
||||
// 审批人为空时类型
|
||||
userTaskEmptyApproveTypeList: cloneDeep(config.userTaskConfig.userTaskEmptyApproveTypeList),
|
||||
// 审批人为空时转交人
|
||||
userTaskEmptyApproveUser: '',
|
||||
formData: {},
|
||||
userTypeForm: {
|
||||
levelSupervisor: '1'
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.childNode = this.modelValue
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.childNode = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.form = {}
|
||||
this.form = cloneDeep(this.childNode)
|
||||
this.selectedButtonInfo = this.form.properties.buttonInfo
|
||||
this.fieldInfo = this.form.properties.fieldInfo
|
||||
this.drawer = true
|
||||
// 设置默认选中的用户类型单选 userSelectionType
|
||||
if (this.form.properties.participateInfo.length > 0) {
|
||||
this.userSelectionType = this.form.properties.participateInfo[0].key
|
||||
// 如果包含表单内的人
|
||||
const formUserObj = this.form.properties.participateInfo.find((f) => f.key === 'FORM_USER')
|
||||
if (formUserObj) {
|
||||
this.userTypeForm.formUser = formUserObj.value
|
||||
}
|
||||
// 如果是直属主管或者连续多级审批的
|
||||
this.form.properties.participateInfo.forEach((item) => {
|
||||
// 如果只是普通的主管以及级别
|
||||
if (item.key === 'SUPERVISOR' || item.key === 'MUL_LEVEL_SUPERVISOR') {
|
||||
this.userTypeForm.levelSupervisor = item.value
|
||||
}
|
||||
// 如果是表单内的人的主管以及级别
|
||||
if (item.key === 'FORM_USER_SUPERVISOR' || item.key === 'FORM_USER_MUL_LEVEL_SUPERVISOR') {
|
||||
this.userTypeForm.levelSupervisor = item.value
|
||||
this.userTypeForm.formUser = JSON.parse(item.extJson).value
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 设置发起人
|
||||
this.userSelectionType = 'INITIATOR'
|
||||
this.form.properties.participateInfo = [{ key: 'INITIATOR', label: '发起人', value: '发起人:${INITIATOR}' }]
|
||||
}
|
||||
// 校验状态
|
||||
this.isNodeLegal()
|
||||
// 设置第一个选项卡打开选择器的按钮是否展示
|
||||
if (
|
||||
this.userSelectionType === 'USER' ||
|
||||
this.userSelectionType === 'ROLE' ||
|
||||
this.userSelectionType === 'ORG' ||
|
||||
this.userSelectionType === 'POSITION' ||
|
||||
this.userSelectionType === 'FORM_USER' ||
|
||||
this.userSelectionType === 'FORM_USER_SUPERVISOR' ||
|
||||
this.userSelectionType === 'FORM_USER_MUL_LEVEL_SUPERVISOR'
|
||||
) {
|
||||
this.seleType = true
|
||||
}
|
||||
// 初始化自定义表单字段值
|
||||
this.initFormInfo()
|
||||
},
|
||||
initFormInfo() {
|
||||
const processConfigInfo = cloneDeep(this.processConfigInfo)
|
||||
if (!this.form.properties.formInfo.find((f) => f.key === 'FORM_URL')) {
|
||||
this.formData.FORM_URL = processConfigInfo.processUserTaskFormUrl
|
||||
} else {
|
||||
this.formData.FORM_URL = this.form.properties.formInfo.find((f) => f.key === 'FORM_URL').value
|
||||
}
|
||||
if (!this.form.properties.formInfo.find((f) => f.key === 'MOBILE_FORM_URL')) {
|
||||
this.formData.MOBILE_FORM_URL = processConfigInfo.processUserTaskMobileFormUrl
|
||||
} else {
|
||||
this.formData.MOBILE_FORM_URL = this.form.properties.formInfo.find((f) => f.key === 'MOBILE_FORM_URL').value
|
||||
}
|
||||
},
|
||||
editTitle() {
|
||||
this.isEditTitle = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.nodeTitle.focus()
|
||||
})
|
||||
},
|
||||
saveTitle() {
|
||||
this.isEditTitle = false
|
||||
},
|
||||
save() {
|
||||
if (isEmpty(this.form.id)) {
|
||||
this.form.id = this.$TOOL.snowyUuid()
|
||||
}
|
||||
this.form.properties.buttonInfo = this.$refs.propButtonInfo.selectedButtonKeyList()
|
||||
if (this.recordData.formType === 'DESIGN') {
|
||||
this.form.properties.fieldInfo = this.$refs.propFieldInfo.selectedFieldList()
|
||||
}
|
||||
if (this.isNodeLegal()) {
|
||||
this.form.properties.executionListenerInfo = this.$refs.propExecutionListenerInfoRef.selectedListenerList()
|
||||
this.form.properties.taskListenerInfo = this.$refs.propTaskListenerInfoRef.selectedListenerList()
|
||||
if (this.recordData.formType === 'DESIGN') {
|
||||
this.form.dataLegal = true
|
||||
this.$emit('update:modelValue', this.form)
|
||||
this.drawer = false
|
||||
} else {
|
||||
this.$refs.userTaskFormRef
|
||||
.validate()
|
||||
.then((values) => {
|
||||
this.form.dataLegal = true
|
||||
this.form.properties.formInfo = cloneDeep(config.nodeModel.formInfo)
|
||||
this.form.properties.formInfo.find((f) => f.key === 'FORM_URL').value = values.FORM_URL
|
||||
this.form.properties.formInfo.find((f) => f.key === 'MOBILE_FORM_URL').value = values.MOBILE_FORM_URL
|
||||
this.$emit('update:modelValue', this.form)
|
||||
this.drawer = false
|
||||
})
|
||||
.catch((err) => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
selectionClick(value) {
|
||||
const type = value
|
||||
const result = []
|
||||
this.form.properties.participateInfo = []
|
||||
const obj = {}
|
||||
obj.key = type
|
||||
obj.label = ''
|
||||
obj.value = ''
|
||||
if (type === 'ORG_LEADER' || type === 'INITIATOR') {
|
||||
// 部门主管 发起人
|
||||
this.seleType = false
|
||||
obj.label = this.userSelectionTypeList.filter((item) => item.value === type)[0].label
|
||||
obj.value = this.userSelectionTypeList.filter((item) => item.value === type)[0].label + ':${' + type + '}'
|
||||
} else if (type === 'SUPERVISOR' || type === 'MUL_LEVEL_SUPERVISOR') {
|
||||
this.seleType = false
|
||||
// 直属主管 连续多级审批 默认选中直接主管
|
||||
obj.label = this.userSelectionTypeList.filter((item) => item.value === type)[0].label
|
||||
obj.value = this.userTypeForm.levelSupervisor
|
||||
} else if (type === 'FORM_USER') {
|
||||
this.seleType = this.recordData.formType === 'DESIGN'
|
||||
} else if (type === 'FORM_USER_SUPERVISOR' || type === 'FORM_USER_MUL_LEVEL_SUPERVISOR') {
|
||||
this.seleType = this.recordData.formType === 'DESIGN'
|
||||
} else {
|
||||
this.seleType = true
|
||||
}
|
||||
result.push(obj)
|
||||
this.form.properties.participateInfo = result
|
||||
// 清空自定义表单内的人员输入框
|
||||
this.userTypeForm.formUser = ''
|
||||
this.isNodeLegal()
|
||||
},
|
||||
// 打开各种选择器
|
||||
openSelector() {
|
||||
let type = this.userSelectionType
|
||||
let data = this.form.properties.participateInfo
|
||||
if (type === 'ROLE') {
|
||||
this.$refs.roleselectorPlus.showRolePlusModal(data)
|
||||
}
|
||||
if (type === 'USER') {
|
||||
this.$refs.userselectorPlus.showUserPlusModal(data)
|
||||
}
|
||||
if (type === 'POSITION') {
|
||||
this.$refs.posselectorPlus.showPosPlusModal(data)
|
||||
}
|
||||
if (type === 'ORG') {
|
||||
this.$refs.orgselectorPlus.showOrgPlusModal(data)
|
||||
}
|
||||
if (type === 'FORM_USER' || type === 'FORM_USER_SUPERVISOR' || type === 'FORM_USER_MUL_LEVEL_SUPERVISOR') {
|
||||
this.$refs.formuserselector.showFormUserModal(data[0])
|
||||
}
|
||||
},
|
||||
delNode() {
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
this.$emit('update:modelValue', this.childNode.childNode)
|
||||
// eslint-disable-next-line vue/require-explicit-emits
|
||||
this.$emit('deleteParalle')
|
||||
},
|
||||
delUser(index) {
|
||||
this.form.nodeUserList.splice(index, 1)
|
||||
},
|
||||
// 选择转交人
|
||||
seleApproveUser() {
|
||||
const data = [this.form.properties.configInfo.userTaskEmptyApproveUser]
|
||||
this.$refs.userselectorApprove.showUserPlusModal(data)
|
||||
},
|
||||
// 选择转交人回调
|
||||
callBackApprove(value) {
|
||||
this.form.properties.configInfo.userTaskEmptyApproveUser = value[0].id
|
||||
this.form.properties.configInfo.userTaskEmptyApproveUserArray = value
|
||||
},
|
||||
// 清除转交人
|
||||
closeApproveUserTag() {
|
||||
this.form.properties.configInfo.userTaskEmptyApproveUser = ''
|
||||
this.form.properties.configInfo.userTaskEmptyApproveUserArray = []
|
||||
},
|
||||
// 点击自动转交给某人单选时
|
||||
userTaskEmptyApproveTypeChange(value) {
|
||||
const type = value.target.value
|
||||
if (type === 'AUTO_TURN') {
|
||||
// 赋值默认的管理员
|
||||
this.form.properties.configInfo.userTaskEmptyApproveUser = JSON.parse(this.recordData.extJson)[0].id
|
||||
this.form.properties.configInfo.userTaskEmptyApproveUserArray = JSON.parse(this.recordData.extJson)
|
||||
} else {
|
||||
// 置为空
|
||||
this.closeApproveUserTag()
|
||||
}
|
||||
},
|
||||
// 校验节点是否合法
|
||||
isNodeLegal() {
|
||||
if (this.form.properties.participateInfo.length > 0) {
|
||||
if (isEmpty(this.form.properties.participateInfo[0].label)) {
|
||||
this.nodeLegal = false
|
||||
return false
|
||||
} else {
|
||||
// 再看看默认转交人是否OK
|
||||
// eslint-disable-next-line no-lonely-if
|
||||
if (this.form.properties.configInfo.userTaskEmptyApproveType === 'AUTO_TURN') {
|
||||
if (!isEmpty(this.form.properties.configInfo.userTaskEmptyApproveUser)) {
|
||||
this.nodeLegal = true
|
||||
return true
|
||||
} else {
|
||||
this.nodeLegal = false
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
this.nodeLegal = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.nodeLegal = false
|
||||
return false
|
||||
}
|
||||
},
|
||||
selectHandle(type, data) {
|
||||
const value = []
|
||||
if (data.length > 0) {
|
||||
data.forEach((item) => {
|
||||
value.push(item.id)
|
||||
})
|
||||
}
|
||||
if (type === 1) {
|
||||
this.$refs.userselector.showUserModal(value)
|
||||
}
|
||||
if (type === 2) {
|
||||
this.$refs.roleselector.showRoleModal(value)
|
||||
}
|
||||
// this.select(type, data)
|
||||
},
|
||||
// 公共回调方法,因为它们返回的数据结构一致
|
||||
callBack(value) {
|
||||
if (value.label === []) {
|
||||
this.nodeLegal = false
|
||||
} else {
|
||||
this.form.properties.participateInfo[0] = value
|
||||
}
|
||||
this.isNodeLegal()
|
||||
},
|
||||
// 表单内的人选择器回调
|
||||
formuserClick(value) {
|
||||
// eslint-disable-next-line no-undefined
|
||||
if (value) {
|
||||
const participateInfo = this.form.properties.participateInfo[0].key
|
||||
const result = []
|
||||
const obj = {}
|
||||
if (participateInfo === 'FORM_USER_SUPERVISOR' || participateInfo === 'FORM_USER_MUL_LEVEL_SUPERVISOR') {
|
||||
obj.key = participateInfo
|
||||
obj.label = this.userSelectionTypeList.filter((item) => item.value === participateInfo)[0].label
|
||||
obj.value = this.userTypeForm.levelSupervisor
|
||||
const extJson = {
|
||||
key: 'FORM_USER',
|
||||
label: '表单内的人',
|
||||
value: value.model
|
||||
}
|
||||
obj.extJson = JSON.stringify(extJson)
|
||||
} else {
|
||||
obj.key = 'FORM_USER'
|
||||
obj.label = this.userSelectionTypeList.filter((item) => item.value === 'FORM_USER')[0].label
|
||||
obj.value = value.model
|
||||
}
|
||||
result.push(obj)
|
||||
this.form.properties.participateInfo = result
|
||||
} else {
|
||||
this.nodeLegal = false
|
||||
}
|
||||
this.isNodeLegal()
|
||||
},
|
||||
// 监听自定义表单人员输入
|
||||
customFormUser() {
|
||||
if (this.userTypeForm.formUser) {
|
||||
const participateInfo = this.form.properties.participateInfo[0].key
|
||||
const result = []
|
||||
const obj = {}
|
||||
if (participateInfo === 'FORM_USER_SUPERVISOR' || participateInfo === 'FORM_USER_MUL_LEVEL_SUPERVISOR') {
|
||||
obj.key = participateInfo
|
||||
obj.label = this.userSelectionTypeList.filter((item) => item.value === participateInfo)[0].label
|
||||
obj.value = this.userTypeForm.levelSupervisor
|
||||
const extJson = {
|
||||
key: 'FORM_USER',
|
||||
label: '表单内的人',
|
||||
value: this.userTypeForm.formUser
|
||||
}
|
||||
obj.extJson = JSON.stringify(extJson)
|
||||
} else {
|
||||
obj.key = 'FORM_USER'
|
||||
obj.label = this.userSelectionTypeList.filter((item) => item.value === 'FORM_USER')[0].label
|
||||
obj.value = this.userTypeForm.formUser
|
||||
}
|
||||
result.push(obj)
|
||||
this.form.properties.participateInfo = result
|
||||
this.nodeLegal = false
|
||||
} else {
|
||||
this.form.properties.participateInfo = []
|
||||
this.nodeLegal = true
|
||||
}
|
||||
this.isNodeLegal()
|
||||
},
|
||||
// 选择主管层级
|
||||
levelSupervisorChange(value) {
|
||||
this.form.properties.participateInfo[0].value = value
|
||||
},
|
||||
toText(childNode) {
|
||||
if (!isEmpty(childNode)) {
|
||||
const strArray = this.toTag(childNode.properties.participateInfo[0])
|
||||
if (strArray.length > 0) {
|
||||
let value = ''
|
||||
// eslint-disable-next-line no-plusplus
|
||||
for (let i = 0; i < strArray.length; i++) {
|
||||
if (strArray.length === i + 1) {
|
||||
value = value + strArray[i]
|
||||
} else {
|
||||
value = value + strArray[i] + ','
|
||||
}
|
||||
}
|
||||
return value
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
toTag(participateInfo) {
|
||||
// eslint-disable-next-line no-undefined
|
||||
if (participateInfo === undefined) {
|
||||
return []
|
||||
}
|
||||
if (isEmpty(participateInfo.label)) {
|
||||
return []
|
||||
} else {
|
||||
let resultArray = []
|
||||
if (participateInfo.label.indexOf(',') !== -1) {
|
||||
resultArray = participateInfo.label.split(',')
|
||||
} else {
|
||||
resultArray.push(participateInfo.label)
|
||||
}
|
||||
return resultArray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,180 +0,0 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
// 根据自定义的此节点定义的,转换表单的隐藏、必填、禁用
|
||||
export default {
|
||||
// 设置字段显示与否
|
||||
convSettingsField(formJson, fieldInfo) {
|
||||
// 递归遍历控件树
|
||||
const traverse = (array) => {
|
||||
array.forEach((element) => {
|
||||
if (element.type === 'grid' || element.type === 'tabs') {
|
||||
// 栅格布局 and 标签页
|
||||
element.columns.forEach((item) => {
|
||||
traverse(item.list)
|
||||
})
|
||||
} else if (element.type === 'card') {
|
||||
// 卡片布局 and 动态表格
|
||||
traverse(element.list)
|
||||
} else if (element.type === 'table') {
|
||||
// 表格布局
|
||||
element.trs.forEach((item) => {
|
||||
item.tds.forEach((val) => {
|
||||
traverse(val.list)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const type = element.type
|
||||
if ((type !== 'alert') & (type !== 'text') & (type !== 'divider') & (type !== 'html')) {
|
||||
const obj = fieldInfo.find((i) => i.key === element.model)
|
||||
if (obj) {
|
||||
element.options.hidden = obj.value === 'HIDE' // ? true : false
|
||||
element.options.disabled = obj.value === 'READ' // ? true : false
|
||||
} else {
|
||||
ElMessage.warning('程序检测到功能字段配置发生了异常,依然能正常使用,请联系管理员进行流程重新配置部署!')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
traverse(formJson.list)
|
||||
return formJson
|
||||
},
|
||||
// 掏出所有字段,返回列表
|
||||
getListField(data) {
|
||||
let result = []
|
||||
// 递归遍历控件树
|
||||
const traverse = (array) => {
|
||||
array.forEach((element) => {
|
||||
if (element.type === 'grid' || element.type === 'tabs') {
|
||||
// 栅格布局 and 标签页
|
||||
element.columns.forEach((item) => {
|
||||
traverse(item.list)
|
||||
})
|
||||
} else if (element.type === 'card') {
|
||||
// 卡片布局 and 动态表格
|
||||
traverse(element.list)
|
||||
} else if (element.type === 'table') {
|
||||
// 表格布局
|
||||
element.trs.forEach((item) => {
|
||||
item.tds.forEach((val) => {
|
||||
traverse(val.list)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const type = element.type
|
||||
// 排除一些
|
||||
if ((type !== 'alert') & (type !== 'text') & (type !== 'divider') & (type !== 'batch') & (type !== 'html')) {
|
||||
result.push(element)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
traverse(data)
|
||||
return result
|
||||
},
|
||||
// 取节点(用到按钮权限跟字段),并且给节点set一个json,也就是我们的审批记录
|
||||
getChildNode(modelJson, activityId, dataList) {
|
||||
let result = {}
|
||||
let traverse = (obj) => {
|
||||
// obj.properties.commentList = []
|
||||
if (obj.type === 'exclusiveGateway' || obj.type === 'parallelGateway') {
|
||||
// 网关下分2步走
|
||||
if (obj.conditionNodeList) {
|
||||
obj.conditionNodeList.forEach((item) => {
|
||||
traverse(item)
|
||||
})
|
||||
}
|
||||
if (obj.childNode) {
|
||||
traverse(obj.childNode)
|
||||
}
|
||||
} else {
|
||||
if (obj.id === activityId) {
|
||||
result = obj
|
||||
} else {
|
||||
// 这里追加记录
|
||||
// if (dataList) {
|
||||
// dataList.forEach((item) => {
|
||||
// // 给对应的节点
|
||||
// if (item.activityId === obj.id) {
|
||||
// obj.properties.commentList.push(item)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// 再穿下去
|
||||
if (obj.childNode) {
|
||||
traverse(obj.childNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 传入流程的这个
|
||||
traverse(modelJson)
|
||||
return result
|
||||
},
|
||||
// 遍历表单,将组件设为禁用
|
||||
convFormComponentsDisabled (formJson) {
|
||||
// 递归遍历控件树
|
||||
const traverse = (array) => {
|
||||
array.forEach((element) => {
|
||||
if (element.type === 'grid' || element.type === 'tabs') {
|
||||
// 栅格布局 and 标签页
|
||||
element.columns.forEach((item) => {
|
||||
traverse(item.list)
|
||||
})
|
||||
} else if (element.type === 'card') {
|
||||
// 卡片布局 and 动态表格
|
||||
traverse(element.list)
|
||||
} else if (element.type === 'table') {
|
||||
// 表格布局
|
||||
element.trs.forEach((item) => {
|
||||
item.tds.forEach((val) => {
|
||||
traverse(val.list)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const type = element.type
|
||||
if ((type !== 'alert') & (type !== 'text') & (type !== 'divider') & (type !== 'html')) {
|
||||
element.options.disabled = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
traverse(formJson.list)
|
||||
return formJson
|
||||
},
|
||||
// 将渲染图形的信息跟审批记录进行融合,每个节点的配置内添加commentList
|
||||
coalesceDataListChildNode(modelJson, dataList) { // activityId,
|
||||
// let result = {}
|
||||
const traverse = (obj) => {
|
||||
// obj.properties.commentList = []
|
||||
if (obj.type === 'exclusiveGateway' || obj.type === 'parallelGateway') {
|
||||
// 网关下分2步走
|
||||
if (obj.conditionNodeList) {
|
||||
obj.conditionNodeList.forEach((item) => {
|
||||
traverse(item)
|
||||
})
|
||||
}
|
||||
if (obj.childNode) {
|
||||
traverse(obj.childNode)
|
||||
}
|
||||
} else {
|
||||
if (dataList) {
|
||||
dataList.forEach((item) => {
|
||||
// 给对应的节点
|
||||
if (item.activityId === obj.id) {
|
||||
// 增加多个对象
|
||||
obj.properties.commentList.push(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 再穿下去
|
||||
if (obj.childNode) {
|
||||
traverse(obj.childNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 传入流程的这个
|
||||
traverse(modelJson)
|
||||
return modelJson
|
||||
}
|
||||
}
|
||||
@@ -1,649 +0,0 @@
|
||||
<template>
|
||||
<formContainer
|
||||
v-model:visible="drawer"
|
||||
:destroy-on-close="true"
|
||||
:title="modelTitle"
|
||||
:width="700"
|
||||
:bodyStyle="{ 'padding-top': '0px' }"
|
||||
>
|
||||
<el-form ref="noticeFormRef" :model="formData" layout="vertical">
|
||||
<el-tabs v-model:activeKey="activeKey">
|
||||
<el-tab-pane key="1" tab="人员配置" force-render>
|
||||
<div v-show="formVerify" style="margin-bottom: 10px">
|
||||
<el-alert message="请切换标签查看,填写完必填项!" type="error" />
|
||||
</div>
|
||||
<div v-show="alertShow" style="margin-bottom: 10px">
|
||||
<el-alert message="未选择任何类型的人员配置,默认所有人均可参与此流程。" type="warning" />
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">配置使用该流程的人员</span>
|
||||
</div>
|
||||
<el-button type="primary" :icon="Plus" round @click="selectionParticipants('ORG')" size="small">
|
||||
选择机构
|
||||
</el-button>
|
||||
<p />
|
||||
<prop-tag :tagList="getTagList('ORG')" />
|
||||
<el-divider />
|
||||
<el-button type="primary" round @click="selectionParticipants('ROLE')" size="small">
|
||||
<!-- <plus-outlined /> -->
|
||||
选择角色
|
||||
</el-button>
|
||||
<p />
|
||||
<prop-tag :tagList="getTagList('ROLE')" />
|
||||
<el-divider />
|
||||
<el-button type="primary" round @click="selectionParticipants('POSITION')" size="small">
|
||||
<!-- <plus-outlined /> -->
|
||||
选择职位
|
||||
</el-button>
|
||||
<p />
|
||||
<prop-tag :tagList="getTagList('POSITION')" />
|
||||
<el-divider />
|
||||
<el-button type="primary" round @click="selectionParticipants('USER')" size="small">
|
||||
<!-- <plus-outlined /> -->
|
||||
选择用户
|
||||
</el-button>
|
||||
<p />
|
||||
<prop-tag :tagList="getTagList('USER')" />
|
||||
<el-divider />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane key="2" tab="基础配置" force-render>
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">流程基础全局配置</span>
|
||||
</div>
|
||||
<el-row :gutter="[10, 0]">
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
label="流水号"
|
||||
name="processSnTemplateId"
|
||||
:rules="[{ required: true, message: '请选择流水号' }]"
|
||||
>
|
||||
<el-select
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processSnTemplateId"
|
||||
v-model:value="form.properties.configInfo.processSnTemplateId"
|
||||
placeholder="请选择流水号"
|
||||
:options="snTemplateArray"
|
||||
>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item
|
||||
v-if="recordData.formType === 'DESIGN'"
|
||||
label="打印模板"
|
||||
name="processPrintTemplateId"
|
||||
:rules="[{ required: true, message: '请选择打印模板' }]"
|
||||
>
|
||||
<el-select
|
||||
v-if="form&&form.properties&&form.properties.configInfo.processPrintTemplateId"
|
||||
v-model:value="form.properties.configInfo.processPrintTemplateId"
|
||||
placeholder="请选择打印模板"
|
||||
:options="printTemplateArray"
|
||||
/>
|
||||
</el-form-item>
|
||||
<span v-else>
|
||||
<p>打印模板</p>
|
||||
<p>自定义表单内提供打印方法</p>
|
||||
</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item
|
||||
label="标题模板"
|
||||
name="processTitleTemplate"
|
||||
:rules="[{ required: true, message: '请创造标题模板' }]"
|
||||
>
|
||||
<template-generator
|
||||
ref="processTitleGenerator"
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processTitleTemplate"
|
||||
v-model:inputValue="form.properties.configInfo.processTitleTemplate"
|
||||
:fieldInfoLis="fieldInfoLis"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="摘要模板"
|
||||
name="processAbstractTemplate"
|
||||
:rules="[{ required: true, message: '请创造摘要模板' }]"
|
||||
>
|
||||
<template-generator
|
||||
ref="processAbstractGenerator"
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processAbstractTemplate"
|
||||
v-model:inputValue="form.properties.configInfo.processAbstractTemplate"
|
||||
:fieldInfoLis="fieldInfoLis"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开启自动去重" name="processEnableAutoDistinct">
|
||||
<el-switch v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableAutoDistinct" v-model:checked="form.properties.configInfo.processEnableAutoDistinct" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableAutoDistinct" name="processAutoDistinctType">
|
||||
<el-radio-group v-model:value="form.properties.configInfo.processAutoDistinctType">
|
||||
<el-radio
|
||||
v-for="autoDistinctType in processAutoDistinctTypeList"
|
||||
:key="autoDistinctType.value"
|
||||
:value="autoDistinctType.value"
|
||||
>{{ autoDistinctType.label }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-row :gutter="[10, 0]">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开启审批撤销" name="processEnableRevoke">
|
||||
<el-switch v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableRevoke" v-model:checked="form.properties.configInfo.processEnableRevoke" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开启意见必填" name="processEnableCommentRequired">
|
||||
<el-switch v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableCommentRequired" v-model:checked="form.properties.configInfo.processEnableCommentRequired" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane key="3" tab="通知配置" force-render>
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">配置通知事项</span>
|
||||
</div>
|
||||
<el-form-item label="开启退回通知" name="processEnableBackNotice">
|
||||
<el-switch v-model:checked="formData.processEnableBackNotice" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="退回通知方式"
|
||||
v-show="formData.processEnableBackNotice"
|
||||
name="processBackNoticeChannel"
|
||||
:rules="[{ required: formData.processEnableBackNotice, message: '请选择通知方式' }]"
|
||||
>
|
||||
<el-checkbox-group v-model:value="formData.processBackNoticeChannel" :options="noticeInfoList" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="退回通知模板"
|
||||
v-show="formData.processEnableBackNotice"
|
||||
name="processBackNoticeTemplate"
|
||||
:rules="[{ required: formData.processEnableBackNotice, message: '请创造通知模板' }]"
|
||||
>
|
||||
<template-generator
|
||||
ref="enableBackNoticeRef"
|
||||
v-model:inputValue="formData.processBackNoticeTemplate"
|
||||
:fieldInfoLis="fieldInfoLis"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开启待办通知" name="processEnableTodoNotice">
|
||||
<el-switch v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableTodoNotice" v-model:checked="form.properties.configInfo.processEnableTodoNotice" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="待办通知方式"
|
||||
v-show="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableTodoNotice"
|
||||
name="processTodoNoticeChannel"
|
||||
:rules="[{ required: formData.processEnableTodoNotice, message: '请选择通知方式' }]"
|
||||
>
|
||||
<el-checkbox-group
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processTodoNoticeChannel"
|
||||
v-model:value="form.properties.configInfo.processTodoNoticeChannel"
|
||||
:options="noticeInfoList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="待办通知模板"
|
||||
v-show="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableTodoNotice"
|
||||
name="processTodoNoticeTemplate"
|
||||
:rules="[{ required: formData.processEnableTodoNotice, message: '请创造通知模板' }]"
|
||||
>
|
||||
<template-generator
|
||||
ref="todoNoticeChannelRef"
|
||||
:fieldInfoLis="fieldInfoLis"
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processTodoNoticeTemplate"
|
||||
v-model:inputValue="form.properties.configInfo.processTodoNoticeTemplate"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开启抄送通知" name="processEnableCopyNotice">
|
||||
<el-switch v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableCopyNotice" v-model:checked="form.properties.configInfo.processEnableCopyNotice" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="抄送通知方式"
|
||||
v-show="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableCopyNotice"
|
||||
name="processCopyNoticeChannel"
|
||||
:rules="[{ required: formData.processEnableCopyNotice, message: '请选择通知方式' }]"
|
||||
>
|
||||
<el-checkbox-group
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processCopyNoticeChannel"
|
||||
v-model:value="form.properties.configInfo.processCopyNoticeChannel"
|
||||
:options="noticeInfoList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="抄送通知模板"
|
||||
v-show="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableCopyNotice"
|
||||
name="processCopyNoticeTemplate"
|
||||
:rules="[{ required: formData.processEnableCopyNotice, message: '请创造通知模板' }]"
|
||||
>
|
||||
<template-generator
|
||||
ref="enableCopyNoticeRef"
|
||||
:fieldInfoLis="fieldInfoLis"
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processCopyNoticeTemplate"
|
||||
v-model:inputValue="form.properties.configInfo.processCopyNoticeTemplate"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="开启完成通知" name="processEnableCompleteNotice">
|
||||
<el-switch v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableCompleteNotice" v-model:checked="form.properties.configInfo.processEnableCompleteNotice" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="完成通知方式"
|
||||
v-show="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableCompleteNotice"
|
||||
name="processCompleteNoticeChannel"
|
||||
:rules="[{ required: formData.processEnableCompleteNotice, message: '请选择通知方式' }]"
|
||||
>
|
||||
<el-checkbox-group
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processCompleteNoticeChannel"
|
||||
v-model:value="form.properties.configInfo.processCompleteNoticeChannel"
|
||||
:options="noticeInfoList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="完成通知模板"
|
||||
v-show="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processEnableCompleteNotice"
|
||||
name="processCompleteNoticeTemplate"
|
||||
:rules="[{ required: formData.processEnableCompleteNotice, message: '请创造通知模板' }]"
|
||||
>
|
||||
<template-generator
|
||||
ref="enableCompleteNoticeRef"
|
||||
:fieldInfoLis="fieldInfoLis"
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processCompleteNoticeTemplate"
|
||||
v-model:inputValue="form.properties.configInfo.processCompleteNoticeTemplate"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane key="4" tab="表单预设" force-render v-if="recordData.formType !== 'DESIGN'">
|
||||
<div class="mb-2">
|
||||
<span class="left-span-label">预设全局需要的表单</span>
|
||||
</div>
|
||||
<el-form-item
|
||||
label="开始节点表单"
|
||||
name="processStartTaskFormUrl"
|
||||
:rules="[{ required: true, message: '请输入开始节点表单' }]"
|
||||
>
|
||||
<el-input
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processStartTaskFormUrl"
|
||||
v-model:value="form.properties.configInfo.processStartTaskFormUrl"
|
||||
addon-before="src/views/flw/customform/"
|
||||
addon-after=".vue"
|
||||
placeholder="请输入开始节点表单组件"
|
||||
allow-clear
|
||||
>
|
||||
<template #suffix>
|
||||
<el-button
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processStartTaskFormUrl"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="$refs.previewCustomFormRef.onOpen(form.properties.configInfo.processStartTaskFormUrl)"
|
||||
>
|
||||
预览
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="移动端开始节点表单"
|
||||
name="processStartTaskMobileFormUrl"
|
||||
:rules="[{ required: true, message: '请输入移动端开始节点表单' }]"
|
||||
>
|
||||
<el-input
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processStartTaskMobileFormUrl"
|
||||
v-model:value="form.properties.configInfo.processStartTaskMobileFormUrl"
|
||||
addon-before="pages/flw/customform/"
|
||||
addon-after=".vue"
|
||||
placeholder="请输入移动端开始节点表单组件"
|
||||
allow-clear
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="人员节点表单"
|
||||
name="processUserTaskFormUrl"
|
||||
:rules="[{ required: true, message: '请输入人员节点表单' }]"
|
||||
>
|
||||
<el-input
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processUserTaskFormUrl"
|
||||
v-model:value="form.properties.configInfo.processUserTaskFormUrl"
|
||||
addon-before="src/views/flw/customform/"
|
||||
addon-after=".vue"
|
||||
placeholder="请输入人员节点表单组件"
|
||||
allow-clear
|
||||
>
|
||||
<template #suffix>
|
||||
<el-button
|
||||
v-if="form&&form.properties.configInfo.processUserTaskFormUrl"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="$refs.previewCustomFormRef.onOpen(form.properties.configInfo.processUserTaskFormUrl)"
|
||||
>
|
||||
预览
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="移动端人员节点表单"
|
||||
name="processUserTaskMobileFormUrl"
|
||||
:rules="[{ required: true, message: '请输入移动端人员节点表单' }]"
|
||||
>
|
||||
<el-input
|
||||
v-if="form&&form.properties&&form.properties.configInfo&&form.properties.configInfo.processUserTaskMobileFormUrl"
|
||||
v-model:value="form.properties.configInfo.processUserTaskMobileFormUrl"
|
||||
addon-before="pages/flw/customform/"
|
||||
addon-after=".vue"
|
||||
placeholder="请输入移动端人员节点表单组件"
|
||||
allow-clear
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane key="5" tab="执行监听" force-render>
|
||||
<prop-listener-info
|
||||
ref="propListenerInfoRef"
|
||||
:listenerValue="form&&form.properties?.executionListenerInfo"
|
||||
:defaultListenerList="executionListenerInfo"
|
||||
:listener-value-array="executionListenerArray"
|
||||
listener-type="global"
|
||||
:execution-listener-selector-for-custom-event-array="executionListenerSelectorForCustomEventArray"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button type="primary" style="margin-right: 8px" @click="onFinish">保存</el-button>
|
||||
<el-button @click="drawer = false">取消</el-button>
|
||||
</template>
|
||||
|
||||
<role-selector-plus
|
||||
ref="roleselectorPlus"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:role-page-api="selectorApiFunction.rolePageApi"
|
||||
:checked-role-list-api="selectorApiFunction.checkedRoleListApi"
|
||||
:data-is-converter-flw="true"
|
||||
@onBack="callBack"
|
||||
/>
|
||||
<user-selector-plus
|
||||
ref="userselectorPlus"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:user-page-api="selectorApiFunction.userPageApi"
|
||||
:checked-user-list-api="selectorApiFunction.checkedUserListApi"
|
||||
:data-is-converter-flw="true"
|
||||
@onBack="callBack"
|
||||
/>
|
||||
<pos-selector-plus
|
||||
ref="posselectorPlus"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:pos-page-api="selectorApiFunction.posPageApi"
|
||||
:checked-pos-list-api="selectorApiFunction.checkedPosListApi"
|
||||
:datel-is-converter-flw="true"
|
||||
@onBack="callBack"
|
||||
/>
|
||||
<org-selector-plus
|
||||
ref="orgselectorPlus"
|
||||
:org-tree-api="selectorApiFunction.orgTreeApi"
|
||||
:org-page-api="selectorApiFunction.orgPageApi"
|
||||
:checked-org-list-api="selectorApiFunction.checkedOrgListApi"
|
||||
:data-is-converter-flw="true"
|
||||
@onBack="callBack"
|
||||
/>
|
||||
<preview-custom-form ref="previewCustomFormRef" />
|
||||
</formContainer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import templateGenerator from './nodes/prop/templateGenerator.vue'
|
||||
import config from '@/components/XnWorkflow/nodes/config/config'
|
||||
import roleSelectorPlus from '@/components/Selector/roleSelectorPlus.vue'
|
||||
import userSelectorPlus from '@/components/Selector/userSelectorPlus.vue'
|
||||
import posSelectorPlus from '@/components/Selector/posSelectorPlus.vue'
|
||||
import orgSelectorPlus from '@/components/Selector/orgSelectorPlus.vue'
|
||||
import propTag from './nodes/prop/propTag.vue'
|
||||
import PropListenerInfo from '@/components/XnWorkflow/nodes/prop/propListenerInfo.vue'
|
||||
import PreviewCustomForm from '@/components/XnWorkflow/nodes/common/previewCustomForm.vue'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import formContainer from '@/components/formContainer/index.vue'
|
||||
export default {
|
||||
components: {
|
||||
PropListenerInfo,
|
||||
templateGenerator,
|
||||
roleSelectorPlus,
|
||||
userSelectorPlus,
|
||||
posSelectorPlus,
|
||||
orgSelectorPlus,
|
||||
propTag,
|
||||
PreviewCustomForm,
|
||||
formContainer,
|
||||
Plus
|
||||
},
|
||||
props: {
|
||||
modelValue: { type: Object, default: () => {} },
|
||||
formFieldListValue: { type: Array, default: () => [] },
|
||||
recordData: { type: Object, default: () => {} },
|
||||
snTemplateArray: { type: Array, default: () => [] },
|
||||
printTemplateArray: { type: Array, default: () => [] },
|
||||
executionListenerArray: { type: Array, default: () => [] },
|
||||
executionListenerSelectorForCustomEventArray: { type: Array, default: () => [] },
|
||||
taskListenerArray: { type: Array, default: () => [] },
|
||||
selectorApiFunction: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
noticeInfoList: cloneDeep(config.noticeInfoList),
|
||||
// 摘要模板,因为要从传来的字段中取
|
||||
abstractStr: '',
|
||||
executionListenerInfo: cloneDeep(config.listener.processExecutionListenerInfo),
|
||||
// 自动去重类型
|
||||
processAutoDistinctTypeList: [
|
||||
{
|
||||
label: '当审批人和发起人是同一个人,审批自动通过',
|
||||
value: 'SAMPLE'
|
||||
},
|
||||
{
|
||||
label: '当同一审批人在流程中连续多次出现时,自动去重',
|
||||
value: 'MULTIPLE'
|
||||
}
|
||||
],
|
||||
drawer: false,
|
||||
modelTitle: '全局属性',
|
||||
activeKey: '1',
|
||||
childNode: this.modelValue,
|
||||
form: {},
|
||||
formData: {},
|
||||
fieldInfoLis: [],
|
||||
formVerify: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 监听内部数组,选了人员相关,我们就不提示
|
||||
alertShow() {
|
||||
if(this.form&&this.form.properties&&this.form.properties.participateInfo){
|
||||
return this.form.properties.participateInfo.length <= 0
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue(val) {
|
||||
this.childNode = val
|
||||
},
|
||||
childNode(val) {
|
||||
this.$emit('update:modelValue', val)
|
||||
},
|
||||
formFieldListValue(val) {
|
||||
// 获取主表名称
|
||||
const parentTableName = JSON.parse(this.recordData.tableJson).filter((item) => item.tableType === 'parent')[0]
|
||||
.tableName
|
||||
// 监听到字段列表后,将其转至定义的变量中
|
||||
this.fieldInfoLis = []
|
||||
// 不仅表单中有字段,而且还要必须选择了主表
|
||||
if (val.length > 0) {
|
||||
const fildLists = this.getListField(val)
|
||||
fildLists.forEach((item) => {
|
||||
const obj = {}
|
||||
// 判断是否是选择了表,并且选择了字段
|
||||
if (item.selectTable && item.selectColumn) {
|
||||
// 判断是否是主表的字段,并且是必填项
|
||||
const requireds = item.rules[0].required
|
||||
if ((item.selectTable === parentTableName) & requireds) {
|
||||
obj.label = item.label
|
||||
obj.value = item.model
|
||||
this.fieldInfoLis.push(obj)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showDrawer() {
|
||||
this.form = {}
|
||||
console.log(this.childNode,"hahhahahahah28992392399293");
|
||||
this.form = cloneDeep(this.childNode)
|
||||
this.formData = this.form&&this.form.properties&&this.form.properties.configInfo?this.form.properties.configInfo:{}
|
||||
this.drawer = true
|
||||
// 制作默认的摘要字段
|
||||
this.makeAbstractTemp()
|
||||
},
|
||||
// 制作默认显示的摘要信息
|
||||
makeAbstractTemp() {
|
||||
let temp = this.form&&this.form.properties&&this.form.properties.configInfo.processAbstractTemplate?this.form.properties.configInfo.processAbstractTemplate:''
|
||||
if (temp === '') {
|
||||
if (this.fieldInfoLis.length > 0) {
|
||||
let fieldInfoTemp = ''
|
||||
for (let a = 0; a < this.fieldInfoLis.length; a++) {
|
||||
// 最多3个摘要,按顺序而来
|
||||
if (a < 3) {
|
||||
const str = this.fieldInfoLis[a].label + ':' + this.fieldInfoLis[a].value
|
||||
if (a === 3 - 1 || a === this.fieldInfoLis.length - 1) {
|
||||
fieldInfoTemp = fieldInfoTemp + str
|
||||
} else {
|
||||
fieldInfoTemp = fieldInfoTemp + str + ','
|
||||
}
|
||||
}
|
||||
}
|
||||
temp = fieldInfoTemp
|
||||
}
|
||||
}
|
||||
},
|
||||
onFinish() {
|
||||
// 校验表单的正确性
|
||||
this.$refs.noticeFormRef
|
||||
.validate()
|
||||
.then((values) => {
|
||||
if (this.form.id === '') {
|
||||
this.form.id = this.$TOOL.snowyUuid()
|
||||
}
|
||||
// 获取输入的监听
|
||||
this.form.properties.executionListenerInfo = this.$refs.propListenerInfoRef.selectedListenerList()
|
||||
this.form.dataLegal = true
|
||||
this.form.properties.configInfo = values
|
||||
this.$emit('update:modelValue', this.form)
|
||||
this.drawer = false
|
||||
})
|
||||
.catch((info) => {
|
||||
this.formVerify = true
|
||||
setTimeout((e) => {
|
||||
this.formVerify = false
|
||||
}, 2000)
|
||||
})
|
||||
},
|
||||
// 选择参与人
|
||||
selectionParticipants(type) {
|
||||
console.log(type,"type=====----2--1-2-2-12-");
|
||||
let participateInfo = this.form&&this.form.properties&&this.form.properties.participateInfo?this.form.properties.participateInfo:[]
|
||||
let data = []
|
||||
console.log(this.form,"999992929232");
|
||||
if (participateInfo.length > 0) {
|
||||
participateInfo.forEach((item) => {
|
||||
if (item.key === type) {
|
||||
data.push(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (type === 'ORG') {
|
||||
this.$refs.orgselectorPlus.showOrgPlusModal(data)
|
||||
}
|
||||
if (type === 'ROLE') {
|
||||
this.$refs.roleselectorPlus.showRolePlusModal(data)
|
||||
}
|
||||
if (type === 'POSITION') {
|
||||
this.$refs.posselectorPlus.showPosPlusModal(data)
|
||||
}
|
||||
if (type === 'USER') {
|
||||
this.$refs.userselectorPlus.showUserPlusModal(data)
|
||||
}
|
||||
},
|
||||
// 回调函数,这几个选择人员相关的设计器,都是的
|
||||
callBack(value) {
|
||||
let participateInfo = this.form.properties.participateInfo
|
||||
if (participateInfo.length > 0) {
|
||||
let mark = 0
|
||||
for (let a = 0; a < participateInfo.length; a++) {
|
||||
if (value.key === participateInfo[a].key) {
|
||||
if (value.label === '') {
|
||||
participateInfo.splice(a, 1)
|
||||
} else {
|
||||
participateInfo[a] = value
|
||||
}
|
||||
mark = 1
|
||||
}
|
||||
}
|
||||
if (mark === 0) {
|
||||
participateInfo.push(value)
|
||||
}
|
||||
} else {
|
||||
this.form.properties.participateInfo.push(value)
|
||||
}
|
||||
},
|
||||
// 获取tag标签的内容
|
||||
getTagList(type) {
|
||||
const participateInfo = this.form&&this.form.properties&&this.form.properties.participateInfo?this.form.properties.participateInfo:[]
|
||||
if (participateInfo.length < 0) {
|
||||
return undefined
|
||||
} else {
|
||||
return participateInfo.find((item) => item.key === type)
|
||||
}
|
||||
},
|
||||
getListField(data) {
|
||||
let result = []
|
||||
// 递归遍历控件树
|
||||
const traverse = (array) => {
|
||||
array.forEach((element) => {
|
||||
if (element.type === 'grid' || element.type === 'tabs') {
|
||||
// 栅格布局 and 标签页
|
||||
element.columns.forEach((item) => {
|
||||
traverse(item.list)
|
||||
})
|
||||
} else if (element.type === 'card') {
|
||||
// 卡片布局 and 动态表格
|
||||
traverse(element.list)
|
||||
} else if (element.type === 'table') {
|
||||
// 表格布局
|
||||
element.trs.forEach((item) => {
|
||||
item.tds.forEach((val) => {
|
||||
traverse(val.list)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const type = element.type
|
||||
// 排除一些
|
||||
if (
|
||||
(type !== 'alert') &
|
||||
(type !== 'text') &
|
||||
(type !== 'divider') &
|
||||
(type !== 'batch') &
|
||||
(type !== 'html')
|
||||
) {
|
||||
result.push(element)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
traverse(data)
|
||||
return result
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.showDrawer()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,9 @@
|
||||
<script lang="ts" setup>
|
||||
import BpmnViewer from 'bpmn-js/lib/Viewer'
|
||||
import DefaultEmptyXML from './plugins/defaultEmpty'
|
||||
// import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
// import { formatDate } from '@/utils/formatTime'
|
||||
// import { isEmpty } from '@/utils/is'
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import { isEmpty } from '@/utils/is'
|
||||
|
||||
defineOptions({ name: 'MyProcessViewer' })
|
||||
|
||||
@@ -231,11 +231,11 @@ const highlightDiagram = async () => {
|
||||
}
|
||||
}
|
||||
})
|
||||
// if (!isEmpty(removeTaskDefinitionKeyList)) {
|
||||
// taskList.value = taskList.value.filter(
|
||||
// (item) => !removeTaskDefinitionKeyList.includes(item.taskDefinitionKey)
|
||||
// )
|
||||
// }
|
||||
if (!isEmpty(removeTaskDefinitionKeyList)) {
|
||||
taskList.value = taskList.value.filter(
|
||||
(item) => !removeTaskDefinitionKeyList.includes(item.taskDefinitionKey)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const getActivityHighlightCss = (activity) => {
|
||||
@@ -314,75 +314,75 @@ const elementHover = (element) => {
|
||||
if (!activity) {
|
||||
return
|
||||
}
|
||||
// if (!elementOverlayIds.value[element.value.id] && element.value.type !== 'bpmn:Process') {
|
||||
// let html = `<div class="element-overlays">
|
||||
// <p>Elemet id: ${element.value.id}</p>
|
||||
// <p>Elemet type: ${element.value.type}</p>
|
||||
// </div>` // 默认值
|
||||
// if (element.value.type === 'bpmn:StartEvent' && processInstance.value) {
|
||||
// html = `<p>发起人:${processInstance.value.startUser.nickname}</p>
|
||||
// <p>部门:${processInstance.value.startUser.deptName}</p>
|
||||
// <p>创建时间:${formatDate(processInstance.value.createTime)}`
|
||||
// } else if (element.value.type === 'bpmn:UserTask') {
|
||||
// let task = taskList.value.find((m) => m.id === activity.taskId) // 找到活动对应的 taskId
|
||||
// if (!task) {
|
||||
// return
|
||||
// }
|
||||
// // let optionData = getIntDictOptions(DICT_TYPE.BPM_TASK_STATUS)
|
||||
// let dataResult = ''
|
||||
// // optionData.forEach((element) => {
|
||||
// // if (element.value == task.status) {
|
||||
// // dataResult = element.label
|
||||
// // }
|
||||
// // })
|
||||
// html = `<p>审批人:${task.assigneeUser.nickname}</p>
|
||||
// <p>部门:${task.assigneeUser.deptName}</p>
|
||||
// <p>结果:${dataResult}</p>
|
||||
// <p>创建时间:${formatDate(task.createTime)}</p>`
|
||||
// // html = `<p>审批人:${task.assigneeUser.nickname}</p>
|
||||
// // <p>部门:${task.assigneeUser.deptName}</p>
|
||||
// // <p>结果:${getIntDictOptions(
|
||||
// // DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT,
|
||||
// // task.status
|
||||
// // )}</p>
|
||||
// // <p>创建时间:${formatDate(task.createTime)}</p>`
|
||||
// if (task.endTime) {
|
||||
// html += `<p>结束时间:${formatDate(task.endTime)}</p>`
|
||||
// }
|
||||
// if (task.reason) {
|
||||
// html += `<p>审批建议:${task.reason}</p>`
|
||||
// }
|
||||
// } else if (element.value.type === 'bpmn:ServiceTask' && processInstance.value) {
|
||||
// if (activity.startTime > 0) {
|
||||
// html = `<p>创建时间:${formatDate(activity.startTime)}</p>`
|
||||
// }
|
||||
// if (activity.endTime > 0) {
|
||||
// html += `<p>结束时间:${formatDate(activity.endTime)}</p>`
|
||||
// }
|
||||
// console.log(html)
|
||||
// } else if (element.value.type === 'bpmn:EndEvent' && processInstance.value) {
|
||||
// // let optionData = getIntDictOptions(DICT_TYPE.BPM_TASK_STATUS)
|
||||
// let dataResult = ''
|
||||
// // optionData.forEach((element) => {
|
||||
// // if (element.value == processInstance.value.status) {
|
||||
// // dataResult = element.label
|
||||
// // }
|
||||
// // })
|
||||
// html = `<p>结果:${dataResult}</p>`
|
||||
// // html = `<p>结果:${getIntDictOptions(
|
||||
// // DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT,
|
||||
// // processInstance.value.status
|
||||
// // )}</p>`
|
||||
// if (processInstance.value.endTime) {
|
||||
// html += `<p>结束时间:${formatDate(processInstance.value.endTime)}</p>`
|
||||
// }
|
||||
// }
|
||||
// // console.log(html, 'html111111111111111')
|
||||
// elementOverlayIds.value[element.value.id] = toRaw(overlays.value)?.add(element.value, {
|
||||
// position: { left: 0, bottom: 0 },
|
||||
// html: `<div class="element-overlays">${html}</div>`
|
||||
// })
|
||||
// }
|
||||
if (!elementOverlayIds.value[element.value.id] && element.value.type !== 'bpmn:Process') {
|
||||
let html = `<div class="element-overlays">
|
||||
<p>Elemet id: ${element.value.id}</p>
|
||||
<p>Elemet type: ${element.value.type}</p>
|
||||
</div>` // 默认值
|
||||
if (element.value.type === 'bpmn:StartEvent' && processInstance.value) {
|
||||
html = `<p>发起人:${processInstance.value.startUser.nickname}</p>
|
||||
<p>部门:${processInstance.value.startUser.deptName}</p>
|
||||
<p>创建时间:${formatDate(processInstance.value.createTime)}`
|
||||
} else if (element.value.type === 'bpmn:UserTask') {
|
||||
let task = taskList.value.find((m) => m.id === activity.taskId) // 找到活动对应的 taskId
|
||||
if (!task) {
|
||||
return
|
||||
}
|
||||
let optionData = getIntDictOptions(DICT_TYPE.BPM_TASK_STATUS)
|
||||
let dataResult = ''
|
||||
optionData.forEach((element) => {
|
||||
if (element.value == task.status) {
|
||||
dataResult = element.label
|
||||
}
|
||||
})
|
||||
html = `<p>审批人:${task.assigneeUser.nickname}</p>
|
||||
<p>部门:${task.assigneeUser.deptName}</p>
|
||||
<p>结果:${dataResult}</p>
|
||||
<p>创建时间:${formatDate(task.createTime)}</p>`
|
||||
// html = `<p>审批人:${task.assigneeUser.nickname}</p>
|
||||
// <p>部门:${task.assigneeUser.deptName}</p>
|
||||
// <p>结果:${getIntDictOptions(
|
||||
// DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT,
|
||||
// task.status
|
||||
// )}</p>
|
||||
// <p>创建时间:${formatDate(task.createTime)}</p>`
|
||||
if (task.endTime) {
|
||||
html += `<p>结束时间:${formatDate(task.endTime)}</p>`
|
||||
}
|
||||
if (task.reason) {
|
||||
html += `<p>审批建议:${task.reason}</p>`
|
||||
}
|
||||
} else if (element.value.type === 'bpmn:ServiceTask' && processInstance.value) {
|
||||
if (activity.startTime > 0) {
|
||||
html = `<p>创建时间:${formatDate(activity.startTime)}</p>`
|
||||
}
|
||||
if (activity.endTime > 0) {
|
||||
html += `<p>结束时间:${formatDate(activity.endTime)}</p>`
|
||||
}
|
||||
console.log(html)
|
||||
} else if (element.value.type === 'bpmn:EndEvent' && processInstance.value) {
|
||||
let optionData = getIntDictOptions(DICT_TYPE.BPM_TASK_STATUS)
|
||||
let dataResult = ''
|
||||
optionData.forEach((element) => {
|
||||
if (element.value == processInstance.value.status) {
|
||||
dataResult = element.label
|
||||
}
|
||||
})
|
||||
html = `<p>结果:${dataResult}</p>`
|
||||
// html = `<p>结果:${getIntDictOptions(
|
||||
// DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT,
|
||||
// processInstance.value.status
|
||||
// )}</p>`
|
||||
if (processInstance.value.endTime) {
|
||||
html += `<p>结束时间:${formatDate(processInstance.value.endTime)}</p>`
|
||||
}
|
||||
}
|
||||
// console.log(html, 'html111111111111111')
|
||||
elementOverlayIds.value[element.value.id] = toRaw(overlays.value)?.add(element.value, {
|
||||
position: { left: 0, bottom: 0 },
|
||||
html: `<div class="element-overlays">${html}</div>`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 流程图的元素被 out
|
||||
|
||||
@@ -8,7 +8,7 @@ import { isAny } from 'bpmn-js/lib/features/modeling/util/ModelingUtil'
|
||||
|
||||
import { getChildLanes } from 'bpmn-js/lib/features/modeling/util/LaneUtil'
|
||||
|
||||
// import { hasPrimaryModifier } from 'diagram-js/lib/util/Mouse'
|
||||
import { hasPrimaryModifier } from 'diagram-js/lib/util/Mouse'
|
||||
|
||||
/**
|
||||
* A provider for BPMN 2.0 elements context pad
|
||||
@@ -51,9 +51,9 @@ export default function ContextPadProvider(
|
||||
const context = event.context,
|
||||
shape = context.shape
|
||||
|
||||
// if (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) {
|
||||
// return
|
||||
// }
|
||||
if (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) {
|
||||
return
|
||||
}
|
||||
|
||||
const entries = contextPad.getEntries(shape)
|
||||
|
||||
|
||||
@@ -8,4 +8,4 @@ import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
|
||||
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
|
||||
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
|
||||
|
||||
export { MyProcessDesigner, MyProcessPenal,MyProcessViewer }
|
||||
export { MyProcessDesigner, MyProcessPenal, MyProcessViewer }
|
||||
|
||||
@@ -1,100 +1,125 @@
|
||||
<template>
|
||||
<div
|
||||
class='process-panel__container'
|
||||
:style="{ width: `${width}px`, height: `700px`, overflow: 'auto', background: '#fff' }"
|
||||
>
|
||||
<el-collapse v-model='activeTab'>
|
||||
<el-collapse-item name='base'>
|
||||
<!-- class="panel-tab__title" -->
|
||||
<template #title>
|
||||
<Icon name='el-icon-InfoFilled' />
|
||||
常规
|
||||
</template>
|
||||
<ElementBaseInfo
|
||||
:id-edit-disabled='idEditDisabled'
|
||||
:business-object='elementBusinessObject'
|
||||
:type='elementType'
|
||||
:model='model'
|
||||
/>
|
||||
</el-collapse-item>
|
||||
<!-- <el-collapse-item name="condition" v-if="elementType === 'Process'" key="message">
|
||||
<template #title>
|
||||
<Icon name="el-icon-Comment" />
|
||||
消息与信号
|
||||
</template>
|
||||
<SignalAndMassage />
|
||||
</el-collapse-item>-->
|
||||
<el-collapse-item name='condition' v-if='conditionFormVisible' key='condition'>
|
||||
<template #title>
|
||||
<Icon name='el-icon-Promotion' />
|
||||
流转条件
|
||||
</template>
|
||||
<FlowCondition :business-object='elementBusinessObject' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='condition' v-if='formVisible' key='form'>
|
||||
<template #title>
|
||||
<Icon name='el-icon-List' />
|
||||
表单
|
||||
</template>
|
||||
<ElementForm :id='elementId' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='task' v-if="elementType.indexOf('Task') !== -1" key='task'>
|
||||
<template #title>
|
||||
<Icon name='el-icon-Checked' />
|
||||
任务(审批人)
|
||||
</template>
|
||||
<ElementTask :id='elementId' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<!-- <el-collapse-item name='multiInstance' v-if="elementType.indexOf('Task') !== -1" key='multiInstance'>-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <Icon name='el-icon-HelpFilled' />-->
|
||||
<!-- 多实例(会签配置)-->
|
||||
<!-- </template>-->
|
||||
<!-- <ElementMultiInstance :business-object='elementBusinessObject' :type='elementType' />-->
|
||||
<!-- </el-collapse-item>-->
|
||||
<!-- <el-collapse-item name='listeners' key='listeners'>-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <Icon name='el-icon-BellFilled' />-->
|
||||
<!-- 执行监听器-->
|
||||
<!-- </template>-->
|
||||
<!-- <ElementListeners :id='elementId' :type='elementType' />-->
|
||||
<!-- </el-collapse-item>-->
|
||||
<!-- <el-collapse-item name='taskListeners' v-if="elementType === 'UserTask'" key='taskListeners'>-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <Icon name='el-icon-BellFilled' />-->
|
||||
<!-- 任务监听器-->
|
||||
<!-- </template>-->
|
||||
<!-- <UserTaskListeners :id='elementId' :type='elementType' />-->
|
||||
<!-- </el-collapse-item>-->
|
||||
<!-- <el-collapse-item name='extensions' key='extensions'>-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <Icon name='el-icon-CirclePlusFilled' />-->
|
||||
<!-- 扩展属性-->
|
||||
<!-- </template>-->
|
||||
<!-- <ElementProperties :id='elementId' :type='elementType' />-->
|
||||
<!-- </el-collapse-item>-->
|
||||
<el-collapse-item name='other' key='other'>
|
||||
<template #title>
|
||||
<Icon name='el-icon-Promotion' />
|
||||
其他
|
||||
</template>
|
||||
<ElementOtherConfig :id='elementId' />
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
<div class='process-panel__container' :style='{ width: `${width}px` }'>
|
||||
<el-collapse v-model='activeTab'>
|
||||
<el-collapse-item name='base'>
|
||||
<!-- class="panel-tab__title" -->
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
常规
|
||||
</template
|
||||
>
|
||||
<ElementBaseInfo
|
||||
:id-edit-disabled='idEditDisabled'
|
||||
:business-object='elementBusinessObject'
|
||||
:type='elementType'
|
||||
:model='model'
|
||||
/>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='condition' v-if="elementType === 'Process'" key='message'>
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<Comment />
|
||||
</el-icon>
|
||||
消息与信号
|
||||
</template>
|
||||
<signal-and-massage />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='condition' v-if='conditionFormVisible' key='condition'>
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<Promotion />
|
||||
</el-icon>
|
||||
流转条件
|
||||
</template>
|
||||
<flow-condition :business-object='elementBusinessObject' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='condition' v-if='formVisible' key='form'>
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<List />
|
||||
</el-icon>
|
||||
表单
|
||||
</template>
|
||||
<element-form :id='elementId' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='task' v-if="elementType.indexOf('Task') !== -1" key='task'>
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<Checked />
|
||||
</el-icon>
|
||||
任务(审批人)
|
||||
</template>
|
||||
<element-task :id='elementId' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item
|
||||
name='multiInstance'
|
||||
v-if="elementType.indexOf('Task') !== -1"
|
||||
key='multiInstance'
|
||||
>
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<HelpFilled />
|
||||
</el-icon>
|
||||
多实例(会签配置)
|
||||
</template>
|
||||
<element-multi-instance :business-object='elementBusinessObject' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='listeners' key='listeners'>
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<BellFilled />
|
||||
</el-icon>
|
||||
执行监听器
|
||||
</template>
|
||||
<element-listeners :id='elementId' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='taskListeners' v-if="elementType === 'UserTask'" key='taskListeners'>
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<BellFilled />
|
||||
</el-icon>
|
||||
任务监听器
|
||||
</template>
|
||||
<user-task-listeners :id='elementId' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='extensions' key='extensions'>
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<CirclePlusFilled />
|
||||
</el-icon>
|
||||
扩展属性
|
||||
</template>
|
||||
<element-properties :id='elementId' :type='elementType' />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name='other' key='other'>
|
||||
<template #title>
|
||||
<el-icon :size='20'>
|
||||
<Promotion />
|
||||
</el-icon>
|
||||
其他
|
||||
</template>
|
||||
<element-other-config :id='elementId' />
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</template>
|
||||
<script lang='ts' setup>
|
||||
import { onMounted, provide, ref, watch, onBeforeUnmount } from 'vue'
|
||||
import {CirclePlusFilled, BellFilled,HelpFilled, Checked, List, Promotion, Comment, InfoFilled } from '@element-plus/icons-vue'
|
||||
|
||||
|
||||
import ElementBaseInfo from './base/ElementBaseInfo.vue'
|
||||
import ElementOtherConfig from './other/ElementOtherConfig.vue'
|
||||
import ElementTask from './task/ElementTask.vue'
|
||||
// import ElementMultiInstance from './multi-instance/ElementMultiInstance.vue'
|
||||
import ElementMultiInstance from './multi-instance/ElementMultiInstance.vue'
|
||||
import FlowCondition from './flow-condition/FlowCondition.vue'
|
||||
// import SignalAndMassage from './signal-message/SignalAndMessage.vue'
|
||||
// import ElementListeners from './listeners/ElementListeners.vue'
|
||||
// import ElementProperties from './properties/ElementProperties.vue'
|
||||
import ElementForm from './form/ElementForm.vue'
|
||||
// import UserTaskListeners from './listeners/UserTaskListeners.vue'
|
||||
import SignalAndMassage from './signal-message/SignalAndMessage.vue'
|
||||
import ElementListeners from './listeners/ElementListeners.vue'
|
||||
import ElementProperties from './properties/ElementProperties.vue'
|
||||
// import ElementForm from './form/ElementForm.vue'
|
||||
import UserTaskListeners from './listeners/UserTaskListeners.vue'
|
||||
import ElementForm from '@/components/bpmnProcessDesigner/package/penal/form/ElementForm.vue'
|
||||
|
||||
defineOptions({ name: 'MyPropertiesPanel' })
|
||||
|
||||
@@ -105,24 +130,24 @@ defineOptions({ name: 'MyPropertiesPanel' })
|
||||
* @Date 2021年3月31日18:57:51
|
||||
*/
|
||||
const props = defineProps({
|
||||
bpmnModeler: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
}
|
||||
},
|
||||
prefix: {
|
||||
type: String,
|
||||
default: 'camunda'
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 480
|
||||
},
|
||||
idEditDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
model: Object // 流程模型的数据
|
||||
bpmnModeler: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
}
|
||||
},
|
||||
prefix: {
|
||||
type: String,
|
||||
default: 'camunda'
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 480
|
||||
},
|
||||
idEditDisabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
model: Object // 流程模型的数据
|
||||
})
|
||||
|
||||
const activeTab = ref('base')
|
||||
@@ -141,94 +166,94 @@ const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||
const unwatchBpmn = watch(
|
||||
() => props.bpmnModeler,
|
||||
() => {
|
||||
// 避免加载时 流程图 并未加载完成
|
||||
if (!props.bpmnModeler) {
|
||||
console.log('缺少props.bpmnModeler')
|
||||
return
|
||||
}
|
||||
// 避免加载时 流程图 并未加载完成
|
||||
if (!props.bpmnModeler) {
|
||||
console.log('缺少props.bpmnModeler')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('props.bpmnModeler 有值了!!!')
|
||||
const w = window as any
|
||||
w.bpmnInstances = {
|
||||
modeler: props.bpmnModeler,
|
||||
modeling: props.bpmnModeler.get('modeling'),
|
||||
moddle: props.bpmnModeler.get('moddle'),
|
||||
eventBus: props.bpmnModeler.get('eventBus'),
|
||||
bpmnFactory: props.bpmnModeler.get('bpmnFactory'),
|
||||
elementFactory: props.bpmnModeler.get('elementFactory'),
|
||||
elementRegistry: props.bpmnModeler.get('elementRegistry'),
|
||||
replace: props.bpmnModeler.get('replace'),
|
||||
selection: props.bpmnModeler.get('selection')
|
||||
}
|
||||
console.log('props.bpmnModeler 有值了!!!')
|
||||
const w = window as any
|
||||
w.bpmnInstances = {
|
||||
modeler: props.bpmnModeler,
|
||||
modeling: props.bpmnModeler.get('modeling'),
|
||||
moddle: props.bpmnModeler.get('moddle'),
|
||||
eventBus: props.bpmnModeler.get('eventBus'),
|
||||
bpmnFactory: props.bpmnModeler.get('bpmnFactory'),
|
||||
elementFactory: props.bpmnModeler.get('elementFactory'),
|
||||
elementRegistry: props.bpmnModeler.get('elementRegistry'),
|
||||
replace: props.bpmnModeler.get('replace'),
|
||||
selection: props.bpmnModeler.get('selection')
|
||||
}
|
||||
|
||||
console.log(bpmnInstances(), 'window.bpmnInstances')
|
||||
getActiveElement()
|
||||
unwatchBpmn()
|
||||
// console.log(bpmnInstances(), 'window.bpmnInstances')
|
||||
getActiveElement()
|
||||
unwatchBpmn()
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
const getActiveElement = () => {
|
||||
// 初始第一个选中元素 bpmn:Process
|
||||
// 初始第一个选中元素 bpmn:Process
|
||||
initFormOnChanged(null)
|
||||
props.bpmnModeler.on('import.done', (e) => {
|
||||
// console.log(e, 'eeeee')
|
||||
initFormOnChanged(null)
|
||||
props.bpmnModeler.on('import.done', e => {
|
||||
console.log(e, 'eeeee')
|
||||
initFormOnChanged(null)
|
||||
})
|
||||
// 监听选择事件,修改当前激活的元素以及表单
|
||||
props.bpmnModeler.on('selection.changed', ({ newSelection }) => {
|
||||
initFormOnChanged(newSelection[0] || null)
|
||||
})
|
||||
props.bpmnModeler.on('element.changed', ({ element }) => {
|
||||
// 保证 修改 "默认流转路径" 类似需要修改多个元素的事件发生的时候,更新表单的元素与原选中元素不一致。
|
||||
if (element && element.id === elementId.value) {
|
||||
initFormOnChanged(element)
|
||||
}
|
||||
})
|
||||
})
|
||||
// 监听选择事件,修改当前激活的元素以及表单
|
||||
props.bpmnModeler.on('selection.changed', ({ newSelection }) => {
|
||||
initFormOnChanged(newSelection[0] || null)
|
||||
})
|
||||
props.bpmnModeler.on('element.changed', ({ element }) => {
|
||||
// 保证 修改 "默认流转路径" 类似需要修改多个元素的事件发生的时候,更新表单的元素与原选中元素不一致。
|
||||
if (element && element.id === elementId.value) {
|
||||
initFormOnChanged(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 初始化数据
|
||||
const initFormOnChanged = element => {
|
||||
let activatedElement = element
|
||||
if (!activatedElement) {
|
||||
activatedElement =
|
||||
bpmnInstances().elementRegistry.find(el => el.type === 'bpmn:Process') ??
|
||||
bpmnInstances().elementRegistry.find(el => el.type === 'bpmn:Collaboration')
|
||||
}
|
||||
if (!activatedElement) return
|
||||
console.log(`
|
||||
----------
|
||||
select element changed:
|
||||
id: ${activatedElement.id}
|
||||
type: ${activatedElement.businessObject.$type}
|
||||
----------
|
||||
`)
|
||||
console.log('businessObject: ', activatedElement.businessObject)
|
||||
bpmnInstances().bpmnElement = activatedElement
|
||||
bpmnElement.value = activatedElement
|
||||
elementId.value = activatedElement.id
|
||||
elementType.value = activatedElement.type.split(':')[1] || ''
|
||||
elementBusinessObject.value = JSON.parse(JSON.stringify(activatedElement.businessObject))
|
||||
conditionFormVisible.value = !!(
|
||||
elementType.value === 'SequenceFlow' &&
|
||||
activatedElement.source &&
|
||||
activatedElement.source.type.indexOf('StartEvent') === -1
|
||||
)
|
||||
formVisible.value = elementType.value === 'UserTask' || elementType.value === 'StartEvent'
|
||||
const initFormOnChanged = (element) => {
|
||||
let activatedElement = element
|
||||
if (!activatedElement) {
|
||||
activatedElement =
|
||||
bpmnInstances().elementRegistry.find((el) => el.type === 'bpmn:Process') ??
|
||||
bpmnInstances().elementRegistry.find((el) => el.type === 'bpmn:Collaboration')
|
||||
}
|
||||
if (!activatedElement) return
|
||||
// console.log(`
|
||||
// ----------
|
||||
// select element changed:
|
||||
// id: ${activatedElement.id}
|
||||
// type: ${activatedElement.businessObject.$type}
|
||||
// ----------
|
||||
// `)
|
||||
// console.log('businessObject: ', activatedElement.businessObject)
|
||||
bpmnInstances().bpmnElement = activatedElement
|
||||
bpmnElement.value = activatedElement
|
||||
elementId.value = activatedElement.id
|
||||
elementType.value = activatedElement.type.split(':')[1] || ''
|
||||
elementBusinessObject.value = JSON.parse(JSON.stringify(activatedElement.businessObject))
|
||||
conditionFormVisible.value = !!(
|
||||
elementType.value === 'SequenceFlow' &&
|
||||
activatedElement.source &&
|
||||
activatedElement.source.type.indexOf('StartEvent') === -1
|
||||
)
|
||||
formVisible.value = elementType.value === 'UserTask' || elementType.value === 'StartEvent'
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
const w = window as any
|
||||
w.bpmnInstances = null
|
||||
console.log(props, 'props1')
|
||||
console.log(props.bpmnModeler, 'props.bpmnModeler1')
|
||||
const w = window as any
|
||||
w.bpmnInstances = null
|
||||
// console.log(props, 'props1')
|
||||
// console.log(props.bpmnModeler, 'props.bpmnModeler1')
|
||||
})
|
||||
|
||||
watch(
|
||||
() => elementId.value,
|
||||
() => {
|
||||
activeTab.value = 'base'
|
||||
activeTab.value = 'base'
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -1,177 +1,158 @@
|
||||
<template>
|
||||
<div class="panel-tab__content">
|
||||
<el-form label-width="90px" v-if="needProps.type != 'bpmn:Process'" :model="needProps" :rules="rules">
|
||||
<!-- <div v-if="needProps.type == 'bpmn:Process'">
|
||||
<el-form-item label="流程标识" prop="id">
|
||||
<el-input
|
||||
v-model="needProps.id"
|
||||
:disabled="needProps.id !== undefined && needProps.id.length > 0"
|
||||
placeholder="请输入流标标识"
|
||||
@change="handleKeyUpdate"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div> -->
|
||||
<div>
|
||||
<el-form-item label="ID">
|
||||
<el-input v-model="elementBaseInfo.id" clearable @change="updateBaseInfo('id')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="名称">
|
||||
<el-input v-model="elementBaseInfo.name" clearable @change="updateBaseInfo('name')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input
|
||||
v-model="elementBaseInfo.documentation"
|
||||
clearable
|
||||
@change="updateBaseInfo('documentation')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="panel-tab__content">
|
||||
<el-form label-width="90px" :model="needProps" :rules="rules">
|
||||
<div v-if="needProps.type == 'bpmn:Process'">
|
||||
<!-- 如果是 Process 信息的时候,使用自定义表单 -->
|
||||
<el-form-item label="流程标识" prop="id">
|
||||
<el-input
|
||||
v-model="needProps.id"
|
||||
placeholder="请输入流标标识"
|
||||
:disabled="needProps.id !== undefined && needProps.id.length > 0"
|
||||
@change="handleKeyUpdate"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="流程名称" prop="name">
|
||||
<el-input
|
||||
v-model="needProps.name"
|
||||
placeholder="请输入流程名称"
|
||||
clearable
|
||||
@change="handleNameUpdate"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-form-item label="ID">
|
||||
<el-input v-model="elementBaseInfo.id" clearable @change="updateBaseInfo('id')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="名称">
|
||||
<el-input v-model="elementBaseInfo.name" clearable @change="updateBaseInfo('name')" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref, watch, onBeforeUnmount, toRaw } from 'vue'
|
||||
defineOptions({ name: 'ElementBaseInfo' })
|
||||
|
||||
const props = defineProps({
|
||||
businessObject: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
businessObject: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
})
|
||||
const needProps = ref<any>({})
|
||||
const bpmnElement = ref()
|
||||
const elementBaseInfo = ref<any>({})
|
||||
|
||||
// 流程表单的下拉框的数据
|
||||
// const forms = ref([])
|
||||
// 流程模型的校验
|
||||
const rules = reactive({
|
||||
id: [{ required: true, message: '流程标识不能为空', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '流程名称不能为空', trigger: 'blur' }]
|
||||
id: [{ required: true, message: '流程标识不能为空', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '流程名称不能为空', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||
const resetBaseInfo = () => {
|
||||
console.log(window, 'window')
|
||||
console.log(bpmnElement.value, 'bpmnElement')
|
||||
// console.log(window, 'window')
|
||||
// console.log(bpmnElement.value, 'bpmnElement')
|
||||
|
||||
bpmnElement.value = bpmnInstances()?.bpmnElement
|
||||
// console.log(bpmnElement.value, 'resetBaseInfo11111111111')
|
||||
elementBaseInfo.value = bpmnElement.value.businessObject
|
||||
needProps.value['type'] = bpmnElement.value.businessObject.$type
|
||||
// elementBaseInfo.value['typess'] = bpmnElement.value.businessObject.$type
|
||||
bpmnElement.value = bpmnInstances()?.bpmnElement
|
||||
// console.log(bpmnElement.value, 'resetBaseInfo11111111111')
|
||||
elementBaseInfo.value = bpmnElement.value.businessObject
|
||||
needProps.value['type'] = bpmnElement.value.businessObject.$type
|
||||
// elementBaseInfo.value['typess'] = bpmnElement.value.businessObject.$type
|
||||
|
||||
// elementBaseInfo.value = JSON.parse(JSON.stringify(bpmnElement.value.businessObject))
|
||||
// console.log(elementBaseInfo.value, 'elementBaseInfo22222222222')
|
||||
// elementBaseInfo.value = JSON.parse(JSON.stringify(bpmnElement.value.businessObject))
|
||||
// console.log(elementBaseInfo.value, 'elementBaseInfo22222222222')
|
||||
}
|
||||
const handleKeyUpdate = value => {
|
||||
//校验 value 的值,只有 XML NCName 通过的情况下,才进行赋值。否则,会导致流程图报错,无法绘制的问题
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
if (!value.match(/[a-zA-Z_][\-_.0-9a-zA-Z$]*/)) {
|
||||
console.log('key 不满足 XML NCName 规则,所以不进行赋值')
|
||||
return
|
||||
}
|
||||
console.log('key 满足 XML NCName 规则,所以进行赋值')
|
||||
const handleKeyUpdate = (value) => {
|
||||
// 校验 value 的值,只有 XML NCName 通过的情况下,才进行赋值。否则,会导致流程图报错,无法绘制的问题
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
if (!value.match(/[a-zA-Z_][\-_.0-9a-zA-Z$]*/)) {
|
||||
console.log('key 不满足 XML NCName 规则,所以不进行赋值')
|
||||
return
|
||||
}
|
||||
// console.log('key 满足 XML NCName 规则,所以进行赋值')
|
||||
|
||||
// 在 BPMN 的 XML 中,流程标识 key,其实对应的是 id 节点
|
||||
// 在 BPMN 的 XML 中,流程标识 key,其实对应的是 id 节点
|
||||
elementBaseInfo.value['id'] = value
|
||||
|
||||
elementBaseInfo.value['id'] = value
|
||||
|
||||
setTimeout(() => {
|
||||
updateBaseInfo('id')
|
||||
}, 100)
|
||||
setTimeout(() => {
|
||||
updateBaseInfo('id')
|
||||
}, 100)
|
||||
}
|
||||
const handleNameUpdate = value => {
|
||||
console.log(elementBaseInfo, 'elementBaseInfo')
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
elementBaseInfo.value['name'] = value
|
||||
const handleNameUpdate = (value) => {
|
||||
// console.log(elementBaseInfo, 'elementBaseInfo')
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
elementBaseInfo.value['name'] = value
|
||||
|
||||
setTimeout(() => {
|
||||
updateBaseInfo('name')
|
||||
}, 100)
|
||||
setTimeout(() => {
|
||||
updateBaseInfo('name')
|
||||
}, 100)
|
||||
}
|
||||
const handleClassifyUpdate = value => {
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
elementBaseInfo.value['processCategory'] = value
|
||||
|
||||
setTimeout(() => {
|
||||
updateBaseInfo('processCategory')
|
||||
}, 100)
|
||||
}
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
// if (needProps.value.id == undefined) {
|
||||
// // handleKeyUpdate(Math.random().toString(36).slice(-8))\
|
||||
// console.log(elementBaseInfo.value, '123')
|
||||
// }
|
||||
}, 10)
|
||||
})
|
||||
// const handleDescriptionUpdate=(value)=> {
|
||||
// TODO 芋艿:documentation 暂时无法修改,后续在看看
|
||||
// this.elementBaseInfo['documentation'] = value;
|
||||
// this.updateBaseInfo('documentation');
|
||||
// }
|
||||
const updateBaseInfo = key => {
|
||||
console.log(key, 'key')
|
||||
// 触发 elementBaseInfo 对应的字段
|
||||
const attrObj = Object.create(null)
|
||||
// console.log(attrObj, 'attrObj')
|
||||
attrObj[key] = elementBaseInfo.value[key]
|
||||
// console.log(attrObj, 'attrObj111')
|
||||
// const attrObj = {
|
||||
// id: elementBaseInfo.value[key]
|
||||
// // di: { id: `${elementBaseInfo.value[key]}_di` }
|
||||
// }
|
||||
// console.log(elementBaseInfo, 'elementBaseInfo11111111111')
|
||||
needProps.value = { ...elementBaseInfo.value, ...needProps.value }
|
||||
const updateBaseInfo = (key) => {
|
||||
// console.log(key, 'key')
|
||||
// 触发 elementBaseInfo 对应的字段
|
||||
const attrObj = Object.create(null)
|
||||
// console.log(attrObj, 'attrObj')
|
||||
attrObj[key] = elementBaseInfo.value[key]
|
||||
// console.log(attrObj, 'attrObj111')
|
||||
// const attrObj = {
|
||||
// id: elementBaseInfo.value[key]
|
||||
// // di: { id: `${elementBaseInfo.value[key]}_di` }
|
||||
// }
|
||||
// console.log(elementBaseInfo, 'elementBaseInfo11111111111')
|
||||
needProps.value = { ...elementBaseInfo.value, ...needProps.value }
|
||||
|
||||
if (key === 'id') {
|
||||
// console.log('jinru')
|
||||
console.log(window, 'window')
|
||||
console.log(bpmnElement.value, 'bpmnElement')
|
||||
console.log(toRaw(bpmnElement.value), 'bpmnElement')
|
||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||
id: elementBaseInfo.value[key],
|
||||
di: { id: `${elementBaseInfo.value[key]}_di` }
|
||||
})
|
||||
} else {
|
||||
console.log(attrObj, 'attrObj')
|
||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), attrObj)
|
||||
}
|
||||
if (key === 'id') {
|
||||
// console.log('jinru')
|
||||
// console.log(window, 'window')
|
||||
// console.log(bpmnElement.value, 'bpmnElement')
|
||||
// console.log(toRaw(bpmnElement.value), 'bpmnElement')
|
||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||
id: elementBaseInfo.value[key],
|
||||
di: { id: `${elementBaseInfo.value[key]}_di` }
|
||||
})
|
||||
} else {
|
||||
// console.log(attrObj, 'attrObj')
|
||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), attrObj)
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.businessObject,
|
||||
val => {
|
||||
// console.log(val, 'val11111111111111111111')
|
||||
if (val) {
|
||||
// nextTick(() => {
|
||||
resetBaseInfo()
|
||||
// })
|
||||
}
|
||||
() => props.businessObject,
|
||||
(val) => {
|
||||
// console.log(val, 'val11111111111111111111')
|
||||
if (val) {
|
||||
// nextTick(() => {
|
||||
resetBaseInfo()
|
||||
// })
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.model?.key,
|
||||
val => {
|
||||
// 针对上传的 bpmn 流程图时,保证 key 和 name 的更新
|
||||
if (val) {
|
||||
handleKeyUpdate(props.model.key)
|
||||
handleNameUpdate(props.model.name)
|
||||
}
|
||||
() => props.model?.key,
|
||||
(val) => {
|
||||
// 针对上传的 bpmn 流程图时,保证 key 和 name 的更新
|
||||
if (val) {
|
||||
handleKeyUpdate(props.model.key)
|
||||
handleNameUpdate(props.model.name)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// watch(
|
||||
@@ -194,6 +175,6 @@ watch(
|
||||
// }
|
||||
// }
|
||||
onBeforeUnmount(() => {
|
||||
bpmnElement.value = null
|
||||
bpmnElement.value = null
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref, watch, onBeforeUnmount,toRaw,nextTick } from 'vue'
|
||||
defineOptions({ name: 'FlowCondition' })
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
@@ -1,239 +1,239 @@
|
||||
<template>
|
||||
<div class='panel-tab__content'>
|
||||
<el-form label-width='80px'>
|
||||
<el-form-item label='流程表单'>
|
||||
<!-- <el-input v-model="formKey" clearable @change="updateElementFormKey" />-->
|
||||
<el-select v-model='formKey' clearable @change='updateElementFormKey'>
|
||||
<el-option v-for='form in formList' :key='form.id' :label='form.name' :value='"key_"+form.id' />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="业务标识">-->
|
||||
<!-- <el-select v-model="businessKey" @change="updateElementBusinessKey">-->
|
||||
<!-- <el-option v-for="i in fieldList" :key="i.id" :value="i.id" :label="i.label" />-->
|
||||
<!-- <el-option label="无" value="" />-->
|
||||
<!-- </el-select>-->
|
||||
<!-- </el-form-item>-->
|
||||
</el-form>
|
||||
<div class="panel-tab__content">
|
||||
<el-form label-width="80px">
|
||||
<el-form-item label="流程表单">
|
||||
<!-- <el-input v-model="formKey" clearable @change="updateElementFormKey" />-->
|
||||
<el-select v-model="formKey" clearable @change="updateElementFormKey">
|
||||
<el-option v-for="form in formList" :key="form.id" :label="form.name" :value="form.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="业务标识">-->
|
||||
<!-- <el-select v-model="businessKey" @change="updateElementBusinessKey">-->
|
||||
<!-- <el-option v-for="i in fieldList" :key="i.id" :value="i.id" :label="i.label" />-->
|
||||
<!-- <el-option label="无" value="" />-->
|
||||
<!-- </el-select>-->
|
||||
<!-- </el-form-item>-->
|
||||
</el-form>
|
||||
|
||||
<!--字段列表-->
|
||||
<!-- <div class="element-property list-property">-->
|
||||
<!-- <el-divider><Icon icon="ep:coin" /> 表单字段</el-divider>-->
|
||||
<!-- <el-table :data="fieldList" max-height="240" fit border>-->
|
||||
<!-- <el-table-column label="序号" type="index" width="50px" />-->
|
||||
<!-- <el-table-column label="字段名称" prop="label" min-width="80px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column-->
|
||||
<!-- label="字段类型"-->
|
||||
<!-- prop="type"-->
|
||||
<!-- min-width="80px"-->
|
||||
<!-- :formatter="(row) => fieldType[row.type] || row.type"-->
|
||||
<!-- show-overflow-tooltip-->
|
||||
<!-- />-->
|
||||
<!-- <el-table-column-->
|
||||
<!-- label="默认值"-->
|
||||
<!-- prop="defaultValue"-->
|
||||
<!-- min-width="80px"-->
|
||||
<!-- show-overflow-tooltip-->
|
||||
<!-- />-->
|
||||
<!-- <el-table-column label="操作" width="90px">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-button type="primary" link @click="openFieldForm(scope, scope.$index)"-->
|
||||
<!-- >编辑</el-button-->
|
||||
<!-- >-->
|
||||
<!-- <el-divider direction="vertical" />-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- style="color: #ff4d4f"-->
|
||||
<!-- @click="removeField(scope, scope.$index)"-->
|
||||
<!-- >移除</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- </el-table>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="element-drawer__button">-->
|
||||
<!-- <XButton type="primary" proIcon="ep:plus" title="添加字段" @click="openFieldForm(null, -1)" />-->
|
||||
<!-- </div>-->
|
||||
<!--字段列表-->
|
||||
<!-- <div class="element-property list-property">-->
|
||||
<!-- <el-divider><Icon icon="ep:coin" /> 表单字段</el-divider>-->
|
||||
<!-- <el-table :data="fieldList" max-height="240" fit border>-->
|
||||
<!-- <el-table-column label="序号" type="index" width="50px" />-->
|
||||
<!-- <el-table-column label="字段名称" prop="label" min-width="80px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column-->
|
||||
<!-- label="字段类型"-->
|
||||
<!-- prop="type"-->
|
||||
<!-- min-width="80px"-->
|
||||
<!-- :formatter="(row) => fieldType[row.type] || row.type"-->
|
||||
<!-- show-overflow-tooltip-->
|
||||
<!-- />-->
|
||||
<!-- <el-table-column-->
|
||||
<!-- label="默认值"-->
|
||||
<!-- prop="defaultValue"-->
|
||||
<!-- min-width="80px"-->
|
||||
<!-- show-overflow-tooltip-->
|
||||
<!-- />-->
|
||||
<!-- <el-table-column label="操作" width="90px">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-button type="primary" link @click="openFieldForm(scope, scope.$index)"-->
|
||||
<!-- >编辑</el-button-->
|
||||
<!-- >-->
|
||||
<!-- <el-divider direction="vertical" />-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- style="color: #ff4d4f"-->
|
||||
<!-- @click="removeField(scope, scope.$index)"-->
|
||||
<!-- >移除</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- </el-table>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="element-drawer__button">-->
|
||||
<!-- <XButton type="primary" proIcon="ep:plus" title="添加字段" @click="openFieldForm(null, -1)" />-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!--字段配置侧边栏-->
|
||||
<!-- <el-drawer-->
|
||||
<!-- v-model="fieldModelVisible"-->
|
||||
<!-- title="字段配置"-->
|
||||
<!-- :size="`${width}px`"-->
|
||||
<!-- append-to-body-->
|
||||
<!-- destroy-on-close-->
|
||||
<!-- >-->
|
||||
<!-- <el-form :model="formFieldForm" label-width="90px">-->
|
||||
<!-- <el-form-item label="字段ID">-->
|
||||
<!-- <el-input v-model="formFieldForm.id" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="类型">-->
|
||||
<!-- <el-select-->
|
||||
<!-- v-model="formFieldForm.typeType"-->
|
||||
<!-- placeholder="请选择字段类型"-->
|
||||
<!-- clearable-->
|
||||
<!-- @change="changeFieldTypeType"-->
|
||||
<!-- >-->
|
||||
<!-- <el-option v-for="(value, key) of fieldType" :label="value" :value="key" :key="key" />-->
|
||||
<!-- </el-select>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="类型名称" v-if="formFieldForm.typeType === 'custom'">-->
|
||||
<!-- <el-input v-model="formFieldForm.type" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="名称">-->
|
||||
<!-- <el-input v-model="formFieldForm.label" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="时间格式" v-if="formFieldForm.typeType === 'date'">-->
|
||||
<!-- <el-input v-model="formFieldForm.datePattern" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="默认值">-->
|
||||
<!-- <el-input v-model="formFieldForm.defaultValue" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-form>-->
|
||||
<!--字段配置侧边栏-->
|
||||
<!-- <el-drawer-->
|
||||
<!-- v-model="fieldModelVisible"-->
|
||||
<!-- title="字段配置"-->
|
||||
<!-- :size="`${width}px`"-->
|
||||
<!-- append-to-body-->
|
||||
<!-- destroy-on-close-->
|
||||
<!-- >-->
|
||||
<!-- <el-form :model="formFieldForm" label-width="90px">-->
|
||||
<!-- <el-form-item label="字段ID">-->
|
||||
<!-- <el-input v-model="formFieldForm.id" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="类型">-->
|
||||
<!-- <el-select-->
|
||||
<!-- v-model="formFieldForm.typeType"-->
|
||||
<!-- placeholder="请选择字段类型"-->
|
||||
<!-- clearable-->
|
||||
<!-- @change="changeFieldTypeType"-->
|
||||
<!-- >-->
|
||||
<!-- <el-option v-for="(value, key) of fieldType" :label="value" :value="key" :key="key" />-->
|
||||
<!-- </el-select>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="类型名称" v-if="formFieldForm.typeType === 'custom'">-->
|
||||
<!-- <el-input v-model="formFieldForm.type" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="名称">-->
|
||||
<!-- <el-input v-model="formFieldForm.label" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="时间格式" v-if="formFieldForm.typeType === 'date'">-->
|
||||
<!-- <el-input v-model="formFieldForm.datePattern" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="默认值">-->
|
||||
<!-- <el-input v-model="formFieldForm.defaultValue" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-form>-->
|
||||
|
||||
<!-- <!– 枚举值设置 –>-->
|
||||
<!-- <template v-if="formFieldForm.type === 'enum'">-->
|
||||
<!-- <el-divider key="enum-divider" />-->
|
||||
<!-- <p class="listener-filed__title" key="enum-title">-->
|
||||
<!-- <span><Icon icon="ep:menu" />枚举值列表:</span>-->
|
||||
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'enum')"-->
|
||||
<!-- >添加枚举值</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </p>-->
|
||||
<!-- <el-table :data="fieldEnumList" key="enum-table" max-height="240" fit border>-->
|
||||
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||
<!-- <el-table-column label="枚举值编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="枚举值名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="操作" width="90px">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- @click="openFieldOptionForm(scope, scope.$index, 'enum')"-->
|
||||
<!-- >编辑</el-button-->
|
||||
<!-- >-->
|
||||
<!-- <el-divider direction="vertical" />-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- style="color: #ff4d4f"-->
|
||||
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'enum')"-->
|
||||
<!-- >移除</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- </el-table>-->
|
||||
<!-- </template>-->
|
||||
<!-- <!– 枚举值设置 –>-->
|
||||
<!-- <template v-if="formFieldForm.type === 'enum'">-->
|
||||
<!-- <el-divider key="enum-divider" />-->
|
||||
<!-- <p class="listener-filed__title" key="enum-title">-->
|
||||
<!-- <span><Icon icon="ep:menu" />枚举值列表:</span>-->
|
||||
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'enum')"-->
|
||||
<!-- >添加枚举值</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </p>-->
|
||||
<!-- <el-table :data="fieldEnumList" key="enum-table" max-height="240" fit border>-->
|
||||
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||
<!-- <el-table-column label="枚举值编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="枚举值名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="操作" width="90px">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- @click="openFieldOptionForm(scope, scope.$index, 'enum')"-->
|
||||
<!-- >编辑</el-button-->
|
||||
<!-- >-->
|
||||
<!-- <el-divider direction="vertical" />-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- style="color: #ff4d4f"-->
|
||||
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'enum')"-->
|
||||
<!-- >移除</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- </el-table>-->
|
||||
<!-- </template>-->
|
||||
|
||||
<!-- <!– 校验规则 –>-->
|
||||
<!-- <el-divider key="validation-divider" />-->
|
||||
<!-- <p class="listener-filed__title" key="validation-title">-->
|
||||
<!-- <span><Icon icon="ep:menu" />约束条件列表:</span>-->
|
||||
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'constraint')"-->
|
||||
<!-- >添加约束</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </p>-->
|
||||
<!-- <el-table :data="fieldConstraintsList" key="validation-table" max-height="240" fit border>-->
|
||||
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||
<!-- <el-table-column label="约束名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="约束配置" prop="config" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="操作" width="90px">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- @click="openFieldOptionForm(scope, scope.$index, 'constraint')"-->
|
||||
<!-- >编辑</el-button-->
|
||||
<!-- >-->
|
||||
<!-- <el-divider direction="vertical" />-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- style="color: #ff4d4f"-->
|
||||
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'constraint')"-->
|
||||
<!-- >移除</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- </el-table>-->
|
||||
<!-- <!– 校验规则 –>-->
|
||||
<!-- <el-divider key="validation-divider" />-->
|
||||
<!-- <p class="listener-filed__title" key="validation-title">-->
|
||||
<!-- <span><Icon icon="ep:menu" />约束条件列表:</span>-->
|
||||
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'constraint')"-->
|
||||
<!-- >添加约束</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </p>-->
|
||||
<!-- <el-table :data="fieldConstraintsList" key="validation-table" max-height="240" fit border>-->
|
||||
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||
<!-- <el-table-column label="约束名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="约束配置" prop="config" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="操作" width="90px">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- @click="openFieldOptionForm(scope, scope.$index, 'constraint')"-->
|
||||
<!-- >编辑</el-button-->
|
||||
<!-- >-->
|
||||
<!-- <el-divider direction="vertical" />-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- style="color: #ff4d4f"-->
|
||||
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'constraint')"-->
|
||||
<!-- >移除</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- </el-table>-->
|
||||
|
||||
<!-- <!– 表单属性 –>-->
|
||||
<!-- <el-divider key="property-divider" />-->
|
||||
<!-- <p class="listener-filed__title" key="property-title">-->
|
||||
<!-- <span><Icon icon="ep:menu" />字段属性列表:</span>-->
|
||||
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'property')"-->
|
||||
<!-- >添加属性</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </p>-->
|
||||
<!-- <el-table :data="fieldPropertiesList" key="property-table" max-height="240" fit border>-->
|
||||
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||
<!-- <el-table-column label="属性编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="操作" width="90px">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- @click="openFieldOptionForm(scope, scope.$index, 'property')"-->
|
||||
<!-- >编辑</el-button-->
|
||||
<!-- >-->
|
||||
<!-- <el-divider direction="vertical" />-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- style="color: #ff4d4f"-->
|
||||
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'property')"-->
|
||||
<!-- >移除</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- </el-table>-->
|
||||
<!-- <!– 表单属性 –>-->
|
||||
<!-- <el-divider key="property-divider" />-->
|
||||
<!-- <p class="listener-filed__title" key="property-title">-->
|
||||
<!-- <span><Icon icon="ep:menu" />字段属性列表:</span>-->
|
||||
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'property')"-->
|
||||
<!-- >添加属性</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </p>-->
|
||||
<!-- <el-table :data="fieldPropertiesList" key="property-table" max-height="240" fit border>-->
|
||||
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||
<!-- <el-table-column label="属性编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip />-->
|
||||
<!-- <el-table-column label="操作" width="90px">-->
|
||||
<!-- <template #default="scope">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- @click="openFieldOptionForm(scope, scope.$index, 'property')"-->
|
||||
<!-- >编辑</el-button-->
|
||||
<!-- >-->
|
||||
<!-- <el-divider direction="vertical" />-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- link-->
|
||||
<!-- style="color: #ff4d4f"-->
|
||||
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'property')"-->
|
||||
<!-- >移除</el-button-->
|
||||
<!-- >-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<!-- </el-table>-->
|
||||
|
||||
<!-- <!– 底部按钮 –>-->
|
||||
<!-- <div class="element-drawer__button">-->
|
||||
<!-- <el-button>取 消</el-button>-->
|
||||
<!-- <el-button type="primary" @click="saveField">保 存</el-button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </el-drawer>-->
|
||||
<!-- <!– 底部按钮 –>-->
|
||||
<!-- <div class="element-drawer__button">-->
|
||||
<!-- <el-button>取 消</el-button>-->
|
||||
<!-- <el-button type="primary" @click="saveField">保 存</el-button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </el-drawer>-->
|
||||
|
||||
<!-- <el-dialog-->
|
||||
<!-- v-model="fieldOptionModelVisible"-->
|
||||
<!-- :title="optionModelTitle"-->
|
||||
<!-- width="600px"-->
|
||||
<!-- append-to-body-->
|
||||
<!-- destroy-on-close-->
|
||||
<!-- >-->
|
||||
<!-- <el-form :model="fieldOptionForm" label-width="96px">-->
|
||||
<!-- <el-form-item label="编号/ID" v-if="fieldOptionType !== 'constraint'" key="option-id">-->
|
||||
<!-- <el-input v-model="fieldOptionForm.id" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="名称" v-if="fieldOptionType !== 'property'" key="option-name">-->
|
||||
<!-- <el-input v-model="fieldOptionForm.name" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="配置" v-if="fieldOptionType === 'constraint'" key="option-config">-->
|
||||
<!-- <el-input v-model="fieldOptionForm.config" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="值" v-if="fieldOptionType === 'property'" key="option-value">-->
|
||||
<!-- <el-input v-model="fieldOptionForm.value" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-form>-->
|
||||
<!-- <template #footer>-->
|
||||
<!-- <el-button @click="fieldOptionModelVisible = false">取 消</el-button>-->
|
||||
<!-- <el-button type="primary" @click="saveFieldOption">确 定</el-button>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-dialog>-->
|
||||
</div>
|
||||
<!-- <el-dialog-->
|
||||
<!-- v-model="fieldOptionModelVisible"-->
|
||||
<!-- :title="optionModelTitle"-->
|
||||
<!-- width="600px"-->
|
||||
<!-- append-to-body-->
|
||||
<!-- destroy-on-close-->
|
||||
<!-- >-->
|
||||
<!-- <el-form :model="fieldOptionForm" label-width="96px">-->
|
||||
<!-- <el-form-item label="编号/ID" v-if="fieldOptionType !== 'constraint'" key="option-id">-->
|
||||
<!-- <el-input v-model="fieldOptionForm.id" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="名称" v-if="fieldOptionType !== 'property'" key="option-name">-->
|
||||
<!-- <el-input v-model="fieldOptionForm.name" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="配置" v-if="fieldOptionType === 'constraint'" key="option-config">-->
|
||||
<!-- <el-input v-model="fieldOptionForm.config" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- <el-form-item label="值" v-if="fieldOptionType === 'property'" key="option-value">-->
|
||||
<!-- <el-input v-model="fieldOptionForm.value" clearable />-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-form>-->
|
||||
<!-- <template #footer>-->
|
||||
<!-- <el-button @click="fieldOptionModelVisible = false">取 消</el-button>-->
|
||||
<!-- <el-button type="primary" @click="saveFieldOption">确 定</el-button>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-dialog>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup>
|
||||
import { ref, onMounted, inject, toRaw, watch, nextTick } from 'vue'
|
||||
import { listAllWFForm } from '@/api/process-boot/workflow/form'
|
||||
<script lang="ts" setup>
|
||||
import { getFormSimpleList } from '@/api/bpm-boot/form'
|
||||
|
||||
|
||||
defineOptions({ name: 'ElementForm' })
|
||||
|
||||
const props = defineProps({
|
||||
id: String,
|
||||
type: String
|
||||
id: String,
|
||||
type: String
|
||||
})
|
||||
const prefix = inject('prefix')
|
||||
const width = inject('width')
|
||||
@@ -244,12 +244,12 @@ const optionModelTitle = ref('')
|
||||
const fieldList = ref<any[]>([])
|
||||
const formFieldForm = ref<any>({})
|
||||
const fieldType = ref({
|
||||
long: '长整型',
|
||||
string: '字符串',
|
||||
boolean: '布尔类',
|
||||
date: '日期类',
|
||||
enum: '枚举类',
|
||||
custom: '自定义类型'
|
||||
long: '长整型',
|
||||
string: '字符串',
|
||||
boolean: '布尔类',
|
||||
date: '日期类',
|
||||
enum: '枚举类',
|
||||
custom: '自定义类型'
|
||||
})
|
||||
const formFieldIndex = ref(-1) // 编辑中的字段, -1 为新增
|
||||
const formFieldOptionIndex = ref(-1) // 编辑中的字段配置项, -1 为新增
|
||||
@@ -267,215 +267,215 @@ const otherExtensions = ref()
|
||||
|
||||
const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||
const resetFormList = () => {
|
||||
bpmnELement.value = bpmnInstances().bpmnElement
|
||||
formKey.value = bpmnELement.value.businessObject.formKey
|
||||
if (formKey.value?.length > 0) {
|
||||
formKey.value = parseInt(formKey.value)
|
||||
}
|
||||
// 获取元素扩展属性 或者 创建扩展属性
|
||||
elExtensionElements.value =
|
||||
bpmnELement.value.businessObject.get('extensionElements') ||
|
||||
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
|
||||
// 获取元素表单配置 或者 创建新的表单配置
|
||||
formData.value =
|
||||
elExtensionElements.value.values.filter((ex) => ex.$type === `${prefix}:FormData`)?.[0] ||
|
||||
bpmnInstances().moddle.create(`${prefix}:FormData`, { fields: [] })
|
||||
bpmnELement.value = bpmnInstances().bpmnElement
|
||||
formKey.value = bpmnELement.value.businessObject.formKey
|
||||
// if (formKey.value?.length > 0) {
|
||||
// formKey.value = parseInt(formKey.value)
|
||||
// }
|
||||
// 获取元素扩展属性 或者 创建扩展属性
|
||||
elExtensionElements.value =
|
||||
bpmnELement.value.businessObject.get('extensionElements') ||
|
||||
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
|
||||
// 获取元素表单配置 或者 创建新的表单配置
|
||||
formData.value =
|
||||
elExtensionElements.value.values.filter((ex) => ex.$type === `${prefix}:FormData`)?.[0] ||
|
||||
bpmnInstances().moddle.create(`${prefix}:FormData`, { fields: [] })
|
||||
|
||||
// 业务标识 businessKey, 绑定在 formData 中
|
||||
businessKey.value = formData.value.businessKey
|
||||
// 业务标识 businessKey, 绑定在 formData 中
|
||||
businessKey.value = formData.value.businessKey
|
||||
|
||||
// 保留剩余扩展元素,便于后面更新该元素对应属性
|
||||
otherExtensions.value = elExtensionElements.value.values.filter(
|
||||
(ex) => ex.$type !== `${prefix}:FormData`
|
||||
)
|
||||
// 保留剩余扩展元素,便于后面更新该元素对应属性
|
||||
otherExtensions.value = elExtensionElements.value.values.filter(
|
||||
(ex) => ex.$type !== `${prefix}:FormData`
|
||||
)
|
||||
|
||||
// 复制原始值,填充表格
|
||||
fieldList.value = JSON.parse(JSON.stringify(formData.value.fields || []))
|
||||
// 复制原始值,填充表格
|
||||
fieldList.value = JSON.parse(JSON.stringify(formData.value.fields || []))
|
||||
|
||||
// 更新元素扩展属性,避免后续报错
|
||||
updateElementExtensions()
|
||||
// 更新元素扩展属性,避免后续报错
|
||||
updateElementExtensions()
|
||||
}
|
||||
const updateElementFormKey = () => {
|
||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
||||
formKey: formKey.value
|
||||
})
|
||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
||||
formKey: formKey.value
|
||||
})
|
||||
}
|
||||
const updateElementBusinessKey = () => {
|
||||
bpmnInstances().modeling.updateModdleProperties(toRaw(bpmnELement.value), formData.value, {
|
||||
businessKey: businessKey.value
|
||||
})
|
||||
bpmnInstances().modeling.updateModdleProperties(toRaw(bpmnELement.value), formData.value, {
|
||||
businessKey: businessKey.value
|
||||
})
|
||||
}
|
||||
// 根据类型调整字段type
|
||||
const changeFieldTypeType = (type) => {
|
||||
// this.$set(this.formFieldForm, "type", type === "custom" ? "" : type);
|
||||
formFieldForm.value['type'] = type === 'custom' ? '' : type
|
||||
// this.$set(this.formFieldForm, "type", type === "custom" ? "" : type);
|
||||
formFieldForm.value['type'] = type === 'custom' ? '' : type
|
||||
}
|
||||
|
||||
// 打开字段详情侧边栏
|
||||
const openFieldForm = (field, index) => {
|
||||
formFieldIndex.value = index
|
||||
if (index !== -1) {
|
||||
const FieldObject = formData.value.fields[index]
|
||||
formFieldForm.value = JSON.parse(JSON.stringify(field))
|
||||
// 设置自定义类型
|
||||
// this.$set(this.formFieldForm, "typeType", !this.fieldType[field.type] ? "custom" : field.type);
|
||||
formFieldForm.value['typeType'] = !fieldType.value[field.type] ? 'custom' : field.type
|
||||
// 初始化枚举值列表
|
||||
field.type === 'enum' &&
|
||||
(fieldEnumList.value = JSON.parse(JSON.stringify(FieldObject?.values || [])))
|
||||
// 初始化约束条件列表
|
||||
fieldConstraintsList.value = JSON.parse(
|
||||
JSON.stringify(FieldObject?.validation?.constraints || [])
|
||||
)
|
||||
// 初始化自定义属性列表
|
||||
fieldPropertiesList.value = JSON.parse(JSON.stringify(FieldObject?.properties?.values || []))
|
||||
} else {
|
||||
formFieldForm.value = {}
|
||||
// 初始化枚举值列表
|
||||
fieldEnumList.value = []
|
||||
// 初始化约束条件列表
|
||||
fieldConstraintsList.value = []
|
||||
// 初始化自定义属性列表
|
||||
fieldPropertiesList.value = []
|
||||
}
|
||||
fieldModelVisible.value = true
|
||||
formFieldIndex.value = index
|
||||
if (index !== -1) {
|
||||
const FieldObject = formData.value.fields[index]
|
||||
formFieldForm.value = JSON.parse(JSON.stringify(field))
|
||||
// 设置自定义类型
|
||||
// this.$set(this.formFieldForm, "typeType", !this.fieldType[field.type] ? "custom" : field.type);
|
||||
formFieldForm.value['typeType'] = !fieldType.value[field.type] ? 'custom' : field.type
|
||||
// 初始化枚举值列表
|
||||
field.type === 'enum' &&
|
||||
(fieldEnumList.value = JSON.parse(JSON.stringify(FieldObject?.values || [])))
|
||||
// 初始化约束条件列表
|
||||
fieldConstraintsList.value = JSON.parse(
|
||||
JSON.stringify(FieldObject?.validation?.constraints || [])
|
||||
)
|
||||
// 初始化自定义属性列表
|
||||
fieldPropertiesList.value = JSON.parse(JSON.stringify(FieldObject?.properties?.values || []))
|
||||
} else {
|
||||
formFieldForm.value = {}
|
||||
// 初始化枚举值列表
|
||||
fieldEnumList.value = []
|
||||
// 初始化约束条件列表
|
||||
fieldConstraintsList.value = []
|
||||
// 初始化自定义属性列表
|
||||
fieldPropertiesList.value = []
|
||||
}
|
||||
fieldModelVisible.value = true
|
||||
}
|
||||
// 打开字段 某个 配置项 弹窗
|
||||
const openFieldOptionForm = (option, index, type) => {
|
||||
fieldOptionModelVisible.value = true
|
||||
fieldOptionType.value = type
|
||||
formFieldOptionIndex.value = index
|
||||
if (type === 'property') {
|
||||
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
||||
return (optionModelTitle.value = '属性配置')
|
||||
}
|
||||
if (type === 'enum') {
|
||||
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
||||
return (optionModelTitle.value = '枚举值配置')
|
||||
}
|
||||
fieldOptionModelVisible.value = true
|
||||
fieldOptionType.value = type
|
||||
formFieldOptionIndex.value = index
|
||||
if (type === 'property') {
|
||||
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
||||
return (optionModelTitle.value = '约束条件配置')
|
||||
return (optionModelTitle.value = '属性配置')
|
||||
}
|
||||
if (type === 'enum') {
|
||||
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
||||
return (optionModelTitle.value = '枚举值配置')
|
||||
}
|
||||
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
|
||||
return (optionModelTitle.value = '约束条件配置')
|
||||
}
|
||||
|
||||
// 保存字段 某个 配置项
|
||||
const saveFieldOption = () => {
|
||||
if (formFieldOptionIndex.value === -1) {
|
||||
if (fieldOptionType.value === 'property') {
|
||||
fieldPropertiesList.value.push(fieldOptionForm.value)
|
||||
}
|
||||
if (fieldOptionType.value === 'constraint') {
|
||||
fieldConstraintsList.value.push(fieldOptionForm.value)
|
||||
}
|
||||
if (fieldOptionType.value === 'enum') {
|
||||
fieldEnumList.value.push(fieldOptionForm.value)
|
||||
}
|
||||
} else {
|
||||
fieldOptionType.value === 'property' &&
|
||||
fieldPropertiesList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
||||
fieldOptionType.value === 'constraint' &&
|
||||
fieldConstraintsList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
||||
fieldOptionType.value === 'enum' &&
|
||||
fieldEnumList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
||||
if (formFieldOptionIndex.value === -1) {
|
||||
if (fieldOptionType.value === 'property') {
|
||||
fieldPropertiesList.value.push(fieldOptionForm.value)
|
||||
}
|
||||
fieldOptionModelVisible.value = false
|
||||
fieldOptionForm.value = {}
|
||||
if (fieldOptionType.value === 'constraint') {
|
||||
fieldConstraintsList.value.push(fieldOptionForm.value)
|
||||
}
|
||||
if (fieldOptionType.value === 'enum') {
|
||||
fieldEnumList.value.push(fieldOptionForm.value)
|
||||
}
|
||||
} else {
|
||||
fieldOptionType.value === 'property' &&
|
||||
fieldPropertiesList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
||||
fieldOptionType.value === 'constraint' &&
|
||||
fieldConstraintsList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
||||
fieldOptionType.value === 'enum' &&
|
||||
fieldEnumList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
|
||||
}
|
||||
fieldOptionModelVisible.value = false
|
||||
fieldOptionForm.value = {}
|
||||
}
|
||||
// 保存字段配置
|
||||
const saveField = () => {
|
||||
const { id, type, label, defaultValue, datePattern } = formFieldForm.value
|
||||
const Field = bpmnInstances().moddle.create(`${prefix}:FormField`, { id, type, label })
|
||||
defaultValue && (Field.defaultValue = defaultValue)
|
||||
datePattern && (Field.datePattern = datePattern)
|
||||
// 构建属性
|
||||
if (fieldPropertiesList.value && fieldPropertiesList.value.length) {
|
||||
const fieldPropertyList = fieldPropertiesList.value.map((fp) => {
|
||||
return bpmnInstances().moddle.create(`${prefix}:Property`, {
|
||||
id: fp.id,
|
||||
value: fp.value
|
||||
})
|
||||
})
|
||||
Field.properties = bpmnInstances().moddle.create(`${prefix}:Properties`, {
|
||||
values: fieldPropertyList
|
||||
})
|
||||
}
|
||||
// 构建校验规则
|
||||
if (fieldConstraintsList.value && fieldConstraintsList.value.length) {
|
||||
const fieldConstraintList = fieldConstraintsList.value.map((fc) => {
|
||||
return bpmnInstances().moddle.create(`${prefix}:Constraint`, {
|
||||
name: fc.name,
|
||||
config: fc.config
|
||||
})
|
||||
})
|
||||
Field.validation = bpmnInstances().moddle.create(`${prefix}:Validation`, {
|
||||
constraints: fieldConstraintList
|
||||
})
|
||||
}
|
||||
// 构建枚举值
|
||||
if (fieldEnumList.value && fieldEnumList.value.length) {
|
||||
Field.values = fieldEnumList.value.map((fe) => {
|
||||
return bpmnInstances().moddle.create(`${prefix}:Value`, { name: fe.name, id: fe.id })
|
||||
})
|
||||
}
|
||||
// 更新数组 与 表单配置实例
|
||||
if (formFieldIndex.value === -1) {
|
||||
fieldList.value.push(formFieldForm.value)
|
||||
formData.value.fields.push(Field)
|
||||
} else {
|
||||
fieldList.value.splice(formFieldIndex.value, 1, formFieldForm.value)
|
||||
formData.value.fields.splice(formFieldIndex.value, 1, Field)
|
||||
}
|
||||
updateElementExtensions()
|
||||
fieldModelVisible.value = false
|
||||
const { id, type, label, defaultValue, datePattern } = formFieldForm.value
|
||||
const Field = bpmnInstances().moddle.create(`${prefix}:FormField`, { id, type, label })
|
||||
defaultValue && (Field.defaultValue = defaultValue)
|
||||
datePattern && (Field.datePattern = datePattern)
|
||||
// 构建属性
|
||||
if (fieldPropertiesList.value && fieldPropertiesList.value.length) {
|
||||
const fieldPropertyList = fieldPropertiesList.value.map((fp) => {
|
||||
return bpmnInstances().moddle.create(`${prefix}:Property`, {
|
||||
id: fp.id,
|
||||
value: fp.value
|
||||
})
|
||||
})
|
||||
Field.properties = bpmnInstances().moddle.create(`${prefix}:Properties`, {
|
||||
values: fieldPropertyList
|
||||
})
|
||||
}
|
||||
// 构建校验规则
|
||||
if (fieldConstraintsList.value && fieldConstraintsList.value.length) {
|
||||
const fieldConstraintList = fieldConstraintsList.value.map((fc) => {
|
||||
return bpmnInstances().moddle.create(`${prefix}:Constraint`, {
|
||||
name: fc.name,
|
||||
config: fc.config
|
||||
})
|
||||
})
|
||||
Field.validation = bpmnInstances().moddle.create(`${prefix}:Validation`, {
|
||||
constraints: fieldConstraintList
|
||||
})
|
||||
}
|
||||
// 构建枚举值
|
||||
if (fieldEnumList.value && fieldEnumList.value.length) {
|
||||
Field.values = fieldEnumList.value.map((fe) => {
|
||||
return bpmnInstances().moddle.create(`${prefix}:Value`, { name: fe.name, id: fe.id })
|
||||
})
|
||||
}
|
||||
// 更新数组 与 表单配置实例
|
||||
if (formFieldIndex.value === -1) {
|
||||
fieldList.value.push(formFieldForm.value)
|
||||
formData.value.fields.push(Field)
|
||||
} else {
|
||||
fieldList.value.splice(formFieldIndex.value, 1, formFieldForm.value)
|
||||
formData.value.fields.splice(formFieldIndex.value, 1, Field)
|
||||
}
|
||||
updateElementExtensions()
|
||||
fieldModelVisible.value = false
|
||||
}
|
||||
|
||||
// 移除某个 字段的 配置项
|
||||
const removeFieldOptionItem = (option, index, type) => {
|
||||
// console.log(option, 'option')
|
||||
if (type === 'property') {
|
||||
fieldPropertiesList.value.splice(index, 1)
|
||||
return
|
||||
}
|
||||
if (type === 'enum') {
|
||||
fieldEnumList.value.splice(index, 1)
|
||||
return
|
||||
}
|
||||
fieldConstraintsList.value.splice(index, 1)
|
||||
// console.log(option, 'option')
|
||||
if (type === 'property') {
|
||||
fieldPropertiesList.value.splice(index, 1)
|
||||
return
|
||||
}
|
||||
if (type === 'enum') {
|
||||
fieldEnumList.value.splice(index, 1)
|
||||
return
|
||||
}
|
||||
fieldConstraintsList.value.splice(index, 1)
|
||||
}
|
||||
// 移除 字段
|
||||
const removeField = (field, index) => {
|
||||
console.log(field, 'field')
|
||||
fieldList.value.splice(index, 1)
|
||||
formData.value.fields.splice(index, 1)
|
||||
updateElementExtensions()
|
||||
console.log(field, 'field')
|
||||
fieldList.value.splice(index, 1)
|
||||
formData.value.fields.splice(index, 1)
|
||||
updateElementExtensions()
|
||||
}
|
||||
|
||||
const updateElementExtensions = () => {
|
||||
// 更新回扩展元素
|
||||
const newElExtensionElements = bpmnInstances().moddle.create(`bpmn:ExtensionElements`, {
|
||||
values: otherExtensions.value.concat(formData.value)
|
||||
})
|
||||
// 更新到元素上
|
||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
||||
extensionElements: newElExtensionElements
|
||||
})
|
||||
// 更新回扩展元素
|
||||
const newElExtensionElements = bpmnInstances().moddle.create(`bpmn:ExtensionElements`, {
|
||||
values: otherExtensions.value.concat(formData.value)
|
||||
})
|
||||
// 更新到元素上
|
||||
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
||||
extensionElements: newElExtensionElements
|
||||
})
|
||||
}
|
||||
|
||||
const formList = ref([]) // 流程表单的下拉框的数据
|
||||
onMounted(async () => {
|
||||
await listAllWFForm().then(res => {
|
||||
formList.value = res.data
|
||||
})
|
||||
await getFormSimpleList().then(res => {
|
||||
formList.value = res.data
|
||||
})
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.id,
|
||||
(val) => {
|
||||
val &&
|
||||
val.length &&
|
||||
nextTick(() => {
|
||||
resetFormList()
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
() => props.id,
|
||||
(val) => {
|
||||
val &&
|
||||
val.length &&
|
||||
nextTick(() => {
|
||||
resetFormList()
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -1,238 +1,290 @@
|
||||
<template>
|
||||
<div class="panel-tab__content">
|
||||
<el-table :data="elementListenersList" size="small" border>
|
||||
<el-table-column label="序号" width="50px" type="index" />
|
||||
<el-table-column label="事件类型" min-width="100px" prop="event" />
|
||||
<el-table-column
|
||||
label="监听器类型"
|
||||
min-width="100px"
|
||||
show-overflow-tooltip
|
||||
:formatter="row => listenerTypeObject[row.listenerType]"
|
||||
<div class='panel-tab__content'>
|
||||
<el-table :data='elementListenersList' size='small' border>
|
||||
<el-table-column label='序号' width='50px' type='index' />
|
||||
<el-table-column label='事件类型' min-width='100px' prop='event' />
|
||||
<el-table-column
|
||||
label='监听器类型'
|
||||
min-width='100px'
|
||||
show-overflow-tooltip
|
||||
:formatter='(row) => listenerTypeObject[row.listenerType]'
|
||||
/>
|
||||
<el-table-column label='操作' width='100px'>
|
||||
<template #default='scope'>
|
||||
<el-button size='small' link @click='openListenerForm(scope.row, scope.$index)'
|
||||
>编辑
|
||||
</el-button
|
||||
>
|
||||
<el-divider direction='vertical' />
|
||||
<el-button size='small' link style='color: #ff4d4f' @click='removeListener(scope.$index)'
|
||||
>移除
|
||||
</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class='element-drawer__button'>
|
||||
<XButton
|
||||
type="primary"
|
||||
preIcon="ep:plus"
|
||||
title="添加监听器"
|
||||
size="small"
|
||||
@click="openListenerForm(null)"
|
||||
/>
|
||||
<el-table-column label="操作" width="100px">
|
||||
<template #default="scope">
|
||||
<el-button size="small" link @click="openListenerForm(scope.row, scope.$index)">编辑</el-button>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button size="small" link style="color: #ff4d4f" @click="removeListener(scope.$index)">
|
||||
移除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="element-drawer__button">
|
||||
<el-button type="primary" icon="el-icon-Plus" size="small" @click="openListenerForm(null)">
|
||||
添加监听器
|
||||
</el-button>
|
||||
<el-button type="success" icon="el-icon-Select" size="small" @click="openProcessListenerDialog">
|
||||
选择监听器
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 监听器 编辑/创建 部分 -->
|
||||
<el-drawer
|
||||
v-model="listenerFormModelVisible"
|
||||
title="执行监听器"
|
||||
:size="`${width}px`"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form :model="listenerForm" label-width="96px" ref="listenerFormRef">
|
||||
<el-form-item label="事件类型" prop="event" :rules="{ required: true, trigger: ['blur', 'change'] }">
|
||||
<el-select v-model="listenerForm.event">
|
||||
<el-option label="start" value="start" />
|
||||
<el-option label="end" value="end" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="监听器类型"
|
||||
prop="listenerType"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model="listenerForm.listenerType">
|
||||
<el-option
|
||||
v-for="i in Object.keys(listenerTypeObject)"
|
||||
:key="i"
|
||||
:label="listenerTypeObject[i]"
|
||||
:value="i"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'classListener'"
|
||||
label="Java类"
|
||||
prop="class"
|
||||
key="listener-class"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.class" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'expressionListener'"
|
||||
label="表达式"
|
||||
prop="expression"
|
||||
key="listener-expression"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.expression" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
|
||||
label="代理表达式"
|
||||
prop="delegateExpression"
|
||||
key="listener-delegate"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.delegateExpression" clearable />
|
||||
</el-form-item>
|
||||
<template v-if="listenerForm.listenerType === 'scriptListener'">
|
||||
<el-form-item
|
||||
label="脚本格式"
|
||||
prop="scriptFormat"
|
||||
key="listener-script-format"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.scriptFormat" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="脚本类型"
|
||||
prop="scriptType"
|
||||
key="listener-script-type"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
|
||||
>
|
||||
<el-select v-model="listenerForm.scriptType">
|
||||
<el-option label="内联脚本" value="inlineScript" />
|
||||
<el-option label="外部脚本" value="externalScript" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.scriptType === 'inlineScript'"
|
||||
label="脚本内容"
|
||||
prop="value"
|
||||
key="listener-script"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.value" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.scriptType === 'externalScript'"
|
||||
label="资源地址"
|
||||
prop="resource"
|
||||
key="listener-resource"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.resource" clearable />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
<el-divider />
|
||||
<p class="listener-filed__title">
|
||||
<span>
|
||||
<Icon icon="ep:menu" />
|
||||
注入字段:
|
||||
</span>
|
||||
<el-button type="primary" @click="openListenerFieldForm(null)">添加字段</el-button>
|
||||
</p>
|
||||
<el-table :data="fieldsListOfListener" size="small" max-height="240" fit border style="flex: none">
|
||||
<el-table-column label="序号" width="50px" type="index" />
|
||||
<el-table-column label="字段名称" min-width="100px" prop="name" />
|
||||
<el-table-column
|
||||
label="字段类型"
|
||||
min-width="80px"
|
||||
show-overflow-tooltip
|
||||
:formatter="row => fieldTypeObject[row.fieldType]"
|
||||
/>
|
||||
<el-table-column
|
||||
label="字段值/表达式"
|
||||
min-width="100px"
|
||||
show-overflow-tooltip
|
||||
:formatter="row => row.string || row.expression"
|
||||
/>
|
||||
<el-table-column label="操作" width="130px">
|
||||
<template #default="scope">
|
||||
<el-button size="small" link @click="openListenerFieldForm(scope.row, scope.$index)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button size="small" link style="color: #ff4d4f" @click="removeListenerField(scope.$index)">
|
||||
移除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="element-drawer__button">
|
||||
<el-button @click="listenerFormModelVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="saveListenerConfig">保 存</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 注入西段 编辑/创建 部分 -->
|
||||
<el-dialog
|
||||
title="字段配置"
|
||||
v-model="listenerFieldFormModelVisible"
|
||||
width="600px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form :model="listenerFieldForm" label-width="96spx" ref="listenerFieldFormRef" style="height: 136px">
|
||||
<el-form-item label="字段名称:" prop="name" :rules="{ required: true, trigger: ['blur', 'change'] }">
|
||||
<el-input v-model="listenerFieldForm.name" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="字段类型:"
|
||||
prop="fieldType"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model="listenerFieldForm.fieldType">
|
||||
<el-option
|
||||
v-for="i in Object.keys(fieldTypeObject)"
|
||||
:key="i"
|
||||
:label="fieldTypeObject[i]"
|
||||
:value="i"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerFieldForm.fieldType === 'string'"
|
||||
label="字段值:"
|
||||
prop="string"
|
||||
key="field-string"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerFieldForm.string" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerFieldForm.fieldType === 'expression'"
|
||||
label="表达式:"
|
||||
prop="expression"
|
||||
key="field-expression"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerFieldForm.expression" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button size="small" @click="listenerFieldFormModelVisible = false">取 消</el-button>
|
||||
<el-button size="small" type="primary" @click="saveListenerFiled">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- <Plus type='primary'-->
|
||||
<!-- title='添加监听器'-->
|
||||
<!-- size='small'-->
|
||||
<!-- @click='openListenerForm(null)' />-->
|
||||
<XButton
|
||||
type="success"
|
||||
preIcon="ep:select"
|
||||
title="选择监听器"
|
||||
size="small"
|
||||
@click="openProcessListenerDialog"
|
||||
/>
|
||||
<!-- <Select-->
|
||||
<!-- type='success'-->
|
||||
<!-- title='选择监听器'-->
|
||||
<!-- size='small'-->
|
||||
<!-- @click='openProcessListenerDialog'-->
|
||||
<!-- />-->
|
||||
</div>
|
||||
|
||||
<!-- 选择弹窗 -->
|
||||
<ProcessListenerDialog ref="processListenerDialogRef" @select="selectProcessListener" />
|
||||
<!-- 监听器 编辑/创建 部分 -->
|
||||
<el-drawer
|
||||
v-model='listenerFormModelVisible'
|
||||
title='执行监听器'
|
||||
:size='`${width}px`'
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form :model='listenerForm' label-width='96px' ref='listenerFormRef'>
|
||||
<el-form-item
|
||||
label='事件类型'
|
||||
prop='event'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model='listenerForm.event'>
|
||||
<el-option label='start' value='start' />
|
||||
<el-option label='end' value='end' />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label='监听器类型'
|
||||
prop='listenerType'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model='listenerForm.listenerType'>
|
||||
<el-option
|
||||
v-for='i in Object.keys(listenerTypeObject)'
|
||||
:key='i'
|
||||
:label='listenerTypeObject[i]'
|
||||
:value='i'
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'classListener'"
|
||||
label='Java类'
|
||||
prop='class'
|
||||
key='listener-class'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model='listenerForm.class' clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'expressionListener'"
|
||||
label='表达式'
|
||||
prop='expression'
|
||||
key='listener-expression'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model='listenerForm.expression' clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
|
||||
label='代理表达式'
|
||||
prop='delegateExpression'
|
||||
key='listener-delegate'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model='listenerForm.delegateExpression' clearable />
|
||||
</el-form-item>
|
||||
<template v-if="listenerForm.listenerType === 'scriptListener'">
|
||||
<el-form-item
|
||||
label='脚本格式'
|
||||
prop='scriptFormat'
|
||||
key='listener-script-format'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
|
||||
>
|
||||
<el-input v-model='listenerForm.scriptFormat' clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label='脚本类型'
|
||||
prop='scriptType'
|
||||
key='listener-script-type'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
|
||||
>
|
||||
<el-select v-model='listenerForm.scriptType'>
|
||||
<el-option label='内联脚本' value='inlineScript' />
|
||||
<el-option label='外部脚本' value='externalScript' />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.scriptType === 'inlineScript'"
|
||||
label='脚本内容'
|
||||
prop='value'
|
||||
key='listener-script'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
|
||||
>
|
||||
<el-input v-model='listenerForm.value' clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.scriptType === 'externalScript'"
|
||||
label='资源地址'
|
||||
prop='resource'
|
||||
key='listener-resource'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
|
||||
>
|
||||
<el-input v-model='listenerForm.resource' clearable />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
<el-divider />
|
||||
<p class='listener-filed__title'>
|
||||
<span><Menu />注入字段:</span>
|
||||
<XButton type='primary' @click='openListenerFieldForm(null)' title='添加字段' />
|
||||
</p>
|
||||
<el-table
|
||||
:data='fieldsListOfListener'
|
||||
size='small'
|
||||
max-height='240'
|
||||
fit
|
||||
border
|
||||
style='flex: none'
|
||||
>
|
||||
<el-table-column label='序号' width='50px' type='index' />
|
||||
<el-table-column label='字段名称' min-width='100px' prop='name' />
|
||||
<el-table-column
|
||||
label='字段类型'
|
||||
min-width='80px'
|
||||
show-overflow-tooltip
|
||||
:formatter='(row) => fieldTypeObject[row.fieldType]'
|
||||
/>
|
||||
<el-table-column
|
||||
label='字段值/表达式'
|
||||
min-width='100px'
|
||||
show-overflow-tooltip
|
||||
:formatter='(row) => row.string || row.expression'
|
||||
/>
|
||||
<el-table-column label='操作' width='130px'>
|
||||
<template #default='scope'>
|
||||
<el-button size='small' link @click='openListenerFieldForm(scope.row, scope.$index)'
|
||||
>编辑
|
||||
</el-button
|
||||
>
|
||||
<el-divider direction='vertical' />
|
||||
<el-button
|
||||
size='small'
|
||||
link
|
||||
style='color: #ff4d4f'
|
||||
@click='removeListenerField(scope.$index)'
|
||||
>移除
|
||||
</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class='element-drawer__button'>
|
||||
<el-button @click='listenerFormModelVisible = false'>取 消</el-button>
|
||||
<el-button type='primary' @click='saveListenerConfig'>保 存</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 注入西段 编辑/创建 部分 -->
|
||||
<el-dialog
|
||||
title='字段配置'
|
||||
v-model='listenerFieldFormModelVisible'
|
||||
width='600px'
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form
|
||||
:model='listenerFieldForm'
|
||||
label-width='96spx'
|
||||
ref='listenerFieldFormRef'
|
||||
style='height: 136px'
|
||||
>
|
||||
<el-form-item
|
||||
label='字段名称:'
|
||||
prop='name'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model='listenerFieldForm.name' clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label='字段类型:'
|
||||
prop='fieldType'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model='listenerFieldForm.fieldType'>
|
||||
<el-option
|
||||
v-for='i in Object.keys(fieldTypeObject)'
|
||||
:key='i'
|
||||
:label='fieldTypeObject[i]'
|
||||
:value='i'
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerFieldForm.fieldType === 'string'"
|
||||
label='字段值:'
|
||||
prop='string'
|
||||
key='field-string'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model='listenerFieldForm.string' clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerFieldForm.fieldType === 'expression'"
|
||||
label='表达式:'
|
||||
prop='expression'
|
||||
key='field-expression'
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model='listenerFieldForm.expression' clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button size='small' @click='listenerFieldFormModelVisible = false'>取 消</el-button>
|
||||
<el-button size='small' type='primary' @click='saveListenerFiled'>确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<!-- 选择弹窗 -->
|
||||
<ProcessListenerDialog ref='processListenerDialogRef' @select='selectProcessListener' />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, nextTick, inject } from 'vue'
|
||||
<script lang='ts' setup>
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import XButton from '@/components/XButton/src/XButton.vue'
|
||||
import { Plus, Select, Menu } from '@element-plus/icons-vue'
|
||||
import { createListenerObject, updateElementExtensions } from '../../utils'
|
||||
import { initListenerType, initListenerForm, listenerType, fieldType, initListenerForm2 } from './utilSelf'
|
||||
import {
|
||||
initListenerType,
|
||||
initListenerForm,
|
||||
listenerType,
|
||||
fieldType,
|
||||
initListenerForm2
|
||||
} from './utilSelf'
|
||||
import ProcessListenerDialog from './ProcessListenerDialog.vue'
|
||||
|
||||
defineOptions({ name: 'ElementListeners' })
|
||||
|
||||
const props = defineProps({
|
||||
id: String,
|
||||
type: String
|
||||
id: String,
|
||||
type: String
|
||||
})
|
||||
const prefix = inject('prefix')
|
||||
const width = inject('width')
|
||||
@@ -254,147 +306,158 @@ const listenerFieldFormRef = ref()
|
||||
const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||
|
||||
const resetListenersList = () => {
|
||||
bpmnElement.value = bpmnInstances().bpmnElement
|
||||
otherExtensionList.value = []
|
||||
bpmnElementListeners.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
ex => ex.$type === `${prefix}:ExecutionListener`
|
||||
) ?? []
|
||||
elementListenersList.value = bpmnElementListeners.value.map(listener => initListenerType(listener))
|
||||
bpmnElement.value = bpmnInstances().bpmnElement
|
||||
otherExtensionList.value = []
|
||||
bpmnElementListeners.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
(ex) => ex.$type === `${prefix}:ExecutionListener`
|
||||
) ?? []
|
||||
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
|
||||
initListenerType(listener)
|
||||
)
|
||||
}
|
||||
// 打开 监听器详情 侧边栏
|
||||
const openListenerForm = (listener, index?) => {
|
||||
// debugger
|
||||
if (listener) {
|
||||
listenerForm.value = initListenerForm(listener)
|
||||
editingListenerIndex.value = index
|
||||
} else {
|
||||
listenerForm.value = {}
|
||||
editingListenerIndex.value = -1 // 标记为新增
|
||||
// debugger
|
||||
if (listener) {
|
||||
listenerForm.value = initListenerForm(listener)
|
||||
editingListenerIndex.value = index
|
||||
} else {
|
||||
listenerForm.value = {}
|
||||
editingListenerIndex.value = -1 // 标记为新增
|
||||
}
|
||||
if (listener && listener.fields) {
|
||||
fieldsListOfListener.value = listener.fields.map((field) => ({
|
||||
...field,
|
||||
fieldType: field.string ? 'string' : 'expression'
|
||||
}))
|
||||
} else {
|
||||
fieldsListOfListener.value = []
|
||||
listenerForm.value['fields'] = []
|
||||
}
|
||||
// 打开侧边栏并清楚验证状态
|
||||
listenerFormModelVisible.value = true
|
||||
nextTick(() => {
|
||||
if (listenerFormRef.value) {
|
||||
listenerFormRef.value.clearValidate()
|
||||
}
|
||||
if (listener && listener.fields) {
|
||||
fieldsListOfListener.value = listener.fields.map(field => ({
|
||||
...field,
|
||||
fieldType: field.string ? 'string' : 'expression'
|
||||
}))
|
||||
} else {
|
||||
fieldsListOfListener.value = []
|
||||
listenerForm.value['fields'] = []
|
||||
}
|
||||
// 打开侧边栏并清楚验证状态
|
||||
listenerFormModelVisible.value = true
|
||||
nextTick(() => {
|
||||
if (listenerFormRef.value) {
|
||||
listenerFormRef.value.clearValidate()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
// 打开监听器字段编辑弹窗
|
||||
const openListenerFieldForm = (field, index?) => {
|
||||
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {}
|
||||
editingListenerFieldIndex.value = field ? index : -1
|
||||
listenerFieldFormModelVisible.value = true
|
||||
nextTick(() => {
|
||||
if (listenerFieldFormRef.value) {
|
||||
listenerFieldFormRef.value.clearValidate()
|
||||
}
|
||||
})
|
||||
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {}
|
||||
editingListenerFieldIndex.value = field ? index : -1
|
||||
listenerFieldFormModelVisible.value = true
|
||||
nextTick(() => {
|
||||
if (listenerFieldFormRef.value) {
|
||||
listenerFieldFormRef.value.clearValidate()
|
||||
}
|
||||
})
|
||||
}
|
||||
// 保存监听器注入字段
|
||||
const saveListenerFiled = async () => {
|
||||
// debugger
|
||||
let validateStatus = await listenerFieldFormRef.value.validate()
|
||||
if (!validateStatus) return // 验证不通过直接返回
|
||||
if (editingListenerFieldIndex.value === -1) {
|
||||
fieldsListOfListener.value.push(listenerFieldForm.value)
|
||||
listenerForm.value.fields.push(listenerFieldForm.value)
|
||||
} else {
|
||||
fieldsListOfListener.value.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||
listenerForm.value.fields.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||
}
|
||||
listenerFieldFormModelVisible.value = false
|
||||
nextTick(() => {
|
||||
listenerFieldForm.value = {}
|
||||
})
|
||||
// debugger
|
||||
let validateStatus = await listenerFieldFormRef.value.validate()
|
||||
if (!validateStatus) return // 验证不通过直接返回
|
||||
if (editingListenerFieldIndex.value === -1) {
|
||||
fieldsListOfListener.value.push(listenerFieldForm.value)
|
||||
listenerForm.value.fields.push(listenerFieldForm.value)
|
||||
} else {
|
||||
fieldsListOfListener.value.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||
listenerForm.value.fields.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||
}
|
||||
listenerFieldFormModelVisible.value = false
|
||||
nextTick(() => {
|
||||
listenerFieldForm.value = {}
|
||||
})
|
||||
}
|
||||
// 移除监听器字段
|
||||
const removeListenerField = index => {
|
||||
// debugger
|
||||
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
|
||||
confirmButtonText: '确 认',
|
||||
cancelButtonText: '取 消'
|
||||
})
|
||||
.then(() => {
|
||||
fieldsListOfListener.value.splice(index, 1)
|
||||
listenerForm.value.fields.splice(index, 1)
|
||||
})
|
||||
.catch(() => console.info('操作取消'))
|
||||
const removeListenerField = (index) => {
|
||||
// debugger
|
||||
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
|
||||
confirmButtonText: '确 认',
|
||||
cancelButtonText: '取 消'
|
||||
})
|
||||
.then(() => {
|
||||
fieldsListOfListener.value.splice(index, 1)
|
||||
listenerForm.value.fields.splice(index, 1)
|
||||
})
|
||||
.catch(() => console.info('操作取消'))
|
||||
}
|
||||
// 移除监听器
|
||||
const removeListener = index => {
|
||||
debugger
|
||||
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
|
||||
confirmButtonText: '确 认',
|
||||
cancelButtonText: '取 消'
|
||||
})
|
||||
.then(() => {
|
||||
bpmnElementListeners.value.splice(index, 1)
|
||||
elementListenersList.value.splice(index, 1)
|
||||
updateElementExtensions(bpmnElement.value, otherExtensionList.value.concat(bpmnElementListeners.value))
|
||||
})
|
||||
.catch(() => console.info('操作取消'))
|
||||
const removeListener = (index) => {
|
||||
debugger
|
||||
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
|
||||
confirmButtonText: '确 认',
|
||||
cancelButtonText: '取 消'
|
||||
})
|
||||
.then(() => {
|
||||
bpmnElementListeners.value.splice(index, 1)
|
||||
elementListenersList.value.splice(index, 1)
|
||||
updateElementExtensions(
|
||||
bpmnElement.value,
|
||||
otherExtensionList.value.concat(bpmnElementListeners.value)
|
||||
)
|
||||
})
|
||||
.catch(() => console.info('操作取消'))
|
||||
}
|
||||
// 保存监听器配置
|
||||
const saveListenerConfig = async () => {
|
||||
// debugger
|
||||
let validateStatus = await listenerFormRef.value.validate()
|
||||
if (!validateStatus) return // 验证不通过直接返回
|
||||
const listenerObject = createListenerObject(listenerForm.value, false, prefix)
|
||||
if (editingListenerIndex.value === -1) {
|
||||
bpmnElementListeners.value.push(listenerObject)
|
||||
elementListenersList.value.push(listenerForm.value)
|
||||
} else {
|
||||
bpmnElementListeners.value.splice(editingListenerIndex.value, 1, listenerObject)
|
||||
elementListenersList.value.splice(editingListenerIndex.value, 1, listenerForm.value)
|
||||
}
|
||||
// 保存其他配置
|
||||
otherExtensionList.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
ex => ex.$type !== `${prefix}:ExecutionListener`
|
||||
) ?? []
|
||||
updateElementExtensions(bpmnElement.value, otherExtensionList.value.concat(bpmnElementListeners.value))
|
||||
// 4. 隐藏侧边栏
|
||||
listenerFormModelVisible.value = false
|
||||
listenerForm.value = {}
|
||||
// debugger
|
||||
let validateStatus = await listenerFormRef.value.validate()
|
||||
if (!validateStatus) return // 验证不通过直接返回
|
||||
const listenerObject = createListenerObject(listenerForm.value, false, prefix)
|
||||
if (editingListenerIndex.value === -1) {
|
||||
bpmnElementListeners.value.push(listenerObject)
|
||||
elementListenersList.value.push(listenerForm.value)
|
||||
} else {
|
||||
bpmnElementListeners.value.splice(editingListenerIndex.value, 1, listenerObject)
|
||||
elementListenersList.value.splice(editingListenerIndex.value, 1, listenerForm.value)
|
||||
}
|
||||
// 保存其他配置
|
||||
otherExtensionList.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
(ex) => ex.$type !== `${prefix}:ExecutionListener`
|
||||
) ?? []
|
||||
updateElementExtensions(
|
||||
bpmnElement.value,
|
||||
otherExtensionList.value.concat(bpmnElementListeners.value)
|
||||
)
|
||||
// 4. 隐藏侧边栏
|
||||
listenerFormModelVisible.value = false
|
||||
listenerForm.value = {}
|
||||
}
|
||||
|
||||
// 打开监听器弹窗
|
||||
const processListenerDialogRef = ref()
|
||||
const openProcessListenerDialog = async () => {
|
||||
processListenerDialogRef.value.open('execution')
|
||||
processListenerDialogRef.value.open('execution')
|
||||
}
|
||||
const selectProcessListener = listener => {
|
||||
const listenerForm = initListenerForm2(listener)
|
||||
const listenerObject = createListenerObject(listenerForm, false, prefix)
|
||||
bpmnElementListeners.value.push(listenerObject)
|
||||
elementListenersList.value.push(listenerForm)
|
||||
const selectProcessListener = (listener) => {
|
||||
const listenerForm = initListenerForm2(listener)
|
||||
const listenerObject = createListenerObject(listenerForm, false, prefix)
|
||||
bpmnElementListeners.value.push(listenerObject)
|
||||
elementListenersList.value.push(listenerForm)
|
||||
|
||||
// 保存其他配置
|
||||
otherExtensionList.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
ex => ex.$type !== `${prefix}:ExecutionListener`
|
||||
) ?? []
|
||||
updateElementExtensions(bpmnElement.value, otherExtensionList.value.concat(bpmnElementListeners.value))
|
||||
// 保存其他配置
|
||||
otherExtensionList.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
(ex) => ex.$type !== `${prefix}:ExecutionListener`
|
||||
) ?? []
|
||||
updateElementExtensions(
|
||||
bpmnElement.value,
|
||||
otherExtensionList.value.concat(bpmnElementListeners.value)
|
||||
)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.id,
|
||||
val => {
|
||||
val &&
|
||||
val.length &&
|
||||
nextTick(() => {
|
||||
resetListenersList()
|
||||
})
|
||||
(val) => {
|
||||
val &&
|
||||
val.length &&
|
||||
nextTick(() => {
|
||||
resetListenersList()
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
@@ -1,81 +1,86 @@
|
||||
<!-- 执行器选择 -->
|
||||
<template>
|
||||
<Dialog title="请选择监听器" v-model="dialogVisible" width="1024px">
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||
<el-table-column label="名字" align="center" prop="name" />
|
||||
<el-table-column label="类型" align="center" prop="type">
|
||||
<template #default="scope">
|
||||
<!-- <dict-tag :type="DICT_TYPE.BPM_PROCESS_LISTENER_TYPE" :value="scope.row.type" /> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="事件" align="center" prop="event" />
|
||||
<el-table-column label="值类型" align="center" prop="valueType">
|
||||
<template #default="scope">
|
||||
<!-- <dict-tag
|
||||
:type="DICT_TYPE.BPM_PROCESS_LISTENER_VALUE_TYPE"
|
||||
:value="scope.row.valueType"
|
||||
/> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="值" align="center" prop="value" />
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="select(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
<Dialog title='请选择监听器' v-model='dialogVisible' width='1024px'>
|
||||
<ContentWrap>
|
||||
<el-table v-loading='loading' :data='list' :stripe='true' :show-overflow-tooltip='true'>
|
||||
<el-table-column label='名字' align='center' prop='name' />
|
||||
<el-table-column label='类型' align='center' prop='type'>
|
||||
<template #default='scope'>
|
||||
<dict-tag :type='DICT_TYPE.BPM_PROCESS_LISTENER_TYPE' :value='scope.row.type' />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label='事件' align='center' prop='event' />
|
||||
<el-table-column label='值类型' align='center' prop='valueType'>
|
||||
<template #default='scope'>
|
||||
<dict-tag
|
||||
:type='DICT_TYPE.BPM_PROCESS_LISTENER_VALUE_TYPE'
|
||||
:value='scope.row.valueType'
|
||||
/>
|
||||
</ContentWrap>
|
||||
</Dialog>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label='值' align='center' prop='value' />
|
||||
<el-table-column label='操作' align='center'>
|
||||
<template #default='scope'>
|
||||
<el-button link type='primary' @click='select(scope.row)'> 选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<!-- <Pagination-->
|
||||
<!-- :total='total'-->
|
||||
<!-- v-model:page='queryParams.pageNo'-->
|
||||
<!-- v-model:limit='queryParams.pageSize'-->
|
||||
<!-- @pagination='getList'-->
|
||||
<!-- />-->
|
||||
</ContentWrap>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, watch, onBeforeUnmount } from 'vue'
|
||||
// import { ProcessListenerApi, ProcessListenerVO } from '@/api/bpm/processListener'
|
||||
// import { DICT_TYPE } from '@/utils/dict'
|
||||
// import { CommonStatusEnum } from '@/utils/constants'
|
||||
<script setup lang='ts'>
|
||||
import { ProcessListenerApi, ProcessListenerVO } from '@/api/bpm/processListener'
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { CommonStatusEnum } from '@/utils/constants'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useMessage } from '@/hooks/web/useMessage'
|
||||
import DictTag from '@/components/DictTag/src/DictTag.vue'
|
||||
import ContentWrap from '@/components/ContentWrap/src/ContentWrap.vue'
|
||||
import Dialog from '@/components/Dialog/src/Dialog.vue'
|
||||
|
||||
/** BPM 流程 表单 */
|
||||
defineOptions({ name: 'ProcessListenerDialog' })
|
||||
|
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const list = ref([]) // 列表的数据
|
||||
const list = ref<ProcessListenerVO[]>([]) // 列表的数据
|
||||
const total = ref(0) // 列表的总页数
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
type: undefined
|
||||
// status: CommonStatusEnum.ENABLE
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
type: undefined,
|
||||
status: CommonStatusEnum.ENABLE
|
||||
})
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (type: string) => {
|
||||
dialogVisible.value = true
|
||||
loading.value = true
|
||||
try {
|
||||
queryParams.pageNo = 1
|
||||
queryParams.type = type
|
||||
// const data = await ProcessListenerApi.getProcessListenerPage(queryParams)
|
||||
// list.value = data.list
|
||||
// total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
dialogVisible.value = true
|
||||
loading.value = true
|
||||
try {
|
||||
queryParams.pageNo = 1
|
||||
queryParams.type = type
|
||||
const data = await ProcessListenerApi.getProcessListenerPage(queryParams)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
|
||||
/** 提交表单 */
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
const select = async row => {
|
||||
dialogVisible.value = false
|
||||
// 发送操作成功的事件
|
||||
emit('select', row)
|
||||
const select = async (row) => {
|
||||
dialogVisible.value = false
|
||||
// 发送操作成功的事件
|
||||
emit('select', row)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,288 +1,320 @@
|
||||
<template>
|
||||
<div class="panel-tab__content">
|
||||
<el-table :data="elementListenersList" size="small" border>
|
||||
<el-table-column label="序号" width="50px" type="index" />
|
||||
<el-table-column
|
||||
label="事件类型"
|
||||
min-width="80px"
|
||||
show-overflow-tooltip
|
||||
:formatter="row => listenerEventTypeObject[row.event]"
|
||||
/>
|
||||
<el-table-column label="事件id" min-width="80px" prop="id" show-overflow-tooltip />
|
||||
<el-table-column
|
||||
label="监听器类型"
|
||||
min-width="80px"
|
||||
show-overflow-tooltip
|
||||
:formatter="row => listenerTypeObject[row.listenerType]"
|
||||
/>
|
||||
<el-table-column label="操作" width="90px">
|
||||
<template #default="scope">
|
||||
<el-button size="small" link @click="openListenerForm(scope.row, scope.$index)">编辑</el-button>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button
|
||||
size="small"
|
||||
link
|
||||
style="color: #ff4d4f"
|
||||
@click="removeListener(scope.row, scope.$index)"
|
||||
>
|
||||
移除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="element-drawer__button">
|
||||
<el-Button size="small" type="primary" icon="el-icon-Plus" @click="openListenerForm(null)">
|
||||
添加监听器
|
||||
</el-Button>
|
||||
<el-button type="success" icon="el-icon-Select" size="small" @click="openProcessListenerDialog">
|
||||
选择监听器
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 监听器 编辑/创建 部分 -->
|
||||
<el-drawer
|
||||
v-model="listenerFormModelVisible"
|
||||
title="任务监听器"
|
||||
:size="`${width}px`"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form size="small" :model="listenerForm" label-width="96px" ref="listenerFormRef">
|
||||
<el-form-item label="事件类型" prop="event" :rules="{ required: true, trigger: ['blur', 'change'] }">
|
||||
<el-select v-model="listenerForm.event">
|
||||
<el-option
|
||||
v-for="i in Object.keys(listenerEventTypeObject)"
|
||||
:key="i"
|
||||
:label="listenerEventTypeObject[i]"
|
||||
:value="i"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="监听器ID" prop="id" :rules="{ required: true, trigger: ['blur', 'change'] }">
|
||||
<el-input v-model="listenerForm.id" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="监听器类型"
|
||||
prop="listenerType"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model="listenerForm.listenerType">
|
||||
<el-option
|
||||
v-for="i in Object.keys(listenerTypeObject)"
|
||||
:key="i"
|
||||
:label="listenerTypeObject[i]"
|
||||
:value="i"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'classListener'"
|
||||
label="Java类"
|
||||
prop="class"
|
||||
key="listener-class"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.class" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'expressionListener'"
|
||||
label="表达式"
|
||||
prop="expression"
|
||||
key="listener-expression"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.expression" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
|
||||
label="代理表达式"
|
||||
prop="delegateExpression"
|
||||
key="listener-delegate"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.delegateExpression" clearable />
|
||||
</el-form-item>
|
||||
<template v-if="listenerForm.listenerType === 'scriptListener'">
|
||||
<el-form-item
|
||||
label="脚本格式"
|
||||
prop="scriptFormat"
|
||||
key="listener-script-format"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.scriptFormat" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="脚本类型"
|
||||
prop="scriptType"
|
||||
key="listener-script-type"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
|
||||
>
|
||||
<el-select v-model="listenerForm.scriptType">
|
||||
<el-option label="内联脚本" value="inlineScript" />
|
||||
<el-option label="外部脚本" value="externalScript" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.scriptType === 'inlineScript'"
|
||||
label="脚本内容"
|
||||
prop="value"
|
||||
key="listener-script"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.value" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.scriptType === 'externalScript'"
|
||||
label="资源地址"
|
||||
prop="resource"
|
||||
key="listener-resource"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.resource" clearable />
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-if="listenerForm.event === 'timeout'">
|
||||
<el-form-item label="定时器类型" prop="eventDefinitionType" key="eventDefinitionType">
|
||||
<el-select v-model="listenerForm.eventDefinitionType">
|
||||
<el-option label="日期" value="date" />
|
||||
<el-option label="持续时长" value="duration" />
|
||||
<el-option label="循环" value="cycle" />
|
||||
<el-option label="无" value="null" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="!!listenerForm.eventDefinitionType && listenerForm.eventDefinitionType !== 'null'"
|
||||
label="定时器"
|
||||
prop="eventTimeDefinitions"
|
||||
key="eventTimeDefinitions"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写定时器配置' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.eventTimeDefinitions" clearable />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
|
||||
<el-divider />
|
||||
<p class="listener-filed__title">
|
||||
<span>
|
||||
<Icon icon="ep:menu" />
|
||||
注入字段:
|
||||
</span>
|
||||
<el-button size="small" type="primary" @click="openListenerFieldForm(null)">添加字段</el-button>
|
||||
</p>
|
||||
<el-table :data="fieldsListOfListener" size="small" max-height="240" fit border style="flex: none">
|
||||
<el-table-column label="序号" width="50px" type="index" />
|
||||
<el-table-column label="字段名称" min-width="100px" prop="name" />
|
||||
<el-table-column
|
||||
label="字段类型"
|
||||
min-width="80px"
|
||||
show-overflow-tooltip
|
||||
:formatter="row => fieldTypeObject[row.fieldType]"
|
||||
/>
|
||||
<el-table-column
|
||||
label="字段值/表达式"
|
||||
min-width="100px"
|
||||
show-overflow-tooltip
|
||||
:formatter="row => row.string || row.expression"
|
||||
/>
|
||||
<el-table-column label="操作" width="100px">
|
||||
<template #default="scope">
|
||||
<el-button size="small" link @click="openListenerFieldForm(scope.row, scope.$index)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button
|
||||
size="small"
|
||||
link
|
||||
style="color: #ff4d4f"
|
||||
@click="removeListenerField(scope.row, scope.$index)"
|
||||
>
|
||||
移除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="element-drawer__button">
|
||||
<el-button size="small" @click="listenerFormModelVisible = false">取 消</el-button>
|
||||
<el-button size="small" type="primary" @click="saveListenerConfig">保 存</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 注入西段 编辑/创建 部分 -->
|
||||
<el-dialog
|
||||
title="字段配置"
|
||||
v-model="listenerFieldFormModelVisible"
|
||||
width="600px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form
|
||||
:model="listenerFieldForm"
|
||||
size="small"
|
||||
label-width="96px"
|
||||
ref="listenerFieldFormRef"
|
||||
style="height: 136px"
|
||||
>
|
||||
<el-form-item label="字段名称:" prop="name" :rules="{ required: true, trigger: ['blur', 'change'] }">
|
||||
<el-input v-model="listenerFieldForm.name" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="字段类型:"
|
||||
prop="fieldType"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model="listenerFieldForm.fieldType">
|
||||
<el-option
|
||||
v-for="i in Object.keys(fieldTypeObject)"
|
||||
:key="i"
|
||||
:label="fieldTypeObject[i]"
|
||||
:value="i"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerFieldForm.fieldType === 'string'"
|
||||
label="字段值:"
|
||||
prop="string"
|
||||
key="field-string"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerFieldForm.string" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerFieldForm.fieldType === 'expression'"
|
||||
label="表达式:"
|
||||
prop="expression"
|
||||
key="field-expression"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerFieldForm.expression" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button size="small" @click="listenerFieldFormModelVisible = false">取 消</el-button>
|
||||
<el-button size="small" type="primary" @click="saveListenerFiled">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<div class="panel-tab__content">
|
||||
<el-table :data="elementListenersList" size="small" border>
|
||||
<el-table-column label="序号" width="50px" type="index" />
|
||||
<el-table-column
|
||||
label="事件类型"
|
||||
min-width="80px"
|
||||
show-overflow-tooltip
|
||||
:formatter="(row) => listenerEventTypeObject[row.event]"
|
||||
/>
|
||||
<el-table-column label="事件id" min-width="80px" prop="id" show-overflow-tooltip />
|
||||
<el-table-column
|
||||
label="监听器类型"
|
||||
min-width="80px"
|
||||
show-overflow-tooltip
|
||||
:formatter="(row) => listenerTypeObject[row.listenerType]"
|
||||
/>
|
||||
<el-table-column label="操作" width="90px">
|
||||
<template #default="scope">
|
||||
<el-button size="small" link @click="openListenerForm(scope.row, scope.$index)"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button
|
||||
size="small"
|
||||
link
|
||||
style="color: #ff4d4f"
|
||||
@click="removeListener(scope.row, scope.$index)"
|
||||
>移除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="element-drawer__button">
|
||||
<XButton
|
||||
size="small"
|
||||
type="primary"
|
||||
preIcon="ep:plus"
|
||||
title="添加监听器"
|
||||
@click="openListenerForm(null)"
|
||||
/>
|
||||
<XButton
|
||||
type="success"
|
||||
preIcon="ep:select"
|
||||
title="选择监听器"
|
||||
size="small"
|
||||
@click="openProcessListenerDialog"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 选择弹窗 -->
|
||||
<!-- <ProcessListenerDialog ref="processListenerDialogRef" @select="selectProcessListener" /> -->
|
||||
<!-- 监听器 编辑/创建 部分 -->
|
||||
<el-drawer
|
||||
v-model="listenerFormModelVisible"
|
||||
title="任务监听器"
|
||||
:size="`${width}px`"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form size="small" :model="listenerForm" label-width="96px" ref="listenerFormRef">
|
||||
<el-form-item
|
||||
label="事件类型"
|
||||
prop="event"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model="listenerForm.event">
|
||||
<el-option
|
||||
v-for="i in Object.keys(listenerEventTypeObject)"
|
||||
:key="i"
|
||||
:label="listenerEventTypeObject[i]"
|
||||
:value="i"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="监听器ID"
|
||||
prop="id"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.id" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="监听器类型"
|
||||
prop="listenerType"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model="listenerForm.listenerType">
|
||||
<el-option
|
||||
v-for="i in Object.keys(listenerTypeObject)"
|
||||
:key="i"
|
||||
:label="listenerTypeObject[i]"
|
||||
:value="i"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'classListener'"
|
||||
label="Java类"
|
||||
prop="class"
|
||||
key="listener-class"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.class" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'expressionListener'"
|
||||
label="表达式"
|
||||
prop="expression"
|
||||
key="listener-expression"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.expression" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
|
||||
label="代理表达式"
|
||||
prop="delegateExpression"
|
||||
key="listener-delegate"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerForm.delegateExpression" clearable />
|
||||
</el-form-item>
|
||||
<template v-if="listenerForm.listenerType === 'scriptListener'">
|
||||
<el-form-item
|
||||
label="脚本格式"
|
||||
prop="scriptFormat"
|
||||
key="listener-script-format"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.scriptFormat" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="脚本类型"
|
||||
prop="scriptType"
|
||||
key="listener-script-type"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
|
||||
>
|
||||
<el-select v-model="listenerForm.scriptType">
|
||||
<el-option label="内联脚本" value="inlineScript" />
|
||||
<el-option label="外部脚本" value="externalScript" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.scriptType === 'inlineScript'"
|
||||
label="脚本内容"
|
||||
prop="value"
|
||||
key="listener-script"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.value" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerForm.scriptType === 'externalScript'"
|
||||
label="资源地址"
|
||||
prop="resource"
|
||||
key="listener-resource"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.resource" clearable />
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-if="listenerForm.event === 'timeout'">
|
||||
<el-form-item label="定时器类型" prop="eventDefinitionType" key="eventDefinitionType">
|
||||
<el-select v-model="listenerForm.eventDefinitionType">
|
||||
<el-option label="日期" value="date" />
|
||||
<el-option label="持续时长" value="duration" />
|
||||
<el-option label="循环" value="cycle" />
|
||||
<el-option label="无" value="null" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="!!listenerForm.eventDefinitionType && listenerForm.eventDefinitionType !== 'null'"
|
||||
label="定时器"
|
||||
prop="eventTimeDefinitions"
|
||||
key="eventTimeDefinitions"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写定时器配置' }"
|
||||
>
|
||||
<el-input v-model="listenerForm.eventTimeDefinitions" clearable />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
|
||||
<el-divider />
|
||||
<p class="listener-filed__title">
|
||||
<span><Icon icon="ep:menu" />注入字段:</span>
|
||||
<el-button size="small" type="primary" @click="openListenerFieldForm(null)"
|
||||
>添加字段</el-button
|
||||
>
|
||||
</p>
|
||||
<el-table
|
||||
:data="fieldsListOfListener"
|
||||
size="small"
|
||||
max-height="240"
|
||||
fit
|
||||
border
|
||||
style="flex: none"
|
||||
>
|
||||
<el-table-column label="序号" width="50px" type="index" />
|
||||
<el-table-column label="字段名称" min-width="100px" prop="name" />
|
||||
<el-table-column
|
||||
label="字段类型"
|
||||
min-width="80px"
|
||||
show-overflow-tooltip
|
||||
:formatter="(row) => fieldTypeObject[row.fieldType]"
|
||||
/>
|
||||
<el-table-column
|
||||
label="字段值/表达式"
|
||||
min-width="100px"
|
||||
show-overflow-tooltip
|
||||
:formatter="(row) => row.string || row.expression"
|
||||
/>
|
||||
<el-table-column label="操作" width="100px">
|
||||
<template #default="scope">
|
||||
<el-button size="small" link @click="openListenerFieldForm(scope.row, scope.$index)"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button
|
||||
size="small"
|
||||
link
|
||||
style="color: #ff4d4f"
|
||||
@click="removeListenerField(scope.row, scope.$index)"
|
||||
>移除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="element-drawer__button">
|
||||
<el-button size="small" @click="listenerFormModelVisible = false">取 消</el-button>
|
||||
<el-button size="small" type="primary" @click="saveListenerConfig">保 存</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 注入西段 编辑/创建 部分 -->
|
||||
<el-dialog
|
||||
title="字段配置"
|
||||
v-model="listenerFieldFormModelVisible"
|
||||
width="600px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form
|
||||
:model="listenerFieldForm"
|
||||
size="small"
|
||||
label-width="96px"
|
||||
ref="listenerFieldFormRef"
|
||||
style="height: 136px"
|
||||
>
|
||||
<el-form-item
|
||||
label="字段名称:"
|
||||
prop="name"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerFieldForm.name" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="字段类型:"
|
||||
prop="fieldType"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-select v-model="listenerFieldForm.fieldType">
|
||||
<el-option
|
||||
v-for="i in Object.keys(fieldTypeObject)"
|
||||
:key="i"
|
||||
:label="fieldTypeObject[i]"
|
||||
:value="i"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerFieldForm.fieldType === 'string'"
|
||||
label="字段值:"
|
||||
prop="string"
|
||||
key="field-string"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerFieldForm.string" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="listenerFieldForm.fieldType === 'expression'"
|
||||
label="表达式:"
|
||||
prop="expression"
|
||||
key="field-expression"
|
||||
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||
>
|
||||
<el-input v-model="listenerFieldForm.expression" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button size="small" @click="listenerFieldFormModelVisible = false">取 消</el-button>
|
||||
<el-button size="small" type="primary" @click="saveListenerFiled">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<!-- 选择弹窗 -->
|
||||
<ProcessListenerDialog ref="processListenerDialogRef" @select="selectProcessListener" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, provide, ref, watch, nextTick, inject } from 'vue'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { createListenerObject, updateElementExtensions } from '../../utils'
|
||||
import { initListenerForm, initListenerType, eventType, listenerType, fieldType, initListenerForm2 } from './utilSelf'
|
||||
// import ProcessListenerDialog from '@/components/bpmnProcessDesigner/package/penal/listeners/ProcessListenerDialog.vue'
|
||||
import {
|
||||
initListenerForm,
|
||||
initListenerType,
|
||||
eventType,
|
||||
listenerType,
|
||||
fieldType,
|
||||
initListenerForm2
|
||||
} from './utilSelf'
|
||||
import ProcessListenerDialog from '@/components/bpmnProcessDesigner/package/penal/listeners/ProcessListenerDialog.vue'
|
||||
|
||||
defineOptions({ name: 'UserTaskListeners' })
|
||||
|
||||
const props = defineProps({
|
||||
id: String,
|
||||
type: String
|
||||
id: String,
|
||||
type: String
|
||||
})
|
||||
const prefix = inject('prefix')
|
||||
const width = inject('width')
|
||||
@@ -305,144 +337,155 @@ const listenerFieldFormRef = ref()
|
||||
const bpmnInstances = () => (window as any)?.bpmnInstances
|
||||
|
||||
const resetListenersList = () => {
|
||||
console.log(
|
||||
bpmnInstances().bpmnElement,
|
||||
'window.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElement'
|
||||
)
|
||||
bpmnElement.value = bpmnInstances().bpmnElement
|
||||
otherExtensionList.value = []
|
||||
bpmnElementListeners.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values.filter(
|
||||
ex => ex.$type === `${prefix}:TaskListener`
|
||||
) ?? []
|
||||
elementListenersList.value = bpmnElementListeners.value.map(listener => initListenerType(listener))
|
||||
console.log(
|
||||
bpmnInstances().bpmnElement,
|
||||
'window.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElement'
|
||||
)
|
||||
bpmnElement.value = bpmnInstances().bpmnElement
|
||||
otherExtensionList.value = []
|
||||
bpmnElementListeners.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values.filter(
|
||||
(ex) => ex.$type === `${prefix}:TaskListener`
|
||||
) ?? []
|
||||
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
|
||||
initListenerType(listener)
|
||||
)
|
||||
}
|
||||
const openListenerForm = (listener, index?) => {
|
||||
if (listener) {
|
||||
listenerForm.value = initListenerForm(listener)
|
||||
editingListenerIndex.value = index
|
||||
} else {
|
||||
listenerForm.value = {}
|
||||
editingListenerIndex.value = -1 // 标记为新增
|
||||
}
|
||||
if (listener && listener.fields) {
|
||||
fieldsListOfListener.value = listener.fields.map(field => ({
|
||||
...field,
|
||||
fieldType: field.string ? 'string' : 'expression'
|
||||
}))
|
||||
} else {
|
||||
fieldsListOfListener.value = []
|
||||
listenerForm.value['fields'] = []
|
||||
}
|
||||
// 打开侧边栏并清楚验证状态
|
||||
listenerFormModelVisible.value = true
|
||||
nextTick(() => {
|
||||
if (listenerFormRef.value) listenerFormRef.value.clearValidate()
|
||||
})
|
||||
if (listener) {
|
||||
listenerForm.value = initListenerForm(listener)
|
||||
editingListenerIndex.value = index
|
||||
} else {
|
||||
listenerForm.value = {}
|
||||
editingListenerIndex.value = -1 // 标记为新增
|
||||
}
|
||||
if (listener && listener.fields) {
|
||||
fieldsListOfListener.value = listener.fields.map((field) => ({
|
||||
...field,
|
||||
fieldType: field.string ? 'string' : 'expression'
|
||||
}))
|
||||
} else {
|
||||
fieldsListOfListener.value = []
|
||||
listenerForm.value['fields'] = []
|
||||
}
|
||||
// 打开侧边栏并清楚验证状态
|
||||
listenerFormModelVisible.value = true
|
||||
nextTick(() => {
|
||||
if (listenerFormRef.value) listenerFormRef.value.clearValidate()
|
||||
})
|
||||
}
|
||||
// 移除监听器
|
||||
const removeListener = (listener, index?) => {
|
||||
console.log(listener, 'listener')
|
||||
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
|
||||
confirmButtonText: '确 认',
|
||||
cancelButtonText: '取 消'
|
||||
console.log(listener, 'listener')
|
||||
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
|
||||
confirmButtonText: '确 认',
|
||||
cancelButtonText: '取 消'
|
||||
})
|
||||
.then(() => {
|
||||
bpmnElementListeners.value.splice(index, 1)
|
||||
elementListenersList.value.splice(index, 1)
|
||||
updateElementExtensions(
|
||||
bpmnElement.value,
|
||||
otherExtensionList.value.concat(bpmnElementListeners.value)
|
||||
)
|
||||
})
|
||||
.then(() => {
|
||||
bpmnElementListeners.value.splice(index, 1)
|
||||
elementListenersList.value.splice(index, 1)
|
||||
updateElementExtensions(bpmnElement.value, otherExtensionList.value.concat(bpmnElementListeners.value))
|
||||
})
|
||||
.catch(() => console.info('操作取消'))
|
||||
.catch(() => console.info('操作取消'))
|
||||
}
|
||||
// 保存监听器
|
||||
const saveListenerConfig = async () => {
|
||||
let validateStatus = await listenerFormRef.value.validate()
|
||||
if (!validateStatus) return // 验证不通过直接返回
|
||||
const listenerObject = createListenerObject(listenerForm.value, true, prefix)
|
||||
if (editingListenerIndex.value === -1) {
|
||||
bpmnElementListeners.value.push(listenerObject)
|
||||
elementListenersList.value.push(listenerForm.value)
|
||||
} else {
|
||||
bpmnElementListeners.value.splice(editingListenerIndex.value, 1, listenerObject)
|
||||
elementListenersList.value.splice(editingListenerIndex.value, 1, listenerForm.value)
|
||||
}
|
||||
// 保存其他配置
|
||||
otherExtensionList.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
ex => ex.$type !== `${prefix}:TaskListener`
|
||||
) ?? []
|
||||
updateElementExtensions(bpmnElement.value, otherExtensionList.value.concat(bpmnElementListeners.value))
|
||||
// 4. 隐藏侧边栏
|
||||
listenerFormModelVisible.value = false
|
||||
listenerForm.value = {}
|
||||
let validateStatus = await listenerFormRef.value.validate()
|
||||
if (!validateStatus) return // 验证不通过直接返回
|
||||
const listenerObject = createListenerObject(listenerForm.value, true, prefix)
|
||||
if (editingListenerIndex.value === -1) {
|
||||
bpmnElementListeners.value.push(listenerObject)
|
||||
elementListenersList.value.push(listenerForm.value)
|
||||
} else {
|
||||
bpmnElementListeners.value.splice(editingListenerIndex.value, 1, listenerObject)
|
||||
elementListenersList.value.splice(editingListenerIndex.value, 1, listenerForm.value)
|
||||
}
|
||||
// 保存其他配置
|
||||
otherExtensionList.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
(ex) => ex.$type !== `${prefix}:TaskListener`
|
||||
) ?? []
|
||||
updateElementExtensions(
|
||||
bpmnElement.value,
|
||||
otherExtensionList.value.concat(bpmnElementListeners.value)
|
||||
)
|
||||
// 4. 隐藏侧边栏
|
||||
listenerFormModelVisible.value = false
|
||||
listenerForm.value = {}
|
||||
}
|
||||
// 打开监听器字段编辑弹窗
|
||||
const openListenerFieldForm = (field, index?) => {
|
||||
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {}
|
||||
editingListenerFieldIndex.value = field ? index : -1
|
||||
listenerFieldFormModelVisible.value = true
|
||||
nextTick(() => {
|
||||
if (listenerFieldFormRef.value) listenerFieldFormRef.value.clearValidate()
|
||||
})
|
||||
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {}
|
||||
editingListenerFieldIndex.value = field ? index : -1
|
||||
listenerFieldFormModelVisible.value = true
|
||||
nextTick(() => {
|
||||
if (listenerFieldFormRef.value) listenerFieldFormRef.value.clearValidate()
|
||||
})
|
||||
}
|
||||
// 保存监听器注入字段
|
||||
const saveListenerFiled = async () => {
|
||||
let validateStatus = await listenerFieldFormRef.value.validate()
|
||||
if (!validateStatus) return // 验证不通过直接返回
|
||||
if (editingListenerFieldIndex.value === -1) {
|
||||
fieldsListOfListener.value.push(listenerFieldForm.value)
|
||||
listenerForm.value.fields.push(listenerFieldForm.value)
|
||||
} else {
|
||||
fieldsListOfListener.value.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||
listenerForm.value.fields.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||
}
|
||||
listenerFieldFormModelVisible.value = false
|
||||
nextTick(() => {
|
||||
listenerFieldForm.value = {}
|
||||
})
|
||||
let validateStatus = await listenerFieldFormRef.value.validate()
|
||||
if (!validateStatus) return // 验证不通过直接返回
|
||||
if (editingListenerFieldIndex.value === -1) {
|
||||
fieldsListOfListener.value.push(listenerFieldForm.value)
|
||||
listenerForm.value.fields.push(listenerFieldForm.value)
|
||||
} else {
|
||||
fieldsListOfListener.value.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||
listenerForm.value.fields.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
|
||||
}
|
||||
listenerFieldFormModelVisible.value = false
|
||||
nextTick(() => {
|
||||
listenerFieldForm.value = {}
|
||||
})
|
||||
}
|
||||
// 移除监听器字段
|
||||
const removeListenerField = (field, index) => {
|
||||
console.log(field, 'field')
|
||||
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
|
||||
confirmButtonText: '确 认',
|
||||
cancelButtonText: '取 消'
|
||||
console.log(field, 'field')
|
||||
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
|
||||
confirmButtonText: '确 认',
|
||||
cancelButtonText: '取 消'
|
||||
})
|
||||
.then(() => {
|
||||
fieldsListOfListener.value.splice(index, 1)
|
||||
listenerForm.value.fields.splice(index, 1)
|
||||
})
|
||||
.then(() => {
|
||||
fieldsListOfListener.value.splice(index, 1)
|
||||
listenerForm.value.fields.splice(index, 1)
|
||||
})
|
||||
.catch(() => console.info('操作取消'))
|
||||
.catch(() => console.info('操作取消'))
|
||||
}
|
||||
|
||||
// 打开监听器弹窗
|
||||
const processListenerDialogRef = ref()
|
||||
const openProcessListenerDialog = async () => {
|
||||
processListenerDialogRef.value.open('task')
|
||||
processListenerDialogRef.value.open('task')
|
||||
}
|
||||
const selectProcessListener = listener => {
|
||||
const listenerForm = initListenerForm2(listener)
|
||||
const listenerObject = createListenerObject(listenerForm, true, prefix)
|
||||
bpmnElementListeners.value.push(listenerObject)
|
||||
elementListenersList.value.push(listenerForm)
|
||||
const selectProcessListener = (listener) => {
|
||||
const listenerForm = initListenerForm2(listener)
|
||||
const listenerObject = createListenerObject(listenerForm, true, prefix)
|
||||
bpmnElementListeners.value.push(listenerObject)
|
||||
elementListenersList.value.push(listenerForm)
|
||||
|
||||
// 保存其他配置
|
||||
otherExtensionList.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
ex => ex.$type !== `${prefix}:TaskListener`
|
||||
) ?? []
|
||||
updateElementExtensions(bpmnElement.value, otherExtensionList.value.concat(bpmnElementListeners.value))
|
||||
// 保存其他配置
|
||||
otherExtensionList.value =
|
||||
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||
(ex) => ex.$type !== `${prefix}:TaskListener`
|
||||
) ?? []
|
||||
updateElementExtensions(
|
||||
bpmnElement.value,
|
||||
otherExtensionList.value.concat(bpmnElementListeners.value)
|
||||
)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.id,
|
||||
val => {
|
||||
val &&
|
||||
val.length &&
|
||||
nextTick(() => {
|
||||
resetListenersList()
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
() => props.id,
|
||||
(val) => {
|
||||
val &&
|
||||
val.length &&
|
||||
nextTick(() => {
|
||||
resetListenersList()
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref, watch, onBeforeUnmount,toRaw,nextTick } from 'vue'
|
||||
defineOptions({ name: 'ElementMultiInstance' })
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineOptions({ name: 'ElementOtherConfig' })
|
||||
import { onMounted, reactive, ref, watch, onBeforeUnmount,toRaw,nextTick } from 'vue'
|
||||
const props = defineProps({
|
||||
id: String
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user