阅片添加分割工具

uat_us
wangxiaoshuang 2026-03-23 10:01:22 +08:00
parent 18a71725f9
commit 266886fa64
25 changed files with 3783 additions and 564 deletions

View File

@ -115,8 +115,7 @@ export default {
} }
}, },
mounted() { mounted() {
// this.show = process.env.VUE_APP_OSS_PATH === '/test/dist' this.show = process.env.VUE_APP_OSS_PATH === '/test/dist'
this.show = false
Vue.prototype.$openI18n = this.openI18n Vue.prototype.$openI18n = this.openI18n
}, },
// watch: { // watch: {

View File

@ -319,3 +319,84 @@ export function getReportsChartData(param) {
data: param data: param
}) })
} }
// 分割相关
// 获取分割组
export function getSegmentationList(param) {
return request({
url: `/Segmentation/getSegmentationList`,
method: 'post',
data: param
})
}
// 新增修改分割组
export function addOrUpdateSegmentation(param) {
return request({
url: `/Segmentation/addOrUpdateSegmentation`,
method: 'post',
data: param
})
}
// 删除分割组
export function deleteSegmentation(segmentationId) {
return request({
url: `/Segmentation/deleteSegmentation/${segmentationId}`,
method: 'delete'
})
}
// 获取分割
export function getSegmentList(param) {
return request({
url: `/Segmentation/getSegmentList`,
method: 'post',
data: param
})
}
// 新增修改分割
export function addOrUpdateSegment(param) {
return request({
url: `/Segmentation/addOrUpdateSegment`,
method: 'post',
data: param
})
}
// 删除分割
export function deleteSegment(segmentId) {
return request({
url: `/Segmentation/deleteSegment/${segmentId}`,
method: 'delete'
})
}
// 获取分割绑定关系
export function getSegmentBindingList(param) {
return request({
url: `/Segmentation/getSegmentBindingList`,
method: 'post',
data: param
})
}
// 保存分割绑定关系(可用作修改删除)
export function saveSegmentBindingAndAnswer(param) {
return request({
url: `/Segmentation/saveSegmentBindingAndAnswer`,
method: 'post',
data: param
})
}
// 获取表格问题配置
export function getReadingTableQuestionTrialById(params) {
return request({
url: `/ReadingQuestion/getReadingTableQuestionTrialById`,
method: 'post',
params
})
}
// 获取外层问题配置
export function getReadingQuestionTrialById(params) {
return request({
url: `/ReadingQuestion/getReadingQuestionTrialById`,
method: 'post',
params
})
}

12
src/icons/svg/contour.svg Normal file
View File

@ -0,0 +1,12 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" class="h-6 w-6" color="#fff">
<path
d="M10.3945 12.6113C10.043 12.6113 9.78516 12.3945 9.78516 12.0371C9.78516 11.6855 10.043 11.4688 10.3945 11.4688H13.2012C13.5527 11.4688 13.8164 11.6855 13.8164 12.0371C13.8164 12.3945 13.5527 12.6113 13.2012 12.6113H10.3945Z"
fill="currentColor"></path>
<path opacity="0.5"
d="M18.312 6.84473C21.8473 8.88583 22.9225 13.6424 20.7134 17.4687C18.5042 21.2951 13.8473 22.7422 10.312 20.7011C9.51661 20.2419 8.84737 19.6439 8.31042 18.9512C11.3012 19.3598 14.4827 17.8251 16.1946 14.8598C17.9067 11.8945 17.6457 8.3712 15.7963 5.98538C16.6645 6.10409 17.5167 6.38556 18.312 6.84473Z"
fill="currentColor"></path>
<circle cx="13.7852" cy="13.4688" r="8" stroke="currentColor"></circle>
<path
d="M4.50586 8.22266C4.14844 8.22266 3.92578 7.9707 3.92578 7.60742V5.68555H2.10352C1.74609 5.68555 1.5 5.46875 1.5 5.11719C1.5 4.76562 1.74609 4.54297 2.10352 4.54297H3.92578V2.61523C3.92578 2.25195 4.14844 2 4.50586 2C4.85742 2 5.08008 2.25195 5.08008 2.61523V4.54297H6.89648C7.25391 4.54297 7.50586 4.76562 7.50586 5.11719C7.50586 5.46875 7.25391 5.68555 6.89648 5.68555H5.08008V7.60742C5.08008 7.9707 4.85742 8.22266 4.50586 8.22266Z"
fill="currentColor"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

1
src/icons/svg/fill.svg Normal file
View File

@ -0,0 +1 @@
<svg width="18px" height="18px" viewBox="0 0 18 18" class="text-primary"><g id="view-fill" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Group-13"><rect id="Rectangle" x="0" y="0" width="18" height="18"></rect><rect id="Rectangle" fill="currentColor" x="2" y="2" width="14" height="14" rx="1"></rect></g></g></svg>

After

Width:  |  Height:  |  Size: 338 B

View File

@ -0,0 +1 @@
<svg width="18px" height="18px" viewBox="0 0 18 18" class="text-primary"><g id="view-outline-fill" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Group-13"><rect id="Rectangle" x="0" y="0" width="18" height="18"></rect><rect id="Rectangle" stroke="currentColor" x="1.5" y="1.5" width="15" height="15" rx="1"></rect><rect id="Rectangle" fill="currentColor" x="3.5" y="3.5" width="11" height="11" rx="1"></rect></g></g></svg>

After

Width:  |  Height:  |  Size: 446 B

View File

@ -0,0 +1 @@
<svg width="18px" height="18px" viewBox="0 0 18 18" class="text-primary"><g id="view-outline" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Group-13"><rect id="Rectangle" x="0" y="0" width="18" height="18"></rect><rect id="Rectangle" stroke="currentColor" x="1.5" y="1.5" width="15" height="15" rx="1"></rect></g></g></svg>

After

Width:  |  Height:  |  Size: 347 B

View File

@ -0,0 +1,823 @@
<template>
<div ref="viewport-volume" class="viewport-wrapper" v-loading="loading" :element-loading-text="NSTip"
element-loading-background="rgba(0, 0, 0, 0.8)" @mouseup="sliderMouseup" @mousemove="sliderMousemove"
@mouseleave="sliderMouseleave" :style="{ color: '#ddd' }">
<div v-if="series && taskInfo" class="left-top-text">
<div v-if="taskInfo.IsExistsClinicalData" class="cd-info" :title="$t('trials:reading:button:clinicalData')">
<svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
@click.stop="viewCD(series.TaskInfo.VisitTaskId)" />
</div>
<h2 v-if="taskInfo.IsReadingShowSubjectInfo && series.TaskInfo" class="subject-info">
{{ `${series.TaskInfo.SubjectCode} ${series.TaskInfo.TaskBlindName} ` }}
</h2>
<div>Series: #{{ series.SeriesNumber }}</div>
<div v-if="imageInfo.total">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div>
<div>{{ series.Modality }}</div>
</div>
<div v-if="series" class="right-top-text">
<div>{{ series.Description }}</div>
</div>
<div v-if="series" class="left-bottom-text">
<div v-show="mousePosition.index.length > 0">
Pos: {{ mousePosition.index[0] }}, {{ mousePosition.index[1] }}, {{ mousePosition.index[2] }}
</div>
<div
v-if="(series.Modality === 'CT' || series.Modality === 'DR' || series.Modality === 'CR') && mousePosition.value">
HU: {{ mousePosition.value }}
</div>
<div v-else-if="(series.Modality === 'PT' && mousePosition.value)">
SUVbw(g/ml): {{ digitPlaces === -1 ? mousePosition.value.toFixed(3) :
mousePosition.value.toFixed(digitPlaces)
}}
</div>
<div v-else-if="mousePosition.value">
Density: {{ mousePosition.value }}
</div>
<div v-show="imageInfo.size">
W*H: {{ imageInfo.size }}
</div>
</div>
<div v-if="series" class="right-bottom-text">
<div v-show="imageInfo.location">Location: {{
`${Number(imageInfo.location).toFixed(digitPlaces)} mm`
}}</div>
<div v-show="imageInfo.sliceThickness">Slice Thickness: {{
`${Number(imageInfo.sliceThickness).toFixed(digitPlaces)} mm`
}}</div>
<div v-show="imageInfo.wwwc">WW/WL: {{ imageInfo.wwwc }}</div>
</div>
<div class="orientation-top">
{{ markers.top }}
</div>
<div class="orientation-right">
{{ markers.right }}
</div>
<div class="orientation-bottom">
{{ markers.bottom }}
</div>
<div class="orientation-left">
{{ markers.left }}
</div>
<div ref="sliderBox" class="right-slider-box" @click.stop="clickSlider($event)">
<div :style="{ top: sliderInfo.height + '%' }" class="slider" @click.stop.prevent="() => { return }"
@mousedown.stop="sliderMousedown($event)" />
</div>
</div>
</template>
<script>
import {
metaData,
getRenderingEngine,
utilities as csUtils,
cache
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData'
import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
import { setPetColorMapTransferFunctionForVolumeActor } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetColorMapTransferFunctionForVolumeActor'
import { vec3, mat4 } from 'gl-matrix'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
export default {
name: 'MPRViewport',
props: {
renderingEngineId: {
type: String,
required: true
},
viewportId: {
type: String,
required: true
},
viewportIndex: {
type: Number,
required: true
},
MPRInfo: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
element: '',
series: {},
ctSeries: {},
petSeries: {},
taskInfo: null,
sliderInfo: {
oldB: null,
oldM: null,
isMove: false,
height: 0
},
mousePosition: {
index: [],
value: null,
modalityUnit: '',
world: []
},
imageInfo: {
zoom: null,
size: null,
location: null,
sliceThickness: null,
wwwc: null,
total: 0,
sliceThickness: 0
},
digitPlaces: 2,
orientationMarkers: [],
originalMarkers: [],
markers: { top: '', right: '', bottom: '', left: '' },
playClipState: false,
wwwcIdx: 2,
presetName: '',
volumeId: null,
defaultWindowLevel: {},
rotateAngle: 0,
rotateBarLeft: 0,
loading: false,
}
},
mounted() {
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.$nextTick(() => {
this.initViewport()
})
},
watch: {
MPRInfo: {
handler() {
if (!this.series.orientation) return false
switch (this.series.orientation) {
case 'AXIAL':
this.imageInfo.size = `${this.MPRInfo.SAGITTAL.imageNum}*${this.MPRInfo.CORONAL.imageNum}`
break;
case 'CORONAL':
this.imageInfo.size = `${this.MPRInfo.SAGITTAL.imageNum}*${this.MPRInfo.AXIAL.imageNum}`
break;
case 'SAGITTAL':
this.imageInfo.size = `${this.MPRInfo.CORONAL.imageNum}*${this.MPRInfo.AXIAL.imageNum}`
break;
}
},
deep: true
}
},
methods: {
initViewport() {
this.element = this.$refs['viewport-volume']
const resizeObserver = new ResizeObserver(() => {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
if (renderingEngine) {
renderingEngine.resize(true, false)
}
})
this.element.oncontextmenu = (e) => e.preventDefault()
// resizeObserver.observe(this.element)
this.element.addEventListener("CORNERSTONE_VOLUME_NEW_IMAGE", this.stackNewImage)
this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
this.element.addEventListener('wheel', (e) => {
// console.log('CORNERSTONE_STACK_VIEWPORT_SCROLL')
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const currentImageIdIndex = viewport.getCurrentImageIdIndex()
const totalImages = this.imageInfo.total;
//
if (currentImageIdIndex >= totalImages - 1) {
//
csUtils.jumpToSlice(viewport.element, { imageIndex: 0 });
} else if (currentImageIdIndex <= 0) {
//
csUtils.jumpToSlice(viewport.element, { imageIndex: totalImages - 1 });
}
});
this.element.addEventListener('CORNERSTONE_TOOLS_MOUSE_MOVE', this.cornerstoneToolsMouseMove)
// this.element.addEventListener(cornerstoneTools.Enums.Events.MOUSE_WHEEL, this.handletoolsMouseWheel)
this.element.addEventListener('mouseleave', () => {
this.mousePosition.index = []
this.mousePosition.value = null
})
document.addEventListener('mouseup', () => {
this.sliderMouseup()
})
document.addEventListener('mousemove', (e) => {
this.sliderMousemove(e)
})
},
determineImagePlane(imageOrientationPatient) {
// imageOrientationPatient [rowX, rowY, rowZ, colX, colY, colZ]
// (rowX, rowY, rowZ)
const [rowX, rowY, rowZ] = imageOrientationPatient;
// X, Y, Z
const dotX = Math.abs(rowX);
const dotY = Math.abs(rowY);
const dotZ = Math.abs(rowZ);
//
const maxDot = Math.max(dotX, dotY, dotZ);
//
if (maxDot === dotX) {
// X 线 Y Z
// 线
//
// X-Y (rowZ ) Axial
// X-Z (rowY ) Sagittal
// 线线
// 线 = ×
const [colX, colY, colZ] = imageOrientationPatient.slice(3);
const normalX = rowY * colZ - rowZ * colY;
const normalY = rowZ * colX - rowX * colZ;
const normalZ = rowX * colY - rowY * colX;
const absNormalX = Math.abs(normalX);
const absNormalY = Math.abs(normalY);
const absNormalZ = Math.abs(normalZ);
const maxNormal = Math.max(absNormalX, absNormalY, absNormalZ);
if (maxNormal === absNormalZ) {
return 'AXIAL';
} else if (maxNormal === absNormalY) {
return 'SAGITTAL';
} else if (maxNormal === absNormalX) {
return 'CORONAL';
}
} else if (maxDot === dotY) {
// Y Coronal
return 'SAGITTAL';
} else if (maxDot === dotZ) {
// Z Sagittal
return 'CORONAL';
}
return 'unknown';
},
stackNewImage(e) {
const { detail } = e
this.series.SliceIndex = detail.imageIndex
this.sliderInfo.height = detail.imageIndex * 100 / detail.numberOfSlices
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4)
let imageIds = viewport.getImageIds(this.volumeId)
let imageId = imageIds[0]
let volume = cache.getVolume(this.volumeId)
let spacing = volume ? volume.spacing : []
// if (this.series.orientation === 'AXIAL') imageId = viewport.getCurrentImageId()
if (imageId && volume) {
this.$emit('setMPRInfo', { type: this.series.orientation, key: "imageNum", value: detail.numberOfSlices })
const imagePlaneModule = metaData.get('imagePlaneModule', imageId)
let type = this.determineImagePlane(imagePlaneModule.imageOrientationPatient)
this.imageInfo.location = type === this.series.orientation ? imagePlaneModule.sliceLocation : ''
this.imageInfo.sliceThickness = type === this.series.orientation ? spacing[2] : spacing[0]
this.imageInfo.total = detail.numberOfSlices
this.getOrientationMarker()
let properties = viewport.getProperties(this.volumeId)
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const windowWidth = upper - lower
const windowCenter = (upper + lower) / 2
this.defaultWindowLevel.windowWidth = windowWidth
this.defaultWindowLevel.windowCenter = windowCenter
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
}
}
if (volume) {
const toolGroupId = 'share-viewport-volume'
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId)
toolGroup.setToolEnabled('ScaleOverlay')
}
// const toolGroupId = this.viewportId
},
setFullScreen(index) {
setTimeout(() => {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
csUtils.jumpToSlice(viewport.element, { imageIndex: index })
viewport.render()
})
},
voiModified(e) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
let properties = viewport.getProperties()
if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
lower,
upper
)
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
this.$emit('upperRangeChange', Math.round(windowWidth))
}
},
getOrientationMarker() {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const { viewUp, viewPlaneNormal } = viewport.getCamera()
const viewRight = vec3.create()
vec3.cross(viewRight, viewUp, viewPlaneNormal)
const columnCosines = [-viewUp[0], -viewUp[1], -viewUp[2]]
const rowCosines = viewRight
const rowString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(rowCosines)
const columnString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(columnCosines)
const oppositeRowString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(rowString)
const oppositeColumnString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(columnString)
this.markers.top = oppositeColumnString
this.markers.right = rowString
this.markers.bottom = columnString
this.markers.left = oppositeRowString
this.orientationMarkers = [oppositeColumnString, rowString, columnString, oppositeRowString]
if (this.originalMarkers.length === 0) {
this.originalMarkers = [...this.orientationMarkers]
}
},
setMarkers() {
const markers = [...this.orientationMarkers]
for (const key in this.markers) {
const v = markers.shift(0)
this.markers[key] = v
}
},
resetOrientationMarkers() {
if (this.originalMarkers.length > 0) {
this.orientationMarkers = [...this.originalMarkers]
this.setMarkers()
}
},
rotateOrientationMarkers(type) {
if (this.orientationMarkers.length > 0) {
if (type === 1) {
this.resetOrientationMarkers()
return
}
const markers = [...this.orientationMarkers]
if (type === 2) {
//
this.orientationMarkers[0] = markers[2]
this.orientationMarkers[2] = markers[0]
} else if (type === 3) {
//
this.orientationMarkers[1] = markers[3]
this.orientationMarkers[3] = markers[1]
} else if (type === 4) {
// 90
this.orientationMarkers = markers.slice(1, 4).concat(markers[0])
} else if (type === 5) {
// 90
this.orientationMarkers = [markers[3]].concat(markers.slice(0, 3))
}
this.setMarkers()
}
},
toggleClipPlay(isPlay, framesPerSecond) {
this.playClipState = isPlay
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (isPlay) {
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: true })
} else {
cornerstoneTools.utilities.cine.stopClip(viewport.element)
}
},
scrollPage(type) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const currentImageIdIndex = viewport.getCurrentImageIdIndex()
const numImages = viewport.getImageIds().length
let newImageIdIndex = null
if (type === 0) {
newImageIdIndex = 0
} else if (type === -1) {
newImageIdIndex = currentImageIdIndex === 0 ? currentImageIdIndex : currentImageIdIndex - 1
} else if (type === 1) {
newImageIdIndex = currentImageIdIndex === numImages - 1 ? currentImageIdIndex : currentImageIdIndex + 1
} else if (type === 99999) {
newImageIdIndex = numImages - 1
}
// viewport.setImageIdIndex(newImageIdIndex)
csUtils.jumpToSlice(viewport.element, { imageIndex: newImageIdIndex })
cornerstoneTools.utilities.cine.stopClip(viewport.element)
},
setZoom(ratio) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom()
if (ratio > 0) {
viewport.setZoom(zoom * 1.05)
} else {
viewport.setZoom(zoom / 1.05)
}
viewport.render()
},
resize(forceFitToWindow) {
console.log('resize: ', forceFitToWindow)
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (!forceFitToWindow) {
viewport.setZoom(0.5)
viewport.render()
} else {
viewport.setZoom(1)
viewport.render()
}
},
voiChange(v) {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const voiRange = { lower: 0, upper: v }
const viewport = renderingEngine.getViewport(this.viewportId)
if (!viewport) return
let volumeId = this.volumeId
const viewportsContainingVolumeUID = csUtils.getViewportsWithVolumeId(
volumeId,
viewport.renderingEngineId
)
viewport.setProperties({ voiRange }, volumeId)
viewportsContainingVolumeUID.forEach((vp) => {
vp.render()
// this.$refs[vp.id].voiModified()
this.voiModified()
})
},
setPreset(presetName) {
this.presetName = presetName
},
async createImageIdsAndCacheMetaData(obj) {
this.loading = true
await createImageIdsAndCacheMetaData({
modality: obj.Modality,
imageIds: obj.ImageIds
})
this.loading = false
},
async setSeriesInfo(obj, isLocate = false) {
try {
let data = obj
if (this.series && data.Id === this.series.Id && data.Description === this.series.Description && !isLocate && !data.isLocation) {
data.SliceIndex = this.series.SliceIndex
}
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
if (isLocate) return csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex });
this.series = {}
this.volumeId = data.SeriesInstanceUid
this.series = { ...data }
viewport
.setVolumes([{
volumeId: this.volumeId, callback: (r) => {
if (this.series.Modality === 'PT') {
setPetColorMapTransferFunctionForVolumeActor(r, true)
} else {
setCtTransferFunctionForVolumeActor(r)
}
console.log("渲染成功")
DicomEvent.$emit("isloaded", {})
}
}]).then(res => {
if (data.isLocation) {
setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); })
}
})
viewport.render()
} catch (e) {
console.log(e)
}
},
cornerstoneToolsMouseMove(e) {
const { currentPoints } = e.detail
const worldPoint = currentPoints.world
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const imageData = viewport.getImageData()
if (!imageData) return
const index = imageData.imageData.worldToIndex(worldPoint)
index[0] = Math.floor(index[0])
index[1] = Math.floor(index[1])
index[2] = Math.floor(index[2])
this.mousePosition.index = index
},
toggleTask(evt, visitTaskNum, i) {
this.$emit('activeViewport', this.viewportIndex)
const num = visitTaskNum + i
if (num >= 0 && num <= this.taskInfo.VisitNum) {
this.$emit('toggleTaskByViewport', { series: this.series, visitTaskNum: num })
}
evt.stopImmediatePropagation()
evt.stopPropagation()
evt.preventDefault()
},
viewCD(taskId) {
this.$emit('previewCD', taskId)
},
setWwwcIdx(idx) {
this.wwwcIdx = idx
},
clickSlider(e) {
const height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
this.sliderInfo.height = height
let sliceIdx = Math.trunc(this.imageInfo.total * height / 100)
sliceIdx = sliceIdx >= this.imageInfo.total ? this.imageInfo.total : sliceIdx < 0 ? 0 : sliceIdx
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseup(e) {
this.sliderInfo.isMove = false
this.$emit('contentMouseup', e)
},
sliderMousedown(e) {
const boxHeight = this.$refs['sliderBox'].clientHeight
this.sliderInfo.oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
this.sliderInfo.oldM = e.clientY
this.sliderInfo.isMove = true
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
},
sliderMousemove(e) {
if (!this.sliderInfo.isMove) return
const delta = this.sliderInfo.oldB - (this.sliderInfo.oldM - e.clientY)
const boxHeight = this.$refs['sliderBox'].clientHeight
if (delta < 0) return
if (delta > boxHeight) return
const height = delta * 100 / boxHeight
let sliceIdx = Math.trunc(this.imageInfo.total * height / 100)
sliceIdx = sliceIdx >= this.imageInfo.total ? this.imageInfo.total - 1 : sliceIdx < 0 ? 0 : sliceIdx
this.sliderInfo.height = height
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(
this.viewportId
)
// viewport.setImageIdIndex(sliceIdx)
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIdx })
viewport.render()
},
sliderMouseleave(e) {
if (!this.sliderInfo.isMove) return
this.sliderInfo.isMove = false
},
rotate(angle) {
let renderingEngine = getRenderingEngine(this.renderingEngineId)
let viewport = renderingEngine.getViewport(this.viewportId)
const camera = viewport.getCamera()
const { viewUp, position, focalPoint } = camera
const [cx, cy, cz] = focalPoint
const [ax, ay, az] = [0, 0, 1]
const newPosition = [0, 0, 0]
const newFocalPoint = [0, 0, 0]
const newViewUp = [0, 0, 0]
const transform = mat4.identity(new Float32Array(16))
mat4.translate(transform, transform, [cx, cy, cz])
mat4.rotate(transform, transform, angle, [ax, ay, az])
mat4.translate(transform, transform, [-cx, -cy, -cz])
vec3.transformMat4(newPosition, position, transform)
vec3.transformMat4(newFocalPoint, focalPoint, transform)
mat4.identity(transform)
mat4.rotate(transform, transform, angle, [ax, ay, az])
vec3.transformMat4(newViewUp, viewUp, transform)
viewport.setCamera({
position: newPosition,
viewUp: newViewUp,
focalPoint: newFocalPoint
})
viewport.render()
},
clickRotate(e) {
// console.log('clickRotate')
const container = document.getElementById('rotateBar')
const containerWidth = container.offsetWidth
const slider = document.getElementById('rotateSlider')
const sliderWidth = slider.offsetWidth
const x = Math.trunc(e.offsetX)
const deltaX = x - this.rotateBarLeft
const angle = Math.sin((deltaX * (360 / (containerWidth - sliderWidth))) * Math.PI / 180)
this.rotate(angle)
this.rotateBarLeft = x
},
preventDefault(e) {
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
}
},
computed: {
NSTip() {
return `NS: ${this.$store.state.trials.uploadTip}`
}
},
}
</script>
<style lang="scss" scoped>
.viewport-wrapper {
width: 100%;
height: 100%;
position: relative;
cursor: default !important;
.left-top-text {
position: absolute;
left: 5px;
top: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
.cd-info {
// color: #ddd;
font-size: 18px;
}
.subject-info {
color: #f44336;
padding: 5px 0px;
margin: 0;
}
}
.top-center-tool {
position: absolute;
left: 50%;
top: 5px;
transform: translateX(-50%);
z-index: 1;
.toggle-visit-container {
display: flex;
}
.arrw_icon {
width: 20px;
height: 20px;
background-color: #3f3f3f;
text-align: center;
line-height: 20px;
border-radius: 10%;
}
.arrow_text {
height: 20px;
line-height: 20px;
background-color: #00000057;
color: #fff;
padding: 0 10px;
font-size: 14px;
}
}
.right-top-text {
position: absolute;
right: 5px;
top: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
}
.left-bottom-text {
position: absolute;
left: 5px;
bottom: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-bottom-text {
position: absolute;
right: 5px;
bottom: 5px;
// color: #ddd;
z-index: 1;
font-size: 12px;
}
.right-slider-box {
position: absolute;
right: 1px;
height: calc(100% - 140px);
transform: translateY(-50%);
top: calc(50% - 30px);
width: 10px;
background: #333;
z-index: 1;
cursor: pointer;
}
.right-slider-box:after {
content: '';
position: absolute;
bottom: -20px;
left: 0;
height: 20px;
width: 100%;
background: #333;
}
.slider {
height: 20px;
width: 100%;
position: absolute;
top: 0;
z-index: 10;
background: #9e9e9e;
cursor: move
}
.orientation-top {
position: absolute;
left: 50%;
top: 30px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-bottom {
position: absolute;
left: 50%;
bottom: 15px;
color: #f44336;
transform: translateX(-50%);
z-index: 1;
}
.orientation-left {
position: absolute;
top: 50%;
left: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
.orientation-right {
position: absolute;
top: 50%;
right: 15px;
color: #f44336;
transform: translateY(-50%);
z-index: 1;
}
}
.color_bar {
position: absolute;
transform: rotate(-90deg);
transform-origin: right;
left: -150px;
top: 30%;
z-index: 1;
}
.rotate_slider_box {
position: absolute;
width: 380px;
height: 10px;
bottom: 5px;
left: 50%;
transform: translateX(-50%);
background: #333;
z-index: 10;
cursor: pointer;
.box {
z-index: 10;
background: #9e9e9e;
height: 100%;
width: 20px;
position: absolute;
top: 0;
cursor: move
}
}
</style>

View File

@ -162,7 +162,7 @@
</div> </div>
<!-- MPR --> <!-- MPR -->
<div class="tool-item" :title="`${$t('trials:reading:button:mpr')}`" @click.prevent="openMPRViewport()" <div class="tool-item" :title="`${$t('trials:reading:button:mpr')}`" @click.prevent="openMPRViewport()"
v-if="criterionType === 0 && readingTool === 0"> v-if="(criterionType === 0 && readingTool === 0) || this.readingTool === 3">
<svg-icon icon-class="mpr" class="svg-icon" style="transform: rotate(180deg);" /> <svg-icon icon-class="mpr" class="svg-icon" style="transform: rotate(180deg);" />
</div> </div>
<!-- 十字准星 --> <!-- 十字准星 -->
@ -299,24 +299,29 @@
<!-- viewports --> <!-- viewports -->
<div class="viewports-wrapper"> <div class="viewports-wrapper">
<div ref="container" class="grid-container"> <div ref="container" class="grid-container">
<!-- isMPR && index === 2 ? 'grid-cell-3' : '', -->
<div :class="['viewports-box', isFusion || isMPR ? 'viewports-box-down' : '']" :style="gridStyle"> <div :class="['viewports-box', isFusion || isMPR ? 'viewports-box-down' : '']" :style="gridStyle">
<div v-for="(v, index) in cellsMax" v-show="index < cells.length" :key="`viewport-${index}`" <div v-for="(v, index) in cellsMax" v-show="index < cells.length" :key="`viewport-${index}`"
:style="cellStyle" :style="cellStyle"
:class="['grid-cell', isMPR && index === 2 ? 'grid-cell-3' : '', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']" :class="['grid-cell', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)"> @dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
<VolumeViewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`"
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="index"
@activeViewport="activeViewport" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" v-if="readingTool === 3" />
<Viewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`" <Viewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`"
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="index" :rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="index"
@activeViewport="activeViewport" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD" @activeViewport="activeViewport" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" /> @renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" v-else />
</div> </div>
</div> </div>
<div v-if="criterionType === 0 && readingTool === 0" <div v-if="(criterionType === 0 && readingTool === 0) || readingTool === 3"
:class="['viewports-box', !isMPR ? 'viewports-box-down' : '']" :style="gridStyle"> :class="['viewports-box', !isMPR ? 'viewports-box-down' : '']" :style="gridStyleMPR">
<div v-for="(v, index) in 3" :key="`viewport-volume-${index}`" :style="cellStyle" <div v-for="(v, index) in 3" :key="`viewport-MPR-${index}`" :style="cellStyle"
:class="['grid-cell', isMPR && index === 0 ? 'grid-cell-3' : '', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']" :class="['grid-cell', index === 0 ? 'grid-cell-3' : '', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)"> @dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
<VolumeViewport :ref="`viewport-volume-${index}`" :data-viewport-uid="`viewport-volume-${index}`" <MPRViewport :ref="`viewport-MPR-${index}`" :data-viewport-uid="`viewport-MPR-${index}`"
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-volume-${index}`" :rendering-engine-id="renderingEngineId" :viewport-id="`viewport-MPR-${index}`"
:viewport-index="index" :MPRInfo="MPRInfo" @activeViewport="activeViewport" @setMPRInfo="setMPRInfo" :viewport-index="index" :MPRInfo="MPRInfo" @activeViewport="activeViewport" @setMPRInfo="setMPRInfo"
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" /> @renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" />
@ -340,23 +345,49 @@
</div> </div>
<!-- 表单 --> <!-- 表单 -->
<div class="form-wrapper"> <div class="form-wrapper">
<el-tabs v-model="formWrapperActiveName" v-if="readingTool === 3" @tab-click="handleClick">
<el-tab-pane :label="$t('trials:reading:dicom3D:tabs:ecrf')" name="ecrf">
<div v-for="s in visitTaskList" v-show="lastViewportTaskId === s.VisitTaskId" :key="s.VisitTaskId" <div v-for="s in visitTaskList" v-show="lastViewportTaskId === s.VisitTaskId" :key="s.VisitTaskId"
style="height: 100%;"> style="height: 100%;">
<mRecisit v-if="lastViewportTaskId && criterionType === 7 && lastViewportTaskIds.includes(s.VisitTaskId)" <customize-question-list
v-if="lastViewportTaskId && criterionType === 0 && lastViewportTaskIds.includes(s.VisitTaskId)"
:ref="`ecrf_${s.VisitTaskId}`"
:reading-task-state="taskInfo && currentVisitInfo.VisitTaskId === taskInfo.VisitTaskId ? readingTaskState : 2"
:last-viewport-task-id="lastViewportTaskId" :visit-info="s" @resetAnnotations="resetAnnotations"
@setReadingTaskState="setReadingTaskState" @viewCustomAnnotationSeries="viewCustomAnnotationSeries"
@getCustomScreenshots="getCustomScreenshots" @setReadingToolActive="setReadingToolActive"
@setReadingToolPassive="setReadingToolPassive" @handleReadingChart="handleReadingChart"
@openSegmentForm="openSegmentForm" />
</div>
</el-tab-pane>
<el-tab-pane :label="$t('trials:reading:dicom3D:tabs:segment')" name="segment">
<Segmentations ref="Segmentations" :visitInfo="taskInfo" :isMPR="isMPR"
:volumeToolGroupId="volumeToolGroupId" :viewportKey="viewportKey"
:activeViewportIndex="activeViewportIndex" :activeTool.sync="activeTool"
:actionConfiguration="actionConfiguration" @setToolsPassive="setToolsPassive" @resetQuestion="resetQuestion"/>
</el-tab-pane>
</el-tabs>
<template v-else>
<div v-for="s in visitTaskList" v-show="lastViewportTaskId === s.VisitTaskId" :key="s.VisitTaskId"
style="height: 100%;">
<mRecisit
v-if="lastViewportTaskId && criterionType === 7 && lastViewportTaskIds.includes(s.VisitTaskId)"
:ref="`ecrf_${s.VisitTaskId}`" :ref="`ecrf_${s.VisitTaskId}`"
:reading-task-state="currentVisitInfo.VisitTaskId === taskInfo.VisitTaskId ? readingTaskState : 2" :reading-task-state="currentVisitInfo.VisitTaskId === taskInfo.VisitTaskId ? readingTaskState : 2"
:last-viewport-task-id="lastViewportTaskId" :visit-info="s" @removeAnnotation="removeAnnotation" :last-viewport-task-id="lastViewportTaskId" :visit-info="s" @removeAnnotation="removeAnnotation"
@getScreenshots="getScreenshots" @setMarkName="setMarkName" @imageLocation="imageLocation" @getScreenshots="getScreenshots" @setMarkName="setMarkName" @imageLocation="imageLocation"
@resetAnnotations="resetAnnotations" @getAnnotations="getAnnotations" @setToolToTarget="setToolToTarget" @resetAnnotations="resetAnnotations" @getAnnotations="getAnnotations"
@handleReadingChart="handleReadingChart" @setReadingToolPassive="setReadingToolPassive" /> @setToolToTarget="setToolToTarget" @handleReadingChart="handleReadingChart"
@setReadingToolPassive="setReadingToolPassive" />
<recisit <recisit
v-else-if="lastViewportTaskId && criterionType === 1 && lastViewportTaskIds.includes(s.VisitTaskId)" v-else-if="lastViewportTaskId && criterionType === 1 && lastViewportTaskIds.includes(s.VisitTaskId)"
:ref="`ecrf_${s.VisitTaskId}`" :ref="`ecrf_${s.VisitTaskId}`"
:reading-task-state="currentVisitInfo.VisitTaskId === taskInfo.VisitTaskId ? readingTaskState : 2" :reading-task-state="currentVisitInfo.VisitTaskId === taskInfo.VisitTaskId ? readingTaskState : 2"
:last-viewport-task-id="lastViewportTaskId" :visit-info="s" @removeAnnotation="removeAnnotation" :last-viewport-task-id="lastViewportTaskId" :visit-info="s" @removeAnnotation="removeAnnotation"
@getScreenshots="getScreenshots" @setMarkName="setMarkName" @imageLocation="imageLocation" @getScreenshots="getScreenshots" @setMarkName="setMarkName" @imageLocation="imageLocation"
@resetAnnotations="resetAnnotations" @getAnnotations="getAnnotations" @setToolToTarget="setToolToTarget" @resetAnnotations="resetAnnotations" @getAnnotations="getAnnotations"
@handleReadingChart="handleReadingChart" @setReadingToolPassive="setReadingToolPassive" /> @setToolToTarget="setToolToTarget" @handleReadingChart="handleReadingChart"
@setReadingToolPassive="setReadingToolPassive" />
<customize-question-list <customize-question-list
v-else-if="lastViewportTaskId && criterionType === 0 && lastViewportTaskIds.includes(s.VisitTaskId)" v-else-if="lastViewportTaskId && criterionType === 0 && lastViewportTaskIds.includes(s.VisitTaskId)"
:ref="`ecrf_${s.VisitTaskId}`" :ref="`ecrf_${s.VisitTaskId}`"
@ -366,6 +397,7 @@
@getCustomScreenshots="getCustomScreenshots" @setReadingToolActive="setReadingToolActive" @getCustomScreenshots="getCustomScreenshots" @setReadingToolActive="setReadingToolActive"
@setReadingToolPassive="setReadingToolPassive" @handleReadingChart="handleReadingChart" /> @setReadingToolPassive="setReadingToolPassive" @handleReadingChart="handleReadingChart" />
</div> </div>
</template>
</div> </div>
</div> </div>
</div> </div>
@ -444,6 +476,11 @@
@close="closeFusion" @fusion="handleFusion" /> @close="closeFusion" @fusion="handleFusion" />
</el-dialog> </el-dialog>
<el-dialog :visible.sync="segmentVisible" :close-on-click-modal="false" :title="$t('trials:segment:title:bind')"
width="550px">
<SegmentForm v-if="segmentVisible" :visible.sync="segmentVisible" :visitInfo="segmentVisitInfo"
@handleSegmentSave="handleSegmentSave" />
</el-dialog>
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId" <upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId"
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible" :subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible"
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" /> :visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" />
@ -479,7 +516,9 @@ import { getTools, getCustomizeStandardsTools, config } from './toolConfig'
import StudyList from './StudyList' import StudyList from './StudyList'
import Viewport from './Viewport' import Viewport from './Viewport'
import PetCtViewport from './PetCtViewport' import PetCtViewport from './PetCtViewport'
import MPRViewport from './MPRViewport'
import VolumeViewport from './VolumeViewport' import VolumeViewport from './VolumeViewport'
import Segmentations from './Segmentations'
import mRecisit from './mRecist/QuestionList' import mRecisit from './mRecist/QuestionList'
import recisit from './Recist/QuestionList' import recisit from './Recist/QuestionList'
import customizeQuestionList from './customize/QuestionList' import customizeQuestionList from './customize/QuestionList'
@ -491,6 +530,7 @@ import WL from '@/views/trials/trials-panel/reading/dicoms/components/WL'
import Others from '@/views/trials/trials-panel/reading/dicoms/components/Others' import Others from '@/views/trials/trials-panel/reading/dicoms/components/Others'
import ClinicalData from '@/views/trials/trials-panel/reading/clinical-data' import ClinicalData from '@/views/trials/trials-panel/reading/clinical-data'
import FusionForm from './FusionForm.vue' import FusionForm from './FusionForm.vue'
import SegmentForm from './SegmentForm.vue'
import colorMap from './colorMap.vue' import colorMap from './colorMap.vue'
import RectangleROITool from './tools/RectangleROITool' import RectangleROITool from './tools/RectangleROITool'
import ScaleOverlayTool from './tools/ScaleOverlayTool' import ScaleOverlayTool from './tools/ScaleOverlayTool'
@ -527,7 +567,10 @@ const {
VolumeRotateTool, VolumeRotateTool,
CrosshairsTool, CrosshairsTool,
EllipticalROITool, EllipticalROITool,
synchronizers synchronizers,
PlanarFreehandContourSegmentationTool,
BrushTool,
utilities: CStUtils,
// cursors // cursors
} = cornerstoneTools } = cornerstoneTools
const { createCameraPositionSynchronizer, createVOISynchronizer, createSlabThicknessSynchronizer } = synchronizers const { createCameraPositionSynchronizer, createVOISynchronizer, createSlabThicknessSynchronizer } = synchronizers
@ -562,7 +605,9 @@ export default {
StudyList, StudyList,
Viewport, Viewport,
PetCtViewport, PetCtViewport,
MPRViewport,
VolumeViewport, VolumeViewport,
Segmentations,
mRecisit, mRecisit,
recisit, recisit,
customizeQuestionList, customizeQuestionList,
@ -573,6 +618,7 @@ export default {
Others, Others,
ClinicalData, ClinicalData,
FusionForm, FusionForm,
SegmentForm,
colorMap, colorMap,
downloadDicomAndNonedicom, downloadDicomAndNonedicom,
uploadDicomAndNonedicom, uploadDicomAndNonedicom,
@ -687,6 +733,24 @@ export default {
SAGITTAL: { SAGITTAL: {
imageNum: 0 imageNum: 0
}, },
},
segmentVisible: false,
segmentVisitInfo: {},
formWrapperActiveName: 'ecrf',
actionConfiguration: {
contourBidirectional: {
method: CStUtils.segmentation.segmentContourAction,
bindings: [
{
key: 'c',
},
],
data: {
segmentData: new Map(),
segmentationId: null
},
},
} }
} }
}, },
@ -694,8 +758,17 @@ export default {
gridStyle() { gridStyle() {
return { return {
display: 'grid', display: 'grid',
gridTemplateRows: `repeat(${this.isMPR ? 2 : this.rows}, 1fr)`, gridTemplateRows: `repeat(${this.rows}, 1fr)`,
gridTemplateColumns: `repeat(${this.isMPR ? 2 : this.cols}, 1fr)`, gridTemplateColumns: `repeat(${this.cols}, 1fr)`,
height: '100%',
width: '100%'
}
},
gridStyleMPR() {
return {
display: 'grid',
gridTemplateRows: `repeat(2, 1fr)`,
gridTemplateColumns: `repeat(2, 1fr)`,
height: '100%', height: '100%',
width: '100%' width: '100%'
} }
@ -712,11 +785,11 @@ export default {
return Array(this.rows * this.cols).fill(0) return Array(this.rows * this.cols).fill(0)
}, },
viewportKey() { viewportKey() {
return this.isMPR ? 'viewport-volume' : this.isFusion ? 'viewport-fusion' : 'viewport' return this.isMPR ? 'viewport-MPR' : this.isFusion ? 'viewport-fusion' : 'viewport'
}, },
openManuals() { openManuals() {
return !this.taskInfo.IsReadKeyFile && this.taskInfo.IsHaveKeyFile return !this.taskInfo.IsReadKeyFile && this.taskInfo.IsHaveKeyFile
} },
}, },
watch: { watch: {
openManuals: { openManuals: {
@ -787,7 +860,7 @@ export default {
} else { } else {
this.tools = getTools(this.criterionType) this.tools = getTools(this.criterionType)
} }
console.log(toolsEvents, 'toolsEvents')
this.trialId = this.$route.query.trialId this.trialId = this.$route.query.trialId
this.readingTaskState = this.taskInfo.ReadingTaskState this.readingTaskState = this.taskInfo.ReadingTaskState
if (!this.taskInfo.IsBaseLine && this.taskInfo.IsReadingTaskViewInOrder !== 0) { if (!this.taskInfo.IsBaseLine && this.taskInfo.IsReadingTaskViewInOrder !== 0) {
@ -816,6 +889,20 @@ export default {
this.getSystemInfoReading(); this.getSystemInfoReading();
}, },
methods: { methods: {
resetQuestion(){
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].getQuestions(false)
},
handleSegmentSave(obj) {
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].handleSegmentSave(obj)
},
openSegmentForm(obj) {
let { visitInfo } = obj
this.segmentVisitInfo = visitInfo
this.segmentVisible = true
},
handleClick(tab, event) {
this.formWrapperActiveName = tab.name
},
setMPRInfo(obj) { setMPRInfo(obj) {
let { type, key, value } = obj let { type, key, value } = obj
this.$set(this.MPRInfo[type], key, value) this.$set(this.MPRInfo[type], key, value)
@ -1071,7 +1158,7 @@ export default {
} }
let viewportIds = ['viewport-0', 'viewport-1', 'viewport-2', 'viewport-3'] let viewportIds = ['viewport-0', 'viewport-1', 'viewport-2', 'viewport-3']
const fusionViewportIds = ['viewport-fusion-0', 'viewport-fusion-1', 'viewport-fusion-2', 'viewport-fusion-3'] const fusionViewportIds = ['viewport-fusion-0', 'viewport-fusion-1', 'viewport-fusion-2', 'viewport-fusion-3']
const volumeViewportIds = ['viewport-volume-0', 'viewport-volume-1', 'viewport-volume-2'] const volumeViewportIds = ['viewport-MPR-0', 'viewport-MPR-1', 'viewport-MPR-2']
const element1 = this.$refs['viewport-0'][0].$el const element1 = this.$refs['viewport-0'][0].$el
const element2 = this.$refs['viewport-1'][0].$el const element2 = this.$refs['viewport-1'][0].$el
const element3 = this.$refs['viewport-2'][0].$el const element3 = this.$refs['viewport-2'][0].$el
@ -1098,13 +1185,49 @@ export default {
element: element4 element: element4
} }
] ]
if (this.criterionType === 0 && this.readingTool === 0) { if (this.readingTool === 3) {
const volumeElement1 = this.$refs['viewport-volume-0'][0].$el viewportInputArray = [
const volumeElement2 = this.$refs['viewport-volume-1'][0].$el {
const volumeElement3 = this.$refs['viewport-volume-2'][0].$el viewportId: 'viewport-0',
type: ViewportType.ORTHOGRAPHIC,
element: element1,
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL
}
},
{
viewportId: 'viewport-1',
type: ViewportType.ORTHOGRAPHIC,
element: element2,
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL
}
},
{
viewportId: 'viewport-2',
type: ViewportType.ORTHOGRAPHIC,
element: element3,
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL
}
},
{
viewportId: 'viewport-3',
type: ViewportType.ORTHOGRAPHIC,
element: element4,
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL
}
}
]
}
if ((this.criterionType === 0 && this.readingTool === 0) || this.readingTool === 3) {
const volumeElement1 = this.$refs['viewport-MPR-0'][0].$el
const volumeElement2 = this.$refs['viewport-MPR-1'][0].$el
const volumeElement3 = this.$refs['viewport-MPR-2'][0].$el
const arr = [ const arr = [
{ {
viewportId: 'viewport-volume-0', viewportId: 'viewport-MPR-0',
type: ViewportType.ORTHOGRAPHIC, type: ViewportType.ORTHOGRAPHIC,
element: volumeElement1, element: volumeElement1,
defaultOptions: { defaultOptions: {
@ -1112,7 +1235,7 @@ export default {
} }
}, },
{ {
viewportId: 'viewport-volume-1', viewportId: 'viewport-MPR-1',
type: ViewportType.ORTHOGRAPHIC, type: ViewportType.ORTHOGRAPHIC,
element: volumeElement2, element: volumeElement2,
defaultOptions: { defaultOptions: {
@ -1120,7 +1243,7 @@ export default {
} }
}, },
{ {
viewportId: 'viewport-volume-2', viewportId: 'viewport-MPR-2',
type: ViewportType.ORTHOGRAPHIC, type: ViewportType.ORTHOGRAPHIC,
element: volumeElement3, element: volumeElement3,
defaultOptions: { defaultOptions: {
@ -1198,14 +1321,14 @@ export default {
cornerstoneTools.addTool(MIPJumpToClickTool) cornerstoneTools.addTool(MIPJumpToClickTool)
cornerstoneTools.addTool(VolumeRotateTool) cornerstoneTools.addTool(VolumeRotateTool)
cornerstoneTools.addTool(CrosshairsTool) cornerstoneTools.addTool(CrosshairsTool)
cornerstoneTools.addTool(PlanarFreehandContourSegmentationTool)
cornerstoneTools.addTool(BrushTool)
viewportIds.forEach((viewportId, i) => { viewportIds.forEach((viewportId, i) => {
// const toolGroupId = `viewport-${i}` // const toolGroupId = `viewport-${i}`
let toolGroupId = viewportId let toolGroupId = viewportId
if (volumeViewportIds.includes(viewportId)) { if (volumeViewportIds.includes(viewportId)) {
toolGroupId = this.volumeToolGroupId toolGroupId = this.volumeToolGroupId
} }
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) ? ToolGroupManager.getToolGroup(toolGroupId) : ToolGroupManager.createToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) ? ToolGroupManager.getToolGroup(toolGroupId) : ToolGroupManager.createToolGroup(toolGroupId)
toolGroup.addViewport(viewportId, renderingEngineId) toolGroup.addViewport(viewportId, renderingEngineId)
toolGroup.addTool(StackScrollTool.toolName, { toolGroup.addTool(StackScrollTool.toolName, {
@ -1215,6 +1338,44 @@ export default {
toolGroup.addTool(PanTool.toolName) toolGroup.addTool(PanTool.toolName)
toolGroup.addTool(ZoomTool.toolName) toolGroup.addTool(ZoomTool.toolName)
toolGroup.addTool(BrushTool.toolName)
if (this.readingTool === 3 || toolGroupId === this.volumeToolGroupId) {
toolGroup.addToolInstance(
'CircularBrush',
BrushTool.toolName,
{
activeStrategy: 'FILL_INSIDE_CIRCLE',
preview: {
previewColors: {}
}
}
);
toolGroup.addToolInstance(
'CircularEraser',
BrushTool.toolName,
{
activeStrategy: 'ERASE_INSIDE_CIRCLE',
preview: {
previewColors: {}
}
}
)
toolGroup.addTool(PlanarFreehandContourSegmentationTool.toolName, {
cachedStats: true,
});
// toolGroup.setToolActive(PlanarFreehandContourSegmentationTool.toolName, {
// bindings: [
// {
// mouseButton: MouseBindings.Primary, // Left Click
// },
// {
// mouseButton: MouseBindings.Primary, // Shift + Left Click
// modifierKey: cornerstoneTools.Enums.KeyboardBindings.Shift,
// },
// ],
// });
}
if (volumeViewportIds.includes(viewportId)) { if (volumeViewportIds.includes(viewportId)) {
toolGroup.addTool(WindowLevelTool.toolName, { toolGroup.addTool(WindowLevelTool.toolName, {
targetViewportIds: volumeViewportIds targetViewportIds: volumeViewportIds
@ -1251,7 +1412,8 @@ export default {
// cachedStats: false // cachedStats: false
}) })
toolGroup.addTool(BidirectionalTool.toolName, { toolGroup.addTool(BidirectionalTool.toolName, {
// cachedStats: true // cachedStats: true,
actions: this.actionConfiguration,
getTextLines: this.getBidirectionalToolTextLines getTextLines: this.getBidirectionalToolTextLines
}) })
toolGroup.addTool(CircleROITool.toolName, { toolGroup.addTool(CircleROITool.toolName, {
@ -1308,9 +1470,6 @@ export default {
toolGroup.setToolActive(PanTool.toolName, { toolGroup.setToolActive(PanTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Auxiliary }] bindings: [{ mouseButton: MouseBindings.Auxiliary }]
}) })
// toolGroup.setToolEnabled(ScaleOverlayTool.toolName);
// toolGroup.setToolPassive(PanTool.toolName)
// toolGroup.setToolPassive(ZoomTool.toolName)
toolGroup.setToolPassive(WindowLevelTool.toolName) toolGroup.setToolPassive(WindowLevelTool.toolName)
toolGroup.setToolPassive(WindowLevelRegionTool.toolName) toolGroup.setToolPassive(WindowLevelRegionTool.toolName)
toolGroup.setToolPassive(PlanarRotateTool.toolName) toolGroup.setToolPassive(PlanarRotateTool.toolName)
@ -1326,6 +1485,7 @@ export default {
toolGroup.setToolPassive(FixedRadiusCircleROITool.toolName) toolGroup.setToolPassive(FixedRadiusCircleROITool.toolName)
toolGroup.setToolPassive(AngleTool.toolName) toolGroup.setToolPassive(AngleTool.toolName)
toolGroup.setToolPassive(CobbAngleTool.toolName) toolGroup.setToolPassive(CobbAngleTool.toolName)
if (this.readingTool === 3) toolGroup.setToolPassive(PlanarFreehandContourSegmentationTool.toolName)
} else { } else {
toolGroup.setToolEnabled(ArrowAnnotateTool.toolName) toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
toolGroup.setToolEnabled(RectangleROITool.toolName) toolGroup.setToolEnabled(RectangleROITool.toolName)
@ -1337,6 +1497,7 @@ export default {
toolGroup.setToolEnabled(FixedRadiusCircleROITool.toolName) toolGroup.setToolEnabled(FixedRadiusCircleROITool.toolName)
toolGroup.setToolEnabled(AngleTool.toolName) toolGroup.setToolEnabled(AngleTool.toolName)
toolGroup.setToolEnabled(CobbAngleTool.toolName) toolGroup.setToolEnabled(CobbAngleTool.toolName)
if (this.readingTool === 3) toolGroup.setToolEnabled(PlanarFreehandContourSegmentationTool.toolName)
} }
toolGroup.setToolPassive(EraserTool.toolName) toolGroup.setToolPassive(EraserTool.toolName)
}) })
@ -1346,7 +1507,7 @@ export default {
if (this.readingTool === 2) { if (this.readingTool === 2) {
this.setUpSynchronizers() this.setUpSynchronizers()
} }
if (this.criterionType === 0 && this.readingTool === 0) { if ((this.criterionType === 0 && this.readingTool === 0) || this.readingTool === 3) {
this.setUpSynchronizersMPR() this.setUpSynchronizersMPR()
} }
}, },
@ -1500,7 +1661,6 @@ export default {
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].setAnnotation({ annotation, toolName: annotation.metadata.toolName }) this.$refs[`ecrf_${this.lastViewportTaskId}`][0].setAnnotation({ annotation, toolName: annotation.metadata.toolName })
this.markedSeriesIds.push(series.Id) this.markedSeriesIds.push(series.Id)
} }
this.setToolsPassive() this.setToolsPassive()
}, },
annotationModifiedListener(e) { annotationModifiedListener(e) {
@ -1516,6 +1676,7 @@ export default {
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].modifyAnnotation({ annotation, toolName: annotation.metadata.toolName }) this.$refs[`ecrf_${this.lastViewportTaskId}`][0].modifyAnnotation({ annotation, toolName: annotation.metadata.toolName })
} }
this.setToolsPassive() this.setToolsPassive()
}, },
annotationRemovedListener(e) { annotationRemovedListener(e) {
const { annotation } = e.detail const { annotation } = e.detail
@ -1552,9 +1713,10 @@ export default {
if (!annotation) return if (!annotation) return
const i = this.tools.findIndex(i => i.toolName === annotation.metadata.toolName) const i = this.tools.findIndex(i => i.toolName === annotation.metadata.toolName)
if (i === -1) { if (i === -1) {
this.setToolsPassive() if (annotation.metadata.toolName !== PlanarFreehandContourSegmentationTool.toolName) this.setToolsPassive()
return return
} }
if (annotation.data.segmentation || annotation.data.segment) return
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) { if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
@ -1593,7 +1755,6 @@ export default {
// } // }
} }
} }
this.setToolsPassive() this.setToolsPassive()
}, },
validMarkName(markName) { validMarkName(markName) {
@ -1639,9 +1800,10 @@ export default {
if (!annotation) return if (!annotation) return
const i = this.tools.findIndex(i => i.toolName === annotation.metadata.toolName) const i = this.tools.findIndex(i => i.toolName === annotation.metadata.toolName)
if (i === -1) { if (i === -1) {
this.setToolsPassive() if (annotation.metadata.toolName !== PlanarFreehandContourSegmentationTool.toolName) this.setToolsPassive()
return return
} }
if (annotation.data.segmentation || annotation.data.segment) return
if (!annotation.data.label) return if (!annotation.data.label) return
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
@ -1672,6 +1834,7 @@ export default {
// //
return return
} }
if (annotation.data.segmentation || annotation.data.segment) return
if (annotation.visitTaskId === this.taskInfo.VisitTaskId) { if (annotation.visitTaskId === this.taskInfo.VisitTaskId) {
const isBound = this.$refs[`ecrf_${annotation.visitTaskId}`][0].verifyAnnotationIsBound(annotation) const isBound = this.$refs[`ecrf_${annotation.visitTaskId}`][0].verifyAnnotationIsBound(annotation)
if (isBound && this.activeTool === 'Eraser') { if (isBound && this.activeTool === 'Eraser') {
@ -1724,6 +1887,9 @@ export default {
}, },
contentMouseup(e) { contentMouseup(e) {
console.log('contentMouseup') console.log('contentMouseup')
if (this.$refs.Segmentations) {
this.$refs.Segmentations.contentMouseup()
}
if (this.curOperation.type === 'Modified') { if (this.curOperation.type === 'Modified') {
let annotation = this.curOperation.annotation let annotation = this.curOperation.annotation
this.saveCustomAnnotation(annotation) this.saveCustomAnnotation(annotation)
@ -2270,6 +2436,7 @@ export default {
if (!obj.isCanActiveTool) { if (!obj.isCanActiveTool) {
if (this.activeTool === toolName) { if (this.activeTool === toolName) {
this.setToolsPassive() this.setToolsPassive()
} }
this.tools[i].isDisabled = true this.tools[i].isDisabled = true
e.target.style.cursor = 'not-allowed' e.target.style.cursor = 'not-allowed'
@ -2282,6 +2449,7 @@ export default {
// //
setViewportRotate(value) { setViewportRotate(value) {
this.setToolsPassive() this.setToolsPassive()
const renderingEngine = getRenderingEngine(renderingEngineId) const renderingEngine = getRenderingEngine(renderingEngineId)
const viewportId = `${this.viewportKey}-${this.activeViewportIndex}` const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
const viewport = renderingEngine.getViewport(viewportId) const viewport = renderingEngine.getViewport(viewportId)
@ -2620,6 +2788,7 @@ export default {
this.cols = 1 this.cols = 1
this.activeViewportIndex = 0 this.activeViewportIndex = 0
this.setToolsPassive() this.setToolsPassive()
} }
if (taskIndex === this.activeTaskIndex) return if (taskIndex === this.activeTaskIndex) return
if (!this.selectArr.includes(taskInfo.VisitTaskId)) { if (!this.selectArr.includes(taskInfo.VisitTaskId)) {
@ -2865,13 +3034,23 @@ export default {
const i = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.visitTaskId) const i = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.visitTaskId)
if (i === -1) return if (i === -1) return
const studyList = this.visitTaskList[i].StudyList const studyList = this.visitTaskList[i].StudyList
let series = this.getMarkedSeries(studyList, obj.annotation, true) let series = null
if (obj.segment) {
let study = studyList.find(item => item.StudyId === obj.segmentGroup.StudyId)
series = study.SeriesList.find(item => item.Id === obj.segmentGroup.SeriesId)
let sliceIndex = obj.segment.bidirectional.sliceIndex || 0
series.SliceIndex = series.InstanceCount - 1 - sliceIndex
series.segment = obj.segment
} else {
series = this.getMarkedSeries(studyList, obj.annotation, true)
}
if (series) { if (series) {
if (this.isFusion && series.SeriesInstanceUid !== this.fusionSerieId.ct && series.SeriesInstanceUid !== this.fusionSerieId.pt) { if (this.isFusion && series.SeriesInstanceUid !== this.fusionSerieId.ct && series.SeriesInstanceUid !== this.fusionSerieId.pt) {
return await this.$confirm(this.$t('trials:reading:confirm:fusionPTOrCTInconsistent')) return await this.$confirm(this.$t('trials:reading:confirm:fusionPTOrCTInconsistent'))
} }
this.activeViewportIndex = this.cells.length - 1 this.activeViewportIndex = this.cells.length - 1
if (obj.annotation.from === 'MPR') { if (obj.annotation && obj.annotation.from === 'MPR') {
let viewPlaneNormal = obj.annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',') let viewPlaneNormal = obj.annotation?.metadata?.viewPlaneNormal.map(i => i == 0 ? 0 : i).join(',')
if (viewPlaneNormal === '0,0,-1') { if (viewPlaneNormal === '0,0,-1') {
this.activeViewportIndex = 0 this.activeViewportIndex = 0
@ -2906,7 +3085,7 @@ export default {
} }
} }
} }
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, true) this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, obj.segment ? false : true)
this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex) this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
} }
}, },
@ -3087,7 +3266,6 @@ export default {
if (obj.isActiveTarget && obj.SplitOrMergeType !== '1' && obj.SplitOrMergeType !== '3') { if (obj.isActiveTarget && obj.SplitOrMergeType !== '1' && obj.SplitOrMergeType !== '3') {
this.setToolToTarget(obj) this.setToolToTarget(obj)
} }
resolve() resolve()
}) })
}, },
@ -3097,6 +3275,7 @@ export default {
const toolName = obj.markTool const toolName = obj.markTool
if (this.activeTool) { if (this.activeTool) {
this.setToolsPassive() this.setToolsPassive()
} }
const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}` const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}`
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
@ -3317,9 +3496,9 @@ export default {
syncColormap: false syncColormap: false
}) })
let viewportIds = [ let viewportIds = [
`viewport-volume-0`, `viewport-MPR-0`,
`viewport-volume-1`, `viewport-MPR-1`,
`viewport-volume-2` `viewport-MPR-2`
] ]
viewportIds.forEach((viewportId) => { viewportIds.forEach((viewportId) => {
MPRVoiSynchronizer.add({ MPRVoiSynchronizer.add({
@ -3331,9 +3510,9 @@ export default {
// Add viewports to VOI synchronizers // Add viewports to VOI synchronizers
[ [
`viewport-volume-0`, `viewport-MPR-0`,
`viewport-volume-1`, `viewport-MPR-1`,
`viewport-volume-2` `viewport-MPR-2`
].forEach((viewportId) => { ].forEach((viewportId) => {
synchronizer.add({ synchronizer.add({
renderingEngineId: this.renderingEngineId, renderingEngineId: this.renderingEngineId,
@ -3360,7 +3539,7 @@ export default {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
if (this.isMPR) { if (this.isMPR) {
if (!data) return resolve(false) if (!data) return resolve(false)
let viewportSeries = this.$refs[`viewport-volume-0`][0].series let viewportSeries = this.$refs[`viewport-MPR-0`][0].series
if (data && viewportSeries.SeriesInstanceUid === data.SeriesInstanceUid) return resolve(true) if (data && viewportSeries.SeriesInstanceUid === data.SeriesInstanceUid) return resolve(true)
} }
if (!data) { if (!data) {
@ -3378,8 +3557,8 @@ export default {
if (!res) return false if (!res) return false
} }
this.isMPR = true this.isMPR = true
this.rows = 3 // this.rows = 3
this.cols = 1 // this.cols = 1
this.loading = true this.loading = true
this.loadingText = this.$t('trials:lugano:message:loadVolumes') this.loadingText = this.$t('trials:lugano:message:loadVolumes')
if (!data) this.activeViewportIndex = 0 if (!data) this.activeViewportIndex = 0
@ -3388,9 +3567,9 @@ export default {
await this.getVolume(series) await this.getVolume(series)
this.loading = false this.loading = false
this.loadingText = null this.loadingText = null
this.$refs[`viewport-volume-0`][0].setSeriesInfo(Object.assign({ orientation: 'AXIAL', isLocation: data && this.activeViewportIndex === 0 }, series)) this.$refs[`viewport-MPR-0`][0].setSeriesInfo(Object.assign({ orientation: 'AXIAL', isLocation: data && this.activeViewportIndex === 0 }, series))
this.$refs[`viewport-volume-1`][0].setSeriesInfo(Object.assign({ orientation: 'SAGITTAL', isLocation: data && this.activeViewportIndex === 1 }, series)) this.$refs[`viewport-MPR-1`][0].setSeriesInfo(Object.assign({ orientation: 'SAGITTAL', isLocation: data && this.activeViewportIndex === 1 }, series))
this.$refs[`viewport-volume-2`][0].setSeriesInfo(Object.assign({ orientation: 'CORONAL', isLocation: data && this.activeViewportIndex === 2 }, series)) this.$refs[`viewport-MPR-2`][0].setSeriesInfo(Object.assign({ orientation: 'CORONAL', isLocation: data && this.activeViewportIndex === 2 }, series))
resolve(false) resolve(false)
}) })

View File

@ -0,0 +1,193 @@
<template>
<el-form ref="segmentForm" :model="form" label-width="120px" label-position="left">
<!-- 检查名称 -->
<el-form-item :label="$t('segment:form:label:studyName')" prop="taskBlindName">
<el-select v-model="form.studyId" clearable @change="(e) => handleChange(e, 'study')">
<el-option v-for="item in studyList" :key="item.StudyId" :label="item.StudyCode"
:value="item.StudyId" />
</el-select>
</el-form-item>
<!-- 序列名称 -->
<el-form-item :label="$t('segment:form:label:seriesName')" prop="taskBlindName">
<el-select v-model="form.seriesId" clearable @change="(e) => handleChange(e, 'series')">
<el-option v-for="item in seriesList" :key="item.Id"
:label="`#${item.SeriesNumber}/${item.Modality}/${item.Description}`" :value="item.Id" />
</el-select>
</el-form-item>
<!-- 分割组名称 -->
<el-form-item :label="$t('segment:form:label:segmentGroupName')" prop="taskBlindName">
<el-select v-model="form.segmentGroupId" clearable @change="(e) => handleChange(e, 'segmentGroup')">
<el-option v-for="item in segmentGroupList" :key="item.Id" :label="item.SegmentationName"
:value="item.Id" />
</el-select>
</el-form-item>
<!-- 分割名称 -->
<el-form-item :label="$t('segment:form:label:segmentName')" prop="taskBlindName">
<el-select v-model="form.segmentId" clearable>
<el-option v-for="item in segmentList" :key="item.Id" :label="item.SegmentName" :value="item.Id" />
</el-select>
</el-form-item>
<el-form-item style="text-align:right;">
<!-- 取消 -->
<el-button size="mini" @click="handleCancel">{{ $t('common:button:cancel') }}</el-button>
<!-- 确认 -->
<el-button type="primary" size="mini" @click="handleSave">
{{ $t('common:button:confirm') }}</el-button>
</el-form-item>
</el-form>
</template>
<script>
import { getSegmentationList, getSegmentList } from '@/api/reading'
export default {
name: 'FusionForm',
props: {
visible: {
type: Boolean,
default: false
},
visitInfo: {
type: Object,
default: () => {
return {}
}
}
},
data() {
return {
form: {
studyId: '',
seriesId: '',
segmentGroupId: '',
segmentId: ""
},
studyList: [],
seriesList: [],
segmentGroupList: [],
segmentList: [],
segmentionList: []
}
},
mounted() {
this.init()
},
methods: {
async init() {
let studyList = this.visitInfo.StudyList
let s = await this.getSegmentationList()
this.segmentionList = s
let StudyIds = s.map(item => item.StudyId)
let SeriesIds = s.map(item => item.SeriesId)
studyList = studyList.filter(item => StudyIds.includes(item.StudyId))
studyList.forEach(study => {
study.SeriesList = study.SeriesList.filter(item => SeriesIds.includes(item.Id))
})
this.studyList = studyList
},
async handleChange(e, key) {
if (key === 'study') {
this.seriesList = this.studyList.find(item => item.StudyId === this.form.studyId).SeriesList
}
if (key === 'series') {
this.segmentGroupList = this.segmentionList.filter(item => item.SeriesId === this.form.seriesId)
}
if (key === 'segmentGroup') {
let list = await this.getSegmentList(this.form.segmentGroupId)
this.segmentList = list.filter(item => item.SegmentJson)
}
},
handleCancel() {
this.$emit("update:visible", false)
},
handleSave() {
let segment = this.segmentList.find(item => item.Id === this.form.segmentId)
if (segment.SegmentJson) {
let obj = JSON.parse(segment.SegmentJson)
segment.stats = obj.stats
segment.bidirectional = obj.bidirectional
}
this.$emit('handleSegmentSave', segment)
this.handleCancel()
},
//
async getSegmentationList() {
try {
let data = {
VisitTaskId: this.visitInfo.VisitTaskId,
PageSize: 9999,
PageIndex: 1,
}
this.loading = true;
let res = await getSegmentationList(data);
this.loading = false;
if (res.IsSuccess) {
return res.Result.CurrentPageData;
}
} catch (err) {
this.loading = false
console.log(err)
}
},
//
async getSegmentList(id) {
try {
let data = {
SegmentationId: id,
PageSize: 9999,
PageIndex: 1,
}
this.loading = true;
let res = await getSegmentList(data)
this.loading = false;
if (res.IsSuccess) {
return res.Result.CurrentPageData
}
} catch (err) {
this.loading = false
console.log(err)
}
},
}
}
</script>
<style lang="scss" scoped>
.series-table {
::v-deep.el-table {
background-color: #1e1e1e !important;
color: #dfdfdf;
}
::v-deep.el-table td.el-table__cell,
.el-table th.el-table__cell.is-leaf {
border-bottom: 1px solid #dfdfdf;
}
.el-table--border::after,
.el-table--group::after,
.el-table::before {
background-color: #1e1e1e;
}
::v-deep.el-table__header-wrapper {
th {
background-color: #1e1e1e !important;
color: #dfdfdf;
}
}
::v-deep.el-table__body-wrapper {
tr {
background-color: #1e1e1e !important;
color: #dfdfdf;
}
tr:hover>td {
background-color: #1e1e1e !important;
}
}
::v-deep.el-table__empty-block {
background-color: #1e1e1e !important;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,10 @@
<template> <template>
<div v-loading="loading" class="study-wrapper"> <div v-loading="loading" class="study-wrapper">
<div class="study-info"> <div class="study-info">
<div <div v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo" :title="taskInfo.SubjectCode">
v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo"
:title="taskInfo.SubjectCode"
>
{{ taskInfo.SubjectCode }} {{ taskInfo.SubjectCode }}
</div> </div>
<div <div v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo" :title="visitTaskInfo.TaskBlindName">
v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo"
:title="visitTaskInfo.TaskBlindName"
>
{{ visitTaskInfo.TaskBlindName }} {{ visitTaskInfo.TaskBlindName }}
</div> </div>
</div> </div>
@ -18,15 +12,14 @@
<el-collapse v-model="activeNames"> <el-collapse v-model="activeNames">
<el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`" :name="`${study.StudyId}`"> <el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`" :name="`${study.StudyId}`">
<template slot="title"> <template slot="title">
<div <div v-if="!study.IsCriticalSequence" class="dicom-desc">
v-if="!study.IsCriticalSequence"
class="dicom-desc"
>
<template v-if="taskInfo && taskInfo.IsShowStudyName"> <template v-if="taskInfo && taskInfo.IsShowStudyName">
<div style="text-overflow: ellipsis;overflow: hidden;"> <div style="text-overflow: ellipsis;overflow: hidden;">
<span :title="study.StudyCode">{{ study.StudyCode }}</span> <span :title="study.StudyCode">{{ study.StudyCode }}</span>
<span v-if="study.StudyName" :title="study.StudyName" style="margin-left: 5px;">{{ study.StudyName }}</span> <span v-if="study.StudyName" :title="study.StudyName" style="margin-left: 5px;">{{ study.StudyName
<span v-else :title="study.Modalities" style="margin-left: 5px;">{{ `${study.Modalities} (${study.SeriesCount})` }}</span> }}</span>
<span v-else :title="study.Modalities" style="margin-left: 5px;">{{ `${study.Modalities}
(${study.SeriesCount})` }}</span>
</div> </div>
<div v-if="study.StudyName" style="text-overflow: ellipsis;overflow: hidden;"> <div v-if="study.StudyName" style="text-overflow: ellipsis;overflow: hidden;">
<span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span> <span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
@ -46,48 +39,33 @@
</div> </div>
</template> </template>
<div class="dicom-list-container"> <div class="dicom-list-container">
<div <div v-for="(series, i) in study.SeriesList" :key="series.Id" style="position:relative;margin-top:1px;"
v-for="(series, i) in study.SeriesList" @click="activeSeries(series, i, index)">
:key="series.Id" <div :class="{ 'series-active': index === activeStudyIndex && i === activeSeriesIndex }"
style="position:relative;margin-top:1px;" class="series-wrapper">
@click="activeSeries(series, i, index)"
>
<div
:class="{'series-active': index === activeStudyIndex && i === activeSeriesIndex}"
class="series-wrapper"
>
<div class="series-image"> <div class="series-image">
<el-image <el-image style="width: 100%;height: 100%;"
style="width: 100%;height: 100%;"
:src="`${OSSclientConfig.basePath}${series.ImageResizePath || series.NoneDicomFileFirstFile}`" :src="`${OSSclientConfig.basePath}${series.ImageResizePath || series.NoneDicomFileFirstFile}`"
fit="fill" fit="fill" crossorigin="anonymous" />
crossorigin="anonymous"
/>
</div> </div>
<div class="series-text"> <div class="series-text">
<div v-if="series.IsExistMutiFrames && series.InstanceCount > 1" <div v-if="series.IsExistMutiFrames && series.InstanceCount > 1"
style="position: absolute;right: 0;top: 0;"> style="position: absolute;right: 0;top: 0;">
<el-popover <el-popover placement="right" trigger="hover" popper-class="instance_frame_wrapper">
placement="right"
trigger="hover"
popper-class="instance_frame_wrapper"
>
<div class="frame_list"> <div class="frame_list">
<div <div v-for="(instance, idx) in series.InstanceInfoList" :key="instance.Id" class="frame_content"
v-for="(instance, idx) in series.InstanceInfoList" :style="{ 'margin-bottom': idx < series.InstanceInfoList.length - 1 ? '5px' : '0px' }"
:key="instance.Id" @click.stop="showMultiFrames(index, series, i, instance)">
class="frame_content"
:style="{'margin-bottom':idx<series.InstanceInfoList.length-1? '5px':'0px'}"
@click.stop="showMultiFrames(index,series, i, instance)"
>
<div> <div>
<div>{{ instance.InstanceNumber }}</div> <div>{{ instance.InstanceNumber }}</div>
<div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ? instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div> <div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ?
instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
</div> </div>
</div> </div>
</div> </div>
<i slot="reference" class="el-icon-connection" style="font-size: 15px;cursor: pointer;color: #ffeb3b;" /> <i slot="reference" class="el-icon-connection"
style="font-size: 15px;cursor: pointer;color: #ffeb3b;" />
</el-popover> </el-popover>
</div> </div>
<div v-if="!study.IsCriticalSequence" class="text-desc" :title="series.SeriesNumber"> <div v-if="!study.IsCriticalSequence" class="text-desc" :title="series.SeriesNumber">
@ -104,17 +82,19 @@
<span v-show="series.LoadedImageCount < series.InstanceCount"> <span v-show="series.LoadedImageCount < series.InstanceCount">
{{ series.Modality }}: {{ series.LoadedImageCount }}/{{ series.InstanceCount }} image {{ series.Modality }}: {{ series.LoadedImageCount }}/{{ series.InstanceCount }} image
</span> </span>
<span v-show="series.LoadedImageCount >= series.InstanceCount">{{ series.Modality }}: {{ series.InstanceCount }} image</span> <span v-show="series.LoadedImageCount >= series.InstanceCount">{{ series.Modality }}: {{
series.InstanceCount
}} image</span>
</div> </div>
<div style="line-height: 12px;"> <div style="line-height: 12px;">
<i v-show="series.IsBeMark || markedSeriesIds.includes(series.Id)" class="el-icon-star-on" style="font-size: 12px;color: #ff5722;" /> <i v-show="series.IsBeMark || markedSeriesIds.includes(series.Id)" class="el-icon-star-on"
style="font-size: 12px;color: #ff5722;" />
</div> </div>
</div> </div>
</div> </div>
<div v-if="series.LoadedImageCount > 0 && series.LoadedImageCount < series.InstanceCount" style="width: 100%;"> <div v-if="series.LoadedImageCount > 0 && series.LoadedImageCount < series.InstanceCount"
<el-progress style="width: 100%;">
:percentage="parseInt((series.LoadedImageProgress / series.InstanceCount).toFixed(2))" <el-progress :percentage="parseInt((series.LoadedImageProgress / series.InstanceCount).toFixed(2))" />
/>
</div> </div>
</div> </div>
</div> </div>
@ -124,6 +104,7 @@
</div> </div>
</template> </template>
<script> <script>
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
export default { export default {
name: 'StudyList', name: 'StudyList',
props: { props: {
@ -168,6 +149,7 @@ export default {
this.activeStudyIndex = studyIndex this.activeStudyIndex = studyIndex
this.activeSeriesIndex = seriesIndex this.activeSeriesIndex = seriesIndex
this.$emit('activeSeries', series) this.$emit('activeSeries', series)
DicomEvent.$emit('activeSeries', series)
}, },
activeStudy(id) { activeStudy(id) {
if (this.activeNames.indexOf(id) > -1) return if (this.activeNames.indexOf(id) > -1) return
@ -179,6 +161,7 @@ export default {
const studyId = this.studyList[studyIndex].StudyId const studyId = this.studyList[studyIndex].StudyId
if (!studyId) return if (!studyId) return
this.activeStudy(studyId) this.activeStudy(studyId)
DicomEvent.$emit('activeSeries', this.studyList[studyIndex].SeriesList[this.activeSeriesIndex])
}, },
showMultiFrames(studyIndex, series, seriesIndex, instance) { showMultiFrames(studyIndex, series, seriesIndex, instance) {
let obj = Object.assign({}, series) let obj = Object.assign({}, series)
@ -224,13 +207,14 @@ export default {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.study-wrapper{ .study-wrapper {
width:100%; width: 100%;
height: 100%; height: 100%;
overflow-y: hidden; overflow-y: hidden;
overflow-x: hidden; overflow-x: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.study-info { .study-info {
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
@ -241,7 +225,8 @@ export default {
background-color: #4c4c4c; background-color: #4c4c4c;
height: 50px; height: 50px;
} }
.dicom-desc{
.dicom-desc {
font-weight: bold; font-weight: bold;
font-size: 13px; font-size: 13px;
text-align: left; text-align: left;
@ -258,19 +243,23 @@ export default {
touch-action: auto; touch-action: auto;
overflow-y: auto; overflow-y: auto;
} }
.series-active { .series-active {
background-color: #607d8b!important; background-color: #607d8b !important;
border: 1px solid #607d8b!important; border: 1px solid #607d8b !important;
} }
::v-deep.el-progress__text{
::v-deep.el-progress__text {
color: #ccc; color: #ccc;
font-size: 12px; font-size: 12px;
} }
.dicom-list-container{
.dicom-list-container {
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
.series-wrapper { .series-wrapper {
width: 100%; width: 100%;
padding: 5px; padding: 5px;
@ -279,21 +268,26 @@ export default {
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
background-color: #3a3a3a; background-color: #3a3a3a;
.el-progress__text{
.el-progress__text {
display: none; display: none;
} }
.el-progress-bar{
padding-right:0px; .el-progress-bar {
padding-right: 0px;
} }
.series-image { .series-image {
width: 50px; width: 50px;
height: 50px; height: 50px;
} }
.series-text { .series-text {
flex: 1; flex: 1;
padding-left: 5px; padding-left: 5px;
color: #ddd; color: #ddd;
position: relative; position: relative;
.text-desc { .text-desc {
width: 100px; width: 100px;
white-space: nowrap; white-space: nowrap;
@ -306,27 +300,32 @@ export default {
} }
} }
::v-deep.el-collapse{
::v-deep.el-collapse {
border: none; border: none;
.el-collapse-item{
background-color: #000!important; .el-collapse-item {
background-color: #000 !important;
color: #ddd; color: #ddd;
} }
.el-collapse-item__content{
padding-bottom:0px; .el-collapse-item__content {
background-color: #000!important; padding-bottom: 0px;
background-color: #000 !important;
} }
.el-collapse-item__header{
background-color: #000!important; .el-collapse-item__header {
background-color: #000 !important;
color: #ddd; color: #ddd;
border-bottom-color:#5a5a5a; border-bottom-color: #5a5a5a;
padding-left: 5px; padding-left: 5px;
// height: 50px; // height: 50px;
line-height: 20px; line-height: 20px;
} }
} }
::v-deep .el-progress-bar__inner{
::v-deep .el-progress-bar__inner {
transition: width 0s ease; transition: width 0s ease;
} }
} }

View File

@ -68,6 +68,8 @@
<script> <script>
import { import {
metaData, metaData,
volumeLoader,
setVolumesForViewports,
getRenderingEngine, getRenderingEngine,
utilities as csUtils, utilities as csUtils,
cache cache
@ -77,8 +79,9 @@ import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/read
import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor' import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
import { setPetColorMapTransferFunctionForVolumeActor } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetColorMapTransferFunctionForVolumeActor' import { setPetColorMapTransferFunctionForVolumeActor } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetColorMapTransferFunctionForVolumeActor'
import { vec3, mat4 } from 'gl-matrix' import { vec3, mat4 } from 'gl-matrix'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
export default { export default {
name: 'ImageViewport', name: 'MPRViewport',
props: { props: {
renderingEngineId: { renderingEngineId: {
type: String, type: String,
@ -92,12 +95,6 @@ export default {
type: Number, type: Number,
required: true required: true
}, },
MPRInfo: {
type: Object,
default: () => {
return {}
}
}
}, },
data() { data() {
return { return {
@ -125,7 +122,9 @@ export default {
sliceThickness: null, sliceThickness: null,
wwwc: null, wwwc: null,
total: 0, total: 0,
sliceThickness: 0 sliceThickness: 0,
imageOrientationPatient: [],
imagePositionPatient: []
}, },
digitPlaces: 2, digitPlaces: 2,
orientationMarkers: [], orientationMarkers: [],
@ -271,20 +270,21 @@ export default {
const viewport = renderingEngine.getViewport(this.viewportId) const viewport = renderingEngine.getViewport(this.viewportId)
const zoom = viewport.getZoom() const zoom = viewport.getZoom()
this.imageInfo.zoom = zoom.toFixed(4) this.imageInfo.zoom = zoom.toFixed(4)
let imageIds = viewport.getImageIds(this.volumeId) let imageId = viewport.getCurrentImageId()
let imageId = imageIds[0]
let volume = cache.getVolume(this.volumeId)
let { spacing } = volume
// if (this.series.orientation === 'AXIAL') imageId = viewport.getCurrentImageId()
if (imageId) { if (imageId) {
this.$emit('setMPRInfo', { type: this.series.orientation, key: "imageNum", value: detail.numberOfSlices })
const imagePlaneModule = metaData.get('imagePlaneModule', imageId) const imagePlaneModule = metaData.get('imagePlaneModule', imageId)
let type = this.determineImagePlane(imagePlaneModule.imageOrientationPatient) this.imageInfo.imageOrientationPatient = imagePlaneModule.imageOrientationPatient
this.imageInfo.location = type === this.series.orientation ? imagePlaneModule.sliceLocation : '' this.imageInfo.imagePositionPatient = imagePlaneModule.imagePositionPatient
this.imageInfo.sliceThickness = type === this.series.orientation ? spacing[2] : spacing[0] this.imageInfo.size = `${imagePlaneModule.columns}*${imagePlaneModule.rows}`
this.imageInfo.location = imagePlaneModule.sliceLocation
this.imageInfo.total = detail.numberOfSlices this.imageInfo.total = detail.numberOfSlices
this.getOrientationMarker() this.getOrientationMarker()
let properties = viewport.getProperties(this.volumeId) // this.$emit('renderAnnotations', this.series)
let properties = viewport.getProperties()
if (this.isFusion) {
properties = viewport.getProperties(this.ptVolumeId)
}
if (properties && properties.voiRange) { if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange var { lower, upper } = properties.voiRange
const windowWidth = upper - lower const windowWidth = upper - lower
@ -293,11 +293,10 @@ export default {
this.defaultWindowLevel.windowCenter = windowCenter this.defaultWindowLevel.windowCenter = windowCenter
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}` this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
} }
} const toolGroupId = this.viewportId
// const toolGroupId = this.viewportId
const toolGroupId = 'share-viewport-volume'
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId)
toolGroup.setToolEnabled('ScaleOverlay') toolGroup.setToolEnabled('ScaleOverlay')
}
}, },
setFullScreen(index) { setFullScreen(index) {
@ -468,17 +467,33 @@ export default {
}) })
this.loading = false this.loading = false
}, },
async getVolume(serie, isFusion = false) {
return new Promise(async res => {
let volumeId = `${isFusion ? 'fusion_' : ''}` + serie.SeriesInstanceUid;
let volume = null;
if (cache.getVolume(volumeId)) {
volume = cache.getVolume(volumeId)
} else {
await this.createImageIdsAndCacheMetaData(serie)
volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds: serie.ImageIds })
volume.load()
}
res({ volumeId, volume })
})
},
async setSeriesInfo(obj, isLocate = false) { async setSeriesInfo(obj, isLocate = false) {
try { try {
let data = obj let data = obj
if (this.series && data.Id === this.series.Id && data.Description === this.series.Description && !isLocate && !data.isLocation) { if (this.series && data.Id === this.series.Id && data.Description === this.series.Description && !isLocate && !data.isLocation) {
data.SliceIndex = this.series.SliceIndex data.SliceIndex = this.series.SliceIndex
} }
// console.log(data.SliceIndex)
const renderingEngine = getRenderingEngine(this.renderingEngineId) const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId) const viewport = renderingEngine.getViewport(this.viewportId)
if (isLocate) return csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); if (isLocate) return csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex });
this.series = {} this.series = {}
this.volumeId = data.SeriesInstanceUid let res = await this.getVolume(obj)
this.volumeId = res.volumeId
this.series = { ...data } this.series = { ...data }
viewport viewport
.setVolumes([{ .setVolumes([{
@ -491,9 +506,13 @@ export default {
console.log("渲染成功") console.log("渲染成功")
} }
}]).then(res => { }]).then(res => {
if (data.segment) {
return DicomEvent.$emit("isloaded", { segment: data.segment })
}
if (data.isLocation) { if (data.isLocation) {
setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); }) setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); })
} }
DicomEvent.$emit("isloaded", {})
}) })
viewport.render() viewport.render()
} catch (e) { } catch (e) {

View File

@ -59,6 +59,7 @@
:parentQsId="parentQsId" :isBaseline="isBaseline" :reading-task-state="readingTaskState" :parentQsId="parentQsId" :isBaseline="isBaseline" :reading-task-state="readingTaskState"
:question-form="QuestionsForm" :visit-task-id="visitTaskId" :criterion-id="criterionId" :question-form="QuestionsForm" :visit-task-id="visitTaskId" :criterion-id="criterionId"
:type="addOrEdit.type" :calculationList="calculationList" :questionsMarkStatus="questionsMarkStatus" :type="addOrEdit.type" :calculationList="calculationList" :questionsMarkStatus="questionsMarkStatus"
:questionsSegmentMarkStatus="questionsSegmentMarkStatus"
@formItemTableNumberChange="formItemTableNumberChange" @resetFormItemData="resetTableFormItemData" @formItemTableNumberChange="formItemTableNumberChange" @resetFormItemData="resetTableFormItemData"
@setFormItemData="setFormTableItemData" @operateImageMarker="operateImageMarker" @save="save" @setFormItemData="setFormTableItemData" @operateImageMarker="operateImageMarker" @save="save"
@handleReadingChart="handleReadingChart" /> @handleReadingChart="handleReadingChart" />
@ -183,7 +184,49 @@
<el-input v-if="question.Type === 'increment'" v-model="questionForm[question.Id]" disabled /> <el-input v-if="question.Type === 'increment'" v-model="questionForm[question.Id]" disabled />
<!-- 数值 --> <!-- 数值 -->
<template v-if="question.Type === 'number' && (question.ImageMarkEnum === 1 || question.ImageMarkEnum === 2)"> <template v-if="question.Type === 'number' && (question.ImageMarkEnum === 1 || question.ImageMarkEnum === 2)">
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;"> <div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;"
v-if="question.ImageMarkTypeEnum === 1">
<el-input type="text" @change="(val) => { formItemNumberChange(val, question) }"
@input="numberInput(question.Id)"
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
v-model="questionForm[question.Id]"
:title="questionsMarkStatus[question.Id] ? questionsMarkStatus[question.Id].OrderMarkName : question.Remark"
:disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1 || readingTaskState === 2"
style="width: 150px;margin-right: 5px;">
<template v-if="question.Unit !== 0" slot="append">
{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit }}
</template>
</el-input>
<svg-icon v-if="question.ShowChartTypeEnum > 0 && taskInfo.IsReadingTaskViewInOrder === 1"
icon-class="readingChart" class="svg-icon svg-readingChart" @click.stop="(e) => handleReadingChart({
e,
data: {
QuestionId: question.Id,
QuestionName: question.QuestionName
}
})" />
<!-- 绑定 -->
<el-button v-if="readingTaskState < 2 && (!questionsSegmentMarkStatus[question.Id])" size="mini" type="text"
@click="operateImageMarker({ operateStateEnum: 21, question })">
{{ $t('dicom3D:CustomizeQuestionFormItem:button:bind') }}
</el-button>
<!-- 更改 -->
<el-button v-if="readingTaskState < 2 && (questionsSegmentMarkStatus[question.Id])" size="mini" type="text"
@click="operateImageMarker({ operateStateEnum: 22, question })">
{{ $t('dicom3D:CustomizeQuestionFormItem:button:edit') }}
</el-button>
<!-- 查看 -->
<el-button v-if="questionsSegmentMarkStatus[question.Id]" size="mini" type="text"
@click="operateImageMarker({ operateStateEnum: 23, question })">
{{ $t('dicom3D:CustomizeQuestionFormItem:button:view') }}
</el-button>
<!-- 移除 -->
<el-button v-if="readingTaskState < 2 && (questionsSegmentMarkStatus[question.Id])" size="mini" type="text"
@click="operateImageMarker({ operateStateEnum: 24, question })">
{{ $t('dicom3D:CustomizeQuestionFormItem:button:remove') }}
</el-button>
</div>
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;" v-else>
<el-input type="text" @change="(val) => { formItemNumberChange(val, question) }" <el-input type="text" @change="(val) => { formItemNumberChange(val, question) }"
@input="numberInput(question.Id)" @input="numberInput(question.Id)"
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)" @blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
@ -312,9 +355,10 @@
:isNoneDicom="isNoneDicom" :reading-task-state="readingTaskState" :question-form="questionForm" :isNoneDicom="isNoneDicom" :reading-task-state="readingTaskState" :question-form="questionForm"
:visit-task-id="visitTaskId" :criterion-id="criterionId" :calculationList="calculationList" :visit-task-id="visitTaskId" :criterion-id="criterionId" :calculationList="calculationList"
:questionMarkInfoList="questionMarkInfoList" :questionsMarkStatus="questionsMarkStatus" :questionMarkInfoList="questionMarkInfoList" :questionsMarkStatus="questionsMarkStatus"
@formItemNumberChange="formItemNumberChange" @setFormItemData="setFormItemData" :questionsSegmentMarkStatus="questionsSegmentMarkStatus" @formItemNumberChange="formItemNumberChange"
@resetFormItemData="resetFormItemData" @getQuestions="getQuestions" @operateImageMarker="operateImageMarker" @setFormItemData="setFormItemData" @resetFormItemData="resetFormItemData" @getQuestions="getQuestions"
@unBindAnnotationToQuestion="unBindAnnotationToQuestion" @handleReadingChart="handleReadingChart" /> @operateImageMarker="operateImageMarker" @unBindAnnotationToQuestion="unBindAnnotationToQuestion"
@handleReadingChart="handleReadingChart" @saveSegmentBindingAndAnswer="saveSegmentBindingAndAnswer" />
</template> </template>
<!-- <base-model :config="addOrEdit" <!-- <base-model :config="addOrEdit"
@ -397,6 +441,12 @@ export default {
return {} return {}
} }
}, },
questionsSegmentMarkStatus: {
type: Object,
default() {
return {}
}
},
isNoneDicom: { isNoneDicom: {
type: Boolean, type: Boolean,
default: false default: false
@ -556,8 +606,65 @@ export default {
this.operateImageMarker({ operateStateEnum, question: this.question, picturePath }) this.operateImageMarker({ operateStateEnum, question: this.question, picturePath })
} }
}) })
DicomEvent.$on('setTableQuestionAnswer', async (DATA) => {
let { id, answer, ParentQsId, data } = DATA
console.log(ParentQsId, this.question.Id)
if (this.question.Id === ParentQsId) {
this.QuestionsForm[id] = answer
if (data.RowId) {
let i = this.AnswersList.findIndex(i => i.RowId === this.QuestionsForm.RowId)
this.AnswersList[i][id] = this.QuestionsForm[id]
this.$emit('setFormItemData', { key: this.question.Id, val: this.AnswersList, question: this.question })
this.formItemNumberChange(this.question.Id, true)
this.$emit('saveSegmentBindingAndAnswer', [data])
} else {
try {
// loading = this.$loading({ fullscreen: true })
let answers = []
let reg = new RegExp(/^[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}$/)
for (const k in this.QuestionsForm) {
if (reg.test(k)) {
if (answers.findIndex(i => i.tableQuestionId === k) === -1) {
answers.push({ tableQuestionId: k, answer: this.QuestionsForm[k] })
}
}
}
this.QuestionsList.forEach(k => {
if (reg.test(k.Id)) {
if (answers.findIndex(i => i.tableQuestionId === k.Id) === -1) {
answers.push({ tableQuestionId: k.Id, answer: '' })
}
}
})
let params = {
questionId: this.question.Id,
RowIndex: this.questionForm[this.question.Id].length + 1,
RowId: this.QuestionsForm.RowId ? this.QuestionsForm.RowId : '',
visitTaskId: this.visitTaskId,
trialId: this.$route.query.trialId,
answerList: answers
}
let res = await submitTableQuestion(params)
if (res.IsSuccess) {
this.QuestionsForm.RowId = res.Result.RowId
obj.rowId = res.Result.RowId
data.RowId = res.Result.RowId
this.AnswersList.push(this.QuestionsForm)
this.$emit('setFormItemData', { key: this.question.Id, val: this.AnswersList, question: this.question })
this.formItemNumberChange(this.question.Id, true)
this.$emit('saveSegmentBindingAndAnswer', [data])
}
} catch (e) {
console.log(e)
}
}
}
})
}, },
methods: { methods: {
saveSegmentBindingAndAnswer(list) {
this.$emit('saveSegmentBindingAndAnswer', list)
},
handleReadingChart(row) { handleReadingChart(row) {
this.$emit('handleReadingChart', row) this.$emit('handleReadingChart', row)
}, },

View File

@ -19,9 +19,10 @@
:isNoneDicom="isNoneDicom" :question="question" :question-form="questionForm" :isNoneDicom="isNoneDicom" :question="question" :question-form="questionForm"
:reading-task-state="readingTaskState" :criterion-id="criterionId" :calculation-list="calculationList" :reading-task-state="readingTaskState" :criterion-id="criterionId" :calculation-list="calculationList"
:question-mark-info-list="questionMarkInfoList" :questions-mark-status="questionsMarkStatus" :question-mark-info-list="questionMarkInfoList" :questions-mark-status="questionsMarkStatus"
:is-baseline="isBaseLineTask" @resetFormItemData="resetFormItemData" @setFormItemData="setFormItemData" :questionsSegmentMarkStatus="questionsSegmentMarkStatus" :is-baseline="isBaseLineTask"
@getQuestions="getQuestions" @operateImageMarker="operateImageMarker" @resetFormItemData="resetFormItemData" @setFormItemData="setFormItemData" @getQuestions="getQuestions"
@unBindAnnotationToQuestion="unBindAnnotationToQuestion" @handleReadingChart="handleReadingChart" /> @operateImageMarker="operateImageMarker" @unBindAnnotationToQuestion="unBindAnnotationToQuestion"
@handleReadingChart="handleReadingChart" @saveSegmentBindingAndAnswer="saveSegmentBindingAndAnswer" />
</template> </template>
<el-form-item v-if="readingTaskState < 2"> <el-form-item v-if="readingTaskState < 2">
@ -58,7 +59,7 @@
<script> <script>
import { getCustomTableQuestionAnswer, changeDicomReadingQuestionAnswer, submitVisitTaskQuestionsInDto, verifyVisitTaskQuestions, getQuestionCalculateRelation, saveTaskQuestion } from '@/api/trials' import { getCustomTableQuestionAnswer, changeDicomReadingQuestionAnswer, submitVisitTaskQuestionsInDto, verifyVisitTaskQuestions, getQuestionCalculateRelation, saveTaskQuestion } from '@/api/trials'
import { setSkipReadingCache, resetReadingTask, saveTableQuestionMark, saveAnswerAndBindingNoneDicomMark, changePlottingScaleChangeAnswer } from '@/api/reading' import { setSkipReadingCache, resetReadingTask, saveTableQuestionMark, saveAnswerAndBindingNoneDicomMark, changePlottingScaleChangeAnswer, getSegmentBindingList, saveSegmentBindingAndAnswer, getSegmentList, getSegmentationList } from '@/api/reading'
import const_ from '@/const/sign-code' import const_ from '@/const/sign-code'
import QuestionFormItem from './QuestionFormItem' import QuestionFormItem from './QuestionFormItem'
import SignForm from '@/views/trials/components/newSignForm' import SignForm from '@/views/trials/components/newSignForm'
@ -116,6 +117,7 @@ export default {
imageTool: '', imageTool: '',
imageToolAttribute: '', imageToolAttribute: '',
questionsMarkStatus: {}, questionsMarkStatus: {},
questionsSegmentMarkStatus: {},
digitPlaces: 2, digitPlaces: 2,
questionImageToolAttributeInfo: {}, questionImageToolAttributeInfo: {},
unSaveTargets: [], unSaveTargets: [],
@ -133,6 +135,7 @@ export default {
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.getQuestionCalculateRelation() this.getQuestionCalculateRelation()
this.getQuestions(true) this.getQuestions(true)
this.initSegmentBinding()
DicomEvent.$on('opentableCol', (data) => { DicomEvent.$on('opentableCol', (data) => {
let { visible } = data let { visible } = data
this.isTableVisible = visible this.isTableVisible = visible
@ -433,8 +436,13 @@ export default {
REMOVE: 4, // REMOVE: 4, //
SAVE_OUTER: 5, // SAVE_OUTER: 5, //
UPDATE: 6, // UPDATE: 6, //
SAVE_TABLE: 7 // SAVE_TABLE: 7, //
BIND_SEGMENT: 21, //
CHANGE_SEGMENT: 22, //
VIEW_SEGMENT: 23, //
REMOVE_SEGMENT: 24, //
} }
console.log(obj, 'obj')
const { question, operateStateEnum, rowId, answer } = obj const { question, operateStateEnum, rowId, answer } = obj
const { Id, IsTableQuestion, ImageTool, ImageToolAttribute, ParentQsId, RowId, QuestionName, QuestionEnName } = question const { Id, IsTableQuestion, ImageTool, ImageToolAttribute, ParentQsId, RowId, QuestionName, QuestionEnName } = question
@ -446,7 +454,7 @@ export default {
operateQuestionId: Id, operateQuestionId: Id,
operateQuestionName: this.isEN ? QuestionEnName : QuestionName, operateQuestionName: this.isEN ? QuestionEnName : QuestionName,
operateRowId: RowId, operateRowId: RowId,
operateParentQsId: ParentQsId operateParentQsId: ParentQsId,
}) })
const stateHandlers = { const stateHandlers = {
[STATE.BIND]: () => this.$emit('setReadingToolPassive'), [STATE.BIND]: () => this.$emit('setReadingToolPassive'),
@ -456,12 +464,182 @@ export default {
[STATE.REMOVE]: this.handleRemoveAnnotation, [STATE.REMOVE]: this.handleRemoveAnnotation,
[STATE.SAVE_OUTER]: this.isNoneDicom ? this.handleSaveNoneDicomOuterQuestions : this.handleSaveOuterQuestions, [STATE.SAVE_OUTER]: this.isNoneDicom ? this.handleSaveNoneDicomOuterQuestions : this.handleSaveOuterQuestions,
[STATE.UPDATE]: this.handleUpdateValue, [STATE.UPDATE]: this.handleUpdateValue,
[STATE.SAVE_TABLE]: this.isNoneDicom ? this.handleSaveNoneDicomTableQuestions : this.handleSaveTableQuestions [STATE.SAVE_TABLE]: this.isNoneDicom ? this.handleSaveNoneDicomTableQuestions : this.handleSaveTableQuestions,
[STATE.BIND_SEGMENT]: this.handleBindSegment,
[STATE.CHANGE_SEGMENT]: this.handleBindSegment,
[STATE.VIEW_SEGMENT]: this.handleViewSegment,
[STATE.REMOVE_SEGMENT]: this.handleRemoveSegment,
} }
const handler = stateHandlers[operateStateEnum] const handler = stateHandlers[operateStateEnum]
handler && await handler.call(this, obj) handler && await handler.call(this, obj)
}, },
async handleViewSegment(obj) {
try {
let o = {}
if (this.isTableQuestion) {
o.TableQuestionId = this.operateQuestionId
o.RowId = this.operateRowId
} else {
o.QuestionId = this.operateQuestionId
}
let list = await this.getSegmentBindingList(o)
if (list && list.length > 0) {
let segment = await this.getSegmentList(list[0].SegmentId)
if (segment[0].SegmentJson) {
let obj = JSON.parse(segment[0].SegmentJson)
segment[0].stats = obj.stats
segment[0].bidirectional = obj.bidirectional
segment[0].segmentationId = segment[0].SegmentationId
segment[0].segmentIndex = segment[0].SegmentMumber
}
let segmentGroup = await this.getSegmentationList(list[0].SegmentationId)
this.$emit('viewCustomAnnotationSeries', {
visitTaskId: this.visitTaskId,
segment: segment[0],
segmentGroup: segmentGroup[0]
})
}
} catch (err) {
console.log(err)
}
},
handleBindSegment(obj) {
this.$emit("openSegmentForm", { visitInfo: this.visitInfo })
},
handleSegmentSave(obj) {
let imageToolAttribute = this.imageToolAttribute
let answer = ''
if (imageToolAttribute === 'length' || imageToolAttribute === 'width') {
let s = {
length: "maxMajor",
width: 'maxMinor'
}
if (!obj.bidirectional || !obj.bidirectional.maxMajor) return this.$confirm(this.$t("segment:error:notValue"))
answer = obj.bidirectional[s[imageToolAttribute]] ? (obj.bidirectional[s[imageToolAttribute]]).toFixed(this.digitPlaces) : ''
} else {
if (!obj.stats) return this.$confirm(this.$t("segment:error:notValue"))
answer = obj.stats[imageToolAttribute] ? Number((obj.stats[imageToolAttribute]).value).toFixed(this.digitPlaces) : ''
}
let o = {
Answer: answer,
SegmentId: obj.Id,
SegmentationId: obj.SegmentationId,
QuestionId: this.isTableQuestion ? this.operateParentQsId : this.operateQuestionId,
RowId: this.isTableQuestion ? this.operateRowId : null,
TableQuestionId: this.isTableQuestion ? this.operateQuestionId : null,
VisitTaskId: this.visitTaskId,
}
if (this.isTableQuestion) {
return DicomEvent.$emit('setTableQuestionAnswer', { id: this.operateQuestionId, answer, ParentQsId: this.operateParentQsId, data: o })
} else {
this.$set(this.questionForm, this.operateQuestionId, answer)
}
this.saveSegmentBindingAndAnswer([o])
},
//
async handleRemoveSegment(obj) {
const { question } = obj
let confirm = await this.$confirm(this.$t('segment:confirm:sureDelete'))
if (!confirm) return false
this.$set(this.questionForm, question.Id, '')
let o = {
Answer: '',
SegmentId: null,
SegmentationId: null,
QuestionId: this.isTableQuestion ? this.operateParentQsId : this.operateQuestionId,
RowId: this.isTableQuestion ? this.operateRowId : null,
TableQuestionId: this.isTableQuestion ? this.operateQuestionId : null,
VisitTaskId: this.visitTaskId,
}
this.saveSegmentBindingAndAnswer([o])
},
//
async saveSegmentBindingAndAnswer(list) {
try {
let data = {
VisitTaskId: this.visitTaskId,
BindingList: list
}
let res = await saveSegmentBindingAndAnswer(data)
if (res.IsSuccess) {
this.initSegmentBinding()
}
} catch (err) {
console.log(err)
}
},
//
async initSegmentBinding() {
try {
let list = await this.getSegmentBindingList()
this.questionsSegmentMarkStatus = {}
list.forEach(item => {
if (item.TableQuestionId && item.RowId) {
this.$set(this.questionsSegmentMarkStatus, `${item.RowId}_${item.TableQuestionId}`, item.SegmentId)
} else {
this.$set(this.questionsSegmentMarkStatus, item.QuestionId, item.SegmentId)
}
})
} catch (err) {
console.log(err)
}
},
//
async getSegmentBindingList(param = {}) {
try {
let data = {
VisitTaskId: this.visitTaskId,
PageSize: 9999,
PageIndex: 1,
}
data = Object.assign(data, param)
let res = await getSegmentBindingList(data)
if (res.IsSuccess) {
return res.Result.CurrentPageData
}
} catch (err) {
console.log(err)
}
},
//
async getSegmentList(id) {
try {
let data = {
// SegmentationId: id,
PageSize: 9999,
PageIndex: 1,
}
if (id) data.Id = id
let res = await getSegmentList(data)
if (res.IsSuccess) {
return res.Result.CurrentPageData
}
} catch (err) {
console.log(err)
}
},
//
async getSegmentationList(id) {
try {
let data = {
VisitTaskId: this.visitInfo.VisitTaskId,
PageSize: 9999,
PageIndex: 1,
}
if (id) data.Id = id
let res = await getSegmentationList(data);
if (res.IsSuccess) {
return res.Result.CurrentPageData;
}
} catch (err) {
console.log(err)
}
},
async handleViewAnnotation(obj) { async handleViewAnnotation(obj) {
const index = this.findMarkIndex(obj.question) const index = this.findMarkIndex(obj.question)
if (index === -1) return if (index === -1) return

View File

@ -107,7 +107,53 @@
<el-input v-if="question.Type === 'increment'" v-model="questionForm[question.Id]" disabled /> <el-input v-if="question.Type === 'increment'" v-model="questionForm[question.Id]" disabled />
<!-- 数值 --> <!-- 数值 -->
<template v-if="question.Type === 'number' && (question.ImageMarkEnum === 1 || question.ImageMarkEnum === 2)"> <template v-if="question.Type === 'number' && (question.ImageMarkEnum === 1 || question.ImageMarkEnum === 2)">
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;"> <div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;"
v-if="question.ImageMarkTypeEnum === 1">
<el-input type="text" @change="(val) => { formItemNumberChange(val, question) }"
@input="numberInput(question.Id)"
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
v-model="questionForm[question.Id]"
:title="questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].OrderMarkName : question.Remark"
:disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1 || question.IsPreinstall"
style="width: 150px;margin-right: 5px;">
<template v-if="question.Unit !== 0" slot="append">
{{ question.Unit !== 4 ? $fd('ValueUnit', question.Unit) : question.CustomUnit }}
</template>
</el-input>
<svg-icon v-if="question.ShowChartTypeEnum > 0 && taskInfo.IsReadingTaskViewInOrder === 1"
icon-class="readingChart" class="svg-icon svg-readingChart" @click.stop="(e) => handleReadingChart({
e,
data: {
TableQuestionId: question.Id,
RowIndex: questionForm.RowIndex,
QuestionName: question.QuestionName
}
})" />
<!-- 绑定 -->
<el-button
v-if="readingTaskState < 2 && (!questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id])"
size="mini" type="text" @click="operateImageMarker({ operateStateEnum: 21, question })">
{{ $t('dicom3D:CustomizeQuestionFormItem:button:bind') }}
</el-button>
<!-- 更改 -->
<el-button
v-if="readingTaskState < 2 && (questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id])"
size="mini" type="text" @click="operateImageMarker({ operateStateEnum: 22, question })">
{{ $t('dicom3D:CustomizeQuestionFormItem:button:edit') }}
</el-button>
<!-- 查看 -->
<el-button v-if="questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id]" size="mini"
type="text" @click="operateImageMarker({ operateStateEnum: 23, question })">
{{ $t('dicom3D:CustomizeQuestionFormItem:button:view') }}
</el-button>
<!-- 移除 -->
<el-button
v-if="readingTaskState < 2 && (questionsSegmentMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id])"
size="mini" type="text" @click="operateImageMarker({ operateStateEnum: 24, question })">
{{ $t('dicom3D:CustomizeQuestionFormItem:button:remove') }}
</el-button>
</div>
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;" v-else>
<el-input type="text" @change="(val) => { formItemNumberChange(val, question) }" <el-input type="text" @change="(val) => { formItemNumberChange(val, question) }"
@input="numberInput(question.Id)" @input="numberInput(question.Id)"
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)" @blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
@ -276,6 +322,12 @@ export default {
return {} return {}
} }
}, },
questionsSegmentMarkStatus: {
type: Object,
default() {
return {}
}
},
parentQsId: { parentQsId: {
type: String, type: String,
default: '' default: ''

View File

@ -386,6 +386,35 @@ const config = {
'disabledReason': '' 'disabledReason': ''
}, },
], ],
'customizeStandardsSegmentDicom': [
// {
// 'name': 'Contour分割',
// 'icon': 'contour',
// 'toolName': 'Contour',
// 'props': ['length'],
// 'i18nKey': 'trials:reading:button:Contour',
// 'isDisabled': false,
// 'disabledReason': ''
// },
{
'name': 'Labelmap分割',
'icon': 'labelmap',
'toolName': 'Labelmap',
'props': ['max', 'min', 'volume', 'count', 'mean', 'stdDev', 'length', 'width'],
'i18nKey': 'trials:reading:button:Labelmap',
'isDisabled': false,
'disabledReason': ''
},
// {
// 'name': 'Surface分割',
// 'icon': 'surface',
// 'toolName': 'Surface',
// 'props': ['area', 'mean', 'max', 'stdDev'],
// 'i18nKey': 'trials:reading:button:Surface',
// 'isDisabled': false,
// 'disabledReason': ''
// },
],
} }
const getTools = (criterionType) => { const getTools = (criterionType) => {
const standard = config.standards.find(s => s.type === criterionType) const standard = config.standards.find(s => s.type === criterionType)
@ -399,4 +428,8 @@ const getCustomizeStandardsNoneDicomTools = (toolNames) => {
const filteredTools = config.customizeStandardsNoneDicom.filter(item => toolNames.includes(item.toolName)) const filteredTools = config.customizeStandardsNoneDicom.filter(item => toolNames.includes(item.toolName))
return filteredTools || [] return filteredTools || []
} }
export { config, getTools, getCustomizeStandardsTools, getCustomizeStandardsNoneDicomTools } const getCustomizeStandardsSegmentDicomTools = (toolNames) => {
const filteredTools = config.customizeStandardsSegmentDicom.filter(item => toolNames.includes(item.toolName))
return filteredTools || []
}
export { config, getTools, getCustomizeStandardsTools, getCustomizeStandardsNoneDicomTools, getCustomizeStandardsSegmentDicomTools }

View File

@ -323,7 +323,7 @@ export default {
) )
var token = getToken() var token = getToken()
var path = '' var path = ''
if (this.readingTool === 0 || this.readingTool === 2) { if (this.readingTool === 0 || this.readingTool === 2 || this.readingTool === 3) {
if (this.criterionType === 0 && this.trialId === '08dd28b3-6843-fc05-0242-ac1301000000') { if (this.criterionType === 0 && this.trialId === '08dd28b3-6843-fc05-0242-ac1301000000') {
path = `/fusion?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${this.trialId}&studyId=62b3dfc4-1e04-4180-910d-fe595f398361&ctseriesId=1bd24f53-d419-32e5-92d4-2b04640aaa65&ptseriesId=2b7b128d-8c3f-8357-ad14-e38f3acbbdff&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&TokenKey=${token}&lang=${this.$i18n.locale}` path = `/fusion?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${this.trialId}&studyId=62b3dfc4-1e04-4180-910d-fe595f398361&ctseriesId=1bd24f53-d419-32e5-92d4-2b04640aaa65&ptseriesId=2b7b128d-8c3f-8357-ad14-e38f3acbbdff&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&TokenKey=${token}&lang=${this.$i18n.locale}`
} else { } else {

View File

@ -484,8 +484,15 @@
:disabled="form.IsRequired === 2 && item.value === 1">{{ item.label }}</el-radio> :disabled="form.IsRequired === 2 && item.value === 1">{{ item.label }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!-- 测量工具 ImageTool --> <!--标记类型-->
<el-form-item v-if="form.ImageMarkEnum === 1 || form.ImageMarkEnum === 2" <el-form-item v-if="form.ImageMarkEnum === 1 || form.ImageMarkEnum === 2"
:label="$t('trials:readingUnit:qsList:title:ImageMarkTypeEnum')" prop="ImageMarkTypeEnum">
<el-radio-group v-model="form.ImageMarkTypeEnum" @change="ImageMarkTypeEnumChange">
<el-radio v-for="item of $d.ImageMarkType" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<!-- 测量工具 ImageTool -->
<el-form-item v-if="(form.ImageMarkEnum === 1 || form.ImageMarkEnum === 2) && form.ImageMarkTypeEnum === 0"
:label="$t('trials:readingUnit:qsList:title:ImageTool')" prop="ImageTool" :rules="[ :label="$t('trials:readingUnit:qsList:title:ImageTool')" prop="ImageTool" :rules="[
{ required: true, message: this.$t('common:ruleMessage:select') } { required: true, message: this.$t('common:ruleMessage:select') }
]"> ]">
@ -495,6 +502,17 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!-- 分割工具 ImageTool -->
<el-form-item v-if="(form.ImageMarkEnum === 1 || form.ImageMarkEnum === 2) && form.ImageMarkTypeEnum === 1"
:label="$t('trials:readingUnit:qsList:title:ImageTool')" prop="ImageTool" :rules="[
{ required: true, message: this.$t('common:ruleMessage:select') }
]">
<el-radio-group v-model="form.ImageTool" @change="imageSegmentToolChange">
<el-radio v-for="tool of readingSegmentTools" :key="tool.toolName" :label="tool.toolName">
{{ $t(tool.i18nKey) }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 测量值 ImageToolAttribute --> <!-- 测量值 ImageToolAttribute -->
<el-form-item v-if="form.ImageTool && imageToolAttributes.length > 0" <el-form-item v-if="form.ImageTool && imageToolAttributes.length > 0"
:label="$t('trials:readingUnit:qsList:title:ImageToolAttribute')" prop="ImageToolAttribute" :rules="[ :label="$t('trials:readingUnit:qsList:title:ImageToolAttribute')" prop="ImageToolAttribute" :rules="[
@ -696,6 +714,12 @@ export default {
return [] return []
} }
}, },
readingSegmentTools: {
type: Array,
default() {
return []
}
},
readingVersionEnum: { readingVersionEnum: {
type: Number, type: Number,
default: 0 default: 0
@ -754,6 +778,7 @@ export default {
ClassifyEditType: null, ClassifyEditType: null,
ClassifyShowType: null, ClassifyShowType: null,
ImageMarkEnum: 0, ImageMarkEnum: 0,
ImageMarkTypeEnum: 0,
ShowChartTypeEnum: 0, ShowChartTypeEnum: 0,
ImageTool: '', ImageTool: '',
ImageToolAttribute: '', ImageToolAttribute: '',
@ -1050,9 +1075,12 @@ export default {
} }
} }
} }
if (this.form.ImageTool) { if (this.form.ImageTool && this.form.ImageMarkTypeEnum === 0) {
this.imageToolChange(this.form.ImageTool) this.imageToolChange(this.form.ImageTool)
} }
if (this.form.ImageTool && this.form.ImageMarkTypeEnum === 1) {
this.imageSegmentToolChange(this.form.ImageTool)
}
} }
if (!this.data.ShowOrder && this.data.ShowOrder !== 0) { if (!this.data.ShowOrder && this.data.ShowOrder !== 0) {
if (this.list.length > 0) { if (this.list.length > 0) {
@ -1172,14 +1200,26 @@ export default {
this.form.ImageTool = '' this.form.ImageTool = ''
this.form.ImageToolAttribute = '' this.form.ImageToolAttribute = ''
this.imageToolAttributes = [] this.imageToolAttributes = []
this.form.ImageMarkTypeEnum = 0
} }
}, },
ImageMarkTypeEnumChange(val) {
this.form.ImageTool = ''
this.form.ImageToolAttribute = ''
this.imageToolAttributes = []
},
imageToolChange(v) { imageToolChange(v) {
let i = this.readingTools.findIndex(tool => tool.toolName === v) let i = this.readingTools.findIndex(tool => tool.toolName === v)
if (i > -1) { if (i > -1) {
this.imageToolAttributes = this.readingTools[i].props this.imageToolAttributes = this.readingTools[i].props
} }
}, },
imageSegmentToolChange(v) {
let i = this.readingSegmentTools.findIndex(tool => tool.toolName === v)
if (i > -1) {
this.imageToolAttributes = this.readingSegmentTools[i].props
}
},
parentQuestionChange(val, form) { parentQuestionChange(val, form) {
this.isParentExistGroup = false this.isParentExistGroup = false
if (val) { if (val) {
@ -1273,6 +1313,7 @@ export default {
form.ClassifyType = null form.ClassifyType = null
form.ClassifyShowType = null form.ClassifyShowType = null
form.ImageMarkEnum = 0 form.ImageMarkEnum = 0
form.ImageMarkTypeEnum = 0
form.ShowChartTypeEnum = 0 form.ShowChartTypeEnum = 0
form.ImageTool = '' form.ImageTool = ''
form.ImageToolAttribute = '' form.ImageToolAttribute = ''

View File

@ -1,148 +1,81 @@
<template> <template>
<div v-loading="loading"> <div v-loading="loading">
<div <div class="search-form" style="text-align: left;">
class="search-form"
style="text-align: left;"
>
<!-- 新增 --> <!-- 新增 -->
<el-button <el-button v-if="!isConfirm && hasPermi(['trials:trials-panel:setting:reading-unit:edit']) && !isFromSystem"
v-if="!isConfirm && hasPermi(['trials:trials-panel:setting:reading-unit:edit']) && !isFromSystem" size="mini" type="primary" @click="handleAdd">
size="mini"
type="primary"
@click="handleAdd"
>
{{ $t('common:button:add') }} {{ $t('common:button:add') }}
</el-button> </el-button>
<!-- 预览 --> <!-- 预览 -->
<el-button <el-button v-if="isPreview" :disabled="tblList.length === 0" size="mini" type="primary" @click="handlePreview">
v-if="isPreview"
:disabled="tblList.length===0"
size="mini"
type="primary"
@click="handlePreview"
>
{{ $t('common:button:preview') }} {{ $t('common:button:preview') }}
</el-button> </el-button>
</div> </div>
<el-table <el-table :data="tblList" size="small">
:data="tblList" <el-table-column prop="ShowOrder" label="" width="50" />
size="small"
>
<el-table-column
prop="ShowOrder"
label=""
width="50"
/>
<!-- 分组 --> <!-- 分组 -->
<el-table-column <el-table-column prop="QuestionGroupName" v-if="$i18n.locale === 'zh'"
prop="QuestionGroupName" :label="$t('trials:readingUnit:qsList:title:groupNameEn')" show-overflow-tooltip />
v-if="$i18n.locale === 'zh'"
:label="$t('trials:readingUnit:qsList:title:groupNameEn')"
show-overflow-tooltip
/>
<!-- 分组(EN) --> <!-- 分组(EN) -->
<el-table-column <el-table-column prop="QuestionGroupEnName" v-if="$i18n.locale === 'en'"
prop="QuestionGroupEnName" :label="$t('trials:readingUnit:qsList:title:groupNameEn')" show-overflow-tooltip />
v-if="$i18n.locale === 'en'"
:label="$t('trials:readingUnit:qsList:title:groupNameEn')"
show-overflow-tooltip
/>
<!-- 名称 --> <!-- 名称 -->
<el-table-column <el-table-column prop="QuestionName" v-if="$i18n.locale === 'zh'"
prop="QuestionName" :label="$t('trials:readingUnit:qsList:title:qsNameEn')" show-overflow-tooltip />
v-if="$i18n.locale === 'zh'"
:label="$t('trials:readingUnit:qsList:title:qsNameEn')"
show-overflow-tooltip
/>
<!-- 名称(EN) --> <!-- 名称(EN) -->
<el-table-column <el-table-column prop="QuestionEnName" v-if="$i18n.locale === 'en'"
prop="QuestionEnName" :label="$t('trials:readingUnit:qsList:title:qsNameEn')" show-overflow-tooltip />
v-if="$i18n.locale === 'en'"
:label="$t('trials:readingUnit:qsList:title:qsNameEn')"
show-overflow-tooltip
/>
<!-- 题型 --> <!-- 题型 -->
<el-table-column <el-table-column prop="Type" :label="$t('trials:readingUnit:qsList:title:type')" show-overflow-tooltip>
prop="Type"
:label="$t('trials:readingUnit:qsList:title:type')"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('Criterion_Question_Type',scope.row.Type) }} {{ $fd('Criterion_Question_Type', scope.row.Type) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 是否显示 --> <!-- 是否显示 -->
<el-table-column <el-table-column prop="ShowQuestion" :label="$t('trials:readingUnit:qsList:title:isShow')" show-overflow-tooltip>
prop="ShowQuestion"
:label="$t('trials:readingUnit:qsList:title:isShow')"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('ShowQuestion',scope.row.ShowQuestion) }} {{ $fd('ShowQuestion', scope.row.ShowQuestion) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 是否必填 --> <!-- 是否必填 -->
<el-table-column <el-table-column prop="IsRequired" :label="$t('trials:readingUnit:qsList:title:isRequired')"
prop="IsRequired" show-overflow-tooltip>
:label="$t('trials:readingUnit:qsList:title:isRequired')"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('QuestionRequired',scope.row.IsRequired) }} {{ $fd('QuestionRequired', scope.row.IsRequired) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 是否裁判问题 --> <!-- 是否裁判问题 -->
<el-table-column <el-table-column prop="IsJudgeQuestion" :label="$t('trials:readingUnit:qsList:title:isJudgeQuestion')" width="120"
prop="IsJudgeQuestion" show-overflow-tooltip>
:label="$t('trials:readingUnit:qsList:title:isJudgeQuestion')"
width="120"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('YesOrNo', scope.row.IsJudgeQuestion) }} {{ $fd('YesOrNo', scope.row.IsJudgeQuestion) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 是否在阅片页面显示 --> <!-- 是否在阅片页面显示 -->
<el-table-column <el-table-column prop="IsShowInDicom" :label="$t('trials:readingUnit:qsList:title:isShowInDicom')" width="140"
prop="IsShowInDicom" show-overflow-tooltip>
:label="$t('trials:readingUnit:qsList:title:isShowInDicom')"
width="140"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('YesOrNo', scope.row.IsShowInDicom) }} {{ $fd('YesOrNo', scope.row.IsShowInDicom) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 是否在全局阅片显示 --> <!-- 是否在全局阅片显示 -->
<el-table-column <el-table-column prop="GlobalReadingShowType" :label="$t('trials:readingUnit:qsList:title:globalReadingShowType')"
prop="GlobalReadingShowType" width="160" show-overflow-tooltip>
:label="$t('trials:readingUnit:qsList:title:globalReadingShowType')"
width="160"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('GlobalReadingShowType', scope.row.GlobalReadingShowType) }} {{ $fd('GlobalReadingShowType', scope.row.GlobalReadingShowType) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 导出目标表格 --> <!-- 导出目标表格 -->
<el-table-column <el-table-column prop="ExportResult" :label="$t('trials:readingUnit:qsList:title:ExportResult')" width="160"
prop="ExportResult" show-overflow-tooltip>
:label="$t('trials:readingUnit:qsList:title:ExportResult')"
width="160"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ getStringResult(scope.row.ExportResult, 'ExportResult') }} {{ getStringResult(scope.row.ExportResult, 'ExportResult') }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 限制编辑 --> <!-- 限制编辑 -->
<el-table-column <el-table-column prop="LimitEdit" :label="$t('trials:readingUnit:qsList:title:limitEdit')" width="160"
prop="LimitEdit" show-overflow-tooltip>
:label="$t('trials:readingUnit:qsList:title:limitEdit')"
width="160"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('LimitEdit', scope.row.LimitEdit) }} {{ $fd('LimitEdit', scope.row.LimitEdit) }}
</template> </template>
@ -154,105 +87,50 @@
width="140" width="140"
show-overflow-tooltip show-overflow-tooltip
/> --> /> -->
<el-table-column <el-table-column prop="" :label="$t('common:action:action')" width="300" show-overflow-tooltip>
prop=""
:label="$t('common:action:action')"
width="300"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 编辑 --> <!-- 编辑 -->
<el-button <el-button v-if="!isConfirm && !isFromSystem && hasPermi(['trials:trials-panel:setting:reading-unit:edit'])"
v-if="!isConfirm && !isFromSystem && hasPermi(['trials:trials-panel:setting:reading-unit:edit'])" type="primary" size="mini" @click="handleEdit(scope.row)">
type="primary"
size="mini"
@click="handleEdit(scope.row)"
>
{{ $t('trials:readingUnit:qsList:title:edit') }} {{ $t('trials:readingUnit:qsList:title:edit') }}
</el-button> </el-button>
<!-- 查看 --> <!-- 查看 -->
<el-button <el-button v-else type="primary" size="mini" @click="handlelook(scope.row)">
v-else
type="primary"
size="mini"
@click="handlelook(scope.row)"
>
{{ $t('trials:readingUnit:qsList:title:view') }} {{ $t('trials:readingUnit:qsList:title:view') }}
</el-button> </el-button>
<!-- 表格问题 --> <!-- 表格问题 -->
<el-button <el-button v-if="scope.row.Type === 'table' || scope.row.Type === 'basicTable'" type="primary" size="mini"
v-if="scope.row.Type === 'table' || scope.row.Type === 'basicTable'" @click="handleConfig(scope.row)">
type="primary"
size="mini"
@click="handleConfig(scope.row)"
>
{{ $t('trials:readingUnit:qsList:title:tableQs') }} {{ $t('trials:readingUnit:qsList:title:tableQs') }}
</el-button> </el-button>
<!-- 删除 --> <!-- 删除 -->
<el-button <el-button v-if="!isConfirm && !isFromSystem && hasPermi(['trials:trials-panel:setting:reading-unit:edit'])"
v-if="!isConfirm && !isFromSystem && hasPermi(['trials:trials-panel:setting:reading-unit:edit'])" type="danger" size="mini" @click="handleDelete(scope.row)">
type="danger"
size="mini"
@click="handleDelete(scope.row)"
>
{{ $t('trials:readingUnit:qsList:title:delete') }} {{ $t('trials:readingUnit:qsList:title:delete') }}
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-dialog <el-dialog v-if="addOrEdit.visible" :visible.sync="addOrEdit.visible" :close-on-click-modal="false"
v-if="addOrEdit.visible" :title="addOrEdit.title" width="800px" append-to-body custom-class="base-dialog-wrapper">
:visible.sync="addOrEdit.visible" <questions-form ref="addOrEdit" :data="rowData" :trial-criterion-id="trialCriterionId"
:close-on-click-modal="false" :is-from-system="isFromSystem" :digit-places="digitPlaces" :readingTools="readingTools"
:title="addOrEdit.title" :readingSegmentTools="readingSegmentTools" :readingVersionEnum="readingVersionEnum" :list="tblList"
width="800px" :is-look="isLook" :is-system-criterion="isSystemCriterion" @close="addOrEdit.visible = false" @getList="getList"
append-to-body @reloadArbitrationRules="reloadArbitrationRules" />
custom-class="base-dialog-wrapper"
>
<questions-form
ref="addOrEdit"
:data="rowData"
:trial-criterion-id="trialCriterionId"
:is-from-system="isFromSystem"
:digit-places="digitPlaces"
:readingTools="readingTools"
:readingVersionEnum="readingVersionEnum"
:list="tblList"
:is-look="isLook"
:is-system-criterion="isSystemCriterion"
@close="addOrEdit.visible = false"
@getList="getList"
@reloadArbitrationRules="reloadArbitrationRules"
/>
</el-dialog> </el-dialog>
<el-dialog <el-dialog v-if="preview.visible" :visible.sync="preview.visible" :close-on-click-modal="false"
v-if="preview.visible" :title="preview.title" :fullscreen="true">
:visible.sync="preview.visible"
:close-on-click-modal="false"
:title="preview.title"
:fullscreen="true"
>
<questions-preview :criterion-id="trialCriterionId" :is-system-criterion="isSystemCriterion" :form-type="1" /> <questions-preview :criterion-id="trialCriterionId" :is-system-criterion="isSystemCriterion" :form-type="1" />
</el-dialog> </el-dialog>
<el-dialog <el-dialog v-if="config.visible" :visible.sync="config.visible" :close-on-click-modal="false" :title="config.title"
v-if="config.visible" :fullscreen="true">
:visible.sync="config.visible" <table-qs-list :digit-places="digitPlaces" :reading-question-id="rowData.Id" :is-from-system="isFromSystem"
:close-on-click-modal="false" :is-confirm="isConfirm" :criterion-id="trialCriterionId" :readingTools="readingTools"
:title="config.title" :readingSegmentTools="readingSegmentTools" :readingVersionEnum="readingVersionEnum"
:fullscreen="true" @close="config.visible = false" />
>
<table-qs-list
:digit-places="digitPlaces"
:reading-question-id="rowData.Id"
:is-from-system="isFromSystem"
:is-confirm="isConfirm"
:criterion-id="trialCriterionId"
:readingTools="readingTools"
:readingVersionEnum="readingVersionEnum"
@close="config.visible = false"
/>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
@ -310,6 +188,12 @@ export default {
return [] return []
} }
}, },
readingSegmentTools: {
type: Array,
default() {
return []
}
},
readingVersionEnum: { readingVersionEnum: {
type: Number, type: Number,
default: 0 default: 0
@ -350,7 +234,8 @@ export default {
this.rowData = { this.rowData = {
ReadingQuestionCriterionTrialId: this.trialCriterionId, ReadingQuestionCriterionTrialId: this.trialCriterionId,
ReadingCriterionPageId: this.readingCriterionPageId, ReadingCriterionPageId: this.readingCriterionPageId,
Id: '' } Id: ''
}
this.isLook = false this.isLook = false
this.addOrEdit.title = this.$t('trials:readingUnit:qsList:title:add')// '' this.addOrEdit.title = this.$t('trials:readingUnit:qsList:title:add')// ''
this.addOrEdit.visible = true this.addOrEdit.visible = true
@ -362,9 +247,9 @@ export default {
this.rowData.ReadingCriterionPageId = this.readingCriterionPageId this.rowData.ReadingCriterionPageId = this.readingCriterionPageId
let title = '' let title = ''
if (this.$i18n.locale === 'zh' && (row.QuestionName || row.GroupName)) { if (this.$i18n.locale === 'zh' && (row.QuestionName || row.GroupName)) {
title =`${row.QuestionName ? row.QuestionName : row.GroupName}` title = `${row.QuestionName ? row.QuestionName : row.GroupName}`
} else if (this.$i18n.locale === 'en' && (row.QuestionEnName || row.GroupEnName)) { } else if (this.$i18n.locale === 'en' && (row.QuestionEnName || row.GroupEnName)) {
title =`: ${row.QuestionEnName ? row.QuestionEnName : row.GroupEnName}` title = `: ${row.QuestionEnName ? row.QuestionEnName : row.GroupEnName}`
} }
this.addOrEdit.title = `${this.$t('trials:readingUnit:qsList:title:view')} ${title} `// '' this.addOrEdit.title = `${this.$t('trials:readingUnit:qsList:title:view')} ${title} `// ''
this.addOrEdit.visible = true this.addOrEdit.visible = true
@ -431,5 +316,4 @@ export default {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped></style>
</style>

View File

@ -1,59 +1,37 @@
<template> <template>
<div> <div>
<el-form <el-form ref="readingCriterionsForm" v-loading="loading" :model="form" :rules="rules" label-width="120px"
ref="readingCriterionsForm" size="small">
v-loading="loading"
:model="form"
:rules="rules"
label-width="120px"
size="small"
>
<!-- '表单问题' --> <!-- '表单问题' -->
<el-form-item :label="$t('trials:readingUnit:readingCriterion:title:formQs')"> <el-form-item :label="$t('trials:readingUnit:readingCriterion:title:formQs')">
<questions-list <questions-list :ref="`questionList${trialReadingCriterionId}`" v-if="form.FormType === 1"
:ref="`questionList${trialReadingCriterionId}`" :trial-reading-criterion-id="trialReadingCriterionId" :list="readingInfo.TrialQuestionList"
v-if="form.FormType===1" :trial-criterion-id="readingInfo.TrialCriterionId" :is-confirm="isConfirm"
:trial-reading-criterion-id="trialReadingCriterionId" :is-system-criterion="isSystemCriterion" :is-from-system="readingInfo.IsFromSystem"
:list="readingInfo.TrialQuestionList" :digit-places="digitPlaces" :readingTools="readingTools" :readingSegmentTools="readingSegmentTools"
:trial-criterion-id="readingInfo.TrialCriterionId" :readingVersionEnum="readingVersionEnum" @reloadArbitrationRules="reloadArbitrationRules" />
:is-confirm="isConfirm"
:is-system-criterion="isSystemCriterion"
:is-from-system="readingInfo.IsFromSystem"
:digit-places="digitPlaces"
:readingTools="readingTools"
:readingVersionEnum="readingVersionEnum"
@reloadArbitrationRules="reloadArbitrationRules"
/>
</el-form-item> </el-form-item>
<el-form-item v-if=" hasPermi(['trials:trials-panel:setting:reading-unit:edit'])"> <el-form-item v-if="hasPermi(['trials:trials-panel:setting:reading-unit:edit'])">
<!-- &lt;!&ndash; 保存 &ndash;&gt;--> <!-- &lt;!&ndash; 保存 &ndash;&gt;-->
<!-- <el-button--> <!-- <el-button-->
<!-- v-if="!isConfirm && isAdditionalAssessment"--> <!-- v-if="!isConfirm && isAdditionalAssessment"-->
<!-- type="primary"--> <!-- type="primary"-->
<!-- @click="handleSave(true)"--> <!-- @click="handleSave(true)"-->
<!-- >--> <!-- >-->
<!-- {{ $t('common:button:save') }}--> <!-- {{ $t('common:button:save') }}-->
<!-- </el-button>--> <!-- </el-button>-->
<!-- 基础数据配置 --> <!-- 基础数据配置 -->
<el-button <el-button type="primary" @click="configBaseDataVisible = true">
type="primary"
@click="configBaseDataVisible = true"
>
{{ $t('trials:readingUnit:readingCriterion:title:baseDataCfg') }} {{ $t('trials:readingUnit:readingCriterion:title:baseDataCfg') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 基础数据配置 --> <!-- 基础数据配置 -->
<el-dialog <el-dialog v-if="configBaseDataVisible" :title="$t('trials:readingUnit:readingCriterion:title:baseDataCfg')"
v-if="configBaseDataVisible" :visible.sync="configBaseDataVisible" :close-on-click-modal="false" :fullscreen="true" append-to-body
:title="$t('trials:readingUnit:readingCriterion:title:baseDataCfg')" custom-class="base-dialog-wrapper">
:visible.sync="configBaseDataVisible" <BaseDataConfig :trial-reading-criterion-id="trialReadingCriterionId" :is-from-system="readingInfo.IsFromSystem"
:close-on-click-modal="false" :is-confirm="isConfirm" />
:fullscreen="true"
append-to-body
custom-class="base-dialog-wrapper"
>
<BaseDataConfig :trial-reading-criterion-id="trialReadingCriterionId" :is-from-system="readingInfo.IsFromSystem" :is-confirm="isConfirm" />
</el-dialog> </el-dialog>
@ -85,6 +63,12 @@ export default {
default() { default() {
return [] return []
} }
},
readingSegmentTools: {
type: Array,
default() {
return []
}
} }
}, },
data() { data() {
@ -122,7 +106,7 @@ export default {
this.additionalAssessmentOptionList = res.Result this.additionalAssessmentOptionList = res.Result
if (this.additionalAssessmentOptionList.length > 0) { if (this.additionalAssessmentOptionList.length > 0) {
this.additionalAssessmentOptionList.forEach(v => { this.additionalAssessmentOptionList.forEach(v => {
this.$set(this.form, 'AdditionalAssessmentType'+v.Id, v.IsSelected) this.$set(this.form, 'AdditionalAssessmentType' + v.Id, v.IsSelected)
}) })
} }
getTrialReadingCriterionInfo({ trialId, TrialReadingCriterionId: this.trialReadingCriterionId }).then(res => { getTrialReadingCriterionInfo({ trialId, TrialReadingCriterionId: this.trialReadingCriterionId }).then(res => {
@ -185,7 +169,7 @@ export default {
reloadArbitrationRules() { reloadArbitrationRules() {
this.$emit('reloadArbitrationRules') this.$emit('reloadArbitrationRules')
}, },
handleConfig() {} handleConfig() { }
} }
} }

View File

@ -30,9 +30,8 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!-- 测量工具 --> <!-- 测量工具 && (form.ReadingTool === 0 || form.ReadingTool === 1 || form.ReadingTool === 2)-->
<el-form-item <el-form-item v-if="CriterionType === 0 && form.ReadingVersionEnum === 1"
v-if="CriterionType === 0 && (form.ReadingTool === 0 || form.ReadingTool === 1 || form.ReadingTool === 2) && form.ReadingVersionEnum === 1"
:label="$t('trials:readingUnit:readingRules:title:measureTool')"> :label="$t('trials:readingUnit:readingRules:title:measureTool')">
<el-checkbox-group v-model="form.ReadingToolList" :disabled="isConfirm || <el-checkbox-group v-model="form.ReadingToolList" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) !hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
@ -42,6 +41,17 @@
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<!--分割工具 && (form.ReadingTool === 0 || form.ReadingTool === 1 || form.ReadingTool === 2)-->
<el-form-item v-if="CriterionType === 0 && form.ReadingVersionEnum === 1 && form.ReadingTool === 3"
:label="$t('trials:readingUnit:readingRules:title:segmentTool')">
<el-checkbox-group v-model="form.SegmentToolList" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<el-checkbox v-for="tool in segmentTools" :key="tool.toolName" :label="tool.toolName" name="SegmentToolList">
{{ $t(`${tool.i18nKey}`) }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<!--检查类型筛选--> <!--检查类型筛选-->
<el-form-item :label="$t('trials:processCfg:form:IsImageFilter')" prop="IsImageFilter"> <el-form-item :label="$t('trials:processCfg:form:IsImageFilter')" prop="IsImageFilter">
<el-radio-group v-model="form.IsImageFilter" @input="IsImageFilterChange" :disabled="isConfirm || <el-radio-group v-model="form.IsImageFilter" @input="IsImageFilterChange" :disabled="isConfirm ||
@ -421,6 +431,7 @@ export default {
ReadingTool: 0, ReadingTool: 0,
ReadingVersionEnum: null, ReadingVersionEnum: null,
ReadingToolList: [], ReadingToolList: [],
SegmentToolList: [],
ReadingTaskViewEnum: null, ReadingTaskViewEnum: null,
IsImageLabeled: null, IsImageLabeled: null,
IsReadingShowSubjectInfo: null, IsReadingShowSubjectInfo: null,
@ -616,7 +627,8 @@ export default {
modalityList: [], modalityList: [],
CriterionModalitys: [], CriterionModalitys: [],
modalityIsCheck: false, // modalityIsCheck: false, //
tools: [] tools: [],
segmentTools: []
} }
}, },
mounted() { mounted() {
@ -737,13 +749,20 @@ export default {
// //
handleReadingToolInput(val) { handleReadingToolInput(val) {
this.form.ReadingToolList = [] this.form.ReadingToolList = []
if (this.CriterionType !== 0) return this.tools = [] this.form.SegmentToolList = []
if (val === 0 || val === 2) { if (this.CriterionType !== 0) {
this.segmentTools = []
return this.tools = []
}
if (val === 0 || val === 2 || val === 3) {
this.tools = [...config.customizeStandards] this.tools = [...config.customizeStandards]
} }
if (val === 1) { if (val === 1) {
this.tools = [...config.customizeStandardsNoneDicom] this.tools = [...config.customizeStandardsNoneDicom]
} }
if (val === 3) {
this.segmentTools = [...config.customizeStandardsSegmentDicom]
}
}, },
// //
IsImageFilterChange(data) { IsImageFilterChange(data) {
@ -786,12 +805,15 @@ export default {
this.form.KeyFileListStr = this.form.KeyFileList.map(item => item.FileName).join(',') this.form.KeyFileListStr = this.form.KeyFileList.map(item => item.FileName).join(',')
} }
if (this.CriterionType === 0) { if (this.CriterionType === 0) {
if (this.form.ReadingTool === 0 || this.form.ReadingTool === 2) { if (this.form.ReadingTool === 0 || this.form.ReadingTool === 2 || this.form.ReadingTool === 3) {
this.tools = [...config.customizeStandards] this.tools = [...config.customizeStandards]
} }
if (this.form.ReadingTool === 1) { if (this.form.ReadingTool === 1) {
this.tools = [...config.customizeStandardsNoneDicom] this.tools = [...config.customizeStandardsNoneDicom]
} }
if (this.form.ReadingTool === 3) {
this.segmentTools = [...config.customizeStandardsSegmentDicom]
}
} }
this.CriterionModalitys = this.form.CriterionModalitys this.CriterionModalitys = this.form.CriterionModalitys
? this.form.CriterionModalitys.split('|') ? this.form.CriterionModalitys.split('|')
@ -817,7 +839,7 @@ export default {
this.$emit('setGlobalReading', res.Result.IsGlobalReading) this.$emit('setGlobalReading', res.Result.IsGlobalReading)
this.$emit('setOncologyReading', res.Result.IsOncologyReading) this.$emit('setOncologyReading', res.Result.IsOncologyReading)
this.$emit('setDigitPlaces', res.Result.DigitPlaces) this.$emit('setDigitPlaces', res.Result.DigitPlaces)
this.$emit('setReadingTools', { readingTools: res.Result.ReadingToolList, isNoneDicom: this.form.ReadingTool === 1 }) this.$emit('setReadingTools', { readingTools: res.Result.ReadingToolList, readingSegmentTools: res.Result.SegmentToolList, ReadingTool: this.form.ReadingTool })
if (res.Result.ReadingType === 1) { if (res.Result.ReadingType === 1) {
this.$emit('setArbitrationReading', false) this.$emit('setArbitrationReading', false)
@ -859,7 +881,7 @@ export default {
this.$emit('setGlobalReading', this.form.IsGlobalReading) this.$emit('setGlobalReading', this.form.IsGlobalReading)
this.$emit('setOncologyReading', this.form.IsOncologyReading) this.$emit('setOncologyReading', this.form.IsOncologyReading)
this.$emit('setDigitPlaces', this.form.DigitPlaces) this.$emit('setDigitPlaces', this.form.DigitPlaces)
this.$emit('setReadingTools', { readingTools: this.form.ReadingToolList, isNoneDicom: this.form.ReadingTool === 1 }) this.$emit('setReadingTools', { readingTools: this.form.ReadingToolList, readingSegmentTools: this.form.SegmentToolList, ReadingTool: this.form.ReadingTool })
if (this.form.ReadingType === 1) { if (this.form.ReadingType === 1) {
this.$emit('setArbitrationReading', false) this.$emit('setArbitrationReading', false)
} }

View File

@ -286,8 +286,15 @@
:disabled="form.IsRequired === 2 && item.value === 1">{{ item.label }}</el-radio> :disabled="form.IsRequired === 2 && item.value === 1">{{ item.label }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!-- 测量工具 ImageTool --> <!--标记类型-->
<el-form-item v-if="form.ImageMarkEnum === 1 || form.ImageMarkEnum === 2" <el-form-item v-if="form.ImageMarkEnum === 1 || form.ImageMarkEnum === 2"
:label="$t('trials:readingUnit:qsList:title:ImageMarkTypeEnum')" prop="ImageMarkTypeEnum">
<el-radio-group v-model="form.ImageMarkTypeEnum" @change="ImageMarkTypeEnumChange">
<el-radio v-for="item of $d.ImageMarkType" :key="item.id" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<!-- 测量工具 ImageTool -->
<el-form-item v-if="(form.ImageMarkEnum === 1 || form.ImageMarkEnum === 2) && form.ImageMarkTypeEnum === 0"
:label="$t('trials:readingUnit:qsList:title:ImageTool')" prop="ImageTool" :rules="[ :label="$t('trials:readingUnit:qsList:title:ImageTool')" prop="ImageTool" :rules="[
{ required: true, message: this.$t('common:ruleMessage:select') } { required: true, message: this.$t('common:ruleMessage:select') }
]"> ]">
@ -297,6 +304,17 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!-- 分割工具 ImageTool -->
<el-form-item v-if="(form.ImageMarkEnum === 1 || form.ImageMarkEnum === 2) && form.ImageMarkTypeEnum === 1"
:label="$t('trials:readingUnit:qsList:title:ImageTool')" prop="ImageTool" :rules="[
{ required: true, message: this.$t('common:ruleMessage:select') }
]">
<el-radio-group v-model="form.ImageTool" @change="imageSegmentToolChange">
<el-radio v-for="tool of readingSegmentTools" :key="tool.toolName" :label="tool.toolName">
{{ $t(tool.i18nKey) }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 测量值 ImageToolAttribute --> <!-- 测量值 ImageToolAttribute -->
<el-form-item v-if="form.ImageTool && imageToolAttributes.length > 0" <el-form-item v-if="form.ImageTool && imageToolAttributes.length > 0"
:label="$t('trials:readingUnit:qsList:title:ImageToolAttribute')" prop="ImageToolAttribute" :rules="[ :label="$t('trials:readingUnit:qsList:title:ImageToolAttribute')" prop="ImageToolAttribute" :rules="[
@ -563,6 +581,12 @@ export default {
return [] return []
} }
}, },
readingSegmentTools: {
type: Array,
default() {
return []
}
},
readingVersionEnum: { readingVersionEnum: {
type: Number, type: Number,
default: 0 default: 0
@ -617,6 +641,7 @@ export default {
ClassifyEditType: null, ClassifyEditType: null,
ClassifyShowType: null, ClassifyShowType: null,
ImageMarkEnum: 0, ImageMarkEnum: 0,
ImageMarkTypeEnum: 0,
ShowChartTypeEnum: 0, ShowChartTypeEnum: 0,
ImageTool: '', ImageTool: '',
ImageToolAttribute: '', ImageToolAttribute: '',
@ -898,9 +923,12 @@ export default {
} }
} }
} }
if (this.form.ImageTool) { if (this.form.ImageTool && this.form.ImageMarkTypeEnum === 0) {
this.imageToolChange(this.form.ImageTool) this.imageToolChange(this.form.ImageTool)
} }
if (this.form.ImageTool && this.form.ImageMarkTypeEnum === 1) {
this.imageSegmentToolChange(this.form.ImageTool)
}
} }
if (this.form.ClassifyTableQuestionId) { if (this.form.ClassifyTableQuestionId) {
this.classifyQuestionChange(this.form.ClassifyTableQuestionId) this.classifyQuestionChange(this.form.ClassifyTableQuestionId)
@ -1011,14 +1039,26 @@ export default {
this.form.ImageTool = '' this.form.ImageTool = ''
this.form.ImageToolAttribute = '' this.form.ImageToolAttribute = ''
this.imageToolAttributes = [] this.imageToolAttributes = []
this.form.ImageMarkTypeEnum = 0
} }
}, },
ImageMarkTypeEnumChange(val) {
this.form.ImageTool = ''
this.form.ImageToolAttribute = ''
this.imageToolAttributes = []
},
imageToolChange(v) { imageToolChange(v) {
let i = this.readingTools.findIndex(tool => tool.toolName === v) let i = this.readingTools.findIndex(tool => tool.toolName === v)
if (i > -1) { if (i > -1) {
this.imageToolAttributes = this.readingTools[i].props this.imageToolAttributes = this.readingTools[i].props
} }
}, },
imageSegmentToolChange(v) {
let i = this.readingSegmentTools.findIndex(tool => tool.toolName === v)
if (i > -1) {
this.imageToolAttributes = this.readingSegmentTools[i].props
}
},
async parentQuestionChange(val, form) { async parentQuestionChange(val, form) {
if (val) { if (val) {
var index = this.parentOptions.findIndex(item => { var index = this.parentOptions.findIndex(item => {
@ -1129,6 +1169,7 @@ export default {
form.ClassifyType = null form.ClassifyType = null
form.ClassifyShowType = null form.ClassifyShowType = null
form.ImageMarkEnum = 0 form.ImageMarkEnum = 0
form.ImageMarkTypeEnum = 0
form.ShowChartTypeEnum = 0 form.ShowChartTypeEnum = 0
form.ImageTool = '' form.ImageTool = ''
form.ImageToolAttribute = '' form.ImageToolAttribute = ''

View File

@ -1,73 +1,37 @@
<template> <template>
<div v-loading="loading"> <div v-loading="loading">
<div <div class="search-form" style="text-align: right;">
class="search-form" <el-button v-if="!isConfirm && !isFromSystem" size="mini" type="primary" @click="handleAdd">
style="text-align: right;" {{ $t('common:button:new') }}
>
<el-button
v-if="!isConfirm && !isFromSystem"
size="mini"
type="primary"
@click="handleAdd"
>
{{$t('common:button:new')}}
</el-button> </el-button>
</div> </div>
<el-table <el-table v-adaptive="{ bottomOffset: 60 }" :data="list" size="small" height="100">
v-adaptive="{bottomOffset:60}" <el-table-column prop="ShowOrder" :label="$t('trials:qcCfg:table:order')" min-width="70" />
:data="list"
size="small"
height="100"
>
<el-table-column
prop="ShowOrder"
:label="$t('trials:qcCfg:table:order')"
min-width="70"
/>
<!-- 名称 --> <!-- 名称 -->
<el-table-column <el-table-column prop="QuestionName" v-if="$i18n.locale === 'zh'"
prop="QuestionName" :label="$t('trials:readingUnit:qsList:title:qsName')" show-overflow-tooltip />
v-if="$i18n.locale === 'zh'"
:label="$t('trials:readingUnit:qsList:title:qsName')"
show-overflow-tooltip
/>
<!-- 名称(EN) --> <!-- 名称(EN) -->
<el-table-column <el-table-column prop="QuestionEnName" v-if="$i18n.locale === 'en'"
prop="QuestionEnName" :label="$t('trials:readingUnit:qsList:title:qsNameEn')" show-overflow-tooltip />
v-if="$i18n.locale === 'en'"
:label="$t('trials:readingUnit:qsList:title:qsNameEn')"
show-overflow-tooltip
/>
<!-- 题型 --> <!-- 题型 -->
<el-table-column <el-table-column prop="Type" :label="$t('trials:readingUnit:qsList:title:type')" show-overflow-tooltip>
prop="Type"
:label="$t('trials:readingUnit:qsList:title:type')"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('Criterion_Question_Type',scope.row.Type) }} {{ $fd('Criterion_Question_Type', scope.row.Type) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 是否显示 --> <!-- 是否显示 -->
<el-table-column <el-table-column prop="ShowQuestion" :label="$t('trials:readingUnit:qsList:title:isShow')" show-overflow-tooltip>
prop="ShowQuestion"
:label="$t('trials:readingUnit:qsList:title:isShow')"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('ShowQuestion',scope.row.ShowQuestion) }} {{ $fd('ShowQuestion', scope.row.ShowQuestion) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 是否必填 --> <!-- 是否必填 -->
<el-table-column <el-table-column prop="IsRequired" :label="$t('trials:readingUnit:qsList:title:isRequired')"
prop="IsRequired" show-overflow-tooltip>
:label="$t('trials:readingUnit:qsList:title:isRequired')"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('QuestionRequired',scope.row.IsRequired) }} {{ $fd('QuestionRequired', scope.row.IsRequired) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 是否裁判问题 --> <!-- 是否裁判问题 -->
@ -104,41 +68,26 @@
</template> </template>
</el-table-column> --> </el-table-column> -->
<!-- 导出目标表格 --> <!-- 导出目标表格 -->
<el-table-column <el-table-column prop="ExportResult" :label="$t('trials:readingUnit:qsList:title:ExportResult')" width="160"
prop="ExportResult" show-overflow-tooltip>
:label="$t('trials:readingUnit:qsList:title:ExportResult')"
width="160"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ getStringResult(scope.row.ExportResult, 'ExportResult') }} {{ getStringResult(scope.row.ExportResult, 'ExportResult') }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 限制编辑 --> <!-- 限制编辑 -->
<el-table-column <el-table-column prop="LimitEdit" :label="$t('trials:readingUnit:qsList:title:limitEdit')" show-overflow-tooltip>
prop="LimitEdit"
:label="$t('trials:readingUnit:qsList:title:limitEdit')"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('LimitEdit', scope.row.LimitEdit) }} {{ $fd('LimitEdit', scope.row.LimitEdit) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column prop="IsCopy" :label="$t('trials:readingUnit:qsList:title:PrecopyValue')" show-overflow-tooltip>
prop="IsCopy"
:label="$t('trials:readingUnit:qsList:title:PrecopyValue')"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('YesOrNo', scope.row.IsCopy) }} {{ $fd('YesOrNo', scope.row.IsCopy) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 最大行数 --> <!-- 最大行数 -->
<el-table-column <el-table-column prop="MaxRowCount" :label="$t('trials:readingUnit:qsList:title:MaxRowCount')"
prop="MaxRowCount" show-overflow-tooltip>
:label="$t('trials:readingUnit:qsList:title:MaxRowCount')"
show-overflow-tooltip
>
</el-table-column> </el-table-column>
<!-- 注释 --> <!-- 注释 -->
<!-- <el-table-column <!-- <el-table-column
@ -148,35 +97,15 @@
show-overflow-tooltip show-overflow-tooltip
> >
</el-table-column> --> </el-table-column> -->
<el-table-column <el-table-column prop="" :label="$t('common:action:action')" width="200" show-overflow-tooltip>
prop=""
:label="$t('common:action:action')"
width="200"
show-overflow-tooltip
>
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button v-if="!isConfirm && !isFromSystem" type="primary" size="mini" @click="handleEdit(scope.row)">
v-if="!isConfirm && !isFromSystem"
type="primary"
size="mini"
@click="handleEdit(scope.row)"
>
{{ $t('common:button:edit') }} {{ $t('common:button:edit') }}
</el-button> </el-button>
<el-button <el-button v-else type="primary" size="mini" @click="handleLook(scope.row)">
v-else
type="primary"
size="mini"
@click="handleLook(scope.row)"
>
{{ $t('trials:readingPeriod:button:view') }} {{ $t('trials:readingPeriod:button:view') }}
</el-button> </el-button>
<el-button <el-button v-if="!isConfirm && !isFromSystem" type="danger" size="mini" @click="handleDelete(scope.row)">
v-if="!isConfirm && !isFromSystem"
type="danger"
size="mini"
@click="handleDelete(scope.row)"
>
{{ $t('common:button:delete') }} {{ $t('common:button:delete') }}
</el-button> </el-button>
@ -184,29 +113,12 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-dialog <el-dialog v-if="addOrEdit.visible" :visible.sync="addOrEdit.visible" :close-on-click-modal="false"
v-if="addOrEdit.visible" :title="addOrEdit.title" width="600px" append-to-body custom-class="base-dialog-wrapper">
:visible.sync="addOrEdit.visible" <TableQsForm ref="addOrEdit" :data="rowData" :list="list" :type="type" :is-from-system="isFromSystem"
:close-on-click-modal="false" :digit-places="digitPlaces" :reading-question-id="readingQuestionId" :criterion-id="criterionId"
:title="addOrEdit.title" :readingTools="readingTools" :readingSegmentTools="readingSegmentTools" :readingVersionEnum="readingVersionEnum"
width="600px" @close="addOrEdit.visible = false" @getList="getList" />
append-to-body
custom-class="base-dialog-wrapper"
>
<TableQsForm
ref="addOrEdit"
:data="rowData"
:list="list"
:type="type"
:is-from-system="isFromSystem"
:digit-places="digitPlaces"
:reading-question-id="readingQuestionId"
:criterion-id="criterionId"
:readingTools="readingTools"
:readingVersionEnum="readingVersionEnum"
@close="addOrEdit.visible = false"
@getList="getList"
/>
</el-dialog> </el-dialog>
</div> </div>
@ -250,6 +162,12 @@ export default {
return [] return []
} }
}, },
readingSegmentTools: {
type: Array,
default() {
return []
}
},
readingVersionEnum: { readingVersionEnum: {
type: Number, type: Number,
default: 0 default: 0
@ -296,9 +214,9 @@ export default {
this.type = 'look' this.type = 'look'
let title = '' let title = ''
if (this.$i18n.locale === 'zh' && (row.QuestionName || row.GroupName)) { if (this.$i18n.locale === 'zh' && (row.QuestionName || row.GroupName)) {
title =`${row.QuestionName ? row.QuestionName : row.GroupName}` title = `${row.QuestionName ? row.QuestionName : row.GroupName}`
} else if (this.$i18n.locale === 'en' && (row.QuestionEnName || row.GroupEnName)) { } else if (this.$i18n.locale === 'en' && (row.QuestionEnName || row.GroupEnName)) {
title =`: ${row.QuestionEnName ? row.QuestionEnName : row.GroupEnName}` title = `: ${row.QuestionEnName ? row.QuestionEnName : row.GroupEnName}`
} }
this.addOrEdit.title = `${this.$t('trials:readingPeriod:button:view')}${title}` this.addOrEdit.title = `${this.$t('trials:readingPeriod:button:view')}${title}`
this.addOrEdit.visible = true this.addOrEdit.visible = true
@ -337,4 +255,3 @@ export default {
} }
} }
</script> </script>

View File

@ -29,8 +29,8 @@
<el-collapse-item :title="$t('trials:readingUnit:readingCriterion')" name="2"> <el-collapse-item :title="$t('trials:readingUnit:readingCriterion')" name="2">
<ReadingCriterions :ref="`readingCriterions${item.TrialReadingCriterionId}`" <ReadingCriterions :ref="`readingCriterions${item.TrialReadingCriterionId}`"
:trial-reading-criterion-id="TrialReadingCriterionId" :digit-places="digitPlaces" :trial-reading-criterion-id="TrialReadingCriterionId" :digit-places="digitPlaces"
:readingTools="readingTools" :is-additional-assessment="isAdditionalAssessment" :readingTools="readingTools" :readingSegmentTools="readingSegmentTools"
@reloadArbitrationRules="reloadArbitrationRules" /> :is-additional-assessment="isAdditionalAssessment" @reloadArbitrationRules="reloadArbitrationRules" />
</el-collapse-item> </el-collapse-item>
<!-- 全局阅片 --> <!-- 全局阅片 -->
<el-collapse-item v-if="isGlobalReading && CriterionType !== 10" <el-collapse-item v-if="isGlobalReading && CriterionType !== 10"
@ -107,7 +107,7 @@ import GlobalReading from "./components/GlobalReading";
import OncologyForm from "./components/OncologyForm"; import OncologyForm from "./components/OncologyForm";
import SignForm from "@/views/trials/components/newSignForm"; import SignForm from "@/views/trials/components/newSignForm";
import const_ from "@/const/sign-code"; import const_ from "@/const/sign-code";
import { getCustomizeStandardsTools, getCustomizeStandardsNoneDicomTools } from '@/views/trials/trials-panel/reading/dicoms3D/components/toolConfig' import { getCustomizeStandardsTools, getCustomizeStandardsNoneDicomTools, getCustomizeStandardsSegmentDicomTools } from '@/views/trials/trials-panel/reading/dicoms3D/components/toolConfig'
export default { export default {
name: "ReadingUnit", name: "ReadingUnit",
components: { components: {
@ -141,7 +141,8 @@ export default {
isGlobalReading: false, isGlobalReading: false,
digitPlaces: 0, digitPlaces: 0,
isAdditionalAssessment: false, isAdditionalAssessment: false,
readingTools: [] readingTools: [],
readingSegmentTools: []
}; };
}, },
watch: { watch: {
@ -230,13 +231,16 @@ export default {
this.digitPlaces = digitPlaces; this.digitPlaces = digitPlaces;
}, },
setReadingTools(data) { setReadingTools(data) {
let { readingTools, isNoneDicom } = data let { readingTools, readingSegmentTools, ReadingTool } = data
if (isNoneDicom) { if (ReadingTool === 1) {
this.readingTools = getCustomizeStandardsNoneDicomTools(readingTools) this.readingTools = getCustomizeStandardsNoneDicomTools(readingTools)
} else { } else {
this.readingTools = getCustomizeStandardsTools(readingTools) this.readingTools = getCustomizeStandardsTools(readingTools)
} }
if (ReadingTool === 3) {
this.readingSegmentTools = getCustomizeStandardsSegmentDicomTools(readingSegmentTools)
}
console.log(this.readingSegmentTools, 'this.readingSegmentTools')
}, },
setIsClinicalReading(isClinicalReading) { setIsClinicalReading(isClinicalReading) {
this.isClinicalReading = isClinicalReading; this.isClinicalReading = isClinicalReading;

View File

@ -71,7 +71,6 @@ export default {
'#505372', '#505372',
'#ff994d', '#ff994d',
'#fb628b', '#fb628b',
], ],
trialCriterionList: [], trialCriterionList: [],
loading_left: false, loading_left: false,