374 lines
9.5 KiB
Vue
Raw Normal View History

<script lang="ts" setup>
import { nextTick, reactive, ref } from "vue"
import { type ElMessageBoxOptions, ElMessageBox, ElMessage } from "element-plus"
import { deleteTableDataApi, getTableDataApi } from "@/api/table"
2024-07-22 11:40:25 +08:00
import { type TableResponseData } 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,
2023-06-20 09:13:47 +08:00
type VxeFormProps
} from "vxe-table"
2023-02-22 15:53:04 +08:00
defineOptions({
2023-06-20 09:13:47 +08:00
// 命名当前组件
2023-02-22 15:53:04 +08:00
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: {
2023-06-20 09:13:47 +08:00
query: ({ page, form }) => {
xGridOpt.loading = true
crudStore.clearTable()
2023-06-20 09:13:47 +08:00
return new Promise((resolve) => {
let total = 0
let result: RowMeta[] = []
/** 加载数据 */
2024-07-22 11:40:25 +08:00
const callback = (res: TableResponseData) => {
2023-06-20 09:13:47 +08:00
if (res?.data) {
// 总数
2023-06-20 09:13:47 +08:00
total = res.data.total
// 列表数据
result = res.data.list
}
xGridOpt.loading = false
2023-06-20 09:13:47 +08:00
// 返回值有格式要求,详情见 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>()
2023-06-20 09:13:47 +08:00
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 }) => {
2023-06-20 09:13:47 +08:00
switch (true) {
case !itemValue:
return new Error("请输入")
case !itemValue.trim():
return new Error("空格无效")
}
}
}
],
password: [
{
required: true,
validator: ({ itemValue }) => {
2023-06-20 09:13:47 +08:00
switch (true) {
case !itemValue:
return new Error("请输入")
case !itemValue.trim():
return new Error("空格无效")
}
}
}
]
}
})
//#endregion
2023-06-20 09:13:47 +08:00
//#region 增删改查
const crudStore = reactive({
2023-06-20 09:13:47 +08:00
/** 表单类型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 = "新增用户"
}
// 禁用表单项
2023-06-20 09:13:47 +08:00
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
2023-06-20 09:13:47 +08:00
xFormDom.value?.validate((errMap) => {
if (errMap) return
xFormOpt.loading = true
2023-06-20 09:13:47 +08:00
const callback = () => {
xFormOpt.loading = false
xModalDom.value?.close()
ElMessage.success("操作成功")
!crudStore.isUpdate && crudStore.afterInsert()
crudStore.commitQuery()
}
if (crudStore.isUpdate) {
2023-06-20 09:13:47 +08:00
// 模拟调用修改接口成功
setTimeout(() => callback(), 1000)
} else {
2023-06-20 09:13:47 +08:00
// 模拟调用新增接口成功
setTimeout(() => callback(), 1000)
}
})
},
/** 新增后是否跳入最后一页 */
afterInsert: () => {
2023-06-20 09:13:47 +08:00
const pager = xGridDom.value?.getProxyInfo()?.pager
if (pager) {
2023-06-20 09:13:47 +08:00
const currentTotal = pager.currentPage * pager.pageSize
if (currentTotal === pager.total) {
++pager.currentPage
}
}
},
/** 删除 */
onDelete: (row: RowMeta) => {
2024-03-28 21:34:24 +08:00
const tip = `确定 <strong style="color: var(--el-color-danger);"> 删除 </strong> 用户 <strong style="color: var(--el-color-primary);"> ${row.username} </strong> `
const config: ElMessageBoxOptions = {
type: "warning",
showClose: true,
closeOnClickModal: true,
closeOnPressEscape: true,
cancelButtonText: "取消",
confirmButtonText: "确定",
dangerouslyUseHTMLString: true
}
2023-06-20 09:13:47 +08:00
ElMessageBox.confirm(tip, "提示", config).then(() => {
deleteTableDataApi(row.id).then(() => {
ElMessage.success("删除成功")
crudStore.afterDelete()
crudStore.commitQuery()
})
2023-06-20 09:13:47 +08:00
})
},
/** 删除后是否返回上一页 */
afterDelete: () => {
const tableData: RowMeta[] = xGridDom.value!.getData()
2023-06-20 09:13:47 +08:00
const pager = xGridDom.value?.getProxyInfo()?.pager
if (pager && pager.currentPage > 1 && tableData.length === 1) {
--pager.currentPage
}
},
/** 更多自定义方法 */
2023-06-20 09:13:47 +08:00
moreFn: () => {}
})
//#endregion
</script>
2022-10-20 20:58:57 +08:00
<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 }">
2022-10-27 18:20:57 +08:00
<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>
2022-10-20 20:58:57 +08:00
</template>