自主产品,供应链食堂系统。将两个端拆开了。
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.

1225 lines
34 KiB

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