RelatedPara.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { Link } from "react-router";
  2. import { Badge, Card, List, message, Modal, Skeleton } from "antd";
  3. import { get } from "../../request";
  4. import { useEffect, useState, type JSX } from "react";
  5. import TocPath, {
  6. type ITocPathNode,
  7. } from "../../../src/components/tipitaka/TocPath";
  8. import store from "../../store";
  9. import { change } from "../../reducers/para-change";
  10. interface ITag {
  11. id?: string;
  12. name: string;
  13. color?: string;
  14. }
  15. interface IRelatedParaData {
  16. book: number;
  17. para: number[];
  18. book_title_pali: string;
  19. book_title?: string;
  20. cs6_para: number;
  21. path?: ITocPathNode[];
  22. tags?: ITag[];
  23. }
  24. interface IRelatedParaResponse {
  25. ok: boolean;
  26. message: string;
  27. data: {
  28. rows: IRelatedParaData[];
  29. count: number;
  30. };
  31. }
  32. interface IWidget {
  33. book?: number;
  34. para?: number;
  35. trigger?: JSX.Element;
  36. }
  37. const RelatedParaWidget = ({ book, para, trigger }: IWidget) => {
  38. const [isModalOpen, setIsModalOpen] = useState(false);
  39. const [tableData, setTableData] = useState<IRelatedParaData[]>([]);
  40. const [load, setLoad] = useState(true);
  41. const showModal = () => {
  42. setIsModalOpen(true);
  43. };
  44. const handleOk = () => {
  45. setIsModalOpen(false);
  46. };
  47. const handleCancel = () => {
  48. setIsModalOpen(false);
  49. };
  50. useEffect(() => {
  51. const fetchRelatedParagraphs = async () => {
  52. if (typeof book === "number" && typeof para === "number" && isModalOpen) {
  53. setLoad(true);
  54. try {
  55. const json = await get<IRelatedParaResponse>(
  56. `/v2/related-paragraph?book=${book}&para=${para}`
  57. );
  58. console.log("import", json);
  59. if (json.ok) {
  60. setTableData(json.data.rows);
  61. } else {
  62. message.error(json.message);
  63. }
  64. } catch (error) {
  65. message.error("请求失败,请稍后重试");
  66. console.error("获取相关段落失败:", error);
  67. } finally {
  68. setLoad(false);
  69. }
  70. }
  71. };
  72. fetchRelatedParagraphs();
  73. }, [book, para, isModalOpen]);
  74. return (
  75. <>
  76. <span onClick={showModal}>{trigger ? trigger : "相关段落"}</span>
  77. <Modal
  78. title="根本和注疏"
  79. open={isModalOpen}
  80. onOk={handleOk}
  81. onCancel={handleCancel}
  82. >
  83. {load ? (
  84. <Skeleton paragraph={{ rows: 4 }} active />
  85. ) : (
  86. <List
  87. itemLayout="vertical"
  88. size="small"
  89. split={false}
  90. dataSource={tableData}
  91. renderItem={(item) => {
  92. const isPali = item.tags?.find((tag) => tag.name === "pāḷi");
  93. const isAttha = item.tags?.find(
  94. (tag) => tag.name === "aṭṭhakathā"
  95. );
  96. const isTika = item.tags?.find((tag) => tag.name === "ṭīkā");
  97. const firstPara = item.para.length > 0 ? item.para[0] : 0;
  98. return (
  99. <List.Item>
  100. <Badge.Ribbon
  101. text={
  102. isPali
  103. ? "pāḷi"
  104. : isAttha
  105. ? "aṭṭhakathā"
  106. : isTika
  107. ? "ṭīkā"
  108. : undefined
  109. }
  110. color={
  111. isPali
  112. ? "volcano"
  113. : isAttha
  114. ? "green"
  115. : isTika
  116. ? "cyan"
  117. : undefined
  118. }
  119. >
  120. <Card
  121. title={
  122. <Link
  123. to={`/article/para/${item.book}-${firstPara}?book=${item.book}&par=${item.para}`}
  124. target="_blank"
  125. >
  126. {item.book_title_pali}
  127. </Link>
  128. }
  129. size="small"
  130. >
  131. <TocPath
  132. data={item.path}
  133. onChange={(node: ITocPathNode) => {
  134. if (node.book && node.paragraph) {
  135. const type = node.level
  136. ? node.level < 8
  137. ? "chapter"
  138. : "para"
  139. : "para";
  140. store.dispatch(
  141. change({
  142. book: node.book,
  143. para: node.paragraph,
  144. type: type,
  145. })
  146. );
  147. }
  148. }}
  149. />
  150. </Card>
  151. </Badge.Ribbon>
  152. </List.Item>
  153. );
  154. }}
  155. />
  156. )}
  157. </Modal>
  158. </>
  159. );
  160. };
  161. export default RelatedParaWidget;