systemUnit.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. <!-- -->
  2. <template>
  3. <div style="height: 100%" class="flexStar">
  4. <div class="boxswai" style="width: 26%; padding-left: 0px">
  5. <div class="boxnei" style="display: flex; flex-direction: column">
  6. <div style="overflow: auto; flex: 1;height:500px">
  7. <el-tree
  8. v-if="ishowTree"
  9. lazy :props="defaultProps" @node-click="getNodeDetail" :load="loadNode" :expand-on-click-node="false"
  10. highlight-current
  11. node-key="id"
  12. ref="tree"
  13. :default-expanded-keys="defaultExpandedKeys"
  14. :data="treeData">
  15. <span
  16. class="custom-tree-node"
  17. :class="data.moreShow?'show':''"
  18. slot-scope="{ node, data }"
  19. @mouseleave="mouseout(data)"
  20. >
  21. <div class="pd-r-20">
  22. {{ node.label }}
  23. <div class="normal-black">
  24. <div >
  25. <el-link :underline="false">
  26. <i
  27. class="el-icon-menu "
  28. @click="showMenu($event,data, node)"
  29. ></i>
  30. </el-link>
  31. <ul
  32. v-show="menuvisible"
  33. :style="{ left: menuleft + 'px', top: menutop + 'px' }"
  34. class="contextmenu"
  35. >
  36. <li v-for="item in menusData" :key="item" @click="menuClick($event,item,data,node)" >
  37. <i :class="item.icon"></i>{{item.label}}
  38. </li>
  39. </ul>
  40. </div>
  41. </div>
  42. </div>
  43. </span>
  44. </el-tree>
  45. </div>
  46. </div>
  47. </div>
  48. <div
  49. class="boxswai"
  50. style="width: 74%; padding-left: 0px; padding-right: 0px"
  51. >
  52. <div class="boxnei">
  53. <h4 class="mg-b-10">节点信息</h4>
  54. <form class="form-horizontal">
  55. <table class="table-form" style="width: 100%;">
  56. <tbody>
  57. <tr>
  58. <td class="tit" width="10%">节点编码:</td>
  59. <td id="code">{{ nodeDetail.nodeCode||'' }}</td>
  60. <td class="tit" width="10%">节点名称:</td>
  61. <td id="name">{{ nodeDetail.nodeName||'' }}</td>
  62. <td class="tit" width="10%">节点类型:</td>
  63. <td id="nodeType">{{nodeDetail.nodeTypeName||""}}</td>
  64. </tr>
  65. <tr>
  66. <td class="tit" width="10%">工程类型:</td>
  67. <td id="workType">{{ nodeDetail.engineeringTypeName||'' }}</td>
  68. <td class="tit" width="10%" >备注</td>
  69. <td id="nodeType" colspan="4">{{nodeDetail.remarks||""}}</td>
  70. </tr>
  71. </tbody>
  72. </table>
  73. </form>
  74. <h4 class="mg-b-10 mg-t-20">下级节点列表</h4>
  75. <div class="tableclass">
  76. <el-table
  77. :data="tableData"
  78. border
  79. height="650"
  80. style="width: 100%">
  81. <el-table-column
  82. prop="nodeCode"
  83. label="节点编号"
  84. width="180">
  85. </el-table-column>
  86. <el-table-column
  87. prop="nodeName"
  88. label="节点名称"
  89. >
  90. </el-table-column>
  91. <el-table-column
  92. width="180"
  93. prop="nodeName"
  94. label="节点类型">
  95. </el-table-column>
  96. <el-table-column
  97. width="180"
  98. prop="engineeringTypeName"
  99. label="工程类型">
  100. </el-table-column>
  101. </el-table>
  102. </div>
  103. </div>
  104. </div>
  105. <!-- 新增编辑节点 -->
  106. <el-dialog
  107. title="节点"
  108. :visible.sync="adddialogVisible"
  109. width="30%"
  110. append-to-body
  111. :before-close="handleAddClose">
  112. <el-form label-position="left" label-width="80px" :model="addForm" ref="ruleForm" :rules="addFormrules">
  113. <el-form-item label="节点编码" prop="nodeCode">
  114. <el-input v-model="addForm.nodeCode"></el-input>
  115. </el-form-item>
  116. <el-form-item label="节点名称" prop="nodeName">
  117. <el-input v-model="addForm.nodeName"></el-input>
  118. </el-form-item>
  119. <el-form-item label="节点类型" prop="nodeType">
  120. <el-select v-model="addForm.nodeType" placeholder="请选择节点类型" style="width: 100%;">
  121. <el-option
  122. v-for="item in dataTypeList"
  123. :key="item.id"
  124. :label="item.dictValue"
  125. :value="item.dictKey"
  126. ></el-option>
  127. </el-select>
  128. </el-form-item>
  129. <el-form-item label="工程类型" prop="engineeringTypeName">
  130. <el-input v-model="addForm.engineeringTypeName" disabled></el-input>
  131. </el-form-item>
  132. <el-form-item label="备注" prop="remarks">
  133. <el-input v-model="addForm.remarks"></el-input>
  134. </el-form-item>
  135. </el-form>
  136. <span slot="footer" class="dialog-footer">
  137. <el-button @click="adddialogVisible = false">取 消</el-button>
  138. <el-button type="primary" @click="saveAddform" :loading="saveNodeLoading">确 定</el-button>
  139. </span>
  140. </el-dialog>
  141. <!-- 排序弹窗 -->
  142. <el-dialog
  143. title="节点排序"
  144. :visible.sync="sortTag"
  145. append-to-body
  146. width="30%"
  147. :before-close="handleSortClose">
  148. <ManualSorting
  149. v-if="sortTag2"
  150. @bianhua='bianhua()'
  151. :sort='sort'
  152. />
  153. <span slot="footer" class="dialog-footer">
  154. <el-button @click="sortTag = false,sortTag2=false">取 消</el-button>
  155. <el-button type="primary" @click="editSort()" >确 定</el-button>
  156. </span>
  157. </el-dialog>
  158. </div>
  159. </template>
  160. <script >
  161. import ManualSorting from '@/components/WbsTree/ManualSorting'
  162. import { getLazyTree,add,getDetail,getChildList,updateNode,removeNode,getSameList,sortNode,getEngineeringTypeName } from "@/api/measure/template.js";
  163. import { getDictionary } from "@/api/system/dict";
  164. import {isObjectEmpty} from "@/util/util";
  165. export default {
  166. components:{
  167. ManualSorting
  168. },
  169. data() {
  170. return {
  171. ishowTree:true,
  172. treeData: [{
  173. label: '系统计量单元',
  174. children: [
  175. {
  176. label: '总则',
  177. children: [{
  178. label: '保险费'
  179. }]
  180. },
  181. {
  182. label: '路基工程',
  183. children: [{
  184. label: '清理与掘除'
  185. }]
  186. },
  187. {
  188. label: '路面工程',
  189. children: [{
  190. label: '底基层'
  191. }]
  192. },
  193. ]
  194. }],
  195. defaultExpandedKeys:[],
  196. defaultProps: {
  197. children: 'children',
  198. label: 'nodeName',
  199. isLeaf: 'notExsitChild'
  200. },
  201. menuvisible:false,//右键菜单
  202. menuleft:20,
  203. menutop:0,
  204. menusData:[
  205. {icon: 'el-icon-plus', label: '新增节点', key: "add"},
  206. {icon: 'el-icon-s-promotion', label: '编辑节点', key: "edit"},
  207. {icon: 'el-icon-sort', label: '排序节点', key: "sort"},
  208. {icon: 'el-icon-delete', label: '删除节点', key: "del"},
  209. ],//树组件操作菜单
  210. menuKey:'',
  211. adddialogVisible:false,//新增节点
  212. addForm:{},
  213. nodeDetail:{},
  214. addFormrules:{
  215. nodeName: [
  216. { required: true, message: '请输入节点名称', trigger: 'blur' },
  217. ],
  218. engineeringType: [
  219. { required: true, message: '请输入工程类型', trigger: 'blur' }
  220. ]
  221. },
  222. sortTag2: false,
  223. sortTag: false,
  224. sort: [],
  225. tableData:[],
  226. id:'',//模板ID
  227. dataTypeList:[],//节点类型
  228. saveNodeLoading:false
  229. };
  230. },
  231. created () {
  232. this.init();
  233. },
  234. methods: {
  235. init(){
  236. const {id} = this.$route.query;
  237. this.id = id
  238. this.getNodeTypelist()
  239. },
  240. //获取节点类型
  241. getNodeTypelist () {
  242. if (this.dataTypeList.length > 1) {
  243. return;
  244. }
  245. getDictionary({
  246. code: 'meter_node_type'
  247. }).then((res) => {
  248. res.data.data.forEach(element => {
  249. element.dictKey = Number(element.dictKey)
  250. });
  251. this.dataTypeList = res.data.data;
  252. })
  253. },
  254. //获取节点类型对应的名称
  255. getNodeTypeName(type){
  256. this.dataTypeList.forEach((ele)=>{
  257. if(ele.dictKey==type){
  258. this.nodeDetail.nodeTypeName=ele.dictValue
  259. }
  260. })
  261. },
  262. loadNode (node, resolve) {
  263. let pid = 0;
  264. if (node.level != 0) {
  265. pid = node.data.id
  266. }
  267. getLazyTree({
  268. templateId:this.id,
  269. id:pid
  270. }).then((res) => {
  271. let arr = [];
  272. if (Array.isArray(res.data.data)) {
  273. arr = res.data.data;
  274. }
  275. return resolve(arr);
  276. })
  277. },
  278. async getLazytree () {//冲洗获取wbs树
  279. const { data: res } = await getLazyTree({id:0,templateId:this.id})
  280. //console.log(res);
  281. if (res.code == 200) {
  282. this.treeData = res.data
  283. }
  284. },
  285. handleNodeClick(data) {
  286. console.log(data);
  287. this.curTreeData=data
  288. },
  289. //树形控件菜单相关方法
  290. mouseout(){
  291. this.menuvisible=false
  292. },
  293. //展示菜单
  294. showMenu(e,data,node){
  295. e.preventDefault();
  296. console.log(e,'e');
  297. var x = e.pageX; //这个应该是相对于整个浏览器页面的x坐标,左上角为坐标原点(0,0)
  298. var y = e.pageY; //这个应该是相对于整个浏览器页面的y坐标,左上角为坐标原点(0,0)
  299. this.menutop = y;
  300. this.menuleft = x;
  301. this.menuvisible=true
  302. },
  303. getEngineeringTypeNameById(id){
  304. getEngineeringTypeName({id}).then((res)=>{
  305. console.log(res.data.data,'data');
  306. if(!isObjectEmpty(res.data.data)){
  307. console.log(111111);
  308. this.addForm.engineeringTypeName=res.data.data||''
  309. }else{
  310. this.addForm.engineeringTypeName=''
  311. }
  312. })
  313. },
  314. menuClick(e,item,data,node){
  315. this.menuKey=''
  316. e.preventDefault();
  317. if(item.key==='add'){
  318. console.log('新增');
  319. this.menuKey='add'
  320. this.adddialogVisible=true
  321. this.getEngineeringTypeNameById(data.id)
  322. this.addForm.engineeringTypeName=node.parent.data.engineeringTypeName
  323. this.addNodeHandle()
  324. }
  325. else if(item.key==='edit'){
  326. console.log('编辑',data,node);
  327. this.menuKey='edit'
  328. this.adddialogVisible=true
  329. this.editNodeHandle()
  330. }
  331. else if(item.key==='del'){
  332. this.menuKey='del'
  333. console.log('删除');
  334. this.deleNode(data,node)
  335. }
  336. else if(item.key==='sort'){
  337. this.menuKey='sort'
  338. console.log('排序');
  339. this.paixuMD(data,node)
  340. }
  341. },
  342. editNodeHandle(){
  343. if(!this.curTreeData.id || !this.curTreeNode.id){
  344. this.$message({
  345. type: "warning",
  346. message: "请先选择节点"
  347. })
  348. return;
  349. }
  350. this.addForm=this.curTreeData
  351. },
  352. addNodeHandle(){
  353. if(!this.curTreeData.id ){
  354. this.$message({
  355. type: "warning",
  356. message: "请先选择节点"
  357. })
  358. return;
  359. }
  360. },
  361. handleAddClose(){
  362. this.adddialogVisible=false
  363. },
  364. saveAddform(){
  365. //新增节点确定
  366. this.adddialogVisible=false
  367. if( this.menuKey==='add'){
  368. this.$refs.ruleForm.validate(async (valid) => {
  369. if(valid){
  370. this.saveNodeLoading=true
  371. this.addForm.parentId=this.curTreeData.id
  372. this.addForm.ancestor=this.curTreeData.ancestor
  373. this.addForm.templateId=this.curTreeData.templateId
  374. let subobj=this.addForm
  375. add(subobj).then(() => {
  376. this.saveNodeLoading=false
  377. this.updateTreeNewNode();
  378. this.dialogVisible = false;
  379. this.addForm={}
  380. this.$message({
  381. type: "success",
  382. message: "新增成功!"
  383. });
  384. })
  385. }
  386. })
  387. }
  388. if(this.menuKey==='edit'){
  389. let subobj=this.addForm
  390. updateNode(subobj).then(() => {
  391. this.saveNodeLoading=false
  392. this.updateTreeNewNode();
  393. this.dialogVisible = false;
  394. this.addForm={}
  395. this.$message({
  396. type: "success",
  397. message: "修改成功!"
  398. });
  399. getDetail(subobj.id).then((res) => {
  400. this.nodeDetail = Object.assign({}, res.data.data);
  401. this.getNodeTypeName(this.nodeDetail.nodeType)
  402. })
  403. })
  404. }
  405. },
  406. getNodeDetail (data, node) {
  407. let parentName = '';
  408. if (node.parent.data) {
  409. parentName = node.parent.data.title;
  410. }
  411. this.curTreeData = data;
  412. this.curTreeNode = node;
  413. this.curTreeData.parentName = parentName;
  414. getDetail(data.id).then((res) => {
  415. res.data.data.parentName = parentName;
  416. this.tableData = [res.data.data];
  417. this.nodeDetail = Object.assign({}, res.data.data);
  418. this.getNodeTypeName(this.nodeDetail.nodeType)
  419. })
  420. getChildList({id: this.curTreeData.id}).then((res)=>{
  421. this.tableData=res.data.data
  422. })
  423. // this.updateNodeTable();
  424. //获取节点展开路径
  425. // this.getExpandedKeys(node);
  426. },
  427. updateTreeNewNode () {
  428. let detail = (this.nodeDetail.parentId ? this.nodeDetail : this.curTreeData);
  429. getLazyTree({id:detail.id,templateId:this.id}).then((res) => {
  430. let node = this.$refs.tree.getNode(detail.parentId);
  431. // node.isLeaf = false;
  432. // node.isLeafByUser = false;
  433. //console.log(node)
  434. this.$refs.tree.updateKeyChildren(detail.id, res.data.data)
  435. })
  436. },
  437. //排序
  438. handleSortClose(){
  439. this.sortdialogVisible=false
  440. },
  441. bianhua () {
  442. this.sortTag2 = false
  443. this.$nextTick(() => {
  444. this.sortTag2 = true
  445. })
  446. },
  447. editSort () {//修改排序
  448. let sortArr = this.sort, newArr = []
  449. for (let i = 0; i < sortArr.length; i++) {
  450. newArr.push({
  451. id: sortArr[i].id,
  452. nodeName: sortArr[i].nodeName
  453. })
  454. }
  455. this.wbsTreeSort(newArr)
  456. },
  457. ids() {
  458. let ids = [];
  459. this.sort.forEach(ele => {
  460. ids.push(ele.id);
  461. });
  462. return ids.join(",");
  463. },
  464. async wbsTreeSort () {//表单排序
  465. const { data: res } = await sortNode({ids:this.ids()})
  466. //console.log(res);
  467. if (res.code == 200) {
  468. this.sortTag = false
  469. this.sortTag2 = false
  470. this.ishowTree=false
  471. setTimeout(() => {
  472. this.ishowTree=true
  473. }, 100);
  474. }
  475. },
  476. paixuMD (data) {
  477. this.sortTag = true
  478. this.sortTag2 = true
  479. this.findWbsTreeSameLevel(data.parentId)
  480. },
  481. async findWbsTreeSameLevel (parentId) {//查询当前节点的同级节点
  482. const { data: res } = await getSameList({ parentId })
  483. //console.log(res);
  484. if (res.code === 200) {
  485. this.sort = res.data
  486. }
  487. },
  488. deleNode(data, node) {
  489. this.$confirm(
  490. "此操作将删除节点【" + data.nodeName + "】, 是否继续?",
  491. "提示",
  492. {
  493. confirmButtonText: "确定",
  494. cancelButtonText: "取消",
  495. type: "warning",
  496. }
  497. )
  498. .then(() => {
  499. removeNode(data.id).then(() => {
  500. this.$refs.tree.remove(node);
  501. this.$message({
  502. type: "success",
  503. message: "删除成功!",
  504. });
  505. });
  506. })
  507. .catch(() => {});
  508. },
  509. },
  510. }
  511. </script>
  512. <style lang='scss' scoped>
  513. .custom-tree-node {
  514. .normal-black {
  515. display: none;
  516. }
  517. &:hover {
  518. .normal-black {
  519. display: inline-block;
  520. }
  521. }
  522. &.show .normal-black {
  523. display: inline-block;
  524. }
  525. }
  526. // 树形控件菜单样式
  527. .contextmenu {
  528. margin: 0;
  529. background: #fff;
  530. z-index: 1000;
  531. position: fixed; //关键样式设置固定定位
  532. list-style-type: none;
  533. padding: 5px 0;
  534. border-radius: 4px;
  535. font-size: 12px;
  536. font-weight: 400;
  537. color: #333;
  538. box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
  539. }
  540. .contextmenu li {
  541. margin: 0;
  542. padding: 7px 16px;
  543. cursor: pointer;
  544. }
  545. .contextmenu li:hover {
  546. background: #eee;
  547. }
  548. .form-horizontal .table-form, .form-horizontal .table-form td {
  549. border: 1px solid #ddd;
  550. background-color: #fdfdfd;
  551. font-size: 14px;
  552. padding: 10px;
  553. color: #606266
  554. }
  555. </style>