Просмотр исходного кода

:construction: 从服务器读取discussion 并显示

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

+ 5 - 0
dashboard/src/components/api/Comment.ts

@@ -2,8 +2,13 @@ import { IUserRequest } from "./Auth";
 
 export interface ICommentRequest {
   id?: string;
+  res_id?: string;
+  res_type?: string;
+  title?: string;
   content?: string;
+  parent?: string;
   editor?: IUserRequest;
+  created_at?: string;
   updated_at?: string;
 }
 

+ 25 - 10
dashboard/src/components/comment/CommentBox.tsx

@@ -1,15 +1,20 @@
 import { useState } from "react";
-import { Button, Drawer } from "antd";
+import { Drawer } from "antd";
 import CommentTopic from "./CommentTopic";
 import CommentListCard from "./CommentListCard";
+import { IComment } from "./CommentItem";
 
 interface IWidget {
   trigger?: JSX.Element;
+  resId?: string;
+  resType?: string;
+  onCommentCountChange?: Function;
 }
-const Widget = ({ trigger }: IWidget) => {
+const Widget = ({ trigger, resId, resType, onCommentCountChange }: IWidget) => {
   const [open, setOpen] = useState(false);
   const [childrenDrawer, setChildrenDrawer] = useState(false);
-
+  const [topicComment, setTopicComment] = useState<IComment>();
+  console.log(resId, resType);
   const showDrawer = () => {
     setOpen(true);
   };
@@ -18,8 +23,12 @@ const Widget = ({ trigger }: IWidget) => {
     setOpen(false);
   };
 
-  const showChildrenDrawer = () => {
+  const showChildrenDrawer = (
+    e: React.MouseEvent<HTMLSpanElement, MouseEvent>,
+    comment: IComment
+  ) => {
     setChildrenDrawer(true);
+    setTopicComment(comment);
   };
 
   const onChildrenDrawerClose = () => {
@@ -30,16 +39,22 @@ const Widget = ({ trigger }: IWidget) => {
     <>
       <span onClick={showDrawer}>{trigger}</span>
       <Drawer
-        title="Multi-level drawer"
+        title="Discussion"
         width={520}
         closable={false}
         onClose={onClose}
         open={open}
       >
-        <Button type="primary" onClick={showChildrenDrawer}>
-          Two-level drawer
-        </Button>
-        <CommentListCard resId="" onSelect={showChildrenDrawer} />
+        <CommentListCard
+          resId={resId}
+          resType={resType}
+          onSelect={showChildrenDrawer}
+          onItemCountChange={(count: number) => {
+            if (typeof onCommentCountChange !== "undefined") {
+              onCommentCountChange(count);
+            }
+          }}
+        />
         <Drawer
           title="Two-level Drawer"
           width={480}
@@ -47,7 +62,7 @@ const Widget = ({ trigger }: IWidget) => {
           onClose={onChildrenDrawerClose}
           open={childrenDrawer}
         >
-          <CommentTopic resId="" />
+          <CommentTopic comment={topicComment} resId="" />
         </Drawer>
       </Drawer>
     </>

+ 98 - 0
dashboard/src/components/comment/CommentCreate.tsx

@@ -0,0 +1,98 @@
+import { useState } from "react";
+import { useIntl } from "react-intl";
+import { Button, Card } from "antd";
+import { Input, message } from "antd";
+import { SaveOutlined } from "@ant-design/icons";
+import {
+  ProForm,
+  ProFormText,
+  ProFormTextArea,
+} from "@ant-design/pro-components";
+import { Col, Row, Space } from "antd";
+
+import { IComment } from "./CommentItem";
+import { post } from "../../request";
+import { ICommentRequest, ICommentResponse } from "../api/Comment";
+
+interface IWidget {
+  data: IComment;
+  onCreated?: Function;
+}
+const Widget = ({ data, onCreated }: IWidget) => {
+  const intl = useIntl();
+
+  const formItemLayout = {
+    labelCol: { span: 4 },
+    wrapperCol: { span: 20 },
+  };
+  return (
+    <div>
+      <ProForm<IComment>
+        {...formItemLayout}
+        layout="horizontal"
+        submitter={{
+          render: (props, doms) => {
+            return (
+              <Row>
+                <Col span={14} offset={4}>
+                  <Space>{doms}</Space>
+                </Col>
+              </Row>
+            );
+          },
+        }}
+        onFinish={async (values) => {
+          //新建
+          post<ICommentRequest, ICommentResponse>(`/v2/discussion`, {
+            res_id: data.resId,
+            res_type: data.resType,
+            title: values.title,
+            content: values.content,
+          })
+            .then((json) => {
+              console.log(json);
+              if (json.ok) {
+                message.success(intl.formatMessage({ id: "flashes.success" }));
+                if (typeof onCreated !== "undefined") {
+                  onCreated(json.data);
+                }
+              } else {
+                message.error(json.message);
+              }
+            })
+            .catch((e) => {
+              message.error(e.message);
+            });
+        }}
+        params={{}}
+        request={async () => {
+          return data;
+        }}
+      >
+        {data.parent ? (
+          <></>
+        ) : (
+          <ProFormText
+            name="title"
+            label={intl.formatMessage({ id: "forms.fields.title.label" })}
+            tooltip="最长为 24 位"
+            placeholder={intl.formatMessage({
+              id: "forms.message.title.required",
+            })}
+            rules={[{ required: true, message: "这是必填项" }]}
+          />
+        )}
+
+        <ProFormTextArea
+          name="content"
+          label={intl.formatMessage({ id: "forms.fields.content.label" })}
+          placeholder={intl.formatMessage({
+            id: "forms.fields.content.placeholder",
+          })}
+        />
+      </ProForm>
+    </div>
+  );
+};
+
+export default Widget;

+ 78 - 4
dashboard/src/components/comment/CommentEdit.tsx

@@ -3,17 +3,24 @@ import { useIntl } from "react-intl";
 import { Button, Card } from "antd";
 import { Input, message } from "antd";
 import { SaveOutlined } from "@ant-design/icons";
+import {
+  ProForm,
+  ProFormText,
+  ProFormTextArea,
+} from "@ant-design/pro-components";
+import { Col, Row, Space } from "antd";
 
 import { IComment } from "./CommentItem";
-import { put } from "../../request";
+import { post, put } from "../../request";
 import { ICommentRequest, ICommentResponse } from "../api/Comment";
 
 const { TextArea } = Input;
 
 interface IWidget {
   data: IComment;
+  onCreated?: Function;
 }
-const Widget = ({ data }: IWidget) => {
+const Widget = ({ data, onCreated }: IWidget) => {
   const intl = useIntl();
   const [value, setValue] = useState(data.content);
 
@@ -21,7 +28,7 @@ const Widget = ({ data }: IWidget) => {
 
   const save = () => {
     setSaving(true);
-    put<ICommentRequest, ICommentResponse>(`/v2/comment/${data.id}`, {
+    put<ICommentRequest, ICommentResponse>(`/v2/discussion/${data.id}`, {
       content: value,
     })
       .then((json) => {
@@ -40,9 +47,76 @@ const Widget = ({ data }: IWidget) => {
         message.error(e.message);
       });
   };
-
+  const formItemLayout = {
+    labelCol: { span: 4 },
+    wrapperCol: { span: 20 },
+  };
   return (
     <div>
+      <ProForm<IComment>
+        {...formItemLayout}
+        layout="horizontal"
+        submitter={{
+          render: (props, doms) => {
+            return (
+              <Row>
+                <Col span={14} offset={4}>
+                  <Space>{doms}</Space>
+                </Col>
+              </Row>
+            );
+          },
+        }}
+        onFinish={async (values) => {
+          if (typeof values.id === "undefined") {
+            //新建
+            post<ICommentRequest, ICommentResponse>(`/v2/discussion`, {
+              res_id: data.resId,
+              res_type: data.resType,
+              title: values.title,
+              content: values.content,
+            })
+              .then((json) => {
+                console.log(json);
+                if (json.ok) {
+                  message.success(
+                    intl.formatMessage({ id: "flashes.success" })
+                  );
+                  if (typeof onCreated !== "undefined") {
+                    onCreated(json.data);
+                  }
+                } else {
+                  message.error(json.message);
+                }
+              })
+              .catch((e) => {
+                message.error(e.message);
+              });
+          } else {
+            //修改
+          }
+        }}
+        params={{}}
+        request={async () => {
+          return data;
+        }}
+      >
+        <ProFormText
+          name="title"
+          label={intl.formatMessage({ id: "forms.fields.title.label" })}
+          tooltip="最长为 24 位"
+          placeholder={intl.formatMessage({
+            id: "forms.message.title.required",
+          })}
+        />
+        <ProFormTextArea
+          name="content"
+          label={intl.formatMessage({ id: "forms.fields.content.label" })}
+          placeholder={intl.formatMessage({
+            id: "forms.fields.content.placeholder",
+          })}
+        />
+      </ProForm>
       <Card
         title={<span>{data.user.nickName}</span>}
         extra={

+ 13 - 2
dashboard/src/components/comment/CommentItem.tsx

@@ -6,7 +6,10 @@ import CommentEdit from "./CommentEdit";
 
 export interface IComment {
   id?: string; //id未提供为新建
+  resId?: string;
+  resType?: string;
   user: IUser;
+  parent?: string;
   title?: string;
   content?: string;
   children?: IComment[];
@@ -17,8 +20,9 @@ interface IWidget {
   data: IComment;
   create?: boolean;
   onSelect?: Function;
+  onCreated?: Function;
 }
-const Widget = ({ data, create = false, onSelect }: IWidget) => {
+const Widget = ({ data, create = false, onSelect, onCreated }: IWidget) => {
   const [edit, setEdit] = useState(false);
 
   return (
@@ -28,7 +32,14 @@ const Widget = ({ data, create = false, onSelect }: IWidget) => {
       </div>
       <div style={{ flex: "auto" }}>
         {edit || create ? (
-          <CommentEdit data={data} />
+          <CommentEdit
+            data={data}
+            onCreated={(e: IComment) => {
+              if (typeof onCreated !== "undefined") {
+                onCreated(e);
+              }
+            }}
+          />
         ) : (
           <CommentShow
             data={data}

+ 2 - 3
dashboard/src/components/comment/CommentList.tsx

@@ -1,8 +1,7 @@
-import { Card, List, Avatar, Space } from "antd";
+import { List, Avatar, Space } from "antd";
 import { MessageOutlined } from "@ant-design/icons";
 
 import { IComment } from "./CommentItem";
-import { Link } from "react-router-dom";
 
 interface IWidget {
   data: IComment[];
@@ -34,7 +33,7 @@ const Widget = ({ data, onSelect }: IWidget) => {
                 <span
                   onClick={(e) => {
                     if (typeof onSelect !== "undefined") {
-                      onSelect(e);
+                      onSelect(e, item);
                     }
                   }}
                 >

+ 78 - 22
dashboard/src/components/comment/CommentListCard.tsx

@@ -1,42 +1,98 @@
-import { Card } from "antd";
-import { useState } from "react";
+import { Card, message } from "antd";
+import { useState, useEffect } from "react";
+import { useIntl } from "react-intl";
+import { useAppSelector } from "../../hooks";
+import { currentUser as _currentUser } from "../../reducers/current-user";
+import { get } from "../../request";
+import { ICommentListResponse } from "../api/Comment";
+import CommentCreate from "./CommentCreate";
 
 import { IComment } from "./CommentItem";
 import CommentList from "./CommentList";
 
-const defaultData: IComment[] = Array(5)
-  .fill(3)
-  .map((item, id) => {
-    return {
-      id: "dd",
-      content: "评论内容",
-      title: "评论标题" + id,
-      user: {
-        id: "string",
-        nickName: "Visuddhinanda",
-        realName: "Visuddhinanda",
-        avatar: "",
-      },
-    };
-  });
 interface IWidget {
-  resId: string;
+  resId?: string;
+  resType?: string;
   onSelect?: Function;
+  onItemCountChange?: Function;
 }
-const Widget = ({ resId, onSelect }: IWidget) => {
-  const [data, setData] = useState<IComment[]>(defaultData);
+const Widget = ({ resId, resType, onSelect, onItemCountChange }: IWidget) => {
+  const intl = useIntl();
+  const [data, setData] = useState<IComment[]>([]);
+
+  const _currUser = useAppSelector(_currentUser);
+  useEffect(() => {
+    get<ICommentListResponse>(`/v2/discussion?view=res_id&id=${resId}`)
+      .then((json) => {
+        console.log(json);
+        if (json.ok) {
+          message.success(intl.formatMessage({ id: "flashes.success" }));
+          const discussions: IComment[] = json.data.rows.map((item) => {
+            return {
+              id: item.id,
+              resId: item.res_id,
+              resType: item.res_type,
+              user: {
+                id: item.editor?.id ? item.editor.id : "",
+                nickName: item.editor?.nickName ? item.editor.nickName : "",
+                realName: item.editor?.userName ? item.editor.userName : "",
+                avatar: item.editor?.avatar ? item.editor.avatar : "",
+              },
+              title: item.title,
+              content: item.content,
+              createdAt: item.created_at,
+              updatedAt: item.updated_at,
+            };
+          });
+          setData(discussions);
+        } else {
+          message.error(json.message);
+        }
+      })
+      .catch((e) => {
+        message.error(e.message);
+      });
+  }, [intl]);
+
+  if (typeof resId === "undefined") {
+    return <div>该资源尚未创建,不能发表讨论。</div>;
+  }
 
   return (
     <div>
       <Card title="问题列表" extra={<a href="#">More</a>}>
         <CommentList
-          onSelect={(e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
+          onSelect={(
+            e: React.MouseEvent<HTMLSpanElement, MouseEvent>,
+            comment: IComment
+          ) => {
             if (typeof onSelect !== "undefined") {
-              onSelect(e);
+              onSelect(e, comment);
             }
           }}
           data={data}
         />
+        {
+          <CommentCreate
+            data={{
+              resId: resId,
+              resType: resType,
+              user: {
+                id: "string",
+                nickName: _currUser ? _currUser.nickName : "Visuddhinanda",
+                realName: _currUser ? _currUser.realName : "Visuddhinanda",
+                avatar: _currUser ? _currUser.avatar : "",
+              },
+            }}
+            onCreated={(e: IComment) => {
+              // const orgData = JSON.parse(JSON.stringify(data));
+              if (typeof onItemCountChange !== "undefined") {
+                onItemCountChange(data.length + 1);
+              }
+              setData([...data, e]);
+            }}
+          />
+        }
       </Card>
     </div>
   );

+ 4 - 4
dashboard/src/components/comment/CommentTopic.tsx

@@ -23,17 +23,17 @@ const defaultData: IComment[] = Array(5)
 
 interface IWidget {
   resId: string;
+  comment?: IComment;
 }
-const Widget = ({ resId }: IWidget) => {
+const Widget = ({ resId, comment }: IWidget) => {
   const [childrenData, setChildrenData] = useState<IComment[]>(defaultData);
-  const [data, setData] = useState<IComment>();
 
   return (
     <div>
-      <CommentTopicHead data={data} />
+      <CommentTopicHead data={comment} />
       <Divider />
       <CommentTopicList data={childrenData} />
-      {data ? <CommentItem data={data} create={true} /> : undefined}
+      {comment ? <CommentItem data={comment} create={true} /> : undefined}
     </div>
   );
 };

+ 2 - 5
dashboard/src/components/comment/CommentTopicList.tsx

@@ -1,14 +1,11 @@
-import { Card, List, Avatar, Space } from "antd";
-import { MessageOutlined } from "@ant-design/icons";
+import { List } from "antd";
 
 import CommentItem, { IComment } from "./CommentItem";
-import { Link } from "react-router-dom";
 
 interface IWidget {
   data: IComment[];
-  onSelect?: Function;
 }
-const Widget = ({ data, onSelect }: IWidget) => {
+const Widget = ({ data }: IWidget) => {
   return (
     <div>
       <List

+ 19 - 6
dashboard/src/components/template/Wbw/WbwPali.tsx

@@ -23,6 +23,7 @@ const Widget = ({ data, onSave }: IWidget) => {
   const [click, setClicked] = useState(false);
   const [paliColor, setPaliColor] = useState("unset");
   const [isHover, setIsHover] = useState(false);
+  const [hasComment, setHasComment] = useState(data.hasComment);
 
   const handleClickChange = (open: boolean) => {
     if (open) {
@@ -106,12 +107,24 @@ const Widget = ({ data, onSave }: IWidget) => {
       {data.word.value}
     </span>
   );
-
-  const discussionIcon = isHover ? (
-    <CommentBox trigger={<CommentOutlined style={{ cursor: "pointer" }} />} />
-  ) : (
-    <></>
-  );
+  console.log(data);
+  const discussionIcon =
+    isHover || hasComment ? (
+      <CommentBox
+        resId={data.uid}
+        resType="wbw"
+        trigger={<CommentOutlined style={{ cursor: "pointer" }} />}
+        onCommentCountChange={(count: number) => {
+          if (count > 0) {
+            setHasComment(true);
+          } else {
+            setHasComment(false);
+          }
+        }}
+      />
+    ) : (
+      <></>
+    );
   if (typeof data.real !== "undefined" && PaliReal(data.real.value) !== "") {
     //非标点符号
     return (

+ 2 - 0
dashboard/src/components/template/Wbw/WbwWord.tsx

@@ -57,6 +57,7 @@ interface WbwElement3 {
   status: WbwStatus;
 }
 export interface IWbw {
+  uid?: string;
   word: WbwElement;
   real?: WbwElement;
   meaning?: WbwElement2;
@@ -74,6 +75,7 @@ export interface IWbw {
   locked?: boolean;
   confidence: number;
   attachments?: UploadFile[];
+  hasComment?: boolean;
 }
 export interface IWbwFields {
   meaning?: boolean;

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

@@ -12,6 +12,7 @@ const items = {
   "forms.fields.subtitle.label": "副标题",
   "forms.fields.summary.label": "简介",
   "forms.fields.content.label": "内容",
+  "forms.fields.content.placeholder": "请输入内容",
   "forms.fields.tag.label": "标签",
   "forms.fields.power.label": "权限",
   "forms.fields.type.label": "类型",