refactor: P1-2 actions 层 DB 操作下沉到 data-access (exams/homework/questions/announcements)

This commit is contained in:
SpecialX
2026-06-18 02:31:16 +08:00
parent 2c8e229e00
commit 84d6636bd1
9 changed files with 858 additions and 438 deletions

View File

@@ -2,16 +2,21 @@
import { revalidatePath } from "next/cache"
import { createId } from "@paralleldrive/cuid2"
import { eq } from "drizzle-orm"
import { requireAuth, requirePermission, PermissionDeniedError } from "@/shared/lib/auth-guard"
import { Permissions } from "@/shared/types/permissions"
import { db } from "@/shared/db"
import { announcements } from "@/shared/db/schema"
import type { ActionState } from "@/shared/types/action-state"
import { CreateAnnouncementSchema, UpdateAnnouncementSchema } from "./schema"
import { getAnnouncements, getAnnouncementById } from "./data-access"
import {
getAnnouncements,
getAnnouncementById,
insertAnnouncement,
updateAnnouncementById,
deleteAnnouncementById,
publishAnnouncementById,
archiveAnnouncementById,
} from "./data-access"
import type { GetAnnouncementsParams, Announcement } from "./types"
export async function createAnnouncementAction(
@@ -49,9 +54,8 @@ export async function createAnnouncementAction(
? new Date(input.publishedAt)
: null
const id = createId()
await db.insert(announcements).values({
id,
const id = await insertAnnouncement({
id: createId(),
title: input.title,
content: input.content,
type: input.type,
@@ -105,7 +109,6 @@ export async function updateAnnouncementAction(
}
const input = parsed.data
const wasPublished = existing.status === "published"
const isPublished = input.status === "published"
const publishedAt = isPublished
? existing.publishedAt
@@ -115,24 +118,20 @@ export async function updateAnnouncementAction(
? new Date(input.publishedAt)
: null
await db
.update(announcements)
.set({
title: input.title,
content: input.content,
type: input.type,
status: input.status,
targetGradeId: input.targetGradeId,
targetClassId: input.targetClassId,
publishedAt,
updatedAt: new Date(),
})
.where(eq(announcements.id, id))
await updateAnnouncementById(id, {
title: input.title,
content: input.content,
type: input.type,
status: input.status,
targetGradeId: input.targetGradeId,
targetClassId: input.targetClassId,
publishedAt,
updatedAt: new Date(),
})
revalidatePath("/admin/announcements")
revalidatePath(`/admin/announcements/${id}`)
revalidatePath("/announcements")
void wasPublished
return { success: true, message: "Announcement updated", data: id }
} catch (e) {
@@ -151,7 +150,7 @@ export async function deleteAnnouncementAction(id: string): Promise<ActionState<
const existing = await getAnnouncementById(id)
if (!existing) return { success: false, message: "Announcement not found" }
await db.delete(announcements).where(eq(announcements.id, id))
await deleteAnnouncementById(id)
revalidatePath("/admin/announcements")
revalidatePath("/announcements")
@@ -173,14 +172,10 @@ export async function publishAnnouncementAction(id: string): Promise<ActionState
const existing = await getAnnouncementById(id)
if (!existing) return { success: false, message: "Announcement not found" }
await db
.update(announcements)
.set({
status: "published",
publishedAt: existing.publishedAt ? new Date(existing.publishedAt) : new Date(),
updatedAt: new Date(),
})
.where(eq(announcements.id, id))
const publishedAt = existing.publishedAt
? new Date(existing.publishedAt)
: new Date()
await publishAnnouncementById(id, publishedAt)
revalidatePath("/admin/announcements")
revalidatePath(`/admin/announcements/${id}`)
@@ -203,13 +198,7 @@ export async function archiveAnnouncementAction(id: string): Promise<ActionState
const existing = await getAnnouncementById(id)
if (!existing) return { success: false, message: "Announcement not found" }
await db
.update(announcements)
.set({
status: "archived",
updatedAt: new Date(),
})
.where(eq(announcements.id, id))
await archiveAnnouncementById(id)
revalidatePath("/admin/announcements")
revalidatePath(`/admin/announcements/${id}`)

View File

@@ -7,8 +7,10 @@ import { db } from "@/shared/db"
import { announcements, users } from "@/shared/db/schema"
import type {
Announcement,
AnnouncementInsertData,
AnnouncementStatus,
AnnouncementType,
AnnouncementUpdateData,
GetAnnouncementsParams,
} from "./types"
@@ -118,3 +120,67 @@ export const getAnnouncementById = cache(
}
}
)
export async function insertAnnouncement(
data: AnnouncementInsertData
): Promise<string> {
await db.insert(announcements).values({
id: data.id,
title: data.title,
content: data.content,
type: data.type,
status: data.status,
targetGradeId: data.targetGradeId,
targetClassId: data.targetClassId,
authorId: data.authorId,
publishedAt: data.publishedAt,
})
return data.id
}
export async function updateAnnouncementById(
id: string,
data: AnnouncementUpdateData
): Promise<void> {
await db
.update(announcements)
.set({
title: data.title,
content: data.content,
type: data.type,
status: data.status,
targetGradeId: data.targetGradeId,
targetClassId: data.targetClassId,
publishedAt: data.publishedAt,
updatedAt: data.updatedAt,
})
.where(eq(announcements.id, id))
}
export async function deleteAnnouncementById(id: string): Promise<void> {
await db.delete(announcements).where(eq(announcements.id, id))
}
export async function publishAnnouncementById(
id: string,
publishedAt: Date
): Promise<void> {
await db
.update(announcements)
.set({
status: "published",
publishedAt,
updatedAt: new Date(),
})
.where(eq(announcements.id, id))
}
export async function archiveAnnouncementById(id: string): Promise<void> {
await db
.update(announcements)
.set({
status: "archived",
updatedAt: new Date(),
})
.where(eq(announcements.id, id))
}

View File

@@ -25,3 +25,26 @@ export type GetAnnouncementsParams = {
page?: number
pageSize?: number
}
export interface AnnouncementInsertData {
id: string
title: string
content: string
type: AnnouncementType
status: AnnouncementStatus
targetGradeId: string | null
targetClassId: string | null
authorId: string
publishedAt: Date | null
}
export interface AnnouncementUpdateData {
title: string
content: string
type: AnnouncementType
status: AnnouncementStatus
targetGradeId: string | null
targetClassId: string | null
publishedAt: Date | null
updatedAt: Date
}