diff --git a/.env.production b/.env.production index c2f9efd..6d79b3c 100644 --- a/.env.production +++ b/.env.production @@ -9,8 +9,8 @@ VITE_PUBLIC_PATH = /aixiaocaishen VITE_USE_MOCK = true #新数据接口 -VITE_APP_API_BASE_URL = https://api.homilychart.com/link -# VITE_APP_API_BASE_URL = "http://39.101.133.168:8828/link" +# VITE_APP_API_BASE_URL = https://api.homilychart.com/link +VITE_APP_API_BASE_URL = "http://39.101.133.168:8828/link" VITE_APP_IMG_API_BASE_URL = "https://api.homilychart.com/hljw/api/aws/upload" #MJ API diff --git a/src/api/AIxiaocaishen.js b/src/api/AIxiaocaishen.js index 0cbce31..2b6ee70 100644 --- a/src/api/AIxiaocaishen.js +++ b/src/api/AIxiaocaishen.js @@ -99,12 +99,13 @@ export const getAnnouncementAPI = function () { // 获取用户次数接口 export const getUserCountAPI = function (params) { return request({ - url: `${APIurl}/api/ai_god/userUsageInfo`, + // 'http://39.101.133.168:8828/link/api/aiEmotion/client/getRemainNum', + url: `${APIurl}/api/aiEmotion/client/getRemainNum`, method: "POST", - data: new URLSearchParams(params), - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, + data: params, + // headers: { + // "Content-Type": "application/x-www-form-urlencoded", + // }, }); }; // 推荐问题/每日复盘/小财神简介点击事件接口 diff --git a/src/store/audio.js b/src/store/audio.js index a33154c..7f5d82a 100644 --- a/src/store/audio.js +++ b/src/store/audio.js @@ -9,7 +9,10 @@ export const useAudioStore = defineStore('audio', { lastVoiceState: null, ttsUrl:'', isNewInstance: false, // 新增是否是新实例的标志 - nowSound:'' + nowSound:'', + currentAudioUrl: '', // 当前音频URL + isPaused: false, // 是否处于暂停状态 + duration: 0 // 音频总时长 }), actions: { // 设置音频实例 @@ -19,19 +22,67 @@ export const useAudioStore = defineStore('audio', { // 播放控制 play() { if (this.soundInstance) { + if (this.isPaused && this.playbackPosition > 0) { + // 从暂停位置继续播放 + this.soundInstance.seek(this.playbackPosition) + } this.soundInstance.play() this.isPlaying = true + this.isPaused = false } }, // 暂停控制 pause() { - if (this.soundInstance) { + if (this.soundInstance && this.isPlaying) { + // 保存当前播放位置 + this.playbackPosition = this.soundInstance.seek() || 0 this.soundInstance.pause() this.isPlaying = false + this.isPaused = true + } + }, + // 停止播放 + stop() { + if (this.soundInstance) { + this.soundInstance.stop() + this.isPlaying = false + this.isPaused = false + this.playbackPosition = 0 } }, + // 切换播放/暂停 + togglePlayPause() { + if (this.isPlaying) { + this.pause() + } else { + this.play() + } + }, + // 设置当前音频URL + setCurrentAudioUrl(url) { + if (this.currentAudioUrl !== url) { + // 如果是新的音频,重置播放状态 + this.stop() + this.currentAudioUrl = url + this.playbackPosition = 0 + this.isPaused = false + } + }, + // 语音开关控制 toggleVoice() { this.isVoiceEnabled = !this.isVoiceEnabled + if (!this.isVoiceEnabled) { + // 关闭语音时停止当前播放 + this.stop() + } + }, + // 重置音频状态 + resetAudioState() { + this.stop() + this.currentAudioUrl = '' + this.ttsUrl = '' + this.soundInstance = null + this.nowSound = '' } } }) diff --git a/src/store/chat.js b/src/store/chat.js index 6da35cb..dbf5685 100644 --- a/src/store/chat.js +++ b/src/store/chat.js @@ -11,9 +11,10 @@ export const useChatStore = defineStore('chat', { actions: { async getUserCount() { const result = await getUserCountAPI({ - token: localStorage.getItem('localToken') + token: localStorage.getItem('localToken'), + source: '1' }) - this.UserCount = result.data.hasCount + this.UserCount = result.data }, setLoading(status) { this.isLoading = status diff --git a/src/views/AIchat.vue b/src/views/AIchat.vue index bdbdcdb..8085cf8 100644 --- a/src/views/AIchat.vue +++ b/src/views/AIchat.vue @@ -146,6 +146,69 @@ const pauseAudio = () => { } }; +// 音频轮流播放方法 +const playAudioSequence = (audioUrls) => { + if (!audioUrls || audioUrls.length === 0) { + console.warn("音频URL列表为空,跳过播放"); + return; + } + + let currentIndex = 0; + + const playNext = () => { + if (currentIndex >= audioUrls.length) { + console.log("所有音频播放完成"); + return; + } + + const currentUrl = audioUrls[currentIndex]; + console.log(`正在播放第${currentIndex + 1}个音频:`, currentUrl); + + // 停止当前播放的音频 + if (audioStore.nowSound) { + audioStore.nowSound.stop(); + } + + const sound = new Howl({ + src: [currentUrl], + html5: true, + format: ["mp3", "acc"], + rate: 1.2, + onplay: () => { + audioStore.isPlaying = true; + console.log(`开始播放音频 ${currentIndex + 1}`); + }, + onend: () => { + audioStore.isPlaying = false; + console.log(`音频 ${currentIndex + 1} 播放完成`); + currentIndex++; + // 播放下一个音频 + setTimeout(() => { + playNext(); + }, 500); // 间隔500ms播放下一个 + }, + onstop: () => { + audioStore.isPlaying = false; + }, + onloaderror: (id, err) => { + console.error(`音频 ${currentIndex + 1} 加载失败:`, err); + currentIndex++; + // 跳过失败的音频,播放下一个 + setTimeout(() => { + playNext(); + }, 100); + } + }); + + audioStore.nowSound = sound; + audioStore.setAudioInstance(sound); + sound.play(); + }; + + // 开始播放第一个音频 + playNext(); +}; + // 获取消息 const chatMsg = computed(() => chatStore.messages); const props = defineProps({ @@ -494,6 +557,18 @@ watch( const result23 = await dbqbSecondThreeAPI(params2); const result24 = await dbqbSecondFourAPI(params2); + // 收集所有音频URL + const audioUrls = []; + if (result21.data.url) audioUrls.push(result21.data.url.trim()); + if (result22.data.url) audioUrls.push(result22.data.url.trim()); + if (result23.data.url) audioUrls.push(result23.data.url.trim()); + if (result24.data.url) audioUrls.push(result24.data.url.trim()); + + // 开始轮流播放音频 + if (audioUrls.length > 0 && audioStore.isVoiceEnabled) { + playAudioSequence(audioUrls); + } + const katexRegex = /\$\$(.*?)\$\$/g; // 删除正在为您生成信息 chatStore.messages.pop(); diff --git a/src/views/AiEmotion.vue b/src/views/AiEmotion.vue index 19d40ef..1aff158 100644 --- a/src/views/AiEmotion.vue +++ b/src/views/AiEmotion.vue @@ -183,11 +183,43 @@ import blueBorderImg from '@/assets/img/AiEmotion/blueBorder.png' //导入蓝色 import { ElMessage } from 'element-plus'; import { useEmotionStore } from '@/store/emotion'; // 导入Pinia store import { useAudioStore } from '@/store/audio.js'; // 导入音频store +import { useChatStore } from '@/store/chat.js'; // 导入聊天store import { Howl, Howler } from 'howler'; // 导入音频播放库 import { reactive } from 'vue'; +import { marked } from 'marked'; // 引入marked库 // 使用Pinia store const emotionStore = useEmotionStore(); const audioStore = useAudioStore(); +const chatStore = useChatStore(); + +// 处理refuse数据的函数 +function processRefuseMessage(refuseData) { + if (!refuseData) return '未知错误'; + + // 如果refuse数据包含Markdown格式,进行转换 + try { + // 配置marked选项 + marked.setOptions({ + breaks: true, // 支持换行符转换为
+ gfm: true, // 启用 GitHub Flavored Markdown + sanitize: false, // 不清理 HTML + smartLists: true, // 智能列表 + smartypants: true, // 智能标点符号 + xhtml: false, // 不使用 XHTML 输出 + }); + + // 将Markdown转换为HTML + const htmlContent = marked(refuseData); + + // 移除HTML标签,只保留纯文本用于ElMessage显示 + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = htmlContent; + return tempDiv.textContent || tempDiv.innerText || refuseData; + } catch (error) { + console.error('处理refuse消息时出错:', error); + return refuseData; + } +} // 组件引用 const marketTemperatureRef = ref(null); // 引用市场温度计组件 @@ -357,7 +389,7 @@ watch(currentStock, (newStock) => { nextTick(() => { renderCharts(newStock.apiData); - console.log('0000000000000000000000000',newStock.apiData) + console.log('0000000000000000000000000', newStock.apiData) // 检查场景应用部分是否已经在视口中,如果是则立即触发效果 setTimeout(() => { if (scenarioApplicationRef.value && parsedConclusion.value) { @@ -663,8 +695,11 @@ function playAudio(url) { console.log('开始创建音频实例...'); try { + // 设置当前音频URL + audioStore.setCurrentAudioUrl(url); + // 停止之前的音频 - if (audioStore.nowSound) { + if (audioStore.nowSound && audioStore.nowSound.playing()) { audioStore.nowSound.stop(); } @@ -675,19 +710,35 @@ function playAudio(url) { format: ['mp3', 'wav'], onplay: () => { isAudioPlaying.value = true; + audioStore.isPlaying = true; console.log('开始播放场景应用语音'); }, onend: () => { isAudioPlaying.value = false; + audioStore.isPlaying = false; + audioStore.isPaused = false; + audioStore.playbackPosition = 0; console.log('场景应用语音播放结束'); }, onstop: () => { isAudioPlaying.value = false; + audioStore.isPlaying = false; console.log('场景应用语音播放停止'); }, + onpause: () => { + isAudioPlaying.value = false; + audioStore.isPlaying = false; + console.log('场景应用语音播放暂停'); + }, onerror: (error) => { isAudioPlaying.value = false; + audioStore.isPlaying = false; console.error('音频播放错误:', error); + }, + onload: () => { + // 音频加载完成,获取时长 + audioStore.duration = newSound.duration(); + console.log('音频加载完成,时长:', audioStore.duration); } }); @@ -726,14 +777,18 @@ async function handleSendMessage(input) { console.log("发送内容:", input); // 检查用户输入内容是否为空 + if (!input || !input.trim()) { + ElMessage.warning("输入内容不能为空"); + return; + } + // 触发图片旋转 + isRotating.value = true; + // 设置加载状态,隐藏图表页面 + isLoading.value = true; + if (input.trim()) { const userMessage = reactive({ sender: 'user', text: input }); messages.value.push(userMessage); - // 设置加载状态,隐藏图表页面 - isLoading.value = true; - isPageLoaded.value = false; - // 触发图片旋转 - isRotating.value = true; try { // 用来调用工作流接口的参数 @@ -750,20 +805,21 @@ async function handleSendMessage(input) { aibullPrivilegeState: "1", aigoldBullPrivilegeS: "1", airadarPrivilegeStat: "1", - marketList: "hk,cn,usa,my,sg,vi,in,gb", + marketList: "hk,cn,can,usa,my,sg,vi,in,gb", }, }; const result = await getReplyAPI(params); const response = await result.json(); // 解析返回的 JSON 数据 - console.log("工作流接口返回数据:", response); - // 解析 data 字段 const parsedData = JSON.parse(response.data); // 将字符串形式的 JSON 转换为对象 console.log("解析后的数据:", parsedData); if (parsedData && parsedData.market && parsedData.code) { console.log("工作流接口返回股票信息:", parsedData); + + isPageLoaded.value = false; + // 调用第二个工作流接口 const conclusionParams = { content: input.trim(), @@ -776,12 +832,6 @@ async function handleSendMessage(input) { code: parsedData.code, market: parsedData.market, }; - console.log('======================================') - - // 取消自动滚动效果 - // console.log('第二个工作流接口开始调用,立即开始缓慢滚动'); - // startAutoScroll(); - // 同时调用第二个数据流接口和fetchData方法 const [conclusionResult, fetchDataResult] = await Promise.all([ getConclusionAPI(conclusionParams), @@ -797,22 +847,21 @@ async function handleSendMessage(input) { conclusionData.value = conclusionResponse.data; // 将结论数据存储到store中的当前激活股票 emotionStore.updateActiveStockConclusion(conclusionResponse.data); - console.log("结论数据已存储到响应式变量和store中:", conclusionData.value); } - - console.log('------------------------------------') - } else { - ElMessage.error('工作流接口未返回非股票信息'); + // 不是股票信息,显示refuse信息,但不隐藏页面数据 + ElMessage.error(processRefuseMessage(parsedData.refuse)); + return; // 直接返回,不进行后续处理 } } catch (error) { ElMessage.error('请求工作流接口失败,请检查网络连接'); + return; // 请求失败时直接返回 } finally { - // 停止图片旋转 - isRotating.value = false; + // 停止图片旋转(只有在设置了旋转状态时才需要停止) + if (isRotating.value) { + isRotating.value = false; + } } - } else { - ElMessage.error('消息发送失败,请检查网络连接'); } } @@ -857,17 +906,13 @@ async function fetchData(code, market, stockName, queryText) { conclusionData: conclusionData.value, // 包含结论数据 timestamp: new Date().toISOString() }; - // 将股票数据添加到store中 emotionStore.addStock(stockData); - - console.log('股票数据已添加到store'); - } else { - ElMessage.error('获取接口数据失败'); + ElMessage.error('请求失败,请检查网络连接'); } } catch (error) { - ElMessage.error('获取接口数据失败。。。'); + ElMessage.error('请求失败,请检查网络连接'); } } @@ -1115,7 +1160,15 @@ function triggerAutoScroll() { } // 页面挂载完成后触发图片旋转和设置滚动监听 -onMounted(() => { +onMounted(async () => { + // 确保获取用户次数 + try { + await chatStore.getUserCount(); + console.log('情绪大模型页面:用户次数获取成功'); + } catch (error) { + console.error('情绪大模型页面:获取用户次数失败', error); + } + startImageRotation(); // 等待DOM完全渲染后设置监听器 @@ -1141,6 +1194,9 @@ onUnmounted(() => { } }); +// 声明组件可以触发的事件 +const emit = defineEmits(['updateMessage', 'sendMessage', 'ensureAIchat']); + // 导出方法供外部使用 defineExpose({ handleSendMessage, @@ -1517,21 +1573,21 @@ defineExpose({ color: white; font-size: 20px; font-weight: bold; - margin-left: 44%; + margin-left: 45%; } .title3 { color: white; font-size: 20px; font-weight: bold; - margin-left: 43%; + margin-left: 44.6%; } .title4 { color: white; font-size: 20px; font-weight: bold; - margin-left: 41.5%; + margin-left: 44%; } .class09 { @@ -1580,7 +1636,7 @@ defineExpose({ /* 设置容器宽度 */ height: auto; /* 高度根据内容动态变化 */ - min-height: 66rem; + min-height: 69rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; } @@ -1596,7 +1652,7 @@ defineExpose({ /* 设置容器宽度 */ height: auto; /* 高度根据内容动态变化 */ - min-height: 86rem; + min-height: 90rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; } diff --git a/src/views/Selectmodel.vue b/src/views/Selectmodel.vue index 699361c..ba3c347 100644 --- a/src/views/Selectmodel.vue +++ b/src/views/Selectmodel.vue @@ -32,21 +32,31 @@ import { onMounted, ref } from 'vue' import { useRouter } from 'vue-router' import { setHeight } from '@/utils/setHeight' +import { useDataStore } from "@/store/dataList.js"; +const { getQueryVariable, setActiveTabIndex } = useDataStore(); const router = useRouter() const pageRef = ref(null) -onMounted(() => { - setHeight(pageRef.value) +// onMounted(() => { +// setHeight(pageRef.value) +// }) +onMounted(async () => { + const isPhone = + /phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone/i.test( + navigator.userAgent + ); + !isPhone && + localStorage.setItem( + "localToken", + decodeURIComponent(String(getQueryVariable("token"))) + ); }) - const goToDBQBmodel = () => { router.push('/DBQBmodel') - window.location.href = '/DBQBmodel' } const goToEmotionsmodel = () => { router.push('/Emotionsmodel') - window.location.href = '/Emotionsmodel' } diff --git a/src/views/components/emoEnergyConverter.vue b/src/views/components/emoEnergyConverter.vue index 646c338..e4a8e8c 100644 --- a/src/views/components/emoEnergyConverter.vue +++ b/src/views/components/emoEnergyConverter.vue @@ -244,12 +244,7 @@ function initQXNLZHEcharts(kline, qxnlzhqData) { show: true, trigger: 'axis', axisPointer: { - type: 'cross', - crossStyle: { - color: '#fff', - width: 1, - type: 'solid' - }, + type: 'line', lineStyle: { color: '#fff', width: 1, @@ -280,10 +275,10 @@ function initQXNLZHEcharts(kline, qxnlzhqData) { let color = param.color if (param.seriesType === 'candlestick') { - let openPrice = value[0] // 开盘价 - let closePrice = value[1] // 收盘价 - let lowPrice = value[2] // 最低价 - let highPrice = value[3] // 最高价 + let openPrice = value[1] // 开盘价 + let closePrice = value[2] // 收盘价 + let lowPrice = value[3] // 最低价 + let highPrice = value[4] // 最高价 // 检查数据有效性 if (typeof openPrice !== 'number' || typeof closePrice !== 'number' || @@ -293,10 +288,10 @@ function initQXNLZHEcharts(kline, qxnlzhqData) { let priceChange = closePrice - openPrice let changePercent = ((priceChange / openPrice) * 100).toFixed(2) - let changeColor = priceChange >= 0 ? '#ef232a' : '#14b143' + let changeColor = priceChange >= 0 ? '#14b143' : '#ef232a' result += `
` - result += `
${param.seriesName}
` + // result += `
${param.seriesName}
` result += `
开盘: ${openPrice.toFixed(2)}
` result += `
收盘: ${closePrice.toFixed(2)}
` result += `
最低: ${lowPrice.toFixed(2)}
` @@ -317,7 +312,7 @@ function initQXNLZHEcharts(kline, qxnlzhqData) { { type: 'slider', xAxisIndex: 0, - start: 40, + start: 0, end: 100, show: true, bottom: 10, @@ -335,7 +330,7 @@ function initQXNLZHEcharts(kline, qxnlzhqData) { { type: 'inside', xAxisIndex: 0, - start: 70, + start: 0, end: 100, zoomOnMouseWheel: true, moveOnMouseMove: true, @@ -349,9 +344,21 @@ function initQXNLZHEcharts(kline, qxnlzhqData) { rotate: 45, // 日期旋转45度防止重叠 color: "white" }, + axisLine: { + // show: false, + lineStyle: { + color: 'white', // x轴线颜色 + } + }, }, yAxis: { scale: true, + axisLine: { + // show: false, + lineStyle: { + color: 'white', // x轴线颜色 + } + }, splitLine: { show: false, }, @@ -391,10 +398,10 @@ function initQXNLZHEcharts(kline, qxnlzhqData) { itemStyle: { normal: { // 阳线样式(收盘 > 开盘) - color: 'transparent', // 阳线色 - color0: '#008080', // 阴线色 - borderColor: '#ff0783', // 阳线边框色(红) - borderColor0: '#008080', // 阴线边框色(绿) + color: '#14b143', // 开盘价 < 收盘价时为绿色 + color0: '#ef232a', // 开盘价 > 收盘价时为红色 + borderColor: '#14b143', // 阳线边框色(绿) + borderColor0: '#ef232a', // 阴线边框色(红) } }, // 实现 分区域背景色 diff --git a/src/views/components/emotionalBottomRadar.vue b/src/views/components/emotionalBottomRadar.vue index a056922..14b400b 100644 --- a/src/views/components/emotionalBottomRadar.vue +++ b/src/views/components/emotionalBottomRadar.vue @@ -19,8 +19,28 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { // 日期-作为x轴 let dateArray = barAndLineData.map(subArray => subArray[0]) - // k线,取前四个即可 - let kLineDataArray = KlineData.map(subArray => subArray.slice(1, 5)) + // k线数据格式:['2025/04/24', 250.5, 259.51, 249.2, 259.54, 274.899, 0.685, 258.354] + // 原始数据:索引1=开盘价, 索引2=收盘价, 索引3=最低价, 索引4=最高价 + // ECharts candlestick需要:[开盘, 收盘, 最低, 最高] + let kLineDataArray = KlineData.map(subArray => [ + subArray[1], // 开盘价 + subArray[2], // 收盘价 + subArray[3], // 最低价 + subArray[4] // 最高价 + ]) + + // 计算K线数据的最小值,用于设置y轴起始值 + let allKlineValues = [] + kLineDataArray.forEach(item => { + if (Array.isArray(item) && item.length >= 4) { + // K线数据格式:[开盘价, 收盘价, 最低价, 最高价] + allKlineValues.push(item[0], item[1], item[2], item[3]) + } + }) + + // 找到最小值并向下取整到10的整数倍 + let minValue = Math.min(...allKlineValues.filter(val => typeof val === 'number' && !isNaN(val))) + let yAxisMin = Math.floor(minValue / 10) * 10 // 红线,取第二个值 let redLineDataArray = barAndLineData.map(subArray => subArray[1]) // 色块数据格式化 @@ -157,24 +177,34 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { if (param.seriesType === 'candlestick') { // ECharts candlestick的value格式:[开盘, 收盘, 最低, 最高] - // 但param.value可能包含额外信息,需要从原始数据中获取 - let dataIndex = param.dataIndex - let candlestickData = kLineDataArray[dataIndex] + let candlestickData = param.value + + // 确保数据有效性 + if (!Array.isArray(candlestickData) || candlestickData.length < 4) { + return '' + } + + let openPrice = candlestickData[1] // 开盘价 + let closePrice = candlestickData[2] // 收盘价 + let lowPrice = candlestickData[3] // 最低价 + let highPrice = candlestickData[4] // 最高价 + + // 确保所有价格都是有效数字 + if (typeof openPrice !== 'number' || typeof closePrice !== 'number' || + typeof lowPrice !== 'number' || typeof highPrice !== 'number') { + return '' + } - let openPrice = candlestickData[0] // 开盘价 - let closePrice = candlestickData[1] // 收盘价 - let lowPrice = candlestickData[2] // 最低价 - let highPrice = candlestickData[3] // 最高价 let priceChange = closePrice - openPrice let changePercent = ((priceChange / openPrice) * 100).toFixed(2) - let changeColor = priceChange >= 0 ? '#14b143' : '#ef232a' // 互换颜色:上涨绿色,下跌红色 + let changeColor = priceChange >= 0 ? '#14b143' : '#ef232a' // 互换颜色:上涨红色,下跌绿色 result += `
` result += `
${param.seriesName}
` - result += `
开盘: ${openPrice.toFixed(2)}
` - result += `
收盘: ${closePrice.toFixed(2)}
` - result += `
最低: ${lowPrice.toFixed(2)}
` - result += `
最高: ${highPrice.toFixed(2)}
` + result += `
开盘: ${openPrice.toFixed(1)}
` + result += `
收盘: ${closePrice.toFixed(1)}
` + result += `
最低: ${lowPrice.toFixed(1)}
` + result += `
最高: ${highPrice.toFixed(1)}
` result += `
涨跌: ${priceChange >= 0 ? '+' : ''}${priceChange.toFixed(2)} (${changePercent}%)
` result += `
` } else if (param.seriesName === '红线') { @@ -183,7 +213,6 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { result += `
${param.seriesName}: ${value}
` } }) - return result } }, @@ -251,7 +280,7 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { axisPointer: { link: { xAxisIndex: 'all' - } + }, } }, { @@ -319,6 +348,7 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { type: 'value', gridIndex: 0, splitNumber: 4, + min: yAxisMin, // 设置y轴最小值为数据中最小值的10的整数倍 axisLine: { lineStyle: { color: 'white' // y轴坐标轴颜色 @@ -331,9 +361,6 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { width: 50, // 宽度限制 color: 'white', formatter: function (value, index) { - if (index === 0) { - return '0' - } return value.toFixed(2) } }, @@ -344,7 +371,6 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { type: 'dotted' // 设置网格线类型 dotted:虚线 solid:实线 } }, - // min: 4, scale: true, // 不强制包含0,不然k线图底部空余太多 }, { @@ -424,7 +450,7 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { { type: 'slider', xAxisIndex: [0, 1, 2], - start: 70, + start: 0, end: 100, show: true, bottom: 10, @@ -449,7 +475,7 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { { type: 'inside', xAxisIndex: [0, 1, 2], - start: 70, + start: 0, end: 100, zoomOnMouseWheel: true, moveOnMouseMove: true, @@ -464,13 +490,13 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) { xAxisIndex: 0, yAxisIndex: 0, itemStyle: { - color: '#14b143', // 上涨颜色 (绿) - color0: '#ef232a', // 下跌颜色 (红) + color: '#14b143', // 开盘价 > 收盘价时为绿色 + color0: '#ef232a', // 开盘价 < 收盘价时为红色 borderColor: '#14b143', borderColor0: '#ef232a', normal: { - color: '#14b143', // 上涨颜色 (绿) - color0: '#ef232a', // 下跌颜色 (红) + color: '#14b143', // 开盘价 > 收盘价时为绿色 + color0: '#ef232a', // 开盘价 < 收盘价时为红色 borderColor: '#14b143', borderColor0: '#ef232a', opacity: function (params) { diff --git a/src/views/components/marketTemperature.vue b/src/views/components/marketTemperature.vue index f200ef0..bcb98a9 100644 --- a/src/views/components/marketTemperature.vue +++ b/src/views/components/marketTemperature.vue @@ -337,6 +337,7 @@ function initChart(raw, klineDataRawValue, WDRLValue) { data: klineData, itemStyle: { normal: { + color: '#00FF00', // 阳线红色 color0: '#FF0000', // 阴线绿色 borderColor: '#00FF00', // 阳线边框红色 diff --git a/src/views/homePage.vue b/src/views/homePage.vue index 7a2adf4..6a61aca 100644 --- a/src/views/homePage.vue +++ b/src/views/homePage.vue @@ -46,7 +46,19 @@ const chatStore = useChatStore(); const audioStore = useAudioStore(); const isVoice = computed(() => audioStore.isVoiceEnabled); const toggleVoice = () => { - audioStore.toggleVoice(); + if (!audioStore.isVoiceEnabled) { + // 如果语音功能关闭,先开启语音功能 + audioStore.toggleVoice(); + } else { + // 如果语音功能开启,则切换播放/暂停状态 + if (audioStore.currentAudioUrl || audioStore.ttsUrl) { + // 有音频时切换播放/暂停 + audioStore.togglePlayPause(); + } else { + // 没有音频时关闭语音功能 + audioStore.toggleVoice(); + } + } }; // 将默认值改为从 sessionStorage 中获取,如果没有则使用默认值 'aifindCow'为第一个默认tab const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat"); @@ -143,6 +155,13 @@ const sendMessage = async () => { ElMessage.error("请先登录"); return; } + + // 检查输入内容是否为空 + if (!message.value || !message.value.trim()) { + ElMessage.warning("输入内容不能为空"); + return; + } + isScrolling.value = false; // 判断当前是否为 AiEmotion 组件 @@ -157,7 +176,6 @@ const sendMessage = async () => { ensureAIchat(); console.log(chatStore.isLoading, "isLoading.value1111"); - if (!message.value) return; if (chatStore.isLoading) return; chatStore.setLoading(true); console.log(chatStore.isLoading, "isLoading.value2222"); @@ -485,15 +503,15 @@ document.addEventListener( ); onMounted(async () => { - const isPhone = - /phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone/i.test( - navigator.userAgent - ); - !isPhone && - localStorage.setItem( - "localToken", - decodeURIComponent(String(getQueryVariable("token"))) - ); + // const isPhone = + // /phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone/i.test( + // navigator.userAgent + // ); + // !isPhone && + // localStorage.setItem( + // "localToken", + // decodeURIComponent(String(getQueryVariable("token"))) + // ); setHeight(document.getElementById("testId")); // 给父组件发送窗口高度 // 获取次数 await chatStore.getUserCount(); @@ -585,43 +603,20 @@ onMounted(async () => { alt="夺宝奇兵大模型" /> - AI情绪大模型 - - + AI情绪大模型 + + +