From 295f9cb304932ab19eaac8fe310de1b9c5a90b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Czhuzihan=E2=80=9D=E2=80=83?= <“772644120@qq.com”> Date: Thu, 7 Aug 2025 14:19:58 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- upload.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upload.js b/upload.js index 6559cb2..f964bf7 100644 --- a/upload.js +++ b/upload.js @@ -29,7 +29,7 @@ const config = { const localDir = path.join(__dirname, 'dist'); // 服务器目标目录 // const remoteDir = process.env.SFTP_REMOTE_DIR; // 如果使用环境变量 -const remoteDir = '/home/ubuntu/mnt/teacher_test/nginx-1/dist'; +const remoteDir = '/home/ubuntu/mnt/Teacher_Evaluation/nginx/dist'; async function uploadToServer() { const sftp = new SftpClient(); From 9635735c47fd6d97965e9560c32ebecac1a97aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Czhuzihan=E2=80=9D=E2=80=83?= <“772644120@qq.com”> Date: Thu, 7 Aug 2025 17:29:07 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Dashboard.vue | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/components/Dashboard.vue b/src/components/Dashboard.vue index 5d1904a..830730d 100644 --- a/src/components/Dashboard.vue +++ b/src/components/Dashboard.vue @@ -194,14 +194,15 @@ const redirectToResearchEvaluation = async () => { const result = await response.json(); if (result.code === 0) { // 跳转到目标网站 - await localStorage.setItem('access_token', result.data.access); - await localStorage.setItem('refresh_token', result.data.refresh); - await localStorage.setItem('user_info', JSON.stringify({ - user_id: result.data.user_id, - username: result.data.username, - permission: '2' - })); - window.location.href = 'http://82.156.236.221:10004/user/file' + // await localStorage.setItem('access_token', result.data.access); + // await localStorage.setItem('refresh_token', result.data.refresh); + // await localStorage.setItem('user_info', JSON.stringify({ + // user_id: result.data.user_id, + // username: result.data.username, + // permission: '2' + // })); + window.open(`http://82.156.236.221:10004/user/file?refresh_token=${result.data.refresh}`), '_blank'; + } else { console.error('代理登录失败:', result.error); } @@ -218,14 +219,14 @@ const redirectToResearchEvaluation2 = async () => { const result = await response.json(); if (result.code === 0) { // 跳转到目标网站 - await localStorage.setItem('access_token', result.data.access); - await localStorage.setItem('refresh_token', result.data.refresh); - await localStorage.setItem('user_info', JSON.stringify({ - user_id: result.data.user_id, - username: result.data.username, - permission: '1' - })) - window.location.href = 'http://82.156.236.221:10004/admin/manage' + // await localStorage.setItem('access_token', result.data.access); + // await localStorage.setItem('refresh_token', result.data.refresh); + // await localStorage.setItem('user_info', JSON.stringify({ + // user_id: result.data.user_id, + // username: result.data.username, + // permission: '1' + // })) + window.open(`http://82.156.236.221:10004/admin/manage?refresh_token=${result.data.refresh}`), '_blank'; } else { console.error('代理登录失败:', result.error); } From e244c3b38e124cf34212a04de194f9b9e4b678ce Mon Sep 17 00:00:00 2001 From: liuzhiyuan <> Date: Tue, 12 Aug 2025 16:54:20 +0800 Subject: [PATCH 3/7] =?UTF-8?q?fix=EF=BC=9A=20=E4=BF=AE=E6=94=B9=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.js | 2 +- upload.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.js b/src/config.js index b8812db..5090474 100644 --- a/src/config.js +++ b/src/config.js @@ -6,7 +6,7 @@ const config = { apiBaseUrl: 'http://192.168.5.49:48080', }, production: { - apiBaseUrl: 'http://36.103.203.89:48089', + apiBaseUrl: 'http://36.103.199.218:48089', } }; diff --git a/upload.js b/upload.js index f964bf7..637b5d1 100644 --- a/upload.js +++ b/upload.js @@ -17,7 +17,7 @@ const config = { // password: process.env.SFTP_PASS, // 直接配置 - host: '36.103.203.89', + host: '36.103.199.218', port: 22, username: 'liuyang', password: 'Asdf!234', From 776fb6dc15bea0f3917b31f9f4427dcf638d0e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Czhuzihan=E2=80=9D=E2=80=83?= <“772644120@qq.com”> Date: Thu, 14 Aug 2025 13:53:41 +0800 Subject: [PATCH 4/7] =?UTF-8?q?fix:=E5=9C=86=E7=8E=AF=E5=AE=BD=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Dashboard.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Dashboard.vue b/src/components/Dashboard.vue index 830730d..2038ab6 100644 --- a/src/components/Dashboard.vue +++ b/src/components/Dashboard.vue @@ -1212,10 +1212,10 @@ const initCharts = () => { }, series: [ { - type: 'pie', - radius: ['30%', '70%'], - center: ['60%', '50%'], - roseType: 'area', + type: 'pie', // 饼图 可选pie | ring + radius: ['30%', '50%'], + center: ['50%', '50%'], + // roseType: 'area', label: { show: true, formatter: '{b}: {d}%', From 848159a6185665f4e1dd11799a2f4f34d7ebdf11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Czhuzihan=E2=80=9D=E2=80=83?= <“772644120@qq.com”> Date: Fri, 15 Aug 2025 16:34:02 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E6=96=B0=E6=9C=8D=E5=8A=A1=E5=99=A8?= =?UTF-8?q?=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config.js b/src/config.js index 5090474..5a0c80c 100644 --- a/src/config.js +++ b/src/config.js @@ -6,7 +6,8 @@ const config = { apiBaseUrl: 'http://192.168.5.49:48080', }, production: { - apiBaseUrl: 'http://36.103.199.218:48089', + apiBaseUrl: 'http://221.238.217.216:4160', + // apiBaseUrl: 'http://36.103.199.218:48089', } }; From 55ad1b125f8c9bff5d413eb2a696f811349f9d92 Mon Sep 17 00:00:00 2001 From: liuzhiyuan <> Date: Sat, 30 Aug 2025 13:10:25 +0800 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E5=A4=A7=E5=B1=8F?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=AD=A6=E6=9C=AF=E4=BA=A7=E5=87=BA=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=EF=BC=81=E8=B0=83=E6=95=B4=E6=99=BA=E8=83=BD=E5=8A=A9?= =?UTF-8?q?=E6=89=8B=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Dashboard.vue | 209 ++++++++++++++++++++++++++--------- src/config.js | 9 +- 2 files changed, 166 insertions(+), 52 deletions(-) diff --git a/src/components/Dashboard.vue b/src/components/Dashboard.vue index 2038ab6..72cb33d 100644 --- a/src/components/Dashboard.vue +++ b/src/components/Dashboard.vue @@ -46,8 +46,8 @@ -
-

学术产出

+
+

学术产出

+
+ + + +
+
+
-
+
@@ -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; - - // 解析流式数据(假设API返回ndjson格式) - 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); } } } + // API响应完成后,设置isLoading为false + 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', () => {}); }) @@ -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; } \ No newline at end of file diff --git a/src/config.js b/src/config.js index 5a0c80c..2d70fb4 100644 --- a/src/config.js +++ b/src/config.js @@ -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; \ No newline at end of file From 1300959ee072d893c2db9a799c90999513d81424 Mon Sep 17 00:00:00 2001 From: liuzhiyuan <> Date: Sat, 30 Aug 2025 13:11:43 +0800 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config.js b/src/config.js index 2d70fb4..51010d9 100644 --- a/src/config.js +++ b/src/config.js @@ -8,10 +8,10 @@ const config = { 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', + // 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', } };