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.

738 lines
19 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <script setup>
  2. // 导入
  3. import { ref, computed, onMounted, watch, nextTick } from "vue";
  4. import { setHeight } from "../utils/setHeight";
  5. import { getUserCountAPI } from "../api/AIxiaocaishen";
  6. import { ElMessage } from 'element-plus'
  7. import AIchat from "./AIchat.vue";
  8. import AIfind from "./AIfind.vue";
  9. import { useAppBridge } from '../assets/js/useAppBridge.js'
  10. import { useDataStore } from '@/store/dataList.js'
  11. import { useChatStore } from '../store/chat'
  12. import { useAudioStore } from '../store/audio'
  13. import _ from "lodash";
  14. import logo from "../assets/img/homePage/logo.png";
  15. import madeInHL from "../assets/img/homePage/madeInHL.png";
  16. import getCountAll from "../assets/img/homePage/get-count-all.png";
  17. import announcementBtn from "../assets/img/homePage/announcement.png";
  18. import thinkActive from "../assets/img/homePage/tail/think-active.png";
  19. import thinkNoActive from "../assets/img/homePage/tail/think-no-active.png";
  20. import languageBtn from "../assets/img/homePage/tail/language.png";
  21. import voice from "../assets/img/homePage/tail/voice.png";
  22. import voiceNoActive from "../assets/img/homePage/tail/voice-no-active.png";
  23. import sendBtn from "../assets/img/homePage/tail/send.png";
  24. import msgBtn from "../assets/img/homePage/tail/msg.png";
  25. // import { useUserStore } from "../store/userPessionCode.js";
  26. const { getQueryVariable } = useDataStore()
  27. // 变量
  28. // 音频管理
  29. const audioStore = useAudioStore()
  30. const isVoice = computed(() => audioStore.isVoiceEnabled)
  31. const toggleVoice = () => {
  32. audioStore.toggleVoice()
  33. }
  34. // 将默认值改为从 sessionStorage 中获取,如果没有则使用默认值 'aifindCow'为第一个默认tab
  35. const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat");
  36. const activeIndex = ref(
  37. parseInt(sessionStorage.getItem("activeIndexAI") || "0")
  38. );
  39. const tabs = computed(() => [
  40. {
  41. name: "AIchat",
  42. label: "AI对话",
  43. },
  44. {
  45. name: "AIfind",
  46. label: "发现",
  47. },
  48. ]);
  49. // 修改 setActiveTab 方法,添加一个可选参数 forceAIchat
  50. const setActiveTab = (tab, index, forceAIchat = false) => {
  51. isScrolling.value = false; //回复滚动到底部方法
  52. isAnnouncementVisible.value = false;
  53. if (forceAIchat && activeTab.value !== "AIchat") {
  54. activeTab.value = "AIchat";
  55. activeIndex.value = 0;
  56. sessionStorage.setItem("activeTabAI", "AIchat");
  57. sessionStorage.setItem("activeIndexAI", "0");
  58. } else {
  59. activeTab.value = tab;
  60. activeIndex.value = index;
  61. sessionStorage.setItem("activeTabAI", tab);
  62. sessionStorage.setItem("activeIndexAI", index.toString());
  63. }
  64. console.log(tab, index, "tab, index");
  65. setHeight(document.getElementById("testId")); // 给父组件发送窗口高度
  66. };
  67. // 修改 activeComponent 的计算逻辑
  68. const activeComponent = computed(() => {
  69. if (isAnnouncementVisible.value) {
  70. return Announcement;
  71. }
  72. return activeTab.value === "AIchat" ? AIchat : AIfind;
  73. });
  74. // 新增一个方法,调用时先判断是否处于 AIchat,若不在则跳转到 AIchat
  75. const ensureAIchat = () => {
  76. setActiveTab("AIchat", 0, true);
  77. };
  78. // 获取次数
  79. // const UserCount = ref(0);
  80. // const getUserCount = async () => {
  81. // const result = await getUserCountAPI({ token: localStorage.getItem('localToken') });
  82. // UserCount.value = result.data.hasCount;
  83. // };
  84. const UserCount = computed(() => chatStore.UserCount)
  85. const getCount = () => {
  86. console.log('点击了获取次数的按钮')
  87. }
  88. // 深度思考
  89. const isThinking = ref(true);
  90. const toggleThink = () => {
  91. isThinking.value = !isThinking.value;
  92. };
  93. // 发送消息
  94. const message = ref("");
  95. // 传输对象
  96. const messages = ref([]);
  97. // 信息加载状态
  98. const isLoading = computed(() => { chatStore.isLoading });
  99. // 添加用户消息
  100. const updateMessage = (title) => {
  101. message.value = title;
  102. // console.log("updateMessage 的值:", title);
  103. };
  104. const sendMessage = async () => {
  105. if (localStorage.getItem('localToken') == null||localStorage.getItem('localToken') == '') {
  106. ElMessage.error('请先登录');
  107. return ;
  108. }
  109. isScrolling.value = false;
  110. // 调用 ensureAIchat 确保跳转到 AIchat 页面
  111. ensureAIchat();
  112. if (!message.value) return;
  113. if (chatStore.isLoading) return;
  114. console.log(chatStore.isLoading, 'isLoading.value1111');
  115. chatStore.setLoading(true);
  116. console.log(chatStore.isLoading, 'isLoading.value2222');
  117. // 发送消息时,设置 isLoading 为 true
  118. messages.value = [
  119. ...messages.value,
  120. {
  121. sender: "user",
  122. content: message.value,
  123. timestamp: new Date().toISOString(),
  124. }
  125. ];
  126. // 重置消息输入框
  127. message.value = "";
  128. };
  129. // 公告
  130. // 引入公告组件
  131. import Announcement from "./Announcement.vue";
  132. // 新增一个变量来控制是否显示公告页面
  133. const isAnnouncementVisible = ref(false);
  134. const showAnnouncement = async () => {
  135. console.log("打开公告");
  136. isScrolling.value = false; //回复滚动到底部方法
  137. setActiveTab('', -1); // 清空当前选中状态
  138. isAnnouncementVisible.value = true; // 显示公告页面
  139. };
  140. // 点击剩余次数会弹出的弹窗
  141. // 新增一个 ref 来控制弹窗的显示与隐藏
  142. const dialogVisible = ref(false);
  143. // 获取次数
  144. const showCount = () => {
  145. console.log("显示剩余次数");
  146. // 显示弹窗
  147. dialogVisible.value = true;
  148. console.log("dialogVisible 的值:", dialogVisible.value); // 添加日志确认
  149. };
  150. // 保证发送消息时,滚动屏在底部
  151. const chatStore = useChatStore()
  152. const tabContent = ref(null);
  153. const isScrolling = ref(false); //判断用户是否在滚动
  154. const smoothScrollToBottom = async () => {
  155. // console.log('调用滚动到底部的方法')
  156. // await nextTick();
  157. const container = tabContent.value;
  158. // console.log(container, 'container')
  159. // console.log(isScrolling.value, 'isScrolling.value')
  160. if (!container) return;
  161. await nextTick(); // 确保在DOM更新后执行
  162. if (!isScrolling.value) {
  163. container.scrollTop = container.scrollHeight - container.offsetHeight;
  164. // container.scrollTop = container.scrollHeight;
  165. // container.scrollTop = container.offsetHeight;
  166. // container.scrollTop = container.scrollHeight + container.offsetHeight;
  167. // console.log(container.scrollHeight, container.offsetHeight, container.scrollHeight - container.offsetHeight, container.scrollTop, "总长度", "可视长度", "位置")
  168. }
  169. }
  170. const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 500, { trailing: false });
  171. watch(
  172. () => chatStore.messages,
  173. () => {
  174. // console.log('messages变化了')
  175. throttledSmoothScrollToBottom();
  176. // setTimeout(throttledSmoothScrollToBottom, 100);
  177. },
  178. { deep: true, immediate: true }
  179. );
  180. watch(
  181. activeTab,
  182. async () => {
  183. // console.log('activeTab变化了', activeTab.value)
  184. isScrolling.value = false; //回复滚动到底部方法
  185. await nextTick(); // 等待DOM更新
  186. throttledSmoothScrollToBottom();
  187. // setTimeout(throttledSmoothScrollToBottom, 100);
  188. },
  189. { deep: true, immediate: true }
  190. );
  191. // 获取token的核心函数
  192. const fnGetToken = () => {
  193. // console.log('进入fnGetToken')
  194. window.JWready = (ress) => {
  195. // console.log('进入JWready')
  196. try {
  197. ress = JSON.parse(ress)
  198. // console.log(ress, 'ress')
  199. } catch (error) {
  200. console.log(error, 'fnGetToken error')
  201. } //platform为5是app端
  202. // platform.value = ress.data.platform
  203. // 处理平台判断
  204. console.log(ress.data.platform, 'ress.data.platform')
  205. if (!ress.data.platform) {
  206. // 非App环境通过URL参数获取
  207. localStorage.setItem('localToken', decodeURIComponent(String(getQueryVariable('token'))))
  208. // localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w")
  209. } else {
  210. // App环境通过桥接获取
  211. useAppBridge().packageFun(
  212. 'JWgetStorage',
  213. (response) => {
  214. const res = JSON.parse(response) // 解析返回的结果
  215. localStorage.setItem('localToken', res.data)
  216. // localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w")
  217. },
  218. 5,
  219. {
  220. key: 'token'
  221. }
  222. )
  223. }
  224. }
  225. // console.log('出来了')
  226. // 触发App桥接
  227. useAppBridge().packageFun('JWwebReady', () => { }, 5, {})
  228. }
  229. // 在setTimeout中延迟执行
  230. setTimeout(() => {
  231. fnGetToken()
  232. }, 800)
  233. // const tabContainer = tabContent.value
  234. // let befortop = 0
  235. // tabContainer.addEventListener('scroll', () => {
  236. // const aftertop = tabContainer.scrollTop
  237. // if (aftertop - befortop > 0) {
  238. // console.log('向下滚动')
  239. // isScrolling.value = true
  240. // } else {
  241. // console.log('向上滚动')
  242. // isScrolling.value = false
  243. // }
  244. // befortop = aftertop
  245. // })
  246. const heightListener = () => {
  247. const tabContainer = tabContent.value;
  248. let befortop = 0;
  249. const scrollHandler = () => {
  250. const aftertop = tabContainer.scrollTop;
  251. // 新增底部判断逻辑
  252. const isBottom = aftertop + tabContainer.offsetHeight + 50 >= tabContainer.scrollHeight;
  253. if (activeTab.value === 'AIchat') {
  254. if (aftertop - befortop > 0) {
  255. // console.log('向下滚动');
  256. isScrolling.value = true;
  257. } else {
  258. // console.log('向上滚动');
  259. isScrolling.value = true;
  260. }
  261. // 添加底部状态检测
  262. if (isBottom) {
  263. // console.log('滚动到底部');
  264. isScrolling.value = false;
  265. }
  266. }
  267. befortop = aftertop;
  268. };
  269. // console.log(isScrolling.value, 'isScrolling.value')
  270. tabContainer.addEventListener('scroll', scrollHandler);
  271. };
  272. const throttledHeightListener = _.throttle(heightListener, 500, { trailing: false });
  273. onMounted(async () => {
  274. const isPhone =
  275. /phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone/i.test(
  276. navigator.userAgent
  277. )
  278. !isPhone &&
  279. localStorage.setItem('localToken', decodeURIComponent(String(getQueryVariable('token'))))
  280. setHeight(document.getElementById("testId")); // 给父组件发送窗口高度
  281. await chatStore.getUserCount();
  282. throttledSmoothScrollToBottom();
  283. throttledHeightListener();
  284. })
  285. </script>
  286. <template>
  287. <div class="homepage" id="testId">
  288. <el-container>
  289. <!-- AI小财神头部 logo 次数 公告 -->
  290. <el-header class="homepage-head">
  291. <!-- logo -->
  292. <div class="homepage-logo">
  293. <img :src="logo" alt="图片加载失败" class="logo1" />
  294. <img :src="madeInHL" alt="图片加载失败" class="logo2" />
  295. </div>
  296. <div class="homepage-right-group">
  297. <div class="count-badge" @click="showCount">
  298. <img :src="getCountAll" class="action-btn" />
  299. <div class="count-number">{{ UserCount }}</div>
  300. </div>
  301. <img :src="announcementBtn" class="announcement-btn action-btn" @click="showAnnouncement" />
  302. </div>
  303. </el-header>
  304. <!-- 主体部分小人 问题轮询图 对话内容 -->
  305. <el-main class="homepage-body">
  306. <div class="main-wrapper">
  307. <section class="tab-section">
  308. <div class="tab-container">
  309. <div v-for="(tab, index) in tabs" :key="tab.name" @click="setActiveTab(tab.name, index)"
  310. :class="['tab-item', { active: activeIndex === index && !isAnnouncementVisible }]">
  311. <span>{{ tab.label }}</span>
  312. </div>
  313. </div>
  314. </section>
  315. <div class="tab-content" ref="tabContent">
  316. <component :is="activeComponent" :messages="messages" @updateMessage="updateMessage"
  317. @sendMessage="sendMessage" />
  318. </div>
  319. </div>
  320. </el-main>
  321. <!-- 尾部 问题输入框 深度思考 多语言 语音播报 -->
  322. <el-footer class="homepage-footer">
  323. <!-- 第一行按钮 -->
  324. <div class="footer-first-line">
  325. <div class="left-group">
  326. <img v-if="isThinking" :src="thinkActive" @click="toggleThink" class="action-btn" />
  327. <img v-else :src="thinkNoActive" @click="toggleThink" class="action-btn" />
  328. <img :src="languageBtn" @click="changeLanguage" class="action-btn" />
  329. <img v-if="isVoice" :src="voice" @click="toggleVoice" class="action-btn" />
  330. <img v-else :src="voiceNoActive" @click="toggleVoice" class="action-btn" />
  331. </div>
  332. <img v-if="!chatStore.isLoading" :src="sendBtn" @click="sendMessage" class="action-btn send-btn" />
  333. <div v-else>
  334. <el-icon class="is-loading">
  335. <Loading />
  336. </el-icon>
  337. </div>
  338. </div>
  339. <!-- 第二行输入框 -->
  340. <div class="footer-second-line">
  341. <img :src="msgBtn" class="msg-icon" />
  342. <el-input type="textarea" v-model="message" :autosize="{ minRows: 1, maxRows: 4 }" placeholder="给AI小财神发消息..."
  343. class="msg-input" @keydown.enter.exact.prevent="isLoading ? null : sendMessage()" resize="none">
  344. </el-input>
  345. </div>
  346. </el-footer>
  347. </el-container>
  348. <!-- 弹窗 -->
  349. <!-- 新增弹窗组件 -->
  350. <el-dialog v-model="dialogVisible" width="65%">
  351. <!-- 自定义标题插槽实现居中显示 -->
  352. <template #header>
  353. <div style="text-align: center">
  354. <span>活动规则</span>
  355. </div>
  356. </template>
  357. <!-- 中间内容部分 -->
  358. <p>
  359. 活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则活动规则
  360. </p>
  361. <template #footer>
  362. <!-- 添加一个div来包裹按钮并设置样式使其居中 -->
  363. <div style="text-align: center">
  364. <el-button style="background-color: orange; color: white; border: none" @click="dialogVisible = false">
  365. 去充值
  366. </el-button>
  367. </div>
  368. </template>
  369. </el-dialog>
  370. </div>
  371. </template>
  372. <style scoped>
  373. /* 标签栏 */
  374. .tab-container {
  375. display: flex;
  376. gap: 30px;
  377. margin-bottom: 10px;
  378. padding: 0 20px;
  379. justify-content: flex-end;
  380. /* 新增右对齐 */
  381. }
  382. .tab-item {
  383. cursor: pointer;
  384. padding: 8px 12px;
  385. font-size: clamp(18px, 3vw, 20px);
  386. color: #999;
  387. transition: all 0.3s;
  388. border-bottom: 2px solid transparent;
  389. font-weight: bold;
  390. }
  391. .tab-item.active {
  392. color: #000;
  393. border-color: #000;
  394. }
  395. .tab-item:not(.active):hover {
  396. color: #666;
  397. }
  398. .tab-content {
  399. /* height: 100%; */
  400. overflow-y: auto;
  401. overflow-x: hidden;
  402. scroll-behavior: smooth;
  403. /* 添加平滑滚动效果 */
  404. }
  405. @media (max-width: 768px) {
  406. .tab-container {
  407. gap: 15px;
  408. padding: 0 10px;
  409. }
  410. .tab-item {
  411. font-size: clamp(14px, 3vw, 16px);
  412. padding: 6px 10px;
  413. }
  414. }
  415. </style>
  416. <style scoped>
  417. .homepage {
  418. height: 100vh;
  419. margin: 0 auto;
  420. background-image: url(src/assets/img/homePage/bk.png);
  421. background-size: 100% 100%;
  422. background-repeat: no-repeat;
  423. background-position: center;
  424. display: flex;
  425. overflow: auto;
  426. }
  427. .homepage .el-container {
  428. height: 100%;
  429. flex-direction: column;
  430. /* 明确纵向排列 */
  431. display: flex;
  432. overflow: auto;
  433. }
  434. .el-container .el-header {
  435. height: 10%;
  436. /* 设置头部高度 */
  437. margin-top: 5px;
  438. }
  439. .el-container .el-main {
  440. overflow-y: hidden;
  441. overflow-x: hidden;
  442. /* 新增滚动条 */
  443. flex: 1 1 0%;
  444. min-height: 0;
  445. scrollbar-width: thin;
  446. scrollbar-color: #888 transparent;
  447. }
  448. .el-container .el-footer {
  449. /* height: 11%; */
  450. height: auto;
  451. min-height: 70px;
  452. gap: 5px;
  453. margin-top: 0;
  454. }
  455. .homepage-head {
  456. padding: 0px;
  457. /* 启用 flex 布局 */
  458. display: flex;
  459. position: relative;
  460. /* 左右分开布局 */
  461. justify-content: space-between;
  462. }
  463. .homepage-right-group {
  464. display: flex;
  465. gap: 8px;
  466. align-items: center;
  467. margin-left: auto;
  468. margin-right: 20px;
  469. }
  470. .homepage-right-group .action-btn {
  471. height: 40px;
  472. }
  473. .homepage-right-group .count-badge {
  474. position: relative;
  475. cursor: pointer;
  476. }
  477. .homepage-right-group .count-badge .count-number {
  478. position: absolute;
  479. top: 6px;
  480. right: 29px;
  481. color: #573dfc;
  482. font-size: 12px;
  483. font-weight: bold;
  484. }
  485. .homepage-right-group .announcement-btn {
  486. cursor: pointer;
  487. transition: transform 0.3s;
  488. }
  489. /* @keyframes tilt {
  490. 0% { transform: rotate(0deg); }
  491. 50% { transform: rotate(10deg); }
  492. 100% { transform: rotate(-10deg); }
  493. 130% { transform: rotate(0deg); }
  494. } */
  495. .homepage-right-group .announcement-btn:hover {
  496. transform: scale(1.3);
  497. /* animation: tilt 1s ease-in-out; */
  498. }
  499. .homepage-body {
  500. padding: 0px;
  501. height: calc(100% - 70px);
  502. /* 根据底部高度调整 */
  503. }
  504. .main-wrapper {
  505. height: 100%;
  506. display: flex;
  507. flex-direction: column;
  508. }
  509. .tab-section {
  510. flex-shrink: 0;
  511. /* 禁止伸缩 */
  512. }
  513. .tab-content {
  514. flex: 1;
  515. overflow-y: auto;
  516. min-height: 0;
  517. /* 关键:允许内容收缩 */
  518. }
  519. .homepage-logo {
  520. height: 100%;
  521. /* 改为根据内容自适应 */
  522. width: fit-content;
  523. display: flex;
  524. flex-direction: column;
  525. align-items: center;
  526. justify-content: center;
  527. /* 固定左间距 */
  528. margin-left: 20px;
  529. margin-right: auto;
  530. /* 新增相对定位 */
  531. position: relative;
  532. }
  533. /* 新增媒体查询适配小屏幕 */
  534. @media (max-width: 768px) {
  535. .homepage-logo {
  536. margin-left: 10px;
  537. left: 0;
  538. }
  539. }
  540. .logo1 {
  541. width: 120px;
  542. /* 固定 logo1 尺寸 */
  543. height: auto;
  544. margin-bottom: 8px;
  545. /* 添加间距 */
  546. }
  547. .logo2 {
  548. width: 80px;
  549. /* 缩小 logo2 尺寸 */
  550. height: auto;
  551. }
  552. /* 尾部 */
  553. .homepage-footer {
  554. display: flex;
  555. flex-direction: column;
  556. gap: 5px;
  557. /* margin-top: auto; */
  558. margin-bottom: 20px;
  559. flex-shrink: 0;
  560. height: auto;
  561. }
  562. .footer-first-line {
  563. display: flex;
  564. justify-content: space-between;
  565. align-items: center;
  566. margin-bottom: auto;
  567. flex-shrink: 0;
  568. }
  569. .left-group {
  570. display: flex;
  571. gap: 15px;
  572. }
  573. .action-btn {
  574. cursor: pointer;
  575. transition: transform 0.2s;
  576. height: 28px;
  577. }
  578. .action-btn:hover {
  579. transform: scale(1.05);
  580. }
  581. .send-btn {
  582. margin-left: auto;
  583. margin-right: 5px;
  584. }
  585. .footer-second-line {
  586. position: relative;
  587. display: flex;
  588. height: auto;
  589. align-items: flex-end;
  590. flex: 1;
  591. margin-top: auto;
  592. min-height: 34px;
  593. }
  594. .msg-icon {
  595. position: absolute;
  596. left: 12px;
  597. top: 50%;
  598. transform: translateY(-50%);
  599. width: 24px;
  600. z-index: 1;
  601. }
  602. .msg-input:deep(.el-textarea__inner) {
  603. border: none !important;
  604. box-shadow: none !important;
  605. overflow-y: auto !important;
  606. /* 强制显示滚动条 */
  607. transition: all 0.2s ease-out;
  608. /* 添加过渡效果 */
  609. }
  610. /* .msg-input:deep(.el-textarea__inner:focus) {
  611. border: none !important;
  612. box-shadow: 0 4px 12px rgba(89, 24, 241, 0.3) !important;
  613. } */
  614. .msg-input {
  615. min-height: 34px;
  616. max-height: 120px;
  617. width: calc(100% - 65px);
  618. border-radius: 20px;
  619. padding: 0px 20px 0 45px;
  620. font-size: 16px;
  621. transition: height 0.2s ease-out;
  622. /* 添加高度过渡效果 */
  623. overflow-y: hidden;
  624. /* 隐藏垂直滚动条 */
  625. box-shadow: 0 4px 12px rgba(89, 24, 241, 0.3);
  626. background: #fff;
  627. }
  628. .msg-input:focus {
  629. outline: none;
  630. }
  631. @media (max-width: 768px) {
  632. .action-btn {
  633. height: 28px;
  634. }
  635. .footer-second-line {
  636. height: 50px;
  637. }
  638. .msg-input {
  639. font-size: 16px;
  640. }
  641. }
  642. </style>