기술나눔

jeecgboot-vue3 기반의 Flowable 프로세스 - 통합 모방 DingTalk 프로세스 (5) json 데이터 저장 및 모방 DingTalk 프로세스 표시

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

이 프로젝트의 라이센스 문제로 인해 오픈 소스화할 수 없습니다. 더 많은 기술 지원 및 서비스를 받으려면 내 Knowledge Planet에 가입하세요.

1. 딩톡을 흉내내는 과정을 저장하고 표시하기 위한 인터페이스를 만들어야 합니다. 먼저 테이블을 생성하고 이를 온라인으로 사용하여 테이블을 생성합니다.

2. 위의 코드를 생성하여 해당 프런트엔드 및 백엔드 프로젝트에 넣습니다.

3. 프런트 엔드 모방 DingTalk 프로세스의 디자인 기능을 수정하고 다음과 같이 원본 목록 페이지에 대화 상자를 추가합니다.

  1. <el-dialog :title="designerData.name" class="ddDialog" v-model="designerOpen" append-to-body fullscreen>
  2. <ding-designer
  3. ref="ddDesigner"
  4. v-loading="designerLoading"
  5. :process = "flowJsonData"
  6. @save="onSaveDesigner"
  7. />
  8. </el-dialog>

4. 위의 모조 못 박기 프로세스 구성 요소를 추가합니다.

  1. <template>
  2. <div class="formDesign">
  3. <FlowDesign :process="process" :fields="fields" :readOnly="readOnly">
  4. <el-switch
  5. inline-prompt
  6. size="large"
  7. active-text="正常模式"
  8. inactive-text="暗黑模式"
  9. @change="handleToggleDark"
  10. v-model="isDark"
  11. />
  12. <el-switch
  13. v-model="readOnly"
  14. size="large"
  15. active-text="只读模式"
  16. inactive-text="编辑模式"
  17. inline-prompt
  18. :active-value="true"
  19. :inactive-value="false"
  20. />
  21. <el-button-group>
  22. <el-button @click="viewJson" size="small" type="primary" round icon="View"> 查看Json</el-button>
  23. </el-button-group>
  24. <el-button-group>
  25. <el-button @click="viewXmlBpmn" size="small" type="primary" round icon="View"> 查看XML </el-button>
  26. </el-button-group>
  27. <el-button-group>
  28. <el-button @click="converterBpmn" size="small" type="primary" round icon="View"> 预览bpmn </el-button>
  29. </el-button-group>
  30. <el-button-group>
  31. <el-button @click="save" size="small" type="primary" round icon="View"> 保存 </el-button>
  32. </el-button-group>
  33. </FlowDesign>
  34. <el-dialog title="预览" width="60%" v-model="previewModelVisible" append-to-body destroy-on-close>
  35. <highlightjs :language="previewType" :code="previewResult" style="height: 80vh" />
  36. </el-dialog>
  37. <!-- Bpmn流程图 -->
  38. <el-dialog :title="processView.title" v-model="processView.open" width="70%" append-to-body>
  39. <process-viewer :key="`designer-${processView.title}`" :xml="processView.xmlData" :style="{height: '500px'}" />
  40. </el-dialog>
  41. </div>
  42. </template>
  43. <script setup lang="ts" name="DingDesigner">
  44. import { ref, reactive, toRaw, onMounted } from 'vue';
  45. import '@/views/lowflow/styles/index.scss'
  46. // If you want to use ElMessage, import it.
  47. import 'element-plus/dist/index.css';
  48. import 'element-plus/theme-chalk/display.css';
  49. import FlowDesign from '@/views/lowflow/flowDesign/index.vue'
  50. import type { Field } from '@/views/lowflow/components/Render/type'
  51. import type { EndNode, FlowNode, StartNode } from '@/views/lowflow/flowDesign/nodes/type'
  52. import { viewXml, ddToBpmnXml } from '@/views/lowflow/api/modules/model'
  53. import ProcessViewer from '@/components/ProcessViewer/index.vue';
  54. import { useMessage } from '/@/hooks/web/useMessage';
  55. const { createMessage, createConfirm } = useMessage();
  56. const props = defineProps({
  57. process: {
  58. type: Object,
  59. required: true
  60. },
  61. });
  62. const emit = defineEmits([
  63. 'save'
  64. ])
  65. const previewModelVisible = ref(false)
  66. const previewResult = ref('')
  67. const previewType = ref('xml')
  68. const processView = reactive<any>({
  69. title: '',
  70. open: false,
  71. xmlData:'',
  72. })
  73. // 流程节点
  74. /*const process = ref<FlowNode>({
  75. id: 'root',
  76. pid: undefined,
  77. type: 'start',
  78. name: '流程开始',
  79. executionListeners: [],
  80. formProperties: [],
  81. child: {
  82. id: 'end',
  83. pid: 'root',
  84. type: 'end',
  85. name: '流程结束',
  86. executionListeners: [],
  87. child: undefined
  88. } as EndNode
  89. } as StartNode)*/
  90. // 表单字段
  91. const fields = ref<Field[]>([
  92. {
  93. id: 'field_da2w55',
  94. type: 'formItem',
  95. label: '请假人',
  96. name: 'UserSelector',
  97. value: null,
  98. readonly: false,
  99. required: true,
  100. hidden: false,
  101. props: {
  102. multiple: false,
  103. disabled: false,
  104. placeholder: '请选择用户',
  105. style: {
  106. width: '100%'
  107. }
  108. }
  109. },
  110. {
  111. id: 'field_fa2w40',
  112. type: 'formItem',
  113. label: '请假天数',
  114. name: 'ElInputNumber',
  115. value: null,
  116. readonly: false,
  117. required: true,
  118. hidden: false,
  119. props: {
  120. disabled: false,
  121. placeholder: '请假天数',
  122. style: {
  123. width: '100%'
  124. },
  125. min: 0,
  126. max: 100,
  127. step: 1,
  128. precision: 0
  129. }
  130. },
  131. {
  132. id: 'field_d42t45',
  133. type: 'formItem',
  134. label: '请假事由',
  135. name: 'ElSelect',
  136. value: null,
  137. readonly: false,
  138. required: true,
  139. hidden: false,
  140. props: {
  141. disabled: false,
  142. multiple: false,
  143. placeholder: '请选择请假事由',
  144. options: [
  145. {
  146. label: '事假',
  147. value: '事假'
  148. },
  149. {
  150. label: '病假',
  151. value: '病假'
  152. },
  153. {
  154. label: '婚假',
  155. value: '婚假'
  156. },
  157. {
  158. label: '产假',
  159. value: '产假'
  160. },
  161. {
  162. label: '丧假',
  163. value: '丧假'
  164. },
  165. {
  166. label: '其他',
  167. value: '其他'
  168. }
  169. ],
  170. style: {
  171. width: '100%'
  172. }
  173. }
  174. },
  175. {
  176. id: 'field_522g58',
  177. type: 'formItem',
  178. label: '请假原因',
  179. name: 'ElInput',
  180. value: null,
  181. readonly: false,
  182. required: true,
  183. hidden: false,
  184. props: {
  185. type: 'textarea',
  186. placeholder: '请输入请假原因',
  187. autosize: {
  188. minRows: 3,
  189. maxRows: 3
  190. },
  191. disabled: false,
  192. style: {
  193. width: '100%'
  194. }
  195. }
  196. }
  197. ])
  198. // 是否只读
  199. const readOnly = ref(false)
  200. // 是否暗黑模式
  201. const isDark = ref(false)
  202. const viewJson = () => {
  203. const processJson = JSON.stringify(props.process,undefined, 2);
  204. previewResult.value = processJson;
  205. previewType.value = 'json'
  206. previewModelVisible.value = true
  207. }
  208. const viewXmlBpmn = () => {
  209. const processModel = {
  210. code: 'test',
  211. name: '测试',
  212. icon: {
  213. name: 'el:HomeFilled',
  214. color: '#409EFF'
  215. },
  216. process: props.process,
  217. enable: true,
  218. version: 1,
  219. sort: 0,
  220. groupId: '',
  221. remark: ''
  222. }
  223. const xmlData = viewXml(processModel)
  224. xmlData.then((result) => {
  225. previewResult.value = result
  226. previewType.value = 'xml'
  227. previewModelVisible.value = true
  228. })
  229. }
  230. const converterBpmn = () => {
  231. const processModel = {
  232. code: 'test',
  233. name: '测试',
  234. icon: {
  235. name: 'el:HomeFilled',
  236. color: '#409EFF'
  237. },
  238. process: props.process,
  239. enable: true,
  240. version: 1,
  241. sort: 0,
  242. groupId: '',
  243. remark: ''
  244. }
  245. ddToBpmnXml(processModel).then(res => {
  246. console.log("ddToBpmnXml res",res)
  247. processView.xmlData = res.result
  248. processView.title = "Bpmn流程图预览"
  249. processView.open = true
  250. })
  251. }
  252. const save = () => {
  253. const flowData = props.process
  254. emit('save', flowData);
  255. }
  256. const handleToggleDark = () => {
  257. if (isDark.value) {
  258. document.documentElement.classList.add('dark')
  259. } else {
  260. document.documentElement.classList.remove('dark')
  261. }
  262. }
  263. onMounted(() => {
  264. });
  265. </script>
  266. <style scoped lang="scss">
  267. .formDesign {
  268. z-index: 999;
  269. top: 120px;
  270. height: 100%;
  271. }
  272. </style>

5. 렌더링은 다음과 같습니다.

포인트 디자인은 다음과 같습니다.