fix: 修改大屏中的学术产出展示!调整智能助手接口

This commit is contained in:
liuzhiyuan 2025-08-30 13:10:25 +08:00
parent 848159a618
commit 55ad1b125f
2 changed files with 166 additions and 52 deletions

View File

@ -46,8 +46,8 @@
</div>
<!-- 学术产出 -->
<div class="dashboard-panel" style="flex: 1 1 0;">
<h2>学术产出</h2>
<div class="dashboard-panel" style="flex: 1.4;">
<h2 style="margin-bottom: 0;">学术产出</h2>
<div class="output-content">
<div ref="outputChartRef" class="chart-container-65"></div>
<!-- <div class="international-impact">
@ -138,10 +138,18 @@
<div v-html="dashboardData2?.prompt"></div>
</div>
<div v-for="(message, index) in chatMessages" :key="index"
:class="['message', message.role === 'user' ? 'user-message' : 'assistant-message']">
<div v-html="message.content"></div>
:class="['message', message.role === 'user' ? 'user-message' : 'assistant-message']" v-show="!message.isHidden">
<!-- 修改这里的显示逻辑 -->
<div v-if="message.isThinking" class="thinking-message">
<span class="loading-dot"></span>
<span class="loading-dot"></span>
<span class="loading-dot"></span>
</div>
<div v-else-if="message.isTyping" v-html="message.content"></div>
<div v-else v-html="message.content"></div>
</div>
<div v-if="isLoading" class="assistant-message loading-message">
<div v-if="isLoading && (!chatMessages.length || !chatMessages[chatMessages.length-1].isThinking)"
class="assistant-message loading-message">
<span class="loading-dot"></span>
<span class="loading-dot"></span>
<span class="loading-dot"></span>
@ -367,6 +375,8 @@ const chatMessagesRef = ref(null)
const userInput = ref('')
const isLoading = ref(false)
const chatMessages = ref([])
let typingInterval = null
let thinkingInterval = null
// DeepSeek API
const sendMessage = async () => {
@ -374,35 +384,41 @@ const sendMessage = async () => {
//
const userMessage = userInput.value.trim();
chatMessages.value.push({ role: 'user', content: userMessage });
chatMessages.value.push({
role: 'user',
content: userMessage,
isTyping: false,
isThinking: false
});
userInput.value = '';
//
await nextTick();
scrollToBottom();
//
// await nextTick();
// scrollToBottom();
//
isLoading.value = true;
chatMessages.value.push({ role: 'assistant', content: '思考中...' });
chatMessages.value.push({
role: 'assistant',
content: '',
isTyping: false,
isThinking: true,
isHidden: true //
});
const aiMessageIndex = chatMessages.value.length - 1;
try {
// 5
const apiMessages = chatMessages.value
.slice(-5)
.map(msg => ({ role: msg.role, content: msg.content }));
// API
const response = await fetch('https://api.deepseek.com/chat/completions', {
const response = await fetch(`${getChatApiUrl()}/chat/chat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer sk-06801499dd52426fa7cf3b0670931e3a'
},
body: JSON.stringify({
model: 'deepseek-chat',
messages: apiMessages,
stream: true //
model: "deepseek-r1:7b",
messages: [{ role: "user", content: userMessage }],
options: { temperature: 0.6 },
keep_thinking: false
})
});
@ -412,37 +428,75 @@ const sendMessage = async () => {
//
const reader = response.body.getReader();
let fullResponse = '';
const decoder = new TextDecoder();
let buffer = "";
let fullResponse = "";
//
chatMessages.value[aiMessageIndex] = {
role: 'assistant',
content: '',
isTyping: false,
isThinking: false,
isHidden: true //
};
//
await nextTick();
scrollToBottom();
// API
while (true) {
const { done, value } = await reader.read();
if (done) break;
// APIndjson
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(line => line.trim());
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() || "";
for (const line of lines) {
if (!line.trim()) continue;
try {
const data = JSON.parse(line.replace('data: ', ''));
if (data.choices?.[0]?.delta?.content) {
fullResponse += data.choices[0].delta.content;
// UI
chatMessages.value[aiMessageIndex].content = md.render(fullResponse);
scrollToBottom();
const obj = JSON.parse(line);
if (obj.message?.content) {
fullResponse += obj.message.content;
}
} catch (e) {
console.warn('解析流数据失败:', e);
console.warn('解析JSON失败:', e);
}
}
}
// APIisLoadingfalse
setTimeout(() => {
isLoading.value = false;
//
chatMessages.value[aiMessageIndex].isHidden = false;
//
let typingIndex = 0;
const typingInterval = setInterval(() => {
if (typingIndex < fullResponse.length) {
chatMessages.value[aiMessageIndex].content =
fullResponse.substring(0, typingIndex + 1);
typingIndex++;
scrollToBottom();
} else {
clearInterval(typingInterval);
}
}, 20);
}, 100)
} catch (error) {
console.error('请求失败:', error);
chatMessages.value[aiMessageIndex].content = '抱歉,回答时遇到问题,请重试。';
} finally {
isLoading.value = false;
chatMessages.value[aiMessageIndex] = {
role: 'assistant',
content: '抱歉,回答时遇到问题,请重试。',
isTyping: false,
isThinking: false,
isHidden: false //
};
scrollToBottom();
}
};
@ -451,7 +505,7 @@ const sendMessage = async () => {
const scrollToBottom = () => {
nextTick().then(() => {
if (chatMessagesRef.value) {
chatMessagesRef.value.scrollTop = chatMessagesRef.value.scrollHeight;
chatMessagesRef.value.scrollTop = chatMessagesRef.value.scrollHeight;
}
});
};
@ -504,7 +558,7 @@ const dashboardData2 = ref(null);
const loading = ref(true);
// API
import { getApiBaseUrl } from '../config';
import { getApiBaseUrl, getChatApiUrl } from '../config';
// API
const fetchDashboardData = async () => {
@ -1087,14 +1141,27 @@ const initCharts = () => {
'博士': outputLegendStatus.value[2],
'硕士': outputLegendStatus.value[1],
'学士': outputLegendStatus.value[0],
}
},
top: 10 //
},
grid: {
left: '3%',
right: '12%',
bottom: '3%',
top: '20%', //
containLabel: true
},
grid: { left: '3%', right: '12%', bottom: '3%', containLabel: true },
yAxis: {
type: 'category',
data: outputData.value.months,
axisLine: { lineStyle: { color: '#fff' } },
axisLabel: { color: '#fff' }
axisLabel: {
color: '#fff',
margin: 15 // y
},
axisTick: {
alignWithLabel: true
}
},
xAxis: {
type: 'value',
@ -1106,7 +1173,8 @@ const initCharts = () => {
type: 'dashed',
color: 'rgba(255, 255, 255, 0.2)'
}
}
},
interval: 1
},
series: [
{
@ -1114,13 +1182,16 @@ const initCharts = () => {
type: 'bar',
data: outputData.value.doctor,
itemStyle: { color: '#4080ff' },
barWidth: '20%',
barGap: '20%',
barWidth: '25%', //
barGap: '20%', //
label: {
show: true,
position: 'right',
color: '#fff',
formatter: '{c}'
formatter: function(params) {
// 0
return params.value > 0 ? params.value : '';
}
}
},
{
@ -1128,13 +1199,16 @@ const initCharts = () => {
type: 'bar',
data: outputData.value.master,
itemStyle: { color: 'rgb(107,187,196)' },
barWidth: '20%',
barWidth: '25%',
barGap: '20%',
label: {
show: true,
position: 'right',
color: '#fff',
formatter: '{c}'
formatter: function(params) {
// 0
return params.value > 0 ? params.value : '';
}
}
},
{
@ -1142,13 +1216,16 @@ const initCharts = () => {
type: 'bar',
data: outputData.value.bachelor,
itemStyle: { color: 'rgb(107,187,19)' },
barWidth: '20%',
barWidth: '25%',
barGap: '20%',
label: {
show: true,
position: 'right',
color: '#fff',
formatter: '{c}'
formatter: function(params) {
// 0
return params.value > 0 ? params.value : '';
}
}
}
]
@ -1313,6 +1390,12 @@ const newsData = ref([]);
//
onUnmounted(() => {
if (typingInterval) {
clearInterval(typingInterval);
}
if (thinkingInterval) {
clearInterval(thinkingInterval);
}
window.removeEventListener('resize', () => {});
})
</script>
@ -1766,7 +1849,31 @@ onUnmounted(() => {
.assistant-panel .panel-header {
display: flex;
align-items: center;
cursor: move; /* 整个头部可拖动 */
user-select: none; /* 防止拖动时选中文本 */
cursor: move;
user-select: none;
}
/* 思考消息样式 */
.thinking-message {
display: flex;
align-items: center;
}
.thinking-dots::after {
content: '...';
display: inline-block;
width: 20px;
animation: blinkDots 1.5s infinite steps(4, end);
}
@keyframes blinkDots {
0%, 100% { opacity: 0; }
25% { opacity: 0.5; }
50% { opacity: 1; }
}
.message {
transition: all 0.3s ease;
}
</style>

View File

@ -3,16 +3,23 @@ const env = import.meta.env.MODE || 'development';
const config = {
development: {
apiBaseUrl: 'http://192.168.5.49:48080',
// apiBaseUrl: 'http://192.168.5.49:48080',
apiBaseUrl: 'http://36.103.199.218:48089',
chatApiUrl: 'http://36.103.199.218:8093'
},
production: {
apiBaseUrl: 'http://221.238.217.216:4160',
chatApiUrl: 'http://221.238.217.216:8093',
// apiBaseUrl: 'http://36.103.199.218:48089',
// chatApiUrl: 'http://36.103.199.218:8093',
}
};
export const getApiBaseUrl = () => {
return config[env].apiBaseUrl;
};
export const getChatApiUrl = () => {
return config[env].chatApiUrl;
}
export default config;