fetch(add): 新增
Some checks failed
构建并部署前端到测试环境 / build-and-deploy (push) Failing after 6s

This commit is contained in:
sexygoat
2026-01-27 09:18:45 +08:00
parent 0eed8244e5
commit 5c6312c407
33 changed files with 4897 additions and 374 deletions

View File

@@ -12,11 +12,12 @@
<template #title>
<div style="line-height: 1.8">
<p><strong>导入说明</strong></p>
<p>1. 请先下载模板文件按照模板格式填写设备信息</p>
<p>2. 支持 Excel 格式.xlsx, .xls单次最多导入 500 </p>
<p>3. 必填字段设备编号设备名称设备类型ICCID绑定网卡</p>
<p>4. ICCID 必须在系统中已存在否则导入失败</p>
<p>5. 设备编号重复将自动跳过</p>
<p>1. 请先下载 CSV 模板文件按照模板格式填写设备信息</p>
<p>2. 支持 CSV 格式.csv单次最多导入 1000 </p>
<p>3. CSV 文件编码UTF-8推荐 GBK</p>
<p>4. 必填字段device_no设备号device_name设备名称device_model设备型号</p>
<p>5. 可选字段device_type设备类型manufacturer制造商max_sim_slots最大插槽数默认1</p>
<p>6. 设备号重复将自动跳过导入后可在任务管理中查看详情</p>
</div>
</template>
</ElAlert>
@@ -31,18 +32,15 @@
<ElUpload
ref="uploadRef"
drag
:action="uploadUrl"
:on-change="handleFileChange"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:auto-upload="false"
:on-change="handleFileChange"
:limit="1"
accept=".xlsx,.xls"
accept=".csv"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__text"> CSV 文件拖到此处<em>点击选择</em></div>
<template #tip>
<div class="el-upload__tip">只能上传 xlsx/xls 文件且不超过 5MB</div>
<div class="el-upload__tip">只能上传 CSV 文件且不超过 10MB</div>
</template>
</ElUpload>
<div style="margin-top: 16px; text-align: center">
@@ -124,7 +122,7 @@
<ElOption label="完成" value="success" />
<ElOption label="失败" value="failed" />
</ElSelect>
<ElButton size="small" @click="refreshList">刷新</ElButton>
<ElButton @click="refreshList">刷新</ElButton>
</div>
</div>
</template>
@@ -239,6 +237,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import {
Download,
UploadFilled,
@@ -249,10 +248,14 @@
CircleCloseFilled,
TrendCharts
} from '@element-plus/icons-vue'
import type { UploadInstance, UploadRawFile } from 'element-plus'
import type { UploadInstance } from 'element-plus'
import { StorageService } from '@/api/modules/storage'
import { DeviceService } from '@/api/modules'
defineOptions({ name: 'DeviceImport' })
const router = useRouter()
interface FailReason {
row: number
deviceCode: string
@@ -276,8 +279,7 @@
}
const uploadRef = ref<UploadInstance>()
const uploadUrl = ref('/api/batch/device-import')
const fileList = ref<UploadRawFile[]>([])
const fileList = ref<File[]>([])
const uploading = ref(false)
const detailDialogVisible = ref(false)
const statusFilter = ref('')
@@ -366,8 +368,25 @@
}, 1000)
}
const handleFileChange = (file: any, files: any[]) => {
fileList.value = files
const handleFileChange = (uploadFile: any) => {
// 验证文件大小10MB限制
const maxSize = 10 * 1024 * 1024
if (uploadFile.raw && uploadFile.raw.size > maxSize) {
ElMessage.error('文件大小不能超过 10MB')
uploadRef.value?.clearFiles()
fileList.value = []
return
}
// 验证文件类型
if (uploadFile.raw && !uploadFile.raw.name.endsWith('.csv')) {
ElMessage.error('只能上传 CSV 文件')
uploadRef.value?.clearFiles()
fileList.value = []
return
}
fileList.value = uploadFile.raw ? [uploadFile.raw] : []
}
const clearFiles = () => {
@@ -375,56 +394,73 @@
fileList.value = []
}
/**
* 三步上传流程
* 1. 调用 StorageService.getUploadUrl() 获取预签名 URL 和 file_key
* 2. 调用 StorageService.uploadFile() 上传文件到对象存储
* 3. 调用 DeviceService.importDevices() 触发后端导入任务
*/
const submitUpload = async () => {
if (!fileList.value.length) {
ElMessage.warning('请先选择文件')
ElMessage.warning('请先选择CSV文件')
return
}
const file = fileList.value[0]
uploading.value = true
ElMessage.info('正在导入设备并绑定ICCID请稍候...')
// 模拟上传和导入过程
setTimeout(() => {
const newRecord: ImportRecord = {
id: Date.now().toString(),
batchNo: `DEV${new Date().getTime()}`,
fileName: fileList.value[0].name,
totalCount: 100,
successCount: 95,
failCount: 5,
bindCount: 95,
status: 'success',
progress: 100,
importTime: new Date().toLocaleString('zh-CN'),
operator: 'admin',
failReasons: [
{
row: 12,
deviceCode: 'TEST001',
iccid: '89860123456789012351',
message: 'ICCID 不存在'
},
{ row: 34, deviceCode: 'TEST002', iccid: '89860123456789012352', message: '设备类型无效' }
]
try {
// 第一步:获取预签名上传 URL
ElMessage.info('正在准备上传...')
const uploadUrlRes = await StorageService.getUploadUrl({
file_name: file.name,
content_type: 'text/csv',
purpose: 'iot_import'
})
if (uploadUrlRes.code !== 0) {
throw new Error(uploadUrlRes.msg || '获取上传地址失败')
}
importRecords.value.unshift(newRecord)
uploading.value = false
const { upload_url, file_key } = uploadUrlRes.data
// 第二步:上传文件到对象存储
ElMessage.info('正在上传文件...')
await StorageService.uploadFile(upload_url, file, 'text/csv')
// 第三步调用设备导入API
ElMessage.info('正在创建导入任务...')
const importRes = await DeviceService.importDevices({
file_key,
batch_no: `DEV-${Date.now()}`
})
if (importRes.code !== 0) {
throw new Error(importRes.msg || '创建导入任务失败')
}
const taskNo = importRes.data.task_no
// 清空文件列表
clearFiles()
ElMessage.success(
`导入完成!成功 ${newRecord.successCount} 条,失败 ${newRecord.failCount} 条,已绑定 ${newRecord.bindCount} 个ICCID`
)
}, 2000)
}
const handleUploadSuccess = () => {
ElMessage.success('上传成功')
}
// 显示成功消息并提供跳转链接
ElMessage.success({
message: `导入任务已创建!任务编号:${taskNo}`,
duration: 5000,
showClose: true
})
const handleUploadError = () => {
uploading.value = false
ElMessage.error('上传失败')
// 3秒后跳转到任务管理页面
setTimeout(() => {
router.push('/asset-management/task-management')
}, 3000)
} catch (error: any) {
console.error('设备导入失败:', error)
ElMessage.error(error.message || '设备导入失败')
} finally {
uploading.value = false
}
}
const refreshList = () => {