From b63d116b6c9cbf6a34ea9e4959a9d235dc798ff7 Mon Sep 17 00:00:00 2001
From: SpecialX <47072643+wangxiner55@users.noreply.github.com>
Date: Sat, 4 Jul 2026 10:22:48 +0800
Subject: [PATCH] feat(diagnostic): refactor services with monitor and context
providers
- Update default-diagnostic-service.ts
- Update diagnostic-monitor-context.tsx
- Update diagnostic-service-context.tsx
- Update monitored-diagnostic-service.ts
- Update teacher diagnostic page
---
.../(dashboard)/teacher/diagnostic/page.tsx | 14 ++++-------
.../services/default-diagnostic-service.ts | 2 --
.../services/diagnostic-monitor-context.tsx | 24 +++++++++++++++----
.../services/diagnostic-service-context.tsx | 23 ++++++++++++++----
.../services/monitored-diagnostic-service.ts | 2 --
5 files changed, 42 insertions(+), 23 deletions(-)
diff --git a/src/app/(dashboard)/teacher/diagnostic/page.tsx b/src/app/(dashboard)/teacher/diagnostic/page.tsx
index eb52628..8babc1d 100644
--- a/src/app/(dashboard)/teacher/diagnostic/page.tsx
+++ b/src/app/(dashboard)/teacher/diagnostic/page.tsx
@@ -8,12 +8,9 @@ import { ReportList } from "@/modules/diagnostic/components/report-list"
import {
DiagnosticServiceProvider,
} from "@/modules/diagnostic/services/diagnostic-service-context"
-import { defaultDiagnosticService } from "@/modules/diagnostic/services/default-diagnostic-service"
-import { createMonitoredDiagnosticService } from "@/modules/diagnostic/services/monitored-diagnostic-service"
import {
DiagnosticMonitorProvider,
} from "@/modules/diagnostic/services/diagnostic-monitor-context"
-import { noopDiagnosticMonitor } from "@/modules/diagnostic/services/diagnostic-monitor"
import type { DiagnosticReportType, DiagnosticReportStatus } from "@/modules/diagnostic/types"
export const dynamic = "force-dynamic"
@@ -64,11 +61,8 @@ export default async function TeacherDiagnosticPage({
// v2-P2-2: 移除客户端 filter,DataScope 过滤已在 data-access 层完成
// class_members scope 的学生已通过 filters.studentId 在 data-access 层过滤
- // v2-P2-7: 包装默认服务以添加监控埋点(默认 no-op,生产环境可注入真实实现)
- const monitoredService = createMonitoredDiagnosticService(
- defaultDiagnosticService,
- noopDiagnosticMonitor,
- )
+ // v2-P2-7: service 组装移至 DiagnosticServiceProvider(客户端),
+ // 避免 server component 创建含函数的对象传给 client component。
return (
@@ -78,8 +72,8 @@ export default async function TeacherDiagnosticPage({
{t("title.teacherReportListDesc")}
-
-
+
+
diff --git a/src/modules/diagnostic/services/default-diagnostic-service.ts b/src/modules/diagnostic/services/default-diagnostic-service.ts
index 9496160..7ef8f0a 100644
--- a/src/modules/diagnostic/services/default-diagnostic-service.ts
+++ b/src/modules/diagnostic/services/default-diagnostic-service.ts
@@ -1,5 +1,3 @@
-"use client"
-
import type { ActionState } from "@/shared/types/action-state"
import {
diff --git a/src/modules/diagnostic/services/diagnostic-monitor-context.tsx b/src/modules/diagnostic/services/diagnostic-monitor-context.tsx
index 3e91e08..2d3e761 100644
--- a/src/modules/diagnostic/services/diagnostic-monitor-context.tsx
+++ b/src/modules/diagnostic/services/diagnostic-monitor-context.tsx
@@ -10,13 +10,22 @@
* 默认值为 noopDiagnosticMonitor(不发送任何事件),
* 确保未注入 Provider 时业务流程不受影响。
*
+ * 注意:monitor prop 为可选,Server Component 不应传递含函数的对象。
+ * 若需注入真实监控实现,请在 Client Component 内部使用。
+ *
* 用法:
* ```tsx
- *
- *
+ * // Server Component(不传 monitor)
+ *
+ *
*
*
*
+ *
+ * // Client Component(可注入真实实现)
+ *
+ * ...
+ *
* ```
*/
@@ -32,8 +41,12 @@ const DiagnosticMonitorContext = createContext(
)
interface DiagnosticMonitorProviderProps {
- /** 监控实现(默认使用 noop,生产环境注入真实实现) */
- monitor: DiagnosticMonitor
+ /**
+ * 监控实现(可选)。
+ * 未传时使用 noopDiagnosticMonitor。
+ * Server Component 不要传此 prop(含函数无法跨边界传递)。
+ */
+ monitor?: DiagnosticMonitor
children: ReactNode
}
@@ -41,8 +54,9 @@ export function DiagnosticMonitorProvider({
monitor,
children,
}: DiagnosticMonitorProviderProps): ReactNode {
+ const value = monitor ?? noopDiagnosticMonitor
return (
-
+
{children}
)
diff --git a/src/modules/diagnostic/services/diagnostic-service-context.tsx b/src/modules/diagnostic/services/diagnostic-service-context.tsx
index 6af750d..f9720d4 100644
--- a/src/modules/diagnostic/services/diagnostic-service-context.tsx
+++ b/src/modules/diagnostic/services/diagnostic-service-context.tsx
@@ -1,8 +1,12 @@
"use client"
-import { createContext, useContext, type ReactNode } from "react"
+import { createContext, useContext, useMemo, type ReactNode } from "react"
import type { DiagnosticService } from "./diagnostic-service"
+import { defaultDiagnosticService } from "./default-diagnostic-service"
+import { createMonitoredDiagnosticService } from "./monitored-diagnostic-service"
+import { noopDiagnosticMonitor } from "./diagnostic-monitor"
+import { useDiagnosticMonitor } from "./diagnostic-monitor-context"
/**
* v2-P1-4: 诊断模块服务 Context。
@@ -10,13 +14,14 @@ import type { DiagnosticService } from "./diagnostic-service"
* 组件通过 useDiagnosticService() 获取服务实现,
* 而非直接 import actions,实现依赖反转。
*
- * 默认由 DefaultDiagnosticServiceProvider 注入真实实现(调用 Server Actions);
+ * 默认由 DiagnosticServiceProvider 在客户端组装默认实现(调用 Server Actions);
* 测试时可注入 mock 实现以隔离组件测试。
*/
const DiagnosticServiceContext = createContext(null)
interface DiagnosticServiceProviderProps {
- service: DiagnosticService
+ /** 可选自定义服务实现,未传则使用 defaultDiagnosticService + 监控包装 */
+ service?: DiagnosticService
children: ReactNode
}
@@ -24,8 +29,18 @@ export function DiagnosticServiceProvider({
service,
children,
}: DiagnosticServiceProviderProps): ReactNode {
+ const monitor = useDiagnosticMonitor()
+ const value = useMemo(() => {
+ if (service) return service
+ // 客户端组装:默认 service + 监控埋点包装
+ return createMonitoredDiagnosticService(
+ defaultDiagnosticService,
+ monitor ?? noopDiagnosticMonitor,
+ )
+ }, [service, monitor])
+
return (
-
+
{children}
)
diff --git a/src/modules/diagnostic/services/monitored-diagnostic-service.ts b/src/modules/diagnostic/services/monitored-diagnostic-service.ts
index 381b94e..a036457 100644
--- a/src/modules/diagnostic/services/monitored-diagnostic-service.ts
+++ b/src/modules/diagnostic/services/monitored-diagnostic-service.ts
@@ -1,5 +1,3 @@
-"use client"
-
/**
* v2-P2-7: 带监控埋点的诊断服务工厂。
*