Industrial-image-management.../src/views/construction-operation-plat.../implementation-workflow/data-processing/data-preprocessing/index.vue

532 lines
13 KiB
Vue
Raw Normal View History

2025-07-14 11:11:33 +08:00
<template>
<GiPageLayout>
<div class="data-preprocessing-container">
<!-- 步骤指示器 -->
<div class="steps-container">
<a-steps :current="currentStep" size="small" class="preprocessing-steps">
<a-step title="选择数据" />
<a-step title="预处理设置" />
<a-step title="执行预处理" />
<a-step title="完成" />
</a-steps>
</div>
<!-- 步骤内容 -->
<div class="step-content">
<!-- 第一步选择数据 -->
<div v-if="currentStep === 0" class="step-panel">
<div class="step-header">
<h3>选择要预处理的数据</h3>
</div>
<div class="data-selection">
<!-- 项目选择 -->
<div class="project-select">
<a-select
v-model="selectedProject"
placeholder="请选择项目"
allow-clear
style="width: 300px"
>
<a-option
v-for="project in projectList"
:key="project.id"
:value="project.id"
>
{{ project.name }}
</a-option>
</a-select>
</div>
<!-- 文件列表 -->
<div class="file-list">
<a-table
:data="fileList"
:columns="fileColumns"
:row-selection="{ type: 'checkbox' }"
@select="handleFileSelect"
@select-all="handleFileSelectAll"
row-key="id"
:pagination="false"
:scroll="{ y: 400 }"
>
<template #fileName="{ record }">
<div class="file-item">
<a-checkbox :checked="selectedFiles.includes(record.id)" />
<span class="file-name">{{ record.fileName }}</span>
</div>
</template>
<template #fileType="{ record }">
<a-tag :color="getFileTypeColor(record.fileType)">
{{ record.fileType }}
</a-tag>
</template>
<template #fileSize="{ record }">
<span>{{ record.fileSize }}</span>
</template>
<template #uploadTime="{ record }">
<span>{{ record.uploadTime }}</span>
</template>
</a-table>
</div>
</div>
<div class="step-actions">
<a-button
type="primary"
@click="nextStep"
:disabled="selectedFiles.length === 0"
>
下一步
</a-button>
</div>
</div>
<!-- 第二步预处理设置 -->
<div v-if="currentStep === 1" class="step-panel">
<div class="step-header">
<h3>预处理设置</h3>
</div>
<div class="preprocessing-settings">
<!-- 图像处理选项 -->
<div class="setting-group">
<h4>图像处理</h4>
<div class="setting-options">
<a-checkbox v-model="settings.image.denoise">去噪</a-checkbox>
<a-checkbox v-model="settings.image.enhance">增强</a-checkbox>
<a-checkbox v-model="settings.image.crop">裁剪</a-checkbox>
<a-checkbox v-model="settings.image.rotate">旋转校正</a-checkbox>
</div>
</div>
<!-- 视频处理选项 -->
<div class="setting-group">
<h4>视频处理</h4>
<div class="setting-options">
<a-checkbox v-model="settings.video.keyFrameExtraction">关键帧提取</a-checkbox>
<a-checkbox v-model="settings.video.stabilization">稳定化</a-checkbox>
<a-checkbox v-model="settings.video.split">分辨率调整</a-checkbox>
</div>
</div>
<!-- 输出格式设置 -->
<div class="setting-group">
<h4>输出格式</h4>
<a-form-item label="输出格式">
<a-select v-model="settings.output.format" style="width: 200px">
<a-option value="JPG">JPG</a-option>
<a-option value="PNG">PNG</a-option>
<a-option value="TIFF">TIFF</a-option>
<a-option value="MP4">MP4</a-option>
</a-select>
</a-form-item>
<a-form-item label="输出目录">
<a-input v-model="settings.output.directory" style="width: 300px" />
</a-form-item>
</div>
</div>
<div class="step-actions">
<a-button @click="prevStep">上一步</a-button>
<a-button type="primary" @click="nextStep">下一步</a-button>
</div>
</div>
<!-- 第三步执行预处理 -->
<div v-if="currentStep === 2" class="step-panel">
<div class="step-header">
<h3>执行预处理</h3>
</div>
<div class="processing-section">
<div class="processing-status">
<div class="status-text">
<span v-if="!isProcessing">准备预处理...</span>
<span v-else>正在处理中...</span>
</div>
<div class="progress-container">
<a-progress
:percent="processingProgress"
:status="isProcessing ? 'normal' : 'warning'"
/>
<span class="progress-text">{{ processingProgress }}%</span>
</div>
</div>
</div>
<div class="step-actions">
<a-button @click="prevStep" :disabled="isProcessing">上一步</a-button>
<a-button
v-if="!isProcessing"
type="primary"
@click="startProcessing"
>
开始预处理
</a-button>
<a-button
v-else
type="primary"
@click="nextStep"
:disabled="processingProgress < 100"
>
下一步
</a-button>
</div>
</div>
<!-- 第四步完成 -->
<div v-if="currentStep === 3" class="step-panel">
<div class="step-header">
<h3>完成</h3>
</div>
<div class="completion-section">
<div class="completion-icon">
<div class="success-icon">
<GiSvgIcon name="check-circle" size="48" />
</div>
</div>
<div class="completion-text">
<h4>预处理完成</h4>
<p>数据预处理已成功完成共处理了 {{ selectedFiles.length }} 个文件</p>
</div>
</div>
<div class="step-actions">
<a-button @click="viewResults">查看结果</a-button>
<a-button type="primary" @click="continueProcessing">继续处理</a-button>
</div>
</div>
</div>
</div>
</GiPageLayout>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { Message } from '@arco-design/web-vue'
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'
defineOptions({ name: 'DataPreprocessing' })
// 当前步骤
const currentStep = ref(0)
const isProcessing = ref(false)
const processingProgress = ref(0)
// 项目列表
const projectList = ref([
{ id: 1, name: 'A风场2023年检查' },
{ id: 2, name: 'B风场维修项目' },
{ id: 3, name: 'C风场建设项目' }
])
const selectedProject = ref<number>()
const selectedFiles = ref<number[]>([])
// 文件列表
const fileList = ref([
{
id: 1,
fileName: 'IMG_20231105_1430.jpg',
fileType: 'image',
fileSize: '3.2MB',
uploadTime: '2023-11-05 14:32'
},
{
id: 2,
fileName: 'VID_20231106_0915.mp4',
fileType: 'video',
fileSize: '45.6MB',
uploadTime: '2023-11-06 09:18'
}
])
// 文件表格列配置
const fileColumns: TableColumnData[] = [
{
title: '文件名',
dataIndex: 'fileName',
width: 300,
ellipsis: true,
tooltip: true
},
{
title: '类型',
dataIndex: 'fileType',
slotName: 'fileType',
width: 100,
align: 'center'
},
{
title: '大小',
dataIndex: 'fileSize',
slotName: 'fileSize',
width: 100,
align: 'center'
},
{
title: '上传时间',
dataIndex: 'uploadTime',
slotName: 'uploadTime',
width: 150,
align: 'center'
}
]
// 预处理设置
const settings = reactive({
image: {
denoise: false,
enhance: false,
crop: false,
rotate: false
},
video: {
keyFrameExtraction: false,
stabilization: false,
split: false
},
output: {
format: 'JPG',
directory: '/output/processed'
}
})
// 获取文件类型颜色
const getFileTypeColor = (type: string) => {
switch (type) {
case 'image':
return 'blue'
case 'video':
return 'green'
case 'audio':
return 'orange'
case 'document':
return 'purple'
default:
return 'gray'
}
}
// 文件选择处理
const handleFileSelect = (selectedRowKeys: number[]) => {
selectedFiles.value = selectedRowKeys
}
const handleFileSelectAll = (checked: boolean) => {
if (checked) {
selectedFiles.value = fileList.value.map(file => file.id)
} else {
selectedFiles.value = []
}
}
// 步骤导航
const nextStep = () => {
if (currentStep.value < 3) {
currentStep.value++
}
}
const prevStep = () => {
if (currentStep.value > 0) {
currentStep.value--
}
}
// 开始处理
const startProcessing = () => {
isProcessing.value = true
processingProgress.value = 0
// 模拟处理进度
const timer = setInterval(() => {
processingProgress.value += 10
if (processingProgress.value >= 100) {
clearInterval(timer)
isProcessing.value = false
Message.success('预处理完成!')
}
}, 500)
}
// 查看结果
const viewResults = () => {
Message.info('跳转到结果页面')
}
// 继续处理
const continueProcessing = () => {
currentStep.value = 0
selectedFiles.value = []
selectedProject.value = undefined
processingProgress.value = 0
isProcessing.value = false
Message.info('开始新的预处理任务')
}
onMounted(() => {
// 初始化数据
})
</script>
<style scoped lang="less">
.data-preprocessing-container {
padding: 20px;
}
.steps-container {
margin-bottom: 40px;
.preprocessing-steps {
max-width: 600px;
margin: 0 auto;
}
}
.step-content {
min-height: 500px;
}
.step-panel {
background: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.step-header {
margin-bottom: 24px;
border-bottom: 1px solid #e8e8e8;
padding-bottom: 16px;
h3 {
margin: 0;
color: #333;
font-size: 18px;
font-weight: 600;
}
}
.data-selection {
.project-select {
margin-bottom: 20px;
}
.file-list {
margin-bottom: 20px;
}
}
.file-item {
display: flex;
align-items: center;
gap: 8px;
.file-name {
color: #333;
}
}
.preprocessing-settings {
.setting-group {
margin-bottom: 32px;
h4 {
margin-bottom: 16px;
color: #333;
font-size: 16px;
font-weight: 600;
}
.setting-options {
display: flex;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 16px;
}
}
}
.processing-section {
text-align: center;
padding: 40px;
.processing-status {
.status-text {
font-size: 16px;
color: #666;
margin-bottom: 24px;
}
.progress-container {
display: flex;
align-items: center;
gap: 16px;
max-width: 400px;
margin: 0 auto;
.progress-text {
font-weight: 600;
color: #333;
}
}
}
}
.completion-section {
text-align: center;
padding: 40px;
.completion-icon {
margin-bottom: 24px;
.success-icon {
display: inline-block;
color: #52c41a;
}
}
.completion-text {
h4 {
margin-bottom: 12px;
color: #333;
font-size: 20px;
font-weight: 600;
}
p {
color: #666;
font-size: 14px;
}
}
}
.step-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 40px;
padding-top: 24px;
border-top: 1px solid #e8e8e8;
}
:deep(.arco-steps-item-title) {
font-size: 14px;
font-weight: 500;
}
:deep(.arco-table-cell) {
padding: 8px 16px;
}
:deep(.arco-form-item) {
margin-bottom: 16px;
}
:deep(.arco-form-item-label) {
font-weight: 500;
}
</style>