This commit is contained in:
ditiqi 2025-01-22 19:25:55 +08:00
parent 0da8a60bd6
commit 8e9b23e7e8
5 changed files with 177 additions and 20 deletions

View File

@ -35,6 +35,7 @@ export class PostRouter {
} as Prisma.InputJsonObject; // 明确指定类型
return await this.postService.create(input, { staff });
}),
softDeleteByIds: this.trpc.protectProcedure
.input(
z.object({

View File

@ -27,6 +27,7 @@ export class PostService extends BaseService<Prisma.PostDelegate> {
params: { staff?: UserProfile; tx?: Prisma.PostDelegate },
) {
args.data.authorId = params?.staff?.id;
// args.data.resources
const result = await super.create(args);
EventBus.emit('dataChanged', {
type: ObjectType.POST,

View File

@ -0,0 +1,113 @@
import { createContext, useContext, ReactNode, useEffect } from "react";
import { useForm, FormProvider, SubmitHandler } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { api, usePost } from "@nice/client";
// import { PostDto, PostLevel, PostStatus } from "@nice/common";
// import { api, usePost } from "@nice/client";
import toast from "react-hot-toast";
import { useNavigate } from "react-router-dom";
import { Post, PostType } from "@nice/common";
// 定义帖子表单验证 Schema
const postSchema = z.object({
title: z.string().min(1, "标题不能为空"),
content: z.string().min(1, "内容不能为空"),
resources: z.array(z.string()).nullish(),
isPublic: z.boolean(),
signature: z.string().nullish(),
});
// 定义课程表单验证 Schema
export type PostFormData = z.infer<typeof postSchema>;
interface PostEditorContextType {
onSubmit: SubmitHandler<PostFormData>;
editId?: string; // 添加 editId
part?: string;
// course?: PostDto;
}
interface PostFormProviderProps {
children: ReactNode;
editId?: string; // 添加 editId 参数
part?: string;
}
const PostEditorContext = createContext<PostEditorContextType | null>(null);
export function PostFormProvider({ children, editId }: PostFormProviderProps) {
const { create, update } = usePost();
const { data: post }: { data: Post } = api.post.findById.useQuery(
{
id: editId,
},
{ enabled: !!editId }
);
const navigate = useNavigate();
const methods = useForm<PostFormData>({
resolver: zodResolver(postSchema),
defaultValues: {
resources: [],
},
});
useEffect(() => {
if (post) {
const formData = {
title: post.title,
content: post.content,
signature: (post.meta as any)?.signature,
};
methods.reset(formData as any);
}
}, [post, methods]);
const onSubmit: SubmitHandler<PostFormData> = async (
data: PostFormData
) => {
try {
if (editId) {
// await update.mutateAsync({
// where: { id: editId },
// data: {
// ...data
// }
// })
toast.success("课程更新成功!");
} else {
const result = await create.mutateAsync({
data: {
type: PostType.POST,
...data,
resources: data.resources?.length
? {
connect: data.resources.map((id) => ({
id,
})),
}
: undefined,
},
});
// navigate(`/course/${result.id}/editor`, { replace: true });
toast.success("发送成功!");
}
methods.reset(data);
} catch (error) {
console.error("Error submitting form:", error);
toast.error("操作失败,请重试!");
}
};
return (
<PostEditorContext.Provider
value={{
onSubmit,
editId,
// course
}}>
<FormProvider {...methods}>{children}</FormProvider>
</PostEditorContext.Provider>
);
}
export const usePostEditor = () => {
const context = useContext(PostEditorContext);
if (!context) {
throw new Error("usePostEditor must be used within PostFormProvider");
}
return context;
};

View File

@ -0,0 +1,22 @@
import { ReactNode, useEffect, useState } from "react";
import { Outlet, useNavigate, useParams } from "react-router-dom";
import { motion } from "framer-motion";
import { NavItem } from "@nice/client";
import { PostFormProvider } from "../context/PostEditorContext";
export default function PostEditorLayout() {
const { id } = useParams();
return (
<>
<PostFormProvider editId={id}>
<div className="min-h-screen bg-gray-50">
<div className="p-6">
<Outlet></Outlet>
</div>
</div>
</PostFormProvider>
</>
);
}

View File

@ -20,6 +20,7 @@ import CourseContentForm from "../components/models/course/editor/form/CourseCon
import { CourseGoalForm } from "../components/models/course/editor/form/CourseGoalForm";
import CourseSettingForm from "../components/models/course/editor/form/CourseSettingForm";
import CourseEditorLayout from "../components/models/course/editor/layout/CourseEditorLayout";
import PostEditorLayout from "../components/models/post/PostEditor/layout/PostEditorLayout";
interface CustomIndexRouteObject extends IndexRouteObject {
name?: string;
@ -57,8 +58,22 @@ export const routes: CustomRouteObject[] = [
{
index: true,
element: <HomePage />,
}
},
],
},
{
path: "post",
children: [
{
path: ":id?/editor",
element: <PostEditorLayout></PostEditorLayout>,
children: [
{
index: true,
element: <CourseBasicForm></CourseBasicForm>,
},
],
},
],
},
{
@ -67,24 +82,29 @@ export const routes: CustomRouteObject[] = [
{
path: ":id?/editor",
element: <CourseEditorLayout></CourseEditorLayout>,
children: [{
index: true,
element: <CourseBasicForm></CourseBasicForm>
},
{
path: 'goal',
element: <CourseGoalForm></CourseGoalForm>
},
{
path: 'content',
element: <CourseContentForm></CourseContentForm>
},
{
path: 'setting',
element: <CourseSettingForm></CourseSettingForm>
}
]
}
children: [
{
index: true,
element: <CourseBasicForm></CourseBasicForm>,
},
{
path: "goal",
element: <CourseGoalForm></CourseGoalForm>,
},
{
path: "content",
element: (
<CourseContentForm></CourseContentForm>
),
},
{
path: "setting",
element: (
<CourseSettingForm></CourseSettingForm>
),
},
],
},
],
},
{