2022-10-25 17:29:28 +08:00
|
|
|
|
<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"
|
2022-10-25 17:29:28 +08:00
|
|
|
|
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
|
2022-10-25 17:29:28 +08:00
|
|
|
|
} 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"
|
|
|
|
|
})
|
|
|
|
|
|
2022-10-25 17:29:28 +08:00
|
|
|
|
//#region vxe-grid
|
2023-05-21 09:51:41 +08:00
|
|
|
|
interface RowMeta {
|
2022-10-25 17:29:28 +08:00
|
|
|
|
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 }) => {
|
2022-10-25 17:29:28 +08:00
|
|
|
|
xGridOpt.loading = true
|
|
|
|
|
crudStore.clearTable()
|
2023-06-20 09:13:47 +08:00
|
|
|
|
return new Promise((resolve) => {
|
2022-10-25 17:29:28 +08:00
|
|
|
|
let total = 0
|
2023-05-21 09:51:41 +08:00
|
|
|
|
let result: RowMeta[] = []
|
2022-10-25 17:29:28 +08:00
|
|
|
|
/** 加载数据 */
|
2024-07-22 11:40:25 +08:00
|
|
|
|
const callback = (res: TableResponseData) => {
|
2023-06-20 09:13:47 +08:00
|
|
|
|
if (res?.data) {
|
2022-10-25 17:29:28 +08:00
|
|
|
|
// 总数
|
2023-06-20 09:13:47 +08:00
|
|
|
|
total = res.data.total
|
|
|
|
|
// 列表数据
|
|
|
|
|
result = res.data.list
|
2022-10-25 17:29:28 +08:00
|
|
|
|
}
|
|
|
|
|
xGridOpt.loading = false
|
2023-06-20 09:13:47 +08:00
|
|
|
|
// 返回值有格式要求,详情见 vxe-table 官方文档
|
2022-10-25 17:29:28 +08:00
|
|
|
|
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({
|
2022-10-25 17:29:28 +08:00
|
|
|
|
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("空格无效")
|
2022-10-25 17:29:28 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
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("空格无效")
|
2022-10-25 17:29:28 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
//#endregion
|
|
|
|
|
|
2023-06-20 09:13:47 +08:00
|
|
|
|
//#region 增删改查
|
2022-10-25 17:29:28 +08:00
|
|
|
|
const crudStore = reactive({
|
2023-06-20 09:13:47 +08:00
|
|
|
|
/** 表单类型,true 表示修改,false 表示新增 */
|
2022-10-25 17:29:28 +08:00
|
|
|
|
isUpdate: true,
|
|
|
|
|
/** 加载表格数据 */
|
|
|
|
|
commitQuery: () => xGridDom.value?.commitProxy("query"),
|
|
|
|
|
/** 清空表格数据 */
|
|
|
|
|
clearTable: () => xGridDom.value?.reloadData([]),
|
|
|
|
|
/** 点击显示弹窗 */
|
2023-05-21 09:51:41 +08:00
|
|
|
|
onShowModal: (row?: RowMeta) => {
|
2022-10-25 17:29:28 +08:00
|
|
|
|
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)
|
2022-10-25 17:29:28 +08:00
|
|
|
|
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) => {
|
2022-10-25 17:29:28 +08:00
|
|
|
|
if (errMap) return
|
|
|
|
|
xFormOpt.loading = true
|
2023-06-20 09:13:47 +08:00
|
|
|
|
const callback = () => {
|
2022-10-25 17:29:28 +08:00
|
|
|
|
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
|
|
|
|
// 模拟调用修改接口成功
|
2022-10-25 17:29:28 +08:00
|
|
|
|
setTimeout(() => callback(), 1000)
|
|
|
|
|
} else {
|
2023-06-20 09:13:47 +08:00
|
|
|
|
// 模拟调用新增接口成功
|
2022-10-25 17:29:28 +08:00
|
|
|
|
setTimeout(() => callback(), 1000)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
/** 新增后是否跳入最后一页 */
|
|
|
|
|
afterInsert: () => {
|
2023-06-20 09:13:47 +08:00
|
|
|
|
const pager = xGridDom.value?.getProxyInfo()?.pager
|
2022-10-25 17:29:28 +08:00
|
|
|
|
if (pager) {
|
2023-06-20 09:13:47 +08:00
|
|
|
|
const currentTotal = pager.currentPage * pager.pageSize
|
|
|
|
|
if (currentTotal === pager.total) {
|
2022-10-25 17:29:28 +08:00
|
|
|
|
++pager.currentPage
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
/** 删除 */
|
2023-05-21 09:51:41 +08:00
|
|
|
|
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> ?`
|
2022-10-25 17:29:28 +08:00
|
|
|
|
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()
|
2022-10-25 17:29:28 +08:00
|
|
|
|
})
|
2023-06-20 09:13:47 +08:00
|
|
|
|
})
|
2022-10-25 17:29:28 +08:00
|
|
|
|
},
|
|
|
|
|
/** 删除后是否返回上一页 */
|
|
|
|
|
afterDelete: () => {
|
2023-05-21 09:51:41 +08:00
|
|
|
|
const tableData: RowMeta[] = xGridDom.value!.getData()
|
2023-06-20 09:13:47 +08:00
|
|
|
|
const pager = xGridDom.value?.getProxyInfo()?.pager
|
2022-10-25 17:29:28 +08:00
|
|
|
|
if (pager && pager.currentPage > 1 && tableData.length === 1) {
|
|
|
|
|
--pager.currentPage
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
/** 更多自定义方法 */
|
2023-06-20 09:13:47 +08:00
|
|
|
|
moreFn: () => {}
|
2022-10-25 17:29:28 +08:00
|
|
|
|
})
|
|
|
|
|
//#endregion
|
|
|
|
|
</script>
|
2022-10-20 20:58:57 +08:00
|
|
|
|
|
|
|
|
|
<template>
|
2022-10-25 17:29:28 +08:00
|
|
|
|
<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>
|
2022-10-25 17:29:28 +08:00
|
|
|
|
<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>
|