visuddhinanda 2 سال پیش
والد
کامیت
3bcc177d60

+ 82 - 0
dashboard/src/components/course/AcceptCourse.tsx

@@ -0,0 +1,82 @@
+/**
+ * 学生接受课程管理员的邀请 参加课程
+ */
+import { Button, message, Modal, Typography } from "antd";
+import { useIntl } from "react-intl";
+import { ExclamationCircleFilled } from "@ant-design/icons";
+
+import { delete_, put } from "../../request";
+import {
+  ICourseMemberData,
+  ICourseMemberDeleteResponse,
+  ICourseMemberResponse,
+  TCourseJoinMode,
+  TCourseMemberStatus,
+} from "../api/Course";
+
+const { confirm } = Modal;
+const { Text } = Typography;
+
+interface IWidget {
+  joinMode?: TCourseJoinMode;
+  currUser?: ICourseMemberData;
+  onStatusChanged?: Function;
+}
+const AcceptCourseWidget = ({
+  joinMode,
+  currUser,
+  onStatusChanged,
+}: IWidget) => {
+  const intl = useIntl();
+
+  const statusChange = (status: ICourseMemberData | undefined) => {
+    if (typeof onStatusChanged !== "undefined") {
+      onStatusChanged(status);
+    }
+  };
+  return (
+    <>
+      <Button
+        type="primary"
+        onClick={() => {
+          confirm({
+            title: "参加此课程吗?",
+            icon: <ExclamationCircleFilled />,
+            content: intl.formatMessage({
+              id: `course.join.mode.open.message`,
+            }),
+            onOk() {
+              return put<ICourseMemberData, ICourseMemberResponse>(
+                "/v2/course-member/" + currUser?.id,
+                {
+                  user_id: "",
+                  course_id: "",
+                  status: "accepted",
+                }
+              )
+                .then((json) => {
+                  console.log("leave", json);
+                  if (json.ok) {
+                    console.log("accepted", json.data);
+                    statusChange(json.data);
+                    message.success(
+                      intl.formatMessage({ id: "flashes.success" })
+                    );
+                  } else {
+                    message.error(json.message);
+                  }
+                })
+                .catch((error) => {
+                  message.error(error);
+                });
+            },
+          });
+        }}
+      >
+        参加
+      </Button>
+    </>
+  );
+};
+
+export default AcceptCourseWidget;

+ 82 - 0
dashboard/src/components/course/AcceptNotCourse.tsx

@@ -0,0 +1,82 @@
+/**
+ * 学生接受课程管理员的邀请 参加课程
+ */
+import { Button, message, Modal, Typography } from "antd";
+import { useIntl } from "react-intl";
+import { ExclamationCircleFilled } from "@ant-design/icons";
+
+import { delete_, put } from "../../request";
+import {
+  ICourseMemberData,
+  ICourseMemberDeleteResponse,
+  ICourseMemberResponse,
+  TCourseJoinMode,
+  TCourseMemberStatus,
+} from "../api/Course";
+
+const { confirm } = Modal;
+const { Text } = Typography;
+
+interface IWidget {
+  joinMode?: TCourseJoinMode;
+  currUser?: ICourseMemberData;
+  onStatusChanged?: Function;
+}
+const AcceptNotCourseWidget = ({
+  joinMode,
+  currUser,
+  onStatusChanged,
+}: IWidget) => {
+  const intl = useIntl();
+
+  const statusChange = (status: ICourseMemberData | undefined) => {
+    if (typeof onStatusChanged !== "undefined") {
+      onStatusChanged(status);
+    }
+  };
+  return (
+    <>
+      <Button
+        type="default"
+        onClick={() => {
+          confirm({
+            title: "拒绝参加此课程吗?",
+            icon: <ExclamationCircleFilled />,
+            content: intl.formatMessage({
+              id: "course.rejected.message",
+            }),
+            onOk() {
+              return put<ICourseMemberData, ICourseMemberResponse>(
+                "/v2/course-member/" + currUser?.id,
+                {
+                  user_id: "",
+                  course_id: "",
+                  status: "rejected",
+                }
+              )
+                .then((json) => {
+                  console.log("leave", json);
+                  if (json.ok) {
+                    console.log("rejected", json.data);
+                    statusChange(json.data);
+                    message.success(
+                      intl.formatMessage({ id: "flashes.success" })
+                    );
+                  } else {
+                    message.error(json.message);
+                  }
+                })
+                .catch((error) => {
+                  message.error(error);
+                });
+            },
+          });
+        }}
+      >
+        拒绝
+      </Button>
+    </>
+  );
+};
+
+export default AcceptNotCourseWidget;

+ 98 - 0
dashboard/src/components/course/SignUp.tsx

@@ -0,0 +1,98 @@
+/**
+ * 报名按钮
+ * 已经报名显示报名状态
+ * 未报名显示报名按钮以及必要的提示
+ */
+import { Button, message, Modal, Typography } from "antd";
+
+import { useIntl } from "react-intl";
+import { ExclamationCircleFilled } from "@ant-design/icons";
+
+import { useAppSelector } from "../../hooks";
+import { currentUser as _currentUser } from "../../reducers/current-user";
+import { post } from "../../request";
+import {
+  ICourseMemberData,
+  ICourseMemberResponse,
+  TCourseExpRequest,
+  TCourseJoinMode,
+} from "../api/Course";
+
+const { confirm } = Modal;
+const { Text } = Typography;
+
+interface IWidget {
+  courseId: string;
+  startAt?: string;
+  joinMode?: TCourseJoinMode;
+  expRequest?: TCourseExpRequest;
+  onStatusChanged?: Function;
+}
+const Widget = ({
+  courseId,
+  joinMode,
+  startAt,
+  expRequest,
+  onStatusChanged,
+}: IWidget) => {
+  const user = useAppSelector(_currentUser);
+  const intl = useIntl();
+
+  return (
+    <Button
+      type="primary"
+      onClick={() => {
+        confirm({
+          title: "你想要报名课程吗?",
+          icon: <ExclamationCircleFilled />,
+          content: (
+            <div>
+              <div>
+                {intl.formatMessage({
+                  id: `course.join.mode.${joinMode}.message`,
+                })}
+              </div>
+              <Text type="danger">
+                {intl.formatMessage({
+                  id: `course.exp.request.${expRequest}.message`,
+                })}
+              </Text>
+            </div>
+          ),
+          onOk() {
+            return post<ICourseMemberData, ICourseMemberResponse>(
+              "/v2/course-member",
+              {
+                user_id: user?.id ? user?.id : "",
+                role: "student",
+                course_id: courseId ? courseId : "",
+                operating: "sign_up",
+              }
+            )
+              .then((json) => {
+                console.log("add member", json);
+                if (json.ok) {
+                  console.log("new", json.data);
+                  if (typeof onStatusChanged !== "undefined") {
+                    onStatusChanged(json.data.status);
+                  }
+                  message.success(
+                    intl.formatMessage({ id: "flashes.success" })
+                  );
+                } else {
+                  message.error(json.message);
+                }
+              })
+              .catch((error) => {
+                message.error(error);
+              });
+          },
+        });
+      }}
+    >
+      报名
+    </Button>
+  );
+};
+
+export default Widget;

+ 143 - 0
dashboard/src/components/course/Status.tsx

@@ -0,0 +1,143 @@
+/**
+ * 报名按钮
+ * 已经报名显示报名状态
+ * 未报名显示报名按钮以及必要的提示
+ */
+import { Space, Typography } from "antd";
+import { useEffect, useState } from "react";
+import { useIntl } from "react-intl";
+
+import { get } from "../../request";
+import {
+  ICourseMemberData,
+  ICourseMemberListResponse,
+  TCourseExpRequest,
+  TCourseJoinMode,
+} from "../api/Course";
+import AcceptCourse from "./AcceptCourse";
+import AcceptNotCourse from "./AcceptNotCourse";
+import LeaveCourse from "./LeaveCourse";
+
+const { Paragraph } = Typography;
+
+interface IWidget {
+  courseId: string;
+  startAt?: string;
+  joinMode?: TCourseJoinMode;
+  expRequest?: TCourseExpRequest;
+}
+const Widget = ({ courseId, joinMode, startAt, expRequest }: IWidget) => {
+  const intl = useIntl();
+  const [currMember, setCurrMember] = useState<ICourseMemberData>();
+
+  const today = new Date();
+  const courseStart = new Date(startAt ? startAt : "3000-01-01");
+
+  useEffect(() => {
+    /**
+     * 获取该课程我的报名状态
+     */
+    const url = `/v2/course-member?view=user&course=${courseId}`;
+    console.log(url);
+    get<ICourseMemberListResponse>(url).then((json) => {
+      console.log("course member", json);
+      if (json.ok) {
+        let role: string[] = [];
+        for (const iterator of json.data.rows) {
+          if (typeof iterator.role !== "undefined") {
+            role.push(iterator.role);
+            setCurrMember(iterator);
+          }
+        }
+      }
+    });
+  }, [courseId]);
+
+  let labelStatus = "";
+  let operation: React.ReactNode | undefined;
+  if (currMember?.role === "student" || currMember?.role === "assistant") {
+    labelStatus = intl.formatMessage({
+      id: `course.member.status.${currMember.status}.label`,
+    });
+    switch (currMember.status) {
+      case "normal":
+        operation = (
+          <Space>
+            <LeaveCourse
+              joinMode={joinMode}
+              currUser={currMember}
+              onStatusChanged={(status: ICourseMemberData | undefined) => {
+                setCurrMember(status);
+              }}
+            />
+          </Space>
+        );
+        break;
+      case "sign_up":
+        operation = (
+          <Space>
+            <LeaveCourse
+              joinMode={joinMode}
+              currUser={currMember}
+              onStatusChanged={(status: ICourseMemberData | undefined) => {
+                setCurrMember(status);
+              }}
+            />
+          </Space>
+        );
+        break;
+      case "invited":
+        operation = (
+          <Space>
+            <AcceptCourse
+              joinMode={joinMode}
+              currUser={currMember}
+              onStatusChanged={(status: ICourseMemberData | undefined) => {
+                setCurrMember(status);
+              }}
+            />
+            <AcceptNotCourse
+              joinMode={joinMode}
+              currUser={currMember}
+              onStatusChanged={(status: ICourseMemberData | undefined) => {
+                setCurrMember(status);
+              }}
+            />
+          </Space>
+        );
+        break;
+      case "accepted":
+        operation = (
+          <Space>
+            <LeaveCourse
+              joinMode={joinMode}
+              currUser={currMember}
+              onStatusChanged={(status: ICourseMemberData | undefined) => {
+                setCurrMember(status);
+              }}
+            />
+          </Space>
+        );
+        break;
+      case "rejected":
+        break;
+      case "blocked":
+        break;
+      case "left":
+        break;
+    }
+  } else {
+    if (courseStart < today) {
+      labelStatus = "已经过期";
+    } else {
+    }
+  }
+  return (
+    <div>
+      <Paragraph>{labelStatus}</Paragraph>
+      {operation}
+    </div>
+  );
+};
+
+export default Widget;