feat(shared,prisma): 建立日课表与岛组件契约及数据范围模型
This commit is contained in:
1 parent
c0ebf88138
commit
66ef878a71
11 files changed
+758
-11
No files matched your search
+181
@@ -0,0 +1,181 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "TimeLayoutItem" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"timeLayoutId" TEXT NOT NULL,
|
||||
"position" INTEGER NOT NULL,
|
||||
"name" TEXT NOT NULL DEFAULT '',
|
||||
"startTime" TEXT NOT NULL,
|
||||
"endTime" TEXT NOT NULL,
|
||||
"timeType" TEXT NOT NULL DEFAULT 'LESSON',
|
||||
"isHideDefault" BOOLEAN NOT NULL DEFAULT false,
|
||||
"defaultClassId" TEXT,
|
||||
"breakName" TEXT NOT NULL DEFAULT '',
|
||||
"actionSet" TEXT NOT NULL DEFAULT '{}',
|
||||
CONSTRAINT "TimeLayoutItem_timeLayoutId_fkey" FOREIGN KEY ("timeLayoutId") REFERENCES "TimeLayout" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ClassPlanGroup" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"classId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"isGlobal" BOOLEAN NOT NULL DEFAULT false,
|
||||
"isDefault" BOOLEAN NOT NULL DEFAULT false,
|
||||
CONSTRAINT "ClassPlanGroup_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ClassPlan" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"classId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"timeLayoutId" TEXT NOT NULL,
|
||||
"associatedGroup" TEXT,
|
||||
"weekday" INTEGER NOT NULL DEFAULT 0,
|
||||
"weekCountDiv" INTEGER NOT NULL DEFAULT 0,
|
||||
"weekCountDivTotal" INTEGER NOT NULL DEFAULT 2,
|
||||
"weekStart" INTEGER NOT NULL DEFAULT 1,
|
||||
"weekEnd" INTEGER NOT NULL DEFAULT 60,
|
||||
"isEnabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"isOverlay" BOOLEAN NOT NULL DEFAULT false,
|
||||
"overlaySourceId" TEXT,
|
||||
"overlayDate" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "ClassPlan_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "ClassPlan_timeLayoutId_fkey" FOREIGN KEY ("timeLayoutId") REFERENCES "TimeLayout" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "ClassPlan_associatedGroup_fkey" FOREIGN KEY ("associatedGroup") REFERENCES "ClassPlanGroup" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ClassPlanEntry" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"classPlanId" TEXT NOT NULL,
|
||||
"timeLayoutItemId" TEXT NOT NULL,
|
||||
"courseId" TEXT,
|
||||
"isChangedClass" BOOLEAN NOT NULL DEFAULT false,
|
||||
"isEnabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"location" TEXT,
|
||||
"legacyScheduleId" TEXT,
|
||||
CONSTRAINT "ClassPlanEntry_classPlanId_fkey" FOREIGN KEY ("classPlanId") REFERENCES "ClassPlan" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "ClassPlanEntry_timeLayoutItemId_fkey" FOREIGN KEY ("timeLayoutItemId") REFERENCES "TimeLayoutItem" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "ClassPlanEntry_courseId_fkey" FOREIGN KEY ("courseId") REFERENCES "Course" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ScheduledClassPlan" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"classId" TEXT NOT NULL,
|
||||
"date" TEXT NOT NULL,
|
||||
"classPlanId" TEXT NOT NULL,
|
||||
CONSTRAINT "ScheduledClassPlan_classPlanId_fkey" FOREIGN KEY ("classPlanId") REFERENCES "ClassPlan" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "ScheduledClassPlan_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PromotionRun" (
|
||||
"year" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"status" TEXT NOT NULL,
|
||||
"snapshotPath" TEXT NOT NULL DEFAULT '',
|
||||
"message" TEXT NOT NULL DEFAULT '',
|
||||
"classCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"studentCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"finishedAt" DATETIME
|
||||
);
|
||||
|
||||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Course" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"initial" TEXT NOT NULL DEFAULT '',
|
||||
"isOutDoor" BOOLEAN NOT NULL DEFAULT false,
|
||||
"teacherId" TEXT NOT NULL,
|
||||
"classId" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "Course_teacherId_fkey" FOREIGN KEY ("teacherId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "Course_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_Course" ("classId", "createdAt", "id", "name", "teacherId") SELECT "classId", "createdAt", "id", "name", "teacherId" FROM "Course";
|
||||
DROP TABLE "Course";
|
||||
ALTER TABLE "new_Course" RENAME TO "Course";
|
||||
CREATE INDEX "Course_classId_idx" ON "Course"("classId");
|
||||
CREATE INDEX "Course_teacherId_idx" ON "Course"("teacherId");
|
||||
CREATE UNIQUE INDEX "Course_classId_name_key" ON "Course"("classId", "name");
|
||||
CREATE TABLE "new_PermissionGroup" (
|
||||
"scope" TEXT NOT NULL DEFAULT 'SELF_CLASS',
|
||||
"scopeValue" TEXT NOT NULL DEFAULT '',
|
||||
"defaultRole" TEXT,
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL DEFAULT '',
|
||||
"builtin" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
INSERT INTO "new_PermissionGroup" ("builtin", "createdAt", "defaultRole", "description", "id", "name", "updatedAt") SELECT "builtin", "createdAt", "defaultRole", "description", "id", "name", "updatedAt" FROM "PermissionGroup";
|
||||
DROP TABLE "PermissionGroup";
|
||||
ALTER TABLE "new_PermissionGroup" RENAME TO "PermissionGroup";
|
||||
CREATE UNIQUE INDEX "PermissionGroup_defaultRole_key" ON "PermissionGroup"("defaultRole");
|
||||
CREATE UNIQUE INDEX "PermissionGroup_name_key" ON "PermissionGroup"("name");
|
||||
CREATE TABLE "new_TimeLayout" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"classId" TEXT,
|
||||
"name" TEXT NOT NULL,
|
||||
"source" TEXT NOT NULL DEFAULT 'classisland',
|
||||
"items" TEXT NOT NULL DEFAULT '[]',
|
||||
"isOverlay" BOOLEAN NOT NULL DEFAULT false,
|
||||
"overlaySourceId" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "TimeLayout_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_TimeLayout" ("classId", "createdAt", "id", "items", "name", "source", "updatedAt") SELECT "classId", "createdAt", "id", "items", "name", "source", "updatedAt" FROM "TimeLayout";
|
||||
DROP TABLE "TimeLayout";
|
||||
ALTER TABLE "new_TimeLayout" RENAME TO "TimeLayout";
|
||||
CREATE INDEX "TimeLayout_classId_idx" ON "TimeLayout"("classId");
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TimeLayoutItem_timeLayoutId_position_idx" ON "TimeLayoutItem"("timeLayoutId", "position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ClassPlanGroup_classId_idx" ON "ClassPlanGroup"("classId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ClassPlan_classId_weekday_idx" ON "ClassPlan"("classId", "weekday");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ClassPlanEntry_classPlanId_timeLayoutItemId_key" ON "ClassPlanEntry"("classPlanId", "timeLayoutItemId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ScheduledClassPlan_classId_date_key" ON "ScheduledClassPlan"("classId", "date");
|
||||
|
||||
|
||||
-- 将旧行按实际教学周展开为完整的一天,避免不同行的周次范围互相遮挡。
|
||||
INSERT INTO TimeLayout (id,classId,name,source,items,createdAt,updatedAt)
|
||||
SELECT 'legacy-layout-' || classId || '-' || dayOfWeek,classId,'兼容作息 ' || dayOfWeek,'manual','[]',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP FROM Schedule GROUP BY classId,dayOfWeek;
|
||||
INSERT INTO TimeLayoutItem (id,timeLayoutId,position,name,startTime,endTime,timeType)
|
||||
SELECT 'legacy-layout-' || classId || '-' || dayOfWeek || '-' || startTime || '-' || endTime,'legacy-layout-' || classId || '-' || dayOfWeek,
|
||||
ROW_NUMBER() OVER (PARTITION BY classId,dayOfWeek ORDER BY startTime), '',startTime,endTime,'LESSON' FROM Schedule GROUP BY classId,dayOfWeek,startTime,endTime;
|
||||
WITH RECURSIVE weeks(w) AS (SELECT 1 UNION ALL SELECT w+1 FROM weeks WHERE w<60)
|
||||
INSERT INTO ClassPlan (id,classId,name,timeLayoutId,weekday,weekStart,weekEnd,createdAt,updatedAt)
|
||||
SELECT 'legacy-plan-' || s.classId || '-' || s.dayOfWeek || '-' || w,s.classId,'兼容第 ' || w || ' 周星期 ' || s.dayOfWeek,'legacy-layout-' || s.classId || '-' || s.dayOfWeek,s.dayOfWeek,w,w,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP
|
||||
FROM Schedule s CROSS JOIN weeks WHERE w BETWEEN s.weekStart AND s.weekEnd AND (s.weekParity='ALL' OR s.weekParity=CASE w%2 WHEN 1 THEN 'ODD' ELSE 'EVEN' END) GROUP BY s.classId,s.dayOfWeek,w;
|
||||
INSERT INTO ClassPlanEntry (id,classPlanId,timeLayoutItemId,courseId,location,legacyScheduleId)
|
||||
SELECT s.id || '-' || p.weekStart,p.id,t.id,s.courseId,s.location,s.id FROM ClassPlan p JOIN Schedule s ON s.classId=p.classId AND s.dayOfWeek=p.weekday
|
||||
AND p.weekStart BETWEEN s.weekStart AND s.weekEnd AND (s.weekParity='ALL' OR s.weekParity=CASE p.weekStart%2 WHEN 1 THEN 'ODD' ELSE 'EVEN' END)
|
||||
JOIN TimeLayoutItem t ON t.timeLayoutId=p.timeLayoutId AND t.startTime=s.startTime AND t.endTime=s.endTime
|
||||
WHERE s.id=(SELECT MIN(s2.id) FROM Schedule s2 WHERE s2.classId=s.classId AND s2.dayOfWeek=s.dayOfWeek AND s2.startTime=s.startTime AND s2.endTime=s.endTime AND p.weekStart BETWEEN s2.weekStart AND s2.weekEnd AND (s2.weekParity='ALL' OR s2.weekParity=CASE p.weekStart%2 WHEN 1 THEN 'ODD' ELSE 'EVEN' END));
|
||||
|
||||
-- 升级现有角色默认组,新增的两个管理能力初始只给管理员。
|
||||
INSERT INTO PermissionGroupItem (id,groupId,key,createdAt) SELECT 'v14-timetable-' || id,id,'timetable:manage',CURRENT_TIMESTAMP FROM PermissionGroup WHERE defaultRole='ADMIN';
|
||||
INSERT INTO PermissionGroupItem (id,groupId,key,createdAt) SELECT 'v14-update-' || id,id,'client:update',CURRENT_TIMESTAMP FROM PermissionGroup WHERE defaultRole='ADMIN';
|
||||
|
||||
UPDATE Course SET initial=substr(name,1,1) WHERE initial='';
|
||||
|
||||
-- 仅保留旧接口返回字段;课表解析不读取它,业务启用规则仍以日课表为唯一真值。
|
||||
INSERT INTO AppSetting (key,value,createdAt,updatedAt) SELECT 'schedule.compat.' || id,json_object('weekStart',weekStart,'weekEnd',weekEnd,'weekParity',weekParity),CURRENT_TIMESTAMP,CURRENT_TIMESTAMP FROM Schedule;
|
||||
@@ -0,0 +1,31 @@
|
||||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Class" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"grade" TEXT NOT NULL,
|
||||
"enrollmentYear" INTEGER,
|
||||
"classIndex" INTEGER,
|
||||
"teacherId" TEXT,
|
||||
"code" TEXT NOT NULL,
|
||||
"passwordHash" TEXT,
|
||||
"termWeeks" INTEGER NOT NULL DEFAULT 20,
|
||||
"termStartDate" TEXT,
|
||||
"studentGradeQueryEnabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"archivedYearId" TEXT,
|
||||
"archivedAt" DATETIME,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "Class_teacherId_fkey" FOREIGN KEY ("teacherId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT "Class_archivedYearId_fkey" FOREIGN KEY ("archivedYearId") REFERENCES "ArchivedYear" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_Class" ("archivedAt", "archivedYearId", "classIndex", "code", "createdAt", "enrollmentYear", "grade", "id", "name", "passwordHash", "studentGradeQueryEnabled", "teacherId", "termStartDate", "termWeeks", "updatedAt") SELECT "archivedAt", "archivedYearId", "classIndex", "code", "createdAt", "enrollmentYear", "grade", "id", "name", "passwordHash", "studentGradeQueryEnabled", "teacherId", "termStartDate", "termWeeks", "updatedAt" FROM "Class";
|
||||
DROP TABLE "Class";
|
||||
ALTER TABLE "new_Class" RENAME TO "Class";
|
||||
CREATE UNIQUE INDEX "Class_code_key" ON "Class"("code");
|
||||
CREATE INDEX "Class_teacherId_idx" ON "Class"("teacherId");
|
||||
CREATE INDEX "Class_enrollmentYear_idx" ON "Class"("enrollmentYear");
|
||||
CREATE INDEX "Class_archivedYearId_idx" ON "Class"("archivedYearId");
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
-- 将历史离线导入的 JSON 时间点补为关系记录;items 仅保留原始审计来源。
|
||||
INSERT INTO TimeLayoutItem (id,timeLayoutId,position,name,startTime,endTime,timeType,isHideDefault,breakName)
|
||||
SELECT 'import-point-'||t.id||'-'||j.key,t.id,CAST(j.key AS INTEGER),COALESCE(json_extract(j.value,'$.name'),''),json_extract(j.value,'$.startTime'),json_extract(j.value,'$.endTime'),
|
||||
CASE json_extract(j.value,'$.type') WHEN 'break' THEN 'BREAK' WHEN 'divider' THEN 'DIVIDER' WHEN 'action' THEN 'ACTION' ELSE 'LESSON' END,
|
||||
COALESCE(json_extract(j.value,'$.skipped'),false),CASE json_extract(j.value,'$.type') WHEN 'break' THEN COALESCE(json_extract(j.value,'$.name'),'') ELSE '' END
|
||||
FROM TimeLayout t,json_each(CASE WHEN json_valid(t.items) THEN t.items ELSE '[]' END) j
|
||||
WHERE NOT EXISTS(SELECT 1 FROM TimeLayoutItem p WHERE p.timeLayoutId=t.id)
|
||||
AND json_extract(j.value,'$.startTime') IS NOT NULL AND json_extract(j.value,'$.endTime') IS NOT NULL;
|
||||
@@ -211,7 +211,7 @@ model Class {
|
||||
/// 班号(同一届内的序号)
|
||||
classIndex Int?
|
||||
/// 班主任(每班 1 人);科任老师按科目配在 Course 上
|
||||
teacherId String
|
||||
teacherId String?
|
||||
/// 班级码:ClassHelper 班级端登录用(唯一,字母数字,4~16 位,存大写)
|
||||
code String @unique
|
||||
/// 班级密码(bcrypt 哈希);null = 尚未设置,此时禁止班级端登录
|
||||
@@ -230,7 +230,7 @@ model Class {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
teacher User @relation("ClassOwner", fields: [teacherId], references: [id], onDelete: Cascade)
|
||||
teacher User? @relation("ClassOwner", fields: [teacherId], references: [id], onDelete: SetNull)
|
||||
archivedYear ArchivedYear? @relation(fields: [archivedYearId], references: [id], onDelete: SetNull)
|
||||
students Student[]
|
||||
courses Course[]
|
||||
@@ -240,6 +240,9 @@ model Class {
|
||||
grades Grade[]
|
||||
exams Exam[]
|
||||
timeLayouts TimeLayout[]
|
||||
classPlans ClassPlan[]
|
||||
planGroups ClassPlanGroup[]
|
||||
scheduledPlans ScheduledClassPlan[]
|
||||
clientDevices ClientDevice[]
|
||||
|
||||
@@index([teacherId])
|
||||
@@ -255,6 +258,8 @@ model Class {
|
||||
model Course {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
initial String @default("")
|
||||
isOutDoor Boolean @default(false)
|
||||
/// 该班该科的任课老师
|
||||
teacherId String
|
||||
classId String
|
||||
@@ -265,6 +270,7 @@ model Course {
|
||||
schedules Schedule[]
|
||||
homeworks Homework[]
|
||||
grades Grade[]
|
||||
planEntries ClassPlanEntry[]
|
||||
|
||||
@@unique([classId, name])
|
||||
@@index([classId])
|
||||
@@ -384,16 +390,20 @@ model NotificationRead {
|
||||
/// 课表时间配置(ClassIsland 同款 JSON 导入后的节次时间表)
|
||||
model TimeLayout {
|
||||
id String @id @default(cuid())
|
||||
classId String
|
||||
classId String?
|
||||
name String
|
||||
/// 来源:classisland | manual
|
||||
source String @default("classisland")
|
||||
/// 节次数组(JSON 字符串):[{ index, name, startTime, endTime, type, skipped }]
|
||||
items String
|
||||
items String @default("[]")
|
||||
isOverlay Boolean @default(false)
|
||||
overlaySourceId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
||||
class Class? @relation(fields: [classId], references: [id], onDelete: Cascade)
|
||||
points TimeLayoutItem[]
|
||||
plans ClassPlan[]
|
||||
|
||||
@@index([classId])
|
||||
}
|
||||
@@ -429,6 +439,8 @@ model Grade {
|
||||
}
|
||||
|
||||
model PermissionGroup {
|
||||
scope String @default("SELF_CLASS")
|
||||
scopeValue String @default("")
|
||||
/// 角色默认组;自定义组为空,改名不影响对应角色。
|
||||
defaultRole String? @unique
|
||||
id String @id @default(cuid())
|
||||
@@ -526,7 +538,7 @@ model ClientDevice {
|
||||
|
||||
/// 下发给客户端设备的指令(远控:关机 / 重启 / 注销 / 锁屏)。
|
||||
///
|
||||
/// 客户端心跳时拉取未确认且未过期的指令,**执行前必须在界面上二次确认**,
|
||||
/// 客户端心跳时拉取未回执且未过期的指令,收到即执行(2026-10-17 产品要求),
|
||||
/// 执行后回执(`ackedAt` + `result`)。
|
||||
model ClientCommand {
|
||||
id String @id @default(cuid())
|
||||
@@ -539,7 +551,7 @@ model ClientCommand {
|
||||
createdAt DateTime @default(now())
|
||||
/// 过期时间:超过后不再下发(避免机器离线后几天突然关机)
|
||||
expiresAt DateTime?
|
||||
/// 客户端确认执行的时间
|
||||
/// 客户端回执执行结果的时间
|
||||
ackedAt DateTime?
|
||||
/// 执行结果说明(成功 / 失败原因)
|
||||
result String @default("")
|
||||
@@ -615,3 +627,93 @@ model Exam {
|
||||
@@unique([classId, name])
|
||||
@@index([classId])
|
||||
}
|
||||
|
||||
/// 服务端不用单机 Profile:全校共享时间表 + 班级日课表替代档案。
|
||||
model TimeLayoutItem {
|
||||
id String @id @default(cuid())
|
||||
timeLayoutId String
|
||||
position Int
|
||||
name String @default("")
|
||||
startTime String
|
||||
endTime String
|
||||
timeType String @default("LESSON")
|
||||
isHideDefault Boolean @default(false)
|
||||
defaultClassId String?
|
||||
breakName String @default("")
|
||||
actionSet String @default("{}")
|
||||
layout TimeLayout @relation(fields: [timeLayoutId], references: [id], onDelete: Cascade)
|
||||
entries ClassPlanEntry[]
|
||||
@@index([timeLayoutId, position])
|
||||
}
|
||||
|
||||
model ClassPlanGroup {
|
||||
id String @id @default(cuid())
|
||||
classId String
|
||||
name String
|
||||
isGlobal Boolean @default(false)
|
||||
isDefault Boolean @default(false)
|
||||
plans ClassPlan[]
|
||||
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
||||
@@index([classId])
|
||||
}
|
||||
|
||||
model ClassPlan {
|
||||
id String @id @default(cuid())
|
||||
classId String
|
||||
name String
|
||||
timeLayoutId String
|
||||
associatedGroup String?
|
||||
weekday Int @default(0)
|
||||
weekCountDiv Int @default(0)
|
||||
weekCountDivTotal Int @default(2)
|
||||
weekStart Int @default(1)
|
||||
weekEnd Int @default(60)
|
||||
isEnabled Boolean @default(true)
|
||||
isOverlay Boolean @default(false)
|
||||
overlaySourceId String?
|
||||
overlayDate String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
||||
layout TimeLayout @relation(fields: [timeLayoutId], references: [id], onDelete: Cascade)
|
||||
group ClassPlanGroup? @relation(fields: [associatedGroup], references: [id], onDelete: SetNull)
|
||||
entries ClassPlanEntry[]
|
||||
scheduled ScheduledClassPlan[]
|
||||
@@index([classId, weekday])
|
||||
}
|
||||
|
||||
model ClassPlanEntry {
|
||||
id String @id @default(cuid())
|
||||
classPlanId String
|
||||
timeLayoutItemId String
|
||||
courseId String?
|
||||
isChangedClass Boolean @default(false)
|
||||
isEnabled Boolean @default(true)
|
||||
location String?
|
||||
legacyScheduleId String?
|
||||
plan ClassPlan @relation(fields: [classPlanId], references: [id], onDelete: Cascade)
|
||||
timePoint TimeLayoutItem @relation(fields: [timeLayoutItemId], references: [id], onDelete: Cascade)
|
||||
course Course? @relation(fields: [courseId], references: [id], onDelete: SetNull)
|
||||
@@unique([classPlanId, timeLayoutItemId])
|
||||
}
|
||||
|
||||
model ScheduledClassPlan {
|
||||
id String @id @default(cuid())
|
||||
classId String
|
||||
date String
|
||||
classPlanId String
|
||||
plan ClassPlan @relation(fields: [classPlanId], references: [id], onDelete: Cascade)
|
||||
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
||||
@@unique([classId, date])
|
||||
}
|
||||
|
||||
model PromotionRun {
|
||||
year Int @id
|
||||
status String
|
||||
snapshotPath String @default("")
|
||||
message String @default("")
|
||||
classCount Int @default(0)
|
||||
studentCount Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
finishedAt DateTime?
|
||||
}
|
||||
Reference in new issue
Block a user