Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📜 Recent review details⏰ Context from checks skipped due to timeout. (2)
🧰 Additional context used📓 Path-based instructions (2)web/default/src/**/*.{ts,tsx}📄 CodeRabbit inference engine (web/default/AGENTS.md)
Files:
web/default/src/**/*.test.ts📄 CodeRabbit inference engine (web/default/AGENTS.md)
Files:
🧠 Learnings (1)📓 Common learnings🔇 Additional comments (2)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds notification auto-open helpers and a close-for-today action, hardens Markdown rendering and tests, updates quota/redemption transaction handling, and changes OpenAI empty-completion retry behavior. It also adds process-document placement rules and adjusts one log-filter test. ChangesNotification Close-for-Today & Auto-Open Refactor
Markdown Link Hardening
Quota and Redemption Transaction Fixes
OpenAI Empty-Completion Retry Handling
Process Document Placement Rule
Log ID Filter Assertion Update
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/components/ui/markdown.test.ts`:
- Around line 23-39: The markdown link tests in renderMarkdownForTest cover
valid links and invalid href encoding, but they do not protect against dangerous
protocols. Add a regression test in markdown.test.ts that renders a link with a
malicious scheme such as javascript: or data: and asserts the output is
sanitized or falls back to plain text, so protocol-validation regressions are
caught.
In `@web/default/src/components/ui/markdown.tsx`:
- Around line 729-739: The helper currently named renderMarkdownForTest is used
by the production Markdown component, so rename it to a production-appropriate
name and update its call site inside Markdown to match. Also add an explicit
return type annotation to Markdown so it complies with the required typing
guideline; use the Markdown and renderMarkdownForTest symbols to locate the
change.
- Around line 176-198: Update normalizeUrl to reject unsafe URL schemes up front
so javascript: and similar values are never returned, even after
encoding/cleanup; keep the logic in the normalizeUrl helper so callers like the
markdown rendering path continue to use a safe URL. Also change sanitizeHtml to
fail closed: in the DOMPurify resolution fallback path, return an empty string
instead of the raw html when sanitize() can’t be resolved, so the
dangerouslySetInnerHTML usage in markdown.tsx never renders unsanitized markup.
In `@web/default/src/hooks/use-notifications.ts`:
- Line 36: The useNotifications hook currently relies on inferred return shape,
which should be made explicit because it is a shared contract. Extract a
UseNotificationsResult type that captures the hook’s returned object, then
annotate the useNotifications export with that return type so any shape changes
are caught at compile time. Keep the type definition close to useNotifications
and update the hook implementation to satisfy the new explicit contract.
- Around line 162-202: The auto-open effect in use-notifications should remember
the current contentSignature even when popoverOpen is already true, since the
early return leaves lastAutoOpenedSignatureRef unset and causes an immediate
reopen after manual close. Update the useEffect flow around
shouldAutoOpenNotifications and getAutoNotificationTab so the signature is
recorded whenever the current content has effectively been seen/opened, not only
after scheduling handleOpenPopover. Keep the existing timeout behavior for
automatic opening, but ensure lastAutoOpenedSignatureRef.current is set in the
open state path too.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 28934d5d-dffb-49bd-b047-0188634a342e
📒 Files selected for processing (8)
web/default/src/components/layout/components/app-header.tsxweb/default/src/components/layout/components/public-header.tsxweb/default/src/components/notification-popover.tsxweb/default/src/components/ui/markdown.test.tsweb/default/src/components/ui/markdown.tsxweb/default/src/hooks/notification-utils.test.tsweb/default/src/hooks/notification-utils.tsweb/default/src/hooks/use-notifications.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (3)
web/default/**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
In
web/default/, use Bun for frontend dependency and script commands (bun install,bun run dev,bun run build,bun run i18n:*).
Files:
web/default/src/hooks/notification-utils.test.tsweb/default/src/components/ui/markdown.test.tsweb/default/src/components/layout/components/app-header.tsxweb/default/src/components/layout/components/public-header.tsxweb/default/src/hooks/notification-utils.tsweb/default/src/components/notification-popover.tsxweb/default/src/hooks/use-notifications.tsweb/default/src/components/ui/markdown.tsx
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/hooks/notification-utils.test.tsweb/default/src/components/ui/markdown.test.tsweb/default/src/components/layout/components/app-header.tsxweb/default/src/components/layout/components/public-header.tsxweb/default/src/hooks/notification-utils.tsweb/default/src/components/notification-popover.tsxweb/default/src/hooks/use-notifications.tsweb/default/src/components/ui/markdown.tsx
web/default/src/**/*.test.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
工具函数与纯逻辑应优先编写单元测试;测试文件应命名为
*.test.ts。
Files:
web/default/src/hooks/notification-utils.test.tsweb/default/src/components/ui/markdown.test.ts
🔇 Additional comments (2)
web/default/src/components/ui/markdown.tsx (1)
132-134: LGTM!Also applies to: 594-596
web/default/src/hooks/notification-utils.ts (1)
54-62: 🎯 Functional CorrectnessNo change needed — the fingerprint already covers the rendered announcement fields.
> Likely an incorrect or invalid review comment.
| export function renderMarkdownForTest(markdown: string): string { | ||
| const markdownParser = createMarkdownParser() | ||
| const parsedHtml = markdownParser.parse(markdown, markdownOptions) | ||
| return DOMPurify.sanitize(parsedHtml, sanitizeOptions) | ||
| return sanitizeHtml(parsedHtml) | ||
| } | ||
|
|
||
| export function Markdown(props: MarkdownProps) { | ||
| const html = useMemo(() => renderMarkdown(props.children), [props.children]) | ||
| const html = useMemo( | ||
| () => renderMarkdownForTest(props.children), | ||
| [props.children] | ||
| ) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Rename the production helper and add the component return type.
renderMarkdownForTest() is now used by production Markdown, so the name is misleading; Markdown also lacks the required explicit return type.
Suggested cleanup
-export function renderMarkdownForTest(markdown: string): string {
+export function renderMarkdownHtml(markdown: string): string {
const markdownParser = createMarkdownParser()
const parsedHtml = markdownParser.parse(markdown, markdownOptions)
return sanitizeHtml(parsedHtml)
}
+
+export const renderMarkdownForTest = renderMarkdownHtml
-export function Markdown(props: MarkdownProps) {
+export function Markdown(props: MarkdownProps): React.JSX.Element {
const html = useMemo(
- () => renderMarkdownForTest(props.children),
+ () => renderMarkdownHtml(props.children),
[props.children]
)As per coding guidelines, “变量与函数命名应有意义” and “参数与返回值应显式标注类型.”
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function renderMarkdownForTest(markdown: string): string { | |
| const markdownParser = createMarkdownParser() | |
| const parsedHtml = markdownParser.parse(markdown, markdownOptions) | |
| return DOMPurify.sanitize(parsedHtml, sanitizeOptions) | |
| return sanitizeHtml(parsedHtml) | |
| } | |
| export function Markdown(props: MarkdownProps) { | |
| const html = useMemo(() => renderMarkdown(props.children), [props.children]) | |
| const html = useMemo( | |
| () => renderMarkdownForTest(props.children), | |
| [props.children] | |
| ) | |
| export function renderMarkdownHtml(markdown: string): string { | |
| const markdownParser = createMarkdownParser() | |
| const parsedHtml = markdownParser.parse(markdown, markdownOptions) | |
| return sanitizeHtml(parsedHtml) | |
| } | |
| export const renderMarkdownForTest = renderMarkdownHtml | |
| export function Markdown(props: MarkdownProps): React.JSX.Element { | |
| const html = useMemo( | |
| () => renderMarkdownHtml(props.children), | |
| [props.children] | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/default/src/components/ui/markdown.tsx` around lines 729 - 739, The
helper currently named renderMarkdownForTest is used by the production Markdown
component, so rename it to a production-appropriate name and update its call
site inside Markdown to match. Also add an explicit return type annotation to
Markdown so it complies with the required typing guideline; use the Markdown and
renderMarkdownForTest symbols to locate the change.
Source: Coding guidelines
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/package.json`:
- Line 95: `jsdom` is a test-only package and should not remain in the
production dependencies list. Move the `jsdom` entry in
`web/default/package.json` from `dependencies` to `devDependencies` alongside
`@types/jsdom`, then regenerate the Bun lockfile so the package metadata stays
in sync. Keep the change scoped to the package manifest used by
`markdown.test.ts`.
In `@web/default/src/hooks/notification-utils.ts`:
- Around line 138-190: The notification signature guard currently persists
through window.sessionStorage, which changes the behavior from “once after page
load” to “once per tab session.” Update getLastAutoOpenedNotificationSignature()
and rememberAutoOpenedNotificationSignature() in notification-utils so they rely
on the in-memory memoryLastAutoOpenedSignature only, removing the sessionStorage
read/write path while keeping the existing fallback behavior for repeated hook
remounts within the same page load.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 88ee126d-60ac-4bd8-bc65-12446111a32d
⛔ Files ignored due to path filters (1)
web/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (11)
AGENTS.mdCLAUDE.mdfix_quota.difffix_relay.diffmodel/log_test.goweb/default/package.jsonweb/default/src/components/ui/markdown.test.tsweb/default/src/components/ui/markdown.tsxweb/default/src/hooks/notification-utils.test.tsweb/default/src/hooks/notification-utils.tsweb/default/src/hooks/use-notifications.ts
💤 Files with no reviewable changes (2)
- fix_quota.diff
- fix_relay.diff
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
web/default/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (web/default/AGENTS.md)
web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用useTranslation()取得t,并通过t()渲染用户可见文本;子组件也应自行使用useTranslation()保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用any,优先使用具体类型或unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用import type。
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用props.xxx以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的types中。
在 React 中应合理使用useMemo、useCallback、React.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态import。
React Query 的数据获取应使用useQuery、变更应使用useMutation;每个查询需配置唯一queryKey,并在成功后对相关查询执行invalidateQueries;服务端错误应统一交给handleServerError。
Axios 请求应使用项目统一的api实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用handleServerError,展示层应使用toast.error等统一方式;文案需走 i18n;路由级错误应由errorComponent承接;表单错误应通过form.setError等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用cn()合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与dark:处理。
应使用语义化 HTML、正确关联label与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用aria-hidden="true"。
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用dangerouslySetInnerHTML;跨域与 Cookie 需配合withCredentials并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过.env读取,并使用VITE_前缀;代码中不得硬编码密钥。
Files:
web/default/src/hooks/notification-utils.test.tsweb/default/src/components/ui/markdown.test.tsweb/default/src/hooks/notification-utils.tsweb/default/src/components/ui/markdown.tsxweb/default/src/hooks/use-notifications.ts
web/default/src/**/*.test.ts
📄 CodeRabbit inference engine (web/default/AGENTS.md)
工具函数与纯逻辑应优先编写单元测试;测试文件应命名为
*.test.ts。
Files:
web/default/src/hooks/notification-utils.test.tsweb/default/src/components/ui/markdown.test.ts
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType); do not directly callencoding/jsonexcept for type references likejson.RawMessageandjson.Number.
All database code must remain compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions, avoid backend-specific SQL/features without cross-DB fallback, use the shared quoting/boolean helpers for raw SQL, and ensure migrations work on all three databases.
**/*.go: All JSON marshal/unmarshal operations in Go must use the wrapper functions incommon/json.go(common.Marshal,common.Unmarshal,common.UnmarshalJsonStr,common.DecodeJson,common.GetJsonType); do not directly callencoding/jsonin business code.
All database code in Go must remain compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions, avoid database-specific features without fallback, and ensure migrations work across all three databases.
Files:
model/log_test.go
web/default/**/package.json
📄 CodeRabbit inference engine (web/default/AGENTS.md)
脚本与包管理以
package.json为准;发布前应执行 typecheck、lint、format、生产构建,并检查产物体积与环境变量配置。
Files:
web/default/package.json
web/default/{package.json,bun.lockb}
📄 CodeRabbit inference engine (AGENTS.md)
Use Bun as the preferred package manager and script runner for the frontend in
web/default/(bun install,bun run dev,bun run build, andbun run i18n:*).
Files:
web/default/package.json
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: MAX-API-Next/MAX-API
Timestamp: 2026-06-28T15:10:54.494Z
Learning: Protected project identity and attribution references related to `max-api` and `max-api-next` must not be modified, deleted, renamed, replaced, or removed anywhere in the repository.
Learnt from: CR
Repo: MAX-API-Next/MAX-API
Timestamp: 2026-06-28T15:10:54.494Z
Learning: All non-project process documents must be created and kept under `.tmp/`; do not place investigation notes, scratch drafts, temporary release-note/PR-copy drafts, one-off deployment notes, or similar internal process documents elsewhere in the repo.
Learnt from: CR
Repo: MAX-API-Next/MAX-API
Timestamp: 2026-06-28T15:11:06.840Z
Learning: Use `bun` as the preferred package manager and script runner for the frontend in `web/default/` (`bun install`, `bun run dev`, `bun run build`, `bun run i18n:*`).
Learnt from: CR
Repo: MAX-API-Next/MAX-API
Timestamp: 2026-06-28T15:11:06.840Z
Learning: Do not modify, delete, replace, or remove any protected project identity references related to `max-api` or `MAX API Next`, including in README files, license headers, package metadata, HTML titles, comments, docs, CI/CD configs, and import or module paths.
Learnt from: CR
Repo: MAX-API-Next/MAX-API
Timestamp: 2026-06-28T15:11:06.840Z
Learning: All non-project process documents (investigation notes, review outputs, scratch plans, temporary drafts, one-off deployment notes, private operation notes, and similar internal work artifacts) must be created and kept under `.tmp/`; project-owned agent workflows and reusable skills under `.agents/skills/` must remain tracked unless retired.
🪛 ast-grep (0.44.0)
web/default/src/components/ui/markdown.test.ts
[warning] 72-72: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(>${label}<)
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
🪛 LanguageTool
CLAUDE.md
[uncategorized] ~144-~144: The official name of this software platform is spelled with a capital “H”.
Context: ... files in the repository root, docs/, .github/, or source directories unless the con...
(GITHUB)
AGENTS.md
[uncategorized] ~144-~144: The official name of this software platform is spelled with a capital “H”.
Context: ... files in the repository root, docs/, .github/, or source directories unless the con...
(GITHUB)
🪛 OpenGrep (1.23.0)
web/default/src/components/ui/markdown.tsx
[ERROR] 185-185: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
🔇 Additional comments (6)
model/log_test.go (1)
50-52: LGTM!AGENTS.md (1)
138-146: LGTM!CLAUDE.md (1)
138-146: LGTM!web/default/src/components/ui/markdown.tsx (2)
758-768: Duplicate: rename the production helper and annotateMarkdown’s return type.
renderMarkdownForTest()is still used by productionMarkdown, andMarkdownstill lacks the explicit return type required by the TS guidelines.
132-138: LGTM!Also applies to: 179-227, 645-656
web/default/src/components/ui/markdown.test.ts (1)
21-28: LGTM!Also applies to: 30-45, 47-52, 54-75, 77-91
| "eslint-plugin-react-hooks": "^7.1.1", | ||
| "eslint-plugin-react-refresh": "^0.5.2", | ||
| "globals": "^17.6.0", | ||
| "jsdom": "^29.1.1", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Move test-only jsdom to devDependencies.
jsdom is only used by markdown.test.ts, so keeping it in production dependencies increases install surface unnecessarily. Move it next to @types/jsdom and regenerate the Bun lockfile afterward.
Proposed package cleanup
+ "jsdom": "^29.1.1",
"`@types/jsdom`": "^28.0.3",
...
- "jsdom": "^29.1.1",As per coding guidelines, “Use Bun as the preferred package manager and script runner for the frontend in web/default/.”
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "jsdom": "^29.1.1", |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/default/package.json` at line 95, `jsdom` is a test-only package and
should not remain in the production dependencies list. Move the `jsdom` entry in
`web/default/package.json` from `dependencies` to `devDependencies` alongside
`@types/jsdom`, then regenerate the Bun lockfile so the package metadata stays
in sync. Keep the change scoped to the package manifest used by
`markdown.test.ts`.
Sources: Coding guidelines, Learnings
Important
📝 变更描述 / Description
修复公告中心在渲染包含链接的 Markdown 内容时崩溃的问题。原因是自定义
markedlink renderer 复用了脱离运行时 parser 上下文的默认 renderer,导致点击或打开公告时读取parseInline报错。本次改为在当前 renderer 上下文中渲染链接文本,并保留外链安全属性与 DOMPurify 清理流程。同时恢复公告中心的自动弹出行为:页面加载到公告/通知内容后会自动打开一次,用户点击“今日关闭”后当天不再自动弹出。公告已读与自动弹出去重也改为基于内容版本签名,避免同一后端 id 的公告编辑后仍被视为已读;公告签名会排序,避免服务端返回顺序变化导致重复弹出。
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
已通过以下本地验证: