Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web into main
continuous-integration/drone/push Build is passing Details

uat_us
caiyiling 2026-03-31 10:07:50 +08:00
commit 72d0494baa
4 changed files with 166 additions and 23 deletions

View File

@ -127,7 +127,6 @@ export default {
sliceThickness: null,
wwwc: null,
total: 0,
sliceThickness: 0
},
digitPlaces: 2,
orientationMarkers: [],
@ -277,6 +276,7 @@ export default {
let imageId = imageIds[0]
let volume = cache.getVolume(this.volumeId)
let spacing = volume ? volume.spacing : []
console.log(spacing, 'spacing')
// if (this.series.orientation === 'AXIAL') imageId = viewport.getCurrentImageId()
if (imageId && volume) {
this.$emit('setMPRInfo', { type: this.series.orientation, key: "imageNum", value: detail.numberOfSlices })
@ -501,7 +501,8 @@ export default {
DicomEvent.$emit("isloaded", {})
}
}]).then(r => {
if (data.isLocation) {
console.log(this.imageInfo.zoom, 'this.imageInfo.zoom')
if (data.isLocation || !this.imageInfo.zoom) {
setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); })
}
})

View File

@ -1401,7 +1401,9 @@ export default {
toolGroup.addTool(WindowLevelTool.toolName, {
targetViewportIds: volumeViewportIds
})
toolGroup.addTool(CrosshairsTool.toolName);
toolGroup.addTool(CrosshairsTool.toolName, {
getReferenceLineColor: this.setCrosshairsToolLineColor
});
} else {
toolGroup.addTool(WindowLevelTool.toolName)
}
@ -2037,6 +2039,21 @@ export default {
const viewport = renderingEngine.getViewport(viewportId)
viewport.render()
},
setCrosshairsToolLineColor(viewportId) {
let colors = [
'#0ca8df',
'#ffd10a',
'#b6d634',
'#3fbe95',
'#785db0',
'#5070dd',
'#505372',
'#ff994d',
'#fb628b',
]
let index = viewportId.split("-").pop()
return colors[colors.length - 1 - Number(index)] || colors[0]
},
getLengthToolTextLines(data, targetId) {
const cachedVolumeStats = data.cachedStats[targetId]
const { length, unit } = cachedVolumeStats
@ -2519,6 +2536,9 @@ export default {
viewport.resetProperties()
viewport.render()
renderingEngine.render()
if (this.readingTool === 3) {
DicomEvent.$emit('isloaded', {})
}
},
//
async changeLayout(v) {
@ -2797,6 +2817,18 @@ export default {
toggleFullScreen(e, index) {
this.fullScreenIndex = this.fullScreenIndex === index ? null : index
this.activeViewportIndex = index
if (this.readingTool === 3 || this.isMPR) {
// this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series)
this.$nextTick(() => {
const renderingEngine = getRenderingEngine(renderingEngineId)
renderingEngine.resize(true, false)
renderingEngine.render()
if (this.readingTool === 3) {
DicomEvent.$emit('isloaded', {})
}
})
}
if (this.isFusion) {
const viewportIds = [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`]
viewportIds.forEach(id => {
@ -2899,7 +2931,16 @@ export default {
this.activeViewportIndex = 0
this.fullScreenIndex = null
this.isMPR = false
return this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(obj)
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(obj)
return this.$nextTick(() => {
const renderingEngine = getRenderingEngine(renderingEngineId)
renderingEngine.resize(true, false)
renderingEngine.render()
if (this.readingTool === 3) {
DicomEvent.$emit('isloaded', {})
}
})
}
if (!obj.IsDicom) {
return this.previewNoneDicoms(obj)
@ -3523,9 +3564,9 @@ export default {
syncColormap: false
})
let viewportIds = [
`viewport-volume-0`,
`viewport-volume-1`,
`viewport-volume-2`
`viewport-MPR-0`,
`viewport-MPR-1`,
`viewport-MPR-2`
]
viewportIds.forEach((viewportId) => {
MPRVoiSynchronizer.add({

View File

@ -205,7 +205,9 @@
<svg-icon :icon-class="item && !item.view ? 'eye' : 'eye-open'"
@click.stop="viewSegment(item, !item.view)" class="docShow" />
<i class="el-icon-lock" v-if="item.lock" @click.stop="lockSegment(item, false)"></i>
<el-popover placement="bottom" width="40" trigger="click" class="docShow">
<el-popover placement="bottom" width="40" trigger="click" class="docShow"
:value="popoverId === `popover-${item.segmentationId}_${item.segmentIndex}`"
@show="handleClickPopover(item)">
<div class="SegmentGroupBtnBox">
<div class="SegmentGroupBtn" @click.stop="rename('segment', item)">
{{ $t('trials:reading:Segmentations:button:renameSegmentGroup') }}
@ -352,7 +354,8 @@ export default {
drawing: false, //
isDel: false,
digitPlaces: 2,
isloaded: false
isloaded: false,
popoverId: null
}
},
mounted() {
@ -376,6 +379,9 @@ export default {
})
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
// document.addEventListener("click", () => {
// this.popoverId = null
// });
},
computed: {
curSegmentGroup() {
@ -411,6 +417,9 @@ export default {
}
},
methods: {
handleClickPopover(item) {
this.popoverId = `popover-${item.segmentationId}_${item.segmentIndex}`
},
initThreshold() {
if (!this.ThresholdTools.includes(this.activeTool)) {
this.setToolActive(this.ThresholdTools[0])
@ -559,7 +568,7 @@ export default {
let item = arr[j]
let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
item.bidirectionalView = view
if (!bidirectional) return false
if (!bidirectional) continue
annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
}
this.resetViewport()
@ -715,18 +724,24 @@ export default {
} else {
let item = this.segmentList.find(i => i.segmentationId === this.segmentationId)
let segmentIndex = item.segments[item.segments.length - 1].segmentIndex + 1
let arr = item.segments.sort((a, b) => a.segmentIndex - b.segmentIndex)
let segmentIndex = arr[item.segments.length - 1].segmentIndex + 1
let obj = {
segmentIndex: segmentIndex,
segmentationId: this.segmentationId,
SegmentLabel: `Segment ${segmentIndex}`,
color: item.segments.length > this.colors.length ? this.colors[0] : this.colors[item.segments.length],
color: item.segments.length >= this.colors.length ? this.colors[0] : this.colors[item.segments.length],
stats: null,
bidirectional: null,
bidirectionalView: true,
view: true,
lock: false
}
if (item.segments.length >= this.colors.length) {
let index = item.segments.length % this.colors.length
let color = this.randomNearColor(this.colors[index], 4)
obj.color = color
}
let id = await this.addOrUpdateSegment({ name: obj.SegmentLabel, color: obj.color, segmentIndex: obj.segmentIndex, segmentationId: obj.segmentationId })
obj.id = id
item.segments.push(obj)
@ -1485,6 +1500,7 @@ export default {
})
}
this.isloaded = false
this.readingSegmentByConfig()
}
} catch (err) {
this.loading = false
@ -1589,6 +1605,87 @@ export default {
b = parseInt(rgb[3], 16);
return [r, g, b, alpha * 255];
},
randomNearColor(hex, range = 3) {
if (!/^#([0-9a-fA-F]{6})$/.test(hex)) {
throw new Error('请输入正确的 6 位十六进制颜色值,例如 #000000');
}
const hexToRgb = (hex) => ({
r: parseInt(hex.slice(1, 3), 16),
g: parseInt(hex.slice(3, 5), 16),
b: parseInt(hex.slice(5, 7), 16),
});
const rgbToHsl = (r, g, b) => {
r /= 255; g /= 255; b /= 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h = 0, s = 0;
const l = (max + min) / 2;
if (max !== min) {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h *= 60;
}
return { h, s: s * 100, l: l * 100 };
};
const hslToRgb = (h, s, l) => {
h /= 360; s /= 100; l /= 100;
let r, g, b;
if (s === 0) {
r = g = b = l;
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255),
};
};
const rgbToHex = (r, g, b) =>
`#${[r, g, b].map(v => v.toString(16).padStart(2, '0')).join('')}`;
const clamp = (v, min, max) => Math.min(max, Math.max(min, v));
const randomOffset = (n) => (Math.random() * 2 - 1) * n;
const { r, g, b } = hexToRgb(hex);
const { h, s, l } = rgbToHsl(r, g, b);
const nh = (h + randomOffset(range) + 360) % 360;
const ns = clamp(s + randomOffset(range), 0, 100);
const nl = clamp(l + randomOffset(range), 0, 100);
const rgb = hslToRgb(nh, ns, nl);
return rgbToHex(rgb.r, rgb.g, rgb.b);
}
},
}

View File

@ -281,6 +281,10 @@ export default {
this.imageInfo.size = `${imagePlaneModule.columns}*${imagePlaneModule.rows}`
this.imageInfo.location = imagePlaneModule.sliceLocation
this.imageInfo.total = detail.numberOfSlices
let type = this.determineImagePlane(imagePlaneModule.imageOrientationPatient)
let volume = cache.getVolume(this.volumeId)
let spacing = volume ? volume.spacing : []
this.imageInfo.sliceThickness = type === 'AXIAL' ? spacing[2] : spacing[0]
this.getOrientationMarker()
if (this.series && this.series.Id) {
let annotations = cornerstoneTools.annotation.state.getAllAnnotations().filter(item => item.metadata.toolName !== 'ScaleOverlay' && item.metadata.volumeId !== this.volumeId && !item.metadata.segmentationId && item.seriesId !== this.series.Id)