李兴辉 89b04fb058 init
2025-03-10 13:49:13 +08:00

1503 lines
41 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="z-table">
<view class="z-table-main" :style="[{ 'background-color': this.tempbackgroundColor }, { color: this.temptextColor }, { height: tableHeight + 'px' }]">
<view v-if="!tableLoaded && (!tableData || !columns)" :class="['z-loading', { ztableLoading: tableShow }]"><view class="z-loading-animate"></view></view>
<!-- 查询过滤器 -->
<view v-if="tbName.length > 0 || searchBox" class="pagination" :style="[{ 'border-bottom': '1rpx solid ' + templineColor }]">
<uni-lr-row :layout="searchBoxTW" style="height: 100%;width: 100%;padding:0">
<uni-input-row
slot="left"
v-if="tbName.length > 0 || searchBox"
type="hint"
:inputBorder="false"
v-model="tbName"
style="height: 100%;"
:after="false"
:hintIcons="false"
inputIcon="info"
:placeholderColor="temptitleColor"
:alignment="titleAlignment"
:iconColor="tempiconColor"
:readonlyColor="tempbackgroundColor"
:showButton="searchBox"
buttonIcon="search"
@buttonClick="buttonClick"
></uni-input-row>
<uni-lr-row v-if="searchBox" slot="right" :layout="40" style="height: 100%;width: 100%;">
<uni-input-row
slot="left"
type="combox"
rowHeight="100%"
:after="false"
:inputBorder="false"
:textColor="temptextColor"
:iconColor="tempiconColor"
:defaultColor="tempbackgroundColor"
:selectorColor="tempbackgroundColor"
:verify="true"
:clearable="true"
v-model="searchCol"
:range="searchColData"
rangeKey="field"
rangeVal="title"
placeholder="列名"
></uni-input-row>
<uni-input-row
slot="right"
type="text"
rowHeight="100%"
:after="false"
:inputBorder="false"
:textColor="temptextColor"
:iconColor="tempiconColor"
:defaultColor="tempbackgroundColor"
:buttonColor="tempbuttonColor"
clearable
showButton
btConfirm
buttonIcon="search"
v-model="searchVal"
@clear="onSearchClear"
@confirm="onSearch($event)"
placeholder="搜索内容"
></uni-input-row>
</uni-lr-row>
</uni-lr-row>
</view>
<!-- 表格内容 -->
<!-- "{ height: (searchBox || tbName.length > 0 ? 0 : 10) + (pagination ? 0 : 10) + 80 + '%' }" -->
<scroll-view scroll-y="true" scroll-x="true" :style="tbHeight">
<view class="z-table-pack" :style="[{ 'background-color': tempbackgroundColor }, { color: temptextColor }]">
<!-- 行头部 -->
<view class="z-table-title" :style="[{ 'border-right': '1rpx solid ' + templineColor }, { 'border-bottom': '1rpx solid ' + templineColor }]">
<!-- 添加行编号 -->
<view
v-if="rowNumbers"
:class="['z-table-title-item', { 'z-table-stick-side': fixedSelectBox }]"
:style="[
{ 'border-left': '1rpx solid ' + templineColor },
{ 'border-right': '1rpx solid ' + (showSelect ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ 'border-top': '1rpx solid ' + templineColor },
{ width: rowNW + 'rpx' },
{ 'background-color': tempbackgroundColor },
{ color: temptextColor }
]"
>
<view class="z-table-col-text text-center">
<view v-if="rowCount">{{ tableData.length }}</view>
</view>
</view>
<!-- 单选图片显示 -->
<view
v-if="showSelect && singleSelect"
:class="['z-table-title-item', { 'z-table-stick-side': fixedSelectBox }]"
:style="[
{ 'border-left': '1rpx solid ' + templineColor },
{ 'border-right': '1rpx solid ' + templineColor },
{ 'border-top': '1rpx solid ' + templineColor },
{ left: rowNumbers ? rowNW + 'rpx' : '0' },
{ width: showSW + 'rpx' },
{ 'background-color': tempbackgroundColor },
{ color: temptextColor }
]"
>
<uni-icons :color="tempiconColor" type="circle-filled" size="18"></uni-icons>
</view>
<!-- 多选复选框显示 -->
<view
v-if="showSelect && !singleSelect"
:class="['z-table-title-item', { 'z-table-stick-side': fixedSelectBox }]"
:style="[
{ 'border-left': '1rpx solid ' + templineColor },
{ 'border-right': '1rpx solid ' + templineColor },
{ 'border-top': '1rpx solid ' + templineColor },
{ left: rowNumbers ? rowNW + 'rpx' : '0' },
{ width: showSW + 'rpx' },
{ 'background-color': tempbackgroundColor },
{ color: temptextColor }
]"
>
<view class="select-box" @click="doSelect(true)"><view :class="['select-tip', { selected: selectAll }]"></view></view>
</view>
<!-- 列集合遍历 -->
<view
class="z-table-title-item"
:class="{ 'z-table-stick-side': stickSide && index == 0 }"
:style="[
{ 'border-left': '1rpx solid ' + (index === 0 ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ 'border-top': '1rpx solid ' + templineColor },
{ left: stickSide ? (rowNumbers ? rowNW : 0) + (showSelect ? showSW : 0) + 'rpx' : '0' },
{ width: item.width ? item.width + 'rpx' : '200rpx' },
{ 'background-color': tempbackgroundColor },
{ color: temptextColor }
]"
v-for="(item, index) in columns"
:key="index"
v-if="!item.hidden"
@click="sort(item.field, index)"
>
<view v-if="item.group" style="height: 100%;width: 100%;">
<!-- 显示列分组标题明细 -->
<view v-for="(gCol, gIndex) in item.columns" :key="gIndex">
<view
v-if="gIndex === 0 && item.gTitle && item.gTitle.length > 0"
:class="[
'z-table-col-text',
{
'text-left': item.talign === 'left' || talign === 'left',
'text-center': item.talign === 'center' || talign === 'center',
'text-right': item.talign === 'right' || talign === 'right'
}
]"
>
<view v-html="getTitleText(item)"></view>
</view>
<view
v-if="gCol.title && gCol.title.length > 0"
:class="[
'z-table-col-text',
{
'text-left': gCol.talign === 'left' || talign === 'left',
'text-center': gCol.talign === 'center' || talign === 'center',
'text-right': gCol.talign === 'right' || talign === 'right'
}
]"
>
<view v-html="getTitleText(gCol)"></view>
</view>
</view>
</view>
<view
v-else
:class="[
'z-table-col-text',
{
'text-left': item.talign === 'left' || talign === 'left',
'text-center': item.talign === 'center' || talign === 'center',
'text-right': item.talign === 'right' || talign === 'right'
}
]"
>
<view v-if="item.title && item.title.length > 0" v-html="getTitleText(item)"></view>
<view v-if="item.hasOwnProperty('field') && item.hasOwnProperty('sort') && tableData.length" class="sort">
<view
class="up-arrow"
:style="{ 'border-bottom': '4px solid ' + (nowSortKey == item.field && sortType == 'asc' ? temptitleColor : temptextColor) }"
></view>
<view
class="down-arrow"
:style="{ 'border-top': '4px solid ' + (nowSortKey == item.field && sortType == 'desc' ? temptitleColor : temptextColor) }"
></view>
</view>
</view>
</view>
</view>
<!-- 行内容 -->
<view
v-if="tableData.length"
:style="[{ 'border-right': '1rpx solid ' + templineColor }]"
:class="['table-container-box', { 'short-table': !longTable && showBottomSum }]"
>
<view
v-if="row.rowSearch && (!pagination || (current * pageSize - pageSize <= iIndex && iIndex < current * pageSize))"
class="z-table-container-row"
:class="{ 'z-table-has-bottom': showBottomSum }"
v-for="(row, iIndex) in tableData"
:key="iIndex"
:style="onRowStyle(row, iIndex)"
>
<!-- 添加行编号 -->
<view
v-if="rowNumbers"
:class="['z-table-container-col', { 'z-table-stick-side': fixedSelectBox }]"
:style="[
{ 'border-left': '1rpx solid ' + templineColor },
{ 'border-right': '1rpx solid ' + (showSelect ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ 'border-top': '1rpx solid ' + (iIndex === 0 ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ 'border-bottom': (!fillRow && iIndex == tableData.length - 1 ? '1' : '0') + 'rpx solid ' + templineColor },
{ width: rowNW + 'rpx' },
{ 'background-color': tempbackgroundColor }
]"
>
<view class="z-table-col-text text-center">
<view>{{ iIndex + 1 }}</view>
</view>
</view>
<!-- 添加复选框 -->
<view
v-if="showSelect"
:class="['z-table-container-col', { 'z-table-stick-side': fixedSelectBox }]"
:style="[
{ 'border-left': '1rpx solid ' + templineColor },
{ 'border-right': '1rpx solid ' + templineColor },
{ 'border-top': '1rpx solid ' + (iIndex === 0 ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ 'border-bottom': (!fillRow && iIndex == tableData.length - 1 ? '1' : '0') + 'rpx solid ' + templineColor },
{ left: rowNumbers ? rowNW + 'rpx' : '0' },
{ width: showSW + 'rpx' },
{ 'background-color': tempbackgroundColor }
]"
>
<view class="select-box" @click="doSelect(false, iIndex, row)"><view :class="['select-tip', { selected: row['rowChecked'] }]"></view></view>
</view>
<!-- 行数据遍历 -->
<view
:class="['z-table-container-col', { 'z-table-stick-side': stickSide && jIndex == 0 }]"
:style="[
{ 'border-left': '1rpx solid ' + (jIndex === 0 ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ 'border-top': '1rpx solid ' + (iIndex === 0 ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ 'border-bottom': (!fillRow && iIndex == tableData.length - 1 ? '1' : '0') + 'rpx solid ' + templineColor },
{ left: stickSide ? (rowNumbers ? rowNW : 0) + (showSelect ? showSW : 0) + 'rpx' : '0' },
{ width: col.width ? col.width + 'rpx' : '200rpx' }
]"
v-for="(col, jIndex) in columns"
:key="jIndex"
v-if="!col.hidden"
@click="itemClick(iIndex, row, col)"
>
<!-- 多分组的时候,是否需要把内容填充 style="height: 100%;width: 100%;" -->
<view v-if="col.group">
<view v-for="(gCol, gIndex) in col['columns']" :key="gIndex">
<view
v-html="getRowContent(row, gCol, iIndex)"
:class="[
'z-table-col-text',
{
'text-left': col.align === 'left' || align === 'left',
'text-center': col.align === 'center' || align === 'center',
'text-right': col.align === 'right' || align === 'right'
}
]"
></view>
</view>
</view>
<view
v-else
v-html="getRowContent(row, col, iIndex)"
:class="[
'z-table-col-text',
{
'text-left': col.align === 'left' || align === 'left',
'text-center': col.align === 'center' || align === 'center',
'text-right': col.align === 'right' || align === 'right'
}
]"
></view>
</view>
</view>
<!-- 空白行 -->
<view
v-if="fillRow && tableData.length < fillCount"
class="z-table-container-row"
:class="{ 'z-table-has-bottom': showBottomSum }"
v-for="(row, marginIndex) in fillCount"
>
<!-- 添加行编号 -->
<view
v-if="rowNumbers"
:class="['z-table-container-col', { 'z-table-stick-side': fixedSelectBox }]"
:style="[
{ 'border-left': '1rpx solid ' + templineColor },
{ 'border-right': '1rpx solid ' + (showSelect ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ width: rowNW + 'rpx' },
{ 'background-color': (tableData.length + marginIndex) % 2 === 0 ? tempbackgroundColor2 : tempbackgroundColor }
]"
>
<view class="z-table-col-text text-center"><view></view></view>
</view>
<!-- 添加复选框 -->
<view
v-if="showSelect"
:class="['z-table-container-col', { 'z-table-stick-side': fixedSelectBox }]"
:style="[
{ 'border-left': '1rpx solid ' + templineColor },
{ 'border-right': '1rpx solid ' + templineColor },
{ left: rowNumbers ? rowNW + 'rpx' : '0' },
{ width: showSW + 'rpx' },
{ 'background-color': (tableData.length + marginIndex) % 2 === 0 ? tempbackgroundColor2 : tempbackgroundColor }
]"
>
<view><view class="select-tip"></view></view>
</view>
<!-- 行数据遍历 -->
<view
:class="['z-table-container-col', { 'z-table-stick-side': stickSide && jIndex == 0 }]"
:style="[
{ 'border-left': '1rpx solid ' + (marginjIndex === 0 ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ left: stickSide ? (rowNumbers ? rowNW : 0) + (showSelect ? showSW : 0) + 'rpx' : '0' },
{ width: col.width ? col.width + 'rpx' : '200rpx' },
{ 'background-color': (tableData.length + marginIndex) % 2 === 0 ? tempbackgroundColor2 : tempbackgroundColor }
]"
v-for="(col, marginjIndex) in columns"
v-if="!col.hidden"
>
<view class="z-table-col-text"></view>
</view>
</view>
</view>
</view>
<!-- 页脚 -->
<view
:class="['z-table-bottom', { 'long-table': longTable }]"
:style="[{ 'border-right': '1rpx solid ' + templineColor }, { 'border-bottom': '1rpx solid ' + templineColor }]"
v-if="showBottomSum && tableData.length"
>
<!-- 行号和复选框站的宽度 -->
<view
class="z-table-bottom-col z-table-stick-side"
:style="[
{ 'border-left': '1rpx solid ' + templineColor },
{ 'border-right': '1rpx solid ' + templineColor },
{ 'border-top': '1rpx solid ' + templineColor },
{ width: (rowNumbers ? rowNW : 0) + (showSelect ? showSW : 0) + (rowNumbers && showSelect ? -1 : 0) + 'rpx' },
{ 'background-color': tempfooterColor },
{ color: temptextColor }
]"
>
<view class="z-table-bottom-text"><uni-icons :color="tempiconColor" type="huizong" size="20" /></view>
</view>
<!-- 遍历列数分别计算合计值 -->
<view
class="z-table-bottom-col"
:class="{ 'z-table-stick-side': stickSide && sumIndex == 0 }"
:style="[
{ 'border-left': '1rpx solid ' + (sumIndex === 0 ? 'rgb(0, 0, 0, 0)' : templineColor) },
{ 'border-top': '1rpx solid ' + templineColor },
{ left: stickSide ? (rowNumbers ? rowNW : 0) + (showSelect ? showSW : 0) + 'rpx' : '0' },
{ width: sumCol.width ? sumCol.width + 'rpx' : '200rpx' },
{ 'background-color': tempfooterColor },
{ color: temptextColor }
]"
v-for="(sumCol, sumIndex) in columns"
:key="sumIndex"
v-if="!sumCol['hidden']"
>
<view
class="z-table-bottom-text"
:class="[
'z-table-col-text',
{
'text-left': sumCol.align === 'left' || align === 'left',
'text-center': sumCol.align === 'center' || align === 'center',
'text-right': sumCol.align === 'right' || align === 'right'
}
]"
>
<!-- 默认总计后面扩展平均值最大最小值都可以 -->
<text>{{ dosum(sumCol) }}</text>
</view>
</view>
</view>
</scroll-view>
<!-- 分页器 -->
<view v-if="pagination" class="pagination" :style="[{ 'border-top': '1rpx solid ' + templineColor }]">
<uni-pagination
style="height: 100%;"
show-icon="true"
:pageSize="pageSize"
:iconColor="tempiconColor"
:textColor1="temptitleColor"
:textColor="temptextColor"
:buttonColor="tempbuttonColor"
:total="searchLen > 0 ? searchLen : tableData.length"
:current="current"
@change="paginationChange"
></uni-pagination>
</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以'|'链接,如果不带'|'默认键值同名
* cellClick(是否监听点击事件Boolean)}
* stickSide Boolean | 是否固定右侧首栏 默认不显示
* showBottomSum Boolean | 是否显示底部统计 默认不显示
* showLoading Boolean | 是否首次加载首次加载不显示暂无数据内容
* emptyText String | 空数据显示的文字内容
* tableHeight Number | 设置表格高度会滚动
* sort Boolean | 开启排序
* showSelect Boolean | 开启选择
* singleSelect Boolean | 在开启选择的状态下是否开起单选
* align String | 内容对齐方式 left center right
* talign String | 表头对齐方式 left center right
*
* event: onSort | 排序事件 返回{field: 被排序列的字段名, type: 正序'asc'/倒序'desc'}
* onSelect | 选中时触发 返回选择的行的下标
* onClick | 单元格点击事件 返回点击单元格所属行的数据
*
* function: resetSort | 调用后重置排序 *注意:不会触发sort事件
*
* */
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: [],
//分页器,每页数据量
pageSize: 100,
//分页器,当前页
current: 1,
//查询过滤后的数据源总数
searchLen: 0,
//查询列下拉框数据源
searchColData: [],
//查询列下拉框选中行数据
searchCol: {},
//查询过滤输入框输入的内容
searchVal: '',
//查询管理器中的宽度比例 title width
searchBoxTW: 100,
//按钮颜色
tempbuttonColor: '#ffffff',
//选择行背景颜色
tempselectRowColor: '#ffe48d',
//图片按钮颜色
tempiconColor: '#000000',
//标题类字体颜色
temptitleColor: '#5500ff',
//文本颜色/线颜色
temptextColor: '#000000',
//线颜色
templineColor: '#d4d4d4',
//主背景颜色
tempbackgroundColor: '#f3f3f3',
//次背景颜色
tempbackgroundColor2: '#ffffff',
//页脚背景颜色
tempfooterColor: '#d4e6ff',
fillCount: 15
};
},
computed: {
//表格高度样式设置,计算是否显示表头和分页器,然后计算出行内容高度
tbHeight() {
let h=0;
if(this.searchBox || this.tbName.length > 0){
h+=33;
}
if(this.pagination)
{
h+=33;
}
return {height:this.tableHeight-h+"px"};
}
},
props: {
tbName: {
type: String,
default: ''
},
tableData: {
type: [Array, Boolean],
default() {
return false;
}
},
columns: {
/*
*
* [{title: xxx, field: 当前列展示对象名, 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: 500
},
//开启选择
showSelect: {
type: Boolean,
default: false
},
//在开启选择的状态下是否开起单选
singleSelect: {
type: Boolean,
default: true
},
//内容对齐方式 left center right
align: {
type: String,
default: 'left' // right|center|left
},
//表头对齐方式 left center right
talign: {
type: String,
default: 'left' // right|center|left
},
//如果为true当用户点击行的时候该复选框就会被选中或取消选中。
//如果为false当用户仅在点击该复选框的时候才会被选中或取消。
checkOnSelect: {
type: Boolean,
default: true
},
//是否固定复选框
fixedSelectBox: {
type: Boolean,
default: true
},
//是否显示总行数。
rowCount: {
type: Boolean,
default: false
},
//如果为true则显示一个行号列。
rowNumbers: {
type: Boolean,
default: false
},
//表格数据查询操作
searchBox: {
type: Boolean,
default: false
},
//表格数据分页操作
pagination: {
type: Boolean,
default: false
},
//行序号宽度 rowNumbersWidth
rowNW: {
type: Number,
default: 50
},
//复选框宽度 showSelectWidth
showSW: {
type: Number,
default: 50
},
// 主题颜色,默认白色
theme: {
type: String,
default: ''
},
//按钮背景颜色
buttonColor: {
type: String,
default: '#ffffff'
},
//选择行背景颜色
selectRowColor: {
type: String,
default: '#ffe48d'
},
//图片按钮颜色
iconColor: {
type: String,
default: '#000000'
},
//标题类字体颜色
titleColor: {
type: String,
default: '#5500ff'
},
//标题类字体对齐方式 默认左对齐
titleAlignment: {
type: String,
default: 'left'
},
//文本颜色
textColor: {
type: String,
default: '#000000'
},
//线条颜色
lineColor: {
type: String,
default: '#d4d4d4'
},
//主背景颜色
backgroundColor: {
type: String,
default: '#f3f3f3'
},
//次背景颜色
backgroundColor2: {
type: String,
default: '#ffffff'
},
//页脚颜色
footerColor: {
type: String,
default: '#d4e6ff'
},
//是否填充空行
fillRow: {
type: Boolean,
default: false
}
},
created() {},
mounted() {
//初始化表格数据
this.init();
//设置主题颜色
if (this.theme === 'white') {
//白色
//按钮颜色
this.tempbuttonColor = '#ffffff';
//选择行背景颜色
this.tempselectRowColor = '#ffe48d';
//图片按钮颜色
this.tempiconColor = '#000000';
//标题类字体颜色
this.temptitleColor = '#5500ff';
//文本颜色/线颜色
this.temptextColor = '#000000';
//线颜色
this.templineColor = '#d4d4d4';
//主背景颜色
this.tempbackgroundColor = '#f3f3f3';
//次背景颜色
this.tempbackgroundColor2 = '#ffffff';
//页脚颜色
this.tempfooterColor = '#d4e6ff';
} else if (this.theme === 'black') {
//黑色
this.tempbuttonColor = '#5e6576';
this.tempselectRowColor = '#5e6434';
this.tempiconColor = '#bcc1d6';
this.temptitleColor = '#2488ea';
this.temptextColor = '#bcc1d6';
this.templineColor = '#8e93a1';
this.tempbackgroundColor = '#0f1628';
this.tempbackgroundColor2 = '#1c263f';
this.tempfooterColor = '#545834';
} else {
//自定义
this.tempbuttonColor = this.buttonColor;
this.tempselectRowColor = this.selectRowColor;
this.tempiconColor = this.iconColor;
this.temptitleColor = this.titleColor;
this.temptextColor = this.textColor;
this.templineColor = this.lineColor;
this.tempbackgroundColor = this.backgroundColor;
this.tempbackgroundColor2 = this.backgroundColor2;
this.tempfooterColor = this.footerColor;
}
},
watch: {
columns(e) {
this.init();
},
tableData() {
this.init();
},
buttonColor(newVal, oldVal) {
this.tempbuttonColor = newVal;
},
selectRowColor(newVal, oldVal) {
this.tempselectRowColor = newVal;
},
iconColor(newVal, oldVal) {
this.tempiconColor = newVal;
},
titleColor(newVal, oldVal) {
this.temptitleColor = newVal;
},
textColor(newVal, oldVal) {
this.temptextColor = newVal;
},
backgroundColor(newVal, oldVal) {
this.tempbackgroundColor = newVal;
},
backgroundColor2(newVal, oldVal) {
this.tempbackgroundColor2 = newVal;
}
// tableHeight(newVal,oldVal){
// console.log(newVal+'高度改变'+oldVal);
// if (newVal != oldVal) {
// console.log('高度改变');
// }
// },
},
methods: {
//行样式操作
onRowStyle(row, index) {
let backgroundColor = row['rowChecked'] ? this.tempselectRowColor : index % 2 === 0 ? this.tempbackgroundColor2 : this.tempbackgroundColor;
let css = {
'background-color': backgroundColor,
color: this.temptextColor
};
this.$emit('onRowStyle', { index: index, row: row }, res => {
var assignObj = Object.assign(css, res);
});
return css;
},
async init() {
// 重置选择内容
this.selectAll = false;
this.selectArr = [];
this.tableLoaded = false;
this.tableShow = true;
this.searchLen = 0;
this.pageSize = 100;
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;
});
}
if (_this.tableData && _this.tableData.length) {
_this.tableData.forEach((item, index) => {
this.$set(item, 'rowChecked', false);
this.$set(item, 'rowSearch', true);
this.$set(item, 'rowIndex', index);
});
}
let tempSearchColData = [];
if (_this.columns && _this.columns.length) {
_this.columns.forEach((item, index) => {
if (item['group'] && item['columns'].length > 0) {
item['columns'].forEach((gItem, gIndex) => {
if (gItem.field && gItem.title) {
this.$set(gItem, 'index', index + gIndex);
tempSearchColData.push(gItem);
}
});
} else {
if (item.field && item.title) {
this.$set(item, 'index', index);
tempSearchColData.push(item);
}
}
});
this.searchColData = tempSearchColData;
}
},
getPageSize(selecter) {
// 获取元素信息
let query = uni.createSelectorQuery().in(this),
_this = this;
return new Promise((resolve, reject) => {
query
.select(selecter)
.boundingClientRect(res => {
resolve(res);
})
.exec();
});
},
//页脚计算数量
dosum({ field, noSum = false, formatNum = true }) {
let sum = '-';
if (noSum) return sum;
if (this.tableData) {
if (
this.tableData.every(item => {
return !Number.isNaN(item[field] - 0);
})
) {
sum = 0;
this.tableData.map((item, index) => {
if (!field && index != 0) {
sum = '-';
} else {
let val = item[field] - 0;
if (Number.isNaN(val) || !item['rowSearch']) {
sum += 0;
} else {
sum += val;
}
}
});
}
}
// sum = sum == 0 ? "-" : sum
// return formatNum ? this.numTransform(sum) : sum
return sum;
},
//得到单元格html内容
getRowContent(row, col, index) {
let tempHTML = '';
//得到内容
let rowKey = row[col.field];
if ([null, ''].includes(rowKey)) {
rowKey = '-';
}
let { formatNum = true } = col;
if (rowKey || rowKey === 0) {
tempHTML = rowKey;
// tempHTML = isNaN(rowKey - 0) || !formatNum
// ? rowKey
// : this.numTransform(rowKey - 0);
}
//设置自定义内容
if (col.format) {
tempHTML = col.format(rowKey, row, index);
}
tempHTML = "<view style='white-space:normal;word-break:break-all;word-wrap:break-word;'>" + tempHTML + '</view>';
//设置超链接路径
if (col.link) {
let link = col.link(tempHTML, row, index);
let urlParam = {};
if (link.params && link.params.length > 0) {
link.params.forEach(item => {
if (~item.indexOf('|')) {
let temp = item.split('|');
urlParam[temp[0]] = row[temp[1]];
} else {
urlParam[item] = row[item];
}
});
}
let url = this.setUrlParams(link.url, urlParam); //得到超链接参数
tempHTML = '<a style="color:' + this.temptitleColor + '" href="' + url + '">' + tempHTML + '</a>';
}
//设置自定义单元格样式
if (col.styler) {
let align = 'flex-start'; //默认 left
if (col.align === 'center' || align === 'center') {
align = 'center';
}
if (col.align === 'right' || align === 'right') {
align = 'flex-end';
}
let style = ' display: flex;' + 'width: 100%;' + 'height: 100%;' + 'flex: 1;' + 'justify-content: ' + align + ';' + 'align-content:center; ';
style += col.styler(rowKey, row, index);
tempHTML = '<view style="' + style + '"><view>' + tempHTML + '</view></view>';
}
return tempHTML.toString();
},
// 得到超链接参数
setUrlParams(url, params) {
let tempUrl = url,
keyArr = Object.keys(params);
keyArr.forEach(item => {
tempUrl += `&${item}=${params[item]}`;
});
tempUrl = tempUrl.replace(/\&/, '?');
return tempUrl;
},
//排序操作
sort(field, index) {
if (!field || !this.columns[index].sort) {
return;
}
// 排序功能: 如果点击的排序按钮是原先的 那么更改排序类型
// 如果点击的另一个排序按钮 那么选择当前排序并且排序类型改为降序(desc)
if (field != this.nowSortKey) {
this.nowSortKey = field;
this.sortType = 'desc';
} else {
this.toggleSort();
}
//优先先本地排序如果需要重新从数据库查询可调用onSort事件
let arr = this.tableData;
for (let j = 0; j < arr.length - 1; j++) {
//外层循环,控制趟数,每一次找到一个最大值
for (let i = 0; i < arr.length - 1 - j; i++) {
// 内层循环,控制比较的次数,并且判断两个数的大小
if (this.sortType == 'asc') {
if (arr[i][this.nowSortKey] > arr[i + 1][this.nowSortKey]) {
let temp = arr[i + 1];
arr[i + 1] = arr[i];
arr[i] = temp;
}
} else if (arr[i][this.nowSortKey] < arr[i + 1][this.nowSortKey]) {
let temp = arr[i + 1];
arr[i + 1] = arr[i];
arr[i] = temp;
}
}
}
this.$emit('onSort', {
field: 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';
},
// 单元格点击事件
itemClick(index, row, col) {
//隐藏查询工具栏
if (this.searchBoxTW === 0) {
this.buttonClick();
}
//点击就选中行
if (this.checkOnSelect) {
this.doSelect(false, index, row);
}
//监听单元格点击事件
if (col.cellClick) {
this.$emit('onClick', { index: index, row: row, col: col });
}
},
//选中行事件 isAll:是否为全选
doSelect(isAll = false, thisIndex, thisRow) {
if (isAll) {
this.selectArr = [];
this.selectAll = !this.selectAll;
this.tableData.forEach((item, index) => {
if (this.selectAll) {
if (item['rowSearch']) {
if (!item['rowChecked']) {
this.$set(item, 'rowChecked', true);
}
this.selectArr.push(index);
}
} else {
if (item['rowChecked']) {
this.$set(item, 'rowChecked', false);
}
}
});
} else {
const thisCheck = this.tableData[thisIndex]['rowChecked'] || false;
this.$set(this.tableData[thisIndex], 'rowChecked', !thisCheck);
//检查是否已经为全部选中状态
var tempSelectAll = true;
//单选
if (this.singleSelect) {
//判断是不是原来选择的索引如果就直接清空不需要在push到选择数组中
if (this.selectArr.length > 0 && this.selectArr[0] == thisIndex) {
this.selectArr = [];
} else {
this.selectArr = [];
this.selectArr.push(thisIndex);
}
tempSelectAll = false;
}
this.selectArr = [];
for (let i = 0; i < this.tableData.length; i++) {
if (this.singleSelect && thisIndex !== i) {
//单选
//除了当前选中的,其他全部为未选中状态
this.$set(this.tableData[i], 'rowChecked', false);
} else {
//多选
if (tempSelectAll && !this.tableData[i]['rowChecked']) {
tempSelectAll = false;
}
if (this.tableData[i]['rowChecked']) {
this.selectArr.push(i);
}
}
}
this.selectAll = tempSelectAll;
}
const index = this.singleSelect ? (this.selectArr.length > 0 ? this.selectArr[0] : -1) : this.selectArr;
this.$emit('onSelect', { index: index, row: thisRow });
},
// 返回表头标签内容
getTitleText(col) {
let tempHTML = '';
if (col.titler) {
tempHTML = col.titler();
} else if (col.title) {
tempHTML = col.title;
} else {
tempHTML = col.gTitle;
}
return tempHTML.toString();
},
//分页器点击事件
paginationChange(e) {
this.current = e.current;
// console.log(JSON.stringify(e)+this.current);
},
//搜索内容提交事件
onSearch(e) {
//搜索内容为空的时候,默认全选
if (e === '') {
this.tableData.forEach((item, index) => {
this.$set(item, 'rowSearch', true);
});
this.searchLen = this.tableData.length;
this.pageSize = 100;
return;
}
//过滤后的数据总行数
var len = 0;
this.tableData.forEach((item, index) => {
//指定列过滤
if (this.searchCol['index'] >= 0) {
var cellVal = item[this.searchCol['key']] + '';
if (cellVal.length > 0 && cellVal.indexOf(e) > -1) {
this.$set(item, 'rowSearch', true);
len += 1;
} else {
this.$set(item, 'rowSearch', false);
}
} else {
//全列过滤
this.$set(item, 'rowSearch', false);
let exist = false;
for (var i = 0; i < this.searchColData.length; i++) {
//列集合中不存在field
if (!this.searchColData[i]['field']) {
continue;
}
var cellVal = item[this.searchColData[i]['field']] + '';
if (cellVal.length > 0 && cellVal.indexOf(e) > -1) {
this.$set(item, 'rowSearch', true);
exist = true;
}
}
len += exist ? 1 : 0;
}
});
this.searchLen = len;
//查询后的数据不进行分页
this.current = 1;
this.pageSize = this.tableData.length;
},
//搜索清空按钮事件
onSearchClear() {
this.onSearch('');
},
// 展开查询框按钮事件
buttonClick() {
this.searchBoxTW = this.searchBoxTW === 0 ? 100 : 0;
}
}
};
</script>
<style lang="scss">
.m-input-row {
padding: 0;
}
.pagination {
// height: 10%;
height: 33px;
}
.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%;
width: 100%;
min-height: 130rpx;
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-pack {
position: relative;
min-height: 100%;
width: fit-content;
}
.z-table-title {
position: sticky;
width: 100% !important;
top: 0;
min-height: 64rpx;
z-index: 1;
.z-table-title-item {
// border-bottom: solid 1rpx #dbdbdb;
// border-right: 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 3rpx;
min-height: 64rpx;
align-items: center;
line-height: 64rpx;
box-sizing: border-box;
// flex-direction:column;
// border-right: solid 1rpx #dbdbdb;
}
}
.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 0 16rpx 0;
box-sizing: border-box;
}
.z-table-bottom-text {
line-height: 100%;
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: 30rpx;
height: 30rpx;
line-height: 14rpx;
margin: 0 5rpx;
border: solid 2rpx #4298f7;
border-radius: 4rpx;
background: #fff;
text-align: center;
}
.select-tip {
display: inline-block;
opacity: 0;
transform: rotate(90deg);
transition: all 0.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%;
height: 100%;
flex: 1;
justify-content: flex-start;
align-content: center;
&.text-center {
justify-content: center;
}
&.text-right {
justify-content: flex-end;
}
}
}
</style>