小说小程序前端代码仓库(小程序)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

727 lines
14 KiB

  1. <template>
  2. <!-- 小说详情页面 -->
  3. <view class="novel-detail">
  4. <!-- 顶部返回导航 -->
  5. <uv-navbar title="小说详情" :autoBack="true" fixed placeholder titleStyle="color: #333; font-weight: 700;"
  6. :border="false">
  7. <template #left>
  8. <BackArrow :size="56" color="#333" @back="goBack" />
  9. </template>
  10. </uv-navbar>
  11. <!-- 小说基本信息 -->
  12. <view class="novel-info">
  13. <view class="novel-cover">
  14. <image :src="novelData.coverUrl" mode="aspectFill"></image>
  15. </view>
  16. <view class="novel-basic">
  17. <text class="title">{{ novelData.title }}</text>
  18. <view class="author-line">
  19. <text class="label">作者</text>
  20. <text class="author">{{ novelData.author }}</text>
  21. </view>
  22. <view class="status-line">
  23. <text class="label">完结</text>
  24. <text class="status">{{ novelData.status }}</text>
  25. </view>
  26. <view class="score-line">
  27. <text class="score">{{ novelData.score || 2814}}</text>
  28. <text class="score-label">作者累计亲密度值</text>
  29. </view>
  30. </view>
  31. </view>
  32. <!-- 推荐票数显示 -->
  33. <view class="recommendation-section">
  34. <view class="rec-left">
  35. <text class="rec-count">2814</text>
  36. <text class="rec-label">推荐票数</text>
  37. </view>
  38. <view class="rec-divider"></view>
  39. <view class="rec-right">
  40. <button class="recommend-btn" @click="recommendNovel">
  41. <text class="btn-icon">📑</text>
  42. 投推荐票
  43. </button>
  44. </view>
  45. </view>
  46. <!-- 阅读和收藏按钮 -->
  47. <!-- 我的等级 -->
  48. <view class="user-level">
  49. <view class="level-left">
  50. <view class="level-title">
  51. <text class="title-icon">👑</text>
  52. <text>我的等级</text>
  53. </view>
  54. <view class="level-info">
  55. <image class="user-avatar"
  56. src="https://tse4-mm.cn.bing.net/th/id/OIP-C.iUyxJ_fxLjjX3kEBjteXWwAAAA?rs=1&pid=ImgDetMain"
  57. mode="aspectFill"></image>
  58. <view class="user-details">
  59. <text class="username">周海</text>
  60. <view class="user-score">
  61. <text class="score-value">6785452</text>
  62. <text class="score-label">亲密值</text>
  63. </view>
  64. <text class="user-role">护书使者 五级</text>
  65. </view>
  66. </view>
  67. </view>
  68. <view class="level-right">
  69. <view class="rank-btn">
  70. <image class="rank-icon"
  71. src="https://tse4-mm.cn.bing.net/th/id/OIP-C.iUyxJ_fxLjjX3kEBjteXWwAAAA?rs=1&pid=ImgDetMain"
  72. mode="aspectFit"></image>
  73. <text>读者榜单</text>
  74. <text class="check-text">点击查看</text>
  75. </view>
  76. </view>
  77. </view>
  78. <!-- 小说简介 -->
  79. <view class="novel-intro">
  80. <view class="intro-title">
  81. <text>简介</text>
  82. </view>
  83. <view class="intro-content">
  84. <text>这游戏也太真实了吧</text>
  85. <text>搬砖跑腿捡垃圾送快递......公司最多能让你体会到996的艰辛在这里你能体会到超级加倍的007</text>
  86. <text>好了不废话了伟大的管理者大人嘛就去搬砖了那位大人说了只要我们努力献上自己的肝下个月他又能换一套全新的动力甲到时候候带我们开全新的地图去广阔的废土捡更多的垃圾</text>
  87. <text>穿越到废土世界的基光发现自己解锁了游戏所系统能够从平行世界召唤名为"玩家"的生物</text>
  88. </view>
  89. </view>
  90. <!-- 目录 -->
  91. <view class="novel-catalog" @click="$refs.chapterPopup.open()">
  92. <view class="catalog-header">
  93. <view class="catalog-title">
  94. <text class="title-icon">📖</text>
  95. <text>目录</text>
  96. </view>
  97. <view class="chapter-nav">
  98. <text class="current-chapter">第九集 - 高去与归来</text>
  99. <text class="nav-arrow">></text>
  100. </view>
  101. </view>
  102. </view>
  103. <!-- 目录弹窗完整内容内联 -->
  104. <!-- 书评区域 -->
  105. <view class="comments-section">
  106. <view class="comments-header">
  107. <view class="header-left">
  108. <text class="title-icon">📝</text>
  109. <text>书评</text>
  110. </view>
  111. <view class="header-right">
  112. <text @click="goToWriteReview">写书评</text>
  113. </view>
  114. </view>
  115. <view class="comment-list">
  116. <commentItem v-for="(item, index) in 10" :key="index" />
  117. </view>
  118. </view>
  119. <!-- 底部操作栏 -->
  120. <view class="novel-bottom">
  121. <view class="bottom-left">
  122. <view class="action-btn" @click="addToBookshelf">
  123. <text class="btn-icon">📚</text>
  124. <text>加入书架</text>
  125. </view>
  126. <view class="action-btn" @click="goToGiftbox">
  127. <text class="btn-icon">🎁</text>
  128. <text>礼物盒</text>
  129. </view>
  130. <view class="action-btn" @click="toggleInteractive">
  131. <text class="btn-icon">🎯</text>
  132. <text>互动打赏</text>
  133. </view>
  134. </view>
  135. <view class="bottom-right">
  136. <button class="read-now-btn" @click="startReading">立即阅读</button>
  137. </view>
  138. </view>
  139. <chapterPopup ref="chapterPopup" />
  140. </view>
  141. </template>
  142. <script>
  143. import catalogpopup from '@/components/novel/CatalogPopup.vue'
  144. import BackArrow from './components/BackArrow.vue'
  145. import chapterPopup from '../components/novel/chapterPopup.vue'
  146. import commentItem from '../components/comment/commentItem.vue'
  147. export default {
  148. components: {
  149. catalogpopup,
  150. BackArrow,
  151. chapterPopup,
  152. commentItem,
  153. },
  154. data() {
  155. return {
  156. novelData: {
  157. id: '1',
  158. title: '这游戏也太真实了',
  159. author: '大宝鉴在在',
  160. category: '玄幻',
  161. wordCount: '2814',
  162. coverUrl: 'https://tse4-mm.cn.bing.net/th/id/OIP-C.iUyxJ_fxLjjX3kEBjteXWwAAAA?rs=1&pid=ImgDetMain',
  163. introduction: '这游戏也太真实了!\n模拟,模拟,模拟,这游戏……公空居然把自己做成了游戏的NPC?这是什么新型的套路啊!好了,不要慌了,作为的管理者人员都在忙碌着,都在工作人员中,只要我们努力就自己的事,下个月他又给一套全新的剧情开始,如何将模拟的开关全新的世界,去广阔的世界去探索吧!'
  164. },
  165. isCollected: false,
  166. comments: [{
  167. username: '方寒锋',
  168. avatar: '/static/images/user1.jpg',
  169. content: '我是全书中年龄最大的人,这是一本很好的文章!满满心头热,只要对你"安全"文案有兴趣的,都可以不虚,不害怕,不要想太多就去尝试阅读吧!',
  170. time: '2024-07-09'
  171. }],
  172. currentIndex: 0,
  173. }
  174. },
  175. computed: {
  176. userInfo() {
  177. return {
  178. avatar: '/static/images/avatar.jpg',
  179. level: '67级达人'
  180. }
  181. }
  182. },
  183. methods: {
  184. goBack() {
  185. uni.navigateBack()
  186. },
  187. startReading() {
  188. uni.navigateTo({
  189. url: `/pages_order/novel/readnovels?id=${this.novelData.id}`
  190. })
  191. },
  192. toggleCollect() {
  193. this.isCollected = !this.isCollected
  194. // TODO: 实现收藏功能
  195. },
  196. recommendNovel() {
  197. if (!this.novelData.id) {
  198. uni.showToast({
  199. title: '无效的小说ID',
  200. icon: 'none'
  201. })
  202. return
  203. }
  204. uni.navigateTo({
  205. url: `/pages_order/novel/vote?id=${this.novelData.id}`
  206. })
  207. },
  208. goToWriteReview() {
  209. // 跳转到写书评页面,传递书名参数
  210. uni.navigateTo({
  211. url: `/pages_order/novel/Review?title=${encodeURIComponent(this.novelData.title)}`
  212. })
  213. },
  214. addToBookshelf() {
  215. // TODO: 实现加入书架功能
  216. uni.showToast({
  217. title: '已加入书架',
  218. icon: 'success'
  219. })
  220. },
  221. toggleInteractive() {
  222. // 跳转到互动打赏页面
  223. uni.navigateTo({
  224. url: `/pages_order/novel/Tipping?id=${this.novelData.id}`
  225. })
  226. },
  227. goToGiftbox() {
  228. uni.navigateTo({
  229. url: '/pages_order/novel/Giftbox'
  230. })
  231. },
  232. handleShowCatalog() {
  233. console.log('点击目录区域');
  234. this.showCatalog = true;
  235. },
  236. selectChapter(idx) {
  237. this.currentIndex = idx
  238. this.showCatalog = false
  239. // TODO: 跳转到对应章节内容
  240. },
  241. goToCommentReply() {
  242. uni.navigateTo({
  243. url: '/pages_order/novel/comments'
  244. })
  245. }
  246. }
  247. }
  248. </script>
  249. <style lang="scss" scoped>
  250. .novel-detail {
  251. min-height: 100vh;
  252. background-color: #f5f5f5;
  253. padding-bottom: calc(env(safe-area-inset-bottom) + 30rpx);
  254. }
  255. .nav-header {
  256. display: flex;
  257. justify-content: space-between;
  258. align-items: center;
  259. padding: 20rpx 30rpx;
  260. background-color: transparent;
  261. position: fixed;
  262. top: 0;
  263. left: 0;
  264. right: 0;
  265. z-index: 100;
  266. }
  267. .novel-info {
  268. padding: 20rpx;
  269. display: flex;
  270. background: #fff;
  271. }
  272. .novel-cover {
  273. width: 200rpx;
  274. height: 280rpx;
  275. margin-right: 20rpx;
  276. }
  277. .novel-cover image {
  278. width: 100%;
  279. height: 100%;
  280. border-radius: 8rpx;
  281. }
  282. .novel-basic {
  283. flex: 1;
  284. display: flex;
  285. flex-direction: column;
  286. justify-content: space-between;
  287. }
  288. .title {
  289. font-size: 36rpx;
  290. font-weight: bold;
  291. margin-bottom: 16rpx;
  292. }
  293. .author-line,
  294. .status-line {
  295. display: flex;
  296. align-items: center;
  297. margin-bottom: 12rpx;
  298. font-size: 28rpx;
  299. color: #666;
  300. }
  301. .label {
  302. color: #999;
  303. margin-right: 8rpx;
  304. }
  305. .score-line {
  306. margin-top: 16rpx;
  307. }
  308. .score {
  309. font-size: 32rpx;
  310. color: #333;
  311. font-weight: bold;
  312. }
  313. .score-label {
  314. font-size: 24rpx;
  315. color: #999;
  316. margin-left: 8rpx;
  317. }
  318. .recommendation-section {
  319. padding: 24rpx 32rpx;
  320. background: #fff;
  321. display: flex;
  322. justify-content: space-between;
  323. align-items: center;
  324. position: relative;
  325. }
  326. .rec-left {
  327. display: flex;
  328. flex-direction: column;
  329. align-items: flex-start;
  330. margin-left: 70rpx;
  331. }
  332. .rec-count {
  333. font-size: 44rpx;
  334. font-weight: 500;
  335. color: #333;
  336. line-height: 1.2;
  337. }
  338. .rec-label {
  339. font-size: 26rpx;
  340. color: #999;
  341. margin-top: 4rpx;
  342. }
  343. .rec-divider {
  344. position: absolute;
  345. right: 160rpx;
  346. top: 20rpx;
  347. bottom: 20rpx;
  348. width: 2rpx;
  349. background: #eee;
  350. }
  351. .rec-right {
  352. flex-shrink: 0;
  353. }
  354. .recommend-btn {
  355. background: #fff;
  356. color: #4a90e2;
  357. border: 2rpx solid #4a90e2;
  358. border-radius: 40rpx;
  359. padding: 12rpx 32rpx;
  360. font-size: 28rpx;
  361. display: flex;
  362. align-items: center;
  363. line-height: 1;
  364. height: 64rpx;
  365. }
  366. .btn-icon {
  367. margin-right: 8rpx;
  368. font-size: 32rpx;
  369. }
  370. .action-buttons {
  371. display: flex;
  372. padding: 30rpx;
  373. gap: 20rpx;
  374. button {
  375. flex: 1;
  376. height: 80rpx;
  377. border-radius: 40rpx;
  378. font-size: 32rpx;
  379. display: flex;
  380. align-items: center;
  381. justify-content: center;
  382. }
  383. .read-btn {
  384. background-color: #4a90e2;
  385. color: #fff;
  386. }
  387. .collect-btn {
  388. background-color: #f0f0f0;
  389. color: #666;
  390. }
  391. }
  392. .user-level {
  393. margin: 20rpx 30rpx;
  394. background-color: #fff;
  395. border-radius: 12rpx;
  396. padding: 24rpx 32rpx;
  397. display: flex;
  398. justify-content: space-between;
  399. align-items: stretch;
  400. }
  401. .level-left {
  402. flex: 1;
  403. }
  404. .level-title {
  405. display: flex;
  406. align-items: center;
  407. gap: 8rpx;
  408. margin-bottom: 20rpx;
  409. margin-left: 20rpx;
  410. .title-icon {
  411. font-size: 36rpx;
  412. color: #FFB800;
  413. }
  414. text {
  415. font-size: 32rpx;
  416. font-weight: 500;
  417. color: #333;
  418. }
  419. }
  420. .level-info {
  421. display: flex;
  422. align-items: flex-start;
  423. gap: 20rpx;
  424. }
  425. .user-avatar {
  426. width: 80rpx;
  427. height: 80rpx;
  428. border-radius: 50%;
  429. border: 2rpx solid #f0f0f0;
  430. }
  431. .user-details {
  432. display: flex;
  433. flex-direction: column;
  434. gap: 8rpx;
  435. }
  436. .username {
  437. font-size: 28rpx;
  438. color: #333;
  439. font-weight: 500;
  440. }
  441. .user-score {
  442. display: flex;
  443. align-items: center;
  444. gap: 8rpx;
  445. .score-value {
  446. font-size: 28rpx;
  447. color: #333;
  448. }
  449. .score-label {
  450. font-size: 24rpx;
  451. color: #999;
  452. }
  453. }
  454. .user-role {
  455. font-size: 24rpx;
  456. color: #666;
  457. background: #f5f5f5;
  458. padding: 4rpx 12rpx;
  459. border-radius: 4rpx;
  460. display: inline-block;
  461. }
  462. .level-right {
  463. display: flex;
  464. align-items: center;
  465. }
  466. .rank-btn {
  467. display: flex;
  468. flex-direction: column;
  469. align-items: center;
  470. justify-content: center;
  471. padding: 0 20rpx;
  472. .rank-icon {
  473. width: 200rpx;
  474. height: 60rpx;
  475. margin-bottom: 8rpx;
  476. }
  477. text {
  478. font-size: 26rpx;
  479. color: #333;
  480. line-height: 1.4;
  481. }
  482. .check-text {
  483. font-size: 22rpx;
  484. color: #999;
  485. }
  486. }
  487. .novel-intro {
  488. margin: 20rpx 30rpx;
  489. background-color: #fff;
  490. border-radius: 12rpx;
  491. padding: 24rpx;
  492. }
  493. .intro-title {
  494. font-size: 32rpx;
  495. font-weight: 500;
  496. color: #333;
  497. margin-bottom: 16rpx;
  498. }
  499. .intro-content {
  500. font-size: 28rpx;
  501. color: #666;
  502. line-height: 1.6;
  503. display: flex;
  504. flex-direction: column;
  505. gap: 16rpx;
  506. text {
  507. display: block;
  508. }
  509. }
  510. .comments-section {
  511. margin: 20rpx 30rpx;
  512. background-color: #fff;
  513. border-radius: 12rpx;
  514. padding: 24rpx;
  515. }
  516. .comments-header {
  517. display: flex;
  518. align-items: center;
  519. margin-bottom: 24rpx;
  520. border-bottom: 2rpx solid #f5f5f5;
  521. padding-bottom: 24rpx;
  522. justify-content: flex-start;
  523. }
  524. .header-left {
  525. display: flex;
  526. align-items: center;
  527. gap: 8rpx;
  528. .title-icon {
  529. font-size: 32rpx;
  530. }
  531. text {
  532. display: flex;
  533. align-items: center;
  534. font-size: 32rpx;
  535. font-weight: 500;
  536. color: #333;
  537. white-space: nowrap;
  538. }
  539. }
  540. .header-right {
  541. margin-left: auto;
  542. }
  543. .comment-list {
  544. display: flex;
  545. flex-direction: column;
  546. gap: 32rpx;
  547. }
  548. .like-icon {
  549. font-size: 24rpx;
  550. color: #999;
  551. }
  552. .like-count {
  553. font-size: 24rpx;
  554. color: #999;
  555. }
  556. .novel-catalog {
  557. margin: 20rpx 30rpx;
  558. background-color: #fff;
  559. border-radius: 12rpx;
  560. padding: 24rpx;
  561. .catalog-header {
  562. display: flex;
  563. justify-content: space-between;
  564. align-items: center;
  565. border-bottom: 2rpx solid #f5f5f5;
  566. .catalog-title {
  567. display: flex;
  568. align-items: center;
  569. gap: 8rpx;
  570. .title-icon {
  571. font-size: 32rpx;
  572. }
  573. text {
  574. font-size: 32rpx;
  575. font-weight: 500;
  576. color: #333;
  577. }
  578. }
  579. }
  580. .chapter-nav {
  581. display: flex;
  582. align-items: center;
  583. gap: 8rpx;
  584. .current-chapter {
  585. font-size: 28rpx;
  586. color: #666;
  587. }
  588. .nav-arrow {
  589. font-size: 28rpx;
  590. color: #999;
  591. }
  592. }
  593. }
  594. .novel-bottom {
  595. position: fixed;
  596. bottom: 0;
  597. left: 0;
  598. right: 0;
  599. height: 100rpx;
  600. background: #fff;
  601. display: flex;
  602. align-items: center;
  603. padding: 0 30rpx;
  604. padding-bottom: env(safe-area-inset-bottom);
  605. box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
  606. .bottom-left {
  607. flex: 1;
  608. display: flex;
  609. gap: 40rpx;
  610. }
  611. .action-btn {
  612. display: flex;
  613. flex-direction: column;
  614. align-items: center;
  615. gap: 4rpx;
  616. .btn-icon {
  617. font-size: 40rpx;
  618. line-height: 1;
  619. }
  620. text {
  621. font-size: 24rpx;
  622. color: #666;
  623. }
  624. }
  625. .bottom-right {
  626. flex-shrink: 0;
  627. }
  628. .read-now-btn {
  629. background: #1a237e;
  630. color: #fff;
  631. font-size: 32rpx;
  632. height: 80rpx;
  633. line-height: 80rpx;
  634. padding: 0 60rpx;
  635. border-radius: 40rpx;
  636. border: none;
  637. }
  638. }
  639. </style>