302 lines
8.9 KiB
PHP
302 lines
8.9 KiB
PHP
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
|
// +----------------------------------------------------------------------
|
|
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
|
// +----------------------------------------------------------------------
|
|
// | Author: ywxapp<admin@ywxapp.cn>
|
|
// +----------------------------------------------------------------------
|
|
declare (strict_types = 1);
|
|
|
|
namespace addon\blog\controller;
|
|
|
|
use addon\blog\model\BlogArticle as ArticleModel;
|
|
use addon\blog\model\BlogCategory as CategoryModel;
|
|
use addon\blog\model\BlogComment as CommentModel;
|
|
use addon\blog\model\BlogTag as TagModel;
|
|
use addon\blog\model\BlogLike as LikeModel;
|
|
use addon\blog\model\BlogFavorite as FavoriteModel;
|
|
use ywxapp\model\MemberUser;
|
|
use think\facade\Cache;
|
|
use think\facade\Request;
|
|
use think\facade\View;
|
|
|
|
/**
|
|
* Article 类
|
|
*
|
|
* @author ywxapp <admin@ywxapp.cn>
|
|
*/
|
|
class Article extends BlogFrontend
|
|
{
|
|
|
|
public function initialize()
|
|
{
|
|
}
|
|
|
|
protected $noNeedLogin = ['*'];
|
|
|
|
/**
|
|
* 网站首页
|
|
*/
|
|
public function index()
|
|
{
|
|
$page = Request::param('page', 1);
|
|
|
|
$articles = ArticleModel::with(['user', 'category', 'tags'])
|
|
->where('status', 1)
|
|
->order('create_at', 'desc')
|
|
->paginate(['list_rows' => 10, 'page' => $page]);
|
|
|
|
$hotArticles = ArticleModel::with(['user', 'category'])
|
|
->where('status', 1)
|
|
->order('view_count', 'desc')
|
|
->limit(5)
|
|
->select();
|
|
|
|
$recommendedArticles = ArticleModel::with(['user', 'category'])
|
|
->where('status', 1)
|
|
->where('is_top', 1)
|
|
->order('like_count', 'desc')
|
|
->limit(5)
|
|
->select();
|
|
|
|
$categories = CategoryModel::withCount(['articles' =>
|
|
function ($query, &$alias) {
|
|
$query->where('status', 1);
|
|
$alias = 'card_count';
|
|
}])
|
|
->order('sort', 'asc')
|
|
->select();
|
|
|
|
$tags = TagModel::withCount('articles')
|
|
->order('create_at', 'desc')
|
|
->limit(20)
|
|
->select();
|
|
|
|
$latestComments = CommentModel::with(['user', 'article'])
|
|
->where('status', 1)
|
|
->order('create_at', 'desc')
|
|
->limit(5)
|
|
->select();
|
|
|
|
$this->view->assign('articles', $articles);
|
|
$this->view->assign('hotArticles', $hotArticles);
|
|
$this->view->assign('recommendedArticles', $recommendedArticles);
|
|
$this->view->assign('categories', $categories);
|
|
$this->view->assign('tags', $tags);
|
|
$this->view->assign('latestComments', $latestComments);
|
|
return $this->view->fetch();
|
|
}
|
|
|
|
/**
|
|
* 文章详情页
|
|
*/
|
|
public function detail($id)
|
|
{
|
|
$article = ArticleModel::with(['user', 'category', 'tags'])
|
|
->where('id', $id)
|
|
->where('status', 1)
|
|
->find();
|
|
|
|
if (!$article) {
|
|
return $this->error('文章不存在或已被删除');
|
|
}
|
|
|
|
$article->view_count += 1;
|
|
$article->save();
|
|
|
|
$comments = CommentModel::with([
|
|
'member',
|
|
'children' =>
|
|
function ($q) {
|
|
$q->with(['user'])->where('status', 1)->order('create_at', 'asc');
|
|
},
|
|
])
|
|
->where('aid', $id)
|
|
->where('pid', 0)
|
|
->where('status', 1)
|
|
->order('create_at', 'desc')
|
|
->paginate(10);
|
|
|
|
$relatedArticles = \addon\blog\service\BlogSearchService::related($article->id, 5);
|
|
|
|
return View::fetch('article/detail', [
|
|
'article' => $article,
|
|
'comments' => $comments,
|
|
'relatedArticles' => $relatedArticles
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 文章点赞
|
|
*/
|
|
public function like($id)
|
|
{
|
|
if (! $this->auth->isLogin) {
|
|
return json(['code' => 0, 'msg' => '请先登录']);
|
|
}
|
|
$uid = $this->auth->model->uid;
|
|
|
|
$article = ArticleModel::find($id);
|
|
if (!$article) {
|
|
return json(['code' => 0, 'msg' => '文章不存在']);
|
|
}
|
|
|
|
$like = LikeModel::where('uid', $uid)
|
|
->where('aid', $id)
|
|
->find();
|
|
|
|
if ($like) {
|
|
$like->delete();
|
|
$article->like_count = max(0, $article->like_count - 1);
|
|
$action = 'cancel';
|
|
} else {
|
|
$like = new LikeModel();
|
|
$like->uid = $uid;
|
|
$like->aid = $id;
|
|
$like->save();
|
|
$article->like_count += 1;
|
|
$action = 'add';
|
|
}
|
|
|
|
$article->save();
|
|
|
|
return json([
|
|
'code' => 1,
|
|
'msg' => $action == 'add' ? '点赞成功' : '已取消点赞',
|
|
'count' => $article->like_count,
|
|
'action' => $action
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 文章收藏
|
|
*/
|
|
public function favorite($id)
|
|
{
|
|
if (! $this->auth->isLogin) {
|
|
return json(['code' => 0, 'msg' => '请先登录']);
|
|
}
|
|
$uid = $this->auth->model->uid;
|
|
|
|
$article = ArticleModel::find($id);
|
|
if (!$article) {
|
|
return json(['code' => 0, 'msg' => '文章不存在']);
|
|
}
|
|
|
|
$favorite = FavoriteModel::where('uid', $uid)
|
|
->where('aid', $id)
|
|
->find();
|
|
|
|
if ($favorite) {
|
|
$favorite->delete();
|
|
$article->favorite_count = max(0, $article->favorite_count - 1);
|
|
$action = 'cancel';
|
|
} else {
|
|
$favorite = new FavoriteModel();
|
|
$favorite->uid = $uid;
|
|
$favorite->aid = $id;
|
|
$favorite->save();
|
|
$article->favorite_count += 1;
|
|
$action = 'add';
|
|
}
|
|
|
|
$article->save();
|
|
|
|
return json([
|
|
'code' => 1,
|
|
'msg' => $action == 'add' ? '收藏成功' : '已取消收藏',
|
|
'count' => $article->favorite_count,
|
|
'action' => $action
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 获取文章评论
|
|
*/
|
|
public function getComments($id)
|
|
{
|
|
$page = Request::param('page', 1);
|
|
$pageSize = Request::param('page_size', 10);
|
|
|
|
$comments = CommentModel::with(['user'])
|
|
->where('aid', $id)
|
|
->where('pid', 0)
|
|
->where('status', 1)
|
|
->order('create_at', 'desc')
|
|
->page($page, $pageSize)
|
|
->select();
|
|
|
|
$total = CommentModel::where('aid', $id)
|
|
->where('pid', 0)
|
|
->where('status', 1)
|
|
->count();
|
|
|
|
$commentList = [];
|
|
foreach ($comments as $comment) {
|
|
$commentList[] = [
|
|
'id' => $comment->id,
|
|
'content' => $comment->content,
|
|
'create_at' => date('Y-m-d H:i', $comment->create_at),
|
|
'member' => [
|
|
'uid' => $comment->user->uid,
|
|
'nickname' => $comment->user->nickname,
|
|
'avatar' => $comment->user->avatar ?? '/static/images/avatar.png'
|
|
],
|
|
'like_count' => $comment->like_count
|
|
];
|
|
}
|
|
|
|
return json([
|
|
'code' => 1,
|
|
'data' => [
|
|
'list' => $commentList,
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'page_size' => $pageSize
|
|
]
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 个人博客主页:展示该用户的资料 + 已发布文章(多用户门户)
|
|
*/
|
|
public function author($id)
|
|
{
|
|
$author = MemberUser::find($id);
|
|
if (!$author) {
|
|
return $this->error('用户不存在');
|
|
}
|
|
|
|
$stats = [
|
|
'articles' => ArticleModel::where('uid', $id)->where('status', 1)->count(),
|
|
'views' => (int) ArticleModel::where('uid', $id)->where('status', 1)->sum('view_count'),
|
|
'likes' => (int) ArticleModel::where('uid', $id)->where('status', 1)->sum('like_count'),
|
|
];
|
|
|
|
$join = $author->create_at;
|
|
if (is_numeric($join)) {
|
|
$join = date('Y-m-d', (int) $join);
|
|
} else {
|
|
$ts = strtotime((string) $join);
|
|
$join = $ts !== false ? date('Y-m-d', $ts) : (string) $join;
|
|
}
|
|
|
|
$avatar = $author->avatar ?: '/static/blog/img/portrait.jpg';
|
|
|
|
$articles = ArticleModel::with(['user', 'category', 'tags'])
|
|
->where('uid', $id)
|
|
->where('status', 1)
|
|
->order('create_at', 'desc')
|
|
->paginate(10);
|
|
|
|
return View::fetch('article/author', [
|
|
'author' => $author,
|
|
'avatar' => $avatar,
|
|
'author_join' => $join,
|
|
'stats' => $stats,
|
|
'articles' => $articles,
|
|
]);
|
|
}
|
|
}
|