liym 52a5cb8dc6
chore: fix typo (#222)
Co-authored-by: pany <939630029@qq.com>
2024-12-03 14:27:23 +08:00

375 lines
9.5 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.

<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 TableResponseData } from "@/api/table/types/table"
import RoleColumnSlots from "./tsx/RoleColumnSlots"
import StatusColumnSlots from "./tsx/StatusColumnSlots"
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: RoleColumnSlots
},
{
field: "phone",
title: "手机号"
},
{
field: "email",
title: "邮箱"
},
{
field: "status",
title: "状态",
slots: StatusColumnSlots
},
{
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: TableResponseData) => {
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: 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
}
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>