Compare commits

...

51 Commits
master ... dev

Author SHA1 Message Date
宋杰 1b2dcc1cfe 解决小屏的情绪解码器有两个dataZoom的问题。 23 hours ago
宋杰 0055c8c9a0 Merge branch 'songjie/feature-20250628160649-上线前优化' into milestone-20250710-上线前优化 23 hours ago
宋杰 492e7b5e32 解决从首页直接到情绪大模型没有横线标识的问题; 23 hours ago
no99 80131f76ef Merge branch 'hongxilin/feature-20250628153758-财神优化:字正确性,一致性等' into milestone-20250710-上线前优化 1 day ago
no99 4fd87b97ff 打开手机控制台 1 day ago
no99 7905582284 Merge branch 'hongxilin/feature-20250628153758-财神优化:字正确性,一致性等' into milestone-20250710-上线前优化 1 day ago
no99 5e0157b162 1.历史记录的消息改为keyword。 1 day ago
宋杰 2e83f2cf7b 情绪大模型历史记录展示对话时间和接口统一。 1 day ago
宋杰 4f0f33d196 解决情绪大模型遮挡金轮的问题。 1 day ago
宋杰 ca6f8b590a 夺宝奇兵大模型思考过程后不再出现“......” 1 day ago
宋杰 c14a59fb29 修改选择模型页面样式问题。 1 day ago
no99 b187f613bf Merge branch 'hongxilin/feature-20250628153758-财神优化:字正确性,一致性等' into milestone-20250710-上线前优化 1 day ago
no99 e185c4679c 1.app手机返回消息异常; 1 day ago
宋杰 9ad6acd078 Merge branch 'milestone-20250710-上线前优化' of http://39.101.133.168:8807/hongxilin/AIxiaocaishen into milestone-20250710-上线前优化 1 day ago
宋杰 e003a93b76 解决情绪大模型搜索股票后再查看历史记录输入框一直禁用的问题。 1 day ago
no99 d5d8b95cc4 Merge branch 'hongxilin/feature-20250628153758-财神优化:字正确性,一致性等' into milestone-20250710-上线前优化 1 day ago
no99 4b7b2b0258 情绪大模型和夺宝奇兵大模型历史记录开关分开控制 1 day ago
宋杰 a85ade2bb2 解决情绪大模型音频喇叭状态的问题; 1 day ago
宋杰 e6be67c018 解决新股票结论覆盖旧股票结论的问题; 1 day ago
no99 cc952e0121 正在播放其他音频的过程中,发送消息后播放新音频时,旧音频按钮状态未改变的问题 1 day ago
no99 e0beca81d2 手机版回绝文案溢出问题 1 day ago
宋杰 4c65491889 新增在情绪解码器热力矩阵区域也能缩放; 1 day ago
宋杰 d398e6ac10 Merge branch 'songjie/feature-20250628160649-上线前优化' into milestone-20250710-上线前优化 2 days ago
宋杰 5cb72d6775 情绪大模型喇叭颜色校正; 2 days ago
no99 98c4d841f2 音频问题1 2 days ago
宋杰 6e85ce2338 修改手机端样式; 2 days ago
宋杰 df0f904764 情绪能量转化器中情绪临界区字体颜色修改。 2 days ago
宋杰 b4474927b1 解决第一个接口失败的提示语宽度超出的问题; 2 days ago
宋杰 0ac0744283 第一个工作流请求失败使用接口返回发msg。 2 days ago
宋杰 f3f3896248 Merge branch 'milestone-20250710-上线前优化' of http://39.101.133.168:8807/hongxilin/AIxiaocaishen into milestone-20250710-上线前优化 2 days ago
宋杰 4cab11d3e2 Merge branch 'songjie/feature-20250628160649-上线前优化' into milestone-20250710-上线前优化 2 days ago
宋杰 eeb51c14dc 思考过程完成后不再出现后端的kaishi字段内容; 2 days ago
no99 ac4171fddc Merge branch 'hongxilin/feature-20250628153758-财神优化:字正确性,一致性等' into milestone-20250710-上线前优化 2 days ago
no99 c83c36e43c 情绪大模型用户信息添加发送时间 2 days ago
宋杰 55ada1f88c Merge branch 'milestone-20250710-上线前优化' of http://39.101.133.168:8807/hongxilin/AIxiaocaishen into milestone-20250710-上线前优化 2 days ago
宋杰 7f5d3ce5a6 情绪大模型取消对话数限制,并且查询同一只股票不再去重; 2 days ago
no99 bd40aa2408 Merge branch 'hongxilin/feature-20250628153758-财神优化:字正确性,一致性等' into milestone-20250710-上线前优化 2 days ago
no99 7677bb7459 夺宝奇兵大模型用户信息添加发送时间 2 days ago
宋杰 c16773e469 情绪大模型返回顶部全局唯一;情绪大模型手机端加入背景颜色; 2 days ago
no99 baabaf73c0 Merge branch 'hongxilin/feature-20250628153758-财神优化:字正确性,一致性等' into milestone-20250710-上线前优化 2 days ago
no99 8ab9e36bde 1.修改用户反馈和公告的位置; 2 days ago
宋杰 dd99f8a220 两个模型的思考过程修改完成;情绪大模型新增计算属性显示对话; 2 days ago
宋杰 4636df2f07 思考过程动图在文本框内部; 2 days ago
宋杰 5236ecc4ba 修改免责声明字体; 2 days ago
宋杰 f1da05ac3d 情绪大模型搜索股票时记录实时更新; 3 days ago
宋杰 4a8daf207a 思考过程使用导入图片的方式; 3 days ago
宋杰 37598eef94 历史记录条目展示股票名称加代码; 3 days ago
宋杰 71df42d399 Merge branch 'milestone-20250710-上线前优化' of http://39.101.133.168:8807/hongxilin/AIxiaocaishen into milestone-20250710-上线前优化 3 days ago
no99 8c0749ed7e 返回首页,获取历史纪录的数据返回格式更改 3 days ago
宋杰 56bd68c1f8 获取历史记录接口没有数据时前端不会报错; 3 days ago
宋杰 1d1e2cbefd 修改情绪大模型字体大小;开发环境加前缀; 3 days ago
  1. 2
      .env.development
  2. 2
      src/store/chat.js
  3. 29
      src/store/emotion.ts
  4. 232
      src/views/AIchat.vue
  5. 2305
      src/views/AiEmotion.vue
  6. 4
      src/views/DBQBmodel.vue
  7. 2
      src/views/Emotionsmodel.vue
  8. 226
      src/views/components/HistoryRecord.vue
  9. 2
      src/views/components/emoEnergyConverter.vue
  10. 15
      src/views/components/emotionDecod.vue
  11. 155
      src/views/homePage.vue

2
.env.development

@ -2,7 +2,7 @@
VITE_ENV = 'development'
VITE_OUTPUT_DIR = 'dev'
# public path
VITE_PUBLIC_PATH = /
VITE_PUBLIC_PATH = /aixiaocaishen
#新数据接口
VITE_APP_API_BASE_URL = "http://39.101.133.168:8828/link"

2
src/store/chat.js

@ -11,6 +11,8 @@ export const useChatStore = defineStore("chat", {
searchRecord: false,
currentUserIndex: null,
announcementMsg: null,
aiChatCall:false,
aiEmotionCall:false
}),
actions: {
async getUserCount() {

29
src/store/emotion.ts

@ -6,9 +6,7 @@ export const useEmotionStore = defineStore('emotion', {
history: [] as HistoryItem[], // 历史记录数组
stockList: [] as StockData[], // 当前显示的股票列表
activeStockIndex: 0, // 当前激活的股票索引
maxStocks: 10, // 最大股票数量限制
conversations: [] as ConversationMessage[], // 对话消息数组
maxConversations: 100, // 最大对话数量限制
}),
persist: {
key: 'emotion-store',
@ -22,12 +20,8 @@ export const useEmotionStore = defineStore('emotion', {
},
// 获取股票数量
stockCount: (state) => state.stockList.length,
// 是否达到最大股票数量
isMaxStocks: (state) => state.stockList.length >= state.maxStocks,
// 获取对话数量
conversationCount: (state) => state.conversations.length,
// 是否达到最大对话数量
isMaxConversations: (state) => state.conversations.length >= state.maxConversations,
// 获取最近的对话消息
recentConversations: (state) => {
return state.conversations.slice(-20); // 返回最近20条对话
@ -44,28 +38,9 @@ export const useEmotionStore = defineStore('emotion', {
},
// 添加新股票
addStock(stockData: StockData) {
// 检查是否已存在相同的股票
const existingIndex = this.stockList.findIndex(
stock => stock.stockInfo.code === stockData.stockInfo.code &&
stock.stockInfo.market === stockData.stockInfo.market
);
if (existingIndex !== -1) {
// 如果股票已存在,更新数据并切换到该股票
this.stockList[existingIndex] = stockData;
this.activeStockIndex = existingIndex;
} else {
// 如果达到最大数量,移除最旧的股票
if (this.stockList.length >= this.maxStocks) {
this.stockList.shift();
if (this.activeStockIndex > 0) {
this.activeStockIndex--;
}
}
// 添加新股票并设为当前激活
this.stockList.push(stockData);
this.activeStockIndex = this.stockList.length - 1;
}
// 同时添加到历史记录
// this.addHistory({
@ -130,10 +105,6 @@ export const useEmotionStore = defineStore('emotion', {
},
// 添加对话消息
addConversation(message: ConversationMessage) {
// 如果达到最大数量,移除最旧的消息
if (this.conversations.length >= this.maxConversations) {
this.conversations.shift();
}
// 添加新消息到数组末尾
this.conversations.push({
...message,

232
src/views/AIchat.vue

@ -18,6 +18,10 @@ import { useChatStore } from "../store/chat";
import { useAudioStore } from "../store/audio";
import { useDataStore } from "@/store/dataList.js";
import { marked } from "marked"; // marked
// GIF
import thinkingGif from "@/assets/img/gif/思考.gif";
import analyzeGif from "@/assets/img/gif/解析.gif";
import generateGif from "@/assets/img/gif/生成.gif";
import katex from "katex"; // KaTeX
import { htmlToText } from "html-to-text";
import { Howl, Howler } from "howler";
@ -145,7 +149,7 @@ const playNextAudio = () => {
setTimeout(() => {
isCallingPlayNext = false;
playNextAudio();
}, 500);
}, 200);
} else {
console.log("🎉 所有音频播放完成,清除音频实例");
chatStore.messages[chatStore.currentUserIndex].audioStatus = false;
@ -748,7 +752,6 @@ const createTypingEffect = (message, content, speed) => {
if (message.end) {
chatStore.getUserCount();
chatStore.isLoading = false;
chatStore.searchRecord = true;
console.log("打印完毕,接触输入框禁用状态");
emit("enableInput");
}
@ -952,8 +955,8 @@ async function showThinkingProcess(stockName = null) {
class: "ing",
type: "ing",
flag: true,
content: "正在思考......",
gif: "/src/assets/img/gif/思考.gif",
content: "夺宝奇兵大模型正在思考",
gif: thinkingGif,
});
chatStore.messages.push(thinkingMessage1);
await new Promise((resolve) => setTimeout(resolve, 1500));
@ -965,8 +968,8 @@ async function showThinkingProcess(stockName = null) {
class: "ing",
type: "ing",
flag: true,
content: "正在解析关键数据......",
gif: "/src/assets/img/gif/解析.gif",
content: "正在解析关键数据",
gif: analyzeGif,
});
chatStore.messages.push(thinkingMessage2);
@ -985,8 +988,8 @@ async function showThinkingProcess(stockName = null) {
class: "ing",
type: "ing",
flag: true,
content: `正在生成${stockName}全景作战报告......`,
gif: "/src/assets/img/gif/生成.gif",
content: `正在生成${stockName}全景作战报告`,
gif: generateGif,
});
chatStore.messages.push(thinkingMessage3);
await new Promise((resolve) => setTimeout(resolve, 1500));
@ -997,9 +1000,7 @@ async function showThinkingProcess(stockName = null) {
sender: "ai",
class: "ing",
type: "ing",
flag: true,
content: "报告已生成!",
gif: "/src/assets/img/gif/生成.gif",
});
chatStore.messages.push(thinkingMessage4);
await new Promise((resolve) => setTimeout(resolve, 1500));
@ -1027,8 +1028,8 @@ async function continueThinkingProcess(thinkingMessageRef, stockName) {
class: "ing",
type: "ing",
flag: true,
content: `正在生成${stockName}全景作战报告......`,
gif: "/src/assets/img/gif/生成.gif",
content: `正在生成${stockName}全景作战报告`,
gif: generateGif,
});
chatStore.messages.push(thinkingMessage3);
await new Promise((resolve) => setTimeout(resolve, 1500));
@ -1039,7 +1040,6 @@ async function continueThinkingProcess(thinkingMessageRef, stockName) {
sender: "ai",
class: "ing",
type: "ing",
flag: true,
content: "报告已生成!",
});
chatStore.messages.push(thinkingMessage4);
@ -1063,6 +1063,33 @@ watch(
previousMessagesLength.value = newVal.length;
if (newVal.length > 0) {
//
console.log("chatStore.currentUserIndex", chatStore.currentUserIndex);
if (chatStore.currentUserIndex != null) {
chatStore.messages[chatStore.currentUserIndex].audioStatus = false;
}
chatStore.currentUserIndex = null;
audioStore.stop(); //
// 🔧
audioQueue.value = [];
isPlayingAudio.value = false;
currentPlayIndex = 0;
isCallingPlayNext = false;
//
audioPreloadStatus.one = { loaded: false, url: null };
audioPreloadStatus.two = { loaded: false, url: null };
audioPreloadStatus.three = { loaded: false, url: null };
audioPreloadStatus.four = { loaded: false, url: null };
//
audioStore.soundInstance = null;
audioStore.nowSound = null;
audioStore.isPlaying = false;
audioStore.isPaused = false;
audioStore.playbackPosition = 0;
console.log("消息列表已更新,最新消息:", newVal[newVal.length - 1]);
chatStore.messages.push(newVal[newVal.length - 1]);
chatStore.currentUserIndex = chatStore.messages.length - 1;
@ -1101,6 +1128,8 @@ watch(
console.log(codeData.value, "codeData");
//
if (result.code == 200) {
//
chatStore.searchRecord = true;
//
if (thinkingMessageRef && codeData.value.name) {
await continueThinkingProcess(
@ -1108,12 +1137,17 @@ watch(
codeData.value.name
);
}
for (let i = chatStore.messages.length - 1; i >= 0; --i) {
if (chatStore.messages[i].sender == "user") {
chatStore.messages[i].audioStatus = true;
break;
}
}
chatStore.messages.push({
class: "ing",
type: "ing",
flag: flag,
content: result.data.kaishi,
// class: "ing",
// type: "ing",
// flag: flag,
// content: result.data.kaishi,
});
} else {
//
@ -1148,7 +1182,7 @@ watch(
class: "ing",
type: "ing",
flag: flag,
content: aiContent,
content: AIcontent,
});
chatStore.isLoading = false;
@ -2417,6 +2451,16 @@ watch(
return;
}
try {
//
chatStore.currentUserIndex = null;
audioStore.stop(); //
//
emit("enableInput");
//
typingQueue.value = [];
isTypingInProgress.value = false;
//
chatStore.messages = [];
@ -2770,7 +2814,7 @@ function KlineCanvsEcharts(containerId) {
name: "\u4eea\u8868\u76d8",
type: "gauge",
center: ["50%", "50%"],
radius: "90%",
radius: window.innerWidth > 768 ? "90%" : "70%",
startAngle: 140,
endAngle: -140,
min: 0,
@ -3286,10 +3330,10 @@ function KlineCanvsEcharts(containerId) {
{
textStyle: {
color: "black",
fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8),
fontSize: window.innerWidth > 768 ? 12 : 9,
},
width: "100%",
top: window.innerWidth > 768 ? "0%" : "-1%",
top: window.innerWidth > 768 ? "5%" : "4%",
left: "center",
itemGap: window.innerWidth > 768 ? 20 : 10,
itemWidth: 10,
@ -3324,10 +3368,10 @@ function KlineCanvsEcharts(containerId) {
{
textStyle: {
color: "black",
fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8),
fontSize: window.innerWidth > 768 ? 12 : 9,
},
orient: "horizontal",
top: window.innerWidth > 768 ? "3%" : "2%",
top: window.innerWidth > 768 ? "8%" : "7%",
width: "100%",
left: "center",
itemGap: 15,
@ -3339,11 +3383,11 @@ function KlineCanvsEcharts(containerId) {
rich: {
green: {
color: "green",
fontSize: window.innerWidth > 768 ? 20 : 10,
fontSize: window.innerWidth > 768 ? 12 : 9,
},
red: {
color: "red",
fontSize: window.innerWidth > 768 ? 20 : 10,
fontSize: window.innerWidth > 768 ? 12 : 9,
},
},
},
@ -3359,10 +3403,10 @@ function KlineCanvsEcharts(containerId) {
{
textStyle: {
color: "black",
fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8),
fontSize: window.innerWidth > 768 ? 12 : 9,
},
orient: "horizontal",
top: window.innerWidth > 768 ? "68%" : "64%",
top: window.innerWidth > 768 ? "62%" : "60%",
width: "100%",
left: "center",
itemGap: 15,
@ -3374,11 +3418,11 @@ function KlineCanvsEcharts(containerId) {
rich: {
green: {
color: "green",
fontSize: window.innerWidth > 768 ? 20 : 10,
fontSize: window.innerWidth > 768 ? 12 : 9,
},
red: {
color: "red",
fontSize: window.innerWidth > 768 ? 20 : 10,
fontSize: window.innerWidth > 768 ? 12 : 9,
},
},
},
@ -3465,53 +3509,62 @@ function KlineCanvsEcharts(containerId) {
},
grid: [
{
top: window.innerWidth > 768 ? "12%" : "10%",
left:
window.innerWidth > 1024
? "70vw"
? "14%"
: window.innerWidth > 768
? "65vw"
: "55vw",
? "18%"
: window.innerWidth > 375
? "20%"
: "22%",
right:
window.innerWidth > 1024
? "40vw"
? "9%"
: window.innerWidth > 768
? "30vw"
: "40vw",
top: window.innerWidth > 768 ? "8%" : "5%",
height: window.innerWidth > 768 ? "34%" : "34%",
? "12%"
: "14%",
height: window.innerWidth > 768 ? "27%" : "29%",
containLabel: false,
},
{
top: window.innerWidth > 768 ? "42%" : "42%",
left:
window.innerWidth > 1024
? "70vw"
? "14%"
: window.innerWidth > 768
? "65vw"
: "55vw",
? "18%"
: window.innerWidth > 375
? "20%"
: "22%",
right:
window.innerWidth > 1024
? "40vw"
? "9%"
: window.innerWidth > 768
? "30vw"
: "40vw",
top: window.innerWidth > 768 ? "45%" : "42%",
height: window.innerWidth > 768 ? "22%" : "22%",
? "12%"
: "14%",
height: window.innerWidth > 768 ? "20%" : "18%",
containLabel: false,
},
{
top: window.innerWidth > 768 ? "66%" : "64%",
left:
window.innerWidth > 1024
? "70vw"
? "14%"
: window.innerWidth > 768
? "65vw"
: "55vw",
? "18%"
: window.innerWidth > 375
? "20%"
: "22%",
right:
window.innerWidth > 1024
? "40vw"
? "9%"
: window.innerWidth > 768
? "30vw"
: "40vw",
top: window.innerWidth > 768 ? "73%" : "70%",
? "12%"
: "14%",
height: window.innerWidth > 768 ? "20%" : "22%",
containLabel: false,
},
@ -3556,6 +3609,7 @@ function KlineCanvsEcharts(containerId) {
axisLabel: {
show: true,
interval: "auto",
fontSize: window.innerWidth > 768 ? 12 : 9,
},
},
],
@ -3652,11 +3706,15 @@ function KlineCanvsEcharts(containerId) {
show: true,
xAxisIndex: [0, 1, 2],
type: "slider",
top: window.innerWidth > 768 ? "95%" : "96%",
top: window.innerWidth > 768 ? "90%" : "91%",
// left: window.innerWidth > 768 ? "10%" : "8%",
// right: window.innerWidth > 768 ? "4%" : "8%",
height: 20,
start: 98,
end: 100,
textStyle: {
fontSize: window.innerWidth > 768 ? 12 : 9,
},
},
],
visualMap: [
@ -4092,6 +4150,11 @@ function KlineCanvsEcharts(containerId) {
type: "solid",
},
data: [{ yAxis: 20 }],
label: {
normal: {
fontSize: window.innerWidth > 768 ? 12 : 9,
},
},
},
},
{
@ -4109,6 +4172,11 @@ function KlineCanvsEcharts(containerId) {
type: "solid",
},
data: [{ yAxis: 50 }],
label: {
normal: {
fontSize: window.innerWidth > 768 ? 12 : 9,
},
},
},
},
{
@ -4126,6 +4194,11 @@ function KlineCanvsEcharts(containerId) {
type: "solid",
},
data: [{ yAxis: 80 }],
label: {
normal: {
fontSize: window.innerWidth > 768 ? 12 : 9,
},
},
},
},
{
@ -4144,6 +4217,11 @@ function KlineCanvsEcharts(containerId) {
type: "solid",
},
data: [{ yAxis: 100 }],
label: {
normal: {
fontSize: window.innerWidth > 768 ? 12 : 9,
},
},
},
},
],
@ -4280,6 +4358,8 @@ onMounted(() => {
});
renderAllKlineCharts();
console.log("组件挂载完成");
//
chatStore.currentUserIndex = null;
chatStore.messages.forEach((item) => {
if (item.sender == "user") {
@ -4376,6 +4456,8 @@ onUnmounted(() => {
<div v-for="(msg, index) in chatMsg" :key="index">
<!-- 用户消息容器包含喇叭按钮 -->
<div v-if="msg.sender === 'user'" class="user-message-container">
<div class="user-msg">
<div class="user-content">
<img
:src="msg.audioStatus ? voice : voiceNoActive"
class="user-message-speaker"
@ -4395,6 +4477,11 @@ onUnmounted(() => {
<div v-html="msg.content"></div>
</div>
</div>
<div v-if="msg.timestamp" class="user-sendTime">
{{ moment(msg.timestamp).format("YYYY-MM-DD HH:mm:ss") }}
</div>
</div>
</div>
<!-- AI消息和其他类型消息 -->
<div
@ -4465,7 +4552,7 @@ onUnmounted(() => {
</div>
<div v-else-if="msg.type == 'content2'" class="content2">
<div class="kline-container content2chart">
<div :id="'kline-container-' + index" class="chart-mount-point">
<div :id="'kline-container-' + index" class="chart-mount-pointJN">
<div v-if="!msg.hasValidData" class="no-data-message">
<p>暂无数据</p>
</div>
@ -4677,18 +4764,37 @@ p {
/* 用户消息容器样式 */
.user-message-container {
display: flex;
align-items: flex-start;
/* align-items: flex-start; */
margin: 10px 0px;
justify-content: flex-end;
gap: 10px;
/* align-items: center; */
flex-direction: column;
}
.user-msg {
margin-left: auto;
}
.user-content {
display: flex;
height: 100%;
align-items: center;
margin-right: 5px;
}
.user-sendTime {
width: 100%;
text-align: center;
color: rgba(255, 255, 255, 0.6);
font-size: 0.8rem;
}
.user-message-speaker {
width: 32px;
height: 32px;
object-fit: contain;
margin-top: 5px;
margin-right: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
@ -4951,10 +5057,18 @@ p {
width: 90%;
}
.kline-container .chart-mount-pointJN {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
}
/* AI消息容器样式 */
.ai-message-container {
display: flex;
align-items: flex-start;
align-items: center;
gap: 10px;
margin-right: auto;
max-width: 80%;
@ -4984,7 +5098,7 @@ p {
.ai-message-content {
display: flex;
align-items: center;
white-space: nowrap;
/* white-space: nowrap; */
width: fit-content;
overflow: visible;
}

2305
src/views/AiEmotion.vue
File diff suppressed because it is too large
View File

4
src/views/DBQBmodel.vue

@ -121,7 +121,7 @@ const goToHomePage = () => {
align-items: center;
justify-content: center;
/* 添加水平居中 */
gap: 23px;
/* gap: 23px; */
margin-bottom: 10px;
flex-wrap: wrap;
/* 添加换行支持,防止小屏幕溢出 */
@ -181,7 +181,7 @@ const goToHomePage = () => {
.btn-item img {
width: 50%;
margin-top: 20px;
/* margin-top: 20px; */
}
}
</style>

2
src/views/Emotionsmodel.vue

@ -63,7 +63,7 @@ onUnmounted(() => {
const goToAiEmotion = () => {
// sessionStorage homepage.vue AiEmotion tab
sessionStorage.setItem("activeTabAI", "AiEmotion");
sessionStorage.setItem("activeIndexAI", "2");
sessionStorage.setItem("activeIndexAI", "1");
router.push("/homePage");
};
</script>

226
src/views/components/HistoryRecord.vue

@ -25,23 +25,23 @@
<div v-if="isCollapsed" class="collapsed-bottom-container">
<div
class="collapsed-bottom-btn"
@click="handleFeedbackClick"
title="用户反馈"
@click="handleAnnouncementClick"
title="公告"
>
<img
class="collapsed-bottom-feedback"
src="https://d31zlh4on95l9h.cloudfront.net/images/41d6e25c19466718d462bcee2f050140.png"
class="collapsed-bottom-announcement"
src="https://d31zlh4on95l9h.cloudfront.net/images/c51c7fbb68671729801fb10d65bd7789.png"
alt="icon"
/>
</div>
<div
class="collapsed-bottom-btn"
@click="handleAnnouncementClick"
title="公告"
@click="handleFeedbackClick"
title="用户反馈"
>
<img
class="collapsed-bottom-announcement"
src="https://d31zlh4on95l9h.cloudfront.net/images/c51c7fbb68671729801fb10d65bd7789.png"
class="collapsed-bottom-feedback"
src="https://d31zlh4on95l9h.cloudfront.net/images/41d6e25c19466718d462bcee2f050140.png"
alt="icon"
/>
</div>
@ -78,7 +78,7 @@
</div>
<div v-else v-for="history in categoryHistory" :key="history.name">
<div class="categoryName">
<div class="categoryName" v-if="history.list.length!=0">
{{ history.name }}
</div>
<div
@ -95,9 +95,28 @@
/>
</div>
<div class="record-msg">
<div class="record-text">{{ record.stockCode }}</div>
<div class="record-text">
<span class="stock-name">{{ record.stockName }}</span>
<span class="stock-code">({{ record.stockCode }})</span>
<div v-if="history.name === '置顶'">
<svg
t="1755227529729"
class="top-icon"
viewBox="320 280 380 460"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="7392"
>
<path
d="M351.085714 292.571429h321.828572v29.257142H351.085714v-29.257142z m175.542857 125.805714l146.285715 146.285714-20.48 20.48-125.805715-125.805714V731.428571h-29.257142v-272.091428L371.565714 585.142857l-20.48-20.48 146.285715-146.285714h29.257142z"
fill="#FFFFFF"
p-id="7393"
></path>
</svg>
</div>
</div>
<div class="record-time">
{{ moment(record.updatedTime).format("YYYY-MM-DD HH:mm:ss") }}
{{ moment(record.createdTime).format("YYYY-MM-DD HH:mm:ss") }}
</div>
</div>
</div>
@ -167,17 +186,17 @@
</div>
<div class="bottom-container">
<div class="bottom-btn" @click="handleFeedbackClick" title="用户反馈">
<div class="bottom-btn" @click="handleAnnouncementClick" title="公告">
<img
class="bottom-feedback"
src="https://d31zlh4on95l9h.cloudfront.net/images/41d6e25c19466718d462bcee2f050140.png"
class="bottom-announcement"
src="https://d31zlh4on95l9h.cloudfront.net/images/c51c7fbb68671729801fb10d65bd7789.png"
alt="icon"
/>
</div>
<div class="bottom-btn" @click="handleAnnouncementClick" title="公告">
<div class="bottom-btn" @click="handleFeedbackClick" title="用户反馈">
<img
class="bottom-announcement"
src="https://d31zlh4on95l9h.cloudfront.net/images/c51c7fbb68671729801fb10d65bd7789.png"
class="bottom-feedback"
src="https://d31zlh4on95l9h.cloudfront.net/images/41d6e25c19466718d462bcee2f050140.png"
alt="icon"
/>
</div>
@ -222,7 +241,7 @@
</div>
<div v-else v-for="history in categoryHistory" :key="history.name">
<div class="categoryName">
<div class="categoryName" v-if="history.list.length!=0">
{{ history.name }}
</div>
<div
@ -239,9 +258,28 @@
/>
</div>
<div class="record-msg">
<div class="record-text">{{ record.stockCode }}</div>
<div class="record-text">
<span class="stock-name">{{ record.stockName }}</span>
<span class="stock-code">({{ record.stockCode }})</span>
<div v-if="history.name === '置顶'">
<svg
t="1755227529729"
class="top-icon"
viewBox="320 280 380 460"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="7392"
>
<path
d="M351.085714 292.571429h321.828572v29.257142H351.085714v-29.257142z m175.542857 125.805714l146.285715 146.285714-20.48 20.48-125.805715-125.805714V731.428571h-29.257142v-272.091428L371.565714 585.142857l-20.48-20.48 146.285715-146.285714h29.257142z"
fill="#FFFFFF"
p-id="7393"
></path>
</svg>
</div>
</div>
<div class="record-time">
{{ moment(record.updatedTime).format("YYYY-MM-DD HH:mm:ss") }}
{{ moment(record.createdTime).format("YYYY-MM-DD HH:mm:ss") }}
</div>
</div>
</div>
@ -313,27 +351,27 @@
<div class="mobile-bottom-container">
<div
class="mobile-bottom-btn"
@click="handleFeedbackClick"
title="用户反馈"
@click="handleAnnouncementClick"
title="公告"
>
<img
class="mobile-bottom-feedback"
src="https://d31zlh4on95l9h.cloudfront.net/images/41d6e25c19466718d462bcee2f050140.png"
class="mobile-bottom-announcement"
src="https://d31zlh4on95l9h.cloudfront.net/images/c51c7fbb68671729801fb10d65bd7789.png"
alt="icon"
/>
<div class="mobile-bottom-text">用户反馈</div>
<div class="mobile-bottom-text">公告</div>
</div>
<div
class="mobile-bottom-btn"
@click="handleAnnouncementClick"
title="公告"
@click="handleFeedbackClick"
title="用户反馈"
>
<img
class="mobile-bottom-announcement"
src="https://d31zlh4on95l9h.cloudfront.net/images/c51c7fbb68671729801fb10d65bd7789.png"
class="mobile-bottom-feedback"
src="https://d31zlh4on95l9h.cloudfront.net/images/41d6e25c19466718d462bcee2f050140.png"
alt="icon"
/>
<div class="mobile-bottom-text">公告</div>
<div class="mobile-bottom-text">用户反馈</div>
</div>
</div>
</div>
@ -415,11 +453,52 @@ const closeDeleteDialog = () => {
const historyRecords = ref([]);
const categoryHistory = ref([]);
let chatFirstFlag = true;
let emotionTirstFlag = true;
const getHistoryList = async (params) => {
try {
const result = await getHistoryListAPI(params);
historyRecords.value = result.data.list;
let remainingRecords = result.data.list; //
historyRecords.value = result.data;
let remainingRecords = result.data; //
console.log(
"params",
params,
"result",
result.data,
"chatFirstFlag",
chatFirstFlag,
"emotionTirstFlag",
emotionTirstFlag
);
if (chatFirstFlag && params.model == 1 && result.data.length != 0) {
const userAgent = navigator.userAgent;
if (
!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
userAgent
)
) {
chatStore.aiChatCall = true;
}
chatFirstFlag = false;
}
if (emotionTirstFlag && params.model == 2 && result.data.length != 0) {
const userAgent = navigator.userAgent;
if (
!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
userAgent
)
) {
chatStore.aiEmotionCall = true;
}
emotionTirstFlag = false;
}
if (props.currentType == "AIchat") {
isCollapsed.value = !chatStore.aiChatCall;
} else {
isCollapsed.value = !chatStore.aiEmotionCall;
}
// 1.
let topList = remainingRecords.filter((record) => record.isTop === 1);
@ -428,12 +507,12 @@ const getHistoryList = async (params) => {
// 2.
let todayList = remainingRecords.filter((record) => {
const today = moment().format("YYYY-MM-DD");
const recordDate = moment(record.updatedTime).format("YYYY-MM-DD");
const recordDate = moment(record.createdTime).format("YYYY-MM-DD");
return recordDate === today;
});
remainingRecords = remainingRecords.filter((record) => {
const today = moment().format("YYYY-MM-DD");
const recordDate = moment(record.updatedTime).format("YYYY-MM-DD");
const recordDate = moment(record.createdTime).format("YYYY-MM-DD");
return recordDate !== today;
});
@ -441,13 +520,13 @@ const getHistoryList = async (params) => {
let recent3DaysList = remainingRecords.filter((record) => {
const threeDaysAgo = moment().subtract(3, "days").startOf("day");
const yesterday = moment().subtract(1, "days").endOf("day");
const recordDate = moment(record.updatedTime);
const recordDate = moment(record.createdTime);
return recordDate.isAfter(threeDaysAgo) && recordDate.isBefore(yesterday);
});
remainingRecords = remainingRecords.filter((record) => {
const threeDaysAgo = moment().subtract(3, "days").startOf("day");
const yesterday = moment().subtract(1, "days").endOf("day");
const recordDate = moment(record.updatedTime);
const recordDate = moment(record.createdTime);
return !(
recordDate.isAfter(threeDaysAgo) && recordDate.isBefore(yesterday)
);
@ -456,28 +535,28 @@ const getHistoryList = async (params) => {
// 4. 73
let recent7DaysList = remainingRecords.filter((record) => {
const sevenDaysAgo = moment().subtract(7, "days").startOf("day");
const recordDate = moment(record.updatedTime);
const recordDate = moment(record.createdTime);
return recordDate.isAfter(sevenDaysAgo);
});
remainingRecords = remainingRecords.filter((record) => {
const sevenDaysAgo = moment().subtract(7, "days").startOf("day");
const recordDate = moment(record.updatedTime);
const recordDate = moment(record.createdTime);
return !recordDate.isAfter(sevenDaysAgo);
});
// 5. 30
let recent30DaysList = remainingRecords.filter((record) => {
const thirtyDaysAgo = moment().subtract(30, "days").startOf("day");
const recordDate = moment(record.updatedTime);
const recordDate = moment(record.createdTime);
return recordDate.isAfter(thirtyDaysAgo);
});
remainingRecords = remainingRecords.filter((record) => {
const thirtyDaysAgo = moment().subtract(30, "days").startOf("day");
const recordDate = moment(record.updatedTime);
const recordDate = moment(record.createdTime);
return !recordDate.isAfter(thirtyDaysAgo);
});
historyRecords.value = result.data.list;
historyRecords.value = result.data;
categoryHistory.value = [
{
@ -505,6 +584,9 @@ const getHistoryList = async (params) => {
console.log("categoryHistory", categoryHistory.value);
} catch (e) {
console.error("获取历史记录出错", e);
// historyRecordscategoryHistory
historyRecords.value = [];
categoryHistory.value = [];
}
};
@ -554,10 +636,20 @@ const openHistory = () => {
// token: localStorage.getItem("localToken"),
// });
isCollapsed.value = false;
if (props.currentType == "AIchat") {
chatStore.aiChatCall = true;
} else if (props.currentType == "AiEmotion") {
chatStore.aiEmotionCall = true;
}
};
const closeHistory = () => {
isCollapsed.value = true;
if (props.currentType == "AIchat") {
chatStore.aiChatCall = false;
} else if (props.currentType == "AiEmotion") {
chatStore.aiEmotionCall = false;
}
};
const openDetail = (record) => {
@ -575,26 +667,35 @@ const selectRecord = async (record) => {
});
if (result && result.data) {
if (props.isMobile) {
//
isCollapsed.value = true;
if (props.currentType == "AIchat") {
chatStore.aiChatCall = false;
} else if (props.currentType == "AiEmotion") {
chatStore.aiEmotionCall = false;
}
}
historyData.value = result.data;
chatStore.dbqbClickRecord = historyData.value;
//
const stockData = {
queryText: record.stockCode || record.stockName || '', // 使
queryText: record.keyword || record.stockCode || record.stockName || "", // 使keyword
stockInfo: {
name: result.data.stockData?.stockName || record.stockName || '',
code: record.stockCode || '',
market: record.stockMarket || 'cn'
name: result.data.stockData?.stockName || record.stockName || "",
code: record.stockCode || "",
market: record.stockMarket || "cn",
},
apiData: result.data.stockData || {}, //
conclusionData: result.data.wokeFlowData?.One || {}, //
timestamp: new Date().toISOString()
timestamp: record.createdTime || new Date().toISOString(), // 使createdTime
};
// emit
emit('selectRecord', stockData);
console.log('历史记录数据已发送给父组件:', stockData);
emit("selectRecord", stockData);
console.log("历史记录数据已发送给父组件:", stockData);
} else {
console.error('历史记录数据格式不正确:', result);
console.error("历史记录数据格式不正确:", result);
}
} catch (e) {
console.error("获取历史记录数据失败", e);
@ -651,6 +752,7 @@ defineExpose({
isCollapsed,
toggleCollapse,
getHistoryList,
selectedRecordId,
});
//
@ -702,6 +804,7 @@ onMounted(() => {
}
.mobileCollapsed {
/* max-width: 400px */
width: 80vw;
}
@ -814,6 +917,7 @@ onMounted(() => {
width: 100%;
/* padding: 20px; */
overflow: hidden;
min-height: 0;
}
.head-container {
@ -909,6 +1013,10 @@ onMounted(() => {
background: rgba(255, 255, 255, 0.1);
}
.history-item.active {
background: rgba(255, 255, 255, 0.5);
}
.record-content {
display: flex;
width: 100%;
@ -932,9 +1040,27 @@ onMounted(() => {
margin-bottom: 6px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
display: flex;
}
.top-icon {
margin-left: 5px;
color: white;
height: auto;
width: 15px;
}
.stock-name {
font-weight: 500;
margin-right: 4px;
}
.stock-code {
color: rgba(255, 255, 255, 0.7);
font-size: 12px;
font-weight: 400;
}
.record-time {

2
src/views/components/emoEnergyConverter.vue

@ -152,7 +152,7 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
max: qxnlzhqData.js,
name: "【情绪临界区】",
color: "#FFC0AA",
fontColor: 'white',
fontColor: '#2D2D89',
NumberColor: 'white',
},
];

15
src/views/components/emotionDecod.vue

@ -282,12 +282,19 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
},
bottom: "8%", //
},
{
show: !1,
type: "slider",
},
// {
// show: true,
// type: "slider",
// xAxisIndex: [0, 1, 2],
// bottom: "0%",
// textStyle: {
// color: "white",
// },
// },
{
type: "inside",
xAxisIndex: [0, 1, 2],
filterMode: "filter",
},
],
series: [

155
src/views/homePage.vue

@ -34,9 +34,9 @@ import feedbackBtn from "../assets/img/Feedback/feedbackBtn.png";
import AiEmotion from "./AiEmotion.vue";
import HistoryRecord from "./components/HistoryRecord.vue";
// import VConsole from "vconsole";
import VConsole from "vconsole";
// const vConsole = new VConsole();
const vConsole = new VConsole();
const isMobile = ref(null);
@ -181,7 +181,7 @@ watch(
() => chatStore.announcementMsg,
(newVal) => {
console.log("监听到公告改变", chatStore.announcementMsg);
if (chatStore.announcementMsg) {
if (chatStore.announcementMsg && !isInputDisabled.value) {
message.value = chatStore.announcementMsg;
chatStore.announcementMsg = null;
}
@ -192,6 +192,8 @@ watch(
() => dataStore.isFeedback,
async (newVal) => {
if (!dataStore.isFeedback) {
//
isAnnouncementVisible.value = false;
await nextTick();
//
throttledHeightListener();
@ -217,6 +219,10 @@ const sendMessage = async () => {
//
//
if (historyRecordRef) {
historyRecordRef.value.selectedRecordId = null;
}
// AiEmotion
if (activeTab.value === "AiEmotion") {
//
@ -250,9 +256,8 @@ const sendMessage = async () => {
{
sender: "user",
content: messageContent,
timestamp: new Date().toISOString(),
audioArray: [],
audioStatus: true,
audioStatus: false,
},
];
console.log(messages.value, "messages.value");
@ -267,7 +272,7 @@ const enableInput = () => {
//
const handleHistorySelect = (stockData) => {
console.log('接收到历史记录数据:', stockData);
console.log("接收到历史记录数据:", stockData);
// AiEmotionAiEmotion
// if (activeTab.value !== 'AiEmotion') {
@ -279,7 +284,7 @@ const handleHistorySelect = (stockData) => {
if (aiEmotionRef.value && aiEmotionRef.value.addStock) {
aiEmotionRef.value.addStock(stockData);
} else {
console.error('AiEmotion组件或addStock方法不可用');
console.error("AiEmotion组件或addStock方法不可用");
}
});
};
@ -353,7 +358,7 @@ const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 300, {
});
watch(
() => chatStore.messages,
() => chatStore.messages.length,
() => {
// console.log('messages')
// AIchat
@ -362,7 +367,7 @@ watch(
}
// setTimeout(throttledSmoothScrollToBottom, 100);
},
{ deep: true, immediate: true }
{ deep: false, immediate: true }
);
watch(
@ -382,7 +387,7 @@ watch(
console.log("activeTab变化了", activeTab.value);
if (activeTab.value == "AIchat" || activeTab.value == "AiEmotion") {
if (historyRecordRef.value && historyRecordRef.value.getHistoryList) {
historyRecordRef.value.getHistoryList({
const result = historyRecordRef.value.getHistoryList({
model: activeTab.value == "AIchat" ? 1 : 2,
token: localStorage.getItem("localToken"),
});
@ -392,7 +397,7 @@ watch(
if (activeTab.value === "AIchat") {
isScrolling.value = false; //
setTimeout(() => {
throttledSmoothScrollToBottom();
// throttledSmoothScrollToBottom();
}, 100);
}
// AiEmotion
@ -590,6 +595,11 @@ const onBlur = function () {
let touchmoveHandlerRef = null;
const touchmoveHandler = (e) => {
if (!dataStore.isFeedback) {
if (historyRecordRef) {
if (!historyRecordRef.value.isCollapsed) {
return;
}
}
//
const isScrollableArea = e.target.closest(".tab-content");
@ -628,6 +638,45 @@ const expandHistory = () => {
) {
console.log("存在");
historyRecordRef.value.isCollapsed = !historyRecordRef.value.isCollapsed;
if (activeTab.value == "AIchat") {
chatStore.aiChatCall = true;
} else if (activeTab.value == "AiEmotion") {
chatStore.aiEmotionCall = true;
}
}
};
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
}
};
@ -716,6 +765,14 @@ onUnmounted(() => {
<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"
@ -750,13 +807,22 @@ onUnmounted(() => {
>
<span>{{ tab.label }}</span>
</div>
<div v-if="!isMobile" class="pc-count-badge" @click="showCount">
<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
@ -880,6 +946,14 @@ onUnmounted(() => {
<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"
@ -1178,16 +1252,41 @@ body {
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: 120px;
width: 200px;
height: 100%;
margin-left: auto;
margin-right: 20px;
position: absolute;
right: 20px;
display: flex;
}
.pc-countBtn {
width: 65%;
height: 100%;
position: relative;
}
.pc-count-badge:hover {
.pc-countBtn:hover {
transform: scale(1.05);
}
@ -1217,6 +1316,28 @@ body {
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;

Loading…
Cancel
Save