ariyamaggika пре 3 година
родитељ
комит
1f0f1cd426

+ 1 - 0
cpp/out/build/x64-Debug/VSInheritEnvironments.txt

@@ -0,0 +1 @@
+msvc_x64_x64

+ 76 - 0
dashboard/src/components/library/course/AddLesson.tsx

@@ -0,0 +1,76 @@
+import { useIntl } from "react-intl";
+import {
+  ProForm,
+  ProFormSelect,
+  ProFormText,
+} from "@ant-design/pro-components";
+import { Button, message, Popover } from "antd";
+import { UserAddOutlined } from "@ant-design/icons";
+import { get } from "../../../request";
+
+import { IUserListResponse } from "../../api/Auth";
+
+interface IFormData {
+  userId: string;
+}
+
+interface IWidget {
+  groupId?: string;
+}
+const Widget = ({ groupId }: IWidget) => {
+  const intl = useIntl();
+
+  const form = (
+    <ProForm<IFormData>
+      onFinish={async (values: IFormData) => {
+        // TODO
+        console.log(values);
+        message.success(intl.formatMessage({ id: "flashes.success" }));
+      }}
+    >
+      <ProForm.Group>
+        <ProFormSelect
+          name="userId"
+          label={intl.formatMessage({ id: "forms.fields.user.label" })}
+          showSearch
+          debounceTime={300}
+          request={async ({ keyWord }) => {
+            console.log("keyWord", keyWord);
+            const json = await get<IUserListResponse>(`/v2/user?view=key&key=`);
+            const userList = json.data.rows.map((item) => {
+              return {
+                value: item.id,
+                label: `${item.userName}-${item.nickName}`,
+              };
+            });
+            console.log("json", userList);
+            return userList;
+          }}
+          placeholder={intl.formatMessage({ id: "forms.fields.user.required" })}
+          rules={[
+            {
+              required: true,
+              message: intl.formatMessage({
+                id: "forms.message.user.required",
+              }),
+            },
+          ]}
+        />
+      </ProForm.Group>
+    </ProForm>
+  );
+  return (
+    <Popover
+      placement="bottom"
+      arrowPointAtCenter
+      content={form}
+      trigger="click"
+    >
+      <Button icon={<UserAddOutlined />} key="add" type="primary">
+        {intl.formatMessage({ id: "buttons.lesson.add.lesson" })}
+      </Button>
+    </Popover>
+  );
+};
+
+export default Widget;

+ 86 - 0
dashboard/src/components/library/course/AddStudent.tsx

@@ -0,0 +1,86 @@
+import { useIntl } from "react-intl";
+import {
+  ProForm,
+  ProFormSelect,
+  ProFormText,
+} from "@ant-design/pro-components";
+import { Button, message, Popover, MenuProps } from "antd";
+import { UserAddOutlined } from "@ant-design/icons";
+import { get } from "../../../request";
+
+import { IUserListResponse } from "../../api/Auth";
+
+interface IFormData {
+  userId: string;
+}
+
+interface IWidget {
+  groupId?: string;
+}
+
+const Widget = ({ groupId }: IWidget) => {
+  const intl = useIntl();
+
+  const form = (
+    <ProForm<IFormData>
+      onFinish={async (values: IFormData) => {
+        // TODO
+        console.log(values);
+        message.success(intl.formatMessage({ id: "flashes.success" }));
+      }}
+    >
+      <ProForm.Group>
+        <ProFormSelect
+          name="userId"
+          label={intl.formatMessage({ id: "forms.fields.user.label" })}
+          showSearch
+          debounceTime={300}
+          request={async ({ keyWord }) => {
+            console.log("keyWord", keyWord);
+            const json = await get<IUserListResponse>(`/v2/user?view=key&key=`);
+            const userList = json.data.rows.map((item) => {
+              return {
+                value: item.id,
+                label: `${item.userName}-${item.nickName}`,
+              };
+            });
+            console.log("json", userList);
+            return userList;
+          }}
+          placeholder={intl.formatMessage({ id: "forms.fields.user.required" })}
+          rules={[
+            {
+              required: true,
+              message: intl.formatMessage({
+                id: "forms.message.user.required",
+              }),
+            },
+          ]}
+        />
+        <ProFormSelect
+          colProps={{ xl: 8, md: 12 }}
+          name="userType"
+          label={intl.formatMessage({ id: "forms.fields.type.label" })}
+          valueEnum={{
+            1: intl.formatMessage({ id: "forms.fields.students.label" }),
+            2: intl.formatMessage({ id: "forms.fields.assistant.label" }),
+          }}
+        />
+      </ProForm.Group>
+    </ProForm>
+  );
+  return (
+    <Popover
+      placement="bottom"
+      arrowPointAtCenter
+      content={form}
+      trigger="click"
+    >
+      <Button icon={<UserAddOutlined />} key="add" type="primary">
+        {intl.formatMessage({ id: "buttons.group.add.member" })}
+      </Button>
+    </Popover>
+  );
+};
+
+export default Widget;

+ 76 - 0
dashboard/src/components/library/course/AddTeacher.tsx

@@ -0,0 +1,76 @@
+import { useIntl } from "react-intl";
+import {
+  ProForm,
+  ProFormSelect,
+  ProFormText,
+} from "@ant-design/pro-components";
+import { Button, message, Popover } from "antd";
+import { UserAddOutlined } from "@ant-design/icons";
+import { get } from "../../../request";
+
+import { IUserListResponse } from "../../api/Auth";
+
+interface IFormData {
+  userId: string;
+}
+
+interface IWidget {
+  groupId?: string;
+}
+const Widget = ({ groupId }: IWidget) => {
+  const intl = useIntl();
+
+  const form = (
+    <ProForm<IFormData>
+      onFinish={async (values: IFormData) => {
+        // TODO
+        console.log(values);
+        message.success(intl.formatMessage({ id: "flashes.success" }));
+      }}
+    >
+      <ProForm.Group>
+        <ProFormSelect
+          name="userId"
+          label={intl.formatMessage({ id: "forms.fields.user.label" })}
+          showSearch
+          debounceTime={300}
+          request={async ({ keyWord }) => {
+            console.log("keyWord", keyWord);
+            const json = await get<IUserListResponse>(`/v2/user?view=key&key=`);
+            const userList = json.data.rows.map((item) => {
+              return {
+                value: item.id,
+                label: `${item.userName}-${item.nickName}`,
+              };
+            });
+            console.log("json", userList);
+            return userList;
+          }}
+          placeholder={intl.formatMessage({ id: "forms.fields.user.required" })}
+          rules={[
+            {
+              required: true,
+              message: intl.formatMessage({
+                id: "forms.message.user.required",
+              }),
+            },
+          ]}
+        />
+      </ProForm.Group>
+    </ProForm>
+  );
+  return (
+    <Popover
+      placement="bottom"
+      arrowPointAtCenter
+      content={form}
+      trigger="click"
+    >
+      <Button icon={<UserAddOutlined />} key="add" type="primary">
+        {intl.formatMessage({ id: "buttons.group.add.member" })}
+      </Button>
+    </Popover>
+  );
+};
+
+export default Widget;

+ 82 - 0
dashboard/src/components/library/course/LessonSelect.tsx

@@ -0,0 +1,82 @@
+//选择讲师组件
+
+import { useIntl } from "react-intl";
+import { useState } from "react";
+import { ProList } from "@ant-design/pro-components";
+import { UserAddOutlined } from "@ant-design/icons";
+import { Space, Tag, Button, Layout } from "antd";
+import AddLesson from "./AddLesson";
+
+const { Content } = Layout;
+
+const defaultData = [
+  {
+    id: "1",
+    name: "lesson0",
+    //tag: [{ title: "管理员", color: "success" }],
+    //image:
+    //  "https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg",
+  },
+];
+type DataItem = typeof defaultData[number];
+interface IWidgetGroupFile {
+  groupId?: string;
+}
+const Widget = ({ groupId }: IWidgetGroupFile) => {
+  const intl = useIntl(); //i18n
+  const [dataSource, setDataSource] = useState<DataItem[]>(defaultData);
+
+  return (
+    <Content>
+      <Space>{groupId}</Space>
+      <ProList<DataItem>
+        rowKey="id"
+        headerTitle={intl.formatMessage({ id: "forms.fields.lesson.label" })}
+        toolBarRender={() => {
+          return [<AddLesson groupId={groupId} />];
+        }}
+        dataSource={dataSource}
+        showActions="hover"
+        onDataSourceChange={setDataSource}
+        metas={{
+          title: {
+            dataIndex: "name",
+          },
+          avatar: {
+            dataIndex: "image",
+            editable: false,
+          },
+          // subTitle: {
+          //   render: (text, row, index, action) => {
+          //     const showtag = row.tag.map((item, id) => {
+          //       return (
+          //         <Tag color={item.color} key={id}>
+          //           {item.title}
+          //         </Tag>
+          //       );
+          //     });
+          //     return <Space size={0}>{showtag}</Space>;
+          //   },
+          // },
+          actions: {
+            render: (text, row, index, action) => [
+              <Button
+                style={{ padding: 0, margin: 0 }}
+                type="link"
+                danger
+                onClick={() => {
+                  action?.startEditable(row.id);
+                }}
+                key="link"
+              >
+                {intl.formatMessage({ id: "buttons.remove" })}
+              </Button>,
+            ],
+          },
+        }}
+      />
+    </Content>
+  );
+};
+
+export default Widget;

+ 55 - 0
dashboard/src/components/library/course/LessonTreeShow.tsx

@@ -0,0 +1,55 @@
+//上传封面组件
+import React, { useState } from "react";
+import { LoadingOutlined, PlusOutlined } from "@ant-design/icons";
+import { message, Upload, Tree } from "antd";
+import type { UploadChangeParam } from "antd/es/upload";
+import type { RcFile, UploadFile, UploadProps } from "antd/es/upload/interface";
+
+import type { DataNode } from "antd/es/tree";
+/*
+const dig = (path = "0", level = 3) => {
+  const list = [];
+  for (let i = 0; i < 10; i += 1) {
+    const key = `a-${i}`;
+    const treeNode: DataNode = {
+      title: key,
+      key,
+    };
+
+    if (level > 0) {
+      treeNode.children = dig(key, level - 1);
+    }
+
+    list.push(treeNode);
+  }
+  return list;
+};
+
+const treeData = dig();
+*/
+const treeData: DataNode[] = [
+  {
+    title: "课程1",
+    key: "0-0",
+    children: [
+      { title: "课程1-0", key: "0-0-0", isLeaf: true },
+      { title: "课程1-1", key: "0-0-1", isLeaf: true },
+      { title: "课程1-2", key: "0-0-2", isLeaf: true },
+      { title: "课程1-3", key: "0-0-3", isLeaf: true },
+    ],
+  },
+  {
+    title: "课程2",
+    key: "0-1",
+    children: [
+      { title: "课程2-0", key: "0-1-0", isLeaf: true },
+      { title: "课程2-1", key: "0-1-1", isLeaf: true },
+      { title: "课程2-2", key: "0-1-2", isLeaf: true },
+    ],
+  },
+];
+const Widget = () => {
+  return <Tree treeData={treeData} height={233} defaultExpandAll />;
+};
+
+export default Widget;

+ 98 - 0
dashboard/src/components/library/course/StudentsSelect.tsx

@@ -0,0 +1,98 @@
+//选择讲师组件
+
+import { useIntl } from "react-intl";
+import { useState } from "react";
+import { ProList } from "@ant-design/pro-components";
+import { UserAddOutlined } from "@ant-design/icons";
+import { Space, Tag, Button, Layout } from "antd";
+import AddStudent from "./AddStudent";
+
+const { Content } = Layout;
+
+const defaultData = [
+  {
+    id: "1",
+    name: "小僧善巧",
+    tag: [{ title: "助教", color: "success" }],
+    image:
+      "https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg",
+  },
+  {
+    id: "2",
+    name: "学员1",
+    tag: [{ title: "学员", color: "blue" }],
+    image:
+      "https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg",
+  },
+  {
+    id: "3",
+    name: "学员2",
+    tag: [{ title: "学员", color: "blue" }],
+    image:
+      "https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg",
+  },
+];
+type DataItem = typeof defaultData[number];
+interface IWidgetGroupFile {
+  groupId?: string;
+}
+const Widget = ({ groupId }: IWidgetGroupFile) => {
+  const intl = useIntl(); //i18n
+  const [dataSource, setDataSource] = useState<DataItem[]>(defaultData);
+
+  return (
+    <Content>
+      <Space>{groupId}</Space>
+      <ProList<DataItem>
+        rowKey="id"
+        headerTitle={intl.formatMessage({
+          id: "forms.fields.studentsassistant.label",
+        })}
+        toolBarRender={() => {
+          return [<AddStudent groupId={groupId} />];
+        }}
+        dataSource={dataSource}
+        showActions="hover"
+        onDataSourceChange={setDataSource}
+        metas={{
+          title: {
+            dataIndex: "name",
+          },
+          avatar: {
+            dataIndex: "image",
+            editable: false,
+          },
+          subTitle: {
+            render: (text, row, index, action) => {
+              const showtag = row.tag.map((item, id) => {
+                return (
+                  <Tag color={item.color} key={id}>
+                    {item.title}
+                  </Tag>
+                );
+              });
+              return <Space size={0}>{showtag}</Space>;
+            },
+          },
+          actions: {
+            render: (text, row, index, action) => [
+              <Button
+                style={{ padding: 0, margin: 0 }}
+                type="link"
+                danger
+                onClick={() => {
+                  action?.startEditable(row.id);
+                }}
+                key="link"
+              >
+                {intl.formatMessage({ id: "buttons.remove" })}
+              </Button>,
+            ],
+          },
+        }}
+      />
+    </Content>
+  );
+};
+
+export default Widget;

+ 82 - 0
dashboard/src/components/library/course/TeacherSelect.tsx

@@ -0,0 +1,82 @@
+//选择讲师组件
+
+import { useIntl } from "react-intl";
+import { useState } from "react";
+import { ProList } from "@ant-design/pro-components";
+import { UserAddOutlined } from "@ant-design/icons";
+import { Space, Tag, Button, Layout } from "antd";
+import AddTeacher from "./AddTeacher";
+
+const { Content } = Layout;
+
+const defaultData = [
+  {
+    id: "1",
+    name: "小僧善巧",
+    tag: [{ title: "管理员", color: "success" }],
+    image:
+      "https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg",
+  },
+];
+type DataItem = typeof defaultData[number];
+interface IWidgetGroupFile {
+  groupId?: string;
+}
+const Widget = ({ groupId }: IWidgetGroupFile) => {
+  const intl = useIntl(); //i18n
+  const [dataSource, setDataSource] = useState<DataItem[]>(defaultData);
+
+  return (
+    <Content>
+      <Space>{groupId}</Space>
+      <ProList<DataItem>
+        rowKey="id"
+        headerTitle={intl.formatMessage({ id: "forms.fields.teacher.label" })}
+        toolBarRender={() => {
+          return [<AddTeacher groupId={groupId} />];
+        }}
+        dataSource={dataSource}
+        showActions="hover"
+        onDataSourceChange={setDataSource}
+        metas={{
+          title: {
+            dataIndex: "name",
+          },
+          avatar: {
+            dataIndex: "image",
+            editable: false,
+          },
+          subTitle: {
+            render: (text, row, index, action) => {
+              const showtag = row.tag.map((item, id) => {
+                return (
+                  <Tag color={item.color} key={id}>
+                    {item.title}
+                  </Tag>
+                );
+              });
+              return <Space size={0}>{showtag}</Space>;
+            },
+          },
+          actions: {
+            render: (text, row, index, action) => [
+              <Button
+                style={{ padding: 0, margin: 0 }}
+                type="link"
+                danger
+                onClick={() => {
+                  action?.startEditable(row.id);
+                }}
+                key="link"
+              >
+                {intl.formatMessage({ id: "buttons.remove" })}
+              </Button>,
+            ],
+          },
+        }}
+      />
+    </Content>
+  );
+};
+
+export default Widget;

+ 66 - 0
dashboard/src/components/library/course/UploadTexture.tsx

@@ -0,0 +1,66 @@
+//上传封面组件
+import React, { useState } from 'react';
+import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
+import { message, Upload } from 'antd';
+import type { UploadChangeParam } from 'antd/es/upload';
+import type { RcFile, UploadFile, UploadProps } from 'antd/es/upload/interface';
+
+const getBase64 = (img: RcFile, callback: (url: string) => void) => {
+  const reader = new FileReader();
+  reader.addEventListener('load', () => callback(reader.result as string));
+  reader.readAsDataURL(img);
+};
+
+const beforeUpload = (file: RcFile) => {
+  const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
+  if (!isJpgOrPng) {
+    message.error('You can only upload JPG/PNG file!');
+  }
+  const isLt2M = file.size / 1024 / 1024 < 2;
+  if (!isLt2M) {
+    message.error('Image must smaller than 2MB!');
+  }
+  return isJpgOrPng && isLt2M;
+};
+
+const Widget = () => {
+  const [loading, setLoading] = useState(false);
+  const [imageUrl, setImageUrl] = useState<string>();
+
+  const handleChange: UploadProps['onChange'] = (info: UploadChangeParam<UploadFile>) => {
+    if (info.file.status === 'uploading') {
+      setLoading(true);
+      return;
+    }
+    if (info.file.status === 'done') {
+      // Get this url from response in real world.
+      getBase64(info.file.originFileObj as RcFile, (url) => {
+        setLoading(false);
+        setImageUrl(url);
+      });
+    }
+  };
+
+  const uploadButton = (
+    <div>
+      {loading ? <LoadingOutlined /> : <PlusOutlined />}
+      <div style={{ marginTop: 8 }}>Upload</div>
+    </div>
+  );
+
+  return (
+    <Upload
+      name="avatar"
+      listType="picture-card"
+      className="avatar-uploader"
+      showUploadList={false}
+      action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
+      beforeUpload={beforeUpload}
+      onChange={handleChange}
+    >
+      {imageUrl ? <img src={imageUrl} alt="avatar" style={{ width: '100%' }} /> : uploadButton}
+    </Upload>
+  );
+};
+
+export default Widget;

+ 1 - 0
dashboard/src/locales/zh-Hans/buttons.ts

@@ -22,6 +22,7 @@ const items = {
   "buttons.click.upload": "点击上传",
   "buttons.group.exit": "退群",
   "buttons.group.add.member": "加人",
+  "buttons.lesson.add.lesson": "加入",
 };
 
 export default items;

+ 6 - 0
dashboard/src/locales/zh-Hans/forms.ts

@@ -21,6 +21,10 @@ const items = {
   "forms.fields.publicity.private.label": "私有",
   "forms.fields.publicity.public.label": "公开",
   "forms.fields.teacher.label": "主讲人",
+  "forms.fields.studentsassistant.label": "学生与助教",
+  "forms.fields.students.label": "学生",
+  "forms.fields.assistant.label": "助教",
+  "forms.fields.lesson.label": "讲",
   "forms.fields.note.label": "注解",
   "forms.fields.confidence.label": "信心指数",
   "forms.fields.confidence.0.label": "不靠谱",
@@ -28,6 +32,8 @@ const items = {
   "forms.fields.confidence.50.label": "一般",
   "forms.fields.confidence.75.label": "还可以",
   "forms.fields.confidence.100.label": "有把握",
+  "forms.fields.upload.texture": "上传封面",
+  "forms.fields.markdown.label": "markdown效果预览",
   "forms.fields.role.label": "角色",
   "forms.fields.name.label": "名称",
   "forms.fields.meaning.label": "意思",

+ 1 - 1
dashboard/src/pages/library/course/course.tsx

@@ -75,4 +75,4 @@ export default Widget;
       </div>
     </div>
   );
-*/
+*/

+ 241 - 0
dashboard/src/pages/studio/course/edit.tsx

@@ -0,0 +1,241 @@
+import { useState } from "react";
+import { useParams } from "react-router-dom";
+import { useIntl, FormattedMessage } from "react-intl";
+import {
+  ProForm,
+  ProFormText,
+  ProFormTextArea,
+  ProFormDateRangePicker,
+} from "@ant-design/pro-components";
+import { Card, message, Col, Row, Divider, Tabs } from "antd";
+import { get, put } from "../../../request";
+import { marked } from "marked";
+import {
+  ICourseDataRequest,
+  ICourseResponse,
+} from "../../../components/api/Course";
+import PublicitySelect from "../../../components/studio/PublicitySelect";
+import GoBack from "../../../components/studio/GoBack";
+import UploadTexture from "../../../components/library/course/UploadTexture";
+import TeacherSelect from "../../../components/library/course/TeacherSelect";
+import StudentsSelect from "../../../components/library/course/StudentsSelect";
+import LessonSelect from "../../../components/library/course/LessonSelect";
+import LessonTreeShow from "../../../components/library/course/LessonTreeShow";
+
+interface IFormData {
+  uid: string;
+  title: string;
+
+  t_type: string;
+  status: number;
+  lang: string;
+}
+const onChange = (key: string) => {
+  console.log(key);
+};
+let groupid = "1";
+
+const Widget = () => {
+  const intl = useIntl();
+  const { studioname, courseid } = useParams(); //url 参数
+  const [title, setTitle] = useState("loading");
+
+  return (
+    <Tabs
+      onChange={onChange}
+      type="card"
+      items={[
+        {
+          label: `基本信息`,
+          key: "1",
+          children: (
+            <Card
+              title={
+                <GoBack
+                  to={`/studio/${studioname}/course/list`}
+                  title={title}
+                />
+              }
+            >
+              <ProForm<IFormData>
+                onFinish={async (values: IFormData) => {
+                  // TODO
+                  let request = {
+                    uid: courseid?.toString,
+                    title: "课程" + courseid,
+                    subtitle: "课程副标题" + courseid,
+                    teacher: 1,
+                    course_count: 2,
+                    type: 30,
+                    created_at: "",
+                    updated_at: "",
+                    article_id: 1, //"1e642dac-dcb2-468a-8cc7-0228e5ca6ac4",
+                    course_start_at: "", //课程开始时间
+                    course_end_at: "", //课程结束时间
+                    intro_markdown: "", //简介
+                    cover_img_name: "", //封面图片文件名
+                  };
+                }}
+                /*		    const request = {
+    uid: courseid ? courseid : "",
+    title: values.title,
+    subtitle: values.subtitle,
+    teacher: values.teacher,//UserID
+    course_count: values.course_count,//课程数
+    type: values.type,//类型-公开/内部
+    created_at: values.created_at,//创建时间
+    updated_at: values.updated_at,//修改时间
+    article_id: values.article_id,//文集ID
+    course_start_at: values.course_start_at,//课程开始时间
+    course_end_at: values.course_end_at,//课程结束时间
+    intro_markdown: values.intro_markdown,//简介
+    cover_img_name: values.cover_img_name,//封面图片文件名
+  };
+  console.log(request);
+  const res = await put<ICourseDataRequest, ICourseResponse>(
+    `/v2/course/${courseid}`,
+    request
+  );
+  console.log(res);
+  if (res.ok) {
+    message.success(intl.formatMessage({ id: "flashes.success" }));
+  } else {
+    message.error(res.message);
+  }
+}}
+request={async () => {
+  const res = await get<ICourseResponse>(`/v2/course/${courseid}`);
+  setTitle(res.data.title);
+  return {
+    uid: res.data.uid,
+    title: res.data.title,
+    subtitle: res.data.subtitle,
+    summary: res.data.summary,
+    content: res.data.content,
+    content_type: res.data.content_type,
+    lang: res.data.lang,
+    status: res.data.status,
+  };
+}}*/
+              >
+                <ProForm.Group>
+                  <ProFormText
+                    width="md"
+                    name="title"
+                    required
+                    label={intl.formatMessage({
+                      id: "forms.fields.title.label",
+                    })}
+                    rules={[
+                      {
+                        required: true,
+                        message: intl.formatMessage({
+                          id: "forms.message.title.required",
+                        }),
+                      },
+                    ]}
+                  />
+                </ProForm.Group>
+                <ProForm.Group>
+                  <ProFormText
+                    width="md"
+                    name="subtitle"
+                    label={intl.formatMessage({
+                      id: "forms.fields.subtitle.label",
+                    })}
+                  />
+                </ProForm.Group>
+                <ProForm.Group>
+                  <p style={{ fontWeight: "bold", fontSize: 15 }}>
+                    <FormattedMessage id="forms.fields.upload.texture" />{" "}
+                  </p>
+                  <UploadTexture />
+                </ProForm.Group>
+                <ProForm.Group>
+                  <ProFormDateRangePicker
+                    width="md"
+                    name={["contract", "createTime"]}
+                    label="课程区间"
+                  />
+                </ProForm.Group>
+                <ProForm.Group>
+                  <PublicitySelect />
+                </ProForm.Group>
+                <Divider />
+
+                <Row>
+                  <Col flex="400px">
+                    <TeacherSelect groupId={groupid} />
+                  </Col>
+                </Row>
+                <Divider />
+                <Row>
+                  <Col flex="400px">
+                    <LessonSelect groupId={groupid} />
+                  </Col>
+                </Row>
+                <Divider />
+                <ProForm.Group>
+                  <ProFormTextArea
+                    name="summary"
+                    width="md"
+                    label={intl.formatMessage({
+                      id: "forms.fields.summary.label",
+                    })}
+                  />
+
+                  <p style={{ fontWeight: "bold", fontSize: 15 }}>
+                    <FormattedMessage id="forms.fields.markdown.label" />{" "}
+                  </p>
+                  <Row>
+                    <div
+                      dangerouslySetInnerHTML={{
+                        __html: marked.parse(
+                          "# 这是标题\n" +
+                            "[ **M** ] arkdown + E [ **ditor** ] = **Mditor**  \n" +
+                            "**这是加粗的文字**\n\n" +
+                            "*这是倾斜的文字*`\n\n" +
+                            "***这是斜体加粗的文字***\n\n" +
+                            "~~这是加删除线的文字~~ \n\n"
+                        ),
+                      }}
+                    ></div>
+                  </Row>
+                </ProForm.Group>
+              </ProForm>
+            </Card>
+          ),
+        },
+        {
+          label: `学生与助教选择 `,
+          key: "2",
+          children: (
+            <Card
+              title={
+                <GoBack
+                  to={`/studio/${studioname}/course/list`}
+                  title={title}
+                />
+              }
+            >
+              <ProForm<IFormData> onFinish={async (values: IFormData) => {}}>
+                <ProForm.Group>
+                  <LessonTreeShow />
+                </ProForm.Group>
+                <ProForm.Group></ProForm.Group>
+
+                <Row>
+                  <Col flex="400px">
+                    <StudentsSelect groupId={groupid} />
+                  </Col>
+                </Row>
+              </ProForm>
+            </Card>
+          ),
+        },
+      ]}
+    />
+  );
+};
+
+export default Widget;