trends-table-vue3
Version:
动态表格
690 lines (689 loc) • 21.5 kB
JavaScript
import { resolveComponent, resolveDirective, openBlock, createElementBlock, normalizeStyle, createElementVNode, createBlock, withCtx, createVNode, createCommentVNode, Fragment, renderList, withDirectives, toDisplayString, renderSlot } from "vue";
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i)
view[i] = s.charCodeAt(i) & 255;
return buf;
}
function xlsxStyle(wb) {
let ws = wb.Sheets["Sheet1"];
for (let key in ws) {
ws["!cols"].wpx = ["14", 100, "200", 200];
const num = key.slice(1, key.length);
if (num === "1" && ws[key].t !== "z") {
ws[key].s = {
font: {
//字体相关样式
name: "宋体",
//字体类型
sz: "11",
//字体大小
color: { rgb: "" },
//字体颜色
bgColor: { rgb: "e7e2e200" },
//字体颜色
bold: true
//是否加粗
},
// border: {
// top: {
// style: "thin",
// color: {
// auto: 1,
// },
// },
// left: {
// style: "thin",
// color: {
// auto: 1,
// },
// },
// right: {
// style: "thin",
// color: {
// auto: 1,
// },
// },
// bottom: {
// style: "thin",
// color: {
// auto: 1,
// },
// },
// },
alignment: {
/// 自动换行
wrapText: 1,
// 居中
horizontal: "center",
vertical: "center",
indent: 0
}
};
} else {
if (key !== "!rows" && key !== "!cols" && key !== "!ref" && key !== "!fullref" && ws[key].t !== "z") {
ws[key].s = {
font: {
//字体相关样式
name: "宋体",
//字体类型
sz: "10",
//字体大小
color: { rgb: "" }
//字体颜色
},
// border: {
// top: {
// style: "thin",
// color: {
// auto: 1,
// },
// },
// left: {
// style: "thin",
// color: {
// auto: 1,
// },
// },
// right: {
// style: "thin",
// color: {
// auto: 1,
// },
// },
// bottom: {
// style: "thin",
// color: {
// auto: 1,
// },
// },
// },
alignment: {
/// 自动换行
wrapText: 1,
// 居中
horizontal: "center",
vertical: "center",
indent: 0
}
};
}
}
}
}
const $base = {
s2ab,
xlsxStyle
};
const index = {
name: "TrendsTable",
props: {
// 数据 - 来源
data: Array,
// 表头 - 来源
header: Array,
// 分页参数
pageOpts: {
type: Object,
default: () => {
return {
pageNum: 1,
// 第几页
pageSize: 10
// 一页几条
};
}
},
// 表头显示配置,未配置时默认全部显示;配置后按照配置项及顺序依次显示。
fieldList: {
type: Array,
default: () => {
return [];
}
},
// 表头参数
headerOpts: {
type: Object,
default: () => {
return {
name: "name",
// 表头名字
nameTag: "-",
// 处理多级表头的标识(只支持出现一次)
prop: "value"
// 表头prop
};
}
},
// 合并行列的处理方法
rowColumnMerge: {
type: Function,
default: () => {
}
},
// 同 Table 属性 empty-text
emptyText: {
type: String,
default: "暂无数据"
},
// 同 Table-column 属性 type。参考值 'default' | 'selection' | 'index' | 'expand'。
columnType: {
type: String,
default: void 0
},
// 同 Table 事件 selection-change。columnType=selection有效。
selectionChange: {
type: Function,
default: () => {
}
},
// 同 Table-column 属性 selectable。columnType=selection有效。
selectable: {
type: Function,
default: () => {
return true;
}
},
// 最大高度
maxHeight: {
type: [Number, String],
default: "auto"
},
// 字体大小
fontSize: {
type: Number,
default: 12
},
// 表头字体颜色
headerColor: {
type: String,
default: "#909399"
},
// 表头背景颜色
headerBgColor: {
type: String,
default: "#f5f7fa"
},
// 表格字体颜色
bodyColor: {
type: String,
default: "#606266"
},
// 是否开启show-overflow-tooltip
tooltip: {
type: Boolean,
default: false
},
// 固定+列宽配置参数
fixedAndColumnw: {
type: Object,
default: () => {
return {};
}
},
// 工具箱
tools: {
type: Object,
default: () => {
return {
// 需要导入的插件,
plugin: {
saveAs: null,
// import { saveAs } from 'file-saver';
write: null,
// import { write } from "xlsx-style-vite";
utils: null
// import { utils } from 'xlsx';
},
header: false,
// 表头筛选
excel: false,
// 下载表格数据为excel文件
excelFileName: "表格Excel文件"
// excel参数 - 文件名称(excel为true时选填)
};
}
}
},
data() {
return {
// 数据 - 处理显示
useData: this.data,
// 表头 - 处理显示
useHeader: this.header,
// 工具 - 处理显示
userTools: this.tools,
// 表格加载
loading: false,
// 表格加载文本
loadingText: "",
// 高度
trendsTableH: 0
};
},
watch: {
header: {
handler(val) {
this.initHeader();
},
deep: true,
immediate: true
},
data: {
handler(val) {
this.initData();
},
deep: true,
immediate: true
}
},
mounted() {
this.init();
},
methods: {
init() {
this.$nextTick(() => {
this.trendsTableH = this.$refs.trendsTable.offsetHeight;
});
let tools = {
// 需要导入的插件
plugin: {
saveAs: null,
// import { saveAs } from 'file-saver';
write: null,
// import { write } from "xlsx-style-vite";
utils: null
// import { utils } from 'xlsx';
},
header: false,
// 表头筛选
excel: false,
// 打印
excelFileName: "表格Excel文件"
// 打印 - 文件内容
};
for (let key in this.tools) {
if (tools[key] !== void 0) {
tools[key] = this.tools[key];
}
}
this.userTools = tools;
},
/** 导出按钮操作 */
excelDownload(excelName) {
if (this.userTools.plugin.saveAs === null || this.userTools.plugin.write === null || this.userTools.plugin.utils === null) {
console.warn("工具tools依赖于一下插件:file-saver/xlsx-style-vite/xlsx。请检查并安装。");
return;
}
this.loading = true;
this.loadingText = "导出中,请稍后....";
setTimeout(() => {
try {
const $e = this.$refs["report-table"].$el;
let $table = $e.querySelector(".el-table__fixed");
if (!$table) {
$table = $e;
}
let wb = this.tools.plugin.utils.table_to_book($table, { raw: true });
$base.xlsxStyle(wb);
var ws = this.tools.plugin.write(wb, { bookType: "xlsx", bookSST: false, type: "binary" });
this.tools.plugin.saveAs(
new Blob([$base.s2ab(ws)], { type: "" }),
// new Blob([ws],{type: 'application/octet-stream'}),
`${excelName}.xlsx`
);
} catch (e) {
if (typeof console !== "undefined")
console.error(e);
}
this.loading = false;
this.loadingText = "";
}, 1e3);
},
initHeader() {
if (this.header.length > 0) {
let headerOpts = {
name: "name",
// 表头名字
nameTag: "-",
// 处理多级表头的标识(只支持出现一次)
prop: "value"
// 表头prop
};
for (let key in this.headerOpts) {
if (headerOpts[key] !== void 0) {
headerOpts[key] = this.headerOpts[key];
}
}
let header = [];
if (this.fieldList.length === 0) {
header = JSON.parse(JSON.stringify(this.header));
} else {
this.fieldList.forEach((field) => {
const nums = this.header.length;
for (let i = 0; i < nums; i++) {
const item = this.header[i];
if (field === item[headerOpts.prop]) {
header.push(item);
break;
}
}
});
}
if (this.data.length > 0) {
let fixedAndColumnw = {
fixedNum: 0,
// 左侧固定列。0不固定,1固定第一列。
fixedLastNum: 0,
// 右侧固定列。0不固定,1固定第一列。
trendsWidthNum: 0,
// 计算列宽 - 从0算。-1时,全部列计算;不为-1时,计算小于其的索引列
trendsWidth: 250,
// 计算列宽 - 默认最大宽度,列数低于可控范围时失效
trendsWidthsFixed: []
// 计算列宽 - 手动设置固定宽度;从索引0开始设置;如:[100, 100, 100, null, 100],3不处理,不在数组内的其他索引不处理。
};
for (let key in this.fixedAndColumnw) {
if (fixedAndColumnw[key] !== void 0) {
fixedAndColumnw[key] = this.fixedAndColumnw[key];
}
}
this.originalTableHeader(header, this.data, headerOpts.prop, fixedAndColumnw);
}
header = this.tableHeaderLevel2(header, headerOpts);
header.forEach((item, i) => {
item.headerShow = true;
});
this.useHeader = JSON.parse(JSON.stringify(header));
} else {
this.useHeader = [];
}
},
initData() {
if (this.data.length > 0) {
this.useData = JSON.parse(JSON.stringify(this.data));
} else {
this.useData = [];
}
},
/**
* 动态表格,原始表头数据处理。
* @param {Array} headers 表头原始数据
* @param {Array} data 表体原始数据
* @param {String} prop 表头prop
* @param {Number} opt
* @example
this.originalTableHeader(header, this.data, this.headerOpts.prop);
*/
originalTableHeader(headers, data, prop = "prop", opt) {
const dataNum = data.length;
headers.forEach((item, i) => {
if (opt.trendsWidthNum !== 0) {
if (opt.trendsWidthNum === -1 || opt.trendsWidthNum !== -1 && i < opt.trendsWidthNum) {
let width = 80;
for (let a = 0; a < dataNum; a++) {
if (item[prop] && data[a][item[prop]] !== void 0 && data[a][item[prop]] !== null) {
const rowStrW = (data[a][item[prop]].toString().length + 3) * this.fontSize + 1;
if (rowStrW > opt.trendsWidth) {
width = opt.trendsWidth;
break;
}
if (rowStrW > 80 && rowStrW < opt.trendsWidth && width < rowStrW) {
width = rowStrW;
}
}
}
item.width = width;
}
}
if (i < opt.fixedNum) {
item.fixed = "left";
} else if (i > headers.length - 1 - opt.fixedLastNum) {
item.fixed = "right";
} else {
item.fixed = false;
}
});
if (opt.trendsWidthsFixed.length > 0) {
opt.trendsWidthsFixed.forEach((w, i) => {
if (w !== null) {
headers[i].width = w;
}
});
}
},
/**
* 多级表头数据处理
* @param {Array} titleList 表头数据
* @param {String} label 表头label
* @param {String} prop 表头prop
* @example header = this.tableHeaderLevel2(header, this.headerOpts.name, this.headerOpts.prop);
*/
tableHeaderLevel2(titleList, headerOpts) {
const headers = [];
titleList.forEach((h, i) => {
if (h[headerOpts.name].includes(headerOpts.nameTag)) {
const names = h[headerOpts.name].split(headerOpts.nameTag);
if (headers.length > 0 && headers[headers.length - 1].label === names[0]) {
let temp = JSON.parse(JSON.stringify(h));
temp.label = names[1];
temp.prop = h[headerOpts.prop];
if (!headers[headers.length - 1].fixed && h.fixed !== false) {
headers[headers.length - 1].fixed = h.fixed;
}
headers[headers.length - 1].children.push(temp);
} else {
const temp = {
children: [],
label: names[0],
prop: null
};
if (!temp.fixed && h.fixed !== false) {
temp.fixed = h.fixed;
}
let temp2 = JSON.parse(JSON.stringify(h));
temp2.label = names[1];
temp2.prop = h[headerOpts.prop];
temp.children.push(temp2);
headers.push(temp);
}
} else {
let temp = JSON.parse(JSON.stringify(h));
temp.label = h[headerOpts.name];
temp.prop = h[headerOpts.prop];
headers.push(temp);
}
});
return headers;
}
}
};
const index_vue_vue_type_style_index_0_scoped_fa2655ba_lang = "";
const _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const _sfc_main = index;
const _hoisted_1 = { class: "el-dropdown-link" };
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_Files = resolveComponent("Files");
const _component_el_icon = resolveComponent("el-icon");
const _component_Menu = resolveComponent("Menu");
const _component_el_checkbox = resolveComponent("el-checkbox");
const _component_el_dropdown_item = resolveComponent("el-dropdown-item");
const _component_el_dropdown_menu = resolveComponent("el-dropdown-menu");
const _component_el_dropdown = resolveComponent("el-dropdown");
const _component_el_table_column = resolveComponent("el-table-column");
const _component_el_table = resolveComponent("el-table");
const _directive_loading = resolveDirective("loading");
return openBlock(), createElementBlock("div", {
class: "trendsTable",
ref: "trendsTable",
style: normalizeStyle({
height: _ctx.maxHeight
})
}, [
createElementVNode("div", {
class: "tools",
style: normalizeStyle({
height: _ctx.tools.header || _ctx.tools.excel ? `30px` : "auto"
})
}, [
_ctx.userTools.excel ? (openBlock(), createBlock(_component_el_icon, {
key: 0,
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.excelDownload(_ctx.userTools.excelFileName)),
class: "one",
size: "18"
}, {
default: withCtx(() => [
createVNode(_component_Files)
]),
_: 1
})) : createCommentVNode("", true),
_ctx.userTools.header ? (openBlock(), createBlock(_component_el_dropdown, {
key: 1,
class: "one"
}, {
dropdown: withCtx(() => [
createVNode(_component_el_dropdown_menu, null, {
default: withCtx(() => [
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.useHeader, (h, hi) => {
return openBlock(), createBlock(_component_el_dropdown_item, { key: hi }, {
default: withCtx(() => [
createVNode(_component_el_checkbox, {
modelValue: h.headerShow,
"onUpdate:modelValue": ($event) => h.headerShow = $event,
label: h.label,
size: "small"
}, null, 8, ["modelValue", "onUpdate:modelValue", "label"])
]),
_: 2
}, 1024);
}), 128))
]),
_: 1
})
]),
default: withCtx(() => [
createElementVNode("span", _hoisted_1, [
createVNode(_component_el_icon, { size: "18" }, {
default: withCtx(() => [
createVNode(_component_Menu)
]),
_: 1
})
])
]),
_: 1
})) : createCommentVNode("", true)
], 4),
withDirectives((openBlock(), createBlock(_component_el_table, {
ref: "report-table",
style: normalizeStyle({
"--fontSize": _ctx.fontSize + "px",
"--headerColor": _ctx.headerColor,
"--bodyColor": _ctx.bodyColor,
"--headerBgColor": _ctx.headerBgColor
}),
"element-loading-text": _ctx.loadingText,
class: "comTable",
data: _ctx.useData,
"max-height": _ctx.maxHeight === "auto" ? _ctx.maxHeight : _ctx.tools.header || _ctx.tools.excel ? `${_ctx.trendsTableH - 30}px` : `${_ctx.trendsTableH}px`,
"span-method": _ctx.rowColumnMerge,
"empty-text": _ctx.emptyText,
onSelectionChange: _ctx.selectionChange,
border: ""
}, {
default: withCtx(() => [
_ctx.columnType === "index" ? (openBlock(), createBlock(_component_el_table_column, {
key: 0,
type: "index",
label: "序号",
fixed: "",
align: "center",
"min-width": "50"
}, {
default: withCtx((scope) => [
createElementVNode("span", null, toDisplayString((_ctx.pageOpts.pageNum - 1) * _ctx.pageOpts.pageSize + scope.$index + 1), 1)
]),
_: 1
})) : createCommentVNode("", true),
_ctx.columnType === "selection" ? (openBlock(), createBlock(_component_el_table_column, {
key: 1,
type: "selection",
fixed: "",
align: "center",
selectable: _ctx.selectable
}, null, 8, ["selectable"])) : createCommentVNode("", true),
_ctx.columnType === "expand" ? (openBlock(), createBlock(_component_el_table_column, {
key: 2,
type: "expand",
label: "展开",
fixed: "",
align: "center",
"min-width": "50"
}, {
default: withCtx((scope) => [
renderSlot(_ctx.$slots, "columnTypeExpand", {
row: scope.row
}, void 0, true)
]),
_: 3
})) : createCommentVNode("", true),
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.useHeader, (h, hi) => {
return openBlock(), createElementBlock(Fragment, { key: hi }, [
h.headerShow ? (openBlock(), createBlock(_component_el_table_column, {
key: 0,
label: h.label,
prop: h.prop,
fixed: h.fixed,
"min-width": h.width,
"show-overflow-tooltip": _ctx.tooltip,
sortable: h.sortable,
align: "center"
}, {
default: withCtx(() => [
h.children ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(h.children, (h2, h2i) => {
return openBlock(), createBlock(_component_el_table_column, {
key: h2i,
label: h2.label,
prop: h2.prop,
fixed: h2.fixed,
"min-width": h2.width,
"show-overflow-tooltip": _ctx.tooltip,
align: "center"
}, null, 8, ["label", "prop", "fixed", "min-width", "show-overflow-tooltip"]);
}), 128)) : createCommentVNode("", true)
]),
_: 2
}, 1032, ["label", "prop", "fixed", "min-width", "show-overflow-tooltip", "sortable"])) : createCommentVNode("", true)
], 64);
}), 128)),
renderSlot(_ctx.$slots, "otherColumn", {}, void 0, true)
]),
_: 3
}, 8, ["style", "element-loading-text", "data", "max-height", "span-method", "empty-text", "onSelectionChange"])), [
[_directive_loading, _ctx.loading]
])
], 4);
}
const TrendsTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-fa2655ba"]]);
const components = [
TrendsTable
];
const globals = {
install: function(app) {
components.map((item) => {
app.component(item.name, item);
});
},
// 局部引入时使用
TrendsTable
};
export {
globals as default
};