From 577e782cd84fe9d1c2d55d0712b3166d66f4c05b Mon Sep 17 00:00:00 2001 From: chenghuan Date: Mon, 10 Nov 2025 09:16:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E2=80=9C=E6=88=91=E7=9A=84=E4=B9=A6=E5=8D=95=E2=80=9D=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.vue | 2 +- api/modules/book.ts | 204 ++++++++ components/book/BookCard.vue | 168 ++++++ components/book/CommentList.vue | 237 +++++++++ locale/en.json | 75 ++- locale/zh-Hans.json | 75 ++- main.js | 16 - pages.json | 42 ++ pages/book/README.md | 207 ++++++++ pages/book/detail.vue | 620 ++++++++++++++++++++++ pages/book/index.vue | 24 + pages/book/listen/index.vue | 295 +++++++++++ pages/book/listen/player.vue | 614 ++++++++++++++++++++++ pages/book/reader.vue | 888 ++++++++++++++++++++++++++++++++ pages/book/review.vue | 513 ++++++++++++++++++ pages/index/index.vue | 3 +- pages/user/index.vue | 4 +- pages/user/myBook/index.vue | 225 ++++++++ pages/user/order/index.vue | 10 +- pages/user/settings/index.vue | 110 +++- static/tailwind.css | 13 +- stores/book.ts | 88 ++++ stores/sys.ts | 22 + stores/user.ts | 6 + types/book.d.ts | 91 ++++ 25 files changed, 4515 insertions(+), 37 deletions(-) create mode 100644 api/modules/book.ts create mode 100644 components/book/BookCard.vue create mode 100644 components/book/CommentList.vue create mode 100644 pages/book/README.md create mode 100644 pages/book/detail.vue create mode 100644 pages/book/index.vue create mode 100644 pages/book/listen/index.vue create mode 100644 pages/book/listen/player.vue create mode 100644 pages/book/reader.vue create mode 100644 pages/book/review.vue create mode 100644 pages/user/myBook/index.vue create mode 100644 stores/book.ts create mode 100644 stores/sys.ts create mode 100644 types/book.d.ts diff --git a/App.vue b/App.vue index 8281a62..82ff1a6 100644 --- a/App.vue +++ b/App.vue @@ -13,7 +13,7 @@ diff --git a/components/book/CommentList.vue b/components/book/CommentList.vue new file mode 100644 index 0000000..f28e5f9 --- /dev/null +++ b/components/book/CommentList.vue @@ -0,0 +1,237 @@ + + + + + diff --git a/locale/en.json b/locale/en.json index d5b973c..6133184 100644 --- a/locale/en.json +++ b/locale/en.json @@ -90,7 +90,16 @@ "failed": "Failed", "networkError": "Network Error", "pleaseInput": "Please Input", - "pleaseSelect": "Please Select" + "pleaseSelect": "Please Select", + "data_null": "No Data", + "submit_text": "Submit", + "cancel_text": "Cancel", + "confirm_text": "Confirm", + "limit_title": "Tips", + "justNow": "Just Now", + "minutesAgo": " mins ago", + "hoursAgo": " hours ago", + "daysAgo": " days ago" }, "user": { "title": "My", @@ -100,6 +109,10 @@ "about": "About Us", "feedback": "Feedback", "settings": "Settings", + "language": "Language", + "languageSelect": "Select Language", + "languageChangeSuccess": "Language changed successfully", + "languageChangeFailed": "Failed to change language", "subscribe": "Subscribe", "myAccount": "My Account", "notSet": "Not Set", @@ -188,5 +201,65 @@ "yearCard": "Yearly", "days": "days", "selectPackage": "Please select a package" + }, + "book": { + "title": "My Books", + "myBook": "My Books", + "read": "Read", + "listen": "Listen", + "comment": "Review", + "choose": "Browse Books", + "nullText": "No books yet, go shopping~", + "afterPurchase": "Available after purchase", + "contents": "Contents", + "zjContents": "Chapter List", + "set": "Settings", + "font": "Font Size", + "bgColor": "Background", + "type": "Reading Mode", + "type_1": "Scroll", + "type_2": "Page Turn", + "voices_null": "No audio available", + "endText": "Trial ended, purchase to continue", + "language": "Book language" + }, + "bookDetails": { + "title": "Book Details", + "title_comment": "Reviews", + "authorName": "Author: ", + "introduction": "Introduction", + "message": "Reviews", + "more": "More", + "relatedBooks": "Related Books", + "startReading": "Start Reading", + "startListening": "Start Listening", + "tryRead": "Try Reading", + "tryListen": "Try Listening", + "buy": "Buy Now", + "buttonText1": "Buy Now", + "buttonText2": "Purchased", + "list": "Select", + "makeComment": "Write Review", + "reply": "Reply to ", + "dpl": "'s comment", + "enterText": "Enter your comment", + "replyText": "Reply to ", + "supportSuccess": "Liked", + "supportCancel": "Unliked", + "deleteText": "Delete this comment?", + "deleteSuccess": "Deleted" + }, + "home": { + "readingCount": " reads", + "listenCount": " listens", + "purchased": " purchased" + }, + "listen": { + "title": "Audio Book", + "speed": "Playback Speed", + "chapterList": "Chapter List" + }, + "workOrder": { + "submit_success": "Submitted successfully" } } diff --git a/locale/zh-Hans.json b/locale/zh-Hans.json index e88b185..8dd831c 100644 --- a/locale/zh-Hans.json +++ b/locale/zh-Hans.json @@ -91,7 +91,16 @@ "failed": "操作失败", "networkError": "网络连接失败", "pleaseInput": "请输入", - "pleaseSelect": "请选择" + "pleaseSelect": "请选择", + "data_null": "暂无数据", + "submit_text": "提交", + "cancel_text": "取消", + "confirm_text": "确定", + "limit_title": "提示", + "justNow": "刚刚", + "minutesAgo": "分钟前", + "hoursAgo": "小时前", + "daysAgo": "天前" }, "user": { "title": "我的", @@ -101,6 +110,10 @@ "about": "关于我们", "feedback": "问题反馈", "settings": "设置", + "language": "语言", + "languageSelect": "选择语言", + "languageChangeSuccess": "语言切换成功", + "languageChangeFailed": "语言切换失败", "subscribe": "订阅", "myAccount": "我的账户", "notSet": "未设置", @@ -189,5 +202,65 @@ "yearCard": "年卡", "days": "天", "selectPackage": "请选择套餐" + }, + "book": { + "title": "我的书单", + "myBook": "我的书单", + "read": "阅读", + "listen": "听书", + "comment": "书评", + "choose": "去选书", + "nullText": "暂无书籍,快去选购吧~", + "afterPurchase": "购买后即可使用此功能", + "contents": "目录", + "zjContents": "章节目录", + "set": "设置", + "font": "字体大小", + "bgColor": "背景颜色", + "type": "阅读模式", + "type_1": "上下滚动", + "type_2": "左右翻页", + "voices_null": "暂无音频文件", + "endText": "试读已结束,购买后继续阅读", + "language": "书籍语言" + }, + "bookDetails": { + "title": "书籍详情", + "title_comment": "书评", + "authorName": "作者:", + "introduction": "内容简介", + "message": "书评", + "more": "更多", + "relatedBooks": "相关推荐", + "startReading": "开始阅读", + "startListening": "开始听书", + "tryRead": "试读", + "tryListen": "试听", + "buy": "立即购买", + "buttonText1": "立即购买", + "buttonText2": "已购买", + "list": "选择规格", + "makeComment": "发表评论", + "reply": "回复", + "dpl": "的评论", + "enterText": "请输入评论内容", + "replyText": "回复", + "supportSuccess": "点赞成功", + "supportCancel": "取消点赞", + "deleteText": "确定删除此评论吗?", + "deleteSuccess": "删除成功" + }, + "home": { + "readingCount": "次阅读", + "listenCount": "次听书", + "purchased": "人购买" + }, + "listen": { + "title": "听书", + "speed": "播放速度", + "chapterList": "章节列表" + }, + "workOrder": { + "submit_success": "提交成功" } } diff --git a/main.js b/main.js index a563d93..1fafc57 100644 --- a/main.js +++ b/main.js @@ -7,21 +7,6 @@ let i18nConfig = { messages } -// #ifndef VUE3 -import Vue from 'vue' -import VueI18n from 'vue-i18n'' -Vue.use(VueI18n) -export i18n = new VueI18n(i18nConfig) -Vue.config.productionTip = false -App.mpType = 'app' -const app = new Vue({ - i18n, - ...App -}) -app.$mount() -// #endif - -// #ifdef VUE3 import { createSSRApp } from 'vue' import { createI18n } from 'vue-i18n' import { createPinia } from 'pinia' @@ -35,4 +20,3 @@ export function createApp() { app } } -// #endif diff --git a/pages.json b/pages.json index 5d3b9c5..a2e20b6 100644 --- a/pages.json +++ b/pages.json @@ -73,6 +73,48 @@ "navigationBarTitleText": "%user.feedback%", "navigationStyle": "custom" } + }, { + "path": "pages/user/myBook/index", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "%book.title%" + } + }, { + "path": "pages/book/index", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "%book.title%" + } + }, { + "path": "pages/book/detail", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "%details.title%" + } + }, { + "path": "pages/book/review", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "%details.title_comment%" + } + }, { + "path": "pages/book/reader", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "%book.read%" + } + }, { + "path": "pages/book/listen/index", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "%listen.title%" + } + }, { + "path": "pages/book/listen/player", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "%listen.title%" + } } ], // "tabBar": { diff --git a/pages/book/README.md b/pages/book/README.md new file mode 100644 index 0000000..1248394 --- /dev/null +++ b/pages/book/README.md @@ -0,0 +1,207 @@ +# 我的书单功能模块 + +## 概述 + +本模块是从nuttyreading项目迁移并升级到Vue3+TypeScript+Pinia+TailwindCSS+WotUI+i18n技术栈的"我的书单"功能。 + +## 功能列表 + +### 1. 书单列表 (`pages/book/index.vue`) +- ✅ 显示用户已购买的所有书籍 +- ✅ 分页加载 +- ✅ 空状态处理 +- ✅ 支持跳转到详情、阅读器、听书、书评页面 +- ✅ iOS平台自动隐藏书评按钮 + +### 2. 书籍详情 (`pages/book/detail.vue`) +- ✅ 显示书籍封面、标题、作者、简介 +- ✅ 显示阅读数、听书数、购买数统计 +- ✅ 显示前2条书评(非iOS) +- ✅ 显示相关推荐书籍 +- ✅ 根据购买状态显示不同操作按钮 +- ✅ 购买弹窗 + +### 3. 书评系统 (`pages/book/review.vue`) +- ✅ 评论列表展示 +- ✅ 发表评论(富文本编辑器) +- ✅ 点赞/取消点赞 +- ✅ 回复评论 +- ✅ 删除评论 +- ✅ 分页加载更多 +- ✅ Emoji支持(待完善) + +### 4. 阅读器 (`pages/book/reader.vue`) +- ✅ 上下滚动模式 +- ✅ 左右翻页模式 +- ✅ 字体大小调节(8个级别) +- ✅ 主题切换(5种主题) +- ✅ 章节目录 +- ✅ 阅读进度保存和恢复 +- ✅ 图片内容显示 +- ✅ 试读限制提示 + +### 5. 听书功能 +#### 章节列表 (`pages/book/listen/index.vue`) +- ✅ 显示书籍信息 +- ✅ 章节列表 +- ✅ 章节锁定状态 +- ✅ 音频文件检查 + +#### 音频播放器 (`pages/book/listen/player.vue`) +- ✅ 音频播放/暂停 +- ✅ 进度条控制 +- ✅ 快进/快退(15秒) +- ✅ 上一章/下一章 +- ✅ 播放速度调节(0.5x - 2x) +- ✅ 自动播放下一章 +- ✅ 封面旋转动画 + +## 技术栈 + +- **框架**: Vue3 Composition API +- **语言**: TypeScript +- **状态管理**: Pinia +- **UI组件**: WotUI +- **样式**: SCSS + TailwindCSS +- **国际化**: vue-i18n + +## 文件结构 + +``` +pages/book/ +├── index.vue # 书单列表 +├── detail.vue # 书籍详情 +├── review.vue # 书评页面 +├── reader.vue # 阅读器 +└── listen/ + ├── index.vue # 听书章节列表 + └── player.vue # 音频播放器 + +components/book/ +├── CustomNavbar.vue # 自定义导航栏 +├── BookCard.vue # 书籍卡片 +└── CommentList.vue # 评论列表 + +api/modules/ +└── book.ts # 书籍API + +stores/ +└── book.ts # 书籍状态管理 + +types/ +└── book.d.ts # 类型定义 +``` + +## API接口 + +所有API接口保持与原项目完全一致: + +- `bookAbroad/home/getbooks` - 获取我的书单 +- `bookAbroad/home/getBookInfo` - 获取书籍详情 +- `bookAbroad/home/getBookReadCount` - 获取统计数据 +- `bookAbroad/home/getRecommendBook` - 获取推荐书籍 +- `bookAbroad/getBookAbroadCommentTree` - 获取评论列表 +- `bookAbroad/insertBookAbroadComment` - 发表评论 +- `bookAbroad/insertBookAbroadCommentLike` - 点赞 +- `bookAbroad/delBookAbroadCommentLike` - 取消点赞 +- `bookAbroad/delBookAbroadComment` - 删除评论 +- `bookAbroad/home/getBookChapter` - 获取章节列表 +- `bookAbroad/home/getBookChapterContent` - 获取章节内容 +- `bookAbroad/home/getBookReadRate` - 获取阅读进度 +- `bookAbroad/home/insertBookReadRate` - 保存阅读进度 + +## 国际化 + +支持中文和英文两种语言,所有文本通过i18n配置管理。 + +### 翻译键 +- `book.*` - 书单相关 +- `details.*` - 详情相关 +- `listen.*` - 听书相关 +- `common.*` - 通用文本 + +## 平台适配 + +### iOS特殊处理 +- 书评功能在iOS平台自动隐藏 +- 使用条件编译 `#ifdef APP-PLUS` 判断平台 + +### 刘海屏适配 +- 所有页面自动适配状态栏高度 +- 使用 `uni.getSystemInfoSync().safeArea` 获取安全区域 + +## 使用说明 + +### 1. 从书单列表进入 +```typescript +uni.navigateTo({ + url: '/pages/book/index' +}) +``` + +### 2. 直接进入书籍详情 +```typescript +uni.navigateTo({ + url: `/pages/book/detail?id=${bookId}` +}) +``` + +### 3. 进入阅读器 +```typescript +// 已购买 +uni.navigateTo({ + url: `/pages/book/reader?isBuy=0&bookId=${bookId}` +}) + +// 试读 +uni.navigateTo({ + url: `/pages/book/reader?isBuy=1&bookId=${bookId}&count=${freeChapterCount}` +}) +``` + +### 4. 进入听书 +```typescript +uni.navigateTo({ + url: `/pages/book/listen/index?bookId=${bookId}` +}) +``` + +## 注意事项 + +1. **不要修改API接口**:所有接口地址和参数必须与原项目保持一致 +2. **UI组件使用WotUI**:不要使用uView或uni-ui组件 +3. **国际化文本**:所有文本必须通过i18n配置,不能硬编码 +4. **iOS平台**:注意书评功能的隐藏处理 +5. **类型安全**:充分利用TypeScript类型检查 + +## 待优化项 + +1. Emoji选择器组件需要集成完整的Emoji库 +2. 阅读器可以添加更多主题 +3. 音频播放器可以添加播放列表功能 +4. 可以添加书签功能 +5. 可以添加笔记功能 + +## 测试清单 + +- [ ] 书单列表加载和分页 +- [ ] 书籍详情所有信息显示 +- [ ] 书评发表、点赞、删除 +- [ ] 阅读器两种模式切换 +- [ ] 阅读器字体和主题设置 +- [ ] 阅读进度保存和恢复 +- [ ] 听书播放控制 +- [ ] 听书速度调节 +- [ ] iOS平台书评隐藏 +- [ ] 试读/试听限制 +- [ ] 国际化文本切换 + +## 更新日志 + +### v1.0.0 (2024-01-XX) +- ✅ 完成从Vue2到Vue3的迁移 +- ✅ 完成TypeScript类型定义 +- ✅ 完成Pinia状态管理 +- ✅ 完成WotUI组件替换 +- ✅ 完成国际化配置 +- ✅ 完成所有功能页面 diff --git a/pages/book/detail.vue b/pages/book/detail.vue new file mode 100644 index 0000000..d4e50ba --- /dev/null +++ b/pages/book/detail.vue @@ -0,0 +1,620 @@ + + + + + diff --git a/pages/book/index.vue b/pages/book/index.vue new file mode 100644 index 0000000..1da8775 --- /dev/null +++ b/pages/book/index.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/pages/book/listen/index.vue b/pages/book/listen/index.vue new file mode 100644 index 0000000..53fa183 --- /dev/null +++ b/pages/book/listen/index.vue @@ -0,0 +1,295 @@ + + + + + diff --git a/pages/book/listen/player.vue b/pages/book/listen/player.vue new file mode 100644 index 0000000..fe6c281 --- /dev/null +++ b/pages/book/listen/player.vue @@ -0,0 +1,614 @@ + + + + + diff --git a/pages/book/reader.vue b/pages/book/reader.vue new file mode 100644 index 0000000..dc07b6a --- /dev/null +++ b/pages/book/reader.vue @@ -0,0 +1,888 @@ + + + + + diff --git a/pages/book/review.vue b/pages/book/review.vue new file mode 100644 index 0000000..42983a4 --- /dev/null +++ b/pages/book/review.vue @@ -0,0 +1,513 @@ + + + + + diff --git a/pages/index/index.vue b/pages/index/index.vue index 47ad80d..6feac22 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -1,6 +1,7 @@ diff --git a/pages/user/index.vue b/pages/user/index.vue index 09129ce..a993067 100644 --- a/pages/user/index.vue +++ b/pages/user/index.vue @@ -96,8 +96,8 @@ const menuItems = computed(() => [ { id: 2, name: t('user.myBooklist'), - url: '/pages/book/index', - type: 'switchTab' + url: '/pages/user/myBook/index', + type: 'pageJump' }, { id: 3, diff --git a/pages/user/myBook/index.vue b/pages/user/myBook/index.vue new file mode 100644 index 0000000..abd58d8 --- /dev/null +++ b/pages/user/myBook/index.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/pages/user/order/index.vue b/pages/user/order/index.vue index f81bb3c..f74ff0d 100644 --- a/pages/user/order/index.vue +++ b/pages/user/order/index.vue @@ -1,21 +1,13 @@