diff --git a/README.md b/README.md index 40e1f82..b015e02 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,4 @@ npm install @coze/api npm install html-to-text npm install echarts npm install lodash 安装 lodash 组件,解决数据处理问题 +npm install vue-device-detect 安装 vue-device-detect 组件,解决移动端适配问题 diff --git a/package-lock.json b/package-lock.json index 0f7efbe..15ec7ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "reset-css": "^5.0.2", "vconsole": "^3.15.1", "vue": "^3.2.26", + "vue-device-detect": "^1.0.3", "vue-i18n": "^10.0.3", "vue-request": "^1.2.3", "vue-router": "^4.0.12" @@ -6692,6 +6693,32 @@ "node": ">=4.2.0" } }, + "node_modules/ua-parser-js": { + "version": "1.0.40", + "resolved": "https://mirrors.huaweicloud.com/repository/npm/ua-parser-js/-/ua-parser-js-1.0.40.tgz", + "integrity": "sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/ufo": { "version": "1.5.4", "resolved": "https://mirrors.huaweicloud.com/repository/npm/ufo/-/ufo-1.5.4.tgz", @@ -7687,6 +7714,19 @@ } } }, + "node_modules/vue-device-detect": { + "version": "1.0.3", + "resolved": "https://mirrors.huaweicloud.com/repository/npm/vue-device-detect/-/vue-device-detect-1.0.3.tgz", + "integrity": "sha512-3DzdW88bHReUS9hUaqXvUXFmpa9QsZ0Dmo8EjvteBU1OoaDP9jwEj+LvCXjYSzGBC1fEylTHoOXwvqj4jwBHOQ==", + "license": "ISC", + "dependencies": { + "ua-parser-js": "^1.0.2", + "vue-device-detect": "^1.0.0" + }, + "peerDependencies": { + "vue": "^3.2.32" + } + }, "node_modules/vue-eslint-parser": { "version": "8.3.0", "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", diff --git a/package.json b/package.json index d59fb47..3a451c3 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "reset-css": "^5.0.2", "vconsole": "^3.15.1", "vue": "^3.2.26", + "vue-device-detect": "^1.0.3", "vue-i18n": "^10.0.3", "vue-request": "^1.2.3", "vue-router": "^4.0.12" diff --git a/src/assets/img/Feedback/border.png b/src/assets/img/Feedback/border.png new file mode 100644 index 0000000..2e2460c Binary files /dev/null and b/src/assets/img/Feedback/border.png differ diff --git a/src/assets/img/Feedback/failure.png b/src/assets/img/Feedback/failure.png new file mode 100644 index 0000000..0414a93 Binary files /dev/null and b/src/assets/img/Feedback/failure.png differ diff --git a/src/assets/img/Feedback/save.png b/src/assets/img/Feedback/save.png new file mode 100644 index 0000000..e6fd6b7 Binary files /dev/null and b/src/assets/img/Feedback/save.png differ diff --git a/src/assets/img/Feedback/success.png b/src/assets/img/Feedback/success.png new file mode 100644 index 0000000..5659b61 Binary files /dev/null and b/src/assets/img/Feedback/success.png differ diff --git a/src/store/audio.js b/src/store/audio.js index 8697713..da1c41a 100644 --- a/src/store/audio.js +++ b/src/store/audio.js @@ -5,6 +5,7 @@ export const useAudioStore = defineStore('audio', { soundInstance: null, // Howl 实例 isPlaying: false, // 播放状态 isVoiceEnabled: true, // 新增声音开关状态 + playbackPosition: 0, // 新增播放位置存储 lastVoiceState: null, ttsUrl:'' }), diff --git a/src/views/AIchat.vue b/src/views/AIchat.vue index ff913a4..cf4e105 100644 --- a/src/views/AIchat.vue +++ b/src/views/AIchat.vue @@ -96,11 +96,10 @@ const playAudio = (url) => { const handlePlay = () => { - if (audioStore.soundInstance) { - Howler.unload(); // 添加清理旧实例 - // audioStore.soundInstance.stop() - } - + // if (audioStore.soundInstance) { + // Howler.unload(); // 添加清理旧实例 + // // audioStore.soundInstance.stop() + // } const newSound = new Howl({ src: [url], html5: true, // 强制HTML5 Audio解决iOS兼容问题 @@ -149,11 +148,11 @@ const pauseAudio = () => { } audioStore.isPlaying = false; - // 添加状态同步 - nextTick(() => { - Howler.unload(); - audioStore.soundInstance = null; - }); + // // 添加状态同步 + // nextTick(() => { + // Howler.unload(); + // audioStore.soundInstance = null; + // }); } }; @@ -375,111 +374,6 @@ watch( } } - // if (status === null || status.code == 200) { - // if (ans.value.answerG !== "") { - // AIcontent.value = ans.value.answerG; - // const code = ans.value.code; - // const market = ans.value.market; - // const data = JSON.parse(ans.value.duobaoData); - - // console.log("处理 K 线数据 - 开始"); - // console.log(data, "data"); - - // const Kline20 = { - // name: data.data.HomePage.StockInformation.Name, - // Kline: data.data.AIBull.KLine20 - // } - - // // 打印K线数据结构 - // console.log("K线数据结构:", Kline20); - // console.log("K线数据名称:", Kline20.name); - // console.log("K线数据数组长度:", Kline20.Kline ? Kline20.Kline.length : 0); - - // // 输出第一个数据点作为示例 - // if (Kline20.Kline && Kline20.Kline.length > 0) { - // console.log("K线首个数据点:", Kline20.Kline[0]); - // } - - // // 设置数据有效标志 - // hasValidData.value = true; - // console.log("hasValidData设置为:", hasValidData.value); - - // chatStore.messages.pop(); - - // // 先推送K线图消息 - // const klineMessageId = `kline-${Date.now()}`; - // console.log("生成K线消息ID:", klineMessageId); - - // chatStore.messages.push({ - // sender: "ai", - // type: "kline", - // chartData: Kline20, - // messageId: klineMessageId, - // hasValidData: true // 添加hasValidData标志 - // }); - - // console.log("K线消息已添加到聊天列表"); - - // // 再推送文字分析内容的消息 - // chatStore.messages.push({ - // sender: "ai", - // content: "AI正在思考中..." - // }); - - // // 在渲染完成后初始化图表 - // nextTick(() => { - // console.log("nextTick开始 - 准备渲染图表"); - // console.log("消息列表:", chatStore.messages); - - // // 寻找最新添加的K线消息索引 - // let klineIndex = -1; - // for (let i = 0; i < chatStore.messages.length; i++) { - // if (chatStore.messages[i].messageId === klineMessageId) { - // klineIndex = i; - // break; - // } - // } - - // console.log("找到的K线消息索引:", klineIndex); - - // if (klineIndex !== -1) { - // const containerId = `kline-container-${klineIndex}`; - // console.log("图表容器ID:", containerId); - - // // 确保DOM已经渲染完成 - // setTimeout(() => { - // console.log("延时执行,确保DOM已渲染"); - // KlineCanvsEcharts(containerId); - // }, 100); // 短暂延时确保DOM已渲染 - // } else { - // console.warn("未找到K线消息"); - // } - // }); - - // } else if (ans.value.answerN !== "") { - // AIcontent.value = ans.value.answerN; - // } else if (ans.value.answerO !== "") { - // AIcontent.value = ans.value.answerO; - // } - - // // 使用marked库将Markdown转换为HTML - // AIcontent.value = marked(AIcontent.value,); - // // 使用 KaTeX 渲染数学公式 - // const katexRegex = /\$\$(.*?)\$\$/g; - // AIcontent.value = AIcontent.value.replace(katexRegex, (match, formula) => { - // try { - // return katex.renderToString(formula, { throwOnError: false }); - // } catch (error) { - // console.error('KaTeX 渲染错误:', error); - // return match; - // } - // }); - - // chatStore.messages.push({ - // sender: "ai", - // content: AIcontent.value - // }) - // 修改后的消息处理逻辑 const processedContent = marked(AIcontent.value); const katexRegex = /\$\$(.*?)\$\$/g; @@ -861,13 +755,14 @@ watch( tryPlay(); } else { console.log("关闭语音播放"); + pauseAudio(); // 强制停止并释放资源 - Howler.stop(); - Howler.unload(); - if (audioStore.soundInstance) { - audioStore.soundInstance.off(); // 移除所有事件监听 - audioStore.soundInstance = null; - } + // Howler.stop(); + // Howler.unload(); + // if (audioStore.soundInstance) { + // audioStore.soundInstance.off(); // 移除所有事件监听 + // audioStore.soundInstance = null; + // } } }, { immediate: true } @@ -972,7 +867,8 @@ onUnmounted(() => { {{ questions.title }} -
+
{{ questions.title }} diff --git a/src/views/Announcement.vue b/src/views/Announcement.vue index 6ebe11b..49a9a4d 100644 --- a/src/views/Announcement.vue +++ b/src/views/Announcement.vue @@ -1,6 +1,17 @@ diff --git a/src/views/Feedback.vue b/src/views/Feedback.vue index 7216669..2ddb55a 100644 --- a/src/views/Feedback.vue +++ b/src/views/Feedback.vue @@ -6,6 +6,10 @@ import feedback from "../assets/img/Feedback/feedback.png"; import feedbackImg from "../assets/img/Feedback/feedbackImg.png"; import feedbackSuccess from "../assets/img/Feedback/feedbackSuccess.png"; import noFeedback from "../assets/img/Feedback/noFeedback.png"; +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"; const dataStore = useDataStore() @@ -14,8 +18,54 @@ const uploadUrl = import.meta.env.VITE_APP_IMG_API_BASE_URL; const feedbackFileList = ref([]); const isHistoryFeedback = ref(false); +const submitSuccessDialogVisible = ref(false) +const submitFailureDialogVisible = ref(false) +const submitFailureContent = ref('') const feedbackSubmit = async () => { console.log(feedbackContent.value) + console.log(feedbackFileList.value) + if (feedbackContent.value == '' && feedbackFileList.value.length == 0) { + submitFailureDialogVisible.value = true; + submitFailureContent.value = '请输入反馈内容或上传图片'; + } else { + try { + + submitSuccessDialogVisible.value = true; + } catch (error) { + submitFailureDialogVisible.value = true; + submitFailureContent.value = '反馈提交异常(错误代码:' + error.response.status + '),建议尝试更换网络环境后重新提交。'; + } + } + +} + +const submitSuccessConfirm = () => { + feedbackContent.value = ''; + feedbackFileList.value = []; + if (localStorage.getItem('feedbackContent')) { + localStorage.removeItem('feedbackContent'); + } + if (localStorage.getItem('feedbackFileList')) { + localStorage.removeItem('feedbackFileList'); + } + submitSuccessDialogVisible.value = false; +} +const submitFailureConfirm = () => { + submitFailureDialogVisible.value = false; +} +// 字数限制提示弹窗 +const feedbackContentOverLengthDialogVisible = ref(false) + +const feedbackContentLengthJudge = () => { + console.log('字数判断'); + console.log(feedbackContent.value.length) + if (feedbackContent.value.length >= 2000) { + feedbackContentOverLengthDialogVisible.value = true; + } +} + +const feedbackContentOverLengthConfirm = () => { + feedbackContentOverLengthDialogVisible.value = false; } const feedbackContentChange = () => { @@ -59,13 +109,40 @@ const handlePictureCardPreview = (uploadFile) => { dialogVisible.value = true } +// 返回弹窗 +const feedbackBackDialogVisible = ref(false) + const feedbackBack = () => { + feedbackBackDialogVisible.value = true; +} +// 确人保存 +const feedbackBackConfirm = () => { + feedbackBackDialogVisible.value = false; + dataStore.isFeedback = false; +} +// 取消保存 +const feedbackBackCancel = () => { + if (localStorage.getItem('feedbackContent')) { + localStorage.removeItem('feedbackContent'); + } + if (localStorage.getItem('feedbackFileList')) { + localStorage.removeItem('feedbackFileList'); + } + feedbackBackDialogVisible.value = false; dataStore.isFeedback = false; } onMounted(() => { - feedbackContent.value = localStorage.getItem('feedbackContent'); - feedbackFileList.value = JSON.parse(localStorage.getItem('feedbackFileList')); + if (localStorage.getItem('feedbackContent')) { + feedbackContent.value = localStorage.getItem('feedbackContent') + } else { + feedbackContent.value = ''; + } + if (localStorage.getItem('feedbackFileList')) { + feedbackFileList.value = JSON.parse(localStorage.getItem('feedbackFileList')); + } else { + feedbackFileList.value = []; + } console.log(uploadUrl) }) @@ -74,7 +151,11 @@ onMounted(() => { \ No newline at end of file diff --git a/src/views/homePage.vue b/src/views/homePage.vue index c05e834..3a7469e 100644 --- a/src/views/homePage.vue +++ b/src/views/homePage.vue @@ -163,6 +163,7 @@ const isAnnouncementVisible = ref(false); const showAnnouncement = async () => { console.log("打开公告"); + dataStore.isFeedback = false; // 显示用户反馈页面 isScrolling.value = false; //回复滚动到底部方法 setActiveTab('', -1); // 清空当前选中状态 @@ -318,6 +319,31 @@ const heightListener = () => { const throttledHeightListener = _.throttle(heightListener, 500, { trailing: false }); +const goToRecharge = () => { + console.log('点击充值') + // http://39.101.133.168:8919/payment/recharge/index? + // url=http%3A%2F%2Flocalhost%3A8080%2FLiveActivity%2Fpck + // &platform=1 + // &token=+S4h5QEE1hTIb4CxphrnbZi0+fEeMx8pywnIlrmTmo4QO6IolWnVWu5r+J4rKXMwK41UPfKqyIp+RvWmtM8 + + const userAgent = navigator.userAgent.toLowerCase(); + const mobileKeywords = ['mobile', 'android', 'iphone', 'ipad', 'ipod']; + const isMobile = mobileKeywords.some(keyword => userAgent.includes(keyword)); + + console.log(isMobile ? '手机' : '电脑') + + const url = encodeURI("http://192.168.1.103:3000/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 + +} + + const adjustFooterPosition = (height) => { console.log('调整底部位置', height) const footer = document.querySelector('.el-footer'); @@ -403,12 +429,14 @@ window.addEventListener('resize', () => { // 禁用全局触摸滚动 document.addEventListener('touchmove', (e) => { - // 判断触摸目标是否在可滚动区域内 - const isScrollableArea = e.target.closest('.tab-content'); + if (!dataStore.isFeedback) { + // 判断触摸目标是否在可滚动区域内 + const isScrollableArea = e.target.closest('.tab-content'); - // 如果不在可滚动区域,则阻止滚动 - if (!isScrollableArea) { - e.preventDefault(); + // 如果不在可滚动区域,则阻止滚动 + if (!isScrollableArea) { + e.preventDefault(); + } } }, { passive: false }); @@ -470,7 +498,7 @@ onMounted(async () => {
+ @sendMessage="sendMessage" @ensureAIchat="ensureAIchat"/>
@@ -543,7 +571,7 @@ onMounted(async () => {