管理端修改

This commit is contained in:
tianmo committed 2026-09-30 18:01:35 +08:00
1 parent 5fe7f5d476
commit b652132957
8 files changed
+257 -7

No files matched your search

@@ -211,6 +211,12 @@ export class AdminController {
return this.admin.listNotifyLogs(env, Number(page) || 1, Number(pageSize) || 20);
}
/** 后台需要的站点级信息(静态资源域名等),不分数据源。 */
@Get('site')
siteInfo() {
return this.admin.siteInfo();
}
@Post('entitlements')
grantEntitlement(@AdminEnvParam() env: DataSourceEnv, @Body() body: unknown) {
const parsed = grantSchema.safeParse(body);
@@ -188,14 +188,34 @@ export class AdminService {
};
const d = this.delegate(this.prisma.clientFor(env), readonly ? readonly.delegate : def!.delegate);
const [items, total] = await Promise.all([
const [rows, total] = await Promise.all([
d.findMany({ where, orderBy: readonly ? readonly.orderBy : def!.orderBy, skip: (current - 1) * size, take: size }),
d.count({ where }),
]);
// 有些资源要补几个派生字段给后台用(比如课时要带出所属课程的 code,才能拼封面图地址)
const items = def?.decorate
? await def.decorate(this.prisma.clientFor(env), rows as Record<string, unknown>[])
: rows;
return { items, total, page: current, pageSize: size };
}
/**
* 后台需要的站点级信息。都是服务端 .env 里的对外域名,只读展示——
* 后台改了不生效,改这里没用。
*/
siteInfo() {
return {
/** 课程数据域名:封面、视频等静态资源,也是拼封面图地址用的那个 */
staticBaseUrl: this.cfg.STATIC_BASE_URL,
/** 服务端 API 域名 */
apiBaseUrl: this.cfg.API_BASE_URL,
/** 管理后台域名 */
adminOrigin: this.cfg.ADMIN_ORIGIN,
};
}
async createResource(env: DataSourceEnv, name: string, payload: unknown) {
const def = RESOURCES[name];
if (!def) throw AppError.notFound(`资源不可创建:${name}`);
@@ -1,4 +1,5 @@
import { z } from 'zod';
import type { PrismaClient } from '@prisma/client';
/**
* 可 CRUD 的资源注册表。
@@ -45,6 +46,14 @@ export interface ResourceDef {
searchField?: string;
/** 创建时需要自动补齐的字段 */
defaults?: Record<string, unknown>;
/**
* 列表返回前补派生字段。用来给后台拼封面图地址——
* 课时表里只有 course_id,得先查出课程的 code 才能拼出 Course/{code}.png。
*/
decorate?: (
db: PrismaClient,
rows: Record<string, unknown>[],
) => Promise<Record<string, unknown>[]>;
}
export const RESOURCES: Record<string, ResourceDef> = {
@@ -80,6 +89,20 @@ export const RESOURCES: Record<string, ResourceDef> = {
}),
orderBy: [{ sort_order: 'asc' }, { id: 'asc' }],
searchField: 'lesson_title',
/** 带上所属课程的 code:后台拿它拼课程封面图,课时自己那张图不用 */
decorate: async (db, rows) => {
const courseIds = [...new Set(rows.map((r) => Number(r.course_id)))].filter((n) => Number.isFinite(n));
if (courseIds.length === 0) return rows;
const courses = await db.course.findMany({
where: { id: { in: courseIds } },
select: { id: true, code: true, title: true },
});
const byId = new Map(courses.map((c) => [c.id, c]));
return rows.map((r) => {
const course = byId.get(Number(r.course_id));
return { ...r, course_code: course?.code ?? null, course_title: course?.title ?? null };
});
},
},
'home-courses': {