Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
00dcbe16
authored
May 29, 2025
by
ZengZhiqiang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
增加BPMN流程设计器的时间事件配置面板
parent
d9bcd823
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
526 additions
and
0 deletions
+526
-0
src/components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue
+59
-0
src/components/bpmnProcessDesigner/package/penal/time-event-config/CycleConfig.vue
+119
-0
src/components/bpmnProcessDesigner/package/penal/time-event-config/DurationConfig.vue
+66
-0
src/components/bpmnProcessDesigner/package/penal/time-event-config/TimeEventConfig.vue
+282
-0
No files found.
src/components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue
View file @
00dcbe16
...
@@ -68,6 +68,11 @@
...
@@ -68,6 +68,11 @@
:business-object=
"elementBusinessObject"
:business-object=
"elementBusinessObject"
/>
/>
</el-collapse-item>
</el-collapse-item>
<!-- 新增的时间事件配置项 -->
<el-collapse-item
v-if=
"elementType === 'IntermediateCatchEvent'"
name=
"timeEvent"
>
<
template
#
title
><Icon
icon=
"ep:timer"
/>
时间事件
</
template
>
<TimeEventConfig
:businessObject=
"bpmnElement.value?.businessObject"
:key=
"elementId"
/>
</el-collapse-item>
</el-collapse>
</el-collapse>
</div>
</div>
</template>
</template>
...
@@ -83,6 +88,8 @@ import ElementProperties from './properties/ElementProperties.vue'
...
@@ -83,6 +88,8 @@ import ElementProperties from './properties/ElementProperties.vue'
// import ElementForm from './form/ElementForm.vue'
// import ElementForm from './form/ElementForm.vue'
import
UserTaskListeners
from
'./listeners/UserTaskListeners.vue'
import
UserTaskListeners
from
'./listeners/UserTaskListeners.vue'
import
{
getTaskCollapseItemName
,
isTaskCollapseItemShow
}
from
'./task/data'
import
{
getTaskCollapseItemName
,
isTaskCollapseItemShow
}
from
'./task/data'
import
TimeEventConfig
from
"./time-event-config/TimeEventConfig.vue"
import
{
ref
,
computed
,
watch
,
onMounted
}
from
'vue'
defineOptions
({
name
:
'MyPropertiesPanel'
})
defineOptions
({
name
:
'MyPropertiesPanel'
})
...
@@ -121,6 +128,8 @@ const formVisible = ref(false) // 表单配置
...
@@ -121,6 +128,8 @@ const formVisible = ref(false) // 表单配置
const
bpmnElement
=
ref
()
const
bpmnElement
=
ref
()
const
isReady
=
ref
(
false
)
const
isReady
=
ref
(
false
)
const
type
=
ref
(
'time'
)
const
condition
=
ref
(
''
)
provide
(
'prefix'
,
props
.
prefix
)
provide
(
'prefix'
,
props
.
prefix
)
provide
(
'width'
,
props
.
width
)
provide
(
'width'
,
props
.
width
)
...
@@ -255,4 +264,54 @@ watch(
...
@@ -255,4 +264,54 @@ watch(
activeTab
.
value
=
'base'
activeTab
.
value
=
'base'
}
}
)
)
function
updateNode
()
{
const
moddle
=
window
.
bpmnInstances
?.
moddle
const
modeling
=
window
.
bpmnInstances
?.
modeling
const
elementRegistry
=
window
.
bpmnInstances
?.
elementRegistry
if
(
!
moddle
||
!
modeling
||
!
elementRegistry
)
return
const
element
=
elementRegistry
.
get
(
props
.
businessObject
.
id
)
if
(
!
element
)
return
let
timerDef
=
moddle
.
create
(
'bpmn:TimerEventDefinition'
,
{})
if
(
type
.
value
===
'time'
)
{
timerDef
.
timeDate
=
moddle
.
create
(
'bpmn:FormalExpression'
,
{
body
:
condition
.
value
})
}
else
if
(
type
.
value
===
'duration'
)
{
timerDef
.
timeDuration
=
moddle
.
create
(
'bpmn:FormalExpression'
,
{
body
:
condition
.
value
})
}
else
if
(
type
.
value
===
'cycle'
)
{
timerDef
.
timeCycle
=
moddle
.
create
(
'bpmn:FormalExpression'
,
{
body
:
condition
.
value
})
}
modeling
.
updateModdleProperties
(
element
,
element
.
businessObject
,
{
eventDefinitions
:
[
timerDef
]
}
)
console
.
log
(
'当前eventDefinitions:'
,
element
.
businessObject
.
eventDefinitions
)
}
// 初始化和监听
function
syncFromBusinessObject
()
{
if
(
props
.
businessObject
)
{
const
timerDef
=
(
props
.
businessObject
.
eventDefinitions
||
[])[
0
]
if
(
timerDef
)
{
if
(
timerDef
.
timeDate
)
{
type
.
value
=
'time'
condition
.
value
=
timerDef
.
timeDate
.
body
}
else
if
(
timerDef
.
timeDuration
)
{
type
.
value
=
'duration'
condition
.
value
=
timerDef
.
timeDuration
.
body
}
else
if
(
timerDef
.
timeCycle
)
{
type
.
value
=
'cycle'
condition
.
value
=
timerDef
.
timeCycle
.
body
}
}
}
}
onMounted
(
syncFromBusinessObject
)
watch
(()
=>
props
.
businessObject
,
syncFromBusinessObject
,
{
deep
:
true
})
</
script
>
</
script
>
src/components/bpmnProcessDesigner/package/penal/time-event-config/CycleConfig.vue
0 → 100644
View file @
00dcbe16
<
template
>
<el-tabs
v-model=
"tab"
>
<el-tab-pane
label=
"CRON表达式"
name=
"cron"
>
<div
style=
"margin-bottom: 10px;"
>
<el-input
v-model=
"cronStr"
readonly
style=
"width: 400px; font-weight: bold;"
:key=
"'cronStr'"
/>
</div>
<div
style=
"display: flex; gap: 8px; margin-bottom: 8px;"
>
<el-input
v-model=
"fields.second"
placeholder=
"秒"
style=
"width: 80px;"
:key=
"'second'"
/>
<el-input
v-model=
"fields.minute"
placeholder=
"分"
style=
"width: 80px;"
:key=
"'minute'"
/>
<el-input
v-model=
"fields.hour"
placeholder=
"时"
style=
"width: 80px;"
:key=
"'hour'"
/>
<el-input
v-model=
"fields.day"
placeholder=
"天"
style=
"width: 80px;"
:key=
"'day'"
/>
<el-input
v-model=
"fields.month"
placeholder=
"月"
style=
"width: 80px;"
:key=
"'month'"
/>
<el-input
v-model=
"fields.week"
placeholder=
"周"
style=
"width: 80px;"
:key=
"'week'"
/>
<el-input
v-model=
"fields.year"
placeholder=
"年"
style=
"width: 80px;"
:key=
"'year'"
/>
</div>
<el-tabs
v-model=
"activeField"
type=
"card"
style=
"margin-bottom: 8px;"
>
<el-tab-pane
v-for=
"f in cronFieldList"
:label=
"f.label"
:name=
"f.key"
:key=
"f.key"
>
<div
style=
"margin-bottom: 8px;"
>
<el-radio-group
v-model=
"cronMode[f.key]"
:key=
"'radio-'+f.key"
>
<el-radio
label=
"every"
:key=
"'every-'+f.key"
>
每
{{
f
.
label
}}
</el-radio>
<el-radio
label=
"range"
:key=
"'range-'+f.key"
>
从
<el-input-number
v-model=
"cronRange[f.key][0]"
:min=
"f.min"
:max=
"f.max"
size=
"small"
style=
"width:60px"
:key=
"'range0-'+f.key"
/>
到
<el-input-number
v-model=
"cronRange[f.key][1]"
:min=
"f.min"
:max=
"f.max"
size=
"small"
style=
"width:60px"
:key=
"'range1-'+f.key"
/>
之间每
{{
f
.
label
}}
</el-radio>
<el-radio
label=
"step"
:key=
"'step-'+f.key"
>
从第
<el-input-number
v-model=
"cronStep[f.key][0]"
:min=
"f.min"
:max=
"f.max"
size=
"small"
style=
"width:60px"
:key=
"'step0-'+f.key"
/>
开始每
<el-input-number
v-model=
"cronStep[f.key][1]"
:min=
"1"
:max=
"f.max"
size=
"small"
style=
"width:60px"
:key=
"'step1-'+f.key"
/>
{{
f
.
label
}}
</el-radio>
<el-radio
label=
"appoint"
:key=
"'appoint-'+f.key"
>
指定
</el-radio>
</el-radio-group>
</div>
<div
v-if=
"cronMode[f.key]==='appoint'"
>
<el-checkbox-group
v-model=
"cronAppoint[f.key]"
:key=
"'group-'+f.key"
>
<el-checkbox
v-for=
"n in f.max+1"
:label=
"pad(n-1)"
:key=
"'cb-'+f.key+'-'+(n-1)"
>
{{
pad
(
n
-
1
)
}}
</el-checkbox>
</el-checkbox-group>
</div>
</el-tab-pane>
</el-tabs>
</el-tab-pane>
<el-tab-pane
label=
"标准格式"
name=
"iso"
:key=
"'iso-tab'"
>
<div
style=
"margin-bottom: 10px;"
>
<el-input
v-model=
"isoStr"
placeholder=
"如R1/2025-05-21T21:59:54/P3DT30M30S"
style=
"width: 400px; font-weight: bold;"
:key=
"'isoStr'"
/>
</div>
<div
style=
"margin-bottom: 10px;"
>
循环次数:
<el-input-number
v-model=
"repeat"
:min=
"1"
style=
"width: 100px;"
:key=
"'repeat'"
/></div>
<div
style=
"margin-bottom: 10px;"
>
日期时间:
<el-date-picker
v-model=
"isoDate"
type=
"datetime"
placeholder=
"选择日期时间"
style=
"width: 200px;"
:key=
"'isoDate'"
/></div>
<div
style=
"margin-bottom: 10px;"
>
当前时长:
<el-input
v-model=
"isoDuration"
placeholder=
"如P3DT30M30S"
style=
"width: 200px;"
:key=
"'isoDuration'"
/></div>
<div>
<div>
秒:
<el-button
v-for=
"s in [5,10,30,50]"
@
click=
"setDuration('S',s)"
:key=
"'sec-'+s"
>
{{
s
}}
</el-button>
自定义
</div>
<div>
分:
<el-button
v-for=
"m in [5,10,30,50]"
@
click=
"setDuration('M',m)"
:key=
"'min-'+m"
>
{{
m
}}
</el-button>
自定义
</div>
<div>
小时:
<el-button
v-for=
"h in [4,8,12,24]"
@
click=
"setDuration('H',h)"
:key=
"'hour-'+h"
>
{{
h
}}
</el-button>
自定义
</div>
<div>
天:
<el-button
v-for=
"d in [1,2,3,4]"
@
click=
"setDuration('D',d)"
:key=
"'day-'+d"
>
{{
d
}}
</el-button>
自定义
</div>
<div>
月:
<el-button
v-for=
"mo in [1,2,3,4]"
@
click=
"setDuration('M',mo)"
:key=
"'mon-'+mo"
>
{{
mo
}}
</el-button>
自定义
</div>
<div>
年:
<el-button
v-for=
"y in [1,2,3,4]"
@
click=
"setDuration('Y',y)"
:key=
"'year-'+y"
>
{{
y
}}
</el-button>
自定义
</div>
</div>
</el-tab-pane>
</el-tabs>
</
template
>
<
script
setup
>
import
{
ref
,
watch
,
computed
}
from
'vue'
const
props
=
defineProps
({
value
:
String
})
const
emit
=
defineEmits
([
'change'
])
const
tab
=
ref
(
'cron'
)
const
cronStr
=
ref
(
props
.
value
||
'* * * * * ?'
)
const
fields
=
ref
({
second
:
'*'
,
minute
:
'*'
,
hour
:
'*'
,
day
:
'*'
,
month
:
'*'
,
week
:
'?'
,
year
:
''
})
const
cronFieldList
=
[
{
key
:
'second'
,
label
:
'秒'
,
min
:
0
,
max
:
59
},
{
key
:
'minute'
,
label
:
'分'
,
min
:
0
,
max
:
59
},
{
key
:
'hour'
,
label
:
'时'
,
min
:
0
,
max
:
23
},
{
key
:
'day'
,
label
:
'天'
,
min
:
1
,
max
:
31
},
{
key
:
'month'
,
label
:
'月'
,
min
:
1
,
max
:
12
},
{
key
:
'week'
,
label
:
'周'
,
min
:
1
,
max
:
7
},
{
key
:
'year'
,
label
:
'年'
,
min
:
1970
,
max
:
2099
}
]
const
activeField
=
ref
(
'second'
)
const
cronMode
=
ref
({
second
:
'appoint'
,
minute
:
'every'
,
hour
:
'every'
,
day
:
'every'
,
month
:
'every'
,
week
:
'every'
,
year
:
'every'
})
const
cronAppoint
=
ref
({
second
:
[
'00'
,
'01'
],
minute
:
[],
hour
:
[],
day
:
[],
month
:
[],
week
:
[],
year
:
[]
})
const
cronRange
=
ref
({
second
:
[
0
,
1
],
minute
:
[
0
,
1
],
hour
:
[
0
,
1
],
day
:
[
1
,
2
],
month
:
[
1
,
2
],
week
:
[
1
,
2
],
year
:
[
1970
,
1971
]
})
const
cronStep
=
ref
({
second
:
[
1
,
1
],
minute
:
[
1
,
1
],
hour
:
[
1
,
1
],
day
:
[
1
,
1
],
month
:
[
1
,
1
],
week
:
[
1
,
1
],
year
:
[
1970
,
1
]
})
function
pad
(
n
)
{
return
n
<
10
?
'0'
+
n
:
''
+
n
}
watch
([
fields
,
cronMode
,
cronAppoint
,
cronRange
,
cronStep
],
()
=>
{
// 组装cron表达式
let
arr
=
cronFieldList
.
map
(
f
=>
{
if
(
cronMode
.
value
[
f
.
key
]
===
'every'
)
return
'*'
if
(
cronMode
.
value
[
f
.
key
]
===
'appoint'
)
return
cronAppoint
.
value
[
f
.
key
].
join
(
','
)
||
'*'
if
(
cronMode
.
value
[
f
.
key
]
===
'range'
)
return
`
${
cronRange
.
value
[
f
.
key
][
0
]}
-
${
cronRange
.
value
[
f
.
key
][
1
]}
`
if
(
cronMode
.
value
[
f
.
key
]
===
'step'
)
return
`
${
cronStep
.
value
[
f
.
key
][
0
]}
/
${
cronStep
.
value
[
f
.
key
][
1
]}
`
return
fields
.
value
[
f
.
key
]
||
'*'
})
// week和year特殊处理
arr
[
5
]
=
arr
[
5
]
||
'?'
cronStr
.
value
=
arr
.
join
(
' '
)
if
(
tab
.
value
===
'cron'
)
emit
(
'change'
,
cronStr
.
value
)
},
{
deep
:
true
})
// 标准格式
const
isoStr
=
ref
(
''
)
const
repeat
=
ref
(
1
)
const
isoDate
=
ref
(
''
)
const
isoDuration
=
ref
(
''
)
function
setDuration
(
type
,
val
)
{
// 组装ISO 8601字符串
let
d
=
isoDuration
.
value
if
(
!
d
.
includes
(
type
))
d
+=
val
+
type
else
d
=
d
.
replace
(
new
RegExp
(
`\\d+
${
type
}
`
),
val
+
type
)
isoDuration
.
value
=
d
updateIsoStr
()
}
function
updateIsoStr
()
{
let
str
=
`R
${
repeat
.
value
}
`
if
(
isoDate
.
value
)
str
+=
'/'
+
(
typeof
isoDate
.
value
===
'string'
?
isoDate
.
value
:
new
Date
(
isoDate
.
value
).
toISOString
())
if
(
isoDuration
.
value
)
str
+=
'/'
+
isoDuration
.
value
isoStr
.
value
=
str
if
(
tab
.
value
===
'iso'
)
emit
(
'change'
,
isoStr
.
value
)
}
watch
([
repeat
,
isoDate
,
isoDuration
],
updateIsoStr
)
watch
(()
=>
props
.
value
,
(
val
)
=>
{
if
(
!
val
)
return
if
(
tab
.
value
===
'cron'
)
cronStr
.
value
=
val
if
(
tab
.
value
===
'iso'
)
isoStr
.
value
=
val
},
{
immediate
:
true
})
</
script
>
\ No newline at end of file
src/components/bpmnProcessDesigner/package/penal/time-event-config/DurationConfig.vue
0 → 100644
View file @
00dcbe16
<
template
>
<div>
<div
style=
"margin-bottom: 10px;"
>
当前选择:
<el-input
v-model=
"isoString"
readonly
style=
"width: 300px;"
/></div>
<div
v-for=
"unit in units"
:key=
"unit.key"
style=
"margin-bottom: 8px;"
>
<span>
{{
unit
.
label
}}
:
</span>
<el-button-group>
<el-button
v-for=
"val in unit.presets"
:key=
"val"
size=
"mini"
@
click=
"setUnit(unit.key, val)"
>
{{
val
}}
</el-button>
<el-input
v-model
.
number=
"custom[unit.key]"
size=
"mini"
style=
"width: 60px; margin-left: 8px;"
placeholder=
"自定义"
@
change=
"setUnit(unit.key, custom[unit.key])"
/>
</el-button-group>
</div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
watch
,
computed
}
from
'vue'
const
props
=
defineProps
({
value
:
String
})
const
emit
=
defineEmits
([
'change'
])
const
units
=
[
{
key
:
'Y'
,
label
:
'年'
,
presets
:
[
1
,
2
,
3
,
4
]
},
{
key
:
'M'
,
label
:
'月'
,
presets
:
[
1
,
2
,
3
,
4
]
},
{
key
:
'D'
,
label
:
'天'
,
presets
:
[
1
,
2
,
3
,
4
]
},
{
key
:
'H'
,
label
:
'时'
,
presets
:
[
4
,
8
,
12
,
24
]
},
{
key
:
'm'
,
label
:
'分'
,
presets
:
[
5
,
10
,
30
,
50
]
},
{
key
:
'S'
,
label
:
'秒'
,
presets
:
[
5
,
10
,
30
,
50
]
}
]
const
custom
=
ref
({
Y
:
''
,
M
:
''
,
D
:
''
,
H
:
''
,
m
:
''
,
S
:
''
})
const
isoString
=
ref
(
''
)
function
setUnit
(
key
,
val
)
{
if
(
!
val
||
isNaN
(
val
))
{
custom
.
value
[
key
]
=
''
return
}
custom
.
value
[
key
]
=
val
updateIsoString
()
}
function
updateIsoString
()
{
let
str
=
'P'
if
(
custom
.
value
.
Y
)
str
+=
custom
.
value
.
Y
+
'Y'
if
(
custom
.
value
.
M
)
str
+=
custom
.
value
.
M
+
'M'
if
(
custom
.
value
.
D
)
str
+=
custom
.
value
.
D
+
'D'
if
(
custom
.
value
.
H
||
custom
.
value
.
m
||
custom
.
value
.
S
)
str
+=
'T'
if
(
custom
.
value
.
H
)
str
+=
custom
.
value
.
H
+
'H'
if
(
custom
.
value
.
m
)
str
+=
custom
.
value
.
m
+
'M'
if
(
custom
.
value
.
S
)
str
+=
custom
.
value
.
S
+
'S'
isoString
.
value
=
str
===
'P'
?
''
:
str
emit
(
'change'
,
isoString
.
value
)
}
watch
(()
=>
props
.
value
,
(
val
)
=>
{
if
(
!
val
)
return
// 解析ISO 8601字符串到custom
const
match
=
val
.
match
(
/^P
(?:(\d
+
)
Y
)?(?:(\d
+
)
M
)?(?:(\d
+
)
D
)?(?:
T
(?:(\d
+
)
H
)?(?:(\d
+
)
M
)?(?:(\d
+
)
S
)?)?
$/
)
if
(
match
)
{
custom
.
value
.
Y
=
match
[
1
]
||
''
custom
.
value
.
M
=
match
[
2
]
||
''
custom
.
value
.
D
=
match
[
3
]
||
''
custom
.
value
.
H
=
match
[
4
]
||
''
custom
.
value
.
m
=
match
[
5
]
||
''
custom
.
value
.
S
=
match
[
6
]
||
''
updateIsoString
()
}
},
{
immediate
:
true
})
</
script
>
src/components/bpmnProcessDesigner/package/penal/time-event-config/TimeEventConfig.vue
0 → 100644
View file @
00dcbe16
<
template
>
<div
class=
"panel-tab__content"
>
<div
style=
"margin-top: 10px;"
>
<span>
类型:
</span>
<el-button-group>
<el-button
size=
"mini"
:type=
"type==='time'?'primary':''"
@
click=
"setType('time')"
>
时间
</el-button>
<el-button
size=
"mini"
:type=
"type==='duration'?'primary':''"
@
click=
"setType('duration')"
>
持续
</el-button>
<el-button
size=
"mini"
:type=
"type==='cycle'?'primary':''"
@
click=
"setType('cycle')"
>
循环
</el-button>
</el-button-group>
<el-icon
v-if=
"valid"
color=
"green"
style=
"margin-left:8px"
><CircleCheckFilled
/></el-icon>
</div>
<div
style=
"margin-top: 10px; display: flex; align-items: center;"
>
<span>
条件:
</span>
<el-input
v-model=
"condition"
:placeholder=
"placeholder"
style=
"width: calc(100% - 100px);"
:readonly=
"type !== 'duration' && type !== 'cycle'"
@
focus=
"handleInputFocus"
@
blur=
"updateNode"
>
<template
#
suffix
>
<el-tooltip
v-if=
"!valid"
content=
"格式错误"
placement=
"top"
>
<el-icon
color=
"orange"
><WarningFilled
/></el-icon>
</el-tooltip>
<el-tooltip
:content=
"helpText"
placement=
"top"
>
<el-icon
color=
"#409EFF"
style=
"cursor: pointer"
@
click=
"showHelp = true"
><QuestionFilled
/></el-icon>
</el-tooltip>
<el-button
v-if=
"type === 'time'"
@
click=
"showDatePicker = true"
style=
"margin-left: 4px"
circle
size=
"small"
>
<Icon
icon=
"ep:calendar"
/>
</el-button>
<el-button
v-if=
"type === 'duration'"
@
click=
"showDurationDialog = true"
style=
"margin-left: 4px"
circle
size=
"small"
>
<Icon
icon=
"ep:timer"
/>
</el-button>
<el-button
v-if=
"type === 'cycle'"
@
click=
"showCycleDialog = true"
style=
"margin-left: 4px"
circle
size=
"small"
>
<Icon
icon=
"ep:setting"
/>
</el-button>
</
template
>
</el-input>
</div>
<!-- 时间选择器 -->
<el-dialog
v-model=
"showDatePicker"
title=
"选择时间"
width=
"400px"
@
close=
"showDatePicker=false"
>
<el-date-picker
v-model=
"dateValue"
type=
"datetime"
placeholder=
"选择日期时间"
style=
"width: 100%;"
@
change=
"onDateChange"
/>
<
template
#
footer
>
<el-button
@
click=
"showDatePicker=false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"onDateConfirm"
>
确定
</el-button>
</
template
>
</el-dialog>
<!-- 持续时长选择器 -->
<el-dialog
v-model=
"showDurationDialog"
title=
"时间配置"
width=
"600px"
@
close=
"showDurationDialog=false"
>
<DurationConfig
:value=
"condition"
@
change=
"onDurationChange"
/>
<
template
#
footer
>
<el-button
@
click=
"showDurationDialog=false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"onDurationConfirm"
>
确定
</el-button>
</
template
>
</el-dialog>
<!-- 循环配置器 -->
<el-dialog
v-model=
"showCycleDialog"
title=
"时间配置"
width=
"800px"
@
close=
"showCycleDialog=false"
>
<CycleConfig
:value=
"condition"
@
change=
"onCycleChange"
/>
<
template
#
footer
>
<el-button
@
click=
"showCycleDialog=false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"onCycleConfirm"
>
确定
</el-button>
</
template
>
</el-dialog>
<!-- 帮助说明 -->
<el-dialog
v-model=
"showHelp"
title=
"格式说明"
width=
"600px"
@
close=
"showHelp=false"
>
<div
v-html=
"helpHtml"
></div>
<
template
#
footer
>
<el-button
@
click=
"showHelp=false"
>
关闭
</el-button>
</
template
>
</el-dialog>
</div>
</template>
<
script
lang=
"ts"
setup
>
import
{
ref
,
computed
,
watch
,
onMounted
}
from
'vue'
import
{
CircleCheckFilled
,
WarningFilled
,
QuestionFilled
}
from
'@element-plus/icons-vue'
import
DurationConfig
from
'./DurationConfig.vue'
import
CycleConfig
from
'./CycleConfig.vue'
import
{
createListenerObject
,
updateElementExtensions
}
from
'../../utils'
const
bpmnInstances
=
()
=>
(
window
as
any
).
bpmnInstances
const
props
=
defineProps
({
businessObject
:
Object
})
const
type
=
ref
(
'time'
)
const
condition
=
ref
(
''
)
const
valid
=
ref
(
true
)
const
showDatePicker
=
ref
(
false
)
const
showDurationDialog
=
ref
(
false
)
const
showCycleDialog
=
ref
(
false
)
const
showHelp
=
ref
(
false
)
const
dateValue
=
ref
(
null
)
const
bpmnElement
=
ref
(
null
)
const
placeholder
=
computed
(()
=>
{
if
(
type
.
value
===
'time'
)
return
'请输入时间'
if
(
type
.
value
===
'duration'
)
return
'请输入持续时长'
if
(
type
.
value
===
'cycle'
)
return
'请输入循环表达式'
return
''
})
const
helpText
=
computed
(()
=>
{
if
(
type
.
value
===
'time'
)
return
'选择具体时间'
if
(
type
.
value
===
'duration'
)
return
'ISO 8601格式,如PT1H'
if
(
type
.
value
===
'cycle'
)
return
'CRON表达式或ISO 8601周期'
return
''
})
const
helpHtml
=
computed
(()
=>
{
if
(
type
.
value
===
'duration'
)
{
return
`指定定时器之前要等待多长时间。S表示秒,M表示分,D表示天;P表示时间段,T表示精确到时间的时间段。<br>
时间格式依然为ISO 8601格式,一年两个月三天四小时五分六秒内,可以写成P1Y2M3DT4H5M6S。<br>
P是开始标记,T是时间和日期分割标记,没有日期只有时间T是不能省去的,比如1小时执行一次应写成PT1H。`
}
if
(
type
.
value
===
'cycle'
)
{
return
`支持CRON表达式(如0 0/30 * * * ?)或ISO 8601周期(如R3/PT10M)。`
}
return
''
})
// 初始化和监听
function
syncFromBusinessObject
()
{
if
(
props
.
businessObject
)
{
const
timerDef
=
(
props
.
businessObject
.
eventDefinitions
||
[])[
0
]
if
(
timerDef
)
{
if
(
timerDef
.
timeDate
)
{
type
.
value
=
'time'
condition
.
value
=
timerDef
.
timeDate
.
body
}
else
if
(
timerDef
.
timeDuration
)
{
type
.
value
=
'duration'
condition
.
value
=
timerDef
.
timeDuration
.
body
}
else
if
(
timerDef
.
timeCycle
)
{
type
.
value
=
'cycle'
condition
.
value
=
timerDef
.
timeCycle
.
body
}
}
}
}
onMounted
(
syncFromBusinessObject
)
// 切换类型
function
setType
(
t
)
{
type
.
value
=
t
condition
.
value
=
''
updateNode
()
}
// 输入校验
watch
([
type
,
condition
],
()
=>
{
valid
.
value
=
validate
()
// updateNode() // 可以注释掉,避免频繁触发
})
function
validate
()
{
if
(
type
.
value
===
'time'
)
{
return
!!
condition
.
value
&&
!
isNaN
(
Date
.
parse
(
condition
.
value
))
}
if
(
type
.
value
===
'duration'
)
{
return
/^P.*$/
.
test
(
condition
.
value
)
}
if
(
type
.
value
===
'cycle'
)
{
return
/^
([
0-9*
\/
?,
]
+|R
\d
*
\/
P.*
)
$/
.
test
(
condition
.
value
)
}
return
true
}
// 选择时间
function
onDateChange
(
val
)
{
dateValue
.
value
=
val
}
function
onDateConfirm
()
{
if
(
dateValue
.
value
)
{
condition
.
value
=
new
Date
(
dateValue
.
value
).
toISOString
()
showDatePicker
.
value
=
false
updateNode
()
}
}
// 持续时长
function
onDurationChange
(
val
)
{
condition
.
value
=
val
}
function
onDurationConfirm
()
{
showDurationDialog
.
value
=
false
updateNode
()
}
// 循环
function
onCycleChange
(
val
)
{
condition
.
value
=
val
}
function
onCycleConfirm
()
{
showCycleDialog
.
value
=
false
updateNode
()
}
// 输入框聚焦时弹窗(可选)
function
handleInputFocus
()
{
if
(
type
.
value
===
'time'
)
showDatePicker
.
value
=
true
if
(
type
.
value
===
'duration'
)
showDurationDialog
.
value
=
true
if
(
type
.
value
===
'cycle'
)
showCycleDialog
.
value
=
true
}
// 同步到节点
function
updateNode
()
{
const
moddle
=
window
.
bpmnInstances
?.
moddle
const
modeling
=
window
.
bpmnInstances
?.
modeling
const
elementRegistry
=
window
.
bpmnInstances
?.
elementRegistry
if
(
!
moddle
||
!
modeling
||
!
elementRegistry
)
return
// 获取元素
if
(
!
props
.
businessObject
||
!
props
.
businessObject
.
id
)
return
const
element
=
elementRegistry
.
get
(
props
.
businessObject
.
id
)
if
(
!
element
)
return
// 1. 复用原有 timerDef,或新建
let
timerDef
=
(
element
.
businessObject
.
eventDefinitions
&&
element
.
businessObject
.
eventDefinitions
[
0
])
if
(
!
timerDef
)
{
timerDef
=
bpmnInstances
().
bpmnFactory
.
create
(
'bpmn:TimerEventDefinition'
,
{})
modeling
.
updateProperties
(
element
,
{
eventDefinitions
:
[
timerDef
]
})
}
// 2. 清空原有
delete
timerDef
.
timeDate
delete
timerDef
.
timeDuration
delete
timerDef
.
timeCycle
// 3. 设置新的
if
(
type
.
value
===
'time'
&&
condition
.
value
)
{
timerDef
.
timeDate
=
bpmnInstances
().
bpmnFactory
.
create
(
'bpmn:FormalExpression'
,
{
body
:
condition
.
value
})
}
else
if
(
type
.
value
===
'duration'
&&
condition
.
value
)
{
timerDef
.
timeDuration
=
bpmnInstances
().
bpmnFactory
.
create
(
'bpmn:FormalExpression'
,
{
body
:
condition
.
value
})
}
else
if
(
type
.
value
===
'cycle'
&&
condition
.
value
)
{
timerDef
.
timeCycle
=
bpmnInstances
().
bpmnFactory
.
create
(
'bpmn:FormalExpression'
,
{
body
:
condition
.
value
})
}
bpmnInstances
().
modeling
.
updateProperties
(
toRaw
(
element
),
{
eventDefinitions
:
[
timerDef
]
})
}
watch
(
()
=>
props
.
businessObject
,
(
val
)
=>
{
if
(
val
)
{
nextTick
(()
=>
{
syncFromBusinessObject
()
})
}
},
{
immediate
:
true
}
)
</
script
>
<
style
scoped
>
/* 相关样式 */
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment