Files
vue3-element-admin/src/views/demo/table.vue
Jachin f797606c44 chore: prettier & lint
Former-commit-id: 486f65e137348f400d7b95067bd3cd5a2f23ff44
2023-08-07 18:39:29 +08:00

440 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="table-page">
<div class="table-wrap">
<el-table :data="tableData" border>
<el-table-column
v-for="oneCol in tableColList"
:key="oneCol.prop"
:prop="oneCol.prop"
:label="oneCol.label"
min-width="200"
:fixed="oneCol.fixed"
>
<template #header>
<div class="table-head">
<div class="label-wrap" @click="handleClickHead(oneCol)">
<div>{{ oneCol.label }}</div>
<template v-if="oneCol.order">
<i-ep-sort-up v-if="oneCol.order === 'asc'" />
<i-ep-sort-down v-else />
</template>
</div>
<el-dropdown
trigger="click"
@command="(command: string) => handleCommand(command, oneCol)"
>
<i-ep-arrow-down class="action-more" />
<template #dropdown>
<el-dropdown-menu>
<template v-if="oneCol.prop === 'id'">
<el-dropdown-item :command="TableCommand.ASC">
升序
</el-dropdown-item>
<el-dropdown-item :command="TableCommand.DESC">
降序
</el-dropdown-item>
</template>
<el-dropdown-item :command="TableCommand.FIXED">
{{ oneCol.fixed ? "解冻" : "冻结" }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
</el-table>
</div>
<h3>解析excel</h3>
<el-upload
:disabled="state.fileList.length !== 0"
class="upload"
drag
accept=".xls,.xlsx"
:show-file-list="false"
action=""
:http-request="handleUploadFile"
>
<i-ep-upload-filled class="icon" />
<div class="el-upload__text">拖拽excel到这里</div>
</el-upload>
<div v-loading="loading" class="excel-table-wrap">
<el-table
v-if="state.tableExcelHead.length && state.excelTableData.length"
:data="state.excelTableData"
stripe
border
style="width: 100%"
size="small"
>
<el-table-column
v-for="(item, index) in state.tableExcelHead"
:key="index"
:prop="item"
:label="item"
width="150"
>
<template #default="scope">
<span class="overflow-ellipsis">{{ scope.row[item] }}</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script lang="ts" setup>
import * as XLSX from "xlsx/xlsx.mjs";
import { cloneDeep } from "lodash-es";
enum TableCommand {
// 冻结
FIXED = "fixed",
// 升序
ASC = "asc",
// 降序
DESC = "desc",
}
let tableData = ref<any[]>([]);
const loading = ref(false);
const orginData = [
{
date: "2016-05-03",
name: "admin",
address: "广东",
id: 1,
gender: "男",
height: 176,
school: "清华大学",
hobby: "游泳",
},
{
date: "2016-05-02",
name: "admin",
address: "江西",
id: 3,
gender: "男",
height: 167,
school: "清华大学",
hobby: "游泳",
},
{
date: "2016-05-04",
name: "admin",
address: "湖南",
id: 4,
gender: "男",
height: 176,
school: "清华大学",
hobby: "游泳",
},
{
date: "2016-05-01",
name: "admin",
address: "重庆",
id: 2,
gender: "女",
height: 178,
school: "清华大学",
hobby: "游泳",
},
];
const state = reactive({
fileList: [],
excelData: [],
tableHead: [],
sheetList: [] as any[],
allSheetObj: {} as any,
tableExcelHead: [] as string[],
activeSheet: "",
fileName: "",
excelTableData: [],
});
onMounted(() => {
tableData.value = orginData.map((item) => item);
});
interface ColumnProp {
label: string;
prop: string;
order: null | string;
fixed: null | string;
}
const tableColList = ref<ColumnProp[]>([
{
label: "ID",
prop: "id",
order: null,
fixed: null,
},
{
label: "姓名",
prop: "name",
order: null,
fixed: null,
},
{
label: "性别",
prop: "gender",
order: null,
fixed: null,
},
{
label: "日期",
prop: "date",
order: null,
fixed: null,
},
{
label: "地址",
prop: "address",
order: null,
fixed: null,
},
{
label: "身高",
prop: "height",
order: null,
fixed: null,
},
{
label: "学校",
prop: "school",
order: null,
fixed: null,
},
{
label: "爱好",
prop: "hobby",
order: null,
fixed: null,
},
]);
const handleCommand = (command: string, tableCol: ColumnProp) => {
if (command === TableCommand.FIXED) {
tableColList.value.forEach((item) => {
if (item.prop === tableCol.prop) {
// 冻结/解冻
item.fixed = item.fixed ? null : "left";
}
});
}
// 升序
if (command === TableCommand.ASC) {
tableColList.value.forEach((item) => {
if (item.prop === tableCol.prop) {
item.order = "asc";
sortTableData(item);
}
});
}
// 降序
if (command === TableCommand.DESC) {
tableColList.value.forEach((item) => {
if (item.prop === tableCol.prop) {
item.order = "desc";
sortTableData(item);
}
});
}
};
// 点击表头循环排序
const handleClickHead = (oneCol: ColumnProp) => {
// 排序顺序
const sortArr = [null, "asc", "desc"];
const { order } = oneCol;
const findIndex = sortArr.findIndex((el) => el === order);
let currentIndex = findIndex + 1;
if (currentIndex > 2) {
currentIndex = 0;
}
// 排序只能排一列
tableColList.value.forEach((item) => {
if (item.prop === oneCol.prop) {
item.order = sortArr[currentIndex];
} else {
item.order = null;
}
});
sortTableData(oneCol);
};
const sortTableData = (sortCol: ColumnProp) => {
// 升序
if (sortCol.order === TableCommand.ASC) {
const compare = (p: string) => (m: any, n: any) => m[p] - n[p];
tableData.value = cloneDeep(orginData).sort(compare(sortCol.prop));
}
// 降序
if (sortCol.order === TableCommand.DESC) {
const compare = (p: string) => (m: any, n: any) => n[p] - m[p];
tableData.value = cloneDeep(orginData).sort(compare(sortCol.prop));
}
// 不排序
if (!sortCol.order) {
tableData.value = cloneDeep(orginData).map((item: any) => item);
}
};
const handleUploadFile = (data: any) => {
const { file } = data;
const { size, name } = file;
state.fileName = name;
// 获取最后一个.的位置
const index = name.lastIndexOf(".");
// 获取文件类型
const ext = name.substring(index + 1);
const accept = ["xlsx", "xls"];
if (!accept.includes(ext)) {
ElMessage({
type: "error",
message: "请选择xls或者xlsx文件",
});
return;
}
loading.value = true;
readFile(file, "");
};
const currentSheetName = computed(() => {
const find = state.sheetList.find(
(item) => item.sheetId === state.activeSheet
);
return find?.name || "";
});
const getFile = () => {
const sheetName = `${currentSheetName.value}`;
let workbook = XLSX.utils.book_new();
workbook = {
...workbook,
SheetNames: [sheetName],
Sheets: {},
};
workbook.Sheets[sheetName] = state.allSheetObj[sheetName];
const wopts = {
bookType: "xlsx", // 要生成的文件类型
bookSST: false, // 是否生成Shared String Table官方解释是如果开启生成速度会下降但在低版本IOS设备上有更好的兼容性
type: "binary", // 二进制格式
};
const wbout = XLSX.write(workbook, wopts);
const transform = (s: any) => {
const buf = new ArrayBuffer(s.length);
const view = new Uint8Array(buf);
// eslint-disable-next-line no-bitwise
for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
return buf;
};
// 字符串转ArrayBuffer
const blob = new Blob([transform(wbout)], {
type: "application/octet-stream",
});
const file = new window.File([blob], state.fileName, { type: "xlsx" });
};
const readFile = (file: any, callback: any) => {
const rABS = true; // true: readAsBinaryString ; false: readAsArrayBuffer
const reader = new FileReader();
reader.onload = function (e) {
let data = e.target?.result as any;
if (!rABS) data = new Uint8Array(data);
const readData = XLSX.read(data, {
type: rABS ? "binary" : "array",
cellText: false,
cellDates: true,
});
const { Sheets, Workbook } = readData;
state.sheetList = Workbook.Sheets;
state.activeSheet = state.sheetList[0].sheetId;
state.allSheetObj = Sheets;
const result = XLSX.utils.sheet_to_json(
state.allSheetObj[currentSheetName.value],
{ raw: false, dateNF: "YYYY-MM-DD HH:mm:ss" }
);
const allData = XLSX.utils.sheet_to_json(
state.allSheetObj[currentSheetName.value],
{ header: 1 }
);
state.tableExcelHead = allData.length > 0 ? allData[0] : Array(10).fill("");
state.excelTableData = result;
// getFile();
// 获取表头key
if (callback) callback(readData);
};
if (rABS) {
reader.readAsBinaryString(file);
} else {
reader.readAsArrayBuffer(file);
}
loading.value = false;
};
</script>
<style lang="scss" scoped>
.table-page {
width: 100%;
height: calc(100vh - 84px);
padding: 10px;
.table-wrap {
// height: 100%;
padding: 20px;
background-color: #fff;
.el-table {
width: 800px;
.table-head {
display: flex;
align-items: center;
justify-content: space-between;
.label-wrap {
display: flex;
flex: 1;
align-items: center;
cursor: pointer;
svg {
margin-left: 5px;
}
}
.action-more {
cursor: pointer;
&:hover {
color: #409eff;
}
}
}
}
}
.upload {
box-sizing: border-box;
height: 230px;
margin-top: 16px;
margin-bottom: 20px;
background-color: #e3f2fd;
border: 2px dashed #90caf9;
border-radius: 2px;
:deep(.el-upload-dragger) {
padding: 0;
background-color: #e3f2fd;
border: none;
.icon {
font-size: 110px;
color: #90caf9;
}
}
}
.excel-table-wrap {
width: 100%;
min-height: 300px;
}
}
</style>