wbs-tree.vue 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. <template>
  2. <hc-drawer v-model="isShow" is-close to-id="hc-project-list" @close="dialogClose">
  3. <div class="hc-project-wbs-tree flex">
  4. <div class="header hc-flex">
  5. <div class="name flex-1">{{ typeLable }} - {{ projectInfo.projectName }}</div>
  6. <div class="hc-flex">
  7. <el-dropdown trigger="click">
  8. <el-button hc-btn type="success">
  9. <span>数据同步</span>
  10. <hc-icon name="arrow-down-s" />
  11. </el-button>
  12. <template #dropdown>
  13. <el-dropdown-menu>
  14. <template v-for="item in dataSyncMenu" :key="item.key">
  15. <el-dropdown-item @click="dataSyncMenuClick(item)">{{ item.name }}</el-dropdown-item>
  16. </template>
  17. </el-dropdown-menu>
  18. </template>
  19. </el-dropdown>
  20. <el-button v-if="isFormSet" class="ml-3" hc-btn type="primary" @click="setIsFormSetValue">表单设置</el-button>
  21. <el-button v-else class="ml-3" hc-btn type="primary" @click="setIsFormSetValue">元素设置</el-button>
  22. <el-button hc-btn type="danger" @click="nodeParamClick">节点参数</el-button>
  23. <el-button color="#626aef" hc-btn @click="toIndependent">独立表单库</el-button>
  24. <el-button hc-btn type="warning" @click="archiveClick">归档文件时间</el-button>
  25. </div>
  26. </div>
  27. <div class="body">
  28. <hc-body padding="8px" split :options="splitOptions">
  29. <template #left>
  30. <hc-card v-loading="isTreeLoading" class="is-tree" scrollbar title="工程节点信息">
  31. <template #search>
  32. <hc-search-input v-model="searchTree.queryValue" @search="searchTreeClick">
  33. <template #prepend>
  34. <el-select v-model="searchTree.type" placeholder="类型" style="width: 75px">
  35. <el-option label="节点" value="1" />
  36. <el-option label="表名" value="2" />
  37. </el-select>
  38. </template>
  39. </hc-search-input>
  40. </template>
  41. <div v-if="isShowTree">
  42. <hc-data-tree
  43. v-if="isSearchTree" :auto-expand-keys="treeExpandKeys" :datas="treeLoadData" :h-props="treeProps"
  44. :menus="treeMenus" tree-key="id" @menu-tap="treeMenuClick" @node-tap="treeNodeClick"
  45. />
  46. <hc-lazy-tree
  47. v-else :auto-expand-keys="treeExpandKeys" :h-props="treeProps" :menus="treeMenus"
  48. tree-key="id" @load="treeLoadNode" @menu-tap="treeMenuClick" @node-tap="treeNodeClick"
  49. />
  50. </div>
  51. </hc-card>
  52. </template>
  53. <template v-if="isFormSet">
  54. <div class="body-top">
  55. <hc-card title="节点信息">
  56. <hc-table :column="nodeTableColumn" :datas="nodeTableData" :is-index="false">
  57. <template #nodeType="{ row }">
  58. {{ getDictionaryName(nodeTypelist, row.nodeType, true) }}
  59. </template>
  60. </hc-table>
  61. </hc-card>
  62. </div>
  63. <div class="body-content">
  64. <hc-card title="当前项目信息表">
  65. <template #extra>
  66. <el-button :disabled="infoTableData.length <= 0" hc-btn type="primary" @click="editRowClick(row)">编辑</el-button>
  67. <el-button :disabled="infoTableData.length <= 0" hc-btn type="success" @click="sortClick">排序</el-button>
  68. </template>
  69. <hc-table v-loading="infoTableLoading" :column="infoTableColumn" :datas="infoTableData" :is-index="false">
  70. <template #tableType="{ row }">
  71. {{ getDictionaryName(tableTypelist, row.tableType, true) }}
  72. </template>
  73. <template #tableOwner="{ row }">
  74. {{ getDictionaryName(ownerTypeList, row.tableOwner, true) }}
  75. </template>
  76. <template #action="{ row }">
  77. <el-link type="primary" @click="previewClick(row)">预览</el-link>
  78. <el-link v-if="row.status === 1" type="warning" @click="hideClick(row)">隐藏表单</el-link>
  79. <el-link v-if="row.status === 0" type="success" @click="hideClick(row)">取消隐藏</el-link>
  80. <el-link type="primary" @click="handleEdit(row)">编辑</el-link>
  81. <el-link v-del-com:[delInfoTableRow]="row" type="danger">删除</el-link>
  82. </template>
  83. </hc-table>
  84. </hc-card>
  85. </div>
  86. </template>
  87. <template v-else>
  88. <hc-card>
  89. <hc-table v-loading="infoTableLoading" :column="infoTableColumn1" :datas="infoTableData" :is-index="false">
  90. <template #tableType="{ row }">
  91. {{ getDictionaryName(tableTypelist, row.tableType, true) }}
  92. </template>
  93. <template #isLinkTable="{ row }">
  94. {{ row.isLinkTable === 2 ? '是' : '否' }}
  95. </template>
  96. <template #tableOwner="{ row }">
  97. {{ getDictionaryName(ownerTypeList, row.tableOwner, true) }}
  98. </template>
  99. <template #action="{ row }">
  100. <el-link type="success" @click="associationList(row)">关联清表</el-link>
  101. <el-link v-loading="row.editElementLoading" :disabled="row.excelId === -1 || isNullES(row.excelId) " type="primary" class="link-class" @click="editElement(row)">编辑元素</el-link>
  102. <el-link v-loading="row.adjustExcelLoading" :disabled="row.excelId === -1 || isNullES(row.excelId)" type="warning" class="link-class" @click="adjustExcelClick(row)">调整表单</el-link>
  103. <el-link type="primary" @click="elementFormulasClick(row)">编辑元素公式</el-link>
  104. <el-link v-loading="row.syncTableLoading" type="warning" @click="syncTable(row)">表单同步</el-link>
  105. <el-link v-if="treeItem.nodeType === 1000 || treeItem.nodeType === 1001" type="primary" @click="linkNodeClick(row)">关联节点</el-link>
  106. <el-link v-del-com:[delInfoTableRow]="row" type="danger">删除表单</el-link>
  107. </template>
  108. </hc-table>
  109. </hc-card>
  110. </template>
  111. </hc-body>
  112. </div>
  113. </div>
  114. <!-- 编辑节点 -->
  115. <TreeNodeEditDialog
  116. v-model="isTreeNodeEditShow" :major-type="majorDataTypeList" :node="treeInfo"
  117. :node-type="nodeTypelist" :pid="projectInfo.id" :tree-props="treeProps" :type="Number(isType)"
  118. :wid="wbsId" @change="treeNodeEditChange" @close="treeNodeEditClose"
  119. />
  120. <!-- 节点排序 -->
  121. <hc-new-dialog v-model="nodeSortModalShow" is-table title="调整排序" widths="1100px" @save="nodeSortModalSave">
  122. <hc-table
  123. :column="nodeSortTableColumn" :datas="nodeSortTableData" :index-style="{ width: 80 }"
  124. :loading="nodeSortNodeLoading" is-row-drop quick-sort ui="hc-table-row-drop"
  125. @row-drop="nodeSortTableRowDrop" @row-sort="nodeSortTableRowDrop"
  126. >
  127. <template #action="{ row, index }">
  128. <span :class="index === 0 ? 'text-gray' : 'text-link'" class="text-xl" @click="upNodeSortClick(row, index)">
  129. <hc-icon fill name="arrow-up" />
  130. </span>
  131. <span :class=" index === nodeSortTableData.length - 1 ? 'text-gray' : 'text-link' " class="ml-2 text-xl" @click="downNodeSortClick(row, index)">
  132. <hc-icon fill name="arrow-down" />
  133. </span>
  134. </template>
  135. </hc-table>
  136. </hc-new-dialog>
  137. <!-- 关联清表 -->
  138. <HcAssociationList v-model="isAssociationShow" :info="associationInfo" @change="getInfoTableData" />
  139. <!-- 编辑元素 -->
  140. <HcEditElement v-model="isEditElementShow" :data="editElementData" :info="editElementInfo" @to-page="editElementToPage" />
  141. <!-- 调整表单 -->
  142. <HcAdjustExcel v-model="isAdjustExcelShow" :info="adjustExcelInfo" />
  143. <!-- 编辑元素公式 -->
  144. <hc-dialog v-model="elementFormulasShow" :footer="false" :title="elementFormulasName" is-table widths="600px" @close="elementFormulasClose">
  145. <template #search>
  146. <hc-search-input v-model="formulaInput" @search="searchFormulaClick" />
  147. </template>
  148. <hc-table v-loading="formulaTableLoading" :column="formulaTableColumn" :datas="formulaTableData" :is-current-row="false" :is-index="false">
  149. <template #action="{ row }">
  150. <el-link :type="row.globalFormula === 1 ? 'warning' : 'primary'" @click="toFormulaGlobal(row)">全局公式</el-link>
  151. <el-link v-show="row.hasPartFormula" :type="row.isSaveFormula === 1 ? 'warning' : 'primary'" @click="toFormulaNodes(row)">节点公式</el-link>
  152. </template>
  153. </hc-table>
  154. </hc-dialog>
  155. <!-- 编辑公式 -->
  156. <HcEditFormula v-model="isEditFormulaShow" :data="editFormulaData" @finish="editFormulaFinish" />
  157. <!-- 节点参数设置 -->
  158. <nodeParamDialog v-model="nodeParamShow" :node-id="treeItem.id" :node-info="treeItem" :project-id="projectInfo.id" :scope-type="10" @close="nodeParamClose" />
  159. <!-- 独立表单库 -->
  160. <independentPage v-model="independentShow" :project-id="projectInfo.id" :wbs-id="wbsId" :wbs-type="isType" @close="independentClose" />
  161. <!-- 归档文件时间 -->
  162. <archiveTime v-model="isArchiveShow" />
  163. <!-- 编辑元素表信息 -->
  164. <editElePage v-model="editEleShow" :owner-type-list="ownerTypeList" :tab="infoTableData" :table-typelist="tableTypelist" @close="editClose" />
  165. <!-- 表单调整排序 -->
  166. <tableSort v-model="tableSortShow" :tab="infoTableData" @close="tableSortShowClose" />
  167. <!-- 预览 -->
  168. <previewPage v-model="previewShow" :info="previewInfo" />
  169. <!-- 创建新的元素表 -->
  170. <createNewExcel
  171. v-model="isCreateShow" :e-key="eKey" :init-table-id="initTableId" :init-table-name="initTableName"
  172. :node="treeItem" :owner-type-list="ownerTypeList" :table-id="tableId" :table-typelist="tableTypelist"
  173. :title="modalTitle" :type="0" :wid="wbsId" :is-add="isAddType" @close="createClose"
  174. />
  175. <!-- 分配WBS -->
  176. <allocateWbs v-model="isAllocateShow" :data="allocateWbsInfo" :project-id="projectInfo.id" :type="1" :wbs-type="isType" />
  177. </hc-drawer>
  178. </template>
  179. <script setup>
  180. import { nextTick, onDeactivated, ref, watch } from 'vue'
  181. import { useAppStore } from '~src/store'
  182. import { HcFirmMsg, getStore, setStore } from 'hc-vue3-ui'
  183. import { deepClone, getArrValue, getObjValue, isNullES } from 'js-fast-way'
  184. import { getDictionaryData, reloadPage } from '~uti/tools'
  185. //组件
  186. import TreeNodeEditDialog from './tree-node-edit.vue'
  187. import HcAdjustExcel from './adjust-excel.vue'
  188. import HcAssociationList from './association-list.vue'
  189. import HcEditElement from './edit-element.vue'
  190. import HcEditFormula from './edit-formula.vue'
  191. import nodeParamDialog from '../../desk/wbs/node-param-dialog.vue'
  192. import independentPage from './independent/index.vue'
  193. import archiveTime from './archiveTime.vue'
  194. import editElePage from '../../desk/wbs/edit-ele.vue'
  195. import tableSort from '../../desk/wbs/table-sort.vue'
  196. import previewPage from './previewPage.vue'
  197. import createNewExcel from '../../desk/wbs/create-new-excel.vue'
  198. import allocateWbs from '../list/independent/allocateWbs.vue'
  199. //接口
  200. import excelApi from '~api/exctab/exceltab'
  201. import wbsTreeApi from '~api/wbs/tree'
  202. import mainApi from '~api/wbs/private'
  203. //参数
  204. const props = defineProps({
  205. type: {
  206. type: [String, Number],
  207. default: '1',
  208. },
  209. info: {
  210. type: Object,
  211. default: () => ({}),
  212. },
  213. })
  214. //事件
  215. const emit = defineEmits(['change', 'close'])
  216. //页面分割
  217. const splitOptions = { sizes: [25, 75], snapOffset: 0, minSize: [300, 300] }
  218. //双向绑定
  219. // eslint-disable-next-line no-undef
  220. const isShow = defineModel('modelValue', {
  221. default: false,
  222. })
  223. const store = useAppStore()
  224. //监听数据
  225. const isType = ref(props.type)
  226. const projectInfo = ref(props.info)
  227. watch(
  228. () => [props.type, props.info],
  229. ([type, info]) => {
  230. isType.value = type
  231. projectInfo.value = info
  232. },
  233. { deep: true },
  234. )
  235. //监听显示
  236. watch(isShow, (val) => {
  237. if (val) {
  238. getProjectData()
  239. } else {
  240. //projectInfo.value = {}
  241. //isType.value = ''
  242. emit('close')
  243. }
  244. })
  245. //关闭弹窗
  246. const dialogClose = () => {
  247. infoTableData.value = []
  248. nodeTableData.value = []
  249. isShow.value = false
  250. emit('close')
  251. }
  252. //获取项目信息
  253. const typeLable = ref('')
  254. const wbsId = ref('')
  255. const getProjectData = () => {
  256. const type = isType.value ?? 1
  257. const wbsArr = [
  258. 'WBS树管理',
  259. '实验划分',
  260. '计量管理',
  261. '日志树管理',
  262. '征拆划分',
  263. ]
  264. typeLable.value = wbsArr[Number(type) - 1]
  265. const wbsIds = [
  266. 'referenceWbsTemplateId',
  267. 'referenceWbsTemplateIdTrial',
  268. 'referenceWbsTemplateIdMeter',
  269. 'referenceLogWbsTemplateId',
  270. 'referenceWbsTemplateIdLar',
  271. ]
  272. wbsId.value = projectInfo.value[wbsIds[Number(type) - 1]]
  273. console.log('info: ', projectInfo.value)
  274. getNodeTypelist(Number(type) - 1)
  275. getTableTypelist(Number(type) - 1)
  276. getDataTypelist()
  277. getOwnerTypelist()
  278. getMajorDataTypeList()
  279. }
  280. //获取节点类型
  281. const nodeTypelist = ref([])
  282. const getNodeTypelist = async (type) => {
  283. //计量管理,征拆划分,实验划分,WBS树管理,日志树管理
  284. const types = [
  285. 'wbs_node_type',
  286. 'trial_node_type',
  287. 'meter_node_type',
  288. 'wbs_node_type',
  289. 'lar_node_type',
  290. ]
  291. const data = await getDictionaryData(types[type])
  292. nodeTypelist.value = getArrValue(data)
  293. }
  294. //获取表单类型
  295. const tableTypelist = ref([])
  296. const getTableTypelist = async (type) => {
  297. //计量管理,征拆划分,实验划分,WBS树管理,日志树管理
  298. const types = [
  299. 'table_type',
  300. 'trial_table_type',
  301. 'table_type',
  302. 'table_type',
  303. 'table_type',
  304. ]
  305. const data = await getDictionaryData(types[type])
  306. tableTypelist.value = getArrValue(data)
  307. }
  308. //获取数据类型
  309. const dataTypeList = ref([])
  310. const getDataTypelist = async () => {
  311. const data = await getDictionaryData('data_type')
  312. dataTypeList.value = getArrValue(data)
  313. }
  314. //获取业主类型
  315. const ownerTypeList = ref([])
  316. const getOwnerTypelist = async () => {
  317. const data = await getDictionaryData('owner_type')
  318. ownerTypeList.value = getArrValue(data)
  319. }
  320. //获取类型字典
  321. const majorDataTypeList = ref([])
  322. const getMajorDataTypeList = async () => {
  323. const data = await getDictionaryData('major_data_type')
  324. majorDataTypeList.value = getArrValue(data)
  325. }
  326. //获取字典里的数据
  327. const getDictionaryName = (arr, id, name) => {
  328. if (isNullES(id)) return name ? '' : {}
  329. const item = arr.find((item) => item.value === Number(id))
  330. return name ? item?.label : getObjValue(item)
  331. }
  332. const isShowTree = ref(true)
  333. const refreshTree = () => {
  334. isShowTree.value = false
  335. setTimeout(() => {
  336. isShowTree.value = true
  337. }, 1000)
  338. }
  339. //树节点搜索
  340. const isSearchTree = ref(false)
  341. const isTreeLoading = ref(false)
  342. const searchTree = ref({ queryValue: '', type: '1' })
  343. const searchTreeClick = () => {
  344. const { queryValue } = searchTree.value
  345. isSearchTree.value = !isNullES(queryValue)
  346. getTreeLoadData()
  347. }
  348. //获取搜索树的数据
  349. const treeLoadData = ref([])
  350. const getTreeLoadData = async () => {
  351. isTreeLoading.value = true
  352. const { data } = await wbsTreeApi.getQueryValueByType({
  353. ...searchTree.value,
  354. wbsId: wbsId.value,
  355. projectId: projectInfo.value.id,
  356. })
  357. treeLoadData.value = getArrValue(data)
  358. isTreeLoading.value = false
  359. }
  360. //树属性
  361. const treeExpandKeys = ref(getStore('project-wbs-tree-expand-keys') || [])
  362. const treeProps = {
  363. children: 'children',
  364. label: 'title',
  365. isLeaf: ({ hasChildren, isExistForm, majorDataType, nodeType }) => {
  366. let tag = false
  367. if (!hasChildren) {
  368. tag = true
  369. }
  370. if (isExistForm === 1) {
  371. tag = true
  372. }
  373. if (nodeType >= 6 && nodeType <= 13) {
  374. tag = true
  375. }
  376. //中间交工。开工报告、质量评定)
  377. if (majorDataType >= 1 && majorDataType <= 3) {
  378. tag = true
  379. }
  380. return tag
  381. },
  382. }
  383. //树的右键菜单
  384. const treeMenus = [
  385. { icon: 'draft', label: '编辑节点', key: 'edit' },
  386. { icon: 'refresh', label: '同步新增元素表单', key: 'sync1' },
  387. { icon: 'loop-left', label: '同步元素表单排序到合同段', key: 'sync3' },
  388. { icon: 'loop-right', label: '同步节点基础信息及表单URL', key: 'sync2' },
  389. { icon: 'arrow-up-down', label: '调整排序', key: 'rank' },
  390. { icon: 'delete-bin', label: '删除节点', key: 'del' },
  391. ]
  392. //菜单被点击
  393. const treeMenuItem = ref({})
  394. const treeMenuClick = async ({ key, node, data }) => {
  395. if (key === 'edit') {
  396. //编辑节点
  397. data.parentName = node?.parent?.data?.title ?? '' //获取父节点名称
  398. treeItem.value = data
  399. await getTreeDetail()
  400. await nextTick()
  401. isTreeNodeEditShow.value = true
  402. } else if (key === 'sync1') {
  403. const { primaryKeyId, pKeyId } = data
  404. const pid = primaryKeyId ? primaryKeyId : pKeyId
  405. if (isNullES(pid)) {
  406. window.$message.warning('参数异常,请稍后重试')
  407. return
  408. }
  409. //同步新增元素表单
  410. HcFirmMsg(
  411. {
  412. text: `是否同步节点【${data.title}】?`,
  413. loadingText: '数据同步中...',
  414. },
  415. async (resolve) => {
  416. const { isRes } = await mainApi.syncNodeTable(pid)
  417. resolve() //关闭弹窗
  418. if (!isRes) return
  419. window.$message.success('同步成功')
  420. getInfoTableData()
  421. },
  422. )
  423. } else if (key === 'sync3') {
  424. const { id } = projectInfo.value
  425. if (isNullES(id)) {
  426. window.$message.warning('参数异常,请稍后重试')
  427. return
  428. }
  429. //同步元素表单排序到合同段
  430. HcFirmMsg(
  431. {
  432. text: '同步元素表单排序到合同段?',
  433. loadingText: '数据同步中...',
  434. },
  435. async (resolve) => {
  436. const { isRes } = await mainApi.syncContractTabSort(id)
  437. resolve() //关闭弹窗
  438. if (!isRes) return
  439. window.$message.success('同步成功')
  440. getInfoTableData()
  441. },
  442. )
  443. } else if (key === 'sync2') {
  444. const { primaryKeyId, pKeyId } = data
  445. const pid = primaryKeyId ? primaryKeyId : pKeyId
  446. if (isNullES(pid)) {
  447. window.$message.warning('参数异常,请稍后重试')
  448. return
  449. }
  450. //同步节点基础信息及表单URL
  451. HcFirmMsg(
  452. {
  453. text: `是否同步节点【${data.title}】到合同段?`,
  454. loadingText: '数据同步中...',
  455. },
  456. async (resolve) => {
  457. const { isRes } = await mainApi.syncNodeinfo(pid)
  458. resolve() //关闭弹窗
  459. if (!isRes) return
  460. window.$message.success('同步成功')
  461. getInfoTableData()
  462. },
  463. )
  464. } else if (key === 'rank') {
  465. const { parentId } = data
  466. const { id } = projectInfo.value
  467. if (isNullES(id) || isNullES(wbsId.value)) {
  468. window.$message.warning('参数异常,请稍后重试')
  469. return
  470. }
  471. //调整排序
  472. nodeSortModalShow.value = true
  473. nodeSortNodeLoading.value = true
  474. const { data: apiData } = await wbsTreeApi.findWbsTreePrivateSameLevel({
  475. parentId: parentId,
  476. projectId: id,
  477. wbsId: wbsId.value,
  478. })
  479. nodeSortNodeLoading.value = false
  480. nodeSortTableData.value = getArrValue(apiData)
  481. } else if (key === 'del') {
  482. if (node.level <= 1) {
  483. window.$message.warning('当前节点无法删除')
  484. return
  485. }
  486. const { primaryKeyId, pKeyId } = data
  487. const pid = primaryKeyId ? primaryKeyId : pKeyId
  488. if (isNullES(pid)) {
  489. window.$message.warning('参数异常,请稍后重试')
  490. return
  491. }
  492. //删除节点
  493. HcFirmMsg(
  494. {
  495. text: `此操作将删除节点【${data.title}】,是否继续?`,
  496. loadingText: '删除节点中...',
  497. },
  498. async (resolve) => {
  499. const { isRes } = await mainApi.del(pid)
  500. resolve() //关闭弹窗
  501. if (!isRes) return
  502. window.$message.success('删除成功')
  503. reloadPage()
  504. },
  505. )
  506. }
  507. }
  508. //节点排序
  509. const nodeSortModalShow = ref(false)
  510. const nodeSortTableColumn = ref([
  511. { key: 'tableName', name: '节点名称' },
  512. { key: 'action', name: '排序', width: 90 },
  513. ])
  514. const nodeSortTableData = ref([])
  515. const nodeSortNodeLoading = ref(false)
  516. //拖动完成
  517. const nodeSortTableRowDrop = (rows) => {
  518. nodeSortTableData.value = [] // 先清空,否则排序会异常
  519. nextTick(() => {
  520. nodeSortTableData.value = rows
  521. })
  522. }
  523. //向上
  524. const upNodeSortClick = (row, index) => {
  525. const data = nodeSortTableData.value || []
  526. if (index !== 0) {
  527. const tmp = data.splice(index - 1, 1)
  528. nodeSortTableData.value.splice(index, 0, tmp[0])
  529. } else {
  530. window?.$message?.warning('已经处于置顶,无法上移')
  531. }
  532. }
  533. //向下
  534. const downNodeSortClick = (row, index) => {
  535. const indexs = index + 1
  536. const data = nodeSortTableData.value
  537. if (indexs !== data.length) {
  538. const tmp = data.splice(indexs, 1)
  539. nodeSortTableData.value.splice(index, 0, tmp[0])
  540. } else {
  541. window?.$message?.warning('已经处于置底,无法下移')
  542. }
  543. }
  544. //节点排序完成
  545. const nodeSortModalSave = async () => {
  546. const arr = deepClone(nodeSortTableData.value)
  547. if (arr.length <= 0) {
  548. window.$message.warning('数据异常,请稍后重试')
  549. nodeSortModalShow.value = false
  550. return
  551. }
  552. //处理顺序
  553. for (let i = 0; i < arr.length; i++) {
  554. arr[i].sort = i + 1
  555. }
  556. //发起请求
  557. const { isRes } = await wbsTreeApi.wbsTreePrivateSort(arr)
  558. if (!isRes) return
  559. window.$message.success('排序完成')
  560. nodeSortModalShow.value = false
  561. // reloadPage()
  562. refreshTree()
  563. }
  564. //编辑节点
  565. const isTreeNodeEditShow = ref(false)
  566. //编辑节点被关闭
  567. const treeNodeEditClose = () => {
  568. isTreeNodeEditShow.value = false
  569. treeMenuItem.value = {}
  570. }
  571. //编辑节点被修改
  572. const treeNodeEditChange = () => {
  573. isTreeNodeEditShow.value = false
  574. treeMenuItem.value = {}
  575. console.log('编辑节点被修改')
  576. refreshTree()
  577. }
  578. //懒加载树
  579. const treeLoadNode = async ({ item, level }, resolve) => {
  580. let pid = level !== 0 ? item.id : 0
  581. const { data } = await mainApi.getLazytree({
  582. wbsId: wbsId.value,
  583. parentId: pid,
  584. tenantId: store.tenantId,
  585. projectId: projectInfo.value.id,
  586. wbsType: isType.value,
  587. })
  588. resolve(getArrValue(data))
  589. }
  590. //节点信息
  591. const nodeTableColumn = ref([
  592. { key: 'nodeName', name: '当前节点', align: 'center' },
  593. { key: 'nodeType', name: '节点类型', align: 'center' },
  594. { key: 'parentName', name: '上级节点', align: 'center' },
  595. ])
  596. const nodeTableData = ref([])
  597. //节点被点击
  598. const treeItem = ref({})
  599. const nodePid = ref('')
  600. const treeNodeClick = ({ node, data, keys }) => {
  601. nodePid.value = data.primaryKeyId ? data.primaryKeyId : data.pKeyId
  602. //获取父节点名称
  603. let parentName = ''
  604. if (node?.parent?.data) {
  605. parentName = node.parent.data.title ?? ''
  606. }
  607. data.parentName = parentName
  608. //设置相关数据
  609. treeItem.value = getObjValue(data)
  610. setStore('project-wbs-tree-expand-keys', keys)
  611. treeExpandKeys.value = getArrValue(keys)
  612. //获取节点详情
  613. getTreeDetail()
  614. getInfoTableData()
  615. }
  616. //获取节点详情
  617. const treeInfo = ref({})
  618. const getTreeDetail = async () => {
  619. const { id, parentName } = treeItem.value
  620. const { data } = await mainApi.detail({
  621. id,
  622. wbsId: wbsId.value,
  623. projectId: projectInfo.value.id,
  624. })
  625. const res = getObjValue(data)
  626. res.parentName = parentName
  627. treeInfo.value = res
  628. nodeTableData.value = [res]
  629. }
  630. //当前项目信息表
  631. const infoTableLoading = ref(false)
  632. const infoTableColumn = ref([
  633. { key: 'tableName', name: '表单名称' },
  634. { key: 'elementTotal', name: '字段总量', align: 'center', width: 80 },
  635. { key: 'fillRate', name: '填报率', align: 'center', width: 80 },
  636. { key: 'tableType', name: '表单类型', align: 'center', width: 100 },
  637. { key: 'tableOwner', name: '所属方', align: 'center', width: 100 },
  638. { key: 'action', name: '操作', align: 'center', width: 160 },
  639. ])
  640. const infoTableData = ref([])
  641. const getInfoTableData = async () => {
  642. const { id } = treeItem.value
  643. infoTableLoading.value = true
  644. const { data } = await mainApi.findNodeTableByCondition({
  645. parentId: id,
  646. wbsId: wbsId.value,
  647. projectId: projectInfo.value.id,
  648. })
  649. infoTableData.value = getArrValue(data)
  650. infoTableLoading.value = false
  651. }
  652. //当前项目信息表删除
  653. const delInfoTableRow = async ({ item }, resolve) => {
  654. const { isRes } = await mainApi.removeTableByCondition({
  655. id: item.id,
  656. wbsId: wbsId.value,
  657. projectId: projectInfo.value.id,
  658. })
  659. resolve() //关闭弹窗
  660. if (!isRes) return
  661. window.$message.success('删除成功')
  662. getInfoTableData().then()
  663. }
  664. //表单设置
  665. const isFormSet = ref(true)
  666. const infoTableColumn1 = ref([
  667. { key: 'tableName', name: '表单名称' },
  668. { key: 'tableType', name: '表单类型', align: 'center', width: 80 },
  669. { key: 'fillRate', name: '填报率', align: 'center', width: 80 },
  670. { key: 'isLinkTable', name: '关联清表', align: 'center', width: 80 },
  671. { key: 'tableOwner', name: '所属方', align: 'center', width: 100 },
  672. {
  673. key: 'action',
  674. name: '操作',
  675. align: 'center',
  676. fixed: 'right',
  677. },
  678. ])
  679. const setIsFormSetValue = () => {
  680. isFormSet.value = !isFormSet.value
  681. if (isFormSet.value) {
  682. getTreeDetail()
  683. }
  684. getInfoTableData()
  685. }
  686. //数据同步按钮菜单
  687. const dataSyncMenu = [
  688. { key: 'jdSync', name: '节点参数同步', load: false },
  689. { key: 'dqSync', name: '电签同步', load: false },
  690. { key: 'gsSync', name: '公式同步', load: false },
  691. ]
  692. const dataSyncMenuClick = (item) => {
  693. let pid = treeItem.value.primaryKeyId
  694. ? treeItem.value.primaryKeyId
  695. : treeItem.value.pKeyId
  696. const { key } = item
  697. if (key === 'jdSync') {
  698. //是否同步节点参数
  699. HcFirmMsg(
  700. {
  701. text: '是否同步节点参数?',
  702. loadingText: '数据同步中...',
  703. },
  704. async (resolve) => {
  705. const { isRes } = await mainApi.syncNodeParam({
  706. projectId: projectInfo.value.id,
  707. pKeyId: pid,
  708. })
  709. resolve() //关闭弹窗
  710. if (!isRes) return
  711. window.$message.success('同步成功')
  712. },
  713. )
  714. } else if (key === 'dqSync') {
  715. //是否同步电签
  716. HcFirmMsg(
  717. {
  718. text: '是否同步电签?',
  719. loadingText: '数据同步中...',
  720. },
  721. async (resolve) => {
  722. const { isRes } = await mainApi.syncProjecteVisa({
  723. projectId: projectInfo.value.id,
  724. pKeyId: pid,
  725. })
  726. resolve() //关闭弹窗
  727. if (!isRes) return
  728. window.$message.success('同步成功')
  729. },
  730. )
  731. } else if (key === 'gsSync') {
  732. window.$message.success('暂无接口')
  733. }
  734. }
  735. // 关联清表
  736. const isAssociationShow = ref(false)
  737. const associationInfo = ref({})
  738. const associationList = async (item) => {
  739. associationInfo.value = item
  740. await nextTick()
  741. isAssociationShow.value = true
  742. }
  743. //编辑元素
  744. const isEditElementShow = ref(false)
  745. const editElementInfo = ref({})
  746. const editElementData = ref({})
  747. const editElementLoading = ref(false)
  748. const editElement = async (row) => {
  749. row.editElementLoading = true
  750. const { code, data } = await excelApi.getExcelHtml({ pkeyId: row.pkeyId })
  751. if (code !== 200 || isNullES(data)) {
  752. editElementLoading.value = false
  753. window?.$message.warning('表单异常,请联系管理员')
  754. return
  755. }
  756. row.editElementLoading = false
  757. editElementInfo.value = row
  758. editElementData.value = {
  759. pid: projectInfo.value.id,
  760. wbsid: wbsId.value,
  761. nodeid: treeItem.value.id,
  762. }
  763. await nextTick()
  764. isEditElementShow.value = true
  765. }
  766. //调整表单
  767. const isAdjustExcelShow = ref(false)
  768. const adjustExcelInfo = ref({})
  769. const adjustExcelClick = async (row) => {
  770. const { pkeyId, excelId } = row
  771. if (isNullES(pkeyId) || isNullES(excelId)) {
  772. window?.$message.warning('表单值异常,请联系管理员')
  773. return
  774. }
  775. row.adjustExcelLoading = true
  776. const { code, data } = await excelApi.getExcelHtml({ pkeyId })
  777. if (code !== 200 || isNullES(data)) {
  778. row.adjustExcelLoading = false
  779. window?.$message.warning('表单异常,请联系管理员')
  780. return
  781. }
  782. adjustExcelInfo.value = deepClone(row)
  783. row.adjustExcelLoading = false
  784. await nextTick()
  785. isAdjustExcelShow.value = true
  786. }
  787. //编辑元素里的跳转页面
  788. const editElementToPage = async (name) => {
  789. const row = deepClone(editElementInfo.value)
  790. //表单调整
  791. if (name === 'adjustment') {
  792. adjustExcelInfo.value = deepClone(row)
  793. await nextTick()
  794. isAdjustExcelShow.value = true
  795. }
  796. //公式配置
  797. if (name === 'formula') {
  798. console.log('还没做')
  799. }
  800. }
  801. //编辑元素公式
  802. const elementFormulasName = ref('')
  803. const elementFormulasObj = ref({})
  804. const elementFormulasShow = ref(false)
  805. const elementFormulasClick = async (row) => {
  806. elementFormulasObj.value = row
  807. elementFormulasName.value = row.tableName + ' 元素公式'
  808. elementFormulasShow.value = true
  809. formulaTableLoading.value = true
  810. const { data } = await wbsTreeApi.selectFormElements({
  811. id: row.pkeyId,
  812. type: 0,
  813. })
  814. const arr = getArrValue(data)
  815. formulaTableData.value = arr
  816. formulaTableList.value = deepClone(arr)
  817. formulaTableLoading.value = false
  818. }
  819. //元素公式列表
  820. const formulaTableLoading = ref(false)
  821. const formulaTableColumn = [
  822. { key: 'eName', name: '字段信息' },
  823. { key: 'action', name: '操作', width: 160, align: 'center' },
  824. ]
  825. const formulaTableData = ref([])
  826. const formulaTableList = ref([])
  827. // 搜索元素公式
  828. const formulaInput = ref('')
  829. const searchFormulaClick = () => {
  830. const arr = formulaTableList.value
  831. formulaTableData.value = arr.filter(({ eName }) => {
  832. return eName.indexOf(formulaInput.value) > -1
  833. })
  834. }
  835. //编辑元素公式关闭
  836. const elementFormulasClose = () => {
  837. elementFormulasShow.value = false
  838. formulaTableLoading.value = false
  839. elementFormulasName.value = ''
  840. formulaTableData.value = []
  841. formulaTableList.value = []
  842. }
  843. //编辑公式
  844. const isEditFormulaShow = ref(false)
  845. const editFormulaData = ref({})
  846. //全局公式,10
  847. const toFormulaGlobal = async (row) => {
  848. elementFormulasClose()
  849. const formulasObj = elementFormulasObj.value
  850. formulasObj.hasPartFormula = row.hasPartFormula
  851. editFormulaData.value = {
  852. node: formulasObj,
  853. pid: projectInfo.value.id,
  854. wbsId: wbsId.value,
  855. nodeId: treeItem.value.id,
  856. eleId: row.id,
  857. eleType: false,
  858. tableType: true,
  859. globalType: 10,
  860. }
  861. await nextTick()
  862. isEditFormulaShow.value = true
  863. }
  864. //节点公式,20
  865. const toFormulaNodes = async (row) => {
  866. elementFormulasClose()
  867. const formulasObj = elementFormulasObj.value
  868. const title = `${formulasObj.tableName ? formulasObj.tableName + ' 元素公式(元素库)' : '元素公式(元素库)'}`
  869. editFormulaData.value = {
  870. node: treeItem.value,
  871. pid: projectInfo.value.id,
  872. wbsId: wbsId.value,
  873. nodeId: treeItem.value.id,
  874. eleId: row.id,
  875. tableType: false,
  876. globalType: 20,
  877. cardTitle: title,
  878. }
  879. await nextTick()
  880. isEditFormulaShow.value = true
  881. }
  882. //公式操作完成
  883. const editFormulaFinish = () => {
  884. isEditFormulaShow.value = false
  885. editFormulaData.value = {}
  886. }
  887. //离开了当前页面
  888. onDeactivated(() => {
  889. isAdjustExcelShow.value = false
  890. })
  891. //节点参数
  892. const nodeParamShow = ref(false)
  893. const nodeParamClose = () => {
  894. nodeParamShow.value = false
  895. }
  896. const nodeParamClick = async () => {
  897. const { id } = treeItem.value
  898. if (!id) {
  899. window?.$message.warning('请先选择节点')
  900. return
  901. }
  902. await nextTick()
  903. nodeParamShow.value = true
  904. }
  905. //独立表单库
  906. const independentShow = ref(false)
  907. const independentClose = () => {
  908. independentShow.value = false
  909. }
  910. const toIndependent = () => {
  911. independentShow.value = true
  912. }
  913. //归档文件时间
  914. const isArchiveShow = ref(false)
  915. const archiveClick = async () => {
  916. await nextTick()
  917. isArchiveShow.value = true
  918. }
  919. //编辑元素表单
  920. const editEleShow = ref(false)
  921. const editClose = () => {
  922. editEleShow.value = false
  923. }
  924. const editRowClick = async (row) => {
  925. await nextTick()
  926. editEleShow.value = true
  927. }
  928. // 元素表排序
  929. const tableSortShow = ref(false)
  930. const sortClick = async () => {
  931. await nextTick()
  932. tableSortShow.value = true
  933. }
  934. const tableSortShowClose = () => {
  935. tableSortShow.value = false
  936. getInfoTableData()
  937. }
  938. //预览
  939. const previewShow = ref(false)
  940. const previewInfo = ref({})
  941. const previewClick = async (row) => {
  942. await nextTick()
  943. previewShow.value = true
  944. previewInfo.value = row
  945. }
  946. //创建新的元素表
  947. const isCreateShow = ref(false)
  948. const modalTitle = ref('创建新的元素表')
  949. const isAddType = ref(true)
  950. const createClose = async () => {
  951. isCreateShow.value = false
  952. getInfoTableData()
  953. }
  954. const initTableName = ref('')
  955. const initTableId = ref('')
  956. const eKey = ref('')
  957. const tableId = ref('')
  958. const handleEdit = async (row) => {
  959. await nextTick()
  960. isCreateShow.value = true
  961. isAddType.value = false
  962. modalTitle.value = row.tableName + '元素编辑'
  963. isAddType.value = false
  964. tableId.value = row.pkeyId
  965. initTableName.value = row.initTableName
  966. initTableId.value = row.initTableId
  967. eKey.value = row.ekey
  968. }
  969. //隐藏表单
  970. const hideClick = async (row) => {
  971. //隐藏按钮
  972. const { code, error } = await wbsTreeApi.updateStatus({
  973. pKeyId: row.pkeyId,
  974. })
  975. if (!error && code === 200) {
  976. if (row.status == 0) {
  977. row.status = 1
  978. } else {
  979. row.status = 0
  980. }
  981. }
  982. }
  983. //表单同步
  984. const syncTable = async (row) => {
  985. row.syncTableLoading = true
  986. const { code, error } = await wbsTreeApi.syncCurrentFormInProject({
  987. pKeyId: row.pkeyId,
  988. })
  989. row.syncTableLoading = false
  990. if (!error && code === 200) {
  991. window?.$message.success('操作成功')
  992. }
  993. }
  994. //关联节点
  995. const isAllocateShow = ref(false)
  996. const allocateWbsInfo = ref({})
  997. const linkNodeClick = async (row) => {
  998. allocateWbsInfo.value = row
  999. await nextTick()
  1000. isAllocateShow.value = true
  1001. }
  1002. </script>
  1003. <style lang="scss" scoped>
  1004. .hc-project-wbs-tree {
  1005. position: relative;
  1006. background: #ececec;
  1007. border-radius: 4px;
  1008. height: 100%;
  1009. flex-direction: column;
  1010. overflow: hidden;
  1011. .header {
  1012. color: white;
  1013. background: #54565a;
  1014. padding: 10px 14px;
  1015. flex-shrink: 0;
  1016. .name {
  1017. white-space: nowrap;
  1018. overflow: hidden;
  1019. text-overflow: ellipsis;
  1020. }
  1021. }
  1022. .body {
  1023. flex: 1;
  1024. flex-basis: auto;
  1025. position: relative;
  1026. }
  1027. }
  1028. </style>
  1029. <style lang="scss">
  1030. .hc-project-wbs-tree .body {
  1031. .el-card.hc-card-box {
  1032. --el-card-padding: 12px;
  1033. --el-card-border-radius: 5px;
  1034. }
  1035. .hc-page-split-content {
  1036. position: relative;
  1037. .body-top {
  1038. position: relative;
  1039. height: 129.5px;
  1040. }
  1041. .body-content {
  1042. position: relative;
  1043. margin-top: 10px;
  1044. height: calc(100% - 129.5px);
  1045. }
  1046. }
  1047. }
  1048. </style>