You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

gridTableSimple.vue 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. <!--
  2. Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. -->
  13. <template>
  14. <div class="cl-slickgrid-container">
  15. <div class="data-show-container">
  16. <div v-show="incorrectData"
  17. class="error-msg-container">
  18. {{$t('components.gridIncorrectDataError')}}
  19. </div>
  20. <div v-show="!incorrectData && requestError"
  21. class="error-msg-container">
  22. {{errorMsg}}
  23. </div>
  24. <div v-show="!fullData.length && updated && !incorrectData && !requestError"
  25. class="error-msg-container">
  26. {{$t('components.gridTableNoData')}}
  27. </div>
  28. <div :id="itemId"
  29. v-show="!!fullData.length && !incorrectData"
  30. class="grid-item"></div>
  31. </div>
  32. <div class="operate-container"
  33. v-if="showOperate && (fullData.length || requestError)">
  34. <div class="filter-container"
  35. @keyup.enter="filterChange">
  36. <div v-for="(item, itemIndex) in filterArr"
  37. :key="itemIndex">
  38. <el-input class="filter-input"
  39. :class="item.showError ? 'error-border' : ''"
  40. v-model="item.model"></el-input>
  41. <span class="input-behind"
  42. v-if="itemIndex === filterArr.length - 1">{{$t('symbols.slashes')}}</span>
  43. <span class="input-behind"
  44. v-else>{{$t('symbols.point')}}</span>
  45. </div>
  46. <el-button class="filter-check"
  47. size="mini"
  48. v-if="!!filterArr.length"
  49. @click="filterChange">
  50. <i class="el-icon-check"></i></el-button>
  51. <span class="filter-incorrect-text"
  52. v-if="!filterCorrect">{{$t('components.inCorrectInput')}}</span>
  53. </div>
  54. <div class="accuracy-container">
  55. {{$t('components.gridAccuracy')}}<el-select v-model="accuracy"
  56. class="select-item"
  57. @change="accuracyChange">
  58. <el-option v-for="item in accuracyArr"
  59. :key="item.label"
  60. :label="item.label"
  61. :value="item.value"></el-option>
  62. </el-select>
  63. <div class="full-screen-icon"
  64. :title="$t('scalar.fullScreen')"
  65. @click="toggleFullScreen"
  66. :class="fullScreen ? 'active-color' : ''">
  67. <span><i class="el-icon-full-screen"></i></span>
  68. </div>
  69. </div>
  70. </div>
  71. </div>
  72. </template>
  73. <script>
  74. import 'slickgrid/css/smoothness/jquery-ui-1.11.3.custom.css';
  75. import 'slickgrid/slick.grid.css';
  76. import 'slickgrid/lib/jquery-3.1.0';
  77. import 'slickgrid/lib/jquery-ui-1.9.2';
  78. import 'slickgrid/lib/jquery.event.drag-2.3.0.js';
  79. import 'slickgrid/slick.core.js';
  80. import 'slickgrid/slick.dataview.js';
  81. import 'slickgrid/slick.grid.js';
  82. export default {
  83. props: {
  84. // Table data
  85. fullData: {
  86. type: Array,
  87. default() {
  88. return [];
  89. },
  90. },
  91. // Display operation Bar
  92. showOperate: {
  93. type: Boolean,
  94. default: true,
  95. },
  96. // Display full screen
  97. fullScreen: {
  98. type: Boolean,
  99. default: false,
  100. },
  101. },
  102. data() {
  103. return {
  104. itemId: '', // Dom id
  105. gridObj: null, // slickgrid object
  106. columnsData: [], // Column information
  107. columnsLength: 0, // Column length
  108. filterArr: [], // Dimension selection array
  109. formateData: [], // formatted data
  110. formateArr: [], // formatted Array
  111. statistics: {}, // Object contain maximun and minimun
  112. accuracy: 5, // accuracy value
  113. incorrectData: false, // Wheather the dimension is correctly selected
  114. updated: false, // Updated
  115. scrollTop: false, // Wheather scroll to the top
  116. filterCorrect: true, // Wheather the dimension input is correct
  117. requestError: false, // Exceeded the specification
  118. errorMsg: '', // Error message
  119. viewResizeFlag: false, // Size reset flag
  120. // Accuray options
  121. accuracyArr: [
  122. {label: 0, value: 0},
  123. {label: 1, value: 1},
  124. {label: 2, value: 2},
  125. {label: 3, value: 3},
  126. {label: 4, value: 4},
  127. {label: 5, value: 5},
  128. ],
  129. // Table configuration items
  130. optionObj: {
  131. enableColumnReorder: false,
  132. enableCellNavigation: true,
  133. frozenColumn: 0,
  134. frozenRow: 0,
  135. },
  136. };
  137. },
  138. computed: {},
  139. watch: {},
  140. mounted() {
  141. this.init();
  142. },
  143. methods: {
  144. /**
  145. * Initialize
  146. */
  147. init() {
  148. this.itemId =
  149. `${new Date().getTime()}` + `${this.$store.state.componentsCount}`;
  150. this.$store.commit('componentsNum');
  151. },
  152. /**
  153. * Initialize dimension selection
  154. * @param {Array} dimension Dimension array
  155. * @param {String} filterStr Dimension String
  156. */
  157. initializeFilterArr(dimension, filterStr) {
  158. if (!filterStr) {
  159. this.filterArr = [];
  160. return;
  161. }
  162. const tempFilterArr = filterStr.slice(1, filterStr.length - 1).split(',');
  163. const tempArr = [];
  164. for (let i = 0; i < tempFilterArr.length; i++) {
  165. tempArr.push({
  166. model: tempFilterArr[i],
  167. max: dimension[i] - 1,
  168. showError: false,
  169. });
  170. }
  171. this.filterArr = tempArr;
  172. },
  173. /**
  174. * Initialize column information
  175. */
  176. formateColumnsData() {
  177. this.columnsData = [
  178. {
  179. id: -1,
  180. name: ' ',
  181. field: -1,
  182. width: 100,
  183. headerCssClass: 'headerStyle',
  184. },
  185. ];
  186. const columnSample = this.formateData[0];
  187. if (columnSample) {
  188. columnSample.forEach((num, numIndex) => {
  189. const order = numIndex;
  190. this.columnsData.push({
  191. id: order,
  192. name: order,
  193. field: order,
  194. width: 100,
  195. headerCssClass: 'headerStyle',
  196. formatter: this.formateValueColor,
  197. });
  198. });
  199. } else {
  200. this.columnsData = [];
  201. }
  202. },
  203. /**
  204. * Setting the Background color of data
  205. * @param {Number} row
  206. * @param {Number} cell
  207. * @param {String} value,
  208. * @param {Object} columnDef
  209. * @param {Object} dataContext
  210. * @return {String}
  211. */
  212. formateValueColor(row, cell, value, columnDef, dataContext) {
  213. if (
  214. !cell ||
  215. !value ||
  216. isNaN(value) ||
  217. value === Infinity ||
  218. value === -Infinity
  219. ) {
  220. return value;
  221. } else if (value < 0) {
  222. return `<span class="table-item-span" style="background:rgba(94, 124, 224, ${value /
  223. this.statistics.min})">${value}</span>`;
  224. } else {
  225. return `<span class="table-item-span" style="background:rgba(246, 111, 106, ${value /
  226. this.statistics.max})">${value}</span>`;
  227. }
  228. },
  229. /**
  230. * Convetring raw data into table data
  231. */
  232. formateGridArray() {
  233. if (this.fullData instanceof Array) {
  234. if (this.fullData.length) {
  235. if (this.fullData[0] instanceof Array) {
  236. this.formateData = this.fullData;
  237. } else {
  238. this.formateData = [this.fullData];
  239. }
  240. } else {
  241. this.formateData = [[]];
  242. this.columnsData = [];
  243. }
  244. } else {
  245. this.formateData = [[this.fullData]];
  246. }
  247. const tempArr = [];
  248. this.formateData.forEach((outerData, outerIndex) => {
  249. const tempData = {
  250. '-1': outerIndex,
  251. };
  252. outerData.forEach((innerData, innerIndex) => {
  253. const innerOrder = innerIndex;
  254. if (isNaN(innerData)) {
  255. tempData[innerOrder] = innerData;
  256. } else {
  257. tempData[innerOrder] = innerData.toFixed(this.accuracy);
  258. }
  259. });
  260. tempArr.push(tempData);
  261. });
  262. this.formateArr = tempArr;
  263. },
  264. /**
  265. * Update the table
  266. */
  267. updateGrid() {
  268. this.$nextTick(() => {
  269. if (!this.gridObj) {
  270. this.gridObj = new Slick.Grid(
  271. `#${this.itemId}`,
  272. this.formateArr,
  273. this.columnsData,
  274. this.optionObj,
  275. );
  276. this.columnsLength = this.columnsData.length;
  277. }
  278. this.gridObj.setData(this.formateArr, this.scrollTop);
  279. this.scrollTop = false;
  280. const columnsLength = this.columnsData.length;
  281. if (this.columnsLength !== columnsLength || this.viewResizeFlag) {
  282. this.gridObj.setColumns(this.columnsData);
  283. this.columnsLength = columnsLength;
  284. this.viewResizeFlag = false;
  285. }
  286. this.gridObj.render();
  287. });
  288. },
  289. /**
  290. * accuracy changed
  291. * @param {Number} value The value after changed
  292. */
  293. accuracyChange(value) {
  294. this.formateGridArray();
  295. if (!this.requestError && !this.incorrectData) {
  296. this.updateGrid();
  297. }
  298. },
  299. /**
  300. * Dimension selection changed
  301. */
  302. filterChange() {
  303. // 校验检索条件
  304. let filterCorrect = true;
  305. let incorrectData = false;
  306. let limitCount = 2;
  307. const tempArr = [];
  308. this.filterArr.forEach((filter) => {
  309. let value = filter.model.trim();
  310. if (!isNaN(value)) {
  311. if (
  312. value < -(filter.max + 1) ||
  313. value > filter.max ||
  314. value === '' ||
  315. value % 1
  316. ) {
  317. filter.showError = true;
  318. filterCorrect = false;
  319. } else {
  320. filter.showError = false;
  321. value = Number(value);
  322. }
  323. } else if (value === ':') {
  324. filter.showError = false;
  325. if (!limitCount) {
  326. incorrectData = true;
  327. } else {
  328. limitCount--;
  329. }
  330. } else {
  331. filter.showError = true;
  332. filterCorrect = false;
  333. }
  334. tempArr.push(value);
  335. });
  336. this.filterCorrect = filterCorrect;
  337. if (incorrectData && filterCorrect) {
  338. this.incorrectData = true;
  339. return;
  340. } else {
  341. this.incorrectData = false;
  342. }
  343. if (filterCorrect) {
  344. this.$emit('martixFilterChange', tempArr);
  345. }
  346. },
  347. /**
  348. * Updating Table Data
  349. * @param {Boolean} newDataFlag Wheather data is updated
  350. * @param {Array} dimension Array of dimension
  351. * @param {Object} statistics Object contains maximun and minimun
  352. * @param {String} filterStr String of dimension selection
  353. */
  354. updateGridData(newDataFlag, dimension, statistics, filterStr) {
  355. this.updated = true;
  356. this.requestError = false;
  357. this.$nextTick(() => {
  358. if (!this.fullData || !this.fullData.length) {
  359. return;
  360. }
  361. if (newDataFlag) {
  362. this.initializeFilterArr(dimension, filterStr);
  363. this.scrollTop = true;
  364. }
  365. if (newDataFlag || this.statistics.max === undefined) {
  366. this.statistics = statistics;
  367. }
  368. this.formateGridArray();
  369. this.formateColumnsData();
  370. if (!this.incorrectData) {
  371. this.updateGrid();
  372. }
  373. });
  374. },
  375. /**
  376. * Update the view Size
  377. */
  378. resizeView() {
  379. if (this.gridObj) {
  380. if (this.incorrectData || this.requestError) {
  381. this.viewResizeFlag = true;
  382. } else {
  383. this.$nextTick(() => {
  384. this.gridObj.resizeCanvas();
  385. this.gridObj.render();
  386. });
  387. }
  388. }
  389. },
  390. /**
  391. * Expand/Collapse in full screen
  392. */
  393. toggleFullScreen() {
  394. this.$emit('toggleFullScreen');
  395. },
  396. /**
  397. * Show Error message
  398. * @param {String} errorMsg Error message
  399. * @param {Array} dimension Array of dimension
  400. * @param {String} filterStr String of dimension selection
  401. */
  402. showRequestErrorMessage(errorMsg, dimension, filterStr) {
  403. this.errorMsg = errorMsg;
  404. if (!this.filterArr.length && dimension && filterStr) {
  405. this.initializeFilterArr(dimension, filterStr);
  406. }
  407. this.requestError = true;
  408. },
  409. },
  410. destroyed() {},
  411. };
  412. </script>
  413. <style lang="scss">
  414. .cl-slickgrid-container {
  415. width: 100%;
  416. height: 100%;
  417. display: flex;
  418. flex-direction: column;
  419. .data-show-container {
  420. width: 100%;
  421. flex: 1;
  422. .grid-item {
  423. width: 100%;
  424. height: 100%;
  425. }
  426. .error-msg-container {
  427. width: 100%;
  428. height: 100%;
  429. display: flex;
  430. align-items: center;
  431. justify-content: center;
  432. }
  433. }
  434. .info-show-container {
  435. width: 100%;
  436. }
  437. .operate-container {
  438. width: 100%;
  439. text-overflow: ellipsis;
  440. white-space: nowrap;
  441. overflow: hidden;
  442. z-index: 99;
  443. flex-wrap: wrap;
  444. .full-screen-icon {
  445. float: right;
  446. margin-left: 15px;
  447. height: 100%;
  448. line-height: 34px;
  449. cursor: pointer;
  450. :hover {
  451. color: #3e98c5;
  452. }
  453. }
  454. .active-color {
  455. color: #3e98c5;
  456. }
  457. .filter-container {
  458. float: left;
  459. flex-wrap: wrap;
  460. display: flex;
  461. .error-border {
  462. input {
  463. border-color: red;
  464. }
  465. }
  466. .filter-input {
  467. width: 50px;
  468. text-align: center;
  469. }
  470. .input-behind {
  471. padding: 0 5px;
  472. }
  473. .filter-incorrect-text {
  474. margin-left: 10px;
  475. line-height: 32px;
  476. color: red;
  477. }
  478. }
  479. .accuracy-container {
  480. float: right;
  481. .select-item {
  482. width: 60px;
  483. }
  484. }
  485. }
  486. }
  487. .slick-cell,
  488. .slick-headerrow-column,
  489. .slick-footerrow-column {
  490. padding: 0;
  491. border-top: none;
  492. border-left: none;
  493. text-align: center;
  494. }
  495. .grid-canvas-left .slick-cell {
  496. height: 54px;
  497. }
  498. .slick-viewport-left {
  499. overflow: hidden !important;
  500. }
  501. .slick-viewport-left .slick-row {
  502. background-color: white !important;
  503. ::-webkit-scrollbar {
  504. width: 0px;
  505. }
  506. }
  507. .ui-widget-content {
  508. background: none;
  509. }
  510. .headerStyle {
  511. vertical-align: middle;
  512. text-align: center;
  513. }
  514. .filter-check {
  515. font-size: 18px;
  516. color: #00a5a7;
  517. cursor: pointer;
  518. }
  519. .table-item-span {
  520. display: block;
  521. width: 100%;
  522. height: 100%;
  523. text-align: center;
  524. }
  525. </style>