import { useAuth } from '../composables/useAuth' export const API_BASE = '/api' export interface ApiResponse { code: number message: string result: T } export interface ParseApiOptions { skipSessionExpired?: boolean } export async function parseApiResponse(response: Response, options?: ParseApiOptions): Promise { let data: ApiResponse try { data = await response.json() } catch { throw new Error('响应解析失败') } if (data.code === 401 && !options?.skipSessionExpired) { const { handleSessionExpired } = useAuth() handleSessionExpired() throw new Error(data.message || '登录已过期,请重新登录') } if (data.code !== 200) { throw new Error(data.message || '请求失败') } return data.result } // 带认证的 fetch,仅附加 Authorization,业务状态由 parseApiResponse 解析 export async function authFetch(input: RequestInfo | URL, init: RequestInit = {}): Promise { const { getToken } = useAuth() const headers = new Headers(init.headers) const token = getToken() if (token && !headers.has('Authorization')) { headers.set('Authorization', `Bearer ${token}`) } return fetch(input, { ...init, headers }) } export async function authFetchJson( input: RequestInfo | URL, init: RequestInit = {}, options?: ParseApiOptions ): Promise { const response = await authFetch(input, init) return parseApiResponse(response, options) } export async function fetchJson( input: RequestInfo | URL, init: RequestInit = {}, options?: ParseApiOptions ): Promise { const response = await fetch(input, init) return parseApiResponse(response, options) } // 通用请求头配置 export const getAuthHeaders = () => { const token = localStorage.getItem('token') return { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) } } // 认证相关类型 export interface User { id: number username: string email: string role: string isActive: number createdAt: string updatedAt: string } export interface LoginRequest { username: string password: string } export interface LoginResponse { token: string user: User expire: number } // 角色相关类型 export interface Role { id: number name: string description: string createdAt: string updatedAt: string } // 作品相关类型 export interface Work { id: string title: string category: string year: string heroImg: string desc: string techStack: { category: string; items: string[] }[] gallery: string[] links: { live?: string; github?: string; demo?: string } next: string } // 分类相关类型 export interface Category { id: number name: string slug: string description: string sortOrder: number createdAt: string updatedAt: string } // 专栏相关类型 export interface Column { id: number name: string description: string cover: string isActive: number sortOrder: number createdAt: string updatedAt: string } // 标签相关类型 export interface Tag { id: number name: string slug: string createdAt: string updatedAt: string } // 文章相关类型 export interface Post { id: number title: string categoryId: number categoryName?: string // Display name categorySlug?: string category?: Category // Optional full object columnId?: number | null columnName?: string tags?: Tag[] date: string excerpt?: string content?: string isPublished?: number readCount?: number } export interface PostHistory { id: number postId: number version: number title: string categoryId: number categoryName?: string columnId?: number columnName?: string tagIds?: number[] tagNames?: string[] excerpt?: string content?: string isPublished: number modifiedBy: number modifiedByName?: string modifiedAt: string createdAt: string } export interface PostHistoryFieldDiff { from: string to: string changed: boolean diff?: string } export interface PostHistoryDiff { fromVersion: number toVersion: number fields: Record } export interface HotSearchKeyword { keyword: string count: number } // 代码类型 export interface CodeType { id: number name: string category: number // 0前端 1后端 2其他 } export const CODE_TYPE_CATEGORY_LABELS: Record = { 0: '前端', 1: '后端', 2: '其他' } export const getCodeTypes = async (): Promise => { const response = await fetch(`${API_BASE}/code-types`) return await parseApiResponse(response) } export const getAdminCodeTypes = async (): Promise => { const response = await authFetch(`${API_BASE}/admin/code-types`, { headers: getAuthHeaders() }) return await parseApiResponse(response) } export const createCodeType = async (data: Omit): Promise => { const response = await authFetch(`${API_BASE}/admin/code-types`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } export const updateCodeType = async (id: number, data: Omit): Promise => { const response = await authFetch(`${API_BASE}/admin/code-types/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } export const deleteCodeType = async (id: number): Promise => { const response = await authFetch(`${API_BASE}/admin/code-types/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } // 代码片段相关类型 export interface Snippet { id: string title: string code: string type: string codeTypeId?: number codeType?: CodeType description?: string viewCount?: number } // 系统配置相关类型 export interface Setting { id: number keyName: string value: string description: string createdAt: string updatedAt: string } // 操作日志相关类型 export interface OperationLog { id: number userId: number username: string ip: string region?: string path: string method: string action?: string params: string status: number duration: number createdAt: string } // 分页响应类型 export interface PaginationResponse { list: T[] total: number page: number size: number } // 登录API export const login = async (credentials: LoginRequest): Promise => { try { const response = await fetch(`${API_BASE}/admin/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credentials), }) const result = await parseApiResponse<{ token: string; user: User; expire: number }>(response, { skipSessionExpired: true, }) return { token: result.token, user: result.user, expire: result.expire, } } catch (error) { console.error('Login error:', error) throw error } } // 用户管理API export interface GetUsersParams { page?: number pageSize?: number keyword?: string } export const getUsersPaginated = async (params: GetUsersParams = {}): Promise> => { const page = params.page ?? 1 const pageSize = params.pageSize ?? 10 const qs = new URLSearchParams({ page: String(page), pageSize: String(pageSize) }) if (params.keyword) qs.set('keyword', params.keyword) const response = await authFetch(`${API_BASE}/admin/users?${qs}`, { headers: getAuthHeaders() }) return await parseApiResponse(response) } export const getUsers = async (): Promise => { try { const data = await getUsersPaginated({ page: 1, pageSize: 1000 }) return data.list } catch (error) { console.error('Get users error:', error) throw error } } export const fetchUser = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/users/${id}`, { headers: getAuthHeaders() }) return await parseApiResponse(response) } catch (error) { console.error(`Error fetching user ${id}:`, error) throw error } } export const createUser = async (userData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/users`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(userData) }) await parseApiResponse(response) } catch (error) { console.error('Create user error:', error) throw error } } export const updateUser = async (id: number, userData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/users/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(userData) }) await parseApiResponse(response) } catch (error) { console.error('Update user error:', error) throw error } } export const deleteUser = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/users/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete user error:', error) throw error } } // 角色管理API export const getRoles = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/roles`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { console.error('Get roles error:', error) throw error } } export const createRole = async (roleData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/roles`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(roleData) }) await parseApiResponse(response) } catch (error) { console.error('Create role error:', error) throw error } } export const updateRole = async (id: number, roleData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/roles/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(roleData) }) await parseApiResponse(response) } catch (error) { console.error('Update role error:', error) throw error } } export const deleteRole = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/roles/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete role error:', error) throw error } } export const fetchRole = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/roles/${id}`, { headers: getAuthHeaders() }) return await parseApiResponse(response) } catch (error) { console.error(`Error fetching role ${id}:`, error) throw error } } // 作品管理API export const getAdminWorks = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/works`, { headers: getAuthHeaders() }) const data = await parseApiResponse>(response) const list = data?.list return (list && Array.isArray(list)) ? list : [] } catch (error) { console.error('Get admin works error:', error) throw error } } export const fetchWorks = async (): Promise => { try { const result = await fetchJson(`${API_BASE}/works`) if (!result) { return [] } if (!Array.isArray(result)) { return [] } // 确保每个 work 对象的字段格式正确 return result.map((work: any) => ({ id: work.id || '', title: work.title || '', category: work.category || '', year: work.year || '', heroImg: work.heroImg || '', desc: work.desc || '', techStack: Array.isArray(work.techStack) ? work.techStack : [], gallery: Array.isArray(work.gallery) ? work.gallery : [], links: work.links || {}, next: work.next || '' })) as Work[] } catch (error) { console.error('Error fetching works:', error) return [] } } export const fetchWork = async (id: string): Promise => { try { const result = await fetchJson(`${API_BASE}/works/${id}`) if (!result) { throw new Error('Work not found') } // 确保 techStack 和 gallery 始终是数组 if (!Array.isArray(result.techStack)) { result.techStack = [] } if (!Array.isArray(result.gallery)) { result.gallery = [] } return result } catch (error) { console.error(`Error fetching work ${id}:`, error) return { id: 'default', title: '默认作品', category: '默认分类', year: '2024', heroImg: '', desc: '', techStack: [], gallery: [], links: {}, next: '' } } } export const createWork = async (workData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/works`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(workData) }) await parseApiResponse(response) } catch (error) { console.error('Create work error:', error) throw error } } export const updateWork = async (id: string, workData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/works/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(workData) }) await parseApiResponse(response) } catch (error) { console.error('Update work error:', error) throw error } } export const deleteWork = async (id: string): Promise => { try { const response = await authFetch(`${API_BASE}/admin/works/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete work error:', error) throw error } } // 文章管理API export const getAdminPosts = async ( page: number = 1, pageSize: number = 20, keyword?: string ): Promise> => { try { const params = new URLSearchParams() params.append('page', page.toString()) params.append('pageSize', pageSize.toString()) if (keyword) { params.append('keyword', keyword) } const response = await authFetch(`${API_BASE}/admin/posts?${params.toString()}`, { headers: getAuthHeaders() }) return await parseApiResponse(response) } catch (error) { console.error('Get admin posts error:', error) throw error } } export const fetchPosts = async ( query?: string, categoryId?: number, tagId?: number, columnId?: number, page?: number, pageSize?: number ): Promise> => { try { let url = `${API_BASE}/posts` const params = new URLSearchParams() if (query) params.append('q', query) if (categoryId) params.append('category', categoryId.toString()) if (tagId) params.append('tag', tagId.toString()) if (columnId) params.append('column', columnId.toString()) if (page) params.append('page', page.toString()) if (pageSize) params.append('pageSize', pageSize.toString()) if (params.toString()) { url += `?${params.toString()}` } const data = await fetchJson | Post[]>(url) // 返回分页格式的响应 if (data && typeof data === 'object' && 'list' in data) { return data as PaginationResponse } // 兼容旧格式(直接返回数组) const list = Array.isArray(data) ? data : [] return { list, total: list.length, page: page || 1, size: pageSize || list.length } } catch (error) { console.error('Error fetching posts:', error) return { list: [], total: 0, page: page || 1, size: pageSize || 10 } } } export const fetchPost = async (id: number | string): Promise => { try { const response = await fetch(`${API_BASE}/posts/${id}`) return await parseApiResponse(response) } catch (error) { console.error(`Error fetching post ${id}:`, error) // Return empty fallback return { id: Number(id), title: '未知文章', categoryId: 0, date: '2024-01-01' } } } // 获取推荐文章(基于IP的协同过滤) export const getRecommendedPosts = async (postId: number | string, limit: number = 3): Promise => { try { const response = await fetch(`${API_BASE}/posts/${postId}/recommendations?limit=${limit}`) return await parseApiResponse(response) || [] } catch (error) { console.error(`Error fetching recommended posts for ${postId}:`, error) return [] } } export const createPost = async (postData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/posts`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(postData) }) await parseApiResponse(response) } catch (error) { console.error('Create post error:', error) throw error } } export const updatePost = async (id: number | string, postData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/posts/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(postData) }) await parseApiResponse(response) } catch (error) { console.error('Update post error:', error) throw error } } // 更新文章关联关系(只更新分类、专栏、标签,不更新内容) export const updatePostRelations = async ( id: number | string, relations: { categoryId: number; columnId: number | null; tagIds: number[] } ): Promise => { try { const payload: any = { categoryId: relations.categoryId, tagIds: relations.tagIds } if (relations.columnId !== null && relations.columnId > 0) { payload.columnId = relations.columnId } else { payload.columnId = null } const response = await authFetch(`${API_BASE}/admin/posts/${id}/relations`, { method: 'PATCH', headers: getAuthHeaders(), body: JSON.stringify(payload) }) await parseApiResponse(response) } catch (error) { console.error('Update post relations error:', error) throw error } } export const togglePostStatus = async (id: number, isPublished: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/posts/${id}/status`, { method: 'PATCH', headers: getAuthHeaders(), body: JSON.stringify({ isPublished }) }) await parseApiResponse(response) } catch (error) { console.error('Toggle post status error:', error) throw error } } export const deletePost = async (id: number | string): Promise => { try { const response = await authFetch(`${API_BASE}/admin/posts/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete post error:', error) throw error } } // 分类管理API export const fetchCategories = async (): Promise => { try { const response = await fetch(`${API_BASE}/categories`) return await parseApiResponse(response) || [] } catch (error) { console.error('Fetch categories error:', error) return [] } } export const getAdminCategories = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/categories`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { console.error('Get admin categories error:', error) throw error } } export const createCategory = async (data: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/categories`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { throw error } } export const updateCategory = async (id: number, data: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/categories/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { throw error } } export const deleteCategory = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/categories/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { throw error } } // 专栏管理API export const fetchColumns = async (): Promise => { try { const response = await fetch(`${API_BASE}/columns`) return await parseApiResponse(response) || [] } catch (error) { return [] } } export const fetchColumn = async (id: number): Promise => { try { const response = await fetch(`${API_BASE}/columns/${id}`) return await parseApiResponse(response) } catch (error) { throw error } } export const getAdminColumns = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/columns`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { throw error } } export const createColumn = async (data: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/columns`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { throw error } } export const updateColumn = async (id: number, data: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/columns/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { throw error } } export const deleteColumn = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/columns/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { throw error } } export const fetchColumnPosts = async (id: number): Promise => { try { const response = await fetch(`${API_BASE}/columns/${id}/posts`) return await parseApiResponse(response) || [] } catch (error) { console.error('Fetch column posts error:', error) return [] } } export const addPostToColumn = async (columnId: number, postId: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/columns/${columnId}/posts`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify({ postId }) }) await parseApiResponse(response) } catch (error) { throw error } } export const removePostFromColumn = async (columnId: number, postId: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/columns/${columnId}/posts/${postId}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { throw error } } // 标签管理API (复用现有 Tag 类型) export const fetchTags = async (): Promise => { try { const response = await fetch(`${API_BASE}/tags`) return await parseApiResponse(response) || [] } catch (error) { return [] } } export const adminGetTags = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/tags`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { throw error } } export const adminGetTag = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/tags/${id}`, { headers: getAuthHeaders() }) return await parseApiResponse(response) // Adapt to standard response } catch (error) { throw error } } export const createTag = async (data: { name: string; slug: string }): Promise => { try { const response = await authFetch(`${API_BASE}/admin/tags`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { throw error } } export const updateTag = async (id: number, data: { name: string; slug: string }): Promise => { try { const response = await authFetch(`${API_BASE}/admin/tags/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { throw error } } export const deleteTag = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/tags/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { throw error } } // 文章历史记录API export const getPostHistory = async (postId: number | string): Promise => { try { const response = await authFetch(`${API_BASE}/admin/posts/${postId}/history`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { console.error('Get post history error:', error) throw error } } export const getPostHistoryByVersion = async (postId: number | string, version: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/posts/${postId}/history/${version}`, { headers: getAuthHeaders() }) return await parseApiResponse(response) } catch (error) { console.error('Get post history by version error:', error) throw error } } export const getPostHistoryDiff = async ( postId: number | string, fromVersion: number, toVersion: number ): Promise => { const response = await authFetch( `${API_BASE}/admin/posts/${postId}/history/diff?from=${fromVersion}&to=${toVersion}`, { headers: getAuthHeaders() } ) return await parseApiResponse(response) } export const restorePostHistory = async (postId: number | string, version: number): Promise => { const response = await authFetch(`${API_BASE}/admin/posts/${postId}/history/${version}/restore`, { method: 'POST', headers: getAuthHeaders() }) return await parseApiResponse(response) } export const getHotSearches = async (limit = 10, days = 30): Promise => { return (await fetchJson(`${API_BASE}/search/hot?limit=${limit}&days=${days}`)) || [] } // 代码片段管理API export const getAdminSnippets = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/snippets`, { headers: getAuthHeaders() }) const data = await parseApiResponse(response) return (data?.list || []) as Snippet[] } catch (error) { console.error('Get admin snippets error:', error) throw error } } export const fetchSnippets = async (): Promise => { try { const response = await fetch(`${API_BASE}/snippets`) return await parseApiResponse(response) || [] } catch (error) { console.error('Error fetching snippets:', error) return [] } } export const fetchSnippet = async (id: string): Promise => { try { const response = await fetch(`${API_BASE}/snippets/${id}`) return await parseApiResponse(response) } catch (error) { console.error(`Error fetching snippet ${id}:`, error) return { id: id, title: '默认代码片段', code: 'console.log("Hello World");', type: 'js' } } } export const createSnippet = async (snippetData: Omit & { type?: string }): Promise => { try { const response = await authFetch(`${API_BASE}/admin/snippets`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(snippetData) }) await parseApiResponse(response) } catch (error) { console.error('Create snippet error:', error) throw error } } export const updateSnippet = async (id: string, snippetData: Omit & { type?: string }): Promise => { try { const response = await authFetch(`${API_BASE}/admin/snippets/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(snippetData) }) await parseApiResponse(response) } catch (error) { console.error('Update snippet error:', error) throw error } } export const deleteSnippet = async (id: string): Promise => { try { const response = await authFetch(`${API_BASE}/admin/snippets/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete snippet error:', error) throw error } } // 系统配置API export const getSettings = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/settings`, { headers: getAuthHeaders() }) const data = await parseApiResponse(response) if (!data) { return [] } return Array.isArray(data) ? data : [] } catch (error) { console.error('Get settings error:', error) throw error } } export const createSetting = async (settingData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/settings`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(settingData) }) await parseApiResponse(response) } catch (error) { console.error('Create setting error:', error) throw error } } export const updateSetting = async (settingData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/settings`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(settingData) }) await parseApiResponse(response) } catch (error) { console.error('Update setting error:', error) throw error } } export const deleteSetting = async (keyName: string): Promise => { try { const response = await authFetch(`${API_BASE}/admin/settings/${keyName}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete setting error:', error) throw error } } // 公开设置API(前端使用,无需认证) export interface PublicSettings { site_title?: string site_description?: string site_author?: string site_keywords?: string visible_menus?: string posts_per_page?: string } export const getPublicSettings = async (): Promise => { try { const response = await fetch(`${API_BASE}/settings`) return await parseApiResponse(response) || {} } catch (error) { console.error('Get public settings error:', error) // 返回空对象,前端使用默认值 return {} } } // 操作日志筛选参数 export interface OperationLogFilters { action?: string method?: string status?: number userId?: number startDate?: string endDate?: string } // 操作日志API export const getOperationLogs = async ( page: number = 1, pageSize: number = 10, filters: OperationLogFilters = {} ): Promise> => { try { const qs = new URLSearchParams({ page: String(page), pageSize: String(pageSize) }) if (filters.action) qs.set('action', filters.action) if (filters.method) qs.set('method', filters.method) if (filters.status) qs.set('status', String(filters.status)) if (filters.userId) qs.set('userId', String(filters.userId)) if (filters.startDate) qs.set('startDate', filters.startDate) if (filters.endDate) qs.set('endDate', filters.endDate) const response = await authFetch(`${API_BASE}/admin/operation-logs?${qs}`, { headers: getAuthHeaders() }) return await parseApiResponse(response) } catch (error) { console.error('Get operation logs error:', error) throw error } } // 访问日志类型 export interface AccessLog { id: number ip: string userAgent: string path: string method: string statusCode: number responseTime: number region: string createdAt: string } // 访问日志筛选参数 export interface AccessLogFilters { path?: string region?: string startDate?: string endDate?: string } // 访问日志API export const getAccessLogs = async ( page: number = 1, pageSize: number = 10, filters: AccessLogFilters = {} ): Promise> => { try { const qs = new URLSearchParams({ page: String(page), pageSize: String(pageSize) }) if (filters.path) qs.set('path', filters.path) if (filters.region) qs.set('region', filters.region) if (filters.startDate) qs.set('startDate', filters.startDate) if (filters.endDate) qs.set('endDate', filters.endDate) const response = await authFetch(`${API_BASE}/admin/access-logs?${qs}`, { headers: getAuthHeaders() }) return await parseApiResponse(response) } catch (error) { console.error('Get access logs error:', error) throw error } } // 文章访问记录类型(来自 user_access_logs 表) export interface PostAccessLog { id: number userId: number ip: string region: string articleId: number createdAt: string } // 获取指定文章的访问记录 export const getPostAccessLogs = async (postId: number, page: number = 1, pageSize: number = 20): Promise> => { try { const response = await authFetch(`${API_BASE}/admin/posts/${postId}/access-logs?page=${page}&pageSize=${pageSize}`, { headers: getAuthHeaders() }) return await parseApiResponse(response) } catch (error) { console.error('Get post access logs error:', error) throw error } } // 仪表盘数据类型 export interface DashboardStats { users: number posts: number works: number snippets: number } // 最近活动类型 export interface RecentActivity { id: number icon: string text: string time: string } // 仪表盘API export const getDashboardStats = async (startDate?: string, endDate?: string): Promise => { try { let url = `${API_BASE}/admin/dashboard/stats` const params = new URLSearchParams() if (startDate) params.append('startDate', startDate) if (endDate) params.append('endDate', endDate) if (params.toString()) url += `?${params.toString()}` return await authFetchJson(url, { headers: getAuthHeaders() }) } catch (error) { console.error('Get dashboard stats error:', error) throw error } } // 获取最近活动 export const getRecentActivities = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/dashboard/activities`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { console.error('Get recent activities error:', error) throw error } } // 关于页面相关类型 export interface Experience { year: string role: string company: string } export interface AboutProfile { id: number name: string avatar: string location: string bio: string email: string wechat: string techStack: string[] experiences: Experience[] isPrimary: boolean createdAt: string updatedAt: string } // 关于页面API export const fetchAboutProfile = async (): Promise => { try { const result = await fetchJson(`${API_BASE}/about`) if (!result) { throw new Error('个人资料数据为空') } // 确保 techStack 和 experiences 始终是数组 if (!Array.isArray(result.techStack)) { result.techStack = [] } if (!Array.isArray(result.experiences)) { result.experiences = [] } return result } catch (error) { console.error('Fetch about profile error:', error) throw error } } export const getAdminAboutProfiles = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/about`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { console.error('Get admin about profiles error:', error) throw error } } export const createAboutProfile = async (profileData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/about`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(profileData) }) await parseApiResponse(response) } catch (error) { console.error('Create about profile error:', error) throw error } } export const updateAboutProfile = async (id: number, profileData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/about/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(profileData) }) await parseApiResponse(response) } catch (error) { console.error('Update about profile error:', error) throw error } } export const deleteAboutProfile = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/about/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete about profile error:', error) throw error } } // 客户评价相关类型 export interface Testimonial { id: number content: string author: string role: string avatar: string rating: number createdAt: string updatedAt: string } // 合作伙伴相关类型 export interface Partner { id: number name: string logo: string description: string website: string createdAt: string updatedAt: string } // 客户评价API export const fetchTestimonials = async (): Promise => { try { const response = await fetch(`${API_BASE}/testimonials`) return await parseApiResponse(response) || [] } catch (error) { console.error('Fetch testimonials error:', error) throw error } } export const createTestimonial = async (data: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/testimonials`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { console.error('Create testimonial error:', error) throw error } } export const updateTestimonial = async (id: number, data: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/testimonials/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { console.error('Update testimonial error:', error) throw error } } export const deleteTestimonial = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/testimonials/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete testimonial error:', error) throw error } } // 合作伙伴API export const fetchPartners = async (): Promise => { try { const response = await fetch(`${API_BASE}/partners`) return await parseApiResponse(response) || [] } catch (error) { console.error('Fetch partners error:', error) throw error } } export const createPartner = async (data: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/partners`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { console.error('Create partner error:', error) throw error } } export const updatePartner = async (id: number, data: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/partners/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data) }) await parseApiResponse(response) } catch (error) { console.error('Update partner error:', error) throw error } } export const deletePartner = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/partners/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete partner error:', error) throw error } } // 咨询相关类型 export interface Inquiry { id?: number name: string company: string contactMethod: string contactValue: string budget: string description: string status?: number // 0-Unread, 1-Read, 2-Contacted createdAt?: string } // OSS配置相关类型 export interface OSSConfig { id: number name: string storageType: string // 通用字段(向后兼容) accessKey?: string secretKey?: string bucket?: string region?: string domain?: string // 阿里云OSS专用字段 ossAccessKeyId?: string ossAccessKeySecret?: string ossEndpoint?: string ossBucket?: string ossDomain?: string // 腾讯云COS专用字段 qcloudSecretId?: string qcloudSecretKey?: string qcloudRegion?: string qcloudBucket?: string qcloudDomain?: string // 七牛云专用字段 qiniuAccessKey?: string qiniuSecretKey?: string qiniuBucket?: string qiniuRegion?: string qiniuDomain?: string isActive: number createdAt: string updatedAt: string } // 向后兼容的旧接口定义(已废弃,保留用于类型兼容) export interface OSSConfigOld { id: number name: string storageType: string // local/qcloud/aliyun/qiniu accessKey: string // 加密存储,返回时显示为 *** secretKey: string // 加密存储,返回时显示为 *** bucket: string region: string domain: string isActive: number createdAt: string updatedAt: string } export interface EmailSuffix { id: number suffix: string isActive: boolean sortOrder: number createdAt: string updatedAt: string } // 咨询相关API export const submitInquiry = async (data: Inquiry): Promise => { try { await fetchJson(`${API_BASE}/inquiries`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }) } catch (error) { console.error('Submit inquiry error:', error) throw error } } export const fetchEmailSuffixes = async (): Promise => { try { const response = await fetch(`${API_BASE}/email-suffixes`) return await parseApiResponse(response) || [] } catch (error) { console.error('Fetch email suffixes error:', error) throw error } } export const fetchInquiries = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/inquiries`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { console.error('Fetch inquiries error:', error) throw error } } // OSS配置相关API export const getOSSConfigs = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/oss-configs`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { console.error('Get OSS configs error:', error) throw error } } export const createOSSConfig = async (configData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/oss-configs`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(configData) }) return await parseApiResponse(response) } catch (error) { console.error('Create OSS config error:', error) throw error } } export const updateOSSConfig = async (id: number, configData: Partial>): Promise => { try { const response = await authFetch(`${API_BASE}/admin/oss-configs/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(configData) }) return await parseApiResponse(response) } catch (error) { console.error('Update OSS config error:', error) throw error } } export const deleteOSSConfig = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/oss-configs/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete OSS config error:', error) throw error } } // 附件相关类型 export interface Attachment { id: number categoryId?: number category?: { id: number name: string } originalName: string storedName: string filePath: string fileUrl: string fileSize: number fileType: string mimeType: string storageType: string ossConfigId?: number createdAt: string updatedAt: string } // 附件分类相关类型 export interface AttachmentCategory { id: number name: string description: string sortOrder: number createdAt: string updatedAt: string } // 附件管理API export const getAdminAttachments = async (params?: { page?: number pageSize?: number categoryId?: number fileType?: string keyword?: string }): Promise<{ list: Attachment[], total: number, page: number, size: number }> => { try { const queryParams = new URLSearchParams() if (params?.page) queryParams.append('page', params.page.toString()) if (params?.pageSize) queryParams.append('pageSize', params.pageSize.toString()) if (params?.categoryId) queryParams.append('categoryId', params.categoryId.toString()) if (params?.fileType) queryParams.append('fileType', params.fileType) if (params?.keyword) queryParams.append('keyword', params.keyword) const url = `${API_BASE}/admin/attachments${queryParams.toString() ? '?' + queryParams.toString() : ''}` const data = await authFetchJson>(url, { headers: getAuthHeaders() }) return { list: data?.list || [], total: data?.total || 0, page: data?.page || 1, size: data?.size || 20 } } catch (error) { console.error('Get admin attachments error:', error) throw error } } export const updateAttachment = async (id: number, data: { categoryId?: number | null }): Promise => { try { return await authFetchJson(`${API_BASE}/admin/attachments/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data) }) } catch (error) { console.error('Update attachment error:', error) throw error } } // 附件分类管理API export const getAttachmentCategories = async (): Promise => { try { const response = await authFetch(`${API_BASE}/admin/attachment-categories`, { headers: getAuthHeaders() }) return await parseApiResponse(response) || [] } catch (error) { console.error('Get attachment categories error:', error) throw error } } export const createAttachmentCategory = async (categoryData: Omit): Promise => { try { const response = await authFetch(`${API_BASE}/admin/attachment-categories`, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(categoryData) }) await parseApiResponse(response) } catch (error) { console.error('Create attachment category error:', error) throw error } } export const updateAttachmentCategory = async (id: number, categoryData: Partial>): Promise => { try { const response = await authFetch(`${API_BASE}/admin/attachment-categories/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(categoryData) }) await parseApiResponse(response) } catch (error) { console.error('Update attachment category error:', error) throw error } } export const deleteAttachmentCategory = async (id: number): Promise => { try { const response = await authFetch(`${API_BASE}/admin/attachment-categories/${id}`, { method: 'DELETE', headers: getAuthHeaders() }) await parseApiResponse(response) } catch (error) { console.error('Delete attachment category error:', error) throw error } }