yuanxingsheji/施工操作台/操作台.html

2777 lines
110 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!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;
}
/* 响应式调整 */
@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>
<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="fieldwork">
<template slot="title">
<i class="el-icon-map-location"></i>
<span>外业施工</span>
</template>
<el-menu-item
index="fieldwork-project"
@click="switchModule('fieldwork-project')"
>
<span>项目列表</span>
<el-badge :value="3" :max="99" class="item"></el-badge>
</el-menu-item>
<el-menu-item
index="fieldwork-tools"
@click="switchModule('fieldwork-tools')"
>
<span>现场工艺/装备/软件工具/算法开发</span>
</el-menu-item>
</el-submenu>
<!-- 数据处理 - 下拉菜单 -->
<el-submenu index="data">
<template slot="title">
<i class="el-icon-upload"></i>
<span>数据处理</span>
</template>
<el-menu-item
index="data-import"
@click="switchModule('data-import')"
>
<span>数据入库</span>
</el-menu-item>
<!-- 智能巡检平台 - 二级下拉菜单 -->
<el-submenu index="inspection">
<template slot="title">智能巡检平台</template>
<el-menu-item
index="inspection-defect"
@click="switchModule('inspection-defect')"
>
<span>缺陷检测算法</span>
</el-menu-item>
<el-menu-item
index="inspection-tree"
@click="switchModule('inspection-tree')"
>
<span>树状可视化管理</span>
</el-menu-item>
<el-menu-item
index="inspection-standard"
@click="switchModule('inspection-standard')"
>
<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-lifecycle"
@click="switchModule('inspection-lifecycle')"
>
<span>全生命周期管理</span>
</el-menu-item>
<el-menu-item
index="inspection-drone"
@click="switchModule('inspection-drone')"
>
<span>无人机云服务、航线规划、机场管理</span>
</el-menu-item>
</el-submenu>
<el-menu-item
index="data-report"
@click="switchModule('data-report')"
>
<span>报告修改审核</span>
</el-menu-item>
<el-menu-item
index="data-video"
@click="switchModule('data-video')"
>
<span>塔下检测视频</span>
</el-menu-item>
</el-submenu>
<!-- 项目交付 - 下拉菜单 -->
<el-submenu index="delivery">
<template slot="title">
<i class="el-icon-finished"></i>
<span>项目交付</span>
</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-menu-item index="others" @click="switchModule('others')">
<i class="el-icon-set-up"></i>
<span slot="title">其他</span>
</el-menu-item>
</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">12<span class="data-unit"></span></div>
</div>
<div class="data-card">
<div class="data-title">发现缺陷</div>
<div class="data-value">8<span class="data-unit"></span></div>
</div>
<div class="data-card">
<div class="data-title">待审核报告</div>
<div class="data-value">3<span class="data-unit"></span></div>
</div>
<div class="data-card">
<div class="data-title">设备在线</div>
<div class="data-value">5/6<span class="data-unit"></span></div>
</div>
</div>
<div class="card-container">
<el-tabs v-model="dashboardTab">
<el-tab-pane label="任务进度" name="tasks">
<div class="chart-container" ref="taskChart"></div>
<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="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="defects">
<div class="chart-container" ref="defectChart"></div>
<h3>最新缺陷</h3>
<el-table :data="recentDefects" 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="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="time" label="发现时间" width="180"></el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button size="mini" @click="viewDefectDetail(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 === 'fieldwork-project'">
<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-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="editProject(scope.row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!-- 外业施工 - 现场工具模块 -->
<div v-if="activeModule === 'fieldwork-tools'">
<h2 class="module-title">现场工艺/装备/软件工具/算法开发</h2>
<div class="card-container">
<el-alert
title="此功能正在开发中,敬请期待"
type="info"
show-icon
:closable="false"
>
</el-alert>
<div style="margin-top: 20px; text-align: center;">
<img src="https://via.placeholder.com/600x300?text=开发中" style="max-width: 100%;">
</div>
</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('fieldwork-project')">返回项目列表</el-button>
</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"
>
<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 === 'inspection-drone'">
<h2 class="module-title">无人机云服务、航线规划、机场管理</h2>
<div class="card-container">
<el-alert
title="此功能正在开发中,敬请期待"
type="info"
show-icon
:closable="false"
>
</el-alert>
<div style="margin-top: 20px; text-align: center;">
<img src="https://via.placeholder.com/600x300?text=开发中" style="max-width: 100%;">
</div>
</div>
</div>
<!-- 数据处理 - 报告修改审核模块 -->
<div v-if="activeModule === 'data-report'">
<h2 class="module-title">报告修改审核</h2>
<div class="card-container">
<el-tabs v-model="reportReviewTab">
<el-tab-pane label="待审核" name="pending">
<el-table :data="pendingReports" 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="submitter" label="提交人" width="120"></el-table-column>
<el-table-column prop="submitTime" label="提交时间" width="180"></el-table-column>
<el-table-column label="操作" width="250">
<template slot-scope="scope">
<el-button size="mini" @click="reviewReport(scope.row)">审核</el-button>
<el-button size="mini" type="primary" @click="viewReport(scope.row)">查看</el-button>
<el-button size="mini" type="success" @click="approveReport(scope.row)">通过</el-button>
<el-button size="mini" type="danger" @click="rejectReport(scope.row)">驳回</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="已审核" name="reviewed">
<el-table :data="reviewedReports" 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="submitter" label="提交人" width="120"></el-table-column>
<el-table-column prop="reviewer" label="审核人" width="120"></el-table-column>
<el-table-column prop="reviewTime" 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' : '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="viewReport(scope.row)">查看</el-button>
<el-button size="mini" type="primary" @click="viewReviewComments(scope.row)">备注</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
<!-- 报告审核对话框 -->
<el-dialog title="报告审核" :visible.sync="reportReviewDialogVisible" width="80%">
<div v-if="currentReviewReport">
<div class="report-preview">
<div class="report-section">
<h2 class="report-title">{{ currentReviewReport.name }}</h2>
<div class="report-content">
<p><strong>项目名称:</strong> {{ currentReviewReport.project }}</p>
<p><strong>机组编号:</strong> {{ currentReviewReport.turbine }}</p>
<p><strong>检查日期:</strong> {{ currentReviewReport.date }}</p>
<p><strong>检查人员:</strong> {{ currentReviewReport.inspector }}</p>
</div>
</div>
<div class="report-section" v-if="currentReviewReport.defects && currentReviewReport.defects.length > 0">
<h3 class="report-title">缺陷列表</h3>
<div class="report-content">
<div class="defect-item" v-for="(defect, index) in currentReviewReport.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>
<div style="margin-top: 20px;">
<h3>审核意见</h3>
<el-input
type="textarea"
:rows="4"
placeholder="请输入审核意见"
v-model="reviewComments"
></el-input>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="reportReviewDialogVisible = false">取消</el-button>
<el-button type="danger" @click="rejectReport(currentReviewReport)">驳回</el-button>
<el-button type="primary" @click="approveReport(currentReviewReport)">通过</el-button>
</span>
</el-dialog>
</div>
<!-- 数据处理 - 塔下检测视频模块 -->
<div v-if="activeModule === 'data-video'">
<h2 class="module-title">塔下检测视频</h2>
<div class="card-container">
<div style="margin-bottom: 20px;">
<el-input
placeholder="搜索项目或机组"
v-model="videoSearch"
clearable
style="width: 300px;"
>
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
</div>
<el-table :data="filteredVideos" 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="duration" label="时长" width="100"></el-table-column>
<el-table-column prop="size" label="文件大小" width="120"></el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-button size="mini" @click="playVideo(scope.row)">播放</el-button>
<el-button size="mini" type="primary" @click="analyzeVideo(scope.row)">分析</el-button>
<el-button size="mini" type="danger" @click="deleteVideo(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 视频播放对话框 -->
<el-dialog title="视频播放" :visible.sync="videoPlayerDialogVisible" width="70%">
<video
v-if="currentVideo"
controls
autoplay
style="width: 100%;"
>
<source :src="currentVideo.url" type="video/mp4">
您的浏览器不支持 HTML5 视频。
</video>
<span slot="footer" class="dialog-footer">
<el-button @click="videoPlayerDialogVisible = 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 === 'others'">
<h2 class="module-title">其他</h2>
<div class="card-container">
<el-tabs v-model="othersTab">
<el-tab-pane label="系统设置" name="settings">
<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 label="数据备份">
<el-switch v-model="settingsForm.autoBackup"></el-switch>
<span style="margin-left: 10px; color: #909399;">{{ settingsForm.autoBackup ? '已开启' : '已关闭' }}</span>
</el-form-item>
<el-form-item label="备份频率">
<el-select v-model="settingsForm.backupFrequency" :disabled="!settingsForm.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>
<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="help">
<div style="margin-bottom: 20px;">
<el-input
placeholder="搜索帮助内容"
v-model="helpSearch"
clearable
style="width: 300px;"
>
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
</div>
<el-collapse v-model="activeHelpItems">
<el-collapse-item title="如何创建新项目" name="1">
<div>1. 点击"外业施工" -> "项目列表"</div>
<div>2. 点击右上角的"新建项目"按钮</div>
<div>3. 填写项目基本信息并保存</div>
</el-collapse-item>
<el-collapse-item title="如何上传检查数据" name="2">
<div>1. 在项目列表中选择要上传数据的项目</div>
<div>2. 点击"数据处理" -> "数据入库"</div>
<div>3. 拖拽或选择要上传的文件</div>
<div>4. 点击"开始上传"按钮</div>
</el-collapse-item>
<el-collapse-item title="如何生成检查报告" name="3">
<div>1. 确保所有检查数据已上传</div>
<div>2. 点击"数据处理" -> "报告生成"</div>
<div>3. 点击"生成新报告"按钮</div>
<div>4. 填写报告内容并保存</div>
</el-collapse-item>
<el-collapse-item title="如何进行可靠性评估" name="4">
<div>1. 点击"项目交付" -> "可靠性评估"</div>
<div>2. 选择要评估的项目</div>
<div>3. 点击"生成评估报告"按钮</div>
<div>4. 查看评估结果并导出报告</div>
</el-collapse-item>
</el-collapse>
</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: 'tasks',
standardTab: 'defect',
lifecycleTab: 'turbine',
reportReviewTab: 'pending',
othersTab: 'settings',
activeDataType: 'image',
storageStep: 0,
activeHelpItems: ['1'],
// 用户信息
userInfo: {
name: '张工程师',
role: '施工组长'
},
// 工作台数据
myTasks: [
{ 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' },
{ name: 'C风场数据整理', project: 'C风场年度检查', progress: 90, status: 'success', deadline: '2023-11-10' }
],
recentDefects: [
{ type: '前缘腐蚀', position: '1号机组-2号叶片-叶尖', severity: '高', time: '2023-11-05 14:30' },
{ type: '后缘开裂', position: '2号机组-3号叶片-中部', severity: '中', time: '2023-11-06 09:15' },
{ type: '表面划痕', position: '3号机组-1号叶片-根部', severity: '低', time: '2023-11-07 16:45' }
],
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 }
],
// 数据入库
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: '成功' }
],
// 缺陷检测算法
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: '缺陷' }
]
}
]
},
{
id: 2,
label: 'B风场',
type: 'farm',
children: [
{
id: 201,
label: '1号机组',
type: 'turbine',
status: '维修中',
lastInspection: '2023-10-28',
defects: 3,
children: [
{ id: 2011, label: '1号叶片', type: 'blade', status: '缺陷' },
{ id: 2012, label: '2号叶片', type: 'blade', status: '维修中' },
{ id: 2013, 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: [] }
],
// 报告修改审核
pendingReports: [
{ name: 'A风场2号机组检查报告', project: 'A风场2023年检查', turbine: 'A-002', submitter: '张工程师', submitTime: '2023-11-06 14:30' },
{ name: 'B风场2号机组检查报告', project: 'B风场维修项目', turbine: 'B-002', submitter: '李技术员', submitTime: '2023-11-07 09:15' }
],
reviewedReports: [
{ name: 'A风场1号机组检查报告', project: 'A风场2023年检查', turbine: 'A-001', submitter: '张工程师', reviewer: '王经理', reviewTime: '2023-11-05 16:45', status: '通过' },
{ name: 'C风场1号机组检查报告', project: 'C风场年度检查', turbine: 'C-001', submitter: '赵工程师', reviewer: '王经理', reviewTime: '2023-10-30 11:20', status: '驳回' }
],
currentReviewReport: null,
reportReviewDialogVisible: false,
reviewComments: '',
// 塔下检测视频
videoSearch: '',
videos: [
{ name: 'A-001塔下检测', project: 'A风场2023年检查', turbine: 'A-001', date: '2023-11-05', duration: '12:34', size: '156MB', url: 'https://example.com/videos/a001.mp4' },
{ name: 'A-002塔下检测', project: 'A风场2023年检查', turbine: 'A-002', date: '2023-11-06', duration: '15:20', size: '198MB', url: 'https://example.com/videos/a002.mp4' },
{ name: 'B-001塔下检测', project: 'B风场维修项目', turbine: 'B-001', date: '2023-10-28', duration: '18:45', size: '245MB', url: 'https://example.com/videos/b001.mp4' }
],
currentVideo: null,
videoPlayerDialogVisible: false,
// 可靠性评估
selectedProject: null,
reliabilityData: null,
// 数据质量评估
qualityData: null,
// 质量入库
storageCheckResults: [
{ item: '检查数据完整性', status: '通过', message: '所有必填字段均已填写' },
{ item: '图片质量检查', status: '通过', message: '所有图片清晰可辨' },
{ item: '视频质量检查', status: '通过', message: '视频完整且清晰' },
{ item: '报告一致性检查', status: '通过', message: '报告与数据一致' }
],
storageForm: {
qualityScore: 4,
notes: '',
storageLocation: 'main'
},
// 其他-系统设置
settingsForm: {
themeColor: '#409EFF',
notificationMethods: ['站内消息', '电子邮件'],
autoBackup: true,
backupFrequency: 'weekly'
},
helpSearch: '',
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()) ||
turbine.name.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())
);
},
filteredVideos() {
if (!this.videoSearch) return this.videos;
return this.videos.filter(video =>
video.name.toLowerCase().includes(this.videoSearch.toLowerCase()) ||
video.project.toLowerCase().includes(this.videoSearch.toLowerCase()) ||
video.turbine.toLowerCase().includes(this.videoSearch.toLowerCase())
);
},
canProceedToNextStep() {
return this.storageCheckResults.every(item => item.status === '通过');
}
},
mounted() {
this.initCharts();
},
watch: {
treeSearch(val) {
this.$refs.tree.filter(val);
}
},
methods: {
toggleSidebar() {
this.isCollapse = !this.isCollapse;
},
switchModule(module) {
this.activeModule = module;
},
logout() {
this.$confirm('确定要退出登录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$message({
type: 'success',
message: '已退出登录'
});
// 实际应用中这里应该跳转到登录页面
}).catch(() => {
this.$message({
type: 'info',
message: '已取消退出'
});
});
},
// 工作台方法
initCharts() {
// 任务进度图表
const taskChart = echarts.init(this.$refs.taskChart);
taskChart.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'
}
}
]
});
// 缺陷统计图表
const defectChart = echarts.init(this.$refs.defectChart);
defectChart.setOption({
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
series: [
{
name: '缺陷类型',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '18',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: 12, name: '前缘腐蚀' },
{ value: 8, name: '后缘开裂' },
{ value: 5, name: '表面划痕' },
{ value: 3, name: '雷击损伤' },
{ value: 2, name: '其他缺陷' }
]
}
]
});
},
viewTaskDetail(task) {
this.$message(`查看任务: ${task.name}`);
},
viewDefectDetail(defect) {
this.$message(`查看缺陷: ${defect.type} (${defect.position})`);
},
handleNotification(notification) {
this.$message(`处理通知: ${notification.title}`);
},
// 项目列表方法
showProjectDialog() {
this.$message('显示新建项目对话框');
},
refreshProjects() {
this.$message('刷新项目列表');
},
viewProjectDetail(project) {
this.$message(`查看项目: ${project.name}`);
},
editProject(project) {
this.$message(`编辑项目: ${project.name}`);
},
// 数据入库方法
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.$message(`预览文件: ${file.name}`);
},
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: '已取消删除'
});
});
},
// 缺陷检测算法方法
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 = url;
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}`);
},
// 报告修改审核方法
reviewReport(report) {
this.currentReviewReport = {
name: report.name,
project: report.project,
turbine: report.turbine,
date: report.date,
inspector: '张工程师',
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' }
]
}
]
};
this.reportReviewDialogVisible = true;
},
approveReport(report) {
this.$confirm(`确定要通过报告 ${report.name} 的审核吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.pendingReports = this.pendingReports.filter(item => item.name !== report.name);
this.reviewedReports.unshift({
name: report.name,
project: report.project,
turbine: report.turbine,
submitter: '张工程师',
reviewer: this.userInfo.name,
reviewTime: new Date().toLocaleString(),
status: '通过'
});
this.reportReviewDialogVisible = false;
this.$message({
type: 'success',
message: '报告审核通过!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消操作'
});
});
},
rejectReport(report) {
this.$confirm(`确定要驳回报告 ${report.name} 吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.pendingReports = this.pendingReports.filter(item => item.name !== report.name);
this.reviewedReports.unshift({
name: report.name,
project: report.project,
turbine: report.turbine,
submitter: '张工程师',
reviewer: this.userInfo.name,
reviewTime: new Date().toLocaleString(),
status: '驳回'
});
this.reportReviewDialogVisible = false;
this.$message({
type: 'success',
message: '报告已驳回!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消操作'
});
});
},
viewReviewComments(report) {
this.$message(`查看审核备注: ${report.name}`);
},
// 塔下检测视频方法
playVideo(video) {
this.currentVideo = video;
this.videoPlayerDialogVisible = true;
},
analyzeVideo(video) {
this.$message(`分析视频: ${video.name}`);
},
deleteVideo(video) {
this.$confirm(`确定要删除视频 ${video.name} 吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.videos = this.videos.filter(item => item.name !== video.name);
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
// 可靠性评估方法
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;
},
// 系统设置方法
saveSettings() {
this.$message.success('系统设置已保存');
},
resetSettings() {
this.settingsForm = {
themeColor: '#409EFF',
notificationMethods: ['站内消息', '电子邮件'],
autoBackup: true,
backupFrequency: 'weekly'
};
this.$message.success('已恢复默认设置');
}
}
});
</script>
</body>
</html>