Industrial-image-management.../src/views/operation-platform/data-processing/data-storage/index.vue

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

<template>
<GiPageLayout>
<!-- 页面标题 -->
<div class="page-header">
<h2 class="page-title">数据入库 - 1号机组叶片A型检查</h2>
</div>
<!-- 选项卡区域 -->
<div class="tabs-section">
<a-tabs v-model:active-key="activeTab" type="line">
<a-tab-pane key="image" tab="图片" title="图片">
<div class="tab-content">
<!-- 文件上传区域 -->
<div class="upload-section">
<a-upload
:custom-request="customUpload"
:show-file-list="false"
multiple
:accept="getAcceptType()"
@change="handleFileChange"
drag
class="upload-dragger"
>
<div class="upload-content">
<div class="upload-icon">
<icon-upload :size="48" />
</div>
<div class="upload-text">
<p class="primary-text">将文件拖拽到此处<span class="link-text">点击上传</span></p>
<p class="secondary-text">支持上传任意不超过100MB格式文件</p>
</div>
</div>
</a-upload>
</div>
<!-- 操作按钮区域 -->
<div class="action-buttons">
<a-button
type="primary"
@click="startUpload"
:loading="uploading"
:disabled="uploadQueue.length === 0"
>
开始上传
</a-button>
<a-button @click="clearFiles">清空文件</a-button>
<a-button @click="batchImport">批量导入...</a-button>
</div>
<!-- 已上传数据列表 -->
<div class="uploaded-files-section">
<h3 class="section-title">已上传数据</h3>
<a-table
:columns="fileColumns"
:data="uploadedFiles"
:pagination="false"
:scroll="{ x: '100%' }"
>
<!-- 文件类型 -->
<template #type="{ record }">
<a-tag :color="getFileTypeColor(record.type)" size="small">
{{ record.type }}
</a-tag>
</template>
<!-- 文件大小 -->
<template #size="{ record }">
<span>{{ formatFileSize(record.size) }}</span>
</template>
<!-- 状态 -->
<template #status="{ record }">
<a-tag :color="getStatusColor(record.status)" size="small">
{{ record.status }}
</a-tag>
</template>
<!-- 操作 -->
<template #action="{ record }">
<a-space>
<a-button size="small" @click="previewFile(record)">预览</a-button>
<a-button size="small" status="danger" @click="deleteFile(record)">删除</a-button>
</a-space>
</template>
</a-table>
</div>
</div>
</a-tab-pane>
<a-tab-pane key="video" tab="视频" title="视频">
<div class="tab-content">
<a-empty description="视频上传功能开发中..." />
</div>
</a-tab-pane>
<a-tab-pane key="audio" tab="语音" title="语音">
<div class="tab-content">
<a-empty description="语音上传功能开发中..." />
</div>
</a-tab-pane>
<a-tab-pane key="document" tab="文档" title="文档">
<div class="tab-content">
<a-empty description="文档上传功能开发中..." />
</div>
</a-tab-pane>
<a-tab-pane key="other" tab="其他" title="其他">
<div class="tab-content">
<a-empty description="其他文件上传功能开发中..." />
</div>
</a-tab-pane>
</a-tabs>
</div>
<!-- 文件预览模态框 -->
<a-modal
v-model:visible="previewModalVisible"
title="文件预览"
:width="800"
:footer="false"
>
<div class="preview-container">
<div v-if="previewFileData && previewFileData.type === 'image'" class="image-preview">
<img :src="previewFileData.url" :alt="previewFileData.name" style="max-width: 100%; height: auto;" />
</div>
<div v-else-if="previewFileData && previewFileData.type === 'video'" class="video-preview">
<video :src="previewFileData.url" controls style="max-width: 100%; height: auto;" />
</div>
<div v-else class="file-info">
<p>文件名:{{ previewFileData?.name }}</p>
<p>文件类型:{{ previewFileData?.type }}</p>
<p>文件大小:{{ formatFileSize(previewFileData?.size) }}</p>
</div>
</div>
</a-modal>
</GiPageLayout>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'
import { Message } from '@arco-design/web-vue'
import type { TableColumnData } from '@arco-design/web-vue'
import { IconUpload } from '@arco-design/web-vue/es/icon'
// 活动选项卡
const activeTab = ref('image')
// 上传状态
const uploading = ref(false)
const uploadQueue = ref<any[]>([])
// 预览模态框
const previewModalVisible = ref(false)
const previewFileData = ref<any>(null)
// 已上传文件列表
const uploadedFiles = ref([
{
id: 1,
name: 'IMG_20231105_1430.jpg',
type: 'image',
size: 3355443, // 3.2MB
uploadTime: '2023-11-05 14:32',
status: '成功',
url: '/api/files/IMG_20231105_1430.jpg'
},
{
id: 2,
name: 'VID_20231106_0915.mp4',
type: 'video',
size: 47185920, // 45.6MB
uploadTime: '2023-11-06 09:18',
status: '成功',
url: '/api/files/VID_20231106_0915.mp4'
},
{
id: 3,
name: 'IMG_20231107_1645.jpg',
type: 'image',
size: 2936013, // 2.8MB
uploadTime: '2023-11-07 16:48',
status: '成功',
url: '/api/files/IMG_20231107_1645.jpg'
}
])
// 文件表格列配置
const fileColumns: TableColumnData[] = [
{ title: '文件名', dataIndex: 'name', width: 250 },
{ title: '类型', dataIndex: 'type', slotName: 'type', width: 100 },
{ title: '大小', dataIndex: 'size', slotName: 'size', width: 100 },
{ title: '上传时间', dataIndex: 'uploadTime', width: 150 },
{ title: '状态', dataIndex: 'status', slotName: 'status', width: 100 },
{ title: '操作', slotName: 'action', width: 150, fixed: 'right' }
]
// 根据选项卡获取接受的文件类型
const getAcceptType = () => {
const typeMap: Record<string, string> = {
'image': 'image/*',
'video': 'video/*',
'audio': 'audio/*',
'document': '.pdf,.doc,.docx,.txt,.xls,.xlsx,.ppt,.pptx',
'other': '*'
}
return typeMap[activeTab.value] || '*'
}
// 获取文件类型颜色
const getFileTypeColor = (type: string) => {
const colorMap: Record<string, string> = {
'image': 'blue',
'video': 'green',
'audio': 'orange',
'document': 'purple',
'other': 'gray'
}
return colorMap[type] || 'gray'
}
// 获取状态颜色
const getStatusColor = (status: string) => {
const colorMap: Record<string, string> = {
'成功': 'green',
'失败': 'red',
'上传中': 'blue',
'等待': 'orange'
}
return colorMap[status] || 'gray'
}
// 格式化文件大小
const formatFileSize = (bytes: number) => {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + sizes[i]
}
// 自定义上传请求
const customUpload = (option: any) => {
const { file } = option
// 检查文件大小
if (file.size > 100 * 1024 * 1024) {
Message.error('文件大小不能超过100MB')
return
}
// 添加到上传队列
uploadQueue.value.push({
file,
name: file.name,
size: file.size,
type: getFileType(file.name),
status: '等待'
})
Message.success(`文件 ${file.name} 已添加到上传队列`)
}
// 获取文件类型
const getFileType = (fileName: string) => {
const extension = fileName.split('.').pop()?.toLowerCase()
if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(extension || '')) {
return 'image'
} else if (['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'].includes(extension || '')) {
return 'video'
} else if (['mp3', 'wav', 'ogg', 'flac', 'aac'].includes(extension || '')) {
return 'audio'
} else if (['pdf', 'doc', 'docx', 'txt', 'xls', 'xlsx', 'ppt', 'pptx'].includes(extension || '')) {
return 'document'
} else {
return 'other'
}
}
// 处理文件变化
const handleFileChange = (fileList: any[]) => {
// 文件选择处理逻辑
}
// 开始上传
const startUpload = async () => {
if (uploadQueue.value.length === 0) {
Message.warning('请先选择要上传的文件')
return
}
uploading.value = true
try {
// 模拟上传过程
for (let i = 0; i < uploadQueue.value.length; i++) {
const queueItem = uploadQueue.value[i]
queueItem.status = '上传中'
// 模拟上传延迟
await new Promise(resolve => setTimeout(resolve, 1000))
// 添加到已上传列表
uploadedFiles.value.push({
id: Date.now() + i,
name: queueItem.name,
type: queueItem.type,
size: queueItem.size,
uploadTime: new Date().toLocaleString(),
status: '成功',
url: `/api/files/${queueItem.name}`
})
}
uploadQueue.value = []
Message.success('所有文件上传完成')
} catch (error) {
Message.error('上传失败,请重试')
} finally {
uploading.value = false
}
}
// 清空文件
const clearFiles = () => {
uploadQueue.value = []
Message.success('已清空文件队列')
}
// 批量导入
const batchImport = () => {
Message.info('批量导入功能开发中...')
}
// 预览文件
const previewFile = (file: any) => {
previewFileData.value = file
previewModalVisible.value = true
}
// 删除文件
const deleteFile = (file: any) => {
const index = uploadedFiles.value.findIndex(f => f.id === file.id)
if (index > -1) {
uploadedFiles.value.splice(index, 1)
Message.success('文件已删除')
}
}
</script>
<style scoped lang="less">
.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;
}
.upload-section {
margin-bottom: 16px;
.upload-dragger {
:deep(.arco-upload-drag) {
border: 2px dashed #d9d9d9;
border-radius: 8px;
background: #fafafa;
padding: 40px;
text-align: center;
transition: all 0.3s ease;
&:hover {
border-color: #1890ff;
background: #f0f7ff;
}
}
}
.upload-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
.upload-icon {
color: #bfbfbf;
font-size: 48px;
}
.upload-text {
.primary-text {
font-size: 16px;
color: #595959;
margin: 0 0 8px 0;
.link-text {
color: #1890ff;
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}
.secondary-text {
font-size: 14px;
color: #8c8c8c;
margin: 0;
}
}
}
}
.action-buttons {
display: flex;
gap: 12px;
margin-bottom: 24px;
}
.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>