Browse Source

引入AI探牛,夺宝利剑,音频继续播放,音频速度1.2,接入查询股票接口

hxl
no99 4 weeks ago
parent
commit
3326b448eb
  1. 1
      README.md
  2. 10
      package-lock.json
  3. 1
      package.json
  4. 322
      src/api/AIxiaocaishen.js
  5. BIN
      src/assets/img/Feedback/back.png
  6. BIN
      src/assets/img/Feedback/purpleDot.png
  7. 4
      src/store/audio.js
  8. 3554
      src/views/AIchat.vue
  9. 40
      src/views/Announcement.vue
  10. 141
      src/views/Feedback.vue
  11. 14
      src/views/homePage.vue
  12. 50
      vite.config.js

1
README.md

@ -18,3 +18,4 @@ npm install html-to-text
npm install echarts
npm install lodash 安装 lodash 组件,解决数据处理问题
npm install vue-device-detect 安装 vue-device-detect 组件,解决移动端适配问题
npm install moment 安装 moment 组件,解决时间处理问题

10
package-lock.json

@ -23,6 +23,7 @@
"lodash": "^4.17.21",
"marked": "^15.0.7",
"mitt": "^3.0.1",
"moment": "^2.30.1",
"pinia": "^2.3.1",
"pinia-plugin-persistedstate": "^1.0.3",
"reset-css": "^5.0.2",
@ -5233,6 +5234,15 @@
"random": "bin/random"
}
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",

1
package.json

@ -30,6 +30,7 @@
"lodash": "^4.17.21",
"marked": "^15.0.7",
"mitt": "^3.0.1",
"moment": "^2.30.1",
"pinia": "^2.3.1",
"pinia-plugin-persistedstate": "^1.0.3",
"reset-css": "^5.0.2",

322
src/api/AIxiaocaishen.js

@ -1,177 +1,213 @@
import request from '../utils/request'
import request from "../utils/request";
const APIurl = import.meta.env.VITE_APP_API_BASE_URL
const MJAPIurl = import.meta.env.VITE_APP_MJ_API_BASE_URL
const APIurl = import.meta.env.VITE_APP_API_BASE_URL;
const MJAPIurl = import.meta.env.VITE_APP_MJ_API_BASE_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'
}
})
}
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'
}
})
}
// 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'
}
})
}
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'
}
})
}
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'
}
})
}
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'
})
}
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"
})
})
}
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"
})
})
}
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({
url: `${APIurl}/api/ai_god/userUsageInfo`,
method: 'POST',
data: new URLSearchParams(params),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
}
return request({
url: `${APIurl}/api/ai_god/userUsageInfo`,
method: "POST",
data: new URLSearchParams(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'
}
})
}
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'
}
})
}
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": "7484443705572556826",
"parameters": params,
}),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer pat_TJbuxUiZdl6U3oiiSeceQnHg5XdaZsWpxc6oIozc2Auhd9YuyBvFslJJQUFUym1F'
}
})
}
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_DLMr7u1d6pmgC2demIYksrOm0r2k2w9XDxKmHvBvOQ5Lw5AYrByJ2IZpdwoJPYGi",
},
});
};
// 获取回复接口流式
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_TJbuxUiZdl6U3oiiSeceQnHg5XdaZsWpxc6oIozc2Auhd9YuyBvFslJJQUFUym1F'
}
}
)
}
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_DLMr7u1d6pmgC2demIYksrOm0r2k2w9XDxKmHvBvOQ5Lw5AYrByJ2IZpdwoJPYGi",
},
});
};
// 接受音频
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_TJbuxUiZdl6U3oiiSeceQnHg5XdaZsWpxc6oIozc2Auhd9YuyBvFslJJQUFUym1F',
'Content-Type': 'application/json'
}
})
}
return fetch("https://api.coze.cn/v1/workflow/run", {
method: "POST",
body: JSON.stringify({
workflow_id: "7481639836165275702",
parameters: params,
}),
headers: {
Authorization:
"Bearer pat_DLMr7u1d6pmgC2demIYksrOm0r2k2w9XDxKmHvBvOQ5Lw5AYrByJ2IZpdwoJPYGi",
"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: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};

BIN
src/assets/img/Feedback/back.png

After

Width: 200  |  Height: 200  |  Size: 7.4 KiB

BIN
src/assets/img/Feedback/purpleDot.png

After

Width: 32  |  Height: 32  |  Size: 717 B

4
src/store/audio.js

@ -7,7 +7,9 @@ export const useAudioStore = defineStore('audio', {
isVoiceEnabled: true, // 新增声音开关状态
playbackPosition: 0, // 新增播放位置存储
lastVoiceState: null,
ttsUrl:''
ttsUrl:'',
isNewInstance: false, // 新增是否是新实例的标志
nowSound:''
}),
actions: {
// 设置音频实例

3554
src/views/AIchat.vue
File diff suppressed because it is too large
View File

40
src/views/Announcement.vue

@ -1,6 +1,17 @@
<script setup>
import { ref, onMounted } from "vue";
import { getAnnouncementAPI, qsArpAamClickAPI } from "../api/AIxiaocaishen";
import { getAnnouncementAPI, qsArpAamClickAPI, getMarketAndCodeAPI } from "../api/AIxiaocaishen";
const marketList = ref({
"usa": "美股",
"cn": "A股",
"hk": "港股",
"sg": "新加坡股",
"my": "马股",
"th": "泰股",
"vi": "越南股",
"can": "加拿大股"
})
const codeList = ref([
{ market: '美股', code: ['Tesla', 'NVDA', 'APPL'] },
@ -13,6 +24,29 @@ const codeList = ref([
{ market: '加拿大股', code: [] },
])
const getMarketAndCode = async () => {
const result = await getMarketAndCodeAPI()
console.log(result.data, "MarketAndCode");
for (let i = 0; i < result.data.length; i++) {
const item = result.data[i];
const market = marketList.value[item.market];
const codeLists=item.code.split(',')
console.log(codeLists, "codeLists",market,'market');
const targetMarket=codeList.value.find(item=>item.market==market)
if(targetMarket){
targetMarket.code=codeLists
console.log(targetMarket, "targetMarket");
}else{
console.log("未找到对应的市场")
}
}
}
const announcementVideo = ref({});
const getAnnouncement = async () => {
const result = await getAnnouncementAPI()
@ -46,6 +80,7 @@ const clickCode = (code) => {
onMounted(() => {
getAnnouncement()
getMarketAndCode()
})
</script>
@ -136,8 +171,7 @@ onMounted(() => {
color: #4591E7;
}
.code{
.code {
cursor: pointer;
}
</style>

141
src/views/Feedback.vue

@ -1,7 +1,7 @@
<script setup>
import { ref, computed, onMounted, watch, nextTick, onUnmounted } from "vue";
import { useDataStore } from '@/store/dataList.js'
import { addFeedbackAPI, getFeedbackAPI } from "../api/AIxiaocaishen"
import feedback from "../assets/img/Feedback/feedback.png";
import feedbackImg from "../assets/img/Feedback/feedbackImg.png";
import feedbackSuccess from "../assets/img/Feedback/feedbackSuccess.png";
@ -10,6 +10,10 @@ import border from "../assets/img/Feedback/border.png";
import success from "../assets/img/Feedback/success.png";
import failure from "../assets/img/Feedback/failure.png";
import save from "../assets/img/Feedback/save.png";
import back from "../assets/img/Feedback/back.png";
import purpleDot from "../assets/img/Feedback/purpleDot.png";
import moment from 'moment';
const dataStore = useDataStore()
@ -29,6 +33,31 @@ const feedbackSubmit = async () => {
submitFailureContent.value = '请输入反馈内容或上传图片';
} else {
try {
let img1 = ''
let img2 = ''
let img3 = '';
if (feedbackFileList.value[0]) {
img1 = feedbackFileList.value[0].url;
}
if (feedbackFileList.value[1]) {
img2 = feedbackFileList.value[1].url;
}
if (feedbackFileList.value[2]) {
img3 = feedbackFileList.value[2].url;
}
console.log(img1, img2, img3);
const result = await addFeedbackAPI({
token: localStorage.getItem('localToken'),
content: feedbackContent.value,
image1: img1,
image2: img2,
image3: img3,
})
console.log(result)
feedbackHistory();
submitSuccessDialogVisible.value = true;
} catch (error) {
@ -36,7 +65,29 @@ const feedbackSubmit = async () => {
submitFailureContent.value = '反馈提交异常(错误代码:' + error.response.status + '),建议尝试更换网络环境后重新提交。';
}
}
}
const feedbackHistoryList = ref([])
const feedbackHistory = async () => {
try {
const result = await getFeedbackAPI({
token: localStorage.getItem('localToken'),
})
console.log(result)
if (result.data.length > 0) {
isHistoryFeedback.value = true;
feedbackHistoryList.value = result.data;
} else {
isHistoryFeedback.value = false;
}
} catch (error) {
console.log(error)
}
}
const submitSuccessConfirm = () => {
@ -132,7 +183,10 @@ const feedbackBackCancel = () => {
dataStore.isFeedback = false;
}
onMounted(() => {
feedbackHistory()
if (localStorage.getItem('feedbackContent')) {
feedbackContent.value = localStorage.getItem('feedbackContent')
} else {
@ -152,9 +206,7 @@ onMounted(() => {
<el-container>
<div>
<div @click="feedbackBack">
<el-icon style="font-size: 50px;">
<Back />
</el-icon>
<img :src="back" alt="返回按钮" class="backImg">
</div>
</div>
<el-scrollbar>
@ -201,7 +253,32 @@ onMounted(() => {
历史反馈内容
</div>
<div v-if="isHistoryFeedback">
有内容
<div v-for="(item, index) in feedbackHistoryList" :key="index" class="feedbackHistory">
<div class="feedbackHistoryItem">
<div class="feedbackHistoryTitle">
<img :src="purpleDot" alt="紫点" class="purpleDot">
{{ moment(item.created_at).format('YYYY-MM-DD HH:mm') }}
<div class="feedbackSuccess">
<div class="feedbackSuccessWord">
反馈成功
</div>
<img class="feedbackSuccessImg" :src="feedbackSuccess" alt="成功">
</div>
</div>
<div class="feedbackHistoryContent">
{{ item.content }}
</div>
<div class="feedbackHistoryImg">
<el-image v-if="item.image1" :src="item.image1" alt="图片错误"
class="feedbackHistoryImgItem" :preview-src-list="[item.image1]" />
<el-image v-if="item.image2" :src="item.image2" alt="图片错误"
class="feedbackHistoryImgItem" :preview-src-list="[item.image2]" />
<el-image v-if="item.image3" :src="item.image3" alt="图片错误"
class="feedbackHistoryImgItem" :preview-src-list="[item.image3]" />
</div>
</div>
</div>
</div>
<div v-else>
<div class="noFeedback">
@ -280,6 +357,13 @@ onMounted(() => {
</template>
<style scoped>
.backImg{
width: 40px;
height: 40px;
margin-left: 10px;
}
.el-container {
display: flex;
flex-direction: column;
@ -412,7 +496,7 @@ onMounted(() => {
border: none;
}
.nosave{
.nosave {
color: #816CF6;
background: white;
border: none;
@ -467,6 +551,51 @@ onMounted(() => {
font-weight: bold;
color: #ff4646
}
.purpleDot {
margin: 0px 5px 0px 0px;
width: 20px;
height: 20px;
}
.feedbackHistoryTitle {
display: flex;
}
.feedbackSuccess {
margin-left: auto;
display: flex;
}
.feedbackSuccessWord {
padding: 3px 0 0 0;
color: #4221FF;
font-weight: bold;
}
.feedbackSuccessImg {
width: 30px;
height: auto;
margin: 0 5px;
}
.feedbackHistoryContent {
min-height: 50px;
margin: 0 0 0 25px;
font-weight: bold;
}
.feedbackHistoryImg {
display: flex;
margin: 0px 0px 0px 20px;
}
.feedbackHistoryImgItem {
width: 100px;
height: auto;
margin: 5px 10px;
}
</style>
<style>
.uploadImg .el-upload {

14
src/views/homePage.vue

@ -119,10 +119,10 @@ const updateMessage = (title) => {
// console.log("updateMessage :", title);
};
const sendMessage = async () => {
// if (localStorage.getItem('localToken') == null||localStorage.getItem('localToken') == '') {
// ElMessage.error('');
// return ;
// }
if (localStorage.getItem('localToken') == null||localStorage.getItem('localToken') == '') {
ElMessage.error('请先登录');
return ;
}
isScrolling.value = false;
// ensureAIchat AIchat
ensureAIchat();
@ -332,14 +332,14 @@ const goToRecharge = () => {
console.log(isMobile ? '手机' : '电脑')
const url = encodeURI("http://192.168.1.103:3000/homePage")
const url = encodeURI("http://39.101.133.168:8857/aixiaocaishen/homePage")
console.log(url, 'url')
const platform = isMobile ? 2 : 1
const token = localStorage.getItem('localToken')
const rechargeUrl = 'http://39.101.133.168:8919/payment/recharge/index?' + 'url=' + url + '&platform=' + platform + '&token=' + token
console.log(rechargeUrl, 'rechargeUrl')
window.location.href=rechargeUrl
window.location.href = rechargeUrl
}
@ -498,7 +498,7 @@ onMounted(async () => {
</section>
<div class="tab-content" ref="tabContent">
<component :is="activeComponent" :messages="messages" @updateMessage="updateMessage"
@sendMessage="sendMessage" @ensureAIchat="ensureAIchat"/>
@sendMessage="sendMessage" @ensureAIchat="ensureAIchat" />
</div>
</div>

50
vite.config.js

@ -1,38 +1,38 @@
import { defineConfig, loadEnv } from 'vite'
import pkg from './package.json' // 新增包信息导入
import dayjs from 'dayjs' // 新增时间库导入
import { fileURLToPath, URL } from 'url' // 新增路径处理模块
import { wrapperEnv } from './build/utils'
import { createVitePlugins } from './build/vite/plugin'
import { createProxy } from './build/vite/proxy'
import { createBuild } from './build/vite/build'
import { defineConfig, loadEnv } from "vite";
import pkg from "./package.json"; // 新增包信息导入
import dayjs from "dayjs"; // 新增时间库导入
import { fileURLToPath, URL } from "url"; // 新增路径处理模块
import { wrapperEnv } from "./build/utils";
import { createVitePlugins } from "./build/vite/plugin";
import { createProxy } from "./build/vite/proxy";
import { createBuild } from "./build/vite/build";
const { dependencies, devDependencies, name, version } = pkg
const { dependencies, devDependencies, name, version } = pkg;
// 应用信息
const __APP_INFO__ = {
pkg: { dependencies, devDependencies, name, version },
lastBuildTime: dayjs().format('YYYY-MM-DD HH:mm:ss')
}
lastBuildTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
};
// https://vite.dev/config/
export default defineConfig(({ command, mode }) => {
// console.log('command', command)
const root = process.cwd() // 当前工作目录
const isBuild = command === 'build' // 是否是构建 serve
const env = loadEnv(mode, root) // 加载env环境
const root = process.cwd(); // 当前工作目录
const isBuild = command === "build"; // 是否是构建 serve
const env = loadEnv(mode, root); // 加载env环境
// The boolean type read by loadEnv is a string. This function can be converted to boolean type
const viteEnv = wrapperEnv(env)
const viteEnv = wrapperEnv(env);
// console.log('viteEnv', viteEnv)
const { VITE_PUBLIC_PATH, VITE_OUTPUT_DIR } = viteEnv
const { VITE_PUBLIC_PATH, VITE_OUTPUT_DIR } = viteEnv;
return {
base: VITE_PUBLIC_PATH,
root,
plugins: createVitePlugins(viteEnv, isBuild),
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
css: {
preprocessorOptions: {
@ -41,17 +41,17 @@ export default defineConfig(({ command, mode }) => {
additionalData: `
@import "@/styles/mixin.scss";
@import "@/styles/variables.scss";
`
}
}
`,
},
},
},
server: {
host: true,
proxy: createProxy()
proxy: createProxy(),
},
build: createBuild(viteEnv),
define: {
__APP_INFO__: JSON.stringify(__APP_INFO__)
__APP_INFO__: JSON.stringify(__APP_INFO__),
}
}
})
};
});
Loading…
Cancel
Save