handsontable.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. <template>
  2. <div id="handsontable" v-loading="isLoading">
  3. <el-row class="left">
  4. <el-select v-model="onlyRead" @change="getData(false)" style="width:100px;margin-right:20px;vertical-align:bottom;">
  5. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
  6. </el-select>
  7. <el-select v-model="showType" @change="initHot" style="width:100px;margin-right:10px;vertical-align:bottom;">
  8. <el-option v-for="item in showTypes" :key="item.value" :label="item.label" :value="item.value"></el-option>
  9. </el-select>
  10. <el-button v-show="!onlyRead" @click="addSp">添加</el-button>
  11. <el-button @click="reset">刷新</el-button>
  12. <el-button v-show="!onlyRead" @click="undo">撤销</el-button>
  13. </el-row>
  14. <div v-show="main &&main.length" :id="id"></div>
  15. <div class="center" v-show="!main || !main.length" style="height: 400px;padding-top:140px;box-sizing:border-box;">
  16. <i class="icon-wushuju iconfont"></i>
  17. 暂无数据
  18. </div>
  19. <!-- <add-business :buildMess="buildMess" :dialog="dialog"></add-business> -->
  20. <el-pagination class="right" v-show="main && main.length" @size-change="handleSizeChange" @current-change="handleCurrentChange"
  21. :current-page="page.pageNumber" :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper"
  22. :total="page.total">
  23. </el-pagination>
  24. <!-- <div class="right" v-show="main && main.length">
  25. <my-pagination :page="page" @change="pageChange"></my-pagination>
  26. </div> -->
  27. <!-- 二维码弹窗 -->
  28. <qrcode :dialog="dialog" :qrcodeUrl="qrcodeUrl" :addBody="true" ref="qrcode"></qrcode>
  29. </div>
  30. </template>
  31. <script>
  32. // 引用handsontable插件
  33. import "@/assets/js/chosen.jquery.min";
  34. import tools from "@/utils/scan/tools";
  35. import "@/assets/js/handsontable-chosen-editor";
  36. import myPagination from "@/components/common/myPagination";
  37. import addBusiness from "@/components/business_space/dialogs/addDialog/businessDialog"
  38. import showTools from "@/utils/handsontable/notShow"
  39. import handsonUtils from "@/utils/hasontableUtils"
  40. import Handsontable from "handsontable-pro"
  41. import buildFloor from '@/utils/handsontable/buildFloorData'
  42. import 'handsontable-pro/dist/handsontable.full.css'
  43. import zhCN from 'handsontable-pro/languages/zh-CN';
  44. import qrcode from "@/components/ledger/lib/qrcode";
  45. import { queryZone, updateZone, deleteZone, createZone, BeatchQueryParam, updateRelateInSpAndBuild } from "@/api/scan/request";
  46. import { mapGetters, mapActions } from "vuex";
  47. export default {
  48. props: {
  49. id: {},
  50. zoneCode: {}
  51. },
  52. components: {
  53. qrcode, //二维码页面
  54. myPagination,
  55. addBusiness
  56. },
  57. computed: {
  58. ...mapGetters("layout", ["projectId", "secret", "userId"]),
  59. showTypes() {
  60. return this.onlyRead ?
  61. [{ value: "Visible", label: '只看采集信息' }, { value: "all", label: '全部' }] :
  62. [{ value: "partInfo", label: '隐藏信息点' }, { value: "all", label: '全部' }]
  63. }
  64. },
  65. data() {
  66. return {
  67. dialog: {
  68. qrcode: false, //二维码弹窗
  69. addDevice: false
  70. },
  71. qrcodeUrl: "",//二维码图片地址
  72. headers: null,
  73. main: [],
  74. hot: null,
  75. isLoading: true,
  76. options: [{
  77. value: true,
  78. label: '只读模式'
  79. }, {
  80. value: false,
  81. label: '编辑模式'
  82. }],
  83. onlyRead: true,
  84. showType: "",
  85. page: {
  86. pageSize: 50,
  87. pageSizes: [10, 20, 50, 100],
  88. pageNumber: 1,
  89. total: 0
  90. },
  91. param: {
  92. ProjId: this.projectId, //项目id
  93. UserId: this.userId, //用户id
  94. secret: this.secret
  95. },
  96. buildMess: null,
  97. filtersArr: [], //表格数据被过滤后的下标
  98. copyMain: [], //深拷贝数组
  99. buildFloorData: [], //楼层数据
  100. };
  101. },
  102. created() {
  103. this.setData()
  104. buildFloor.getData(this.buildFloorData)
  105. },
  106. mounted() { },
  107. methods: {
  108. setData() {
  109. this.param.ProjId = this.projectId
  110. this.param.UserId = this.userId
  111. this.param.secret = this.secret
  112. },
  113. //获取表格数据
  114. getHeader(headers, buildFloorSelectd) {
  115. this.headers = headers
  116. this.buildFloorSelectd = buildFloorSelectd
  117. this.getData()
  118. },
  119. getData() {
  120. this.isLoading = true
  121. let params = {
  122. zone: this.zoneCode,
  123. data: {
  124. Filters: ``,
  125. Orders: "createTime desc, RoomID asc",
  126. PageNumber: this.page.pageNumber,
  127. PageSize: this.page.pageSize
  128. }
  129. }
  130. if (this.buildFloorSelectd[0] == "noKnow") {
  131. params.data.Filters += `buildingId isNull`
  132. } else if (this.buildFloorSelectd[0] && this.buildFloorSelectd[0] != "all") {
  133. params.data.Filters += `buildingId='${this.buildFloorSelectd[0]}'`
  134. }
  135. if (this.buildFloorSelectd.length > 1) {
  136. if (this.buildFloorSelectd[1] == "noKnow") {
  137. params.data.Filters += `;floorId isNull`
  138. } else if (this.buildFloorSelectd[1] && this.buildFloorSelectd[1] != "all") {
  139. params.data.Filters += `;floorId='${this.buildFloorSelectd[1]}'`
  140. }
  141. }
  142. if (!params.data.Filters) {
  143. delete params.data.Filters
  144. }
  145. // if (this.buildFloorSelectd.length && this.buildFloorSelectd[0] && this.buildFloorSelectd[1]) {
  146. // params.data.Filters = `BuildingId='${this.buildFloorSelectd[0]}';FloorId='${this.buildFloorSelectd[1]}'`
  147. // }
  148. // else if (buildFloorSelectd.length && buildFloorSelectd[0] && !buildFloorSelectd[1]) {
  149. // params.data.Filters = `BuildingId='${buildFloorSelectd[0]}'`
  150. // } else {
  151. // params.data.Filters = `BuildingId='';FloorId=''`
  152. // }
  153. queryZone(params, res => {
  154. this.page.total = res.Total
  155. this.main = res.Content.map((item) => {
  156. if (item.hasOwnProperty("BuildingId") && item.hasOwnProperty("FloorId")) {
  157. item.flowBuild = item.BuildingId + "-" + item.FloorId
  158. } else if (item.hasOwnProperty("BuildingId") && !item.hasOwnProperty("FloorId")) {
  159. item.flowBuild = item.BuildingId
  160. }
  161. return item
  162. });
  163. if (this.main && this.main.length && this.main[0].RoomID) {
  164. this.copyMain = tools.deepCopy(this.main);
  165. }
  166. this.isLoading = false
  167. this.getMain()
  168. })
  169. },
  170. //获取表格主体内容
  171. getMain() {
  172. if (!!this.hot) {
  173. this.hot.destroy();
  174. this.hot = null;
  175. }
  176. this.$nextTick(() => {
  177. this.initHot();
  178. });
  179. },
  180. //初始化handsontable组件
  181. initHot() {
  182. var container = document.getElementById(this.id);
  183. let winHeight = document.documentElement.clientHeight;
  184. this.hot = new Handsontable(container, {
  185. data: this.main,
  186. colHeaders: this.delHeader(this.headers), //表头文案
  187. columns: this.getType(this.headers), //数据显示格式
  188. filters: true,
  189. fixedColumnsLeft: 4,
  190. maxRows: this.main.length,
  191. height: winHeight - 100 - 50 - 176,
  192. columnSorting: true, //添加排序
  193. sortIndicator: true, //添加排序
  194. renderAllRows: true,
  195. autoColumnSize: true,
  196. observeChanges: false,
  197. language: "zh-CN",
  198. manualColumnResize: true,
  199. manualColumnMove: true,
  200. dropdownMenu: [
  201. "filter_by_condition",
  202. "filter_by_value",
  203. "filter_action_bar"
  204. ],
  205. contextMenu: {
  206. items: {
  207. remove_row: {
  208. name: "删除该业务空间"
  209. }
  210. }
  211. },
  212. // 事件
  213. afterChange: this.tdChange, //修改后
  214. afterFilter: this.trimmedRows, //排序前
  215. afterRemoveRow: this.romoveFm, //右键删除
  216. afterOnCellMouseDown: this.eventClick //鼠标点击
  217. });
  218. let pro = document.getElementById("hot-display-license-info");
  219. if (!!pro) {
  220. pro.parentNode.removeChild(pro);
  221. }
  222. },
  223. //表格中的查看详情
  224. eventClick(el, rowArr) {
  225. let filter = this.filtersArr;
  226. //被筛选过后的数组
  227. let trimmedArr = this.trimmedRows();
  228. //是否启用了排序
  229. let isSort = this.hot.getPlugin("columnSorting").isSorted();
  230. // debugger
  231. if (trimmedArr.length && isSort) {
  232. let sortArr = this.myHotArr.getPlugin("columnSorting").rowsMapper
  233. .__arrayMap;
  234. let infos = this.main[trimmedArr[sortArr[rowArr.row]]];
  235. this.getInfors(infos, rowArr);
  236. } else if (isSort) {
  237. //排序后的数组
  238. let sortArr = this.hot.getPlugin("columnSorting").rowsMapper.__arrayMap;
  239. let infos = this.main[sortArr[rowArr.row]];
  240. this.getInfors(infos, rowArr);
  241. } else if (trimmedArr.length) {
  242. let infos = this.main[trimmedArr[rowArr.row]];
  243. this.getInfors(infos, rowArr);
  244. } else {
  245. let infos = this.main[rowArr.row];
  246. this.getInfors(infos, rowArr);
  247. }
  248. },
  249. getInfors(infos, row) {
  250. let val = this.hot.colToProp(row.col);
  251. if (val == "point") {
  252. this.$router.push({
  253. path: "/ledger/spaceDetail",
  254. query: { RoomID: infos.RoomID, zone: this.zoneCode, isMyTab: 2 }
  255. })
  256. } else if (val == "RoomQRCode") {
  257. this.qrcodeUrl = this.main[row.row].RoomQRCode
  258. if (!!this.qrcodeUrl) {
  259. this.dialog.qrcode = true;
  260. } else {
  261. this.$message("此设备没有设备二维码")
  262. }
  263. } else {
  264. return false;
  265. }
  266. },
  267. //表格发生更改
  268. tdChange(changeData, source) {
  269. if (!this.onlyRead) {
  270. if (changeData) {
  271. let trimmedArr = this.trimmedRows();
  272. let param = handsonUtils.getParam(changeData, source, this.hot, trimmedArr);
  273. let data = []
  274. for (let i = 0; i < param.length; i++) {
  275. if (param[i].RoomID) {
  276. data.push(param[i])
  277. } else {
  278. this.handleCreateZone(param[i])
  279. }
  280. }
  281. //如果data中包含/且data长度为1,将其转换成.
  282. if (changeData.length == 1 && changeData[0][1].indexOf("/") > 0) {
  283. changeData[0][1] = changeData[0][1].split("/").join(".")
  284. }
  285. // 存在data进行修改请求
  286. if (data && data.length) {
  287. this.updateBusiness(data, changeData)
  288. }
  289. }
  290. }
  291. },
  292. //右键删除
  293. romoveFm() {
  294. let params = tools.differenceArr(this.main, this.copyMain)
  295. if (params.length < 1 || this.main > this.copyMain) {
  296. return
  297. }
  298. let param = {
  299. data: [],
  300. zone: this.zoneCode
  301. }
  302. params.map(item => {
  303. if (item.RoomID)
  304. param.data.push({ RoomID: item.RoomID })
  305. })
  306. this.$confirm("此操作将删除业务空间,是否继续?", "提示", {
  307. confirmButtonText: '确定',
  308. cancelButtonText: '取消',
  309. type: 'warning'
  310. }).then(() => {
  311. deleteZone(param, res => {
  312. this.$message.success("删除成功!")
  313. this.getData()
  314. })
  315. }).catch(() => {
  316. this.getData()
  317. this.$message("取消删除")
  318. })
  319. },
  320. //创建业务空间
  321. handleCreateZone(param) {
  322. let keys = Object.keys(param)
  323. keys.map((key) => { //将值为空字符串的属性删除
  324. if (param[key] == "") {
  325. delete param[key]
  326. }
  327. })
  328. if (!param.RoomLocalName) {
  329. this.$message("新增业务空间本地名称不能为空!")
  330. return
  331. }
  332. if (!Object.keys(param).length) {
  333. this.$message("新添加业务空间内容不能为空!")
  334. return
  335. }
  336. if (this.buildFloorSelectd && this.buildFloorSelectd[0] && this.buildFloorSelectd[1]) {
  337. param.BuildingId = this.buildFloorSelectd[0]
  338. param.FloorId = this.buildFloorSelectd[1]
  339. }
  340. // else if (this.buildMess.selectd && this.buildMess.selectd[0] && !this.buildMess.selectd[1]) {
  341. // param.BuildingId = this.buildMess.selectd[0]
  342. // }
  343. let params = {
  344. zone: this.zoneCode,
  345. data: {
  346. Content: [param]
  347. }
  348. }
  349. createZone(params, res => {
  350. this.$message.success("添加成功!")
  351. this.getData()
  352. })
  353. },
  354. // 修改
  355. updateBusiness(data, change) {
  356. let param = {
  357. data: {
  358. Content: [],
  359. Projection: []
  360. },
  361. zone: this.zoneCode
  362. };
  363. let keyList = [];
  364. //生成要修改字段列表
  365. change.map((item) => {
  366. let key = item[1].split(".")[0]
  367. if (key == "flowBuild" && keyList.indexOf(key) == -1) {
  368. keyList.push("BuildingId", "FloorId")
  369. param.data.Projection.push("BuildingId", "FloorId")
  370. }
  371. if (item[1] && keyList.indexOf(key) == -1) {
  372. keyList.push(key)
  373. }
  374. if (item[1] && item[3] == "" && param.data.Projection.indexOf(key) == -1) {
  375. param.data.Projection.push(key)
  376. }
  377. })
  378. //生成对应修改数据
  379. data.map((item, index) => {
  380. keyList.map(value => {
  381. if (value == "BuildingId") {
  382. let itemData = tools.dataForKey(item, "flowBuild")
  383. if (itemData == "") {
  384. tools.setDataForKey(item, "BuildingId", null)
  385. tools.setDataForKey(item, "FloorId", null)
  386. } else {
  387. let BuildingId = itemData.split("-")[0]
  388. let FloorId = itemData.split("-")[1]
  389. if (BuildingId && FloorId) {
  390. tools.setDataForKey(item, "BuildingId", BuildingId)
  391. tools.setDataForKey(item, "FloorId", FloorId)
  392. } else if (BuildingId && !FloorId) {
  393. tools.setDataForKey(item, "BuildingId", BuildingId)
  394. tools.setDataForKey(item, "FloorId", null)
  395. }
  396. }
  397. } else {
  398. let itemData = tools.dataForKey(item, value)
  399. tools.setDataForKey(item, value, itemData == "" ? null : itemData)
  400. }
  401. })
  402. param.data.Content.push(item);
  403. })
  404. if (param.data.Projection.indexOf('BuildingId') > -1) {
  405. let pa = param.data.Content.map(t => {
  406. return {
  407. type: this.zoneCode,
  408. spaceId: t.RoomID,
  409. id: t.FloorId || t.BuildingId || null,
  410. }
  411. })
  412. updateRelateInSpAndBuild(pa, res => {
  413. this.$message.success('修改成功')
  414. })
  415. } else {
  416. param.data.Projection = []
  417. updateZone(param, (res) => {
  418. this.$message.success('修改成功')
  419. })
  420. }
  421. },
  422. //获取被筛选掉的行号
  423. trimmedRows() {
  424. // var plugin = hot.getPlugin('trimRows').trimmedRows;//获取被筛选掉的行号
  425. var plugin = this.hot.getPlugin("trimRows").trimmedRows;
  426. let dataLength = this.main.length;
  427. let dataArr = new Array();
  428. for (let i = 0; i < dataLength; i++) {
  429. dataArr.push(i);
  430. }
  431. if (plugin.length <= 0) {
  432. dataArr = undefined;
  433. } else {
  434. dataArr = this.array_diff(dataArr, plugin);
  435. }
  436. this.filtersArr = dataArr;
  437. return dataArr || [];
  438. // var DataArray = new Array();
  439. // for (var i = 0; i < plugin.length; i++) {
  440. // // 通过行号获取数据
  441. // DataArray.push(this.hot.getSourceDataAtRow(plugin[i]));
  442. // }
  443. },
  444. //去除数组中相同的元素
  445. array_diff(a, b) {
  446. for (var i = 0; i < b.length; i++) {
  447. for (var j = 0; j < a.length; j++) {
  448. if (a[j] == b[i]) {
  449. a.splice(j, 1);
  450. j = j - 1;
  451. }
  452. }
  453. }
  454. return a;
  455. },
  456. //获取动态参数
  457. getBatch(data) {
  458. let param = {
  459. secret: this.secret,
  460. ProjId: this.projectId,
  461. data: {
  462. criterias: []
  463. }
  464. };
  465. this.headers.map(head => {
  466. if (
  467. head.InputMode == "L" ||
  468. head.InputMode == "L1" ||
  469. head.InputMode == "L2" ||
  470. head.InputMode == "M"
  471. ) {
  472. data.map(item => {
  473. let cur = tools.dataForKey(item, head.Path);
  474. if (cur) {
  475. param.data.criterias.push({
  476. id: item.RoomID,
  477. code: head.InfoPointCode
  478. });
  479. }
  480. });
  481. }
  482. });
  483. if (param.data.criterias.length) {
  484. BeatchQueryParam(param, res => {
  485. this.main = data.map(item => {
  486. res.Content.map(child => {
  487. if (item.RoomID == child.id) {
  488. if (child.data || child.data == 0) {
  489. this.headers.map(head => {
  490. if (head.InfoPointCode == child.code) {
  491. tools.setDataForKey(item, head.Path, child.data);
  492. }
  493. });
  494. } else {
  495. this.headers.map(head => {
  496. if (head.InfoPointCode == child.code) {
  497. tools.setDataForKey(
  498. item,
  499. head.Path,
  500. // child.error ? "表号功能号格式错误" : "表号功能号不存在"
  501. child.error ? child.value ? "表号功能号格式错误" : "表号功能号不存在" : "暂未采集到实时数据"
  502. );
  503. }
  504. });
  505. }
  506. }
  507. });
  508. return item;
  509. });
  510. this.hot.loadData(this.main);
  511. });
  512. }
  513. },
  514. /**
  515. * 表头文案处理函数
  516. * @param list header数组数据
  517. *
  518. * @return 处理好的文案
  519. */
  520. delHeader(list) {
  521. let arr = tools.copyArr(list)
  522. let data = showTools.headerTextFilter(arr, "space", this.onlyRead, this.showType)
  523. data.unshift("是否关联平面图", "与空间相关联的设备");
  524. if (this.showType == "all") {
  525. data.splice(4, 0, "所属建筑楼层")
  526. }
  527. return data;
  528. },
  529. /**
  530. * 表头数据处理函数
  531. * @param arr header数组数据
  532. *
  533. * @return 处理好的数据格式
  534. */
  535. getType(list) {
  536. let arr = tools.copyArr(list)
  537. let data = showTools.headerTypeFilter(arr, "space", this.onlyRead, this.showType)
  538. data.unshift({
  539. data: "Outline",
  540. renderer: this.myRenderer,
  541. readOnly: true
  542. }, {
  543. data: "point",
  544. renderer: this.facilityRender,
  545. readOnly: true
  546. });
  547. if (this.showType == "all") {
  548. data.splice(4, 0, {
  549. data: "flowBuild",
  550. renderer: tools.customDropdownRenderer,
  551. editor: "chosen",
  552. chosenOptions: {
  553. data: this.buildFloorData
  554. },
  555. readOnly: this.onlyRead
  556. })
  557. }
  558. return data;
  559. },
  560. myRenderer(instance, td, row, col, prop, value, cellProperties) {
  561. if (value && value.length && value[0]) {
  562. td.innerHTML = "已关联"
  563. } else {
  564. td.innerHTML = "未关联"
  565. }
  566. return td;
  567. },
  568. facilityRender(instance, td, row, col, prop, value, cellProperties) {
  569. td.style.color = "#409EFF"
  570. td.style.cursor = "pointer"
  571. td.innerHTML = "点击查看"
  572. return td;
  573. },
  574. /** 页面中的按钮事件--------------------------- */
  575. addSp() {
  576. if (this.main && this.main.length && this.main[0].RoomID) {
  577. this.hot.destroy()
  578. this.hot = null
  579. this.main.unshift({})
  580. this.getMain()
  581. } else {
  582. if (this.main && this.main.length) {
  583. this.$message("请添加完成后继续添加")
  584. } else {
  585. this.main.unshift({})
  586. this.getMain()
  587. }
  588. }
  589. },
  590. //刷新
  591. reset() {
  592. this.getData()
  593. },
  594. //撤回操作
  595. undo() {
  596. this.hot.undo()
  597. },
  598. /** 分页事件------------------------ */
  599. //切换每页显示多少条数据
  600. handleSizeChange(val) {
  601. this.page.pageSize = val
  602. this.getData()
  603. },
  604. //切换页数
  605. handleCurrentChange(val) {
  606. this.page.pageNumber = val
  607. this.getData()
  608. }
  609. },
  610. watch: {
  611. projectId() {
  612. this.setData()
  613. this.main = null
  614. },
  615. showTypes: {
  616. handler(newName, oldName) {
  617. if (newName && newName[0] && newName[0].value) {
  618. this.showType = newName[0].value
  619. } else {
  620. this.showType = ""
  621. }
  622. },
  623. immediate: true,
  624. deep: true
  625. }
  626. }
  627. };
  628. </script>
  629. <style lang="less" scoped>
  630. #handsontable {
  631. .left {
  632. padding-top: 0;
  633. padding-bottom: 10px;
  634. }
  635. .no-data {
  636. height: 150px;
  637. line-height: 150px;
  638. text-align: center;
  639. color: gray;
  640. }
  641. }
  642. </style>