This commit is contained in:
parent
b85889486c
commit
24affac448
|
|
@ -34,8 +34,8 @@ export function addImageInfoAPI(data) {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data,
|
data,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'multipart/form-data'
|
'Content-Type': 'multipart/form-data',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,4 +48,11 @@ export function updateImageSureAPI(data) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改标注
|
||||||
|
export function updateImageAnnotationAPI(data) {
|
||||||
|
return request({
|
||||||
|
url: '/image/caption/manualAnnotation',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
|
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="$emit('start-upload')"
|
@click="$emit('start-upload', null)"
|
||||||
:disabled="
|
:disabled="
|
||||||
fileList.length === 0 || selectedTag.length === 0
|
fileList.length === 0 || selectedTag.length === 0
|
||||||
"
|
"
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
(file, fileList) => $emit('file-change', file, fileList)
|
(file, fileList) => $emit('file-change', file, fileList)
|
||||||
"
|
"
|
||||||
@remove-image="(index) => $emit('remove-image', index)"
|
@remove-image="(index) => $emit('remove-image', index)"
|
||||||
@start-upload="$emit('start-upload')"
|
@start-upload="$emit('start-upload', remarkInfo)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -108,6 +108,17 @@ export default {
|
||||||
this.$emit('hand-click', result, index)
|
this.$emit('hand-click', result, index)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
groupedImageResults: {
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal.length > 0) {
|
||||||
|
this.remarkInfo = newVal[0].remark
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
v-else
|
v-else
|
||||||
:src="currentImage.url"
|
:src="imgSrc"
|
||||||
alt="preview"
|
alt="preview"
|
||||||
class="annotation-preview-image"
|
class="annotation-preview-image"
|
||||||
/>
|
/>
|
||||||
|
|
@ -280,19 +280,15 @@
|
||||||
|
|
||||||
<div v-if="isReAnnotating" class="annotation-type">
|
<div v-if="isReAnnotating" class="annotation-type">
|
||||||
<span class="label">标注类型:</span>
|
<span class="label">标注类型:</span>
|
||||||
<el-select
|
<el-radio-group v-model="annotationType" size="small">
|
||||||
v-model="annotationType"
|
<el-radio-button
|
||||||
placeholder="请选择"
|
|
||||||
size="small"
|
|
||||||
class="annotation-type-select"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="option in annotationTypeOptions"
|
v-for="option in annotationTypeOptions"
|
||||||
:key="option.value"
|
:key="option.value"
|
||||||
:label="option.label"
|
:label="option.value"
|
||||||
:value="option.value"
|
>
|
||||||
/>
|
{{ option.label }}
|
||||||
</el-select>
|
</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="annotation-info">
|
<div class="annotation-info">
|
||||||
|
|
@ -302,18 +298,14 @@
|
||||||
{{ originalSize.height }}
|
{{ originalSize.height }}
|
||||||
</p>
|
</p>
|
||||||
<p v-if="annotationCoords">
|
<p v-if="annotationCoords">
|
||||||
左上:({{ annotationCoords.x1 }},
|
当前标注:左上:({{ annotationCoords.x1 }},
|
||||||
{{ annotationCoords.y1 }}) ,右下:({{
|
{{ annotationCoords.y1 }}) ,右下:({{
|
||||||
annotationCoords.x2
|
annotationCoords.x2
|
||||||
}}, {{ annotationCoords.y2 }})
|
}}, {{ annotationCoords.y2 }})
|
||||||
</p>
|
</p>
|
||||||
<!-- <p v-else
|
<p v-if="!annotationCoords && isReAnnotating">
|
||||||
>请{{
|
请先选择标注类型,然后拖拽绘制标注框
|
||||||
isReAnnotating
|
</p>
|
||||||
? '拖拽绘制标注框'
|
|
||||||
: '点击重新标注'
|
|
||||||
}}</p
|
|
||||||
> -->
|
|
||||||
</div>
|
</div>
|
||||||
<div class="annotation-buttons">
|
<div class="annotation-buttons">
|
||||||
<el-button
|
<el-button
|
||||||
|
|
@ -329,16 +321,61 @@
|
||||||
取消标注
|
取消标注
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="success"
|
||||||
size="small"
|
size="small"
|
||||||
:disabled="!annotationCoords || !annotationType"
|
:disabled="!annotationCoords || !annotationType"
|
||||||
@click="emitAnnotation"
|
@click="saveTemporaryAnnotation"
|
||||||
>
|
>
|
||||||
提交
|
临时确定
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
:disabled="annotations.length === 0"
|
||||||
|
@click="submitAllAnnotations"
|
||||||
|
>
|
||||||
|
提交全部
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 标注列表 -->
|
||||||
|
<div
|
||||||
|
v-if="isReAnnotating && annotations.length > 0"
|
||||||
|
class="annotation-list"
|
||||||
|
>
|
||||||
|
<div class="annotation-list-title"
|
||||||
|
>已标注列表({{ annotations.length }})</div
|
||||||
|
>
|
||||||
|
<div class="annotation-list-content">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in annotations"
|
||||||
|
:key="index"
|
||||||
|
class="annotation-list-item"
|
||||||
|
>
|
||||||
|
<span class="annotation-item-info">
|
||||||
|
<span class="annotation-item-type">{{
|
||||||
|
getTypeLabel(item.type)
|
||||||
|
}}</span>
|
||||||
|
<span class="annotation-item-coords"
|
||||||
|
>({{ item.coords.x1 }},
|
||||||
|
{{ item.coords.y1 }}) - ({{
|
||||||
|
item.coords.x2
|
||||||
|
}}, {{ item.coords.y2 }})</span
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
icon="el-icon-delete"
|
||||||
|
@click="removeAnnotation(index)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="annotation-empty">请先选择图片</div>
|
<div v-else class="annotation-empty">请先选择图片</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -346,6 +383,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import {
|
||||||
|
getSelectedAPI,
|
||||||
|
updateImageAnnotationAPI,
|
||||||
|
} from '@/api/imageCaptioning/imageCaptioning'
|
||||||
export default {
|
export default {
|
||||||
name: 'ImageResults',
|
name: 'ImageResults',
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -396,13 +437,19 @@ export default {
|
||||||
currentRect: null,
|
currentRect: null,
|
||||||
annotationCoords: null,
|
annotationCoords: null,
|
||||||
annotationType: '',
|
annotationType: '',
|
||||||
|
annotations: [],
|
||||||
annotationTypeOptions: [
|
annotationTypeOptions: [
|
||||||
{ label: '人物', value: 'person' },
|
// { label: '人物', value: 'person' },
|
||||||
{ label: '物体', value: 'object' },
|
// { label: '物体', value: 'object' },
|
||||||
{ label: '场景', value: 'scene' },
|
// { label: '场景', value: 'scene' },
|
||||||
],
|
],
|
||||||
|
|
||||||
|
imgSrc: '',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
this.getTags()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isGroupImageSelected(groupIndex, imageIndex) {
|
isGroupImageSelected(groupIndex, imageIndex) {
|
||||||
// 根据分组索引和图片索引判断是否选中
|
// 根据分组索引和图片索引判断是否选中
|
||||||
|
|
@ -439,17 +486,17 @@ export default {
|
||||||
|
|
||||||
// 点击图片显示弹框
|
// 点击图片显示弹框
|
||||||
onClickImage(image) {
|
onClickImage(image) {
|
||||||
|
console.log('image', image)
|
||||||
if (!image || !image.url) {
|
if (!image || !image.url) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.currentImage = image
|
this.currentImage = image
|
||||||
|
this.imgSrc = image.url
|
||||||
this.imageDialogVisible = true
|
this.imageDialogVisible = true
|
||||||
this.annotationCoords = null
|
this.annotationCoords = null
|
||||||
this.annotationType = ''
|
this.annotationType = ''
|
||||||
|
this.annotations = []
|
||||||
this.isReAnnotating = false
|
this.isReAnnotating = false
|
||||||
this.$nextTick(() => {
|
|
||||||
this.renderBaseImage()
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 关闭图片显示弹框
|
// 关闭图片显示弹框
|
||||||
|
|
@ -462,6 +509,8 @@ export default {
|
||||||
this.isReAnnotating = true
|
this.isReAnnotating = true
|
||||||
this.annotationCoords = null
|
this.annotationCoords = null
|
||||||
this.annotationType = ''
|
this.annotationType = ''
|
||||||
|
this.imgSrc = this.currentImage.originUrl
|
||||||
|
this.annotations = []
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.renderBaseImage()
|
this.renderBaseImage()
|
||||||
})
|
})
|
||||||
|
|
@ -469,9 +518,16 @@ export default {
|
||||||
|
|
||||||
cancelReAnnotation() {
|
cancelReAnnotation() {
|
||||||
this.isReAnnotating = false
|
this.isReAnnotating = false
|
||||||
this.clearDrawing()
|
// 清空所有状态
|
||||||
this.annotationCoords = null
|
this.annotationCoords = null
|
||||||
this.annotationType = ''
|
this.annotationType = ''
|
||||||
|
this.annotations = []
|
||||||
|
this.currentRect = null
|
||||||
|
this.isDrawing = false
|
||||||
|
this.startPoint = null
|
||||||
|
this.imgSrc = this.currentImage.url
|
||||||
|
// 清空画布
|
||||||
|
this.clearDrawing()
|
||||||
},
|
},
|
||||||
|
|
||||||
renderBaseImage() {
|
renderBaseImage() {
|
||||||
|
|
@ -512,8 +568,12 @@ export default {
|
||||||
ctx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight)
|
ctx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight)
|
||||||
this.scaleInfo = { scale, offsetX, offsetY }
|
this.scaleInfo = { scale, offsetX, offsetY }
|
||||||
this.clearDrawing()
|
this.clearDrawing()
|
||||||
|
// 重新绘制已保存的标注
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.drawCurrentRect()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
img.src = this.currentImage.url
|
img.src = this.imgSrc
|
||||||
},
|
},
|
||||||
|
|
||||||
clearDrawing() {
|
clearDrawing() {
|
||||||
|
|
@ -524,7 +584,12 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
handleMouseDown(event) {
|
handleMouseDown(event) {
|
||||||
if (!this.currentImage) return
|
if (!this.currentImage || !this.annotationType) {
|
||||||
|
if (!this.annotationType) {
|
||||||
|
this.$message.warning('请先选择标注类型')
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
const position = this.getCanvasPosition(event)
|
const position = this.getCanvasPosition(event)
|
||||||
this.isDrawing = true
|
this.isDrawing = true
|
||||||
this.startPoint = position
|
this.startPoint = position
|
||||||
|
|
@ -563,10 +628,22 @@ export default {
|
||||||
|
|
||||||
drawCurrentRect() {
|
drawCurrentRect() {
|
||||||
const drawCanvas = this.$refs.drawCanvas
|
const drawCanvas = this.$refs.drawCanvas
|
||||||
if (!drawCanvas || !this.currentRect) return
|
if (!drawCanvas) return
|
||||||
const ctx = drawCanvas.getContext('2d')
|
const ctx = drawCanvas.getContext('2d')
|
||||||
ctx.clearRect(0, 0, drawCanvas.width, drawCanvas.height)
|
ctx.clearRect(0, 0, drawCanvas.width, drawCanvas.height)
|
||||||
ctx.strokeStyle = '#ff8800'
|
|
||||||
|
// 绘制已保存的标注框
|
||||||
|
this.annotations.forEach((annotation) => {
|
||||||
|
const rect = this.convertToCanvasCoords(annotation.coords)
|
||||||
|
ctx.strokeStyle = '#ff0000'
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
ctx.setLineDash([])
|
||||||
|
ctx.strokeRect(rect.x, rect.y, rect.width, rect.height)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 绘制当前正在绘制的标注框
|
||||||
|
if (this.currentRect) {
|
||||||
|
ctx.strokeStyle = '#409eff' // 红线
|
||||||
ctx.lineWidth = 2
|
ctx.lineWidth = 2
|
||||||
ctx.setLineDash([6, 4])
|
ctx.setLineDash([6, 4])
|
||||||
ctx.strokeRect(
|
ctx.strokeRect(
|
||||||
|
|
@ -576,6 +653,7 @@ export default {
|
||||||
this.currentRect.height,
|
this.currentRect.height,
|
||||||
)
|
)
|
||||||
ctx.setLineDash([])
|
ctx.setLineDash([])
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
calculateOriginalCoords(rect) {
|
calculateOriginalCoords(rect) {
|
||||||
|
|
@ -621,25 +699,187 @@ export default {
|
||||||
return Math.max(min, Math.min(max, value))
|
return Math.max(min, Math.min(max, value))
|
||||||
},
|
},
|
||||||
|
|
||||||
emitAnnotation() {
|
convertToCanvasCoords(coords) {
|
||||||
if (
|
const { scale, offsetX, offsetY } = this.scaleInfo
|
||||||
!this.annotationCoords ||
|
if (!scale) return { x: 0, y: 0, width: 0, height: 0 }
|
||||||
!this.currentImage ||
|
const x1 = coords.x1 * scale + offsetX
|
||||||
!this.annotationType
|
const y1 = coords.y1 * scale + offsetY
|
||||||
)
|
const x2 = coords.x2 * scale + offsetX
|
||||||
|
const y2 = coords.y2 * scale + offsetY
|
||||||
|
return {
|
||||||
|
x: Math.min(x1, x2),
|
||||||
|
y: Math.min(y1, y2),
|
||||||
|
width: Math.abs(x2 - x1),
|
||||||
|
height: Math.abs(y2 - y1),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
saveTemporaryAnnotation() {
|
||||||
|
if (!this.annotationCoords || !this.annotationType) {
|
||||||
|
this.$message.warning('请先完成标注并选择类型')
|
||||||
return
|
return
|
||||||
this.$emit('manual-annotation', {
|
}
|
||||||
image: this.currentImage,
|
this.annotations.push({
|
||||||
coords: this.annotationCoords,
|
coords: { ...this.annotationCoords },
|
||||||
type: this.annotationType,
|
type: this.annotationType,
|
||||||
|
typeName: this.getTypeLabel(this.annotationType),
|
||||||
})
|
})
|
||||||
this.$message.success('坐标已生成')
|
this.annotationCoords = null
|
||||||
|
this.annotationType = ''
|
||||||
|
this.clearDrawing()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.drawCurrentRect()
|
||||||
|
})
|
||||||
|
this.$message.success('标注已保存')
|
||||||
|
},
|
||||||
|
|
||||||
|
removeAnnotation(index) {
|
||||||
|
this.annotations.splice(index, 1)
|
||||||
|
// 清空当前正在绘制的标注
|
||||||
|
this.currentRect = null
|
||||||
|
this.annotationCoords = null
|
||||||
|
this.isDrawing = false
|
||||||
|
// 重新绘制画布(只绘制剩余的已保存标注)
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.clearDrawing()
|
||||||
|
this.drawCurrentRect()
|
||||||
|
})
|
||||||
|
// this.$message.success('标注已删除')
|
||||||
|
},
|
||||||
|
|
||||||
|
getTypeLabel(value) {
|
||||||
|
const option = this.annotationTypeOptions.find(
|
||||||
|
(opt) => opt.value === value,
|
||||||
|
)
|
||||||
|
return option ? option.label : value
|
||||||
|
},
|
||||||
|
|
||||||
|
async submitAllAnnotations() {
|
||||||
|
if (this.annotations.length === 0) {
|
||||||
|
this.$message.warning('请至少添加一个标注')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.currentImage) {
|
||||||
|
this.$message.warning('图片信息缺失')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 生成带标注的图片base64
|
||||||
|
const imageCanvas = this.$refs.imageCanvas
|
||||||
|
const drawCanvas = this.$refs.drawCanvas
|
||||||
|
if (!imageCanvas || !drawCanvas) {
|
||||||
|
this.$message.error('无法获取画布')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个临时canvas用于合成最终图片
|
||||||
|
const finalCanvas = document.createElement('canvas')
|
||||||
|
finalCanvas.width = this.originalSize.width
|
||||||
|
finalCanvas.height = this.originalSize.height
|
||||||
|
const finalCtx = finalCanvas.getContext('2d')
|
||||||
|
|
||||||
|
// 加载原始图片
|
||||||
|
const img = new Image()
|
||||||
|
img.crossOrigin = 'Anonymous'
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
img.onload = () => {
|
||||||
|
// 绘制原始图片
|
||||||
|
finalCtx.drawImage(
|
||||||
|
img,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
this.originalSize.width,
|
||||||
|
this.originalSize.height,
|
||||||
|
)
|
||||||
|
|
||||||
|
// 绘制所有标注框
|
||||||
|
this.annotations.forEach((annotation) => {
|
||||||
|
const { coords } = annotation
|
||||||
|
finalCtx.strokeStyle = '#03FB02'
|
||||||
|
finalCtx.lineWidth = 1.5
|
||||||
|
finalCtx.strokeRect(
|
||||||
|
coords.x1,
|
||||||
|
coords.y1,
|
||||||
|
coords.x2 - coords.x1,
|
||||||
|
coords.y2 - coords.y1,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
img.onerror = reject
|
||||||
|
img.src = this.imgSrc
|
||||||
|
})
|
||||||
|
|
||||||
|
// 转换为base64
|
||||||
|
const base64Image = finalCanvas.toDataURL('image/png')
|
||||||
|
|
||||||
|
// 提交数据
|
||||||
|
// this.$emit('manual-annotation', {
|
||||||
|
// image: this.currentImage,
|
||||||
|
// annotations: this.annotations,
|
||||||
|
// base64Image: base64Image,
|
||||||
|
// })
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'base64Image',
|
||||||
|
base64Image,
|
||||||
|
'annotations',
|
||||||
|
this.annotations,
|
||||||
|
'image',
|
||||||
|
this.currentImage,
|
||||||
|
)
|
||||||
|
|
||||||
|
// 根据this.annotations 把重复的标签去重
|
||||||
|
const tagList = new Set(this.annotations.map((e) => e.typeName))
|
||||||
|
console.log('tagList', tagList)
|
||||||
|
|
||||||
|
// 组装参数
|
||||||
|
const params = {
|
||||||
|
id: this.currentImage.id,
|
||||||
|
bast64: base64Image,
|
||||||
|
jsonData: JSON.stringify(
|
||||||
|
this.annotations.map((e) => {
|
||||||
|
return {
|
||||||
|
class: e.typeName,
|
||||||
|
confidence: 0,
|
||||||
|
bbox: {
|
||||||
|
x1: e.coords.x1,
|
||||||
|
y1: e.coords.y1,
|
||||||
|
x2: e.coords.x2,
|
||||||
|
y2: e.coords.y2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
// 获取标签去重后的数据(Set转数组后join)
|
||||||
|
type: Array.from(tagList).join(','),
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('params', params)
|
||||||
|
|
||||||
|
const res = await updateImageAnnotationAPI(params)
|
||||||
|
|
||||||
|
console.log('res', res)
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.$message.success('标注已提交')
|
||||||
|
this.cancelReAnnotation()
|
||||||
|
this.imageDialogVisible = false
|
||||||
|
}
|
||||||
|
// this.$message.success('标注已提交')
|
||||||
|
// 重置状态
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交标注失败:', error)
|
||||||
|
this.$message.error('提交标注失败,请重试')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
resetAnnotation() {
|
resetAnnotation() {
|
||||||
this.currentImage = null
|
this.currentImage = null
|
||||||
this.annotationCoords = null
|
this.annotationCoords = null
|
||||||
this.annotationType = ''
|
this.annotationType = ''
|
||||||
|
this.annotations = []
|
||||||
this.isReAnnotating = false
|
this.isReAnnotating = false
|
||||||
this.originalSize = { width: 0, height: 0 }
|
this.originalSize = { width: 0, height: 0 }
|
||||||
this.scaleInfo = { scale: 1, offsetX: 0, offsetY: 0 }
|
this.scaleInfo = { scale: 1, offsetX: 0, offsetY: 0 }
|
||||||
|
|
@ -647,6 +887,17 @@ export default {
|
||||||
this.startPoint = null
|
this.startPoint = null
|
||||||
this.currentRect = null
|
this.currentRect = null
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 获取标签
|
||||||
|
getTags() {
|
||||||
|
getSelectedAPI().then((res) => {
|
||||||
|
// console.log('res标签', res)
|
||||||
|
this.annotationTypeOptions = res.data.map((item) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -751,11 +1002,13 @@ export default {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.annotation-type-select {
|
.annotation-type .label {
|
||||||
flex: 1;
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.annotation-info {
|
.annotation-info {
|
||||||
|
|
@ -782,6 +1035,66 @@ export default {
|
||||||
padding: 30px 0;
|
padding: 30px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.annotation-list {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotation-list-title {
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #e4e7ed;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotation-list-content {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotation-list-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px 16px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotation-list-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotation-list-item:hover {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotation-item-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotation-item-type {
|
||||||
|
padding: 2px 8px;
|
||||||
|
background: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotation-item-coords {
|
||||||
|
color: #606266;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-hand {
|
.icon-hand {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 25px;
|
top: 25px;
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ export default {
|
||||||
this.addId = ''
|
this.addId = ''
|
||||||
},
|
},
|
||||||
|
|
||||||
startUpload() {
|
startUpload(remarkInfo = '') {
|
||||||
console.log('开始上传')
|
console.log('开始上传')
|
||||||
if (this.selectedTag.length === 0) {
|
if (this.selectedTag.length === 0) {
|
||||||
this.$message.warning('请选择需要标注的内容标签')
|
this.$message.warning('请选择需要标注的内容标签')
|
||||||
|
|
@ -224,7 +224,7 @@ export default {
|
||||||
// 修改参数处理方式,与之前的params 保持一致
|
// 修改参数处理方式,与之前的params 保持一致
|
||||||
const params = {
|
const params = {
|
||||||
param: selectedTagNames,
|
param: selectedTagNames,
|
||||||
remark: this.remarkInfo,
|
remark: remarkInfo || this.remarkInfo,
|
||||||
id: this.addId,
|
id: this.addId,
|
||||||
}
|
}
|
||||||
formData.append('params', JSON.stringify(params))
|
formData.append('params', JSON.stringify(params))
|
||||||
|
|
@ -250,6 +250,7 @@ export default {
|
||||||
operaName: record.operaName,
|
operaName: record.operaName,
|
||||||
images: record.fileVoList.map((item) => ({
|
images: record.fileVoList.map((item) => ({
|
||||||
url: item.bjUrl || '未找到图片地址',
|
url: item.bjUrl || '未找到图片地址',
|
||||||
|
originUrl: item.imageUrl,
|
||||||
id: item.imageId || item.id,
|
id: item.imageId || item.id,
|
||||||
name: item.originalName,
|
name: item.originalName,
|
||||||
contentImage: item.contentImage,
|
contentImage: item.contentImage,
|
||||||
|
|
@ -511,7 +512,8 @@ export default {
|
||||||
index: index, // 下标
|
index: index, // 下标
|
||||||
operaName: record.operaName,
|
operaName: record.operaName,
|
||||||
images: record.fileVoList.map((item) => ({
|
images: record.fileVoList.map((item) => ({
|
||||||
url: item.bjUrl || item.url,
|
url: item.bjUrl,
|
||||||
|
originUrl: item.imageUrl,
|
||||||
id: item.imageId || item.id,
|
id: item.imageId || item.id,
|
||||||
name: item.originalName,
|
name: item.originalName,
|
||||||
contentImage: item.contentImage,
|
contentImage: item.contentImage,
|
||||||
|
|
@ -524,6 +526,7 @@ export default {
|
||||||
isSure: record.isSure,
|
isSure: record.isSure,
|
||||||
operId: record.operaId,
|
operId: record.operaId,
|
||||||
id: record.id,
|
id: record.id,
|
||||||
|
remark: record.remark,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue