TriggerNodeConfig.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. <template>
  2. <el-drawer
  3. :append-to-body="true"
  4. v-model="settingVisible"
  5. :show-close="false"
  6. :size="630"
  7. :before-close="saveConfig"
  8. >
  9. <template #header>
  10. <div class="config-header">
  11. <input
  12. v-if="showInput"
  13. type="text"
  14. class="config-editable-input"
  15. @blur="blurEvent()"
  16. v-mountedFocus
  17. v-model="nodeName"
  18. :placeholder="nodeName"
  19. />
  20. <div v-else class="node-name">
  21. {{ nodeName }} <Icon class="ml-1" icon="ep:edit-pen" :size="16" @click="clickIcon()" />
  22. </div>
  23. <div class="divide-line"></div>
  24. </div>
  25. </template>
  26. <div>
  27. <el-form ref="formRef" :model="configForm" label-position="top" :rules="formRules">
  28. <el-form-item label="触发器类型" prop="type">
  29. <el-select v-model="configForm.type">
  30. <el-option
  31. v-for="(item, index) in TRIGGER_TYPES"
  32. :key="index"
  33. :value="item.value"
  34. :label="item.label"
  35. />
  36. </el-select>
  37. </el-form-item>
  38. <!-- HTTP 请求触发器 -->
  39. <div
  40. v-if="configForm.type === TriggerTypeEnum.HTTP_REQUEST && configForm.httpRequestSetting"
  41. >
  42. <el-form-item>
  43. <el-alert
  44. title="仅支持 POST 请求,以请求体方式接收参数"
  45. type="warning"
  46. show-icon
  47. :closable="false"
  48. />
  49. </el-form-item>
  50. <!-- 请求地址-->
  51. <el-form-item label="请求地址" prop="httpRequestSetting.url">
  52. <el-input v-model="configForm.httpRequestSetting.url" />
  53. </el-form-item>
  54. <!-- 请求头,请求体设置-->
  55. <HttpRequestParamSetting
  56. :header="configForm.httpRequestSetting.header"
  57. :body="configForm.httpRequestSetting.body"
  58. :bind="'httpRequestSetting'"
  59. />
  60. <!-- 返回值设置-->
  61. <el-form-item label="返回值">
  62. <el-alert
  63. title="通过请求返回值, 可以修改流程表单的值"
  64. type="warning"
  65. show-icon
  66. :closable="false"
  67. />
  68. </el-form-item>
  69. <el-form-item>
  70. <div
  71. class="flex pt-2"
  72. v-for="(item, index) in configForm.httpRequestSetting.response"
  73. :key="index"
  74. >
  75. <div class="mr-2">
  76. <el-form-item
  77. :prop="`httpRequestSetting.response.${index}.key`"
  78. :rules="{
  79. required: true,
  80. message: '表单字段不能为空',
  81. trigger: 'blur'
  82. }"
  83. >
  84. <el-select class="w-160px!" v-model="item.key" placeholder="请选择表单字段">
  85. <el-option
  86. v-for="(field, fIdx) in formFields"
  87. :key="fIdx"
  88. :label="field.title"
  89. :value="field.field"
  90. :disabled="!field.required"
  91. />
  92. </el-select>
  93. </el-form-item>
  94. </div>
  95. <div class="mr-2">
  96. <el-form-item
  97. :prop="`httpRequestSetting.response.${index}.value`"
  98. :rules="{
  99. required: true,
  100. message: '请求返回字段不能为空',
  101. trigger: 'blur'
  102. }"
  103. >
  104. <el-input class="w-160px" v-model="item.value" placeholder="请求返回字段" />
  105. </el-form-item>
  106. </div>
  107. <div class="mr-1 pt-1 cursor-pointer">
  108. <Icon
  109. icon="ep:delete"
  110. :size="18"
  111. @click="deleteHttpResponseSetting(configForm.httpRequestSetting.response!, index)"
  112. />
  113. </div>
  114. </div>
  115. <el-button
  116. type="primary"
  117. text
  118. @click="addHttpResponseSetting(configForm.httpRequestSetting.response!)"
  119. >
  120. <Icon icon="ep:plus" class="mr-5px" />添加一行
  121. </el-button>
  122. </el-form-item>
  123. </div>
  124. <!-- 表单数据修改触发器 -->
  125. <div v-if="configForm.type === TriggerTypeEnum.FORM_UPDATE">
  126. <div v-for="(formSetting, index) in configForm.formSettings" :key="index">
  127. <el-card class="w-580px mt-4">
  128. <template #header>
  129. <div class="flex items-center justify-between">
  130. <div>修改表单设置 {{ index + 1 }}</div>
  131. <el-button
  132. type="primary"
  133. plain
  134. circle
  135. v-if="configForm.formSettings!.length > 1"
  136. @click="deleteFormSetting(index)"
  137. >
  138. <Icon icon="ep:close" />
  139. </el-button>
  140. </div>
  141. </template>
  142. <!-- 条件设置 -->
  143. <ConditionDialog
  144. :ref="`condition-${index}`"
  145. @update-condition="(val) => handleConditionUpdate(index, val)"
  146. />
  147. <div class="cursor-pointer" v-if="formSetting.conditionType">
  148. <el-tag
  149. type="success"
  150. effect="light"
  151. closable
  152. @close="deleteFormUpdateCondition(formSetting)"
  153. @click="openFormUpdateCondition(index, formSetting)"
  154. >
  155. {{ showConditionText(formSetting) }}
  156. </el-tag>
  157. </div>
  158. <el-button
  159. v-else
  160. type="primary"
  161. text
  162. @click="addFormUpdateCondition(index, formSetting)"
  163. >
  164. <Icon icon="ep:link" class="mr-5px" />添加条件
  165. </el-button>
  166. <el-divider content-position="left">修改表单字段设置</el-divider>
  167. <!-- 表单字段修改设置 -->
  168. <div
  169. class="flex items-center"
  170. v-for="key in Object.keys(formSetting.updateFormFields || {})"
  171. :key="key"
  172. >
  173. <div class="mr-2 flex items-center">
  174. <el-form-item>
  175. <el-select
  176. class="w-160px!"
  177. :model-value="key"
  178. @update:model-value="(newKey) => updateFormFieldKey(formSetting, key, newKey)"
  179. placeholder="请选择表单字段"
  180. :disabled="key !== ''"
  181. >
  182. <el-option
  183. v-for="(field, fIdx) in optionalUpdateFormFields"
  184. :key="fIdx"
  185. :label="field.title"
  186. :value="field.field"
  187. :disabled="field.disabled"
  188. />
  189. </el-select>
  190. </el-form-item>
  191. </div>
  192. <div class="mx-2"><el-form-item>的值设置为</el-form-item></div>
  193. <div class="mr-2">
  194. <el-form-item
  195. :prop="`formSettings.${index}.updateFormFields.${key}`"
  196. :rules="{
  197. required: true,
  198. message: '值不能为空',
  199. trigger: 'blur'
  200. }"
  201. >
  202. <el-input
  203. class="w-160px"
  204. v-model="formSetting.updateFormFields![key]"
  205. placeholder="请输入"
  206. :disabled="!key"
  207. />
  208. </el-form-item>
  209. </div>
  210. <div class="mr-1 pt-1 cursor-pointer">
  211. <el-form-item>
  212. <Icon
  213. icon="ep:delete"
  214. :size="18"
  215. @click="deleteFormFieldSetting(formSetting, key)"
  216. />
  217. </el-form-item>
  218. </div>
  219. </div>
  220. <!-- 添加表单字段按钮 -->
  221. <el-button type="primary" text @click="addFormFieldSetting(formSetting)">
  222. <Icon icon="ep:memo" class="mr-5px" />添加修改字段
  223. </el-button>
  224. </el-card>
  225. </div>
  226. <!-- 添加新的设置 -->
  227. <el-button class="mt-6" type="primary" text @click="addFormSetting">
  228. <Icon icon="ep:setting" class="mr-5px" />添加设置
  229. </el-button>
  230. </div>
  231. </el-form>
  232. </div>
  233. <template #footer>
  234. <el-divider />
  235. <div>
  236. <el-button type="primary" @click="saveConfig">确 定</el-button>
  237. <el-button @click="closeDrawer">取 消</el-button>
  238. </div>
  239. </template>
  240. </el-drawer>
  241. </template>
  242. <script setup lang="ts">
  243. import {
  244. SimpleFlowNode,
  245. NodeType,
  246. TriggerSetting,
  247. TRIGGER_TYPES,
  248. TriggerTypeEnum,
  249. FormTriggerSetting,
  250. DEFAULT_CONDITION_GROUP_VALUE
  251. } from '../consts'
  252. import { useWatchNode, useDrawer, useNodeName, useFormFields, getConditionShowText } from '../node'
  253. import HttpRequestParamSetting from './components/HttpRequestParamSetting.vue'
  254. import ConditionDialog from './components/ConditionDialog.vue'
  255. const { proxy } = getCurrentInstance() as any
  256. defineOptions({
  257. name: 'TriggerNodeConfig'
  258. })
  259. const props = defineProps({
  260. flowNode: {
  261. type: Object as () => SimpleFlowNode,
  262. required: true
  263. }
  264. })
  265. const message = useMessage() // 消息弹窗
  266. // 抽屉配置
  267. const { settingVisible, closeDrawer, openDrawer } = useDrawer()
  268. // 当前节点
  269. const currentNode = useWatchNode(props)
  270. // 节点名称
  271. const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(NodeType.TRIGGER_NODE)
  272. // 触发器表单配置
  273. const formRef = ref() // 表单 Ref
  274. // 表单校验规则
  275. const formRules = reactive({
  276. type: [{ required: true, message: '触发器类型不能为空', trigger: 'change' }],
  277. 'httpRequestSetting.url': [{ required: true, message: '请求地址不能为空', trigger: 'blur' }]
  278. })
  279. // 触发器配置表单数据
  280. const configForm = ref<TriggerSetting>({
  281. type: TriggerTypeEnum.HTTP_REQUEST,
  282. httpRequestSetting: {
  283. url: '',
  284. header: [],
  285. body: [],
  286. response: []
  287. },
  288. formSettings: [
  289. {
  290. conditionGroups: DEFAULT_CONDITION_GROUP_VALUE,
  291. updateFormFields: {}
  292. }
  293. ]
  294. })
  295. // 流程表单字段
  296. const formFields = useFormFields()
  297. // 可选的修改的表单字段
  298. const optionalUpdateFormFields = computed(() => {
  299. return formFields.map((field) => ({
  300. title: field.title,
  301. field: field.field,
  302. disabled: false
  303. }))
  304. })
  305. /** 添加 HTTP 请求返回值设置项 */
  306. const addHttpResponseSetting = (responseSetting: Record<string, string>[]) => {
  307. responseSetting.push({
  308. key: '',
  309. value: ''
  310. })
  311. }
  312. /** 删除 HTTP 请求返回值设置项 */
  313. const deleteHttpResponseSetting = (responseSetting: Record<string, string>[], index: number) => {
  314. responseSetting.splice(index, 1)
  315. }
  316. /** 添加新的修改表单设置 */
  317. const addFormSetting = () => {
  318. configForm.value.formSettings!.push({
  319. conditionGroups: DEFAULT_CONDITION_GROUP_VALUE,
  320. updateFormFields: {}
  321. })
  322. }
  323. /** 删除修改表单设置 */
  324. const deleteFormSetting = (index: number) => {
  325. configForm.value.formSettings!.splice(index, 1)
  326. }
  327. /** 添加条件配置 */
  328. const addFormUpdateCondition = (index: number, formSetting: FormTriggerSetting) => {
  329. const conditionDialog = proxy.$refs[`condition-${index}`][0]
  330. conditionDialog.open(formSetting)
  331. }
  332. /** 删除条件配置 */
  333. const deleteFormUpdateCondition = (formSetting: FormTriggerSetting) => {
  334. formSetting.conditionType = undefined
  335. }
  336. /** 打开条件配置弹窗 */
  337. const openFormUpdateCondition = (index: number, formSetting: FormTriggerSetting) => {
  338. const conditionDialog = proxy.$refs[`condition-${index}`][0]
  339. conditionDialog.open(formSetting)
  340. }
  341. /** 处理条件配置保存 */
  342. const handleConditionUpdate = (index: number, condition: any) => {
  343. configForm.value.formSettings![index].conditionType = condition.conditionType
  344. configForm.value.formSettings![index].conditionExpression = condition.conditionExpression
  345. configForm.value.formSettings![index].conditionGroups = condition.conditionGroups
  346. }
  347. /** 条件配置展示 */
  348. const showConditionText = (formSetting: FormTriggerSetting) => {
  349. return getConditionShowText(
  350. formSetting.conditionType,
  351. formSetting.conditionExpression,
  352. formSetting.conditionGroups,
  353. formFields
  354. )
  355. }
  356. /** 添加修改字段设置项 */
  357. const addFormFieldSetting = (formSetting: FormTriggerSetting) => {
  358. if (!formSetting) return
  359. if (!formSetting.updateFormFields) {
  360. formSetting.updateFormFields = {}
  361. }
  362. formSetting.updateFormFields[''] = undefined
  363. }
  364. /** 更新字段 KEY */
  365. const updateFormFieldKey = (formSetting: FormTriggerSetting, oldKey: string, newKey: string) => {
  366. if (!formSetting?.updateFormFields) return
  367. const value = formSetting.updateFormFields[oldKey]
  368. delete formSetting.updateFormFields[oldKey]
  369. formSetting.updateFormFields[newKey] = value
  370. }
  371. /** 删除修改字段设置项 */
  372. const deleteFormFieldSetting = (formSetting: FormTriggerSetting, key: string) => {
  373. if (!formSetting?.updateFormFields) return
  374. delete formSetting.updateFormFields[key]
  375. }
  376. /** 保存配置 */
  377. const saveConfig = async () => {
  378. if (!formRef) return false
  379. const valid = await formRef.value.validate()
  380. if (!valid) return false
  381. const showText = getShowText()
  382. if (!showText) return false
  383. currentNode.value.name = nodeName.value!
  384. currentNode.value.showText = showText
  385. if (configForm.value.type === TriggerTypeEnum.HTTP_REQUEST) {
  386. configForm.value.formSettings = undefined
  387. }
  388. if (configForm.value.type === TriggerTypeEnum.FORM_UPDATE) {
  389. configForm.value.httpRequestSetting = undefined
  390. }
  391. currentNode.value.triggerSetting = configForm.value
  392. settingVisible.value = false
  393. return true
  394. }
  395. /** 获取节点展示内容 */
  396. const getShowText = (): string => {
  397. let showText = ''
  398. if (configForm.value.type === TriggerTypeEnum.HTTP_REQUEST) {
  399. showText = `${configForm.value.httpRequestSetting?.url}`
  400. } else if (configForm.value.type === TriggerTypeEnum.FORM_UPDATE) {
  401. for (const [index, setting] of configForm.value.formSettings!.entries()) {
  402. if (!setting.updateFormFields || Object.keys(setting.updateFormFields).length === 0) {
  403. message.warning(`请添加表单设置${index + 1}的修改字段`)
  404. return ''
  405. }
  406. }
  407. showText = '修改表单数据'
  408. }
  409. return showText
  410. }
  411. /** 显示触发器节点配置, 由父组件传过来 */
  412. const showTriggerNodeConfig = (node: SimpleFlowNode) => {
  413. nodeName.value = node.name
  414. if (node.triggerSetting) {
  415. configForm.value = {
  416. type: node.triggerSetting.type,
  417. httpRequestSetting: node.triggerSetting.httpRequestSetting || {
  418. url: '',
  419. header: [],
  420. body: [],
  421. response: []
  422. },
  423. formSettings: node.triggerSetting.formSettings || [
  424. {
  425. conditionGroups: DEFAULT_CONDITION_GROUP_VALUE,
  426. updateFormFields: {}
  427. }
  428. ]
  429. }
  430. }
  431. }
  432. defineExpose({ openDrawer, showTriggerNodeConfig }) // 暴露方法给父组件
  433. </script>
  434. <style lang="scss" scoped></style>