diff --git a/apps/web/src/components/models/course/editor/form/CourseContentForm/SortableSection.tsx b/apps/web/src/components/models/course/editor/form/CourseContentForm/SortableSection.tsx new file mode 100644 index 0000000..020d944 --- /dev/null +++ b/apps/web/src/components/models/course/editor/form/CourseContentForm/SortableSection.tsx @@ -0,0 +1,182 @@ +import { + PlusOutlined, + DragOutlined, + DeleteOutlined, + CaretRightOutlined, + SaveOutlined, +} from "@ant-design/icons"; +import { + Form, + Alert, + Button, + Input, + Select, + Space, + Collapse, + message, +} from "antd"; +import React, { useCallback, useEffect, useState } from "react"; +import { + DndContext, + closestCenter, + KeyboardSensor, + PointerSensor, + useSensor, + useSensors, + DragEndEvent, +} from "@dnd-kit/core"; +import { api, emitDataChange } from "@nice/client"; +import { + arrayMove, + SortableContext, + sortableKeyboardCoordinates, + useSortable, + verticalListSortingStrategy, +} from "@dnd-kit/sortable"; +import { CSS } from "@dnd-kit/utilities"; +import QuillEditor from "@web/src/components/common/editor/quill/QuillEditor"; +import { TusUploader } from "@web/src/components/common/uploader/TusUploader"; +import { Lecture, LectureType, PostType } from "@nice/common"; +import { useCourseEditor } from "../../context/CourseEditorContext"; +import { usePost } from "@nice/client"; +import toast from "react-hot-toast"; +import { CourseContentFormHeader } from "./CourseContentFormHeader"; +import { CourseSectionEmpty } from "./CourseSectionEmpty"; +import { LectureData, SectionData } from "./interface"; +interface SortableSectionProps { + courseId?: string; + field: SectionData; + remove: () => void; + children: React.ReactNode; +} + +export const SortableSection: React.FC = ({ + field, + remove, + courseId, + children, +}) => { + const { + attributes, + listeners, + setNodeRef, + transform, + transition, + isDragging, + } = useSortable({ id: field?.id }); + + const [form] = Form.useForm(); + const [editing, setEditing] = useState(field.id ? false : true); + const [loading, setLoading] = useState(false); + const { create, update } = usePost(); + + const handleSave = async () => { + if (!courseId) { + toast.error("课程未创建,请先填写课程基本信息完成创建"); + return; + } + try { + setLoading(true); + const values = await form.validateFields(); + let result; + try { + if (!field?.id) { + result = await create.mutateAsync({ + data: { + title: values?.title, + type: PostType.SECTION, + parentId: courseId, + }, + }); + } else { + result = await update.mutateAsync({ + data: { + title: values?.title, + }, + }); + } + } catch (err) { + console.log(err); + } + + field.id = result.id; + setEditing(false); + message.success("保存成功"); + } catch (error) { + console.log(error); + message.error("保存失败"); + } finally { + setLoading(false); + } + }; + + const style = { + transform: CSS.Transform.toString(transform), + transition, + backgroundColor: isDragging ? "#f5f5f5" : undefined, + }; + + return ( +
+ + + + + + + + + + + ) : ( +
+ + + {field.title || "未命名章节"} + + + + + +
+ ) + } + key={field.id || "new"}> + {children} +
+
+
+ ); +};