|
@@ -2,20 +2,17 @@
|
|
|
|
|
|
|
|
namespace App\Http\Controllers\Library;
|
|
namespace App\Http\Controllers\Library;
|
|
|
|
|
|
|
|
|
|
+use App\Http\Api\ChannelApi;
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Controllers\Controller;
|
|
|
-use Illuminate\Http\Request;
|
|
|
|
|
-use Illuminate\Support\Facades\Cookie;
|
|
|
|
|
-use Illuminate\Support\Facades\File;
|
|
|
|
|
-use Illuminate\Support\Str;
|
|
|
|
|
-use Illuminate\Support\Facades\Log;
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
use App\Models\PaliText;
|
|
use App\Models\PaliText;
|
|
|
use App\Models\ProgressChapter;
|
|
use App\Models\ProgressChapter;
|
|
|
-use App\Services\TermService;
|
|
|
|
|
use App\Models\Tag;
|
|
use App\Models\Tag;
|
|
|
use App\Models\TagMap;
|
|
use App\Models\TagMap;
|
|
|
-
|
|
|
|
|
|
|
+use App\Services\TermService;
|
|
|
|
|
+use Illuminate\Http\Request;
|
|
|
|
|
+use Illuminate\Support\Facades\Cookie;
|
|
|
|
|
+use Illuminate\Support\Facades\File;
|
|
|
|
|
+use Illuminate\Support\Str;
|
|
|
|
|
|
|
|
class TipitakaController extends Controller
|
|
class TipitakaController extends Controller
|
|
|
{
|
|
{
|
|
@@ -31,8 +28,6 @@ class TipitakaController extends Controller
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 构造函数,注入 TermService
|
|
* 构造函数,注入 TermService
|
|
|
- *
|
|
|
|
|
- * @param \App\Services\TermService $termService
|
|
|
|
|
*/
|
|
*/
|
|
|
public function __construct(
|
|
public function __construct(
|
|
|
protected TermService $termService,
|
|
protected TermService $termService,
|
|
@@ -45,8 +40,8 @@ class TipitakaController extends Controller
|
|
|
{
|
|
{
|
|
|
return hexdec(substr(str_replace('-', '', $uid), 0, 4)) % 255;
|
|
return hexdec(substr(str_replace('-', '', $uid), 0, 4)) % 255;
|
|
|
}
|
|
}
|
|
|
- protected static int $nextId = 1;
|
|
|
|
|
|
|
|
|
|
|
|
+ protected static int $nextId = 1;
|
|
|
|
|
|
|
|
// app/Http/Controllers/Library/CategoryController.php
|
|
// app/Http/Controllers/Library/CategoryController.php
|
|
|
// category() 方法修改版
|
|
// category() 方法修改版
|
|
@@ -67,32 +62,32 @@ class TipitakaController extends Controller
|
|
|
// ── 当前分类 ──────────────────────────────────────────
|
|
// ── 当前分类 ──────────────────────────────────────────
|
|
|
if ($id) {
|
|
if ($id) {
|
|
|
$currentCategory = collect($categories)->firstWhere('id', $id);
|
|
$currentCategory = collect($categories)->firstWhere('id', $id);
|
|
|
- if (!$currentCategory) {
|
|
|
|
|
|
|
+ if (! $currentCategory) {
|
|
|
abort(404);
|
|
abort(404);
|
|
|
}
|
|
}
|
|
|
$breadcrumbs = $this->getBreadcrumbs($currentCategory, $categories);
|
|
$breadcrumbs = $this->getBreadcrumbs($currentCategory, $categories);
|
|
|
} else {
|
|
} else {
|
|
|
// 首页:虚拟顶级分类
|
|
// 首页:虚拟顶级分类
|
|
|
$currentCategory = ['id' => null, 'name' => '三藏'];
|
|
$currentCategory = ['id' => null, 'name' => '三藏'];
|
|
|
- $breadcrumbs = [];
|
|
|
|
|
|
|
+ $breadcrumbs = [];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ── 子分类 ─────────────────────────────────────────────
|
|
// ── 子分类 ─────────────────────────────────────────────
|
|
|
$subCategories = array_values(array_filter(
|
|
$subCategories = array_values(array_filter(
|
|
|
$categories,
|
|
$categories,
|
|
|
- fn($cat) => $cat['parent_id'] == $id
|
|
|
|
|
|
|
+ fn ($cat) => $cat['parent_id'] == $id
|
|
|
));
|
|
));
|
|
|
- if (count($subCategories) === 0 && !$request->has('book')) {
|
|
|
|
|
|
|
+ if (count($subCategories) === 0 && ! $request->has('book')) {
|
|
|
$paliBooks = $this->getPaliBooks($categories, $id);
|
|
$paliBooks = $this->getPaliBooks($categories, $id);
|
|
|
- foreach ($paliBooks as $value) {
|
|
|
|
|
|
|
+ foreach ($paliBooks as $value) {
|
|
|
$subCategories[] = [
|
|
$subCategories[] = [
|
|
|
'id' => $id,
|
|
'id' => $id,
|
|
|
'name' => $value->text,
|
|
'name' => $value->text,
|
|
|
- 'book' => "{$value->book}-{$value->paragraph}"
|
|
|
|
|
|
|
+ 'book' => "{$value->book}-{$value->paragraph}",
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- $allNames = array_map(fn($item) => $item['name'], $subCategories);
|
|
|
|
|
|
|
+ $allNames = array_map(fn ($item) => $item['name'], $subCategories);
|
|
|
|
|
|
|
|
// 去重
|
|
// 去重
|
|
|
$allNames = array_values(array_unique($allNames));
|
|
$allNames = array_values(array_unique($allNames));
|
|
@@ -112,25 +107,28 @@ class TipitakaController extends Controller
|
|
|
$subCategories[$key]['name'] = $termMap[$name] ?? $name;
|
|
$subCategories[$key]['name'] = $termMap[$name] ?? $name;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
// ── 过滤参数 ────────────────────────────────────────────
|
|
// ── 过滤参数 ────────────────────────────────────────────
|
|
|
- $selectedType = request('type', 'all');
|
|
|
|
|
- $selectedLang = request('lang', 'all');
|
|
|
|
|
|
|
+ $selectedType = request('type', 'all');
|
|
|
|
|
+ $selectedLang = request('lang', 'all');
|
|
|
$selectedAuthor = request('author', 'all');
|
|
$selectedAuthor = request('author', 'all');
|
|
|
- $selectedSort = request('sort', 'new');
|
|
|
|
|
- $selectedChannel = request('channel', 'all');
|
|
|
|
|
|
|
+ $selectedSort = request('sort', 'new');
|
|
|
|
|
+ $selectedChannel = request('channel', 'all');
|
|
|
|
|
+
|
|
|
|
|
+ // ── 当前频道(提供 channel 参数时) ──────────────────────
|
|
|
|
|
+ $currentChannel = $selectedChannel !== 'all'
|
|
|
|
|
+ ? (ChannelApi::getById($selectedChannel) ?: null)
|
|
|
|
|
+ : null;
|
|
|
|
|
|
|
|
$sortList = [
|
|
$sortList = [
|
|
|
- ['key' => 'new', 'label' => __('library.badge_updated'),],
|
|
|
|
|
- ['key' => 'progress', 'label' => '完成度',],
|
|
|
|
|
|
|
+ ['key' => 'new', 'label' => __('library.badge_updated')],
|
|
|
|
|
+ ['key' => 'progress', 'label' => '完成度'],
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
$selected = [
|
|
$selected = [
|
|
|
- 'type' => $selectedType,
|
|
|
|
|
- 'lang' => $selectedLang,
|
|
|
|
|
|
|
+ 'type' => $selectedType,
|
|
|
|
|
+ 'lang' => $selectedLang,
|
|
|
'author' => $selectedAuthor,
|
|
'author' => $selectedAuthor,
|
|
|
- 'sort' => $selectedSort,
|
|
|
|
|
|
|
+ 'sort' => $selectedSort,
|
|
|
'channel' => $selectedChannel,
|
|
'channel' => $selectedChannel,
|
|
|
];
|
|
];
|
|
|
if ($request->has('book')) {
|
|
if ($request->has('book')) {
|
|
@@ -168,7 +166,8 @@ class TipitakaController extends Controller
|
|
|
'totalCount',
|
|
'totalCount',
|
|
|
'recommended',
|
|
'recommended',
|
|
|
'activeAuthors',
|
|
'activeAuthors',
|
|
|
- 'sortList'
|
|
|
|
|
|
|
+ 'sortList',
|
|
|
|
|
+ 'currentChannel'
|
|
|
));
|
|
));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -203,36 +202,23 @@ class TipitakaController extends Controller
|
|
|
['id' => 5, 'title' => '长部·梵网经', 'category' => '经藏'],
|
|
['id' => 5, 'title' => '长部·梵网经', 'category' => '经藏'],
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
private function mockActiveAuthors()
|
|
private function mockActiveAuthors()
|
|
|
{
|
|
{
|
|
|
return [
|
|
return [
|
|
|
[
|
|
[
|
|
|
- 'name' => 'Bhikkhu Bodhi',
|
|
|
|
|
- 'avatar' => null,
|
|
|
|
|
- 'color' => '#2d5a8e',
|
|
|
|
|
|
|
+ 'name' => 'Bhikkhu Bodhi',
|
|
|
|
|
+ 'avatar' => null,
|
|
|
|
|
+ 'color' => '#2d5a8e',
|
|
|
'initials' => 'BB',
|
|
'initials' => 'BB',
|
|
|
- 'count' => 24,
|
|
|
|
|
|
|
+ 'count' => 24,
|
|
|
],
|
|
],
|
|
|
[
|
|
[
|
|
|
- 'name' => 'Bhikkhu Sujato',
|
|
|
|
|
- 'avatar' => null,
|
|
|
|
|
- 'color' => '#5a2d8e',
|
|
|
|
|
|
|
+ 'name' => 'Bhikkhu Sujato',
|
|
|
|
|
+ 'avatar' => null,
|
|
|
|
|
+ 'color' => '#5a2d8e',
|
|
|
'initials' => 'BS',
|
|
'initials' => 'BS',
|
|
|
- 'count' => 18,
|
|
|
|
|
- ],
|
|
|
|
|
- [
|
|
|
|
|
- 'name' => 'Buddhaghosa',
|
|
|
|
|
- 'avatar' => null,
|
|
|
|
|
- 'color' => '#8e5a2d',
|
|
|
|
|
- 'initials' => 'BG',
|
|
|
|
|
- 'count' => 12,
|
|
|
|
|
- ],
|
|
|
|
|
- [
|
|
|
|
|
- 'name' => 'Bhikkhu Brahmali',
|
|
|
|
|
- 'avatar' => null,
|
|
|
|
|
- 'color' => '#2d8e5a',
|
|
|
|
|
- 'initials' => 'BR',
|
|
|
|
|
- 'count' => 9,
|
|
|
|
|
|
|
+ 'count' => 18,
|
|
|
],
|
|
],
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
@@ -256,12 +242,10 @@ class TipitakaController extends Controller
|
|
|
['id' => '1', 'name' => 'sutta'],
|
|
['id' => '1', 'name' => 'sutta'],
|
|
|
['id' => '48', 'name' => 'vinaya'],
|
|
['id' => '48', 'name' => 'vinaya'],
|
|
|
['id' => '66', 'name' => 'abhidhamma'],
|
|
['id' => '66', 'name' => 'abhidhamma'],
|
|
|
- ['id' => '82', 'name' => 'añña']
|
|
|
|
|
|
|
+ ['id' => '82', 'name' => 'añña'],
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
private function subCategories($categories, int $id)
|
|
private function subCategories($categories, int $id)
|
|
|
{
|
|
{
|
|
|
return array_filter($categories, function ($cat) use ($id) {
|
|
return array_filter($categories, function ($cat) use ($id) {
|
|
@@ -273,7 +257,7 @@ class TipitakaController extends Controller
|
|
|
{
|
|
{
|
|
|
if ($id) {
|
|
if ($id) {
|
|
|
$currentCategory = collect($categories)->firstWhere('id', $id);
|
|
$currentCategory = collect($categories)->firstWhere('id', $id);
|
|
|
- if (!$currentCategory) {
|
|
|
|
|
|
|
+ if (! $currentCategory) {
|
|
|
abort(404);
|
|
abort(404);
|
|
|
}
|
|
}
|
|
|
// 标签查章节
|
|
// 标签查章节
|
|
@@ -290,18 +274,22 @@ class TipitakaController extends Controller
|
|
|
foreach ($booksChapter as $key => $value) {
|
|
foreach ($booksChapter as $key => $value) {
|
|
|
$chapters[] = [$value->book, $value->paragraph];
|
|
$chapters[] = [$value->book, $value->paragraph];
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
return $chapters;
|
|
return $chapters;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
private function getPaliBooks(array $categories, string $id)
|
|
private function getPaliBooks(array $categories, string $id)
|
|
|
{
|
|
{
|
|
|
$chapters = $this->getBooksIdInCat($categories, $id);
|
|
$chapters = $this->getBooksIdInCat($categories, $id);
|
|
|
|
|
|
|
|
$books = PaliText::whereIns(['book', 'paragraph'], $chapters)->get();
|
|
$books = PaliText::whereIns(['book', 'paragraph'], $chapters)->get();
|
|
|
|
|
+
|
|
|
return $books;
|
|
return $books;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
private function getBooks(array $categories, ?string $id, array $filters)
|
|
private function getBooks(array $categories, ?string $id, array $filters)
|
|
|
{
|
|
{
|
|
|
- //根据分类获取书号
|
|
|
|
|
|
|
+ // 根据分类获取书号
|
|
|
if (isset($filters['book'])) {
|
|
if (isset($filters['book'])) {
|
|
|
$chapters = [explode('-', $filters['book'])];
|
|
$chapters = [explode('-', $filters['book'])];
|
|
|
} else {
|
|
} else {
|
|
@@ -328,10 +316,11 @@ class TipitakaController extends Controller
|
|
|
->whereIns(['book', 'para'], $chapters);
|
|
->whereIns(['book', 'para'], $chapters);
|
|
|
if ($filters['sort'] === 'new') {
|
|
if ($filters['sort'] === 'new') {
|
|
|
$table = $table->orderBy('last_chapter_completed_at', 'desc');
|
|
$table = $table->orderBy('last_chapter_completed_at', 'desc');
|
|
|
- } else if ($filters['sort'] === 'progress') {
|
|
|
|
|
|
|
+ } elseif ($filters['sort'] === 'progress') {
|
|
|
$table = $table->orderBy('progress', 'desc');
|
|
$table = $table->orderBy('progress', 'desc');
|
|
|
}
|
|
}
|
|
|
$books = $table->take(100)->get();
|
|
$books = $table->take(100)->get();
|
|
|
|
|
+
|
|
|
return $this->getBooksInfo($books);
|
|
return $this->getBooksInfo($books);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -340,7 +329,7 @@ class TipitakaController extends Controller
|
|
|
$pali = PaliText::where('level', 1)->get();
|
|
$pali = PaliText::where('level', 1)->get();
|
|
|
// 获取该分类下的书籍
|
|
// 获取该分类下的书籍
|
|
|
$categoryBooks = [];
|
|
$categoryBooks = [];
|
|
|
- $books->each(function ($book) use (&$categoryBooks, $pali) {
|
|
|
|
|
|
|
+ $books->each(function ($book) use (&$categoryBooks, $pali) {
|
|
|
$title = $book->title;
|
|
$title = $book->title;
|
|
|
if (empty($title)) {
|
|
if (empty($title)) {
|
|
|
$title = $pali->firstWhere('book', $book->book)->toc;
|
|
$title = $pali->firstWhere('book', $book->book)->toc;
|
|
@@ -361,23 +350,23 @@ class TipitakaController extends Controller
|
|
|
$subTitle = $this->getBookType($book->book, $book->para);
|
|
$subTitle = $this->getBookType($book->book, $book->para);
|
|
|
|
|
|
|
|
$categoryBooks[] = [
|
|
$categoryBooks[] = [
|
|
|
- "id" => $book->uid,
|
|
|
|
|
- "title" => $title,
|
|
|
|
|
- "author" => $book->channel->name,
|
|
|
|
|
|
|
+ 'id' => $book->uid,
|
|
|
|
|
+ 'title' => $title,
|
|
|
|
|
+ 'author' => $book->channel->name,
|
|
|
'subTitle' => $subTitle,
|
|
'subTitle' => $subTitle,
|
|
|
- "publisher" => $book->channel->owner,
|
|
|
|
|
|
|
+ 'publisher' => $book->channel->owner,
|
|
|
'completed_chapters' => $book->completed_chapters,
|
|
'completed_chapters' => $book->completed_chapters,
|
|
|
- "type" => __('labels.' . $book->channel->type),
|
|
|
|
|
- "cover" => $coverUrl,
|
|
|
|
|
|
|
+ 'type' => __('labels.'.$book->channel->type),
|
|
|
|
|
+ 'cover' => $coverUrl,
|
|
|
'cover_gradient' => $this->coverGradients[$colorIdx % count($this->coverGradients)],
|
|
'cover_gradient' => $this->coverGradients[$colorIdx % count($this->coverGradients)],
|
|
|
- "description" => $book->summary ?? "比库戒律的详细说明",
|
|
|
|
|
- "language" => __('language.' . $book->channel->lang),
|
|
|
|
|
|
|
+ 'description' => $book->summary ?? '比库戒律的详细说明',
|
|
|
|
|
+ 'language' => __('language.'.$book->channel->lang),
|
|
|
];
|
|
];
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
return $categoryBooks;
|
|
return $categoryBooks;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
private function getBookType(int $book, int $para)
|
|
private function getBookType(int $book, int $para)
|
|
|
{
|
|
{
|
|
|
|
|
|
|
@@ -386,21 +375,23 @@ class TipitakaController extends Controller
|
|
|
$tags = Tag::whereIn('id', $tagIds)->select('name')->get();
|
|
$tags = Tag::whereIn('id', $tagIds)->select('name')->get();
|
|
|
foreach ($tags as $key => $tag) {
|
|
foreach ($tags as $key => $tag) {
|
|
|
if (in_array($tag->name, ['pāḷi', 'aṭṭhakathā', 'ṭīkā'])) {
|
|
if (in_array($tag->name, ['pāḷi', 'aṭṭhakathā', 'ṭīkā'])) {
|
|
|
- return __('library.' . $tag->name);
|
|
|
|
|
|
|
+ return __('library.'.$tag->name);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
private function loadCategories()
|
|
private function loadCategories()
|
|
|
{
|
|
{
|
|
|
- $json = file_get_contents(public_path("data/category/default.json"));
|
|
|
|
|
|
|
+ $json = file_get_contents(public_path('data/category/default.json'));
|
|
|
$tree = json_decode($json, true);
|
|
$tree = json_decode($json, true);
|
|
|
$flat = self::flattenWithIds($tree);
|
|
$flat = self::flattenWithIds($tree);
|
|
|
|
|
+
|
|
|
return $flat;
|
|
return $flat;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public static function flattenWithIds(array $tree, int $parentId = 0, int $level = 1): array
|
|
|
|
|
|
|
+ public static function flattenWithIds(array $tree, int $parentId = 0, int $level = 1): array
|
|
|
{
|
|
{
|
|
|
|
|
|
|
|
$flat = [];
|
|
$flat = [];
|
|
@@ -413,7 +404,7 @@ class TipitakaController extends Controller
|
|
|
'parent_id' => $parentId,
|
|
'parent_id' => $parentId,
|
|
|
'name' => $node['name'] ?? null,
|
|
'name' => $node['name'] ?? null,
|
|
|
'tag' => $node['tag'] ?? [],
|
|
'tag' => $node['tag'] ?? [],
|
|
|
- "description" => "佛教戒律经典",
|
|
|
|
|
|
|
+ 'description' => '佛教戒律经典',
|
|
|
'level' => $level,
|
|
'level' => $level,
|
|
|
];
|
|
];
|
|
|
|
|
|
|
@@ -421,7 +412,7 @@ class TipitakaController extends Controller
|
|
|
|
|
|
|
|
if (isset($node['children']) && is_array($node['children'])) {
|
|
if (isset($node['children']) && is_array($node['children'])) {
|
|
|
$childrenLevel = $level + 1;
|
|
$childrenLevel = $level + 1;
|
|
|
- $flat = array_merge($flat, self::flattenWithIds($node['children'], $currentId, $childrenLevel));
|
|
|
|
|
|
|
+ $flat = array_merge($flat, self::flattenWithIds($node['children'], $currentId, $childrenLevel));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|