Browse Source

Merge branch 'songjie/feature-20250924120152-大财神功能开发分支' into milestone-20250924-接入大财神工作流

milestone-20250924-接入大财神工作流
宋杰 2 weeks ago
parent
commit
8ad837d487
  1. 367
      src/api/deepNine.js
  2. 148
      src/components/deepNine/MessageItem.vue
  3. 51
      src/components/deepNine/ThinkingGif.vue
  4. 54
      src/store/deepNine.js
  5. 89
      src/store/deepNineAudio.js
  6. 12
      src/views/deepNine.vue
  7. 428
      src/views/homePage.vue

367
src/api/deepNine.js

@ -0,0 +1,367 @@
import request from "../utils/request";
const APIurl = import.meta.env.VITE_APP_API_BASE_URL;
const cozeAPIurl = import.meta.env.VITE_APP_API_BASE_CAZE_URL;
const MJAPIurl = import.meta.env.VITE_APP_MJ_API_BASE_URL;
const HWurl = import.meta.env.VITE_APP_API_BASE_HW_URL;
//各个模块权限code接口
export const pessionAPI = function (params) {
return request({
url: `${APIurl}/api/brain/privilege`,
method: "post",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
//数据接口
export const dataListAPI = function (params) {
// URLSearchParams只接受全部字符串的数据
// 将传入数据转化成字符串
const StringParams = new URLSearchParams(
Object.entries(params).map(([key, value]) => [key, String(value)])
);
return request({
url: `${APIurl}/api/brain/data`,
method: "post",
data: StringParams,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
//统计用户行为接口
export const computedUsersAPI = function (params) {
return request({
url: `${APIurl}/BrainStatistics/getStatistic`,
method: "post",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
// 首次进入小财神
export const useAiGodAPI = function (params) {
return request({
url: `${APIurl}/api/ai_god/useAiGod`,
method: "post",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
// 停留时间
export const updateStayTimeAPI = function (params) {
return request({
url: `${APIurl}/api/ai_god/updateStayTime`,
method: "post",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
// 获取新闻接口
export const getNewsAPI = function () {
return request({
url: `${APIurl}/api/ai_god/news`,
method: "POST",
});
};
// 获取引导搜索词接口
export const getQuestionAPI = function () {
return request({
url: `${APIurl}/api/ai_god/shows`,
method: "POST",
data: new URLSearchParams({
type: "1",
num: "10",
state: "1",
}),
});
};
// 获取公告接口
export const getAnnouncementAPI = function () {
return request({
url: `${APIurl}/api/ai_god/shows`,
method: "POST",
data: new URLSearchParams({
type: "3",
num: "1",
state: "1",
}),
});
};
// 获取用户次数接口
export const getUserCountAPI = function (params) {
return request({
// 'http://39.101.133.168:8828/link/api/aiEmotion/client/getRemainNum',
url: `${APIurl}/api/aiEmotion/client/getRemainNum`,
method: "POST",
data: params,
// headers: {
// "Content-Type": "application/x-www-form-urlencoded",
// },
});
};
// 推荐问题/每日复盘/小财神简介点击事件接口
export const qsArpAamClickAPI = function (params) {
return request({
url: `${APIurl}/api/ai_god/shows/click`,
method: "POST",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
// 财经新闻点击事件接口
export const newsClickAPI = function (params) {
return request({
url: `${APIurl}/api/ai_god/news/click`,
method: "POST",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
// 获取回复接口
export const getReplyAPI = function (params) {
return fetch("https://api.coze.cn/v1/workflow/run", {
method: "POST",
body: JSON.stringify({
workflow_id: "7491496473373540363",
parameters: params,
}),
headers: {
"Content-Type": "application/json",
Authorization:
"Bearer pat_lK1fvhLn9LnWCRETP7yFeR6xQ0niwQdcHJ5ZqpnUk8BdiUWCraPLSzWhiQNp2zOl",
},
});
};
// 获取回复接口流式
export const getReplyStreamAPI = function (params) {
return fetch(`https://api.coze.cn/v1/workflow/stream_run`, {
method: "POST",
body: JSON.stringify({
workflow_id: "7481159261435854860",
parameters: params,
}),
headers: {
"Content-Type": "application/json",
Authorization:
"Bearer pat_lK1fvhLn9LnWCRETP7yFeR6xQ0niwQdcHJ5ZqpnUk8BdiUWCraPLSzWhiQNp2zOl",
},
});
};
// 接受音频
export const TTSAPI = function (params) {
return fetch("https://api.coze.cn/v1/workflow/run", {
method: "POST",
body: JSON.stringify({
workflow_id: "7481639836165275702",
parameters: params,
}),
headers: {
Authorization:
"Bearer pat_lK1fvhLn9LnWCRETP7yFeR6xQ0niwQdcHJ5ZqpnUk8BdiUWCraPLSzWhiQNp2zOl",
"Content-Type": "application/json",
},
});
};
// 反馈前台-用户提交反馈接口
export const addFeedbackAPI = function (params) {
return request({
url: `${APIurl}/api/ai_god/feedback/add`,
method: "POST",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
// 反馈前台-查询该用户提交的全部反馈内容
export const getFeedbackAPI = function (params) {
return request({
url: `${APIurl}/api/ai_god/feedback/select`,
method: "POST",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
// 公告-查询市场和股票
export const getMarketAndCodeAPI = function (params) {
return request({
url: `${APIurl}/api/ai_god/market/list`,
method: "POST",
data: new URLSearchParams(params),
headers: {
token:
"pCtw6AYK0EHAaIexoFHsbZjtsfEAIhcmwkCFm6uKko8VPfMvyDiODL9v9c0veic9fIpQbvT8zN4sH/Si6Q",
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
// 登录获取次数接口
export const addUsageAPI = function (params) {
return request({
url: `${APIurl}/api/ai_god/addUsage`,
method: "POST",
data: new URLSearchParams(params),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
// duobao11
export const dbqbFirstAPI = function (params) {
return request({
url: `${cozeAPIurl}/api/workflow/dbqbFirst`,
method: "POST",
data: params,
});
};
// duobao21
export const dbqbSecondOneAPI = function (params) {
return request({
url: `${cozeAPIurl}/api/workflow/dbqbSecondOne`,
method: "POST",
data: params,
});
};
// duobao22
export const dbqbSecondTwoAPI = function (params) {
return request({
url: `${cozeAPIurl}/api/workflow/dbqbSecondTwo`,
method: "POST",
data: params,
});
};
// duobao23
export const dbqbSecondThreeAPI = function (params) {
return request({
url: `${cozeAPIurl}/api/workflow/dbqbSecondThree`,
method: "POST",
data: params,
});
};
// duobao24
export const dbqbSecondFourAPI = function (params) {
return request({
url: `${cozeAPIurl}/api/workflow/dbqbSecondFour`,
method: "POST",
data: params,
});
};
// 历史记录 列表
export const getHistoryListAPI = function (params) {
return request({
url: `${APIurl}/api/workflow/listHistory`,
method: "POST",
data: params,
});
};
export const changeTopAPI = function (params) {
return request({
url: `${APIurl}/api/workflow/topRecord`,
method: "POST",
data: params,
headers: {
token: localStorage.getItem("localToken"),
},
});
};
export const deleteRecordAPI = function (params) {
return request({
url: `${APIurl}/api/workflow/deleteRecord`,
method: "POST",
data: params,
});
};
export const clickRecordAPI = function (params) {
return request({
url: `${APIurl}/api/workflow/clickRecord`,
method: "POST",
data: params,
});
};
// 8.18金币兑换Token start
export const showExchangeAPI = function (params) {
return request({
url: `${APIurl}/api/showExchange`,
method: "POST",
data: params,
headers: {
token: localStorage.getItem("localToken"),
},
});
};
export const godExchangeAPI = function (params) {
return request({
url: `${APIurl}/api/godExchange`,
method: "POST",
data: params,
headers: {
token: localStorage.getItem("localToken"),
},
});
};
export const exchangeAPI = function (params) {
return request({
url: `${APIurl}/api/exchange`,
method: "POST",
data: params,
});
};
export const getGoldCoinAPI = function (params) {
return request({
url: `${HWurl}/api/haiwai/user/getGoldCoin`,
method: "POST",
data: params,
});
};
export const getUserInfoAPI = function (params) {
return request({
url: `${HWurl}/api/v2/member/info`,
method: "POST",
data: params,
});
};
// 8.18金币兑换Token end
// 8.25权限控制 start
export const checkStatusAPI = function (headers, params) {
return request({
url: `${APIurl}/api/workflow/checkStatus`, method: "POST",
data: params,
headers: headers,
});
};
// 8.25权限控制 end

148
src/components/deepNine/MessageItem.vue

@ -0,0 +1,148 @@
<template>
<div
class="message-item"
:class="{
'user-message': msg.sender === 'user',
'ai-message': msg.sender === 'ai',
[msg.class]: msg.class
}"
>
<div v-if="msg.type === 'kline'" class="kline-container">
<div :id="'kline-container-' + index" class="chart-mount-point">
<div v-if="!msg.hasValidData" class="no-data-message">
<p>暂无K线数据</p>
</div>
</div>
</div>
<div v-else-if="msg.type == 'ing'" class="ai-message-container">
<thinking-gif
v-if="msg.gif"
:type="getGifType(msg.gif)"
/>
<div class="ai-message-content" :class="{ fourStep: msg.nowrap }">
<div v-if="msg.flag">
<span>{{ msg.content }}</span>
<span class="loading-dots">
<span class="dot">.</span>
<span class="dot">.</span>
<span class="dot">.</span>
<span class="dot">.</span>
<span class="dot">.</span>
<span class="dot">.</span>
</span>
</div>
<div v-else v-html="msg.content"></div>
</div>
</div>
<div v-else class="message-content" v-html="msg.content"></div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ThinkingGif from './ThinkingGif.vue';
import thinkingGif from "@/assets/img/gif/思考.gif";
import analyzeGif from "@/assets/img/gif/解析.gif";
import generateGif from "@/assets/img/gif/生成.gif";
const props = defineProps({
msg: {
type: Object,
required: true
},
index: {
type: Number,
required: true
}
});
// GIF
const getGifType = (gifPath) => {
if (gifPath === thinkingGif) return 'thinking';
if (gifPath === analyzeGif) return 'analyze';
if (gifPath === generateGif) return 'generate';
return 'thinking';
};
</script>
<style scoped>
.message-item {
margin-bottom: 15px;
padding: 10px;
border-radius: 8px;
}
.user-message {
background-color: #e6f7ff;
margin-left: 20%;
}
.ai-message {
background-color: #f5f5f5;
margin-right: 20%;
}
.kline-container {
width: 100%;
height: 400px;
}
.chart-mount-point {
width: 100%;
height: 100%;
}
.no-data-message {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: #999;
}
.ai-message-container {
display: flex;
flex-direction: column;
}
.ai-message-content {
padding: 10px;
}
.loading-dots .dot {
animation: loading 1.4s infinite;
display: inline-block;
opacity: 0;
}
.loading-dots .dot:nth-child(1) {
animation-delay: 0s;
}
.loading-dots .dot:nth-child(2) {
animation-delay: 0.2s;
}
.loading-dots .dot:nth-child(3) {
animation-delay: 0.4s;
}
.loading-dots .dot:nth-child(4) {
animation-delay: 0.6s;
}
.loading-dots .dot:nth-child(5) {
animation-delay: 0.8s;
}
.loading-dots .dot:nth-child(6) {
animation-delay: 1s;
}
@keyframes loading {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>

51
src/components/deepNine/ThinkingGif.vue

@ -0,0 +1,51 @@
<template>
<div class="thinking-gif-container">
<img
v-if="gifSrc"
:src="gifSrc"
alt="思考过程"
class="thinking-gif"
/>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
// GIF
import thinkingGif from "@/assets/img/gif/思考.gif";
import analyzeGif from "@/assets/img/gif/解析.gif";
import generateGif from "@/assets/img/gif/生成.gif";
const props = defineProps({
type: {
type: String,
default: 'thinking'
}
});
const gifSrc = computed(() => {
switch(props.type) {
case 'thinking':
return thinkingGif;
case 'analyze':
return analyzeGif;
case 'generate':
return generateGif;
default:
return thinkingGif;
}
});
</script>
<style scoped>
.thinking-gif-container {
display: flex;
justify-content: center;
margin: 10px 0;
}
.thinking-gif {
max-width: 100%;
height: auto;
}
</style>

54
src/store/deepNine.js

@ -0,0 +1,54 @@
import { defineStore } from "pinia";
import { getUserCountAPI } from "@/api/AIxiaocaishen";
export const useDeepNineStore = defineStore("deepNine", {
state: () => ({
messages: [],
isLoading: false, // 新增加载状态
UserCount: 0,
chartData: [],
kLineData: [],
dbqbClickRecord: {},
searchRecord: false,
currentUserIndex: null,
inputUserIndex:null,
announcementMsg: null,
// 调用接口状态
aiChatCall:false,
aiEmotionCall:false,
deepNineCall:false,
// 输入框控制
chatInput:false,
emotionInput:false,
deepNineInput:false,
firstAPICall:false,
dbqbScrollToTop:true,
}),
actions: {
async getUserCount() {
const result = await getUserCountAPI({
token: localStorage.getItem("localToken"),
source: "1",
});
this.UserCount = result.data;
},
setLoading(status) {
this.isLoading = status;
},
isLoadingT() {
this.isLoading = true;
},
isLoadingF() {
this.isLoading = false;
},
addKLineData(data) {
this.kLineData.push(data);
},
},
persist: {
key: "deepNine_messages",
storage: sessionStorage,
paths: ["messages", "kLineData"],
},
});

89
src/store/deepNineAudio.js

@ -0,0 +1,89 @@
import { defineStore } from 'pinia'
export const useDeepNineAudioStore = defineStore('deepNineAudio', {
state: () => ({
soundInstance: null, // Howl 实例
isPlaying: false, // 播放状态
isVoiceEnabled: true, // 新增声音开关状态
playbackPosition: 0, // 新增播放位置存储
lastVoiceState: null,
ttsUrl:'',
isNewInstance: false, // 新增是否是新实例的标志
nowSound:'',
currentAudioUrl: '', // 当前音频URL
isPaused: false, // 是否处于暂停状态
duration: 0 // 音频总时长
}),
actions: {
// 设置音频实例
setAudioInstance(instance) {
this.soundInstance = instance
},
// 播放控制
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 && 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 = ''
}
}
})

12
src/views/deepNine.vue

@ -1,6 +1,8 @@
<script setup> <script setup>
import { ref, onMounted, watch, nextTick, reactive, onUnmounted } from "vue"; import { ref, onMounted, watch, nextTick, reactive, onUnmounted } from "vue";
import { ElDialog, ElMessage } from "element-plus"; import { ElDialog, ElMessage } from "element-plus";
import MessageItem from "@/components/deepNine/MessageItem.vue";
import ThinkingGif from "@/components/deepNine/ThinkingGif.vue";
import { import {
getReplyStreamAPI, getReplyStreamAPI,
getReplyAPI, getReplyAPI,
@ -12,10 +14,10 @@ import {
dbqbSecondThreeAPI, dbqbSecondThreeAPI,
dbqbSecondFourAPI, dbqbSecondFourAPI,
dataListAPI, dataListAPI,
} from "../api/AIxiaocaishen";
} from "../api/deepNine";
import { useUserStore } from "../store/userPessionCode"; import { useUserStore } from "../store/userPessionCode";
import { useChatStore } from "../store/chat";
import { useAudioStore } from "../store/audio";
import { useDeepNineStore } from "../store/deepNine";
import { useDeepNineAudioStore } from "../store/deepNineAudio";
import { useDataStore } from "@/store/dataList.js"; import { useDataStore } from "@/store/dataList.js";
import { marked } from "marked"; // marked import { marked } from "marked"; // marked
// GIF // GIF
@ -37,8 +39,8 @@ import logo2 from "@/assets/img/AIchat/开启无限财富.png";
import getCountAll from "../assets/img/homePage/get-count-all.png"; import getCountAll from "../assets/img/homePage/get-count-all.png";
import voice from "../assets/img/homePage/tail/voice.png"; import voice from "../assets/img/homePage/tail/voice.png";
import voiceNoActive from "../assets/img/homePage/tail/voice-no-active.png"; import voiceNoActive from "../assets/img/homePage/tail/voice-no-active.png";
const chatStore = useChatStore();
const audioStore = useAudioStore();
const chatStore = useDeepNineStore();
const audioStore = useDeepNineAudioStore();
const dataStore = useDataStore(); const dataStore = useDataStore();
// //

428
src/views/homePage.vue

@ -22,6 +22,7 @@ import { useDataStore } from "@/store/dataList.js";
import { useChatStore } from "../store/chat"; import { useChatStore } from "../store/chat";
import { useEmotionAudioStore } from "../store/emotionAudio"; import { useEmotionAudioStore } from "../store/emotionAudio";
import { useAudioStore } from "../store/audio"; import { useAudioStore } from "../store/audio";
import { useDeepNineStore } from "../store/deepNine";
import _ from "lodash"; import _ from "lodash";
import logo from "../assets/img/homePage/logo.png"; import logo from "../assets/img/homePage/logo.png";
@ -52,6 +53,8 @@ const isMobile = ref(null);
// AiEmotion ref // AiEmotion ref
const aiEmotionRef = ref(null); const aiEmotionRef = ref(null);
// ref
const deepNineRef = ref(null);
// ref // ref
const historyRecordRef = ref(null); const historyRecordRef = ref(null);
// import { useUserStore } from "../store/userPessionCode.js"; // import { useUserStore } from "../store/userPessionCode.js";
@ -313,6 +316,35 @@ const sendMessage = async () => {
return; return;
} }
//
if (activeTab.value === "deepNine") {
//
isInputDisabled.value = true;
// store
const deepNineStore = useDeepNineStore();
// store
const messageContent = message.value;
message.value = ""; //
setTimeout(() => {
console.log("深度九大模型:添加消息", messageContent);
messages.value = [
...messages.value,
{
sender: "user",
content: messageContent,
audioArray: [],
audioStatus: false,
},
];
}, 200);
return;
}
// ensureAIchat AIchat // ensureAIchat AIchat
ensureAIchat(); ensureAIchat();
@ -750,8 +782,8 @@ watch(
activeTab.value == "AIchat" activeTab.value == "AIchat"
? 1 ? 1
: activeTab.value == "AiEmotion" : activeTab.value == "AiEmotion"
? 2
: 3;
? 2
: 3;
const result = historyRecordRef.value.getHistoryList({ const result = historyRecordRef.value.getHistoryList({
model: model, model: model,
token: localStorage.getItem("localToken"), token: localStorage.getItem("localToken"),
@ -1310,58 +1342,35 @@ onUnmounted(() => {
<template> <template>
<div class="homepage" id="testId"> <div class="homepage" id="testId">
<!-- 历史记录组件 --> <!-- 历史记录组件 -->
<HistoryRecord
ref="historyRecordRef"
:current-type="activeTab"
@selectRecord="handleHistorySelect"
:isMobile="isMobile"
@showAnnouncement="showAnnouncement"
@showFeedback="showFeedback"
/>
<div
v-if="isMobile && !historyRecordRef?.isCollapsed"
class="zhezhao"
@click="expandHistory"
></div>
<el-container
v-if="!dataStore.isFeedback"
class="main-container"
:class="{
collapsed: !isMobile && historyRecordRef?.isCollapsed,
unCollapsed: !isMobile && !historyRecordRef?.isCollapsed,
}"
>
<HistoryRecord ref="historyRecordRef" :current-type="activeTab" @selectRecord="handleHistorySelect"
:isMobile="isMobile" @showAnnouncement="showAnnouncement" @showFeedback="showFeedback" />
<div v-if="isMobile && !historyRecordRef?.isCollapsed" class="zhezhao" @click="expandHistory"></div>
<el-container v-if="!dataStore.isFeedback" class="main-container" :class="{
collapsed: !isMobile && historyRecordRef?.isCollapsed,
unCollapsed: !isMobile && !historyRecordRef?.isCollapsed,
}">
<!-- AI小财神头部 logo 次数 公告 --> <!-- AI小财神头部 logo 次数 公告 -->
<el-header class="homepage-head"> <el-header class="homepage-head">
<!-- logo --> <!-- logo -->
<div class="homepage-logo" v-if="isMobile"> <div class="homepage-logo" v-if="isMobile">
<img
class="expand"
@click="expandHistory"
src="https://d31zlh4on95l9h.cloudfront.net/images/37fe3d79a8a700f6c674c9f0e7af066b.png"
alt="icon"
/>
<img class="expand" @click="expandHistory"
src="https://d31zlh4on95l9h.cloudfront.net/images/37fe3d79a8a700f6c674c9f0e7af066b.png" alt="icon" />
<img :src="logo" alt="图片加载失败" class="logo1" /> <img :src="logo" alt="图片加载失败" class="logo1" />
<!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> --> <!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> -->
</div> </div>
<div class="homepage-right-group" v-if="isMobile"> <div class="homepage-right-group" v-if="isMobile">
<div class="count-badge" @click="showCount"> <div class="count-badge" @click="showCount">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
class="action-btn"
/>
<img src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
class="action-btn" />
<div class="count-number">{{ UserCount }}</div> <div class="count-number">{{ UserCount }}</div>
<div class="clickGetCount">点击获取Token</div> <div class="clickGetCount">点击获取Token</div>
</div> </div>
<div class="backToHomeBtn" @click="backToHome()"> <div class="backToHomeBtn" @click="backToHome()">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/9272c00f21a2724c3a76e375949ee1de.png"
alt="返回首页"
class="backImg"
/>
<img src="https://d31zlh4on95l9h.cloudfront.net/images/9272c00f21a2724c3a76e375949ee1de.png" alt="返回首页"
class="backImg" />
<div class="backContent">返回首页</div> <div class="backContent">返回首页</div>
</div> </div>
<!-- <img <!-- <img
@ -1381,22 +1390,14 @@ onUnmounted(() => {
<el-main class="homepage-body"> <el-main class="homepage-body">
<div class="main-wrapper"> <div class="main-wrapper">
<section class="tab-section"> <section class="tab-section">
<div
class="tab-container"
:class="{
pcTabContainer: !isMobile,
}"
>
<div class="tab-container" :class="{
pcTabContainer: !isMobile,
}">
<div class="tab-items-container"> <div class="tab-items-container">
<div
v-for="(tab, index) in tabs"
:key="tab.name"
@click="setActiveTab(tab.name, index)"
:class="[
'tab-item',
{ active: activeIndex === index && !isAnnouncementVisible },
]"
>
<div v-for="(tab, index) in tabs" :key="tab.name" @click="setActiveTab(tab.name, index)" :class="[
'tab-item',
{ active: activeIndex === index && !isAnnouncementVisible },
]">
<span>{{ tab.label }}</span> <span>{{ tab.label }}</span>
</div> </div>
</div> </div>
@ -1408,90 +1409,46 @@ onUnmounted(() => {
<div class="pc-clickGetCount">点击获取Token</div> <div class="pc-clickGetCount">点击获取Token</div>
</div> </div>
<div class="pc-backToHomeBtn" @click="backToHome()"> <div class="pc-backToHomeBtn" @click="backToHome()">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/9272c00f21a2724c3a76e375949ee1de.png"
alt="返回首页"
class="pc-backImg"
/>
<img src="https://d31zlh4on95l9h.cloudfront.net/images/9272c00f21a2724c3a76e375949ee1de.png"
alt="返回首页" class="pc-backImg" />
<div class="pc-backContent">返回首页</div> <div class="pc-backContent">返回首页</div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<!-- AIchat页面的独立滚动容器 --> <!-- AIchat页面的独立滚动容器 -->
<div
v-show="activeTab === 'AIchat'"
class="tab-content"
:class="{
pcTabContent: !isMobile,
}"
ref="tabContentAIchat"
>
<component
v-if="activeTab === 'AIchat'"
:is="activeComponent"
:messages="messages"
@updateMessage="updateMessage"
@sendMessage="sendMessage"
@ensureAIchat="ensureAIchat"
@enableInput="enableInput"
/>
<div v-show="activeTab === 'AIchat'" class="tab-content" :class="{
pcTabContent: !isMobile,
}" ref="tabContentAIchat">
<component v-if="activeTab === 'AIchat'" :is="activeComponent" :messages="messages"
@updateMessage="updateMessage" @sendMessage="sendMessage" @ensureAIchat="ensureAIchat"
@enableInput="enableInput" />
</div> </div>
<!-- AiEmotion页面的独立滚动容器 --> <!-- AiEmotion页面的独立滚动容器 -->
<div
v-show="activeTab === 'AiEmotion'"
class="tab-content"
:class="{
pcTabContent: !isMobile,
}"
ref="tabContentAiEmotion"
>
<component
v-if="activeTab === 'AiEmotion'"
:is="activeComponent"
:messages="messages"
@updateMessage="updateMessage"
@sendMessage="sendMessage"
@ensureAIchat="ensureAIchat"
@enableInput="enableInput"
@scrollToBottom="handleAiEmotionScrollToBottom"
@showCount="showCount"
ref="aiEmotionRef"
/>
<div v-show="activeTab === 'AiEmotion'" class="tab-content" :class="{
pcTabContent: !isMobile,
}" ref="tabContentAiEmotion">
<component v-if="activeTab === 'AiEmotion'" :is="activeComponent" :messages="messages"
@updateMessage="updateMessage" @sendMessage="sendMessage" @ensureAIchat="ensureAIchat"
@enableInput="enableInput" @scrollToBottom="handleAiEmotionScrollToBottom" @showCount="showCount"
ref="aiEmotionRef" />
</div> </div>
<!-- deepNine页面的独立滚动容器 --> <!-- deepNine页面的独立滚动容器 -->
<div
v-show="activeTab === 'deepNine'"
class="tab-content"
:class="{
pcTabContent: !isMobile,
}"
ref="tabContentDeepNine"
>
<component
v-if="activeTab === 'deepNine'"
:is="activeComponent"
:messages="messages"
@updateMessage="updateMessage"
@sendMessage="sendMessage"
@ensureAIchat="ensureAIchat"
@enableInput="enableInput"
@scrollToBottom="handleDeepNineScrollToBottom"
@showCount="showCount"
ref="deepNineRef"
/>
<div v-show="activeTab === 'deepNine'" class="tab-content" :class="{
pcTabContent: !isMobile,
}" ref="tabContentDeepNine">
<component v-if="activeTab === 'deepNine'" :is="activeComponent" :messages="messages"
@updateMessage="updateMessage" @sendMessage="sendMessage" @ensureAIchat="ensureAIchat"
@enableInput="enableInput" @scrollToBottom="handleDeepNineScrollToBottom" @showCount="showCount"
ref="deepNineRef" />
</div> </div>
</div> </div>
</el-main> </el-main>
<!-- 尾部 问题输入框 深度思考 多语言 语音播报 --> <!-- 尾部 问题输入框 深度思考 多语言 语音播报 -->
<el-footer
class="homepage-footer"
:class="{
pcFooter: !isMobile,
}"
id="input"
>
<el-footer class="homepage-footer" :class="{
pcFooter: !isMobile,
}" id="input">
<!-- 第一行按钮 --> <!-- 第一行按钮 -->
<div class="footer-first-line"> <div class="footer-first-line">
<div class="left-group"> <div class="left-group">
@ -1501,32 +1458,16 @@ onUnmounted(() => {
<!-- PC端按钮 --> <!-- PC端按钮 -->
<template v-if="!isMobile"> <template v-if="!isMobile">
<!-- 夺宝奇兵大模型按钮 --> <!-- 夺宝奇兵大模型按钮 -->
<img
:src="activeTab === 'AIchat' ? dbqbButton01 : dbqbButton02"
@click="setActiveTab('AIchat', 0)"
class="action-btn model-btn"
alt="夺宝奇兵大模型"
/>
<img :src="activeTab === 'AIchat' ? dbqbButton01 : dbqbButton02" @click="setActiveTab('AIchat', 0)"
class="action-btn model-btn" alt="夺宝奇兵大模型" />
<!-- AI情绪大模型按钮 --> <!-- AI情绪大模型按钮 -->
<img
:src="
activeTab === 'AiEmotion' ? emotionButton01 : emotionButton02
"
@click="setActiveTab('AiEmotion', 1)"
class="action-btn model-btn"
alt="AI情绪大模型"
/>
<img :src="activeTab === 'AiEmotion' ? emotionButton01 : emotionButton02
" @click="setActiveTab('AiEmotion', 1)" class="action-btn model-btn" alt="AI情绪大模型" />
<!-- 深度九大模型按钮 --> <!-- 深度九大模型按钮 -->
<img
:src="
activeTab === 'deepNine' ? emotionButton01 : emotionButton02
"
@click="setActiveTab('deepNine', 2)"
class="action-btn model-btn"
alt="深度九大模型"
/>
<img :src="activeTab === 'deepNine' ? emotionButton01 : emotionButton02
" @click="setActiveTab('deepNine', 2)" class="action-btn model-btn" alt="深度九大模型" />
</template> </template>
<!-- 手机端下拉选择 --> <!-- 手机端下拉选择 -->
<template v-else> <template v-else>
<el-select v-model="activeTabMobile" class="mobile-model-select" @change="handleMobileTabChange"> <el-select v-model="activeTabMobile" class="mobile-model-select" @change="handleMobileTabChange">
@ -1551,75 +1492,45 @@ onUnmounted(() => {
<div class="footer-second-line"> <div class="footer-second-line">
<!-- <img :src="msgBtn" class="msg-icon" /> --> <!-- <img :src="msgBtn" class="msg-icon" /> -->
<div class="input-container"> <div class="input-container">
<el-input
type="textarea"
v-model="message"
@focus="onFocus"
@blur="onBlur"
:autosize="{ minRows: 1, maxRows: 4 }"
class="msg-input"
@keydown.enter.exact.prevent="
<el-input type="textarea" v-model="message" @focus="onFocus" @blur="onBlur"
:autosize="{ minRows: 1, maxRows: 4 }" class="msg-input" @keydown.enter.exact.prevent="
isLoading || isInputDisabled ? null : sendMessage() isLoading || isInputDisabled ? null : sendMessage()
"
:disabled="isInputDisabled"
resize="none"
:class="{ input: !message && !inputing }"
@compositionstart="inputing = true"
@compositionend="inputing = false"
>
" :disabled="isInputDisabled" resize="none" :class="{ input: !message && !inputing }"
@compositionstart="inputing = true" @compositionend="inputing = false">
</el-input> </el-input>
<img
:src="
isInputDisabled
? 'https://d31zlh4on95l9h.cloudfront.net/images/aa192bcbc1682c97e1bc6fb422f2afff.png'
: 'https://d31zlh4on95l9h.cloudfront.net/images/e6ec2ae238ced85b74e0912e988f243e.png'
"
@click="sendMessage"
class="action-btn send-btn-inner"
:style="{
<img :src="isInputDisabled
? 'https://d31zlh4on95l9h.cloudfront.net/images/aa192bcbc1682c97e1bc6fb422f2afff.png'
: 'https://d31zlh4on95l9h.cloudfront.net/images/e6ec2ae238ced85b74e0912e988f243e.png'
" @click="sendMessage" class="action-btn send-btn-inner" :style="{
opacity: isInputDisabled ? 0.5 : 1, opacity: isInputDisabled ? 0.5 : 1,
cursor: isInputDisabled ? 'not-allowed' : 'pointer', cursor: isInputDisabled ? 'not-allowed' : 'pointer',
}"
/>
}" />
</div> </div>
</div> </div>
</el-footer> </el-footer>
</el-container> </el-container>
<el-container
v-else
class="main-container"
:class="{
collapsed: historyRecordRef?.isCollapsed && !isMobile,
unCollapsed: !historyRecordRef?.isCollapsed && !isMobile,
}"
>
<el-container v-else class="main-container" :class="{
collapsed: historyRecordRef?.isCollapsed && !isMobile,
unCollapsed: !historyRecordRef?.isCollapsed && !isMobile,
}">
<el-header class="homepage-head"> <el-header class="homepage-head">
<!-- logo --> <!-- logo -->
<div class="homepage-logo"> <div class="homepage-logo">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/4c91fce359a1c184772857594c38e3b4.png"
alt="返回按钮"
class="backToHomeImg"
@click="feedbackBack"
/>
<img src="https://d31zlh4on95l9h.cloudfront.net/images/4c91fce359a1c184772857594c38e3b4.png" alt="返回按钮"
class="backToHomeImg" @click="feedbackBack" />
<!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> --> <!-- <img :src="madeInHL" alt="图片加载失败" class="logo2" /> -->
</div> </div>
<div class="homepage-right-group"> <div class="homepage-right-group">
<div class="count-badge" @click="showCount"> <div class="count-badge" @click="showCount">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
class="action-btn"
/>
<img src="https://d31zlh4on95l9h.cloudfront.net/images/74e20c65c9ef2526477c63ad68698a50.png"
class="action-btn" />
<div class="count-number">{{ UserCount }}</div> <div class="count-number">{{ UserCount }}</div>
<div class="clickGetCount">点击获取Token</div> <div class="clickGetCount">点击获取Token</div>
</div> </div>
<div class="backToHomeBtn" @click="backToHome()"> <div class="backToHomeBtn" @click="backToHome()">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/9272c00f21a2724c3a76e375949ee1de.png"
alt="返回首页"
class="backImg"
/>
<img src="https://d31zlh4on95l9h.cloudfront.net/images/9272c00f21a2724c3a76e375949ee1de.png" alt="返回首页"
class="backImg" />
<div class="backContent">返回首页</div> <div class="backContent">返回首页</div>
</div> </div>
<!-- <img <!-- <img
@ -1647,12 +1558,7 @@ onUnmounted(() => {
<div class="changeMsg"> <div class="changeMsg">
<div class="changeInfo"> <div class="changeInfo">
<div class="changeImg"> <div class="changeImg">
<img
:src="userInfo.img"
alt="头像"
class="changeImgClass"
@error="handleImageError"
/>
<img :src="userInfo.img" alt="头像" class="changeImgClass" @error="handleImageError" />
</div> </div>
<div class="changeContent"> <div class="changeContent">
<div class="changeUsername">{{ userInfo.nickname }}</div> <div class="changeUsername">{{ userInfo.nickname }}</div>
@ -1667,22 +1573,13 @@ onUnmounted(() => {
<div class="changeLevel"> <div class="changeLevel">
<div class="changeLevelTitle">兑换Token</div> <div class="changeLevelTitle">兑换Token</div>
<div class="changeLevelContent"> <div class="changeLevelContent">
<div
class="changeLevelItems"
v-for="item in changeLevelList"
:key="item"
:class="{
changeLevelItemsActive: item.position == activeLevel.position,
}"
@click="chooseLevel(item)"
>
<div class="changeLevelItems" v-for="item in changeLevelList" :key="item" :class="{
changeLevelItemsActive: item.position == activeLevel.position,
}" @click="chooseLevel(item)">
<div class="changeLevelItem"> <div class="changeLevelItem">
<div class="changeLevelItemToken"> <div class="changeLevelItemToken">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/403ef762dd2f335df3b0c9e3fe488375.png"
alt="token"
class="changeLevelItemTokenImg"
/>
<img src="https://d31zlh4on95l9h.cloudfront.net/images/403ef762dd2f335df3b0c9e3fe488375.png" alt="token"
class="changeLevelItemTokenImg" />
{{ item.calculatedPosition }} {{ item.calculatedPosition }}
</div> </div>
<div class="changeLevelItemToken">{{ item.position }} 金币</div> <div class="changeLevelItemToken">{{ item.position }} 金币</div>
@ -1704,12 +1601,7 @@ onUnmounted(() => {
<div class="changeMsg"> <div class="changeMsg">
<div class="changeInfo"> <div class="changeInfo">
<div class="changeImg"> <div class="changeImg">
<img
:src="userInfo.img"
alt="头像"
class="changeImgClass"
@error="handleImageError"
/>
<img :src="userInfo.img" alt="头像" class="changeImgClass" @error="handleImageError" />
</div> </div>
<div class="changeContent"> <div class="changeContent">
<div class="changeJwcode">精网号{{ userInfo.jwcode }}</div> <div class="changeJwcode">精网号{{ userInfo.jwcode }}</div>
@ -1726,22 +1618,13 @@ onUnmounted(() => {
</div> </div>
<div class="changeLevelContent"> <div class="changeLevelContent">
<div
class="changeLevelItems"
v-for="item in changeLevelList"
:key="item"
:class="{
changeLevelItemsActive: item.position == activeLevel.position,
}"
@click="chooseLevel(item)"
>
<div class="changeLevelItems" v-for="item in changeLevelList" :key="item" :class="{
changeLevelItemsActive: item.position == activeLevel.position,
}" @click="chooseLevel(item)">
<div class="changeLevelItem"> <div class="changeLevelItem">
<div class="changeLevelItemToken"> <div class="changeLevelItemToken">
<img
src="https://d31zlh4on95l9h.cloudfront.net/images/403ef762dd2f335df3b0c9e3fe488375.png"
alt="token"
class="changeLevelItemTokenImg"
/>
<img src="https://d31zlh4on95l9h.cloudfront.net/images/403ef762dd2f335df3b0c9e3fe488375.png" alt="token"
class="changeLevelItemTokenImg" />
{{ item.calculatedPosition }} {{ item.calculatedPosition }}
</div> </div>
<div class="changeLevelItemToken">{{ item.position }} 金币</div> <div class="changeLevelItemToken">{{ item.position }} 金币</div>
@ -1758,11 +1641,7 @@ onUnmounted(() => {
<div class="changeBtn" @click="changeToken">立即兑换</div> <div class="changeBtn" @click="changeToken">立即兑换</div>
</el-dialog> </el-dialog>
<el-dialog
v-model="rechargeDialogVisible"
:width="isMobile ? '60%' : '30%'"
:show-close="false"
>
<el-dialog v-model="rechargeDialogVisible" :width="isMobile ? '60%' : '30%'" :show-close="false">
<div class="rechargeDialogTitle">温馨提示</div> <div class="rechargeDialogTitle">温馨提示</div>
<div class="rechargeDialogContent"> <div class="rechargeDialogContent">
尊敬的用户您好您当前的金币余额不足无法进行兑换可充值金币后进行兑换点击下方的前往充值可进行充值 尊敬的用户您好您当前的金币余额不足无法进行兑换可充值金币后进行兑换点击下方的前往充值可进行充值
@ -1770,21 +1649,13 @@ onUnmounted(() => {
<div class="rechargeDialogBtnGroup"> <div class="rechargeDialogBtnGroup">
<div class="recharge" @click="goRecharge">前往充值</div> <div class="recharge" @click="goRecharge">前往充值</div>
<div
class="rechargeDialogCancel"
@click="rechargeDialogVisible = false"
>
<div class="rechargeDialogCancel" @click="rechargeDialogVisible = false">
取消 取消
</div> </div>
</div> </div>
</el-dialog> </el-dialog>
<el-dialog
v-model="confirmDialogVisible"
:width="isMobile ? '60%' : '30%'"
:show-close="false"
align-center="true"
>
<el-dialog v-model="confirmDialogVisible" :width="isMobile ? '60%' : '30%'" :show-close="false" align-center="true">
<div class="confirmDialogTitle">兑换</div> <div class="confirmDialogTitle">兑换</div>
<div class="confirmDialogContent"> <div class="confirmDialogContent">
尊敬的用户您好您确认要花费{{ activeLevel.position }}金币兑换{{ 尊敬的用户您好您确认要花费{{ activeLevel.position }}金币兑换{{
@ -1799,45 +1670,30 @@ onUnmounted(() => {
</div> </div>
</el-dialog> </el-dialog>
<el-dialog
v-model="changeSuccessDialogVisible"
:width="isMobile ? '60%' : '30%'"
:show-close="false"
class="changeSuccessDialog"
align-center
center
>
<el-dialog v-model="changeSuccessDialogVisible" :width="isMobile ? '60%' : '30%'" :show-close="false"
class="changeSuccessDialog" align-center center>
<div class="changeSuccessDialogTitle"> <div class="changeSuccessDialogTitle">
<img
v-if="!isMobile"
src="https://d31zlh4on95l9h.cloudfront.net/images/84edd341b2ddec464fc4475254f7a309.png"
style="scale: 0.7"
alt="token图标"
/>
<img v-if="!isMobile" src="https://d31zlh4on95l9h.cloudfront.net/images/84edd341b2ddec464fc4475254f7a309.png"
style="scale: 0.7" alt="token图标" />
兑换成功 兑换成功
</div> </div>
<div class="changeSuccessDialogContent"> <div class="changeSuccessDialogContent">
尊敬的用户恭喜您成功兑换{{ activeLevel.calculatedPosition }} Token 尊敬的用户恭喜您成功兑换{{ activeLevel.calculatedPosition }} Token
</div> </div>
<div class="changeSuccessDialogFooter"> <div class="changeSuccessDialogFooter">
<button
class="confirmButton"
@click="changeSuccessDialogVisible = false"
>
<button class="confirmButton" @click="changeSuccessDialogVisible = false">
确定 确定
</button> </button>
</div> </div>
</el-dialog> </el-dialog>
<!-- Token规则提示框 --> <!-- Token规则提示框 -->
<div
v-if="tokenRuleDialogVisible"
class="tokenRuleDialog"
@click="closeTokenRuleDialog"
>
<div v-if="tokenRuleDialogVisible" class="tokenRuleDialog" @click="closeTokenRuleDialog">
<div class="tokenRuleDialogContent" @click.stop> <div class="tokenRuleDialogContent" @click.stop>
<div class="tokenRuleDialogClose" @click="closeTokenRuleDialog"> <div class="tokenRuleDialogClose" @click="closeTokenRuleDialog">
<el-icon><Close /></el-icon>
<el-icon>
<Close />
</el-icon>
</div> </div>
<div class="tokenRuleDialogTitle">Token规则</div> <div class="tokenRuleDialogTitle">Token规则</div>
@ -1898,7 +1754,8 @@ onUnmounted(() => {
} }
.pcTabContainer { .pcTabContainer {
padding: 0 20px; /* 添加内边距,避免内容贴边 */
padding: 0 20px;
/* 添加内边距,避免内容贴边 */
} }
.tab-item { .tab-item {
@ -1950,10 +1807,11 @@ onUnmounted(() => {
.tab-container { .tab-container {
justify-content: center; justify-content: center;
} }
.tab-items-container { .tab-items-container {
justify-content: center; justify-content: center;
gap: 0px; /* 移动端使用更小的间距 */
gap: 0px;
/* 移动端使用更小的间距 */
} }
.tab-item { .tab-item {
@ -2028,9 +1886,12 @@ body {
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
} }
.main-container.unCollapsed { .main-container.unCollapsed {
margin-left: 300px; /* 为历史记录组件留出空间 */
margin-left: 300px;
/* 为历史记录组件留出空间 */
} }
/* 当历史记录组件折叠时调整主容器边距 */ /* 当历史记录组件折叠时调整主容器边距 */
.main-container.collapsed { .main-container.collapsed {
margin-left: 40px; margin-left: 40px;
@ -2222,10 +2083,12 @@ body {
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
} }
.pc-backImg { .pc-backImg {
width: 100%; width: 100%;
height: auto; height: auto;
} }
.pc-backContent { .pc-backContent {
width: 100%; width: 100%;
text-align: center; text-align: center;
@ -2587,6 +2450,7 @@ body {
margin-bottom: 15px; margin-bottom: 15px;
align-items: center; align-items: center;
} }
.changePay { .changePay {
color: #4e86fe; color: #4e86fe;
margin: 0px 5px; margin: 0px 5px;
@ -2619,6 +2483,7 @@ body {
align-items: center; align-items: center;
letter-spacing: 10px; letter-spacing: 10px;
} }
.rechargeDialogContent { .rechargeDialogContent {
padding: 20px; padding: 20px;
font-size: 1.2rem; font-size: 1.2rem;
@ -2668,6 +2533,7 @@ body {
align-items: center; align-items: center;
letter-spacing: 10px; letter-spacing: 10px;
} }
.confirmDialogContent { .confirmDialogContent {
padding: 20px; padding: 20px;
font-size: 1.2rem; font-size: 1.2rem;
@ -2823,6 +2689,7 @@ body {
.tokenRuleDialog { .tokenRuleDialog {
bottom: 20%; bottom: 20%;
} }
.tokenRuleDialogContent { .tokenRuleDialogContent {
width: 80vw; width: 80vw;
padding: 15px 20px; padding: 15px 20px;
@ -2919,6 +2786,7 @@ body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.changeRule { .changeRule {
margin-left: 10px; margin-left: 10px;
width: 0%; width: 0%;
@ -2964,6 +2832,7 @@ body {
.rechargeDialogTitle { .rechargeDialogTitle {
font-size: 1.3rem; font-size: 1.3rem;
} }
.rechargeDialogContent { .rechargeDialogContent {
padding: 10px 0px; padding: 10px 0px;
font-size: 0.8rem; font-size: 0.8rem;
@ -2984,6 +2853,7 @@ body {
.confirmDialogTitle { .confirmDialogTitle {
font-size: 1.3rem; font-size: 1.3rem;
} }
.confirmDialogContent { .confirmDialogContent {
padding: 10px 0px; padding: 10px 0px;
font-size: 0.8rem; font-size: 0.8rem;

Loading…
Cancel
Save