Files
front/src/views/ops/pages/system-settings/account-management/index.vue
2026-03-08 22:41:42 +08:00

410 lines
9.4 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.
<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>