Browse Source

滑动节流,防止用户重复提交

hxl
hongxilin 2 months ago
parent
commit
00be6bcd56
  1. 3
      README.md
  2. 6
      package-lock.json
  3. 1
      package.json
  4. 14
      src/store/chat.js
  5. 15
      src/views/AIchat.vue
  6. 29
      src/views/homePage.vue

3
README.md

@ -15,4 +15,5 @@ npm install marked 解析markdown 解析文本样式
npm install katex 数学公式 解析数学公式样式 npm install katex 数学公式 解析数学公式样式
npm install @coze/api npm install @coze/api
npm install html-to-text npm install html-to-text
npm install echarts
npm install echarts
npm install lodash 安装 lodash 组件,解决数据处理问题

6
package-lock.json

@ -20,6 +20,7 @@
"howler": "^2.2.4", "howler": "^2.2.4",
"html-to-text": "^9.0.5", "html-to-text": "^9.0.5",
"katex": "^0.16.21", "katex": "^0.16.21",
"lodash": "^4.17.21",
"marked": "^15.0.7", "marked": "^15.0.7",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"pinia": "^2.3.1", "pinia": "^2.3.1",
@ -4926,8 +4927,9 @@
}, },
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
"resolved": "https://mirrors.huaweicloud.com/repository/npm/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
}, },
"node_modules/lodash-es": { "node_modules/lodash-es": {
"version": "4.17.21", "version": "4.17.21",

1
package.json

@ -27,6 +27,7 @@
"howler": "^2.2.4", "howler": "^2.2.4",
"html-to-text": "^9.0.5", "html-to-text": "^9.0.5",
"katex": "^0.16.21", "katex": "^0.16.21",
"lodash": "^4.17.21",
"marked": "^15.0.7", "marked": "^15.0.7",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"pinia": "^2.3.1", "pinia": "^2.3.1",

14
src/store/chat.js

@ -2,8 +2,20 @@ import { defineStore } from 'pinia';
export const useChatStore = defineStore('chat', { export const useChatStore = defineStore('chat', {
state: () => ({ state: () => ({
messages: []
messages: [],
isLoading: false // 新增加载状态
}), }),
actions: {
setLoading(status) {
this.isLoading = status
},
isLoadingT() {
this.isLoading = true;
},
isLoadingF() {
this.isLoading = false;
}
},
persist: { persist: {
enabled: true, enabled: true,
strategies: [ strategies: [

15
src/views/AIchat.vue

@ -34,7 +34,7 @@ const showQuestions = (questions) => {
currentQuestions.value = questions; currentQuestions.value = questions;
// //
emit("updateMessage", questions.title); emit("updateMessage", questions.title);
emit("sendMessage");
// emit("sendMessage");
}; };
// //
@ -78,9 +78,6 @@ const props = defineProps({
messages: Array, messages: Array,
}); });
//
const isLoading = ref(false);
// //
const typewriterContent = ref("") const typewriterContent = ref("")
const isTyping = ref(false) const isTyping = ref(false)
@ -116,7 +113,6 @@ watch(
if (newVal.length > 0) { if (newVal.length > 0) {
console.log("消息列表已更新,最新消息:", newVal[newVal.length - 1]) console.log("消息列表已更新,最新消息:", newVal[newVal.length - 1])
chatStore.messages.push(newVal[newVal.length - 1]) chatStore.messages.push(newVal[newVal.length - 1])
isLoading.value = true;
console.log("消息列表已更新,最新消息:", chatMsg[chatMsg.length - 1]); console.log("消息列表已更新,最新消息:", chatMsg[chatMsg.length - 1]);
@ -300,13 +296,10 @@ watch(
return match; return match;
} }
}); });
chatStore.setLoading(false);
}); });
} }
}, 50); // 50ms/ }, 50); // 50ms/
//
isLoading.value = false;
} }
catch (e) { catch (e) {
console.error('请求失败:', e); console.error('请求失败:', e);
@ -314,11 +307,9 @@ watch(
sender: "ai", sender: "ai",
content: "AI思考失败,请稍后再试... ", content: "AI思考失败,请稍后再试... ",
}); });
chatStore.setLoading(false);
} }
} }
}, },
{ deep: true } { deep: true }
); );

29
src/views/homePage.vue

@ -9,8 +9,10 @@ import { useAppBridge } from '../assets/js/useAppBridge.js'
import { useDataStore } from '@/store/dataList.js' import { useDataStore } from '@/store/dataList.js'
import { useChatStore } from '../store/chat' import { useChatStore } from '../store/chat'
import { useAudioStore } from '../store/audio' import { useAudioStore } from '../store/audio'
import _ from "lodash";
// import { useUserStore } from "../store/userPessionCode.js"; // import { useUserStore } from "../store/userPessionCode.js";
const { getQueryVariable } = useDataStore() const { getQueryVariable } = useDataStore()
// //
// //
const audioStore = useAudioStore() const audioStore = useAudioStore()
@ -88,7 +90,7 @@ const message = ref("");
// //
const messages = ref([]); const messages = ref([]);
// //
const isLoading = ref(false);
const isLoading = computed(() => { chatStore.isLoading });
// //
const updateMessage = (title) => { const updateMessage = (title) => {
@ -100,7 +102,11 @@ const sendMessage = async () => {
ensureAIchat(); ensureAIchat();
if (!message.value) return; if (!message.value) return;
if (isLoading.value) return;
if (chatStore.isLoading) return;
console.log(chatStore.isLoading, 'isLoading.value1111');
chatStore.setLoading(true);
console.log(chatStore.isLoading, 'isLoading.value2222');
// isLoading true // isLoading true
messages.value = [ messages.value = [
@ -160,13 +166,14 @@ const smoothScrollToBottom = async () => {
} }
const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 500, { trailing: false });
const handleScroll = function () { const handleScroll = function () {
const scrollContainer = tabContent.value const scrollContainer = tabContent.value
const scrollTop = scrollContainer.scrollTop const scrollTop = scrollContainer.scrollTop
const scrollHeight = scrollContainer.scrollHeight const scrollHeight = scrollContainer.scrollHeight
const offsetHeight = scrollContainer.offsetHeight const offsetHeight = scrollContainer.offsetHeight
console.log(scrollTop, scrollHeight, offsetHeight, "scrollTop, scrollHeight, offsetHeight");
// console.log(scrollTop, scrollHeight, offsetHeight, "scrollTop, scrollHeight, offsetHeight");
if (scrollTop + offsetHeight < scrollHeight) { if (scrollTop + offsetHeight < scrollHeight) {
// //
isScrolling.value = true isScrolling.value = true
@ -174,14 +181,14 @@ const handleScroll = function () {
// //
isScrolling.value = false isScrolling.value = false
} }
console.log(isScrolling.value)
// console.log(isScrolling.value)
} }
watch( watch(
() => chatStore.messages, () => chatStore.messages,
() => { () => {
smoothScrollToBottom();
throttledSmoothScrollToBottom();
}, },
{ deep: true, immediate: true } { deep: true, immediate: true }
); );
@ -190,7 +197,7 @@ watch(
watch( watch(
activeTab, activeTab,
async (newVal) => { async (newVal) => {
smoothScrollToBottom();
throttledSmoothScrollToBottom();
}); });
@ -230,7 +237,7 @@ const fnGetToken = () => {
onMounted(async () => { onMounted(async () => {
setHeight(document.getElementById("testId")); // setHeight(document.getElementById("testId")); //
getUserCount(); getUserCount();
smoothScrollToBottom();
throttledSmoothScrollToBottom();
// //
tabContent.value.addEventListener('scroll', handleScroll) tabContent.value.addEventListener('scroll', handleScroll)
@ -288,7 +295,13 @@ onMounted(async () => {
<img v-else src="src\assets\img\homePage\tail\voice-no-active.png" @click="toggleVoice" <img v-else src="src\assets\img\homePage\tail\voice-no-active.png" @click="toggleVoice"
class="action-btn" /> class="action-btn" />
</div> </div>
<img src="src\assets\img\homePage\tail\send.png" @click="sendMessage" class="action-btn send-btn" />
<img v-if="!chatStore.isLoading" src="src\assets\img\homePage\tail\send.png" @click="sendMessage"
class="action-btn send-btn" />
<div v-else>
<el-icon class="is-loading">
<Loading />
</el-icon>
</div>
</div> </div>
<!-- 第二行输入框 --> <!-- 第二行输入框 -->

Loading…
Cancel
Save