ExtraSettings.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. <template>
  2. <el-form ref="formRef" :model="modelData" label-width="120px" class="mt-20px">
  3. <el-form-item class="mb-20px">
  4. <template #label>
  5. <el-text size="large" tag="b">提交人权限</el-text>
  6. </template>
  7. <div class="flex flex-col">
  8. <el-checkbox v-model="modelData.allowCancelRunningProcess" label="允许撤销审批中的申请" />
  9. <div class="ml-22px">
  10. <el-text type="info"> 第一个审批节点通过后,提交人仍可撤销申请 </el-text>
  11. </div>
  12. </div>
  13. </el-form-item>
  14. <el-form-item v-if="modelData.processIdRule" class="mb-20px">
  15. <template #label>
  16. <el-text size="large" tag="b">流程编码</el-text>
  17. </template>
  18. <div class="flex flex-col">
  19. <div>
  20. <el-input
  21. v-model="modelData.processIdRule.prefix"
  22. class="w-130px!"
  23. placeholder="前缀"
  24. :disabled="!modelData.processIdRule.enable"
  25. >
  26. <template #prepend>
  27. <el-checkbox v-model="modelData.processIdRule.enable" />
  28. </template>
  29. </el-input>
  30. <el-select
  31. v-model="modelData.processIdRule.infix"
  32. class="w-130px! ml-5px"
  33. placeholder="中缀"
  34. :disabled="!modelData.processIdRule.enable"
  35. >
  36. <el-option
  37. v-for="item in timeOptions"
  38. :key="item.value"
  39. :label="item.label"
  40. :value="item.value"
  41. />
  42. </el-select>
  43. <el-input
  44. v-model="modelData.processIdRule.postfix"
  45. class="w-80px! ml-5px"
  46. placeholder="后缀"
  47. :disabled="!modelData.processIdRule.enable"
  48. />
  49. <el-input-number
  50. v-model="modelData.processIdRule.length"
  51. class="w-120px! ml-5px"
  52. :min="5"
  53. :disabled="!modelData.processIdRule.enable"
  54. />
  55. </div>
  56. <div class="ml-22px" v-if="modelData.processIdRule.enable">
  57. <el-text type="info"> 编码示例:{{ numberExample }} </el-text>
  58. </div>
  59. </div>
  60. </el-form-item>
  61. <el-form-item class="mb-20px">
  62. <template #label>
  63. <el-text size="large" tag="b">自动去重</el-text>
  64. </template>
  65. <div class="flex flex-col">
  66. <div>
  67. <el-text> 同一审批人在流程中重复出现时: </el-text>
  68. </div>
  69. <el-radio-group v-model="modelData.autoApprovalType">
  70. <div class="flex flex-col">
  71. <el-radio :value="0">不自动通过</el-radio>
  72. <el-radio :value="1">仅审批一次,后续重复的审批节点均自动通过</el-radio>
  73. <el-radio :value="2">仅针对连续审批的节点自动通过</el-radio>
  74. </div>
  75. </el-radio-group>
  76. </div>
  77. </el-form-item>
  78. <el-form-item v-if="modelData.titleSetting" class="mb-20px">
  79. <template #label>
  80. <el-text size="large" tag="b">标题设置</el-text>
  81. </template>
  82. <div class="flex flex-col">
  83. <el-radio-group v-model="modelData.titleSetting.enable">
  84. <div class="flex flex-col">
  85. <el-radio :value="false"
  86. >系统默认 <el-text type="info"> 展示流程名称 </el-text></el-radio
  87. >
  88. <el-radio :value="true">
  89. 自定义标题
  90. <el-text>
  91. <el-tooltip content="输入字符 '{' 即可插入表单字段" effect="light" placement="top">
  92. <Icon icon="ep:question-filled" class="ml-5px" />
  93. </el-tooltip>
  94. </el-text>
  95. </el-radio>
  96. </div>
  97. </el-radio-group>
  98. <el-mention
  99. v-if="modelData.titleSetting.enable"
  100. v-model="modelData.titleSetting.title"
  101. type="textarea"
  102. prefix="{"
  103. split="}"
  104. whole
  105. :options="formFieldOptions4Title"
  106. placeholder="请插入表单字段(输入 '{' 可以选择表单字段)或输入文本"
  107. class="w-600px!"
  108. />
  109. </div>
  110. </el-form-item>
  111. <el-form-item
  112. v-if="modelData.summarySetting && modelData.formType === BpmModelFormType.NORMAL"
  113. class="mb-20px"
  114. >
  115. <template #label>
  116. <el-text size="large" tag="b">摘要设置</el-text>
  117. </template>
  118. <div class="flex flex-col">
  119. <el-radio-group v-model="modelData.summarySetting.enable">
  120. <div class="flex flex-col">
  121. <el-radio :value="false">
  122. 系统默认 <el-text type="info"> 展示表单前 3 个字段 </el-text>
  123. </el-radio>
  124. <el-radio :value="true"> 自定义摘要 </el-radio>
  125. </div>
  126. </el-radio-group>
  127. <el-select
  128. class="w-500px!"
  129. v-if="modelData.summarySetting.enable"
  130. v-model="modelData.summarySetting.summary"
  131. multiple
  132. placeholder="请选择要展示的表单字段"
  133. >
  134. <el-option
  135. v-for="item in formFieldOptions4Summary"
  136. :key="item.value"
  137. :label="item.label"
  138. :value="item.value"
  139. />
  140. </el-select>
  141. </div>
  142. </el-form-item>
  143. <el-form-item class="mb-20px">
  144. <template #label>
  145. <el-text size="large" tag="b">流程前置通知</el-text>
  146. </template>
  147. <div class="flex flex-col w-100%">
  148. <div class="flex">
  149. <el-switch
  150. v-model="processBeforeTriggerEnable"
  151. @change="handleProcessBeforeTriggerEnableChange"
  152. />
  153. <div class="ml-80px">流程启动后通知</div>
  154. </div>
  155. <HttpRequestSetting
  156. v-if="processBeforeTriggerEnable"
  157. v-model:setting="modelData.processBeforeTriggerSetting"
  158. :responseEnable="true"
  159. :formItemPrefix="'processBeforeTriggerSetting'"
  160. />
  161. </div>
  162. </el-form-item>
  163. <el-form-item class="mb-20px">
  164. <template #label>
  165. <el-text size="large" tag="b">流程后置通知</el-text>
  166. </template>
  167. <div class="flex flex-col w-100%">
  168. <div class="flex">
  169. <el-switch
  170. v-model="processAfterTriggerEnable"
  171. @change="handleProcessAfterTriggerEnableChange"
  172. />
  173. <div class="ml-80px">流程结束后通知</div>
  174. </div>
  175. <HttpRequestSetting
  176. v-if="processAfterTriggerEnable"
  177. v-model:setting="modelData.processAfterTriggerSetting"
  178. :responseEnable="true"
  179. :formItemPrefix="'processAfterTriggerSetting'"
  180. />
  181. </div>
  182. </el-form-item>
  183. <el-form-item class="mb-20px">
  184. <template #label>
  185. <el-text size="large" tag="b">任务前置通知</el-text>
  186. </template>
  187. <div class="flex flex-col w-100%">
  188. <div class="flex">
  189. <el-switch
  190. v-model="taskBeforeTriggerEnable"
  191. @change="handleTaskBeforeTriggerEnableChange"
  192. />
  193. <div class="ml-80px">任务执行时通知</div>
  194. </div>
  195. <HttpRequestSetting
  196. v-if="taskBeforeTriggerEnable"
  197. v-model:setting="modelData.taskBeforeTriggerSetting"
  198. :responseEnable="true"
  199. :formItemPrefix="'taskBeforeTriggerSetting'"
  200. />
  201. </div>
  202. </el-form-item>
  203. <el-form-item class="mb-20px">
  204. <template #label>
  205. <el-text size="large" tag="b">任务后置通知</el-text>
  206. </template>
  207. <div class="flex flex-col w-100%">
  208. <div class="flex">
  209. <el-switch
  210. v-model="taskAfterTriggerEnable"
  211. @change="handleTaskAfterTriggerEnableChange"
  212. />
  213. <div class="ml-80px">任务结束后通知</div>
  214. </div>
  215. <HttpRequestSetting
  216. v-if="taskAfterTriggerEnable"
  217. v-model:setting="modelData.taskAfterTriggerSetting"
  218. :responseEnable="true"
  219. :formItemPrefix="'taskAfterTriggerSetting'"
  220. />
  221. </div>
  222. </el-form-item>
  223. </el-form>
  224. </template>
  225. <script setup lang="ts">
  226. import dayjs from 'dayjs'
  227. import { BpmAutoApproveType, BpmModelFormType } from '@/utils/constants'
  228. import * as FormApi from '@/api/bpm/form'
  229. import { parseFormFields } from '@/components/FormCreate/src/utils'
  230. import { ProcessVariableEnum } from '@/components/SimpleProcessDesignerV2/src/consts'
  231. import HttpRequestSetting from '@/components/SimpleProcessDesignerV2/src/nodes-config/components/HttpRequestSetting.vue'
  232. const modelData = defineModel<any>()
  233. const formFields = ref<string[]>([])
  234. const props = defineProps({
  235. // 流程表单 ID
  236. modelFormId: {
  237. type: Number,
  238. required: false,
  239. default: undefined,
  240. }
  241. })
  242. // 监听 modelFormId 变化
  243. watch(
  244. () => props.modelFormId,
  245. async (newVal) => {
  246. if (newVal) {
  247. const form = await FormApi.getForm(newVal);
  248. formFields.value = form?.fields;
  249. } else {
  250. // 如果 modelFormId 为空,清空表单字段
  251. formFields.value = [];
  252. }
  253. },
  254. { immediate: true },
  255. );
  256. // 暴露给子组件使用
  257. provide('formFields', formFields)
  258. /** 自定义 ID 流程编码 */
  259. const timeOptions = ref([
  260. {
  261. value: '',
  262. label: '无'
  263. },
  264. {
  265. value: 'DAY',
  266. label: '精确到日'
  267. },
  268. {
  269. value: 'HOUR',
  270. label: '精确到时'
  271. },
  272. {
  273. value: 'MINUTE',
  274. label: '精确到分'
  275. },
  276. {
  277. value: 'SECOND',
  278. label: '精确到秒'
  279. }
  280. ])
  281. const numberExample = computed(() => {
  282. if (modelData.value.processIdRule.enable) {
  283. let infix = ''
  284. switch (modelData.value.processIdRule.infix) {
  285. case 'DAY':
  286. infix = dayjs().format('YYYYMMDD')
  287. break
  288. case 'HOUR':
  289. infix = dayjs().format('YYYYMMDDHH')
  290. break
  291. case 'MINUTE':
  292. infix = dayjs().format('YYYYMMDDHHmm')
  293. break
  294. case 'SECOND':
  295. infix = dayjs().format('YYYYMMDDHHmmss')
  296. break
  297. default:
  298. break
  299. }
  300. return (
  301. modelData.value.processIdRule.prefix +
  302. infix +
  303. modelData.value.processIdRule.postfix +
  304. '1'.padStart(modelData.value.processIdRule.length - 1, '0')
  305. )
  306. } else {
  307. return ''
  308. }
  309. })
  310. /** 是否开启流程前置通知 */
  311. const processBeforeTriggerEnable = ref(false)
  312. const handleProcessBeforeTriggerEnableChange = (val: boolean | string | number) => {
  313. if (val) {
  314. modelData.value.processBeforeTriggerSetting = {
  315. url: '',
  316. header: [],
  317. body: [],
  318. response: []
  319. }
  320. } else {
  321. modelData.value.processBeforeTriggerSetting = null
  322. }
  323. }
  324. /** 是否开启流程后置通知 */
  325. const processAfterTriggerEnable = ref(false)
  326. const handleProcessAfterTriggerEnableChange = (val: boolean | string | number) => {
  327. if (val) {
  328. modelData.value.processAfterTriggerSetting = {
  329. url: '',
  330. header: [],
  331. body: [],
  332. response: []
  333. }
  334. } else {
  335. modelData.value.processAfterTriggerSetting = null
  336. }
  337. }
  338. /** 是否开启任务前置通知 */
  339. const taskBeforeTriggerEnable = ref(false)
  340. const handleTaskBeforeTriggerEnableChange = (val: boolean | string | number) => {
  341. if (val) {
  342. modelData.value.taskBeforeTriggerSetting = {
  343. url: '',
  344. header: [],
  345. body: [],
  346. response: []
  347. }
  348. } else {
  349. modelData.value.taskBeforeTriggerSetting = null
  350. }
  351. }
  352. /** 是否开启任务后置通知 */
  353. const taskAfterTriggerEnable = ref(false)
  354. const handleTaskAfterTriggerEnableChange = (val: boolean | string | number) => {
  355. if (val) {
  356. modelData.value.taskAfterTriggerSetting = {
  357. url: '',
  358. header: [],
  359. body: [],
  360. response: []
  361. }
  362. } else {
  363. modelData.value.taskAfterTriggerSetting = null
  364. }
  365. }
  366. /** 表单选项 */
  367. const formField = ref<Array<{ field: string; title: string }>>([])
  368. const formFieldOptions4Title = computed(() => {
  369. let cloneFormField = formField.value.map((item) => {
  370. return {
  371. label: item.title,
  372. value: item.field
  373. }
  374. })
  375. // 固定添加发起人 ID 字段
  376. cloneFormField.unshift({
  377. label: '流程名称',
  378. value: ProcessVariableEnum.PROCESS_DEFINITION_NAME
  379. })
  380. cloneFormField.unshift({
  381. label: '发起时间',
  382. value: ProcessVariableEnum.START_TIME
  383. })
  384. cloneFormField.unshift({
  385. label: '发起人',
  386. value: ProcessVariableEnum.START_USER_ID
  387. })
  388. return cloneFormField
  389. })
  390. const formFieldOptions4Summary = computed(() => {
  391. return formField.value.map((item) => {
  392. return {
  393. label: item.title,
  394. value: item.field
  395. }
  396. })
  397. })
  398. /** 兼容以前未配置更多设置的流程 */
  399. const initData = () => {
  400. if (!modelData.value.processIdRule) {
  401. modelData.value.processIdRule = {
  402. enable: false,
  403. prefix: '',
  404. infix: '',
  405. postfix: '',
  406. length: 5
  407. }
  408. }
  409. if (!modelData.value.autoApprovalType) {
  410. modelData.value.autoApprovalType = BpmAutoApproveType.NONE
  411. }
  412. if (!modelData.value.titleSetting) {
  413. modelData.value.titleSetting = {
  414. enable: false,
  415. title: ''
  416. }
  417. }
  418. if (!modelData.value.summarySetting) {
  419. modelData.value.summarySetting = {
  420. enable: false,
  421. summary: []
  422. }
  423. }
  424. if (modelData.value.processBeforeTriggerSetting) {
  425. processBeforeTriggerEnable.value = true
  426. }
  427. if (modelData.value.processAfterTriggerSetting) {
  428. processAfterTriggerEnable.value = true
  429. }
  430. if (modelData.value.taskBeforeTriggerSetting) {
  431. taskBeforeTriggerEnable.value = true
  432. }
  433. if (modelData.value.taskAfterTriggerSetting) {
  434. taskAfterTriggerEnable.value = true
  435. }
  436. }
  437. defineExpose({ initData })
  438. /** 监听表单 ID 变化,加载表单数据 */
  439. watch(
  440. () => modelData.value.formId,
  441. async (newFormId) => {
  442. if (newFormId && modelData.value.formType === BpmModelFormType.NORMAL) {
  443. const data = await FormApi.getForm(newFormId)
  444. const result: Array<{ field: string; title: string }> = []
  445. if (data.fields) {
  446. data.fields.forEach((fieldStr: string) => {
  447. parseFormFields(JSON.parse(fieldStr), result)
  448. })
  449. }
  450. formField.value = result
  451. } else {
  452. formField.value = []
  453. }
  454. },
  455. { immediate: true }
  456. )
  457. </script>