index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. <template>
  2. <div class="boxswai">
  3. <div class="boxnei">
  4. <el-row
  5. :gutter="20"
  6. style="height:100%;"
  7. >
  8. <el-col
  9. :span="5"
  10. style="height:99%;"
  11. >
  12. <div
  13. style="fontSize:18px; font-weight: 900;"
  14. class="marbottom5"
  15. >元素识别</div>
  16. <div style="height:98%;overflow: auto;width:auto;">
  17. <div class="flex">
  18. <el-input
  19. size="small"
  20. placeholder="输入关键字搜索"
  21. clearable
  22. @clear="allTreeShow = false"
  23. v-model="filterText">
  24. </el-input>
  25. <el-button size="small" class="mg-l-10" @click="treeFilter">搜索</el-button>
  26. </div>
  27. <el-tree
  28. :data="treeData"
  29. :props="treeProps"
  30. @node-click="handleNodeClick"
  31. :load="loadNode"
  32. :expand-on-click-node="false"
  33. lazy
  34. v-show="!allTreeShow"
  35. ></el-tree>
  36. <el-tree
  37. style="width:100%;"
  38. ref="treeall"
  39. v-loading="treeloading"
  40. :data="allTreeData"
  41. :props="treeProps"
  42. @node-click="handleNodeClick"
  43. node-key="id"
  44. :expand-on-click-node="false"
  45. :filter-node-method="filterNode"
  46. v-show="allTreeShow"
  47. >
  48. </el-tree>
  49. </div>
  50. </el-col>
  51. <el-col
  52. :span="19"
  53. style="height:98%;"
  54. >
  55. <div v-if="addElementForm.deptName==''">表名称</div>
  56. <div v-else>{{addElementForm.deptName}}</div>
  57. <el-row
  58. class="martop20"
  59. :gutter="20"
  60. style="height:96%;"
  61. >
  62. <el-col
  63. :span="16"
  64. style="overflow:auto;height:100%;border:1px solid black; border-radius: 4px;box-sizing: border-box;padding: 10px 10px;"
  65. >
  66. <div
  67. class="parent"
  68. id='parent'
  69. >
  70. </div>
  71. </el-col>
  72. <el-col
  73. :span="8"
  74. style="overflow:auto;height:100%;"
  75. >
  76. <div class="flexBetween flexItemsC">
  77. <el-button
  78. type="info"
  79. size="mini"
  80. :disabled="from.id==''"
  81. @click="automaticRecognition"
  82. >自动识别</el-button>
  83. <div
  84. class="el-icon-plus"
  85. @click="pushTableData"
  86. style="width:16px;height:16px;backgroundColor:#1DD81D;color:#fff;cursor: pointer;"
  87. ></div>
  88. </div>
  89. <el-table
  90. class="martop20"
  91. :data="tableData"
  92. border
  93. style="width: 100%"
  94. >
  95. <el-table-column
  96. type="index"
  97. label="坐标"
  98. >
  99. </el-table-column>
  100. <el-table-column
  101. prop="eName"
  102. label="元素名称"
  103. >
  104. <template slot-scope="scope">
  105. <el-input
  106. v-model="scope.row.eName"
  107. placeholder="请输入内容"
  108. ></el-input>
  109. </template>
  110. </el-table-column>
  111. <el-table-column
  112. prop="eType"
  113. label="数据类型"
  114. >
  115. <template slot-scope="scope">
  116. <el-select
  117. v-model="scope.row.eType"
  118. placeholder="请选择"
  119. >
  120. <el-option
  121. v-for="item in dataType"
  122. :key="item.dictKey"
  123. :label="item.dictValue"
  124. :value="item.dictKey"
  125. >
  126. </el-option>
  127. </el-select>
  128. </template>
  129. </el-table-column>
  130. <el-table-column
  131. prop="eAllowDeviation"
  132. label="允许偏差值"
  133. >
  134. <template slot-scope="scope">
  135. <el-input
  136. v-model="scope.row.eAllowDeviation"
  137. placeholder="请输入内容"
  138. ></el-input>
  139. </template>
  140. </el-table-column>
  141. <el-table-column label="操作">
  142. <template slot-scope="scope">
  143. <el-link
  144. type="danger"
  145. @click="deleteTableData(scope.$index)"
  146. >删除</el-link>
  147. </template>
  148. </el-table-column>
  149. </el-table>
  150. <el-button
  151. type="success"
  152. class="martop20 dingwei"
  153. @click="establish()"
  154. :disabled="from.id==''"
  155. >关联WBS并创建元素</el-button>
  156. </el-col>
  157. </el-row>
  158. </el-col>
  159. </el-row>
  160. <!-- 关联公共WBS模板 -->
  161. <el-dialog
  162. title="关联公共WBS模板"
  163. class="excelBox"
  164. :visible.sync="AssociatedPublicTap"
  165. modal-append-to-body
  166. append-to-body
  167. :before-close="AssociatedPublicClose"
  168. >
  169. <el-row :gutter="20">
  170. <el-col :span="12">
  171. <el-select
  172. style="width:100%;"
  173. v-model="GLExcelFrom.name"
  174. placeholder="请选择"
  175. @change="changetherr()"
  176. >
  177. <el-option
  178. v-for="(item,key) in GLExcelData"
  179. :key="key"
  180. :label="item.wbsName"
  181. :value="item.id"
  182. >
  183. </el-option>
  184. </el-select>
  185. <el-scrollbar style="height:50vh;">
  186. <el-tree
  187. v-if="GLExcelFromtag"
  188. @node-click="handleNodeClickExcel"
  189. ref="tree"
  190. class="filter-tree"
  191. style="margin-top:10px;"
  192. :props="GLExcelProps"
  193. :data="exceldata"
  194. :load="loadNodeTan"
  195. lazy
  196. node-key="id"
  197. accordion
  198. :show-checkbox="activeName == 'add'"
  199. :check-strictly="true"
  200. >
  201. </el-tree>
  202. </el-scrollbar>
  203. </el-col>
  204. <el-col
  205. :span="12"
  206. v-if="addElementForm.wbsId"
  207. >
  208. <el-tabs v-model="activeName" type="card" >
  209. <el-tab-pane label="关联元素表" name="link">
  210. <el-table
  211. :data="addTableData"
  212. border
  213. style="width: 100%"
  214. class="martop20"
  215. >
  216. <el-table-column
  217. prop="tableName"
  218. label="已有元素表名称"
  219. align="center"
  220. >
  221. </el-table-column>
  222. <el-table-column
  223. prop="name"
  224. label="操作"
  225. align="center"
  226. >
  227. <template slot-scope="scope">
  228. <el-button
  229. type="primary"
  230. size="mini"
  231. style="margin:0px;"
  232. @click="relationMD(scope.row,'关联')"
  233. v-show="!scope.row.checknd"
  234. :loading="scope.row.loading"
  235. >选择关联</el-button>
  236. <el-button
  237. type="danger"
  238. size="mini"
  239. style="margin:0px;"
  240. @click="relationMD(scope.row,'取消关联')"
  241. v-show="scope.row.checknd"
  242. :loading="scope.row.loading"
  243. >取消关联</el-button>
  244. </template>
  245. </el-table-column>
  246. </el-table>
  247. </el-tab-pane>
  248. <el-tab-pane label="新增元素表" name="add">
  249. <div>
  250. <div class="flexBetween martop20">
  251. <el-input
  252. v-model="addElementForm.deptName"
  253. placeholder="请输入表名"
  254. ></el-input>
  255. <el-select
  256. class="marleft10"
  257. v-model="addElementForm.tableType"
  258. placeholder="请选择表类型"
  259. >
  260. <el-option
  261. v-for="(item,index) in exceltypeData"
  262. :key="index"
  263. :label="item.dictValue"
  264. :value="item.dictKey"
  265. ></el-option>
  266. </el-select>
  267. </div>
  268. <el-select
  269. style="width:100%;"
  270. class="martop20"
  271. v-model="addElementForm.tableOwner"
  272. placeholder="请选择所属方"
  273. >
  274. <el-option
  275. v-for="(item,index) in ownerTypeList"
  276. :key="index"
  277. :label="item.dictValue"
  278. :value="item.dictKey"
  279. ></el-option>
  280. </el-select>
  281. </div>
  282. </el-tab-pane>
  283. </el-tabs>
  284. </el-col>
  285. </el-row>
  286. <span
  287. slot="footer"
  288. class="dialog-footer"
  289. style="display: flex;justify-content: center;align-items: center;"
  290. >
  291. <el-button @click="AssociatedPublicClose()">取 消</el-button>
  292. <el-button
  293. style="margin-left:30px;"
  294. type="primary"
  295. @click="saveElementMD()"
  296. >确 定</el-button>
  297. </span>
  298. </el-dialog>
  299. </div>
  300. </div>
  301. </template>
  302. <script>
  303. import { tabLazytree, getExcelHtmlCol, excelType, submitExcelRelationWbsTreeAndElement, getWbsTypeList, getLazytree,cancelRelation,saveRelation,searchNodeTables,tabLazytreeAll} from "@/api/exctab/excelmodel";
  304. import { dictionarydataType } from "@/api/exctab/editelement";
  305. import { getColByTabId } from "@/api/manager/AdjustForm";
  306. import { selectByNodeTable } from "@/api/manager/wbstree";
  307. import { getDictionary } from "@/api/system/dict";
  308. import Vue from 'vue'
  309. export default {
  310. data () {
  311. return {
  312. //#region 左侧树节点
  313. treeData: [],
  314. treeProps: {
  315. label: 'name',
  316. children: 'children',
  317. isLeaf: 'hasChildren'
  318. },
  319. //#endregion
  320. excelSrc: '',
  321. from: {
  322. id: '',
  323. },
  324. tableData: [],//外层table
  325. dataType: [],
  326. filterText:"",//搜索关键字
  327. allTreeShow:false,//是否显示整棵树
  328. treeloading:false,
  329. AssociatedPublicTap: false,
  330. //#region 弹框属性
  331. GLExcelFrom: {
  332. id: "",
  333. name: '',
  334. search: '',//搜素框舒服的值
  335. },
  336. GLExcelData: [],//
  337. allTreeData:[],
  338. GLExcelProps: {
  339. label: 'title',
  340. children: 'children',
  341. isLeaf: function (data) {
  342. if (data.hasChildren && data.isExistForm != 1) {
  343. return false
  344. } else if (data.hasChildren && data.isExistForm == 1) {
  345. return true
  346. } else {
  347. return true
  348. }
  349. }
  350. },
  351. exceldata: [],//清表模板树数据
  352. addTableData: [],//新增元素信息表
  353. exceltypeData: [],//清表类型
  354. addElement: false,
  355. GLExcelFromtag: false,
  356. addElementForm: {
  357. id: "",
  358. initTableName: "",
  359. deptName: '',
  360. tableType: '',
  361. tableOwner: '',
  362. wbsId: '',
  363. parentId: '',
  364. },
  365. //#endregion
  366. ownerTypeList: [],
  367. activeName:'link',
  368. }
  369. },
  370. methods: {
  371. //搜索树
  372. treeFilter(){
  373. if(this.filterText){
  374. this.allTreeShow = true;
  375. if(!this.allTreeData.length){
  376. this.treeloading = true;
  377. tabLazytreeAll({
  378. modeId: this.$route.params.id,
  379. name:'',
  380. }).then((res)=>{
  381. this.treeloading = false;
  382. this.allTreeData = res.data.data;
  383. this.$nextTick(()=>{
  384. this.$refs.treeall.filter(this.filterText);
  385. })
  386. })
  387. }else{
  388. this.$refs.treeall.filter(this.filterText);
  389. }
  390. }else{
  391. this.allTreeShow = false;
  392. }
  393. },
  394. filterNode(value, data) {
  395. if (!value) return true;
  396. return data.name.indexOf(value) !== -1;
  397. },
  398. //#region
  399. handleNodeClick (data) {//树节点点击事件
  400. console.log(data);
  401. if (data.fileType == 3) {
  402. this.getExcelHtmlCol(data.id)//获取excel模板
  403. if (this.dataType.length == 0) {
  404. this.dictionarydataType() //数据类型字典
  405. }
  406. this.addElement = false
  407. this.addElementForm.deptName = data.name
  408. this.from.id = data.id
  409. this.tableData = [];
  410. }
  411. },
  412. async loadNode (node, resolve) {//懒加载获取节点
  413. if (node.level === 0) {
  414. return resolve(await this.tabLazytree(this.$route.params.id, 0))
  415. }
  416. if (node.level > 0) {
  417. return resolve(await this.tabLazytree(this.$route.params.id, node.data.id))
  418. }
  419. },
  420. automaticRecognition () {//自动识别按钮
  421. this.getColByTabId()
  422. },
  423. pushTableData () {//
  424. if (this.from.id) {
  425. this.tableData.push({
  426. eName: '',
  427. eType: 1,
  428. eAllowDeviation: ''
  429. })
  430. }
  431. },
  432. deleteTableData (key) {//删除
  433. this.tableData.splice(key, 1)
  434. },
  435. async getColByTabId () {//获取字段信息
  436. const { data: res } = await getColByTabId({ tabId: this.from.id })
  437. console.log(res);
  438. if (res.code === 200) {
  439. res.data.forEach((element)=>{
  440. element.eName = element.textInfo;
  441. element.eType = 1;
  442. })
  443. this.tableData = res.data
  444. }
  445. },
  446. async getExcelHtmlCol (id) {//获取excel模板
  447. const { data: res } = await getExcelHtmlCol({ id })
  448. console.log(res);
  449. if (res.code == 200) {
  450. // let _that = this
  451. var MyComponent = await Vue.extend({
  452. data () {
  453. return {
  454. formData: {}
  455. }
  456. },
  457. template: res.data,
  458. })
  459. var component = new MyComponent().$mount()
  460. let na = document.getElementById('parent')
  461. na.innerHTML = `<div
  462. class='parent'
  463. id='parent'"
  464. ></div>`
  465. document.getElementById('parent').appendChild(component.$el);
  466. }
  467. },
  468. //#endregion
  469. //#region 关联公共WBS模板弹框
  470. establish () {//关联WBS并创建元素
  471. if(this.tableData.length == 0){
  472. this.$message({
  473. type: 'warning',
  474. message: '至少有一条元素才能创建元素表'
  475. })
  476. return;
  477. }
  478. let arr = [];
  479. this.tableData.forEach((element,index)=>{
  480. if(element.eName == ''){
  481. arr.push(index+1);
  482. }
  483. })
  484. if(arr.length > 0){
  485. this.$message({
  486. type: 'warning',
  487. message: arr.join(',')+'条的元素名称未填写'
  488. })
  489. return;
  490. }
  491. this.getWbsTypeList()
  492. this.AssociatedPublicTap = true
  493. },
  494. AssociatedPublicClose () {//关联公共WBS模板关闭事件
  495. // this.addElementForm = {
  496. // id: "",
  497. // initTableName: "",
  498. // deptName: this.addElementForm.deptName,
  499. // tableType: '',
  500. // tableOwner: '',
  501. // wbsId: '',
  502. // parentId: '',
  503. // }
  504. // this.GLExcelFrom = {
  505. // name: '',
  506. // search: ''
  507. // }
  508. // this.exceldata = []
  509. // this.addElement = false
  510. this.addTableData = []
  511. this.AssociatedPublicTap = false
  512. },
  513. async loadNodeTan (node, resolve) {//懒加载
  514. console.log(node);
  515. if (node.level === 0) {
  516. return resolve(await this.getLazytree(0));
  517. } else {
  518. return resolve(await this.getLazytree(node.data.id));
  519. }
  520. },
  521. changetherr () {//下拉框change事件
  522. this.GLExcelFromtag = false
  523. if (this.GLExcelFrom.name != "") {
  524. this.GLExcelFrom.search = ''
  525. this.exceldata = []
  526. this.addTableData = []
  527. this.addElementForm.wbsId = ''
  528. this.$nextTick(() => {
  529. this.GLExcelFromtag = true
  530. })
  531. }
  532. },
  533. addElementMD () {//新增元素信息表按钮
  534. this.excelType()
  535. this.addElement = true
  536. },
  537. async getWbsTypeList () {//获取清表模板信息
  538. const { data: res } = await getWbsTypeList({ wbstype: 1 })
  539. console.log(res);
  540. if (res.code === 200 && res.msg === '操作成功') {
  541. this.GLExcelData = res.data
  542. }
  543. },
  544. async getLazytree (parentId) {//清表树信息
  545. const { data: res } = await getLazytree({
  546. parentId: parentId,
  547. wbsId: this.GLExcelFrom.name,
  548. wbsType: '1'
  549. })
  550. console.log(res);
  551. if (res.code === 200 && res.msg === '操作成功') {
  552. res.data.forEach(val => {
  553. val.isExistForm = !!val.isExistForm
  554. })
  555. return res.data
  556. } else {
  557. return []
  558. }
  559. },
  560. handleNodeClickExcel (data) {//点击节点事件
  561. this.addElementForm.wbsId = this.GLExcelFrom.name
  562. this.addElementForm.parentId = data.id
  563. //this.selectByNodeTable(data.id)
  564. this.searchNodeTables(data.id)
  565. },
  566. async selectByNodeTable (id) {//获取清表信息
  567. const { data: res } = await selectByNodeTable(id)
  568. console.log(res);
  569. if (res.code == 200) {
  570. if (res.data.length > 0) {
  571. res.data.forEach(val => {
  572. if (val.isLinkTable == 2) {
  573. val.checknd = true
  574. } else {
  575. val.checknd = false
  576. }
  577. val.loading = false;
  578. })
  579. this.addTableData = res.data
  580. }else{
  581. this.addTableData = []
  582. }
  583. }
  584. },
  585. //查看节点下已关联的元素表信息
  586. searchNodeTables(id){
  587. searchNodeTables(id,this.from.id).then((res)=>{
  588. if (res.data.data.length > 0) {
  589. res.data.data.forEach(val => {
  590. if (val.isLinkTable == 2) {
  591. val.checknd = true
  592. } else {
  593. val.checknd = false
  594. }
  595. val.loading = false;
  596. })
  597. this.addTableData = res.data.data
  598. }else{
  599. this.addTableData = []
  600. }
  601. })
  602. },
  603. async excelType () {//清表类型
  604. const { data: res } = await excelType({ code: 'sys_excltab_type' })
  605. console.log(res);
  606. if (res.code === 200) {
  607. this.exceltypeData = res.data
  608. }
  609. },
  610. relationMD (row, type) {//关联取消关联
  611. row.loading = true;
  612. if (type == '关联') {
  613. saveRelation(row.id,this.from.id,this.tableData).then(()=>{
  614. row.checknd = true;
  615. row.isLinkTable = 2;
  616. }).finally(()=>{
  617. row.loading = false;
  618. })
  619. } else {
  620. cancelRelation({
  621. id:row.id,
  622. excelTabId:this.from.id,
  623. }).then(()=>{
  624. row.checknd = false;
  625. row.isLinkTable = 1;
  626. }).finally(()=>{
  627. row.loading = false;
  628. })
  629. }
  630. },
  631. saveElementMD () {//保存按钮
  632. if (this.addElementForm.wbsId) {
  633. if (this.activeName == 'link') {
  634. this.submitExcelRelationWbsTreeAndElement({
  635. excelTabId:this.from.id,
  636. elementList: this.tableData,
  637. submitStatus:1
  638. })
  639. } else {
  640. if (this.addElementForm.deptName && this.addElementForm.tableType && this.addElementForm.tableOwner) {
  641. let nodeIds = this.$refs.tree.getCheckedKeys();
  642. if(nodeIds.length < 1){
  643. this.$message({
  644. type: 'warning',
  645. message: '至少勾选一个节点'
  646. })
  647. return;
  648. }
  649. this.submitExcelRelationWbsTreeAndElement({
  650. deptName: this.addElementForm.deptName,
  651. tableType: this.addElementForm.tableType,
  652. tableOwner: this.addElementForm.tableOwner,
  653. wbsId: this.addElementForm.wbsId,
  654. elementList: this.tableData,
  655. nodeIds:nodeIds,
  656. excelTabId:this.from.id,
  657. submitStatus:2
  658. })
  659. }else{
  660. this.$message({
  661. type: 'warning',
  662. message: '请填写和选择新增的表名,表类型,表所属方'
  663. })
  664. }
  665. }
  666. } else {
  667. this.$message({
  668. type: 'warning',
  669. message: '请先选择WBS树节点表单'
  670. })
  671. }
  672. },
  673. async submitExcelRelationWbsTreeAndElement (da) {//保存接口
  674. const { data: res } = await submitExcelRelationWbsTreeAndElement(da)
  675. console.log(res);
  676. if (res.code == 200) {
  677. this.$message({
  678. type: 'success',
  679. message: '设置成功'
  680. })
  681. this.AssociatedPublicTap = false
  682. }
  683. },
  684. //#endregion
  685. //#region 接口
  686. async tabLazytree (modeId, parentId) {
  687. const { data: res } = await tabLazytree({ modeId, parentId })
  688. console.log(res);
  689. if (res.code == 200) {
  690. if (res.data.length > 0) {
  691. res.data.forEach(val => {
  692. val.hasChildren = !val.hasChildren
  693. });
  694. }
  695. return res.data
  696. }
  697. },
  698. async dictionarydataType () {//数据类型字典
  699. const { data: res } = await dictionarydataType()
  700. console.log(res);
  701. if (res.code == 200) {
  702. res.data.forEach(element => {
  703. element.dictKey = Number(element.dictKey)
  704. });
  705. this.dataType = res.data
  706. }
  707. },
  708. //#endregion
  709. getOwnerTypelist () {
  710. if (this.ownerTypeList.length > 1) {
  711. return;
  712. }
  713. getDictionary({
  714. code: 'owner_type'
  715. }).then((res) => {
  716. res.data.data.forEach(element => {
  717. element.dictKey = Number(element.dictKey)
  718. });
  719. this.ownerTypeList = res.data.data;
  720. })
  721. },
  722. },
  723. created () {
  724. this.getOwnerTypelist();
  725. this.excelType();
  726. }
  727. }
  728. </script>
  729. <style lang="scss" scoped>
  730. .boxswai {
  731. padding: 0px 14px 10px 14px !important;
  732. }
  733. .dingwei {
  734. position: fixed;
  735. bottom: 40px;
  736. right: 40px;
  737. }
  738. //树结构超长后产生滚动条
  739. .el-tree > .el-tree-node {
  740. min-width: 100%;
  741. display: inline-block;
  742. }
  743. .boxswai{
  744. height: 100%;
  745. box-sizing: border-box;
  746. padding-bottom: 10px;
  747. }
  748. </style>