fix(home): 碧蓝档案活动卡片不再把已结束的活动当成当前活动 - #823
beichen24a1 wants to merge 5 commits into
Conversation
审查者指南修复碧蓝档案首页活动卡片在活动间隙优先展示已排期活动,过滤零时长公告,并按进行中、即将开始和已结束状态正确呈现倒计时与本地化文案;测试覆盖相关选择、空状态和倒计时场景。 碧蓝档案活动选择流程图flowchart TD
A["Filter zero-duration entries"] --> B{"Running activity exists?"}
B -->|Yes| C["Select running activity"]
B -->|No| D{"Upcoming activity exists?"}
D -->|Yes| E["Select nearest upcoming activity"]
D -->|No| F{"Ended activity exists?"}
F -->|Yes| G["Select most recently ended activity"]
F -->|No| H["Return empty activity overview"]
文件级变更
提示与命令与 Sourcery 交互
自定义使用体验访问你的控制面板以便:
获取帮助Original review guide in EnglishReviewer's Guide修复碧蓝档案首页活动卡片在活动间隙优先展示已排期活动,过滤零时长公告,并按进行中、即将开始和已结束状态正确呈现倒计时与本地化文案;测试覆盖相关选择、空状态和倒计时场景。 Flow diagram for Blue Archive activity selectionflowchart TD
A["Filter zero-duration entries"] --> B{"Running activity exists?"}
B -->|Yes| C["Select running activity"]
B -->|No| D{"Upcoming activity exists?"}
D -->|Yes| E["Select nearest upcoming activity"]
D -->|No| F{"Ended activity exists?"}
F -->|Yes| G["Select most recently ended activity"]
F -->|No| H["Return empty activity overview"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
嘿——我发现了 2 个问题
面向 AI Agent 的提示
请处理本次代码审查中的评论:
## 单独评论
### 评论 1
<location path="frontend/src/views/home/blueArchivePresentation.ts" line_range="10" />
<code_context>
const time = (value: string) => new Date(value).getTime()
- const activities = overview.activities
+ // 开始与结束同一时刻的条目(如「常驻化」公告)不是一段活动,挑出来也没法展示
+ const activities = overview.activities.filter(item => time(item.endTime) > time(item.startTime))
const running = activities
.filter(item => time(item.startTime) <= now && time(item.endTime) > now)
</code_context>
<issue_to_address>
**问题(bug_risk):** 一个有效的即将开始的活动会被选中用于横幅展示,但倒计时仍然使用 `overview.endTime`,因此在活动间隔期间,它倒计时的是即将开始活动的结束时间,而不是开始时间,并将其显示在“活动剩余时间”下方。因此,对于尚未开始的活动,卡片会显示具有误导性的剩余时长。
**触发条件:** 当前没有正在进行的活动,且下一个预定活动设置了封面时。
**建议修复:** 使用即将开始活动的 `startTime` 作为倒计时目标,并将其标记为开始倒计时;或者为即将开始的活动和正在进行的活动保留独立的展示状态。
</issue_to_address>
### 评论 2
<location path="frontend/src/views/home/blueArchivePresentation.ts" line_range="23-25" />
<code_context>
const time = (value: string) => new Date(value).getTime()
- const activities = overview.activities
+ // 开始与结束同一时刻的条目(如「常驻化」公告)不是一段活动,挑出来也没法展示
+ const activities = overview.activities.filter(item => time(item.endTime) > time(item.startTime))
const running = activities
.filter(item => time(item.startTime) <= now && time(item.endTime) > now)
</code_context>
<issue_to_address>
**问题(broader_impact):** 仅在活动选择时过滤零时长公告,会导致原始的零时长条目仍然保留在返回的 `activities` 数组中。如果输入只包含此类条目,组件会认为活动列表非空,但收到的 `versionName`、`startTime` 和 `endTime` 为空,于是跳过空状态,并渲染出日期无效的信息卡片。
**触发条件:** 服务器响应中只包含开始时间等于结束时间的公告条目,或所有实际活动都被过滤掉时。
**建议修复:** 从 `blueArchivePresentation` 返回经过过滤的活动列表,或者让组件的空状态检查使用经过过滤/可渲染的活动数量。
```suggestion
return {
...overview,
activities,
versionName: current?.name ?? '',
cover: current?.cover ?? '',
startTime: current?.startTime ?? '',
endTime: current?.endTime ?? '',
}
```
</issue_to_address>Sourcery 评估
等待批准。 需要先处理 2 个发现的问题。
阻塞性问题:frontend/src/views/home/blueArchivePresentation.ts:10、frontend/src/views/home/blueArchivePresentation.ts:25
Original comment in English
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="frontend/src/views/home/blueArchivePresentation.ts" line_range="10" />
<code_context>
const time = (value: string) => new Date(value).getTime()
- const activities = overview.activities
+ // 开始与结束同一时刻的条目(如「常驻化」公告)不是一段活动,挑出来也没法展示
+ const activities = overview.activities.filter(item => time(item.endTime) > time(item.startTime))
const running = activities
.filter(item => time(item.startTime) <= now && time(item.endTime) > now)
</code_context>
<issue_to_address>
**issue (bug_risk):** A valid upcoming activity is selected for the banner, but the countdown still uses `overview.endTime`, so during an activity gap it counts down to the upcoming event's end rather than its start and displays it under “活动剩余时间”. The card therefore shows a misleading remaining duration for an event that has not begun.
**Triggers:** When there is no running activity and the next scheduled activity has a cover.
**Suggested fix:** Use the upcoming activity's `startTime` as the countdown target and label it as a start countdown, or retain separate presentation state for upcoming versus running events.
</issue_to_address>
### Comment 2
<location path="frontend/src/views/home/blueArchivePresentation.ts" line_range="23-25" />
<code_context>
const time = (value: string) => new Date(value).getTime()
- const activities = overview.activities
+ // 开始与结束同一时刻的条目(如「常驻化」公告)不是一段活动,挑出来也没法展示
+ const activities = overview.activities.filter(item => time(item.endTime) > time(item.startTime))
const running = activities
.filter(item => time(item.startTime) <= now && time(item.endTime) > now)
</code_context>
<issue_to_address>
**issue (broader_impact):** Filtering zero-duration notices only for activity selection leaves the original zero-duration entries in the returned `activities` array. If the input contains only such entries, the component sees a non-empty activity list but receives empty `versionName`, `startTime`, and `endTime`, skips the empty state, and renders an invalid-date information card.
**Triggers:** When a server response contains only start-equals-end announcement entries, or all real activities have been filtered out.
**Suggested fix:** Return the filtered activity list from `blueArchivePresentation`, or make the component's empty-state check use the filtered/renderable activity count.
```suggestion
return {
...overview,
activities,
versionName: current?.name ?? '',
cover: current?.cover ?? '',
startTime: current?.startTime ?? '',
endTime: current?.endTime ?? '',
}
```
</issue_to_address>Sourcery assessment
Approval pending. 2 findings to address first.
Blocking findings: frontend/src/views/home/blueArchivePresentation.ts:10, frontend/src/views/home/blueArchivePresentation.ts:25
回应 Sourcery 在 AUTO-MAS-Project#823 提出的两条意见: - 卡片区分「未开始 / 进行中 / 已结束」三种状态:展示还没开始的活动时,倒计时数到它的 开始时间(标签改为「距开始」),不再拿结束时间冒充「活动剩余时间」;已结束则不倒计时 - blueArchivePresentation 一并回传过滤后的 activities 列表,避免响应里只剩零时长公告时, 组件按非空列表跳过空状态、渲染出日期为空的卡片
qiyinxi
left a comment
There was a problem hiding this comment.
审了 48cbd71,vitest 597 passed、lint 通过,typecheck 的 4 个错是 dev 既有(#814)。改动本身对,但优先级改成「进行中 > 下一场 > 最近结束」之后,另外两条展示路径还是老逻辑,间隙里会更常走到:
- 无封面分支没动(HomeBlueArchiveOverview.vue#L117-L120):仍是「活动剩余时间」+ 倒计到
overview.endTime。下一场没封面、或封面加载失败时,显示的是一个还没开始的活动的结束倒计时。 - 首页轮播同样:Home.vue#L334 经
sraActivityBanner只带 endTime,HomeActivityCarousel.vue#L55-L58 只有「剩余 / 已结束」两态;改完后间隙里轮播显示下一场名字 + 倒计到它的结束时间,改之前显示「最近结束 + 已结束」反而是对的。banner 得带 startTime(或 phase),轮播按阶段显示「距开始」。
nit:有封面分支展示下一场时,L78 的「{time} 结束」和 L100 的「后续活动即将开始」和卡片正在展示的内容对不上。
另外「进行中」多条时这里取最早结束优先,#733 后端取最早开始优先(JP 今天两者结果不同),请两边统一成这里的规则。
|
@sourcery-ai review |
回应 qiyinxi 在 AUTO-MAS-Project#823 的 review:无封面信息条改用与有封面分支同一套 phase 判断(未开始时倒计到开始时间、标题改「距开始」);轮播 banner 数据补上 startTime,间隙里轮到下一场时显示「距开始」并倒计到开始时间;有封面卡片展示下一场时「{time} 结束」改说「{time} 开始」,不再重复「后续活动即将开始」。
|
三处都改了,推在
验证: 第 4 点(「进行中」多条取最早结束优先)认同你的规则: |
There was a problem hiding this comment.
嘿——我发现了 2 个问题
AI Agent 提示词
请处理本次代码审查中的评论:
## 单独的评论
### 评论 1
<location path="frontend/src/views/home/components/HomeBlueArchiveOverview.vue" line_range="229-237" />
<code_context>
+const currentPhase = computed<'running' | 'upcoming' | 'ended' | 'none'>(() => {
+ const { startTime, endTime } = overview.value
+ if (!endTime) return 'none'
+ const now = Date.now()
+ if (now >= getCountdownValue(endTime)) return 'ended'
+ if (now < getCountdownValue(startTime)) return 'upcoming'
+ return 'running'
+})
</code_context>
<issue_to_address>
**issue (bug_risk):** `currentPhase` 和 `countdownTarget` 依赖 `Date.now()`,而 `Date.now()` 不是响应式的,因此它们只会在 `overview` 发生变化时重新计算。当一个即将开始的活动开始,或一个进行中的活动结束时,标签和目标值在下一次数据刷新前都不会切换;倒计时已经归零,但界面仍显示旧的阶段。
**触发条件:** 页面在没有刷新 overview 的情况下持续打开,并跨越了活动的开始或结束时间。
**建议修复:** 使用至少每秒更新一次的响应式时钟驱动计算状态,或者在倒计时生命周期中更新阶段和目标值。
```suggestion
// 卡片当前展示的是哪一种活动:进行中、还没开始、刚结束,或没有能展示的活动
const currentTime = ref(Date.now())
setInterval(() => {
currentTime.value = Date.now()
}, 1000)
const currentPhase = computed<'running' | 'upcoming' | 'ended' | 'none'>(() => {
const { startTime, endTime } = overview.value
if (!endTime) return 'none'
if (currentTime.value >= getCountdownValue(endTime)) return 'ended'
if (currentTime.value < getCountdownValue(startTime)) return 'upcoming'
return 'running'
})
```
</issue_to_address>
### 评论 2
<location path="frontend/src/views/home/blueArchivePresentation.ts" line_range="22" />
<code_context>
+ .sort((a, b) => time(b.endTime) - time(a.endTime))
+ // 进行中的活动优先;活动间隙先让位给已排期的下一场,两者都没有才退回最近结束的那一场,
+ // 免得卡片在活动间隙整个空掉
+ const current = running[0] ?? upcoming[0] ?? ended[0]
return {
...overview,
</code_context>
<issue_to_address>
**issue (bug_risk):** `blueArchivePresentation` 选中一个即将开始的活动后,卡片中的其他时间显示仍然使用 `endTime`:有封面分支会将日期标记为 `endsAt`,无封面分支则会在 `versionRemaining` 下倒计时至结束时间。因此,卡片可能在结束日期旁显示开始倒计时,或者将整个未来活动的持续时间作为倒计时,而不是倒计时到活动开始。
**触发条件:** 活动间隙期间选中了下一场已排期的活动,且该活动的开始时间在未来。
**建议修复:** 让日期行和无封面倒计时使用相同的、依赖活动阶段的目标值和标签;对于即将开始的活动,应选择 `startTime` 和 `startsIn`。
</issue_to_address>Sourcery 评估
等待批准。 请先处理 2 个发现的问题。
阻塞性发现:frontend/src/views/home/components/HomeBlueArchiveOverview.vue:237、frontend/src/views/home/blueArchivePresentation.ts:22
Original comment in English
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="frontend/src/views/home/components/HomeBlueArchiveOverview.vue" line_range="229-237" />
<code_context>
+const currentPhase = computed<'running' | 'upcoming' | 'ended' | 'none'>(() => {
+ const { startTime, endTime } = overview.value
+ if (!endTime) return 'none'
+ const now = Date.now()
+ if (now >= getCountdownValue(endTime)) return 'ended'
+ if (now < getCountdownValue(startTime)) return 'upcoming'
+ return 'running'
+})
</code_context>
<issue_to_address>
**issue (bug_risk):** `currentPhase` and `countdownTarget` depend on `Date.now()`, which is not reactive, so they are evaluated only when `overview` changes. When an upcoming event starts or a running event ends, the label and target never transition until the next data refresh; the countdown reaches zero while still showing the old phase.
**Triggers:** When the page remains open across an event start or end without an overview refresh.
**Suggested fix:** Drive the computed state from a reactive clock updated at least once per second, or update the phase/target from the countdown lifecycle.
```suggestion
// 卡片当前展示的是哪一种活动:进行中、还没开始、刚结束,或没有能展示的活动
const currentTime = ref(Date.now())
setInterval(() => {
currentTime.value = Date.now()
}, 1000)
const currentPhase = computed<'running' | 'upcoming' | 'ended' | 'none'>(() => {
const { startTime, endTime } = overview.value
if (!endTime) return 'none'
if (currentTime.value >= getCountdownValue(endTime)) return 'ended'
if (currentTime.value < getCountdownValue(startTime)) return 'upcoming'
return 'running'
})
```
</issue_to_address>
### Comment 2
<location path="frontend/src/views/home/blueArchivePresentation.ts" line_range="22" />
<code_context>
+ .sort((a, b) => time(b.endTime) - time(a.endTime))
+ // 进行中的活动优先;活动间隙先让位给已排期的下一场,两者都没有才退回最近结束的那一场,
+ // 免得卡片在活动间隙整个空掉
+ const current = running[0] ?? upcoming[0] ?? ended[0]
return {
...overview,
</code_context>
<issue_to_address>
**issue (bug_risk):** After `blueArchivePresentation` selects an upcoming activity, the card's other time displays still use `endTime`: the cover branch labels the date as `endsAt`, and the no-cover branch counts down under `versionRemaining` to the end. The card therefore shows a start countdown beside an end date, or counts down the entire future activity instead of counting down to its start.
**Triggers:** When the next scheduled activity is selected during an activity gap and its start time is in the future.
**Suggested fix:** Use the same phase-dependent target and label for the date row and the no-cover countdown, selecting `startTime` and `startsIn` for upcoming activities.
</issue_to_address>Sourcery assessment
Approval pending. 2 findings to address first.
Blocking findings: frontend/src/views/home/components/HomeBlueArchiveOverview.vue:237, frontend/src/views/home/blueArchivePresentation.ts:22
回应 qiyinxi 在 AUTO-MAS-Project#823 的意见:后端原来取最早开始,与首页卡片(取最早结束)不是一套口径,JP 今天两处会指向不同活动。改成同一口径,对应测试一并更新。
回应 Sourcery 的意见:currentPhase 与 countdownTarget 原来读 Date.now(),不是响应式的,跨过活动开始或结束时倒计时已经归零、标签却停在旧阶段。改成一个每秒更新的 ref 时钟驱动(卸载时清理),顺带把 activeActivities 与 getPlainTimeStatus 也接上同一个时钟,整个组件的「现在」只有一个来源。
|
@sourcery-ai review |
|
Sorry @beichen24a1, you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 2 days and 23 hours by commenting |
|
补一条状态说明,免得下面的评估面板被误读。 Sourcery 上一轮(15:57)提的 2 个问题都已经处理:
刚才想请 Sourcery 重跑一次做确认,它的回复是免费审查额度已用完(250,000 diff 字符 / 7 天,提示约 2 天 23 小时后才能再请求),所以面板上的「等待批准」不会再自动更新——不是这里还有未处理的问题。 当前状态:全量 |
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
碧蓝档案活动卡片在活动间隙会退回展示「最近结束」的那一场,带来两个用户直接能看到的问题:
0天0时,看着像时间算错了(无封面的那条分支早已判断结束态并显示「已结束」)顺带忽略 Kivo 里「常驻化」这类开始与结束同一时刻的公告:它不是一段活动,被挑出来也无法展示。
blueArchivePresentation的用例相应更新,并补上「间隙优先下一场」「退回最近结束」「忽略零时长条目」三条。Sourcery 摘要
修正碧蓝档案首页活动卡片的活动选择与倒计时状态展示。
新功能:
错误修复:
测试:
Original summary in English
Sourcery 总结
修正碧蓝档案首页活动卡片的活动选择与倒计时状态展示。
新功能:
错误修复:
改进:
测试:
杂项:
Original summary in English
Sourcery 摘要
修正碧蓝档案首页活动卡片的活动选择与倒计时状态展示。
新功能:
问题修复:
测试:
Original summary in English
Sourcery 摘要
修正 Blue Archive 主页活动的选择和倒计时状态,确保即将开始、进行中、已结束以及非活动条目均能正确显示。
新功能:
错误修复:
改进:
测试:
杂项:
Original summary in English
Sourcery 总结
修正碧蓝档案首页活动卡片的活动选择和倒计时状态,确保活动间隙优先展示下一场已排期活动。
新功能:
错误修复:
改进:
测试:
杂项:
Original summary in English
Summary by Sourcery
修正碧蓝档案首页活动卡片的活动选择和倒计时状态,确保活动间隙优先展示下一场已排期活动。
New Features:
Bug Fixes:
Enhancements:
Tests:
Chores:
Original summary in English