| 
					
				 | 
			
			
				@@ -3,9 +3,96 @@ const router = express.Router(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const {Article, Category} = require('../../models') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const {Op} = require('sequelize') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/*  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    查询文章列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GET /admin/articles 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @api {get} /admin/articles 查询文章列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiName GetArticles 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiGroup Articles 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiVersion 1.0.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiDescription 获取文章列表,支持分页和多条件筛选 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [currentPage=1] 当前页码,默认为1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [pageSize=10] 每页显示数量,默认为10 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [title] 标题搜索关键词(模糊匹配) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String|Array} [cropIds] 作物筛选ID,支持逗号分隔的多个ID或数组形式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [categoryId] 用户分类ID,根据用户传递的category参数值进行精确匹配 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [isRecommended] 推荐筛选,0-非推荐文章,1-推荐文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Boolean} status 请求状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} message 响应消息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Object} data 响应数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Array} data.articles 文章列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.articles.id 文章ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} data.articles.title 文章标题 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.articles.subtitle] 文章副标题 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} data.articles.content 文章内容 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.articles.type 文章类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.articles.img] 文章图片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Date} [data.articles.date] 文章日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.articles.author] 作者 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.articles.category 用户分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.articles.crop 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.articles.isRecommended 是否推荐(0-不推荐,1-推荐) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.articles.seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.articles.seoDescription] SEO描述 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Date} data.articles.createdAt 创建时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Date} data.articles.updatedAt 更新时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Object} [data.articles.cropInfo] 作物信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.articles.cropInfo.id 作物ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} data.articles.cropInfo.name 作物名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.articles.cropInfo.level 作物层级 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.articles.cropInfo.parentId 父级作物ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Object} data.pagination 分页信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.pagination.total 总数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.pagination.currentPage 当前页码 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.pagination.pageSize 每页数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccessExample {json} Success-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 200 OK 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "成功", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "data": { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "articles": [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *       { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "id": 96, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "title": "测试文章", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "subtitle": "副标题", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "content": "<p>文章内容</p>", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "type": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "img": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "date": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "author": "作者", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "category": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "crop": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "isRecommended": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "seoKeyword": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "seoDescription": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "createdAt": "2025-09-14T09:21:24.000Z", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "updatedAt": "2025-09-14T09:21:24.000Z", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "cropInfo": { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *           "id": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *           "name": "荔枝", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *           "level": 2, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *           "parentId": 40 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "pagination": { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *       "total": 19, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *       "currentPage": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *       "pageSize": 10 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiErrorExample {json} Error-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 500 Internal Server Error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "失败", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "errors": ["错误信息"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 router.get('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -26,9 +113,9 @@ router.get('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             offset, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             include: [{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 model: Category, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                as: 'categoryInfo', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                as: 'cropInfo', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 attributes: ['id', 'name', 'level', 'parentId'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                required: false // LEFT JOIN,即使没有分类也能返回文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                required: false // LEFT JOIN,即使没有作物也能返回文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -42,29 +129,45 @@ router.get('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 分类筛选 - 支持多选和包含子分类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if(query.categoryIds){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            let categoryIds = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 作物筛选 - 支持多选和包含子分类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(query.cropIds){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let cropIds = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // 处理categoryIds参数(支持逗号分隔的多个ID) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if(typeof query.categoryIds === 'string'){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                categoryIds = query.categoryIds.split(',').map(id => parseInt(id.trim())).filter(id => !isNaN(id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } else if(Array.isArray(query.categoryIds)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                categoryIds = query.categoryIds.map(id => parseInt(id)).filter(id => !isNaN(id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 处理cropIds参数(支持逗号分隔的多个ID) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(typeof query.cropIds === 'string'){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                cropIds = query.cropIds.split(',').map(id => parseInt(id.trim())).filter(id => !isNaN(id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else if(Array.isArray(query.cropIds)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                cropIds = query.cropIds.map(id => parseInt(id)).filter(id => !isNaN(id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                categoryIds = [parseInt(query.categoryIds)].filter(id => !isNaN(id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                cropIds = [parseInt(query.cropIds)].filter(id => !isNaN(id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if(categoryIds.length > 0){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(cropIds.length > 0){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // 获取所有选中的分类及其子分类的ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                const allCategoryIds = await getAllCategoryIdsWithChildren(categoryIds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                const allCropIds = await getAllCategoryIdsWithChildren(cropIds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                whereConditions.category = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    [Op.in]: allCategoryIds 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                whereConditions.crop = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    [Op.in]: allCropIds 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 用户分类筛选 - 根据用户传递的category参数值查询 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(query.categoryId){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            const categoryId = parseInt(query.categoryId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(!isNaN(categoryId)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                whereConditions.category = categoryId; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 推荐筛选 - 根据是否推荐进行筛选 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(query.isRecommended !== undefined){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            const isRecommended = parseInt(query.isRecommended); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(!isNaN(isRecommended) && (isRecommended === 0 || isRecommended === 1)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                whereConditions.isRecommended = isRecommended; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // 如果有查询条件,添加到condition中 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if(Object.keys(whereConditions).length > 0){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             condition.where = whereConditions; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -93,9 +196,76 @@ router.get('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/*  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    查询文章详情 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GET /admin/articles/:id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @api {get} /admin/articles/:id 查询文章详情 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiName GetArticleById 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiGroup Articles 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiVersion 1.0.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiDescription 根据文章ID获取文章详细信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} id 文章ID(路径参数) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Boolean} status 请求状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} message 响应消息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Object} data 文章详细信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.id 文章ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} data.title 文章标题 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.subtitle] 文章副标题 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} data.content 文章内容 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.type 文章类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.img] 文章图片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Date} [data.date] 文章日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.author] 作者 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.category 用户分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.crop 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.isRecommended 是否推荐(0-不推荐,1-推荐) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.seoDescription] SEO描述 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Date} data.createdAt 创建时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Date} data.updatedAt 更新时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Object} [data.cropInfo] 作物信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.cropInfo.id 作物ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} data.cropInfo.name 作物名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.cropInfo.level 作物层级 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.cropInfo.parentId 父级作物ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccessExample {json} Success-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 200 OK 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "成功", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "data": { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "id": 96, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "title": "测试文章", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "subtitle": "副标题", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "content": "<p>文章内容</p>", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "type": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "img": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "date": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "author": "作者", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "category": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "crop": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "isRecommended": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "seoKeyword": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "seoDescription": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "createdAt": "2025-09-14T09:21:24.000Z", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "updatedAt": "2025-09-14T09:21:24.000Z", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "cropInfo": { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *       "id": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *       "name": "荔枝", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *       "level": 2, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *       "parentId": 40 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiErrorExample {json} Error-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 404 Not Found 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "文章未找到" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 router.get('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -106,7 +276,7 @@ router.get('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         const article = await Article.findByPk(id, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             include: [{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 model: Category, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                as: 'categoryInfo', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                as: 'cropInfo', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 attributes: ['id', 'name', 'level', 'parentId'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 required: false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }] 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -133,9 +303,93 @@ router.get('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/*  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    创建文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    POST /admin/articles/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @api {post} /admin/articles 创建文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiName CreateArticle 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiGroup Articles 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiVersion 1.0.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiDescription 创建新的文章,支持富文本内容和图片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} title 文章标题(必填,1-500字符) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} content 文章内容(必填,富文本格式,最大5MB) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [type] 文章类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [img] 文章图片URL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Date} [date] 文章发布日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [author] 作者 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [category] 用户分类ID(用户传递的参数) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [crop] 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [isRecommended=0] 是否推荐,0-不推荐,1-推荐 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [subtitle] 副标题(最大200字符) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [seoDescription] SEO描述 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Boolean} status 请求状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} message 响应消息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Object} data 创建的文章信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.id 文章ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} data.title 文章标题 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.subtitle] 文章副标题 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} data.content 文章内容 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.type 文章类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.img] 文章图片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Date} [data.date] 文章日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.author] 作者 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.category 用户分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.crop 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.isRecommended 是否推荐 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} [data.seoDescription] SEO描述 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Date} data.createdAt 创建时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Date} data.updatedAt 更新时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccessExample {json} Success-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 201 Created 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "成功", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "data": { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "id": 97, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "title": "新文章标题", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "subtitle": "副标题", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "content": "<p>文章内容</p>", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "type": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "img": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "date": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "author": "作者", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "category": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "crop": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "isRecommended": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "seoKeyword": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "seoDescription": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "createdAt": "2025-09-14T09:21:49.333Z", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "updatedAt": "2025-09-14T09:21:49.333Z" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiErrorExample {json} Error-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 400 Bad Request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "请求参数错误", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "errors": ["标题不能为空"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiErrorExample {json} Error-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 400 Bad Request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "请求参数错误", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "errors": ["推荐字段只能是0或1"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiErrorExample {json} Error-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 400 Bad Request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "请求参数错误", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "errors": ["副标题长度不能超过200个字符"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 router.post('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -175,7 +429,8 @@ router.post('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         console.error('请求体:', JSON.stringify(req.body, null, 2)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if(error.message === '标题不能为空' || error.message === '内容不能为空' ||  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           error.message.includes('长度不能超过') || error.message.includes('不允许的脚本标签')){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           error.message.includes('长度不能超过') || error.message.includes('不允许的脚本标签') || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           error.message.includes('推荐字段只能是0或1') || error.message.includes('副标题长度不能超过')){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             res.status(400).json({  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 status:false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 message:'请求参数错误', 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -212,9 +467,32 @@ router.post('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/*  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    删除文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GET /admin/articles/:id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @api {delete} /admin/articles/:id 删除文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiName DeleteArticle 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiGroup Articles 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiVersion 1.0.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiDescription 根据文章ID删除文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} id 文章ID(路径参数) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Boolean} status 请求状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} message 响应消息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccessExample {json} Success-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 200 OK 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "成功" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiErrorExample {json} Error-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 404 Not Found 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "文章未找到" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 router.delete('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -246,9 +524,70 @@ router.delete('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/*  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    更新文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GET /admin/articles/:id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @api {put} /admin/articles/:id 更新文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiName UpdateArticle 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiGroup Articles 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiVersion 1.0.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiDescription 根据文章ID更新文章信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} id 文章ID(路径参数) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [title] 文章标题(1-500字符) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [content] 文章内容(富文本格式,最大5MB) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [type] 文章类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [img] 文章图片URL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Date} [date] 文章发布日期 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [author] 作者 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [category] 用户分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [crop] 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [isRecommended] 是否推荐,0-不推荐,1-推荐 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [subtitle] 副标题(最大200字符) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {String} [seoDescription] SEO描述 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Boolean} status 请求状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {String} message 响应消息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Object} data 更新后的文章信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccessExample {json} Success-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 200 OK 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "成功", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "data": { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "id": 97, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "title": "更新后的标题", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "subtitle": "更新后的副标题", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "content": "<p>更新后的内容</p>", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "type": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "img": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "date": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "author": "作者", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "category": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "crop": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "isRecommended": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "seoKeyword": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "seoDescription": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "createdAt": "2025-09-14T09:21:49.333Z", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "updatedAt": "2025-09-14T09:22:10.000Z" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiErrorExample {json} Error-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 404 Not Found 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "文章未找到" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiErrorExample {json} Error-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 400 Bad Request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "请求参数错误", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "errors": ["推荐字段只能是0或1"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 router.put('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -340,6 +679,8 @@ function filterBody(req){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             author: req.body.author ? String(req.body.author).trim() : null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             category: req.body.category ? parseInt(req.body.category) : null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             crop: req.body.crop ? parseInt(req.body.crop) : null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            isRecommended: req.body.isRecommended !== undefined ? parseInt(req.body.isRecommended) : 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            subtitle: req.body.subtitle ? String(req.body.subtitle).trim() : null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             seoKeyword: req.body.seoKeyword ? String(req.body.seoKeyword).trim() : null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             seoDescription: req.body.seoDescription ? String(req.body.seoDescription).trim() : null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         }; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -363,6 +704,16 @@ function filterBody(req){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             throw new Error('内容过长,请减少内容长度'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 验证推荐字段 - 只能是0或1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (body.isRecommended !== 0 && body.isRecommended !== 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            throw new Error('推荐字段只能是0或1'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 验证副标题长度 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (body.subtitle && body.subtitle.length > 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            throw new Error('副标题长度不能超过200个字符'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // 检查富文本内容是否包含危险标签或脚本 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         const dangerousTags = /<script[^>]*>.*?<\/script>/gi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (dangerousTags.test(body.content)) { 
			 |