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

1244 lines
35 KiB

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