Merge remote-tracking branch 'origin/view' into view_dev

This commit is contained in:
“zhuzihan”  2025-07-03 17:55:43 +08:00
commit afc2c36178
6 changed files with 1484 additions and 1983 deletions

View File

@ -104,15 +104,10 @@
<div ref="awardsChartRef" class="chart-container"></div>
</div>
<!-- 新闻与动态 -->
<!-- 教师服务与社会贡献项目分布 -->
<div class="dashboard-panel" style="flex: 1 1 0;">
<h2>新闻与动态</h2>
<div class="news-list custom-scrollbar" ref="newsListRef">
<div class="news-item" v-for="(item, index) in newsData" :key="index">
<span class="news-title">{{ item.title }}</span>
<span class="news-date">{{ item.date }}</span>
</div>
</div>
<h2>教师服务与社会贡献项目分布</h2>
<div ref="teacherServiceChartRef" class="chart-container"></div>
</div>
</div>
@ -137,11 +132,14 @@
<h2>智能助手</h2>
<div class="assistant-container">
<div class="assistant-header">
<img src="../assets/logo1.png" alt="北京理工大学" class="assistant-avatar" />
<img :src="dashboardData2?.logoUrl" class="assistant-avatar" />
<h3>北京理工大学</h3>
</div>
<div class="assistant-interface">
<div class="assistant-messages custom-scrollbar" ref="chatMessagesRef">
<div class="assistant-message message">
<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>
@ -213,7 +211,25 @@
const outputChartRef = ref(null)
const awardsChartRef = ref(null)
const fundingChartRef = ref(null)
const newsListRef = 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: [],
@ -229,7 +245,6 @@
const userInput = ref('')
const isLoading = ref(false)
const chatMessages = ref([
{ role: 'assistant', content: '您好,我是北京理工大学科研评估智能助手,有什么可以帮助您的吗?' }
])
// DeepSeek API
@ -253,7 +268,7 @@
try {
// DeepSeek API
const apiMessages = [
{ role: 'system', content: '你是北京理工大学的智能助手,专门回答关于科研评估、学术成果和大学研究项目方面的问题。请不要给我返回任何.md格式如果有人问你使用的什么模型你就说你是李昂出品必属精品' }
{ role: 'system', content: '' }
]
// 10()
@ -356,16 +371,12 @@
//
const dashboardData = ref(null);
const dashboardData2 = ref(null);
const loading = ref(true);
// API
import { getApiBaseUrl } from '../config';
// token
const getToken = () => {
return localStorage.getItem('token');
};
// API
const fetchDashboardData = async () => {
try {
@ -377,14 +388,6 @@
dashboardData.value = data.data;
// UI
if (data) {
//
if (data.newsData && data.newsData.length > 0) {
newsData.value = data.newsData;
}
// UI
// UI
updateChartsWithDashboardData();
}
} else {
@ -396,6 +399,162 @@
loading.value = false;
}
};
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();
}
} catch (error) {
console.error('获取仪表盘数据出错:', error);
} finally {
loading.value = false;
}
};
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 = {
datax,
datay,
history,
ishistory
};
//
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();
}
} else {
console.error(`获取教师数据失败 (type=${type}):`, res.statusText);
}
} 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
},
series: [
{
data: [
{
value: studyData.value.datay
}
]
}
]
});
}
}
const updateResearcherChart = () => {
const researcherChart = echarts.getInstanceByDom(researcherChartRef.value);
if (researcherChart) {
researcherChart.setOption({
legend: {
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: ['当前数量'],
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 fetchLabData = async () => {
try {
const res = await fetch(`${getApiBaseUrl()}/admin-api/pg/research-data-dashboard/get-release`);
@ -427,15 +586,6 @@
const data = await res.json();
// keyFields
const afterAnalysis = data.data.afterAnalysis || [];
// const datax = [];
// const datay = [];
// afterAnalysis.forEach(item => {
// const year = Object.keys(item)[0]; //
// const quantity = item[year]; //
// datax.push(year);
// datay.push(quantity);
// });
const datax = afterAnalysis.map(item => item.year);
const datay = afterAnalysis.map(item => item.quantity);
labLineData.value = {
@ -487,9 +637,8 @@ const updateLabLineChart = () => {
// 使
const updateChartsWithDashboardData = () => {
if (!dashboardData.value) return;
if (!dashboardData2.value) return;
//
//
};
//
@ -499,7 +648,7 @@ const updateLabLineChart = () => {
researcherChart.setOption({
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: {
data: ['当前数量', '历史最高'],
data: researcherData.value.ishistory ? ['当前数量', '历史最高'] : ['当前数量'],
textStyle: { color: '#fff' }
},
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
@ -517,7 +666,7 @@ const updateLabLineChart = () => {
},
yAxis: {
type: 'category',
data: ['博士生导师', '高被引学者', '教师总数'],
data: researcherData.value.datax,
axisLine: { lineStyle: { color: '#fff' } },
axisLabel: { color: '#fff' },
splitLine: { show: false }
@ -527,7 +676,7 @@ const updateLabLineChart = () => {
name: '当前数量',
type: 'bar',
stack: 'total',
data: [150, 100, 50],
data: researcherData.value.datay,
itemStyle: { color: '#a95df3' },
barWidth: '40%', //
label: {
@ -541,7 +690,7 @@ const updateLabLineChart = () => {
name: '历史最高',
type: 'bar',
stack: 'total',
data: [80, 50, 30],
data: researcherData.value.history,
itemStyle: { color: '#7b49ca' },
label: {
show: true,
@ -553,6 +702,52 @@ const updateLabLineChart = () => {
]
})
//
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({
@ -716,30 +911,38 @@ const updateLabLineChart = () => {
const awardsChart = echarts.init(awardsChartRef.value)
awardsChart.setOption({
radar: {
indicator: [
{ name: '国家级科技奖励', max: 100 },
{ name: '省部级科技奖励', max: 100 },
{ name: '学术会议最佳论文', max: 100 },
{ name: '行业技术创新奖项', max: 100 },
{ name: '国际学术奖励', max: 100 }
],
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' } }
name: { textStyle: { color: '#fff' } },
radius: '70%'
},
series: [
{
type: 'radar',
data: [
{
value: [80, 70, 90, 75, 85],
value: studyData.value.datay,
name: '奖项分布',
areaStyle: { opacity: 0 }, //
lineStyle: { color: '#ffd700', width: 2 },
itemStyle: { color: '#ffd700' }
}
]
],
label: {
show: true, //
position: 'top', //
color: '#fff', //
fontSize: 10 //
},
emphasis: {
label: {
show: true, //
fontSize: 12, //
fontWeight: 'bold' //
}
}
}
]
})
@ -798,9 +1001,6 @@ const updateLabLineChart = () => {
]
})
//
startNewsScroll()
//
window.addEventListener('resize', () => {
researcherChart.resize()
@ -809,16 +1009,22 @@ const updateLabLineChart = () => {
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(() => {
@ -832,31 +1038,9 @@ const updateLabLineChart = () => {
updateChartsWithData();
}
}, { deep: true });
//
const updateChartsWithData = () => {
if (!dashboardData.value) return;
//
newsData.value = dashboardData.value.newsData || [];
//
if (researcherChartRef.value) {
const researcherChart = echarts.getInstanceByDom(researcherChartRef.value);
if (researcherChart && dashboardData.value.researcherStats) {
//
researcherChart.setOption({
series: [{
data: [
dashboardData.value.researcherStats.professor || 0,
dashboardData.value.researcherStats.associateProfessor || 0,
dashboardData.value.researcherStats.assistantProfessor || 0
]
}]
});
}
}
//
const paperCountEl = document.querySelector('.stat-card:nth-child(1) .stat-value');
const patentCountEl = document.querySelector('.stat-card:nth-child(2) .stat-value');
@ -864,19 +1048,19 @@ const updateLabLineChart = () => {
const keyProjectsEl = document.querySelector('.stat-card:nth-child(4) .stat-value');
if (paperCountEl) {
paperCountEl.innerHTML = `<span class="stat-prefix">累计</span>${dashboardData.value.paperCount || 0}`;
paperCountEl.innerHTML = `<span class="stat-prefix" style="font-size: 12px;">累计</span>${dashboardData.value.paperCount || 0}`;
}
if (patentCountEl) {
patentCountEl.innerHTML = `<span class="stat-prefix">本年</span>${dashboardData.value.patentCount || 0}`;
patentCountEl.innerHTML = `<span class="stat-prefix" style="font-size: 12px;">本年</span>${dashboardData.value.patentCount || 0}`;
}
if (highImpactPapersEl) {
highImpactPapersEl.innerHTML = `<span class="stat-prefix">累计</span>${dashboardData.value.highImpactPapers || 0}`;
highImpactPapersEl.innerHTML = `<span class="stat-prefix" style="font-size: 12px;">累计</span>${dashboardData.value.highImpactPapers || 0}`;
}
if (keyProjectsEl) {
keyProjectsEl.innerHTML = `<span class="stat-prefix">国家重点</span>${dashboardData.value.keyProjects || 0}<span>项</span>`;
keyProjectsEl.innerHTML = `<span class="stat-prefix" style="font-size: 12px;">国家重点</span>${dashboardData.value.keyProjects || 0}<span>项</span>`;
}
//
@ -907,9 +1091,10 @@ const updateLabLineChart = () => {
//
onUnmounted(() => {
if (scrollInterval) {
clearInterval(scrollInterval)
}
// resize
window.removeEventListener('resize', () => {
//
});
})
</script>
@ -946,7 +1131,6 @@ const updateLabLineChart = () => {
<style scoped>
/* 特定于Dashboard的样式 */
.dashboard {
background-color: #102048;
color: white;
}
@ -995,7 +1179,7 @@ const updateLabLineChart = () => {
.chart-container {
width: 100%;
height: 100%;
min-height: 150px;
min-height: 160px;
}
.year-selector {
@ -1028,8 +1212,9 @@ const updateLabLineChart = () => {
.stat-card h3 {
margin: 0 0 10px 0;
font-size: 14px;
font-size: 12px;
font-weight: normal;
white-space: nowrap;
}
.stat-value {
@ -1041,9 +1226,10 @@ const updateLabLineChart = () => {
align-items: baseline;
}
.stat-prefix {
.stat-value .stat-prefix {
font-size: 12px !important;
margin-right: 5px;
white-space: nowrap;
}
/* 学术产出布局 */
@ -1144,39 +1330,6 @@ const updateLabLineChart = () => {
height: 100%;
}
/* 新闻列表 */
.news-list {
padding: 10px;
flex: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
max-height: 200px;
}
.news-item {
display: flex;
justify-content: space-between;
padding: 8px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
margin-bottom: 8px;
background-color: rgba(36,69,142,1);
border: 1px solid rgba(73,134,255,1);
border-radius: 5px;
color: rgba(123,173,255,1);
}
.news-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 70%;
}
.news-date {
opacity: 0.7;
}
/* 智能助手样式 */
.assistant-container {
flex: 1;

View File

@ -315,8 +315,8 @@ const handleSearch = () => {
filteredLabs.value = labs.value;
} else {
filteredLabs.value = labs.value.filter(lab =>
lab.basicInformation.name1.includes(searchQuery.value) ||
(lab.name0 && lab.name0.includes(searchQuery.value))
lab.basicInformation.name1 && lab.basicInformation.name1.includes(searchQuery.value) ||
(lab.basicInformation.name0 && lab.basicInformation.name0.includes(searchQuery.value))
);
}

View File

@ -12,7 +12,6 @@
<div class="basic-info">
<div class="form-row">
<div class="form-item">
{{console.log(labData)}}
<span class="label">编号:</span>
<span class="display-text">{{ labData.basicInformation.name0 }}</span>
</div>

View File

@ -50,7 +50,7 @@
</h1>
</div>
<div class="search-box">
<input type="text" placeholder="请输入教师姓名或ID" v-model="searchQuery" @input="handleSearch" />
<input type="text" placeholder="请输入教师姓名" v-model="searchQuery" @input="handleSearch" />
<button class="search-button">
<svg class="search-icon" viewBox="0 0 24 24" width="20" height="20">
<path fill="white"
@ -71,28 +71,32 @@
<div class="card-top">
<div class="teacher-left">
<div class="teacher-photo">
<img :src="teacher.photo" alt="教师照片" />
<img :src="teacher.basicInformation.name7" alt="教师照片" />
</div>
<div class="teacher-id">ID: {{ teacher.idcode || teacher.id }}</div>
<!-- <div class="teacher-id">姓名{{ teacher.basicInformation.name0 }}</div> -->
</div>
<div class="teacher-info">
<div class="info-row">
<span class="info-label">姓名:</span>
<span class="info-value">{{ teacher.name }}</span>
<span class="info-value">{{ teacher.basicInformation.name0 }}</span>
</div>
<div class="info-row">
<span class="info-label">教育背景:</span>
<span class="info-label">职称 / 职务:</span>
<span class="info-value">{{ teacher.basicInformation.name2 }} / {{ teacher.basicInformation.name3 }}</span>
</div>
<div class="info-row">
<span class="info-label">所属院校:</span>
<span class="info-value">{{ teacher.education }}</span>
<span class="info-value">{{ teacher.basicInformation.name4 }}</span>
</div>
<div class="info-row">
<span class="info-label">论文:</span>
<span class="info-value">{{ teacher.papers }}</span>
<span class="info-label">最高学历:</span>
<span class="info-value">{{ teacher.basicInformation.name5 }}</span>
</div>
<div class="info-row">
<span class="info-label">项目:</span>
<span class="info-value">{{ teacher.projects }}</span>
<span class="info-label">学科方向:</span>
<span class="info-value">{{ teacher.basicInformation.name6 }}</span>
</div>
</div>
</div>
@ -106,30 +110,9 @@
</div>
</div>
<!-- 自定义维度对话框 -->
<el-dialog v-model="dimensionDialogVisible" :title="isEditingDimension ? '编辑维度' : '添加维度'" width="30%"
custom-class="dimension-dialog">
<el-form :model="dimensionForm" :rules="dimensionRules" ref="dimensionFormRef" label-position="top">
<el-form-item label="维度名称" prop="name">
<el-input v-model="dimensionForm.name" placeholder="请输入维度名称" />
</el-form-item>
<el-form-item label="权重(W)" prop="weight">
<el-input-number v-model="dimensionForm.weight" :min="1" :max="100" :step="1" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dimensionDialogVisible = false">取消</el-button>
<el-button type="danger" v-if="isEditingDimension" @click="deleteDimension">删除</el-button>
<el-button type="primary" @click="saveDimension">确定</el-button>
</span>
</template>
</el-dialog>
<TalentDrawerDetail v-model:visible="drawerVisible" :is-edit="isEditMode" :dimensions="dimensions"
:teacher-data="selectedTeacher" @save="handleSaveEvaluation" />
<DimensionDrawer v-model:visible="dimensionDrawerVisible" :dimensions="dimensions" category="talent"
@save="handleSaveDimensions" />
</template>
<script setup>
@ -137,7 +120,6 @@ import { ref, onMounted, watch, nextTick } from 'vue';
import * as echarts from 'echarts/core';
import { RadarChart } from 'echarts/charts';
//
import DimensionDrawer from './DimensionDrawer.vue';
import TalentDrawerDetail from './TalentDrawerDetail.vue';
import {
TitleComponent,
@ -226,29 +208,17 @@ const dimensions = ref([]); // 改为空数组从API获取数据
//
onMounted(async () => {
try {
//
const response = await axios.get(`${getApiBaseUrl()}/admin-api/pg/J-dimensions/talent`);
dimensions.value = response.data.data;
//
await loadTeachers();
//
handleSearch();
} catch (error) {
console.error('获取维度数据失败:', error);
ElMessage.error('获取维度数据失败');
}
await teacherLabs();
});
//
const loadTeachers = async () => {
const teacherLabs = async () => {
try {
const response = await axios.get(`${getApiBaseUrl()}/admin-api/pg/J-talents/talents`);
const response = await axios.get(`${getApiBaseUrl()}/admin-api/pg/teacher-evaluation-results/get-release`);
teachers.value = response.data.data;
handleSearch();
} catch (error) {
console.error('获取教师数据失败:', error);
ElMessage.error('获取教师数据失败');
ElMessage.error('获取工程研究中心数据失败');
}
};
@ -257,8 +227,7 @@ const dimensionDialogVisible = ref(false);
const isEditingDimension = ref(false);
const currentDimensionIndex = ref(-1);
const dimensionForm = ref({
name: '',
weight: 10
name: ''
});
const dimensionFormRef = ref(null);
const dimensionRules = {
@ -331,8 +300,7 @@ const handleSearch = () => {
filteredTeachers.value = teachers.value;
} else {
filteredTeachers.value = teachers.value.filter(teacher =>
teacher.name.includes(searchQuery.value) ||
teacher.id.includes(searchQuery.value)
teacher.basicInformation.name0.includes(searchQuery.value)
);
}
};
@ -348,28 +316,10 @@ const initRadarCharts = () => {
const chart = echarts.init(chartDom);
//
const indicators = dimensions.value.map(dim => ({
name: dim.name,
max: 100
const indicators = teacher.dimension.map(dim => ({
name: dim
}));
//
const baseValue = teacher.id ? parseInt(teacher.id.slice(-2)) : Math.floor(Math.random() * 30);
//
let evaluationData = teacher.evaluationData || [];
if (evaluationData.length !== dimensions.value.length) {
//
evaluationData = dimensions.value.map((_, dimIndex) => {
// 使ID
const offset = (dimIndex * 7 + baseValue) % 35;
// 20-95
return Math.min(95, Math.max(20, Math.floor(Math.random() * 40) + 30 + offset));
});
//
teacher.evaluationData = evaluationData;
}
chart.setOption({
radar: {
indicator: indicators,
@ -377,18 +327,31 @@ const initRadarCharts = () => {
axisLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.2)' } },
splitLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.2)' } },
name: { textStyle: { color: '#fff', fontSize: 10 } },
radius: '70%'
radius: '50%'
},
series: [
{
type: 'radar',
data: [
{
value: evaluationData,
value: teacher.result,
name: '评估结果',
areaStyle: { opacity: 0 }, //
lineStyle: { color: 'rgb(63, 196, 15)', width: 2 }, // 线RGB(63, 196, 15)
itemStyle: { color: 'rgb(63, 196, 15)' } //
itemStyle: { color: 'rgb(63, 196, 15)' }, //
label: {
show: true, //
position: 'top', //
color: '#fff', //
fontSize: 10 //
},
emphasis: {
label: {
show: true, //
fontSize: 12, //
fontWeight: 'bold' //
}
}
}
]
}
@ -432,6 +395,9 @@ const openTeacherDetail = (teacher) => {
</style>
<style scoped>
.teacher-info span{
font-size: 14px;
}
.evaluation-page {
position: absolute;
top: 0;
@ -692,7 +658,7 @@ const openTeacherDetail = (teacher) => {
/* 教师卡片网格 */
.teacher-card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 20px;
overflow-y: auto;
/* 允许卡片区域滚动 */

File diff suppressed because it is too large Load Diff

View File

@ -118,7 +118,9 @@
font-size: 16px;
text-align: center;
}
h2{
text-align: left!important;
}
.panel-header {
display: flex;
justify-content: space-between;