Term.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import { useEffect, useState } from "react";
  2. import { Link } from "react-router-dom";
  3. import { Button, Popover, Skeleton, Space } from "antd";
  4. import { Typography } from "antd";
  5. import { SearchOutlined, EditOutlined } from "@ant-design/icons";
  6. import store from "../../store";
  7. import TermModal from "../term/TermModal";
  8. import { ITerm } from "../term/TermEdit";
  9. import { ITermDataResponse } from "../api/Term";
  10. import { changedTerm, refresh } from "../../reducers/term-change";
  11. import { useAppSelector } from "../../hooks";
  12. import { get } from "../../request";
  13. import { fullUrl } from "../../utils";
  14. const { Text, Title } = Typography;
  15. interface ITermSummary {
  16. ok: boolean;
  17. message: string;
  18. data: string;
  19. }
  20. interface IWidgetTermCtl {
  21. id?: string;
  22. word?: string;
  23. meaning?: string;
  24. meaning2?: string;
  25. channel?: string /**该术语在term表中的channel_id */;
  26. parentChannelId?: string /**该术语所在译文的channel_id */;
  27. parentStudioId?: string /**该术语所在译文的studio_id */;
  28. summary?: string;
  29. isCommunity?: string;
  30. }
  31. const TermCtl = ({
  32. id,
  33. word,
  34. meaning,
  35. meaning2,
  36. channel,
  37. parentChannelId,
  38. parentStudioId,
  39. summary,
  40. isCommunity,
  41. }: IWidgetTermCtl) => {
  42. const [openPopover, setOpenPopover] = useState(false);
  43. const [termData, setTermData] = useState<ITerm>();
  44. const [content, setContent] = useState<string>();
  45. const newTerm: ITermDataResponse | undefined = useAppSelector(changedTerm);
  46. useEffect(() => {
  47. setTermData({
  48. id: id,
  49. word: word,
  50. meaning: meaning,
  51. meaning2: meaning2?.split(","),
  52. summary: summary,
  53. channelId: channel,
  54. });
  55. }, [id, meaning, meaning2, channel, summary, word]);
  56. useEffect(() => {
  57. if (newTerm?.word === word) {
  58. setTermData({
  59. id: newTerm?.guid,
  60. word: newTerm?.word,
  61. meaning: newTerm?.meaning,
  62. meaning2: newTerm?.other_meaning?.split(","),
  63. summary: newTerm?.note ? newTerm?.note : "",
  64. channelId: newTerm?.channal,
  65. });
  66. }
  67. }, [newTerm, word]);
  68. const onModalClose = () => {
  69. if (document.getElementsByTagName("body")[0].hasAttribute("style")) {
  70. document.getElementsByTagName("body")[0].removeAttribute("style");
  71. }
  72. };
  73. if (typeof termData?.id === "string") {
  74. return (
  75. <>
  76. <Popover
  77. title={
  78. <Space style={{ justifyContent: "space-between", width: "100%" }}>
  79. <Text strong>{termData.meaning}</Text>
  80. <Space>
  81. <Button
  82. onClick={() => {
  83. window.open(
  84. fullUrl(`/term/list/${termData.word}`),
  85. "_blank"
  86. );
  87. }}
  88. type="link"
  89. size="small"
  90. icon={<SearchOutlined />}
  91. />
  92. <TermModal
  93. onUpdate={(value: ITermDataResponse) => {
  94. onModalClose();
  95. store.dispatch(refresh(value));
  96. }}
  97. onClose={() => {
  98. onModalClose();
  99. }}
  100. trigger={
  101. <Button
  102. onClick={() => {
  103. setOpenPopover(false);
  104. }}
  105. type="link"
  106. size="small"
  107. icon={<EditOutlined />}
  108. />
  109. }
  110. id={termData.id}
  111. word={termData.word}
  112. channelId={termData.channelId}
  113. parentChannelId={parentChannelId}
  114. parentStudioId={parentStudioId}
  115. />
  116. </Space>
  117. </Space>
  118. }
  119. open={openPopover}
  120. onOpenChange={(visible) => {
  121. setOpenPopover(visible);
  122. if (
  123. visible &&
  124. typeof content === "undefined" &&
  125. typeof id !== "undefined"
  126. ) {
  127. const value = sessionStorage.getItem(`term/summary/${id}`);
  128. if (value !== null) {
  129. setContent(value);
  130. return;
  131. } else {
  132. const url = `/v2/term-summary/${id}`;
  133. console.log("url", url);
  134. get<ITermSummary>(url).then((json) => {
  135. if (json.ok) {
  136. setContent(json.data !== "" ? json.data : " ");
  137. sessionStorage.setItem(`term/summary/${id}`, json.data);
  138. }
  139. });
  140. }
  141. }
  142. }}
  143. content={
  144. <div style={{ maxWidth: 500, minWidth: 300 }}>
  145. <Title level={5}>
  146. <Link to={`/term/list/${termData.word}`} target="_blank">
  147. {word}
  148. </Link>
  149. </Title>
  150. {content ? (
  151. content
  152. ) : (
  153. <Skeleton
  154. title={{ width: 200 }}
  155. paragraph={{ rows: 4 }}
  156. active
  157. />
  158. )}
  159. </div>
  160. }
  161. placement="bottom"
  162. >
  163. <Typography.Link style={{ color: isCommunity ? "green" : undefined }}>
  164. {termData?.meaning
  165. ? termData?.meaning
  166. : termData?.word
  167. ? termData?.word
  168. : "unknown"}
  169. </Typography.Link>
  170. </Popover>
  171. {"("}
  172. <Text italic>{word}</Text>
  173. {termData?.meaning2 ? (
  174. <Text>{`,${termData?.meaning2}`}</Text>
  175. ) : undefined}
  176. {")"}
  177. </>
  178. );
  179. } else {
  180. //术语未创建
  181. return (
  182. <TermModal
  183. onUpdate={(value: ITermDataResponse) => {
  184. onModalClose();
  185. store.dispatch(refresh(value));
  186. }}
  187. onClose={() => {
  188. onModalClose();
  189. }}
  190. trigger={
  191. <Typography.Link>
  192. <Text type="danger">{termData?.word}</Text>
  193. </Typography.Link>
  194. }
  195. word={termData?.word}
  196. parentChannelId={parentChannelId}
  197. parentStudioId={parentStudioId}
  198. />
  199. );
  200. }
  201. };
  202. interface IWidgetTerm {
  203. props: string;
  204. }
  205. const Widget = ({ props }: IWidgetTerm) => {
  206. const prop = JSON.parse(atob(props)) as IWidgetTermCtl;
  207. return (
  208. <>
  209. <TermCtl {...prop} />
  210. </>
  211. );
  212. };
  213. export default Widget;