Browse Source

Merge pull request #1790 from visuddhinanda/agile

支持段落链接
visuddhinanda 2 years ago
parent
commit
19930eaa2d

+ 19 - 0
dashboard/src/components/api/Article.ts

@@ -214,3 +214,22 @@ export interface IPageNavItem {
   created_at: string;
   created_at: string;
   updated_at: string;
   updated_at: string;
 }
 }
+
+export interface ICSParaNavResponse {
+  ok: boolean;
+  data: ICSParaNavData;
+  message: string;
+}
+
+export interface ICSParaNavData {
+  curr: ICSParaNavItem;
+  prev?: ICSParaNavItem;
+  next?: ICSParaNavItem;
+  end: number;
+}
+
+export interface ICSParaNavItem {
+  book: number;
+  start: number;
+  content: string;
+}

+ 12 - 0
dashboard/src/components/article/Article.tsx

@@ -5,6 +5,7 @@ import TypeTerm from "./TypeTerm";
 import TypePali from "./TypePali";
 import TypePali from "./TypePali";
 import "./article.css";
 import "./article.css";
 import TypePage from "./TypePage";
 import TypePage from "./TypePage";
+import TypeCSPara from "./TypeCSPara";
 
 
 export type ArticleMode = "read" | "edit" | "wbw";
 export type ArticleMode = "read" | "edit" | "wbw";
 export type ArticleType =
 export type ArticleType =
@@ -149,6 +150,17 @@ const ArticleWidget = ({
             }
             }
           }}
           }}
         />
         />
+      ) : type === "cs-para" ? (
+        <TypeCSPara
+          articleId={articleId}
+          channelId={channelId}
+          mode={mode}
+          onArticleChange={(type: ArticleType, id: string) => {
+            if (typeof onArticleChange !== "undefined") {
+              onArticleChange(type, id);
+            }
+          }}
+        />
       ) : (
       ) : (
         <></>
         <></>
       )}
       )}

+ 168 - 0
dashboard/src/components/article/TypeCSPara.tsx

@@ -0,0 +1,168 @@
+import { useEffect, useState } from "react";
+import { Alert, message } from "antd";
+import { useIntl } from "react-intl";
+
+import { get } from "../../request";
+import { ICSParaNavData, ICSParaNavResponse } from "../api/Article";
+import { ArticleMode, ArticleType } from "./Article";
+import TypePali from "./TypePali";
+import NavigateButton from "./NavigateButton";
+import ArticleSkeleton from "./ArticleSkeleton";
+import ErrorResult from "../general/ErrorResult";
+import "./article.css";
+
+interface IParam {
+  articleId?: string;
+  mode?: ArticleMode | null;
+  channelId?: string | null;
+  book?: string | null;
+  para?: string | null;
+}
+interface IWidget {
+  articleId?: string;
+  mode?: ArticleMode | null;
+  channelId?: string | null;
+  onArticleChange?: Function;
+  onFinal?: Function;
+  onLoad?: Function;
+}
+const TypeCSParaWidget = ({
+  channelId,
+  articleId,
+  mode = "read",
+  onArticleChange,
+}: IWidget) => {
+  /**
+   * 页面加载
+   * M 缅文页码
+   * P PTS页码
+   * V vri页码
+   * T 泰文页码
+   * O 其他
+   * para 缅文段落号
+   * url 格式 /article/page/M-dīghanikāya-2-10
+   * 书名在 dashboard\src\components\fts\book_name.ts
+   */
+
+  const [paramPali, setParamPali] = useState<IParam>();
+  const [nav, setNav] = useState<ICSParaNavData>();
+  const [errorCode, setErrorCode] = useState<number>();
+  const [errorMessage, setErrorMessage] = useState<string>();
+  const [pageInfo, setPageInfo] = useState<string>();
+  const intl = useIntl();
+
+  useEffect(() => {
+    if (typeof articleId === "undefined") {
+      console.error("articleId 不能为空");
+      return;
+    }
+
+    const pageParam = articleId.split("_");
+    if (pageParam.length !== 3) {
+      console.error("pageParam 必须为三个");
+      return;
+    }
+
+    const url = `/v2/nav-cs-para/${articleId}`;
+    setPageInfo("");
+    console.log("url", url);
+    get<ICSParaNavResponse>(url)
+      .then((json) => {
+        if (json.ok) {
+          const data = json.data;
+          setNav(data);
+          const begin = data.curr.start;
+          const end = data.end;
+          let para: number[] = [];
+          for (let index = begin; index <= end; index++) {
+            para.push(index);
+          }
+          setParamPali({
+            articleId: `${data.curr.book}-${data.curr.start}`,
+            book: data.curr.book.toString(),
+            para: para.join(),
+            mode: mode,
+            channelId: channelId,
+          });
+        } else {
+          message.error(json.message);
+        }
+      })
+      .finally(() => {})
+      .catch((e) => {
+        console.error(e);
+        setErrorCode(e);
+        if (e === 404) {
+          setErrorMessage(`该页面不存在。页面信息:${pageInfo}`);
+        }
+      });
+  }, [articleId, channelId, mode, pageInfo]);
+
+  return (
+    <div>
+      {pageInfo ? <Alert message={pageInfo} type="info" closable /> : undefined}
+      {paramPali ? (
+        <>
+          <TypePali
+            type={"para"}
+            hideNav
+            {...paramPali}
+            onArticleChange={(type: ArticleType, id: string) => {
+              if (typeof onArticleChange !== "undefined") {
+                onArticleChange(type, id);
+              }
+            }}
+          />
+          <NavigateButton
+            prevTitle={nav?.prev?.content.slice(0, 10)}
+            nextTitle={nav?.next?.content.slice(0, 10)}
+            onNext={(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
+              if (typeof onArticleChange !== "undefined") {
+                if (typeof articleId === "undefined") {
+                  return;
+                }
+                const pageParam = articleId.split("_");
+                if (pageParam.length !== 3) {
+                  return;
+                }
+                const id = `${pageParam[0]}-${pageParam[1]}-${
+                  parseInt(pageParam[2]) + 1
+                }`;
+                let target = "_self";
+                if (event.ctrlKey || event.metaKey) {
+                  target = "_blank";
+                }
+                onArticleChange("cs-para", id, target);
+              }
+            }}
+            onPrev={(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
+              if (typeof onArticleChange !== "undefined") {
+                if (typeof articleId === "undefined") {
+                  return;
+                }
+                const pageParam = articleId.split("_");
+                if (pageParam.length < 3) {
+                  return;
+                }
+                const id = `${pageParam[0]}-${pageParam[1]}-${
+                  parseInt(pageParam[2]) - 1
+                }`;
+                let target = "_self";
+                if (event.ctrlKey || event.metaKey) {
+                  target = "_blank";
+                }
+                onArticleChange("cs-para", id, target);
+              }
+            }}
+          />
+        </>
+      ) : errorCode ? (
+        <ErrorResult code={errorCode} message={errorMessage} />
+      ) : (
+        <ArticleSkeleton />
+      )}
+    </div>
+  );
+};
+
+export default TypeCSParaWidget;

+ 6 - 7
dashboard/src/components/article/TypePage.tsx

@@ -1,18 +1,16 @@
 import { useEffect, useState } from "react";
 import { useEffect, useState } from "react";
+import { Alert, message } from "antd";
+import { useIntl } from "react-intl";
 
 
 import { get } from "../../request";
 import { get } from "../../request";
 import { IPageNavData, IPageNavResponse } from "../api/Article";
 import { IPageNavData, IPageNavResponse } from "../api/Article";
-
 import { ArticleMode, ArticleType } from "./Article";
 import { ArticleMode, ArticleType } from "./Article";
-import "./article.css";
-import { Alert, message } from "antd";
-
 import { bookName } from "../fts/book_name";
 import { bookName } from "../fts/book_name";
 import TypePali from "./TypePali";
 import TypePali from "./TypePali";
 import NavigateButton from "./NavigateButton";
 import NavigateButton from "./NavigateButton";
 import ArticleSkeleton from "./ArticleSkeleton";
 import ArticleSkeleton from "./ArticleSkeleton";
 import ErrorResult from "../general/ErrorResult";
 import ErrorResult from "../general/ErrorResult";
-import { useIntl } from "react-intl";
+import "./article.css";
 
 
 interface IParam {
 interface IParam {
   articleId?: string;
   articleId?: string;
@@ -30,7 +28,7 @@ interface IWidget {
   onFinal?: Function;
   onFinal?: Function;
   onLoad?: Function;
   onLoad?: Function;
 }
 }
-const TypeTermWidget = ({
+const TypePageWidget = ({
   channelId,
   channelId,
   articleId,
   articleId,
   focus,
   focus,
@@ -120,6 +118,7 @@ const TypeTermWidget = ({
         <>
         <>
           <TypePali
           <TypePali
             type={"para"}
             type={"para"}
+            hideNav
             {...paramPali}
             {...paramPali}
             focus={focus}
             focus={focus}
             onArticleChange={(type: ArticleType, id: string) => {
             onArticleChange={(type: ArticleType, id: string) => {
@@ -180,4 +179,4 @@ const TypeTermWidget = ({
   );
   );
 };
 };
 
 
-export default TypeTermWidget;
+export default TypePageWidget;

+ 22 - 16
dashboard/src/components/article/TypePali.tsx

@@ -25,6 +25,7 @@ interface IWidget {
   para?: string | null;
   para?: string | null;
   active?: boolean;
   active?: boolean;
   focus?: string | null;
   focus?: string | null;
+  hideNav?: boolean;
   onArticleChange?: Function;
   onArticleChange?: Function;
   onFinal?: Function;
   onFinal?: Function;
   onLoad?: Function;
   onLoad?: Function;
@@ -37,6 +38,7 @@ const TypePaliWidget = ({
   articleId,
   articleId,
   mode = "read",
   mode = "read",
   active = true,
   active = true,
+  hideNav = false,
   focus,
   focus,
   onArticleChange,
   onArticleChange,
   onFinal,
   onFinal,
@@ -270,22 +272,26 @@ const TypePaliWidget = ({
           <Divider />
           <Divider />
           {extra}
           {extra}
           <Divider />
           <Divider />
-          <Navigate
-            type={type as ArticleType}
-            articleId={articleId}
-            onChange={(
-              event: React.MouseEvent<HTMLElement, MouseEvent>,
-              newId: string
-            ) => {
-              let target: string = "_self";
-              if (event.ctrlKey || event.metaKey) {
-                target = "_blank";
-              }
-              if (typeof onArticleChange !== "undefined") {
-                onArticleChange(type, newId, target);
-              }
-            }}
-          />
+          {hideNav ? (
+            <></>
+          ) : (
+            <Navigate
+              type={type as ArticleType}
+              articleId={articleId}
+              onChange={(
+                event: React.MouseEvent<HTMLElement, MouseEvent>,
+                newId: string
+              ) => {
+                let target: string = "_self";
+                if (event.ctrlKey || event.metaKey) {
+                  target = "_blank";
+                }
+                if (typeof onArticleChange !== "undefined") {
+                  onArticleChange(type, newId, target);
+                }
+              }}
+            />
+          )}
         </>
         </>
       )}
       )}
     </div>
     </div>

+ 3 - 3
dashboard/src/components/fts/book_name.csv

@@ -177,9 +177,9 @@ id,book,name,term,v_title,m_title,p_title,abbr
 180,161,Petavatthupāḷi,petavatthupāḷi,petavatthupāḷi,petavatthupāḷi,petavatthupāḷi,peta.
 180,161,Petavatthupāḷi,petavatthupāḷi,petavatthupāḷi,petavatthupāḷi,petavatthupāḷi,peta.
 181,162,Theragāthāpāḷi,theragāthāpāḷi,theragāthāpāḷi,theragāthāpāḷi,theragāthāpāḷi,theragāthā.
 181,162,Theragāthāpāḷi,theragāthāpāḷi,theragāthāpāḷi,theragāthāpāḷi,theragāthāpāḷi,theragāthā.
 182,163,Therīgāthāpāḷi,therīgāthāpāḷi,therīgāthāpāḷi,therīgāthāpāḷi,therīgāthāpāḷi,therī.
 182,163,Therīgāthāpāḷi,therīgāthāpāḷi,therīgāthāpāḷi,therīgāthāpāḷi,therīgāthāpāḷi,therī.
-183,164,Mūlapaṇṇāsapāḷi,majimanikaya,majimanikaya,majimanikaya,majimanikaya,ma.
-184,165,Majjhimapaṇṇāsapāḷi,majimanikaya,majimanikaya,majimanikaya,majimanikaya,ma.
-185,166,Uparipaṇṇāsapāḷi,majimanikaya,majimanikaya,majimanikaya,majimanikaya,ma.
+183,164,Mūlapaṇṇāsapāḷi,majjhimanikaya,majjhimanikaya,majjhimanikaya,majjhimanikaya,ma.
+184,165,Majjhimapaṇṇāsapāḷi,majjhimanikaya,majjhimanikaya,majjhimanikaya,majjhimanikaya,ma.
+185,166,Uparipaṇṇāsapāḷi,majjhimanikaya,majjhimanikaya,majjhimanikaya,majjhimanikaya,ma.
 186,167,Sagāthāvaggo,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃ.
 186,167,Sagāthāvaggo,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃ.
 187,168,Nidānavaggo,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃ.
 187,168,Nidānavaggo,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃ.
 188,169,Khandhavaggo,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃ.
 188,169,Khandhavaggo,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃyuttanikāya,saṃ.

+ 12 - 12
dashboard/src/components/fts/book_name.json

@@ -1783,30 +1783,30 @@
     "id": 183,
     "id": 183,
     "book": 164,
     "book": 164,
     "name": "Mūlapaṇṇāsapāḷi",
     "name": "Mūlapaṇṇāsapāḷi",
-    "term": "majimanikaya",
-    "v_title": "majimanikaya",
-    "m_title": "majimanikaya",
-    "p_title": "majimanikaya",
+    "term": "majjhimanikaya",
+    "v_title": "majjhimanikaya",
+    "m_title": "majjhimanikaya",
+    "p_title": "majjhimanikaya",
     "abbr": "ma."
     "abbr": "ma."
   },
   },
   {
   {
     "id": 184,
     "id": 184,
     "book": 165,
     "book": 165,
     "name": "Majjhimapaṇṇāsapāḷi",
     "name": "Majjhimapaṇṇāsapāḷi",
-    "term": "majimanikaya",
-    "v_title": "majimanikaya",
-    "m_title": "majimanikaya",
-    "p_title": "majimanikaya",
+    "term": "majjhimanikaya",
+    "v_title": "majjhimanikaya",
+    "m_title": "majjhimanikaya",
+    "p_title": "majjhimanikaya",
     "abbr": "ma."
     "abbr": "ma."
   },
   },
   {
   {
     "id": 185,
     "id": 185,
     "book": 166,
     "book": 166,
     "name": "Uparipaṇṇāsapāḷi",
     "name": "Uparipaṇṇāsapāḷi",
-    "term": "majimanikaya",
-    "v_title": "majimanikaya",
-    "m_title": "majimanikaya",
-    "p_title": "majimanikaya",
+    "term": "majjhimanikaya",
+    "v_title": "majjhimanikaya",
+    "m_title": "majjhimanikaya",
+    "p_title": "majjhimanikaya",
     "abbr": "ma."
     "abbr": "ma."
   },
   },
   {
   {

+ 13 - 13
dashboard/src/components/fts/book_name.ts

@@ -1783,30 +1783,30 @@ export const bookName = [
     id: 183,
     id: 183,
     book: 164,
     book: 164,
     name: "Mūlapaṇṇāsapāḷi",
     name: "Mūlapaṇṇāsapāḷi",
-    term: "majimanikaya",
-    v_title: "majimanikaya",
-    m_title: "majimanikaya",
-    p_title: "majimanikaya",
+    term: "majjhimanikaya",
+    v_title: "majjhimanikaya",
+    m_title: "majjhimanikaya",
+    p_title: "majjhimanikaya",
     abbr: "ma.",
     abbr: "ma.",
   },
   },
   {
   {
     id: 184,
     id: 184,
     book: 165,
     book: 165,
     name: "Majjhimapaṇṇāsapāḷi",
     name: "Majjhimapaṇṇāsapāḷi",
-    term: "majimanikaya",
-    v_title: "majimanikaya",
-    m_title: "majimanikaya",
-    p_title: "majimanikaya",
+    term: "majjhimanikaya",
+    v_title: "majjhimanikaya",
+    m_title: "majjhimanikaya",
+    p_title: "majjhimanikaya",
     abbr: "ma.",
     abbr: "ma.",
   },
   },
   {
   {
     id: 185,
     id: 185,
     book: 166,
     book: 166,
     name: "Uparipaṇṇāsapāḷi",
     name: "Uparipaṇṇāsapāḷi",
-    term: "majimanikaya",
-    v_title: "majimanikaya",
-    m_title: "majimanikaya",
-    p_title: "majimanikaya",
+    term: "majjhimanikaya",
+    v_title: "majjhimanikaya",
+    m_title: "majjhimanikaya",
+    p_title: "majjhimanikaya",
     abbr: "ma.",
     abbr: "ma.",
   },
   },
   {
   {
@@ -2767,6 +2767,6 @@ export const bookName = [
     v_title: "pācittiyapāḷi",
     v_title: "pācittiyapāḷi",
     m_title: "pācittiyapāḷi",
     m_title: "pācittiyapāḷi",
     p_title: "vinayapiṭaka",
     p_title: "vinayapiṭaka",
-    abbr: "vi.\n",
+    abbr: "vi.",
   },
   },
 ];
 ];

+ 51 - 0
dashboard/src/components/template/ParaLink.tsx

@@ -0,0 +1,51 @@
+import { ArticleCtl, TDisplayStyle } from "./Article";
+import { csParaMap } from "./cs_para_map";
+
+interface IWidgetParaLinkCtl {
+  title?: string;
+  bookName?: string | null;
+  paragraphs?: string | null;
+  style?: TDisplayStyle;
+  book?: number;
+  para?: number;
+}
+export const ParaLinkCtl = ({
+  title,
+  bookName,
+  paragraphs,
+  style = "modal",
+  book,
+  para,
+}: IWidgetParaLinkCtl) => {
+  const bookPara = csParaMap.find((value) => value.name === bookName);
+  return (
+    <>
+      {bookPara ? (
+        <ArticleCtl
+          title={title}
+          type={"cs-para"}
+          focus={book && para ? `${book}-${para}` : undefined}
+          id={`${bookPara?.book}_${bookPara?.para}_${paragraphs}`}
+          style={style}
+        />
+      ) : (
+        <>{title}</>
+      )}
+    </>
+  );
+};
+
+interface IWidget {
+  props: string;
+}
+const Widget = ({ props }: IWidget) => {
+  const prop = JSON.parse(atob(props)) as IWidgetParaLinkCtl;
+  console.log(prop);
+  return (
+    <>
+      <ParaLinkCtl {...prop} />
+    </>
+  );
+};
+
+export default Widget;

+ 10 - 1
dashboard/src/components/template/Wbw/WbwPali.tsx

@@ -21,6 +21,7 @@ import { add, relationAddParam } from "../../../reducers/relation-add";
 import { ArticleMode } from "../../article/Article";
 import { ArticleMode } from "../../article/Article";
 import { anchor, showWbw } from "../../../reducers/wbw";
 import { anchor, showWbw } from "../../../reducers/wbw";
 import { CommentOutlinedIcon } from "../../../assets/icon";
 import { CommentOutlinedIcon } from "../../../assets/icon";
+import { ParaLinkCtl } from "../ParaLink";
 
 
 const { Paragraph } = Typography;
 const { Paragraph } = Typography;
 interface IWidget {
 interface IWidget {
@@ -344,7 +345,15 @@ const WbwPaliWidget = ({ data, channelId, mode, display, onSave }: IWidget) => {
     //标点符号
     //标点符号
     return (
     return (
       <div className="pali_shell" style={{ cursor: "unset" }}>
       <div className="pali_shell" style={{ cursor: "unset" }}>
-        {paliWord}
+        {data.type?.value === ":cs.para:" ? (
+          <ParaLinkCtl
+            title={data.word.value}
+            bookName={data.grammar?.value}
+            paragraphs={data.factors?.value}
+          />
+        ) : (
+          paliWord
+        )}
       </div>
       </div>
     );
     );
   }
   }

+ 44 - 0
dashboard/src/components/template/cs_para_map.ts

@@ -0,0 +1,44 @@
+export const csParaMap = [
+  { name: "pārā.", book: 213, para: 3 },
+  { name: "pāci.", book: 214, para: 3 },
+  { name: "mahāva.", book: 215, para: 3 },
+  { name: "cūḷava.", book: 216, para: 3 },
+  { name: "pari.", book: 217, para: 3 },
+  { name: "pārā.aṭṭha.", book: 138, para: 3 },
+  { name: "pāci.aṭṭha.", book: 139, para: 3 },
+  { name: "mahāva.aṭṭha.", book: 140, para: 3 },
+  { name: "cūḷava.aṭṭha.", book: 141, para: 3 },
+  { name: "pari.aṭṭha.", book: 142, para: 3 },
+
+  { name: "dī.ni.1.", book: 93, para: 3 },
+  { name: "dī.ni.2.", book: 94, para: 3 },
+  { name: "dī.ni.3.", book: 95, para: 3 },
+
+  { name: "ma.ni.1.", book: 164, para: 3 },
+  { name: "ma.ni.2.", book: 165, para: 3 },
+  { name: "ma.ni.3.", book: 166, para: 3 },
+  { name: "ma.ni.aṭṭha.1.", book: 130, para: 3 },
+  { name: "ma.ni.aṭṭha.2.", book: 131, para: 3 },
+  { name: "ma.ni.aṭṭha.3.", book: 132, para: 3 },
+  { name: "ma.ni.ṭī.1.", book: 192, para: 3 },
+  { name: "ma.ni.ṭī.2.", book: 193, para: 3 },
+  { name: "ma.ni.ṭī.3.", book: 194, para: 3 },
+
+  { name: "saṃ.ni.1.", book: 167, para: 3 },
+  { name: "saṃ.ni.2.", book: 168, para: 3 },
+  { name: "saṃ.ni.3.", book: 169, para: 3 },
+  { name: "saṃ.ni.4.", book: 170, para: 3 },
+  { name: "saṃ.ni.5.", book: 171, para: 3 },
+
+  { name: "a.ni.1.", book: 84, para: 3 },
+  { name: "a.ni.2.", book: 85, para: 3 },
+  { name: "a.ni.3.", book: 86, para: 3 },
+  { name: "a.ni.4.", book: 87, para: 3 },
+  { name: "a.ni.5.", book: 88, para: 3 },
+  { name: "a.ni.6.", book: 89, para: 3 },
+  { name: "a.ni.7.", book: 90, para: 3 },
+  { name: "a.ni.8.", book: 91, para: 3 },
+  { name: "a.ni.9.", book: 92, para: 3 },
+  { name: "a.ni.10.", book: 82, para: 3 },
+  { name: "a.ni.11.", book: 83, para: 3 },
+];