|
@ -3,14 +3,14 @@ |
|
|
import { ref, computed, onMounted, watch, nextTick, onUnmounted } from "vue"; |
|
|
import { ref, computed, onMounted, watch, nextTick, onUnmounted } from "vue"; |
|
|
import { setHeight } from "../utils/setHeight"; |
|
|
import { setHeight } from "../utils/setHeight"; |
|
|
import { getUserCountAPI } from "../api/AIxiaocaishen"; |
|
|
import { getUserCountAPI } from "../api/AIxiaocaishen"; |
|
|
import { ElMessage } from 'element-plus' |
|
|
|
|
|
|
|
|
import { ElMessage } from "element-plus"; |
|
|
import AIchat from "./AIchat.vue"; |
|
|
import AIchat from "./AIchat.vue"; |
|
|
import AIfind from "./AIfind.vue"; |
|
|
import AIfind from "./AIfind.vue"; |
|
|
import Feedback from "./Feedback.vue"; |
|
|
import Feedback from "./Feedback.vue"; |
|
|
import { useAppBridge } from '../assets/js/useAppBridge.js' |
|
|
|
|
|
import { useDataStore } from '@/store/dataList.js' |
|
|
|
|
|
import { useChatStore } from '../store/chat' |
|
|
|
|
|
import { useAudioStore } from '../store/audio' |
|
|
|
|
|
|
|
|
import { useAppBridge } from "../assets/js/useAppBridge.js"; |
|
|
|
|
|
import { useDataStore } from "@/store/dataList.js"; |
|
|
|
|
|
import { useChatStore } from "../store/chat"; |
|
|
|
|
|
import { useAudioStore } from "../store/audio"; |
|
|
import _ from "lodash"; |
|
|
import _ from "lodash"; |
|
|
|
|
|
|
|
|
import logo from "../assets/img/homePage/logo.png"; |
|
|
import logo from "../assets/img/homePage/logo.png"; |
|
@ -31,24 +31,23 @@ import msgBtn from "../assets/img/homePage/tail/msg.png"; |
|
|
import feedbackBtn from "../assets/img/Feedback/feedbackBtn.png"; |
|
|
import feedbackBtn from "../assets/img/Feedback/feedbackBtn.png"; |
|
|
import AiEmotion from "./AiEmotion.vue"; |
|
|
import AiEmotion from "./AiEmotion.vue"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// import VConsole from 'vconsole'; |
|
|
// import VConsole from 'vconsole'; |
|
|
|
|
|
|
|
|
// const vConsole = new VConsole(); |
|
|
// const vConsole = new VConsole(); |
|
|
|
|
|
|
|
|
// 获取 AiEmotion 组件的 ref |
|
|
// 获取 AiEmotion 组件的 ref |
|
|
const aiEmotionRef = ref(null) |
|
|
|
|
|
|
|
|
const aiEmotionRef = ref(null); |
|
|
// import { useUserStore } from "../store/userPessionCode.js"; |
|
|
// import { useUserStore } from "../store/userPessionCode.js"; |
|
|
const { getQueryVariable, setActiveTabIndex } = useDataStore() |
|
|
|
|
|
const dataStore = useDataStore() |
|
|
|
|
|
const chatStore = useChatStore() |
|
|
|
|
|
|
|
|
const { getQueryVariable, setActiveTabIndex } = useDataStore(); |
|
|
|
|
|
const dataStore = useDataStore(); |
|
|
|
|
|
const chatStore = useChatStore(); |
|
|
// 变量 |
|
|
// 变量 |
|
|
// 音频管理 |
|
|
// 音频管理 |
|
|
const audioStore = useAudioStore() |
|
|
|
|
|
const isVoice = computed(() => audioStore.isVoiceEnabled) |
|
|
|
|
|
|
|
|
const audioStore = useAudioStore(); |
|
|
|
|
|
const isVoice = computed(() => audioStore.isVoiceEnabled); |
|
|
const toggleVoice = () => { |
|
|
const toggleVoice = () => { |
|
|
audioStore.toggleVoice() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
audioStore.toggleVoice(); |
|
|
|
|
|
}; |
|
|
// 将默认值改为从 sessionStorage 中获取,如果没有则使用默认值 'aifindCow'为第一个默认tab |
|
|
// 将默认值改为从 sessionStorage 中获取,如果没有则使用默认值 'aifindCow'为第一个默认tab |
|
|
const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat"); |
|
|
const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat"); |
|
|
const activeIndex = ref( |
|
|
const activeIndex = ref( |
|
@ -66,13 +65,13 @@ const tabs = computed(() => [ |
|
|
// }, |
|
|
// }, |
|
|
{ |
|
|
{ |
|
|
name: "AiEmotion", |
|
|
name: "AiEmotion", |
|
|
label: "AI情绪大模型" |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
label: "AI情绪大模型", |
|
|
|
|
|
}, |
|
|
]); |
|
|
]); |
|
|
|
|
|
|
|
|
// 修改 setActiveTab 方法,添加一个可选参数 forceAIchat |
|
|
// 修改 setActiveTab 方法,添加一个可选参数 forceAIchat |
|
|
const setActiveTab = (tab, index, forceAIchat = false) => { |
|
|
const setActiveTab = (tab, index, forceAIchat = false) => { |
|
|
isScrolling.value = false; //回复滚动到底部方法 |
|
|
|
|
|
|
|
|
isScrolling.value = false; //回复滚动到底部方法 |
|
|
isAnnouncementVisible.value = false; |
|
|
isAnnouncementVisible.value = false; |
|
|
if (forceAIchat && activeTab.value !== "AIchat") { |
|
|
if (forceAIchat && activeTab.value !== "AIchat") { |
|
|
activeTab.value = "AIchat"; |
|
|
activeTab.value = "AIchat"; |
|
@ -85,7 +84,7 @@ const setActiveTab = (tab, index, forceAIchat = false) => { |
|
|
sessionStorage.setItem("activeTabAI", tab); |
|
|
sessionStorage.setItem("activeTabAI", tab); |
|
|
sessionStorage.setItem("activeIndexAI", index.toString()); |
|
|
sessionStorage.setItem("activeIndexAI", index.toString()); |
|
|
} |
|
|
} |
|
|
setActiveTabIndex(index) |
|
|
|
|
|
|
|
|
setActiveTabIndex(index); |
|
|
console.log(tab, index, "tab, index"); |
|
|
console.log(tab, index, "tab, index"); |
|
|
setHeight(document.getElementById("testId")); // 给父组件发送窗口高度 |
|
|
setHeight(document.getElementById("testId")); // 给父组件发送窗口高度 |
|
|
}; |
|
|
}; |
|
@ -110,12 +109,11 @@ const ensureAIchat = () => { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// 获取次数 |
|
|
// 获取次数 |
|
|
const UserCount = computed(() => chatStore.UserCount) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const UserCount = computed(() => chatStore.UserCount); |
|
|
|
|
|
|
|
|
const getCount = () => { |
|
|
const getCount = () => { |
|
|
console.log('点击了获取次数的按钮') |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
console.log("点击了获取次数的按钮"); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
// 深度思考 |
|
|
// 深度思考 |
|
|
const isThinking = ref(true); |
|
|
const isThinking = ref(true); |
|
@ -128,7 +126,9 @@ const message = ref(""); |
|
|
// 传输对象 |
|
|
// 传输对象 |
|
|
const messages = ref([]); |
|
|
const messages = ref([]); |
|
|
// 信息加载状态 |
|
|
// 信息加载状态 |
|
|
const isLoading = computed(() => { chatStore.isLoading }); |
|
|
|
|
|
|
|
|
const isLoading = computed(() => { |
|
|
|
|
|
chatStore.isLoading; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
// 添加用户消息 |
|
|
// 添加用户消息 |
|
|
const updateMessage = (title) => { |
|
|
const updateMessage = (title) => { |
|
@ -136,14 +136,17 @@ const updateMessage = (title) => { |
|
|
// console.log("updateMessage 的值:", title); |
|
|
// console.log("updateMessage 的值:", title); |
|
|
}; |
|
|
}; |
|
|
const sendMessage = async () => { |
|
|
const sendMessage = async () => { |
|
|
if (localStorage.getItem('localToken') == null || localStorage.getItem('localToken') == '') { |
|
|
|
|
|
ElMessage.error('请先登录'); |
|
|
|
|
|
|
|
|
if ( |
|
|
|
|
|
localStorage.getItem("localToken") == null || |
|
|
|
|
|
localStorage.getItem("localToken") == "" |
|
|
|
|
|
) { |
|
|
|
|
|
ElMessage.error("请先登录"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
isScrolling.value = false; |
|
|
isScrolling.value = false; |
|
|
|
|
|
|
|
|
// 判断当前是否为 AiEmotion 组件 |
|
|
// 判断当前是否为 AiEmotion 组件 |
|
|
if (activeTab.value === 'AiEmotion') { |
|
|
|
|
|
|
|
|
if (activeTab.value === "AiEmotion") { |
|
|
// 调用 AiEmotion 组件的 handleSendMessage 方法 |
|
|
// 调用 AiEmotion 组件的 handleSendMessage 方法 |
|
|
aiEmotionRef.value?.handleSendMessage(message.value); |
|
|
aiEmotionRef.value?.handleSendMessage(message.value); |
|
|
message.value = ""; // 清空输入框 |
|
|
message.value = ""; // 清空输入框 |
|
@ -153,11 +156,11 @@ const sendMessage = async () => { |
|
|
// 调用 ensureAIchat 确保跳转到 AIchat 页面 |
|
|
// 调用 ensureAIchat 确保跳转到 AIchat 页面 |
|
|
ensureAIchat(); |
|
|
ensureAIchat(); |
|
|
|
|
|
|
|
|
console.log(chatStore.isLoading, 'isLoading.value1111'); |
|
|
|
|
|
|
|
|
console.log(chatStore.isLoading, "isLoading.value1111"); |
|
|
if (!message.value) return; |
|
|
if (!message.value) return; |
|
|
if (chatStore.isLoading) return; |
|
|
if (chatStore.isLoading) return; |
|
|
chatStore.setLoading(true); |
|
|
chatStore.setLoading(true); |
|
|
console.log(chatStore.isLoading, 'isLoading.value2222'); |
|
|
|
|
|
|
|
|
console.log(chatStore.isLoading, "isLoading.value2222"); |
|
|
|
|
|
|
|
|
const messageContent = message.value; |
|
|
const messageContent = message.value; |
|
|
// 重置消息输入框 |
|
|
// 重置消息输入框 |
|
@ -172,12 +175,10 @@ const sendMessage = async () => { |
|
|
sender: "user", |
|
|
sender: "user", |
|
|
content: messageContent, |
|
|
content: messageContent, |
|
|
timestamp: new Date().toISOString(), |
|
|
timestamp: new Date().toISOString(), |
|
|
} |
|
|
|
|
|
|
|
|
}, |
|
|
]; |
|
|
]; |
|
|
console.log(messages.value, 'messages.value'); |
|
|
|
|
|
|
|
|
console.log(messages.value, "messages.value"); |
|
|
}, 200); |
|
|
}, 200); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// 公告 |
|
|
// 公告 |
|
@ -190,8 +191,8 @@ const isAnnouncementVisible = ref(false); |
|
|
const showAnnouncement = async () => { |
|
|
const showAnnouncement = async () => { |
|
|
console.log("打开公告"); |
|
|
console.log("打开公告"); |
|
|
dataStore.isFeedback = false; // 显示用户反馈页面 |
|
|
dataStore.isFeedback = false; // 显示用户反馈页面 |
|
|
isScrolling.value = false; //回复滚动到底部方法 |
|
|
|
|
|
setActiveTab('', -1); // 清空当前选中状态 |
|
|
|
|
|
|
|
|
isScrolling.value = false; //回复滚动到底部方法 |
|
|
|
|
|
setActiveTab("", -1); // 清空当前选中状态 |
|
|
|
|
|
|
|
|
isAnnouncementVisible.value = true; // 显示公告页面 |
|
|
isAnnouncementVisible.value = true; // 显示公告页面 |
|
|
}; |
|
|
}; |
|
@ -200,7 +201,7 @@ const showAnnouncement = async () => { |
|
|
const showFeedback = () => { |
|
|
const showFeedback = () => { |
|
|
console.log("打开用户反馈"); |
|
|
console.log("打开用户反馈"); |
|
|
dataStore.isFeedback = true; // 显示用户反馈页面 |
|
|
dataStore.isFeedback = true; // 显示用户反馈页面 |
|
|
} |
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
// 点击剩余次数会弹出的弹窗 |
|
|
// 点击剩余次数会弹出的弹窗 |
|
|
// 新增一个 ref 来控制弹窗的显示与隐藏 |
|
|
// 新增一个 ref 来控制弹窗的显示与隐藏 |
|
@ -216,10 +217,10 @@ const showCount = () => { |
|
|
// 保证发送消息时,滚动屏在底部 |
|
|
// 保证发送消息时,滚动屏在底部 |
|
|
|
|
|
|
|
|
const tabContent = ref(null); |
|
|
const tabContent = ref(null); |
|
|
const isScrolling = ref(false); //判断用户是否在滚动 |
|
|
|
|
|
|
|
|
const isScrolling = ref(false); //判断用户是否在滚动 |
|
|
|
|
|
|
|
|
const smoothScrollToBottom = async () => { |
|
|
const smoothScrollToBottom = async () => { |
|
|
console.log('调用滚动到底部的方法') |
|
|
|
|
|
|
|
|
console.log("调用滚动到底部的方法"); |
|
|
// await nextTick(); |
|
|
// await nextTick(); |
|
|
const container = tabContent.value; |
|
|
const container = tabContent.value; |
|
|
// console.log(container, 'container') |
|
|
// console.log(container, 'container') |
|
@ -235,10 +236,11 @@ const smoothScrollToBottom = async () => { |
|
|
// container.scrollTop = container.scrollHeight + container.offsetHeight; |
|
|
// container.scrollTop = container.scrollHeight + container.offsetHeight; |
|
|
// console.log(container.scrollHeight, container.offsetHeight, container.scrollHeight - container.offsetHeight, container.scrollTop, "总长度", "可视长度", "位置") |
|
|
// console.log(container.scrollHeight, container.offsetHeight, container.scrollHeight - container.offsetHeight, container.scrollTop, "总长度", "可视长度", "位置") |
|
|
} |
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 500, { trailing: false }); |
|
|
|
|
|
|
|
|
const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 500, { |
|
|
|
|
|
trailing: false, |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
watch( |
|
|
watch( |
|
|
() => chatStore.messages, |
|
|
() => chatStore.messages, |
|
@ -250,16 +252,15 @@ watch( |
|
|
{ deep: true, immediate: true } |
|
|
{ deep: true, immediate: true } |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch( |
|
|
watch( |
|
|
activeTab, |
|
|
activeTab, |
|
|
async () => { |
|
|
async () => { |
|
|
console.log('activeTab变化了', activeTab.value) |
|
|
|
|
|
if (activeTab.value === 'AIchat') { |
|
|
|
|
|
isScrolling.value = false; //回复滚动到底部方法 |
|
|
|
|
|
|
|
|
console.log("activeTab变化了", activeTab.value); |
|
|
|
|
|
if (activeTab.value === "AIchat") { |
|
|
|
|
|
isScrolling.value = false; //回复滚动到底部方法 |
|
|
setTimeout(() => { |
|
|
setTimeout(() => { |
|
|
throttledSmoothScrollToBottom(); |
|
|
throttledSmoothScrollToBottom(); |
|
|
}, 100) |
|
|
|
|
|
|
|
|
}, 100); |
|
|
} |
|
|
} |
|
|
// setTimeout(throttledSmoothScrollToBottom, 100); |
|
|
// setTimeout(throttledSmoothScrollToBottom, 100); |
|
|
}, |
|
|
}, |
|
@ -272,43 +273,46 @@ const fnGetToken = () => { |
|
|
window.JWready = (ress) => { |
|
|
window.JWready = (ress) => { |
|
|
// console.log('进入JWready') |
|
|
// console.log('进入JWready') |
|
|
try { |
|
|
try { |
|
|
ress = JSON.parse(ress) |
|
|
|
|
|
|
|
|
ress = JSON.parse(ress); |
|
|
// console.log(ress, 'ress') |
|
|
// console.log(ress, 'ress') |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.log(error, 'fnGetToken error') |
|
|
|
|
|
|
|
|
console.log(error, "fnGetToken error"); |
|
|
} //platform为5是app端 |
|
|
} //platform为5是app端 |
|
|
// platform.value = ress.data.platform |
|
|
// platform.value = ress.data.platform |
|
|
// 处理平台判断 |
|
|
// 处理平台判断 |
|
|
console.log(ress.data.platform, 'ress.data.platform') |
|
|
|
|
|
|
|
|
console.log(ress.data.platform, "ress.data.platform"); |
|
|
if (!ress.data.platform) { |
|
|
if (!ress.data.platform) { |
|
|
// 非App环境通过URL参数获取 |
|
|
// 非App环境通过URL参数获取 |
|
|
localStorage.setItem('localToken', decodeURIComponent(String(getQueryVariable('token')))) |
|
|
|
|
|
|
|
|
localStorage.setItem( |
|
|
|
|
|
"localToken", |
|
|
|
|
|
decodeURIComponent(String(getQueryVariable("token"))) |
|
|
|
|
|
); |
|
|
// localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w") |
|
|
// localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w") |
|
|
} else { |
|
|
} else { |
|
|
// App环境通过桥接获取 |
|
|
// App环境通过桥接获取 |
|
|
useAppBridge().packageFun( |
|
|
useAppBridge().packageFun( |
|
|
'JWgetStorage', |
|
|
|
|
|
|
|
|
"JWgetStorage", |
|
|
(response) => { |
|
|
(response) => { |
|
|
const res = JSON.parse(response) // 解析返回的结果 |
|
|
|
|
|
localStorage.setItem('localToken', res.data) |
|
|
|
|
|
|
|
|
const res = JSON.parse(response); // 解析返回的结果 |
|
|
|
|
|
localStorage.setItem("localToken", res.data); |
|
|
// localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w") |
|
|
// localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w") |
|
|
}, |
|
|
}, |
|
|
5, |
|
|
5, |
|
|
{ |
|
|
{ |
|
|
key: 'token' |
|
|
|
|
|
|
|
|
key: "token", |
|
|
} |
|
|
} |
|
|
) |
|
|
|
|
|
|
|
|
); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
}; |
|
|
// console.log('出来了') |
|
|
// console.log('出来了') |
|
|
// 触发App桥接 |
|
|
// 触发App桥接 |
|
|
useAppBridge().packageFun('JWwebReady', () => { }, 5, {}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
useAppBridge().packageFun("JWwebReady", () => {}, 5, {}); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
// 在setTimeout中延迟执行 |
|
|
// 在setTimeout中延迟执行 |
|
|
setTimeout(() => { |
|
|
setTimeout(() => { |
|
|
fnGetToken() |
|
|
|
|
|
}, 800) |
|
|
|
|
|
|
|
|
fnGetToken(); |
|
|
|
|
|
}, 800); |
|
|
|
|
|
|
|
|
const heightListener = () => { |
|
|
const heightListener = () => { |
|
|
const tabContainer = tabContent.value; |
|
|
const tabContainer = tabContent.value; |
|
@ -318,9 +322,10 @@ const heightListener = () => { |
|
|
const aftertop = tabContainer.scrollTop; |
|
|
const aftertop = tabContainer.scrollTop; |
|
|
|
|
|
|
|
|
// 新增底部判断逻辑 |
|
|
// 新增底部判断逻辑 |
|
|
const isBottom = aftertop + tabContainer.offsetHeight + 50 >= tabContainer.scrollHeight; |
|
|
|
|
|
|
|
|
const isBottom = |
|
|
|
|
|
aftertop + tabContainer.offsetHeight + 50 >= tabContainer.scrollHeight; |
|
|
|
|
|
|
|
|
if (activeTab.value === 'AIchat') { |
|
|
|
|
|
|
|
|
if (activeTab.value === "AIchat") { |
|
|
if (aftertop - befortop > 0) { |
|
|
if (aftertop - befortop > 0) { |
|
|
// console.log('向下滚动'); |
|
|
// console.log('向下滚动'); |
|
|
isScrolling.value = true; |
|
|
isScrolling.value = true; |
|
@ -340,42 +345,52 @@ const heightListener = () => { |
|
|
|
|
|
|
|
|
// console.log(isScrolling.value, 'isScrolling.value') |
|
|
// console.log(isScrolling.value, 'isScrolling.value') |
|
|
|
|
|
|
|
|
tabContainer.addEventListener('scroll', scrollHandler); |
|
|
|
|
|
|
|
|
tabContainer.addEventListener("scroll", scrollHandler); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const throttledHeightListener = _.throttle(heightListener, 500, { trailing: false }); |
|
|
|
|
|
|
|
|
const throttledHeightListener = _.throttle(heightListener, 500, { |
|
|
|
|
|
trailing: false, |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
const goToRecharge = () => { |
|
|
const goToRecharge = () => { |
|
|
console.log('点击充值') |
|
|
|
|
|
|
|
|
console.log("点击充值"); |
|
|
// http://39.101.133.168:8919/payment/recharge/index? |
|
|
// http://39.101.133.168:8919/payment/recharge/index? |
|
|
// url=http%3A%2F%2Flocalhost%3A8080%2FLiveActivity%2Fpck |
|
|
// url=http%3A%2F%2Flocalhost%3A8080%2FLiveActivity%2Fpck |
|
|
// &platform=1 |
|
|
// &platform=1 |
|
|
// &token=+S4h5QEE1hTIb4CxphrnbZi0+fEeMx8pywnIlrmTmo4QO6IolWnVWu5r+J4rKXMwK41UPfKqyIp+RvWmtM8 |
|
|
// &token=+S4h5QEE1hTIb4CxphrnbZi0+fEeMx8pywnIlrmTmo4QO6IolWnVWu5r+J4rKXMwK41UPfKqyIp+RvWmtM8 |
|
|
|
|
|
|
|
|
const userAgent = navigator.userAgent.toLowerCase(); |
|
|
const userAgent = navigator.userAgent.toLowerCase(); |
|
|
const mobileKeywords = ['mobile', 'android', 'iphone', 'ipad', 'ipod']; |
|
|
|
|
|
const isMobile = mobileKeywords.some(keyword => userAgent.includes(keyword)); |
|
|
|
|
|
|
|
|
|
|
|
console.log(isMobile ? '手机' : '电脑') |
|
|
|
|
|
|
|
|
|
|
|
const url = encodeURI("http://39.101.133.168:8857/aixiaocaishen/homePage") |
|
|
|
|
|
console.log(url, 'url') |
|
|
|
|
|
const platform = isMobile ? 2 : 1 |
|
|
|
|
|
const token = encodeURIComponent(localStorage.getItem('localToken')) |
|
|
|
|
|
console.log(token, 'token') |
|
|
|
|
|
const rechargeUrl = 'http://39.101.133.168:8919/payment/recharge/index?' + 'url=' + url + '&platform=' + platform + '&token=' + token |
|
|
|
|
|
console.log(rechargeUrl, 'rechargeUrl') |
|
|
|
|
|
window.location.href = rechargeUrl |
|
|
|
|
|
|
|
|
const mobileKeywords = ["mobile", "android", "iphone", "ipad", "ipod"]; |
|
|
|
|
|
const isMobile = mobileKeywords.some((keyword) => |
|
|
|
|
|
userAgent.includes(keyword) |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
console.log(isMobile ? "手机" : "电脑"); |
|
|
|
|
|
|
|
|
|
|
|
const url = encodeURI("http://39.101.133.168:8857/aixiaocaishen/homePage"); |
|
|
|
|
|
console.log(url, "url"); |
|
|
|
|
|
const platform = isMobile ? 2 : 1; |
|
|
|
|
|
const token = encodeURIComponent(localStorage.getItem("localToken")); |
|
|
|
|
|
console.log(token, "token"); |
|
|
|
|
|
const rechargeUrl = |
|
|
|
|
|
"http://39.101.133.168:8919/payment/recharge/index?" + |
|
|
|
|
|
"url=" + |
|
|
|
|
|
url + |
|
|
|
|
|
"&platform=" + |
|
|
|
|
|
platform + |
|
|
|
|
|
"&token=" + |
|
|
|
|
|
token; |
|
|
|
|
|
console.log(rechargeUrl, "rechargeUrl"); |
|
|
|
|
|
window.location.href = rechargeUrl; |
|
|
// window.open(rechargeUrl) |
|
|
// window.open(rechargeUrl) |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
const adjustFooterPosition = (height) => { |
|
|
const adjustFooterPosition = (height) => { |
|
|
console.log('调整底部位置', height) |
|
|
|
|
|
const footer = document.querySelector('.el-footer'); |
|
|
|
|
|
const main = document.querySelector('.el-main'); |
|
|
|
|
|
const homePage = document.querySelector('.homepage'); |
|
|
|
|
|
const app = document.getElementById('app'); |
|
|
|
|
|
|
|
|
console.log("调整底部位置", height); |
|
|
|
|
|
const footer = document.querySelector(".el-footer"); |
|
|
|
|
|
const main = document.querySelector(".el-main"); |
|
|
|
|
|
const homePage = document.querySelector(".homepage"); |
|
|
|
|
|
const app = document.getElementById("app"); |
|
|
// Footer 的默认高度(假设为 60px) // 动态推高 Footer |
|
|
// Footer 的默认高度(假设为 60px) // 动态推高 Footer |
|
|
// footer.style.bottom = `${keyboardHeight}px`; |
|
|
// footer.style.bottom = `${keyboardHeight}px`; |
|
|
// 给 Main 区域留出 Footer + 键盘的空间 |
|
|
// 给 Main 区域留出 Footer + 键盘的空间 |
|
@ -384,8 +399,8 @@ const adjustFooterPosition = (height) => { |
|
|
|
|
|
|
|
|
void homePage.offsetHeight; |
|
|
void homePage.offsetHeight; |
|
|
|
|
|
|
|
|
const html = document.querySelector('html'); |
|
|
|
|
|
const body = document.querySelector('body'); |
|
|
|
|
|
|
|
|
const html = document.querySelector("html"); |
|
|
|
|
|
const body = document.querySelector("body"); |
|
|
|
|
|
|
|
|
html.style.height = `${height}px`; |
|
|
html.style.height = `${height}px`; |
|
|
body.style.height = `${height}px`; |
|
|
body.style.height = `${height}px`; |
|
@ -394,9 +409,9 @@ const adjustFooterPosition = (height) => { |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
setTimeout(() => { |
|
|
// 隐藏滚动条 |
|
|
// 隐藏滚动条 |
|
|
html.style.overflow = 'hidden'; |
|
|
|
|
|
body.style.overflow = 'hidden'; |
|
|
|
|
|
}, 200) |
|
|
|
|
|
|
|
|
html.style.overflow = "hidden"; |
|
|
|
|
|
body.style.overflow = "hidden"; |
|
|
|
|
|
}, 200); |
|
|
|
|
|
|
|
|
// console.log(html.offsetHeight, 'html') |
|
|
// console.log(html.offsetHeight, 'html') |
|
|
// console.log(html.clientHeight, 'html') |
|
|
// console.log(html.clientHeight, 'html') |
|
@ -411,68 +426,74 @@ const adjustFooterPosition = (height) => { |
|
|
// console.log(main.offsetHeight, 'main') |
|
|
// console.log(main.offsetHeight, 'main') |
|
|
// console.log(main.clientHeight, 'mainClientHeight') |
|
|
// console.log(main.clientHeight, 'mainClientHeight') |
|
|
// console.log(main.scrollHeight, 'mainScrollHeight') |
|
|
// console.log(main.scrollHeight, 'mainScrollHeight') |
|
|
|
|
|
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const onFocus = function () { |
|
|
const onFocus = function () { |
|
|
const visualViewport = window.visualViewport |
|
|
|
|
|
|
|
|
const visualViewport = window.visualViewport; |
|
|
// 获取可视区域高度 |
|
|
// 获取可视区域高度 |
|
|
setTimeout(() => { |
|
|
setTimeout(() => { |
|
|
console.log('输入框聚焦') |
|
|
|
|
|
|
|
|
console.log("输入框聚焦"); |
|
|
|
|
|
|
|
|
console.log(visualViewport.height, 'visualViewport.height') |
|
|
|
|
|
const keyboardHeight = window.innerHeight - visualViewport.height |
|
|
|
|
|
console.log(window.innerHeight, 'window.innerHeight') |
|
|
|
|
|
console.log(keyboardHeight, 'keyboardHeight') |
|
|
|
|
|
|
|
|
console.log(visualViewport.height, "visualViewport.height"); |
|
|
|
|
|
const keyboardHeight = window.innerHeight - visualViewport.height; |
|
|
|
|
|
console.log(window.innerHeight, "window.innerHeight"); |
|
|
|
|
|
console.log(keyboardHeight, "keyboardHeight"); |
|
|
|
|
|
|
|
|
adjustFooterPosition(visualViewport.height) |
|
|
|
|
|
}, 200) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
adjustFooterPosition(visualViewport.height); |
|
|
|
|
|
}, 200); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
const onBlur = function () { |
|
|
const onBlur = function () { |
|
|
const visualViewport = window.visualViewport |
|
|
|
|
|
|
|
|
const visualViewport = window.visualViewport; |
|
|
setTimeout(() => { |
|
|
setTimeout(() => { |
|
|
console.log('输入框失焦') |
|
|
|
|
|
|
|
|
console.log("输入框失焦"); |
|
|
|
|
|
|
|
|
const keyboardHeight = window.innerHeight - visualViewport.height |
|
|
|
|
|
console.log(window.innerHeight, 'window.innerHeight') |
|
|
|
|
|
console.log(visualViewport.height, 'visualViewport.height') |
|
|
|
|
|
console.log(keyboardHeight, 'keyboardHeight') |
|
|
|
|
|
adjustFooterPosition(visualViewport.height) |
|
|
|
|
|
}, 200) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
const keyboardHeight = window.innerHeight - visualViewport.height; |
|
|
|
|
|
console.log(window.innerHeight, "window.innerHeight"); |
|
|
|
|
|
console.log(visualViewport.height, "visualViewport.height"); |
|
|
|
|
|
console.log(keyboardHeight, "keyboardHeight"); |
|
|
|
|
|
adjustFooterPosition(visualViewport.height); |
|
|
|
|
|
}, 200); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
window.addEventListener('resize', () => { |
|
|
|
|
|
|
|
|
window.addEventListener("resize", () => { |
|
|
// 检测是否为iOS设备 |
|
|
// 检测是否为iOS设备 |
|
|
const isIOS = /iPhone|iPad|iPod|ios/i.test(navigator.userAgent); |
|
|
const isIOS = /iPhone|iPad|iPod|ios/i.test(navigator.userAgent); |
|
|
console.log('是否为iOS设备:', isIOS); |
|
|
|
|
|
|
|
|
console.log("是否为iOS设备:", isIOS); |
|
|
if (!isIOS) { |
|
|
if (!isIOS) { |
|
|
console.log('窗口大小变化') |
|
|
|
|
|
const homePage = document.querySelector('.homepage'); |
|
|
|
|
|
|
|
|
console.log("窗口大小变化"); |
|
|
|
|
|
const homePage = document.querySelector(".homepage"); |
|
|
homePage.style.height = `${window.innerHeight}px`; |
|
|
homePage.style.height = `${window.innerHeight}px`; |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// 禁用全局触摸滚动 |
|
|
// 禁用全局触摸滚动 |
|
|
document.addEventListener('touchmove', (e) => { |
|
|
|
|
|
if (!dataStore.isFeedback) { |
|
|
|
|
|
// 判断触摸目标是否在可滚动区域内 |
|
|
|
|
|
const isScrollableArea = e.target.closest('.tab-content'); |
|
|
|
|
|
|
|
|
|
|
|
// 如果不在可滚动区域,则阻止滚动 |
|
|
|
|
|
if (!isScrollableArea) { |
|
|
|
|
|
e.preventDefault(); |
|
|
|
|
|
|
|
|
document.addEventListener( |
|
|
|
|
|
"touchmove", |
|
|
|
|
|
(e) => { |
|
|
|
|
|
if (!dataStore.isFeedback) { |
|
|
|
|
|
// 判断触摸目标是否在可滚动区域内 |
|
|
|
|
|
const isScrollableArea = e.target.closest(".tab-content"); |
|
|
|
|
|
|
|
|
|
|
|
// 如果不在可滚动区域,则阻止滚动 |
|
|
|
|
|
if (!isScrollableArea) { |
|
|
|
|
|
e.preventDefault(); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
}, { passive: false }); |
|
|
|
|
|
|
|
|
}, |
|
|
|
|
|
{ passive: false } |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
onMounted(async () => { |
|
|
onMounted(async () => { |
|
|
const isPhone = |
|
|
const isPhone = |
|
|
/phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone/i.test( |
|
|
/phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone/i.test( |
|
|
navigator.userAgent |
|
|
navigator.userAgent |
|
|
) |
|
|
|
|
|
|
|
|
); |
|
|
!isPhone && |
|
|
!isPhone && |
|
|
localStorage.setItem('localToken', decodeURIComponent(String(getQueryVariable('token')))) |
|
|
|
|
|
|
|
|
localStorage.setItem( |
|
|
|
|
|
"localToken", |
|
|
|
|
|
decodeURIComponent(String(getQueryVariable("token"))) |
|
|
|
|
|
); |
|
|
setHeight(document.getElementById("testId")); // 给父组件发送窗口高度 |
|
|
setHeight(document.getElementById("testId")); // 给父组件发送窗口高度 |
|
|
// 获取次数 |
|
|
// 获取次数 |
|
|
await chatStore.getUserCount(); |
|
|
await chatStore.getUserCount(); |
|
@ -486,7 +507,7 @@ onMounted(async () => { |
|
|
|
|
|
|
|
|
// 初始化视口高度变量 |
|
|
// 初始化视口高度变量 |
|
|
// updateAppHeight(); |
|
|
// updateAppHeight(); |
|
|
}) |
|
|
|
|
|
|
|
|
}); |
|
|
</script> |
|
|
</script> |
|
|
|
|
|
|
|
|
<template> |
|
|
<template> |
|
@ -505,8 +526,16 @@ onMounted(async () => { |
|
|
<img :src="getCountAll" class="action-btn" /> |
|
|
<img :src="getCountAll" class="action-btn" /> |
|
|
<div class="count-number">{{ UserCount }}次</div> |
|
|
<div class="count-number">{{ UserCount }}次</div> |
|
|
</div> |
|
|
</div> |
|
|
<img :src="announcementBtn" class="announcement-btn action-btn" @click="showAnnouncement" /> |
|
|
|
|
|
<img :src="feedbackBtn" class="announcement-btn action-btn" @click="showFeedback" /> |
|
|
|
|
|
|
|
|
<img |
|
|
|
|
|
:src="announcementBtn" |
|
|
|
|
|
class="announcement-btn action-btn" |
|
|
|
|
|
@click="showAnnouncement" |
|
|
|
|
|
/> |
|
|
|
|
|
<img |
|
|
|
|
|
:src="feedbackBtn" |
|
|
|
|
|
class="announcement-btn action-btn" |
|
|
|
|
|
@click="showFeedback" |
|
|
|
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
</el-header> |
|
|
</el-header> |
|
|
|
|
|
|
|
@ -515,18 +544,30 @@ onMounted(async () => { |
|
|
<div class="main-wrapper"> |
|
|
<div class="main-wrapper"> |
|
|
<section class="tab-section"> |
|
|
<section class="tab-section"> |
|
|
<div class="tab-container"> |
|
|
<div class="tab-container"> |
|
|
<div v-for="(tab, index) in tabs" :key="tab.name" @click="setActiveTab(tab.name, index)" |
|
|
|
|
|
:class="['tab-item', { active: activeIndex === index && !isAnnouncementVisible }]"> |
|
|
|
|
|
|
|
|
<div |
|
|
|
|
|
v-for="(tab, index) in tabs" |
|
|
|
|
|
:key="tab.name" |
|
|
|
|
|
@click="setActiveTab(tab.name, index)" |
|
|
|
|
|
:class="[ |
|
|
|
|
|
'tab-item', |
|
|
|
|
|
{ active: activeIndex === index && !isAnnouncementVisible }, |
|
|
|
|
|
]" |
|
|
|
|
|
> |
|
|
<span>{{ tab.label }}</span> |
|
|
<span>{{ tab.label }}</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</section> |
|
|
</section> |
|
|
<div class="tab-content" ref="tabContent"> |
|
|
<div class="tab-content" ref="tabContent"> |
|
|
<component :is="activeComponent" :messages="messages" @updateMessage="updateMessage" |
|
|
|
|
|
@sendMessage="sendMessage" @ensureAIchat="ensureAIchat" ref="aiEmotionRef"/> |
|
|
|
|
|
|
|
|
<component |
|
|
|
|
|
:is="activeComponent" |
|
|
|
|
|
:messages="messages" |
|
|
|
|
|
@updateMessage="updateMessage" |
|
|
|
|
|
@sendMessage="sendMessage" |
|
|
|
|
|
@ensureAIchat="ensureAIchat" |
|
|
|
|
|
ref="aiEmotionRef" |
|
|
|
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
</el-main> |
|
|
</el-main> |
|
|
<!-- 尾部: 问题输入框 深度思考 多语言 语音播报 --> |
|
|
<!-- 尾部: 问题输入框 深度思考 多语言 语音播报 --> |
|
|
<el-footer class="homepage-footer" id="input"> |
|
|
<el-footer class="homepage-footer" id="input"> |
|
@ -545,16 +586,33 @@ onMounted(async () => { |
|
|
/> |
|
|
/> |
|
|
<!-- AI情绪大模型按钮 --> |
|
|
<!-- AI情绪大模型按钮 --> |
|
|
<img |
|
|
<img |
|
|
:src="activeTab === 'AiEmotion' ? emotionButton02 : emotionButton01" |
|
|
|
|
|
|
|
|
:src=" |
|
|
|
|
|
activeTab === 'AiEmotion' ? emotionButton02 : emotionButton01 |
|
|
|
|
|
" |
|
|
@click="setActiveTab('AiEmotion', 1)" |
|
|
@click="setActiveTab('AiEmotion', 1)" |
|
|
class="action-btn model-btn" |
|
|
class="action-btn model-btn" |
|
|
alt="AI情绪大模型" |
|
|
alt="AI情绪大模型" |
|
|
/> |
|
|
/> |
|
|
<img v-if="isVoice" :src="voice" @click="toggleVoice" class="action-btn" /> |
|
|
|
|
|
<img v-else :src="voiceNoActive" @click="toggleVoice" class="action-btn" /> |
|
|
|
|
|
|
|
|
<img |
|
|
|
|
|
v-if="isVoice" |
|
|
|
|
|
:src="voice" |
|
|
|
|
|
@click="toggleVoice" |
|
|
|
|
|
class="action-btn" |
|
|
|
|
|
/> |
|
|
|
|
|
<img |
|
|
|
|
|
v-else |
|
|
|
|
|
:src="voiceNoActive" |
|
|
|
|
|
@click="toggleVoice" |
|
|
|
|
|
class="action-btn" |
|
|
|
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
<img v-if="!chatStore.isLoading" :src="sendBtn" @click="sendMessage" class="action-btn send-btn" /> |
|
|
|
|
|
<div v-else> |
|
|
|
|
|
|
|
|
<img |
|
|
|
|
|
v-if="!chatStore.isLoading" |
|
|
|
|
|
:src="sendBtn" |
|
|
|
|
|
@click="sendMessage" |
|
|
|
|
|
class="action-btn send-btn" |
|
|
|
|
|
/> |
|
|
|
|
|
<div v-else @click="chatStore.setLoading(false)"> |
|
|
<el-icon class="is-loading"> |
|
|
<el-icon class="is-loading"> |
|
|
<Loading /> |
|
|
<Loading /> |
|
|
</el-icon> |
|
|
</el-icon> |
|
@ -564,9 +622,17 @@ onMounted(async () => { |
|
|
<!-- 第二行输入框 --> |
|
|
<!-- 第二行输入框 --> |
|
|
<div class="footer-second-line"> |
|
|
<div class="footer-second-line"> |
|
|
<img :src="msgBtn" class="msg-icon" /> |
|
|
<img :src="msgBtn" class="msg-icon" /> |
|
|
<el-input type="textarea" v-model="message" @focus="onFocus" @blur="onBlur" |
|
|
|
|
|
:autosize="{ minRows: 1, maxRows: 4 }" placeholder="给AI小财神发消息..." class="msg-input" |
|
|
|
|
|
@keydown.enter.exact.prevent="isLoading ? null : sendMessage()" resize="none"> |
|
|
|
|
|
|
|
|
<el-input |
|
|
|
|
|
type="textarea" |
|
|
|
|
|
v-model="message" |
|
|
|
|
|
@focus="onFocus" |
|
|
|
|
|
@blur="onBlur" |
|
|
|
|
|
:autosize="{ minRows: 1, maxRows: 4 }" |
|
|
|
|
|
placeholder="给AI小财神发消息..." |
|
|
|
|
|
class="msg-input" |
|
|
|
|
|
@keydown.enter.exact.prevent="isLoading ? null : sendMessage()" |
|
|
|
|
|
resize="none" |
|
|
|
|
|
> |
|
|
</el-input> |
|
|
</el-input> |
|
|
</div> |
|
|
</div> |
|
|
</el-footer> |
|
|
</el-footer> |
|
@ -584,8 +650,16 @@ onMounted(async () => { |
|
|
<img :src="getCountAll" class="action-btn" /> |
|
|
<img :src="getCountAll" class="action-btn" /> |
|
|
<div class="count-number">{{ UserCount }}次</div> |
|
|
<div class="count-number">{{ UserCount }}次</div> |
|
|
</div> |
|
|
</div> |
|
|
<img :src="announcementBtn" class="announcement-btn action-btn" @click="showAnnouncement" /> |
|
|
|
|
|
<img :src="feedbackBtn" class="announcement-btn action-btn" @click="showFeedback" /> |
|
|
|
|
|
|
|
|
<img |
|
|
|
|
|
:src="announcementBtn" |
|
|
|
|
|
class="announcement-btn action-btn" |
|
|
|
|
|
@click="showAnnouncement" |
|
|
|
|
|
/> |
|
|
|
|
|
<img |
|
|
|
|
|
:src="feedbackBtn" |
|
|
|
|
|
class="announcement-btn action-btn" |
|
|
|
|
|
@click="showFeedback" |
|
|
|
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
</el-header> |
|
|
</el-header> |
|
|
|
|
|
|
|
@ -605,15 +679,9 @@ onMounted(async () => { |
|
|
</template> |
|
|
</template> |
|
|
<!-- 中间内容部分 --> |
|
|
<!-- 中间内容部分 --> |
|
|
<div class="ruleContent"> |
|
|
<div class="ruleContent"> |
|
|
<p> |
|
|
|
|
|
试运行期间,AI小财神可以检索全市场数据 |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
(每个市场20支股票,股票详情参见【公告】页面), |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
弘历会员每人每日拥有10次检索机会! |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
<p>试运行期间,AI小财神可以检索全市场数据</p> |
|
|
|
|
|
<p>(每个市场20支股票,股票详情参见【公告】页面),</p> |
|
|
|
|
|
<p>弘历会员每人每日拥有10次检索机会!</p> |
|
|
</div> |
|
|
</div> |
|
|
<!-- <template #footer> --> |
|
|
<!-- <template #footer> --> |
|
|
<!-- 添加一个div来包裹按钮,并设置样式使其居中 --> |
|
|
<!-- 添加一个div来包裹按钮,并设置样式使其居中 --> |
|
@ -655,7 +723,7 @@ onMounted(async () => { |
|
|
.tab-item.active { |
|
|
.tab-item.active { |
|
|
/* color: #000; |
|
|
/* color: #000; |
|
|
border-color: #000; */ |
|
|
border-color: #000; */ |
|
|
background: linear-gradient(0deg, #ffffff, #fec13e); |
|
|
|
|
|
|
|
|
background: linear-gradient(0deg, #ffffff, #fec13e); |
|
|
-webkit-background-clip: text; |
|
|
-webkit-background-clip: text; |
|
|
background-clip: text; |
|
|
background-clip: text; |
|
|
-webkit-text-fill-color: transparent; |
|
|
-webkit-text-fill-color: transparent; |
|
|