From 38430ddb8612fce15a2f1c940f9bd57d4da3e70b Mon Sep 17 00:00:00 2001 From: zhangzengfei <zhangzengfei@smartai.com> Date: 星期四, 16 九月 2021 11:59:39 +0800 Subject: [PATCH] add new key --- components/z-table/z-table.vue | 1568 +++++++++++++++++++++++++++++----------------------------- 1 files changed, 784 insertions(+), 784 deletions(-) diff --git a/components/z-table/z-table.vue b/components/z-table/z-table.vue index 0fd3b01..b0f14b5 100644 --- a/components/z-table/z-table.vue +++ b/components/z-table/z-table.vue @@ -1,784 +1,784 @@ -<template> - <view class="z-table"> - <view class="z-table-main" :style="compluteHeight"> - <view v-if="!tableLoaded && (!tableData || !columns)" :class="['z-loading', {ztableLoading: tableShow}]"> - <view class="z-loading-animate"></view> - </view> - <view class="z-table-container"> - <view class="z-table-pack"> - <view class="z-table-title"> - <view class="z-table-title-item" :class="{ 'z-table-stick-side': stickSide && index == 0 }" :style="{ width: item.width ? item.width + 'rpx' : '200rpx' }" - v-for="(item, index) in columns" :key="index" @click="sort(item.key, index)"> - <view v-if="showSelect && !singleSelect && index === 0" class="select-box" @click="doSelect(true)"> - <view :class="['select-tip', {'selected': selectAll}]"></view> - </view> - <view :class="['z-table-col-text', {'text-left': titleTextAlign === 'left', 'text-center': titleTextAlign === 'center', 'text-right': titleTextAlign === 'right'}]"> - <view v-html="getTitleText(item.title)"></view> - <view v-if="item.hasOwnProperty('key') && item.hasOwnProperty('sort') && tableData.length" class="sort"> - <view class="up-arrow" :class="{ action: nowSortKey == item.key && sortType == 'asc' }"></view> - <view class="down-arrow" :class="{ action: nowSortKey == item.key && sortType == 'desc' }"></view> - </view> - </view> - </view> - </view> - <view v-if="tableData.length" :class="['table-container-box', {'short-table': !longTable && showBottomSum}]"> - <view class="z-table-container-row" :class="{ 'z-table-has-bottom': showBottomSum }" v-for="(row, iIndex) in tableData" - :key="iIndex"> - <view :class="['z-table-container-col', { 'z-table-stick-side': stickSide && jIndex == 0 }]" :style="{ width: col.width ? col.width + 'rpx' : '200rpx' }" - v-for="(col, jIndex) in columns" :key="jIndex" @click="itemClick(row, col)"> - <view v-if="showSelect && jIndex === 0" class="select-box" @click="doSelect(false, iIndex)"> - <view :class="['select-tip', {'selected': selectArr.includes(iIndex)}]"></view> - </view> - <view :class="['z-table-col-text', {'text-left': textAlign === 'left', 'text-center': textAlign === 'center', 'text-right': textAlign === 'right'}]"> - <view v-if="!col.isLink" v-html="getRowContent(row, col)"> - <!-- <view v-if="!col.render" v-html="getRowContent(row, col)"></view> --> - <!-- <renderComponents v-else :row="row" :col="col" /> --> - </view> - <!-- #ifdef H5 --> - <router-link v-else-if="setUrl(row, col).indexOf('http') != 0" :to="setUrl(row, col)" v-html="getRowContent(row, col)"></router-link> - <a v-else-if="col.isLink" :href="setUrl(row, col)" v-html="getRowContent(row, col)"></a> - <!-- #endif --> - <!-- #ifndef H5 --> - <navigator v-else-if="col.isLink" :url="setUrl(row, col)" v-html="getRowContent(row, col)"></navigator> - <!-- #endif --> - </view> - </view> - </view> - </view> - <view :class="['z-table-bottom', {'long-table': longTable}]" v-if="showBottomSum && tableData.length"> - <view class="z-table-bottom-col" :class="{ 'z-table-stick-side': stickSide && sumIndex == 0 }" :style="{ width: sumCol.width ? sumCol.width + 'rpx' : '200rpx' }" - v-for="(sumCol, sumIndex) in columns" :key="sumIndex"> - <view class="z-table-bottom-text"> - <!-- <view v-if="sumIndex != 0" class="z-table-bottom-text-title">{{ sumCol.title }}</view> --> - <text :class="{ sum: sumIndex == 0 }">{{ sumIndex == 0 ? '鎬昏' : dosum(sumCol) }}</text> - </view> - </view> - </view> - </view> - </view> - <view v-if="tableData && tableData.length == 0 && !tableLoaded" class="table-empty"> - <!-- image v-if="!showLoading" class="empty-img" src="../static/empty.png"></image --> - <view v-html="showLoading ? '' : emptyText"></view> - </view> - </view> - </view> -</template> - -<script> - /* - * 琛ㄦ牸浣跨敤 - * 娉ㄦ剰濡傛灉闇�瑕佸紓姝ュ姞杞斤紝闇�瑕佹妸tableData鍒濆鍊艰涓篺alse锛屽綋娌℃湁鏁版嵁鐨勬椂鍊欏�间负绌烘暟缁� - * props: tableData [Array | Boolean] | 琛ㄦ牸鏁版嵁 濡傛灉涓篺alse鍒欐樉绀簂oading - * columns [Array | Boolean] | 鏁版嵁鏄犲皠琛� 濡傛灉涓篺alse鍒欐樉绀簂oading 姣忓垪params => title(琛ㄥご鏂囧瓧鍙互鏄痟tml瀛楃涓叉ā鐗�), width(姣忓垪瀹藉害) [, key(瀵瑰簲tableData鐨勫瓧娈靛悕) || format(鑷畾涔夊唴瀹�), sort(鏄惁瑕佹帓搴�), isLink(鏄惁鏄剧ず涓鸿秴閾炬帴Object)] - * format鏍煎紡: {template: 瀛楃涓叉ā鐗堢敤#key#琛ㄧず闇�瑕佽鏇挎崲鐨勬暟鎹�,names: 瀵瑰簲template灞炴�у唴瑕佽鏇挎崲鐨勫唴瀹圭殑key} - * isLink鏍煎紡: {url: 閾炬帴鍦板潃, params: 鍦板潃甯︾殑鍙傛暟Array[key|value, key|value, ...]姣忎竴椤归兘鏄痥ey鍜寁alue浠�'|'閾炬帴,濡傛灉涓嶅甫'|'榛樿閿�煎悓鍚� - * listenerClick(鏄惁鐩戝惉鐐瑰嚮浜嬩欢Boolean)} - * stickSide Boolean | 鏄惁鍥哄畾鍙充晶棣栨爮 榛樿涓嶆樉绀� - * showBottomSum Boolean | 鏄惁鏄剧ず搴曢儴缁熻 榛樿涓嶆樉绀� - * showLoading Boolean | 鏄惁棣栨鍔犺浇棣栨鍔犺浇涓嶆樉绀烘殏鏃犳暟鎹唴瀹� - * emptyText String | 绌烘暟鎹樉绀虹殑鏂囧瓧鍐呭 - * tableHeight Number | 璁剧疆琛ㄦ牸楂樺害浼氭粴鍔� - * sort Boolean | 寮�鍚帓搴� - * showSelect Boolean | 寮�鍚�夋嫨 - * singleSelect Boolean | 鍦ㄥ紑鍚�夋嫨鐨勭姸鎬佷笅鏄惁寮�璧峰崟閫� - * textAlign String | 鍐呭瀵归綈鏂瑰紡 left center right - * titleTextAlign String | 琛ㄥご瀵归綈鏂瑰紡 left center right - * - * event: onSort | 鎺掑簭浜嬩欢 杩斿洖{key: 琚帓搴忓垪鐨勫瓧娈靛悕, type: 姝e簭'asc'/鍊掑簭'desc'} - * onSelect | 閫変腑鏃惰Е鍙� 杩斿洖閫夋嫨鐨勮鐨勪笅鏍� - * onClick | 鍗曞厓鏍肩偣鍑讳簨浠� 杩斿洖鐐瑰嚮鍗曞厓鏍兼墍灞炶鐨勬暟鎹� - * - * function: resetSort | 璋冪敤鍚庨噸缃帓搴� *娉ㄦ剰:涓嶄細瑙﹀彂sort浜嬩欢 - * - * */ - import Vue from 'vue' - // import tableRender from './table-render' - - export default { - data() { - return { - version: '1.1.3', - nowSortKey: '', - sortType: 'desc', // asc/desc 鍗囧簭/闄嶅簭 - longTable: true, - lineHeight: uni.upx2px(64), - tableLoaded: false, - tableShow: true, - selectAll: false, - selectArr: [] - } - }, - // mixin: [tableRender], - computed: { - compluteHeight() { - return this.tableHeight ? - 'height: ' + uni.upx2px(this.tableHeight) + 'px' : - '' - } - }, - props: { - tableData: { - type: [Array, Boolean], - default () { - return false - } - }, - columns: { - /* - * - * [{title: xxx, key: 褰撳墠鍒楀睍绀哄璞″悕, width: 鍒楀, render: function}] - * - * */ - type: [Array, Boolean], - required: true - }, - stickSide: { - type: Boolean, - default: false - }, - showBottomSum: { - type: Boolean, - default: false - }, - showLoading: { - type: Boolean, - default: true - }, - emptyText: { - type: String, - default: '鏆傛棤鏁版嵁' - }, - tableHeight: { - type: [Number, Boolean], - default: 0 - }, - showSelect: { - type: Boolean, - default: false - }, - singleSelect: { - type: Boolean, - default: false - }, - textAlign: { - type: String, - default: 'left' // right|center|left - }, - titleTextAlign: { - type: String, - default: 'left' // right|center|left - } - }, - mounted() { - this.init() - }, - // components: { - // renderComponents: { - // functional: true, - // props: { - // row: { - // type: Object, - // required: true - // }, - // col: { - // type: Object, - // required: true - // } - // }, - // render: function(h, ctx) { - // return _this[ctx.props.col.render](h, ctx.props) - // } - // } - // }, - watch: { - columns() { - this.init() - }, - tableData() { - this.init() - } - }, - methods: { - async init() { - // 閲嶇疆閫夋嫨鍐呭 - this.selectAll = false - this.selectArr = [] - this.tableLoaded = false - this.tableShow = true - let _this = this - let container = await _this.getPageSize('.z-table-container'), - pack = await _this.getPageSize('.z-table-pack') - _this.timer && clearTimeout(_this.timer) - if (container && pack) { - _this.$nextTick(function() { - if (_this.tableData && _this.tableData.length) { - _this.tableShow = false - _this.timer = setTimeout(function() { - _this.tableLoaded = true - }, 300) - } - }) - if (container.height != pack.height) { - _this.longTable = true - } else { - _this.longTable = false - } - } else { - _this.tableLoaded = false - _this.$nextTick(function() { - _this.tableShow = true - }) - } - }, - getPageSize(selecter) { - // 鑾峰彇鍏冪礌淇℃伅 - let query = uni.createSelectorQuery().in(this), - _this = this - return new Promise((resolve, reject) => { - query - .select(selecter) - .boundingClientRect(res => { - resolve(res) - }) - .exec() - }) - }, - dosum({key, noSum = false, formatNum = true}) { - let sum = '-' - if (noSum) return sum - if (this.tableData) { - if ( - this.tableData.every(item => { - return !Number.isNaN(item[key] - 0) - }) - ) { - sum = 0 - this.tableData.map((item, index) => { - if (!key && index != 0) { - sum = '-' - } else { - let val = item[key] - 0 - if (Number.isNaN(val)) { - sum += 0 - } else { - sum += val - } - } - }) - } - } - // sum = sum == 0 ? "-" : sum - return formatNum ? this.numTransform(sum) : sum - }, - getRowContent(row, col) { - // 琛ㄦ牸鍊煎鐞嗗嚱鏁� - // 濡傛灉columns甯︿簡key鍒欐樉绀哄搴旂殑key - // 濡傛灉columns甯︾殑format鍒欐寜瑙勫畾杩斿洖format鍚庣殑html - // format瑙勫畾: params names <Array> 瀵瑰簲tableData鐨勯敭鍚�,浣滀负鍖归厤template涓袱涓�#涔嬮棿鍔ㄦ�佸唴瀹圭殑鍚嶅瓧 - // params template <String> html瀛楃涓叉ā鐗� - let tempHTML = '' - let rowKey = row[col.key] - if ([null, ''].includes(rowKey)) { - rowKey = '-' - } - let { formatNum = true } = col - if (rowKey || rowKey === 0) { - tempHTML = isNaN(rowKey - 0) || !formatNum ? - rowKey : - this.numTransform(rowKey - 0) - // tempHTML = tempHTML == 0 ? "-" : tempHTML - } else if (!!col.format) { - let tempFormat = col.format.template - col.format.names.map(item => { - let regexp = new RegExp(`\#${item}\#`, 'mg') - tempFormat = tempFormat.replace(regexp, row[item]) - }) - tempHTML = tempFormat - } else if (!col.render) { - let error = new Error('鏁版嵁鐨刱ey鎴杅ormat鍊艰嚦灏戜竴涓笉涓虹┖') - throw error - } - // console.log(tempHTML) - return tempHTML.toString() - }, - sort(key, index) { - if (!key || !this.columns[index].sort) { - return - } - // 鎺掑簭鍔熻兘: 濡傛灉鐐瑰嚮鐨勬帓搴忔寜閽槸鍘熷厛鐨� 閭d箞鏇存敼鎺掑簭绫诲瀷 - // 濡傛灉鐐瑰嚮鐨勫彟涓�涓帓搴忔寜閽� 閭d箞閫夋嫨褰撳墠鎺掑簭骞朵笖鎺掑簭绫诲瀷鏀逛负闄嶅簭(desc) - if (key != this.nowSortKey) { - this.nowSortKey = key - this.sortType = 'desc' - } else { - this.toggleSort() - } - this.$emit('onSort', { - key: this.nowSortKey, - type: this.sortType - }) - }, - toggleSort() { - this.sortType = this.sortType == 'asc' ? 'desc' : 'asc' - }, - numTransform(n) { - if (Number.isNaN(n - 0)) { - return n - } - if (Math.abs(n) >= 100000000) { - n = Number((n / 100000000).toFixed(1)) + '浜�' - } else if (Math.abs(n) >= 10000) { - n = Number((n / 10000).toFixed(1)) + '涓�' - } - return n.toString() - }, - resetSort() { - // 閲嶇疆鎺掑簭鐘舵�� - this.nowSortKey = '' - this.sortType = 'desc' - }, - setUrl(row, col) { - if (!col.isLink) { - return - } - let urlParam = {} - let { - isLink: { - url, - params = [] - } - } = col - params.forEach(item => { - if (~item.indexOf('|')) { - let temp = item.split('|') - urlParam[temp[0]] = row[temp[1]] - } else { - urlParam[item] = row[item] - } - }) - url = this.setUrlParams(url, urlParam) - return url - }, - setUrlParams(url, params) { - let tempUrl = url, - keyArr = Object.keys(params) - keyArr.forEach(item => { - tempUrl += `&${item}=${params[item]}` - }) - tempUrl = tempUrl.replace(/\&/, '?') - return tempUrl - }, - itemClick(row, col) { - if (col.listenerClick) { - this.$emit('onClick', row) - } - }, - doSelect(isAll = false, index) { - let temp = new Set() - if (isAll) { - // 鍏ㄩ�� - if (!this.selectAll) { - for (let i = 0; i < this.tableData.length; i++) { - temp.add(i) - } - } - } else { - // if (!this.singleSelect) { - // this.selectArr.forEach(item => { - // temp.add(item) - // }) - // } - this.selectArr.forEach(item => { - temp.add(item) - }) - if (temp.has(index)) { - temp.delete(index) - } else { - if (this.singleSelect) { - temp.clear() - } - temp.add(index) - } - } - this.selectArr = Array.from(temp) - // console.log(this.selectArr) - if (this.selectArr.length == this.tableData.length) { - this.selectAll = true - } else { - this.selectAll = false - } - - this.$emit('onSelect', this.selectArr) - }, - // 1.1.1 - getTitleText(title) { - // 鑷畾涔夎〃澶� - let tempHTML = title - return tempHTML.toString() - } - } - } -</script> - -<style lang="scss"> - .navigator-hover { - background: transparent; - opacity: 1; - } - - @mixin ellipsis($num: 1) { - overflow: hidden; - text-overflow: ellipsis; - - @if $num==1 { - white-space: nowrap; - } - - @else { - display: -webkit-box; - -webkit-line-clamp: $num; - /* autoprefixer: off */ - -webkit-box-orient: vertical; - /* autoprefixer: on */ - } - } - - // 涓夎褰� - %triangle-basic { - content: ''; - height: 0; - width: 0; - overflow: hidden; - } - - @mixin triangle($direction, $size, $borderColor) { - @extend %triangle-basic; - - @if $direction==top { - border-bottom: $size solid $borderColor; - border-left: $size dashed transparent; - border-right: $size dashed transparent; - border-top: 0; - } - - @else if $direction==right { - border-left: $size solid $borderColor; - border-top: $size dashed transparent; - border-bottom: $size dashed transparent; - border-right: 0; - } - - @else if $direction==bottom { - border-top: $size solid $borderColor; - border-left: $size dashed transparent; - border-right: $size dashed transparent; - border-bottom: 0; - } - - @else if $direction==left { - border-right: $size solid $borderColor; - border-top: $size dashed transparent; - border-bottom: $size dashed transparent; - border-left: 0; - } - } - - a { - text-decoration: none; - } - - .z-table { - position: relative; - display: inline-block; - height: 100%; - min-height: 130rpx; - width: 100%; - background: #fff; - border: solid 2rpx #ccc; - font-size: $uni-font-size-sm; - box-sizing: border-box; - transform: translateZ(0); - - .z-table-main { - height: 100%; - box-sizing: border-box; - } - - .z-table-container { - height: 100%; - overflow: scroll; - box-sizing: border-box; - } - - .z-table-pack { - position: relative; - min-height: 100%; - width: fit-content; - } - - .z-table-title { - position: sticky; - top: 0; - height: 64rpx; - z-index: 1; - - .z-table-title-item { - border-bottom: solid 1rpx #dbdbdb; - background: #f8f8f8; - } - - .z-table-stick-side { - position: sticky; - top: 0; - left: 0; - border-right: solid 1rpx #dbdbdb; - box-sizing: border-box; - } - } - - .table-container-box.short-table { - padding-bottom: 48rpx; - } - - .z-table-title, - .z-table-container-row { - display: flex; - width: fit-content; - white-space: nowrap; - box-sizing: border-box; - - .z-table-title-item, - .z-table-container-col { - @include ellipsis(); - display: inline-flex; - padding: 0 16rpx; - height: 64rpx; - align-items: center; - line-height: 64rpx; - box-sizing: border-box; - } - } - - .z-table-container-row { - z-index: 0; - border-bottom: solid 1rpx #f4f4f4; - box-sizing: border-box; - } - - .z-table-stick-side { - position: sticky; - left: 0; - background: #f7f9ff; - border-right: solid 1rpx #dbdbdb; - box-sizing: border-box; - } - - .z-table-bottom { - position: absolute; - bottom: 0; - z-index: 9; - display: flex; - justify-items: center; - width: fit-content; - background: #4298f7 !important; - color: #fff !important; - white-space: nowrap; - box-sizing: border-box; - - &.long-table { - position: sticky; - } - - .z-table-stick-side { - background: #4298f7 !important; - box-sizing: border-box; - } - - .z-table-bottom-col { - display: inline-flex; - align-items: center; - text-align: center; - padding: 16rpx; - box-sizing: border-box; - } - - .z-table-bottom-text { - line-height: 100%; - box-sizing: border-box; - } - - .z-table-bottom-text-title { - margin-bottom: 10rpx; - font-size: 22rpx; - color: #aad0ff; - box-sizing: border-box; - } - - .sum { - margin-left: 14rpx; - font-size: 28rpx; - box-sizing: border-box; - } - } - - .table-empty { - position: absolute; - top: 64rpx; - height: 64rpx; - line-height: 64rpx; - width: 100%; - text-align: center; - } - - .sort { - display: flex; - padding: 5rpx; - flex-direction: column; - justify-content: center; - - .up-arrow { - @include triangle(top, 10rpx, #ccc); - display: block; - margin-bottom: 5rpx; - - &.action { - @include triangle(top, 10rpx, #4298f7); - } - } - - .down-arrow { - @include triangle(bottom, 10rpx, #ccc); - display: block; - - &.action { - @include triangle(bottom, 10rpx, #4298f7); - } - } - } - - // 1.0.5 - .z-loading { - position: absolute; - top: 0; - left: 0; - z-index: 2; - display: flex; - align-items: center; - justify-content: center; - height: 100%; - width: 100%; - background: #fff; - opacity: 0; - transition: all 0.3s; - - &.ztableLoading { - opacity: 1; - } - - .z-loading-animate { - position: relative; - display: inline-block; - width: 30rpx; - height: 30rpx; - margin-right: 20rpx; - border-radius: 100%; - border: solid 6rpx #ccc; - vertical-align: middle; - animation: rotate 1s ease-in-out infinite; - - &::after { - content: ''; - display: block; - position: absolute; - top: -10rpx; - z-index: 1; - background: #fff; - width: 20rpx; - height: 20rpx; - border-radius: 10rpx; - } - } - - @keyframes rotate { - from { - transform: rotate(0deg); - } - - to { - transform: rotate(360deg); - } - } - } - - // 1.1.0 - .select-box { - display: inline-block; - width: 26rpx; - height: 26rpx; - line-height: 14rpx; - margin-right: 15rpx; - border: solid 2rpx #4298f7; - border-radius: 4rpx; - background: #fff; - text-align: center; - } - - .select-tip { - display: inline-block; - opacity: 0; - transform: rotate(90deg); - transition: all .3s; - - &.selected { - position: relative; - top: 4rpx; - left: -4rpx; - height: 4rpx; - background: #4298f7; - width: 10rpx; - opacity: 1; - transform: rotate(45deg); - - &:before, - &:after { - content: ''; - position: absolute; - display: block; - height: 4rpx; - background: #4298f7; - } - - &:before { - bottom: -2rpx; - left: -4rpx; - width: 8rpx; - transform: rotate(-90deg); - } - - &:after { - bottom: 16rpx; - right: -16rpx; - width: 34rpx; - transform: rotate(-90deg); - } - } - } - - // 1.1.1 - .z-table-col-text { - display: flex; - width: 100%; - flex: 1; - justify-content: flex-start; - align-content: center; - - &.text-center { - justify-content: center; - } - - &.text-right { - justify-content: flex-end; - } - } - } -</style> +<template> + <view class="z-table"> + <view class="z-table-main" :style="compluteHeight"> + <view v-if="!tableLoaded && (!tableData || !columns)" :class="['z-loading', {ztableLoading: tableShow}]"> + <view class="z-loading-animate"></view> + </view> + <view class="z-table-container"> + <view class="z-table-pack"> + <view class="z-table-title"> + <view class="z-table-title-item" :class="{ 'z-table-stick-side': stickSide && index == 0 }" :style="{ width: item.width ? item.width + 'rpx' : '200rpx' }" + v-for="(item, index) in columns" :key="index" @click="sort(item.key, index)"> + <view v-if="showSelect && !singleSelect && index === 0" class="select-box" @click="doSelect(true)"> + <view :class="['select-tip', {'selected': selectAll}]"></view> + </view> + <view :class="['z-table-col-text', {'text-left': titleTextAlign === 'left', 'text-center': titleTextAlign === 'center', 'text-right': titleTextAlign === 'right'}]"> + <view v-html="getTitleText(item.title)"></view> + <view v-if="item.hasOwnProperty('key') && item.hasOwnProperty('sort') && tableData.length" class="sort"> + <view class="up-arrow" :class="{ action: nowSortKey == item.key && sortType == 'asc' }"></view> + <view class="down-arrow" :class="{ action: nowSortKey == item.key && sortType == 'desc' }"></view> + </view> + </view> + </view> + </view> + <view v-if="tableData.length" :class="['table-container-box', {'short-table': !longTable && showBottomSum}]"> + <view class="z-table-container-row" :class="{ 'z-table-has-bottom': showBottomSum }" v-for="(row, iIndex) in tableData" + :key="iIndex"> + <view :class="['z-table-container-col', { 'z-table-stick-side': stickSide && jIndex == 0 }]" :style="{ width: col.width ? col.width + 'rpx' : '200rpx' }" + v-for="(col, jIndex) in columns" :key="jIndex" @click="itemClick(row, col)"> + <view v-if="showSelect && jIndex === 0" class="select-box" @click="doSelect(false, iIndex)"> + <view :class="['select-tip', {'selected': selectArr.includes(iIndex)}]"></view> + </view> + <view :class="['z-table-col-text', {'text-left': textAlign === 'left', 'text-center': textAlign === 'center', 'text-right': textAlign === 'right'}]"> + <view v-if="!col.isLink" v-html="getRowContent(row, col)"> + <!-- <view v-if="!col.render" v-html="getRowContent(row, col)"></view> --> + <!-- <renderComponents v-else :row="row" :col="col" /> --> + </view> + <!-- #ifdef H5 --> + <router-link v-else-if="setUrl(row, col).indexOf('http') != 0" :to="setUrl(row, col)" v-html="getRowContent(row, col)"></router-link> + <a v-else-if="col.isLink" :href="setUrl(row, col)" v-html="getRowContent(row, col)"></a> + <!-- #endif --> + <!-- #ifndef H5 --> + <navigator v-else-if="col.isLink" :url="setUrl(row, col)" v-html="getRowContent(row, col)"></navigator> + <!-- #endif --> + </view> + </view> + </view> + </view> + <view :class="['z-table-bottom', {'long-table': longTable}]" v-if="showBottomSum && tableData.length"> + <view class="z-table-bottom-col" :class="{ 'z-table-stick-side': stickSide && sumIndex == 0 }" :style="{ width: sumCol.width ? sumCol.width + 'rpx' : '200rpx' }" + v-for="(sumCol, sumIndex) in columns" :key="sumIndex"> + <view class="z-table-bottom-text"> + <!-- <view v-if="sumIndex != 0" class="z-table-bottom-text-title">{{ sumCol.title }}</view> --> + <text :class="{ sum: sumIndex == 0 }">{{ sumIndex == 0 ? '鎬昏' : dosum(sumCol) }}</text> + </view> + </view> + </view> + </view> + </view> + <view v-if="tableData && tableData.length == 0 && !tableLoaded" class="table-empty"> + <!-- image v-if="!showLoading" class="empty-img" src="../static/empty.png"></image --> + <view v-html="showLoading ? '' : emptyText"></view> + </view> + </view> + </view> +</template> + +<script> + /* + * 琛ㄦ牸浣跨敤 + * 娉ㄦ剰濡傛灉闇�瑕佸紓姝ュ姞杞斤紝闇�瑕佹妸tableData鍒濆鍊艰涓篺alse锛屽綋娌℃湁鏁版嵁鐨勬椂鍊欏�间负绌烘暟缁� + * props: tableData [Array | Boolean] | 琛ㄦ牸鏁版嵁 濡傛灉涓篺alse鍒欐樉绀簂oading + * columns [Array | Boolean] | 鏁版嵁鏄犲皠琛� 濡傛灉涓篺alse鍒欐樉绀簂oading 姣忓垪params => title(琛ㄥご鏂囧瓧鍙互鏄痟tml瀛楃涓叉ā鐗�), width(姣忓垪瀹藉害) [, key(瀵瑰簲tableData鐨勫瓧娈靛悕) || format(鑷畾涔夊唴瀹�), sort(鏄惁瑕佹帓搴�), isLink(鏄惁鏄剧ず涓鸿秴閾炬帴Object)] + * format鏍煎紡: {template: 瀛楃涓叉ā鐗堢敤#key#琛ㄧず闇�瑕佽鏇挎崲鐨勬暟鎹�,names: 瀵瑰簲template灞炴�у唴瑕佽鏇挎崲鐨勫唴瀹圭殑key} + * isLink鏍煎紡: {url: 閾炬帴鍦板潃, params: 鍦板潃甯︾殑鍙傛暟Array[key|value, key|value, ...]姣忎竴椤归兘鏄痥ey鍜寁alue浠�'|'閾炬帴,濡傛灉涓嶅甫'|'榛樿閿�煎悓鍚� + * listenerClick(鏄惁鐩戝惉鐐瑰嚮浜嬩欢Boolean)} + * stickSide Boolean | 鏄惁鍥哄畾鍙充晶棣栨爮 榛樿涓嶆樉绀� + * showBottomSum Boolean | 鏄惁鏄剧ず搴曢儴缁熻 榛樿涓嶆樉绀� + * showLoading Boolean | 鏄惁棣栨鍔犺浇棣栨鍔犺浇涓嶆樉绀烘殏鏃犳暟鎹唴瀹� + * emptyText String | 绌烘暟鎹樉绀虹殑鏂囧瓧鍐呭 + * tableHeight Number | 璁剧疆琛ㄦ牸楂樺害浼氭粴鍔� + * sort Boolean | 寮�鍚帓搴� + * showSelect Boolean | 寮�鍚�夋嫨 + * singleSelect Boolean | 鍦ㄥ紑鍚�夋嫨鐨勭姸鎬佷笅鏄惁寮�璧峰崟閫� + * textAlign String | 鍐呭瀵归綈鏂瑰紡 left center right + * titleTextAlign String | 琛ㄥご瀵归綈鏂瑰紡 left center right + * + * event: onSort | 鎺掑簭浜嬩欢 杩斿洖{key: 琚帓搴忓垪鐨勫瓧娈靛悕, type: 姝e簭'asc'/鍊掑簭'desc'} + * onSelect | 閫変腑鏃惰Е鍙� 杩斿洖閫夋嫨鐨勮鐨勪笅鏍� + * onClick | 鍗曞厓鏍肩偣鍑讳簨浠� 杩斿洖鐐瑰嚮鍗曞厓鏍兼墍灞炶鐨勬暟鎹� + * + * function: resetSort | 璋冪敤鍚庨噸缃帓搴� *娉ㄦ剰:涓嶄細瑙﹀彂sort浜嬩欢 + * + * */ + import Vue from 'vue' + // import tableRender from './table-render' + + export default { + data() { + return { + version: '1.1.3', + nowSortKey: '', + sortType: 'desc', // asc/desc 鍗囧簭/闄嶅簭 + longTable: true, + lineHeight: uni.upx2px(64), + tableLoaded: false, + tableShow: true, + selectAll: false, + selectArr: [] + } + }, + // mixin: [tableRender], + computed: { + compluteHeight() { + return this.tableHeight ? + 'height: ' + uni.upx2px(this.tableHeight) + 'px' : + '' + } + }, + props: { + tableData: { + type: [Array, Boolean], + default () { + return false + } + }, + columns: { + /* + * + * [{title: xxx, key: 褰撳墠鍒楀睍绀哄璞″悕, width: 鍒楀, render: function}] + * + * */ + type: [Array, Boolean], + required: true + }, + stickSide: { + type: Boolean, + default: false + }, + showBottomSum: { + type: Boolean, + default: false + }, + showLoading: { + type: Boolean, + default: true + }, + emptyText: { + type: String, + default: '鏆傛棤鏁版嵁' + }, + tableHeight: { + type: [Number, Boolean], + default: 0 + }, + showSelect: { + type: Boolean, + default: false + }, + singleSelect: { + type: Boolean, + default: false + }, + textAlign: { + type: String, + default: 'left' // right|center|left + }, + titleTextAlign: { + type: String, + default: 'left' // right|center|left + } + }, + mounted() { + this.init() + }, + // components: { + // renderComponents: { + // functional: true, + // props: { + // row: { + // type: Object, + // required: true + // }, + // col: { + // type: Object, + // required: true + // } + // }, + // render: function(h, ctx) { + // return _this[ctx.props.col.render](h, ctx.props) + // } + // } + // }, + watch: { + columns() { + this.init() + }, + tableData() { + this.init() + } + }, + methods: { + async init() { + // 閲嶇疆閫夋嫨鍐呭 + this.selectAll = false + this.selectArr = [] + this.tableLoaded = false + this.tableShow = true + let _this = this + let container = await _this.getPageSize('.z-table-container'), + pack = await _this.getPageSize('.z-table-pack') + _this.timer && clearTimeout(_this.timer) + if (container && pack) { + _this.$nextTick(function() { + if (_this.tableData && _this.tableData.length) { + _this.tableShow = false + _this.timer = setTimeout(function() { + _this.tableLoaded = true + }, 300) + } + }) + if (container.height != pack.height) { + _this.longTable = true + } else { + _this.longTable = false + } + } else { + _this.tableLoaded = false + _this.$nextTick(function() { + _this.tableShow = true + }) + } + }, + getPageSize(selecter) { + // 鑾峰彇鍏冪礌淇℃伅 + let query = uni.createSelectorQuery().in(this), + _this = this + return new Promise((resolve, reject) => { + query + .select(selecter) + .boundingClientRect(res => { + resolve(res) + }) + .exec() + }) + }, + dosum({key, noSum = false, formatNum = true}) { + let sum = '-' + if (noSum) return sum + if (this.tableData) { + if ( + this.tableData.every(item => { + return !Number.isNaN(item[key] - 0) + }) + ) { + sum = 0 + this.tableData.map((item, index) => { + if (!key && index != 0) { + sum = '-' + } else { + let val = item[key] - 0 + if (Number.isNaN(val)) { + sum += 0 + } else { + sum += val + } + } + }) + } + } + // sum = sum == 0 ? "-" : sum + return formatNum ? this.numTransform(sum) : sum + }, + getRowContent(row, col) { + // 琛ㄦ牸鍊煎鐞嗗嚱鏁� + // 濡傛灉columns甯︿簡key鍒欐樉绀哄搴旂殑key + // 濡傛灉columns甯︾殑format鍒欐寜瑙勫畾杩斿洖format鍚庣殑html + // format瑙勫畾: params names <Array> 瀵瑰簲tableData鐨勯敭鍚�,浣滀负鍖归厤template涓袱涓�#涔嬮棿鍔ㄦ�佸唴瀹圭殑鍚嶅瓧 + // params template <String> html瀛楃涓叉ā鐗� + let tempHTML = '' + let rowKey = row[col.key] + if ([null, ''].includes(rowKey)) { + rowKey = '-' + } + let { formatNum = true } = col + if (rowKey || rowKey === 0) { + tempHTML = isNaN(rowKey - 0) || !formatNum ? + rowKey : + this.numTransform(rowKey - 0) + // tempHTML = tempHTML == 0 ? "-" : tempHTML + } else if (!!col.format) { + let tempFormat = col.format.template + col.format.names.map(item => { + let regexp = new RegExp(`\#${item}\#`, 'mg') + tempFormat = tempFormat.replace(regexp, row[item]) + }) + tempHTML = tempFormat + } else if (!col.render) { + let error = new Error('鏁版嵁鐨刱ey鎴杅ormat鍊艰嚦灏戜竴涓笉涓虹┖') + throw error + } + // console.log(tempHTML) + return tempHTML.toString() + }, + sort(key, index) { + if (!key || !this.columns[index].sort) { + return + } + // 鎺掑簭鍔熻兘: 濡傛灉鐐瑰嚮鐨勬帓搴忔寜閽槸鍘熷厛鐨� 閭d箞鏇存敼鎺掑簭绫诲瀷 + // 濡傛灉鐐瑰嚮鐨勫彟涓�涓帓搴忔寜閽� 閭d箞閫夋嫨褰撳墠鎺掑簭骞朵笖鎺掑簭绫诲瀷鏀逛负闄嶅簭(desc) + if (key != this.nowSortKey) { + this.nowSortKey = key + this.sortType = 'desc' + } else { + this.toggleSort() + } + this.$emit('onSort', { + key: this.nowSortKey, + type: this.sortType + }) + }, + toggleSort() { + this.sortType = this.sortType == 'asc' ? 'desc' : 'asc' + }, + numTransform(n) { + if (Number.isNaN(n - 0)) { + return n + } + if (Math.abs(n) >= 100000000) { + n = Number((n / 100000000).toFixed(1)) + '浜�' + } else if (Math.abs(n) >= 10000) { + n = Number((n / 10000).toFixed(1)) + '涓�' + } + return n.toString() + }, + resetSort() { + // 閲嶇疆鎺掑簭鐘舵�� + this.nowSortKey = '' + this.sortType = 'desc' + }, + setUrl(row, col) { + if (!col.isLink) { + return + } + let urlParam = {} + let { + isLink: { + url, + params = [] + } + } = col + params.forEach(item => { + if (~item.indexOf('|')) { + let temp = item.split('|') + urlParam[temp[0]] = row[temp[1]] + } else { + urlParam[item] = row[item] + } + }) + url = this.setUrlParams(url, urlParam) + return url + }, + setUrlParams(url, params) { + let tempUrl = url, + keyArr = Object.keys(params) + keyArr.forEach(item => { + tempUrl += `&${item}=${params[item]}` + }) + tempUrl = tempUrl.replace(/\&/, '?') + return tempUrl + }, + itemClick(row, col) { + if (col.listenerClick) { + this.$emit('onClick', row) + } + }, + doSelect(isAll = false, index) { + let temp = new Set() + if (isAll) { + // 鍏ㄩ�� + if (!this.selectAll) { + for (let i = 0; i < this.tableData.length; i++) { + temp.add(i) + } + } + } else { + // if (!this.singleSelect) { + // this.selectArr.forEach(item => { + // temp.add(item) + // }) + // } + this.selectArr.forEach(item => { + temp.add(item) + }) + if (temp.has(index)) { + temp.delete(index) + } else { + if (this.singleSelect) { + temp.clear() + } + temp.add(index) + } + } + this.selectArr = Array.from(temp) + // console.log(this.selectArr) + if (this.selectArr.length == this.tableData.length) { + this.selectAll = true + } else { + this.selectAll = false + } + + this.$emit('onSelect', this.selectArr) + }, + // 1.1.1 + getTitleText(title) { + // 鑷畾涔夎〃澶� + let tempHTML = title + return tempHTML.toString() + } + } + } +</script> + +<style lang="scss"> + .navigator-hover { + background: transparent; + opacity: 1; + } + + @mixin ellipsis($num: 1) { + overflow: hidden; + text-overflow: ellipsis; + + @if $num==1 { + white-space: nowrap; + } + + @else { + display: -webkit-box; + -webkit-line-clamp: $num; + /* autoprefixer: off */ + -webkit-box-orient: vertical; + /* autoprefixer: on */ + } + } + + // 涓夎褰� + %triangle-basic { + content: ''; + height: 0; + width: 0; + overflow: hidden; + } + + @mixin triangle($direction, $size, $borderColor) { + @extend %triangle-basic; + + @if $direction==top { + border-bottom: $size solid $borderColor; + border-left: $size dashed transparent; + border-right: $size dashed transparent; + border-top: 0; + } + + @else if $direction==right { + border-left: $size solid $borderColor; + border-top: $size dashed transparent; + border-bottom: $size dashed transparent; + border-right: 0; + } + + @else if $direction==bottom { + border-top: $size solid $borderColor; + border-left: $size dashed transparent; + border-right: $size dashed transparent; + border-bottom: 0; + } + + @else if $direction==left { + border-right: $size solid $borderColor; + border-top: $size dashed transparent; + border-bottom: $size dashed transparent; + border-left: 0; + } + } + + a { + text-decoration: none; + } + + .z-table { + position: relative; + display: inline-block; + height: 100%; + min-height: 130rpx; + width: 100%; + background: #fff; + border: solid 2rpx #ccc; + font-size: $uni-font-size-sm; + box-sizing: border-box; + transform: translateZ(0); + + .z-table-main { + height: 100%; + box-sizing: border-box; + } + + .z-table-container { + height: 100%; + overflow: scroll; + box-sizing: border-box; + } + + .z-table-pack { + position: relative; + min-height: 100%; + width: fit-content; + } + + .z-table-title { + position: sticky; + top: 0; + height: 64rpx; + z-index: 1; + + .z-table-title-item { + border-bottom: solid 1rpx #dbdbdb; + background: #f8f8f8; + } + + .z-table-stick-side { + position: sticky; + top: 0; + left: 0; + border-right: solid 1rpx #dbdbdb; + box-sizing: border-box; + } + } + + .table-container-box.short-table { + padding-bottom: 48rpx; + } + + .z-table-title, + .z-table-container-row { + display: flex; + width: fit-content; + white-space: nowrap; + box-sizing: border-box; + + .z-table-title-item, + .z-table-container-col { + @include ellipsis(); + display: inline-flex; + padding: 0 16rpx; + height: 64rpx; + align-items: center; + line-height: 64rpx; + box-sizing: border-box; + } + } + + .z-table-container-row { + z-index: 0; + border-bottom: solid 1rpx #f4f4f4; + box-sizing: border-box; + } + + .z-table-stick-side { + position: sticky; + left: 0; + background: #f7f9ff; + border-right: solid 1rpx #dbdbdb; + box-sizing: border-box; + } + + .z-table-bottom { + position: absolute; + bottom: 0; + z-index: 9; + display: flex; + justify-items: center; + width: fit-content; + background: #4298f7 !important; + color: #fff !important; + white-space: nowrap; + box-sizing: border-box; + + &.long-table { + position: sticky; + } + + .z-table-stick-side { + background: #4298f7 !important; + box-sizing: border-box; + } + + .z-table-bottom-col { + display: inline-flex; + align-items: center; + text-align: center; + padding: 16rpx; + box-sizing: border-box; + } + + .z-table-bottom-text { + line-height: 100%; + box-sizing: border-box; + } + + .z-table-bottom-text-title { + margin-bottom: 10rpx; + font-size: 22rpx; + color: #aad0ff; + box-sizing: border-box; + } + + .sum { + margin-left: 14rpx; + font-size: 28rpx; + box-sizing: border-box; + } + } + + .table-empty { + position: absolute; + top: 64rpx; + height: 64rpx; + line-height: 64rpx; + width: 100%; + text-align: center; + } + + .sort { + display: flex; + padding: 5rpx; + flex-direction: column; + justify-content: center; + + .up-arrow { + @include triangle(top, 10rpx, #ccc); + display: block; + margin-bottom: 5rpx; + + &.action { + @include triangle(top, 10rpx, #4298f7); + } + } + + .down-arrow { + @include triangle(bottom, 10rpx, #ccc); + display: block; + + &.action { + @include triangle(bottom, 10rpx, #4298f7); + } + } + } + + // 1.0.5 + .z-loading { + position: absolute; + top: 0; + left: 0; + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; + background: #fff; + opacity: 0; + transition: all 0.3s; + + &.ztableLoading { + opacity: 1; + } + + .z-loading-animate { + position: relative; + display: inline-block; + width: 30rpx; + height: 30rpx; + margin-right: 20rpx; + border-radius: 100%; + border: solid 6rpx #ccc; + vertical-align: middle; + animation: rotate 1s ease-in-out infinite; + + &::after { + content: ''; + display: block; + position: absolute; + top: -10rpx; + z-index: 1; + background: #fff; + width: 20rpx; + height: 20rpx; + border-radius: 10rpx; + } + } + + @keyframes rotate { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } + } + } + + // 1.1.0 + .select-box { + display: inline-block; + width: 26rpx; + height: 26rpx; + line-height: 14rpx; + margin-right: 15rpx; + border: solid 2rpx #4298f7; + border-radius: 4rpx; + background: #fff; + text-align: center; + } + + .select-tip { + display: inline-block; + opacity: 0; + transform: rotate(90deg); + transition: all .3s; + + &.selected { + position: relative; + top: 4rpx; + left: -4rpx; + height: 4rpx; + background: #4298f7; + width: 10rpx; + opacity: 1; + transform: rotate(45deg); + + &:before, + &:after { + content: ''; + position: absolute; + display: block; + height: 4rpx; + background: #4298f7; + } + + &:before { + bottom: -2rpx; + left: -4rpx; + width: 8rpx; + transform: rotate(-90deg); + } + + &:after { + bottom: 16rpx; + right: -16rpx; + width: 34rpx; + transform: rotate(-90deg); + } + } + } + + // 1.1.1 + .z-table-col-text { + display: flex; + width: 100%; + flex: 1; + justify-content: flex-start; + align-content: center; + + &.text-center { + justify-content: center; + } + + &.text-right { + justify-content: flex-end; + } + } + } +</style> -- Gitblit v1.8.0