质控像素匿名

uat_us
wangxiaoshuang 2026-04-24 14:37:36 +08:00
parent 946203f124
commit 64d8c853b3
4 changed files with 212 additions and 29 deletions

View File

@ -57,6 +57,7 @@
<div style="position: absolute;top: 50%;left: 15px;color: #f44336;">{{ markers.left }}</div>
<div class="info-instance">
<svg-icon icon-class="IsMasked" style="font-size:20px;" v-show="dicomInfo.IsMasked" />
<!-- <div v-show="dicomInfo.pixel">
Pixel: {{ dicomInfo.pixel }}mm
</div>-->
@ -138,6 +139,7 @@ export default {
zoom: 0,
location: '',
fps: 5,
IsMasked: false
},
toolState: {
initialized: false,
@ -378,6 +380,8 @@ export default {
e.detail.enabledElement.options = {}
var data = e.detail.image.data
this.dicomInfo.hospital = data.string('x00080080')
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === e.detail.image.imageId)
this.dicomInfo.IsMasked = instanceInfo.IsMasked
// this.dicomInfo.pid = data.string('x00100020')
this.dicomInfo.pid = data.string('x00120040')
this.dicomInfo.name = data.string('x00100010')

View File

@ -7,16 +7,25 @@
</div>
</div>-->
<div class="Anonymous" v-if="isAnonymous">
<div :class="{ btn: true, activeBtn: activeTool === 'Note_RectangleRoi' }"
@click="setToolActive($event, 'Note_RectangleRoi')">矩形</div>
<div :class="{ btn: true, activeBtn: activeTool === 'Eraser' }" @click="setToolActive($event, 'Eraser')">清除
<div
:class="{ btn: true, activeBtn: activeTool === 'Note_RectangleRoi' && !isComparison, isNoted: isComparison }"
@click="setToolActive($event, 'Note_RectangleRoi')">{{
$t('DicomViewer:anonymous:Note_RectangleRoi') }}</div>
<div :class="{ btn: true, activeBtn: activeTool === 'Eraser' && !isComparison, isNoted: isComparison }"
@click="setToolActive($event, 'Eraser')">{{
$t('DicomViewer:anonymous:Eraser') }}
</div>
<div class="btn" @click="anonymousImage"></div>
<div class="btn">应用整个序列</div>
<div :class="{ btn: true, isNoted: isComparison }" @click="anonymousImage(false)">{{
$t('DicomViewer:anonymous:Application') }}</div>
<div :class="{ btn: true, isNoted: isComparison }" @click="anonymousImage(true)">{{
$t('DicomViewer:anonymous:ApplicationAll') }}</div>
<!-- <div class="btn">刷新图像</div> -->
<div class="btn" v-if="!isComparison"></div>
<div class="btn" v-else>退</div>
<div class="btn">恢复</div>
<div class="btn" v-if="!isComparison" @click="comparison(true)">{{
$t('DicomViewer:anonymous:Comparison') }}</div>
<div class="btn" v-else @click="comparison(false)">{{
$t('DicomViewer:anonymous:Exit') }}</div>
<div :class="{ btn: true, isNoted: isComparison }" @click="recovery(false)">{{
$t('DicomViewer:anonymous:Recovery') }}</div>
</div>
<div v-show="layoutRow >= 1" class="dicom-row" :style="{ height: rowHeight }">
<div v-show="layoutRow >= 1 && layoutCol >= 1" class="dicom-item"
@ -90,7 +99,9 @@
<option value="3x2">3x2</option>
<option value="3x3">3x3</option>
</select>
<div class="btnBox" @click="openAnonymous"></div>
<div class="btnBox" v-if="hasAnonymous" @click="openAnonymous">{{ $t('DicomViewer:anonymous:PixelAnonymity')
}}
</div>
</div>
</div>
<!-- 图像变换 -->
@ -330,7 +341,7 @@
<!-- 提交 -->
<el-form-item style="margin-top: 20px;text-align: right;" v-if="isEdit">
<el-button type="primary" @click="submitForm" size="small">{{ $t('trials:ptData:button:submit')
}}</el-button>
}}</el-button>
</el-form-item>
</el-form>
</div>
@ -374,6 +385,10 @@ export default {
type: Boolean,
default: false
},
Comparison: {
type: Boolean,
default: false
},
modality: {
type: String,
default: ''
@ -381,6 +396,7 @@ export default {
},
data() {
return {
hasAnonymous: false,
isAnonymous: false,
isComparison: false,
activeTool: '',
@ -450,6 +466,8 @@ export default {
}
},
mounted() {
let type = this.$router.currentRoute.query.type ? this.$router.currentRoute.query.type : ''
this.hasAnonymous = type === 'Study'
this.customWwc = {
visible: false,
title: this.$t('DicomViewer:data:customWwc'),
@ -468,11 +486,116 @@ export default {
},
methods: {
anonymousImage() {
console.log(this.series, 'this.series')
comparison(f) {
this.isComparison = f
this.$emit("update:Comparison", f)
const elements = document.querySelectorAll('.dicom-item')
const scope = this
Array.from(elements).forEach((element, index) => {
if (element.style.display !== 'none') {
scope.$refs[`dicomCanvas${index}`].setToolPassive(scope.activeTool)
}
})
scope.activeTool = null
if (this.isComparison) {
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(obj => {
let { image } = obj
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
if (!instanceInfo.IsMasked) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
this.changeLayout('1x2')
let serie = {}
Object.keys(this.series).forEach(key => {
if (key !== 'instanceInfoList' && key !== 'imageIds') {
serie[key] = this.series[key]
}
})
let imageId = image.imageId
let newImageId = imageId.split("?")[0].split(".MaskDicom_")[0] + "?" + imageId.split("?")[1]
let info0 = {}, info1 = {}
Object.keys(instanceInfo).forEach(key => {
info0[key] = instanceInfo[key]
info1[key] = instanceInfo[key]
})
info0.ImageId = imageId
info1.ImageId = newImageId
console.log(info0)
console.log(info1)
let dicomCanvas0_info = Object.assign({
instanceInfoList: [
info0
],
imageIds: [imageId]
}, serie)
let dicomCanvas1_info = Object.assign({
instanceInfoList: [
info1
],
imageIds: [newImageId]
}, serie)
console.log(dicomCanvas0_info, 'dicomCanvas0_info')
console.log(dicomCanvas1_info, 'dicomCanvas0_info')
this.$refs[`dicomCanvas0`].loadImageStack(dicomCanvas0_info)
this.$refs[`dicomCanvas1`].loadImageStack(dicomCanvas1_info)
})
} else {
this.changeLayout('1x1')
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
}
},
recovery(isAll = false) {
if (this.isComparison) return false
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
let { image } = obj
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
if (!instanceInfo.IsMasked) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
let data = {
// SeriesId: this.series.seriesId,
instanceIdList: [instanceInfo.Id]
}
if (isAll) {
data.SeriesId = this.series.seriesId
delete data.instanceIdList
}
let res = await this.studyUndoMaskImage(data)
if (!res) return false
this.$emit("update:loading", true)
if (!isAll) {
let strs = image.imageId.split("?")
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${res[0].Path}?${strs[1]}`
this.series.instanceInfoList.some(item => {
if (item.Id === instanceInfo.Id) {
item.ImageId = newImageId
item.IsMasked = false
}
return item.Id === instanceInfo.Id
})
let index = this.series.imageIds.findIndex(item => item === image.imageId)
this.series.imageIds.splice(index, 1, newImageId)
await this.$refs[`dicomCanvas0`].reloadImage(newImageId)
} else {
let arr = []
this.series.instanceInfoList.forEach(item => {
let strs = item.ImageId.split("?")
let info = res.find(i => item.Id === i.Id)
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${info.Path}?${strs[1]}`
item.ImageId = newImageId
item.IsMasked = false
arr.push(newImageId)
})
this.series.imageIds = arr
console.log(this.series, 'this.series')
// this.loadImageStack(this.series)
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
}
this.$emit("update:loading", false)
this.$emit('loadStudy', false)
})
},
anonymousImage(isAll = false) {
if (this.isComparison) return false
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
let { toolInfo, image } = obj
console.log(image, 'image')
if (!toolInfo || toolInfo.data.length <= 0) return this.$confirm(this.$t("DicomViewer:anonymous:notMark"))
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
let data = {
@ -480,6 +603,10 @@ export default {
instanceIdList: [instanceInfo.Id],
MaskRegionList: []
}
if (isAll) {
data.SeriesId = this.series.seriesId
delete data.instanceIdList
}
toolInfo.data.forEach(item => {
let currentStart = item.handles.start
let currentEnd = item.handles.end
@ -502,11 +629,37 @@ export default {
})
let res = await this.studyMaskImage(data)
if (!res) return false
// this.$emit("update:loading", true)
// let strs = image.imageId.split("?")
// let newImageId = `${strs[0]}-MaskImage?${strs[1]}`
// console.log(newImageId, 'newImageId')
// this.$refs[`dicomCanvas0`].reloadImage(newImageId)
this.$emit("update:loading", true)
if (!isAll) {
let strs = image.imageId.split("?")
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${res[0].Path}?${strs[1]}`
this.series.instanceInfoList.some(item => {
if (item.Id === instanceInfo.Id) {
item.ImageId = newImageId
item.IsMasked = true
}
return item.Id === instanceInfo.Id
})
let index = this.series.imageIds.findIndex(item => item === image.imageId)
this.series.imageIds.splice(index, 1, newImageId)
await this.$refs[`dicomCanvas0`].reloadImage(newImageId)
} else {
let arr = []
this.series.instanceInfoList.forEach(item => {
let strs = item.ImageId.split("?")
let info = res.find(i => item.Id === i.Id)
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${info.Path}?${strs[1]}`
item.ImageId = newImageId
item.IsMasked = true
arr.push(newImageId)
})
this.series.imageIds = arr
console.log(this.series, 'this.series')
// this.loadImageStack(this.series)
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
}
this.$emit("update:loading", false)
this.$emit('loadStudy', false)
})
},
openAnonymous() {
@ -514,12 +667,12 @@ export default {
if (!this.isAnonymous) {
const elements = document.querySelectorAll('.dicom-item')
const scope = this
scope.activeTool = null
Array.from(elements).forEach((element, index) => {
if (element.style.display !== 'none') {
scope.$refs[`dicomCanvas${index}`].setToolPassive(toolName)
scope.$refs[`dicomCanvas${index}`].setToolPassive(scope.activeTool)
}
})
scope.activeTool = null
} else {
this.activateDicomCanvas(0)
this.changeLayout('1x1')
@ -531,7 +684,22 @@ export default {
let res = await studyMaskImage(data)
this.$emit("update:loading", false)
if (res.IsSuccess) {
return true
return res.Result.OkList
}
return false
} catch (err) {
console.log(err)
this.$emit("update:loading", false)
return false
}
},
async studyUndoMaskImage(data) {
try {
this.$emit("update:loading", true)
let res = await studyUndoMaskImage(data)
this.$emit("update:loading", false)
if (res.IsSuccess) {
return res.Result.OkList
}
return false
} catch (err) {
@ -930,6 +1098,10 @@ export default {
.activeBtn {
background-color: rgba(255, 255, 255, .5);
}
.isNoted {
cursor: not-allowed;
}
}
.btnBox {

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1777010831812" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1646" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 896c-230.058667 0-421.461333-165.546667-461.610667-384a468.565333 468.565333 0 0 1 142.506667-258.816L89.6 149.973333A42.666667 42.666667 0 1 1 149.930667 89.6L934.4 874.112a42.666667 42.666667 0 0 1-60.373333 60.330667l-111.061334-111.061334A466.901333 466.901333 0 0 1 512 896zM253.226667 313.6A382.506667 382.506667 0 0 0 137.514667 512a384.213333 384.213333 0 0 0 563.242666 249.088l-86.528-86.528A192 192 0 0 1 349.44 409.770667L253.226667 313.6z m297.770666 297.728l-138.325333-138.325333a106.666667 106.666667 0 0 0 138.282667 138.282666l0.042666 0.042667z m285.312 22.357333l10.24-18.218666A381.226667 381.226667 0 0 0 886.485333 512a384.213333 384.213333 0 0 0-440.661333-292.949333c-2.944 0.512-9.173333 1.877333-18.730667 4.096a42.88 42.88 0 1 1-19.2-83.541334A470.912 470.912 0 0 1 512 128c230.058667 0 421.461333 165.546667 461.610667 384a467.072 467.072 0 0 1-57.685334 153.856 94.933333 94.933333 0 0 1-8.021333 11.178667 44.373333 44.373333 0 0 1-58.794667 9.088 39.552 39.552 0 0 1-12.8-52.437334z m-188.501333-257.493333a192 192 0 0 1 55.850667 147.626667l-203.52-203.477334a192 192 0 0 1 147.626666 55.893334z" fill="#e6e6e6" p-id="1647"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -124,7 +124,7 @@
</div>
<div class="viewerContent">
<dicom-viewer id="dicomViewer" ref="dicomViewer" style="height:100%" :loading.sync="loading"
:modality="modality" />
:modality="modality" :Comparison.sync="isComparison" @loadStudy="loadStudy" />
</div>
<!-- <div class="viewerRightSidePanel">
<dicom-tools />
@ -202,7 +202,8 @@ export default {
isFromCRCUpload: false,
isReading: null,
activeSeriesId: null,
isPacs: false
isPacs: false,
isComparison: false
}
},
created: function () {
@ -307,7 +308,7 @@ export default {
})
})
},
async loadStudy() {
async loadStudy(isJump = true) {
let params = {}
if (this.isPacs) {
params.IsPacs = true
@ -327,7 +328,7 @@ export default {
isReading = `?IsPacs=true`
}
const url = `/series/list/${this.studyId}${isReading}`
this.getSeriesList(url)
this.getSeriesList(url, isJump)
}
},
async loadPatientStudy() {
@ -392,7 +393,7 @@ export default {
console.log(err)
}
},
async getSeriesList(url) {
async getSeriesList(url, isJump = true) {
try {
const data = await getSeriesList(url)
if (data.IsSuccess) {
@ -431,7 +432,7 @@ export default {
isDeleted: item.IsDeleted,
previewImageUrl: item.ImageResizePath ? this.OSSclientConfig.basePath + item.ImageResizePath : `/api/series/preview/${item.Id}`,
instanceCount: item.InstanceCount,
prefetchInstanceCount: 0,
prefetchInstanceCount: !isJump ? item.InstanceInfoList.length * 100 : 0,
hasLabel: item.HasLabel,
keySeries: item.KeySeries,
tpCode: this.tpCode,
@ -446,8 +447,11 @@ export default {
this.seriesList = seriesList
if (this.seriesList.length > 0) {
this.loadAllImages()
this.$refs.dicomViewer.loadImageStack(this.seriesList[0], this.labels[this.tpCode])
this.firstInstanceId = this.seriesList[0].imageIds[0]
if (isJump) {
this.$refs.dicomViewer.loadImageStack(this.seriesList[0], this.labels[this.tpCode])
this.firstInstanceId = this.seriesList[0].imageIds[0]
}
}
}
} catch (e) {
@ -527,6 +531,7 @@ export default {
}
},
showSeriesImage(e, seriesIndex, series) {
if (!isComparison) return false
this.activeSeriesId = series.seriesId
workSpeedclose(true)
// if (seriesIndex === this.currentSeriesIndex) return
@ -920,6 +925,7 @@ export default {
}
if (this.visitTaskId === params.visitTaskId) {
const seriesIndex = params.seriesIndex
if (!this.seriesList[seriesIndex]) return false
var prefetchInstanceCount = this.seriesList[seriesIndex].prefetchInstanceCount
var instanceCount = this.seriesList[seriesIndex].instanceCount
if (!this.activeSeriesId) {