2025-06-09 14:59:40 +08:00
|
|
|
|
<template>
|
|
|
|
|
<div class="dashboard" style="display: flex; flex-direction: column;position:absolute;top:0;left:0;right:0;bottom:0;">
|
|
|
|
|
|
|
|
|
|
<!-- 顶部导航栏 -->
|
|
|
|
|
<header class="dashboard-header">
|
|
|
|
|
<div class="logo">
|
|
|
|
|
<img src="../assets/logo1.png" alt="北京理工大学" @click="handleLogoClick" style="cursor: pointer;" />
|
|
|
|
|
<img src="../assets/logo2.png" alt="北京理工大学" @click="handleLogoClick" style="cursor: pointer;" />
|
|
|
|
|
<h1 class="main-title">
|
|
|
|
|
<div class="title-line"></div>
|
|
|
|
|
<span class="title-text">智慧科研评估系统</span>
|
|
|
|
|
<div class="title-line"></div>
|
|
|
|
|
</h1>
|
|
|
|
|
</div>
|
2025-06-12 10:35:31 +08:00
|
|
|
|
<!-- <div class="year-selector">
|
2025-06-09 14:59:40 +08:00
|
|
|
|
<el-dropdown>
|
|
|
|
|
<span class="el-dropdown-link">
|
|
|
|
|
2025 <el-icon class="el-icon--right"><arrow-down /></el-icon>
|
|
|
|
|
</span>
|
|
|
|
|
<template #dropdown>
|
|
|
|
|
<el-dropdown-menu>
|
|
|
|
|
<el-dropdown-item>2023</el-dropdown-item>
|
|
|
|
|
<el-dropdown-item>2024</el-dropdown-item>
|
|
|
|
|
<el-dropdown-item>2025</el-dropdown-item>
|
|
|
|
|
</el-dropdown-menu>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dropdown>
|
2025-06-12 10:35:31 +08:00
|
|
|
|
</div> -->
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<!-- 仪表盘内容 - 三列布局 -->
|
|
|
|
|
<div class="dashboard-content" style="flex: 1; overflow: hidden;">
|
|
|
|
|
<!-- 第一列:科研成果、学术产出、研究经费 -->
|
|
|
|
|
<div class="dashboard-column" style="overflow-y: auto;">
|
|
|
|
|
<!-- 科研成果 -->
|
|
|
|
|
<div class="dashboard-panel" style="flex: none; height: 130px;min-height:100px">
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
<h2>科研成果</h2>
|
|
|
|
|
<button class="panel-link" @click="redirectToResearchEvaluation">进入评估 >></button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="research-stats">
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
<h3>论文数量</h3>
|
2025-06-12 10:35:31 +08:00
|
|
|
|
<div class="stat-value"><span class="stat-prefix">累计</span>0</div>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
<h3>专利数量</h3>
|
2025-06-12 10:35:31 +08:00
|
|
|
|
<div class="stat-value"><span class="stat-prefix">本年</span>0</div>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
<h3>高影响力论文</h3>
|
2025-06-12 10:35:31 +08:00
|
|
|
|
<div class="stat-value"><span class="stat-prefix">累计</span>0</div>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
<h3>科研项目数量</h3>
|
2025-06-12 10:35:31 +08:00
|
|
|
|
<div class="stat-value"><span class="stat-prefix">国家重点</span>0<span>项</span></div>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 学术产出 -->
|
|
|
|
|
<div class="dashboard-panel" style="flex: 1 1 0;">
|
|
|
|
|
<h2>学术产出</h2>
|
|
|
|
|
<div class="output-content">
|
|
|
|
|
<div ref="outputChartRef" class="chart-container-65"></div>
|
|
|
|
|
<div class="international-impact">
|
|
|
|
|
<h3 style="font-size:25px;border-bottom: 5px solid rgb(73,134,255);text-align: left;padding-bottom:5px ">国际影响力</h3>
|
|
|
|
|
<div class="journal-stat">
|
|
|
|
|
<span class="journal-name">Nature</span>
|
|
|
|
|
<span class="journal-count">15</span>
|
|
|
|
|
<span class="journal-name2">篇</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="journal-stat">
|
|
|
|
|
<span class="journal-name">Science</span>
|
|
|
|
|
<span class="journal-count">8</span>
|
|
|
|
|
<span class="journal-name2">篇</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 研究经费 -->
|
|
|
|
|
<div class="dashboard-panel" style="flex: 1 1 0;">
|
|
|
|
|
<h2>研究经费: 500万元</h2>
|
|
|
|
|
<div ref="fundingChartRef" class="chart-container-funding"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 第二列:教师科研人才、学术奖项、新闻与动态 -->
|
|
|
|
|
<div class="dashboard-column" style="overflow-y: auto;">
|
|
|
|
|
<!-- 教师科研人才 -->
|
|
|
|
|
<div class="dashboard-panel" style="flex: 1 1 0;">
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
<h2>教师科研人才</h2>
|
|
|
|
|
<button class="panel-link" @click="navigate('talent')">进入评估 >></button>
|
|
|
|
|
</div>
|
|
|
|
|
<div ref="researcherChartRef" class="chart-container"></div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 学术奖项 -->
|
|
|
|
|
<div class="dashboard-panel" style="flex: 1 1 0;">
|
|
|
|
|
<h2>学术奖项</h2>
|
|
|
|
|
<div ref="awardsChartRef" class="chart-container"></div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-07-02 16:56:06 +08:00
|
|
|
|
<!-- 教师服务与社会贡献项目分布 -->
|
2025-06-09 14:59:40 +08:00
|
|
|
|
<div class="dashboard-panel" style="flex: 1 1 0;">
|
2025-07-02 16:56:06 +08:00
|
|
|
|
<h2>教师服务与社会贡献项目分布</h2>
|
|
|
|
|
<div ref="teacherServiceChartRef" class="chart-container"></div>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 第三列:工程研究中心、智能助手 -->
|
|
|
|
|
<div class="dashboard-column" style="overflow-y: auto;">
|
|
|
|
|
<!-- 工程研究中心 -->
|
|
|
|
|
<div class="dashboard-panel" style="flex: 6 1 0;">
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
<h2>工程研究中心</h2>
|
|
|
|
|
<button class="panel-link" @click="navigate('lab')">进入评估 >></button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="lab-charts">
|
|
|
|
|
<div ref="labBarChartRef" class="lab-chart-container"></div>
|
|
|
|
|
<div class="lab-chart-container">
|
|
|
|
|
<div ref="labLineChartRef" class="lab-line-chart"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 智能助手 -->
|
|
|
|
|
<div class="dashboard-panel" style="flex: 4 1 0;">
|
|
|
|
|
<h2>智能助手</h2>
|
|
|
|
|
<div class="assistant-container">
|
|
|
|
|
<div class="assistant-header">
|
2025-07-02 16:56:06 +08:00
|
|
|
|
<img :src="dashboardData2?.logoUrl" class="assistant-avatar" />
|
2025-06-09 14:59:40 +08:00
|
|
|
|
<h3>北京理工大学</h3>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="assistant-interface">
|
|
|
|
|
<div class="assistant-messages custom-scrollbar" ref="chatMessagesRef">
|
2025-07-02 16:56:06 +08:00
|
|
|
|
<div class="assistant-message message">
|
|
|
|
|
<div v-html="dashboardData2?.prompt"></div>
|
|
|
|
|
</div>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
<div v-for="(message, index) in chatMessages" :key="index"
|
|
|
|
|
:class="['message', message.role === 'user' ? 'user-message' : 'assistant-message']">
|
2025-06-26 15:58:51 +08:00
|
|
|
|
<div v-html="message.content"></div>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
<div v-if="isLoading" class="assistant-message loading-message">
|
|
|
|
|
<span class="loading-dot"></span>
|
|
|
|
|
<span class="loading-dot"></span>
|
|
|
|
|
<span class="loading-dot"></span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="assistant-input">
|
|
|
|
|
<input type="text" placeholder="请输入您的问题..." v-model="userInput" @keyup.enter="sendMessage" />
|
|
|
|
|
<button class="assistant-send" @click="sendMessage" :disabled="isLoading || !userInput.trim()">发送</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-07-02 16:56:06 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
|
|
|
|
import * as echarts from 'echarts/core'
|
|
|
|
|
import { BarChart, PieChart, LineChart, RadarChart } from 'echarts/charts'
|
|
|
|
|
import {
|
|
|
|
|
TitleComponent,
|
|
|
|
|
TooltipComponent,
|
|
|
|
|
GridComponent,
|
|
|
|
|
LegendComponent
|
|
|
|
|
} from 'echarts/components'
|
|
|
|
|
import { CanvasRenderer } from 'echarts/renderers'
|
|
|
|
|
import MarkdownIt from 'markdown-it';
|
|
|
|
|
const md = new MarkdownIt();
|
|
|
|
|
// 向父组件发送页面切换事件
|
|
|
|
|
const emit = defineEmits(['navigate', 'logout'])
|
|
|
|
|
const navigate = (page) => {
|
|
|
|
|
emit('navigate', page)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理Logo点击事件
|
|
|
|
|
const handleLogoClick = () => {
|
|
|
|
|
emit('logout')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 跳转到外部科研成果评估链接
|
|
|
|
|
const redirectToResearchEvaluation = () => {
|
|
|
|
|
window.open('http://82.156.236.221:10004/login', '_blank');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 注册必要的 echarts 组件
|
|
|
|
|
echarts.use([
|
|
|
|
|
BarChart,
|
|
|
|
|
PieChart,
|
|
|
|
|
LineChart,
|
|
|
|
|
RadarChart,
|
|
|
|
|
TitleComponent,
|
|
|
|
|
TooltipComponent,
|
|
|
|
|
GridComponent,
|
|
|
|
|
LegendComponent,
|
|
|
|
|
CanvasRenderer
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
// 图表DOM引用
|
|
|
|
|
const researcherChartRef = ref(null)
|
|
|
|
|
const labBarChartRef = ref(null)
|
|
|
|
|
const labLineChartRef = ref(null)
|
|
|
|
|
const outputChartRef = ref(null)
|
|
|
|
|
const awardsChartRef = ref(null)
|
|
|
|
|
const fundingChartRef = ref(null)
|
|
|
|
|
const teacherServiceChartRef = ref(null) // 新增教师服务图表DOM引用
|
|
|
|
|
|
|
|
|
|
// 教研人才图表数据
|
|
|
|
|
const researcherData = ref({
|
|
|
|
|
datax: [],
|
|
|
|
|
datay: [],
|
|
|
|
|
history: [],
|
|
|
|
|
ishistory: false
|
|
|
|
|
})
|
|
|
|
|
// 学术奖项图表数据
|
|
|
|
|
const studyData = ref({
|
|
|
|
|
datax: [],
|
|
|
|
|
datay: []
|
|
|
|
|
})
|
|
|
|
|
// 教师服务与社会贡献项目分布图表数据
|
|
|
|
|
const teacherServiceData = ref({
|
|
|
|
|
datax: [],
|
|
|
|
|
datay: []
|
|
|
|
|
})
|
|
|
|
|
// 工程研究中心图表数据
|
|
|
|
|
const labData = ref({
|
|
|
|
|
datax: [],
|
|
|
|
|
datay: []
|
|
|
|
|
})
|
|
|
|
|
const labLineData = ref({
|
|
|
|
|
datax: [],
|
|
|
|
|
datay: []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// DeepSeek 智能助手相关变量
|
|
|
|
|
const chatMessagesRef = ref(null)
|
|
|
|
|
const userInput = ref('')
|
|
|
|
|
const isLoading = ref(false)
|
|
|
|
|
const chatMessages = ref([
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
// DeepSeek API 调用函数
|
|
|
|
|
const sendMessage = async () => {
|
|
|
|
|
if (!userInput.value.trim() || isLoading.value) return
|
2025-06-09 14:59:40 +08:00
|
|
|
|
|
2025-07-02 16:56:06 +08:00
|
|
|
|
// 添加用户消息到对话
|
|
|
|
|
const userMessage = userInput.value.trim()
|
|
|
|
|
chatMessages.value.push({ role: 'user', content: userMessage })
|
|
|
|
|
userInput.value = ''
|
2025-06-09 14:59:40 +08:00
|
|
|
|
|
2025-07-02 16:56:06 +08:00
|
|
|
|
// 滚动到底部
|
|
|
|
|
await nextTick()
|
|
|
|
|
if (chatMessagesRef.value) {
|
|
|
|
|
chatMessagesRef.value.scrollTop = chatMessagesRef.value.scrollHeight
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 16:56:06 +08:00
|
|
|
|
// 设置加载状态
|
|
|
|
|
isLoading.value = true
|
2025-06-09 14:59:40 +08:00
|
|
|
|
|
2025-07-02 16:56:06 +08:00
|
|
|
|
try {
|
|
|
|
|
// 准备发送到 DeepSeek API 的消息历史
|
|
|
|
|
const apiMessages = [
|
|
|
|
|
{ role: 'system', content: '' }
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
// 添加最近的10条消息历史(如果有的话)
|
|
|
|
|
const recentMessages = chatMessages.value.slice(-10)
|
|
|
|
|
recentMessages.forEach(msg => {
|
|
|
|
|
apiMessages.push({
|
|
|
|
|
role: msg.role === 'assistant' ? 'assistant' : 'user',
|
|
|
|
|
content: msg.content
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 调用 DeepSeek API
|
|
|
|
|
const response = await fetch('https://api.deepseek.com/chat/completions', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
'Authorization': 'Bearer sk-06801499dd52426fa7cf3b0670931e3a'
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
model: 'deepseek-chat',
|
|
|
|
|
messages: apiMessages,
|
|
|
|
|
stream: false
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error('API请求失败')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const data = await response.json()
|
|
|
|
|
const aiResponse = data.choices && data.choices[0]?.message?.content || '抱歉,我无法回答这个问题。'
|
|
|
|
|
|
|
|
|
|
const aiResponseHtml = md.render(aiResponse)
|
|
|
|
|
|
|
|
|
|
// 添加AI回复到对话
|
|
|
|
|
chatMessages.value.push({ role: 'assistant', content: aiResponseHtml })
|
2025-06-09 14:59:40 +08:00
|
|
|
|
|
2025-07-02 16:56:06 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('DeepSeek API调用失败:', error)
|
|
|
|
|
chatMessages.value.push({ role: 'assistant', content: '抱歉,我遇到了技术问题,请稍后再试。' })
|
|
|
|
|
} finally {
|
|
|
|
|
isLoading.value = false
|
2025-06-09 14:59:40 +08:00
|
|
|
|
|
|
|
|
|
// 滚动到底部
|
|
|
|
|
await nextTick()
|
|
|
|
|
if (chatMessagesRef.value) {
|
|
|
|
|
chatMessagesRef.value.scrollTop = chatMessagesRef.value.scrollHeight
|
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 研究经费图例状态
|
|
|
|
|
const fundingLegendStatus = ref([true, true, true])
|
|
|
|
|
|
|
|
|
|
// 学术产出图例状态
|
|
|
|
|
const outputLegendStatus = ref([true, true])
|
|
|
|
|
|
|
|
|
|
// 切换研究经费图例
|
|
|
|
|
const toggleFundingLegend = (index) => {
|
|
|
|
|
fundingLegendStatus.value[index] = !fundingLegendStatus.value[index]
|
|
|
|
|
updateFundingChart()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 切换学术产出图例
|
|
|
|
|
const toggleOutputLegend = (index) => {
|
|
|
|
|
outputLegendStatus.value[index] = !outputLegendStatus.value[index]
|
|
|
|
|
updateOutputChart()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新研究经费图表
|
|
|
|
|
const updateFundingChart = () => {
|
|
|
|
|
const fundingChart = echarts.getInstanceByDom(fundingChartRef.value)
|
|
|
|
|
if (!fundingChart) return
|
|
|
|
|
|
|
|
|
|
fundingChart.setOption({
|
|
|
|
|
legend: {
|
|
|
|
|
selected: {
|
|
|
|
|
'政府 50%': fundingLegendStatus.value[0],
|
|
|
|
|
'企业 25%': fundingLegendStatus.value[1],
|
|
|
|
|
'其他 25%': fundingLegendStatus.value[2]
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新学术产出图表
|
|
|
|
|
const updateOutputChart = () => {
|
|
|
|
|
const outputChart = echarts.getInstanceByDom(outputChartRef.value)
|
|
|
|
|
if (!outputChart) return
|
|
|
|
|
|
|
|
|
|
outputChart.setOption({
|
|
|
|
|
legend: {
|
|
|
|
|
selected: {
|
|
|
|
|
'论文总数': outputLegendStatus.value[0],
|
|
|
|
|
'专利总数': outputLegendStatus.value[1]
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取仪表盘数据
|
|
|
|
|
const dashboardData = ref(null);
|
|
|
|
|
const dashboardData2 = ref(null);
|
|
|
|
|
const loading = ref(true);
|
|
|
|
|
|
|
|
|
|
// 引入API配置
|
|
|
|
|
import { getApiBaseUrl } from '../config';
|
|
|
|
|
|
|
|
|
|
// 从API获取仪表盘数据
|
|
|
|
|
const fetchDashboardData = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await fetch(`${getApiBaseUrl()}/admin-api/pg/J-dashboard/dashboard`);
|
|
|
|
|
|
|
|
|
|
if (response.ok) {
|
|
|
|
|
const data = await response.json();
|
|
|
|
|
console.log("仪表盘数据:", data);
|
|
|
|
|
dashboardData.value = data.data;
|
|
|
|
|
// 更新相应的UI数据
|
|
|
|
|
if (data) {
|
|
|
|
|
updateChartsWithDashboardData();
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
} else {
|
|
|
|
|
console.error('获取仪表盘数据失败:', response.statusText);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取仪表盘数据出错:', error);
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false;
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
};
|
|
|
|
|
const fetchDashboardData2 = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await fetch(`${getApiBaseUrl()}/admin-api/pg/intelligent-assistant/get-release`);
|
|
|
|
|
const data = await response.json();
|
|
|
|
|
dashboardData2.value = data.data;
|
|
|
|
|
if (data) {
|
|
|
|
|
updateChartsWithDashboardData();
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取仪表盘数据出错:', error);
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false;
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fetchTeacherbData = async (type) => {
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch(`${getApiBaseUrl()}/admin-api/pg/teacher-dashboard/get-release?type=${type}`);
|
|
|
|
|
if (res.ok) {
|
|
|
|
|
const data = await res.json();
|
|
|
|
|
// 处理 keyFields 数据
|
|
|
|
|
const keyFields = data.data.keyFields || [];
|
|
|
|
|
const datax = keyFields.map(item => item.fieldName);
|
|
|
|
|
const datay = keyFields.map(item => item.quantity);
|
|
|
|
|
|
|
|
|
|
if (type === 1) {
|
|
|
|
|
const highest = data.data.highestValue || [];
|
|
|
|
|
const ishistory = data.data.historyHighest;
|
|
|
|
|
const history = highest.map(item => item.quantity);
|
|
|
|
|
researcherData.value = {
|
2025-06-26 14:10:48 +08:00
|
|
|
|
datax,
|
2025-07-02 16:56:06 +08:00
|
|
|
|
datay,
|
|
|
|
|
history,
|
|
|
|
|
ishistory
|
2025-06-26 14:10:48 +08:00
|
|
|
|
};
|
|
|
|
|
// 数据更新后,手动更新图表
|
2025-07-02 16:56:06 +08:00
|
|
|
|
updateResearcherChart();
|
|
|
|
|
} else if (type === 2) {
|
|
|
|
|
studyData.value = {
|
|
|
|
|
datax: keyFields.map(item => ({ name: item.fieldName})),
|
|
|
|
|
datay
|
|
|
|
|
};
|
|
|
|
|
updateStudyChart();
|
|
|
|
|
} else if (type === 3) {
|
|
|
|
|
teacherServiceData.value = {
|
|
|
|
|
datax,
|
|
|
|
|
datay
|
|
|
|
|
};
|
|
|
|
|
updateTeacherServiceChart();
|
2025-06-26 14:10:48 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
} else {
|
|
|
|
|
console.error(`获取教师数据失败 (type=${type}):`, res.statusText);
|
2025-06-26 14:10:48 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(`获取教师数据出错 (type=${type}):`, error);
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fetchTeacherbData1 = () => fetchTeacherbData(1);
|
|
|
|
|
const fetchTeacherbData2 = () => fetchTeacherbData(2);
|
|
|
|
|
const fetchTeacherbData3 = () => fetchTeacherbData(3);
|
|
|
|
|
|
|
|
|
|
const updateStudyChart = () => {
|
|
|
|
|
const awardsChart = echarts.getInstanceByDom(awardsChartRef.value);
|
|
|
|
|
if (awardsChart) {
|
|
|
|
|
awardsChart.setOption({
|
|
|
|
|
radar: {
|
|
|
|
|
indicator: studyData.value.datax
|
2025-06-26 14:10:48 +08:00
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
2025-07-02 16:56:06 +08:00
|
|
|
|
data: [
|
|
|
|
|
{
|
|
|
|
|
value: studyData.value.datay
|
|
|
|
|
}
|
|
|
|
|
]
|
2025-06-26 14:10:48 +08:00
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
const updateResearcherChart = () => {
|
|
|
|
|
const researcherChart = echarts.getInstanceByDom(researcherChartRef.value);
|
|
|
|
|
if (researcherChart) {
|
2025-06-09 14:59:40 +08:00
|
|
|
|
researcherChart.setOption({
|
|
|
|
|
legend: {
|
2025-07-02 16:56:06 +08:00
|
|
|
|
data: researcherData.value.ishistory ? ['当前数量', '历史最高'] : ['当前数量']
|
|
|
|
|
},
|
|
|
|
|
yAxis: {
|
|
|
|
|
data: researcherData.value.datax
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
name: '当前数量',
|
|
|
|
|
data: researcherData.value.datay
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: '历史最高',
|
|
|
|
|
data: researcherData.value.history
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const updateTeacherServiceChart = () => {
|
|
|
|
|
const teacherServiceChart = echarts.getInstanceByDom(teacherServiceChartRef.value);
|
|
|
|
|
if (teacherServiceChart) {
|
|
|
|
|
teacherServiceChart.setOption({
|
|
|
|
|
legend: {
|
|
|
|
|
data: ['当前数量'],
|
2025-06-09 14:59:40 +08:00
|
|
|
|
textStyle: { color: '#fff' }
|
|
|
|
|
},
|
|
|
|
|
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
|
|
|
|
xAxis: {
|
|
|
|
|
type: 'value',
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' },
|
|
|
|
|
splitLine: {
|
|
|
|
|
show: true,
|
|
|
|
|
lineStyle: {
|
|
|
|
|
type: 'dashed',
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.2)'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
yAxis: {
|
|
|
|
|
type: 'category',
|
2025-07-02 16:56:06 +08:00
|
|
|
|
data: teacherServiceData.value.datax,
|
2025-06-09 14:59:40 +08:00
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' },
|
|
|
|
|
splitLine: { show: false }
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
name: '当前数量',
|
|
|
|
|
type: 'bar',
|
|
|
|
|
stack: 'total',
|
2025-07-02 16:56:06 +08:00
|
|
|
|
data: teacherServiceData.value.datay,
|
|
|
|
|
itemStyle: { color: '#f39c12' }, // 更换颜色
|
|
|
|
|
barWidth: '40%',
|
2025-06-09 14:59:40 +08:00
|
|
|
|
label: {
|
|
|
|
|
show: true,
|
|
|
|
|
position: 'inside',
|
|
|
|
|
color: '#fff',
|
|
|
|
|
formatter: '{c}'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
2025-07-02 16:56:06 +08:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const fetchLabData = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch(`${getApiBaseUrl()}/admin-api/pg/research-data-dashboard/get-release`);
|
|
|
|
|
if (res) {
|
|
|
|
|
const data = await res.json();
|
|
|
|
|
// 处理 keyFields 数据
|
|
|
|
|
const keyFields = data.data.keyFields || [];
|
|
|
|
|
const datax = keyFields.map(item => item.fieldName);
|
|
|
|
|
const datay = keyFields.map(item => item.quantity);
|
|
|
|
|
labData.value = {
|
|
|
|
|
datax,
|
|
|
|
|
datay
|
|
|
|
|
};
|
|
|
|
|
// 数据更新后,手动更新图表
|
|
|
|
|
updateLabBarChart();
|
|
|
|
|
} else {
|
|
|
|
|
console.error('获取工程研究中心数据失败:', response.statusText);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取工程研究中心数据出错:', error);
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const fetchLabData2 = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch(`${getApiBaseUrl()}/admin-api/pg/changes-in-achievements/get-release`);
|
|
|
|
|
if (res) {
|
|
|
|
|
const data = await res.json();
|
|
|
|
|
// 处理 keyFields 数据
|
|
|
|
|
const afterAnalysis = data.data.afterAnalysis || [];
|
|
|
|
|
const datax = afterAnalysis.map(item => item.year);
|
|
|
|
|
const datay = afterAnalysis.map(item => item.quantity);
|
|
|
|
|
labLineData.value = {
|
|
|
|
|
datax,
|
|
|
|
|
datay
|
|
|
|
|
};
|
|
|
|
|
// 数据更新后,手动更新图表
|
|
|
|
|
updateLabLineChart();
|
|
|
|
|
} else {
|
|
|
|
|
console.error('获取工程研究中心数据失败:', response.statusText);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取工程研究中心数据出错:', error);
|
|
|
|
|
} finally {
|
|
|
|
|
loading.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// 添加更新工程研究中心柱状图的函数
|
|
|
|
|
const updateLabBarChart = () => {
|
|
|
|
|
const labBarChart = echarts.getInstanceByDom(labBarChartRef.value);
|
|
|
|
|
if (labBarChart) {
|
|
|
|
|
labBarChart.setOption({
|
|
|
|
|
xAxis: {
|
|
|
|
|
data: labData.value.datax
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
data: labData.value.datay
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const updateLabLineChart = () => {
|
|
|
|
|
const labLineChart = echarts.getInstanceByDom(labLineChartRef.value);
|
|
|
|
|
if (labLineChart) {
|
|
|
|
|
labLineChart.setOption({
|
|
|
|
|
xAxis: {
|
|
|
|
|
data: labLineData.value.datax
|
2025-06-09 14:59:40 +08:00
|
|
|
|
},
|
2025-07-02 16:56:06 +08:00
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
data: labLineData.value.datay
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// 使用仪表盘数据更新图表
|
|
|
|
|
const updateChartsWithDashboardData = () => {
|
|
|
|
|
if (!dashboardData.value) return;
|
|
|
|
|
if (!dashboardData2.value) return;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 初始化图表
|
|
|
|
|
const initCharts = () => {
|
|
|
|
|
// 研究人员图表 - 横向堆叠柱状图(柱中心显示数字)
|
|
|
|
|
const researcherChart = echarts.init(researcherChartRef.value)
|
|
|
|
|
researcherChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
|
|
|
|
legend: {
|
|
|
|
|
data: researcherData.value.ishistory ? ['当前数量', '历史最高'] : ['当前数量'],
|
|
|
|
|
textStyle: { color: '#fff' }
|
|
|
|
|
},
|
|
|
|
|
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
|
|
|
|
xAxis: {
|
|
|
|
|
type: 'value',
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' },
|
|
|
|
|
splitLine: {
|
|
|
|
|
show: true,
|
|
|
|
|
lineStyle: {
|
|
|
|
|
type: 'dashed',
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.2)'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
yAxis: {
|
|
|
|
|
type: 'category',
|
|
|
|
|
data: researcherData.value.datax,
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' },
|
|
|
|
|
splitLine: { show: false }
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
name: '当前数量',
|
|
|
|
|
type: 'bar',
|
|
|
|
|
stack: 'total',
|
|
|
|
|
data: researcherData.value.datay,
|
|
|
|
|
itemStyle: { color: '#a95df3' },
|
|
|
|
|
barWidth: '40%', // 减小柱宽度
|
|
|
|
|
label: {
|
|
|
|
|
show: true,
|
|
|
|
|
position: 'inside',
|
|
|
|
|
color: '#fff',
|
|
|
|
|
formatter: '{c}'
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
2025-07-02 16:56:06 +08:00
|
|
|
|
{
|
|
|
|
|
name: '历史最高',
|
|
|
|
|
type: 'bar',
|
|
|
|
|
stack: 'total',
|
|
|
|
|
data: researcherData.value.history,
|
|
|
|
|
itemStyle: { color: '#7b49ca' },
|
|
|
|
|
label: {
|
|
|
|
|
show: true,
|
|
|
|
|
position: 'inside',
|
|
|
|
|
color: '#fff',
|
|
|
|
|
formatter: '{c}'
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 教师服务与社会贡献项目分布
|
|
|
|
|
const teacherServiceChart = echarts.init(teacherServiceChartRef.value)
|
|
|
|
|
teacherServiceChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
|
|
|
|
legend: {
|
|
|
|
|
data: ['当前数量'],
|
|
|
|
|
textStyle: { color: '#fff' }
|
|
|
|
|
},
|
|
|
|
|
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
|
|
|
|
xAxis: {
|
|
|
|
|
type: 'value',
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' },
|
|
|
|
|
splitLine: {
|
|
|
|
|
show: true,
|
|
|
|
|
lineStyle: {
|
|
|
|
|
type: 'dashed',
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.2)'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
yAxis: {
|
|
|
|
|
type: 'category',
|
|
|
|
|
data: teacherServiceData.value.datax,
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' },
|
|
|
|
|
splitLine: { show: false }
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
name: '当前数量',
|
|
|
|
|
type: 'bar',
|
|
|
|
|
stack: 'total',
|
|
|
|
|
data: teacherServiceData.value.datay,
|
|
|
|
|
itemStyle: { color: '#f39c12' }, // 更换颜色
|
|
|
|
|
barWidth: '40%',
|
|
|
|
|
label: {
|
|
|
|
|
show: true,
|
|
|
|
|
position: 'inside',
|
|
|
|
|
color: '#fff',
|
|
|
|
|
formatter: '{c}'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 工程研究中心柱状图(调整为占满全部宽度)
|
|
|
|
|
const labBarChart = echarts.init(labBarChartRef.value)
|
|
|
|
|
labBarChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
|
|
|
|
grid: {
|
|
|
|
|
left: '3%',
|
|
|
|
|
right: '4%',
|
|
|
|
|
top: '10%',
|
|
|
|
|
bottom: '5%',
|
|
|
|
|
containLabel: true
|
|
|
|
|
},
|
|
|
|
|
xAxis: {
|
|
|
|
|
type: 'category',
|
|
|
|
|
data: labData.value.datax,
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' }
|
|
|
|
|
},
|
|
|
|
|
yAxis: {
|
|
|
|
|
type: 'value',
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' },
|
|
|
|
|
splitLine: {
|
|
|
|
|
show: true,
|
|
|
|
|
lineStyle: {
|
|
|
|
|
type: 'dashed',
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.2)'
|
2025-06-09 14:59:40 +08:00
|
|
|
|
},
|
2025-07-02 16:56:06 +08:00
|
|
|
|
interval: 1
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
type: 'bar',
|
|
|
|
|
data: labData.value.datay,
|
|
|
|
|
itemStyle: { color: '#4080ff' },
|
|
|
|
|
barWidth: '15%',
|
|
|
|
|
label: {
|
2025-06-09 14:59:40 +08:00
|
|
|
|
show: true,
|
2025-07-02 16:56:06 +08:00
|
|
|
|
position: 'top',
|
|
|
|
|
color: '#fff'
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 工程研究中心折线图(调整为占满全部宽度)
|
|
|
|
|
const labLineChart = echarts.init(labLineChartRef.value)
|
|
|
|
|
labLineChart.setOption({
|
|
|
|
|
title: {
|
|
|
|
|
text: '近三年科研成果增长曲线',
|
|
|
|
|
textStyle: {
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.8)',
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
fontWeight: 'normal'
|
2025-06-09 14:59:40 +08:00
|
|
|
|
},
|
2025-07-02 16:56:06 +08:00
|
|
|
|
left: 'center',
|
|
|
|
|
bottom: '0%'
|
|
|
|
|
},
|
|
|
|
|
tooltip: { trigger: 'axis' },
|
|
|
|
|
grid: {
|
|
|
|
|
left: '3%',
|
|
|
|
|
right: '4%',
|
|
|
|
|
top: '10%',
|
|
|
|
|
bottom: '15%', // 为标题留出空间
|
|
|
|
|
containLabel: true
|
|
|
|
|
},
|
|
|
|
|
xAxis: {
|
|
|
|
|
type: 'category',
|
|
|
|
|
data: labLineData.value.datax,
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' }
|
|
|
|
|
},
|
|
|
|
|
yAxis: {
|
|
|
|
|
type: 'value',
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' },
|
|
|
|
|
splitLine: {
|
|
|
|
|
show: true,
|
|
|
|
|
lineStyle: {
|
|
|
|
|
type: 'dashed',
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.2)'
|
|
|
|
|
},
|
|
|
|
|
interval: 1
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
type: 'line',
|
|
|
|
|
data: labLineData.value.datay,
|
|
|
|
|
lineStyle: { color: '#ffd700', width: 3 },
|
|
|
|
|
itemStyle: { color: '#ffd700' },
|
|
|
|
|
symbolSize: 8
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 学术产出图表 - 横向柱状图(柱末端显示数字)
|
|
|
|
|
const outputChart = echarts.init(outputChartRef.value)
|
|
|
|
|
outputChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
|
|
|
|
legend: {
|
|
|
|
|
data: ['论文总数', '专利总数'],
|
|
|
|
|
textStyle: { color: '#fff' },
|
|
|
|
|
selected: {
|
|
|
|
|
'论文总数': outputLegendStatus.value[0],
|
|
|
|
|
'专利总数': outputLegendStatus.value[1]
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
grid: { left: '3%', right: '12%', bottom: '3%', containLabel: true },
|
|
|
|
|
yAxis: { // 交换了 xAxis 和 yAxis
|
|
|
|
|
type: 'category',
|
|
|
|
|
data: ['1月', '2月', '3月', '4月', '5月'],
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' }
|
|
|
|
|
},
|
|
|
|
|
xAxis: { // 交换了 xAxis 和 yAxis
|
|
|
|
|
type: 'value',
|
|
|
|
|
axisLine: { lineStyle: { color: '#fff' } },
|
|
|
|
|
axisLabel: { color: '#fff' },
|
|
|
|
|
splitLine: {
|
|
|
|
|
show: true,
|
|
|
|
|
lineStyle: {
|
|
|
|
|
type: 'dashed',
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.2)'
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
name: '论文总数',
|
|
|
|
|
type: 'bar',
|
|
|
|
|
data: [140, 160, 180, 190, 210],
|
|
|
|
|
itemStyle: { color: '#4080ff' },
|
|
|
|
|
barWidth: '20%',
|
|
|
|
|
barGap: '20%',
|
|
|
|
|
label: {
|
|
|
|
|
show: true,
|
|
|
|
|
position: 'right',
|
|
|
|
|
color: '#fff',
|
|
|
|
|
formatter: '{c}'
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
2025-07-02 16:56:06 +08:00
|
|
|
|
{
|
|
|
|
|
name: '专利总数',
|
|
|
|
|
type: 'bar',
|
|
|
|
|
data: [100, 110, 120, 130, 150],
|
|
|
|
|
itemStyle: { color: 'rgb(107,187,196)' },
|
|
|
|
|
barWidth: '20%',
|
|
|
|
|
barGap: '20%',
|
|
|
|
|
label: {
|
2025-06-09 14:59:40 +08:00
|
|
|
|
show: true,
|
2025-07-02 16:56:06 +08:00
|
|
|
|
position: 'right',
|
|
|
|
|
color: '#fff',
|
|
|
|
|
formatter: '{c}'
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 学术奖项图表 - 金色雷达图
|
|
|
|
|
const awardsChart = echarts.init(awardsChartRef.value)
|
|
|
|
|
awardsChart.setOption({
|
|
|
|
|
radar: {
|
|
|
|
|
indicator: studyData.value.datax,
|
|
|
|
|
splitArea: { show: false },
|
|
|
|
|
axisLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.2)' } },
|
|
|
|
|
splitLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.2)' } },
|
|
|
|
|
name: { textStyle: { color: '#fff' } },
|
|
|
|
|
radius: '70%'
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
type: 'radar',
|
|
|
|
|
data: [
|
|
|
|
|
{
|
|
|
|
|
value: studyData.value.datay,
|
|
|
|
|
name: '奖项分布',
|
|
|
|
|
areaStyle: { opacity: 0 }, // 移除中间蒙版
|
|
|
|
|
lineStyle: { color: '#ffd700', width: 2 },
|
|
|
|
|
itemStyle: { color: '#ffd700' }
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
],
|
|
|
|
|
label: {
|
|
|
|
|
show: true, // 显示标签
|
|
|
|
|
position: 'top', // 标签位置
|
|
|
|
|
color: '#fff', // 标签颜色
|
|
|
|
|
fontSize: 10 // 标签字体大小
|
2025-06-09 14:59:40 +08:00
|
|
|
|
},
|
2025-07-02 16:56:06 +08:00
|
|
|
|
emphasis: {
|
2025-06-09 14:59:40 +08:00
|
|
|
|
label: {
|
2025-07-02 16:56:06 +08:00
|
|
|
|
show: true, // 鼠标悬停时也显示标签
|
|
|
|
|
fontSize: 12, // 鼠标悬停时字体变大
|
|
|
|
|
fontWeight: 'bold' // 鼠标悬停时字体加粗
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 研究经费图表 - 玫瑰饼图
|
|
|
|
|
const fundingChart = echarts.init(fundingChartRef.value)
|
|
|
|
|
fundingChart.setOption({
|
|
|
|
|
tooltip: { trigger: 'item' },
|
|
|
|
|
legend: {
|
|
|
|
|
orient: 'vertical',
|
|
|
|
|
left: '5%',
|
|
|
|
|
top: 'center',
|
|
|
|
|
textStyle: { color: '#fff' },
|
|
|
|
|
data: ['政府 50%', '企业 25%', '其他 25%'],
|
|
|
|
|
selected: {
|
|
|
|
|
'政府 50%': fundingLegendStatus.value[0],
|
|
|
|
|
'企业 25%': fundingLegendStatus.value[1],
|
|
|
|
|
'其他 25%': fundingLegendStatus.value[2]
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
type: 'pie',
|
|
|
|
|
radius: ['30%', '70%'],
|
|
|
|
|
center: ['60%', '50%'], // 将图表向右移动为图例留出空间
|
|
|
|
|
roseType: 'area',
|
|
|
|
|
label: {
|
|
|
|
|
show: true,
|
|
|
|
|
formatter: '{b}',
|
|
|
|
|
position: 'outside',
|
|
|
|
|
color: '#fff',
|
|
|
|
|
alignTo: 'labelLine',
|
|
|
|
|
distanceToLabelLine: 5
|
|
|
|
|
},
|
|
|
|
|
labelLine: {
|
|
|
|
|
show: true,
|
|
|
|
|
length: 15,
|
|
|
|
|
length2: 10,
|
|
|
|
|
lineStyle: {
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.5)'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
emphasis: {
|
|
|
|
|
itemStyle: {
|
|
|
|
|
shadowBlur: 10,
|
|
|
|
|
shadowOffsetX: 0,
|
|
|
|
|
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
data: [
|
|
|
|
|
{ value: 50, name: '政府 50%', itemStyle: { color: '#9966ff' } },
|
|
|
|
|
{ value: 25, name: '企业 25%', itemStyle: { color: '#ff9933' } },
|
|
|
|
|
{ value: 25, name: '其他 25%', itemStyle: { color: '#3399ff' } }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 响应窗口大小变化
|
|
|
|
|
window.addEventListener('resize', () => {
|
|
|
|
|
researcherChart.resize()
|
|
|
|
|
labBarChart.resize()
|
|
|
|
|
labLineChart.resize()
|
|
|
|
|
outputChart.resize()
|
|
|
|
|
awardsChart.resize()
|
|
|
|
|
fundingChart.resize()
|
|
|
|
|
teacherServiceChart.resize()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生命周期钩子 - 组件挂载后初始化
|
|
|
|
|
onMounted(async() => {
|
|
|
|
|
// 教研人才数据
|
|
|
|
|
await fetchTeacherbData1();
|
|
|
|
|
await fetchTeacherbData2();
|
|
|
|
|
await fetchTeacherbData3(); // 调用新的数据获取函数
|
|
|
|
|
// 工程研究中心数据
|
|
|
|
|
await fetchLabData();
|
|
|
|
|
await fetchLabData2();
|
|
|
|
|
// 获取仪表盘数据
|
|
|
|
|
await fetchDashboardData();
|
|
|
|
|
await fetchDashboardData2();
|
|
|
|
|
|
|
|
|
|
// 初始化图表
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
initCharts();
|
2025-06-09 14:59:40 +08:00
|
|
|
|
});
|
2025-07-02 16:56:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 监听仪表盘数据变化
|
|
|
|
|
watch(dashboardData, () => {
|
|
|
|
|
if (dashboardData.value) {
|
|
|
|
|
updateChartsWithData();
|
|
|
|
|
}
|
|
|
|
|
}, { deep: true });
|
2025-06-09 14:59:40 +08:00
|
|
|
|
// 更新图表数据
|
|
|
|
|
const updateChartsWithData = () => {
|
|
|
|
|
if (!dashboardData.value) return;
|
|
|
|
|
// 更新论文数量、专利数量、高影响力论文和关键项目数量
|
|
|
|
|
const paperCountEl = document.querySelector('.stat-card:nth-child(1) .stat-value');
|
|
|
|
|
const patentCountEl = document.querySelector('.stat-card:nth-child(2) .stat-value');
|
|
|
|
|
const highImpactPapersEl = document.querySelector('.stat-card:nth-child(3) .stat-value');
|
|
|
|
|
const keyProjectsEl = document.querySelector('.stat-card:nth-child(4) .stat-value');
|
|
|
|
|
|
|
|
|
|
if (paperCountEl) {
|
|
|
|
|
paperCountEl.innerHTML = `<span class="stat-prefix">累计</span>${dashboardData.value.paperCount || 0}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (patentCountEl) {
|
|
|
|
|
patentCountEl.innerHTML = `<span class="stat-prefix">本年</span>${dashboardData.value.patentCount || 0}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (highImpactPapersEl) {
|
|
|
|
|
highImpactPapersEl.innerHTML = `<span class="stat-prefix">累计</span>${dashboardData.value.highImpactPapers || 0}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (keyProjectsEl) {
|
|
|
|
|
keyProjectsEl.innerHTML = `<span class="stat-prefix">国家重点</span>${dashboardData.value.keyProjects || 0}<span>项</span>`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新研究经费
|
|
|
|
|
const fundingTitle = document.querySelector('.dashboard-panel:nth-child(3) h2');
|
|
|
|
|
if (fundingTitle && dashboardData.value.fundingAmount) {
|
|
|
|
|
fundingTitle.textContent = `研究经费: ${dashboardData.value.fundingAmount}`;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 定义newsData为ref,使其可响应
|
|
|
|
|
const newsData = ref([]);
|
|
|
|
|
|
|
|
|
|
// 新闻滚动
|
|
|
|
|
let scrollInterval
|
|
|
|
|
const startNewsScroll = () => {
|
|
|
|
|
if (!newsListRef.value) return
|
|
|
|
|
|
|
|
|
|
scrollInterval = setInterval(() => {
|
|
|
|
|
if (newsListRef.value.scrollTop + newsListRef.value.clientHeight >= newsListRef.value.scrollHeight) {
|
|
|
|
|
// 如果已经滚动到底部,重新开始滚动
|
|
|
|
|
newsListRef.value.scrollTop = 0
|
|
|
|
|
} else {
|
|
|
|
|
// 否则继续滚动
|
|
|
|
|
newsListRef.value.scrollTop += 1
|
|
|
|
|
}
|
|
|
|
|
}, 50)
|
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
|
|
|
|
|
// 组件卸载时清理定时器
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
// 移除 resize 事件监听器
|
|
|
|
|
window.removeEventListener('resize', () => {
|
|
|
|
|
// 这里可以添加移除所有图表实例的逻辑,或者在需要时手动销毁
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
@import './common.css';
|
|
|
|
|
|
|
|
|
|
/* 自定义滚动条样式 */
|
|
|
|
|
.custom-scrollbar::-webkit-scrollbar {
|
|
|
|
|
width: 6px;
|
|
|
|
|
height: 6px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.custom-scrollbar::-webkit-scrollbar-track {
|
|
|
|
|
background: rgba(0, 0, 0, 0.1);
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.custom-scrollbar::-webkit-scrollbar-thumb {
|
|
|
|
|
background: rgba(73, 134, 255, 0.5);
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
|
|
|
background: rgba(73, 134, 255, 0.8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.custom-scrollbar {
|
|
|
|
|
scrollbar-width: thin;
|
|
|
|
|
scrollbar-color: rgba(73, 134, 255, 0.5) rgba(0, 0, 0, 0.1);
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
/* 特定于Dashboard的样式 */
|
|
|
|
|
.dashboard {
|
|
|
|
|
background-color: #102048;
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dashboard-content {
|
|
|
|
|
display: flex;
|
|
|
|
|
padding: 15px;
|
|
|
|
|
gap: 15px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dashboard-column {
|
|
|
|
|
flex: 1;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 15px;
|
|
|
|
|
min-width: 0; /* 防止flex子项溢出 */
|
|
|
|
|
max-height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dashboard-panel {
|
|
|
|
|
background-color: rgba(36, 69, 142, 0.5);
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
padding: 15px;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
flex: 1;
|
|
|
|
|
min-height: 200px; /* 设置最小高度 */
|
|
|
|
|
position: relative;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.panel-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.panel-link {
|
|
|
|
|
background: none;
|
|
|
|
|
border: none;
|
|
|
|
|
color: #4080ff;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chart-container {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
min-height: 150px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.year-selector {
|
|
|
|
|
color: white;
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.year-selector .el-dropdown-link {
|
|
|
|
|
color: white;
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.research-stats {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stat-card {
|
|
|
|
|
flex: 1;
|
|
|
|
|
background-color: rgba(64, 128, 255, 0.2);
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
padding: 15px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
border: 1px solid rgba(73,134,255,1);
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stat-card h3 {
|
|
|
|
|
margin: 0 0 10px 0;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
font-weight: normal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stat-value {
|
|
|
|
|
font-size: 17px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #4080ff;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: baseline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stat-prefix {
|
|
|
|
|
font-size: 12px !important;
|
|
|
|
|
margin-right: 5px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 学术产出布局 */
|
|
|
|
|
.output-content {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chart-container-65 {
|
|
|
|
|
width: 65%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.international-impact {
|
|
|
|
|
width: 35%;
|
|
|
|
|
padding: 0 15px;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.international-impact h3 {
|
|
|
|
|
text-align: center;
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.journal-stat {
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
text-align: right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.journal-name {
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
width: 90px;
|
|
|
|
|
display: inline-block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.journal-name2{
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
width: 25px;
|
|
|
|
|
display: inline-block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.journal-count {
|
|
|
|
|
color: #4080ff;
|
|
|
|
|
font-size: 30px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
width: 45px;
|
|
|
|
|
display: inline-block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 研究经费布局 */
|
|
|
|
|
.chart-container-funding {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 图例项 */
|
|
|
|
|
.legend-item {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.legend-color {
|
|
|
|
|
width: 15px;
|
|
|
|
|
height: 15px;
|
|
|
|
|
margin-right: 5px;
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.legend-inactive {
|
|
|
|
|
opacity: 0.5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.legend-inactive .legend-color {
|
|
|
|
|
background-color: #666 !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 工程研究中心图表 */
|
|
|
|
|
.lab-charts {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
flex: 1;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.lab-chart-container {
|
|
|
|
|
height: 50%; /* 调整为均等高度 */
|
|
|
|
|
width: 100%; /* 确保占满全部宽度 */
|
|
|
|
|
position: relative;
|
|
|
|
|
margin: 5px 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.lab-line-chart {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 智能助手样式 */
|
|
|
|
|
.assistant-container {
|
|
|
|
|
flex: 1;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
height: 90%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: 10px;
|
|
|
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-avatar {
|
|
|
|
|
height: 30px;
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-header h3 {
|
|
|
|
|
margin: 0;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-interface {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
flex: 1;
|
|
|
|
|
background-color: rgba(20, 40, 80, 0.3);
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-messages {
|
|
|
|
|
flex: 1;
|
|
|
|
|
padding: 10px;
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message {
|
|
|
|
|
padding: 10px;
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
max-width: 90%;
|
|
|
|
|
word-wrap: break-word;
|
|
|
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-message {
|
|
|
|
|
background-color: rgba(64, 128, 255, 0.2);
|
|
|
|
|
align-self: flex-start;
|
|
|
|
|
border-bottom-left-radius: 0;
|
|
|
|
|
position: relative;
|
|
|
|
|
border-left: 3px solid rgba(73, 134, 255, 0.8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-message:after {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
left: -5px;
|
|
|
|
|
width: 10px;
|
|
|
|
|
height: 10px;
|
|
|
|
|
background-color: rgba(64, 128, 255, 0.2);
|
|
|
|
|
clip-path: polygon(0 0, 100% 100%, 100% 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.user-message {
|
|
|
|
|
background-color: rgba(73, 134, 255, 0.5);
|
|
|
|
|
align-self: flex-end;
|
|
|
|
|
border-bottom-right-radius: 0;
|
|
|
|
|
color: white;
|
|
|
|
|
position: relative;
|
|
|
|
|
border-right: 3px solid rgba(73, 134, 255, 0.8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.user-message:after {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
right: -5px;
|
|
|
|
|
width: 10px;
|
|
|
|
|
height: 10px;
|
|
|
|
|
background-color: rgba(73, 134, 255, 0.5);
|
|
|
|
|
clip-path: polygon(0 0, 0 100%, 100% 100%);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loading-message {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: 15px;
|
|
|
|
|
border: none;
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loading-message:after {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loading-dot {
|
|
|
|
|
width: 8px;
|
|
|
|
|
height: 8px;
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
margin: 0 3px;
|
|
|
|
|
animation: bounce 1.4s infinite ease-in-out both;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loading-dot:nth-child(1) {
|
|
|
|
|
animation-delay: -0.32s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loading-dot:nth-child(2) {
|
|
|
|
|
animation-delay: -0.16s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes bounce {
|
|
|
|
|
0%, 80%, 100% {
|
|
|
|
|
transform: scale(0);
|
|
|
|
|
} 40% {
|
|
|
|
|
transform: scale(1.0);
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-input {
|
|
|
|
|
display: flex;
|
|
|
|
|
padding: 10px;
|
|
|
|
|
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-input input {
|
|
|
|
|
flex: 1;
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.1);
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
color: white;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-input input:focus {
|
|
|
|
|
outline: none;
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.15);
|
|
|
|
|
box-shadow: 0 0 0 2px rgba(73, 134, 255, 0.3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-input input::placeholder {
|
|
|
|
|
color: rgba(255, 255, 255, 0.5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-send {
|
|
|
|
|
background-color: #4080ff;
|
|
|
|
|
color: white;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
padding: 0 15px;
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: background-color 0.3s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-send:hover {
|
|
|
|
|
background-color: #5090ff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.assistant-send:disabled {
|
|
|
|
|
background-color: rgba(64, 128, 255, 0.5);
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 1200px) {
|
2025-06-09 14:59:40 +08:00
|
|
|
|
.output-content {
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
.chart-container-65 {
|
2025-06-09 14:59:40 +08:00
|
|
|
|
width: 100%;
|
2025-07-02 16:56:06 +08:00
|
|
|
|
height: 200px;
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
.international-impact {
|
2025-06-09 14:59:40 +08:00
|
|
|
|
width: 100%;
|
2025-07-02 16:56:06 +08:00
|
|
|
|
padding: 15px 0;
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
2025-07-02 16:56:06 +08:00
|
|
|
|
}
|
|
|
|
|
</style>
|