@@ -207,8 +207,17 @@ public ArticleListItemResponse publish(Long authorId, Long articleId, Instant pu
207207 if (a .getTitle () == null || a .getTitle ().trim ().isEmpty () || a .getContentMarkdown () == null || a .getContentMarkdown ().trim ().isEmpty ()) {
208208 throw new BizException (4002 , "标题和正文不能为空" );
209209 }
210- a .setStatus (ArticleStatus .PUBLISHED );
211- a .setPublishedAt (publishedAt == null ? Instant .now () : publishedAt );
210+ Instant now = Instant .now ();
211+ // 未来时间:按“定时发布”处理(文章在到点前不可见)
212+ if (publishedAt != null && publishedAt .isAfter (now )) {
213+ a .setStatus (ArticleStatus .SCHEDULED );
214+ a .setScheduledAt (publishedAt );
215+ a .setPublishedAt (null );
216+ } else {
217+ a .setStatus (ArticleStatus .PUBLISHED );
218+ a .setPublishedAt (publishedAt == null ? now : publishedAt );
219+ a .setScheduledAt (null );
220+ }
212221 a .setSubmittedAt (null );
213222 a .setReviewedAt (null );
214223 a .setRejectedReason (null );
@@ -217,6 +226,28 @@ public ArticleListItemResponse publish(Long authorId, Long articleId, Instant pu
217226 return mapListItem (a );
218227 }
219228
229+ /**
230+ * 定时任务扫描到点文章并发布。
231+ *
232+ * @return 本轮成功发布数量(可能为 0)
233+ */
234+ public int publishDueScheduled (int batchSize ) {
235+ int limit = Math .max (1 , Math .min (batchSize , 500 ));
236+ Instant now = Instant .now ();
237+ List <Long > ids = articleMapper .listDueScheduledIds (now , limit );
238+ if (ids .isEmpty ()) return 0 ;
239+
240+ int published = 0 ;
241+ for (Long id : ids ) {
242+ int updated = articleMapper .publishScheduledIfDue (id , now );
243+ if (updated > 0 ) {
244+ published ++;
245+ publishedContentCache .evict (id );
246+ }
247+ }
248+ return published ;
249+ }
250+
220251 public void unpublishOrDelete (Long authorId , Long articleId ) {
221252 Article a = articleMapper .selectById (articleId );
222253 if (a == null ) {
@@ -229,12 +260,13 @@ public void unpublishOrDelete(Long authorId, Long articleId) {
229260 return ;
230261 }
231262 a .setStatus (ArticleStatus .DELETED );
263+ a .setScheduledAt (null );
232264 articleMapper .updateById (a );
233265 publishedContentCache .evict (articleId );
234266 }
235267
236268 public PageResult <ArticleListItemResponse > listMine (Long authorId , int page , int size ) {
237- List <ArticleStatus > statuses = List .of (ArticleStatus .DRAFT , ArticleStatus .PUBLISHED );
269+ List <ArticleStatus > statuses = List .of (ArticleStatus .DRAFT , ArticleStatus .SCHEDULED , ArticleStatus . PUBLISHED );
238270 Page <Article > mpPage = new Page <>(page + 1L , size );
239271 LambdaQueryWrapper <Article > w = Wrappers .lambdaQuery ();
240272 w .eq (Article ::getAuthorId , authorId )
0 commit comments