visuddhinanda 2 سال پیش
والد
کامیت
de4a9d6ea2
1فایلهای تغییر یافته به همراه229 افزوده شده و 0 حذف شده
  1. 229 0
      dashboard/src/components/term/TermCommunity.tsx

+ 229 - 0
dashboard/src/components/term/TermCommunity.tsx

@@ -0,0 +1,229 @@
+import {
+  Badge,
+  Card,
+  Dropdown,
+  MenuProps,
+  Popover,
+  Space,
+  Typography,
+} from "antd";
+import { DownOutlined } from "@ant-design/icons";
+import { useState, useEffect } from "react";
+import { useIntl } from "react-intl";
+import { get } from "../../request";
+import { IUser } from "../auth/User";
+import { ITermListResponse } from "../api/Term";
+
+const { Title, Link, Text } = Typography;
+
+interface IItem<R> {
+  value: R;
+  score: number;
+}
+interface IWord {
+  meaning: IItem<string>[];
+  note: IItem<string>[];
+  editor: IItem<IUser>[];
+}
+
+interface IWidget {
+  word: string | undefined;
+}
+const TermCommunityWidget = ({ word }: IWidget) => {
+  const intl = useIntl();
+  const [loaded, setLoaded] = useState(false);
+  const [wordData, setWordData] = useState<IWord>();
+  const minScore = 100; //分数阈值。低于这个分数只显示在弹出菜单中
+
+  useEffect(() => {
+    if (typeof word === "undefined") {
+      return;
+    }
+    const url = `/v2/terms?view=word&word=${word}`;
+    console.log("url", url);
+    get<ITermListResponse>(url)
+      .then((json) => {
+        if (json.ok === false) {
+          console.log("dict community", json.message);
+          return;
+        }
+        console.log("count", json.data);
+        let meaning = new Map<string, number>();
+        let note = new Map<string, number>();
+        let editorId = new Map<string, number>();
+        let editor = new Map<string, IUser>();
+        for (const it of json.data.rows) {
+          let score: number | undefined;
+          let currScore = 100;
+          if (it.exp) {
+            //分数计算
+            currScore = Math.floor(it.exp / 3600);
+          }
+          if (it.meaning) {
+            score = meaning.get(it.meaning);
+            meaning.set(it.meaning, score ? score + currScore : currScore);
+          }
+
+          if (it.note) {
+            score = note.get(it.note);
+            note.set(it.note, score ? score + currScore : currScore);
+          }
+
+          if (it.editor) {
+            score = editorId.get(it.editor.id);
+            editorId.set(it.editor.id, score ? score + currScore : currScore);
+            editor.set(it.editor.id, it.editor);
+          }
+        }
+        let _data: IWord = {
+          meaning: [],
+          note: [],
+          editor: [],
+        };
+        meaning.forEach((value, key, map) => {
+          if (key && key.length > 0) {
+            _data.meaning.push({ value: key, score: value });
+          }
+        });
+        _data.meaning.sort((a, b) => b.score - a.score);
+        note.forEach((value, key, map) => {
+          if (key && key.length > 0) {
+            _data.note.push({ value: key, score: value });
+          }
+        });
+        _data.note.sort((a, b) => b.score - a.score);
+
+        editorId.forEach((value, key, map) => {
+          const currEditor = editor.get(key);
+          if (currEditor) {
+            _data.editor.push({ value: currEditor, score: value });
+          }
+        });
+        _data.editor.sort((a, b) => b.score - a.score);
+        setWordData(_data);
+        console.log("_data", _data);
+        if (_data.editor.length > 0) {
+          setLoaded(true);
+        }
+      })
+      .catch((error) => {
+        console.error(error);
+      });
+  }, [word, setWordData]);
+
+  const isShow = (score: number, index: number) => {
+    const Ms = 500,
+      Rd = 5,
+      minScore = 15;
+    const minOrder = Math.log(score) / Math.log(Math.pow(Ms, 1 / Rd));
+    if (index < minOrder && score > minScore) {
+      return true;
+    } else {
+      return false;
+    }
+  };
+
+  const meaningLow = wordData?.meaning.filter(
+    (value, index: number) => !isShow(value.score, index)
+  );
+  const meaningExtra = meaningLow?.map((item, id) => {
+    return <span key={id}>{item.value}</span>;
+  });
+
+  const mainCollaboratorNum = 3; //默认显示的协作者数量,其余的在更多中显示
+  const collaboratorRender = (name: string, id: number, score: number) => {
+    return (
+      <Space key={id}>
+        {name}
+        <Badge color="geekblue" size="small" count={score} />
+      </Space>
+    );
+  };
+  const items: MenuProps["items"] = wordData?.editor
+    .filter((value, index) => index >= mainCollaboratorNum)
+    .map((item, id) => {
+      return {
+        key: id,
+        label: collaboratorRender(item.value.nickName, id, item.score),
+      };
+    });
+  const more = wordData ? (
+    wordData.editor.length > mainCollaboratorNum ? (
+      <Dropdown menu={{ items }}>
+        <Link>
+          <Space>
+            {intl.formatMessage({
+              id: `buttons.more`,
+            })}
+            <DownOutlined />
+          </Space>
+        </Link>
+      </Dropdown>
+    ) : undefined
+  ) : undefined;
+
+  return loaded ? (
+    <Card>
+      <Title level={5} id={`community`}>
+        {"社区术语"}
+      </Title>
+      <div key="meaning">
+        <Space style={{ flexWrap: "wrap" }}>
+          <Text strong>{"意思:"}</Text>
+          {wordData?.meaning
+            .filter((value, index: number) => isShow(value.score, index))
+            .map((item, id) => {
+              return (
+                <Space key={id}>
+                  {item.value}
+                  <Badge color="geekblue" size="small" count={item.score} />
+                </Space>
+              );
+            })}
+          {meaningLow && meaningLow.length > 0 ? (
+            <Popover content={<Space>{meaningExtra}</Space>} placement="bottom">
+              <Link>
+                <Space>
+                  {intl.formatMessage({
+                    id: `buttons.more`,
+                  })}
+                  <DownOutlined />
+                </Space>
+              </Link>
+            </Popover>
+          ) : undefined}
+        </Space>
+      </div>
+      <div key="note">
+        <Space style={{ flexWrap: "wrap" }}>
+          <Text strong>{"note:"}</Text>
+          {wordData?.note
+            .filter((value) => value.score >= minScore)
+            .map((item, id) => {
+              return (
+                <Space key={id}>
+                  {item.value}
+                  <Badge color="geekblue" size="small" count={item.score} />
+                </Space>
+              );
+            })}
+        </Space>
+      </div>
+      <div key="collaborator">
+        <Space style={{ flexWrap: "wrap" }}>
+          <Text strong>{"贡献者:"}</Text>
+          {wordData?.editor
+            .filter((value, index) => index < mainCollaboratorNum)
+            .map((item, id) => {
+              return collaboratorRender(item.value.nickName, id, item.score);
+            })}
+          {more}
+        </Space>
+      </div>
+    </Card>
+  ) : (
+    <></>
+  );
+};
+
+export default TermCommunityWidget;