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+)',
component: () => import('@/views/dataCenter/evaluate/child/evaluateDetails'),
name: 'Data',
meta: { title: '模型评价详情', activeMenu: '/dataCenter/evaluateDetails' }
meta: { title: '模型评价详情', activeMenu: '/dataCenter/evaluate/evaluateDetails' }
}
]
},

View File

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

View File

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

View File

@ -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: {},
@ -205,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])

View File

@ -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;

View File

@ -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
}
}

View File

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

View File

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

View File

@ -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>

View File

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

View File

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

View File

@ -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]

View File

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

View File

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