feat(core-edu): admin/dashboard/leave-requests 模块 + gRPC + 状态机测试 + nextstep 文档

This commit is contained in:
SpecialX
2026-07-14 15:56:10 +08:00
parent d260df864c
commit 7dd5c44406
23 changed files with 3344 additions and 2 deletions

View File

@@ -0,0 +1,73 @@
import { and, eq, inArray } from "drizzle-orm";
import type { Column, SQL } from "drizzle-orm";
// 数据范围类型
export type DataScope =
| "SELF" // 仅本人
| "CLASS" // 班级
| "GRADE" // 年级
| "SCHOOL" // 学校
| "DISTRICT" // 学区
| "ALL"; // 全部
// 数据范围上下文,由请求头解析得到
export interface DataScopeContext {
scope: DataScope;
userId: string;
classIds?: string[]; // 教师关联的班级 ID 列表
schoolId?: string;
}
// 数据范围列映射,指定各维度对应的表列
export interface DataScopeColumns {
studentId?: Column;
classId?: Column;
gradeId?: Column;
schoolId?: Column;
}
// 根据数据范围上下文构建 WHERE 条件
// 返回 SQL 表达式或 undefined无需过滤时
export function buildDataScopeCondition(
ctx: DataScopeContext,
columns: DataScopeColumns,
): SQL | undefined {
switch (ctx.scope) {
case "SELF":
// 学生只能看自己的数据,按 student_id 过滤
if (!columns.studentId) return undefined;
return eq(columns.studentId, ctx.userId);
case "CLASS":
// 教师只能看自己班级的数据,按 class_id 过滤
if (!columns.classId || !ctx.classIds?.length) return undefined;
return inArray(columns.classId, ctx.classIds);
case "GRADE":
// 按年级过滤,按 grade_id 过滤
// 当前上下文未提供年级 ID暂不加过滤
return undefined;
case "SCHOOL":
// 按学校过滤,按 school_id 过滤
if (!columns.schoolId || !ctx.schoolId) return undefined;
return eq(columns.schoolId, ctx.schoolId);
case "DISTRICT":
case "ALL":
// 区级和全局范围不加过滤
return undefined;
default:
return undefined;
}
}
// 将数据范围条件注入到基础条件中,返回组合后的 WHERE 条件
// baseCondition: 已有的 WHERE 条件(可选)
// ctx: 数据范围上下文(可选,为空时返回基础条件)
// columns: 数据范围列映射
export function injectDataScope(
baseCondition: SQL | undefined,
ctx: DataScopeContext | undefined,
columns: DataScopeColumns,
): SQL | undefined {
if (!ctx) return baseCondition;
const scopeCondition = buildDataScopeCondition(ctx, columns);
return and(baseCondition, scopeCondition);
}