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

1118 lines
32 KiB

  1. <template>
  2. <view class="wyb-table-box">
  3. <view v-if="loading" class="wyb-table-loading-box" :style="{
  4. width: width === 'auto' ? screenWidth : width,
  5. height: height === 'auto' ? '300rpx' : height,
  6. backgroundColor: loaderBgColor,
  7. borderTop: '1px solid' + borderColor,
  8. borderBottom: '1px solid' + borderColor,
  9. borderLeft: showLeftAndRightBorder ? '1px solid' + borderColor : 'none',
  10. borderRight: showLeftAndRightBorder ? '1px solid' + borderColor : 'none'}">
  11. <view class="loader-one" :style="{
  12. width: loaderSize + 'rpx',
  13. height: loaderSize + 'rpx',
  14. borderTop: '3px solid ' + loadingColor.top,
  15. borderRight: '3px solid ' + loadingColor.right,
  16. borderBottom: '3px solid ' + loadingColor.bottom,
  17. borderLeft: '3px solid ' + loadingColor.left}" />
  18. </view>
  19. <view v-if="!loading" class="wyb-table-scroll-view" :style="{
  20. width: width,
  21. height: height,
  22. borderTop: '1px solid' + borderColor,
  23. borderLeft: showLeftAndRightBorder ? '1px solid' + borderColor : 'none',
  24. borderRight: showLeftAndRightBorder ? '1px solid' + borderColor : 'none'}">
  25. <view class="wyb-table-header" :style="{borderBottom: '1px solid' + borderColor}">
  26. <view class="wyb-table-header-item" v-if="enableCheck" :style="{
  27. minWidth: checkColWidth + 'rpx',
  28. maxWidth: checkColWidth + 'rpx',
  29. minHeight: minHeight[0] + 'rpx',
  30. textAlign: textAlign,
  31. justifyContent: textAlign === 'center' ? textAlign : (textAlign === 'left' ? 'flex-start' : 'flex-end'),
  32. fontSize: fontSize[0] + 'rpx',
  33. color: headerFtColor,
  34. padding: padding[0] + 'rpx ' + (padding[1] || padding[0]) + 'rpx',
  35. backgroundColor: headerBgColor,
  36. borderRight: '1px solid' + borderColor,
  37. zIndex: 30,
  38. left: 0,
  39. color: headerFtColor,
  40. backgroundColor: headerBgColor,
  41. position: 'sticky'}">
  42. <view
  43. class="wyb-table-checkbox"
  44. v-if="enableCheck === 'multiple'"
  45. @tap.stop="onCheckAllTap"
  46. :style="{
  47. width: checkColWidth * 0.5 + 'rpx',
  48. height: checkColWidth * 0.5 + 'rpx',
  49. backgroundColor: checkerBoxBgColor,
  50. border: '1px solid ' + checkerBorderColor}">
  51. <text
  52. class="iconfont icon-check"
  53. v-show="checkAll"
  54. :style="{
  55. color: checkerColor,
  56. backgroundColor: checkerBgColor,
  57. paddingTop: (fontSize[1] || fontSize[0]) * 0.15 + 'rpx',
  58. fontSize: (fontSize[1] || fontSize[0]) + 'rpx'}" />
  59. </view>
  60. </view>
  61. <view ref="iosBug" class="wyb-table-header-item" v-for="(item, index) in headers" :key="item.key" @tap="onHeaderItemTap(index)"
  62. :style="{
  63. minWidth: (item.width || defaultColWidth) + 'rpx',
  64. maxWidth: (item.width || defaultColWidth) + 'rpx',
  65. minHeight: minHeight[0] + 'rpx',
  66. textAlign: textAlign,
  67. justifyContent: textAlign === 'center' ? textAlign : (textAlign === 'left' ? 'flex-start' : 'flex-end'),
  68. fontSize: fontSize[0] + 'rpx',
  69. fontWeight: headerWeight ? 'bold' : 'normal',
  70. color: headerFtColor,
  71. padding: padding[0] + 'rpx ' + (padding[1] || padding[0]) + 'rpx',
  72. backgroundColor: headerBgColor,
  73. borderRight: index === headers.length - 1 || (!showVertBorder && index !== 0) ? 'none' : '1px solid' + borderColor,
  74. zIndex: index === 0 ? 20 : 0,
  75. left: index === 0 && firstLineFixed ? (enableCheck ? checkColWidth + 'rpx' : 0) : 'auto',
  76. position: index === 0 ? 'sticky' : 'static'}">
  77. <text :style="{marginLeft: autoSortShow(index) && textAlign !== 'left' ? fontSize[0] * 0.65 + 'rpx' : 0}">
  78. {{item.label || emptyString}}
  79. </text>
  80. <view class="wyb-table-header-icon" v-if="autoSortShow(index)">
  81. <text class="iconfont icon-arrow-up" :style="{
  82. color: sortWays[sortWay] === 'asc' && sortActiveKey === item.key ?
  83. headerFtColor : RGBChange(headerFtColor, 0.7, 'light'),
  84. fontWeight: 'normal',
  85. marginBottom: '-12px',
  86. transform: 'scale(0.4)'}" />
  87. <text class="iconfont icon-arrow-down" :style="{
  88. color: sortWays[sortWay] === 'inv' && sortActiveKey === item.key ?
  89. headerFtColor : RGBChange(headerFtColor, 0.7, 'light'),
  90. fontWeight: 'normal',
  91. transform: 'scale(0.4)'}" />
  92. </view>
  93. </view>
  94. </view>
  95. <view class="wyb-table-content">
  96. <view class="wyb-table-content-line" v-for="(content, cIndex) in contentsSort" :key="contentLineKey(content, cIndex)"
  97. :style="{borderTop: cIndex === 0 ? 'none' : '1px solid' + borderColor}">
  98. <view class="wyb-table-content-item" v-if="enableCheck" :style="{
  99. minWidth: checkColWidth + 'rpx',
  100. maxWidth: checkColWidth + 'rpx',
  101. textAlign: textAlign,
  102. justifyContent: textAlign === 'center' ? textAlign : (textAlign === 'left' ? 'flex-start' : 'flex-end'),
  103. fontSize: (fontSize[1] || fontSize[0]) + 'rpx',
  104. minHeight: (minHeight[1] || minHeight[0]) + 'rpx',
  105. padding: padding[0] + 'rpx ' + (padding[1] || padding[0]) + 'rpx',
  106. borderRight: '1px solid' + borderColor,
  107. zIndex: 21,
  108. color: contentFtColor,
  109. backgroundColor: checkerCellBgColor,
  110. left: 0,
  111. position: 'sticky'}">
  112. <view
  113. class="wyb-table-checkbox"
  114. @tap.stop="onCheckItemTap(cIndex)"
  115. :style="{
  116. width: checkColWidth * 0.5 + 'rpx',
  117. height: checkColWidth * 0.5 + 'rpx',
  118. backgroundColor: checkerBoxBgColor,
  119. border: '1px solid ' + checkerBorderColor}">
  120. <text
  121. class="iconfont icon-check"
  122. v-show="contentsSort[cIndex].checked"
  123. :style="{
  124. color: checkerColor,
  125. backgroundColor: checkerBgColor,
  126. paddingTop: (fontSize[1] || fontSize[0]) * 0.15 + 'rpx',
  127. fontSize: (fontSize[1] || fontSize[0]) + 'rpx'}" />
  128. </view>
  129. </view>
  130. <view
  131. class="wyb-table-content-item"
  132. v-for="(header, hIndex) in headers"
  133. @tap.stop="onContentItemTap(cIndex, hIndex)"
  134. :key="contentItemKey(header, hIndex)"
  135. :style="{
  136. minWidth: (header.width || defaultColWidth) + 'rpx',
  137. maxWidth: (header.width || defaultColWidth) + 'rpx',
  138. textAlign: textAlign,
  139. justifyContent: textAlign === 'center' ? textAlign : (textAlign === 'left' ? 'flex-start' : 'flex-end'),
  140. fontSize: (fontSize[1] || fontSize[0]) + 'rpx',
  141. textDecoration: autoTextDecoration(cIndex, hIndex),
  142. color: autoContentColor(cIndex, hIndex),
  143. backgroundColor: autoContentBgColor(cIndex, hIndex),
  144. minHeight: (minHeight[1] || minHeight[0]) + 'rpx',
  145. padding: padding[0] + 'rpx ' + (padding[1] || padding[0]) + 'rpx',
  146. borderBottom: cIndex === contents.length - 1 ? '1px solid' + borderColor : 'none',
  147. borderRight: hIndex === headers.length - 1 || (!showVertBorder && hIndex !== 0) ? 'none' : '1px solid' + borderColor,
  148. zIndex: hIndex === 0 ? 20 : 0,
  149. left: enableCheck ? checkColWidth + 'rpx' : 0,
  150. position: hIndex === 0 && firstLineFixed ? 'sticky' : 'static'}">{{autoContentItem(cIndex, hIndex)}}</view>
  151. </view>
  152. <view v-if="computedCol.length !== 0" class="wyb-table-content-line" :style="{
  153. position: bottomComputedFixed ? 'sticky' : 'static',
  154. bottom: 0,
  155. zIndex: 25,
  156. borderTop: '1px solid' + borderColor}">
  157. <view class="wyb-table-content-item" v-if="enableCheck" :style="{
  158. minWidth: checkColWidth + 'rpx',
  159. maxWidth: checkColWidth + 'rpx',
  160. textAlign: textAlign,
  161. justifyContent: textAlign === 'center' ? textAlign : (textAlign === 'left' ? 'flex-start' : 'flex-end'),
  162. fontSize: (fontSize[1] || fontSize[0]) + 'rpx',
  163. minHeight: (minHeight[1] || minHeight[0]) + 'rpx',
  164. padding: padding[0] + 'rpx ' + (padding[1] || padding[0]) + 'rpx',
  165. borderBottom: '1px solid' + borderColor,
  166. borderRight: '1px solid' + borderColor,
  167. zIndex: 25,
  168. color: contentFtColor,
  169. backgroundColor: checkerCellBgColor,
  170. left: 0,
  171. position: 'sticky'}"></view>
  172. <view class="wyb-table-content-item" v-for="(header, index) in headers" :key="index"
  173. :style="{
  174. minWidth: (header.width || defaultColWidth) + 'rpx',
  175. maxWidth: (header.width || defaultColWidth) + 'rpx',
  176. textAlign: textAlign,
  177. justifyContent: textAlign === 'center' ? textAlign : (textAlign === 'left' ? 'flex-start' : 'flex-end'),
  178. fontSize: (fontSize[1] || fontSize[0]) + 'rpx',
  179. color: contentFtColor,
  180. minHeight: (minHeight[1] || minHeight[0]) + 'rpx',
  181. padding: padding[0] + 'rpx ' + (padding[1] || padding[0]) + 'rpx',
  182. backgroundColor: index === 0 ? firstColBgColor : contentBgColor,
  183. borderBottom: '1px solid' + borderColor,
  184. borderRight: index === headers.length - 1 || (!showVertBorder && index !== 0) ? 'none' : '1px solid' + borderColor,
  185. zIndex: index === 0 ? 20 : 0,
  186. left: enableCheck ? checkColWidth + 'rpx' : 0,
  187. position: index === 0 && firstLineFixed ? 'sticky' : 'static'}">
  188. {{autoBottomComputedItem(index)}}
  189. </view>
  190. </view>
  191. </view>
  192. </view>
  193. </view>
  194. </template>
  195. <script>
  196. import Pinyin from '../../static/table/characterToPinyin.js'
  197. import {isEqual} from '../../static/table/objEqual.js'
  198. export default {
  199. data() {
  200. return {
  201. bottomComputed: [],
  202. colorList: [],
  203. bgColorList: [],
  204. contentsSort: this.contents.slice(),
  205. oContentsSort: [],
  206. sortWay: 0,
  207. sortKeys: [],
  208. sortActiveKey: '',
  209. sortIsNumbers: [],
  210. checkAll: false,
  211. checkList: [],
  212. onload: true,
  213. event: {
  214. checkType: this.enableCheck,
  215. data: []
  216. },
  217. chars: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
  218. }
  219. },
  220. computed: {
  221. loadingColor() {
  222. let color = this.loaderColor.slice()
  223. let rgbList = this.hexToRgb(color)
  224. let top = 'rgba(' + rgbList[0] + ',' + rgbList[1] + ',' + rgbList[2] + ', 0.3)'
  225. let bottom = 'rgba(' + rgbList[0] + ',' + rgbList[1] + ',' + rgbList[2] + ', 0.3)'
  226. let right = 'rgba(' + rgbList[0] + ',' + rgbList[1] + ',' + rgbList[2] + ', 0.3)'
  227. let left = 'rgb(' + rgbList[0] + ',' + rgbList[1] + ',' + rgbList[2] + ')'
  228. return {
  229. top,
  230. bottom,
  231. right,
  232. left
  233. }
  234. },
  235. contentLineKey() {
  236. return function(content, cIndex) {
  237. return this.randomString(32, this.chars)
  238. }
  239. },
  240. contentItemKey() {
  241. return function(header, hIndex) {
  242. return this.randomString(16, this.chars)
  243. }
  244. },
  245. autoContentItem() {
  246. return function(cIndex, hIndex) {
  247. let content = this.contentsSort[cIndex]
  248. let header = this.headers[hIndex]
  249. let result = ''
  250. if (content[header.key] || content[header.key] === 0) {
  251. result = content[header.key]
  252. if (this.urlCol.length !== 0) {
  253. for (let i in this.urlCol) {
  254. let item = this.urlCol[i]
  255. if (header.key === item.key) {
  256. // 该单元格为链接
  257. result = content[header.key][0]
  258. }
  259. }
  260. }
  261. if (this.formatCol.length !== 0) {
  262. this.formatCol.forEach(item => {
  263. if (header.key === item.key) {
  264. let needRplace = new RegExp(`\#${item['key']}\#`, 'mg')
  265. result = item.template.replace(needRplace, result)
  266. }
  267. })
  268. }
  269. } else {
  270. result = this.emptyString
  271. }
  272. return result
  273. }
  274. },
  275. autoBottomComputedItem() {
  276. return function(index) {
  277. let bottomComputed = {}
  278. let needComputed = []
  279. this.computedCol.forEach(key => {
  280. let computedColData = []
  281. this.contentsSort.forEach(content => {
  282. computedColData.push(content[key] || '0')
  283. })
  284. needComputed.push(computedColData)
  285. })
  286. needComputed.forEach((item, index) => {
  287. let total = 0
  288. item.forEach(num => {
  289. total += parseFloat(num)
  290. })
  291. bottomComputed[this.computedCol[index]] = total
  292. })
  293. let header = this.headers[index]
  294. let result = this.computedCol.includes(header.key) ?
  295. bottomComputed[header.key] : (index === 0 ? '总计' : this.emptyString)
  296. if (this.formatCol.length !== 0) {
  297. this.formatCol.forEach(item => {
  298. if (item.bottomComputedFormat) {
  299. if (header.key === item.key) {
  300. let needRplace = new RegExp(`\#${item['key']}\#`, 'mg')
  301. result = item.template.replace(needRplace, bottomComputed[item.key])
  302. }
  303. }
  304. })
  305. }
  306. return result
  307. }
  308. },
  309. autoTextDecoration() {
  310. return function(cIndex, hIndex) {
  311. let result = 'auto'
  312. let content = this.contentsSort[cIndex]
  313. let header = this.headers[hIndex]
  314. if (this.urlCol.length !== 0) {
  315. for (let i in this.urlCol) {
  316. let item = this.urlCol[i]
  317. if (header.key === item.key) {
  318. // 该单元格为链接
  319. if (content[header.key]) {
  320. result = 'underline'
  321. }
  322. }
  323. }
  324. }
  325. return result
  326. }
  327. },
  328. autoContentBgColor() {
  329. return function(cIndex, hIndex) {
  330. let result = this.contentBgColor
  331. let content = this.contentsSort[cIndex]
  332. let header = this.headers[hIndex]
  333. let keys = []
  334. // 先判断是不是首列,设置基础样式
  335. if (hIndex === 0) {
  336. result = this.firstColBgColor
  337. }
  338. // 再判断条件格式传没传值,设置条件样式
  339. if (this.valueFormat.length !== 0) {
  340. this.valueFormat.forEach(item => {
  341. keys.push(item.key)
  342. })
  343. if (keys.includes(header.key)) {
  344. // 该列开启了条件格式
  345. let key = header.key
  346. let type = this.valueFormat[keys.indexOf(key)].type
  347. let style = this.valueFormat[keys.indexOf(key)].style
  348. let range = this.valueFormat[keys.indexOf(key)].range || ''
  349. switch(type) {
  350. case 'bigger':
  351. if (parseFloat(content[key]) > range) {
  352. if (style.bgColor) result = style.bgColor
  353. }
  354. break
  355. case 'smaller':
  356. if (parseFloat(content[key]) < range) {
  357. if (style.bgColor) result = style.bgColor
  358. }
  359. break
  360. case 'equal':
  361. let val
  362. if (typeof range === 'number') val = parseFloat(content[key])
  363. else val = content[key]
  364. if (val === range) {
  365. if (style.bgColor) result = style.bgColor
  366. }
  367. break
  368. case 'range':
  369. if (parseFloat(content[key]) > range[0] && parseFloat(content[key]) < range[1]){
  370. if (style.bgColor) result = style.bgColor
  371. }
  372. break
  373. case 'average-bigger':
  374. let average = this.getAverage(key)
  375. if (parseFloat(content[key]) > average) {
  376. if (style.bgColor) result = style.bgColor
  377. }
  378. break
  379. case 'average-smaller':
  380. average = this.getAverage(key)
  381. if (parseFloat(content[key]) < average) {
  382. if (style.bgColor) result = style.bgColor
  383. }
  384. break
  385. case 'average-equal':
  386. average = this.getAverage(key)
  387. if (parseFloat(content[key]) === average) {
  388. if (style.bgColor) result = style.bgColor
  389. }
  390. break
  391. }
  392. }
  393. }
  394. return result
  395. }
  396. },
  397. autoContentColor() {
  398. return function(cIndex, hIndex) {
  399. let result = this.contentFtColor
  400. let content = this.contentsSort[cIndex]
  401. let header = this.headers[hIndex]
  402. let keys = []
  403. // 先判断是不是链接,设置基础样式
  404. if (this.urlCol.length !== 0) {
  405. for (let i in this.urlCol) {
  406. let item = this.urlCol[i]
  407. if (header.key === item.key) {
  408. // 该单元格为链接
  409. if (content[header.key]) {
  410. result = this.linkColor
  411. }
  412. }
  413. }
  414. }
  415. // 再判断条件格式传没传值,设置条件样式
  416. if (this.valueFormat.length !== 0) {
  417. this.valueFormat.forEach(item => {
  418. keys.push(item.key)
  419. })
  420. if (keys.includes(header.key)) {
  421. // 该列开启了条件格式
  422. let key = header.key
  423. let type = this.valueFormat[keys.indexOf(key)].type
  424. let style = this.valueFormat[keys.indexOf(key)].style
  425. let range = this.valueFormat[keys.indexOf(key)].range || ''
  426. switch(type) {
  427. case 'bigger':
  428. if (parseFloat(content[key]) > range) {
  429. if (style.color) result = style.color
  430. }
  431. break
  432. case 'smaller':
  433. if (parseFloat(content[key]) < range) {
  434. if (style.color) result = style.color
  435. }
  436. break
  437. case 'equal':
  438. let val
  439. if (typeof range === 'number') val = parseFloat(content[key])
  440. else val = content[key]
  441. if (val === range) {
  442. if (style.color) result = style.color
  443. }
  444. break
  445. case 'range':
  446. if (parseFloat(content[key]) > range[0] && parseFloat(content[key]) < range[1]){
  447. if (style.color) result = style.color
  448. }
  449. break
  450. case 'average-bigger':
  451. let average = this.getAverage(key)
  452. if (parseFloat(content[key]) > average) {
  453. if (style.color) result = style.color
  454. }
  455. break
  456. case 'average-smaller':
  457. average = this.getAverage(key)
  458. if (parseFloat(content[key]) < average) {
  459. if (style.color) result = style.color
  460. }
  461. break
  462. case 'average-equal':
  463. average = this.getAverage(key)
  464. if (parseFloat(content[key]) === average) {
  465. if (style.color) result = style.color
  466. }
  467. break
  468. }
  469. }
  470. }
  471. return result
  472. }
  473. },
  474. autoSortShow() {
  475. return function(hIndex) {
  476. let result = false
  477. let header = this.headers[hIndex]
  478. let keys = []
  479. // 判断排序是否传值
  480. if (this.sortCol.length !== 0 && this.sortKeys.length === 0) {
  481. this.sortCol.forEach(item => {
  482. keys.push(item.key)
  483. })
  484. this.sortKeys = keys
  485. if (keys.includes(header.key)) {
  486. result = true
  487. }
  488. } else if (this.sortCol.length !== 0) {
  489. if (this.sortKeys.includes(header.key)) {
  490. result = true
  491. }
  492. }
  493. return result
  494. }
  495. },
  496. screenWidth() {
  497. return `${uni.getSystemInfoSync()['screenWidth']}px`
  498. }
  499. },
  500. props: {
  501. headers: {
  502. type: Array,
  503. default() {
  504. return []
  505. }
  506. },
  507. contents: {
  508. type: Array,
  509. default() {
  510. return []
  511. }
  512. },
  513. emptyString: {
  514. type: String,
  515. default: '-'
  516. },
  517. width: {
  518. type: String,
  519. default: "100%"
  520. },
  521. height: {
  522. type: String,
  523. default: 'auto'
  524. },
  525. fontSize: {
  526. type: Array,
  527. default() {
  528. return [24]
  529. }
  530. },
  531. defaultColWidth: {
  532. type: Number,
  533. default: 176
  534. },
  535. headerWeight: {
  536. type: Boolean,
  537. default: true
  538. },
  539. minHeight: {
  540. type: Array,
  541. default() {
  542. return [70]
  543. }
  544. },
  545. headerBgColor: {
  546. type: String,
  547. default: '#24ABFD'
  548. },
  549. contentBgColor: {
  550. type: String,
  551. default: '#DADADA'
  552. },
  553. headerFtColor: {
  554. type: String,
  555. default: '#fff'
  556. },
  557. contentFtColor: {
  558. type: String,
  559. default: '#3e3e3e'
  560. },
  561. linkColor: {
  562. type: String,
  563. default: '#0024c8'
  564. },
  565. firstColBgColor: {
  566. type: String,
  567. default: '#DADADA'
  568. },
  569. firstLineFixed: {
  570. type: Boolean,
  571. default: false
  572. },
  573. textAlign: {
  574. type: String,
  575. default: 'center'
  576. },
  577. padding: {
  578. type: Array,
  579. default() {
  580. return [5, 10]
  581. }
  582. },
  583. borderColor: {
  584. type: String,
  585. default: '#fff'
  586. },
  587. urlCol: {
  588. type: Array,
  589. default() {
  590. return []
  591. }
  592. },
  593. computedCol: {
  594. type: Array,
  595. default() {
  596. return []
  597. }
  598. },
  599. bottomComputedFixed: {
  600. type: Boolean,
  601. default: true
  602. },
  603. valueFormat: {
  604. type: Array,
  605. default() {
  606. return []
  607. }
  608. },
  609. formatCol: {
  610. type: Array,
  611. default() {
  612. return []
  613. }
  614. },
  615. showLeftAndRightBorder: {
  616. type: Boolean,
  617. default: false
  618. },
  619. showVertBorder: {
  620. type: Boolean,
  621. default: true
  622. },
  623. sortCol: {
  624. type: Array,
  625. default() {
  626. return []
  627. }
  628. },
  629. sortWays: {
  630. type: Array,
  631. default() {
  632. return ['none', 'asc', 'inv']
  633. }
  634. },
  635. loading: {
  636. type: Boolean,
  637. default: false
  638. },
  639. loaderSize: {
  640. type: [String, Number],
  641. default: 50
  642. },
  643. loaderColor: {
  644. type: String,
  645. default: '#a3a3a3'
  646. },
  647. loaderBgColor: {
  648. type: String,
  649. default: '#f8f8f8'
  650. },
  651. enableCheck: {
  652. type: String,
  653. default: ''
  654. },
  655. checkColWidth: {
  656. type: [String, Number],
  657. default: '70'
  658. },
  659. checkerColor: {
  660. type: String,
  661. default: '#3e3e3e'
  662. },
  663. checkerBorderColor: {
  664. type: String,
  665. default: '#d3d3d3'
  666. },
  667. checkerBgColor: {
  668. type: String,
  669. default: 'rgba(0, 0, 0, 0)'
  670. },
  671. checkerBoxBgColor: {
  672. type: String,
  673. default: 'rgba(0, 0, 0, 0)'
  674. },
  675. checkerCellBgColor: {
  676. type: String,
  677. default: '#f1f1f1'
  678. }
  679. },
  680. watch: {
  681. headers(val) {
  682. this.$forceUpdate()
  683. },
  684. contents(val) {
  685. this.contentsSort = val.slice()
  686. if (this.onload) {
  687. this.contentsSort.forEach(item => {
  688. this.$set(item, 'checked', false)
  689. })
  690. this.oContentsSort = this.contentsSort.slice()
  691. this.onload = false
  692. }
  693. this.$forceUpdate()
  694. }
  695. },
  696. mounted() {
  697. this.contentsSort.forEach(item => {
  698. this.$set(item, 'checked', false)
  699. })
  700. this.oContentsSort = this.contentsSort.slice()
  701. if (this.sortCol.length !== 0) {
  702. this.sortActiveKey = this.sortCol[0].key
  703. uni.setStorageSync('lastSortActiveKey', this.sortActiveKey)
  704. this.doSort(this.sortCol[0].key, this.sortWays[this.sortWay], this.sortCol[0].isNumber)
  705. }
  706. },
  707. methods: {
  708. doSort(key, type, isNumber) {
  709. let arr = this.contentsSort
  710. if (type === 'asc') {
  711. // 升序
  712. if (isNumber) {
  713. arr.sort((a, b) => {
  714. let a1 = (parseFloat(a[key].toString().replace(/[^0-9]/ig, "")) || 0);
  715. let b1 = (parseFloat(b[key].toString().replace(/[^0-9]/ig, "")) || 0);
  716. a1 = a[key] < 0 ? - a1 : a1;
  717. b1 = b[key] < 0 ? - b1 : b1;
  718. return a1 - b1
  719. })
  720. } else {
  721. arr.sort((a, b) => {
  722. let A = Pinyin.getSpell(a[key].charAt(0), function(charactor, spell) {
  723. return spell[1]
  724. }).charAt(0).charCodeAt()
  725. let B = Pinyin.getSpell(b[key].charAt(0), function(charactor, spell) {
  726. return spell[1]
  727. }).charAt(0).charCodeAt()
  728. return A - B
  729. })
  730. }
  731. } else if (type === 'inv') {
  732. // 倒序
  733. if (isNumber) {
  734. arr.sort((a, b) => {
  735. let a1 = (parseFloat(a[key].toString().replace(/[^0-9]/ig, "")) || 0);
  736. let b1 = (parseFloat(b[key].toString().replace(/[^0-9]/ig, "")) || 0);
  737. a1 = a[key] < 0 ? - a1 : a1;
  738. b1 = b[key] < 0 ? - b1 : b1;
  739. return b1 - a1
  740. })
  741. } else {
  742. arr.sort((a, b) => {
  743. let A = Pinyin.getSpell(a[key].charAt(0), function(charactor, spell) {
  744. return spell[1]
  745. }).charAt(0).charCodeAt()
  746. let B = Pinyin.getSpell(b[key].charAt(0), function(charactor, spell) {
  747. return spell[1]
  748. }).charAt(0).charCodeAt()
  749. return B - A
  750. })
  751. }
  752. } else {
  753. this.contentsSort = this.oContentsSort.slice()
  754. }
  755. if (this.enableCheck) {
  756. this.event.data.forEach(item => {
  757. this.contentsSort.forEach((content, index) => {
  758. if (isEqual(item.lineData, content)) {
  759. item.index = index
  760. }
  761. })
  762. })
  763. }
  764. this.$forceUpdate()
  765. },
  766. initBottomComputed() {
  767. let result = {}
  768. let needComputed = []
  769. this.computedCol.forEach(key => {
  770. let computedColData = []
  771. this.contentsSort.forEach(content => {
  772. computedColData.push(content[key] || '0')
  773. })
  774. needComputed.push(computedColData)
  775. })
  776. needComputed.forEach((item, index) => {
  777. let total = 0
  778. item.forEach(num => {
  779. total += parseFloat(num)
  780. })
  781. result[this.computedCol[index]] = total
  782. })
  783. this.bottomComputed = result
  784. },
  785. onHeaderItemTap(index) {
  786. let header = this.headers[index]
  787. const lastSortActiveKey = uni.getStorageSync('lastSortActiveKey') || ''
  788. if (this.sortCol.length !== 0) {
  789. if (this.sortKeys.includes(header.key)) {
  790. // 当前列开启了排序
  791. this.sortActiveKey = header.key
  792. uni.setStorageSync('lastSortActiveKey', this.sortActiveKey)
  793. if (this.sortWay < 2 && lastSortActiveKey === this.sortActiveKey) {
  794. this.sortWay++
  795. } else if (lastSortActiveKey !== this.sortActiveKey) {
  796. this.sortWay = 1
  797. } else if (this.sortWay >= 2) {
  798. this.sortWay = 0
  799. }
  800. let isNumber = this.sortCol[this.sortKeys.indexOf(header.key)].isNumber
  801. // console.log(header.key,this.sortWays[this.sortWay],isNumber)
  802. this.doSort(header.key, this.sortWays[this.sortWay], isNumber)
  803. }
  804. }
  805. },
  806. onContentItemTap(cIndex, hIndex) {
  807. let event = {}
  808. let content = this.contentsSort[cIndex]
  809. let header = this.headers[hIndex]
  810. let keys = []
  811. if (this.urlCol.length !== 0) {
  812. for (let i in this.urlCol) {
  813. let item = this.urlCol[i]
  814. keys.push(item.key)
  815. }
  816. }
  817. if (content[header.key]) {
  818. if (keys.includes(header.key)) {
  819. // 该单元格为链接
  820. switch(this.urlCol[keys.indexOf(header.key)].type) {
  821. case 'route':
  822. let url = content[header.key][1]
  823. if (content[header.key][2]) {
  824. url = `${url}?`
  825. Object.keys(content[header.key][2]).forEach(key => {
  826. url += `&${key}=${content[header['key']][2][key]}`
  827. })
  828. }
  829. uni.navigateTo({url})
  830. break
  831. case 'http':
  832. this.openURL(content[header.key][1])
  833. break
  834. }
  835. } else {
  836. event = {
  837. content: content[header.key],
  838. contentIndex: cIndex,
  839. header: header.label,
  840. headerIndex: hIndex,
  841. key: header.key,
  842. lineData: content
  843. }
  844. this.$emit('onCellClick', event)
  845. }
  846. } else {
  847. event = {
  848. content: '',
  849. contentIndex: cIndex,
  850. header: header.label,
  851. headerIndex: hIndex,
  852. key: header.key,
  853. lineData: content
  854. }
  855. if (keys.includes(header.key)) {
  856. // 该单元格为链接
  857. event['isLink'] = true
  858. }
  859. this.$emit('onCellClick', event)
  860. }
  861. },
  862. onCheckAllTap() {
  863. if (this.enableCheck === 'multiple') {
  864. let checkList = []
  865. this.contentsSort.forEach(item => {
  866. checkList.push(item.checked)
  867. })
  868. this.checkList = checkList
  869. if (!this.checkAll) {
  870. this.checkAll = true
  871. this.contentsSort.forEach(item => {
  872. item.checked = true
  873. })
  874. this.event.data = []
  875. this.contentsSort.forEach((content, index) => {
  876. this.event.data.push({
  877. index,
  878. lineData: content
  879. })
  880. })
  881. } else {
  882. this.checkAll = false
  883. this.event.data = []
  884. this.contentsSort.forEach(item => {
  885. item.checked = false
  886. })
  887. }
  888. this.$emit('onCheck', this.event)
  889. }
  890. },
  891. onCheckItemTap(cIndex) {
  892. let content = this.contentsSort[cIndex]
  893. if (this.enableCheck === 'single') {
  894. this.contentsSort.forEach((item, index) => {
  895. if (cIndex === index) {
  896. item.checked = !item.checked
  897. } else {
  898. item.checked = false
  899. }
  900. })
  901. } else if (this.enableCheck === 'multiple') {
  902. this.contentsSort[cIndex]['checked'] = !this.contentsSort[cIndex]['checked']
  903. }
  904. if (this.contentsSort[cIndex]['checked']) {
  905. if (this.enableCheck === 'single') {
  906. this.event.data = []
  907. }
  908. this.event.data.push({
  909. index: cIndex,
  910. lineData: this.contentsSort[cIndex]
  911. })
  912. } else {
  913. this.event.data.forEach(item => {
  914. if (item.index === cIndex) this.event.data.splice(this.event.data.indexOf(item), 1)
  915. })
  916. if (this.event.data.length === 0) {
  917. this.checkAll = false
  918. }
  919. }
  920. this.$forceUpdate()
  921. this.$emit('onCheck', this.event)
  922. },
  923. openURL(href) {
  924. // #ifdef APP-PLUS
  925. plus.runtime.openURL(href)
  926. // #endif
  927. // #ifdef H5
  928. window.open(href)
  929. // #endif
  930. // #ifdef MP
  931. uni.setClipboardData({
  932. data: href,
  933. success() {
  934. uni.showToast({
  935. title: '网址已复制,请在手机浏览器里粘贴该网址',
  936. icon: 'none'
  937. })
  938. }
  939. })
  940. // #endif
  941. },
  942. getAverage(key) {
  943. let numList = []
  944. this.contentsSort.forEach(content => {
  945. numList.push(parseFloat(content[key]) || 0)
  946. })
  947. return numList.reduce((a, b) => a + b) / numList.length
  948. },
  949. getTotal(key) {
  950. let numList = []
  951. this.contentsSort.forEach(content => {
  952. numList.push(parseFloat(content[key]) || 0)
  953. })
  954. return numList.reduce((a, b) => a + b)
  955. },
  956. RGBChange(color, level, type) {
  957. // 判断颜色类型
  958. let r = 0,
  959. g = 0,
  960. b = 0,
  961. hasAlpha = false,
  962. alpha = 1
  963. if (color.indexOf('#') !== -1) {
  964. // hex转rgb
  965. if (color.length === 4) {
  966. let arr = color.split('')
  967. color = '#' + arr[1] + arr[1] + arr[2] + arr[2] + arr[3] + arr[3]
  968. }
  969. let color16List = [color.substring(1, 3), color.substring(3, 5), color.substring(5, 7)]
  970. r = parseInt(color16List[0], 16)
  971. g = parseInt(color16List[1], 16)
  972. b = parseInt(color16List[2], 16)
  973. } else {
  974. hasAlpha = color.indexOf('a') !== -1
  975. let root = color.slice()
  976. let idx = root.indexOf('(') + 1
  977. root = root.substring(idx)
  978. let firstDotIdx = root.indexOf(',')
  979. r = parseFloat(root.substring(0, firstDotIdx))
  980. root = root.substring(firstDotIdx + 1)
  981. let secondDotIdx = root.indexOf(',')
  982. g = parseFloat(root.substring(0, secondDotIdx))
  983. root = root.substring(secondDotIdx + 1)
  984. if (hasAlpha) {
  985. let thirdDotIdx = root.indexOf(',')
  986. b = parseFloat(root.substring(0, thirdDotIdx))
  987. alpha = parseFloat(root.substring(thirdDotIdx + 1))
  988. } else {
  989. b = parseFloat(root)
  990. }
  991. }
  992. let rgbc = [r, g, b]
  993. // 减淡或加深
  994. for (var i = 0; i < 3; i++)
  995. type === 'light' ? rgbc[i] = Math.floor((255 - rgbc[i]) * level + rgbc[i]) : rgbc[i] = Math.floor(rgbc[i] * (1 -
  996. level))
  997. if (hasAlpha) {
  998. return `rgba(${rgbc[0]}, ${rgbc[1]}, ${rgbc[2]}, ${alpha})`
  999. } else {
  1000. return `rgb(${rgbc[0]}, ${rgbc[1]}, ${rgbc[2]})`
  1001. }
  1002. },
  1003. hexToRgb(color) {
  1004. if (color.length === 4) {
  1005. let arr = color.split('')
  1006. color = '#' + arr[1] + arr[1] + arr[2] + arr[2] + arr[3] + arr[3]
  1007. }
  1008. let color16List = [color.substring(1, 3), color.substring(3, 5), color.substring(5, 7)]
  1009. let r = parseInt(color16List[0], 16)
  1010. let g = parseInt(color16List[1], 16)
  1011. let b = parseInt(color16List[2], 16)
  1012. return [r, g, b]
  1013. },
  1014. randomString(length, chars) {
  1015. var result = ''
  1016. for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]
  1017. return result
  1018. }
  1019. }
  1020. }
  1021. </script>
  1022. <style>
  1023. @import '../../static/table/iconfont.wxss';
  1024. @import '../../static/table/loader.wxss';
  1025. .ios-header-bug {
  1026. height: 0;
  1027. width: 1px;
  1028. opacity: 0;
  1029. }
  1030. .wyb-table-scroll-view {
  1031. overflow: scroll;
  1032. -webkit-overflow-scrolling: touch;
  1033. }
  1034. .wyb-table-scroll-view::-webkit-scrollbar {
  1035. display: none;
  1036. /* #ifdef MP-WEIXIN */
  1037. width: 0;
  1038. height: 0;
  1039. /* #endif */
  1040. }
  1041. .wyb-table-loading-box {
  1042. display: flex;
  1043. align-items: center;
  1044. justify-content: center;
  1045. z-index: 500;
  1046. }
  1047. .wyb-table-header {
  1048. position: sticky;
  1049. top: 0;
  1050. display: grid;
  1051. grid-auto-flow: column;
  1052. width: max-content;
  1053. z-index: 25;
  1054. }
  1055. .wyb-table-header-item {
  1056. flex: 1;
  1057. display: flex;
  1058. align-items: center;
  1059. box-sizing: border-box;
  1060. position: relative;
  1061. }
  1062. .wyb-table-header-icon {
  1063. display: flex;
  1064. flex-direction: column;
  1065. }
  1066. .wyb-table-content-line {
  1067. display: grid;
  1068. grid-auto-flow: column;
  1069. width: max-content;
  1070. position: relative;
  1071. }
  1072. .wyb-table-content-item {
  1073. display: flex;
  1074. flex-direction: row;
  1075. align-items: center;
  1076. box-sizing: border-box;
  1077. }
  1078. .wyb-table-checkbox {
  1079. border-radius: 3px;
  1080. display: flex;
  1081. align-items: center;
  1082. justify-content: center;
  1083. position: relative;
  1084. }
  1085. .icon-check {
  1086. width: 100%;
  1087. height: 100%;
  1088. position: absolute;
  1089. border-radius: 0;
  1090. border-radius: 3px;
  1091. font-weight: bold;
  1092. box-sizing: border-box;
  1093. transform: scale(1.1);
  1094. }
  1095. </style>