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

3468 lines
138 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;
}
/* 施工任务卡片 */
.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>