小说小程序前端代码仓库(小程序)
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.

550 lines
12 KiB

3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
  1. <template>
  2. <view class="page">
  3. <!-- 自定义导航栏 -->
  4. <view class="custom-navbar">
  5. <view class="navbar-left">
  6. <view class="calendar-icon">
  7. <uv-icon name="calendar" color="#ffffff" size="44rpx"></uv-icon>
  8. </view>
  9. </view>
  10. <view class="navbar-center" @click="toSearch">
  11. <view class="search-box">
  12. <uv-icon name="search" color="#999999" size="32rpx"></uv-icon>
  13. <text class="search-placeholder">请输入搜索内容</text>
  14. </view>
  15. </view>
  16. <view class="navbar-right">
  17. <view class="function-btn">
  18. <uv-icon name="more-dot-fill" color="#ffffff" size="44rpx"></uv-icon>
  19. </view>
  20. <view class="function-btn">
  21. <uv-icon name="chat-fill" color="#ffffff" size="44rpx"></uv-icon>
  22. </view>
  23. </view>
  24. </view>
  25. <view class="content">
  26. <!-- 顶部横幅广告 -->
  27. <view class="banner">
  28. <uv-swiper
  29. :list="bannerList"
  30. keyName="image"
  31. :autoplay="true"
  32. :circular="true"
  33. :interval="3000"
  34. radius="10"
  35. :height="400"
  36. indicatorActiveColor="#ffffff"
  37. indicatorInactiveColor="rgba(255, 255, 255, 0.5)"
  38. @click="clickBanner"
  39. >
  40. <template v-slot:default="{item}">
  41. <view class="swiper-item">
  42. <image class="swiper-image" :src="item.image" mode="aspectFill"></image>
  43. <view class="swiper-content">
  44. <view class="swiper-title">{{item.title}}</view>
  45. <view class="swiper-desc">{{item.desc}}</view>
  46. </view>
  47. </view>
  48. </template>
  49. </uv-swiper>
  50. </view>
  51. <!-- 通知区域 -->
  52. <view class="notice" @click="viewNotice">
  53. <view class="notice-left">
  54. <view class="notice-icon">
  55. <image src="/static/image/home/notice.png" mode="aspectFill"></image>
  56. </view>
  57. <view class="">
  58. 全部共告
  59. </view>
  60. </view>
  61. <view class="notice-center">
  62. <view class="notice-tag">{{noticeList.title}}</view>
  63. <view class="notice-text" @click="viewNotice">
  64. {{ noticeList.titleText }}
  65. </view>
  66. </view>
  67. <view class="notice-right">
  68. <uv-icon name="arrow-right" color="#999" size="24rpx"></uv-icon>
  69. </view>
  70. </view>
  71. <!-- 最近更新 -->
  72. <view class="section">
  73. <view class="section-header">
  74. <text class="section-title">最近更新</text>
  75. </view>
  76. <scroll-view scroll-x style="width: 100%;">
  77. <view class="recommend-list">
  78. <view class="recommend-item"
  79. @click="navigateToDetail(item.id)"
  80. v-for="(item, index) in novelList" :key="index">
  81. <novel-item horizontal :key="index" :book="item" />
  82. </view>
  83. </view>
  84. </scroll-view>
  85. </view>
  86. </view>
  87. <!-- 精品推荐 -->
  88. <view class="section1">
  89. <view class="section-header">
  90. <text class="section-title">精品推荐</text>
  91. <text class="section-more" @click="$utils.navigateTo('/pages/index/category')">查看更多 ></text>
  92. </view>
  93. <view class="novel-list">
  94. <novel-item v-for="(item, index) in novelList"
  95. @click="navigateToDetail(item.id)"
  96. :key="index" :book="item" />
  97. </view>
  98. </view>
  99. <PrivacyAgreementPoup />
  100. <tabber select="home" />
  101. </view>
  102. </template>
  103. <script>
  104. import PrivacyAgreementPoup from '@/components/config/PrivacyAgreementPoup.vue'
  105. import tabber from '@/components/base/tabbar.vue'
  106. import novelItem from '@/components/novel/novelItem.vue'
  107. import mixinsList from '@/mixins/list.js'
  108. import {
  109. mapGetters
  110. } from 'vuex'
  111. export default {
  112. components: {
  113. tabber,
  114. PrivacyAgreementPoup,
  115. novelItem,
  116. },
  117. mixins: [mixinsList],
  118. data() {
  119. return {
  120. // 轮播图数据
  121. bannerList: [],
  122. // 最近更新小说列表数据
  123. novelList: [],
  124. // 公告数据
  125. noticeList: {},
  126. // 精品小说列表
  127. mixinsListApi : 'getRecommendList',
  128. }
  129. },
  130. computed: {},
  131. onShow() {
  132. this.getBanner()
  133. this.getNotice()
  134. this.getNewList()
  135. },
  136. methods: {
  137. // 跳转到搜索页面
  138. toSearch() {
  139. this.$utils.navigateTo('/pages/search/index')
  140. },
  141. // 点击轮播图
  142. clickBanner(index) {
  143. // const banner = this.bannerList[index];
  144. // console.log('点击了轮播图:', banner.title);
  145. // // 跳转到小说详情页
  146. // uni.showToast({
  147. // title: '正在前往: ' + banner.title,
  148. // icon: 'none'
  149. // })
  150. // setTimeout(() => {
  151. // this.$utils.navigateTo(`/pages_order/book/bookDetail?id=${banner.id}`)
  152. // }, 500)
  153. },
  154. // 查看公告详情
  155. viewNotice() {
  156. uni.navigateTo({
  157. url: '/pages_order/announcement/announcements'
  158. })
  159. },
  160. navigateToDetail(id) {
  161. // 跳转到小说详情页
  162. this.$utils.navigateTo(`/pages_order/novel/novelDetail?id=${id}`)
  163. },
  164. async getBanner() {
  165. const data = await this.$fetch('getBanner')
  166. this.bannerList = data
  167. },
  168. // 获取公告列表
  169. async getNotice() {
  170. const data = await this.$fetch('getNotice')
  171. this.noticeList = data
  172. },
  173. // 获取最近更新小说列表
  174. async getNewList() {
  175. const data = await this.$fetch('getNewList')
  176. this.novelList = data
  177. },
  178. }
  179. }
  180. </script>
  181. <style scoped lang="scss">
  182. .page {
  183. background-color: #f5f5f5;
  184. // min-height: 100vh;
  185. /* 自定义导航栏样式 */
  186. .custom-navbar {
  187. display: flex;
  188. align-items: center;
  189. justify-content: space-between;
  190. padding: 0 20rpx 20rpx 20rpx;
  191. background-color: #001351; /* 深蓝色背景 */
  192. height: 160rpx;
  193. box-sizing: border-box;
  194. position: sticky;
  195. top: 0;
  196. z-index: 99;
  197. padding-top: calc(var(--status-bar-height) + 20rpx);
  198. .navbar-left {
  199. width: 80rpx;
  200. display: flex;
  201. justify-content: center;
  202. .calendar-icon {
  203. width: 50rpx;
  204. height: 50rpx;
  205. display: flex;
  206. align-items: center;
  207. justify-content: center;
  208. }
  209. }
  210. .navbar-center {
  211. flex: 1;
  212. margin: 0 20rpx;
  213. .search-box {
  214. display: flex;
  215. align-items: center;
  216. background-color: rgba(255, 255, 255, 0.95);
  217. border-radius: 40rpx;
  218. padding: 0 30rpx;
  219. height: 70rpx;
  220. box-sizing: border-box;
  221. .search-placeholder {
  222. color: #999;
  223. font-size: 28rpx;
  224. margin-left: 16rpx;
  225. }
  226. }
  227. }
  228. .navbar-right {
  229. display: flex;
  230. align-items: center;
  231. .function-btn {
  232. margin-left: 16rpx;
  233. width: 50rpx;
  234. height: 50rpx;
  235. display: flex;
  236. justify-content: center;
  237. align-items: center;
  238. }
  239. }
  240. }
  241. .content {
  242. padding-bottom: 5rpx;
  243. }
  244. .banner {
  245. padding: 0;
  246. margin: 20rpx;
  247. border-radius: 10rpx;
  248. overflow: hidden;
  249. box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
  250. transition: all 0.3s;
  251. &:active {
  252. transform: scale(0.98);
  253. }
  254. .swiper-item {
  255. position: relative;
  256. width: 100%;
  257. height: 100%;
  258. .swiper-image {
  259. width: 100%;
  260. height: 100%;
  261. border-radius: 10rpx;
  262. }
  263. .swiper-content {
  264. position: absolute;
  265. bottom: 0;
  266. left: 0;
  267. width: 100%;
  268. padding: 30rpx;
  269. background: linear-gradient(to top, rgba(0,0,0,0.8), rgba(0,0,0,0.3), transparent);
  270. border-bottom-left-radius: 10rpx;
  271. border-bottom-right-radius: 10rpx;
  272. .swiper-title {
  273. font-size: 36rpx;
  274. color: #fff;
  275. font-weight: bold;
  276. margin-bottom: 10rpx;
  277. text-shadow: 0 2rpx 4rpx rgba(0,0,0,0.5);
  278. }
  279. .swiper-desc {
  280. font-size: 28rpx;
  281. color: rgba(255,255,255,0.9);
  282. line-height: 1.4;
  283. text-shadow: 0 1rpx 3rpx rgba(0,0,0,0.5);
  284. }
  285. }
  286. }
  287. }
  288. .notice {
  289. display: flex;
  290. align-items: center;
  291. background-color: #fff;
  292. margin: 20rpx;
  293. margin-bottom: 0;
  294. padding: 20rpx;
  295. border-radius: 10rpx;
  296. box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.05);
  297. transition: all 0.2s;
  298. &:active {
  299. background-color: #f9f9f9;
  300. }
  301. .notice-left {
  302. display: flex;
  303. align-items: center;
  304. margin-right: 20rpx;
  305. flex-direction: column;
  306. font-size: 22rpx;
  307. width: 90rpx;
  308. justify-content: center;
  309. .notice-icon {
  310. width: 60rpx;
  311. height: 60rpx;
  312. border-radius: 30rpx;
  313. overflow: hidden;
  314. box-shadow: 0 2rpx 6rpx rgba(0,0,0,0.1);
  315. image {
  316. width: 100%;
  317. height: 100%;
  318. }
  319. }
  320. }
  321. .notice-center {
  322. flex: 1;
  323. .notice-tag {
  324. font-size: 22rpx;
  325. color: #666;
  326. background-color: #f5f5f5;
  327. padding: 4rpx 12rpx;
  328. border-radius: 6rpx;
  329. margin-right: 10rpx;
  330. width: fit-content;
  331. margin-bottom: 10rpx;
  332. }
  333. .notice-text {
  334. font-size: 26rpx;
  335. color: #333;
  336. overflow: hidden;
  337. white-space: nowrap;
  338. text-overflow: ellipsis;
  339. }
  340. }
  341. .notice-right {
  342. margin-left: 20rpx;
  343. opacity: 0.6;
  344. }
  345. }
  346. .section {
  347. background-color: #fff;
  348. margin: 30rpx 0 0 0;
  349. padding: 10rpx 30rpx;
  350. border-radius: 0;
  351. .section-header {
  352. display: flex;
  353. justify-content: space-between;
  354. align-items: center;
  355. margin-bottom: 20rpx;
  356. .section-title {
  357. font-size: 32rpx;
  358. font-weight: bold;
  359. color: #333;
  360. }
  361. .section-more {
  362. font-size: 24rpx;
  363. color: #999;
  364. }
  365. }
  366. .novel-list {
  367. .novel-item {
  368. display: flex;
  369. padding: 20rpx 0;
  370. border-bottom: 1px solid #eee;
  371. &:last-child {
  372. border-bottom: none;
  373. }
  374. .novel-cover {
  375. width: 160rpx;
  376. height: 200rpx;
  377. border-radius: 8rpx;
  378. margin-right: 20rpx;
  379. }
  380. .novel-info {
  381. flex: 1;
  382. display: flex;
  383. flex-direction: column;
  384. justify-content: space-between;
  385. .novel-title {
  386. font-size: 28rpx;
  387. font-weight: bold;
  388. color: #333;
  389. margin-bottom: 10rpx;
  390. }
  391. .novel-desc {
  392. font-size: 24rpx;
  393. color: #999;
  394. line-height: 1.5;
  395. display: -webkit-box;
  396. -webkit-box-orient: vertical;
  397. -webkit-line-clamp: 3;
  398. overflow: hidden;
  399. }
  400. }
  401. }
  402. }
  403. .recommend-list {
  404. display: flex;
  405. .recommend-item {
  406. width: fit-content;
  407. }
  408. }
  409. }
  410. .section1 {
  411. background-color: #fff;
  412. margin: 0rpx 0 0 0;
  413. padding: 20rpx 30rpx;
  414. border-radius: 0;
  415. .section-header {
  416. display: flex;
  417. justify-content: space-between;
  418. align-items: center;
  419. margin-bottom: 20rpx;
  420. .section-title {
  421. font-size: 32rpx;
  422. font-weight: bold;
  423. color: #333;
  424. }
  425. .section-more {
  426. font-size: 24rpx;
  427. color: #999;
  428. }
  429. }
  430. .novel-list {
  431. .novel-item {
  432. display: flex;
  433. padding: 20rpx 0;
  434. border-bottom: 1px solid #eee;
  435. &:last-child {
  436. border-bottom: none;
  437. }
  438. .novel-cover {
  439. width: 160rpx;
  440. height: 200rpx;
  441. border-radius: 8rpx;
  442. margin-right: 20rpx;
  443. }
  444. .novel-info {
  445. flex: 1;
  446. display: flex;
  447. flex-direction: column;
  448. justify-content: space-between;
  449. .novel-title {
  450. font-size: 28rpx;
  451. font-weight: bold;
  452. color: #333;
  453. margin-bottom: 10rpx;
  454. }
  455. .novel-desc {
  456. font-size: 24rpx;
  457. color: #999;
  458. line-height: 1.5;
  459. display: -webkit-box;
  460. -webkit-box-orient: vertical;
  461. -webkit-line-clamp: 3;
  462. overflow: hidden;
  463. }
  464. }
  465. }
  466. }
  467. .recommend-list {
  468. display: flex;
  469. flex-wrap: wrap;
  470. justify-content: space-between;
  471. .recommend-item {
  472. width: 30%;
  473. margin-bottom: 20rpx;
  474. .recommend-cover {
  475. width: 100%;
  476. height: 200rpx;
  477. border-radius: 8rpx;
  478. margin-bottom: 10rpx;
  479. }
  480. .recommend-title {
  481. font-size: 24rpx;
  482. color: #333;
  483. overflow: hidden;
  484. white-space: nowrap;
  485. text-overflow: ellipsis;
  486. }
  487. }
  488. }
  489. }
  490. }
  491. </style>