feat: 添加登录功能与文章编辑功能

refactor: 重构API服务与全局状态管理

style: 优化UI样式与布局

fix: 修复文章列表与详情页的显示问题

docs: 更新类型定义与注释

chore: 更新依赖包与配置文件
This commit is contained in:
qingfeng1121
2025-10-30 19:00:59 +08:00
parent 85bf3214cc
commit 6d90b5842f
27 changed files with 2400 additions and 304 deletions

View File

@@ -1,46 +1,75 @@
// 基础 API 服务配置
// 基础API服务
import axios from 'axios'
import { ElMessage } from 'element-plus'
// 创建 axios 实例
const apiService = axios.create({
baseURL: 'http://localhost:8080/api', // api的base_url
timeout: 10000, // 请求超时时间
headers: {
'Content-Type': 'application/json'
}
// 创建axios实例
const api = axios.create({
baseURL:'http://localhost:8080/api', // API基础URL
timeout: 10000 // 请求超时时间
})
// 请求拦截器 - 添加认证token
apiService.interceptors.request.use(
// 请求拦截器
api.interceptors.request.use(
config => {
// 从localStorage获取token
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
// 设置Authorization头
config.headers['Authorization'] = `Bearer ${token}`
}
return config
},
error => {
// 请求错误处理
console.error('请求错误:', error)
return Promise.reject(error)
}
)
// 响应拦截器 - 统一处理响应
apiService.interceptors.response.use(
// 响应拦截器
api.interceptors.response.use(
response => {
// 检查响应是否成功
if (response.data && response.data.success) {
return response.data
} else {
// 处理业务错误
return Promise.reject(new Error(response.data?.message || '请求失败'))
}
// 直接返回响应数据
return response.data
},
error => {
// 处理HTTP错误
console.error('API请求错误:', error)
// 可以在这里添加全局错误处理,如显示错误提示
// 错误处理
console.error('响应错误:', error)
let message = '请求失败'
if (error.response) {
// 服务器响应了但状态码不是2xx
switch (error.response.status) {
case 401:
message = '未授权,请重新登录'
// 可以在这里处理登出逻辑
localStorage.removeItem('token')
// 跳转到登录页
window.location.href = '/login'
break
case 403:
message = '拒绝访问'
break
case 404:
message = '请求资源不存在'
break
case 500:
message = '服务器错误'
break
default:
message = error.response.data?.message || message
}
} else if (error.request) {
// 请求已发出但没有收到响应
message = '网络错误,请检查网络连接'
}
// 使用Element Plus的消息组件显示错误信息
ElMessage.error(message)
return Promise.reject(error)
}
)
export default apiService
export default api

View File

@@ -1,119 +1,122 @@
// 文章相关API服务
import apiService from './apiService'
import api from './apiService'
/**
* 文章服务类
*/
class ArticleService {
/**
* 获取已发布文章
* @param {Object} params - 查询参数
* @returns {Promise}
* 获取已发布文章列表
* @param {import('../types').PaginationParams} params - 查询参数
* @returns {Promise<import('../types').ApiResponse<import('../types').Article[]>>}
*/
getAllArticles(params = {}) {
return apiService.get('/articles/published', { params })
return api.get('/articles/published', { params })
}
/**
* 获取单篇文章
* @param {number} id - 文章ID
* @returns {Promise}
* 根据ID获取文章详情
* @param {number} articleid - 文章ID
* @returns {Promise<import('../types').ApiResponse<import('../types').Article>>}
*/
getArticleById(id) {
return apiService.get(`/articles/${id}`)
getArticleById(articleid) {
return api.get(`/articles/${articleid}`)
}
/**
* 根据属性ID获取文章列表
* @param {number} attributeId - 属性ID
* @returns {Promise}
* @param {number} attributeid - 属性ID
* @returns {Promise<import('../types').ApiResponse<import('../types').Article[]>>}
*/
getArticlesByAttributeId(attributeId) {
return apiService.get(`/articles/attribute/${attributeId}`)
getArticlesByAttributeId(attributeid) {
return api.get(`/articles/attribute/${attributeid}`)
}
/**
* 根据标题查询文章列表
* @param {string} title - 文章标题
* @returns {Promise}
* @returns {Promise<import('../types').ApiResponse<import('../types').Article[]>>}
*/
getArticlesByTitle(title) {
return apiService.get(`/articles/title/${title}`)
return api.get(`/articles/title/${title}`)
}
/**
* 获取热门文章
* @returns {Promise}
* @returns {Promise<import('../types').ApiResponse<import('../types').Article[]>>}
*/
getPopularArticles() {
return apiService.get('/articles/popular')
return api.get('/articles/popular')
}
/**
* 创建文章
* @param {Object} articleData - 文章数据
* @returns {Promise}
* @param {import('../types').ArticleDto} articleData - 文章数据
* @returns {Promise<import('../types').ApiResponse<import('../types').Article>>}
*/
createArticle(articleData) {
return apiService.post('/articles', articleData)
createArticle(Article) {
return api.post('/articles', Article)
}
/**
* 更新文章
* @param {number} id - 文章ID
* @param {Object} articleData - 文章数据
* @returns {Promise}
* @param {number} articleid - 文章ID
* @param {import('../types').ArticleDto} articleData - 文章数据
* @returns {Promise<import('../types').ApiResponse<import('../types').Article>>}
*/
updateArticle(id, articleData) {
return apiService.put(`/articles/${id}`, articleData)
updateArticle(articleid, articleData) {
return api.put(`/articles/${articleid}`, articleData)
}
/**
* 删除文章
* @param {number} id - 文章ID
* @returns {Promise}
* @param {number} articleid - 文章ID
* @returns {Promise<import('../types').ApiResponse<boolean>>}
*/
deleteArticle(id) {
return apiService.delete(`/articles/${id}`)
deleteArticle(articleid) {
return api.delete(`/articles/${articleid}`)
}
/**
* 根据分类获取文章
* @param {number} categoryid - 分类ID
* @returns {Promise<import('../types').ApiResponse<import('../types').Article[]>>}
*/
getArticlesByCategory(categoryid) {
return api.get(`/articles/category/${categoryid}`)
}
/**
* 增加文章浏览量
* @param {number} id - 文章ID
* @returns {Promise}
* @param {number} articleid - 文章ID
* @returns {Promise<import('../types').ApiResponse<boolean>>}
*/
incrementArticleViews(id) {
return apiService.post(`/articles/view/${id}`)
}
/**
* 根据分类ID获取文章兼容旧接口
* @param {number} categoryId - 分类ID
* @returns {Promise}
*/
getArticlesByCategory(categoryId) {
return apiService.get(`/articles/category/${categoryId}`)
}
/**
* 根据属性ID获取文章
* @param {number} attributeId - 属性ID
* @returns {Promise}
*/
getArticlesByAttribute(attributeId) {
return apiService.get(`/articles/attribute/${attributeId}`)
incrementArticleViews(articleid) {
return api.post(`/articles/view/${articleid}`)
}
/**
* 根据属性ID获取最新文章
* @param {number} attributeId - 属性ID
* @returns {Promise}
* @param {number} attributeid - 属性ID
* @returns {Promise<import('../types').ApiResponse<import('../types').Article[]>>}
*/
getLatestArticlesByAttribute(attributeId) {
return apiService.get(`/articles/attribute/${attributeId}/latest`)
getLatestArticlesByAttribute(attributeid) {
return api.get(`/articles/attribute/${attributeid}/latest`)
}
/**
* 点赞文章
* @param {number} articleid - 文章ID
* @returns {Promise<import('../types').ApiResponse<boolean>>}
*/
likeArticle(articleid) {
return api.post(`/articles/like/${articleid}`)
}
}
// 导出文章服务实例
export default new ArticleService()
// 创建并导出服务实例
const articleService = new ArticleService()
export default articleService
// 导出服务类供特殊场景使用
export { ArticleService }

View File

@@ -1,5 +1,5 @@
// 分类属性相关API服务
import apiService from './apiService'
import api from './apiService'
/**
* 分类属性服务类
@@ -7,60 +7,64 @@ import apiService from './apiService'
class CategoryAttributeService {
/**
* 根据ID获取分类属性
* @param {number} id - 属性ID
* @returns {Promise}
* @param {number} attributeid - 属性ID
* @returns {Promise<import('../types').ApiResponse<import('../types').CategoryAttribute>>}
*/
getAttributeById(id) {
return apiService.get(`/category-attributes/${id}`)
getAttributeById(attributeid) {
return api.get(`/category-attributes/${attributeid}`)
}
/**
* 根据分类ID获取属性列表
* @param {number} categoryId - 分类ID
* @returns {Promise}
* @param {number} categoryid - 分类ID
* @returns {Promise<import('../types').ApiResponse<import('../types').CategoryAttribute[]>>}
*/
getAttributesByCategory(categoryId) {
return apiService.get(`/category-attributes/category/${categoryId}`)
getAttributesByCategory(categoryid) {
return api.get(`/category-attributes/category/${categoryid}`)
}
/**
* 创建分类属性
* @param {Object} attributeData - 属性数据
* @returns {Promise}
* @param {import('../types').CategoryAttributeDto} attributeData - 属性数据
* @returns {Promise<import('../types').ApiResponse<import('../types').CategoryAttribute>>}
*/
createAttribute(attributeData) {
return apiService.post('/category-attributes', attributeData)
return api.post('/category-attributes', attributeData)
}
/**
* 更新分类属性
* @param {number} id - 属性ID
* @param {Object} attributeData - 属性数据
* @returns {Promise}
* @param {number} attributeid - 属性ID
* @param {import('../types').CategoryAttributeDto} attributeData - 属性数据
* @returns {Promise<import('../types').ApiResponse<import('../types').CategoryAttribute>>}
*/
updateAttribute(id, attributeData) {
return apiService.put(`/category-attributes/${id}`, attributeData)
updateAttribute(attributeid, attributeData) {
return api.put(`/category-attributes/${attributeid}`, attributeData)
}
/**
* 删除分类属性
* @param {number} id - 属性ID
* @returns {Promise}
* @param {number} attributeid - 属性ID
* @returns {Promise<import('../types').ApiResponse<boolean>>}
*/
deleteAttribute(id) {
return apiService.delete(`/category-attributes/${id}`)
deleteAttribute(attributeid) {
return api.delete(`/category-attributes/${attributeid}`)
}
/**
* 检查分类下是否存在指定名称的属性
* @param {number} categoryId - 分类ID
* @param {string} attributeName - 属性名称
* @returns {Promise}
* @param {number} categoryid - 分类ID
* @param {string} attributename - 属性名称
* @returns {Promise<import('../types').ApiResponse<boolean>>}
*/
checkAttributeExists(categoryId, attributeName) {
return apiService.get(`/category-attributes/check-exists?categoryId=${categoryId}&attributeName=${encodeURIComponent(attributeName)}`)
checkAttributeExists(categoryid, attributename) {
return api.get(`/category-attributes/check-exists?categoryid=${categoryid}&attributename=${encodeURIComponent(attributename)}`)
}
}
// 导出分类属性服务实例
export default new CategoryAttributeService()
// 创建并导出服务实例
const categoryAttributeService = new CategoryAttributeService()
export default categoryAttributeService
// 导出服务类供特殊场景使用
export { CategoryAttributeService }

View File

@@ -1,4 +1,4 @@
import apiService from './apiService'
import api from './apiService'
/**
* 分类服务
@@ -6,49 +6,53 @@ import apiService from './apiService'
class CategoryService {
/**
* 获取所有分类
* @returns {Promise}
* @returns {Promise<import('../types').ApiResponse<import('../types').Category[]>>}
*/
getAllCategories() {
return apiService.get('/categories')
return api.get('/categories')
}
/**
* 获取指定分类
* @param {number} id - 分类ID
* @returns {Promise}
* @param {number} typeid - 分类ID
* @returns {Promise<import('../types').ApiResponse<import('../types').Category>>}
*/
getCategory(id) {
return apiService.get(`/categories/${id}`)
getCategory(typeid) {
return api.get(`/categories/${typeid}`)
}
/**
* 创建新分类
* @param {Object} categoryData - 分类数据
* @returns {Promise}
* @param {import('../types').CategoryDto} categoryData - 分类数据
* @returns {Promise<import('../types').ApiResponse<import('../types').Category>>}
*/
createCategory(categoryData) {
return apiService.post('/categories', categoryData)
return api.post('/categories', categoryData)
}
/**
* 更新分类
* @param {number} id - 分类ID
* @param {Object} categoryData - 分类数据
* @returns {Promise}
* @param {number} typeid - 分类ID
* @param {import('../types').CategoryDto} categoryData - 分类数据
* @returns {Promise<import('../types').ApiResponse<import('../types').Category>>}
*/
updateCategory(id, categoryData) {
return apiService.put(`/categories/${id}`, categoryData)
updateCategory(typeid, categoryData) {
return api.put(`/categories/${typeid}`, categoryData)
}
/**
* 删除分类
* @param {number} id - 分类ID
* @returns {Promise}
* @param {number} typeid - 分类ID
* @returns {Promise<import('../types').ApiResponse<boolean>>}
*/
deleteCategory(id) {
return apiService.delete(`/categories/${id}`)
deleteCategory(typeid) {
return api.delete(`/categories/${typeid}`)
}
}
// 导出分类服务实例
export default new CategoryService()
// 创建并导出服务实例
const categoryService = new CategoryService()
export default categoryService
// 导出服务类供特殊场景使用
export { CategoryService }

View File

@@ -1,17 +1,16 @@
// 导出所有服务
import articleService from './articleService'
import messageService from './messageService'
import categoryAttributeService from './categoryAttributeService'
import categoryService from './categoryService'
import categoryAttributeService from './categoryAttributeService'
import loginService from './loginService'
import messageService from './messageService'
// 导出服务类供特殊场景使用
export {
articleService,
messageService,
categoryService,
categoryAttributeService,
categoryService
loginService,
messageService
}

View File

@@ -0,0 +1,59 @@
// 登录相关API服务
import api from "./apiService";
/**
* 登录服务类
*/
class LoginService {
/**
* 用户登录
* @param {import('../types').LoginDto} loginData - 登录数据
* @returns {Promise<import('../types').ApiResponse<import('../types').User>>}
*/
login(loginData) {
return api.post("/auth/login", loginData);
}
/**
* 用户注册
* @param {import('../types').RegisterDto} registerData - 注册数据
* @returns {Promise<import('../types').ApiResponse<import('../types').User>>}
*/
register(registerData) {
return api.post("/auth/register", registerData);
}
/**
* 登出
*/
logout() {
return api.post("/auth/logout");
}
/**
* 获取当前用户信息
* @returns {Promise<import('../types').ApiResponse<import('../types').User>>}
*/
getCurrentUser() {
return api.get("/user/info");
}
/**
* 更新用户信息
* @param {import('../types').UserDto} userData - 用户数据
* @returns {Promise<import('../types').ApiResponse<import('../types').User>>}
*/
updateUser(userData) {
return api.put("/user/update", userData);
}
/**
* 修改密码
* @param {import('../types').ChangePasswordDto} passwordData - 密码数据
* @returns {Promise<import('../types').ApiResponse<boolean>>}
*/
changePassword(passwordData) {
return api.post("/user/change-password", passwordData);
}
}
export default new LoginService();

View File

@@ -7,7 +7,7 @@ import apiService from './apiService'
class MessageService {
/**
* 获取所有留言
* @returns {Promise}
* @returns {Promise<import('../types').ApiResponse<import('../types').Message[]>>}
*/
getAllMessages() {
return apiService.get('/messages')
@@ -15,25 +15,25 @@ class MessageService {
/**
* 获取单条留言
* @param {number} id - 留言ID
* @returns {Promise}
* @param {number} messageid - 留言ID
* @returns {Promise<import('../types').ApiResponse<import('../types').Message>>}
*/
getMessageById(id) {
return apiService.get(`/messages/${id}`)
getMessageById(messageid) {
return apiService.get(`/messages/${messageid}`)
}
/**
* 根据文章ID获取留言
* @param {number} articleId - 文章ID
* @returns {Promise}
* @param {number} articleid - 文章ID
* @returns {Promise<import('../types').ApiResponse<import('../types').Message[]>>}
*/
getMessagesByArticleId(articleId) {
return apiService.get(`/messages/article/${articleId}`)
getMessagesByArticleId(articleid) {
return apiService.get(`/messages/article/${articleid}`)
}
/**
* 获取根留言
* @returns {Promise}
* @returns {Promise<import('../types').ApiResponse<import('../types').Message[]>>}
*/
getRootMessages() {
return apiService.get('/messages/root')
@@ -41,17 +41,17 @@ class MessageService {
/**
* 根据父留言ID获取回复
* @param {number} parentId - 父留言ID
* @returns {Promise}
* @param {number} parentid - 父留言ID
* @returns {Promise<import('../types').ApiResponse<import('../types').Message[]>>}
*/
getRepliesByParentId(parentId) {
return apiService.get(`/messages/${parentId}/replies`)
getRepliesByParentId(parentid) {
return apiService.get(`/messages/${parentid}/replies`)
}
/**
* 根据昵称搜索留言
* @param {string} nickname - 昵称
* @returns {Promise}
* @returns {Promise<import('../types').ApiResponse<import('../types').Message[]>>}
*/
searchMessagesByNickname(nickname) {
return apiService.get(`/messages/search?nickname=${nickname}`)
@@ -59,17 +59,17 @@ class MessageService {
/**
* 获取文章评论数量
* @param {number} articleId - 文章ID
* @returns {Promise}
* @param {number} articleid - 文章ID
* @returns {Promise<import('../types').ApiResponse<number>>}
*/
getMessageCountByArticleId(articleId) {
return apiService.get(`/messages/count/article/${articleId}`)
getMessageCountByArticleId(articleid) {
return apiService.get(`/messages/count/article/${articleid}`)
}
/**
* 创建留言
* @param {Object} messageData - 留言数据
* @returns {Promise}
* @param {import('../types').MessageDto} messageData - 留言数据
* @returns {Promise<import('../types').ApiResponse<import('../types').Message>>}
*/
saveMessage(messageData) {
return apiService.post('/messages', messageData)
@@ -77,20 +77,21 @@ class MessageService {
/**
* 删除留言
* @param {number} id - 留言ID
* @returns {Promise}
* @param {number} messageid - 留言ID
* @returns {Promise<import('../types').ApiResponse<boolean>>}
*/
deleteMessage(id) {
return apiService.delete(`/messages/${id}`)
deleteMessage(messageid) {
return apiService.delete(`/messages/${messageid}`)
}
/**
* 点赞留言
* @param {number} id - 留言ID
* @returns {Promise}
* @param {number} messageid - 留言ID
* @returns {Promise<import('../types').ApiResponse<boolean>>}
*
*/
likeMessage(id) {
return apiService.post(`/messages/${id}/like`)
likeMessage(messageid) {
return apiService.post(`/messages/${messageid}/like`)
}
}