SearchVocabulary.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { get } from "../../request";
  2. import { IVocabularyListResponse } from "../api/Dict";
  3. import { useEffect, useRef, useState } from "react";
  4. import { AutoComplete, Input, Space, Typography } from "antd";
  5. import { DictIcon } from "../../assets/icon";
  6. const { Text, Link } = Typography;
  7. interface ValueType {
  8. key?: string;
  9. label: React.ReactNode;
  10. value: string | number;
  11. }
  12. interface IWidget {
  13. onSearch?: Function;
  14. value?: string;
  15. }
  16. const Widget = ({ value, onSearch }: IWidget) => {
  17. const [options, setOptions] = useState<ValueType[]>([]);
  18. const [fetching, setFetching] = useState(false);
  19. const [input, setInput] = useState<string>();
  20. const [factors, setFactors] = useState<string[]>([]);
  21. const intervalRef = useRef<number | null>(null); //防抖计时器句柄
  22. useEffect(() => {
  23. setInput(value);
  24. console.log("dict input", value);
  25. }, [value]);
  26. const renderItem = (title: string, count: number, meaning?: string) => ({
  27. value: title,
  28. label: (
  29. <div>
  30. <div
  31. style={{
  32. display: "flex",
  33. justifyContent: "space-between",
  34. }}
  35. >
  36. {title}
  37. <span>
  38. <DictIcon /> {count}
  39. </span>
  40. </div>
  41. <div>
  42. <Text type="secondary">{meaning}</Text>
  43. </div>
  44. </div>
  45. ),
  46. });
  47. /**
  48. * 停止查字典计时
  49. * 在两种情况下停止计时
  50. * 1. 开始查字典
  51. * 2. 防抖时间内鼠标移出单词区
  52. */
  53. const stopLookup = () => {
  54. if (intervalRef.current) {
  55. window.clearInterval(intervalRef.current);
  56. intervalRef.current = null;
  57. }
  58. };
  59. const search = (value: string) => {
  60. console.log("search", value);
  61. stopLookup();
  62. if (value === "") {
  63. return;
  64. }
  65. get<IVocabularyListResponse>(`/v2/vocabulary?view=key&key=${value}`)
  66. .then((json) => {
  67. const words: ValueType[] = json.data.rows.map((item) => {
  68. return renderItem(item.word, item.count, item.meaning);
  69. });
  70. setOptions(words);
  71. })
  72. .finally(() => {
  73. console.log("finally");
  74. setFetching(false);
  75. });
  76. };
  77. const startLookup = (value: string) => {
  78. //开始计时,计时结束查字典
  79. console.log("开始计时");
  80. intervalRef.current = window.setInterval(search, 500, value);
  81. };
  82. return (
  83. <div style={{ width: "100%" }}>
  84. <AutoComplete
  85. value={input}
  86. style={{ width: "100%" }}
  87. popupClassName="certain-category-search-dropdown"
  88. dropdownMatchSelectWidth={400}
  89. options={options}
  90. onChange={(value: string, option: ValueType | ValueType[]) => {
  91. console.log("input", value);
  92. setInput(value);
  93. const strFactors = value.replaceAll("+", "-");
  94. if (strFactors.indexOf("-") >= 0) {
  95. setFactors(strFactors.split("-"));
  96. } else {
  97. setFactors([]);
  98. }
  99. }}
  100. onSearch={(value: string) => {
  101. console.log("auto complete on search", value);
  102. if (fetching) {
  103. console.log("fetching");
  104. } else {
  105. setFetching(true);
  106. search(value);
  107. //stopLookup();
  108. //startLookup(value);
  109. }
  110. }}
  111. onSelect={(value: string, option: ValueType) => {
  112. if (typeof onSearch !== "undefined") {
  113. onSearch(value);
  114. }
  115. }}
  116. >
  117. <Input.Search
  118. size="large"
  119. placeholder="input here"
  120. onSearch={(value: string) => {
  121. console.log("on search", value);
  122. if (typeof onSearch !== "undefined") {
  123. onSearch(value);
  124. }
  125. }}
  126. />
  127. </AutoComplete>
  128. <Space>
  129. {factors.map((item, id) => {
  130. return (
  131. <Link
  132. key={id}
  133. onClick={() => {
  134. if (typeof onSearch !== "undefined") {
  135. onSearch(item, true);
  136. }
  137. }}
  138. >
  139. {item}
  140. </Link>
  141. );
  142. })}
  143. </Space>
  144. </div>
  145. );
  146. };
  147. export default Widget;