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

Merge pull request #1731 from visuddhinanda/agile

wbw 全文搜索
visuddhinanda 2 лет назад
Родитель
Сommit
020acf7813

+ 3 - 0
dashboard/src/components/auth/setting/SettingItem.tsx

@@ -24,10 +24,12 @@ const { Text } = Typography;
 interface IWidgetSettingItem {
   data?: ISetting;
   autoSave?: boolean;
+  bordered?: boolean;
   onChange?: Function;
 }
 const SettingItemWidget = ({
   data,
+  bordered = true,
   onChange,
   autoSave = true,
 }: IWidgetSettingItem) => {
@@ -146,6 +148,7 @@ const SettingItemWidget = ({
                   <Select
                     defaultValue={data.defaultValue}
                     style={{ width: 120 }}
+                    bordered={bordered}
                     onChange={(value: string) => {
                       console.log(`selected ${value}`);
                       if (autoSave) {

+ 132 - 30
dashboard/src/components/dict/CaseList.tsx

@@ -1,7 +1,11 @@
-import { Button, List, Tag, Typography } from "antd";
+import { Badge, Button, Card, Checkbox, Select, Space, Typography } from "antd";
+import { DownOutlined, UpOutlined } from "@ant-design/icons";
 import { useEffect, useState } from "react";
+
 import { get } from "../../request";
-import { ICaseListResponse } from "../api/Dict";
+import { ICaseItem, ICaseListResponse } from "../api/Dict";
+import { CheckboxValueType } from "antd/lib/checkbox/Group";
+import { CheckboxChangeEvent } from "antd/es/checkbox";
 const { Text } = Typography;
 
 export interface ICaseListData {
@@ -12,12 +16,37 @@ export interface ICaseListData {
 interface IWidget {
   word?: string;
   lines?: number;
+  onChange?: Function;
 }
-const CaseListWidget = ({ word, lines }: IWidget) => {
+const CaseListWidget = ({ word, lines, onChange }: IWidget) => {
   const [caseData, setCaseData] = useState<ICaseListData[]>();
-  const [first, setFirst] = useState<string>();
-  const [count, setCount] = useState<number>();
   const [showAll, setShowAll] = useState(lines ? false : true);
+  const [words, setWords] = useState<ICaseItem[]>();
+  const [currWord, setCurrWord] = useState<string>();
+  const [checkedList, setCheckedList] = useState<CheckboxValueType[]>([]);
+
+  useEffect(() => {
+    setCaseData(
+      words
+        ?.find((value) => value.word === currWord)
+        ?.case.sort((a, b) => b.count - a.count)
+    );
+  }, [currWord, words]);
+
+  useEffect(() => {
+    if (typeof onChange !== "undefined" && checkedList.length > 0) {
+      onChange(checkedList);
+    }
+  }, [checkedList]);
+
+  useEffect(() => {
+    if (caseData) {
+      setCheckedList(caseData?.map((item) => item.word));
+    } else {
+      setCheckedList([]);
+    }
+  }, [caseData]);
+
   useEffect(() => {
     if (typeof word === "undefined") {
       return;
@@ -25,41 +54,114 @@ const CaseListWidget = ({ word, lines }: IWidget) => {
     get<ICaseListResponse>(`/v2/case/${word}`).then((json) => {
       console.log("case", json);
       if (json.ok && json.data.rows.length > 0) {
+        setWords(json.data.rows);
         const first = json.data.rows.sort((a, b) => b.count - a.count)[0];
-        setCaseData(first.case.sort((a, b) => b.count - a.count));
-        setCount(first.count);
-        setFirst(first.word);
+        setCurrWord(first.word);
       }
     });
   }, [word]);
+
+  let checkAll = true;
+  let indeterminate = false;
+  if (caseData && checkedList) {
+    checkAll = caseData?.length === checkedList?.length;
+    indeterminate =
+      checkedList.length > 0 && checkedList.length < caseData.length;
+  }
+
+  const onWordChange = (list: CheckboxValueType[]) => {
+    setCheckedList(list);
+  };
+
+  const onCheckAllChange = (e: CheckboxChangeEvent) => {
+    if (caseData) {
+      setCheckedList(
+        e.target.checked ? caseData?.map((item) => item.word) : []
+      );
+    } else {
+      setCheckedList([]);
+    }
+  };
+
+  const showWords = showAll ? caseData : caseData?.slice(0, lines);
   return (
     <div style={{ padding: 4 }}>
-      <List
-        header={`${first}:${count}`}
-        footer={
+      <Card
+        size="small"
+        extra={
           lines ? (
             <Button type="link" onClick={() => setShowAll(!showAll)}>
-              {showAll ? "折叠" : "展开"}
+              {showAll ? (
+                <Space>
+                  {"折叠"}
+                  <UpOutlined />
+                </Space>
+              ) : (
+                <Space>
+                  {"展开"}
+                  <DownOutlined />
+                </Space>
+              )}
             </Button>
-          ) : undefined
+          ) : (
+            <></>
+          )
         }
-        size="small"
-        dataSource={showAll ? caseData : caseData?.slice(0, lines)}
-        renderItem={(item) => (
-          <List.Item>
-            <div
-              style={{
-                display: "flex",
-                justifyContent: "space-between",
-                width: "100%",
-              }}
-            >
-              <Text strong={item.bold > 0 ? true : false}>{item.word}</Text>
-              <Tag>{item.count}</Tag>
-            </div>
-          </List.Item>
-        )}
-      />
+        title={
+          <Select
+            value={currWord}
+            bordered={false}
+            onChange={(value: string) => {
+              setCurrWord(value);
+            }}
+            options={words?.map((item, id) => {
+              return {
+                label: (
+                  <Space>
+                    {item.word}
+                    <Badge
+                      count={item.count}
+                      color={"lime"}
+                      status="default"
+                      size="small"
+                    />
+                  </Space>
+                ),
+                value: item.word,
+              };
+            })}
+          />
+        }
+      >
+        <Checkbox
+          indeterminate={indeterminate}
+          onChange={onCheckAllChange}
+          checked={checkAll}
+        >
+          Check all
+        </Checkbox>
+        <Checkbox.Group
+          style={{ display: "grid" }}
+          options={showWords?.map((item, id) => {
+            return {
+              label: (
+                <Space>
+                  <Text strong={item.bold > 0 ? true : false}>{item.word}</Text>
+                  <Badge
+                    size="small"
+                    count={item.count}
+                    overflowCount={9999}
+                    status="default"
+                  />
+                </Space>
+              ),
+              value: item.word,
+            };
+          })}
+          value={checkedList}
+          onChange={onWordChange}
+        />
+      </Card>
     </div>
   );
 };

+ 28 - 2
dashboard/src/components/fts/FtsBookList.tsx

@@ -29,8 +29,10 @@ interface IFtsItem {
 }
 interface IWidget {
   keyWord?: string;
+  keyWords?: string[];
+  engin?: "wbw" | "tulip";
   tags?: string[];
-  bookId?: number;
+  bookId?: string | null;
   book?: number;
   para?: number;
   match?: string | null;
@@ -41,6 +43,8 @@ interface IWidget {
 
 const FtsBookListWidget = ({
   keyWord,
+  keyWords,
+  engin = "wbw",
   tags,
   bookId,
   book,
@@ -53,8 +57,24 @@ const FtsBookListWidget = ({
   const [ftsData, setFtsData] = useState<IFtsItem[]>();
   const [total, setTotal] = useState<number>();
 
+  const focusBooks = bookId?.split(",");
+  console.log("focusBooks", focusBooks);
   useEffect(() => {
-    let url = `/v2/search-book-list?view=${view}&key=${keyWord}`;
+    let words;
+    let api = "";
+    switch (engin) {
+      case "wbw":
+        api = "search-pali-wbw-books";
+        words = keyWords?.join();
+        break;
+      case "tulip":
+        api = "search-book-list";
+        words = keyWord;
+        break;
+      default:
+        break;
+    }
+    let url = `/v2/${api}?view=${view}&key=${words}`;
     if (typeof tags !== "undefined") {
       url += `&tags=${tags}`;
     }
@@ -64,6 +84,7 @@ const FtsBookListWidget = ({
     console.log("url", url);
     get<IFtsResponse>(url).then((json) => {
       if (json.ok) {
+        console.log("data", json.data.rows);
         let totalResult = 0;
         for (const iterator of json.data.rows) {
           totalResult += iterator.count;
@@ -95,9 +116,14 @@ const FtsBookListWidget = ({
         <List.Item>
           <div
             style={{
+              padding: 4,
+              borderRadius: 4,
               display: "flex",
               justifyContent: "space-between",
               cursor: "pointer",
+              backgroundColor: focusBooks?.includes(item.pcdBookId.toString())
+                ? "lightblue"
+                : "unset",
             }}
             onClick={() => {
               if (typeof onSelect !== "undefined") {

+ 31 - 3
dashboard/src/components/fts/FullTextSearchResult.tsx

@@ -43,6 +43,8 @@ interface IFtsItem {
 export type ISearchView = "pali" | "title" | "page";
 interface IWidget {
   keyWord?: string;
+  keyWords?: string[];
+  engin?: "wbw" | "tulip";
   tags?: string[];
   bookId?: string | null;
   book?: number;
@@ -55,6 +57,8 @@ interface IWidget {
 }
 const FullTxtSearchResultWidget = ({
   keyWord,
+  keyWords,
+  engin = "wbw",
   tags,
   bookId,
   book,
@@ -72,11 +76,25 @@ const FullTxtSearchResultWidget = ({
 
   useEffect(
     () => setCurrPage(1),
-    [view, keyWord, tags, bookId, match, pageType]
+    [view, keyWord, keyWords, tags, bookId, match, pageType]
   );
 
   useEffect(() => {
-    let url = `/v2/search?view=${view}&key=${keyWord}`;
+    let words;
+    let api = "";
+    switch (engin) {
+      case "wbw":
+        api = "search-pali-wbw";
+        words = keyWords?.join();
+        break;
+      case "tulip":
+        api = "search";
+        words = keyWord;
+        break;
+      default:
+        break;
+    }
+    let url = `/v2/${api}?view=${view}&key=${words}`;
     if (typeof tags !== "undefined") {
       url += `&tags=${tags}`;
     }
@@ -120,7 +138,17 @@ const FullTxtSearchResultWidget = ({
         }
       })
       .finally(() => setLoading(false));
-  }, [bookId, currPage, keyWord, match, orderBy, pageType, tags, view]);
+  }, [
+    bookId,
+    currPage,
+    keyWord,
+    keyWords,
+    match,
+    orderBy,
+    pageType,
+    tags,
+    view,
+  ]);
   return (
     <List
       style={{ width: "100%" }}

+ 11 - 0
dashboard/src/components/fts/search.css

@@ -13,3 +13,14 @@
   color: #177ddc;
   font-style: unset;
 }
+
+.bld {
+  font-weight: 700;
+}
+
+.hl {
+  background-color: yellow;
+}
+.note {
+  color: #177ddc;
+}

+ 20 - 2
dashboard/src/pages/library/search/search.tsx

@@ -1,6 +1,6 @@
 import { useNavigate, useParams, useSearchParams } from "react-router-dom";
 import { useEffect, useState } from "react";
-import { Row, Col, Breadcrumb, Space, Tabs } from "antd";
+import { Row, Col, Breadcrumb, Space, Tabs, Select } from "antd";
 import FullSearchInput from "../../../components/fts/FullSearchInput";
 import BookTree from "../../../components/corpus/BookTree";
 import FullTextSearchResult, {
@@ -18,6 +18,7 @@ const Widget = () => {
   const navigate = useNavigate();
   const [pageType, setPageType] = useState("P");
   const [view, setView] = useState<ISearchView | undefined>("pali");
+  const [caseWord, setCaseWord] = useState<string[]>();
 
   useEffect(() => {
     const v = searchParams.get("view");
@@ -100,6 +101,16 @@ const Widget = () => {
                     setSearchParams(searchParams);
                   }}
                   size="small"
+                  tabBarExtraContent={
+                    <Select
+                      defaultValue="wbw"
+                      bordered={false}
+                      options={[
+                        { value: "wbw", label: "wbw" },
+                        { value: "tulip", label: "tulip(beta)" },
+                      ]}
+                    />
+                  }
                   items={[
                     {
                       label: `巴利原文`,
@@ -122,6 +133,7 @@ const Widget = () => {
                   view={view as ISearchView}
                   pageType={pageType}
                   keyWord={key}
+                  keyWords={caseWord}
                   tags={searchParams.get("tags")?.split(",")}
                   bookId={searchParams.get("book")}
                   orderBy={searchParams.get("orderby")}
@@ -130,12 +142,18 @@ const Widget = () => {
               </Space>
             </Col>
             <Col xs={0} sm={0} md={5}>
-              <CaseList word={key} lines={5} />
+              <CaseList
+                word={key}
+                lines={5}
+                onChange={(value: string[]) => setCaseWord(value)}
+              />
               <FtsBookList
                 view={view}
                 keyWord={key}
+                keyWords={caseWord}
                 tags={searchParams.get("tags")?.split(",")}
                 match={searchParams.get("match")}
+                bookId={searchParams.get("book")}
                 onSelect={(bookId: number) => {
                   if (bookId !== 0) {
                     searchParams.set("book", bookId.toString());