| | |
| | | <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初始值设为false,当没有数据的时候值为空数组
|
| | | * props: tableData [Array | Boolean] | 表格数据 如果为false则显示loading
|
| | | * columns [Array | Boolean] | 数据映射表 如果为false则显示loading 每列params => title(表头文字可以是html字符串模版), width(每列宽度) [, key(对应tableData的字段名) || format(自定义内容), sort(是否要排序), isLink(是否显示为超链接Object)]
|
| | | * format格式: {template: 字符串模版用#key#表示需要被替换的数据,names: 对应template属性内要被替换的内容的key}
|
| | | * isLink格式: {url: 链接地址, params: 地址带的参数Array[key|value, key|value, ...]每一项都是key和value以'|'链接,如果不带'|'默认键值同名
|
| | | * 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: 正序'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('数据的key或format值至少一个不为空')
|
| | | throw error
|
| | | }
|
| | | // console.log(tempHTML)
|
| | | return tempHTML.toString()
|
| | | },
|
| | | sort(key, index) {
|
| | | if (!key || !this.columns[index].sort) {
|
| | | return
|
| | | }
|
| | | // 排序功能: 如果点击的排序按钮是原先的 那么更改排序类型
|
| | | // 如果点击的另一个排序按钮 那么选择当前排序并且排序类型改为降序(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初始值设为false,当没有数据的时候值为空数组 |
| | | * props: tableData [Array | Boolean] | 表格数据 如果为false则显示loading |
| | | * columns [Array | Boolean] | 数据映射表 如果为false则显示loading 每列params => title(表头文字可以是html字符串模版), width(每列宽度) [, key(对应tableData的字段名) || format(自定义内容), sort(是否要排序), isLink(是否显示为超链接Object)] |
| | | * format格式: {template: 字符串模版用#key#表示需要被替换的数据,names: 对应template属性内要被替换的内容的key} |
| | | * isLink格式: {url: 链接地址, params: 地址带的参数Array[key|value, key|value, ...]每一项都是key和value以'|'链接,如果不带'|'默认键值同名 |
| | | * 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: 正序'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('数据的key或format值至少一个不为空') |
| | | throw error |
| | | } |
| | | // console.log(tempHTML) |
| | | return tempHTML.toString() |
| | | }, |
| | | sort(key, index) { |
| | | if (!key || !this.columns[index].sort) { |
| | | return |
| | | } |
| | | // 排序功能: 如果点击的排序按钮是原先的 那么更改排序类型 |
| | | // 如果点击的另一个排序按钮 那么选择当前排序并且排序类型改为降序(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> |