增加文章点赞和分享功能

This commit is contained in:
李志强 2025-05-20 11:28:29 +08:00
parent 16d2fe4520
commit 40caef19dd
5 changed files with 391 additions and 209 deletions

View File

@ -142,6 +142,16 @@ class ArticlesController extends BaseController
$id = Request::param('id/d', 0);
// 检查文章是否存在
$article = Articles::where('id', $id)
->where('delete_time', null)
->where('status', 2)
->find();
if (!$article) {
return json(['code' => 0, 'msg' => '文章不存在或已被删除']);
}
// 更新点赞数
$result = Articles::where('id', $id)
->where('delete_time', null)
@ -149,7 +159,15 @@ class ArticlesController extends BaseController
->update();
if ($result) {
return json(['code' => 1, 'msg' => '点赞成功']);
// 返回更新后的点赞数
$newLikes = $article['likes'] + 1;
return json([
'code' => 1,
'msg' => '点赞成功',
'data' => [
'likes' => $newLikes
]
]);
} else {
return json(['code' => 0, 'msg' => '点赞失败']);
}

View File

@ -30,12 +30,12 @@
</div>
<div class="article-actions">
<div class="action-item like-btn">
<div class="action-item like-btn" id="likeBtn">
<i class="fa fa-thumbs-up"></i>
<span class="action-text">点赞</span>
<span class="action-count" id="articleLikes">0</span>
</div>
<div class="action-item share-btn">
<div class="action-item share-btn" id="shareBtn">
<i class="fa fa-share-alt"></i>
<span class="action-text">分享</span>
</div>
@ -503,7 +503,7 @@
}
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('DOMContentLoaded', function () {
// 获取文章ID
const articleId = new URLSearchParams(window.location.search).get('id');
if (!articleId) {
@ -518,12 +518,12 @@
}
})
.then(response => {
console.log('Response status:', response.status);
console.log('Response headers:', response.headers);
// console.log('Response status:', response.status);
// console.log('Response headers:', response.headers);
return response.json();
})
.then(result => {
console.log('API response:', result);
// console.log('API response:', result);
if (result.code === 1) {
renderArticleDetail(result.data);
// 更新访问次数
@ -543,27 +543,52 @@
});
// 点赞功能
const likeBtn = document.querySelector('.like-btn');
const likeBtn = document.getElementById('likeBtn');
if (likeBtn) {
likeBtn.addEventListener('click', function() {
// 检查是否已经点赞
if (likeBtn.classList.contains('liked')) {
likeBtn.style.pointerEvents = 'none'; // 禁用点击
likeBtn.style.cursor = 'default'; // 改变鼠标样式
return;
}
likeBtn.addEventListener('click', function () {
// 立即禁用按钮,防止重复点击
likeBtn.style.pointerEvents = 'none';
likeBtn.style.cursor = 'default';
fetch('/index/articles/like?id=' + articleId, {
method: 'POST'
})
.then(response => response.json())
.then(data => {
if (data.code === 1) {
const countElement = this.querySelector('.action-count');
let count = parseInt(countElement.textContent);
countElement.textContent = count + 1;
this.classList.add('liked');
this.style.color = '#f57005';
} else {
alert('点赞失败:' + data.msg);
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.catch(error => {
console.error('点赞请求失败:', error);
});
.then(response => response.json())
.then(data => {
if (data.code === 1) {
const countElement = document.getElementById('articlesLikes');
if (countElement) {
let count = parseInt(countElement.textContent) || 0;
countElement.textContent = count + 1;
}
// 添加点赞状态
likeBtn.classList.add('liked');
likeBtn.querySelector('i').style.color = '#f57005';
layer.msg('点赞成功', {icon: 1});
} else {
// 如果请求失败,恢复按钮状态
likeBtn.style.pointerEvents = 'auto';
likeBtn.style.cursor = 'pointer';
layer.msg('点赞失败:' + data.msg, {icon: 2});
}
})
.catch(error => {
// 如果请求失败,恢复按钮状态
likeBtn.style.pointerEvents = 'auto';
likeBtn.style.cursor = 'pointer';
console.error('点赞请求失败:', error);
layer.msg('点赞失败,请稍后重试', {icon: 2});
});
});
}
@ -571,7 +596,7 @@
const goToTop = document.getElementById('goToTop');
// 监听滚动事件
window.addEventListener('scroll', function() {
window.addEventListener('scroll', function () {
if (window.pageYOffset > 300) {
goToTop.classList.add('show');
} else {
@ -580,7 +605,7 @@
});
// 点击返回顶部
goToTop.addEventListener('click', function() {
goToTop.addEventListener('click', function () {
window.scrollTo({
top: 0,
behavior: 'smooth'
@ -599,18 +624,42 @@
id: articleId
})
})
.then(response => response.json())
.then(result => {
if (result.code === 1) {
// 更新成功,更新页面上的访问次数显示
const viewsElement = document.getElementById('articleViews');
if (viewsElement) {
viewsElement.textContent = result.data.views;
.then(response => response.json())
.then(result => {
if (result.code === 1) {
// 更新成功,更新页面上的访问次数显示
const viewsElement = document.getElementById('articleViews');
if (viewsElement) {
viewsElement.textContent = result.data.views;
}
}
}
})
.catch(error => {
console.error('更新访问次数失败:', error);
})
.catch(error => {
console.error('更新访问次数失败:', error);
});
}
// 分享功能
const shareBtn = document.getElementById('shareBtn');
if (shareBtn) {
shareBtn.addEventListener('click', function () {
// 获取当前页面URL
const currentUrl = window.location.href;
// 创建临时输入框
const tempInput = document.createElement('input');
tempInput.value = currentUrl;
document.body.appendChild(tempInput);
// 选择并复制文本
tempInput.select();
document.execCommand('copy');
// 移除临时输入框
document.body.removeChild(tempInput);
// 提示用户复制成功
alert('链接已复制到剪贴板');
});
}
</script>

View File

@ -18,7 +18,8 @@
<span class="program-author"><i class="fa fa-user"></i> <span id="programAuthor"></span></span>
<span class="program-date"><i class="fa fa-calendar"></i> <span id="programDate"></span></span>
<span class="program-views"><i class="fa-solid fa-eye"></i> <span id="programViews"></span> 浏览</span>
<span class="program-downloads"><i class="fa-solid fa-download"></i> <span id="programDownloads"></span> 下载</span>
<span class="program-downloads"><i class="fa-solid fa-download"></i> <span id="programDownloads"></span>
下载</span>
</div>
</div>
@ -44,12 +45,16 @@
</div>
</div>
<div class="program-content">
</div>
<div class="program-actions">
<div class="action-item download-btn" id="downloadBtn">
<i class="fa fa-download"></i>
<span class="action-text">立即下载</span>
</div>
<div class="action-item share-btn">
<div class="action-item share-btn" id="shareBtn">
<i class="fa fa-share-alt"></i>
<span class="action-text">分享</span>
</div>
@ -203,7 +208,7 @@
margin: 30px 0;
}
.program-navigation a{
.program-navigation a {
color: #333;
text-decoration: none;
}
@ -428,7 +433,7 @@
}
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('DOMContentLoaded', function () {
// 获取程序ID
const programId = new URLSearchParams(window.location.search).get('id');
if (!programId) {
@ -442,44 +447,46 @@
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(result => {
if (result.code === 1) {
renderProgramDetail(result.data);
// 更新访问次数
updateProgramViews(programId);
} else {
alert(result.msg || '获取程序详情失败');
}
})
.catch(error => {
console.error('获取程序详情失败:', error);
alert('获取程序详情失败,请检查网络连接或刷新页面重试');
});
.then(response => response.json())
.then(result => {
if (result.code === 1) {
renderProgramDetail(result.data);
// 更新访问次数
updateProgramViews(programId);
// 初始化分享功能
initShareFunction();
} else {
alert(result.msg || '获取程序详情失败');
}
})
.catch(error => {
console.error('获取程序详情失败:', error);
alert('获取程序详情失败,请检查网络连接或刷新页面重试');
});
// 下载功能
const downloadBtn = document.getElementById('downloadBtn');
if (downloadBtn) {
downloadBtn.addEventListener('click', function() {
downloadBtn.addEventListener('click', function () {
fetch('/index/program/download?id=' + programId, {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.code === 1 && data.data && data.data.fileurl) {
const downloadUrl = window.location.origin + data.data.fileurl;
window.location.href = downloadUrl;
} else {
alert('下载地址不存在');
}
})
.catch(error => {
console.error('下载请求失败:', error);
alert('下载请求失败,请稍后重试');
});
.then(response => response.json())
.then(data => {
if (data.code === 1 && data.data && data.data.fileurl) {
const downloadUrl = window.location.origin + data.data.fileurl;
window.location.href = downloadUrl;
} else {
alert('下载地址不存在');
}
})
.catch(error => {
console.error('下载请求失败:', error);
alert('下载请求失败,请稍后重试');
});
});
}
@ -487,7 +494,7 @@
const goToTop = document.getElementById('goToTop');
// 监听滚动事件
window.addEventListener('scroll', function() {
window.addEventListener('scroll', function () {
if (window.pageYOffset > 300) {
goToTop.classList.add('show');
} else {
@ -496,7 +503,7 @@
});
// 点击返回顶部
goToTop.addEventListener('click', function() {
goToTop.addEventListener('click', function () {
window.scrollTo({
top: 0,
behavior: 'smooth'
@ -516,19 +523,45 @@
id: programId
})
})
.then(response => response.json())
.then(result => {
if (result.code === 1) {
// 更新成功,更新页面上的访问次数显示
const viewsElement = document.getElementById('programViews');
if (viewsElement) {
viewsElement.textContent = result.data.views;
.then(response => response.json())
.then(result => {
if (result.code === 1) {
// 更新成功,更新页面上的访问次数显示
const viewsElement = document.getElementById('programViews');
if (viewsElement) {
viewsElement.textContent = result.data.views;
}
}
}
})
.catch(error => {
console.error('更新访问次数失败:', error);
});
})
.catch(error => {
console.error('更新访问次数失败:', error);
});
}
// 初始化分享功能
function initShareFunction() {
const shareBtn = document.getElementById('shareBtn');
if (shareBtn) {
shareBtn.addEventListener('click', function () {
// 获取当前页面URL
const currentUrl = window.location.href;
// 创建临时输入框
const tempInput = document.createElement('input');
tempInput.value = currentUrl;
document.body.appendChild(tempInput);
// 选择并复制文本
tempInput.select();
document.execCommand('copy');
// 移除临时输入框
document.body.removeChild(tempInput);
// 提示用户复制成功
layer.msg('链接已复制到剪贴板');
});
}
}
</script>
{include file="component/foot" /}

View File

@ -1,4 +1,4 @@
<?php /*a:5:{s:63:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\articles\detail.php";i:1747646466;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\head.php";i:1747617129;s:71:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\header-simple.php";i:1747445574;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\footer.php";i:1747617266;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\foot.php";i:1747616844;}*/ ?>
<?php /*a:5:{s:63:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\articles\detail.php";i:1747711602;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\head.php";i:1747617129;s:71:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\header-simple.php";i:1747705841;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\footer.php";i:1747617266;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\foot.php";i:1747616844;}*/ ?>
<!DOCTYPE html>
<html>
@ -48,7 +48,7 @@
<div class="main-menu">
<div class="container">
<div class="main-menu__logo">
<a href="index.html"><img src="/static/images/logo.png" width="186" alt="Logo"></a>
<a href="index.html"><img src="/static/images/logo1.png" width="186" alt="Logo"></a>
</div>
<div class="main-menu__nav">
<ul class="main-menu__list">
@ -90,7 +90,7 @@
<div class="sticky-nav" style="display: none;">
<div class="container">
<div class="sticky-nav__logo">
<a href="index.html"><img src="/static/images/logo.png" width="150" alt="Logo"></a>
<a href="index.html"><img src="/static/images/logo1.png" width="150" alt="Logo"></a>
</div>
<div class="sticky-nav__menu">
<ul>
@ -475,12 +475,12 @@
</div>
<div class="article-actions">
<div class="action-item like-btn">
<div class="action-item like-btn" id="likeBtn">
<i class="fa fa-thumbs-up"></i>
<span class="action-text">点赞</span>
<span class="action-count" id="articleLikes">0</span>
</div>
<div class="action-item share-btn">
<div class="action-item share-btn" id="shareBtn">
<i class="fa fa-share-alt"></i>
<span class="action-text">分享</span>
</div>
@ -1003,7 +1003,7 @@
}
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('DOMContentLoaded', function () {
// 获取文章ID
const articleId = new URLSearchParams(window.location.search).get('id');
if (!articleId) {
@ -1018,12 +1018,12 @@
}
})
.then(response => {
console.log('Response status:', response.status);
console.log('Response headers:', response.headers);
// console.log('Response status:', response.status);
// console.log('Response headers:', response.headers);
return response.json();
})
.then(result => {
console.log('API response:', result);
// console.log('API response:', result);
if (result.code === 1) {
renderArticleDetail(result.data);
// 更新访问次数
@ -1043,27 +1043,52 @@
});
// 点赞功能
const likeBtn = document.querySelector('.like-btn');
const likeBtn = document.getElementById('likeBtn');
if (likeBtn) {
likeBtn.addEventListener('click', function() {
// 检查是否已经点赞
if (likeBtn.classList.contains('liked')) {
likeBtn.style.pointerEvents = 'none'; // 禁用点击
likeBtn.style.cursor = 'default'; // 改变鼠标样式
return;
}
likeBtn.addEventListener('click', function () {
// 立即禁用按钮,防止重复点击
likeBtn.style.pointerEvents = 'none';
likeBtn.style.cursor = 'default';
fetch('/index/articles/like?id=' + articleId, {
method: 'POST'
})
.then(response => response.json())
.then(data => {
if (data.code === 1) {
const countElement = this.querySelector('.action-count');
let count = parseInt(countElement.textContent);
countElement.textContent = count + 1;
this.classList.add('liked');
this.style.color = '#f57005';
} else {
alert('点赞失败:' + data.msg);
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.catch(error => {
console.error('点赞请求失败:', error);
});
.then(response => response.json())
.then(data => {
if (data.code === 1) {
const countElement = document.getElementById('articlesLikes');
if (countElement) {
let count = parseInt(countElement.textContent) || 0;
countElement.textContent = count + 1;
}
// 添加点赞状态
likeBtn.classList.add('liked');
likeBtn.querySelector('i').style.color = '#f57005';
layer.msg('点赞成功', {icon: 1});
} else {
// 如果请求失败,恢复按钮状态
likeBtn.style.pointerEvents = 'auto';
likeBtn.style.cursor = 'pointer';
layer.msg('点赞失败:' + data.msg, {icon: 2});
}
})
.catch(error => {
// 如果请求失败,恢复按钮状态
likeBtn.style.pointerEvents = 'auto';
likeBtn.style.cursor = 'pointer';
console.error('点赞请求失败:', error);
layer.msg('点赞失败,请稍后重试', {icon: 2});
});
});
}
@ -1071,7 +1096,7 @@
const goToTop = document.getElementById('goToTop');
// 监听滚动事件
window.addEventListener('scroll', function() {
window.addEventListener('scroll', function () {
if (window.pageYOffset > 300) {
goToTop.classList.add('show');
} else {
@ -1080,7 +1105,7 @@
});
// 点击返回顶部
goToTop.addEventListener('click', function() {
goToTop.addEventListener('click', function () {
window.scrollTo({
top: 0,
behavior: 'smooth'
@ -1099,18 +1124,42 @@
id: articleId
})
})
.then(response => response.json())
.then(result => {
if (result.code === 1) {
// 更新成功,更新页面上的访问次数显示
const viewsElement = document.getElementById('articleViews');
if (viewsElement) {
viewsElement.textContent = result.data.views;
.then(response => response.json())
.then(result => {
if (result.code === 1) {
// 更新成功,更新页面上的访问次数显示
const viewsElement = document.getElementById('articleViews');
if (viewsElement) {
viewsElement.textContent = result.data.views;
}
}
}
})
.catch(error => {
console.error('更新访问次数失败:', error);
})
.catch(error => {
console.error('更新访问次数失败:', error);
});
}
// 分享功能
const shareBtn = document.getElementById('shareBtn');
if (shareBtn) {
shareBtn.addEventListener('click', function () {
// 获取当前页面URL
const currentUrl = window.location.href;
// 创建临时输入框
const tempInput = document.createElement('input');
tempInput.value = currentUrl;
document.body.appendChild(tempInput);
// 选择并复制文本
tempInput.select();
document.execCommand('copy');
// 移除临时输入框
document.body.removeChild(tempInput);
// 提示用户复制成功
alert('链接已复制到剪贴板');
});
}
</script>

View File

@ -1,4 +1,4 @@
<?php /*a:5:{s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\program\detail.php";i:1747706200;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\head.php";i:1747617129;s:71:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\header-simple.php";i:1747705841;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\footer.php";i:1747617266;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\foot.php";i:1747616844;}*/ ?>
<?php /*a:5:{s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\program\detail.php";i:1747709473;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\head.php";i:1747617129;s:71:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\header-simple.php";i:1747705841;s:64:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\footer.php";i:1747617266;s:62:"E:\Demos\DemoOwns\PHP\yunzer\app\index\view\component\foot.php";i:1747616844;}*/ ?>
<!DOCTYPE html>
<html>
@ -463,7 +463,8 @@
<span class="program-author"><i class="fa fa-user"></i> <span id="programAuthor"></span></span>
<span class="program-date"><i class="fa fa-calendar"></i> <span id="programDate"></span></span>
<span class="program-views"><i class="fa-solid fa-eye"></i> <span id="programViews"></span> 浏览</span>
<span class="program-downloads"><i class="fa-solid fa-download"></i> <span id="programDownloads"></span> 下载</span>
<span class="program-downloads"><i class="fa-solid fa-download"></i> <span id="programDownloads"></span>
下载</span>
</div>
</div>
@ -489,12 +490,16 @@
</div>
</div>
<div class="program-content">
</div>
<div class="program-actions">
<div class="action-item download-btn" id="downloadBtn">
<i class="fa fa-download"></i>
<span class="action-text">立即下载</span>
</div>
<div class="action-item share-btn">
<div class="action-item share-btn" id="shareBtn">
<i class="fa fa-share-alt"></i>
<span class="action-text">分享</span>
</div>
@ -703,7 +708,7 @@
margin: 30px 0;
}
.program-navigation a{
.program-navigation a {
color: #333;
text-decoration: none;
}
@ -928,7 +933,7 @@
}
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('DOMContentLoaded', function () {
// 获取程序ID
const programId = new URLSearchParams(window.location.search).get('id');
if (!programId) {
@ -942,44 +947,46 @@
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(result => {
if (result.code === 1) {
renderProgramDetail(result.data);
// 更新访问次数
updateProgramViews(programId);
} else {
alert(result.msg || '获取程序详情失败');
}
})
.catch(error => {
console.error('获取程序详情失败:', error);
alert('获取程序详情失败,请检查网络连接或刷新页面重试');
});
.then(response => response.json())
.then(result => {
if (result.code === 1) {
renderProgramDetail(result.data);
// 更新访问次数
updateProgramViews(programId);
// 初始化分享功能
initShareFunction();
} else {
alert(result.msg || '获取程序详情失败');
}
})
.catch(error => {
console.error('获取程序详情失败:', error);
alert('获取程序详情失败,请检查网络连接或刷新页面重试');
});
// 下载功能
const downloadBtn = document.getElementById('downloadBtn');
if (downloadBtn) {
downloadBtn.addEventListener('click', function() {
downloadBtn.addEventListener('click', function () {
fetch('/index/program/download?id=' + programId, {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.code === 1 && data.data && data.data.fileurl) {
const downloadUrl = window.location.origin + data.data.fileurl;
window.location.href = downloadUrl;
} else {
alert('下载地址不存在');
}
})
.catch(error => {
console.error('下载请求失败:', error);
alert('下载请求失败,请稍后重试');
});
.then(response => response.json())
.then(data => {
if (data.code === 1 && data.data && data.data.fileurl) {
const downloadUrl = window.location.origin + data.data.fileurl;
window.location.href = downloadUrl;
} else {
alert('下载地址不存在');
}
})
.catch(error => {
console.error('下载请求失败:', error);
alert('下载请求失败,请稍后重试');
});
});
}
@ -987,7 +994,7 @@
const goToTop = document.getElementById('goToTop');
// 监听滚动事件
window.addEventListener('scroll', function() {
window.addEventListener('scroll', function () {
if (window.pageYOffset > 300) {
goToTop.classList.add('show');
} else {
@ -996,7 +1003,7 @@
});
// 点击返回顶部
goToTop.addEventListener('click', function() {
goToTop.addEventListener('click', function () {
window.scrollTo({
top: 0,
behavior: 'smooth'
@ -1016,19 +1023,45 @@
id: programId
})
})
.then(response => response.json())
.then(result => {
if (result.code === 1) {
// 更新成功,更新页面上的访问次数显示
const viewsElement = document.getElementById('programViews');
if (viewsElement) {
viewsElement.textContent = result.data.views;
.then(response => response.json())
.then(result => {
if (result.code === 1) {
// 更新成功,更新页面上的访问次数显示
const viewsElement = document.getElementById('programViews');
if (viewsElement) {
viewsElement.textContent = result.data.views;
}
}
}
})
.catch(error => {
console.error('更新访问次数失败:', error);
});
})
.catch(error => {
console.error('更新访问次数失败:', error);
});
}
// 初始化分享功能
function initShareFunction() {
const shareBtn = document.getElementById('shareBtn');
if (shareBtn) {
shareBtn.addEventListener('click', function () {
// 获取当前页面URL
const currentUrl = window.location.href;
// 创建临时输入框
const tempInput = document.createElement('input');
tempInput.value = currentUrl;
document.body.appendChild(tempInput);
// 选择并复制文本
tempInput.select();
document.execCommand('copy');
// 移除临时输入框
document.body.removeChild(tempInput);
// 提示用户复制成功
layer.msg('链接已复制到剪贴板');
});
}
}
</script>
</body>