first commit
This commit is contained in:
@@ -0,0 +1,712 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
<div class="main">
|
||||
<div class="location">
|
||||
<div class="container">
|
||||
<div class="location-item">
|
||||
<a href="/">首页</a>
|
||||
<span>></span>
|
||||
<a href="/index/articles/index">{$cateName}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body-container">
|
||||
<div class="article-detail-container">
|
||||
<div class="article-header">
|
||||
<h1 class="article-title">{$article.title}</h1>
|
||||
{if $article.is_trans eq 1 && $article.transurl}
|
||||
<div class="trans">转载至:<span class="trans-url" data-url="{$article.transurl}">{$article.transurl}</span>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="article-meta">
|
||||
<span class="article-author"><i class="fa fa-user"></i> <span>{$article.author}</span></span>
|
||||
<span class="article-date"><i class="fa fa-calendar"></i>
|
||||
<span>{$article.create_time|date="Y-m-d"}</span></span>
|
||||
<span class="article-views"><i class="fa-solid fa-eye"></i> <span>{$article.views}</span> 阅读</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="article-content">
|
||||
{$article.content|raw}
|
||||
</div>
|
||||
|
||||
<div class="disclaimers">
|
||||
<div class="disclaimer-item">
|
||||
<div class="disclaimer-title">免责声明:</div>
|
||||
<div class="disclaimer-content">
|
||||
<?php echo $config['disclaimers'] ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="article-tags">
|
||||
<span class="tag-label">标签:</span>
|
||||
<div>
|
||||
{if $article.tags}
|
||||
{volist name="article.tags|explode=',',','" id="tag"}
|
||||
<span class="tag-item">{$tag}</span>
|
||||
{/volist}
|
||||
{else}
|
||||
<span class="no-tags">暂无标签</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="article-actions">
|
||||
<div class="action-item like-btn" data-id="{$article.id}">
|
||||
<i class="fa fa-thumbs-up"></i>
|
||||
<span class="action-text">点赞</span>
|
||||
<span class="action-count">{$article.likes}</span>
|
||||
</div>
|
||||
<div class="action-item share-btn">
|
||||
<i class="fa fa-share-alt"></i>
|
||||
<span class="action-text">分享</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="article-navigation">
|
||||
<div class="prev-article">
|
||||
{if $prevArticle}
|
||||
<a href="/index/articles/detail?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>
|
||||
<div class="next-article">
|
||||
{if $nextArticle}
|
||||
<a href="/index/articles/detail?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>
|
||||
</div>
|
||||
|
||||
<div class="related-articles">
|
||||
<h3 class="related-title">相关推荐</h3>
|
||||
<div class="related-list">
|
||||
{volist name="relatedArticles" id="related"}
|
||||
<div class="related-item">
|
||||
<a href="/index/articles/detail?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>
|
||||
</a>
|
||||
</div>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="article-detail-right">
|
||||
<div class="aboutauthor">
|
||||
<div class="aboutauthor-title">关于作者</div>
|
||||
<div class="aboutauthor-main">
|
||||
<div class="aboutauthor-main-top">
|
||||
<div class="aboutauthor-avatar">
|
||||
<img src="{$authorInfo.avatar}" alt="作者头像">
|
||||
</div>
|
||||
<div class="aboutauthor-info">
|
||||
<div class="author-name">{$authorInfo.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aboutauthor-main-middle">
|
||||
<div class="author-stats">
|
||||
|
||||
<div class="author-stats-item">
|
||||
<h6>资源</h6>
|
||||
<span class="count">{$authorInfo.resource_count}</span>
|
||||
</div>
|
||||
<div class="author-stats-item">
|
||||
<h6>文章</h6>
|
||||
<span class="count">{$authorInfo.article_count}</span>
|
||||
</div>
|
||||
<div class="author-stats-item">
|
||||
<h6>粉丝</h6>
|
||||
<span class="count">
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aboutauthor-btn">
|
||||
<button class="follow-btn">
|
||||
<i class="fa fa-user-plus"></i> 关注他
|
||||
</button>
|
||||
<button class="message-btn">
|
||||
<i class="fa fa-envelope"></i> 发私信
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 返回顶部按钮 -->
|
||||
<div class="go-to-top">
|
||||
<i class="layui-icon-up"></i>
|
||||
</div>
|
||||
|
||||
{include file="component/footer" /}
|
||||
|
||||
<script>
|
||||
// 更新访问次数
|
||||
async function updateArticleViews(articleId) {
|
||||
try {
|
||||
await fetch('/index/articles/updateViews', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: articleId })
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新访问次数失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后执行
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const articleId = '{$article.id}';
|
||||
|
||||
// 更新访问次数
|
||||
updateArticleViews(articleId);
|
||||
|
||||
// 点赞功能
|
||||
document.querySelector('.like-btn').addEventListener('click', async function () {
|
||||
try {
|
||||
const response = await fetch('/index/articles/like?id=' + articleId, {
|
||||
method: 'POST',
|
||||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.code === 1) {
|
||||
const countElement = this.querySelector('.action-count');
|
||||
countElement.textContent = parseInt(countElement.textContent) + 1;
|
||||
this.classList.add('liked');
|
||||
this.querySelector('i').style.color = '#f57005';
|
||||
layer.msg('点赞成功', { icon: 1 });
|
||||
} else {
|
||||
layer.msg(result.msg, { icon: 2 });
|
||||
}
|
||||
} catch (error) {
|
||||
layer.msg('点赞失败,请稍后重试', { icon: 2 });
|
||||
}
|
||||
});
|
||||
|
||||
// 分享功能
|
||||
document.querySelector('.share-btn').addEventListener('click', function () {
|
||||
const url = window.location.href;
|
||||
navigator.clipboard.writeText(url).then(() => {
|
||||
layer.msg('链接已复制到剪贴板', { icon: 1 });
|
||||
}).catch(() => {
|
||||
layer.msg('复制失败,请手动复制', { icon: 2 });
|
||||
});
|
||||
});
|
||||
|
||||
// 转载链接点击
|
||||
document.querySelector('.trans-url')?.addEventListener('click', function () {
|
||||
const url = this.dataset.url;
|
||||
if (url) {
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
});
|
||||
|
||||
// 返回顶部
|
||||
const goToTop = document.querySelector('.go-to-top');
|
||||
window.addEventListener('scroll', function () {
|
||||
if (window.scrollY > 300) {
|
||||
goToTop.classList.add('show');
|
||||
} else {
|
||||
goToTop.classList.remove('show');
|
||||
}
|
||||
});
|
||||
|
||||
goToTop.addEventListener('click', function () {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.location {
|
||||
max-width: 1200px;
|
||||
margin: 30px auto;
|
||||
}
|
||||
|
||||
.main .body-container {
|
||||
display: flex;
|
||||
max-width: 1200px;
|
||||
margin: 30px auto;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.article-detail-container {
|
||||
padding: 50px;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor {
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-title {
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-main .aboutauthor-main-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 20px !important;
|
||||
padding: 20px 0;
|
||||
border-bottom: 1px solid #efefef;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-main .aboutauthor-main-top .aboutauthor-avatar {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-main .aboutauthor-main-top .aboutauthor-info .author-name {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-main .aboutauthor-main-top .aboutauthor-avatar img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
margin: 0px;
|
||||
min-width: 0px;
|
||||
max-width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-main .aboutauthor-main-middle {
|
||||
/* margin-left: 20px; */
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-main .aboutauthor-main-middle .author-stats {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-main .aboutauthor-main-middle .author-stats .author-stats-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-main .aboutauthor-main-middle .author-stats .author-stats-item .count {
|
||||
/* font-size: 30px; */
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-btn {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-btn .follow-btn {
|
||||
background-color: #0081ff;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.main .body-container .article-detail-right .aboutauthor-btn .message-btn {
|
||||
color: #0081ff;
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
|
||||
.article-header {
|
||||
margin-bottom: 30px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.article-title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.article-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.article-meta span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.article-meta i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.article-content {
|
||||
line-height: 1.8;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
margin-bottom: 30px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.article-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 15px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.article-tags {
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tag-label {
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.tag-item {
|
||||
background: #f2f2f2;
|
||||
padding: 4px 10px;
|
||||
border-radius: 15px;
|
||||
font-size: 12px;
|
||||
margin-right: 8px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.article-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;
|
||||
}
|
||||
|
||||
.action-item i {
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.action-count {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.article-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.prev-article,
|
||||
.next-article {
|
||||
max-width: 45%;
|
||||
}
|
||||
|
||||
.prev-article a,
|
||||
.next-article a {
|
||||
color: #333 !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.prev-article a:hover,
|
||||
.next-article a:hover {
|
||||
color: #f57005 !important;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.related-articles {
|
||||
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;
|
||||
}
|
||||
|
||||
.article-comments {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.comments-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.comment-form {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.comment-textarea {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
resize: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.comment-submit {
|
||||
background: #f57005;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.comment-item {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.comment-avatar img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.comment-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.comment-user {
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.comment-text {
|
||||
line-height: 1.6;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.comment-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.comment-reply {
|
||||
cursor: pointer;
|
||||
color: #f57005;
|
||||
}
|
||||
|
||||
.no-comments,
|
||||
.no-related,
|
||||
.no-tags {
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.article-title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.related-list {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
|
||||
.article-meta {
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 返回顶部按钮样式 */
|
||||
.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);
|
||||
}
|
||||
|
||||
.go-to-top i {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.go-to-top {
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.location-item a {
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.disclaimers {
|
||||
color: #b1b1b1;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.disclaimer-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.disclaimer-content {
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.disclaimer-content p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
{include file="component/foot" /}
|
||||
@@ -0,0 +1,562 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
|
||||
<!-- 简约现代文章中心 -->
|
||||
<div class="modern-articles-page">
|
||||
<!-- 简约标题区 -->
|
||||
<div class="modern-header">
|
||||
<div class="container">
|
||||
<h1 class="modern-title">文章中心</h1>
|
||||
<p class="modern-subtitle">探索知识与洞见</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区 -->
|
||||
<div class="container">
|
||||
<div class="modern-layout">
|
||||
<!-- 侧边分类导航 -->
|
||||
<aside class="modern-sidebar">
|
||||
<div class="sidebar-card">
|
||||
<h3 class="sidebar-title">
|
||||
<i class="layui-icon layui-icon-list"></i>
|
||||
<span>分类导航</span>
|
||||
</h3>
|
||||
<ul class="category-menu">
|
||||
{volist name="cate.subCategories" id="subCategory"}
|
||||
<li class="menu-item {$cate.id == $subCategory.id ? 'active' : ''}"
|
||||
data-cateid="{$subCategory.id}">
|
||||
<span>{$subCategory.name}</span>
|
||||
<i class="layui-icon layui-icon-right"></i>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 文章内容区 -->
|
||||
<main class="modern-main">
|
||||
<!-- 文章列表 -->
|
||||
<div class="article-grid" id="articleList">
|
||||
{volist name="cate.subCategories" id="subCategory"}
|
||||
{if $cate.id == $subCategory.id}
|
||||
{if !empty($subCategory.list)}
|
||||
{volist name="subCategory.list" id="article"}
|
||||
<article class="article-card">
|
||||
<div class="card-image">
|
||||
<img src="{$article.image}" alt="{$article.title}">
|
||||
<div class="image-overlay"></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="meta-info">
|
||||
<!-- <span class="category-tag">${article.category_name || '未分类'}</span> -->
|
||||
<time class="publish-date">{:date('Y-m-d', $article['create_time'])}</time>
|
||||
</div>
|
||||
|
||||
<a href="/index/articles/detail?id=${article.id}">
|
||||
<h3 class="article-title">${article.title}</h3>
|
||||
</a>
|
||||
<div class="card-footer">
|
||||
<div class="stats">
|
||||
<span class="views"><i class="layui-icon layui-icon-eye"></i> ${article.views ||
|
||||
0}</span>
|
||||
<span class="likes"><i class="layui-icon layui-icon-praise"></i> ${article.likes ||
|
||||
0}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/volist}
|
||||
{else}
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
</div>
|
||||
<h4>暂无文章</h4>
|
||||
<p>当前分类下没有找到相关文章</p>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/volist}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="modern-pagination" id="pagination"></div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['laypage', 'jquery'], function () {
|
||||
var laypage = layui.laypage;
|
||||
var $ = layui.jquery;
|
||||
|
||||
// 分类切换
|
||||
$('.menu-item').on('click', function () {
|
||||
var cateid = $(this).data('cateid');
|
||||
var $menuItems = $('.menu-item');
|
||||
|
||||
// 更新选中状态
|
||||
$menuItems.removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
// 加载文章
|
||||
loadArticles(cateid, 1);
|
||||
});
|
||||
|
||||
// 页面加载完成后,自动触发第一个分类的点击事件
|
||||
$(document).ready(function () {
|
||||
var $firstMenuItem = $('.menu-item').first();
|
||||
if ($firstMenuItem.length > 0) {
|
||||
$firstMenuItem.click();
|
||||
}
|
||||
});
|
||||
|
||||
// 加载文章函数
|
||||
function loadArticles(cateid, page) {
|
||||
$.ajax({
|
||||
url: '/index/articles/list',
|
||||
type: 'POST',
|
||||
data: {
|
||||
cate: cateid,
|
||||
page: page
|
||||
},
|
||||
beforeSend: function () {
|
||||
$('#articleList').html('<div class="loading-state"><i class="layui-icon layui-icon-loading"></i>加载中...</div>');
|
||||
},
|
||||
success: function (res) {
|
||||
if (res.code === 1) {
|
||||
var html = '';
|
||||
if (res.data.articles && res.data.articles.length > 0) {
|
||||
res.data.articles.forEach(function (article) {
|
||||
html += `<article class="article-card">
|
||||
<div class="card-image">
|
||||
<img src="${article.image}" alt="${article.title}">
|
||||
<div class="image-overlay"></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="meta-info">
|
||||
|
||||
</div>
|
||||
<a href="/index/articles/detail?id=${article.id}" class="read-more">
|
||||
<h3 class="article-title">${article.title}</h3>
|
||||
</a>
|
||||
<div class="card-footer">
|
||||
<div class="stats">
|
||||
<span class="views"><i class="layui-icon layui-icon-eye"></i> ${article.views || 0}</span>
|
||||
<span class="likes"><i class="layui-icon layui-icon-praise"></i> ${article.likes || 0}</span>
|
||||
</div>
|
||||
<div class="times">
|
||||
<time class="publish-date">${article.create_time ? new Date(article.create_time * 1000).toLocaleDateString() : ''}</time>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>`;
|
||||
});
|
||||
} else {
|
||||
html = `<div class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
</div>
|
||||
<h4>暂无文章</h4>
|
||||
<p>当前分类下没有找到相关文章</p>
|
||||
</div>`;
|
||||
}
|
||||
$('#articleList').html(html);
|
||||
|
||||
// 渲染分页
|
||||
laypage.render({
|
||||
elem: 'pagination',
|
||||
count: res.data.total || 0,
|
||||
limit: res.data.per_page || 12,
|
||||
curr: res.data.current_page || 1,
|
||||
theme: '#1E9FFF',
|
||||
layout: ['prev', 'page', 'next'],
|
||||
jump: function (obj, first) {
|
||||
if (!first) {
|
||||
loadArticles(cateid, obj.curr);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{include file="component/footer" /}
|
||||
|
||||
<style>
|
||||
/* 基础样式重置 */
|
||||
.modern-articles-page {
|
||||
font-family: 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
background-color: #f9fafc;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
/* 标题区样式 */
|
||||
.modern-header {
|
||||
background: linear-gradient(135deg, #1E9FFF 0%, #0d8aff 100%);
|
||||
color: white;
|
||||
padding: 80px 0 60px;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 300;
|
||||
margin-bottom: 15px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 300;
|
||||
opacity: 0.9;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 布局结构 */
|
||||
.modern-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 260px 1fr;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
/* 侧边栏样式 */
|
||||
.modern-sidebar {
|
||||
position: sticky;
|
||||
top: 30px;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.sidebar-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.03);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #555;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.sidebar-title i {
|
||||
margin-right: 10px;
|
||||
font-size: 1.2rem;
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.category-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background-color: #f8fafd;
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.menu-item.active {
|
||||
background-color: #f0f7ff;
|
||||
border-left-color: #1E9FFF;
|
||||
color: #1E9FFF;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.menu-item i {
|
||||
font-size: 0.9rem;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.menu-item.active i,
|
||||
.menu-item:hover i {
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
/* 主内容区样式 */
|
||||
.modern-main {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 文章网格布局 */
|
||||
.article-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 25px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
/* 文章卡片样式 */
|
||||
.article-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.03);
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.article-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.card-image {
|
||||
height: 135px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.image-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.3), transparent);
|
||||
}
|
||||
|
||||
.article-card:hover .card-image img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 20px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.card-content .read-more h3:hover {
|
||||
color: #1E9FFF !important;
|
||||
transition: all ease .5s;
|
||||
font-weight:700;
|
||||
}
|
||||
|
||||
.meta-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
/* margin-bottom: 12px; */
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.category-tag {
|
||||
background: #f0f7ff;
|
||||
color: #1E9FFF;
|
||||
padding: 3px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.article-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
margin: 0 0 10px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.article-excerpt {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
margin: 0 0 20px;
|
||||
flex: 1;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.stats {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.times,
|
||||
.stats {
|
||||
font-size: 0.85rem;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.stats i {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.read-more {
|
||||
color: #1E9FFF;
|
||||
font-size: 0.9rem;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.read-more:hover {
|
||||
color: #0d8aff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 分页样式 */
|
||||
.modern-pagination {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.layui-laypage a,
|
||||
.layui-laypage span {
|
||||
border-radius: 4px !important;
|
||||
margin: 0 3px !important;
|
||||
}
|
||||
|
||||
.layui-laypage a {
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
.layui-laypage .layui-laypage-curr .layui-laypage-em {
|
||||
background-color: #1E9FFF !important;
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.empty-state {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 3rem;
|
||||
color: #ddd;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.empty-icon i {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.empty-state h4 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
color: #999;
|
||||
font-size: 0.95rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-state {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.loading-state i {
|
||||
font-size: 1.5rem;
|
||||
margin-right: 10px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 992px) {
|
||||
.modern-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.modern-sidebar {
|
||||
position: static;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.article-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.modern-header {
|
||||
padding: 60px 0 40px;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.article-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
{include file="component/foot" /}
|
||||
@@ -0,0 +1,76 @@
|
||||
<div class="container py-5">
|
||||
<div class="row g-4">
|
||||
<!-- 左侧分类列表 -->
|
||||
<div class="col-lg-3">
|
||||
<div class="category-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<i class="layui-icon layui-icon-app"></i>
|
||||
<span>文章分类</span>
|
||||
</div>
|
||||
<div class="category-list">
|
||||
{volist name="categories" id="cate"}
|
||||
<div class="category-item {$category.id == $cate.id ? 'active' : ''}" data-cateid="{$cate.id}">{$cate.name}</div>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧文章列表 -->
|
||||
<div class="col-lg-9">
|
||||
{if $category}
|
||||
<div class="category-header mb-4">
|
||||
<h2 class="category-title">{$category.name}</h2>
|
||||
<p class="category-desc">{$category.desc|default=''}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="article-list">
|
||||
{volist name="articles" id="article"}
|
||||
<div class="article-item">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-4">
|
||||
<div class="article-image">
|
||||
<img src="{$article.image|default='/static/images/default.jpg'}" alt="{$article.title}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="article-content">
|
||||
<h3 class="article-title">
|
||||
<a href="/index/articles/detail?id={$article.id}">{$article.title}</a>
|
||||
</h3>
|
||||
<p class="article-desc">{$article.desc|default=''}</p>
|
||||
<div class="article-meta">
|
||||
<div class="article-stats">
|
||||
<span><i class="layui-icon layui-icon-eye"></i> {$article.views|default=0}</span>
|
||||
<span><i class="layui-icon layui-icon-praise"></i> {$article.likes|default=0}</span>
|
||||
<span><i class="layui-icon layui-icon-date"></i> {$article.create_time|date="Y-m-d"}</span>
|
||||
</div>
|
||||
<a href="/index/articles/detail?id={$article.id}" class="btn-detail">查看详情</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="mt-5">
|
||||
{$articles|raw}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['layer'], function () {
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
|
||||
// 分类切换
|
||||
$('.category-item').on('click', function() {
|
||||
var cateid = $(this).data('cateid');
|
||||
window.location.href = '/index/articles/list?cate=' + cateid;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>错误提示</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" href="/static/layui/css/layui.css">
|
||||
<style>
|
||||
.error-container {
|
||||
text-align: center;
|
||||
padding: 50px 20px;
|
||||
}
|
||||
.error-icon {
|
||||
font-size: 48px;
|
||||
color: #FF5722;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.error-message {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.back-btn {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="error-container">
|
||||
<div class="error-icon">
|
||||
<i class="layui-icon layui-icon-face-cry"></i>
|
||||
</div>
|
||||
<div class="error-message">
|
||||
<?php echo $msg; ?>
|
||||
</div>
|
||||
<div class="back-btn">
|
||||
<a href="javascript:history.back();" class="layui-btn layui-btn-primary">返回上一页</a>
|
||||
<a href="/" class="layui-btn">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/layui/layui.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="main-header">
|
||||
<!-- Banner轮播 -->
|
||||
<div class="layui-carousel" id="test10" lay-filter="test10">
|
||||
<div carousel-item="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,344 @@
|
||||
<script src="__LAYUI__/layui.js" charset="utf-8"></script>
|
||||
<script src="__JS__/bootstrap.bundle.js"></script>
|
||||
<script charset="UTF-8" id="LA_COLLECT" src="//www.yunzer.cn/plugins/js-sdk-pro.min.js"></script>
|
||||
<script>LA.init({ id: "KoyzaWWEcLvPzkQn", ck: "KoyzaWWEcLvPzkQn", autoTrack: true, prefix: 'event' })</script>
|
||||
<script src="__JS__/banner.js"></script>
|
||||
|
||||
<script>
|
||||
// 在页面加载时立即执行
|
||||
(function () {
|
||||
// 检查是否已经刷新过
|
||||
if (sessionStorage.getItem('has_refreshed') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查localStorage中是否有用户账号
|
||||
var userAccount = localStorage.getItem('user_account');
|
||||
if (userAccount) {
|
||||
// 同步到cookie
|
||||
document.cookie = "user_account=" + userAccount + "; path=/";
|
||||
|
||||
// 如果有其他必要的数据,也同步到cookie
|
||||
var userId = localStorage.getItem('user_id');
|
||||
var userName = localStorage.getItem('user_name');
|
||||
var userAvatar = localStorage.getItem('user_avatar');
|
||||
|
||||
if (userId) document.cookie = "user_id=" + userId + "; path=/";
|
||||
if (userName) document.cookie = "user_name=" + userName + "; path=/";
|
||||
if (userAvatar) document.cookie = "user_avatar=" + userAvatar + "; path=/";
|
||||
|
||||
// 刷新页面以应用新的cookie,并标记已刷新
|
||||
if (!document.cookie.includes('user_id')) {
|
||||
sessionStorage.setItem('has_refreshed', 'true');
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// 搜索功能相关代码
|
||||
layui.use(['layer'], function () {
|
||||
var layer = layui.layer;
|
||||
var $ = layui.jquery;
|
||||
|
||||
// 执行搜索
|
||||
function executeSearch() {
|
||||
var searchInput = document.getElementById('searchInput');
|
||||
if (!searchInput) {
|
||||
layer.msg('搜索组件初始化失败');
|
||||
return;
|
||||
}
|
||||
|
||||
var keyword = searchInput.value.trim();
|
||||
var type = document.getElementById('searchType').value;
|
||||
|
||||
if (!keyword) {
|
||||
layer.msg('请输入搜索关键词');
|
||||
return;
|
||||
}
|
||||
|
||||
// 跳转到统一的搜索结果页面
|
||||
window.location.href = '/index/search/index?keyword=' + encodeURIComponent(keyword) + '&type=' + type;
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
$(function () {
|
||||
var searchMask = $('#searchMask');
|
||||
var searchInput = $('#searchInput');
|
||||
var searchBtn = $('#searchBtn');
|
||||
var mainSearchIcon = $('#mainSearchIcon');
|
||||
var stickySearchIcon = $('#stickySearchIcon');
|
||||
|
||||
// 显示搜索框
|
||||
function showSearch() {
|
||||
searchMask.addClass('show');
|
||||
setTimeout(function () {
|
||||
searchInput.focus();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// 隐藏搜索框
|
||||
function hideSearch() {
|
||||
searchMask.removeClass('show');
|
||||
searchInput.val('');
|
||||
}
|
||||
|
||||
// 绑定搜索图标点击事件
|
||||
mainSearchIcon.on('click', showSearch);
|
||||
stickySearchIcon.on('click', showSearch);
|
||||
|
||||
// 绑定搜索按钮点击事件
|
||||
searchBtn.on('click', function (e) {
|
||||
e.preventDefault();
|
||||
executeSearch();
|
||||
});
|
||||
|
||||
// 绑定回车键搜索
|
||||
searchInput.on('keypress', function (e) {
|
||||
if (e.which === 13) {
|
||||
e.preventDefault();
|
||||
executeSearch();
|
||||
}
|
||||
});
|
||||
|
||||
// 点击遮罩层关闭搜索框
|
||||
searchMask.on('click', function (e) {
|
||||
if ($(e.target).hasClass('search-mask')) {
|
||||
hideSearch();
|
||||
}
|
||||
});
|
||||
|
||||
// 绑定ESC键关闭搜索框
|
||||
$(document).on('keydown', function (e) {
|
||||
if (e.keyCode === 27 && searchMask.hasClass('show')) {
|
||||
hideSearch();
|
||||
}
|
||||
});
|
||||
|
||||
// 输入框获得焦点时选中所有文本
|
||||
searchInput.on('focus', function () {
|
||||
this.select();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 其他功能相关代码
|
||||
layui.use(['carousel', 'form'], function () {
|
||||
var carousel = layui.carousel;
|
||||
var form = layui.form;
|
||||
var $ = layui.$;
|
||||
|
||||
// 检查本地存储并自动登录
|
||||
function checkAutoLogin() {
|
||||
// 如果已经登录,不再执行自动登录
|
||||
if ($('#userAvatarMain').length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已经尝试过自动登录,不再执行
|
||||
if (sessionStorage.getItem('auto_login_attempted') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 从localStorage获取用户账号
|
||||
var userAccount = localStorage.getItem('user_account');
|
||||
if (userAccount) {
|
||||
// 标记已尝试自动登录
|
||||
sessionStorage.setItem('auto_login_attempted', 'true');
|
||||
|
||||
// 发送自动登录请求
|
||||
$.ajax({
|
||||
url: '/index/user/login',
|
||||
type: 'POST',
|
||||
data: {
|
||||
account: userAccount,
|
||||
password: atob(localStorage.getItem('user_password'))
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// 设置cookie
|
||||
document.cookie = "user_id=" + res.data.id + "; path=/";
|
||||
document.cookie = "user_name=" + res.data.name + "; path=/";
|
||||
document.cookie = "user_avatar=" + res.data.avatar + "; path=/";
|
||||
document.cookie = "user_account=" + userAccount + "; path=/";
|
||||
|
||||
// 同时更新localStorage
|
||||
localStorage.setItem('user_id', res.data.id);
|
||||
localStorage.setItem('user_name', res.data.name);
|
||||
localStorage.setItem('user_avatar', res.data.avatar);
|
||||
|
||||
// 登录成功,强制刷新页面
|
||||
window.location.href = window.location.href + '?t=' + new Date().getTime();
|
||||
} else {
|
||||
// 登录失败,清除所有相关存储
|
||||
localStorage.removeItem('user_account');
|
||||
localStorage.removeItem('user_password');
|
||||
sessionStorage.removeItem('auto_login_attempted');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时检查自动登录
|
||||
checkAutoLogin();
|
||||
|
||||
$(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"); // 保证只显示一个
|
||||
});
|
||||
|
||||
// 点击页面其他地方隐藏所有菜单
|
||||
$(document).click(function (e) {
|
||||
if (!$(e.target).closest('.user-dropdown, #userAvatarMain, #userAvatarSticky').length) {
|
||||
$("#userDropdownMain, #userDropdownSticky").removeClass("show");
|
||||
}
|
||||
});
|
||||
|
||||
// 点击菜单项时隐藏菜单
|
||||
$("#userDropdownMain li a, #userDropdownSticky li a").click(function () {
|
||||
$("#userDropdownMain, #userDropdownSticky").removeClass("show");
|
||||
});
|
||||
});
|
||||
|
||||
// 退出登录
|
||||
$('.logout-btn').on('click', function () {
|
||||
layer.confirm('确定要退出登录吗?', {
|
||||
btn: ['确定', '取消']
|
||||
}, function () {
|
||||
// 先发送退出请求
|
||||
$.ajax({
|
||||
url: '/index/user/logout',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// 清除localStorage
|
||||
localStorage.removeItem('user_account');
|
||||
localStorage.removeItem('user_password');
|
||||
localStorage.removeItem('user_id');
|
||||
localStorage.removeItem('user_name');
|
||||
localStorage.removeItem('user_avatar');
|
||||
|
||||
// 清除sessionStorage
|
||||
sessionStorage.removeItem('auto_login_attempted');
|
||||
sessionStorage.removeItem('has_refreshed');
|
||||
|
||||
// 清除cookie
|
||||
document.cookie = "user_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
document.cookie = "user_name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
document.cookie = "user_avatar=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
document.cookie = "user_account=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
document.cookie = "user_password=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
|
||||
// 强制刷新页面,不使用缓存
|
||||
window.location.href = window.location.href + '?t=' + new Date().getTime();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 监听滚动事件
|
||||
$(window).scroll(function () {
|
||||
var scrollTop = $(window).scrollTop();
|
||||
if (scrollTop > 150) { // 当滚动超过150px时显示固定导航
|
||||
$('.sticky-nav').fadeIn();
|
||||
} else {
|
||||
$('.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';
|
||||
// });
|
||||
|
||||
form.on('submit(accountLogin)', function (data) {
|
||||
$.ajax({
|
||||
url: '{:url("index/user/login")}',
|
||||
type: 'POST',
|
||||
data: data.field,
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// 存储登录数据,设置7天过期
|
||||
var expireTime = new Date().getTime() + 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
// 设置localStorage
|
||||
localStorage.setItem('user_account', data.field.account);
|
||||
localStorage.setItem('user_password', btoa(data.field.password));
|
||||
localStorage.setItem('expire_time', expireTime);
|
||||
localStorage.setItem('is_auto_login', 'true');
|
||||
|
||||
// 设置cookie
|
||||
document.cookie = "user_id=" + res.data.id + "; path=/";
|
||||
document.cookie = "user_name=" + res.data.name + "; path=/";
|
||||
document.cookie = "user_avatar=" + res.data.avatar + "; path=/";
|
||||
document.cookie = "expire_time=" + expireTime + "; path=/";
|
||||
document.cookie = "is_auto_login=true; path=/";
|
||||
document.cookie = "user_account=" + data.field.account + "; path=/";
|
||||
document.cookie = "user_password=" + btoa(data.field.password) + "; path=/";
|
||||
|
||||
// 设置sessionStorage
|
||||
sessionStorage.setItem('auto_login_attempted', 'true');
|
||||
|
||||
layer.msg('登录成功', {
|
||||
icon: 1,
|
||||
time: 2000,
|
||||
shade: 0.3
|
||||
}, function () {
|
||||
// 获取当前页面URL,如果是从其他页面跳转来的,则返回上一页
|
||||
var currentUrl = window.location.href;
|
||||
var referrer = document.referrer;
|
||||
|
||||
// 如果是从登录页面跳转来的,则返回上一页
|
||||
if (referrer && referrer.includes('/index/user/login')) {
|
||||
window.location.href = referrer;
|
||||
} else {
|
||||
// 否则刷新当前页面
|
||||
window.location.href = currentUrl + '?t=' + new Date().getTime();
|
||||
}
|
||||
});
|
||||
layer.msg(res.msg, {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,60 @@
|
||||
<footer class="footer" style="background-image: url(__IMAGES__/footer-bg-1.png)">
|
||||
<div class="container">
|
||||
<div class="row" style="width: 100%;">
|
||||
<div class="row-main">
|
||||
<div class="mr-20">
|
||||
<img src="{$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;">
|
||||
<div>
|
||||
<h4 class="text-white f-20 font-weight-normal mb-3">关于我们</h4>
|
||||
<ul class="list-unstyled footer-sub-menu">
|
||||
<li><a href="#" class="footer-link">概况</a></li>
|
||||
<li><a href="#" class="footer-link">资讯</a></li>
|
||||
<li><a href="#" class="footer-link">加入我们</a></li>
|
||||
<li><a href="#" class="footer-link">联系我们</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-white f-20 font-weight-normal mb-3">商务合作</h4>
|
||||
<ul class="list-unstyled footer-sub-menu">
|
||||
<li><a href="#" class="footer-link">商务合作</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-white f-20 font-weight-normal mb-3">服务支持</h4>
|
||||
<ul class="list-unstyled footer-sub-menu">
|
||||
<li><a href="#" class="footer-link">常见问答</a></li>
|
||||
<li><a href="#" class="footer-link">软件下载</a></li>
|
||||
<li><a href="#" class="footer-link">服务政策</a></li>
|
||||
<li><a href="#" class="footer-link">投诉建议</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-center">
|
||||
<img src="{$config['web_wechat']}" alt="微信二维码" class="img-fluid" style="max-width: 150px;">
|
||||
<p class="text-white-50 mt-2">微信公众号</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<section class="copyright text-center">
|
||||
<div class="container wow fadeInUp animated" data-wow-delay="400ms"
|
||||
style="visibility: visible; animation-delay: 400ms; animation-name: fadeInUp;">
|
||||
<p class="copyright__text">Copyright <span class="dynamic-year">2025</span> | All Rights By <a
|
||||
href="http://www.yunzer.cn">Yunzer</a></p>
|
||||
</div>
|
||||
<div class="container wow fadeInUp animated" data-wow-delay="400ms"
|
||||
style="visibility: visible; animation-delay: 400ms; animation-name: fadeInUp;">
|
||||
<a href="https://beian.miit.gov.cn/" target="_blank" rel="nofollow">{$config['admin_icp']}</a>
|
||||
</div>
|
||||
<div class="tongji">
|
||||
<script id="LA-DATA-WIDGET" crossorigin="anonymous" charset="UTF-8"
|
||||
src="https://v6-widget.51.la/v6/KoyzaWWEcLvPzkQn/quote.js?theme=#1690FF,#FFFFFF,#999999,#FFFFFF,#FFFFFF,#1690FF,12&f=12"></script>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,341 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{$config['web_title']}</title>
|
||||
<link rel="stylesheet" href="__LAYUI__/css/layui.css">
|
||||
<link rel="stylesheet" href="__CSS__/style.css">
|
||||
<link rel="stylesheet" href="__CSS__/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="__CSS__/fontawesome.css">
|
||||
|
||||
<style>
|
||||
/* 用户头像样式 */
|
||||
#userAvatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
.main-menu__right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.username {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
color: #333;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.search-icon:hover {
|
||||
color: #1e9fff;
|
||||
}
|
||||
|
||||
.search-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 9999;
|
||||
display: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-mask.show {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-20px);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.search-mask.show .search-container {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
background: #fff;
|
||||
border-radius: 30px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.search-box button {
|
||||
height: 100%;
|
||||
padding: 0 30px;
|
||||
border: none;
|
||||
background: #1E9FFF;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.search-box button:hover {
|
||||
background: #1a8fe6;
|
||||
}
|
||||
|
||||
.search-type {
|
||||
height: 100%;
|
||||
padding: 0 15px;
|
||||
border: none;
|
||||
border-right: 1px solid #eee;
|
||||
background: #f8f8f8;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 10px center;
|
||||
background-size: 12px;
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
.search-type:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.search-type:focus {
|
||||
background-color: #fff;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<style>
|
||||
/* 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;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
min-height: 23vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -0,0 +1,908 @@
|
||||
<?php
|
||||
/**
|
||||
* 商业使用授权协议
|
||||
*
|
||||
* Copyright (c) 2025 [云泽网]. 保留所有权利.
|
||||
*
|
||||
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
|
||||
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
|
||||
*
|
||||
* 授权购买请联系: 357099073@qq.com
|
||||
* 官方网站: https://www.yunzer.cn
|
||||
*
|
||||
* 评估用户须知:
|
||||
* 1. 禁止移除版权声明
|
||||
* 2. 禁止用于生产环境
|
||||
* 3. 禁止转售或分发
|
||||
*/
|
||||
|
||||
// 获取当前登录状态
|
||||
$isLoggedIn = false;
|
||||
$userInfo = [
|
||||
'is_login' => false,
|
||||
'name' => '',
|
||||
'avatar' => '/static/images/avatar.png' // 默认头像
|
||||
];
|
||||
|
||||
// 检查cookie
|
||||
$userAccount = cookie('user_account');
|
||||
if ($userAccount) {
|
||||
$isLoggedIn = true;
|
||||
$userInfo = [
|
||||
'is_login' => true,
|
||||
'name' => cookie('user_name'),
|
||||
'avatar' => cookie('user_avatar') ? cookie('user_avatar') : '/static/images/avatar.png'
|
||||
];
|
||||
}
|
||||
|
||||
// 添加一个隐藏的div来存储登录状态
|
||||
$loginStatus = [
|
||||
'isLoggedIn' => $isLoggedIn,
|
||||
'userAccount' => $userAccount ?? ''
|
||||
];
|
||||
?>
|
||||
|
||||
<!-- 添加一个隐藏的div来存储登录状态 -->
|
||||
<div id="loginStatus" style="display: none;" data-is-logged-in="{$isLoggedIn}" data-user-account="{$userAccount ?? ''}">
|
||||
</div>
|
||||
|
||||
<div style="display: flex;flex-direction: column;">
|
||||
<!-- 导航栏 -->
|
||||
<div class="main-menu">
|
||||
<div class="container">
|
||||
<div class="main-menu__logo">
|
||||
<a href="/index.html"><img src="__IMAGES__/logo1.png" width="186" alt="Logo"></a>
|
||||
</div>
|
||||
<div class="main-menu__nav">
|
||||
<ul class="main-menu__list">
|
||||
<li><a href="/">首页</a></li>
|
||||
<li><a href="/index/articles/index?cateid=1">站点资讯</a></li>
|
||||
<li><a href="/index/articles/index?cateid=3">技术文章</a></li>
|
||||
<li><a href="/index/program/index?cateid=2">办公资源</a></li>
|
||||
<li><a href="/index/program/index?cateid=1">程序下载</a></li>
|
||||
<li><a href="/index/game/index?cateid=8">游戏下载</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="main-menu__search">
|
||||
<i class="layui-icon layui-icon-search search-icon" id="mainSearchIcon"></i>
|
||||
</div>
|
||||
<div class="main-menu__right">
|
||||
<div class="username">
|
||||
<?php if ($userInfo['is_login']): ?>
|
||||
<span class="username-text">{$userInfo.name}</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<!-- 根据登录状态显示不同的内容 -->
|
||||
<?php if ($isLoggedIn): ?>
|
||||
<div class="layui-inline" style="position: relative;margin-left:20px;">
|
||||
<img src="{$userInfo.avatar}" 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>
|
||||
<?php else: ?>
|
||||
<div class="layui-inline">
|
||||
<a href="/index/user/login" class="layui-btn layui-btn-normal">登录</a>
|
||||
<a href="/index/user/register" class="layui-btn layui-btn-primary">注册</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 固定导航 -->
|
||||
<div class="sticky-nav" style="display: none;">
|
||||
<div class="container">
|
||||
<div class="sticky-nav__logo">
|
||||
<a href="/index.html"><img src="__IMAGES__/logo1.png" width="150" alt="Logo"></a>
|
||||
</div>
|
||||
<div class="sticky-nav__menu">
|
||||
<ul>
|
||||
<li><a href="/">首页</a></li>
|
||||
<li><a href="/index/articles/index?cateid=1">站点资讯</a></li>
|
||||
<li><a href="/index/articles/index?cateid=3">技术文章</a></li>
|
||||
<li><a href="/index/program/index?cateid=2">办公资源</a></li>
|
||||
<li><a href="/index/program/index?cateid=1">程序下载</a></li>
|
||||
<li><a href="/index/game/index?cateid=8">游戏下载</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sticky-nav__search">
|
||||
<i class="layui-icon layui-icon-search search-icon" id="stickySearchIcon"></i>
|
||||
</div>
|
||||
<div class="sticky-nav__right">
|
||||
<div class="main-menu__right">
|
||||
<div class="username">
|
||||
<?php if ($userInfo['is_login']): ?>
|
||||
<span class="username-text">{$userInfo.name}</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<!-- 根据登录状态显示不同的内容 -->
|
||||
<?php if ($isLoggedIn): ?>
|
||||
<div class="layui-inline" style="position: relative;margin-left:20px;">
|
||||
<img src="{$userInfo.avatar}" 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>
|
||||
<?php else: ?>
|
||||
<div class="layui-inline">
|
||||
<a href="/index/user/login" class="layui-btn layui-btn-normal">登录</a>
|
||||
<a href="/index/user/register" class="layui-btn layui-btn-primary">注册</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 搜索遮罩 -->
|
||||
<div class="search-mask" id="searchMask">
|
||||
<div class="search-container">
|
||||
<div class="search-box">
|
||||
<select id="searchType" class="search-type">
|
||||
<option value="articles">文章</option>
|
||||
<option value="resources">资源</option>
|
||||
</select>
|
||||
<input type="text" id="searchInput" placeholder="请输入搜索关键词">
|
||||
<button id="searchBtn">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 在页面加载时立即执行
|
||||
(function () {
|
||||
// 检查是否已经刷新过
|
||||
if (sessionStorage.getItem('has_refreshed') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查localStorage中是否有用户账号
|
||||
var userAccount = localStorage.getItem('user_account');
|
||||
if (userAccount) {
|
||||
// 同步到cookie
|
||||
document.cookie = "user_account=" + userAccount + "; path=/";
|
||||
|
||||
// 如果有其他必要的数据,也同步到cookie
|
||||
var userId = localStorage.getItem('user_id');
|
||||
var userName = localStorage.getItem('user_name');
|
||||
var userAvatar = localStorage.getItem('user_avatar');
|
||||
|
||||
if (userId) document.cookie = "user_id=" + userId + "; path=/";
|
||||
if (userName) document.cookie = "user_name=" + userName + "; path=/";
|
||||
if (userAvatar) document.cookie = "user_avatar=" + userAvatar + "; path=/";
|
||||
|
||||
// 刷新页面以应用新的cookie,并标记已刷新
|
||||
if (!document.cookie.includes('user_id')) {
|
||||
sessionStorage.setItem('has_refreshed', 'true');
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
layui.use(['carousel', 'form', 'layer'], function () {
|
||||
var carousel = layui.carousel, form = layui.form, layer = layui.layer, $ = layui.$;
|
||||
|
||||
// 检查本地存储并自动登录
|
||||
function checkAutoLogin() {
|
||||
// 如果已经登录,不再执行自动登录
|
||||
if ($('#userAvatarMain').length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已经尝试过自动登录,不再执行
|
||||
if (sessionStorage.getItem('auto_login_attempted') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 从localStorage获取用户账号
|
||||
var userAccount = localStorage.getItem('user_account');
|
||||
if (userAccount) {
|
||||
// 标记已尝试自动登录
|
||||
sessionStorage.setItem('auto_login_attempted', 'true');
|
||||
|
||||
// 发送自动登录请求
|
||||
$.ajax({
|
||||
url: '/index/user/login',
|
||||
type: 'POST',
|
||||
data: {
|
||||
account: userAccount,
|
||||
password: atob(localStorage.getItem('user_password'))
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// 设置cookie
|
||||
document.cookie = "user_id=" + res.data.id + "; path=/";
|
||||
document.cookie = "user_name=" + res.data.name + "; path=/";
|
||||
document.cookie = "user_avatar=" + res.data.avatar + "; path=/";
|
||||
document.cookie = "user_account=" + userAccount + "; path=/";
|
||||
|
||||
// 同时更新localStorage
|
||||
localStorage.setItem('user_id', res.data.id);
|
||||
localStorage.setItem('user_name', res.data.name);
|
||||
localStorage.setItem('user_avatar', res.data.avatar);
|
||||
|
||||
// 登录成功,强制刷新页面
|
||||
window.location.href = window.location.href + '?t=' + new Date().getTime();
|
||||
} else {
|
||||
// 登录失败,清除所有相关存储
|
||||
localStorage.removeItem('user_account');
|
||||
localStorage.removeItem('user_password');
|
||||
sessionStorage.removeItem('auto_login_attempted');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时检查自动登录
|
||||
checkAutoLogin();
|
||||
|
||||
$(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"); // 保证只显示一个
|
||||
});
|
||||
|
||||
// 点击页面其他地方隐藏所有菜单
|
||||
$(document).click(function (e) {
|
||||
if (!$(e.target).closest('.user-dropdown, #userAvatarMain, #userAvatarSticky').length) {
|
||||
$("#userDropdownMain, #userDropdownSticky").removeClass("show");
|
||||
}
|
||||
});
|
||||
|
||||
// 点击菜单项时隐藏菜单
|
||||
$("#userDropdownMain li a, #userDropdownSticky li a").click(function () {
|
||||
$("#userDropdownMain, #userDropdownSticky").removeClass("show");
|
||||
});
|
||||
});
|
||||
|
||||
// 退出登录
|
||||
$('.logout-btn').on('click', function () {
|
||||
layer.confirm('确定要退出登录吗?', {
|
||||
btn: ['确定', '取消']
|
||||
}, function () {
|
||||
// 先发送退出请求
|
||||
$.ajax({
|
||||
url: '/index/user/logout',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// 清除localStorage
|
||||
localStorage.removeItem('user_account');
|
||||
localStorage.removeItem('user_password');
|
||||
localStorage.removeItem('user_id');
|
||||
localStorage.removeItem('user_name');
|
||||
localStorage.removeItem('user_avatar');
|
||||
|
||||
// 清除sessionStorage
|
||||
sessionStorage.removeItem('auto_login_attempted');
|
||||
sessionStorage.removeItem('has_refreshed');
|
||||
|
||||
// 清除cookie
|
||||
document.cookie = "user_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
document.cookie = "user_name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
document.cookie = "user_avatar=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
document.cookie = "user_account=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
document.cookie = "user_password=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
|
||||
// 强制刷新页面,不使用缓存
|
||||
window.location.href = window.location.href + '?t=' + new Date().getTime();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 监听滚动事件
|
||||
$(window).scroll(function () {
|
||||
var scrollTop = $(window).scrollTop();
|
||||
if (scrollTop > 150) { // 当滚动超过150px时显示固定导航
|
||||
$('.sticky-nav').fadeIn();
|
||||
} else {
|
||||
$('.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';
|
||||
});
|
||||
|
||||
form.on('submit(accountLogin)', function (data) {
|
||||
$.ajax({
|
||||
url: '{:url("index/user/login")}',
|
||||
type: 'POST',
|
||||
data: data.field,
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// 存储登录数据,设置7天过期
|
||||
var expireTime = new Date().getTime() + 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
// 设置localStorage
|
||||
localStorage.setItem('user_account', data.field.account);
|
||||
localStorage.setItem('user_password', btoa(data.field.password));
|
||||
localStorage.setItem('expire_time', expireTime);
|
||||
localStorage.setItem('is_auto_login', 'true');
|
||||
|
||||
// 设置cookie
|
||||
document.cookie = "user_id=" + res.data.id + "; path=/";
|
||||
document.cookie = "user_name=" + res.data.name + "; path=/";
|
||||
document.cookie = "user_avatar=" + res.data.avatar + "; path=/";
|
||||
document.cookie = "expire_time=" + expireTime + "; path=/";
|
||||
document.cookie = "is_auto_login=true; path=/";
|
||||
document.cookie = "user_account=" + data.field.account + "; path=/";
|
||||
document.cookie = "user_password=" + btoa(data.field.password) + "; path=/";
|
||||
|
||||
// 设置sessionStorage
|
||||
sessionStorage.setItem('auto_login_attempted', 'true');
|
||||
|
||||
layer.msg('登录成功', {
|
||||
icon: 1,
|
||||
time: 2000,
|
||||
shade: 0.3
|
||||
}, function () {
|
||||
// 获取当前页面URL
|
||||
var currentUrl = window.location.href;
|
||||
|
||||
// 如果当前页面是登录页面,则跳转到首页
|
||||
if (currentUrl.includes('/index/user/login')) {
|
||||
window.location.href = '/index.html';
|
||||
} else {
|
||||
// 否则刷新当前页面
|
||||
window.location.href = currentUrl + '?t=' + new Date().getTime();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// 搜索功能相关代码
|
||||
layui.use(['layer'], function () {
|
||||
var layer = layui.layer;
|
||||
var $ = layui.jquery;
|
||||
|
||||
// 执行搜索
|
||||
function executeSearch() {
|
||||
var searchInput = document.getElementById('searchInput');
|
||||
if (!searchInput) {
|
||||
layer.msg('搜索组件初始化失败');
|
||||
return;
|
||||
}
|
||||
|
||||
var keyword = searchInput.value.trim();
|
||||
var type = document.getElementById('searchType').value;
|
||||
|
||||
if (!keyword) {
|
||||
layer.msg('请输入搜索关键词');
|
||||
return;
|
||||
}
|
||||
|
||||
// 跳转到统一的搜索结果页面
|
||||
window.location.href = '/index/search/index?keyword=' + encodeURIComponent(keyword) + '&type=' + type;
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
$(function() {
|
||||
var searchMask = $('#searchMask');
|
||||
var searchInput = $('#searchInput');
|
||||
var searchBtn = $('#searchBtn');
|
||||
var mainSearchIcon = $('#mainSearchIcon');
|
||||
var stickySearchIcon = $('#stickySearchIcon');
|
||||
|
||||
// 显示搜索框
|
||||
function showSearch() {
|
||||
searchMask.addClass('show');
|
||||
setTimeout(function() {
|
||||
searchInput.focus();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// 隐藏搜索框
|
||||
function hideSearch() {
|
||||
searchMask.removeClass('show');
|
||||
searchInput.val('');
|
||||
}
|
||||
|
||||
// 绑定搜索图标点击事件
|
||||
mainSearchIcon.on('click', showSearch);
|
||||
stickySearchIcon.on('click', showSearch);
|
||||
|
||||
// 绑定搜索按钮点击事件
|
||||
searchBtn.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
executeSearch();
|
||||
});
|
||||
|
||||
// 绑定回车键搜索
|
||||
searchInput.on('keypress', function(e) {
|
||||
if (e.which === 13) {
|
||||
e.preventDefault();
|
||||
executeSearch();
|
||||
}
|
||||
});
|
||||
|
||||
// 点击遮罩层关闭搜索框
|
||||
searchMask.on('click', function(e) {
|
||||
if ($(e.target).hasClass('search-mask')) {
|
||||
hideSearch();
|
||||
}
|
||||
});
|
||||
|
||||
// 绑定ESC键关闭搜索框
|
||||
$(document).on('keydown', function(e) {
|
||||
if (e.keyCode === 27 && searchMask.hasClass('show')) {
|
||||
hideSearch();
|
||||
}
|
||||
});
|
||||
|
||||
// 输入框获得焦点时选中所有文本
|
||||
searchInput.on('focus', function() {
|
||||
this.select();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 用户头像样式 */
|
||||
#userAvatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
.main-menu__right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.username {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 搜索相关样式 */
|
||||
.search-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 9999;
|
||||
display: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-mask.show {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-20px);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.search-mask.show .search-container {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
background: #fff;
|
||||
border-radius: 30px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.search-box button {
|
||||
height: 100%;
|
||||
padding: 0 30px;
|
||||
border: none;
|
||||
background: #1E9FFF;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.search-box button:hover {
|
||||
background: #1a8fe6;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
color: #333;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.search-icon:hover {
|
||||
color: #1e9fff;
|
||||
}
|
||||
|
||||
.search-type {
|
||||
height: 100%;
|
||||
padding: 0 15px;
|
||||
border: none;
|
||||
border-right: 1px solid #eee;
|
||||
background: #f8f8f8;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 10px center;
|
||||
background-size: 12px;
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
.search-type:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.search-type:focus {
|
||||
background-color: #fff;
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.search-results {
|
||||
padding: 15px;
|
||||
max-height: 370px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.search-section h3 {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.search-section ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.search-section li {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px dashed #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.search-section li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.search-section a {
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.search-section a:hover {
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.search-section .downloads {
|
||||
color: #1E9FFF;
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
/* 自定义滚动条样式 */
|
||||
.search-results::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.search-results::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.search-results::-webkit-scrollbar-thumb {
|
||||
background: #ccc;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.search-results::-webkit-scrollbar-thumb:hover {
|
||||
background: #999;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
/**
|
||||
* 商业使用授权协议
|
||||
*
|
||||
* Copyright (c) 2025 [云泽网]. 保留所有权利.
|
||||
*
|
||||
* 本软件仅供评估使用。任何商业用途必须获得书面授权许可。
|
||||
* 未经授权商业使用本软件属于侵权行为,将承担法律责任。
|
||||
*
|
||||
* 授权购买请联系: 357099073@qq.com
|
||||
* 官方网站: https://www.yunzer.cn
|
||||
*
|
||||
* 评估用户须知:
|
||||
* 1. 禁止移除版权声明
|
||||
* 2. 禁止用于生产环境
|
||||
* 3. 禁止转售或分发
|
||||
*/
|
||||
|
||||
// 获取当前登录状态
|
||||
$isLoggedIn = false;
|
||||
$userInfo = [
|
||||
'is_login' => false,
|
||||
'name' => '',
|
||||
'avatar' => '/static/images/avatar.png' // 默认头像
|
||||
];
|
||||
|
||||
// 检查cookie
|
||||
$userAccount = cookie('user_account');
|
||||
if ($userAccount) {
|
||||
$isLoggedIn = true;
|
||||
$userInfo = [
|
||||
'is_login' => true,
|
||||
'name' => cookie('user_name'),
|
||||
'avatar' => cookie('user_avatar') ? cookie('user_avatar') : '/static/images/avatar.png'
|
||||
];
|
||||
}
|
||||
|
||||
// 添加一个隐藏的div来存储登录状态
|
||||
$loginStatus = [
|
||||
'isLoggedIn' => $isLoggedIn,
|
||||
'userAccount' => $userAccount ?? ''
|
||||
];
|
||||
?>
|
||||
|
||||
<!-- 添加一个隐藏的div来存储登录状态 -->
|
||||
<div id="loginStatus" style="display: none;" data-is-logged-in="{$isLoggedIn}" data-user-account="{$userAccount ?? ''}">
|
||||
</div>
|
||||
|
||||
<div style="display: flex;flex-direction: column;">
|
||||
<!-- <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" style="margin-right: 10px;"></span>
|
||||
<a href="{$config['web_phone']}">{$config['web_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['web_mail']}">{$config['web_mail']}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="topbar-one__social" style="width: 30%;">
|
||||
<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['web_wechat']}" alt="公众号二维码" style="width:180px;height:180px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- 导航栏 -->
|
||||
<div class="main-menu">
|
||||
<div class="container">
|
||||
<div class="main-menu__logo">
|
||||
<a href="/"><img src="{$config['logo1']}" width="186" alt="Logo"></a>
|
||||
</div>
|
||||
<div class="main-menu__nav">
|
||||
<ul class="main-menu__list">
|
||||
<li><a href="/">首页</a></li>
|
||||
<li><a href="/index/articles/index?cateid=1">站点资讯</a></li>
|
||||
<li><a href="/index/articles/index?cateid=3">技术文章</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="main-menu__search">
|
||||
<i class="layui-icon layui-icon-search search-icon" id="mainSearchIcon"></i>
|
||||
</div>
|
||||
<!-- 搜索蒙版 -->
|
||||
<div class="search-mask" id="searchMask" style="">
|
||||
<div class="search-container">
|
||||
<div class="search-box">
|
||||
<select id="searchType" class="search-type">
|
||||
<option value="articles">文章</option>
|
||||
<option value="resources">资源</option>
|
||||
</select>
|
||||
<input type="text" id="searchInput" placeholder="请输入搜索关键词">
|
||||
<button class="search-btn" id="searchBtn">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-menu__right">
|
||||
<div class="username">
|
||||
<?php if ($userInfo['is_login']): ?>
|
||||
<span class="username-text">{$userInfo.name}</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<!-- 根据登录状态显示不同的内容 -->
|
||||
<?php if ($userInfo['is_login']): ?>
|
||||
<div class="layui-inline" style="position: relative;margin-left:20px;">
|
||||
<img src="{$userInfo.avatar}" 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>
|
||||
<?php else: ?>
|
||||
<div class="layui-inline">
|
||||
<a href="/index/user/login" class="layui-btn layui-btn-normal">登录</a>
|
||||
<a href="/index/user/register" class="layui-btn layui-btn-primary">注册</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 固定导航 -->
|
||||
<div class="sticky-nav" style="display: none;">
|
||||
<div class="container">
|
||||
<div class="sticky-nav__logo">
|
||||
<a href="/"><img src="{$config['logo1']}" width="150" alt="Logo"></a>
|
||||
</div>
|
||||
<div class="sticky-nav__menu">
|
||||
<ul>
|
||||
<li><a href="/">首页</a></li>
|
||||
<li><a href="/index/articles/index?cateid=1">站点资讯</a></li>
|
||||
<li><a href="/index/articles/index?cateid=3">技术文章</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sticky-nav__search">
|
||||
<i class="layui-icon layui-icon-search search-icon" id="stickySearchIcon"></i>
|
||||
</div>
|
||||
<div class="sticky-nav__right">
|
||||
<div class="main-menu__right">
|
||||
<div class="username">
|
||||
<?php if ($userInfo['is_login']): ?>
|
||||
<span class="username-text">{$userInfo.name}</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<!-- 根据登录状态显示不同的内容 -->
|
||||
<?php if ($userInfo['is_login']): ?>
|
||||
<div class="layui-inline" style="position: relative;margin-left:20px;">
|
||||
<img src="{$userInfo.avatar}" 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>
|
||||
<?php else: ?>
|
||||
<div class="layui-inline">
|
||||
<a href="/index/user/login" class="layui-btn layui-btn-normal">登录</a>
|
||||
<a href="/index/user/register" class="layui-btn layui-btn-primary">注册</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<main class="main-content">
|
||||
<div class="container">
|
||||
|
||||
|
||||
</div>
|
||||
</main>
|
||||
@@ -0,0 +1,724 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
<div class="main">
|
||||
<div class="main-top">
|
||||
<div class="main-top-main">
|
||||
<div class="main-title">
|
||||
<?php echo $game['title']; ?>
|
||||
</div>
|
||||
<div class="location">
|
||||
<div class="container">
|
||||
<div class="location-item">
|
||||
<a href="/">首页</a>
|
||||
<span>></span>
|
||||
<a href="/index/game/list" id="cateLink"><?php echo $cateName; ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-main">
|
||||
<div class="detail-top">
|
||||
<div class="detail-top-card">
|
||||
<div class="detail-top-card-left">
|
||||
<div class="article-cover">
|
||||
<img src="<?php echo $game['icon'] ?: '/static/images/default-game.png'; ?>">
|
||||
<!-- <img src="https://www.yunzer.cn/storage/uploads/20250523/b75a51fa606fd3a18261a6ea283d35fe.jpg" alt=""> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-top-card-right">
|
||||
<div class="detail-top-card-right-top">
|
||||
<div class="collect-btn">
|
||||
<button class="btn btn-primary" id="collectBtn" data-game-id="<?php echo $game['id']; ?>">
|
||||
<i class="fa-solid fa-heart"></i> 收藏
|
||||
</button>
|
||||
</div>
|
||||
<div class="report-btn">
|
||||
<button class="btn btn-primary" id="reportBtn" style="margin-left: 20px;">
|
||||
<i class="fa-solid fa-flag"></i> 举报
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-top-card-right-middle">
|
||||
<div class="game-info">
|
||||
<div class="title">Free</div>
|
||||
<div class="infos">
|
||||
<div class="infoitem"><span>更新时间:</span><span
|
||||
class="infoitem-value"><?php echo date('Y-m-d', $game['create_time']); ?></span>
|
||||
</div>
|
||||
<div class="infoitem"><span>所属分类:</span><span
|
||||
class="infoitem-value"><?php echo $cateName; ?></span></div>
|
||||
<div class="infoitem"><span>程序编号:</span><span
|
||||
class="infoitem-value"><?php echo $game['number']; ?></span></div>
|
||||
<div class="infoitem"><span>查看:</span><span
|
||||
class="infoitem-value"><?php echo $game['views']; ?></span></div>
|
||||
<div class="infoitem"><span>下载:</span><span
|
||||
class="infoitem-value"><?php echo $game['downloads']; ?></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-top-card-right-bottom">
|
||||
<div class="game-actions1">
|
||||
<div style="display: flex;gap: 30px;}">
|
||||
<button id="downloadBtn" class="btn btn-primary">
|
||||
<i class="fa-solid fa-download"></i> 立即下载
|
||||
</button>
|
||||
<button id="codeBtn" class="codebtn">
|
||||
<i class="fa-solid fa-download"></i> 分享码:<?php echo $game['code']; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-middle">
|
||||
<div class="detial-middle-left">
|
||||
<div class="game-detail">
|
||||
<div class="game-info">
|
||||
<div class="game-content">
|
||||
<div class="game-desc">
|
||||
<?php echo $game['content']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="game-actions">
|
||||
<div style="display: flex;gap: 30px;}">
|
||||
<button id="downloadBtn" class="btn btn-primary">
|
||||
<i class="fa-solid fa-download"></i> 立即下载
|
||||
</button>
|
||||
<button id="codeBtn" class="codebtn">
|
||||
<i class="fa-solid fa-download"></i> 分享码:<?php echo $game['code']; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="disclaimers">
|
||||
<div class="disclaimer-item">
|
||||
<div class="disclaimer-title">免责声明:</div>
|
||||
<div class="disclaimer-content">
|
||||
<?php echo $config['disclaimers'] ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="game-navigation">
|
||||
<div class="prev-game" id="prevGame">
|
||||
</div>
|
||||
<div class="next-game" id="nextGame">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 相关游戏 -->
|
||||
<?php if (!empty($relatedGames)): ?>
|
||||
<div class="related-games">
|
||||
<h3>相关游戏</h3>
|
||||
<div class="game-list">
|
||||
<?php foreach ($relatedGames as $related): ?>
|
||||
<div class="game-item"
|
||||
onclick="window.location.href='/index/game/detail?id=<?php echo $related['id']; ?>'">
|
||||
<div class="game-cover">
|
||||
<img src="<?php echo $related['icon'] ?: '/static/images/default-game.png'; ?>"
|
||||
alt="<?php echo $related['title']; ?>">
|
||||
</div>
|
||||
<div class="game-info">
|
||||
<h4 class="game-title-1"><?php echo $related['title']; ?></h4>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detial-middle-right">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 返回顶部按钮 -->
|
||||
<div class="go-to-top" id="goToTop">
|
||||
<i class="layui-icon layui-icon-top"></i>
|
||||
</div>
|
||||
|
||||
{include file="component/footer" /}
|
||||
|
||||
<script>
|
||||
// 页面加载完成后执行
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// 获取游戏ID
|
||||
const gameId = new URLSearchParams(window.location.search).get('id');
|
||||
if (!gameId) {
|
||||
alert('游戏ID不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取游戏详情
|
||||
fetch('/index/game/detail?id=' + gameId, {
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.code === 1) {
|
||||
// 渲染上一篇
|
||||
const prevGame = document.getElementById('prevGame');
|
||||
if (result.data.prevGame) {
|
||||
prevGame.innerHTML = `
|
||||
<a href="/index/game/detail?id=${result.data.prevGame.id}">
|
||||
<i class="fa fa-arrow-left"></i> 上一篇:${result.data.prevGame.title}
|
||||
</a>
|
||||
`;
|
||||
} else {
|
||||
prevGame.innerHTML = '<span class="disabled"><i class="fa fa-arrow-left"></i> 没有上一篇了</span>';
|
||||
}
|
||||
|
||||
// 渲染下一篇
|
||||
const nextGame = document.getElementById('nextGame');
|
||||
if (result.data.nextGame) {
|
||||
nextGame.innerHTML = `
|
||||
<a href="/index/game/detail?id=${result.data.nextGame.id}">
|
||||
下一篇:${result.data.nextGame.title} <i class="fa fa-arrow-right"></i>
|
||||
</a>
|
||||
`;
|
||||
} else {
|
||||
nextGame.innerHTML = '<span class="disabled">没有下一篇了 <i class="fa fa-arrow-right"></i></span>';
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('获取游戏详情失败:', error);
|
||||
});
|
||||
|
||||
// 更新访问次数
|
||||
updateGameViews(gameId);
|
||||
|
||||
// 下载功能
|
||||
const downloadBtn = document.getElementById('downloadBtn');
|
||||
if (downloadBtn) {
|
||||
downloadBtn.addEventListener('click', function () {
|
||||
fetch('/index/game/downloadurl?id=' + gameId, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('网络响应失败');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (data.code === 1) {
|
||||
const downloadsElement = document.getElementById('gameDownloads');
|
||||
if (downloadsElement) {
|
||||
let downloads = parseInt(downloadsElement.textContent);
|
||||
downloadsElement.textContent = downloads + 1;
|
||||
}
|
||||
|
||||
// 直接使用返回的URL
|
||||
if (data.data && data.data.url) {
|
||||
window.open(data.data.url, '_blank');
|
||||
} else {
|
||||
alert('下载地址不存在');
|
||||
}
|
||||
} else {
|
||||
alert('下载失败:' + data.msg);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('下载请求失败:', error);
|
||||
alert('下载请求失败,请稍后重试');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//复制分享码
|
||||
const codeBtn = document.getElementById('codeBtn');
|
||||
if (codeBtn) {
|
||||
codeBtn.addEventListener('click', function () {
|
||||
const code = '<?php echo $game['code']; ?>';
|
||||
if (code) {
|
||||
// 创建一个临时输入框
|
||||
const tempInput = document.createElement('input');
|
||||
tempInput.value = code;
|
||||
document.body.appendChild(tempInput);
|
||||
tempInput.select();
|
||||
|
||||
try {
|
||||
// 尝试使用传统的复制方法
|
||||
document.execCommand('copy');
|
||||
layer.msg('分享码已复制到剪贴板');
|
||||
} catch (err) {
|
||||
console.error('复制失败:', err);
|
||||
layer.msg('复制失败,请手动复制');
|
||||
} finally {
|
||||
// 移除临时输入框
|
||||
document.body.removeChild(tempInput);
|
||||
}
|
||||
} else {
|
||||
layer.msg('分享码不存在');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 返回顶部功能
|
||||
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 updateGameViews(gameId) {
|
||||
fetch('/index/game/updateViews', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: 'id=' + gameId
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.code === 1) {
|
||||
const viewsElement = document.querySelector('.game-views');
|
||||
if (viewsElement) {
|
||||
viewsElement.innerHTML = `<i class="fa-solid fa-eye"></i> ${result.data.views}`;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('更新访问次数失败:', error);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.main-top {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background-color: #0081ff;
|
||||
/* background: url('/static/images/top-bg.jpg') no-repeat center center; */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-top-card {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
margin-top: 30px;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.main-top-main {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding-top: 50px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.main-top-main .main-title {
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
max-width: 1000px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.detail-top {
|
||||
max-width: 1400px;
|
||||
/* height: 300px; */
|
||||
margin: 30px auto;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.detail-top-card {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
|
||||
.detail-top-card img {
|
||||
width: 400px;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.detail-top-card-right {
|
||||
/* height: 230px; */
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-left: 20px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.detail-top-card-right-top {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle {}
|
||||
|
||||
.detail-top-card-right-middle .game-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle .game-info .title {
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
color: #42d697;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle .game-info .infos {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle .game-info .infos .infoitem {
|
||||
margin-right: 60px;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle .game-info .infos .infoitem span {
|
||||
color: #7d879c;
|
||||
}
|
||||
|
||||
.detail-middle {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.detail-main {
|
||||
position: relative;
|
||||
top: -200px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.location {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.location a {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.game-detail {
|
||||
padding: 50px;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.game-header {
|
||||
margin-bottom: 30px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.game-title {
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.game-title-1 {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.game-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.game-meta span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.game-meta i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.game-content {
|
||||
line-height: 1.8;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.game-cover {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.game-cover img {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.game-desc {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.game-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 40px;
|
||||
margin: 30px 0;
|
||||
padding: 20px 0;
|
||||
border-top: 1px solid #eee;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.game-actions1 {
|
||||
display: flex;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.game-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.prev-game,
|
||||
.next-game {
|
||||
max-width: 45%;
|
||||
}
|
||||
|
||||
.prev-game a,
|
||||
.next-game a {
|
||||
color: #333 !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.prev-game a:hover,
|
||||
.next-game a:hover {
|
||||
color: #f57005 !important;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn {
|
||||
/* background: #f57005; */
|
||||
color: #fff;
|
||||
padding: 5px 15px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
/* background: #e66600; */
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.codebtn {
|
||||
color: #0d6efd;
|
||||
padding: 15px 30px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #0d6efd;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.codebtn:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.related-games {
|
||||
margin: 40px 0;
|
||||
}
|
||||
|
||||
.related-games h3 {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.related-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.game-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.game-item {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.game-item:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.game-item a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.game-cover img {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.game-info {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.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) {
|
||||
.game-title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.game-list {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
|
||||
.game-meta {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.go-to-top {
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.disclaimers {
|
||||
color: #b1b1b1;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.disclaimer-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.disclaimer-content {
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.disclaimer-content p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.infoitem-value {
|
||||
border: 1px #0d6efd dashed;
|
||||
padding: 3px 6px;
|
||||
font-size: 13px;
|
||||
background-color: #0081ff12;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
{include file="component/foot" /}
|
||||
@@ -0,0 +1,539 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
|
||||
<!-- 简约现代文章中心 -->
|
||||
<div class="modern-games-page">
|
||||
<!-- 简约标题区 -->
|
||||
<div class="modern-header">
|
||||
<div class="container">
|
||||
<h1 class="modern-title">游戏中心</h1>
|
||||
<p class="modern-subtitle">发现精彩游戏世界</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区 -->
|
||||
<div class="container">
|
||||
<div class="modern-layout">
|
||||
<!-- 侧边分类导航 -->
|
||||
<aside class="modern-sidebar">
|
||||
<div class="sidebar-card">
|
||||
<h3 class="sidebar-title">
|
||||
<i class="layui-icon layui-icon-list"></i>
|
||||
<span>分类导航</span>
|
||||
</h3>
|
||||
<ul class="category-menu">
|
||||
{volist name="cate.subCategories" id="subCategory"}
|
||||
<li class="menu-item {$cate.id == $subCategory.id ? 'active' : ''}" data-cateid="{$subCategory.id}">
|
||||
<span>{$subCategory.name}</span>
|
||||
<i class="layui-icon layui-icon-right"></i>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 文章内容区 -->
|
||||
<main class="modern-main">
|
||||
<!-- 文章列表 -->
|
||||
<div class="game-grid" id="gameList">
|
||||
{volist name="cate.subCategories" id="subCategory"}
|
||||
{if $cate.id == $subCategory.id}
|
||||
{if !empty($subCategory.list)}
|
||||
{volist name="subCategory.list" id="game"}
|
||||
<game class="game-card">
|
||||
<div class="card-image">
|
||||
<img src="{$game.icon|default=$subCategory.icon|default='/static/images/default-game.jpg'}" alt="{$game.title}">
|
||||
<div class="image-overlay"></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="meta-info">
|
||||
<span class="category-tag">{$subCategory.name}</span>
|
||||
<time class="publish-date">{$game.create_time|date="Y-m-d"}</time>
|
||||
</div>
|
||||
<h3 class="game-title">{$game.title}</h3>
|
||||
<div class="card-footer">
|
||||
<div class="stats">
|
||||
<span class="views"><i class="layui-icon layui-icon-eye"></i> {$game.views|default=0}</span>
|
||||
<span class="likes"><i class="layui-icon layui-icon-praise"></i> {$game.likes|default=0}</span>
|
||||
</div>
|
||||
<a href="/index/game/detail?id={$game.id}" class="read-more">阅读更多</a>
|
||||
</div>
|
||||
</div>
|
||||
</game>
|
||||
{/volist}
|
||||
{else}
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
</div>
|
||||
<h4>暂无文章</h4>
|
||||
<p>当前分类下没有找到相关文章</p>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/volist}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="modern-pagination" id="pagination"></div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['laypage', 'jquery'], function(){
|
||||
var laypage = layui.laypage;
|
||||
var $ = layui.jquery;
|
||||
|
||||
// 分类切换
|
||||
$('.menu-item').on('click', function() {
|
||||
var cateid = $(this).data('cateid');
|
||||
var $menuItems = $('.menu-item');
|
||||
|
||||
// 更新选中状态
|
||||
$menuItems.removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
// 加载文章
|
||||
loadArticles(cateid, 1);
|
||||
});
|
||||
|
||||
// 页面加载完成后,自动触发第一个分类的点击事件
|
||||
$(document).ready(function() {
|
||||
var $firstMenuItem = $('.menu-item').first();
|
||||
if ($firstMenuItem.length > 0) {
|
||||
$firstMenuItem.click();
|
||||
}
|
||||
});
|
||||
|
||||
// 加载文章函数
|
||||
function loadArticles(cateid, page) {
|
||||
$.ajax({
|
||||
url: '/index/game/list',
|
||||
type: 'POST',
|
||||
data: {
|
||||
cate: cateid,
|
||||
page: page
|
||||
},
|
||||
beforeSend: function() {
|
||||
$('#gameList').html('<div class="loading-state"><i class="layui-icon layui-icon-loading"></i>加载中...</div>');
|
||||
},
|
||||
success: function(res) {
|
||||
if(res.code === 1) {
|
||||
var html = '';
|
||||
if(res.data.games && res.data.games.length > 0) {
|
||||
res.data.games.forEach(function(game) {
|
||||
html += `<game class="game-card">
|
||||
<div class="card-image">
|
||||
<img src="${game.icon || game.category_icon || '/static/images/default-game.jpg'}" alt="${game.title}">
|
||||
<div class="image-overlay"></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="meta-info">
|
||||
<span class="category-tag">${game.category_name || '未分类'}</span>
|
||||
<time class="publish-date">${game.create_time || ''}</time>
|
||||
</div>
|
||||
<h3 class="game-title">${game.title}</h3>
|
||||
<div class="card-footer">
|
||||
<div class="stats">
|
||||
<span class="views"><i class="layui-icon layui-icon-eye"></i> ${game.views || 0}</span>
|
||||
<span class="likes"><i class="layui-icon layui-icon-praise"></i> ${game.likes || 0}</span>
|
||||
</div>
|
||||
<a href="/index/game/detail?id=${game.id}" class="read-more">阅读更多</a>
|
||||
</div>
|
||||
</div>
|
||||
</game>`;
|
||||
});
|
||||
} else {
|
||||
html = `<div class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
</div>
|
||||
<h4>暂无文章</h4>
|
||||
<p>当前分类下没有找到相关文章</p>
|
||||
</div>`;
|
||||
}
|
||||
$('#gameList').html(html);
|
||||
|
||||
// 渲染分页
|
||||
laypage.render({
|
||||
elem: 'pagination',
|
||||
count: res.data.total || 0,
|
||||
limit: res.data.per_page || 12,
|
||||
curr: res.data.current_page || 1,
|
||||
theme: '#1E9FFF',
|
||||
layout: ['prev', 'page', 'next'],
|
||||
jump: function(obj, first) {
|
||||
if(!first) {
|
||||
loadArticles(cateid, obj.curr);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{include file="component/footer" /}
|
||||
|
||||
<style>
|
||||
/* 基础样式重置 */
|
||||
.modern-games-page {
|
||||
font-family: 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
background-color: #f9fafc;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
/* 标题区样式 */
|
||||
.modern-header {
|
||||
background: linear-gradient(135deg, #1E9FFF 0%, #0d8aff 100%);
|
||||
color: white;
|
||||
padding: 80px 0 60px;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 300;
|
||||
margin-bottom: 15px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 300;
|
||||
opacity: 0.9;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 布局结构 */
|
||||
.modern-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 260px 1fr;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
/* 侧边栏样式 */
|
||||
.modern-sidebar {
|
||||
position: sticky;
|
||||
top: 30px;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.sidebar-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.03);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #555;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.sidebar-title i {
|
||||
margin-right: 10px;
|
||||
font-size: 1.2rem;
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.category-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background-color: #f8fafd;
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.menu-item.active {
|
||||
background-color: #f0f7ff;
|
||||
border-left-color: #1E9FFF;
|
||||
color: #1E9FFF;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.menu-item i {
|
||||
font-size: 0.9rem;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.menu-item.active i,
|
||||
.menu-item:hover i {
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
/* 主内容区样式 */
|
||||
.modern-main {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 文章网格布局 */
|
||||
.game-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
/* 文章卡片样式 */
|
||||
.game-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.03);
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.game-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.card-image {
|
||||
height: 180px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.image-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.3), transparent);
|
||||
}
|
||||
|
||||
.game-card:hover .card-image img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 20px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.meta-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.category-tag {
|
||||
background: #f0f7ff;
|
||||
color: #1E9FFF;
|
||||
padding: 3px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.game-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
margin: 0 0 10px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.game-excerpt {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
margin: 0 0 20px;
|
||||
flex: 1;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.stats {
|
||||
font-size: 0.85rem;
|
||||
color: #999;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.stats i {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.read-more {
|
||||
color: #1E9FFF;
|
||||
font-size: 0.9rem;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.read-more:hover {
|
||||
color: #0d8aff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 分页样式 */
|
||||
.modern-pagination {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.layui-laypage a,
|
||||
.layui-laypage span {
|
||||
border-radius: 4px !important;
|
||||
margin: 0 3px !important;
|
||||
}
|
||||
|
||||
.layui-laypage a {
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
.layui-laypage .layui-laypage-curr .layui-laypage-em {
|
||||
background-color: #1E9FFF !important;
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.empty-state {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 3rem;
|
||||
color: #ddd;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.empty-icon i {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.empty-state h4 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
color: #999;
|
||||
font-size: 0.95rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-state {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.loading-state i {
|
||||
font-size: 1.5rem;
|
||||
margin-right: 10px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 992px) {
|
||||
.modern-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.modern-sidebar {
|
||||
position: static;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.game-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.modern-header {
|
||||
padding: 60px 0 40px;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.game-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
{include file="component/foot" /}
|
||||
@@ -0,0 +1,76 @@
|
||||
<div class="container py-5">
|
||||
<div class="row g-4">
|
||||
<!-- 左侧分类列表 -->
|
||||
<div class="col-lg-3">
|
||||
<div class="category-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<i class="layui-icon layui-icon-app"></i>
|
||||
<span>文章分类</span>
|
||||
</div>
|
||||
<div class="category-list">
|
||||
{volist name="categories" id="cate"}
|
||||
<div class="category-item {$category.id == $cate.id ? 'active' : ''}" data-cateid="{$cate.id}">{$cate.name}</div>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧文章列表 -->
|
||||
<div class="col-lg-9">
|
||||
{if $category}
|
||||
<div class="category-header mb-4">
|
||||
<h2 class="category-title">{$category.name}</h2>
|
||||
<p class="category-desc">{$category.desc|default=''}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="article-list">
|
||||
{volist name="games" id="article"}
|
||||
<div class="article-item">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-4">
|
||||
<div class="article-image">
|
||||
<img src="{$article.image|default='/static/images/default.jpg'}" alt="{$article.title}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="article-content">
|
||||
<h3 class="article-title">
|
||||
<a href="/index/game/detail?id={$article.id}">{$article.title}</a>
|
||||
</h3>
|
||||
<p class="article-desc">{$article.desc|default=''}</p>
|
||||
<div class="article-meta">
|
||||
<div class="article-stats">
|
||||
<span><i class="layui-icon layui-icon-eye"></i> {$article.views|default=0}</span>
|
||||
<span><i class="layui-icon layui-icon-praise"></i> {$article.likes|default=0}</span>
|
||||
<span><i class="layui-icon layui-icon-date"></i> {$article.create_time|date="Y-m-d"}</span>
|
||||
</div>
|
||||
<a href="/index/game/detail?id={$article.id}" class="btn-detail">查看详情</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="mt-5">
|
||||
{$games|raw}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['layer'], function () {
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
|
||||
// 分类切换
|
||||
$('.category-item').on('click', function() {
|
||||
var cateid = $(this).data('cateid');
|
||||
window.location.href = '/index/game/list?cate=' + cateid;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,5 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
{include file="component/main" /}
|
||||
{include file="component/footer" /}
|
||||
{include file="component/foot" /}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,535 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
|
||||
<!-- 简约现代文章中心 -->
|
||||
<div class="modern-programs-page">
|
||||
<!-- 简约标题区 -->
|
||||
<div class="modern-header">
|
||||
<div class="container">
|
||||
<h1 class="modern-title">资源中心</h1>
|
||||
<p class="modern-subtitle">发现优质程序与工具</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区 -->
|
||||
<div class="container">
|
||||
<div class="modern-layout">
|
||||
<!-- 侧边分类导航 -->
|
||||
<aside class="modern-sidebar">
|
||||
<div class="sidebar-card">
|
||||
<h3 class="sidebar-title">
|
||||
<i class="layui-icon layui-icon-list"></i>
|
||||
<span>分类导航</span>
|
||||
</h3>
|
||||
<ul class="category-menu">
|
||||
{volist name="cate.subCategories" id="subCategory"}
|
||||
<li class="menu-item {$cate.id == $subCategory.id ? 'active' : ''}" data-cateid="{$subCategory.id}">
|
||||
<span>{$subCategory.name}</span>
|
||||
<i class="layui-icon layui-icon-right"></i>
|
||||
</li>
|
||||
{/volist}
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 文章内容区 -->
|
||||
<main class="modern-main">
|
||||
<!-- 文章列表 -->
|
||||
<div class="article-grid" id="programList">
|
||||
{volist name="cate.subCategories" id="subCategory"}
|
||||
{if $cate.id == $subCategory.id}
|
||||
{if !empty($subCategory.list)}
|
||||
{volist name="subCategory.list" id="program"}
|
||||
<program class="program-card">
|
||||
<div class="card-image">
|
||||
<img src="{$program.icon|default='/static/images/default-program.jpg'}" alt="{$program.title}">
|
||||
<div class="image-overlay"></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="meta-info">
|
||||
<span class="category-tag">{$subCategory.name}</span>
|
||||
<time class="publish-date">{$program.create_time|date="Y-m-d"}</time>
|
||||
</div>
|
||||
<h3 class="program-title">{$program.title}</h3>
|
||||
<div class="card-footer">
|
||||
<div class="stats">
|
||||
<span class="views"><i class="layui-icon layui-icon-eye"></i> {$program.views|default=0}</span>
|
||||
<span class="likes"><i class="layui-icon layui-icon-praise"></i> {$program.likes|default=0}</span>
|
||||
</div>
|
||||
<a href="/index/program/detail?id={$program.id}" class="read-more">阅读更多</a>
|
||||
</div>
|
||||
</div>
|
||||
</program>
|
||||
{/volist}
|
||||
{else}
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
</div>
|
||||
<h4>暂无文章</h4>
|
||||
<p>当前分类下没有找到相关文章</p>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/volist}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="modern-pagination" id="pagination"></div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['laypage', 'jquery'], function(){
|
||||
var laypage = layui.laypage;
|
||||
var $ = layui.jquery;
|
||||
|
||||
// 分类切换
|
||||
$('.menu-item').on('click', function() {
|
||||
var cateid = $(this).data('cateid');
|
||||
var $menuItems = $('.menu-item');
|
||||
|
||||
// 更新选中状态
|
||||
$menuItems.removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
// 加载文章
|
||||
loadArticles(cateid, 1);
|
||||
});
|
||||
|
||||
// 页面加载完成后,自动触发第一个分类的点击事件
|
||||
$(document).ready(function() {
|
||||
var $firstMenuItem = $('.menu-item').first();
|
||||
if ($firstMenuItem.length > 0) {
|
||||
$firstMenuItem.click();
|
||||
}
|
||||
});
|
||||
|
||||
// 加载文章函数
|
||||
function loadArticles(cateid, page) {
|
||||
$.ajax({
|
||||
url: '/index/program/list',
|
||||
type: 'POST',
|
||||
data: {
|
||||
cate: cateid,
|
||||
page: page
|
||||
},
|
||||
beforeSend: function() {
|
||||
$('#programList').html('<div class="loading-state"><i class="layui-icon layui-icon-loading"></i>加载中...</div>');
|
||||
},
|
||||
success: function(res) {
|
||||
if(res.code === 1) {
|
||||
var html = '';
|
||||
if(res.data.programs && res.data.programs.length > 0) {
|
||||
res.data.programs.forEach(function(program) {
|
||||
html += `<program class="program-card">
|
||||
<div class="card-image">
|
||||
<img src="${program.icon || '/static/images/default-program.jpg'}" alt="${program.title}">
|
||||
<div class="image-overlay"></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="meta-info">
|
||||
<span class="category-tag">${program.category_name || '未分类'}</span>
|
||||
<time class="publish-date">${program.create_time || ''}</time>
|
||||
</div>
|
||||
<h3 class="program-title">${program.title}</h3>
|
||||
<div class="card-footer">
|
||||
<div class="stats">
|
||||
<span class="views"><i class="layui-icon layui-icon-eye"></i> ${program.views || 0}</span>
|
||||
<span class="likes"><i class="layui-icon layui-icon-praise"></i> ${program.likes || 0}</span>
|
||||
</div>
|
||||
<a href="/index/program/detail?id=${program.id}" class="read-more">阅读更多</a>
|
||||
</div>
|
||||
</div>
|
||||
</program>`;
|
||||
});
|
||||
} else {
|
||||
html = `<div class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
</div>
|
||||
<h4>暂无文章</h4>
|
||||
<p>当前分类下没有找到相关文章</p>
|
||||
</div>`;
|
||||
}
|
||||
$('#programList').html(html);
|
||||
|
||||
// 渲染分页
|
||||
laypage.render({
|
||||
elem: 'pagination',
|
||||
count: res.data.total || 0,
|
||||
limit: res.data.per_page || 12,
|
||||
curr: res.data.current_page || 1,
|
||||
theme: '#1E9FFF',
|
||||
layout: ['prev', 'page', 'next'],
|
||||
jump: function(obj, first) {
|
||||
if(!first) {
|
||||
loadArticles(cateid, obj.curr);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{include file="component/footer" /}
|
||||
|
||||
<style>
|
||||
/* 基础样式重置 */
|
||||
.modern-programs-page {
|
||||
font-family: 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
background-color: #f9fafc;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
/* 标题区样式 */
|
||||
.modern-header {
|
||||
background: linear-gradient(135deg, #1E9FFF 0%, #0d8aff 100%);
|
||||
color: white;
|
||||
padding: 80px 0 60px;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 300;
|
||||
margin-bottom: 15px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 300;
|
||||
opacity: 0.9;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 布局结构 */
|
||||
.modern-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 260px 1fr;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
/* 侧边栏样式 */
|
||||
.modern-sidebar {
|
||||
position: sticky;
|
||||
top: 30px;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.sidebar-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.03);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #555;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.sidebar-title i {
|
||||
margin-right: 10px;
|
||||
font-size: 1.2rem;
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.category-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background-color: #f8fafd;
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.menu-item.active {
|
||||
background-color: #f0f7ff;
|
||||
border-left-color: #1E9FFF;
|
||||
color: #1E9FFF;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.menu-item i {
|
||||
font-size: 0.9rem;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.menu-item.active i,
|
||||
.menu-item:hover i {
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
/* 主内容区样式 */
|
||||
.modern-main {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 文章网格布局 */
|
||||
.article-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
/* 文章卡片样式 */
|
||||
.article-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.03);
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.article-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.card-image {
|
||||
height: 180px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.image-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.3), transparent);
|
||||
}
|
||||
|
||||
.article-card:hover .card-image img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 20px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.meta-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.category-tag {
|
||||
background: #f0f7ff;
|
||||
color: #1E9FFF;
|
||||
padding: 3px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.program-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
margin: 0 0 10px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.program-excerpt {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
margin: 0 0 20px;
|
||||
flex: 1;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.stats {
|
||||
font-size: 0.85rem;
|
||||
color: #999;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.stats i {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.read-more {
|
||||
color: #1E9FFF;
|
||||
font-size: 0.9rem;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.read-more:hover {
|
||||
color: #0d8aff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 分页样式 */
|
||||
.modern-pagination {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.layui-laypage a,
|
||||
.layui-laypage span {
|
||||
border-radius: 4px !important;
|
||||
margin: 0 3px !important;
|
||||
}
|
||||
|
||||
.layui-laypage a {
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
.layui-laypage .layui-laypage-curr .layui-laypage-em {
|
||||
background-color: #1E9FFF !important;
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.empty-state {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 3rem;
|
||||
color: #ddd;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.empty-icon i {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.empty-state h4 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
color: #999;
|
||||
font-size: 0.95rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-state {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.loading-state i {
|
||||
font-size: 1.5rem;
|
||||
margin-right: 10px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 1200px) {
|
||||
.article-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.modern-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.modern-sidebar {
|
||||
position: static;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.article-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.article-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
{include file="component/foot" /}
|
||||
@@ -0,0 +1,261 @@
|
||||
<div class="container py-5">
|
||||
<div class="row g-4">
|
||||
<!-- 左侧分类列表 -->
|
||||
<div class="col-lg-3">
|
||||
<div class="category-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<i class="layui-icon layui-icon-app"></i>
|
||||
<span>程序分类</span>
|
||||
</div>
|
||||
<div class="category-list">
|
||||
{volist name="categories" id="cate"}
|
||||
<div class="category-item {$category.id == $cate.id ? 'active' : ''}" data-cateid="{$cate.id}">{$cate.name}</div>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧程序列表 -->
|
||||
<div class="col-lg-9">
|
||||
{if $category}
|
||||
<div class="category-header mb-4">
|
||||
<h2 class="category-title">{$category.name}</h2>
|
||||
<p class="category-desc">{$category.desc|default=''}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="program-list">
|
||||
{if empty($programs)}
|
||||
<div class="empty-state">
|
||||
<i class="layui-icon layui-icon-face-surprised"></i>
|
||||
<p>暂无程序</p>
|
||||
</div>
|
||||
{else}
|
||||
{volist name="programs" id="program"}
|
||||
<div class="program-item">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-4">
|
||||
<div class="program-image">
|
||||
<img src="{$program.icon}" alt="{$program.title}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="program-content">
|
||||
<h3 class="program-title">
|
||||
<a href="/index/program/detail?id={$program.id}">{$program.title}</a>
|
||||
</h3>
|
||||
<p class="program-desc">{$program.desc|default=''}</p>
|
||||
<div class="program-meta">
|
||||
<div class="program-stats">
|
||||
<span><i class="layui-icon layui-icon-eye"></i> {$program.views|default=0}</span>
|
||||
<span><i class="layui-icon layui-icon-download-circle"></i> {$program.downloads|default=0}</span>
|
||||
<span><i class="layui-icon layui-icon-date"></i> {$program.create_time|date="Y-m-d"}</span>
|
||||
</div>
|
||||
<a href="/index/program/detail?id={$program.id}" class="btn-detail">查看详情</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
{if !empty($programs)}
|
||||
<div class="mt-5">
|
||||
{$programs->render()|raw}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.program-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.program-item {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.program-item:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.program-image {
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.program-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.program-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.program-title {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.program-title a {
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.program-title a:hover {
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.program-desc {
|
||||
color: #666;
|
||||
margin-bottom: 15px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.program-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.program-stats {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.program-stats span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.btn-detail {
|
||||
padding: 6px 15px;
|
||||
background: #1E9FFF;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-detail:hover {
|
||||
background: #0d8aff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.category-sidebar {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.category-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
padding: 10px 15px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.category-item:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.category-item.active {
|
||||
background: #1E9FFF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.category-header {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.category-title {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.category-desc {
|
||||
margin: 10px 0 0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.empty-state i {
|
||||
font-size: 48px;
|
||||
color: #999;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
color: #666;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['layer'], function () {
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
|
||||
// 分类切换
|
||||
$('.category-item').on('click', function() {
|
||||
var cateid = $(this).data('cateid');
|
||||
window.location.href = '/index/program/list?cate=' + cateid;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
// 页面加载完成后,自动触发第一个分类的点击事件
|
||||
$(document).ready(function() {
|
||||
var $firstMenuItem = $('.category-item').first();
|
||||
if ($firstMenuItem.length > 0) {
|
||||
$firstMenuItem.click();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,956 @@
|
||||
{include file="component/head" /}
|
||||
<link href="__STATIC__/css/lightbox.min.css" rel="stylesheet">
|
||||
<link href="__CSS__/swiper-bundle.min.css" rel="stylesheet">
|
||||
<script src="__JS__/jquery.min.js"></script>
|
||||
<script src="__JS__/lightbox.min.js"></script>
|
||||
<script src="__JS__/swiper-bundle.min.js"></script>
|
||||
{include file="component/header" /}
|
||||
<div class="main">
|
||||
<div class="main-top">
|
||||
<div class="main-top-main">
|
||||
<div class="main-title">
|
||||
<?php echo $resources['title']; ?>
|
||||
</div>
|
||||
<div class="location">
|
||||
<div class="container">
|
||||
<div class="location-item">
|
||||
<a href="/">首页</a>
|
||||
<span>></span>
|
||||
<a href="/index/resources/list" id="cateLink"><?php echo $cateName; ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-main">
|
||||
<div class="detail-top">
|
||||
<div class="detail-top-left">
|
||||
<div class="detail-top-card">
|
||||
<div class="detail-top-card-left">
|
||||
<div class="article-cover">
|
||||
<div class="swiper resources-swiper">
|
||||
<div class="swiper-wrapper">
|
||||
{php}
|
||||
// 兼容字符串和数组
|
||||
$images = isset($resources['images']) ? $resources['images'] : [];
|
||||
if (is_string($images)) {
|
||||
$images = explode(',', $images);
|
||||
}
|
||||
$images = array_filter($images); // 移除空值
|
||||
if (empty($images) && !empty($resources['icon'])) {
|
||||
$images = [$resources['icon']];
|
||||
}
|
||||
{/php}
|
||||
{volist name="images" id="image"}
|
||||
<div class="swiper-slide">
|
||||
<a href="<?php $img = trim($image, ', ');
|
||||
echo (strpos($img, 'http') === 0 ? $img : request()->domain() . $img); ?>"
|
||||
data-lightbox="resources-gallery">
|
||||
<img src="<?php $img = trim($image, ', ');
|
||||
echo (strpos($img, 'http') === 0 ? $img : request()->domain() . $img); ?>"
|
||||
alt="<?php echo $resources['title']; ?>">
|
||||
</a>
|
||||
</div>
|
||||
{/volist}
|
||||
</div>
|
||||
<div class="swiper-button-prev"></div>
|
||||
<div class="swiper-button-next"></div>
|
||||
<div class="swiper-pagination"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-top-card-right">
|
||||
<!-- <div class="detail-top-card-right-top">
|
||||
<div class="collect-btn">
|
||||
<button class="btn btn-primary" id="collectBtn"
|
||||
data-resources-id="<?php echo $resources['id']; ?>">
|
||||
<i class="fa-solid fa-heart"></i> 收藏
|
||||
</button>
|
||||
</div>
|
||||
<div class="report-btn">
|
||||
<button class="btn btn-primary" id="reportBtn" style="margin-left: 20px;">
|
||||
<i class="fa-solid fa-flag"></i> 举报
|
||||
</button>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="detail-top-card-right-middle">
|
||||
<div class="resources-info">
|
||||
<div class="title">Free</div>
|
||||
<div class="infos">
|
||||
<div style="display: flex;">
|
||||
<div class="infoitem">
|
||||
<span>程序编号:</span>
|
||||
<span class="infoitem-value"><?php echo $resources['number']; ?></span>
|
||||
</div>
|
||||
<div class="infoitem">
|
||||
<span>所属分类:</span>
|
||||
<span class="infoitem-value"><?php echo $cateName; ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex;">
|
||||
<div class="infoitem">
|
||||
<span>更新时间:</span>
|
||||
<span
|
||||
class="infoitem-value"><?php echo date('Y-m-d', $resources['create_time']); ?></span>
|
||||
</div>
|
||||
<div class="infoitem">
|
||||
<span>查看:</span>
|
||||
<span class="infoitem-value"><?php echo $resources['views']; ?></span>
|
||||
<span>次</span>
|
||||
</div>
|
||||
<div class="infoitem">
|
||||
<span>下载:</span>
|
||||
<span class="infoitem-value"><?php echo $resources['downloads']; ?></span>
|
||||
<span>次</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-top-card-right-bottom">
|
||||
<div class="resources-actions1">
|
||||
<div style="display: flex;gap: 30px;}">
|
||||
<button id="downloadBtn" class="btn btn-primary">
|
||||
<i class="fa-solid fa-download"></i> 立即下载
|
||||
</button>
|
||||
<button id="codeBtn" class="codebtn">
|
||||
<i class="fa-solid fa-download"></i> 分享码:<?php echo $resources['code']; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-top-right">
|
||||
<div class="aboutauthor-main">
|
||||
<div class="aboutauthor-main-top">
|
||||
<div class="aboutauthor-avatar">
|
||||
<img src="{$authorInfo.avatar}" alt="作者头像">
|
||||
</div>
|
||||
<div class="aboutauthor-info">
|
||||
<div class="author-name">{$authorInfo.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aboutauthor-main-middle">
|
||||
<div class="author-stats">
|
||||
|
||||
<div class="author-stats-item">
|
||||
<h6>资源</h6>
|
||||
<span class="count">{$authorInfo.resource_count}</span>
|
||||
</div>
|
||||
<div class="author-stats-item">
|
||||
<h6>文章</h6>
|
||||
<span class="count">{$authorInfo.article_count}</span>
|
||||
</div>
|
||||
<div class="author-stats-item">
|
||||
<h6>粉丝</h6>
|
||||
<span class="count">
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aboutauthor-btn">
|
||||
<button class="follow-btn">
|
||||
<i class="fa fa-user-plus"></i> 关注他
|
||||
</button>
|
||||
<button class="message-btn">
|
||||
<i class="fa fa-envelope"></i> 发私信
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-middle">
|
||||
<div class="detial-middle-left">
|
||||
<div class="resources-detail">
|
||||
<div class="resources-info">
|
||||
<div class="resources-content">
|
||||
<div class="resources-desc">
|
||||
<?php echo $resources['content']; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resources-actions">
|
||||
<div style="display: flex;gap: 30px;}">
|
||||
<button id="downloadBtn" class="btn btn-primary">
|
||||
<i class="fa-solid fa-download"></i> 立即下载
|
||||
</button>
|
||||
<button id="codeBtn" class="codebtn">
|
||||
<i class="fa-solid fa-download"></i> 分享码:<?php echo $resources['code']; ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="disclaimers">
|
||||
<div class="disclaimer-item">
|
||||
<div class="disclaimer-title">免责声明:</div>
|
||||
<div class="disclaimer-content">
|
||||
<?php echo $config['disclaimers'] ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resources-navigation">
|
||||
<div class="prev-resources" id="prevResources">
|
||||
</div>
|
||||
<div class="next-resources" id="nextResources">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 相关资源 -->
|
||||
<?php if (!empty($relatedResourcess)): ?>
|
||||
<div class="related-resourcess">
|
||||
<h3>相关资源</h3>
|
||||
<div class="resources-list">
|
||||
<?php foreach ($relatedResourcess as $related): ?>
|
||||
<div class="resources-item"
|
||||
onclick="window.location.href='/index/resources/detail?id=<?php echo $related['id']; ?>'">
|
||||
<div class="resources-cover">
|
||||
<img src="<?php echo $related['icon'] ?: '/static/images/default-resources.png'; ?>"
|
||||
alt="<?php echo $related['title']; ?>">
|
||||
</div>
|
||||
<div class="resources-info">
|
||||
<h4 class="resources-title-1"><?php echo $related['title']; ?></h4>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detial-middle-right">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 返回顶部按钮 -->
|
||||
<div class="go-to-top" id="goToTop">
|
||||
<i class="layui-icon layui-icon-top"></i>
|
||||
</div>
|
||||
|
||||
{include file="component/footer" /}
|
||||
|
||||
<script>
|
||||
// 页面加载完成后执行
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
// 获取资源ID
|
||||
const resourcesId = new URLSearchParams(window.location.search).get('id');
|
||||
if (!resourcesId) {
|
||||
alert('资源ID不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取资源详情
|
||||
fetch('/index/resources/detail?id=' + resourcesId, {
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.code === 1) {
|
||||
// 渲染上一篇
|
||||
const prevResources = document.getElementById('prevResources');
|
||||
if (result.data.prevResources) {
|
||||
prevResources.innerHTML = `
|
||||
<a href="/index/resources/detail?id=${result.data.prevResources.id}">
|
||||
<i class="fa fa-arrow-left"></i> 上一篇:${result.data.prevResources.title}
|
||||
</a>
|
||||
`;
|
||||
} else {
|
||||
prevResources.innerHTML = '<span class="disabled"><i class="fa fa-arrow-left"></i> 没有上一篇了</span>';
|
||||
}
|
||||
|
||||
// 渲染下一篇
|
||||
const nextResources = document.getElementById('nextResources');
|
||||
if (result.data.nextResources) {
|
||||
nextResources.innerHTML = `
|
||||
<a href="/index/resources/detail?id=${result.data.nextResources.id}">
|
||||
下一篇:${result.data.nextResources.title} <i class="fa fa-arrow-right"></i>
|
||||
</a>
|
||||
`;
|
||||
} else {
|
||||
nextResources.innerHTML = '<span class="disabled">没有下一篇了 <i class="fa fa-arrow-right"></i></span>';
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('获取资源详情失败:', error);
|
||||
});
|
||||
|
||||
// 更新访问次数
|
||||
updateResourcesViews(resourcesId);
|
||||
|
||||
// 下载功能
|
||||
const downloadBtn = document.getElementById('downloadBtn');
|
||||
if (downloadBtn) {
|
||||
downloadBtn.addEventListener('click', function () {
|
||||
fetch('/index/resources/downloadurl?id=' + resourcesId, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('网络响应失败');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (data.code === 1) {
|
||||
const downloadsElement = document.getElementById('resourcesDownloads');
|
||||
if (downloadsElement) {
|
||||
let downloads = parseInt(downloadsElement.textContent);
|
||||
downloadsElement.textContent = downloads + 1;
|
||||
}
|
||||
|
||||
// 直接使用返回的URL
|
||||
if (data.data && data.data.url) {
|
||||
window.open(data.data.url, '_blank');
|
||||
} else {
|
||||
alert('下载地址不存在');
|
||||
}
|
||||
} else {
|
||||
alert('下载失败:' + data.msg);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('下载请求失败:', error);
|
||||
alert('下载请求失败,请稍后重试');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const swiper = new Swiper('.resources-swiper', {
|
||||
slidesPerView: 1,
|
||||
spaceBetween: 30,
|
||||
loop: true,
|
||||
autoplay: {
|
||||
delay: 3000,
|
||||
disableOnInteraction: false,
|
||||
},
|
||||
pagination: {
|
||||
el: '.swiper-pagination',
|
||||
clickable: true,
|
||||
},
|
||||
navigation: {
|
||||
nextEl: '.swiper-button-next',
|
||||
prevEl: '.swiper-button-prev',
|
||||
},
|
||||
});
|
||||
|
||||
// 初始化 Lightbox
|
||||
lightbox.option({
|
||||
'resizeDuration': 200,
|
||||
'wrapAround': true,
|
||||
'albumLabel': "图片 %1 / %2",
|
||||
'fadeDuration': 300,
|
||||
'imageFadeDuration': 300,
|
||||
'positionFromTop': 100,
|
||||
'maxWidth': 1200,
|
||||
'maxHeight': 800,
|
||||
'disableScrolling': true,
|
||||
'showImageNumberLabel': true,
|
||||
'alwaysShowNavOnTouchDevices': true
|
||||
});
|
||||
|
||||
//复制分享码
|
||||
const codeBtn = document.getElementById('codeBtn');
|
||||
if (codeBtn) {
|
||||
codeBtn.addEventListener('click', function () {
|
||||
const code = '<?php echo $resources['code']; ?>';
|
||||
if (code) {
|
||||
// 创建一个临时输入框
|
||||
const tempInput = document.createElement('input');
|
||||
tempInput.value = code;
|
||||
document.body.appendChild(tempInput);
|
||||
tempInput.select();
|
||||
|
||||
try {
|
||||
// 尝试使用传统的复制方法
|
||||
document.execCommand('copy');
|
||||
layer.msg('分享码已复制到剪贴板');
|
||||
} catch (err) {
|
||||
console.error('复制失败:', err);
|
||||
layer.msg('复制失败,请手动复制');
|
||||
} finally {
|
||||
// 移除临时输入框
|
||||
document.body.removeChild(tempInput);
|
||||
}
|
||||
} else {
|
||||
layer.msg('分享码不存在');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 返回顶部功能
|
||||
const goToTop = document.getElementById('goToTop');
|
||||
if (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 updateResourcesViews(resourcesId) {
|
||||
fetch('/index/resources/updateViews', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: 'id=' + resourcesId
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.code === 1) {
|
||||
const viewsElement = document.querySelector('.resources-views');
|
||||
if (viewsElement) {
|
||||
viewsElement.innerHTML = `<i class="fa-solid fa-eye"></i> ${result.data.views}`;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('更新访问次数失败:', error);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.main-top {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background-color: #0081ff;
|
||||
/* background: url('/static/images/top-bg.jpg') no-repeat center center; */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-top-card {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
margin-top: 30px;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.main-top-main {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding-top: 50px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.main-top-main .main-title {
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
max-width: 1000px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.detail-top {
|
||||
max-width: 1400px;
|
||||
/* height: 300px; */
|
||||
margin: 30px auto;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.detail-top-left {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.detail-top-right {
|
||||
width: 30%;
|
||||
border-left: 1px solid #eee;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.detail-top-card {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
|
||||
.detail-top-card img {
|
||||
width: 350px;
|
||||
height: 260px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.detail-top-card-right {
|
||||
/* height: 230px; */
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-left: 20px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.detail-top-card-right-top {
|
||||
display: flex;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle {}
|
||||
|
||||
.detail-top-card-right-middle .resources-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle .resources-info .title {
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
color: #42d697;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle .resources-info .infos {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle .resources-info .infos .infoitem {
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.detail-top-card-right-middle .resources-info .infos .infoitem span {
|
||||
color: #7d879c;
|
||||
}
|
||||
|
||||
.detail-middle {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.detail-main {
|
||||
position: relative;
|
||||
top: -200px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.location {
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.location a {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.resources-detail {
|
||||
padding: 50px;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.resources-header {
|
||||
margin-bottom: 30px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.resources-title {
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.resources-title-1 {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.resources-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.resources-meta span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.resources-meta i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.resources-content {
|
||||
line-height: 1.8;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.resources-cover {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.resources-cover img {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.resources-desc {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.resources-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 40px;
|
||||
margin: 30px 0;
|
||||
padding: 20px 0;
|
||||
border-top: 1px solid #eee;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.resources-actions1 {
|
||||
display: flex;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.resources-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.prev-resources,
|
||||
.next-resources {
|
||||
max-width: 45%;
|
||||
}
|
||||
|
||||
.prev-resources a,
|
||||
.next-resources a {
|
||||
color: #333 !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.prev-resources a:hover,
|
||||
.next-resources a:hover {
|
||||
color: #f57005 !important;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn {
|
||||
/* background: #f57005; */
|
||||
color: #fff;
|
||||
padding: 5px 15px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
/* background: #e66600; */
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.codebtn {
|
||||
color: #0d6efd;
|
||||
padding: 15px 30px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #0d6efd;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.codebtn:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.related-resourcess {
|
||||
margin: 40px 0;
|
||||
}
|
||||
|
||||
.related-resourcess h3 {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.related-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.resources-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.resources-item {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.resources-item:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.resources-item a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.resources-cover img {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.resources-info {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.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) {
|
||||
.resources-title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.resources-list {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
|
||||
.resources-meta {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.go-to-top {
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.disclaimers {
|
||||
color: #b1b1b1;
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.disclaimer-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.disclaimer-content {
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.disclaimer-content p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.infoitem-value {
|
||||
border: 1px #0d6efd dashed;
|
||||
padding: 3px 6px;
|
||||
font-size: 13px;
|
||||
background-color: #0081ff12;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.detail-top-card-left {
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.swiper .swiper-button-prev,
|
||||
.swiper .swiper-button-next {
|
||||
color: #3881fd;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.swiper .swiper-button-prev:after,
|
||||
.swiper .swiper-button-next:after {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* about author css */
|
||||
.detail-top-right .aboutauthor-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-main .aboutauthor-main-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 20px !important;
|
||||
padding: 20px 0;
|
||||
border-bottom: 1px solid #efefef;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-main .aboutauthor-main-top .aboutauthor-avatar {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-main .aboutauthor-main-top .aboutauthor-info .author-name {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-main .aboutauthor-main-top .aboutauthor-avatar img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
margin: 0px;
|
||||
min-width: 0px;
|
||||
max-width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-main .aboutauthor-main-middle {
|
||||
/* margin-left: 20px; */
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-main .aboutauthor-main-middle .author-stats {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-main .aboutauthor-main-middle .author-stats .author-stats-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-main .aboutauthor-main-middle .author-stats .author-stats-item .count {
|
||||
/* font-size: 30px; */
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-btn {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-btn .follow-btn {
|
||||
background-color: #0081ff;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.detail-top-right .aboutauthor-btn .message-btn {
|
||||
color: #0081ff;
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
</style>
|
||||
|
||||
{include file="component/foot" /}
|
||||
@@ -0,0 +1,357 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
|
||||
<!-- 简约现代资源中心 -->
|
||||
<div class="modern-resources-page">
|
||||
<!-- 简约标题区 -->
|
||||
<div class="modern-header">
|
||||
<div class="container">
|
||||
<h1 class="modern-title">资源中心</h1>
|
||||
<p class="modern-subtitle">网络天下资源,一站式搜索</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区 -->
|
||||
<div class="container">
|
||||
{volist name="categories" id="category"}
|
||||
<div class="category-section">
|
||||
<div class="category-header">
|
||||
<div class="category-info">
|
||||
<h2 class="category-title">{$category.parent.name}</h2>
|
||||
</div>
|
||||
<div class="category-count">
|
||||
<span class="count-badge">{$category.subCategories|count} 个分类</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resource-grid">
|
||||
{volist name="category.subCategories" id="subCategory"}
|
||||
<a href="/index/resources/list?cid={$subCategory.id}" class="resource-card">
|
||||
<div class="card-image">
|
||||
<img src="{$subCategory.icon|default='/static/images/default-resource.jpg'}" alt="{$subCategory.name}">
|
||||
<div class="image-overlay"></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="meta-info">
|
||||
</div>
|
||||
<h3 class="resource-title">{$subCategory.name}</h3>
|
||||
<div class="card-footer">
|
||||
<div class="resource-stats">
|
||||
<span class="stat-item">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
<span>{$subCategory.resource_count} 个资源</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="view-more">
|
||||
<span>查看资源</span>
|
||||
<i class="layui-icon layui-icon-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* 基础样式重置 */
|
||||
.modern-resources-page {
|
||||
font-family: 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
background-color: #f9fafc;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
/* 标题区样式 */
|
||||
.modern-header {
|
||||
background: linear-gradient(135deg, #1E9FFF 0%, #0d8aff 100%);
|
||||
color: white;
|
||||
padding: 150px 0;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modern-header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: url('/static/images/pattern.png') repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 300;
|
||||
margin-bottom: 15px;
|
||||
letter-spacing: 1px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 300;
|
||||
opacity: 0.9;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 分类区块样式 */
|
||||
.category-section {
|
||||
margin-bottom: 60px;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.category-header {
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.category-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.category-title {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.category-subtitle {
|
||||
font-size: 1rem;
|
||||
color: #666;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.category-count {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.count-badge {
|
||||
background: #f0f7ff;
|
||||
color: #1E9FFF;
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 资源网格布局 */
|
||||
.resource-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
/* 资源卡片样式 */
|
||||
.resource-card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.03);
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
border: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.resource-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
|
||||
border-color: #e6f7ff;
|
||||
}
|
||||
|
||||
.card-image {
|
||||
height: 180px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.card-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.image-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.3), transparent);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.status-badge.active {
|
||||
background: rgba(82, 196, 26, 0.9);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-badge.inactive {
|
||||
background: rgba(255, 77, 79, 0.9);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.resource-card:hover .card-image img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 20px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.meta-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.resource-number {
|
||||
background: #f0f7ff;
|
||||
color: #1E9FFF;
|
||||
padding: 3px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.resource-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
margin: 0 0 15px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: auto;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.resource-stats {
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.stat-item i {
|
||||
font-size: 1rem;
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.view-more {
|
||||
color: #1E9FFF;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.view-more i {
|
||||
font-size: 0.8rem;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.resource-card:hover .view-more i {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 1200px) {
|
||||
.resource-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.resource-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.category-section {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.resource-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.category-title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.category-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.category-count {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
h2{
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
{include file="component/foot" /}
|
||||
@@ -0,0 +1,306 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
|
||||
<!-- 简约现代资源列表页 -->
|
||||
<div class="modern-resources-page">
|
||||
<!-- 简约标题区 -->
|
||||
<div class="modern-header">
|
||||
<div class="container">
|
||||
<h1 class="modern-title">{$category.name}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区 -->
|
||||
<div class="container">
|
||||
<div class="modern-layout">
|
||||
<!-- 资源列表网格 -->
|
||||
<div class="resource-grid" id="resourceList">
|
||||
{volist name="data" id="resource"}
|
||||
<div class="resource-card">
|
||||
<div class="card-image">
|
||||
<img src="{$resource.icon|default='/static/images/default-resource.jpg'}"
|
||||
alt="{$resource.title}">
|
||||
<div class="image-overlay"></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="meta-info">
|
||||
<span class="resource-number">{$resource.number}</span>
|
||||
<time class="create-date">{$resource.create_time|date="Y-m-d"}</time>
|
||||
</div>
|
||||
<h3 class="resource-title">{$resource.title}</h3>
|
||||
<div class="card-footer">
|
||||
<div class="resource-stats">
|
||||
<span class="stat-item">
|
||||
<i class="layui-icon layui-icon-template-1"></i>
|
||||
<span>资源详情</span>
|
||||
</span>
|
||||
</div>
|
||||
<a href="/index/resources/detail?id={$resource.id}" class="view-more">
|
||||
<span>查看详情</span>
|
||||
<i class="layui-icon layui-icon-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
{$page|raw}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* 基础样式重置 */
|
||||
.modern-resources-page {
|
||||
font-family: 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
background-color: #f9fafc;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
/* 标题区样式 */
|
||||
.modern-header {
|
||||
background: linear-gradient(135deg, #1E9FFF 0%, #0d8aff 100%);
|
||||
color: white;
|
||||
padding: 150px 0;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modern-header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: url('/static/images/pattern.png') repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 300;
|
||||
margin-bottom: 15px;
|
||||
letter-spacing: 1px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 300;
|
||||
opacity: 0.9;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 资源网格布局 */
|
||||
.resource-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 25px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
/* 资源卡片样式 */
|
||||
.resource-card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.03);
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.resource-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
|
||||
border-color: #e6f7ff;
|
||||
}
|
||||
|
||||
.card-image {
|
||||
height: 180px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.card-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.image-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.3), transparent);
|
||||
}
|
||||
|
||||
.resource-card:hover .card-image img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 20px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.meta-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.resource-number {
|
||||
background: #f0f7ff;
|
||||
color: #1E9FFF;
|
||||
padding: 3px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.resource-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
margin: 0 0 15px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
padding-top: 10px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: normal;
|
||||
max-height: 3.2em;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: auto;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.resource-stats {
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.stat-item i {
|
||||
font-size: 1rem;
|
||||
color: #1E9FFF;
|
||||
}
|
||||
|
||||
.view-more {
|
||||
color: #1E9FFF;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.view-more i {
|
||||
font-size: 0.8rem;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.resource-card:hover .view-more i {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
/* 分页样式 */
|
||||
.pagination-container {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.pagination-container .pagination {
|
||||
display: inline-flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.pagination-container .pagination a,
|
||||
.pagination-container .pagination span {
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.pagination-container .pagination a:hover {
|
||||
background: #f0f7ff;
|
||||
color: #1E9FFF;
|
||||
border-color: #e6f7ff;
|
||||
}
|
||||
|
||||
.pagination-container .pagination .active {
|
||||
background: #1E9FFF;
|
||||
color: white;
|
||||
border-color: #1E9FFF;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 1200px) {
|
||||
.resource-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.resource-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.resource-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.modern-title {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.modern-subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
{include file="component/foot" /}
|
||||
@@ -0,0 +1,132 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
<div class="layui-container" style="padding: 20px 0;">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<!-- 搜索头部 -->
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header" style="display: flex; align-items: center;">
|
||||
<h6 class="layui-inline" style="margin-bottom: 0;padding:10px 0;">搜索结果:{$keyword}</h6>
|
||||
<!-- <div class="layui-inline" style="float: right;">
|
||||
<a href="/index/search/list?keyword={$keyword}&type=article" class="layui-btn layui-btn-sm {$type == 'article' ? 'layui-btn-normal' : 'layui-btn-primary'}">文章</a>
|
||||
<a href="/index/search/list?keyword={$keyword}&type=resource" class="layui-btn layui-btn-sm {$type == 'resource' ? 'layui-btn-normal' : 'layui-btn-primary'}">资源</a>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 搜索结果列表 -->
|
||||
<div class="layui-row layui-col-space20" style="margin-top: 20px;">
|
||||
{if $items}
|
||||
{volist name="items" id="item"}
|
||||
<div class="layui-col-md12">
|
||||
<div class="search-result-item" onclick="window.location.href='<?php echo $type == 'articles' ? url('articles/detail', ['id' => $item['id']]) : $item['detail_url'] ?>'">
|
||||
<div class="search-result-image">
|
||||
<?php if($type == 'article'): ?>
|
||||
<img src="<?php echo $item['image'] ?: '/static/images/default.jpg' ?>" alt="<?php echo $item['title'] ?>">
|
||||
<?php else: ?>
|
||||
<img src="<?php echo $item['icon'] ?: '/static/images/default.jpg' ?>" alt="<?php echo $item['title'] ?>">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="search-result-content">
|
||||
<h3 class="search-result-title"><?php echo $item['title'] ?></h3>
|
||||
<div class="search-result-meta">
|
||||
<span class="layui-badge layui-bg-blue"><?php echo $item['cate'] ?></span>
|
||||
<?php if($type == 'article'): ?>
|
||||
<span class="layui-badge layui-bg-green">作者:<?php echo $item['author'] ?></span>
|
||||
<?php else: ?>
|
||||
<span class="layui-badge layui-bg-green">上传者:<?php echo $item['uploader'] ?></span>
|
||||
<?php endif; ?>
|
||||
<span class="layui-badge layui-bg-gray"><?php echo $item['publishdate'] ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/volist}
|
||||
{else}
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body" style="text-align: center; padding: 50px 0;">
|
||||
<i class="layui-icon layui-icon-face-surprised" style="font-size: 48px; color: #999;"></i>
|
||||
<p style="margin-top: 15px; color: #999;">暂无相关{$type == 'article' ? '文章' : '资源'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div id="pagination" style="text-align: center; margin-top: 20px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{include file="component/footer" /}
|
||||
{include file="component/foot" /}
|
||||
|
||||
<script>
|
||||
layui.use(['laypage'], function(){
|
||||
var laypage = layui.laypage;
|
||||
|
||||
//执行一个laypage实例
|
||||
laypage.render({
|
||||
elem: 'pagination',
|
||||
count: {$count},
|
||||
limit: {$limit},
|
||||
curr: {$page},
|
||||
jump: function(obj, first){
|
||||
if(!first){
|
||||
var url = '/index/search/list?keyword={$keyword}&type={$type}&page=' + obj.curr + '&limit=' + obj.limit;
|
||||
window.location.href = url;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.search-result-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.search-result-item:hover {
|
||||
background-color:rgb(255, 255, 255);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 2px 8px rgba(0, 174, 255, 0.5);
|
||||
}
|
||||
|
||||
.search-result-image {
|
||||
margin-right: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.search-result-image img {
|
||||
width: 250px;
|
||||
height: 140px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.search-result-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.search-result-title {
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.search-result-meta {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-result-meta .layui-badge {
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,268 @@
|
||||
<div class="avatar-section">
|
||||
<h2 class="section-title">修改头像</h2>
|
||||
|
||||
<div class="avatar-upload-container">
|
||||
<div class="current-avatar">
|
||||
<img src="{$user.avatar|default='/static/images/avatar.png'}" alt="当前头像" id="currentAvatar">
|
||||
<p class="avatar-tip">当前头像</p>
|
||||
</div>
|
||||
|
||||
<div class="upload-area" id="uploadArea">
|
||||
<i class="layui-icon layui-icon-upload"></i>
|
||||
<p>点击或拖拽图片到此处上传</p>
|
||||
<p class="upload-tip">支持 jpg、png、gif 格式,大小不超过 2MB</p>
|
||||
<input type="file" id="avatarFile" accept="image/*" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="avatar-preview" style="display: none;">
|
||||
<h3>预览</h3>
|
||||
<div class="preview-container">
|
||||
<img src="" alt="预览图" id="previewImage">
|
||||
</div>
|
||||
<div class="preview-actions">
|
||||
<button class="layui-btn" id="confirmUpload">确认上传</button>
|
||||
<button class="layui-btn layui-btn-primary" id="cancelUpload">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.avatar-section {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.avatar-upload-container {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.current-avatar {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.current-avatar img {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 3px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.avatar-tip {
|
||||
margin-top: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
flex: 1;
|
||||
border: 2px dashed #d9d9d9;
|
||||
border-radius: 8px;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-area:hover {
|
||||
border-color: #1677ff;
|
||||
}
|
||||
|
||||
.upload-area .layui-icon {
|
||||
font-size: 48px;
|
||||
color: #999;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.upload-area p {
|
||||
margin: 8px 0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.upload-tip {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.avatar-preview {
|
||||
margin-top: 32px;
|
||||
padding-top: 32px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.avatar-preview h3 {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.preview-container img {
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.preview-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preview-actions .layui-btn {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.avatar-upload-container {
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.current-avatar img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['upload', 'layer'], function () {
|
||||
var upload = layui.upload;
|
||||
var layer = layui.layer;
|
||||
|
||||
// 点击上传区域触发文件选择
|
||||
document.getElementById('uploadArea').addEventListener('click', function () {
|
||||
document.getElementById('avatarFile').click();
|
||||
});
|
||||
|
||||
// 处理文件选择
|
||||
document.getElementById('avatarFile').addEventListener('change', function (e) {
|
||||
var file = e.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// 检查文件类型
|
||||
if (!['image/jpeg', 'image/png', 'image/gif', 'image/webp'].includes(file.type)) {
|
||||
layer.msg('请上传 jpg、png、webp 或 gif 格式的图片');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查文件大小
|
||||
if (file.size > 2 * 1024 * 1024) {
|
||||
layer.msg('图片大小不能超过 2MB');
|
||||
return;
|
||||
}
|
||||
|
||||
// 预览图片
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
document.getElementById('previewImage').src = e.target.result;
|
||||
document.querySelector('.avatar-preview').style.display = 'block';
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
// 确认上传
|
||||
document.getElementById('confirmUpload').addEventListener('click', function () {
|
||||
var file = document.getElementById('avatarFile').files[0];
|
||||
if (!file) return;
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('avatar', file);
|
||||
|
||||
// 显示上传中
|
||||
var loadIndex = layer.load(2);
|
||||
|
||||
// 发送上传请求
|
||||
fetch('/index/user/update_avatar', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
layer.close(loadIndex);
|
||||
if (data.code === 0) {
|
||||
// 更新cookie中的头像
|
||||
document.cookie = "user_avatar=" + data.data.url + "; path=/";
|
||||
|
||||
// 更新localStorage中的头像
|
||||
localStorage.setItem('user_avatar', data.data.url);
|
||||
|
||||
layer.msg('头像上传成功', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
}, function () {
|
||||
// 更新当前头像显示
|
||||
document.getElementById('currentAvatar').src = data.data.url;
|
||||
// 隐藏预览区域
|
||||
document.querySelector('.avatar-preview').style.display = 'none';
|
||||
// 清空文件输入
|
||||
document.getElementById('avatarFile').value = '';
|
||||
|
||||
// 刷新页面以更新所有显示的头像
|
||||
window.location.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(data.msg || '上传失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
layer.close(loadIndex);
|
||||
layer.msg('上传失败,请重试', { icon: 2 });
|
||||
});
|
||||
});
|
||||
|
||||
// 取消上传
|
||||
document.getElementById('cancelUpload').addEventListener('click', function () {
|
||||
document.querySelector('.avatar-preview').style.display = 'none';
|
||||
document.getElementById('avatarFile').value = '';
|
||||
});
|
||||
|
||||
// 拖拽上传
|
||||
var uploadArea = document.getElementById('uploadArea');
|
||||
|
||||
uploadArea.addEventListener('dragover', function (e) {
|
||||
e.preventDefault();
|
||||
this.style.borderColor = '#1677ff';
|
||||
});
|
||||
|
||||
uploadArea.addEventListener('dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
this.style.borderColor = '#d9d9d9';
|
||||
});
|
||||
|
||||
uploadArea.addEventListener('drop', function (e) {
|
||||
e.preventDefault();
|
||||
this.style.borderColor = '#d9d9d9';
|
||||
|
||||
var file = e.dataTransfer.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// 触发文件选择事件
|
||||
var dataTransfer = new DataTransfer();
|
||||
dataTransfer.items.add(file);
|
||||
document.getElementById('avatarFile').files = dataTransfer.files;
|
||||
|
||||
// 手动触发change事件
|
||||
var event = new Event('change');
|
||||
document.getElementById('avatarFile').dispatchEvent(event);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,427 @@
|
||||
<div class="basic-info">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">个人资料</li>
|
||||
<li>修改头像</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<form class="layui-form" lay-filter="basicForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" value="{$user.name}" placeholder="请输入用户名"
|
||||
class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">账号</label>
|
||||
<div class="layui-input-block" style="display: flex; align-items: center;">
|
||||
<input type="text" value="{$user.account}" class="layui-input" disabled>
|
||||
<button class="layui-btn" style="margin-left: 20px;">编辑</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">QQ</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="qq" value="{$user.qq}" placeholder="请输入QQ号" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">微信</label>
|
||||
<div class="layui-input-block">
|
||||
{if $user.wechat}
|
||||
<input type="text" name="wechat" value="{$user.wechat}" placeholder="请输入微信号"
|
||||
class="layui-input">
|
||||
{else}
|
||||
<button class="layui-btn" id="bindWechat">绑定微信号</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="phone" value="{$user.phone}" placeholder="请输入手机号"
|
||||
class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">性别</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="sex" value="1" title="男" {if $user.sex==1}checked{/if}>
|
||||
<input type="radio" name="sex" value="2" title="女" {if $user.sex==2}checked{/if}>
|
||||
<input type="radio" name="sex" value="0" title="保密" {if $user.sex==0}checked{/if}>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="saveBasic">保存修改</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="avatar-section">
|
||||
<div class="avatar-upload-container">
|
||||
<div class="current-avatar">
|
||||
<img src="{$user.avatar|default='/static/images/avatar.png'}" alt="当前头像" id="currentAvatar">
|
||||
<p class="avatar-tip">当前头像</p>
|
||||
</div>
|
||||
|
||||
<div class="upload-area" id="uploadArea">
|
||||
<i class="layui-icon layui-icon-upload"></i>
|
||||
<p>点击或拖拽图片到此处上传</p>
|
||||
<p class="upload-tip">支持 jpg、png、gif 格式,大小不超过 2MB</p>
|
||||
<input type="file" id="avatarFile" accept="image/*" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="avatar-preview" style="display: none;">
|
||||
<h3>预览</h3>
|
||||
<div class="preview-container">
|
||||
<img src="" alt="预览图" id="previewImage">
|
||||
</div>
|
||||
<div class="preview-actions">
|
||||
<button class="layui-btn" id="confirmUpload">确认上传</button>
|
||||
<button class="layui-btn layui-btn-primary" id="cancelUpload">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
layui.use(['form', 'layer', 'upload'], function () {
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var upload = layui.upload;
|
||||
|
||||
// 绑定微信号按钮点击事件
|
||||
document.getElementById('bindWechat').addEventListener('click', function () {
|
||||
// 发送 AJAX 请求调用 qrcode 接口
|
||||
fetch('/index/user/qrcode')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.code === 0) {
|
||||
// 二维码生成成功,这里可以添加显示二维码的逻辑,例如弹出一个窗口显示二维码
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '微信绑定二维码',
|
||||
content: `<img src="${data.data.qrcode_url}" alt="微信绑定二维码">`,
|
||||
area: ['300px', '300px']
|
||||
});
|
||||
} else {
|
||||
// 二维码生成失败,提示用户
|
||||
layer.msg(data.msg, { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
// 请求出错,提示用户
|
||||
layer.msg('请求出错,请稍后重试', { icon: 2 });
|
||||
});
|
||||
});
|
||||
|
||||
// 监听个人资料表单提交
|
||||
form.on('submit(saveBasic)', function (data) {
|
||||
// 发送AJAX请求保存数据
|
||||
fetch('/index/user/saveBasic', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify(data.field)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.code === 0) {
|
||||
layer.msg(result.msg, { icon: 1 }, function () {
|
||||
// 保存成功后刷新页面
|
||||
window.location.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(result.msg, { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('保存失败:', error);
|
||||
layer.msg('保存失败,请稍后重试', { icon: 2 });
|
||||
});
|
||||
|
||||
return false; // 阻止表单默认提交
|
||||
});
|
||||
|
||||
// 点击上传区域触发文件选择
|
||||
document.getElementById('uploadArea').addEventListener('click', function () {
|
||||
document.getElementById('avatarFile').click();
|
||||
});
|
||||
|
||||
// 处理文件选择
|
||||
document.getElementById('avatarFile').addEventListener('change', function (e) {
|
||||
var file = e.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// 检查文件类型
|
||||
if (!['image/jpeg', 'image/png', 'image/gif', 'image/webp'].includes(file.type)) {
|
||||
layer.msg('请上传 jpg、png、webp 或 gif 格式的图片');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查文件大小
|
||||
if (file.size > 2 * 1024 * 1024) {
|
||||
layer.msg('图片大小不能超过 2MB');
|
||||
return;
|
||||
}
|
||||
|
||||
// 预览图片
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
document.getElementById('previewImage').src = e.target.result;
|
||||
document.querySelector('.avatar-preview').style.display = 'block';
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
// 确认上传
|
||||
document.getElementById('confirmUpload').addEventListener('click', function () {
|
||||
var file = document.getElementById('avatarFile').files[0];
|
||||
if (!file) return;
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('avatar', file);
|
||||
|
||||
// 显示上传中
|
||||
var loadIndex = layer.load(2);
|
||||
|
||||
// 发送上传请求
|
||||
fetch('/index/user/update_avatar', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
layer.close(loadIndex);
|
||||
if (data.code === 0) {
|
||||
// 更新cookie中的头像
|
||||
document.cookie = "user_avatar=" + data.data.url + "; path=/";
|
||||
|
||||
// 更新localStorage中的头像
|
||||
localStorage.setItem('user_avatar', data.data.url);
|
||||
|
||||
layer.msg('头像上传成功', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
}, function () {
|
||||
// 更新当前头像显示
|
||||
document.getElementById('currentAvatar').src = data.data.url;
|
||||
// 隐藏预览区域
|
||||
document.querySelector('.avatar-preview').style.display = 'none';
|
||||
// 清空文件输入
|
||||
document.getElementById('avatarFile').value = '';
|
||||
|
||||
// 刷新页面以更新所有显示的头像
|
||||
window.location.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(data.msg || '上传失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
layer.close(loadIndex);
|
||||
layer.msg('上传失败,请重试', { icon: 2 });
|
||||
});
|
||||
});
|
||||
|
||||
// 取消上传
|
||||
document.getElementById('cancelUpload').addEventListener('click', function () {
|
||||
document.querySelector('.avatar-preview').style.display = 'none';
|
||||
document.getElementById('avatarFile').value = '';
|
||||
});
|
||||
|
||||
// 拖拽上传
|
||||
var uploadArea = document.getElementById('uploadArea');
|
||||
|
||||
uploadArea.addEventListener('dragover', function (e) {
|
||||
e.preventDefault();
|
||||
this.style.borderColor = '#1677ff';
|
||||
});
|
||||
|
||||
uploadArea.addEventListener('dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
this.style.borderColor = '#d9d9d9';
|
||||
});
|
||||
|
||||
uploadArea.addEventListener('drop', function (e) {
|
||||
e.preventDefault();
|
||||
this.style.borderColor = '#d9d9d9';
|
||||
|
||||
var file = e.dataTransfer.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// 触发文件选择事件
|
||||
var dataTransfer = new DataTransfer();
|
||||
dataTransfer.items.add(file);
|
||||
document.getElementById('avatarFile').files = dataTransfer.files;
|
||||
|
||||
// 手动触发change事件
|
||||
var event = new Event('change');
|
||||
document.getElementById('avatarFile').dispatchEvent(event);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
.basic-info {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.layui-form-label {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.layui-input-block {
|
||||
margin-left: 130px;
|
||||
}
|
||||
|
||||
.layui-form-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.layui-textarea {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.avatar-section {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.avatar-upload-container {
|
||||
display: flex;
|
||||
gap: 40px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.current-avatar {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.current-avatar img {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 3px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.avatar-tip {
|
||||
margin-top: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
flex: 1;
|
||||
border: 2px dashed #d9d9d9;
|
||||
border-radius: 8px;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-area:hover {
|
||||
border-color: #1677ff;
|
||||
}
|
||||
|
||||
.upload-area .layui-icon {
|
||||
font-size: 48px;
|
||||
color: #999;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.upload-area p {
|
||||
margin: 8px 0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.upload-tip {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.avatar-preview {
|
||||
margin-top: 32px;
|
||||
padding-top: 32px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.avatar-preview h3 {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.preview-container img {
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.preview-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preview-actions .layui-btn {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.layui-form-label {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.layui-input-block {
|
||||
margin-left: 110px;
|
||||
}
|
||||
|
||||
.avatar-upload-container {
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.current-avatar img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,326 @@
|
||||
<div class="basic-info">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">全部消息</li>
|
||||
<li>未读消息</li>
|
||||
<li>已读消息</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<div class="message-list" id="allMessages">
|
||||
<!-- 消息列表将通过JavaScript动态加载 -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="message-list" id="unreadMessages">
|
||||
<!-- 未读消息列表 -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="message-list" id="readMessages">
|
||||
<!-- 已读消息列表 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.basic-info {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.layui-form-label {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.layui-input-block {
|
||||
margin-left: 130px;
|
||||
}
|
||||
|
||||
.layui-form-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.layui-textarea {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.message-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.message-item:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.message-item.unread {
|
||||
background-color: #f0f7ff;
|
||||
}
|
||||
|
||||
.message-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.message-title {
|
||||
font-weight: 500;
|
||||
margin-bottom: 4px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.message-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.message-time {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.message-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.message-actions button {
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
background: none;
|
||||
border: 1px solid #d9d9d9;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.message-actions button:hover {
|
||||
border-color: #1677ff;
|
||||
color: #1677ff;
|
||||
}
|
||||
|
||||
.empty-message {
|
||||
text-align: center;
|
||||
padding: 40px 0;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.layui-form-label {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.layui-input-block {
|
||||
margin-left: 110px;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.message-avatar {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['element', 'layer'], function () {
|
||||
var element = layui.element;
|
||||
var layer = layui.layer;
|
||||
|
||||
// 加载消息列表
|
||||
function loadMessages(type) {
|
||||
var container = document.getElementById(type + 'Messages');
|
||||
var loadIndex = layer.load(2);
|
||||
|
||||
fetch('/index/user/getMessages?type=' + type)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
layer.close(loadIndex);
|
||||
if (data.code === 0) {
|
||||
renderMessages(container, data.data);
|
||||
} else {
|
||||
layer.msg(data.msg || '加载失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
layer.close(loadIndex);
|
||||
layer.msg('加载失败,请重试', { icon: 2 });
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染消息列表
|
||||
function renderMessages(container, messages) {
|
||||
if (!messages || messages.length === 0) {
|
||||
container.innerHTML = '<div class="empty-message">暂无消息</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '';
|
||||
messages.forEach(function (message) {
|
||||
html += `
|
||||
<div class="message-item ${message.is_read ? '' : 'unread'}" data-id="${message.id}">
|
||||
<img src="${message.avatar || '/static/images/avatar.png'}" class="message-avatar" alt="头像">
|
||||
<div class="message-content">
|
||||
<div class="message-title">${message.title}</div>
|
||||
<div class="message-text">${message.content}</div>
|
||||
<div class="message-meta">
|
||||
<span class="message-time">${message.create_time}</span>
|
||||
<div class="message-actions">
|
||||
${!message.is_read ? '<button class="mark-read">标记已读</button>' : ''}
|
||||
<button class="delete-message">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
container.innerHTML = html;
|
||||
|
||||
// 绑定事件
|
||||
bindMessageEvents(container);
|
||||
}
|
||||
|
||||
// 绑定消息事件
|
||||
function bindMessageEvents(container) {
|
||||
// 标记已读
|
||||
container.querySelectorAll('.mark-read').forEach(btn => {
|
||||
btn.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
var messageId = this.closest('.message-item').dataset.id;
|
||||
markAsRead(messageId);
|
||||
});
|
||||
});
|
||||
|
||||
// 删除消息
|
||||
container.querySelectorAll('.delete-message').forEach(btn => {
|
||||
btn.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
var messageId = this.closest('.message-item').dataset.id;
|
||||
deleteMessage(messageId);
|
||||
});
|
||||
});
|
||||
|
||||
// 点击消息
|
||||
container.querySelectorAll('.message-item').forEach(item => {
|
||||
item.addEventListener('click', function () {
|
||||
var messageId = this.dataset.id;
|
||||
viewMessage(messageId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 标记已读
|
||||
function markAsRead(messageId) {
|
||||
fetch('/index/user/markMessageRead', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: messageId })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.code === 0) {
|
||||
layer.msg('已标记为已读', { icon: 1 });
|
||||
// 重新加载消息列表
|
||||
loadMessages('all');
|
||||
loadMessages('unread');
|
||||
loadMessages('read');
|
||||
} else {
|
||||
layer.msg(data.msg || '操作失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
layer.msg('操作失败,请重试', { icon: 2 });
|
||||
});
|
||||
}
|
||||
|
||||
// 删除消息
|
||||
function deleteMessage(messageId) {
|
||||
layer.confirm('确定要删除这条消息吗?', {
|
||||
btn: ['确定', '取消']
|
||||
}, function () {
|
||||
fetch('/index/user/deleteMessage', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: messageId })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.code === 0) {
|
||||
layer.msg('删除成功', { icon: 1 });
|
||||
// 重新加载消息列表
|
||||
loadMessages('all');
|
||||
loadMessages('unread');
|
||||
loadMessages('read');
|
||||
} else {
|
||||
layer.msg(data.msg || '删除失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
layer.msg('删除失败,请重试', { icon: 2 });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 查看消息详情
|
||||
function viewMessage(messageId) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '消息详情',
|
||||
area: ['500px', '400px'],
|
||||
content: '/index/user/messageDetail?id=' + messageId
|
||||
});
|
||||
}
|
||||
|
||||
// 监听标签切换
|
||||
element.on('tab(messageTabs)', function (data) {
|
||||
var type = ['all', 'unread', 'read'][data.index];
|
||||
loadMessages(type);
|
||||
});
|
||||
|
||||
// 初始加载全部消息
|
||||
loadMessages('all');
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,209 @@
|
||||
<div class="notifications-section">
|
||||
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="notificationTabs">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">全部通知</li>
|
||||
<li>未读通知</li>
|
||||
<li>已读通知</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<div class="notification-list" id="allNotifications"></div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="notification-list" id="unreadNotifications"></div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="notification-list" id="readNotifications"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.notifications-section {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.notification-list {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.notification-item {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.notification-item:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.notification-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.notification-time {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.notification-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.notification-item.unread .notification-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.notification-item.unread::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #1677ff;
|
||||
border-radius: 50%;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.notification-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['element', 'layer'], function () {
|
||||
var element = layui.element;
|
||||
var layer = layui.layer;
|
||||
|
||||
// 加载通知列表
|
||||
function loadNotifications(type) {
|
||||
var container = document.getElementById(type + 'Notifications');
|
||||
container.innerHTML = '<div class="layui-anim layui-anim-upbit layui-anim-loop layui-anim-shrink" style="text-align: center; padding: 20px;"><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i></div>';
|
||||
|
||||
fetch('/index/user/getNotifications?type=' + type)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.code === 0) {
|
||||
if (data.data.length === 0) {
|
||||
container.innerHTML = '<div class="layui-none">暂无通知</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '';
|
||||
data.data.forEach(function (notification) {
|
||||
html += `
|
||||
<div class="notification-item ${notification.is_read ? '' : 'unread'}" data-id="${notification.id}">
|
||||
<div class="notification-content">
|
||||
<div class="notification-title">${notification.title}</div>
|
||||
<div class="notification-time">${notification.create_time}</div>
|
||||
</div>
|
||||
<div class="notification-actions">
|
||||
<button class="layui-btn layui-btn-xs" onclick="viewNotification(${notification.id})">查看</button>
|
||||
<button class="layui-btn layui-btn-xs layui-btn-danger" onclick="deleteNotification(${notification.id})">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
container.innerHTML = html;
|
||||
} else {
|
||||
layer.msg(data.msg || '加载失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
layer.msg('加载失败,请重试', { icon: 2 });
|
||||
});
|
||||
}
|
||||
|
||||
// 查看通知
|
||||
window.viewNotification = function (notificationId) {
|
||||
fetch('/index/user/readNotification', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: notificationId })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.code === 0) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '通知详情',
|
||||
area: ['500px', '400px'],
|
||||
content: '/index/user/notificationDetail?id=' + notificationId
|
||||
});
|
||||
// 重新加载通知列表
|
||||
loadNotifications('all');
|
||||
loadNotifications('unread');
|
||||
loadNotifications('read');
|
||||
} else {
|
||||
layer.msg(data.msg || '操作失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
layer.msg('操作失败,请重试', { icon: 2 });
|
||||
});
|
||||
}
|
||||
|
||||
// 删除通知
|
||||
window.deleteNotification = function (notificationId) {
|
||||
layer.confirm('确定要删除这条通知吗?', {
|
||||
btn: ['确定', '取消']
|
||||
}, function () {
|
||||
fetch('/index/user/deleteNotification', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: notificationId })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.code === 0) {
|
||||
layer.msg('删除成功', { icon: 1 });
|
||||
// 重新加载通知列表
|
||||
loadNotifications('all');
|
||||
loadNotifications('unread');
|
||||
loadNotifications('read');
|
||||
} else {
|
||||
layer.msg(data.msg || '删除失败', { icon: 2 });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
layer.msg('删除失败,请重试', { icon: 2 });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 监听标签切换
|
||||
element.on('tab(notificationTabs)', function (data) {
|
||||
var type = ['all', 'unread', 'read'][data.index];
|
||||
loadNotifications(type);
|
||||
});
|
||||
|
||||
// 初始加载全部通知
|
||||
loadNotifications('all');
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,100 @@
|
||||
<div class="security-section">
|
||||
<h2 class="section-title">安全设置</h2>
|
||||
|
||||
<form class="layui-form" lay-filter="securityForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">登录密码</label>
|
||||
<div class="layui-input-block">
|
||||
<button type="button" class="layui-btn" onclick="changePassword()">修改密码</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">手机绑定</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="phone-info">
|
||||
<span id="phoneNumber">未绑定</span>
|
||||
<button type="button" class="layui-btn layui-btn-primary" onclick="bindPhone()">绑定手机</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.security-section {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.phone-info,
|
||||
.email-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.layui-form-label {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.layui-input-block {
|
||||
margin-left: 130px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.layui-form-label {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.layui-input-block {
|
||||
margin-left: 110px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function () {
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
|
||||
// 加载用户安全信息
|
||||
loadSecurityInfo();
|
||||
});
|
||||
|
||||
// 修改密码
|
||||
function changePassword() {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '修改密码',
|
||||
area: ['500px', '400px'],
|
||||
content: '/index/user/updatePassword',
|
||||
end: function () {
|
||||
// 检查是否需要跳转到登录页
|
||||
if (window.needRedirect) {
|
||||
window.location.href = '/index/user/login';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定手机
|
||||
function bindPhone() {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '绑定手机',
|
||||
area: ['500px', '400px'],
|
||||
content: '/index/user/component/bindPhone'
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,157 @@
|
||||
<div class="sidebar">
|
||||
<div class="user-info">
|
||||
<div class="avatar-wrapper">
|
||||
<img src="{$user.avatar|default='/static/images/avatar.png'}" class="avatar" alt="用户头像">
|
||||
</div>
|
||||
<h3 class="username">{$user.name}</h3>
|
||||
<p class="email">{$user.account}</p>
|
||||
</div>
|
||||
|
||||
<nav class="menu">
|
||||
<a href="javascript:;" class="menu-item active" data-target="profile-basic">
|
||||
<i class="icon">👤</i>
|
||||
<span>个人资料</span>
|
||||
</a>
|
||||
<a href="javascript:;" class="menu-item" data-target="profile-wallet">
|
||||
<i class="icon">💰</i>
|
||||
<span>我的钱包</span>
|
||||
</a>
|
||||
<a href="javascript:;" class="menu-item" data-target="profile-messages">
|
||||
<i class="icon">✉️</i>
|
||||
<span>我的消息</span>
|
||||
</a>
|
||||
<a href="javascript:;" class="menu-item" data-target="profile-notifications">
|
||||
<i class="icon">🔔</i>
|
||||
<span>系统通知</span>
|
||||
</a>
|
||||
<a href="javascript:;" class="menu-item" data-target="profile-security">
|
||||
<i class="icon">🛡️</i>
|
||||
<span>安全设置</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sidebar {
|
||||
width: 260px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
padding: 24px 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
text-align: center;
|
||||
padding: 0 24px 24px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
margin-bottom: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
width: 88px;
|
||||
height: 88px;
|
||||
margin: 0 auto 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 3px solid #f5f5f5;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.avatar:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0 0 4px;
|
||||
}
|
||||
|
||||
.email {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 4px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background: #f5f7fa;
|
||||
color: #1677ff;
|
||||
}
|
||||
|
||||
.menu-item.active {
|
||||
background: #e6f4ff;
|
||||
color: #1677ff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 20px;
|
||||
margin-right: 12px;
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* 响应式适配 */
|
||||
@media (max-width: 768px) {
|
||||
.sidebar {
|
||||
width: 100%;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// 获取当前页面路径
|
||||
const currentPath = window.location.pathname;
|
||||
|
||||
// 移除所有active类
|
||||
document.querySelectorAll('.menu-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
|
||||
// 为当前页面对应的菜单项添加active类
|
||||
document.querySelectorAll('.menu-item').forEach(item => {
|
||||
if (item.getAttribute('href') === currentPath) {
|
||||
item.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,86 @@
|
||||
<div class="basic-info">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">积分</li>
|
||||
<li>云币</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<p>您当前的积分余额:<span id="points-balance">0</span></p>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<p>您当前的云币余额:<span id="cloud-coins-balance">0</span></p>
|
||||
<p>云币是真钱充值后获得的平台币。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
layui.use(['element'], function () {
|
||||
var element = layui.element;
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
// JavaScript 部分,处理 tab 切换
|
||||
const tabs = document.querySelectorAll('.tab');
|
||||
const contents = document.querySelectorAll('.content-item');
|
||||
|
||||
tabs.forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
// 移除所有 tab 的 active 类
|
||||
tabs.forEach(t => t.classList.remove('active'));
|
||||
// 给当前点击的 tab 添加 active 类
|
||||
tab.classList.add('active');
|
||||
|
||||
const target = tab.dataset.target;
|
||||
// 隐藏所有内容项
|
||||
contents.forEach(content => {
|
||||
content.classList.remove('active');
|
||||
if (content.id === target) {
|
||||
content.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
/* 样式部分 */
|
||||
.tab-container {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 10px 20px;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
border-color: #ccc;
|
||||
border-bottom: 1px solid white;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding: 20px;
|
||||
border: 1px solid #ccc;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.content-item {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content-item.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.layui-unselect.layui-tab-bar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,661 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="__LAYUI__/css/layui.css">
|
||||
<script src="__JS__/gt4.js"></script>
|
||||
<script src="__LAYUI__/layui.js" charset="utf-8"></script>
|
||||
<title>用户登录</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background: #f5f7fa;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
width: 420px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.login-header {
|
||||
padding: 40px 40px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-header h2 {
|
||||
font-size: 28px;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.login-header p {
|
||||
color: #666;
|
||||
margin: 10px 0 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
padding: 20px 40px 40px;
|
||||
}
|
||||
|
||||
.layui-form-item {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.layui-input {
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e4e7ed;
|
||||
padding: 0 15px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.layui-input:focus {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
.layui-btn {
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
background: #409eff;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.layui-btn:hover {
|
||||
background: #66b1ff;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.layui-tab {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.layui-tab-title {
|
||||
border: none;
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
.layui-tab-title li {
|
||||
font-size: 15px;
|
||||
color: #666;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.layui-tab-title .layui-this {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.layui-tab-title .layui-this:after {
|
||||
border-bottom: 2px solid #409eff;
|
||||
}
|
||||
|
||||
.layui-tab-content {
|
||||
padding: 20px 0 0;
|
||||
}
|
||||
|
||||
.wechat-login {
|
||||
text-align: center;
|
||||
padding: 30px 0;
|
||||
/* padding-bottom: 60px; */
|
||||
}
|
||||
|
||||
.wechat-login img {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.wechat-login img:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.wechat-login p {
|
||||
margin-top: 15px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#qrcode-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#qrcode-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#qrcode-loading .layui-icon {
|
||||
font-size: 40px;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
#qrcode-loading p {
|
||||
margin-top: 10px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.layui-input-inline {
|
||||
margin-right: 0px !important;
|
||||
}
|
||||
|
||||
#getCode {
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
padding: 0 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.layui-input-block {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
/* margin: 50px auto; */
|
||||
text-align: center;
|
||||
}
|
||||
.qrcode-container {
|
||||
margin: 20px 0;
|
||||
}
|
||||
.qrcode-container img {
|
||||
max-width: 200px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.qrcode-container p {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.status {
|
||||
color: #666;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.error {
|
||||
color: #ff4d4f;
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<div class="login-header">
|
||||
<h2>欢迎登录</h2>
|
||||
<p>请选择登录方式</p>
|
||||
</div>
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li lay-id="account">账密登录</li>
|
||||
<!-- <li lay-id="phone">手机验证码</li> -->
|
||||
<li class="layui-this" lay-id="wechat">微信登录</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item" id="account">
|
||||
<form action="#" method="post" class="layui-form login-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<input type="text" name="account" required lay-verify="required" placeholder="请输入用户名"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<input type="password" name="password" required lay-verify="required"
|
||||
placeholder="请输入密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div id="gt-captcha" style="width: 100%;"></div>
|
||||
</div>
|
||||
<div class="layui-form-item" style="display: flex;flex-direction: column;align-items: center;">
|
||||
<div class="layui-input-block" style="margin-left: 0;margin-bottom: 10px;">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit
|
||||
lay-filter="accountLogin">登录</button>
|
||||
</div>
|
||||
<div style="margin-bottom: 10px;color: #aaa;">or</div>
|
||||
<div>
|
||||
<a href="{:url('/index/user/register')}" class="">注册</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- <div class="layui-tab-item" id="phone">
|
||||
<form action="#" method="post" class="layui-form login-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<input type="tel" name="phone" required lay-verify="required|phone" placeholder="请输入手机号"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<div class="layui-input-inline" style="width: calc(100% - 120px);">
|
||||
<input type="text" name="code" required lay-verify="required" placeholder="请输入验证码"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width: 110px;">
|
||||
<button type="button" class="layui-btn" id="getCode">获取验证码</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div id="gt-captcha" style="width: 100%;"></div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit lay-filter="phoneLogin">登录</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div> -->
|
||||
<div class="layui-tab-item layui-show" id="wechat">
|
||||
<div class="wechat-login">
|
||||
<div class="container">
|
||||
<h2>微信扫码登录</h2>
|
||||
<div class="qrcode-container">
|
||||
<img id="qrcode" src="__IMAGES__/loading.gif" alt="微信登录二维码" onclick="reGenerateQrcode()">
|
||||
<!-- <p>点击二维码可刷新</p> -->
|
||||
</div>
|
||||
<div id="status" class="status">正在加载二维码...</div>
|
||||
<div id="error" class="error"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// 全局变量
|
||||
var checkLoginTimer = null;
|
||||
var currentSceneStr = '';
|
||||
var currentTicket = '';
|
||||
var qrcodeExpireTime = 0;
|
||||
var $ = layui.jquery;
|
||||
|
||||
// 获取微信登录二维码
|
||||
function getQrcode() {
|
||||
$.ajax({
|
||||
url: '/index/wechat/getLoginTicket',
|
||||
type: 'GET',
|
||||
success: function(res) {
|
||||
if (res.code === 0) {
|
||||
$('#qrcode').attr('src', res.data.url);
|
||||
currentSceneStr = res.data.scene_str;
|
||||
currentTicket = res.data.ticket;
|
||||
// 设置二维码过期时间(5分钟)
|
||||
qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000);
|
||||
$('#status').text('等待扫码...');
|
||||
$('#error').text('');
|
||||
// 开始检查登录状态
|
||||
startCheckLogin();
|
||||
} else {
|
||||
$('#error').text('获取二维码失败:' + res.msg);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#error').text('获取二维码失败,请刷新页面重试');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 开始检查登录状态
|
||||
function startCheckLogin() {
|
||||
if (checkLoginTimer) {
|
||||
clearInterval(checkLoginTimer);
|
||||
}
|
||||
|
||||
checkLoginTimer = setInterval(function() {
|
||||
// 检查二维码是否过期
|
||||
if (new Date().getTime() > qrcodeExpireTime) {
|
||||
clearInterval(checkLoginTimer);
|
||||
$('#status').html('二维码已过期<br>请点击刷新');
|
||||
$('#qrcode').css('opacity', '0.02');
|
||||
$('#status').css({
|
||||
'position': 'relative',
|
||||
'top': '-150px',
|
||||
'font-size': '20px',
|
||||
'font-weight': 'bolder'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/index/wechat/checkLoginStatus',
|
||||
type: 'POST',
|
||||
data: {
|
||||
scene_str: currentSceneStr,
|
||||
ticket: currentTicket
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.code === 1) {
|
||||
// 登录成功
|
||||
clearInterval(checkLoginTimer);
|
||||
$('#status').text('登录成功,正在跳转...');
|
||||
// 保存用户信息到localStorage
|
||||
if (res.data) {
|
||||
localStorage.setItem('user_account', res.data.user_account);
|
||||
localStorage.setItem('expire_time', res.data.expire_time);
|
||||
localStorage.setItem('is_auto_login', res.data.is_auto_login);
|
||||
}
|
||||
// 设置cookie
|
||||
document.cookie = `user_account=${res.data.user_account}; path=/; max-age=${7*24*3600}`;
|
||||
document.cookie = `user_avatar=${res.data.avatar}; path=/; max-age=${7*24*3600}`;
|
||||
document.cookie = `user_name=${res.data.name}; path=/; max-age=${7*24*3600}`;
|
||||
document.cookie = `open_id=${res.data.openid}; path=/; max-age=${7*24*3600}`;
|
||||
|
||||
// 跳转到首页或其他页面
|
||||
setTimeout(function() {
|
||||
window.location.href = '/';
|
||||
}, 1000);
|
||||
} else if (res.code === 0) {
|
||||
// 更新状态信息
|
||||
$('#status').text(res.msg);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#error').text('检查登录状态失败,请重试');
|
||||
}
|
||||
});
|
||||
}, 2000); // 每2秒检查一次
|
||||
}
|
||||
|
||||
// 重新生成二维码的全局函数
|
||||
function reGenerateQrcode() {
|
||||
if (!currentSceneStr) {
|
||||
getQrcode();
|
||||
return;
|
||||
}
|
||||
|
||||
// 清除之前的定时器
|
||||
if (checkLoginTimer) {
|
||||
clearInterval(checkLoginTimer);
|
||||
checkLoginTimer = null;
|
||||
}
|
||||
|
||||
// 恢复二维码和状态文本的样式
|
||||
$('#qrcode').css('opacity', '1');
|
||||
$('#status').css({
|
||||
'position': 'static',
|
||||
'top': 'auto',
|
||||
'font-size': '14px',
|
||||
'font-weight': 'normal'
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: '/index/wechat/reGenerateQrcode',
|
||||
type: 'POST',
|
||||
data: {
|
||||
scene_str: currentSceneStr
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.code === 0) {
|
||||
$('#qrcode').attr('src', res.data.url);
|
||||
currentSceneStr = res.data.scene_str;
|
||||
currentTicket = res.data.ticket;
|
||||
// 设置新的二维码过期时间(5分钟)
|
||||
qrcodeExpireTime = new Date().getTime() + (res.data.expire_seconds * 1000);
|
||||
$('#status').text('等待扫码...');
|
||||
$('#error').text('');
|
||||
// 开始检查登录状态
|
||||
startCheckLogin();
|
||||
} else {
|
||||
$('#error').text('刷新二维码失败:' + res.msg);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#error').text('刷新二维码失败,请重试');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
layui.use(['form', 'element', 'jquery'], function () {
|
||||
var form = layui.form;
|
||||
var element = layui.element;
|
||||
var layer = layui.layer;
|
||||
|
||||
// 页面加载完成后获取二维码
|
||||
$(document).ready(function() {
|
||||
getQrcode();
|
||||
});
|
||||
|
||||
// 检查极验验证是否开启
|
||||
<?php if ($config['geetest_open'] == 1): ?>
|
||||
// 初始化极验验证
|
||||
var handler = function (captchaObj) {
|
||||
// 将验证码渲染到指定容器
|
||||
captchaObj.appendTo('#gt-captcha');
|
||||
|
||||
// 账密登录表单提交
|
||||
form.on('submit(accountLogin)', function (data) {
|
||||
var validate = captchaObj.getValidate();
|
||||
if (!validate) {
|
||||
layer.msg('请完成验证码验证', {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
return false;
|
||||
}
|
||||
data.field.geetest_challenge = validate.geetest_challenge;
|
||||
data.field.geetest_validate = validate.geetest_validate;
|
||||
data.field.geetest_seccode = validate.geetest_seccode;
|
||||
|
||||
$.ajax({
|
||||
url: '{:url("index/user/login")}',
|
||||
type: 'POST',
|
||||
data: data.field,
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// 存储登录数据,设置7天过期
|
||||
var expireTime = new Date().getTime() + 7 * 24 * 60 * 60 * 1000;
|
||||
localStorage.setItem('user_account', data.field.account);
|
||||
localStorage.setItem('user_password', btoa(data.field.password));
|
||||
localStorage.setItem('expire_time', expireTime);
|
||||
// 添加登录状态标记
|
||||
localStorage.setItem('is_auto_login', 'true');
|
||||
|
||||
layer.msg('登录成功', {
|
||||
icon: 1,
|
||||
time: 2000,
|
||||
shade: 0.3
|
||||
}, function () {
|
||||
window.location.href = '{:url("/")}';
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 手机验证码登录表单提交
|
||||
form.on('submit(phoneLogin)', function (data) {
|
||||
var validate = captchaObj.getValidate();
|
||||
if (!validate) {
|
||||
layer.msg('请完成验证码验证', {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
return false;
|
||||
}
|
||||
data.field.geetest_challenge = validate.geetest_challenge;
|
||||
data.field.geetest_validate = validate.geetest_validate;
|
||||
data.field.geetest_seccode = validate.geetest_seccode;
|
||||
|
||||
$.ajax({
|
||||
url: '{:url("index/user/login")}',
|
||||
type: 'POST',
|
||||
data: data.field,
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('登录成功', {
|
||||
icon: 1,
|
||||
time: 2000,
|
||||
shade: 0.3
|
||||
}, function () {
|
||||
window.location.href = '{:url("/")}';
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 点击获取验证码按钮时验证
|
||||
var getCodeBtn = document.getElementById('getCode');
|
||||
if (getCodeBtn) {
|
||||
getCodeBtn.addEventListener('click', function () {
|
||||
console.log('获取验证码');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 直接使用配置初始化极验验证,并添加错误处理
|
||||
initGeetest4({
|
||||
captchaId: '{$config[\'geetest_id\']}',
|
||||
offline: false,
|
||||
new_captcha: true
|
||||
}, handler, function (error) {
|
||||
console.error('极验验证初始化失败:', error);
|
||||
layer.msg('验证码初始化失败,请刷新页面重试', {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
});
|
||||
<?php else: ?>
|
||||
// 极验验证关闭,移除验证码容器
|
||||
$('#gt-captcha').remove();
|
||||
|
||||
// 移除表单提交时的验证码验证逻辑
|
||||
form.on('submit(accountLogin)', function (data) {
|
||||
$.ajax({
|
||||
url: '{:url("index/user/login")}',
|
||||
type: 'POST',
|
||||
data: data.field,
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
// 存储登录数据,设置7天过期
|
||||
var expireTime = new Date().getTime() + 7 * 24 * 60 * 60 * 1000;
|
||||
localStorage.setItem('user_account', data.field.account);
|
||||
localStorage.setItem('user_password', btoa(data.field.password));
|
||||
localStorage.setItem('expire_time', expireTime);
|
||||
// 添加登录状态标记
|
||||
localStorage.setItem('is_auto_login', 'true');
|
||||
|
||||
layer.msg('登录成功', {
|
||||
icon: 1,
|
||||
time: 2000,
|
||||
shade: 0.3
|
||||
}, function () {
|
||||
window.location.href = '{:url("/")}';
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
form.on('submit(phoneLogin)', function (data) {
|
||||
$.ajax({
|
||||
url: '{:url("index/user/login")}',
|
||||
type: 'POST',
|
||||
data: data.field,
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('登录成功', {
|
||||
icon: 1,
|
||||
time: 2000,
|
||||
shade: 0.3
|
||||
}, function () {
|
||||
window.location.href = '{:url("/")}';
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {
|
||||
icon: 2,
|
||||
time: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 移除获取验证码按钮的验证码验证逻辑
|
||||
var getCodeBtn = document.getElementById('getCode');
|
||||
if (getCodeBtn) {
|
||||
getCodeBtn.addEventListener('click', function () {
|
||||
console.log('获取验证码');
|
||||
});
|
||||
}
|
||||
<?php endif; ?>
|
||||
|
||||
// 页面加载时检查是否有保存的登录数据
|
||||
$(function () {
|
||||
var expireTime = localStorage.getItem('expire_time');
|
||||
var isAutoLogin = localStorage.getItem('is_auto_login');
|
||||
|
||||
if (expireTime && new Date().getTime() < expireTime && isAutoLogin === 'true') {
|
||||
// 只填充账号,不填充密码
|
||||
$('input[name="account"]').val(localStorage.getItem('user_account'));
|
||||
} else {
|
||||
// 如果过期或未开启自动登录,清除数据
|
||||
localStorage.removeItem('user_account');
|
||||
localStorage.removeItem('user_password');
|
||||
localStorage.removeItem('expire_time');
|
||||
localStorage.removeItem('is_auto_login');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.layui-form-item a {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.layui-form-item a:hover {
|
||||
color: rgb(58, 125, 196);
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,175 @@
|
||||
{include file="component/head" /}
|
||||
{include file="component/header" /}
|
||||
|
||||
<div class="profile-container">
|
||||
<div class="profile-sidebar">
|
||||
<div class="menu">
|
||||
<div class="menu-item active" data-target="profile-basic">
|
||||
<i class="layui-icon layui-icon-user"></i>
|
||||
<span>基本资料</span>
|
||||
</div>
|
||||
<div class="menu-item" data-target="profile-wallet">
|
||||
<i class="layui-icon layui-icon-wallet"></i>
|
||||
<span>我的钱包</span>
|
||||
</div>
|
||||
<div class="menu-item" data-target="profile-messages">
|
||||
<i class="layui-icon layui-icon-message"></i>
|
||||
<span>我的消息</span>
|
||||
</div>
|
||||
<div class="menu-item" data-target="profile-notifications">
|
||||
<i class="layui-icon layui-icon-notice"></i>
|
||||
<span>系统通知</span>
|
||||
</div>
|
||||
<div class="menu-item" data-target="profile-security">
|
||||
<i class="layui-icon layui-icon-password"></i>
|
||||
<span>安全设置</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="profile-main">
|
||||
<div class="content-area">
|
||||
<!-- 个人资料 -->
|
||||
<div id="profile-basic" class="content-section active">
|
||||
{include file="user/component/basic" /}
|
||||
</div>
|
||||
|
||||
<!-- 我的钱包 -->
|
||||
<div id="profile-wallet" class="content-section">
|
||||
{include file="user/component/wallet" /}
|
||||
</div>
|
||||
|
||||
<!-- 我的消息 -->
|
||||
<div id="profile-messages" class="content-section">
|
||||
{include file="user/component/messages" /}
|
||||
</div>
|
||||
|
||||
<!-- 系统通知 -->
|
||||
<div id="profile-notifications" class="content-section">
|
||||
{include file="user/component/notifications" /}
|
||||
</div>
|
||||
|
||||
<!-- 安全设置 -->
|
||||
<div id="profile-security" class="content-section">
|
||||
{include file="user/component/security" /}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.profile-container {
|
||||
display: flex;
|
||||
max-width: 1200px;
|
||||
margin: 40px auto;
|
||||
gap: 24px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.profile-sidebar {
|
||||
width: 260px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 16px 24px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
color: #666;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
color: #1677ff;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.menu-item.active {
|
||||
color: #1677ff;
|
||||
background: #e6f4ff;
|
||||
border-right: 3px solid #1677ff;
|
||||
}
|
||||
|
||||
.menu-item .layui-icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.profile-main {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content-section.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 响应式适配 */
|
||||
@media (max-width: 768px) {
|
||||
.profile-container {
|
||||
flex-direction: column;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.profile-sidebar {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
flex-shrink: 0;
|
||||
border-right: none;
|
||||
border-bottom: 3px solid transparent;
|
||||
}
|
||||
|
||||
.menu-item.active {
|
||||
border-right: none;
|
||||
border-bottom: 3px solid #1677ff;
|
||||
}
|
||||
|
||||
.profile-main {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
layui.use(['jquery'], function(){
|
||||
var $ = layui.jquery;
|
||||
|
||||
// 菜单切换
|
||||
$('.menu-item').on('click', function(){
|
||||
var target = $(this).data('target');
|
||||
|
||||
// 移除所有active类
|
||||
$('.menu-item').removeClass('active');
|
||||
$('.content-section').removeClass('active');
|
||||
|
||||
// 添加active类
|
||||
$(this).addClass('active');
|
||||
$('#' + target).addClass('active');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{include file="component/foot" /}
|
||||
@@ -0,0 +1,240 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="__LAYUI__/css/layui.css">
|
||||
<script src="__LAYUI__/layui.js" charset="utf-8"></script>
|
||||
<title>用户注册</title>
|
||||
<style>
|
||||
/* 保持原有样式不变 */
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background: #f5f7fa;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.register-container {
|
||||
width: 420px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.register-header {
|
||||
padding: 40px 40px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.register-header h2 {
|
||||
font-size: 28px;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.register-header p {
|
||||
color: #666;
|
||||
margin: 10px 0 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.register-form {
|
||||
padding: 20px 40px 40px;
|
||||
}
|
||||
|
||||
.layui-form-item {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.layui-input {
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e4e7ed;
|
||||
padding: 0 15px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.layui-input:focus {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
|
||||
.layui-btn {
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
background: #409eff;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.layui-btn:hover {
|
||||
background: #66b1ff;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.layui-input-inline {
|
||||
margin-right: 0px !important;
|
||||
}
|
||||
|
||||
#getCode {
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
padding: 0 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.layui-input-block {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.login-link {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.login-link a {
|
||||
color: #409eff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.login-link a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="register-container">
|
||||
<div class="register-header">
|
||||
<h2>用户注册</h2>
|
||||
<p>创建您的账号</p>
|
||||
</div>
|
||||
<form action="#" method="post" class="layui-form register-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<input type="account" name="account" required lay-verify="required|account" placeholder="请输入邮箱"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<div class="layui-input-inline" style="width: calc(100% - 120px);">
|
||||
<input type="text" name="code" required lay-verify="required" placeholder="请输入验证码"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-input-inline" style="width: 110px;">
|
||||
<button type="button" class="layui-btn" id="getCode">获取验证码</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<input type="password" name="password" required lay-verify="required" placeholder="请输入密码"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<input type="password" name="repassword" required lay-verify="required" placeholder="请确认密码"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<button class="layui-btn layui-btn-fluid" lay-submit lay-filter="register">注册</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-link">
|
||||
已有账号?<a href="{:url('/index/user/login')}">立即登录</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function () {
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
|
||||
// 注册表单提交
|
||||
form.on('submit(register)', function (data) {
|
||||
$.ajax({
|
||||
url: '{:url("index/user/register")}',
|
||||
type: 'POST',
|
||||
data: data.field,
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('注册成功', {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
}, function () {
|
||||
window.location.href = '{:url("index/user/login")}';
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('网络错误,请稍后重试');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 获取验证码按钮点击事件
|
||||
document.getElementById('getCode').addEventListener('click', function () {
|
||||
var account = document.querySelector('input[name="account"]').value;
|
||||
if (!account) {
|
||||
layer.msg('请先输入邮箱地址');
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送邮箱验证码请求
|
||||
$.ajax({
|
||||
url: '{:url("index/user/sendEmailCode")}',
|
||||
type: 'POST',
|
||||
data: { account: account },
|
||||
dataType: 'json', // 添加这行
|
||||
success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('验证码已发送,请查收邮件');
|
||||
// 禁用按钮60秒
|
||||
var btn = document.getElementById('getCode');
|
||||
var countdown = 60;
|
||||
btn.disabled = true;
|
||||
var timer = setInterval(function () {
|
||||
if (countdown > 0) {
|
||||
btn.innerHTML = countdown + '秒后重试';
|
||||
countdown--;
|
||||
} else {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '获取验证码';
|
||||
clearInterval(timer);
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
layer.msg(res.msg);
|
||||
}
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
console.log(xhr.responseText); // 添加调试信息
|
||||
layer.msg('网络错误,请稍后重试');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,91 @@
|
||||
{include file="component/head" /}
|
||||
<form class="layui-form" action="/index/user/updatePassword" method="post">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">旧密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="old_password" required lay-verify="required" placeholder="请输入旧密码"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">新密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="new_password" required lay-verify="required|password" placeholder="请输入新密码"
|
||||
autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">确认密码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="password" name="confirm_password" required lay-verify="required|confirmPassword"
|
||||
placeholder="请再次输入新密码" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="updatePassword">立即修改</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
layui.use(['form', 'layer'], function () {
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var $ = layui.$;
|
||||
|
||||
// 自定义验证规则
|
||||
form.verify({
|
||||
password: [
|
||||
/^[\S]{6,20}$/,
|
||||
'密码长度必须在6-20个字符之间'
|
||||
],
|
||||
confirmPassword: function (value) {
|
||||
var password = document.querySelector('input[name=new_password]').value;
|
||||
if (value !== password) {
|
||||
return '两次输入的密码不一致';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 监听提交
|
||||
form.on('submit(updatePassword)', function (data) {
|
||||
// 显示加载中
|
||||
var loadIndex = layer.load(2);
|
||||
|
||||
$.ajax({
|
||||
url: '/index/user/updatePassword',
|
||||
type: 'POST',
|
||||
data: data.field,
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
layer.close(loadIndex);
|
||||
if (res.code === 0) {
|
||||
layer.msg(res.msg, {
|
||||
icon: 1,
|
||||
time: 1000,
|
||||
end: function() {
|
||||
// 设置跳转标记
|
||||
parent.window.needRedirect = true;
|
||||
// 关闭当前弹窗
|
||||
var index = parent.layer.getFrameIndex(window.name);
|
||||
parent.layer.close(index);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, { icon: 2 });
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.close(loadIndex);
|
||||
layer.msg('请求失败,请重试', { icon: 2 });
|
||||
}
|
||||
});
|
||||
return false; // 阻止表单默认提交
|
||||
});
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user