ItemDrawer.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. <template>
  2. <el-drawer class="local-launch_drawer-wrap" title="测试表单" :model-value="modelValue" size="760px" @update:model-value="updateModelValue">
  3. <!-- <div v-loading="loading" class="local_loading" element-loading-text="加载中..." element-loading-background="rgba(0, 0, 0, 0.1)" />-->
  4. <div class="info-wrap">
  5. <FormCreate class="form-wrap" :option="formOption" :rule="formRule" />
  6. <el-timeline class="timeline-wrap">
  7. <el-timeline-item v-for="(v, index) in processTimelineList" :key="index">
  8. <template v-if="v.conditionNode === 1">
  9. <el-radio-group v-model="processChecked[v.name]" size="small">
  10. <el-radio-button v-for="c of v.conditionNodeList" :key="c.name" :label="c.name" />
  11. </el-radio-group>
  12. </template>
  13. <template v-else>
  14. {{ v.name }}
  15. <!-- {{ v.local_name }} -->
  16. <div v-if="v.type !== 0" style="display: flex; align-items: center; gap: 6px">
  17. <el-button :icon="Plus" style="width: 32px" @click="selectHandler(v.name)" />
  18. <FlowNodeAvatar v-for="(item, index) in userMap.get(v.name)" :key="index" :name="item.name" style="margin-top: 5px" />
  19. </div>
  20. </template>
  21. </el-timeline-item>
  22. </el-timeline>
  23. </div>
  24. </el-drawer>
  25. <use-select ref="useSelectRef"></use-select>
  26. </template>
  27. <script setup lang="ts">
  28. import model from '@/api/flow/process'
  29. import viewForm from '@/utils/form'
  30. import { ref, shallowRef, computed, reactive } from 'vue'
  31. import { ElMessage } from 'element-plus'
  32. import { Plus } from '@element-plus/icons-vue'
  33. import UseSelect from '@/components/scWorkflow/select.vue'
  34. import FlowNodeAvatar from '@/components/Flow/FlowNodeAvatar.vue'
  35. import user from '@/api/system/user'
  36. type Props = {
  37. modelValue: boolean
  38. record: { processId: string; [key: string]: any }
  39. }
  40. const props = defineProps<Props>()
  41. /*const props = withDefaults(defineProps<Props>(), {
  42. modelValue: false
  43. })*/
  44. const emit = defineEmits<{
  45. 'update:modelValue': [bool: boolean] // 具名元组语法
  46. update: [value: string]
  47. }>()
  48. const updateModelValue = (bool: boolean) => emit('update:modelValue', bool)
  49. const userMap = ref(new Map())
  50. const useSelectRef = ref()
  51. const selectHandler = (name: string) => {
  52. if (!userMap.value.get(name)) {
  53. userMap.value.set(name, [])
  54. }
  55. useSelectRef.value.open(1, userMap.value.get(name))
  56. }
  57. const FormCreate = viewForm.$form()
  58. const formOption = ref({
  59. // resetBtn: { show: true },
  60. onSubmit(formData) {
  61. // console.error(formData, 'formData')
  62. const processId = props.record.processId
  63. formOption.value.submitBtn.loading = true
  64. const processForm: any[] = JSON.parse(cur_processForm_str)
  65. processForm.forEach(v => {
  66. // 填写的数据存储(local_: 本地数据处理标识)
  67. v.local_value = formData[v.field]
  68. })
  69. const assigneeMap = {}
  70. userMap.value.forEach((v, k) => {
  71. assigneeMap[k] = {
  72. assigneeList: v,
  73. type: 1
  74. }
  75. })
  76. model
  77. .processLaunchApi({
  78. processId, // 流程ID
  79. processForm: JSON.stringify(processForm), // 流程表单JSON内容 & local_value 保存
  80. assigneeMap: assigneeMap // 流程节点审批人
  81. })
  82. .then(res => {
  83. ElMessage.success('提交成功')
  84. updateModelValue(false)
  85. })
  86. .finally(() => {
  87. formOption.value.submitBtn.loading = false
  88. })
  89. },
  90. submitBtn: { loading: false }
  91. /*formData: {
  92. local_workflow: {},
  93. test_3: 'eeeee'
  94. }*/
  95. })
  96. /*const formData = ref({
  97. local_workflow: {}
  98. })*/
  99. /*const workflowItem = computed(() => {
  100. return {
  101. type:'ScWorkflow',
  102. field: 'local_workflow'
  103. }
  104. })*/
  105. /*const workflowItem = {
  106. type: 'ScWorkflow',
  107. field: 'local_workflow'
  108. }
  109. const formRule = shallowRef([workflowItem])*/
  110. // 当前form 表单数据字符串
  111. let cur_processForm_str = '[]'
  112. const formRule = shallowRef([])
  113. const loading = ref(true)
  114. const processChecked = reactive({
  115. /*'local_条件分支_期限': '短期'*/
  116. })
  117. const localProcessData = ref<any[]>([])
  118. let c_idx = 0
  119. const packageProcess = (data, list = []) => {
  120. return data.reduce((_list, config) => {
  121. if (config.conditionNode === 0) {
  122. // console.log(config.name, 'name 普通节点名称', config)
  123. if (!config.local_name) {
  124. // 普通节点 展示 控制
  125. config.local_name = (config.nodeAssigneeList || []).map(x => x.name).join(',') || config.name
  126. }
  127. userMap.value.set(config.name, config.nodeAssigneeList)
  128. _list.push(config)
  129. } else if (config.conditionNode === 1) {
  130. // 自定义标识key
  131. if (!config.name) {
  132. config.name = `local_${c_idx++}`
  133. }
  134. // console.log('条件节点', config)
  135. _list.push(config)
  136. if (Array.isArray(config.conditionNodeList) && config.conditionNodeList.length) {
  137. const _val = processChecked[config.name]
  138. let condition = config.conditionNodeList[0]
  139. if (_val) {
  140. config.conditionNodeList.some(_condition => {
  141. if (_condition.name === _val) {
  142. condition = _condition
  143. return true
  144. }
  145. })
  146. } else {
  147. // console.error('else......', condition)
  148. processChecked[config.name] = condition.name
  149. }
  150. // console.warn('条件节点', condition.name)
  151. if (Array.isArray(condition.childNode) && condition.childNode.length) {
  152. packageProcess(condition.childNode, _list)
  153. }
  154. }
  155. }
  156. return _list
  157. }, list)
  158. }
  159. const processTimelineList = computed(() => {
  160. return packageProcess(localProcessData.value)
  161. })
  162. model.processListNodeMapApi(props.record.processId).then(res => {
  163. // model.processListNodeMapApi('1747258191679991809').then((res: any[]) => {
  164. localProcessData.value = res
  165. // console.error(localProcessData, 'res..... processListNodeMapApi')
  166. })
  167. model.processDetailApi(props.record.processId).then(res => {
  168. // model.processDetailApi('1747258191679991809').then(res => {
  169. // console.error(res, '详情 process....', props.record)
  170. // modelContent 审批流数据
  171. let local_workflow = {}
  172. try {
  173. console.log(JSON.parse(res.modelContent))
  174. const modelContent = JSON.parse(res.modelContent)
  175. local_workflow = modelContent.nodeConfig ?? modelContent.childNode
  176. } catch (e) {}
  177. // formOption.value.formData = { local_workflow, test_3: 'eeeee' }
  178. cur_processForm_str = res.processForm || '[]'
  179. // processForm 动态表单
  180. formRule.value = [...JSON.parse(cur_processForm_str) /*, { ...workflowItem, value: local_workflow }*/ /*, { type: 'input', field: 'test_3' }*/]
  181. // loading.value = false
  182. // console.error(formData.value, 'formData.value')
  183. })
  184. </script>
  185. <style lang="scss">
  186. .local-launch_drawer-wrap {
  187. .el-drawer__header {
  188. display: flex;
  189. padding: 16px 24px;
  190. align-items: center;
  191. justify-content: space-between;
  192. background-color: var(--el-color-info-light-9);
  193. text-align: left;
  194. /* margin-right: 0; */
  195. margin-bottom: 0;
  196. }
  197. .el-drawer__close-btn {
  198. padding: 0;
  199. margin-right: -12px;
  200. }
  201. .el-drawer__body {
  202. position: relative;
  203. //display: flex;
  204. //flex-direction: column;
  205. }
  206. .local_loading {
  207. position: absolute;
  208. left: 0;
  209. display: flex;
  210. align-items: center;
  211. justify-content: center;
  212. width: 100%;
  213. height: 100%;
  214. z-index: 999;
  215. background: rgba(0, 0, 0, 0.05);
  216. }
  217. }
  218. </style>
  219. <style scoped lang="scss">
  220. .info-wrap {
  221. display: flex;
  222. .form-wrap {
  223. flex: 1;
  224. }
  225. .timeline-wrap {
  226. margin-left: 8px;
  227. flex-shrink: 0;
  228. padding: 0;
  229. width: 360px;
  230. }
  231. }
  232. </style>