WbwSent.tsx 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. import { Button, Dropdown, message, Progress, Space, Tree } from "antd";
  2. import { useEffect, useState } from "react";
  3. import { MoreOutlined, ExclamationCircleOutlined } from "@ant-design/icons";
  4. import { useAppSelector } from "../../hooks";
  5. import { mode as _mode } from "../../reducers/article-mode";
  6. import { post } from "../../request";
  7. import { ArticleMode } from "../article/Article";
  8. import WbwWord, {
  9. IWbw,
  10. IWbwFields,
  11. TWbwDisplayMode,
  12. WbwElement,
  13. WbwStatus,
  14. } from "./Wbw/WbwWord";
  15. import { TChannelType } from "../api/Channel";
  16. import { IDictRequest } from "../api/Dict";
  17. import { useIntl } from "react-intl";
  18. import { add } from "../../reducers/sent-word";
  19. import store from "../../store";
  20. import { settingInfo } from "../../reducers/setting";
  21. import { GetUserSetting } from "../auth/setting/default";
  22. import { getGrammar } from "../../reducers/term-vocabulary";
  23. import modal from "antd/lib/modal";
  24. import { UserWbwPost } from "../dict/MyCreate";
  25. import { currentUser } from "../../reducers/current-user";
  26. import Studio, { IStudio } from "../auth/Studio";
  27. import { IChannel } from "../channel/Channel";
  28. import TimeShow from "../general/TimeShow";
  29. import moment from "moment";
  30. export const paraMark = (wbwData: IWbw[]): IWbw[] => {
  31. //处理段落标记,支持点击段落引用弹窗
  32. let start = false;
  33. let bookCode = "";
  34. let count = 0;
  35. let currPara = 0;
  36. let bookCodeStack: string[] = [];
  37. wbwData.forEach((value: IWbw, index: number, array: IWbw[]) => {
  38. if (value.word.value === "(") {
  39. start = true;
  40. bookCode = "";
  41. bookCodeStack = [];
  42. return;
  43. }
  44. if (start) {
  45. if (!isNaN(Number(value.word.value.replaceAll("-", "")))) {
  46. console.debug("para mark", "number", value.word.value);
  47. if (bookCode === "" && bookCodeStack.length > 0) {
  48. //继承之前的
  49. let bookCodeList = bookCodeStack;
  50. bookCode = bookCodeList[0];
  51. }
  52. const dot = bookCode.lastIndexOf(".");
  53. let bookName = "";
  54. let paraNum = "";
  55. if (dot === -1) {
  56. bookName = bookCode;
  57. paraNum = value.word.value;
  58. } else {
  59. bookName = bookCode.substring(0, dot + 1);
  60. paraNum = bookCode.substring(dot + 1) + value.word.value;
  61. }
  62. bookName = bookName.substring(0, 64).toLowerCase();
  63. if (!bookCodeStack.includes(bookName)) {
  64. bookCodeStack.push(bookName);
  65. }
  66. if (bookName !== "") {
  67. array[index].bookName = bookName;
  68. count++;
  69. }
  70. } else if (value.word.value === ";") {
  71. bookCode = "";
  72. return;
  73. } else if (value.word.value === ")") {
  74. start = false;
  75. return;
  76. }
  77. bookCode += value.word.value;
  78. }
  79. });
  80. if (count > 0) {
  81. console.debug("para mark", count, wbwData);
  82. }
  83. return wbwData;
  84. };
  85. interface IMagicDictRequest {
  86. book: number;
  87. para: number;
  88. word_start: number;
  89. word_end: number;
  90. data: IWbw[];
  91. channel_id: string;
  92. lang?: string[];
  93. }
  94. interface IMagicDictResponse {
  95. ok: boolean;
  96. message: string;
  97. data: IWbw[];
  98. }
  99. interface IWbwXml {
  100. id: string;
  101. pali: WbwElement<string>;
  102. real?: WbwElement<string | null>;
  103. type?: WbwElement<string | null>;
  104. gramma?: WbwElement<string | null>;
  105. mean?: WbwElement<string | null>;
  106. org?: WbwElement<string | null>;
  107. om?: WbwElement<string | null>;
  108. case?: WbwElement<string | null>;
  109. parent?: WbwElement<string | null>;
  110. pg?: WbwElement<string | null>;
  111. parent2?: WbwElement<string | null>;
  112. rela?: WbwElement<string | null>;
  113. lock?: boolean;
  114. bmt?: WbwElement<string | null>;
  115. bmc?: WbwElement<number | null>;
  116. cf: number;
  117. }
  118. interface IWbwUpdateResponse {
  119. ok: boolean;
  120. message: string;
  121. data: { rows?: IWbwXml[]; count: number };
  122. }
  123. interface IWbwWord {
  124. words: IWbwXml[];
  125. sn: number;
  126. }
  127. interface IWbwRequest {
  128. book: number;
  129. para: number;
  130. sn: number;
  131. channel_id: string;
  132. data: IWbwWord[];
  133. }
  134. interface IWidget {
  135. data: IWbw[];
  136. answer?: IWbw[];
  137. book: number;
  138. para: number;
  139. wordStart: number;
  140. wordEnd: number;
  141. channel?: IChannel;
  142. channelId: string;
  143. channelType?: TChannelType;
  144. channelLang?: string;
  145. display?: TWbwDisplayMode;
  146. fields?: IWbwFields;
  147. layoutDirection?: "h" | "v";
  148. refreshable?: boolean;
  149. mode?: ArticleMode;
  150. wbwProgress?: boolean;
  151. studio?: IStudio;
  152. readonly?: boolean;
  153. onMagicDictDone?: Function;
  154. onChange?: Function;
  155. }
  156. export const WbwSentCtl = ({
  157. data,
  158. answer,
  159. channel,
  160. channelId,
  161. channelType,
  162. channelLang,
  163. book,
  164. para,
  165. wordStart,
  166. wordEnd,
  167. display = "block",
  168. fields,
  169. layoutDirection = "h",
  170. mode,
  171. refreshable = false,
  172. wbwProgress = false,
  173. readonly = false,
  174. studio,
  175. onChange,
  176. onMagicDictDone,
  177. }: IWidget) => {
  178. const intl = useIntl();
  179. const [wordData, setWordData] = useState<IWbw[]>(paraMark(data));
  180. const [wbwMode, setWbwMode] = useState(display);
  181. const [fieldDisplay, setFieldDisplay] = useState(fields);
  182. const [displayMode, setDisplayMode] = useState<ArticleMode>();
  183. const [loading, setLoading] = useState(false);
  184. const [progress, setProgress] = useState(0);
  185. const [showProgress, setShowProgress] = useState(false);
  186. const user = useAppSelector(currentUser);
  187. console.debug("wbw sent lang", channelLang);
  188. useEffect(() => setShowProgress(wbwProgress), [wbwProgress]);
  189. const settings = useAppSelector(settingInfo);
  190. const sysGrammar = useAppSelector(getGrammar)?.filter(
  191. (value) => value.tag === ":collocation:"
  192. );
  193. useEffect(() => {
  194. //计算完成度
  195. const allWord = wordData.filter(
  196. (value) =>
  197. value.real.value &&
  198. value.real.value?.length > 0 &&
  199. value.type?.value !== ".ctl."
  200. );
  201. const final = allWord.filter(
  202. (value) =>
  203. value.meaning?.value &&
  204. value.factors?.value &&
  205. value.factorMeaning?.value &&
  206. value.case?.value
  207. );
  208. console.debug("wbw progress", allWord, final);
  209. let finalLen: number = 0;
  210. final.forEach((value) => {
  211. if (value.real.value) {
  212. finalLen += value.real.value?.length;
  213. }
  214. });
  215. let allLen: number = 0;
  216. allWord.forEach((value) => {
  217. if (value.real.value) {
  218. allLen += value.real.value?.length;
  219. }
  220. });
  221. const progress = Math.round((finalLen * 100) / allLen);
  222. setProgress(progress);
  223. }, [wordData]);
  224. const newMode = useAppSelector(_mode);
  225. const update = (data: IWbw[]) => {
  226. console.debug("wbw update");
  227. setWordData(paraMark(data));
  228. if (typeof onChange !== "undefined") {
  229. onChange(data);
  230. }
  231. };
  232. useEffect(() => {
  233. if (refreshable) {
  234. setWordData(paraMark(data));
  235. }
  236. }, [data, refreshable]);
  237. useEffect(() => {
  238. //发布句子里面的单词的变更。给术语输入菜单用。
  239. let words = new Map<string, number>();
  240. wordData
  241. .filter(
  242. (value) =>
  243. value.type?.value !== null &&
  244. value.type?.value !== ".ctl." &&
  245. value.real.value &&
  246. value.real.value.length > 0
  247. )
  248. .forEach((value) => {
  249. words.set(value.real.value ? value.real.value : "", 1);
  250. if (value.parent?.value) {
  251. words.set(value.parent.value, 1);
  252. }
  253. });
  254. let pubWords: string[] = [];
  255. words.forEach((value, key) => pubWords.push(key));
  256. const sentId = `${book}-${para}-${wordStart}-${wordEnd}`;
  257. store.dispatch(add({ sentId: sentId, words: pubWords }));
  258. }, [book, para, wordData, wordEnd, wordStart]);
  259. useEffect(() => {
  260. console.log("mode", mode);
  261. let currMode: ArticleMode | undefined;
  262. if (typeof mode !== "undefined") {
  263. currMode = mode;
  264. } else if (typeof newMode !== "undefined") {
  265. if (typeof newMode.id === "undefined") {
  266. currMode = newMode.mode;
  267. } else {
  268. const sentId = newMode.id.split("-");
  269. if (sentId.length === 2) {
  270. if (book === parseInt(sentId[0]) && para === parseInt(sentId[1])) {
  271. currMode = newMode.mode;
  272. }
  273. }
  274. }
  275. } else {
  276. currMode = undefined;
  277. }
  278. setDisplayMode(currMode);
  279. switch (currMode) {
  280. case "edit":
  281. if (typeof display === "undefined") {
  282. setWbwMode("block");
  283. }
  284. if (typeof fields === "undefined") {
  285. setFieldDisplay({
  286. meaning: true,
  287. factors: false,
  288. factorMeaning: false,
  289. case: false,
  290. });
  291. }
  292. break;
  293. case "wbw":
  294. if (typeof display === "undefined") {
  295. setWbwMode("block");
  296. }
  297. if (typeof fields === "undefined") {
  298. setFieldDisplay({
  299. meaning: true,
  300. factors: true,
  301. factorMeaning: true,
  302. case: true,
  303. });
  304. }
  305. break;
  306. }
  307. }, [newMode, mode, book, para, display, fields]);
  308. const magicDictLookup = () => {
  309. let _lang = GetUserSetting("setting.dict.lang", settings);
  310. const url = `/v2/wbwlookup`;
  311. console.log("magic dict url", url);
  312. if (typeof _lang === "object") {
  313. }
  314. post<IMagicDictRequest, IMagicDictResponse>(url, {
  315. book: book,
  316. para: para,
  317. word_start: wordStart,
  318. word_end: wordEnd,
  319. data: wordData,
  320. channel_id: channelId,
  321. lang: _lang?.toString().split(","),
  322. })
  323. .then((json) => {
  324. if (json.ok) {
  325. console.log("magic dict result", json.data);
  326. update(json.data);
  327. if (channelType !== "nissaya") {
  328. saveWbwAll(json.data);
  329. }
  330. } else {
  331. console.error(json.message);
  332. }
  333. })
  334. .finally(() => {
  335. setLoading(false);
  336. if (typeof onMagicDictDone !== "undefined") {
  337. onMagicDictDone();
  338. }
  339. });
  340. };
  341. const wbwToXml = (item: IWbw) => {
  342. return {
  343. pali: item.word,
  344. real: item.real,
  345. id: `${book}-${para}-` + item.sn.join("-"),
  346. type: item.type,
  347. gramma: item.grammar,
  348. mean: item.meaning
  349. ? {
  350. value: item.meaning.value,
  351. status: item.meaning?.status,
  352. }
  353. : undefined,
  354. org: item.factors,
  355. om: item.factorMeaning,
  356. case: item.case,
  357. parent: item.parent,
  358. pg: item.grammar2,
  359. parent2: item.parent2,
  360. rela: item.relation,
  361. lock: item.locked,
  362. note: item.note,
  363. bmt: item.bookMarkText,
  364. bmc: item.bookMarkColor,
  365. attachments: JSON.stringify(item.attachments),
  366. cf: item.confidence,
  367. };
  368. };
  369. const saveWbwAll = (wbwData: IWbw[]) => {
  370. let arrSn: number[] = [];
  371. wbwData.forEach((value) => {
  372. if (!arrSn.includes(value.sn[0])) {
  373. arrSn.push(value.sn[0]);
  374. }
  375. });
  376. const postParam: IWbwRequest = {
  377. book: book,
  378. para: para,
  379. channel_id: channelId,
  380. sn: wbwData[0].sn[0],
  381. data: arrSn.map((item) => {
  382. return {
  383. sn: item,
  384. words: wbwData.filter((value) => value.sn[0] === item).map(wbwToXml),
  385. };
  386. }),
  387. };
  388. post<IWbwRequest, IWbwUpdateResponse>(`/v2/wbw`, postParam).then((json) => {
  389. if (json.ok) {
  390. message.info(json.data.count + " updated");
  391. } else {
  392. message.error(json.message);
  393. }
  394. });
  395. };
  396. const saveWord = (wbwData: IWbw[], sn: number) => {
  397. if (channelType === "nissaya") {
  398. } else {
  399. const data = wbwData.filter((value) => value.sn[0] === sn);
  400. const postParam: IWbwRequest = {
  401. book: book,
  402. para: para,
  403. channel_id: channelId,
  404. sn: sn,
  405. data: [
  406. {
  407. sn: sn,
  408. words: data.map(wbwToXml),
  409. },
  410. ],
  411. };
  412. post<IWbwRequest, IWbwUpdateResponse>(`/v2/wbw`, postParam).then(
  413. (json) => {
  414. if (json.ok) {
  415. message.info(json.data.count + " updated");
  416. } else {
  417. message.error(json.message);
  418. }
  419. }
  420. );
  421. }
  422. };
  423. const wordSplit = (id: number, hyphen = "-") => {
  424. let factors = wordData[id]?.factors?.value;
  425. if (typeof factors === "string") {
  426. let sFm = wordData[id]?.factorMeaning?.value;
  427. if (typeof sFm === "undefined" || sFm === null) {
  428. sFm = new Array(factors.split("+")).fill([""]).join("+");
  429. }
  430. if (wordData[id].case?.value?.split("#")[0] === ".un.") {
  431. factors = `[+${factors}+]`;
  432. sFm = `+${sFm}+`;
  433. } else if (hyphen !== "") {
  434. factors = factors.replaceAll("+", `+${hyphen}+`);
  435. sFm = sFm.replaceAll("+", `+${hyphen}+`);
  436. }
  437. let fm = sFm.split("+");
  438. const children: IWbw[] | undefined = factors
  439. .split("+")
  440. .map((item, index) => {
  441. return {
  442. word: { value: item, status: 5 },
  443. real: {
  444. value: item
  445. .replaceAll("-", "")
  446. .replaceAll("[", "")
  447. .replaceAll("]", ""),
  448. status: 5,
  449. },
  450. meaning: { value: fm[index], status: 5 },
  451. book: wordData[id].book,
  452. para: wordData[id].para,
  453. sn: [...wordData[id].sn, index],
  454. confidence: 1,
  455. };
  456. });
  457. if (typeof children !== "undefined") {
  458. console.log("children", children);
  459. const newData: IWbw[] = [...wordData];
  460. newData.splice(id + 1, 0, ...children);
  461. console.log("new-data", newData);
  462. update(newData);
  463. saveWord(newData, wordData[id].sn[0]);
  464. }
  465. }
  466. };
  467. const wbwPublish = (wbwData: IWbw[], isPublic: boolean) => {
  468. let wordData: IDictRequest[] = [];
  469. wbwData.forEach((data) => {
  470. if (
  471. (typeof data.meaning?.value === "string" &&
  472. data.meaning?.value.trim().length > 0) ||
  473. (typeof data.factorMeaning?.value === "string" &&
  474. data.factorMeaning.value.trim().length > 0)
  475. ) {
  476. const [wordType, wordGrammar] = data.case?.value
  477. ? data.case?.value?.split("#")
  478. : ["", ""];
  479. let conf = data.confidence * 100;
  480. if (data.confidence.toString() === "0.5") {
  481. conf = 100;
  482. }
  483. wordData.push({
  484. word: data.real.value ? data.real.value : "",
  485. type: wordType,
  486. grammar: wordGrammar,
  487. mean: data.meaning?.value,
  488. parent: data.parent?.value,
  489. factors: data.factors?.value,
  490. factormean: data.factorMeaning?.value,
  491. note: data.note?.value,
  492. confidence: conf,
  493. language: channelLang,
  494. status: isPublic ? 30 : 5,
  495. });
  496. }
  497. });
  498. UserWbwPost(wordData, "wbw")
  499. .finally(() => {
  500. setLoading(false);
  501. })
  502. .then((json) => {
  503. if (json.ok) {
  504. message.success(
  505. "wbw " + intl.formatMessage({ id: "flashes.success" })
  506. );
  507. } else {
  508. message.error(json.message);
  509. }
  510. });
  511. };
  512. interface wbwOptions {
  513. studio?: IStudio;
  514. answer?: IWbw;
  515. }
  516. const wbwRender = (item: IWbw, id: number, options?: wbwOptions) => {
  517. return (
  518. <WbwWord
  519. data={item}
  520. answer={options?.answer}
  521. channelId={channelId}
  522. key={id}
  523. mode={displayMode}
  524. display={wbwMode}
  525. fields={fieldDisplay}
  526. studio={studio}
  527. readonly={readonly}
  528. onChange={(e: IWbw, isPublish: boolean, isPublic: boolean) => {
  529. let newData = [...wordData];
  530. newData.forEach((value, index, array) => {
  531. //把新的数据更新到数组
  532. if (value.sn.join() === e.sn.join()) {
  533. console.log("found", e.sn);
  534. array[index] = e;
  535. }
  536. });
  537. if (e.sn.length > 1) {
  538. //把meaning 数据更新到 拆分前单词的factor meaning
  539. const factorMeaning = newData
  540. .filter((value) => {
  541. if (
  542. value.sn.length === e.sn.length &&
  543. e.sn.slice(0, e.sn.length - 1).join() ===
  544. value.sn.slice(0, e.sn.length - 1).join() &&
  545. value.real.value &&
  546. value.real.value.length > 0
  547. ) {
  548. return true;
  549. } else {
  550. return false;
  551. }
  552. })
  553. .map((item) => item.meaning?.value)
  554. .join("+");
  555. console.log("fm", factorMeaning);
  556. newData.forEach((value, index, array) => {
  557. //把新的数据更新到数组
  558. if (value.sn.join() === e.sn.slice(0, e.sn.length - 1).join()) {
  559. console.log("found", value.sn);
  560. array[index].factorMeaning = {
  561. value: factorMeaning,
  562. status: 5,
  563. };
  564. if (array[index].meaning?.status !== WbwStatus.manual) {
  565. array[index].meaning = {
  566. value: factorMeaning.replaceAll("+", " "),
  567. status: 5,
  568. };
  569. }
  570. }
  571. });
  572. }
  573. update(newData);
  574. saveWord(newData, e.sn[0]);
  575. if (isPublish === true) {
  576. wbwPublish([e], isPublic);
  577. }
  578. }}
  579. onSplit={() => {
  580. const newData: IWbw[] = JSON.parse(JSON.stringify(wordData));
  581. if (
  582. id < wordData.length - 1 &&
  583. wordData[id + 1].sn.join("-").indexOf(wordData[id].sn.join("-")) ===
  584. 0
  585. ) {
  586. //合并
  587. console.log("合并");
  588. const compactData = newData.filter((value, index) => {
  589. if (
  590. index !== id &&
  591. value.sn.join("-").indexOf(wordData[id].sn.join("-")) === 0
  592. ) {
  593. return false;
  594. } else {
  595. return true;
  596. }
  597. });
  598. update(compactData);
  599. saveWord(compactData, wordData[id].sn[0]);
  600. } else {
  601. //拆开
  602. console.log("拆开");
  603. wordSplit(id);
  604. }
  605. }}
  606. />
  607. );
  608. };
  609. const resetWbw = () => {
  610. const newData: IWbw[] = [];
  611. let count = 0;
  612. wordData.forEach((value: IWbw) => {
  613. if (
  614. value.type?.value !== null &&
  615. value.type?.value !== ".ctl." &&
  616. value.real.value &&
  617. value.real.value.length > 0
  618. ) {
  619. count++;
  620. newData.push({
  621. uid: value.uid,
  622. book: value.book,
  623. para: value.para,
  624. sn: value.sn,
  625. word: value.word,
  626. real: value.real,
  627. style: value.style,
  628. meaning: { value: "", status: 7 },
  629. type: { value: "", status: 7 },
  630. grammar: { value: "", status: 7 },
  631. grammar2: { value: "", status: 7 },
  632. parent: { value: "", status: 7 },
  633. parent2: { value: "", status: 7 },
  634. case: { value: "", status: 7 },
  635. factors: { value: "", status: 7 },
  636. factorMeaning: { value: "", status: 7 },
  637. confidence: value.confidence,
  638. });
  639. } else {
  640. newData.push(value);
  641. }
  642. });
  643. message.info(`已经重置${count}个`);
  644. update(newData);
  645. saveWbwAll(newData);
  646. };
  647. let updatedAt = moment("1970-1-1");
  648. data.forEach((value) => {
  649. if (moment(value.updated_at).isAfter(updatedAt)) {
  650. updatedAt = moment(value.updated_at);
  651. }
  652. });
  653. return (
  654. <div style={{ width: "100%" }}>
  655. <div style={{ display: showProgress ? "flex" : "none" }}>
  656. <div className="progress" style={{ width: 400 }}>
  657. <Progress percent={progress} size="small" />
  658. </div>
  659. <Space>
  660. <Studio data={studio} hideAvatar />
  661. {<TimeShow updatedAt={updatedAt.toString()} />}
  662. </Space>
  663. </div>
  664. <div className={`layout-${layoutDirection}`}>
  665. <Dropdown
  666. menu={{
  667. items: [
  668. {
  669. key: "magic-dict-current",
  670. label: intl.formatMessage({
  671. id: "buttons.magic-dict",
  672. }),
  673. },
  674. {
  675. key: "progress",
  676. label: "显示/隐藏进度条",
  677. },
  678. {
  679. key: "wbw-dict-publish-all",
  680. label: "发布全部单词",
  681. },
  682. {
  683. type: "divider",
  684. },
  685. {
  686. key: "copy-text",
  687. label: intl.formatMessage({
  688. id: "buttons.copy.pali.text",
  689. }),
  690. },
  691. {
  692. key: "reset",
  693. label: intl.formatMessage({
  694. id: "buttons.reset.wbw",
  695. }),
  696. danger: true,
  697. },
  698. ],
  699. onClick: ({ key }) => {
  700. console.log(`Click on item ${key}`);
  701. switch (key) {
  702. case "magic-dict-current":
  703. setLoading(true);
  704. magicDictLookup();
  705. break;
  706. case "wbw-dict-publish-all":
  707. wbwPublish(
  708. wordData,
  709. user?.roles?.includes("basic") ? false : true
  710. );
  711. break;
  712. case "copy-text":
  713. const paliText = wordData
  714. .filter((value) => value.type?.value !== ".ctl.")
  715. .map((item) => item.word.value)
  716. .join(" ");
  717. navigator.clipboard.writeText(paliText).then(() => {
  718. message.success("已经拷贝到剪贴板");
  719. });
  720. break;
  721. case "progress":
  722. setShowProgress((origin) => !origin);
  723. break;
  724. case "reset":
  725. modal.confirm({
  726. title: "清除逐词解析数据",
  727. icon: <ExclamationCircleOutlined />,
  728. content: "清除这个句子的逐词解析数据,此操作不可恢复",
  729. okText: "确认",
  730. cancelText: "取消",
  731. onOk: () => {
  732. resetWbw();
  733. },
  734. });
  735. break;
  736. }
  737. },
  738. }}
  739. placement="bottomLeft"
  740. >
  741. <Button
  742. loading={loading}
  743. onClick={(e) => e.preventDefault()}
  744. icon={<MoreOutlined />}
  745. size="small"
  746. type="text"
  747. style={{ backgroundColor: "lightblue", opacity: 0.3 }}
  748. />
  749. </Dropdown>
  750. {layoutDirection === "h" ? (
  751. wordData
  752. .map((item, index) => {
  753. let newItem = item;
  754. const spell = item.real.value;
  755. if (spell) {
  756. const matched = sysGrammar?.find((value) =>
  757. value.word.split("...").includes(spell)
  758. );
  759. if (matched) {
  760. console.debug("wbw sent grammar matched", matched);
  761. newItem.grammarId = matched.guid;
  762. }
  763. }
  764. return newItem;
  765. })
  766. .map((item, id) => {
  767. const currAnswer = answer?.find(
  768. (value) => value.sn.join() === item.sn.join()
  769. );
  770. return wbwRender(item, id, {
  771. studio: studio,
  772. answer: currAnswer,
  773. });
  774. })
  775. ) : (
  776. <Tree
  777. selectable={true}
  778. blockNode
  779. treeData={wordData
  780. .filter((value) => value.sn.length === 1)
  781. .map((item, id) => {
  782. const children = wordData.filter(
  783. (value) =>
  784. value.sn.length === 2 &&
  785. value.sn.slice(0, 1).join() === wordData[id].sn.join()
  786. );
  787. return {
  788. title: wbwRender(item, id),
  789. key: item.sn.join(),
  790. isLeaf: !item.factors?.value?.includes("+"),
  791. children:
  792. children.length > 0
  793. ? children.map((item, id) => {
  794. return {
  795. title: wbwRender(item, id),
  796. key: item.sn.join(),
  797. isLeaf: true,
  798. };
  799. })
  800. : undefined,
  801. };
  802. })}
  803. loadData={({ key, children }: any) =>
  804. new Promise<void>((resolve) => {
  805. console.log("key", key, children);
  806. if (children) {
  807. resolve();
  808. return;
  809. }
  810. wordSplit(key, "");
  811. resolve();
  812. })
  813. }
  814. />
  815. )}
  816. </div>
  817. </div>
  818. );
  819. };
  820. interface IWidgetWbwSent {
  821. props: string;
  822. }
  823. const WbwSentWidget = ({ props }: IWidgetWbwSent) => {
  824. const prop = JSON.parse(atob(props)) as IWidget;
  825. return <WbwSentCtl {...prop} />;
  826. };
  827. export default WbwSentWidget;