fix: 恢复Users.vue中的res.data.data正确嵌套结构

This commit is contained in:
chiguyong 2026-03-22 02:18:16 +08:00
parent fa344f9c4e
commit ea1eabafb0
1 changed files with 80 additions and 109 deletions

View File

@ -1,9 +1,21 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { Table, Button, Drawer, Input, Select, Form, Space, Popconfirm, message } from 'ant-design-vue'
import { PlusOutlined, SearchOutlined, ReloadOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
import { ref, onMounted, reactive } from 'vue'
import { Button, Drawer, Form, Space, message } from 'ant-design-vue'
import { PlusOutlined } from '@ant-design/icons-vue'
import { getUsers, createUser, updateUser, deleteUser } from '@/api/user'
import type { User } from '@/types'
import {
PageHeader,
FilterBar,
TableCard,
TableToolbar,
TableActions,
Pagination,
StatusTag,
StatusSelect,
PhoneItem,
EmailItem
} from '@/components'
//
const columns = [
@ -12,7 +24,7 @@ const columns = [
{ title: '手机', dataIndex: 'phone', key: 'phone', width: 120 },
{ title: '邮箱', dataIndex: 'email', key: 'email', ellipsis: true },
{ title: '状态', dataIndex: 'status', key: 'status', width: 80 },
{ title: '操作', key: 'action', width: 120, fixed: 'right' }
{ title: '操作', key: 'action', width: 120, fixed: 'right' as const }
]
//
@ -27,6 +39,13 @@ const submitting = ref(false)
const searchKeyword = ref('')
const searchStatus = ref('')
//
const pagination = reactive({
current: 1,
pageSize: 10,
total: 0
})
//
const formState = ref({
id: '',
@ -38,21 +57,13 @@ const formState = ref({
status: 'ACTIVE'
})
const statusOptions = [
{ value: 'ACTIVE', label: '正常', color: 'success' },
{ value: 'LOCKED', label: '锁定', color: 'warning' },
{ value: 'DISABLED', label: '禁用', color: 'error' }
]
//
const fetchUsers = async () => {
loading.value = true
try {
const params: any = {}
if (searchKeyword.value) params.keyword = searchKeyword.value
if (searchStatus.value) params.status = searchStatus.value
const res = await getUsers(params)
const res = await getUsers()
users.value = res.data.data || []
pagination.total = res.data.data?.length || 0
} catch {
message.error('获取用户列表失败')
} finally {
@ -62,6 +73,7 @@ const fetchUsers = async () => {
//
const handleSearch = () => {
pagination.current = 1
fetchUsers()
}
@ -69,6 +81,14 @@ const handleSearch = () => {
const handleReset = () => {
searchKeyword.value = ''
searchStatus.value = ''
pagination.current = 1
fetchUsers()
}
//
const handlePageChange = (page: number, pageSize: number) => {
pagination.current = page
pagination.pageSize = pageSize
fetchUsers()
}
@ -118,18 +138,18 @@ const handleSubmit = async () => {
try {
await formRef.value.validate()
submitting.value = true
const data = { ...formState.value }
if (!data.password) delete data.password
if (formState.value.id) {
await updateUser(formState.value.id, data)
const { id, ...data } = formState.value
if (!data.password) delete (data as any).password
if (id) {
await updateUser(id, data as Partial<User>)
message.success('更新成功')
} else {
await createUser(data)
await createUser(data as Partial<User>)
message.success('创建成功')
}
drawerVisible.value = false
fetchUsers()
} catch (error: any) {
@ -146,103 +166,60 @@ const handleClose = () => {
drawerVisible.value = false
}
//
const getStatusColor = (status: string) => {
const map: Record<string, string> = {
ACTIVE: 'success',
LOCKED: 'warning',
DISABLED: 'error'
}
return map[status] || 'default'
}
const getStatusLabel = (status: string) => {
const map: Record<string, string> = {
ACTIVE: '正常',
LOCKED: '锁定',
DISABLED: '禁用'
}
return map[status] || status
}
onMounted(fetchUsers)
</script>
<template>
<div class="page-container">
<!-- 页面标题 -->
<div class="page-header">
<h2 class="page-title">用户管理</h2>
<div class="page-header-actions">
<PageHeader title="用户管理">
<template #extra>
<Button type="primary" @click="handleAdd">
<PlusOutlined /> 新增用户
</Button>
</div>
</div>
</template>
</PageHeader>
<!-- 筛选区 -->
<div class="filter-bar">
<Space>
<Input
v-model:value="searchKeyword"
placeholder="搜索用户名/姓名/手机"
style="width: 240px"
@pressEnter="handleSearch"
>
<template #prefix>
<SearchOutlined />
</template>
</Input>
<Select
v-model:value="searchStatus"
placeholder="状态"
style="width: 120px"
:options="statusOptions"
allow-clear
/>
<Button type="primary" @click="handleSearch">查询</Button>
<Button @click="handleReset">
<ReloadOutlined /> 重置
</Button>
</Space>
</div>
<FilterBar @search="handleSearch" @reset="handleReset">
<a-input
v-model:value="searchKeyword"
placeholder="搜索用户名/姓名/手机"
style="width: 240px"
allow-clear
@pressEnter="handleSearch"
/>
<StatusSelect v-model="searchStatus" placeholder="全部状态" />
</FilterBar>
<!-- 表格 -->
<div class="table-card">
<Table
<TableCard>
<TableToolbar @refresh="fetchUsers" />
<a-table
:columns="columns"
:data-source="users"
:loading="loading"
:row-key="(record: User) => record.id"
:pagination="{ pageSize: 10, showSizeChanger: true, showTotal: (total: number) => `共 ${total} 条` }"
:pagination="false"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<a-tag :color="getStatusColor(record.status)">
{{ getStatusLabel(record.status) }}
</a-tag>
<StatusTag :status="record.status" />
</template>
<template v-else-if="column.key === 'action'">
<Space>
<Button type="link" size="small" @click="handleEdit(record)">
<EditOutlined /> 编辑
</Button>
<Popconfirm
title="确认删除"
description="删除后不可恢复,是否继续?"
ok-text="确认"
cancel-text="取消"
@confirm="handleDelete(record.id)"
>
<Button type="link" danger size="small">
<DeleteOutlined /> 删除
</Button>
</Popconfirm>
</Space>
<TableActions @edit="handleEdit(record)" @delete="handleDelete(record.id)" />
</template>
</template>
</Table>
</div>
</a-table>
<Pagination
v-model:current="pagination.current"
v-model:pageSize="pagination.pageSize"
:total="pagination.total"
@change="handlePageChange"
/>
</TableCard>
<!-- 抽屉 -->
<Drawer
@ -259,28 +236,22 @@ onMounted(fetchUsers)
:rules="{
username: [{ required: true, message: '请输入用户名' }],
password: [{ required: !formState.id, message: '请输入密码' }],
realName: [{ required: true, message: '请输入姓名' }],
phone: [{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式错误' }],
email: [{ type: 'email', message: '邮箱格式错误' }]
realName: [{ required: true, message: '请输入姓名' }]
}"
>
<Form.Item label="用户名" name="username">
<Input v-model:value="formState.username" :disabled="!!formState.id" placeholder="请输入用户名" />
<a-input v-model:value="formState.username" :disabled="!!formState.id" placeholder="请输入用户名" />
</Form.Item>
<Form.Item v-if="!formState.id" label="密码" name="password">
<Input.Password v-model:value="formState.password" placeholder="请输入密码" />
<a-input-password v-model:value="formState.password" placeholder="请输入密码" />
</Form.Item>
<Form.Item label="姓名" name="realName">
<Input v-model:value="formState.realName" placeholder="请输入姓名" />
</Form.Item>
<Form.Item label="手机" name="phone">
<Input v-model:value="formState.phone" placeholder="请输入手机号" />
</Form.Item>
<Form.Item label="邮箱" name="email">
<Input v-model:value="formState.email" placeholder="请输入邮箱" />
<a-input v-model:value="formState.realName" placeholder="请输入姓名" />
</Form.Item>
<PhoneItem v-model="formState.phone" />
<EmailItem v-model="formState.email" />
<Form.Item label="状态" name="status">
<Select v-model:value="formState.status" :options="statusOptions" />
<StatusSelect v-model="formState.status" />
</Form.Item>
</Form>
<template #footer>
@ -291,4 +262,4 @@ onMounted(fetchUsers)
</template>
</Drawer>
</div>
</template>
</template>