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.

856 lines
20 KiB

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