From ba168ff55cd5828c94daf205440c7e3eba31a2a3 Mon Sep 17 00:00:00 2001 From: Default Date: Mon, 7 Apr 2025 20:12:34 +0800 Subject: [PATCH 1/5] debug --- code/app/admin/controller/Site.php | 12 +++- code/app/model/AutoSwitchViewModel.php | 19 ++++-- code/app/model/DomainModel.php | 73 +++++++++++++++------ code/app/model/SubjectFomartModel.php | 39 +++++++++++ code/app/model/TemplatesModel.php | 56 +++++++++++----- code/extend/template/ziku/WordsEntities.php | 1 - 6 files changed, 159 insertions(+), 41 deletions(-) diff --git a/code/app/admin/controller/Site.php b/code/app/admin/controller/Site.php index cc28a91..d2a2862 100644 --- a/code/app/admin/controller/Site.php +++ b/code/app/admin/controller/Site.php @@ -78,10 +78,13 @@ class Site extends BaseController $arrDomain['t_cfg'] = json_encode($TCfgTemplate, JSON_UNESCAPED_UNICODE); + /** @var DomainModel **/ $DomainModel = DomainModel::where('d_domain', $arrDomain['d_domain'])->findOrEmpty(); $DomainModel->fill($arrDomain); $DomainModel->save(); + + DomainModel::flushAllDomianOnCache(); } @@ -179,6 +182,7 @@ class Site extends BaseController $this->validate($arrData, $arrRule); if ($arrData['d_id']) { + /** @var DomainModel **/ $DomainModel = DomainModel::where('d_id', $arrData['d_id'])->findOrEmpty(); } else { $DomainModel = new DomainModel; @@ -187,6 +191,8 @@ class Site extends BaseController $DomainModel->fill($arrData); $DomainModel->save(); + DomainModel::flushAllDomianOnCache(); + return $this->success(); } @@ -347,13 +353,15 @@ class Site extends BaseController SubjectFomartGroupModel::whereIn('sfg_id', $arrSfgId)->delete(); + SubjectFomartModel::whereIn('sfg_id', $arrSfgId)->delete(); + return $this->success(); } - /** + /** * 替换模板分组列表 * * @param Request $Request @@ -387,7 +395,7 @@ class Site extends BaseController }); } if (!empty($arrData['sfg_id'])) { - $SubjectFomartModel->where('sf.sfg_id',$arrData['sfg_id']); + $SubjectFomartModel->where('sf.sfg_id', $arrData['sfg_id']); } $Paginate = $SubjectFomartModel->paginate([ diff --git a/code/app/model/AutoSwitchViewModel.php b/code/app/model/AutoSwitchViewModel.php index 57a0ac2..aa86cab 100644 --- a/code/app/model/AutoSwitchViewModel.php +++ b/code/app/model/AutoSwitchViewModel.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace app\model; use think\Request; +use think\exception\HttpException; class AutoSwitchViewModel { @@ -14,14 +15,24 @@ class AutoSwitchViewModel $strDomain = $Request->rootDomain(); - // var_dump($strDomain); + $DomainModel = DomainModel::getDomainOnCacheByDomain($strDomain); - $DomainModel = DomainModel::getDomainByCache($strDomain); + if (empty($DomainModel)) { + throw new HttpException(404, 'Site config not Found'); + } - $TemplatesModel = TemplatesModel::getTemplateOnCache($DomainModel->t_id); + // echo $DomainModel->getFomartSubject('NV_SHENG_URL'); + + // exit; + + $TemplatesModel = TemplatesModel::getTemplateOnCacheByTId($DomainModel->t_id); + + if (empty($DomainModel)) { + throw new HttpException(500, 'Site template not Found'); + } $Request->DomainModel = $DomainModel; - + $Request->TemplatesModel = $TemplatesModel; return [ diff --git a/code/app/model/DomainModel.php b/code/app/model/DomainModel.php index 7801458..5157848 100644 --- a/code/app/model/DomainModel.php +++ b/code/app/model/DomainModel.php @@ -17,20 +17,57 @@ class DomainModel extends BaseModel protected $json = ['t_cfg']; + static public $arrAllDomain = []; - static public function getDomainByCache($strDomain) + /** + * Undocumented function + * + * @return array + */ + static public function getAllDomainOnCache(): array { - $strKey = "D:" . $strDomain; - return DomainModel::where('d_domain', $strDomain)->cache($strKey, 24 * 3600)->find(); + if (empty(self::$arrAllDomain)) { + $strKey = 'Domain:All'; + self::$arrAllDomain = Cache::get($strKey); + if (empty(self::$arrAllDomain)) { + self::flushAllDomianOnCache(); + } + } + return self::$arrAllDomain; } - static public function flushDomainCache($strDomain) + /** + * Undocumented function + * + * @return void + */ + static public function flushAllDomianOnCache() { - $strKey = "D:" . $strDomain; - return Cache::delete($strKey); + + self::$arrAllDomain = []; + $strKey = 'Domain:All'; + $DomainModelAll = DomainModel::select(); + foreach ($DomainModelAll as $DomainModel) { + self::$arrAllDomain[$DomainModel->d_domain] = $DomainModel; + } + + return Cache::set($strKey, self::$arrAllDomain); } + /** + * Undocumented function + * + * @param string $strDomain + * @return DomainModel|NULL + */ + static public function getDomainOnCacheByDomain($strDomain): DomainModel|NULL + { + if (key_exists($strDomain, self::getAllDomainOnCache())) { + return self::getAllDomainOnCache()[$strDomain]; + } + return NULL; + } /** * Undocumented function @@ -59,19 +96,20 @@ class DomainModel extends BaseModel */ public function getFomartSubject($strKey) //, $intNum = 1, $boolRand = false) { - // echo $strKey; - // exit; - // echo '
';
-        // var_dump($this->t_cfg);
-        // exit;
         $intSfgId = $this->t_cfg->{$strKey}['sfg_id'];
-        // $SubjectFomartCol = SubjectFomartModel::where('sfg_id', $intSfgId)->select();
 
-        $SubjectFomartModel =  SubjectFomartModel::where('sfg_id', $intSfgId)->select()->first();
-        // var_dump($SubjectFomartModel->toArray());
+        // $SubjectFomartModel = SubjectFomartModel::where('sfg_id', $intSfgId)->select()->first();
+        $arrAllSubjectFomartModel = SubjectFomartModel::getAllSubjectFomartOnCacheBySfgId($intSfgId);
+
+        $SubjectFomartModel =  (is_array($arrAllSubjectFomartModel) && !empty($arrAllSubjectFomartModel)) ? reset($arrAllSubjectFomartModel) : null;
+
+        return empty($SubjectFomartModel) ? '' : $SubjectFomartModel->sf_val;
+
+        // echo '
';
+        // print_r($SubjectFomartModel);
         // exit;
 
-        return  $SubjectFomartModel->sf_val;
+        // return  $SubjectFomartModel->sf_val;
     }
 
 
@@ -79,14 +117,11 @@ class DomainModel extends BaseModel
      * Undocumented function
      *
      * @param array $arrArgs
-     * @return void
+     * @return string
      */
     static public function getPageUrl($strKey, array $arrArgs): string
     {
         $Request = request();
-        // $strKey = $Request->controller(false, true) . '@' .
-        //     $Request->action(true) . '@URL';
-        // $strKey = strtoupper($strKey);
 
         $strSfVal =  $Request->DomainModel->getFomartSubject($strKey);
 
diff --git a/code/app/model/SubjectFomartModel.php b/code/app/model/SubjectFomartModel.php
index 9ed9f7c..4676a1c 100644
--- a/code/app/model/SubjectFomartModel.php
+++ b/code/app/model/SubjectFomartModel.php
@@ -14,4 +14,43 @@ class SubjectFomartModel extends BaseModel
 {
     protected $name = 'subject_fomart';
     protected $pk = 'sf_id';
+
+    static public $arrAllSubjectFomart = [];
+
+    /**
+     * Undocumented function
+     *
+     * @param integer $intSfgId
+     * @return SubjectFomartModel[]
+     */
+    static public function getAllSubjectFomartOnCacheBySfgId(int $intSfgId): array
+    {
+        if (empty(self::$arrAllSubjectFomart)) {
+            $strKey = 'SubjectFomart:All';
+            self::$arrAllSubjectFomart = Cache::get($strKey);
+            if (empty(self::$arrAllSubjectFomart)) {
+                self::flushAllSubjectFomartOnCache();
+            }
+        }
+
+        return self::$arrAllSubjectFomart[$intSfgId] ?? [];
+    }
+
+    /**
+     * Undocumented function
+     *
+     * @return void
+     */
+    static public function flushAllSubjectFomartOnCache()
+    {
+        self::$arrAllSubjectFomart = [];
+        $strKey = 'SubjectFomart:All';
+        $SubjectFomartModelAll = SubjectFomartModel::select();
+        foreach ($SubjectFomartModelAll as $SubjectFomartModel) {
+            self::$arrAllSubjectFomart[$SubjectFomartModel->sfg_id][] = $SubjectFomartModel;
+        }
+
+        return Cache::set($strKey, self::$arrAllSubjectFomart);
+    }
+
 }
diff --git a/code/app/model/TemplatesModel.php b/code/app/model/TemplatesModel.php
index 9b6199c..a562fd6 100644
--- a/code/app/model/TemplatesModel.php
+++ b/code/app/model/TemplatesModel.php
@@ -32,29 +32,55 @@ class TemplatesModel extends BaseModel
     //     }
     // }
 
+    static public $arrAllTemplate = [];
 
-    static $arrTemplates = [];
-
-    static public function getTemplateOnCache($intTId)
+    /**
+     * Undocumented function
+     *
+     * @return array
+     */
+    static public function getAllTemplateOnCache(): array
     {
-        if (self::$arrTemplates == []) {
-            self::$arrTemplates =  Cache::get('Templates');
-
-            if (empty(self::$arrTemplates)) {
-                self::flushCache();
-                self::$arrTemplates =  Cache::get('Templates');
+        if (empty(self::$arrAllTemplate)) {
+            $strKey = 'Template:All';
+            self::$arrAllTemplate = Cache::get($strKey);
+            if (empty(self::$arrAllTemplate)) {
+                self::flushAllTemplateOnCache();
             }
         }
-
-        return  self::$arrTemplates[$intTId] ?? NULL;
+        return  self::$arrAllTemplate;
     }
 
-    static public function flushCache()
+    /**
+     * Undocumented function
+     *
+     * @return void
+     */
+    static public function flushAllTemplateOnCache()
     {
-        $TemplatesModelAll = self::select();
 
-        $TemplatesCol = $TemplatesModelAll->column(null, 't_id');
+        self::$arrAllTemplate = [];
+        $strKey = 'Template:All';
+        $TemplateModelAll = self::select();
+        foreach ($TemplateModelAll as $TemplateModel) {
+            self::$arrAllTemplate[$TemplateModel->t_id] = $TemplateModel;
+        }
 
-        Cache::tag('Templates')->set('Templates', $TemplatesCol);
+        return Cache::set($strKey, self::$arrAllTemplate);
+    }
+
+    /**
+     * Undocumented function
+     *
+     * @param int $intTId
+     * @return TemplatesModel|NULL
+     */
+    static public function getTemplateOnCacheByTId(int $intTId): TemplatesModel|NULL
+    {
+        if (key_exists($intTId, self::getAllTemplateOnCache())) {
+            return self::getAllTemplateOnCache()[$intTId];
+        }
+
+        return NULL;
     }
 }
diff --git a/code/extend/template/ziku/WordsEntities.php b/code/extend/template/ziku/WordsEntities.php
index f08570f..a478f99 100644
--- a/code/extend/template/ziku/WordsEntities.php
+++ b/code/extend/template/ziku/WordsEntities.php
@@ -9,7 +9,6 @@ class WordsEntities
 
     static public function getWords($strWords)
     {
-
         if (!isset(self::$arrZiKu[$strWords])) {
             self::$arrZiKu[$strWords] = customEntities($strWords);
         }

From df4278d1d8bc544142ddb6a29f4c8fdb248c0124 Mon Sep 17 00:00:00 2001
From: Default 
Date: Mon, 7 Apr 2025 20:18:03 +0800
Subject: [PATCH 2/5] debug

---
 code/app/home/controller/Novel.php | 94 ++++++++++++++----------------
 1 file changed, 43 insertions(+), 51 deletions(-)

diff --git a/code/app/home/controller/Novel.php b/code/app/home/controller/Novel.php
index 35d2473..a9b7f17 100644
--- a/code/app/home/controller/Novel.php
+++ b/code/app/home/controller/Novel.php
@@ -82,11 +82,11 @@ class Novel extends BaseController
             'strDescription' => $strDescription,
             'strPageCode' => 'rank'
         ]);
-        if ($boolIsMobile) {
-            return View::fetch();
-        } else {
-            return View::fetch('pc/getNovelRank');
-        }
+
+
+        $strView = $boolIsMobile ? '' : 'pc/getNovelRank';
+
+        return $this->rending($strView);
     }
 
     /**
@@ -170,8 +170,8 @@ class Novel extends BaseController
         // 更新值
         ConverterMovel::setVal([
             'intPage' => $intPage,
-            'strNovelSex' => $arrSexChinese[$strGender],  
-            'strNovelCategoryName' => str_replace("小说", "", $strSearchCategory), 
+            'strNovelSex' => $arrSexChinese[$strGender],
+            'strNovelCategoryName' => str_replace("小说", "", $strSearchCategory),
             'strNovelStatus' => $strSearchStatus,
         ]);
 
@@ -199,8 +199,7 @@ class Novel extends BaseController
             'strDescription' => $strDescription,
 
         ]);
-
-        return View::fetch($strTemplate);
+        return $this->rending($strTemplate);
     }
 
     /**
@@ -262,11 +261,11 @@ class Novel extends BaseController
             'strKeywords' => $strKeywords,
             'strDescription' => $strDescription,
         ]);
-        if ($boolIsMobile) {
-            return View::fetch();
-        } else {
-            return View::fetch('pc/getNovelChannel');
-        }
+
+
+        $strView = $boolIsMobile ? '' : 'pc/getNovelChannel';
+
+        return $this->rending($strView);
     }
 
     /**
@@ -414,7 +413,7 @@ class Novel extends BaseController
             'strNovelName' => $arrNovel['og_novel_book_name'],
             'strNovelAuthor' => $arrNovel['og_novel_author'],
             'strNovelCategoryName' => $arrNovel['og_novel_category'],
-            'strNovelSex' => $arrNovel['category_sex'] == 'man' ? '男生' : '女生', 
+            'strNovelSex' => $arrNovel['category_sex'] == 'man' ? '男生' : '女生',
             'strNovelStatus' => $arrNovel['og_novel_status'],
             'strNovelDescription' => $arrNovel['n_page_description'],
         ]);
@@ -444,13 +443,11 @@ class Novel extends BaseController
             'strKeywords' => $strKeywords,
             'strDescription' => $strDescription,
         ]);
-       
 
-        if ($boolIsMobile) {
-            return View::fetch('getNovelInfo');
-        } else {
-            return View::fetch('pc/getNovelInfo');
-        }
+
+        $strView = $boolIsMobile ? 'getNovelInfo' : 'pc/getNovelInfo';
+
+        return $this->rending($strView);
     }
 
     /**
@@ -511,7 +508,7 @@ class Novel extends BaseController
             'strNovelName' => $arrNovel['og_novel_book_name'],
             'strNovelAuthor' => $arrNovel['og_novel_author'],
             'strNovelCategoryName' => $arrNovel['og_novel_category'],
-            'strNovelSex' => $arrNovel['category_sex'] == 'man' ? '男生' : '女生', 
+            'strNovelSex' => $arrNovel['category_sex'] == 'man' ? '男生' : '女生',
             'strNovelStatus' => $arrNovel['og_novel_status'],
             'strNovelDescription' => $arrNovel['n_page_description'],
         ]);
@@ -536,11 +533,10 @@ class Novel extends BaseController
             'strKeywords' => $strKeywords,
             'strDescription' => $strDescription,
         ]);
-        if ($boolIsMobile) {
-            return View::fetch();
-        } else {
-            return View::fetch('pc/getNovelInfo');
-        }
+
+        $strView = $boolIsMobile ? '' : 'pc/getNovelInfo';
+
+        return $this->rending($strView);
     }
 
     /**
@@ -626,11 +622,10 @@ class Novel extends BaseController
             'strKeywords' => $strKeywords,
             'strDescription' => $strDescription,
         ]);
-        if ($boolIsMobile) {
-            return View::fetch('getNovelChapter');
-        } else {
-            return View::fetch('pc/getNovelChapter');
-        }
+
+        $strView = $boolIsMobile ? 'getNovelChapter' : 'pc/getNovelChapter';
+
+        return $this->rending($strView);
     }
 
 
@@ -702,11 +697,10 @@ class Novel extends BaseController
             'strKeywords' => $strKeywords,
             'strDescription' => $strDescription,
         ]);
-        if ($boolIsMobile) {
-            return View::fetch();
-        } else {
-            return View::fetch('pc/getNovelChapter');
-        }
+
+        $strView = $boolIsMobile ? '' : 'pc/getNovelChapter';
+
+        return $this->rending($strView);
     }
 
     /**
@@ -754,7 +748,7 @@ class Novel extends BaseController
         // 更新值
         ConverterMovel::setVal([
             'intPage' => $intPage,
-            'strNovelSex' => $arrNovel['category_sex'] == 'man' ? '男生' : '女生', 
+            'strNovelSex' => $arrNovel['category_sex'] == 'man' ? '男生' : '女生',
             'strNovelName' => $arrNovel['og_novel_book_name'],
             'strNovelAuthor' => $arrNovel['og_novel_author'],
             'strNovelCategoryName' => $arrNovel['og_novel_category'],
@@ -783,11 +777,11 @@ class Novel extends BaseController
             'strKeywords' => $strKeywords,
             'strDescription' => $strDescription,
         ]);
-        if ($boolIsMobile) {
-            return View::fetch();
-        } else {
-            return View::fetch('pc/getNovelChapterAll');
-        }
+
+
+        $strView = $boolIsMobile ? '' : 'pc/getNovelChapterAll';
+
+        return $this->rending($strView);
     }
 
     /**
@@ -832,9 +826,9 @@ class Novel extends BaseController
         ConverterMovel::setVal([
             'intPage' => $intPage,
             'strSearchKeywords' => $strSearchKeywords,
-             // FIXED 如果不知道怎么做,就不要用这个模板,你现在太过依赖这个模板,这个模板如果是一个刚毕业的大学生的垃圾论文项目,你也被他的四维锁死?
-             // 这个和模板没有关系, 昨天 grok 使用超限制了,使用you.com 提供的 tkd 设计,它设计的 tkd模板 需要的 字段比较多,那几个 性别 和 分类 放在搜索是不太合理
-             // 现在改了,使用grok 设计的 ,ai 记录在  app/home/view/kuangyu/推广SEO过程设计记录/TKD/搜索页Tkd.md
+            // FIXED 如果不知道怎么做,就不要用这个模板,你现在太过依赖这个模板,这个模板如果是一个刚毕业的大学生的垃圾论文项目,你也被他的四维锁死?
+            // 这个和模板没有关系, 昨天 grok 使用超限制了,使用you.com 提供的 tkd 设计,它设计的 tkd模板 需要的 字段比较多,那几个 性别 和 分类 放在搜索是不太合理
+            // 现在改了,使用grok 设计的 ,ai 记录在  app/home/view/kuangyu/推广SEO过程设计记录/TKD/搜索页Tkd.md
         ]);
 
         $strTitleTemplate =  $Request->DomainModel->getFomartSubject(getFomartSubjectKey(__METHOD__) . '@TITLE');
@@ -856,12 +850,10 @@ class Novel extends BaseController
             'strKeywords' => $strKeywords,
             'strDescription' => $strDescription,
         ]);
+        
+        $strView = $boolIsMobile ? '' : 'pc/getSearchNovel';
 
-        if ($boolIsMobile) {
-            return View::fetch();
-        } else {
-            return View::fetch('pc/getSearchNovel');
-        }
+        return $this->rending($strView);
     }
 
     /**

From fe3fb26bd7b7e71b2bbca6f745528512a447cd4d Mon Sep 17 00:00:00 2001
From: Default 
Date: Tue, 8 Apr 2025 00:27:02 +0800
Subject: [PATCH 3/5] debug

---
 code/app/home/BaseController.php              |   2 -
 code/app/home/controller/Novel.php            |  20 +-
 code/app/home/view/kuangyu/basePc.html        |  10 +-
 code/app/model/CategoryModel.php              |  11 ++
 code/app/model/ChapterModel.php               |   8 +-
 code/app/model/NovelModel.php                 |  39 ++--
 code/app/task/crawler/zw630/Scheduler.php     |   4 +-
 .../task/crawler/zw630/page/ChapterPage.php   |  28 ++-
 .../app/task/crawler/zw630/page/NovelPage.php |  12 ++
 code/app/task/crawler/zw630/page/Site.php     |   2 +-
 code/config/console.php                       |   2 +
 code/database/mongo/migrations/category.php   |  10 +
 code/database/mongo/migrations/chapter.php    |  23 +++
 code/database/mongo/migrations/novel.php      |  34 ++++
 .../mongo/migrations/novel_clicks.php         |  10 +
 code/extend/db/DatabaseManage.php             |   2 +-
 code/extend/db/MongoMigrate.php               | 176 ++++++++++++++++++
 code/extend/db/NovelManage.php                | 114 ++++++++++++
 18 files changed, 461 insertions(+), 46 deletions(-)
 create mode 100644 code/database/mongo/migrations/category.php
 create mode 100644 code/database/mongo/migrations/chapter.php
 create mode 100644 code/database/mongo/migrations/novel.php
 create mode 100644 code/database/mongo/migrations/novel_clicks.php
 create mode 100644 code/extend/db/MongoMigrate.php
 create mode 100644 code/extend/db/NovelManage.php

diff --git a/code/app/home/BaseController.php b/code/app/home/BaseController.php
index 5c28d30..7bc3838 100644
--- a/code/app/home/BaseController.php
+++ b/code/app/home/BaseController.php
@@ -62,8 +62,6 @@ abstract class BaseController
      */
     protected function initialize()
     {
-        // TODO 因为视图无法渲染 request 暂时使用这个
-        View::assign("DomainModel", $this->request->DomainModel);
         $this->initSiteTKD();
     }
 
diff --git a/code/app/home/controller/Novel.php b/code/app/home/controller/Novel.php
index a9b7f17..a7645d4 100644
--- a/code/app/home/controller/Novel.php
+++ b/code/app/home/controller/Novel.php
@@ -357,14 +357,13 @@ class Novel extends BaseController
      */
     public function getKanNovelInfo(Request $Request)
     {
-        // TODO 这个页面数据没有处理
-        // FIXED 不要这样打标记好不好,沟通成本太高了,你直接标注缺少什么数据,什么数据有问题,什么数据需要转换
-        // TODO  这个是 kan 小说页面的控制器,是直接复制 小说详情的控制器,
-        //       1.从这个页面上看,这个应该展示 kan 小说的名字才对,目前 title 还是 小说的名字 ,
+
         //       $arrNovel['og_novel_book_name']  = kan 小说 的 名字
 
         $intNId = $Request->param('n_id');
 
+        $intForgeId = $Request->param('n_forge_id');
+
         $boolIsMobile = $Request->param('boolIsMobile');
 
         $NovelModel = new NovelModel;
@@ -372,6 +371,13 @@ class Novel extends BaseController
         // 小说详情
         $arrNovel = $NovelModel->getNovelByNId($intNId);
 
+        foreach ($arrNovel['n_forge_novel'] as $arrForgeNovel) {
+            if ($arrForgeNovel['n_forge_id'] == $intForgeId) {
+                $arrNovel['og_novel_book_name'] = $arrForgeNovel['n_forge_title'];
+                break;
+            }
+        }
+
         // 分品拼音
         $arrNovel['category_pinyin'] = CategoryModel::getPinYinByZh($arrNovel['og_novel_category']);
 
@@ -826,9 +832,7 @@ class Novel extends BaseController
         ConverterMovel::setVal([
             'intPage' => $intPage,
             'strSearchKeywords' => $strSearchKeywords,
-            // FIXED 如果不知道怎么做,就不要用这个模板,你现在太过依赖这个模板,这个模板如果是一个刚毕业的大学生的垃圾论文项目,你也被他的四维锁死?
-            // 这个和模板没有关系, 昨天 grok 使用超限制了,使用you.com 提供的 tkd 设计,它设计的 tkd模板 需要的 字段比较多,那几个 性别 和 分类 放在搜索是不太合理
-            // 现在改了,使用grok 设计的 ,ai 记录在  app/home/view/kuangyu/推广SEO过程设计记录/TKD/搜索页Tkd.md
+
         ]);
 
         $strTitleTemplate =  $Request->DomainModel->getFomartSubject(getFomartSubjectKey(__METHOD__) . '@TITLE');
@@ -850,7 +854,7 @@ class Novel extends BaseController
             'strKeywords' => $strKeywords,
             'strDescription' => $strDescription,
         ]);
-        
+
         $strView = $boolIsMobile ? '' : 'pc/getSearchNovel';
 
         return $this->rending($strView);
diff --git a/code/app/home/view/kuangyu/basePc.html b/code/app/home/view/kuangyu/basePc.html
index 691e313..9785f8c 100644
--- a/code/app/home/view/kuangyu/basePc.html
+++ b/code/app/home/view/kuangyu/basePc.html
@@ -91,14 +91,8 @@
     
     
     {$DomainModel->d_statis|raw}
-    {:request()->DomainModel->d_statis}
-    
-    
-    
-    
-    
-    
-    {:request()->DomainModel->d_domian}
+
+
 
 
 
\ No newline at end of file
diff --git a/code/app/model/CategoryModel.php b/code/app/model/CategoryModel.php
index 664ed00..1164f1f 100644
--- a/code/app/model/CategoryModel.php
+++ b/code/app/model/CategoryModel.php
@@ -124,4 +124,15 @@ class CategoryModel extends MongoModel
     {
         return in_array($strName, self::$arrMan) ? 'man' : 'women';
     }
+
+    /**
+     * determine the gender of the novel category
+     *
+     * @param string $strName
+     * @return string
+     */
+    static public function checkSexZh(string $strName): string
+    {
+        return in_array($strName, self::$arrMan) ? '男生' : '女生';
+    }
 }
diff --git a/code/app/model/ChapterModel.php b/code/app/model/ChapterModel.php
index 5741e5f..1dd6e96 100644
--- a/code/app/model/ChapterModel.php
+++ b/code/app/model/ChapterModel.php
@@ -123,7 +123,7 @@ class ChapterModel extends MongoModel
      * @param integer $intNId
      * @return null|array
      */
-    public function getLatestChapter(int $intNId): null|array
+    public function getLatestChapter(int $intNId, bool $boolReadContent = true): null|array
     {
         $arrFilter = ['n_id' => $intNId, 'c_page' => 0];
 
@@ -135,8 +135,10 @@ class ChapterModel extends MongoModel
 
         if (!empty($arrChapter)) {
             applyToKeys($arrChapter, ['created_at', 'updated_at'], 'formatMongoDate');
-
-            $arrChapter['content'] = StorageCore::getInstance()->read($arrChapter['c_content_path']);
+            $arrChapter['content'] = '';
+            if ($boolReadContent) {
+                $arrChapter['content'] = StorageCore::getInstance()->read($arrChapter['c_content_path']);
+            }
         }
 
         return  $arrChapter ?? [];
diff --git a/code/app/model/NovelModel.php b/code/app/model/NovelModel.php
index 14df81b..cd5eacb 100644
--- a/code/app/model/NovelModel.php
+++ b/code/app/model/NovelModel.php
@@ -88,6 +88,7 @@ class NovelModel extends MongoModel
 
         $arrOptions['limit'] = $intCount;
 
+        $arrFilter['n_have_chapter'] = 1;
 
         $Cursor = $this->getCol()->find($arrFilter, $arrOptions);
 
@@ -110,14 +111,11 @@ class NovelModel extends MongoModel
      */
     public function getNovelByNId(int $intNId): null|array
     {
-        $arrFilter = ['n_id' => $intNId];
+        $arrFilter = ['n_id' => $intNId, 'n_have_chapter' => 1];
         $arrOptions = self::$arrNovelOptions;
         $arrNovel =  $this->getOne($arrFilter, $arrOptions);
         applyToKeys($arrNovel, ['created_at', 'updated_at'], 'formatMongoDate');
-        if (!empty($arrNovel['og_novel_category'])) {
-            $arrNovel['category_pinyin'] = CategoryModel::getPinYinByZh($arrNovel['og_novel_category']);
-            $arrNovel['category_sex'] = CategoryModel::checkSex($arrNovel['og_novel_category']);
-        }
+
 
         return $arrNovel;
     }
@@ -141,6 +139,8 @@ class NovelModel extends MongoModel
                 return $arrResult;
             }
 
+            $arrFilter['n_have_chapter'] = 1;
+
             $pipeline = [
                 ['$match' => $arrFilter],
                 ['$sample' => ['size' => $intCount]]
@@ -180,7 +180,7 @@ class NovelModel extends MongoModel
         $strStatus = NULL,
         array $arrSort = ['n_level' => -1]
     ): array {
-        $arrFilter = [];
+        $arrFilter = ['n_have_chapter' => 1,];
 
         switch ($intType) {
             case 1:
@@ -219,6 +219,7 @@ class NovelModel extends MongoModel
         int $intLifeTime = 24 * 3600,
     ): array {
         try {
+            $arrFilter['n_have_chapter'] = 1;
 
             $arrResult = $this->checkCacheByKey($strKey);
             if ($arrResult !== NULL) {
@@ -295,7 +296,7 @@ class NovelModel extends MongoModel
                 return $arrResult;
             }
 
-            $arrFilter = [];
+            $arrFilter = ['n_have_chapter' => 1,];
 
             switch ($intType) {
                 case 1:
@@ -362,12 +363,12 @@ class NovelModel extends MongoModel
             $intLifeTime = 24 * 3600;
 
             $arrResult =  $this->checkCacheByKey($strKey);
-          
+
             if ($arrResult !== NULL) {
                 return $arrResult;
             }
 
-            $arrFilter = [];
+            $arrFilter = ['n_have_chapter' => 1,];
             switch ($intType) {
                 case 1:
                     $arrCategory = array_values(CategoryModel::getManCategory());
@@ -398,10 +399,10 @@ class NovelModel extends MongoModel
                 ],
             ];
 
-        
+
             $Cursor = $this->getCol()->find($arrFilter, $arrOptions);
             $arrResult = iterator_to_array($Cursor);
-      
+
             shuffle($arrResult);
 
             $arrResult = array_slice($arrResult, 0, $intCount);
@@ -435,6 +436,7 @@ class NovelModel extends MongoModel
             }
             $arrFilter = [
                 'og_novel_status' => "已完结",
+                'n_have_chapter' => 1,
             ];
 
             $arrOptions = [
@@ -487,19 +489,16 @@ class NovelModel extends MongoModel
             if ($arrResult !== NULL) {
                 return $arrResult;
             }
+
+            $arrFilter = ['n_have_chapter' => 1,];
+
             if ($intType == 1) {
                 $arrCategory = array_values(CategoryModel::getManCategory());
-                $arrFilter = [
-                    'og_novel_category' => ['$in' => $arrCategory]
-                ];
+                $arrFilter['og_novel_category'] = ['$in' => $arrCategory];
             } elseif ($intType == 2) {
                 $arrCategory = array_values(CategoryModel::getWomenCategory());
-                $arrFilter = [
-                    'og_novel_category' => ['$in' => $arrCategory]
-                ];
-            } else {
-                $arrFilter = [];
-            }
+                $arrFilter['og_novel_category'] = ['$in' => $arrCategory];
+            } 
 
             $arrOptions = [
                 'sort' => ['og_novel_update_time' => -1],
diff --git a/code/app/task/crawler/zw630/Scheduler.php b/code/app/task/crawler/zw630/Scheduler.php
index a10c558..d8ece01 100644
--- a/code/app/task/crawler/zw630/Scheduler.php
+++ b/code/app/task/crawler/zw630/Scheduler.php
@@ -36,8 +36,8 @@ class Scheduler
 
         $arrFilter = [];
         // for ($intNId = 1; $intNId <= 531208; $intNId++) {
-            // for ($intNId = 1; $intNId <= 10000; $intNId++) {
-            for ($intNId = 1; $intNId <= 20000; $intNId++) {
+        // for ($intNId = 1; $intNId <= 10000; $intNId++) {
+        for ($intNId = 1; $intNId <= 6; $intNId++) {
             $arrFilter[] = [
                 'n_source_id' => $intNId,
                 'page' => 0,
diff --git a/code/app/task/crawler/zw630/page/ChapterPage.php b/code/app/task/crawler/zw630/page/ChapterPage.php
index f91a330..72478dd 100644
--- a/code/app/task/crawler/zw630/page/ChapterPage.php
+++ b/code/app/task/crawler/zw630/page/ChapterPage.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace app\task\crawler\zw630\page;
 
+use app\model\ChapterModel;
 use storage\StorageCore;
 
 class ChapterPage extends BasePage
@@ -70,7 +71,7 @@ class ChapterPage extends BasePage
                 $arrExisting = (array) $arrExisting;
                 $this->arrChapterInfo = array_merge($arrExisting,   $this->getChapterInfo());
 
-                $this->arrChapterInfo['updated_at'] = new \MongoDB\BSON\UTCDateTime(); // 添加更新时间
+                $this->arrChapterInfo['updated_at'] = new \MongoDB\BSON\UTCDateTime();
                 $Col->updateOne(
                     ['c_site_uuid' => $strUUId],
                     ['$set' =>   $this->arrChapterInfo],
@@ -94,6 +95,8 @@ class ChapterPage extends BasePage
 
                 $this->getMongoBase()->insertOne('chapter',   $this->arrChapterInfo);
 
+                $this->updateNovelHaveChapter($intNId);
+
                 if (!StorageCore::getInstance()->has($this->arrChapterInfo['c_content_path'])) {
                     StorageCore::getInstance()->set($this->arrChapterInfo['c_content_path'], $this->strChapterContent);
                 }
@@ -106,6 +109,29 @@ class ChapterPage extends BasePage
         }
     }
 
+
+    /**
+     * Undocumented function
+     *
+     * @param integer $intNId
+     * @return void
+     */
+    protected function updateNovelHaveChapter(int $intNId)
+    {
+        $arrFilter = [
+            'n_id' => $intNId,
+        ];
+
+        $ChapterModel =  new ChapterModel;
+        $arrLasteChapter =  $ChapterModel->getLatestChapter($intNId, false);
+
+        if (!empty($arrLasteChapter)) {
+            $arrUpdate['$set']['n_have_chapter'] = 1;
+            $arrUpdate['$set']['og_novel_latest_chapter_name'] = $arrLasteChapter['name'];
+            $this->getMongoBase()->updateOne('novel', $arrFilter, $arrUpdate);
+        }
+    }
+
     protected $arrNextPage;
 
     /**
diff --git a/code/app/task/crawler/zw630/page/NovelPage.php b/code/app/task/crawler/zw630/page/NovelPage.php
index d98d3ab..882ffa1 100644
--- a/code/app/task/crawler/zw630/page/NovelPage.php
+++ b/code/app/task/crawler/zw630/page/NovelPage.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace app\task\crawler\zw630\page;
 
+use app\model\CategoryModel;
 use ddl\DDLManage;
 use QL\QueryList;
 
@@ -51,6 +52,7 @@ class NovelPage extends BasePage
             $arrNovelInfo['n_site_uuid'] = $strUUId;
             $arrNovelInfo['n_source_id'] = $intNSourceId;
             $arrNovelInfo['n_level'] = 1;
+            $arrNovelInfo['n_have_chapter'] = 0;
             $arrNovelInfo['n_id'] =  $this->getMongoBase()->getNextSequence('novel');
             $this->getMongoBase()->insertOne('novel',   $arrNovelInfo);
         }
@@ -176,7 +178,17 @@ class NovelPage extends BasePage
                 $this->arrNovelInfo['n_source_id'] = $this->arrData['n_source_id'];
                 $this->arrNovelInfo['n_id'] =  $this->getMongoBase()->getNextSequence('novel');
                 $this->arrNovelInfo['n_level'] = 1;
+                $this->arrNovelInfo['n_have_chapter'] = 0;
                 $this->arrNovelInfo['n_cover_path'] = '/img/' . date('Y/m/d', time() - 24 * 3600 * 14) . '/' . $this->arrNovelInfo['n_id'] . '.jpg';
+
+                
+                if (!empty($this->arrNovelInfo['og_novel_category'])) {
+                    $this->arrNovelInfo['category_pinyin'] = CategoryModel::getPinYinByZh($this->arrNovelInfo['og_novel_category']);
+                    $this->arrNovelInfo['category_sex'] = CategoryModel::checkSex($this->arrNovelInfo['og_novel_category']);
+                    $this->arrNovelInfo['category_sex_zh'] = CategoryModel::checkSexZh($this->arrNovelInfo['og_novel_category']);
+                }
+
+
                 $this->getMongoBase()->insertOne('novel',   $this->arrNovelInfo);
 
                 $this->boolIsFirstSave = true;
diff --git a/code/app/task/crawler/zw630/page/Site.php b/code/app/task/crawler/zw630/page/Site.php
index 86adbb7..d36bc15 100644
--- a/code/app/task/crawler/zw630/page/Site.php
+++ b/code/app/task/crawler/zw630/page/Site.php
@@ -25,7 +25,7 @@ class Site
      *
      * @var string
      */
-    protected $strDomain = 'https://www.630zw.org';
+    protected $strDomain = 'https://www.630zw.com';
 
     /**
      * Undocumented function
diff --git a/code/config/console.php b/code/config/console.php
index 98da0ec..10089f1 100644
--- a/code/config/console.php
+++ b/code/config/console.php
@@ -11,5 +11,7 @@ return [
     'commands' => [
         'task' => 'microserver\ServerConsole',
         'db:manage' => 'db\DatabaseManage',
+        'mongo:manage' => 'db\MongoMigrate',
+        'novel:manage' => 'db\NovelManage',
     ],
 ];
diff --git a/code/database/mongo/migrations/category.php b/code/database/mongo/migrations/category.php
new file mode 100644
index 0000000..ed64e88
--- /dev/null
+++ b/code/database/mongo/migrations/category.php
@@ -0,0 +1,10 @@
+ 'category',
+    'indexes' => [
+        [
+            'key' => ['ca_name' => 1],
+            'options' => ['unique' => true]
+        ],
+    ]
+];
diff --git a/code/database/mongo/migrations/chapter.php b/code/database/mongo/migrations/chapter.php
new file mode 100644
index 0000000..fe81801
--- /dev/null
+++ b/code/database/mongo/migrations/chapter.php
@@ -0,0 +1,23 @@
+ 'chapter',
+    'indexes' => [
+        [
+            'key' => ['c_site_uuid' => 1],
+            'options' => ['unique' => true]
+        ],
+
+        [
+            'key' => ['n_id' => 1],
+            'options' => ['unique' => false]
+        ],
+        [
+            'key' => ['c_sort_num' => 1],
+            'options' => ['unique' => false]
+        ],
+        [
+            'key' => ['c_page' => 1],
+            'options' => ['unique' => false]
+        ],
+    ]
+];
diff --git a/code/database/mongo/migrations/novel.php b/code/database/mongo/migrations/novel.php
new file mode 100644
index 0000000..4baab22
--- /dev/null
+++ b/code/database/mongo/migrations/novel.php
@@ -0,0 +1,34 @@
+ 'novel',
+    'indexes' => [
+        [
+            'key' => ['n_id' => 1],
+            'options' => ['unique' => false]
+        ],
+        [
+            'key' => ['og_title' => 1],
+            'options' => ['unique' => false]
+        ],
+        [
+            'key' => ['og_novel_status' => 1],
+            'options' => ['unique' => false]
+        ],
+        [
+            'key' => ['n_site_uuid' => 1],
+            'options' => ['unique' => true]
+        ],
+        [
+            'key' => ['n_related_novel.n_id' => 1],
+            'options' => ['unique' => false]
+        ],
+        [
+            'key' => ['n_forge_novel.n_forge_id' => 1],
+            'options' => ['unique' => false]
+        ],
+        [
+            'key' => ['n_have_chapter' => 1],
+            'options' => ['unique' => false]
+        ],
+    ]
+];
diff --git a/code/database/mongo/migrations/novel_clicks.php b/code/database/mongo/migrations/novel_clicks.php
new file mode 100644
index 0000000..66665a7
--- /dev/null
+++ b/code/database/mongo/migrations/novel_clicks.php
@@ -0,0 +1,10 @@
+ 'novel_clicks',
+    'indexes' => [
+        [
+            'key' => ['n_id' => 1, 'nc_date' => 1, 'nc_type' => 1],
+            'options' => ['unique' => true]
+        ],
+    ]
+];
diff --git a/code/extend/db/DatabaseManage.php b/code/extend/db/DatabaseManage.php
index 89dc728..b1432a2 100644
--- a/code/extend/db/DatabaseManage.php
+++ b/code/extend/db/DatabaseManage.php
@@ -98,7 +98,7 @@ class DatabaseManage extends Command
             $Output->writeln("创建临时导入文件失败.");
             return;
         }
-       
+
         $strCmd = "mysql -h{$strHost} -P{$strPort} -u{$strUserName} -p{$strPwd} {$strDb} < {$strTempFile}";
 
         system($strCmd, $intResultCode);
diff --git a/code/extend/db/MongoMigrate.php b/code/extend/db/MongoMigrate.php
new file mode 100644
index 0000000..2d84b68
--- /dev/null
+++ b/code/extend/db/MongoMigrate.php
@@ -0,0 +1,176 @@
+setName('mongo:manage')
+            ->addArgument('action', \think\console\input\Argument::OPTIONAL, 'The action to perform: migrate')
+            ->setDescription('Manage the mongo, migarte index or drop all index');
+    }
+
+    /**
+     * Undocumented function
+     *
+     * @param Input $input
+     * @param Output $Output
+     * @return void
+     */
+    protected function execute(Input $input, Output $Output)
+    {
+        $strAction = $input->getArgument('action');
+
+        if ($strAction === 'migrate') {
+            $this->migrate($Output);
+        } else  if ($strAction === 'drop') {
+            $this->dropAllIndexes($Output);
+        } else {
+            $Output->writeln("Invalid action. Use 'migrate'  or 'drop'");
+        }
+    }
+
+    /**
+     * Undocumented function
+     *
+     * @param Output $Output
+     * @return void
+     */
+    protected function dropAllIndexes(Output $Output)
+    {
+        try {
+            DDLManage::load('MongoBase');
+            $Db = MongoBase::getInstance()->getDb();
+
+            $ColsInfo =  $Db->listCollections();
+
+            foreach ($ColsInfo as $ColInfo) {
+                $strColName = $ColInfo->getName();
+                $Col =  $Db->selectCollection($strColName);
+
+
+                $arrIndexes = iterator_to_array($Col->listIndexes());
+                $arrIndexesToDrop = [];
+
+
+                foreach ($arrIndexes as $Index) {
+                    $strIndexName = $Index->getName();
+                    if ($strIndexName !== '_id_') {
+                        $arrIndexesToDrop[] = $strIndexName;
+                    }
+                }
+
+
+                if (!empty($arrIndexesToDrop)) {
+                    foreach ($arrIndexesToDrop as $strIndexName) {
+                        $Col->dropIndex($strIndexName);
+                        $Output->writeln("  Dropped index: {$strIndexName} from collection: {$strColName}");
+                    }
+                } else {
+                    $Output->writeln("  No non-_id indexes found in collection: {$strColName}");
+                }
+            }
+        } catch (\Exception $e) {
+            $Output->writeln("Failed to drop indexes: {$e->getMessage()}");
+        }
+    }
+
+    /**
+     * Undocumented function
+     *
+     * @param Output $Output
+     * @return void
+     */
+    protected function migrate(Output $Output)
+    {
+        try {
+            DDLManage::load('MongoBase');
+            $strMigrationDir =  root_path() . 'database/mongo/migrations';
+
+
+            if (!is_dir($strMigrationDir)) {
+                mkdir($strMigrationDir, 0755, true);
+                $Output->writeln("Created migration directory: {$strMigrationDir}");
+            }
+
+
+            $arrFiles = glob($strMigrationDir . '/*.php');
+            if (empty($arrFiles)) {
+                $Output->writeln('No migration files found.');
+                return 0;
+            }
+
+            sort($arrFiles);
+
+            $Db = MongoBase::getInstance()->getDb();
+
+            foreach ($arrFiles as $strFile) {
+                $Output->writeln("Processing migration: " . basename($strFile));
+
+
+                $arrMigration = require $strFile;
+                if (!is_array($arrMigration) || !isset($arrMigration['collection']) || !isset($arrMigration['indexes'])) {
+                    $Output->writeln("Invalid migration format in {$strFile}");
+                    continue;
+                }
+
+                $strCollectionName = $arrMigration['collection'];
+                $arrIndexes = $arrMigration['indexes'];
+
+
+                $Col =  $Db->selectCollection($strCollectionName);
+
+
+                $arrExistingIndexes = iterator_to_array($Col->listIndexes());
+
+                $arrExistingIndexKeys = [];
+                foreach ($arrExistingIndexes as $Index) {
+                    $strKey = json_encode($Index->getKey());
+                    $arrExistingIndexKeys[$strKey] = $Index->getName();
+                }
+
+
+                foreach ($arrIndexes as $arrIndex) {
+                    $arrKey = $arrIndex['key'];
+                    $arrOptions = $arrIndex['options'] ?? [];
+
+
+                    $strKey = json_encode($arrKey);
+
+
+                    if (array_key_exists($strKey, $arrExistingIndexKeys)) {
+                        $Output->writeln("  Index for " . json_encode($arrKey) . " already exists as {$arrExistingIndexKeys[$strKey]}, skipping...");
+                        continue;
+                    }
+
+
+                    $arrIndexNameParts = [];
+                    foreach ($arrKey as $field => $direction) {
+                        $arrIndexNameParts[] = "{$field}_{$direction}";
+                    }
+                    $strIndexName = implode('_', $arrIndexNameParts);
+
+
+                    $arrOptions['name'] = $strIndexName;
+                    $Col->createIndex($arrKey, $arrOptions);
+
+                    $Output->writeln("  Created index: {$strIndexName} for " . json_encode($arrKey));
+                }
+            }
+
+            $Output->writeln('Migration completed successfully!');
+            return 0;
+        } catch (\Exception $e) {
+            $Output->writeln("Error: {$e->getMessage()}");
+            return 1;
+        }
+    }
+}
diff --git a/code/extend/db/NovelManage.php b/code/extend/db/NovelManage.php
new file mode 100644
index 0000000..0120566
--- /dev/null
+++ b/code/extend/db/NovelManage.php
@@ -0,0 +1,114 @@
+setName('novel:manage')
+            ->addArgument('action', \think\console\input\Argument::OPTIONAL, 'The action to perform: reset')
+            ->setDescription('Manage the novel data: reset or ...');
+    }
+
+    protected function execute(Input $input, Output $Output)
+    {
+        $strAction = $input->getArgument('action');
+
+        if ($strAction === 'reset') {
+            $this->resetData($Output);
+        } else {
+            $Output->writeln("Invalid action. Use 'reset' ");
+        }
+    }
+
+    private function resetData(Output $Output)
+    {
+        DDLManage::load('MongoBase');
+
+        $Db = MongoBase::getInstance()->getDb();
+
+        $NovelCol = $Db->selectCollection('novel');
+
+        $ChapterCol = $Db->selectCollection('chapter');
+
+        $ChapterModel =  new ChapterModel;
+
+        $intBatchSize = 1000;
+
+        $LastId = null;
+
+        while (true) {
+
+            $arrFilter = [];
+            if (!is_null($LastId)) {
+                $arrFilter['_id'] = ['$gt' => $LastId];
+            }
+            $arrOptions = [
+                'sort'           => ['_id' => 1],
+                'limit'          => $intBatchSize,
+                'noCursorTimeout' => true,
+            ];
+
+            $Cursor = $NovelCol->find($arrFilter, $arrOptions);
+            $arrDocs = iterator_to_array($Cursor);
+
+            if (empty($arrDocs)) {
+                echo "全部处理完毕。\n";
+                break;
+            }
+
+            $arrBulkOps = [];
+
+            foreach ($arrDocs as $arrDoc) {
+                $arrUpdateData = [];
+
+                if (!empty($arrDoc['og_novel_category'])) {
+                    $arrUpdateData['category_pinyin'] = CategoryModel::getPinYinByZh($arrDoc['og_novel_category']);
+                    $arrUpdateData['category_sex'] = CategoryModel::checkSex($arrDoc['og_novel_category']);
+                    $arrUpdateData['category_sex_zh'] = CategoryModel::checkSexZh($arrDoc['og_novel_category']);
+                }
+
+                $arrLasteChapter =  $ChapterModel->getLatestChapter($arrDoc['n_id'], false);
+
+                if (!empty($arrLasteChapter)) {
+                    $arrUpdateData['n_have_chapter'] = 1;
+                    $arrUpdateData['og_novel_latest_chapter_name'] = $arrLasteChapter['name'];
+                }
+
+                if (!empty($arrUpdateData)) {
+                    $arrBulkOps[] = [
+                        'updateOne' => [
+                            ['_id' => $arrDoc['_id']],
+                            ['$set' => $arrUpdateData],
+                        ],
+                    ];
+                }
+
+                $LastId = $arrDoc['_id'];
+            }
+
+            if (!empty($arrBulkOps)) {
+                $Result = $NovelCol->bulkWrite($arrBulkOps);
+                printf("本批匹配 %d 条记录, 修改 %d 条记录\n", $Result->getMatchedCount(), $Result->getModifiedCount());
+            } else {
+                echo "本批无需要更新的记录。\n";
+            }
+
+            echo "已处理一批,最后 _id: " . (string)$LastId . "\n";
+        }
+    }
+}

From 076f897dc7cada1f90cfc3597823da8afeac1542 Mon Sep 17 00:00:00 2001
From: Default 
Date: Tue, 8 Apr 2025 01:30:41 +0800
Subject: [PATCH 4/5] debug

---
 code/app/common.php                    |  2 +
 code/app/model/AutoSwitchViewModel.php |  4 --
 code/app/model/GanRaoMaModel.php       | 84 +++++++++++++++++++++++++-
 code/app/model/MongoModel.php          | 28 +++++++++
 4 files changed, 111 insertions(+), 7 deletions(-)

diff --git a/code/app/common.php b/code/app/common.php
index 36731f2..3c70743 100644
--- a/code/app/common.php
+++ b/code/app/common.php
@@ -1,4 +1,5 @@
 getFomartSubject('NV_SHENG_URL');
-
-        // exit;
-
         $TemplatesModel = TemplatesModel::getTemplateOnCacheByTId($DomainModel->t_id);
 
         if (empty($DomainModel)) {
diff --git a/code/app/model/GanRaoMaModel.php b/code/app/model/GanRaoMaModel.php
index 32db24e..940c757 100644
--- a/code/app/model/GanRaoMaModel.php
+++ b/code/app/model/GanRaoMaModel.php
@@ -22,6 +22,60 @@ class GanRaoMaModel extends MongoModel
      */
     protected $strCollection = 'gan_rao_ma';
 
+
+
+    /**
+     * Undocumented variable
+     *
+     * @var array
+     */
+    static public $arrSelfClosing = [
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+        '',
+    ];
+
+    const LETTERS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+
+    const CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+
+    public static function generateRandomStrings(int $count): array
+    {
+        static $lettersLength = null;
+        static $charsLength = null;
+
+        if ($lettersLength === null) {
+            $lettersLength = strlen(self::LETTERS) - 1;
+            $charsLength = strlen(self::CHARS) - 1;
+        }
+
+
+        $result = array_fill(0, $count, '');
+
+        array_walk($result, function (&$value) use ($lettersLength, $charsLength) {
+            $length = random_int(5, 10);
+            $value = self::LETTERS[random_int(0, $lettersLength)];
+            $i = 1;
+            while ($i < $length) {
+                $value .= self::CHARS[random_int(0, $charsLength)];
+                $i++;
+            }
+        });
+
+        return $result;
+    }
+
+
+
     /**
      * Undocumented function
      *
@@ -33,9 +87,33 @@ class GanRaoMaModel extends MongoModel
      * @param int  $intEndNumber          生成标签,随机结束位置  随机生成(10-20)个标签  20
      * @return string
      */
-    static public function getGrmCode($strDomain, $strPageCode, $intLine, $strDifference,$intStartNumber,$intEndNumber): string
+    static public function getGrmCode($strDomain, $strPageCode, $intLine, $strDifference, $intStartNumber, $intEndNumber): string
     {
-        // TODO  干扰码功能实现
-        return (string)mt_rand(1, 100);
+        $arrFilter = [
+            'grm_domain' => (string) $strDomain,
+            'grm_page_code' => (string) $strPageCode,
+            'grm_page_line' => (string)$intLine,
+            'grm_page_diff' => (string) $strDifference,
+        ];
+        $arrGrm =  self::getInstance()->getOne($arrFilter);
+
+        if (empty($arrGrm)) {
+            $intNum = mt_rand($intStartNumber, $intEndNumber);
+            $arrGrmCode = self::$arrSelfClosing;
+            shuffle($arrGrmCode);
+            $arrGrmCode =  array_slice($arrGrmCode, 0, $intNum);
+            $strGrmCode = implode('', $arrGrmCode);
+            $intRandNum = substr_count($strGrmCode, '%s');
+            $arrRandStr = self::generateRandomStrings($intRandNum);
+            $strGrmCode = sprintf($strGrmCode, ...$arrRandStr);
+
+            $arrData = $arrFilter;
+            $arrData['grm_code'] =   $strGrmCode;
+            self::getInstance()->insert($arrData);
+        } else {
+            $strGrmCode = $arrGrm['grm_code'];
+        }
+
+        return  $strGrmCode;
     }
 }
diff --git a/code/app/model/MongoModel.php b/code/app/model/MongoModel.php
index cd3980d..a5c0f17 100644
--- a/code/app/model/MongoModel.php
+++ b/code/app/model/MongoModel.php
@@ -14,6 +14,22 @@ use think\facade\Cache;
  */
 abstract class MongoModel
 {
+
+    /**
+     * Undocumented variable
+     *
+     * @var GanRaoMaModel
+     */
+    static public $obj;
+
+    static public function getInstance()
+    {
+        if (static::$obj == NULL) {
+            static::$obj = new static;
+        }
+        return  static::$obj;
+    }
+
     /**
      * collection name
      *
@@ -115,4 +131,16 @@ abstract class MongoModel
             Cache::set($strKey, $mixedData, $intLifeTime);
         }
     }
+
+    /**
+     * Undocumented function
+     *
+     * @param array $arrData
+     * @return mixed
+     */
+    public function insert(array $arrData, array $arrOptions = []): mixed
+    {
+        $Result = $this->getCol()->insertOne($arrData);
+        return $Result->getInsertedId();
+    }
 }

From 7980d4611018e96b908719043bd865fd3765ee56 Mon Sep 17 00:00:00 2001
From: Default 
Date: Tue, 8 Apr 2025 01:31:20 +0800
Subject: [PATCH 5/5] debug

---
 code/database/mongo/migrations/gan_rao_ma.php | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100644 code/database/mongo/migrations/gan_rao_ma.php

diff --git a/code/database/mongo/migrations/gan_rao_ma.php b/code/database/mongo/migrations/gan_rao_ma.php
new file mode 100644
index 0000000..e12b9a1
--- /dev/null
+++ b/code/database/mongo/migrations/gan_rao_ma.php
@@ -0,0 +1,10 @@
+ 'gan_rao_ma',
+    'indexes' => [
+        [
+            'key' => ['grm_domain' => 1, 'grm_page_code' => 1, 'grm_page_line' => 1, 'grm_page_diff' => 1],
+            'options' => ['unique' => true]
+        ],
+    ]
+];