形变接口原型
This commit is contained in:
parent
a79c4f3489
commit
3dd794d7f0
|
@ -3,8 +3,8 @@
|
||||||
VITE_API_PREFIX = '/dev-api'
|
VITE_API_PREFIX = '/dev-api'
|
||||||
|
|
||||||
# 接口地址
|
# 接口地址
|
||||||
# VITE_API_BASE_URL = 'http://pms.dtyx.net:9158/'
|
VITE_API_BASE_URL = 'http://pms.dtyx.net:9158/'
|
||||||
VITE_API_BASE_URL = 'http://localhost:8888/'
|
# VITE_API_BASE_URL = 'http://localhost:8888/'
|
||||||
|
|
||||||
# 接口地址 (WebSocket)
|
# 接口地址 (WebSocket)
|
||||||
VITE_API_WS_URL = 'ws://localhost:8000'
|
VITE_API_WS_URL = 'ws://localhost:8000'
|
||||||
|
@ -13,7 +13,7 @@ VITE_API_WS_URL = 'ws://localhost:8000'
|
||||||
VITE_BASE = '/'
|
VITE_BASE = '/'
|
||||||
|
|
||||||
# 是否开启开发者工具
|
# 是否开启开发者工具
|
||||||
VITE_OPEN_DEVTOOLS = false
|
VITE_OPEN_DEVTOOLS = true
|
||||||
|
|
||||||
# 应用配置面板
|
# 应用配置面板
|
||||||
VITE_APP_SETTING = true
|
VITE_APP_SETTING = true
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,125 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-tab-pane key="props" tap="形变" title="形变原数据">
|
||||||
|
<div class="tab-content">
|
||||||
|
<raw-data>
|
||||||
|
|
||||||
|
</raw-data>
|
||||||
|
</div>
|
||||||
|
</a-tab-pane>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import rawData from './raw-data.vue';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.data-storage-container {
|
||||||
|
padding: 16px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #262626;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-section {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-section {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 12px;
|
||||||
|
background: #fafafa;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.filter-item {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.filter-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #595959;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploaded-files-section {
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #262626;
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-container {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.image-preview,
|
||||||
|
.video-preview {
|
||||||
|
max-height: 500px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-info {
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 8px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #595959;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-tabs-nav) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-tabs-tab) {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-table-th) {
|
||||||
|
background-color: #fafafa;
|
||||||
|
color: #8c8c8c;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-table-td) {
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-tag) {
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-btn-size-small) {
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-upload-drag:hover) {
|
||||||
|
border-color: #1890ff;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,590 @@
|
||||||
|
<template>
|
||||||
|
<GiPageLayout>
|
||||||
|
<div class="raw-data-container">
|
||||||
|
<!-- <div class="page-header">
|
||||||
|
<div class="page-title">原始数据管理</div>
|
||||||
|
<div class="page-subtitle">管理和分析原始视频数据</div>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<div class="action-bar">
|
||||||
|
<div class="action-buttons">
|
||||||
|
<a-button type="primary" @click="showUploadModal = true">
|
||||||
|
<template #icon>
|
||||||
|
<IconUpload />
|
||||||
|
</template>
|
||||||
|
上传视频
|
||||||
|
</a-button>
|
||||||
|
<a-button type="primary" @click="handleBatchAnalysis">
|
||||||
|
<template #icon>
|
||||||
|
<IconPlayCircle />
|
||||||
|
</template>
|
||||||
|
批量分析
|
||||||
|
</a-button>
|
||||||
|
<a-button type="primary" @click="handleExportData">
|
||||||
|
<template #icon>
|
||||||
|
<IconDownload />
|
||||||
|
</template>
|
||||||
|
导出数据
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<div class="filter-section">
|
||||||
|
<a-form :model="filterForm" layout="inline">
|
||||||
|
<a-form-item label="项目">
|
||||||
|
<a-select v-model="filterForm.projectId" placeholder="请选择项目">
|
||||||
|
<a-option value="project-1">风电场A区</a-option>
|
||||||
|
<a-option value="project-2">风电场B区</a-option>
|
||||||
|
<a-option value="project-3">风电场C区</a-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="机组号">
|
||||||
|
<a-input v-model="filterForm.unitNumber" placeholder="请输入机组号" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="状态">
|
||||||
|
<a-select v-model="filterForm.status" placeholder="请选择状态">
|
||||||
|
<a-option value="completed">已完成</a-option>
|
||||||
|
<a-option value="pending">待分析</a-option>
|
||||||
|
<a-option value="analyzing">分析中</a-option>
|
||||||
|
<a-option value="failed">失败</a-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<a-button type="primary" @click="handleFilterChange">查询</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project-sections">
|
||||||
|
<div v-for="project in filteredProjects" :key="project.id" class="project-section">
|
||||||
|
<div class="project-header">
|
||||||
|
<div class="project-title">{{ project.name }}</div>
|
||||||
|
<div class="project-stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<IconVideoCamera />
|
||||||
|
{{ project.totalVideos }} 个视频
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<IconCheckCircle />
|
||||||
|
{{ project.completedCount }} 个已完成
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<IconClockCircle />
|
||||||
|
{{ project.pendingCount }} 个待分析
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="units-grid">
|
||||||
|
<div v-for="unit in project.units" :key="unit.id" class="unit-card">
|
||||||
|
<div class="unit-header">
|
||||||
|
<div class="unit-title">{{ unit.number }}</div>
|
||||||
|
<div class="unit-actions">
|
||||||
|
<a-button type="primary" size="small" @click="handleViewUnitVideos(unit)">查看全部</a-button>
|
||||||
|
<a-button type="primary" size="small" @click="handleAnalyzeUnit(unit)">{{
|
||||||
|
getAnalysisButtonText(unit.status)
|
||||||
|
}}</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="videos-list">
|
||||||
|
<div v-for="video in unit.videos" :key="video.id" class="video-item">
|
||||||
|
<div class="video-thumbnail">
|
||||||
|
<img :src="video.thumbnail" alt="Video Thumbnail" />
|
||||||
|
<div class="video-overlay" @click="handlePlayVideo(video)">
|
||||||
|
<IconPlayArrowFill style="font-size: 24px; color: #fff;" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="video-info">
|
||||||
|
<div class="video-name">{{ video.name }}</div>
|
||||||
|
<div class="video-meta">
|
||||||
|
<span>{{ video.duration }}</span>
|
||||||
|
<span>{{ video.angle }}°</span>
|
||||||
|
</div>
|
||||||
|
<div class="video-status">
|
||||||
|
<a-tag :color="getStatusColor(video.status)">{{ getStatusText(video.status) }}</a-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="analysis-progress">
|
||||||
|
<div class="progress-info">
|
||||||
|
<span>分析进度</span>
|
||||||
|
<span>{{ unit.progress }}%</span>
|
||||||
|
</div>
|
||||||
|
<a-progress :percent="unit.progress" :show-text="false" status="active" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 视频播放模态框 -->
|
||||||
|
<a-modal v-model:visible="videoModalVisible" title="原始视频播放" width="900px" @ok="videoModalVisible = false"
|
||||||
|
@cancel="videoModalVisible = false">
|
||||||
|
<video v-if="selectedVideo" :src="selectedVideo.url" controls
|
||||||
|
style="width: 100%; height: 480px; border-radius: 8px; background: #000;"></video>
|
||||||
|
<div v-if="selectedVideo" class="video-meta-info">
|
||||||
|
<p>项目:{{ selectedVideo.projectName }}</p>
|
||||||
|
<p>机组号:{{ selectedVideo.unitNumber }}</p>
|
||||||
|
<p>采集人:{{ selectedVideo.collector }}</p>
|
||||||
|
<p>风速:{{ selectedVideo.windSpeed }} m/s</p>
|
||||||
|
<p>转速:{{ selectedVideo.rpm }} rpm</p>
|
||||||
|
<p>采集时间:{{ selectedVideo.time }}</p>
|
||||||
|
<p>角度:{{ selectedVideo.angle }}°</p>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
|
<!-- 上传视频模态框 -->
|
||||||
|
<a-modal v-model:visible="showUploadModal" title="上传原始视频" width="600px" @ok="handleUpload"
|
||||||
|
@cancel="showUploadModal = false">
|
||||||
|
<a-form :model="uploadForm" layout="vertical">
|
||||||
|
<a-form-item label="项目" required>
|
||||||
|
<a-select v-model="uploadForm.projectId" placeholder="请选择项目">
|
||||||
|
<a-option value="project-1">风电场A区</a-option>
|
||||||
|
<a-option value="project-2">风电场B区</a-option>
|
||||||
|
<a-option value="project-3">风电场C区</a-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="机组号" required>
|
||||||
|
<a-input v-model="uploadForm.unitNumber" placeholder="请输入机组号" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="采集人" required>
|
||||||
|
<a-input v-model="uploadForm.collector" placeholder="请输入采集人姓名" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="风速 (m/s)">
|
||||||
|
<a-input-number v-model="uploadForm.windSpeed" :min="0" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="转速 (rpm)">
|
||||||
|
<a-input-number v-model="uploadForm.rpm" :min="0" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="采集时间" required>
|
||||||
|
<a-date-picker v-model="uploadForm.time" show-time format="YYYY-MM-DD HH:mm" style="width: 100%;" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="视频文件(可多选,建议3个角度)" required>
|
||||||
|
<a-upload v-model:file-list="uploadForm.fileList" :multiple="true" :limit="3" accept="video/*"
|
||||||
|
:auto-upload="false" list-type="picture-card">
|
||||||
|
<template #upload-button>
|
||||||
|
<a-button>选择视频</a-button>
|
||||||
|
</template>
|
||||||
|
</a-upload>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</GiPageLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed } from 'vue'
|
||||||
|
import { Message } from '@arco-design/web-vue'
|
||||||
|
import {
|
||||||
|
IconUpload,
|
||||||
|
IconPlayCircle,
|
||||||
|
IconDownload,
|
||||||
|
IconVideoCamera,
|
||||||
|
IconCheckCircle,
|
||||||
|
IconClockCircle,
|
||||||
|
IconPlayArrowFill
|
||||||
|
} from '@arco-design/web-vue/es/icon'
|
||||||
|
|
||||||
|
const showUploadModal = ref(false)
|
||||||
|
const videoModalVisible = ref(false)
|
||||||
|
const selectedVideo = ref<any>(null)
|
||||||
|
|
||||||
|
const filterForm = reactive({
|
||||||
|
projectId: '',
|
||||||
|
unitNumber: '',
|
||||||
|
status: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const uploadForm = reactive({
|
||||||
|
projectId: '',
|
||||||
|
unitNumber: '',
|
||||||
|
collector: '',
|
||||||
|
windSpeed: null,
|
||||||
|
rpm: null,
|
||||||
|
time: '',
|
||||||
|
fileList: []
|
||||||
|
})
|
||||||
|
|
||||||
|
// 示例数据结构
|
||||||
|
const projects = ref([
|
||||||
|
{
|
||||||
|
id: 'project-1',
|
||||||
|
name: '风电场A区',
|
||||||
|
totalVideos: 6,
|
||||||
|
completedCount: 4,
|
||||||
|
pendingCount: 2,
|
||||||
|
units: [
|
||||||
|
{
|
||||||
|
id: 'A-001',
|
||||||
|
number: 'A-001',
|
||||||
|
status: 'completed',
|
||||||
|
progress: 100,
|
||||||
|
videos: [
|
||||||
|
{
|
||||||
|
id: 'v1',
|
||||||
|
name: 'A-001-正面',
|
||||||
|
url: '/videos/A-001-front.mp4',
|
||||||
|
thumbnail: '/images/A-001-front.jpg',
|
||||||
|
angle: 0,
|
||||||
|
duration: '00:30',
|
||||||
|
status: 'completed',
|
||||||
|
projectName: '风电场A区',
|
||||||
|
unitNumber: 'A-001',
|
||||||
|
collector: '张三',
|
||||||
|
windSpeed: 8.2,
|
||||||
|
rpm: 15,
|
||||||
|
time: '2023-11-05 08:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'v2',
|
||||||
|
name: 'A-001-侧面',
|
||||||
|
url: '/videos/A-001-side.mp4',
|
||||||
|
thumbnail: '/images/A-001-side.jpg',
|
||||||
|
angle: 90,
|
||||||
|
duration: '00:30',
|
||||||
|
status: 'completed',
|
||||||
|
projectName: '风电场A区',
|
||||||
|
unitNumber: 'A-001',
|
||||||
|
collector: '张三',
|
||||||
|
windSpeed: 8.2,
|
||||||
|
rpm: 15,
|
||||||
|
time: '2023-11-05 08:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'v3',
|
||||||
|
name: 'A-001-背面',
|
||||||
|
url: '/videos/A-001-back.mp4',
|
||||||
|
thumbnail: '/images/A-001-back.jpg',
|
||||||
|
angle: 180,
|
||||||
|
duration: '00:30',
|
||||||
|
status: 'pending',
|
||||||
|
projectName: '风电场A区',
|
||||||
|
unitNumber: 'A-001',
|
||||||
|
collector: '张三',
|
||||||
|
windSpeed: 8.2,
|
||||||
|
rpm: 15,
|
||||||
|
time: '2023-11-05 08:00'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'A-002',
|
||||||
|
number: 'A-002',
|
||||||
|
status: 'analyzing',
|
||||||
|
progress: 60,
|
||||||
|
videos: [
|
||||||
|
{
|
||||||
|
id: 'v4',
|
||||||
|
name: 'A-002-正面',
|
||||||
|
url: '/videos/A-002-front.mp4',
|
||||||
|
thumbnail: '/images/A-002-front.jpg',
|
||||||
|
angle: 0,
|
||||||
|
duration: '00:28',
|
||||||
|
status: 'analyzing',
|
||||||
|
projectName: '风电场A区',
|
||||||
|
unitNumber: 'A-002',
|
||||||
|
collector: '李四',
|
||||||
|
windSpeed: 7.9,
|
||||||
|
rpm: 14,
|
||||||
|
time: '2023-11-05 12:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'v5',
|
||||||
|
name: 'A-002-侧面',
|
||||||
|
url: '/videos/A-002-side.mp4',
|
||||||
|
thumbnail: '/images/A-002-side.jpg',
|
||||||
|
angle: 90,
|
||||||
|
duration: '00:28',
|
||||||
|
status: 'pending',
|
||||||
|
projectName: '风电场A区',
|
||||||
|
unitNumber: 'A-002',
|
||||||
|
collector: '李四',
|
||||||
|
windSpeed: 7.9,
|
||||||
|
rpm: 14,
|
||||||
|
time: '2023-11-05 12:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'v6',
|
||||||
|
name: 'A-002-背面',
|
||||||
|
url: '/videos/A-002-back.mp4',
|
||||||
|
thumbnail: '/images/A-002-back.jpg',
|
||||||
|
angle: 180,
|
||||||
|
duration: '00:28',
|
||||||
|
status: 'pending',
|
||||||
|
projectName: '风电场A区',
|
||||||
|
unitNumber: 'A-002',
|
||||||
|
collector: '李四',
|
||||||
|
windSpeed: 7.9,
|
||||||
|
rpm: 14,
|
||||||
|
time: '2023-11-05 12:00'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
// ... 其他项目
|
||||||
|
])
|
||||||
|
|
||||||
|
const filteredProjects = computed(() => {
|
||||||
|
// 按筛选条件过滤
|
||||||
|
return projects.value
|
||||||
|
.filter(p => !filterForm.projectId || p.id === filterForm.projectId)
|
||||||
|
.map(project => ({
|
||||||
|
...project,
|
||||||
|
units: project.units
|
||||||
|
.filter(u => !filterForm.unitNumber || u.number === filterForm.unitNumber)
|
||||||
|
.map(unit => ({
|
||||||
|
...unit,
|
||||||
|
videos: unit.videos.filter(v => !filterForm.status || v.status === filterForm.status)
|
||||||
|
}))
|
||||||
|
.filter(u => u.videos.length > 0)
|
||||||
|
}))
|
||||||
|
.filter(p => p.units.length > 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleFilterChange() {
|
||||||
|
// 这里可以加API请求
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePlayVideo(video: any) {
|
||||||
|
selectedVideo.value = video
|
||||||
|
videoModalVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleViewUnitVideos(unit: any) {
|
||||||
|
// 可扩展为弹窗或跳转页面,展示该机组所有视频
|
||||||
|
Message.info(`查看机组 ${unit.number} 的所有视频`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAnalyzeUnit(unit: any) {
|
||||||
|
// 触发分析流程
|
||||||
|
Message.success(`已提交机组 ${unit.number} 的分析任务`)
|
||||||
|
// 实际应调用API并刷新状态
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusColor(status: string) {
|
||||||
|
switch (status) {
|
||||||
|
case 'completed': return 'green'
|
||||||
|
case 'pending': return 'gray'
|
||||||
|
case 'analyzing': return 'blue'
|
||||||
|
case 'failed': return 'red'
|
||||||
|
default: return 'gray'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getStatusText(status: string) {
|
||||||
|
switch (status) {
|
||||||
|
case 'completed': return '已完成'
|
||||||
|
case 'pending': return '待分析'
|
||||||
|
case 'analyzing': return '分析中'
|
||||||
|
case 'failed': return '失败'
|
||||||
|
default: return '未知'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getAnalysisButtonText(status: string) {
|
||||||
|
switch (status) {
|
||||||
|
case 'completed': return '重新分析'
|
||||||
|
case 'pending': return '分析'
|
||||||
|
case 'analyzing': return '分析中...'
|
||||||
|
case 'failed': return '重新分析'
|
||||||
|
default: return '分析'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBatchAnalysis() {
|
||||||
|
Message.success('批量分析任务已提交')
|
||||||
|
}
|
||||||
|
function handleExportData() {
|
||||||
|
Message.success('数据导出成功')
|
||||||
|
}
|
||||||
|
function handleUpload() {
|
||||||
|
Message.success('上传成功')
|
||||||
|
showUploadModal.value = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.raw-data-container {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
color: #1d2129;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #86909c;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.filter-section {
|
||||||
|
margin-left: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-sections {
|
||||||
|
.project-section {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px #f0f1f2;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
.project-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
.project-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.units-grid {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.unit-card {
|
||||||
|
background: #fafbfc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
width: 360px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
.unit-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.unit-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.videos-list {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.video-item {
|
||||||
|
width: 100px;
|
||||||
|
|
||||||
|
.video-thumbnail {
|
||||||
|
position: relative;
|
||||||
|
width: 100px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-info {
|
||||||
|
margin-top: 4px;
|
||||||
|
|
||||||
|
.video-name {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #1d2129;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-meta {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #86909c;
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-status {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-progress {
|
||||||
|
margin-top: 8px;
|
||||||
|
|
||||||
|
.progress-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #86909c;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-meta-info {
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #4e5969;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 2px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<GiPageLayout>
|
<GiPageLayout>
|
||||||
<!-- 页面标题 -->
|
<!-- 页面标题 -->
|
||||||
<!-- <div class="page-header">
|
<!-- <div class="page-header">
|
||||||
<h2 class="page-title">图像音频关联查看</h2>
|
<h2 class="page-title">图像音频关联查看</h2>
|
||||||
</div>-->
|
</div>-->
|
||||||
|
|
||||||
|
@ -17,62 +17,32 @@
|
||||||
<!-- 项目选择 -->
|
<!-- 项目选择 -->
|
||||||
<div class="filter-item">
|
<div class="filter-item">
|
||||||
<span class="filter-label">项目:</span>
|
<span class="filter-label">项目:</span>
|
||||||
<a-select
|
<a-select v-model="filterParams.project" placeholder="请选择项目" :options="projectOptions" allow-search
|
||||||
v-model="filterParams.project"
|
allow-clear :loading="loading.project" style="width: 200px" @change="handleFilterChange" />
|
||||||
placeholder="请选择项目"
|
|
||||||
:options="projectOptions"
|
|
||||||
allow-search
|
|
||||||
allow-clear
|
|
||||||
:loading="loading.project"
|
|
||||||
style="width: 200px"
|
|
||||||
@change="handleFilterChange"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 机组选择 -->
|
<!-- 机组选择 -->
|
||||||
<div class="filter-item">
|
<div class="filter-item">
|
||||||
<span class="filter-label">机组:</span>
|
<span class="filter-label">机组:</span>
|
||||||
<a-select
|
<a-select v-model="filterParams.unit" placeholder="请先选择项目" :options="unitOptions" allow-search
|
||||||
v-model="filterParams.unit"
|
allow-clear :disabled="!filterParams.project" :loading="loading.unit" style="width: 200px"
|
||||||
placeholder="请先选择项目"
|
@change="handleFilterChange" />
|
||||||
:options="unitOptions"
|
|
||||||
allow-search
|
|
||||||
allow-clear
|
|
||||||
:disabled="!filterParams.project"
|
|
||||||
:loading="loading.unit"
|
|
||||||
style="width: 200px"
|
|
||||||
@change="handleFilterChange"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 部件选择 -->
|
<!-- 部件选择 -->
|
||||||
<div class="filter-item">
|
<div class="filter-item">
|
||||||
<span class="filter-label">部件:</span>
|
<span class="filter-label">部件:</span>
|
||||||
<a-select
|
<a-select v-model="filterParams.component" placeholder="请先选择机组" :options="componentOptions"
|
||||||
v-model="filterParams.component"
|
allow-search allow-clear :disabled="!filterParams.unit" :loading="loading.component"
|
||||||
placeholder="请先选择机组"
|
style="width: 200px" @change="handleFilterChange" />
|
||||||
:options="componentOptions"
|
|
||||||
allow-search
|
|
||||||
allow-clear
|
|
||||||
:disabled="!filterParams.unit"
|
|
||||||
:loading="loading.component"
|
|
||||||
style="width: 200px"
|
|
||||||
@change="handleFilterChange"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 已上传数据列表 -->
|
<!-- 已上传数据列表 -->
|
||||||
<div class="uploaded-files-section">
|
<div class="uploaded-files-section">
|
||||||
<a-table
|
<a-table :columns="fileColumns" :data="imageList" :pagination="false"
|
||||||
:columns="fileColumns"
|
:scroll="{ x: '100%', y: 'calc(100vh - 380px)' }" :loading="loading.image" class="scrollable-table">
|
||||||
:data="imageList"
|
|
||||||
:pagination="false"
|
|
||||||
:scroll="{ x: '100%', y: 'calc(100vh - 380px)' }"
|
|
||||||
:loading="loading.image"
|
|
||||||
class="scrollable-table"
|
|
||||||
>
|
|
||||||
<!-- 文件类型 -->
|
<!-- 文件类型 -->
|
||||||
<template #type="{ record }">
|
<template #type="{ record }">
|
||||||
<a-tag :color="getFileTypeColor(record.type)" size="small">
|
<a-tag :color="getFileTypeColor(record.type)" size="small">
|
||||||
|
@ -82,7 +52,7 @@
|
||||||
|
|
||||||
<!-- 文件大小 -->
|
<!-- 文件大小 -->
|
||||||
<template #size="{ record }">
|
<template #size="{ record }">
|
||||||
<span>{{ record.imageTypeLabel}}</span>
|
<span>{{ record.imageTypeLabel }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
|
@ -103,6 +73,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="props" tap="形变" title="形变原数据">
|
||||||
|
<div class="tab-content">
|
||||||
|
<raw-data>
|
||||||
|
|
||||||
|
</raw-data>
|
||||||
|
</div>
|
||||||
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -112,11 +89,11 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, computed,onMounted } from 'vue'
|
import { ref, reactive, computed, onMounted } from 'vue'
|
||||||
import { Message } from '@arco-design/web-vue'
|
import { Message } from '@arco-design/web-vue'
|
||||||
import type { TableColumnData } from '@arco-design/web-vue'
|
import type { TableColumnData } from '@arco-design/web-vue'
|
||||||
import PreviewModal from './components/PreviewModal.vue'
|
import PreviewModal from './components/PreviewModal.vue'
|
||||||
|
import rawData from './components/raw-data.vue'
|
||||||
import {
|
import {
|
||||||
getProjectList,
|
getProjectList,
|
||||||
getTurbineList,
|
getTurbineList,
|
||||||
|
@ -128,6 +105,7 @@ import {
|
||||||
batchUploadImages,
|
batchUploadImages,
|
||||||
uploadImageToPartV2
|
uploadImageToPartV2
|
||||||
} from '@/apis/industrial-image'
|
} from '@/apis/industrial-image'
|
||||||
|
import DeformationTap from './components/DeformationTap.vue'
|
||||||
|
|
||||||
const previewModal = ref()
|
const previewModal = ref()
|
||||||
// 活动选项卡
|
// 活动选项卡
|
||||||
|
@ -141,9 +119,9 @@ const filterParams = reactive({
|
||||||
})
|
})
|
||||||
|
|
||||||
// 筛选选项
|
// 筛选选项
|
||||||
const projectOptions = ref<Array<{label: string, value: string}>>([])
|
const projectOptions = ref<Array<{ label: string, value: string }>>([])
|
||||||
const unitOptions = ref<Array<{label: string, value: string}>>([])
|
const unitOptions = ref<Array<{ label: string, value: string }>>([])
|
||||||
const componentOptions = ref<Array<{label: string, value: string}>>([])
|
const componentOptions = ref<Array<{ label: string, value: string }>>([])
|
||||||
|
|
||||||
// 图像列表
|
// 图像列表
|
||||||
const imageList = ref<Array<{
|
const imageList = ref<Array<{
|
||||||
|
@ -255,33 +233,28 @@ const handleFilterChange = async () => {
|
||||||
|
|
||||||
loading.image = true
|
loading.image = true
|
||||||
try {
|
try {
|
||||||
let params = {
|
const params: any = {
|
||||||
projectId: filterParams.project
|
|
||||||
}
|
|
||||||
if(filterParams.unit){
|
|
||||||
params = {
|
|
||||||
projectId: filterParams.project,
|
projectId: filterParams.project,
|
||||||
turbineId: filterParams.unit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filterParams.unit) {
|
||||||
|
params.turbineId = filterParams.unit
|
||||||
}
|
}
|
||||||
if(filterParams.component){
|
|
||||||
params = {
|
if (filterParams.component) {
|
||||||
projectId: filterParams.project,
|
params.partId = filterParams.component
|
||||||
turbineId: filterParams.unit,
|
|
||||||
partId: filterParams.component
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await getImageList(params)
|
const res = await getImageList(params)
|
||||||
imageList.value = res.data.map((item: any) => ({
|
imageList.value = res.data.map((item: any) => ({
|
||||||
id: item.imageId,
|
id: item.imageId,
|
||||||
name: item.imageName,
|
name: item.imageName,
|
||||||
type: item.imageType?item.imageType:"未指定类型",
|
type: item.imageType ? item.imageType : "未指定类型",
|
||||||
imageTypeLabel: item.imageTypeLabel,
|
imageTypeLabel: item.imageTypeLabel,
|
||||||
shootingTime: item.shootingTime,
|
shootingTime: item.shootingTime,
|
||||||
preTreatment: item.preTreatment?"已审核":"未审核",
|
preTreatment: item.preTreatment ? "已审核" : "未审核",
|
||||||
imagePath: item.imagePath,
|
imagePath: item.imagePath,
|
||||||
audioList:item.audioList
|
audioList: item.audioList
|
||||||
}))
|
}))
|
||||||
Message.success(`获取到 ${imageList.value.length} 条图像数据`)
|
Message.success(`获取到 ${imageList.value.length} 条图像数据`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -313,14 +286,6 @@ const fileColumns: TableColumnData[] = [
|
||||||
{ title: '操作', slotName: 'action', width: 150, fixed: 'right' }
|
{ title: '操作', slotName: 'action', width: 150, fixed: 'right' }
|
||||||
]
|
]
|
||||||
|
|
||||||
// 过滤后的文件列表
|
|
||||||
const filteredFiles = computed(() => {
|
|
||||||
return uploadedFiles.value.filter(file =>
|
|
||||||
(filterParams.project === null || file.project === filterParams.project) &&
|
|
||||||
(filterParams.unit === null || file.unit === filterParams.unit) &&
|
|
||||||
(filterParams.component === null || file.component === filterParams.component)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获取文件类型颜色
|
// 获取文件类型颜色
|
||||||
const getFileTypeColor = (type: string) => {
|
const getFileTypeColor = (type: string) => {
|
||||||
|
@ -363,7 +328,7 @@ const previewFile = (file: any) => {
|
||||||
/* previewFileData.value = file
|
/* previewFileData.value = file
|
||||||
previewModalVisible.value = true*/
|
previewModalVisible.value = true*/
|
||||||
|
|
||||||
const fileObj ={
|
const fileObj = {
|
||||||
id: file.id,
|
id: file.id,
|
||||||
name: file.name,
|
name: file.name,
|
||||||
url: getImageUrl(file.imagePath),
|
url: getImageUrl(file.imagePath),
|
||||||
|
@ -374,12 +339,7 @@ const previewFile = (file: any) => {
|
||||||
|
|
||||||
// 删除文件
|
// 删除文件
|
||||||
const deleteFile = (file: any) => {
|
const deleteFile = (file: any) => {
|
||||||
console.log(index);
|
|
||||||
const index = uploadedFiles.value.findIndex(f => f.id === file.id)
|
|
||||||
if (index > -1) {
|
|
||||||
uploadedFiles.value.splice(index, 1)
|
|
||||||
Message.success('文件已删除')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue