新增缺陷增加轴向和弦向字段|缺陷检测界面新增图像预览功能和增加典型图片设置功能|去除可视化菜单
This commit is contained in:
parent
70fca26e10
commit
fe6e84f5f7
|
@ -765,12 +765,6 @@ export const systemRoutes: RouteRecordRaw[] = [
|
|||
redirect: '/construction-operation-platform/implementation-workflow/data-processing/intelligent-inspection/defect-algorithm',
|
||||
meta: { title: '数据分析与图像检测', icon: 'scan', hidden: false },
|
||||
children: [
|
||||
{
|
||||
path: '/construction-operation-platform/implementation-workflow/data-processing/intelligent-inspection/tree-visualization',
|
||||
name: 'TreeVisualization',
|
||||
component: () => import('@/views/project-operation-platform/data-processing/key-info-extraction/index.vue'),
|
||||
meta: { title: '可视化管理', icon: 'cluster', hidden: false },
|
||||
},
|
||||
{
|
||||
path: '/construction-operation-platform/implementation-workflow/data-processing/intelligent-inspection/defect-algorithm',
|
||||
name: 'DefectAlgorithm',
|
||||
|
|
|
@ -70,6 +70,6 @@ declare global {
|
|||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
|
||||
import('vue')
|
||||
}
|
||||
|
|
|
@ -12,6 +12,14 @@
|
|||
<a-form-item label="缺陷名称" field="defectName">
|
||||
<a-input v-model="form.defectName" placeholder="请输入缺陷名称" />
|
||||
</a-form-item>
|
||||
|
||||
<!-- 缺陷位置 -->
|
||||
<a-form-item
|
||||
field="defectPosition"
|
||||
label="缺陷位置"
|
||||
>
|
||||
<a-input v-model="form.defectPosition" placeholder="请输入缺陷位置" />
|
||||
</a-form-item>
|
||||
|
||||
<!-- 缺陷类型 -->
|
||||
<a-form-item
|
||||
|
@ -27,19 +35,47 @@
|
|||
<a-option v-for="type in defectTypes" :key="type.code" :value="type.code">{{ type.label }}</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 缺陷位置 -->
|
||||
<a-form-item
|
||||
field="defectPosition"
|
||||
label="缺陷位置"
|
||||
>
|
||||
<a-input v-model="form.defectPosition" placeholder="请输入缺陷位置" />
|
||||
</a-form-item>
|
||||
|
||||
<!--轴向尺寸-->
|
||||
<div class="dimension-fields">
|
||||
<a-form-item
|
||||
field="axialDimension"
|
||||
label="轴向尺寸 (mm)"
|
||||
:rules="[{ type: 'number', min: 0, message: '必须大于等于0' }]"
|
||||
>
|
||||
<a-input-number
|
||||
v-model="form.axialDimension"
|
||||
:min="0"
|
||||
:step="1"
|
||||
placeholder="请输入轴向尺寸"
|
||||
mode="button"
|
||||
size="large"
|
||||
>
|
||||
</a-input-number>
|
||||
</a-form-item>
|
||||
|
||||
<!--弦向尺寸 -->
|
||||
<a-form-item
|
||||
field="chordDimension"
|
||||
label="弦向尺寸 (mm)"
|
||||
:rules="[{ type: 'number', min: 0, message: '必须大于等于0' }]"
|
||||
>
|
||||
<a-input-number
|
||||
v-model="form.chordDimension"
|
||||
:min="0"
|
||||
:step="1"
|
||||
placeholder="请输入弦向尺寸"
|
||||
mode="button"
|
||||
size="large"
|
||||
>
|
||||
</a-input-number>
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 缺陷等级 -->
|
||||
<a-form-item
|
||||
field="defectLevel"
|
||||
label="缺陷等级"
|
||||
label="严重程度"
|
||||
:rules="[{ required: true, message: '请选择缺陷等级' }]"
|
||||
>
|
||||
<a-select
|
||||
|
@ -104,6 +140,8 @@ interface DefectFormData {
|
|||
defectPosition: string
|
||||
description: string
|
||||
repairIdea: string
|
||||
axialDimension: number | 0
|
||||
chordDimension: number | 0
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
|
@ -135,7 +173,9 @@ const form = reactive<DefectFormData>({
|
|||
defectLevelLabel: '',
|
||||
defectPosition: '',
|
||||
description: '',
|
||||
repairIdea: '建议进行进一步检查'
|
||||
repairIdea: '建议进行进一步检查',
|
||||
axialDimension: 0, // 初始为null
|
||||
chordDimension: 0 // 初始为null
|
||||
})
|
||||
|
||||
// 获取缺陷类型列表
|
||||
|
@ -326,6 +366,7 @@ const handleSubmit = async () => {
|
|||
}
|
||||
|
||||
// 触发提交事件
|
||||
console.log("form:",form);
|
||||
emit('submit', form, props.annotation)
|
||||
|
||||
} catch (error) {
|
||||
|
@ -434,6 +475,25 @@ onMounted(() => {
|
|||
}
|
||||
}
|
||||
|
||||
.dimension-fields {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
:deep(.arco-input-number) {
|
||||
width: 100%;
|
||||
|
||||
.arco-input-number-step {
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.arco-input-number-input {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.arco-form-item) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
<template>
|
||||
<a-modal
|
||||
:visible="previewModalVisible"
|
||||
title="图像详情"
|
||||
width="80%"
|
||||
:footer="footerButtons"
|
||||
:mask-closable="true"
|
||||
@update:visible="emit('update:previewModalVisible', $event)"
|
||||
:confirm-loading="loading"
|
||||
>
|
||||
<div v-if="previewImage" class="modal-image-viewer">
|
||||
<img :src="getImageUrl(previewImage.imagePath)" :alt="editingData.imageName" class="preview-image" />
|
||||
|
||||
<div class="image-details">
|
||||
<a-form layout="vertical" :model="editingData">
|
||||
<a-form-item label="图片名称" field="imageName">
|
||||
<a-input v-model="editingData.imageName" />
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="大小" field="size">
|
||||
<a-input :model-value="formatFileSize(editingData.size || 0)" disabled />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="尺寸" field="imageResolution">
|
||||
<a-input v-model="editingData.imageResolution" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="采集员ID" field="collectId">
|
||||
<a-input v-model="editingData.collectId" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="采集员姓名" field="collectorName">
|
||||
<a-input v-model="editingData.collectorName" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="来源" field="imageSource">
|
||||
<a-input v-model="editingData.imageSource" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="图片类型" field="imageType">
|
||||
<a-select v-model="editingData.imageType">
|
||||
<a-option value="DEFECT">缺陷影像</a-option>
|
||||
<a-option value="TYPICAL">典型影像</a-option>
|
||||
<a-option value="OTHER">其他影像</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item label="图片类型描述" field="imageTypeLabel">
|
||||
<a-textarea
|
||||
v-model="editingData.imageTypeLabel"
|
||||
:auto-size="{ minRows: 2, maxRows: 4 }"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button @click="emit('update:previewModalVisible', false)">取消</a-button>
|
||||
<a-button type="primary" :loading="loading" @click="handleSave">保存</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import axios from 'axios'
|
||||
|
||||
const props = defineProps<{
|
||||
previewModalVisible: boolean
|
||||
previewImage: {
|
||||
imagePath: string
|
||||
imageName: string
|
||||
size?: number
|
||||
imageResolution?: string
|
||||
collectId?: string
|
||||
collectorName?: string
|
||||
imageSource?: string
|
||||
imageType?: string
|
||||
imageTypeLabel?: string
|
||||
partId?: string
|
||||
} | null
|
||||
selectedImage: any | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:previewModalVisible': [visible: boolean]
|
||||
'save': [data: any]
|
||||
}>()
|
||||
|
||||
const loading = ref(false)
|
||||
const editingData = ref<{
|
||||
imagePath: string
|
||||
imageName: string
|
||||
size?: number
|
||||
imageResolution?: string
|
||||
collectId?: string
|
||||
collectorName?: string
|
||||
imageSource?: string
|
||||
imageType?: string
|
||||
imageTypeLabel?: string
|
||||
partId?: string
|
||||
imageId?:string
|
||||
}>({
|
||||
imagePath: '',
|
||||
imageName: '',
|
||||
size: 0,
|
||||
imageResolution: '',
|
||||
collectId: '',
|
||||
collectorName: '',
|
||||
imageSource: '',
|
||||
imageType: '',
|
||||
imageTypeLabel: '',
|
||||
partId: '',
|
||||
imageId:''
|
||||
})
|
||||
|
||||
// 监听预览图片变化,初始化编辑数据
|
||||
watch(() => props.previewImage, (newVal) => {
|
||||
if (newVal) {
|
||||
editingData.value = { ...newVal }
|
||||
}
|
||||
}, { immediate: true, deep: true })
|
||||
|
||||
const getImageUrl = (imagePath: string): string => {
|
||||
if (!imagePath) return ''
|
||||
if (imagePath.startsWith('http')) return imagePath
|
||||
const baseUrl = 'http://pms.dtyx.net:9158'
|
||||
return `${baseUrl}${imagePath}`
|
||||
}
|
||||
|
||||
const formatFileSize = (size: number): string => {
|
||||
if (size < 1024) return `${size} B`
|
||||
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`
|
||||
if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(1)} MB`
|
||||
return `${(size / (1024 * 1024 * 1024)).toFixed(1)} GB`
|
||||
}
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!editingData.value.imageName?.trim()) {
|
||||
Message.error('图片名称不能为空')
|
||||
return
|
||||
}
|
||||
|
||||
if (!editingData.value.partId) {
|
||||
Message.error('缺少部件ID,无法保存')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true
|
||||
|
||||
// 构造请求数据
|
||||
const requestData = {
|
||||
collectId: editingData.value.collectId,
|
||||
collectorName: editingData.value.collectorName,
|
||||
imageSource: editingData.value.imageSource,
|
||||
imageType: editingData.value.imageType,
|
||||
imageTypeLabel: editingData.value.imageTypeLabel,
|
||||
imageList: [
|
||||
{
|
||||
imageId: editingData.value.imageId,
|
||||
imageName: editingData.value.imageName,
|
||||
imageResolution: editingData.value.imageResolution,
|
||||
}
|
||||
],
|
||||
}
|
||||
console.log("requestData:",requestData);
|
||||
|
||||
// 调用接口更新数据
|
||||
const response = await axios.put(
|
||||
`http://pms.dtyx.net:9158/image/setting-info/${editingData.value.partId}`,
|
||||
requestData
|
||||
)
|
||||
|
||||
if (response.data && response.data.code === 0) {
|
||||
Message.success('图片信息保存成功')
|
||||
emit('save', editingData.value)
|
||||
emit('update:previewModalVisible', false)
|
||||
} else {
|
||||
Message.error(response.data?.message || '保存失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存图片信息失败:', error)
|
||||
Message.error('保存失败,请稍后重试')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.modal-image-viewer {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
align-items: flex-start;
|
||||
|
||||
.preview-image {
|
||||
flex: 1;
|
||||
max-width: 60%;
|
||||
max-height: 500px;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.image-details {
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
|
||||
:deep(.arco-form) {
|
||||
.arco-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.modal-image-viewer {
|
||||
flex-direction: column;
|
||||
|
||||
.preview-image {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -349,6 +349,7 @@ export function useIndustrialImage() {
|
|||
}
|
||||
|
||||
const handleImagePreview = (image: any) => {
|
||||
console.log("image:",image);
|
||||
previewImage.value = image
|
||||
previewModalVisible.value = true
|
||||
}
|
||||
|
|
|
@ -145,7 +145,14 @@
|
|||
</div>
|
||||
|
||||
<!-- 模态框 -->
|
||||
|
||||
<ImageModals
|
||||
:preview-modal-visible="previewModalVisible"
|
||||
:preview-image="previewImage"
|
||||
:process-image="processImage"
|
||||
:selected-image="selectedImage"
|
||||
@update:preview-modal-visible="previewModalVisible = $event"
|
||||
@save="handleSaveImageSuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -158,6 +165,7 @@ import ProjectTree from './components/ProjectTree.vue'
|
|||
import ImagePreview from './components/ImagePreview.vue'
|
||||
import ImageCanvas from '@/views/project-operation-platform/data-processing/industrial-image/components/ImageCanvas.vue'
|
||||
import IndustrialImageList from '@/components/IndustrialImageList/index.vue'
|
||||
import ImageModals from './components/ImageModals.vue'
|
||||
import RecognitionResults from './components/RecognitionResults.vue'
|
||||
import DefectListPanel from './components/DefectListPanel.vue'
|
||||
import DefectDetailsForm from './components/DefectDetailsForm.vue'
|
||||
|
@ -212,6 +220,19 @@ const loadDefectLevels = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
// 添加保存成功处理
|
||||
const handleSaveImageSuccess = (updatedData: any) => {
|
||||
// 可以在这里更新本地数据或执行其他操作
|
||||
Message.success('图片信息已更新')
|
||||
// 如果需要更新selectedImage或previewImage
|
||||
if (selectedImage.value && selectedImage.value.id === updatedData.id) {
|
||||
selectedImage.value = { ...selectedImage.value, ...updatedData }
|
||||
}
|
||||
if (previewImage.value && previewImage.value.id === updatedData.id) {
|
||||
previewImage.value = { ...previewImage.value, ...updatedData }
|
||||
}
|
||||
}
|
||||
|
||||
// 使用组合式函数
|
||||
const {
|
||||
// 数据
|
||||
|
@ -594,8 +615,8 @@ const handleDefectFormSubmit = async (formData: any, annotation: Annotation) =>
|
|||
const defectData = {
|
||||
attachId: attachId,
|
||||
attachPath: '',
|
||||
// axial: 0,
|
||||
// chordwise: 0,
|
||||
axial: formData.axialDimension,
|
||||
chordwise: formData.chordDimension,
|
||||
// defectCode: `MANUAL_${Date.now()}`,
|
||||
defectId: '',
|
||||
defectLevel: formData.defectLevel,
|
||||
|
|
Loading…
Reference in New Issue