add
This commit is contained in:
parent
5a5d4ec3ff
commit
7e482f8c53
|
@ -1,25 +1,27 @@
|
|||
import { db, Prisma, PrismaClient } from "@nice/common";
|
||||
import { db, Prisma, PrismaClient } from '@nice/common';
|
||||
|
||||
export type Operations =
|
||||
| 'aggregate'
|
||||
| 'count'
|
||||
| 'create'
|
||||
| 'createMany'
|
||||
| 'delete'
|
||||
| 'deleteMany'
|
||||
| 'findFirst'
|
||||
| 'findMany'
|
||||
| 'findUnique'
|
||||
| 'update'
|
||||
| 'updateMany'
|
||||
| 'upsert';
|
||||
export type DelegateFuncs = { [K in Operations]: (args: any) => Promise<unknown> }
|
||||
| 'aggregate'
|
||||
| 'count'
|
||||
| 'create'
|
||||
| 'createMany'
|
||||
| 'delete'
|
||||
| 'deleteMany'
|
||||
| 'findFirst'
|
||||
| 'findMany'
|
||||
| 'findUnique'
|
||||
| 'update'
|
||||
| 'updateMany'
|
||||
| 'upsert';
|
||||
export type DelegateFuncs = {
|
||||
[K in Operations]: (args: any) => Promise<unknown>;
|
||||
};
|
||||
export type DelegateArgs<T> = {
|
||||
[K in keyof T]: T[K] extends (args: infer A) => Promise<any> ? A : never;
|
||||
[K in keyof T]: T[K] extends (args: infer A) => Promise<any> ? A : never;
|
||||
};
|
||||
|
||||
export type DelegateReturnTypes<T> = {
|
||||
[K in keyof T]: T[K] extends (args: any) => Promise<infer R> ? R : never;
|
||||
[K in keyof T]: T[K] extends (args: any) => Promise<infer R> ? R : never;
|
||||
};
|
||||
|
||||
export type WhereArgs<T> = T extends { where?: infer W } ? W : never;
|
||||
|
@ -28,17 +30,17 @@ export type DataArgs<T> = T extends { data: infer D } ? D : never;
|
|||
export type IncludeArgs<T> = T extends { include: infer I } ? I : never;
|
||||
export type OrderByArgs<T> = T extends { orderBy: infer O } ? O : never;
|
||||
export type UpdateOrderArgs = {
|
||||
id: string
|
||||
overId: string
|
||||
}
|
||||
id: string;
|
||||
overId: string;
|
||||
};
|
||||
export interface FindManyWithCursorType<T extends DelegateFuncs> {
|
||||
cursor?: string;
|
||||
limit?: number;
|
||||
where?: WhereArgs<DelegateArgs<T>['findUnique']>;
|
||||
select?: SelectArgs<DelegateArgs<T>['findUnique']>;
|
||||
orderBy?: OrderByArgs<DelegateArgs<T>['findMany']>
|
||||
cursor?: string;
|
||||
limit?: number;
|
||||
where?: WhereArgs<DelegateArgs<T>['findUnique']>;
|
||||
select?: SelectArgs<DelegateArgs<T>['findUnique']>;
|
||||
orderBy?: OrderByArgs<DelegateArgs<T>['findMany']>;
|
||||
}
|
||||
export type TransactionType = Omit<
|
||||
PrismaClient,
|
||||
'$connect' | '$disconnect' | '$on' | '$transaction' | '$use' | '$extends'
|
||||
>;
|
||||
PrismaClient,
|
||||
'$connect' | '$disconnect' | '$on' | '$transaction' | '$use' | '$extends'
|
||||
>;
|
||||
|
|
|
@ -3,8 +3,10 @@ import { TrpcService } from '@server/trpc/trpc.service';
|
|||
import { CourseMethodSchema, Prisma } from '@nice/common';
|
||||
import { PostService } from './post.service';
|
||||
import { z, ZodType } from 'zod';
|
||||
import { UpdateOrderArgs } from '../base/base.type';
|
||||
const PostCreateArgsSchema: ZodType<Prisma.PostCreateArgs> = z.any();
|
||||
const PostUpdateArgsSchema: ZodType<Prisma.PostUpdateArgs> = z.any();
|
||||
const PostUpdateOrderArgsSchema: ZodType<UpdateOrderArgs> = z.any();
|
||||
const PostFindFirstArgsSchema: ZodType<Prisma.PostFindFirstArgs> = z.any();
|
||||
const PostFindManyArgsSchema: ZodType<Prisma.PostFindManyArgs> = z.any();
|
||||
const PostDeleteManyArgsSchema: ZodType<Prisma.PostDeleteManyArgs> = z.any();
|
||||
|
@ -107,5 +109,21 @@ export class PostRouter {
|
|||
.query(async ({ input }) => {
|
||||
return await this.postService.findManyWithPagination(input);
|
||||
}),
|
||||
updateOrder: this.trpc.protectProcedure
|
||||
.input(PostUpdateOrderArgsSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const { staff } = ctx;
|
||||
return await this.postService.updateOrder(input);
|
||||
}),
|
||||
updateOrderByIds: this.trpc.protectProcedure
|
||||
.input(
|
||||
z.object({
|
||||
ids: z.array(z.string()),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const { staff } = ctx;
|
||||
return await this.postService.updateOrderByIds(input.ids);
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import EventBus, { CrudOperation } from '@server/utils/event-bus';
|
|||
import { BaseTreeService } from '../base/base.tree.service';
|
||||
import { z } from 'zod';
|
||||
import { DefaultArgs } from '@prisma/client/runtime/library';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@Injectable()
|
||||
export class PostService extends BaseTreeService<Prisma.PostDelegate> {
|
||||
|
@ -43,6 +44,7 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
|
|||
content: content,
|
||||
title: title,
|
||||
authorId: params?.staff?.id,
|
||||
updatedAt: dayjs().toDate(),
|
||||
resources: {
|
||||
connect: resourceIds.map((fileId) => ({ fileId })),
|
||||
},
|
||||
|
@ -71,6 +73,7 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
|
|||
parentId: courseId,
|
||||
title: title,
|
||||
authorId: staff?.id,
|
||||
updatedAt: dayjs().toDate(),
|
||||
} as any,
|
||||
},
|
||||
{ tx },
|
||||
|
@ -152,6 +155,7 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
|
|||
params?: { staff?: UserProfile; tx?: Prisma.TransactionClient },
|
||||
) {
|
||||
args.data.authorId = params?.staff?.id;
|
||||
args.data.updatedAt = dayjs().toDate();
|
||||
const result = await super.create(args);
|
||||
EventBus.emit('dataChanged', {
|
||||
type: ObjectType.POST,
|
||||
|
@ -162,6 +166,7 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
|
|||
}
|
||||
async update(args: Prisma.PostUpdateArgs, staff?: UserProfile) {
|
||||
args.data.authorId = staff?.id;
|
||||
args.data.updatedAt = dayjs().toDate();
|
||||
const result = await super.update(args);
|
||||
EventBus.emit('dataChanged', {
|
||||
type: ObjectType.POST,
|
||||
|
@ -246,8 +251,38 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
|
|||
}[];
|
||||
totalPages: number;
|
||||
}> {
|
||||
// super.updateOrder;
|
||||
return super.findManyWithPagination(args);
|
||||
}
|
||||
|
||||
async updateOrderByIds(ids: string[]) {
|
||||
const posts = await db.post.findMany({
|
||||
where: { id: { in: ids } },
|
||||
select: { id: true, order: true },
|
||||
});
|
||||
const postMap = new Map(posts.map((post) => [post.id, post]));
|
||||
const orderedPosts = ids
|
||||
.map((id) => postMap.get(id))
|
||||
.filter((post): post is { id: string; order: number } => !!post);
|
||||
|
||||
// 生成仅需更新的操作
|
||||
const updates = orderedPosts
|
||||
.map((post, index) => ({
|
||||
id: post.id,
|
||||
newOrder: index, // 按数组索引设置新顺序
|
||||
currentOrder: post.order,
|
||||
}))
|
||||
.filter(({ newOrder, currentOrder }) => newOrder !== currentOrder)
|
||||
.map(({ id, newOrder }) =>
|
||||
db.post.update({
|
||||
where: { id },
|
||||
data: { order: newOrder },
|
||||
}),
|
||||
);
|
||||
|
||||
// 批量执行更新
|
||||
return updates.length > 0 ? await db.$transaction(updates) : [];
|
||||
}
|
||||
protected async setPerms(data: Post, staff?: UserProfile) {
|
||||
if (!staff) return;
|
||||
const perms: ResPerm = {
|
||||
|
|
|
@ -37,5 +37,4 @@ export class PostQueueService implements OnModuleInit {
|
|||
debounce: { id: `${QueueJobType.UPDATE_POST_STATE}_${data.id}` },
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
Department,
|
||||
getRandomElement,
|
||||
getRandomElements,
|
||||
PostType,
|
||||
Staff,
|
||||
TaxonomySlug,
|
||||
Term,
|
||||
|
@ -14,6 +15,7 @@ import {
|
|||
import EventBus from '@server/utils/event-bus';
|
||||
import { capitalizeFirstLetter, DevDataCounts, getCounts } from './utils';
|
||||
import { StaffService } from '@server/models/staff/staff.service';
|
||||
import dayjs from 'dayjs';
|
||||
@Injectable()
|
||||
export class GenDevService {
|
||||
private readonly logger = new Logger(GenDevService.name);
|
||||
|
@ -22,7 +24,7 @@ export class GenDevService {
|
|||
terms: Record<TaxonomySlug, Term[]> = {
|
||||
[TaxonomySlug.CATEGORY]: [],
|
||||
[TaxonomySlug.TAG]: [],
|
||||
[TaxonomySlug.LEVEL]: []
|
||||
[TaxonomySlug.LEVEL]: [],
|
||||
};
|
||||
depts: Department[] = [];
|
||||
domains: Department[] = [];
|
||||
|
@ -35,7 +37,7 @@ export class GenDevService {
|
|||
private readonly departmentService: DepartmentService,
|
||||
private readonly staffService: StaffService,
|
||||
private readonly termService: TermService,
|
||||
) { }
|
||||
) {}
|
||||
async genDataEvent() {
|
||||
EventBus.emit('genDataEvent', { type: 'start' });
|
||||
try {
|
||||
|
@ -58,6 +60,7 @@ export class GenDevService {
|
|||
if (this.counts.termCount === 0) {
|
||||
this.logger.log('Generate terms');
|
||||
await this.createTerms(null, TaxonomySlug.CATEGORY, depth, count);
|
||||
await this.createLevelTerm();
|
||||
const domains = this.depts.filter((item) => item.isDomain);
|
||||
for (const domain of domains) {
|
||||
await this.createTerms(domain, TaxonomySlug.CATEGORY, depth, count);
|
||||
|
@ -174,7 +177,54 @@ export class GenDevService {
|
|||
}
|
||||
}
|
||||
}
|
||||
private async createLevelTerm() {
|
||||
try {
|
||||
// 1. 获取分类时添加异常处理
|
||||
const taxLevel = await db.taxonomy.findFirst({
|
||||
where: { slug: TaxonomySlug.LEVEL },
|
||||
});
|
||||
|
||||
if (!taxLevel) {
|
||||
throw new Error('LEVEL taxonomy not found');
|
||||
}
|
||||
|
||||
// 2. 使用数组定义初始化数据 + 名称去重
|
||||
const termsToCreate = [
|
||||
{ name: '初级', taxonomyId: taxLevel.id },
|
||||
{ name: '中级', taxonomyId: taxLevel.id },
|
||||
{ name: '高级', taxonomyId: taxLevel.id }, // 改为高级更合理
|
||||
];
|
||||
await this.termService.createMany({
|
||||
data: termsToCreate,
|
||||
});
|
||||
console.log('created level terms');
|
||||
} catch (error) {
|
||||
console.error('Failed to create level terms:', error);
|
||||
throw error; // 向上抛出错误供上层处理
|
||||
}
|
||||
}
|
||||
private async createCourse(
|
||||
title: string,
|
||||
deptId: string,
|
||||
cateId: string,
|
||||
levelId: string,
|
||||
) {
|
||||
const course = await db.post.create({
|
||||
data: {
|
||||
type: PostType.COURSE,
|
||||
title: title,
|
||||
updatedAt: dayjs().toDate(),
|
||||
depts: {
|
||||
connect: {
|
||||
id: deptId,
|
||||
},
|
||||
},
|
||||
terms:{
|
||||
connect:[cateId,levelId].map
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
private async createDepartment(
|
||||
name: string,
|
||||
parentId?: string | null,
|
||||
|
|
|
@ -115,7 +115,7 @@ export function CourseFormProvider({
|
|||
});
|
||||
message.success("课程更新成功!");
|
||||
} else {
|
||||
const result = await createCourse.mutateAsync({
|
||||
const result = await create.mutateAsync({
|
||||
courseDetail: {
|
||||
data: {
|
||||
title: formattedValues.title || "12345",
|
||||
|
|
|
@ -48,7 +48,7 @@ export const LectureList: React.FC<LectureListProps> = ({
|
|||
field,
|
||||
sectionId,
|
||||
}) => {
|
||||
const { softDeleteByIds } = usePost();
|
||||
const { softDeleteByIds, updateOrderByIds } = usePost();
|
||||
const { data: lectures = [], isLoading } = (
|
||||
api.post.findMany as any
|
||||
).useQuery(
|
||||
|
@ -87,11 +87,19 @@ export const LectureList: React.FC<LectureListProps> = ({
|
|||
const handleDragEnd = (event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
if (!over || active.id === over.id) return;
|
||||
|
||||
// updateOrder.mutateAsync({
|
||||
// id: active.id,
|
||||
// overId: over.id,
|
||||
// });
|
||||
let newItems = [];
|
||||
setItems((items) => {
|
||||
const oldIndex = items.findIndex((item) => item.id === active.id);
|
||||
const newIndex = items.findIndex((item) => item.id === over.id);
|
||||
return arrayMove(items, oldIndex, newIndex);
|
||||
newItems = arrayMove(items, oldIndex, newIndex);
|
||||
return newItems;
|
||||
});
|
||||
updateOrderByIds.mutateAsync({
|
||||
ids: newItems.map((item) => item.id),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
// import { FormArrayField } from "@web/src/components/common/form/FormArrayField";
|
||||
// import { useFormContext } from "react-hook-form";
|
||||
// import { CourseFormData } from "../context/CourseEditorContext";
|
||||
// import InputList from "@web/src/components/common/input/InputList";
|
||||
// import { useState } from "react";
|
||||
// import { Form } from "antd";
|
||||
|
||||
// export function CourseGoalForm() {
|
||||
// return (
|
||||
// <div className="max-w-2xl mx-auto space-y-6 p-6">
|
||||
// <Form.Item name="requirements" label="前置要求">
|
||||
// <InputList placeholder="请输入前置要求"></InputList>
|
||||
// </Form.Item>
|
||||
// <Form.Item name="objectives" label="学习目标">
|
||||
// <InputList placeholder="请输入学习目标"></InputList>
|
||||
// </Form.Item>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
|
@ -1,26 +0,0 @@
|
|||
// import AvatarUploader from "@web/src/components/common/uploader/AvatarUploader";
|
||||
// import { Form, Input } from "antd";
|
||||
|
||||
// export default function CourseSettingForm() {
|
||||
// return (
|
||||
// <div className="max-w-2xl mx-auto space-y-6 p-6">
|
||||
// <Form.Item
|
||||
// name="title"
|
||||
// label="课程预览图"
|
||||
// >
|
||||
// <AvatarUploader
|
||||
// style={
|
||||
// {
|
||||
// width: "120px",
|
||||
// height: "120px",
|
||||
// margin:" 0 10px"
|
||||
// }
|
||||
// }
|
||||
// onChange={(value) => {
|
||||
// console.log(value);
|
||||
// }}
|
||||
// ></AvatarUploader>
|
||||
// </Form.Item>
|
||||
// </div>
|
||||
// )
|
||||
// }
|
|
@ -113,5 +113,8 @@ export function useEntity<T extends keyof RouterInputs>(
|
|||
T,
|
||||
"updateOrder"
|
||||
>, // 更新实体顺序的 mutation 函数
|
||||
updateOrderByIds: createMutationHandler(
|
||||
"updateOrderByIds"
|
||||
) as MutationResult<T, "updateOrderByIds">, // 更新实体顺序的 mutation 函数
|
||||
};
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ model Department {
|
|||
id String @id @default(cuid())
|
||||
name String
|
||||
order Float?
|
||||
posts Post[] @relation("post_dept")
|
||||
ancestors DeptAncestry[] @relation("DescendantToAncestor")
|
||||
descendants DeptAncestry[] @relation("AncestorToDescendant")
|
||||
parentId String? @map("parent_id")
|
||||
|
@ -200,6 +201,8 @@ model Post {
|
|||
order Float? @default(0) @map("order")
|
||||
duration Int?
|
||||
rating Int? @default(0)
|
||||
|
||||
depts Department[] @relation("post_dept")
|
||||
// 索引
|
||||
// 日期时间类型字段
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
|
Loading…
Reference in New Issue