visuddhinanda 3 лет назад
Родитель
Сommit
583dec8630

+ 115 - 0
dashboard/src/components/course/AddMember.tsx

@@ -0,0 +1,115 @@
+import { useIntl } from "react-intl";
+import { ProForm, ProFormSelect } from "@ant-design/pro-components";
+import { Button, message, Popover } from "antd";
+import { UserAddOutlined } from "@ant-design/icons";
+
+import { get, post } from "../../request";
+import { IUserListResponse } from "../api/Auth";
+import { useState } from "react";
+import { ICourseMemberData, ICourseMemberResponse } from "../api/Course";
+
+interface IFormData {
+  userId: string;
+  role: string;
+}
+
+interface IWidget {
+  courseId?: string;
+  onCreated?: Function;
+}
+const Widget = ({ courseId, onCreated }: IWidget) => {
+  const intl = useIntl();
+  const [open, setOpen] = useState(false);
+
+  const form = (
+    <ProForm<IFormData>
+      onFinish={async (values: IFormData) => {
+        // TODO
+        console.log(values);
+        if (typeof courseId !== "undefined") {
+          post<ICourseMemberData, ICourseMemberResponse>("/v2/course-member", {
+            user_id: values.userId,
+            role: values.role,
+            course_id: courseId,
+          }).then((json) => {
+            console.log("add member", json);
+            if (json.ok) {
+              message.success(intl.formatMessage({ id: "flashes.success" }));
+              setOpen(false);
+              if (typeof onCreated !== "undefined") {
+                onCreated();
+              }
+            }
+          });
+        }
+      }}
+    >
+      <ProForm.Group>
+        <ProFormSelect
+          width="sm"
+          name="userId"
+          label={intl.formatMessage({ id: "forms.fields.user.label" })}
+          showSearch
+          debounceTime={300}
+          request={async ({ keyWords }) => {
+            console.log("keyWord", keyWords);
+            const json = await get<IUserListResponse>(
+              `/v2/user?view=key&key=${keyWords}`
+            );
+            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.message.user.required",
+          })}
+          rules={[
+            {
+              required: true,
+              message: intl.formatMessage({
+                id: "forms.message.user.required",
+              }),
+            },
+          ]}
+        />
+      </ProForm.Group>
+      <ProForm.Group>
+        <ProFormSelect
+          width="sm"
+          name="role"
+          label={intl.formatMessage({ id: "forms.fields.type.label" })}
+          valueEnum={{
+            student: intl.formatMessage({ id: "forms.fields.student.label" }),
+            assistant: intl.formatMessage({
+              id: "forms.fields.assistant.label",
+            }),
+          }}
+        />
+      </ProForm.Group>
+    </ProForm>
+  );
+  const handleClickChange = (open: boolean) => {
+    setOpen(open);
+  };
+  return (
+    <Popover
+      placement="bottomLeft"
+      arrowPointAtCenter
+      content={form}
+      trigger="click"
+      open={open}
+      onOpenChange={handleClickChange}
+    >
+      <Button icon={<UserAddOutlined />} key="add" type="primary">
+        {intl.formatMessage({ id: "buttons.group.add.member" })}
+      </Button>
+    </Popover>
+  );
+};
+
+export default Widget;

+ 180 - 0
dashboard/src/components/course/CourseMember.tsx

@@ -0,0 +1,180 @@
+import { useIntl } from "react-intl";
+import { useRef, useState } from "react";
+import { ActionType, ProList } from "@ant-design/pro-components";
+import { Space, Tag, Button, Layout, Popconfirm } from "antd";
+
+import CourseAddMember from "./AddMember";
+import { delete_, get } from "../../request";
+
+import {
+  ICourseMemberDeleteResponse,
+  ICourseMemberListResponse,
+} from "../api/Course";
+
+const { Content } = Layout;
+
+interface IRoleTag {
+  title: string;
+  color: string;
+}
+interface DataItem {
+  id: number;
+  userId: string;
+  name?: string;
+  tag: IRoleTag[];
+  image: string;
+}
+interface IWidget {
+  courseId?: string;
+}
+const Widget = ({ courseId }: IWidget) => {
+  const intl = useIntl(); //i18n
+  const [canDelete, setCanDelete] = useState(false);
+  const [memberCount, setMemberCount] = useState<number>();
+
+  const ref = useRef<ActionType>();
+  return (
+    <Content>
+      <ProList<DataItem>
+        rowKey="id"
+        actionRef={ref}
+        headerTitle={
+          intl.formatMessage({ id: "group.member" }) +
+          "-" +
+          memberCount?.toString()
+        }
+        toolBarRender={() => {
+          return [
+            canDelete ? (
+              <CourseAddMember
+                courseId={courseId}
+                onCreated={() => {
+                  ref.current?.reload();
+                }}
+              />
+            ) : (
+              <></>
+            ),
+          ];
+        }}
+        showActions="hover"
+        request={async (params = {}, sorter, filter) => {
+          // TODO
+          console.log(params, sorter, filter);
+
+          let url = `/v2/course-member?view=course&id=${courseId}`;
+          const offset =
+            ((params.current ? params.current : 1) - 1) *
+            (params.pageSize ? params.pageSize : 20);
+          url += `&limit=${params.pageSize}&offset=${offset}`;
+          if (typeof params.keyword !== "undefined") {
+            url += "&search=" + (params.keyword ? params.keyword : "");
+          }
+          const res = await get<ICourseMemberListResponse>(url);
+          if (res.ok) {
+            console.log(res.data);
+            setMemberCount(res.data.count);
+            switch (res.data.role) {
+              case "owner":
+                setCanDelete(true);
+                break;
+              case "manager":
+                setCanDelete(true);
+                break;
+            }
+            const items: DataItem[] = res.data.rows.map((item, id) => {
+              let member: DataItem = {
+                id: item.id ? item.id : 0,
+                userId: item.user_id,
+                name: item.user?.nickName,
+                tag: [],
+                image: "",
+              };
+              member.tag.push({
+                title: intl.formatMessage({
+                  id: "forms.fields." + item.role + ".label",
+                }),
+                color: "default",
+              });
+
+              return member;
+            });
+            console.log(items);
+            return {
+              total: res.data.count,
+              succcess: true,
+              data: items,
+            };
+          } else {
+            console.error(res.message);
+            return {
+              total: 0,
+              succcess: false,
+              data: [],
+            };
+          }
+        }}
+        pagination={{
+          showQuickJumper: true,
+          showSizeChanger: true,
+        }}
+        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) => [
+              canDelete ? (
+                <Popconfirm
+                  placement="bottomLeft"
+                  title={intl.formatMessage({
+                    id: "forms.message.member.delete",
+                  })}
+                  onConfirm={(
+                    e?: React.MouseEvent<HTMLElement, MouseEvent>
+                  ) => {
+                    console.log("delete", row.id);
+                    delete_<ICourseMemberDeleteResponse>(
+                      "/v2/course-member/" + row.id
+                    ).then((json) => {
+                      if (json.ok) {
+                        console.log("delete ok");
+                        ref.current?.reload();
+                      }
+                    });
+                  }}
+                  okText={intl.formatMessage({ id: "buttons.ok" })}
+                  cancelText={intl.formatMessage({ id: "buttons.cancel" })}
+                >
+                  <Button size="small" type="link" danger key="link">
+                    {intl.formatMessage({ id: "buttons.remove" })}
+                  </Button>
+                </Popconfirm>
+              ) : (
+                <></>
+              ),
+            ],
+          },
+        }}
+      />
+    </Content>
+  );
+};
+
+export default Widget;