Browse Source

点赞取消功能

dev_des
1054425342@qq.com 4 weeks ago
parent
commit
9e4a60001e
  1. 6
      components/DynamicIsland.vue
  2. 79
      components/WaterfallLayout.vue
  3. 70
      pages/index/timeShopBank.vue
  4. 138
      pages/notes/detail.vue
  5. 4
      static/js/request.js

6
components/DynamicIsland.vue

@ -104,6 +104,7 @@
<view class="time-reward-label" @click="toPoint" <view class="time-reward-label" @click="toPoint"
style="margin-top: 15rpx;font-weight: bold;font-size: 26rpx;"> style="margin-top: 15rpx;font-weight: bold;font-size: 26rpx;">
积分:{{totalPoints||0}}<text 积分:{{totalPoints||0}}<text
@click.stop="pointDetail"
style="color: #999999;font-size: 22rpx;margin-left: 10rpx;">积分获取规则</text> style="color: #999999;font-size: 22rpx;margin-left: 10rpx;">积分获取规则</text>
</view> </view>
</view> </view>
@ -387,6 +388,11 @@
url: '/subPackages/other/introduction' url: '/subPackages/other/introduction'
}) })
}, },
pointDetail(){
uni.navigateTo({
url:'/subPackages/user/privacyInfo?id=10222'
})
}
}, },
}; };

79
components/WaterfallLayout.vue

@ -12,7 +12,6 @@
<view class="column"> <view class="column">
<view <view
v-for="(item, index) in leftItems" v-for="(item, index) in leftItems"
:key="item.id || index"
class="waterfall-item" class="waterfall-item"
@click="handleItemClick(index, leftItems)" @click="handleItemClick(index, leftItems)"
> >
@ -33,16 +32,16 @@
/> />
<text class="username">{{ item.nickname }}</text> <text class="username">{{ item.nickname }}</text>
</view> </view>
<view class="like-info"> <view class="like-info" @click.stop="handleLikeClick(item)">
<image <image
v-if="!item.userLiked" v-if="!item.userLiked"
src="https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png" src="https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png"
style="height: 22rpx; width: 25rpx" style="height: 30rpx; width: 35rpx"
></image> ></image>
<image <image
v-else v-else
src="https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png" src="https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png"
style="height: 22rpx; width: 25rpx" style="height: 30rpx; width: 35rpx"
></image> ></image>
<text class="like-count">{{ item.likeCount || 0 }}</text> <text class="like-count">{{ item.likeCount || 0 }}</text>
</view> </view>
@ -55,7 +54,6 @@
<view class="column"> <view class="column">
<view <view
v-for="(item, index) in rightItems" v-for="(item, index) in rightItems"
:key="item.id || index"
class="waterfall-item" class="waterfall-item"
@click="handleItemClick(index, rightItems)" @click="handleItemClick(index, rightItems)"
> >
@ -79,16 +77,16 @@
}}{{ item.nickname }}</text }}{{ item.nickname }}</text
> >
</view> </view>
<view class="like-info"> <view class="like-info" @click.stop="handleLikeClick(item)">
<image <image
v-if="!item.userLiked" v-if="!item.userLiked"
src="https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png" src="https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png"
style="height: 22rpx; width: 25rpx" style="height: 30rpx; width: 35rpx"
></image> ></image>
<image <image
v-else v-else
src="https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png" src="https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png"
style="height: 22rpx; width: 25rpx" style="height: 30rpx; width: 35rpx"
></image> ></image>
<text class="like-count">{{ item.likeCount || 0 }}</text> <text class="like-count">{{ item.likeCount || 0 }}</text>
</view> </view>
@ -144,6 +142,70 @@ export default {
this.calculateLayout(this.items); this.calculateLayout(this.items);
}, },
methods: { methods: {
// /
handleLikeClick(item) {
if (!item || !item.id) {
uni.showToast({
title: "操作失败,笔记ID不存在",
icon: "none",
});
return;
}
// UI
const isLiked = !item.userLiked;
item.userLiked = isLiked;
item.likeCount = isLiked
? (item.likeCount || 0) + 1
: Math.max((item.likeCount || 0) - 1, 0);
// API
const url = isLiked
? `/framework/noteLike/add/${item.id}`
: `/framework/noteLike/cancel/${item.id}`;
this.Post({}, url, "DES")
.then((res) => {
if (res.code !== 200) {
// UI
item.userLiked = !isLiked;
item.likeCount = !isLiked
? (item.likeCount || 0) + 1
: Math.max((item.likeCount || 0) - 1, 0);
uni.showToast({
title: res.msg || "操作失败,请稍后重试",
icon: "none",
});
} else {
//
this.$emit("like-change", {
noteId: item.id,
isLiked: isLiked,
likeCount: item.likeCount,
});
//
uni.$emit('note-like-change', {
noteId: item.id,
isLiked: isLiked,
likeCount: item.likeCount
});
}
})
.catch((err) => {
// UI
item.userLiked = !isLiked;
item.likeCount = !isLiked
? (item.likeCount || 0) + 1
: Math.max((item.likeCount || 0) - 1, 0);
uni.showToast({
title: err.msg || "网络异常,请稍后重试",
icon: "none",
});
});
},
// DOM // DOM
getColumnHeight(columnRef) { getColumnHeight(columnRef) {
if (!columnRef) return 0; if (!columnRef) return 0;
@ -370,6 +432,7 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6rpx; gap: 6rpx;
padding: 4rpx 8rpx;
} }
.like-icon { .like-icon {

70
pages/index/timeShopBank.vue

@ -44,20 +44,13 @@
<!-- 内容区域 --> <!-- 内容区域 -->
<view class="content-area"> <view class="content-area">
<view v-if="currentTab == 0" class="notes-content"> <view v-if="currentTab == 0" class="notes-content">
<view class="fab-container">
<image
:src="
showImg('/uploads/20250825/7ea7864b8abb89c3dd7834f025e49b3f.png')
"
style="width: 91rpx; height: 91rpx"
></image>
</view>
<WaterfallLayout <WaterfallLayout
:items="waterfallItems" :items="waterfallItems"
:column-count="2" :column-count="2"
:column-gap="16" :column-gap="16"
:item-gap="16" :item-gap="16"
@item-click="handleItemClick" @item-click="handleItemClick"
@like-change="handleNoteLikeChange"
style="margin-top: 20rpx" style="margin-top: 20rpx"
/> />
</view> </view>
@ -66,32 +59,32 @@
</view> --> </view> -->
<!-- 关注tab内容 --> <!-- 关注tab内容 -->
<view v-if="currentTab == 1" class="follow-content"> <view v-if="currentTab == 1" class="follow-content">
<FollowTab /> <!-- <FollowTab /> -->
<!-- <text class="coming-soon">关注功能开发中...</text> --> <text class="coming-soon">关注功能开发中...</text>
</view> </view>
<!-- 推荐tab内容 --> <!-- 推荐tab内容 -->
<view v-if="currentTab == 2" class="notes-content"> <view v-if="currentTab == 2" class="notes-content">
<view class="fab-container">
<image
@click="goToPublish"
:src="
showImg('/uploads/20250825/7ea7864b8abb89c3dd7834f025e49b3f.png')
"
style="width: 91rpx; height: 91rpx"
></image>
</view>
<WaterfallLayout <WaterfallLayout
:items="waterfallItems" :items="waterfallItems"
:column-count="2" :column-count="2"
:column-gap="16" :column-gap="16"
:item-gap="16" :item-gap="16"
@item-click="handleItemClick" @item-click="handleItemClick"
@like-change="handleNoteLikeChange"
style="margin-top: 20rpx" style="margin-top: 20rpx"
/> />
</view> </view>
</view> </view>
<!-- <view class="fab-container">
<image
@click="goToPublish"
:src="
showImg('/uploads/20250825/7ea7864b8abb89c3dd7834f025e49b3f.png')
"
style="width: 91rpx; height: 91rpx"
></image>
</view> -->
<!-- 控制按钮 --> <!-- 控制按钮 -->
<!-- <view class="controls"> <!-- <view class="controls">
<button @click="addRandomItem" class="control-btn primary"> <button @click="addRandomItem" class="control-btn primary">
@ -149,6 +142,9 @@ export default {
{}; {};
// //
this.getRecommendList(1); this.getRecommendList(1);
//
uni.$on("note-like-change", this.handleNoteLikeChange);
}, },
onShow() { onShow() {
if (this.userInfo && this.userInfo.id) { if (this.userInfo && this.userInfo.id) {
@ -156,6 +152,11 @@ export default {
} }
}, },
//
onUnload() {
uni.$off("note-like-change", this.handleNoteLikeChange);
},
// //
onReachBottom() { onReachBottom() {
this.loadMoreItems(); this.loadMoreItems();
@ -283,6 +284,34 @@ export default {
} }
// tab // tab
}, },
//
handleNoteLikeChange(data) {
console.log(data, "data");
if (!data || !data.noteId) return;
//
const updateItemInList = (items) => {
for (let i = 0; i < items.length; i++) {
if (items[i].id == data.noteId) {
//
items[i].userLiked = data.isLiked;
items[i].likeCount = data.likeCount;
return true;
}
}
return false;
};
//
const updated = updateItemInList(this.waterfallItems);
console.log(updated, "updated");
//
if (updated) {
// 使Vue
this.$forceUpdate();
}
},
}, },
}; };
</script> </script>
@ -362,7 +391,6 @@ page {
justify-content: center; justify-content: center;
height: 100%; height: 100%;
position: relative; position: relative;
cursor: pointer;
} }
.tab-text { .tab-text {

138
pages/notes/detail.vue

@ -14,7 +14,12 @@
@change="swiperChange" @change="swiperChange"
> >
<swiper-item v-for="(item, index) in topBanner" :key="index"> <swiper-item v-for="(item, index) in topBanner" :key="index">
<image class="top-banner" :src="item" mode="aspectFill" @click="previewImage(item)"></image> <image
class="top-banner"
:src="item"
mode="aspectFill"
@click="previewImage(item)"
></image>
</swiper-item> </swiper-item>
</swiper> </swiper>
@ -39,13 +44,13 @@
<view class="author-info"> <view class="author-info">
<text class="author-name">{{ noteDetail.nickname }}</text> <text class="author-name">{{ noteDetail.nickname }}</text>
</view> </view>
<!-- <view <view
class="follow-btn" class="follow-btn"
:class="{ followed: noteDetail.user.isFollowed }" :class="{ followed: noteDetail.user.isFollowed }"
@click="toggleFollow" @click="toggleFollow"
> >
{{ noteDetail.user.isFollowed ? "已关注" : "关注" }} {{ noteDetail.user.isFollowed ? "已关注" : "关注" }}
</view> --> </view>
</view> </view>
<!-- 笔记标题 --> <!-- 笔记标题 -->
<view class="note-title"> <view class="note-title">
@ -91,7 +96,7 @@
<view class="comments-section"> <view class="comments-section">
<view class="comments-header"> <view class="comments-header">
<text class="comments-title" <text class="comments-title"
>评论 ({{ noteDetail.comments.length }})</text >评论 ({{ noteDetail.commentCount || 0 }})</text
> >
</view> </view>
@ -143,18 +148,14 @@
mode="widthFix" mode="widthFix"
:src=" :src="
!noteDetail.userLiked !noteDetail.userLiked
? showImg( ? 'https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png'
'https://epic.js-dyyj.com/uploads/20250728/2f3ae212c01fa3b67be81abc5723cf5c.png' : 'https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png'
)
: showImg(
'https://epic.js-dyyj.com/uploads/20250728/dd7ed269b24e84a2dd141da6ab980fd6.png'
)
" "
></image> ></image>
<text <text
class="like-count" class="like-count"
:class="{ 'liked-text': noteDetail.userLiked }" :class="{ 'liked-text': noteDetail.userLiked }"
>{{ noteDetail.likeCount }}</text >{{ noteDetail.likeCount || 0 }}</text
> >
</view> </view>
</view> </view>
@ -241,52 +242,6 @@ export default {
uni.hideLoading(); uni.hideLoading();
} }
}, },
//
loadMockData() {
this.noteDetail = {
id: "mock001",
title: "首期「桃园山河令」",
content:
"一周前,我们种下了一片想象中的桃园,并向江湖发出了一封「桃园山河令」,邀请你来分享属于自己的“桃园时刻”。未曾想到,这片初生的桃园,会迎来五湖四海如此多的“桃园客”——这是我们想送给每一位「EpicSoul交响」星球上「三个桃子」粉丝的名字。这些回响,来自每一位被「三个桃子」IP故事所触动的你。因为是你们,用一个个真实、温暖的故事,让我们想象中的那片桃园,迅速地枝繁叶茂,长满了沉甸甸的果实。",
image: "https://des.dayunyuanjian.cn/epicSoul/canal-town.jpg",
tags: ["时间里的约定", "审美", "治愈系调色"],
likes: 30,
isLiked: false,
createTime: "2025-08-20 14:30:00",
user: {
id: "user001",
name: "发布者",
avatar: "/uploads/20250826/b4b7c64ce37481e75742454c037e6407.png",
isFollowed: false,
},
comments: [
{
id: "comment001",
content:
"我的「桃园时刻」是和发小一起玩耍,阳光透过桃叶洒下斑驳光影,空气中弥漫着桃子的香甜。我们一起摘桃子,分享秘密,笑声在桃园里回荡。",
createTime: "2025-08-20 15:00:00",
user: {
id: "user002",
name: "@小新",
avatar: "/uploads/20250826/d68433653e8b8cceba9bc4a6ab2a394d.png",
},
},
{
id: "comment002",
content:
"我的「桃园时刻」是和家人一起野餐,在桃树下享受美食,孩子们在周围嬉戏,欢声笑语让时光变得缓慢而美好。",
createTime: "2025-08-20 16:20:00",
user: {
id: "user003",
name: "Mr.曾",
avatar: "/uploads/20250826/d68433653e8b8cceba9bc4a6ab2a394d.png",
},
},
],
};
},
// //
previewImage(imageUrl) { previewImage(imageUrl) {
uni.previewImage({ uni.previewImage({
@ -333,36 +288,69 @@ export default {
// //
async toggleLike() { async toggleLike() {
if (!this.noteId) {
uni.showToast({
title: "笔记ID不存在",
icon: "none",
});
return;
}
try { try {
const action = this.noteDetail.isLiked ? "cancel" : "like"; //
const res = await this.Post( const originalLiked = this.noteDetail.userLiked;
{ const originalLikeCount = this.noteDetail.likeCount || 0;
method: "POST",
noteId: this.noteId,
action: action,
},
"/framework/note/like",
"DES"
);
if (res.code === 200) { // UI
this.noteDetail.isLiked = !this.noteDetail.isLiked; this.noteDetail.userLiked = !this.noteDetail.userLiked;
this.noteDetail.likes += this.noteDetail.isLiked ? 1 : -1; this.noteDetail.likeCount =
(this.noteDetail.likeCount || 0) +
(this.noteDetail.userLiked ? 1 : -1);
// API
const apiUrl = this.noteDetail.userLiked
? "/framework/noteLike/add/" + this.noteId
: "/framework/noteLike/cancel/" + this.noteId;
const res = await this.Post({}, apiUrl, "DES");
// if (res.code === 200) {
// API使API
if (res.data && res.data.likeCount !== undefined) { if (res.data && res.data.likeCount !== undefined) {
this.noteDetail.likes = res.data.likeCount; this.noteDetail.likeCount = res.data.likeCount;
} }
// timeShopBank
uni.$emit('note-like-change', {
noteId: this.noteId,
isLiked: this.noteDetail.userLiked,
likeCount: this.noteDetail.likeCount
});
//
} else { } else {
// UI
this.noteDetail.userLiked = originalLiked;
this.noteDetail.likeCount = originalLikeCount;
uni.showToast({ uni.showToast({
title: res.msg || (action === "like" ? "点赞失败" : "取消点赞失败"), title:
res.msg ||
(this.noteDetail.userLiked ? "点赞失败" : "取消点赞失败"),
icon: "none", icon: "none",
}); });
} }
} catch (error) { } catch (error) {
console.error("点赞操作失败:", error); console.error("点赞操作失败:", error);
// UI
this.noteDetail.userLiked = !this.noteDetail.userLiked;
this.noteDetail.likeCount =
(this.noteDetail.likeCount || 0) +
(this.noteDetail.userLiked ? 1 : -1);
uni.showToast({ uni.showToast({
title: "操作失败", title: "网络异常,请稍后重试",
icon: "none", icon: "none",
}); });
} }
@ -629,7 +617,7 @@ export default {
} }
.comment-input-section-box { .comment-input-section-box {
position: fixed; position: fixed;
bottom: 0; bottom: -1px;
left: 0; left: 0;
right: 0; right: 0;
z-index: 999; z-index: 999;

4
static/js/request.js

@ -9,8 +9,8 @@ const DEV_API_URL = 'https://epic.dayunyuanjian.cn';
const PROD_API_URL = 'https://epic.dayunyuanjian.cn'; const PROD_API_URL = 'https://epic.dayunyuanjian.cn';
const NEWAPIURL = process.env.NODE_ENV === 'development' ? DEV_API_URL : PROD_API_URL; const NEWAPIURL = process.env.NODE_ENV === 'development' ? DEV_API_URL : PROD_API_URL;
// const DEV_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx'; // const DEV_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx';
const DEV_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx'; // const DEV_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx';
// const DEV_API_URL_DES = 'http://192.168.124.8:8083/xcx'; const DEV_API_URL_DES = 'http://192.168.124.8:8083/xcx';
// const PROD_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx'; // const PROD_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx';
const PROD_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx'; const PROD_API_URL_DES = 'https://des.dayunyuanjian.cn/xcx';
const NEWAPIURL_DES = process.env.NODE_ENV === 'development' ? DEV_API_URL_DES : PROD_API_URL_DES; const NEWAPIURL_DES = process.env.NODE_ENV === 'development' ? DEV_API_URL_DES : PROD_API_URL_DES;

Loading…
Cancel
Save