feat: 初始化慧遇书院官网一期
This commit is contained in:
17
server/api/admin/media/[id].delete.ts
Normal file
17
server/api/admin/media/[id].delete.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { isMediaReferenced, moveMediaFiles, serializeMedia, type MediaAssetRow } from '../../../utils/media'
|
||||
import { useDatabase } from '../../../utils/db'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const user = await requireAdmin(event)
|
||||
const id = Number(getRouterParam(event, 'id'))
|
||||
if (!Number.isSafeInteger(id) || id < 1) throw createError({ statusCode: 400, statusMessage: '无效的素材编号' })
|
||||
const db = useDatabase()
|
||||
const row = db.prepare("SELECT * FROM media_assets WHERE id = ? AND status = 'active'").get(id) as MediaAssetRow | undefined
|
||||
if (!row) throw createError({ statusCode: 404, statusMessage: '素材不存在' })
|
||||
if (isMediaReferenced(db, row)) throw createError({ statusCode: 409, statusMessage: '素材正在被草稿或已发布页面引用,不能删除' })
|
||||
await moveMediaFiles(row, 'trash')
|
||||
const timestamp = new Date().toISOString()
|
||||
db.prepare("UPDATE media_assets SET status = 'trash', deleted_at = ?, updated_at = ? WHERE id = ?").run(timestamp, timestamp, id)
|
||||
writeAuditLog(event, { operatorId: user.id, action: 'media.trash', entityType: 'media', entityKey: row.asset_key })
|
||||
return { data: serializeMedia({ ...row, status: 'trash', deleted_at: timestamp, updated_at: timestamp }) }
|
||||
})
|
||||
25
server/api/admin/media/[id].patch.ts
Normal file
25
server/api/admin/media/[id].patch.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { z } from 'zod'
|
||||
import { serializeMedia, type MediaAssetRow } from '../../../utils/media'
|
||||
import { useDatabase } from '../../../utils/db'
|
||||
|
||||
const updateSchema = z.object({
|
||||
altText: z.string().trim().max(160),
|
||||
source: z.string().trim().max(200),
|
||||
copyright: z.string().trim().max(200),
|
||||
authorizationStatus: z.enum(['pending', 'authorized', 'restricted']),
|
||||
})
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const user = await requireAdmin(event)
|
||||
const id = Number(getRouterParam(event, 'id'))
|
||||
if (!Number.isSafeInteger(id) || id < 1) throw createError({ statusCode: 400, statusMessage: '无效的素材编号' })
|
||||
const input = updateSchema.parse(await readBody(event))
|
||||
const db = useDatabase()
|
||||
const timestamp = new Date().toISOString()
|
||||
const result = db.prepare(`UPDATE media_assets SET alt_text = ?, source_text = ?, copyright_text = ?, authorization_status = ?, updated_at = ? WHERE id = ? AND status = 'active'`)
|
||||
.run(input.altText, input.source, input.copyright, input.authorizationStatus, timestamp, id)
|
||||
if (!result.changes) throw createError({ statusCode: 404, statusMessage: '素材不存在' })
|
||||
const row = db.prepare('SELECT * FROM media_assets WHERE id = ?').get(id) as MediaAssetRow
|
||||
writeAuditLog(event, { operatorId: user.id, action: 'media.update', entityType: 'media', entityKey: row.asset_key })
|
||||
return { data: serializeMedia(row) }
|
||||
})
|
||||
16
server/api/admin/media/[id]/restore.post.ts
Normal file
16
server/api/admin/media/[id]/restore.post.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { moveMediaFiles, serializeMedia, type MediaAssetRow } from '../../../../utils/media'
|
||||
import { useDatabase } from '../../../../utils/db'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const user = await requireAdmin(event)
|
||||
const id = Number(getRouterParam(event, 'id'))
|
||||
if (!Number.isSafeInteger(id) || id < 1) throw createError({ statusCode: 400, statusMessage: '无效的素材编号' })
|
||||
const db = useDatabase()
|
||||
const row = db.prepare("SELECT * FROM media_assets WHERE id = ? AND status = 'trash'").get(id) as MediaAssetRow | undefined
|
||||
if (!row) throw createError({ statusCode: 404, statusMessage: '回收站中不存在该素材' })
|
||||
await moveMediaFiles(row, 'restore')
|
||||
const timestamp = new Date().toISOString()
|
||||
db.prepare("UPDATE media_assets SET status = 'active', deleted_at = NULL, updated_at = ? WHERE id = ?").run(timestamp, id)
|
||||
writeAuditLog(event, { operatorId: user.id, action: 'media.restore', entityType: 'media', entityKey: row.asset_key })
|
||||
return { data: serializeMedia({ ...row, status: 'active', deleted_at: null, updated_at: timestamp }) }
|
||||
})
|
||||
11
server/api/admin/media/index.get.ts
Normal file
11
server/api/admin/media/index.get.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { isMediaReferenced, serializeMedia, type MediaAssetRow } from '../../../utils/media'
|
||||
import { useDatabase } from '../../../utils/db'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAdmin(event)
|
||||
const query = getQuery(event)
|
||||
const status = query.status === 'trash' ? 'trash' : 'active'
|
||||
const db = useDatabase()
|
||||
const rows = db.prepare('SELECT * FROM media_assets WHERE status = ? ORDER BY created_at DESC LIMIT 200').all(status) as MediaAssetRow[]
|
||||
return { data: rows.map(row => serializeMedia(row, isMediaReferenced(db, row))) }
|
||||
})
|
||||
Reference in New Issue
Block a user