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.

3341 lines
84 KiB

7 months ago
4 weeks ago
4 weeks ago
4 weeks ago
2 months ago
2 months ago
7 months ago
7 months ago
7 months ago
7 months ago
4 weeks ago
4 weeks ago
7 months ago
4 weeks ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
4 weeks ago
4 weeks ago
7 months ago
7 months ago
2 months ago
7 months ago
7 months ago
1 month ago
4 weeks ago
4 weeks ago
4 weeks ago
1 month ago
1 month ago
1 month ago
7 months ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
7 months ago
7 months ago
7 months ago
7 months ago
4 weeks ago
1 month 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 month ago
2 months ago
7 months ago
7 months ago
4 months ago
4 weeks ago
4 weeks ago
2 months ago
2 months ago
4 weeks ago
1 month ago
1 month ago
1 month ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
1 month ago
1 month ago
1 month ago
1 month ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
4 weeks ago
4 weeks ago
4 weeks ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month 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
4 weeks ago
4 weeks ago
  1. <script setup>
  2. // 导入
  3. import { ref, computed, onMounted, watch, nextTick, onUnmounted, h } from "vue";
  4. import { setHeight } from "../utils/setHeight";
  5. import {
  6. getUserCountAPI,
  7. showExchangeAPI,
  8. godExchangeAPI,
  9. exchangeAPI,
  10. getGoldCoinAPI,
  11. } from "../api/AIxiaocaishen";
  12. import { ElMessage } from "element-plus";
  13. import AIchat from "./AIchat.vue";
  14. import AIfind from "./AIfind.vue";
  15. import AiEmotion from "./AiEmotion.vue";
  16. import deepNine from "./deepNine.vue";
  17. import Feedback from "./Feedback.vue";
  18. import Announcement from "./Announcement.vue";
  19. import { useAppBridge } from "../assets/js/useAppBridge.js";
  20. import { useDataStore } from "@/store/dataList.js";
  21. import { useChatStore } from "../store/chat";
  22. import { useEmotionAudioStore } from "../store/emotionAudio";
  23. import { useAudioStore } from "../store/audio";
  24. import { useDeepNineStore } from "../store/deepNine";
  25. import _ from "lodash";
  26. import logo from "../assets/img/homePage/logo.png";
  27. import madeInHL from "../assets/img/homePage/madeInHL.png";
  28. import getCountAll from "../assets/img/homePage/get-count-all.png";
  29. import announcementBtn from "../assets/img/homePage/announcement.png";
  30. import thinkActive from "../assets/img/homePage/tail/think-active.png";
  31. import thinkNoActive from "../assets/img/homePage/tail/think-no-active.png";
  32. import languageBtn from "../assets/img/homePage/tail/language.png";
  33. import dbqbButton01 from "../assets/img/AiEmotion/dbqb-button01.png";
  34. import dbqbButton02 from "../assets/img/AiEmotion/dbqb-button02.png";
  35. import emotionButton01 from "../assets/img/AiEmotion/emotion-button01.png";
  36. import emotionButton02 from "../assets/img/AiEmotion/emotion-button02.png";
  37. import voice from "../assets/img/homePage/tail/voice.png";
  38. import voiceNoActive from "../assets/img/homePage/tail/voice-no-active.png";
  39. import sendBtn from "../assets/img/homePage/tail/send.png";
  40. import msgBtn from "../assets/img/homePage/tail/msg.png";
  41. import feedbackBtn from "../assets/img/Feedback/feedbackBtn.png";
  42. import back from "../assets/img/Feedback/back.png";
  43. import HistoryRecord from "./components/HistoryRecord.vue";
  44. // import VConsole from "vconsole";
  45. // const vConsole = new VConsole();
  46. const isMobile = ref(null);
  47. // 获取 AiEmotion 组件的 ref
  48. const aiEmotionRef = ref(null);
  49. // 获取深度九大模型组件的 ref
  50. const deepNineRef = ref(null);
  51. // 获取历史记录组件的 ref
  52. const historyRecordRef = ref(null);
  53. // import { useUserStore } from "../store/userPessionCode.js";
  54. const { getQueryVariable, setActiveTabIndex, getUserInfo } = useDataStore();
  55. const dataStore = useDataStore();
  56. const chatStore = useChatStore();
  57. const deepNineStore = useDeepNineStore();
  58. // 变量
  59. // 音频管理
  60. const emotionAudioStore = useEmotionAudioStore();
  61. const audioStore = useAudioStore();
  62. // 根据当前页面类型获取对应的音频store
  63. const getCurrentAudioStore = () => {
  64. return activeTab.value === "AiEmotion" ? emotionAudioStore : audioStore;
  65. };
  66. const isVoice = computed(() => {
  67. const currentStore = getCurrentAudioStore();
  68. return currentStore.isVoiceEnabled;
  69. });
  70. const toggleVoice = () => {
  71. const currentStore = getCurrentAudioStore();
  72. if (!currentStore.isVoiceEnabled) {
  73. // 如果语音功能关闭,先开启语音功能
  74. currentStore.toggleVoice();
  75. } else {
  76. // 如果语音功能开启,则切换播放/暂停状态
  77. if (currentStore.currentAudioUrl || currentStore.ttsUrl) {
  78. // 有音频时切换播放/暂停
  79. currentStore.togglePlayPause();
  80. } else {
  81. // 没有音频时关闭语音功能
  82. currentStore.toggleVoice();
  83. }
  84. }
  85. };
  86. // 将默认值改为从 sessionStorage 中获取,如果没有则使用默认值 'aifindCow'为第一个默认tab
  87. const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat");
  88. const activeIndex = ref(
  89. parseInt(sessionStorage.getItem("activeIndexAI") || "0")
  90. );
  91. // 手机端选择器的值,与activeTab保持同步
  92. const activeTabMobile = ref(activeTab.value);
  93. // 下拉菜单开关状态
  94. const isDropdownOpen = ref(false);
  95. // 模型选项数据
  96. const modelOptions = [
  97. {
  98. label: "夺宝奇兵大模型",
  99. value: "AIchat",
  100. image:
  101. "https://d31zlh4on95l9h.cloudfront.net/images/0389f08c458c20b715be7acebf7a8eb2.png",
  102. },
  103. {
  104. label: "AI情绪大模型",
  105. value: "AiEmotion",
  106. image:
  107. "https://d31zlh4on95l9h.cloudfront.net/images/aed3597ea187c5af6c88d5a5c67fc9c1.png",
  108. },
  109. {
  110. label: "深度九大模型",
  111. value: "deepNine",
  112. image:
  113. "https://d31zlh4on95l9h.cloudfront.net/images/35bf808538183be0062e4647570a9abd.png",
  114. },
  115. ];
  116. // 监听activeTab变化,同步到activeTabMobile
  117. watch(activeTab, (newVal) => {
  118. activeTabMobile.value = newVal;
  119. });
  120. // 切换下拉菜单显示状态
  121. const toggleDropdown = () => {
  122. isDropdownOpen.value = !isDropdownOpen.value;
  123. };
  124. // 选择选项
  125. const selectOption = (value) => {
  126. activeTabMobile.value = value;
  127. isDropdownOpen.value = false;
  128. const tabIndexMap = {
  129. AIchat: 0,
  130. AiEmotion: 1,
  131. deepNine: 2,
  132. };
  133. setActiveTab(value, tabIndexMap[value]);
  134. };
  135. // 获取当前选中选项的标签
  136. const getSelectedOptionLabel = () => {
  137. const option = modelOptions.find(
  138. (opt) => opt.value === activeTabMobile.value
  139. );
  140. return option ? option.label : "请选择模型";
  141. };
  142. // 获取当前选中选项的图片
  143. const getSelectedOptionImage = () => {
  144. const option = modelOptions.find(
  145. (opt) => opt.value === activeTabMobile.value
  146. );
  147. return option ? option.image : "";
  148. };
  149. // 点击外部关闭下拉菜单
  150. onMounted(() => {
  151. document.addEventListener("click", (e) => {
  152. const container = document.querySelector(".custom-select-container");
  153. if (container && !container.contains(e.target) && isDropdownOpen.value) {
  154. isDropdownOpen.value = false;
  155. }
  156. });
  157. });
  158. // 手机端选择器变化处理(保留原函数以兼容其他地方可能的调用)
  159. const handleMobileTabChange = (value) => {
  160. const tabIndexMap = {
  161. AIchat: 0,
  162. AiEmotion: 1,
  163. deepNine: 2,
  164. };
  165. setActiveTab(value, tabIndexMap[value]);
  166. };
  167. const tabs = computed(() => [
  168. {
  169. name: "AIchat",
  170. label: "夺宝奇兵大模型",
  171. },
  172. // {
  173. // name: "AIfind",
  174. // label: "发现",
  175. // },
  176. {
  177. name: "AiEmotion",
  178. label: "AI情绪大模型",
  179. },
  180. {
  181. name: "deepNine",
  182. label: "深度九大模型",
  183. },
  184. ]);
  185. // 修改 setActiveTab 方法,添加一个可选参数 forceAIchat
  186. const setActiveTab = (tab, index, forceAIchat = false) => {
  187. isScrolling.value = false; //回复滚动到底部方法
  188. isAnnouncementVisible.value = false;
  189. // 重置输入框禁用状态,防止页面切换时状态残留
  190. console.log("tab", tab, "index", index);
  191. if (tab == "AIchat") {
  192. isInputDisabled.value = chatStore.chatInput;
  193. console.log("切换到AIchat页面,输入框状态为", isInputDisabled.value);
  194. } else if (tab == "AiEmotion") {
  195. isInputDisabled.value = chatStore.emotionInput;
  196. console.log("切换到AiEmotion页面,输入框状态为", isInputDisabled.value);
  197. } else if (tab == "deepNine") {
  198. isInputDisabled.value = chatStore.deepNineInput;
  199. console.log("切换到deepNine页面,输入框状态为", isInputDisabled.value);
  200. } else {
  201. isInputDisabled.value = false;
  202. }
  203. if (forceAIchat && activeTab.value !== "AIchat") {
  204. activeTab.value = "AIchat";
  205. activeIndex.value = 0;
  206. sessionStorage.setItem("activeTabAI", "AIchat");
  207. sessionStorage.setItem("activeIndexAI", "0");
  208. } else {
  209. activeTab.value = tab;
  210. activeIndex.value = index;
  211. sessionStorage.setItem("activeTabAI", tab);
  212. sessionStorage.setItem("activeIndexAI", index.toString());
  213. }
  214. setActiveTabIndex(index);
  215. console.log(tab, index, "tab, index");
  216. setHeight(document.getElementById("testId")); // 给父组件发送窗口高度
  217. // 在页面切换时获取最新的次数
  218. chatStore.getUserCount();
  219. };
  220. // 修改 activeComponent 的计算逻辑
  221. const activeComponent = computed(() => {
  222. if (activeTab.value === "AIchat") {
  223. return AIchat;
  224. } else if (activeTab.value === "AIfind") {
  225. return AIfind;
  226. } else if (activeTab.value === "AiEmotion") {
  227. return AiEmotion; // 新增逻辑
  228. } else if (activeTab.value === "deepNine") {
  229. return deepNine;
  230. }
  231. });
  232. const activeTwoTab = computed(() => {
  233. if (isAnnouncementVisible.value) {
  234. return Announcement;
  235. } else {
  236. return Feedback;
  237. }
  238. });
  239. // 新增一个方法,调用时先判断是否处于 AIchat,若不在则跳转到 AIchat
  240. const ensureAIchat = () => {
  241. setActiveTab("AIchat", 0, true);
  242. };
  243. // 获取次数
  244. const UserCount = computed(() => chatStore.UserCount);
  245. const getCount = () => {
  246. console.log("点击了获取次数的按钮");
  247. };
  248. // 深度思考
  249. const isThinking = ref(true);
  250. const toggleThink = () => {
  251. isThinking.value = !isThinking.value;
  252. };
  253. // 发送消息
  254. const message = ref("");
  255. // 传输对象
  256. const messages = ref([]);
  257. // 信息加载状态
  258. const isLoading = computed(() => {
  259. chatStore.isLoading;
  260. });
  261. // 输入框禁用状态
  262. const isInputDisabled = ref(false);
  263. // 添加用户消息
  264. const updateMessage = (title) => {
  265. message.value = title;
  266. console.log("updateMessage 的值:", title);
  267. };
  268. watch(
  269. () => chatStore.announcementMsg,
  270. (newVal) => {
  271. console.log("监听到公告改变", chatStore.announcementMsg);
  272. if (chatStore.announcementMsg && !isInputDisabled.value) {
  273. message.value = chatStore.announcementMsg;
  274. chatStore.announcementMsg = null;
  275. }
  276. }
  277. );
  278. watch(
  279. () => dataStore.isFeedback,
  280. async (newVal) => {
  281. if (!dataStore.isFeedback) {
  282. // 重置公告页面显示状态
  283. isAnnouncementVisible.value = false;
  284. await nextTick();
  285. // 监听页面高度
  286. throttledHeightListener();
  287. }
  288. }
  289. );
  290. watch(
  291. () => chatStore.chatInput,
  292. async (newVal) => {
  293. if (activeTab.value == "AIchat") {
  294. isInputDisabled.value = chatStore.chatInput;
  295. }
  296. }
  297. );
  298. watch(
  299. () => chatStore.emotionInput,
  300. async (newVal) => {
  301. if (activeTab.value == "AiEmotion") {
  302. isInputDisabled.value = chatStore.emotionInput;
  303. }
  304. }
  305. );
  306. watch(
  307. () => chatStore.deepNineInput,
  308. async (newVal) => {
  309. console.log("deepNineInput", chatStore.deepNineInput);
  310. if (activeTab.value == "deepNine") {
  311. isInputDisabled.value = chatStore.deepNineInput;
  312. }
  313. }
  314. );
  315. const sendMessage = async () => {
  316. if (
  317. localStorage.getItem("localToken") == null ||
  318. localStorage.getItem("localToken") == ""
  319. ) {
  320. ElMessage.error("请先登录");
  321. return;
  322. }
  323. // 检查输入内容是否为空
  324. if (!message.value || !message.value.trim()) {
  325. ElMessage.warning("输入内容不能为空");
  326. return;
  327. }
  328. isScrolling.value = false;
  329. // 注意:历史记录会在消息发送后自动更新,无需手动添加
  330. // 取消历史记录选中状态
  331. if (historyRecordRef) {
  332. historyRecordRef.value.selectedRecordId = null;
  333. }
  334. // 判断当前是否为 AiEmotion 组件
  335. if (activeTab.value === "AiEmotion") {
  336. // 禁用输入框
  337. isInputDisabled.value = true;
  338. chatStore.emotionInput = true;
  339. // 调用 AiEmotion 组件的 handleSendMessage 方法
  340. aiEmotionRef.value?.handleSendMessage(message.value, () => {
  341. // 打字机效果完成后的回调,重新启用输入框
  342. isInputDisabled.value = false;
  343. chatStore.emotionInput = false;
  344. });
  345. message.value = ""; // 清空输入框
  346. return;
  347. }
  348. // 判断当前是否为深度九大模型
  349. if (activeTab.value === "deepNine") {
  350. // 禁用输入框
  351. isInputDisabled.value = true;
  352. chatStore.deepNineInput = true;
  353. // 获取深度九大模型的 store
  354. const deepNineStore = useDeepNineStore();
  355. // 添加消息到深度九大模型的 store 中
  356. const messageContent = message.value;
  357. message.value = ""; // 清空输入框
  358. setTimeout(() => {
  359. console.log("深度九大模型:添加消息", messageContent);
  360. messages.value = [
  361. ...messages.value,
  362. {
  363. sender: "user",
  364. content: messageContent,
  365. audioArray: [],
  366. audioStatus: false,
  367. },
  368. ];
  369. }, 200);
  370. return;
  371. }
  372. // 调用 ensureAIchat 确保跳转到 AIchat 页面
  373. ensureAIchat();
  374. if (isInputDisabled.value) return;
  375. isInputDisabled.value = true;
  376. chatStore.chatInput = true;
  377. const messageContent = message.value;
  378. // 重置消息输入框
  379. message.value = "";
  380. setTimeout(() => {
  381. console.log("延时后添加消息", messageContent);
  382. // 发送消息时,设置 isLoading 为 true
  383. messages.value = [
  384. ...messages.value,
  385. {
  386. sender: "user",
  387. content: messageContent,
  388. audioArray: [],
  389. audioStatus: false,
  390. },
  391. ];
  392. console.log(messages.value, "messages.value");
  393. }, 200);
  394. };
  395. // 重新启用输入框的方法
  396. const enableInput = () => {
  397. console.log("解除禁用");
  398. isInputDisabled.value = false;
  399. };
  400. // 处理历史记录选择
  401. const handleHistorySelect = (stockData) => {
  402. console.log("接收到历史记录数据:", stockData);
  403. // 只在情绪大模型中处理历史记录选择
  404. if (activeTab.value === 'AiEmotion') {
  405. // 等待组件渲染完成后调用addStock方法
  406. nextTick(() => {
  407. if (aiEmotionRef.value && aiEmotionRef.value.addStock) {
  408. aiEmotionRef.value.addStock(stockData);
  409. } else {
  410. console.error("AiEmotion组件或addStock方法不可用");
  411. }
  412. });
  413. } else {
  414. console.log("历史记录选择仅在情绪大模型中有效");
  415. }
  416. };
  417. // 公告
  418. // 新增一个变量来控制是否显示公告页面
  419. const isAnnouncementVisible = ref(false);
  420. // Token规则提示框相关
  421. const tokenRuleDialogVisible = ref(false);
  422. const hasShownTokenRule = ref({
  423. AIchat: sessionStorage.getItem("hasShownTokenRule_AIchat") === "true",
  424. AiEmotion: sessionStorage.getItem("hasShownTokenRule_AiEmotion") === "true",
  425. deepNine: sessionStorage.getItem("hasShownTokenRule_deepNine") === "true",
  426. });
  427. // 关闭Token规则提示框
  428. const closeTokenRuleDialog = () => {
  429. tokenRuleDialogVisible.value = false;
  430. };
  431. // 打开Token规则提示框
  432. const openTokenRuleDialog = () => {
  433. tokenRuleDialogVisible.value = true;
  434. };
  435. // 添加全局点击事件监听器,使任何点击动作都能关闭提示框
  436. // 定义处理函数,以便正确移除事件监听器
  437. const handleGlobalClick = (event) => {
  438. // 检查点击事件是否来自"兑换规则"按钮
  439. const changeRuleElement = document.querySelector(".changeRule");
  440. if (
  441. changeRuleElement &&
  442. (changeRuleElement === event.target ||
  443. changeRuleElement.contains(event.target))
  444. ) {
  445. // 如果点击的是"兑换规则"按钮,不关闭提示框
  446. return;
  447. }
  448. if (tokenRuleDialogVisible.value) {
  449. tokenRuleDialogVisible.value = false;
  450. }
  451. };
  452. onMounted(() => {
  453. document.addEventListener("click", handleGlobalClick);
  454. });
  455. // 在组件卸载时移除事件监听器
  456. onUnmounted(() => {
  457. document.removeEventListener("click", handleGlobalClick);
  458. });
  459. // 检查是否需要显示Token规则提示框(从其他页面跳转过来时)
  460. const checkTokenRuleOnPageLoad = () => {
  461. const activeTab = sessionStorage.getItem("activeTabAI");
  462. const fromExternalPage = sessionStorage.getItem("fromExternalPage");
  463. if (
  464. fromExternalPage === "true" &&
  465. activeTab &&
  466. !hasShownTokenRule.value[activeTab]
  467. ) {
  468. tokenRuleDialogVisible.value = true;
  469. hasShownTokenRule.value[activeTab] = true;
  470. sessionStorage.setItem(`hasShownTokenRule_${activeTab}`, "true");
  471. // 清除标记,避免重复显示
  472. sessionStorage.removeItem("fromExternalPage");
  473. }
  474. };
  475. const showAnnouncement = async () => {
  476. console.log("打开公告");
  477. dataStore.isFeedback = true; // 显示用户反馈页面
  478. isScrolling.value = false; //回复滚动到底部方法
  479. isAnnouncementVisible.value = true; // 显示公告页面
  480. if (isMobile.value) {
  481. if (historyRecordRef) {
  482. historyRecordRef.value.isCollapsed = true;
  483. }
  484. }
  485. };
  486. // 跳转用户反馈
  487. const showFeedback = () => {
  488. console.log("打开用户反馈");
  489. dataStore.isFeedback = true; // 显示用户反馈页面
  490. isAnnouncementVisible.value = false; // 显示反馈页面
  491. if (isMobile.value) {
  492. if (historyRecordRef) {
  493. historyRecordRef.value.isCollapsed = true;
  494. }
  495. }
  496. };
  497. // 保证发送消息时,滚动屏在底部
  498. const tabContentAIchat = ref(null);
  499. const tabContentAiEmotion = ref(null);
  500. const tabContentDeepNine = ref(null);
  501. const isScrolling = ref(false); //判断用户是否在滚动
  502. // AiEmotion页面高度监听器相关变量
  503. const aiEmotionHeightObserver = ref(null);
  504. const isAiEmotionAutoScrollEnabled = ref(false);
  505. const isAiEmotionUserScrolling = ref(false); // 用户是否正在手动滚动
  506. const aiEmotionScrollTimer = ref(null); // 滚动检测定时器
  507. const isChartInteracting = ref(false); // 图表是否正在交互
  508. const chartInteractionTimer = ref(null); // 图表交互检测定时器
  509. // 获取当前活动页面的滚动容器
  510. const getCurrentScrollContainer = () => {
  511. if (activeTab.value === "AIchat") {
  512. return tabContentAIchat.value;
  513. } else if (activeTab.value === "AiEmotion") {
  514. return tabContentAiEmotion.value;
  515. } else if (activeTab.value === "deepNine") {
  516. return tabContentDeepNine.value;
  517. }
  518. return null;
  519. };
  520. const smoothScrollToBottom = async () => {
  521. const container = getCurrentScrollContainer();
  522. if (!container) return;
  523. await nextTick(); // 确保在DOM更新后执行
  524. if (!isScrolling.value) {
  525. container.scrollTop = container.scrollHeight - container.offsetHeight;
  526. }
  527. };
  528. const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 300, {
  529. trailing: false,
  530. });
  531. // AiEmotion页面自动滚动到底部的防抖函数
  532. const debouncedAiEmotionScrollToBottom = _.debounce(() => {
  533. if (
  534. activeTab.value === "AiEmotion" &&
  535. isAiEmotionAutoScrollEnabled.value &&
  536. !isAiEmotionUserScrolling.value &&
  537. !isChartInteracting.value
  538. ) {
  539. const container = tabContentAiEmotion.value;
  540. if (container) {
  541. container.scrollTop = container.scrollHeight - container.offsetHeight;
  542. }
  543. }
  544. }, 150);
  545. // 启动AiEmotion页面高度监听器
  546. const startAiEmotionHeightObserver = () => {
  547. // 先停止之前的监听器
  548. stopAiEmotionHeightObserver();
  549. isAiEmotionAutoScrollEnabled.value = true;
  550. // 创建ResizeObserver监听页面内容变化
  551. aiEmotionHeightObserver.value = new ResizeObserver((entries) => {
  552. if (
  553. isAiEmotionAutoScrollEnabled.value &&
  554. activeTab.value === "AiEmotion" &&
  555. !isChartInteracting.value
  556. ) {
  557. debouncedAiEmotionScrollToBottom();
  558. }
  559. });
  560. // 监听document.body的尺寸变化
  561. if (document.body) {
  562. aiEmotionHeightObserver.value.observe(document.body);
  563. }
  564. // 创建MutationObserver监听DOM结构变化
  565. const mutationObserver = new MutationObserver((mutations) => {
  566. let shouldScroll = false;
  567. mutations.forEach((mutation) => {
  568. if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
  569. // 检查新增的节点是否包含实际内容
  570. const hasContent = Array.from(mutation.addedNodes).some((node) => {
  571. if (node.nodeType === Node.ELEMENT_NODE) {
  572. return node.offsetHeight > 0 || node.scrollHeight > 0;
  573. }
  574. return (
  575. node.nodeType === Node.TEXT_NODE &&
  576. node.textContent.trim().length > 0
  577. );
  578. });
  579. if (hasContent) {
  580. shouldScroll = true;
  581. }
  582. }
  583. });
  584. if (
  585. shouldScroll &&
  586. isAiEmotionAutoScrollEnabled.value &&
  587. activeTab.value === "AiEmotion" &&
  588. !isChartInteracting.value
  589. ) {
  590. debouncedAiEmotionScrollToBottom();
  591. }
  592. });
  593. // 监听AiEmotion页面的主要内容区域的DOM变化
  594. const aiEmotionContainer = tabContentAiEmotion.value;
  595. if (aiEmotionContainer) {
  596. mutationObserver.observe(aiEmotionContainer, {
  597. childList: true,
  598. subtree: true,
  599. attributes: false,
  600. characterData: true,
  601. });
  602. }
  603. // 保存mutationObserver引用以便清理
  604. aiEmotionHeightObserver.value.mutationObserver = mutationObserver;
  605. // 为AiEmotion页面的滚动容器添加滚动事件监听器
  606. if (aiEmotionContainer) {
  607. aiEmotionContainer.addEventListener("scroll", handleAiEmotionUserScroll, {
  608. passive: true,
  609. });
  610. // 保存滚动事件监听器引用以便清理
  611. aiEmotionHeightObserver.value.scrollListener = handleAiEmotionUserScroll;
  612. }
  613. console.log("AiEmotion页面高度监听器已启动");
  614. };
  615. // AiEmotion页面用户滚动检测
  616. const handleAiEmotionUserScroll = () => {
  617. // 标记用户正在滚动
  618. isAiEmotionUserScrolling.value = true;
  619. // 清除之前的定时器
  620. if (aiEmotionScrollTimer.value) {
  621. clearTimeout(aiEmotionScrollTimer.value);
  622. }
  623. // 设置定时器,2秒后恢复自动滚动
  624. // aiEmotionScrollTimer.value = setTimeout(() => {
  625. // isAiEmotionUserScrolling.value = false;
  626. // console.log("AiEmotion页面用户滚动检测:恢复自动滚动");
  627. // }, 2000);
  628. };
  629. // 图表交互状态管理
  630. const handleChartInteractionStart = () => {
  631. console.log("图表交互开始,临时禁用自动滚动");
  632. isChartInteracting.value = true;
  633. // 清除之前的定时器
  634. if (chartInteractionTimer.value) {
  635. clearTimeout(chartInteractionTimer.value);
  636. }
  637. };
  638. const handleChartInteractionEnd = () => {
  639. // 清除之前的定时器
  640. if (chartInteractionTimer.value) {
  641. clearTimeout(chartInteractionTimer.value);
  642. }
  643. // 设置定时器,1秒后恢复自动滚动
  644. chartInteractionTimer.value = setTimeout(() => {
  645. isChartInteracting.value = false;
  646. console.log("图表交互结束,恢复自动滚动");
  647. }, 1000);
  648. };
  649. // 暴露图表交互管理函数给全局使用
  650. window.handleChartInteractionStart = handleChartInteractionStart;
  651. window.handleChartInteractionEnd = handleChartInteractionEnd;
  652. // 处理AiEmotion页面的滚动请求
  653. const handleAiEmotionScrollToBottom = () => {
  654. if (activeTab.value === "AiEmotion") {
  655. const container = tabContentAiEmotion.value;
  656. if (container) {
  657. // 使用nextTick确保DOM已更新
  658. nextTick(() => {
  659. container.scrollTop = container.scrollHeight - container.offsetHeight;
  660. console.log("AiEmotion页面:执行容器滚动到底部");
  661. });
  662. }
  663. }
  664. };
  665. // 停止AiEmotion页面高度监听器
  666. const stopAiEmotionHeightObserver = () => {
  667. isAiEmotionAutoScrollEnabled.value = false;
  668. isAiEmotionUserScrolling.value = false;
  669. // 清理滚动检测定时器
  670. if (aiEmotionScrollTimer.value) {
  671. clearTimeout(aiEmotionScrollTimer.value);
  672. aiEmotionScrollTimer.value = null;
  673. }
  674. if (aiEmotionHeightObserver.value) {
  675. // 清理ResizeObserver
  676. aiEmotionHeightObserver.value.disconnect();
  677. // 清理MutationObserver
  678. if (aiEmotionHeightObserver.value.mutationObserver) {
  679. aiEmotionHeightObserver.value.mutationObserver.disconnect();
  680. aiEmotionHeightObserver.value.mutationObserver = null;
  681. }
  682. // 清理滚动事件监听器
  683. if (
  684. aiEmotionHeightObserver.value.scrollListener &&
  685. tabContentAiEmotion.value
  686. ) {
  687. tabContentAiEmotion.value.removeEventListener(
  688. "scroll",
  689. aiEmotionHeightObserver.value.scrollListener
  690. );
  691. aiEmotionHeightObserver.value.scrollListener = null;
  692. }
  693. aiEmotionHeightObserver.value = null;
  694. }
  695. console.log("AiEmotion页面高度监听器已停止");
  696. };
  697. watch(
  698. () => chatStore.messages.length,
  699. () => {
  700. // console.log('messages变化了')
  701. // 只有在AIchat页面时才执行自动滚动
  702. if (activeTab.value === "AIchat" || activeTab.value === "deepNine") {
  703. throttledSmoothScrollToBottom();
  704. }
  705. },
  706. { deep: false, immediate: true }
  707. );
  708. watch(
  709. () => deepNineStore.messages.length,
  710. () => {
  711. // console.log('messages变化了')
  712. // 只有在AIchat页面时才执行自动滚动
  713. if (activeTab.value === "AIchat" || activeTab.value === "deepNine") {
  714. throttledSmoothScrollToBottom();
  715. }
  716. },
  717. { deep: false, immediate: true }
  718. );
  719. // 监听-当点击夺宝奇兵大模型的历史记录时,滚动到顶部
  720. watch(
  721. () => chatStore.dbqbClickRecord,
  722. async (newValue, oldValue) => {
  723. const container = getCurrentScrollContainer();
  724. if (!container) return;
  725. await nextTick(); // 确保在DOM更新后执行
  726. container.scrollTop = 0;
  727. }
  728. );
  729. // 监听-当点击深度九大模型的历史记录时,滚动到顶部
  730. watch(
  731. () => deepNineStore.dbqbClickRecord,
  732. async (newValue, oldValue) => {
  733. const container = getCurrentScrollContainer();
  734. if (!container) return;
  735. await nextTick(); // 确保在DOM更新后执行
  736. container.scrollTop = 0;
  737. }
  738. );
  739. watch(
  740. () => chatStore.dbqbScrollToTop,
  741. async (newValue, oldValue) => {
  742. const container = getCurrentScrollContainer();
  743. if (!container) return;
  744. await nextTick(); // 确保在DOM更新后执行
  745. container.scrollTop = 0;
  746. }
  747. );
  748. watch(
  749. activeTab,
  750. async () => {
  751. console.log("activeTab变化了", activeTab.value);
  752. if (
  753. activeTab.value == "AIchat" ||
  754. activeTab.value == "AiEmotion" ||
  755. activeTab.value == "deepNine"
  756. ) {
  757. if (historyRecordRef.value && historyRecordRef.value.getHistoryList) {
  758. let model =
  759. activeTab.value == "AIchat"
  760. ? 1
  761. : activeTab.value == "AiEmotion"
  762. ? 2
  763. : 3;
  764. const result = historyRecordRef.value.getHistoryList({
  765. model: model,
  766. token: localStorage.getItem("localToken"),
  767. });
  768. }
  769. }
  770. if (activeTab.value === "AIchat" || activeTab.value === "deepNine") {
  771. isScrolling.value = false; //回复滚动到底部方法
  772. // 停止AiEmotion页面的高度监听器
  773. stopAiEmotionHeightObserver();
  774. setTimeout(() => {
  775. // throttledSmoothScrollToBottom();
  776. }, 100);
  777. } else if (activeTab.value === "AiEmotion") {
  778. // 启动AiEmotion页面的高度监听器
  779. await nextTick(); // 确保DOM更新后启动监听器
  780. startAiEmotionHeightObserver();
  781. } else {
  782. // 其他页面时停止AiEmotion页面的高度监听器
  783. stopAiEmotionHeightObserver();
  784. }
  785. },
  786. { deep: true, immediate: true }
  787. );
  788. // 获取token的核心函数
  789. // const fnGetToken = () => {
  790. // // console.log('进入fnGetToken')
  791. // window.JWready = (ress) => {
  792. // // console.log('进入JWready')
  793. // try {
  794. // ress = JSON.parse(ress);
  795. // // console.log(ress, 'ress')
  796. // } catch (error) {
  797. // console.log(error, "fnGetToken error");
  798. // } //platform为5是app端
  799. // // platform.value = ress.data.platform
  800. // // 处理平台判断
  801. // console.log(ress.data.platform, "ress.data.platform");
  802. // if (!ress.data.platform) {
  803. // // 非App环境通过URL参数获取
  804. // localStorage.setItem(
  805. // "localToken",
  806. // decodeURIComponent(String(getQueryVariable("token")))
  807. // );
  808. // // localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w")
  809. // } else {
  810. // // App环境通过桥接获取
  811. // useAppBridge().packageFun(
  812. // "JWgetStorage",
  813. // (response) => {
  814. // const res = JSON.parse(response); // 解析返回的结果
  815. // localStorage.setItem("localToken", res.data);
  816. // // localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w")
  817. // },
  818. // 5,
  819. // {
  820. // key: "token",
  821. // }
  822. // );
  823. // }
  824. // };
  825. // // console.log('出来了')
  826. // // 触发App桥接
  827. // useAppBridge().packageFun("JWwebReady", () => {}, 5, {});
  828. // };
  829. // 在setTimeout中延迟执行
  830. // setTimeout(() => {
  831. // fnGetToken();
  832. // }, 800);
  833. const heightListener = () => {
  834. const tabContainer = getCurrentScrollContainer();
  835. if (!tabContainer) return;
  836. let befortop = 0;
  837. const scrollHandler = () => {
  838. const aftertop = tabContainer.scrollTop;
  839. // 新增底部判断逻辑
  840. const isBottom =
  841. aftertop + tabContainer.offsetHeight + 70 >= tabContainer.scrollHeight;
  842. if (activeTab.value === "AIchat") {
  843. if (aftertop - befortop > 0) {
  844. // console.log("向下滚动");
  845. isScrolling.value = true;
  846. } else {
  847. // console.log("向上滚动");
  848. isScrolling.value = true;
  849. }
  850. // 添加底部状态检测
  851. if (isBottom) {
  852. // console.log("滚动到底部");
  853. isScrolling.value = false;
  854. }
  855. }
  856. befortop = aftertop;
  857. };
  858. // console.log(isScrolling.value, 'isScrolling.value')
  859. tabContainer.addEventListener("scroll", scrollHandler);
  860. };
  861. const throttledHeightListener = _.throttle(heightListener, 500, {
  862. trailing: false,
  863. });
  864. // const goToRecharge = () => {
  865. // console.log("点击充值");
  866. // // http://39.101.133.168:8919/payment/recharge/index?
  867. // // url=http%3A%2F%2Flocalhost%3A8080%2FLiveActivity%2Fpck
  868. // // &platform=1
  869. // // &token=+S4h5QEE1hTIb4CxphrnbZi0+fEeMx8pywnIlrmTmo4QO6IolWnVWu5r+J4rKXMwK41UPfKqyIp+RvWmtM8
  870. // const userAgent = navigator.userAgent.toLowerCase();
  871. // const mobileKeywords = ["mobile", "android", "iphone", "ipad", "ipod"];
  872. // const isMobile = mobileKeywords.some((keyword) =>
  873. // userAgent.includes(keyword)
  874. // );
  875. // console.log(isMobile ? "手机" : "电脑");
  876. // const url = encodeURI("http://39.101.133.168:8857/aixiaocaishen/homePage");
  877. // console.log(url, "url");
  878. // const platform = isMobile ? 2 : 1;
  879. // const token = encodeURIComponent(localStorage.getItem("localToken"));
  880. // console.log(token, "token");
  881. // const rechargeUrl =
  882. // "http://39.101.133.168:8919/payment/recharge/index?" +
  883. // "url=" +
  884. // url +
  885. // "&platform=" +
  886. // platform +
  887. // "&token=" +
  888. // token;
  889. // console.log(rechargeUrl, "rechargeUrl");
  890. // window.location.href = rechargeUrl;
  891. // // window.open(rechargeUrl)
  892. // };
  893. const adjustFooterPosition = (height) => {
  894. const html = document.querySelector("html");
  895. const body = document.querySelector("body");
  896. const isAndroid = /Android/i.test(navigator.userAgent);
  897. if (isAndroid) {
  898. console.log("是安卓设备");
  899. console.log("window.visualViewport", window.visualViewport.height);
  900. const homePage = document.querySelector(".homepage");
  901. homePage.style.height = `${height}px`;
  902. // homePage.style.height = `460px`;
  903. html.scrollTop = 0;
  904. } else {
  905. console.log("非安卓设备");
  906. console.log("调整底部位置", height);
  907. const homePage = document.querySelector(".homepage");
  908. homePage.style.height = `${height}px`;
  909. html.scrollTop = 0;
  910. }
  911. setTimeout(() => {
  912. // 隐藏滚动条
  913. html.style.overflow = "hidden";
  914. body.style.overflow = "hidden";
  915. }, 200);
  916. };
  917. // 是否正在输入法组合
  918. const inputing = ref(false);
  919. const onFocus = function () {
  920. const visualViewport = window.visualViewport;
  921. // 获取可视区域高度
  922. setTimeout(() => {
  923. console.log("输入框聚焦");
  924. console.log(visualViewport.height, "visualViewport.height");
  925. const keyboardHeight = window.innerHeight - visualViewport.height;
  926. console.log(window.innerHeight, "window.innerHeight");
  927. console.log(keyboardHeight, "keyboardHeight");
  928. adjustFooterPosition(visualViewport.height);
  929. }, 200);
  930. };
  931. const onBlur = function () {
  932. inputing.value = false;
  933. const visualViewport = window.visualViewport;
  934. setTimeout(() => {
  935. console.log("输入框失焦");
  936. const keyboardHeight = window.innerHeight - visualViewport.height;
  937. console.log(window.innerHeight, "window.innerHeight");
  938. console.log(visualViewport.height, "visualViewport.height");
  939. console.log(keyboardHeight, "keyboardHeight");
  940. adjustFooterPosition(visualViewport.height);
  941. }, 200);
  942. };
  943. // window.addEventListener("resize", () => {
  944. // // 检测是否为iOS设备
  945. // const isIOS = /iPhone|iPad|iPod|ios/i.test(navigator.userAgent);
  946. // console.log("是否为iOS设备:", isIOS);
  947. // if (!isIOS) {
  948. // console.log("窗口大小变化");
  949. // const homePage = document.querySelector(".homepage");
  950. // homePage.style.height = `${window.innerHeight}px`;
  951. // }
  952. // });
  953. let touchmoveHandlerRef = null;
  954. const touchmoveHandler = (e) => {
  955. if (!dataStore.isFeedback) {
  956. if (historyRecordRef) {
  957. if (!historyRecordRef.value.isCollapsed) {
  958. return;
  959. }
  960. }
  961. // 判断触摸目标是否在当前活动页面的可滚动区域内
  962. const currentContainer = getCurrentScrollContainer();
  963. const isScrollableArea =
  964. currentContainer && currentContainer.contains(e.target);
  965. // 如果不在可滚动区域,则阻止滚动
  966. if (!isScrollableArea) {
  967. e.preventDefault();
  968. }
  969. }
  970. };
  971. const judgeDevice = async () => {
  972. // 延时300ms
  973. await new Promise((resolve) => setTimeout(resolve, 200));
  974. const userAgent = navigator.userAgent;
  975. isMobile.value =
  976. /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
  977. userAgent
  978. );
  979. console.log("当前设备为:", isMobile.value ? "移动端" : "PC端");
  980. };
  981. const throttledJudgeDevice = _.throttle(judgeDevice, 300, {
  982. trailing: false,
  983. });
  984. const expandHistory = () => {
  985. if (
  986. historyRecordRef.value &&
  987. historyRecordRef.value.isCollapsed !== undefined
  988. ) {
  989. console.log("存在");
  990. historyRecordRef.value.isCollapsed = !historyRecordRef.value.isCollapsed;
  991. if (activeTab.value == "AIchat") {
  992. chatStore.aiChatCall = true;
  993. } else if (activeTab.value == "AiEmotion") {
  994. chatStore.aiEmotionCall = true;
  995. } else if (activeTab.value == "deepNine") {
  996. chatStore.deepNineCall = true;
  997. }
  998. }
  999. };
  1000. const feedbackBack = () => {
  1001. dataStore.isFeedback = false;
  1002. };
  1003. const backToHome = () => {
  1004. if (isMobile.value) {
  1005. console.log("用户是移动端");
  1006. // 调用原生方法跳转到首页
  1007. uni.postMessage({
  1008. data: {
  1009. val: {
  1010. name: "JWopenView",
  1011. extra: {
  1012. data: {
  1013. type: 3,
  1014. },
  1015. },
  1016. },
  1017. },
  1018. });
  1019. } else {
  1020. console.log("用户是pc端");
  1021. const env = import.meta.env.VITE_ENV;
  1022. console.log("当前的环境为:", env);
  1023. if (env == "development" || env == "test") {
  1024. window.parent.location.href =
  1025. "http://121.89.234.155:8807/hljw/homepage?menu=999999991";
  1026. } else {
  1027. window.parent.postMessage(
  1028. {
  1029. type: "NAVIGATE_TO_HOMEPAGE",
  1030. menu: "999999991",
  1031. },
  1032. "*"
  1033. );
  1034. }
  1035. // window.parent.location.href = window.parent.document.referrer
  1036. }
  1037. };
  1038. // 8.18金币兑换Token start
  1039. const userInfo = ref({
  1040. nickname: "",
  1041. img: "",
  1042. jwcode: "",
  1043. });
  1044. const changeRule = ref({
  1045. gold: 1,
  1046. token: 1,
  1047. });
  1048. const changeLevelList = ref([
  1049. { position: 10, calculatedPosition: 10 },
  1050. { position: 20, calculatedPosition: 20 },
  1051. { position: 50, calculatedPosition: 50 },
  1052. { position: 100, calculatedPosition: 100 },
  1053. { position: 200, calculatedPosition: 200 },
  1054. { position: 500, calculatedPosition: 500 },
  1055. { position: 1000, calculatedPosition: 1000 },
  1056. ]);
  1057. const activeLevel = ref(
  1058. changeLevelList.value[0] || { position: 10, calculatedPosition: 10 }
  1059. );
  1060. const gold = ref(90);
  1061. // 点击剩余次数会弹出的弹窗
  1062. // 新增一个 ref 来控制弹窗的显示与隐藏
  1063. const dialogVisible = ref(false);
  1064. const rechargeDialogVisible = ref(false);
  1065. const confirmDialogVisible = ref(false);
  1066. const changeSuccessDialogVisible = ref(false);
  1067. // 图片加载错误处理
  1068. const handleImageError = (event) => {
  1069. console.error("图片加载失败:", event.target.src);
  1070. // 可以设置默认图片或重试逻辑
  1071. event.target.src =
  1072. "https://cdn.legu168.com/jtzy/Product/pcjingwang/images/userimg.png";
  1073. };
  1074. // 获取次数
  1075. const showCount = async () => {
  1076. try {
  1077. if (activeTab.value == "deepNine") {
  1078. return;
  1079. }
  1080. if (
  1081. !dataStore.userInfo.img ||
  1082. !dataStore.userInfo.nickname ||
  1083. !dataStore.userInfo.jwcode
  1084. ) {
  1085. console.log("缺少用户信息,调用方法");
  1086. await getUserInfo();
  1087. }
  1088. userInfo.value.nickname = dataStore.userInfo.nickname;
  1089. userInfo.value.img = dataStore.userInfo.img;
  1090. userInfo.value.jwcode = dataStore.userInfo.jwcode;
  1091. console.log("userInfo", userInfo.value);
  1092. const [res, res2] = await Promise.all([
  1093. showExchangeAPI(),
  1094. getGoldCoinAPI({
  1095. token: String(localStorage.getItem("localToken")),
  1096. }),
  1097. ]);
  1098. changeLevelList.value = res.data;
  1099. activeLevel.value = changeLevelList.value[0];
  1100. changeRule.value.token = res.data[0].ratio;
  1101. gold.value = res2.data.total;
  1102. // 显示弹窗
  1103. dialogVisible.value = true;
  1104. console.log("dialogVisible 的值:", dialogVisible.value); // 添加日志确认
  1105. } catch (e) {
  1106. console.error("获取兑换列表出错", e);
  1107. }
  1108. };
  1109. const chooseLevel = (item) => {
  1110. activeLevel.value = item;
  1111. };
  1112. const changeToken = () => {
  1113. if (gold.value < activeLevel.value.position) {
  1114. rechargeDialogVisible.value = true;
  1115. return;
  1116. } else {
  1117. confirmDialogVisible.value = true;
  1118. }
  1119. };
  1120. const goRecharge = () => {
  1121. console.log("执行前往充值方法");
  1122. sessionStorage.setItem("rechargeFlag", "1");
  1123. sessionStorage.setItem("activeLevel", JSON.stringify(activeLevel.value));
  1124. if (isMobile.value) {
  1125. console.log("用户是移动端");
  1126. uni.postMessage({
  1127. data: {
  1128. val: {
  1129. name: "JWopenView",
  1130. extra: {
  1131. data: {
  1132. type: 4,
  1133. },
  1134. },
  1135. },
  1136. },
  1137. });
  1138. } else {
  1139. console.log("用户是pc端");
  1140. const env = import.meta.env.VITE_ENV;
  1141. console.log("当前的环境为:", env);
  1142. if (env == "development" || env == "test") {
  1143. window.parent.location.href =
  1144. "http://121.89.234.155:8807/user/myGold?token=" +
  1145. encodeURIComponent(localStorage.getItem("localToken")) +
  1146. "&where=xiaocaishen&successUrl=https://hwjb.homilychart.com/aixiaocaishen/homePage";
  1147. // "&where=xiaocaishen&successUrl=http://192.168.1.5:3000/aixiaocaishen/homePage";
  1148. } else {
  1149. window.parent.location.href =
  1150. "https://web.homilychart.com/user/myGold?token=" +
  1151. encodeURIComponent(localStorage.getItem("localToken")) +
  1152. "&where=xiaocaishen&successUrl=https://mp.homilychart.com/aixiaocaishen/homePage";
  1153. }
  1154. // window.parent.location.href = window.parent.document.referrer
  1155. }
  1156. };
  1157. const goChange = async () => {
  1158. try {
  1159. await exchangeAPI({
  1160. token: String(localStorage.getItem("localToken")),
  1161. num: activeLevel.value.position,
  1162. });
  1163. confirmDialogVisible.value = false;
  1164. dialogVisible.value = false;
  1165. changeSuccessDialogVisible.value = true;
  1166. // setTimeout(() => {
  1167. // changeSuccessDialogVisible.value = false;
  1168. // }, 2000);
  1169. // 刷新次数
  1170. await chatStore.getUserCount();
  1171. } catch (e) {
  1172. console.error("兑换失败", e);
  1173. }
  1174. };
  1175. // 8.18金币兑换Token end
  1176. onMounted(async () => {
  1177. // 检查是否需要显示Token规则提示框
  1178. checkTokenRuleOnPageLoad();
  1179. throttledJudgeDevice();
  1180. // 禁用全局触摸滚动
  1181. touchmoveHandlerRef = touchmoveHandler;
  1182. document.addEventListener("touchmove", touchmoveHandlerRef, {
  1183. passive: false,
  1184. });
  1185. setHeight(document.getElementById("testId")); // 给父组件发送窗口高度
  1186. // 获取次数
  1187. await chatStore.getUserCount();
  1188. // 滚动到底部
  1189. throttledSmoothScrollToBottom();
  1190. // 监听页面高度
  1191. throttledHeightListener();
  1192. // 添加输入框焦点处理
  1193. // handleInputFocus();
  1194. // 初始化视口高度变量
  1195. // updateAppHeight();
  1196. // 添加原生事件监听器
  1197. window.showCountHandler = showCount;
  1198. window.addEventListener("resize", throttledJudgeDevice);
  1199. window.receiveUniAppMessage = async function (messageData) {
  1200. console.log("收到 uni-app 消息:", messageData);
  1201. // 根据消息类型进行不同处理
  1202. switch (messageData.type) {
  1203. case "paymentSuccess":
  1204. // 处理支付成功消息
  1205. const [res1, res2] = await Promise.all([
  1206. godExchangeAPI({ state: 1 }),
  1207. getGoldCoinAPI({ token: String(localStorage.getItem("localToken")) }),
  1208. ]);
  1209. gold.value = res2.data.total;
  1210. rechargeDialogVisible.value = false;
  1211. break;
  1212. default:
  1213. console.log("未知消息类型:", messageData.type);
  1214. }
  1215. };
  1216. if (
  1217. sessionStorage.getItem("rechargeFlag") == "1" &&
  1218. getQueryVariable("successType") == "success"
  1219. ) {
  1220. await godExchangeAPI({ state: 1 });
  1221. await showCount();
  1222. activeLevel.value =
  1223. JSON.parse(sessionStorage.getItem("activeLevel")) ||
  1224. changeLevelList.value[0];
  1225. console.log("activeLevel", activeLevel.value);
  1226. sessionStorage.removeItem("activeLevel");
  1227. sessionStorage.setItem("rechargeFlag", "0");
  1228. }
  1229. });
  1230. onUnmounted(() => {
  1231. window.removeEventListener("resize", throttledJudgeDevice);
  1232. if (touchmoveHandlerRef) {
  1233. console.log("卸载touchmoveHandlerRef组件");
  1234. document.removeEventListener("touchmove", touchmoveHandlerRef);
  1235. }
  1236. // 清理AiEmotion页面的高度监听器
  1237. stopAiEmotionHeightObserver();
  1238. delete window.showCountHandler;
  1239. delete window.receiveUniAppMessage;
  1240. // 清理图表交互相关的定时器和全局函数
  1241. if (chartInteractionTimer.value) {
  1242. clearTimeout(chartInteractionTimer.value);
  1243. }
  1244. if (window.handleChartInteractionStart) {
  1245. delete window.handleChartInteractionStart;
  1246. }
  1247. if (window.handleChartInteractionEnd) {
  1248. delete window.handleChartInteractionEnd;
  1249. }
  1250. });
  1251. </script>
  1252. <template>
  1253. <div class="homepage" id="testId">
  1254. <!-- 历史记录组件 -->
  1255. <HistoryRecord
  1256. ref="historyRecordRef"
  1257. :current-type="activeTab"
  1258. @selectRecord="handleHistorySelect"
  1259. :isMobile="isMobile"
  1260. @showAnnouncement="showAnnouncement"
  1261. @showFeedback="showFeedback"
  1262. />
  1263. <div
  1264. v-if="isMobile && !historyRecordRef?.isCollapsed"
  1265. class="zhezhao"
  1266. @click="expandHistory"
  1267. ></div>
  1268. <el-container
  1269. v-if="!dataStore.isFeedback"
  1270. class="main-container"
  1271. :class="{
  1272. collapsed: !isMobile && historyRecordRef?.isCollapsed,
  1273. unCollapsed: !isMobile && !historyRecordRef?.isCollapsed,
  1274. }"
  1275. >
  1276. <!-- AI小财神头部 logo 次数 公告 -->
  1277. <el-header class="homepage-head">
  1278. <!-- logo -->
  1279. <div class="homepage-logo" v-if="isMobile">
  1280. <img
  1281. class="expand"
  1282. @click="expandHistory"
  1283. src="https://d31zlh4on95l9h.cloudfront.net/images/37fe3d79a8a700f6c674c9f0e7af066b.png"
  1284. alt="icon"
  1285. />
  1286. <img :src="logo" alt="图片加载失败" class="logo1" />
  1287. <!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> -->
  1288. </div>
  1289. <div class="homepage-right-group" v-if="isMobile">
  1290. <div
  1291. class="count-badge"
  1292. @click="showCount"
  1293. :class="{ 'deepnine-model': activeTab === 'deepNine' }"
  1294. >
  1295. <img
  1296. v-if="activeTab !== 'deepNine'"
  1297. src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
  1298. class="action-btn"
  1299. />
  1300. <img
  1301. v-else
  1302. src="https://d31zlh4on95l9h.cloudfront.net/images/4621e0d1463a13c6654fe39215ee64c2.png"
  1303. class="action-btn"
  1304. />
  1305. <div class="count-number">{{ UserCount }}</div>
  1306. <div class="clickGetCount">
  1307. {{
  1308. activeTab === "deepNine" ? "深度九专属Token" : "点击获取Token"
  1309. }}
  1310. </div>
  1311. </div>
  1312. <div class="backToHomeBtn" @click="backToHome()">
  1313. <img
  1314. src="https://d31zlh4on95l9h.cloudfront.net/images/9272c00f21a2724c3a76e375949ee1de.png"
  1315. alt="返回首页"
  1316. class="backImg"
  1317. />
  1318. <div class="backContent">返回首页</div>
  1319. </div>
  1320. <!-- <img
  1321. :src="announcementBtn"
  1322. class="announcement-btn action-btn"
  1323. @click="showAnnouncement"
  1324. />
  1325. <img
  1326. :src="feedbackBtn"
  1327. class="announcement-btn action-btn"
  1328. @click="showFeedback"
  1329. /> -->
  1330. </div>
  1331. </el-header>
  1332. <!-- 主体部分小人 问题轮询图 对话内容 -->
  1333. <el-main class="homepage-body">
  1334. <div class="main-wrapper">
  1335. <section class="tab-section">
  1336. <div
  1337. class="tab-container"
  1338. :class="{
  1339. pcTabContainer: !isMobile,
  1340. }"
  1341. >
  1342. <div class="tab-items-container">
  1343. <div
  1344. v-for="(tab, index) in tabs"
  1345. :key="tab.name"
  1346. @click="setActiveTab(tab.name, index)"
  1347. :class="[
  1348. 'tab-item',
  1349. { active: activeIndex === index && !isAnnouncementVisible },
  1350. ]"
  1351. >
  1352. <span>{{ tab.label }}</span>
  1353. </div>
  1354. </div>
  1355. <div v-if="!isMobile" class="pc-count-badge">
  1356. <div class="pc-countBtn" @click="showCount">
  1357. <div
  1358. class="pc-action-btn"
  1359. :class="{
  1360. 'dbqb-model': activeTab === 'dbqb',
  1361. 'emotion-model': activeTab === 'emotion',
  1362. 'deepnine-model': activeTab === 'deepNine',
  1363. }"
  1364. >
  1365. <div class="pc-count-number">{{ UserCount }}</div>
  1366. </div>
  1367. <div class="pc-clickGetCount">
  1368. {{
  1369. activeTab === "deepNine"
  1370. ? "深度九专属Token"
  1371. : "点击获取Token"
  1372. }}
  1373. </div>
  1374. </div>
  1375. <div class="pc-backToHomeBtn" @click="backToHome()">
  1376. <img
  1377. src="https://d31zlh4on95l9h.cloudfront.net/images/9272c00f21a2724c3a76e375949ee1de.png"
  1378. alt="返回首页"
  1379. class="pc-backImg"
  1380. />
  1381. <div class="pc-backContent">返回首页</div>
  1382. </div>
  1383. </div>
  1384. </div>
  1385. </section>
  1386. <!-- AIchat页面的独立滚动容器 -->
  1387. <div
  1388. v-show="activeTab === 'AIchat'"
  1389. class="tab-content"
  1390. :class="{
  1391. pcTabContent: !isMobile,
  1392. }"
  1393. ref="tabContentAIchat"
  1394. >
  1395. <component
  1396. v-if="activeTab === 'AIchat'"
  1397. :is="activeComponent"
  1398. :messages="messages"
  1399. @updateMessage="updateMessage"
  1400. @sendMessage="sendMessage"
  1401. @ensureAIchat="ensureAIchat"
  1402. @enableInput="enableInput"
  1403. />
  1404. </div>
  1405. <!-- AiEmotion页面的独立滚动容器 -->
  1406. <div
  1407. v-show="activeTab === 'AiEmotion'"
  1408. class="tab-content"
  1409. :class="{
  1410. pcTabContent: !isMobile,
  1411. }"
  1412. ref="tabContentAiEmotion"
  1413. >
  1414. <component
  1415. v-if="activeTab === 'AiEmotion'"
  1416. :is="activeComponent"
  1417. :messages="messages"
  1418. @updateMessage="updateMessage"
  1419. @sendMessage="sendMessage"
  1420. @ensureAIchat="ensureAIchat"
  1421. @enableInput="enableInput"
  1422. @scrollToBottom="handleAiEmotionScrollToBottom"
  1423. @showCount="showCount"
  1424. ref="aiEmotionRef"
  1425. />
  1426. </div>
  1427. <!-- deepNine页面的独立滚动容器 -->
  1428. <div
  1429. v-show="activeTab === 'deepNine'"
  1430. class="tab-content"
  1431. :class="{
  1432. pcTabContent: !isMobile,
  1433. }"
  1434. ref="tabContentDeepNine"
  1435. >
  1436. <component
  1437. v-if="activeTab === 'deepNine'"
  1438. :is="activeComponent"
  1439. :messages="messages"
  1440. @updateMessage="updateMessage"
  1441. @sendMessage="sendMessage"
  1442. @ensureAIchat="ensureAIchat"
  1443. @enableInput="enableInput"
  1444. @scrollToBottom="handleDeepNineScrollToBottom"
  1445. @showCount="showCount"
  1446. ref="deepNineRef"
  1447. />
  1448. </div>
  1449. </div>
  1450. </el-main>
  1451. <!-- 尾部 问题输入框 深度思考 多语言 语音播报 -->
  1452. <el-footer
  1453. class="homepage-footer"
  1454. :class="{
  1455. pcFooter: !isMobile,
  1456. }"
  1457. id="input"
  1458. >
  1459. <!-- 第一行按钮 -->
  1460. <div class="footer-first-line">
  1461. <div class="left-group">
  1462. <!-- <img v-if="isThinking" :src="thinkActive" @click="toggleThink" class="action-btn" />
  1463. <img v-else :src="thinkNoActive" @click="toggleThink" class="action-btn" />
  1464. <img :src="languageBtn" @click="changeLanguage" class="action-btn" /> -->
  1465. <!-- PC端按钮 -->
  1466. <template v-if="!isMobile">
  1467. <!-- 夺宝奇兵大模型按钮 -->
  1468. <img
  1469. :src="activeTab === 'AIchat' ? dbqbButton01 : dbqbButton02"
  1470. @click="setActiveTab('AIchat', 0)"
  1471. class="action-btn model-btn"
  1472. alt="夺宝奇兵大模型"
  1473. />
  1474. <!-- AI情绪大模型按钮 -->
  1475. <img
  1476. :src="
  1477. activeTab === 'AiEmotion' ? emotionButton01 : emotionButton02
  1478. "
  1479. @click="setActiveTab('AiEmotion', 1)"
  1480. class="action-btn model-btn"
  1481. alt="AI情绪大模型"
  1482. />
  1483. <!-- 深度九大模型按钮 -->
  1484. <img
  1485. :src="
  1486. activeTab === 'deepNine'
  1487. ? 'https://d31zlh4on95l9h.cloudfront.net/images/07349ebc846a6772b1ab8a47b54635ff.png'
  1488. : 'https://d31zlh4on95l9h.cloudfront.net/images/29f0ad8e4e47f58952cc4a957ce9db10.png'
  1489. "
  1490. @click="setActiveTab('deepNine', 2)"
  1491. class="action-btn model-btn"
  1492. alt="深度九大模型"
  1493. />
  1494. </template>
  1495. <!-- 手机端下拉选择 - 自定义组件 -->
  1496. <template v-else>
  1497. <div class="custom-select-container">
  1498. <div class="custom-select-header" @click="toggleDropdown">
  1499. <div class="select-option-with-image">
  1500. <img :src="getSelectedOptionImage()" class="option-image" />
  1501. <span>{{ getSelectedOptionLabel() }}</span>
  1502. </div>
  1503. <div
  1504. class="dropdown-arrow"
  1505. :class="{ 'arrow-up': isDropdownOpen }"
  1506. >
  1507. <img
  1508. src="https://d31zlh4on95l9h.cloudfront.net/images/5f96dfcbff643cbbcf0f2790dbb4e54a.png"
  1509. style="width: 24px; height: 24px; object-fit: contain"
  1510. alt="箭头"
  1511. />
  1512. </div>
  1513. </div>
  1514. <div class="custom-select-dropdown" v-if="isDropdownOpen">
  1515. <div
  1516. v-for="option in modelOptions"
  1517. :key="option.value"
  1518. class="custom-select-option"
  1519. :class="{
  1520. 'option-selected': activeTabMobile === option.value,
  1521. }"
  1522. @click="selectOption(option.value)"
  1523. >
  1524. <div class="select-option-with-image">
  1525. <img :src="option.image" class="option-image" />
  1526. <span>{{ option.label }}</span>
  1527. </div>
  1528. </div>
  1529. </div>
  1530. </div>
  1531. </template>
  1532. <!-- <img v-if="
  1533. getCurrentAudioStore().isVoiceEnabled &&
  1534. getCurrentAudioStore().isPlaying
  1535. " :src="voice" @click="toggleVoice" class="action-btn" style="animation: pulse 1.5s infinite" />
  1536. <img v-else-if="
  1537. getCurrentAudioStore().isVoiceEnabled &&
  1538. !getCurrentAudioStore().isPlaying
  1539. " :src="voiceNoActive" @click="toggleVoice" class="action-btn" />
  1540. <img v-else :src="voiceNoActive" @click="toggleVoice" class="action-btn" /> -->
  1541. </div>
  1542. </div>
  1543. <!-- 第二行输入框 -->
  1544. <div class="footer-second-line">
  1545. <!-- <img :src="msgBtn" class="msg-icon" /> -->
  1546. <div class="input-container">
  1547. <el-input
  1548. type="textarea"
  1549. v-model="message"
  1550. @focus="onFocus"
  1551. @blur="onBlur"
  1552. :autosize="{ minRows: 1, maxRows: 4 }"
  1553. class="msg-input"
  1554. @keydown.enter.exact.prevent="
  1555. isLoading || isInputDisabled ? null : sendMessage()
  1556. "
  1557. :disabled="isInputDisabled"
  1558. resize="none"
  1559. :class="{ input: !message && !inputing }"
  1560. @compositionstart="inputing = true"
  1561. @compositionend="inputing = false"
  1562. >
  1563. </el-input>
  1564. <img
  1565. :src="
  1566. isInputDisabled
  1567. ? 'https://d31zlh4on95l9h.cloudfront.net/images/aa192bcbc1682c97e1bc6fb422f2afff.png'
  1568. : 'https://d31zlh4on95l9h.cloudfront.net/images/e6ec2ae238ced85b74e0912e988f243e.png'
  1569. "
  1570. @click="sendMessage"
  1571. class="action-btn send-btn-inner"
  1572. :style="{
  1573. opacity: isInputDisabled ? 0.5 : 1,
  1574. cursor: isInputDisabled ? 'not-allowed' : 'pointer',
  1575. }"
  1576. />
  1577. </div>
  1578. </div>
  1579. </el-footer>
  1580. </el-container>
  1581. <el-container
  1582. v-else
  1583. class="main-container"
  1584. :class="{
  1585. collapsed: historyRecordRef?.isCollapsed && !isMobile,
  1586. unCollapsed: !historyRecordRef?.isCollapsed && !isMobile,
  1587. }"
  1588. >
  1589. <el-header class="homepage-head">
  1590. <!-- logo -->
  1591. <div class="homepage-logo">
  1592. <img
  1593. src="https://d31zlh4on95l9h.cloudfront.net/images/4c91fce359a1c184772857594c38e3b4.png"
  1594. alt="返回按钮"
  1595. class="backToHomeImg"
  1596. @click="feedbackBack"
  1597. />
  1598. <!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> -->
  1599. </div>
  1600. <div class="homepage-right-group">
  1601. <div class="count-badge" @click="showCount">
  1602. <img
  1603. v-if="activeTab !== 'deepNine'"
  1604. src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
  1605. class="action-btn"
  1606. />
  1607. <img
  1608. v-else
  1609. src="https://d31zlh4on95l9h.cloudfront.net/images/4621e0d1463a13c6654fe39215ee64c2.png"
  1610. class="action-btn"
  1611. />
  1612. <div class="count-number">{{ UserCount }}</div>
  1613. <div class="clickGetCount">点击获取Token</div>
  1614. </div>
  1615. <div class="backToHomeBtn" @click="backToHome()">
  1616. <img
  1617. src="https://d31zlh4on95l9h.cloudfront.net/images/9272c00f21a2724c3a76e375949ee1de.png"
  1618. alt="返回首页"
  1619. class="backImg"
  1620. />
  1621. <div class="backContent">返回首页</div>
  1622. </div>
  1623. <!-- <img
  1624. :src="announcementBtn"
  1625. class="announcement-btn action-btn"
  1626. @click="showAnnouncement"
  1627. />
  1628. <img
  1629. :src="feedbackBtn"
  1630. class="announcement-btn action-btn"
  1631. @click="showFeedback"
  1632. /> -->
  1633. </div>
  1634. </el-header>
  1635. <!-- 主体部分小人 问题轮询图 对话内容 -->
  1636. <el-main class="homepage-body">
  1637. <component :is="activeTwoTab" />
  1638. </el-main>
  1639. </el-container>
  1640. <!-- 弹窗 -->
  1641. <!-- 新增弹窗组件 -->
  1642. <el-dialog v-if="!isMobile" v-model="dialogVisible" width="48%">
  1643. <!-- 中间内容部分 -->
  1644. <div class="changeMsg">
  1645. <div class="changeInfo">
  1646. <div class="changeImg">
  1647. <img
  1648. :src="userInfo.img"
  1649. alt="头像"
  1650. class="changeImgClass"
  1651. @error="handleImageError"
  1652. />
  1653. </div>
  1654. <div class="changeContent">
  1655. <div class="changeUsername">{{ userInfo.nickname }}</div>
  1656. <div class="changeJwcode">精网号{{ userInfo.jwcode }}</div>
  1657. </div>
  1658. </div>
  1659. <div class="changeRule" @click="openTokenRuleDialog">
  1660. 兑换规则{{ changeRule.gold }}金币={{ changeRule.token }}Token
  1661. <div>点击查看详情</div>
  1662. </div>
  1663. </div>
  1664. <div class="changeLevel">
  1665. <div class="changeLevelTitle">兑换Token</div>
  1666. <div class="changeLevelContent">
  1667. <div
  1668. class="changeLevelItems"
  1669. v-for="item in changeLevelList"
  1670. :key="item"
  1671. :class="{
  1672. changeLevelItemsActive: item.position == activeLevel.position,
  1673. }"
  1674. @click="chooseLevel(item)"
  1675. >
  1676. <div class="changeLevelItem">
  1677. <div class="changeLevelItemToken">
  1678. <img
  1679. src="https://d31zlh4on95l9h.cloudfront.net/images/403ef762dd2f335df3b0c9e3fe488375.png"
  1680. alt="token"
  1681. class="changeLevelItemTokenImg"
  1682. />
  1683. {{ item.calculatedPosition }}
  1684. </div>
  1685. <div class="changeLevelItemToken">{{ item.position }} 金币</div>
  1686. </div>
  1687. </div>
  1688. </div>
  1689. </div>
  1690. <div class="changeNow">
  1691. 应付金额
  1692. <div class="changePay">{{ activeLevel.position }}</div>
  1693. (金币余额{{ gold }})
  1694. </div>
  1695. <div class="changeBtn" @click="changeToken">立即兑换</div>
  1696. </el-dialog>
  1697. <el-dialog v-else v-model="dialogVisible" width="80%">
  1698. <!-- 中间内容部分 -->
  1699. <div class="changeMsg">
  1700. <div class="changeInfo">
  1701. <div class="changeImg">
  1702. <img
  1703. :src="userInfo.img"
  1704. alt="头像"
  1705. class="changeImgClass"
  1706. @error="handleImageError"
  1707. />
  1708. </div>
  1709. <div class="changeContent">
  1710. <div class="changeJwcode">精网号{{ userInfo.jwcode }}</div>
  1711. </div>
  1712. </div>
  1713. </div>
  1714. <div class="changeLevel">
  1715. <div class="changeLevelTitle">
  1716. 兑换Token
  1717. <div class="changeRule" @click="openTokenRuleDialog">
  1718. (兑换规则{{ changeRule.gold }}金币={{ changeRule.token }}Token)
  1719. <div>点击查看详情</div>
  1720. </div>
  1721. </div>
  1722. <div class="changeLevelContent">
  1723. <div
  1724. class="changeLevelItems"
  1725. v-for="item in changeLevelList"
  1726. :key="item"
  1727. :class="{
  1728. changeLevelItemsActive: item.position == activeLevel.position,
  1729. }"
  1730. @click="chooseLevel(item)"
  1731. >
  1732. <div class="changeLevelItem">
  1733. <div class="changeLevelItemToken">
  1734. <img
  1735. src="https://d31zlh4on95l9h.cloudfront.net/images/403ef762dd2f335df3b0c9e3fe488375.png"
  1736. alt="token"
  1737. class="changeLevelItemTokenImg"
  1738. />
  1739. {{ item.calculatedPosition }}
  1740. </div>
  1741. <div class="changeLevelItemToken">{{ item.position }} 金币</div>
  1742. </div>
  1743. </div>
  1744. </div>
  1745. </div>
  1746. <div class="changeNow">
  1747. 应付金额
  1748. <div class="changePay">{{ activeLevel.position }}</div>
  1749. (金币余额{{ gold }})
  1750. </div>
  1751. <div class="changeBtn" @click="changeToken">立即兑换</div>
  1752. </el-dialog>
  1753. <el-dialog
  1754. v-model="rechargeDialogVisible"
  1755. :width="isMobile ? '60%' : '30%'"
  1756. :show-close="false"
  1757. >
  1758. <div class="rechargeDialogTitle">温馨提示</div>
  1759. <div class="rechargeDialogContent">
  1760. 尊敬的用户您好您当前的金币余额不足无法进行兑换可充值金币后进行兑换点击下方的前往充值可进行充值
  1761. </div>
  1762. <div class="rechargeDialogBtnGroup">
  1763. <div class="recharge" @click="goRecharge">前往充值</div>
  1764. <div
  1765. class="rechargeDialogCancel"
  1766. @click="rechargeDialogVisible = false"
  1767. >
  1768. 取消
  1769. </div>
  1770. </div>
  1771. </el-dialog>
  1772. <el-dialog
  1773. v-model="confirmDialogVisible"
  1774. :width="isMobile ? '60%' : '30%'"
  1775. :show-close="false"
  1776. align-center="true"
  1777. >
  1778. <div class="confirmDialogTitle">兑换</div>
  1779. <div class="confirmDialogContent">
  1780. 尊敬的用户您好您确认要花费{{ activeLevel.position }}金币兑换{{
  1781. activeLevel.calculatedPosition
  1782. }}Token吗
  1783. </div>
  1784. <div class="confirmDialogBtnGroup">
  1785. <div class="confirmDialogConfirm" @click="goChange()">确认</div>
  1786. <div class="confirmDialogCancel" @click="confirmDialogVisible = false">
  1787. 取消
  1788. </div>
  1789. </div>
  1790. </el-dialog>
  1791. <el-dialog
  1792. v-model="changeSuccessDialogVisible"
  1793. :width="isMobile ? '60%' : '30%'"
  1794. :show-close="false"
  1795. class="changeSuccessDialog"
  1796. align-center
  1797. center
  1798. >
  1799. <div class="changeSuccessDialogTitle">
  1800. <img
  1801. v-if="!isMobile"
  1802. src="https://d31zlh4on95l9h.cloudfront.net/images/84edd341b2ddec464fc4475254f7a309.png"
  1803. style="scale: 0.7"
  1804. alt="token图标"
  1805. />
  1806. 兑换成功
  1807. </div>
  1808. <div class="changeSuccessDialogContent">
  1809. 尊敬的用户恭喜您成功兑换{{ activeLevel.calculatedPosition }} Token
  1810. </div>
  1811. <div class="changeSuccessDialogFooter">
  1812. <button
  1813. class="confirmButton"
  1814. @click="changeSuccessDialogVisible = false"
  1815. >
  1816. 确定
  1817. </button>
  1818. </div>
  1819. </el-dialog>
  1820. <!-- Token规则提示框 -->
  1821. <div
  1822. v-if="tokenRuleDialogVisible"
  1823. class="tokenRuleDialog"
  1824. @click="closeTokenRuleDialog"
  1825. >
  1826. <div class="tokenRuleDialogContent" @click.stop>
  1827. <div class="tokenRuleDialogClose" @click="closeTokenRuleDialog">
  1828. <el-icon>
  1829. <Close />
  1830. </el-icon>
  1831. </div>
  1832. <div class="tokenRuleDialogTitle">Token规则</div>
  1833. <div class="tokenRuleSection">
  1834. <div class="tokenRuleSectionTitle">Token消耗规则</div>
  1835. <div class="tokenRuleItem">
  1836. "夺宝奇兵大模型""AI情绪大模型"中搜索股票消耗普通Token"深度九大模型"中搜索股票消耗专属Token
  1837. </div>
  1838. <div class="tokenRuleItem">
  1839. "夺宝奇兵大模型""AI情绪大模型""深度九大模型"中搜索股票若搜索成功内容正常生成则会消耗1Token
  1840. </div>
  1841. <div class="tokenRuleItem">
  1842. "夺宝奇兵大模型""AI情绪大模型""深度九大模型"中搜索股票若搜索有误无法生成内容则不会消耗Token
  1843. </div>
  1844. <div class="tokenRuleItem">
  1845. 搜索同一只股票产出内容相同时只扣除1Token
  1846. </div>
  1847. <div class="tokenRuleItem">
  1848. "夺宝奇兵"中的Token和"AI小财神"中的普通Token是互通的
  1849. </div>
  1850. </div>
  1851. <div class="tokenRuleSection">
  1852. <div class="tokenRuleSectionTitle">Token兑换规则</div>
  1853. <div class="tokenRuleItem">
  1854. 点击右上角"获取Token"即可进入Token兑换页进行金币兑换Token只能兑换普通Token
  1855. </div>
  1856. <div class="tokenRuleItem">
  1857. 金币兑换Token的比例为1金币=1Token一经兑换不予退还
  1858. </div>
  1859. </div>
  1860. <div class="tokenRuleNote">
  1861. 注意报告生成过程中请耐心等待在此期间请勿进行页面刷新操作以免导致报告生成进程中断
  1862. </div>
  1863. </div>
  1864. </div>
  1865. </div>
  1866. </template>
  1867. <style scoped>
  1868. /* 标签栏 */
  1869. .tab-container {
  1870. display: flex;
  1871. margin-bottom: 10px;
  1872. height: 100%;
  1873. position: relative;
  1874. align-items: center;
  1875. width: 100%;
  1876. /* 使用三段式布局 */
  1877. justify-content: space-between;
  1878. }
  1879. .tab-items-container {
  1880. display: flex;
  1881. justify-content: center;
  1882. flex: 1;
  1883. gap: 200px;
  1884. }
  1885. .pcTabContainer {
  1886. padding: 0 20px;
  1887. /* 添加内边距,避免内容贴边 */
  1888. }
  1889. .tab-item {
  1890. cursor: pointer;
  1891. padding: 8px 12px;
  1892. font-size: clamp(18px, 3vw, 20px);
  1893. color: #fff;
  1894. transition: all 0.3s;
  1895. border-bottom: 2px solid transparent;
  1896. font-weight: bold;
  1897. /* 确保tab项目不会被挤压 */
  1898. flex-shrink: 0;
  1899. }
  1900. .tab-item.active {
  1901. /* color: #000;
  1902. border-color: #000; */
  1903. background: linear-gradient(0deg, #ffffff, #fec13e);
  1904. -webkit-background-clip: text;
  1905. background-clip: text;
  1906. -webkit-text-fill-color: transparent;
  1907. color: transparent;
  1908. border-color: #fec13e;
  1909. }
  1910. .tab-item:not(.active):hover {
  1911. color: #999999;
  1912. }
  1913. .tab-content {
  1914. overflow-y: auto;
  1915. overflow-x: hidden;
  1916. scroll-behavior: smooth;
  1917. height: 100%;
  1918. /* 添加平滑滚动效果 */
  1919. }
  1920. .pcTabContent {
  1921. padding: 0 6%;
  1922. }
  1923. .backToHomeImg {
  1924. width: 40px;
  1925. height: 40px;
  1926. margin-left: 10px;
  1927. }
  1928. @media (max-width: 768px) {
  1929. .tab-container {
  1930. justify-content: center;
  1931. }
  1932. .tab-items-container {
  1933. justify-content: center;
  1934. gap: 0px;
  1935. /* 移动端使用更小的间距 */
  1936. }
  1937. .tab-item {
  1938. font-size: clamp(14px, 3vw, 16px);
  1939. padding: 6px 10px;
  1940. }
  1941. }
  1942. </style>
  1943. <style scoped>
  1944. html {
  1945. height: 100dvh;
  1946. overflow: hidden !important;
  1947. position: fixed;
  1948. margin: 0;
  1949. padding: 0;
  1950. -webkit-overflow-scrolling: auto;
  1951. /* 禁用 iOS 弹性滚动 */
  1952. }
  1953. body {
  1954. height: 100dvh;
  1955. overflow: clip;
  1956. margin: 0;
  1957. padding: 0;
  1958. -webkit-overflow-scrolling: auto;
  1959. /* 禁用 iOS 弹性滚动 */
  1960. position: fixed;
  1961. }
  1962. #app {
  1963. overflow: hidden;
  1964. height: 100%;
  1965. margin: 0;
  1966. padding: 0;
  1967. }
  1968. .homepage {
  1969. /* height: var(--app-height, 100vh); */
  1970. height: var(--app-height, 100vh);
  1971. margin: 0 auto;
  1972. background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/98c8230d386012c9f1e70bf05a30de5e.png");
  1973. background-size: 100% 100%;
  1974. background-repeat: no-repeat;
  1975. background-position: center;
  1976. display: flex;
  1977. flex-direction: row;
  1978. /* 改为水平布局 */
  1979. overflow: hidden;
  1980. position: fixed;
  1981. top: 0;
  1982. left: 0;
  1983. right: 0;
  1984. bottom: 0;
  1985. width: 100%;
  1986. /* -webkit-overflow-scrolling: touch; */
  1987. }
  1988. .zhezhao {
  1989. width: 100%;
  1990. height: 100%;
  1991. background-color: rgba(0, 0, 0, 0.5);
  1992. z-index: 100;
  1993. position: fixed;
  1994. }
  1995. @media (min-width: 769px) {
  1996. .main-container {
  1997. flex: 1;
  1998. transition: margin-left 0.3s ease;
  1999. display: flex;
  2000. flex-direction: column;
  2001. overflow: hidden;
  2002. }
  2003. .main-container.unCollapsed {
  2004. margin-left: 300px;
  2005. /* 为历史记录组件留出空间 */
  2006. }
  2007. /* 当历史记录组件折叠时调整主容器边距 */
  2008. .main-container.collapsed {
  2009. margin-left: 40px;
  2010. }
  2011. }
  2012. /* 移动端适配 */
  2013. @media (max-width: 768px) {
  2014. .homepage {
  2015. background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/90d31d7052e729c63acb9e2cb94d1307.png");
  2016. }
  2017. }
  2018. .homepage .el-container {
  2019. height: 100%;
  2020. flex-direction: column;
  2021. display: flex;
  2022. width: 100%;
  2023. overflow: hidden;
  2024. /* 防止容器滚动 */
  2025. }
  2026. .el-container .el-header {
  2027. flex-shrink: 0;
  2028. /* 防止头部压缩 */
  2029. height: auto;
  2030. min-height: 60px;
  2031. padding: 5px 0;
  2032. position: sticky;
  2033. top: 0;
  2034. z-index: 10;
  2035. /* background-color: rgba(255, 255, 255, 0.9); */
  2036. }
  2037. .el-container .el-main {
  2038. flex: 1;
  2039. /* 自动占据剩余空间 */
  2040. overflow: hidden;
  2041. /* 主容器不滚动 */
  2042. display: flex;
  2043. flex-direction: column;
  2044. min-height: 0;
  2045. /* 允许内容区域缩小 */
  2046. position: relative;
  2047. height: auto;
  2048. }
  2049. .el-container .el-footer {
  2050. flex-shrink: 0;
  2051. height: auto;
  2052. min-height: 70px;
  2053. position: sticky;
  2054. bottom: 0;
  2055. z-index: 20;
  2056. background-color: rgba(211, 24, 24, 0);
  2057. box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
  2058. -webkit-transform: translateZ(0);
  2059. transform: translateZ(0);
  2060. padding-bottom: env(safe-area-inset-bottom, 0);
  2061. /* 适配iPhone X及以上的底部安全区域 */
  2062. }
  2063. .homepage-head {
  2064. padding: 0px;
  2065. display: flex;
  2066. position: relative;
  2067. justify-content: space-between;
  2068. width: 100%;
  2069. }
  2070. .homepage-right-group {
  2071. display: flex;
  2072. /* gap: 8px; */
  2073. align-items: center;
  2074. margin-left: auto;
  2075. margin-right: 5px;
  2076. }
  2077. .homepage-right-group .action-btn {
  2078. height: 40px;
  2079. }
  2080. .count-badge {
  2081. position: relative;
  2082. cursor: pointer;
  2083. }
  2084. .count-badge:hover {
  2085. transform: scale(1.05);
  2086. }
  2087. .count-number {
  2088. position: absolute;
  2089. top: 16px;
  2090. right: 0px;
  2091. width: 68%;
  2092. text-align: center;
  2093. color: #6a00ff;
  2094. }
  2095. .deepnine-model .count-number {
  2096. color: blue;
  2097. font-size: 12px;
  2098. font-weight: bold;
  2099. }
  2100. .clickGetCount {
  2101. width: 100%;
  2102. text-align: center;
  2103. color: white;
  2104. font-size: 12px;
  2105. }
  2106. .backToHomeBtn {
  2107. display: flex;
  2108. flex-direction: column;
  2109. justify-content: center;
  2110. align-items: center;
  2111. cursor: pointer;
  2112. }
  2113. .backToHomeBtn:hover {
  2114. transform: scale(1.05);
  2115. }
  2116. .backImg {
  2117. width: 60%;
  2118. height: auto;
  2119. }
  2120. .backContent {
  2121. width: 100%;
  2122. text-align: center;
  2123. color: white;
  2124. font-size: 12px;
  2125. white-space: nowrap;
  2126. }
  2127. .pc-count-badge {
  2128. display: flex;
  2129. height: 100%;
  2130. gap: 10px;
  2131. align-items: center;
  2132. /* 移除绝对定位,使用flex布局自然定位 */
  2133. flex-shrink: 0;
  2134. }
  2135. .pc-countBtn {
  2136. height: 60px;
  2137. width: 115px;
  2138. position: relative;
  2139. cursor: pointer;
  2140. display: flex;
  2141. flex-direction: column;
  2142. align-items: center;
  2143. }
  2144. .pc-countBtn:hover {
  2145. transform: scale(1.05);
  2146. }
  2147. .pc-action-btn {
  2148. width: 100%;
  2149. height: 70%;
  2150. background-repeat: no-repeat;
  2151. background-size: 100% 100%;
  2152. background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png");
  2153. }
  2154. .pc-action-btn.deepnine-model {
  2155. background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/4621e0d1463a13c6654fe39215ee64c2.png");
  2156. }
  2157. .pc-count-number {
  2158. position: absolute;
  2159. top: 15px;
  2160. right: 4px;
  2161. width: 68%;
  2162. text-align: center;
  2163. color: #6a00ff;
  2164. }
  2165. .deepnine-model .pc-count-number {
  2166. color: blue;
  2167. font-size: 15px;
  2168. font-weight: bold;
  2169. }
  2170. .pc-clickGetCount {
  2171. width: 100%;
  2172. text-align: center;
  2173. color: white;
  2174. font-size: 12px;
  2175. }
  2176. .pc-backToHomeBtn {
  2177. width: 30%;
  2178. height: 100%;
  2179. display: flex;
  2180. flex-direction: column;
  2181. align-items: center;
  2182. cursor: pointer;
  2183. }
  2184. .pc-backImg {
  2185. width: 100%;
  2186. height: auto;
  2187. }
  2188. .pc-backContent {
  2189. width: 100%;
  2190. text-align: center;
  2191. color: white;
  2192. font-size: 12px;
  2193. }
  2194. .pc-backToHomeBtn:hover {
  2195. transform: scale(1.05);
  2196. }
  2197. .homepage-right-group .announcement-btn {
  2198. cursor: pointer;
  2199. transition: transform 0.3s;
  2200. }
  2201. .homepage-right-group .announcement-btn:hover {
  2202. transform: scale(1.3);
  2203. }
  2204. .homepage-body {
  2205. padding: 0px;
  2206. display: flex;
  2207. flex-direction: column;
  2208. flex: 1;
  2209. min-height: 0;
  2210. /* 允许内容区域缩小 */
  2211. overflow: hidden;
  2212. }
  2213. .main-wrapper {
  2214. height: 100%;
  2215. display: flex;
  2216. flex-direction: column;
  2217. flex: 1;
  2218. min-height: 0;
  2219. /* 允许内容区域缩小 */
  2220. }
  2221. .tab-section {
  2222. flex-shrink: 0;
  2223. /* 禁止伸缩 */
  2224. }
  2225. .tab-content {
  2226. flex: 1;
  2227. overflow-y: auto;
  2228. min-height: 0;
  2229. /* 关键:允许内容收缩 */
  2230. }
  2231. .homepage-logo {
  2232. height: 100%;
  2233. width: fit-content;
  2234. display: flex;
  2235. /* flex-direction: column; */
  2236. align-items: center;
  2237. justify-content: center;
  2238. margin-left: 20px;
  2239. margin-right: auto;
  2240. position: relative;
  2241. gap: 10px;
  2242. }
  2243. .expand {
  2244. font-size: 2.5rem;
  2245. cursor: pointer;
  2246. color: white;
  2247. }
  2248. .logo1 {
  2249. width: 110px;
  2250. height: auto;
  2251. margin-bottom: 8px;
  2252. }
  2253. .logo2 {
  2254. width: 80px;
  2255. height: auto;
  2256. }
  2257. /* 尾部 */
  2258. .homepage-footer {
  2259. display: flex;
  2260. flex-direction: column;
  2261. gap: 5px;
  2262. flex-shrink: 0;
  2263. /* width: 100%; */
  2264. background-color: #fff;
  2265. }
  2266. .pcFooter {
  2267. margin: 0 6% 4%;
  2268. }
  2269. .footer-first-line {
  2270. display: flex;
  2271. justify-content: space-between;
  2272. align-items: center;
  2273. padding: 5px 15px;
  2274. flex-shrink: 0;
  2275. }
  2276. .left-group {
  2277. display: flex;
  2278. gap: 15px;
  2279. }
  2280. .action-btn {
  2281. cursor: pointer;
  2282. transition: transform 0.2s;
  2283. height: 28px;
  2284. }
  2285. .model-btn {
  2286. height: 32px;
  2287. transition: all 0.3s ease;
  2288. }
  2289. .model-btn:hover {
  2290. transform: scale(1.1);
  2291. }
  2292. /* 手机端模型选择器样式 */
  2293. .mobile-model-select {
  2294. width: 180px;
  2295. --el-select-border-color-hover: var(--el-border-color-hover);
  2296. --el-select-disabled-border: var(--el-disabled-border-color);
  2297. --el-select-font-size: var(--el-font-size-base);
  2298. --el-select-close-hover-color: var(--el-text-color-secondary);
  2299. --el-select-input-focus-border-color: var(--el-color-primary);
  2300. --el-select-input-font-size: 14px;
  2301. }
  2302. .send-btn {
  2303. margin-left: 10px;
  2304. height: 33px !important;
  2305. width: auto;
  2306. /* margin-right: 5px; */
  2307. }
  2308. .input-container {
  2309. position: relative;
  2310. width: 100%;
  2311. }
  2312. .send-btn-inner {
  2313. position: absolute;
  2314. right: 10px;
  2315. top: 50%;
  2316. transform: translateY(-50%);
  2317. height: 28px !important;
  2318. width: auto;
  2319. z-index: 10;
  2320. transition: all 0.3s ease;
  2321. }
  2322. .send-btn-inner:hover {
  2323. transform: translateY(-50%) scale(1.1);
  2324. }
  2325. /* 音频播放动画 */
  2326. @keyframes pulse {
  2327. 0% {
  2328. transform: scale(1);
  2329. }
  2330. 50% {
  2331. transform: scale(1.1);
  2332. }
  2333. 100% {
  2334. transform: scale(1);
  2335. }
  2336. }
  2337. .footer-second-line {
  2338. position: relative;
  2339. display: flex;
  2340. align-items: center;
  2341. padding: 5px 15px 10px;
  2342. flex-shrink: 0;
  2343. }
  2344. .msg-icon {
  2345. position: absolute;
  2346. left: 25px;
  2347. top: 50%;
  2348. transform: translateY(-50%);
  2349. width: 24px;
  2350. z-index: 999;
  2351. }
  2352. .msg-input:deep(.el-textarea__inner) {
  2353. border: none !important;
  2354. box-shadow: none !important;
  2355. overflow-y: auto !important;
  2356. transition: all 0.2s ease-out;
  2357. resize: none !important;
  2358. line-height: 1.5 !important;
  2359. max-height: 100px !important;
  2360. padding-right: 45px !important;
  2361. }
  2362. .msg-input {
  2363. min-height: 34px;
  2364. width: 100%;
  2365. border-radius: 5px;
  2366. font-size: 16px;
  2367. transition: all 0.3s ease-out;
  2368. overflow-y: hidden;
  2369. box-shadow: 0 4px 12px rgba(89, 24, 241, 0.3);
  2370. background: #fff;
  2371. z-index: 5;
  2372. /* 添加iOS设备特殊处理 */
  2373. -webkit-appearance: none;
  2374. appearance: none;
  2375. }
  2376. .msg-input:focus {
  2377. outline: none;
  2378. }
  2379. .input::before {
  2380. content: "请输入股票名称或股票代码...";
  2381. position: absolute;
  2382. left: 11px;
  2383. top: 5px;
  2384. color: var(--el-text-color-secondary);
  2385. pointer-events: none;
  2386. white-space: nowrap;
  2387. overflow-x: hidden;
  2388. text-overflow: ellipsis;
  2389. width: 80%;
  2390. z-index: 6;
  2391. }
  2392. .changeMsg {
  2393. display: flex;
  2394. width: 100%;
  2395. margin-bottom: 30px;
  2396. flex-wrap: wrap;
  2397. gap: 20px;
  2398. }
  2399. .changeInfo {
  2400. display: flex;
  2401. background-color: #f8f8f8;
  2402. border-radius: 5px;
  2403. padding: 10px 20px;
  2404. width: 40%;
  2405. white-space: nowrap;
  2406. align-items: center;
  2407. justify-content: center;
  2408. }
  2409. .changeImg {
  2410. height: 100%;
  2411. display: flex;
  2412. justify-content: center;
  2413. align-items: center;
  2414. margin-right: 10px;
  2415. }
  2416. .changeImgClass {
  2417. width: 50px;
  2418. height: auto;
  2419. }
  2420. .changeContent {
  2421. display: flex;
  2422. flex-direction: column;
  2423. justify-content: center;
  2424. font-weight: bold;
  2425. }
  2426. .changeRule {
  2427. display: flex;
  2428. flex-direction: column;
  2429. background-color: #f8f8f8;
  2430. border-radius: 5px;
  2431. text-align: center;
  2432. align-items: center;
  2433. justify-content: center;
  2434. color: #4e86fe;
  2435. white-space: nowrap;
  2436. padding: 5px 20px;
  2437. min-width: 40%;
  2438. transition: all 0.3s ease;
  2439. cursor: pointer;
  2440. }
  2441. .changeRule:hover {
  2442. background-color: #e8f0ff;
  2443. box-shadow: 0 2px 8px rgba(78, 134, 254, 0.2);
  2444. transform: translateY(-2px);
  2445. }
  2446. .changeLevel {
  2447. display: flex;
  2448. flex-direction: column;
  2449. }
  2450. .changeLevelTitle {
  2451. font-weight: bold;
  2452. margin-bottom: 10px;
  2453. }
  2454. .changeLevelContent {
  2455. display: flex;
  2456. flex-wrap: wrap;
  2457. gap: 15px;
  2458. margin-bottom: 10px;
  2459. }
  2460. .changeLevelItems {
  2461. display: flex;
  2462. background-color: #f8f8f8;
  2463. width: calc(20% - 12px);
  2464. min-width: 70px;
  2465. max-width: 150px;
  2466. justify-content: center;
  2467. align-items: center;
  2468. flex-direction: column;
  2469. border-radius: 10px;
  2470. padding: 5px;
  2471. cursor: pointer;
  2472. }
  2473. .changeLevelItems:hover {
  2474. background-color: #ecf2ff;
  2475. }
  2476. .changeLevelItemsActive {
  2477. border: 1px solid #4e86fe;
  2478. background-color: #ecf2ff;
  2479. }
  2480. .changeLevelItem {
  2481. display: flex;
  2482. flex-direction: column;
  2483. justify-content: center;
  2484. align-items: center;
  2485. }
  2486. .changeLevelItemToken {
  2487. display: flex;
  2488. justify-content: center;
  2489. align-items: center;
  2490. }
  2491. .changeLevelItemTokenImg {
  2492. width: 40px;
  2493. height: 40px;
  2494. }
  2495. .changeNow {
  2496. display: flex;
  2497. white-space: nowrap;
  2498. /* font-weight: bold; */
  2499. margin-bottom: 15px;
  2500. align-items: center;
  2501. }
  2502. .changePay {
  2503. color: #4e86fe;
  2504. margin: 0px 5px;
  2505. font-size: 1.1rem;
  2506. }
  2507. .changeBtn {
  2508. width: 40%;
  2509. max-width: 350px;
  2510. background-color: #4e86fe;
  2511. color: white;
  2512. display: flex;
  2513. justify-content: center;
  2514. align-content: center;
  2515. padding: 10px;
  2516. border-radius: 5px;
  2517. cursor: pointer;
  2518. margin: 0 auto;
  2519. }
  2520. .changeBtn:hover {
  2521. background-color: #3a73e6;
  2522. }
  2523. .rechargeDialogTitle {
  2524. font-size: 1.7rem;
  2525. /* font-weight: bold; */
  2526. color: #4e86fe;
  2527. display: flex;
  2528. justify-content: center;
  2529. align-items: center;
  2530. letter-spacing: 10px;
  2531. }
  2532. .rechargeDialogContent {
  2533. padding: 20px;
  2534. font-size: 1.2rem;
  2535. }
  2536. .rechargeDialogBtnGroup {
  2537. display: flex;
  2538. font-size: 1.2rem;
  2539. padding: 0px 20px;
  2540. justify-content: space-between;
  2541. }
  2542. .recharge {
  2543. color: white;
  2544. background-color: #4e86fe;
  2545. padding: 10px 20px;
  2546. border-radius: 13px;
  2547. cursor: pointer;
  2548. min-width: 20%;
  2549. text-align: center;
  2550. white-space: nowrap;
  2551. }
  2552. .recharge:hover {
  2553. background-color: #3a73e6;
  2554. }
  2555. .rechargeDialogCancel {
  2556. border: 1px solid rgb(202, 202, 202);
  2557. padding: 10px 20px;
  2558. border-radius: 13px;
  2559. cursor: pointer;
  2560. min-width: 20%;
  2561. text-align: center;
  2562. }
  2563. .rechargeDialogCancel:hover {
  2564. background-color: #ecf2ff;
  2565. }
  2566. .confirmDialogTitle {
  2567. font-size: 1.7rem;
  2568. /* font-weight: bold; */
  2569. color: #4e86fe;
  2570. display: flex;
  2571. justify-content: center;
  2572. align-items: center;
  2573. letter-spacing: 10px;
  2574. }
  2575. .confirmDialogContent {
  2576. padding: 20px;
  2577. font-size: 1.2rem;
  2578. }
  2579. .confirmDialogBtnGroup {
  2580. display: flex;
  2581. font-size: 1.2rem;
  2582. padding: 0px 20px;
  2583. justify-content: space-between;
  2584. }
  2585. .confirmDialogConfirm {
  2586. color: white;
  2587. background-color: #4e86fe;
  2588. padding: 10px 20px;
  2589. border-radius: 13px;
  2590. cursor: pointer;
  2591. min-width: 20%;
  2592. text-align: center;
  2593. }
  2594. .confirmDialogConfirm:hover {
  2595. background-color: #3a73e6;
  2596. }
  2597. .confirmDialogCancel {
  2598. border: 1px solid rgb(202, 202, 202);
  2599. padding: 10px 20px;
  2600. border-radius: 13px;
  2601. cursor: pointer;
  2602. min-width: 20%;
  2603. text-align: center;
  2604. }
  2605. .confirmDialogCancel:hover {
  2606. background-color: #ecf2ff;
  2607. }
  2608. .changeSuccessDialogTitle {
  2609. font-size: 1.7rem;
  2610. font-weight: bold;
  2611. color: #7849de;
  2612. display: flex;
  2613. justify-content: center;
  2614. align-items: center;
  2615. letter-spacing: 10px;
  2616. }
  2617. .changeSuccessDialogTitle image {
  2618. font-size: 1.7rem;
  2619. font-weight: bold;
  2620. color: #7849de;
  2621. display: flex;
  2622. justify-content: center;
  2623. align-items: center;
  2624. letter-spacing: 10px;
  2625. }
  2626. .changeSuccessDialogContent {
  2627. padding: 20px;
  2628. color: white;
  2629. font-size: 1.2rem;
  2630. font-weight: bold;
  2631. text-align: center;
  2632. }
  2633. /* Token规则提示框样式 - 与DBQBmodel无权限弹出框一致 */
  2634. .tokenRuleDialog {
  2635. width: 100%;
  2636. display: flex;
  2637. justify-content: center;
  2638. align-items: center;
  2639. position: fixed;
  2640. bottom: 20%;
  2641. color: white;
  2642. z-index: 9999;
  2643. }
  2644. .tokenRuleDialogContent {
  2645. position: relative;
  2646. border-radius: 5px;
  2647. border: 1px solid white;
  2648. padding: 20px 30px;
  2649. background-color: #261176;
  2650. display: flex;
  2651. flex-direction: column;
  2652. justify-content: center;
  2653. align-items: flex-start;
  2654. max-width: 500px;
  2655. width: 70vw;
  2656. max-height: 70vh;
  2657. /* overflow-y: auto; */
  2658. box-sizing: border-box;
  2659. }
  2660. .tokenRuleDialogClose {
  2661. border-radius: 5px;
  2662. border: 1px solid white;
  2663. background-color: #8621d9;
  2664. padding: 2px;
  2665. display: flex;
  2666. justify-content: center;
  2667. align-items: center;
  2668. position: absolute;
  2669. top: 0px;
  2670. right: 0px;
  2671. width: 24px;
  2672. height: 24px;
  2673. cursor: pointer;
  2674. color: white;
  2675. }
  2676. .tokenRuleDialogTitle {
  2677. color: #fec13e;
  2678. font-size: 20px;
  2679. font-weight: bold;
  2680. text-align: center;
  2681. width: 100%;
  2682. }
  2683. .tokenRuleSection {
  2684. width: 100%;
  2685. }
  2686. .tokenRuleSectionTitle {
  2687. color: #fec13e;
  2688. font-size: 16px;
  2689. font-weight: bold;
  2690. margin-bottom: 8px;
  2691. }
  2692. .tokenRuleItem {
  2693. color: white;
  2694. font-size: 16px;
  2695. line-height: 1.5;
  2696. }
  2697. .tokenRuleNote {
  2698. background: rgba(134, 33, 217, 0.3);
  2699. border: 1px solid #fec13e;
  2700. border-radius: 5px;
  2701. padding: 12px;
  2702. color: white;
  2703. font-size: 14px;
  2704. line-height: 1.5;
  2705. text-align: center;
  2706. word-wrap: break-word;
  2707. overflow-wrap: break-word;
  2708. }
  2709. @media (max-width: 768px) {
  2710. .tokenRuleDialog {
  2711. bottom: 20%;
  2712. }
  2713. .tokenRuleDialogContent {
  2714. width: 80vw;
  2715. padding: 15px 20px;
  2716. max-height: 85vh;
  2717. }
  2718. .tokenRuleDialogTitle {
  2719. font-size: 18px;
  2720. }
  2721. .tokenRuleSectionTitle {
  2722. font-size: 14px;
  2723. margin-bottom: 6px;
  2724. }
  2725. .tokenRuleItem {
  2726. font-size: 13px;
  2727. line-height: 1.4;
  2728. word-wrap: break-word;
  2729. overflow-wrap: break-word;
  2730. }
  2731. .tokenRuleNote {
  2732. font-size: 12px;
  2733. padding: 10px;
  2734. line-height: 1.4;
  2735. }
  2736. .tokenRuleDialogClose {
  2737. width: 20px;
  2738. height: 20px;
  2739. }
  2740. }
  2741. @media (max-width: 768px) {
  2742. .logo1 {
  2743. max-width: 110px;
  2744. width: 25vw;
  2745. }
  2746. .homepage-right-group {
  2747. gap: 10px;
  2748. }
  2749. .homepage-right-group .action-btn {
  2750. height: 30px;
  2751. }
  2752. .count-number {
  2753. top: 10px;
  2754. font-size: 12px;
  2755. }
  2756. .backImg {
  2757. width: 35px;
  2758. height: auto;
  2759. }
  2760. .action-btn {
  2761. height: 21px;
  2762. }
  2763. .footer-second-line {
  2764. padding: 5px 10px 10px;
  2765. }
  2766. .msg-input {
  2767. /* min-height: 44px; */
  2768. /* height: 44px; */
  2769. font-size: 16px;
  2770. }
  2771. /* .changeImg {
  2772. width: 30px;
  2773. height: 30px;
  2774. } */
  2775. .changeLevel {
  2776. flex-direction: horizontal;
  2777. }
  2778. .changeLevelContent {
  2779. display: flex;
  2780. /* justify-content: center; */
  2781. }
  2782. .changeLevelItems {
  2783. flex: 0 0 calc(33% - 20px);
  2784. /* margin-right: auto; */
  2785. }
  2786. .changeLevelTitle {
  2787. align-items: center;
  2788. display: flex;
  2789. flex-direction: column;
  2790. }
  2791. .changeRule {
  2792. margin-left: 10px;
  2793. width: 0%;
  2794. background-color: white;
  2795. }
  2796. .changeMsg {
  2797. gap: 10px 20px;
  2798. margin-bottom: 10px;
  2799. }
  2800. .changeImgClass {
  2801. width: 30px;
  2802. height: 30px;
  2803. }
  2804. /* .changeContent {
  2805. font-size: 0.5rem;
  2806. } */
  2807. .changeLevelItems {
  2808. font-size: 0.7rem;
  2809. min-width: 0px;
  2810. }
  2811. .changeLevelItemToken {
  2812. white-space: nowrap;
  2813. }
  2814. .changeLevelItemTokenImg {
  2815. width: 20px;
  2816. height: 20px;
  2817. }
  2818. .changeInfo {
  2819. margin: 0px auto;
  2820. }
  2821. .changeBtn {
  2822. margin: 0px auto;
  2823. }
  2824. .rechargeDialogTitle {
  2825. font-size: 1.3rem;
  2826. }
  2827. .rechargeDialogContent {
  2828. padding: 10px 0px;
  2829. font-size: 0.8rem;
  2830. }
  2831. .rechargeDialogBtnGroup {
  2832. font-size: 1rem;
  2833. }
  2834. .recharge {
  2835. padding: 5px 10px;
  2836. }
  2837. .rechargeDialogCancel {
  2838. padding: 5px 10px;
  2839. }
  2840. .confirmDialogTitle {
  2841. font-size: 1.3rem;
  2842. }
  2843. .confirmDialogContent {
  2844. padding: 10px 0px;
  2845. font-size: 0.8rem;
  2846. }
  2847. .confirmDialogBtnGroup {
  2848. font-size: 1rem;
  2849. }
  2850. .confirmDialogConfirm {
  2851. padding: 5px 10px;
  2852. }
  2853. .confirmDialogCancel {
  2854. padding: 5px 10px;
  2855. }
  2856. .changeSuccessDialogTitle {
  2857. font-size: 1.3rem;
  2858. }
  2859. .changeSuccessDialogContent {
  2860. font-size: 1rem;
  2861. }
  2862. }
  2863. @media (min-width: 320px) and (max-width: 375px) {
  2864. .tokenRuleDialog {
  2865. bottom: 10%;
  2866. }
  2867. }
  2868. </style>
  2869. <style>
  2870. .changeSuccessDialog {
  2871. background: linear-gradient(180deg, #80d3f8, #8080ff);
  2872. }
  2873. .changeSuccessDialogFooter {
  2874. display: flex;
  2875. justify-content: center;
  2876. margin-top: 20px;
  2877. }
  2878. .confirmButton {
  2879. background: #8a52df;
  2880. color: white;
  2881. border: none;
  2882. border-radius: 5px;
  2883. padding: 8px 30px;
  2884. font-size: 16px;
  2885. cursor: pointer;
  2886. transition: all 0.3s ease;
  2887. }
  2888. .confirmButton:hover {
  2889. background: #3a75e6;
  2890. transform: translateY(-2px);
  2891. box-shadow: 0 2px 8px rgba(78, 134, 254, 0.3);
  2892. }
  2893. /* 自定义下拉选择框样式 */
  2894. .custom-select-container {
  2895. position: relative;
  2896. width: 100%;
  2897. margin-bottom: 10px;
  2898. font-size: 14px;
  2899. user-select: none;
  2900. }
  2901. .custom-select-header {
  2902. display: flex;
  2903. align-items: center;
  2904. justify-content: space-between;
  2905. padding: 8px 12px;
  2906. background: #3549b9;
  2907. color: white;
  2908. border-radius: 4px;
  2909. cursor: pointer;
  2910. box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  2911. gap: 10px;
  2912. }
  2913. .dropdown-arrow {
  2914. transition: transform 0.3s ease;
  2915. display: flex;
  2916. }
  2917. .arrow-up {
  2918. transform: rotate(180deg);
  2919. }
  2920. .custom-select-dropdown {
  2921. position: absolute;
  2922. bottom: 100%;
  2923. left: 0;
  2924. width: 100%;
  2925. max-height: 200px;
  2926. overflow-y: auto;
  2927. background: #3549b9;
  2928. border-radius: 4px;
  2929. box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.15);
  2930. z-index: 100;
  2931. margin-bottom: 4px;
  2932. color: white;
  2933. }
  2934. .custom-select-option {
  2935. padding: 8px 12px;
  2936. cursor: pointer;
  2937. transition: background-color 0.2s;
  2938. }
  2939. .custom-select-option:hover {
  2940. background-color: #f5f7fa;
  2941. }
  2942. .option-selected {
  2943. background-color: #6a00ff;
  2944. color: white;
  2945. font-weight: 500;
  2946. }
  2947. .select-option-with-image {
  2948. display: flex;
  2949. align-items: center;
  2950. gap: 10px;
  2951. }
  2952. .option-image {
  2953. width: 24px;
  2954. height: 24px;
  2955. object-fit: contain;
  2956. }
  2957. </style>