addItemModel.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. <!-- 新增实例 -->
  2. <template>
  3. <Modal
  4. class="getItemModal"
  5. :show="isShowModel"
  6. title="添加实例对象"
  7. mode="full"
  8. @close="modalClose"
  9. >
  10. <template #content class="xxx">
  11. <div class="getItem">
  12. <div id="left" class="left">
  13. <div class="top">
  14. <Cascader
  15. caption="专业系统"
  16. multiple
  17. allText="全部"
  18. :all="false"
  19. :data="categoryList"
  20. showPanel
  21. width="300"
  22. @confirm="changeEquip"
  23. ></Cascader>
  24. <Cascader
  25. caption="建筑楼层"
  26. allText="全部"
  27. multiple
  28. :data="buildFloorList"
  29. @confirm="changeFloor"
  30. showPanel
  31. width="300"
  32. ></Cascader>
  33. <!-- <Cascader
  34. caption="分区类型"
  35. multiple
  36. :data="cascaderData6"
  37. showPanel
  38. width="300"
  39. ></Cascader> -->
  40. <Input
  41. iconType="search"
  42. v-model="queryText"
  43. placeholder="搜索设备名称或本地编码"
  44. @pressEnter="pressEnter"
  45. />
  46. </div>
  47. <div class="localDom" ref="localDom">
  48. <el-table
  49. v-if="tableHeight > 0"
  50. size="small"
  51. ref="multipleTable"
  52. :data="equiptable"
  53. tooltip-effect="dark"
  54. style="width: 100%"
  55. :height="tableHeight"
  56. @selection-change="handleSelectionChange"
  57. >
  58. <el-table-column type="selection" width="55"> </el-table-column>
  59. <el-table-column type="localName" label="本地名称" width="300">
  60. <template slot-scope="scope">{{
  61. scope.row.localName ? scope.row.localName : "--"
  62. }}</template>
  63. </el-table-column>
  64. <el-table-column prop="localId" label="本地编码" width="300">
  65. <template slot-scope="scope">{{
  66. scope.row.localId ? scope.row.localId : "--"
  67. }}</template>
  68. </el-table-column>
  69. <el-table-column
  70. prop="bimLocation"
  71. label="位置"
  72. show-overflow-tooltip
  73. width="300"
  74. >
  75. <template slot-scope="scope">{{
  76. scope.row.building || scope.row.floor
  77. ? scope.row.building && scope.row.floor
  78. ? scope.row.building.localName +
  79. "-" +
  80. scope.row.floor.localName
  81. : scope.row.building
  82. ? scope.row.building.localName
  83. : scope.row.floor.localName
  84. : "--"
  85. }}</template>
  86. </el-table-column>
  87. <el-table-column
  88. prop="codeName"
  89. label="类型"
  90. show-overflow-tooltip
  91. width="300"
  92. >
  93. </el-table-column>
  94. </el-table>
  95. </div>
  96. <Pagination
  97. class="page-box"
  98. :pageCountShow="true"
  99. :pageCount="tableTotal"
  100. :pageSizeSetting="true"
  101. @change="currentChangeHandle"
  102. />
  103. </div>
  104. <div class="right">
  105. <div class="top">
  106. <div class="top-l">
  107. <span class="equip-title">已选实例</span>
  108. <span class="equip-num">{{ choiceEquipList.length }}</span>
  109. </div>
  110. <div class="top-r" @click="clearChoiceEqipment">清空</div>
  111. </div>
  112. <ul class="choiceList">
  113. <li class="choiceList-item">
  114. <div
  115. class="treeList"
  116. v-for="(items, key) in equipData"
  117. :key="key"
  118. >
  119. <div class="title" @click="collapse(items)">
  120. <i
  121. v-bind:class="[
  122. items.showChildren ? 'caret-icon-active' : 'caret-icon',
  123. 'el-icon-caret-bottom',
  124. ]"
  125. ></i>
  126. <span class="equip-title">{{ items.title }}</span>
  127. <span class="equip-num">{{ items.number }}</span>
  128. </div>
  129. <el-collapse-transition>
  130. <ul class="treeList-bodys" v-show="items.showChildren">
  131. <li
  132. class="treeList-item"
  133. v-for="(item, key) in items.children"
  134. :key="key"
  135. >
  136. <div class="item-title">
  137. {{ item.localName ? item.localName : "空" }}
  138. </div>
  139. <i
  140. class="el-icon-error"
  141. @click="deleteItem(items, key)"
  142. ></i>
  143. </li>
  144. </ul>
  145. </el-collapse-transition>
  146. </div>
  147. </li>
  148. </ul>
  149. </div>
  150. </div>
  151. <div class="btn-list">
  152. <el-button @click="modalClose">取消</el-button>
  153. <el-button type="primary" @click="finish">确认</el-button>
  154. </div>
  155. </template>
  156. </Modal>
  157. </template>
  158. <script>
  159. import { mapMutations, mapState } from "vuex";
  160. import {
  161. buildiFloor,
  162. readCategory,
  163. queryEquip,
  164. queryLegend,
  165. } from "@/api/editer";
  166. import bus from "@/bus/bus";
  167. export default {
  168. props: ["showAddItemModel"],
  169. computed: {
  170. ...mapState([
  171. "editCmd",
  172. "projectId",
  173. "equipmentItemNum",
  174. "equipmentItemList",
  175. ]),
  176. },
  177. data() {
  178. return {
  179. isShowModel: false,
  180. equipTypeString: "", //设备类型选中条件
  181. buildIdString: "", //建筑id 类型string
  182. floorIdString: "", // 楼层id 类型string
  183. tableTotal: 0, //搜索获取得设备总数
  184. equiptable: [], //table数据
  185. equipData: [], //选中得设备数组 右侧二级树
  186. buildFloorList: [], // 建筑查询数据
  187. categoryList: [], //设备类型
  188. tableHeight: 0, //table的高度
  189. choiceEquipList: [], // 选中得设备数组//非树机构
  190. pageSize: 20,
  191. currentPage: 1,
  192. local: null, //table loading
  193. local2: null, // 全局 loading
  194. queryText: "", //搜索框数据
  195. filtIdListString: "", // 要过滤的 id 字符串
  196. };
  197. },
  198. methods: {
  199. // 筛选设备
  200. changeEquip(list) {
  201. const classCode = []; // 设备类型
  202. this.currentPage = 1;
  203. list.forEach((val) => {
  204. if (val.index == 3) {
  205. classCode.push(val.id);
  206. }
  207. });
  208. //设备类型转换
  209. this.equipTypeString = classCode.length
  210. ? ";classCode in " + JSON.stringify(classCode)
  211. : "";
  212. // 调用设备接口
  213. this.queryEquip();
  214. },
  215. // 筛选楼层
  216. changeFloor(list) {
  217. let buildIdList = []; // 设备类型
  218. let floorIdList = [];
  219. let isfloornull = "";
  220. let isbuildnull = "";
  221. this.currentPage = 1;
  222. // 遍历获取对应得楼层id、建筑id
  223. list.forEach((val) => {
  224. if (val.index == 1) {
  225. if (val.id == "bisnull") {
  226. isbuildnull = "buildingId isNull";
  227. } else {
  228. buildIdList.push(val.id);
  229. }
  230. }
  231. if (val.index == 2) {
  232. if (val.id == "fisnull") {
  233. isfloornull = "floorId isNull";
  234. } else {
  235. floorIdList.push(val.id);
  236. }
  237. }
  238. });
  239. // 对id数组和or isnull 进行拼接
  240. if (buildIdList.length) {
  241. if (isbuildnull) {
  242. isbuildnull = "or " + isbuildnull;
  243. }
  244. }
  245. this.buildIdString = buildIdList.length
  246. ? ";buildingId in " + JSON.stringify(buildIdList) + isbuildnull
  247. : isbuildnull
  248. ? ";" + isbuildnull
  249. : "";
  250. if (floorIdList.length) {
  251. if (isfloornull) {
  252. isfloornull = "or " + isfloornull;
  253. }
  254. }
  255. this.floorIdString = floorIdList.length
  256. ? ";floorId in " + JSON.stringify(floorIdList) + isfloornull
  257. : isfloornull
  258. ? ";" + isfloornull
  259. : "";
  260. // 调用设备接口
  261. this.queryEquip();
  262. },
  263. // 搜索设备
  264. queryEquip() {
  265. let data = {
  266. cascade: [
  267. {
  268. name: "building",
  269. projection: ["id", "name", "localName"],
  270. },
  271. {
  272. name: "floor",
  273. projection: ["id", "name", "localName"],
  274. },
  275. ],
  276. orders: "name asc, createTime desc",
  277. pageNumber: this.currentPage,
  278. pageSize: this.pageSize,
  279. filters: `projectId='${this.projectId}'${this.filtIdListString}${this.buildIdString}${this.floorIdString}${this.equipTypeString};localName contain "${this.queryText}" or localId contain "${this.queryText}"`,
  280. };
  281. this.localLoading();
  282. queryEquip(data)
  283. .then((res) => {
  284. this.tableTotal = res.total;
  285. this.equiptable = res.content;
  286. this.$loading.close(this.local);
  287. })
  288. .catch((error) => {
  289. console.log("it is error!", error);
  290. this.$loading.close(this.local);
  291. });
  292. },
  293. // 关闭弹窗
  294. modalClose() {
  295. this.isShowModel = false;
  296. this.$emit("closeModel");
  297. },
  298. // 确认/提交
  299. finish() {
  300. // 获取选中图例得 iamge url
  301. if (!this.equipData.length) {
  302. this.modalClose();
  303. }
  304. const categoryList = [];
  305. this.equipData.forEach((item) => {
  306. categoryList.push(item.id);
  307. });
  308. // 获取设备得图片
  309. const categoryListString = JSON.stringify(categoryList);
  310. let data = {
  311. cascade: [
  312. {
  313. name: "anchorList",
  314. },
  315. {
  316. name: "state",
  317. },
  318. ],
  319. filters: `category in ${categoryListString}`,
  320. pageNumber: 1,
  321. pageSize: 1000,
  322. };
  323. this.local2 = this.$loading({ type: "global" });
  324. queryLegend(data)
  325. .then((res) => {
  326. if (res.content && res.content.length) {
  327. let list = this.choiceEquipList;
  328. res.content.forEach((contentType) => {
  329. list.forEach((item) => {
  330. if (item.classCode == contentType.category) {
  331. item.url = contentType.state[0].pic;
  332. item.state = contentType.state;
  333. }
  334. });
  335. });
  336. this.choiceEquipList = list;
  337. }
  338. // // 将选中的设备类存到vuex中
  339. bus.$emit("addEquipment", this.choiceEquipList);
  340. this.$loading.close(this.local2);
  341. this.modalClose();
  342. })
  343. .catch((res) => {
  344. console.log(res);
  345. this.$loading.close(this.local2);
  346. this.modalClose();
  347. });
  348. },
  349. // 搜索回车
  350. pressEnter() {
  351. this.currentPage = 1;
  352. this.queryEquip();
  353. },
  354. // /是否下拉折叠
  355. collapse(item) {
  356. item.showChildren = !item.showChildren;
  357. },
  358. // 删除item
  359. deleteItem(items, key) {
  360. let deleteItem = items.children.splice(key, 1);
  361. items.number = items.children.length;
  362. this.$refs.multipleTable.toggleRowSelection(deleteItem[0]);
  363. let index = -1;
  364. this.choiceEquipList.forEach((item, i) => {
  365. if (item.id == deleteItem[0].id) {
  366. index = i;
  367. }
  368. });
  369. if (index >= 0) {
  370. this.choiceEquipList.splice(key, 1);
  371. }
  372. this.handleSelectionChange(this.choiceEquipList);
  373. },
  374. clearChoiceEqipment() {
  375. this.$refs.multipleTable.clearSelection();
  376. },
  377. /**
  378. * 构建树list
  379. * list 需要递归得数组
  380. * arr 需要返回得结果
  381. * nameList 要递归得判断条件
  382. * index 树得层
  383. */
  384. mapList(
  385. list,
  386. arr = [],
  387. nameList = ["id", "localName", "floor"],
  388. index = 0
  389. ) {
  390. index++;
  391. if (list.length) {
  392. list.forEach((item) => {
  393. if (item[nameList[2]] && item[nameList[2]].length) {
  394. const obj = {
  395. title: item[nameList[1]],
  396. id: item[nameList[0]],
  397. index: index,
  398. children: [],
  399. };
  400. const children = this.mapList(
  401. item[nameList[2]],
  402. [],
  403. nameList,
  404. index
  405. );
  406. obj.children = children;
  407. arr.push(obj);
  408. } else {
  409. arr.push({
  410. title: item[nameList[1]],
  411. id: item[nameList[0]],
  412. index: index,
  413. });
  414. }
  415. });
  416. }
  417. return arr;
  418. },
  419. // 选中table回调
  420. handleSelectionChange(list) {
  421. let arr = [];
  422. // let newList = this.choiceEquipList.concat(list);
  423. this.choiceEquipList = list;
  424. // newList = this._.uniqBy(newList, "id");
  425. list.forEach((item) => {
  426. if (arr.length) {
  427. let index = -1;
  428. arr.forEach((aItem) => {
  429. if (aItem.id == item.classCode) {
  430. index = 1;
  431. aItem.children.push(item);
  432. aItem.number++;
  433. }
  434. });
  435. if (index == -1) {
  436. let obj = {
  437. id: item.classCode,
  438. title: item.codeName,
  439. children: [item],
  440. number: 1,
  441. showChildren: true,
  442. };
  443. arr.push(obj);
  444. }
  445. } else {
  446. let obj = {
  447. id: item.classCode,
  448. title: item.codeName,
  449. children: [],
  450. number: 1,
  451. showChildren: true,
  452. };
  453. obj.children.push(item);
  454. arr.push(obj);
  455. }
  456. });
  457. this.equipData = arr;
  458. },
  459. // 切换分页
  460. currentChangeHandle(pageMsg) {
  461. this.pageSize = pageMsg.newPageSize;
  462. this.currentPage = pageMsg.newPage;
  463. this.queryEquip();
  464. },
  465. // 局部加载
  466. localLoading() {
  467. this.local = this.$loading({
  468. el: this.$refs.localDom,
  469. type: "local",
  470. size: "min",
  471. });
  472. },
  473. // 打开窗口初始化弹窗
  474. initAddModel() {
  475. const data = {
  476. projectId: this.projectId,
  477. };
  478. // 建筑查询条件
  479. buildiFloor(data).then((res) => {
  480. this.buildFloorList = this.mapList(res.content);
  481. });
  482. // 设备类型查询条件
  483. readCategory(data).then((res) => {
  484. this.categoryList = this.mapList(
  485. res.content,
  486. [],
  487. ["code", "name", "children"]
  488. );
  489. });
  490. // 设置table的高
  491. setTimeout(() => {
  492. const domLeft = document.getElementById("left");
  493. if (domLeft) {
  494. this.tableHeight = domLeft.offsetHeight - 140;
  495. // 调取设备接口
  496. this.queryEquip();
  497. }
  498. });
  499. // 清空选中的item;
  500. this.choiceEquipList = [];
  501. // 清空右侧二级树
  502. this.equipData = [];
  503. },
  504. },
  505. watch: {
  506. // 是否打开弹窗
  507. showAddItemModel(val) {
  508. this.isShowModel = val;
  509. if (val) {
  510. this.initAddModel();
  511. }
  512. },
  513. // 监听设备变化,获取设备时做相应的过滤
  514. equipmentItemNum: {
  515. handler: function (val) {
  516. if (!val) return;
  517. const idList = [];
  518. this.equipmentItemList.forEach((item) => {
  519. idList.push(item.legendData.attachObjectIds[0]);
  520. });
  521. const filtIdListString = idList.length
  522. ? ";not id in " + JSON.stringify(idList)
  523. : "";
  524. this.filtIdListString = filtIdListString;
  525. },
  526. deep: true,
  527. immediate: true,
  528. },
  529. },
  530. };
  531. </script>
  532. <style lang="less" scoped>
  533. ul,
  534. li {
  535. margin: 0;
  536. padding: 0;
  537. list-style-type: none;
  538. }
  539. .getItemModal {
  540. height: calc(~"100% - 110px");
  541. .getItem {
  542. height: calc(~"100% - 110px");
  543. display: flex;
  544. margin: 0 32px 16px 32px;
  545. border: 1px solid #e4e5e7;
  546. position: relative;
  547. top: 16px;
  548. .xxx {
  549. width: 100%;
  550. position: relative;
  551. // height: 100%;
  552. }
  553. }
  554. /deep/ .p-modal-main .p-modal-content-full {
  555. height: calc(100vh - 56px) !important;
  556. }
  557. /deep/ .p-modal-main .p-modal-content-full .p-modal-content-main {
  558. height: 100% !important;
  559. }
  560. .right {
  561. width: 420px;
  562. height: 100%;
  563. overflow-y: scroll;
  564. border-left: 1px solid #eff0f1;
  565. .top {
  566. height: 58px;
  567. border-bottom: 1px solid #eff0f1;
  568. display: flex;
  569. align-items: center;
  570. justify-content: space-between;
  571. box-sizing: border-box;
  572. padding: 0 12px 0 12px;
  573. .top-l {
  574. display: flex;
  575. .equip-title {
  576. font-size: 14px;
  577. color: #8d9399;
  578. }
  579. .equip-num {
  580. font-size: 14px;
  581. margin-left: 12px;
  582. color: #1f2429;
  583. background: #eff0f1;
  584. padding: 0 10px 0 10px;
  585. }
  586. }
  587. .top-r {
  588. color: #0091ff;
  589. cursor: pointer;
  590. }
  591. }
  592. .choiceList {
  593. .choiceList-item {
  594. .treeList {
  595. width: 100%;
  596. .title {
  597. width: 100%;
  598. height: 40px;
  599. box-sizing: border-box;
  600. padding: 0 16px 0 16px;
  601. display: flex;
  602. align-items: center;
  603. line-height: 40px;
  604. .equip-title {
  605. font-size: 14px;
  606. color: #8d9399;
  607. line-height: 14px;
  608. cursor: pointer;
  609. }
  610. .equip-num {
  611. font-size: 14px;
  612. margin-left: 12px;
  613. color: #1f2429;
  614. background: #eff0f1;
  615. padding: 0 10px 0 10px;
  616. line-height: 24px;
  617. }
  618. .caret-icon {
  619. animation: nowhirling 0.2s linear forwards;
  620. }
  621. .caret-icon-active {
  622. animation: whirling 0.2s linear forwards;
  623. }
  624. }
  625. .treeList-bodys {
  626. .treeList-item {
  627. width: 100%;
  628. height: 40px;
  629. display: flex;
  630. align-items: center;
  631. justify-content: space-between;
  632. box-sizing: border-box;
  633. padding: 0 16px 0 50px;
  634. cursor: pointer;
  635. &:hover {
  636. background: #f5f6f7;
  637. }
  638. }
  639. }
  640. }
  641. }
  642. }
  643. }
  644. .left {
  645. flex: 1;
  646. position: relative;
  647. .top {
  648. width: 100%;
  649. height: 58px;
  650. border-bottom: 1px solid #eff0f1;
  651. display: flex;
  652. align-items: center;
  653. justify-content: flex-start;
  654. &:first-child {
  655. margin-right: 24px;
  656. }
  657. &:last-child {
  658. margin-left: 24px;
  659. }
  660. }
  661. .page-box {
  662. position: absolute;
  663. right: 24px;
  664. bottom: 24px;
  665. }
  666. }
  667. .btn-list {
  668. width: 100%;
  669. display: flex;
  670. justify-content: flex-end;
  671. margin-top: 24px;
  672. padding-right: 32px;
  673. box-sizing: border-box;
  674. }
  675. }
  676. @keyframes whirling {
  677. 0% {
  678. transform: rotate(-90deg);
  679. -ms-transform: rotate(-90deg); /* Internet Explorer */
  680. -moz-transform: rotate(-90deg); /* Firefox */
  681. -webkit-transform: rotate(-90deg); /* Safari 和 Chrome */
  682. -o-transform: rotate(-90deg); /* Opera */
  683. }
  684. 100% {
  685. transform: rotate(0deg);
  686. -ms-transform: rotate(0deg); /* Internet Explorer */
  687. -moz-transform: rotate(0deg); /* Firefox */
  688. -webkit-transform: rotate(0deg); /* Safari 和 Chrome */
  689. -o-transform: rotate(0deg); /* Opera */
  690. }
  691. }
  692. @keyframes nowhirling {
  693. 0% {
  694. transform: rotate(0deg);
  695. -ms-transform: rotate(0deg); /* Internet Explorer */
  696. -moz-transform: rotate(0deg); /* Firefox */
  697. -webkit-transform: rotate(0deg); /* Safari 和 Chrome */
  698. -o-transform: rotate(0deg); /* Opera */
  699. }
  700. 100% {
  701. transform: rotate(-90deg);
  702. -ms-transform: rotate(-90deg); /* Internet Explorer */
  703. -moz-transform: rotate(-90deg); /* Firefox */
  704. -webkit-transform: rotate(-90deg); /* Safari 和 Chrome */
  705. -o-transform: rotate(-90deg); /* Opera */
  706. }
  707. }
  708. </style>