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