2025-06-09 14:59:40 +08:00
|
|
|
|
<template>
|
|
|
|
|
<div class="evaluation-page">
|
|
|
|
|
<!-- 顶部导航栏 -->
|
|
|
|
|
<header class="dashboard-header">
|
|
|
|
|
<div class="logo">
|
2025-07-17 15:32:42 +08:00
|
|
|
|
<img src="../assets/logo1.png" alt="北京理工大学" @click="handleLogoClick" />
|
|
|
|
|
<img src="../assets/logo2.png" alt="北京理工大学" @click="handleLogoClick" />
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
2025-07-17 15:32:42 +08:00
|
|
|
|
<h1 class="main-title">
|
|
|
|
|
<span class="title-text">智慧科研评估系统</span>
|
|
|
|
|
</h1>
|
|
|
|
|
<div class="header-placeholder"></div> <!-- 用于平衡布局的占位元素 -->
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<!-- 主内容区域 -->
|
|
|
|
|
<div class="content-container">
|
|
|
|
|
<!-- 右侧内容区 -->
|
|
|
|
|
<div class="main-content">
|
|
|
|
|
<!-- 搜索和操作栏 -->
|
|
|
|
|
<div class="action-bar">
|
2025-07-12 14:58:38 +08:00
|
|
|
|
<div class="sidebar-header">
|
|
|
|
|
<h1 class="sidebar-title">
|
|
|
|
|
<span class="home-link" @click="jumpToDashboard">首页</span> > 工程研究中心评估
|
|
|
|
|
</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
|
2025-06-09 14:59:40 +08:00
|
|
|
|
type="text"
|
|
|
|
|
placeholder="请输入工程研究中心名称或ID号"
|
|
|
|
|
v-model="searchQuery"
|
|
|
|
|
@input="handleSearch"
|
2025-07-12 14:58:38 +08:00
|
|
|
|
/>
|
|
|
|
|
<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> -->
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 工程研究中心卡片列表 -->
|
|
|
|
|
<div class="lab-card-grid custom-scrollbar">
|
2025-07-12 14:58:38 +08:00
|
|
|
|
<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)"
|
|
|
|
|
/>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
<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>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
<div class="card-content" @click="openLabDetail(lab)">
|
2025-06-09 14:59:40 +08:00
|
|
|
|
<div class="lab-info">
|
|
|
|
|
<div class="info-item">
|
2025-07-09 14:16:36 +08:00
|
|
|
|
<span class="info-label">中心名称:</span>
|
2025-07-04 16:52:29 +08:00
|
|
|
|
<span class="info-value">{{ lab.basicInformation.name2 }}</span>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
<div class="info-item">
|
|
|
|
|
<span class="info-label">所属领域:</span>
|
2025-07-12 14:58:38 +08:00
|
|
|
|
<span class="info-value">{{ lab.basicInformation.name3 }}</span>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
<div class="info-item">
|
|
|
|
|
<span class="info-label">所属学校:</span>
|
2025-07-04 16:52:29 +08:00
|
|
|
|
<span class="info-value">{{ lab.basicInformation.name4 }}</span>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
<div class="info-item">
|
|
|
|
|
<span class="info-label">主管部门:</span>
|
2025-07-04 16:52:29 +08:00
|
|
|
|
<span class="info-value">{{ lab.basicInformation.name5 }}</span>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
<div class="evaluation-chart" @click="openLabDetail(lab)">
|
|
|
|
|
<div :id="`lab-chart-${lab.id}`" class="radar-chart"></div> <!-- 根据lab.id确保唯一性 -->
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
2025-07-12 14:58:38 +08:00
|
|
|
|
|
2025-07-12 16:08:19 +08:00
|
|
|
|
<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>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 维度设置抽屉 -->
|
|
|
|
|
<LabDimensionDrawer
|
|
|
|
|
v-model:visible="dimensionDrawerVisible"
|
|
|
|
|
:dimensions="dimensions"
|
|
|
|
|
@save="handleSaveDimensions"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<LabDrawerDetail
|
2025-07-12 14:58:38 +08:00
|
|
|
|
v-model:visible="drawerVisible"
|
|
|
|
|
:is-edit="isEditMode"
|
|
|
|
|
:dimensions="dimensions"
|
|
|
|
|
:lab-data="selectedLab"
|
|
|
|
|
@save="handleSaveEvaluation"
|
2025-06-09 14:59:40 +08:00
|
|
|
|
/>
|
2025-07-12 14:58:38 +08:00
|
|
|
|
|
|
|
|
|
<!-- 得分比较弹窗 -->
|
|
|
|
|
<el-dialog
|
|
|
|
|
v-model="scoreComparisonDialogVisible"
|
|
|
|
|
title="得分比较"
|
2025-08-07 12:57:42 +08:00
|
|
|
|
width="80%"
|
2025-07-12 14:58:38 +08:00
|
|
|
|
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"
|
|
|
|
|
>
|
2025-08-07 12:57:42 +08:00
|
|
|
|
<el-table-column prop="category" label=""></el-table-column>
|
2025-07-12 14:58:38 +08:00
|
|
|
|
<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>
|
2025-08-07 12:57:42 +08:00
|
|
|
|
<el-table-column
|
|
|
|
|
prop="totalScore"
|
|
|
|
|
label="总分"
|
|
|
|
|
align="center">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<span :class="{
|
|
|
|
|
'max-score-in-column': Number(row.totalScore) === columnStats.totalScore?.max,
|
|
|
|
|
'min-score-in-column': Number(row.totalScore) === columnStats.totalScore?.min
|
|
|
|
|
}">
|
|
|
|
|
{{ row.totalScore }}
|
|
|
|
|
</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
2025-07-12 14:58:38 +08:00
|
|
|
|
</el-table>
|
|
|
|
|
</el-dialog>
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2025-07-12 14:58:38 +08:00
|
|
|
|
import { ref, onMounted, watch, nextTick, computed, onBeforeUnmount } from 'vue'; // 引入 onBeforeUnmount
|
2025-06-09 14:59:40 +08:00
|
|
|
|
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';
|
2025-07-12 14:58:38 +08:00
|
|
|
|
import { ElMessage, ElDialog, ElTable, ElTableColumn } from 'element-plus';
|
2025-06-09 14:59:40 +08:00
|
|
|
|
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);
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
// 得分比较相关响应式变量
|
|
|
|
|
const scoreComparisonMode = ref(false); // 是否处于得分比较模式
|
|
|
|
|
const selectedLabs = ref([]); // 存储选中的 Lab Card 数据
|
|
|
|
|
const scoreComparisonDialogVisible = ref(false); // 控制得分比较弹窗显示
|
|
|
|
|
|
|
|
|
|
// 存储 Echarts 实例,用于销毁
|
|
|
|
|
const chartInstances = new Map();
|
|
|
|
|
|
2025-07-12 16:08:19 +08:00
|
|
|
|
// 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;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2025-06-09 14:59:40 +08:00
|
|
|
|
// 打开添加评估抽屉
|
|
|
|
|
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 () => {
|
2025-06-26 14:10:48 +08:00
|
|
|
|
await loadLabs();
|
2025-06-09 14:59:40 +08:00
|
|
|
|
});
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
// 组件销毁前,销毁所有 Echarts 实例和事件监听器
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
chartInstances.forEach(chart => {
|
|
|
|
|
chart.dispose();
|
|
|
|
|
});
|
|
|
|
|
chartInstances.clear();
|
|
|
|
|
window.removeEventListener('resize', debounceResize); // 移除全局resize监听
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2025-06-09 14:59:40 +08:00
|
|
|
|
// 加载工程研究中心数据
|
|
|
|
|
const loadLabs = async () => {
|
|
|
|
|
try {
|
2025-06-26 14:10:48 +08:00
|
|
|
|
const response = await axios.get(`${getApiBaseUrl()}/admin-api/pg/evaluation-results/get-release`);
|
2025-07-12 14:58:38 +08:00
|
|
|
|
// 为每个lab添加selected属性,并确保它是一个响应式引用
|
|
|
|
|
// 同时确保 result 数组中的数据是数字类型
|
|
|
|
|
labs.value = response.data.data.map(lab => ({
|
|
|
|
|
...lab,
|
|
|
|
|
selected: false,
|
|
|
|
|
result: lab.result.map(Number) // 确保 radarData 转换为数字
|
|
|
|
|
}));
|
2025-06-09 14:59:40 +08:00
|
|
|
|
// 先更新过滤的工程研究中心列表
|
|
|
|
|
handleSearch();
|
|
|
|
|
// 给一个短暂的延时,确保DOM已经更新
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
updateAllRadarCharts();
|
|
|
|
|
}, 100);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
ElMessage.error('获取工程研究中心数据失败');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
// 节流函数 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);
|
|
|
|
|
};
|
2025-06-09 14:59:40 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
const debounceResize = debounce(() => {
|
|
|
|
|
chartInstances.forEach(chart => {
|
|
|
|
|
chart && chart.resize();
|
|
|
|
|
});
|
|
|
|
|
}, 300); // 300ms 节流
|
|
|
|
|
|
2025-06-09 14:59:40 +08:00
|
|
|
|
// 更新所有雷达图
|
|
|
|
|
const updateAllRadarCharts = () => {
|
|
|
|
|
nextTick(() => {
|
2025-07-12 14:58:38 +08:00
|
|
|
|
// 先销毁不再存在的图表实例
|
|
|
|
|
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}`);
|
2025-06-09 14:59:40 +08:00
|
|
|
|
if (!chartDom) return;
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
let chart = chartInstances.get(lab.id);
|
|
|
|
|
if (!chart) {
|
|
|
|
|
chart = echarts.init(chartDom);
|
|
|
|
|
chartInstances.set(lab.id, chart);
|
|
|
|
|
// 只在第一次创建时添加 resize 监听
|
|
|
|
|
window.addEventListener('resize', debounceResize);
|
|
|
|
|
}
|
2025-06-09 14:59:40 +08:00
|
|
|
|
|
|
|
|
|
// 从二级维度生成指标
|
2025-07-12 14:58:38 +08:00
|
|
|
|
const indicators = lab.dimension.map(name => ({ name: name, max: 50 })); // 假设最大值为50
|
2025-06-09 14:59:40 +08:00
|
|
|
|
// 准备雷达图数据
|
2025-07-12 14:58:38 +08:00
|
|
|
|
let radarData = lab.result; // 已确保为数字数组
|
2025-06-26 14:10:48 +08:00
|
|
|
|
|
2025-06-09 14:59:40 +08:00
|
|
|
|
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',
|
2025-07-04 16:52:29 +08:00
|
|
|
|
fontSize: 10
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
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)'
|
2025-06-27 15:54:55 +08:00
|
|
|
|
},
|
|
|
|
|
label: {
|
|
|
|
|
show: true, // 显示标签
|
|
|
|
|
position: 'top', // 标签位置
|
|
|
|
|
color: '#fff', // 标签颜色
|
|
|
|
|
fontSize: 10 // 标签字体大小
|
|
|
|
|
},
|
|
|
|
|
emphasis: {
|
|
|
|
|
label: {
|
|
|
|
|
show: true, // 鼠标悬停时也显示标签
|
|
|
|
|
fontSize: 12, // 鼠标悬停时字体变大
|
|
|
|
|
fontWeight: 'bold' // 鼠标悬停时字体加粗
|
|
|
|
|
}
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 搜索功能
|
|
|
|
|
const searchQuery = ref('');
|
|
|
|
|
|
|
|
|
|
// 处理搜索
|
|
|
|
|
const handleSearch = () => {
|
|
|
|
|
if (searchQuery.value === '') {
|
|
|
|
|
filteredLabs.value = labs.value;
|
|
|
|
|
} else {
|
|
|
|
|
filteredLabs.value = labs.value.filter(lab =>
|
2025-07-12 14:58:38 +08:00
|
|
|
|
(lab.basicInformation.name2 && lab.basicInformation.name2.includes(searchQuery.value)) ||
|
2025-07-04 16:52:29 +08:00
|
|
|
|
(lab.basicInformation.name1 && lab.basicInformation.name1.includes(searchQuery.value))
|
2025-06-09 14:59:40 +08:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在过滤后调用更新雷达图
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
updateAllRadarCharts();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 打开工程研究中心详情抽屉
|
2025-06-27 15:54:55 +08:00
|
|
|
|
const openLabDetail = async (lab) => {
|
2025-07-12 14:58:38 +08:00
|
|
|
|
// 如果在比较模式,点击卡片不打开详情
|
|
|
|
|
if (scoreComparisonMode.value) return;
|
2025-06-09 14:59:40 +08:00
|
|
|
|
selectedLab.value = lab;
|
|
|
|
|
isEditMode.value = true;
|
|
|
|
|
drawerVisible.value = true;
|
|
|
|
|
};
|
2025-07-12 14:58:38 +08:00
|
|
|
|
|
|
|
|
|
// --- 得分比较功能实现 ---
|
|
|
|
|
|
|
|
|
|
// 切换得分比较模式
|
|
|
|
|
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 = {
|
2025-08-07 12:57:42 +08:00
|
|
|
|
category: `${lab.basicInformation.name0}-${lab.basicInformation.name4}-${lab.basicInformation.name2}`
|
2025-07-12 14:58:38 +08:00
|
|
|
|
};
|
2025-08-07 12:57:42 +08:00
|
|
|
|
|
|
|
|
|
if (Array.isArray(lab.result)) {
|
|
|
|
|
let total = 0;
|
|
|
|
|
lab.result.forEach((score, index) => {
|
|
|
|
|
const numericScore = Number(score) || 0;
|
|
|
|
|
row[`score${index + 1}`] = numericScore;
|
|
|
|
|
total += numericScore;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 修改这里:使用Math.round()四舍五入并转换为整数
|
|
|
|
|
row.totalScore = Math.round(total);
|
|
|
|
|
} else {
|
|
|
|
|
row.totalScore = 0; // 设置为整数0
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
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)
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-08-07 12:57:42 +08:00
|
|
|
|
// 添加总分统计
|
|
|
|
|
const totalScores = scoreComparisonTableData.value.map(row => Number(row.totalScore));
|
|
|
|
|
if (totalScores.length > 0) {
|
|
|
|
|
stats.totalScore = {
|
|
|
|
|
max: Math.max(...totalScores),
|
|
|
|
|
min: Math.min(...totalScores)
|
|
|
|
|
};
|
|
|
|
|
}
|
2025-07-12 14:58:38 +08:00
|
|
|
|
// 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();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style>
|
2025-07-12 14:58:38 +08:00
|
|
|
|
/* common.css 保持不变,用于全局样式 */
|
2025-06-09 14:59:40 +08:00
|
|
|
|
@import './common.css';
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2025-07-12 14:58:38 +08:00
|
|
|
|
.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;
|
|
|
|
|
}
|
2025-06-09 14:59:40 +08:00
|
|
|
|
.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);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-17 15:32:42 +08:00
|
|
|
|
/* .dashboard-header {
|
2025-06-09 14:59:40 +08:00
|
|
|
|
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;
|
2025-07-17 15:32:42 +08:00
|
|
|
|
} */
|
2025-06-09 14:59:40 +08:00
|
|
|
|
|
|
|
|
|
.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;
|
2025-07-12 14:58:38 +08:00
|
|
|
|
max-height: none;
|
|
|
|
|
height: auto;
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 搜索和操作栏 */
|
|
|
|
|
.action-bar {
|
|
|
|
|
height: 64px;
|
|
|
|
|
display: flex;
|
2025-07-12 14:58:38 +08:00
|
|
|
|
justify-content: space-between; /* 使得左中右元素分散对齐 */
|
2025-06-09 14:59:40 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
|
|
|
|
|
/* 新增:得分比较按钮组容器,与搜索框分离 */
|
|
|
|
|
.score-comparison-wrapper {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 10px; /* 按钮之间的间距 */
|
|
|
|
|
margin-right: 20px; /* 与搜索框的间距 */
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-09 14:59:40 +08:00
|
|
|
|
.search-box {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
2025-07-12 14:58:38 +08:00
|
|
|
|
width: 300px; /* 调整宽度,不再包含得分比较按钮 */
|
2025-06-09 14:59:40 +08:00
|
|
|
|
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 {
|
2025-07-12 14:58:38 +08:00
|
|
|
|
display: flex; /* 使用 flex 布局 */
|
|
|
|
|
flex-wrap: wrap; /* 允许项目换行 */
|
|
|
|
|
gap: 20px; /* 项目间的间距 */
|
2025-06-09 14:59:40 +08:00
|
|
|
|
padding: 20px;
|
|
|
|
|
background-color: #262F50;
|
|
|
|
|
border-radius: 10px;
|
2025-07-12 14:58:38 +08:00
|
|
|
|
overflow-y: auto;
|
|
|
|
|
justify-content: flex-start;
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.lab-card {
|
2025-07-12 14:58:38 +08:00
|
|
|
|
box-sizing: border-box;
|
2025-07-31 16:20:36 +08:00
|
|
|
|
flex: 0 0 calc((100% - 41px) / 3);
|
2025-06-09 14:59:40 +08:00
|
|
|
|
background-color: #1f3266;
|
|
|
|
|
border-radius: 8px;
|
2025-07-31 16:20:36 +08:00
|
|
|
|
|
2025-06-09 14:59:40 +08:00
|
|
|
|
border: 1px solid rgba(73,134,255,0.3);
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
2025-07-12 14:58:38 +08:00
|
|
|
|
min-height: 350px;
|
2025-06-09 14:59:40 +08:00
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: transform 0.2s, box-shadow 0.2s;
|
2025-07-12 16:08:19 +08:00
|
|
|
|
position: relative; /* 添加此行,以便tooltip定位 */
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.lab-card:hover {
|
|
|
|
|
transform: translateY(-3px);
|
|
|
|
|
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
/* 复选框容器样式 */
|
|
|
|
|
.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; /* 移除默认外边距 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-06-09 14:59:40 +08:00
|
|
|
|
.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);
|
2025-07-12 14:58:38 +08:00
|
|
|
|
/* 确保ID不被复选框遮挡,如果复选框在左边,这里可能需要调整padding-left或margin-left */
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.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 {
|
2025-07-11 14:46:04 +08:00
|
|
|
|
width: 100%;
|
2025-06-09 14:59:40 +08:00
|
|
|
|
display: flex;
|
2025-07-11 14:46:04 +08:00
|
|
|
|
flex-direction: row; /* 修改为横向排列 */
|
|
|
|
|
flex-wrap: wrap; /* 允许元素换行 */
|
2025-06-09 14:59:40 +08:00
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.info-item {
|
|
|
|
|
margin-bottom: 5px;
|
2025-07-11 14:46:04 +08:00
|
|
|
|
width: calc(50% - 5px); /* 每个元素占一半宽度,减去 gap 的一半 */
|
2025-06-09 14:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-12 14:58:38 +08:00
|
|
|
|
/* 得分比较按钮样式 */
|
|
|
|
|
.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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-09 14:59:40 +08:00
|
|
|
|
@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%;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-12 14:58:38 +08:00
|
|
|
|
.searchbox{
|
|
|
|
|
display: flex;
|
|
|
|
|
}
|
2025-07-12 16:08:19 +08:00
|
|
|
|
|
|
|
|
|
/* 评估摘要的容器,用于定位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; /* 与文本的距离 */
|
2025-07-31 16:20:36 +08:00
|
|
|
|
width: 25vw;
|
2025-07-12 16:08:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 气泡的小箭头 */
|
|
|
|
|
.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;
|
2025-07-12 14:58:38 +08:00
|
|
|
|
}
|
2025-06-09 14:59:40 +08:00
|
|
|
|
</style>
|