detail.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999
  1. <template>
  2. <view class="container">
  3. <!-- H5环境自定义导航栏 -->
  4. <view class="h5-custom-navbar" v-if="isH5">
  5. <view class="h5-navbar-left" @click="goBack">
  6. <view class="h5-back-icon">
  7. <view class="h5-arrow-left"></view>
  8. </view>
  9. </view>
  10. <text class="h5-navbar-title">农业知识</text>
  11. <view class="h5-navbar-right"></view>
  12. </view>
  13. <!-- 文章内容区 -->
  14. <view class="article-container" :style="isH5 ? 'margin-top: 90rpx;' : ''">
  15. <!-- 加载状态显示 -->
  16. <view class="loading-container" v-if="loading">
  17. <view class="loading-spinner"></view>
  18. <text class="loading-text">加载中...</text>
  19. </view>
  20. <!-- 内容区域 -->
  21. <block v-else>
  22. <!-- 封面图轮播 -->
  23. <swiper class="cover-swiper"
  24. indicator-dots
  25. autoplay
  26. circular
  27. interval="3000"
  28. duration="500"
  29. indicator-active-color="#4CAF50"
  30. indicator-color="rgba(255,255,255,0.5)"
  31. @change="handleSwiperChange">
  32. <!-- 有实际图片时展示 -->
  33. <swiper-item v-for="(slide, index) in articleImages" :key="slide.id" v-if="articleImages.length > 0">
  34. <view class="swiper-item-container" :style="{ backgroundColor: slide.color || '#4CAF50' }">
  35. <image class="swiper-image" :src="slide.url" mode="aspectFill" v-if="slide.url"></image>
  36. <view class="pattern-overlay"></view>
  37. <view class="swiper-overlay">
  38. <text class="swiper-title">{{ slide.title || articleInfo.title }}</text>
  39. <text class="swiper-subtitle">{{ slide.subtitle || '' }}</text>
  40. </view>
  41. </view>
  42. </swiper-item>
  43. <!-- 没有图片时使用生成的轮播图 -->
  44. <swiper-item v-for="(slide, index) in carouselImages" :key="slide.id" v-if="articleImages.length === 0">
  45. <view class="swiper-item-container" :style="{ backgroundColor: slide.color || '#4CAF50' }">
  46. <view class="pattern-overlay"></view>
  47. <view class="agri-icon" v-html="slide.icon"></view>
  48. <view class="swiper-overlay">
  49. <text class="swiper-title">{{ slide.title || articleInfo.title }}</text>
  50. <text class="swiper-subtitle">{{ slide.subtitle || '' }}</text>
  51. </view>
  52. </view>
  53. </swiper-item>
  54. </swiper>
  55. <view class="swiper-counter" v-if="(articleImages.length > 0 && articleImages.length > 1) || (articleImages.length === 0 && carouselImages.length > 0)">
  56. <text>{{ currentSwiperIndex + 1 }}/{{ articleImages.length > 0 ? articleImages.length : carouselImages.length }}</text>
  57. </view>
  58. <!-- 标题及元信息 -->
  59. <view class="article-header">
  60. <text class="article-title">{{ articleInfo.title }}</text>
  61. <view class="article-meta">
  62. <text class="source">{{ articleInfo.source }}</text>
  63. <text class="dot">·</text>
  64. <text class="date">{{ formatDate(articleInfo.publishDate) }}</text>
  65. <view class="views">
  66. <!-- <text class="view-icon">&#xe614;</text> -->
  67. <image src="../../static/icons/yidu.png" mode="aspectFit"></image>
  68. <text class="view-count">{{ articleInfo.viewCount }}</text>
  69. </view>
  70. </view>
  71. </view>
  72. <!-- 文章正文 -->
  73. <view class="article-content">
  74. <!-- 如果有HTML内容则渲染HTML内容 -->
  75. <rich-text v-if="articleInfo.content" :nodes="processHtmlContent(articleInfo.content)"></rich-text>
  76. <!-- 无内容时的备用内容 -->
  77. <view v-else class="content-section">
  78. <text class="paragraph">
  79. 暂无详细内容
  80. </text>
  81. </view>
  82. </view>
  83. <!-- 视频示例 -->
  84. <view class="video-container" v-if="articleInfo.contentType === 'video' && articleInfo.videoUrl">
  85. <video
  86. class="article-video"
  87. :src="articleInfo.videoUrl"
  88. autoplay=true
  89. controls
  90. object-fit="contain"
  91. poster=""
  92. ></video>
  93. <text class="video-title">{{ articleInfo.title }}</text>
  94. </view>
  95. <!-- 视频预览 -->
  96. <view class="video-container" v-else-if="articleInfo.contentType === 'video'">
  97. <view class="video-poster">
  98. <view class="video-color-bg" style="background-color: #33691E;">
  99. <view class="video-pattern"></view>
  100. <text class="video-label">视频教学</text>
  101. </view>
  102. <view class="play-button">
  103. <view class="triangle-play"></view>
  104. </view>
  105. <text class="video-duration">{{ articleInfo.duration || '00:00' }}</text>
  106. </view>
  107. <text class="video-title">{{ articleInfo.title }}</text>
  108. </view>
  109. </block>
  110. </view>
  111. <!-- 底部功能区 -->
  112. <!-- <view class="footer-action" v-if="!loading">
  113. <view class="action-button like" @click="handleLike">
  114. <view class="action-icon-wrapper">
  115. <text v-if="articleInfo.isLiked" class="material-icon">&#xe87d;</text>
  116. <text v-else class="material-icon">&#xe87e;</text>
  117. </view>
  118. <text class="action-text">{{ articleInfo.isLiked ? '已点赞' : '点赞' }}</text>
  119. </view>
  120. <view class="action-button collect" @click="handleCollect">
  121. <view class="action-icon-wrapper">
  122. <text v-if="articleInfo.isFavorite" class="material-icon">&#xe838;</text>
  123. <text v-else class="material-icon">&#xe83a;</text>
  124. </view>
  125. <text class="action-text">{{ articleInfo.isFavorite ? '已收藏' : '收藏' }}</text>
  126. </view>
  127. <view class="action-button share" @click="handleShare">
  128. <view class="action-icon-wrapper">
  129. <text class="material-icon">&#xe80d;</text>
  130. </view>
  131. <text class="action-text">分享</text>
  132. </view>
  133. </view> -->
  134. <!-- 返回顶部 -->
  135. <view class="back-to-top" @click="scrollToTop">
  136. <view class="top-arrow"></view>
  137. <text class="top-text">顶部</text>
  138. </view>
  139. </view>
  140. </template>
  141. <script>
  142. import { getArticleDetail, getArticleImages, likeArticle, unlikeArticle, favoriteArticle, unfavoriteArticle } from '@/api/services/knowledge.js';
  143. import api from "@/config/api.js";
  144. export default {
  145. data() {
  146. return {
  147. baseUrl:api.im,
  148. title: "农业知识",
  149. // 文章ID
  150. id: null,
  151. // 文章类型
  152. type: null,
  153. // 加载状态
  154. loading: true,
  155. // 文章信息
  156. articleInfo: {
  157. id: '',
  158. title: '',
  159. source: '',
  160. publishDate: '',
  161. viewCount: 0,
  162. content: '',
  163. contentType: 'article',
  164. videoUrl: '',
  165. duration: '',
  166. isLiked: false,
  167. isFavorite: false
  168. },
  169. // 文章相关图片
  170. articleImages: [],
  171. // 轮播图(当没有真实图片时使用)
  172. carouselImages: [],
  173. currentSwiperIndex: 0,
  174. isH5: false // 是否是H5环境
  175. }
  176. },
  177. onLoad(options) {
  178. console.log("this...",this.baseUrl);
  179. console.log("process.env.NODE_ENV",process.env.NODE_ENV);
  180. // 检测是否在H5环境中运行
  181. // #ifdef H5
  182. this.isH5 = true;
  183. // #endif
  184. // 设置导航栏标题
  185. uni.setNavigationBarTitle({
  186. title: '农业知识'
  187. });
  188. // 获取参数
  189. this.id = options.id;
  190. this.type = options.type;
  191. // 加载文章详情
  192. this.loadArticleDetail();
  193. },
  194. onNavigationBarButtonTap(e) {
  195. if (e.index === 0) {
  196. this.goBack();
  197. }
  198. },
  199. methods: {
  200. // 加载文章详情
  201. async loadArticleDetail() {
  202. if (!this.id) {
  203. uni.showToast({
  204. title: '文章ID不能为空',
  205. icon: 'none'
  206. });
  207. return;
  208. }
  209. try {
  210. this.loading = true;
  211. const result = await getArticleDetail(this.id);
  212. if (result.data.code === 200 && result.data.data) {
  213. // 设置文章信息
  214. this.articleInfo = result.data.data;
  215. this.articleInfo.videoUrl = this.baseUrl + result.data.data.videoUrl
  216. // 加载文章相关图片
  217. await this.loadArticleImages();
  218. // 如果没有相关图片,生成默认轮播图数据
  219. if (this.articleImages.length === 0) {
  220. this.generateCarouselImages();
  221. }
  222. } else {
  223. uni.showToast({
  224. title: result.data.msg || '获取文章详情失败',
  225. icon: 'none'
  226. });
  227. }
  228. } catch (error) {
  229. console.error('获取文章详情失败:', error);
  230. uni.showToast({
  231. title: '网络异常,请稍后重试',
  232. icon: 'none'
  233. });
  234. } finally {
  235. this.loading = false;
  236. }
  237. },
  238. // 加载文章相关图片
  239. async loadArticleImages() {
  240. try {
  241. const result = await getArticleImages(this.id);
  242. if (result.data.code === 200 && result.data.data) {
  243. this.articleImages = result.data.data;
  244. } else {
  245. console.log('获取文章图片失败:', result.data.msg);
  246. this.articleImages = [];
  247. }
  248. } catch (error) {
  249. console.error('获取文章图片失败:', error);
  250. this.articleImages = [];
  251. }
  252. },
  253. // 生成默认轮播图数据
  254. generateCarouselImages() {
  255. // 如果没有内容,生成基于文章类型和内容的默认轮播图
  256. const colors = ['#8BC34A', '#4CAF50', '#7CB342', '#689F38', '#33691E'];
  257. const icons = [
  258. '<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2zm0 18a8 8 0 1 1 8-8 8 8 0 0 1-8 8z"></path><path d="M12 6a1 1 0 0 0-1 1v5a1 1 0 0 0 .55.89l4 2a1 1 0 0 0 .9-1.78L13 11.28V7a1 1 0 0 0-1-1z"></path></svg>',
  259. '<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12h-4 M17 12l-3-3 M17 12l-3 3 M3 6h10 M13 6l-3-3 M13 6l-3 3 M3 18h10 M13 18l-3-3 M13 18l-3 3"></path></svg>',
  260. '<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"></path><path d="M18.5 3a2.5 2.5 0 0 1 0 5H12v6.5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V9"></path></svg>',
  261. ];
  262. // 根据文章类型生成不同的默认轮播图
  263. let subtitles = [];
  264. if (this.type === 'tech') {
  265. subtitles = ['科学种植技术', '提高农作物产量', '农业技术创新', '绿色生态农业'];
  266. } else {
  267. subtitles = ['政策解读要点', '补贴申请指南', '农业发展方向', '乡村振兴战略'];
  268. }
  269. // 生成3个轮播图
  270. this.carouselImages = [];
  271. for (let i = 0; i < 3; i++) {
  272. this.carouselImages.push({
  273. color: colors[i % colors.length],
  274. title: this.articleInfo.title,
  275. subtitle: subtitles[i % subtitles.length],
  276. icon: icons[i % icons.length]
  277. });
  278. }
  279. },
  280. // 格式化日期
  281. formatDate(dateStr) {
  282. if (!dateStr) return '';
  283. const date = new Date(dateStr);
  284. return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
  285. },
  286. // 返回上一页
  287. goBack() {
  288. uni.navigateBack();
  289. },
  290. // 滚动到顶部
  291. scrollToTop() {
  292. uni.pageScrollTo({
  293. scrollTop: 0,
  294. duration: 300
  295. });
  296. },
  297. // 点赞/取消点赞
  298. async handleLike() {
  299. try {
  300. if (this.articleInfo.isLiked) {
  301. // 已点赞,执行取消点赞
  302. const result = await unlikeArticle(this.id);
  303. if (result.data.code === 200) {
  304. this.articleInfo.isLiked = false;
  305. uni.showToast({
  306. title: '取消点赞成功',
  307. icon: 'none'
  308. });
  309. }
  310. } else {
  311. // 未点赞,执行点赞
  312. const result = await likeArticle(this.id);
  313. if (result.data.code === 200) {
  314. this.articleInfo.isLiked = true;
  315. uni.showToast({
  316. title: '点赞成功',
  317. icon: 'none'
  318. });
  319. }
  320. }
  321. } catch (error) {
  322. console.error('操作失败:', error);
  323. if (error.response && error.response.status === 401) {
  324. uni.showToast({
  325. title: '请先登录',
  326. icon: 'none'
  327. });
  328. } else {
  329. uni.showToast({
  330. title: '网络异常,请稍后重试',
  331. icon: 'none'
  332. });
  333. }
  334. }
  335. },
  336. // 收藏/取消收藏
  337. async handleCollect() {
  338. try {
  339. if (this.articleInfo.isFavorite) {
  340. // 已收藏,执行取消收藏
  341. const result = await unfavoriteArticle(this.id);
  342. if (result.data.code === 200) {
  343. this.articleInfo.isFavorite = false;
  344. uni.showToast({
  345. title: '取消收藏成功',
  346. icon: 'none'
  347. });
  348. }
  349. } else {
  350. // 未收藏,执行收藏
  351. const result = await favoriteArticle(this.id);
  352. if (result.data.code === 200) {
  353. this.articleInfo.isFavorite = true;
  354. uni.showToast({
  355. title: '收藏成功',
  356. icon: 'none'
  357. });
  358. }
  359. }
  360. } catch (error) {
  361. console.error('操作失败:', error);
  362. if (error.response && error.response.status === 401) {
  363. uni.showToast({
  364. title: '请先登录',
  365. icon: 'none'
  366. });
  367. } else {
  368. uni.showToast({
  369. title: '网络异常,请稍后重试',
  370. icon: 'none'
  371. });
  372. }
  373. }
  374. },
  375. // 分享
  376. handleShare() {
  377. uni.showShareMenu({
  378. withShareTicket: true,
  379. menus: ['shareAppMessage', 'shareTimeline']
  380. });
  381. },
  382. // 处理轮播图切换
  383. handleSwiperChange(e) {
  384. this.currentSwiperIndex = e.detail.current;
  385. },
  386. // 处理HTML内容
  387. processHtmlContent(content) {
  388. if (!content) return '';
  389. // 确保内容是字符串
  390. let htmlContent = content.toString();
  391. // 如果内容不是HTML格式,尝试解析
  392. if (!htmlContent.includes('<div class="content-section">')) {
  393. try {
  394. // 尝试解码可能被转义的HTML
  395. htmlContent = htmlContent.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&amp;/g, '&');
  396. } catch (e) {
  397. console.error('HTML内容格式化失败:', e);
  398. }
  399. }
  400. return htmlContent;
  401. }
  402. }
  403. }
  404. </script>
  405. <style>
  406. /* 字体图标 */
  407. @font-face {
  408. font-family: 'iconfont';
  409. src: url('https://at.alicdn.com/t/font_3442238_cosd6rj55jg.ttf') format('truetype');
  410. }
  411. @font-face {
  412. font-family: 'Material Icons';
  413. font-style: normal;
  414. font-weight: 400;
  415. src: url(https://fonts.gstatic.com/s/materialicons/v139/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
  416. }
  417. .icon, .view-icon, .play-icon, .action-icon, .top-icon {
  418. font-family: 'iconfont';
  419. }
  420. .material-icon {
  421. font-family: 'Material Icons';
  422. font-weight: normal;
  423. font-style: normal;
  424. font-size: 50rpx;
  425. line-height: 1;
  426. letter-spacing: normal;
  427. text-transform: none;
  428. display: inline-block;
  429. white-space: nowrap;
  430. word-wrap: normal;
  431. direction: ltr;
  432. -webkit-font-smoothing: antialiased;
  433. color: #4CAF50;
  434. }
  435. /* 容器样式 */
  436. .container {
  437. background-color: #f8f8f8;
  438. min-height: 100vh;
  439. position: relative;
  440. padding-bottom: 120rpx;
  441. }
  442. /* 删除自定义导航栏样式 */
  443. .custom-navbar {
  444. display: none;
  445. }
  446. .navbar-left, .back-icon, .navbar-title, .navbar-right, .arrow-left {
  447. display: none;
  448. }
  449. /* 文章容器 */
  450. .article-container {
  451. background-color: #fff;
  452. border-radius: 0;
  453. overflow: hidden;
  454. }
  455. /* 封面图轮播 */
  456. .cover-swiper {
  457. width: 100%;
  458. height: 420rpx;
  459. position: relative;
  460. }
  461. .swiper-item-container {
  462. position: relative;
  463. width: 100%;
  464. height: 100%;
  465. display: flex;
  466. align-items: center;
  467. justify-content: center;
  468. border-radius: 0;
  469. }
  470. .swiper-image {
  471. width: 100%;
  472. height: 100%;
  473. display: block;
  474. object-fit: cover;
  475. }
  476. .swiper-overlay {
  477. position: absolute;
  478. bottom: 0;
  479. left: 0;
  480. right: 0;
  481. padding: 40rpx 30rpx;
  482. background: linear-gradient(to top, rgba(0,0,0,0.7), rgba(0,0,0,0));
  483. display: flex;
  484. flex-direction: column;
  485. justify-content: flex-end;
  486. align-items: flex-start;
  487. color: #fff;
  488. }
  489. .swiper-title {
  490. font-size: 42rpx;
  491. font-weight: bold;
  492. margin-bottom: 10rpx;
  493. text-shadow: 0 2px 4px rgba(0,0,0,0.5);
  494. }
  495. .swiper-subtitle {
  496. font-size: 28rpx;
  497. opacity: 0.9;
  498. text-shadow: 0 1px 2px rgba(0,0,0,0.5);
  499. }
  500. /* 文章头部信息 */
  501. .article-header {
  502. padding: 30rpx 30rpx 0;
  503. }
  504. .article-title {
  505. font-size: 42rpx;
  506. font-weight: bold;
  507. color: #333;
  508. line-height: 1.4;
  509. margin-bottom: 20rpx;
  510. }
  511. .article-meta {
  512. display: flex;
  513. align-items: center;
  514. margin-bottom: 40rpx;
  515. }
  516. .source {
  517. font-size: 24rpx;
  518. color: #666;
  519. }
  520. .dot {
  521. margin: 0 10rpx;
  522. color: #999;
  523. }
  524. .date {
  525. font-size: 24rpx;
  526. color: #999;
  527. }
  528. .views {
  529. margin-left: auto;
  530. display: flex;
  531. align-items: center;
  532. }
  533. .views image {
  534. padding-right: 6px;
  535. width: 16px; /* 设置图标宽度 */
  536. height: 16px; /* 设置图标高度 */
  537. vertical-align: middle;
  538. }
  539. .view-icon {
  540. font-size: 24rpx;
  541. color: #999;
  542. margin-right: 6rpx;
  543. }
  544. .view-count {
  545. font-size: 24rpx;
  546. color: #999;
  547. }
  548. /* 文章内容 */
  549. .article-content {
  550. padding: 0 30rpx 40rpx;
  551. }
  552. .content-section {
  553. margin-bottom: 40rpx;
  554. }
  555. .section-title {
  556. font-size: 34rpx;
  557. font-weight: bold;
  558. color: #2e7d32;
  559. margin-bottom: 20rpx;
  560. display: block;
  561. }
  562. .paragraph {
  563. font-size: 30rpx;
  564. line-height: 1.8;
  565. color: #333;
  566. margin-bottom: 20rpx;
  567. display: block;
  568. }
  569. .content-image {
  570. width: 100%;
  571. margin: 20rpx 0;
  572. border-radius: 12rpx;
  573. }
  574. .image-caption {
  575. font-size: 24rpx;
  576. color: #999;
  577. text-align: center;
  578. display: block;
  579. margin-top: 10rpx;
  580. }
  581. /* 注意事项盒子 */
  582. .note-box {
  583. background-color: #f1f8e9;
  584. border-left: 8rpx solid #8bc34a;
  585. padding: 20rpx;
  586. border-radius: 8rpx;
  587. margin: 20rpx 0;
  588. }
  589. .note-title {
  590. font-size: 28rpx;
  591. font-weight: bold;
  592. color: #558b2f;
  593. margin-bottom: 10rpx;
  594. display: block;
  595. }
  596. .note-content {
  597. font-size: 26rpx;
  598. line-height: 1.6;
  599. color: #689f38;
  600. display: block;
  601. }
  602. /* 视频容器 */
  603. .video-container {
  604. margin: 0 30rpx 40rpx;
  605. border-radius: 0;
  606. overflow: hidden;
  607. background-color: #fff;
  608. }
  609. .article-video {
  610. width: 100%;
  611. height: 500rpx;
  612. }
  613. .video-poster {
  614. position: relative;
  615. width: 100%;
  616. height: 380rpx;
  617. }
  618. .video-color-bg {
  619. position: absolute;
  620. top: 0;
  621. left: 0;
  622. right: 0;
  623. bottom: 0;
  624. display: flex;
  625. align-items: center;
  626. justify-content: center;
  627. border-radius: 0;
  628. }
  629. .video-pattern {
  630. position: absolute;
  631. top: 0;
  632. left: 0;
  633. right: 0;
  634. bottom: 0;
  635. opacity: 0.1;
  636. background-image:
  637. linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%,
  638. rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);
  639. background-size: 50px 50px;
  640. }
  641. .video-label {
  642. color: white;
  643. font-size: 32rpx;
  644. font-weight: bold;
  645. text-shadow: 0 2px 4px rgba(0,0,0,0.5);
  646. z-index: 5;
  647. }
  648. .play-button {
  649. position: absolute;
  650. top: 50%;
  651. left: 50%;
  652. transform: translate(-50%, -50%);
  653. width: 120rpx;
  654. height: 120rpx;
  655. background-color: rgba(0, 0, 0, 0.6);
  656. border-radius: 50%;
  657. display: flex;
  658. align-items: center;
  659. justify-content: center;
  660. z-index: 10;
  661. box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.3);
  662. border: 4rpx solid rgba(255, 255, 255, 0.8);
  663. }
  664. .triangle-play {
  665. width: 0;
  666. height: 0;
  667. border-top: 26rpx solid transparent;
  668. border-bottom: 26rpx solid transparent;
  669. border-left: 40rpx solid #fff;
  670. margin-left: 10rpx;
  671. }
  672. .video-duration {
  673. position: absolute;
  674. bottom: 20rpx;
  675. right: 20rpx;
  676. padding: 6rpx 12rpx;
  677. background-color: rgba(0, 0, 0, 0.6);
  678. color: #fff;
  679. font-size: 22rpx;
  680. border-radius: 4rpx;
  681. }
  682. .video-title {
  683. font-size: 28rpx;
  684. font-weight: bold;
  685. color: #333;
  686. padding: 20rpx;
  687. display: block;
  688. }
  689. /* 底部功能区 */
  690. .footer-action {
  691. position: fixed;
  692. bottom: 0;
  693. left: 0;
  694. right: 0;
  695. height: 100rpx;
  696. background-color: #fff;
  697. display: flex;
  698. align-items: center;
  699. justify-content: space-around;
  700. box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
  701. z-index: 99;
  702. }
  703. .action-button {
  704. display: flex;
  705. flex-direction: column;
  706. align-items: center;
  707. padding: 10rpx 0;
  708. }
  709. .action-icon-wrapper {
  710. display: flex;
  711. align-items: center;
  712. justify-content: center;
  713. margin-bottom: 6rpx;
  714. }
  715. .action-text {
  716. font-size: 24rpx;
  717. color: #4CAF50;
  718. font-weight: 500;
  719. }
  720. .action-button:active {
  721. opacity: 0.7;
  722. }
  723. /* 返回顶部按钮 */
  724. .back-to-top {
  725. position: fixed;
  726. right: 30rpx;
  727. bottom: 120rpx;
  728. width: 100rpx;
  729. height: 100rpx;
  730. background-color: rgba(46, 125, 50, 0.9);
  731. border-radius: 50%;
  732. display: flex;
  733. flex-direction: column;
  734. align-items: center;
  735. justify-content: center;
  736. z-index: 99;
  737. }
  738. .top-arrow {
  739. width: 20rpx;
  740. height: 20rpx;
  741. border-top: 4rpx solid #fff;
  742. border-left: 4rpx solid #fff;
  743. transform: rotate(45deg);
  744. margin-bottom: 6rpx;
  745. }
  746. .top-text {
  747. color: #fff;
  748. font-size: 22rpx;
  749. }
  750. .swiper-counter {
  751. position: absolute;
  752. top: 110rpx;
  753. right: 30rpx;
  754. padding: 6rpx 12rpx;
  755. background-color: rgba(0, 0, 0, 0.5);
  756. color: #fff;
  757. font-size: 22rpx;
  758. border-radius: 20rpx;
  759. z-index: 10;
  760. }
  761. .pattern-overlay {
  762. position: absolute;
  763. top: 0;
  764. left: 0;
  765. right: 0;
  766. bottom: 0;
  767. opacity: 0.1;
  768. background-image:
  769. linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%,
  770. rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);
  771. background-size: 50px 50px;
  772. }
  773. .agri-icon {
  774. position: absolute;
  775. top: 40%;
  776. left: 50%;
  777. transform: translate(-50%, -50%);
  778. opacity: 0.8;
  779. width: 120rpx;
  780. height: 120rpx;
  781. z-index: 5;
  782. }
  783. .agri-icon svg {
  784. width: 100%;
  785. height: 100%;
  786. stroke-width: 1.5;
  787. }
  788. .section-image {
  789. margin: 20rpx 0;
  790. width: 100%;
  791. }
  792. .color-image {
  793. width: 100%;
  794. height: 300rpx;
  795. border-radius: 0;
  796. display: flex;
  797. align-items: center;
  798. justify-content: center;
  799. position: relative;
  800. overflow: hidden;
  801. }
  802. .color-image::before {
  803. content: "";
  804. position: absolute;
  805. top: 0;
  806. left: 0;
  807. right: 0;
  808. bottom: 0;
  809. background-image:
  810. linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%,
  811. rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);
  812. background-size: 50px 50px;
  813. opacity: 0.2;
  814. }
  815. .image-label {
  816. color: white;
  817. font-size: 32rpx;
  818. font-weight: bold;
  819. text-shadow: 0 2px 4px rgba(0,0,0,0.5);
  820. z-index: 5;
  821. }
  822. /* 删除浮动返回按钮样式 */
  823. .float-back-button, .float-back-icon {
  824. display: none;
  825. }
  826. /* H5导航栏样式 */
  827. .h5-custom-navbar {
  828. position: fixed;
  829. top: 0;
  830. left: 0;
  831. right: 0;
  832. height: 90rpx;
  833. background-color: #fff;
  834. display: flex;
  835. align-items: center;
  836. padding: 0 30rpx;
  837. z-index: 100;
  838. box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
  839. }
  840. .h5-navbar-left {
  841. width: 80rpx;
  842. height: 80rpx;
  843. display: flex;
  844. align-items: center;
  845. justify-content: center;
  846. }
  847. .h5-back-icon {
  848. font-size: 40rpx;
  849. color: #333;
  850. display: flex;
  851. align-items: center;
  852. justify-content: center;
  853. }
  854. .h5-navbar-title {
  855. flex: 1;
  856. text-align: center;
  857. font-size: 32rpx;
  858. font-weight: bold;
  859. color: #333;
  860. }
  861. .h5-navbar-right {
  862. width: 60rpx;
  863. }
  864. .h5-arrow-left {
  865. width: 24rpx;
  866. height: 24rpx;
  867. border-top: 4rpx solid #333;
  868. border-left: 4rpx solid #333;
  869. transform: rotate(-45deg);
  870. }
  871. /* 加载状态 */
  872. .loading-container {
  873. display: flex;
  874. flex-direction: column;
  875. align-items: center;
  876. justify-content: center;
  877. height: 400rpx;
  878. }
  879. .loading-spinner {
  880. width: 80rpx;
  881. height: 80rpx;
  882. border: 6rpx solid rgba(76, 175, 80, 0.2);
  883. border-radius: 50%;
  884. border-top: 6rpx solid #4CAF50;
  885. animation: spin 1s linear infinite;
  886. }
  887. @keyframes spin {
  888. 0% { transform: rotate(0deg); }
  889. 100% { transform: rotate(360deg); }
  890. }
  891. .loading-text {
  892. margin-top: 20rpx;
  893. font-size: 28rpx;
  894. color: #999;
  895. }
  896. </style>