WbwCase.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import { useEffect, useState } from "react";
  2. import { IntlShape, useIntl } from "react-intl";
  3. import { Typography, Button, Space } from "antd";
  4. import { SwapOutlined } from "@ant-design/icons";
  5. import type { MenuProps } from "antd";
  6. import { Dropdown } from "antd";
  7. import { LoadingOutlined, FileExclamationOutlined } from "@ant-design/icons";
  8. import { IWbw, TWbwDisplayMode } from "./WbwWord";
  9. import "./wbw.css";
  10. import { useAppSelector } from "../../../hooks";
  11. import { inlineDict as _inlineDict } from "../../../reducers/inline-dict";
  12. import WbwParent2 from "./WbwParent2";
  13. import { IApiResponseDictData } from "../../api/Dict";
  14. export interface ValueType {
  15. key: string;
  16. label: string;
  17. }
  18. const { Text } = Typography;
  19. export const caseInDict = (
  20. wordIn: string,
  21. wordIndex: string[],
  22. wordList: IApiResponseDictData[],
  23. intl: IntlShape
  24. ): MenuProps["items"] => {
  25. if (!wordIn) {
  26. return [];
  27. }
  28. if (wordIndex.includes(wordIn)) {
  29. const result = wordList.filter((word) => word.word === wordIn);
  30. //查重
  31. //TODO 加入信心指数并排序
  32. let myMap = new Map<string, number>();
  33. let factors: string[] = [];
  34. for (const iterator of result) {
  35. myMap.set(iterator.type + "#" + iterator.grammar, 1);
  36. }
  37. myMap.forEach((value, key, map) => {
  38. factors.push(key);
  39. });
  40. const menu = factors.map((item) => {
  41. const arrItem: string[] = item
  42. .replaceAll(".", "")
  43. .replaceAll("#", "$")
  44. .split("$");
  45. let noNull = arrItem.filter((item) => item !== "");
  46. noNull.forEach((item, index, arr) => {
  47. arr[index] = intl.formatMessage({
  48. id: `dict.fields.type.${item}.short.label`,
  49. });
  50. });
  51. return { key: item, label: noNull.join(" ") };
  52. });
  53. if (menu.length > 0) {
  54. return menu;
  55. } else {
  56. return [
  57. {
  58. key: "",
  59. disabled: true,
  60. label: (
  61. <>
  62. <FileExclamationOutlined />{" "}
  63. {intl.formatMessage({
  64. id: "labels.empty",
  65. })}
  66. </>
  67. ),
  68. },
  69. ];
  70. }
  71. } else {
  72. return [
  73. {
  74. key: "",
  75. disabled: true,
  76. label: (
  77. <>
  78. <LoadingOutlined />{" "}
  79. {intl.formatMessage({
  80. id: "labels.loading",
  81. })}
  82. </>
  83. ),
  84. },
  85. ];
  86. }
  87. };
  88. interface IWidget {
  89. data: IWbw;
  90. display?: TWbwDisplayMode;
  91. onSplit?: Function;
  92. onChange?: Function;
  93. }
  94. const WbwCaseWidget = ({ data, display, onSplit, onChange }: IWidget) => {
  95. const intl = useIntl();
  96. const defaultMenu: MenuProps["items"] = [
  97. {
  98. key: "loading",
  99. label: (
  100. <Space>
  101. <LoadingOutlined />
  102. {"Loading"}
  103. </Space>
  104. ),
  105. },
  106. ];
  107. const [items, setItems] = useState<MenuProps["items"]>(defaultMenu);
  108. const inlineDict = useAppSelector(_inlineDict);
  109. useEffect(() => {
  110. if (!data.real.value) {
  111. return;
  112. }
  113. setItems(
  114. caseInDict(
  115. data.real.value,
  116. inlineDict.wordIndex,
  117. inlineDict.wordList,
  118. intl
  119. )
  120. );
  121. }, [data.real.value, inlineDict, intl]);
  122. const onClick: MenuProps["onClick"] = (e) => {
  123. console.log("click ", e);
  124. if (typeof onChange !== "undefined") {
  125. onChange(e.key);
  126. }
  127. };
  128. const showSplit: boolean = data.factors?.value?.includes("+") ? true : false;
  129. let caseElement: JSX.Element | JSX.Element[] | undefined;
  130. if (display === "block") {
  131. if (
  132. typeof data.case?.value === "string" &&
  133. data.case.value?.trim().length > 0
  134. ) {
  135. caseElement = data.case.value
  136. .replace("#", "$")
  137. .split("$")
  138. .map((item, id) => {
  139. if (item !== "") {
  140. const strCase = item.replaceAll(".", "");
  141. return (
  142. <span key={id} className="case">
  143. {intl.formatMessage({
  144. id: `dict.fields.type.${strCase}.short.label`,
  145. })}
  146. </span>
  147. );
  148. } else {
  149. return <span key={id}>-</span>;
  150. }
  151. });
  152. } else {
  153. //空白的语法信息在逐词解析模式显示占位字符串
  154. caseElement = (
  155. <span>{intl.formatMessage({ id: "dict.fields.case.label" })}</span>
  156. );
  157. }
  158. }
  159. if (
  160. typeof data.real?.value === "string" &&
  161. data.real.value.trim().length > 0
  162. ) {
  163. //非标点符号
  164. return (
  165. <div className="wbw_word_item" style={{ display: "flex" }}>
  166. <Text type="secondary">
  167. <div>
  168. <Dropdown
  169. key="dropdown"
  170. menu={{ items, onClick }}
  171. placement="bottomLeft"
  172. >
  173. <span>{caseElement}</span>
  174. </Dropdown>
  175. <WbwParent2 data={data} />
  176. {showSplit ? (
  177. <Button
  178. key="button"
  179. className="wbw_split"
  180. size="small"
  181. shape="circle"
  182. icon={<SwapOutlined />}
  183. onClick={() => {
  184. if (typeof onSplit !== "undefined") {
  185. onSplit(true);
  186. }
  187. }}
  188. />
  189. ) : undefined}
  190. </div>
  191. </Text>
  192. </div>
  193. );
  194. } else {
  195. //标点符号
  196. return <></>;
  197. }
  198. };
  199. export default WbwCaseWidget;