dashboard/src/components/LabDrawerDetail.vue
2025-06-09 14:59:40 +08:00

1495 lines
45 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
<el-drawer
v-model="drawerVisible"
:title="drawerTitle"
direction="rtl"
size="900px"
:before-close="handleClose"
custom-class="lab-drawer"
>
<div class="drawer-content">
<!-- 标签导航 -->
<div class="tab-navigation">
<div
v-for="(tab, index) in tabs"
:key="index"
:class="['tab-item', { active: activeTab === tab.value }]"
@click="activeTab = tab.value"
>
{{ tab.label }}
</div>
</div>
<!-- URL输入标签页 -->
<div v-if="activeTab === 'url'" class="tab-content">
<div class="url-input-container">
<el-input
v-model="urlInput"
placeholder="请输入URL"
class="url-input"
/>
<el-button
type="primary"
@click="fetchDataFromUrl"
class="send-button"
>
发送
</el-button>
</div>
</div>
<!-- 上传文档标签页 -->
<div v-else-if="activeTab === 'upload'" class="tab-content">
<el-upload
class="upload-container"
action="#"
:auto-upload="false"
:on-change="handleFileChange"
v-if="false"
>
<el-button type="primary" style="display: inline-block;">选择文件True</el-button>
<div class="el-upload__tip" style="display: inline-block;margin-left: 30px;width: 100%;">请上传文档支持PDFDOCDOCX格式</div>
</el-upload>
<el-upload
class="upload-container"
action="#"
:auto-upload="false"
:on-change="fakeFileChange"
>
<el-button type="primary" style="display: inline-block;">选择文件</el-button>
<div class="el-upload__tip" style="display: inline-block;margin-left: 30px;width: 100%;">请上传文档支持PDFDOCDOCX格式</div>
</el-upload>
</div>
<!-- 手动输入标签页 -->
<div v-else class="tab-content">
<div class="manual-input-tip">请手动填写以下信息</div>
</div>
<!-- 工程研究中心信息表单 - 仅在数据加载后显示 -->
<div v-if="formData.name || activeTab == 'manual'" class="lab-info-form">
<div class="form-header">
<div class="image-section">
<div class="lab-image">
<img :src="formData.image || defaultImage" alt="工程研究中心照片" />
</div>
</div>
<div class="basic-info">
<div class="form-row">
<div class="form-item">
<span class="label">编号:</span>
<el-input v-model="formData.idcode" placeholder="请输入编号" />
</div>
<div class="form-item">
<span class="label">工程研究中心名称:</span>
<el-input v-model="formData.name" placeholder="请输入工程研究中心名称" />
</div>
</div>
<div class="form-row">
<div class="form-item">
<span class="label">所属领域:</span>
<el-input v-model="formData.field" placeholder="请输入所属领域" />
</div>
<div class="form-item">
<span class="label">所属学校:</span>
<el-input v-model="formData.school" placeholder="请输入所属学校" />
</div>
<div class="form-item">
<span class="label">主管部门:</span>
<el-input v-model="formData.department" placeholder="请输入主管部门" />
</div>
</div>
</div>
</div>
<!-- 工程研究中心年度信息 - 合并成一个card -->
<div class="detail-sections">
<h3 class="section-title">工程研究中心详细信息</h3>
<!-- 年份选择标签导航 -->
<div class="year-tabs" v-if="yearTabs.length > 0">
<div
v-for="tab in yearTabs"
:key="tab.year"
:class="['year-tab', { active: activeYear === tab.year }]"
@click="activeYear = tab.year"
>
{{ tab.year }}年度
</div>
</div>
<!-- 年度详细信息内容 -->
<div class="year-content" v-if="currentYearData || !hasAnnualData">
<!-- 如果没有年度数据显示编辑表单 -->
<div v-if="!hasAnnualData" class="edit-form">
<!-- 工程研究中心概况 -->
<div class="form-section">
<h4 class="form-section-title">工程研究中心概况</h4>
<el-input
type="textarea"
v-model="formData.labOverview"
:rows="4"
placeholder="请输入工程研究中心概况"
/>
</div>
<!-- 主要研究方向 -->
<div class="form-section">
<h4 class="form-section-title">主要研究方向</h4>
<el-input
type="textarea"
v-model="formData.researchDirections"
:rows="4"
placeholder="请输入主要研究方向"
/>
</div>
<!-- 核心成果 -->
<div class="form-section">
<h4 class="form-section-title">核心成果</h4>
<el-input
type="textarea"
v-model="formData.coreAchievements"
:rows="4"
placeholder="请输入核心成果"
/>
</div>
<!-- 组织架构 -->
<div class="form-section">
<h4 class="form-section-title">组织架构</h4>
<el-input
type="textarea"
v-model="formData.organization"
:rows="4"
placeholder="请输入组织架构"
/>
</div>
<!-- 管理制度 -->
<div class="form-section">
<h4 class="form-section-title">管理制度</h4>
<el-input
type="textarea"
v-model="formData.managementSystem"
:rows="4"
placeholder="请输入管理制度"
/>
</div>
<!-- 未来规划 -->
<div class="form-section">
<h4 class="form-section-title">未来规划</h4>
<el-input
type="textarea"
v-model="formData.futurePlans"
:rows="4"
placeholder="请输入未来规划"
/>
</div>
<!-- 工程研究中心其他成就信息 -->
<div class="form-section">
<h4 class="form-section-title">工程研究中心其他成就信息</h4>
<el-input
type="textarea"
v-model="formData.labAchievements"
:rows="4"
placeholder="请输入工程研究中心其他成就信息"
/>
</div>
</div>
<!-- 如果有年度数据显示年度信息 -->
<div v-else class="year-info-display">
<!-- 总体情况 -->
<div v-if="currentYearData['1.总体情况']" class="info-section">
<h4 class="info-title">📊 总体情况</h4>
<p class="info-content">{{ currentYearData['1.总体情况'] }}</p>
</div>
<!-- 技术攻关与创新情况 -->
<div v-if="currentYearData.技术攻关与创新情况" class="info-section">
<h4 class="info-title">🔬 技术攻关与创新情况</h4>
<p class="info-content">{{ currentYearData.技术攻关与创新情况 }}</p>
</div>
<!-- 工程化案例 -->
<div v-if="currentYearData['2.工程化案例']" class="info-section">
<h4 class="info-title">🏭 工程化案例</h4>
<p class="info-content">{{ currentYearData['2.工程化案例'] }}</p>
</div>
<!-- 行业服务情况 -->
<div v-if="currentYearData['3.行业服务情况']" class="info-section">
<h4 class="info-title">🤝 行业服务情况</h4>
<p class="info-content">{{ currentYearData['3.行业服务情况'] }}</p>
</div>
<!-- 学科发展支撑情况 -->
<div v-if="currentYearData['1.学科发展支撑情况']" class="info-section">
<h4 class="info-title">📚 学科发展支撑情况</h4>
<p class="info-content">{{ currentYearData['1.学科发展支撑情况'] }}</p>
</div>
<!-- 人才培养情况 -->
<div v-if="currentYearData['2.人才培养情况']" class="info-section">
<h4 class="info-title">🎓 人才培养情况</h4>
<p class="info-content">{{ currentYearData['2.人才培养情况'] }}</p>
</div>
<!-- 研究队伍建设情况 -->
<div v-if="currentYearData['3.研究队伍建设情况']" class="info-section">
<h4 class="info-title">👥 研究队伍建设情况</h4>
<p class="info-content">{{ currentYearData['3.研究队伍建设情况'] }}</p>
</div>
<!-- 主管部门依托单位支持情况 -->
<div v-if="currentYearData['1.主管部门、依托单位支持情况']" class="info-section">
<h4 class="info-title">🏛 主管部门依托单位支持情况</h4>
<p class="info-content">{{ currentYearData['1.主管部门、依托单位支持情况'] }}</p>
</div>
<!-- 仪器设备共享等情况 -->
<div v-if="currentYearData['2.仪器设备共享等情况']" class="info-section">
<h4 class="info-title">🔧 仪器设备共享等情况</h4>
<p class="info-content">{{ currentYearData['2.仪器设备共享等情况'] }}</p>
</div>
<!-- 学风建设情况 -->
<div v-if="currentYearData['3.学风建设情况']" class="info-section">
<h4 class="info-title">📖 学风建设情况</h4>
<p class="info-content">{{ currentYearData['3.学风建设情况'] }}</p>
</div>
<!-- 技术委员会工作情况 -->
<div v-if="currentYearData['4.技术委员会工作情况']" class="info-section">
<h4 class="info-title"> 技术委员会工作情况</h4>
<p class="info-content">{{ currentYearData['4.技术委员会工作情况'] }}</p>
</div>
<!-- 下一年度工作计划 -->
<div v-if="currentYearData.下一年度工作计划" class="info-section">
<h4 class="info-title">🎯 下一年度工作计划</h4>
<p class="info-content">{{ currentYearData.下一年度工作计划 }}</p>
</div>
<!-- 问题与建议 -->
<div v-if="currentYearData.问题与建议" class="info-section">
<h4 class="info-title">💭 问题与建议</h4>
<p class="info-content">{{ currentYearData.问题与建议 }}</p>
</div>
<!-- 统计数据 -->
<div class="stats-section">
<h4 class="info-title">📈 统计数据</h4>
<div class="stats-grid">
<div v-if="currentYearData.在读博士生" class="stat-item">
<div class="stat-label">在读博士生</div>
<div class="stat-value">{{ currentYearData.在读博士生 }}</div>
</div>
<div v-if="currentYearData.在读硕士生" class="stat-item">
<div class="stat-label">在读硕士生</div>
<div class="stat-value">{{ currentYearData.在读硕士生 }}</div>
</div>
<div v-if="currentYearData['固定人员(人)']" class="stat-item">
<div class="stat-label">固定人员</div>
<div class="stat-value">{{ currentYearData['固定人员(人)'] }}</div>
</div>
<div v-if="currentYearData['流动人员(人)']" class="stat-item">
<div class="stat-label">流动人员</div>
<div class="stat-value">{{ currentYearData['流动人员(人)'] }}</div>
</div>
<div v-if="currentYearData['有效专利(项)']" class="stat-item">
<div class="stat-label">有效专利</div>
<div class="stat-value">{{ currentYearData['有效专利(项)'] }}</div>
</div>
<div v-if="currentYearData['当年项目到账总经费(万元)']" class="stat-item">
<div class="stat-label">项目经费</div>
<div class="stat-value">{{ currentYearData['当年项目到账总经费(万元)'] }}万元</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 雷达图 -->
<div class="evaluation-chart-section">
<div id="lab-evaluation-radar-chart" class="radar-chart"></div>
</div>
<!-- 添加二级维度评估部分 -->
<div class="detail-sections" v-if="false && props.dimensions && props.dimensions.length > 0">
<h3 class="section-title">二级维度评估数据</h3>
<div class="section-content">
<div v-for="(dim, dimIndex) in props.dimensions" :key="`dim-${dimIndex}`" class="sub-dimension-section">
<div class="primary-dimension-name">{{ dim.name }}</div>
<div v-if="dim.subDimensions && dim.subDimensions.length > 0" class="sub-dimensions-list">
<div v-for="(subDim, subIndex) in dim.subDimensions" :key="`subDim-${dimIndex}-${subIndex}`" class="sub-dimension-item">
<div class="sub-dimension-name">{{ subDim.name }} (权重: {{ subDim.weight }}%)</div>
<el-slider
v-model="subDimensionEvaluations[dim.name][subDim.name]"
:min="0"
:max="100"
:step="1"
:show-tooltip="true"
:format-tooltip="value => `${value}`"
@change="updateRadarChart"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<template #footer>
<div class="drawer-footer">
<button class="drawer-btn cancel-btn" @click="handleClose">取消</button>
<button class="drawer-btn confirm-btn" @click="handleSave">确定</button>
</div>
</template>
</el-drawer>
</template>
<script setup>
import { ref, reactive, computed, onMounted, watch, nextTick, onUnmounted } from 'vue';
import * as echarts from 'echarts/core';
import { RadarChart } from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent
} from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
import axios from 'axios';
import { ElMessage } from 'element-plus';
import { getApiBaseUrl } from '../config'; // 导入API基础URL函数
// 注册必要的echarts组件
echarts.use([
RadarChart,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
CanvasRenderer
]);
const props = defineProps({
visible: {
type: Boolean,
default: false
},
isEdit: {
type: Boolean,
default: false
},
dimensions: {
type: Array,
default: () => []
},
labData: {
type: Object,
default: () => ({})
}
});
const emit = defineEmits(['update:visible', 'save']);
// 用于visible属性的双向绑定
const drawerVisible = computed({
get: () => props.visible,
set: (val) => emit('update:visible', val)
});
// 默认工程研究中心图片占位符
const defaultImage = `/image/实验室1.png`;
// 抽屉标题的计算属性
const drawerTitle = computed(() => props.isEdit ? '详情' : '新增评估');
// 标签页配置
const tabs = [
{ label: 'URL输入', value: 'url' },
{ label: '上传文档', value: 'upload' },
{ label: '手动录入', value: 'manual' }
];
// 激活的标签页
const activeTab = ref('url');
// URL输入
const urlInput = ref('');
// 数据是否已加载标志
const dataLoaded = ref(false);
// 选择的上传文件
const selectedFile = ref(null);
// 表单数据
const formData = reactive({
id: '',
idcode: '',
name: '',
field: '',
school: '',
department: '',
achievements: '',
image: '',
labAchievements: '',
labOverview: '', // 工程研究中心概况
researchDirections: '', // 主要研究方向
coreAchievements: '', // 核心成果
organization: '', // 组织架构
managementSystem: '', // 管理制度
futurePlans: '', // 未来规划
evaluationData: [], // 会在初始化二级维度时设置
sub_dimension_evaluations: {} // 清空二级维度评估数据
});
// 年份tab相关变量
const yearTabs = ref([]);
const activeYear = ref('');
// 计算当前年度数据
const currentYearData = computed(() => {
if (!activeYear.value || !formData.annual_data) return {};
try {
const annualData = typeof formData.annual_data === 'string'
? JSON.parse(formData.annual_data)
: formData.annual_data;
return annualData.find(data => data.归属年份 === activeYear.value) || {};
} catch (error) {
console.error('解析年度数据失败:', error);
return {};
}
});
// 检查是否有年度数据
const hasAnnualData = computed(() => {
return formData.annual_data && formData.annual_data.length > 0 && yearTabs.value.length > 0;
});
// 初始化年份标签
const initYearTabs = () => {
yearTabs.value = [];
activeYear.value = '';
if (!formData.annual_data) return;
try {
const annualData = typeof formData.annual_data === 'string'
? JSON.parse(formData.annual_data)
: formData.annual_data;
if (Array.isArray(annualData)) {
yearTabs.value = annualData.map(data => ({
year: data.归属年份,
label: `${data.归属年份}年度`
})).sort((a, b) => b.year.localeCompare(a.year)); // 按年份降序排列
// 默认选择最新年份
if (yearTabs.value.length > 0) {
activeYear.value = yearTabs.value[0].year;
}
}
} catch (error) {
console.error('初始化年份标签失败:', error);
}
};
// 二级维度评估数据的响应式对象
const subDimensionEvaluations = reactive({});
// 雷达图实例
let chart = null;
// 从props初始化表单数据
watch(() => props.labData, (newValue) => {
if (newValue && Object.keys(newValue).length > 0 && props.visible) {
Object.assign(formData, newValue);
if (props.isEdit) {
dataLoaded.value = true;
// 重新初始化年份标签和二级维度评估数据和雷达图
nextTick(() => {
initYearTabs();
initSubDimensionEvaluations();
initRadarChart();
});
}
}
}, { deep: true });
// 监听抽屉可见性变化
watch(() => props.visible, (isVisible) => {
if (isVisible) {
if (props.isEdit && props.labData && Object.keys(props.labData).length > 0) {
// 编辑模式:当抽屉变为可见时
Object.assign(formData, props.labData);
dataLoaded.value = true;
} else if (!props.isEdit) {
// 新增模式:清空表单数据
Object.assign(formData, {
id: '', // ID会在保存时生成
idcode: '', // 清空编号
name: '',
field: '',
school: '',
department: '',
achievements: '',
image: defaultImage,
labAchievements: '',
labOverview: '',
researchDirections: '',
coreAchievements: '',
organization: '',
managementSystem: '',
futurePlans: '',
evaluationData: [], // 会在初始化二级维度时设置
sub_dimension_evaluations: {} // 清空二级维度评估数据
});
dataLoaded.value = true;
}
// 在视图更新后初始化
nextTick(() => {
// 初始化年份标签
initYearTabs();
// 初始化二级维度评估数据
initSubDimensionEvaluations();
// 然后初始化雷达图
initRadarChart();
});
}
});
// 监听维度变化,更新雷达图
watch(() => props.dimensions, () => {
if (props.visible && dataLoaded.value) {
nextTick(() => {
initSubDimensionEvaluations();
initRadarChart();
});
}
}, { deep: true });
// 组件挂载时初始化
onMounted(() => {
if (props.visible && dataLoaded.value) {
initSubDimensionEvaluations();
initRadarChart();
}
// 添加全局窗口大小变化事件监听
window.addEventListener('resize', handleResize);
});
// 组件卸载时移除事件监听
onUnmounted(() => {
// 移除窗口大小变化事件监听器
window.removeEventListener('resize', handleResize);
// 销毁图表实例
if (chart) {
chart.dispose();
chart = null;
}
});
// 处理窗口大小变化
const handleResize = () => {
if (chart) {
chart.resize();
}
};
// 初始化二级维度评估数据
const initSubDimensionEvaluations = () => {
// 为每个维度创建一个对象来存储评估数据
props.dimensions.forEach(dim => {
if (!subDimensionEvaluations[dim.name]) {
subDimensionEvaluations[dim.name] = {};
}
if (dim.subDimensions) {
dim.subDimensions.forEach(subDim => {
// 如果已有评估数据,则使用现有数据
if (formData.sub_dimension_evaluations &&
formData.sub_dimension_evaluations[dim.name] &&
formData.sub_dimension_evaluations[dim.name][subDim.name] !== undefined) {
subDimensionEvaluations[dim.name][subDim.name] = formData.sub_dimension_evaluations[dim.name][subDim.name];
} else {
// 否则使用默认值或从evaluationData中获取
const subDimIndex = props.dimensions.findIndex(d => d.name === dim.name);
if (subDimIndex !== -1 && formData.evaluationData && formData.evaluationData[subDimIndex] !== undefined) {
subDimensionEvaluations[dim.name][subDim.name] = formData.evaluationData[subDimIndex];
} else {
// 生成60-90之间的随机分数
subDimensionEvaluations[dim.name][subDim.name] = Math.floor(Math.random() * 31) + 60;
}
}
});
}
});
};
// 更新雷达图
const updateRadarChart = () => {
// 将二级维度评估数据保存到formData
saveSubDimensionEvaluations();
// 重新初始化雷达图
initRadarChart();
};
// 保存二级维度评估数据到formData
const saveSubDimensionEvaluations = () => {
// 深拷贝当前评估数据
formData.sub_dimension_evaluations = JSON.parse(JSON.stringify(subDimensionEvaluations));
// 同时更新一维evaluationData用于兼容
const evaluationValues = [];
props.dimensions.forEach(dim => {
if (dim.subDimensions && dim.subDimensions.length > 0) {
dim.subDimensions.forEach(subDim => {
if (subDimensionEvaluations[dim.name] &&
subDimensionEvaluations[dim.name][subDim.name] !== undefined) {
evaluationValues.push(subDimensionEvaluations[dim.name][subDim.name]);
}
});
}
});
if (evaluationValues.length > 0) {
formData.evaluationData = evaluationValues;
}
};
// 初始化雷达图
const initRadarChart = () => {
const chartDom = document.getElementById('lab-evaluation-radar-chart');
if (!chartDom) {
console.error('雷达图DOM元素不存在');
return;
}
// 清除任何现有图表
echarts.dispose(chartDom);
chart = echarts.init(chartDom);
// 从二级维度生成指标
const indicators = [];
if (props.dimensions && props.dimensions.length > 0) {
props.dimensions.forEach(dim => {
if (dim.subDimensions && dim.subDimensions.length > 0) {
dim.subDimensions.forEach(subDim => {
indicators.push({
name: subDim.name,
max: 100
});
});
}
});
}
// 如果没有维度,使用默认维度
if (indicators.length === 0) {
indicators.push(
{ name: '创新水平', max: 100 },
{ name: '研究能力', max: 100 },
{ name: '成果转化', max: 100 },
{ name: '学科建设', max: 100 },
{ name: '行业贡献', max: 100 },
{ name: '发展潜力', max: 100 }
);
}
// 准备雷达图数据
let radarData = [];
// 检查是否有二级维度评估数据
let hasSubDimensionData = false;
props.dimensions.forEach(dim => {
if (dim.subDimensions && dim.subDimensions.length > 0 &&
subDimensionEvaluations[dim.name]) {
dim.subDimensions.forEach(subDim => {
if (subDimensionEvaluations[dim.name][subDim.name] !== undefined) {
hasSubDimensionData = true;
radarData.push(subDimensionEvaluations[dim.name][subDim.name]);
}
});
}
});
// 如果没有二级维度数据使用传统的evaluationData
if (!hasSubDimensionData) {
// 确保评估数据与指标数量匹配
if (!formData.evaluationData || formData.evaluationData.length !== indicators.length) {
// 生成随机评估数据范围在60-90之间
formData.evaluationData = indicators.map(() => Math.floor(Math.random() * 31) + 60);
}
radarData = formData.evaluationData;
}
// 更新图表
chart.setOption({
radar: {
indicator: indicators,
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', fontSize: 10 } },
radius: '70%'
},
series: [
{
type: 'radar',
data: [
{
value: radarData,
name: '评估结果',
areaStyle: { opacity: 0.2, color: 'rgb(238, 23, 143)' },
lineStyle: { color: 'rgb(238, 23, 143)', width: 2 },
itemStyle: { color: 'rgb(238, 23, 143)' }
}
]
}
]
});
};
// 处理文件变更
const handleFileChange = async (file) => {
selectedFile.value = file;
// 检查文件类型
if (!file.raw.name.endsWith('.docx')) {
ElMessage.error('只支持.docx格式的Word文档');
return;
}
// 创建表单数据
const uploadFormData = new FormData();
uploadFormData.append('file', file.raw);
try {
// 获取JWT令牌
const token = localStorage.getItem('token');
if (!token) {
ElMessage.error('未登录或登录已过期,请重新登录');
return;
}
// 显示加载状态
ElMessage.info('正在解析文档,请稍候...');
// 发送文件到后端API
const response = await axios.post(
`${getApiBaseUrl()}/api/upload-lab-document`,
uploadFormData,
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'multipart/form-data'
}
}
);
// 检查响应
if (response.data && response.data.success) {
// 使用API返回的数据更新表单
const labData = response.data.data;
Object.assign(formData, labData);
// 设置数据已加载标志
dataLoaded.value = true;
// 更新图表
nextTick(() => {
initRadarChart();
});
ElMessage.success('文档解析成功');
} else {
throw new Error(response.data.detail || '文档解析失败');
}
} catch (error) {
console.error('上传文档时发生错误:', error);
ElMessage.error(`上传文档失败: ${error.response?.data?.detail || error.message}`);
}
};
// 从URL获取数据
const fetchDataFromUrl = async () => {
if (!urlInput.value) {
return;
}
// 演示使用模拟数据
fetchMockData();
};
// 用于演示的模拟数据
const fetchMockData = () => {
// 模拟与图片中匹配的响应数据
const response = {
id: 'BLG45187',
name: '基础力学教学实验中心',
field: '力学工程',
school: '北京理工大学',
department: '教育部',
achievements: '28项',
image: defaultImage,
labAchievements: `基础力学教学实验中心成立于2018年是北京理工大学重点建设的工程研究中心之一。致力于力学基础理论与应用研究为工业和国防科技提供科研支持。
工程研究中心拥有先进的力学测试设备和模拟系统,在材料力学、流体力学等领域具有领先优势。近年来承担多项国家重点研发计划项目。
工程研究中心现有研究人员26人其中教授5人副教授8人讲师和工程技术人员13人。拥有博士生导师6人硕士生导师10人。
近五年承担国家重点研发计划项目3项国家自然科学基金项目12项省部级科研项目25项企业合作项目30余项。
近五年发表SCI论文120余篇获得国家发明专利35项省部级科技奖励5项。多项成果已在航空航天、高端装备制造等领域实现转化应用。`,
evaluationData: [85, 78, 92, 76, 88, 80]
};
// 使用响应更新表单数据
Object.assign(formData, response);
// 设置数据已加载标志
dataLoaded.value = true;
// 更新图表
nextTick(() => {
initRadarChart();
});
};
// 处理关闭
const handleClose = () => {
drawerVisible.value = false;
// 重置数据加载状态
if (!props.isEdit) {
dataLoaded.value = false;
}
};
// 处理保存
const handleSave = async () => {
try {
// 如果是新增评估不需要传id字段
if (!props.isEdit) {
// 在新增模式下删除id字段因为后端通过是否有id字段来判断是新增还是修改
delete formData.id;
// 确保用户已经输入idcode
if (!formData.idcode) {
ElMessage.warning('请输入编号');
return;
}
}
// 保存二级维度评估数据
saveSubDimensionEvaluations();
// 准备请求体数据
const payload = {
data_type: "lab", // 指定为工程研究中心评估类型
data: { ...formData }
};
// 从localStorage获取JWT令牌
const token = localStorage.getItem('token');
if (!token) {
ElMessage.error('未登录或登录已过期,请重新登录');
return;
}
// 发送POST请求到后端API添加Authorization头
const response = await axios.post(`${getApiBaseUrl()}/api/save-data`, payload, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (response.data.success) {
// 如果是新增操作后端会返回生成的id需要更新表单数据的id
if (response.data.id && !props.isEdit) {
formData.id = response.data.id;
}
// 通知父组件刷新数据并传递保存的数据
emit('save', { ...formData });
// 不再在这里关闭抽屉,由父组件决定何时关闭
// 也不再显示成功消息,由父组件处理
} else {
throw new Error(response.data.message || '保存失败');
}
} catch (error) {
console.error('保存工程研究中心评估数据失败:', error);
ElMessage.error(`保存工程研究中心评估数据失败: ${error.response?.data?.detail || error.message}`);
}
};
// 处理模拟文件上传
const fakeFileChange = (file) => {
// 显示加载状态
ElMessage.info('正在解析文档,请稍候...');
// 禁用表单,模拟加载状态
dataLoaded.value = false;
// 添加8秒延迟模拟真实文件处理过程
setTimeout(() => {
// 模拟教育部土木信息技术工程研究中心的数据
const response = {
id: '',
idcode: 'ERC-CE-2001',
name: '教育部土木信息技术工程研究中心',
field: '土木工程与信息技术交叉领域',
school: '同济大学',
department: '教育部',
achievements: '42项',
image: defaultImage,
// 分类详细信息
labOverview: `依托同济大学教育部土木信息技术工程研究中心是教育部为推动高校科技成果转化与高新技术产业化设立的44个工程研究中心之一聚焦土木工程与信息技术的交叉领域。中心秉持"传统与现代相结合"理念,采用"学科创新"发展思路,通过现代信息技术实现土木信息资源在线化与共享化,提升行业信息化水平。中心在土木信息集成与交互系统、移动终端及嵌入式软件、工程信息管理系统等领域取得多项成果,技术产品广泛应用于全国重大土木工程项目。
成立时间: 2001年
依托单位: 同济大学
验收时间: 2004年8月
主任: 朱合华教授(中国工程院院士)
常务副主任: 李晓军教授
副主任: 沈奕、刘学增、俞登华
办公室主任: 沈奕`,
researchDirections: `1. 土木工程数字化设计软件
2. 土木工程数值计算分析软件
3. 土木工程全寿命周期数字化管理系统
4. 土木工程信息采集终端设备及硬件装置
5. iS3智慧基础设施平台
6. 土木工程信息化标准`,
coreAchievements: `1. iS3智慧基础设施平台: 国内首创的基础设施智慧化"操作系统",支持地下工程研究中心数据管理、综合管廊施工、基坑监测、轨道交通项目等。
2. 技术产品应用:
(1) 上海同隧信息科技有限公司: 地下工程研究中心数据管理、综合管廊施工全过程管理、基坑施工自动化监测、轨道交通工程行为标准化研究。
(2) 上海同岩土木工程科技股份有限公司: 高速公路隧道病害检测车、地铁隧道结构变形快速检测车、基于视频的结构变形在线监测系统等。
3. 中国智慧基础设施联盟: 依托iS3平台成立推动基础设施信息化发展。
4. 标准化成果: 参与制定《岩石隧道工程地质信息交换标准》《岩石隧道工程结构信息模型交付标准》等团体标准。`,
organization: `1. 管理委员会: 制定发展规划,审查预算,协调管理与人事。
2. 中心办公室: 负责日常事务、文件管理、宣传推广、分中心协调。
3. 分中心:
(1) 地下基础设施安全检测与养护装备分中心(上海同岩土木工程科技股份有限公司)
(2) 智慧地下基础设施分中心(上海同隧信息科技有限公司)
(3) 中电建西北院分中心(中国电建集团西北勘测设计研究院有限公司)
(4) 合肥分中心(合肥市轨道交通集团有限公司)
(5) 筹备中: 苏州、滁州
4. 技术委员会:
(1) 主任: 龚晓南(中国工程院院士)
(2) 副主任: 崔俊芝、梁文灏、杜彦良
(3) 委员: 陈艾荣、顾祥林等13位专家
5. 部门设置:
(1) 综合管理部: 俞登华、昌永杰
(2) 技术研发部: 芮易、凌加鑫、李涛、蔡永桢
(3) 产品研发部: 陈超、阿迪力·如苏力、王宇昀、李圣
(4) 项目建设部: 朱伟佳、江俊凯、曾佩、刘灿宇、陆从山`,
managementSystem: `1. 管理细则: 依据《土木信息技术教育部工程研究中心管理实施细则》,实行每周五天工作制,规范日常管理,强调团队协作与职业道德。
2. 分中心管理办法:
(1) 分中心需具备自主知识产权、工程化装备、市场转化经验及明确目标。
(2) 每年与中心合作项目规模不低于50万元。
(3) 主任负责制,主任需具备学术背景和管理经验。`,
futurePlans: `1. 分中心扩展: 计划于2024年在深圳、广州、苏州、西安设立新分中心。
2. 技术创新: 深化iS3平台应用推进基础设施信息化研究。
3. 标准化建设: 制定更多土木工程信息化标准。
4. 人才培养: 加强土木信息技术交叉领域人才培养,建立校企联合培养基地。`,
labAchievements: `教育部土木信息技术工程研究中心在土木工程与信息技术交叉领域取得了一系列重要成就。中心秉持"传统与现代相结合"理念,将现代信息技术应用于土木工程领域,推动了行业的数字化转型。
中心开发的iS3智慧基础设施平台是国内首创的基础设施智慧化"操作系统"已在地下工程研究中心数据管理综合管廊施工基坑监测轨道交通项目等多个领域得到应用
中心参与制定了岩石隧道工程地质信息交换标准岩石隧道工程结构信息模型交付标准等团体标准推动了行业标准化建设
中心发表高水平学术论文200余篇获得国家发明专利50余项省部级科技奖励10余项多项成果已实现产业化转化取得了显著的经济和社会效益`,
evaluationData: [92, 90, 88, 90, 93, 90, 85, 92]
};
// 使用响应更新表单数据
Object.assign(formData, response);
// 设置数据已加载标志
dataLoaded.value = true;
// 更新图表
nextTick(() => {
initSubDimensionEvaluations();
initRadarChart();
});
ElMessage.success('模拟文档解析成功');
}, 8000); // 8秒延迟
};
</script>
<style>
@import './common.css';
.el-drawer{
border-left: 1px solid #4986ff;
}
.el-drawer__body{
padding: 0px !important;
}
.el-drawer__header{
background-color: #0c1633 !important;
margin-bottom:0px !important;
}
.el-drawer__footer{
background-color: #0c1633 !important;
}
</style>
<style scoped>
.lab-drawer :deep(.el-drawer__header) {
margin-bottom: 0;
color: white;
background-color: #0c1633;
border-bottom: 1px solid rgba(73,134,255,0.3);
}
.lab-drawer :deep(.el-drawer__body) {
padding: 0;
overflow: hidden;
background-color: #0c1633;
}
.drawer-content {
padding: 20px;
color: white;
height: 100%;
overflow-y: auto;
background-color: #0c1633;
}
/* 标签导航 */
.tab-navigation {
display: flex;
border-bottom: 1px solid rgba(73,134,255,0.3);
margin-bottom: 20px;
}
.tab-item {
padding: 10px 20px;
cursor: pointer;
font-size: 16px;
color: rgba(255,255,255,0.7);
position: relative;
}
.tab-item.active {
color: #4986ff;
font-weight: bold;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: -1px;
left: 0;
width: 100%;
height: 2px;
background-color: #4986ff;
}
/* URL输入部分 */
.url-input-container {
display: flex;
margin-bottom: 20px;
}
.url-input {
flex: 1;
margin-right: 10px;
}
/* 上传部分 */
.upload-container {
margin-bottom: 20px;
}
.el-upload__tip {
color: rgba(255,255,255,0.7);
margin-top: 5px;
}
/* 手动输入提示 */
.manual-input-tip {
margin-bottom: 20px;
color: rgba(255,255,255,0.7);
}
/* 工程研究中心信息表单 */
.form-header {
display: flex;
margin-bottom: 30px;
background-color: #1f3266;
border-radius: 8px;
padding: 15px;
border: 1px solid rgba(73,134,255,0.3);
}
.image-section {
margin-right: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.lab-image {
width: 150px;
height: 100px;
overflow: hidden;
border-radius: 4px;
margin-bottom: 10px;
}
.lab-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.basic-info {
flex: 1;
}
.form-row {
display: flex;
margin-bottom: 15px;
}
.form-item {
flex: 1;
margin-right: 15px;
display: flex;
flex-direction: column;
}
.form-item:last-child {
margin-right: 0;
}
.form-item.full-width {
flex: 3;
}
.label {
display: block;
margin-bottom: 8px;
color: rgba(255,255,255,0.7);
}
/* 详细信息部分 */
.detail-sections {
margin-bottom: 30px;
background-color: #1f3266;
border-radius: 8px;
padding: 15px;
border: 1px solid rgba(73,134,255,0.3);
}
.section-title {
margin: 15px 0 10px;
font-size: 16px;
color: rgba(255,255,255,0.9);
}
.section-content {
margin-bottom: 20px;
}
/* 雷达图部分 */
.evaluation-chart-section {
background-color: #1f3266;
border-radius: 8px;
padding: 15px;
border: 1px solid rgba(73,134,255,0.3);
}
.radar-chart {
width: 100%;
height: 300px; /* 明确指定雷达图高度 */
min-height: 300px; /* 确保最小高度 */
}
/* 抽屉页脚 */
.lab-drawer :deep(.el-drawer__footer) {
border-top: 1px solid rgba(73,134,255,0.3);
padding: 10px 20px;
background-color: #0c1633;
}
.drawer-footer {
display: flex;
justify-content: flex-end;
}
/* 按钮样式 */
.drawer-btn {
padding: 8px 15px;
border-radius: 10px;
font-size: 14px;
font-family: PingFangSC-regular;
cursor: pointer;
margin-left: 10px;
}
.cancel-btn {
background-color: transparent;
color: rgba(255,255,255,0.8);
border: 1px solid rgba(73,134,255,0.5);
}
.confirm-btn {
background-color: rgba(14,62,167,1);
color: rgba(255,255,255,1);
border: 1px solid rgba(73,134,255,1);
}
/* Element Plus组件的深色主题覆盖样式 */
:deep(.el-input__wrapper),
:deep(.el-textarea__wrapper) {
background-color: rgba(255,255,255,0.1);
box-shadow: 0 0 0 1px rgba(73,134,255,0.3) inset;
}
:deep(.el-input__inner),
:deep(.el-textarea__inner) {
background-color: transparent;
color: white;
}
:deep(.el-input__inner::placeholder),
:deep(.el-textarea__inner::placeholder) {
color: rgba(255,255,255,0.5);
}
:deep(.el-select .el-input__wrapper) {
background-color: rgba(255,255,255,0.1);
box-shadow: 0 0 0 1px rgba(73,134,255,0.3) inset;
}
:deep(.el-select-dropdown__item) {
color: #606266;
}
:deep(.el-date-editor) {
background-color: rgba(255,255,255,0.1);
border-color: rgba(73,134,255,0.3);
color: white;
}
:deep(.el-upload),
:deep(.el-upload-dragger) {
background-color: rgba(255,255,255,0.1);
border-color: rgba(73,134,255,0.3);
}
/* 滚动条样式 */
.drawer-content::-webkit-scrollbar {
width: 6px;
}
.drawer-content::-webkit-scrollbar-track {
background: transparent;
}
.drawer-content::-webkit-scrollbar-thumb {
background-color: #4986ff;
border-radius: 10px;
border: none;
}
.sub-dimension-section {
margin-bottom: 20px;
background-color: rgba(12, 22, 51, 0.3);
border-radius: 8px;
padding: 15px;
border: 1px solid rgba(73, 134, 255, 0.3);
}
.primary-dimension-name {
font-size: 16px;
font-weight: bold;
color: #4986ff;
margin-bottom: 15px;
border-bottom: 1px solid rgba(73, 134, 255, 0.3);
padding-bottom: 8px;
}
.sub-dimensions-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.sub-dimension-item {
padding: 10px;
background-color: rgba(31, 50, 102, 0.3);
border-radius: 6px;
}
.sub-dimension-name {
margin-bottom: 10px;
color: white;
font-size: 14px;
}
/* Override element-plus slider styles for dark theme */
.sub-dimension-item :deep(.el-slider__runway) {
background-color: rgba(255, 255, 255, 0.1);
}
.sub-dimension-item :deep(.el-slider__bar) {
background-color: #4986ff;
}
.sub-dimension-item :deep(.el-slider__button) {
border: 2px solid #4986ff;
background-color: white;
}
/* 年份tab样式 */
.year-tabs {
display: flex;
border-bottom: 1px solid rgba(73,134,255,0.3);
margin-bottom: 20px;
overflow-x: auto;
}
.year-tab {
padding: 12px 20px;
cursor: pointer;
border-bottom: 2px solid transparent;
color: rgba(255,255,255,0.6);
font-weight: 500;
white-space: nowrap;
transition: all 0.3s;
margin-right: 10px;
}
.year-tab:hover {
color: #4986ff;
background-color: rgba(73,134,255,0.1);
}
.year-tab.active {
color: #4986ff;
border-bottom-color: #4986ff;
background-color: rgba(73,134,255,0.2);
}
/* 年度信息展示样式 */
.year-info-display {
padding: 20px 0;
}
.info-section {
margin-bottom: 25px;
padding: 15px;
background-color: rgba(12,22,51,0.3);
border-radius: 8px;
border-left: 4px solid #4986ff;
}
.info-title {
font-size: 16px;
font-weight: 600;
color: #4986ff;
margin: 0 0 12px 0;
display: flex;
align-items: center;
}
.info-content {
line-height: 1.8;
color: rgba(255,255,255,0.9);
margin: 0;
text-align: justify;
word-break: break-all;
}
/* 统计数据网格样式 */
.stats-section {
margin-top: 20px;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
margin-top: 15px;
}
.stat-item {
background: rgba(31,50,102,0.4);
padding: 15px;
border-radius: 8px;
text-align: center;
border: 1px solid rgba(73,134,255,0.3);
}
.stat-label {
color: rgba(255,255,255,0.7);
font-size: 12px;
margin-bottom: 8px;
}
.stat-value {
color: #4986ff;
font-size: 18px;
font-weight: bold;
}
/* 编辑表单样式 */
.edit-form {
padding: 20px 0;
}
.form-section {
margin-bottom: 20px;
}
.form-section-title {
font-size: 14px;
font-weight: 600;
color: #4986ff;
margin: 0 0 10px 0;
}
</style><style>
.el-upload--text{
width: 100%;
}</style>