<template>
<div class="ymstable">
<div class="slot">
<div>
<slot name="batchProcess"></slot>
<el-button @click="batchChange" v-if="isBatchChange">{{ batchChangeLabel }}</el-button>
<el-button
type="danger"
@click="batchDel"
style="margin-right: 20px;"
v-if="isBatchDel"
>{{ batchDelLabel }}</el-button>
<slot name="filter"></slot>
</div>
<div>
<slot name="queryTable"></slot>
<el-button @click="exportExcel" v-if="isExport">导出Excel</el-button>
</div>
</div>
<div class="append" v-if="isAppend" @click="appendRow">
<i class="el-icon-circle-plus-outline" />
</div>
<el-table
:row-class-name="tableRowClassName"
:data="tableData"
:header-cell-style="{background:'#f2f2f2', color:'#333'}"
calss="table"
ref="ymstable"
tooltip-effect="dark"
style="width: 100%;"
@selection-change="handleSelectionChange"
@sort-change="sortChange"
@filter-change="filterChange"
@cell-click="cellClick"
:cell-style="cellStyle"
>
<el-table-column type="selection" width="85"></el-table-column>
<el-table-column
v-if="isOperational ? isFirst : false"
label="操作"
align="center"
width="150px"
>
<template slot-scope="scope">
<el-button
v-if="isEditable"
@click.stop="handleEdit(scope.$index, scope.row)"
size="mini"
type="primary"
>{{ scope.row.changeButton }}</el-button>
<el-button
v-if="isDeletable"
@click.stop="handleDelete(scope.$index, scope.row)"
size="mini"
type="danger"
>删除</el-button>
</template>
</el-table-column>
<el-table-column v-if="isMultiple" :type="type" width="55" align="center"></el-table-column>
<el-table-column
v-for="(item, index) in colProps"
:key="index"
:label="item.label"
:prop="item.value"
:width="item.width"
:sortable="item.sortable"
align="left"
:filters="item.filters"
:column-key="item.value"
>
<template slot-scope="scope">
<el-input
v-if="scope.row.status && item.type === 'editText'"
size="mini"
placeholder="请输入内容"
v-model.trim="scope.row[item.value]"
></el-input>
<span v-if="item.type === 'editText' && !scope.row.status">{{ scope.row[item.value] }}</span>
<el-select
v-if="scope.row.status && item.type === 'selection'"
size="mini"
placeholder="请选择"
v-model="scope.row[item.value]"
>
<el-option
v-for="li in rowSelOpts[item.value]"
:key="li.value"
:label="li.label"
:value="li.value"
/>
</el-select>
<span v-if="item.type === 'selection' && !scope.row.status">{{ scope.row[item.value] }}</span>
<span v-else-if="item.type === 'text'">{{ scope.row[item.value] }}</span>
<a
:href="fileServer + scope.row[hrefs[item.value]]"
v-else-if="item.type === 'append'"
>{{ scope.row[item.value] }}</a>
<img :src="scope.row[item.value]" v-else-if="item.type === 'img'" />
<el-badge
v-else-if="item.type === 'dot'"
:is-dot="scope.row.ISREAD === 'false' ? true : false"
>{{ scope.row[item.value] }}</el-badge>
</template>
</el-table-column>
<el-table-column
v-if="isOperational ? !isFirst : false"
label="操作"
align="center"
width="150px"
>
<template slot-scope="scope">
<el-button
v-if="isEditable"
@click="handleEdit(scope.$index, scope.row)"
size="mini"
type="primary"
>{{ scope.row.changeButton }}</el-button>
<el-button
v-if="isDeletable"
@click="handleDelete(scope.$index, scope.row)"
size="mini"
type="danger"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination" v-if="isPagination">
<el-pagination
layout="total, sizes, prev, pager, next, jumper"
:current-page="currentPage"
@size-change="sizeChange"
@current-change="currentChange"
:page-size="pageSize"
background
:page-sizes="pageSizes"
:total="total"
></el-pagination>
</div>
</div>
</template>
<script>
export default {
name: "YmsTable",
computed: {
tableData: {
get() {
if (this.isFilter) {
return this.filtered.slice(
(this.currentPage - 1) * this.pageSize,
this.currentPage * this.pageSize
);
}
const res = this.list.slice(
(this.currentPage - 1) * this.pageSize,
this.currentPage * this.pageSize
);
return res;
},
set() {}
},
total: {
get() {
return this.isFilter ? this.filtered.length : this.list.length;
},
set() {}
}
},
watch: {
tableData: {
handler(tableData) {
this.$nextTick(() => {
// const pageMulSel =
// this.multipleSelection[this.currentPage.toString()] || {};
// const rows = pageMulSel.ids || [];
// rows.forEach(row => {
// this.$refs.ymstable.toggleRowSelection(tableData[row]);
// });
// 表数据改变 则 清空选择项
this.$refs.ymstable.clearSelection();
});
}
},
filterCriteria: {
handler(filterCriteria) {
if (this.list.length === 0) return;
if (Array.isArray(filterCriteria)) {
if (filterCriteria.length === 0) {
this.isFilter = false;
} else {
this.filtered = this.list.filter(
item => filterCriteria.indexOf(item.title) > -1
);
this.isFilter = true;
}
} else if (filterCriteria.value === "") {
this.isFilter = false;
} else {
this.filtered = this.list.filter(
item => filterCriteria.value === item[filterCriteria.prop]
);
this.isFilter = true;
}
},
deep: true
},
list: {
handler(newVal, oldVal) {
// 修正数据源变化时页数问题导致新数据不显示,做项目统计时发现的
const difference = oldVal.length - newVal.length;
console.log(difference);
if (difference > 0) {
if (
this.currentPage !== 1 &&
this.currentPage * this.pageSize > newVal.length
) {
this.currentPage = Math.ceil(newVal.length / this.pageSize);
}
}
//
if (this.colName) {
this.filterChange(this.colName);
}
}
}
},
data() {
return {
multipleSelection: {},
prop: null,
order: null,
isFilter: false,
editContext: "编辑",
batchChangeCriteria: "",
filteredIds: [],
filterList: [],
flatMulti: null,
filterCols: [], // 存储在
currentPage: 1,
pageSizes: [5, 10, 20, 50, 100, 200],
pageSize: 10,
filterMaps: [],
filtered: null,
colName: null,
oldRow: null
};
},
props: {
numberCols: {
type: Array,
default() {
return [];
}
},
hrefs: {
type: Object,
default() {
return {};
}
},
isFirst: {
type: Boolean,
default: false
},
filterCriteria: {
type: [Array, String, Object]
},
isBatchChange: {
type: Boolean,
default: false
},
batchChangeLabel: {
type: String,
default: "批量修改"
},
isBatchDel: {
type: Boolean,
default: false
},
batchDelLabel: {
type: String,
default: "批量删除"
},
list: {
type: Array,
default() {
return [];
}
},
isPagination: {
type: Boolean,
default: true
},
isAppend: {
type: Boolean,
default: false
},
isMultiple: {
type: Boolean,
default: true
},
type: {
type: String,
default: "selection"
},
colProps: {
type: Array,
default() {
return [];
}
},
isOperational: {
type: Boolean,
default: true
},
isEditable: {
type: Boolean,
default: true
},
isDeletable: {
type: Boolean,
default: true
},
isAgree: {
type: Boolean,
default: true
},
isReject: {
type: Boolean,
default: true
},
fileServer: {
type: String,
default: "http://10.6.2.130:8888/workflow"
},
isDialog: {
type: Boolean,
default: false
},
rowSelOpts: {
type: Object,
default() {
return {};
}
},
isExport: {
type: Boolean,
default: true
},
cellStyle: {
type: Object,
default() {
return {};
}
}
},
methods: {
// eslint-disable-next-line no-unused-vars
tableRowClassName({ row, rowIndex }) {
if (rowIndex % 2 === 0) {
return "warning-row";
}
// if (rowIndex % 2 === 1) {}
return "";
},
cellClick(row, column, cell, event) {
if (event.target.nodeName !== "A") {
this.$emit("cellClick", row, column, cell, event);
}
},
getMultiSelFlat() {
// 提取全部选中条目
const valArr = Array.from(Object.values(this.multipleSelection));
let flat = [];
valArr.forEach(item => {
flat = flat.concat(item.data);
// flat.push(item.data)
});
this.flatMulti = flat;
},
filterChange(colName) {
this.colName = colName;
this.multipleSelection = {};
const prop = Object.keys(colName)[0];
let isExist = false;
const { length } = this.filterMaps;
for (let i = 0; i < length; i++) {
const _prop = Object.keys(this.filterMaps[i])[0];
if (prop === _prop) {
this.filterMaps[i] = colName;
isExist = true;
break;
}
}
if (!isExist) {
this.filterMaps.push(colName);
}
// console.log(this.filterMaps)
const len = this.filterMaps.length;
let filtered = this.list;
for (let i = 0; i < len; i++) {
const _prop = Object.keys(this.filterMaps[i])[0];
const values = Object.values(this.filterMaps[i])[0];
if (values.length !== 0) {
filtered = this.list.filter(li => values.indexOf(li[_prop]) > -1);
}
}
this.filtered = filtered;
// console.log(this.list)
if (filtered.length !== this.list.length) {
this.isFilter = true;
} else {
this.isFilter = false;
}
},
// eslint-disable-next-line no-unused-vars
sortChange({ column, prop, order }) {
this.multipleSelection = {};
// 进行全局
if (order === "ascending") {
if (this.numberCols.indexOf(prop) > -1) {
this.list = this.list.sort(
(a, b) => Number(a[prop]) - Number(b[prop])
);
} else {
this.list = this.list.sort((a, b) => a[prop] - b[prop]);
}
} else if (order === "descending") {
if (this.numberCols.indexOf(prop) > -1) {
this.list.sort((a, b) => Number(b[prop]) - Number(a[prop]));
} else {
this.list.sort((a, b) => b[prop] - a[prop]);
}
}
// this.$emit("sortChange", { column, prop, order });
},
currentChange(currentPage) {
// 获取u当前页数
this.currentPage = currentPage;
},
sizeChange(pageSize) {
this.multipleSelection = {};
// 更改条目数量
this.pageSize = pageSize;
},
batchDel() {
// 批量删除
this.getMultiSelFlat();
if (this.flatMulti.length === 0) return;
if (this.batchChangeLabel === this.batchDelLabel) {
this.multipleSelection = {};
}
/* const ids = [];
this.flatMulti.forEach(item => {
ids.push(item.id);
}); */
/* if (this.isFilter) {
this.filtered = this.filtered.filter(
item => ids.findIndex(li => li === item.id) === -1
);
} */
if (this.isFilter) {
this.filtered = this.filtered.filter(
item => this.flatMulti.findIndex(li => li.id === item.id) === -1
);
}
this.$emit("batchDel", this.flatMulti);
this.multipleSelection[this.currentPage] = {};
},
batchChange() {
// 批量修改
this.getMultiSelFlat();
if (this.flatMulti.length === 0) return;
this.$emit("batchChange", this.flatMulti);
this.multipleSelection[this.currentPage] = {};
},
handleEdit(index, row) {
// 行内编辑
if (this.isDialog) {
this.oldRow = JSON.parse(JSON.stringify(row));
this.$emit("dialog", row, this.oldRow);
} else if (row.status) {
// row.changeButton = "编辑";
// row.status = false;
// 交给父组件执行
this.$emit("rowEdit", row, this.oldRow);
} else {
// eslint-disable-next-line no-param-reassign
row.changeButton = "保存";
// eslint-disable-next-line no-param-reassign
row.status = true;
this.oldRow = JSON.parse(JSON.stringify(row));
}
},
handleDelete(index, row) {
// 逐条删除
this.$emit("rowDel", row);
},
handleSelectionChange(val) {
// 获取checkbox选中数目
this.$nextTick(() => {
const ids = [];
val.forEach(li => {
const target = this.tableData.findIndex(
item => !!item && !!li && item.id === li.id
);
if (target || target === 0) {
ids.push(target);
}
});
if (!this.multipleSelection[this.currentPage]) {
this.multipleSelection[this.currentPage] = {};
}
this.multipleSelection[this.currentPage].data = val;
this.multipleSelection[this.currentPage].ids = ids;
// this.$emit("mutiSelectionChange", val, ids);
});
console.log(val);
this.$nextTick(() => {
this.$emit("selectChange", val);
});
},
exportExcel() {
// 导出excel
this.getMultiSelFlat();
if (this.flatMulti.length === 0) {
// 全部导出
console.log(this.list);
} else {
// 导出选中条目
console.log(this.flatMulti);
}
},
appendRow() {
this.$emit("appendRow");
}
}
};
</script>
<style>
.el-table .warning-row {
background: rgb(201, 233, 192);
}
.el-table .success-row {
background: #f0f9eb;
}
.ymstable {
display: flex;
flex-direction: column;
flex: 1;
}
.slot {
display: flex;
justify-content: space-between;
}
.table {
display: flex;
}
.pagination {
display: flex;
flex-direction: row-reverse;
}
.append {
font-size: 18px;
margin: 0 auto;
cursor: pointer;
display: flex;
flex: 1;
border: 1px solid rgb(241, 204, 102);
}
.el-badge /deep/.is-dot {
z-index: 9999 !important;
}
</style>
该表格模板使用时,如何设置可以实现仅单选