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

Merge branch 'agile' of github.com:iapt-platform/mint into agile

Jeremy Zheng 1 год назад
Родитель
Сommit
9bd6bd3c0c

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

@@ -235,3 +235,12 @@ export interface ICSParaNavItem {
   start: number;
   content: string;
 }
+
+export interface IArticleFtsListResponse {
+  ok: boolean;
+  message: string;
+  data: {
+    rows: IArticleDataResponse[];
+    page: { size: number; current: number; total: number };
+  };
+}

+ 8 - 7
dashboard/src/components/article/article.css

@@ -6,28 +6,29 @@ h5,
 h6 {
   font-weight: 700;
 }
-.pcd_article h2 {
+.pcd_article h1 {
   margin-top: 1em;
-  font-size: 28px;
+  font-size: 27px !important;
   border-bottom: 1px solid gray;
 }
 .pcd_article h2 {
   margin-top: 1em;
-  font-size: 22px;
+  font-size: 24px !important;
   border-bottom: 1px solid gray;
 }
 .pcd_article h3 {
   margin-top: 0.5em;
-  font-size: 16px;
+  font-size: 22px !important;
 }
 .pcd_article h4 {
-  font-size: 100%;
+  font-size: 20px !important;
 }
 .pcd_article h5 {
-  font-size: 100%;
+  font-size: 18px !important;
 }
 .pcd_article h6 {
-  font-size: 100%;
+  font-size: 16px !important;
+  font-weight: 700;
 }
 .pcd_article blockquote {
   margin-left: 1em;

+ 11 - 6
dashboard/src/components/channel/ChannelMy.tsx

@@ -170,10 +170,13 @@ const ChannelMy = ({
       const id = articleId?.split("-");
       if (id?.length === 2) {
         const url = `/v2/sentences-in-chapter?book=${id[0]}&para=${id[1]}`;
-        console.info("ChannelMy url", url);
+        console.info("ChannelMy url api request", url);
         get<ISentInChapterListResponse>(url)
           .then((res) => {
-            console.debug("ChannelMy ISentInChapterListResponse", res);
+            console.debug(
+              "ChannelMy ISentInChapterListResponse api response",
+              res
+            );
             if (res && res.ok) {
               sentList = res.data.rows.map((item) => {
                 return `${item.book}-${item.paragraph}-${item.word_begin}-${item.word_end}`;
@@ -189,7 +192,8 @@ const ChannelMy = ({
           });
       }
     } else {
-      setSentencesId(getSentIdInArticle());
+      sentList = getSentIdInArticle();
+      setSentencesId(sentList);
       loadChannel(sentList);
     }
   };
@@ -199,14 +203,15 @@ const ChannelMy = ({
     console.debug("sentences", sentences);
     const currOwner = "all";
 
-    console.log("owner", currOwner);
+    const url = `/v2/channel-progress`;
+    console.info("api request", url);
     setLoading(true);
-    post<IProgressRequest, IApiResponseChannelList>(`/v2/channel-progress`, {
+    post<IProgressRequest, IApiResponseChannelList>(url, {
       sentence: sentences,
       owner: currOwner,
     })
       .then((res) => {
-        console.debug("progress data", res.data.rows);
+        console.debug("progress data api response", res);
         const items: IItem[] = res.data.rows
           .filter((value) => value.name.substring(0, 4) !== "_Sys")
           .map((item, id) => {

+ 8 - 4
dashboard/src/components/discussion/DiscussionButton.tsx

@@ -10,11 +10,15 @@ import { discussionList } from "../../reducers/discussion-count";
 import { IDiscussionCountData, IDiscussionCountWbw } from "../api/Comment";
 import { useEffect, useState } from "react";
 
-export const openDiscussion = (resId: string, withStudent: boolean) => {
+export const openDiscussion = (
+  resId: string,
+  resType: TResType,
+  withStudent: boolean
+) => {
   const data: IShowDiscussion = {
     type: "discussion",
     resId: resId,
-    resType: "sentence",
+    resType: resType,
     withStudent: withStudent,
   };
   console.debug("discussion show", data);
@@ -70,7 +74,7 @@ const DiscussionButton = ({
     );
   }
 
-  console.debug("DiscussionButton", discussions, wbw, withStudent);
+  //console.debug("DiscussionButton", discussions, wbw, withStudent);
 
   let currCount = CommentCount;
   if (onlyMe) {
@@ -107,7 +111,7 @@ const DiscussionButton = ({
         }}
         onClick={(event) => {
           if (resId) {
-            openDiscussion(resId, wbw ? true : false);
+            openDiscussion(resId, resType, wbw ? true : false);
           }
         }}
       >

+ 6 - 4
dashboard/src/components/export/ExportModal.tsx

@@ -57,7 +57,7 @@ const ExportModalWidget = ({
   const [isModalOpen, setIsModalOpen] = useState(open);
   const [filename, setFilename] = useState<string>();
   const [url, setUrl] = useState<string>();
-  const [format, setFormat] = useState<string>("html");
+  const [format, setFormat] = useState<string>("markdown");
   const [exportStatus, setExportStatus] = useState<IStatus>();
   const [exportStart, setExportStart] = useState(false);
   const [hasOrigin, setHasOrigin] = useState(false);
@@ -175,15 +175,17 @@ const ExportModalWidget = ({
             defaultValue={format}
             bordered={false}
             options={[
+              {
+                value: "markdown",
+                label: "Markdown",
+              },
               {
                 value: "pdf",
                 label: "PDF",
-                disabled: true,
               },
               {
-                value: "word",
+                value: "docx",
                 label: "Word",
-                disabled: true,
               },
               {
                 value: "html",

+ 4 - 3
dashboard/src/components/general/NissayaCard.tsx

@@ -22,7 +22,7 @@ interface INissayaCardModal {
 export const NissayaCardPop = ({ text, trigger }: INissayaCardModal) => {
   return (
     <Popover
-      style={{ width: 600 }}
+      style={{ width: 700 }}
       content={<NissayaCardWidget text={text} cache={true} hideEditButton />}
       placement="bottom"
     >
@@ -105,10 +105,11 @@ const NissayaCardWidget = ({
     }
 
     const url = `/v2/nissaya-card/${text}?lang=${uiLang}&content_type=json`;
-    console.log("url", url);
+    console.debug("api request", url);
     setLoading(true);
     get<INissayaCardResponse>(url)
       .then((json) => {
+        console.debug("api response", json);
         if (json.ok) {
           setCardData(json.data.row);
           setTerm(json.data.ending);
@@ -169,7 +170,7 @@ const NissayaCardWidget = ({
       </div>
       <Paragraph>{term?.meaning}</Paragraph>
       <MdView html={term?.html} />
-      {cardData ? <NissayaCardTable data={cardData} /> : undefined}
+      {cardData ? <NissayaCardTable data={cardData} /> : <></>}
     </div>
   );
 };

+ 106 - 31
dashboard/src/components/general/NissayaCardTable.tsx

@@ -1,14 +1,57 @@
-import { Button, Space, Table, Tag } from "antd";
+import { Button, Space, Table, Tag, Typography } from "antd";
 import lodash from "lodash";
 import { useEffect, useState } from "react";
 import { ArrowRightOutlined } from "@ant-design/icons";
 import Marked from "./Marked";
+import GrammarLookup from "../dict/GrammarLookup";
+import { useIntl } from "react-intl";
+
+const { Link } = Typography;
+
+const caseTags = [
+  { case: "fpp", tags: ["verb", "derivative", "passive-verb"] },
+  { case: "ger", tags: ["verb"] },
+  { case: "inf", tags: ["verb"] },
+  { case: "grd", tags: ["verb"] },
+  { case: "pp", tags: ["verb", "participle"] },
+  { case: "prp", tags: ["verb", "participle"] },
+  { case: "v", tags: ["verb"] },
+  { case: "v:ind", tags: ["verb"] },
+  { case: "vdn", tags: ["verb", "participle"] },
+];
+interface ITags {
+  tag: string;
+  count: number;
+}
+const getCaseTags = (input: string[]): ITags[] => {
+  let tagsMap = new Map<string, number>();
+  input.forEach((value: string) => {
+    const found = caseTags.find((value1) => value1.case === value);
+    if (found !== undefined) {
+      found.tags.forEach((value3) => {
+        const count = tagsMap.get(value3);
+        if (typeof count === "undefined") {
+          tagsMap.set(value3, 1);
+        } else {
+          tagsMap.set(value3, count + 1);
+        }
+      });
+    }
+  });
+  let tags: ITags[] = [];
+  tagsMap.forEach((value, key, map) => {
+    tags.push({ tag: key, count: value });
+  });
+  tags.sort((a, b) => b.count - a.count);
+  return tags;
+};
 
 const randomString = () =>
   lodash.times(20, () => lodash.random(35).toString(36)).join("");
 
 interface ICaseItem {
   label: string;
+  case: string;
   link: string;
 }
 interface IRelationNode {
@@ -19,6 +62,7 @@ interface DataType {
   key: string;
   relation: string;
   localRelation?: string;
+  tags?: ITags[];
   to?: IRelationNode;
   from?: IRelationNode;
   category?: { name: string; note: string; meaning: string };
@@ -39,12 +83,12 @@ interface IWidget {
   data?: INissayaRelation[];
 }
 const NissayaCardTableWidget = ({ data }: IWidget) => {
-  const [tableData, setTableData] = useState<DataType[]>();
-  useEffect(() => {
-    if (typeof data === "undefined") {
-      setTableData(undefined);
-      return;
-    }
+  const intl = useIntl();
+  let tableData: DataType[] = [];
+
+  if (typeof data === "undefined") {
+    tableData = [];
+  } else {
     console.log("data", data);
     let category: string[] = [];
     let newData: DataType[] = [];
@@ -77,12 +121,20 @@ const NissayaCardTableWidget = ({ data }: IWidget) => {
               };
             });
           console.log("children", children);
+          let caseList: string[] = [];
+          children.forEach((value) => {
+            value.to?.case?.forEach((value1) => {
+              caseList.push(value1.case);
+            });
+          });
+          const tags = getCaseTags(caseList);
           newData.push({
             key: randomString(),
             relation: item.relation,
             localRelation: item.local_relation,
             from: item.from,
             to: item.to,
+            tags: tags,
             category: item.category,
             translation: item.local_ending,
             children: children.length > 1 ? [...children] : undefined,
@@ -101,8 +153,9 @@ const NissayaCardTableWidget = ({ data }: IWidget) => {
       }
     });
     console.log("newData", newData);
-    setTableData(newData);
-  }, [data]);
+    tableData = newData;
+  }
+
   return (
     <Table
       size="small"
@@ -111,20 +164,17 @@ const NissayaCardTableWidget = ({ data }: IWidget) => {
           title: "本词特征",
           dataIndex: "from",
           key: "from",
-          width: 40,
+          width: "10%",
           render: (value, record, index) => {
             return (
               <Space>
                 {record.from?.case?.map((item, id) => {
                   return (
-                    <Button
-                      key={id}
-                      type="link"
-                      size="small"
-                      onClick={() => window.open(item.link, "_blank")}
-                    >
-                      <Tag>{item.label}</Tag>
-                    </Button>
+                    <GrammarLookup key={id} word={item.case}>
+                      <Link>
+                        <Tag>{item.label}</Tag>
+                      </Link>
+                    </GrammarLookup>
                   );
                 })}
                 {record.from?.spell}
@@ -136,12 +186,14 @@ const NissayaCardTableWidget = ({ data }: IWidget) => {
           title: "关系",
           dataIndex: "relation",
           key: "relation",
-          width: "22%",
+          width: "30%",
           render: (value, record, index) => {
             return (
-              <Space>
-                {record.relation}
-                {record.localRelation}
+              <Space direction="vertical">
+                <GrammarLookup word={record.relation}>
+                  <Link>{record.relation}</Link>
+                </GrammarLookup>
+                <div>{record.localRelation}</div>
               </Space>
             );
           },
@@ -150,6 +202,7 @@ const NissayaCardTableWidget = ({ data }: IWidget) => {
           title: "目标词特征",
           dataIndex: "to",
           key: "to",
+          width: "20%",
           render: (value, record, index) => {
             if (record.isChildren) {
               return (
@@ -174,31 +227,53 @@ const NissayaCardTableWidget = ({ data }: IWidget) => {
               return (
                 <Space>
                   <ArrowRightOutlined />
-                  {record.category?.meaning}
+                  {record.tags?.map((item, id) => {
+                    return (
+                      <Tag key={id}>
+                        {intl.formatMessage({
+                          id: `dict.case.category.${item.tag}`,
+                        })}
+                      </Tag>
+                    );
+                  })}
                 </Space>
               );
             }
           },
         },
+        {
+          title: "语法点",
+          dataIndex: "to",
+          key: "grammar",
+          width: "20%",
+          render: (value, record, index) => {
+            if (!record.isChildren) {
+              return (
+                <GrammarLookup word={record.category?.name}>
+                  <Link>{record.category?.meaning}</Link>
+                </GrammarLookup>
+              );
+            }
+          },
+        },
         {
           title: "含义",
           dataIndex: "address",
-          width: "30%",
+          width: "40%",
           key: "address",
           render: (value, record, index) => {
             if (record.isChildren) {
               return undefined;
             } else {
-              return <Marked text={record.category?.note} />;
+              return (
+                <div>
+                  <Marked text={record.category?.note} />
+                  <div>{record.translation}</div>
+                </div>
+              );
             }
           },
         },
-        {
-          title: "翻译建议",
-          dataIndex: "translation",
-          width: "20%",
-          key: "translation",
-        },
       ]}
       dataSource={tableData}
     />

+ 0 - 2
dashboard/src/components/tag/TagSelectButton.tsx

@@ -33,8 +33,6 @@ const TagSelectButtonWidget = ({
   const studioName =
     course?.course?.studio?.realName ?? user?.nickName ?? undefined;
 
-  console.debug("TagSelectButton studioName", studioName);
-
   return (
     <TagsManager
       title={selectorTitle}

+ 8 - 4
dashboard/src/components/template/SentRead.tsx

@@ -96,10 +96,14 @@ const SentReadFrame = ({
     );
     if (typeof displayOriginal === "boolean") {
       if (boxOrg.current) {
-        if (displayOriginal === true) {
-          boxOrg.current.style.display = "block";
-        } else {
+        if (
+          displayOriginal === false &&
+          translation &&
+          translation.length > 0
+        ) {
           boxOrg.current.style.display = "none";
+        } else {
+          boxOrg.current.style.display = "block";
         }
       }
     }
@@ -170,7 +174,7 @@ const SentReadFrame = ({
                         break;
                       case "discussion":
                         if (item.id) {
-                          openDiscussion(item.id, false);
+                          openDiscussion(item.id, "sentence", false);
                         }
                         break;
                       case "pr":

+ 36 - 3
dashboard/src/components/template/Wbw/RelaGraphic.tsx

@@ -1,4 +1,5 @@
 import { Typography } from "antd";
+import { useIntl } from "react-intl";
 
 import Mermaid from "../../general/Mermaid";
 import { useAppSelector } from "../../../hooks";
@@ -6,7 +7,10 @@ import { getGrammar } from "../../../reducers/term-vocabulary";
 import { IWbwRelation } from "./WbwDetailRelation";
 import { IWbw } from "./WbwWord";
 import { relationWordId } from "./WbwRelationAdd";
-import { useIntl } from "react-intl";
+import store from "../../../store";
+import { openPanel } from "../../../reducers/right-panel";
+import { grammar } from "../../../reducers/command";
+import { fullUrl } from "../../../utils";
 
 const { Text } = Typography;
 
@@ -27,6 +31,32 @@ const RelaGraphicWidget = ({ wbwData }: IWidget) => {
   const terms = useAppSelector(getGrammar);
   const intl = useIntl();
 
+  const onLoad = () => {
+    const links = document.getElementsByTagName("a");
+    alert(links.length + "links");
+    // 为每个链接添加点击事件监听器
+    for (let i = 0; i < links.length; i++) {
+      (function (index) {
+        links[index].addEventListener("click", function (e) {
+          // 阻止链接的默认点击行为
+          e.preventDefault();
+          // 在这里执行你想在点击链接时执行的代码
+          console.log("链接被点击: ", this.href);
+          alert("链接被点击" + this.href);
+          const iPos = this.href.lastIndexOf("grammar/");
+          if (iPos >= 0) {
+            const word = this.href.substring(iPos + 8);
+            console.debug("relation graphic", word);
+            store.dispatch(grammar(word));
+            store.dispatch(openPanel("grammar"));
+          } else {
+            window.location.href = this.href;
+          }
+        });
+      })(i);
+    }
+  };
+
   const grammarStr = (input?: string | null) => {
     if (!input) {
       return "";
@@ -75,9 +105,12 @@ const RelaGraphicWidget = ({ wbwData }: IWidget) => {
               (value: IWbw) => relationWordId(value) === relation.dest_id
             );
             const toMeaning = pureMeaning(toWord?.meaning?.value);
+            const url = fullUrl("/term/list/" + relation.relation);
             const toGrammar = grammarStr(toWord?.case?.value);
-
-            return `${relation.sour_id}("${relation.sour_spell}<br />${fromMeaning}<br />${fromGrammar}") --"${relation.relation}<br />${localName}"--> ${relation.dest_id}("${relation.dest_spell}<br />${toMeaning}<br />${toGrammar}")\n`;
+            const strFrom = `${relation.sour_id}("${relation.sour_spell}<br />${fromMeaning}<br />${fromGrammar}")`;
+            const strRelation = `"<a href='${url}' target='_blank'>${relation.relation}</a><br />${localName}"`;
+            const strTo = `${relation.dest_id}("${relation.dest_spell}<br />${toMeaning}<br />${toGrammar}")`;
+            return `${strFrom} --${strRelation}--> ${strTo}\n`;
           });
           return graphic.join("");
         } else {

+ 3 - 7
dashboard/src/components/template/Wbw/WbwDetailRelation.tsx

@@ -111,7 +111,8 @@ const WbwDetailRelationWidget = ({
 
   useEffect(() => {
     let grammar = data.case?.value
-      ?.replace("#", "$")
+      ?.replace("v:ind", "v")
+      .replace("#", "$")
       .replace(":", "$")
       .replaceAll(".", "")
       .split("$");
@@ -122,13 +123,12 @@ const WbwDetailRelationWidget = ({
         grammar = [data.grammar2?.value.replaceAll(".", "")];
       }
     }
-    console.log("relation match grammar", grammar);
     if (typeof grammar === "undefined") {
       return;
     }
 
     //找出符合条件的relation
-    console.debug("relation match data=", data);
+
     const filteredRelation = relations?.filter((value) => {
       let caseMatch = true;
       let spellMatch = true;
@@ -158,12 +158,8 @@ const WbwDetailRelationWidget = ({
         // 使用正则表达式
         spellMatch = regex.test(data.real.value);
       }
-
-      console.debug("relation match", value, caseMatch, spellMatch);
-
       return caseMatch && spellMatch;
     });
-    console.debug("relation match filteredRelation=", filteredRelation);
 
     setCurrRelation(filteredRelation);
     setRelationOptions(filteredRelation);

+ 2 - 5
dashboard/src/components/template/Wbw/WbwPali.tsx

@@ -108,10 +108,9 @@ const WbwPaliWidget = ({
    * 高亮可能的单词
    */
   useEffect(() => {
-    console.debug("relation match data=", data);
-
     let grammar = data.case?.value
-      ?.replace("#", "$")
+      ?.replace("v:ind", "v")
+      .replace("#", "$")
       .replace(":", "$")
       .replaceAll(".", "")
       .split("$");
@@ -149,8 +148,6 @@ const WbwPaliWidget = ({
           spellMatch = false;
         }
       }
-      console.debug("relation match", value, caseMatch, spellMatch);
-
       return caseMatch && spellMatch;
     });
     if (match && match.length > 0) {

+ 47 - 1
dashboard/src/components/template/WbwSent.tsx

@@ -4,7 +4,7 @@ import { MoreOutlined, ExclamationCircleOutlined } from "@ant-design/icons";
 
 import { useAppSelector } from "../../hooks";
 import { mode as _mode } from "../../reducers/article-mode";
-import { get, post } from "../../request";
+import { delete_, get, post } from "../../request";
 import { ArticleMode } from "../article/Article";
 import WbwWord, {
   IWbw,
@@ -30,6 +30,7 @@ import TimeShow from "../general/TimeShow";
 import moment from "moment";
 import { courseInfo } from "../../reducers/current-course";
 import { ISentenceWbwListResponse } from "../api/Corpus";
+import { IDeleteResponse } from "../api/Article";
 
 export const getWbwProgress = (data: IWbw[], answer?: IWbw[]) => {
   //计算完成度
@@ -774,6 +775,28 @@ export const WbwSentCtl = ({
     }
   });
 
+  const deleteWbw = () => {
+    const url = `/v2/wbw-sentence/${book}-${para}-${wordStart}-${wordEnd}?channel=${channelId}`;
+    console.info("api request", url);
+    setLoading(true);
+    delete_<IDeleteResponse>(url)
+      .then((json) => {
+        console.debug("api response", json);
+        if (json.ok) {
+          message.success(
+            intl.formatMessage(
+              { id: "message.delete.success" },
+              { count: json.data }
+            )
+          );
+        } else {
+          message.error(json.message);
+        }
+      })
+      .finally(() => setLoading(false))
+      .catch((e) => console.log("Oops errors!", e));
+  };
+
   return (
     <div style={{ width: "100%" }}>
       <div
@@ -828,6 +851,17 @@ export const WbwSentCtl = ({
                 }),
                 danger: true,
               },
+              {
+                type: "divider",
+              },
+              {
+                key: "delete",
+                label: intl.formatMessage({
+                  id: "buttons.delete.wbw.sentence",
+                }),
+                danger: true,
+                disabled: true,
+              },
             ],
             onClick: ({ key }) => {
               console.log(`Click on item ${key}`);
@@ -870,6 +904,18 @@ export const WbwSentCtl = ({
                     },
                   });
                   break;
+                case "delete":
+                  modal.confirm({
+                    title: "清除逐词解析数据",
+                    icon: <ExclamationCircleOutlined />,
+                    content: "删除整句的逐词解析数据,此操作不可恢复",
+                    okText: "确认",
+                    cancelText: "取消",
+                    onOk: () => {
+                      deleteWbw();
+                    },
+                  });
+                  break;
               }
             },
           }}

+ 1 - 1
dashboard/src/components/term/GrammarBook.tsx

@@ -129,7 +129,7 @@ const GrammarBookWidget = () => {
                 let weight = 0;
                 const wordBegin = item.word
                   .toLocaleLowerCase()
-                  .indexOf(keyWord);
+                  .indexOf(keyWord.toLocaleLowerCase());
                 if (wordBegin >= 0) {
                   weight += (1 / (wordBegin + 1)) * 1000;
                   const wordRemain =

+ 1 - 0
dashboard/src/locales/en-US/buttons.ts

@@ -93,6 +93,7 @@ const items = {
   "buttons.select.channel": "Select Channel",
   "buttons.set.display.mode": "Display Mode",
   "buttons.manage": "Manage",
+  "buttons.delete.wbw.sentence": "Delete Wbw",
 };
 
 export default items;

+ 4 - 0
dashboard/src/locales/en-US/dict/index.ts

@@ -163,6 +163,10 @@ const items = {
   "dict.fields.type.comp.short.label": "comp.",
   "dict.fields.type.others.label": "others",
   "dict.fields.type.others.short.label": "others",
+  "dict.case.category.verb": "verb",
+  "dict.case.category.derivative": "derivative",
+  "dict.case.category.passive-verb": "passive-verb",
+  "dict.case.category.participle": "participle",
 };
 
 export default items;

+ 1 - 0
dashboard/src/locales/en-US/message.ts

@@ -14,6 +14,7 @@ const items = {
   "message.password.reset": "please set new password",
   "message.get.token.fail": "get token fail",
   "message.confirm-password.validate.fail": "password validate fail",
+  "message.delete.success": "delete record {count}",
 };
 
 export default items;

+ 1 - 0
dashboard/src/locales/zh-Hans/buttons.ts

@@ -93,6 +93,7 @@ const items = {
   "buttons.select.channel": "选择版本风格",
   "buttons.set.display.mode": "显示模式",
   "buttons.manage": "管理",
+  "buttons.delete.wbw.sentence": "删除整句逐词解析",
 };
 
 export default items;

+ 6 - 2
dashboard/src/locales/zh-Hans/dict/index.ts

@@ -54,8 +54,8 @@ const items = {
   "dict.fields.type.imp.short.label": "命令",
   "dict.fields.type.cond.label": "条件",
   "dict.fields.type.cond.short.label": "条件",
-  "dict.fields.type.opt.label": "愿望",
-  "dict.fields.type.opt.short.label": "愿望",
+  "dict.fields.type.opt.label": "潜能",
+  "dict.fields.type.opt.short.label": "",
   "dict.fields.type.pres.label": "现",
   "dict.fields.type.pres.short.label": "现",
   "dict.fields.type.aor.label": "过",
@@ -163,6 +163,10 @@ const items = {
   "dict.fields.type.comp.short.label": "合",
   "dict.fields.type.others.label": "其他",
   "dict.fields.type.others.short.label": "其他",
+  "dict.case.category.verb": "动词",
+  "dict.case.category.derivative": "衍生词",
+  "dict.case.category.passive-verb": "被动动词",
+  "dict.case.category.participle": "分词",
 };
 
 export default items;

+ 1 - 0
dashboard/src/locales/zh-Hans/message.ts

@@ -14,6 +14,7 @@ const items = {
   "message.password.reset": "请设置新的密码",
   "message.get.token.fail": "获取token失败",
   "message.confirm-password.validate.fail": "两次密码不一致",
+  "message.delete.success": "成功删除{count}条数据",
 };
 
 export default items;

+ 1 - 1
dashboard/src/pages/library/article/show.tsx

@@ -326,7 +326,7 @@ const Widget = () => {
                 <ToolButtonTag type={type} articleId={id} />
                 <ToolButtonPr type={type} articleId={id} />
                 <ToolButtonDiscussion type={type} articleId={id} />
-                <ToolButtonSearch type={type} articleId={id} />
+                <ToolButtonSearch type={type as ArticleType} articleId={id} />
                 <ToolButtonSetting type={type} articleId={id} />
               </Space>
             </div>

+ 1 - 1
dashboard/src/theme/antd.dark.css

@@ -72,7 +72,7 @@ h5,
 h6 {
   margin-top: 0;
   margin-bottom: 0.5em;
-  color: rgba(255, 255, 255, 0.85);
+  color: #000000d9;
   font-weight: 500;
 }
 p {