Files
vue3-element-admin/src/views/demo/vxe-table/index.vue
2025-06-11 22:43:19 +08:00

633 lines
17 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="app-container">
<!-- 表格 -->
<vxe-grid ref="xGrid" v-bind="gridOptions" v-on="gridEvents">
<!-- 搜索 -->
<!-- <template #form-roles="{ data }">
<el-select
v-model="data.roles"
multiple
collapse-tags
collapse-tags-tooltip
placeholder="请选择角色"
filterable
clearable
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template> -->
<!-- 左侧按钮列表 -->
<template #toolbar-btns>
<vxe-button status="primary" icon="vxe-icon-add" @click="curd.onShowModal()">
新增用户
</vxe-button>
<vxe-button status="danger" icon="vxe-icon-delete" @click="curd.onDelete()">
批量删除
</vxe-button>
</template>
<!-- 展开列 -->
<template #column-expand="{ row }">
<div style="padding: 20px">
<ul>
<li>
<span>ID</span>
<span>{{ row.id }}</span>
</li>
<li>
<span>UserName</span>
<span>{{ row.username }}</span>
</li>
<li>
<span>CreateTime</span>
<span>{{ row.createTime }}</span>
</li>
</ul>
</div>
</template>
<!-- 角色列 -->
<template #column-roles="{ row, column }">
<el-tag
v-for="(role, index) in row[column.field].split(',')"
:key="index"
:type="role === 'admin' ? 'primary' : 'warning'"
effect="plain"
>
{{ role }}
</el-tag>
</template>
<!-- 操作列 -->
<template #column-operate="{ row }">
<el-button link type="primary" @click="curd.onShowModal(row)">修改</el-button>
<el-button link type="danger" @click="curd.onDelete(row)">删除</el-button>
</template>
</vxe-grid>
<!-- 弹窗 -->
<vxe-modal ref="xModal" v-bind="modalOptions">
<!-- 表单 -->
<vxe-form ref="xForm" v-bind="formOptions" />
</vxe-modal>
</div>
</template>
<script setup lang="ts">
import { reactive, onMounted } from "vue";
import type {
VxeGridInstance,
VxeGridProps,
VxeGridListeners,
VxeModalInstance,
VxeModalProps,
VxeFormInstance,
VxeFormProps,
} from "vxe-table";
import { VXETable } from "vxe-table";
const options = [
{ label: "管理员", value: "admin" },
{ label: "用户", value: "user" },
{ label: "访客", value: "guest" },
];
onMounted(() => {
setTimeout(() => {
gridOptions!.formConfig!.items!.forEach((item) => {
if (item.field === "roles") {
item!.itemRender!.props!.options = options;
}
});
}, 500);
});
// #region vxe-grid
interface RowMeta {
id: number;
username: string;
roles: string;
phone: string;
email: string;
status: boolean;
createTime: string;
}
const xGrid = ref<VxeGridInstance<RowMeta>>();
const gridOptions = reactive<VxeGridProps<RowMeta>>({
// 自动监听父元素的变化去重新计算表格
autoResize: true,
// 是否显示表尾
showFooter: true,
// 表尾数据(优先级比 footerMethod 高)
// footerData: [
// {
// username: "-",
// roles: "-",
// phone: "-",
// email: "-",
// status: "启用7条",
// createTime: "-",
// },
// ],
// 表尾的数据获取方法,返回一个二维数组
footerMethod({ columns, data }) {
return [
columns.map((column, columnIndex) => {
if (columnIndex === 0 || column.field === undefined) {
return "";
} else if (column.field === "status") {
return `启用:${data.reduce((sum, row) => sum + (row.status ? 1 : 0), 0)}`;
}
return "-";
}),
];
},
// 列配置
columns: [
{ type: "checkbox", width: 60 },
{
type: "expand",
width: 60,
slots: {
// 只对 type=expand 有效,自定义展开后的内容模板
content: "column-expand",
},
},
{ type: "seq", width: 60 },
{ field: "id", title: "ID", visible: false },
{ field: "username", title: "用户名" },
{ field: "roles", title: "角色", slots: { default: "column-roles" } },
{ field: "phone", title: "手机号" },
{ field: "email", title: "邮箱" },
{
field: "status",
title: "状态",
sortable: true,
filters: [
{ label: "启用", value: true },
{ label: "禁用", value: false },
],
// 数据筛选,只对 filters 有效,筛选是否允许多选
filterMultiple: false,
formatter({ cellValue }) {
return cellValue === true ? "启用" : "禁用";
},
},
{ field: "createTime", title: "创建时间", sortable: true },
{
title: "操作",
width: "150px",
fixed: "right",
showOverflow: false,
slots: {
default: "column-operate",
},
},
],
// 列配置信息
columnConfig: {
// 每一列是否启用列宽调整
resizable: true,
},
// 自定义列配置项
customConfig: {
// 是否允许列选中
checkMethod: ({ column }) => !["username"].includes(column.field),
},
// 复选框配置项
checkboxConfig: {
// 是否保留勾选状态(需要有 row-config.keyField
// reserve: true,
},
// 展开行配置项(不支持虚拟滚动)
expandConfig: {
// 展开列显示的字段名,可以直接显示在单元格中
// labelField: "username",
// 每次只能展开一行
accordion: true,
},
// 行配置信息
rowConfig: {
// 自定义行数据唯一主键的字段名
keyField: "id",
// 当鼠标点击行时,是否要高亮当前行
isCurrent: true,
},
// 表单配置项
formConfig: {
// 项配置
items: [
{
span: 4,
field: "username",
title: "用户名",
// 前缀配置项
titlePrefix: {
useHTML: true,
content:
'点击链接:<a class="link" href="https://vxetable.cn" target="_blank">vxe-table官网</a>',
icon: "vxe-icon-question-circle-fill",
},
// 项渲染器配置项
itemRender: {
// 渲染器名称
name: "VxeInput",
// 渲染的参数
props: {
type: "text",
clearable: true,
placeholder: "请输入用户名",
},
},
},
{
span: 4,
field: "roles",
title: "角色",
// 默认收起
folding: true,
itemRender: {
name: "VxeSelect",
props: {
multiple: true,
multiCharOverflow: -1,
filterable: true,
clearable: true,
options: [],
placeholder: "请选择角色",
},
},
},
// {
// span: 4,
// field: "roles",
// title: "角色",
// // 默认收起
// folding: true,
// // 插槽
// slots: {
// // 自定义表单项
// default: "form-roles",
// },
// },
{
collapseNode: true,
itemRender: {
name: "VxeButtonGroup",
options: [
{
type: "submit",
status: "primary",
icon: "vxe-icon-search",
content: "搜索",
},
{ type: "reset", icon: "vxe-icon-refresh", content: "重置" },
],
},
},
],
},
// 工具栏配置
toolbarConfig: {
// 导入按钮配置(需要设置 "import-config"
import: true,
// 导出按钮配置(需要设置 "export-config"
export: true,
// 打印按钮配置(需要设置 "print-config"
print: true,
// 刷新按钮配置
refresh: true,
// 是否允许最大化显示
zoom: true,
// 自定义列配置
custom: true,
//插槽
slots: {
// 按钮列表
buttons: "toolbar-btns",
},
},
// 导入配置项
importConfig: {},
// 导出配置项
exportConfig: {
// 指定列
columns: [{ field: "phone" }, { field: "email" }, { field: "status" }, { field: "createTime" }],
},
// 打印配置项
printConfig: {},
// 筛选配置项
filterConfig: {
// 所有列是否使用服务端筛选
remote: false,
},
// 排序配置项
sortConfig: {
// 所有列是否使用服务端排序
remote: false,
// 是否启用多列组合筛选
multiple: false,
// 只对 multiple 有效,是否按照先后触发顺序进行排序
chronological: true,
},
// 分页配置项
pagerConfig: {
enabled: true,
pageSize: 10,
},
// 数据代理配置项
proxyConfig: {
// 是否自动加载查询数据
autoLoad: true,
// 启用动态序号代理(分页之后索引自动计算为当前页的起始序号)
seq: true,
// 表单代理
form: true,
// 是否代理筛选(只对 filter-config.remote=true 时有效)
filter: true,
// 是否代理排序(只对 sort-config.remote=true 时有效)
sort: true,
// 获取响应的值配置
response: {
// 只对 pager-config 配置了有效,响应结果中获取数据列表的属性(分页场景)
result: "result",
// 只对 pager-config 配置了有效,响应结果中获取分页的属性(分页场景)
total: "total",
},
ajax: {
// 接收 Promise
query: ({ page: { currentPage, pageSize }, form, filters, sort, sorts }) => {
console.log({ currentPage, pageSize, form, filters, sort, sorts });
return new Promise<{ total: number; result: RowMeta[] }>((resolve) => {
setTimeout(() => {
const list = [
{
username: "Richard Clark",
roles: "editor",
phone: "18185826431",
email: "y.djf@xiswx.fk",
status: true,
createTime: "2010-04-17 12:39:20",
id: 810000201008060500,
},
{
username: "Robert Garcia",
roles: "admin",
phone: "18125716043",
email: "z.japgndxosu@inoudjxc.ie",
status: false,
createTime: "2020-01-02 11:51:58",
id: 130000201904129330,
},
{
username: "Thomas Moore",
roles: "admin",
phone: "18106622048",
email: "j.fvsgnjjutm@fmjw.se",
status: true,
createTime: "1983-10-12 10:06:41",
id: 420000198203053100,
},
{
username: "Dorothy Lewis",
roles: "admin",
phone: "13321357284",
email: "o.htso@iwxvehrs.tj",
status: true,
createTime: "1970-03-03 00:26:45",
id: 150000201803243100,
},
{
username: "George Rodriguez",
roles: "admin",
phone: "18158641167",
email: "x.sigizx@fwknokiqn.tr",
status: true,
createTime: "1988-03-16 14:46:26",
id: 610000199308265900,
},
{
username: "Angela Jackson",
roles: "admin",
phone: "19810721230",
email: "j.gqrdqaqtu@ipthgm.fj",
status: true,
createTime: "2006-09-26 12:53:37",
id: 350000197310101440,
},
{
username: "James Walker",
roles: "admin",
phone: "18123903251",
email: "k.axmdcsl@mcmeudog.cl",
status: true,
createTime: "1981-01-19 12:51:34",
id: 130000199308208900,
},
{
username: "Paul Garcia",
roles: "admin",
phone: "18617930381",
email: "c.glufsn@vwqntlllj.es",
status: false,
createTime: "2009-12-04 20:40:57",
id: 510000199212239200,
},
{
username: "Jeffrey Miller",
roles: "admin",
phone: "18145245413",
email: "u.poqrqw@arto.rw",
status: false,
createTime: "1991-04-01 05:16:52",
id: 330000198604109760,
},
{
username: "Donna Lewis",
roles: "editor",
phone: "19839835537",
email: "l.lmpeoupu@rujdlzdbk.gf",
status: true,
createTime: "1987-11-29 21:47:37",
id: 640000197005230500,
},
{
username: "Jennifer Smith",
roles: "editor",
phone: "18145245413",
email: "j.jqx@xjxqx.jp",
status: true,
createTime: "1991-04-01 05:16:52",
id: 640000197005230000,
},
];
resolve({
result: list.slice((currentPage - 1) * pageSize, currentPage * pageSize),
total: list.length,
});
}, 500);
});
},
},
},
});
const gridEvents: VxeGridListeners<RowMeta> = {
// 只对 form-config 配置时有效,表单重置时会触发该事件
formReset() {
console.log("Form Reset");
},
};
// #endregion
// #region vxe-modal
const xModal = ref<VxeModalInstance>();
const modalOptions = reactive<VxeModalProps>({
// 窗口的标题
title: "",
// 是否允许点击遮罩层关闭窗口
maskClosable: true,
// 是否允许按 Esc 键关闭窗口
escClosable: true,
// 在窗口隐藏之前执行
beforeHideMethod: () => {
xForm.value?.clearValidate();
return Promise.resolve();
},
});
// #endregion
// #region vxe-form
const xForm = ref<VxeFormInstance>();
const formOptions = reactive<VxeFormProps>({
// 所有项的栅格占据的列数
span: 24,
// 所有项的标题宽度
titleWidth: 100,
// 表单数据
data: {
username: "",
password: "",
},
// 项列表
items: [
{
field: "username",
title: "用户名",
itemRender: {
name: "VxeInput",
props: {
placeholder: "请输入",
},
},
},
{
field: "password",
title: "密码",
itemRender: {
name: "VxeInput",
props: {
placeholder: "请输入",
},
},
},
{
align: "right",
itemRender: {
name: "$buttons",
children: [
{
props: {
content: "取消",
},
events: {
click: () => xModal.value?.close(),
},
},
{
props: {
type: "submit",
content: "确定",
status: "primary",
},
events: {
click: () => curd.onSubmitForm(),
},
},
],
},
},
],
/** 校验规则 */
rules: {
username: [
{
required: true,
validator: ({ itemValue }) => {
switch (true) {
case !itemValue:
return new Error("请输入");
case !itemValue.trim():
return new Error("空格无效");
}
},
},
],
password: [
{
required: true,
validator: ({ itemValue }) => {
switch (true) {
case !itemValue:
return new Error("请输入");
case !itemValue.trim():
return new Error("空格无效");
}
},
},
],
},
});
// #endregion
const curd = {
commitQuery: () => xGrid.value?.commitProxy("query"),
onShowModal: (row?: RowMeta) => {
if (row) {
modalOptions.title = "修改用户";
} else {
modalOptions.title = "新增用户";
}
xModal.value?.open();
},
/** 确定并保存 */
onSubmitForm: () => {
console.log("提交表单");
},
onDelete: (row?: RowMeta) => {
let ids = [];
if (row === undefined) {
// 获取当前已选中的行数据
const selected = xGrid.value?.getCheckboxRecords();
if (!selected || selected.length === 0) {
VXETable.modal.message({
content: "请至少选择一条数据",
status: "warning",
});
return;
}
ids = selected.map((item) => item.id);
} else {
ids = [row.id];
}
VXETable.modal.confirm("确定要删除吗?").then((type) => {
if (type === "confirm") {
// 执行删除操作
console.log("删除的ID", ids);
}
});
},
};
</script>
<style scoped></style>