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.

1552 lines
40 KiB

5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
2 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
  1. <script setup>
  2. // 导入
  3. import { ref, computed, onMounted, watch, nextTick, onUnmounted, h } 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 Feedback from "./Feedback.vue";
  10. import Announcement from "./Announcement.vue";
  11. import { useAppBridge } from "../assets/js/useAppBridge.js";
  12. import { useDataStore } from "@/store/dataList.js";
  13. import { useChatStore } from "../store/chat";
  14. import { useEmotionAudioStore } from "../store/emotionAudio";
  15. import { useAudioStore } from "../store/audio";
  16. import _ from "lodash";
  17. import logo from "../assets/img/homePage/logo.png";
  18. import madeInHL from "../assets/img/homePage/madeInHL.png";
  19. import getCountAll from "../assets/img/homePage/get-count-all.png";
  20. import announcementBtn from "../assets/img/homePage/announcement.png";
  21. import thinkActive from "../assets/img/homePage/tail/think-active.png";
  22. import thinkNoActive from "../assets/img/homePage/tail/think-no-active.png";
  23. import languageBtn from "../assets/img/homePage/tail/language.png";
  24. import dbqbButton01 from "../assets/img/AiEmotion/dbqb-button01.png";
  25. import dbqbButton02 from "../assets/img/AiEmotion/dbqb-button02.png";
  26. import emotionButton01 from "../assets/img/AiEmotion/emotion-button01.png";
  27. import emotionButton02 from "../assets/img/AiEmotion/emotion-button02.png";
  28. import voice from "../assets/img/homePage/tail/voice.png";
  29. import voiceNoActive from "../assets/img/homePage/tail/voice-no-active.png";
  30. import sendBtn from "../assets/img/homePage/tail/send.png";
  31. import msgBtn from "../assets/img/homePage/tail/msg.png";
  32. import feedbackBtn from "../assets/img/Feedback/feedbackBtn.png";
  33. import AiEmotion from "./AiEmotion.vue";
  34. import HistoryRecord from "./components/HistoryRecord.vue";
  35. // import VConsole from "vconsole";
  36. // const vConsole = new VConsole();
  37. const isMobile = ref(null);
  38. // 获取 AiEmotion 组件的 ref
  39. const aiEmotionRef = ref(null);
  40. // 获取历史记录组件的 ref
  41. const historyRecordRef = ref(null);
  42. // import { useUserStore } from "../store/userPessionCode.js";
  43. const { getQueryVariable, setActiveTabIndex } = useDataStore();
  44. const dataStore = useDataStore();
  45. const chatStore = useChatStore();
  46. // 变量
  47. // 音频管理
  48. const emotionAudioStore = useEmotionAudioStore();
  49. const audioStore = useAudioStore();
  50. // 根据当前页面类型获取对应的音频store
  51. const getCurrentAudioStore = () => {
  52. return activeTab.value === "AiEmotion" ? emotionAudioStore : audioStore;
  53. };
  54. const isVoice = computed(() => {
  55. const currentStore = getCurrentAudioStore();
  56. return currentStore.isVoiceEnabled;
  57. });
  58. const toggleVoice = () => {
  59. const currentStore = getCurrentAudioStore();
  60. if (!currentStore.isVoiceEnabled) {
  61. // 如果语音功能关闭,先开启语音功能
  62. currentStore.toggleVoice();
  63. } else {
  64. // 如果语音功能开启,则切换播放/暂停状态
  65. if (currentStore.currentAudioUrl || currentStore.ttsUrl) {
  66. // 有音频时切换播放/暂停
  67. currentStore.togglePlayPause();
  68. } else {
  69. // 没有音频时关闭语音功能
  70. currentStore.toggleVoice();
  71. }
  72. }
  73. };
  74. // 将默认值改为从 sessionStorage 中获取,如果没有则使用默认值 'aifindCow'为第一个默认tab
  75. const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat");
  76. const activeIndex = ref(
  77. parseInt(sessionStorage.getItem("activeIndexAI") || "0")
  78. );
  79. const tabs = computed(() => [
  80. {
  81. name: "AIchat",
  82. label: "夺宝奇兵大模型",
  83. },
  84. // {
  85. // name: "AIfind",
  86. // label: "发现",
  87. // },
  88. {
  89. name: "AiEmotion",
  90. label: "AI情绪大模型",
  91. },
  92. ]);
  93. // 修改 setActiveTab 方法,添加一个可选参数 forceAIchat
  94. const setActiveTab = (tab, index, forceAIchat = false) => {
  95. isScrolling.value = false; //回复滚动到底部方法
  96. isAnnouncementVisible.value = false;
  97. // 重置输入框禁用状态,防止页面切换时状态残留
  98. isInputDisabled.value = false;
  99. if (forceAIchat && activeTab.value !== "AIchat") {
  100. activeTab.value = "AIchat";
  101. activeIndex.value = 0;
  102. sessionStorage.setItem("activeTabAI", "AIchat");
  103. sessionStorage.setItem("activeIndexAI", "0");
  104. } else {
  105. activeTab.value = tab;
  106. activeIndex.value = index;
  107. sessionStorage.setItem("activeTabAI", tab);
  108. sessionStorage.setItem("activeIndexAI", index.toString());
  109. }
  110. setActiveTabIndex(index);
  111. console.log(tab, index, "tab, index");
  112. setHeight(document.getElementById("testId")); // 给父组件发送窗口高度
  113. };
  114. // 修改 activeComponent 的计算逻辑
  115. const activeComponent = computed(() => {
  116. if (activeTab.value === "AIchat") {
  117. return AIchat;
  118. } else if (activeTab.value === "AIfind") {
  119. return AIfind;
  120. } else if (activeTab.value === "AiEmotion") {
  121. return AiEmotion; // 新增逻辑
  122. }
  123. });
  124. const activeTwoTab = computed(() => {
  125. if (isAnnouncementVisible.value) {
  126. return Announcement;
  127. } else {
  128. return Feedback;
  129. }
  130. });
  131. // 新增一个方法,调用时先判断是否处于 AIchat,若不在则跳转到 AIchat
  132. const ensureAIchat = () => {
  133. setActiveTab("AIchat", 0, true);
  134. };
  135. // 获取次数
  136. const UserCount = computed(() => chatStore.UserCount);
  137. const getCount = () => {
  138. console.log("点击了获取次数的按钮");
  139. };
  140. // 深度思考
  141. const isThinking = ref(true);
  142. const toggleThink = () => {
  143. isThinking.value = !isThinking.value;
  144. };
  145. // 发送消息
  146. const message = ref("");
  147. // 传输对象
  148. const messages = ref([]);
  149. // 信息加载状态
  150. const isLoading = computed(() => {
  151. chatStore.isLoading;
  152. });
  153. // 输入框禁用状态(用于情绪大模型)
  154. const isInputDisabled = ref(false);
  155. // 添加用户消息
  156. const updateMessage = (title) => {
  157. message.value = title;
  158. console.log("updateMessage 的值:", title);
  159. };
  160. watch(
  161. () => chatStore.announcementMsg,
  162. (newVal) => {
  163. console.log("监听到公告改变", chatStore.announcementMsg);
  164. if (chatStore.announcementMsg) {
  165. message.value = chatStore.announcementMsg;
  166. chatStore.announcementMsg = null;
  167. }
  168. }
  169. );
  170. watch(
  171. () => dataStore.isFeedback,
  172. async (newVal) => {
  173. if (!dataStore.isFeedback) {
  174. await nextTick();
  175. // 监听页面高度
  176. throttledHeightListener();
  177. }
  178. }
  179. );
  180. const sendMessage = async () => {
  181. if (
  182. localStorage.getItem("localToken") == null ||
  183. localStorage.getItem("localToken") == ""
  184. ) {
  185. ElMessage.error("请先登录");
  186. return;
  187. }
  188. // 检查输入内容是否为空
  189. if (!message.value || !message.value.trim()) {
  190. ElMessage.warning("输入内容不能为空");
  191. return;
  192. }
  193. isScrolling.value = false;
  194. // 注意:历史记录会在消息发送后自动更新,无需手动添加
  195. // 判断当前是否为 AiEmotion 组件
  196. if (activeTab.value === "AiEmotion") {
  197. // 禁用输入框
  198. isInputDisabled.value = true;
  199. // 调用 AiEmotion 组件的 handleSendMessage 方法
  200. aiEmotionRef.value?.handleSendMessage(message.value, () => {
  201. // 打字机效果完成后的回调,重新启用输入框
  202. isInputDisabled.value = false;
  203. });
  204. message.value = ""; // 清空输入框
  205. return;
  206. }
  207. // 调用 ensureAIchat 确保跳转到 AIchat 页面
  208. ensureAIchat();
  209. console.log(isInputDisabled.value, "isInputDisabled.value1111");
  210. if (isInputDisabled.value) return;
  211. isInputDisabled.value = true;
  212. console.log(isInputDisabled.value, "isInputDisabled.value2222");
  213. const messageContent = message.value;
  214. // 重置消息输入框
  215. message.value = "";
  216. setTimeout(() => {
  217. console.log("延时后添加消息", messageContent);
  218. // 发送消息时,设置 isLoading 为 true
  219. messages.value = [
  220. ...messages.value,
  221. {
  222. sender: "user",
  223. content: messageContent,
  224. timestamp: new Date().toISOString(),
  225. audioArray: [],
  226. audioStatus: true,
  227. },
  228. ];
  229. console.log(messages.value, "messages.value");
  230. }, 200);
  231. };
  232. // 重新启用输入框的方法
  233. const enableInput = () => {
  234. console.log("解除禁用");
  235. isInputDisabled.value = false;
  236. };
  237. // 处理历史记录选择
  238. const handleHistorySelect = (stockData) => {
  239. console.log("接收到历史记录数据:", stockData);
  240. // 如果当前不在AiEmotion页面,切换到AiEmotion页面
  241. // if (activeTab.value !== 'AiEmotion') {
  242. // setActiveTab('AiEmotion', 1);
  243. // }
  244. // 等待组件渲染完成后调用addStock方法
  245. nextTick(() => {
  246. if (aiEmotionRef.value && aiEmotionRef.value.addStock) {
  247. aiEmotionRef.value.addStock(stockData);
  248. } else {
  249. console.error("AiEmotion组件或addStock方法不可用");
  250. }
  251. });
  252. };
  253. // 公告
  254. // 新增一个变量来控制是否显示公告页面
  255. const isAnnouncementVisible = ref(false);
  256. const showAnnouncement = async () => {
  257. console.log("打开公告");
  258. dataStore.isFeedback = true; // 显示用户反馈页面
  259. isScrolling.value = false; //回复滚动到底部方法
  260. isAnnouncementVisible.value = true; // 显示公告页面
  261. if (isMobile.value) {
  262. if (historyRecordRef) {
  263. historyRecordRef.value.isCollapsed = true;
  264. }
  265. }
  266. };
  267. // 跳转用户反馈
  268. const showFeedback = () => {
  269. console.log("打开用户反馈");
  270. dataStore.isFeedback = true; // 显示用户反馈页面
  271. isAnnouncementVisible.value = false; // 显示反馈页面
  272. if (isMobile.value) {
  273. if (historyRecordRef) {
  274. historyRecordRef.value.isCollapsed = true;
  275. }
  276. }
  277. };
  278. // 点击剩余次数会弹出的弹窗
  279. // 新增一个 ref 来控制弹窗的显示与隐藏
  280. const dialogVisible = ref(false);
  281. // 获取次数
  282. const showCount = () => {
  283. console.log("显示剩余次数");
  284. // 显示弹窗
  285. dialogVisible.value = true;
  286. console.log("dialogVisible 的值:", dialogVisible.value); // 添加日志确认
  287. };
  288. // 保证发送消息时,滚动屏在底部
  289. const tabContent = ref(null);
  290. const isScrolling = ref(false); //判断用户是否在滚动
  291. const smoothScrollToBottom = async () => {
  292. // console.log("调用滚动到底部的方法");
  293. // await nextTick();
  294. const container = tabContent.value;
  295. // console.log(container, 'container')
  296. // console.log(isScrolling.value, 'isScrolling.value')
  297. if (!container) return;
  298. await nextTick(); // 确保在DOM更新后执行
  299. if (!isScrolling.value) {
  300. container.scrollTop = container.scrollHeight - container.offsetHeight;
  301. // container.scrollTop = container.scrollHeight;
  302. // container.scrollTop = container.offsetHeight;
  303. // container.scrollTop = container.scrollHeight + container.offsetHeight;
  304. // console.log(container.scrollHeight, container.offsetHeight, container.scrollHeight - container.offsetHeight, container.scrollTop, "总长度", "可视长度", "位置")
  305. }
  306. };
  307. const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 300, {
  308. trailing: false,
  309. });
  310. watch(
  311. () => chatStore.messages,
  312. () => {
  313. // console.log('messages变化了')
  314. // 只有在AIchat页面时才执行自动滚动
  315. if (activeTab.value === "AIchat") {
  316. throttledSmoothScrollToBottom();
  317. }
  318. // setTimeout(throttledSmoothScrollToBottom, 100);
  319. },
  320. { deep: true, immediate: true }
  321. );
  322. watch(
  323. () => chatStore.dbqbClickRecord,
  324. async (newValue, oldValue) => {
  325. const container = tabContent.value;
  326. if (!container) return;
  327. await nextTick(); // 确保在DOM更新后执行
  328. container.scrollTop = 0;
  329. }
  330. );
  331. watch(
  332. activeTab,
  333. async () => {
  334. console.log("activeTab变化了", activeTab.value);
  335. if (activeTab.value == "AIchat" || activeTab.value == "AiEmotion") {
  336. if (historyRecordRef.value && historyRecordRef.value.getHistoryList) {
  337. historyRecordRef.value.getHistoryList({
  338. model: activeTab.value == "AIchat" ? 1 : 2,
  339. token: localStorage.getItem("localToken"),
  340. });
  341. }
  342. }
  343. if (activeTab.value === "AIchat") {
  344. isScrolling.value = false; //回复滚动到底部方法
  345. setTimeout(() => {
  346. throttledSmoothScrollToBottom();
  347. }, 100);
  348. }
  349. // AiEmotion页面不执行自动滚动,避免刷新后滚动到底部
  350. // setTimeout(throttledSmoothScrollToBottom, 100);
  351. },
  352. { deep: true, immediate: true }
  353. );
  354. // 获取token的核心函数
  355. const fnGetToken = () => {
  356. // console.log('进入fnGetToken')
  357. window.JWready = (ress) => {
  358. // console.log('进入JWready')
  359. try {
  360. ress = JSON.parse(ress);
  361. // console.log(ress, 'ress')
  362. } catch (error) {
  363. console.log(error, "fnGetToken error");
  364. } //platform为5是app端
  365. // platform.value = ress.data.platform
  366. // 处理平台判断
  367. console.log(ress.data.platform, "ress.data.platform");
  368. if (!ress.data.platform) {
  369. // 非App环境通过URL参数获取
  370. localStorage.setItem(
  371. "localToken",
  372. decodeURIComponent(String(getQueryVariable("token")))
  373. );
  374. // localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w")
  375. } else {
  376. // App环境通过桥接获取
  377. useAppBridge().packageFun(
  378. "JWgetStorage",
  379. (response) => {
  380. const res = JSON.parse(response); // 解析返回的结果
  381. localStorage.setItem("localToken", res.data);
  382. // localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w")
  383. },
  384. 5,
  385. {
  386. key: "token",
  387. }
  388. );
  389. }
  390. };
  391. // console.log('出来了')
  392. // 触发App桥接
  393. useAppBridge().packageFun("JWwebReady", () => {}, 5, {});
  394. };
  395. // 在setTimeout中延迟执行
  396. setTimeout(() => {
  397. fnGetToken();
  398. }, 800);
  399. const heightListener = () => {
  400. const tabContainer = tabContent.value;
  401. let befortop = 0;
  402. const scrollHandler = () => {
  403. const aftertop = tabContainer.scrollTop;
  404. // 新增底部判断逻辑
  405. const isBottom =
  406. aftertop + tabContainer.offsetHeight + 70 >= tabContainer.scrollHeight;
  407. if (activeTab.value === "AIchat") {
  408. if (aftertop - befortop > 0) {
  409. // console.log("向下滚动");
  410. isScrolling.value = true;
  411. } else {
  412. // console.log("向上滚动");
  413. isScrolling.value = true;
  414. }
  415. // 添加底部状态检测
  416. if (isBottom) {
  417. // console.log("滚动到底部");
  418. isScrolling.value = false;
  419. }
  420. }
  421. befortop = aftertop;
  422. };
  423. // console.log(isScrolling.value, 'isScrolling.value')
  424. tabContainer.addEventListener("scroll", scrollHandler);
  425. };
  426. const throttledHeightListener = _.throttle(heightListener, 500, {
  427. trailing: false,
  428. });
  429. // const goToRecharge = () => {
  430. // console.log("点击充值");
  431. // // http://39.101.133.168:8919/payment/recharge/index?
  432. // // url=http%3A%2F%2Flocalhost%3A8080%2FLiveActivity%2Fpck
  433. // // &platform=1
  434. // // &token=+S4h5QEE1hTIb4CxphrnbZi0+fEeMx8pywnIlrmTmo4QO6IolWnVWu5r+J4rKXMwK41UPfKqyIp+RvWmtM8
  435. // const userAgent = navigator.userAgent.toLowerCase();
  436. // const mobileKeywords = ["mobile", "android", "iphone", "ipad", "ipod"];
  437. // const isMobile = mobileKeywords.some((keyword) =>
  438. // userAgent.includes(keyword)
  439. // );
  440. // console.log(isMobile ? "手机" : "电脑");
  441. // const url = encodeURI("http://39.101.133.168:8857/aixiaocaishen/homePage");
  442. // console.log(url, "url");
  443. // const platform = isMobile ? 2 : 1;
  444. // const token = encodeURIComponent(localStorage.getItem("localToken"));
  445. // console.log(token, "token");
  446. // const rechargeUrl =
  447. // "http://39.101.133.168:8919/payment/recharge/index?" +
  448. // "url=" +
  449. // url +
  450. // "&platform=" +
  451. // platform +
  452. // "&token=" +
  453. // token;
  454. // console.log(rechargeUrl, "rechargeUrl");
  455. // window.location.href = rechargeUrl;
  456. // // window.open(rechargeUrl)
  457. // };
  458. const adjustFooterPosition = (height) => {
  459. const html = document.querySelector("html");
  460. const body = document.querySelector("body");
  461. const isAndroid = /Android/i.test(navigator.userAgent);
  462. if (isAndroid) {
  463. console.log("是安卓设备");
  464. console.log("window.visualViewport", window.visualViewport.height);
  465. const homePage = document.querySelector(".homepage");
  466. homePage.style.height = `${height}px`;
  467. // homePage.style.height = `460px`;
  468. html.scrollTop = 0;
  469. } else {
  470. console.log("非安卓设备");
  471. console.log("调整底部位置", height);
  472. const homePage = document.querySelector(".homepage");
  473. homePage.style.height = `${height}px`;
  474. html.scrollTop = 0;
  475. }
  476. setTimeout(() => {
  477. // 隐藏滚动条
  478. html.style.overflow = "hidden";
  479. body.style.overflow = "hidden";
  480. }, 200);
  481. };
  482. const onFocus = function () {
  483. const visualViewport = window.visualViewport;
  484. // 获取可视区域高度
  485. setTimeout(() => {
  486. console.log("输入框聚焦");
  487. console.log(visualViewport.height, "visualViewport.height");
  488. const keyboardHeight = window.innerHeight - visualViewport.height;
  489. console.log(window.innerHeight, "window.innerHeight");
  490. console.log(keyboardHeight, "keyboardHeight");
  491. adjustFooterPosition(visualViewport.height);
  492. }, 200);
  493. };
  494. const onBlur = function () {
  495. const visualViewport = window.visualViewport;
  496. setTimeout(() => {
  497. console.log("输入框失焦");
  498. const keyboardHeight = window.innerHeight - visualViewport.height;
  499. console.log(window.innerHeight, "window.innerHeight");
  500. console.log(visualViewport.height, "visualViewport.height");
  501. console.log(keyboardHeight, "keyboardHeight");
  502. adjustFooterPosition(visualViewport.height);
  503. }, 200);
  504. };
  505. // window.addEventListener("resize", () => {
  506. // // 检测是否为iOS设备
  507. // const isIOS = /iPhone|iPad|iPod|ios/i.test(navigator.userAgent);
  508. // console.log("是否为iOS设备:", isIOS);
  509. // if (!isIOS) {
  510. // console.log("窗口大小变化");
  511. // const homePage = document.querySelector(".homepage");
  512. // homePage.style.height = `${window.innerHeight}px`;
  513. // }
  514. // });
  515. let touchmoveHandlerRef = null;
  516. const touchmoveHandler = (e) => {
  517. if (!dataStore.isFeedback) {
  518. // 判断触摸目标是否在可滚动区域内
  519. const isScrollableArea = e.target.closest(".tab-content");
  520. // 如果不在可滚动区域,则阻止滚动
  521. if (!isScrollableArea) {
  522. e.preventDefault();
  523. }
  524. }
  525. };
  526. const judgeDevice = async () => {
  527. // 延时300ms
  528. await new Promise((resolve) => setTimeout(resolve, 200));
  529. const userAgent = navigator.userAgent;
  530. isMobile.value =
  531. /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
  532. userAgent
  533. );
  534. console.log("当前设备为:", isMobile.value ? "移动端" : "PC端");
  535. };
  536. const throttledJudgeDevice = _.throttle(judgeDevice, 300, {
  537. trailing: false,
  538. });
  539. const expandHistory = () => {
  540. // if (activeTab.value == "AIchat" || activeTab.value == "AiEmotion") {
  541. // historyRecordRef.value.getHistoryList({
  542. // token: localStorage.getItem("localToken"),
  543. // model: activeTab.value == "AIchat" ? 1 : 2,
  544. // });
  545. // }
  546. if (
  547. historyRecordRef.value &&
  548. historyRecordRef.value.isCollapsed !== undefined
  549. ) {
  550. console.log("存在");
  551. historyRecordRef.value.isCollapsed = !historyRecordRef.value.isCollapsed;
  552. }
  553. };
  554. const backToHome = () => {
  555. if (isMobile.value) {
  556. console.log("用户是移动端");
  557. // 调用原生方法跳转到首页
  558. uni.postMessage({
  559. data: {
  560. val: {
  561. name: "JWopenView",
  562. extra: {
  563. data: {
  564. type: 3,
  565. },
  566. },
  567. },
  568. },
  569. });
  570. } else {
  571. console.log("用户是pc端");
  572. const env = import.meta.env.VITE_ENV;
  573. console.log("当前的环境为:", env);
  574. if (env == "development" || env == "test") {
  575. window.parent.location.href =
  576. "http://121.89.234.155:8807/hljw/homepage?menu=999999991";
  577. } else if (env == "product") {
  578. window.parent.location.href =
  579. "https://web.homilychart.com/product/hljw/homepage?menu=999999991";
  580. } else if (env == "production") {
  581. window.parent.location.href =
  582. "https://web.homilychart.com/hljw/homepage?menu=999999991";
  583. }
  584. // window.parent.location.href = window.parent.document.referrer
  585. }
  586. };
  587. onMounted(async () => {
  588. throttledJudgeDevice();
  589. // 禁用全局触摸滚动
  590. touchmoveHandlerRef = touchmoveHandler;
  591. document.addEventListener("touchmove", touchmoveHandlerRef, {
  592. passive: false,
  593. });
  594. setHeight(document.getElementById("testId")); // 给父组件发送窗口高度
  595. // 获取次数
  596. await chatStore.getUserCount();
  597. // 滚动到底部
  598. throttledSmoothScrollToBottom();
  599. // 监听页面高度
  600. throttledHeightListener();
  601. // 添加输入框焦点处理
  602. // handleInputFocus();
  603. // 初始化视口高度变量
  604. // updateAppHeight();
  605. // 添加原生事件监听器
  606. window.addEventListener("resize", throttledJudgeDevice);
  607. });
  608. onUnmounted(() => {
  609. window.removeEventListener("resize", throttledJudgeDevice);
  610. if (touchmoveHandlerRef) {
  611. console.log("卸载touchmoveHandlerRef组件");
  612. document.removeEventListener("touchmove", touchmoveHandlerRef);
  613. }
  614. });
  615. </script>
  616. <template>
  617. <div class="homepage" id="testId">
  618. <!-- 历史记录组件 -->
  619. <HistoryRecord
  620. ref="historyRecordRef"
  621. :current-type="activeTab"
  622. @selectRecord="handleHistorySelect"
  623. :isMobile="isMobile"
  624. @showAnnouncement="showAnnouncement"
  625. @showFeedback="showFeedback"
  626. />
  627. <div
  628. v-if="isMobile && !historyRecordRef?.isCollapsed"
  629. class="zhezhao"
  630. @click="expandHistory"
  631. ></div>
  632. <el-container
  633. v-if="!dataStore.isFeedback"
  634. class="main-container"
  635. :class="{
  636. collapsed: historyRecordRef?.isCollapsed && !isMobile,
  637. unCollapsed: !historyRecordRef?.isCollapsed && !isMobile,
  638. }"
  639. >
  640. <!-- AI小财神头部 logo 次数 公告 -->
  641. <el-header class="homepage-head">
  642. <!-- logo -->
  643. <div class="homepage-logo" v-if="isMobile">
  644. <img
  645. class="expand"
  646. @click="expandHistory"
  647. src="https://d31zlh4on95l9h.cloudfront.net/images/37fe3d79a8a700f6c674c9f0e7af066b.png"
  648. alt="icon"
  649. />
  650. <img :src="logo" alt="图片加载失败" class="logo1" />
  651. <!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> -->
  652. </div>
  653. <div class="homepage-right-group" v-if="isMobile">
  654. <div class="count-badge" @click="showCount">
  655. <img
  656. src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
  657. class="action-btn"
  658. />
  659. <div class="count-number">{{ UserCount }}</div>
  660. <div class="clickGetCount">点击获取次数</div>
  661. </div>
  662. <div class="backToHomeBtn" @click="backToHome()">
  663. <img
  664. src="https://d31zlh4on95l9h.cloudfront.net/images/d8b388e461423f79087ddbe016002217.png"
  665. alt="返回首页"
  666. class="backImg"
  667. />
  668. <div class="backContent">返回首页</div>
  669. </div>
  670. <!-- <img
  671. :src="announcementBtn"
  672. class="announcement-btn action-btn"
  673. @click="showAnnouncement"
  674. />
  675. <img
  676. :src="feedbackBtn"
  677. class="announcement-btn action-btn"
  678. @click="showFeedback"
  679. /> -->
  680. </div>
  681. </el-header>
  682. <!-- 主体部分小人 问题轮询图 对话内容 -->
  683. <el-main class="homepage-body">
  684. <div class="main-wrapper">
  685. <section class="tab-section">
  686. <div
  687. class="tab-container"
  688. :class="{
  689. pcTabContainer: !isMobile,
  690. }"
  691. >
  692. <div
  693. v-for="(tab, index) in tabs"
  694. :key="tab.name"
  695. @click="setActiveTab(tab.name, index)"
  696. :class="[
  697. 'tab-item',
  698. { active: activeIndex === index && !isAnnouncementVisible },
  699. ]"
  700. >
  701. <span>{{ tab.label }}</span>
  702. </div>
  703. <div v-if="!isMobile" class="pc-count-badge">
  704. <div class="pc-countBtn" @click="showCount">
  705. <div class="pc-action-btn">
  706. <div class="pc-count-number">{{ UserCount }}</div>
  707. </div>
  708. <div class="pc-clickGetCount">点击获取次数</div>
  709. </div>
  710. <div class="pc-backToHomeBtn" @click="backToHome()">
  711. <img
  712. src="https://d31zlh4on95l9h.cloudfront.net/images/d8b388e461423f79087ddbe016002217.png"
  713. alt="返回首页"
  714. class="pc-backImg"
  715. />
  716. <div class="pc-backContent">返回首页</div>
  717. </div>
  718. </div>
  719. </div>
  720. </section>
  721. <div
  722. class="tab-content"
  723. :class="{
  724. pcTabContent: !isMobile,
  725. }"
  726. ref="tabContent"
  727. >
  728. <component
  729. :is="activeComponent"
  730. :messages="messages"
  731. @updateMessage="updateMessage"
  732. @sendMessage="sendMessage"
  733. @ensureAIchat="ensureAIchat"
  734. @enableInput="enableInput"
  735. ref="aiEmotionRef"
  736. />
  737. </div>
  738. </div>
  739. </el-main>
  740. <!-- 尾部 问题输入框 深度思考 多语言 语音播报 -->
  741. <el-footer
  742. class="homepage-footer"
  743. :class="{
  744. pcFooter: !isMobile,
  745. }"
  746. id="input"
  747. >
  748. <!-- 第一行按钮 -->
  749. <div class="footer-first-line">
  750. <div class="left-group">
  751. <!-- <img v-if="isThinking" :src="thinkActive" @click="toggleThink" class="action-btn" />
  752. <img v-else :src="thinkNoActive" @click="toggleThink" class="action-btn" />
  753. <img :src="languageBtn" @click="changeLanguage" class="action-btn" /> -->
  754. <!-- 夺宝奇兵大模型按钮 -->
  755. <img
  756. :src="activeTab === 'AIchat' ? dbqbButton01 : dbqbButton02"
  757. @click="setActiveTab('AIchat', 0)"
  758. class="action-btn model-btn"
  759. alt="夺宝奇兵大模型"
  760. />
  761. <!-- AI情绪大模型按钮 -->
  762. <img
  763. :src="
  764. activeTab === 'AiEmotion' ? emotionButton01 : emotionButton02
  765. "
  766. @click="setActiveTab('AiEmotion', 1)"
  767. class="action-btn model-btn"
  768. alt="AI情绪大模型"
  769. />
  770. <!-- <img v-if="
  771. getCurrentAudioStore().isVoiceEnabled &&
  772. getCurrentAudioStore().isPlaying
  773. " :src="voice" @click="toggleVoice" class="action-btn" style="animation: pulse 1.5s infinite" />
  774. <img v-else-if="
  775. getCurrentAudioStore().isVoiceEnabled &&
  776. !getCurrentAudioStore().isPlaying
  777. " :src="voiceNoActive" @click="toggleVoice" class="action-btn" />
  778. <img v-else :src="voiceNoActive" @click="toggleVoice" class="action-btn" /> -->
  779. </div>
  780. </div>
  781. <!-- 第二行输入框 -->
  782. <div class="footer-second-line">
  783. <!-- <img :src="msgBtn" class="msg-icon" /> -->
  784. <div class="input-container">
  785. <el-input
  786. type="textarea"
  787. v-model="message"
  788. @focus="onFocus"
  789. @blur="onBlur"
  790. :autosize="{ minRows: 1, maxRows: 4 }"
  791. placeholder="请输入股票名称或股票代码..."
  792. class="msg-input"
  793. @keydown.enter.exact.prevent="
  794. isLoading || isInputDisabled ? null : sendMessage()
  795. "
  796. :disabled="isInputDisabled"
  797. resize="none"
  798. >
  799. </el-input>
  800. <img
  801. :src="
  802. isInputDisabled
  803. ? 'https://d31zlh4on95l9h.cloudfront.net/images/aa192bcbc1682c97e1bc6fb422f2afff.png'
  804. : 'https://d31zlh4on95l9h.cloudfront.net/images/e6ec2ae238ced85b74e0912e988f243e.png'
  805. "
  806. @click="sendMessage"
  807. class="action-btn send-btn-inner"
  808. :style="{
  809. opacity: isInputDisabled ? 0.5 : 1,
  810. cursor: isInputDisabled ? 'not-allowed' : 'pointer',
  811. }"
  812. />
  813. </div>
  814. </div>
  815. </el-footer>
  816. </el-container>
  817. <el-container
  818. v-else
  819. class="main-container"
  820. :class="{
  821. collapsed: historyRecordRef?.isCollapsed && !isMobile,
  822. unCollapsed: !historyRecordRef?.isCollapsed && !isMobile,
  823. }"
  824. >
  825. <el-header class="homepage-head">
  826. <!-- logo -->
  827. <div class="homepage-logo">
  828. <img :src="logo" alt="图片加载失败" class="logo1" />
  829. <!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> -->
  830. </div>
  831. <div class="homepage-right-group">
  832. <div class="count-badge" @click="showCount">
  833. <img
  834. src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
  835. class="action-btn"
  836. />
  837. <div class="count-number">{{ UserCount }}</div>
  838. <div class="clickGetCount">点击获取次数</div>
  839. </div>
  840. <div class="backToHomeBtn" @click="backToHome()">
  841. <img
  842. src="https://d31zlh4on95l9h.cloudfront.net/images/d8b388e461423f79087ddbe016002217.png"
  843. alt="返回首页"
  844. class="backImg"
  845. />
  846. <div class="backContent">返回首页</div>
  847. </div>
  848. <!-- <img
  849. :src="announcementBtn"
  850. class="announcement-btn action-btn"
  851. @click="showAnnouncement"
  852. />
  853. <img
  854. :src="feedbackBtn"
  855. class="announcement-btn action-btn"
  856. @click="showFeedback"
  857. /> -->
  858. </div>
  859. </el-header>
  860. <!-- 主体部分小人 问题轮询图 对话内容 -->
  861. <el-main class="homepage-body">
  862. <component :is="activeTwoTab" />
  863. </el-main>
  864. </el-container>
  865. <!-- 弹窗 -->
  866. <!-- 新增弹窗组件 -->
  867. <el-dialog v-model="dialogVisible" max-width="65%">
  868. <!-- 自定义标题插槽实现居中显示 -->
  869. <template #header>
  870. <div style="text-align: center">
  871. <span>活动规则</span>
  872. </div>
  873. </template>
  874. <!-- 中间内容部分 -->
  875. <div class="ruleContent">
  876. <p>试运行期间AI小财神可以检索全市场数据</p>
  877. <p>每个市场20支股票股票详情参见公告页面</p>
  878. <!-- <p>弘历会员每人每日拥有10次检索机会</p> -->
  879. </div>
  880. <!-- <template #footer> -->
  881. <!-- 添加一个div来包裹按钮并设置样式使其居中 -->
  882. <!-- <div style="text-align: center"> -->
  883. <!-- <el-button style="background-color: orange; color: white; border: none" @click="goToRecharge"> -->
  884. <!-- 去充值 -->
  885. <!-- </el-button> -->
  886. <!-- </div> -->
  887. <!-- </template> -->
  888. </el-dialog>
  889. </div>
  890. </template>
  891. <style scoped>
  892. /* 标签栏 */
  893. .tab-container {
  894. display: flex;
  895. margin-bottom: 10px;
  896. height: 100%;
  897. position: relative;
  898. justify-content: center;
  899. align-items: center;
  900. gap: 25vw;
  901. /* 新增右对齐 */
  902. }
  903. .pcTabContainer {
  904. }
  905. .tab-item {
  906. cursor: pointer;
  907. padding: 8px 12px;
  908. font-size: clamp(18px, 3vw, 20px);
  909. /* color: #999; */
  910. color: #fff;
  911. transition: all 0.3s;
  912. border-bottom: 2px solid transparent;
  913. font-weight: bold;
  914. }
  915. .tab-item.active {
  916. /* color: #000;
  917. border-color: #000; */
  918. background: linear-gradient(0deg, #ffffff, #fec13e);
  919. -webkit-background-clip: text;
  920. background-clip: text;
  921. -webkit-text-fill-color: transparent;
  922. color: transparent;
  923. border-color: #fec13e;
  924. }
  925. .tab-item:not(.active):hover {
  926. color: #999999;
  927. }
  928. .tab-content {
  929. overflow-y: auto;
  930. overflow-x: hidden;
  931. scroll-behavior: smooth;
  932. height: 100%;
  933. /* 添加平滑滚动效果 */
  934. }
  935. /* .pcTabContent {
  936. margin: 0 6%;
  937. } */
  938. @media (max-width: 768px) {
  939. .tab-container {
  940. gap: 15px;
  941. padding: 0 10px;
  942. }
  943. .tab-item {
  944. font-size: clamp(14px, 3vw, 16px);
  945. padding: 6px 10px;
  946. }
  947. }
  948. </style>
  949. <style scoped>
  950. html {
  951. height: 100dvh;
  952. overflow: hidden !important;
  953. position: fixed;
  954. margin: 0;
  955. padding: 0;
  956. -webkit-overflow-scrolling: auto;
  957. /* 禁用 iOS 弹性滚动 */
  958. }
  959. body {
  960. height: 100dvh;
  961. overflow: clip;
  962. margin: 0;
  963. padding: 0;
  964. -webkit-overflow-scrolling: auto;
  965. /* 禁用 iOS 弹性滚动 */
  966. position: fixed;
  967. }
  968. #app {
  969. overflow: hidden;
  970. height: 100%;
  971. margin: 0;
  972. padding: 0;
  973. }
  974. .homepage {
  975. /* height: var(--app-height, 100vh); */
  976. height: var(--app-height, 100vh);
  977. margin: 0 auto;
  978. background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/2dc3c13a74100b906e809d26b66db211.png");
  979. background-size: 100% 100%;
  980. background-repeat: no-repeat;
  981. background-position: center;
  982. display: flex;
  983. flex-direction: row;
  984. /* 改为水平布局 */
  985. overflow: hidden;
  986. position: fixed;
  987. top: 0;
  988. left: 0;
  989. right: 0;
  990. bottom: 0;
  991. width: 100%;
  992. /* -webkit-overflow-scrolling: touch; */
  993. }
  994. .main-container {
  995. flex: 1;
  996. transition: margin-left 0.3s ease;
  997. display: flex;
  998. flex-direction: column;
  999. overflow: hidden;
  1000. }
  1001. .main-container.unCollapsed {
  1002. margin-left: 300px; /* 为历史记录组件留出空间 */
  1003. }
  1004. /* 当历史记录组件折叠时调整主容器边距 */
  1005. .main-container.collapsed {
  1006. margin-left: 3%;
  1007. }
  1008. .zhezhao {
  1009. width: 100%;
  1010. height: 100%;
  1011. background-color: rgba(0, 0, 0, 0.5);
  1012. z-index: 100;
  1013. position: fixed;
  1014. }
  1015. /* 移动端适配 */
  1016. @media (max-width: 768px) {
  1017. .homepage {
  1018. background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/90d31d7052e729c63acb9e2cb94d1307.png");
  1019. }
  1020. .main-container {
  1021. /* margin-left: 280px; */
  1022. }
  1023. .main-container.unCollapsed {
  1024. margin-left: 280px;
  1025. }
  1026. .main-container.collapsed {
  1027. margin-left: 40px;
  1028. }
  1029. }
  1030. .homepage .el-container {
  1031. height: 100%;
  1032. flex-direction: column;
  1033. display: flex;
  1034. width: 100%;
  1035. overflow: hidden;
  1036. /* 防止容器滚动 */
  1037. }
  1038. .el-container .el-header {
  1039. flex-shrink: 0;
  1040. /* 防止头部压缩 */
  1041. height: auto;
  1042. min-height: 60px;
  1043. padding: 5px 0;
  1044. position: sticky;
  1045. top: 0;
  1046. z-index: 10;
  1047. /* background-color: rgba(255, 255, 255, 0.9); */
  1048. }
  1049. .el-container .el-main {
  1050. flex: 1;
  1051. /* 自动占据剩余空间 */
  1052. overflow: hidden;
  1053. /* 主容器不滚动 */
  1054. display: flex;
  1055. flex-direction: column;
  1056. min-height: 0;
  1057. /* 允许内容区域缩小 */
  1058. position: relative;
  1059. height: auto;
  1060. }
  1061. .el-container .el-footer {
  1062. flex-shrink: 0;
  1063. height: auto;
  1064. min-height: 70px;
  1065. position: sticky;
  1066. bottom: 0;
  1067. z-index: 20;
  1068. background-color: rgba(211, 24, 24, 0);
  1069. box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
  1070. -webkit-transform: translateZ(0);
  1071. transform: translateZ(0);
  1072. padding-bottom: env(safe-area-inset-bottom, 0);
  1073. /* 适配iPhone X及以上的底部安全区域 */
  1074. }
  1075. .homepage-head {
  1076. padding: 0px;
  1077. display: flex;
  1078. position: relative;
  1079. justify-content: space-between;
  1080. width: 100%;
  1081. }
  1082. .homepage-right-group {
  1083. display: flex;
  1084. gap: 8px;
  1085. align-items: center;
  1086. margin-left: auto;
  1087. margin-right: 20px;
  1088. }
  1089. .homepage-right-group .action-btn {
  1090. height: 40px;
  1091. }
  1092. .count-badge {
  1093. position: relative;
  1094. cursor: pointer;
  1095. }
  1096. .count-badge:hover {
  1097. transform: scale(1.05);
  1098. }
  1099. .count-number {
  1100. position: absolute;
  1101. top: 16px;
  1102. right: 0px;
  1103. width: 68%;
  1104. text-align: center;
  1105. color: #6a00ff;
  1106. font-size: 14px;
  1107. font-weight: bold;
  1108. }
  1109. .clickGetCount {
  1110. width: 100%;
  1111. text-align: center;
  1112. color: white;
  1113. font-size: 12px;
  1114. }
  1115. .backToHomeBtn {
  1116. display: flex;
  1117. flex-direction: column;
  1118. justify-content: center;
  1119. align-items: center;
  1120. }
  1121. .backImg {
  1122. width: 100%;
  1123. height: auto;
  1124. }
  1125. .backContent {
  1126. width: 100%;
  1127. text-align: center;
  1128. color: white;
  1129. font-size: 12px;
  1130. white-space: nowrap;
  1131. }
  1132. .pc-count-badge {
  1133. width: 200px;
  1134. height: 100%;
  1135. position: absolute;
  1136. right: 20px;
  1137. display: flex;
  1138. }
  1139. .pc-countBtn {
  1140. width: 65%;
  1141. height: 100%;
  1142. position: relative;
  1143. }
  1144. .pc-countBtn:hover {
  1145. transform: scale(1.05);
  1146. }
  1147. .pc-action-btn {
  1148. width: 100%;
  1149. height: 70%;
  1150. background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png");
  1151. background-repeat: no-repeat;
  1152. background-size: 100% 100%;
  1153. }
  1154. .pc-count-number {
  1155. position: absolute;
  1156. top: 15px;
  1157. right: 4px;
  1158. width: 68%;
  1159. text-align: center;
  1160. color: #6a00ff;
  1161. font-size: 15px;
  1162. font-weight: bold;
  1163. }
  1164. .pc-clickGetCount {
  1165. width: 100%;
  1166. text-align: center;
  1167. color: white;
  1168. font-size: 12px;
  1169. }
  1170. .pc-backToHomeBtn {
  1171. width: 35%;
  1172. height: 100%;
  1173. display: flex;
  1174. flex-direction: column;
  1175. align-items: center;
  1176. }
  1177. .pc-backImg {
  1178. width: auto;
  1179. height: 70%;
  1180. }
  1181. .pc-backContent {
  1182. width: 100%;
  1183. text-align: center;
  1184. color: white;
  1185. font-size: 12px;
  1186. }
  1187. .pc-backToHomeBtn:hover {
  1188. transform: scale(1.05);
  1189. }
  1190. .homepage-right-group .announcement-btn {
  1191. cursor: pointer;
  1192. transition: transform 0.3s;
  1193. }
  1194. .homepage-right-group .announcement-btn:hover {
  1195. transform: scale(1.3);
  1196. }
  1197. .homepage-body {
  1198. padding: 0px;
  1199. display: flex;
  1200. flex-direction: column;
  1201. flex: 1;
  1202. min-height: 0;
  1203. /* 允许内容区域缩小 */
  1204. overflow: hidden;
  1205. }
  1206. .main-wrapper {
  1207. height: 100%;
  1208. display: flex;
  1209. flex-direction: column;
  1210. flex: 1;
  1211. min-height: 0;
  1212. /* 允许内容区域缩小 */
  1213. }
  1214. .tab-section {
  1215. flex-shrink: 0;
  1216. /* 禁止伸缩 */
  1217. }
  1218. .tab-content {
  1219. flex: 1;
  1220. overflow-y: auto;
  1221. min-height: 0;
  1222. /* 关键:允许内容收缩 */
  1223. }
  1224. .homepage-logo {
  1225. height: 100%;
  1226. width: fit-content;
  1227. display: flex;
  1228. /* flex-direction: column; */
  1229. align-items: center;
  1230. justify-content: center;
  1231. margin-left: 20px;
  1232. margin-right: auto;
  1233. position: relative;
  1234. gap: 10px;
  1235. }
  1236. .expand {
  1237. font-size: 2.5rem;
  1238. cursor: pointer;
  1239. color: white;
  1240. }
  1241. .logo1 {
  1242. width: 110px;
  1243. height: auto;
  1244. margin-bottom: 8px;
  1245. }
  1246. .logo2 {
  1247. width: 80px;
  1248. height: auto;
  1249. }
  1250. /* 尾部 */
  1251. .homepage-footer {
  1252. display: flex;
  1253. flex-direction: column;
  1254. gap: 5px;
  1255. flex-shrink: 0;
  1256. /* width: 100%; */
  1257. background-color: #fff;
  1258. }
  1259. .pcFooter {
  1260. margin: 0 6% 4%;
  1261. }
  1262. .footer-first-line {
  1263. display: flex;
  1264. justify-content: space-between;
  1265. align-items: center;
  1266. padding: 5px 15px;
  1267. flex-shrink: 0;
  1268. }
  1269. .left-group {
  1270. display: flex;
  1271. gap: 15px;
  1272. }
  1273. .action-btn {
  1274. cursor: pointer;
  1275. transition: transform 0.2s;
  1276. height: 28px;
  1277. }
  1278. .model-btn {
  1279. height: 32px;
  1280. transition: all 0.3s ease;
  1281. }
  1282. .model-btn:hover {
  1283. transform: scale(1.1);
  1284. }
  1285. .send-btn {
  1286. margin-left: 10px;
  1287. height: 33px !important;
  1288. width: auto;
  1289. /* margin-right: 5px; */
  1290. }
  1291. .input-container {
  1292. position: relative;
  1293. width: 100%;
  1294. }
  1295. .send-btn-inner {
  1296. position: absolute;
  1297. right: 10px;
  1298. top: 50%;
  1299. transform: translateY(-50%);
  1300. height: 28px !important;
  1301. width: auto;
  1302. z-index: 10;
  1303. transition: all 0.3s ease;
  1304. }
  1305. .send-btn-inner:hover {
  1306. transform: translateY(-50%) scale(1.1);
  1307. }
  1308. /* 音频播放动画 */
  1309. @keyframes pulse {
  1310. 0% {
  1311. transform: scale(1);
  1312. }
  1313. 50% {
  1314. transform: scale(1.1);
  1315. }
  1316. 100% {
  1317. transform: scale(1);
  1318. }
  1319. }
  1320. .footer-second-line {
  1321. position: relative;
  1322. display: flex;
  1323. align-items: center;
  1324. padding: 5px 15px 10px;
  1325. flex-shrink: 0;
  1326. }
  1327. .msg-icon {
  1328. position: absolute;
  1329. left: 25px;
  1330. top: 50%;
  1331. transform: translateY(-50%);
  1332. width: 24px;
  1333. z-index: 999;
  1334. }
  1335. .msg-input:deep(.el-textarea__inner) {
  1336. border: none !important;
  1337. box-shadow: none !important;
  1338. overflow-y: auto !important;
  1339. transition: all 0.2s ease-out;
  1340. resize: none !important;
  1341. line-height: 1.5 !important;
  1342. max-height: 100px !important;
  1343. padding-right: 45px !important;
  1344. }
  1345. .msg-input:deep(.el-textarea__inner::placeholder) {
  1346. white-space: nowrap !important;
  1347. overflow: hidden !important;
  1348. text-overflow: ellipsis !important;
  1349. }
  1350. .msg-input {
  1351. min-height: 34px;
  1352. width: 100%;
  1353. border-radius: 5px;
  1354. font-size: 16px;
  1355. transition: all 0.3s ease-out;
  1356. overflow-y: hidden;
  1357. box-shadow: 0 4px 12px rgba(89, 24, 241, 0.3);
  1358. background: #fff;
  1359. z-index: 5;
  1360. /* 添加iOS设备特殊处理 */
  1361. -webkit-appearance: none;
  1362. appearance: none;
  1363. }
  1364. .msg-input:focus {
  1365. outline: none;
  1366. }
  1367. @media (max-width: 768px) {
  1368. .action-btn {
  1369. height: 21px;
  1370. }
  1371. .footer-second-line {
  1372. padding: 5px 10px 10px;
  1373. }
  1374. .msg-input {
  1375. /* min-height: 44px; */
  1376. /* height: 44px; */
  1377. font-size: 16px;
  1378. }
  1379. }
  1380. .ruleContent {
  1381. text-align: center;
  1382. }
  1383. </style>