提交代码
This commit is contained in:
parent
d9a58838ad
commit
48fba692e7
|
|
@ -64,7 +64,9 @@
|
|||
style="width: 150px;"
|
||||
/>
|
||||
<!-- 显示标注进度 -->
|
||||
<span>({{ (scope.row.status1Count + scope.row.status2Count) + '/' + scope.row.totalCount }})</span>
|
||||
<span>({{
|
||||
(scope.row.status1Count + scope.row.status2Count) + '/' + scope.row.totalCount
|
||||
}})</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ export default {
|
|||
id: this.id,
|
||||
data: { image: this.fileUrl },
|
||||
};
|
||||
|
||||
if (this.annotations) {
|
||||
task.annotations = this.getAnnotations();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@
|
|||
<ul>
|
||||
<li v-for="(item, index) in images" :key="item.fileId" class="list-item">
|
||||
<div @click="setItem(item, index)">
|
||||
<input type="checkbox" :checked="item.fileAnnotationStatus!=='0'" disabled>
|
||||
<input type="checkbox" :checked="item.fileAnnotationStatus!=='0' && item.fileAnnotationStatus!=='3'"
|
||||
disabled
|
||||
>
|
||||
<span :class="{'highlighted': itemIndex === index}" style="font-size: 14px; margin-left: 5px;"
|
||||
>{{ item.fileName }}</span>
|
||||
</div>
|
||||
|
|
@ -105,7 +107,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
auditFailedReason: '',
|
||||
fileAnnotationStatus: '1',
|
||||
fileAnnotationStatus: '',
|
||||
itemIndex: 0,
|
||||
annotationResult: [],
|
||||
item: {},
|
||||
|
|
@ -150,9 +152,7 @@ export default {
|
|||
loadTaskList() {
|
||||
getMyNoAnnotatedTask().then(res => {
|
||||
this.taskList = res.data
|
||||
console.log(this.taskList)
|
||||
this.taskId = Number(this.$route.params && this.$route.params.taskId)
|
||||
console.log(this.taskId)
|
||||
this.selectTask(this.taskId)
|
||||
})
|
||||
},
|
||||
|
|
@ -207,7 +207,6 @@ export default {
|
|||
fetchImages() {
|
||||
if (!this.taskId) return
|
||||
getMyAnnotationFiles(this.annotationType, this.taskId).then(response => {
|
||||
console.log(response)
|
||||
this.itemIndex = 0
|
||||
this.images = response.data
|
||||
this.updateTaskData(this.images[this.itemIndex])
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
<template>
|
||||
<div class="label-studio-annotator">
|
||||
<div class="button-container">
|
||||
<el-button type="success" plain size="small" :disabled="this.annotations === null" @click="agreement(1)">通过</el-button>
|
||||
<el-button type="danger" plain size="small" :disabled="this.annotations === null" @click="showDisagreement()">不通过</el-button>
|
||||
<el-button type="success" plain size="small"
|
||||
:disabled="this.fileAnnotationStatus === '2' || this.annotations ===null" @click="agreement(1)"
|
||||
>
|
||||
通过
|
||||
</el-button>
|
||||
<el-button type="danger" plain size="small"
|
||||
:disabled="this.fileAnnotationStatus === '2' || this.annotations ===null"
|
||||
@click="showDisagreement()"
|
||||
>
|
||||
不通过
|
||||
</el-button>
|
||||
</div>
|
||||
<div id="label-studio" class="annotation-container"></div>
|
||||
|
||||
|
|
@ -10,9 +19,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import LabelStudio from 'label-studio';
|
||||
import '@/assets/styles/labelStudio.scss';
|
||||
import {agreement, manualAnnotate } from '../../../../api/dataCenter/annotationTask';
|
||||
import LabelStudio from 'label-studio'
|
||||
import '@/assets/styles/labelStudio.scss'
|
||||
import { agreement, manualAnnotate } from '../../../../api/dataCenter/annotationTask'
|
||||
|
||||
export default {
|
||||
name: 'LabelStudioAnnotator',
|
||||
|
|
@ -22,6 +31,7 @@ export default {
|
|||
config: { type: String, required: true },
|
||||
id: { type: Number, required: true },
|
||||
itemIndex: { type: Number, required: true },
|
||||
fileAnnotationStatus: { type: String, required: true },
|
||||
annotations: {
|
||||
type: Array,
|
||||
default: () => [] // 默认值为空数组
|
||||
|
|
@ -30,28 +40,29 @@ export default {
|
|||
computed: {
|
||||
index: {
|
||||
get() {
|
||||
return this.itemIndex;
|
||||
return this.itemIndex
|
||||
},
|
||||
set(value) {
|
||||
this.$parent.updateItemIndex(value); // 更新父组件的索引
|
||||
this.$parent.updateItemIndex(value, this.annotationStatus) // 更新父组件的索引
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
annotationStatus: '',
|
||||
labelStudio: null,
|
||||
annotationsList: [] ,
|
||||
annotationsList: [],
|
||||
disagreementReason: '' // 存储不同意的原因
|
||||
};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
fileUrl: 'resetLabelStudio' // 当文件地址变化时,重置LabelStudio
|
||||
},
|
||||
mounted() {
|
||||
this.initLabelStudio(); // 组件挂载完成后初始化LabelStudio
|
||||
this.initLabelStudio() // 组件挂载完成后初始化LabelStudio
|
||||
},
|
||||
methods: {
|
||||
showDisagreement(){
|
||||
showDisagreement() {
|
||||
this.$prompt('请输入驳回原因', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
|
|
@ -60,24 +71,24 @@ export default {
|
|||
inputPattern: /^.{0,200}$/, // 限制最多200字符
|
||||
inputErrorMessage: '描述不能超过200字符',
|
||||
beforeClose: (action, instance, done) => {
|
||||
if (action ==='confirm'){
|
||||
if (action === 'confirm') {
|
||||
// 验证输入框内容是否为空(必填)
|
||||
if (!instance.inputValue) {
|
||||
this.$message({
|
||||
type: 'error',
|
||||
message: '不通过原因不能为空'
|
||||
});
|
||||
return; // 阻止关闭弹框
|
||||
})
|
||||
return // 阻止关闭弹框
|
||||
}
|
||||
}
|
||||
done();
|
||||
done()
|
||||
}
|
||||
})
|
||||
.then(({ value }) => {
|
||||
this.sendDisagreement(value);
|
||||
this.sendDisagreement(value)
|
||||
})
|
||||
.catch(() => {
|
||||
});
|
||||
})
|
||||
},
|
||||
// 发送不同意原因到后台
|
||||
sendDisagreement(value) {
|
||||
|
|
@ -86,19 +97,20 @@ export default {
|
|||
fileId: Number(this.id),
|
||||
auditFailedReason: value
|
||||
}).then(response => {
|
||||
this.$modal.msgSuccess('已提交不通过原因');
|
||||
this.index++; // 更新索引
|
||||
this.$modal.msgSuccess('已提交不通过原因')
|
||||
this.annotationStatus = '3'
|
||||
this.index++ // 更新索引
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
// 处理返回的标注数据
|
||||
getAnnotations() {
|
||||
return [{
|
||||
result: this.annotations.map(annotation => ({
|
||||
type: "rectanglelabels",
|
||||
from_name: "label",
|
||||
to_name: "image",
|
||||
type: 'rectanglelabels',
|
||||
from_name: 'label',
|
||||
to_name: 'image',
|
||||
value: {
|
||||
rectanglelabels: [annotation.label],
|
||||
x: annotation.x,
|
||||
|
|
@ -107,41 +119,42 @@ export default {
|
|||
height: annotation.height
|
||||
}
|
||||
}))
|
||||
}];
|
||||
}]
|
||||
},
|
||||
//不同意
|
||||
disagreement(){
|
||||
disagreement() {
|
||||
|
||||
},
|
||||
//同意的接口调用后台
|
||||
agreement(){
|
||||
agreement() {
|
||||
agreement({
|
||||
taskId : Number(this.taskId),
|
||||
fileId : Number(this.id)
|
||||
taskId: Number(this.taskId),
|
||||
fileId: Number(this.id)
|
||||
}).then(response => {
|
||||
this.annotationStatus = '2'
|
||||
this.$modal.msgSuccess('已同意标注')
|
||||
this.index++; // 更新索引
|
||||
this.index++ // 更新索引
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
// 初始化 LabelStudio
|
||||
initLabelStudio() {
|
||||
this.cleanupLabelStudio(); // 清理之前的实例
|
||||
this.cleanupLabelStudio() // 清理之前的实例
|
||||
|
||||
const task = {
|
||||
id: this.id,
|
||||
data: { image: this.fileUrl },
|
||||
};
|
||||
data: { image: this.fileUrl }
|
||||
}
|
||||
if (this.annotations) {
|
||||
task.annotations = this.getAnnotations();
|
||||
task.annotations = this.getAnnotations()
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
const labelStudioElement = document.getElementById('label-studio');
|
||||
const labelStudioElement = document.getElementById('label-studio')
|
||||
if (!labelStudioElement) {
|
||||
console.error('Label Studio element not found');
|
||||
return;
|
||||
console.error('Label Studio element not found')
|
||||
return
|
||||
}
|
||||
|
||||
this.labelStudio = new LabelStudio('label-studio', {
|
||||
|
|
@ -151,50 +164,51 @@ export default {
|
|||
task,
|
||||
onLabelStudioLoad: (LS) => {
|
||||
if (!LS.annotationStore.selectedAnnotation) {
|
||||
const annotation = LS.annotationStore.addAnnotation({ userGenerate: true });
|
||||
LS.annotationStore.selectAnnotation(annotation.id);
|
||||
const annotation = LS.annotationStore.addAnnotation({ userGenerate: true })
|
||||
LS.annotationStore.selectAnnotation(annotation.id)
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
// 重置 LabelStudio
|
||||
resetLabelStudio() {
|
||||
this.cleanupLabelStudio();
|
||||
this.initLabelStudio(); // 重新初始化
|
||||
this.cleanupLabelStudio()
|
||||
this.initLabelStudio() // 重新初始化
|
||||
},
|
||||
// 清理 LabelStudio 实例
|
||||
cleanupLabelStudio() {
|
||||
if (this.labelStudio && this.labelStudio.destroy) {
|
||||
this.labelStudio.destroy();
|
||||
this.labelStudio.destroy()
|
||||
}
|
||||
const labelStudioElement = document.getElementById('label-studio');
|
||||
const labelStudioElement = document.getElementById('label-studio')
|
||||
if (labelStudioElement) {
|
||||
labelStudioElement.innerHTML = ''; // 清空容器
|
||||
labelStudioElement.innerHTML = '' // 清空容器
|
||||
}
|
||||
this.labelStudio = null; // 置空实例
|
||||
this.labelStudio = null // 置空实例
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.button-container {
|
||||
margin: 10px;
|
||||
}
|
||||
.label-studio-annotator{
|
||||
|
||||
.label-studio-annotator {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.annotation-container{
|
||||
.annotation-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
>div{
|
||||
> div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 5px;
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@
|
|||
</div>
|
||||
<div class="bottom-content-center">
|
||||
<div>
|
||||
<custom-label-studio :annotations="annotationResult" :taskId="taskId || 0" :item-index="itemIndex"
|
||||
<custom-label-studio :fileAnnotationStatus="fileAnnotationStatus" :annotations="annotationResult"
|
||||
:taskId="taskId || 0" :item-index="itemIndex"
|
||||
:config="labelConfig" :id="task.id" :file-url="task.data.image"
|
||||
@update-itemIndex="updateItemIndex"
|
||||
></custom-label-studio>
|
||||
|
|
@ -107,6 +108,7 @@ export default {
|
|||
return {
|
||||
itemIndex: 0,
|
||||
annotationResult: [],
|
||||
fileAnnotationStatus: '',
|
||||
item: {},
|
||||
taskList: [],
|
||||
task: {
|
||||
|
|
@ -147,9 +149,9 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
// 更新项的索引并切换任务数据
|
||||
updateItemIndex(val) {
|
||||
updateItemIndex(val, fileAnnotationStatus) {
|
||||
const item = this.images[val]
|
||||
this.images[val - 1].fileAnnotationStatus = '2'
|
||||
this.images[val - 1].fileAnnotationStatus = fileAnnotationStatus
|
||||
this.itemIndex = val
|
||||
this.updateTaskData(item)
|
||||
},
|
||||
|
|
@ -158,7 +160,7 @@ export default {
|
|||
loadTaskList() {
|
||||
getMyNoAnnotatedTask().then(res => {
|
||||
this.taskList = res.data
|
||||
this.taskId = Number(this.$route.params && this.$route.params.taskId);
|
||||
this.taskId = Number(this.$route.params && this.$route.params.taskId)
|
||||
this.selectTask(this.taskId)
|
||||
})
|
||||
},
|
||||
|
|
@ -201,6 +203,7 @@ export default {
|
|||
setItem(item, index) {
|
||||
this.annotationResult = JSON.parse(item.annotationResult)
|
||||
this.itemIndex = index
|
||||
|
||||
this.updateTaskData(item)
|
||||
},
|
||||
|
||||
|
|
@ -229,6 +232,7 @@ export default {
|
|||
this.task.data.image = `${url.minioUrl}${item.fileUrl}`
|
||||
this.task.id = item.fileId
|
||||
this.annotationResult = JSON.parse(item.annotationResult)
|
||||
this.fileAnnotationStatus = item.fileAnnotationStatus
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,9 @@ export default {
|
|||
};
|
||||
},
|
||||
methods: {
|
||||
uploadFileId(res){
|
||||
console.log("addDataSetDialog.vue",res)
|
||||
},
|
||||
// 数据提交
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
|
|
|
|||
|
|
@ -1,34 +1,40 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog title="导入" :visible.sync="isOpen" width="700px" append-to-body :modal="false" @close="cancel" :close-on-click-modal="false">
|
||||
<el-form ref="form" :model="form" :rules="importRules" label-width="100px">
|
||||
<el-form-item label="数据来源" prop="dataSource" >
|
||||
<el-radio-group v-model="form.dataSource">
|
||||
<el-dialog title="导入" :visible.sync="isOpen" width="700px" append-to-body :modal="false" @close="cancel"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form ref="form" :model="form" :rules="importRules" label-width="100px">
|
||||
<el-form-item label="数据来源" prop="dataSource">
|
||||
<el-radio-group v-model="form.dataSource" @change="handleDataSourceChange">
|
||||
<el-radio :label="0" border>系统选择</el-radio>
|
||||
<el-radio :label="1" border>本地上传</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="导入路径" prop="inputPath">
|
||||
<el-input placeholder="请选择导入路径" readonly :disabled="true" v-model="form.inputPath" class="input-with-select">
|
||||
<el-button slot="append" icon="el-icon-folder-opened" @click="selectFolder(0)"></el-button>
|
||||
<el-input placeholder="请选择导入路径" readonly :disabled="true" v-model="form.inputPath"
|
||||
class="input-with-select"
|
||||
>
|
||||
<el-button slot="append" icon="el-icon-folder-opened" @click="selectFolder(0)"></el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<div v-show="form.dataSource ===1">
|
||||
<el-form-item label="上传文件">
|
||||
<uploadFiles :disabled="form.inputId===0" :key="new Date().getTime()" :parent-id="form.inputId.toString()" :fileUrl="form.inputPath || ''"/>
|
||||
<uploadFiles @file-uploaded="uploadFileId" :disabled="form.inputId===0" :key="new Date().getTime()"
|
||||
:parent-id="form.inputId.toString()" :fileUrl="form.inputPath || ''"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="数据标注状态" prop="isAnnotated">
|
||||
<el-radio-group v-model="form.isAnnotated">
|
||||
<el-radio :label="0" border>未标注</el-radio>
|
||||
<el-radio :label="1" border>已标注</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="form.isAnnotated === 1">
|
||||
<div style="display: flex;flex-direction: column;">
|
||||
<span>文件存放方式满足YOLO格式</span>
|
||||
<img style="width: 50%" :src="ObjectDetection_YOLO" alt="Weibo">
|
||||
</div>
|
||||
</el-form-item>-->
|
||||
<!-- <el-form-item label="数据标注状态" prop="isAnnotated">
|
||||
<el-radio-group v-model="form.isAnnotated">
|
||||
<el-radio :label="0" border>未标注</el-radio>
|
||||
<el-radio :label="1" border>已标注</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="form.isAnnotated === 1">
|
||||
<div style="display: flex;flex-direction: column;">
|
||||
<span>文件存放方式满足YOLO格式</span>
|
||||
<img style="width: 50%" :src="ObjectDetection_YOLO" alt="Weibo">
|
||||
</div>
|
||||
</el-form-item>-->
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
|
|
@ -36,7 +42,9 @@
|
|||
<el-button @click="cancel">取 消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<selectFolderDialog :open="folderOpen" :folder-type="folderType" @dialog-cancel="handleCancel" @update-data ="updateData" />
|
||||
<selectFolderDialog :open="folderOpen" :folder-type="folderType" @dialog-cancel="handleCancel"
|
||||
@update-data="updateData"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
|
@ -48,20 +56,20 @@ import uploadFiles from '../../library/child/uploadFiles.vue'
|
|||
import { importData } from '@/api/dataCenter/dataSet'
|
||||
|
||||
export default {
|
||||
components: { uploadFiles, selectFolderDialog},
|
||||
components: { uploadFiles, selectFolderDialog },
|
||||
props: {
|
||||
open: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
default: false
|
||||
},
|
||||
dataType:{
|
||||
dataType: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
getList: {
|
||||
type: Function,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
datasetId: {
|
||||
type: String,
|
||||
|
|
@ -72,44 +80,59 @@ export default {
|
|||
computed: {
|
||||
isOpen: {
|
||||
get() {
|
||||
return this.open;
|
||||
return this.open
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('update:open', value);
|
||||
},
|
||||
},
|
||||
this.$emit('update:open', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isOpen(newVal, oldVal) {
|
||||
if (newVal) {
|
||||
this.fileIds = []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: this.dataType, // 创建一个本地副本
|
||||
ObjectDetection_YOLO:ObjectDetection_YOLO,
|
||||
ObjectDetection_YOLO: ObjectDetection_YOLO,
|
||||
folderOpen: false,
|
||||
folderType:0,
|
||||
folderType: 0,
|
||||
fileIds: [],
|
||||
form: {
|
||||
dataSource:0,
|
||||
inputId:0,
|
||||
inputPath:'',
|
||||
dataSource: 0,
|
||||
inputId: 0,
|
||||
inputPath: ''
|
||||
}, // 初始化为空
|
||||
importRules:{
|
||||
dataSource:[
|
||||
{ required: true, message: '数据来源不能为空', trigger: 'blur' },
|
||||
importRules: {
|
||||
dataSource: [
|
||||
{ required: true, message: '数据来源不能为空', trigger: 'blur' }
|
||||
],
|
||||
inputPath:[
|
||||
{ required: true, message: '导入路径不能为空', trigger: 'blur' },
|
||||
inputPath: [
|
||||
{ required: true, message: '导入路径不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleDataSourceChange() {
|
||||
this.fileIds = []
|
||||
},
|
||||
uploadFileId(res) {
|
||||
this.fileIds.push(res.fileId)
|
||||
},
|
||||
// 数据提交
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
this.$refs['form'].validate(valid => {
|
||||
if (valid) {
|
||||
this.form.datasetId = this.datasetId
|
||||
this.form.dataType = this.dataType
|
||||
this.form.fileIds = this.fileIds
|
||||
importData(this.form).then(response => {
|
||||
this.$modal.msgSuccess("导入成功");
|
||||
this.cancel();
|
||||
this.$modal.msgSuccess('导入成功')
|
||||
this.cancel()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
@ -117,37 +140,37 @@ export default {
|
|||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.getList();
|
||||
this.isOpen = false;
|
||||
this.reset();
|
||||
this.$emit('dialog-cancel'); // 通知父组件
|
||||
this.getList()
|
||||
this.isOpen = false
|
||||
this.reset()
|
||||
this.$emit('dialog-cancel') // 通知父组件
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
dataSource:0,
|
||||
inputId:0,
|
||||
outputId:0
|
||||
}; // 清空表单
|
||||
this.$refs.form.resetFields(); // 调用 Element UI 的重置方法
|
||||
dataSource: 0,
|
||||
inputId: 0,
|
||||
outputId: 0
|
||||
} // 清空表单
|
||||
this.$refs.form.resetFields() // 调用 Element UI 的重置方法
|
||||
},
|
||||
//选择文件夹
|
||||
selectFolder(folderType){
|
||||
this.folderType = folderType;
|
||||
this.folderOpen = true;
|
||||
selectFolder(folderType) {
|
||||
this.folderType = folderType
|
||||
this.folderOpen = true
|
||||
},
|
||||
handleCancel(){
|
||||
this.folderOpen = false;
|
||||
handleCancel() {
|
||||
this.folderOpen = false
|
||||
},
|
||||
updateData(data){
|
||||
updateData(data) {
|
||||
|
||||
if (data.folderType === 0) {
|
||||
this.form.inputPath = data.folder || ''; // 确保 inputPath 是非空字符串
|
||||
this.form.inputId = data.fileId || 0;
|
||||
this.form.inputPath = data.folder || '' // 确保 inputPath 是非空字符串
|
||||
this.form.inputId = data.fileId || 0
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
@ -156,7 +179,7 @@ export default {
|
|||
z-index: 2000 !important; /* Set a lower z-index for dialog */
|
||||
}
|
||||
|
||||
input[aria-hidden=true]{
|
||||
input[aria-hidden=true] {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getDetails, addDetails, updateDetails } from '@/api/dataCenter/evaluateDetails';
|
||||
import { getDetails, addDetails, updateDetails } from '@/api/dataCenter/evaluateDetails'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
|
@ -45,23 +45,16 @@ export default {
|
|||
computed: {
|
||||
isOpen: {
|
||||
get() {
|
||||
return this.open;
|
||||
return this.open
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('dialog-cancel');
|
||||
this.$emit('dialog-cancel')
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
justSqmple: null,
|
||||
loseSample: null,
|
||||
tpNum: null,
|
||||
tnNum: null,
|
||||
fpNum: null,
|
||||
fnNum: null
|
||||
},
|
||||
form: {},
|
||||
rules: {
|
||||
justSqmple: [
|
||||
{ required: true, message: '请输入正样本数', trigger: 'blur' },
|
||||
|
|
@ -73,59 +66,68 @@ export default {
|
|||
],
|
||||
tpNum: [
|
||||
{ required: true, message: '请输入TP数量', trigger: 'blur' },
|
||||
{ pattern: /^[1-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
|
||||
{ pattern: /^[0-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
|
||||
{ validator: this.validatePositiveSamples, trigger: 'blur' }
|
||||
],
|
||||
fnNum: [
|
||||
{ required: true, message: '请输入FN数量', trigger: 'blur' },
|
||||
{ pattern: /^[1-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
|
||||
{ pattern: /^[0-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
|
||||
{ validator: this.validatePositiveSamples, trigger: 'blur' }
|
||||
],
|
||||
tnNum: [
|
||||
{ required: true, message: '请输入TN数量', trigger: 'blur' },
|
||||
{ pattern: /^[1-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
|
||||
{ pattern: /^[0-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
|
||||
{ validator: this.validateNegativeSamples, trigger: 'blur' }
|
||||
],
|
||||
fpNum: [
|
||||
{ required: true, message: '请输入FP数量', trigger: 'blur' },
|
||||
{ pattern: /^[1-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
|
||||
{ pattern: /^[0-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
|
||||
{ validator: this.validateNegativeSamples, trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isOpen(newVal) {
|
||||
if (newVal && this.evaluateDetailId) {
|
||||
getDetails(this.evaluateDetailId).then((res) => {
|
||||
this.form = res.data;
|
||||
});
|
||||
this.form = res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
validatePositiveSamples(rule, value, callback) {
|
||||
const { tpNum, fnNum, justSqmple } = this.form;
|
||||
if (tpNum != null && fnNum != null && justSqmple != null) {
|
||||
if (tpNum + fnNum !== parseInt(justSqmple, 10)) {
|
||||
callback(new Error('TP和FN之和必须等于正样本数'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
console.log(this.form)
|
||||
const { tpNum, fnNum, justSqmple } = this.form
|
||||
|
||||
// 转换为数值类型,避免字符串拼接导致的问题
|
||||
const tp = Number(tpNum)
|
||||
const fn = Number(fnNum)
|
||||
const just = Number(justSqmple)
|
||||
|
||||
// 校验 TP + FN 是否等于正样本数
|
||||
if (tp + fn !== just) {
|
||||
callback(new Error('TP和FN之和必须等于正样本数'))
|
||||
} else {
|
||||
callback();
|
||||
callback()
|
||||
}
|
||||
},
|
||||
|
||||
validateNegativeSamples(rule, value, callback) {
|
||||
const { tnNum, fpNum, loseSample } = this.form;
|
||||
if (tnNum != null && fpNum != null && loseSample != null) {
|
||||
if (tnNum + fpNum !== parseInt(loseSample, 10)) {
|
||||
callback(new Error('FP和TN之和必须等于负样本数'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
console.log(this.form)
|
||||
const { tnNum, fpNum, loseSample } = this.form
|
||||
|
||||
// 转换为数值类型
|
||||
const tn = Number(tnNum)
|
||||
const fp = Number(fpNum)
|
||||
const lose = Number(loseSample)
|
||||
|
||||
// 校验 TN + FP 是否等于负样本数
|
||||
if (tn + fp !== lose) {
|
||||
callback(new Error('FP和TN之和必须等于负样本数'))
|
||||
} else {
|
||||
callback();
|
||||
callback()
|
||||
}
|
||||
},
|
||||
/** 提交按钮 */
|
||||
|
|
@ -134,30 +136,30 @@ export default {
|
|||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
updateDetails(this.form).then((res) => {
|
||||
this.$modal.msgSuccess('修改成功');
|
||||
this.isOpen = false;
|
||||
this.getList();
|
||||
});
|
||||
this.$modal.msgSuccess('修改成功')
|
||||
this.isOpen = false
|
||||
this.getList()
|
||||
})
|
||||
} else {
|
||||
this.form.evaluateId = this.evaluateId;
|
||||
this.form.evaluateId = this.evaluateId
|
||||
addDetails(this.form).then((response) => {
|
||||
this.$modal.msgSuccess('新增成功');
|
||||
this.isOpen = false;
|
||||
this.getList();
|
||||
});
|
||||
this.$modal.msgSuccess('新增成功')
|
||||
this.isOpen = false
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
cancel() {
|
||||
this.isOpen = false;
|
||||
this.resetForm();
|
||||
this.isOpen = false
|
||||
this.resetForm()
|
||||
},
|
||||
resetForm() {
|
||||
this.form = {};
|
||||
this.form = {}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ export default {
|
|||
formData.append('fileUrl', this.fileUrl)
|
||||
|
||||
uploadFiles(formData)
|
||||
.then(() => {
|
||||
.then(res => {
|
||||
currentChunk++
|
||||
const progress = Math.floor((currentChunk / totalChunks) * 100)
|
||||
this.$set(this.uploadsNum, file.name, progress)
|
||||
|
|
@ -163,11 +163,17 @@ export default {
|
|||
if (currentChunk < totalChunks) {
|
||||
uploadNextChunk()
|
||||
} else {
|
||||
console.log(res)
|
||||
console.log(this.$parent)
|
||||
// 通过 $emit 触发父组件方法
|
||||
this.$emit('file-uploaded', res.data);
|
||||
console.log(res)
|
||||
this.startNextUpload()
|
||||
this.checkAllUploadsComplete()
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
.catch(reason => {
|
||||
console.log(reason)
|
||||
this.$set(this.uploadFailed, file.name, true)
|
||||
this.startNextUpload()
|
||||
})
|
||||
|
|
@ -187,7 +193,6 @@ export default {
|
|||
// 启动队列中的下一个文件上传(控制并发)
|
||||
startNextUpload() {
|
||||
if (!this.drawer) return // 如果停止上传,则不启动新任务
|
||||
|
||||
Object.keys(this.uploadsNum).forEach((fileName) => {
|
||||
if (this.uploadsNum[fileName] === 100) {
|
||||
delete this.uploadsNum[fileName]
|
||||
|
|
|
|||
|
|
@ -339,6 +339,9 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
uploadFileId(res){
|
||||
console.log("file.vue",res)
|
||||
},
|
||||
/** 转换菜单数据结构 */
|
||||
normalizer(node) {
|
||||
if (node.children && !node.children.length) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue