diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 0000000..ed350ec --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,133 @@ +setRules([ + '@PSR12:risky' => true, + 'array_syntax' => ['syntax' => 'short'], + 'binary_operator_spaces' => [ + 'default' => 'single_space', + 'operators' => ['=>' => 'single_space'], + ], + 'blank_line_after_namespace' => true, + 'array_indentation'=>true, + 'blank_line_after_opening_tag' => true, + 'blank_line_before_statement' => [ + 'statements' => ['return'], + ], + 'braces' => true, + 'cast_spaces' => true, + 'class_attributes_separation' => [ + 'elements' => [ + 'method' => 'one', + 'trait_import' => 'none', + ], + ], + 'class_definition' => true, + 'concat_space' => [ + 'spacing' => 'one', + ], + 'declare_equal_normalize' => true, + 'elseif' => true, + 'encoding' => true, + 'full_opening_tag' => true, + 'fully_qualified_strict_types' => true, + 'function_declaration' => true, + 'function_typehint_space' => true, + 'heredoc_to_nowdoc' => true, + 'include' => true, + 'increment_style' => ['style' => 'post'], + 'indentation_type' => true, + 'linebreak_after_opening_tag' => true, + 'line_ending' => true, + 'lowercase_cast' => true, + 'constant_case' => true, + 'lowercase_keywords' => true, + 'lowercase_static_reference' => true, + 'magic_method_casing' => true, + 'magic_constant_casing' => true, + 'method_argument_space' => true, + 'native_function_casing' => true, + 'no_alias_functions' => true, + 'no_extra_blank_lines' => [ + 'tokens' => [ + 'extra', + 'throw', + 'use', + ], + ], + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_closing_tag' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_mixed_echo_print' => [ + 'use' => 'echo', + ], + 'no_multiline_whitespace_around_double_arrow' => true, + 'multiline_whitespace_before_semicolons' => [ + 'strategy' => 'no_multi_line', + ], + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_spaces_after_function_name' => true, + 'no_spaces_around_offset' => true, + 'no_spaces_inside_parenthesis' => true, + 'no_trailing_comma_in_list_call' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_trailing_whitespace' => true, + 'no_trailing_whitespace_in_comment' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unreachable_default_argument_value' => true, + 'no_useless_return' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'normalize_index_brace' => true, + 'not_operator_with_successor_space' => false, + 'object_operator_without_whitespace' => true, + 'ordered_imports' => ['sort_algorithm' => 'alpha'], + 'phpdoc_indent' => true, + 'general_phpdoc_tag_rename' => true, + 'phpdoc_inline_tag_normalizer' => true, + 'phpdoc_tag_type' => true, + 'phpdoc_no_access' => true, + 'phpdoc_no_package' => true, + 'phpdoc_no_useless_inheritdoc' => true, + 'phpdoc_scalar' => true, + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_summary' => true, + 'phpdoc_to_comment' => true, + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'phpdoc_var_without_name' => true, + 'psr_autoloading' => true, + 'self_accessor' => true, + 'short_scalar_cast' => true, + 'simplified_null_return' => false, + 'single_blank_line_at_eof' => true, + 'single_blank_line_before_namespace' => true, + 'single_class_element_per_statement' => true, + 'single_import_per_statement' => true, + 'single_line_after_imports' => true, + 'single_line_comment_style' => [ + 'comment_types' => ['hash'], + ], + 'single_quote' => true, + 'space_after_semicolon' => true, + 'standardize_not_equals' => true, + 'switch_case_semicolon_to_colon' => true, + 'switch_case_space' => true, + 'ternary_operator_spaces' => true, + 'trailing_comma_in_multiline' => true, + 'trim_array_spaces' => true, + 'unary_operator_spaces' => true, + 'visibility_required' => [ + 'elements' => ['method', 'property'], + ], + 'whitespace_after_comma_in_array' => true, + 'no_unused_imports' => true, + + ]) + // ->setIndent("\t") + ->setLineEnding("\n"); diff --git a/app/common.php b/app/common.php index bcc2cf2..84fd0e3 100644 --- a/app/common.php +++ b/app/common.php @@ -77,7 +77,7 @@ function get_source_link($url) { if (empty($url)) { - $url = '/static/images/avatar.jpeg'; + $url = '/static/images/avatar.png'; } if (strpos($url, '/') === 0) { return $url; @@ -302,4 +302,26 @@ if (!function_exists('ua_htmlentities')) { return htmlentities($string); } +} + +function show_time_ago($timestamp) { + $current_time = new DateTime(); + $target_time = new DateTime("@$timestamp"); + $interval = $current_time->diff($target_time); + + if ($interval->y > 0) { + $result = $interval->format('%y 年前'); + } elseif ($interval->m > 0) { + $result = $interval->format('%m 个月前'); + } elseif ($interval->d > 0) { + $result = $interval->format('%d 天前'); + } elseif ($interval->h > 0) { + $result = $interval->format('%h 小时前'); + } elseif ($interval->i > 0) { + $result = $interval->format('%i 分钟前'); + } else { + $result = $interval->format('%s 秒前'); + } + + return $result; } \ No newline at end of file diff --git a/app/index/controller/Common.php b/app/index/controller/Common.php index 82716d1..28082f3 100644 --- a/app/index/controller/Common.php +++ b/app/index/controller/Common.php @@ -5,93 +5,110 @@ namespace app\index\controller; use app\model\Category; use app\model\Nav; use app\model\Post; +use app\model\PostVisit; use think\facade\Cache; use think\facade\Session; use think\facade\View; -use think\helper\Str; use UserHub\Client; class Common extends BaseController { - public function initialize() - { - parent::initialize(); + protected $userinfo = []; - $site_logo = get_source_link(get_system_config('site_logo')); + public function initialize() + { + parent::initialize(); - View::assign('site_logo', $site_logo); - $site_logo_box = get_source_link(get_system_config('site_logo_box')); + $site_logo = get_source_link(get_system_config('site_logo')); - View::assign('site_logo_box', $site_logo_box); + View::assign('site_logo', $site_logo); + $site_logo_box = get_source_link(get_system_config('site_logo_box')); - $list_nav_slide = Nav::where('type', 3)->cacheAlways('type_list_3')->order('sort asc')->where('status', 1)->select(); + View::assign('site_logo_box', $site_logo_box); - View::assign('list_nav_slide', $list_nav_slide); + $list_nav_slide = Nav::where('type', 3)->cacheAlways('type_list_3')->order('sort asc')->where('status', 1)->select(); - $list_nav_friend_url = Nav::where('type', 2)->cacheAlways('type_list_2')->order('sort asc')->where('status', 1)->select(); - View::assign('list_nav_friend_url', $list_nav_friend_url); + View::assign('list_nav_slide', $list_nav_slide); - $list_header_nav = Nav::where('type', 11)->cacheAlways('type_list_11')->order('sort asc')->where('status', 1)->select(); - View::assign('list_header_nav', $list_header_nav); + $list_nav_friend_url = Nav::where('type', 2)->cacheAlways('type_list_2')->order('sort asc')->where('status', 1)->select(); + View::assign('list_nav_friend_url', $list_nav_friend_url); - $list_category_first_level = Category::where('level', 1)->where('status', 1)->where('type', 3)->cacheAlways('category_type_list_3')->order('sort asc')->select(); - View::assign('list_category_first_level', $list_category_first_level); - $list_nav_more = Nav::where('type', 8)->cacheAlways('type_list_8')->order('sort asc')->where('status', 1)->select(); - View::assign('list_nav_more', $list_nav_more); + $list_header_nav = Nav::where('type', 11)->cacheAlways('type_list_11')->order('sort asc')->where('status', 1)->select(); + View::assign('list_header_nav', $list_header_nav); - $top_posts = Post::where('is_top', 1)->limit(8)->where('type', 3)->cacheAlways('top_post')->select(); - View::assign('top_posts', $top_posts); + $list_category_first_level = Category::where('level', 1)->where('status', 1)->where('type', 3)->cacheAlways('category_type_list_3')->order('sort asc')->select(); + View::assign('list_category_first_level', $list_category_first_level); + $list_nav_more = Nav::where('type', 8)->cacheAlways('type_list_8')->order('sort asc')->where('status', 1)->select(); + View::assign('list_nav_more', $list_nav_more); - $this->userHubLogin(); - } + $top_posts = Post::where('is_top', 1)->limit(8)->where('type', 3)->cacheAlways('top_post')->select(); + View::assign('top_posts', $top_posts); - public function userHubLogin() - { - $user_uid = Session::get('user_uid'); - $user_info = []; - if (empty($user_uid)) { - $code = $this->request->param('code'); + $list_site_last_visit = PostVisit::order('id desc') + ->group('ip,uid') + ->limit(6) + ->cache(60) + ->select(); + View::assign('list_site_last_visit', $list_site_last_visit); - // 实例化客户端,传入相关参数 - $user_hub_client = new Client([ - 'key' => get_system_config('user_hub_key'), - 'secret' => get_system_config('user_hub_secret'), - 'host' => get_system_config('user_hub_host'), - ]); - if (empty($code)) { - // 跳转登录 - $url = $user_hub_client->getBowserRedirectUrl($this->request->url(true)); - View::assign('login_url',$url); - } else { - // 获取用户信息 - $user_info = $user_hub_client->getUserinfoByCode($code); - Session::set('user_uid', $user_info['uid']); - - } - }else{ - $user_info = self::getUserInfo($user_uid); - } - View::assign('user_info',$user_info); - } + $total_hits = Post::cache(60)->sum('hits'); + View::assign('total_hits', $total_hits); - public static function getUserInfo($uid) - { - $cache_key = 'user_uid_'.$uid; - $user_info = Cache::get($cache_key); + $total_week_hits = PostVisit::cache(60)->where('create_time', '>', time() - 86400 * 7)->count(); + $total_day_hits = PostVisit::cache(60)->where('create_time', '>', time() - 86400)->count(); + View::assign('total_week_hits', $total_week_hits); + View::assign('total_day_hits', $total_day_hits); - if(is_null($user_info)){ - // 实例化客户端,传入相关参数 - $user_hub_client = new Client([ - 'key' => get_system_config('user_hub_key'), - 'secret' => get_system_config('user_hub_secret'), - 'host' => get_system_config('user_hub_host'), - ]); - - $user_info = $user_hub_client->getUserinfoByUid($uid); - - Cache::set($cache_key,$user_info); + $this->userHubLogin(); } - return $user_info; - } + public function userHubLogin() + { + $user_uid = Session::get('user_uid'); + $user_info = []; + if (empty($user_uid)) { + $code = $this->request->param('code'); + + // 实例化客户端,传入相关参数 + $user_hub_client = new Client([ + 'key' => get_system_config('user_hub_key'), + 'secret' => get_system_config('user_hub_secret'), + 'host' => get_system_config('user_hub_host'), + ]); + if (empty($code)) { + // 跳转登录 + $url = $user_hub_client->getBowserRedirectUrl($this->request->url(true)); + View::assign('login_url', $url); + } else { + // 获取用户信息 + $user_info = $user_hub_client->getUserinfoByCode($code); + Session::set('user_uid', $user_info['uid']); + } + } else { + $user_info = self::getUserInfo($user_uid); + } + $this->userinfo = $user_info; + View::assign('user_info', $user_info); + } + + public static function getUserInfo($uid) + { + $cache_key = 'user_uid_' . $uid; + $user_info = Cache::get($cache_key); + + if (is_null($user_info)) { + // 实例化客户端,传入相关参数 + $user_hub_client = new Client([ + 'key' => get_system_config('user_hub_key'), + 'secret' => get_system_config('user_hub_secret'), + 'host' => get_system_config('user_hub_host'), + ]); + + $user_info = $user_hub_client->getUserinfoByUid($uid); + + Cache::set($cache_key, $user_info); + } + + return $user_info; + } } diff --git a/app/index/controller/Index.php b/app/index/controller/Index.php index b6b9b70..b67489b 100644 --- a/app/index/controller/Index.php +++ b/app/index/controller/Index.php @@ -8,18 +8,16 @@ use app\model\PostCategory; use think\facade\Cache; use think\facade\Session; use think\facade\View; -use think\Request; class Index extends Common { /** - * 显示资源列表 + * 显示资源列表. * * @return \think\Response */ public function index() { - $page_cache_key = md5($this->request->url()); $content = Cache::get($page_cache_key); @@ -47,20 +45,18 @@ class Index extends Common if (empty($sub_category_id)) { $categorys = [$category_id]; - $categorys = array_merge($categorys, array_column((array)Category::getListLevel($category_id), 3)); + $categorys = array_merge($categorys, array_column((array) Category::getListLevel($category_id), 3)); $categorys_where = PostCategory::whereIn('category_id', $categorys); $model_post = Post::hasWhere('categorys', $categorys_where)->where('status', 1)->order('id desc'); } else { - $model_sub_category = Category::find($sub_category_id); $page_title .= "-{$model_sub_category->title}"; $model_post = Post::hasWhere('categorys', ['category_id' => $sub_category_id])->where('status', 1)->order('id desc'); } } else { - $model_post = Post::where('status', 1)->order('id desc'); } @@ -84,9 +80,9 @@ class Index extends Common 'category_id' => $this->request->param('category_id'), 'sub_category_id' => $this->request->param('sub_category_id'), 'page' => $page, - 'keywords' => $keywords + 'keywords' => $keywords, ], - 'list_rows' => 10 + 'list_rows' => 10, ]); View::assign('current_category', $current_category); @@ -102,13 +98,12 @@ class Index extends Common return $content; } - public function logout() { Session::clear(); $back_url = $this->request->param('back_url', '/'); + return $this->success('退出成功', $back_url); } - } diff --git a/app/index/controller/Post.php b/app/index/controller/Post.php index 4cbcceb..c40b11e 100644 --- a/app/index/controller/Post.php +++ b/app/index/controller/Post.php @@ -5,17 +5,16 @@ declare(strict_types=1); namespace app\index\controller; use app\model\Post as ModelPost; -use app\model\PostCategory; +use app\model\PostVisit; use think\facade\Cache; +use think\facade\Db; use think\facade\View; use think\model\Relation; -use think\Request; class Post extends Common { - /** - * 显示指定的资源 + * 显示指定的资源. * * @param int $id * @return \think\Response @@ -29,31 +28,45 @@ class Post extends Common $model_post = Cache::get($cache_key); if (empty($model_post)) { - $model_post = ModelPost::with([ 'comments' => function (Relation $query) { $query->order('id asc'); - } + }, ])->where('uid', $uid)->find(); if (empty($model_post)) { return $this->error('链接已失效', '/'); } - Cache::set($cache_key, $model_post,600); + Cache::set($cache_key, $model_post, 600); } - - $model_post->hits = $model_post->hits + 1; + $model_post->hits = Db::raw('hits + 1'); $model_post->save(); - + $this->recordVisit($model_post->id); + $list_last_visit = PostVisit::where('post_id', $model_post->id) + ->order('id desc') + ->group('ip,uid') + ->limit(12) + ->cache(60) + ->select(); View::assign('post', $model_post); - + View::assign('list_last_visit', $list_last_visit); return View::fetch(); } + public function recordVisit($post_id) + { + $model_visit = new PostVisit(); + $model_visit->uid = $this->userinfo['uid'] ?? ''; + $model_visit->post_id = $post_id; + $model_visit->avatar = $this->userinfo['avatar'] ?? ''; + $model_visit->nickname = $this->userinfo['nickname'] ?? ''; + $model_visit->ip = $this->request->ip(); + $model_visit->save(); + } } diff --git a/app/model/Admin.php b/app/model/Admin.php index 6c97d7f..8771450 100644 --- a/app/model/Admin.php +++ b/app/model/Admin.php @@ -15,7 +15,7 @@ class Admin extends Model { if(empty($value)){ - return '/static/images/avatar.jpeg'; + return '/static/images/avatar.png'; } return \get_source_link($value); diff --git a/app/model/Post.php b/app/model/Post.php index 887de96..9f34d85 100644 --- a/app/model/Post.php +++ b/app/model/Post.php @@ -23,6 +23,9 @@ class Post extends Base use SoftDelete; // + + public const CACHE_KEY_HITS = 'cache_hits_'; + public static $autoClearCache = [ [ 'name' => 'top_post' @@ -184,7 +187,7 @@ class Post extends Base public function getPosterAttr($value) { if (empty($value)) { - $value = '/static/images/avatar.jpeg'; + $value = '/static/images/avatar.png'; } return get_source_link($value); @@ -233,4 +236,31 @@ class Post extends Base } return $end_content; } + + public function getHitsTitleAttr() + { + $cache_key = static::CACHE_KEY_HITS.$this->getAttr('id'); + + $value = Cache::get($cache_key); + + if(!is_null($value)) { + return $value; + } + + $value = $this->getData('hits'); + + Cache::set($cache_key, $value, 600); + + return $value; + } + + public function setHitsAttr($value) + { + $cache_key = static::CACHE_KEY_HITS.$this->getAttr('id'); + + $this->getAttr('hits_title'); + Cache::inc($cache_key); + + return $value; + } } diff --git a/app/model/PostVisit.php b/app/model/PostVisit.php new file mode 100644 index 0000000..8a470ec --- /dev/null +++ b/app/model/PostVisit.php @@ -0,0 +1,44 @@ +getAttr('avatar'); + + if(empty($value)) { + $value = '/static/images/avatar.png'; + } + + return $value; + } + + public function getNicknameTitleAttr() + { + $value = $this->getAttr('nickname'); + + if(empty($value)) { + $value = 'IP用户:'.$this->getAttr('ip'); + } + + return $value; + } + + public function getCreateTimeTitleAttr() + { + $value = $this->getData('create_time'); + + return show_time_ago($value); + } +} diff --git a/app/model/User.php b/app/model/User.php index b85e914..94185fd 100644 --- a/app/model/User.php +++ b/app/model/User.php @@ -19,7 +19,7 @@ class User extends Model public function getAvatarAttr($value) { if(empty($value)){ - return '/static/images/avatar.jpeg'; + return '/static/images/avatar.png'; } return \get_source_link($value); diff --git a/database/migrations/20230628025857_create_table_post_visit.php b/database/migrations/20230628025857_create_table_post_visit.php new file mode 100644 index 0000000..916a502 --- /dev/null +++ b/database/migrations/20230628025857_create_table_post_visit.php @@ -0,0 +1,42 @@ +table('post_visit'); + $table->addColumn(ColumnFormat::timestamp('create_time')); + $table->addColumn(ColumnFormat::timestamp('update_time')); + $table->addColumn(ColumnFormat::timestamp('delete_time')); + $table->addColumn(ColumnFormat::integer('post_id')); + $table->addColumn(ColumnFormat::stringUrl('ip')); + $table->addColumn(ColumnFormat::stringNormal('nickname')); + $table->addColumn(ColumnFormat::stringNormal('uid')); + $table->addColumn(ColumnFormat::stringUrl('avatar')); + $table->create(); + } +} diff --git a/database/seeds/InitAdmin.php b/database/seeds/InitAdmin.php index 194f239..6afd1db 100644 --- a/database/seeds/InitAdmin.php +++ b/database/seeds/InitAdmin.php @@ -19,7 +19,7 @@ class InitAdmin extends Seeder $account['account'] = 'admin'; $account['salt'] = Str::random(6); $account['password'] = md5('123456'.$account['salt']); - $account['avatar'] = '/static/images/avatar.jpeg'; + $account['avatar'] = '/static/images/avatar.png'; $model_admin = Admin::where('account',$account['account'])->find(); diff --git a/public/static/css/index.css b/public/static/css/index.css new file mode 100644 index 0000000..7f19f15 --- /dev/null +++ b/public/static/css/index.css @@ -0,0 +1,4 @@ +.ul-avatar-sidebar-list { + display: flex; + flex-wrap: wrap; +} \ No newline at end of file diff --git a/public/static/images/avatar.jpeg b/public/static/images/avatar.jpeg deleted file mode 100644 index c2bc2b7..0000000 Binary files a/public/static/images/avatar.jpeg and /dev/null differ diff --git a/public/static/images/avatar.png b/public/static/images/avatar.png new file mode 100644 index 0000000..4024db3 Binary files /dev/null and b/public/static/images/avatar.png differ diff --git a/view/index/common/_require.html b/view/index/common/_require.html index b448315..48929c8 100644 --- a/view/index/common/_require.html +++ b/view/index/common/_require.html @@ -1,7 +1,11 @@ + + + + diff --git a/view/index/common/_right.html b/view/index/common/_right.html index 1fac6ce..766f11c 100644 --- a/view/index/common/_right.html +++ b/view/index/common/_right.html @@ -74,6 +74,36 @@ +