parent
2f52a66c74
commit
c8063fa38f
@ -0,0 +1,149 @@
|
||||
// api/post.ts
|
||||
import request from './request'
|
||||
import type { Post, PostListParams, PostListResponse } from '@/views/post'
|
||||
|
||||
export const postApi = {
|
||||
// 获取我的帖子列表
|
||||
getMyPosts(params: PostListParams): Promise<PostListResponse> {
|
||||
return request({
|
||||
url: '/posts/my-posts',
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
},
|
||||
|
||||
// 获取帖子详情
|
||||
getPostDetail(id: number): Promise<Post> {
|
||||
return request({
|
||||
url: `/posts/${id}`,
|
||||
method: 'GET'
|
||||
})
|
||||
},
|
||||
|
||||
// 创建帖子
|
||||
createPost(data: Partial<Post>): Promise<Post> {
|
||||
return request({
|
||||
url: '/posts',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
},
|
||||
|
||||
// 更新帖子
|
||||
updatePost(id: number, data: Partial<Post>): Promise<Post> {
|
||||
return request({
|
||||
url: `/posts/${id}`,
|
||||
method: 'PUT',
|
||||
data
|
||||
})
|
||||
},
|
||||
|
||||
// 删除单个帖子
|
||||
deletePost(id: number): Promise<void> {
|
||||
return request({
|
||||
url: `/posts/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
},
|
||||
|
||||
// 批量删除帖子
|
||||
batchDeletePosts(ids: number[]): Promise<void> {
|
||||
return request({
|
||||
url: '/posts/batch-delete',
|
||||
method: 'DELETE',
|
||||
data: { ids }
|
||||
})
|
||||
},
|
||||
|
||||
// 发布帖子(从草稿状态发布)
|
||||
publishPost(id: number): Promise<Post> {
|
||||
return request({
|
||||
url: `/posts/${id}/publish`,
|
||||
method: 'POST'
|
||||
})
|
||||
},
|
||||
|
||||
// 将帖子设为草稿
|
||||
draftPost(id: number): Promise<Post> {
|
||||
return request({
|
||||
url: `/posts/${id}/draft`,
|
||||
method: 'POST'
|
||||
})
|
||||
},
|
||||
|
||||
// 获取帖子统计信息
|
||||
getPostStats(): Promise<{
|
||||
totalPosts: number
|
||||
totalViews: number
|
||||
totalLikes: number
|
||||
totalComments: number
|
||||
todayPosts: number
|
||||
weekPosts: number
|
||||
monthPosts: number
|
||||
}> {
|
||||
return request({
|
||||
url: '/posts/stats',
|
||||
method: 'GET'
|
||||
})
|
||||
},
|
||||
|
||||
// 点赞帖子
|
||||
likePost(id: number): Promise<{ liked: boolean; likesCount: number }> {
|
||||
return request({
|
||||
url: `/posts/${id}/like`,
|
||||
method: 'POST'
|
||||
})
|
||||
},
|
||||
|
||||
// 取消点赞
|
||||
unlikePost(id: number): Promise<{ liked: boolean; likesCount: number }> {
|
||||
return request({
|
||||
url: `/posts/${id}/unlike`,
|
||||
method: 'POST'
|
||||
})
|
||||
},
|
||||
|
||||
// 增加浏览量
|
||||
increaseViews(id: number): Promise<{ views: number }> {
|
||||
return request({
|
||||
url: `/posts/${id}/view`,
|
||||
method: 'POST'
|
||||
})
|
||||
},
|
||||
|
||||
// 搜索帖子
|
||||
searchPosts(params: {
|
||||
keyword: string
|
||||
category?: string
|
||||
page?: number
|
||||
pageSize?: number
|
||||
}): Promise<PostListResponse> {
|
||||
return request({
|
||||
url: '/posts/search',
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
},
|
||||
|
||||
// 获取热门帖子
|
||||
getHotPosts(params: {
|
||||
period?: 'day' | 'week' | 'month'
|
||||
limit?: number
|
||||
} = {}): Promise<Post[]> {
|
||||
return request({
|
||||
url: '/posts/hot',
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
},
|
||||
|
||||
// 获取推荐帖子
|
||||
getRecommendedPosts(limit = 10): Promise<Post[]> {
|
||||
return request({
|
||||
url: '/posts/recommended',
|
||||
method: 'GET',
|
||||
params: { limit }
|
||||
})
|
||||
}
|
||||
}
|
||||
//
|
@ -0,0 +1,111 @@
|
||||
// types/post.ts
|
||||
export interface Post {
|
||||
id: number
|
||||
title: string
|
||||
content?: string
|
||||
category: string
|
||||
views: number
|
||||
likes: number
|
||||
comments?: number
|
||||
createdAt: string
|
||||
updatedAt?: string
|
||||
status: 'published' | 'draft'
|
||||
author?: {
|
||||
id: number
|
||||
username: string
|
||||
avatar?: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface PostListParams {
|
||||
page: number
|
||||
pageSize: number
|
||||
title?: string
|
||||
category?: string
|
||||
status?: string
|
||||
sortBy?: 'createdAt' | 'views' | 'likes'
|
||||
sortOrder?: 'asc' | 'desc'
|
||||
}
|
||||
|
||||
export interface PostListResponse {
|
||||
data: Post[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
|
||||
export interface FilterForm {
|
||||
title: string
|
||||
category: string
|
||||
status?: string
|
||||
}
|
||||
|
||||
export interface Pagination {
|
||||
currentPage: number
|
||||
pageSize: number
|
||||
total: number
|
||||
}
|
||||
|
||||
export interface Stats {
|
||||
totalPosts: number
|
||||
totalViews: number
|
||||
totalLikes: number
|
||||
totalComments: number
|
||||
avgViews: number
|
||||
avgLikes: number
|
||||
}
|
||||
|
||||
export interface DeleteDialog {
|
||||
visible: boolean
|
||||
loading: boolean
|
||||
type: 'single' | 'batch'
|
||||
post?: Post
|
||||
}
|
||||
|
||||
// types/api.ts
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
timestamp: number
|
||||
}
|
||||
|
||||
export interface ApiError {
|
||||
code: number
|
||||
message: string
|
||||
details?: any
|
||||
}
|
||||
|
||||
// types/category.ts
|
||||
export interface Category {
|
||||
id: string
|
||||
name: string
|
||||
description?: string
|
||||
color?: string
|
||||
icon?: string
|
||||
}
|
||||
|
||||
export const CATEGORIES: Category[] = [
|
||||
{ id: 'tech', name: '技术讨论', color: 'primary', icon: 'Monitor' },
|
||||
{ id: 'life', name: '生活随笔', color: 'success', icon: 'Coffee' },
|
||||
{ id: 'study', name: '学习分享', color: 'warning', icon: 'Reading' },
|
||||
{ id: 'qa', name: '问答求助', color: 'info', icon: 'QuestionFilled' }
|
||||
]
|
||||
|
||||
// types/user.ts
|
||||
export interface User {
|
||||
id: number
|
||||
username: string
|
||||
email: string
|
||||
avatar?: string
|
||||
role: 'admin' | 'user'
|
||||
createdAt: string
|
||||
profile?: {
|
||||
nickname?: string
|
||||
bio?: string
|
||||
location?: string
|
||||
website?: string
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,138 @@
|
||||
// hooks/usePost.ts
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import type { Post, PostListParams, FilterForm, Pagination, Stats } from '@/views/post'
|
||||
import { postApi } from '@/utils/post'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
export function usePostManagement() {
|
||||
const loading = ref(false)
|
||||
const posts = ref<Post[]>([])
|
||||
const selectedPosts = ref<Post[]>([])
|
||||
|
||||
const filterForm = reactive<FilterForm>({
|
||||
title: '',
|
||||
category: '',
|
||||
status: ''
|
||||
})
|
||||
|
||||
const pagination = reactive<Pagination>({
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 计算统计数据
|
||||
const stats = computed<Stats>(() => {
|
||||
const totalPosts = posts.value.length
|
||||
const totalViews = posts.value.reduce((sum, post) => sum + post.views, 0)
|
||||
const totalLikes = posts.value.reduce((sum, post) => sum + post.likes, 0)
|
||||
const totalComments = posts.value.reduce((sum, post) => sum + (post.comments || 0), 0)
|
||||
const avgViews = totalPosts > 0 ? totalViews / totalPosts : 0
|
||||
const avgLikes = totalPosts > 0 ? totalLikes / totalPosts : 0
|
||||
|
||||
return {
|
||||
totalPosts,
|
||||
totalViews,
|
||||
totalLikes,
|
||||
totalComments,
|
||||
avgViews,
|
||||
avgLikes
|
||||
}
|
||||
})
|
||||
|
||||
// 获取帖子列表
|
||||
const fetchPosts = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params: PostListParams = {
|
||||
page: pagination.currentPage,
|
||||
pageSize: pagination.pageSize,
|
||||
title: filterForm.title || undefined,
|
||||
category: filterForm.category || undefined,
|
||||
status: filterForm.status || undefined
|
||||
}
|
||||
|
||||
const response = await postApi.getMyPosts(params)
|
||||
posts.value = response.data
|
||||
pagination.total = response.total
|
||||
} catch (error) {
|
||||
ElMessage.error('获取帖子列表失败')
|
||||
console.error('Fetch posts error:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 删除帖子
|
||||
const deletePost = async (postId: number): Promise<boolean> => {
|
||||
try {
|
||||
await postApi.deletePost(postId)
|
||||
ElMessage.success('删除成功')
|
||||
return true
|
||||
} catch (error) {
|
||||
ElMessage.error('删除失败')
|
||||
console.error('Delete post error:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
const batchDeletePosts = async (postIds: number[]): Promise<boolean> => {
|
||||
try {
|
||||
await postApi.batchDeletePosts(postIds)
|
||||
ElMessage.success(`成功删除 ${postIds.length} 个帖子`)
|
||||
return true
|
||||
} catch (error) {
|
||||
ElMessage.error('批量删除失败')
|
||||
console.error('Batch delete posts error:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.currentPage = 1
|
||||
fetchPosts()
|
||||
}
|
||||
|
||||
// 重置筛选
|
||||
const handleReset = () => {
|
||||
Object.keys(filterForm).forEach(key => {
|
||||
filterForm[key as keyof FilterForm] = ''
|
||||
})
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
// 选择变化
|
||||
const handleSelectionChange = (selection: Post[]) => {
|
||||
selectedPosts.value = selection
|
||||
}
|
||||
|
||||
// 分页变化
|
||||
const handleSizeChange = (newSize: number) => {
|
||||
pagination.pageSize = newSize
|
||||
fetchPosts()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newPage: number) => {
|
||||
pagination.currentPage = newPage
|
||||
fetchPosts()
|
||||
}
|
||||
|
||||
return {
|
||||
loading,
|
||||
posts,
|
||||
selectedPosts,
|
||||
filterForm,
|
||||
pagination,
|
||||
stats,
|
||||
fetchPosts,
|
||||
deletePost,
|
||||
batchDeletePosts,
|
||||
handleSearch,
|
||||
handleReset,
|
||||
handleSelectionChange,
|
||||
handleSizeChange,
|
||||
handleCurrentChange
|
||||
}
|
||||
}
|
Loading…
Reference in new issue