Skip to content

fix(home): 碧蓝档案活动卡片不再把已结束的活动当成当前活动 - #823

Open
beichen24a1 wants to merge 5 commits into
AUTO-MAS-Project:devfrom
beichen24a1:fix/ba-home-card-activity-window
Open

beichen24a1 wants to merge 5 commits into
AUTO-MAS-Project:devfrom
beichen24a1:fix/ba-home-card-activity-window

Conversation

@beichen24a1

@beichen24a1 beichen24a1 commented Sep 16, 2026

Copy link
Copy Markdown

碧蓝档案活动卡片在活动间隙会退回展示「最近结束」的那一场,带来两个用户直接能看到的问题:

  • 已排期的下一场被挡住:下一场活动已经公布时,卡片仍显示上一场,右下角却写着「后续活动即将开始」
  • 倒计时停在 0 天 0 时:有封面的横幅无条件显示「活动剩余时间」,活动一结束就变成 0天0时,看着像时间算错了(无封面的那条分支早已判断结束态并显示「已结束」)

顺带忽略 Kivo 里「常驻化」这类开始与结束同一时刻的公告:它不是一段活动,被挑出来也无法展示。

blueArchivePresentation 的用例相应更新,并补上「间隙优先下一场」「退回最近结束」「忽略零时长条目」三条。

Sourcery 摘要

修正碧蓝档案首页活动卡片的活动选择与倒计时状态展示。

新功能:

  • 显示即将开始活动的开始倒计时及对应本地化文案。

错误修复:

  • 修复活动间隙优先展示已排期下一场活动,并避免已结束活动显示为当前活动的问题。
  • 修复活动结束后封面卡片倒计时停留在 0 天 0 时的问题。
  • 忽略开始与结束时间相同的非活动条目,避免渲染空白活动卡片。

测试:

  • 更新蓝色档案活动卡片用例,覆盖下一场活动、最近结束活动、零时长条目及空状态。
Original summary in English

Sourcery 总结

修正碧蓝档案首页活动卡片的活动选择与倒计时状态展示。

新功能:

  • 显示即将开始的碧蓝档案活动及其开始倒计时。

错误修复:

  • 修复活动间隙优先展示已排期的下一场活动,避免将已结束活动误显示为当前活动。
  • 修复活动结束后活动卡片倒计时停留在 0 天 0 时的问题。
  • 忽略开始与结束时间相同的非活动条目,避免渲染空白活动卡片。

改进:

  • 统一活动卡片和碧蓝档案概览对进行中、即将开始及已结束活动的状态展示。

测试:

  • 更新碧蓝档案活动展示用例,覆盖下一场活动、最近结束活动、零时长条目及空状态。

杂项:

  • 补充本次碧蓝档案首页活动卡片修复的变更记录。
Original summary in English

Sourcery 摘要

修正碧蓝档案首页活动卡片的活动选择与倒计时状态展示。

新功能:

  • 显示即将开始活动的开始倒计时及对应的本地化文案。

问题修复:

  • 修复活动间隙优先展示已排期的下一场活动,避免已结束活动被当作当前活动展示。
  • 修复活动结束后封面卡片仍显示 0 天 0 时倒计时的问题。
  • 忽略开始与结束时间相同的非活动条目,避免渲染空白活动卡片。

测试:

  • 更新碧蓝档案活动卡片测试,覆盖下一场活动、最近结束活动、零时长条目及空状态。
Original summary in English

Sourcery 摘要

修正 Blue Archive 主页活动的选择和倒计时状态,确保即将开始、进行中、已结束以及非活动条目均能正确显示。

新功能:

  • 为主页活动轮播和 Blue Archive 概览中的即将开始活动添加本地化倒计时信息。

错误修复:

  • 在活动间隔期间显示下一个已安排的 Blue Archive 活动,而不是将最近结束的活动视为当前活动。
  • 防止已结束的活动卡片显示过时的 0 天、0 小时倒计时。
  • 忽略无法呈现为活动的零时长公告。

改进:

  • 统一 Blue Archive 活动在进行中、即将开始和已结束状态下的状态、标签及倒计时目标。

测试:

  • 扩展 Blue Archive 展示测试,覆盖即将开始的活动、回退到最近结束的活动、零时长条目和空状态。

杂项:

  • 在变更日志中记录 Blue Archive 主页活动卡片的修复。
Original summary in English

Sourcery 总结

修正碧蓝档案首页活动卡片的活动选择和倒计时状态,确保活动间隙优先展示下一场已排期活动。

新功能:

  • 显示即将开始的碧蓝档案活动,并提供开始时间倒计时及本地化状态文案。

错误修复:

  • 修复活动间隙错误展示最近结束活动并遮挡已排期下一场活动的问题。
  • 修复活动结束后活动卡片倒计时停留在 0 天 0 时的问题。
  • 忽略开始与结束时间相同的非活动条目,避免渲染空白活动卡片。

改进:

  • 统一首页活动轮播与碧蓝档案概览对进行中、即将开始和已结束活动的状态展示。

测试:

  • 更新碧蓝档案展示用例,覆盖下一场活动、最近结束活动、零时长条目及空状态。

杂项:

  • 记录碧蓝档案首页活动卡片修复。
Original summary in English

Summary by Sourcery

修正碧蓝档案首页活动卡片的活动选择和倒计时状态,确保活动间隙优先展示下一场已排期活动。

New Features:

  • 显示即将开始的碧蓝档案活动,并提供开始时间倒计时及本地化状态文案。

Bug Fixes:

  • 修复活动间隙错误展示最近结束活动并遮挡已排期下一场活动的问题。
  • 修复活动结束后活动卡片倒计时停留在 0 天 0 时的问题。
  • 忽略开始与结束时间相同的非活动条目,避免渲染空白活动卡片。

Enhancements:

  • 统一首页活动轮播与碧蓝档案概览对进行中、即将开始和已结束活动的状态展示。

Tests:

  • 更新碧蓝档案展示用例,覆盖下一场活动、最近结束活动、零时长条目及空状态。

Chores:

  • 记录碧蓝档案首页活动卡片修复。
Original summary in English

@sourcery-ai

sourcery-ai Bot commented Sep 16, 2026

Copy link
Copy Markdown

审查者指南

修复碧蓝档案首页活动卡片在活动间隙优先展示已排期活动,过滤零时长公告,并按进行中、即将开始和已结束状态正确呈现倒计时与本地化文案;测试覆盖相关选择、空状态和倒计时场景。

碧蓝档案活动选择流程图

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"]
Loading

文件级变更

变更 详情 文件
调整活动选择优先级并过滤不可展示的零时长条目。
  • 过滤开始时间等于结束时间的公告条目
  • 按进行中、最近即将开始、最近结束的顺序选择卡片活动
  • 将过滤后的活动列表回传,确保空状态正确触发
frontend/src/views/home/blueArchivePresentation.ts
frontend/src/views/home/blueArchivePresentation.test.ts
根据活动阶段切换倒计时目标和显示文案,避免结束活动显示零时长。
  • 为即将开始的活动显示开始倒计时及对应文案
  • 活动结束或无可展示活动时隐藏倒计时,并显示结束状态
  • 进行中活动继续倒计时至结束时间
frontend/src/views/home/components/HomeBlueArchiveOverview.vue
frontend/src/i18n/locales/en-US.ts
frontend/src/i18n/locales/ja-JP.ts
frontend/src/i18n/locales/zh-CN.ts
补充变更记录。
  • 记录活动间隙错误展示和倒计时停滞问题的修复
changelog.d/fix-ba-home-card-activity-window.fix.md

提示与命令

与 Sourcery 交互

  • 触发新的审查: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 根据审查评论生成 GitHub issue: 回复审查评论,请 Sourcery 根据该评论创建 issue。你也可以使用 @sourcery-ai issue 回复审查评论,以根据该评论创建 issue。
  • 生成拉取请求标题: 在拉取请求标题的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在拉取请求中评论 @sourcery-ai title,以随时生成或重新生成标题。
  • 生成拉取请求摘要: 在拉取请求正文中你希望摘要出现的位置写入 @sourcery-ai summary,即可随时生成 PR 摘要。你也可以在拉取请求中评论 @sourcery-ai summary,以随时生成或重新生成摘要。
  • 生成审查者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时生成或重新生成审查者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这一功能会很有用。
  • 忽略所有 Sourcery 审查: 在拉取请求中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。如果你想从头开始一次新的审查,这一功能尤其有用——别忘了评论 @sourcery-ai review 来触发新的审查!

自定义使用体验

访问你的控制面板以便:

  • 启用或禁用审查功能,例如 Sourcery 生成的拉取请求摘要、审查者指南及其他功能。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查说明。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

修复碧蓝档案首页活动卡片在活动间隙优先展示已排期活动,过滤零时长公告,并按进行中、即将开始和已结束状态正确呈现倒计时与本地化文案;测试覆盖相关选择、空状态和倒计时场景。

Flow diagram for Blue Archive activity selection

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"]
Loading

File-Level Changes

Change Details Files
调整活动选择优先级并过滤不可展示的零时长条目。
  • 过滤开始时间等于结束时间的公告条目
  • 按进行中、最近即将开始、最近结束的顺序选择卡片活动
  • 将过滤后的活动列表回传,确保空状态正确触发
frontend/src/views/home/blueArchivePresentation.ts
frontend/src/views/home/blueArchivePresentation.test.ts
根据活动阶段切换倒计时目标和显示文案,避免结束活动显示零时长。
  • 为即将开始的活动显示开始倒计时及对应文案
  • 活动结束或无可展示活动时隐藏倒计时,并显示结束状态
  • 进行中活动继续倒计时至结束时间
frontend/src/views/home/components/HomeBlueArchiveOverview.vue
frontend/src/i18n/locales/en-US.ts
frontend/src/i18n/locales/ja-JP.ts
frontend/src/i18n/locales/zh-CN.ts
补充变更记录。
  • 记录活动间隙错误展示和倒计时停滞问题的修复
changelog.d/fix-ba-home-card-activity-window.fix.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嘿——我发现了 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:10frontend/src/views/home/blueArchivePresentation.ts:25


Sourcery 对开源项目免费——如果您喜欢我们的评审,请考虑分享 ✨
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 is free for open source - if you like our reviews please consider sharing them ✨

Comment thread frontend/src/views/home/blueArchivePresentation.ts
Comment thread frontend/src/views/home/blueArchivePresentation.ts
回应 Sourcery 在 AUTO-MAS-Project#823 提出的两条意见:

- 卡片区分「未开始 / 进行中 / 已结束」三种状态:展示还没开始的活动时,倒计时数到它的
  开始时间(标签改为「距开始」),不再拿结束时间冒充「活动剩余时间」;已结束则不倒计时
- blueArchivePresentation 一并回传过滤后的 activities 列表,避免响应里只剩零时长公告时,
  组件按非空列表跳过空状态、渲染出日期为空的卡片

@qiyinxi qiyinxi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审了 48cbd71,vitest 597 passed、lint 通过,typecheck 的 4 个错是 dev 既有(#814)。改动本身对,但优先级改成「进行中 > 下一场 > 最近结束」之后,另外两条展示路径还是老逻辑,间隙里会更常走到:

  1. 无封面分支没动(HomeBlueArchiveOverview.vue#L117-L120):仍是「活动剩余时间」+ 倒计到 overview.endTime。下一场没封面、或封面加载失败时,显示的是一个还没开始的活动的结束倒计时。
  2. 首页轮播同样:Home.vue#L334sraActivityBanner 只带 endTime,HomeActivityCarousel.vue#L55-L58 只有「剩余 / 已结束」两态;改完后间隙里轮播显示下一场名字 + 倒计到它的结束时间,改之前显示「最近结束 + 已结束」反而是对的。banner 得带 startTime(或 phase),轮播按阶段显示「距开始」。

nit:有封面分支展示下一场时,L78 的「{time} 结束」和 L100 的「后续活动即将开始」和卡片正在展示的内容对不上。

另外「进行中」多条时这里取最早结束优先,#733 后端取最早开始优先(JP 今天两者结果不同),请两边统一成这里的规则。

@HarcoChen

Copy link
Copy Markdown
Contributor

@sourcery-ai review

回应 qiyinxi 在 AUTO-MAS-Project#823 的 review:无封面信息条改用与有封面分支同一套 phase 判断(未开始时倒计到开始时间、标题改「距开始」);轮播 banner 数据补上 startTime,间隙里轮到下一场时显示「距开始」并倒计到开始时间;有封面卡片展示下一场时「{time} 结束」改说「{time} 开始」,不再重复「后续活动即将开始」。
@beichen24a1

Copy link
Copy Markdown
Author

三处都改了,推在 79882996

  1. 无封面分支HomeBlueArchiveOverview.vue:119):改用与有封面分支同一套 phase 判断(running / upcoming / ended / none),展示还没开始的活动时倒计到开始时间、标题显示「距开始」,不再拿结束时间冒充「活动剩余时间」。下一场没封面、或封面加载失败时都会走这条路径。
  2. 轮播HomeActivityCarousel.vue:55):给 ActivityBannerSourceActivityBannerItem 各补了 startTime(终末地取 record.StartTime、明日方舟取 activity.UtcStartTime、蓝档等走 sraActivityBanneroverview.startTime),轮播在「还没开始」时把 label 换成「距开始」、倒计到开始时间;已结束那一态的行为没动,免得影响其它 7 个游戏。
  3. nit:有封面卡片展示下一场时,时间行改说「{time} 开始」(新增 home.bluearchive.startsAt),「后续活动即将开始」在正展示下一场时不再显示。

验证:vitest 597 passed(64 个文件,含 i18n 词表校验)、lint 0 errors、typecheck 仍只剩 dev 既有的那 4 个(#814)。三个语言各补了「距开始」与「{time} 开始」两个词条。

第 4 点(「进行中」多条取最早结束优先)认同你的规则#733 后端现在取的是最早开始,我会改成最早结束,两处统一。那边还有 HarcoChen 的架构意见(统一活动信息的获取、BAAH 端点别塞 scripts.py)要一起处理,改动面较大,我会在 #733 上单独说明。

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嘿——我发现了 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:237frontend/src/views/home/blueArchivePresentation.ts:22


Sourcery 对开源项目免费——如果您喜欢我们的审查,请考虑分享它们 ✨
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


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread frontend/src/views/home/components/HomeBlueArchiveOverview.vue
Comment thread frontend/src/views/home/blueArchivePresentation.ts
beichen24a1 added a commit to beichen24a1/AUTO-MAS that referenced this pull request Sep 17, 2026
回应 qiyinxi 在 AUTO-MAS-Project#823 的意见:后端原来取最早开始,与首页卡片(取最早结束)不是一套口径,JP 今天两处会指向不同活动。改成同一口径,对应测试一并更新。
回应 Sourcery 的意见:currentPhase 与 countdownTarget 原来读 Date.now(),不是响应式的,跨过活动开始或结束时倒计时已经归零、标签却停在旧阶段。改成一个每秒更新的 ref 时钟驱动(卸载时清理),顺带把 activeActivities 与 getPlainTimeStatus 也接上同一个时钟,整个组件的「现在」只有一个来源。
@beichen24a1

Copy link
Copy Markdown
Author

@sourcery-ai review

@sourcery-ai

sourcery-ai Bot commented Sep 17, 2026

Copy link
Copy Markdown

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-ai review. Upgrade to get a review now.

@beichen24a1

Copy link
Copy Markdown
Author

补一条状态说明,免得下面的评估面板被误读。

Sourcery 上一轮(15:57)提的 2 个问题都已经处理

  1. 响应式问题HomeBlueArchiveOverview.vue)→ 701e3daccurrentPhase / countdownTarget / activeActivities / getPlainTimeStatus 改由每秒更新一次的 ref 时钟驱动(卸载时清理),不再各自调用 Date.now()。跨过活动开始或结束时,标签、倒计时目标与配色会在下一秒跟着切。
  2. 时间显示不一致blueArchivePresentation.ts:22)→ 其实在 79882996 就已经改掉了:日期行按阶段取 timeLabel(未开始时说「{time} 开始」),无封面分支换用 remainingLabel / countdownTarget,两个分支共用同一套 currentPhase

刚才想请 Sourcery 重跑一次做确认,它的回复是免费审查额度已用完(250,000 diff 字符 / 7 天,提示约 2 天 23 小时后才能再请求),所以面板上的「等待批准」不会再自动更新——不是这里还有未处理的问题

当前状态:全量 vitest 597 passed(64 个文件)、lint 0 errors、typecheck 仅剩 dev 既有的 4 个(#814),CI 三项全绿,GitHub 侧显示 CLEAN / MERGEABLE

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants