质控像素匿名

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

View File

@ -7,16 +7,25 @@
</div> </div>
</div>--> </div>-->
<div class="Anonymous" v-if="isAnonymous"> <div class="Anonymous" v-if="isAnonymous">
<div :class="{ btn: true, activeBtn: activeTool === 'Note_RectangleRoi' }" <div
@click="setToolActive($event, 'Note_RectangleRoi')">矩形</div> :class="{ btn: true, activeBtn: activeTool === 'Note_RectangleRoi' && !isComparison, isNoted: isComparison }"
<div :class="{ btn: true, activeBtn: activeTool === 'Eraser' }" @click="setToolActive($event, 'Eraser')">清除 @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>
<div class="btn" @click="anonymousImage"></div> <div :class="{ btn: true, isNoted: isComparison }" @click="anonymousImage(false)">{{
<div class="btn">应用整个序列</div> $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">刷新图像</div> -->
<div class="btn" v-if="!isComparison"></div> <div class="btn" v-if="!isComparison" @click="comparison(true)">{{
<div class="btn" v-else>退</div> $t('DicomViewer:anonymous:Comparison') }}</div>
<div class="btn">恢复</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>
<div v-show="layoutRow >= 1" class="dicom-row" :style="{ height: rowHeight }"> <div v-show="layoutRow >= 1" class="dicom-row" :style="{ height: rowHeight }">
<div v-show="layoutRow >= 1 && layoutCol >= 1" class="dicom-item" <div v-show="layoutRow >= 1 && layoutCol >= 1" class="dicom-item"
@ -90,7 +99,9 @@
<option value="3x2">3x2</option> <option value="3x2">3x2</option>
<option value="3x3">3x3</option> <option value="3x3">3x3</option>
</select> </select>
<div class="btnBox" @click="openAnonymous"></div> <div class="btnBox" v-if="hasAnonymous" @click="openAnonymous">{{ $t('DicomViewer:anonymous:PixelAnonymity')
}}
</div>
</div> </div>
</div> </div>
<!-- 图像变换 --> <!-- 图像变换 -->
@ -374,6 +385,10 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
Comparison: {
type: Boolean,
default: false
},
modality: { modality: {
type: String, type: String,
default: '' default: ''
@ -381,6 +396,7 @@ export default {
}, },
data() { data() {
return { return {
hasAnonymous: false,
isAnonymous: false, isAnonymous: false,
isComparison: false, isComparison: false,
activeTool: '', activeTool: '',
@ -450,6 +466,8 @@ export default {
} }
}, },
mounted() { mounted() {
let type = this.$router.currentRoute.query.type ? this.$router.currentRoute.query.type : ''
this.hasAnonymous = type === 'Study'
this.customWwc = { this.customWwc = {
visible: false, visible: false,
title: this.$t('DicomViewer:data:customWwc'), title: this.$t('DicomViewer:data:customWwc'),
@ -468,11 +486,116 @@ export default {
}, },
methods: { methods: {
anonymousImage() { 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') 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 => { this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
let { toolInfo, image } = obj let { toolInfo, image } = obj
console.log(image, 'image')
if (!toolInfo || toolInfo.data.length <= 0) return this.$confirm(this.$t("DicomViewer:anonymous:notMark")) 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 instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
let data = { let data = {
@ -480,6 +603,10 @@ export default {
instanceIdList: [instanceInfo.Id], instanceIdList: [instanceInfo.Id],
MaskRegionList: [] MaskRegionList: []
} }
if (isAll) {
data.SeriesId = this.series.seriesId
delete data.instanceIdList
}
toolInfo.data.forEach(item => { toolInfo.data.forEach(item => {
let currentStart = item.handles.start let currentStart = item.handles.start
let currentEnd = item.handles.end let currentEnd = item.handles.end
@ -502,11 +629,37 @@ export default {
}) })
let res = await this.studyMaskImage(data) let res = await this.studyMaskImage(data)
if (!res) return false if (!res) return false
// this.$emit("update:loading", true) this.$emit("update:loading", true)
// let strs = image.imageId.split("?") if (!isAll) {
// let newImageId = `${strs[0]}-MaskImage?${strs[1]}` let strs = image.imageId.split("?")
// console.log(newImageId, 'newImageId') let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${res[0].Path}?${strs[1]}`
// this.$refs[`dicomCanvas0`].reloadImage(newImageId) 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() { openAnonymous() {
@ -514,12 +667,12 @@ export default {
if (!this.isAnonymous) { if (!this.isAnonymous) {
const elements = document.querySelectorAll('.dicom-item') const elements = document.querySelectorAll('.dicom-item')
const scope = this const scope = this
scope.activeTool = null
Array.from(elements).forEach((element, index) => { Array.from(elements).forEach((element, index) => {
if (element.style.display !== 'none') { if (element.style.display !== 'none') {
scope.$refs[`dicomCanvas${index}`].setToolPassive(toolName) scope.$refs[`dicomCanvas${index}`].setToolPassive(scope.activeTool)
} }
}) })
scope.activeTool = null
} else { } else {
this.activateDicomCanvas(0) this.activateDicomCanvas(0)
this.changeLayout('1x1') this.changeLayout('1x1')
@ -531,7 +684,22 @@ export default {
let res = await studyMaskImage(data) let res = await studyMaskImage(data)
this.$emit("update:loading", false) this.$emit("update:loading", false)
if (res.IsSuccess) { 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 return false
} catch (err) { } catch (err) {
@ -930,6 +1098,10 @@ export default {
.activeBtn { .activeBtn {
background-color: rgba(255, 255, 255, .5); background-color: rgba(255, 255, 255, .5);
} }
.isNoted {
cursor: not-allowed;
}
} }
.btnBox { .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>
<div class="viewerContent"> <div class="viewerContent">
<dicom-viewer id="dicomViewer" ref="dicomViewer" style="height:100%" :loading.sync="loading" <dicom-viewer id="dicomViewer" ref="dicomViewer" style="height:100%" :loading.sync="loading"
:modality="modality" /> :modality="modality" :Comparison.sync="isComparison" @loadStudy="loadStudy" />
</div> </div>
<!-- <div class="viewerRightSidePanel"> <!-- <div class="viewerRightSidePanel">
<dicom-tools /> <dicom-tools />
@ -202,7 +202,8 @@ export default {
isFromCRCUpload: false, isFromCRCUpload: false,
isReading: null, isReading: null,
activeSeriesId: null, activeSeriesId: null,
isPacs: false isPacs: false,
isComparison: false
} }
}, },
created: function () { created: function () {
@ -307,7 +308,7 @@ export default {
}) })
}) })
}, },
async loadStudy() { async loadStudy(isJump = true) {
let params = {} let params = {}
if (this.isPacs) { if (this.isPacs) {
params.IsPacs = true params.IsPacs = true
@ -327,7 +328,7 @@ export default {
isReading = `?IsPacs=true` isReading = `?IsPacs=true`
} }
const url = `/series/list/${this.studyId}${isReading}` const url = `/series/list/${this.studyId}${isReading}`
this.getSeriesList(url) this.getSeriesList(url, isJump)
} }
}, },
async loadPatientStudy() { async loadPatientStudy() {
@ -392,7 +393,7 @@ export default {
console.log(err) console.log(err)
} }
}, },
async getSeriesList(url) { async getSeriesList(url, isJump = true) {
try { try {
const data = await getSeriesList(url) const data = await getSeriesList(url)
if (data.IsSuccess) { if (data.IsSuccess) {
@ -431,7 +432,7 @@ export default {
isDeleted: item.IsDeleted, isDeleted: item.IsDeleted,
previewImageUrl: item.ImageResizePath ? this.OSSclientConfig.basePath + item.ImageResizePath : `/api/series/preview/${item.Id}`, previewImageUrl: item.ImageResizePath ? this.OSSclientConfig.basePath + item.ImageResizePath : `/api/series/preview/${item.Id}`,
instanceCount: item.InstanceCount, instanceCount: item.InstanceCount,
prefetchInstanceCount: 0, prefetchInstanceCount: !isJump ? item.InstanceInfoList.length * 100 : 0,
hasLabel: item.HasLabel, hasLabel: item.HasLabel,
keySeries: item.KeySeries, keySeries: item.KeySeries,
tpCode: this.tpCode, tpCode: this.tpCode,
@ -446,9 +447,12 @@ export default {
this.seriesList = seriesList this.seriesList = seriesList
if (this.seriesList.length > 0) { if (this.seriesList.length > 0) {
this.loadAllImages() this.loadAllImages()
if (isJump) {
this.$refs.dicomViewer.loadImageStack(this.seriesList[0], this.labels[this.tpCode]) this.$refs.dicomViewer.loadImageStack(this.seriesList[0], this.labels[this.tpCode])
this.firstInstanceId = this.seriesList[0].imageIds[0] this.firstInstanceId = this.seriesList[0].imageIds[0]
} }
}
} }
} catch (e) { } catch (e) {
console.log(e) console.log(e)
@ -527,6 +531,7 @@ export default {
} }
}, },
showSeriesImage(e, seriesIndex, series) { showSeriesImage(e, seriesIndex, series) {
if (!isComparison) return false
this.activeSeriesId = series.seriesId this.activeSeriesId = series.seriesId
workSpeedclose(true) workSpeedclose(true)
// if (seriesIndex === this.currentSeriesIndex) return // if (seriesIndex === this.currentSeriesIndex) return
@ -920,6 +925,7 @@ export default {
} }
if (this.visitTaskId === params.visitTaskId) { if (this.visitTaskId === params.visitTaskId) {
const seriesIndex = params.seriesIndex const seriesIndex = params.seriesIndex
if (!this.seriesList[seriesIndex]) return false
var prefetchInstanceCount = this.seriesList[seriesIndex].prefetchInstanceCount var prefetchInstanceCount = this.seriesList[seriesIndex].prefetchInstanceCount
var instanceCount = this.seriesList[seriesIndex].instanceCount var instanceCount = this.seriesList[seriesIndex].instanceCount
if (!this.activeSeriesId) { if (!this.activeSeriesId) {