visuddhinanda 3 лет назад
Родитель
Сommit
6459b58e7e

+ 92 - 30
dashboard/src/pages/studio/anthology/list.tsx

@@ -1,42 +1,27 @@
 import { useParams } from "react-router-dom";
-import { ProTable } from "@ant-design/pro-components";
+import { ActionType, ProTable } from "@ant-design/pro-components";
 import { useIntl } from "react-intl";
 import { Link } from "react-router-dom";
-import { Space, Table, Typography } from "antd";
+import { message, Modal, Space, Table, Typography } from "antd";
 import { PlusOutlined } from "@ant-design/icons";
-import type { MenuProps } from "antd";
-import { Button, Dropdown, Menu, Popover } from "antd";
-import { SearchOutlined, DeleteOutlined } from "@ant-design/icons";
+import { Button, Dropdown, Popover } from "antd";
+import {
+  ExclamationCircleOutlined,
+  TeamOutlined,
+  DeleteOutlined,
+} from "@ant-design/icons";
 
 import AnthologyCreate from "../../../components/anthology/AnthologyCreate";
-import { IAnthologyListResponse } from "../../../components/api/Article";
-import { get } from "../../../request";
+import {
+  IAnthologyListResponse,
+  IDeleteResponse,
+} from "../../../components/api/Article";
+import { delete_, get } from "../../../request";
 import { PublicityValueEnum } from "../../../components/studio/table";
+import { useRef } from "react";
 
 const { Text } = Typography;
 
-const onMenuClick: MenuProps["onClick"] = (e) => {
-  console.log("click", e);
-};
-
-const menu = (
-  <Menu
-    onClick={onMenuClick}
-    items={[
-      {
-        key: "share",
-        label: "分享",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "delete",
-        label: "删除",
-        icon: <DeleteOutlined />,
-      },
-    ]}
-  />
-);
-
 interface IItem {
   sn: number;
   id: string;
@@ -51,9 +36,45 @@ const Widget = () => {
   const intl = useIntl();
   const { studioname } = useParams();
   const anthologyCreate = <AnthologyCreate studio={studioname} />;
+  const showDeleteConfirm = (id: string, title: string) => {
+    Modal.confirm({
+      icon: <ExclamationCircleOutlined />,
+      title:
+        intl.formatMessage({
+          id: "message.delete.sure",
+        }) +
+        intl.formatMessage({
+          id: "message.irrevocable",
+        }),
+
+      content: title,
+      okText: intl.formatMessage({
+        id: "buttons.delete",
+      }),
+      okType: "danger",
+      cancelText: intl.formatMessage({
+        id: "buttons.no",
+      }),
+      onOk() {
+        console.log("delete", id);
+        return delete_<IDeleteResponse>(`/v2/anthology/${id}`)
+          .then((json) => {
+            if (json.ok) {
+              message.success("删除成功");
+              ref.current?.reload();
+            } else {
+              message.error(json.message);
+            }
+          })
+          .catch((e) => console.log("Oops errors!", e));
+      },
+    });
+  };
+  const ref = useRef<ActionType>();
   return (
     <>
       <ProTable<IItem>
+        actionRef={ref}
         columns={[
           {
             title: intl.formatMessage({
@@ -124,7 +145,48 @@ const Widget = () => {
             width: 120,
             valueType: "option",
             render: (text, row, index, action) => [
-              <Dropdown.Button type="link" key={index} overlay={menu}>
+              <Dropdown.Button
+                key={index}
+                type="link"
+                menu={{
+                  items: [
+                    {
+                      key: "share",
+                      label: intl.formatMessage({
+                        id: "buttons.share",
+                      }),
+                      icon: <TeamOutlined />,
+                      disabled: true,
+                    },
+                    {
+                      key: "remove",
+                      label: (
+                        <Text type="danger">
+                          {intl.formatMessage({
+                            id: "buttons.delete",
+                          })}
+                        </Text>
+                      ),
+                      icon: (
+                        <Text type="danger">
+                          <DeleteOutlined />
+                        </Text>
+                      ),
+                    },
+                  ],
+                  onClick: (e) => {
+                    switch (e.key) {
+                      case "share":
+                        break;
+                      case "remove":
+                        showDeleteConfirm(row.id, row.title);
+                        break;
+                      default:
+                        break;
+                    }
+                  },
+                }}
+              >
                 <Link to={`/studio/${studioname}/anthology/${row.id}/edit`}>
                   {intl.formatMessage({
                     id: "buttons.edit",

+ 100 - 31
dashboard/src/pages/studio/article/list.tsx

@@ -1,44 +1,35 @@
 import { useParams, Link } from "react-router-dom";
 import { useIntl } from "react-intl";
 
-import { Space, Button, Popover, Dropdown, MenuProps, Menu, Table } from "antd";
-import { ProTable } from "@ant-design/pro-components";
+import {
+  Space,
+  Button,
+  Popover,
+  Dropdown,
+  Table,
+  Typography,
+  Modal,
+  message,
+} from "antd";
+import { ActionType, ProTable } from "@ant-design/pro-components";
 import {
   PlusOutlined,
-  SearchOutlined,
   DeleteOutlined,
+  TeamOutlined,
+  ExclamationCircleOutlined,
 } from "@ant-design/icons";
 
 import ArticleCreate from "../../../components/article/ArticleCreate";
-import { get } from "../../../request";
-import { IArticleListResponse } from "../../../components/api/Article";
+import { delete_, get } from "../../../request";
+import {
+  IArticleListResponse,
+  IDeleteResponse,
+} from "../../../components/api/Article";
 import { PublicityValueEnum } from "../../../components/studio/table";
-const onMenuClick: MenuProps["onClick"] = (e) => {
-  console.log("click", e);
-};
+import { useRef } from "react";
+
+const { Text } = Typography;
 
-const menu = (
-  <Menu
-    onClick={onMenuClick}
-    items={[
-      {
-        key: "1",
-        label: "在藏经阁中打开",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "2",
-        label: "分享",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "delete",
-        label: "删除",
-        icon: <DeleteOutlined />,
-      },
-    ]}
-  />
-);
 interface DataItem {
   sn: number;
   id: string;
@@ -53,9 +44,46 @@ const Widget = () => {
   const { studioname } = useParams(); //url 参数
   const articleCreate = <ArticleCreate studio={studioname} />;
 
+  const showDeleteConfirm = (id: string, title: string) => {
+    Modal.confirm({
+      icon: <ExclamationCircleOutlined />,
+      title:
+        intl.formatMessage({
+          id: "message.delete.sure",
+        }) +
+        intl.formatMessage({
+          id: "message.irrevocable",
+        }),
+
+      content: title,
+      okText: intl.formatMessage({
+        id: "buttons.delete",
+      }),
+      okType: "danger",
+      cancelText: intl.formatMessage({
+        id: "buttons.no",
+      }),
+      onOk() {
+        console.log("delete", id);
+        return delete_<IDeleteResponse>(`/v2/article/${id}`)
+          .then((json) => {
+            if (json.ok) {
+              message.success("删除成功");
+              ref.current?.reload();
+            } else {
+              message.error(json.message);
+            }
+          })
+          .catch((e) => console.log("Oops errors!", e));
+      },
+    });
+  };
+
+  const ref = useRef<ActionType>();
   return (
     <>
       <ProTable<DataItem>
+        actionRef={ref}
         columns={[
           {
             title: intl.formatMessage({
@@ -135,7 +163,48 @@ const Widget = () => {
             valueType: "option",
             render: (text, row, index, action) => {
               return [
-                <Dropdown.Button key={index} type="link" overlay={menu}>
+                <Dropdown.Button
+                  key={index}
+                  type="link"
+                  menu={{
+                    items: [
+                      {
+                        key: "share",
+                        label: intl.formatMessage({
+                          id: "buttons.share",
+                        }),
+                        icon: <TeamOutlined />,
+                        disabled: true,
+                      },
+                      {
+                        key: "remove",
+                        label: (
+                          <Text type="danger">
+                            {intl.formatMessage({
+                              id: "buttons.delete",
+                            })}
+                          </Text>
+                        ),
+                        icon: (
+                          <Text type="danger">
+                            <DeleteOutlined />
+                          </Text>
+                        ),
+                      },
+                    ],
+                    onClick: (e) => {
+                      switch (e.key) {
+                        case "share":
+                          break;
+                        case "remove":
+                          showDeleteConfirm(row.id, row.title);
+                          break;
+                        default:
+                          break;
+                      }
+                    },
+                  }}
+                >
                   <Link to={`/studio/${studioname}/article/${row.id}/edit`}>
                     {intl.formatMessage({
                       id: "buttons.edit",

+ 94 - 34
dashboard/src/pages/studio/channel/list.tsx

@@ -1,43 +1,23 @@
 import { useParams } from "react-router-dom";
-import { ProTable } from "@ant-design/pro-components";
+import { ActionType, ProTable } from "@ant-design/pro-components";
 import { useIntl } from "react-intl";
 import { Link } from "react-router-dom";
-import { Space, Table } from "antd";
-import type { MenuProps } from "antd";
-import { Button, Dropdown, Menu, Popover } from "antd";
-import { SearchOutlined, PlusOutlined } from "@ant-design/icons";
+import { message, Modal, Space, Table, Typography } from "antd";
+import { Button, Dropdown, Popover } from "antd";
+import {
+  PlusOutlined,
+  ExclamationCircleOutlined,
+  DeleteOutlined,
+  TeamOutlined,
+} from "@ant-design/icons";
 
 import ChannelCreate from "../../../components/channel/ChannelCreate";
-import { get } from "../../../request";
+import { delete_, get } from "../../../request";
 import { IApiResponseChannelList } from "../../../components/api/Channel";
 import { PublicityValueEnum } from "../../../components/studio/table";
-
-const onMenuClick: MenuProps["onClick"] = (e) => {
-  console.log("click", e);
-};
-
-const menu = (
-  <Menu
-    onClick={onMenuClick}
-    items={[
-      {
-        key: "1",
-        label: "在藏经阁中打开",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "2",
-        label: "分享",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "3",
-        label: "删除",
-        icon: <SearchOutlined />,
-      },
-    ]}
-  />
-);
+import { IDeleteResponse } from "../../../components/api/Article";
+import { useRef } from "react";
+const { Text } = Typography;
 
 interface IItem {
   id: number;
@@ -53,9 +33,48 @@ const Widget = () => {
   const intl = useIntl();
   const { studioname } = useParams();
   const channelCreate = <ChannelCreate studio={studioname} />;
+
+  const showDeleteConfirm = (id: string, title: string) => {
+    Modal.confirm({
+      icon: <ExclamationCircleOutlined />,
+      title:
+        intl.formatMessage({
+          id: "message.delete.sure",
+        }) +
+        intl.formatMessage({
+          id: "message.irrevocable",
+        }),
+
+      content: title,
+      okText: intl.formatMessage({
+        id: "buttons.delete",
+      }),
+      okType: "danger",
+      cancelText: intl.formatMessage({
+        id: "buttons.no",
+      }),
+      onOk() {
+        console.log("delete", id);
+        return delete_<IDeleteResponse>(`/v2/channel/${id}`)
+          .then((json) => {
+            if (json.ok) {
+              message.success("删除成功");
+              ref.current?.reload();
+            } else {
+              message.error(json.message);
+            }
+          })
+          .catch((e) => console.log("Oops errors!", e));
+      },
+    });
+  };
+
+  const ref = useRef<ActionType>();
+
   return (
     <>
       <ProTable<IItem>
+        actionRef={ref}
         columns={[
           {
             title: intl.formatMessage({
@@ -173,7 +192,48 @@ const Widget = () => {
             valueType: "option",
             render: (text, row, index, action) => {
               return [
-                <Dropdown.Button key={index} type="link" overlay={menu}>
+                <Dropdown.Button
+                  key={index}
+                  type="link"
+                  menu={{
+                    items: [
+                      {
+                        key: "share",
+                        label: intl.formatMessage({
+                          id: "buttons.share",
+                        }),
+                        icon: <TeamOutlined />,
+                        disabled: true,
+                      },
+                      {
+                        key: "remove",
+                        label: (
+                          <Text type="danger">
+                            {intl.formatMessage({
+                              id: "buttons.delete",
+                            })}
+                          </Text>
+                        ),
+                        icon: (
+                          <Text type="danger">
+                            <DeleteOutlined />
+                          </Text>
+                        ),
+                      },
+                    ],
+                    onClick: (e) => {
+                      switch (e.key) {
+                        case "share":
+                          break;
+                        case "remove":
+                          showDeleteConfirm(row.uid, row.title);
+                          break;
+                        default:
+                          break;
+                      }
+                    },
+                  }}
+                >
                   <Link to={`/studio/${studioname}/channel/${row.uid}/edit`}>
                     {intl.formatMessage({
                       id: "buttons.edit",

+ 80 - 23
dashboard/src/pages/studio/course/list.tsx

@@ -11,40 +11,30 @@ import {
   Menu,
   Table,
   Image,
+  message,
+  Modal,
+  Typography,
 } from "antd";
 import { ProTable, ActionType } from "@ant-design/pro-components";
-import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
+import {
+  PlusOutlined,
+  DeleteOutlined,
+  TeamOutlined,
+  ExclamationCircleOutlined,
+} from "@ant-design/icons";
 
 import CourseCreate from "../../../components/course/CourseCreate";
-import { API_HOST, get } from "../../../request";
+import { API_HOST, delete_, get } from "../../../request";
 import {
   ICourseListResponse,
   ICourseNumberResponse,
   TCourseMemberStatus,
 } from "../../../components/api/Course";
 import { PublicityValueEnum } from "../../../components/studio/table";
+import { IDeleteResponse } from "../../../components/api/Article";
 
-const onMenuClick: MenuProps["onClick"] = (e) => {
-  console.log("click", e);
-};
+const { Text } = Typography;
 
-const menu = (
-  <Menu
-    onClick={onMenuClick}
-    items={[
-      {
-        key: "manage",
-        label: "管理",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "delete",
-        label: "删除",
-        icon: <SearchOutlined />,
-      },
-    ]}
-  />
-);
 interface DataItem {
   sn: number;
   id: string; //课程ID
@@ -115,6 +105,42 @@ const Widget = () => {
       }
     });
   }, [studioname]);
+
+  const showDeleteConfirm = (id: string, title: string) => {
+    Modal.confirm({
+      icon: <ExclamationCircleOutlined />,
+      title:
+        intl.formatMessage({
+          id: "message.delete.sure",
+        }) +
+        intl.formatMessage({
+          id: "message.irrevocable",
+        }),
+
+      content: title,
+      okText: intl.formatMessage({
+        id: "buttons.delete",
+      }),
+      okType: "danger",
+      cancelText: intl.formatMessage({
+        id: "buttons.no",
+      }),
+      onOk() {
+        console.log("delete", id);
+        return delete_<IDeleteResponse>(`/v2/course/${id}`)
+          .then((json) => {
+            if (json.ok) {
+              message.success("删除成功");
+              ref.current?.reload();
+            } else {
+              message.error(json.message);
+            }
+          })
+          .catch((e) => console.log("Oops errors!", e));
+      },
+    });
+  };
+
   return (
     <>
       <ProTable<DataItem>
@@ -246,7 +272,38 @@ const Widget = () => {
                   break;
               }
               return [
-                <Dropdown.Button key={index} type="text" overlay={menu}>
+                <Dropdown.Button
+                  key={index}
+                  type="link"
+                  menu={{
+                    items: [
+                      {
+                        key: "remove",
+                        label: (
+                          <Text type="danger">
+                            {intl.formatMessage({
+                              id: "buttons.delete",
+                            })}
+                          </Text>
+                        ),
+                        icon: (
+                          <Text type="danger">
+                            <DeleteOutlined />
+                          </Text>
+                        ),
+                      },
+                    ],
+                    onClick: (e) => {
+                      switch (e.key) {
+                        case "remove":
+                          showDeleteConfirm(row.id, row.title);
+                          break;
+                        default:
+                          break;
+                      }
+                    },
+                  }}
+                >
                   {mainButton}
                 </Dropdown.Button>,
               ];

+ 100 - 49
dashboard/src/pages/studio/dict/list.tsx

@@ -3,53 +3,33 @@ import { useIntl } from "react-intl";
 
 import {
   Button,
-  Layout,
   Space,
   Table,
   Dropdown,
-  MenuProps,
-  Menu,
   Drawer,
+  message,
+  Modal,
+  Typography,
 } from "antd";
-import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
-import { ProTable } from "@ant-design/pro-components";
+import {
+  PlusOutlined,
+  ExclamationCircleOutlined,
+  DeleteOutlined,
+} from "@ant-design/icons";
+import { ActionType, ProTable } from "@ant-design/pro-components";
 
 import DictCreate from "../../../components/dict/DictCreate";
 import { IApiResponseDictList } from "../../../components/api/Dict";
-import { get } from "../../../request";
-import { useState } from "react";
+import { delete_, get } from "../../../request";
+import { useRef, useState } from "react";
 import DictEdit from "../../../components/dict/DictEdit";
+import { IDeleteResponse } from "../../../components/api/Article";
 
-const onMenuClick: MenuProps["onClick"] = (e) => {
-  console.log("click", e);
-};
-
-const menu = (
-  <Menu
-    onClick={onMenuClick}
-    items={[
-      {
-        key: "1",
-        label: "在藏经阁中打开",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "2",
-        label: "分享",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "3",
-        label: "删除",
-        icon: <SearchOutlined />,
-      },
-    ]}
-  />
-);
+const { Text } = Typography;
 
 interface IItem {
-  id: number;
-  wordId: number;
+  sn: number;
+  wordId: string;
   word: string;
   type: string;
   grammar: string;
@@ -65,20 +45,57 @@ const Widget = () => {
   const { studioname } = useParams();
   const [isEditOpen, setIsEditOpen] = useState(false);
   const [isCreateOpen, setIsCreateOpen] = useState(false);
-  const [wordId, setWordId] = useState(0);
+  const [wordId, setWordId] = useState<string>();
   const [drawerTitle, setDrawerTitle] = useState("New Word");
 
+  const showDeleteConfirm = (id: string, title: string) => {
+    Modal.confirm({
+      icon: <ExclamationCircleOutlined />,
+      title:
+        intl.formatMessage({
+          id: "message.delete.sure",
+        }) +
+        intl.formatMessage({
+          id: "message.irrevocable",
+        }),
+
+      content: title,
+      okText: intl.formatMessage({
+        id: "buttons.delete",
+      }),
+      okType: "danger",
+      cancelText: intl.formatMessage({
+        id: "buttons.no",
+      }),
+      onOk() {
+        console.log("delete", id);
+        return delete_<IDeleteResponse>(`/v2/userdict/${id}`)
+          .then((json) => {
+            if (json.ok) {
+              message.success("删除成功");
+              ref.current?.reload();
+            } else {
+              message.error(json.message);
+            }
+          })
+          .catch((e) => console.log("Oops errors!", e));
+      },
+    });
+  };
+
+  const ref = useRef<ActionType>();
+
   return (
     <>
-      <Layout>{studioname}</Layout>
       <ProTable<IItem>
+        actionRef={ref}
         columns={[
           {
             title: intl.formatMessage({
               id: "dict.fields.sn.label",
             }),
-            dataIndex: "id",
-            key: "id",
+            dataIndex: "sn",
+            key: "sn",
             width: 80,
             search: false,
           },
@@ -172,16 +189,50 @@ const Widget = () => {
                 <Dropdown.Button
                   key={index}
                   type="link"
-                  overlay={menu}
-                  onClick={() => {
-                    setWordId(row.wordId);
-                    setDrawerTitle(row.word);
-                    setIsEditOpen(true);
+                  menu={{
+                    items: [
+                      {
+                        key: "remove",
+                        label: (
+                          <Text type="danger">
+                            {intl.formatMessage({
+                              id: "buttons.delete",
+                            })}
+                          </Text>
+                        ),
+                        icon: (
+                          <Text type="danger">
+                            <DeleteOutlined />
+                          </Text>
+                        ),
+                      },
+                    ],
+                    onClick: (e) => {
+                      switch (e.key) {
+                        case "share":
+                          break;
+                        case "remove":
+                          showDeleteConfirm(row.wordId, row.word);
+                          break;
+                        default:
+                          break;
+                      }
+                    },
                   }}
                 >
-                  {intl.formatMessage({
-                    id: "buttons.edit",
-                  })}
+                  <Button
+                    type="link"
+                    size="small"
+                    onClick={() => {
+                      setWordId(row.wordId);
+                      setDrawerTitle(row.word);
+                      setIsEditOpen(true);
+                    }}
+                  >
+                    {intl.formatMessage({
+                      id: "buttons.edit",
+                    })}
+                  </Button>
                 </Dropdown.Button>,
               ];
             },
@@ -230,14 +281,14 @@ const Widget = () => {
             url += "&search=" + (params.keyword ? params.keyword : "");
           }
           console.log(url);
-          const res: IApiResponseDictList = await get(url);
+          const res = await get<IApiResponseDictList>(url);
 
           const items: IItem[] = res.data.rows.map((item, id) => {
             const date = new Date(item.updated_at);
             const id2 =
               ((params.current || 1) - 1) * (params.pageSize || 20) + id + 1;
             return {
-              id: id2,
+              sn: id2,
               wordId: item.id,
               word: item.word,
               type: item.type,

+ 91 - 27
dashboard/src/pages/studio/group/list.tsx

@@ -1,37 +1,22 @@
 import { useParams, Link } from "react-router-dom";
 import { useIntl } from "react-intl";
-import { Button, Popover, Typography, Dropdown, Menu, MenuProps } from "antd";
-import { ProTable } from "@ant-design/pro-components";
-import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
+import { Button, Popover, Typography, Dropdown, Modal, message } from "antd";
+import { ActionType, ProTable } from "@ant-design/pro-components";
+import {
+  PlusOutlined,
+  DeleteOutlined,
+  ExclamationCircleOutlined,
+} from "@ant-design/icons";
 
-import { get } from "../../../request";
+import { delete_, get } from "../../../request";
 import { IGroupListResponse } from "../../../components/api/Group";
 import GroupCreate from "../../../components/group/GroupCreate";
 import { RoleValueEnum } from "../../../components/studio/table";
+import { IDeleteResponse } from "../../../components/api/Article";
+import { useRef } from "react";
 
 const { Text } = Typography;
 
-const onMenuClick: MenuProps["onClick"] = (e) => {
-  console.log("click", e);
-};
-const menu = (
-  <Menu
-    onClick={onMenuClick}
-    items={[
-      {
-        key: "1",
-        label: "在藏经阁中打开",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "2",
-        label: "分享",
-        icon: <SearchOutlined />,
-      },
-    ]}
-  />
-);
-
 interface DataItem {
   sn: number;
   id: string;
@@ -44,9 +29,48 @@ interface DataItem {
 const Widget = () => {
   const intl = useIntl(); //i18n
   const { studioname } = useParams(); //url 参数
+
+  const showDeleteConfirm = (id: string, title: string) => {
+    Modal.confirm({
+      icon: <ExclamationCircleOutlined />,
+      title:
+        intl.formatMessage({
+          id: "message.delete.sure",
+        }) +
+        intl.formatMessage({
+          id: "message.irrevocable",
+        }),
+
+      content: title,
+      okText: intl.formatMessage({
+        id: "buttons.delete",
+      }),
+      okType: "danger",
+      cancelText: intl.formatMessage({
+        id: "buttons.no",
+      }),
+      onOk() {
+        console.log("delete", id);
+        return delete_<IDeleteResponse>(`/v2/group/${id}`)
+          .then((json) => {
+            if (json.ok) {
+              message.success("删除成功");
+              ref.current?.reload();
+            } else {
+              message.error(json.message);
+            }
+          })
+          .catch((e) => console.log("Oops errors!", e));
+      },
+    });
+  };
+
+  const ref = useRef<ActionType>();
+
   return (
     <>
       <ProTable<DataItem>
+        actionRef={ref}
         columns={[
           {
             title: intl.formatMessage({
@@ -107,7 +131,40 @@ const Widget = () => {
             width: 120,
             valueType: "option",
             render: (text, row, index, action) => [
-              <Dropdown.Button type="link" key={index} overlay={menu}>
+              <Dropdown.Button
+                key={index}
+                type="link"
+                menu={{
+                  items: [
+                    {
+                      key: "remove",
+                      label: (
+                        <Text type="danger">
+                          {intl.formatMessage({
+                            id: "buttons.delete",
+                          })}
+                        </Text>
+                      ),
+                      icon: (
+                        <Text type="danger">
+                          <DeleteOutlined />
+                        </Text>
+                      ),
+                    },
+                  ],
+                  onClick: (e) => {
+                    switch (e.key) {
+                      case "share":
+                        break;
+                      case "remove":
+                        showDeleteConfirm(row.id, row.name);
+                        break;
+                      default:
+                        break;
+                    }
+                  },
+                }}
+              >
                 <Link to={`/studio/${studioname}/group/${row.id}/edit`}>
                   {intl.formatMessage({
                     id: "buttons.edit",
@@ -160,7 +217,14 @@ const Widget = () => {
         }}
         toolBarRender={() => [
           <Popover
-            content={<GroupCreate studio={studioname} />}
+            content={
+              <GroupCreate
+                studio={studioname}
+                onCreate={() => {
+                  ref.current?.reload();
+                }}
+              />
+            }
             placement="bottomRight"
           >
             <Button key="button" icon={<PlusOutlined />} type="primary">

+ 89 - 34
dashboard/src/pages/studio/term/list.tsx

@@ -1,38 +1,27 @@
 import { useParams } from "react-router-dom";
-import { ProTable } from "@ant-design/pro-components";
+import { ActionType, ProTable } from "@ant-design/pro-components";
 import { useIntl } from "react-intl";
-import { Button, Space, Table, Dropdown, Menu, MenuProps } from "antd";
 import {
-  SearchOutlined,
-  DeleteOutlined,
-  ShareAltOutlined,
-} from "@ant-design/icons";
+  Button,
+  Space,
+  Table,
+  Dropdown,
+  Typography,
+  Modal,
+  message,
+} from "antd";
+import { ExclamationCircleOutlined, DeleteOutlined } from "@ant-design/icons";
 
-import { ITermListResponse } from "../../../components/api/Term";
-import { get } from "../../../request";
+import {
+  ITermDeleteRequest,
+  ITermListResponse,
+} from "../../../components/api/Term";
+import { delete_, delete_2, get } from "../../../request";
 import TermCreate from "../../../components/term/TermCreate";
+import { IDeleteResponse } from "../../../components/api/Article";
+import { useRef } from "react";
 
-const onMenuClick: MenuProps["onClick"] = (e) => {
-  console.log("click", e);
-};
-
-const menu = (
-  <Menu
-    onClick={onMenuClick}
-    items={[
-      {
-        key: "1",
-        label: "更多查询",
-        icon: <SearchOutlined />,
-      },
-      {
-        key: "3",
-        label: "删除",
-        icon: <DeleteOutlined />,
-      },
-    ]}
-  />
-);
+const { Text } = Typography;
 
 interface IItem {
   sn: number;
@@ -50,9 +39,53 @@ const Widget = () => {
   const intl = useIntl();
   const { studioname } = useParams();
 
+  const showDeleteConfirm = (id: string, title: string) => {
+    Modal.confirm({
+      icon: <ExclamationCircleOutlined />,
+      title:
+        intl.formatMessage({
+          id: "message.delete.sure",
+        }) +
+        intl.formatMessage({
+          id: "message.irrevocable",
+        }),
+
+      content: title,
+      okText: intl.formatMessage({
+        id: "buttons.delete",
+      }),
+      okType: "danger",
+      cancelText: intl.formatMessage({
+        id: "buttons.no",
+      }),
+      onOk() {
+        console.log("delete", id);
+        return delete_2<ITermDeleteRequest, IDeleteResponse>(
+          `/v2/terms/${id}`,
+          {
+            uuid: true,
+            id: [id],
+          }
+        )
+          .then((json) => {
+            if (json.ok) {
+              message.success("删除成功");
+              ref.current?.reload();
+            } else {
+              message.error(json.message);
+            }
+          })
+          .catch((e) => console.log("Oops errors!", e));
+      },
+    });
+  };
+
+  const ref = useRef<ActionType>();
+
   return (
     <>
       <ProTable<IItem>
+        actionRef={ref}
         columns={[
           {
             title: intl.formatMessage({
@@ -150,11 +183,33 @@ const Widget = () => {
                 <Dropdown.Button
                   key={index}
                   type="link"
-                  overlay={menu}
-                  onClick={() => {
-                    //setWordId(row.wordId);
-                    //setDrawerTitle(row.word);
-                    //setIsEditOpen(true);
+                  menu={{
+                    items: [
+                      {
+                        key: "remove",
+                        label: (
+                          <Text type="danger">
+                            {intl.formatMessage({
+                              id: "buttons.delete",
+                            })}
+                          </Text>
+                        ),
+                        icon: (
+                          <Text type="danger">
+                            <DeleteOutlined />
+                          </Text>
+                        ),
+                      },
+                    ],
+                    onClick: (e) => {
+                      switch (e.key) {
+                        case "remove":
+                          showDeleteConfirm(row.id, row.word);
+                          break;
+                        default:
+                          break;
+                      }
+                    },
                   }}
                 >
                   <TermCreate