refactor(data-access): 组 A 模块迁移至 cacheFn(users/school/rbac/textbooks/questions/course-plans/standards/files/dashboard/parent/proctoring)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import "server-only"
|
||||
|
||||
import { cache } from "react"
|
||||
import { cacheFn } from "@/shared/lib/cache"
|
||||
import { and, asc, eq, inArray } from "drizzle-orm"
|
||||
|
||||
import { db } from "@/shared/db"
|
||||
@@ -39,7 +39,7 @@ const toWeekday = (d: Date): Weekday => {
|
||||
return isWeekday(normalized) ? normalized : 1
|
||||
}
|
||||
|
||||
export const getChildren = cache(async (parentId: string): Promise<ParentChildRelation[]> => {
|
||||
export const getChildrenRaw = async (parentId: string): Promise<ParentChildRelation[]> => {
|
||||
const id = parentId.trim()
|
||||
if (!id) return []
|
||||
|
||||
@@ -62,14 +62,19 @@ export const getChildren = cache(async (parentId: string): Promise<ParentChildRe
|
||||
relation: r.relation,
|
||||
createdAt: r.createdAt.toISOString(),
|
||||
}))
|
||||
}
|
||||
|
||||
export const getChildren = cacheFn(getChildrenRaw, {
|
||||
tags: ["parent"],
|
||||
ttl: 300,
|
||||
keyParts: ["parent", "getChildren"],
|
||||
})
|
||||
|
||||
/**
|
||||
* 校验家长与子女的关系是否存在,并返回关系类型。
|
||||
* 同时按 parentId 与 studentId 过滤,防止跨家庭信息泄露。
|
||||
*/
|
||||
export const verifyParentChildRelation = cache(
|
||||
async (studentId: string, parentId: string): Promise<string | null> => {
|
||||
export const verifyParentChildRelationRaw = async (studentId: string, parentId: string): Promise<string | null> => {
|
||||
const [row] = await db
|
||||
.select({ relation: parentStudentRelations.relation })
|
||||
.from(parentStudentRelations)
|
||||
@@ -81,11 +86,15 @@ export const verifyParentChildRelation = cache(
|
||||
)
|
||||
.limit(1)
|
||||
return row?.relation ?? null
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const getChildBasicInfo = cache(
|
||||
async (
|
||||
export const verifyParentChildRelation = cacheFn(verifyParentChildRelationRaw, {
|
||||
tags: ["parent"],
|
||||
ttl: 300,
|
||||
keyParts: ["parent", "verifyParentChildRelation"],
|
||||
})
|
||||
|
||||
export const getChildBasicInfoRaw = async (
|
||||
studentId: string,
|
||||
relation: string | null = null,
|
||||
): Promise<ChildBasicInfo | null> => {
|
||||
@@ -109,8 +118,13 @@ export const getChildBasicInfo = cache(
|
||||
classId: activeClass?.classId ?? null,
|
||||
relation,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const getChildBasicInfo = cacheFn(getChildBasicInfoRaw, {
|
||||
tags: ["parent"],
|
||||
ttl: 300,
|
||||
keyParts: ["parent", "getChildBasicInfo"],
|
||||
})
|
||||
|
||||
const buildHomeworkSummary = (
|
||||
assignments: Awaited<ReturnType<typeof getStudentHomeworkAssignments>>,
|
||||
@@ -197,8 +211,7 @@ const buildWeeklySchedule = (
|
||||
)
|
||||
}
|
||||
|
||||
export const getChildDashboardData = cache(
|
||||
async (studentId: string, relation: string | null = null): Promise<ChildDashboardData | null> => {
|
||||
export const getChildDashboardDataRaw = async (studentId: string, relation: string | null = null): Promise<ChildDashboardData | null> => {
|
||||
const basicInfo = await getChildBasicInfo(studentId, relation)
|
||||
if (!basicInfo) return null
|
||||
|
||||
@@ -221,11 +234,15 @@ export const getChildDashboardData = cache(
|
||||
gradeSummary,
|
||||
examResults,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const getParentDashboardData = cache(
|
||||
async (parentId: string): Promise<ParentDashboardData> => {
|
||||
export const getChildDashboardData = cacheFn(getChildDashboardDataRaw, {
|
||||
tags: ["parent"],
|
||||
ttl: 300,
|
||||
keyParts: ["parent", "getChildDashboardData"],
|
||||
})
|
||||
|
||||
export const getParentDashboardDataRaw = async (parentId: string): Promise<ParentDashboardData> => {
|
||||
const id = parentId.trim()
|
||||
if (!id) return { parentName: null, children: [] }
|
||||
|
||||
@@ -248,15 +265,19 @@ export const getParentDashboardData = cache(
|
||||
parentName,
|
||||
children: children.filter((c): c is ChildDashboardData => c !== null),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const getParentDashboardData = cacheFn(getParentDashboardDataRaw, {
|
||||
tags: ["parent"],
|
||||
ttl: 300,
|
||||
keyParts: ["parent", "getParentDashboardData"],
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取家长所有子女的轻量列表(id + name),用于详情页头部多子女切换器。
|
||||
* 一次批量查询,避免 N+1。
|
||||
*/
|
||||
export const getChildNameList = cache(
|
||||
async (parentId: string): Promise<Array<{ id: string; name: string | null }>> => {
|
||||
export const getChildNameListRaw = async (parentId: string): Promise<Array<{ id: string; name: string | null }>> => {
|
||||
const relations = await getChildren(parentId)
|
||||
if (relations.length === 0) return []
|
||||
|
||||
@@ -265,32 +286,40 @@ export const getChildNameList = cache(
|
||||
id: r.studentId,
|
||||
name: nameMap.get(r.studentId)?.name ?? null,
|
||||
}))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const getChildNameList = cacheFn(getChildNameListRaw, {
|
||||
tags: ["parent"],
|
||||
ttl: 300,
|
||||
keyParts: ["parent", "getChildNameList"],
|
||||
})
|
||||
|
||||
/**
|
||||
* v4-P1-5: 批量查询多个学生的家长 userId 列表。
|
||||
* 用于通知场景:报告/成绩发布时同步通知所有相关家长。
|
||||
* 返回去重后的 parentId 数组。
|
||||
*/
|
||||
export const getParentIdsByStudentIds = cache(
|
||||
async (studentIds: string[]): Promise<string[]> => {
|
||||
export const getParentIdsByStudentIdsRaw = async (studentIds: string[]): Promise<string[]> => {
|
||||
if (studentIds.length === 0) return []
|
||||
const rows = await db
|
||||
.select({ parentId: parentStudentRelations.parentId })
|
||||
.from(parentStudentRelations)
|
||||
.where(inArray(parentStudentRelations.studentId, studentIds))
|
||||
return Array.from(new Set(rows.map((r) => r.parentId)))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const getParentIdsByStudentIds = cacheFn(getParentIdsByStudentIdsRaw, {
|
||||
tags: ["parent"],
|
||||
ttl: 300,
|
||||
keyParts: ["parent", "getParentIdsByStudentIds"],
|
||||
})
|
||||
|
||||
/**
|
||||
* L-2: 批量查询学生→家长映射(保留关联关系)。
|
||||
* 用于考勤通知等需要按家长-学生分组发送的场景,避免 N+1 查询。
|
||||
* 返回数组形如 [{ parentId, studentId }],同一家长多个学生会出现多条。
|
||||
*/
|
||||
export const getParentStudentMapByStudentIds = cache(
|
||||
async (studentIds: string[]): Promise<Array<{ parentId: string; studentId: string }>> => {
|
||||
export const getParentStudentMapByStudentIdsRaw = async (studentIds: string[]): Promise<Array<{ parentId: string; studentId: string }>> => {
|
||||
if (studentIds.length === 0) return []
|
||||
const rows = await db
|
||||
.select({
|
||||
@@ -300,5 +329,10 @@ export const getParentStudentMapByStudentIds = cache(
|
||||
.from(parentStudentRelations)
|
||||
.where(inArray(parentStudentRelations.studentId, studentIds))
|
||||
return rows.map((r) => ({ parentId: r.parentId, studentId: r.studentId }))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const getParentStudentMapByStudentIds = cacheFn(getParentStudentMapByStudentIdsRaw, {
|
||||
tags: ["parent"],
|
||||
ttl: 300,
|
||||
keyParts: ["parent", "getParentStudentMapByStudentIds"],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user