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
This commit is contained in:
@@ -8,12 +8,9 @@ import { ReportList } from "@/modules/diagnostic/components/report-list"
|
|||||||
import {
|
import {
|
||||||
DiagnosticServiceProvider,
|
DiagnosticServiceProvider,
|
||||||
} from "@/modules/diagnostic/services/diagnostic-service-context"
|
} 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 {
|
import {
|
||||||
DiagnosticMonitorProvider,
|
DiagnosticMonitorProvider,
|
||||||
} from "@/modules/diagnostic/services/diagnostic-monitor-context"
|
} from "@/modules/diagnostic/services/diagnostic-monitor-context"
|
||||||
import { noopDiagnosticMonitor } from "@/modules/diagnostic/services/diagnostic-monitor"
|
|
||||||
import type { DiagnosticReportType, DiagnosticReportStatus } from "@/modules/diagnostic/types"
|
import type { DiagnosticReportType, DiagnosticReportStatus } from "@/modules/diagnostic/types"
|
||||||
|
|
||||||
export const dynamic = "force-dynamic"
|
export const dynamic = "force-dynamic"
|
||||||
@@ -64,11 +61,8 @@ export default async function TeacherDiagnosticPage({
|
|||||||
// v2-P2-2: 移除客户端 filter,DataScope 过滤已在 data-access 层完成
|
// v2-P2-2: 移除客户端 filter,DataScope 过滤已在 data-access 层完成
|
||||||
// class_members scope 的学生已通过 filters.studentId 在 data-access 层过滤
|
// class_members scope 的学生已通过 filters.studentId 在 data-access 层过滤
|
||||||
|
|
||||||
// v2-P2-7: 包装默认服务以添加监控埋点(默认 no-op,生产环境可注入真实实现)
|
// v2-P2-7: service 组装移至 DiagnosticServiceProvider(客户端),
|
||||||
const monitoredService = createMonitoredDiagnosticService(
|
// 避免 server component 创建含函数的对象传给 client component。
|
||||||
defaultDiagnosticService,
|
|
||||||
noopDiagnosticMonitor,
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex-1 flex-col space-y-8 p-8 md:flex">
|
<div className="h-full flex-1 flex-col space-y-8 p-8 md:flex">
|
||||||
@@ -78,8 +72,8 @@ export default async function TeacherDiagnosticPage({
|
|||||||
{t("title.teacherReportListDesc")}
|
{t("title.teacherReportListDesc")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<DiagnosticMonitorProvider monitor={noopDiagnosticMonitor}>
|
<DiagnosticMonitorProvider>
|
||||||
<DiagnosticServiceProvider service={monitoredService}>
|
<DiagnosticServiceProvider>
|
||||||
<ReportList reports={reports.reports} />
|
<ReportList reports={reports.reports} />
|
||||||
</DiagnosticServiceProvider>
|
</DiagnosticServiceProvider>
|
||||||
</DiagnosticMonitorProvider>
|
</DiagnosticMonitorProvider>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import type { ActionState } from "@/shared/types/action-state"
|
import type { ActionState } from "@/shared/types/action-state"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -10,13 +10,22 @@
|
|||||||
* 默认值为 noopDiagnosticMonitor(不发送任何事件),
|
* 默认值为 noopDiagnosticMonitor(不发送任何事件),
|
||||||
* 确保未注入 Provider 时业务流程不受影响。
|
* 确保未注入 Provider 时业务流程不受影响。
|
||||||
*
|
*
|
||||||
|
* 注意:monitor prop 为可选,Server Component 不应传递含函数的对象。
|
||||||
|
* 若需注入真实监控实现,请在 Client Component 内部使用。
|
||||||
|
*
|
||||||
* 用法:
|
* 用法:
|
||||||
* ```tsx
|
* ```tsx
|
||||||
* <DiagnosticMonitorProvider monitor={postHogMonitor}>
|
* // Server Component(不传 monitor)
|
||||||
* <DiagnosticServiceProvider service={defaultDiagnosticService}>
|
* <DiagnosticMonitorProvider>
|
||||||
|
* <DiagnosticServiceProvider>
|
||||||
* <ReportList />
|
* <ReportList />
|
||||||
* </DiagnosticServiceProvider>
|
* </DiagnosticServiceProvider>
|
||||||
* </DiagnosticMonitorProvider>
|
* </DiagnosticMonitorProvider>
|
||||||
|
*
|
||||||
|
* // Client Component(可注入真实实现)
|
||||||
|
* <DiagnosticMonitorProvider monitor={postHogMonitor}>
|
||||||
|
* ...
|
||||||
|
* </DiagnosticMonitorProvider>
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -32,8 +41,12 @@ const DiagnosticMonitorContext = createContext<DiagnosticMonitor>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
interface DiagnosticMonitorProviderProps {
|
interface DiagnosticMonitorProviderProps {
|
||||||
/** 监控实现(默认使用 noop,生产环境注入真实实现) */
|
/**
|
||||||
monitor: DiagnosticMonitor
|
* 监控实现(可选)。
|
||||||
|
* 未传时使用 noopDiagnosticMonitor。
|
||||||
|
* Server Component 不要传此 prop(含函数无法跨边界传递)。
|
||||||
|
*/
|
||||||
|
monitor?: DiagnosticMonitor
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,8 +54,9 @@ export function DiagnosticMonitorProvider({
|
|||||||
monitor,
|
monitor,
|
||||||
children,
|
children,
|
||||||
}: DiagnosticMonitorProviderProps): ReactNode {
|
}: DiagnosticMonitorProviderProps): ReactNode {
|
||||||
|
const value = monitor ?? noopDiagnosticMonitor
|
||||||
return (
|
return (
|
||||||
<DiagnosticMonitorContext.Provider value={monitor}>
|
<DiagnosticMonitorContext.Provider value={value}>
|
||||||
{children}
|
{children}
|
||||||
</DiagnosticMonitorContext.Provider>
|
</DiagnosticMonitorContext.Provider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { createContext, useContext, type ReactNode } from "react"
|
import { createContext, useContext, useMemo, type ReactNode } from "react"
|
||||||
|
|
||||||
import type { DiagnosticService } from "./diagnostic-service"
|
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。
|
* v2-P1-4: 诊断模块服务 Context。
|
||||||
@@ -10,13 +14,14 @@ import type { DiagnosticService } from "./diagnostic-service"
|
|||||||
* 组件通过 useDiagnosticService() 获取服务实现,
|
* 组件通过 useDiagnosticService() 获取服务实现,
|
||||||
* 而非直接 import actions,实现依赖反转。
|
* 而非直接 import actions,实现依赖反转。
|
||||||
*
|
*
|
||||||
* 默认由 DefaultDiagnosticServiceProvider 注入真实实现(调用 Server Actions);
|
* 默认由 DiagnosticServiceProvider 在客户端组装默认实现(调用 Server Actions);
|
||||||
* 测试时可注入 mock 实现以隔离组件测试。
|
* 测试时可注入 mock 实现以隔离组件测试。
|
||||||
*/
|
*/
|
||||||
const DiagnosticServiceContext = createContext<DiagnosticService | null>(null)
|
const DiagnosticServiceContext = createContext<DiagnosticService | null>(null)
|
||||||
|
|
||||||
interface DiagnosticServiceProviderProps {
|
interface DiagnosticServiceProviderProps {
|
||||||
service: DiagnosticService
|
/** 可选自定义服务实现,未传则使用 defaultDiagnosticService + 监控包装 */
|
||||||
|
service?: DiagnosticService
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,8 +29,18 @@ export function DiagnosticServiceProvider({
|
|||||||
service,
|
service,
|
||||||
children,
|
children,
|
||||||
}: DiagnosticServiceProviderProps): ReactNode {
|
}: DiagnosticServiceProviderProps): ReactNode {
|
||||||
|
const monitor = useDiagnosticMonitor()
|
||||||
|
const value = useMemo<DiagnosticService>(() => {
|
||||||
|
if (service) return service
|
||||||
|
// 客户端组装:默认 service + 监控埋点包装
|
||||||
|
return createMonitoredDiagnosticService(
|
||||||
|
defaultDiagnosticService,
|
||||||
|
monitor ?? noopDiagnosticMonitor,
|
||||||
|
)
|
||||||
|
}, [service, monitor])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DiagnosticServiceContext.Provider value={service}>
|
<DiagnosticServiceContext.Provider value={value}>
|
||||||
{children}
|
{children}
|
||||||
</DiagnosticServiceContext.Provider>
|
</DiagnosticServiceContext.Provider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* v2-P2-7: 带监控埋点的诊断服务工厂。
|
* v2-P2-7: 带监控埋点的诊断服务工厂。
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user