ChannelSentDiff.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. import { Button, Col, List, message, Row, Space, Typography } from "antd";
  2. import { diffChars } from "diff";
  3. import { useEffect, useState } from "react";
  4. import { SwapRightOutlined } from "@ant-design/icons";
  5. import { post } from "../../request";
  6. import {
  7. ISentenceDiffData,
  8. ISentenceDiffRequest,
  9. ISentenceDiffResponse,
  10. ISentenceNewMultiResponse,
  11. ISentenceNewRequest,
  12. } from "../api/Corpus";
  13. import { IChannel } from "./Channel";
  14. const { Text } = Typography;
  15. interface IDiffData {
  16. id: string;
  17. srcContent?: string;
  18. destContent?: string | JSX.Element;
  19. }
  20. interface ISentenceData {
  21. book: number;
  22. paragraph: number;
  23. wordStart: number;
  24. wordEnd: number;
  25. content: string;
  26. }
  27. interface IWidget {
  28. srcChannel?: IChannel;
  29. destChannel?: IChannel;
  30. sentences?: string[];
  31. goPrev?: Function;
  32. onSubmit?: Function;
  33. }
  34. const Widget = ({
  35. srcChannel,
  36. destChannel,
  37. sentences,
  38. goPrev,
  39. onSubmit,
  40. }: IWidget) => {
  41. const [srcApiData, setSrcApiData] = useState<ISentenceDiffData[]>([]);
  42. const [srcData, setSrcData] = useState<ISentenceData[]>([]);
  43. const [destData, setDestData] = useState<ISentenceData[]>([]);
  44. const [diffData, setDiffData] = useState<IDiffData[]>();
  45. const [loading, setLoading] = useState(false);
  46. useEffect(() => {
  47. if (sentences && srcChannel) {
  48. post<ISentenceDiffRequest, ISentenceDiffResponse>(`/v2/sent-in-channel`, {
  49. sentences: sentences,
  50. channel: srcChannel.id,
  51. }).then((json) => {
  52. if (json.ok) {
  53. console.log("src", srcChannel.id, json.data.rows);
  54. setSrcApiData(json.data.rows);
  55. const data = json.data.rows.map((item) => {
  56. return {
  57. book: item.book_id,
  58. paragraph: item.paragraph,
  59. wordStart: item.word_start,
  60. wordEnd: item.word_end,
  61. content: item.content,
  62. };
  63. });
  64. setSrcData(data);
  65. }
  66. });
  67. }
  68. }, [srcChannel, sentences]);
  69. useEffect(() => {
  70. if (sentences && destChannel) {
  71. post<ISentenceDiffRequest, ISentenceDiffResponse>(`/v2/sent-in-channel`, {
  72. sentences: sentences,
  73. channel: destChannel.id,
  74. }).then((json) => {
  75. if (json.ok) {
  76. console.log("dest", destChannel.id, json.data.rows);
  77. const data = json.data.rows.map((item) => {
  78. return {
  79. book: item.book_id,
  80. paragraph: item.paragraph,
  81. wordStart: item.word_start,
  82. wordEnd: item.word_end,
  83. content: item.content,
  84. };
  85. });
  86. setDestData(data);
  87. }
  88. });
  89. }
  90. }, [destChannel, sentences]);
  91. useEffect(() => {
  92. const diffList = sentences?.map((item) => {
  93. const id = item.split("-");
  94. const srcContent = srcData.find(
  95. (element) =>
  96. element.book === parseInt(id[0]) &&
  97. element.paragraph === parseInt(id[1]) &&
  98. element.wordStart === parseInt(id[2]) &&
  99. element.wordEnd === parseInt(id[3])
  100. );
  101. const destContent = destData.find(
  102. (element) =>
  103. element.book === parseInt(id[0]) &&
  104. element.paragraph === parseInt(id[1]) &&
  105. element.wordStart === parseInt(id[2]) &&
  106. element.wordEnd === parseInt(id[3])
  107. );
  108. const diff = diffChars(
  109. destContent ? destContent.content : "",
  110. srcContent ? srcContent.content : ""
  111. );
  112. const diffResult = diff.map((item) => {
  113. return (
  114. <Text
  115. type={
  116. item.added ? "success" : item.removed ? "danger" : "secondary"
  117. }
  118. delete={item.removed ? true : undefined}
  119. >
  120. {item.value}
  121. </Text>
  122. );
  123. });
  124. return {
  125. id: item,
  126. srcContent: srcContent?.content,
  127. destContent: <>{diffResult}</>,
  128. };
  129. });
  130. setDiffData(diffList);
  131. }, [destData, sentences, srcData]);
  132. return (
  133. <div>
  134. <div style={{ display: "flex", justifyContent: "space-between" }}>
  135. <Button
  136. onClick={() => {
  137. if (typeof goPrev !== "undefined") {
  138. goPrev();
  139. }
  140. }}
  141. >
  142. 上一步
  143. </Button>
  144. <Space>
  145. {srcChannel?.name}
  146. <SwapRightOutlined />
  147. {destChannel?.name}
  148. </Space>
  149. <Button
  150. type="primary"
  151. loading={loading}
  152. onClick={() => {
  153. setLoading(true);
  154. post<ISentenceNewRequest, ISentenceNewMultiResponse>(
  155. `/v2/sentence`,
  156. {
  157. sentences: srcApiData,
  158. channel: destChannel?.id,
  159. }
  160. )
  161. .then((json) => {
  162. if (json.ok) {
  163. if (typeof onSubmit !== "undefined") {
  164. onSubmit();
  165. }
  166. } else {
  167. message.error(json.message);
  168. }
  169. })
  170. .catch((e) => {
  171. console.log(e);
  172. })
  173. .finally(() => {
  174. setLoading(false);
  175. });
  176. }}
  177. >
  178. 开始复制
  179. </Button>
  180. </div>
  181. <List
  182. header={<div>Header</div>}
  183. footer={<div>Footer</div>}
  184. bordered
  185. dataSource={diffData}
  186. renderItem={(item) => (
  187. <List.Item>
  188. <Row style={{ width: "100%" }}>
  189. <Col span={12}>{item.srcContent}</Col>
  190. <Col span={12}>{item.destContent}</Col>
  191. </Row>
  192. </List.Item>
  193. )}
  194. />
  195. </div>
  196. );
  197. };
  198. export default Widget;