增加program详情页
This commit is contained in:
		
							parent
							
								
									f6f8f6ac52
								
							
						
					
					
						commit
						4c6f7277b0
					
				| @ -94,38 +94,48 @@ class Article extends Base | ||||
|              | ||||
|         // 获取相关文章(同分类的其他文章)
 | ||||
|         $relatedArticles = Db::table('yz_article') | ||||
|             ->where('cate', $article['cate']) | ||||
|             ->where('id', '<>', $id) | ||||
|             ->where('delete_time', null) | ||||
|             ->where('status', '<>', 3) | ||||
|             ->order('id DESC') | ||||
|             ->alias('a') | ||||
|             ->join('yz_article_category c', 'a.cate = c.id') | ||||
|             ->where('a.cate', $article['cate']) | ||||
|             ->where('a.id', '<>', $id) | ||||
|             ->where('a.delete_time', null) | ||||
|             ->where('a.status', '=', 2) | ||||
|             ->field([ | ||||
|                 'a.id', | ||||
|                 'a.title', | ||||
|                 'a.desc', | ||||
|                 'IF(a.image IS NULL OR a.image = "", c.image, a.image) as image' | ||||
|             ]) | ||||
|             ->order('a.id DESC') | ||||
|             ->limit(3) | ||||
|             ->select() | ||||
|             ->toArray(); | ||||
| 
 | ||||
|         // 如果是 AJAX 请求,返回 JSON 数据
 | ||||
|         if (Request::isAjax()) { | ||||
|             return json([ | ||||
|                 'code' => 1, | ||||
|                 'msg' => '获取成功', | ||||
|                 'data' => [ | ||||
|                     'article' => $article, | ||||
|                     'cateName' => $cateName, | ||||
|                     'prevArticle' => $prevArticle, | ||||
|                     'nextArticle' => $nextArticle, | ||||
|                     'relatedArticles' => $relatedArticles | ||||
|                 ] | ||||
|             ]); | ||||
|         } | ||||
|              | ||||
|         // 获取评论列表
 | ||||
|         // $comments = Db::table('yz_article_comment')
 | ||||
|         //     ->where('article_id', $id)
 | ||||
|         //     ->where('delete_time', null)
 | ||||
|         //     ->order('id DESC')
 | ||||
|         //     ->select()
 | ||||
|         //     ->toArray();
 | ||||
|          | ||||
|         // 更新浏览量(使用Cookie和IP双重验证)
 | ||||
|         $ip = Request::ip(); | ||||
|         $cookieKey = 'article_view_' . $id; | ||||
|         $viewCookie = Request::cookie($cookieKey); | ||||
|          | ||||
|         // 非 AJAX 请求返回视图
 | ||||
|         View::assign([ | ||||
|             'article' => $article, | ||||
|             'cateName' => $cateName, | ||||
|             'prevArticle' => $prevArticle, | ||||
|             'nextArticle' => $nextArticle, | ||||
|             'relatedArticles' => $relatedArticles, | ||||
|             // 'comments' => $comments
 | ||||
|             'relatedArticles' => $relatedArticles | ||||
|         ]); | ||||
|          | ||||
|         return View::fetch(); | ||||
| 
 | ||||
|         return view('detail'); | ||||
|     } | ||||
| 
 | ||||
|     // 文章点赞
 | ||||
| @ -229,4 +239,37 @@ class Article extends Base | ||||
|             ] | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 更新文章访问次数 | ||||
|      */ | ||||
|     public function updateViews() | ||||
|     { | ||||
|         if (!Request::isPost()) { | ||||
|             return json(['code' => 0, 'msg' => '非法请求']); | ||||
|         } | ||||
| 
 | ||||
|         $id = Request::post('id'); | ||||
|         if (!$id) { | ||||
|             return json(['code' => 0, 'msg' => '参数错误']); | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             // 更新访问次数
 | ||||
|             $article = Db::table('yz_article')->where('id', $id)->find(); | ||||
|             if (!$article) { | ||||
|                 return json(['code' => 0, 'msg' => '文章不存在']); | ||||
|             } | ||||
| 
 | ||||
|             // 更新访问次数
 | ||||
|             Db::table('yz_article')->where('id', $id)->inc('views')->update(); | ||||
|              | ||||
|             // 获取更新后的访问次数
 | ||||
|             $newViews = Db::table('yz_article')->where('id', $id)->value('views'); | ||||
|              | ||||
|             return json(['code' => 1, 'msg' => '更新成功', 'data' => ['views' => $newViews]]); | ||||
|         } catch (\Exception $e) { | ||||
|             return json(['code' => 0, 'msg' => '更新失败:' . $e->getMessage()]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										233
									
								
								app/index/controller/Program.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								app/index/controller/Program.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,233 @@ | ||||
| <?php | ||||
| /** | ||||
|  *	程序下载控制器 | ||||
|  */ | ||||
| namespace app\index\controller; | ||||
| use app\index\controller\Base; | ||||
| use think\facade\Db; | ||||
| use think\facade\View; | ||||
| use think\facade\Request; | ||||
| 
 | ||||
| class Program extends Base | ||||
| { | ||||
|     // 程序列表页
 | ||||
|     public function list() | ||||
|     { | ||||
|         // 获取分类ID
 | ||||
|         $cateId = Request::param('cate/d', 0); | ||||
| 
 | ||||
|         // 构建查询条件
 | ||||
|         $where = [ | ||||
|             ['delete_time', '=', null], | ||||
|             ['status', '=', 1] | ||||
|         ]; | ||||
| 
 | ||||
|         if ($cateId > 0) { | ||||
|             $where[] = ['cate', '=', $cateId]; | ||||
|         } | ||||
| 
 | ||||
|         // 获取程序列表
 | ||||
|         $programs = Db::table('yz_resources') | ||||
|             ->where($where) | ||||
|             ->order('id DESC') | ||||
|             ->paginate([ | ||||
|                 'list_rows' => 10, | ||||
|                 'query' => Request::instance()->param() | ||||
|             ]); | ||||
| 
 | ||||
|         // 获取分类信息
 | ||||
|         $category = null; | ||||
|         if ($cateId > 0) { | ||||
|             $category = Db::table('yz_resources_category') | ||||
|                 ->where('id', $cateId) | ||||
|                 ->where('delete_time', null) | ||||
|                 ->where('status', 1) | ||||
|                 ->find(); | ||||
|         } | ||||
| 
 | ||||
|         // 获取所有分类
 | ||||
|         $categories = Db::table('yz_resources_category') | ||||
|             ->where('delete_time', null) | ||||
|             ->where('status', 1) | ||||
|             ->select() | ||||
|             ->toArray(); | ||||
| 
 | ||||
|         // 将变量传递给视图
 | ||||
|         View::assign([ | ||||
|             'programs' => $programs, | ||||
|             'category' => $category, | ||||
|             'categories' => $categories | ||||
|         ]); | ||||
| 
 | ||||
|         return view('list'); | ||||
|     } | ||||
| 
 | ||||
|     // 程序详情页
 | ||||
|     public function detail() | ||||
|     { | ||||
|         $id = Request::param('id/d', 0); | ||||
|         $program = Db::table('yz_resources')->where('id', $id)->find(); | ||||
|          | ||||
|         // 如果size没有,从附件表中获取
 | ||||
|         if (empty($program['size']) && !empty($program['fileurl'])) { | ||||
|             $attachment = Db::table('yz_attachments') | ||||
|                 ->where('src', $program['fileurl']) | ||||
|                 ->find(); | ||||
|              | ||||
|             if ($attachment && !empty($attachment['size'])) { | ||||
|                 $size = $attachment['size']; | ||||
|                 // 转换文件大小为合适的单位
 | ||||
|                 if ($size >= 1073741824) { // 1GB = 1024MB = 1024*1024KB = 1024*1024*1024B
 | ||||
|                     $program['size'] = round($size / 1073741824, 2) . 'GB'; | ||||
|                 } elseif ($size >= 1048576) { // 1MB = 1024KB = 1024*1024B
 | ||||
|                     $program['size'] = round($size / 1048576, 2) . 'MB'; | ||||
|                 } else { | ||||
|                     $program['size'] = round($size / 1024, 2) . 'KB'; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         if (!$program) { | ||||
|             return json(['code' => 0, 'msg' => '程序不存在或已被删除']); | ||||
|         } | ||||
| 
 | ||||
|         // 获取分类名称
 | ||||
|         $cateName = Db::table('yz_resources_category') | ||||
|             ->where('id', $program['cate']) | ||||
|             ->value('name'); | ||||
|          | ||||
|         // 获取上一个和下一个程序
 | ||||
|         $prevProgram = Db::table('yz_resources') | ||||
|             ->where('id', '<', $id) | ||||
|             ->where('delete_time', null) | ||||
|             ->where('status', 1) | ||||
|             ->order('id DESC') | ||||
|             ->find(); | ||||
|              | ||||
|         $nextProgram = Db::table('yz_resources') | ||||
|             ->where('id', '>', $id) | ||||
|             ->where('delete_time', null) | ||||
|             ->where('status', 1) | ||||
|             ->order('id ASC') | ||||
|             ->find(); | ||||
|              | ||||
|         // 获取相关程序(同分类的其他程序)
 | ||||
|         $relatedPrograms = Db::table('yz_resources') | ||||
|             ->alias('p') | ||||
|             ->join('yz_resources_category c', 'p.cate = c.id') | ||||
|             ->where('p.cate', $program['cate']) | ||||
|             ->where('p.id', '<>', $id) | ||||
|             ->where('p.delete_time', null) | ||||
|             ->where('p.status', 1) | ||||
|             ->field([ | ||||
|                 'p.id', | ||||
|                 'p.title', | ||||
|                 'p.desc', | ||||
|                 'IF(p.icon IS NULL OR p.icon = "", c.icon, p.icon) as icon' | ||||
|             ]) | ||||
|             ->order('p.id DESC') | ||||
|             ->limit(3) | ||||
|             ->select() | ||||
|             ->toArray(); | ||||
| 
 | ||||
|         // 如果是 AJAX 请求,返回 JSON 数据
 | ||||
|         if (Request::isAjax()) { | ||||
|             return json([ | ||||
|                 'code' => 1, | ||||
|                 'msg' => '获取成功', | ||||
|                 'data' => [ | ||||
|                     'program' => $program, | ||||
|                     'cateName' => $cateName, | ||||
|                     'prevProgram' => $prevProgram, | ||||
|                     'nextProgram' => $nextProgram, | ||||
|                     'relatedPrograms' => $relatedPrograms | ||||
|                 ] | ||||
|             ]); | ||||
|         } | ||||
|              | ||||
|         // 非 AJAX 请求返回视图
 | ||||
|         View::assign([ | ||||
|             'program' => $program, | ||||
|             'cateName' => $cateName, | ||||
|             'prevProgram' => $prevProgram, | ||||
|             'nextProgram' => $nextProgram, | ||||
|             'relatedPrograms' => $relatedPrograms | ||||
|         ]); | ||||
| 
 | ||||
|         return view('detail'); | ||||
|     } | ||||
| 
 | ||||
|     // 程序下载
 | ||||
|     public function download() | ||||
|     { | ||||
|         if (!Request::isAjax()) { | ||||
|             return json(['code' => 0, 'msg' => '非法请求']); | ||||
|         } | ||||
| 
 | ||||
|         $id = Request::param('id/d', 0); | ||||
| 
 | ||||
|         // 更新下载次数
 | ||||
|         $result = Db::table('yz_resources') | ||||
|             ->where('id', $id) | ||||
|             ->where('delete_time', null) | ||||
|             ->inc('downloads', 1) | ||||
|             ->update(); | ||||
| 
 | ||||
|         if ($result) { | ||||
|             return json(['code' => 1, 'msg' => '下载成功']); | ||||
|         } else { | ||||
|             return json(['code' => 0, 'msg' => '下载失败']); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 获取访问统计
 | ||||
|     public function viewStats() | ||||
|     { | ||||
|         $id = Request::param('id/d', 0); | ||||
|          | ||||
|         // 获取总访问量
 | ||||
|         $totalViews = Db::table('yz_resources') | ||||
|             ->where('id', $id) | ||||
|             ->value('views'); | ||||
|              | ||||
|         return json([ | ||||
|             'code' => 1, | ||||
|             'data' => [ | ||||
|                 'total' => $totalViews | ||||
|             ] | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 更新程序访问次数 | ||||
|      */ | ||||
|     public function updateViews() | ||||
|     { | ||||
|         if (!Request::isPost()) { | ||||
|             return json(['code' => 0, 'msg' => '非法请求']); | ||||
|         } | ||||
| 
 | ||||
|         $id = Request::post('id'); | ||||
|         if (!$id) { | ||||
|             return json(['code' => 0, 'msg' => '参数错误']); | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             // 更新访问次数
 | ||||
|             $program = Db::table('yz_resources')->where('id', $id)->find(); | ||||
|             if (!$program) { | ||||
|                 return json(['code' => 0, 'msg' => '程序不存在']); | ||||
|             } | ||||
| 
 | ||||
|             // 更新访问次数
 | ||||
|             Db::table('yz_resources')->where('id', $id)->inc('views')->update(); | ||||
|              | ||||
|             // 获取更新后的访问次数
 | ||||
|             $newViews = Db::table('yz_resources')->where('id', $id)->value('views'); | ||||
|              | ||||
|             return json(['code' => 1, 'msg' => '更新成功', 'data' => ['views' => $newViews]]); | ||||
|         } catch (\Exception $e) { | ||||
|             return json(['code' => 0, 'msg' => '更新失败:' . $e->getMessage()]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -4,45 +4,36 @@ | ||||
|     <div class="location"> | ||||
|         <div class="container"> | ||||
|             <div class="location-item"> | ||||
|                 <a href="{:url('index/index/index')}">首页</a> | ||||
|                 <a href="/">首页</a> | ||||
|                 <span>></span> | ||||
|                 <a href="{:url('index/article/index')}">技术文章</a> | ||||
|                 <a href="/index/article/index" id="cateLink"></a> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
| 
 | ||||
|     <div class="article-detail-container"> | ||||
|         <div class="article-header"> | ||||
|             <h1 class="article-title">{$article.title}</h1> | ||||
|             <h1 class="article-title" id="articleTitle"></h1> | ||||
|             <div class="article-meta"> | ||||
|                 <span class="article-author"><i class="fa fa-user"></i> {$article.author}</span> | ||||
|                 <span class="article-date"><i class="fa fa-calendar"></i> {$article.create_time|date='Y-m-d H:i'}</span> | ||||
|                 <span class="article-category"><i class="fa fa-folder"></i> {$cateName}</span> | ||||
|                 <span class="article-views"><i class="fa fa-eye"></i> {$article.views} 阅读</span> | ||||
|                 <span class="article-author"><i class="fa fa-user"></i> <span id="articleAuthor"></span></span> | ||||
|                 <span class="article-date"><i class="fa fa-calendar"></i> <span id="articleDate"></span></span> | ||||
|                 <span class="article-views"><i class="fa-solid fa-eye"></i> <span id="articleViews"></span> 阅读</span> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="article-content"> | ||||
|             {$article.content|raw} | ||||
|         <div class="article-content" id="articleContent"> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="article-tags"> | ||||
|             <span class="tag-label">标签:</span> | ||||
|             {if !empty($article.tags)} | ||||
|             {foreach $article.tags as $tag} | ||||
|             <span class="tag-item">{$tag}</span> | ||||
|             {/foreach} | ||||
|             {else} | ||||
|             <span class="no-tags">暂无标签</span> | ||||
|             {/if} | ||||
|             <div id="articleTags"></div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="article-actions"> | ||||
|             <div class="action-item like-btn"> | ||||
|                 <i class="fa fa-thumbs-up"></i> | ||||
|                 <span class="action-text">点赞</span> | ||||
|                 <span class="action-count">{$article.likes|default=0}</span> | ||||
|                 <span class="action-count" id="articleLikes">0</span> | ||||
|             </div> | ||||
|             <div class="action-item share-btn"> | ||||
|                 <i class="fa fa-share-alt"></i> | ||||
| @ -51,77 +42,17 @@ | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="article-navigation"> | ||||
|             <div class="prev-article"> | ||||
|                 {if !empty($prevArticle)} | ||||
|                 <a href="{:url('index/article/index', ['id' => $prevArticle.id])}"> | ||||
|                     <i class="fa fa-arrow-left"></i> 上一篇:{$prevArticle.title} | ||||
|                 </a> | ||||
|                 {else} | ||||
|                 <span class="disabled"><i class="fa fa-arrow-left"></i> 没有上一篇了</span> | ||||
|                 {/if} | ||||
|             <div class="prev-article" id="prevArticle"> | ||||
|             </div> | ||||
|             <div class="next-article"> | ||||
|                 {if !empty($nextArticle)} | ||||
|                 <a href="{:url('index/article/index', ['id' => $nextArticle.id])}"> | ||||
|                     下一篇:{$nextArticle.title} <i class="fa fa-arrow-right"></i> | ||||
|                 </a> | ||||
|                 {else} | ||||
|                 <span class="disabled">没有下一篇了 <i class="fa fa-arrow-right"></i></span> | ||||
|                 {/if} | ||||
|             <div class="next-article" id="nextArticle"> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="related-articles"> | ||||
|             <h3 class="related-title">相关推荐</h3> | ||||
|             <div class="related-list"> | ||||
|                 {if !empty($relatedArticles)} | ||||
|                 {foreach $relatedArticles as $related} | ||||
|                 <div class="related-item"> | ||||
|                     <a href="{:url('index/article/index', ['id' => $related.id])}"> | ||||
|                         <div class="related-image"> | ||||
|                             <img src="{$related.image}" alt="{$related.title}"> | ||||
|                         </div> | ||||
|                         <div class="related-info"> | ||||
|                             <div class="related-item-title">{$related.title}</div> | ||||
|                             <div class="related-item-desc">{$related.desc}</div> | ||||
|                         </div> | ||||
|                     </a> | ||||
|                 </div> | ||||
|                 {/foreach} | ||||
|                 {else} | ||||
|                 <div class="no-related">暂无相关文章</div> | ||||
|                 {/if} | ||||
|             <div class="related-list" id="relatedArticles"> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- <div class="article-comments"> | ||||
|         <h3 class="comments-title">评论区</h3> | ||||
|         <div class="comment-form"> | ||||
|             <textarea placeholder="请输入您的评论..." class="comment-textarea"></textarea> | ||||
|             <button class="comment-submit">发表评论</button> | ||||
|         </div> | ||||
|         <div class="comment-list"> | ||||
|             {if !empty($comments)} | ||||
|                 {foreach $comments as $comment} | ||||
|                     <div class="comment-item"> | ||||
|                         <div class="comment-avatar"> | ||||
|                             <img src="{$comment.avatar|default='/static/images/default-avatar.png'}" alt="用户头像"> | ||||
|                         </div> | ||||
|                         <div class="comment-content"> | ||||
|                             <div class="comment-user">{$comment.username}</div> | ||||
|                             <div class="comment-text">{$comment.content}</div> | ||||
|                             <div class="comment-footer"> | ||||
|                                 <span class="comment-time">{$comment.create_time|date='Y-m-d H:i'}</span> | ||||
|                                 <span class="comment-reply">回复</span> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 {/foreach} | ||||
|             {else} | ||||
|                 <div class="no-comments">暂无评论,快来抢沙发吧!</div> | ||||
|             {/if} | ||||
|         </div> | ||||
|     </div> --> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| @ -479,33 +410,159 @@ | ||||
|             height: 36px; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     .location-item a { | ||||
|         color: #000 !important;
 | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     document.addEventListener('DOMContentLoaded', function () { | ||||
|     // 格式化日期
 | ||||
|     function formatDate(timestamp) { | ||||
|         const date = new Date(timestamp * 1000); | ||||
|         return date.toLocaleDateString('zh-CN', { | ||||
|             year: 'numeric', | ||||
|             month: '2-digit', | ||||
|             day: '2-digit' | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     // 渲染文章详情
 | ||||
|     function renderArticleDetail(data) { | ||||
|         // 渲染分类链接
 | ||||
|         document.getElementById('cateLink').textContent = data.cateName; | ||||
|          | ||||
|         // 渲染文章标题
 | ||||
|         document.getElementById('articleTitle').textContent = data.article.title; | ||||
|          | ||||
|         // 渲染文章元信息
 | ||||
|         document.getElementById('articleAuthor').textContent = data.article.author; | ||||
|         document.getElementById('articleDate').textContent = formatDate(data.article.create_time); | ||||
|         document.getElementById('articleViews').textContent = data.article.views; | ||||
|          | ||||
|         // 渲染文章内容
 | ||||
|         document.getElementById('articleContent').innerHTML = data.article.content; | ||||
|          | ||||
|         // 渲染标签
 | ||||
|         const tagsContainer = document.getElementById('articleTags'); | ||||
|         if (data.article.tags && data.article.tags.length > 0) { | ||||
|             tagsContainer.innerHTML = data.article.tags.map(tag =>  | ||||
|                 `<span class="tag-item">${tag}</span>` | ||||
|             ).join(''); | ||||
|         } else { | ||||
|             tagsContainer.innerHTML = '<span class="no-tags">暂无标签</span>'; | ||||
|         } | ||||
|          | ||||
|         // 渲染点赞数
 | ||||
|         document.getElementById('articleLikes').textContent = data.article.likes || 0; | ||||
|          | ||||
|         // 渲染上一篇
 | ||||
|         const prevArticle = document.getElementById('prevArticle'); | ||||
|         if (data.prevArticle) { | ||||
|             prevArticle.innerHTML = ` | ||||
|                 <a href="/index/article/detail?id=${data.prevArticle.id}"> | ||||
|                     <i class="fa fa-arrow-left"></i> 上一篇:${data.prevArticle.title} | ||||
|                 </a> | ||||
|             `; | ||||
|         } else { | ||||
|             prevArticle.innerHTML = '<span class="disabled"><i class="fa fa-arrow-left"></i> 没有上一篇了</span>'; | ||||
|         } | ||||
|          | ||||
|         // 渲染下一篇
 | ||||
|         const nextArticle = document.getElementById('nextArticle'); | ||||
|         if (data.nextArticle) { | ||||
|             nextArticle.innerHTML = ` | ||||
|                 <a href="/index/article/detail?id=${data.nextArticle.id}"> | ||||
|                     下一篇:${data.nextArticle.title} <i class="fa fa-arrow-right"></i> | ||||
|                 </a> | ||||
|             `; | ||||
|         } else { | ||||
|             nextArticle.innerHTML = '<span class="disabled">没有下一篇了 <i class="fa fa-arrow-right"></i></span>'; | ||||
|         } | ||||
|          | ||||
|         // 渲染相关文章
 | ||||
|         const relatedArticles = document.getElementById('relatedArticles'); | ||||
|         if (data.relatedArticles && data.relatedArticles.length > 0) { | ||||
|             relatedArticles.innerHTML = data.relatedArticles.map(article => ` | ||||
|                 <div class="related-item"> | ||||
|                     <a href="/index/article/detail?id=${article.id}"> | ||||
|                         <div class="related-image"> | ||||
|                             <img src="${article.image}" alt="${article.title}"> | ||||
|                         </div> | ||||
|                         <div class="related-info"> | ||||
|                             <div class="related-item-title">${article.title}</div> | ||||
|                             <div class="related-item-desc">${article.desc || ''}</div> | ||||
|                         </div> | ||||
|                     </a> | ||||
|                 </div> | ||||
|             `).join(''); | ||||
|         } else { | ||||
|             relatedArticles.innerHTML = '<div class="no-related">暂无相关文章</div>'; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 页面加载完成后执行
 | ||||
|     document.addEventListener('DOMContentLoaded', function() { | ||||
|         // 获取文章ID
 | ||||
|         const articleId = new URLSearchParams(window.location.search).get('id'); | ||||
|         if (!articleId) { | ||||
|             alert('文章ID不存在'); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // 获取文章详情
 | ||||
|         fetch(`/index/article/detail?id=${articleId}`, { | ||||
|             headers: { | ||||
|                 'X-Requested-With': 'XMLHttpRequest' | ||||
|             } | ||||
|         }) | ||||
|             .then(response => { | ||||
|                 console.log('Response status:', response.status); | ||||
|                 console.log('Response headers:', response.headers); | ||||
|                 return response.json(); | ||||
|             }) | ||||
|             .then(result => { | ||||
|                 console.log('API response:', result); | ||||
|                 if (result.code === 1) { | ||||
|                     renderArticleDetail(result.data); | ||||
|                     // 更新访问次数
 | ||||
|                     updateArticleViews(articleId); | ||||
|                 } else { | ||||
|                     console.error('API error:', result.msg); | ||||
|                     alert(result.msg || '获取文章详情失败'); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(error => { | ||||
|                 console.error('获取文章详情失败:', error); | ||||
|                 console.error('Error details:', { | ||||
|                     message: error.message, | ||||
|                     stack: error.stack | ||||
|                 }); | ||||
|                 alert('获取文章详情失败,请检查网络连接或刷新页面重试'); | ||||
|             }); | ||||
| 
 | ||||
|         // 点赞功能
 | ||||
|         const likeBtn = document.querySelector('.like-btn'); | ||||
|         if (likeBtn) { | ||||
|             likeBtn.addEventListener('click', function () { | ||||
|                 const articleId = '{$article.id}'; | ||||
|             likeBtn.addEventListener('click', function() { | ||||
|                 fetch('/index/article/like?id=' + articleId, { | ||||
|                     method: 'POST' | ||||
|                 }) | ||||
|                     .then(response => response.json()) | ||||
|                     .then(data => { | ||||
|                         if (data.code === 1) { | ||||
|                             const countElement = this.querySelector('.action-count'); | ||||
|                             let count = parseInt(countElement.textContent); | ||||
|                             countElement.textContent = count + 1; | ||||
|                             this.classList.add('liked'); | ||||
|                             this.style.color = '#f57005'; | ||||
|                         } else { | ||||
|                             alert('点赞失败:' + data.msg); | ||||
|                         } | ||||
|                     }) | ||||
|                     .catch(error => { | ||||
|                         console.error('点赞请求失败:', error); | ||||
|                     }); | ||||
|                 .then(response => response.json()) | ||||
|                 .then(data => { | ||||
|                     if (data.code === 1) { | ||||
|                         const countElement = this.querySelector('.action-count'); | ||||
|                         let count = parseInt(countElement.textContent); | ||||
|                         countElement.textContent = count + 1; | ||||
|                         this.classList.add('liked'); | ||||
|                         this.style.color = '#f57005'; | ||||
|                     } else { | ||||
|                         alert('点赞失败:' + data.msg); | ||||
|                     } | ||||
|                 }) | ||||
|                 .catch(error => { | ||||
|                     console.error('点赞请求失败:', error); | ||||
|                 }); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
| @ -529,5 +586,31 @@ | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     // 更新文章访问次数
 | ||||
|     function updateArticleViews(articleId) { | ||||
|         fetch('/index/article/updateViews', { | ||||
|             method: 'POST', | ||||
|             headers: { | ||||
|                 'Content-Type': 'application/json', | ||||
|             }, | ||||
|             body: JSON.stringify({ | ||||
|                 id: articleId | ||||
|             }) | ||||
|         }) | ||||
|         .then(response => response.json()) | ||||
|         .then(result => { | ||||
|             if (result.code === 1) { | ||||
|                 // 更新成功,更新页面上的访问次数显示
 | ||||
|                 const viewsElement = document.getElementById('articleViews'); | ||||
|                 if (viewsElement) { | ||||
|                     viewsElement.textContent = result.data.views; | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|             console.error('更新访问次数失败:', error); | ||||
|         }); | ||||
|     } | ||||
| </script> | ||||
| {include file="component/foot" /} | ||||
| @ -1,19 +1,26 @@ | ||||
| <div style="display: flex;flex-direction: column;"> | ||||
|     <div class="topbar-one"> | ||||
| <div class="topbar-one"> | ||||
|         <div class="container"> | ||||
|             <div style="width: 70%;"> | ||||
|                 <ul class="list-unstyled topbar-one__info"> | ||||
|                     <li class="topbar-one__info__item"><span class="topbar-one__info__icon fas fa-phone-alt"></span><a | ||||
|                             href="tel:629-555-0129">(629) 555-0129</a></li> | ||||
|                     <li class="topbar-one__info__item"><span class="topbar-one__info__icon fas fa-envelope"></span><a | ||||
|                             href="mailto:info@example.com">info@example.com</a></li> | ||||
|                     <li class="topbar-one__info__item"> | ||||
|                         <span class="topbar-one__info__icon fas fa-phone-alt" style="margin-right: 10px;"></span> | ||||
|                         <a href="{$config['admin_phone']}">{$config['admin_phone']}</a> | ||||
|                     </li> | ||||
|                     <li class="topbar-one__info__item"> | ||||
|                         <span class="topbar-one__info__icon fas fa-envelope" style="margin-right: 10px;"></span> | ||||
|                         <a href="mailto:{$config['admin_email']}">{$config['admin_email']}</a> | ||||
|                     </li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="topbar-one__social" style="width: 30%;"> | ||||
|                 <a href="https://facebook.com"><i class="fab fa-facebook-f"></i></a> | ||||
|                 <a href="https://twitter.com"><i class="fab fa-twitter"></i></a> | ||||
|                 <a href="https://instagram.com"><i class="fab fa-instagram"></i></a> | ||||
|                 <a href="https://www.youtube.com/"><i class="fab fa-linkedin"></i></a> | ||||
|                 <a href="/index/user/login" class="mr-10"><i class="layui-icon layui-icon-username"></i> 登录</a> | ||||
|                 <a href="/index/user/register" class="mr-10"><i class="layui-icon layui-icon-user"></i> 注册</a> | ||||
|                 <a href="javascript:;" class="qrcode-trigger"><i class="layui-icon layui-icon-qrcode"></i> 公众号</a> | ||||
|                 <div class="qrcode-popup" | ||||
|                     style="display:none;position:absolute;right:54px;top:32px;background:#fff;padding:10px;box-shadow:0 0 10px rgba(0,0,0,0.1); z-index: 1000;"> | ||||
|                     <img src="{$config['admin_wechat']}" alt="公众号二维码" style="width:180px;height:180px;"> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| @ -25,15 +32,35 @@ | ||||
|             </div> | ||||
|             <div class="main-menu__nav"> | ||||
|                 <ul class="main-menu__list"> | ||||
|                     <li><a href="index.html">首页</a></li> | ||||
|                     <li><a href="about.html">关于我们</a></li> | ||||
|                     <li><a href="products.html">产品服务</a></li> | ||||
|                     <li><a href="contact.html">联系我们</a></li> | ||||
|                     <li><a href="/index.html">首页</a></li> | ||||
|                     <li><a href="/about.html">关于我们</a></li> | ||||
|                     <li><a href="/products.html">产品服务</a></li> | ||||
|                     <li><a href="/contact.html">联系我们</a></li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="main-menu__right"> | ||||
|                 <a href="#" class="main-menu__search"><i class="layui-icon layui-icon-search"></i></a> | ||||
|                 <a href="login.html" class="main-menu__login"><i class="layui-icon layui-icon-username"></i></a> | ||||
|                 <div class="layui-inline"> | ||||
|                     <div class="layui-inline" style="position: relative;"> | ||||
|                         <img src="__IMAGES__/avatar.webp" class="layui-circle" | ||||
|                             style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> | ||||
|                         <div class="user-dropdown" id="userDropdownMain"> | ||||
|                             <ul> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/profile"><i | ||||
|                                             class="layui-icon layui-icon-user"></i><span>个人中心</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/settings"><i | ||||
|                                             class="layui-icon layui-icon-set"></i><span>账号管理</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="javascript:;" class="logout-btn"><i | ||||
|                                             class="layui-icon layui-icon-logout"></i><span>退出登录</span></a> | ||||
|                                 </li> | ||||
|                             </ul> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| @ -47,58 +74,320 @@ | ||||
|         </div> | ||||
|         <div class="sticky-nav__menu"> | ||||
|             <ul> | ||||
|                 <li><a href="index.html">首页</a></li> | ||||
|                 <li><a href="about.html">关于我们</a></li> | ||||
|                 <li><a href="products.html">产品服务</a></li> | ||||
|                 <li><a href="contact.html">联系我们</a></li> | ||||
|                 <li><a href="/index.html">首页</a></li> | ||||
|                 <li><a href="/about.html">关于我们</a></li> | ||||
|                 <li><a href="/products.html">产品服务</a></li> | ||||
|                 <li><a href="/contact.html">联系我们</a></li> | ||||
|             </ul> | ||||
|         </div> | ||||
|         <div class="sticky-nav__right"> | ||||
|             <a href="#" class="main-menu__search"><i class="layui-icon layui-icon-search"></i></a> | ||||
|             <a href="login.html" class="main-menu__login"><i class="layui-icon layui-icon-username"></i></a> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="layui-inline"> | ||||
|                     <div class="layui-inline" style="position: relative;"> | ||||
|                         <img src="__IMAGES__/avatar.webp" class="layui-circle" | ||||
|                             style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||
|                         <div class="user-dropdown" id="userDropdownSticky"> | ||||
|                             <ul> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/profile"><i | ||||
|                                             class="layui-icon layui-icon-user"></i><span>个人中心</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/settings"><i | ||||
|                                             class="layui-icon layui-icon-set"></i><span>账号管理</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="javascript:;" class="logout-btn"><i | ||||
|                                             class="layui-icon layui-icon-logout"></i><span>退出登录</span></a> | ||||
|                                 </li> | ||||
|                             </ul> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <script> | ||||
|     layui.use(['carousel', 'form'], function () { | ||||
|         var carousel = layui.carousel | ||||
|             , form = layui.form; | ||||
| <style> | ||||
|     /* 用户头像样式 */ | ||||
|     #userAvatar {
 | ||||
|         width: 40px; | ||||
|         height: 40px; | ||||
|         cursor: pointer; | ||||
|         transition: all 0.3s ease; | ||||
|     } | ||||
| 
 | ||||
|         //图片轮播
 | ||||
|         carousel.render({ | ||||
|             elem: '#test10' | ||||
|             , width: '100%' | ||||
|             , height: '86vh' | ||||
|             , interval: 4000 | ||||
|     #userAvatar:hover {
 | ||||
|         transform: scale(1.05); | ||||
|         box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单容器 */ | ||||
|     .user-dropdown { | ||||
|         position: absolute; | ||||
|         top: 50px; | ||||
|         right: 0; | ||||
|         width: 160px; | ||||
|         background: #fff;
 | ||||
|         border-radius: 4px; | ||||
|         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); | ||||
|         opacity: 0; | ||||
|         visibility: hidden; | ||||
|         transform: translateY(-10px); | ||||
|         transition: all 0.3s ease; | ||||
|         z-index: 9999; | ||||
|     } | ||||
| 
 | ||||
|     .user-dropdown.show { | ||||
|         opacity: 1; | ||||
|         visibility: visible; | ||||
|         transform: translateY(0); | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单列表 */ | ||||
|     .user-dropdown ul { | ||||
|         margin: 0; | ||||
|         padding: 5px 0; | ||||
|         list-style: none; | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单项 */ | ||||
|     .user-dropdown li { | ||||
|         margin: 0; | ||||
|         padding: 0; | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单链接 */ | ||||
|     .user-dropdown li a { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         padding: 10px 15px; | ||||
|         color: #333;
 | ||||
|         text-decoration: none; | ||||
|         transition: all 0.3s ease; | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单图标 */ | ||||
|     .user-dropdown li a i { | ||||
|         margin-right: 10px; | ||||
|         font-size: 16px; | ||||
|         color: #666;
 | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单文字 */ | ||||
|     .user-dropdown li a span { | ||||
|         font-size: 14px; | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单悬停效果 */ | ||||
|     .user-dropdown li a:hover { | ||||
|         background: #f5f5f5;
 | ||||
|         color: #1E9FFF;
 | ||||
|     } | ||||
| 
 | ||||
|     .user-dropdown li a:hover i { | ||||
|         color: #1E9FFF;
 | ||||
|     } | ||||
| 
 | ||||
|     /* 分隔线 */ | ||||
|     .user-dropdown li:not(:last-child) { | ||||
|         border-bottom: 1px solid #f0f0f0;
 | ||||
|     } | ||||
| 
 | ||||
|     #userDropdownSticky a {
 | ||||
|         color: #0d6efd !important;
 | ||||
|     } | ||||
| 
 | ||||
|     /* Banner样式 */ | ||||
|     .banner-content { | ||||
|         position: relative; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         overflow: hidden; | ||||
|     } | ||||
| 
 | ||||
|     .banner-image { | ||||
|         position: absolute; | ||||
|         top: 0; | ||||
|         left: 0; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|     .banner-image img { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         object-fit: cover; | ||||
|         object-position: center; | ||||
|     } | ||||
| 
 | ||||
|     .banner-text { | ||||
|         position: absolute; | ||||
|         top: 40%; | ||||
|         left: 10%; | ||||
|         z-index: 1; | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         align-items: flex-start; | ||||
|         color: #fff;
 | ||||
|     } | ||||
| 
 | ||||
|     .banner-text a { | ||||
|         text-decoration: none; | ||||
|         margin-top: 30px; | ||||
|     } | ||||
| 
 | ||||
|     .banner-title { | ||||
|         font-size: 4em; | ||||
|         font-weight: 600; | ||||
|         margin-bottom: 10px; | ||||
|         text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); | ||||
|     } | ||||
| 
 | ||||
|     .banner-desc { | ||||
|         font-size: 2em; | ||||
|         font-weight: 400; | ||||
|         max-width: 800px; | ||||
|         text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); | ||||
|     } | ||||
| 
 | ||||
|     .banner-btn { | ||||
|         background: #fff;
 | ||||
|         color: #000;
 | ||||
|         padding: 10px 20px; | ||||
|         border-radius: 5px; | ||||
|         cursor: pointer; | ||||
|         transition: all 0.3s ease; | ||||
|     } | ||||
| 
 | ||||
|     .banner-btn:hover { | ||||
|         background: #000;
 | ||||
|         color: #fff;
 | ||||
|     } | ||||
| 
 | ||||
|     .banner-slider { | ||||
|         width: 100%; | ||||
|         height: 86vh; | ||||
|         overflow: hidden; | ||||
|         position: relative; | ||||
|     } | ||||
| 
 | ||||
|     .banner-container { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|     .banner-slide { | ||||
|         display: block; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|     .banner-slide img { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         object-fit: cover; | ||||
|         /* 关键:等比缩放并铺满 */ | ||||
|         display: block; | ||||
|     } | ||||
| 
 | ||||
|     .layui-carousel { | ||||
|         background: #f8f8f8;
 | ||||
|         margin: 0; | ||||
|         padding: 0; | ||||
|     } | ||||
| 
 | ||||
|     /* 确保轮播容器和项目的高度正确 */ | ||||
|     #test10,
 | ||||
|     #test10 [carousel-item],
 | ||||
|     #test10 [carousel-item]>* {
 | ||||
|         height: 86vh !important; | ||||
|     } | ||||
| 
 | ||||
|     #test10 [carousel-item]>* {
 | ||||
|         background: none !important; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     layui.use(['carousel', 'form', 'layer'], function () { | ||||
|         var carousel = layui.carousel, form = layui.form, layer = layui.layer, $ = layui.$; | ||||
| 
 | ||||
|         // 加载banner数据
 | ||||
|         $.ajax({ | ||||
|             url: '/index/index/bannerlist', | ||||
|             type: 'GET', | ||||
|             success: function (res) { | ||||
|                 if (res.code === 1) { | ||||
|                     var bannerHtml = ''; | ||||
|                     res.banner.forEach(function (banner) { | ||||
|                         bannerHtml += '<div>' + | ||||
|                             '<div class="banner-content">' + | ||||
|                             '<div class="banner-image">' + | ||||
|                             '<img src="' + banner.image + '" alt="' + (banner.title || '') + '">' + | ||||
|                             '</div>' + | ||||
|                             '<div class="banner-text">' + | ||||
|                             '<span class="banner-title">' + (banner.title || '') + '</span>' + | ||||
|                             '<span class="banner-desc">' + (banner.desc || '') + '</span>' + | ||||
|                             '<a href="' + (banner.url || 'javascript:;') + '" class="banner-slide">' + | ||||
|                             '<span class="banner-btn">查看详情</span>' + | ||||
|                             '</a>' + | ||||
|                             '</div>' + | ||||
|                             '</div>' + | ||||
|                             '</div>'; | ||||
|                     }); | ||||
|                     $('#test10 div[carousel-item]').html(bannerHtml); | ||||
| 
 | ||||
|                     // 图片轮播
 | ||||
|                     carousel.render({ | ||||
|                         elem: '#test10', | ||||
|                         width: '100%', | ||||
|                         height: '100vh', | ||||
|                         interval: 4000, | ||||
|                         anim: 'fade', | ||||
|                         autoplay: true, | ||||
|                         full: false, | ||||
|                         arrow: 'hover' | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         var $ = layui.$, active = { | ||||
|             set: function (othis) { | ||||
|                 var THIS = 'layui-bg-normal' | ||||
|                     , key = othis.data('key') | ||||
|                     , options = {}; | ||||
|         $(document).ready(function () { | ||||
|             // 主导航头像
 | ||||
|             $("#userAvatarMain").click(function (e) { | ||||
|                 e.stopPropagation(); | ||||
|                 $("#userDropdownMain").toggleClass("show"); | ||||
|                 $("#userDropdownSticky").removeClass("show"); // 保证只显示一个
 | ||||
|             }); | ||||
|             // 固定导航头像
 | ||||
|             $("#userAvatarSticky").click(function (e) { | ||||
|                 e.stopPropagation(); | ||||
|                 $("#userDropdownSticky").toggleClass("show"); | ||||
|                 $("#userDropdownMain").removeClass("show"); // 保证只显示一个
 | ||||
|             }); | ||||
| 
 | ||||
|                 othis.css('background-color', '#5FB878').siblings().removeAttr('style'); | ||||
|                 options[key] = othis.data('value'); | ||||
|                 ins3.reload(options); | ||||
|             } | ||||
|         }; | ||||
|             // 点击页面其他地方隐藏所有菜单
 | ||||
|             $(document).click(function (e) { | ||||
|                 if (!$(e.target).closest('.user-dropdown, #userAvatarMain, #userAvatarSticky').length) { | ||||
|                     $("#userDropdownMain, #userDropdownSticky").removeClass("show"); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|         //监听开关
 | ||||
|         form.on('switch(autoplay)', function () { | ||||
|             ins3.reload({ | ||||
|                 autoplay: this.checked | ||||
|             // 点击菜单项时隐藏菜单
 | ||||
|             $("#userDropdownMain li a, #userDropdownSticky li a").click(function () { | ||||
|                 $("#userDropdownMain, #userDropdownSticky").removeClass("show"); | ||||
|             }); | ||||
|         }); | ||||
| 
 | ||||
|         $('.demoSet').on('keyup', function () { | ||||
|             var value = this.value | ||||
|                 , options = {}; | ||||
|             if (!/^\d+$/.test(value)) return; | ||||
| 
 | ||||
|             options[this.name] = value; | ||||
|             ins3.reload(options); | ||||
|         // 退出登录
 | ||||
|         $('.logout-btn').on('click', function () { | ||||
|             layer.confirm('确定要退出登录吗?', { | ||||
|                 btn: ['确定', '取消'] | ||||
|             }, function () { | ||||
|                 window.location.href = '/index/user/logout'; | ||||
|             }); | ||||
|         }); | ||||
| 
 | ||||
|         // 监听滚动事件
 | ||||
| @ -110,5 +399,29 @@ | ||||
|                 $('.sticky-nav').fadeOut(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         // 公众号二维码
 | ||||
|         const trigger = document.querySelector('.qrcode-trigger'); | ||||
|         const popup = document.querySelector('.qrcode-popup'); | ||||
| 
 | ||||
|         // 鼠标移入显示二维码
 | ||||
|         trigger.addEventListener('mouseenter', function () { | ||||
|             popup.style.display = 'block'; | ||||
|         }); | ||||
| 
 | ||||
|         // 鼠标移出隐藏二维码
 | ||||
|         trigger.addEventListener('mouseleave', function () { | ||||
|             popup.style.display = 'none'; | ||||
|         }); | ||||
| 
 | ||||
|         // 鼠标移入二维码区域时保持显示
 | ||||
|         popup.addEventListener('mouseenter', function () { | ||||
|             popup.style.display = 'block'; | ||||
|         }); | ||||
| 
 | ||||
|         // 鼠标移出二维码区域时隐藏
 | ||||
|         popup.addEventListener('mouseleave', function () { | ||||
|             popup.style.display = 'none'; | ||||
|         }); | ||||
|     }); | ||||
| </script> | ||||
| @ -32,10 +32,10 @@ | ||||
|             </div> | ||||
|             <div class="main-menu__nav"> | ||||
|                 <ul class="main-menu__list"> | ||||
|                     <li><a href="index.html">首页</a></li> | ||||
|                     <li><a href="about.html">关于我们</a></li> | ||||
|                     <li><a href="products.html">产品服务</a></li> | ||||
|                     <li><a href="contact.html">联系我们</a></li> | ||||
|                     <li><a href="/index.html">首页</a></li> | ||||
|                     <li><a href="/about.html">关于我们</a></li> | ||||
|                     <li><a href="/products.html">产品服务</a></li> | ||||
|                     <li><a href="/contact.html">联系我们</a></li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="main-menu__right"> | ||||
| @ -81,10 +81,10 @@ | ||||
|         </div> | ||||
|         <div class="sticky-nav__menu"> | ||||
|             <ul> | ||||
|                 <li><a href="index.html">首页</a></li> | ||||
|                 <li><a href="about.html">关于我们</a></li> | ||||
|                 <li><a href="products.html">产品服务</a></li> | ||||
|                 <li><a href="contact.html">联系我们</a></li> | ||||
|                 <li><a href="/index.html">首页</a></li> | ||||
|                 <li><a href="/about.html">关于我们</a></li> | ||||
|                 <li><a href="/products.html">产品服务</a></li> | ||||
|                 <li><a href="/contact.html">联系我们</a></li> | ||||
|             </ul> | ||||
|         </div> | ||||
|         <div class="sticky-nav__right"> | ||||
|  | ||||
							
								
								
									
										540
									
								
								app/index/view/program/detail.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										540
									
								
								app/index/view/program/detail.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,540 @@ | ||||
| {include file="component/head" /} | ||||
| {include file="component/header-simple" /} | ||||
| <div class="main"> | ||||
|     <div class="location"> | ||||
|         <div class="container"> | ||||
|             <div class="location-item"> | ||||
|                 <a href="/">首页</a> | ||||
|                 <span>></span> | ||||
|                 <a href="/index/program/index" id="cateLink"></a> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="program-detail-container"> | ||||
|         <div class="program-header"> | ||||
|             <h1 class="program-title" id="programTitle"></h1> | ||||
|             <div class="program-meta"> | ||||
|                 <span class="program-author"><i class="fa fa-user"></i> <span id="programAuthor"></span></span> | ||||
|                 <span class="program-date"><i class="fa fa-calendar"></i> <span id="programDate"></span></span> | ||||
|                 <span class="program-views"><i class="fa-solid fa-eye"></i> <span id="programViews"></span> 浏览</span> | ||||
|                 <span class="program-downloads"><i class="fa-solid fa-download"></i> <span id="programDownloads"></span> 下载</span> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="program-content" id="programContent"> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="program-info"> | ||||
|             <div class="info-item"> | ||||
|                 <span class="info-label">软件大小:</span> | ||||
|                 <span id="programSize"></span> | ||||
|             </div> | ||||
|             <div class="info-item"> | ||||
|                 <span class="info-label">运行环境:</span> | ||||
|                 <span id="programEnvironment"></span> | ||||
|             </div> | ||||
|             <div class="info-item"> | ||||
|                 <span class="info-label">更新时间:</span> | ||||
|                 <span id="programUpdateTime"></span> | ||||
|             </div> | ||||
|             <div class="info-item"> | ||||
|                 <span class="info-label">软件版本:</span> | ||||
|                 <span id="programVersion"></span> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="program-actions"> | ||||
|             <div class="action-item download-btn" id="downloadBtn"> | ||||
|                 <i class="fa fa-download"></i> | ||||
|                 <span class="action-text">立即下载</span> | ||||
|             </div> | ||||
|             <div class="action-item share-btn"> | ||||
|                 <i class="fa fa-share-alt"></i> | ||||
|                 <span class="action-text">分享</span> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="program-navigation"> | ||||
|             <div class="prev-program" id="prevProgram"> | ||||
|             </div> | ||||
|             <div class="next-program" id="nextProgram"> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="related-programs"> | ||||
|             <h3 class="related-title">相关推荐</h3> | ||||
|             <div class="related-list" id="relatedPrograms"> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <!-- 返回顶部按钮 --> | ||||
| <div class="go-to-top" id="goToTop"> | ||||
|     <i class="layui-icon layui-icon-top"></i> | ||||
| </div> | ||||
| 
 | ||||
| {include file="component/footer" /} | ||||
| 
 | ||||
| <style> | ||||
|     .location { | ||||
|         max-width: 1000px; | ||||
|         margin: 30px auto; | ||||
|     } | ||||
| 
 | ||||
|     .program-detail-container { | ||||
|         max-width: 1000px; | ||||
|         margin: 30px auto; | ||||
|         padding: 50px; | ||||
|         background: #fff;
 | ||||
|         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); | ||||
|         border-radius: 8px; | ||||
|     } | ||||
| 
 | ||||
|     .program-header { | ||||
|         margin-bottom: 30px; | ||||
|         border-bottom: 1px solid #eee;
 | ||||
|         padding-bottom: 20px; | ||||
|     } | ||||
| 
 | ||||
|     .program-title { | ||||
|         font-size: 28px; | ||||
|         font-weight: 700; | ||||
|         color: #333;
 | ||||
|         margin-bottom: 15px; | ||||
|         line-height: 1.4; | ||||
|     } | ||||
| 
 | ||||
|     .program-meta { | ||||
|         display: flex; | ||||
|         flex-wrap: wrap; | ||||
|         gap: 20px; | ||||
|         color: #666;
 | ||||
|         font-size: 14px; | ||||
|     } | ||||
| 
 | ||||
|     .program-meta span { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| 
 | ||||
|     .program-meta i { | ||||
|         margin-right: 5px; | ||||
|     } | ||||
| 
 | ||||
|     .program-content { | ||||
|         line-height: 1.8; | ||||
|         color: #333;
 | ||||
|         font-size: 16px; | ||||
|         margin-bottom: 30px; | ||||
|     } | ||||
| 
 | ||||
|     .program-info { | ||||
|         background: #f8f9fa;
 | ||||
|         padding: 20px; | ||||
|         border-radius: 8px; | ||||
|         margin: 20px 0; | ||||
|     } | ||||
| 
 | ||||
|     .info-item { | ||||
|         margin-bottom: 10px; | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| 
 | ||||
|     .info-label { | ||||
|         font-weight: bold; | ||||
|         width: 100px; | ||||
|         color: #666;
 | ||||
|     } | ||||
| 
 | ||||
|     .program-actions { | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
|         gap: 40px; | ||||
|         margin: 30px 0; | ||||
|         padding: 20px 0; | ||||
|         border-top: 1px solid #eee;
 | ||||
|         border-bottom: 1px solid #eee;
 | ||||
|     } | ||||
| 
 | ||||
|     .action-item { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         align-items: center; | ||||
|         cursor: pointer; | ||||
|         padding: 15px 30px; | ||||
|         border-radius: 8px; | ||||
|         transition: all 0.3s ease; | ||||
|     } | ||||
| 
 | ||||
|     .download-btn { | ||||
|         background: #f57005;
 | ||||
|         color: #fff;
 | ||||
|     } | ||||
| 
 | ||||
|     .download-btn:hover { | ||||
|         background: #e66600;
 | ||||
|         transform: translateY(-2px); | ||||
|     } | ||||
| 
 | ||||
|     .share-btn { | ||||
|         background: #f8f9fa;
 | ||||
|         color: #666;
 | ||||
|     } | ||||
| 
 | ||||
|     .share-btn:hover { | ||||
|         background: #e9ecef;
 | ||||
|     } | ||||
| 
 | ||||
|     .action-item i { | ||||
|         font-size: 24px; | ||||
|         margin-bottom: 5px; | ||||
|     } | ||||
| 
 | ||||
|     .action-text { | ||||
|         font-size: 14px; | ||||
|     } | ||||
| 
 | ||||
|     .program-navigation { | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|         margin: 30px 0; | ||||
|     } | ||||
| 
 | ||||
|     .prev-program, | ||||
|     .next-program { | ||||
|         max-width: 45%; | ||||
|     } | ||||
| 
 | ||||
|     .prev-program a, | ||||
|     .next-program a { | ||||
|         color: #333;
 | ||||
|         text-decoration: none; | ||||
|     } | ||||
| 
 | ||||
|     .prev-program a:hover, | ||||
|     .next-program a:hover { | ||||
|         color: #f57005;
 | ||||
|     } | ||||
| 
 | ||||
|     .disabled { | ||||
|         color: #999;
 | ||||
|     } | ||||
| 
 | ||||
|     .related-programs { | ||||
|         margin: 40px 0; | ||||
|     } | ||||
| 
 | ||||
|     .related-title { | ||||
|         font-size: 20px; | ||||
|         font-weight: 600; | ||||
|         margin-bottom: 20px; | ||||
|         padding-bottom: 10px; | ||||
|         border-bottom: 1px solid #eee;
 | ||||
|     } | ||||
| 
 | ||||
|     .related-list { | ||||
|         display: grid; | ||||
|         grid-template-columns: repeat(3, 1fr); | ||||
|         gap: 20px; | ||||
|     } | ||||
| 
 | ||||
|     .related-item { | ||||
|         border-radius: 8px; | ||||
|         overflow: hidden; | ||||
|         box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||||
|         transition: transform 0.3s; | ||||
|     } | ||||
| 
 | ||||
|     .related-item:hover { | ||||
|         transform: translateY(-5px); | ||||
|     } | ||||
| 
 | ||||
|     .related-item a { | ||||
|         text-decoration: none; | ||||
|         color: inherit; | ||||
|     } | ||||
| 
 | ||||
|     .related-image img { | ||||
|         width: 100%; | ||||
|         height: 150px; | ||||
|         object-fit: cover; | ||||
|     } | ||||
| 
 | ||||
|     .related-info { | ||||
|         padding: 10px; | ||||
|     } | ||||
| 
 | ||||
|     .related-item-title { | ||||
|         font-size: 16px; | ||||
|         font-weight: 600; | ||||
|         margin-bottom: 5px; | ||||
|         color: #333;
 | ||||
|         overflow: hidden; | ||||
|         text-overflow: ellipsis; | ||||
|         white-space: nowrap; | ||||
|     } | ||||
| 
 | ||||
|     .related-item-desc { | ||||
|         font-size: 12px; | ||||
|         color: #666;
 | ||||
|         overflow: hidden; | ||||
|         text-overflow: ellipsis; | ||||
|         display: -webkit-box; | ||||
|         -webkit-line-clamp: 2; | ||||
|         -webkit-box-orient: vertical; | ||||
|     } | ||||
| 
 | ||||
|     .go-to-top { | ||||
|         position: fixed; | ||||
|         right: 30px; | ||||
|         bottom: 30px; | ||||
|         width: 40px; | ||||
|         height: 40px; | ||||
|         background: #f57005;
 | ||||
|         color: #fff;
 | ||||
|         border-radius: 50%; | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         justify-content: center; | ||||
|         cursor: pointer; | ||||
|         opacity: 0; | ||||
|         visibility: hidden; | ||||
|         transition: all 0.3s ease; | ||||
|         box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); | ||||
|         z-index: 1000; | ||||
|     } | ||||
| 
 | ||||
|     .go-to-top.show { | ||||
|         opacity: 1; | ||||
|         visibility: visible; | ||||
|     } | ||||
| 
 | ||||
|     .go-to-top:hover { | ||||
|         background: #e66600;
 | ||||
|         transform: translateY(-3px); | ||||
|     } | ||||
| 
 | ||||
|     @media (max-width: 768px) { | ||||
|         .program-title { | ||||
|             font-size: 24px; | ||||
|         } | ||||
| 
 | ||||
|         .related-list { | ||||
|             grid-template-columns: repeat(1, 1fr); | ||||
|         } | ||||
| 
 | ||||
|         .program-meta { | ||||
|             gap: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .go-to-top { | ||||
|             right: 20px; | ||||
|             bottom: 20px; | ||||
|             width: 36px; | ||||
|             height: 36px; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     .location-item a { | ||||
|         color: #000 !important;
 | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     // 格式化日期
 | ||||
|     function formatDate(timestamp) { | ||||
|         const date = new Date(timestamp * 1000); | ||||
|         return date.toLocaleDateString('zh-CN', { | ||||
|             year: 'numeric', | ||||
|             month: '2-digit', | ||||
|             day: '2-digit' | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     // 渲染程序详情
 | ||||
|     function renderProgramDetail(data) { | ||||
|         // 渲染分类链接
 | ||||
|         document.getElementById('cateLink').textContent = data.cateName; | ||||
|          | ||||
|         // 渲染程序标题
 | ||||
|         document.getElementById('programTitle').textContent = data.program.title; | ||||
|          | ||||
|         // 渲染程序元信息
 | ||||
|         document.getElementById('programAuthor').textContent = data.program.author; | ||||
|         document.getElementById('programDate').textContent = formatDate(data.program.create_time); | ||||
|         document.getElementById('programViews').textContent = data.program.views; | ||||
|         document.getElementById('programDownloads').textContent = data.program.downloads; | ||||
|          | ||||
|         // 渲染程序内容
 | ||||
|         document.getElementById('programContent').innerHTML = data.program.content; | ||||
|          | ||||
|         // 渲染程序信息
 | ||||
|         document.getElementById('programSize').textContent = data.program.size || '未知'; | ||||
|         document.getElementById('programEnvironment').textContent = data.program.environment || '通用'; | ||||
|         document.getElementById('programUpdateTime').textContent = formatDate(data.program.update_time); | ||||
|         document.getElementById('programVersion').textContent = data.program.version || '1.0.0'; | ||||
|          | ||||
|         // 渲染上一个程序
 | ||||
|         const prevProgram = document.getElementById('prevProgram'); | ||||
|         if (data.prevProgram) { | ||||
|             prevProgram.innerHTML = ` | ||||
|                 <a href="/index/program/detail?id=${data.prevProgram.id}"> | ||||
|                     <i class="fa fa-arrow-left"></i> 上一个:${data.prevProgram.title} | ||||
|                 </a> | ||||
|             `; | ||||
|         } else { | ||||
|             prevProgram.innerHTML = '<span class="disabled"><i class="fa fa-arrow-left"></i> 没有上一个了</span>'; | ||||
|         } | ||||
|          | ||||
|         // 渲染下一个程序
 | ||||
|         const nextProgram = document.getElementById('nextProgram'); | ||||
|         if (data.nextProgram) { | ||||
|             nextProgram.innerHTML = ` | ||||
|                 <a href="/index/program/detail?id=${data.nextProgram.id}"> | ||||
|                     下一个:${data.nextProgram.title} <i class="fa fa-arrow-right"></i> | ||||
|                 </a> | ||||
|             `; | ||||
|         } else { | ||||
|             nextProgram.innerHTML = '<span class="disabled">没有下一个了 <i class="fa fa-arrow-right"></i></span>'; | ||||
|         } | ||||
|          | ||||
|         // 渲染相关程序
 | ||||
|         const relatedPrograms = document.getElementById('relatedPrograms'); | ||||
|         if (data.relatedPrograms && data.relatedPrograms.length > 0) { | ||||
|             relatedPrograms.innerHTML = data.relatedPrograms.map(program => ` | ||||
|                 <div class="related-item"> | ||||
|                     <a href="/index/program/detail?id=${program.id}"> | ||||
|                         <div class="related-image"> | ||||
|                             <img src="${program.icon}" alt="${program.title}"> | ||||
|                         </div> | ||||
|                         <div class="related-info"> | ||||
|                             <div class="related-item-title">${program.title}</div> | ||||
|                             <div class="related-item-desc">${program.desc || ''}</div> | ||||
|                         </div> | ||||
|                     </a> | ||||
|                 </div> | ||||
|             `).join(''); | ||||
|         } else { | ||||
|             relatedPrograms.innerHTML = '<div class="no-related">暂无相关程序</div>'; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 页面加载完成后执行
 | ||||
|     document.addEventListener('DOMContentLoaded', function() { | ||||
|         // 获取程序ID
 | ||||
|         const programId = new URLSearchParams(window.location.search).get('id'); | ||||
|         if (!programId) { | ||||
|             alert('程序ID不存在'); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // 获取程序详情
 | ||||
|         fetch(`/index/program/detail?id=${programId}`, { | ||||
|             headers: { | ||||
|                 'X-Requested-With': 'XMLHttpRequest' | ||||
|             } | ||||
|         }) | ||||
|         .then(response => response.json()) | ||||
|         .then(result => { | ||||
|             if (result.code === 1) { | ||||
|                 renderProgramDetail(result.data); | ||||
|                 // 更新访问次数
 | ||||
|                 updateProgramViews(programId); | ||||
|             } else { | ||||
|                 alert(result.msg || '获取程序详情失败'); | ||||
|             } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|             console.error('获取程序详情失败:', error); | ||||
|             alert('获取程序详情失败,请检查网络连接或刷新页面重试'); | ||||
|         }); | ||||
| 
 | ||||
|         // 下载功能
 | ||||
|         const downloadBtn = document.getElementById('downloadBtn'); | ||||
|         if (downloadBtn) { | ||||
|             downloadBtn.addEventListener('click', function() { | ||||
|                 fetch('/index/program/download?id=' + programId, { | ||||
|                     method: 'POST', | ||||
|                     headers: { | ||||
|                         'X-Requested-With': 'XMLHttpRequest' | ||||
|                     } | ||||
|                 }) | ||||
|                 .then(response => response.json()) | ||||
|                 .then(data => { | ||||
|                     if (data.code === 1) { | ||||
|                         const downloadsElement = document.getElementById('programDownloads'); | ||||
|                         let downloads = parseInt(downloadsElement.textContent); | ||||
|                         downloadsElement.textContent = downloads + 1; | ||||
|                          | ||||
|                         // 获取当前域名
 | ||||
|                         const domain = window.location.origin; | ||||
|                         // 拼接完整的下载地址
 | ||||
|                         if (data.data && data.data.fileurl) { | ||||
|                             const downloadUrl = domain + data.data.fileurl; | ||||
|                             window.location.href = downloadUrl; | ||||
|                         } else { | ||||
|                             alert('下载地址不存在'); | ||||
|                         } | ||||
|                     } else { | ||||
|                         alert('下载失败:' + data.msg); | ||||
|                     } | ||||
|                 }) | ||||
|                 .catch(error => { | ||||
|                     console.error('下载请求失败:', error); | ||||
|                     alert('下载请求失败,请稍后重试'); | ||||
|                 }); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // 返回顶部功能
 | ||||
|         const goToTop = document.getElementById('goToTop'); | ||||
|          | ||||
|         // 监听滚动事件
 | ||||
|         window.addEventListener('scroll', function() { | ||||
|             if (window.pageYOffset > 300) { | ||||
|                 goToTop.classList.add('show'); | ||||
|             } else { | ||||
|                 goToTop.classList.remove('show'); | ||||
|             } | ||||
|         }); | ||||
|          | ||||
|         // 点击返回顶部
 | ||||
|         goToTop.addEventListener('click', function() { | ||||
|             window.scrollTo({ | ||||
|                 top: 0, | ||||
|                 behavior: 'smooth' | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     // 更新程序访问次数
 | ||||
|     function updateProgramViews(programId) { | ||||
|         fetch('/index/program/updateViews', { | ||||
|             method: 'POST', | ||||
|             headers: { | ||||
|                 'Content-Type': 'application/json', | ||||
|                 'X-Requested-With': 'XMLHttpRequest' | ||||
|             }, | ||||
|             body: JSON.stringify({ | ||||
|                 id: programId | ||||
|             }) | ||||
|         }) | ||||
|         .then(response => response.json()) | ||||
|         .then(result => { | ||||
|             if (result.code === 1) { | ||||
|                 // 更新成功,更新页面上的访问次数显示
 | ||||
|                 const viewsElement = document.getElementById('programViews'); | ||||
|                 if (viewsElement) { | ||||
|                     viewsElement.textContent = result.data.views; | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|             console.error('更新访问次数失败:', error); | ||||
|         }); | ||||
|     } | ||||
| </script> | ||||
| {include file="component/foot" /} | ||||
| @ -1,37 +1,76 @@ | ||||
| <?php | ||||
| // +----------------------------------------------------------------------
 | ||||
| // | 路由设置
 | ||||
| // | ThinkPHP [ WE CAN DO IT JUST THINK ]
 | ||||
| // +----------------------------------------------------------------------
 | ||||
| // | Copyright (c) 2006-2019 http://thinkphp.cn All rights reserved.
 | ||||
| // +----------------------------------------------------------------------
 | ||||
| // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
 | ||||
| // +----------------------------------------------------------------------
 | ||||
| // | Author: liu21st <liu21st@gmail.com>
 | ||||
| // +----------------------------------------------------------------------
 | ||||
| 
 | ||||
| return [ | ||||
| 	// pathinfo分隔符
 | ||||
| 	'pathinfo_depr'         => '/', | ||||
| 	// URL伪静态后缀
 | ||||
| 	'url_html_suffix'       => '', | ||||
| 	// URL普通方式参数 用于自动生成
 | ||||
| 	'url_common_param'      => true, | ||||
| 	'url_common_param'       => true, | ||||
| 	// URL参数方式 0 按名称成对解析 1 按顺序解析
 | ||||
| 	'url_param_type'         => 0, | ||||
| 	// 是否开启路由延迟解析
 | ||||
| 	'url_lazy_route'        => false, | ||||
| 	'lazy_route'            => false, | ||||
| 	// 是否强制使用路由
 | ||||
| 	'url_route_must'        => false, | ||||
| 	// 合并路由规则
 | ||||
| 	'route_rule_merge'      => false, | ||||
| 	// 路由是否完全匹配
 | ||||
| 	'route_complete_match'  => true, | ||||
| 	// 访问控制器层名称
 | ||||
| 	'controller_layer'      => 'controller', | ||||
| 	// 空控制器名
 | ||||
| 	'empty_controller'      => 'Error', | ||||
| 	// 是否使用控制器后缀
 | ||||
| 	'controller_suffix'     => false, | ||||
| 	'route_complete_match'  => false, | ||||
| 	// 使用注解路由
 | ||||
| 	'route_annotation'      => false, | ||||
| 	// 默认的路由变量规则
 | ||||
| 	'default_route_pattern' => '[\w\.]+', | ||||
| 	// URL中的控制器访问命名空间(自动多应用模式有效)
 | ||||
| 	'controller_namespace'  => '', | ||||
| 	// 是否自动转换URL中的控制器和操作名
 | ||||
| 	'url_convert'           => true, | ||||
| 	// 默认的访问控制器层
 | ||||
| 	'controller_layer'      => 'controller', | ||||
| 	// 表单请求类型伪装变量
 | ||||
| 	'var_method'           => '_method', | ||||
| 	// 表单ajax伪装变量
 | ||||
| 	'var_ajax'             => '_ajax', | ||||
| 	// 表单pjax伪装变量
 | ||||
| 	'var_pjax'             => '_pjax', | ||||
| 	// 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
 | ||||
| 	'request_cache_key'     => false, | ||||
| 	'request_cache'         => false, | ||||
| 	// 请求缓存有效期
 | ||||
| 	'request_cache_expire'  => null, | ||||
| 	// 全局请求缓存排除规则
 | ||||
| 	'request_cache_except'  => [], | ||||
| 	// 是否开启路由缓存
 | ||||
| 	'route_check_cache'     => false, | ||||
| 	// 路由缓存的Key自定义设置(闭包),默认为当前URL和请求类型的md5
 | ||||
| 	'route_check_cache_key' => '', | ||||
| 	// 路由缓存类型及参数
 | ||||
| 	'route_cache_option'    => [], | ||||
| 	// 默认跳转页面对应的模板文件
 | ||||
| 	'dispatch_success_tmpl' => app()->getThinkPath() . 'tpl/dispatch_jump.tpl', | ||||
| 	'dispatch_error_tmpl'   => app()->getThinkPath() . 'tpl/dispatch_jump.tpl', | ||||
| 	// 异常页面的模板文件
 | ||||
| 	'exception_tmpl'        => app()->getThinkPath() . 'tpl/think_exception.tpl', | ||||
| 	// 错误显示信息,非调试模式有效
 | ||||
| 	'error_message'         => '页面错误!请稍后再试~', | ||||
| 	// 显示错误信息
 | ||||
| 	'show_error_msg'        => false, | ||||
| 	// 异常处理handle类 留空使用 \think\exception\Handle
 | ||||
| 	'exception_handle'      => '', | ||||
| 	// 是否开启URL后缀
 | ||||
| 	'url_html_suffix'       => false, | ||||
| 	// 空控制器名
 | ||||
| 	'empty_controller'      => 'Error', | ||||
| 	// 是否使用控制器后缀
 | ||||
| 	'controller_suffix'     => false, | ||||
| 	// 访问控制器层名称
 | ||||
| 	'controller_layer'      => 'controller', | ||||
| 	// 默认控制器名
 | ||||
| 	'default_controller'    => 'Index', | ||||
| 	// 默认操作名
 | ||||
|  | ||||
| @ -17,6 +17,65 @@ a:hover { | ||||
|   color: #fff !important; | ||||
| } | ||||
| 
 | ||||
| /* 代码块样式 */ | ||||
| pre { | ||||
|   background-color: #f8f9fa; | ||||
|   border-radius: 6px; | ||||
|   padding: 16px; | ||||
|   margin: 20px 0; | ||||
|   overflow: auto; | ||||
|   font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace; | ||||
|   font-size: 14px; | ||||
|   line-height: 1.6; | ||||
|   color: #333; | ||||
|   border-left: 4px solid #0d6efd; | ||||
|   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||||
| } | ||||
| 
 | ||||
| pre code { | ||||
|   background-color: transparent; | ||||
|   padding: 0; | ||||
|   font-size: inherit; | ||||
|   color: inherit; | ||||
|   white-space: pre; | ||||
|   word-break: normal; | ||||
| } | ||||
| 
 | ||||
| /* 代码块响应式样式 */ | ||||
| @media (max-width: 768px) { | ||||
|   pre { | ||||
|     padding: 12px; | ||||
|     font-size: 13px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* 代码高亮样式 */ | ||||
| .hljs-keyword, | ||||
| .hljs-selector-tag { | ||||
|   color: #d73a49; | ||||
| } | ||||
| 
 | ||||
| .hljs-string, | ||||
| .hljs-attr { | ||||
|   color: #032f62; | ||||
| } | ||||
| 
 | ||||
| .hljs-number, | ||||
| .hljs-literal { | ||||
|   color: #005cc5; | ||||
| } | ||||
| 
 | ||||
| .hljs-comment { | ||||
|   color: #6a737d; | ||||
|   font-style: italic; | ||||
| } | ||||
| 
 | ||||
| .hljs-function, | ||||
| .hljs-title { | ||||
|   color: #6f42c1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* 字体大小类 */ | ||||
| .f20, | ||||
| .f-20 { | ||||
| @ -164,6 +223,8 @@ a:hover { | ||||
|   position: relative; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| .main-menu__list { | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|  | ||||
							
								
								
									
										1036
									
								
								runtime/index/temp/402d23cdf323169a38fb26d3649b6ad5.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1036
									
								
								runtime/index/temp/402d23cdf323169a38fb26d3649b6ad5.php
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,4 +1,4 @@ | ||||
| <?php /*a:4:{s:49:"E:\Demo\PHP\yunzer\app\index\view\index\index.php";i:1746890051;s:54:"E:\Demo\PHP\yunzer\app\index\view\component\header.php";i:1747402501;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\main.php";i:1747410946;s:54:"E:\Demo\PHP\yunzer\app\index\view\component\footer.php";i:1747402501;}*/ ?>
 | ||||
| <?php /*a:4:{s:49:"E:\Demo\PHP\yunzer\app\index\view\index\index.php";i:1746890051;s:54:"E:\Demo\PHP\yunzer\app\index\view\component\header.php";i:1747416219;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\main.php";i:1747410946;s:54:"E:\Demo\PHP\yunzer\app\index\view\component\footer.php";i:1747402501;}*/ ?>
 | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| 
 | ||||
| @ -50,10 +50,10 @@ | ||||
|             </div> | ||||
|             <div class="main-menu__nav"> | ||||
|                 <ul class="main-menu__list"> | ||||
|                     <li><a href="index.html">首页</a></li> | ||||
|                     <li><a href="about.html">关于我们</a></li> | ||||
|                     <li><a href="products.html">产品服务</a></li> | ||||
|                     <li><a href="contact.html">联系我们</a></li> | ||||
|                     <li><a href="/index.html">首页</a></li> | ||||
|                     <li><a href="/about.html">关于我们</a></li> | ||||
|                     <li><a href="/products.html">产品服务</a></li> | ||||
|                     <li><a href="/contact.html">联系我们</a></li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="main-menu__right"> | ||||
| @ -99,10 +99,10 @@ | ||||
|         </div> | ||||
|         <div class="sticky-nav__menu"> | ||||
|             <ul> | ||||
|                 <li><a href="index.html">首页</a></li> | ||||
|                 <li><a href="about.html">关于我们</a></li> | ||||
|                 <li><a href="products.html">产品服务</a></li> | ||||
|                 <li><a href="contact.html">联系我们</a></li> | ||||
|                 <li><a href="/index.html">首页</a></li> | ||||
|                 <li><a href="/about.html">关于我们</a></li> | ||||
|                 <li><a href="/products.html">产品服务</a></li> | ||||
|                 <li><a href="/contact.html">联系我们</a></li> | ||||
|             </ul> | ||||
|         </div> | ||||
|         <div class="sticky-nav__right"> | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <?php /*a:5:{s:52:"E:\Demo\PHP\yunzer\app\index\view\article\detail.php";i:1746808591;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\head.php";i:1746890051;s:61:"E:\Demo\PHP\yunzer\app\index\view\component\header-simple.php";i:1746808182;s:54:"E:\Demo\PHP\yunzer\app\index\view\component\footer.php";i:1746796639;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\foot.php";i:1746808046;}*/ ?>
 | ||||
| <?php /*a:5:{s:52:"E:\Demo\PHP\yunzer\app\index\view\article\detail.php";i:1747415479;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\head.php";i:1746890051;s:61:"E:\Demo\PHP\yunzer\app\index\view\component\header-simple.php";i:1747415782;s:54:"E:\Demo\PHP\yunzer\app\index\view\component\footer.php";i:1747402501;s:52:"E:\Demo\PHP\yunzer\app\index\view\component\foot.php";i:1746808046;}*/ ?>
 | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| 
 | ||||
| @ -17,21 +17,28 @@ | ||||
| 
 | ||||
| <body> | ||||
| <div style="display: flex;flex-direction: column;"> | ||||
|     <div class="topbar-one"> | ||||
| <div class="topbar-one"> | ||||
|         <div class="container"> | ||||
|             <div style="width: 70%;"> | ||||
|                 <ul class="list-unstyled topbar-one__info"> | ||||
|                     <li class="topbar-one__info__item"><span class="topbar-one__info__icon fas fa-phone-alt"></span><a | ||||
|                             href="tel:629-555-0129">(629) 555-0129</a></li> | ||||
|                     <li class="topbar-one__info__item"><span class="topbar-one__info__icon fas fa-envelope"></span><a | ||||
|                             href="mailto:info@example.com">info@example.com</a></li> | ||||
|                     <li class="topbar-one__info__item"> | ||||
|                         <span class="topbar-one__info__icon fas fa-phone-alt" style="margin-right: 10px;"></span> | ||||
|                         <a href="<?php echo htmlentities((string) $config['admin_phone']); ?>"><?php echo htmlentities((string) $config['admin_phone']); ?></a>
 | ||||
|                     </li> | ||||
|                     <li class="topbar-one__info__item"> | ||||
|                         <span class="topbar-one__info__icon fas fa-envelope" style="margin-right: 10px;"></span> | ||||
|                         <a href="mailto:<?php echo htmlentities((string) $config['admin_email']); ?>"><?php echo htmlentities((string) $config['admin_email']); ?></a>
 | ||||
|                     </li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="topbar-one__social" style="width: 30%;"> | ||||
|                 <a href="https://facebook.com"><i class="fab fa-facebook-f"></i></a> | ||||
|                 <a href="https://twitter.com"><i class="fab fa-twitter"></i></a> | ||||
|                 <a href="https://instagram.com"><i class="fab fa-instagram"></i></a> | ||||
|                 <a href="https://www.youtube.com/"><i class="fab fa-linkedin"></i></a> | ||||
|                 <a href="/index/user/login" class="mr-10"><i class="layui-icon layui-icon-username"></i> 登录</a> | ||||
|                 <a href="/index/user/register" class="mr-10"><i class="layui-icon layui-icon-user"></i> 注册</a> | ||||
|                 <a href="javascript:;" class="qrcode-trigger"><i class="layui-icon layui-icon-qrcode"></i> 公众号</a> | ||||
|                 <div class="qrcode-popup" | ||||
|                     style="display:none;position:absolute;right:54px;top:32px;background:#fff;padding:10px;box-shadow:0 0 10px rgba(0,0,0,0.1); z-index: 1000;"> | ||||
|                     <img src="<?php echo htmlentities((string) $config['admin_wechat']); ?>" alt="公众号二维码" style="width:180px;height:180px;"> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| @ -43,15 +50,35 @@ | ||||
|             </div> | ||||
|             <div class="main-menu__nav"> | ||||
|                 <ul class="main-menu__list"> | ||||
|                     <li><a href="index.html">首页</a></li> | ||||
|                     <li><a href="about.html">关于我们</a></li> | ||||
|                     <li><a href="products.html">产品服务</a></li> | ||||
|                     <li><a href="contact.html">联系我们</a></li> | ||||
|                     <li><a href="/index.html">首页</a></li> | ||||
|                     <li><a href="/about.html">关于我们</a></li> | ||||
|                     <li><a href="/products.html">产品服务</a></li> | ||||
|                     <li><a href="/contact.html">联系我们</a></li> | ||||
|                 </ul> | ||||
|             </div> | ||||
|             <div class="main-menu__right"> | ||||
|                 <a href="#" class="main-menu__search"><i class="layui-icon layui-icon-search"></i></a> | ||||
|                 <a href="login.html" class="main-menu__login"><i class="layui-icon layui-icon-username"></i></a> | ||||
|                 <div class="layui-inline"> | ||||
|                     <div class="layui-inline" style="position: relative;"> | ||||
|                         <img src="/static/images/avatar.webp" class="layui-circle" | ||||
|                             style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarMain"> | ||||
|                         <div class="user-dropdown" id="userDropdownMain"> | ||||
|                             <ul> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/profile"><i | ||||
|                                             class="layui-icon layui-icon-user"></i><span>个人中心</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/settings"><i | ||||
|                                             class="layui-icon layui-icon-set"></i><span>账号管理</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="javascript:;" class="logout-btn"><i | ||||
|                                             class="layui-icon layui-icon-logout"></i><span>退出登录</span></a> | ||||
|                                 </li> | ||||
|                             </ul> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| @ -65,58 +92,320 @@ | ||||
|         </div> | ||||
|         <div class="sticky-nav__menu"> | ||||
|             <ul> | ||||
|                 <li><a href="index.html">首页</a></li> | ||||
|                 <li><a href="about.html">关于我们</a></li> | ||||
|                 <li><a href="products.html">产品服务</a></li> | ||||
|                 <li><a href="contact.html">联系我们</a></li> | ||||
|                 <li><a href="/index.html">首页</a></li> | ||||
|                 <li><a href="/about.html">关于我们</a></li> | ||||
|                 <li><a href="/products.html">产品服务</a></li> | ||||
|                 <li><a href="/contact.html">联系我们</a></li> | ||||
|             </ul> | ||||
|         </div> | ||||
|         <div class="sticky-nav__right"> | ||||
|             <a href="#" class="main-menu__search"><i class="layui-icon layui-icon-search"></i></a> | ||||
|             <a href="login.html" class="main-menu__login"><i class="layui-icon layui-icon-username"></i></a> | ||||
|             <div class="main-menu__right"> | ||||
|                 <div class="layui-inline"> | ||||
|                     <div class="layui-inline" style="position: relative;"> | ||||
|                         <img src="/static/images/avatar.webp" class="layui-circle" | ||||
|                             style="width: 40px; height: 40px; cursor: pointer;" id="userAvatarSticky"> | ||||
|                         <div class="user-dropdown" id="userDropdownSticky"> | ||||
|                             <ul> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/profile"><i | ||||
|                                             class="layui-icon layui-icon-user"></i><span>个人中心</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="/index/user/settings"><i | ||||
|                                             class="layui-icon layui-icon-set"></i><span>账号管理</span></a> | ||||
|                                 </li> | ||||
|                                 <li> | ||||
|                                     <a href="javascript:;" class="logout-btn"><i | ||||
|                                             class="layui-icon layui-icon-logout"></i><span>退出登录</span></a> | ||||
|                                 </li> | ||||
|                             </ul> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| <script> | ||||
|     layui.use(['carousel', 'form'], function () { | ||||
|         var carousel = layui.carousel | ||||
|             , form = layui.form; | ||||
| <style> | ||||
|     /* 用户头像样式 */ | ||||
|     #userAvatar {
 | ||||
|         width: 40px; | ||||
|         height: 40px; | ||||
|         cursor: pointer; | ||||
|         transition: all 0.3s ease; | ||||
|     } | ||||
| 
 | ||||
|         //图片轮播
 | ||||
|         carousel.render({ | ||||
|             elem: '#test10' | ||||
|             , width: '100%' | ||||
|             , height: '86vh' | ||||
|             , interval: 4000 | ||||
|     #userAvatar:hover {
 | ||||
|         transform: scale(1.05); | ||||
|         box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单容器 */ | ||||
|     .user-dropdown { | ||||
|         position: absolute; | ||||
|         top: 50px; | ||||
|         right: 0; | ||||
|         width: 160px; | ||||
|         background: #fff;
 | ||||
|         border-radius: 4px; | ||||
|         box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); | ||||
|         opacity: 0; | ||||
|         visibility: hidden; | ||||
|         transform: translateY(-10px); | ||||
|         transition: all 0.3s ease; | ||||
|         z-index: 9999; | ||||
|     } | ||||
| 
 | ||||
|     .user-dropdown.show { | ||||
|         opacity: 1; | ||||
|         visibility: visible; | ||||
|         transform: translateY(0); | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单列表 */ | ||||
|     .user-dropdown ul { | ||||
|         margin: 0; | ||||
|         padding: 5px 0; | ||||
|         list-style: none; | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单项 */ | ||||
|     .user-dropdown li { | ||||
|         margin: 0; | ||||
|         padding: 0; | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单链接 */ | ||||
|     .user-dropdown li a { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         padding: 10px 15px; | ||||
|         color: #333;
 | ||||
|         text-decoration: none; | ||||
|         transition: all 0.3s ease; | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单图标 */ | ||||
|     .user-dropdown li a i { | ||||
|         margin-right: 10px; | ||||
|         font-size: 16px; | ||||
|         color: #666;
 | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单文字 */ | ||||
|     .user-dropdown li a span { | ||||
|         font-size: 14px; | ||||
|     } | ||||
| 
 | ||||
|     /* 下拉菜单悬停效果 */ | ||||
|     .user-dropdown li a:hover { | ||||
|         background: #f5f5f5;
 | ||||
|         color: #1E9FFF;
 | ||||
|     } | ||||
| 
 | ||||
|     .user-dropdown li a:hover i { | ||||
|         color: #1E9FFF;
 | ||||
|     } | ||||
| 
 | ||||
|     /* 分隔线 */ | ||||
|     .user-dropdown li:not(:last-child) { | ||||
|         border-bottom: 1px solid #f0f0f0;
 | ||||
|     } | ||||
| 
 | ||||
|     #userDropdownSticky a {
 | ||||
|         color: #0d6efd !important;
 | ||||
|     } | ||||
| 
 | ||||
|     /* Banner样式 */ | ||||
|     .banner-content { | ||||
|         position: relative; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         overflow: hidden; | ||||
|     } | ||||
| 
 | ||||
|     .banner-image { | ||||
|         position: absolute; | ||||
|         top: 0; | ||||
|         left: 0; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|     .banner-image img { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         object-fit: cover; | ||||
|         object-position: center; | ||||
|     } | ||||
| 
 | ||||
|     .banner-text { | ||||
|         position: absolute; | ||||
|         top: 40%; | ||||
|         left: 10%; | ||||
|         z-index: 1; | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         align-items: flex-start; | ||||
|         color: #fff;
 | ||||
|     } | ||||
| 
 | ||||
|     .banner-text a { | ||||
|         text-decoration: none; | ||||
|         margin-top: 30px; | ||||
|     } | ||||
| 
 | ||||
|     .banner-title { | ||||
|         font-size: 4em; | ||||
|         font-weight: 600; | ||||
|         margin-bottom: 10px; | ||||
|         text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); | ||||
|     } | ||||
| 
 | ||||
|     .banner-desc { | ||||
|         font-size: 2em; | ||||
|         font-weight: 400; | ||||
|         max-width: 800px; | ||||
|         text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); | ||||
|     } | ||||
| 
 | ||||
|     .banner-btn { | ||||
|         background: #fff;
 | ||||
|         color: #000;
 | ||||
|         padding: 10px 20px; | ||||
|         border-radius: 5px; | ||||
|         cursor: pointer; | ||||
|         transition: all 0.3s ease; | ||||
|     } | ||||
| 
 | ||||
|     .banner-btn:hover { | ||||
|         background: #000;
 | ||||
|         color: #fff;
 | ||||
|     } | ||||
| 
 | ||||
|     .banner-slider { | ||||
|         width: 100%; | ||||
|         height: 86vh; | ||||
|         overflow: hidden; | ||||
|         position: relative; | ||||
|     } | ||||
| 
 | ||||
|     .banner-container { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|     .banner-slide { | ||||
|         display: block; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|     .banner-slide img { | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         object-fit: cover; | ||||
|         /* 关键:等比缩放并铺满 */ | ||||
|         display: block; | ||||
|     } | ||||
| 
 | ||||
|     .layui-carousel { | ||||
|         background: #f8f8f8;
 | ||||
|         margin: 0; | ||||
|         padding: 0; | ||||
|     } | ||||
| 
 | ||||
|     /* 确保轮播容器和项目的高度正确 */ | ||||
|     #test10,
 | ||||
|     #test10 [carousel-item],
 | ||||
|     #test10 [carousel-item]>* {
 | ||||
|         height: 86vh !important; | ||||
|     } | ||||
| 
 | ||||
|     #test10 [carousel-item]>* {
 | ||||
|         background: none !important; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     layui.use(['carousel', 'form', 'layer'], function () { | ||||
|         var carousel = layui.carousel, form = layui.form, layer = layui.layer, $ = layui.$; | ||||
| 
 | ||||
|         // 加载banner数据
 | ||||
|         $.ajax({ | ||||
|             url: '/index/index/bannerlist', | ||||
|             type: 'GET', | ||||
|             success: function (res) { | ||||
|                 if (res.code === 1) { | ||||
|                     var bannerHtml = ''; | ||||
|                     res.banner.forEach(function (banner) { | ||||
|                         bannerHtml += '<div>' + | ||||
|                             '<div class="banner-content">' + | ||||
|                             '<div class="banner-image">' + | ||||
|                             '<img src="' + banner.image + '" alt="' + (banner.title || '') + '">' + | ||||
|                             '</div>' + | ||||
|                             '<div class="banner-text">' + | ||||
|                             '<span class="banner-title">' + (banner.title || '') + '</span>' + | ||||
|                             '<span class="banner-desc">' + (banner.desc || '') + '</span>' + | ||||
|                             '<a href="' + (banner.url || 'javascript:;') + '" class="banner-slide">' + | ||||
|                             '<span class="banner-btn">查看详情</span>' + | ||||
|                             '</a>' + | ||||
|                             '</div>' + | ||||
|                             '</div>' + | ||||
|                             '</div>'; | ||||
|                     }); | ||||
|                     $('#test10 div[carousel-item]').html(bannerHtml); | ||||
| 
 | ||||
|                     // 图片轮播
 | ||||
|                     carousel.render({ | ||||
|                         elem: '#test10', | ||||
|                         width: '100%', | ||||
|                         height: '100vh', | ||||
|                         interval: 4000, | ||||
|                         anim: 'fade', | ||||
|                         autoplay: true, | ||||
|                         full: false, | ||||
|                         arrow: 'hover' | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         var $ = layui.$, active = { | ||||
|             set: function (othis) { | ||||
|                 var THIS = 'layui-bg-normal' | ||||
|                     , key = othis.data('key') | ||||
|                     , options = {}; | ||||
|         $(document).ready(function () { | ||||
|             // 主导航头像
 | ||||
|             $("#userAvatarMain").click(function (e) { | ||||
|                 e.stopPropagation(); | ||||
|                 $("#userDropdownMain").toggleClass("show"); | ||||
|                 $("#userDropdownSticky").removeClass("show"); // 保证只显示一个
 | ||||
|             }); | ||||
|             // 固定导航头像
 | ||||
|             $("#userAvatarSticky").click(function (e) { | ||||
|                 e.stopPropagation(); | ||||
|                 $("#userDropdownSticky").toggleClass("show"); | ||||
|                 $("#userDropdownMain").removeClass("show"); // 保证只显示一个
 | ||||
|             }); | ||||
| 
 | ||||
|                 othis.css('background-color', '#5FB878').siblings().removeAttr('style'); | ||||
|                 options[key] = othis.data('value'); | ||||
|                 ins3.reload(options); | ||||
|             } | ||||
|         }; | ||||
|             // 点击页面其他地方隐藏所有菜单
 | ||||
|             $(document).click(function (e) { | ||||
|                 if (!$(e.target).closest('.user-dropdown, #userAvatarMain, #userAvatarSticky').length) { | ||||
|                     $("#userDropdownMain, #userDropdownSticky").removeClass("show"); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|         //监听开关
 | ||||
|         form.on('switch(autoplay)', function () { | ||||
|             ins3.reload({ | ||||
|                 autoplay: this.checked | ||||
|             // 点击菜单项时隐藏菜单
 | ||||
|             $("#userDropdownMain li a, #userDropdownSticky li a").click(function () { | ||||
|                 $("#userDropdownMain, #userDropdownSticky").removeClass("show"); | ||||
|             }); | ||||
|         }); | ||||
| 
 | ||||
|         $('.demoSet').on('keyup', function () { | ||||
|             var value = this.value | ||||
|                 , options = {}; | ||||
|             if (!/^\d+$/.test(value)) return; | ||||
| 
 | ||||
|             options[this.name] = value; | ||||
|             ins3.reload(options); | ||||
|         // 退出登录
 | ||||
|         $('.logout-btn').on('click', function () { | ||||
|             layer.confirm('确定要退出登录吗?', { | ||||
|                 btn: ['确定', '取消'] | ||||
|             }, function () { | ||||
|                 window.location.href = '/index/user/logout'; | ||||
|             }); | ||||
|         }); | ||||
| 
 | ||||
|         // 监听滚动事件
 | ||||
| @ -128,49 +417,66 @@ | ||||
|                 $('.sticky-nav').fadeOut(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         // 公众号二维码
 | ||||
|         const trigger = document.querySelector('.qrcode-trigger'); | ||||
|         const popup = document.querySelector('.qrcode-popup'); | ||||
| 
 | ||||
|         // 鼠标移入显示二维码
 | ||||
|         trigger.addEventListener('mouseenter', function () { | ||||
|             popup.style.display = 'block'; | ||||
|         }); | ||||
| 
 | ||||
|         // 鼠标移出隐藏二维码
 | ||||
|         trigger.addEventListener('mouseleave', function () { | ||||
|             popup.style.display = 'none'; | ||||
|         }); | ||||
| 
 | ||||
|         // 鼠标移入二维码区域时保持显示
 | ||||
|         popup.addEventListener('mouseenter', function () { | ||||
|             popup.style.display = 'block'; | ||||
|         }); | ||||
| 
 | ||||
|         // 鼠标移出二维码区域时隐藏
 | ||||
|         popup.addEventListener('mouseleave', function () { | ||||
|             popup.style.display = 'none'; | ||||
|         }); | ||||
|     }); | ||||
| </script> | ||||
| <div class="main"> | ||||
|     <div class="location"> | ||||
|         <div class="container"> | ||||
|             <div class="location-item"> | ||||
|                 <a href="<?php echo url('index/index/index'); ?>">首页</a> | ||||
|                 <a href="/">首页</a> | ||||
|                 <span>></span> | ||||
|                 <a href="<?php echo url('index/article/index'); ?>">技术文章</a> | ||||
|                 <a href="/index/article/index" id="cateLink"></a> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
| 
 | ||||
|     <div class="article-detail-container"> | ||||
|         <div class="article-header"> | ||||
|             <h1 class="article-title"><?php echo htmlentities((string) $article['title']); ?></h1>
 | ||||
|             <h1 class="article-title" id="articleTitle"></h1> | ||||
|             <div class="article-meta"> | ||||
|                 <span class="article-author"><i class="fa fa-user"></i> <?php echo htmlentities((string) $article['author']); ?></span>
 | ||||
|                 <span class="article-date"><i class="fa fa-calendar"></i> <?php echo htmlentities((string) date('Y-m-d H:i',!is_numeric($article['create_time'])? strtotime($article['create_time']) : $article['create_time'])); ?></span>
 | ||||
|                 <span class="article-category"><i class="fa fa-folder"></i> <?php echo htmlentities((string) $cateName); ?></span>
 | ||||
|                 <span class="article-views"><i class="fa fa-eye"></i> <?php echo htmlentities((string) $article['views']); ?> 阅读</span>
 | ||||
|                 <span class="article-author"><i class="fa fa-user"></i> <span id="articleAuthor"></span></span> | ||||
|                 <span class="article-date"><i class="fa fa-calendar"></i> <span id="articleDate"></span></span> | ||||
|                 <span class="article-views"><i class="fa-solid fa-eye"></i> <span id="articleViews"></span> 阅读</span> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="article-content"> | ||||
|             <?php echo $article['content']; ?>
 | ||||
|         <div class="article-content" id="articleContent"> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="article-tags"> | ||||
|             <span class="tag-label">标签:</span> | ||||
|             <?php if(!empty($article['tags'])): foreach($article['tags'] as $tag): ?>
 | ||||
|             <span class="tag-item"><?php echo htmlentities((string) $tag); ?></span>
 | ||||
|             <?php endforeach; else: ?>
 | ||||
|             <span class="no-tags">暂无标签</span> | ||||
|             <?php endif; ?>
 | ||||
|             <div id="articleTags"></div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="article-actions"> | ||||
|             <div class="action-item like-btn"> | ||||
|                 <i class="fa fa-thumbs-up"></i> | ||||
|                 <span class="action-text">点赞</span> | ||||
|                 <span class="action-count"><?php echo htmlentities((string) (isset($article['likes']) && ($article['likes'] !== '')?$article['likes']:0)); ?></span>
 | ||||
|                 <span class="action-count" id="articleLikes">0</span> | ||||
|             </div> | ||||
|             <div class="action-item share-btn"> | ||||
|                 <i class="fa fa-share-alt"></i> | ||||
| @ -179,73 +485,17 @@ | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="article-navigation"> | ||||
|             <div class="prev-article"> | ||||
|                 <?php if(!empty($prevArticle)): ?>
 | ||||
|                 <a href="<?php echo url('index/article/index', ['id' => $prevArticle['id']]); ?>"> | ||||
|                     <i class="fa fa-arrow-left"></i> 上一篇:<?php echo htmlentities((string) $prevArticle['title']); ?>
 | ||||
|                 </a> | ||||
|                 <?php else: ?>
 | ||||
|                 <span class="disabled"><i class="fa fa-arrow-left"></i> 没有上一篇了</span> | ||||
|                 <?php endif; ?>
 | ||||
|             <div class="prev-article" id="prevArticle"> | ||||
|             </div> | ||||
|             <div class="next-article"> | ||||
|                 <?php if(!empty($nextArticle)): ?>
 | ||||
|                 <a href="<?php echo url('index/article/index', ['id' => $nextArticle['id']]); ?>"> | ||||
|                     下一篇:<?php echo htmlentities((string) $nextArticle['title']); ?> <i class="fa fa-arrow-right"></i>
 | ||||
|                 </a> | ||||
|                 <?php else: ?>
 | ||||
|                 <span class="disabled">没有下一篇了 <i class="fa fa-arrow-right"></i></span> | ||||
|                 <?php endif; ?>
 | ||||
|             <div class="next-article" id="nextArticle"> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="related-articles"> | ||||
|             <h3 class="related-title">相关推荐</h3> | ||||
|             <div class="related-list"> | ||||
|                 <?php if(!empty($relatedArticles)): foreach($relatedArticles as $related): ?>
 | ||||
|                 <div class="related-item"> | ||||
|                     <a href="<?php echo url('index/article/index', ['id' => $related['id']]); ?>"> | ||||
|                         <div class="related-image"> | ||||
|                             <img src="<?php echo htmlentities((string) $related['image']); ?>" alt="<?php echo htmlentities((string) $related['title']); ?>"> | ||||
|                         </div> | ||||
|                         <div class="related-info"> | ||||
|                             <div class="related-item-title"><?php echo htmlentities((string) $related['title']); ?></div>
 | ||||
|                             <div class="related-item-desc"><?php echo htmlentities((string) $related['desc']); ?></div>
 | ||||
|                         </div> | ||||
|                     </a> | ||||
|                 </div> | ||||
|                 <?php endforeach; else: ?>
 | ||||
|                 <div class="no-related">暂无相关文章</div> | ||||
|                 <?php endif; ?>
 | ||||
|             <div class="related-list" id="relatedArticles"> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- <div class="article-comments"> | ||||
|         <h3 class="comments-title">评论区</h3> | ||||
|         <div class="comment-form"> | ||||
|             <textarea placeholder="请输入您的评论..." class="comment-textarea"></textarea> | ||||
|             <button class="comment-submit">发表评论</button> | ||||
|         </div> | ||||
|         <div class="comment-list"> | ||||
|             <?php if(!empty($comments)): foreach($comments as $comment): ?>
 | ||||
|                     <div class="comment-item"> | ||||
|                         <div class="comment-avatar"> | ||||
|                             <img src="<?php echo htmlentities((string) (isset($comment['avatar']) && ($comment['avatar'] !== '')?$comment['avatar']:'/static/images/default-avatar.png')); ?>" alt="用户头像"> | ||||
|                         </div> | ||||
|                         <div class="comment-content"> | ||||
|                             <div class="comment-user"><?php echo htmlentities((string) $comment['username']); ?></div>
 | ||||
|                             <div class="comment-text"><?php echo htmlentities((string) $comment['content']); ?></div>
 | ||||
|                             <div class="comment-footer"> | ||||
|                                 <span class="comment-time"><?php echo htmlentities((string) date('Y-m-d H:i',!is_numeric($comment['create_time'])? strtotime($comment['create_time']) : $comment['create_time'])); ?></span>
 | ||||
|                                 <span class="comment-reply">回复</span> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 <?php endforeach; else: ?>
 | ||||
|                 <div class="no-comments">暂无评论,快来抢沙发吧!</div> | ||||
|             <?php endif; ?>
 | ||||
|         </div> | ||||
|     </div> --> | ||||
|     </div> | ||||
| </div> | ||||
| 
 | ||||
| @ -259,7 +509,7 @@ | ||||
|         <div class="row" style="width: 100%;"> | ||||
|             <div class="row-main"> | ||||
|                 <div class="mr-20"> | ||||
|                     <img src="/static/images/logo-l-w.png" alt="" height="70"> | ||||
|                     <img src="<?php echo htmlentities((string) $config['logo']); ?>" alt="" height="70"> | ||||
|                     <p class="text-white-50 my-4 f18" style="width: 400px;">美天智能科技,这里是介绍!</p> | ||||
|                 </div> | ||||
|                 <div style="display: flex; justify-content: space-between;width: 100%;margin-right: 200px;"> | ||||
| @ -291,7 +541,7 @@ | ||||
| 
 | ||||
|                 <div> | ||||
|                     <div class="text-center"> | ||||
|                         <img src="/static/images/code.png" alt="微信二维码" class="img-fluid" style="max-width: 150px;"> | ||||
|                         <img src="<?php echo htmlentities((string) $config['admin_wechat']); ?>" alt="微信二维码" class="img-fluid" style="max-width: 150px;"> | ||||
|                         <p class="text-white-50 mt-2">微信公众号</p> | ||||
|                     </div> | ||||
|                 </div> | ||||
| @ -654,33 +904,159 @@ | ||||
|             height: 36px; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     .location-item a { | ||||
|         color: #000 !important;
 | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <script> | ||||
|     document.addEventListener('DOMContentLoaded', function () { | ||||
|     // 格式化日期
 | ||||
|     function formatDate(timestamp) { | ||||
|         const date = new Date(timestamp * 1000); | ||||
|         return date.toLocaleDateString('zh-CN', { | ||||
|             year: 'numeric', | ||||
|             month: '2-digit', | ||||
|             day: '2-digit' | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     // 渲染文章详情
 | ||||
|     function renderArticleDetail(data) { | ||||
|         // 渲染分类链接
 | ||||
|         document.getElementById('cateLink').textContent = data.cateName; | ||||
|          | ||||
|         // 渲染文章标题
 | ||||
|         document.getElementById('articleTitle').textContent = data.article.title; | ||||
|          | ||||
|         // 渲染文章元信息
 | ||||
|         document.getElementById('articleAuthor').textContent = data.article.author; | ||||
|         document.getElementById('articleDate').textContent = formatDate(data.article.create_time); | ||||
|         document.getElementById('articleViews').textContent = data.article.views; | ||||
|          | ||||
|         // 渲染文章内容
 | ||||
|         document.getElementById('articleContent').innerHTML = data.article.content; | ||||
|          | ||||
|         // 渲染标签
 | ||||
|         const tagsContainer = document.getElementById('articleTags'); | ||||
|         if (data.article.tags && data.article.tags.length > 0) { | ||||
|             tagsContainer.innerHTML = data.article.tags.map(tag =>  | ||||
|                 `<span class="tag-item">${tag}</span>` | ||||
|             ).join(''); | ||||
|         } else { | ||||
|             tagsContainer.innerHTML = '<span class="no-tags">暂无标签</span>'; | ||||
|         } | ||||
|          | ||||
|         // 渲染点赞数
 | ||||
|         document.getElementById('articleLikes').textContent = data.article.likes || 0; | ||||
|          | ||||
|         // 渲染上一篇
 | ||||
|         const prevArticle = document.getElementById('prevArticle'); | ||||
|         if (data.prevArticle) { | ||||
|             prevArticle.innerHTML = ` | ||||
|                 <a href="/index/article/detail?id=${data.prevArticle.id}"> | ||||
|                     <i class="fa fa-arrow-left"></i> 上一篇:${data.prevArticle.title} | ||||
|                 </a> | ||||
|             `; | ||||
|         } else { | ||||
|             prevArticle.innerHTML = '<span class="disabled"><i class="fa fa-arrow-left"></i> 没有上一篇了</span>'; | ||||
|         } | ||||
|          | ||||
|         // 渲染下一篇
 | ||||
|         const nextArticle = document.getElementById('nextArticle'); | ||||
|         if (data.nextArticle) { | ||||
|             nextArticle.innerHTML = ` | ||||
|                 <a href="/index/article/detail?id=${data.nextArticle.id}"> | ||||
|                     下一篇:${data.nextArticle.title} <i class="fa fa-arrow-right"></i> | ||||
|                 </a> | ||||
|             `; | ||||
|         } else { | ||||
|             nextArticle.innerHTML = '<span class="disabled">没有下一篇了 <i class="fa fa-arrow-right"></i></span>'; | ||||
|         } | ||||
|          | ||||
|         // 渲染相关文章
 | ||||
|         const relatedArticles = document.getElementById('relatedArticles'); | ||||
|         if (data.relatedArticles && data.relatedArticles.length > 0) { | ||||
|             relatedArticles.innerHTML = data.relatedArticles.map(article => ` | ||||
|                 <div class="related-item"> | ||||
|                     <a href="/index/article/detail?id=${article.id}"> | ||||
|                         <div class="related-image"> | ||||
|                             <img src="${article.image}" alt="${article.title}"> | ||||
|                         </div> | ||||
|                         <div class="related-info"> | ||||
|                             <div class="related-item-title">${article.title}</div> | ||||
|                             <div class="related-item-desc">${article.desc || ''}</div> | ||||
|                         </div> | ||||
|                     </a> | ||||
|                 </div> | ||||
|             `).join(''); | ||||
|         } else { | ||||
|             relatedArticles.innerHTML = '<div class="no-related">暂无相关文章</div>'; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 页面加载完成后执行
 | ||||
|     document.addEventListener('DOMContentLoaded', function() { | ||||
|         // 获取文章ID
 | ||||
|         const articleId = new URLSearchParams(window.location.search).get('id'); | ||||
|         if (!articleId) { | ||||
|             alert('文章ID不存在'); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // 获取文章详情
 | ||||
|         fetch(`/index/article/detail?id=${articleId}`, { | ||||
|             headers: { | ||||
|                 'X-Requested-With': 'XMLHttpRequest' | ||||
|             } | ||||
|         }) | ||||
|             .then(response => { | ||||
|                 console.log('Response status:', response.status); | ||||
|                 console.log('Response headers:', response.headers); | ||||
|                 return response.json(); | ||||
|             }) | ||||
|             .then(result => { | ||||
|                 console.log('API response:', result); | ||||
|                 if (result.code === 1) { | ||||
|                     renderArticleDetail(result.data); | ||||
|                     // 更新访问次数
 | ||||
|                     updateArticleViews(articleId); | ||||
|                 } else { | ||||
|                     console.error('API error:', result.msg); | ||||
|                     alert(result.msg || '获取文章详情失败'); | ||||
|                 } | ||||
|             }) | ||||
|             .catch(error => { | ||||
|                 console.error('获取文章详情失败:', error); | ||||
|                 console.error('Error details:', { | ||||
|                     message: error.message, | ||||
|                     stack: error.stack | ||||
|                 }); | ||||
|                 alert('获取文章详情失败,请检查网络连接或刷新页面重试'); | ||||
|             }); | ||||
| 
 | ||||
|         // 点赞功能
 | ||||
|         const likeBtn = document.querySelector('.like-btn'); | ||||
|         if (likeBtn) { | ||||
|             likeBtn.addEventListener('click', function () { | ||||
|                 const articleId = '<?php echo htmlentities((string) $article['id']); ?>'; | ||||
|             likeBtn.addEventListener('click', function() { | ||||
|                 fetch('/index/article/like?id=' + articleId, { | ||||
|                     method: 'POST' | ||||
|                 }) | ||||
|                     .then(response => response.json()) | ||||
|                     .then(data => { | ||||
|                         if (data.code === 1) { | ||||
|                             const countElement = this.querySelector('.action-count'); | ||||
|                             let count = parseInt(countElement.textContent); | ||||
|                             countElement.textContent = count + 1; | ||||
|                             this.classList.add('liked'); | ||||
|                             this.style.color = '#f57005'; | ||||
|                         } else { | ||||
|                             alert('点赞失败:' + data.msg); | ||||
|                         } | ||||
|                     }) | ||||
|                     .catch(error => { | ||||
|                         console.error('点赞请求失败:', error); | ||||
|                     }); | ||||
|                 .then(response => response.json()) | ||||
|                 .then(data => { | ||||
|                     if (data.code === 1) { | ||||
|                         const countElement = this.querySelector('.action-count'); | ||||
|                         let count = parseInt(countElement.textContent); | ||||
|                         countElement.textContent = count + 1; | ||||
|                         this.classList.add('liked'); | ||||
|                         this.style.color = '#f57005'; | ||||
|                     } else { | ||||
|                         alert('点赞失败:' + data.msg); | ||||
|                     } | ||||
|                 }) | ||||
|                 .catch(error => { | ||||
|                     console.error('点赞请求失败:', error); | ||||
|                 }); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
| @ -704,6 +1080,32 @@ | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     // 更新文章访问次数
 | ||||
|     function updateArticleViews(articleId) { | ||||
|         fetch('/index/article/updateViews', { | ||||
|             method: 'POST', | ||||
|             headers: { | ||||
|                 'Content-Type': 'application/json', | ||||
|             }, | ||||
|             body: JSON.stringify({ | ||||
|                 id: articleId | ||||
|             }) | ||||
|         }) | ||||
|         .then(response => response.json()) | ||||
|         .then(result => { | ||||
|             if (result.code === 1) { | ||||
|                 // 更新成功,更新页面上的访问次数显示
 | ||||
|                 const viewsElement = document.getElementById('articleViews'); | ||||
|                 if (viewsElement) { | ||||
|                     viewsElement.textContent = result.data.views; | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|         .catch(error => { | ||||
|             console.error('更新访问次数失败:', error); | ||||
|         }); | ||||
|     } | ||||
| </script> | ||||
| </body> | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 云泽网
						云泽网