feat(table): add vxe-table

This commit is contained in:
xiaoxian521 2021-04-02 14:52:50 +08:00
parent 2467de5493
commit 2de43ef859
6 changed files with 238 additions and 403 deletions

5
package-lock.json generated
View File

@ -760,6 +760,11 @@
"resolved": "http://192.168.250.101:4873/follow-redirects/-/follow-redirects-1.13.2.tgz",
"integrity": "sha1-3XPI7/wScoulz0JZ12DqX7g+MUc="
},
"font-awesome": {
"version": "4.7.0",
"resolved": "http://192.168.250.101:4873/font-awesome/-/font-awesome-4.7.0.tgz",
"integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM="
},
"fraction.js": {
"version": "4.0.13",
"resolved": "http://192.168.250.101:4873/fraction.js/-/fraction.js-4.0.13.tgz",

View File

@ -12,6 +12,7 @@
"axios": "^0.21.1",
"dotenv": "^8.2.0",
"element-plus": "^1.0.2-beta.36",
"font-awesome": "^4.7.0",
"mitt": "^2.1.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",

View File

@ -1,5 +1,5 @@
<template>
<section class="app-main">
<section class="app-main" :style="{'margin': appMargin}">
<router-view :key="key" v-slot="{ Component }">
<transition appear name="fade-transform" mode="out-in">
<keep-alive>
@ -13,24 +13,25 @@
<script>
import { computed, defineComponent } from "vue";
import { useRoute } from "vue-router";
import { deviceDetection } from "../../utils/deviceDetection";
export default defineComponent({
name: "AppMain",
setup() {
const route = useRoute();
const key = computed(() => route.path);
const appMargin = computed(() => (deviceDetection() ? 0 : "10px"));
return { key };
return { key, appMargin };
},
});
</script>
<style scoped>
.app-main {
min-height: calc(100vh - 50px);
/* min-height: calc(100vh - 50px); */
width: 100%;
position: relative;
overflow-x: hidden;
margin: 10px;
}
.fixed-header + .app-main {
padding-top: 50px;

View File

@ -9,6 +9,7 @@ import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
// 内置vxe-table
import "font-awesome/css/font-awesome.css"
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'

View File

@ -20,7 +20,7 @@ label {
}
html {
overflow: hidden;
overflow-x: hidden;
width: 100%;
height: 100%;
box-sizing: border-box;
@ -29,7 +29,7 @@ html {
#app {
width: 100%;
height: 100%;
overflow: hidden;
overflow-x: hidden;
}
*,

View File

@ -1,421 +1,248 @@
<template>
<vxe-grid ref="xGrid" v-bind="gridOptions" style="width:98%"></vxe-grid>
<vxe-grid v-bind="gridOptions" style="width:98%"></vxe-grid>
</template>
<script lang='ts'>
import { defineComponent, onMounted, reactive, ref, Ref } from "vue";
import { VXETable, VxeGridInstance, VxeGridProps } from "vxe-table";
import XEUtils from "xe-utils";
import XEAjax from "xe-ajax";
import { reactive } from "vue";
import { VxeGridProps } from "vxe-table";
export default {
name: "user",
setup() {
const xGrid = ref({} as VxeGridInstance);
const gridOptions = reactive({
border: true,
resizable: true,
showHeaderOverflow: true,
showOverflow: true,
highlightHoverRow: true,
keepSource: true,
id: "full_edit_1",
height: 600,
rowId: "id",
customConfig: {
storage: true,
checkMethod({ column }) {
if (["nickname", "role"].includes(column.property)) {
return false;
}
return true;
},
},
printConfig: {
columns: [
{ field: "name" },
{ field: "email" },
{ field: "nickname" },
{ field: "age" },
{ field: "amount" },
],
},
sortConfig: {
trigger: "cell",
remote: true,
},
filterConfig: {
remote: true,
},
height: 500,
printConfig: {},
importConfig: {},
exportConfig: {},
pagerConfig: {
pageSize: 10,
pageSizes: [5, 10, 15, 20, 50, 100, 200, 500, 1000],
},
formConfig: {
titleWidth: 100,
titleAlign: "right",
items: [
{
field: "name",
title: "app.body.label.name",
span: 8,
titlePrefix: {
message: "app.body.valid.rName",
icon: "fa fa-exclamation-circle",
},
itemRender: {
name: "$input",
props: { placeholder: "请输入名称" },
},
},
{
field: "email",
title: "邮件",
span: 8,
itemRender: {
name: "$input",
props: { placeholder: "请输入邮件" },
},
},
{
field: "nickname",
title: "昵称",
span: 8,
itemRender: {
name: "$input",
props: { placeholder: "请输入昵称" },
},
},
{
field: "role",
title: "角色",
span: 8,
folding: true,
itemRender: {
name: "$input",
props: { placeholder: "请输入角色" },
},
},
{
field: "sex",
title: "性别",
span: 8,
folding: true,
titleSuffix: {
message: "注意,必填信息!",
icon: "fa fa-info-circle",
},
itemRender: { name: "$select", options: [] },
},
{
field: "age",
title: "年龄",
span: 8,
folding: true,
itemRender: {
name: "$input",
props: {
type: "number",
min: 1,
max: 120,
placeholder: "请输入年龄",
},
},
},
{
span: 24,
align: "center",
collapseNode: true,
itemRender: {
name: "$buttons",
children: [
{
props: {
type: "submit",
content: "app.body.label.search",
status: "primary",
},
},
{ props: { type: "reset", content: "app.body.label.reset" } },
],
},
},
],
},
toolbarConfig: {
buttons: [
{ code: "insert_actived", name: "新增", icon: "fa fa-plus" },
{ code: "delete", name: "直接删除", icon: "fa fa-trash-o" },
{ code: "mark_cancel", name: "删除/取消", icon: "fa fa-trash-o" },
{
code: "save",
name: "app.body.button.save",
icon: "fa fa-save",
status: "success",
},
],
refresh: true,
import: true,
export: true,
print: true,
zoom: true,
custom: true,
},
proxyConfig: {
seq: true, //
sort: true, //
filter: true, //
form: true, //
props: {
result: "result",
total: "page.total",
},
ajax: {
// Promise
query: ({ page, sorts, filters, form }) => {
const queryParams: any = Object.assign({}, form);
//
const firstSort = sorts[0];
if (firstSort) {
queryParams.sort = firstSort.property;
queryParams.order = firstSort.order;
}
//
filters.forEach(({ property, values }) => {
queryParams[property] = values.join(",");
});
return XEAjax.get(
`https://api.xuliangzhan.com:10443/api/pub/page/list/${page.pageSize}/${page.currentPage}`,
queryParams
);
},
delete: ({ body }) =>
XEAjax.post("https://api.xuliangzhan.com:10443/api/pub/save", body),
save: ({ body }) =>
XEAjax.post("https://api.xuliangzhan.com:10443/api/pub/save", body),
},
},
columns: [
{ type: "checkbox", title: "ID", width: 120 },
{
field: "name",
title: "Name",
sortable: true,
titleHelp: { message: "名称必须填写!" },
editRender: { name: "input", attrs: { placeholder: "请输入名称" } },
},
{
field: "role",
title: "Role",
sortable: true,
filters: [
{ label: "前端开发", value: "前端" },
{ label: "后端开发", value: "后端" },
{ label: "测试", value: "测试" },
{ label: "程序员鼓励师", value: "程序员鼓励师" },
],
filterMultiple: false,
editRender: { name: "input", attrs: { placeholder: "请输入角色" } },
},
{
field: "email",
title: "Email",
width: 160,
editRender: { name: "$input", props: { placeholder: "请输入邮件" } },
},
{
field: "nickname",
title: "Nickname",
editRender: { name: "input", attrs: { placeholder: "请输入昵称" } },
},
{
field: "sex",
title: "Sex",
editRender: {
name: "$select",
options: [],
props: { placeholder: "请选择性别" },
},
},
{
field: "age",
title: "Age",
visible: false,
sortable: true,
editRender: {
name: "$input",
props: { type: "number", min: 1, max: 120 },
},
},
{
field: "amount",
title: "Amount",
formatter({ cellValue }) {
return cellValue
? `${XEUtils.commafy(XEUtils.toNumber(cellValue), {
digits: 2,
})}`
: "";
},
editRender: {
name: "$input",
props: { type: "float", digits: 2, placeholder: "请输入数值" },
},
},
{
field: "updateDate",
title: "Update Date",
width: 160,
visible: false,
sortable: true,
formatter({ cellValue }) {
return XEUtils.toDateString(cellValue, "yyyy-MM-dd HH:ss:mm");
},
},
{
field: "createDate",
title: "Create Date",
width: 160,
visible: false,
sortable: true,
formatter({ cellValue }) {
return XEUtils.toDateString(cellValue, "yyyy-MM-dd");
},
},
],
importConfig: {
remote: true,
types: ["xlsx"],
modes: ["insert"],
//
importMethod({ file }) {
const $grid = xGrid.value;
const formBody = new FormData();
formBody.append("file", file);
return XEAjax.post(
"https://api.xuliangzhan.com:10443/api/pub/import",
formBody
)
.then((data) => {
VXETable.modal.message({
message: `成功导入 ${data.result.insertRows} 条记录!`,
status: "success",
});
//
$grid.commitProxy("query");
})
.catch(() => {
VXETable.modal.message({
message: "导入失败,请检查数据是否正确!",
status: "error",
});
});
},
},
exportConfig: {
remote: true,
types: ["xlsx"],
modes: ["current", "selected", "all"],
//
exportMethod({ options }) {
const $grid = xGrid.value;
const proxyInfo = $grid.getProxyInfo();
//
const body = {
filename: options.filename,
sheetName: options.sheetName,
isHeader: options.isHeader,
original: options.original,
mode: options.mode,
pager: proxyInfo ? proxyInfo.pager : null,
ids:
options.mode === "selected"
? options.data.map((item) => item.id)
: [],
fields: options.columns.map((column) => {
return {
field: column.property,
title: column.title,
};
}),
};
//
return XEAjax.post(
"https://api.xuliangzhan.com:10443/api/pub/export",
body
)
.then((data) => {
if (data.id) {
VXETable.modal.message({
message: "导出成功,开始下载",
status: "success",
});
//
XEAjax.fetch(
`https://api.xuliangzhan.com:10443/api/pub/export/download/${data.id}`
).then((response) => {
response.blob().then((blob) => {
//
VXETable.saveFile({
filename: "导出数据",
type: "xlsx",
content: blob,
});
});
});
}
})
.catch(() => {
VXETable.modal.message({
message: "导出失败!",
status: "error",
});
});
},
},
checkboxConfig: {
labelField: "id",
reserve: true,
highlight: true,
range: true,
},
editRules: {
name: [
{ required: true, message: "app.body.valid.rName" },
{ min: 3, max: 50, message: "名称长度在 3 到 50 个字符" },
],
email: [{ required: true, message: "邮件必须填写" }],
role: [{ required: true, message: "角色必须填写" }],
perfect: true,
pageSize: 15,
},
editConfig: {
trigger: "click",
mode: "row",
showStatus: true,
},
toolbarConfig: {
buttons: [
{
code: "insert_actived",
name: "新增",
status: "perfect",
icon: "fa fa-plus",
},
{
code: "mark_cancel",
name: "标记/取消",
status: "perfect",
icon: "fa fa-trash-o",
},
{
code: "save",
name: "保存",
status: "perfect",
icon: "fa fa-save",
},
],
perfect: true,
refresh: {
icon: "fa fa-refresh",
iconLoading: "fa fa-spinner fa-spin",
},
import: {
icon: "fa fa-upload",
},
export: {
icon: "fa fa-download",
},
print: {
icon: "fa fa-print",
},
// zoom: {
// iconIn: "fa fa-arrows-alt",
// iconOut: "fa fa-expand",
// },
custom: {
icon: "fa fa-cog",
},
},
proxyConfig: {
props: {
result: "result",
total: "page.total",
},
ajax: {
// Promise
query: ({ page }) => {
return new Promise((resolve) => {
setTimeout(() => {
const list = [
{
id: 10001,
name: "Test1",
nickname: "T1",
role: "Develop",
sex: "Man",
age: 28,
address: "Shenzhen",
},
{
id: 10002,
name: "Test2",
nickname: "T2",
role: "Test",
sex: "Women",
age: 22,
address: "Guangzhou",
},
{
id: 10003,
name: "Test3",
nickname: "T3",
role: "PM",
sex: "Man",
age: 32,
address: "Shanghai",
},
{
id: 10004,
name: "Test4",
nickname: "T4",
role: "Designer",
sex: "Women ",
age: 23,
address: "Shenzhen",
},
{
id: 10005,
name: "Test5",
nickname: "T5",
role: "Develop",
sex: "Women ",
age: 30,
address: "Shanghai",
},
{
id: 10006,
name: "Test6",
nickname: "T6",
role: "Designer",
sex: "Women ",
age: 21,
address: "Shenzhen",
},
{
id: 10007,
name: "Test7",
nickname: "T7",
role: "Test",
sex: "Man ",
age: 29,
address: "vxe-table 从入门到放弃",
},
{
id: 10008,
name: "Test8",
nickname: "T8",
role: "Develop",
sex: "Man ",
age: 35,
address: "Shenzhen",
},
{
id: 10009,
name: "Test9",
nickname: "T9",
role: "Develop",
sex: "Man ",
age: 35,
address: "Shenzhen",
},
{
id: 100010,
name: "Test10",
nickname: "T10",
role: "Develop",
sex: "Man ",
age: 35,
address: "Guangzhou",
},
{
id: 100011,
name: "Test11",
nickname: "T11",
role: "Test",
sex: "Women ",
age: 26,
address: "vxe-table 从入门到放弃",
},
{
id: 100012,
name: "Test12",
nickname: "T12",
role: "Develop",
sex: "Man ",
age: 34,
address: "Guangzhou",
},
{
id: 100013,
name: "Test13",
nickname: "T13",
role: "Test",
sex: "Women ",
age: 22,
address: "Shenzhen",
},
];
resolve({
page: {
total: list.length,
},
result: list.slice(
(page.currentPage - 1) * page.pageSize,
page.currentPage * page.pageSize
),
});
}, 100);
});
},
// body { removeRecords }
delete: () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({});
}, 100);
});
},
// body { insertRecords, updateRecords, removeRecords, pendingRecords }
save: () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({});
}, 100);
});
},
},
},
columns: [
{ type: "checkbox", width: 50 },
{ type: "seq", width: 60 },
{ field: "name", title: "Name", editRender: { name: "input" } },
{ field: "nickname", title: "Nickname", editRender: { name: "input" } },
{ field: "role", title: "Role", editRender: { name: "input" } },
{
field: "address",
title: "Address",
showOverflow: true,
editRender: { name: "input" },
},
],
} as VxeGridProps);
onMounted(() => {
const sexList = [
{ label: "女", value: "0" },
{ label: "男", value: "1" },
];
const { formConfig, columns } = gridOptions;
if (columns) {
const sexColumn = columns[5];
if (sexColumn && sexColumn.editRender) {
sexColumn.editRender.options = sexList;
}
}
if (formConfig && formConfig.items) {
const sexItem = formConfig.items[4];
if (sexItem && sexItem.itemRender) {
sexItem.itemRender.options = sexList;
}
}
});
return {
xGrid,
gridOptions,
};
},