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> |