309 lines
10 KiB
TypeScript
309 lines
10 KiB
TypeScript
import {
|
|
mockAdminUsers,
|
|
mockCategories,
|
|
mockDashboardData,
|
|
mockPlatformComments,
|
|
mockPlatformUsers,
|
|
mockPlatformVideos,
|
|
mockStatistics,
|
|
mockTags,
|
|
paginate
|
|
} from './data'
|
|
|
|
const delay = (ms = 120) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
|
|
const mockStore = {
|
|
adminUsers: [...mockAdminUsers],
|
|
users: [...mockPlatformUsers],
|
|
videos: [...mockPlatformVideos],
|
|
comments: [...mockPlatformComments],
|
|
categories: [...mockCategories],
|
|
tags: [...mockTags]
|
|
}
|
|
|
|
function normalize(url: string) {
|
|
return url.replace(/^\/api\/admin/, '')
|
|
}
|
|
|
|
function matchPath(path: string, pattern: string) {
|
|
const pathParts = path.split('/').filter(Boolean)
|
|
const patternParts = pattern.split('/').filter(Boolean)
|
|
if (pathParts.length !== patternParts.length) return false
|
|
return patternParts.every((part, index) => part.startsWith(':') || part === pathParts[index])
|
|
}
|
|
|
|
function pathParam(path: string, indexFromEnd = 1) {
|
|
const parts = path.split('/').filter(Boolean)
|
|
return Number(parts[parts.length - indexFromEnd])
|
|
}
|
|
|
|
function filterByKeyword<T>(list: T[], getter: (item: T) => string, keyword?: string) {
|
|
if (!keyword) return list
|
|
const needle = keyword.toLowerCase()
|
|
return list.filter((item) => getter(item).toLowerCase().includes(needle))
|
|
}
|
|
|
|
export async function mockRequest(url: string, options: any = {}) {
|
|
const method = (options.method || 'GET').toUpperCase()
|
|
const path = normalize(url).split('?')[0]
|
|
const params = options.params || {}
|
|
const body = options.body || {}
|
|
|
|
await delay()
|
|
|
|
if (method === 'GET' && path === '/auth/captcha') {
|
|
return ok({
|
|
captchaKey: `admin-captcha-${Date.now()}`,
|
|
captchaImage: `data:image/svg+xml;utf8,${encodeURIComponent(`
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="40" viewBox="0 0 120 40">
|
|
<rect width="120" height="40" rx="8" fill="#eef2ff"/>
|
|
<path d="M8 27 C22 9, 40 34, 56 12 S88 34, 112 10" stroke="#c7d2fe" stroke-width="2" fill="none"/>
|
|
<text x="16" y="28" fill="#1d4ed8" font-size="24" font-family="Georgia" transform="rotate(-8 16 28)">2</text>
|
|
<text x="40" y="28" fill="#0f766e" font-size="24" font-family="Georgia" transform="rotate(7 40 28)">4</text>
|
|
<text x="66" y="28" fill="#be185d" font-size="24" font-family="Georgia" transform="rotate(-6 66 28)">6</text>
|
|
<text x="92" y="28" fill="#7c3aed" font-size="24" font-family="Georgia" transform="rotate(8 92 28)">8</text>
|
|
</svg>
|
|
`)}`
|
|
})
|
|
}
|
|
|
|
if (method === 'POST' && path === '/auth/login') {
|
|
return ok({
|
|
accessToken: `admin-token-${Date.now()}`,
|
|
refreshToken: `admin-refresh-${Date.now()}`,
|
|
tokenType: 'Bearer',
|
|
expiresIn: 7200,
|
|
adminId: 1,
|
|
username: body.username || 'admin'
|
|
})
|
|
}
|
|
|
|
if (method === 'POST' && path === '/auth/logout') {
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/auth/info') {
|
|
return ok(mockStore.adminUsers[0])
|
|
}
|
|
|
|
if (method === 'GET' && path === '/statistics/dashboard') {
|
|
return ok(mockDashboardData)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/statistics/overview') {
|
|
return ok(mockStatistics)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/statistics/user/trend') {
|
|
return ok(mockStatistics.userTrend)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/statistics/video/trend') {
|
|
return ok(mockStatistics.videoTrend)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/statistics/view/trend') {
|
|
return ok(mockStatistics.viewTrend)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/platform/user/stats') {
|
|
const { totalUsers, newUsersToday, activeUsersToday, userGrowthRate } = mockStatistics
|
|
return ok({ totalUsers, newUsersToday, activeUsersToday, userGrowthRate })
|
|
}
|
|
|
|
if (method === 'GET' && path === '/platform/content/video/stats') {
|
|
const { totalVideos, newVideosToday, pendingReview, videoGrowthRate } = mockStatistics
|
|
return ok({ totalVideos, newVideosToday, pendingReview, videoGrowthRate })
|
|
}
|
|
|
|
if (method === 'GET' && path === '/admin/stats') {
|
|
return ok({
|
|
totalComments: mockStatistics.totalComments,
|
|
commentsToday: 84,
|
|
commentGrowthRate: 5.8
|
|
})
|
|
}
|
|
|
|
if (method === 'GET' && path === '/platform/user/list') {
|
|
let list = [...mockStore.users]
|
|
list = filterByKeyword(list, (item) => `${item.username} ${item.nickname} ${item.phone}`, params.keyword)
|
|
if (params.status !== undefined && params.status !== '') {
|
|
list = list.filter((item) => item.status === Number(params.status))
|
|
}
|
|
return ok(paginate(list, Number(params.page || 1), Number(params.size || 10)))
|
|
}
|
|
|
|
if (method === 'GET' && matchPath(path, '/platform/user/:id')) {
|
|
return ok(mockStore.users.find((item) => item.id === pathParam(path)) || mockStore.users[0])
|
|
}
|
|
|
|
if (method === 'PUT' && matchPath(path, '/platform/user/:id/status/:status')) {
|
|
const user = mockStore.users.find((item) => item.id === pathParam(path, 2))
|
|
if (user) user.status = pathParam(path)
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'PUT' && matchPath(path, '/platform/user/:id/reset-password')) {
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/platform/content/video/list') {
|
|
let list = [...mockStore.videos]
|
|
list = filterByKeyword(list, (item) => item.title, params.keyword)
|
|
if (params.status !== undefined && params.status !== '') {
|
|
list = list.filter((item) => item.status === Number(params.status))
|
|
}
|
|
if (params.auditStatus !== undefined && params.auditStatus !== '') {
|
|
list = list.filter((item) => item.auditStatus === Number(params.auditStatus))
|
|
}
|
|
if (params.categoryId) {
|
|
list = list.filter((item) => item.categoryId === Number(params.categoryId))
|
|
}
|
|
return ok(paginate(list, Number(params.page || 1), Number(params.size || 10)))
|
|
}
|
|
|
|
if (method === 'GET' && matchPath(path, '/platform/content/video/:id')) {
|
|
return ok(mockStore.videos.find((item) => item.id === pathParam(path)) || mockStore.videos[0])
|
|
}
|
|
|
|
if (method === 'POST' && matchPath(path, '/platform/content/video/review/:id')) {
|
|
const video = mockStore.videos.find((item) => item.id === pathParam(path))
|
|
if (video) {
|
|
video.auditStatus = Number(body.status)
|
|
video.auditReason = body.reason || ''
|
|
video.status = Number(body.status) === 1 ? 1 : 2
|
|
video.publishTime = Number(body.status) === 1 ? '2026-03-22 10:30:00' : ''
|
|
}
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'PUT' && matchPath(path, '/platform/content/video/disable/:id')) {
|
|
const video = mockStore.videos.find((item) => item.id === pathParam(path))
|
|
if (video) video.status = 3
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/admin/list') {
|
|
let list = [...mockStore.comments]
|
|
list = filterByKeyword(list, (item) => item.content, params.keyword)
|
|
if (params.status !== undefined && params.status !== '') {
|
|
list = list.filter((item) => item.status === Number(params.status))
|
|
}
|
|
return ok(paginate(list, Number(params.page || 1), Number(params.size || 10)))
|
|
}
|
|
|
|
if (method === 'DELETE' && matchPath(path, '/admin/:id')) {
|
|
const comment = mockStore.comments.find((item) => item.id === pathParam(path))
|
|
if (comment) comment.status = 0
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/platform/content/category/list') {
|
|
return ok([...mockStore.categories].sort((a, b) => a.sort - b.sort))
|
|
}
|
|
|
|
if (method === 'POST' && path === '/platform/content/category') {
|
|
mockStore.categories.push({
|
|
id: mockStore.categories.length + 10,
|
|
name: body.name,
|
|
parentId: body.parentId || 0,
|
|
sort: body.sort || 0,
|
|
icon: body.icon || ''
|
|
})
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'PUT' && path === '/platform/content/category') {
|
|
const category = mockStore.categories.find((item) => item.id === body.id)
|
|
if (category) Object.assign(category, body)
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'DELETE' && matchPath(path, '/platform/content/category/:id')) {
|
|
mockStore.categories = mockStore.categories.filter((item) => item.id !== pathParam(path))
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/content/tag/page') {
|
|
const list = filterByKeyword([...mockStore.tags], (item) => item.name, params.keyword)
|
|
return ok(paginate(list, Number(params.page || 1), Number(params.size || 10)))
|
|
}
|
|
|
|
if (method === 'POST' && path === '/content/tag') {
|
|
mockStore.tags.unshift({
|
|
id: mockStore.tags.length + 1,
|
|
name: body.name,
|
|
useCount: 0,
|
|
createTime: '2026-03-22 10:00:00'
|
|
})
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'PUT' && path === '/content/tag') {
|
|
const tag = mockStore.tags.find((item) => item.id === body.id)
|
|
if (tag) tag.name = body.name
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'DELETE' && matchPath(path, '/content/tag/:id')) {
|
|
mockStore.tags = mockStore.tags.filter((item) => item.id !== pathParam(path))
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'GET' && path === '/user/list') {
|
|
const list = filterByKeyword([...mockStore.adminUsers], (item) => `${item.username} ${item.nickname}`, params.keyword)
|
|
return ok(paginate(list, Number(params.page || 1), Number(params.size || 10)))
|
|
}
|
|
|
|
if (method === 'POST' && path === '/user') {
|
|
mockStore.adminUsers.push({
|
|
id: mockStore.adminUsers.length + 1,
|
|
username: body.username,
|
|
nickname: body.nickname,
|
|
avatar: 'https://picsum.photos/seed/newadmin/120/120',
|
|
email: body.email || '',
|
|
phone: body.phone || '',
|
|
role: body.role || 'manager',
|
|
status: 1,
|
|
lastLoginTime: '',
|
|
lastLoginIp: '',
|
|
createTime: '2026-03-22 10:00:00'
|
|
})
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'PUT' && path === '/user') {
|
|
const admin = mockStore.adminUsers.find((item) => item.id === body.id)
|
|
if (admin) Object.assign(admin, body)
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'PUT' && matchPath(path, '/user/:id/status/:status')) {
|
|
const admin = mockStore.adminUsers.find((item) => item.id === pathParam(path, 2))
|
|
if (admin) admin.status = pathParam(path)
|
|
return ok(null)
|
|
}
|
|
|
|
if (method === 'PUT' && matchPath(path, '/user/:id/reset-password')) {
|
|
return ok(null)
|
|
}
|
|
|
|
return {
|
|
code: 404,
|
|
message: `未找到 Mock 处理器: ${method} ${path}`,
|
|
data: null
|
|
}
|
|
}
|
|
|
|
function ok(data: any) {
|
|
return {
|
|
code: 200,
|
|
message: 'success',
|
|
data
|
|
}
|
|
}
|
|
|
|
export function isMockEnabled() {
|
|
return import.meta.env.VITE_MOCK === 'true' || import.meta.env.VITE_MOCK === true
|
|
}
|