Skip to content

fix/opus: 大量审查及修复工作#26

Merged
Sealt merged 1 commit into
mainfrom
fix/opus
Mar 6, 2026
Merged

fix/opus: 大量审查及修复工作#26
Sealt merged 1 commit into
mainfrom
fix/opus

Conversation

@Sealt

@Sealt Sealt commented Mar 6, 2026

Copy link
Copy Markdown
Member

chore: 删除 api.md 文档,更新 .gitignore
feat(request): 添加 silent 静默模式、URL 校验、循环引用保护
refactor(request): token 读取改用 authStore,缓存清理计时器封装为函数
fix(request): GET 空参数处理,响应非对象类型兼容
refactor(utils): 移除未使用的工具函数(formatPhone、debounce、throttle 等)
fix(utils/time): formatDateTime 增加无效日期防护,substr 替换为 substring
fix(utils/index): formatDate 增加无效日期校验和未来日期处理
feat(constants): 添加 OPERATOR 运营者角色定义
fix(courseTableCache): classId 始终写入缓存
refactor(image): 移除未使用的 generateLocalFileName 函数
feat(semesterCache): 添加 lastKnownCurrent 方法用于学期变更检测
fix(auth store): expireToken 增加重复调用防护和异常捕获
refactor(countdown store): 改用 countdownAPI 模块,修复排序副作用
fix(notifications store): 修复统计数据响应层级取值错误
refactor(schedule store): getter 改用普通函数支持 this 调用,提取颜色分配逻辑
feat(schedule store): 添加 acknowledgeCurrentSemester,优化学期变更检测
fix(schedule store): updateClass 课表刷新失败不阻断绑定流程
refactor(study-tasks store): 改用 studyTaskAPI 模块,studyTasks 重命名为 pendingTasks
fix(study-tasks store): 新建/恢复任务插入到列表头部
refactor(app): pinia 实例提前创建,移除冗余参数
fix(admin): refreshData 添加异常捕获,配置值复制兼容对象类型
fix(admin/rbac): 角色数据解析增加容错处理
refactor(admin/reviews): 移除不准确的状态计数,增加日期校验
fix(gpa-calculator): 百分制转五分制改为线性换算公式
feat(TodayCourse): 同时段多门课程折叠展示,添加绑定班级入口
refactor(TodayCourse): 支持 debugDate 属性,定时器改用 onBeforeUnmount 清理
feat(StudyTaskCard): 首次加载并行请求待完成和已完成任务
feat(materials): 添加热度/时间排序切换,API 调用统一添加异常捕获
fix(materials/detail): 详情加载添加 try-catch,分享标题增加兜底值
refactor(schedule page): 功能说明弹窗改为网格布局,补充学期切换等说明
fix(schedule): 修复 courseData 非空判断,eventCenter 事件正确解绑
fix(schedule-bind): 绑定成功后仅更新本地用户信息,添加定时器清理
fix(ScheduleTable): 日期显示隐藏年份,触摸事件增加空值防护,使用 maxWeeks
fix(notifications): 投稿入口角色判断修正,内容上限提升至 10000 字
fix(notifications/detail): 分享标题增加可选链兜底
fix(map): 异步操作增加组件卸载检查
fix(discover): 仅登录状态下启动在线人数轮询
feat(final-review): 子题全部作答后自动提交父题,项目数据校验
fix(teacher-reviews): 新增校区必填校验,移除无用定时器
fix(webview): decodeURIComponent 增加异常捕获
fix(profile): 积分显示添加加载和失败状态,改用 useDidShow 刷新
fix(contributions/detail): 移除未实现的删除投稿函数
fix(hero): 移除冗余注释
fix(login): 修复空白字符格式

chore: 删除 api.md 文档,更新 .gitignore
feat(request): 添加 silent 静默模式、URL 校验、循环引用保护
refactor(request): token 读取改用 authStore,缓存清理计时器封装为函数
fix(request): GET 空参数处理,响应非对象类型兼容
refactor(utils): 移除未使用的工具函数(formatPhone、debounce、throttle 等)
fix(utils/time): formatDateTime 增加无效日期防护,substr 替换为 substring
fix(utils/index): formatDate 增加无效日期校验和未来日期处理
feat(constants): 添加 OPERATOR 运营者角色定义
fix(courseTableCache): classId 始终写入缓存
refactor(image): 移除未使用的 generateLocalFileName 函数
feat(semesterCache): 添加 lastKnownCurrent 方法用于学期变更检测
fix(auth store): expireToken 增加重复调用防护和异常捕获
refactor(countdown store): 改用 countdownAPI 模块,修复排序副作用
fix(notifications store): 修复统计数据响应层级取值错误
refactor(schedule store): getter 改用普通函数支持 this 调用,提取颜色分配逻辑
feat(schedule store): 添加 acknowledgeCurrentSemester,优化学期变更检测
fix(schedule store): updateClass 课表刷新失败不阻断绑定流程
refactor(study-tasks store): 改用 studyTaskAPI 模块,studyTasks 重命名为 pendingTasks
fix(study-tasks store): 新建/恢复任务插入到列表头部
refactor(app): pinia 实例提前创建,移除冗余参数
fix(admin): refreshData 添加异常捕获,配置值复制兼容对象类型
fix(admin/rbac): 角色数据解析增加容错处理
refactor(admin/reviews): 移除不准确的状态计数,增加日期校验
fix(gpa-calculator): 百分制转五分制改为线性换算公式
feat(TodayCourse): 同时段多门课程折叠展示,添加绑定班级入口
refactor(TodayCourse): 支持 debugDate 属性,定时器改用 onBeforeUnmount 清理
feat(StudyTaskCard): 首次加载并行请求待完成和已完成任务
feat(materials): 添加热度/时间排序切换,API 调用统一添加异常捕获
fix(materials/detail): 详情加载添加 try-catch,分享标题增加兜底值
refactor(schedule page): 功能说明弹窗改为网格布局,补充学期切换等说明
fix(schedule): 修复 courseData 非空判断,eventCenter 事件正确解绑
fix(schedule-bind): 绑定成功后仅更新本地用户信息,添加定时器清理
fix(ScheduleTable): 日期显示隐藏年份,触摸事件增加空值防护,使用 maxWeeks
fix(notifications): 投稿入口角色判断修正,内容上限提升至 10000 字
fix(notifications/detail): 分享标题增加可选链兜底
fix(map): 异步操作增加组件卸载检查
fix(discover): 仅登录状态下启动在线人数轮询
feat(final-review): 子题全部作答后自动提交父题,项目数据校验
fix(teacher-reviews): 新增校区必填校验,移除无用定时器
fix(webview): decodeURIComponent 增加异常捕获
fix(profile): 积分显示添加加载和失败状态,改用 useDidShow 刷新
fix(contributions/detail): 移除未实现的删除投稿函数
fix(hero): 移除冗余注释
fix(login): 修复空白字符格式
@Sealt
Sealt requested a review from AEnjoy as a code owner March 6, 2026 12:19
@Sealt

Sealt commented Mar 6, 2026

Copy link
Copy Markdown
Member Author

/gemini review

Copilot AI 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.

Pull request overview

This PR performs a broad cleanup and reliability pass across the client: it refactors API access into dedicated modules, enhances the request utility (silent mode, validation, idempotency/cache robustness), and fixes/optimizes multiple pages and stores (schedule, study-tasks, notifications, materials, etc.).

Changes:

  • Refactors the monolithic src/api/index.js into per-domain API modules and updates stores/pages to consume them.
  • Enhances src/utils/request.js (silent mode, URL validation, circular-reference-safe request identifier generation, cache cleanup encapsulation, token sourcing via authStore).
  • Improves schedule/semester handling and multiple UI behaviors (event unbinding, timer cleanup, better error handling, and UX tweaks across pages).

Reviewed changes

Copilot reviewed 57 out of 59 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/utils/time.js Adds invalid-date guarding and safer string handling in date formatting (but see review comment).
src/utils/semesterCache.js Adds last-known-current semester persistence for semester-change detection.
src/utils/request.js Adds silent mode, URL validation, circular reference protection, and cache cleanup encapsulation; token now comes from authStore.
src/utils/index.js Adds invalid date and future-date handling in formatDate; removes unused utilities.
src/utils/image.js Removes unused local filename generator; adjusts cache-cleaning return semantics documentation.
src/utils/courseTableCache.js Always persists classId alongside cached course table entries.
src/utils/constants.js Adds OPERATOR role constant and formatting cleanup.
src/stores/study-tasks.js Switches to studyTaskAPI, renames state fields, adjusts insertion order and list transitions.
src/stores/schedule.js Improves semester-change detection, reduces side effects, adds rollback on failed semester switch, and refactors course color assignment.
src/stores/notifications.js Fixes stats response assignment behavior to match actual return shape.
src/stores/countdown.js Switches to countdownAPI, avoids getter sort side effects, and reuses day-calculation logic.
src/stores/auth.js Adds idempotent/guarded expireToken with try/catch protection.
src/pages/webview/index.vue Adds decodeURIComponent error handling for URL/title params.
src/pages/teacher-reviews/index.vue Removes unused timer cleanup; adds campus required validation and safer date formatting.
src/pages/schedule/schedule-bind/index.vue Clears debounce timer on unmount; updates binding flow to only update local user info.
src/pages/schedule/index.vue Refines help modal UI, fixes courseData emptiness check, adds safer submit guard, and corrects eventCenter unbinding.
src/pages/schedule/components/ScheduleTable.vue Improves date display, touch null-guards, and uses maxWeeks instead of magic number.
src/pages/profile/index.vue Adds loading/failed states for points display and refreshes points on useDidShow.
src/pages/notifications/index.vue Adds unmount cleanup for search timer; adjusts contribution entry gating (but see review comment).
src/pages/notifications/detail/index.vue Adds share title fallbacks via optional chaining.
src/pages/notifications/create/index.vue Raises content length limit to 10000 chars with updated validation message.
src/pages/notifications/categories/index.vue Fixes empty-list handling when computing next sort value.
src/pages/materials/index.vue Adds sorting toggle, and wraps API calls with try/catch/finally for more robust loading state handling.
src/pages/materials/detail/index.vue Adds try/catch with toast on load failure; share title fallbacks.
src/pages/map/index.vue Prevents state updates after unmount for async loading; normalizes image handler signatures.
src/pages/login/index.vue Minor whitespace cleanup.
src/pages/home/components/TodayCourse.vue Adds grouped/expandable rendering for same-slot courses, bind-class shortcut, debug date support, and proper interval cleanup.
src/pages/home/components/StudyTaskCard.vue Parallelizes initial loads (pending/completed/stats), updates to new store getters/fields, and improves pagination state handling.
src/pages/hero/index.vue Removes misleading comments and simplifies response-shape handling.
src/pages/gpa-calculator/index.vue Updates 100→5 GPA conversion to a linear formula with clamping.
src/pages/final-review/index.vue Adds project id validation before navigation.
src/pages/final-review/detail/index.vue Adds sub-question completion auto-submit and optional scroll skipping.
src/pages/discover/index.vue Starts online-count polling only when logged in.
src/pages/contributions/detail/index.vue Removes unimplemented delete contribution function.
src/pages/admin/teacher-reviews/index.vue Removes inaccurate status counts and adds safer date parsing.
src/pages/admin/rbac/index.vue Adds tolerant parsing for roles response format and filters invalid entries.
src/pages/admin/heroes/index.vue Adds error isolation around refresh toast behavior.
src/pages/admin/config/index.vue Adds error isolation around refresh toast behavior; improves clipboard copy for object values.
src/app.js Creates Pinia earlier and simplifies lifecycle hook signatures.
src/api/system.js Adds system/stat API module (health check + online stats).
src/api/studyTask.js Adds study task API module.
src/api/review.js Adds review API module.
src/api/rbac.js Adds RBAC API module.
src/api/questions.js Adds questions API module.
src/api/points.js Adds points API module.
src/api/oss.js Adds OSS API module.
src/api/notification.js Adds notification API module.
src/api/material.js Adds material API module.
src/api/index.js Converts to re-export hub for per-domain API modules.
src/api/hero.js Adds hero API module.
src/api/failRate.js Adds fail-rate API module.
src/api/dictionary.js Adds dictionary API module.
src/api/courseTable.js Adds course-table API module with basic input validation.
src/api/countdown.js Adds countdown API module.
src/api/contribution.js Adds contribution API module.
src/api/config.js Adds config API module with basic input validation.
src/api/auth.js Adds auth + user profile API module.
api.md Removes the API markdown document from the repo.
.gitignore Adds temp/ and CLAUDE.md to ignored paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/pages/notifications/index.vue
Comment thread src/utils/time.js
@Sealt
Sealt merged commit dd4eb15 into main Mar 6, 2026
8 checks passed
@Sealt
Sealt deleted the fix/opus branch March 6, 2026 12:31
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

本次提交是对项目进行的一次全面的代码审查和修复,旨在提升代码质量、增强应用功能和提高系统稳定性。通过代码重构和优化,提高了代码的可读性和可维护性。同时,对API接口进行了调整,统一添加了异常捕获,增强了系统的健壮性。

Highlights

  • 代码审查与修复: 本次提交包含了大量的代码审查和修复工作,旨在提升代码质量和应用稳定性。
  • 功能增强: 新增了静默模式、URL校验、循环引用保护等功能,并对现有功能进行了优化。
  • 代码重构: 对多个模块进行了重构,提高了代码的可读性和可维护性。
  • API 接口调整: 移除了 api.md 文档,并将 API 调用统一添加了异常捕获。
Changelog
  • .gitignore
    • 更新 .gitignore,添加了 temp/ 和 CLAUDE.md 文件。
  • api.md
    • 删除了 api.md 文档。
  • src/api/auth.js
    • 添加了 authAPI 和 userAPI 模块,用于处理认证和用户相关的 API 请求。
  • src/api/config.js
    • 添加了 configAPI 模块,用于处理系统配置相关的 API 请求。
  • src/api/contribution.js
    • 添加了 contributionAPI 模块,用于处理用户投稿相关的 API 请求。
  • src/api/countdown.js
    • 添加了 countdownAPI 模块,用于处理倒数日相关的 API 请求。
  • src/api/courseTable.js
    • 添加了 courseTableAPI 模块,用于处理课程表相关的 API 请求。
  • src/api/dictionary.js
    • 添加了 dictionaryAPI 模块,用于处理词典相关的 API 请求。
  • src/api/failRate.js
    • 添加了 failRateAPI 模块,用于处理挂科率相关的 API 请求。
  • src/api/hero.js
    • 添加了 heroAPI 模块,用于处理英雄榜相关的 API 请求。
  • src/api/index.js
    • 将所有 API 模块从 index.js 中分离出来,并统一导出。
  • src/api/material.js
    • 添加了 materialAPI 模块,用于处理资料库相关的 API 请求。
  • src/api/notification.js
    • 添加了 notificationAPI 模块,用于处理通知相关的 API 请求。
  • src/api/oss.js
    • 添加了 ossAPI 模块,用于处理 OSS 相关的 API 请求。
  • src/api/points.js
    • 添加了 pointsAPI 模块,用于处理积分相关的 API 请求。
  • src/api/questions.js
    • 添加了 questionsAPI 模块,用于处理刷题相关的 API 请求。
  • src/api/rbac.js
    • 添加了 rbacAPI 模块,用于处理 RBAC 权限管理相关的 API 请求。
  • src/api/review.js
    • 添加了 reviewAPI 模块,用于处理评价相关的 API 请求。
  • src/api/studyTask.js
    • 添加了 studyTaskAPI 模块,用于处理学习任务相关的 API 请求。
  • src/api/system.js
    • 添加了 systemAPI 和 statAPI 模块,用于处理系统和统计相关的 API 请求。
  • src/app.js
    • 提前创建 pinia 实例,并移除冗余参数。
  • src/pages/admin/config/index.vue
    • 为 refreshData 添加了异常捕获,并兼容对象类型的配置值复制。
  • src/pages/admin/heroes/index.vue
    • 为 refreshData 添加了异常捕获。
  • src/pages/admin/rbac/index.vue
    • 增加了角色数据解析的容错处理。
  • src/pages/admin/teacher-reviews/index.vue
    • 移除了不准确的状态计数,并增加了日期校验。
  • src/pages/contributions/detail/index.vue
    • 移除了未实现的删除投稿函数。
  • src/pages/discover/index.vue
    • 仅在登录状态下启动在线人数轮询。
  • src/pages/final-review/detail/index.vue
    • 子题全部作答后自动提交父题,并跳过滚动。
  • src/pages/final-review/index.vue
    • 添加了项目数据校验。
  • src/pages/gpa-calculator/index.vue
    • 百分制转五分制改为线性换算公式。
  • src/pages/hero/index.vue
    • 移除了冗余注释。
  • src/pages/home/components/StudyTaskCard.vue
    • 首次加载并行请求待完成和已完成任务,并将 studyTasks 重命名为 pendingTasks。
  • src/pages/home/components/TodayCourse.vue
    • 同时段多门课程折叠展示,添加绑定班级入口,并支持 debugDate 属性。
  • src/pages/login/index.vue
    • 修复了空白字符格式。
  • src/pages/map/index.vue
    • 异步操作增加组件卸载检查。
  • src/pages/materials/detail/index.vue
    • 详情加载添加 try-catch,分享标题增加兜底值。
  • src/pages/materials/index.vue
    • 添加了热度/时间排序切换,API 调用统一添加异常捕获。
  • src/pages/notifications/categories/index.vue
    • 创建通知分类时,sort 字段的默认值计算方式更严谨。
  • src/pages/notifications/create/index.vue
    • 内容上限提升至 10000 字。
  • src/pages/notifications/detail/index.vue
    • 分享标题增加可选链兜底。
  • src/pages/notifications/index.vue
    • 投稿入口角色判断修正。
  • src/pages/profile/index.vue
    • 积分显示添加加载和失败状态,改用 useDidShow 刷新。
  • src/pages/schedule/components/ScheduleTable.vue
    • 日期显示隐藏年份,触摸事件增加空值防护,使用 maxWeeks。
  • src/pages/schedule/index.vue
    • 功能说明弹窗改为网格布局,补充学期切换等说明,修复 courseData 非空判断,eventCenter 事件正确解绑。
  • src/pages/schedule/schedule-bind/index.vue
    • 绑定成功后仅更新本地用户信息,添加定时器清理。
  • src/pages/teacher-reviews/index.vue
    • 新增校区必填校验,移除无用定时器。
  • src/pages/webview/index.vue
    • decodeURIComponent 增加异常捕获。
  • src/stores/auth.js
    • expireToken 增加重复调用防护和异常捕获。
  • src/stores/countdown.js
    • 改用 countdownAPI 模块,修复排序副作用。
  • src/stores/notifications.js
    • 修复统计数据响应层级取值错误。
  • src/stores/schedule.js
    • getter 改用普通函数支持 this 调用,提取颜色分配逻辑,添加 acknowledgeCurrentSemester,优化学期变更检测。
  • src/stores/study-tasks.js
    • 改用 studyTaskAPI 模块,studyTasks 重命名为 pendingTasks,新建/恢复任务插入到列表头部。
  • src/utils/image.js
    • 移除未使用的 generateLocalFileName 函数。
  • src/utils/index.js
    • 移除未使用的工具函数(formatPhone、debounce、throttle 等),formatDate 增加无效日期校验和未来日期处理。
  • src/utils/request.js
    • 修复了 GET 请求空参数处理,响应非对象类型兼容,添加 URL 校验,循环引用保护。
  • src/utils/semesterCache.js
    • 添加 lastKnownCurrent 方法用于学期变更检测。
  • src/utils/time.js
    • formatDateTime 增加无效日期防护,substr 替换为 substring。
Activity
  • 大量的代码审查和修复工作
  • 新增静默模式、URL校验、循环引用保护等功能
  • 对多个模块进行了重构
  • 移除了 api.md 文档
  • API 调用统一添加了异常捕获
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request primarily focuses on refactoring API calls into dedicated modules, enhancing state management, and improving UI/UX across various pages, while also addressing several critical issues identified in the review. Key changes include restructuring API calls into separate files for better modularity, updating Pinia stores for countdowns and study tasks to use the new API structure and improve data handling (e.g., fixing side-effects in getters and implementing state rollback on API failures), and refining course schedule display with grouped courses and better semester change detection. Critical fixes address potential security vulnerabilities related to path traversal in API URL construction and open redirects in the webview component, by recommending strict input validation or encoding. Other significant improvements include proper cleanup of event listeners to prevent memory leaks, robust handling of Math.max with empty arrays, and adding error handling and loading states to various data fetching operations across admin and user-facing pages.

Comment thread src/utils/request.js
Comment on lines +69 to 89
const sortObjectKeys = (obj, seen = new WeakSet()) => {
if (obj === null || typeof obj !== 'object') {
return obj
}

if (seen.has(obj)) {
return '[Circular]'
}
seen.add(obj)

if (Array.isArray(obj)) {
return obj.map(item => sortObjectKeys(item))
return obj.map(item => sortObjectKeys(item, seen))
}

return Object.keys(obj)
.sort()
.reduce((sorted, key) => {
sorted[key] = sortObjectKeys(obj[key])
sorted[key] = sortObjectKeys(obj[key], seen)
return sorted
}, {})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

sortObjectKeys 函数中,通过使用 WeakSet 来跟踪已访问的对象,你解决了循环引用可能导致的无限递归问题。这是一个至关重要的修复。之前的实现如果遇到包含循环引用的请求体(例如,在复杂的表单数据中),会导致堆栈溢出错误,从而使整个请求失败甚至可能影响小程序的稳定性。这个改动极大地增强了请求幂等性键生成的健壮性。

Comment thread src/stores/countdown.js
getters: {
// 按目标日期排序的倒数日列表
sortedCountdowns: (state) => {
return state.countdowns.sort((a, b) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

sortedCountdowns getter 中,你将 state.countdowns.sort() 修改为 [...state.countdowns].sort(),这是一个非常重要的修复。直接在 getter 中对 state 数组调用 sort() 会直接修改原始 state,这违反了 Pinia 的核心原则(getter 不应有副作用),并可能导致难以追踪的响应性问题。通过先创建数组的浅拷贝再进行排序,你确保了 state 的不可变性,这是一个很好的实践。

Comment on lines +654 to 665
const reloadScheduleHandler = () => {
loadCourseData()
}

// 页面加载时初始化
onMounted(async () => {
// 监听 reloadSchedule 事件,收到后刷新课表
Taro.eventCenter.on('reloadSchedule', () => {
loadCourseData()
})
Taro.eventCenter.on('reloadSchedule', reloadScheduleHandler)
})

Taro.useUnload(() => {
Taro.eventCenter.off('reloadSchedule', reloadScheduleHandler)
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

你在这里将事件监听器提取为 reloadScheduleHandler 函数,并在 Taro.useUnload 中使用 Taro.eventCenter.off 来移除它,这是一个非常重要的修复。之前的代码在 onMounted 中注册了事件监听器但没有在组件卸载时移除,这会导致内存泄漏。每次重新进入页面都会注册一个新的监听器,导致事件触发时处理函数被多次调用。现在的实现确保了事件监听器的正确清理,避免了潜在的性能问题和意外行为。

Comment thread src/stores/schedule.js
Comment on lines +315 to +338
// 保存旧状态,用于失败回滚
const prevSemester = this.semester
const prevSemesterInfo = this.currentSemesterInfo
const prevMaxWeeks = this.maxWeeks
const prevStartDate = this.semesterStartDate
const prevCurrentWeek = this.currentWeek

// 更新学期信息并计算当前周数
this.updateSemesterInfo(semesterId, true)

// 保存用户手动选择的学期到独立存储
semesterCache.saveUserSelectedSemester(semesterId)
try {
courseTableCache.clearCache(semesterId)
await this.fetchCourseTable(semesterId, true)
// 成功后才持久化用户选择,避免失败时 storage 残留错误学期
semesterCache.saveUserSelectedSemester(semesterId)
} catch (error) {
// 请求失败,回滚 Pinia 状态
this.semester = prevSemester
this.currentSemesterInfo = prevSemesterInfo
this.maxWeeks = prevMaxWeeks
this.semesterStartDate = prevStartDate
this.currentWeek = prevCurrentWeek
throw error
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

switchSemester action 中,你增加了在 API 请求失败时回滚状态的逻辑,这是一个出色的健壮性改进。在尝试切换学期并获取新数据之前,先保存旧的状态(学期、周数、开始日期等),如果 fetchCourseTable 失败,则在 catch 块中将这些状态恢复。这种模式确保了即使在网络不稳定的情况下,应用的状态也能保持一致和可预测,避免了用户界面显示新学期但数据仍是旧的这种不一致情况。

Comment thread src/api/material.js
Comment on lines +20 to +22
getMaterialDetail(md5) {
return get(`/api/v0/materials/${md5}`)
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-medium medium

The application constructs API request URLs by directly concatenating user-supplied identifiers into the URL path. In this file, the getMaterialDetail function concatenates the md5 parameter directly into the URL: return get(`/api/v0/materials/${md5}`). If an attacker provides a malicious string containing path traversal sequences (e.g., ../admin/stats), they can manipulate the request to hit unintended API endpoints. Since these requests are automatically authenticated with the user's token in the request utility, this could lead to unauthorized access to sensitive data or administrative functions if the backend does not strictly validate the path. This pattern is also observed in other API modules such as src/api/config.js, src/api/courseTable.js, and src/api/rbac.js.

Remediation: Implement strict validation for all identifiers used in URL paths. Ensure they match the expected format (e.g., alphanumeric, specific length) and do not contain characters like / or ... Alternatively, use encodeURIComponent for each path component.

Comment on lines 15 to +20
if (params.url) {
webviewUrl.value = decodeURIComponent(params.url)
try {
webviewUrl.value = decodeURIComponent(params.url)
} catch (e) {
webviewUrl.value = params.url
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-medium medium

The webview page takes a url parameter from the router and loads it into a <web-view> component. The implementation includes a fallback where if decodeURIComponent fails, the raw params.url is used. This allows an attacker to craft a link that redirects users to arbitrary external websites. While WeChat mini-programs have a domain allow-list, this can still be exploited for open redirects if any allowed domain has its own redirect vulnerability, or if the allow-list is too broad.

Remediation: Implement a strict allow-list of permitted domains or URLs. Before setting webviewUrl.value, verify that the provided URL belongs to an authorized domain.

categoryForm.value = {
name: '',
sort: Math.max(...categories.value.map(c => c.sort), 0) + 1,
sort: (categories.value.length > 0 ? Math.max(...categories.value.map(c => c.sort), 0) : 0) + 1,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

你对 sort 值的计算方式进行了修正,这是一个很好的边缘情况处理。原先的 Math.max(...categories.value.map(c => c.sort), 0)categories.value 为空数组时,... 操作符不会产生任何参数,Math.max() 会返回 -Infinity,导致计算出错误的 sort 值。通过增加 categories.value.length > 0 的判断,你确保了在数组为空时有一个安全的回退值 0,从而避免了这个问题,使代码更加健壮。

@gemini-code-assist gemini-code-assist 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.

Code Review

这是一个非常出色的 Pull Request,包含了大量的重构、修复和功能增强工作,显著提升了代码库的质量、可维护性和用户体验。

主要亮点包括:

  • API 层重构:将庞大的 api/index.js 拆分为多个模块化的文件,极大地提高了代码的组织性和可读性。
  • 健壮性提升:在多个组件和工具函数中增加了错误处理(try...catch)、空值校验和边界条件检查,例如在 map 页面中处理组件卸载后的异步操作,以及在 request 工具中处理循环引用和非标准响应,有效避免了潜在的运行时错误。
  • 性能优化:在 StudyTaskCard 中使用 Promise.all 并行加载数据,提升了首页加载速度。
  • 用户体验改善
    • TodayCourse 组件支持了同一时间段多门课程的折叠展示,非常实用。
    • 在多个页面(如 materials)的分享功能中增加了标题兜底值。
    • profile 页面为积分显示增加了加载和失败状态。
  • 代码质量
    • 清理了大量未使用的工具函数,减少了代码冗余。
    • countdown store 中,通过创建数组副本修复了 sort 方法直接修改 state 的问题,遵循了状态管理的最佳实践。
    • 在多个组件中,正确地在组件卸载时清理定时器,防止了内存泄漏。

整体而言,这次提交的工作量巨大且质量很高。我只发现了一个小问题,具体见代码评论。合并后,应用的稳定性和可维护性将得到巨大提升。做得非常好!

Note: Security Review did not run due to the size of the PR.

const showAddModal = ref(false);
const submitting = ref(false);
const campusIndex = ref(0);
const searchTimer = ref(null);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

你好,这里移除了 searchTimerref 定义,但在 onSearchInput 函数中仍然使用了 searchTimer.value,这会导致运行时错误。同时,相关的 onUnmounted 钩子也被移除了(L619-623),这可能会导致内存泄漏。

建议恢复定时器相关的逻辑,但可以进行优化。可以将 searchTimer 定义为普通的 let 变量,并在 onUnmounted 中进行清理。

例如:

let searchTimer = null;

const onSearchInput = (e) => {
  searchKeyword.value = e.detail.value;
  if (searchTimer) {
    clearTimeout(searchTimer);
  }
  searchTimer = setTimeout(async () => {
    // ... 搜索逻辑
  }, 300);
};

onUnmounted(() => {
  if (searchTimer) {
    clearTimeout(searchTimer);
  }
});

这样既能保证功能正常,又能在组件卸载时正确清理资源。

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.

2 participants