Merge remote-tracking branch 'origin/bonus-ai' into bonus-ai

This commit is contained in:
weiweiw 2024-12-31 13:20:30 +08:00
commit 64a72a4adb
15 changed files with 306 additions and 196 deletions

View File

@ -158,7 +158,7 @@ export const dynamicRoutes = [
path: 'index/:evaluateId(\\d+)', path: 'index/:evaluateId(\\d+)',
component: () => import('@/views/dataCenter/evaluate/child/evaluateDetails'), component: () => import('@/views/dataCenter/evaluate/child/evaluateDetails'),
name: 'Data', name: 'Data',
meta: { title: '模型评价详情', activeMenu: '/dataCenter/evaluateDetails' } meta: { title: '模型评价详情', activeMenu: '/dataCenter/evaluate/evaluateDetails' }
} }
] ]
}, },

View File

@ -64,7 +64,9 @@
style="width: 150px;" 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> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -76,14 +78,17 @@
<el-table-column label="操作" align="center" min-width="140" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" min-width="140" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
v-if="scope.row.annotatorIds.includes(getUserId)" v-if="scope.row.reviewerIds.split(',').map(Number).includes(getUserId)"
size="mini" size="mini"
type="text" type="text"
@click="handleExamine(scope.row)" @click="handleExamine(scope.row)"
v-hasPermi="['dataCenter:sample:edit']" v-hasPermi="['dataCenter:sample:edit']"
:disabled="scope.row.status1Count ===0"
>审核 >审核
</el-button> </el-button>
<el-button <el-button
v-if="scope.row.annotatorIds.split(',').map(Number).includes(getUserId)"
:disabled="scope.row.status0Count ===0"
size="mini" size="mini"
type="text" type="text"
@click="handleDimension(scope.row)" @click="handleDimension(scope.row)"
@ -91,7 +96,7 @@
>智能标注 >智能标注
</el-button> </el-button>
<el-button <el-button
v-if="scope.row.reviewerIds.includes(getUserId)" v-if="scope.row.annotatorIds.split(',').map(Number).includes(getUserId)"
size="mini" size="mini"
type="text" type="text"
@click="handleAnnotation(scope.row)" @click="handleAnnotation(scope.row)"
@ -104,6 +109,7 @@
type="text" type="text"
@click="handleRelease(scope.row)" @click="handleRelease(scope.row)"
v-hasPermi="['dataCenter:sample:edit']" v-hasPermi="['dataCenter:sample:edit']"
:disabled="scope.row.status2Count ===0"
>发布 >发布
</el-button> </el-button>
</template> </template>
@ -192,6 +198,8 @@ export default {
}, },
computed: { computed: {
getUserId() { getUserId() {
console.log('1,2'.split(',').includes(store.state.user.id + ''))
return store.state.user.id return store.state.user.id
} }
}, },
@ -254,7 +262,7 @@ export default {
}, },
getPercentage(row) { getPercentage(row) {
if (row.totalCount > 0 && row.status0Count >= 0) { if (row.totalCount > 0 && row.status0Count >= 0) {
let percentage = Math.floor((row.status1Count / row.totalCount) * 100) let percentage = Math.floor(((row.status1Count + row.status2Count) / row.totalCount) * 100)
// percentage 0 100 // percentage 0 100
return Math.min(Math.max(percentage, 0), 100) return Math.min(Math.max(percentage, 0), 100)
} }

View File

@ -72,7 +72,6 @@ export default {
id: this.id, id: this.id,
data: { image: this.fileUrl }, data: { image: this.fileUrl },
}; };
if (this.annotations) { if (this.annotations) {
task.annotations = this.getAnnotations(); task.annotations = this.getAnnotations();
} }

View File

@ -72,7 +72,9 @@
<ul> <ul>
<li v-for="(item, index) in images" :key="item.fileId" class="list-item"> <li v-for="(item, index) in images" :key="item.fileId" class="list-item">
<div @click="setItem(item, index)"> <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;" <span :class="{'highlighted': itemIndex === index}" style="font-size: 14px; margin-left: 5px;"
>{{ item.fileName }}</span> >{{ item.fileName }}</span>
</div> </div>
@ -105,7 +107,7 @@ export default {
data() { data() {
return { return {
auditFailedReason: '', auditFailedReason: '',
fileAnnotationStatus: '1', fileAnnotationStatus: '',
itemIndex: 0, itemIndex: 0,
annotationResult: [], annotationResult: [],
item: {}, item: {},
@ -205,7 +207,6 @@ export default {
fetchImages() { fetchImages() {
if (!this.taskId) return if (!this.taskId) return
getMyAnnotationFiles(this.annotationType, this.taskId).then(response => { getMyAnnotationFiles(this.annotationType, this.taskId).then(response => {
console.log(response)
this.itemIndex = 0 this.itemIndex = 0
this.images = response.data this.images = response.data
this.updateTaskData(this.images[this.itemIndex]) this.updateTaskData(this.images[this.itemIndex])

View File

@ -1,8 +1,17 @@
<template> <template>
<div class="label-studio-annotator"> <div class="label-studio-annotator">
<div class="button-container"> <div class="button-container">
<el-button type="success" plain size="small" :disabled="this.annotations === null" @click="agreement(1)">通过</el-button> <el-button type="success" plain size="small"
<el-button type="danger" plain size="small" :disabled="this.annotations === null" @click="showDisagreement()">不通过</el-button> :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>
<div id="label-studio" class="annotation-container"></div> <div id="label-studio" class="annotation-container"></div>
@ -10,9 +19,9 @@
</template> </template>
<script> <script>
import LabelStudio from 'label-studio'; import LabelStudio from 'label-studio'
import '@/assets/styles/labelStudio.scss'; import '@/assets/styles/labelStudio.scss'
import {agreement, manualAnnotate } from '../../../../api/dataCenter/annotationTask'; import { agreement, manualAnnotate } from '../../../../api/dataCenter/annotationTask'
export default { export default {
name: 'LabelStudioAnnotator', name: 'LabelStudioAnnotator',
@ -22,6 +31,7 @@ export default {
config: { type: String, required: true }, config: { type: String, required: true },
id: { type: Number, required: true }, id: { type: Number, required: true },
itemIndex: { type: Number, required: true }, itemIndex: { type: Number, required: true },
fileAnnotationStatus: { type: String, required: true },
annotations: { annotations: {
type: Array, type: Array,
default: () => [] // default: () => [] //
@ -30,28 +40,29 @@ export default {
computed: { computed: {
index: { index: {
get() { get() {
return this.itemIndex; return this.itemIndex
}, },
set(value) { set(value) {
this.$parent.updateItemIndex(value); // this.$parent.updateItemIndex(value, this.annotationStatus) //
} }
} }
}, },
data() { data() {
return { return {
annotationStatus: '',
labelStudio: null, labelStudio: null,
annotationsList: [] , annotationsList: [],
disagreementReason: '' // disagreementReason: '' //
}; }
}, },
watch: { watch: {
fileUrl: 'resetLabelStudio' // LabelStudio fileUrl: 'resetLabelStudio' // LabelStudio
}, },
mounted() { mounted() {
this.initLabelStudio(); // LabelStudio this.initLabelStudio() // LabelStudio
}, },
methods: { methods: {
showDisagreement(){ showDisagreement() {
this.$prompt('请输入驳回原因', { this.$prompt('请输入驳回原因', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
@ -60,24 +71,24 @@ export default {
inputPattern: /^.{0,200}$/, // 200 inputPattern: /^.{0,200}$/, // 200
inputErrorMessage: '描述不能超过200字符', inputErrorMessage: '描述不能超过200字符',
beforeClose: (action, instance, done) => { beforeClose: (action, instance, done) => {
if (action ==='confirm'){ if (action === 'confirm') {
// //
if (!instance.inputValue) { if (!instance.inputValue) {
this.$message({ this.$message({
type: 'error', type: 'error',
message: '不通过原因不能为空' message: '不通过原因不能为空'
}); })
return; // return //
} }
} }
done(); done()
} }
}) })
.then(({ value }) => { .then(({ value }) => {
this.sendDisagreement(value); this.sendDisagreement(value)
}) })
.catch(() => { .catch(() => {
}); })
}, },
// //
sendDisagreement(value) { sendDisagreement(value) {
@ -86,19 +97,20 @@ export default {
fileId: Number(this.id), fileId: Number(this.id),
auditFailedReason: value auditFailedReason: value
}).then(response => { }).then(response => {
this.$modal.msgSuccess('已提交不通过原因'); this.$modal.msgSuccess('已提交不通过原因')
this.index++; // this.annotationStatus = '3'
this.index++ //
}).catch(error => { }).catch(error => {
console.log(error); console.log(error)
}); })
}, },
// //
getAnnotations() { getAnnotations() {
return [{ return [{
result: this.annotations.map(annotation => ({ result: this.annotations.map(annotation => ({
type: "rectanglelabels", type: 'rectanglelabels',
from_name: "label", from_name: 'label',
to_name: "image", to_name: 'image',
value: { value: {
rectanglelabels: [annotation.label], rectanglelabels: [annotation.label],
x: annotation.x, x: annotation.x,
@ -107,41 +119,42 @@ export default {
height: annotation.height height: annotation.height
} }
})) }))
}]; }]
}, },
// //
disagreement(){ disagreement() {
}, },
// //
agreement(){ agreement() {
agreement({ agreement({
taskId : Number(this.taskId), taskId: Number(this.taskId),
fileId : Number(this.id) fileId: Number(this.id)
}).then(response => { }).then(response => {
this.annotationStatus = '2'
this.$modal.msgSuccess('已同意标注') this.$modal.msgSuccess('已同意标注')
this.index++; // this.index++ //
}).catch(error => { }).catch(error => {
console.log(error); console.log(error)
}); })
}, },
// LabelStudio // LabelStudio
initLabelStudio() { initLabelStudio() {
this.cleanupLabelStudio(); // this.cleanupLabelStudio() //
const task = { const task = {
id: this.id, id: this.id,
data: { image: this.fileUrl }, data: { image: this.fileUrl }
}; }
if (this.annotations) { if (this.annotations) {
task.annotations = this.getAnnotations(); task.annotations = this.getAnnotations()
} }
this.$nextTick(() => { this.$nextTick(() => {
const labelStudioElement = document.getElementById('label-studio'); const labelStudioElement = document.getElementById('label-studio')
if (!labelStudioElement) { if (!labelStudioElement) {
console.error('Label Studio element not found'); console.error('Label Studio element not found')
return; return
} }
this.labelStudio = new LabelStudio('label-studio', { this.labelStudio = new LabelStudio('label-studio', {
@ -151,50 +164,51 @@ export default {
task, task,
onLabelStudioLoad: (LS) => { onLabelStudioLoad: (LS) => {
if (!LS.annotationStore.selectedAnnotation) { if (!LS.annotationStore.selectedAnnotation) {
const annotation = LS.annotationStore.addAnnotation({ userGenerate: true }); const annotation = LS.annotationStore.addAnnotation({ userGenerate: true })
LS.annotationStore.selectAnnotation(annotation.id); LS.annotationStore.selectAnnotation(annotation.id)
} }
}, }
}); })
}); })
}, },
// LabelStudio // LabelStudio
resetLabelStudio() { resetLabelStudio() {
this.cleanupLabelStudio(); this.cleanupLabelStudio()
this.initLabelStudio(); // this.initLabelStudio() //
}, },
// LabelStudio // LabelStudio
cleanupLabelStudio() { cleanupLabelStudio() {
if (this.labelStudio && this.labelStudio.destroy) { 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) { if (labelStudioElement) {
labelStudioElement.innerHTML = ''; // labelStudioElement.innerHTML = '' //
} }
this.labelStudio = null; // this.labelStudio = null //
} }
} }
}; }
</script> </script>
<style scoped> <style scoped>
.button-container { .button-container {
margin: 10px; margin: 10px;
} }
.label-studio-annotator{
.label-studio-annotator {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.annotation-container{ .annotation-container {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
>div{ > div {
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 5px; padding: 5px;

View File

@ -85,7 +85,8 @@
</div> </div>
<div class="bottom-content-center"> <div class="bottom-content-center">
<div> <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" :config="labelConfig" :id="task.id" :file-url="task.data.image"
@update-itemIndex="updateItemIndex" @update-itemIndex="updateItemIndex"
></custom-label-studio> ></custom-label-studio>
@ -107,6 +108,7 @@ export default {
return { return {
itemIndex: 0, itemIndex: 0,
annotationResult: [], annotationResult: [],
fileAnnotationStatus: '',
item: {}, item: {},
taskList: [], taskList: [],
task: { task: {
@ -147,9 +149,9 @@ export default {
}, },
methods: { methods: {
// //
updateItemIndex(val) { updateItemIndex(val, fileAnnotationStatus) {
const item = this.images[val] const item = this.images[val]
this.images[val - 1].fileAnnotationStatus = '2' this.images[val - 1].fileAnnotationStatus = fileAnnotationStatus
this.itemIndex = val this.itemIndex = val
this.updateTaskData(item) this.updateTaskData(item)
}, },
@ -158,7 +160,7 @@ export default {
loadTaskList() { loadTaskList() {
getMyNoAnnotatedTask().then(res => { getMyNoAnnotatedTask().then(res => {
this.taskList = res.data 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) this.selectTask(this.taskId)
}) })
}, },
@ -201,6 +203,7 @@ export default {
setItem(item, index) { setItem(item, index) {
this.annotationResult = JSON.parse(item.annotationResult) this.annotationResult = JSON.parse(item.annotationResult)
this.itemIndex = index this.itemIndex = index
this.updateTaskData(item) this.updateTaskData(item)
}, },
@ -229,6 +232,7 @@ export default {
this.task.data.image = `${url.minioUrl}${item.fileUrl}` this.task.data.image = `${url.minioUrl}${item.fileUrl}`
this.task.id = item.fileId this.task.id = item.fileId
this.annotationResult = JSON.parse(item.annotationResult) this.annotationResult = JSON.parse(item.annotationResult)
this.fileAnnotationStatus = item.fileAnnotationStatus
} }
} }

View File

@ -76,14 +76,17 @@
<el-table-column label="操作" align="center" min-width="140" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" min-width="140" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
v-if="scope.row.annotatorIds.includes(getUserId)" v-if="scope.row.reviewerIds.split(',').map(Number).includes(getUserId)"
size="mini" size="mini"
type="text" type="text"
@click="handleExamine(scope.row)" @click="handleExamine(scope.row)"
v-hasPermi="['dataCenter:sample:edit']" v-hasPermi="['dataCenter:sample:edit']"
:disabled="scope.row.status1Count ===0"
>审核 >审核
</el-button> </el-button>
<el-button <el-button
v-if="scope.row.annotatorIds.split(',').map(Number).includes(getUserId)"
:disabled="scope.row.status0Count ===0"
size="mini" size="mini"
type="text" type="text"
@click="handleDimension(scope.row)" @click="handleDimension(scope.row)"
@ -91,7 +94,7 @@
>智能标注 >智能标注
</el-button> </el-button>
<el-button <el-button
v-if="scope.row.reviewerIds.includes(getUserId)" v-if="scope.row.annotatorIds.split(',').map(Number).includes(getUserId)"
size="mini" size="mini"
type="text" type="text"
@click="handleAnnotation(scope.row)" @click="handleAnnotation(scope.row)"
@ -104,6 +107,7 @@
type="text" type="text"
@click="handleRelease(scope.row)" @click="handleRelease(scope.row)"
v-hasPermi="['dataCenter:sample:edit']" v-hasPermi="['dataCenter:sample:edit']"
:disabled="scope.row.status2Count ===0"
>发布 >发布
</el-button> </el-button>
</template> </template>
@ -252,7 +256,7 @@ export default {
}, },
getPercentage(row) { getPercentage(row) {
if (row.totalCount > 0 && row.status0Count >= 0) { if (row.totalCount > 0 && row.status0Count >= 0) {
let percentage = Math.floor((row.status1Count / row.totalCount) * 100) let percentage = Math.floor(((row.status1Count + row.status2Count) / row.totalCount) * 100)
// percentage 0 100 // percentage 0 100
return Math.min(Math.max(percentage, 0), 100) return Math.min(Math.max(percentage, 0), 100)
} }

View File

@ -76,14 +76,17 @@
<el-table-column label="操作" align="center" min-width="140" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" min-width="140" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
v-if="scope.row.annotatorIds.includes(getUserId)" v-if="scope.row.reviewerIds.split(',').map(Number).includes(getUserId)"
size="mini" size="mini"
type="text" type="text"
@click="handleExamine(scope.row)" @click="handleExamine(scope.row)"
v-hasPermi="['dataCenter:sample:edit']" v-hasPermi="['dataCenter:sample:edit']"
:disabled="scope.row.status1Count ===0"
>审核 >审核
</el-button> </el-button>
<el-button <el-button
v-if="scope.row.annotatorIds.split(',').map(Number).includes(getUserId)"
:disabled="scope.row.status0Count ===0"
size="mini" size="mini"
type="text" type="text"
@click="handleDimension(scope.row)" @click="handleDimension(scope.row)"
@ -91,7 +94,7 @@
>智能标注 >智能标注
</el-button> </el-button>
<el-button <el-button
v-if="scope.row.reviewerIds.includes(getUserId)" v-if="scope.row.annotatorIds.split(',').map(Number).includes(getUserId)"
size="mini" size="mini"
type="text" type="text"
@click="handleAnnotation(scope.row)" @click="handleAnnotation(scope.row)"
@ -104,6 +107,7 @@
type="text" type="text"
@click="handleRelease(scope.row)" @click="handleRelease(scope.row)"
v-hasPermi="['dataCenter:sample:edit']" v-hasPermi="['dataCenter:sample:edit']"
:disabled="scope.row.status2Count ===0"
>发布 >发布
</el-button> </el-button>
</template> </template>
@ -252,7 +256,7 @@ export default {
}, },
getPercentage(row) { getPercentage(row) {
if (row.totalCount > 0 && row.status0Count >= 0) { if (row.totalCount > 0 && row.status0Count >= 0) {
let percentage = Math.floor((row.status1Count / row.totalCount) * 100) let percentage = Math.floor(((row.status1Count + row.status2Count) / row.totalCount) * 100)
// percentage 0 100 // percentage 0 100
return Math.min(Math.max(percentage, 0), 100) return Math.min(Math.max(percentage, 0), 100)
} }

View File

@ -136,6 +136,9 @@ export default {
}; };
}, },
methods: { methods: {
uploadFileId(res){
console.log("addDataSetDialog.vue",res)
},
// //
submitForm() { submitForm() {
this.$refs["form"].validate(valid => { this.$refs["form"].validate(valid => {

View File

@ -1,34 +1,40 @@
<template> <template>
<div> <div>
<el-dialog title="导入" :visible.sync="isOpen" width="700px" append-to-body :modal="false" @close="cancel" :close-on-click-modal="false"> <el-dialog title="导入" :visible.sync="isOpen" width="700px" append-to-body :modal="false" @close="cancel"
<el-form ref="form" :model="form" :rules="importRules" label-width="100px"> :close-on-click-modal="false"
<el-form-item label="数据来源" prop="dataSource" > >
<el-radio-group v-model="form.dataSource"> <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="0" border>系统选择</el-radio>
<el-radio :label="1" border>本地上传</el-radio> <el-radio :label="1" border>本地上传</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="导入路径" prop="inputPath"> <el-form-item label="导入路径" prop="inputPath">
<el-input placeholder="请选择导入路径" readonly :disabled="true" v-model="form.inputPath" class="input-with-select"> <el-input placeholder="请选择导入路径" readonly :disabled="true" v-model="form.inputPath"
<el-button slot="append" icon="el-icon-folder-opened" @click="selectFolder(0)"></el-button> class="input-with-select"
>
<el-button slot="append" icon="el-icon-folder-opened" @click="selectFolder(0)"></el-button>
</el-input> </el-input>
</el-form-item> </el-form-item>
<div v-show="form.dataSource ===1"> <div v-show="form.dataSource ===1">
<el-form-item label="上传文件"> <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>
<!-- <el-form-item label="数据标注状态" prop="isAnnotated"> <!-- <el-form-item label="数据标注状态" prop="isAnnotated">
<el-radio-group v-model="form.isAnnotated"> <el-radio-group v-model="form.isAnnotated">
<el-radio :label="0" border>未标注</el-radio> <el-radio :label="0" border>未标注</el-radio>
<el-radio :label="1" border>已标注</el-radio> <el-radio :label="1" border>已标注</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item v-show="form.isAnnotated === 1"> <el-form-item v-show="form.isAnnotated === 1">
<div style="display: flex;flex-direction: column;"> <div style="display: flex;flex-direction: column;">
<span>文件存放方式满足YOLO格式</span> <span>文件存放方式满足YOLO格式</span>
<img style="width: 50%" :src="ObjectDetection_YOLO" alt="Weibo"> <img style="width: 50%" :src="ObjectDetection_YOLO" alt="Weibo">
</div> </div>
</el-form-item>--> </el-form-item>-->
</div> </div>
</el-form> </el-form>
<template #footer> <template #footer>
@ -36,7 +42,9 @@
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
</template> </template>
</el-dialog> </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> </div>
</template> </template>
@ -48,20 +56,20 @@ import uploadFiles from '../../library/child/uploadFiles.vue'
import { importData } from '@/api/dataCenter/dataSet' import { importData } from '@/api/dataCenter/dataSet'
export default { export default {
components: { uploadFiles, selectFolderDialog}, components: { uploadFiles, selectFolderDialog },
props: { props: {
open: { open: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
dataType:{ dataType: {
type: String, type: String,
default: '', default: '',
required: true required: true
}, },
getList: { getList: {
type: Function, type: Function,
required: true, required: true
}, },
datasetId: { datasetId: {
type: String, type: String,
@ -72,44 +80,59 @@ export default {
computed: { computed: {
isOpen: { isOpen: {
get() { get() {
return this.open; return this.open
}, },
set(value) { set(value) {
this.$emit('update:open', value); this.$emit('update:open', value)
}, }
}, }
},
watch: {
isOpen(newVal, oldVal) {
if (newVal) {
this.fileIds = []
}
}
}, },
data() { data() {
return { return {
type: this.dataType, // type: this.dataType, //
ObjectDetection_YOLO:ObjectDetection_YOLO, ObjectDetection_YOLO: ObjectDetection_YOLO,
folderOpen: false, folderOpen: false,
folderType:0, folderType: 0,
fileIds: [],
form: { form: {
dataSource:0, dataSource: 0,
inputId:0, inputId: 0,
inputPath:'', inputPath: ''
}, // }, //
importRules:{ importRules: {
dataSource:[ dataSource: [
{ required: true, message: '数据来源不能为空', trigger: 'blur' }, { required: true, message: '数据来源不能为空', trigger: 'blur' }
], ],
inputPath:[ inputPath: [
{ required: true, message: '导入路径不能为空', trigger: 'blur' }, { required: true, message: '导入路径不能为空', trigger: 'blur' }
] ]
} }
}; }
}, },
methods: { methods: {
handleDataSourceChange() {
this.fileIds = []
},
uploadFileId(res) {
this.fileIds.push(res.fileId)
},
// //
submitForm() { submitForm() {
this.$refs["form"].validate(valid => { this.$refs['form'].validate(valid => {
if (valid) { if (valid) {
this.form.datasetId = this.datasetId this.form.datasetId = this.datasetId
this.form.dataType = this.dataType this.form.dataType = this.dataType
this.form.fileIds = this.fileIds
importData(this.form).then(response => { importData(this.form).then(response => {
this.$modal.msgSuccess("导入成功"); this.$modal.msgSuccess('导入成功')
this.cancel(); this.cancel()
}) })
} }
}) })
@ -117,37 +140,37 @@ export default {
}, },
// //
cancel() { cancel() {
this.getList(); this.getList()
this.isOpen = false; this.isOpen = false
this.reset(); this.reset()
this.$emit('dialog-cancel'); // this.$emit('dialog-cancel') //
}, },
// //
reset() { reset() {
this.form = { this.form = {
dataSource:0, dataSource: 0,
inputId:0, inputId: 0,
outputId:0 outputId: 0
}; // } //
this.$refs.form.resetFields(); // Element UI this.$refs.form.resetFields() // Element UI
}, },
// //
selectFolder(folderType){ selectFolder(folderType) {
this.folderType = folderType; this.folderType = folderType
this.folderOpen = true; this.folderOpen = true
}, },
handleCancel(){ handleCancel() {
this.folderOpen = false; this.folderOpen = false
}, },
updateData(data){ updateData(data) {
if (data.folderType === 0) { if (data.folderType === 0) {
this.form.inputPath = data.folder || ''; // inputPath this.form.inputPath = data.folder || '' // inputPath
this.form.inputId = data.fileId || 0; this.form.inputId = data.fileId || 0
} }
} }
}, }
}; }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@ -156,7 +179,7 @@ export default {
z-index: 2000 !important; /* Set a lower z-index for dialog */ z-index: 2000 !important; /* Set a lower z-index for dialog */
} }
input[aria-hidden=true]{ input[aria-hidden=true] {
display: none !important; display: none !important;
} }
</style> </style>

View File

@ -63,21 +63,26 @@ export default {
loseSample: [ loseSample: [
{ required: true, message: '请输入负样本数', trigger: 'blur' }, { required: true, message: '请输入负样本数', trigger: 'blur' },
{ pattern: /^[1-9]\d*$/, message: '只能输入正整数', trigger: 'blur' } { pattern: /^[1-9]\d*$/, message: '只能输入正整数', trigger: 'blur' }
], ],
tpNum: [ tpNum: [
{ required: true, message: '请输入TP数量', trigger: 'blur' }, { 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' }
], ],
tnNum: [{ required: true, message: '请输入TN数量', trigger: 'blur' }, fnNum: [
{ pattern: /^[1-9]\d*$/, message: '只能输入正整数', trigger: 'blur' } { required: true, message: '请输入FN数量', trigger: 'blur' },
{ pattern: /^[0-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
{ validator: this.validatePositiveSamples, trigger: 'blur' }
], ],
fpNum: [{ required: true, message: '请输入FP数量', trigger: 'blur' }, tnNum: [
{ pattern: /^[1-9]\d*$/, message: '只能输入正整数', trigger: 'blur' } { required: true, message: '请输入TN数量', trigger: 'blur' },
{ pattern: /^[0-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
{ validator: this.validateNegativeSamples, trigger: 'blur' }
], ],
fnNum: [{ required: true, message: '请输入FN数量', trigger: 'blur' }, fpNum: [
{ pattern: /^[1-9]\d*$/, message: '只能输入正整数', trigger: 'blur' } { required: true, message: '请输入FP数量', trigger: 'blur' },
{ pattern: /^[0-9]\d*$/, message: '只能输入正整数', trigger: 'blur' },
{ validator: this.validateNegativeSamples, trigger: 'blur' }
] ]
} }
} }
@ -85,27 +90,59 @@ export default {
watch: { watch: {
isOpen(newVal) { isOpen(newVal) {
if (newVal && this.evaluateDetailId) { if (newVal && this.evaluateDetailId) {
getDetails(this.evaluateDetailId).then(res => { getDetails(this.evaluateDetailId).then((res) => {
this.form = res.data this.form = res.data
}) })
} }
} }
}, },
methods: { methods: {
validatePositiveSamples(rule, value, 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()
}
},
validateNegativeSamples(rule, value, 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()
}
},
/** 提交按钮 */ /** 提交按钮 */
submitForm() { submitForm() {
this.$refs['form'].validate(valid => { this.$refs['form'].validate((valid) => {
if (valid) { if (valid) {
if (this.form.id != null) { if (this.form.id != null) {
updateDetails(this.form).then(res => { updateDetails(this.form).then((res) => {
this.$modal.msgSuccess('修改成功') this.$modal.msgSuccess('修改成功')
this.isOpen = false this.isOpen = false
this.getList() this.getList()
}) })
} else { } else {
this.form.evaluateId = this.evaluateId this.form.evaluateId = this.evaluateId
console.log(this.form) addDetails(this.form).then((response) => {
addDetails(this.form).then(response => {
this.$modal.msgSuccess('新增成功') this.$modal.msgSuccess('新增成功')
this.isOpen = false this.isOpen = false
this.getList() this.getList()
@ -125,4 +162,5 @@ export default {
} }
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -149,7 +149,6 @@ export default {
}, },
created() { created() {
this.evaluateId = Number(this.$route.params && this.$route.params.evaluateId) this.evaluateId = Number(this.$route.params && this.$route.params.evaluateId)
console.log(this.evaluateId)
this.getList() this.getList()
}, },
methods: { methods: {

View File

@ -155,7 +155,7 @@ export default {
formData.append('fileUrl', this.fileUrl) formData.append('fileUrl', this.fileUrl)
uploadFiles(formData) uploadFiles(formData)
.then(() => { .then(res => {
currentChunk++ currentChunk++
const progress = Math.floor((currentChunk / totalChunks) * 100) const progress = Math.floor((currentChunk / totalChunks) * 100)
this.$set(this.uploadsNum, file.name, progress) this.$set(this.uploadsNum, file.name, progress)
@ -163,11 +163,17 @@ export default {
if (currentChunk < totalChunks) { if (currentChunk < totalChunks) {
uploadNextChunk() uploadNextChunk()
} else { } else {
console.log(res)
console.log(this.$parent)
// $emit
this.$emit('file-uploaded', res.data);
console.log(res)
this.startNextUpload() this.startNextUpload()
this.checkAllUploadsComplete() this.checkAllUploadsComplete()
} }
}) })
.catch(() => { .catch(reason => {
console.log(reason)
this.$set(this.uploadFailed, file.name, true) this.$set(this.uploadFailed, file.name, true)
this.startNextUpload() this.startNextUpload()
}) })
@ -187,7 +193,6 @@ export default {
// //
startNextUpload() { startNextUpload() {
if (!this.drawer) return // if (!this.drawer) return //
Object.keys(this.uploadsNum).forEach((fileName) => { Object.keys(this.uploadsNum).forEach((fileName) => {
if (this.uploadsNum[fileName] === 100) { if (this.uploadsNum[fileName] === 100) {
delete this.uploadsNum[fileName] delete this.uploadsNum[fileName]

View File

@ -339,6 +339,9 @@ export default {
} }
}, },
methods: { methods: {
uploadFileId(res){
console.log("file.vue",res)
},
/** 转换菜单数据结构 */ /** 转换菜单数据结构 */
normalizer(node) { normalizer(node) {
if (node.children && !node.children.length) { if (node.children && !node.children.length) {

View File

@ -26,7 +26,7 @@
/> />
</el-form-item> </el-form-item>
<el-form-item label="手机号码" prop="phonenumber"> <el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" <el-input v-model="queryParams.phonenumber" placeholder="请输入完整手机号码" clearable style="width: 240px"
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
@ -82,7 +82,9 @@
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row> </el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange" :selectable="checkSelectable" :row-class-name="getRowClassName"> <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"
:selectable="checkSelectable" :row-class-name="getRowClassName"
>
<el-table-column type="selection" width="50" align="center"/> <el-table-column type="selection" width="50" align="center"/>
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible"/> <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible"/>
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" <el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible"
@ -112,13 +114,13 @@
<el-table-column label="账号时效" align="center"> <el-table-column label="账号时效" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{scope.row.isPermanent==1?"长期账号":"临时账号" }}</span> <span>{{ scope.row.isPermanent == 1 ? '长期账号' : '临时账号' }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="config.registersConfig.approvalStatus" label="审批状态" align="center"> <el-table-column v-if="config.registersConfig.approvalStatus" label="审批状态" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{scope.row.approvalStatus==0?"未审批":"已审批" }}</span> <span>{{ scope.row.approvalStatus == 0 ? '未审批' : '已审批' }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160"> <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
@ -127,7 +129,9 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="!hasSystemOrAuditrRole(scope.row.roles) && scope.row.userId !== 1 && scope.row.isBuiltIn !== '0'"> <template slot-scope="scope"
v-if="!hasSystemOrAuditrRole(scope.row.roles) && scope.row.userId !== 1 && scope.row.isBuiltIn !== '0'"
>
<el-button size="mini" type="text" icon="el-icon-edit" @click="confirmPassword(scope.row)" <el-button size="mini" type="text" icon="el-icon-edit" @click="confirmPassword(scope.row)"
v-hasPermi="['system:user:edit']" v-hasPermi="['system:user:edit']"
>修改 >修改
@ -220,7 +224,7 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="状态"> <el-form-item label="状态">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status">
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ <el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{
dict.label dict.label
@ -330,11 +334,11 @@ import {
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import Treeselect from '@riophae/vue-treeselect' import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css' import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import {validateNewPassword } from '@/utils/validate' import { validateNewPassword } from '@/utils/validate'
export default { export default {
name: 'User', name: 'User',
dicts: ['sys_normal_disable', 'sys_user_sex', 'sys_login_type','sys_user_permanent'], dicts: ['sys_normal_disable', 'sys_user_sex', 'sys_login_type', 'sys_user_permanent'],
components: { Treeselect }, components: { Treeselect },
data() { data() {
return { return {
@ -428,7 +432,7 @@ export default {
trigger: ['blur', 'change'] trigger: ['blur', 'change']
} }
], ],
deptId:[ { required: true, message: '请选择归属部门', trigger: 'blur' }], deptId: [{ required: true, message: '请选择归属部门', trigger: 'blur' }],
phonenumber: [ phonenumber: [
{ required: true, message: '手机号不能为空', trigger: 'blur' }, { required: true, message: '手机号不能为空', trigger: 'blur' },
{ {
@ -452,12 +456,14 @@ export default {
}, },
computed: { computed: {
config() { config() {
return JSON.parse(localStorage.getItem('systemConfig')) || {registersConfig: { return JSON.parse(localStorage.getItem('systemConfig')) || {
registersConfig: {
phoneRegisters: true, phoneRegisters: true,
emailRegisters: true, emailRegisters: true,
verificationCode:true, verificationCode: true,
approvalStatus:true, approvalStatus: true
}}; // JSON }
} // JSON
} }
}, },
watch: { watch: {
@ -476,8 +482,8 @@ export default {
methods: { methods: {
/* 手机号码脱敏 */ /* 手机号码脱敏 */
hidePhone(phone) { hidePhone(phone) {
if (!phone) return ''; if (!phone) return ''
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'); return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
}, },
/* 表单登录权限自定义校验 */ /* 表单登录权限自定义校验 */
validateLoginType(rule, value, callback) { validateLoginType(rule, value, callback) {
@ -585,13 +591,13 @@ export default {
// //
handleSelectionChange(selection) { handleSelectionChange(selection) {
// //
const validSelection = selection.filter(row => this.checkSelectable(row)); const validSelection = selection.filter(row => this.checkSelectable(row))
// roleId // roleId
this.ids = validSelection.map(item => item.userId); this.ids = validSelection.map(item => item.userId)
// //
this.single = validSelection.length !== 1; this.single = validSelection.length !== 1
this.multiple = !validSelection.length; this.multiple = !validSelection.length
}, },
// //
handleCommand(command, row) { handleCommand(command, row) {
@ -641,7 +647,7 @@ export default {
this.form.password = '' this.form.password = ''
}) })
}, },
confirmPassword(row){ confirmPassword(row) {
this.$prompt('请输入密码,鉴别用户', '提示', { this.$prompt('请输入密码,鉴别用户', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
@ -650,14 +656,14 @@ export default {
inputErrorMessage: '用户密码长度必须介于 8 和 16 之间', inputErrorMessage: '用户密码长度必须介于 8 和 16 之间',
inputValidator: (value) => { inputValidator: (value) => {
// validateNewPassword // validateNewPassword
const errorMessage=function(error) { const errorMessage = function(error) {
if (error) { if (error) {
return error.message; return error.message
} else { } else {
console.log('验证通过'); console.log('验证通过')
} }
}; }
validateNewPassword(null, value, errorMessage); validateNewPassword(null, value, errorMessage)
} }
}).then(({ value }) => { }).then(({ value }) => {
confirmPassword(value).then(response => { confirmPassword(value).then(response => {
@ -667,7 +673,7 @@ export default {
}).catch(() => { }).catch(() => {
}) })
}, },
confirmResetPwd(row){ confirmResetPwd(row) {
this.$prompt('请输入密码,鉴别用户', '提示', { this.$prompt('请输入密码,鉴别用户', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
@ -676,14 +682,14 @@ export default {
inputErrorMessage: '用户密码长度必须介于 8 和 16 之间', inputErrorMessage: '用户密码长度必须介于 8 和 16 之间',
inputValidator: (value) => { inputValidator: (value) => {
// validateNewPassword // validateNewPassword
const errorMessage=function(error) { const errorMessage = function(error) {
if (error) { if (error) {
return error.message; return error.message
} else { } else {
console.log('验证通过'); console.log('验证通过')
} }
}; }
validateNewPassword(null, value, errorMessage); validateNewPassword(null, value, errorMessage)
} }
}).then(({ value }) => { }).then(({ value }) => {
confirmPassword(value).then(response => { confirmPassword(value).then(response => {
@ -703,14 +709,14 @@ export default {
inputErrorMessage: '用户密码长度必须介于 8 和 16 之间', inputErrorMessage: '用户密码长度必须介于 8 和 16 之间',
inputValidator: (value) => { inputValidator: (value) => {
// validateNewPassword // validateNewPassword
const errorMessage=function(error) { const errorMessage = function(error) {
if (error) { if (error) {
return error.message; return error.message
} else { } else {
console.log('验证通过'); console.log('验证通过')
} }
}; }
validateNewPassword(null, value, errorMessage); validateNewPassword(null, value, errorMessage)
} }
}).then(({ value }) => { }).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => { resetUserPwd(row.userId, value).then(response => {
@ -791,20 +797,19 @@ export default {
hasSystemOrAuditrRole(roles) { hasSystemOrAuditrRole(roles) {
if (!roles || !Array.isArray(roles)) { if (!roles || !Array.isArray(roles)) {
return false; // roles false return false // roles false
} }
return roles.some(role => role.roleKey === 'systemAdmin' || role.roleKey === 'audit'); // roleKey admin return roles.some(role => role.roleKey === 'systemAdmin' || role.roleKey === 'audit') // roleKey admin
}, },
// //
checkSelectable(row) { checkSelectable(row) {
return !(row.userId === 1 || row.isBuiltIn === '0' || this.hasSystemOrAuditrRole(row.roles)); return !(row.userId === 1 || row.isBuiltIn === '0' || this.hasSystemOrAuditrRole(row.roles))
}, },
getRowClassName(row) { getRowClassName(row) {
return !this.checkSelectable(row) ? 'disabled-row' : ''; return !this.checkSelectable(row) ? 'disabled-row' : ''
}, }
} }
} }
@ -824,4 +829,4 @@ export default {
.disabled-row:hover td { .disabled-row:hover td {
background-color: #f5f7fa !important; background-color: #f5f7fa !important;
} }
</style> </style>