Просмотр исходного кода

Merge pull request #2013 from visuddhinanda/agile

路径添加当前章节
visuddhinanda 2 лет назад
Родитель
Сommit
ac2d047b75

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

@@ -10,6 +10,7 @@ import { ISearchParams } from "../../pages/library/article/show";
 import TypeCourse from "./TypeCourse";
 import { useEffect, useState } from "react";
 import { fullUrl } from "../../utils";
+import TypeSeries from "./TypeSeries";
 
 export type ArticleMode = "read" | "edit" | "wbw";
 export type ArticleType =
@@ -184,6 +185,21 @@ const ArticleWidget = ({
             }
           }}
         />
+      ) : type === "series" ? (
+        <TypeSeries
+          articleId={onArticleChange ? articleId : currId}
+          channelId={channelId}
+          onArticleChange={(
+            type: ArticleType,
+            id: string,
+            target: string,
+            param: ISearchParams[]
+          ) => {
+            if (typeof onArticleChange !== "undefined") {
+              onArticleChange(type, id, target, param);
+            }
+          }}
+        />
       ) : type === "page" ? (
         <TypePage
           articleId={onArticleChange ? articleId : currId}

+ 53 - 26
dashboard/src/components/article/PaliTextToc.tsx

@@ -5,46 +5,65 @@ import { get } from "../../request";
 import { IPaliTocListResponse } from "../api/Corpus";
 import { ListNodeData } from "./EditableTree";
 import TocTree from "./TocTree";
+import { Skeleton } from "antd";
 
 interface IWidget {
   book?: number;
   para?: number;
+  series?: string;
   channel?: string;
   onSelect?: Function;
+  onClick?: Function;
 }
-const PaliTextTocWidget = ({ book, para, channel, onSelect }: IWidget) => {
+const PaliTextTocWidget = ({
+  book,
+  para,
+  series,
+  channel,
+  onSelect,
+  onClick,
+}: IWidget) => {
   const [tocList, setTocList] = useState<ListNodeData[]>([]);
   const [selectedKeys, setSelectedKeys] = useState<Key[]>();
   const [expandedKeys, setExpandedKeys] = useState<Key[]>();
-
+  const [loading, setLoading] = useState(true);
   useEffect(() => {
-    get<IPaliTocListResponse>(
-      `/v2/palitext?view=book-toc&book=${book}&para=${para}`
-    ).then((json) => {
-      const toc = json.data.rows.map((item, id) => {
-        return {
-          key: `${item.book}-${item.paragraph}`,
-          title: item.toc,
-          level: parseInt(item.level),
-        };
-      });
-      setTocList(toc);
-      if (json.data.rows.length > 0) {
-        let path: string[] = [];
-        for (let index = json.data.rows.length - 1; index >= 0; index--) {
-          const element = json.data.rows[index];
-          if (element.book === book && para && element.paragraph <= para) {
-            path.push(`${element.book}-${element.paragraph}`);
-            break;
+    let url = `/v2/palitext?view=book-toc&book=${book}&para=${para}`;
+    if (series) {
+      url = `/v2/palitext?view=book-toc&series=${series}`;
+    } else {
+      url = `/v2/palitext?view=book-toc&book=${book}&para=${para}`;
+    }
+    setLoading(true);
+    get<IPaliTocListResponse>(url)
+      .then((json) => {
+        const toc = json.data.rows.map((item, id) => {
+          return {
+            key: `${item.book}-${item.paragraph}`,
+            title: item.toc,
+            level: parseInt(item.level),
+          };
+        });
+        setTocList(toc);
+        if (json.data.rows.length > 0) {
+          let path: string[] = [];
+          for (let index = json.data.rows.length - 1; index >= 0; index--) {
+            const element = json.data.rows[index];
+            if (element.book === book && para && element.paragraph <= para) {
+              path.push(`${element.book}-${element.paragraph}`);
+              break;
+            }
           }
+          setExpandedKeys(path);
+          setSelectedKeys(path);
         }
-        setExpandedKeys(path);
-        setSelectedKeys(path);
-      }
-    });
-  }, [book, para]);
+      })
+      .finally(() => setLoading(false));
+  }, [book, para, series]);
 
-  return (
+  return loading ? (
+    <Skeleton active />
+  ) : (
     <TocTree
       treeData={tocList}
       selectedKeys={selectedKeys}
@@ -54,6 +73,14 @@ const PaliTextTocWidget = ({ book, para, channel, onSelect }: IWidget) => {
           onSelect(selectedKeys);
         }
       }}
+      onClick={(
+        id: string,
+        e: React.MouseEvent<HTMLSpanElement, MouseEvent>
+      ) => {
+        if (typeof onClick !== "undefined") {
+          onClick(id, e);
+        }
+      }}
     />
   );
 };

+ 40 - 21
dashboard/src/components/article/TypePali.tsx

@@ -119,19 +119,22 @@ const TypePaliWidget = ({
           }
 
           setToc(json.data.toc);
+
           switch (type) {
             case "chapter":
-              if (typeof articleId === "string" && channelId) {
-                const [book, para] = articleId?.split("-");
-                post<IViewRequest, IViewStoreResponse>("/v2/view", {
-                  target_type: type,
-                  book: parseInt(book),
-                  para: parseInt(para),
-                  channel: channelId,
-                  mode: srcDataMode,
-                }).then((json) => {
-                  console.log("view", json.data);
-                });
+              if (typeof articleId === "string") {
+                const [book, para] = articleId.split("-");
+                if (channelId) {
+                  post<IViewRequest, IViewStoreResponse>("/v2/view", {
+                    target_type: type,
+                    book: parseInt(book),
+                    para: parseInt(para),
+                    channel: channelId,
+                    mode: srcDataMode,
+                  }).then((json) => {
+                    console.log("view", json.data);
+                  });
+                }
               }
               break;
             default:
@@ -195,6 +198,24 @@ const TypePaliWidget = ({
     return;
   };
 
+  const title = articleData?.title_text
+    ? articleData?.title_text
+    : articleData?.title;
+
+  let fullPath: ITocPathNode[] = [];
+  if (articleData && articleData.path && articleData.path.length > 0) {
+    if (typeof articleId === "string") {
+      const [book, para] = articleId.split("-");
+      const currNode: ITocPathNode = {
+        book: parseInt(book),
+        paragraph: parseInt(para),
+        title: title ?? "",
+        level: articleData.path[articleData.path.length - 1].level + 1,
+      };
+      fullPath = [...articleData.path, currNode];
+    }
+  }
+
   return (
     <div>
       {loading ? (
@@ -205,16 +226,12 @@ const TypePaliWidget = ({
         <>
           <ArticleView
             id={articleData?.uid}
-            title={
-              articleData?.title_text
-                ? articleData?.title_text
-                : articleData?.title
-            }
+            title={title}
             subTitle={articleData?.subtitle}
             summary={articleData?.summary}
             content={articleData ? articleData.content : ""}
             html={articleHtml}
-            path={articleData?.path}
+            path={fullPath}
             created_at={articleData?.created_at}
             updated_at={articleData?.updated_at}
             channels={channels}
@@ -234,16 +251,18 @@ const TypePaliWidget = ({
               >
             ) => {
               let newType = type;
+              let newArticle = "";
               if (node.level === 0) {
                 newType = "series";
+                newArticle = node.title;
               } else {
                 newType = "chapter";
+                newArticle = node.key
+                  ? node.key
+                  : `${node.book}-${node.paragraph}`;
               }
 
               if (typeof onArticleChange !== "undefined") {
-                const newArticle = node.key
-                  ? node.key
-                  : `${node.book}-${node.paragraph}`;
                 const target = e.ctrlKey || e.metaKey ? "_blank" : "self";
                 onArticleChange(newType, newArticle, target);
               }
@@ -290,7 +309,7 @@ const TypePaliWidget = ({
             <Navigate
               type={type as ArticleType}
               articleId={articleId}
-              path={articleData?.path}
+              path={fullPath}
               onPathChange={(key: string) => {
                 const node = articleData?.path?.find(
                   (value) => value.title === key

+ 42 - 0
dashboard/src/components/article/TypeSeries.tsx

@@ -0,0 +1,42 @@
+import { Typography } from "antd";
+import PaliTextToc from "./PaliTextToc";
+
+const { Title } = Typography;
+
+interface IWidget {
+  articleId?: string;
+  channelId?: string | null;
+  onArticleChange?: Function;
+}
+const TypeSeriesWidget = ({
+  channelId,
+  articleId,
+  onArticleChange,
+}: IWidget) => {
+  return (
+    <div>
+      <Title level={3}>
+        {"丛书:"}
+        {articleId}
+      </Title>
+      <Title level={4}>{"书目列表"}</Title>
+      <PaliTextToc
+        series={articleId}
+        onClick={(
+          id: string,
+          e: React.MouseEvent<HTMLSpanElement, MouseEvent>
+        ) => {
+          if (typeof onArticleChange !== "undefined") {
+            if (e.ctrlKey || e.metaKey) {
+              onArticleChange("chapter", id, "_blank");
+            } else {
+              onArticleChange("chapter", id, "_self");
+            }
+          }
+        }}
+      />
+    </div>
+  );
+};
+
+export default TypeSeriesWidget;

+ 14 - 7
dashboard/src/components/corpus/TocPath.tsx

@@ -2,7 +2,7 @@ import { useNavigate, useSearchParams } from "react-router-dom";
 import { Breadcrumb, MenuProps, Popover, Tag, Typography } from "antd";
 
 import PaliText from "../template/Wbw/PaliText";
-import React, { useEffect, useState } from "react";
+import React from "react";
 import { fullUrl } from "../../utils";
 
 export interface ITocPathNode {
@@ -35,16 +35,15 @@ const TocPathWidget = ({
   onChange,
   onMenuClick,
 }: IWidgetTocPath): JSX.Element => {
-  const [currData, setCurrData] = useState(data);
   const navigate = useNavigate();
   const [searchParams] = useSearchParams();
   console.debug("TocPathWidget render");
-  useEffect(() => setCurrData(data), [data]);
+
   const fullPath = (
     <Breadcrumb
       style={{ whiteSpace: "nowrap", width: "100%", fontSize: style?.fontSize }}
     >
-      {currData.map((item, id) => {
+      {data.map((item, id) => {
         return (
           <Breadcrumb.Item
             menu={
@@ -91,7 +90,11 @@ const TocPathWidget = ({
             }}
             key={id}
           >
-            <Typography.Link>
+            <Typography.Text
+              style={{
+                cursor: id < data.length - 1 ? "pointer" : "unset",
+              }}
+            >
               {item.level < 99 ? (
                 <span
                   style={
@@ -104,17 +107,21 @@ const TocPathWidget = ({
                       : undefined
                   }
                 >
-                  <PaliText text={item.title} />
+                  <PaliText
+                    text={item.title}
+                    style={{ opacity: id < data.length - 1 ? 0.5 : 1 }}
+                  />
                 </span>
               ) : (
                 <Tag>{item.title}</Tag>
               )}
-            </Typography.Link>
+            </Typography.Text>
           </Breadcrumb.Item>
         );
       })}
     </Breadcrumb>
   );
+
   if (typeof trigger === "undefined") {
     return fullPath;
   } else {