文章接口
文章管理相关的 API 接口,包括文章的增删改查、发布、审核等操作。
获取文章列表
接口信息
GET /api/articles
Authorization: Bearer {token}
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | integer | 否 | 页码,默认 1 |
| page_size | integer | 否 | 每页数量,默认 20 |
| keyword | string | 否 | 搜索关键词 |
| category_id | integer | 否 | 分类 ID |
| tag_id | integer | 否 | 标签 ID |
| status | integer | 否 | 状态(0草稿/1已发布) |
| is_top | integer | 否 | 是否置顶(0否/1是) |
| is_hot | integer | 否 | 是否热门(0否/1是) |
| start_time | string | 否 | 开始时间 |
| end_time | string | 否 | 结束时间 |
| sort | string | 否 | 排序字段(create_time/view_count) |
| order | string | 否 | 排序方式(asc/desc) |
请求示例
GET /api/articles?page=1&page_size=20&category_id=1&status=1&sort=create_time&order=desc
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
响应示例
成功响应(200)
{
"code": 200,
"message": "获取成功",
"data": {
"list": [
{
"id": 1,
"title": "Vue 3 Composition API 详解",
"summary": "本文详细介绍 Vue 3 的 Composition API 用法...",
"cover": "https://example.com/uploads/2024/01/15/cover.jpg",
"author": {
"id": 1,
"username": "admin",
"nickname": "管理员"
},
"category": {
"id": 1,
"name": "前端开发"
},
"tags": [
{
"id": 1,
"name": "Vue.js"
},
{
"id": 2,
"name": "JavaScript"
}
],
"view_count": 1234,
"is_top": 0,
"is_hot": 1,
"status": 1,
"create_time": "2024-01-15 14:30:25",
"update_time": "2024-01-15 15:20:10"
}
],
"total": 128,
"page": 1,
"page_size": 20,
"total_pages": 7
},
"timestamp": 1705317025
}
代码示例
JavaScript (Axios)
import axios from 'axios'
const getArticles = async (params = {}) => {
try {
const response = await axios.get('/api/articles', {
params: {
page: params.page || 1,
page_size: params.pageSize || 20,
category_id: params.categoryId,
status: params.status,
keyword: params.keyword,
sort: params.sort || 'create_time',
order: params.order || 'desc'
},
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`
}
})
return response.data.data
} catch (error) {
console.error('获取文章列表失败:', error)
throw error
}
}
// 使用示例
getArticles({
page: 1,
pageSize: 20,
categoryId: 1,
status: 1
}).then(data => {
console.log('文章列表:', data.list)
console.log('总数:', data.total)
})
PHP (cURL)
<?php
$url = 'http://your-domain.com/api/articles?page=1&page_size=20&category_id=1';
$token = 'YOUR_JWT_TOKEN';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token,
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if ($result['code'] === 200) {
$articles = $result['data']['list'];
foreach ($articles as $article) {
echo $article['title'] . "\n";
}
}
获取文章详情
接口信息
GET /api/articles/{id}
Authorization: Bearer {token}
路径参数
| 参数 | 类型 | 说明 |
|---|---|---|
| id | integer | 文章 ID |
响应示例
成功响应(200)
{
"code": 200,
"message": "获取成功",
"data": {
"id": 1,
"title": "Vue 3 Composition API 详解",
"content": "<p>文章正文内容...</p>",
"summary": "文章摘要",
"cover": "https://example.com/uploads/2024/01/15/cover.jpg",
"author": {
"id": 1,
"username": "admin",
"nickname": "管理员",
"avatar": "https://example.com/avatar/admin.jpg"
},
"category": {
"id": 1,
"name": "前端开发",
"alias": "frontend"
},
"tags": [
{
"id": 1,
"name": "Vue.js",
"alias": "vuejs"
}
],
"seo_title": "Vue 3 Composition API 详解 - 技术博客",
"seo_keywords": "Vue3,Composition API,前端",
"seo_description": "详细介绍 Vue 3 的 Composition API",
"view_count": 1234,
"like_count": 56,
"comment_count": 12,
"is_top": 0,
"is_hot": 1,
"is_recommend": 1,
"status": 1,
"create_time": "2024-01-15 14:30:25",
"update_time": "2024-01-15 15:20:10",
"publish_time": "2024-01-15 14:30:25"
},
"timestamp": 1705317025
}
文章不存在(404)
{
"code": 404,
"message": "文章不存在",
"timestamp": 1705317025
}
创建文章
接口信息
POST /api/articles
Authorization: Bearer {token}
Content-Type: application/json
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| title | string | 是 | 文章标题 |
| content | string | 是 | 文章内容 |
| summary | string | 否 | 摘要(留空自动提取) |
| cover | string | 否 | 封面图片 URL |
| category_id | integer | 是 | 主分类 ID |
| category_ids | array | 否 | 副分类 ID 数组 |
| tag_ids | array | 否 | 标签 ID 数组 |
| seo_title | string | 否 | SEO 标题 |
| seo_keywords | string | 否 | SEO 关键词 |
| seo_description | string | 否 | SEO 描述 |
| is_top | integer | 否 | 是否置顶(0/1) |
| is_hot | integer | 否 | 是否热门(0/1) |
| is_recommend | integer | 否 | 是否推荐(0/1) |
| status | integer | 否 | 状态(0草稿/1发布),默认 0 |
| publish_time | string | 否 | 发布时间 |
| template | string | 否 | 模板文件名 |
请求示例
{
"title": "Vue 3 Composition API 详解",
"content": "<p>文章正文内容...</p>",
"summary": "本文详细介绍 Vue 3 的 Composition API",
"cover": "https://example.com/uploads/2024/01/15/cover.jpg",
"category_id": 1,
"category_ids": [1, 2],
"tag_ids": [1, 2, 3],
"seo_title": "Vue 3 Composition API 详解 - 前端技术",
"seo_keywords": "Vue3,Composition API,前端框架",
"seo_description": "详细介绍 Vue 3 Composition API 的使用方法和最佳实践",
"is_top": 0,
"is_hot": 1,
"is_recommend": 1,
"status": 1,
"publish_time": "2024-01-15 14:30:00"
}
响应示例
成功响应(201)
{
"code": 201,
"message": "创建成功",
"data": {
"id": 100,
"title": "Vue 3 Composition API 详解",
"create_time": "2024-01-15 14:30:25"
},
"timestamp": 1705317025
}
验证失败(422)
{
"code": 422,
"message": "数据验证失败",
"errors": {
"title": ["标题不能为空"],
"content": ["内容不能为空"],
"category_id": ["请选择分类"]
},
"timestamp": 1705317025
}
代码示例
const createArticle = async (data) => {
try {
const response = await axios.post('/api/articles', {
title: data.title,
content: data.content,
summary: data.summary,
cover: data.cover,
category_id: data.categoryId,
tag_ids: data.tagIds,
seo_title: data.seoTitle,
seo_keywords: data.seoKeywords,
seo_description: data.seoDescription,
status: data.status || 0
}, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
}
})
return response.data
} catch (error) {
console.error('创建文章失败:', error)
throw error
}
}
// 使用示例
createArticle({
title: 'Vue 3 入门教程',
content: '<p>教程内容...</p>',
categoryId: 1,
tagIds: [1, 2, 3],
status: 1
}).then(result => {
console.log('文章创建成功,ID:', result.data.id)
})
更新文章
接口信息
PUT /api/articles/{id}
Authorization: Bearer {token}
Content-Type: application/json
路径参数
| 参数 | 类型 | 说明 |
|---|---|---|
| id | integer | 文章 ID |
请求参数
与创建文章相同,所有字段都是可选的,只更新传入的字段。
请求示例
{
"title": "Vue 3 Composition API 完整指南",
"content": "<p>更新后的内容...</p>",
"is_hot": 1
}
响应示例
成功响应(200)
{
"code": 200,
"message": "更新成功",
"data": {
"id": 1,
"title": "Vue 3 Composition API 完整指南",
"update_time": "2024-01-15 16:45:30"
},
"timestamp": 1705317025
}
无权限(403)
{
"code": 403,
"message": "您没有权限编辑此文章",
"timestamp": 1705317025
}
删除文章
接口信息
DELETE /api/articles/{id}
Authorization: Bearer {token}
路径参数
| 参数 | 类型 | 说明 |
|---|---|---|
| id | integer | 文章 ID |
响应示例
成功响应(200)
{
"code": 200,
"message": "删除成功",
"timestamp": 1705317025
}
代码示例
const deleteArticle = async (id) => {
try {
await axios.delete(`/api/articles/${id}`, {
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`
}
})
console.log('文章删除成功')
} catch (error) {
console.error('删除失败:', error)
throw error
}
}
// 使用示例
deleteArticle(1)
批量删除文章
接口信息
DELETE /api/articles/batch
Authorization: Bearer {token}
Content-Type: application/json
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| ids | array | 是 | 文章 ID 数组 |
请求示例
{
"ids": [1, 2, 3, 4, 5]
}
响应示例
{
"code": 200,
"message": "批量删除成功",
"data": {
"success_count": 5,
"failed_count": 0
},
"timestamp": 1705317025
}
发布文章
接口信息
POST /api/articles/{id}/publish
Authorization: Bearer {token}
Content-Type: application/json
路径参数
| 参数 | 类型 | 说明 |
|---|---|---|
| id | integer | 文章 ID |
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| publish_time | string | 否 | 发布时间,默认当前时间 |
请求示例
{
"publish_time": "2024-01-15 18:00:00"
}
响应示例
{
"code": 200,
"message": "发布成功",
"data": {
"id": 1,
"status": 1,
"publish_time": "2024-01-15 18:00:00"
},
"timestamp": 1705317025
}
审核文章
接口信息
POST /api/articles/{id}/audit
Authorization: Bearer {token}
Content-Type: application/json
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| status | integer | 是 | 审核状态(1通过/2拒绝) |
| reason | string | 否 | 拒绝原因 |
请求示例
{
"status": 1
}
或
{
"status": 2,
"reason": "内容不符合规范"
}
响应示例
{
"code": 200,
"message": "审核通过",
"timestamp": 1705317025
}
文章点赞
接口信息
POST /api/articles/{id}/like
Authorization: Bearer {token}
响应示例
{
"code": 200,
"message": "点赞成功",
"data": {
"like_count": 57
},
"timestamp": 1705317025
}
文章收藏
接口信息
POST /api/articles/{id}/favorite
Authorization: Bearer {token}
响应示例
{
"code": 200,
"message": "收藏成功",
"data": {
"favorite_count": 23
},
"timestamp": 1705317025
}
增加浏览量
接口信息
POST /api/articles/{id}/view
响应示例
{
"code": 200,
"message": "操作成功",
"data": {
"view_count": 1235
},
"timestamp": 1705317025
}
获取相关文章
接口信息
GET /api/articles/{id}/related?limit=5
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| limit | integer | 否 | 数量限制,默认 5 |
响应示例
{
"code": 200,
"message": "获取成功",
"data": [
{
"id": 2,
"title": "Vue 3 响应式原理解析",
"summary": "深入解析 Vue 3 的响应式系统",
"cover": "https://example.com/uploads/cover2.jpg",
"create_time": "2024-01-14 10:20:00"
}
],
"timestamp": 1705317025
}
搜索文章
接口信息
GET /api/articles/search?keyword=Vue
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| keyword | string | 是 | 搜索关键词 |
| page | integer | 否 | 页码 |
| page_size | integer | 否 | 每页数量 |
响应示例
{
"code": 200,
"message": "搜索成功",
"data": {
"list": [
{
"id": 1,
"title": "Vue 3 Composition API 详解",
"summary": "本文详细介绍 Vue 3...",
"highlight": {
"title": "<em>Vue</em> 3 Composition API 详解",
"content": "...介绍 <em>Vue</em> 3..."
}
}
],
"total": 15,
"page": 1,
"page_size": 20
},
"timestamp": 1705317025
}
导出文章
接口信息
GET /api/articles/export?format=excel&ids=1,2,3
Authorization: Bearer {token}
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| format | string | 是 | 格式(excel/csv/pdf) |
| ids | string | 否 | 文章ID,逗号分隔 |
响应
直接返回文件下载流
批量操作
批量更新状态
接口信息
PUT /api/articles/batch
Authorization: Bearer {token}
Content-Type: application/json
请求参数
{
"ids": [1, 2, 3],
"data": {
"status": 1,
"is_hot": 1
}
}
响应示例
{
"code": 200,
"message": "批量更新成功",
"data": {
"success_count": 3,
"failed_count": 0
},
"timestamp": 1705317025
}
错误处理
常见错误
422 验证错误
{
"code": 422,
"message": "数据验证失败",
"errors": {
"title": ["标题不能为空", "标题长度不能超过100个字符"],
"category_id": ["分类不存在"],
"content": ["内容不能为空"]
}
}
403 权限错误
{
"code": 403,
"message": "您没有权限执行此操作"
}
404 未找到
{
"code": 404,
"message": "文章不存在或已被删除"
}
完整示例
Vue 3 组合式 API
<template>
<div class="article-list">
<el-table :data="articles" v-loading="loading">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="title" label="标题" />
<el-table-column prop="category.name" label="分类" />
<el-table-column prop="view_count" label="浏览量" width="100" />
<el-table-column prop="create_time" label="创建时间" width="180" />
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button @click="editArticle(row.id)">编辑</el-button>
<el-button type="danger" @click="deleteArticle(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="page"
:page-size="pageSize"
:total="total"
@current-change="handlePageChange"
/>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import articleApi from '@/api/article'
const articles = ref([])
const loading = ref(false)
const page = ref(1)
const pageSize = ref(20)
const total = ref(0)
const fetchArticles = async () => {
loading.value = true
try {
const res = await articleApi.getList({
page: page.value,
pageSize: pageSize.value
})
articles.value = res.list
total.value = res.total
} catch (error) {
ElMessage.error('获取文章列表失败')
} finally {
loading.value = false
}
}
const handlePageChange = (newPage) => {
page.value = newPage
fetchArticles()
}
const deleteArticle = async (id) => {
try {
await articleApi.delete(id)
ElMessage.success('删除成功')
fetchArticles()
} catch (error) {
ElMessage.error('删除失败')
}
}
onMounted(() => {
fetchArticles()
})
</script>
API 封装
// api/article.js
import request from '@/utils/request'
export default {
// 获取列表
getList(params) {
return request.get('/articles', { params })
},
// 获取详情
getDetail(id) {
return request.get(`/articles/${id}`)
},
// 创建
create(data) {
return request.post('/articles', data)
},
// 更新
update(id, data) {
return request.put(`/articles/${id}`, data)
},
// 删除
delete(id) {
return request.delete(`/articles/${id}`)
},
// 批量删除
batchDelete(ids) {
return request.delete('/articles/batch', { data: { ids } })
},
// 发布
publish(id, publishTime) {
return request.post(`/articles/${id}/publish`, { publish_time: publishTime })
},
// 搜索
search(keyword, page = 1) {
return request.get('/articles/search', {
params: { keyword, page }
})
}
}
