This commit is contained in:
make
2025-04-01 17:34:31 +08:00
6 changed files with 372 additions and 124 deletions

View File

@@ -827,4 +827,36 @@ namespace {
{
return strtoupper(str_replace('::', '@', ltrim(strrchr($strAction, "\\"), "\\")));
}
/**
* Undocumented function
*
* @param MongoDB\BSON\UTCDateTime $mongoDate
* @param string $format
* @return string
*/
function formatMongoDate(\MongoDB\BSON\UTCDateTime $mongoDate, string $strFormat = "Y-m-d H:i:s"): string
{
$intTimestamp = (int) ((string) $mongoDate / 1000);
return gmdate($strFormat, $intTimestamp);
}
/**
* Undocumented function
*
* @param array $arrData
* @param array $arrKeys
* @param callable $Callback
* @return void
*/
function applyToKeys(null|array &$arrData, array $arrKeys, callable $Callback)
{
if (empty($arrData)) return;
foreach ($arrKeys as $strKey) {
if (key_exists($strKey, $arrData)) {
$arrData[$strKey] = $Callback($arrData[$strKey]);
}
}
}
}

View File

@@ -6,7 +6,9 @@ namespace app\home\controller;
use app\home\BaseController;
use app\model\CategoryModel;
use app\model\ChapterModel;
use app\model\ConverterMovel;
use app\model\NovelClicksModel;
use app\model\NovelModel;
use storage\StorageCore;
use think\facade\View;
@@ -110,7 +112,6 @@ class Novel extends BaseController
}
// 小说状态
// $strStatus = $Request->param('strStatus');
$arrStatus = [
'all' => NULL,
'lianzai' => '连载中',
@@ -232,83 +233,84 @@ class Novel extends BaseController
}
/**
* 分类
* 分类
*
* @todo 第一版本不需要
* @param Request $Request
* @param [type] $intCategoryId
* @param integer $intPage
* @return void
*/
public function getNovelCategory(Request $Request, $intCategoryId = null, $intPage = 1)
{
$boolIsMobile = $Request->param('boolIsMobile');
$strChannel = $Request->param('strChannel'); // 区分男生 / 女生频道
// public function getNovelCategory(Request $Request, $intCategoryId = null, $intPage = 1)
// {
// $boolIsMobile = $Request->param('boolIsMobile');
// $strChannel = $Request->param('strChannel'); // 区分男生 / 女生频道
// 模拟数据-推荐等级为9的连载的男生频道/女生频道, 随机12个小说
$arrRecommendSerializationNovel = [
['id' => 1, 'name' => '小说1', 'author' => '作者1'],
['id' => 2, 'name' => '小说2', 'author' => '作者2'],
['id' => 3, 'name' => '小说3', 'author' => '作者3'],
['id' => 4, 'name' => '小说3', 'author' => '作者3'],
['id' => 5, 'name' => '小说3', 'author' => '作者3'],
['id' => 6, 'name' => '小说3', 'author' => '作者3'],
['id' => 7, 'name' => '小说3', 'author' => '作者3'],
['id' => 8, 'name' => '小说3', 'author' => '作者3'],
['id' => 9, 'name' => '小说3', 'author' => '作者3'],
['id' => 10, 'name' => '小说3', 'author' => '作者3'],
['id' => 11, 'name' => '小说3', 'author' => '作者3'],
['id' => 12, 'name' => '小说3', 'author' => '作者3'],
];
// 模拟数据-推荐等级为9的完结的男生频道/女生频道, 随机8个小说
$arrRecommendEndNovel = [
['id' => 1, 'name' => '小说1', 'author' => '作者1'],
['id' => 2, 'name' => '小说2', 'author' => '作者2'],
['id' => 3, 'name' => '小说3', 'author' => '作者3'],
['id' => 4, 'name' => '小说3', 'author' => '作者3'],
['id' => 5, 'name' => '小说3', 'author' => '作者3'],
['id' => 6, 'name' => '小说3', 'author' => '作者3'],
['id' => 7, 'name' => '小说3', 'author' => '作者3'],
['id' => 8, 'name' => '小说3', 'author' => '作者3'],
// // 模拟数据-推荐等级为9的连载的男生频道/女生频道, 随机12个小说
// $arrRecommendSerializationNovel = [
// ['id' => 1, 'name' => '小说1', 'author' => '作者1'],
// ['id' => 2, 'name' => '小说2', 'author' => '作者2'],
// ['id' => 3, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 4, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 5, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 6, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 7, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 8, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 9, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 10, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 11, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 12, 'name' => '小说3', 'author' => '作者3'],
// ];
// // 模拟数据-推荐等级为9的完结的男生频道/女生频道, 随机8个小说
// $arrRecommendEndNovel = [
// ['id' => 1, 'name' => '小说1', 'author' => '作者1'],
// ['id' => 2, 'name' => '小说2', 'author' => '作者2'],
// ['id' => 3, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 4, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 5, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 6, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 7, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 8, 'name' => '小说3', 'author' => '作者3'],
];
// ];
// 模拟数据-最近更新-随机50
$arrNewsUpdateNovel = [
['id' => 1, 'name' => '小说1', 'author' => '作者1'],
['id' => 2, 'name' => '小说2', 'author' => '作者2'],
['id' => 3, 'name' => '小说3', 'author' => '作者3'],
['id' => 4, 'name' => '小说3', 'author' => '作者3'],
['id' => 5, 'name' => '小说3', 'author' => '作者3'],
['id' => 6, 'name' => '小说3', 'author' => '作者3'],
['id' => 7, 'name' => '小说3', 'author' => '作者3'],
['id' => 8, 'name' => '小说3', 'author' => '作者3'],
['id' => 9, 'name' => '小说3', 'author' => '作者3'],
['id' => 10, 'name' => '小说3', 'author' => '作者3'],
['id' => 1, 'name' => '小说1', 'author' => '作者1'],
['id' => 2, 'name' => '小说2', 'author' => '作者2'],
['id' => 3, 'name' => '小说3', 'author' => '作者3'],
['id' => 4, 'name' => '小说3', 'author' => '作者3'],
['id' => 5, 'name' => '小说3', 'author' => '作者3'],
['id' => 6, 'name' => '小说3', 'author' => '作者3'],
['id' => 7, 'name' => '小说3', 'author' => '作者3'],
['id' => 8, 'name' => '小说3', 'author' => '作者3'],
['id' => 9, 'name' => '小说3', 'author' => '作者3'],
['id' => 10, 'name' => '小说3', 'author' => '作者3'],
];
// // 模拟数据-最近更新-随机50
// $arrNewsUpdateNovel = [
// ['id' => 1, 'name' => '小说1', 'author' => '作者1'],
// ['id' => 2, 'name' => '小说2', 'author' => '作者2'],
// ['id' => 3, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 4, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 5, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 6, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 7, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 8, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 9, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 10, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 1, 'name' => '小说1', 'author' => '作者1'],
// ['id' => 2, 'name' => '小说2', 'author' => '作者2'],
// ['id' => 3, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 4, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 5, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 6, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 7, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 8, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 9, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 10, 'name' => '小说3', 'author' => '作者3'],
// ];
View::assign([
'arrNewsUpdateNovel' => $arrNewsUpdateNovel,
'arrRecommendSerializationNovel' => $arrRecommendSerializationNovel,
'arrRecommendEndNovel' => $arrRecommendEndNovel,
'arrAdBanner' => [],
'strPageCode' => 'category'
]);
if ($boolIsMobile) {
return View::fetch();
} else {
return View::fetch('pc/getNovelCategory');
}
}
// View::assign([
// 'arrNewsUpdateNovel' => $arrNewsUpdateNovel,
// 'arrRecommendSerializationNovel' => $arrRecommendSerializationNovel,
// 'arrRecommendEndNovel' => $arrRecommendEndNovel,
// 'arrAdBanner' => [],
// 'strPageCode' => 'category'
// ]);
// if ($boolIsMobile) {
// return View::fetch();
// } else {
// return View::fetch('pc/getNovelCategory');
// }
// }
/**
* 小说详情
@@ -322,12 +324,29 @@ class Novel extends BaseController
$boolIsMobile = $Request->param('boolIsMobile');
$NovelModel = new NovelModel;
$arrNovel = $NovelModel->getNovelInfo($intNId);
$ChapterModel = new ChapterModel;
$arrLatestChapter = $ChapterModel->getLatestChapter($intNId);
$NovelClicksModel = new NovelClicksModel;
$arrNovelClicks = $NovelClicksModel->getStats($intNId);
// echo '<pre>';
// print_r($arrNovel);
// exit;
$strNovel = '斗罗大陆';
ConverterMovel::setVal("strNovelName", $strNovel);
// 模拟数据-随机推荐数据10条
$arrRecommendNovel = [
['id' => 1, 'name' => '小说1', 'author' => '作者1'],
@@ -343,7 +362,7 @@ class Novel extends BaseController
// 最新章节 取最新5章节
// 相邻推荐->关联的 kan 数据
// 精品推荐->同分类随机10条数据
// 最新要点->取新意章节, 随机提取一部分内容 大概150字数
// {strNovelName}最新章节_{strNovelName}{strNovelAuthor}_{strNovelName}全文阅读_{strSiteName}
// {strNovelName}免费全文阅读-{strNovelName}{strNovelAuthor}-{strSiteName}
@@ -380,11 +399,9 @@ class Novel extends BaseController
public function getNovelNewsChapter(Request $Request)
{
$intNId = $Request->param('n_id');
$boolIsMobile = $Request->param('boolIsMobile');
// 模拟数据-随机推荐数据10条
@@ -495,7 +512,7 @@ class Novel extends BaseController
// 小说章节-搜索
// 小说-搜索
public function getSearchNovel(Request $Request)
{
$boolIsMobile = $Request->param('boolIsMobile');
@@ -526,69 +543,70 @@ class Novel extends BaseController
/**
* 小说章节-文章-自定义页面-列表
*
* @todo 第一版本不做
* @param Request $Request
* @param [type] $intCategoryId
* @param integer $intPage
* @return void
*/
public function getArticleList(Request $Request, $intCategoryId = null, $intPage = 1)
{
$boolIsMobile = $Request->param('boolIsMobile');
// public function getArticleList(Request $Request, $intCategoryId = null, $intPage = 1)
// {
// $boolIsMobile = $Request->param('boolIsMobile');
// 模拟数据
$arrNewsNovel = [
['id' => 1, 'name' => '小说1', 'author' => '作者1'],
['id' => 2, 'name' => '小说2', 'author' => '作者2'],
['id' => 3, 'name' => '小说3', 'author' => '作者3'],
['id' => 4, 'name' => '小说3', 'author' => '作者3'],
['id' => 5, 'name' => '小说3', 'author' => '作者3'],
['id' => 6, 'name' => '小说3', 'author' => '作者3'],
['id' => 7, 'name' => '小说3', 'author' => '作者3'],
['id' => 8, 'name' => '小说3', 'author' => '作者3'],
];
// // 模拟数据
// $arrNewsNovel = [
// ['id' => 1, 'name' => '小说1', 'author' => '作者1'],
// ['id' => 2, 'name' => '小说2', 'author' => '作者2'],
// ['id' => 3, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 4, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 5, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 6, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 7, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 8, 'name' => '小说3', 'author' => '作者3'],
// ];
View::assign([
'arrNewsNovel' => $arrNewsNovel,
'strPageCode' => 'article'
]);
if ($boolIsMobile) {
return View::fetch();
} else {
return View::fetch('pc/getArticleList');
}
}
// View::assign([
// 'arrNewsNovel' => $arrNewsNovel,
// 'strPageCode' => 'article'
// ]);
// if ($boolIsMobile) {
// return View::fetch();
// } else {
// return View::fetch('pc/getArticleList');
// }
// }
/**
* 小说章节-文章-自定义页面-详情
*
* @todo 第一版本不做
* @param Request $Request
* @param [type] $intArticleId
* @return void
*/
public function getArticleInfo(Request $Request, $intArticleId)
{
$boolIsMobile = $Request->param('boolIsMobile');
// public function getArticleInfo(Request $Request, $intArticleId)
// {
// $boolIsMobile = $Request->param('boolIsMobile');
// 模拟数据
$arrNewsNovel = [
['id' => 1, 'name' => '小说1', 'author' => '作者1'],
['id' => 2, 'name' => '小说2', 'author' => '作者2'],
['id' => 3, 'name' => '小说3', 'author' => '作者3'],
['id' => 4, 'name' => '小说3', 'author' => '作者3'],
['id' => 5, 'name' => '小说3', 'author' => '作者3'],
['id' => 6, 'name' => '小说3', 'author' => '作者3'],
['id' => 7, 'name' => '小说3', 'author' => '作者3'],
['id' => 8, 'name' => '小说3', 'author' => '作者3'],
];
// // 模拟数据
// $arrNewsNovel = [
// ['id' => 1, 'name' => '小说1', 'author' => '作者1'],
// ['id' => 2, 'name' => '小说2', 'author' => '作者2'],
// ['id' => 3, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 4, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 5, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 6, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 7, 'name' => '小说3', 'author' => '作者3'],
// ['id' => 8, 'name' => '小说3', 'author' => '作者3'],
// ];
View::assign([
'arrNewsNovel' => $arrNewsNovel,
'strPageCode' => 'article'
]);
if ($boolIsMobile) {
return View::fetch();
} else {
return View::fetch('pc/getArticleInfo');
}
}
// View::assign([
// 'arrNewsNovel' => $arrNewsNovel,
// 'strPageCode' => 'article'
// ]);
// if ($boolIsMobile) {
// return View::fetch();
// } else {
// return View::fetch('pc/getArticleInfo');
// }
// }
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace app\model;
use DateTime;
use storage\StorageCore;
use think\facade\Cache;
use think\Model;
@@ -14,4 +15,76 @@ use think\Model;
class ChapterModel extends MongoModel
{
protected $strCollection = 'chapter';
static public $arrChapterOptions = [
'typeMap' => [
'root' => 'array',
'document' => 'array',
'array' => 'array',
],
'projection' => [
'_id' => 0,
'c_page_title' => 0,
'c_page_keywords' => 0,
'c_page_description' => 0,
'c_source_uri' => 0,
'c_source_id' => 0,
'c_site_name' => 0,
'c_site_code' => 0,
'c_site_uuid' => 0,
],
];
/**
* Undocumented function
*
* @param integer $intNId
* @return null|array
*/
public function getLatestChapter(int $intNId): null|array
{
$arrFilter = ['n_id' => $intNId, 'c_page' => 0];
$arrOptions = self::$arrChapterOptions;
$arrOptions['sort'] = ['c_sort_num' => -1];
$arrChapter = $this->getOne($arrFilter, $arrOptions);
if (!empty($arrChapter)) {
applyToKeys($arrChapter, ['created_at', 'updated_at'], 'formatMongoDate');
$arrChapter['content'] = StorageCore::getInstance()->read($arrChapter['c_content_path']);
}
return $arrChapter;
}
/**
* Undocumented function
*
* @param integer $intNId
* @return null|array
*/
public function getChapterAll(array $arrFilter, array $arrOptions = []): null|array
{
// $arrFilter = ['n_id' => $intNId, 'c_page' => 0];
// $arrOptions = self::$arrChapterOptions;
// $arrOptions['sort'] = ['c_sort_num' => -1];
// $arrChapter = $this->getOne($arrFilter, $arrOptions);
// if (!empty($arrChapter)) {
// applyToKeys($arrChapter, ['created_at', 'updated_at'], 'formatMongoDate');
// $arrChapter['content'] = StorageCore::getInstance()->read($arrChapter['c_content_path']);
// }
// return $arrChapter;
}
}

View File

@@ -7,8 +7,6 @@ namespace app\model;
use db\mongo\MongoBase;
use ddl\DDLManage;
use MongoDB\Collection;
use think\facade\Cache;
use think\Model;
/**
* @mixin think\Model
@@ -68,4 +66,15 @@ abstract class MongoModel
{
return $this->strCollection;
}
/**
* Undocumented function
*
* @param array $arrFilter
* @return array|object|null
*/
public function getOne(array $arrFilter = [], array $arrOptions = []): array|object|null
{
return $this->getCol()->findOne($arrFilter, $arrOptions);
}
}

View File

@@ -64,4 +64,40 @@ class NovelClicksModel extends MongoModel
}
return true;
}
public function getStats(int $intNId): array
{
$Now = new DateTime();
$strDailyDate = $Now->format('Y-m-d');
$strWeeklyDate = $Now->modify('monday this week')->format('Y-m-d');
$strMonthlyDate = $Now->format('Y-m-01');
$query = [
'n_id' => $intNId,
'$or' => [
['nc_type' => 'daily', 'nc_date' => $strDailyDate],
['nc_type' => 'weekly', 'nc_date' => $strWeeklyDate],
['nc_type' => 'monthly', 'nc_date' => $strMonthlyDate],
['nc_type' => 'total', 'nc_date' => null]
]
];
$arrOptions = [
'projection' => ['nc_type' => 1, 'nc_clicks' => 1, '_id' => 0],
'typeMap' => ['root' => 'array', 'document' => 'array', 'array' => 'array']
];
$arrResults = $this->getCol()->find($query, $arrOptions)->toArray();
$arrStats = array_column($arrResults, 'nc_clicks', 'nc_type');
$defaultStats = [
'daily' => 0,
'weekly' => 0,
'monthly' => 0,
'total' => 0
];
$arrStats = array_merge($defaultStats, $arrStats);
return $arrStats;
}
}

View File

@@ -36,7 +36,7 @@ class NovelModel extends MongoModel
try {
$arrConditions = array_map(function ($strKeyword) {
return ['og_title' => ['$regex' => trim($strKeyword), '$arrOptions' => 'i']];
return ['og_title' => ['$regex' => trim($strKeyword), '$options' => 'i']];
}, $arrKeywords);
$UpdateResult = $this->getCol()->updateMany(
@@ -53,6 +53,86 @@ class NovelModel extends MongoModel
return true;
}
static public $arrNovelOptions = [
'typeMap' => [
'root' => 'array',
'document' => 'array',
'array' => 'array',
],
'projection' => [
'_id' => 0,
'og_title' => 0,
'n_site_name' => 0,
'n_site_code' => 0,
'n_site_uuid' => 0,
'n_source_id' => 0,
'n_page_title' => 0,
'og_description' => 0,
'og_novel_latest_chapter_name' => 0,
'og_image' => 0,
'og_novel_latest_chapter_url' => 0,
'og_novel_read_url' => 0,
'og_type' => 0,
'og_url' => 0,
],
];
/**
* Undocumented function
*
* @param integer $intNId
* @return array
*/
public function getNovelInfo(int $intNId): null|array
{
$arrFilter = ['n_id' => $intNId];
$arrOptions = self::$arrNovelOptions;
$arrNovel = $this->getOne($arrFilter, $arrOptions);
applyToKeys($arrNovel, ['created_at', 'updated_at'], 'formatMongoDate');
return $arrNovel;
}
/**
* Undocumented function
*
* @param string $strKey
* @param integer $intCount
* @param int $intLifeTime
* @param array $arrFilter
* @return void
*/
public function getRandNovel(string $strKey, $intCount = 10, int $intLifeTime = 24 * 3600, array $arrFilter = []): array
{
try {
$arrResult = Cache::get($strKey);
// if (empty($arrResult)) {
if (true) {
$pipeline = [
['$match' => $arrFilter],
['$sample' => ['size' => $intCount]]
];
$Novel = $this->getCol()->aggregate($pipeline);
$arrResult = iterator_to_array($Novel);
if (!empty($arrResult)) {
Cache::set($strKey, $arrResult, $intLifeTime);
}
}
return $arrResult;
} catch (\Exception $e) {
return [];
}
}
/**
* Undocumented function
*