Browse Source

Merge branch 'ds' into ds_hxl

ds_hxl
no99 1 week ago
parent
commit
da5b6d00f0
  1. 4
      .env.production
  2. 11
      src/api/AIxiaocaishen.js
  3. 55
      src/store/audio.js
  4. 5
      src/store/chat.js
  5. 75
      src/views/AIchat.vue
  6. 130
      src/views/AiEmotion.vue
  7. 20
      src/views/Selectmodel.vue
  8. 43
      src/views/components/emoEnergyConverter.vue
  9. 78
      src/views/components/emotionalBottomRadar.vue
  10. 1
      src/views/components/marketTemperature.vue
  11. 96
      src/views/homePage.vue

4
.env.production

@ -9,8 +9,8 @@ VITE_PUBLIC_PATH = /aixiaocaishen
VITE_USE_MOCK = true 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" VITE_APP_IMG_API_BASE_URL = "https://api.homilychart.com/hljw/api/aws/upload"
#MJ API #MJ API

11
src/api/AIxiaocaishen.js

@ -99,12 +99,13 @@ export const getAnnouncementAPI = function () {
// 获取用户次数接口 // 获取用户次数接口
export const getUserCountAPI = function (params) { export const getUserCountAPI = function (params) {
return request({ 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", method: "POST",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
data: params,
// headers: {
// "Content-Type": "application/x-www-form-urlencoded",
// },
}); });
}; };
// 推荐问题/每日复盘/小财神简介点击事件接口 // 推荐问题/每日复盘/小财神简介点击事件接口

55
src/store/audio.js

@ -9,7 +9,10 @@ export const useAudioStore = defineStore('audio', {
lastVoiceState: null, lastVoiceState: null,
ttsUrl:'', ttsUrl:'',
isNewInstance: false, // 新增是否是新实例的标志 isNewInstance: false, // 新增是否是新实例的标志
nowSound:''
nowSound:'',
currentAudioUrl: '', // 当前音频URL
isPaused: false, // 是否处于暂停状态
duration: 0 // 音频总时长
}), }),
actions: { actions: {
// 设置音频实例 // 设置音频实例
@ -19,19 +22,67 @@ export const useAudioStore = defineStore('audio', {
// 播放控制 // 播放控制
play() { play() {
if (this.soundInstance) { if (this.soundInstance) {
if (this.isPaused && this.playbackPosition > 0) {
// 从暂停位置继续播放
this.soundInstance.seek(this.playbackPosition)
}
this.soundInstance.play() this.soundInstance.play()
this.isPlaying = true this.isPlaying = true
this.isPaused = false
} }
}, },
// 暂停控制 // 暂停控制
pause() { pause() {
if (this.soundInstance) {
if (this.soundInstance && this.isPlaying) {
// 保存当前播放位置
this.playbackPosition = this.soundInstance.seek() || 0
this.soundInstance.pause() this.soundInstance.pause()
this.isPlaying = false 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() { toggleVoice() {
this.isVoiceEnabled = !this.isVoiceEnabled this.isVoiceEnabled = !this.isVoiceEnabled
if (!this.isVoiceEnabled) {
// 关闭语音时停止当前播放
this.stop()
}
},
// 重置音频状态
resetAudioState() {
this.stop()
this.currentAudioUrl = ''
this.ttsUrl = ''
this.soundInstance = null
this.nowSound = ''
} }
} }
}) })

5
src/store/chat.js

@ -11,9 +11,10 @@ export const useChatStore = defineStore('chat', {
actions: { actions: {
async getUserCount() { async getUserCount() {
const result = await getUserCountAPI({ 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) { setLoading(status) {
this.isLoading = status this.isLoading = status

75
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 chatMsg = computed(() => chatStore.messages);
const props = defineProps({ const props = defineProps({
@ -494,6 +557,18 @@ watch(
const result23 = await dbqbSecondThreeAPI(params2); const result23 = await dbqbSecondThreeAPI(params2);
const result24 = await dbqbSecondFourAPI(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; const katexRegex = /\$\$(.*?)\$\$/g;
// //
chatStore.messages.pop(); chatStore.messages.pop();

130
src/views/AiEmotion.vue

@ -183,11 +183,43 @@ import blueBorderImg from '@/assets/img/AiEmotion/blueBorder.png' //导入蓝色
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { useEmotionStore } from '@/store/emotion'; // Pinia store import { useEmotionStore } from '@/store/emotion'; // Pinia store
import { useAudioStore } from '@/store/audio.js'; // store import { useAudioStore } from '@/store/audio.js'; // store
import { useChatStore } from '@/store/chat.js'; // store
import { Howl, Howler } from 'howler'; // import { Howl, Howler } from 'howler'; //
import { reactive } from 'vue'; import { reactive } from 'vue';
import { marked } from 'marked'; // marked
// 使Pinia store // 使Pinia store
const emotionStore = useEmotionStore(); const emotionStore = useEmotionStore();
const audioStore = useAudioStore(); const audioStore = useAudioStore();
const chatStore = useChatStore();
// refuse
function processRefuseMessage(refuseData) {
if (!refuseData) return '未知错误';
// refuseMarkdown
try {
// marked
marked.setOptions({
breaks: true, // <br>
gfm: true, // GitHub Flavored Markdown
sanitize: false, // HTML
smartLists: true, //
smartypants: true, //
xhtml: false, // 使 XHTML
});
// MarkdownHTML
const htmlContent = marked(refuseData);
// HTMLElMessage
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); // const marketTemperatureRef = ref(null); //
@ -357,7 +389,7 @@ watch(currentStock, (newStock) => {
nextTick(() => { nextTick(() => {
renderCharts(newStock.apiData); renderCharts(newStock.apiData);
console.log('0000000000000000000000000',newStock.apiData)
console.log('0000000000000000000000000', newStock.apiData)
// //
setTimeout(() => { setTimeout(() => {
if (scenarioApplicationRef.value && parsedConclusion.value) { if (scenarioApplicationRef.value && parsedConclusion.value) {
@ -663,8 +695,11 @@ function playAudio(url) {
console.log('开始创建音频实例...'); console.log('开始创建音频实例...');
try { try {
// URL
audioStore.setCurrentAudioUrl(url);
// //
if (audioStore.nowSound) {
if (audioStore.nowSound && audioStore.nowSound.playing()) {
audioStore.nowSound.stop(); audioStore.nowSound.stop();
} }
@ -675,19 +710,35 @@ function playAudio(url) {
format: ['mp3', 'wav'], format: ['mp3', 'wav'],
onplay: () => { onplay: () => {
isAudioPlaying.value = true; isAudioPlaying.value = true;
audioStore.isPlaying = true;
console.log('开始播放场景应用语音'); console.log('开始播放场景应用语音');
}, },
onend: () => { onend: () => {
isAudioPlaying.value = false; isAudioPlaying.value = false;
audioStore.isPlaying = false;
audioStore.isPaused = false;
audioStore.playbackPosition = 0;
console.log('场景应用语音播放结束'); console.log('场景应用语音播放结束');
}, },
onstop: () => { onstop: () => {
isAudioPlaying.value = false; isAudioPlaying.value = false;
audioStore.isPlaying = false;
console.log('场景应用语音播放停止'); console.log('场景应用语音播放停止');
}, },
onpause: () => {
isAudioPlaying.value = false;
audioStore.isPlaying = false;
console.log('场景应用语音播放暂停');
},
onerror: (error) => { onerror: (error) => {
isAudioPlaying.value = false; isAudioPlaying.value = false;
audioStore.isPlaying = false;
console.error('音频播放错误:', error); console.error('音频播放错误:', error);
},
onload: () => {
//
audioStore.duration = newSound.duration();
console.log('音频加载完成,时长:', audioStore.duration);
} }
}); });
@ -726,14 +777,18 @@ async function handleSendMessage(input) {
console.log("发送内容:", input); console.log("发送内容:", input);
// //
if (!input || !input.trim()) {
ElMessage.warning("输入内容不能为空");
return;
}
//
isRotating.value = true;
//
isLoading.value = true;
if (input.trim()) { if (input.trim()) {
const userMessage = reactive({ sender: 'user', text: input }); const userMessage = reactive({ sender: 'user', text: input });
messages.value.push(userMessage); messages.value.push(userMessage);
//
isLoading.value = true;
isPageLoaded.value = false;
//
isRotating.value = true;
try { try {
// //
@ -750,20 +805,21 @@ async function handleSendMessage(input) {
aibullPrivilegeState: "1", aibullPrivilegeState: "1",
aigoldBullPrivilegeS: "1", aigoldBullPrivilegeS: "1",
airadarPrivilegeStat: "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 result = await getReplyAPI(params);
const response = await result.json(); // JSON const response = await result.json(); // JSON
console.log("工作流接口返回数据:", response);
// data // data
const parsedData = JSON.parse(response.data); // JSON const parsedData = JSON.parse(response.data); // JSON
console.log("解析后的数据:", parsedData); console.log("解析后的数据:", parsedData);
if (parsedData && parsedData.market && parsedData.code) { if (parsedData && parsedData.market && parsedData.code) {
console.log("工作流接口返回股票信息:", parsedData); console.log("工作流接口返回股票信息:", parsedData);
isPageLoaded.value = false;
// //
const conclusionParams = { const conclusionParams = {
content: input.trim(), content: input.trim(),
@ -776,12 +832,6 @@ async function handleSendMessage(input) {
code: parsedData.code, code: parsedData.code,
market: parsedData.market, market: parsedData.market,
}; };
console.log('======================================')
//
// console.log('');
// startAutoScroll();
// fetchData // fetchData
const [conclusionResult, fetchDataResult] = await Promise.all([ const [conclusionResult, fetchDataResult] = await Promise.all([
getConclusionAPI(conclusionParams), getConclusionAPI(conclusionParams),
@ -797,22 +847,21 @@ async function handleSendMessage(input) {
conclusionData.value = conclusionResponse.data; conclusionData.value = conclusionResponse.data;
// store // store
emotionStore.updateActiveStockConclusion(conclusionResponse.data); emotionStore.updateActiveStockConclusion(conclusionResponse.data);
console.log("结论数据已存储到响应式变量和store中:", conclusionData.value);
} }
console.log('------------------------------------')
} else { } else {
ElMessage.error('工作流接口未返回非股票信息');
// refuse
ElMessage.error(processRefuseMessage(parsedData.refuse));
return; //
} }
} catch (error) { } catch (error) {
ElMessage.error('请求工作流接口失败,请检查网络连接'); ElMessage.error('请求工作流接口失败,请检查网络连接');
return; //
} finally { } 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, // conclusionData: conclusionData.value, //
timestamp: new Date().toISOString() timestamp: new Date().toISOString()
}; };
// store // store
emotionStore.addStock(stockData); emotionStore.addStock(stockData);
console.log('股票数据已添加到store');
} else { } else {
ElMessage.error('获取接口数据失败');
ElMessage.error('请求失败,请检查网络连接');
} }
} catch (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(); startImageRotation();
// DOM // DOM
@ -1141,6 +1194,9 @@ onUnmounted(() => {
} }
}); });
//
const emit = defineEmits(['updateMessage', 'sendMessage', 'ensureAIchat']);
// 使 // 使
defineExpose({ defineExpose({
handleSendMessage, handleSendMessage,
@ -1517,21 +1573,21 @@ defineExpose({
color: white; color: white;
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;
margin-left: 44%;
margin-left: 45%;
} }
.title3 { .title3 {
color: white; color: white;
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;
margin-left: 43%;
margin-left: 44.6%;
} }
.title4 { .title4 {
color: white; color: white;
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;
margin-left: 41.5%;
margin-left: 44%;
} }
.class09 { .class09 {
@ -1580,7 +1636,7 @@ defineExpose({
/* 设置容器宽度 */ /* 设置容器宽度 */
height: auto; height: auto;
/* 高度根据内容动态变化 */ /* 高度根据内容动态变化 */
min-height: 66rem;
min-height: 69rem;
/* 设置最小高度,确保图片显示 */ /* 设置最小高度,确保图片显示 */
margin: 0 auto; margin: 0 auto;
} }
@ -1596,7 +1652,7 @@ defineExpose({
/* 设置容器宽度 */ /* 设置容器宽度 */
height: auto; height: auto;
/* 高度根据内容动态变化 */ /* 高度根据内容动态变化 */
min-height: 86rem;
min-height: 90rem;
/* 设置最小高度,确保图片显示 */ /* 设置最小高度,确保图片显示 */
margin: 0 auto; margin: 0 auto;
} }

20
src/views/Selectmodel.vue

@ -32,21 +32,31 @@
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { setHeight } from '@/utils/setHeight' import { setHeight } from '@/utils/setHeight'
import { useDataStore } from "@/store/dataList.js";
const { getQueryVariable, setActiveTabIndex } = useDataStore();
const router = useRouter() const router = useRouter()
const pageRef = ref(null) 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 = () => { const goToDBQBmodel = () => {
router.push('/DBQBmodel') router.push('/DBQBmodel')
window.location.href = '/DBQBmodel'
} }
const goToEmotionsmodel = () => { const goToEmotionsmodel = () => {
router.push('/Emotionsmodel') router.push('/Emotionsmodel')
window.location.href = '/Emotionsmodel'
} }
</script> </script>

43
src/views/components/emoEnergyConverter.vue

@ -244,12 +244,7 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
show: true, show: true,
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: {
type: 'cross',
crossStyle: {
color: '#fff',
width: 1,
type: 'solid'
},
type: 'line',
lineStyle: { lineStyle: {
color: '#fff', color: '#fff',
width: 1, width: 1,
@ -280,10 +275,10 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
let color = param.color let color = param.color
if (param.seriesType === 'candlestick') { 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' || if (typeof openPrice !== 'number' || typeof closePrice !== 'number' ||
@ -293,10 +288,10 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
let priceChange = closePrice - openPrice let priceChange = closePrice - openPrice
let changePercent = ((priceChange / openPrice) * 100).toFixed(2) let changePercent = ((priceChange / openPrice) * 100).toFixed(2)
let changeColor = priceChange >= 0 ? '#ef232a' : '#14b143'
let changeColor = priceChange >= 0 ? '#14b143' : '#ef232a'
result += `<div style="margin-bottom: 6px;">` result += `<div style="margin-bottom: 6px;">`
result += `<div style="color: #fff; font-weight: bold;">${param.seriesName}</div>`
// result += `<div style="color: #fff; font-weight: bold;">${param.seriesName}</div>`
result += `<div style="color: #fff;">开盘: ${openPrice.toFixed(2)}</div>` result += `<div style="color: #fff;">开盘: ${openPrice.toFixed(2)}</div>`
result += `<div style="color: #fff;">收盘: ${closePrice.toFixed(2)}</div>` result += `<div style="color: #fff;">收盘: ${closePrice.toFixed(2)}</div>`
result += `<div style="color: #fff;">最低: ${lowPrice.toFixed(2)}</div>` result += `<div style="color: #fff;">最低: ${lowPrice.toFixed(2)}</div>`
@ -317,7 +312,7 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
{ {
type: 'slider', type: 'slider',
xAxisIndex: 0, xAxisIndex: 0,
start: 40,
start: 0,
end: 100, end: 100,
show: true, show: true,
bottom: 10, bottom: 10,
@ -335,7 +330,7 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
{ {
type: 'inside', type: 'inside',
xAxisIndex: 0, xAxisIndex: 0,
start: 70,
start: 0,
end: 100, end: 100,
zoomOnMouseWheel: true, zoomOnMouseWheel: true,
moveOnMouseMove: true, moveOnMouseMove: true,
@ -349,9 +344,21 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
rotate: 45, // 45 rotate: 45, // 45
color: "white" color: "white"
}, },
axisLine: {
// show: false,
lineStyle: {
color: 'white', // x线
}
},
}, },
yAxis: { yAxis: {
scale: true, scale: true,
axisLine: {
// show: false,
lineStyle: {
color: 'white', // x线
}
},
splitLine: { splitLine: {
show: false, show: false,
}, },
@ -391,10 +398,10 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
itemStyle: { itemStyle: {
normal: { normal: {
// 线 > // 线 >
color: 'transparent', // 线
color0: '#008080', // 线
borderColor: '#ff0783', // 线
borderColor0: '#008080', // 线绿
color: '#14b143', // < 绿
color0: '#ef232a', // >
borderColor: '#14b143', // 线绿
borderColor0: '#ef232a', // 线
} }
}, },
// //

78
src/views/components/emotionalBottomRadar.vue

@ -19,8 +19,28 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
// -x // -x
let dateArray = barAndLineData.map(subArray => subArray[0]) 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]) let redLineDataArray = barAndLineData.map(subArray => subArray[1])
// //
@ -157,24 +177,34 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
if (param.seriesType === 'candlestick') { if (param.seriesType === 'candlestick') {
// ECharts candlestickvalue[, , , ] // ECharts candlestickvalue[, , , ]
// 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 priceChange = closePrice - openPrice
let changePercent = ((priceChange / openPrice) * 100).toFixed(2) let changePercent = ((priceChange / openPrice) * 100).toFixed(2)
let changeColor = priceChange >= 0 ? '#14b143' : '#ef232a' // 绿
let changeColor = priceChange >= 0 ? '#14b143' : '#ef232a' // 绿
result += `<div style="margin-bottom: 6px;">` result += `<div style="margin-bottom: 6px;">`
result += `<div style="color: #fff; font-weight: bold;">${param.seriesName}</div>` result += `<div style="color: #fff; font-weight: bold;">${param.seriesName}</div>`
result += `<div style="color: #fff;">开盘: ${openPrice.toFixed(2)}</div>`
result += `<div style="color: #fff;">收盘: ${closePrice.toFixed(2)}</div>`
result += `<div style="color: #fff;">最低: ${lowPrice.toFixed(2)}</div>`
result += `<div style="color: #fff;">最高: ${highPrice.toFixed(2)}</div>`
result += `<div style="color: #fff;">开盘: ${openPrice.toFixed(1)}</div>`
result += `<div style="color: #fff;">收盘: ${closePrice.toFixed(1)}</div>`
result += `<div style="color: #fff;">最低: ${lowPrice.toFixed(1)}</div>`
result += `<div style="color: #fff;">最高: ${highPrice.toFixed(1)}</div>`
result += `<div style="color: ${changeColor};">涨跌: ${priceChange >= 0 ? '+' : ''}${priceChange.toFixed(2)} (${changePercent}%)</div>` result += `<div style="color: ${changeColor};">涨跌: ${priceChange >= 0 ? '+' : ''}${priceChange.toFixed(2)} (${changePercent}%)</div>`
result += `</div>` result += `</div>`
} else if (param.seriesName === '红线') { } else if (param.seriesName === '红线') {
@ -183,7 +213,6 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
result += `<div style="color: ${color}; margin-bottom: 4px;">${param.seriesName}: ${value}</div>` result += `<div style="color: ${color}; margin-bottom: 4px;">${param.seriesName}: ${value}</div>`
} }
}) })
return result return result
} }
}, },
@ -251,7 +280,7 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
axisPointer: { axisPointer: {
link: { link: {
xAxisIndex: 'all' xAxisIndex: 'all'
}
},
} }
}, },
{ {
@ -319,6 +348,7 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
type: 'value', type: 'value',
gridIndex: 0, gridIndex: 0,
splitNumber: 4, splitNumber: 4,
min: yAxisMin, // y10
axisLine: { axisLine: {
lineStyle: { lineStyle: {
color: 'white' // y color: 'white' // y
@ -331,9 +361,6 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
width: 50, // width: 50, //
color: 'white', color: 'white',
formatter: function (value, index) { formatter: function (value, index) {
if (index === 0) {
return '0'
}
return value.toFixed(2) return value.toFixed(2)
} }
}, },
@ -344,7 +371,6 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
type: 'dotted' // 线 dotted线 solid:线 type: 'dotted' // 线 dotted线 solid:线
} }
}, },
// min: 4,
scale: true, // 0k线 scale: true, // 0k线
}, },
{ {
@ -424,7 +450,7 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
{ {
type: 'slider', type: 'slider',
xAxisIndex: [0, 1, 2], xAxisIndex: [0, 1, 2],
start: 70,
start: 0,
end: 100, end: 100,
show: true, show: true,
bottom: 10, bottom: 10,
@ -449,7 +475,7 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
{ {
type: 'inside', type: 'inside',
xAxisIndex: [0, 1, 2], xAxisIndex: [0, 1, 2],
start: 70,
start: 0,
end: 100, end: 100,
zoomOnMouseWheel: true, zoomOnMouseWheel: true,
moveOnMouseMove: true, moveOnMouseMove: true,
@ -464,13 +490,13 @@ function initEmotionalBottomRadar(KlineData, barAndLineData) {
xAxisIndex: 0, xAxisIndex: 0,
yAxisIndex: 0, yAxisIndex: 0,
itemStyle: { itemStyle: {
color: '#14b143', // (绿)
color0: '#ef232a', // ()
color: '#14b143', // > 绿
color0: '#ef232a', // <
borderColor: '#14b143', borderColor: '#14b143',
borderColor0: '#ef232a', borderColor0: '#ef232a',
normal: { normal: {
color: '#14b143', // (绿)
color0: '#ef232a', // ()
color: '#14b143', // > 绿
color0: '#ef232a', // <
borderColor: '#14b143', borderColor: '#14b143',
borderColor0: '#ef232a', borderColor0: '#ef232a',
opacity: function (params) { opacity: function (params) {

1
src/views/components/marketTemperature.vue

@ -337,6 +337,7 @@ function initChart(raw, klineDataRawValue, WDRLValue) {
data: klineData, data: klineData,
itemStyle: { itemStyle: {
normal: { normal: {
color: '#00FF00', // 线 color: '#00FF00', // 线
color0: '#FF0000', // 线绿 color0: '#FF0000', // 线绿
borderColor: '#00FF00', // 线 borderColor: '#00FF00', // 线

96
src/views/homePage.vue

@ -46,7 +46,19 @@ const chatStore = useChatStore();
const audioStore = useAudioStore(); const audioStore = useAudioStore();
const isVoice = computed(() => audioStore.isVoiceEnabled); const isVoice = computed(() => audioStore.isVoiceEnabled);
const toggleVoice = () => { const toggleVoice = () => {
audioStore.toggleVoice();
if (!audioStore.isVoiceEnabled) {
//
audioStore.toggleVoice();
} else {
// /
if (audioStore.currentAudioUrl || audioStore.ttsUrl) {
// /
audioStore.togglePlayPause();
} else {
//
audioStore.toggleVoice();
}
}
}; };
// sessionStorage 使 'aifindCow'tab // sessionStorage 使 'aifindCow'tab
const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat"); const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat");
@ -143,6 +155,13 @@ const sendMessage = async () => {
ElMessage.error("请先登录"); ElMessage.error("请先登录");
return; return;
} }
//
if (!message.value || !message.value.trim()) {
ElMessage.warning("输入内容不能为空");
return;
}
isScrolling.value = false; isScrolling.value = false;
// AiEmotion // AiEmotion
@ -157,7 +176,6 @@ const sendMessage = async () => {
ensureAIchat(); ensureAIchat();
console.log(chatStore.isLoading, "isLoading.value1111"); console.log(chatStore.isLoading, "isLoading.value1111");
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");
@ -485,15 +503,15 @@ document.addEventListener(
); );
onMounted(async () => { 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")); // setHeight(document.getElementById("testId")); //
// //
await chatStore.getUserCount(); await chatStore.getUserCount();
@ -585,43 +603,20 @@ onMounted(async () => {
alt="夺宝奇兵大模型" alt="夺宝奇兵大模型"
/> />
<!-- AI情绪大模型按钮 --> <!-- AI情绪大模型按钮 -->
<img
:src="
activeTab === 'AiEmotion' ? emotionButton01 : emotionButton02
"
@click="setActiveTab('AiEmotion', 1)"
class="action-btn model-btn"
alt="AI情绪大模型"
/>
<img
v-if="isVoice"
:src="voice"
@click="toggleVoice"
class="action-btn"
/>
<img
v-else
:src="voiceNoActive"
@click="toggleVoice"
class="action-btn"
/>
<img :src="activeTab === 'AiEmotion' ? emotionButton01 : emotionButton02
" @click="setActiveTab('AiEmotion', 1)" class="action-btn model-btn" alt="AI情绪大模型" />
<img v-if="audioStore.isVoiceEnabled && !audioStore.isPlaying" :src="voice" @click="toggleVoice" class="action-btn" />
<img v-else-if="audioStore.isVoiceEnabled && audioStore.isPlaying" :src="voice" @click="toggleVoice" class="action-btn" style="opacity: 0.7; animation: pulse 1.5s infinite;" />
<img v-else :src="voiceNoActive" @click="toggleVoice" class="action-btn" />
</div> </div>
</div> </div>
<!-- 第二行输入框 --> <!-- 第二行输入框 -->
<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="请输入股票名称或股票代码..." class="msg-input"
@keydown.enter.exact.prevent="isLoading ? null : sendMessage()" resize="none">
</el-input> </el-input>
<img <img
v-if="!chatStore.isLoading" v-if="!chatStore.isLoading"
@ -681,8 +676,8 @@ onMounted(async () => {
<!-- 中间内容部分 --> <!-- 中间内容部分 -->
<div class="ruleContent"> <div class="ruleContent">
<p>试运行期间AI小财神可以检索全市场数据</p> <p>试运行期间AI小财神可以检索全市场数据</p>
<p>每个市场20支股票股票详情参见公告页面</p>
<p>弘历会员每人每日拥有10次检索机会</p>
<p>每个市场20支股票股票详情参见公告页面</p>
<!-- <p>弘历会员每人每日拥有10次检索机会</p> -->
</div> </div>
<!-- <template #footer> --> <!-- <template #footer> -->
<!-- 添加一个div来包裹按钮并设置样式使其居中 --> <!-- 添加一个div来包裹按钮并设置样式使其居中 -->
@ -1006,6 +1001,19 @@ body {
/* margin-right: 5px; */ /* margin-right: 5px; */
} }
/* 音频播放动画 */
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
.footer-second-line { .footer-second-line {
position: relative; position: relative;
display: flex; display: flex;

Loading…
Cancel
Save