384 lines
9.8 KiB
Vue
384 lines
9.8 KiB
Vue
<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 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"
|
||
|
||
//#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: any) => {
|
||
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>
|