Skip to content

Commit ceefb4d

Browse files
committed
refactor(article): 优化首页最新文章查询逻辑
- 重构 getIndexRecentArticles 方法,分离查询构建逻辑到独立方法 - 添加置顶文章ID集合构建方法,提高查找效率 - 实现分页补偿机制,确保多页间文章数量一致性 - 修复分页时置顶文章重复显示问题 - 更新 AGENTS.md 文档,补充首页两列对齐约束说明
1 parent 7163de4 commit ceefb4d

File tree

4 files changed

+69
-44
lines changed

4 files changed

+69
-44
lines changed

.claude/CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**遵循并维护/创建**最近的 AGENTS.md 文件。它是一个给 AI 代理使用的自述文件,包含项目上下文和指令。

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- 涉及到新增 Repository(新增表/集合)时,除了 SQL 建表外,必须同步更新 `src/main/resources/repository.json`,并且 Repository 的 `super("...")`/模型常量中不要写 `symphony_` 前缀(框架会根据 `jdbc.tablePrefix` 自动加前缀)。
77
- 除非用户提到代码编译有问题或者主动要求你进行编译,否则不要使用mvn编译java,这个过程会浪费用户的时间,除非你觉得非常有必要,并且询问用户且被同意
88
- 每次遇到新的项目架构关键信息,对后续项目AI使用有帮助的,请主动维护AGENTS.md,注意每次维护不要过度细节,只要让AI正确理解就可以了,防止prompt token过长
9+
- 我和你沟通都是在开发环境(http://localhost:8080),生产环境是摸鱼派(https://fishpi.cn),如果你能调用Chrome,可以调试辅助你诊断代码,注意,如果你编译了js和css,强制刷新开发环境就会生效,如果你改了Java或者FTL,那就需要告知用户通过IDEA重新编译或者重启服务端才能生效
910

1011
## 协作目标
1112
- `AGENTS.md` 保持精简,只保留会影响决策的长期约定;新增内容优先补充“关键链路”,避免堆砌背景信息。
@@ -54,6 +55,7 @@
5455
- 有效期字段:勋章 `expireTime`(毫秒,`0`=永久);会员 `expiresAt`(可回填勋章到期)。
5556
- 首页最新文章链路:`IndexProcessor#loadIndexData` 通过 `ArticleQueryService#getIndexRecentArticles(fetchSize, page)` 组装 classic/mobile 首页“最新文章”;第一页置顶插入与数量行为在该方法维护。
5657
- 首页两列对齐约束:`getIndexRecentArticles` 的第一页会插入全部置顶且不截断;第二页起需按第一页“置顶占位数”补偿 `fetchSize` 与分页偏移,保证两列等高且不丢中间文章。
58+
- 首页右侧排行补偿(无前端延迟):由 `IndexProcessor#loadIndexData` 按两列最新文章的最大行数计算 `rankCompensateRows`,先换算“右栏总补偿行数”再分摊到 `checkinVisibleCount/onlineVisibleCount`,Freemarker 直接按该数量渲染,不再依赖 JS 运行时增删行。
5759
- 路由总入口:`Router#requestMapping` + 各 Processor `register()`;新增路由先决定使用 `loginCheck` / `apiCheck` / `permission` / `anonymousViewCheck` 哪条链路。
5860
- `LoginCheckMidware#handle`:未登录统一 401(特殊 URI `/gen` 返回空 SVG);支持 `Sessions``apiKey` 两种登录态来源。
5961
- 新接口若需“页面登录态 + apiKey 调用”双兼容,路由层优先挂 `loginCheck::handle`,处理方法再读取 `context.attr(User.USER)`;避免只挂 `permission` 导致拿不到当前用户对象。

src/main/java/org/b3log/symphony/processor/IndexProcessor.java

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -453,14 +453,6 @@ public void showWatch(final RequestContext context) {
453453
public synchronized void loadIndexData() {
454454
Map<String, Object> dataModel = new HashMap<>();
455455

456-
// 签到排行
457-
final List<JSONObject> users = activityQueryService.getTopCheckinUsers(10);
458-
dataModel.put(Common.TOP_CHECKIN_USERS, users);
459-
460-
// 在线时间排行
461-
final List<JSONObject> onlineTopUsers = activityQueryService.getTopOnlineTimeUsers(9);
462-
dataModel.put("onlineTopUsers", onlineTopUsers);
463-
464456
// 热议
465457
final List<JSONObject> hotArticles = articleQueryService.getHotArticles(11);
466458
dataModel.put(Common.HOT, hotArticles);
@@ -470,14 +462,37 @@ public synchronized void loadIndexData() {
470462
final List<JSONObject> qaArticles = (List<JSONObject>) result.get(Article.ARTICLES);
471463
dataModel.put(Common.QNA,qaArticles);
472464

465+
final int recentFetchSize = 18;
466+
473467
// 最近文章
474-
final List<JSONObject> recentArticles = articleQueryService.getIndexRecentArticles(18, 1);
468+
final List<JSONObject> recentArticles = articleQueryService.getIndexRecentArticles(recentFetchSize, 1);
475469
dataModel.put(Common.RECENT_ARTICLES, recentArticles);
476470

477471
// 最近文章第二列
478-
final List<JSONObject> recentArticles2 = articleQueryService.getIndexRecentArticles(18, 2);
472+
final List<JSONObject> recentArticles2 = articleQueryService.getIndexRecentArticles(recentFetchSize, 2);
479473
dataModel.put("recentArticles2", recentArticles2);
480474

475+
// 右侧排行补偿行数(由首页置顶导致的额外文章行数决定)
476+
final int maxRecentColumnRows = Math.max(recentArticles.size(), recentArticles2.size());
477+
final int rankCompensateRows = Math.max(0, maxRecentColumnRows - recentFetchSize);
478+
// 文章行高约 40px,排行行高约 34px,先换算为“右栏总补偿行数”后再分摊到两个排行,避免双倍补偿
479+
final int totalRankExtraRows = (int) Math.round((double) rankCompensateRows * 40 / 34);
480+
final int checkinExtraRows = (totalRankExtraRows + 1) / 2;
481+
final int onlineExtraRows = totalRankExtraRows / 2;
482+
final int checkinVisibleCount = 9 + checkinExtraRows;
483+
final int onlineVisibleCount = 8 + onlineExtraRows;
484+
dataModel.put("rankCompensateRows", rankCompensateRows);
485+
dataModel.put("checkinVisibleCount", checkinVisibleCount);
486+
dataModel.put("onlineVisibleCount", onlineVisibleCount);
487+
488+
// 签到排行
489+
final List<JSONObject> users = activityQueryService.getTopCheckinUsers(checkinVisibleCount);
490+
dataModel.put(Common.TOP_CHECKIN_USERS, users);
491+
492+
// 在线时间排行
493+
final List<JSONObject> onlineTopUsers = activityQueryService.getTopOnlineTimeUsers(onlineVisibleCount);
494+
dataModel.put("onlineTopUsers", onlineTopUsers);
495+
481496
// 长篇文章专区(最近 & 热门)
482497
final List<JSONObject> recentLongArticles = articleQueryService.getIndexLongArticles(50);
483498
dataModel.put("recentLongArticles", recentLongArticles);

src/main/resources/skins/classic/index.ftl

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
</#if>
3838
<div class="main">
3939
<div class="wrapper index-full-size-white" id="nightTips" style="display: none"></div>
40-
<div class="wrapper" style="padding-bottom: 20px">
41-
<div class="index-recent fn-flex-1">
40+
<div class="wrapper" id="indexTopWrapper" style="padding-bottom: 20px">
41+
<div class="index-recent fn-flex-1" id="indexRecentColLeft">
4242
<div class="index-head-title">
4343
<div style="float:left;font-size:13px;margin:5px 0 10px 0; font-weight:bold;">最新</div>
4444
<div style="clear:both;"></div>
@@ -74,6 +74,7 @@
7474
.rank {
7575
padding: 7px 15px 7px 15px !important;
7676
}
77+
7778
</style>
7879
<#list recentArticles as article>
7980
<li class="fn-flex">
@@ -102,7 +103,7 @@
102103
</div>
103104

104105
</div>
105-
<div class="index-recent fn-flex-1">
106+
<div class="index-recent fn-flex-1" id="indexRecentColRight">
106107
<div class="index-head-title">
107108
<div style="float:left;font-size:13px;margin:5px 0 10px 0; font-weight:bold;">&nbsp;</div>
108109
<div style="float:right;font-size:13px;margin:5px 0 0 0;">
@@ -138,7 +139,7 @@
138139
</ul>
139140
</div>
140141
</div>
141-
<div class="index-recent fn-flex-1">
142+
<div class="index-recent fn-flex-1" id="indexRankCol">
142143
<div class="module-panel">
143144
<#if TGIF == '0'>
144145
<div class="TGIF__item" style="margin-bottom: 17px; margin-top: 5px">
@@ -179,17 +180,21 @@
179180
</#if>
180181
</div>
181182

182-
<div class="index-head-title">
183-
<div style="float:left;font-size:13px;margin:5px 0 10px 0; font-weight:bold;">今日连签排行</div>
184-
<div style="float:right;font-size:13px;margin:5px 0 0 0;"><a href="${servePath}/top/checkin">更多</a>
183+
<#assign checkinVisibleCount=(checkinVisibleCount!9)>
184+
<#assign onlineVisibleCount=(onlineVisibleCount!8)>
185+
186+
<div>
187+
<div class="index-head-title">
188+
<div style="float:left;font-size:13px;margin:5px 0 10px 0; font-weight:bold;">今日连签排行</div>
189+
<div style="float:right;font-size:13px;margin:5px 0 0 0;"><a href="${servePath}/top/checkin">更多</a>
190+
</div>
191+
<div style="clear:both;"></div>
185192
</div>
186-
<div style="clear:both;"></div>
187-
</div>
188-
<div class="module-panel">
189-
<ul class="module-list">
190-
<#list topCheckinUsers as user>
191-
<#if user_index < 9>
192-
<li class="fn-flex rank topCheckInUsersElement">
193+
<div class="module-panel">
194+
<ul class="module-list">
195+
<#list topCheckinUsers as user>
196+
<#if user_index lt checkinVisibleCount>
197+
<li class="fn-flex rank topCheckInUsersElement">
193198
<#if user_index == 0 || user_index == 1 || user_index == 2>
194199
<span
195200
<#if user_index == 0>
@@ -214,23 +219,23 @@
214219
<a class="tooltipped tooltipped-s fn-right count ft-gray ft-smaller"
215220
aria-label="${checkinStreakPart0Label}${user.userLongestCheckinStreak}${checkinStreakPart1Label}${user.userCurrentCheckinStreak}${checkinStreakPart2Label}"
216221
href="${servePath}/top/checkin">${user.userCurrentCheckinStreak}${checkinStreakPart2Label}</a>
217-
</li>
218-
</#if>
219-
</#list>
220-
</ul>
221-
</div>
222+
</li>
223+
</#if>
224+
</#list>
225+
</ul>
226+
</div>
222227

223-
<div class="index-head-title">
224-
<div style="float:left;font-size:13px;margin:20px 0 10px 0; font-weight:bold;">在线时间排行</div>
225-
<div style="float:right;font-size:13px;margin:20px 0 0 0;"><a href="${servePath}/top/online">更多</a>
228+
<div class="index-head-title">
229+
<div style="float:left;font-size:13px;margin:20px 0 10px 0; font-weight:bold;">在线时间排行</div>
230+
<div style="float:right;font-size:13px;margin:20px 0 0 0;"><a href="${servePath}/top/online">更多</a>
231+
</div>
232+
<div style="clear:both;"></div>
226233
</div>
227-
<div style="clear:both;"></div>
228-
</div>
229-
<div class="module-panel">
230-
<ul class="module-list">
231-
<#list onlineTopUsers as user>
232-
<#if user_index < 8>
233-
<li class="fn-flex rank topCheckInUsersElement">
234+
<div class="module-panel">
235+
<ul class="module-list">
236+
<#list onlineTopUsers as user>
237+
<#if user_index lt onlineVisibleCount>
238+
<li class="fn-flex rank topCheckInUsersElement">
234239
<#if user_index == 0 || user_index == 1 || user_index == 2>
235240
<span
236241
<#if user_index == 0>
@@ -270,10 +275,11 @@
270275
${user.onlineMinute} 分钟
271276
</#if>
272277
</a>
273-
</li>
274-
</#if>
275-
</#list>
276-
</ul>
278+
</li>
279+
</#if>
280+
</#list>
281+
</ul>
282+
</div>
277283
</div>
278284
</div>
279285
</div>
@@ -670,7 +676,7 @@
670676
<div class="index-head-title">
671677
<div style="float:left;font-size:13px;margin:5px 0 10px 0; font-weight:bold;cursor: pointer">最新注册</div>
672678
<#list recentRegUsers as user>
673-
<#if user_index = 0>
679+
<#if user_index == 0>
674680
<a target="_blank" href="${servePath}/member/${user.userName}"
675681
style="float: right; margin: 5px 0 10px 0; color: #646464; text-decoration: none">
676682
🎉 欢迎新人 <b>${user.userName}</b>
@@ -1171,6 +1177,7 @@
11711177
initLongShelfAuto('long-recent', 3600);
11721178
initLongShelfAuto('long-hot', 3600);
11731179
});
1180+
11741181
</script>
11751182
</body>
11761183
</html>

0 commit comments

Comments
 (0)