bonus-ui/src/views/dataCenter/mirror/child/customDialog.vue

284 lines
11 KiB
Vue
Raw Normal View History

2024-12-11 18:37:05 +08:00
<template>
<div>
2024-12-15 17:33:04 +08:00
<el-dialog :title="title" :visible.sync="isOpen" width="500px" append-to-body @close="cancel"
:close-on-click-modal="false"
>
2024-12-11 18:37:05 +08:00
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="镜像名称" prop="mirrorName">
2024-12-15 17:33:04 +08:00
<el-input v-model="form.mirrorName" maxlength="100" placeholder="请输入镜像名称"/>
</el-form-item>
<el-form-item label="镜像版本" prop="mirrorVersion">
<el-input v-model="form.mirrorVersion" placeholder="请输入镜像名称"/>
2024-12-11 18:37:05 +08:00
</el-form-item>
<el-form-item label="所属模型" prop="ownModel">
2024-12-15 17:33:04 +08:00
<el-select v-model="form.ownModel" placeholder="请选择所属模型" clearable style="width: 100%">
<el-option v-for="dict in modelList" :key="dict.id" :label="dict.modelName +' - '+dict.modelVersion"
:value="dict.id"
/>
</el-select>
2024-12-11 18:37:05 +08:00
</el-form-item>
<el-form-item label="运行环境" prop="runEnvironment">
2024-12-15 17:33:04 +08:00
<el-select v-model="form.runEnvironment" placeholder="请选择运行环境" clearable style="width: 100%">
<el-option v-for="dict in runEnvironmentList" :key="dict.value" :label="dict.label"
:value="dict.value"
/>
</el-select>
2024-12-11 18:37:05 +08:00
</el-form-item>
<el-form-item label="模型框架" prop="modelFrame">
2024-12-15 17:33:04 +08:00
<el-select v-model="form.modelFrame" placeholder="请选择模型框架" clearable style="width: 100%">
<el-option v-for="dict in dict.type.ai_frame_type" :key="dict.value" :label="dict.label"
:value="dict.value"
/>
</el-select>
2024-12-11 18:37:05 +08:00
</el-form-item>
<el-form-item label="语言" prop="language">
2024-12-15 17:33:04 +08:00
<el-select v-model="form.language" placeholder="请选择语言" clearable style="width: 100%">
<el-option v-for="dict in languageList" :key="dict.value" :label="dict.label"
:value="dict.value"
/>
</el-select>
2024-12-11 18:37:05 +08:00
</el-form-item>
2024-12-15 17:33:04 +08:00
<el-form-item label="镜像文件" prop="modelFileName">
<div class="custom-upload">
<input type="file" ref="modelInput" style="display: none" @change="handleFileChange('modelFile', $event)"
accept=".zip"
/>
<el-button size="mini" type="text" v-if="!form.modelFileName" @click="triggerFileInput('modelInput')">选择文件
</el-button>
<span style="cursor: pointer;" @click="triggerFileInput('modelInput')" v-if="form.modelFileName"
>{{ form.modelFileName }}</span>
<el-progress v-if="uploading" :percentage="uploadProgress.modelFile"/>
</div>
2024-12-11 18:37:05 +08:00
</el-form-item>
2024-12-15 17:33:04 +08:00
<el-form-item label="接口文档" prop="manualFileName">
<div class="custom-upload">
<input type="file" ref="manualInput" style="display: none"
@change="handleFileChange('manualFile', $event)" accept=".doc,.docx,.pdf"
/>
<el-button size="mini" type="text" v-if="!form.manualFileName" @click="triggerFileInput('manualInput')">
选择文件
</el-button>
<span style="cursor: pointer;" @click="triggerFileInput('manualInput')" v-if="form.manualFileName"
>{{ form.manualFileName }}<i></i></span>
<el-progress v-if="uploading" :percentage="uploadProgress.manualFile"/>
</div>
2024-12-11 18:37:05 +08:00
</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>
2024-12-15 17:33:04 +08:00
import { getManager, addManager, updateManager, uploadFile, listAll } from '@/api/dataCenter/mirror'
2024-12-11 18:37:05 +08:00
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 {
2024-12-15 17:33:04 +08:00
runEnvironmentList: [{
value: '0',
label: 'CPU'
},
{
value: '1',
label: 'GPU'
}],
languageList: [
{ 'value': '0', 'label': 'Java' },
{ 'value': '1', 'label': 'Python' },
{ 'value': '2', 'label': 'JavaScript (Node.js)' },
{ 'value': '3', 'label': 'PHP' },
{ 'value': '4', 'label': 'C# (.NET)' },
{ 'value': '5', 'label': 'Ruby' },
{ 'value': '6', 'label': 'Go (Golang)' },
{ 'value': '7', 'label': 'C/C++' },
{ 'value': '8', 'label': 'Kotlin' },
{ 'value': '9', 'label': 'Rust' },
{ 'value': '10', 'label': 'Scala' },
{ 'value': '11', 'label': 'Perl' },
{ 'value': '12', 'label': 'Swift' },
{ 'value': '13', 'label': 'Elixir' }
],
modelList: [],
2024-12-11 18:37:05 +08:00
uploadProgress: { modelFile: 0, manualFile: 0 },
uploading: false,
chunkSize: 1024 * 1024 * 20, // 20MB
form: { modelFile: null, manualFile: null, modelFileName: '', manualFileName: '' },
rules: {
2024-12-15 17:33:04 +08:00
mirrorName: [{ required: true, message: '镜像名称不能为空', trigger: 'blur' }],
mirrorVersion: [{
2024-12-11 18:37:05 +08:00
required: true,
message: '版本号不能为空',
trigger: 'blur'
}, { pattern: /^V\d{1,3}(\.\d{1,3}){2}$/, message: '版本名称式不正确,应为 VX.Y.Z 格式', trigger: 'blur' }],
2024-12-15 17:33:04 +08:00
runEnvironment: [{ required: true, message: '请选择运行环境', trigger: 'blur' }],
language: [{ required: true, message: '请选择语言', trigger: 'blur' }],
2024-12-11 18:37:05 +08:00
modelFrame: [{ required: true, message: '请选择模型框架', trigger: 'blur' }],
2024-12-15 17:33:04 +08:00
modelFileName: [{ required: true, message: '请上传镜像文件', trigger: 'blur' }],
manualFileName: [{ required: true, message: '请上传接口文档', trigger: 'blur' }]
2024-12-11 18:37:05 +08:00
},
currentUpload: { modelFile: null, manualFile: null } // 为每个文件设置独立的上传任务
}
},
watch: {
isOpen(newVal) {
if (newVal) {
2024-12-15 17:33:04 +08:00
console.log(this.mirrorId)
2024-12-11 18:37:05 +08:00
if (this.mirrorId) {
getManager(this.mirrorId).then(response => {
this.form = response.data
})
2024-12-15 17:33:04 +08:00
listAll().then(response => {
this.modelList = response.data
})
2024-12-11 18:37:05 +08:00
}
}
}
},
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') {
2024-12-15 17:33:04 +08:00
this.form.mirrorPath = res.data.fileUrl
2024-12-11 18:37:05 +08:00
}
if (field === 'manualFile') {
2024-12-15 17:33:04 +08:00
this.form.documentPath = res.data.fileUrl
2024-12-11 18:37:05 +08:00
}
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>