visuddhinanda 2 лет назад
Родитель
Сommit
477ca4d459
1 измененных файлов с 153 добавлено и 258 удалено
  1. 153 258
      dashboard/src/components/course/CourseMemberList.tsx

+ 153 - 258
dashboard/src/components/course/CourseMemberList.tsx

@@ -1,37 +1,76 @@
 import { useIntl } from "react-intl";
-
-import { Space, Button, Dropdown, Table, Modal } from "antd";
-import { ActionType, ProTable } from "@ant-design/pro-components";
-import {
-  DeleteOutlined,
-  BarChartOutlined,
-  ExclamationCircleFilled,
-} from "@ant-design/icons";
+import { Dropdown, Modal, Tag } from "antd";
+import { ActionType, ProList } from "@ant-design/pro-components";
+import { ExclamationCircleFilled } from "@ant-design/icons";
 
 import { delete_, get, put } from "../../request";
 import { ICourseMember } from "./CourseMember";
 import AddMember from "./AddMember";
-import { useRef, useState } from "react";
+import { useEffect, useRef, useState } from "react";
 import {
+  ICourseDataResponse,
   ICourseMemberData,
   ICourseMemberDeleteResponse,
   ICourseMemberListResponse,
   ICourseMemberResponse,
+  ICourseResponse,
+  TCourseMemberAction,
   TCourseMemberStatus,
 } from "../api/Course";
 import { ItemType } from "antd/lib/menu/hooks/useItems";
+import User from "../auth/User";
+import { managerCanDo } from "./RolePower";
 const { confirm } = Modal;
 
+interface IStatusColor {
+  status: TCourseMemberStatus;
+  color: string;
+}
+export const getStatusColor = (status?: TCourseMemberStatus): string => {
+  let color = "unset";
+  const setting: IStatusColor[] = [
+    { status: "applied", color: "blue" },
+    { status: "invited", color: "blue" },
+    { status: "accepted", color: "green" },
+    { status: "rejected", color: "orange" },
+    { status: "disagreed", color: "red" },
+    { status: "left", color: "red" },
+    { status: "blocked", color: "orange" },
+  ];
+  const CourseStatusColor = setting.find((value) => value.status === status);
+
+  if (CourseStatusColor) {
+    color = CourseStatusColor.color;
+  }
+  return color;
+};
+
 interface IWidget {
-  studioName?: string;
   courseId?: string;
+  onSelect?: Function;
 }
 
-const CourseMemberListWidget = ({ studioName, courseId }: IWidget) => {
+const CourseMemberListWidget = ({ courseId, onSelect }: IWidget) => {
   const intl = useIntl(); //i18n
   const [canDelete, setCanDelete] = useState(false);
+  const [course, setCourse] = useState<ICourseDataResponse>();
   const ref = useRef<ActionType>();
 
+  useEffect(() => {
+    if (courseId) {
+      const url = `/v2/course/${courseId}`;
+      console.debug("course url", url);
+      get<ICourseResponse>(url)
+        .then((json) => {
+          console.debug("course data", json.data);
+          if (json.ok) {
+            setCourse(json.data);
+          }
+        })
+        .catch((e) => console.error(e));
+    }
+  }, [courseId]);
+
   const ChangeStatus = (
     id: string,
     name: string,
@@ -70,214 +109,91 @@ const CourseMemberListWidget = ({ studioName, courseId }: IWidget) => {
   };
   return (
     <>
-      <ProTable<ICourseMember>
+      <ProList<ICourseMember>
         actionRef={ref}
-        columns={[
-          {
-            title: intl.formatMessage({
-              id: "dict.fields.sn.label",
-            }),
-            dataIndex: "sn",
-            key: "sn",
-            width: 50,
+        search={{
+          filterType: "light",
+        }}
+        onItem={(record: ICourseMember, index: number) => {
+          return {
+            onClick: (event) => {
+              // 点击行
+              if (typeof onSelect !== "undefined") {
+                onSelect(record);
+              }
+            },
+          };
+        }}
+        metas={{
+          title: {
+            dataIndex: "name",
             search: false,
           },
-          {
-            title: intl.formatMessage({
-              id: "forms.fields.name.label",
-            }),
-            dataIndex: "name",
-            key: "name",
+          avatar: {
+            render(dom, entity, index, action, schema) {
+              return <User {...entity.user} showName={false} />;
+            },
+            editable: false,
           },
-          {
-            title: intl.formatMessage({
-              id: "forms.fields.role.label",
-            }),
-            dataIndex: "role",
-            key: "role",
-            width: 100,
+          description: {
+            dataIndex: "desc",
             search: false,
-            filters: true,
-            onFilter: true,
-            valueEnum: {
-              all: {
-                text: intl.formatMessage({
-                  id: "tables.publicity.all",
-                }),
-                status: "Default",
-              },
-              student: {
-                text: intl.formatMessage({
-                  id: "auth.role.student",
-                }),
-                status: "Default",
-              },
-              assistant: {
-                text: intl.formatMessage({
-                  id: "auth.role.assistant",
-                }),
-                status: "Success",
-              },
-            },
           },
-          {
-            title: intl.formatMessage({
-              id: "forms.fields.status.label",
-            }),
-            dataIndex: "status",
-            key: "status",
-            width: 100,
+          subTitle: {
             search: false,
-            filters: true,
-            onFilter: true,
-            valueEnum: {
-              /**"success","processing","error","default","warning" */
-              all: {
-                text: intl.formatMessage({
-                  id: "tables.publicity.all",
-                }),
-                status: "default",
-              },
-              normal: {
-                text: intl.formatMessage({
-                  id: "course.member.status.normal.label",
-                }),
-                status: "success",
-              },
-              sign_up: {
-                text: intl.formatMessage({
-                  id: "course.member.status.sign_up.label",
-                }),
-                status: "Processing",
-              },
-              invited: {
-                text: intl.formatMessage({
-                  id: "course.member.status.invited.label",
-                }),
-                status: "default",
-              },
-              accepted: {
-                text: intl.formatMessage({
-                  id: "course.member.status.accepted.label",
-                }),
-                status: "success",
-              },
-              rejected: {
-                text: intl.formatMessage({
-                  id: "course.member.status.rejected.label",
-                }),
-                status: "warning",
-              },
-              left: {
-                text: intl.formatMessage({
-                  id: "course.member.status.left.label",
-                }),
-                status: "error",
-              },
-              blocked: {
-                text: intl.formatMessage({
-                  id: "course.member.status.blocked.label",
-                }),
-                status: "error",
-              },
+            render: (
+              dom: React.ReactNode,
+              entity: ICourseMember,
+              index: number
+            ) => {
+              return (
+                <Tag>
+                  {intl.formatMessage({
+                    id: `auth.role.${entity.role}`,
+                  })}
+                </Tag>
+              );
             },
           },
-          {
-            title: intl.formatMessage({
-              id: "course.exp.start.label",
-            }),
-            dataIndex: "startExp",
-            key: "startExp",
-          },
-          {
-            title: intl.formatMessage({
-              id: "course.exp.current.label",
-            }),
-            dataIndex: "currentExp",
-            key: "currentExp",
-          },
-          {
-            title: intl.formatMessage({
-              id: "course.exp.end.label",
-            }),
-            dataIndex: "endExp",
-            key: "endExp",
-          },
-          {
-            title: intl.formatMessage({ id: "buttons.option" }),
-            key: "option",
-            width: 120,
-            valueType: "option",
+          actions: {
+            search: false,
             render: (text, row, index, action) => {
-              let items: ItemType[] = [];
-              switch (row.status) {
-                case "accepted":
-                  items = [
-                    {
-                      key: "exp",
-                      label: "查看经验值",
-                      icon: <BarChartOutlined />,
-                    },
-                    {
-                      key: "block",
-                      label: "屏蔽",
-                      icon: <DeleteOutlined />,
-                      danger: true,
-                    },
-                  ];
-                  break;
-                case "sign_up":
-                  items = [
-                    {
-                      key: "accept",
-                      label: "接受",
-                      icon: <BarChartOutlined />,
-                    },
-                    {
-                      key: "reject",
-                      label: "拒绝",
-                      icon: <DeleteOutlined />,
-                      danger: true,
-                    },
-                  ];
-                  break;
-                case "invited":
-                  items = [
-                    {
-                      key: "delete",
-                      label: "删除",
-                      icon: <DeleteOutlined />,
-                      danger: true,
-                    },
-                  ];
-                  break;
-                case "normal":
-                  items = [
-                    {
-                      key: "exp",
-                      label: "查看经验值",
-                      icon: <BarChartOutlined />,
-                    },
-                    {
-                      key: "block",
-                      label: "屏蔽",
-                      icon: <DeleteOutlined />,
-                      danger: true,
-                    },
-                  ];
-                  break;
-                default:
-                  items = [
-                    {
-                      key: "none",
-                      label: "无操作",
-                      disabled: true,
-                    },
-                  ];
-                  break;
-              }
+              let canUndo = false;
+              const statusColor = getStatusColor(row.status);
+              const actions: TCourseMemberAction[] = [
+                "invite",
+                "revoke",
+                "accept",
+                "reject",
+                "block",
+              ];
+              const undo = {
+                key: "undo",
+                label: "撤销上次操作",
+                disabled: !canUndo,
+              };
+              const items: ItemType[] = actions.map((item) => {
+                return {
+                  key: item,
+                  label: intl.formatMessage({
+                    id: `course.member.status.${item}.button`,
+                  }),
+                  disabled: !managerCanDo(
+                    item,
+                    course?.start_at,
+                    course?.end_at,
+                    course?.join,
+                    row.status
+                  ),
+                };
+              });
 
               return [
+                <span style={{ color: statusColor }}>
+                  {intl.formatMessage({
+                    id: `course.member.status.${row.status}.label`,
+                  })}
+                </span>,
                 canDelete ? (
                   <Dropdown.Button
                     key={index}
@@ -333,43 +249,31 @@ const CourseMemberListWidget = ({ studioName, courseId }: IWidget) => {
               ];
             },
           },
-        ]}
-        rowSelection={{
-          // 自定义选择项参考: https://ant.design/components/table-cn/#components-table-demo-row-selection-custom
-          // 注释该行则默认不显示下拉选项
-          selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
-        }}
-        tableAlertRender={({
-          selectedRowKeys,
-          selectedRows,
-          onCleanSelected,
-        }) => (
-          <Space size={24}>
-            <span>
-              {intl.formatMessage({ id: "buttons.selected" })}
-              {selectedRowKeys.length}
-              <Button
-                type="link"
-                style={{ marginInlineStart: 8 }}
-                onClick={onCleanSelected}
-              >
-                {intl.formatMessage({
-                  id: "buttons.unselect",
-                })}
-              </Button>
-            </span>
-          </Space>
-        )}
-        tableAlertOptionRender={() => {
-          return (
-            <Space size={16}>
-              <Button type="link">
-                {intl.formatMessage({
-                  id: "buttons.delete.all",
-                })}
-              </Button>
-            </Space>
-          );
+          role: {
+            // 自己扩展的字段,主要用于筛选,不在列表中显示
+            title: "角色",
+            valueType: "select",
+            valueEnum: {
+              all: {
+                text: intl.formatMessage({
+                  id: "tables.publicity.all",
+                }),
+                status: "Default",
+              },
+              student: {
+                text: intl.formatMessage({
+                  id: "auth.role.student",
+                }),
+                status: "Default",
+              },
+              assistant: {
+                text: intl.formatMessage({
+                  id: "auth.role.assistant",
+                }),
+                status: "Success",
+              },
+            },
+          },
         }}
         request={async (params = {}, sorter, filter) => {
           console.log(params, sorter, filter);
@@ -382,33 +286,25 @@ const CourseMemberListWidget = ({ studioName, courseId }: IWidget) => {
           if (typeof params.keyword !== "undefined") {
             url += "&search=" + (params.keyword ? params.keyword : "");
           }
+          console.info("api request", url);
           const res = await get<ICourseMemberListResponse>(url);
           if (res.ok) {
-            console.log(res.data);
-            switch (res.data.role) {
-              case "owner":
-              case "manager":
-              case "assistant":
-                setCanDelete(true);
-                break;
+            console.debug("api response", res.data);
+            if (res.data.role === "owner" || res.data.role === "manager") {
+              setCanDelete(true);
             }
             const items: ICourseMember[] = res.data.rows.map((item, id) => {
               let member: ICourseMember = {
                 sn: id + 1,
                 id: item.id,
                 userId: item.user_id,
+                user: item.user,
                 name: item.user?.nickName,
                 role: item.role,
                 status: item.status,
                 tag: [],
                 image: "",
               };
-              member.tag.push({
-                title: intl.formatMessage({
-                  id: "forms.fields." + item.role + ".label",
-                }),
-                color: "default",
-              });
 
               return member;
             });
@@ -433,7 +329,6 @@ const CourseMemberListWidget = ({ studioName, courseId }: IWidget) => {
           showQuickJumper: true,
           showSizeChanger: true,
         }}
-        search={false}
         options={{
           search: true,
         }}