dashboard/src/components/LabDetail.vue

1208 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="evaluation-page">
<!-- 顶部导航栏 -->
<header class="dashboard-header">
<div class="logo">
<img src="../assets/logo1.png" alt="北京理工大学" @click="handleLogoClick" />
<img src="../assets/logo2.png" alt="北京理工大学" @click="handleLogoClick" />
</div>
<h1 class="main-title">
<span class="title-text">智慧科研评估系统</span>
</h1>
<div class="header-placeholder"></div> <!-- 用于平衡布局的占位元素 -->
</header>
<!-- 主内容区域 -->
<div class="content-container">
<!-- 右侧内容区 -->
<div class="main-content">
<!-- 搜索和操作栏 -->
<div class="action-bar">
<div class="sidebar-header">
<h1 class="sidebar-title">
<span class="home-link" @click="jumpToDashboard">首页</span>&nbsp;>&nbsp;工程研究中心评估
</h1>
</div>
<div class="searchbox">
<!-- 新增得分比较按钮组 -->
<div class="score-comparison-wrapper">
<el-button
type="primary"
v-if="!scoreComparisonMode"
class="compare-score-btn"
@click="toggleScoreComparisonMode"
>
得分比较
</el-button>
<template v-else>
<el-button class="compare-score-btn close-btn" @click="toggleScoreComparisonMode">
关闭
</el-button>
<el-button
class="compare-score-btn start-compare-btn"
@click="openScoreComparisonDialog"
:disabled="selectedLabs.length < 2"
:class="{ 'disabled-btn': selectedLabs.length < 2 }"
>
开始比较 ({{ selectedLabs.length }})
</el-button>
</template>
</div>
<!-- 搜索框 -->
<div class="search-box">
<input
type="text"
placeholder="请输入工程研究中心名称或ID号"
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" d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
</svg>
</button>
</div>
<!-- <button class="add-evaluation-btn" @click="openAddEvaluationDrawer">
新增评估
</button> -->
</div>
</div>
<!-- 工程研究中心卡片列表 -->
<div class="lab-card-grid custom-scrollbar">
<div v-for="(lab) in filteredLabs" :key="lab.id" class="lab-card">
<!-- 复选框 -->
<div v-if="scoreComparisonMode" class="card-checkbox-wrapper">
<input
type="checkbox"
v-model="lab.selected"
@change="handleLabSelection(lab)"
/>
</div>
<div class="card-header" @click="openLabDetail(lab)">
<span class="lab-id" :style="scoreComparisonMode?'margin-left: 40px;':''">ID: {{ lab.basicInformation.name1 || lab.id }}</span>
<span class="total-score">年份: <span class="score-value">{{ lab.basicInformation.name0 }}</span></span>
</div>
<div class="card-content" @click="openLabDetail(lab)">
<div class="lab-info">
<div class="info-item">
<span class="info-label">中心名称:</span>
<span class="info-value">{{ lab.basicInformation.name2 }}</span>
</div>
<div class="info-item">
<span class="info-label">所属领域:</span>
<span class="info-value">{{ lab.basicInformation.name3 }}</span>
</div>
<div class="info-item">
<span class="info-label">所属学校:</span>
<span class="info-value">{{ lab.basicInformation.name4 }}</span>
</div>
<div class="info-item">
<span class="info-label">主管部门:</span>
<span class="info-value">{{ lab.basicInformation.name5 }}</span>
</div>
</div>
</div>
<div class="evaluation-chart" @click="openLabDetail(lab)">
<div :id="`lab-chart-${lab.id}`" class="radar-chart"></div> <!-- 根据lab.id确保唯一性 -->
</div>
<div class="evaluation-info-wrapper"
@mouseenter="showTooltip(lab.id, lab.abstracts)"
@mouseleave="hideTooltip">
<div class="evaluation-info">评估摘要{{ lab.abstracts }}</div>
<div v-if="currentTooltip.labId === lab.id && currentTooltip.visible" class="tooltip">
{{ currentTooltip.content }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 维度设置抽屉 -->
<LabDimensionDrawer
v-model:visible="dimensionDrawerVisible"
:dimensions="dimensions"
@save="handleSaveDimensions"
/>
<LabDrawerDetail
v-model:visible="drawerVisible"
:is-edit="isEditMode"
:dimensions="dimensions"
:lab-data="selectedLab"
@save="handleSaveEvaluation"
/>
<!-- 得分比较弹窗 -->
<el-dialog
v-model="scoreComparisonDialogVisible"
title="得分比较"
width="70%"
center
:append-to-body="true"
class="score-comparison-dialog"
>
<el-table
:data="scoreComparisonTableData"
style="width: 100%"
border
stripe
class="default-table score-comparison-table"
:row-class-name="tableRowClassName"
>
<el-table-column prop="category" label="" width="180"></el-table-column>
<el-table-column
v-for="(header) in scoreComparisonHeaders"
:key="header.prop"
:prop="header.prop"
:label="header.label"
align="center"
>
<template #default="{ row }">
<span :class="{
'max-score-in-column': Number(row[header.prop]) === columnStats[header.prop]?.max,
'min-score-in-column': Number(row[header.prop]) === columnStats[header.prop]?.min
}">
{{ row[header.prop] }}
</span>
</template>
</el-table-column>
</el-table>
</el-dialog>
</template>
<script setup>
import { ref, onMounted, watch, nextTick, computed, onBeforeUnmount } from 'vue'; // 引入 onBeforeUnmount
import * as echarts from 'echarts/core';
import { RadarChart } from 'echarts/charts';
import LabDrawerDetail from './LabDrawerDetail.vue';
import LabDimensionDrawer from './LabDimensionDrawer.vue';
import {
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent
} from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
import axios from 'axios';
import { ElMessage, ElDialog, ElTable, ElTableColumn } from 'element-plus';
import { getApiBaseUrl } from '../config'; // 导入API基础URL函数
// 注册必要的 echarts 组件
echarts.use([
RadarChart,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
CanvasRenderer
]);
const drawerVisible = ref(false);
const isEditMode = ref(false);
const selectedLab = ref(null);
const dimensionDrawerVisible = ref(false);
// 得分比较相关响应式变量
const scoreComparisonMode = ref(false); // 是否处于得分比较模式
const selectedLabs = ref([]); // 存储选中的 Lab Card 数据
const scoreComparisonDialogVisible = ref(false); // 控制得分比较弹窗显示
// 存储 Echarts 实例,用于销毁
const chartInstances = new Map();
// Tooltip 相关
const currentTooltip = ref({
labId: null,
content: '',
visible: false
});
const showTooltip = (labId, content) => {
currentTooltip.value = {
labId: labId,
content: content,
visible: true
};
};
const hideTooltip = () => {
currentTooltip.value.visible = false;
};
// 打开添加评估抽屉
const openAddEvaluationDrawer = () => {
isEditMode.value = false;
selectedLab.value = null;
drawerVisible.value = true;
};
// 打开维度设置抽屉
const openDimensionDrawer = () => {
dimensionDrawerVisible.value = true;
};
// 处理保存评估
const handleSaveEvaluation = async (data) => {
// 接收到保存事件后,直接从服务器重新加载最新数据
// 而不是手动更新本地数据
await loadLabs();
// 关闭抽屉
drawerVisible.value = false;
// 显示成功消息
ElMessage.success(isEditMode.value ? '工程研究中心评估数据更新成功' : '工程研究中心评估数据新增成功');
};
// 处理保存维度
const handleSaveDimensions = (newDimensions) => {
dimensions.value = newDimensions;
// 更新所有雷达图
updateAllRadarCharts();
};
// 向父组件发送页面切换事件
const emit = defineEmits(['navigate', 'back-to-dashboard', 'logout']);
// 跳转到仪表盘页面
const jumpToDashboard = () => {
emit('back-to-dashboard');
};
// 处理Logo点击事件
const handleLogoClick = () => {
emit('logout');
};
// 评估维度数据
const dimensions = ref([]);
// 工程研究中心数据
const labs = ref([]);
// 根据搜索过滤工程研究中心
const filteredLabs = ref([]);
// 在组件挂载时获取维度数据
onMounted(async () => {
await loadLabs();
});
// 组件销毁前,销毁所有 Echarts 实例和事件监听器
onBeforeUnmount(() => {
chartInstances.forEach(chart => {
chart.dispose();
});
chartInstances.clear();
window.removeEventListener('resize', debounceResize); // 移除全局resize监听
});
// 加载工程研究中心数据
const loadLabs = async () => {
try {
const response = await axios.get(`${getApiBaseUrl()}/admin-api/pg/evaluation-results/get-release`);
// 为每个lab添加selected属性并确保它是一个响应式引用
// 同时确保 result 数组中的数据是数字类型
labs.value = response.data.data.map(lab => ({
...lab,
selected: false,
result: lab.result.map(Number) // 确保 radarData 转换为数字
}));
// 先更新过滤的工程研究中心列表
handleSearch();
// 给一个短暂的延时确保DOM已经更新
setTimeout(() => {
updateAllRadarCharts();
}, 100);
} catch (error) {
ElMessage.error('获取工程研究中心数据失败');
}
};
// 节流函数 for resize
const debounce = (fn, delay) => {
let timer = null;
return function() {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
};
const debounceResize = debounce(() => {
chartInstances.forEach(chart => {
chart && chart.resize();
});
}, 300); // 300ms 节流
// 更新所有雷达图
const updateAllRadarCharts = () => {
nextTick(() => {
// 先销毁不再存在的图表实例
const currentLabIds = new Set(filteredLabs.value.map(lab => lab.id));
chartInstances.forEach((chart, id) => {
if (!currentLabIds.has(id)) {
chart.dispose();
chartInstances.delete(id);
}
});
filteredLabs.value.forEach((lab) => {
const chartDom = document.getElementById(`lab-chart-${lab.id}`);
if (!chartDom) return;
let chart = chartInstances.get(lab.id);
if (!chart) {
chart = echarts.init(chartDom);
chartInstances.set(lab.id, chart);
// 只在第一次创建时添加 resize 监听
window.addEventListener('resize', debounceResize);
}
// 从二级维度生成指标
const indicators = lab.dimension.map(name => ({ name: name, max: 50 })); // 假设最大值为50
// 准备雷达图数据
let radarData = lab.result; // 已确保为数字数组
chart.setOption({
radar: {
indicator: indicators,
splitArea: {
show: false
},
axisLine: {
lineStyle: {
color: 'rgba(211, 253, 250, 0.8)'
}
},
splitLine: {
lineStyle: {
color: 'rgba(211, 253, 250, 0.8)'
}
},
name: {
textStyle: {
color: '#fff',
fontSize: 10
}
}
},
series: [
{
type: 'radar',
data: [
{
value: radarData,
name: '评估结果',
areaStyle: {
color: 'rgba(255, 0, 255, 0.3)'
},
lineStyle: {
color: 'rgba(255, 0, 255, 0.8)',
width: 1
},
itemStyle: {
color: 'rgba(255, 0, 255, 0.8)'
},
label: {
show: true, // 显示标签
position: 'top', // 标签位置
color: '#fff', // 标签颜色
fontSize: 10 // 标签字体大小
},
emphasis: {
label: {
show: true, // 鼠标悬停时也显示标签
fontSize: 12, // 鼠标悬停时字体变大
fontWeight: 'bold' // 鼠标悬停时字体加粗
}
}
}
]
}
]
});
});
});
};
// 搜索功能
const searchQuery = ref('');
// 处理搜索
const handleSearch = () => {
if (searchQuery.value === '') {
filteredLabs.value = labs.value;
} else {
filteredLabs.value = labs.value.filter(lab =>
(lab.basicInformation.name2 && lab.basicInformation.name2.includes(searchQuery.value)) ||
(lab.basicInformation.name1 && lab.basicInformation.name1.includes(searchQuery.value))
);
}
// 在过滤后调用更新雷达图
nextTick(() => {
updateAllRadarCharts();
});
};
// 打开工程研究中心详情抽屉
const openLabDetail = async (lab) => {
// 如果在比较模式,点击卡片不打开详情
if (scoreComparisonMode.value) return;
selectedLab.value = lab;
isEditMode.value = true;
drawerVisible.value = true;
};
// --- 得分比较功能实现 ---
// 切换得分比较模式
const toggleScoreComparisonMode = () => {
scoreComparisonMode.value = !scoreComparisonMode.value;
if (!scoreComparisonMode.value) {
// 关闭模式时,清空所有选中状态
filteredLabs.value.forEach(lab => {
lab.selected = false;
});
selectedLabs.value = [];
}
};
// 处理 Lab Card 选中状态变化
const handleLabSelection = (lab) => {
// 使用 Vue 的响应式方法确保数组更新被追踪
if (lab.selected) {
selectedLabs.value.push(lab);
} else {
selectedLabs.value = selectedLabs.value.filter(item => item.id !== lab.id);
}
};
// 计算得分比较表格的横向表头
const scoreComparisonHeaders = computed(() => {
if (selectedLabs.value.length === 0) {
return [];
}
// 取第一个选中 Lab 的 dimension 作为横向表头
const firstLabDimensions = selectedLabs.value[0].dimension;
return firstLabDimensions.map((dim, index) => ({
prop: `score${index + 1}`, // 动态生成属性名,例如 score1, score2
label: dim
}));
});
// 计算得分比较表格的数据
const scoreComparisonTableData = computed(() => {
if (selectedLabs.value.length === 0) {
return [];
}
return selectedLabs.value.map(lab => {
const row = {
category: `${lab.basicInformation.name0}-${lab.basicInformation.name2}` // 纵向表头是年份-中心名称
};
// 将 radarData 映射到 row 的动态属性上
lab.result.forEach((score, index) => {
row[`score${index + 1}`] = score;
});
return row;
});
});
// 新增:计算每列的最大值和最小值
const columnStats = computed(() => {
const stats = {};
if (scoreComparisonTableData.value.length === 0 || scoreComparisonHeaders.value.length === 0) {
return stats;
}
scoreComparisonHeaders.value.forEach(header => {
const prop = header.prop;
// 确保在计算最大最小值时,所有值都是数字
const values = scoreComparisonTableData.value.map(row => Number(row[prop]));
if (values.length > 0) {
stats[prop] = {
max: Math.max(...values),
min: Math.min(...values)
};
}
});
// console.log("Calculated columnStats:", stats); // 调试输出
return stats;
});
// 表格行样式,用于隔行高亮
const tableRowClassName = ({ rowIndex }) => {
if (rowIndex % 2 === 1) {
return 'striped-row'; // 奇数行应用条纹样式
}
return '';
};
// 打开得分比较弹窗
const openScoreComparisonDialog = () => {
if (selectedLabs.value.length < 2) {
ElMessage.warning('请至少选择两个工程研究中心进行比较!');
return;
}
scoreComparisonDialogVisible.value = true;
};
// 监听 filteredLabs 变化,更新雷达图
// 这里不再需要深度监听,因为 lab.id 变化不会频繁,内部数据的变化由 ECharts 自身处理
watch(filteredLabs, () => {
nextTick(() => {
updateAllRadarCharts();
});
});
</script>
<style>
/* common.css 保持不变,用于全局样式 */
@import './common.css';
</style>
<style scoped>
.default-table {
background-color: white; /* 表格背景色为白色 */
color: black; /* 文字颜色为黑色 */
border-radius: 8px;
overflow: hidden;
}
/* 新增:得分比较表格的特定样式 */
.score-comparison-table {
max-height: 60vh; /* 设置最大高度例如视口高度的60% */
overflow-y: auto; /* 当内容超出最大高度时,显示垂直滚动条 */
overflow-x: hidden;
}
.default-table th.el-table__cell {
background-color: #f5f7fa !important; /* 表头背景色浅灰 */
color: black !important;
font-weight: bold;
border-right: 1px solid #ebeef5 !important;
border-bottom: 1px solid #ebeef5 !important;
}
.default-table td.el-table__cell {
background-color: white !important; /* 单元格背景色白色 */
color: black !important;
border-right: 1px solid #ebeef5 !important;
border-bottom: 1px solid #ebeef5 !important;
}
.default-table tr:hover > td {
background-color: #f0f2f5 !important; /* 行悬停背景色更浅的灰色 */
}
/* 条纹样式 */
.default-table.el-table--striped .el-table__body tr.striped-row td {
background-color: #fafafa !important; /* 条纹行背景色,比默认单元格略深 */
}
/* 最大值和最小值高亮 */
.max-score-in-column {
color: red; /* 红色 */
font-weight: bold;
}
.min-score-in-column {
color: blue; /* 蓝色 */
font-weight: bold;
}
.evaluation-page {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: flex;
flex-direction: column;
background-color: #0c1633;
color: white;
overflow: hidden; /* 防止页面整体出现滚动条 */
}
/* 自定义滚动条样式 */
.custom-scrollbar {
scrollbar-width: thin;
scrollbar-color: rgba(73,134,255,0.5) rgba(38,47,80,0.3);
}
.custom-scrollbar::-webkit-scrollbar {
width: 8px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: rgba(38,47,80,0.3);
border-radius: 4px;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background-color: rgba(73,134,255,0.5);
border-radius: 4px;
border: 2px solid rgba(38,47,80,0.3);
}
/* .dashboard-header {
height: 60px;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
.logo {
display: flex;
align-items: center;
position: relative;
width: 100%;
}
.logo img {
height: 40px;
margin-right: 10px;
}
.main-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 28px;
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
display: flex;
align-items: center;
white-space: nowrap;
}
.title-line {
border: 2px solid rgba(73,134,255,1);
width: 150px;
}
.title-text {
margin: 0 30px;
} */
.content-container {
display: flex;
flex: 1;
padding: 20px;
overflow: hidden;
gap: 20px;
}
/* 特定于LabDetail的样式 */
.sidebar-header {
height: 64px;
display: flex;
align-items: center;
justify-content: left;
background-color: transparent;
}
.sidebar-title {
font-size: 22px;
font-weight: bold;
color: white;
margin: 0;
text-align: left;
}
.home-link {
text-decoration: underline;
cursor: pointer;
color: #4986ff;
}
.dimension-sidebar {
width: 280px;
display: flex;
flex-direction: column;
max-height: calc(100vh - 100px); /* 限制最大高度 */
}
.dimension-content {
flex: 1;
background-color: #262F50;
border-radius: 10px;
display: flex;
flex-direction: column;
overflow: hidden; /* 加上这个防止内容溢出 */
}
.dimension-section-title {
margin: 15px;
font-size: 16px;
text-align: center;
padding-bottom: 10px;
border-bottom: 1px solid rgba(73,134,255,0.3);
}
.dimension-list {
padding: 0 15px 15px 15px;
display: flex;
flex-direction: column;
gap: 15px;
overflow-y: auto; /* 允许列表滚动 */
flex: 1; /* 让列表占满剩余空间 */
}
.dimension-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 10px;
background-color: rgba(73,134,255,0.1);
border-radius: 4px;
border-left: 3px solid #4986ff;
cursor: pointer; /* 添加指针样式,提示可点击 */
transition: background-color 0.2s;
}
.dimension-item:hover {
background-color: rgba(73,134,255,0.2);
}
.dimension-checkbox {
display: flex;
align-items: center;
}
.dimension-checkbox input[type="checkbox"] {
margin-right: 8px;
accent-color: #4986ff;
}
.dimension-weight {
display: flex;
align-items: center;
color: #4986ff;
}
.weight-label {
margin-right: 5px;
}
.weight-value {
font-weight: bold;
}
.dimension-add {
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
background-color: rgba(73,134,255,0.1);
border-radius: 4px;
cursor: pointer;
margin-top: 10px;
transition: background-color 0.2s;
}
.dimension-add:hover {
background-color: rgba(73,134,255,0.2);
}
.add-icon {
font-size: 18px;
margin-right: 5px;
color: #4986ff;
}
.add-text {
color: #4986ff;
font-weight: bold;
}
/* 右侧内容区 */
.main-content {
flex: 1;
display: flex;
flex-direction: column;
padding: 0 10px;
overflow: hidden;
max-height: none;
height: auto;
}
/* 搜索和操作栏 */
.action-bar {
height: 64px;
display: flex;
justify-content: space-between; /* 使得左中右元素分散对齐 */
align-items: center;
}
/* 新增:得分比较按钮组容器,与搜索框分离 */
.score-comparison-wrapper {
display: flex;
gap: 10px; /* 按钮之间的间距 */
margin-right: 20px; /* 与搜索框的间距 */
}
.search-box {
display: flex;
align-items: center;
width: 300px; /* 调整宽度,不再包含得分比较按钮 */
background-color: rgba(255,255,255,0.1);
border-radius: 20px;
overflow: hidden;
}
.search-box input {
flex: 1;
background: transparent;
border: none;
padding: 10px 15px;
color: white;
outline: none;
}
.search-box input::placeholder {
color: rgba(255,255,255,0.5);
}
.search-button {
background: transparent;
border: none;
color: white;
padding: 0 15px;
cursor: pointer;
display: flex;
align-items: center;
}
.search-icon {
fill: white;
}
.add-evaluation-btn {
background-color: rgba(14,62,167,1);
color: rgba(255,255,255,1);
border: 1px solid rgba(73,134,255,1);
border-radius: 10px;
padding: 8px 15px;
font-size: 14px;
text-align: center;
font-family: PingFangSC-regular;
cursor: pointer;
}
/* 工程研究中心卡片网格 */
.lab-card-grid {
display: flex; /* 使用 flex 布局 */
flex-wrap: wrap; /* 允许项目换行 */
gap: 20px; /* 项目间的间距 */
padding: 20px;
background-color: #262F50;
border-radius: 10px;
overflow-y: auto;
justify-content: flex-start;
}
.lab-card {
box-sizing: border-box;
flex: 0 0 calc((100% - 41px) / 3);
background-color: #1f3266;
border-radius: 8px;
border: 1px solid rgba(73,134,255,0.3);
display: flex;
flex-direction: column;
min-height: 350px;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
position: relative; /* 添加此行以便tooltip定位 */
}
.lab-card:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
/* 复选框容器样式 */
.card-checkbox-wrapper {
position: absolute;
top: 4px; /* 距离顶部 */
left: 8px; /* 距离左侧 */
z-index: 10; /* 确保在最上层 */
background-color: rgba(0, 0, 0, 0.3); /* 半透明黑色背景 */
border-radius: 4px;
padding: 4px;
display: flex;
align-items: center;
justify-content: center;
width: 28px; /* 确保有足够点击区域 */
height: 28px;
}
.card-checkbox-wrapper input[type="checkbox"] {
width: 20px;
height: 20px;
cursor: pointer;
accent-color: #4986ff; /* 改变复选框颜色 */
margin: 0; /* 移除默认外边距 */
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
background-color: rgba(73,134,255,0.1);
border-bottom: 1px solid rgba(73,134,255,0.3);
}
.lab-id {
font-size: 14px;
color: rgba(255,255,255,0.7);
/* 确保ID不被复选框遮挡如果复选框在左边这里可能需要调整padding-left或margin-left */
}
.total-score {
font-size: 14px;
color: rgba(255,255,255,0.7);
}
.score-value {
font-size: 18px;
font-weight: bold;
color: rgb(63, 196, 15);
}
.card-content {
padding: 15px;
display: flex;
gap: 15px;
}
.lab-image {
width: 40%;
height: 120px;
background-color: rgba(73,134,255,0.1);
border-radius: 4px;
overflow: hidden;
}
.lab-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.lab-info {
width: 100%;
display: flex;
flex-direction: row; /* 修改为横向排列 */
flex-wrap: wrap; /* 允许元素换行 */
gap: 10px;
}
.info-item {
margin-bottom: 5px;
width: calc(50% - 5px); /* 每个元素占一半宽度,减去 gap 的一半 */
}
.info-label {
color: rgba(255,255,255,0.7);
margin-right: 5px;
}
.info-value {
color: white;
font-weight: 500;
}
.evaluation-chart {
flex: 1; /* 让雷达图占据剩余空间 */
min-height: 200px; /* 确保雷达图最小高度 */
padding: 10px 15px 15px;
display: flex;
align-items: center;
justify-content: center;
}
.radar-chart {
width: 100%;
height: 100%;
min-height: 180px;
}
/* 二级维度样式 */
.primary-dimension {
flex-direction: column;
align-items: stretch;
margin-bottom: 10px;
}
.dimension-header {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.dimension-name {
font-weight: 500;
}
.dimension-expand {
color: #4986ff;
font-size: 12px;
}
.sub-dimensions {
margin-top: 5px;
margin-left: 15px;
}
.sub-dimension {
background-color: rgba(255,255,255,0.05);
border-left: 2px solid rgba(73,134,255,0.6);
margin-bottom: 5px;
}
/* 得分比较按钮样式 */
.compare-score-btn {
background-color: rgb(13, 70, 192);
border: none;
color: rgba(255,255,255,1);
border-radius: 10px;
padding: 8px 15px;
font-size: 14px;
text-align: center;
font-family: PingFangSC-regular;
cursor: pointer;
transition: background-color 0.2s, border-color 0.2s;
}
.compare-score-btn:hover {
background-color: rgba(14,62,167,0.8);
}
.compare-score-btn.close-btn {
background-color: #f44336; /* 红色 */
border-color: #f44336;
}
.compare-score-btn.close-btn:hover {
background-color: #d32f2f;
}
.compare-score-btn.start-compare-btn {
background-color: #4CAF50; /* 绿色 */
border-color: #4CAF50;
}
.compare-score-btn.start-compare-btn:hover {
background-color: #388E3C;
}
.compare-score-btn.disabled-btn {
background-color: #616161; /* 灰色 */
border-color: #616161;
cursor: not-allowed;
opacity: 0.7;
}
@media (max-width: 1200px) {
.lab-card-grid {
grid-template-columns: 1fr;
}
.dimension-sidebar {
width: 100%;
height: auto;
max-height: 300px;
margin-bottom: 10px;
}
.sidebar-header {
height: auto;
padding: 10px 0;
}
.card-content {
flex-direction: column;
}
.lab-image, .lab-info {
width: 100%;
}
}
.searchbox{
display: flex;
}
/* 评估摘要的容器用于定位tooltip */
.evaluation-info-wrapper {
position: relative;
padding: 20px 15px; /* 保持原有的padding */
}
/* 评估摘要文本样式 */
.evaluation-info {
white-space: normal; /* 允许文本正常换行 */
overflow: hidden; /* 隐藏超出容器的内容 */
text-overflow: ellipsis; /* 显示省略号 */
display: -webkit-box;
-webkit-line-clamp: 2; /* 限制文本为2行 */
-webkit-box-orient: vertical;
font-size: 12px;
}
/* 鼠标悬停时显示的气泡样式 */
.tooltip {
position: absolute;
bottom: 100%; /* 定位在文本上方 */
left: 50%;
transform: translateX(-50%);
background-color: rgba(0, 0, 0, 0.85);
color: #fff;
padding: 8px 12px;
border-radius: 4px;
white-space: pre-wrap; /* 保持文本换行 */
z-index: 100;
max-width: 90%; /* 限制最大宽度 */
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
font-size: 14px;
line-height: 1.5;
pointer-events: none; /* 确保不影响鼠标事件 */
margin-bottom: 10px; /* 与文本的距离 */
width: 25vw;
}
/* 气泡的小箭头 */
.tooltip::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: rgba(0, 0, 0, 0.85) transparent transparent transparent;
}
</style>