You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1552 lines
40 KiB

<script setup>
// 导入
import { ref, computed, onMounted, watch, nextTick, onUnmounted, h } from "vue";
import { setHeight } from "../utils/setHeight";
import { getUserCountAPI } from "../api/AIxiaocaishen";
import { ElMessage } from "element-plus";
import AIchat from "./AIchat.vue";
import AIfind from "./AIfind.vue";
import Feedback from "./Feedback.vue";
import Announcement from "./Announcement.vue";
import { useAppBridge } from "../assets/js/useAppBridge.js";
import { useDataStore } from "@/store/dataList.js";
import { useChatStore } from "../store/chat";
import { useEmotionAudioStore } from "../store/emotionAudio";
import { useAudioStore } from "../store/audio";
import _ from "lodash";
import logo from "../assets/img/homePage/logo.png";
import madeInHL from "../assets/img/homePage/madeInHL.png";
import getCountAll from "../assets/img/homePage/get-count-all.png";
import announcementBtn from "../assets/img/homePage/announcement.png";
import thinkActive from "../assets/img/homePage/tail/think-active.png";
import thinkNoActive from "../assets/img/homePage/tail/think-no-active.png";
import languageBtn from "../assets/img/homePage/tail/language.png";
import dbqbButton01 from "../assets/img/AiEmotion/dbqb-button01.png";
import dbqbButton02 from "../assets/img/AiEmotion/dbqb-button02.png";
import emotionButton01 from "../assets/img/AiEmotion/emotion-button01.png";
import emotionButton02 from "../assets/img/AiEmotion/emotion-button02.png";
import voice from "../assets/img/homePage/tail/voice.png";
import voiceNoActive from "../assets/img/homePage/tail/voice-no-active.png";
import sendBtn from "../assets/img/homePage/tail/send.png";
import msgBtn from "../assets/img/homePage/tail/msg.png";
import feedbackBtn from "../assets/img/Feedback/feedbackBtn.png";
import AiEmotion from "./AiEmotion.vue";
import HistoryRecord from "./components/HistoryRecord.vue";
// import VConsole from "vconsole";
// const vConsole = new VConsole();
const isMobile = ref(null);
// 获取 AiEmotion 组件的 ref
const aiEmotionRef = ref(null);
// 获取历史记录组件的 ref
const historyRecordRef = ref(null);
// import { useUserStore } from "../store/userPessionCode.js";
const { getQueryVariable, setActiveTabIndex } = useDataStore();
const dataStore = useDataStore();
const chatStore = useChatStore();
// 变量
// 音频管理
const emotionAudioStore = useEmotionAudioStore();
const audioStore = useAudioStore();
// 根据当前页面类型获取对应的音频store
const getCurrentAudioStore = () => {
return activeTab.value === "AiEmotion" ? emotionAudioStore : audioStore;
};
const isVoice = computed(() => {
const currentStore = getCurrentAudioStore();
return currentStore.isVoiceEnabled;
});
const toggleVoice = () => {
const currentStore = getCurrentAudioStore();
if (!currentStore.isVoiceEnabled) {
// 如果语音功能关闭,先开启语音功能
currentStore.toggleVoice();
} else {
// 如果语音功能开启,则切换播放/暂停状态
if (currentStore.currentAudioUrl || currentStore.ttsUrl) {
// 有音频时切换播放/暂停
currentStore.togglePlayPause();
} else {
// 没有音频时关闭语音功能
currentStore.toggleVoice();
}
}
};
// 将默认值改为从 sessionStorage 中获取,如果没有则使用默认值 'aifindCow'为第一个默认tab
const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat");
const activeIndex = ref(
parseInt(sessionStorage.getItem("activeIndexAI") || "0")
);
const tabs = computed(() => [
{
name: "AIchat",
label: "夺宝奇兵大模型",
},
// {
// name: "AIfind",
// label: "发现",
// },
{
name: "AiEmotion",
label: "AI情绪大模型",
},
]);
// 修改 setActiveTab 方法,添加一个可选参数 forceAIchat
const setActiveTab = (tab, index, forceAIchat = false) => {
isScrolling.value = false; //回复滚动到底部方法
isAnnouncementVisible.value = false;
// 重置输入框禁用状态,防止页面切换时状态残留
isInputDisabled.value = false;
if (forceAIchat && activeTab.value !== "AIchat") {
activeTab.value = "AIchat";
activeIndex.value = 0;
sessionStorage.setItem("activeTabAI", "AIchat");
sessionStorage.setItem("activeIndexAI", "0");
} else {
activeTab.value = tab;
activeIndex.value = index;
sessionStorage.setItem("activeTabAI", tab);
sessionStorage.setItem("activeIndexAI", index.toString());
}
setActiveTabIndex(index);
console.log(tab, index, "tab, index");
setHeight(document.getElementById("testId")); // 给父组件发送窗口高度
};
// 修改 activeComponent 的计算逻辑
const activeComponent = computed(() => {
if (activeTab.value === "AIchat") {
return AIchat;
} else if (activeTab.value === "AIfind") {
return AIfind;
} else if (activeTab.value === "AiEmotion") {
return AiEmotion; // 新增逻辑
}
});
const activeTwoTab = computed(() => {
if (isAnnouncementVisible.value) {
return Announcement;
} else {
return Feedback;
}
});
// 新增一个方法,调用时先判断是否处于 AIchat,若不在则跳转到 AIchat
const ensureAIchat = () => {
setActiveTab("AIchat", 0, true);
};
// 获取次数
const UserCount = computed(() => chatStore.UserCount);
const getCount = () => {
console.log("点击了获取次数的按钮");
};
// 深度思考
const isThinking = ref(true);
const toggleThink = () => {
isThinking.value = !isThinking.value;
};
// 发送消息
const message = ref("");
// 传输对象
const messages = ref([]);
// 信息加载状态
const isLoading = computed(() => {
chatStore.isLoading;
});
// 输入框禁用状态(用于情绪大模型)
const isInputDisabled = ref(false);
// 添加用户消息
const updateMessage = (title) => {
message.value = title;
console.log("updateMessage 的值:", title);
};
watch(
() => chatStore.announcementMsg,
(newVal) => {
console.log("监听到公告改变", chatStore.announcementMsg);
if (chatStore.announcementMsg) {
message.value = chatStore.announcementMsg;
chatStore.announcementMsg = null;
}
}
);
watch(
() => dataStore.isFeedback,
async (newVal) => {
if (!dataStore.isFeedback) {
await nextTick();
// 监听页面高度
throttledHeightListener();
}
}
);
const sendMessage = async () => {
if (
localStorage.getItem("localToken") == null ||
localStorage.getItem("localToken") == ""
) {
ElMessage.error("请先登录");
return;
}
// 检查输入内容是否为空
if (!message.value || !message.value.trim()) {
ElMessage.warning("输入内容不能为空");
return;
}
isScrolling.value = false;
// 注意:历史记录会在消息发送后自动更新,无需手动添加
// 判断当前是否为 AiEmotion 组件
if (activeTab.value === "AiEmotion") {
// 禁用输入框
isInputDisabled.value = true;
// 调用 AiEmotion 组件的 handleSendMessage 方法
aiEmotionRef.value?.handleSendMessage(message.value, () => {
// 打字机效果完成后的回调,重新启用输入框
isInputDisabled.value = false;
});
message.value = ""; // 清空输入框
return;
}
// 调用 ensureAIchat 确保跳转到 AIchat 页面
ensureAIchat();
console.log(isInputDisabled.value, "isInputDisabled.value1111");
if (isInputDisabled.value) return;
isInputDisabled.value = true;
console.log(isInputDisabled.value, "isInputDisabled.value2222");
const messageContent = message.value;
// 重置消息输入框
message.value = "";
setTimeout(() => {
console.log("延时后添加消息", messageContent);
// 发送消息时,设置 isLoading 为 true
messages.value = [
...messages.value,
{
sender: "user",
content: messageContent,
timestamp: new Date().toISOString(),
audioArray: [],
audioStatus: true,
},
];
console.log(messages.value, "messages.value");
}, 200);
};
// 重新启用输入框的方法
const enableInput = () => {
console.log("解除禁用");
isInputDisabled.value = false;
};
// 处理历史记录选择
const handleHistorySelect = (stockData) => {
console.log("接收到历史记录数据:", stockData);
// 如果当前不在AiEmotion页面,切换到AiEmotion页面
// if (activeTab.value !== 'AiEmotion') {
// setActiveTab('AiEmotion', 1);
// }
// 等待组件渲染完成后调用addStock方法
nextTick(() => {
if (aiEmotionRef.value && aiEmotionRef.value.addStock) {
aiEmotionRef.value.addStock(stockData);
} else {
console.error("AiEmotion组件或addStock方法不可用");
}
});
};
// 公告
// 新增一个变量来控制是否显示公告页面
const isAnnouncementVisible = ref(false);
const showAnnouncement = async () => {
console.log("打开公告");
dataStore.isFeedback = true; // 显示用户反馈页面
isScrolling.value = false; //回复滚动到底部方法
isAnnouncementVisible.value = true; // 显示公告页面
if (isMobile.value) {
if (historyRecordRef) {
historyRecordRef.value.isCollapsed = true;
}
}
};
// 跳转用户反馈
const showFeedback = () => {
console.log("打开用户反馈");
dataStore.isFeedback = true; // 显示用户反馈页面
isAnnouncementVisible.value = false; // 显示反馈页面
if (isMobile.value) {
if (historyRecordRef) {
historyRecordRef.value.isCollapsed = true;
}
}
};
// 点击剩余次数会弹出的弹窗
// 新增一个 ref 来控制弹窗的显示与隐藏
const dialogVisible = ref(false);
// 获取次数
const showCount = () => {
console.log("显示剩余次数");
// 显示弹窗
dialogVisible.value = true;
console.log("dialogVisible 的值:", dialogVisible.value); // 添加日志确认
};
// 保证发送消息时,滚动屏在底部
const tabContent = ref(null);
const isScrolling = ref(false); //判断用户是否在滚动
const smoothScrollToBottom = async () => {
// console.log("调用滚动到底部的方法");
// await nextTick();
const container = tabContent.value;
// console.log(container, 'container')
// console.log(isScrolling.value, 'isScrolling.value')
if (!container) return;
await nextTick(); // 确保在DOM更新后执行
if (!isScrolling.value) {
container.scrollTop = container.scrollHeight - container.offsetHeight;
// container.scrollTop = container.scrollHeight;
// container.scrollTop = container.offsetHeight;
// container.scrollTop = container.scrollHeight + container.offsetHeight;
// console.log(container.scrollHeight, container.offsetHeight, container.scrollHeight - container.offsetHeight, container.scrollTop, "总长度", "可视长度", "位置")
}
};
const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 300, {
trailing: false,
});
watch(
() => chatStore.messages,
() => {
// console.log('messages变化了')
// 只有在AIchat页面时才执行自动滚动
if (activeTab.value === "AIchat") {
throttledSmoothScrollToBottom();
}
// setTimeout(throttledSmoothScrollToBottom, 100);
},
{ deep: true, immediate: true }
);
watch(
() => chatStore.dbqbClickRecord,
async (newValue, oldValue) => {
const container = tabContent.value;
if (!container) return;
await nextTick(); // 确保在DOM更新后执行
container.scrollTop = 0;
}
);
watch(
activeTab,
async () => {
console.log("activeTab变化了", activeTab.value);
if (activeTab.value == "AIchat" || activeTab.value == "AiEmotion") {
if (historyRecordRef.value && historyRecordRef.value.getHistoryList) {
historyRecordRef.value.getHistoryList({
model: activeTab.value == "AIchat" ? 1 : 2,
token: localStorage.getItem("localToken"),
});
}
}
if (activeTab.value === "AIchat") {
isScrolling.value = false; //回复滚动到底部方法
setTimeout(() => {
throttledSmoothScrollToBottom();
}, 100);
}
// AiEmotion页面不执行自动滚动,避免刷新后滚动到底部
// setTimeout(throttledSmoothScrollToBottom, 100);
},
{ deep: true, immediate: true }
);
// 获取token的核心函数
const fnGetToken = () => {
// console.log('进入fnGetToken')
window.JWready = (ress) => {
// console.log('进入JWready')
try {
ress = JSON.parse(ress);
// console.log(ress, 'ress')
} catch (error) {
console.log(error, "fnGetToken error");
} //platform为5是app端
// platform.value = ress.data.platform
// 处理平台判断
console.log(ress.data.platform, "ress.data.platform");
if (!ress.data.platform) {
// 非App环境通过URL参数获取
localStorage.setItem(
"localToken",
decodeURIComponent(String(getQueryVariable("token")))
);
// localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w")
} else {
// App环境通过桥接获取
useAppBridge().packageFun(
"JWgetStorage",
(response) => {
const res = JSON.parse(response); // 解析返回的结果
localStorage.setItem("localToken", res.data);
// localStorage.setItem('localToken', "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w")
},
5,
{
key: "token",
}
);
}
};
// console.log('出来了')
// 触发App桥接
useAppBridge().packageFun("JWwebReady", () => {}, 5, {});
};
// 在setTimeout中延迟执行
setTimeout(() => {
fnGetToken();
}, 800);
const heightListener = () => {
const tabContainer = tabContent.value;
let befortop = 0;
const scrollHandler = () => {
const aftertop = tabContainer.scrollTop;
// 新增底部判断逻辑
const isBottom =
aftertop + tabContainer.offsetHeight + 70 >= tabContainer.scrollHeight;
if (activeTab.value === "AIchat") {
if (aftertop - befortop > 0) {
// console.log("向下滚动");
isScrolling.value = true;
} else {
// console.log("向上滚动");
isScrolling.value = true;
}
// 添加底部状态检测
if (isBottom) {
// console.log("滚动到底部");
isScrolling.value = false;
}
}
befortop = aftertop;
};
// console.log(isScrolling.value, 'isScrolling.value')
tabContainer.addEventListener("scroll", scrollHandler);
};
const throttledHeightListener = _.throttle(heightListener, 500, {
trailing: false,
});
// const goToRecharge = () => {
// console.log("点击充值");
// // http://39.101.133.168:8919/payment/recharge/index?
// // url=http%3A%2F%2Flocalhost%3A8080%2FLiveActivity%2Fpck
// // &platform=1
// // &token=+S4h5QEE1hTIb4CxphrnbZi0+fEeMx8pywnIlrmTmo4QO6IolWnVWu5r+J4rKXMwK41UPfKqyIp+RvWmtM8
// 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;
// // window.open(rechargeUrl)
// };
const adjustFooterPosition = (height) => {
const html = document.querySelector("html");
const body = document.querySelector("body");
const isAndroid = /Android/i.test(navigator.userAgent);
if (isAndroid) {
console.log("是安卓设备");
console.log("window.visualViewport", window.visualViewport.height);
const homePage = document.querySelector(".homepage");
homePage.style.height = `${height}px`;
// homePage.style.height = `460px`;
html.scrollTop = 0;
} else {
console.log("非安卓设备");
console.log("调整底部位置", height);
const homePage = document.querySelector(".homepage");
homePage.style.height = `${height}px`;
html.scrollTop = 0;
}
setTimeout(() => {
// 隐藏滚动条
html.style.overflow = "hidden";
body.style.overflow = "hidden";
}, 200);
};
const onFocus = function () {
const visualViewport = window.visualViewport;
// 获取可视区域高度
setTimeout(() => {
console.log("输入框聚焦");
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);
};
const onBlur = function () {
const visualViewport = window.visualViewport;
setTimeout(() => {
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);
};
// window.addEventListener("resize", () => {
// // 检测是否为iOS设备
// const isIOS = /iPhone|iPad|iPod|ios/i.test(navigator.userAgent);
// console.log("是否为iOS设备:", isIOS);
// if (!isIOS) {
// console.log("窗口大小变化");
// const homePage = document.querySelector(".homepage");
// homePage.style.height = `${window.innerHeight}px`;
// }
// });
let touchmoveHandlerRef = null;
const touchmoveHandler = (e) => {
if (!dataStore.isFeedback) {
// 判断触摸目标是否在可滚动区域内
const isScrollableArea = e.target.closest(".tab-content");
// 如果不在可滚动区域,则阻止滚动
if (!isScrollableArea) {
e.preventDefault();
}
}
};
const judgeDevice = async () => {
// 延时300ms
await new Promise((resolve) => setTimeout(resolve, 200));
const userAgent = navigator.userAgent;
isMobile.value =
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
userAgent
);
console.log("当前设备为:", isMobile.value ? "移动端" : "PC端");
};
const throttledJudgeDevice = _.throttle(judgeDevice, 300, {
trailing: false,
});
const expandHistory = () => {
// if (activeTab.value == "AIchat" || activeTab.value == "AiEmotion") {
// historyRecordRef.value.getHistoryList({
// token: localStorage.getItem("localToken"),
// model: activeTab.value == "AIchat" ? 1 : 2,
// });
// }
if (
historyRecordRef.value &&
historyRecordRef.value.isCollapsed !== undefined
) {
console.log("存在");
historyRecordRef.value.isCollapsed = !historyRecordRef.value.isCollapsed;
}
};
const backToHome = () => {
if (isMobile.value) {
console.log("用户是移动端");
// 调用原生方法跳转到首页
uni.postMessage({
data: {
val: {
name: "JWopenView",
extra: {
data: {
type: 3,
},
},
},
},
});
} else {
console.log("用户是pc端");
const env = import.meta.env.VITE_ENV;
console.log("当前的环境为:", env);
if (env == "development" || env == "test") {
window.parent.location.href =
"http://121.89.234.155:8807/hljw/homepage?menu=999999991";
} else if (env == "product") {
window.parent.location.href =
"https://web.homilychart.com/product/hljw/homepage?menu=999999991";
} else if (env == "production") {
window.parent.location.href =
"https://web.homilychart.com/hljw/homepage?menu=999999991";
}
// window.parent.location.href = window.parent.document.referrer
}
};
onMounted(async () => {
throttledJudgeDevice();
// 禁用全局触摸滚动
touchmoveHandlerRef = touchmoveHandler;
document.addEventListener("touchmove", touchmoveHandlerRef, {
passive: false,
});
setHeight(document.getElementById("testId")); // 给父组件发送窗口高度
// 获取次数
await chatStore.getUserCount();
// 滚动到底部
throttledSmoothScrollToBottom();
// 监听页面高度
throttledHeightListener();
// 添加输入框焦点处理
// handleInputFocus();
// 初始化视口高度变量
// updateAppHeight();
// 添加原生事件监听器
window.addEventListener("resize", throttledJudgeDevice);
});
onUnmounted(() => {
window.removeEventListener("resize", throttledJudgeDevice);
if (touchmoveHandlerRef) {
console.log("卸载touchmoveHandlerRef组件");
document.removeEventListener("touchmove", touchmoveHandlerRef);
}
});
</script>
<template>
<div class="homepage" id="testId">
<!-- 历史记录组件 -->
<HistoryRecord
ref="historyRecordRef"
:current-type="activeTab"
@selectRecord="handleHistorySelect"
:isMobile="isMobile"
@showAnnouncement="showAnnouncement"
@showFeedback="showFeedback"
/>
<div
v-if="isMobile && !historyRecordRef?.isCollapsed"
class="zhezhao"
@click="expandHistory"
></div>
<el-container
v-if="!dataStore.isFeedback"
class="main-container"
:class="{
collapsed: historyRecordRef?.isCollapsed && !isMobile,
unCollapsed: !historyRecordRef?.isCollapsed && !isMobile,
}"
>
<!-- AI小财神头部: logo 次数 公告 -->
<el-header class="homepage-head">
<!-- logo -->
<div class="homepage-logo" v-if="isMobile">
<img
class="expand"
@click="expandHistory"
src="https://d31zlh4on95l9h.cloudfront.net/images/37fe3d79a8a700f6c674c9f0e7af066b.png"
alt="icon"
/>
<img :src="logo" alt="图片加载失败" class="logo1" />
<!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> -->
</div>
<div class="homepage-right-group" v-if="isMobile">
<div class="count-badge" @click="showCount">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
class="action-btn"
/>
<div class="count-number">{{ UserCount }}次</div>
<div class="clickGetCount">点击获取次数</div>
</div>
<div class="backToHomeBtn" @click="backToHome()">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/d8b388e461423f79087ddbe016002217.png"
alt="返回首页"
class="backImg"
/>
<div class="backContent">返回首页</div>
</div>
<!-- <img
:src="announcementBtn"
class="announcement-btn action-btn"
@click="showAnnouncement"
/>
<img
:src="feedbackBtn"
class="announcement-btn action-btn"
@click="showFeedback"
/> -->
</div>
</el-header>
<!-- 主体部分:小人 问题轮询图 对话内容 -->
<el-main class="homepage-body">
<div class="main-wrapper">
<section class="tab-section">
<div
class="tab-container"
:class="{
pcTabContainer: !isMobile,
}"
>
<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>
</div>
<div v-if="!isMobile" class="pc-count-badge">
<div class="pc-countBtn" @click="showCount">
<div class="pc-action-btn">
<div class="pc-count-number">{{ UserCount }}次</div>
</div>
<div class="pc-clickGetCount">点击获取次数</div>
</div>
<div class="pc-backToHomeBtn" @click="backToHome()">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/d8b388e461423f79087ddbe016002217.png"
alt="返回首页"
class="pc-backImg"
/>
<div class="pc-backContent">返回首页</div>
</div>
</div>
</div>
</section>
<div
class="tab-content"
:class="{
pcTabContent: !isMobile,
}"
ref="tabContent"
>
<component
:is="activeComponent"
:messages="messages"
@updateMessage="updateMessage"
@sendMessage="sendMessage"
@ensureAIchat="ensureAIchat"
@enableInput="enableInput"
ref="aiEmotionRef"
/>
</div>
</div>
</el-main>
<!-- 尾部: 问题输入框 深度思考 多语言 语音播报 -->
<el-footer
class="homepage-footer"
:class="{
pcFooter: !isMobile,
}"
id="input"
>
<!-- 第一行按钮 -->
<div class="footer-first-line">
<div class="left-group">
<!-- <img v-if="isThinking" :src="thinkActive" @click="toggleThink" class="action-btn" />
<img v-else :src="thinkNoActive" @click="toggleThink" class="action-btn" />
<img :src="languageBtn" @click="changeLanguage" class="action-btn" /> -->
<!-- 夺宝奇兵大模型按钮 -->
<img
:src="activeTab === 'AIchat' ? dbqbButton01 : dbqbButton02"
@click="setActiveTab('AIchat', 0)"
class="action-btn model-btn"
alt="夺宝奇兵大模型"
/>
<!-- AI情绪大模型按钮 -->
<img
:src="
activeTab === 'AiEmotion' ? emotionButton01 : emotionButton02
"
@click="setActiveTab('AiEmotion', 1)"
class="action-btn model-btn"
alt="AI情绪大模型"
/>
<!-- <img v-if="
getCurrentAudioStore().isVoiceEnabled &&
getCurrentAudioStore().isPlaying
" :src="voice" @click="toggleVoice" class="action-btn" style="animation: pulse 1.5s infinite" />
<img v-else-if="
getCurrentAudioStore().isVoiceEnabled &&
!getCurrentAudioStore().isPlaying
" :src="voiceNoActive" @click="toggleVoice" class="action-btn" />
<img v-else :src="voiceNoActive" @click="toggleVoice" class="action-btn" /> -->
</div>
</div>
<!-- 第二行输入框 -->
<div class="footer-second-line">
<!-- <img :src="msgBtn" class="msg-icon" /> -->
<div class="input-container">
<el-input
type="textarea"
v-model="message"
@focus="onFocus"
@blur="onBlur"
:autosize="{ minRows: 1, maxRows: 4 }"
placeholder="请输入股票名称或股票代码..."
class="msg-input"
@keydown.enter.exact.prevent="
isLoading || isInputDisabled ? null : sendMessage()
"
:disabled="isInputDisabled"
resize="none"
>
</el-input>
<img
:src="
isInputDisabled
? 'https://d31zlh4on95l9h.cloudfront.net/images/aa192bcbc1682c97e1bc6fb422f2afff.png'
: 'https://d31zlh4on95l9h.cloudfront.net/images/e6ec2ae238ced85b74e0912e988f243e.png'
"
@click="sendMessage"
class="action-btn send-btn-inner"
:style="{
opacity: isInputDisabled ? 0.5 : 1,
cursor: isInputDisabled ? 'not-allowed' : 'pointer',
}"
/>
</div>
</div>
</el-footer>
</el-container>
<el-container
v-else
class="main-container"
:class="{
collapsed: historyRecordRef?.isCollapsed && !isMobile,
unCollapsed: !historyRecordRef?.isCollapsed && !isMobile,
}"
>
<el-header class="homepage-head">
<!-- logo -->
<div class="homepage-logo">
<img :src="logo" alt="图片加载失败" class="logo1" />
<!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> -->
</div>
<div class="homepage-right-group">
<div class="count-badge" @click="showCount">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
class="action-btn"
/>
<div class="count-number">{{ UserCount }}次</div>
<div class="clickGetCount">点击获取次数</div>
</div>
<div class="backToHomeBtn" @click="backToHome()">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/d8b388e461423f79087ddbe016002217.png"
alt="返回首页"
class="backImg"
/>
<div class="backContent">返回首页</div>
</div>
<!-- <img
:src="announcementBtn"
class="announcement-btn action-btn"
@click="showAnnouncement"
/>
<img
:src="feedbackBtn"
class="announcement-btn action-btn"
@click="showFeedback"
/> -->
</div>
</el-header>
<!-- 主体部分:小人 问题轮询图 对话内容 -->
<el-main class="homepage-body">
<component :is="activeTwoTab" />
</el-main>
</el-container>
<!-- 弹窗 -->
<!-- 新增弹窗组件 -->
<el-dialog v-model="dialogVisible" max-width="65%">
<!-- 自定义标题插槽,实现居中显示 -->
<template #header>
<div style="text-align: center">
<span>活动规则</span>
</div>
</template>
<!-- 中间内容部分 -->
<div class="ruleContent">
<p>试运行期间,AI小财神可以检索全市场数据</p>
<p>(每个市场20支股票,股票详情参见【公告】页面)</p>
<!-- <p>弘历会员每人每日拥有10次检索机会!</p> -->
</div>
<!-- <template #footer> -->
<!-- 添加一个div来包裹按钮,并设置样式使其居中 -->
<!-- <div style="text-align: center"> -->
<!-- <el-button style="background-color: orange; color: white; border: none" @click="goToRecharge"> -->
<!-- 去充值 -->
<!-- </el-button> -->
<!-- </div> -->
<!-- </template> -->
</el-dialog>
</div>
</template>
<style scoped>
/* 标签栏 */
.tab-container {
display: flex;
margin-bottom: 10px;
height: 100%;
position: relative;
justify-content: center;
align-items: center;
gap: 25vw;
/* 新增右对齐 */
}
.pcTabContainer {
}
.tab-item {
cursor: pointer;
padding: 8px 12px;
font-size: clamp(18px, 3vw, 20px);
/* color: #999; */
color: #fff;
transition: all 0.3s;
border-bottom: 2px solid transparent;
font-weight: bold;
}
.tab-item.active {
/* color: #000;
border-color: #000; */
background: linear-gradient(0deg, #ffffff, #fec13e);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
border-color: #fec13e;
}
.tab-item:not(.active):hover {
color: #999999;
}
.tab-content {
overflow-y: auto;
overflow-x: hidden;
scroll-behavior: smooth;
height: 100%;
/* 添加平滑滚动效果 */
}
/* .pcTabContent {
margin: 0 6%;
} */
@media (max-width: 768px) {
.tab-container {
gap: 15px;
padding: 0 10px;
}
.tab-item {
font-size: clamp(14px, 3vw, 16px);
padding: 6px 10px;
}
}
</style>
<style scoped>
html {
height: 100dvh;
overflow: hidden !important;
position: fixed;
margin: 0;
padding: 0;
-webkit-overflow-scrolling: auto;
/* 禁用 iOS 弹性滚动 */
}
body {
height: 100dvh;
overflow: clip;
margin: 0;
padding: 0;
-webkit-overflow-scrolling: auto;
/* 禁用 iOS 弹性滚动 */
position: fixed;
}
#app {
overflow: hidden;
height: 100%;
margin: 0;
padding: 0;
}
.homepage {
/* height: var(--app-height, 100vh); */
height: var(--app-height, 100vh);
margin: 0 auto;
background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/2dc3c13a74100b906e809d26b66db211.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
display: flex;
flex-direction: row;
/* 改为水平布局 */
overflow: hidden;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
/* -webkit-overflow-scrolling: touch; */
}
.main-container {
flex: 1;
transition: margin-left 0.3s ease;
display: flex;
flex-direction: column;
overflow: hidden;
}
.main-container.unCollapsed {
margin-left: 300px; /* 为历史记录组件留出空间 */
}
/* 当历史记录组件折叠时调整主容器边距 */
.main-container.collapsed {
margin-left: 3%;
}
.zhezhao {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 100;
position: fixed;
}
/* 移动端适配 */
@media (max-width: 768px) {
.homepage {
background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/90d31d7052e729c63acb9e2cb94d1307.png");
}
.main-container {
/* margin-left: 280px; */
}
.main-container.unCollapsed {
margin-left: 280px;
}
.main-container.collapsed {
margin-left: 40px;
}
}
.homepage .el-container {
height: 100%;
flex-direction: column;
display: flex;
width: 100%;
overflow: hidden;
/* 防止容器滚动 */
}
.el-container .el-header {
flex-shrink: 0;
/* 防止头部压缩 */
height: auto;
min-height: 60px;
padding: 5px 0;
position: sticky;
top: 0;
z-index: 10;
/* background-color: rgba(255, 255, 255, 0.9); */
}
.el-container .el-main {
flex: 1;
/* 自动占据剩余空间 */
overflow: hidden;
/* 主容器不滚动 */
display: flex;
flex-direction: column;
min-height: 0;
/* 允许内容区域缩小 */
position: relative;
height: auto;
}
.el-container .el-footer {
flex-shrink: 0;
height: auto;
min-height: 70px;
position: sticky;
bottom: 0;
z-index: 20;
background-color: rgba(211, 24, 24, 0);
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
-webkit-transform: translateZ(0);
transform: translateZ(0);
padding-bottom: env(safe-area-inset-bottom, 0);
/* 适配iPhone X及以上的底部安全区域 */
}
.homepage-head {
padding: 0px;
display: flex;
position: relative;
justify-content: space-between;
width: 100%;
}
.homepage-right-group {
display: flex;
gap: 8px;
align-items: center;
margin-left: auto;
margin-right: 20px;
}
.homepage-right-group .action-btn {
height: 40px;
}
.count-badge {
position: relative;
cursor: pointer;
}
.count-badge:hover {
transform: scale(1.05);
}
.count-number {
position: absolute;
top: 16px;
right: 0px;
width: 68%;
text-align: center;
color: #6a00ff;
font-size: 14px;
font-weight: bold;
}
.clickGetCount {
width: 100%;
text-align: center;
color: white;
font-size: 12px;
}
.backToHomeBtn {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.backImg {
width: 100%;
height: auto;
}
.backContent {
width: 100%;
text-align: center;
color: white;
font-size: 12px;
white-space: nowrap;
}
.pc-count-badge {
width: 200px;
height: 100%;
position: absolute;
right: 20px;
display: flex;
}
.pc-countBtn {
width: 65%;
height: 100%;
position: relative;
}
.pc-countBtn:hover {
transform: scale(1.05);
}
.pc-action-btn {
width: 100%;
height: 70%;
background-image: url("https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png");
background-repeat: no-repeat;
background-size: 100% 100%;
}
.pc-count-number {
position: absolute;
top: 15px;
right: 4px;
width: 68%;
text-align: center;
color: #6a00ff;
font-size: 15px;
font-weight: bold;
}
.pc-clickGetCount {
width: 100%;
text-align: center;
color: white;
font-size: 12px;
}
.pc-backToHomeBtn {
width: 35%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.pc-backImg {
width: auto;
height: 70%;
}
.pc-backContent {
width: 100%;
text-align: center;
color: white;
font-size: 12px;
}
.pc-backToHomeBtn:hover {
transform: scale(1.05);
}
.homepage-right-group .announcement-btn {
cursor: pointer;
transition: transform 0.3s;
}
.homepage-right-group .announcement-btn:hover {
transform: scale(1.3);
}
.homepage-body {
padding: 0px;
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
/* 允许内容区域缩小 */
overflow: hidden;
}
.main-wrapper {
height: 100%;
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
/* 允许内容区域缩小 */
}
.tab-section {
flex-shrink: 0;
/* 禁止伸缩 */
}
.tab-content {
flex: 1;
overflow-y: auto;
min-height: 0;
/* 关键:允许内容收缩 */
}
.homepage-logo {
height: 100%;
width: fit-content;
display: flex;
/* flex-direction: column; */
align-items: center;
justify-content: center;
margin-left: 20px;
margin-right: auto;
position: relative;
gap: 10px;
}
.expand {
font-size: 2.5rem;
cursor: pointer;
color: white;
}
.logo1 {
width: 110px;
height: auto;
margin-bottom: 8px;
}
.logo2 {
width: 80px;
height: auto;
}
/* 尾部 */
.homepage-footer {
display: flex;
flex-direction: column;
gap: 5px;
flex-shrink: 0;
/* width: 100%; */
background-color: #fff;
}
.pcFooter {
margin: 0 6% 4%;
}
.footer-first-line {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 15px;
flex-shrink: 0;
}
.left-group {
display: flex;
gap: 15px;
}
.action-btn {
cursor: pointer;
transition: transform 0.2s;
height: 28px;
}
.model-btn {
height: 32px;
transition: all 0.3s ease;
}
.model-btn:hover {
transform: scale(1.1);
}
.send-btn {
margin-left: 10px;
height: 33px !important;
width: auto;
/* margin-right: 5px; */
}
.input-container {
position: relative;
width: 100%;
}
.send-btn-inner {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
height: 28px !important;
width: auto;
z-index: 10;
transition: all 0.3s ease;
}
.send-btn-inner:hover {
transform: translateY(-50%) scale(1.1);
}
/* 音频播放动画 */
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
.footer-second-line {
position: relative;
display: flex;
align-items: center;
padding: 5px 15px 10px;
flex-shrink: 0;
}
.msg-icon {
position: absolute;
left: 25px;
top: 50%;
transform: translateY(-50%);
width: 24px;
z-index: 999;
}
.msg-input:deep(.el-textarea__inner) {
border: none !important;
box-shadow: none !important;
overflow-y: auto !important;
transition: all 0.2s ease-out;
resize: none !important;
line-height: 1.5 !important;
max-height: 100px !important;
padding-right: 45px !important;
}
.msg-input:deep(.el-textarea__inner::placeholder) {
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
.msg-input {
min-height: 34px;
width: 100%;
border-radius: 5px;
font-size: 16px;
transition: all 0.3s ease-out;
overflow-y: hidden;
box-shadow: 0 4px 12px rgba(89, 24, 241, 0.3);
background: #fff;
z-index: 5;
/* 添加iOS设备特殊处理 */
-webkit-appearance: none;
appearance: none;
}
.msg-input:focus {
outline: none;
}
@media (max-width: 768px) {
.action-btn {
height: 21px;
}
.footer-second-line {
padding: 5px 10px 10px;
}
.msg-input {
/* min-height: 44px; */
/* height: 44px; */
font-size: 16px;
}
}
.ruleContent {
text-align: center;
}
</style>