<template>
|
<div>
|
<!-- 表格 -->
|
<el-table ref="multipleTable" v-loading="tableLoading" :border="border" :data="tableData"
|
:header-cell-style="{ background: '#f8f8f9', color: '#515a6e' }" :height="height"
|
:highlight-current-row="highlightCurrentRow" :row-class-name="rowClassName" :row-style="rowStyle"
|
:row-key="rowKey" :span-method="spanMethod" stripe style="width: 100%" tooltip-effect="dark" @row-click="rowClick"
|
@current-change="currentChange" @selection-change="handleSelectionChange" class="lims-table">
|
<el-table-column align="center" type="selection" width="55" v-if="isSelection" />
|
<el-table-column align="center" label="序号" type="index" width="60" :index="indexMethod" />
|
|
<el-table-column v-for="(item, index) in column" :key="index" :column-key="item.columnKey"
|
:filter-method="item.filterHandler" :filter-multiple="item.filterMultiple" :filtered-value="item.filteredValue"
|
:filters="item.filters" :fixed="item.fixed" :label="item.label" :min-width="item.minWidth" :prop="item.prop"
|
:show-overflow-tooltip="item.dataType === 'action' || item.dataType === 'slot' ? false : true"
|
:sortable="item.sortable ? true : false" :type="item.type" :width="item.dataType === 'action' ? getWidth(item.operation) : item.width" align="center">
|
<!-- <div class="123" v-if="item.type == ''"> -->
|
<template v-if="item.hasOwnProperty('colunmTemplate')" :slot="item.colunmTemplate" slot-scope="scope">
|
<slot v-if="item.theadSlot" :index="index" :name="item.theadSlot" :row="scope.row" />
|
</template>
|
|
<template slot-scope="scope">
|
<!-- 插槽 -->
|
<div v-if="item.dataType == 'slot'">
|
<slot v-if="item.slot" :index="scope.$index" :name="item.slot" :row="scope.row" />
|
</div>
|
<!-- 进度条 -->
|
<div v-else-if="item.dataType == 'progress'">
|
<el-progress :percentage="Number(scope.row[item.prop])" />
|
</div>
|
<!-- 图片 -->
|
<div v-else-if="item.dataType == 'image'">
|
<img :src="javaApi + '/img/' + item.prop" alt="" style="width: 40px; height: 40px; margin-top: 10px" />
|
</div>
|
|
<!-- tag -->
|
<div v-else-if="item.dataType == 'tag'">
|
<el-tag v-if="
|
typeof dataTypeFn(scope.row[item.prop], item.formatData) ==
|
'string'
|
" :title="scope.row[item.prop] | formatters(item.formatData)"
|
:type="formatType(scope.row[item.prop], item.formatType)">{{ scope.row[item.prop] |
|
formatters(item.formatData) }}</el-tag>
|
<el-tag v-for="(tag, index) in dataTypeFn(
|
scope.row[item.prop],
|
item.formatData
|
)" v-else-if="
|
typeof dataTypeFn(scope.row[item.prop], item.formatData) ==
|
'object'
|
" :key="index" :title="scope.row[item.prop] | formatters(item.formatData)"
|
:type="formatType(tag, item.formatType)">{{
|
item.tagGroup
|
? tag[item.tagGroup.label]
|
? tag[item.tagGroup.label]
|
: tag
|
: tag
|
}}</el-tag>
|
<el-tag v-else :title="scope.row[item.prop] | formatters(item.formatData)"
|
:type="formatType(scope.row[item.prop], item.formatType)">{{ scope.row[item.prop] |
|
formatters(item.formatData) }}</el-tag>
|
</div>
|
|
<!-- 按钮 -->
|
<div v-else-if="item.dataType == 'action'">
|
<template v-for="(o, key) in item.operation">
|
<el-button v-show="o.type != 'upload'" size="mini" v-if="o.showHide ? o.showHide(scope.row) : true"
|
:disabled="o.disabled ? o.disabled(scope.row) : false" :icon="iconFn(o)" :plain="o.plain"
|
:style="{ color: o.name === '删除' ? '#f56c6c' : o.color }" :type="o.type | typeFn(scope.row)"
|
@click="o.clickFun(scope.row)" :key="key">
|
{{ o.name }}
|
</el-button>
|
<el-upload :action="javaApi + o.url + '?id=' + (o.uploadIdFun ? o.uploadIdFun(scope.row) : scope.row.id)"
|
size="mini" ref="upload" :multiple="o.multiple ? o.multiple : false" :limit="1"
|
:disabled="o.disabled ? o.disabled(scope.row) : false" :accept="o.accept
|
? o.accept
|
: '.jpg,.jpeg,.png,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar'
|
" v-if="o.type == 'upload'" style="display: inline-block; width: 50px"
|
v-show="o.showHide ? o.showHide(scope.row) : true" :headers="uploadHeader" :on-error="onError"
|
:on-exceed="onExceed" :on-success="handleSuccessUp" :show-file-list="false" :key="key">
|
<el-button :size="o.size ? o.size : 'small'" type="text"
|
:disabled="o.disabled ? o.disabled(scope.row) : false">{{ o.name }}</el-button>
|
</el-upload>
|
</template>
|
</div>
|
<!-- 可点击的文字 -->
|
<div v-else-if="item.dataType == 'link'" class="cell link" style="width: 100%"
|
@click="goLink(scope.row, item.linkMethod)">
|
<span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
|
</div>
|
<!-- 默认纯展示数据 -->
|
<div v-else class="cell" style="width: 100%">
|
<span v-if="!item.formatData">{{ scope.row[item.prop] }}</span>
|
<span v-else>{{
|
scope.row[item.prop] | formatters(item.formatData)
|
}}</span>
|
</div>
|
</template>
|
</el-table-column>
|
</el-table>
|
<pagination v-show="page.total > 0" :total="page.total" :layout="page.layout" :page.sync="page.current"
|
:limit.sync="page.size" @pagination="pagination" />
|
</div>
|
</template>
|
|
<script>
|
// 注:以下是所有配置项,其中最常使用的就是label、width、prop、dataType、slot
|
// label :列名,就是表头上的标签叫什么些什么,类型 string
|
// width:该列宽度, string
|
// prop: table绑定数据字段 string,这一列要展示哪个tableData里面的字段就写哪个字段
|
// dataType: 内置多个基本的element组件可供直接使用 string
|
// slot 当`dataType`为`slot`时必带参数,参数值为插槽的 `slot` 值 string,具体使用方法请看下面的第4点slot插槽的使用
|
// fixed:列是否固定在左侧或者右侧,true 表示固定在左侧 string, boolean
|
// sortable 对应列是否可以排序 boolean, string
|
// filters 数据过滤的选项,数组格式,数组中的元素需要有 text 和 value 属性。Array
|
// columnKey :column 的 key,如果需要使用 filter-change 事件,则需要此属性标识是哪个 column 的筛选条件
|
// filteredValue 选中的数据过滤项,如果需要自定义表头过滤的渲染方式,可能会需要此属性。
|
// filterMultiple 数据过滤的选项是否多选
|
// minWidth 对应列的最小宽度,与 width 的区别是 width 是固定的,min-width 会把剩余宽度按比例分配给设置了 min-width 的列 string
|
// formatData 对数据进行数据处理,接受一个回调函数 (params?: {prop}) => {}
|
// formatType 当 `dataType`为 `tag`时,对标签颜色设置 (params?: {prop}) => { return 'danger'| 'success'... }`
|
// operation 当 `dataType` 为 `option`时,对按钮的 配置,具体配置项以下图为准object
|
// tagGroup 当 `dataType`为 `tag`时,绑定数据集字段显示名称 object
|
/**
|
* 插槽的使用方法:
|
*/
|
/* <div
|
slot="protocolSlot"
|
slot-scope="scope"
|
>
|
<span>{{ scope.row.protocol }}</span>
|
</div>
|
*/
|
/**
|
* 使用formatData进行数据处理
|
*/
|
// {
|
// type: '',
|
// label: '启用状态',
|
// prop: 'is_active',
|
// formatData: (item) => {
|
// const str = item == true ? '已启用' : '未启用'
|
// return str
|
// }
|
// },
|
/**
|
* operation配置
|
*/
|
// operation配置主要是来用于表格里面的操作那一列,通常就会有很多按钮,有以下参数:
|
// name:按钮名称,string
|
// type:按钮类型,`string` | `danger | success`,以elementUi 参数为准
|
// size:按钮大小,以elementUi 参数为准
|
// icon:按钮上的icon,以elementUi 参数为准
|
// plain:按elementUi 文档为准
|
// clickFun:按钮的回调函数
|
export default {
|
name: "ZTTable",
|
filters: {
|
typeFn(val, row) {
|
// console.log(val, row, '11111111');
|
if (typeof val === "function") {
|
return val(row);
|
} else return val;
|
},
|
describeConts(val, describeCont) {
|
if (typeof describeCont === "function") {
|
return describeCont(val);
|
} else return val;
|
},
|
formatters(val, format) {
|
if (typeof format === "function") {
|
return format(val);
|
} else return val;
|
},
|
},
|
props: {
|
isSelection: {
|
type: Boolean,
|
default: false,
|
},
|
height: {
|
type: String,
|
default: null,
|
},
|
tableLoading: {
|
type: Boolean,
|
default: false,
|
},
|
handleSelectionChange: {
|
type: Function,
|
default: () => {
|
return () => { };
|
},
|
},
|
rowClick: {
|
type: Function,
|
default: () => {
|
return () => { };
|
},
|
},
|
currentChange: {
|
type: Function,
|
default: () => {
|
return () => { };
|
},
|
},
|
border: {
|
type: Boolean,
|
default: true,
|
},
|
highlightCurrentRow: {
|
type: Boolean,
|
default: false,
|
},
|
headerCellStyle: {
|
type: Object,
|
default: () => {
|
return {};
|
},
|
},
|
column: {
|
type: Array,
|
default() {
|
return [];
|
},
|
},
|
rowClassName: {
|
type: Function,
|
default: () => { },
|
},
|
rowStyle: {
|
type: Object || Function,
|
default: () => { },
|
},
|
tableData: {
|
type: Array,
|
default() {
|
return [];
|
},
|
},
|
rowKey: {
|
type: String,
|
default: undefined,
|
},
|
page: {
|
type: Object,
|
default() {
|
return {
|
total: 0,
|
current: 0,
|
size: 10,
|
layout: "total, sizes, prev, pager, next, jumper",
|
};
|
},
|
},
|
},
|
data() {
|
return {
|
spanList: [],
|
};
|
},
|
mounted() {
|
this.calculateSpanInfo();
|
},
|
methods: {
|
getWidth(row) {
|
let count = 0;
|
row.forEach((a) => {
|
if (a.showHide!==undefined && a.showHide()) {
|
count += a.name.length;
|
} else if(!a.showHide) {
|
count += a.name.length;
|
}
|
});
|
return count * 15 + 70 + "px";
|
},
|
iconFn(row) {
|
if (row.name === "编辑" || row.name === "修改") {
|
return "el-icon-edit";
|
} else if (row.name === "删除") {
|
return "el-icon-delete";
|
} else if (row.name === "查看") {
|
return "el-icon-view";
|
} else {
|
return row.icon;
|
}
|
// if (typeof (val) === 'function') {
|
// return val(row);
|
// } else return val;
|
},
|
formatType(val, format) {
|
if (typeof format === "function") {
|
return format(val);
|
} else return "";
|
},
|
dataTypeFn(val, format) {
|
if (typeof format === "function") {
|
return format(val);
|
} else return val;
|
},
|
setCurrent(row) {
|
this.$refs.multipleTable.setCurrentRow();
|
},
|
handleSuccessUp(response, label) {
|
if (typeof label === "string") {
|
if (response.code == 200) {
|
this.upData[label] = response.data.url;
|
}
|
} else {
|
if (response.code == 200) {
|
this.$message.success("上传成功");
|
}
|
}
|
},
|
onError(err, file, fileList) {
|
this.$message.error("上传失败");
|
this.$refs.upload.clearFiles();
|
this.uploading = false;
|
},
|
onExceed() {
|
this.$message.warning("超出文件个数");
|
},
|
pagination({ page, limit }) {
|
this.$emit("pagination", { page: page, limit: limit });
|
},
|
indexMethod(index) {
|
// return index * 2;
|
return (this.page.current - 1) * this.page.size + index + 1;
|
},
|
// 点击单元格link事件
|
goLink(row, linkMethod) {
|
if (!linkMethod) {
|
return this.$message.warning("请配置lingk事件");
|
}
|
this.$parent[linkMethod](row);
|
},
|
// 合并单元格
|
calculateSpanInfo() {
|
// 初始化每列的合并信息
|
this.spanList = [];
|
this.column.forEach((m, i) => {
|
if (m.mergeCol) {
|
this.spanList.push({
|
arr: [],
|
position: 0,
|
name: m.prop,
|
index: i + 1,
|
});
|
}
|
});
|
this.spanList.forEach((item, i) => {
|
this.rowspan(
|
this.spanList[i].arr,
|
this.spanList[i].position,
|
item.name
|
);
|
});
|
},
|
rowspan(spanArr, position, spanName) {
|
this.tableData.forEach((item, index) => {
|
if (index === 0) {
|
spanArr.push(1);
|
position = 0;
|
} else {
|
if (
|
this.tableData[index][spanName] ===
|
this.tableData[index - 1][spanName]
|
) {
|
spanArr[position] += 1;
|
spanArr.push(0);
|
} else {
|
spanArr.push(1);
|
position = index;
|
}
|
}
|
});
|
},
|
// 合并单元格
|
spanMethod({ row, column, rowIndex, columnIndex }) {
|
// 一般的合并行
|
if (this.column.find((m) => m.mergeCol)) {
|
let i = null;
|
let obj = this.spanList.find((item, index) => {
|
i = index;
|
return item.index == columnIndex;
|
});
|
if (obj) {
|
const _row = this.spanList[i].arr[rowIndex];
|
const _col = _row > 0 ? 1 : 0;
|
return {
|
rowspan: _row,
|
colspan: _col,
|
};
|
}
|
}
|
// // 特殊的合并行
|
// if (
|
// this.data.spanConfig != undefined &&
|
// this.data.spanConfig.special &&
|
// this.data.spanConfig.special.main &&
|
// this.data.spanConfig.special.rows &&
|
// this.data.spanConfig.special.rows.length > 0
|
// ) {
|
// let i = null;
|
// let obj = this.data.spanConfig.special.rows.find((item, index) => {
|
// i = index;
|
// return item.index == columnIndex;
|
// });
|
// if (obj) {
|
// const _row = this.specialSpanList[i].arr[rowIndex];
|
// const _col = _row > 0 ? 1 : 0;
|
// return {
|
// rowspan: _row,
|
// colspan: _col,
|
// };
|
// }
|
// }
|
},
|
},
|
};
|
</script>
|
|
<style scoped>
|
.el-table>>>.el-table__empty-text {
|
text-align: center;
|
}
|
|
>>>.cell {
|
padding: 0 !important;
|
}
|
|
.cell {
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
padding-right: 4px !important;
|
padding-left: 10px !important;
|
}
|
|
.link {
|
color: rgb(64, 158, 255);
|
cursor: pointer;
|
}
|
|
>>>.el-table__body-wrapper::-webkit-scrollbar {
|
height: 14px;
|
/* 设置滚动条宽度 */
|
}
|
</style>
|
<style>
|
.lims-table .highlight-warning-row-border td:first-child {
|
border-left: 4px solid #ffcd29;
|
}
|
|
.lims-table .highlight-warning-row-border td:last-child {
|
border-right: 4px solid #ffcd29;
|
}
|
|
/* .lims-table .highlight-danger-row-border td {
|
border-top: 2px solid red;
|
border-bottom: 2px solid red;
|
} */
|
|
.lims-table .highlight-danger-row-border td:first-child {
|
border-left: 4px solid #f56c6c;
|
}
|
|
.lims-table .highlight-danger-row-border td:last-child {
|
border-right: 4px solid #f56c6c;
|
}
|
</style>
|