230 lines
8.7 KiB
Vue
230 lines
8.7 KiB
Vue
|
|
<template>
|
||
|
|
<div>
|
||
|
|
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||
|
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||
|
|
<el-form-item label="镜像名称" prop="mirrorName">
|
||
|
|
<el-input v-model="form.mirrorName" placeholder="请输入镜像名称"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="所属模型" prop="ownModel">
|
||
|
|
<el-input v-model="form.ownModel" placeholder="请输入所属模型"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="运行环境" prop="runEnvironment">
|
||
|
|
<el-input v-model="form.runEnvironment" type="textarea" placeholder="请输入内容"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="模型框架" prop="modelFrame">
|
||
|
|
<el-input v-model="form.modelFrame" placeholder="请输入模型框架"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="语言" prop="language">
|
||
|
|
<el-input v-model="form.language" placeholder="请输入语言"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="镜像文件path" prop="mirrorPath">
|
||
|
|
<el-input v-model="form.mirrorPath" placeholder="请输入镜像文件path"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="备注" prop="remark">
|
||
|
|
<el-input v-model="form.remark" placeholder="请输入备注"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="是否删除" prop="isActive">
|
||
|
|
<el-input v-model="form.isActive" placeholder="请输入是否删除"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="数据集id" prop="datasetId">
|
||
|
|
<el-input v-model="form.datasetId" placeholder="请输入数据集id"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="模型文件名" prop="modelFileName">
|
||
|
|
<el-input v-model="form.modelFileName" placeholder="请输入模型文件名"/>
|
||
|
|
</el-form-item>
|
||
|
|
<el-form-item label="使用手册文件名" prop="manualFileName">
|
||
|
|
<el-input v-model="form.manualFileName" placeholder="请输入使用手册文件名"/>
|
||
|
|
</el-form-item>
|
||
|
|
</el-form>
|
||
|
|
<div slot="footer" class="dialog-footer">
|
||
|
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||
|
|
<el-button @click="cancel">取 消</el-button>
|
||
|
|
</div>
|
||
|
|
</el-dialog>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
import { getManager, addManager, updateManager, uploadFile } from '@/api/dataCenter/model'
|
||
|
|
import { datasetList } from '@/api/dataCenter/dataSet'
|
||
|
|
import { generateUUID } from '../../../../utils/configure'
|
||
|
|
|
||
|
|
export default {
|
||
|
|
dicts: ['ai_annotate_type', 'ai_frame_type'],
|
||
|
|
props: {
|
||
|
|
open: { type: Boolean, required: true },
|
||
|
|
getList: { type: Function, required: true },
|
||
|
|
title: { type: String, required: true },
|
||
|
|
mirrorId: { type: [Number, null], default: 0 }
|
||
|
|
},
|
||
|
|
computed: {
|
||
|
|
isOpen: {
|
||
|
|
get() {
|
||
|
|
return this.open
|
||
|
|
},
|
||
|
|
set(value) {
|
||
|
|
this.$emit('dialog-cancel')
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
data() {
|
||
|
|
return {
|
||
|
|
datasetList: [],
|
||
|
|
uploadProgress: { modelFile: 0, manualFile: 0 },
|
||
|
|
uploading: false,
|
||
|
|
chunkSize: 1024 * 1024 * 20, // 20MB
|
||
|
|
form: { modelFile: null, manualFile: null, modelFileName: '', manualFileName: '' },
|
||
|
|
rules: {
|
||
|
|
modelName: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }],
|
||
|
|
modelVersion: [{
|
||
|
|
required: true,
|
||
|
|
message: '版本号不能为空',
|
||
|
|
trigger: 'blur'
|
||
|
|
}, { pattern: /^V\d{1,3}(\.\d{1,3}){2}$/, message: '版本名称式不正确,应为 VX.Y.Z 格式', trigger: 'blur' }],
|
||
|
|
modelType: [{ required: true, message: '请选择模型类型', trigger: 'blur' }],
|
||
|
|
modelFrame: [{ required: true, message: '请选择模型框架', trigger: 'blur' }],
|
||
|
|
modelFileName: [{ required: true, message: '请上传模型文件', trigger: 'blur' }],
|
||
|
|
manualFileName: [{ required: true, message: '请上传使用手册', trigger: 'blur' }]
|
||
|
|
},
|
||
|
|
currentUpload: { modelFile: null, manualFile: null } // 为每个文件设置独立的上传任务
|
||
|
|
}
|
||
|
|
},
|
||
|
|
watch: {
|
||
|
|
isOpen(newVal) {
|
||
|
|
if (newVal) {
|
||
|
|
datasetList({}).then(response => {
|
||
|
|
this.datasetList = response.data
|
||
|
|
})
|
||
|
|
if (this.mirrorId) {
|
||
|
|
getManager(this.mirrorId).then(response => {
|
||
|
|
this.form = response.data
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
methods: {
|
||
|
|
triggerFileInput(refName) {
|
||
|
|
this.$refs[refName].click()
|
||
|
|
},
|
||
|
|
handleFileChange(field, event) {
|
||
|
|
const file = event.target.files[0]
|
||
|
|
if (file) {
|
||
|
|
this.form[field] = file
|
||
|
|
this.form[`${field}Name`] = file.name
|
||
|
|
}
|
||
|
|
},
|
||
|
|
resetField(field) {
|
||
|
|
this.form[field] = null
|
||
|
|
this.form[`${field}Name`] = ''
|
||
|
|
this.$refs[field].value = '' // 重置文件选择
|
||
|
|
},
|
||
|
|
uploadChunks(file, field, uuid) {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
// 文件为空时直接返回
|
||
|
|
if (!file || file.size === 0) {
|
||
|
|
resolve()
|
||
|
|
}
|
||
|
|
const totalChunks = Math.ceil(file.size / this.chunkSize)
|
||
|
|
let currentChunk = 0
|
||
|
|
this.uploading = true // 标记正在上传
|
||
|
|
const controller = new AbortController() // 新增AbortController
|
||
|
|
const signal = controller.signal // 获取 signal 用于中止请求
|
||
|
|
|
||
|
|
const uploadNextChunk = () => {
|
||
|
|
if (this.uploading === false) { // 如果上传已经取消,退出
|
||
|
|
reject('Upload canceled')
|
||
|
|
return
|
||
|
|
}
|
||
|
|
const start = currentChunk * this.chunkSize
|
||
|
|
const end = Math.min(file.size, start + this.chunkSize)
|
||
|
|
const chunk = file.slice(start, end)
|
||
|
|
const formData = new FormData()
|
||
|
|
formData.append('file', chunk)
|
||
|
|
formData.append('fileName', uuid + `.${file.name.split('.').pop().toLowerCase()}`)
|
||
|
|
formData.append('chunk', currentChunk + 1)
|
||
|
|
formData.append('totalChunks', totalChunks)
|
||
|
|
uploadFile(formData, { signal }) // 在上传请求中传入 signal 用于中止
|
||
|
|
.then(res => {
|
||
|
|
currentChunk++
|
||
|
|
// 更新进度
|
||
|
|
this.uploadProgress[field] = Math.floor((currentChunk / totalChunks) * 100)
|
||
|
|
if (currentChunk < totalChunks) {
|
||
|
|
uploadNextChunk()
|
||
|
|
} else {
|
||
|
|
if (field === 'modelFile') {
|
||
|
|
this.form.modelPath = res.data.fileUrl
|
||
|
|
}
|
||
|
|
if (field === 'manualFile') {
|
||
|
|
this.form.modelManual = res.data.fileUrl
|
||
|
|
}
|
||
|
|
resolve() // 上传完成,返回成功
|
||
|
|
}
|
||
|
|
})
|
||
|
|
.catch(error => {
|
||
|
|
if (error.name === 'AbortError') {
|
||
|
|
console.log('Upload was aborted')
|
||
|
|
}
|
||
|
|
reject(error) // 上传失败,返回失败
|
||
|
|
this.$message.error('上传失败')
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
uploadNextChunk()
|
||
|
|
// 将当前上传任务保存到 currentUpload 中
|
||
|
|
this.currentUpload[field] = {
|
||
|
|
abort: () => controller.abort() // 提供 abort 方法来中止上传
|
||
|
|
}
|
||
|
|
|
||
|
|
return this.currentUpload[field] // 返回当前上传任务
|
||
|
|
})
|
||
|
|
},
|
||
|
|
submitForm() {
|
||
|
|
this.$refs.form.validate(valid => {
|
||
|
|
if (valid) {
|
||
|
|
// 上传文件后再调用新增或修改操作
|
||
|
|
// 独立上传每个文件,并确保只有所有文件上传成功后才提交表单
|
||
|
|
Promise.all([
|
||
|
|
this.uploadChunks(this.form.modelFile, 'modelFile', generateUUID()),
|
||
|
|
this.uploadChunks(this.form.manualFile, 'manualFile', generateUUID())
|
||
|
|
]).then(() => {
|
||
|
|
this.uploading = false
|
||
|
|
const action = this.form.id ? updateManager : addManager
|
||
|
|
action(this.form)
|
||
|
|
.then(() => {
|
||
|
|
this.$message.success(this.form.id ? '修改成功' : '新增成功')
|
||
|
|
this.cancel()
|
||
|
|
this.getList()
|
||
|
|
})
|
||
|
|
})
|
||
|
|
.catch(() => {
|
||
|
|
this.$message.error('文件上传失败,无法提交')
|
||
|
|
})
|
||
|
|
}
|
||
|
|
})
|
||
|
|
},
|
||
|
|
cancel() {
|
||
|
|
this.isOpen = false
|
||
|
|
this.uploading = false
|
||
|
|
// 取消当前文件的上传任务
|
||
|
|
if (this.currentUpload.modelFile && this.currentUpload.modelFile.abort) {
|
||
|
|
this.currentUpload.modelFile.abort()
|
||
|
|
}
|
||
|
|
if (this.currentUpload.manualFile && this.currentUpload.manualFile.abort) {
|
||
|
|
this.currentUpload.manualFile.abort()
|
||
|
|
}
|
||
|
|
this.resetForm()
|
||
|
|
},
|
||
|
|
resetForm() {
|
||
|
|
this.resetField('modelInput')
|
||
|
|
this.resetField('manualInput')
|
||
|
|
this.uploading = false
|
||
|
|
this.uploadProgress = { modelFile: 0, manualFile: 0 }
|
||
|
|
this.form = { modelFile: null, manualFile: null, modelFileName: '', manualFileName: '' }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped lang="scss"></style>
|