3468 lines
138 KiB
HTML
3468 lines
138 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>风电叶片检查智能管理平台</title>
|
||
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
|
||
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.3.2/dist/echarts.min.js"></script>
|
||
<style>
|
||
/* 基础样式 */
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
|
||
color: #333;
|
||
background-color: #f0f2f5;
|
||
}
|
||
|
||
.app-container {
|
||
display: flex;
|
||
min-height: 100vh;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 侧边栏样式 */
|
||
.sidebar {
|
||
width: 220px;
|
||
background-color: #304156;
|
||
color: #fff;
|
||
transition: width 0.3s;
|
||
flex-shrink: 0;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.sidebar.collapsed {
|
||
width: 64px;
|
||
}
|
||
|
||
.main-content {
|
||
flex: 1;
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
transition: margin-left 0.3s;
|
||
}
|
||
|
||
.sidebar.collapsed + .main-content {
|
||
margin-left: -156px;
|
||
}
|
||
|
||
.logo {
|
||
padding: 10px 0;
|
||
text-align: center;
|
||
position: relative;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||
}
|
||
|
||
.logo h2 {
|
||
font-size: 18px;
|
||
margin: 5px 0;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
padding: 0 10px;
|
||
}
|
||
|
||
.logo p {
|
||
font-size: 12px;
|
||
margin: 0;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
padding: 0 10px;
|
||
}
|
||
|
||
.toggle-sidebar {
|
||
position: absolute;
|
||
right: 10px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
cursor: pointer;
|
||
color: #fff;
|
||
}
|
||
|
||
/* 菜单项样式 */
|
||
.el-menu {
|
||
border-right: none;
|
||
background-color: transparent;
|
||
}
|
||
|
||
.el-menu-item, .el-submenu__title {
|
||
color: #fff;
|
||
height: 46px;
|
||
line-height: 46px;
|
||
}
|
||
|
||
.el-menu-item:hover, .el-submenu__title:hover {
|
||
background-color: rgba(0, 0, 0, 0.1) !important;
|
||
}
|
||
|
||
.el-menu-item.is-active {
|
||
background-color: rgba(0, 0, 0, 0.2) !important;
|
||
color: #409EFF !important;
|
||
}
|
||
|
||
.el-submenu .el-menu-item {
|
||
min-width: 0 !important;
|
||
padding-left: 50px !important;
|
||
background-color: #1f2d3d !important;
|
||
}
|
||
|
||
.el-submenu .el-menu-item:hover {
|
||
background-color: rgba(0, 0, 0, 0.1) !important;
|
||
}
|
||
|
||
.el-submenu__title {
|
||
padding-left: 20px !important;
|
||
}
|
||
|
||
.el-menu-item [class^=el-icon-], .el-submenu [class^=el-icon-] {
|
||
margin-right: 10px;
|
||
}
|
||
|
||
/* 二级菜单样式 */
|
||
.el-menu--inline .el-menu-item {
|
||
padding-left: 60px !important;
|
||
}
|
||
|
||
/* 折叠状态下的样式 */
|
||
.sidebar.collapsed .el-submenu__icon-arrow {
|
||
display: none;
|
||
}
|
||
|
||
.sidebar.collapsed .el-submenu > .el-menu {
|
||
display: none;
|
||
}
|
||
|
||
/* 徽标样式 */
|
||
.el-badge {
|
||
position: absolute;
|
||
right: 20px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
}
|
||
|
||
.sidebar.collapsed .el-badge {
|
||
right: 5px;
|
||
}
|
||
|
||
/* 用户信息样式 */
|
||
.user-info {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 10px;
|
||
border-top: 1px solid rgba(255,255,255,0.1);
|
||
position: absolute;
|
||
bottom: 0;
|
||
width: 220px;
|
||
background-color: #304156;
|
||
}
|
||
|
||
.user-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
margin-right: 10px;
|
||
background-color: #409EFF;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.user-name {
|
||
flex: 1;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.user-logout {
|
||
cursor: pointer;
|
||
padding: 5px;
|
||
}
|
||
|
||
.sidebar.collapsed .user-info {
|
||
justify-content: center;
|
||
padding: 10px 5px;
|
||
width: 64px;
|
||
}
|
||
|
||
.sidebar.collapsed .user-name,
|
||
.sidebar.collapsed .user-logout {
|
||
display: none;
|
||
}
|
||
|
||
.sidebar.collapsed .user-avatar {
|
||
margin-right: 0;
|
||
}
|
||
|
||
/* 主内容区样式 */
|
||
.module-title {
|
||
margin-bottom: 20px;
|
||
padding-bottom: 10px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
}
|
||
|
||
.card-container {
|
||
background: #fff;
|
||
padding: 20px;
|
||
border-radius: 4px;
|
||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* 实时数据卡片 */
|
||
.real-time-data {
|
||
display: flex;
|
||
margin-bottom: 15px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.data-card {
|
||
flex: 1;
|
||
min-width: 200px;
|
||
margin-right: 15px;
|
||
margin-bottom: 15px;
|
||
padding: 15px;
|
||
background: #fff;
|
||
border-radius: 4px;
|
||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.data-card:last-child {
|
||
margin-right: 0;
|
||
}
|
||
|
||
.data-title {
|
||
font-size: 14px;
|
||
color: #909399;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.data-value {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.data-unit {
|
||
font-size: 12px;
|
||
color: #909399;
|
||
margin-left: 5px;
|
||
}
|
||
|
||
/* 图表容器 */
|
||
.chart-container {
|
||
height: 300px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* 表格样式 */
|
||
.el-table {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* 步骤条样式 */
|
||
.process-steps {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* 机组列表样式 */
|
||
.turbine-list {
|
||
border: 1px solid #ebeef5;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.turbine-item {
|
||
padding: 15px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
}
|
||
|
||
.turbine-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.turbine-title {
|
||
font-weight: bold;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.blade-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 8px 0;
|
||
border-bottom: 1px dashed #ebeef5;
|
||
}
|
||
|
||
.blade-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.blade-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.blade-status {
|
||
width: 80px;
|
||
text-align: center;
|
||
margin: 0 10px;
|
||
padding: 2px 5px;
|
||
border-radius: 3px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.status-待开始 {
|
||
background-color: #f5f5f5;
|
||
color: #909399;
|
||
}
|
||
|
||
.status-进行中 {
|
||
background-color: #ecf5ff;
|
||
color: #409EFF;
|
||
}
|
||
|
||
.status-已完成 {
|
||
background-color: #f0f9eb;
|
||
color: #67C23A;
|
||
}
|
||
|
||
/* 上传区域样式 */
|
||
.upload-area {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.upload-icon {
|
||
font-size: 50px;
|
||
color: #409EFF;
|
||
margin: 20px 0;
|
||
}
|
||
|
||
/* 报告预览样式 */
|
||
.report-preview {
|
||
border: 1px solid #ebeef5;
|
||
padding: 20px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.report-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.report-title {
|
||
font-weight: bold;
|
||
margin-bottom: 10px;
|
||
padding-bottom: 5px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
}
|
||
|
||
.report-content {
|
||
padding: 0 10px;
|
||
}
|
||
|
||
/* 缺陷项样式 */
|
||
.defect-item {
|
||
margin-bottom: 15px;
|
||
padding-bottom: 15px;
|
||
border-bottom: 1px dashed #ebeef5;
|
||
}
|
||
|
||
.defect-title {
|
||
font-weight: bold;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.defect-desc {
|
||
margin-bottom: 10px;
|
||
color: #606266;
|
||
}
|
||
|
||
/* 缺陷图片预览 */
|
||
.defect-images {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.defect-image-preview {
|
||
width: 100px;
|
||
height: 100px;
|
||
margin-right: 10px;
|
||
margin-bottom: 10px;
|
||
border: 1px solid #ebeef5;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.defect-image-preview:hover {
|
||
border-color: #409EFF;
|
||
}
|
||
|
||
/* 图片预览对话框 */
|
||
.image-preview-dialog .el-dialog__body {
|
||
padding: 0;
|
||
}
|
||
|
||
.full-image {
|
||
width: 100%;
|
||
display: block;
|
||
}
|
||
|
||
/* 施工任务卡片 */
|
||
.task-card {
|
||
margin-bottom: 15px;
|
||
border-radius: 4px;
|
||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.task-card:hover {
|
||
transform: translateY(-5px);
|
||
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.task-card-header {
|
||
padding: 15px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.task-card-body {
|
||
padding: 15px;
|
||
}
|
||
|
||
.task-progress {
|
||
margin: 10px 0;
|
||
}
|
||
|
||
/* 监测数据卡片 */
|
||
.monitor-card {
|
||
margin-bottom: 15px;
|
||
border-radius: 4px;
|
||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.monitor-card-header {
|
||
padding: 15px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.monitor-card-body {
|
||
padding: 15px;
|
||
}
|
||
|
||
/* 响应式调整 */
|
||
@media (max-width: 992px) {
|
||
.data-card {
|
||
width: calc(50% - 10px);
|
||
}
|
||
|
||
.data-card:nth-child(2n) {
|
||
margin-right: 0;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.sidebar {
|
||
position: fixed;
|
||
z-index: 1000;
|
||
height: 100vh;
|
||
}
|
||
|
||
.sidebar.collapsed + .main-content {
|
||
margin-left: 0;
|
||
}
|
||
|
||
.main-content {
|
||
margin-left: 220px;
|
||
}
|
||
|
||
.sidebar.collapsed {
|
||
width: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.real-time-data {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.data-card {
|
||
margin-right: 0;
|
||
margin-bottom: 15px;
|
||
width: 100%;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="app" class="app-container">
|
||
<!-- 侧边栏导航 - 优化后的版本 -->
|
||
<div class="sidebar" :class="{collapsed: isCollapse}">
|
||
<div class="logo">
|
||
<h2>风电叶片检查</h2>
|
||
<p>智能管理平台</p>
|
||
<div class="toggle-sidebar" @click="toggleSidebar">
|
||
<i :class="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"></i>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 使用Element UI的菜单组件重构导航 -->
|
||
<el-menu
|
||
:default-active="activeModule"
|
||
class="el-menu-vertical"
|
||
:collapse="isCollapse"
|
||
:collapse-transition="false"
|
||
background-color="#304156"
|
||
text-color="#fff"
|
||
active-text-color="#409EFF"
|
||
>
|
||
<!-- 工作台 -->
|
||
<el-menu-item index="dashboard" @click="switchModule('dashboard')">
|
||
<i class="el-icon-data-line"></i>
|
||
<span slot="title">工作台</span>
|
||
</el-menu-item>
|
||
|
||
<!-- 我的项目 -->
|
||
<el-submenu index="project">
|
||
<template slot="title">
|
||
<i class="el-icon-folder-opened"></i>
|
||
<span>我的项目</span>
|
||
</template>
|
||
<el-menu-item
|
||
index="project-list"
|
||
@click="switchModule('project-list')"
|
||
>
|
||
<span>项目列表</span>
|
||
<el-badge :value="newProjectCount" :max="99" class="item"></el-badge>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="project-construction"
|
||
@click="switchModule('project-construction')"
|
||
>
|
||
<span>我的施工</span>
|
||
</el-menu-item>
|
||
|
||
<!-- 我的业务数据 -->
|
||
<el-submenu index="data-processing">
|
||
<template slot="title">我的业务数据</template>
|
||
<el-menu-item
|
||
index="data-import"
|
||
@click="switchModule('data-import')"
|
||
>
|
||
<span>数据入库</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="data-preprocess"
|
||
@click="switchModule('data-preprocess')"
|
||
>
|
||
<span>数据预处理</span>
|
||
</el-menu-item>
|
||
|
||
<!-- 数据分析或图像检测 - 二级下拉菜单 -->
|
||
<el-submenu index="inspection">
|
||
<template slot="title">数据分析或图像检测</template>
|
||
<el-menu-item
|
||
index="inspection-tree"
|
||
@click="switchModule('inspection-tree')"
|
||
>
|
||
<span>可视化管理</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="inspection-defect"
|
||
@click="switchModule('inspection-defect')"
|
||
>
|
||
<span>缺陷检测</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="inspection-report"
|
||
@click="switchModule('inspection-report')"
|
||
>
|
||
<span>报告生成</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="inspection-standard"
|
||
@click="switchModule('inspection-standard')"
|
||
>
|
||
<span>标准信息库</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="report-review"
|
||
@click="switchModule('report-review')"
|
||
>
|
||
<span>报告修改审核</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="inspection-lifecycle"
|
||
@click="switchModule('inspection-lifecycle')"
|
||
>
|
||
<span>全生命周期管理</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="drone-service"
|
||
@click="switchModule('drone-service')"
|
||
>
|
||
<span>无人机云服务</span>
|
||
<span>航线规划</span>
|
||
<span>机场管理</span>
|
||
</el-menu-item>
|
||
</el-submenu>
|
||
</el-submenu>
|
||
|
||
<!-- 项目交付 -->
|
||
<el-submenu index="delivery">
|
||
<template slot="title">项目交付</template>
|
||
<el-menu-item
|
||
index="delivery-reliability"
|
||
@click="switchModule('delivery-reliability')"
|
||
>
|
||
<span>可靠性评估</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="delivery-quality"
|
||
@click="switchModule('delivery-quality')"
|
||
>
|
||
<span>数据质量评估</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="delivery-storage"
|
||
@click="switchModule('delivery-storage')"
|
||
>
|
||
<span>质量入库</span>
|
||
</el-menu-item>
|
||
</el-submenu>
|
||
</el-submenu>
|
||
|
||
<!-- 我的在线监测业务 -->
|
||
<el-submenu index="monitor-project">
|
||
<template slot="title">
|
||
<i class="el-icon-monitor"></i>
|
||
<span>我的在线监测业务/项目</span>
|
||
</template>
|
||
</el-menu-item>
|
||
</el-submenu>
|
||
|
||
<!-- 塔下监测预报 -->
|
||
<el-submenu index="monitor">
|
||
<template slot="title">
|
||
<i class="el-icon-monitor"></i>
|
||
<span>塔下监测预报</span>
|
||
</template>
|
||
<el-menu-item
|
||
index="monitor-clearance"
|
||
@click="switchModule('monitor-clearance')"
|
||
>
|
||
<span>净空距离</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="monitor-deformation"
|
||
@click="switchModule('monitor-deformation')"
|
||
>
|
||
<span>形变监测</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="monitor-image"
|
||
@click="switchModule('monitor-image')"
|
||
>
|
||
<span>图像检测</span>
|
||
</el-menu-item>
|
||
</el-submenu>
|
||
|
||
<!-- 其他 -->
|
||
<el-submenu index="others">
|
||
<template slot="title">
|
||
<i class="el-icon-set-up"></i>
|
||
<span>其他</span>
|
||
</template>
|
||
<el-menu-item
|
||
index="others-route"
|
||
@click="switchModule('others-route')"
|
||
>
|
||
<span>航线规划</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="others-model"
|
||
@click="switchModule('others-model')"
|
||
>
|
||
<span>三维模型</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="others-template"
|
||
@click="switchModule('others-template')"
|
||
>
|
||
<span>报告模板库</span>
|
||
</el-menu-item>
|
||
<el-menu-item
|
||
index="others-settings"
|
||
@click="switchModule('others-settings')"
|
||
>
|
||
<span>系统设置</span>
|
||
</el-menu-item>
|
||
</el-submenu>
|
||
</el-menu>
|
||
|
||
<div class="user-info">
|
||
<div class="user-avatar">{{ userInfo.name.substring(0,1) }}</div>
|
||
<div class="user-name">{{ userInfo.name }} ({{ userInfo.role }})</div>
|
||
<div class="user-logout" @click="logout">
|
||
<i class="el-icon-switch-button"></i>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 主内容区 -->
|
||
<div class="main-content">
|
||
<!-- 工作台模块 -->
|
||
<div v-if="activeModule === 'dashboard'">
|
||
<h2 class="module-title">工作台</h2>
|
||
|
||
<div class="real-time-data">
|
||
<div class="data-card">
|
||
<div class="data-title">我的项目</div>
|
||
<div class="data-value">{{ myProjects.length }}<span class="data-unit">个</span></div>
|
||
</div>
|
||
<div class="data-card">
|
||
<div class="data-title">进行中任务</div>
|
||
<div class="data-value">{{ ongoingTasks.length }}<span class="data-unit">个</span></div>
|
||
</div>
|
||
<div class="data-card">
|
||
<div class="data-title">待审核报告</div>
|
||
<div class="data-value">{{ pendingReports.length }}<span class="data-unit">份</span></div>
|
||
</div>
|
||
<div class="data-card">
|
||
<div class="data-title">发现缺陷</div>
|
||
<div class="data-value">{{ defectCount }}<span class="data-unit">处</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card-container">
|
||
<el-tabs v-model="dashboardTab">
|
||
<el-tab-pane label="项目进度" name="projects">
|
||
<div class="chart-container" ref="projectChart"></div>
|
||
|
||
<h3>我的项目</h3>
|
||
<el-table :data="myProjects" border style="width: 100%">
|
||
<el-table-column prop="name" label="项目名称" width="200"></el-table-column>
|
||
<el-table-column prop="turbineCount" label="机组数量" width="100"></el-table-column>
|
||
<el-table-column prop="startDate" label="开始日期" width="150"></el-table-column>
|
||
<el-table-column prop="endDate" label="结束日期" width="150"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '进行中' ? 'primary' : scope.row.status === '已完成' ? 'success' : 'info'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="progress" label="进度" width="180">
|
||
<template slot-scope="scope">
|
||
<el-progress :percentage="scope.row.progress" :status="scope.row.status === '已完成' ? 'success' : ''"></el-progress>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewProjectDetail(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="enterProject(scope.row)">进入</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="施工任务" name="tasks">
|
||
<h3>我的任务</h3>
|
||
<el-table :data="myTasks" border style="width: 100%">
|
||
<el-table-column prop="name" label="任务名称" width="180"></el-table-column>
|
||
<el-table-column prop="project" label="所属项目"></el-table-column>
|
||
<el-table-column prop="turbine" label="机组编号" width="120"></el-table-column>
|
||
<el-table-column prop="progress" label="进度" width="120">
|
||
<template slot-scope="scope">
|
||
<el-progress :percentage="scope.row.progress" :status="scope.row.status"></el-progress>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="deadline" label="截止时间" width="180"></el-table-column>
|
||
<el-table-column label="操作" width="120">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewTaskDetail(scope.row)">查看</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="消息通知" name="notifications">
|
||
<el-timeline>
|
||
<el-timeline-item
|
||
v-for="(notification, index) in notifications"
|
||
:key="index"
|
||
:timestamp="notification.time"
|
||
placement="top"
|
||
>
|
||
<el-card>
|
||
<h4>{{ notification.title }}</h4>
|
||
<p>{{ notification.content }}</p>
|
||
<el-button size="mini" v-if="notification.action" @click="handleNotification(notification)">{{ notification.action }}</el-button>
|
||
</el-card>
|
||
</el-timeline-item>
|
||
</el-timeline>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 项目列表模块 -->
|
||
<div v-if="activeModule === 'project-list'">
|
||
<h2 class="module-title">项目列表</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="display: flex; justify-content: space-between; margin-bottom: 20px;">
|
||
<el-input
|
||
placeholder="搜索项目名称"
|
||
v-model="projectSearch"
|
||
clearable
|
||
style="width: 300px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search"></el-button>
|
||
</el-input>
|
||
|
||
<div>
|
||
<el-button type="primary" icon="el-icon-plus" @click="showProjectDialog">新建项目</el-button>
|
||
<el-button icon="el-icon-refresh" @click="refreshProjects">刷新</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<el-tabs v-model="projectTab">
|
||
<el-tab-pane label="全部项目" name="all">
|
||
<el-table :data="filteredProjects" border style="width: 100%">
|
||
<el-table-column prop="name" label="项目名称" width="200"></el-table-column>
|
||
<el-table-column prop="turbineCount" label="机组数量" width="100"></el-table-column>
|
||
<el-table-column prop="startDate" label="开始日期" width="150"></el-table-column>
|
||
<el-table-column prop="endDate" label="结束日期" width="150"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '进行中' ? 'primary' : scope.row.status === '已完成' ? 'success' : 'info'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="progress" label="进度" width="180">
|
||
<template slot-scope="scope">
|
||
<el-progress :percentage="scope.row.progress" :status="scope.row.status === '已完成' ? 'success' : ''"></el-progress>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewProjectDetail(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="enterProject(scope.row)">进入</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="我的项目" name="mine">
|
||
<el-table :data="myProjects" border style="width: 100%">
|
||
<el-table-column prop="name" label="项目名称" width="200"></el-table-column>
|
||
<el-table-column prop="turbineCount" label="机组数量" width="100"></el-table-column>
|
||
<el-table-column prop="startDate" label="开始日期" width="150"></el-table-column>
|
||
<el-table-column prop="endDate" label="结束日期" width="150"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '进行中' ? 'primary' : scope.row.status === '已完成' ? 'success' : 'info'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="progress" label="进度" width="180">
|
||
<template slot-scope="scope">
|
||
<el-progress :percentage="scope.row.progress" :status="scope.row.status === '已完成' ? 'success' : ''"></el-progress>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewProjectDetail(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="enterProject(scope.row)">进入</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="待开工项目" name="pending">
|
||
<el-table :data="pendingProjects" border style="width: 100%">
|
||
<el-table-column prop="name" label="项目名称" width="200"></el-table-column>
|
||
<el-table-column prop="turbineCount" label="机组数量" width="100"></el-table-column>
|
||
<el-table-column prop="startDate" label="开始日期" width="150"></el-table-column>
|
||
<el-table-column prop="endDate" label="结束日期" width="150"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag type="info">{{ scope.row.status }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewProjectDetail(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="enterProject(scope.row)">进入</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 我的施工模块 -->
|
||
<div v-if="activeModule === 'project-construction'">
|
||
<h2 class="module-title">我的施工 - {{ currentProject ? currentProject.name : '请选择项目' }}</h2>
|
||
|
||
<div class="card-container" v-if="currentProject">
|
||
<el-tabs v-model="constructionTab">
|
||
<el-tab-pane label="任务机组" name="turbines">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-input
|
||
placeholder="搜索机组编号"
|
||
v-model="turbineSearch"
|
||
clearable
|
||
style="width: 300px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search"></el-button>
|
||
</el-input>
|
||
</div>
|
||
|
||
<el-table :data="filteredTurbines" border style="width: 100%">
|
||
<el-table-column prop="code" label="机组编号" width="120"></el-table-column>
|
||
<el-table-column prop="type" label="机组类型" width="120"></el-table-column>
|
||
<el-table-column prop="location" label="位置"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '待施工' ? 'info' : scope.row.status === '施工中' ? 'primary' : 'success'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="progress" label="进度" width="180">
|
||
<template slot-scope="scope">
|
||
<el-progress :percentage="scope.row.progress" :status="scope.row.status === '已完成' ? 'success' : ''"></el-progress>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button
|
||
size="mini"
|
||
type="primary"
|
||
@click="startConstruction(scope.row)"
|
||
v-if="scope.row.status === '待施工'"
|
||
>
|
||
开始施工
|
||
</el-button>
|
||
<el-button
|
||
size="mini"
|
||
type="success"
|
||
@click="completeConstruction(scope.row)"
|
||
v-if="scope.row.status === '施工中'"
|
||
>
|
||
完成施工
|
||
</el-button>
|
||
<el-button
|
||
size="mini"
|
||
@click="viewTurbineDetail(scope.row)"
|
||
>
|
||
详情
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="施工报告" name="reports">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-button type="primary" icon="el-icon-plus" @click="createConstructionReport">新建报告</el-button>
|
||
<el-button icon="el-icon-refresh" @click="refreshReports">刷新</el-button>
|
||
</div>
|
||
|
||
<el-table :data="constructionReports" border style="width: 100%">
|
||
<el-table-column prop="turbine" label="机组编号" width="120"></el-table-column>
|
||
<el-table-column prop="date" label="施工日期" width="150"></el-table-column>
|
||
<el-table-column prop="inspector" label="检查人员" width="120"></el-table-column>
|
||
<el-table-column prop="defectCount" label="缺陷数量" width="120"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '草稿' ? 'info' : scope.row.status === '已提交' ? 'primary' : 'success'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewReport(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="editReport(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteReport(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="施工台账" name="records">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-date-picker
|
||
v-model="recordDateRange"
|
||
type="daterange"
|
||
align="right"
|
||
unlink-panels
|
||
range-separator="至"
|
||
start-placeholder="开始日期"
|
||
end-placeholder="结束日期"
|
||
:picker-options="pickerOptions"
|
||
>
|
||
</el-date-picker>
|
||
<el-button type="primary" style="margin-left: 20px;" @click="searchRecords">查询</el-button>
|
||
<el-button @click="exportRecords">导出台账</el-button>
|
||
</div>
|
||
|
||
<el-table :data="constructionRecords" border style="width: 100%">
|
||
<el-table-column prop="date" label="日期" width="150"></el-table-column>
|
||
<el-table-column prop="turbine" label="机组编号" width="120"></el-table-column>
|
||
<el-table-column prop="type" label="工作类型" width="120"></el-table-column>
|
||
<el-table-column prop="content" label="工作内容"></el-table-column>
|
||
<el-table-column prop="operator" label="操作人" width="120"></el-table-column>
|
||
<el-table-column label="操作" width="120">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewRecordDetail(scope.row)">详情</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
|
||
<div class="card-container" v-else>
|
||
<el-alert
|
||
title="请先选择要操作的项目"
|
||
type="info"
|
||
show-icon
|
||
:closable="false"
|
||
>
|
||
</el-alert>
|
||
<el-button type="primary" @click="switchModule('project-list')">选择项目</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 数据入库模块 -->
|
||
<div v-if="activeModule === 'data-import'">
|
||
<h2 class="module-title">数据入库 - {{ currentBlade ? currentBlade.position + '叶片' + currentBlade.type + '检查' : '请选择检查项' }}</h2>
|
||
|
||
<div class="card-container" v-if="currentBlade">
|
||
<el-tabs v-model="activeDataType" class="data-type-tabs">
|
||
<el-tab-pane label="图片" name="image"></el-tab-pane>
|
||
<el-tab-pane label="视频" name="video"></el-tab-pane>
|
||
<el-tab-pane label="语音" name="audio"></el-tab-pane>
|
||
<el-tab-pane label="文档" name="document"></el-tab-pane>
|
||
<el-tab-pane label="其他" name="other"></el-tab-pane>
|
||
</el-tabs>
|
||
|
||
<el-upload
|
||
class="upload-area"
|
||
drag
|
||
action=""
|
||
multiple
|
||
:auto-upload="false"
|
||
:on-change="handleFileChange"
|
||
:file-list="fileList"
|
||
:before-upload="beforeUpload"
|
||
:on-remove="handleRemove"
|
||
>
|
||
<i class="el-icon-upload upload-icon"></i>
|
||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||
<div class="el-upload__tip" slot="tip">支持上传{{ activeDataType === 'image' ? 'JPG/PNG/BMP (不超过10MB)' : activeDataType === 'video' ? 'MP4/AVI/MOV (不超过100MB)' : activeDataType === 'audio' ? 'MP3/WAV (不超过20MB)' : activeDataType === 'document' ? 'PDF/DOC/XLS (不超过50MB)' : '任意 (不超过100MB)' }}格式文件</div>
|
||
</el-upload>
|
||
|
||
<div style="margin: 20px 0;">
|
||
<el-button type="primary" @click="submitUpload">开始上传</el-button>
|
||
<el-button @click="clearFiles">清空文件</el-button>
|
||
<el-button type="text" @click="showBatchImportDialog">批量导入...</el-button>
|
||
</div>
|
||
|
||
<h3>已上传数据</h3>
|
||
<el-table :data="uploadedData" border style="width: 100%; margin-bottom: 20px;">
|
||
<el-table-column prop="name" label="文件名" width="200"></el-table-column>
|
||
<el-table-column prop="type" label="类型" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.type === 'image' ? 'primary' : scope.row.type === 'video' ? 'success' : scope.row.type === 'audio' ? 'warning' : 'info'">
|
||
{{ scope.row.type }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="size" label="大小" width="120"></el-table-column>
|
||
<el-table-column prop="time" label="上传时间" width="180"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '成功' ? 'success' : scope.row.status === '失败' ? 'danger' : 'warning'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="previewFile(scope.row)">预览</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteFile(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<div class="card-container" v-else>
|
||
<el-alert
|
||
title="请先选择要上传数据的检查项"
|
||
type="info"
|
||
show-icon
|
||
:closable="false"
|
||
>
|
||
</el-alert>
|
||
<el-button type="primary" @click="switchModule('project-list')">返回项目列表</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 数据预处理模块 -->
|
||
<div v-if="activeModule === 'data-preprocess'">
|
||
<h2 class="module-title">数据预处理</h2>
|
||
|
||
<div class="card-container">
|
||
<el-steps :active="preprocessStep" finish-status="success" style="margin-bottom: 20px;">
|
||
<el-step title="选择数据"></el-step>
|
||
<el-step title="预处理设置"></el-step>
|
||
<el-step title="执行预处理"></el-step>
|
||
<el-step title="完成"></el-step>
|
||
</el-steps>
|
||
|
||
<div v-if="preprocessStep === 0">
|
||
<h3>选择要预处理的数据</h3>
|
||
<el-select v-model="selectedProject" placeholder="请选择项目" style="width: 300px;">
|
||
<el-option
|
||
v-for="project in projects"
|
||
:key="project.id"
|
||
:label="project.name"
|
||
:value="project.id"
|
||
></el-option>
|
||
</el-select>
|
||
|
||
<div style="margin-top: 20px;">
|
||
<el-table :data="preprocessData" border style="width: 100%">
|
||
<el-table-column type="selection" width="55"></el-table-column>
|
||
<el-table-column prop="name" label="文件名" width="200"></el-table-column>
|
||
<el-table-column prop="type" label="类型" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.type === 'image' ? 'primary' : scope.row.type === 'video' ? 'success' : 'info'">
|
||
{{ scope.row.type }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="size" label="大小" width="120"></el-table-column>
|
||
<el-table-column prop="time" label="上传时间" width="180"></el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<div style="margin-top: 20px;">
|
||
<el-button type="primary" @click="preprocessStep = 1">下一步</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="preprocessStep === 1">
|
||
<h3>预处理设置</h3>
|
||
<el-form :model="preprocessForm" label-width="120px">
|
||
<el-form-item label="图像处理">
|
||
<el-checkbox-group v-model="preprocessForm.imageOptions">
|
||
<el-checkbox label="去噪"></el-checkbox>
|
||
<el-checkbox label="增强"></el-checkbox>
|
||
<el-checkbox label="裁剪"></el-checkbox>
|
||
<el-checkbox label="旋转校正"></el-checkbox>
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
<el-form-item label="视频处理">
|
||
<el-checkbox-group v-model="preprocessForm.videoOptions">
|
||
<el-checkbox label="关键帧提取"></el-checkbox>
|
||
<el-checkbox label="稳定化"></el-checkbox>
|
||
<el-checkbox label="分辨率调整"></el-checkbox>
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
<el-form-item label="输出格式">
|
||
<el-select v-model="preprocessForm.outputFormat" placeholder="请选择输出格式">
|
||
<el-option label="JPG" value="jpg"></el-option>
|
||
<el-option label="PNG" value="png"></el-option>
|
||
<el-option label="MP4" value="mp4"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="输出目录">
|
||
<el-input v-model="preprocessForm.outputPath" placeholder="请输入输出目录"></el-input>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<div style="margin-top: 20px;">
|
||
<el-button @click="preprocessStep = 0">上一步</el-button>
|
||
<el-button type="primary" @click="preprocessStep = 2">下一步</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="preprocessStep === 2">
|
||
<h3>执行预处理</h3>
|
||
<div style="margin-bottom: 20px;">
|
||
<el-progress :percentage="preprocessProgress"></el-progress>
|
||
<div style="margin-top: 10px; color: #909399;">
|
||
{{ preprocessStatus }}
|
||
</div>
|
||
</div>
|
||
|
||
<el-button @click="preprocessStep = 1">上一步</el-button>
|
||
<el-button type="primary" @click="startPreprocess" :disabled="preprocessRunning">开始预处理</el-button>
|
||
</div>
|
||
|
||
<div v-if="preprocessStep === 3">
|
||
<el-result
|
||
icon="success"
|
||
title="预处理完成"
|
||
subTitle="数据预处理已成功完成"
|
||
>
|
||
<template slot="extra">
|
||
<el-button type="primary" size="medium" @click="viewPreprocessResults">查看结果</el-button>
|
||
<el-button size="medium" @click="preprocessStep = 0">继续处理</el-button>
|
||
</template>
|
||
</el-result>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 缺陷检测算法模块 -->
|
||
<div v-if="activeModule === 'inspection-defect'">
|
||
<h2 class="module-title">缺陷检测算法</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-button type="primary" @click="runDefectDetection" icon="el-icon-cpu">运行缺陷检测算法</el-button>
|
||
<el-button @click="showDetectionSettings" icon="el-icon-setting">检测设置</el-button>
|
||
<el-button @click="exportDetectionResults" icon="el-icon-download" :disabled="defectDetectionResults.length === 0">导出结果</el-button>
|
||
</div>
|
||
|
||
<div v-if="detectionRunning" style="margin-bottom: 20px;">
|
||
<el-progress :percentage="detectionProgress"></el-progress>
|
||
<div style="margin-top: 10px; color: #909399;">
|
||
正在检测: {{ detectionStatus }}
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="defectDetectionResults.length > 0">
|
||
<h3>检测结果</h3>
|
||
<el-table :data="defectDetectionResults" border style="width: 100%">
|
||
<el-table-column prop="type" label="缺陷类型" width="180"></el-table-column>
|
||
<el-table-column prop="position" label="位置"></el-table-column>
|
||
<el-table-column prop="size" label="尺寸" width="120"></el-table-column>
|
||
<el-table-column prop="severity" label="严重程度" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.severity === '高' ? 'danger' : scope.row.severity === '中' ? 'warning' : 'success'">
|
||
{{ scope.row.severity }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="图片" width="120">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="previewDefectImages(scope.row)">查看({{ scope.row.images.length }})</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewDefectDetail(scope.row)">详情</el-button>
|
||
<el-button size="mini" type="danger" @click="markAsFalseAlarm(scope.row)">误报</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 树状可视化管理模块 -->
|
||
<div v-if="activeModule === 'inspection-tree'">
|
||
<h2 class="module-title">树状可视化管理</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="height: 600px; display: flex;">
|
||
<div style="width: 300px; border-right: 1px solid #ebeef5; padding-right: 20px; overflow-y: auto;">
|
||
<el-input
|
||
placeholder="搜索机组或叶片"
|
||
v-model="treeSearch"
|
||
clearable
|
||
style="margin-bottom: 15px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search"></el-button>
|
||
</el-input>
|
||
|
||
<el-tree
|
||
:data="treeData"
|
||
:props="treeProps"
|
||
node-key="id"
|
||
default-expand-all
|
||
:filter-node-method="filterTreeNode"
|
||
@node-click="handleTreeNodeClick"
|
||
:expand-on-click-node="false"
|
||
ref="tree"
|
||
>
|
||
<span class="custom-tree-node" slot-scope="{ node, data }">
|
||
<span>
|
||
<i :class="data.type === 'turbine' ? 'el-icon-office-building' : 'el-icon-wind-power'" style="margin-right: 5px;"></i>
|
||
{{ node.label }}
|
||
</span>
|
||
<span v-if="data.type === 'blade' && data.status" style="margin-left: 10px;">
|
||
<el-tag size="mini" :type="data.status === '正常' ? 'success' : 'danger'">
|
||
{{ data.status }}
|
||
</el-tag>
|
||
</span>
|
||
</span>
|
||
</el-tree>
|
||
</div>
|
||
|
||
<div style="flex: 1; padding-left: 20px;">
|
||
<div v-if="selectedTreeNode" style="margin-bottom: 20px;">
|
||
<h3>{{ selectedTreeNode.type === 'turbine' ? '机组' : '叶片' }}详情</h3>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="名称">{{ selectedTreeNode.label }}</el-descriptions-item>
|
||
<el-descriptions-item label="类型">{{ selectedTreeNode.type === 'turbine' ? '机组' : '叶片' }}</el-descriptions-item>
|
||
<el-descriptions-item label="状态" v-if="selectedTreeNode.status">
|
||
<el-tag :type="selectedTreeNode.status === '正常' ? 'success' : 'danger'">
|
||
{{ selectedTreeNode.status }}
|
||
</el-tag>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="最后检查时间" v-if="selectedTreeNode.lastInspection">
|
||
{{ selectedTreeNode.lastInspection }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="缺陷数量" v-if="selectedTreeNode.defects">
|
||
{{ selectedTreeNode.defects }}处
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<div v-if="selectedTreeNode.type === 'blade' && selectedTreeNode.images" style="margin-top: 20px;">
|
||
<h4>检查图片</h4>
|
||
<div style="display: flex; flex-wrap: wrap;">
|
||
<div
|
||
v-for="(img, index) in selectedTreeNode.images"
|
||
:key="index"
|
||
class="defect-image-preview"
|
||
@click="previewImage(img)"
|
||
>
|
||
<img :src="img.thumbnail" style="width: 100%; height: 100%; object-fit: cover;">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else style="height: 500px; display: flex; align-items: center; justify-content: center; color: #909399;">
|
||
请从左侧选择机组或叶片查看详情
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 标准信息库模块 -->
|
||
<div v-if="activeModule === 'inspection-standard'">
|
||
<h2 class="module-title">标准信息库</h2>
|
||
|
||
<div class="card-container">
|
||
<el-tabs v-model="standardTab">
|
||
<el-tab-pane label="缺陷标准" name="defect">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-button type="primary" icon="el-icon-plus" @click="showAddStandardDialog('defect')">新增缺陷标准</el-button>
|
||
<el-button icon="el-icon-download" @click="exportStandards('defect')">导出标准</el-button>
|
||
<el-button icon="el-icon-upload2">导入标准</el-button>
|
||
</div>
|
||
|
||
<el-table :data="defectStandards" border style="width: 100%">
|
||
<el-table-column prop="code" label="缺陷代码" width="120"></el-table-column>
|
||
<el-table-column prop="name" label="缺陷名称" width="180"></el-table-column>
|
||
<el-table-column prop="category" label="缺陷类别" width="120"></el-table-column>
|
||
<el-table-column prop="severity" label="严重程度" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.severity === '高' ? 'danger' : scope.row.severity === '中' ? 'warning' : 'success'">
|
||
{{ scope.row.severity }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="description" label="缺陷描述"></el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="editStandard(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteStandard(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="检查标准" name="inspection">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-button type="primary" icon="el-icon-plus" @click="showAddStandardDialog('inspection')">新增检查标准</el-button>
|
||
<el-button icon="el-icon-download" @click="exportStandards('inspection')">导出标准</el-button>
|
||
<el-button icon="el-icon-upload2">导入标准</el-button>
|
||
</div>
|
||
|
||
<el-table :data="inspectionStandards" border style="width: 100%">
|
||
<el-table-column prop="code" label="标准代码" width="120"></el-table-column>
|
||
<el-table-column prop="name" label="标准名称" width="180"></el-table-column>
|
||
<el-table-column prop="category" label="适用部位" width="120"></el-table-column>
|
||
<el-table-column prop="method" label="检查方法" width="120"></el-table-column>
|
||
<el-table-column prop="description" label="标准描述"></el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="editStandard(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteStandard(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="维修标准" name="repair">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-button type="primary" icon="el-icon-plus" @click="showAddStandardDialog('repair')">新增维修标准</el-button>
|
||
<el-button icon="el-icon-download" @click="exportStandards('repair')">导出标准</el-button>
|
||
<el-button icon="el-icon-upload2">导入标准</el-button>
|
||
</div>
|
||
|
||
<el-table :data="repairStandards" border style="width: 100%">
|
||
<el-table-column prop="code" label="标准代码" width="120"></el-table-column>
|
||
<el-table-column prop="name" label="标准名称" width="180"></el-table-column>
|
||
<el-table-column prop="defectType" label="适用缺陷" width="120"></el-table-column>
|
||
<el-table-column prop="method" label="维修方法" width="120"></el-table-column>
|
||
<el-table-column prop="description" label="标准描述"></el-table-column>
|
||
<el-table-column prop="material" label="所需材料" width="180"></el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="editStandard(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteStandard(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 报告生成模块 -->
|
||
<div v-if="activeModule === 'inspection-report'">
|
||
<h2 class="module-title">报告生成</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-button type="primary" icon="el-icon-plus" @click="generateNewReport">生成新报告</el-button>
|
||
<el-button icon="el-icon-refresh" @click="refreshReportsList">刷新列表</el-button>
|
||
<el-button icon="el-icon-download" @click="exportAllReports">导出全部</el-button>
|
||
</div>
|
||
|
||
<el-table :data="reportList" border style="width: 100%">
|
||
<el-table-column prop="name" label="报告名称" width="200"></el-table-column>
|
||
<el-table-column prop="project" label="所属项目" width="180"></el-table-column>
|
||
<el-table-column prop="turbine" label="机组编号" width="120"></el-table-column>
|
||
<el-table-column prop="date" label="生成日期" width="150"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '已发布' ? 'success' : scope.row.status === '待审核' ? 'warning' : 'info'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="250">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewReport(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="editReport(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="success" @click="publishReport(scope.row)" :disabled="scope.row.status === '已发布'">发布</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteReport(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<!-- 报告预览对话框 -->
|
||
<el-dialog title="报告预览" :visible.sync="reportPreviewDialogVisible" width="80%" top="5vh">
|
||
<div class="report-preview" v-if="currentReport">
|
||
<div class="report-section">
|
||
<h2 class="report-title">{{ currentReport.name }}</h2>
|
||
<div class="report-content">
|
||
<p><strong>项目名称:</strong> {{ currentReport.project }}</p>
|
||
<p><strong>机组编号:</strong> {{ currentReport.turbine }}</p>
|
||
<p><strong>检查日期:</strong> {{ currentReport.date }}</p>
|
||
<p><strong>检查人员:</strong> {{ currentReport.inspector }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="report-section">
|
||
<h3 class="report-title">检查概况</h3>
|
||
<div class="report-content">
|
||
<p>{{ currentReport.summary }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="report-section" v-if="currentReport.defects && currentReport.defects.length > 0">
|
||
<h3 class="report-title">缺陷列表</h3>
|
||
<div class="report-content">
|
||
<div class="defect-item" v-for="(defect, index) in currentReport.defects" :key="index">
|
||
<div class="defect-title">{{ defect.code }} - {{ defect.name }} ({{ defect.severity }})</div>
|
||
<div class="defect-desc">{{ defect.description }}</div>
|
||
<div class="defect-images" v-if="defect.images && defect.images.length > 0">
|
||
<img
|
||
v-for="(img, imgIndex) in defect.images"
|
||
:key="imgIndex"
|
||
:src="img.thumbnail"
|
||
class="defect-image-preview"
|
||
@click="previewImage(img.full)"
|
||
>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="report-section">
|
||
<h3 class="report-title">检查结论</h3>
|
||
<div class="report-content">
|
||
<p>{{ currentReport.conclusion }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="report-section" v-if="currentReport.recommendations">
|
||
<h3 class="report-title">处理建议</h3>
|
||
<div class="report-content">
|
||
<p>{{ currentReport.recommendations }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="reportPreviewDialogVisible = false">关闭</el-button>
|
||
<el-button type="primary" @click="downloadReport(currentReport)">下载报告</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</div>
|
||
|
||
<!-- 全生命周期管理模块 -->
|
||
<div v-if="activeModule === 'inspection-lifecycle'">
|
||
<h2 class="module-title">全生命周期管理</h2>
|
||
|
||
<div class="card-container">
|
||
<el-tabs v-model="lifecycleTab">
|
||
<el-tab-pane label="机组档案" name="turbine">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-input
|
||
placeholder="搜索机组编号或名称"
|
||
v-model="turbineSearch"
|
||
clearable
|
||
style="width: 300px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search"></el-button>
|
||
</el-input>
|
||
</div>
|
||
|
||
<el-table :data="filteredTurbines" border style="width: 100%">
|
||
<el-table-column prop="code" label="机组编号" width="120"></el-table-column>
|
||
<el-table-column prop="name" label="机组名称" width="180"></el-table-column>
|
||
<el-table-column prop="type" label="机组类型" width="120"></el-table-column>
|
||
<el-table-column prop="location" label="地理位置"></el-table-column>
|
||
<el-table-column prop="installDate" label="投运日期" width="120"></el-table-column>
|
||
<el-table-column prop="status" label="运行状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '运行中' ? 'success' : scope.row.status === '停机' ? 'warning' : 'danger'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewTurbineLifecycle(scope.row)">查看</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="叶片档案" name="blade">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-input
|
||
placeholder="搜索叶片编号或所属机组"
|
||
v-model="bladeSearch"
|
||
clearable
|
||
style="width: 300px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search"></el-button>
|
||
</el-input>
|
||
</div>
|
||
|
||
<el-table :data="filteredBlades" border style="width: 100%">
|
||
<el-table-column prop="code" label="叶片编号" width="120"></el-table-column>
|
||
<el-table-column prop="turbine" label="所属机组" width="180"></el-table-column>
|
||
<el-table-column prop="position" label="叶片位置" width="120"></el-table-column>
|
||
<el-table-column prop="type" label="叶片型号" width="120"></el-table-column>
|
||
<el-table-column prop="manufacturer" label="制造商" width="120"></el-table-column>
|
||
<el-table-column prop="status" label="当前状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '正常' ? 'success' : 'danger'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewBladeLifecycle(scope.row)">查看</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
|
||
<!-- 机组生命周期详情对话框 -->
|
||
<el-dialog :title="currentTurbine ? currentTurbine.name + ' - 生命周期记录' : '机组生命周期'" :visible.sync="turbineLifecycleDialogVisible" width="80%">
|
||
<div v-if="currentTurbine">
|
||
<el-descriptions :column="3" border style="margin-bottom: 20px;">
|
||
<el-descriptions-item label="机组编号">{{ currentTurbine.code }}</el-descriptions-item>
|
||
<el-descriptions-item label="机组类型">{{ currentTurbine.type }}</el-descriptions-item>
|
||
<el-descriptions-item label="投运日期">{{ currentTurbine.installDate }}</el-descriptions-item>
|
||
<el-descriptions-item label="地理位置">{{ currentTurbine.location }}</el-descriptions-item>
|
||
<el-descriptions-item label="运行状态">
|
||
<el-tag :type="currentTurbine.status === '运行中' ? 'success' : currentTurbine.status === '停机' ? 'warning' : 'danger'">
|
||
{{ currentTurbine.status }}
|
||
</el-tag>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="累计发电量">{{ currentTurbine.totalPower }} kWh</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<h3 style="margin-bottom: 15px;">生命周期事件</h3>
|
||
<el-timeline>
|
||
<el-timeline-item
|
||
v-for="(event, index) in turbineLifecycleEvents"
|
||
:key="index"
|
||
:timestamp="event.time"
|
||
placement="top"
|
||
:type="event.type === '检查' ? 'primary' : event.type === '维修' ? 'warning' : event.type === '更换' ? 'danger' : 'info'"
|
||
>
|
||
<el-card>
|
||
<h4>{{ event.type }} - {{ event.title }}</h4>
|
||
<p>{{ event.description }}</p>
|
||
<div v-if="event.images && event.images.length > 0" style="margin-top: 10px;">
|
||
<el-image
|
||
v-for="(img, imgIndex) in event.images"
|
||
:key="imgIndex"
|
||
:src="img.thumbnail"
|
||
:preview-src-list="[img.full]"
|
||
style="width: 100px; height: 100px; margin-right: 10px;"
|
||
></el-image>
|
||
</div>
|
||
</el-card>
|
||
</el-timeline-item>
|
||
</el-timeline>
|
||
</div>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="turbineLifecycleDialogVisible = false">关闭</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</div>
|
||
|
||
<!-- 可靠性评估模块 -->
|
||
<div v-if="activeModule === 'delivery-reliability'">
|
||
<h2 class="module-title">可靠性评估</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-select v-model="selectedProject" placeholder="请选择项目" style="width: 300px;">
|
||
<el-option
|
||
v-for="project in projects"
|
||
:key="project.id"
|
||
:label="project.name"
|
||
:value="project.id"
|
||
></el-option>
|
||
</el-select>
|
||
<el-button type="primary" @click="generateReliabilityReport" style="margin-left: 20px;">生成评估报告</el-button>
|
||
</div>
|
||
|
||
<div v-if="reliabilityData" class="chart-container" ref="reliabilityChart"></div>
|
||
|
||
<div v-if="reliabilityData" style="margin-top: 20px;">
|
||
<h3>评估结果</h3>
|
||
<el-table :data="reliabilityData.details" border style="width: 100%">
|
||
<el-table-column prop="turbine" label="机组编号" width="120"></el-table-column>
|
||
<el-table-column prop="score" label="可靠性评分" width="120">
|
||
<template slot-scope="scope">
|
||
<el-rate
|
||
v-model="scope.row.score"
|
||
disabled
|
||
show-score
|
||
text-color="#ff9900"
|
||
score-template="{value} 分"
|
||
></el-rate>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="defectCount" label="缺陷数量" width="120"></el-table-column>
|
||
<el-table-column prop="severity" label="严重程度" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.severity === '高' ? 'danger' : scope.row.severity === '中' ? 'warning' : 'success'">
|
||
{{ scope.row.severity }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="recommendation" label="维护建议"></el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<div v-if="reliabilityData" style="margin-top: 20px;">
|
||
<el-button type="primary" @click="exportReliabilityReport">导出评估报告</el-button>
|
||
<el-button @click="printReliabilityReport">打印</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 数据质量评估模块 -->
|
||
<div v-if="activeModule === 'delivery-quality'">
|
||
<h2 class="module-title">数据质量评估</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-select v-model="selectedProject" placeholder="请选择项目" style="width: 300px;">
|
||
<el-option
|
||
v-for="project in projects"
|
||
:key="project.id"
|
||
:label="project.name"
|
||
:value="project.id"
|
||
></el-option>
|
||
</el-select>
|
||
<el-button type="primary" @click="generateQualityReport" style="margin-left: 20px;">生成质量报告</el-button>
|
||
</div>
|
||
|
||
<div v-if="qualityData" class="chart-container" ref="qualityChart"></div>
|
||
|
||
<div v-if="qualityData" style="margin-top: 20px;">
|
||
<h3>质量评估指标</h3>
|
||
<el-table :data="qualityData.metrics" border style="width: 100%">
|
||
<el-table-column prop="name" label="指标名称" width="180"></el-table-column>
|
||
<el-table-column prop="score" label="评分" width="120">
|
||
<template slot-scope="scope">
|
||
<el-progress :percentage="scope.row.score" :status="scope.row.score >= 90 ? 'success' : scope.row.score >= 70 ? '' : 'exception'"></el-progress>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="description" label="说明"></el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<div v-if="qualityData" style="margin-top: 20px;">
|
||
<h3>改进建议</h3>
|
||
<el-card shadow="never">
|
||
<div v-html="qualityData.suggestions"></div>
|
||
</el-card>
|
||
</div>
|
||
|
||
<div v-if="qualityData" style="margin-top: 20px;">
|
||
<el-button type="primary" @click="exportQualityReport">导出质量报告</el-button>
|
||
<el-button @click="printQualityReport">打印</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 质量入库模块 -->
|
||
<div v-if="activeModule === 'delivery-storage'">
|
||
<h2 class="module-title">质量入库</h2>
|
||
|
||
<div class="card-container">
|
||
<el-steps :active="storageStep" finish-status="success" style="margin-bottom: 20px;">
|
||
<el-step title="选择项目"></el-step>
|
||
<el-step title="数据验证"></el-step>
|
||
<el-step title="质量检查"></el-step>
|
||
<el-step title="入库完成"></el-step>
|
||
</el-steps>
|
||
|
||
<div v-if="storageStep === 0">
|
||
<h3>选择要入库的项目</h3>
|
||
<el-select v-model="selectedProject" placeholder="请选择项目" style="width: 300px;">
|
||
<el-option
|
||
v-for="project in projects"
|
||
:key="project.id"
|
||
:label="project.name"
|
||
:value="project.id"
|
||
></el-option>
|
||
</el-select>
|
||
<el-button type="primary" @click="checkProjectData" style="margin-left: 20px;">检查数据</el-button>
|
||
</div>
|
||
|
||
<div v-if="storageStep === 1">
|
||
<h3>数据验证结果</h3>
|
||
<el-table :data="storageCheckResults" border style="width: 100%; margin-bottom: 20px;">
|
||
<el-table-column prop="item" label="检查项" width="200"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '通过' ? 'success' : 'danger'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="message" label="说明"></el-table-column>
|
||
</el-table>
|
||
|
||
<el-button type="primary" @click="storageStep = 2" :disabled="!canProceedToNextStep">下一步</el-button>
|
||
</div>
|
||
|
||
<div v-if="storageStep === 2">
|
||
<h3>质量检查</h3>
|
||
<el-form :model="storageForm" label-width="120px">
|
||
<el-form-item label="数据质量评分">
|
||
<el-rate
|
||
v-model="storageForm.qualityScore"
|
||
show-text
|
||
:texts="['很差', '较差', '一般', '良好', '优秀']"
|
||
></el-rate>
|
||
</el-form-item>
|
||
<el-form-item label="入库备注">
|
||
<el-input type="textarea" v-model="storageForm.notes"></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="入库位置">
|
||
<el-select v-model="storageForm.storageLocation" placeholder="请选择入库位置">
|
||
<el-option label="主数据库" value="main"></el-option>
|
||
<el-option label="历史数据库" value="history"></el-option>
|
||
<el-option label="测试数据库" value="test"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<el-button @click="storageStep = 1">上一步</el-button>
|
||
<el-button type="primary" @click="completeStorage">完成入库</el-button>
|
||
</div>
|
||
|
||
<div v-if="storageStep === 3">
|
||
<el-result
|
||
icon="success"
|
||
title="入库成功"
|
||
subTitle="项目数据已成功入库"
|
||
>
|
||
<template slot="extra">
|
||
<el-button type="primary" size="medium" @click="viewStoredData">查看入库数据</el-button>
|
||
<el-button size="medium" @click="storageStep = 0">继续入库</el-button>
|
||
</template>
|
||
</el-result>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 净空距离模块 -->
|
||
<div v-if="activeModule === 'monitor-clearance'">
|
||
<h2 class="module-title">净空距离监测</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-date-picker
|
||
v-model="monitorDate"
|
||
type="date"
|
||
placeholder="选择监测日期"
|
||
>
|
||
</el-date-picker>
|
||
<el-button type="primary" style="margin-left: 20px;" @click="searchMonitorData">查询</el-button>
|
||
<el-button @click="exportMonitorData">导出数据</el-button>
|
||
</div>
|
||
|
||
<div class="chart-container" ref="clearanceChart"></div>
|
||
|
||
<el-table :data="clearanceData" border style="width: 100%; margin-top: 20px;">
|
||
<el-table-column prop="time" label="时间" width="180"></el-table-column>
|
||
<el-table-column prop="turbine" label="机组编号" width="120"></el-table-column>
|
||
<el-table-column prop="distance" label="净空距离(m)" width="120"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '正常' ? 'success' : 'danger'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="120">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewClearanceDetail(scope.row)">详情</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 形变监测模块 -->
|
||
<div v-if="activeModule === 'monitor-deformation'">
|
||
<h2 class="module-title">形变监测</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-date-picker
|
||
v-model="deformationDateRange"
|
||
type="daterange"
|
||
align="right"
|
||
unlink-panels
|
||
range-separator="至"
|
||
start-placeholder="开始日期"
|
||
end-placeholder="结束日期"
|
||
:picker-options="pickerOptions"
|
||
>
|
||
</el-date-picker>
|
||
<el-button type="primary" style="margin-left: 20px;" @click="searchDeformationData">查询</el-button>
|
||
<el-button @click="exportDeformationData">导出数据</el-button>
|
||
</div>
|
||
|
||
<div class="chart-container" ref="deformationChart"></div>
|
||
|
||
<el-table :data="deformationData" border style="width: 100%; margin-top: 20px;">
|
||
<el-table-column prop="date" label="日期" width="150"></el-table-column>
|
||
<el-table-column prop="turbine" label="机组编号" width="120"></el-table-column>
|
||
<el-table-column prop="deformationX" label="X方向形变(mm)" width="150"></el-table-column>
|
||
<el-table-column prop="deformationY" label="Y方向形变(mm)" width="150"></el-table-column>
|
||
<el-table-column prop="deformationZ" label="Z方向形变(mm)" width="150"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '正常' ? 'success' : 'danger'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="120">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewDeformationDetail(scope.row)">详情</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 图像检测模块 -->
|
||
<div v-if="activeModule === 'monitor-image'">
|
||
<h2 class="module-title">图像检测</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-date-picker
|
||
v-model="imageDate"
|
||
type="date"
|
||
placeholder="选择监测日期"
|
||
>
|
||
</el-date-picker>
|
||
<el-button type="primary" style="margin-left: 20px;" @click="searchImageData">查询</el-button>
|
||
<el-button @click="exportImageData">导出数据</el-button>
|
||
</div>
|
||
|
||
<div style="display: flex; flex-wrap: wrap;">
|
||
<div class="monitor-card" style="width: calc(50% - 10px); margin-right: 20px; margin-bottom: 20px;" v-for="(item, index) in imageData" :key="index">
|
||
<div class="monitor-card-header">
|
||
{{ item.turbine }} - {{ item.time }}
|
||
<el-tag :type="item.status === '正常' ? 'success' : 'danger'" size="small">
|
||
{{ item.status }}
|
||
</el-tag>
|
||
</div>
|
||
<div class="monitor-card-body">
|
||
<img :src="item.image" style="width: 100%; cursor: pointer;" @click="previewImage(item.image)">
|
||
<div style="margin-top: 10px;">
|
||
<el-tag v-for="(defect, i) in item.defects" :key="i" style="margin-right: 5px; margin-bottom: 5px;">
|
||
{{ defect.type }} ({{ defect.severity }})
|
||
</el-tag>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 航线规划模块 -->
|
||
<div v-if="activeModule === 'others-route'">
|
||
<h2 class="module-title">航线规划</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-button type="primary" icon="el-icon-plus" @click="createNewRoute">新建航线</el-button>
|
||
<el-button icon="el-icon-refresh" @click="refreshRoutes">刷新</el-button>
|
||
<el-button icon="el-icon-download" @click="exportRoutes">导出航线</el-button>
|
||
</div>
|
||
|
||
<div style="height: 600px; display: flex;">
|
||
<div style="width: 300px; border-right: 1px solid #ebeef5; padding-right: 20px; overflow-y: auto;">
|
||
<el-input
|
||
placeholder="搜索航线名称"
|
||
v-model="routeSearch"
|
||
clearable
|
||
style="margin-bottom: 15px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search"></el-button>
|
||
</el-input>
|
||
|
||
<el-table :data="filteredRoutes" border style="width: 100%">
|
||
<el-table-column prop="name" label="航线名称"></el-table-column>
|
||
<el-table-column label="操作" width="80">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewRoute(scope.row)">查看</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<div style="flex: 1; padding-left: 20px;">
|
||
<div v-if="currentRoute" style="margin-bottom: 20px;">
|
||
<h3>{{ currentRoute.name }}</h3>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="创建人">{{ currentRoute.creator }}</el-descriptions-item>
|
||
<el-descriptions-item label="创建时间">{{ currentRoute.createTime }}</el-descriptions-item>
|
||
<el-descriptions-item label="适用机型">{{ currentRoute.droneType }}</el-descriptions-item>
|
||
<el-descriptions-item label="航线长度">{{ currentRoute.length }} km</el-descriptions-item>
|
||
<el-descriptions-item label="预计耗时">{{ currentRoute.duration }} min</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<div style="margin-top: 20px;">
|
||
<img :src="currentRoute.preview" style="width: 100%; border: 1px solid #ebeef5;">
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else style="height: 500px; display: flex; align-items: center; justify-content: center; color: #909399;">
|
||
请从左侧选择航线查看详情
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 三维模型模块 -->
|
||
<div v-if="activeModule === 'others-model'">
|
||
<h2 class="module-title">三维模型</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-button type="primary" icon="el-icon-plus" @click="uploadModel">上传模型</el-button>
|
||
<el-button icon="el-icon-refresh" @click="refreshModels">刷新</el-button>
|
||
<el-button icon="el-icon-download" @click="exportModels">导出模型</el-button>
|
||
</div>
|
||
|
||
<div style="display: flex; flex-wrap: wrap;">
|
||
<div class="monitor-card" style="width: calc(33.33% - 14px); margin-right: 20px; margin-bottom: 20px;" v-for="(model, index) in models" :key="index">
|
||
<div class="monitor-card-header">
|
||
{{ model.name }}
|
||
<el-tag size="small" style="float: right;">{{ model.type }}</el-tag>
|
||
</div>
|
||
<div class="monitor-card-body">
|
||
<img :src="model.thumbnail" style="width: 100%; height: 180px; object-fit: cover; cursor: pointer;" @click="viewModel(model)">
|
||
<div style="margin-top: 10px;">
|
||
<el-button size="mini" @click="viewModel(model)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="editModel(model)">编辑</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteModel(model)">删除</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 报告模板库模块 -->
|
||
<div v-if="activeModule === 'others-template'">
|
||
<h2 class="module-title">报告模板库</h2>
|
||
|
||
<div class="card-container">
|
||
<div style="margin-bottom: 20px;">
|
||
<el-input
|
||
placeholder="搜索模板名称"
|
||
v-model="templateSearch"
|
||
clearable
|
||
style="width: 300px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search"></el-button>
|
||
</el-input>
|
||
<el-button type="primary" style="margin-left: 20px;" icon="el-icon-plus" @click="createTemplate">新建模板</el-button>
|
||
</div>
|
||
|
||
<el-table :data="filteredTemplates" border style="width: 100%">
|
||
<el-table-column prop="name" label="模板名称" width="200"></el-table-column>
|
||
<el-table-column prop="type" label="模板类型" width="120"></el-table-column>
|
||
<el-table-column prop="creator" label="创建人" width="120"></el-table-column>
|
||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||
<el-table-column prop="description" label="描述"></el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewTemplate(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="editTemplate(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteTemplate(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 系统设置模块 -->
|
||
<div v-if="activeModule === 'others-settings'">
|
||
<h2 class="module-title">系统设置</h2>
|
||
|
||
<div class="card-container">
|
||
<el-tabs v-model="settingsTab">
|
||
<el-tab-pane label="个人设置" name="personal">
|
||
<el-form :model="settingsForm" label-width="120px">
|
||
<el-form-item label="主题颜色">
|
||
<el-color-picker v-model="settingsForm.themeColor"></el-color-picker>
|
||
</el-form-item>
|
||
<el-form-item label="通知方式">
|
||
<el-checkbox-group v-model="settingsForm.notificationMethods">
|
||
<el-checkbox label="站内消息" name="type"></el-checkbox>
|
||
<el-checkbox label="电子邮件" name="type"></el-checkbox>
|
||
<el-checkbox label="手机短信" name="type"></el-checkbox>
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" @click="saveSettings">保存设置</el-button>
|
||
<el-button @click="resetSettings">恢复默认</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="系统维护" name="system">
|
||
<el-form :model="systemForm" label-width="120px">
|
||
<el-form-item label="数据备份">
|
||
<el-switch v-model="systemForm.autoBackup"></el-switch>
|
||
<span style="margin-left: 10px; color: #909399;">{{ systemForm.autoBackup ? '已开启' : '已关闭' }}</span>
|
||
</el-form-item>
|
||
<el-form-item label="备份频率">
|
||
<el-select v-model="systemForm.backupFrequency" :disabled="!systemForm.autoBackup">
|
||
<el-option label="每天" value="daily"></el-option>
|
||
<el-option label="每周" value="weekly"></el-option>
|
||
<el-option label="每月" value="monthly"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="备份目录">
|
||
<el-input v-model="systemForm.backupPath"></el-input>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" @click="backupNow">立即备份</el-button>
|
||
<el-button @click="restoreBackup">恢复备份</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="关于系统" name="about">
|
||
<div style="text-align: center; margin: 30px 0;">
|
||
<h3>风电叶片检查智能管理平台</h3>
|
||
<p style="margin: 20px 0; color: #606266;">版本: 2.1.0</p>
|
||
<p style="margin: 20px 0; color: #606266;">© 2023 风电科技股份有限公司 版权所有</p>
|
||
<img src="https://via.placeholder.com/200x100?text=Company+Logo" style="max-width: 200px;">
|
||
</div>
|
||
|
||
<div style="margin-top: 30px;">
|
||
<h4>系统依赖</h4>
|
||
<el-table :data="dependencies" border style="width: 100%">
|
||
<el-table-column prop="name" label="名称" width="200"></el-table-column>
|
||
<el-table-column prop="version" label="版本" width="120"></el-table-column>
|
||
<el-table-column prop="license" label="许可证"></el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 图片预览对话框 -->
|
||
<el-dialog :visible.sync="imagePreviewDialogVisible" class="image-preview-dialog">
|
||
<img :src="previewImageUrl" class="full-image">
|
||
</el-dialog>
|
||
</div>
|
||
|
||
<script>
|
||
new Vue({
|
||
el: '#app',
|
||
data() {
|
||
return {
|
||
isCollapse: false,
|
||
activeModule: 'dashboard',
|
||
dashboardTab: 'projects',
|
||
projectTab: 'all',
|
||
constructionTab: 'turbines',
|
||
standardTab: 'defect',
|
||
lifecycleTab: 'turbine',
|
||
settingsTab: 'personal',
|
||
|
||
// 用户信息
|
||
userInfo: {
|
||
name: '张工程师',
|
||
role: '施工组长'
|
||
},
|
||
|
||
// 工作台数据
|
||
myProjects: [
|
||
{ id: 1, name: 'A风场2023年检查', turbineCount: 15, startDate: '2023-10-01', endDate: '2023-12-31', status: '进行中', progress: 65 },
|
||
{ id: 2, name: 'B风场维修项目', turbineCount: 8, startDate: '2023-09-15', endDate: '2023-11-30', status: '进行中', progress: 45 }
|
||
],
|
||
ongoingTasks: [
|
||
{ name: 'A风场1-5号机组检查', project: 'A风场2023年检查', progress: 65, status: 'success', deadline: '2023-11-15' },
|
||
{ name: 'B风场缺陷修复', project: 'B风场维修项目', progress: 30, status: 'exception', deadline: '2023-11-20' }
|
||
],
|
||
pendingReports: [
|
||
{ name: 'A风场2号机组检查报告', project: 'A风场2023年检查', turbine: 'A-002', submitter: '张工程师', submitTime: '2023-11-06 14:30' }
|
||
],
|
||
defectCount: 8,
|
||
notifications: [
|
||
{ title: '新任务分配', content: '您有新的检查任务: D风场初步检查', time: '2023-11-08 08:00', action: '查看' },
|
||
{ title: '报告审核通过', content: '您提交的A风场检查报告已通过审核', time: '2023-11-07 17:30' },
|
||
{ title: '系统更新', content: '系统将于今晚23:00进行维护更新,预计耗时2小时', time: '2023-11-07 15:20' }
|
||
],
|
||
|
||
// 项目列表数据
|
||
projectSearch: '',
|
||
projects: [
|
||
{ id: 1, name: 'A风场2023年检查', turbineCount: 15, startDate: '2023-10-01', endDate: '2023-12-31', status: '进行中', progress: 65 },
|
||
{ id: 2, name: 'B风场维修项目', turbineCount: 8, startDate: '2023-09-15', endDate: '2023-11-30', status: '进行中', progress: 45 },
|
||
{ id: 3, name: 'C风场年度检查', turbineCount: 20, startDate: '2023-08-01', endDate: '2023-10-31', status: '已完成', progress: 100 },
|
||
{ id: 4, name: 'D风场初步检查', turbineCount: 12, startDate: '2023-11-10', endDate: '2023-12-15', status: '未开始', progress: 0 }
|
||
],
|
||
pendingProjects: [
|
||
{ id: 4, name: 'D风场初步检查', turbineCount: 12, startDate: '2023-11-10', endDate: '2023-12-15', status: '未开始', progress: 0 }
|
||
],
|
||
|
||
// 我的施工数据
|
||
currentProject: null,
|
||
turbineSearch: '',
|
||
turbines: [
|
||
{ id: 1, code: 'A-001', type: '2.5MW', location: 'A风场东区', status: '施工中', progress: 80 },
|
||
{ id: 2, code: 'A-002', type: '2.5MW', location: 'A风场东区', status: '待施工', progress: 0 },
|
||
{ id: 3, code: 'A-003', type: '2.5MW', location: 'A风场西区', status: '已完成', progress: 100 }
|
||
],
|
||
constructionReports: [
|
||
{ turbine: 'A-001', date: '2023-11-05', inspector: '张工程师', defectCount: 2, status: '已提交' },
|
||
{ turbine: 'A-003', date: '2023-11-07', inspector: '李技术员', defectCount: 0, status: '草稿' }
|
||
],
|
||
recordDateRange: '',
|
||
constructionRecords: [
|
||
{ date: '2023-11-05', turbine: 'A-001', type: '检查', content: '完成1号机组检查,发现2处缺陷', operator: '张工程师' },
|
||
{ date: '2023-11-06', turbine: 'A-001', type: '维修', content: '修复1号机组前缘腐蚀', operator: '王维修' },
|
||
{ date: '2023-11-07', turbine: 'A-003', type: '检查', content: '完成3号机组检查,未发现缺陷', operator: '李技术员' }
|
||
],
|
||
pickerOptions: {
|
||
shortcuts: [{
|
||
text: '最近一周',
|
||
onClick(picker) {
|
||
const end = new Date();
|
||
const start = new Date();
|
||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||
picker.$emit('pick', [start, end]);
|
||
}
|
||
}, {
|
||
text: '最近一个月',
|
||
onClick(picker) {
|
||
const end = new Date();
|
||
const start = new Date();
|
||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||
picker.$emit('pick', [start, end]);
|
||
}
|
||
}, {
|
||
text: '最近三个月',
|
||
onClick(picker) {
|
||
const end = new Date();
|
||
const start = new Date();
|
||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||
picker.$emit('pick', [start, end]);
|
||
}
|
||
}]
|
||
},
|
||
|
||
// 数据入库
|
||
currentBlade: {
|
||
position: '1号机组',
|
||
type: 'A型'
|
||
},
|
||
fileList: [],
|
||
uploadedData: [
|
||
{ name: 'IMG_20231105_1430.jpg', type: 'image', size: '3.2MB', time: '2023-11-05 14:32', status: '成功' },
|
||
{ name: 'VID_20231106_0915.mp4', type: 'video', size: '45.6MB', time: '2023-11-06 09:18', status: '成功' },
|
||
{ name: 'IMG_20231107_1645.jpg', type: 'image', size: '2.8MB', time: '2023-11-07 16:48', status: '成功' }
|
||
],
|
||
|
||
// 数据预处理
|
||
preprocessStep: 0,
|
||
selectedProject: null,
|
||
preprocessData: [
|
||
{ name: 'IMG_20231105_1430.jpg', type: 'image', size: '3.2MB', time: '2023-11-05 14:32' },
|
||
{ name: 'VID_20231106_0915.mp4', type: 'video', size: '45.6MB', time: '2023-11-06 09:18' }
|
||
],
|
||
preprocessForm: {
|
||
imageOptions: ['去噪', '增强'],
|
||
videoOptions: ['关键帧提取'],
|
||
outputFormat: 'jpg',
|
||
outputPath: '/output/processed'
|
||
},
|
||
preprocessProgress: 0,
|
||
preprocessStatus: '准备预处理...',
|
||
preprocessRunning: false,
|
||
|
||
// 缺陷检测算法
|
||
detectionRunning: false,
|
||
detectionProgress: 0,
|
||
detectionStatus: '正在初始化...',
|
||
defectDetectionResults: [
|
||
{
|
||
type: '前缘腐蚀',
|
||
position: '1号机组-2号叶片-叶尖',
|
||
size: '15x8mm',
|
||
severity: '高',
|
||
images: [
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Defect+1', full: 'https://via.placeholder.com/800x600?text=Defect+1' },
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Defect+2', full: 'https://via.placeholder.com/800x600?text=Defect+2' }
|
||
]
|
||
},
|
||
{
|
||
type: '后缘开裂',
|
||
position: '2号机组-3号叶片-中部',
|
||
size: '32x5mm',
|
||
severity: '中',
|
||
images: [
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Defect+3', full: 'https://via.placeholder.com/800x600?text=Defect+3' }
|
||
]
|
||
}
|
||
],
|
||
|
||
// 树状可视化管理
|
||
treeSearch: '',
|
||
treeData: [
|
||
{
|
||
id: 1,
|
||
label: 'A风场',
|
||
type: 'farm',
|
||
children: [
|
||
{
|
||
id: 101,
|
||
label: '1号机组',
|
||
type: 'turbine',
|
||
status: '正常',
|
||
lastInspection: '2023-11-05',
|
||
defects: 2,
|
||
children: [
|
||
{ id: 1011, label: '1号叶片', type: 'blade', status: '正常', images: [
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Blade+1', full: 'https://via.placeholder.com/800x600?text=Blade+1' }
|
||
]},
|
||
{ id: 1012, label: '2号叶片', type: 'blade', status: '缺陷', images: [
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Blade+2', full: 'https://via.placeholder.com/800x600?text=Blade+2' },
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Blade+3', full: 'https://via.placeholder.com/800x600?text=Blade+3' }
|
||
]},
|
||
{ id: 1013, label: '3号叶片', type: 'blade', status: '正常', images: [
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Blade+4', full: 'https://via.placeholder.com/800x600?text=Blade+4' }
|
||
]}
|
||
]
|
||
},
|
||
{
|
||
id: 102,
|
||
label: '2号机组',
|
||
type: 'turbine',
|
||
status: '正常',
|
||
lastInspection: '2023-11-06',
|
||
defects: 1,
|
||
children: [
|
||
{ id: 1021, label: '1号叶片', type: 'blade', status: '正常' },
|
||
{ id: 1022, label: '2号叶片', type: 'blade', status: '正常' },
|
||
{ id: 1023, label: '3号叶片', type: 'blade', status: '缺陷' }
|
||
]
|
||
}
|
||
]
|
||
}
|
||
],
|
||
treeProps: {
|
||
label: 'label',
|
||
children: 'children'
|
||
},
|
||
selectedTreeNode: null,
|
||
|
||
// 标准信息库
|
||
defectStandards: [
|
||
{ code: 'DEF001', name: '前缘腐蚀', category: '腐蚀类', severity: '高', description: '叶片前缘因风沙侵蚀导致的材料损失' },
|
||
{ code: 'DEF002', name: '后缘开裂', category: '裂纹类', severity: '中', description: '叶片后缘出现的结构性裂纹' },
|
||
{ code: 'DEF003', name: '表面划痕', category: '损伤类', severity: '低', description: '叶片表面因外力导致的划痕' }
|
||
],
|
||
inspectionStandards: [
|
||
{ code: 'INS001', name: '前缘检查标准', category: '前缘', method: '目视+无人机', description: '前缘腐蚀、损伤的检查标准' },
|
||
{ code: 'INS002', name: '后缘检查标准', category: '后缘', method: '目视+敲击', description: '后缘开裂、分层的检查标准' }
|
||
],
|
||
repairStandards: [
|
||
{ code: 'REP001', name: '前缘腐蚀修复', defectType: '前缘腐蚀', method: '打磨+补漆', description: '前缘腐蚀的标准修复流程', material: '环氧树脂,玻璃纤维布' },
|
||
{ code: 'REP002', name: '后缘开裂修复', defectType: '后缘开裂', method: '注胶+加压', description: '后缘开裂的标准修复流程', material: '结构胶,夹具' }
|
||
],
|
||
|
||
// 报告生成
|
||
reportList: [
|
||
{ name: 'A风场1号机组检查报告', project: 'A风场2023年检查', turbine: 'A-001', date: '2023-11-05', status: '已发布' },
|
||
{ name: 'A风场2号机组检查报告', project: 'A风场2023年检查', turbine: 'A-002', date: '2023-11-06', status: '待审核' },
|
||
{ name: 'B风场1号机组检查报告', project: 'B风场维修项目', turbine: 'B-001', date: '2023-10-28', status: '已发布' }
|
||
],
|
||
currentReport: null,
|
||
reportPreviewDialogVisible: false,
|
||
|
||
// 全生命周期管理
|
||
turbineSearch: '',
|
||
bladeSearch: '',
|
||
turbines: [
|
||
{ code: 'A-001', name: 'A风场1号机组', type: '2.5MW', location: 'A风场东区', installDate: '2020-05-15', status: '运行中', totalPower: '12500000' },
|
||
{ code: 'A-002', name: 'A风场2号机组', type: '2.5MW', location: 'A风场东区', installDate: '2020-05-20', status: '运行中', totalPower: '11800000' },
|
||
{ code: 'B-001', name: 'B风场1号机组', type: '3.0MW', location: 'B风场西区', installDate: '2019-08-10', status: '维修中', totalPower: '9800000' }
|
||
],
|
||
blades: [
|
||
{ code: 'A-001-1', turbine: 'A-001', position: '1号', type: 'B58', manufacturer: '风电科技', status: '正常' },
|
||
{ code: 'A-001-2', turbine: 'A-001', position: '2号', type: 'B58', manufacturer: '风电科技', status: '缺陷' },
|
||
{ code: 'A-001-3', turbine: 'A-001', position: '3号', type: 'B58', manufacturer: '风电科技', status: '正常' },
|
||
{ code: 'B-001-1', turbine: 'B-001', position: '1号', type: 'C62', manufacturer: '绿色能源', status: '维修中' }
|
||
],
|
||
currentTurbine: null,
|
||
turbineLifecycleDialogVisible: false,
|
||
turbineLifecycleEvents: [
|
||
{ time: '2023-11-05', type: '检查', title: '年度例行检查', description: '发现2号叶片前缘腐蚀,需后续维修', images: [
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Inspection+1', full: 'https://via.placeholder.com/800x600?text=Inspection+1' }
|
||
]},
|
||
{ time: '2023-08-12', type: '维修', title: '齿轮箱更换', description: '更换故障齿轮箱,耗时3天', images: [] },
|
||
{ time: '2022-11-20', type: '检查', title: '年度例行检查', description: '机组运行状态良好,无重大缺陷', images: [] },
|
||
{ time: '2020-05-15', type: '投运', title: '机组投运', description: '新机组安装完成并投入运行', images: [] }
|
||
],
|
||
|
||
// 可靠性评估
|
||
reliabilityData: null,
|
||
|
||
// 数据质量评估
|
||
qualityData: null,
|
||
|
||
// 质量入库
|
||
storageCheckResults: [
|
||
{ item: '检查数据完整性', status: '通过', message: '所有必填字段均已填写' },
|
||
{ item: '图片质量检查', status: '通过', message: '所有图片清晰可辨' },
|
||
{ item: '视频质量检查', status: '通过', message: '视频完整且清晰' },
|
||
{ item: '报告一致性检查', status: '通过', message: '报告与数据一致' }
|
||
],
|
||
storageForm: {
|
||
qualityScore: 4,
|
||
notes: '',
|
||
storageLocation: 'main'
|
||
},
|
||
|
||
// 净空距离监测
|
||
monitorDate: '',
|
||
clearanceData: [
|
||
{ time: '2023-11-05 08:00', turbine: 'A-001', distance: '12.5', status: '正常' },
|
||
{ time: '2023-11-05 12:00', turbine: 'A-001', distance: '11.8', status: '正常' },
|
||
{ time: '2023-11-05 16:00', turbine: 'A-001', distance: '9.2', status: '警告' }
|
||
],
|
||
|
||
// 形变监测
|
||
deformationDateRange: '',
|
||
deformationData: [
|
||
{ date: '2023-11-05', turbine: 'A-001', deformationX: '2.1', deformationY: '1.5', deformationZ: '0.8', status: '正常' },
|
||
{ date: '2023-11-06', turbine: 'A-001', deformationX: '2.3', deformationY: '1.6', deformationZ: '0.9', status: '正常' },
|
||
{ date: '2023-11-07', turbine: 'A-001', deformationX: '3.5', deformationY: '2.8', deformationZ: '1.2', status: '警告' }
|
||
],
|
||
|
||
// 图像检测
|
||
imageDate: '',
|
||
imageData: [
|
||
{ turbine: 'A-001', time: '2023-11-05 08:00', image: 'https://via.placeholder.com/400x300?text=Turbine+A-001', status: '正常', defects: [] },
|
||
{ turbine: 'A-001', time: '2023-11-05 12:00', image: 'https://via.placeholder.com/400x300?text=Turbine+A-001', status: '缺陷', defects: [
|
||
{ type: '前缘腐蚀', severity: '中' }
|
||
]},
|
||
{ turbine: 'A-002', time: '2023-11-06 09:00', image: 'https://via.placeholder.com/400x300?text=Turbine+A-002', status: '正常', defects: [] }
|
||
],
|
||
|
||
// 航线规划
|
||
routeSearch: '',
|
||
routes: [
|
||
{ name: 'A风场东区航线', creator: '张工程师', createTime: '2023-10-15', droneType: 'DJI M300', length: '5.2', duration: '45', preview: 'https://via.placeholder.com/600x400?text=Route+Preview' },
|
||
{ name: 'B风场西区航线', creator: '李技术员', createTime: '2023-09-20', droneType: 'DJI M300', length: '6.8', duration: '60', preview: 'https://via.placeholder.com/600x400?text=Route+Preview' }
|
||
],
|
||
currentRoute: null,
|
||
|
||
// 三维模型
|
||
models: [
|
||
{ name: 'A型叶片模型', type: '叶片', thumbnail: 'https://via.placeholder.com/300x200?text=Blade+Model' },
|
||
{ name: '2.5MW机组模型', type: '机组', thumbnail: 'https://via.placeholder.com/300x200?text=Turbine+Model' },
|
||
{ name: 'B风场地形模型', type: '地形', thumbnail: 'https://via.placeholder.com/300x200?text=Terrain+Model' }
|
||
],
|
||
|
||
// 报告模板库
|
||
templateSearch: '',
|
||
templates: [
|
||
{ name: '标准检查报告模板', type: '检查报告', creator: '系统管理员', createTime: '2023-01-10', description: '标准的风电叶片检查报告模板' },
|
||
{ name: '维修报告模板', type: '维修报告', creator: '王维修', createTime: '2023-03-15', description: '风电叶片维修记录报告模板' },
|
||
{ name: '月度报告模板', type: '月度报告', creator: '李经理', createTime: '2023-05-20', description: '风电场月度运行报告模板' }
|
||
],
|
||
|
||
// 系统设置
|
||
settingsForm: {
|
||
themeColor: '#409EFF',
|
||
notificationMethods: ['站内消息', '电子邮件']
|
||
},
|
||
systemForm: {
|
||
autoBackup: true,
|
||
backupFrequency: 'weekly',
|
||
backupPath: '/backups'
|
||
},
|
||
dependencies: [
|
||
{ name: 'Vue.js', version: '2.6.14', license: 'MIT' },
|
||
{ name: 'Element UI', version: '2.15.9', license: 'MIT' },
|
||
{ name: 'ECharts', version: '5.3.2', license: 'Apache-2.0' }
|
||
],
|
||
|
||
// 图片预览
|
||
previewImageUrl: '',
|
||
imagePreviewDialogVisible: false
|
||
}
|
||
},
|
||
computed: {
|
||
filteredProjects() {
|
||
if (!this.projectSearch) return this.projects;
|
||
return this.projects.filter(project =>
|
||
project.name.toLowerCase().includes(this.projectSearch.toLowerCase())
|
||
);
|
||
},
|
||
filteredTurbines() {
|
||
if (!this.turbineSearch) return this.turbines;
|
||
return this.turbines.filter(turbine =>
|
||
turbine.code.toLowerCase().includes(this.turbineSearch.toLowerCase())
|
||
);
|
||
},
|
||
filteredBlades() {
|
||
if (!this.bladeSearch) return this.blades;
|
||
return this.blades.filter(blade =>
|
||
blade.code.toLowerCase().includes(this.bladeSearch.toLowerCase()) ||
|
||
blade.turbine.toLowerCase().includes(this.bladeSearch.toLowerCase())
|
||
);
|
||
},
|
||
filteredRoutes() {
|
||
if (!this.routeSearch) return this.routes;
|
||
return this.routes.filter(route =>
|
||
route.name.toLowerCase().includes(this.routeSearch.toLowerCase())
|
||
);
|
||
},
|
||
filteredTemplates() {
|
||
if (!this.templateSearch) return this.templates;
|
||
return this.templates.filter(template =>
|
||
template.name.toLowerCase().includes(this.templateSearch.toLowerCase()) ||
|
||
template.type.toLowerCase().includes(this.templateSearch.toLowerCase())
|
||
);
|
||
},
|
||
canProceedToNextStep() {
|
||
return this.storageCheckResults.every(item => item.status === '通过');
|
||
},
|
||
newProjectCount() {
|
||
return this.pendingProjects.length;
|
||
}
|
||
},
|
||
mounted() {
|
||
this.initCharts();
|
||
},
|
||
watch: {
|
||
treeSearch(val) {
|
||
this.$refs.tree.filter(val);
|
||
}
|
||
},
|
||
methods: {
|
||
toggleSidebar() {
|
||
this.isCollapse = !this.isCollapse;
|
||
},
|
||
switchModule(module) {
|
||
this.activeModule = module;
|
||
// 初始化模块数据
|
||
if (module === 'dashboard') {
|
||
this.$nextTick(() => {
|
||
this.initCharts();
|
||
});
|
||
}
|
||
},
|
||
logout() {
|
||
this.$confirm('确定要退出登录吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.$message({
|
||
type: 'success',
|
||
message: '已退出登录'
|
||
});
|
||
// 实际应用中这里应该跳转到登录页面
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消退出'
|
||
});
|
||
});
|
||
},
|
||
|
||
// 工作台方法
|
||
initCharts() {
|
||
// 项目进度图表
|
||
if (this.$refs.projectChart) {
|
||
const projectChart = echarts.init(this.$refs.projectChart);
|
||
projectChart.setOption({
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
axisPointer: {
|
||
type: 'shadow'
|
||
}
|
||
},
|
||
legend: {
|
||
data: ['已完成', '进行中', '未开始']
|
||
},
|
||
grid: {
|
||
left: '3%',
|
||
right: '4%',
|
||
bottom: '3%',
|
||
containLabel: true
|
||
},
|
||
xAxis: {
|
||
type: 'value'
|
||
},
|
||
yAxis: {
|
||
type: 'category',
|
||
data: ['A风场', 'B风场', 'C风场', 'D风场']
|
||
},
|
||
series: [
|
||
{
|
||
name: '已完成',
|
||
type: 'bar',
|
||
stack: 'total',
|
||
label: {
|
||
show: true
|
||
},
|
||
emphasis: {
|
||
focus: 'series'
|
||
},
|
||
data: [320, 120, 200, 0],
|
||
itemStyle: {
|
||
color: '#67C23A'
|
||
}
|
||
},
|
||
{
|
||
name: '进行中',
|
||
type: 'bar',
|
||
stack: 'total',
|
||
label: {
|
||
show: true
|
||
},
|
||
emphasis: {
|
||
focus: 'series'
|
||
},
|
||
data: [80, 180, 0, 0],
|
||
itemStyle: {
|
||
color: '#409EFF'
|
||
}
|
||
},
|
||
{
|
||
name: '未开始',
|
||
type: 'bar',
|
||
stack: 'total',
|
||
label: {
|
||
show: true
|
||
},
|
||
emphasis: {
|
||
focus: 'series'
|
||
},
|
||
data: [0, 0, 0, 400],
|
||
itemStyle: {
|
||
color: '#909399'
|
||
}
|
||
}
|
||
]
|
||
});
|
||
}
|
||
|
||
// 净空距离图表
|
||
if (this.$refs.clearanceChart) {
|
||
const clearanceChart = echarts.init(this.$refs.clearanceChart);
|
||
clearanceChart.setOption({
|
||
title: {
|
||
text: '净空距离变化趋势',
|
||
left: 'center'
|
||
},
|
||
tooltip: {
|
||
trigger: 'axis'
|
||
},
|
||
xAxis: {
|
||
type: 'category',
|
||
data: this.clearanceData.map(item => item.time.split(' ')[1])
|
||
},
|
||
yAxis: {
|
||
type: 'value',
|
||
name: '距离(m)'
|
||
},
|
||
series: [{
|
||
data: this.clearanceData.map(item => item.distance),
|
||
type: 'line',
|
||
smooth: true,
|
||
markLine: {
|
||
silent: true,
|
||
data: [{
|
||
yAxis: 10,
|
||
name: '安全阈值',
|
||
lineStyle: {
|
||
color: '#F56C6C'
|
||
},
|
||
label: {
|
||
formatter: '安全阈值: 10m',
|
||
position: 'start'
|
||
}
|
||
}]
|
||
}
|
||
}]
|
||
});
|
||
}
|
||
|
||
// 形变监测图表
|
||
if (this.$refs.deformationChart) {
|
||
const deformationChart = echarts.init(this.$refs.deformationChart);
|
||
deformationChart.setOption({
|
||
title: {
|
||
text: '形变监测趋势',
|
||
left: 'center'
|
||
},
|
||
tooltip: {
|
||
trigger: 'axis'
|
||
},
|
||
legend: {
|
||
data: ['X方向', 'Y方向', 'Z方向'],
|
||
bottom: 10
|
||
},
|
||
xAxis: {
|
||
type: 'category',
|
||
data: this.deformationData.map(item => item.date)
|
||
},
|
||
yAxis: {
|
||
type: 'value',
|
||
name: '形变量(mm)'
|
||
},
|
||
series: [
|
||
{
|
||
name: 'X方向',
|
||
data: this.deformationData.map(item => item.deformationX),
|
||
type: 'line',
|
||
smooth: true
|
||
},
|
||
{
|
||
name: 'Y方向',
|
||
data: this.deformationData.map(item => item.deformationY),
|
||
type: 'line',
|
||
smooth: true
|
||
},
|
||
{
|
||
name: 'Z方向',
|
||
data: this.deformationData.map(item => item.deformationZ),
|
||
type: 'line',
|
||
smooth: true
|
||
}
|
||
]
|
||
});
|
||
}
|
||
},
|
||
viewTaskDetail(task) {
|
||
this.$message(`查看任务: ${task.name}`);
|
||
},
|
||
handleNotification(notification) {
|
||
this.$message(`处理通知: ${notification.title}`);
|
||
},
|
||
|
||
// 项目列表方法
|
||
showProjectDialog() {
|
||
this.$message('显示新建项目对话框');
|
||
},
|
||
refreshProjects() {
|
||
this.$message('刷新项目列表');
|
||
},
|
||
viewProjectDetail(project) {
|
||
this.$message(`查看项目: ${project.name}`);
|
||
},
|
||
enterProject(project) {
|
||
this.currentProject = project;
|
||
this.activeModule = 'project-construction';
|
||
this.$message(`进入项目: ${project.name}`);
|
||
},
|
||
|
||
// 我的施工方法
|
||
startConstruction(turbine) {
|
||
this.$confirm(`确定要开始 ${turbine.code} 的施工吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
turbine.status = '施工中';
|
||
this.$message({
|
||
type: 'success',
|
||
message: '已开始施工'
|
||
});
|
||
|
||
// 记录施工台账
|
||
this.constructionRecords.unshift({
|
||
date: new Date().toLocaleDateString(),
|
||
turbine: turbine.code,
|
||
type: '施工',
|
||
content: `开始${turbine.code}的施工检查`,
|
||
operator: this.userInfo.name
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消操作'
|
||
});
|
||
});
|
||
},
|
||
completeConstruction(turbine) {
|
||
this.$confirm(`确定要完成 ${turbine.code} 的施工吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
turbine.status = '已完成';
|
||
turbine.progress = 100;
|
||
this.$message({
|
||
type: 'success',
|
||
message: '施工已完成'
|
||
});
|
||
|
||
// 记录施工台账
|
||
this.constructionRecords.unshift({
|
||
date: new Date().toLocaleDateString(),
|
||
turbine: turbine.code,
|
||
type: '施工',
|
||
content: `完成${turbine.code}的施工检查`,
|
||
operator: this.userInfo.name
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消操作'
|
||
});
|
||
});
|
||
},
|
||
viewTurbineDetail(turbine) {
|
||
this.$message(`查看机组详情: ${turbine.code}`);
|
||
},
|
||
createConstructionReport() {
|
||
this.$message('创建施工报告');
|
||
},
|
||
refreshReports() {
|
||
this.$message('刷新报告列表');
|
||
},
|
||
viewReport(report) {
|
||
this.currentReport = {
|
||
name: report.turbine + '施工报告',
|
||
project: this.currentProject.name,
|
||
turbine: report.turbine,
|
||
date: report.date,
|
||
inspector: report.inspector,
|
||
summary: `本次施工检查${report.defectCount > 0 ? '发现' + report.defectCount + '处缺陷' : '未发现缺陷'}`,
|
||
defects: report.defectCount > 0 ? [
|
||
{
|
||
code: 'DEF001',
|
||
name: '前缘腐蚀',
|
||
severity: '高',
|
||
description: '叶片前缘有明显腐蚀痕迹,面积约15x8mm',
|
||
images: [
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Defect+1', full: 'https://via.placeholder.com/800x600?text=Defect+1' }
|
||
]
|
||
}
|
||
] : [],
|
||
conclusion: report.defectCount > 0 ? '机组存在缺陷,需要维修' : '机组状况良好',
|
||
recommendations: report.defectCount > 0 ? '建议在下次停机时进行维修处理' : '无需特别处理'
|
||
};
|
||
this.reportPreviewDialogVisible = true;
|
||
},
|
||
editReport(report) {
|
||
this.$message(`编辑报告: ${report.turbine}`);
|
||
},
|
||
deleteReport(report) {
|
||
this.$confirm(`确定要删除 ${report.turbine} 的报告吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.constructionReports = this.constructionReports.filter(item => item.turbine !== report.turbine);
|
||
this.$message({
|
||
type: 'success',
|
||
message: '删除成功!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消删除'
|
||
});
|
||
});
|
||
},
|
||
searchRecords() {
|
||
this.$message('查询施工台账');
|
||
},
|
||
exportRecords() {
|
||
this.$message('导出台账数据');
|
||
},
|
||
viewRecordDetail(record) {
|
||
this.$message(`查看台账详情: ${record.turbine} - ${record.type}`);
|
||
},
|
||
|
||
// 数据入库方法
|
||
handleFileChange(file, fileList) {
|
||
this.fileList = fileList;
|
||
},
|
||
beforeUpload(file) {
|
||
const isLt10M = file.size / 1024 / 1024 < 10;
|
||
if (!isLt10M) {
|
||
this.$message.error('上传文件大小不能超过 10MB!');
|
||
}
|
||
return isLt10M;
|
||
},
|
||
handleRemove(file, fileList) {
|
||
this.fileList = fileList;
|
||
},
|
||
submitUpload() {
|
||
if (this.fileList.length === 0) {
|
||
this.$message.warning('请先选择要上传的文件');
|
||
return;
|
||
}
|
||
|
||
this.$message.success('开始上传文件');
|
||
// 模拟上传进度
|
||
let progress = 0;
|
||
const interval = setInterval(() => {
|
||
progress += Math.random() * 10;
|
||
if (progress >= 100) {
|
||
clearInterval(interval);
|
||
this.$message.success('文件上传成功');
|
||
// 添加到已上传数据列表
|
||
this.fileList.forEach(file => {
|
||
this.uploadedData.unshift({
|
||
name: file.name,
|
||
type: this.activeDataType,
|
||
size: (file.size / 1024 / 1024).toFixed(1) + 'MB',
|
||
time: new Date().toLocaleString(),
|
||
status: '成功'
|
||
});
|
||
});
|
||
this.fileList = [];
|
||
}
|
||
}, 300);
|
||
},
|
||
clearFiles() {
|
||
this.fileList = [];
|
||
},
|
||
showBatchImportDialog() {
|
||
this.$message('显示批量导入对话框');
|
||
},
|
||
previewFile(file) {
|
||
this.previewImageUrl = 'https://via.placeholder.com/800x600?text=' + file.name.split('.')[0];
|
||
this.imagePreviewDialogVisible = true;
|
||
},
|
||
deleteFile(file) {
|
||
this.$confirm(`确定要删除文件 ${file.name} 吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.uploadedData = this.uploadedData.filter(item => item.name !== file.name);
|
||
this.$message({
|
||
type: 'success',
|
||
message: '删除成功!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消删除'
|
||
});
|
||
});
|
||
},
|
||
|
||
// 数据预处理方法
|
||
startPreprocess() {
|
||
this.preprocessRunning = true;
|
||
this.preprocessStatus = '正在预处理数据...';
|
||
|
||
const interval = setInterval(() => {
|
||
this.preprocessProgress += Math.random() * 10;
|
||
if (this.preprocessProgress >= 100) {
|
||
clearInterval(interval);
|
||
this.preprocessStatus = '预处理完成';
|
||
this.preprocessStep = 3;
|
||
this.preprocessRunning = false;
|
||
this.$message.success('数据预处理完成');
|
||
}
|
||
}, 500);
|
||
},
|
||
viewPreprocessResults() {
|
||
this.$message('查看预处理结果');
|
||
this.preprocessStep = 0;
|
||
},
|
||
|
||
// 缺陷检测算法方法
|
||
runDefectDetection() {
|
||
this.detectionRunning = true;
|
||
this.detectionProgress = 0;
|
||
this.detectionStatus = '正在初始化...';
|
||
|
||
const statusMessages = [
|
||
'加载图像数据...',
|
||
'预处理图像...',
|
||
'运行缺陷检测算法...',
|
||
'分析检测结果...',
|
||
'生成报告...'
|
||
];
|
||
|
||
const interval = setInterval(() => {
|
||
this.detectionProgress += Math.random() * 10;
|
||
if (this.detectionProgress >= 100) {
|
||
clearInterval(interval);
|
||
this.detectionStatus = '检测完成';
|
||
setTimeout(() => {
|
||
this.detectionRunning = false;
|
||
this.$message.success('缺陷检测完成');
|
||
}, 500);
|
||
} else {
|
||
const statusIndex = Math.min(
|
||
Math.floor(this.detectionProgress / 20),
|
||
statusMessages.length - 1
|
||
);
|
||
this.detectionStatus = statusMessages[statusIndex];
|
||
}
|
||
}, 500);
|
||
},
|
||
showDetectionSettings() {
|
||
this.$message('显示检测设置对话框');
|
||
},
|
||
exportDetectionResults() {
|
||
this.$message('导出检测结果');
|
||
},
|
||
previewDefectImages(defect) {
|
||
this.previewImageUrl = defect.images[0].full;
|
||
this.imagePreviewDialogVisible = true;
|
||
},
|
||
markAsFalseAlarm(defect) {
|
||
this.$confirm(`确定要将 ${defect.type} 标记为误报吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.defectDetectionResults = this.defectDetectionResults.filter(item => item !== defect);
|
||
this.$message({
|
||
type: 'success',
|
||
message: '已标记为误报!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消操作'
|
||
});
|
||
});
|
||
},
|
||
|
||
// 树状可视化管理方法
|
||
filterTreeNode(value, data) {
|
||
if (!value) return true;
|
||
return data.label.indexOf(value) !== -1;
|
||
},
|
||
handleTreeNodeClick(data) {
|
||
this.selectedTreeNode = data;
|
||
},
|
||
previewImage(url) {
|
||
this.previewImageUrl = typeof url === 'string' ? url : url.full;
|
||
this.imagePreviewDialogVisible = true;
|
||
},
|
||
|
||
// 标准信息库方法
|
||
showAddStandardDialog(type) {
|
||
this.$message(`显示新增${type === 'defect' ? '缺陷' : type === 'inspection' ? '检查' : '维修'}标准对话框`);
|
||
},
|
||
exportStandards(type) {
|
||
this.$message(`导出${type === 'defect' ? '缺陷' : type === 'inspection' ? '检查' : '维修'}标准`);
|
||
},
|
||
editStandard(standard) {
|
||
this.$message(`编辑标准: ${standard.name}`);
|
||
},
|
||
deleteStandard(standard) {
|
||
this.$confirm(`确定要删除标准 ${standard.name} 吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
if (this.standardTab === 'defect') {
|
||
this.defectStandards = this.defectStandards.filter(item => item.code !== standard.code);
|
||
} else if (this.standardTab === 'inspection') {
|
||
this.inspectionStandards = this.inspectionStandards.filter(item => item.code !== standard.code);
|
||
} else {
|
||
this.repairStandards = this.repairStandards.filter(item => item.code !== standard.code);
|
||
}
|
||
this.$message({
|
||
type: 'success',
|
||
message: '删除成功!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消删除'
|
||
});
|
||
});
|
||
},
|
||
|
||
// 报告生成方法
|
||
generateNewReport() {
|
||
this.$message('生成新报告');
|
||
},
|
||
refreshReportsList() {
|
||
this.$message('刷新报告列表');
|
||
},
|
||
exportAllReports() {
|
||
this.$message('导出全部报告');
|
||
},
|
||
viewReport(report) {
|
||
this.currentReport = {
|
||
name: report.name,
|
||
project: report.project,
|
||
turbine: report.turbine,
|
||
date: report.date,
|
||
inspector: '张工程师',
|
||
summary: '本次检查共发现3处缺陷,其中1处为严重缺陷,需要尽快处理。',
|
||
defects: [
|
||
{
|
||
code: 'DEF001',
|
||
name: '前缘腐蚀',
|
||
severity: '高',
|
||
description: '叶片前缘有明显腐蚀痕迹,面积约15x8mm',
|
||
images: [
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Defect+1', full: 'https://via.placeholder.com/800x600?text=Defect+1' }
|
||
]
|
||
},
|
||
{
|
||
code: 'DEF002',
|
||
name: '后缘开裂',
|
||
severity: '中',
|
||
description: '叶片后缘有细小裂纹,长度约32mm',
|
||
images: [
|
||
{ thumbnail: 'https://via.placeholder.com/100x100?text=Defect+2', full: 'https://via.placeholder.com/800x600?text=Defect+2' }
|
||
]
|
||
}
|
||
],
|
||
conclusion: '机组整体状况良好,但存在两处需要关注的缺陷。',
|
||
recommendations: '建议在下次停机时对1号叶片前缘腐蚀进行修复处理,并持续观察2号叶片后缘开裂情况。'
|
||
};
|
||
this.reportPreviewDialogVisible = true;
|
||
},
|
||
editReport(report) {
|
||
this.$message(`编辑报告: ${report.name}`);
|
||
},
|
||
publishReport(report) {
|
||
this.$confirm(`确定要发布报告 ${report.name} 吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
report.status = '已发布';
|
||
this.$message({
|
||
type: 'success',
|
||
message: '报告已发布!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消发布'
|
||
});
|
||
});
|
||
},
|
||
deleteReport(report) {
|
||
this.$confirm(`确定要删除报告 ${report.name} 吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.reportList = this.reportList.filter(item => item.name !== report.name);
|
||
this.$message({
|
||
type: 'success',
|
||
message: '删除成功!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消删除'
|
||
});
|
||
});
|
||
},
|
||
downloadReport(report) {
|
||
this.$message(`下载报告: ${report.name}`);
|
||
this.reportPreviewDialogVisible = false;
|
||
},
|
||
|
||
// 全生命周期管理方法
|
||
viewTurbineLifecycle(turbine) {
|
||
this.currentTurbine = turbine;
|
||
this.turbineLifecycleDialogVisible = true;
|
||
},
|
||
viewBladeLifecycle(blade) {
|
||
this.$message(`查看叶片生命周期: ${blade.code}`);
|
||
},
|
||
|
||
// 可靠性评估方法
|
||
generateReliabilityReport() {
|
||
if (!this.selectedProject) {
|
||
this.$message.warning('请先选择项目');
|
||
return;
|
||
}
|
||
|
||
this.reliabilityData = {
|
||
project: this.projects.find(p => p.id === this.selectedProject).name,
|
||
score: 82,
|
||
details: [
|
||
{ turbine: 'A-001', score: 85, defectCount: 2, severity: '中', recommendation: '建议在下次停机时修复前缘腐蚀' },
|
||
{ turbine: 'A-002', score: 90, defectCount: 1, severity: '低', recommendation: '持续观察后缘开裂情况' },
|
||
{ turbine: 'A-003', score: 95, defectCount: 0, severity: '无', recommendation: '机组状况良好,无需特别处理' }
|
||
]
|
||
};
|
||
|
||
// 初始化图表
|
||
this.$nextTick(() => {
|
||
const chart = echarts.init(this.$refs.reliabilityChart);
|
||
chart.setOption({
|
||
title: {
|
||
text: '机组可靠性评分',
|
||
left: 'center'
|
||
},
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
axisPointer: {
|
||
type: 'shadow'
|
||
}
|
||
},
|
||
grid: {
|
||
left: '3%',
|
||
right: '4%',
|
||
bottom: '3%',
|
||
containLabel: true
|
||
},
|
||
xAxis: {
|
||
type: 'value',
|
||
max: 100,
|
||
axisLabel: {
|
||
formatter: '{value} 分'
|
||
}
|
||
},
|
||
yAxis: {
|
||
type: 'category',
|
||
data: this.reliabilityData.details.map(item => item.turbine)
|
||
},
|
||
series: [
|
||
{
|
||
name: '可靠性评分',
|
||
type: 'bar',
|
||
data: this.reliabilityData.details.map(item => ({
|
||
value: item.score,
|
||
itemStyle: {
|
||
color: item.score >= 90 ? '#67C23A' : item.score >= 70 ? '#409EFF' : '#F56C6C'
|
||
}
|
||
})),
|
||
label: {
|
||
show: true,
|
||
position: 'right',
|
||
formatter: '{c} 分'
|
||
}
|
||
}
|
||
]
|
||
});
|
||
});
|
||
},
|
||
exportReliabilityReport() {
|
||
this.$message('导出可靠性评估报告');
|
||
},
|
||
printReliabilityReport() {
|
||
this.$message('打印可靠性评估报告');
|
||
},
|
||
|
||
// 数据质量评估方法
|
||
generateQualityReport() {
|
||
if (!this.selectedProject) {
|
||
this.$message.warning('请先选择项目');
|
||
return;
|
||
}
|
||
|
||
this.qualityData = {
|
||
project: this.projects.find(p => p.id === this.selectedProject).name,
|
||
score: 88,
|
||
metrics: [
|
||
{ name: '数据完整性', score: 95, description: '所有必填字段均已填写' },
|
||
{ name: '数据准确性', score: 90, description: '数据与实际情况基本一致' },
|
||
{ name: '数据一致性', score: 85, description: '各数据源之间无明显矛盾' },
|
||
{ name: '数据及时性', score: 80, description: '数据采集和录入略有延迟' },
|
||
{ name: '数据可用性', score: 90, description: '数据可直接用于分析和决策' }
|
||
],
|
||
suggestions: `
|
||
<p><strong>改进建议:</strong></p>
|
||
<ul>
|
||
<li>加强数据采集的及时性,尽量在检查完成后24小时内完成数据录入</li>
|
||
<li>对检查人员进行数据一致性培训,减少不同人员记录方式的差异</li>
|
||
<li>建立数据质量检查机制,在数据入库前进行自动校验</li>
|
||
</ul>
|
||
`
|
||
};
|
||
|
||
// 初始化图表
|
||
this.$nextTick(() => {
|
||
const chart = echarts.init(this.$refs.qualityChart);
|
||
chart.setOption({
|
||
title: {
|
||
text: '数据质量评估雷达图',
|
||
left: 'center'
|
||
},
|
||
tooltip: {},
|
||
radar: {
|
||
indicator: this.qualityData.metrics.map(item => ({
|
||
name: item.name,
|
||
max: 100
|
||
})),
|
||
radius: '65%'
|
||
},
|
||
series: [{
|
||
type: 'radar',
|
||
data: [{
|
||
value: this.qualityData.metrics.map(item => item.score),
|
||
name: '数据质量评分',
|
||
areaStyle: {
|
||
color: 'rgba(64, 158, 255, 0.5)'
|
||
}
|
||
}]
|
||
}]
|
||
});
|
||
});
|
||
},
|
||
exportQualityReport() {
|
||
this.$message('导出数据质量评估报告');
|
||
},
|
||
printQualityReport() {
|
||
this.$message('打印数据质量评估报告');
|
||
},
|
||
|
||
// 质量入库方法
|
||
checkProjectData() {
|
||
if (!this.selectedProject) {
|
||
this.$message.warning('请先选择项目');
|
||
return;
|
||
}
|
||
|
||
this.storageStep = 1;
|
||
},
|
||
completeStorage() {
|
||
this.storageStep = 3;
|
||
this.$message.success('项目数据入库成功');
|
||
},
|
||
viewStoredData() {
|
||
this.$message('查看入库数据');
|
||
this.storageStep = 0;
|
||
},
|
||
|
||
// 净空距离监测方法
|
||
searchMonitorData() {
|
||
this.$message('查询净空距离数据');
|
||
},
|
||
exportMonitorData() {
|
||
this.$message('导出净空距离数据');
|
||
},
|
||
viewClearanceDetail(record) {
|
||
this.$message(`查看净空距离详情: ${record.turbine} - ${record.time}`);
|
||
},
|
||
|
||
// 形变监测方法
|
||
searchDeformationData() {
|
||
this.$message('查询形变监测数据');
|
||
},
|
||
exportDeformationData() {
|
||
this.$message('导出形变监测数据');
|
||
},
|
||
viewDeformationDetail(record) {
|
||
this.$message(`查看形变监测详情: ${record.turbine} - ${record.date}`);
|
||
},
|
||
|
||
// 图像检测方法
|
||
searchImageData() {
|
||
this.$message('查询图像检测数据');
|
||
},
|
||
exportImageData() {
|
||
this.$message('导出图像检测数据');
|
||
},
|
||
|
||
// 航线规划方法
|
||
createNewRoute() {
|
||
this.$message('创建新航线');
|
||
},
|
||
refreshRoutes() {
|
||
this.$message('刷新航线列表');
|
||
},
|
||
viewRoute(route) {
|
||
this.currentRoute = route;
|
||
},
|
||
exportRoutes() {
|
||
this.$message('导出航线数据');
|
||
},
|
||
|
||
// 三维模型方法
|
||
uploadModel() {
|
||
this.$message('上传三维模型');
|
||
},
|
||
refreshModels() {
|
||
this.$message('刷新模型列表');
|
||
},
|
||
viewModel(model) {
|
||
this.$message(`查看模型: ${model.name}`);
|
||
},
|
||
editModel(model) {
|
||
this.$message(`编辑模型: ${model.name}`);
|
||
},
|
||
deleteModel(model) {
|
||
this.$confirm(`确定要删除模型 ${model.name} 吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.models = this.models.filter(item => item.name !== model.name);
|
||
this.$message({
|
||
type: 'success',
|
||
message: '删除成功!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消删除'
|
||
});
|
||
});
|
||
},
|
||
exportModels() {
|
||
this.$message('导出三维模型');
|
||
},
|
||
|
||
// 报告模板库方法
|
||
createTemplate() {
|
||
this.$message('创建新模板');
|
||
},
|
||
viewTemplate(template) {
|
||
this.$message(`查看模板: ${template.name}`);
|
||
},
|
||
editTemplate(template) {
|
||
this.$message(`编辑模板: ${template.name}`);
|
||
},
|
||
deleteTemplate(template) {
|
||
this.$confirm(`确定要删除模板 ${template.name} 吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.templates = this.templates.filter(item => item.name !== template.name);
|
||
this.$message({
|
||
type: 'success',
|
||
message: '删除成功!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消删除'
|
||
});
|
||
});
|
||
},
|
||
|
||
// 系统设置方法
|
||
saveSettings() {
|
||
this.$message.success('设置已保存');
|
||
},
|
||
resetSettings() {
|
||
this.settingsForm = {
|
||
themeColor: '#409EFF',
|
||
notificationMethods: ['站内消息', '电子邮件']
|
||
};
|
||
this.$message.success('已恢复默认设置');
|
||
},
|
||
backupNow() {
|
||
this.$message.success('备份已开始');
|
||
},
|
||
restoreBackup() {
|
||
this.$message('恢复备份');
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |