<template>
|
<div>
|
<!-- 表格 -->
|
<el-table
|
ref="multipleTable"
|
v-loading="tableLoading"
|
element-loading-text="加载中..."
|
element-loading-spinner="el-icon-loading"
|
: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="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"
|
: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/' + scope.row[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 == 'link'"
|
class="cell"
|
style="width: 100%"
|
@click="goLink(scope.row, item.linkEvent)"
|
>
|
<span class="link" 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-column
|
v-if="table.operator"
|
:label="(table.operatorConfig && table.operatorConfig.label) || '操作'"
|
:width="
|
table.operatorConfig &&
|
(table.operatorConfig.width
|
? table.operatorConfig.width
|
: calcOperationWidth())
|
"
|
:min-width="
|
(table.operatorConfig && table.operatorConfig.width) ||
|
table.operatorConfig.minWidth ||
|
100
|
"
|
align="center"
|
:fixed="table.operatorConfig ? table.operatorConfig.fixed : 'right'"
|
:show-overflow-tooltip="true"
|
>
|
<template slot-scope="scope">
|
<template v-for="(o, index) in table.operator">
|
<el-button
|
:key="index"
|
v-if="o.type != 'upload'"
|
@click.stop="o.clickFun(scope.row)"
|
:type="o.type || 'text'"
|
:icon="o.icon"
|
:size="o.size || 'small'"
|
:disabled="o.disabled ? o.disabled(scope.row) : false"
|
v-show="o.showFun ? o.showFun(scope.row) : true"
|
:class="[
|
'commonButton',
|
{
|
del: o.name === '删除' || o.name === '作废',
|
},
|
]"
|
>{{ 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' && o.url"
|
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="index"
|
>
|
<el-button
|
:size="o.size ? o.size : 'small'"
|
type="text"
|
:disabled="o.disabled ? o.disabled(scope.row) : false"
|
>{{ o.name }}</el-button
|
>
|
</el-upload>
|
<el-upload
|
action="#"
|
:on-change="
|
(file, fileList) => o.clickFun(scope.row, file, fileList)
|
"
|
:multiple="o.multiple ? o.multiple : false"
|
:limit="o.limit ? o.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' && !o.url"
|
style="display: inline-block; width: 50px"
|
v-show="o.showHide ? o.showHide(scope.row) : true"
|
:auto-upload="false"
|
:on-exceed="onExceed"
|
:show-file-list="false"
|
:key="index"
|
>
|
<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>
|
</template>
|
</el-table-column>
|
</el-table>
|
<pagination
|
v-if="page"
|
v-show="page.total > 0"
|
:total="page.total"
|
:layout="page.layout"
|
:page.sync="page.current"
|
:limit.sync="page.size"
|
@pagination="pagination"
|
style="background-color: #fff"
|
/>
|
</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) {
|
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,
|
},
|
stripe: {
|
type: Boolean,
|
default: false,
|
},
|
headerCellStyle: {
|
type: Object,
|
default: () => {
|
return {};
|
},
|
},
|
// column: {
|
// type: Array,
|
// default() {
|
// return [];
|
// },
|
// },
|
table: {
|
type: Object,
|
default() {
|
return {};
|
},
|
required: true,
|
},
|
rowClassName: {
|
type: Function,
|
default: () => {},
|
},
|
rowStyle: {
|
type: 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: [],
|
column: [],
|
};
|
},
|
watch: {
|
table(val) {
|
this.doLayout();
|
},
|
},
|
mounted() {
|
this.calculateSpanInfo();
|
this.column = this.table.column;
|
},
|
methods: {
|
//计算操作列的宽度
|
calcOperationWidth() {
|
let width = 0;
|
this.table.operator.forEach((item) => {
|
width += item.name.length * 15 + 15;
|
});
|
return width;
|
},
|
doLayout() {
|
this.$nextTick(() => {
|
this.$refs.multipleTable && this.$refs.multipleTable.doLayout();
|
});
|
},
|
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, linkEvent) {
|
if (!linkEvent) {
|
return this.$message.warning("请配置lingk事件");
|
}
|
linkEvent.vueComponent[linkEvent.method](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>
|