<script lang="ts" setup> import { nextTick, reactive, ref } from "vue" import { type ElMessageBoxOptions, ElMessageBox, ElMessage } from "element-plus" import { deleteTableDataApi, getTableDataApi } from "@/api/table" import { type GetTableResponseData } from "@/api/table/types/table" import RoleColumnSolts from "./tsx/RoleColumnSolts" import StatusColumnSolts from "./tsx/StatusColumnSolts" import { type VxeGridInstance, type VxeGridProps, type VxeModalInstance, type VxeModalProps, type VxeFormInstance, type VxeFormProps } from "vxe-table" defineOptions({ // 命名当前组件 name: "VxeTable" }) //#region vxe-grid interface RowMeta { id: string username: string roles: string phone: string email: string status: boolean createTime: string /** vxe-table 自动添加上去的属性 */ _VXE_ID?: string } const xGridDom = ref<VxeGridInstance>() const xGridOpt: VxeGridProps = reactive({ loading: true, autoResize: true, /** 分页配置项 */ pagerConfig: { align: "right" }, /** 表单配置项 */ formConfig: { items: [ { field: "username", itemRender: { name: "$input", props: { placeholder: "用户名", clearable: true } } }, { field: "phone", itemRender: { name: "$input", props: { placeholder: "手机号", clearable: true } } }, { itemRender: { name: "$buttons", children: [ { props: { type: "submit", content: "查询", status: "primary" } }, { props: { type: "reset", content: "重置" } } ] } } ] }, /** 工具栏配置 */ toolbarConfig: { refresh: true, custom: true, slots: { buttons: "toolbar-btns" } }, /** 自定义列配置项 */ customConfig: { /** 是否允许列选中 */ checkMethod: ({ column }) => !["username"].includes(column.field) }, /** 列配置 */ columns: [ { type: "checkbox", width: "50px" }, { field: "username", title: "用户名" }, { field: "roles", title: "角色", /** 自定义列与 type: "html" 的列一起使用,会产生错误,所以采用 TSX 实现 */ slots: RoleColumnSolts }, { field: "phone", title: "手机号" }, { field: "email", title: "邮箱" }, { field: "status", title: "状态", slots: StatusColumnSolts }, { field: "createTime", title: "创建时间" }, { title: "操作", width: "150px", fixed: "right", showOverflow: false, slots: { default: "row-operate" } } ], /** 数据代理配置项(基于 Promise API) */ proxyConfig: { /** 启用动态序号代理 */ seq: true, /** 是否代理表单 */ form: true, /** 是否自动加载,默认为 true */ // autoLoad: false, props: { total: "total" }, ajax: { query: ({ page, form }) => { xGridOpt.loading = true crudStore.clearTable() return new Promise((resolve) => { let total = 0 let result: RowMeta[] = [] /** 加载数据 */ const callback = (res: GetTableResponseData) => { if (res?.data) { // 总数 total = res.data.total // 列表数据 result = res.data.list } xGridOpt.loading = false // 返回值有格式要求,详情见 vxe-table 官方文档 resolve({ total, result }) } /** 接口需要的参数 */ const params = { username: form.username || undefined, phone: form.phone || undefined, size: page.pageSize, currentPage: page.currentPage } /** 调用接口 */ getTableDataApi(params).then(callback).catch(callback) }) } } } }) //#endregion //#region vxe-modal const xModalDom = ref<VxeModalInstance>() const xModalOpt: VxeModalProps = reactive({ title: "", showClose: true, escClosable: true, maskClosable: true, beforeHideMethod: () => { xFormDom.value?.clearValidate() return Promise.resolve() } }) //#endregion //#region vxe-form const xFormDom = ref<VxeFormInstance>() const xFormOpt: VxeFormProps = reactive({ span: 24, titleWidth: "100px", loading: false, /** 是否显示标题冒号 */ titleColon: false, /** 表单数据 */ data: { username: "", password: "" }, /** 项列表 */ items: [ { field: "username", title: "用户名", itemRender: { name: "$input", props: { placeholder: "请输入" } } }, { field: "password", title: "密码", itemRender: { name: "$input", props: { placeholder: "请输入" } } }, { align: "right", itemRender: { name: "$buttons", children: [ { props: { content: "取消" }, events: { click: () => xModalDom.value?.close() } }, { props: { type: "submit", content: "确定", status: "primary" }, events: { click: () => crudStore.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 //#region 增删改查 const crudStore = reactive({ /** 表单类型,true 表示修改,false 表示新增 */ isUpdate: true, /** 加载表格数据 */ commitQuery: () => xGridDom.value?.commitProxy("query"), /** 清空表格数据 */ clearTable: () => xGridDom.value?.reloadData([]), /** 点击显示弹窗 */ onShowModal: (row?: RowMeta) => { if (row) { crudStore.isUpdate = true xModalOpt.title = "修改用户" // 赋值 xFormOpt.data.username = row.username } else { crudStore.isUpdate = false xModalOpt.title = "新增用户" } // 禁用表单项 const props = xFormOpt.items?.[0]?.itemRender?.props props && (props.disabled = crudStore.isUpdate) xModalDom.value?.open() nextTick(() => { !crudStore.isUpdate && xFormDom.value?.reset() xFormDom.value?.clearValidate() }) }, /** 确定并保存 */ onSubmitForm: () => { if (xFormOpt.loading) return xFormDom.value?.validate((errMap) => { if (errMap) return xFormOpt.loading = true const callback = () => { xFormOpt.loading = false xModalDom.value?.close() ElMessage.success("操作成功") !crudStore.isUpdate && crudStore.afterInsert() crudStore.commitQuery() } if (crudStore.isUpdate) { // 模拟调用修改接口成功 setTimeout(() => callback(), 1000) } else { // 模拟调用新增接口成功 setTimeout(() => callback(), 1000) } }) }, /** 新增后是否跳入最后一页 */ afterInsert: () => { const pager = xGridDom.value?.getProxyInfo()?.pager if (pager) { const currentTotal = pager.currentPage * pager.pageSize if (currentTotal === pager.total) { ++pager.currentPage } } }, /** 删除 */ onDelete: (row: RowMeta) => { const tip = `确定 <strong style="color: red"> 删除 </strong> 用户 <strong style="color: #409eff"> ${row.username} </strong> ?` const config: ElMessageBoxOptions = { type: "warning", showClose: true, closeOnClickModal: true, closeOnPressEscape: true, cancelButtonText: "取消", confirmButtonText: "确定", dangerouslyUseHTMLString: true } ElMessageBox.confirm(tip, "提示", config).then(() => { deleteTableDataApi(row.id).then(() => { ElMessage.success("删除成功") crudStore.afterDelete() crudStore.commitQuery() }) }) }, /** 删除后是否返回上一页 */ afterDelete: () => { const tableData: RowMeta[] = xGridDom.value!.getData() const pager = xGridDom.value?.getProxyInfo()?.pager if (pager && pager.currentPage > 1 && tableData.length === 1) { --pager.currentPage } }, /** 更多自定义方法 */ moreFn: () => {} }) //#endregion </script> <template> <div class="app-container"> <!-- 表格 --> <vxe-grid ref="xGridDom" v-bind="xGridOpt"> <!-- 左侧按钮列表 --> <template #toolbar-btns> <vxe-button status="primary" icon="vxe-icon-add" @click="crudStore.onShowModal()">新增用户</vxe-button> <vxe-button status="danger" icon="vxe-icon-delete">批量删除</vxe-button> </template> <!-- 操作 --> <template #row-operate="{ row }"> <el-button link type="primary" @click="crudStore.onShowModal(row)">修改</el-button> <el-button link type="danger" @click="crudStore.onDelete(row)">删除</el-button> </template> </vxe-grid> <!-- 弹窗 --> <vxe-modal ref="xModalDom" v-bind="xModalOpt"> <!-- 表单 --> <vxe-form ref="xFormDom" v-bind="xFormOpt" /> </vxe-modal> </div> </template>