index.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. <template>
  2. <div class="create-approval">
  3. <div class="create-approval-header flex flex_align-center">
  4. <div v-if="false" class="create-approval-header-back">
  5. <el-icon :size="18">
  6. <ArrowLeft />
  7. </el-icon>
  8. </div>
  9. <div class="create-approval-header-left-zh">
  10. <div class="create-approval-header-name">{{ processName }}</div>
  11. <div v-if="false" class="create-approval-header-time">最近保存:6 分钟前</div>
  12. </div>
  13. <div class="create-approval-header-tab-list">
  14. <div
  15. v-for="(item, idx) in componentsArr"
  16. :key="idx"
  17. class="create-approval-header-tab-item"
  18. :class="[item.value === activeTab ? 'active' : '']"
  19. @click="activeComponent(idx)"
  20. >
  21. <span class="create-approval-header-tab-counter">{{ idx + 1 }}</span>
  22. <span>{{ item.label }}</span>
  23. </div>
  24. </div>
  25. <div class="create-approval-header-right">
  26. <el-button type="primary" @click="submitHandler">发布</el-button>
  27. </div>
  28. </div>
  29. <div class="create-approval-main">
  30. <component :is="item.component" v-for="(item, idx) in componentsArr" v-show="item.value === activeTab" ref="compRefs" :key="idx" />
  31. </div>
  32. </div>
  33. </template>
  34. <script setup name="flow_create">
  35. import { computed, nextTick, ref } from 'vue'
  36. import { storeToRefs } from 'pinia'
  37. import useFlowStore from '@/store/modules/flow'
  38. import BasicInfoTab from './components/BasicInfo.vue'
  39. import ExtendSetTab from './components/ExtendSet.vue'
  40. import FlowDesignTab from './components/FlowDesign.vue'
  41. import FormDesignTab from './components/FormDesign.vue'
  42. import { useRoute, useRouter } from 'vue-router'
  43. import process from '@/api/flow/process'
  44. import useStore from '@/store'
  45. import { ElMessage } from 'element-plus'
  46. const { tagsView } = useStore()
  47. const router = useRouter()
  48. const route = useRoute()
  49. const flowStore = useFlowStore()
  50. const { categoryId, processId, processIcon, processKey, processName, remark, modelContent, processForm, processSetting } = storeToRefs(flowStore)
  51. const compRefs = ref() // 实例化子组件
  52. const cache_components = ref({})
  53. const componentsArr = [
  54. {
  55. component: BasicInfoTab,
  56. label: '基础信息',
  57. value: '基础信息'
  58. // ref: 'basicInfoRef'
  59. },
  60. {
  61. component: FormDesignTab,
  62. label: '表单设计',
  63. value: '表单设计'
  64. // ref: 'formDesignRef'
  65. },
  66. {
  67. component: FlowDesignTab,
  68. label: '流程设计',
  69. value: '流程设计'
  70. // ref: 'flowDesignRef'
  71. },
  72. {
  73. component: ExtendSetTab,
  74. label: '扩展设置',
  75. value: '扩展设置'
  76. // ref: 'extendSetRef'
  77. }
  78. ]
  79. const activeTab = ref('基础信息')
  80. const removeCurTab = () => {
  81. cache_components.value = {}
  82. const _view = tagsView.visitedViews.find(v => v.path === '/flow_create/index')
  83. if (_view)
  84. tagsView.delView(_view).then(res => {
  85. const latestView = res.visitedViews.slice(-1)[0]
  86. if (latestView && latestView.fullPath) {
  87. router.push(latestView.fullPath)
  88. } else {
  89. router.push('/')
  90. }
  91. flowStore.$reset()
  92. })
  93. }
  94. const submitHandler = async () => {
  95. // 基础信息
  96. // 表单设计
  97. // 流程设计
  98. // 扩展设置
  99. const leavePageFlag = await validateTabs()
  100. if (!leavePageFlag) return
  101. const params = {
  102. categoryId: categoryId.value,
  103. processIcon: processIcon.value,
  104. processKey: processKey.value,
  105. processName: processName.value,
  106. remark: remark.value,
  107. processId: processId.value,
  108. processForm: processForm.value,
  109. modelContent: JSON.stringify({
  110. key: processKey.value,
  111. name: processName.value,
  112. nodeConfig: JSON.parse(modelContent.value || '{}')
  113. }),
  114. processSetting: processSetting.value
  115. }
  116. const res = await process.progressCreateApi(params)
  117. console.log('---r-e-s----', res)
  118. ElMessage.success('操作成功')
  119. // 创建完成 删除 当前tab页
  120. removeCurTab()
  121. }
  122. // 切换选项卡之前,做相应的保存操作
  123. const validateTabs = async () => {
  124. const _refs = compRefs.value
  125. // await nextTick()
  126. for (let i = 0; i < _refs.length; i++) {
  127. let bool = true
  128. /*// 若没开启过的 tab 需要尝试 进行更新数据
  129. if (!cache_components.value[i]) {
  130. cache_components.value[i]?.updateCompInfo()
  131. }*/
  132. const _validate =
  133. _refs[i]?.validate ||
  134. function () {
  135. return Promise.resolve()
  136. }
  137. await _validate().catch(e => {
  138. activeTab.value = componentsArr[i].label
  139. if (activeTab.value === '表单设计') {
  140. ElMessage.error('请为流程设计表单内容')
  141. }
  142. bool = false
  143. })
  144. if (!bool) return false
  145. }
  146. return true
  147. }
  148. const activeComponent = index => {
  149. const cur = componentsArr[index]
  150. if (activeTab.value !== cur.value) {
  151. if (activeTab.value === '表单设计') {
  152. compRefs.value[1]?.exportJsonEv()
  153. }
  154. // 当前缓存
  155. if (!cache_components.value[index]) {
  156. // 更新数据
  157. const updateCompInfo = compRefs.value[index]?.updateCompInfo
  158. // console.error('刷新数据')
  159. // console.error(updateCompInfo, 'updateCompInfo')
  160. if (updateCompInfo) {
  161. updateCompInfo()
  162. }
  163. }
  164. activeTab.value = cur.value
  165. }
  166. }
  167. const queryObj = computed(() => route.query)
  168. const getCurrentProcessDetailEv = () => {
  169. let _id = queryObj.value.id
  170. if (_id) {
  171. cache_components.value = {}
  172. process.processDetailApi(_id).then(res => {
  173. processId.value = res.processId
  174. categoryId.value = res.categoryId
  175. processIcon.value = res.processIcon
  176. processKey.value = res.processKey
  177. processName.value = res.processName
  178. remark.value = res.remark
  179. let nodeConfig = JSON.parse(res.modelContent).nodeConfig
  180. modelContent.value = JSON.stringify(nodeConfig)
  181. processForm.value = res.processForm
  182. flowStore.setProcessForm(processForm)
  183. flowStore.setProcessSetting(res.processSetting)
  184. })
  185. }
  186. }
  187. getCurrentProcessDetailEv()
  188. </script>
  189. <style scoped lang="scss">
  190. .create-approval {
  191. height: 100%;
  192. min-width: 1200px;
  193. min-height: 600px;
  194. overflow: auto;
  195. &-header {
  196. justify-content: flex-start;
  197. height: 64px;
  198. //z-index: 12;
  199. position: relative;
  200. box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.06);
  201. padding-left: 16px;
  202. padding-right: 20px;
  203. &-back {
  204. display: flex;
  205. justify-content: flex-start;
  206. align-items: center;
  207. height: 100%;
  208. margin-right: 15px;
  209. }
  210. &-left-zh {
  211. width: calc(50% - 316.5px);
  212. min-width: 248px;
  213. }
  214. &-name {
  215. font-weight: 500;
  216. font-size: 16px;
  217. white-space: nowrap;
  218. cursor: pointer;
  219. width: -webkit-fit-content;
  220. width: -moz-fit-content;
  221. width: fit-content;
  222. max-width: 100%;
  223. height: 24px;
  224. overflow: hidden;
  225. text-overflow: ellipsis;
  226. }
  227. &-time {
  228. width: 100%;
  229. height: 20px;
  230. line-height: 20px;
  231. font-size: 12px;
  232. color: #8f959e;
  233. overflow: hidden;
  234. white-space: nowrap;
  235. text-overflow: ellipsis;
  236. }
  237. &-tab-list {
  238. margin-left: 10px;
  239. flex-shrink: 0;
  240. display: flex;
  241. justify-content: center;
  242. }
  243. &-tab-item {
  244. font-family: PingFang SC, Microsoft YaHei;
  245. font-size: 18px;
  246. line-height: 28px;
  247. color: #646a73;
  248. margin-right: 42px;
  249. padding: 18px 0;
  250. border-bottom: 2px solid transparent;
  251. cursor: pointer;
  252. &.active {
  253. // var(--el-color-primary);
  254. border-bottom-color: var(--el-color-primary);
  255. color: var(--el-color-primary);
  256. font-weight: 500;
  257. .create-approval-header-tab-counter {
  258. border-color: var(--el-color-primary);
  259. background-color: var(--el-color-primary);
  260. color: var(--el-color-white);
  261. font-weight: 400;
  262. }
  263. }
  264. }
  265. &-tab-counter {
  266. display: inline-block;
  267. margin-right: 6px;
  268. width: 24px;
  269. height: 24px;
  270. border-radius: 50%;
  271. border: 1px solid #646a73;
  272. font-size: 16px;
  273. line-height: 22px;
  274. text-align: center;
  275. }
  276. &-right {
  277. flex: 1 1;
  278. flex-shrink: 0;
  279. display: flex;
  280. justify-content: flex-end;
  281. align-items: center;
  282. position: relative;
  283. height: 100%;
  284. width: -webkit-fit-content;
  285. width: -moz-fit-content;
  286. width: fit-content;
  287. }
  288. }
  289. &-main {
  290. height: calc(100% - 64px);
  291. }
  292. }
  293. </style>