Browse Source

积分

dev_des
1054425342@qq.com 1 month ago
parent
commit
5a8a05811b
  1. 6905
      audioBook/components/msg copy 2.json
  2. 8508
      audioBook/components/msg.json
  3. 514
      audioBook/pages/index.vue
  4. 6
      pages.json
  5. 19
      pages/index/components/FollowTab.vue
  6. 25
      pages/index/timeShopBank.vue
  7. 6
      pages/login/login.vue
  8. 4
      static/js/request.js
  9. 6
      subPackages/other/ipPoster.vue
  10. 452
      subPackages/points/index.vue

6905
audioBook/components/msg copy 2.json

File diff suppressed because one or more lines are too long

8508
audioBook/components/msg.json

File diff suppressed because one or more lines are too long

514
audioBook/pages/index.vue

@ -3,19 +3,36 @@
<!-- 歌词显示区域 --> <!-- 歌词显示区域 -->
<view class="lyrics-container"> <view class="lyrics-container">
<view class="lyrics-content"> <view class="lyrics-content">
<!-- 当前句子显示 --> <!-- 三句歌词显示 -->
<view class="current-sentence"> <view class="three-sentences">
<!-- 上一句 -->
<view class="sentence-item prev-sentence">
<text class="lyric-line prev-line">
{{ prevSentence ? prevSentence.FinalSentence : "" }}
</text>
</view>
<!-- 当前句子 -->
<view class="sentence-item current-sentence">
<text class="lyric-line active"> <text class="lyric-line active">
{{ currentSentence ? currentSentence.FinalSentence : "" }} {{ currentSentence ? currentSentence.FinalSentence : "" }}
</text> </text>
</view> </view>
<!-- 下一句 -->
<view class="sentence-item next-sentence">
<text class="lyric-line next-line">
{{ nextSentence ? nextSentence.FinalSentence : "" }}
</text>
</view>
</view>
<!-- 句子指示器 --> <!-- 句子指示器 -->
<view class="sentence-indicator"> <!-- <view class="sentence-indicator">
<text class="sentence-text"> <text class="sentence-text">
{{ currentSentenceIndex + 1 }}/{{ totalSentences }} {{ currentSentenceIndex + 1 }}/{{ totalSentences }}
</text> </text>
</view> </view> -->
</view> </view>
</view> </view>
@ -50,29 +67,75 @@
</view> </view>
<text class="time-text">{{ formatTime(duration) }}</text> <text class="time-text">{{ formatTime(duration) }}</text>
</view> </view>
<!-- 句子控制按钮 -->
<view class="sentence-controls"> <!-- 点赞和评论区域 -->
<view class="interaction-section">
<view class="like-section">
<view class="like-btn" @click="toggleLike">
<text class="like-icon">{{ isLiked ? "❤️" : "🤍" }}</text>
<text class="like-count">{{ likeCount }}</text>
</view>
<view class="comment-btn" @click="toggleComments">
<text class="comment-icon">💬</text>
<text class="comment-count">{{ comments.length }}</text>
</view>
</view>
</view>
<!-- 评论列表 -->
<view class="comments-container" v-if="showComments">
<view class="comments-header">
<text class="comments-title">评论 ({{ comments.length }})</text>
<view class="close-btn" @click="closeComments">
<text class="close-icon"></text>
</view>
</view>
<!-- 评论输入框 -->
<view class="comment-input-section">
<input
class="comment-input"
v-model="newComment"
placeholder="写下你的想法..."
@confirm="submitComment"
/>
<view <view
class="control-btn" class="submit-btn"
@click="prevSentence" @click="submitComment"
:disabled="currentSentenceIndex === 0" :class="{ disabled: !newComment.trim() }"
> >
<text class="control-icon-text"></text> <text class="submit-text">发送</text>
</view> </view>
<view class="sentence-info">
<text class="sentence-info-text"
>{{ currentSentenceIndex + 1 }}/{{ totalSentences }}</text
>
</view> </view>
<!-- 评论列表 -->
<scroll-view class="comments-list" scroll-y>
<view <view
class="control-btn" class="comment-item"
@click="nextSentence" v-for="(comment, index) in comments"
:disabled="currentSentenceIndex >= totalSentences - 1" :key="index"
> >
<text class="control-icon-text"></text> <view class="comment-avatar">
<text class="avatar-text">{{ comment.userName.charAt(0) }}</text>
</view>
<view class="comment-content">
<view class="comment-header">
<text class="comment-user">{{ comment.userName }}</text>
<text class="comment-time">{{
formatCommentTime(comment.createTime)
}}</text>
</view>
<text class="comment-text">{{ comment.content }}</text>
</view> </view>
</view> </view>
<!-- 空状态 -->
<view class="empty-comments" v-if="comments.length === 0">
<text class="empty-text">暂无评论快来抢沙发吧~</text>
</view>
</scroll-view>
</view>
<!-- 底部控制按钮 --> <!-- 底部控制按钮 -->
<view class="bottom-controls"> <view class="bottom-controls">
<view class="control-btn"> <view class="control-btn">
@ -135,6 +198,13 @@ export default {
scrollViewHeight: 0, scrollViewHeight: 0,
// //
currentSentenceIndex: 0, currentSentenceIndex: 0,
//
isLiked: false,
likeCount: 0,
comments: [],
showComments: false,
newComment: "",
commentLoading: false,
}; };
}, },
mounted() { mounted() {
@ -181,6 +251,22 @@ export default {
currentSentence() { currentSentence() {
return this.currentChapter.sentences[this.currentSentenceIndex] || null; return this.currentChapter.sentences[this.currentSentenceIndex] || null;
}, },
prevSentence() {
if (this.currentSentenceIndex > 0) {
return (
this.currentChapter.sentences[this.currentSentenceIndex - 1] || null
);
}
return null;
},
nextSentence() {
if (this.currentSentenceIndex < this.totalSentences - 1) {
return (
this.currentChapter.sentences[this.currentSentenceIndex + 1] || null
);
}
return null;
},
}, },
methods: { methods: {
togglePlay() { togglePlay() {
@ -357,31 +443,134 @@ export default {
// //
this.scrollViewHeight = windowHeight - controlsHeight - 60; // 60px this.scrollViewHeight = windowHeight - controlsHeight - 60; // 60px
}, },
// //
prevSentence() { toggleLike() {
if (this.currentSentenceIndex > 0) { this.isLiked = !this.isLiked;
this.currentSentenceIndex--; this.likeCount += this.isLiked ? 1 : -1;
this.activeSentenceIndex = this.currentSentenceIndex;
// // API
const sentence = this.saveLikeStatus();
this.currentChapter.sentences[this.currentSentenceIndex]; },
if (sentence && this.$refs.audioPlayer) { toggleComments() {
this.$refs.audioPlayer.seek(sentence.startTimeInSeconds); this.showComments = !this.showComments;
if (this.showComments && this.comments.length === 0) {
this.loadComments();
} }
},
closeComments() {
this.showComments = false;
},
async loadComments() {
try {
//
// API
this.comments = [
{
id: 1,
userName: "用户1",
content: "这首歌真的很好听!",
createTime: new Date().getTime() - 1000 * 60 * 30, // 30
},
{
id: 2,
userName: "音乐爱好者",
content: "歌词写得很有意境",
createTime: new Date().getTime() - 1000 * 60 * 60 * 2, // 2
},
{
id: 3,
userName: "文艺青年",
content: "每次听都有不同的感受",
createTime: new Date().getTime() - 1000 * 60 * 60 * 24, // 1
},
{
id: 1,
userName: "用户1",
content: "这首歌真的很好听!",
createTime: new Date().getTime() - 1000 * 60 * 30, // 30
},
{
id: 2,
userName: "音乐爱好者",
content: "歌词写得很有意境",
createTime: new Date().getTime() - 1000 * 60 * 60 * 2, // 2
},
{
id: 3,
userName: "文艺青年",
content: "每次听都有不同的感受",
createTime: new Date().getTime() - 1000 * 60 * 60 * 24, // 1
},
];
} catch (error) {
console.error("加载评论失败:", error);
uni.showToast({
title: "加载评论失败",
icon: "none",
});
} }
}, },
nextSentence() { async submitComment() {
if (this.currentSentenceIndex < this.totalSentences - 1) { if (!this.newComment.trim()) {
this.currentSentenceIndex++; uni.showToast({
this.activeSentenceIndex = this.currentSentenceIndex; title: "请输入评论内容",
// icon: "none",
const sentence = });
this.currentChapter.sentences[this.currentSentenceIndex]; return;
if (sentence && this.$refs.audioPlayer) {
this.$refs.audioPlayer.seek(sentence.startTimeInSeconds);
} }
this.commentLoading = true;
try {
//
const newComment = {
id: Date.now(),
userName: "我",
content: this.newComment.trim(),
createTime: new Date().getTime(),
};
this.comments.unshift(newComment);
this.newComment = "";
uni.showToast({
title: "评论成功",
icon: "success",
});
// API
this.saveComment(newComment);
} catch (error) {
console.error("提交评论失败:", error);
uni.showToast({
title: "评论失败",
icon: "none",
});
} finally {
this.commentLoading = false;
}
},
formatCommentTime(timestamp) {
const now = new Date().getTime();
const diff = now - timestamp;
if (diff < 1000 * 60) {
return "刚刚";
} else if (diff < 1000 * 60 * 60) {
return Math.floor(diff / (1000 * 60)) + "分钟前";
} else if (diff < 1000 * 60 * 60 * 24) {
return Math.floor(diff / (1000 * 60 * 60)) + "小时前";
} else {
return Math.floor(diff / (1000 * 60 * 60 * 24)) + "天前";
} }
}, },
async saveLikeStatus() {
// API
console.log("保存点赞状态:", this.isLiked);
},
async saveComment(comment) {
// API
console.log("保存评论:", comment);
},
}, },
}; };
</script> </script>
@ -451,25 +640,49 @@ export default {
position: relative; position: relative;
} }
.current-sentence { .three-sentences {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
gap: 20rpx;
position: relative;
overflow: hidden;
}
.sentence-item {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
transition: all 0.3s ease;
}
.current-sentence {
transform: scale(1.05);
z-index: 2;
}
.prev-sentence {
opacity: 0.5;
transform: scale(0.85) translateY(-10rpx);
}
.next-sentence {
opacity: 0.5;
transform: scale(0.85) translateY(10rpx);
} }
.lyric-line { .lyric-line {
display: block; display: block;
text-align: center; text-align: center;
font-size: 36rpx; line-height: 1.6;
color: #333;
line-height: 1.8;
margin: 0; margin: 0;
transition: all 0.3s ease; transition: all 0.3s ease;
padding: 20rpx; padding: 16rpx 20rpx;
font-weight: 600; word-break: break-all;
} }
.lyric-line.active { .lyric-line.active {
@ -478,6 +691,18 @@ export default {
font-size: 36rpx; font-size: 36rpx;
} }
.lyric-line.prev-line {
color: #999;
font-size: 28rpx;
font-weight: 400;
}
.lyric-line.next-line {
color: #999;
font-size: 28rpx;
font-weight: 400;
}
.sentence-indicator { .sentence-indicator {
position: absolute; position: absolute;
bottom: 20rpx; bottom: 20rpx;
@ -590,31 +815,210 @@ export default {
color: #999; color: #999;
} }
/* 句子控制按钮 */ /* 点赞和评论区域 */
.sentence-controls { .interaction-section {
padding: 20rpx 0;
border-top: 1rpx solid #f0f0f0;
}
.like-section {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
gap: 40rpx; gap: 60rpx;
margin-bottom: 30rpx;
padding: 20rpx 0;
border-top: 1rpx solid #f0f0f0;
} }
.sentence-info { .like-btn,
background: #f8f8f8; .comment-btn {
padding: 12rpx 24rpx; display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
padding: 16rpx 24rpx;
border-radius: 20rpx; border-radius: 20rpx;
min-width: 120rpx; background: #f8f8f8;
text-align: center; transition: all 0.3s ease;
} }
.sentence-info-text { .like-btn:active,
.comment-btn:active {
transform: scale(0.95);
background: #e8e8e8;
}
.like-icon,
.comment-icon {
font-size: 32rpx;
line-height: 1;
}
.like-count,
.comment-count {
font-size: 24rpx;
color: #666;
font-weight: 500;
}
/* 评论容器 */
.comments-container {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 60vh;
background: white;
border-radius: 32rpx 32rpx 0 0;
box-shadow: 0 -8rpx 32rpx rgba(0, 0, 0, 0.1);
z-index: 1000;
display: flex;
flex-direction: column;
}
.comments-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx 40rpx 20rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.comments-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.close-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: #f0f0f0;
}
.close-icon {
font-size: 28rpx; font-size: 28rpx;
color: #666; color: #666;
}
/* 评论输入区域 */
.comment-input-section {
display: flex;
align-items: center;
padding: 20rpx 40rpx;
gap: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.comment-input {
flex: 1;
height: 80rpx;
background: #f8f8f8;
border-radius: 40rpx;
padding: 0 24rpx;
font-size: 28rpx;
border: none;
outline: none;
}
.submit-btn {
padding: 16rpx 32rpx;
background: #007aff;
border-radius: 40rpx;
transition: all 0.3s ease;
}
.submit-btn.disabled {
background: #ccc;
}
.submit-text {
color: white;
font-size: 28rpx;
font-weight: 500; font-weight: 500;
} }
/* 评论列表 */
.comments-list {
flex: 1;
padding: 20rpx 40rpx;
width: 680rpx;
height: 400rpx;
}
.comment-item {
display: flex;
gap: 20rpx;
padding: 24rpx 0;
border-bottom: 1rpx solid #f8f8f8;
}
.comment-item:last-child {
border-bottom: none;
}
.comment-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: linear-gradient(135deg, #667eea, #764ba2);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.avatar-text {
color: white;
font-size: 32rpx;
font-weight: 600;
}
.comment-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 12rpx;
}
.comment-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.comment-user {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
.comment-time {
font-size: 24rpx;
color: #999;
}
.comment-text {
font-size: 28rpx;
color: #333;
line-height: 1.6;
}
/* 空状态 */
.empty-comments {
display: flex;
justify-content: center;
align-items: center;
height: 200rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
/* 底部控制按钮 */ /* 底部控制按钮 */
.bottom-controls { .bottom-controls {
display: flex; display: flex;

6
pages.json

@ -327,6 +327,12 @@
"navigationBarTextStyle": "white", "navigationBarTextStyle": "white",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
},
{
"path": "points/index",
"style": {
"navigationBarTitleText": "积分明细"
}
} }
] ]
}, },

19
pages/index/components/FollowTab.vue

@ -15,15 +15,15 @@
<!-- 我的关注标题和排序 --> <!-- 我的关注标题和排序 -->
<view class="follows-header"> <view class="follows-header">
<text class="follows-title">我的关注 ({{ followsList.length }})</text> <text class="follows-title">我的关注 ({{ followsList.length||0 }})</text>
<view class="sort-option" @click="toggleSort"> <!-- <view class="sort-option" @click="toggleSort">
<text class="sort-text">综合排序</text> <text class="sort-text">综合排序</text>
<image class="sort-arrow" :src="showImg('/uploads/20250826/8e40deaa0bc67da3a9b104ff0e6b3e7c.png')"></image> <image class="sort-arrow" :src="showImg('/uploads/20250826/8e40deaa0bc67da3a9b104ff0e6b3e7c.png')"></image>
</view> </view> -->
</view> </view>
<!-- 分类导航 --> <!-- 分类导航 -->
<view class="category-tabs"> <!-- <view class="category-tabs">
<view <view
class="tab-item" class="tab-item"
:class="{ active: activeCategory === 'all' }" :class="{ active: activeCategory === 'all' }"
@ -38,7 +38,7 @@
> >
商家 商家
</view> </view>
</view> </view> -->
<!-- 关注用户列表 --> <!-- 关注用户列表 -->
<view class="follows-list"> <view class="follows-list">
@ -58,18 +58,18 @@
<view class="follow-status-btn"> <view class="follow-status-btn">
已关注 已关注
</view> </view>
<view class="more-options" @click="showOptions(item)"> <!-- <view class="more-options" @click="showOptions(item)">
<text class="more-dots"></text> <text class="more-dots"></text>
</view> </view> -->
</view> </view>
</view> </view>
</view> </view>
<!-- 推荐用户分隔线 --> <!-- 推荐用户分隔线 -->
<view class="divider-line"></view> <view class="divider-line" v-if="false"></view>
<!-- 推荐用户区域 --> <!-- 推荐用户区域 -->
<view class="recommend-section"> <view class="recommend-section" v-if="false">
<view class="recommend-header"> <view class="recommend-header">
<view class="recommend-title" style="display: flex;align-items: center;"> <view class="recommend-title" style="display: flex;align-items: center;">
你可能感兴趣的人 你可能感兴趣的人
@ -284,7 +284,6 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.follow-tab-container { .follow-tab-container {
background: #fff; background: #fff;
min-height: 100vh;
} }
/* 搜索栏 */ /* 搜索栏 */

25
pages/index/timeShopBank.vue

@ -66,14 +66,29 @@
<text class="coming-soon">笔记功能开发中...</text> <text class="coming-soon">笔记功能开发中...</text>
</view> --> </view> -->
<!-- 关注tab内容 --> <!-- 关注tab内容 -->
<view v-if="currentTab == 1" class="follow-content recommend-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="recommend-content"> <view v-if="currentTab == 2" class="notes-content">
<text class="coming-soon">推荐功能开发中...</text> <view class="fab-container">
<image
:src="
showImg('/uploads/20250825/7ea7864b8abb89c3dd7834f025e49b3f.png')
"
style="width: 91rpx; height: 91rpx"
></image>
</view>
<WaterfallLayout
:items="waterfallItems"
:column-count="2"
:column-gap="16"
:item-gap="16"
@item-click="handleItemClick"
style="margin-top: 20rpx"
/>
</view> </view>
</view> </view>

6
pages/login/login.vue

@ -88,8 +88,14 @@ export default {
token: uni.getStorageSync('token1') token: uni.getStorageSync('token1')
}, '/api/mini_program/bindPhoneNumber') }, '/api/mini_program/bindPhoneNumber')
.then(res => { .then(res => {
this.Post({
}, '/framework/points/add','DES')
.then(res => {
})
this.$store.commit('changeUserInfo', res.data.userinfo); this.$store.commit('changeUserInfo', res.data.userinfo);
this.navigateBasedOnPath(); this.navigateBasedOnPath();
}) })
.catch(error => { .catch(error => {
console.error('绑定手机号失败:', error); console.error('绑定手机号失败:', error);

4
static/js/request.js

@ -8,9 +8,9 @@ const DEV_API_URL = 'http://1.13.193.49';
// const PROD_API_URL = 'https://epic.js-dyyj.com'; // const PROD_API_URL = 'https://epic.js-dyyj.com';
const PROD_API_URL = 'http://1.13.193.49'; const PROD_API_URL = 'http://1.13.193.49';
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 = 'http://192.168.124.177:8083/xcx'; const DEV_API_URL_DES = 'http://192.168.124.177:8083/xcx';
// const DEV_API_URL_DES = 'https://des.js-dyyj.com/xcx'; // const DEV_API_URL_DES = 'https://des.js-dyyj.com/xcx';
const DEV_API_URL_DES = 'http://1.13.193.49:8083/xcx'; // const DEV_API_URL_DES = 'http://1.13.193.49:8083/xcx';
// const PROD_API_URL_DES = 'https://des.js-dyyj.com/xcx'; // const PROD_API_URL_DES = 'https://des.js-dyyj.com/xcx';
const PROD_API_URL_DES = 'http://1.13.193.49:8083/xcx'; const PROD_API_URL_DES = 'http://1.13.193.49:8083/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;

6
subPackages/other/ipPoster.vue

@ -3,13 +3,13 @@
<view class="" style="font-size: 0;"> <view class="" style="font-size: 0;">
<BackButton /> <BackButton />
<view class="" v-if="index==0"> <view class="" v-if="index==0">
<image class="bannerImg" mode="aspectFill" src="https://des.js-dyyj.com/data/2025/09/11/7c5aaadc-0d03-479d-a6b8-a372b0bd7449.jpg"> </image> <image class="bannerImg" mode="aspectFill" src="https://des.js-dyyj.com/data/2025/09/16/1df5889f-9315-4533-839f-232ea65e3364.png"> </image>
</view> </view>
<view class="" v-if="index==1"> <view class="" v-if="index==1">
<image class="bannerImg" mode="aspectFill" src="https://des.js-dyyj.com/data/2025/09/11/ea73035d-f282-4a5b-82df-3ff4be8ba9ae.jpg"> </image> <image class="bannerImg" mode="aspectFill" src="https://des.js-dyyj.com/data/2025/09/16/d31fb948-a705-4e23-9544-38f1e705a146.jpg"> </image>
</view> </view>
<view class="" v-if="index==2"> <view class="" v-if="index==2">
<image class="bannerImg" mode="aspectFill" src="https://des.js-dyyj.com/data/2025/09/11/cade15a3-b473-49fd-80b9-0caee9f7d404.jpg"> </image> <image class="bannerImg" mode="aspectFill" src="https://des.js-dyyj.com/data/2025/09/16/94e342f7-7215-4f93-b4d0-64aedd2cdbe3.jpg"> </image>
</view> </view>
<view class="" v-if="index==3"> <view class="" v-if="index==3">
<image class="bannerImg" mode="aspectFill" src="https://des.js-dyyj.com/data/2025/09/11/4f5581b4-e354-4a2b-8f41-5d37fcd3904b.png"> </image> <image class="bannerImg" mode="aspectFill" src="https://des.js-dyyj.com/data/2025/09/11/4f5581b4-e354-4a2b-8f41-5d37fcd3904b.png"> </image>

452
subPackages/points/index.vue

@ -0,0 +1,452 @@
<template>
<view class="points-detail-page">
<!-- 积分总览 -->
<view class="points-overview">
<view class="total-points">
<text class="points-number">{{ totalPoints }}</text>
<text class="points-label">当前积分</text>
</view>
</view>
<!-- 筛选选项 -->
<view class="filter-tabs">
<view class="tab-item" :class="[{ active: currentTab === 'all' }]" @click="switchTab('all')">
全部
</view>
<view class="tab-item" :class="[{ active: currentTab === 'in' }]" @click="switchTab('in')">
收入
</view>
<view class="tab-item" :class="[{ active: currentTab === 'out' }]" @click="switchTab('out')">
支出
</view>
</view>
<!-- 积分记录列表 -->
<scroll-view class="points-list" scroll-y="true" @scrolltolower="loadMore">
<template v-if="pointsList.length">
<view class="record-item" v-for="(item, index) in pointsList" :key="index">
<view class="record-left">
<view class="record-icon" :class="item.fromType === 'in' ? 'income' : 'expense'">
<uni-icons type="vip" size="30" style="color: white;"></uni-icons>
</view>
<view class="record-info">
<view class="record-title">{{ item.dictName }}</view>
<view class="record-desc">{{ item.remark }}</view>
<view class="record-time">{{ item.createTime }}</view>
</view>
</view>
<view class="record-right">
<view class="record-points" :class="item.fromType === 'in' ? 'income' : 'expense'">
{{ item.points }}
</view>
</view>
</view>
<!-- 加载更多提示 -->
<view class="load-more" v-if="hasMore">
<text class="load-text">{{
loading ? "加载中..." : "上拉加载更多"
}}</text>
</view>
<!-- 没有更多数据 -->
<view class="no-more" v-if="!hasMore && pointsList.length > 0">
<text class="no-more-text">没有更多数据了</text>
</view>
</template>
<!-- 空状态 -->
<view class="empty-state" v-if="pointsList.length === 0 && !loading">
<image class="empty-icon"
src="https://epic.js-dyyj.com/uploads/20250808/c16267f9cc2b7a68bf23713b5847987e.png"
mode="aspectFit"></image>
<text class="empty-text">暂无积分记录</text>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
totalPoints: 0,
currentTab: "all",
pointsList: [],
page: 1,
pageSize: 20,
hasMore: true,
loading: false,
refreshing: false,
};
},
onLoad() {
this.loadPointsData();
this.getTotalPoints();
},
methods: {
//
goBack() {
uni.navigateBack();
},
//
switchTab(tab) {
if (this.currentTab === tab) return;
this.currentTab = tab;
this.resetData();
this.loadPointsData();
},
//
resetData() {
this.pointsList = [];
this.page = 1;
this.hasMore = true;
},
//
async getTotalPoints() {
try {
this.Post({}, '/framework/points/getLastBalance', 'DES').then(res =>{
if (res.code === 200) {
this.totalPoints = res.data || 0;
}
})
} catch (error) {
console.error("获取总积分失败:", error);
}
},
//
async loadPointsData() {
if (this.loading) return;
this.loading = true;
try {
const params = {
page: this.page,
pageSize: this.pageSize,
};
if (this.currentTab !== "all") {
params.fromType = this.currentTab;
}
this.Post(params, '/framework/points/list', 'DES')
.then(res => {
console.log(res)
if (res.code === 200) {
const newData = res.rows || [];
if (this.page === 1) {
this.pointsList = newData;
} else {
this.pointsList = [...this.pointsList, ...newData];
}
this.hasMore = newData.length === this.pageSize;
if (this.hasMore) {
this.page++;
}
} else {
uni.showToast({
title: res.msg || "加载失败",
icon: "none",
});
}
})
} catch (error) {
console.error("加载积分记录失败:", error);
uni.showToast({
title: "网络错误,请重试",
icon: "none",
});
} finally {
this.loading = false;
this.refreshing = false;
}
},
//
loadMore() {
if (this.hasMore && !this.loading) {
this.loadPointsData();
}
},
//
onRefresh() {
this.refreshing = true;
this.resetData();
this.loadPointsData();
this.getTotalPoints();
},
//
formatTime(timestamp) {
const date = new Date(timestamp);
const now = new Date();
const diff = now.getTime() - date.getTime();
//
if (diff < 24 * 60 * 60 * 1000 && now.getDate() === date.getDate()) {
return `今天 ${date.getHours().toString().padStart(2, "0")}:${date
.getMinutes()
.toString()
.padStart(2, "0")}`;
}
//
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
if (yesterday.getDate() === date.getDate()) {
return `昨天 ${date.getHours().toString().padStart(2, "0")}:${date
.getMinutes()
.toString()
.padStart(2, "0")}`;
}
//
return `${date.getMonth() + 1}-${date.getDate()} ${date
.getHours()
.toString()
.padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
},
},
};
</script>
<style scoped>
.points-detail-page {
min-height: 100vh;
background-color: #f5f5f5;
}
/* 导航栏 */
.nav-bar {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 32rpx;
background-color: #fff;
border-bottom: 1rpx solid #eee;
}
.nav-back {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.nav-back .iconfont {
font-size: 36rpx;
color: #333;
}
.nav-title {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
.nav-placeholder {
width: 60rpx;
}
/* 积分总览 */
.points-overview {
background: linear-gradient(135deg, #77f3f9 0%, #764ba2 100%);
padding: 60rpx 32rpx;
text-align: center;
}
.total-points {
display: flex;
flex-direction: column;
align-items: center;
}
.points-number {
font-size: 72rpx;
font-weight: bold;
color: #fff;
margin-bottom: 12rpx;
}
.points-label {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
}
/* 筛选标签 */
.filter-tabs {
display: flex;
background-color: #fff;
padding: 0 32rpx;
}
.tab-item {
flex: 1;
text-align: center;
padding: 32rpx 0;
font-size: 30rpx;
color: #666;
position: relative;
}
.tab-item.active {
color: #77f3f9;
font-weight: 600;
}
.tab-item.active::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background-color: #77f3f9;
border-radius: 2rpx;
}
/* 积分记录列表 */
.points-list {
height: calc(100vh - 368rpx);
padding: 0 30rpx;
width: 690rpx;
}
.record-item {
display: flex;
align-items: center;
justify-content: space-between;
background-color: #fff;
padding: 32rpx 24rpx;
margin-top: 20rpx;
border-radius: 16rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
.record-left {
display: flex;
align-items: center;
flex: 1;
}
.record-icon {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
}
.record-icon.income {
background-color: #e8f5e8;
}
.record-icon.expense {
background-color: #ffeaea;
}
.record-icon .iconfont {
font-size: 36rpx;
}
.record-icon.income .iconfont {
color: #52c41a;
}
.record-icon.expense .iconfont {
color: #ff4d4f;
}
.record-info {
flex: 1;
}
.record-title {
font-size: 32rpx;
color: #333;
font-weight: 500;
margin-bottom: 8rpx;
}
.record-desc {
font-size: 26rpx;
color: #999;
margin-bottom: 8rpx;
}
.record-time {
font-size: 24rpx;
color: #ccc;
}
.record-right {
text-align: right;
}
.record-points {
font-size: 32rpx;
font-weight: 600;
}
.record-points.income {
color: #52c41a;
}
.record-points.expense {
color: #ff4d4f;
}
/* 加载状态 */
.load-more,
.no-more {
text-align: center;
padding: 40rpx 0;
}
.load-text,
.no-more-text {
font-size: 28rpx;
color: #999;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 120rpx 0;
}
.empty-icon {
width: 200rpx;
height: 200rpx;
margin-bottom: 32rpx;
opacity: 0.6;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
</style>
Loading…
Cancel
Save