| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- import {
- Badge,
- Card,
- Dropdown,
- type 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 type { IUser } from "../auth/User";
- import type { ITermListResponse } from "../../api/Term";
- import { Link } from "react-router";
- const { Title, 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 [show, setShow] = useState(false);
- const [wordData, setWordData] = useState<IWord>();
- const minScore = 100; //分数阈值。低于这个分数只显示在弹出菜单中
- useEffect(() => {
- if (typeof word === "undefined") {
- return;
- }
- const url = `/v2/terms?view=word&word=${word}&exp=1`;
- console.log("url", url);
- get<ITermListResponse>(url)
- .then((json) => {
- if (json.ok === false) {
- return;
- }
- const meaning = new Map<string, number>();
- const note = new Map<string, number>();
- const editorId = new Map<string, number>();
- const 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);
- const noteScore = it.note.length;
- note.set(it.note, score ? score + noteScore : noteScore);
- }
- 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);
- }
- }
- const _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);
- if (_data.editor.length > 0) {
- setShow(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
- style={{ display: "none" }}
- 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 }}>
- <Typography.Link>
- <Space>
- {intl.formatMessage({
- id: `buttons.more`,
- })}
- <DownOutlined />
- </Space>
- </Typography.Link>
- </Dropdown>
- ) : undefined
- ) : undefined;
- return show ? (
- <Card>
- <Space>
- <Title level={5} id={`community`}>
- {"社区术语"}
- </Title>
- <Link to={`/term/list/${word}`}>详情</Link>
- </Space>
- <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
- style={{ display: "none" }}
- color="geekblue"
- size="small"
- count={item.score}
- />
- </Space>
- );
- })}
- {meaningLow && meaningLow.length > 0 ? (
- <Popover content={<Space>{meaningExtra}</Space>} placement="bottom">
- <Typography.Link>
- <Space>
- {intl.formatMessage({
- id: `buttons.more`,
- })}
- <DownOutlined />
- </Space>
- </Typography.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;
|