532 lines
13 KiB
Vue
532 lines
13 KiB
Vue
|
<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>
|