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.

840 lines
19 KiB

1 month ago
1 month ago
1 month ago
1 month ago
  1. <template>
  2. <view class="deepMate-page">
  3. <!-- 顶部导航栏 -->
  4. <view class="header" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
  5. <view class="header-left">
  6. <image src="https://d31zlh4on95l9h.cloudfront.net/images/f91e09b5987802185e7679055dafd272.svg" class="icon"></image>
  7. </view>
  8. <view class="header-center">
  9. <text class="title">DeepMate</text>
  10. </view>
  11. <view class="header-right">
  12. <image src="https://d31zlh4on95l9h.cloudfront.net/images/d7c4e74201213a25dd9574e908233928.svg" class="icon"></image>
  13. <image src="https://d31zlh4on95l9h.cloudfront.net/images/099903c4aabf5713488b5cb60815e3f7.svg" class="icon"></image>
  14. <!-- 新增新会话按钮
  15. <button class="new-chat-button" @click="newChat">
  16. <text class="new-chat-text">新会话</text>
  17. </button> -->
  18. </view>
  19. </view>
  20. <!-- 主要内容区域 -->
  21. <view class="main-content">
  22. <view class="banner-panel" v-if="messages.length === 0">
  23. <image src="https://d31zlh4on95l9h.cloudfront.net/images/42e18bd7fe97d4f4f37aa70439a0990b.svg" class="pray-banner" mode="aspectFill" ></image>
  24. <view class="contain">
  25. <!-- 机器人头像和欢迎语 -->
  26. <view class="robot-container" v-if="messages.length === 0">
  27. <image src="https://d31zlh4on95l9h.cloudfront.net/images/61fa384381c88ad80be28f41827fe0e5.svg" class="robot-avatar"></image>
  28. <view class="welcome-message">
  29. <text class="greeting">Hi, 我是您的股市随身顾问~</text>
  30. <text class="description">个股诊断市场情绪解读都可以找我</text>
  31. </view>
  32. </view>
  33. <!-- 功能标签栏 -->
  34. <view class="function-tabs" v-if="messages.length === 0">
  35. <view ref="tabsTrack" class="tabs-track" :style="{ transform: 'translate3d(-' + marqueeOffset + 'px,0,0)' }">
  36. <view class="tab-item" v-for="(tab, idx) in marqueeList" :key="idx">{{ tab }}</view>
  37. </view>
  38. </view>
  39. <!-- 特斯拉推荐卡片 -->
  40. <view class="recommend-card" v-if="messages.length === 0">
  41. <view class="arrow" v-if="messages.length === 0"></view>
  42. <view class="card-content">
  43. <image src="../../static/images/tesla-logo.png" class="logo"></image>
  44. <view class="card-text">
  45. <text class="main-question">当前特斯拉该如何布局</text>
  46. <text class="stock-code">TSLA</text>
  47. </view>
  48. <image src="https://d31zlh4on95l9h.cloudfront.net/images/40d94054644f6e3f1c366751f07f0010.svg" class="arrow-icon" @click="goBlank"></image>
  49. </view>
  50. </view>
  51. </view>
  52. </view>
  53. <!-- 可能感兴趣的话题 -->
  54. <view v-if="messages.length === 0" class="interest-section">
  55. <text class="section-title">- 您可能感兴趣 -</text>
  56. <view class="topics-list">
  57. <view class="topic-item" v-for="topic in hotTopics" :key="topic.id">
  58. <image
  59. :src="topic.icon"
  60. class="tag-icon"
  61. ></image>
  62. <text class="topic-text" @click="sendMessageList(topic.text)">{{ topic.text }}</text>
  63. </view>
  64. </view>
  65. </view>
  66. <!-- 聊天区域 -->
  67. <view class="chat-container" v-if="messages.length > 0">
  68. <view class="message-list" id="messageList">
  69. <view
  70. v-for="(message, index) in messages"
  71. :key="index"
  72. :class="
  73. message.isUser ? 'message user-message' : 'message bot-message'
  74. "
  75. >
  76. <!-- 会话图标 -->
  77. <text
  78. :class="
  79. message.isUser
  80. ? 'fa-solid fa-user message-icon'
  81. : 'fa-solid fa-robot message-icon'
  82. "
  83. ></text>
  84. <!-- 会话内容 -->
  85. <view class="message-content">
  86. <text class="message-text">{{ message.content }}</text>
  87. <!-- loading -->
  88. <view
  89. class="loading-dots"
  90. v-if="message.isThinking || message.isTyping"
  91. >
  92. <text class="dot"></text>
  93. <text class="dot"></text>
  94. <text class="dot"></text>
  95. </view>
  96. </view>
  97. </view>
  98. </view>
  99. </view>
  100. </view>
  101. <!-- 输入框区域 -->
  102. <view class="input-area">
  103. <view class="input-wrapper">
  104. <input
  105. type="text"
  106. placeholder="请输入股票代码/名称,获取AI洞察"
  107. placeholder-style="color:#fff;opacity:1"
  108. class="input-field"
  109. v-model="inputMessage"
  110. @confirm="sendMessage"
  111. />
  112. <image class="send-button" @click="sendMessage" :disabled="isSending">
  113. <!-- <image
  114. src="https://d31zlh4on95l9h.cloudfront.net/images/95f1ea2262e9157db13c93c0dc1c5d96.svg"
  115. class="send-icon"
  116. ></image> -->
  117. </image>
  118. </view>
  119. <text class="disclaimer"
  120. >以上数据由AI生成不作为最终投资建议决策需独立</text
  121. >
  122. </view>
  123. <image class="back-to-top" src="https://d31zlh4on95l9h.cloudfront.net/images/ba357635d2bb480241952bb1cabacd73.svg" @click="scrollToTop"></image>
  124. </view>
  125. </template>
  126. <script setup>
  127. const { safeAreaInsets } = uni.getSystemInfoSync();
  128. import { ref, computed, onMounted, onUnmounted, watch, nextTick } from "vue";
  129. const inputMessage = ref("");
  130. const isSending = ref(false);
  131. const uuid = ref("");
  132. const messages = ref([]);
  133. const hotTopics = ref([
  134. {
  135. id: 1,
  136. text: '英伟达(NVDA)股票情绪温度?',
  137. icon: 'https://d31zlh4on95l9h.cloudfront.net/images/7ed58be0f4b81aeb398d9ba2534a624b.svg'
  138. },
  139. {
  140. id: 2,
  141. text: '博通(AVGO)明天还能涨吗?',
  142. icon: 'https://d31zlh4on95l9h.cloudfront.net/images/7ed58be0f4b81aeb398d9ba2534a624b.svg'
  143. },
  144. {
  145. id: 3,
  146. text: '为什么Fluence Energy(FLNC)会暴涨?',
  147. icon: 'https://d31zlh4on95l9h.cloudfront.net/images/7ed58be0f4b81aeb398d9ba2534a624b.svg'
  148. },
  149. {
  150. id: 4,
  151. text: '为什么Fluence Energy(FLNC)会暴涨?',
  152. icon: 'https://d31zlh4on95l9h.cloudfront.net/images/7ed58be0f4b81aeb398d9ba2534a624b.svg'
  153. }
  154. ]);
  155. // 新增:tabs 列表用于渲染与轮换
  156. const tabsList = ref(['个股诊断', '市场情绪温度计', '买卖时机提示', '个股']);
  157. const marqueeList = computed(() => tabsList.value.concat(tabsList.value));
  158. // 用于无缝滚动的引用与状态(兼容小程序/App)
  159. const tabsTrack = ref(null);
  160. const marqueeOffset = ref(0);
  161. let tabsTickId = 0;
  162. const marqueeSpeed = 0.6; // 像素/帧
  163. let currentThreshold = 0; // 当前第一个标签的宽度(含右外边距)
  164. let contentWidthHalf = 0; // 半宽:单份列表的总宽度
  165. // 统一 raf/caf(小程序端可能没有 rAF)
  166. const hasRAF = typeof requestAnimationFrame === 'function';
  167. const startFrame = (fn) => hasRAF ? requestAnimationFrame(fn) : setTimeout(fn, 16);
  168. const stopFrame = (id) => hasRAF ? cancelAnimationFrame(id) : clearTimeout(id);
  169. // 替换测量:测量双列表轨道总宽度的一半,避免频繁 DOM 重排
  170. const measureContentWidth = (cb) => {
  171. const q = uni.createSelectorQuery();
  172. q.select('.function-tabs .tabs-track').boundingClientRect();
  173. q.exec(res => {
  174. const rect = res && res[0];
  175. if (rect && rect.width) {
  176. contentWidthHalf = rect.width / 2;
  177. if (typeof cb === 'function') cb(contentWidthHalf);
  178. } else {
  179. setTimeout(() => measureContentWidth(cb), 16);
  180. }
  181. });
  182. };
  183. // 原 measureFirstThreshold 保留,但不再用于轮播
  184. const measureFirstThreshold = (cb) => {
  185. if (!tabsList.value.length) { currentThreshold = 0; if (cb) cb(0); return; }
  186. const q = uni.createSelectorQuery();
  187. q.selectAll('.function-tabs .tab-item').boundingClientRect();
  188. q.exec(res => {
  189. if (res && res[0] && res[0].length) {
  190. const firstRect = res[0][0];
  191. const marginRightPx = uni.upx2px(20);
  192. currentThreshold = (firstRect?.width || 0) + marginRightPx;
  193. if (typeof cb === 'function') cb(currentThreshold);
  194. } else {
  195. // 若暂时无法获取,稍后重试一次
  196. setTimeout(() => measureFirstThreshold(cb), 16);
  197. }
  198. });
  199. };
  200. const startTabsMarquee = () => {
  201. stopFrame(tabsTickId);
  202. if (tabsList.value.length <= 1) return; // 单个标签不滚动
  203. marqueeOffset.value = 0;
  204. nextTick(() => {
  205. measureContentWidth(() => {
  206. const step = () => {
  207. marqueeOffset.value += marqueeSpeed;
  208. if (contentWidthHalf > 0 && marqueeOffset.value >= contentWidthHalf) {
  209. marqueeOffset.value = 0; // 重置为 0,实现无缝循环
  210. }
  211. tabsTickId = startFrame(step);
  212. };
  213. step();
  214. });
  215. });
  216. };
  217. // 初始化
  218. onMounted(() => {
  219. initUUID();
  220. if (messages.value.length === 0) {
  221. nextTick(startTabsMarquee);
  222. }
  223. if (messages.value.length > 0) {
  224. nextTick(() => { scrollToBottom(); });
  225. }
  226. });
  227. // 当消息数量变化,控制滚动是否运行
  228. watch(messages, (val) => {
  229. if (val.length === 0) {
  230. nextTick(startTabsMarquee);
  231. } else {
  232. stopFrame(tabsTickId);
  233. }
  234. });
  235. onUnmounted(() => { stopFrame(tabsTickId); });
  236. // 初始化 UUID
  237. const initUUID = () => {
  238. let storedUUID = uni.getStorageSync('user_uuid');
  239. if (!storedUUID) {
  240. storedUUID = generateUUID();
  241. uni.setStorageSync('user_uuid', storedUUID);
  242. }
  243. uuid.value = storedUUID;
  244. };
  245. // 生成简单UUID
  246. const generateUUID = () => {
  247. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  248. var r = Math.random() * 16 | 0,
  249. v = c == 'x' ? r : (r & 0x3 | 0x8);
  250. return v.toString(16);
  251. });
  252. };
  253. // 新会话
  254. const newChat = () => {
  255. messages.value = [];
  256. uni.removeStorageSync('user_uuid');
  257. initUUID();
  258. };
  259. // 跳转到空白页
  260. const goBlank = () => {
  261. uni.navigateTo({
  262. url: '/pages/blank/blank'
  263. });
  264. };
  265. // 发送消息
  266. const sendMessage = () => {
  267. if (inputMessage.value.trim() === "" || isSending.value) return;
  268. const userMessage = {
  269. content: inputMessage.value,
  270. isUser: true,
  271. isThinking: false,
  272. isTyping: false
  273. };
  274. messages.value.push(userMessage);
  275. inputMessage.value = "";
  276. // 滚动到底部
  277. nextTick(() => {
  278. scrollToBottom();
  279. });
  280. // 模拟机器人回复
  281. simulateBotResponse(userMessage.content);
  282. };
  283. // 发送消息
  284. const sendMessageList = (listMessage) => {
  285. console.log(listMessage);
  286. const userMessage = {
  287. content: listMessage,
  288. isUser: true,
  289. isThinking: false,
  290. isTyping: false
  291. };
  292. messages.value.push(userMessage);
  293. inputMessage.value = "";
  294. // 滚动到底部
  295. nextTick(() => {
  296. scrollToBottom();
  297. });
  298. // 模拟机器人回复
  299. simulateBotResponse(userMessage.content);
  300. };
  301. // 模拟机器人回复
  302. const simulateBotResponse = (userMessage) => {
  303. isSending.value = true;
  304. // 添加机器人加载消息
  305. const botMsg = {
  306. content: "",
  307. isUser: false,
  308. isTyping: true,
  309. isThinking: false
  310. };
  311. messages.value.push(botMsg);
  312. // 滚动到底部
  313. nextTick(() => {
  314. scrollToBottom();
  315. });
  316. // 模拟流式响应
  317. let responseText = `我已经收到您的消息: "${userMessage}"。作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?`;
  318. let index = 0;
  319. const typeWriter = () => {
  320. if (index < responseText.length) {
  321. botMsg.content += responseText.charAt(index);
  322. index++;
  323. // 滚动到底部
  324. scrollToBottom();
  325. setTimeout(typeWriter, 30);
  326. } else {
  327. botMsg.isTyping = false;
  328. isSending.value = false;
  329. }
  330. };
  331. setTimeout(typeWriter, 500);
  332. };
  333. // 滚动到底部
  334. const scrollToBottom = () => {
  335. const query = uni.createSelectorQuery();
  336. query.select('#messageList').boundingClientRect();
  337. query.selectViewport().scrollOffset();
  338. query.exec((res) => {
  339. if (res[0] && res[1]) {
  340. uni.pageScrollTo({
  341. scrollTop: res[0].height,
  342. duration: 100
  343. });
  344. }
  345. });
  346. };
  347. const scrollToTop = () => {
  348. uni.pageScrollTo({ scrollTop: 0, duration: 200 });
  349. };
  350. </script>
  351. <style scoped>
  352. .deepMate-page {
  353. display: flex;
  354. flex-direction: column;
  355. height: 100vh;
  356. background-color: #ffffff;
  357. padding: 20rpx;
  358. }
  359. .header {
  360. display: flex;
  361. justify-content: space-between;
  362. align-items: center;
  363. padding: 20rpx 30rpx;
  364. background-color: #ffffff;
  365. }
  366. .header-left,
  367. .header-right {
  368. display: flex;
  369. align-items: center;
  370. }
  371. .header-left .icon,
  372. .header-right .icon {
  373. width: 40rpx;
  374. height: 40rpx;
  375. margin-right: 20rpx;
  376. }
  377. .header-center .title {
  378. font-size: 36rpx;
  379. font-weight: bold;
  380. color: #333333;
  381. }
  382. .new-chat-button {
  383. background-color: #ff6600;
  384. border: none;
  385. border-radius: 8rpx;
  386. padding: 10rpx 20rpx;
  387. }
  388. .new-chat-text {
  389. color: white;
  390. font-size: 24rpx;
  391. }
  392. .main-content {
  393. flex: 1;
  394. padding: 20rpx;
  395. overflow-y: auto;
  396. margin-top: 20rpx;
  397. margin-bottom: 120rpx;
  398. }
  399. .robot-container {
  400. display: flex;
  401. align-items: center;
  402. margin-bottom: 30rpx;
  403. }
  404. .robot-avatar {
  405. width: 130rpx;
  406. height: 130rpx;
  407. border-radius: 50%;
  408. margin-right: 10rpx;
  409. }
  410. .welcome-message {
  411. flex: 1;
  412. }
  413. .greeting {
  414. font-size: 32rpx;
  415. margin-left: 50rpx;
  416. top: 40rpx;
  417. font-weight: bold;
  418. color: #333333;
  419. line-height: 48rpx;
  420. }
  421. .description {
  422. display: block;
  423. font-size: 24rpx;
  424. color: #666666;
  425. line-height: 36rpx;
  426. margin-top: 10rpx;
  427. margin-left: 45rpx;
  428. }
  429. .function-tabs {
  430. display: block;
  431. overflow: hidden;
  432. margin-bottom: 30rpx;
  433. }
  434. .tabs-track {
  435. display: inline-flex;
  436. white-space: nowrap;
  437. will-change: transform;
  438. }
  439. .tab-item {
  440. padding: 5rpx 20rpx;
  441. border-radius: 20rpx;
  442. font-size: 20rpx;
  443. font-weight: 700;
  444. color: #666666;
  445. background-color: #fffefe;
  446. margin-right: 20rpx;
  447. transition: all 0.3s;
  448. }
  449. .tab-item.active {
  450. color: #ff6600;
  451. background-color: #fff;
  452. border: 1rpx solid #ff6600;
  453. }
  454. .recommend-card {
  455. background: url('https://d31zlh4on95l9h.cloudfront.net/images/4da1d629a55c307c3605ca15bf15189a.svg');
  456. background-repeat: no-repeat;
  457. /* border-radius: 20rpx; */
  458. padding: 40rpx;
  459. margin-bottom: 30rpx;
  460. /* box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); */
  461. }
  462. .card-content {
  463. display: flex;
  464. align-items: center;
  465. justify-content: space-between;
  466. }
  467. .logo {
  468. width: 80rpx;
  469. height: 80rpx;
  470. background-color: #ff0000;
  471. border-radius: 10rpx;
  472. display: flex;
  473. align-items: center;
  474. justify-content: center;
  475. margin-right: 20rpx;
  476. }
  477. .card-text {
  478. flex: 1;
  479. margin-left: 20rpx;
  480. }
  481. .main-question {
  482. font-size: 32rpx;
  483. color: #333333;
  484. line-height: 48rpx;
  485. }
  486. .stock-code {
  487. display: block;
  488. font-size: 24rpx;
  489. color: #ff3b30;
  490. background-color: #ffffff;
  491. padding: 2rpx 15rpx;
  492. border-radius: 12rpx;
  493. margin-top: 8rpx;
  494. width: fit-content;
  495. border: 1rpx solid #ff3b30;
  496. }
  497. .arrow-icon {
  498. background: url('https://d31zlh4on95l9h.cloudfront.net/images/40d94054644f6e3f1c366751f07f0010.svg');
  499. background-repeat: no-repeat;
  500. left: 0.5rem;
  501. top: 1.8rem;
  502. background-size: 100% 100%;
  503. width: 60rpx;
  504. height: 60rpx;
  505. }
  506. .interest-section {
  507. margin-bottom: 30rpx;
  508. }
  509. .section-title {
  510. display: block;
  511. text-align: center;
  512. font-size: 26rpx;
  513. color: #666666;
  514. margin-bottom: 20rpx;
  515. }
  516. .topics-list {
  517. display: flex;
  518. flex-direction: column;
  519. gap: 15rpx;
  520. }
  521. .topic-item {
  522. display: flex;
  523. align-items: center;
  524. padding: 15rpx 20rpx;
  525. background-color: #f0f0f0;
  526. border-radius: 15rpx;
  527. width: fit-content;
  528. }
  529. .tag-icon {
  530. width: 24rpx;
  531. height: 24rpx;
  532. margin-right: 10rpx;
  533. }
  534. .topic-text {
  535. font-size: 28rpx;
  536. color: #333333;
  537. flex: 1;
  538. }
  539. /* 聊天区域样式 */
  540. .chat-container {
  541. margin-top: 30rpx;
  542. border-radius: 10rpx;
  543. height: fit-content;
  544. /* overflow-y: auto; */
  545. }
  546. .message-list {
  547. /* padding: 20rpx; */
  548. }
  549. .message {
  550. display: flex;
  551. align-items: flex-start;
  552. margin-bottom: 30rpx;
  553. }
  554. .user-message {
  555. flex-direction: row-reverse;
  556. }
  557. .message-icon {
  558. font-size: 24rpx;
  559. margin: 0 10rpx;
  560. padding: 10rpx;
  561. border-radius: 50%;
  562. background-color: #ddd;
  563. width: 40rpx;
  564. height: 40rpx;
  565. display: flex;
  566. align-items: center;
  567. justify-content: center;
  568. }
  569. .user-message .message-icon {
  570. background-color: #007aff;
  571. color: white;
  572. }
  573. .bot-message .message-icon {
  574. background-color: #34c759;
  575. color: white;
  576. }
  577. .message-content {
  578. max-width: 70%;
  579. position: relative;
  580. }
  581. .user-message .message-content {
  582. background-color: #007aff;
  583. border-radius: 10rpx;
  584. padding: 15rpx;
  585. }
  586. .bot-message .message-content {
  587. background-color: #f0f0f0;
  588. border-radius: 10rpx;
  589. padding: 15rpx;
  590. }
  591. .message-text {
  592. font-size: 28rpx;
  593. line-height: 40rpx;
  594. }
  595. .user-message .message-text {
  596. color: white;
  597. }
  598. .bot-message .message-text {
  599. color: #333;
  600. }
  601. .loading-dots {
  602. display: flex;
  603. align-items: center;
  604. padding-top: 10rpx;
  605. }
  606. .dot {
  607. width: 10rpx;
  608. height: 10rpx;
  609. background-color: #666;
  610. border-radius: 50%;
  611. margin: 0 4rpx;
  612. animation: loading 1.4s infinite ease-in-out both;
  613. }
  614. .user-message .dot {
  615. background-color: white;
  616. }
  617. .dot:nth-child(1) {
  618. animation-delay: -0.32s;
  619. }
  620. .dot:nth-child(2) {
  621. animation-delay: -0.16s;
  622. }
  623. @keyframes loading {
  624. 0%,
  625. 80%,
  626. 100% {
  627. transform: scale(0);
  628. }
  629. 40% {
  630. transform: scale(1);
  631. }
  632. }
  633. .input-area {
  634. position: fixed;
  635. bottom: 0;
  636. left: 0;
  637. right: 0;
  638. padding: 0 40rpx 80rpx 40rpx;
  639. background-color: #ffffff;
  640. }
  641. .input-wrapper {
  642. position: relative;
  643. display: flex;
  644. align-items: center;
  645. padding: 15rpx 20rpx;
  646. background-color: rgb(220, 31, 29);
  647. border-radius: 100rpx;
  648. display: flex;
  649. align-items: center;
  650. justify-content: center;
  651. height: 50rpx;
  652. }
  653. .mic-icon {
  654. width: 36rpx;
  655. height: 36rpx;
  656. margin-right: 20rpx;
  657. }
  658. .input-field {
  659. flex: 1;
  660. font-size: 28rpx;
  661. color: #fff;
  662. display: flex;
  663. align-items: center;
  664. justify-content: center;
  665. margin-left: 60rpx;
  666. background: none;
  667. border: none;
  668. outline: none;
  669. }
  670. .input-field::placeholder {
  671. color: #ffffff !important;
  672. opacity: 1;
  673. }
  674. .send-button {
  675. background: url('https://d31zlh4on95l9h.cloudfront.net/images/95f1ea2262e9157db13c93c0dc1c5d96.svg');
  676. background-repeat: no-repeat;
  677. background-size: 100% 100%;
  678. height: 50rpx;
  679. width: 50rpx;
  680. padding: 0;
  681. border: 1rpx solid transparent;
  682. margin-left: 20rpx;
  683. }
  684. .send-icon {
  685. width: 36rpx;
  686. height: 36rpx;
  687. }
  688. .disclaimer {
  689. font-size: 15rpx;
  690. color: #4d4c4c;
  691. display: flex;
  692. align-items: center;
  693. justify-content: center;
  694. margin-top: 15rpx;
  695. }
  696. .banner-panel {
  697. position: relative;
  698. height: 480rpx; /* 拉长容器,灰色背景跟随变高 */
  699. overflow: hidden; /* 让圆角和内部层剪裁一致 */
  700. border-radius: 15rpx;
  701. }
  702. .pray-banner {
  703. position: absolute;
  704. /* background-size: 100% 100%; */
  705. inset: 0; /* 顶部、底部、左、右都贴合容器 */
  706. width: 100%;
  707. height: 88%;
  708. border-radius: 15rpx;
  709. z-index: 1; /* 在灰底之上、内容之下 */
  710. }
  711. .contain {
  712. margin: 0 20rpx;
  713. gap: 5rpx;
  714. }
  715. .banner-panel .robot-container,
  716. .banner-panel .function-tabs,
  717. .banner-panel .recommend-card {
  718. position: relative;
  719. z-index: 2;
  720. }
  721. .back-to-top {
  722. position: fixed;
  723. right: 30rpx;
  724. bottom: 35%;
  725. width: 100rpx;
  726. height: 100rpx;
  727. z-index: 1000;
  728. }
  729. .back-to-top:active {
  730. transform: scale(0.96);
  731. }
  732. </style>