feat(backend): 添加 Swagger 文档并优化认证接口
- 在 .env 文件中添加 ENABLE_SWAGGER 环境变量 - 在 app.js 中集成 Swagger UI - 重构 auth 路由,添加请求参数验证 - 更新 API 文档,遵循 OpenAPI 3.0 规范 -优化认证接口的错误处理和响应格式
This commit is contained in:
110
admin-system/src/api/animal.ts
Normal file
110
admin-system/src/api/animal.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { request } from '@/api'
|
||||
import type { AxiosResponse } from 'axios'
|
||||
|
||||
// 动物类型
|
||||
export type AnimalType = 'alpaca' | 'dog' | 'cat' | 'rabbit'
|
||||
|
||||
// 动物状态
|
||||
export type AnimalStatus = 'available' | 'claimed' | 'reserved'
|
||||
|
||||
// 认领状态
|
||||
export type ClaimStatus = 'pending' | 'approved' | 'rejected' | 'completed'
|
||||
|
||||
// 动物数据结构
|
||||
export interface Animal {
|
||||
id: number
|
||||
name: string
|
||||
type: AnimalType
|
||||
breed: string
|
||||
age: number
|
||||
price: number
|
||||
status: AnimalStatus
|
||||
image_url: string
|
||||
description: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
// 动物认领记录
|
||||
export interface AnimalClaim {
|
||||
id: number
|
||||
animal_id: number
|
||||
animal_name: string
|
||||
animal_image: string
|
||||
user_name: string
|
||||
user_phone: string
|
||||
status: ClaimStatus
|
||||
applied_at: string
|
||||
processed_at: string
|
||||
}
|
||||
|
||||
// 动物查询参数
|
||||
export interface AnimalQueryParams {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
type?: AnimalType
|
||||
status?: AnimalStatus
|
||||
}
|
||||
|
||||
// 认领记录查询参数
|
||||
export interface ClaimQueryParams {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
status?: ClaimStatus
|
||||
}
|
||||
|
||||
// API响应结构
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
pagination?: {
|
||||
current: number
|
||||
pageSize: number
|
||||
total: number
|
||||
totalPages: number
|
||||
}
|
||||
}
|
||||
|
||||
// 获取动物列表
|
||||
export const getAnimals = async (params?: AnimalQueryParams): Promise<ApiResponse<Animal[]>> => {
|
||||
return request.get<ApiResponse<Animal[]>>('/animals', { params })
|
||||
}
|
||||
|
||||
// 获取动物详情
|
||||
export const getAnimal = async (id: number): Promise<ApiResponse<Animal>> => {
|
||||
return request.get<ApiResponse<Animal>>(`/animals/${id}`)
|
||||
}
|
||||
|
||||
// 创建动物
|
||||
export const createAnimal = async (animalData: Partial<Animal>): Promise<ApiResponse<Animal>> => {
|
||||
return request.post<ApiResponse<Animal>>('/animals', animalData)
|
||||
}
|
||||
|
||||
// 更新动物
|
||||
export const updateAnimal = async (id: number, animalData: Partial<Animal>): Promise<ApiResponse<Animal>> => {
|
||||
return request.put<ApiResponse<Animal>>(`/animals/${id}`, animalData)
|
||||
}
|
||||
|
||||
// 删除动物
|
||||
export const deleteAnimal = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.delete<ApiResponse<void>>(`/animals/${id}`)
|
||||
}
|
||||
|
||||
// 获取认领记录列表
|
||||
export const getAnimalClaims = async (params?: ClaimQueryParams): Promise<ApiResponse<AnimalClaim[]>> => {
|
||||
return request.get<ApiResponse<AnimalClaim[]>>('/animals/claims', { params })
|
||||
}
|
||||
|
||||
// 审核动物认领(通过)
|
||||
export const approveAnimalClaim = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/animals/claims/${id}/approve`)
|
||||
}
|
||||
|
||||
// 拒绝动物认领
|
||||
export const rejectAnimalClaim = async (id: number, reason: string): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/animals/claims/${id}/reject`, { reason })
|
||||
}
|
||||
@@ -151,189 +151,12 @@ export const authAPI = {
|
||||
request.post('/auth/logout')
|
||||
}
|
||||
|
||||
// 用户管理API
|
||||
export const userAPI = {
|
||||
// 获取用户列表
|
||||
getUsers: (params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
search?: string
|
||||
status?: string
|
||||
}) => request.get('/users', { params }),
|
||||
|
||||
// 获取用户详情
|
||||
getUser: (id: number) => request.get(`/users/${id}`),
|
||||
|
||||
// 创建用户
|
||||
createUser: (data: any) => request.post('/users', data),
|
||||
|
||||
// 更新用户
|
||||
updateUser: (id: number, data: any) => request.put(`/users/${id}`, data),
|
||||
|
||||
// 删除用户
|
||||
deleteUser: (id: number) => request.delete(`/users/${id}`),
|
||||
|
||||
// 批量操作
|
||||
batchUsers: (ids: number[], action: string) =>
|
||||
request.post('/users/batch', { ids, action })
|
||||
}
|
||||
|
||||
// 商家管理API
|
||||
export const merchantAPI = {
|
||||
// 获取商家列表
|
||||
getMerchants: (params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
search?: string
|
||||
status?: string
|
||||
type?: string
|
||||
}) => request.get('/merchants', { params }),
|
||||
|
||||
// 获取商家详情
|
||||
getMerchant: (id: number) => request.get(`/merchants/${id}`),
|
||||
|
||||
// 审核商家
|
||||
approveMerchant: (id: number, data: any) => request.post(`/merchants/${id}/approve`, data),
|
||||
|
||||
// 拒绝商家
|
||||
rejectMerchant: (id: number, reason: string) => request.post(`/merchants/${id}/reject`, { reason }),
|
||||
|
||||
// 禁用商家
|
||||
disableMerchant: (id: number) => request.post(`/merchants/${id}/disable`),
|
||||
|
||||
// 启用商家
|
||||
enableMerchant: (id: number) => request.post(`/merchants/${id}/enable`)
|
||||
}
|
||||
|
||||
// 旅行管理API
|
||||
export const travelAPI = {
|
||||
// 获取旅行计划列表
|
||||
getTravelPlans: (params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
search?: string
|
||||
status?: string
|
||||
destination?: string
|
||||
}) => request.get('/travel/plans', { params }),
|
||||
|
||||
// 获取旅行计划详情
|
||||
getTravelPlan: (id: number) => request.get(`/travel/plans/${id}`),
|
||||
|
||||
// 审核旅行计划
|
||||
approveTravelPlan: (id: number) => request.post(`/travel/plans/${id}/approve`),
|
||||
|
||||
// 拒绝旅行计划
|
||||
rejectTravelPlan: (id: number, reason: string) => request.post(`/travel/plans/${id}/reject`, { reason }),
|
||||
|
||||
// 关闭旅行计划
|
||||
closeTravelPlan: (id: number) => request.post(`/travel/plans/${id}/close`)
|
||||
}
|
||||
|
||||
// 动物管理API
|
||||
export const animalAPI = {
|
||||
// 获取动物列表
|
||||
getAnimals: (params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
search?: string
|
||||
status?: string
|
||||
type?: string
|
||||
}) => request.get('/animals', { params }),
|
||||
|
||||
// 获取动物详情
|
||||
getAnimal: (id: number) => request.get(`/animals/${id}`),
|
||||
|
||||
// 创建动物
|
||||
createAnimal: (data: any) => request.post('/animals', data),
|
||||
|
||||
// 更新动物
|
||||
updateAnimal: (id: number, data: any) => request.put(`/animals/${id}`, data),
|
||||
|
||||
// 删除动物
|
||||
deleteAnimal: (id: number) => request.delete(`/animals/${id}`),
|
||||
|
||||
// 审核动物认领
|
||||
approveAnimalClaim: (id: number) => request.post(`/animals/claims/${id}/approve`),
|
||||
|
||||
// 拒绝动物认领
|
||||
rejectAnimalClaim: (id: number, reason: string) => request.post(`/animals/claims/${id}/reject`, { reason })
|
||||
}
|
||||
|
||||
// 订单管理API
|
||||
export const orderAPI = {
|
||||
// 获取订单列表
|
||||
getOrders: (params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
search?: string
|
||||
status?: string
|
||||
type?: string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
}) => request.get('/orders', { params }),
|
||||
|
||||
// 获取订单详情
|
||||
getOrder: (id: number) => request.get(`/orders/${id}`),
|
||||
|
||||
// 更新订单状态
|
||||
updateOrderStatus: (id: number, status: string) => request.put(`/orders/${id}/status`, { status }),
|
||||
|
||||
// 导出订单
|
||||
exportOrders: (params: any) => request.get('/orders/export', {
|
||||
params,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 推广管理API
|
||||
export const promotionAPI = {
|
||||
// 获取推广数据
|
||||
getPromotionStats: () => request.get('/promotion/stats'),
|
||||
|
||||
// 获取推广记录
|
||||
getPromotionRecords: (params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
search?: string
|
||||
status?: string
|
||||
}) => request.get('/promotion/records', { params }),
|
||||
|
||||
// 审核提现申请
|
||||
approveWithdrawal: (id: number) => request.post(`/promotion/withdrawals/${id}/approve`),
|
||||
|
||||
// 拒绝提现申请
|
||||
rejectWithdrawal: (id: number, reason: string) => request.post(`/promotion/withdrawals/${id}/reject`, { reason }),
|
||||
|
||||
// 导出推广数据
|
||||
exportPromotionData: (params: any) => request.get('/promotion/export', {
|
||||
params,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 系统管理API
|
||||
export const systemAPI = {
|
||||
// 获取系统配置
|
||||
getConfig: () => request.get('/system/config'),
|
||||
|
||||
// 更新系统配置
|
||||
updateConfig: (data: any) => request.put('/system/config', data),
|
||||
|
||||
// 获取操作日志
|
||||
getOperationLogs: (params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
search?: string
|
||||
action?: string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
}) => request.get('/system/logs', { params }),
|
||||
|
||||
// 清理缓存
|
||||
clearCache: () => request.post('/system/cache/clear'),
|
||||
|
||||
// 系统健康检查
|
||||
healthCheck: () => request.get('/system/health')
|
||||
}
|
||||
export * from './user'
|
||||
export * from './merchant'
|
||||
export * from './travel'
|
||||
export * from './animal'
|
||||
export * from './order'
|
||||
export * from './promotion'
|
||||
export * from './system'
|
||||
|
||||
export default api
|
||||
73
admin-system/src/api/merchant.ts
Normal file
73
admin-system/src/api/merchant.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { request } from '@/api'
|
||||
import type { AxiosResponse } from 'axios'
|
||||
|
||||
// 商家类型
|
||||
export type MerchantType = 'flower_shop' | 'activity_organizer' | 'farm_owner'
|
||||
|
||||
// 商家状态
|
||||
export type MerchantStatus = 'pending' | 'approved' | 'rejected' | 'disabled'
|
||||
|
||||
// 商家数据结构
|
||||
export interface Merchant {
|
||||
id: number
|
||||
business_name: string
|
||||
merchant_type: MerchantType
|
||||
contact_person: string
|
||||
contact_phone: string
|
||||
status: MerchantStatus
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
// 商家查询参数
|
||||
export interface MerchantQueryParams {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
type?: MerchantType
|
||||
status?: MerchantStatus
|
||||
}
|
||||
|
||||
// API响应结构
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
pagination?: {
|
||||
current: number
|
||||
pageSize: number
|
||||
total: number
|
||||
totalPages: number
|
||||
}
|
||||
}
|
||||
|
||||
// 获取商家列表
|
||||
export const getMerchants = async (params?: MerchantQueryParams): Promise<ApiResponse<Merchant[]>> => {
|
||||
return request.get<ApiResponse<Merchant[]>>('/merchants', { params })
|
||||
}
|
||||
|
||||
// 获取商家详情
|
||||
export const getMerchant = async (id: number): Promise<ApiResponse<Merchant>> => {
|
||||
return request.get<ApiResponse<Merchant>>(`/merchants/${id}`)
|
||||
}
|
||||
|
||||
// 审核商家(通过)
|
||||
export const approveMerchant = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/merchants/${id}/approve`)
|
||||
}
|
||||
|
||||
// 拒绝商家入驻申请
|
||||
export const rejectMerchant = async (id: number, reason: string): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/merchants/${id}/reject`, { reason })
|
||||
}
|
||||
|
||||
// 禁用商家
|
||||
export const disableMerchant = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/merchants/${id}/disable`)
|
||||
}
|
||||
|
||||
// 启用商家
|
||||
export const enableMerchant = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/merchants/${id}/enable`)
|
||||
}
|
||||
95
admin-system/src/api/order.ts
Normal file
95
admin-system/src/api/order.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { request } from '@/api'
|
||||
import type { AxiosResponse } from 'axios'
|
||||
|
||||
// 订单状态
|
||||
export type OrderStatus = 'pending' | 'paid' | 'shipped' | 'completed' | 'cancelled' | 'refunded'
|
||||
|
||||
// 支付方式
|
||||
export type PaymentMethod = 'wechat' | 'alipay' | 'bank' | 'balance'
|
||||
|
||||
// 订单数据结构
|
||||
export interface Order {
|
||||
id: number
|
||||
order_no: string
|
||||
user_id: number
|
||||
user_name: string
|
||||
user_phone: string
|
||||
amount: number
|
||||
status: OrderStatus
|
||||
payment_method: PaymentMethod
|
||||
created_at: string
|
||||
paid_at: string
|
||||
shipped_at: string
|
||||
completed_at: string
|
||||
}
|
||||
|
||||
// 订单查询参数
|
||||
export interface OrderQueryParams {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
order_no?: string
|
||||
status?: OrderStatus
|
||||
orderTime?: [string, string]
|
||||
}
|
||||
|
||||
// 统计数据
|
||||
export interface OrderStatistics {
|
||||
today_orders: number
|
||||
today_sales: number
|
||||
month_orders: number
|
||||
month_sales: number
|
||||
}
|
||||
|
||||
// API响应结构
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
pagination?: {
|
||||
current: number
|
||||
pageSize: number
|
||||
total: number
|
||||
totalPages: number
|
||||
}
|
||||
}
|
||||
|
||||
// 获取订单列表
|
||||
export const getOrders = async (params?: OrderQueryParams): Promise<ApiResponse<Order[]>> => {
|
||||
return request.get<ApiResponse<Order[]>>('/orders', { params })
|
||||
}
|
||||
|
||||
// 获取订单详情
|
||||
export const getOrder = async (id: number): Promise<ApiResponse<Order>> => {
|
||||
return request.get<ApiResponse<Order>>(`/orders/${id}`)
|
||||
}
|
||||
|
||||
// 更新订单状态
|
||||
export const updateOrderStatus = async (id: number, status: OrderStatus): Promise<ApiResponse<void>> => {
|
||||
return request.put<ApiResponse<void>>(`/orders/${id}/status`, { status })
|
||||
}
|
||||
|
||||
// 发货
|
||||
export const shipOrder = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/orders/${id}/ship`)
|
||||
}
|
||||
|
||||
// 完成订单
|
||||
export const completeOrder = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/orders/${id}/complete`)
|
||||
}
|
||||
|
||||
// 取消订单
|
||||
export const cancelOrder = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/orders/${id}/cancel`)
|
||||
}
|
||||
|
||||
// 退款
|
||||
export const refundOrder = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/orders/${id}/refund`)
|
||||
}
|
||||
|
||||
// 获取订单统计数据
|
||||
export const getOrderStatistics = async (): Promise<ApiResponse<OrderStatistics>> => {
|
||||
return request.get<ApiResponse<OrderStatistics>>('/orders/statistics')
|
||||
}
|
||||
133
admin-system/src/api/promotion.ts
Normal file
133
admin-system/src/api/promotion.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import { request } from '@/api'
|
||||
import type { AxiosResponse } from 'axios'
|
||||
|
||||
// 推广活动状态
|
||||
export type PromotionStatus = 'active' | 'upcoming' | 'ended' | 'paused'
|
||||
|
||||
// 奖励类型
|
||||
export type RewardType = 'cash' | 'points' | 'coupon'
|
||||
|
||||
// 奖励状态
|
||||
export type RewardStatus = 'pending' | 'issued' | 'failed'
|
||||
|
||||
// 推广活动数据结构
|
||||
export interface PromotionActivity {
|
||||
id: number
|
||||
name: string
|
||||
description: string
|
||||
reward_type: RewardType
|
||||
reward_amount: number
|
||||
status: PromotionStatus
|
||||
start_time: string
|
||||
end_time: string
|
||||
max_participants: number
|
||||
current_participants: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
// 奖励记录
|
||||
export interface RewardRecord {
|
||||
id: number
|
||||
user_id: number
|
||||
user_name: string
|
||||
user_phone: string
|
||||
activity_id: number
|
||||
activity_name: string
|
||||
reward_type: RewardType
|
||||
reward_amount: number
|
||||
status: RewardStatus
|
||||
issued_at: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
// 推广活动查询参数
|
||||
export interface PromotionQueryParams {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
name?: string
|
||||
status?: PromotionStatus
|
||||
activityTime?: [string, string]
|
||||
}
|
||||
|
||||
// 奖励记录查询参数
|
||||
export interface RewardQueryParams {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
user?: string
|
||||
reward_type?: RewardType
|
||||
status?: RewardStatus
|
||||
}
|
||||
|
||||
// 统计数据
|
||||
export interface PromotionStatistics {
|
||||
total_activities: number
|
||||
active_activities: number
|
||||
total_rewards: number
|
||||
issued_rewards: number
|
||||
total_amount: number
|
||||
}
|
||||
|
||||
// API响应结构
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
pagination?: {
|
||||
current: number
|
||||
pageSize: number
|
||||
total: number
|
||||
totalPages: number
|
||||
}
|
||||
}
|
||||
|
||||
// 获取推广活动列表
|
||||
export const getPromotionActivities = async (params?: PromotionQueryParams): Promise<ApiResponse<PromotionActivity[]>> => {
|
||||
return request.get<ApiResponse<PromotionActivity[]>>('/promotion/activities', { params })
|
||||
}
|
||||
|
||||
// 获取推广活动详情
|
||||
export const getPromotionActivity = async (id: number): Promise<ApiResponse<PromotionActivity>> => {
|
||||
return request.get<ApiResponse<PromotionActivity>>(`/promotion/activities/${id}`)
|
||||
}
|
||||
|
||||
// 创建推广活动
|
||||
export const createPromotionActivity = async (activityData: Partial<PromotionActivity>): Promise<ApiResponse<PromotionActivity>> => {
|
||||
return request.post<ApiResponse<PromotionActivity>>('/promotion/activities', activityData)
|
||||
}
|
||||
|
||||
// 更新推广活动
|
||||
export const updatePromotionActivity = async (id: number, activityData: Partial<PromotionActivity>): Promise<ApiResponse<PromotionActivity>> => {
|
||||
return request.put<ApiResponse<PromotionActivity>>(`/promotion/activities/${id}`, activityData)
|
||||
}
|
||||
|
||||
// 删除推广活动
|
||||
export const deletePromotionActivity = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.delete<ApiResponse<void>>(`/promotion/activities/${id}`)
|
||||
}
|
||||
|
||||
// 暂停推广活动
|
||||
export const pausePromotionActivity = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/promotion/activities/${id}/pause`)
|
||||
}
|
||||
|
||||
// 恢复推广活动
|
||||
export const resumePromotionActivity = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/promotion/activities/${id}/resume`)
|
||||
}
|
||||
|
||||
// 获取奖励记录列表
|
||||
export const getRewardRecords = async (params?: RewardQueryParams): Promise<ApiResponse<RewardRecord[]>> => {
|
||||
return request.get<ApiResponse<RewardRecord[]>>('/promotion/rewards', { params })
|
||||
}
|
||||
|
||||
// 发放奖励
|
||||
export const issueReward = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/promotion/rewards/${id}/issue`)
|
||||
}
|
||||
|
||||
// 获取推广统计数据
|
||||
export const getPromotionStatistics = async (): Promise<ApiResponse<PromotionStatistics>> => {
|
||||
return request.get<ApiResponse<PromotionStatistics>>('/promotion/statistics')
|
||||
}
|
||||
120
admin-system/src/api/system.ts
Normal file
120
admin-system/src/api/system.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { request } from '@/api'
|
||||
import type { AxiosResponse } from 'axios'
|
||||
|
||||
// 服务类型
|
||||
export type ServiceType = 'database' | 'cache' | 'mq'
|
||||
|
||||
// 服务状态
|
||||
export type ServiceStatus = 'running' | 'stopped'
|
||||
|
||||
// 系统服务数据结构
|
||||
export interface Service {
|
||||
id: number
|
||||
name: string
|
||||
type: ServiceType
|
||||
description: string
|
||||
status: ServiceStatus
|
||||
}
|
||||
|
||||
// 系统配置
|
||||
export interface SystemSettings {
|
||||
systemName: string
|
||||
systemVersion: string
|
||||
maintenanceMode: boolean
|
||||
sessionTimeout: number
|
||||
pageSize: number
|
||||
enableSwagger: boolean
|
||||
}
|
||||
|
||||
// 系统信息
|
||||
export interface SystemInfo {
|
||||
version: string
|
||||
environment: string
|
||||
uptime: string
|
||||
startTime: string
|
||||
}
|
||||
|
||||
// 数据库状态
|
||||
export interface DatabaseStatus {
|
||||
status: ServiceStatus
|
||||
type: string
|
||||
connections: string
|
||||
queriesPerMinute: number
|
||||
}
|
||||
|
||||
// 缓存状态
|
||||
export interface CacheStatus {
|
||||
status: ServiceStatus
|
||||
memoryUsage: string
|
||||
hitRate: string
|
||||
keyCount: number
|
||||
}
|
||||
|
||||
// API响应结构
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
|
||||
// 获取系统服务列表
|
||||
export const getServices = async (): Promise<ApiResponse<Service[]>> => {
|
||||
return request.get<ApiResponse<Service[]>>('/system/services')
|
||||
}
|
||||
|
||||
// 启动服务
|
||||
export const startService = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/system/services/${id}/start`)
|
||||
}
|
||||
|
||||
// 停止服务
|
||||
export const stopService = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/system/services/${id}/stop`)
|
||||
}
|
||||
|
||||
// 获取系统信息
|
||||
export const getSystemInfo = async (): Promise<ApiResponse<SystemInfo>> => {
|
||||
return request.get<ApiResponse<SystemInfo>>('/system/info')
|
||||
}
|
||||
|
||||
// 获取数据库状态
|
||||
export const getDatabaseStatus = async (): Promise<ApiResponse<DatabaseStatus>> => {
|
||||
return request.get<ApiResponse<DatabaseStatus>>('/system/database')
|
||||
}
|
||||
|
||||
// 获取缓存状态
|
||||
export const getCacheStatus = async (): Promise<ApiResponse<CacheStatus>> => {
|
||||
return request.get<ApiResponse<CacheStatus>>('/system/cache')
|
||||
}
|
||||
|
||||
// 获取系统配置
|
||||
export const getSystemSettings = async (): Promise<ApiResponse<SystemSettings>> => {
|
||||
return request.get<ApiResponse<SystemSettings>>('/system/settings')
|
||||
}
|
||||
|
||||
// 更新系统配置
|
||||
export const updateSystemSettings = async (settings: SystemSettings): Promise<ApiResponse<void>> => {
|
||||
return request.put<ApiResponse<void>>('/system/settings', settings)
|
||||
}
|
||||
|
||||
// 获取操作日志
|
||||
export const getOperationLogs = async (params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
search?: string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
}): Promise<ApiResponse<any[]>> => {
|
||||
return request.get<ApiResponse<any[]>>('/system/logs', { params })
|
||||
}
|
||||
|
||||
// 清理缓存
|
||||
export const clearCache = async (): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>('/system/cache/clear')
|
||||
}
|
||||
|
||||
// 系统健康检查
|
||||
export const healthCheck = async (): Promise<ApiResponse<any>> => {
|
||||
return request.get<ApiResponse<any>>('/system/health')
|
||||
}
|
||||
68
admin-system/src/api/travel.ts
Normal file
68
admin-system/src/api/travel.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { request } from '@/api'
|
||||
import type { AxiosResponse } from 'axios'
|
||||
|
||||
// 旅行计划状态
|
||||
export type TravelStatus = 'recruiting' | 'full' | 'completed' | 'cancelled'
|
||||
|
||||
// 旅行计划数据结构
|
||||
export interface TravelPlan {
|
||||
id: number
|
||||
destination: string
|
||||
start_date: string
|
||||
end_date: string
|
||||
budget: number
|
||||
max_members: number
|
||||
current_members: number
|
||||
status: TravelStatus
|
||||
creator: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
// 旅行计划查询参数
|
||||
export interface TravelQueryParams {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
destination?: string
|
||||
status?: TravelStatus
|
||||
travelTime?: [string, string]
|
||||
}
|
||||
|
||||
// API响应结构
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
pagination?: {
|
||||
current: number
|
||||
pageSize: number
|
||||
total: number
|
||||
totalPages: number
|
||||
}
|
||||
}
|
||||
|
||||
// 获取旅行计划列表
|
||||
export const getTravelPlans = async (params?: TravelQueryParams): Promise<ApiResponse<TravelPlan[]>> => {
|
||||
return request.get<ApiResponse<TravelPlan[]>>('/travel/plans', { params })
|
||||
}
|
||||
|
||||
// 获取旅行计划详情
|
||||
export const getTravelPlan = async (id: number): Promise<ApiResponse<TravelPlan>> => {
|
||||
return request.get<ApiResponse<TravelPlan>>(`/travel/plans/${id}`)
|
||||
}
|
||||
|
||||
// 审核旅行计划
|
||||
export const approveTravelPlan = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/travel/plans/${id}/approve`)
|
||||
}
|
||||
|
||||
// 拒绝旅行计划
|
||||
export const rejectTravelPlan = async (id: number, reason: string): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/travel/plans/${id}/reject`, { reason })
|
||||
}
|
||||
|
||||
// 关闭旅行计划
|
||||
export const closeTravelPlan = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>(`/travel/plans/${id}/close`)
|
||||
}
|
||||
81
admin-system/src/api/user.ts
Normal file
81
admin-system/src/api/user.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { request } from '@/api'
|
||||
import type { AxiosResponse } from 'axios'
|
||||
|
||||
// 用户状态类型
|
||||
export type UserStatus = 'active' | 'inactive' | 'banned'
|
||||
|
||||
// 用户等级类型
|
||||
export type UserLevel = number
|
||||
|
||||
// 用户数据结构
|
||||
export interface User {
|
||||
id: number
|
||||
openid: string
|
||||
nickname: string
|
||||
avatar: string
|
||||
gender: string
|
||||
birthday: string
|
||||
phone: string
|
||||
email: string
|
||||
status: UserStatus
|
||||
level: UserLevel
|
||||
points: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
// 用户查询参数
|
||||
export interface UserQueryParams {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
keyword?: string
|
||||
status?: UserStatus
|
||||
registerTime?: [string, string]
|
||||
}
|
||||
|
||||
// API响应结构
|
||||
export interface ApiResponse<T> {
|
||||
success: boolean
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
pagination?: {
|
||||
current: number
|
||||
pageSize: number
|
||||
total: number
|
||||
totalPages: number
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
export const getUsers = async (params?: UserQueryParams): Promise<ApiResponse<User[]>> => {
|
||||
return request.get<ApiResponse<User[]>>('/users', { params })
|
||||
}
|
||||
|
||||
// 获取用户详情
|
||||
export const getUser = async (id: number): Promise<ApiResponse<User>> => {
|
||||
return request.get<ApiResponse<User>>(`/users/${id}`)
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
export const createUser = async (userData: Partial<User>): Promise<ApiResponse<User>> => {
|
||||
return request.post<ApiResponse<User>>('/users', userData)
|
||||
}
|
||||
|
||||
// 更新用户
|
||||
export const updateUser = async (id: number, userData: Partial<User>): Promise<ApiResponse<User>> => {
|
||||
return request.put<ApiResponse<User>>(`/users/${id}`, userData)
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
export const deleteUser = async (id: number): Promise<ApiResponse<void>> => {
|
||||
return request.delete<ApiResponse<void>>(`/users/${id}`)
|
||||
}
|
||||
|
||||
// 批量操作用户
|
||||
export const batchUsers = async (
|
||||
ids: number[],
|
||||
action: 'delete' | 'ban' | 'activate'
|
||||
): Promise<ApiResponse<void>> => {
|
||||
return request.post<ApiResponse<void>>('/users/batch', { ids, action })
|
||||
}
|
||||
35
admin-system/src/pages/NotFound.vue
Normal file
35
admin-system/src/pages/NotFound.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div class="not-found">
|
||||
<a-result
|
||||
status="404"
|
||||
title="404"
|
||||
sub-title="抱歉,您访问的页面不存在。"
|
||||
>
|
||||
<template #extra>
|
||||
<a-button type="primary" @click="goHome">
|
||||
返回首页
|
||||
</a-button>
|
||||
</template>
|
||||
</a-result>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const goHome = () => {
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.not-found {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
background-color: #f0f2f5;
|
||||
}
|
||||
</style>
|
||||
@@ -243,31 +243,8 @@ import {
|
||||
CheckOutlined,
|
||||
CloseOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
interface Animal {
|
||||
id: number
|
||||
name: string
|
||||
type: string
|
||||
breed: string
|
||||
age: number
|
||||
price: number
|
||||
status: string
|
||||
image_url: string
|
||||
description: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
interface AnimalClaim {
|
||||
id: number
|
||||
animal_id: number
|
||||
animal_name: string
|
||||
animal_image: string
|
||||
user_name: string
|
||||
user_phone: string
|
||||
status: string
|
||||
applied_at: string
|
||||
processed_at: string
|
||||
}
|
||||
import { getAnimals, deleteAnimal, getAnimalClaims, approveAnimalClaim, rejectAnimalClaim } from '@/api/animal'
|
||||
import type { Animal, AnimalClaim } from '@/api/animal'
|
||||
|
||||
interface SearchForm {
|
||||
keyword: string
|
||||
@@ -295,52 +272,13 @@ const claimSearchForm = reactive<ClaimSearchForm>({
|
||||
status: ''
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const animalList = ref<Animal[]>([
|
||||
{
|
||||
id: 1,
|
||||
name: '小白',
|
||||
type: 'alpaca',
|
||||
breed: '苏利羊驼',
|
||||
age: 2,
|
||||
price: 1000,
|
||||
status: 'available',
|
||||
image_url: 'https://api.dicebear.com/7.x/bottts/svg?seed=alpaca',
|
||||
description: '温顺可爱的羊驼',
|
||||
created_at: '2024-01-10'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '旺财',
|
||||
type: 'dog',
|
||||
breed: '金毛寻回犬',
|
||||
age: 1,
|
||||
price: 800,
|
||||
status: 'claimed',
|
||||
image_url: 'https://api.dicebear.com/7.x/bottts/svg?seed=dog',
|
||||
description: '活泼聪明的金毛',
|
||||
created_at: '2024-02-15'
|
||||
}
|
||||
])
|
||||
|
||||
const claimList = ref<AnimalClaim[]>([
|
||||
{
|
||||
id: 1,
|
||||
animal_id: 1,
|
||||
animal_name: '小白',
|
||||
animal_image: 'https://api.dicebear.com/7.x/bottts/svg?seed=alpaca',
|
||||
user_name: '张先生',
|
||||
user_phone: '13800138000',
|
||||
status: 'pending',
|
||||
applied_at: '2024-03-01',
|
||||
processed_at: ''
|
||||
}
|
||||
])
|
||||
const animalList = ref<Animal[]>([])
|
||||
const claimList = ref<AnimalClaim[]>([])
|
||||
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 50,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
@@ -349,7 +287,7 @@ const pagination = reactive({
|
||||
const claimPagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 30,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
@@ -459,7 +397,7 @@ const claimColumns = [
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
极速版 key: 'actions',
|
||||
key: 'actions',
|
||||
width: 150,
|
||||
align: 'center'
|
||||
}
|
||||
@@ -537,7 +475,16 @@ onMounted(() => {
|
||||
const loadAnimals = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
const response = await getAnimals({
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword,
|
||||
type: searchForm.type,
|
||||
status: searchForm.status
|
||||
})
|
||||
|
||||
animalList.value = response.data
|
||||
pagination.total = response.pagination?.total || 0
|
||||
} catch (error) {
|
||||
message.error('加载动物列表失败')
|
||||
} finally {
|
||||
@@ -548,7 +495,15 @@ const loadAnimals = async () => {
|
||||
const loadClaims = async () => {
|
||||
claimLoading.value = true
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
const response = await getAnimalClaims({
|
||||
page: claimPagination.current,
|
||||
pageSize: claimPagination.pageSize,
|
||||
keyword: claimSearchForm.keyword,
|
||||
status: claimSearchForm.status
|
||||
})
|
||||
|
||||
claimList.value = response.data
|
||||
claimPagination.total = response.pagination?.total || 0
|
||||
} catch (error) {
|
||||
message.error('加载认领记录失败')
|
||||
} finally {
|
||||
@@ -616,7 +571,7 @@ const handleEditAnimal = (record: Animal) => {
|
||||
message.info(`编辑动物: ${record.name}`)
|
||||
}
|
||||
|
||||
const handleDeleteAnimal = (record: Animal) => {
|
||||
const handleDeleteAnimal = async (record: Animal) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确定要删除动物 "${record.name}" 吗?`,
|
||||
@@ -624,6 +579,7 @@ const handleDeleteAnimal = (record: Animal) => {
|
||||
okType: 'danger',
|
||||
onOk: async () => {
|
||||
try {
|
||||
await deleteAnimal(record.id)
|
||||
message.success('动物已删除')
|
||||
loadAnimals()
|
||||
} catch (error) {
|
||||
@@ -633,12 +589,13 @@ const handleDeleteAnimal = (record: Animal) => {
|
||||
})
|
||||
}
|
||||
|
||||
const handleApproveClaim = (record: AnimalClaim) => {
|
||||
const handleApproveClaim = async (record: AnimalClaim) => {
|
||||
Modal.confirm({
|
||||
title: '确认通过',
|
||||
content: `确定要通过用户 "${record.user_name}" 的认领申请吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await approveAnimalClaim(record.id)
|
||||
message.success('认领申请已通过')
|
||||
loadClaims()
|
||||
} catch (error) {
|
||||
@@ -648,12 +605,13 @@ const handleApproveClaim = (record: AnimalClaim) => {
|
||||
})
|
||||
}
|
||||
|
||||
const handleRejectClaim = (record: AnimalClaim) => {
|
||||
const handleRejectClaim = async (record: AnimalClaim) => {
|
||||
Modal.confirm({
|
||||
title: '确认拒绝',
|
||||
content: `确定要拒绝用户 "${record.user_name}" 的认领申请吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await rejectAnimalClaim(record.id, '拒绝原因')
|
||||
message.success('认领申请已拒绝')
|
||||
loadClaims()
|
||||
} catch (error) {
|
||||
|
||||
@@ -150,16 +150,8 @@ import {
|
||||
StopOutlined,
|
||||
PlayCircleOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
interface Merchant {
|
||||
id: number
|
||||
business_name: string
|
||||
merchant_type: string
|
||||
contact_person: string
|
||||
contact_phone: string
|
||||
status: string
|
||||
created_at: string
|
||||
}
|
||||
import { getMerchants, approveMerchant, rejectMerchant, disableMerchant, enableMerchant } from '@/api/merchant'
|
||||
import type { Merchant } from '@/api/merchant'
|
||||
|
||||
interface SearchForm {
|
||||
keyword: string
|
||||
@@ -175,32 +167,11 @@ const searchForm = reactive<SearchForm>({
|
||||
status: ''
|
||||
})
|
||||
|
||||
// 模拟商家数据
|
||||
const merchantList = ref<Merchant[]>([
|
||||
{
|
||||
id: 1,
|
||||
business_name: '鲜花坊',
|
||||
merchant_type: 'flower_shop',
|
||||
contact_person: '张经理',
|
||||
contact_phone: '13800138000',
|
||||
status: 'approved',
|
||||
created_at: '2024-01-15'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
business_name: '阳光农场',
|
||||
merchant_type: 'farm_owner',
|
||||
contact_person: '李场主',
|
||||
contact_phone: '13800138001',
|
||||
status: 'pending',
|
||||
created_at: '2024-02-20'
|
||||
}
|
||||
])
|
||||
|
||||
const merchantList = ref<Merchant[]>([])
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 50,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
@@ -300,8 +271,16 @@ onMounted(() => {
|
||||
const loadMerchants = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// TODO: 调用真实API
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
const response = await getMerchants({
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword,
|
||||
type: searchForm.type,
|
||||
status: searchForm.status
|
||||
})
|
||||
|
||||
merchantList.value = response.data
|
||||
pagination.total = response.pagination?.total || 0
|
||||
} catch (error) {
|
||||
message.error('加载商家列表失败')
|
||||
} finally {
|
||||
@@ -345,6 +324,7 @@ const handleApprove = async (record: Merchant) => {
|
||||
content: `确定要通过商家 "${record.business_name}" 的入驻申请吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await approveMerchant(record.id)
|
||||
message.success('商家入驻申请已通过')
|
||||
loadMerchants()
|
||||
} catch (error) {
|
||||
@@ -360,6 +340,7 @@ const handleReject = async (record: Merchant) => {
|
||||
content: `确定要拒绝商家 "${record.business_name}" 的入驻申请吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await rejectMerchant(record.id, '拒绝原因')
|
||||
message.success('商家入驻申请已拒绝')
|
||||
loadMerchants()
|
||||
} catch (error) {
|
||||
@@ -375,6 +356,7 @@ const handleDisable = async (record: Merchant) => {
|
||||
content: `确定要禁用商家 "${record.business_name}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await disableMerchant(record.id)
|
||||
message.success('商家已禁用')
|
||||
loadMerchants()
|
||||
} catch (error) {
|
||||
@@ -390,6 +372,7 @@ const handleEnable = async (record: Merchant) => {
|
||||
content: `确定要启用商家 "${record.business_name}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await enableMerchant(record.id)
|
||||
message.success('商家已启用')
|
||||
loadMerchants()
|
||||
} catch (error) {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<a-select-option value="shipped">已发货</a-select-option>
|
||||
<a-select-option value="completed">已完成</a-select-option>
|
||||
<a-select-option value="cancelled">已取消</a-select-option>
|
||||
<a-select-option value极速版="refunded">已退款</a-select-option>
|
||||
<a-select-option value="refunded">已退款</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
@@ -92,11 +92,11 @@
|
||||
|
||||
<template v-if="['pending', 'paid'].includes(record.status)">
|
||||
<a-button size="small" danger @click="handleCancel(record)">
|
||||
<极速版CloseOutlined />取消
|
||||
<CloseOutlined />取消
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<template v-if="record.status === '极速版paid'">
|
||||
<template v-if="record.status === 'paid'">
|
||||
<a-button size="small" danger @click="handleRefund(record)">
|
||||
<RollbackOutlined />退款
|
||||
</a-button>
|
||||
@@ -120,10 +120,10 @@
|
||||
<a-statistic title="今日销售额" :value="statistics.today_sales" :precision="2" prefix="¥" :value-style="{ color: '#cf1322' }" />
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-statistic title="本月订单" :value="statistics.month_orders" :precision="0" :value-style="{ color: '#1890极速版ff' }" />
|
||||
<a-statistic title="本月订单" :value="statistics.month_orders" :precision="0" :value-style="{ color: '#1890ff' }" />
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-statistic title="本月销售额" :value="statistics.month_sales" :precision="2" prefix="¥" :极速版value-style="{ color: '#722ed1' }" />
|
||||
<a-statistic title="本月销售额" :value="statistics.month_sales" :precision="2" prefix="¥" :value-style="{ color: '#722ed1' }" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
@@ -156,21 +156,8 @@ import {
|
||||
RollbackOutlined,
|
||||
ShoppingOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
interface Order {
|
||||
id: number
|
||||
order_no: string
|
||||
user_id: number
|
||||
user_name: string
|
||||
user_phone: string
|
||||
amount: number
|
||||
status: string
|
||||
payment_method: string
|
||||
created_at: string
|
||||
paid_at: string
|
||||
shipped_at: string
|
||||
completed_at: string
|
||||
}
|
||||
import { getOrders, updateOrderStatus, getOrderStatistics } from '@/api/order'
|
||||
import type { Order, OrderStatistics } from '@/api/order'
|
||||
|
||||
interface SearchForm {
|
||||
order_no: string
|
||||
@@ -178,13 +165,6 @@ interface SearchForm {
|
||||
orderTime: any[]
|
||||
}
|
||||
|
||||
interface Statistics {
|
||||
today_orders: number
|
||||
today_sales: number
|
||||
month_orders: number
|
||||
month_sales: number
|
||||
}
|
||||
|
||||
const activeTab = ref('orders')
|
||||
const loading = ref(false)
|
||||
|
||||
@@ -194,48 +174,18 @@ const searchForm = reactive<SearchForm>({
|
||||
orderTime: []
|
||||
})
|
||||
|
||||
const statistics = reactive<Statistics>({
|
||||
const statistics = reactive<OrderStatistics>({
|
||||
today_orders: 0,
|
||||
today_sales: 0,
|
||||
month_orders: 0,
|
||||
month_sales: 0
|
||||
})
|
||||
|
||||
const orderList = ref<Order[]>([
|
||||
{
|
||||
id: 1,
|
||||
order_no: 'ORD202403150001',
|
||||
user_id: 1001,
|
||||
user_name: '张先生',
|
||||
user_phone: '13800138000',
|
||||
amount: 299.99,
|
||||
status: 'paid',
|
||||
payment_method: 'wechat',
|
||||
created_at: '2024-03-15 10:30:00',
|
||||
paid_at: '2024-03-15 10:35:00',
|
||||
shipped_at: '',
|
||||
completed_at: ''
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
order_no: 'ORD202403140002',
|
||||
user_id: 1002,
|
||||
user_name: '李女士',
|
||||
user_phone: '13800138001',
|
||||
amount: 极速版199.99,
|
||||
status: 'shipped',
|
||||
payment_method: 'alipay',
|
||||
created_at: '2024-03-14 14:20:00',
|
||||
paid_at: '2024-03-14 14:25:00',
|
||||
shipped_at: '2024-03-15 09:00:00',
|
||||
completed_at: ''
|
||||
}
|
||||
])
|
||||
|
||||
const orderList = ref<Order[]>([])
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 50,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
@@ -244,7 +194,7 @@ const pagination = reactive({
|
||||
const orderColumns = [
|
||||
{ title: '订单号', key: 'order_no', width: 160 },
|
||||
{ title: '用户', dataIndex: 'user_name', key: 'user_name', width: 100 },
|
||||
{ title: '联系电话', dataIndex: 'user极速版_phone', key: 'user_phone', width: 120 },
|
||||
{ title: '联系电话', dataIndex: 'user_phone', key: 'user_phone', width: 120 },
|
||||
{ title: '金额', key: 'amount', width: 100, align: 'center' },
|
||||
{ title: '状态', key: 'status', width: 100, align: 'center' },
|
||||
{ title: '支付方式', key: 'payment_method', width: 100, align: 'center' },
|
||||
@@ -294,7 +244,15 @@ onMounted(() => {
|
||||
const loadOrders = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
const response = await getOrders({
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
order_no: searchForm.order_no,
|
||||
status: searchForm.status
|
||||
})
|
||||
|
||||
orderList.value = response.data
|
||||
pagination.total = response.pagination?.total || 0
|
||||
} catch (error) {
|
||||
message.error('加载订单列表失败')
|
||||
} finally {
|
||||
@@ -304,10 +262,8 @@ const loadOrders = async () => {
|
||||
|
||||
const loadStatistics = async () => {
|
||||
try {
|
||||
statistics.today_orders = 15
|
||||
statistics.today_sales = 4500.50
|
||||
statistics.month_orders = 120
|
||||
statistics.month_sales = 35600.80
|
||||
const response = await getOrderStatistics()
|
||||
Object.assign(statistics, response.data)
|
||||
} catch (error) {
|
||||
message.error('加载统计数据失败')
|
||||
}
|
||||
@@ -345,7 +301,7 @@ const handleRefresh = () => {
|
||||
message.success('数据已刷新')
|
||||
}
|
||||
|
||||
const handleTableChange: TableProps['onChange极速版'] = (pag) => {
|
||||
const handleTableChange: TableProps['onChange'] = (pag) => {
|
||||
pagination.current = pag.current!
|
||||
pagination.pageSize = pag.pageSize!
|
||||
loadOrders()
|
||||
@@ -361,6 +317,7 @@ const handleShip = async (record: Order) => {
|
||||
content: `确定要发货订单 "${record.order_no}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await updateOrderStatus(record.id, 'shipped')
|
||||
message.success('订单已发货')
|
||||
loadOrders()
|
||||
} catch (error) {
|
||||
@@ -376,21 +333,23 @@ const handleComplete = async (record: Order) => {
|
||||
content: `确定要完成订单 "${record.order_no}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await updateOrderStatus(record.id, 'completed')
|
||||
message.success('订单已完成')
|
||||
loadOrders()
|
||||
} catch (error) {
|
||||
message.error('操作失败')
|
||||
}
|
||||
极速版 }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleCancel = async (record: Order) => {
|
||||
Modal.confirm({
|
||||
title: '确认取消',
|
||||
content: `确定要取消订单 "${record.order极速版_no}" 吗?`,
|
||||
on极速版Ok: async () => {
|
||||
content: `确定要取消订单 "${record.order_no}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await updateOrderStatus(record.id, 'cancelled')
|
||||
message.success('订单已取消')
|
||||
loadOrders()
|
||||
} catch (error) {
|
||||
@@ -406,6 +365,7 @@ const handleRefund = async (record: Order) => {
|
||||
content: `确定要退款订单 "${record.order_no}" 吗?退款金额: ¥${record.amount}`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await updateOrderStatus(record.id, 'refunded')
|
||||
message.success('退款申请已提交')
|
||||
loadOrders()
|
||||
} catch (error) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</template>
|
||||
</a-page-header>
|
||||
|
||||
<a-tabs v-model:activeKey="activeTab" @change="handle极速版TabChange">
|
||||
<a-tabs v-model:activeKey="activeTab" @change="handleTabChange">
|
||||
<a-tab-pane key="activities" tab="推广活动">
|
||||
<a-card>
|
||||
<div class="search-container">
|
||||
@@ -27,14 +27,14 @@
|
||||
<a-form-item label="状态">
|
||||
<a-select v-model:value="searchForm.status" placeholder="全部状态" style="width: 120px" allow-clear>
|
||||
<a-select-option value="active">进行中</a-select-option>
|
||||
<a-select-option value="upcoming">未开始</a-select-极速版option>
|
||||
<a-select-option value="upcoming">未开始</a-select-option>
|
||||
<a-select-option value="ended">已结束</a-select-option>
|
||||
<a-select-option value="paused极速版">已暂停</a-select-option>
|
||||
<a-select-option value="paused">已暂停</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="活动时间">
|
||||
<a-range-picker v-model:value="searchForm.activityTime" :placeholder="['开始极速版时间', '结束时间']" />
|
||||
<a-range-picker v-model:value="searchForm.activityTime" :placeholder="['开始时间', '结束时间']" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item>
|
||||
@@ -67,7 +67,7 @@
|
||||
<template v-else-if="column.key === 'reward_amount'">
|
||||
<span v-if="record.reward_type === 'cash'">¥{{ record.reward_amount }}</span>
|
||||
<span v-else-if="record.reward_type === 'points'">{{ record.reward_amount }}积分</span>
|
||||
<span v-else-if="record.reward_type === 'coupon'">{{ record.re极速版ward_amount }}元券</span>
|
||||
<span v-else-if="record.reward_type === 'coupon'">{{ record.reward_amount }}元券</span>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.key === 'participants'">
|
||||
@@ -89,10 +89,10 @@
|
||||
|
||||
<a-button size="small" @click="handleEditActivity(record)">
|
||||
<EditOutlined />编辑
|
||||
</极速版a-button>
|
||||
</a-button>
|
||||
|
||||
<template v-if="record.status === 'active'">
|
||||
极速版 <a-button size="small" danger @click="handlePauseActivity(record)">
|
||||
<a-button size="small" danger @click="handlePauseActivity(record)">
|
||||
<PauseOutlined />暂停
|
||||
</a-button>
|
||||
</template>
|
||||
@@ -127,7 +127,7 @@
|
||||
<a-select-option value="points">积分</a-select-option>
|
||||
<a-select-option value="coupon">优惠券</a-select-option>
|
||||
</a-select>
|
||||
</极速版a-form-item>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="状态">
|
||||
<a-select v-model:value="rewardSearchForm.status" placeholder="全部状态" style="width: 120px" allow-clear>
|
||||
@@ -152,7 +152,7 @@
|
||||
:data-source="rewardList"
|
||||
:loading="rewardLoading"
|
||||
:pagination="rewardPagination"
|
||||
:极速版row-key="record => record.id"
|
||||
:row-key="record => record.id"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'reward_type'">
|
||||
@@ -177,7 +177,7 @@
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<a-button size="small" @click="handleViewRew极速版ard(record)">
|
||||
<a-button size="small" @click="handleViewReward(record)">
|
||||
<EyeOutlined />详情
|
||||
</a-button>
|
||||
</a-space>
|
||||
@@ -185,7 +185,7 @@
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</a极速版-tab-pane>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</template>
|
||||
@@ -206,33 +206,15 @@ import {
|
||||
CheckOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
interface PromotionActivity {
|
||||
id: number
|
||||
name: string
|
||||
description: string
|
||||
reward_type: string极速版
|
||||
reward_amount: number
|
||||
status: string
|
||||
start_time: string
|
||||
end_time: string
|
||||
max_participants:极速版 number
|
||||
current_participants: number
|
||||
created_at: string
|
||||
}
|
||||
|
||||
interface RewardRecord {
|
||||
id: number
|
||||
user_id: number
|
||||
user_name: string
|
||||
user_phone: string
|
||||
activity_id: number
|
||||
activity_name: string
|
||||
reward_type: string
|
||||
reward_amount: number
|
||||
status: string
|
||||
issued_at: string
|
||||
created_at: string
|
||||
}
|
||||
import {
|
||||
getPromotionActivities,
|
||||
deletePromotionActivity,
|
||||
pausePromotionActivity,
|
||||
resumePromotionActivity,
|
||||
getRewardRecords,
|
||||
issueReward
|
||||
} from '@/api/promotion'
|
||||
import type { PromotionActivity, RewardRecord } from '@/api/promotion'
|
||||
|
||||
interface SearchForm {
|
||||
name: string
|
||||
@@ -262,55 +244,13 @@ const rewardSearchForm = reactive<RewardSearchForm>({
|
||||
status: ''
|
||||
})
|
||||
|
||||
const activityList = ref<PromotionActivity[]>([
|
||||
{
|
||||
id: 1,
|
||||
name: '邀请好友得现金',
|
||||
description: '邀请好友注册即可获得现金奖励',
|
||||
reward_type: 'cash',
|
||||
reward_amount: 10,
|
||||
status: 'active',
|
||||
start_time: '极速版2024-03-01',
|
||||
end_time: '2024-03-31',
|
||||
max_participants: 1000极速版,
|
||||
current_participants: 356,
|
||||
created_at: '2024-02-20'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '分享活动得积分',
|
||||
description: '分享活动页面即可获得积分奖励',
|
||||
reward_type: 'points',
|
||||
reward_amount: 100,
|
||||
status: 'upcoming',
|
||||
start_time: '2024-04-01',
|
||||
end_time: '202极速版4-04-30',
|
||||
max_participants: 500,
|
||||
current_p极速版articipants: 0,
|
||||
created_at: '2024-03-10'
|
||||
}
|
||||
])
|
||||
|
||||
const rewardList = ref<RewardRecord[]>([
|
||||
{
|
||||
id: 1,
|
||||
user_id: 1001,
|
||||
user_name: '张先生',
|
||||
user_phone: '13800138000',
|
||||
activity_id: 1,
|
||||
activity_name: '邀请好友极速版得现金',
|
||||
reward_type: 'cash',
|
||||
reward_amount: 10,
|
||||
status: 'issued',
|
||||
issued_at: '2024-03-05 14:30:00',
|
||||
created_at: '2024-03-05 14:25:00'
|
||||
}
|
||||
])
|
||||
const activityList = ref<PromotionActivity[]>([])
|
||||
const rewardList = ref<RewardRecord[]>([])
|
||||
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 50,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
@@ -319,15 +259,15 @@ const pagination = reactive({
|
||||
const rewardPagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 30,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
})
|
||||
|
||||
const activityColumns = [
|
||||
{ title: '活动名称', dataIndex: 'name', key: '极速版name', width: 150 },
|
||||
{ title极速版: '奖励类型', key: 'reward_type', width: 100, align: 'center' },
|
||||
{ title: '活动名称', dataIndex: 'name', key: 'name', width: 150 },
|
||||
{ title: '奖励类型', key: 'reward_type', width: 100, align: 'center' },
|
||||
{ title: '奖励金额', key: 'reward_amount', width: 100, align: 'center' },
|
||||
{ title: '状态', key: 'status', width: 100, align: 'center' },
|
||||
{ title: '活动时间', key: 'time', width: 200,
|
||||
@@ -343,10 +283,10 @@ const rewardColumns = [
|
||||
{ title: '用户', dataIndex: 'user_name', key: 'user_name', width: 100 },
|
||||
{ title: '联系电话', dataIndex: 'user_phone', key: 'user_phone', width: 120 },
|
||||
{ title: '活动名称', dataIndex: 'activity_name', key: 'activity_name', width: 150 },
|
||||
{ title: '奖励类型', key: 'reward_type', width: 100, align: 'center极速版' },
|
||||
{ title: '奖励类型', key: 'reward_type', width: 100, align: 'center' },
|
||||
{ title: '奖励金额', key: 'reward_amount', width: 100, align: 'center' },
|
||||
{ title: '状态', key: 'status', width: 100, align: 'center' },
|
||||
{ title: '发放时间', dataIndex: 'issued_at极速版', key: 'issued_at', width: 极速版150 },
|
||||
{ title: '发放时间', dataIndex: 'issued_at', key: 'issued_at', width: 150 },
|
||||
{ title: '申请时间', dataIndex: 'created_at', key: 'created_at', width: 150 },
|
||||
{ title: '操作', key: 'actions', width: 120, align: 'center' }
|
||||
]
|
||||
@@ -361,7 +301,7 @@ const getStatusColor = (status: string) => {
|
||||
return colors[status as keyof typeof colors] || 'default'
|
||||
}
|
||||
|
||||
const getStatusText = (status: string)极速版 {
|
||||
const getStatusText = (status: string) => {
|
||||
const texts = {
|
||||
active: '进行中',
|
||||
upcoming: '未开始',
|
||||
@@ -382,7 +322,7 @@ const getRewardTypeText = (type: string) => {
|
||||
|
||||
const getRewardStatusColor = (status: string) => {
|
||||
const colors = {
|
||||
pending极速版: 'orange',
|
||||
pending: 'orange',
|
||||
issued: 'green',
|
||||
failed: 'red'
|
||||
}
|
||||
@@ -406,7 +346,15 @@ onMounted(() => {
|
||||
const loadActivities = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
const response = await getPromotionActivities({
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
name: searchForm.name,
|
||||
status: searchForm.status
|
||||
})
|
||||
|
||||
activityList.value = response.data
|
||||
pagination.total = response.pagination?.total || 0
|
||||
} catch (error) {
|
||||
message.error('加载活动列表失败')
|
||||
} finally {
|
||||
@@ -417,7 +365,16 @@ const loadActivities = async () => {
|
||||
const loadRewards = async () => {
|
||||
rewardLoading.value = true
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
const response = await getRewardRecords({
|
||||
page: rewardPagination.current,
|
||||
pageSize: rewardPagination.pageSize,
|
||||
user: rewardSearchForm.user,
|
||||
reward_type: rewardSearchForm.reward_type,
|
||||
status: rewardSearchForm.status
|
||||
})
|
||||
|
||||
rewardList.value = response.data
|
||||
rewardPagination.total = response.pagination?.total || 0
|
||||
} catch (error) {
|
||||
message.error('加载奖励记录失败')
|
||||
} finally {
|
||||
@@ -430,7 +387,7 @@ const handleTabChange = (key: string) => {
|
||||
loadActivities()
|
||||
} else if (key === 'rewards') {
|
||||
loadRewards()
|
||||
极速版 }
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
@@ -444,7 +401,7 @@ const handleReset = () => {
|
||||
status: '',
|
||||
activityTime: []
|
||||
})
|
||||
pagination.current = 1极速版
|
||||
pagination.current = 1
|
||||
loadActivities()
|
||||
}
|
||||
|
||||
@@ -483,15 +440,16 @@ const handleViewActivity = (record: PromotionActivity) => {
|
||||
}
|
||||
|
||||
const handleEditActivity = (record: PromotionActivity) => {
|
||||
message.info(`编辑活动: ${record.name极速版}`)
|
||||
message.info(`编辑活动: ${record.name}`)
|
||||
}
|
||||
|
||||
const handlePauseActivity = async (record: PromotionActivity) => {
|
||||
Modal.confirm({
|
||||
title: '确认暂停',
|
||||
content: `确定要暂停活动 "${record.name}" 极速版吗?`,
|
||||
content: `确定要暂停活动 "${record.name}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await pausePromotionActivity(record.id)
|
||||
message.success('活动已暂停')
|
||||
loadActivities()
|
||||
} catch (error) {
|
||||
@@ -507,6 +465,7 @@ const handleResumeActivity = async (record: PromotionActivity) => {
|
||||
content: `确定要继续活动 "${record.name}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await resumePromotionActivity(record.id)
|
||||
message.success('活动已继续')
|
||||
loadActivities()
|
||||
} catch (error) {
|
||||
@@ -524,6 +483,7 @@ const handleDeleteActivity = async (record: PromotionActivity) => {
|
||||
okType: 'danger',
|
||||
onOk: async () => {
|
||||
try {
|
||||
await deletePromotionActivity(record.id)
|
||||
message.success('活动已删除')
|
||||
loadActivities()
|
||||
} catch (error) {
|
||||
@@ -537,11 +497,12 @@ const handleIssueReward = async (record: RewardRecord) => {
|
||||
Modal.confirm({
|
||||
title: '确认发放',
|
||||
content: `确定要发放奖励给用户 "${record.user_name}" 吗?`,
|
||||
onOk: async ()极速版 => {
|
||||
onOk: async () => {
|
||||
try {
|
||||
await issueReward(record.id)
|
||||
message.success('奖励已发放')
|
||||
loadRewards()
|
||||
极速版 } catch (error) {
|
||||
} catch (error) {
|
||||
message.error('操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
<a-col :span="8">
|
||||
<a-card title="系统信息" size="small">
|
||||
<a-descriptions :column="1" bordered size="small">
|
||||
<a-descriptions-item label="系统版本">v1.0.0</a-descriptions-item>
|
||||
<a-descriptions-item label="运行环境">Production</a-descriptions-item>
|
||||
<极速版a-descriptions-item label="启动时间">2024-03-15 10:00:00</a-descriptions-item>
|
||||
<a-descriptions-item label="运行时长">12天3小时</a-descriptions-item>
|
||||
<a-descriptions-item label="系统版本">{{ systemInfo.version }}</a-descriptions-item>
|
||||
<a-descriptions-item label="运行环境">{{ systemInfo.environment }}</a-descriptions-item>
|
||||
<a-descriptions-item label="启动时间">{{ systemInfo.startTime }}</a-descriptions-item>
|
||||
<a-descriptions-item label="运行时长">{{ systemInfo.uptime }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
</a-col>
|
||||
@@ -27,11 +27,13 @@
|
||||
<a-card title="数据库状态" size="small">
|
||||
<a-descriptions :column="1" bordered size="small">
|
||||
<a-descriptions-item label="连接状态">
|
||||
<a-tag color="green">正常</a-tag>
|
||||
<a-tag :color="databaseStatus.status === 'running' ? 'green' : 'red'">
|
||||
{{ databaseStatus.status === 'running' ? '正常' : '异常' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label极速版="数据库类型">MySQL</a-descriptions-item>
|
||||
<a-descriptions-item label="连接数">15极速版/100</a-descriptions-item>
|
||||
<a-descriptions-item label="查询次数">1,234次/分钟</a-descriptions-item>
|
||||
<a-descriptions-item label="数据库类型">{{ databaseStatus.type }}</a-descriptions-item>
|
||||
<a-descriptions-item label="连接数">{{ databaseStatus.connections }}</a-descriptions-item>
|
||||
<a-descriptions-item label="查询次数">{{ databaseStatus.queriesPerMinute }}次/分钟</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
</a-col>
|
||||
@@ -40,11 +42,13 @@
|
||||
<a-card title="缓存状态" size="small">
|
||||
<a-descriptions :column="1" bordered size="small">
|
||||
<a-descriptions-item label="Redis状态">
|
||||
<a-tag color="green">正常</a-tag>
|
||||
<a-tag :color="cacheStatus.status === 'running' ? 'green' : 'red'">
|
||||
{{ cacheStatus.status === 'running' ? '正常' : '异常' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="内存使用">65%</a-descriptions-item>
|
||||
<a-descriptions-item label="命中率">92%</a-descriptions-item>
|
||||
<a-descriptions-item label="键数量">1,234</a-descriptions-item>
|
||||
<a-descriptions-item label="内存使用">{{ cacheStatus.memoryUsage }}</a-descriptions-item>
|
||||
<a-descriptions-item label="命中率">{{ cacheStatus.hitRate }}</a-descriptions-item>
|
||||
<a-descriptions-item label="键数量">{{ cacheStatus.keyCount }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
</a-col>
|
||||
@@ -90,14 +94,14 @@
|
||||
<a-col :span="12">
|
||||
<a-card title="系统日志" size="small">
|
||||
<a-timeline>
|
||||
<a-t极速版imeline-item color="green">
|
||||
<a-timeline-item color="green">
|
||||
<p>用户登录成功 - admin (2024-03-15 14:30:22)</p>
|
||||
</a-timeline-item>
|
||||
<a-timeline-item color="blue">
|
||||
<p>数据库备份完成 - 备份文件: backup_20240315.sql (2024-03-15 14:00:00)</p>
|
||||
</a-timeline-item>
|
||||
<a-timeline-item color="orange">
|
||||
<p>系统警告 - 内存使用率超过80% (2024-03-15 13:极速版45:18)</极速版p>
|
||||
<p>系统警告 - 内存使用率超过80% (2024-03-15 13:45:18)</p>
|
||||
</a-timeline-item>
|
||||
<a-timeline-item color="green">
|
||||
<p>定时任务执行 - 清理过期日志 (2024-03-15 13:30:00)</p>
|
||||
@@ -112,7 +116,7 @@
|
||||
|
||||
<a-row :gutter="16" style="margin-top: 16px;">
|
||||
<a-col :span="24">
|
||||
<a-card title="系统极速版设置" size="small">
|
||||
<a-card title="系统设置" size="small">
|
||||
<a-form :model="systemSettings" layout="vertical">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
@@ -122,17 +126,17 @@
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="系统版本">
|
||||
<a-input v-model:value="systemSettings.systemVersion" placeholder="请输入系统版本极速版" />
|
||||
<a-input v-model:value="systemSettings.systemVersion" placeholder="请输入系统版本" />
|
||||
</a-form-item>
|
||||
</极速版a-col>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="维护模式">
|
||||
<a-switch v-model:checked="systemSettings.maintenanceMode" />
|
||||
</极速版a-form-item>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="极速版16">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
<a-form-item label="会话超时(分钟)">
|
||||
<a-input-number v-model:value="systemSettings.sessionTimeout" :min="5" :max="480" style="width: 100%" />
|
||||
@@ -162,7 +166,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import {
|
||||
ReloadOutlined,
|
||||
@@ -170,47 +174,39 @@ import {
|
||||
CloudServerOutlined,
|
||||
MessageOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
import {
|
||||
getServices,
|
||||
startService,
|
||||
stopService,
|
||||
getSystemInfo,
|
||||
getDatabaseStatus,
|
||||
getCacheStatus,
|
||||
getSystemSettings,
|
||||
updateSystemSettings
|
||||
} from '@/api/system'
|
||||
import type { Service, SystemInfo, DatabaseStatus, CacheStatus, SystemSettings } from '@/api/system'
|
||||
|
||||
interface Service {
|
||||
id: number
|
||||
name: string
|
||||
type: string
|
||||
description: string
|
||||
status: string
|
||||
}
|
||||
const services = ref<Service[]>([])
|
||||
const systemInfo = ref<SystemInfo>({
|
||||
version: 'v1.0.0',
|
||||
environment: 'Production',
|
||||
uptime: '12天3小时',
|
||||
startTime: '2024-03-15 10:00:00'
|
||||
})
|
||||
|
||||
interface SystemSettings {
|
||||
systemName: string
|
||||
systemVersion: string
|
||||
maintenanceMode: boolean
|
||||
sessionTimeout: number
|
||||
pageSize: number
|
||||
enableSwagger: boolean
|
||||
}
|
||||
const databaseStatus = ref<DatabaseStatus>({
|
||||
status: 'running',
|
||||
type: 'MySQL',
|
||||
connections: '15/100',
|
||||
queriesPerMinute: 1234
|
||||
})
|
||||
|
||||
const services = ref<Service[]>([
|
||||
{
|
||||
id: 1,
|
||||
name: 'MySQL数据库',
|
||||
type: 'database',
|
||||
description: '主数据库服务',
|
||||
status: 'running'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Redis缓存',
|
||||
type: 'cache',
|
||||
description: '缓存服务',
|
||||
status: 'running'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'RabbitMQ',
|
||||
type: 'mq',
|
||||
description: '消息队列服务',
|
||||
status: 'stopped'
|
||||
}
|
||||
])
|
||||
const cacheStatus = ref<CacheStatus>({
|
||||
status: 'running',
|
||||
memoryUsage: '65%',
|
||||
hitRate: '92%',
|
||||
keyCount: 1234
|
||||
})
|
||||
|
||||
const systemSettings = reactive<SystemSettings>({
|
||||
systemName: '结伴客管理系统',
|
||||
@@ -221,18 +217,76 @@ const systemSettings = reactive<SystemSettings>({
|
||||
enableSwagger: true
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
loadSystemInfo()
|
||||
loadDatabaseStatus()
|
||||
loadCacheStatus()
|
||||
loadServices()
|
||||
loadSystemSettings()
|
||||
})
|
||||
|
||||
const loadSystemInfo = async () => {
|
||||
try {
|
||||
const response = await getSystemInfo()
|
||||
systemInfo.value = response.data
|
||||
} catch (error) {
|
||||
message.error('加载系统信息失败')
|
||||
}
|
||||
}
|
||||
|
||||
const loadDatabaseStatus = async () => {
|
||||
try {
|
||||
const response = await getDatabaseStatus()
|
||||
databaseStatus.value = response.data
|
||||
} catch (error) {
|
||||
message.error('加载数据库状态失败')
|
||||
}
|
||||
}
|
||||
|
||||
const loadCacheStatus = async () => {
|
||||
try {
|
||||
const response = await getCacheStatus()
|
||||
cacheStatus.value = response.data
|
||||
} catch (error) {
|
||||
message.error('加载缓存状态失败')
|
||||
}
|
||||
}
|
||||
|
||||
const loadServices = async () => {
|
||||
try {
|
||||
const response = await getServices()
|
||||
services.value = response.data
|
||||
} catch (error) {
|
||||
message.error('加载服务列表失败')
|
||||
}
|
||||
}
|
||||
|
||||
const loadSystemSettings = async () => {
|
||||
try {
|
||||
const response = await getSystemSettings()
|
||||
Object.assign(systemSettings, response.data)
|
||||
} catch (error) {
|
||||
message.error('加载系统设置失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handleRefresh = () => {
|
||||
loadSystemInfo()
|
||||
loadDatabaseStatus()
|
||||
loadCacheStatus()
|
||||
loadServices()
|
||||
message.success('系统状态已刷新')
|
||||
}
|
||||
|
||||
const handleStopService = (service: Service极速版) => {
|
||||
const handleStopService = (service: Service) => {
|
||||
Modal.confirm({
|
||||
title: '确认停止',
|
||||
content: `确定要停止服务 "${service.name}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
service.status = 'stopped'
|
||||
await stopService(service.id)
|
||||
message.success('服务已停止')
|
||||
loadServices()
|
||||
} catch (error) {
|
||||
message.error('操作失败')
|
||||
}
|
||||
@@ -246,8 +300,9 @@ const handleStartService = (service: Service) => {
|
||||
content: `确定要启动服务 "${service.name}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
service.status = 'running'
|
||||
await startService(service.id)
|
||||
message.success('服务已启动')
|
||||
loadServices()
|
||||
} catch (error) {
|
||||
message.error('操作失败')
|
||||
}
|
||||
@@ -259,17 +314,22 @@ const viewLogs = () => {
|
||||
message.info('查看系统日志功能开发中')
|
||||
}
|
||||
|
||||
const saveSettings = () => {
|
||||
message.success('系统设置已保存')
|
||||
const saveSettings = async () => {
|
||||
try {
|
||||
await updateSystemSettings(systemSettings)
|
||||
message.success('系统设置已保存')
|
||||
} catch (error) {
|
||||
message.error('保存设置失败')
|
||||
}
|
||||
}
|
||||
|
||||
const resetSettings = () => {
|
||||
Object.assign(systemSettings, {
|
||||
systemName: '结伴客管理系统',
|
||||
systemVersion: 'v1.0.极速版0',
|
||||
systemVersion: 'v1.0.0',
|
||||
maintenanceMode: false,
|
||||
sessionTimeout: 30,
|
||||
pageSize: 极速版20,
|
||||
pageSize: 20,
|
||||
enableSwagger: true
|
||||
})
|
||||
message.success('设置已重置')
|
||||
|
||||
@@ -150,19 +150,8 @@ import {
|
||||
RocketOutlined,
|
||||
CloseOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
interface TravelPlan {
|
||||
id: number
|
||||
destination: string
|
||||
start_date: string
|
||||
end_date: string
|
||||
budget: number
|
||||
max_members: number
|
||||
current_members: number
|
||||
status: string
|
||||
creator: string
|
||||
created_at: string
|
||||
}
|
||||
import { getTravelPlans, closeTravelPlan } from '@/api/travel'
|
||||
import type { TravelPlan } from '@/api/travel'
|
||||
|
||||
interface SearchForm {
|
||||
destination: string
|
||||
@@ -178,38 +167,11 @@ const searchForm = reactive<SearchForm>({
|
||||
travelTime: []
|
||||
})
|
||||
|
||||
// 模拟旅行数据
|
||||
const travelList = ref<TravelPlan[]>([
|
||||
{
|
||||
id: 1,
|
||||
destination: '西藏',
|
||||
start_date: '2024-07-01',
|
||||
end_date: '2024-07-15',
|
||||
budget: 5000,
|
||||
max_members: 6,
|
||||
current_members: 3,
|
||||
status: 'recruiting',
|
||||
creator: '旅行爱好者',
|
||||
created_at: '2024-06-01'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
destination: '云南',
|
||||
start_date: '2024-08-10',
|
||||
end_date: '2024-08-20',
|
||||
budget: 3000,
|
||||
max_members: 4,
|
||||
current_members: 4,
|
||||
status: 'full',
|
||||
creator: '探险家',
|
||||
created_at: '2024-07-15'
|
||||
}
|
||||
])
|
||||
|
||||
const travelList = ref<TravelPlan[]>([])
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 50,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
@@ -289,8 +251,15 @@ onMounted(() => {
|
||||
const loadTravelPlans = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// TODO: 调用真实API
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
const response = await getTravelPlans({
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
destination: searchForm.destination,
|
||||
status: searchForm.status
|
||||
})
|
||||
|
||||
travelList.value = response.data
|
||||
pagination.total = response.pagination?.total || 0
|
||||
} catch (error) {
|
||||
message.error('加载旅行计划失败')
|
||||
} finally {
|
||||
@@ -299,7 +268,7 @@ const loadTravelPlans = async () => {
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.current = 极速版1
|
||||
pagination.current = 1
|
||||
loadTravelPlans()
|
||||
}
|
||||
|
||||
@@ -346,12 +315,13 @@ const handlePromote = (record: TravelPlan) => {
|
||||
})
|
||||
}
|
||||
|
||||
const handleClose = (record: TravelPlan) => {
|
||||
const handleClose = async (record: TravelPlan) => {
|
||||
Modal.confirm({
|
||||
title: '确认关闭',
|
||||
content: `确定要关闭旅行计划 "${record.destination}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
await closeTravelPlan(record.id)
|
||||
message.success('旅行计划已关闭')
|
||||
loadTravelPlans()
|
||||
} catch (error) {
|
||||
|
||||
@@ -251,20 +251,8 @@ import {
|
||||
DownOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
import type { TableProps } from 'ant-design-vue'
|
||||
|
||||
interface User {
|
||||
id: number
|
||||
username: string
|
||||
nickname: string
|
||||
avatar: string
|
||||
email: string
|
||||
phone: string
|
||||
status: string
|
||||
level: number
|
||||
points: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
import { getUsers, updateUser, createUser, deleteUser } from '@/api/user'
|
||||
import type { User } from '@/api/user'
|
||||
|
||||
interface SearchForm {
|
||||
keyword: string
|
||||
@@ -324,40 +312,11 @@ const formRules = {
|
||||
]
|
||||
}
|
||||
|
||||
// 模拟用户数据
|
||||
const userList = ref<User[]>([
|
||||
{
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
nickname: '系统管理员',
|
||||
avatar: 'https://api.dicebear.com/7.x/miniavs/svg?seed=admin',
|
||||
email: 'admin@jiebanke.com',
|
||||
phone: '13800138000',
|
||||
status: 'active',
|
||||
level: 10,
|
||||
points: 10000,
|
||||
created_at: '2024-01-01',
|
||||
updated_at: '2024-01-01'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
username: 'user001',
|
||||
nickname: '旅行爱好者',
|
||||
avatar: 'https://api.dicebear.com/7.x/miniavs/svg?seed=user1',
|
||||
email: 'user001@example.com',
|
||||
phone: '13800138001',
|
||||
status: 'active',
|
||||
level: 3,
|
||||
points: 1500,
|
||||
created_at: '2024-02-15',
|
||||
updated_at: '2024-02-15'
|
||||
}
|
||||
])
|
||||
|
||||
const userList = ref<User[]>([])
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 50,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
@@ -458,15 +417,15 @@ onMounted(() => {
|
||||
const loadUsers = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// TODO: 调用真实API
|
||||
// const response = await userAPI.getUsers({
|
||||
// page: pagination.current,
|
||||
// pageSize: pagination.pageSize,
|
||||
// ...searchForm
|
||||
// })
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
// userList.value = response.data.users
|
||||
// pagination.total = response.data.pagination.total
|
||||
const response = await getUsers({
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword,
|
||||
status: searchForm.status
|
||||
})
|
||||
|
||||
userList.value = response.data
|
||||
pagination.total = response.pagination?.total || 0
|
||||
} catch (error) {
|
||||
message.error('加载用户列表失败')
|
||||
} finally {
|
||||
@@ -539,7 +498,7 @@ const handleDisable = async (record: User) => {
|
||||
content: `确定要禁用用户 "${record.nickname}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
// await userAPI.updateUser(record.id, { status: 'inactive' })
|
||||
await updateUser(record.id, { status: 'inactive' })
|
||||
message.success('用户已禁用')
|
||||
loadUsers()
|
||||
} catch (error) {
|
||||
@@ -555,7 +514,7 @@ const handleEnable = async (record: User) => {
|
||||
content: `确定要启用用户 "${record.nickname}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
// await userAPI.updateUser(record.id, { status: 'active' })
|
||||
await updateUser(record.id, { status: 'active' })
|
||||
message.success('用户已启用')
|
||||
loadUsers()
|
||||
} catch (error) {
|
||||
@@ -571,7 +530,7 @@ const handleBan = async (record: User) => {
|
||||
content: `确定要封禁用户 "${record.nickname}" 吗?`,
|
||||
onOk: async () => {
|
||||
try {
|
||||
// await userAPI.updateUser(record.id, { status: 'banned' })
|
||||
await updateUser(record.id, { status: 'banned' })
|
||||
message.success('用户已封禁')
|
||||
loadUsers()
|
||||
} catch (error) {
|
||||
@@ -590,7 +549,7 @@ const handleDelete = async (record: User) => {
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
try {
|
||||
// await userAPI.deleteUser(record.id)
|
||||
await deleteUser(record.id)
|
||||
message.success('用户已删除')
|
||||
loadUsers()
|
||||
} catch (error) {
|
||||
@@ -607,11 +566,11 @@ const handleModalOk = async () => {
|
||||
|
||||
if (editingUser.value) {
|
||||
// 编辑用户
|
||||
// await userAPI.updateUser(editingUser.value.id, formState)
|
||||
await updateUser(editingUser.value.id, formState)
|
||||
message.success('用户信息更新成功')
|
||||
} else {
|
||||
// 创建用户
|
||||
// await userAPI.createUser(formState)
|
||||
await createUser(formState)
|
||||
message.success('用户创建成功')
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user