ServiceTask.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <template>
  2. <div>
  3. <el-form-item label="执行方式" key="executeType">
  4. <el-select v-model="serviceTaskForm.executeType" @change="handleExecuteTypeChange">
  5. <el-option label="Java类" value="class" />
  6. <el-option label="表达式" value="expression" />
  7. <el-option label="代理表达式" value="delegateExpression" />
  8. <el-option label="HTTP 调用" value="http" />
  9. </el-select>
  10. </el-form-item>
  11. <el-form-item
  12. v-if="serviceTaskForm.executeType === 'class'"
  13. label="Java类"
  14. prop="class"
  15. key="execute-class"
  16. >
  17. <el-input v-model="serviceTaskForm.class" clearable @change="updateElementTask" />
  18. </el-form-item>
  19. <el-form-item
  20. v-if="serviceTaskForm.executeType === 'expression'"
  21. label="表达式"
  22. prop="expression"
  23. key="execute-expression"
  24. >
  25. <el-input v-model="serviceTaskForm.expression" clearable @change="updateElementTask" />
  26. </el-form-item>
  27. <el-form-item
  28. v-if="serviceTaskForm.executeType === 'delegateExpression'"
  29. label="代理表达式"
  30. prop="delegateExpression"
  31. key="execute-delegate"
  32. >
  33. <el-input v-model="serviceTaskForm.delegateExpression" clearable @change="updateElementTask" />
  34. </el-form-item>
  35. <template v-if="serviceTaskForm.executeType === 'http'">
  36. <el-form-item label="请求方法" key="http-method">
  37. <el-select v-model="httpTaskForm.requestMethod">
  38. <el-option label="GET" value="GET" />
  39. <el-option label="POST" value="POST" />
  40. <el-option label="PUT" value="PUT" />
  41. <el-option label="DELETE" value="DELETE" />
  42. <el-option label="PATCH" value="PATCH" />
  43. <el-option label="HEAD" value="HEAD" />
  44. <el-option label="OPTIONS" value="OPTIONS" />
  45. </el-select>
  46. </el-form-item>
  47. <el-form-item label="请求地址" key="http-url" prop="requestUrl">
  48. <el-input v-model="httpTaskForm.requestUrl" clearable />
  49. </el-form-item>
  50. <el-form-item label="请求头" key="http-headers">
  51. <el-input
  52. v-model="httpTaskForm.requestHeaders"
  53. type="textarea"
  54. resize="vertical"
  55. :autosize="{ minRows: 2, maxRows: 4 }"
  56. clearable
  57. />
  58. </el-form-item>
  59. <!-- <el-form-item label="禁止重定向" key="http-disallow-redirects">-->
  60. <!-- <el-switch v-model="httpTaskForm.disallowRedirects" />-->
  61. <!-- </el-form-item>-->
  62. <!-- <el-form-item label="忽略异常" key="http-ignore-exception">-->
  63. <!-- <el-switch v-model="httpTaskForm.ignoreException" />-->
  64. <!-- </el-form-item>-->
  65. <!-- <el-form-item label="瞬态保存响应参数" key="http-save-transient">-->
  66. <!-- <el-switch v-model="httpTaskForm.saveResponseParametersTransient" />-->
  67. <!-- </el-form-item>-->
  68. <!-- <el-form-item label="JSON 保存响应变量" key="http-save-json">-->
  69. <!-- <el-switch v-model="httpTaskForm.saveResponseVariableAsJson" />-->
  70. <!-- </el-form-item>-->
  71. </template>
  72. </div>
  73. </template>
  74. <script lang="ts" setup>
  75. import { updateElementExtensions } from '@/components/bpmnProcessDesigner/package/utils'
  76. defineOptions({ name: 'ServiceTask' })
  77. const props = defineProps({
  78. id: String,
  79. type: String
  80. })
  81. const prefix = (inject('prefix', 'flowable') || 'flowable') as string
  82. const flowableTypeKey = `${prefix}:type`
  83. const flowableFieldType = `${prefix}:Field`
  84. const HTTP_FIELD_NAMES = [
  85. 'requestMethod',
  86. 'requestUrl',
  87. 'requestHeaders',
  88. 'disallowRedirects',
  89. 'ignoreException',
  90. 'saveResponseParametersTransient',
  91. 'saveResponseVariableAsJson'
  92. ]
  93. const HTTP_BOOLEAN_FIELDS = new Set([
  94. 'disallowRedirects',
  95. 'ignoreException',
  96. 'saveResponseParametersTransient',
  97. 'saveResponseVariableAsJson'
  98. ])
  99. const DEFAULT_TASK_FORM = {
  100. executeType: '',
  101. class: '',
  102. expression: '',
  103. delegateExpression: ''
  104. }
  105. const DEFAULT_HTTP_FORM = {
  106. requestMethod: 'GET',
  107. requestUrl: '',
  108. requestHeaders: 'Content-Type: application/json',
  109. disallowRedirects: false,
  110. ignoreException: false,
  111. saveResponseParametersTransient: false,
  112. saveResponseVariableAsJson: false
  113. }
  114. const serviceTaskForm = ref({ ...DEFAULT_TASK_FORM })
  115. const httpTaskForm = ref({ ...DEFAULT_HTTP_FORM })
  116. const bpmnElement = ref()
  117. const httpInitializing = ref(false)
  118. const bpmnInstances = () => (window as any)?.bpmnInstances
  119. const collectHttpExtensionInfo = () => {
  120. const businessObject = bpmnElement.value?.businessObject
  121. const extensionElements = businessObject?.extensionElements
  122. const httpFields = new Map<string, string>()
  123. const otherExtensions: any[] = []
  124. extensionElements?.values?.forEach((item: any) => {
  125. if (item?.$type === flowableFieldType && HTTP_FIELD_NAMES.includes(item.name)) {
  126. const value = item.string ?? item.stringValue ?? item.expression ?? ''
  127. httpFields.set(item.name, value)
  128. } else {
  129. otherExtensions.push(item)
  130. }
  131. })
  132. return { httpFields, otherExtensions }
  133. }
  134. const resetHttpDefaults = () => {
  135. httpInitializing.value = true
  136. httpTaskForm.value = { ...DEFAULT_HTTP_FORM }
  137. nextTick(() => {
  138. httpInitializing.value = false
  139. })
  140. }
  141. const resetHttpForm = () => {
  142. httpInitializing.value = true
  143. const { httpFields } = collectHttpExtensionInfo()
  144. const nextForm: Record<string, any> = { ...DEFAULT_HTTP_FORM }
  145. HTTP_FIELD_NAMES.forEach((name) => {
  146. const stored = httpFields.get(name)
  147. if (stored !== undefined) {
  148. nextForm[name] = HTTP_BOOLEAN_FIELDS.has(name) ? stored === 'true' : stored
  149. }
  150. })
  151. httpTaskForm.value = nextForm
  152. nextTick(() => {
  153. httpInitializing.value = false
  154. updateHttpExtensions(true)
  155. })
  156. }
  157. const resetServiceTaskForm = () => {
  158. const businessObject = bpmnElement.value?.businessObject
  159. const nextForm: Record<string, any> = { ...DEFAULT_TASK_FORM }
  160. if (businessObject) {
  161. if (businessObject.class) {
  162. nextForm.class = businessObject.class
  163. nextForm.executeType = 'class'
  164. }
  165. if (businessObject.expression) {
  166. nextForm.expression = businessObject.expression
  167. nextForm.executeType = 'expression'
  168. }
  169. if (businessObject.delegateExpression) {
  170. nextForm.delegateExpression = businessObject.delegateExpression
  171. nextForm.executeType = 'delegateExpression'
  172. }
  173. if (businessObject.$attrs?.[flowableTypeKey] === 'http') {
  174. nextForm.executeType = 'http'
  175. }
  176. }
  177. serviceTaskForm.value = nextForm
  178. if (nextForm.executeType === 'http') {
  179. resetHttpForm()
  180. } else {
  181. resetHttpDefaults()
  182. }
  183. }
  184. const shouldPersistField = (name: string, value: any) => {
  185. if (HTTP_BOOLEAN_FIELDS.has(name)) return true
  186. if (name === 'requestMethod') return true
  187. if (name === 'requestUrl') return !!value
  188. return value !== undefined && value !== ''
  189. }
  190. const updateHttpExtensions = (force = false) => {
  191. if (!bpmnElement.value) return
  192. if (!force && (httpInitializing.value || serviceTaskForm.value.executeType !== 'http')) {
  193. return
  194. }
  195. const { httpFields: existingFields, otherExtensions } = collectHttpExtensionInfo()
  196. const desiredEntries: [string, string][] = []
  197. HTTP_FIELD_NAMES.forEach((name) => {
  198. const rawValue = httpTaskForm.value[name]
  199. if (!shouldPersistField(name, rawValue)) {
  200. return
  201. }
  202. const persisted = HTTP_BOOLEAN_FIELDS.has(name)
  203. ? String(!!rawValue)
  204. : rawValue === undefined
  205. ? ''
  206. : String(rawValue)
  207. desiredEntries.push([name, persisted])
  208. })
  209. if (
  210. !force &&
  211. desiredEntries.length === existingFields.size &&
  212. desiredEntries.every(([name, value]) => existingFields.get(name) === value)
  213. ) {
  214. return
  215. }
  216. const moddle = bpmnInstances().moddle
  217. const httpFieldElements = desiredEntries.map(([name, value]) =>
  218. moddle.create(flowableFieldType, {
  219. name,
  220. string: value
  221. })
  222. )
  223. updateElementExtensions(bpmnElement.value, [...otherExtensions, ...httpFieldElements])
  224. }
  225. const removeHttpExtensions = () => {
  226. if (!bpmnElement.value) return
  227. const { httpFields, otherExtensions } = collectHttpExtensionInfo()
  228. if (!httpFields.size) {
  229. return
  230. }
  231. if (!otherExtensions.length) {
  232. bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
  233. extensionElements: null
  234. })
  235. return
  236. }
  237. updateElementExtensions(bpmnElement.value, otherExtensions)
  238. }
  239. const updateElementTask = () => {
  240. if (!bpmnElement.value) return
  241. const taskAttr: Record<string, any> = {
  242. class: null,
  243. expression: null,
  244. delegateExpression: null,
  245. [flowableTypeKey]: null
  246. }
  247. const type = serviceTaskForm.value.executeType
  248. if (type === 'class' || type === 'expression' || type === 'delegateExpression') {
  249. taskAttr[type] = serviceTaskForm.value[type] || null
  250. } else if (type === 'http') {
  251. taskAttr[flowableTypeKey] = 'http'
  252. }
  253. bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), taskAttr)
  254. if (type === 'http') {
  255. updateHttpExtensions(true)
  256. } else {
  257. removeHttpExtensions()
  258. }
  259. }
  260. const handleExecuteTypeChange = (value: string) => {
  261. serviceTaskForm.value.executeType = value
  262. if (value === 'http') {
  263. resetHttpForm()
  264. }
  265. updateElementTask()
  266. }
  267. onBeforeUnmount(() => {
  268. bpmnElement.value = null
  269. })
  270. watch(
  271. () => props.id,
  272. () => {
  273. bpmnElement.value = bpmnInstances().bpmnElement
  274. nextTick(() => {
  275. resetServiceTaskForm()
  276. })
  277. },
  278. { immediate: true }
  279. )
  280. watch(
  281. () => httpTaskForm.value,
  282. () => {
  283. updateHttpExtensions()
  284. },
  285. { deep: true }
  286. )
  287. </script>