410 lines
9.4 KiB
Vue
410 lines
9.4 KiB
Vue
<template>
|
||
<div class="container">
|
||
<Breadcrumb :items="['用户管理']" />
|
||
|
||
<SearchTable
|
||
title="用户管理"
|
||
:form-model="searchForm"
|
||
:form-items="formItems"
|
||
:data="tableData"
|
||
:columns="columns"
|
||
:loading="loading"
|
||
:pagination="pagination"
|
||
@search="handleSearch"
|
||
@reset="handleReset"
|
||
@page-change="handlePageChange"
|
||
@refresh="fetchData"
|
||
>
|
||
<!-- 工具栏左侧 - 新增按钮 -->
|
||
<template #toolbar-left>
|
||
<a-button type="primary" @click="handleAdd">
|
||
<template #icon><icon-plus /></template>
|
||
新增用户
|
||
</a-button>
|
||
</template>
|
||
|
||
<!-- 操作列 -->
|
||
<template #operation="{ record }">
|
||
<a-space>
|
||
<a-button type="text" size="small" @click="handleEdit(record)">
|
||
编辑
|
||
</a-button>
|
||
<a-button type="text" size="small" @click="handleSetPermission(record)">
|
||
权限
|
||
</a-button>
|
||
<a-button type="text" size="small" @click="handleChangePassword(record)">
|
||
改密
|
||
</a-button>
|
||
<a-button type="text" size="small" status="danger" @click="handleDelete(record)">
|
||
删除
|
||
</a-button>
|
||
</a-space>
|
||
</template>
|
||
|
||
<!-- 状态列 -->
|
||
<template #status="{ record }">
|
||
<a-tag :color="record.status === 1 ? 'green' : 'red'">
|
||
{{ record.status === 1 ? '启用' : '禁用' }}
|
||
</a-tag>
|
||
</template>
|
||
</SearchTable>
|
||
|
||
<!-- 新增/编辑用户弹窗 -->
|
||
<a-modal
|
||
v-model:visible="modalVisible"
|
||
:title="modalTitle"
|
||
:mask-closable="false"
|
||
:width="520"
|
||
@ok="handleModalOk"
|
||
@cancel="handleModalCancel"
|
||
>
|
||
<a-form
|
||
ref="formRef"
|
||
:model="formData"
|
||
:rules="formRules"
|
||
:label-col-props="{ span: 6 }"
|
||
:wrapper-col-props="{ span: 16 }"
|
||
>
|
||
<a-form-item field="account" label="账号" validate-trigger="blur">
|
||
<a-input
|
||
v-model="formData.account"
|
||
placeholder="请输入账号"
|
||
:disabled="isEdit"
|
||
/>
|
||
</a-form-item>
|
||
<a-form-item field="name" label="姓名" validate-trigger="blur">
|
||
<a-input v-model="formData.name" placeholder="请输入姓名" />
|
||
</a-form-item>
|
||
<a-form-item field="email" label="邮箱" validate-trigger="blur">
|
||
<a-input v-model="formData.email" placeholder="请输入邮箱" />
|
||
</a-form-item>
|
||
<a-form-item field="phone" label="手机号" validate-trigger="blur">
|
||
<a-input v-model="formData.phone" placeholder="请输入手机号" />
|
||
</a-form-item>
|
||
<a-form-item field="status" label="状态">
|
||
<a-select v-model="formData.status" placeholder="请选择状态">
|
||
<a-option :value="1">正常</a-option>
|
||
<a-option :value="-1">禁用</a-option>
|
||
</a-select>
|
||
</a-form-item>
|
||
</a-form>
|
||
</a-modal>
|
||
|
||
<!-- 删除确认对话框 -->
|
||
<a-modal
|
||
v-model:visible="deleteConfirmVisible"
|
||
title="删除确认"
|
||
@ok="handleConfirmDelete"
|
||
@cancel="deleteConfirmVisible = false"
|
||
>
|
||
<p>确定要删除用户 "{{ userToDelete?.name || userToDelete?.account }}" 吗?</p>
|
||
</a-modal>
|
||
|
||
<!-- 修改密码弹窗 -->
|
||
<PasswordChangeDialog
|
||
:user="passwordChangeUser"
|
||
@update:visible="passwordChangeUser = null"
|
||
@success="fetchData"
|
||
/>
|
||
|
||
<!-- 权限设置弹窗 -->
|
||
<PermissionSettingDialog
|
||
:user="permissionUser"
|
||
@update:visible="handlePermissionDialogClose"
|
||
@success="fetchData"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { ref, reactive, computed, onMounted } from 'vue'
|
||
import { Message } from '@arco-design/web-vue'
|
||
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'
|
||
import SearchTable from '@/components/search-table/index.vue'
|
||
import type { FormItem } from '@/components/search-form/types'
|
||
import type { UserItem } from '@/api/types'
|
||
import {
|
||
fetchUserList,
|
||
createUser,
|
||
modifyUser,
|
||
deleteUser,
|
||
} from '@/api/module/user'
|
||
import PasswordChangeDialog from './components/PasswordChangeDialog.vue'
|
||
import PermissionSettingDialog from './components/PermissionSettingDialog.vue'
|
||
|
||
// 搜索表单配置
|
||
const formItems: FormItem[] = [
|
||
{
|
||
field: 'keyword',
|
||
label: '关键词',
|
||
type: 'input',
|
||
placeholder: '请输入用户名/昵称/手机号',
|
||
span: 8,
|
||
},
|
||
]
|
||
|
||
// 表格列配置
|
||
const columns: TableColumnData[] = [
|
||
{
|
||
title: 'ID',
|
||
dataIndex: 'id',
|
||
width: 80,
|
||
},
|
||
{
|
||
title: '账号',
|
||
dataIndex: 'account',
|
||
width: 120,
|
||
},
|
||
{
|
||
title: '姓名',
|
||
dataIndex: 'name',
|
||
width: 120,
|
||
},
|
||
{
|
||
title: '邮箱',
|
||
dataIndex: 'email',
|
||
width: 180,
|
||
},
|
||
{
|
||
title: '手机号',
|
||
dataIndex: 'phone',
|
||
width: 140,
|
||
},
|
||
{
|
||
title: '状态',
|
||
dataIndex: 'status',
|
||
slotName: 'status',
|
||
width: 100,
|
||
},
|
||
{
|
||
title: '创建时间',
|
||
dataIndex: 'created_at',
|
||
width: 180,
|
||
},
|
||
{
|
||
title: '操作',
|
||
slotName: 'operation',
|
||
width: 150,
|
||
fixed: 'right',
|
||
},
|
||
]
|
||
|
||
// 搜索表单数据
|
||
const searchForm = reactive({
|
||
keyword: '',
|
||
})
|
||
|
||
// 分页配置
|
||
const pagination = reactive({
|
||
current: 1,
|
||
pageSize: 20,
|
||
total: 0,
|
||
})
|
||
|
||
// 表格数据
|
||
const tableData = ref<UserItem[]>([])
|
||
const loading = ref(false)
|
||
|
||
// 弹窗相关
|
||
const modalVisible = ref(false)
|
||
const isEdit = ref(false)
|
||
const formRef = ref()
|
||
const formData = reactive<UserItem>({
|
||
id: undefined,
|
||
account: '',
|
||
name: '',
|
||
email: '',
|
||
phone: '',
|
||
status: 1,
|
||
})
|
||
|
||
// 表单验证规则
|
||
const formRules = {
|
||
account: [
|
||
{ required: true, message: '请输入账号' },
|
||
{ minLength: 3, message: '账号至少3个字符' },
|
||
],
|
||
name: [
|
||
{ required: true, message: '请输入姓名' },
|
||
],
|
||
email: [
|
||
{ match: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, message: '请输入正确的邮箱格式' },
|
||
],
|
||
phone: [
|
||
{ match: /^1[3-9]\d{9}$/, message: '请输入正确的手机号' },
|
||
],
|
||
}
|
||
|
||
// 删除确认
|
||
const deleteConfirmVisible = ref(false)
|
||
const userToDelete = ref<UserItem | null>(null)
|
||
|
||
// 修改密码
|
||
const passwordChangeUser = ref<UserItem | null>(null)
|
||
|
||
// 权限设置
|
||
const permissionUser = ref<UserItem | null>(null)
|
||
|
||
// 关闭权限设置弹窗
|
||
const handlePermissionDialogClose = (visible: boolean) => {
|
||
if (!visible) {
|
||
permissionUser.value = null
|
||
}
|
||
}
|
||
|
||
// 弹窗标题
|
||
const modalTitle = computed(() => (isEdit.value ? '编辑用户' : '新增用户'))
|
||
|
||
// 获取数据
|
||
const fetchData = async () => {
|
||
try {
|
||
loading.value = true
|
||
const res = await fetchUserList({
|
||
page: pagination.current,
|
||
size: pagination.pageSize,
|
||
keyword: searchForm.keyword || undefined,
|
||
})
|
||
if (res?.code === 0) {
|
||
tableData.value = res.details?.data || []
|
||
pagination.total = res.details?.total || 0
|
||
}
|
||
} catch (error) {
|
||
console.error('Failed to fetch user list:', error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 搜索
|
||
const handleSearch = () => {
|
||
pagination.current = 1
|
||
fetchData()
|
||
}
|
||
|
||
// 重置
|
||
const handleReset = () => {
|
||
searchForm.keyword = ''
|
||
pagination.current = 1
|
||
fetchData()
|
||
}
|
||
|
||
// 分页变化
|
||
const handlePageChange = (current: number) => {
|
||
pagination.current = current
|
||
fetchData()
|
||
}
|
||
|
||
// 新增用户
|
||
const handleAdd = () => {
|
||
isEdit.value = false
|
||
resetFormData()
|
||
modalVisible.value = true
|
||
}
|
||
|
||
// 编辑用户
|
||
const handleEdit = (record: UserItem) => {
|
||
isEdit.value = true
|
||
Object.assign(formData, {
|
||
id: record.id,
|
||
account: record.account,
|
||
name: record.name,
|
||
email: record.email,
|
||
phone: record.phone,
|
||
status: record.status ?? 1,
|
||
})
|
||
modalVisible.value = true
|
||
}
|
||
|
||
// 删除用户
|
||
const handleDelete = (record: UserItem) => {
|
||
userToDelete.value = record
|
||
deleteConfirmVisible.value = true
|
||
}
|
||
|
||
// 修改密码
|
||
const handleChangePassword = (record: UserItem) => {
|
||
passwordChangeUser.value = record
|
||
}
|
||
|
||
// 权限设置
|
||
const handleSetPermission = (record: UserItem) => {
|
||
permissionUser.value = record
|
||
}
|
||
|
||
// 确认删除
|
||
const handleConfirmDelete = async () => {
|
||
if (!userToDelete.value?.id) return
|
||
|
||
try {
|
||
loading.value = true
|
||
await deleteUser({ id: userToDelete.value.id })
|
||
Message.success('删除成功')
|
||
deleteConfirmVisible.value = false
|
||
userToDelete.value = null
|
||
await fetchData()
|
||
} catch (error) {
|
||
console.error('Failed to delete user:', error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 弹窗确认
|
||
const handleModalOk = async () => {
|
||
try {
|
||
const valid = await formRef.value?.validate()
|
||
if (valid) return
|
||
|
||
loading.value = true
|
||
if (isEdit.value && formData.id) {
|
||
await modifyUser(formData)
|
||
Message.success('修改成功')
|
||
} else {
|
||
await createUser(formData)
|
||
Message.success('创建成功')
|
||
}
|
||
modalVisible.value = false
|
||
await fetchData()
|
||
} catch (error) {
|
||
console.error('Failed to save user:', error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 弹窗取消
|
||
const handleModalCancel = () => {
|
||
modalVisible.value = false
|
||
formRef.value?.resetFields()
|
||
}
|
||
|
||
// 重置表单数据
|
||
const resetFormData = () => {
|
||
Object.assign(formData, {
|
||
id: undefined,
|
||
account: '',
|
||
name: '',
|
||
email: '',
|
||
phone: '',
|
||
status: 1,
|
||
})
|
||
}
|
||
|
||
// 初始化
|
||
onMounted(() => {
|
||
fetchData()
|
||
})
|
||
</script>
|
||
|
||
<script lang="ts">
|
||
export default {
|
||
name: 'AccountManagement',
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.container {
|
||
padding: 0 20px 20px 20px;
|
||
}
|
||
</style>
|