feat(dashboard,diagnostic,elective): add widgets, layout, parent dashboard, role-config, services, elective components
dashboard: - Add comparison-badge, dashboard-notification-widget, dashboard-responsive-layout, dashboard-time-range-filter - Add parent-dashboard components directory - Add config, hooks, and services directories diagnostic: - Add role-config and services directory elective: - Add elective-course-detail, elective-stats-cards, parent-selection-view components - Add data-access-settings and data-access-stats
This commit is contained in:
97
src/modules/elective/data-access-settings.ts
Normal file
97
src/modules/elective/data-access-settings.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import "server-only"
|
||||
|
||||
import { cache } from "react"
|
||||
import { eq, and } from "drizzle-orm"
|
||||
|
||||
import { db } from "@/shared/db"
|
||||
import { systemSettings } from "@/shared/db/schema"
|
||||
|
||||
/**
|
||||
* 选课模块配置化设置(P2-4 新增)。
|
||||
*
|
||||
* 设计原则:
|
||||
* - 复用全局 `system_settings` 表(category="elective"),避免新增独立表
|
||||
* - 支持按年级覆盖(key=`creditLimit:grade:<gradeId>`),fallback 到全局(key=`creditLimit:default`)
|
||||
* - 用 React `cache()` 包装,单次请求内去重
|
||||
* - 配置缺失时使用默认值(向后兼容)
|
||||
*
|
||||
* 配置项:
|
||||
* - `creditLimit:default` / `creditLimit:grade:<gradeId>`:学期学分上限(默认 10)
|
||||
* - `capacityNotifyThreshold`:容量阈值通知比例 0-1(默认 0.9)
|
||||
*/
|
||||
|
||||
const SETTINGS_CATEGORY = "elective"
|
||||
|
||||
/** 默认学期学分上限(K12 选修课) */
|
||||
const DEFAULT_MAX_CREDIT_PER_TERM = 10
|
||||
/** 默认容量阈值通知比例(90%) */
|
||||
const DEFAULT_CAPACITY_NOTIFY_THRESHOLD = 0.9
|
||||
|
||||
/**
|
||||
* 读取 system_settings 中指定 key 的值。
|
||||
* 失败或未配置时返回 null(不抛错,保证向后兼容)。
|
||||
*/
|
||||
async function readSettingValue(key: string): Promise<string | null> {
|
||||
const [row] = await db
|
||||
.select({ value: systemSettings.value, valueType: systemSettings.valueType })
|
||||
.from(systemSettings)
|
||||
.where(
|
||||
and(
|
||||
eq(systemSettings.category, SETTINGS_CATEGORY),
|
||||
eq(systemSettings.key, key)
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
return row?.value ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学期学分上限(P2-4 新增)。
|
||||
*
|
||||
* 查询顺序:
|
||||
* 1. 若传入 gradeId,先查 `creditLimit:grade:<gradeId>`
|
||||
* 2. 若未配置或未传入 gradeId,fallback 到 `creditLimit:default`
|
||||
* 3. 都未配置则返回默认值 10
|
||||
*
|
||||
* @param gradeId 学生所在年级 ID(可选)
|
||||
*/
|
||||
export const getElectiveCreditLimit = cache(
|
||||
async (gradeId?: string | null): Promise<number> => {
|
||||
if (gradeId) {
|
||||
const gradeValue = await readSettingValue(`creditLimit:grade:${gradeId}`)
|
||||
if (gradeValue !== null) {
|
||||
const parsed = Number(gradeValue)
|
||||
if (!Number.isNaN(parsed) && parsed > 0) return parsed
|
||||
}
|
||||
}
|
||||
const defaultValue = await readSettingValue("creditLimit:default")
|
||||
if (defaultValue !== null) {
|
||||
const parsed = Number(defaultValue)
|
||||
if (!Number.isNaN(parsed) && parsed > 0) return parsed
|
||||
}
|
||||
return DEFAULT_MAX_CREDIT_PER_TERM
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* 获取容量阈值通知比例(P2-4 新增)。
|
||||
*
|
||||
* 当课程 `enrolledCount >= capacity * threshold` 时触发管理员通知。
|
||||
* 默认 0.9(90%)。
|
||||
*/
|
||||
export const getCapacityNotifyThreshold = cache(
|
||||
async (): Promise<number> => {
|
||||
const value = await readSettingValue("capacityNotifyThreshold")
|
||||
if (value !== null) {
|
||||
const parsed = Number(value)
|
||||
if (!Number.isNaN(parsed) && parsed > 0 && parsed <= 1) return parsed
|
||||
}
|
||||
return DEFAULT_CAPACITY_NOTIFY_THRESHOLD
|
||||
}
|
||||
)
|
||||
|
||||
/** 导出默认值常量(供测试与文档引用) */
|
||||
export const ELECTIVE_DEFAULTS = {
|
||||
MAX_CREDIT_PER_TERM: DEFAULT_MAX_CREDIT_PER_TERM,
|
||||
CAPACITY_NOTIFY_THRESHOLD: DEFAULT_CAPACITY_NOTIFY_THRESHOLD,
|
||||
} as const
|
||||
Reference in New Issue
Block a user