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.

1072 lines
24 KiB

  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. <!-- 顶部固定区域占位符 -->
  32. <view class="banner-placeholder"></view>
  33. <view
  34. class="banner-panel"
  35. :class="messages.length === 0 ? '' : 'panelShow'"
  36. :style="{ paddingTop: safeAreaInsets?.top + 'px' }"
  37. >
  38. <image
  39. src="https://d31zlh4on95l9h.cloudfront.net/images/42e18bd7fe97d4f4f37aa70439a0990b.svg"
  40. class="pray-banner"
  41. :class="messages.length === 0 ? '' : 'show'"
  42. :style="{ paddingTop: safeAreaInsets?.top + 'px' }"
  43. mode="aspectFill"
  44. ></image>
  45. <view class="contain">
  46. <!-- 机器人头像和欢迎语 -->
  47. <view class="robot-container">
  48. <image
  49. src="https://d31zlh4on95l9h.cloudfront.net/images/61fa384381c88ad80be28f41827fe0e5.svg"
  50. class="robot-avatar"
  51. ></image>
  52. <view class="welcome-message">
  53. <text class="greeting">Hi, 我是您的股市随身顾问~</text>
  54. <text class="description"
  55. >个股诊断市场情绪解读都可以找我</text
  56. >
  57. </view>
  58. </view>
  59. <!-- 功能标签栏 -->
  60. <view
  61. class="function-tabs"
  62. v-if="messages.length === 0"
  63. scroll-x="true"
  64. show-scrollbar="false"
  65. >
  66. <view class="tab-item">个股诊断</view>
  67. <view class="tab-item">市场情绪温度计</view>
  68. <view class="tab-item">买卖时机提示</view>
  69. <view class="tab-item">个股</view>
  70. </view>
  71. <!-- 特斯拉推荐卡片 -->
  72. <view class="recommend-card" v-if="messages.length === 0">
  73. <view class="arrow" v-if="messages.length === 0"></view>
  74. <view class="card-content">
  75. <image
  76. src="../../static/images/tesla-logo.png"
  77. class="logo"
  78. ></image>
  79. <view class="card-text">
  80. <text class="main-question">当前特斯拉该如何布局</text>
  81. <text class="stock-code">TSLA</text>
  82. </view>
  83. <image
  84. src="https://d31zlh4on95l9h.cloudfront.net/images/40d94054644f6e3f1c366751f07f0010.svg"
  85. class="arrow-icon"
  86. @click="goBlank"
  87. ></image>
  88. </view>
  89. </view>
  90. </view>
  91. </view>
  92. <!-- 可能感兴趣的话题 -->
  93. <view v-if="messages.length === 0" class="interest-section">
  94. <text class="section-title">- 您可能感兴趣 -</text>
  95. <view class="topics-list">
  96. <view class="topic-item" v-for="topic in hotTopics" :key="topic.id">
  97. <image :src="topic.icon" class="tag-icon"></image>
  98. <text class="topic-text" @click="sendMessageList(topic.text)">{{
  99. topic.text
  100. }}</text>
  101. </view>
  102. </view>
  103. </view>
  104. <!-- 聊天区域 -->
  105. <view class="chat-container" v-if="messages.length > 0">
  106. <!-- 给聊天容器添加滚动引用 -->
  107. <scroll-view
  108. class="chat-scroll-view"
  109. scroll-y="true"
  110. :scroll-top="scrollTop"
  111. :style="{ paddingTop: safeAreaInsets?.top + 'px' }"
  112. >
  113. <view class="message-list" id="messageList">
  114. <view
  115. v-for="(message, index) in messages"
  116. :key="index"
  117. :class="
  118. message.isUser ? 'message user-message' : 'message bot-message'
  119. "
  120. >
  121. <!-- 会话图标 -->
  122. <text
  123. :class="
  124. message.isUser
  125. ? 'fa-solid fa-user message-icon'
  126. : 'fa-solid fa-robot message-icon'
  127. "
  128. ></text>
  129. <!-- 会话内容 -->
  130. <view class="message-content">
  131. <!-- loading -->
  132. <view
  133. class="loading-dots"
  134. v-if="message.isThinking || !message.isUser"
  135. >
  136. <div class="thinking-process">
  137. <div class="thinking-header">
  138. <div class="thinking-icon"></div>
  139. <div class="thinking-title">深度思考 正在思考</div>
  140. <div class="thinking-count">25 个结果</div>
  141. <div class="thinking-toggle" @click="toggleThinking">
  142. <span v-if="showThinking"></span>
  143. <span v-else></span>
  144. </div>
  145. </div>
  146. <div v-show="showThinking" class="thinking-content">
  147. <div class="thinking-item">
  148. <div class="item-status">
  149. <span class="checkmark"></span>
  150. </div>
  151. <div class="item-text">问题分析完成</div>
  152. </div>
  153. <div class="thinking-item">
  154. <div class="item-status">
  155. <span class="checkmark"></span>
  156. </div>
  157. <div class="item-text">收集相关信息</div>
  158. </div>
  159. </div>
  160. </div>
  161. </view>
  162. <!-- 使用 rich-text 渲染 Markdown 内容 -->
  163. <rich-text
  164. v-if="!message.isUser"
  165. class="message-text"
  166. :nodes="renderMarkdown(message.content)"
  167. ></rich-text>
  168. <text v-else class="message-text">{{ message.content }}</text>
  169. </view>
  170. </view>
  171. </view>
  172. </scroll-view>
  173. </view>
  174. </view>
  175. <!-- 输入框区域 -->
  176. <view class="input-area">
  177. <view class="input-wrapper">
  178. <input
  179. type="text"
  180. placeholder="请输入股票代码/名称,获取AI洞察"
  181. placeholder-style="color:#fff;opacity:1"
  182. class="input-field"
  183. v-model="inputMessage"
  184. @confirm="sendMessage"
  185. />
  186. <image class="send-button" @click="sendMessage" :disabled="isSending">
  187. <!-- <image
  188. src="https://d31zlh4on95l9h.cloudfront.net/images/95f1ea2262e9157db13c93c0dc1c5d96.svg"
  189. class="send-icon"
  190. ></image> -->
  191. </image>
  192. </view>
  193. <text class="disclaimer"
  194. >以上数据由AI生成不作为最终投资建议决策需独立</text
  195. >
  196. </view>
  197. <image
  198. class="back-to-top"
  199. src="https://d31zlh4on95l9h.cloudfront.net/images/ba357635d2bb480241952bb1cabacd73.svg"
  200. @click="scrollToTop"
  201. ></image>
  202. <footerBar class="static-footer" :type="type"></footerBar>
  203. </view>
  204. </template>
  205. <script setup>
  206. const { safeAreaInsets } = uni.getSystemInfoSync();
  207. import { ref, onMounted, nextTick, watch } from "vue";
  208. import footerBar from "../../components/footerBar-cn.vue";
  209. import marked from "marked"; // 引入 marked 库
  210. // 设置 marked 选项
  211. marked.setOptions({
  212. renderer: new marked.Renderer(),
  213. highlight: null, // 如果需要代码高亮,可以设置适当的函数
  214. langPrefix: "language-",
  215. pedantic: false,
  216. gfm: true,
  217. breaks: false,
  218. sanitize: false,
  219. smartLists: true,
  220. smartypants: false,
  221. xhtml: false,
  222. });
  223. // 创建一个用于渲染 Markdown 的函数
  224. const renderMarkdown = (content) => {
  225. if (!content) return "";
  226. return marked.parse(content);
  227. };
  228. const type = ref("member");
  229. const inputMessage = ref("");
  230. const showThinking = ref(true);
  231. const isSending = ref(false);
  232. const uuid = ref("");
  233. const messages = ref([]);
  234. const scrollTop = ref(0); // 用于控制scroll-view的滚动位置
  235. // const dataInfo = ref("");
  236. const hotTopics = ref([
  237. {
  238. id: 1,
  239. text: "英伟达(NVDA)股票情绪温度?",
  240. icon: "https://d31zlh4on95l9h.cloudfront.net/images/7ed58be0f4b81aeb398d9ba2534a624b.svg",
  241. },
  242. {
  243. id: 2,
  244. text: "博通(AVGO)明天还能涨吗?",
  245. icon: "https://d31zlh4on95l9h.cloudfront.net/images/7ed58be0f4b81aeb398d9ba2534a624b.svg",
  246. },
  247. {
  248. id: 3,
  249. text: "为什么Fluence Energy(FLNC)会暴涨?",
  250. icon: "https://d31zlh4on95l9h.cloudfront.net/images/7ed58be0f4b81aeb398d9ba2534a624b.svg",
  251. },
  252. {
  253. id: 4,
  254. text: "为什么Fluence Energy(FLNC)会暴涨?",
  255. icon: "https://d31zlh4on95l9h.cloudfront.net/images/7ed58be0f4b81aeb398d9ba2534a624b.svg",
  256. },
  257. ]);
  258. // 初始化
  259. onMounted(() => {
  260. initUUID();
  261. // 如果有历史消息,滚动到底部
  262. if (messages.value.length > 0) {
  263. setTimeout(() => {
  264. scrollToBottom();
  265. }, 200);
  266. }
  267. });
  268. // 监听消息变化,当有新消息时自动滚动到最新消息
  269. watch(
  270. messages,
  271. (newMessages) => {
  272. // 延迟执行滚动,确保DOM更新完成
  273. setTimeout(() => {
  274. scrollToBottom();
  275. }, 100);
  276. },
  277. { deep: true }
  278. );
  279. // 初始化 UUID
  280. const initUUID = () => {
  281. let storedUUID = uni.getStorageSync("user_uuid");
  282. if (!storedUUID) {
  283. storedUUID = generateUUID();
  284. uni.setStorageSync("user_uuid", storedUUID);
  285. }
  286. uuid.value = storedUUID;
  287. };
  288. // 生成简单UUID
  289. const generateUUID = () => {
  290. return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
  291. var r = (Math.random() * 16) | 0,
  292. v = c == "x" ? r : (r & 0x3) | 0x8;
  293. return v.toString(16);
  294. });
  295. };
  296. // 新会话
  297. const newChat = () => {
  298. messages.value = [];
  299. uni.removeStorageSync("user_uuid");
  300. initUUID();
  301. };
  302. // 跳转到空白页
  303. const goBlank = () => {
  304. uni.navigateTo({
  305. url: "/pages/blank/blank",
  306. });
  307. };
  308. // 发送消息
  309. const sendMessage = () => {
  310. if (inputMessage.value.trim() === "" || isSending.value) return;
  311. const userMessage = {
  312. content: inputMessage.value,
  313. isUser: true,
  314. isThinking: false,
  315. isTyping: false,
  316. };
  317. messages.value.push(userMessage);
  318. inputMessage.value = "";
  319. // 滚动到底部
  320. setTimeout(() => {
  321. scrollToBottom();
  322. }, 100);
  323. // 模拟机器人回复
  324. simulateBotResponse(userMessage.content);
  325. };
  326. // 发送消息
  327. const sendMessageList = (listMessage) => {
  328. console.log(listMessage);
  329. const userMessage = {
  330. content: listMessage,
  331. isUser: true,
  332. isThinking: false,
  333. isTyping: false,
  334. };
  335. messages.value.push(userMessage);
  336. inputMessage.value = "";
  337. // 滚动到底部
  338. setTimeout(() => {
  339. scrollToBottom();
  340. }, 100);
  341. // 模拟机器人回复
  342. simulateBotResponse(userMessage.content);
  343. };
  344. // 模拟机器人回复
  345. const simulateBotResponse = async (userMessage) => {
  346. isSending.value = true;
  347. // 添加机器人加载消息
  348. const botMsg = {
  349. content: "",
  350. isUser: false,
  351. isTyping: true,
  352. isThinking: false,
  353. };
  354. messages.value.push(botMsg);
  355. const toDataInfo = await getDataInfo();
  356. console.log(toDataInfo);
  357. // dataInfo.value = toDataInfo.data;
  358. // console.log(dataInfo.value);
  359. setTimeout(() => {
  360. }, 10000);
  361. // 滚动到底部
  362. setTimeout(() => {
  363. scrollToBottom();
  364. }, 100);
  365. // 模拟流式响应
  366. let responseText = `我已经收到您的消息: "${userMessage}" + "${toDataInfo.data}"`;
  367. // let responseText = `我已经收到您的消息: "${userMessage}"。
  368. // ## 股票分析报告
  369. // ### 股票名称: Tesla Inc. (TSLA)
  370. // - **当前价格**: 448.980
  371. // - **更新时间**: 23/10/2025
  372. // - **今日无变盘点**
  373. // ### 技术分析
  374. // - **CFTL**: 当前牵牛绳为红色,处于龙线区域,最近出现“牛刀小试”,度牛线目前处于青绿色区域。
  375. // - **空间预测**:
  376. // - 预测低一值: 413.364
  377. // - 预测高一值: 426.636
  378. // - 预测低二值: 421.670
  379. // - 预测高二值: 448.314
  380. // - **能量分析**: AI智能均线多头排列,当前卖盘小于买盘
  381. // ### 资金与主力
  382. // - **主力分析**:
  383. // 1. 该股庄家中长期筹码成本价格为 356.036,短期资金成本价格为 406.429。该股筹码分散,当日筹码成本价格为 439.322。
  384. // 2. 近日没有出现主力集中吸筹。
  385. // 3. 近期主力持仓比例大于散户持仓比例。当日主力持仓增加。当日散户持仓减少。
  386. // ### 综合评价
  387. // - **个股走势评价**:
  388. // - 该股整体趋势向好,出现暴涨的可能性较大,当前如果已经持有该股票,可以继续持股观察,如果尚未持有该股票,可持续进行观察,目前处于机会的初期,处于反弹阶段,可以分步建仓!
  389. // - **核心证据链**:
  390. // - 资金共识:当日多方资金流入。
  391. // - 趋势动能:该股中长期处于上升趋势,短期处于弱势状态。
  392. // - **牛股评级**: ★★★☆☆
  393. // - **暴涨概率**: 60%
  394. // - **风险评估**: 非常安全
  395. // - **安全边际**: 432.671~458.057
  396. // - **黄金价域**: 427.995~440.835`;
  397. let index = 0;
  398. const typeWriter = () => {
  399. if (index < responseText.length) {
  400. // 使用 Vue 的响应式更新机制
  401. messages.value[messages.value.length - 1].content =
  402. responseText.substring(0, index + 1);
  403. index++;
  404. // 滚动到底部,更频繁地触发滚动以适应文本增长
  405. setTimeout(() => {
  406. scrollToBottom();
  407. }, 20);
  408. setTimeout(typeWriter, 30);
  409. } else {
  410. messages.value[messages.value.length - 1].isTyping = false;
  411. isSending.value = false;
  412. dataInfo.value = '';
  413. // 最后确保滚动到底部
  414. setTimeout(() => {
  415. scrollToBottom();
  416. }, 100);
  417. }
  418. };
  419. setTimeout(typeWriter, 500);
  420. };
  421. // 滚动到底部
  422. const scrollToBottom = () => {
  423. // 使用scroll-view的scrollTop属性来控制滚动
  424. const query = uni.createSelectorQuery();
  425. query.select("#messageList").boundingClientRect();
  426. query.exec((res) => {
  427. if (res[0]) {
  428. // 设置scrollTop为消息列表的高度,实现滚动到底部
  429. scrollTop.value = res[0].height;
  430. }
  431. });
  432. };
  433. const scrollToTop = () => {
  434. // 滚动到顶部
  435. scrollTop.value = 0;
  436. };
  437. const toggleThinking = () => {
  438. showThinking.value = !showThinking.value;
  439. };
  440. function getDataInfo() {
  441. return new Promise((resolve, reject) => {
  442. uni.request({
  443. url: "http://localhost:8888/ka",
  444. data: {},
  445. header: {
  446. Accept: "application/json",
  447. "Content-Type": "application/json",
  448. "X-Requested-With": "XMLHttpRequest",
  449. },
  450. method: "GET",
  451. sslVerify: true,
  452. success: (res) => {
  453. resolve(res.data);
  454. },
  455. fail: (error) => {
  456. reject(error);
  457. },
  458. });
  459. });
  460. }
  461. </script>
  462. <style scoped>
  463. .deepMate-page {
  464. display: flex;
  465. flex-direction: column;
  466. height: 100vh;
  467. max-height: 100vh; /* 限制最大高度 */
  468. background-color: #ffffff;
  469. padding: 0; /* 移除padding,避免影响布局 */
  470. position: relative;
  471. overflow: hidden; /* 禁止页面整体滚动 */
  472. -webkit-overflow-scrolling: none; /* 禁用iOS弹性滚动 */
  473. }
  474. /* 顶部导航栏 - 固定定位 */
  475. .header {
  476. display: flex;
  477. justify-content: space-between;
  478. align-items: center;
  479. padding: 20rpx 30rpx;
  480. background-color: #ffffff;
  481. position: fixed;
  482. top: 0;
  483. left: 0;
  484. right: 0;
  485. z-index: 999;
  486. box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
  487. }
  488. /* 顶部固定区域占位符 */
  489. .header-placeholder {
  490. height: 120rpx; /* 与header高度一致 */
  491. }
  492. /* 顶部固定区域占位符 */
  493. .banner-placeholder {
  494. height: 80rpx; /* 与header高度一致,防止内容被固定头部遮挡 */
  495. }
  496. .header-left,
  497. .header-right {
  498. display: flex;
  499. align-items: center;
  500. }
  501. .header-left .icon,
  502. .header-right .icon {
  503. width: 40rpx;
  504. height: 40rpx;
  505. margin-right: 20rpx;
  506. }
  507. .header-center .title {
  508. font-size: 36rpx;
  509. font-weight: bold;
  510. color: #333333;
  511. }
  512. .new-chat-button {
  513. background-color: #ff6600;
  514. border: none;
  515. border-radius: 8rpx;
  516. padding: 10rpx 20rpx;
  517. }
  518. .new-chat-text {
  519. color: white;
  520. font-size: 24rpx;
  521. }
  522. .main-content {
  523. flex: 1;
  524. padding: 20rpx;
  525. overflow-y: hidden; /* 禁止主内容区域滚动 */
  526. margin-top: 20rpx;
  527. margin-bottom: 250rpx; /* 为底部输入区域留出空间 */
  528. max-height: calc(100vh - 200rpx); /* 确保内容区域不会超出视口 */
  529. -webkit-overflow-scrolling: none; /* 禁用iOS弹性滚动 */
  530. }
  531. .robot-container {
  532. display: flex;
  533. align-items: center;
  534. margin-bottom: 30rpx;
  535. }
  536. .robot-avatar {
  537. width: 130rpx;
  538. height: 130rpx;
  539. border-radius: 50%;
  540. margin-right: 10rpx;
  541. }
  542. .welcome-message {
  543. flex: 1;
  544. }
  545. .greeting {
  546. font-size: 32rpx;
  547. margin-left: 50rpx;
  548. top: 40rpx;
  549. font-weight: bold;
  550. color: #333333;
  551. line-height: 48rpx;
  552. }
  553. .description {
  554. display: block;
  555. font-size: 24rpx;
  556. color: #666666;
  557. line-height: 36rpx;
  558. margin-top: 10rpx;
  559. margin-left: 45rpx;
  560. }
  561. .function-tabs {
  562. display: flex;
  563. margin-bottom: 30rpx;
  564. }
  565. .tab-item {
  566. padding: 5rpx 20rpx;
  567. border-radius: 20rpx;
  568. font-size: 20rpx;
  569. font-weight: 700;
  570. color: #666666;
  571. background-color: #fffefe;
  572. margin-right: 20rpx;
  573. transition: all 0.3s;
  574. }
  575. .tab-item.active {
  576. color: #ff6600;
  577. background-color: #fff;
  578. border: 1rpx solid #ff6600;
  579. }
  580. .recommend-card {
  581. background: url("https://d31zlh4on95l9h.cloudfront.net/images/4da1d629a55c307c3605ca15bf15189a.svg");
  582. background-repeat: no-repeat;
  583. /* border-radius: 20rpx; */
  584. padding: 40rpx;
  585. margin-bottom: 30rpx;
  586. /* box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); */
  587. }
  588. .card-content {
  589. display: flex;
  590. align-items: center;
  591. justify-content: space-between;
  592. }
  593. .logo {
  594. width: 80rpx;
  595. height: 80rpx;
  596. background-color: #ff0000;
  597. border-radius: 10rpx;
  598. display: flex;
  599. align-items: center;
  600. justify-content: center;
  601. margin-right: 20rpx;
  602. }
  603. .card-text {
  604. flex: 1;
  605. margin-left: 20rpx;
  606. }
  607. .main-question {
  608. font-size: 32rpx;
  609. color: #333333;
  610. line-height: 48rpx;
  611. }
  612. .stock-code {
  613. display: block;
  614. font-size: 24rpx;
  615. color: #ff3b30;
  616. background-color: #ffffff;
  617. padding: 2rpx 15rpx;
  618. border-radius: 12rpx;
  619. margin-top: 8rpx;
  620. width: fit-content;
  621. border: 1rpx solid #ff3b30;
  622. }
  623. .arrow-icon {
  624. background: url("https://d31zlh4on95l9h.cloudfront.net/images/40d94054644f6e3f1c366751f07f0010.svg");
  625. background-repeat: no-repeat;
  626. left: 0.5rem;
  627. top: 1.8rem;
  628. background-size: 100% 100%;
  629. width: 60rpx;
  630. height: 60rpx;
  631. }
  632. .interest-section {
  633. margin-bottom: 30rpx;
  634. }
  635. .section-title {
  636. display: block;
  637. text-align: center;
  638. font-size: 26rpx;
  639. color: #666666;
  640. margin-bottom: 20rpx;
  641. }
  642. .topics-list {
  643. display: flex;
  644. flex-direction: column;
  645. gap: 15rpx;
  646. }
  647. .topic-item {
  648. display: flex;
  649. align-items: center;
  650. padding: 15rpx 20rpx;
  651. background-color: #f0f0f0;
  652. border-radius: 15rpx;
  653. width: fit-content;
  654. }
  655. .tag-icon {
  656. width: 24rpx;
  657. height: 24rpx;
  658. margin-right: 10rpx;
  659. }
  660. .topic-text {
  661. font-size: 28rpx;
  662. color: #333333;
  663. flex: 1;
  664. }
  665. /* 聊天区域样式 */
  666. .chat-container {
  667. margin-top: 30rpx;
  668. border-radius: 10rpx;
  669. height: fit-content;
  670. /* overflow-y: auto; */
  671. }
  672. .chat-scroll-view {
  673. height: calc(80vh - 250rpx);
  674. /* height: 80vh ; */
  675. /* flex: 1; */
  676. /* height: fit-content; */
  677. margin-top: 70rpx;
  678. }
  679. .message-list {
  680. /* padding: 20rpx; */
  681. /* margin-top: 200rpx; */
  682. }
  683. .message {
  684. display: flex;
  685. align-items: flex-start;
  686. margin-bottom: 30rpx;
  687. }
  688. .user-message {
  689. flex-direction: row-reverse;
  690. }
  691. .message-icon {
  692. font-size: 24rpx;
  693. margin: 0 10rpx;
  694. padding: 10rpx;
  695. border-radius: 50%;
  696. background-color: #ddd;
  697. width: 40rpx;
  698. height: 40rpx;
  699. display: flex;
  700. align-items: center;
  701. justify-content: center;
  702. }
  703. .user-message .message-icon {
  704. background-color: #007aff;
  705. color: white;
  706. }
  707. .bot-message .message-icon {
  708. background-color: #34c759;
  709. color: white;
  710. }
  711. .message-content {
  712. max-width: 70%;
  713. position: relative;
  714. }
  715. .user-message .message-content {
  716. background-color: #007aff;
  717. border-radius: 10rpx;
  718. padding: 15rpx;
  719. }
  720. .bot-message .message-content {
  721. background-color: #f0f0f0;
  722. border-radius: 10rpx;
  723. padding: 15rpx;
  724. }
  725. .message-text {
  726. font-size: 28rpx;
  727. line-height: 40rpx;
  728. }
  729. .user-message .message-text {
  730. color: white;
  731. }
  732. .bot-message .message-text {
  733. color: #333;
  734. }
  735. .loading-dots {
  736. display: flex;
  737. align-items: center;
  738. padding-top: 10rpx;
  739. }
  740. .dot {
  741. width: 10rpx;
  742. height: 10rpx;
  743. background-color: #666;
  744. border-radius: 50%;
  745. margin: 0 4rpx;
  746. animation: loading 1.4s infinite ease-in-out both;
  747. }
  748. .user-message .dot {
  749. background-color: white;
  750. }
  751. .dot:nth-child(1) {
  752. animation-delay: -0.32s;
  753. }
  754. .dot:nth-child(2) {
  755. animation-delay: -0.16s;
  756. }
  757. @keyframes loading {
  758. 0%,
  759. 80%,
  760. 100% {
  761. transform: scale(0);
  762. }
  763. 40% {
  764. transform: scale(1);
  765. }
  766. }
  767. .input-area {
  768. position: fixed;
  769. bottom: 70rpx;
  770. left: 0;
  771. right: 0;
  772. padding: 0 40rpx 80rpx 40rpx;
  773. background-color: #ffffff;
  774. z-index: 999;
  775. -webkit-overflow-scrolling: none; /* 禁用iOS弹性滚动 */
  776. }
  777. .input-wrapper {
  778. position: relative;
  779. display: flex;
  780. align-items: center;
  781. padding: 15rpx 20rpx;
  782. background-color: rgb(220, 31, 29);
  783. border-radius: 100rpx;
  784. display: flex;
  785. align-items: center;
  786. justify-content: center;
  787. height: 50rpx;
  788. }
  789. .mic-icon {
  790. width: 36rpx;
  791. height: 36rpx;
  792. margin-right: 20rpx;
  793. }
  794. .input-field {
  795. flex: 1;
  796. font-size: 28rpx;
  797. color: #fff;
  798. display: flex;
  799. align-items: center;
  800. justify-content: center;
  801. margin-left: 60rpx;
  802. background: none;
  803. border: none;
  804. outline: none;
  805. }
  806. .input-field::placeholder {
  807. color: #ffffff !important;
  808. opacity: 1;
  809. }
  810. .send-button {
  811. background: url("https://d31zlh4on95l9h.cloudfront.net/images/95f1ea2262e9157db13c93c0dc1c5d96.svg");
  812. background-repeat: no-repeat;
  813. background-size: 100% 100%;
  814. height: 50rpx;
  815. width: 50rpx;
  816. padding: 0;
  817. border: 1rpx solid transparent;
  818. margin-left: 20rpx;
  819. }
  820. .send-icon {
  821. width: 36rpx;
  822. height: 36rpx;
  823. }
  824. .disclaimer {
  825. font-size: 15rpx;
  826. color: #4d4c4c;
  827. display: flex;
  828. align-items: center;
  829. justify-content: center;
  830. margin-top: 15rpx;
  831. }
  832. .banner-panel {
  833. position: relative;
  834. height: 480rpx; /* 拉长容器,灰色背景跟随变高 */
  835. overflow: hidden; /* 让圆角和内部层剪裁一致 */
  836. border-radius: 15rpx;
  837. }
  838. .panelShow {
  839. height: 150rpx;
  840. position: fixed;
  841. top: 70rpx;
  842. z-index: 999;
  843. width: 700rpx;
  844. }
  845. .pray-banner {
  846. position: absolute;
  847. /* background-size: 100% 100%; */
  848. inset: 0; /* 顶部、底部、左、右都贴合容器 */
  849. width: 100%;
  850. height: 88%;
  851. border-radius: 15rpx;
  852. z-index: 1; /* 在灰底之上、内容之下 */
  853. }
  854. .contain {
  855. margin: 0 20rpx;
  856. gap: 5rpx;
  857. }
  858. .banner-panel .robot-container,
  859. .banner-panel .function-tabs,
  860. .banner-panel .recommend-card {
  861. position: relative;
  862. z-index: 2;
  863. }
  864. .back-to-top {
  865. position: fixed;
  866. right: 30rpx;
  867. bottom: 35%;
  868. width: 100rpx;
  869. height: 100rpx;
  870. z-index: 1000;
  871. }
  872. .back-to-top:active {
  873. transform: scale(0.96);
  874. }
  875. .static-footer {
  876. position: fixed;
  877. bottom: 0;
  878. z-index: 999;
  879. }
  880. /* 顶部固定区域占位符 */
  881. .banner-placeholder {
  882. height: 120rpx; /* 与header高度一致,防止内容被固定头部遮挡 */
  883. }
  884. .thinking-process {
  885. margin: 20rpx 0;
  886. border: 2rpx solid #e5e5e5;
  887. border-radius: 2rpx;
  888. background-color: #f9f9f9;
  889. }
  890. .thinking-header {
  891. display: flex;
  892. align-items: center;
  893. padding: 20rpx 30rpx;
  894. cursor: pointer;
  895. background-color: #fff;
  896. border-bottom: 2px solid #e5e5e5;
  897. }
  898. .thinking-icon {
  899. font-size: 32rpx;
  900. margin-right: 16rpx;
  901. color: #d47c45;
  902. }
  903. .thinking-title {
  904. font-size: 28rpx;
  905. font-weight: 500;
  906. color: #d47c45;
  907. margin-right: 16rpx;
  908. }
  909. .thinking-count {
  910. font-size: 24rpx;
  911. color: #666;
  912. margin-right: 16rpx;
  913. }
  914. .thinking-toggle {
  915. font-size: 24rpx;
  916. color: #999;
  917. }
  918. .thinking-content {
  919. padding: 20rpx 30rpx;
  920. }
  921. .thinking-item {
  922. display: flex;
  923. align-items: center;
  924. margin-bottom: 16rpx;
  925. padding: 8rpx 0;
  926. }
  927. .item-status {
  928. width: 32rpx;
  929. height: 32rpx;
  930. border-radius: 50%;
  931. background-color: #f0f0f0;
  932. display: flex;
  933. justify-content: center;
  934. align-items: center;
  935. margin-right: 16rpx;
  936. }
  937. .checkmark {
  938. font-size: 20rpx;
  939. color: #ff0000;
  940. }
  941. .item-text {
  942. font-size: 24rpx;
  943. color: #333;
  944. }
  945. </style>