- Add actions-ai-evaluation, actions-analytics, actions-attachments, actions-calendar, actions-comments, actions-formative, actions-questions, actions-review, actions-substitutes - Add corresponding data-access layers for each new action module - Add calendar-view, curriculum-map-view, version-diff-viewer components - Add editor-slice, selection-slice, version-slice hooks for state management - Add document-diff and scope-check lib utilities - Add default-question-service and external-questions-bridge services
142 lines
3.3 KiB
TypeScript
142 lines
3.3 KiB
TypeScript
/**
|
|
* M6 资源附件库 - 数据访问层
|
|
*/
|
|
import "server-only";
|
|
import { db } from "@/shared/db";
|
|
import { lessonPlanAttachments } from "@/shared/db/schema";
|
|
import { and, eq, desc } from "drizzle-orm";
|
|
import type { AttachmentType } from "./lib/type-guards";
|
|
import { isAttachmentType } from "./lib/type-guards";
|
|
|
|
/** 附件记录 */
|
|
export interface LessonPlanAttachment {
|
|
id: string;
|
|
planId: string;
|
|
blockId?: string;
|
|
fileId: string;
|
|
displayName: string;
|
|
attachmentType: AttachmentType;
|
|
uploadedBy: string;
|
|
createdAt: Date;
|
|
}
|
|
|
|
/**
|
|
* 查询课案的所有附件
|
|
*/
|
|
export async function getAttachmentsByPlanId(
|
|
planId: string,
|
|
): Promise<LessonPlanAttachment[]> {
|
|
const rows = await db
|
|
.select()
|
|
.from(lessonPlanAttachments)
|
|
.where(eq(lessonPlanAttachments.planId, planId))
|
|
.orderBy(desc(lessonPlanAttachments.createdAt));
|
|
|
|
return rows.map(mapRowToAttachment);
|
|
}
|
|
|
|
/**
|
|
* 查询特定 Block 的附件
|
|
*/
|
|
export async function getAttachmentsByBlockId(
|
|
planId: string,
|
|
blockId: string,
|
|
): Promise<LessonPlanAttachment[]> {
|
|
const rows = await db
|
|
.select()
|
|
.from(lessonPlanAttachments)
|
|
.where(
|
|
and(
|
|
eq(lessonPlanAttachments.planId, planId),
|
|
eq(lessonPlanAttachments.blockId, blockId),
|
|
),
|
|
)
|
|
.orderBy(desc(lessonPlanAttachments.createdAt));
|
|
|
|
return rows.map(mapRowToAttachment);
|
|
}
|
|
|
|
/**
|
|
* 添加附件
|
|
*/
|
|
export async function createAttachment(
|
|
input: {
|
|
planId: string;
|
|
blockId?: string;
|
|
fileId: string;
|
|
displayName: string;
|
|
attachmentType?: AttachmentType;
|
|
},
|
|
uploadedBy: string,
|
|
): Promise<LessonPlanAttachment> {
|
|
const [row] = await db.insert(lessonPlanAttachments).values({
|
|
planId: input.planId,
|
|
blockId: input.blockId,
|
|
fileId: input.fileId,
|
|
displayName: input.displayName,
|
|
attachmentType: input.attachmentType ?? "reference",
|
|
uploadedBy,
|
|
});
|
|
const insertedId = row.insertId;
|
|
const all = await getAttachmentsByPlanId(input.planId);
|
|
const created = all.find((a) => a.id === String(insertedId));
|
|
if (!created) throw new Error("ATTACHMENT_CREATE_FAILED");
|
|
return created;
|
|
}
|
|
|
|
/**
|
|
* 删除附件
|
|
*/
|
|
export async function deleteAttachment(
|
|
attachmentId: string,
|
|
): Promise<void> {
|
|
await db
|
|
.delete(lessonPlanAttachments)
|
|
.where(eq(lessonPlanAttachments.id, attachmentId));
|
|
}
|
|
|
|
/**
|
|
* 更新附件类型
|
|
*/
|
|
export async function updateAttachmentType(
|
|
attachmentId: string,
|
|
attachmentType: AttachmentType,
|
|
): Promise<void> {
|
|
await db
|
|
.update(lessonPlanAttachments)
|
|
.set({ attachmentType })
|
|
.where(eq(lessonPlanAttachments.id, attachmentId));
|
|
}
|
|
|
|
/**
|
|
* 按 ID 获取附件
|
|
*/
|
|
export async function getAttachmentById(
|
|
id: string,
|
|
): Promise<LessonPlanAttachment | null> {
|
|
const rows = await db
|
|
.select()
|
|
.from(lessonPlanAttachments)
|
|
.where(eq(lessonPlanAttachments.id, id))
|
|
.limit(1);
|
|
return rows.length === 0 ? null : mapRowToAttachment(rows[0]!);
|
|
}
|
|
|
|
function mapRowToAttachment(
|
|
row: typeof lessonPlanAttachments.$inferSelect,
|
|
): LessonPlanAttachment {
|
|
const attachmentType = isAttachmentType(row.attachmentType)
|
|
? row.attachmentType
|
|
: "reference";
|
|
return {
|
|
id: row.id,
|
|
planId: row.planId,
|
|
blockId: row.blockId ?? undefined,
|
|
fileId: row.fileId,
|
|
displayName: row.displayName,
|
|
attachmentType,
|
|
uploadedBy: row.uploadedBy,
|
|
createdAt: row.createdAt,
|
|
};
|
|
}
|