<template>
<div class="content">
<div class="myForm">
<el-form
:model="searchForm"
ref="refForm"
:label-width="searchConfig.labeWidth"
:inline="searchConfig.inline">
<template v-if="searchForm || searchConfig.itemList">
<el-form-item v-for="(item,index) of searchConfig.itemList" :key="index" :label="item.label" :prop="item.prop" :class="item.type" :style="{marginLeft:item.marginLeft}">
<span v-if="item.type =='text'">{{searchForm[item.prop]}}</span>
<el-input v-if="item.type =='input'" v-model="searchForm[item.prop]" clearable :size="item.size?item.size :'medium'" :disabled="item.disabled" :placeholder="item.placeholder" :style="{width: item.width}"></el-input>
<el-select clear="select_btn" v-if="item.type =='select'" v-model="searchForm[item.prop]" clearable :size="item.size?item.size :'medium'" :placeholder="item.placeholder" :style="{width: item.width}">
<el-option v-for="opt of item.option" :key="item.optionControl ? opt[item.optionControl.value] : opt.value" :label="item.optionControl ? opt[item.optionControl.label] : item.label" :value="item.optionControl ? opt[item.optionControl.value] : item.value"></el-option>
</el-select>
<!-- 下拉模糊查询多选 -->
<el-select v-if="item.type =='selectFilter'" v-model="searchForm[item.prop]"
:filterable="searchConfig.paginationOption.remote"
multiple
:loading="searchConfig.paginationOption.loading"
:remote="searchConfig.paginationOption.remote"
:size="item.size?item.size :'medium'"
clearable
:style="{width: item.width}"
:placeholder="item.placeholder">
<el-option v-for="opt of item.option" :key="item.optionControl ? opt[item.optionControl.label] : opt.value" :label="item.optionControl ? opt[item.optionControl.label] : item.label" :value="item.optionControl ? opt[item.optionControl.value] : item.value">
</el-option>
<pagination
v-if="searchConfig.paginationOption.total > 0"
small
:total="searchConfig.paginationOption.total"
:page.sync="searchConfig.paginationOption.pageNum"
:limit.sync="searchConfig.paginationOption.pageSize"
@pagination = "selectpageNationChange"
/>
</el-select>
<el-date-picker v-if="item.type =='datapicker'"
type="date"
:size="item.size?item.size :'medium'"
:placeholder="item.placeholder"
v-model="searchForm[item.prop]"
clearable
:style="{width: item.width}"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
:picker-options="item.hasOwnProperty('dayOptions') && item.dayOptions ? item.dayOptions : {//日限制
disabledDate: (time) => {
return time.getTime() > Date.now()
},
}"
></el-date-picker>
<el-time-picker v-if="item.type =='timepicker'"
:size="item.size?item.size :'medium'"
:placeholder="item.placeholder"
v-model="searchForm[item.prop]"
clearable
:style="{width: item.width}"></el-time-picker>
<!-- 时间范围选择 -->
<el-date-picker
v-if="item.type === 'datetimerange'"
key="datetimerange"
type="datetimerange"
:size="item.size?item.size :'medium'"
v-model="searchForm[item.prop]"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
clearable
:style="{width: item.width}"
:picker-options="item.hasOwnProperty('datetimeOptions') && item.datetimeOptions ? item.datetimeOptions : {//开始-结束时间限制 -带时分秒
onPick: ({ maxDate, minDate }) => {
searchForm[item.prop]= [];
searchForm[item.prop].push( minDate.getTime());
if (maxDate) {
searchForm[item.prop] = []
}
},
disabledDate: time => {//这里没有限制你的开始时间不能小于某个时间,可以在自己页面写
return time.getTime() > new Date().getTime();//time.getTime() + 24 * 3600 * 1000 > new Date().getTime()
},
shortcuts: [
{
text: '最近一个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 29);//这里先限制30天内吧,不然继保那边接口报错
picker.$emit('pick', [start, end]);
}
}]
}"
></el-date-picker>
</el-form-item>
</template>
<!-- 自定义按钮 -->
<template v-if="searchConfig.btnArr">
<el-form-item>
<el-button
v-for="(item, index) of searchConfig.btnArr"
:key="item + index"
:icon="item.icon ? item.icon : ''"
@click="handleClick(item)"
size="mini"
:type="item.type"
:disabled="item.disabled"
>{{ item.name }}</el-button >
</el-form-item>
</template>
<div :class="searchConfig.btnClass ? searchConfig.btnClass : ''">
<div v-if="searchConfig.leftBtnArr">
<el-button
v-for="(item, index) of searchConfig.leftBtnArr"
:key="item + index"
:icon="item.icon ? item.icon : ''"
@click="handleClick(item)"
size="mini"
:type="item.type"
:disabled="item.disabled"
>{{ item.name }}</el-button >
</div>
<div
v-if="searchConfig.rightBtnArr"
:class="
searchConfig.btnClass ? searchConfig.btnClass : 'margin-top' " >
<el-button
v-for="(item, index) of searchConfig.rightBtnArr"
:key="item + index"
:icon="item.icon ? item.icon : ''"
@click="handleClick(item)"
size="mini"
:type="item.type"
:disabled="item.disabled"
>{{ item.name }}</el-button>
</div>
</div>
</el-form>
</div>
<div :class="{'myTable':isMyTable}">
<el-table
:show-header="tableConfig.showHeader"
:show-summary="tableConfig.showSummary"
:summary-method="getSummaries"
:header-cell-style="tableConfig.headerCellStyle ? tableConfig.headerCellStyle : {background: '#0c2c5d'}"
stripe
v-loading="tableConfig.tableLoading"
:data="tableConfig.tableData"
style="width: 100%"
:height="tableConfig.istableHeight ? tableConfig.istableHeight : tableConfig.tHeight"
@row-click="$rowClick"
@selection-change="$handleSelectionChange"
@row-dblclick="$doubleClick"
@current-change="$handleCurrentChange"
:span-method="objectSpanMethod"
:highlight-current-row = "tableConfig.highlight"
show-overflow-tooltip
ref="multipleTable" >
<el-table-column width="65" v-if="tableConfig.rowSelection ==='radio' ">
<template slot-scope="scope">
<el-radio v-model="templateSelection" :label="scope.row" @click.native.prevent="singleElection">{{ "" }}</el-radio>
</template>
</el-table-column>
<el-table-column type="selection" width="55" v-if="tableConfig.rowSelection ==='checkbox'"> </el-table-column>
<el-table-column label="序号" width="50">
<template slot-scope="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column v-for="(item,index) in tableConfig.columns" :key=" index"
:width="item.width?item.width:'auto'"
:min-width="item.minWidth"
:prop="item.prop"
:formatter="item.formatter"
show-overflow-tooltip
tooltip-effect="light"
:align="item.align?item.align:'center'"
:label="item.label">
<template slot-scope="{ row }">
<span v-if="!item.render">{{ row[item.prop] == null || row[item.prop] == '' ? '-' : row[item.prop] }}</span>
<render-dom v-else :render-func="item.render" :row="row"></render-dom>
</template>
</el-table-column>
<el-table-column label="操作" :width="tableConfig.actionWidth ? tableConfig.actionWidth : '200'" v-if="tableConfig.actionArr">
<template slot-scope="{ row }">
<el-button v-for="(item,index) of tableConfig.actionArr"
:key="index" size="mini"
:type="item.type"
:disabled="disabledFunc(item,row)"
@click="item.hasOwnProperty('clickAction')&& typeof item.clickAction(item,row) === 'function' ? item.clickAction(item,row) : clickAction(item,row)">
<span v-if="!item.render"> {{ item.name}}</span>
<render-dom v-else :render-func="item.render" :row="row"></render-dom>
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-if="tableConfig.total > 0"
:total="tableConfig.total"
:page.sync="tableConfig.pageNum"
:limit.sync="tableConfig.pageSize"
@pagination="paginationFunc"
:small="tableConfig.paginationType ? tableConfig.paginationType : false"
/>
</div>
</div>
</template>
<script>
import "@/assets/reset.css";
import "@/assets/global.less";
import renderDom from "./renderDom";
export default {
name: "TableList",
components: { renderDom },
props: {
searchConfig: {
type: Object,
default: function () {
return {
labeWidth: "auto",
paginationOption:{//分页配置项
type:Object,
default:function () {
return {
total: 0,
pageNum: 1,
pageSize: 6,
paginationType: false, //是否使用小型分页,默认false
loading:{//远程数据加载状态显示
type:Boolean,
default:false
},
remote:{//是否支持远程搜索,默认支持
type:Boolean,
default:true
},
}
},
},
};
},
},
searchForm: Object,
tableConfig: {
type: Object,
default: function () {
return {
tableLoading: {
type: Boolean,
default: false,
},
tHeight: null,
istableHeight: null,
rowSelection: "",
total: 0,
pageNum: 1,
pageSize: 10,
paginationType: false, //是否使用小型分页,默认false
tableData: [],
columns: [],
actionArr: [],
actionWidth: '',
highlight:false,
showHeader:true,
headerCellStyle:{
type: Object,
default:()=>{
return {}
},
},
showSummary: { //表尾是否合计行 2022-10-12
type: Boolean,
default: false,
},
};
},
},
tableHeader: {
type: Array,
default: function () {
return [];
},
},
paginationFunc: {
type: Function,
default: function () {},
},
selectpageNationChange: {
type: Function,
default: function () {},
},
toggleSelections: {
type: [Array],
default: function () {
return [];
},
},
isMyTable: {
type: Boolean,
default: true,
},
// toggleSelections: {
// type: [Array,Object,String],
// required: true,
// validator(val) {
// if (Array.isArray(val) || val == '') return {};
// return [];
// },
// },
isobjectSpanMethod: { // 是否合并 2022-10-09
type: Boolean,
default: false
},
spanColumnArr: { // 合并哪几列, [0]为默认第一列[0,1,2,3]为第1,2,3,4合并用第一条的数据
type: Array,
default: () => []
},
spanArr: { // 合并单元格
type: Array,
default: () => {
return []
}
},
},
data() {
return {
multipleSelection: [],
dicts: {},
//选择
templateSelection: "",
templateRadio: "",
// 轮转规则表格数据
rotationRuleList: [],
currentRow: [],
};
},
watch: {
searchForm: {
handler: function (val, oldVal) {
return { ...val };
},
deep: true,
},
tableConfig: {
handler: function (newVal, oldVal) {
return { ...newVal };
},
deep: true,
},
toggleSelections: {
handler: function (val, oldVal) {
return this.toggleSelection(...val);
},
deep: true,
},
},
computed: { },
mounted() {
this.handleWindow();
window.addEventListener("resize", this.handleWindow, true);
},
beforeDestroy() {
window.removeEventListener("resize", this.handleWindow, true);
},
methods: {
handleWindow() {
this.$nextTick(() => {
let bodyHeight =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight;
this.tableConfig.tHeight =
bodyHeight - document.querySelector(".myForm").clientHeight - 150;
});
},
// 点击按钮执行方法
handleClick(type) {
if (type.click == "reset") {//重置
this.resetForm("refForm");
this.paginationFunc();
} else if(type.click == "add") { // 新增
this.$emit("addClickFun");
} else if (type.click == "search") {//查询
this.$emit("serachClickFun", this.searchForm);
} else if (type.click == "import") {//导入
this.$emit('importClickFunc')
} else if (type.click == "download") {//导出
this.$emit('downloadClickFun')
} else if (type.click == "allselect") { //全部选中
this.toggleSelection(this.tableConfig.tableData);
this.$emit("handleSelectionChange", this.multipleSelection);
} else if (type.click instanceof Function) {
this.$emit("clickFunc", type);
}
},
// 清空表单事件
resetForm(formName) {
this.$refs[formName].resetFields();
},
//全部选中
$handleSelectionChange(val) {
this.multipleSelection = val;
this.$emit("handleSelectionChange", this.multipleSelection);
},
//双击
$doubleClick(val) {
this.$refs.multipleTable.toggleRowSelection(val);
this.$emit("doubleclick", val);
},
//取消选择
toggleSelection(rows) {
if( rows) {
if(Array.isArray(rows) && this.tableConfig.rowSelection !== "radio") {
rows.forEach(row => {
this.multipleSelection = row;
this.$refs.multipleTable.toggleRowSelection(row);
});
}else if( this.tableConfig.rowSelection === "radio"){
this.templateRadio = rows.hasOwnProperty('scalaId') ? rows.scalaId : rows.hasOwnProperty('numberCode') ? rows.numberCode : rows.scadaId;
this.templateSelection = rows;
}
}else {
this.$refs.multipleTable.clearSelection();
this.multipleSelection = [];
}
},
//点击行
$rowClick(val) {
if (this.tableConfig.rowSelection === "radio") {
this.templateRadio = val.scalaId;
this.templateSelection = val;
} else {
this.$refs.multipleTable.toggleRowSelection(val);
}
this.$emit("rowClick", val);
},
//点击一行加高光
$handleCurrentChange(val) {
this.currentRow.push(val)
this.$refs.multipleTable.setCurrentRow( val);
this.$emit("handleCurrentChange", val);
},
//单选
singleElection(row) {
// this.templateSelection = this.rotationRuleList.indexOf(row);
this.templateSelection = row;
this.templateRadio = row.scalaId;
},
//table操作列
clickAction(item, row) {
this.$emit("handleOperate", item, row);
},
disabledFunc(item, row) {
let type = typeof item.disabled;
return type === "boolean"
? item.disabled
: type === "function"
? item.disabled({ item, row })
: false;
},
// 表格合并 2022-10-09
objectSpanMethod ({ rowIndex, columnIndex }) {
if (this.spanColumnArr.includes(columnIndex)) {
// 二维数组存储的数据 取出
const _row = this.spanArr[rowIndex]
const _col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
} else {
return false
}
},
// 表尾合计行2022-10-12
getSummaries(param) {
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '总计';
return;
}
const values = data.map(item => Number(item[column.property]));
if (!values.every(value => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
sums[index] += "";
} else {
sums[index] = '';
}
});
return sums;
}
},
};
</script>
<style lang="scss" scoped>
.content {
padding: 0.6rem 1.2rem;
background-color: #0c3568;
overflow: hidden;
.myTable {
margin-top: 20px;
}
}
::v-deep .el-button--text {
background: none !important;
border: none;
}
::v-deep .el-select .el-input__inner {
color: #fff !important;
}
/* 滚动轴颜色 */
/* ::-webkit-scrollbar-thumb {
background:#419be3;
border-radius: 4px;
} */
/* 滚动轴背景色 */
::-webkit-scrollbar-track {
/* background: #0c3568; */
background: #103c73;
}
</style>
--------------renderDom.vue-------------------
<script>
export default {
name: 'RenderDom',
functional: true,
props: {
row: Object,
renderFunc: Function
},
render: function (h, ctx) {
return ctx.props.renderFunc(h, ctx.props.row);
}
};
</script>
封装的基础查询table组件,不支持多级表头
于 2022-09-22 17:51:05 首次发布