refactor(grades,diagnostic): 成绩和学情诊断模块审计修复
P0-1: 10 个页面补充 requirePermission 权限校验 P0-2: diagnostic/data-access-reports.ts 移除直查 users 表,改用 getUserNamesByIds P0-3: 新增 grade/grades/diagnostic 三组 i18n 翻译文件(zh-CN/en) P0-4: 新增 /management/grade 重定向页面 P1-2: 抽取 toNumber/normalize/buildScopeClassFilter 到 lib/grade-utils.ts P1-3: 为 12 个 Action 新增 Zod safeParse 校验(schema.ts +12 查询 schema) P1-4: 修复 as 断言违规,改用类型守卫函数 P2-2: 移除 diagnostic 组件中 Tailwind 任意值 同步更新架构图文档 004 和 005
This commit is contained in:
51
src/modules/grades/lib/grade-utils.ts
Normal file
51
src/modules/grades/lib/grade-utils.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import "server-only"
|
||||
|
||||
import { eq, inArray, sql, type SQL } from "drizzle-orm"
|
||||
|
||||
import { gradeRecords } from "@/shared/db/schema"
|
||||
import type { DataScope } from "@/shared/types/permissions"
|
||||
|
||||
/**
|
||||
* Safely convert an unknown value to a finite number.
|
||||
* Returns 0 when the value is not a finite number.
|
||||
*
|
||||
* Used to normalize numeric columns returned by Drizzle (which may be
|
||||
* string | number depending on the driver) into plain numbers.
|
||||
*/
|
||||
export const toNumber = (v: unknown): number => {
|
||||
const n = typeof v === "number" ? v : Number(v)
|
||||
return Number.isFinite(n) ? n : 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a raw score to a 0-100 scale based on its full score.
|
||||
* Returns 0 when fullScore is non-positive. Result is rounded to 2 decimals.
|
||||
*/
|
||||
export const normalize = (score: number, fullScore: number): number => {
|
||||
if (fullScore <= 0) return 0
|
||||
return Math.round((score / fullScore) * 10000) / 100
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Drizzle SQL filter that restricts `gradeRecords` rows based on
|
||||
* the current user's DataScope. Returns `null` when no row-level filter
|
||||
* is required (e.g. admin / student viewing their own records — the caller
|
||||
* is expected to add the studentId condition separately for `class_members`).
|
||||
*/
|
||||
export const buildScopeClassFilter = (scope: DataScope): SQL | null => {
|
||||
if (scope.type === "all") return null
|
||||
if (scope.type === "class_taught") {
|
||||
return scope.classIds.length > 0
|
||||
? inArray(gradeRecords.classId, scope.classIds)
|
||||
: sql`1=0`
|
||||
}
|
||||
if (scope.type === "grade_managed") return sql`1=0`
|
||||
if (scope.type === "class_members") return null
|
||||
if (scope.type === "children") {
|
||||
return scope.childrenIds.length > 0
|
||||
? inArray(gradeRecords.studentId, scope.childrenIds)
|
||||
: sql`1=0`
|
||||
}
|
||||
if (scope.type === "owned") return eq(gradeRecords.studentId, scope.userId)
|
||||
return sql`1=0`
|
||||
}
|
||||
Reference in New Issue
Block a user