Просмотр исходного кода

优化书籍详情跳转逻辑,新增最近阅读功能,改进首页和书架页面的用户交互,调整样式以提升用户体验,更新API请求路径,修复部分样式问题。

yangwenlan 1 год назад
Родитель
Сommit
de2d9b1ee0

+ 1 - 1
api/api.js

@@ -83,7 +83,7 @@ export const removeBookshelf = (data) => {
 
 // /user/chapter/unlock-status 获取章节解锁状态
 export const getChapterUnlockStatus = (data) => {
-    return requestAll('/user/chapter/unlock-status', data, 'GET', addTokenToHeader())
+    return requestAll('/user/chapter/unlock-status-val', data, 'GET', addTokenToHeader())
 }
 
 // /user/browsing-history 新增用户阅读历史

+ 4 - 7
app.js

@@ -92,18 +92,15 @@ async function onNovelPluginLoad(data) {
   // 设置目录状态(根据unlockStatus数据设置章节状态)
   if (unlockStatus && Array.isArray(unlockStatus.status)) {
     // 将unlockStatus.status数组转换为目录状态格式
-    const contents = unlockStatus.status.map((isUnlocked, index) => {
+    const contents = unlockStatus.status.map((lockState, index) => {
       return {
         index: index, // 章节索引
-        status: isUnlocked ? 1 : 2, // true为已解锁(1),false为未解锁(2)
+        status: lockState,
       };
     });
     
-    // 设置第一章为免费(0)状态,如果有其他免费章节也可以在这里设置
-    if (contents.length > 0) {
-      contents[0].status = 0;
-    }
-    
+
+    console.log("contents",contents);
     // 设置目录状态
     novelManager.setContents({
       contents: contents,

+ 6 - 2
app.json

@@ -7,7 +7,8 @@
     "pages/category/category",
     "pages/mine/mine",
     "pages/book/list",
-    "pages/search/search"
+    "pages/search/search",
+    "components/charge-dialog/charge-dialog"
   ],
   "window": {
     "navigationStyle": "custom",
@@ -17,13 +18,16 @@
     "navigationBarTitleText": "WeChat",
     "navigationBarTextStyle": "black"
   },
+  "usingComponents": {
+    "charge-dialog": "/components/charge-dialog/charge-dialog"
+  },
   "plugins": {
     "novel-plugin": {
       "version": "latest",
       "provider": "wx293c4b6097a8a4d0",
       "genericsImplementation": {
         "novel": {
-          "charge-dialog": "components/charge-dialog"
+          "charge-dialog": "/components/charge-dialog/charge-dialog"
         }
       }
     }

+ 47 - 0
components/charge-dialog/charge-dialog.js

@@ -0,0 +1,47 @@
+const novelPlugin = requirePlugin('novel-plugin')
+import { getNovelDetail } from '../../api/api'
+Component({
+  properties: {
+    novelManagerId: {
+      type: Number,
+      value: -1,
+    },
+    bookId: {
+      type: String,
+      value: '',
+    },
+    chapterIndex: {
+      type: Number,
+      value: -1,
+    },
+    chapterId: {
+      type: String,
+      value: '',
+    },
+    originalId: {
+      type: String,
+      value: '',
+    },
+  },
+
+  onLoad(options) {
+    console.log('options',options)
+    getNovelDetail(options.id).then(res => {
+      console.log('res',res)
+    })
+  },
+
+  methods: {
+    unlock() {
+      // 取出对应的阅读器实例
+      const novelManager = novelPlugin.getNovelManager(this.properties.novelManagerId)
+
+      // do something
+      console.log("======解锁=====")
+      console.log(this.properties)
+
+      // 告诉阅读器这一章已解锁
+      novelManager.paymentCompleted()
+    },
+  },
+})

+ 3 - 0
components/charge-dialog/charge-dialog.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 1 - 0
components/charge-dialog/charge-dialog.wxml

@@ -0,0 +1 @@
+<button bind:tap="unlock">解锁第 {{ chapterIndex + 1 }} 章</button>

+ 1 - 0
components/charge-dialog/charge-dialog.wxss

@@ -0,0 +1 @@
+/* components/charge-dialog/charge-dialog.wxss */

+ 1 - 1
components/gender-tabs/index.wxss

@@ -5,7 +5,7 @@
 
 .tab {
   font-size: 30rpx;
-  margin-right: 40rpx;
+  margin-right: 60rpx;
   padding: 10rpx 0;
   position: relative;
   color: #999;

+ 7 - 2
pages/bookshelf/bookshelf.js

@@ -1,4 +1,5 @@
 import { getBookshelfList, getBrowsingHistory } from '../../api/api'
+import { goToBookDetail } from '../../utils/util'
 
 Page({
   data: {
@@ -87,8 +88,12 @@ Page({
   // 跳转到书籍详情
   goToBookDetail(e) {
     const book = e.currentTarget.dataset.book;
-    wx.navigateTo({
-      url: `/pages/plugins/novel-plugin/index?innerBookId=${book.novelId}`
+    
+    // 使用公共的goToBookDetail函数
+    goToBookDetail({
+      bookId: book.novelId,
+      wxBookId: book.appId, // 使用appId作为wxBookId
+      chapterId: book.novelChapterId
     });
   }
 })

+ 2 - 1
pages/bookshelf/bookshelf.wxss

@@ -34,6 +34,7 @@
 }
 
 .book-list {
+  width: 720rpx;
   height: calc(100vh - 100rpx);
   padding: 20rpx;
 }
@@ -41,7 +42,7 @@
 .book-grid {
   display: grid;
   grid-template-columns: repeat(3, 1fr);
-  gap: 30rpx;
+  gap: 20rpx;
   padding: 10rpx;
 }
 

+ 1 - 1
pages/category/category.wxml

@@ -4,7 +4,7 @@
   <view class="header">
     <gender-tabs gender="{{gender}}" bind:switch="switchGender"/>
     <view class="search-box" bindtap="goToSearch">
-      <icon type="search" size="14" color="#999"/>
+      <icon type="search" size="22" color="#999"/>
       <input 
         type="text" 
         placeholder="请输入书名/口令搜索" 

+ 2 - 3
pages/category/category.wxss

@@ -16,7 +16,6 @@ page {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  width: 90vw;
 }
 
 /* 搜索框 */
@@ -26,8 +25,8 @@ page {
   height: 70rpx;
   background-color: #fff;
   border-radius: 35rpx;
-  padding: 0 30rpx;
-  width: 400rpx;
+  padding: 0 15rpx;
+  width: 420rpx;
 }
 
 .search-box icon {

+ 120 - 1
pages/index/index.js

@@ -1,7 +1,7 @@
 // index.js
 const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
 const testCover = '/assets/images/bg-book.png'
-import { getBannerList, getCardNovels } from '../../api/api'
+import { getBannerList, getCardNovels, getBrowsingHistory } from '../../api/api'
 import { goToBookDetail } from '../../utils/util'
 
 const app = getApp()
@@ -33,6 +33,12 @@ Page({
     showStrongRecommend: false, // 控制强力推荐模块显示/隐藏
     strongBooks: [],
     
+    // 最近阅读书籍
+    recentBook: null, // 最近阅读的书籍
+    showRecentBook: false, // 是否显示最近阅读
+    isRecentBookHidden: false, // 最近阅读是否隐藏
+    recentBookAnimation: {}, // 最近阅读动画数据
+    
     motto: 'Hello World',
     userInfo: {
       avatarUrl: defaultAvatarUrl,
@@ -45,12 +51,19 @@ Page({
   
   onLoad() {
     this.autoLogin();
+    // 创建动画实例
+    this.recentBookAnimator = wx.createAnimation({
+      duration: 300,
+      timingFunction: 'ease',
+    });
   },
 
   onShow() {
     // 每次页面显示时检查是否需要更新数据
     if (this.data.isLoggedIn) {
       this.checkAndUpdateGender();
+      // 每次页面显示时获取最近阅读
+      this.getRecentReadBook();
     }
   },
 
@@ -61,6 +74,64 @@ Page({
     }
   },
 
+  // 页面滚动触发
+  onPageScroll(e) {
+    // 清除之前的定时器
+    if (this.scrollTimer) {
+      clearTimeout(this.scrollTimer);
+      this.scrollTimer = null;
+    }
+    
+    // 滚动时隐藏最近阅读
+    if (e.scrollTop > 300 && !this.data.isRecentBookHidden && this.data.showRecentBook) {
+      this.hideRecentBook();
+    }
+    
+    // 设置滑动停止后的定时器
+    this.lastScrollTop = e.scrollTop;
+    this.scrollTimer = setTimeout(() => {
+      // 2秒后检查是否已经停止滚动
+      if (this.lastScrollTop === e.scrollTop && this.data.isRecentBookHidden && this.data.showRecentBook) {
+        this.showRecentBook();
+      }
+    }, 1500); // 2秒后执行
+  },
+
+  // 隐藏最近阅读
+  hideRecentBook() {
+    // 计算移动距离,只漏出10px
+    const windowWidth = wx.getSystemInfoSync().windowWidth;
+    const rpxToPx = windowWidth / 750; // rpx到px的转换比例
+    const btnWidth = 90 * rpxToPx; // 悬浮按钮宽度,90rpx转换为px
+    const moveX = -(btnWidth + 40); // 只漏出10px
+    
+    this.recentBookAnimator.translateX(moveX).step();
+    this.setData({
+      recentBookAnimation: this.recentBookAnimator.export(),
+      isRecentBookHidden: true
+    });
+  },
+
+  // 显示最近阅读
+  showRecentBook() {
+    this.recentBookAnimator.translateX(0).step();
+    this.setData({
+      recentBookAnimation: this.recentBookAnimator.export(),
+      isRecentBookHidden: false
+    });
+  },
+
+  // 点击隐藏的最近阅读
+  toggleRecentBook() {
+    if (this.data.isRecentBookHidden) {
+      // 隐藏状态点击展开
+      this.showRecentBook();
+    } else {
+      // 展开状态点击跳转
+      this.goToRecentBook();
+    }
+  },
+
   // 自动登录
   async autoLogin() {
     try {
@@ -70,6 +141,8 @@ Page({
         this.setData({ isLoggedIn: true });
         // 获取性别设置并加载数据
         this.initGenderAndLoadData();
+        // 获取最近阅读记录
+        this.getRecentReadBook();
         return;
       }
       
@@ -78,6 +151,8 @@ Page({
       this.setData({ isLoggedIn: true });
       // 登录成功后获取性别设置并加载数据
       this.initGenderAndLoadData();
+      // 获取最近阅读记录
+      this.getRecentReadBook();
       
     } catch (error) {
       console.error('登录失败:', error);
@@ -104,6 +179,50 @@ Page({
     }
   },
 
+  // 获取最近阅读的书籍
+  async getRecentReadBook() {
+    try {
+      const historyList = await getBrowsingHistory();
+      if (Array.isArray(historyList) && historyList.length > 0) {
+        // 取第一本作为最近阅读
+        const recentBook = historyList[0];
+        this.setData({
+          recentBook: recentBook,
+          showRecentBook: true,
+          isRecentBookHidden: false
+        });
+        
+        // 重置动画
+        if (this.recentBookAnimator) {
+          this.recentBookAnimator.translateX(0).step();
+          this.setData({
+            recentBookAnimation: this.recentBookAnimator.export()
+          });
+        }
+      } else {
+        this.setData({
+          showRecentBook: false
+        });
+      }
+    } catch (error) {
+      console.error('获取最近阅读失败:', error);
+      this.setData({
+        showRecentBook: false
+      });
+    }
+  },
+
+  // 跳转到最近阅读的书籍
+  goToRecentBook() {
+    if (this.data.recentBook) {
+      goToBookDetail({
+        bookId: this.data.recentBook.novelId,
+        wxBookId: this.data.recentBook.appId,
+        chapterId: this.data.recentBook.novelChapterId
+      });
+    }
+  },
+
   // 加载所有数据
   loadAllData() {
     wx.showLoading({ title: '加载中...' });

+ 11 - 4
pages/index/index.wxml

@@ -21,7 +21,7 @@
     <view class="tab-search">
       <gender-tabs gender="{{gender}}" bind:switch="switchGender"/>
       <view class="search-box" bindtap="goToSearch">
-        <icon type="search" size="14" color="#999"></icon>
+        <icon type="search" size="22" color="#999"></icon>
         <input placeholder="请输入书名/口令搜索" disabled="true" placeholder-class="placeholder"/>
         <view class="search-placeholder"></view>
       </view>
@@ -36,9 +36,7 @@
         circular="true"
         class="banner-swiper">
         <swiper-item wx:for="{{bannerList}}" wx:key="id">
-          <image src="{{item.cover}}" mode="aspectFill" bindtap="goToBookDetail"  data-book-id="{{ item.id }}"
-          data-wx-book-id="{{ item.wxBookId }}"
-          data-chapter-id="{{ item.chapterId }}" />
+          <image src="{{item.cover}}" mode="aspectFill" bindtap="onBannerTap" data-item="{{item}}"/>
         </swiper-item>
       </swiper>
     </view>
@@ -141,4 +139,13 @@
       </view>
     </view>
   </view>
+  
+  <!-- 最近阅读悬浮按钮 -->
+  <view class="recent-book-float" 
+    wx:if="{{showRecentBook && recentBook}}" 
+    bindtap="toggleRecentBook"
+    animation="{{recentBookAnimation}}">
+    <image src="{{recentBook.novelCover}}" mode="aspectFill"></image>
+    <view class="recent-book-label">继续阅读</view>
+  </view>
 </view>

+ 41 - 6
pages/index/index.wxss

@@ -74,7 +74,7 @@ page {
   padding: 30rpx 30rpx 0 30rpx;
   display: flex;
   justify-content: space-between;
-  align-items: center;
+  align-items: flex-start;
 }
 
 .gender-tabs {
@@ -114,8 +114,8 @@ page {
   height: 70rpx;
   background-color: #fff;
   border-radius: 35rpx;
-  padding: 0 30rpx;
-  width: 400rpx;
+  padding: 0 15rpx;
+  width: 420rpx;
 }
 
 .search-box icon {
@@ -193,7 +193,7 @@ page {
 /* 主编推荐 */
 .recommend-section {
   background-color: #fff;
-  margin: 20rpx 30rpx 30rpx;
+  margin: 5rpx 30rpx;
   border-radius: 20rpx;
   width: 690rpx;
   overflow:hidden;
@@ -278,7 +278,7 @@ page {
 /* 全网热推 */
 .hot-section {
   background-color: #fff;
-  margin: 20rpx 30rpx 30rpx;
+  margin: 30rpx 30rpx 0;
   border-radius: 20rpx;
 }
 
@@ -334,7 +334,7 @@ page {
 /* 强力推荐 */
 .strong-recommend {
   background-color: #fff;
-  margin: 20rpx 30rpx 30rpx;
+  margin: 30rpx 30rpx;
   border-radius: 20rpx;
   width: 690rpx;
   box-sizing: border-box;
@@ -445,3 +445,38 @@ page {
   0% { transform: rotate(0deg); }
   100% { transform: rotate(360deg); }
 }
+
+/* 最近阅读悬浮按钮样式 */
+.recent-book-float {
+  position: fixed;
+  left: 20rpx;
+  bottom: 80rpx;
+  z-index: 999;
+  width: 160rpx;
+  height: 227rpx;
+  border-radius: 12rpx;
+  overflow: hidden;
+  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
+  background-color: #B07B46;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+
+.recent-book-float image {
+  width: 145rpx;
+  height: 170rpx;
+  border-radius: 12rpx;
+}
+
+.recent-book-label {
+  width: 100%;
+  height: 30rpx;
+  font-size: 24rpx;
+  color: #ffffff;
+  background-color: #B07B46;
+  text-align: center;
+  margin-top: 8rpx;
+  margin-bottom: 8rpx;
+}

+ 2 - 1
project.private.config.json

@@ -3,5 +3,6 @@
   "projectname": "readSpace",
   "setting": {
     "compileHotReLoad": true
-  }
+  },
+  "libVersion": "3.7.11"
 }