add
This commit is contained in:
parent
74b618e0c1
commit
5b4953665c
|
@ -0,0 +1,196 @@
|
||||||
|
import {
|
||||||
|
DragOutlined,
|
||||||
|
CaretRightOutlined,
|
||||||
|
SaveOutlined,
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import { Form, Button, Input, Select, Space } from "antd";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useSortable } 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 { LectureType, LessonTypeLabel, PostType } from "@nice/common";
|
||||||
|
import { usePost } from "@nice/client";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
import { LectureData } from "./interface";
|
||||||
|
|
||||||
|
interface SortableLectureProps {
|
||||||
|
field: LectureData;
|
||||||
|
remove: () => void;
|
||||||
|
sectionFieldKey: string;
|
||||||
|
}
|
||||||
|
export const SortableLecture: React.FC<SortableLectureProps> = ({
|
||||||
|
field,
|
||||||
|
remove,
|
||||||
|
sectionFieldKey,
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
attributes,
|
||||||
|
listeners,
|
||||||
|
setNodeRef,
|
||||||
|
transform,
|
||||||
|
transition,
|
||||||
|
isDragging,
|
||||||
|
} = useSortable({ id: field?.id });
|
||||||
|
const { create, update } = usePost();
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [editing, setEditing] = useState(field?.id ? false : true);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const lectureType =
|
||||||
|
Form.useWatch(["meta", "type"], form) || LectureType.ARTICLE;
|
||||||
|
const handleSave = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const values = await form.validateFields();
|
||||||
|
let result;
|
||||||
|
|
||||||
|
if (!field.id) {
|
||||||
|
result = await create.mutateAsync({
|
||||||
|
data: {
|
||||||
|
parentId: sectionFieldKey,
|
||||||
|
type: PostType.LECTURE,
|
||||||
|
title: values?.title,
|
||||||
|
meta: {
|
||||||
|
type: values?.meta?.type,
|
||||||
|
fileIds: values?.meta?.fileIds,
|
||||||
|
},
|
||||||
|
resources: {
|
||||||
|
connect: (values?.meta?.fileIds || []).map(
|
||||||
|
(fileId) => ({
|
||||||
|
fileId,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
},
|
||||||
|
content: values?.content,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result = await update.mutateAsync({
|
||||||
|
where: {
|
||||||
|
id: field?.id,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
title: values?.title,
|
||||||
|
meta: {
|
||||||
|
type: values?.meta?.type,
|
||||||
|
fieldIds: values?.meta?.fileIds,
|
||||||
|
},
|
||||||
|
resources: {
|
||||||
|
connect: (values?.meta?.fileIds || []).map(
|
||||||
|
(fileId) => ({
|
||||||
|
fileId,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
},
|
||||||
|
content: values?.content,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
toast.success("课时已更新");
|
||||||
|
field.id = result.id;
|
||||||
|
setEditing(false);
|
||||||
|
} catch (err) {
|
||||||
|
toast.success("更新失败");
|
||||||
|
console.log(err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
transform: CSS.Transform.toString(transform),
|
||||||
|
transition,
|
||||||
|
borderBottom: "1px solid #f0f0f0",
|
||||||
|
backgroundColor: isDragging ? "#f5f5f5" : undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={setNodeRef} style={style} className="p-4">
|
||||||
|
{editing ? (
|
||||||
|
<Form form={form} initialValues={field}>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<Form.Item
|
||||||
|
name="title"
|
||||||
|
initialValue={field?.title}
|
||||||
|
className="mb-0 flex-1"
|
||||||
|
rules={[{ required: true }]}>
|
||||||
|
<Input placeholder="课时标题" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name={["meta", "type"]}
|
||||||
|
className="mb-0 w-32"
|
||||||
|
rules={[{ required: true }]}>
|
||||||
|
<Select
|
||||||
|
placeholder="选择类型"
|
||||||
|
options={[
|
||||||
|
{ label: "视频", value: LectureType.VIDEO },
|
||||||
|
{
|
||||||
|
label: "文章",
|
||||||
|
value: LectureType.ARTICLE,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4 flex flex-1 ">
|
||||||
|
{lectureType === LectureType.VIDEO ? (
|
||||||
|
<Form.Item
|
||||||
|
name={["meta", "fileIds"]}
|
||||||
|
className="mb-0 flex-1"
|
||||||
|
rules={[{ required: true }]}>
|
||||||
|
<TusUploader multiple={false} />
|
||||||
|
</Form.Item>
|
||||||
|
) : (
|
||||||
|
<Form.Item
|
||||||
|
name="content"
|
||||||
|
className="mb-0 flex-1"
|
||||||
|
rules={[{ required: true }]}>
|
||||||
|
<QuillEditor />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 flex justify-end gap-2">
|
||||||
|
<Button
|
||||||
|
onClick={handleSave}
|
||||||
|
loading={loading}
|
||||||
|
type="primary"
|
||||||
|
icon={<SaveOutlined />}>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setEditing(false);
|
||||||
|
if (!field?.id) {
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Space>
|
||||||
|
<DragOutlined
|
||||||
|
{...attributes}
|
||||||
|
{...listeners}
|
||||||
|
className="cursor-move"
|
||||||
|
/>
|
||||||
|
<CaretRightOutlined />
|
||||||
|
<span>{LessonTypeLabel[field?.meta?.type]}</span>
|
||||||
|
<span>{field?.title || "未命名课时"}</span>
|
||||||
|
</Space>
|
||||||
|
<Space>
|
||||||
|
<Button type="link" onClick={() => setEditing(true)}>
|
||||||
|
编辑
|
||||||
|
</Button>
|
||||||
|
<Button type="link" danger onClick={remove}>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue