handsontable.vue 17 KB

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