Kaynağa Gözat

Merge pull request #2353 from visuddhinanda/development

Development
visuddhinanda 4 ay önce
ebeveyn
işleme
60d90c1a30

+ 11 - 6
api-v8/app/Console/Commands/IndexPaliText.php

@@ -6,6 +6,7 @@ use Illuminate\Console\Command;
 use App\Services\SearchPaliDataService;
 use App\Services\OpenSearchService;
 use App\Services\SummaryService;
+use App\Services\TagService;
 use Illuminate\Support\Facades\Log;
 use App\Models\PaliText;
 
@@ -33,6 +34,7 @@ class IndexPaliText extends Command
     protected $searchPaliDataService;
     protected $openSearchService;
     protected $summaryService;
+    protected $tagService;
     private $isTest = false;
     private $summary = false;
 
@@ -44,12 +46,14 @@ class IndexPaliText extends Command
     public function __construct(
         SearchPaliDataService $searchPaliDataService,
         OpenSearchService $openSearchService,
-        SummaryService $summaryService
+        SummaryService $summaryService,
+        TagService $tagService
     ) {
         parent::__construct();
         $this->searchPaliDataService = $searchPaliDataService;
         $this->openSearchService = $openSearchService;
         $this->summaryService = $summaryService;
+        $this->tagService = $tagService;
     }
 
     /**
@@ -102,7 +106,7 @@ class IndexPaliText extends Command
     /**
      *
      */
-    protected function indexPaliParagraph($paraInfo, $paraContent, $related_id)
+    protected function indexPaliParagraph($paraInfo, $paraContent, $related_id, array $category)
     {
         $paraId = $paraInfo['book'] . '_' . $paraInfo['paragraph'];
         $resource_id = $paraInfo['uid'];
@@ -129,7 +133,7 @@ class IndexPaliText extends Command
             'bold_single' => implode(' ', $paraContent['bold1']),
             'bold_multi' => implode(' ', array_merge($paraContent['bold2'], $paraContent['bold3'])),
             'related_id' => $related_id,
-            'category' => 'pali', // Assuming Pali paragraphs are sutta; adjust as needed
+            'category' => $category, // Assuming Pali paragraphs are sutta; adjust as needed
             'language' => 'pali',
             'updated_at' => now()->toIso8601String(),
             'granularity' => 'paragraph',
@@ -207,7 +211,7 @@ class IndexPaliText extends Command
      * @param int $book
      * @return int
      */
-    protected function indexPaliParagraphs($book, $paragraph)
+    protected function indexPaliParagraphs($book, $paragraph = null)
     {
         $this->info("Starting to index paragraphs for book: $book");
         $total = 0;
@@ -219,7 +223,8 @@ class IndexPaliText extends Command
             $paragraphs = PaliText::where('book', $book)
                 ->orderBy('paragraph')->cursor();
         }
-
+        $bookUid = PaliText::where('book', $book)->where('level', 1)->first()->uid;
+        $category = $this->tagService->getTagsName($bookUid);
         $headings = [];
         $currChapterTitle = '';
         $commentaryId = '';
@@ -245,7 +250,7 @@ class IndexPaliText extends Command
                 }
                 $commentaryId = $paraContent['commentary'];
             }
-            $this->indexPaliParagraph($para->toArray(), $paraContent, $commentaryId);
+            $this->indexPaliParagraph($para->toArray(), $paraContent, $commentaryId, $category);
             $this->info("{$para['book']}-[{$para['paragraph']}]-[{$commentaryId}]");
             usleep(10000);
         }

+ 26 - 27
api-v8/app/Console/Commands/UpgradePaliTextTag.php

@@ -41,29 +41,29 @@ class UpgradePaliTextTag extends Command
      */
     public function handle()
     {
-        if(\App\Tools\Tools::isStop()){
+        if (\App\Tools\Tools::isStop()) {
             return 0;
         }
         $this->info("upgrade pali text tag");
         $startTime = time();
 
         #载入csv数据
-        $csvFile = config("mint.path.pali_title") .'/pali_text_tag.csv';
+        $csvFile = config("mint.path.pali_title") . '/pali_text_tag.csv';
         if (($fp = fopen($csvFile, "r")) === false) {
-            $this->error( "can not open csv file. filename=" . $csvFile. PHP_EOL) ;
-            Log::error( "can not open csv file. filename=" . $csvFile) ;
+            $this->error("can not open csv file. filename=" . $csvFile . PHP_EOL);
+            Log::error("can not open csv file. filename=" . $csvFile);
         }
         Log::info("csv load:" . $csvFile);
         $inputRow = 0;
         $tagCount = 0;
         while (($data = fgetcsv($fp, 0, ',')) !== false) {
             $inputRow++;
-            if($inputRow%100==0){
+            if ($inputRow % 100 == 0) {
                 $this->info($inputRow);
             }
 
             //略过第一行标题行
-            if ($inputRow == 1){
+            if ($inputRow == 1) {
                 continue;
             }
             /*测试第一行
@@ -72,41 +72,40 @@ class UpgradePaliTextTag extends Command
             }
             */
             $book = $data[0];
-            if(!empty($this->argument('book'))){
-                if($book != (int)$this->argument('book')){
+            if (!empty($this->argument('book'))) {
+                if ($book != (int)$this->argument('book')) {
                     continue;
                 }
             }
             $para = $data[1];
-            $tags = explode(':',$data[4]);
-            $paliTextUuid = PaliText::where("book",$book)->where("paragraph",$para)->value('uid');
-            if($paliTextUuid){
+            $tags = explode(':', $data[4]);
+            $paliTextUuid = PaliText::where("book", $book)->where("paragraph", $para)->value('uid');
+            if ($paliTextUuid) {
                 //删除旧数据
-                $tagMapDelete = TagMap::where('table_name' , 'pali_texts')
-                                        ->where('anchor_id' , $paliTextUuid)
-                                        ->delete();
+                $tagMapDelete = TagMap::where('table_name', 'pali_texts')
+                    ->where('anchor_id', $paliTextUuid)
+                    ->delete();
                 foreach ($tags as $key => $tag) {
                     # code...
-                    if(!empty($tag)){
-                        $tagRow = Tag::firstOrCreate(['name'=>$tag],['owner_id'=>config("mint.admin.root_uuid")]);
-                        $tagmap = TagMap::firstOrCreate([
-                                    'table_name' => 'pali_texts',
-                                    'anchor_id' => $paliTextUuid,
-                                    'tag_id' => $tagRow->id
-                                ]);
-                        if($tagmap){
+                    if (!empty($tag)) {
+                        $tagRow = Tag::firstOrCreate(['name' => $tag], ['owner_id' => config("mint.admin.root_uuid")]);
+                        $tagMap = TagMap::firstOrCreate([
+                            'table_name' => 'pali_texts',
+                            'anchor_id' => $paliTextUuid,
+                            'tag_id' => $tagRow->id
+                        ]);
+                        if ($tagMap) {
                             $tagCount++;
                         }
                     }
                 }
-            }else{
-                    $this->error("no palitext uuid book=$book para=$para ");
+            } else {
+                $this->error("no palitext uuid book=$book para=$para ");
             }
-
         }
         fclose($fp);
-        $this->info(" $inputRow para $tagCount tags  finished. in ". time()-$startTime . "s");
-		Log::info("$inputRow para $tagCount tags  finished. in ". time()-$startTime . "s");
+        $this->info(" $inputRow para $tagCount tags  finished. in " . time() - $startTime . "s");
+        Log::info("$inputRow para $tagCount tags  finished. in " . time() - $startTime . "s");
         return 0;
     }
 }

+ 25 - 11
api-v8/app/Http/Controllers/CorpusController.php

@@ -112,9 +112,10 @@ class CorpusController extends Controller
     {
         //
     }
-    public function getSentTpl($id, $channels, $mode = 'edit', $onlyProps = false, $format = 'react')
+    public function getSentTpl($id, $inputChannels, $mode = 'edit', $onlyProps = false, $format = 'react')
     {
         $sent = [];
+        $channels = $inputChannels;
         $sentId = \explode('-', $id);
         if (count($sentId) !== 4) {
             return false;
@@ -122,17 +123,17 @@ class CorpusController extends Controller
         $bookId = (int)$sentId[0];
         if ($bookId < 1000) {
             if ($mode === 'read') {
-                $channelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
+                $originalChannelId = ChannelApi::getSysChannel('_System_Pali_VRI_');
             } else {
-                $channelId = ChannelApi::getSysChannel('_System_Wbw_VRI_');
+                $originalChannelId = ChannelApi::getSysChannel('_System_Wbw_VRI_');
             }
         } else {
-            $channelId = CustomBook::where('book_id', $bookId)->value('channel_id');
+            $originalChannelId = CustomBook::where('book_id', $bookId)->value('channel_id');
         }
 
 
-        if (isset($channelId) && $channelId) {
-            array_push($channels, $channelId);
+        if (isset($originalChannelId) && $originalChannelId) {
+            array_push($channels, $originalChannelId);
         }
         $record = Sentence::select($this->selectCol)
             ->where('book_id', $sentId[0])
@@ -585,6 +586,7 @@ class CorpusController extends Controller
         $sent = [];
         $sent["origin"] = [];
         $sent["translation"] = [];
+        $sent["commentaries"] = [];
 
         //获取句子编号列表
         $sentList = [];
@@ -594,13 +596,10 @@ class CorpusController extends Controller
             $value->sid = "{$currSentId}_{$value->channel_uid}";
         }
         $channelsId = array();
-        $count = 0;
         foreach ($indexChannel as $channelId => $info) {
-            if ($count > 0) {
-                $channelsId[] = $channelId;
-            }
-            $count++;
+            $channelsId[] = $channelId;
         }
+        array_pop($channelsId);
         //遍历列表查找每个句子的所有channel的数据,并填充
         $currPara = "";
         foreach ($sentList as $currSentId => $arrSentId) {
@@ -761,6 +760,17 @@ class CorpusController extends Controller
                                 }
                             );
                             break;
+                        case 'commentary':
+                            $options = [
+                                'debug' => $this->debug,
+                                'format' => $format,
+                                'mode' => $mode,
+                                'channelType' => 'translation',
+                                'contentType' => $row->content_type,
+                            ];
+                            $mdRender = new MdRender($options);
+                            $newSent['html'] = $mdRender->convert($row->content, $channelsId);
+                            break;
                         default:
                             $options = [
                                 'debug' => $this->debug,
@@ -780,6 +790,9 @@ class CorpusController extends Controller
                     case 'original':
                         array_push($sent["origin"], $newSent);
                         break;
+                    case 'commentary':
+                        array_push($sent["commentaries"], $newSent);
+                        break;
                     default:
                         array_push($sent["translation"], $newSent);
                         break;
@@ -977,6 +990,7 @@ class CorpusController extends Controller
             "wordEnd" => $word_end,
             "origin" => [],
             "translation" => [],
+            "commentaries" => [],
         ];
 
         if ($book < 1000) {

+ 1 - 1
api-v8/app/Services/SearchPaliDataService.php

@@ -113,7 +113,7 @@ class SearchPaliDataService
         foreach ($sentences as $key => $sentence) {
             $content = $this->getSentenceText($book, $para, $sentence->word_begin, $sentence->word_end);
             $id = "{$book}-{$para}-{$sentence->word_begin}-{$sentence->word_end}";
-            $markdown[] = $content['markdown'];
+            $markdown[] = "`id:{$id}`" . $content['markdown'];
             $text[] = $content['text'];
             $wordList = array_merge($wordList, $content['words']);
         }

+ 22 - 0
api-v8/app/Services/TagService.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\TagMap;
+
+class TagService
+{
+    public function getTagsName(string $resId)
+    {
+        $tagsName = TagMap::where('table_name', 'pali_texts')
+            ->where('anchor_id', $resId)
+            ->join('tags', 'tag_maps.tag_id', '=', 'tags.id')
+            ->select('tags.name')
+            ->get();
+        $output = [];
+        foreach ($tagsName as $key => $value) {
+            $output[] = $value->name;
+        }
+        return $output;
+    }
+}

+ 2 - 0
dashboard-v4/dashboard/src/components/auth/setting/SettingArticle.tsx

@@ -18,6 +18,8 @@ const SettingArticleWidget = () => {
       </Divider>
       <SettingItem data={SettingFind("setting.display.original", settings)} />
       <SettingItem data={SettingFind("setting.layout.direction", settings)} />
+      <SettingItem data={SettingFind("setting.layout.commentary", settings)} />
+      <SettingItem data={SettingFind("setting.layout.root.fixed", settings)} />
       <SettingItem data={SettingFind("setting.layout.paragraph", settings)} />
       <SettingItem
         data={SettingFind("setting.pali.script.primary", settings)}

+ 28 - 0
dashboard-v4/dashboard/src/components/auth/setting/default.ts

@@ -75,6 +75,26 @@ export const defaultSetting: ISetting[] = [
     ],
     widget: "radio-button",
   },
+  {
+    /**
+     * commentary排版方向
+     */
+    key: "setting.layout.commentary",
+    label: "setting.layout.commentary.label",
+    description: "setting.layout.direction.description",
+    defaultValue: "column",
+    options: [
+      {
+        value: "column",
+        label: "setting.layout.direction.col.label",
+      },
+      {
+        value: "row",
+        label: "setting.layout.direction.row.label",
+      },
+    ],
+    widget: "radio-button",
+  },
   {
     /**
      * 段落或者逐句对读
@@ -258,4 +278,12 @@ export const defaultSetting: ISetting[] = [
     label: "setting.wbw.order.label",
     defaultValue: false,
   },
+  {
+    /**
+     * 是否显示逐词解析输入顺序提示
+     */
+    key: "setting.layout.root.fixed",
+    label: "setting.layout.root.fixed.label",
+    defaultValue: false,
+  },
 ];

+ 82 - 34
dashboard-v4/dashboard/src/components/template/SentEdit.tsx

@@ -15,6 +15,11 @@ import { useAppSelector } from "../../hooks";
 import { currFocus } from "../../reducers/focus";
 import { ISentenceData } from "../api/Corpus";
 import "./SentEdit/style.css";
+import SentCell from "./SentEdit/SentCell";
+import { settingInfo } from "../../reducers/setting";
+import { GetUserSetting } from "../auth/setting/default";
+import { SENTENCE_FIX_WIDTH } from "../../types/article";
+import { useSetting } from "../../hooks/useSetting";
 
 export interface IResNumber {
   translation?: number;
@@ -84,6 +89,7 @@ export interface IWidgetSentEditInner {
   channels?: string[];
   origin?: ISentence[];
   translation?: ISentence[];
+  commentaries?: ISentence[];
   answer?: ISentence;
   path?: ITocPathNode[];
   layout?: "row" | "column";
@@ -98,6 +104,7 @@ export interface IWidgetSentEditInner {
   readonly?: boolean;
   wbwProgress?: number;
   wbwScore?: number;
+
   onTranslationChange?: (data: ISentence) => void;
 }
 export const SentEditInner = ({
@@ -121,6 +128,7 @@ export const SentEditInner = ({
   mode,
   showWbwProgress = false,
   readonly = false,
+  commentaries,
   onTranslationChange,
 }: IWidgetSentEditInner) => {
   const [wbwData, setWbwData] = useState<IWbw[]>();
@@ -133,6 +141,20 @@ export const SentEditInner = ({
   const focus = useAppSelector(currFocus);
   const divRef = useRef<HTMLDivElement>(null);
   const [affix, setAffix] = useState<boolean>(false);
+  const settings = useAppSelector(settingInfo);
+  const [commentaryLayout, setCommentaryLayout] = useState("column");
+  const rootFixed = useSetting("setting.layout.root.fixed");
+
+  useEffect(() => {
+    const layoutCommentary = GetUserSetting(
+      "setting.layout.commentary",
+      settings
+    );
+
+    layoutCommentary &&
+      typeof layoutCommentary === "string" &&
+      setCommentaryLayout(layoutCommentary);
+  }, [settings]);
 
   useEffect(() => {
     if (focus) {
@@ -214,41 +236,67 @@ export const SentEditInner = ({
     <div
       ref={divRef}
       className={`sent-edit-inner` + (isFocus ? " sent-focus" : "")}
+      style={{
+        display: commentaryLayout === "column" ? "block" : "flex",
+        width: commentaryLayout === "column" ? "100%" : SENTENCE_FIX_WIDTH,
+      }}
     >
-      {affix ? (
-        <Affix offsetTop={44}>
-          <div className="affix">{content}</div>
-        </Affix>
-      ) : (
-        content
-      )}
-      <SentTab
-        id={id}
-        book={book}
-        para={para}
-        wordStart={wordStart}
-        wordEnd={wordEnd}
-        channelsId={channelsId}
-        path={path}
-        tranNum={tranNum}
-        nissayaNum={nissayaNum}
-        commNum={commNum}
-        originNum={originNum}
-        simNum={simNum}
-        loadedRes={loadedRes}
-        wbwData={wbwData}
-        origin={origin}
-        magicDictLoading={magicDictLoading}
-        compact={isCompact}
-        mode={articleMode}
-        onMagicDict={(type: string) => {
-          setMagicDict(type);
-          setMagicDictLoading(true);
-        }}
-        onCompact={(value: boolean) => setIsCompact(value)}
-        onModeChange={(value: ArticleMode | undefined) => setArticleMode(value)}
-        onAffix={() => setAffix(!affix)}
-      />
+      <div>
+        {affix || rootFixed === true ? (
+          <Affix offsetTop={44}>
+            <div className="affix">{content}</div>
+          </Affix>
+        ) : (
+          content
+        )}
+        <div
+          style={{
+            width: commentaryLayout === "column" ? "unset" : SENTENCE_FIX_WIDTH,
+          }}
+        >
+          <SentTab
+            id={id}
+            book={book}
+            para={para}
+            wordStart={wordStart}
+            wordEnd={wordEnd}
+            channelsId={channelsId}
+            path={path}
+            tranNum={tranNum}
+            nissayaNum={nissayaNum}
+            commNum={commNum}
+            originNum={originNum}
+            simNum={simNum}
+            loadedRes={loadedRes}
+            wbwData={wbwData}
+            origin={origin}
+            magicDictLoading={magicDictLoading}
+            compact={isCompact}
+            mode={articleMode}
+            onMagicDict={(type: string) => {
+              setMagicDict(type);
+              setMagicDictLoading(true);
+            }}
+            onCompact={(value: boolean) => setIsCompact(value)}
+            onModeChange={(value: ArticleMode | undefined) =>
+              setArticleMode(value)
+            }
+            onAffix={() => setAffix(!affix)}
+          />
+        </div>
+      </div>
+      <div className="pcd_sent_commentary">
+        {commentaries?.map((item, id) => {
+          return (
+            <SentCell
+              value={item}
+              key={id}
+              isPr={false}
+              editMode={item.openInEditMode}
+            />
+          );
+        })}
+      </div>
     </div>
   );
 };

+ 1 - 2
dashboard-v4/dashboard/src/components/template/SentEdit/SentCell.tsx

@@ -1,6 +1,6 @@
 import { useEffect, useState } from "react";
 import { useIntl } from "react-intl";
-import { Divider, message as AntdMessage, Modal, Collapse } from "antd";
+import { message as AntdMessage, Modal, Collapse } from "antd";
 import { ExclamationCircleOutlined, LoadingOutlined } from "@ant-design/icons";
 
 import { ISentence } from "../SentEdit";
@@ -496,7 +496,6 @@ const SentCellWidget = ({
           <SentAttachment sentenceId={sentData?.id} />
         </Collapse.Panel>
       </Collapse>
-      {compact ? undefined : <Divider style={{ margin: "10px 0" }} />}
     </div>
   );
 };

+ 14 - 0
dashboard-v4/dashboard/src/components/template/style.css

@@ -95,3 +95,17 @@
   .ant-tabs-tab-active {
   background: rgba(128, 128, 128, 0.9) !important;
 }
+.pcd_sent_commentary {
+  border: 2px dotted darkred;
+  border-radius: 8px;
+  padding: 4px;
+  margin: 6px;
+  background-color: #f5deb357;
+}
+
+.pcd_sent_commentary .pcd_sent_commentary {
+  background-color: #44c76167;
+}
+.pcd_sent_commentary .pcd_sent_commentary .pcd_sent_commentary {
+  display: none;
+}

+ 19 - 0
dashboard-v4/dashboard/src/hooks/useSetting.ts

@@ -0,0 +1,19 @@
+import { useEffect, useState } from "react";
+import { GetUserSetting } from "../components/auth/setting/default";
+import { useAppSelector } from "../hooks";
+import { settingInfo } from "../reducers/setting";
+
+export function useSetting(key: string) {
+  const [commentaryLayout, setCommentaryLayout] = useState<
+    string | number | boolean | string[] | undefined
+  >();
+  const settings = useAppSelector(settingInfo);
+
+  useEffect(() => {
+    const layoutCommentary = GetUserSetting(key, settings);
+
+    setCommentaryLayout(layoutCommentary);
+  }, [key, settings]);
+
+  return commentaryLayout;
+}

+ 2 - 0
dashboard-v4/dashboard/src/locales/en-US/setting/index.ts

@@ -39,6 +39,8 @@ const items = {
   "term.first.show.meaning_pali": "Meaning & Pali",
   "term.first.show.meaning_others": "Meaning & Others Meaning",
   "term.first.show.meaning": "Meaning Only",
+  "setting.layout.commentary.label": "Commentary Layout",
+  "setting.layout.root.fixed.label": "Root Text Fixed",
 };
 
 export default items;

+ 2 - 0
dashboard-v4/dashboard/src/locales/zh-Hans/setting/index.ts

@@ -39,6 +39,8 @@ const items = {
   "term.first.show.meaning_pali": "意思巴利",
   "term.first.show.meaning_others": "意思其他解释",
   "term.first.show.meaning": "仅意思",
+  "setting.layout.commentary.label": "注释排版方向",
+  "setting.layout.root.fixed.label": "根节点固定显示",
 };
 
 export default items;

+ 8 - 2
dashboard-v4/dashboard/src/pages/library/article/show.tsx

@@ -58,6 +58,7 @@ import PrPull from "../../../components/corpus/PrPull";
 import NotificationIcon from "../../../components/notification/NotificationIcon";
 import SentCart from "../../../components/template/SentEdit/SentCart";
 import { useIntl } from "react-intl";
+import { useSetting } from "../../../hooks/useSetting";
 
 export const scrollToTop = () => {
   document.getElementById("article-root")?.scrollIntoView();
@@ -93,6 +94,8 @@ const Widget = () => {
 
   const paraChange = useAppSelector(paraParam);
 
+  const cLayout = useSetting("setting.layout.commentary");
+
   useEffect(() => {
     if (typeof paraChange === "undefined") {
       return;
@@ -358,7 +361,10 @@ const Widget = () => {
         </Affix>
         <div
           key="main"
-          style={{ width: `calc(100% - ${rightBarWidth})`, display: "flex" }}
+          style={{
+            width: `calc(100% - ${rightBarWidth})`,
+            display: "flex",
+          }}
         >
           <div
             className="article_shell"
@@ -366,7 +372,7 @@ const Widget = () => {
             style={{
               marginLeft: "auto",
               marginRight: "auto",
-              width: 1100,
+              width: cLayout === "column" ? 1200 : "100%",
               maxWidth: currMode === "read" ? 750 : "unset",
             }}
           >

+ 1 - 0
dashboard-v4/dashboard/src/types/article.ts

@@ -0,0 +1 @@
+export const SENTENCE_FIX_WIDTH = 800;