重构认证系统和订单支付功能,新增邮箱验证、密码重置及支付流程

This commit is contained in:
2025-09-22 15:28:18 +08:00
parent 6876683d80
commit 98f81840f2
27 changed files with 2804 additions and 2249 deletions

View File

@@ -5,6 +5,9 @@ NODE_ENV=development
VITE_API_BASE_URL=http://localhost:3200/api/v1
VITE_API_TIMEOUT=30000
# 使用模拟数据(开发环境)
VITE_USE_MOCK=false
# 功能开关
VITE_FEATURE_ANALYTICS=true
VITE_FEATURE_DEBUG=true

View File

@@ -233,6 +233,7 @@ export { default as animalAPI } from './animal'
export { default as orderAPI } from './order'
export { default as promotionAPI } from './promotion'
export { default as systemAPI } from './system'
export { default as dashboardAPI } from './dashboard'
// 重新导出特定类型以避免冲突
export type { ApiResponse } from './user'

View File

@@ -1,29 +1,36 @@
import { request } from '.'
import { mockMerchantAPI } from './mockData'
import { createMockWrapper } from '@/config/mock'
// 定义商家相关类型
export interface Merchant {
id: number
business_name: string
business_license: string
legal_representative: string
name: string
business_name?: string
business_license?: string
legal_representative?: string
contact_person: string
contact_phone: string
contact_email: string
address: string
business_scope: string
contact_email?: string
address?: string
business_scope?: string
type: string
status: string
remark: string
remark?: string
description?: string
created_at: string
updated_at: string
updated_at?: string
}
export interface MerchantQueryParams {
page?: number
limit?: number
keyword?: string
business_name?: string
contact_person?: string
contact_phone?: string
status?: string
type?: string
start_date?: string
end_date?: string
}
@@ -94,7 +101,8 @@ export const disableMerchant = (id: number) =>
export const enableMerchant = (id: number) =>
request.put<{ success: boolean; code: number; message: string }>(`/merchants/${id}/enable`)
export default {
// 使用 mock 包装器
const merchantAPI = createMockWrapper({
getMerchants,
getMerchant,
createMerchant,
@@ -105,4 +113,6 @@ export default {
rejectMerchant,
disableMerchant,
enableMerchant
}
}, mockMerchantAPI)
export default merchantAPI

View File

@@ -6,15 +6,119 @@ const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
// 模拟用户数据
const mockUsers = [
{ id: 1, username: 'admin', nickname: '系统管理员', role: 'admin', status: 'active', createdAt: '2024-01-01' },
{ id: 2, username: 'user1', nickname: '旅行爱好者', role: 'user', status: 'active', createdAt: '2024-01-02' },
{ id: 3, username: 'merchant1', nickname: '花店老板', role: 'merchant', status: 'active', createdAt: '2024-01-03' }
{
id: 1,
username: 'admin',
nickname: '系统管理员',
email: 'admin@example.com',
phone: '13800138001',
avatar: 'https://api.dicebear.com/7.x/miniavs/svg?seed=admin',
userType: 'admin',
status: 'active',
registerTime: '2024-01-01',
lastLoginTime: '2024-03-15 14:30:22',
createdAt: '2024-01-01'
},
{
id: 2,
username: 'user1',
nickname: '旅行爱好者',
email: 'user1@example.com',
phone: '13800138002',
avatar: 'https://api.dicebear.com/7.x/miniavs/svg?seed=user1',
userType: 'normal',
status: 'active',
registerTime: '2024-01-02',
lastLoginTime: '2024-03-15 10:20:15',
createdAt: '2024-01-02'
},
{
id: 3,
username: 'merchant1',
nickname: '花店老板',
email: 'merchant1@example.com',
phone: '13800138003',
avatar: 'https://api.dicebear.com/7.x/miniavs/svg?seed=merchant1',
userType: 'merchant',
status: 'active',
registerTime: '2024-01-03',
lastLoginTime: '2024-03-15 09:45:30',
createdAt: '2024-01-03'
},
{
id: 4,
username: 'user2',
nickname: '探险家',
email: 'user2@example.com',
phone: '13800138004',
avatar: 'https://api.dicebear.com/7.x/miniavs/svg?seed=user2',
userType: 'normal',
status: 'inactive',
registerTime: '2024-01-04',
lastLoginTime: '2024-03-10 16:20:10',
createdAt: '2024-01-04'
},
{
id: 5,
username: 'user3',
nickname: '动物之友',
email: 'user3@example.com',
phone: '13800138005',
avatar: 'https://api.dicebear.com/7.x/miniavs/svg?seed=user3',
userType: 'normal',
status: 'banned',
registerTime: '2024-01-05',
lastLoginTime: '2024-03-05 12:30:45',
createdAt: '2024-01-05'
}
]
// 模拟商家数据
const mockMerchants = [
{ id: 1, name: '鲜花坊', type: 'flower', status: 'approved', contact: '13800138001', createdAt: '2024-01-05' },
{ id: 2, name: '快乐农场', type: 'farm', status: 'approved', contact: '13800138002', createdAt: '2024-01-06' }
{
id: 1,
name: '鲜花坊',
type: 'shop',
status: 'approved',
contact_person: '张三',
contact_phone: '13800138001',
address: '北京市朝阳区花卉市场1号',
description: '专业经营各类鲜花,提供花束定制服务',
created_at: '2024-01-05'
},
{
id: 2,
name: '快乐农场',
type: 'farm',
status: 'approved',
contact_person: '李四',
contact_phone: '13800138002',
address: '河北省承德市农业园区2号',
description: '生态农场,提供动物认领和农产品销售',
created_at: '2024-01-06'
},
{
id: 3,
name: '山水酒店',
type: 'hotel',
status: 'pending',
contact_person: '王五',
contact_phone: '13800138003',
address: '云南省大理市洱海边1号',
description: '精品民宿,提供旅行住宿服务',
created_at: '2024-01-07'
},
{
id: 4,
name: '美食餐厅',
type: 'restaurant',
status: 'rejected',
contact_person: '赵六',
contact_phone: '13800138004',
address: '四川省成都市春熙路88号',
description: '川菜餐厅,提供地道川菜',
created_at: '2024-01-08'
}
]
// 模拟旅行数据
@@ -124,7 +228,7 @@ export const mockUserAPI = {
return createPaginatedResponse(paginatedData, page, pageSize, mockUsers.length)
},
getUserById: async (id: number) => {
getUser: async (id: number) => {
await delay(500)
const user = mockUsers.find(u => u.id === id)
if (user) {
@@ -132,6 +236,88 @@ export const mockUserAPI = {
}
message.error('用户不存在')
throw new Error('用户不存在')
},
createUser: async (data: any) => {
await delay(500)
const newUser = {
id: mockUsers.length + 1,
...data,
createdAt: new Date().toISOString().split('T')[0],
updatedAt: new Date().toISOString().split('T')[0]
}
mockUsers.push(newUser)
return createSuccessResponse(newUser)
},
updateUser: async (id: number, data: any) => {
await delay(500)
const index = mockUsers.findIndex(u => u.id === id)
if (index !== -1) {
mockUsers[index] = {
...mockUsers[index],
...data,
updatedAt: new Date().toISOString().split('T')[0]
}
return createSuccessResponse(mockUsers[index])
}
message.error('用户不存在')
throw new Error('用户不存在')
},
deleteUser: async (id: number) => {
await delay(500)
const index = mockUsers.findIndex(u => u.id === id)
if (index !== -1) {
mockUsers.splice(index, 1)
return createSuccessResponse(null)
}
message.error('用户不存在')
throw new Error('用户不存在')
},
enableUser: async (id: number) => {
await delay(500)
const index = mockUsers.findIndex(u => u.id === id)
if (index !== -1) {
mockUsers[index].status = 'active'
return createSuccessResponse(mockUsers[index])
}
message.error('用户不存在')
throw new Error('用户不存在')
},
disableUser: async (id: number) => {
await delay(500)
const index = mockUsers.findIndex(u => u.id === id)
if (index !== -1) {
mockUsers[index].status = 'inactive'
return createSuccessResponse(mockUsers[index])
}
message.error('用户不存在')
throw new Error('用户不存在')
},
banUser: async (id: number) => {
await delay(500)
const index = mockUsers.findIndex(u => u.id === id)
if (index !== -1) {
mockUsers[index].status = 'banned'
return createSuccessResponse(mockUsers[index])
}
message.error('用户不存在')
throw new Error('用户不存在')
},
unbanUser: async (id: number) => {
await delay(500)
const index = mockUsers.findIndex(u => u.id === id)
if (index !== -1) {
mockUsers[index].status = 'active'
return createSuccessResponse(mockUsers[index])
}
message.error('用户不存在')
throw new Error('用户不存在')
}
}
@@ -139,12 +325,120 @@ export const mockUserAPI = {
export const mockMerchantAPI = {
getMerchants: async (params: any = {}) => {
await delay(800)
const { page = 1, limit = 10 } = params
const { page = 1, limit = 10, keyword = '', status = '', type = '' } = params
// 根据查询参数过滤商家
let filteredMerchants = mockMerchants
if (keyword) {
filteredMerchants = mockMerchants.filter(m =>
m.name.includes(keyword) ||
m.contact_person.includes(keyword)
)
}
if (status) {
filteredMerchants = filteredMerchants.filter(m => m.status === status)
}
if (type) {
filteredMerchants = filteredMerchants.filter(m => m.type === type)
}
const start = (page - 1) * limit
const end = start + limit
const paginatedData = mockMerchants.slice(start, end)
const paginatedData = filteredMerchants.slice(start, end)
return createPaginatedResponse(paginatedData, page, limit, mockMerchants.length)
return createPaginatedResponse(paginatedData, page, limit, filteredMerchants.length)
},
getMerchant: async (id: number) => {
await delay(500)
const merchant = mockMerchants.find(m => m.id === id)
if (merchant) {
return createSuccessResponse(merchant)
}
message.error('商家不存在')
throw new Error('商家不存在')
},
createMerchant: async (data: any) => {
await delay(500)
const newMerchant = {
id: mockMerchants.length + 1,
...data,
created_at: new Date().toISOString().split('T')[0],
updated_at: new Date().toISOString().split('T')[0]
}
mockMerchants.push(newMerchant)
return createSuccessResponse(newMerchant)
},
updateMerchant: async (id: number, data: any) => {
await delay(500)
const index = mockMerchants.findIndex(m => m.id === id)
if (index !== -1) {
mockMerchants[index] = {
...mockMerchants[index],
...data,
updated_at: new Date().toISOString().split('T')[0]
}
return createSuccessResponse(mockMerchants[index])
}
message.error('商家不存在')
throw new Error('商家不存在')
},
deleteMerchant: async (id: number) => {
await delay(500)
const index = mockMerchants.findIndex(m => m.id === id)
if (index !== -1) {
mockMerchants.splice(index, 1)
return createSuccessResponse(null)
}
message.error('商家不存在')
throw new Error('商家不存在')
},
approveMerchant: async (id: number) => {
await delay(500)
const index = mockMerchants.findIndex(m => m.id === id)
if (index !== -1) {
mockMerchants[index].status = 'approved'
return createSuccessResponse(mockMerchants[index])
}
message.error('商家不存在')
throw new Error('商家不存在')
},
rejectMerchant: async (id: number) => {
await delay(500)
const index = mockMerchants.findIndex(m => m.id === id)
if (index !== -1) {
mockMerchants[index].status = 'rejected'
return createSuccessResponse(mockMerchants[index])
}
message.error('商家不存在')
throw new Error('商家不存在')
},
disableMerchant: async (id: number) => {
await delay(500)
const index = mockMerchants.findIndex(m => m.id === id)
if (index !== -1) {
mockMerchants[index].status = 'disabled'
return createSuccessResponse(mockMerchants[index])
}
message.error('商家不存在')
throw new Error('商家不存在')
},
enableMerchant: async (id: number) => {
await delay(500)
const index = mockMerchants.findIndex(m => m.id === id)
if (index !== -1) {
mockMerchants[index].status = 'approved'
return createSuccessResponse(mockMerchants[index])
}
message.error('商家不存在')
throw new Error('商家不存在')
}
}

View File

@@ -67,7 +67,7 @@ export interface ApiResponse<T> {
// 获取订单列表
export const getOrders = (params?: OrderQueryParams) =>
request.get<{ success: boolean; code: number; message: string; data: { orders: Order[]; pagination: any } }>('/orders', { params })
request.get<{ success: boolean; code: number; message: string; data: { orders: Order[]; pagination: any } }>('/orders/admin', { params })
// 获取订单详情
export const getOrder = (id: number) =>

View File

@@ -50,7 +50,7 @@ export interface TravelUpdateData {
// 获取结伴游列表
export const getTravels = (params?: TravelQueryParams) =>
request.get<{ success: boolean; code: number; message: string; data: { travels: Travel[]; pagination: any } }>('/travels', { params })
request.get<{ success: boolean; code: number; message: string; data: { travels: Travel[]; pagination: any } }>('/travel/travels', { params })
// 获取结伴游详情
export const getTravel = (id: number) =>
@@ -80,6 +80,14 @@ export const getTravelPlans = (params?: TravelQueryParams) =>
export const closeTravelPlan = (id: number) =>
request.put<{ success: boolean; code: number; message: string }>(`/travel-plans/${id}/close`)
// 发布旅行
export const publishTravel = (id: number) =>
request.put<{ success: boolean; code: number; message: string }>(`/travels/${id}/publish`)
// 归档旅行
export const archiveTravel = (id: number) =>
request.put<{ success: boolean; code: number; message: string }>(`/travels/${id}/archive`)
export default {
getTravels,
getTravel,
@@ -88,5 +96,7 @@ export default {
deleteTravel,
updateTravelStatus,
getTravelPlans,
closeTravelPlan
closeTravelPlan,
publishTravel,
archiveTravel
}

View File

@@ -65,9 +65,9 @@ export interface ApiResponse<T = any> {
}
export interface UserListResponse {
users: User[]
list: User[]
pagination: {
page: number
current: number
pageSize: number
total: number
totalPages: number

View File

@@ -81,7 +81,7 @@
<!-- 创建/编辑模态框 -->
<a-modal
v-model:visible="modalVisible"
v-model:open="modalVisible"
:title="modalTitle"
width="600px"
:confirm-loading="confirmLoading"

View File

@@ -136,11 +136,10 @@ import { UserOutlined, ShopOutlined, CompassOutlined, HeartOutlined } from '@ant
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { useAppStore } from '@/stores/app'
import * as echarts from 'echarts'
import {
getDashboardData,
getUserGrowthData,
getOrderStatsData
} from '@/api/dashboard'
import dashboardAPI from '@/api/dashboard'
// 解构API方法
const { getDashboardData, getUserGrowthData, getOrderStatsData } = dashboardAPI
// 定义仪表板数据结构
interface DashboardData {
@@ -221,15 +220,25 @@ const loadDashboardData = async () => {
// 获取仪表板数据
const response = await getDashboardData()
if (response.success) {
if (response && response.success) {
dashboardData.value = response.data
} else {
console.warn('获取仪表板数据失败,使用默认数据')
}
// 获取图表数据并更新图表
await updateUserGrowthChart()
await updateOrderStatsChart()
// 延迟更新图表确保DOM已渲染
setTimeout(async () => {
await updateUserGrowthChart()
await updateOrderStatsChart()
}, 200)
} catch (error) {
console.error('加载仪表板数据失败:', error)
// 显示用户友好的错误信息
if (error instanceof Error) {
console.error('API错误:', error.message)
} else {
console.error('API错误:', error)
}
}
}
@@ -276,6 +285,15 @@ const updateOrderStatsChart = async () => {
try {
const response = await getOrderStatsData(7)
if (response.success && orderStatsChart.value) {
// 确保DOM元素已经渲染
await new Promise(resolve => setTimeout(resolve, 100))
// 检查DOM元素是否存在且有尺寸
if (!orderStatsChart.value || orderStatsChart.value.offsetWidth === 0) {
console.warn('订单统计图表DOM元素未准备好')
return
}
// 初始化图表实例
if (!orderStatsChartInstance) {
orderStatsChartInstance = echarts.init(orderStatsChart.value)

View File

@@ -1,7 +1,7 @@
<template>
<a-modal
:title="modalTitle"
:visible="visible"
:open="open"
:confirm-loading="confirmLoading"
:width="800"
@cancel="handleCancel"
@@ -107,7 +107,7 @@ import { getMerchants } from '@/api/flower'
import type { Flower, Merchant } from '@/api/flower'
interface Props {
visible: boolean
open: boolean
currentRecord: Flower | null
mode: 'create' | 'edit' | 'view'
}
@@ -166,8 +166,8 @@ const loadMerchants = async () => {
try {
merchantsLoading.value = true
const response = await getMerchants()
if (response.data.success) {
merchants.value = response.data.data.merchants
if (response.success) {
merchants.value = response.data.merchants
}
} catch (error) {
console.error('加载商家列表失败:', error)
@@ -228,9 +228,9 @@ const handleOk = async () => {
}
}
// 监听 visible 变化
watch(() => props.visible, (visible) => {
if (visible) {
// 监听 open 变化
watch(() => props.open, (open) => {
if (open) {
loadMerchants()
if (props.currentRecord) {
Object.assign(formState, props.currentRecord)

File diff suppressed because one or more lines are too long

View File

@@ -217,7 +217,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, onMounted, h } from 'vue'
import { message, Modal, type FormInstance } from 'ant-design-vue'
import type { TableProps } from 'ant-design-vue'
import {
@@ -231,7 +231,11 @@ import {
StopOutlined
} from '@ant-design/icons-vue'
import { useAppStore } from '@/stores/app'
import {
import merchantAPI from '@/api/merchant'
import type { Merchant, MerchantQueryParams } from '@/api/merchant'
// 解构API方法
const {
getMerchants,
getMerchant,
createMerchant,
@@ -239,8 +243,7 @@ import {
approveMerchant,
rejectMerchant,
disableMerchant
} from '@/api/merchant'
import type { Merchant, MerchantQueryParams } from '@/api/merchant'
} = merchantAPI
interface SearchForm {
keyword: string
@@ -409,8 +412,12 @@ const loadMerchants = async () => {
}
const response = await getMerchants(params)
merchantList.value = response.data.list
pagination.total = response.data.pagination.total
if (response && response.data) {
merchantList.value = response.data.list || response.data
if (response.data.pagination) {
pagination.total = response.data.pagination.total
}
}
} catch (error) {
message.error('加载商家列表失败')
} finally {
@@ -447,6 +454,7 @@ const handleTableChange: TableProps['onChange'] = (pag) => {
const handleView = async (record: Merchant) => {
try {
const response = await getMerchant(record.id)
const merchantData = response.data
Modal.info({
title: '商家详情',
width: 600,
@@ -455,18 +463,18 @@ const handleView = async (record: Merchant) => {
column: 1,
bordered: true
}, [
h('a-descriptions-item', { label: '商家名称' }, response.data.name),
h('a-descriptions-item', { label: '商家名称' }, merchantData.name),
h('a-descriptions-item', { label: '类型' }, [
h('a-tag', { color: getTypeColor(response.data.type) }, getTypeText(response.data.type))
h('a-tag', { color: getTypeColor(merchantData.type) }, getTypeText(merchantData.type))
]),
h('a-descriptions-item', { label: '状态' }, [
h('a-tag', { color: getStatusColor(response.data.status) }, getStatusText(response.data.status))
h('a-tag', { color: getStatusColor(merchantData.status) }, getStatusText(merchantData.status))
]),
h('a-descriptions-item', { label: '联系人' }, response.data.contact_person),
h('a-descriptions-item', { label: '联系电话' }, response.data.contact_phone),
h('a-descriptions-item', { label: '地址' }, response.data.address || '-'),
h('a-descriptions-item', { label: '描述' }, response.data.description || '-'),
h('a-descriptions-item', { label: '创建时间' }, response.data.created_at)
h('a-descriptions-item', { label: '联系人' }, merchantData.contact_person),
h('a-descriptions-item', { label: '联系电话' }, merchantData.contact_phone),
h('a-descriptions-item', { label: '地址' }, merchantData.address || '-'),
h('a-descriptions-item', { label: '描述' }, merchantData.description || '-'),
h('a-descriptions-item', { label: '创建时间' }, merchantData.created_at)
])
]),
okText: '关闭'
@@ -482,7 +490,7 @@ const handleEdit = async (record: Merchant) => {
const response = await getMerchant(record.id)
modalTitle.value = '编辑商家'
isEditing.value = true
currentMerchant.value = response.data
currentMerchant.value = response.data as any
modalVisible.value = true
} catch (error) {
message.error('获取商家详情失败')
@@ -497,7 +505,7 @@ const showCreateModal = () => {
currentMerchant.value = {
status: 'pending',
type: 'farm'
}
} as any
modalVisible.value = true
}
@@ -571,7 +579,7 @@ const handleReject = async (record: Merchant) => {
content: `确定要拒绝商家 "${record.name}" 的审核吗?`,
onOk: async () => {
try {
await rejectMerchant(record.id)
await rejectMerchant(record.id, '审核不通过')
message.success('商家审核已拒绝')
loadMerchants()
} catch (error) {

View File

@@ -388,7 +388,7 @@ const loadTravels = async () => {
const params: TravelQueryParams = {
page: pagination.current,
limit: pagination.pageSize,
keyword: searchForm.keyword,
title: searchForm.keyword, // 修改为title参数而不是keyword
status: searchForm.status
}

View File

@@ -121,7 +121,7 @@
style="width: 120px"
allow-clear
>
<a-select-option value="normal">普通用户</a-select-option>
<a-select-option value="farmer">普通用户</a-select-option>
<a-select-option value="merchant">商家</a-select-option>
<a-select-option value="admin">管理员</a-select-option>
</a-select>
@@ -147,7 +147,7 @@
:data-source="userList"
:loading="loading"
:pagination="pagination"
:row-key="record => record.id"
:row-key="(record: any) => record.id"
@change="handleTableChange"
>
<template #bodyCell="{ column, record }">
@@ -267,7 +267,7 @@
<a-col :span="12">
<a-form-item label="用户类型" name="userType">
<a-select v-model:value="currentUser.userType" placeholder="请选择用户类型">
<a-select-option value="normal">普通用户</a-select-option>
<a-select-option value="farmer">普通用户</a-select-option>
<a-select-option value="merchant">商家</a-select-option>
<a-select-option value="admin">管理员</a-select-option>
</a-select>
@@ -293,7 +293,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { ref, reactive, onMounted, computed, h } from 'vue'
import { message, Modal, type FormInstance } from 'ant-design-vue'
import type { TableProps } from 'ant-design-vue'
import {
@@ -311,8 +311,10 @@ import {
DownOutlined
} from '@ant-design/icons-vue'
import { useAppStore } from '@/stores/app'
import { getUsers, getUser, createUser, updateUser, updateUserStatus } from '@/api/user'
import userAPI from '@/api/user'
// 解构API方法
const { getUsers, getUser, createUser, updateUser, updateUserStatus } = userAPI
import type { User, UserQueryParams } from '@/types/user'
interface SearchForm {
@@ -385,25 +387,27 @@ const columns = [
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
align: 'center'
},
{
title: '用户类型',
dataIndex: 'user_type',
key: 'userType',
width: 100,
align: 'center'
},
{
title: '注册时间',
dataIndex: 'registerTime',
dataIndex: 'created_at',
key: 'registerTime',
width: 120
},
{
title: '最后登录',
dataIndex: 'lastLoginTime',
dataIndex: 'last_login_at',
key: 'lastLoginTime',
width: 120
},
@@ -437,20 +441,24 @@ const getStatusText = (status: string) => {
// 类型映射
const getTypeColor = (type: string) => {
const colors = {
normal: 'blue',
farmer: 'blue',
merchant: 'purple',
admin: 'red'
}
return colors[type as keyof typeof colors] || 'default'
// 处理后端返回的user_type字段可能为user_type或userType
const userType = type && typeof type === 'string' ? type.toLowerCase() : '';
return colors[userType as keyof typeof colors] || 'default'
}
const getTypeText = (type: string) => {
const texts = {
normal: '普通用户',
farmer: '普通用户',
merchant: '商家',
admin: '管理员'
}
return texts[type as keyof typeof texts] || '未知'
// 处理后端返回的user_type字段可能为user_type或userType
const userType = type && typeof type === 'string' ? type.toLowerCase() : '';
return texts[userType as keyof typeof texts] || '未知'
}
// 添加模态框相关状态
@@ -505,9 +513,27 @@ const loadUsers = async () => {
}
const response = await getUsers(params)
userList.value = response.data.list
pagination.total = response.data.pagination.total
if (response && response.data) {
// 根据实际返回的数据结构调整处理方式
if (response.data.users) {
// 如果返回的是分页数据结构 { users: [...], pagination: {...} }
userList.value = response.data.users
if (response.data.pagination) {
pagination.total = response.data.pagination.total
}
} else if (Array.isArray(response.data)) {
// 如果返回的是简单数组
userList.value = response.data
} else if (response.data.list) {
// 兼容旧的分页数据结构 { list: [...], pagination: {...} }
userList.value = response.data.list
if (response.data.pagination) {
pagination.total = response.data.pagination.total
}
}
}
} catch (error) {
console.error('加载用户列表失败:', error)
message.error('加载用户列表失败')
} finally {
loading.value = false
@@ -559,7 +585,7 @@ const handleView = async (record: User) => {
h('a-tag', { color: getStatusColor(response.data.status) }, getStatusText(response.data.status))
]),
h('a-descriptions-item', { label: '用户类型' }, [
h('a-tag', { color: getTypeColor(response.data.userType) }, getTypeText(response.data.userType))
h('a-tag', { color: getTypeColor(response.data.user_type || response.data.userType) }, getTypeText(response.data.user_type || response.data.userType))
]),
h('a-descriptions-item', { label: '注册时间' }, response.data.registerTime),
h('a-descriptions-item', { label: '最后登录' }, response.data.lastLoginTime)