| 
					
				 | 
			
			
				@@ -17,6 +17,7 @@ const {Op} = require('sequelize') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {String|Array} [cropIds] 作物筛选ID,支持逗号分隔的多个ID或数组形式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {Number} [categoryId] 用户分类ID,根据用户传递的category参数值进行精确匹配 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {Number} [isRecommended] 推荐筛选,0-非推荐文章,1-推荐文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [topPosition] 置顶筛选,0-非置顶文章,1-置顶文章 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {String|Array} [newsTypeIds] 文章类型筛选ID,支持逗号分隔的多个ID或数组形式,根据type字段进行筛选 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Boolean} status 请求状态 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -34,6 +35,7 @@ const {Op} = require('sequelize') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Number} data.articles.category 用户分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Number} data.articles.crop 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Number} data.articles.isRecommended 是否推荐(0-不推荐,1-推荐) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.articles.topPosition 是否置顶(0-不置顶,1-置顶) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {String} [data.articles.seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {String} [data.articles.seoDescription] SEO描述 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Date} data.articles.createdAt 创建时间 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -67,6 +69,7 @@ const {Op} = require('sequelize') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *         "category": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *         "crop": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *         "isRecommended": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *         "topPosition": 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *         "seoKeyword": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *         "seoDescription": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *         "createdAt": "2025-09-14T09:21:24.000Z", 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -109,12 +112,15 @@ router.get('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         const offset = (currentPage - 1) * pageSize 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         const condition = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            order:[['updatedAt','DESC']], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            order:[ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ['topPosition', 'DESC'], // 置顶文章优先(1在前,0在后) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ['updatedAt', 'DESC']    // 然后按更新时间倒序 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             limit:pageSize, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             offset, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             attributes: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 'id', 'title', 'subtitle', 'content', 'type', 'img', 'date',  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                'author', 'category', 'crop', 'isRecommended', 'seoKeyword',  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                'author', 'category', 'crop', 'isRecommended', 'topPosition', 'seoKeyword',  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 'seoDescription', 'createdAt', 'updatedAt' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             include: [{ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -174,6 +180,14 @@ router.get('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 置顶筛选 - 根据是否置顶进行筛选 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(query.topPosition !== undefined){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            const topPosition = parseInt(query.topPosition); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(!isNaN(topPosition) && (topPosition === 0 || topPosition === 1)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                whereConditions.topPosition = topPosition; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // 文章类型筛选 - 支持多选 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if(query.newsTypeIds){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             let typeIds = []; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -246,6 +260,7 @@ router.get('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Number} data.category 用户分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Number} data.crop 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Number} data.isRecommended 是否推荐(0-不推荐,1-推荐) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.topPosition 是否置顶(0-不置顶,1-置顶) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {String} [data.seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {String} [data.seoDescription] SEO描述 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Date} data.createdAt 创建时间 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -273,6 +288,7 @@ router.get('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "category": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "crop": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "isRecommended": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "topPosition": 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "seoKeyword": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "seoDescription": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "createdAt": "2025-09-14T09:21:24.000Z", 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -346,6 +362,7 @@ router.get('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {Number} [category] 用户分类ID(用户传递的参数) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {Number} [crop] 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {Number} [isRecommended=0] 是否推荐,0-不推荐,1-推荐 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [topPosition=0] 是否置顶,0-不置顶,1-置顶 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {String} [subtitle] 副标题(最大200字符) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {String} [seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {String} [seoDescription] SEO描述 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -364,6 +381,7 @@ router.get('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Number} data.category 用户分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Number} data.crop 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Number} data.isRecommended 是否推荐 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiSuccess {Number} data.topPosition 是否置顶 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {String} [data.seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {String} [data.seoDescription] SEO描述 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiSuccess {Date} data.createdAt 创建时间 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -386,6 +404,7 @@ router.get('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "category": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "crop": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "isRecommended": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "topPosition": 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "seoKeyword": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "seoDescription": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "createdAt": "2025-09-14T09:21:49.333Z", 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -416,6 +435,14 @@ router.get('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *   "message": "请求参数错误", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *   "errors": ["副标题长度不能超过200个字符"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiErrorExample {json} Error-Response: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * HTTP/1.1 400 Bad Request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "status": false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "message": "请求参数错误", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   "errors": ["置顶字段只能是0或1"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 router.post('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -456,7 +483,8 @@ router.post('/', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if(error.message === '标题不能为空' || error.message === '内容不能为空' ||  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            error.message.includes('长度不能超过') || error.message.includes('不允许的脚本标签') || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           error.message.includes('推荐字段只能是0或1') || error.message.includes('副标题长度不能超过')){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           error.message.includes('推荐字段只能是0或1') || error.message.includes('置顶字段只能是0或1') ||  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           error.message.includes('副标题长度不能超过')){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             res.status(400).json({  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 status:false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 message:'请求参数错误', 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -568,6 +596,7 @@ router.delete('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {Number} [category] 用户分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {Number} [crop] 作物分类ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {Number} [isRecommended] 是否推荐,0-不推荐,1-推荐 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @apiParam {Number} [topPosition] 是否置顶,0-不置顶,1-置顶 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {String} [subtitle] 副标题(最大200字符) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {String} [seoKeyword] SEO关键词 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * @apiParam {String} [seoDescription] SEO描述 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -593,6 +622,7 @@ router.delete('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "category": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "crop": 43, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "isRecommended": 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     "topPosition": 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "seoKeyword": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "seoDescription": null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *     "createdAt": "2025-09-14T09:21:49.333Z", 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -614,6 +644,14 @@ router.delete('/:id', async function(req, res, next) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *   "message": "请求参数错误", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *   "errors": ["推荐字段只能是0或1"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @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 { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -706,6 +744,7 @@ function filterBody(req){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             category: req.body.category !== undefined ? parseInt(req.body.category) : null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             crop: req.body.crop !== undefined ? parseInt(req.body.crop) : null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             isRecommended: req.body.isRecommended !== undefined ? parseInt(req.body.isRecommended) : 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            topPosition: req.body.topPosition !== undefined ? parseInt(req.body.topPosition) : 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 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -735,6 +774,11 @@ function filterBody(req){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             throw new Error('推荐字段只能是0或1'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 验证置顶字段 - 只能是0或1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (body.topPosition !== 0 && body.topPosition !== 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            throw new Error('置顶字段只能是0或1'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // 验证副标题长度 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (body.subtitle && body.subtitle.length > 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             throw new Error('副标题长度不能超过200个字符'); 
			 |