ok1
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,16 @@
|
||||
import { getRequest, postRequest } from '@/utils/request';
|
||||
|
||||
export const aiApi = {
|
||||
|
||||
hotline: () => {
|
||||
return getRequest('/ai/hotline');
|
||||
},
|
||||
|
||||
aiChat : (message, context) => {
|
||||
let url = `/ai/chat?message=${encodeURIComponent(message)}`
|
||||
if (context) {
|
||||
url += `&context=${encodeURIComponent(JSON.stringify(context))}`
|
||||
}
|
||||
return getRequest(url);
|
||||
},
|
||||
}
|
||||
@@ -7,11 +7,4 @@ export const messageApi = {
|
||||
getMenuBadges : (param) => {
|
||||
return postRequest('/message/menubadge', param);
|
||||
},
|
||||
aiChat : (message, context) => {
|
||||
let url = `/message/chat?message=${encodeURIComponent(message)}`
|
||||
if (context) {
|
||||
url += `&context=${encodeURIComponent(JSON.stringify(context))}`
|
||||
}
|
||||
return getRequest(url);
|
||||
},
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
}
|
||||
/** 按钮样式 **/
|
||||
.skin-blue .ant-btn-primary {
|
||||
background-color: #5FA4CC !important;
|
||||
background-color: #53a7d1 !important;
|
||||
color:white!important;
|
||||
border:none!important;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
/** 按钮样式 **/
|
||||
.skin-green .ant-btn-primary {
|
||||
background-color:#009FA6 !important;
|
||||
background-color: #23b67b !important;
|
||||
color:white!important;
|
||||
border:none!important;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
/** 按钮样式 **/
|
||||
.skin-purple .ant-btn-primary {
|
||||
background-color: #A8865D !important;
|
||||
background-color: #9a64cf !important;
|
||||
color:white!important;
|
||||
border:none!important;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
/** 按钮样式 **/
|
||||
.skin-red .ant-btn-primary {
|
||||
background-color: #63B0B0 !important;
|
||||
background-color: #f67f7f !important;
|
||||
color: white !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
/** 按钮样式 **/
|
||||
.skin-yellow .ant-btn-primary {
|
||||
background-color: #C87F0A !important;
|
||||
background-color: #ecbe46 !important;
|
||||
color: white !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
.theme-dark .ant-menu-submenu-active{background-color: #304156 !important;color: #79b2ea!important; }
|
||||
.theme-dark .ant-menu-item-active{background-color: #243448 !important; color: #418dea!important;}
|
||||
.theme-dark .ant-menu-submenu-title {margin:4px 4px!important;padding:0px 20px!important;color: #BFCBD9!important;}
|
||||
.theme-dark .ant-menu-submenu-title {margin:4px 0px!important;color: #BFCBD9!important;} /*padding:0px 20px!important;**/
|
||||
.theme-dark .ant-menu-submenu-open{ color: #BFCBD9 !important;}
|
||||
.theme-dart .ant-menu-submenu-expand-icon, .ant-menu-submenu-arrow{color:#BFCBD9!important; }
|
||||
.theme-dark .ant-menu-submenu-selected { color: #418dea !important;}
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
<div class="ai-chat-wrapper" :class="{ collapsed, resizing }" :style="wrapperStyle">
|
||||
<div class="ai-chat-toggle" @click="collapsed = !collapsed">
|
||||
<div class="ai-chat-toggle-inner">
|
||||
<div class="ai-chat-drag-edge" @mousedown.prevent="startResize"></div>
|
||||
<ZhihuiIcon :icon="collapsed ? 'DoubleLeftOutlined' : 'DoubleRightOutlined'" class="ai-chat-toggle-arrow" @click.stop="collapsed = !collapsed" />
|
||||
<div class="ai-chat-drag-edge" @mousedown.stop="startResize"></div>
|
||||
<ZhihuiIcon icon="DoubleLeftOutlined" v-if="collapsed" class="ai-chat-toggle-arrow"></ZhihuiIcon>
|
||||
<ZhihuiIcon icon="DoubleRightOutlined" v-else class="ai-chat-toggle-arrow"></ZhihuiIcon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ai-chat-body" v-show="!collapsed">
|
||||
@@ -23,7 +24,7 @@
|
||||
|
||||
<!-- 浮动按钮 -->
|
||||
<a-tooltip placement="left">
|
||||
<a-button class="ai-chat-float-btn" :type="collapsed ? 'primary' : 'default'" shape="circle" size="large" @click="collapsed = !collapsed">
|
||||
<a-button class="ai-chat-float-btn" :type="collapsed ? 'primary' : 'default'" shape="circle" size="small" @click="collapsed = !collapsed">
|
||||
<template #icon><ZhihuiIcon :icon="collapsed ? 'RobotOutlined' : 'CloseOutlined'" /></template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
@@ -43,7 +44,7 @@
|
||||
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ZhihuiIcon } from '@/utils/ZhihuiIcon.js'
|
||||
import { messageApi } from '@/api/piao/message'
|
||||
import { aiApi } from '@/api/piao/ai'
|
||||
import zhihuiBus from '@/utils/zhihuiBus'
|
||||
import ChatMessages from './ai-chat/ChatMessages.vue'
|
||||
import ChatInput from './ai-chat/ChatInput.vue'
|
||||
@@ -129,7 +130,7 @@ const sendMessage = async () => {
|
||||
input.value = ''
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await messageApi.aiChat(text, pageContext.value)
|
||||
const res = await aiApi.aiChat(text, pageContext.value)
|
||||
messages.value.push({ role: 'assistant', content: res })
|
||||
} catch {
|
||||
messages.value.push({ role: 'assistant', content: '抱歉,我暂时无法回答,请稍后再试。' })
|
||||
@@ -206,10 +207,10 @@ const sendMessage = async () => {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
padding: 8px 0;
|
||||
padding: 5px 0;
|
||||
}
|
||||
.ai-chat-toggle-arrow {
|
||||
font-size: 13px;
|
||||
font-size: 11px;
|
||||
color: #bbb;
|
||||
transition: color 0.2s, transform 0.2s;
|
||||
}
|
||||
@@ -266,11 +267,11 @@ const sendMessage = async () => {
|
||||
}
|
||||
.ai-chat-float-btn {
|
||||
position: fixed;
|
||||
top: 5px;
|
||||
right: 100px;
|
||||
top: 8px;
|
||||
right: 110px;
|
||||
z-index: 999;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 34px !important;
|
||||
height: 34px !important;
|
||||
font-size: 10px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
<!-- 用户名称 -->
|
||||
<a-dropdown placement="bottomRight" class="user-dropdown">
|
||||
<a style="color: #fffeee" class="user-dropdown-link">
|
||||
<img :src="avatarSrc" class="avatarIcon" />
|
||||
<img :src="avatarSrc" class="avatarIcon" @error="onAvatarError" />
|
||||
<span class="user-name">{{ vueStore.getters.nickName }}</span>
|
||||
<ZhihuiIcon icon="DownOutlined" />
|
||||
</a>
|
||||
@@ -219,9 +219,12 @@ import zhihuiAudio from '@/utils/zhihuiAudio'; // 引入音频播放器
|
||||
|
||||
dayjs.locale('zh-cn');
|
||||
|
||||
const avatarError = ref(false);
|
||||
const avatarSrc = computed(() => {
|
||||
if (avatarError.value) return "/images/defaultavatar.png";
|
||||
return store.getters.avatar ? import.meta.env.VITE_API_DOMAIN + store.getters.avatar : "/images/defaultavatar.png";
|
||||
});
|
||||
const onAvatarError = () => { avatarError.value = true; };
|
||||
|
||||
const vueStore = useStore();
|
||||
const vueRouter = useRouter();
|
||||
@@ -729,12 +732,12 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.avatarIcon {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
height: 33px;
|
||||
width: 33px;
|
||||
border-radius: 50%;
|
||||
background-color: #e4f6f6;
|
||||
background-color: #a8e4e4;
|
||||
opacity: 0.9;
|
||||
border: 1px solid #abcbe7;
|
||||
border: 1px solid #abcbe7;margin-right:5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ import { message } from 'ant-design-vue';
|
||||
import { ArrowDownOutlined, ArrowUpOutlined ,TransactionOutlined,ArrowRightOutlined,SolutionOutlined,ShoppingCartOutlined,MoneyCollectOutlined,ClockCircleOutlined} from '@ant-design/icons-vue';
|
||||
import { chartApi } from '@/api/piao/chart';
|
||||
import { listNotice } from '@/api/system/notice';
|
||||
import { routeApi } from '@/api/piao/route';
|
||||
import { aiApi } from '@/api/piao/ai';
|
||||
import zhihuiBus from '@/utils/zhihuiBus';
|
||||
|
||||
// 定义响应式数据选项
|
||||
@@ -599,91 +599,27 @@ const popLoading = ref(false);
|
||||
const popularLoading = computed(() => {
|
||||
return popLoading.value ? {
|
||||
spinning: true,
|
||||
tip: 'AI正在搜索最新热门航线...',
|
||||
tip: 'AI正在实时搜索最新热门航线...',
|
||||
size: 'large'
|
||||
} : false;
|
||||
});
|
||||
const popularRoutes = ref([]);
|
||||
const fetchPopularRoutes = async () => {
|
||||
popLoading.value = true;
|
||||
let timeoutId = null;
|
||||
|
||||
try {
|
||||
// 创建一个超时Promise
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
timeoutId = setTimeout(() => {
|
||||
reject(new Error('请求超时,请稍后重试'));
|
||||
}, 10000); // 10秒超时
|
||||
});
|
||||
|
||||
// 创建API请求Promise
|
||||
const apiPromise = routeApi.popular(7);
|
||||
|
||||
// 使用Promise.race,哪个先完成就用哪个的结果
|
||||
const res = await Promise.race([apiPromise, timeoutPromise]);
|
||||
|
||||
// 如果请求成功,清除超时计时器
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
// 检查响应是否包含错误
|
||||
const res = await aiApi.hotline();
|
||||
if (typeof res === 'string') {
|
||||
try {
|
||||
const parsed = JSON.parse(res);
|
||||
if (parsed.error) {
|
||||
// 后端返回的错误
|
||||
showNotification('warning', parsed.message || '请求失败');
|
||||
popularRoutes.value = fallbackRoutes;
|
||||
popLoading.value = false;
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
// 不是JSON错误响应,继续正常处理
|
||||
}
|
||||
const data = JSON.parse(res);
|
||||
popularRoutes.value = Array.isArray(data) ? data : fallbackRoutes;
|
||||
} else if (res && res.data) {
|
||||
popularRoutes.value = Array.isArray(res.data) ? res.data : fallbackRoutes;
|
||||
} else {
|
||||
popularRoutes.value = fallbackRoutes;
|
||||
}
|
||||
|
||||
// 正常处理逻辑
|
||||
const events = Array.isArray(res) ? res :
|
||||
(typeof res === 'string' ? res.split('\n\n').filter(line => line.startsWith('data:')) : []);
|
||||
|
||||
let answerData = null;
|
||||
for (const event of events) {
|
||||
try {
|
||||
const eventData = typeof event === 'string' ?
|
||||
JSON.parse(event.replace('data: ', '')) : event;
|
||||
|
||||
if (eventData.event === 'agent_message' && eventData.answer && eventData.answer.trim()) {
|
||||
const parsed = JSON.parse(eventData.answer);
|
||||
if (parsed.data) {
|
||||
answerData = parsed.data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('解析事件失败:', e);
|
||||
}
|
||||
}
|
||||
|
||||
popularRoutes.value = Array.isArray(answerData) ? answerData : fallbackRoutes;
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取热门航线失败:', error);
|
||||
|
||||
// 清除超时计时器(如果还在)
|
||||
if (timeoutId) clearTimeout(timeoutId);
|
||||
|
||||
// 显示错误提示
|
||||
if (error.message === '请求超时,请稍后重试') {
|
||||
showNotification('warning', '请求超时,网络较慢或服务器响应延迟');
|
||||
} else if (error.message.includes('Network Error')) {
|
||||
showNotification('error', '网络错误,请检查网络连接');
|
||||
} else {
|
||||
showNotification('error', '获取数据失败');
|
||||
}
|
||||
|
||||
popularRoutes.value = fallbackRoutes;
|
||||
|
||||
} finally {
|
||||
// 确保无论如何都会关闭loading
|
||||
popLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user