<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, type VxeGridPropTypes, type VxeFormDefines } from "vxe-table" defineOptions({ name: "VxeTable" }) //#region vxe-grid interface IRowMeta { 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 }: VxeGridPropTypes.ProxyAjaxQueryParams) => { xGridOpt.loading = true crudStore.clearTable() return new Promise<any>((resolve: Function) => { let total = 0 let result: IRowMeta[] = [] /** 加载数据 */ const callback = (res: GetTableResponseData) => { if (res && res.data) { const resData = res.data // 总数 if (Number.isInteger(resData.total)) { total = resData.total } // 分页数据 if (Array.isArray(resData.list)) { result = resData.list } } xGridOpt.loading = false 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 = reactive<VxeFormProps>({ 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 }) => { if (!itemValue) { return new Error("请输入") } if (!itemValue.trim()) { return new Error("空格无效") } } } ], password: [ { required: true, validator: ({ itemValue }) => { if (!itemValue) { return new Error("请输入") } if (!itemValue.trim()) { return new Error("空格无效") } } } ] } }) //#endregion //#region CRUD const crudStore = reactive({ /** 表单类型:修改:true 新增:false */ isUpdate: true, /** 加载表格数据 */ commitQuery: () => xGridDom.value?.commitProxy("query"), /** 清空表格数据 */ clearTable: () => xGridDom.value?.reloadData([]), /** 点击显示弹窗 */ onShowModal: (row?: IRowMeta) => { if (row) { crudStore.isUpdate = true xModalOpt.title = "修改用户" // 赋值 xFormOpt.data.username = row.username } else { crudStore.isUpdate = false xModalOpt.title = "新增用户" } // 禁用表单项 if (xFormOpt.items) { if (xFormOpt.items[0]?.itemRender?.props) { xFormOpt.items[0].itemRender.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?: VxeFormDefines.ValidateErrorMapParams) => { if (errMap) return xFormOpt.loading = true const callback = (err?: any) => { xFormOpt.loading = false if (err) return xModalDom.value?.close() ElMessage.success("操作成功") !crudStore.isUpdate && crudStore.afterInsert() crudStore.commitQuery() } if (crudStore.isUpdate) { // 调用修改接口 setTimeout(() => callback(), 1000) } else { // 调用新增接口 setTimeout(() => callback(), 1000) } }) }, /** 新增后是否跳入最后一页 */ afterInsert: () => { const pager: VxeGridPropTypes.ProxyAjaxQueryPageParams = xGridDom.value?.getProxyInfo()?.pager if (pager) { const currTotal: number = pager.currentPage * pager.pageSize if (currTotal === pager.total) { ++pager.currentPage } } }, /** 删除 */ onDelete: (row: IRowMeta) => { 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() }) .catch(() => 1) }) .catch(() => 1) }, /** 删除后是否返回上一页 */ afterDelete: () => { const tableData: IRowMeta[] = xGridDom.value!.getData() const pager: VxeGridPropTypes.ProxyAjaxQueryPageParams = xGridDom.value?.getProxyInfo()?.pager if (pager && pager.currentPage > 1 && tableData.length === 1) { --pager.currentPage } }, /** 更多自定义方法 */ moreFunc: () => {} }) //#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> <style lang="scss" scoped></style>