Browse Source

Merge branch 'dongqian/feature-20250702094358-小财神适配' of http://39.101.133.168:8807/hongxilin/AIxiaocaishen into dongqian/feature-20250702094358-小财神适配

dongqian/feature-20250702094358-小财神适配
no99 12 hours ago
parent
commit
3e7c32451d
  1. 2
      build/vite/build.js
  2. 120
      src/views/AIchat.vue
  3. 121
      src/views/AiEmotion.vue
  4. 4
      src/views/components/emotionDecod.vue
  5. 7
      src/views/components/emotionalBottomRadar.vue

2
build/vite/build.js

@ -5,7 +5,7 @@ export function createBuild(viteEnv) {
outDir: VITE_OUTPUT_DIR,
cssCodeSplit: true, // 禁用 CSS 代码拆分,将整个项目中的所有 CSS 将被提取到一个 CSS 文件中
brotliSize: false, // 关闭打包计算
target: 'es2020',
target: 'esnext',
minify: 'terser', // 混淆器, terser 构建后文件体积更小, esbuild
// 小于此阈值的导入或引用资源将内联为 base64 编码,以避免额外的 http 请求。设置为 0 可以完全禁用此项
assetsInlineLimit: 4096,

120
src/views/AIchat.vue

@ -717,18 +717,37 @@ watch(
//
//
let isCallingPlayNext = false;
//
let currentPlayIndex = 0;
const playNextAudio = () => {
console.log('=== playNextAudio 被调用 ===');
console.log('当前队列状态:', {
queueLength: audioQueue.value.length,
queueItems: audioQueue.value.map(item => item.name),
currentPlayIndex: currentPlayIndex,
isPlayingAudio: isPlayingAudio.value,
isCallingPlayNext: isCallingPlayNext,
audioStoreIsPlaying: audioStore.isPlaying
});
if (audioQueue.value.length === 0 || isPlayingAudio.value || isCallingPlayNext) {
console.log('播放条件不满足 - 队列长度:', audioQueue.value.length, '正在播放:', isPlayingAudio.value, '正在调用:', isCallingPlayNext);
console.log('播放条件不满足 - 队列长度:', audioQueue.value.length, '正在播放:', isPlayingAudio.value, '正在调用:', isCallingPlayNext);
return;
}
//
if (currentPlayIndex >= audioQueue.value.length && audioQueue.value.length > 0) {
console.log('🔄 所有音频播放完成,重置索引从第一个开始');
currentPlayIndex = 0;
}
isCallingPlayNext = true;
isPlayingAudio.value = true;
const audioInfo = audioQueue.value.shift();
const audioInfo = audioQueue.value[currentPlayIndex];
console.log(`开始播放${audioInfo.name}音频,剩余队列:`, audioQueue.value.length);
console.log(`✅ 开始播放${audioInfo.name}音频 (索引:${currentPlayIndex}),队列总长度:`, audioQueue.value.length);
console.log('完整队列内容:', audioQueue.value.map((item, index) => `${index === currentPlayIndex ? '▶️' : '⏸️'} ${item.name}`));
//
if (audioStore.nowSound && (audioStore.nowSound.playing() || audioStore.nowSound.state() === 'loading')) {
@ -744,6 +763,7 @@ watch(
onplay: () => {
audioStore.isPlaying = true;
audioStore.isPaused = false;
isPlayingAudio.value = true; //
isCallingPlayNext = false; //
console.log(`${audioInfo.name}音频开始播放,时长:`, audio.duration());
console.log('音频播放状态确认 - isPlayingAudio:', isPlayingAudio.value, 'audioStore.isPlaying:', audioStore.isPlaying);
@ -761,21 +781,27 @@ watch(
},
onend: () => {
console.log(`${audioInfo.name}音频播放完成,准备播放下一个`);
console.log('播放完成时的状态 - 队列长度:', audioQueue.value.length, 'isPlayingAudio:', isPlayingAudio.value);
console.log('播放完成时的状态 - 当前索引:', currentPlayIndex, '队列长度:', audioQueue.value.length, 'isPlayingAudio:', isPlayingAudio.value);
audioStore.isPlaying = false;
audioStore.isPaused = false;
audioStore.playbackPosition = 0;
isPlayingAudio.value = false;
//
currentPlayIndex++;
//
if (audioQueue.value.length > 0) {
console.log('队列中还有音频,500ms后播放下一个,当前队列:', audioQueue.value.map(item => item.name));
if (currentPlayIndex < audioQueue.value.length) {
console.log(`队列中还有音频,500ms后播放下一个 (索引:${currentPlayIndex}),当前队列:`, audioQueue.value.map((item, index) => `${index === currentPlayIndex ? '▶️' : '⏸️'} ${item.name}`));
setTimeout(() => {
isCallingPlayNext = false; //
playNextAudio();
}, 500);
} else {
console.log('所有音频播放完成');
console.log('🎉 所有音频播放完成,清除音频实例,队列保持完整,下次播放将从第一个开始');
// 使
audioStore.nowSound = null;
audioStore.soundInstance = null;
isCallingPlayNext = false; //
}
},
@ -865,8 +891,10 @@ watch(
console.log('当前音频状态 - isPlaying:', audioStore.isPlaying, 'isPaused:', audioStore.isPaused);
console.log('当前音频实例:', audioStore.soundInstance);
console.log('队列播放状态 - isPlayingAudio:', isPlayingAudio.value, '队列长度:', audioQueue.value.length);
console.log('当前播放索引:', currentPlayIndex, '是否所有音频播放完成:', currentPlayIndex >= audioQueue.value.length);
if (audioStore.soundInstance) {
//
if (audioStore.soundInstance && currentPlayIndex < audioQueue.value.length && isPlayingAudio.value) {
if (audioStore.isPlaying) {
//
console.log('暂停当前音频');
@ -883,23 +911,77 @@ watch(
}
} else {
console.log('没有音频实例,检查是否需要重新播放队列');
console.log('重新播放条件检查:', {
isPlayingAudio: isPlayingAudio.value,
queueLength: audioQueue.value.length,
currentPlayIndex: currentPlayIndex,
condition1: audioQueue.value.length === 0,
condition2: currentPlayIndex >= audioQueue.value.length,
finalCondition: !isPlayingAudio.value && (audioQueue.value.length === 0 || currentPlayIndex >= audioQueue.value.length)
});
//
if (!isPlayingAudio.value && audioQueue.value.length === 0) {
if (!isPlayingAudio.value && (audioQueue.value.length === 0 || currentPlayIndex >= audioQueue.value.length)) {
console.log('所有音频播放完成,重新构建队列从第一个开始播放');
//
//
const audioItems = [];
if (audioPreloadStatus.one.url) {
addToAudioQueue(audioPreloadStatus.one.url, "API1-第一个");
audioItems.push({ url: audioPreloadStatus.one.url, name: "API1-第一个", order: 1 });
}
if (audioPreloadStatus.two.url) {
addToAudioQueue(audioPreloadStatus.two.url, "API2-第二个");
audioItems.push({ url: audioPreloadStatus.two.url, name: "API2-第二个", order: 2 });
}
if (audioPreloadStatus.three.url) {
addToAudioQueue(audioPreloadStatus.three.url, "API3-第三个");
audioItems.push({ url: audioPreloadStatus.three.url, name: "API3-第三个", order: 3 });
}
if (audioPreloadStatus.four.url) {
addToAudioQueue(audioPreloadStatus.four.url, "API4-第四个");
audioItems.push({ url: audioPreloadStatus.four.url, name: "API4-第四个", order: 4 });
}
//
audioItems.sort((a, b) => a.order - b.order);
audioQueue.value = audioItems;
console.log('队列重建完成,队列内容:', audioQueue.value.map(item => item.name));
console.log('开始从第一个音频播放');
//
if (audioQueue.value.length > 0) {
//
isPlayingAudio.value = false;
isCallingPlayNext = false;
currentPlayIndex = 0; //
audioStore.isPlaying = false;
audioStore.isPaused = false;
audioStore.playbackPosition = 0;
audioStore.nowSound = null;
audioStore.soundInstance = null;
console.log('🔄 状态完全重置完成,准备从第一个音频开始播放');
console.log('✅ 完全重置播放状态,准备播放第一个音频');
console.log('重置后状态检查:', {
isPlayingAudio: isPlayingAudio.value,
isCallingPlayNext: isCallingPlayNext,
currentPlayIndex: currentPlayIndex,
audioStoreIsPlaying: audioStore.isPlaying,
queueLength: audioQueue.value.length
});
setTimeout(() => {
console.log('🚀 延迟后开始播放第一个音频');
console.log('播放前最终状态检查:', {
currentPlayIndex: currentPlayIndex,
queueLength: audioQueue.value.length,
queueItems: audioQueue.value.map((item, index) => `${index}: ${item.name}`),
isPlayingAudio: isPlayingAudio.value,
isCallingPlayNext: isCallingPlayNext,
audioStoreIsPlaying: audioStore.isPlaying,
audioStoreInstance: !!audioStore.soundInstance
});
console.log('🎯 即将调用 playNextAudio,期望播放:', audioQueue.value[currentPlayIndex]?.name || '无音频');
playNextAudio();
}, 200);
}
console.log('队列重建完成,开始从第一个音频播放');
} else if (!isPlayingAudio.value && audioQueue.value.length > 0) {
console.log('队列中还有音频,继续播放');
playNextAudio();
@ -1342,7 +1424,7 @@ watch(
// }
// }, 50); // 50ms/
addTypingTask(aiMessage3, [ac31, ac32], 180);
addTypingTask(aiMessage3, [ac31, ac32], 200);
// chatStore.messages.push({
// sender: "ai",
@ -1423,7 +1505,7 @@ watch(
addTypingTask(
aiMessage4,
[ac41, ac42, ac43, ac44, ac45, ac46, ac47, ac48],
180
200
);
// chatStore.messages.push({
@ -1508,7 +1590,7 @@ watch(
// }
// }, 50); // 50ms/
addTypingTask(aiMessage5, [ac51, ac52, ac53, ac54], 180);
addTypingTask(aiMessage5, [ac51, ac52, ac53, ac54], 240);
// chatStore.messages.push({
// sender: "ai",
@ -1539,7 +1621,7 @@ watch(
// }
// }, 50); // 50ms/
addTypingTask(aiMessage6, ["", ac6], 180);
addTypingTask(aiMessage6, ["", ac6], 210);
// chatStore.messages.push({
// sender: "ai",

121
src/views/AiEmotion.vue

@ -24,7 +24,7 @@
<div v-if="isLoading" class="loading-container">
<div class="loading-content">
<div class="loading-spinner"></div>
<div class="loading-text">AI小财神正在加载图表数据和音频内容请稍候...</div>
<div class="loading-text">AI情绪大模型正在努力为您加载请稍候...</div>
</div>
</div>
<!-- 股票标签页 -->
@ -248,6 +248,8 @@ const hasTriggeredAudio = ref(false); // 是否已触发音频播放
const hasTriggeredTypewriter = ref(false); //
const intersectionObserver = ref(null); // observer
const isUserInitiated = ref(false); //
const isUserScrolling = ref(false); //
const scrollTimeout = ref(null); //
//
const displayedTexts = ref({
@ -291,7 +293,19 @@ const stockName = computed(() => currentStock.value?.stockInfo.name || "");
const displayDate = computed(() => {
if (!currentStock.value?.apiData) return "";
const lastData = currentStock.value.apiData.GSWDJ?.at(-1);
return lastData ? lastData[0] : "";
if (!lastData || !lastData[0]) return "";
const dateStr = lastData[0];
// YYYY-MM-DD YYYY/MM/DD
const dateMatch = dateStr.match(/(\d{4})[\-\/](\d{1,2})[\-\/](\d{1,2})/);
if (dateMatch) {
const [, year, month, day] = dateMatch;
// DD/MM/YYYY
return `更新时间:${day.padStart(2, '0')}/${month.padStart(2, '0')}/${year}`;
}
//
return dateStr;
});
const data1 = computed(() => {
if (!currentStock.value?.apiData) return null;
@ -744,6 +758,12 @@ function startTypewriterEffect(conclusion) {
for (let i = 0; i <= disclaimerText.length; i++) {
const timer = setTimeout(() => {
displayedTexts.value.disclaimer = disclaimerText.substring(0, i);
//
if (i === disclaimerText.length) {
setTimeout(() => {
scrollToBottom();
}, 100);
}
}, totalDelay + i * typeSpeed);
typewriterTimers.value.push(timer);
}
@ -792,6 +812,10 @@ function playAudio(url) {
isAudioPlaying.value = true;
emotionAudioStore.isPlaying = true;
console.log('开始播放场景应用语音');
//
setTimeout(() => {
scrollToBottom();
}, 100);
},
onend: () => {
isAudioPlaying.value = false;
@ -1143,6 +1167,12 @@ function renderCharts(data) {
}
const scrollToBottom = async () => {
//
if (isUserScrolling.value) {
console.log('用户正在手动滚动,跳过自动滚动');
return;
}
const container = userInputDisplayRef.value;
if (!container) return;
await nextTick();
@ -1152,6 +1182,32 @@ const scrollToBottom = async () => {
container.scrollTop = container.scrollHeight - container.offsetHeight;
};
//
const handleUserScroll = () => {
isUserScrolling.value = true;
//
if (scrollTimeout.value) {
clearTimeout(scrollTimeout.value);
}
// 2
scrollTimeout.value = setTimeout(() => {
isUserScrolling.value = false;
console.log('用户滚动结束,重新允许自动滚动');
}, 2000);
};
//
const handleWheel = (event) => {
handleUserScroll();
};
//
const handleTouchMove = (event) => {
handleUserScroll();
};
//
function isDataLoaded() {
@ -1352,6 +1408,14 @@ onMounted(async () => {
//
window.addEventListener('resize', globalResizeHandler);
window.aiEmotionGlobalResizeHandler = globalResizeHandler;
//
const container = userInputDisplayRef.value;
if (container) {
container.addEventListener('wheel', handleWheel, { passive: true });
container.addEventListener('touchmove', handleTouchMove, { passive: true });
container.addEventListener('scroll', handleUserScroll, { passive: true });
}
//
function debounce(func, wait) {
@ -1424,6 +1488,20 @@ onUnmounted(() => {
window.removeEventListener('resize', window.aiEmotionGlobalResizeHandler);
window.aiEmotionGlobalResizeHandler = null;
}
//
const container = userInputDisplayRef.value;
if (container) {
container.removeEventListener('wheel', handleWheel);
container.removeEventListener('touchmove', handleTouchMove);
container.removeEventListener('scroll', handleUserScroll);
}
//
if (scrollTimeout.value) {
clearTimeout(scrollTimeout.value);
scrollTimeout.value = null;
}
});
//
@ -1453,7 +1531,7 @@ defineExpose({
display: flex;
align-items: center;
justify-content: center;
gap: 25vw;
gap: 25%;
/* flex-direction: column; */
/* gap: 1rem; */
}
@ -1487,6 +1565,7 @@ defineExpose({
background-size: 100% 100%;
/* width: 50%; */
width: 30vw;
max-width: 400px;
min-width: 200px;
min-height: 40px;
text-align: center;
@ -1504,6 +1583,7 @@ defineExpose({
background-size: 100% 100%;
/* width: 35%; */
width: 30vw;
max-width: 400px;
min-width: 200px;
min-height: 40px;
text-align: center;
@ -1914,7 +1994,7 @@ defineExpose({
/* 确保不超出父容器 */
height: auto;
/* 高度根据内容动态变化 */
min-height: 90rem;
/* min-height: 90rem; */
/* 设置最小高度,确保图片显示 */
margin: 0 auto;
box-sizing: border-box;
@ -1922,7 +2002,6 @@ defineExpose({
transition: all 0.3s ease;
/* 添加平滑过渡效果 */
}
.class04 {
background-image: url('@/assets/img/AiEmotion/bk00000.png');
/* 使用导入的背景图片 */
@ -2010,6 +2089,7 @@ defineExpose({
.span02 {
font-size: 1.5rem;
font-weight: bold;
color: white;
float: right;
margin-top: -2%;
@ -2173,10 +2253,6 @@ defineExpose({
min-height: 60rem;
}
.class05 {
min-height: 75rem;
}
.class06 {
min-height: 58rem;
}
@ -2206,11 +2282,6 @@ defineExpose({
min-height: 55rem;
}
.class05 {
min-height: 65rem;
}
.class06 {
min-height: 50rem;
}
@ -2361,6 +2432,7 @@ defineExpose({
.class04 {
width: 100%;
height: auto;
margin: 0 auto;
/* min-height: 38rem; */
/* min-height: 51rem; */
/* margin-left: -39px; */
@ -2376,10 +2448,6 @@ defineExpose({
min-height: 45rem;
}
.class05 {
min-height: 48rem;
}
.class06 {
min-height: 35rem;
}
@ -2610,7 +2678,7 @@ defineExpose({
background-repeat: no-repeat;
width: 100%;
height: auto;
min-height: 48rem;
/* min-height: 48rem; */
}
.class06 {
@ -2720,11 +2788,11 @@ defineExpose({
align-items: center;
}
.class003{
.class003 {
padding-top: 14%;
gap: 30px;
}
.class003 .div01,
.class003 .div02 {
/* width: 90%; */
@ -2735,7 +2803,7 @@ defineExpose({
}
.span01 {
width: 70%;
width: 50%;
font-size: 1rem;
padding: 6px;
}
@ -2757,11 +2825,6 @@ defineExpose({
min-height: 35rem;
}
.class05 {
min-height: 35rem;
}
.class06 {
min-height: 25rem;
}
@ -2781,8 +2844,8 @@ defineExpose({
display: flex;
justify-content: center;
align-items: center;
min-height: 60vh;
padding: 40px 20px;
min-height: 20vh;
padding: 20px 10px;
}
.loading-content {

4
src/views/components/emotionDecod.vue

@ -451,6 +451,7 @@ onBeforeUnmount(() => {
.qxjmqbox {
height: auto;
width: 100%;
margin:0 auto;
}
#qxjmqEcharts {
@ -473,8 +474,7 @@ onBeforeUnmount(() => {
.qxjmqbox {
height: auto;
width: 100%;
margin: 0;
width: 90%;
}
}

7
src/views/components/emotionalBottomRadar.vue

@ -461,7 +461,7 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
start: 0,
end: 100,
show: true,
bottom: 10,
bottom: window.innerWidth > 768 ? 80 : 50,
height: 20,
borderColor: '#CFD6E3',
fillerColor: 'rgba(135, 175, 274, 0.2)',
@ -701,16 +701,15 @@ onBeforeUnmount(() => {
height: 1040px;
box-sizing: border-box;
overflow: hidden;
margin: 0;
margin: 0px auto !important;
padding: 0;
}
/* 手机端适配样式 */
@media only screen and (max-width: 768px) {
#bottomRadarChart {
width: 100%;
width: 90% !important;
height: 560px;
margin: 0;
padding: 0;
}
}
Loading…
Cancel
Save