Merge branch 'main' into uat_us

uat_us
wangxiaoshuang 2026-04-17 10:01:16 +08:00
commit a3e79db023
70 changed files with 6646 additions and 2145 deletions

1442
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,11 +15,12 @@
"i18n:en": "node i18nGenerate.js lang=en keyCol=5 valCol=7" "i18n:en": "node i18nGenerate.js lang=en keyCol=5 valCol=7"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.726.1", "@aws-sdk/client-s3": "3.726.1",
"@cornerstonejs/adapters": "4.19.2", "@cornerstonejs/adapters": "^4.19.2",
"@cornerstonejs/calculate-suv": "^1.1.0", "@cornerstonejs/calculate-suv": "^1.1.0",
"@cornerstonejs/core": "^4.19.2", "@cornerstonejs/core": "^4.19.2",
"@cornerstonejs/dicom-image-loader": "^4.19.2", "@cornerstonejs/dicom-image-loader": "^4.19.2",
"@cornerstonejs/polymorphic-segmentation": "^4.19.2",
"@cornerstonejs/tools": "^4.19.2", "@cornerstonejs/tools": "^4.19.2",
"@fingerprintjs/fingerprintjs": "^4.6.2", "@fingerprintjs/fingerprintjs": "^4.6.2",
"@icr/polyseg-wasm": "^0.4.0", "@icr/polyseg-wasm": "^0.4.0",
@ -38,7 +39,7 @@
"dcmjs": "^0.29.8", "dcmjs": "^0.29.8",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"dicomedit": "^0.1.0", "dicomedit": "^0.1.0",
"echarts": "^4.8.0", "echarts": "^6.0.0",
"element-ui": "^2.15.14", "element-ui": "^2.15.14",
"exceljs": "^4.4.0", "exceljs": "^4.4.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",

41
src/api/file.js Normal file
View File

@ -0,0 +1,41 @@
import request from '@/utils/request'
export function addOrUpdateFileUploadRecord(params) {
return request({
url: `/FileUploadRecord/addOrUpdateFileUploadRecord`,
method: 'post',
data: params
})
}
export function batchAddSyncFileTask(params) {
return request({
url: `/FileUploadRecord/batchAddSyncFileTask`,
method: 'post',
data: params
})
}
export function getSubjectUploadRecordList(params) {
return request({
url: `/FileUploadRecord/getSubjectUploadRecordList`,
method: 'post',
data: params
})
}
export function getFileUploadRecordList(params) {
return request({
url: `/FileUploadRecord/getFileUploadRecordList`,
method: 'post',
data: params
})
}
export function getUploadFileSyncRecordList(params) {
return request({
url: `/FileUploadRecord/getUploadFileSyncRecordList`,
method: 'post',
data: params
})
}

View File

@ -8,20 +8,49 @@
<script> <script>
import { getReportsChartData } from "@/api/reading" import { getReportsChartData } from "@/api/reading"
let echarts = require('echarts/lib/echarts'); import * as echarts from 'echarts/core';
import { LineChart } from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
DataZoomComponent,
LegendComponent,
DatasetComponent,
// (filter, sort)
TransformComponent
} from 'echarts/components';
//
import { LabelLayout, UniversalTransition } from 'echarts/features';
// Canvas CanvasRenderer SVGRenderer
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
DataZoomComponent,
LegendComponent,
LineChart,
LabelLayout,
UniversalTransition,
CanvasRenderer
]);
// let echarts = require('echarts/lib/echarts');
// //
// require('echarts/lib/chart/bar'); // require('echarts/lib/chart/bar');
require('echarts/lib/chart/line'); // require('echarts/lib/chart/line');
// require('echarts/lib/chart/pie'); // require('echarts/lib/chart/pie');
// require('echarts/lib/chart/scatter'); // require('echarts/lib/chart/scatter');
// //
require('echarts/lib/component/tooltip'); // require('echarts/lib/component/tooltip');
require('echarts/lib/component/title'); // require('echarts/lib/component/title');
require('echarts/lib/component/legend'); // require('echarts/lib/component/legend');
require('echarts/lib/component/grid'); // require('echarts/lib/component/grid');
require('echarts/lib/component/dataZoom'); // require('echarts/lib/component/dataZoom');
export default { export default {
name: "readingChart", name: "readingChart",
props: { props: {
@ -151,7 +180,13 @@ export default {
text: obj.title, text: obj.title,
textStyle: { textStyle: {
color: "#fff" color: "#fff"
} },
left: 0,
top: 0
},
grid: {
left: 50,
bottom: 30
}, },
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
@ -193,6 +228,7 @@ export default {
} }
}, },
axisLine: { axisLine: {
show: true,
lineStyle: { lineStyle: {
color: '#fff', color: '#fff',
} }

View File

@ -1174,6 +1174,7 @@ export default {
}, },
} }
let arr = [] let arr = []
let uploadBatchId = scope.$guid()
for (let i = 0; i < seriesList.length; i++) { for (let i = 0; i < seriesList.length; i++) {
let v = seriesList[i] let v = seriesList[i]
let instanceList = [] let instanceList = []
@ -1266,6 +1267,16 @@ export default {
) { ) {
dicomInfo.uploadFileSize = dicomInfo.fileSize dicomInfo.uploadFileSize = dicomInfo.fileSize
} }
},
{
fileName: o.file.name,
fileSize: o.file.size,
fileType: 'application/dicom',
uploadBatchId: uploadBatchId,
batchDataType: 5,
trialId: params.trialId,
subjectId: params.subjectId,
subjectVisitId: params.subjectVisitId
} }
) )
if (!res || !res.url) { if (!res || !res.url) {
@ -1289,7 +1300,17 @@ export default {
let OSSclient = scope.OSSclient let OSSclient = scope.OSSclient
let seriesRes = await OSSclient.put( let seriesRes = await OSSclient.put(
thumbnailPath, thumbnailPath,
blob blob,
{
fileName: `${v.seriesUid}.jpg`,
fileSize: blob.size,
fileType: 'image/jpeg',
uploadBatchId: uploadBatchId,
batchDataType: 6,
trialId: params.trialId,
subjectId: params.subjectId,
subjectVisitId: params.subjectVisitId
}
) )
if (seriesRes && seriesRes.url) { if (seriesRes && seriesRes.url) {
ImageResizePath = scope.$getObjectName( ImageResizePath = scope.$getObjectName(
@ -1430,7 +1451,20 @@ export default {
} }
let OSSclient = scope.OSSclient let OSSclient = scope.OSSclient
try { try {
let seriesRes = await OSSclient.put(thumbnailPath, blob) let seriesRes = await OSSclient.put(
thumbnailPath,
blob,
{
fileName: `${v.seriesUid}.jpg`,
fileSize: blob.size,
fileType: 'image/jpeg',
uploadBatchId: uploadBatchId,
batchDataType: 6,
trialId: params.trialId,
subjectId: params.subjectId,
subjectVisitId: params.subjectVisitId
}
)
if (seriesRes && seriesRes.url) { if (seriesRes && seriesRes.url) {
o.ImageResizePath = scope.$getObjectName(seriesRes.url) o.ImageResizePath = scope.$getObjectName(seriesRes.url)
} }
@ -1448,6 +1482,7 @@ export default {
if (scope.IsImageSegment) { if (scope.IsImageSegment) {
params.IsImageSegmentLabel = true params.IsImageSegmentLabel = true
} }
params.UploadBatchId = uploadBatchId
addOrUpdateArchiveTaskStudy(params) addOrUpdateArchiveTaskStudy(params)
.then((res) => { .then((res) => {
if (dicomInfo.failedFileCount === dicomInfo.fileCount) { if (dicomInfo.failedFileCount === dicomInfo.fileCount) {

View File

@ -548,8 +548,9 @@ export default {
}) })
if (res.IsSuccess) { if (res.IsSuccess) {
this.studyMonitorId = res.Result this.studyMonitorId = res.Result
let uploadBatchId = this.$guid()
for (let i = 0; i < num; i++) { for (let i = 0; i < num; i++) {
funArr.push(this.handleUploadTask(this.selectArr, i)) funArr.push(this.handleUploadTask(this.selectArr, i, uploadBatchId))
} }
if (funArr.length > 0) { if (funArr.length > 0) {
let res = await Promise.all(funArr) let res = await Promise.all(funArr)
@ -560,7 +561,7 @@ export default {
} }
}, },
// //
async handleUploadTask(arr, index) { async handleUploadTask(arr, index, uploadBatchId) {
if (!this.uploadVisible) return if (!this.uploadVisible) return
let file = this.fileList.filter((item) => item.id === arr[index].id)[0] let file = this.fileList.filter((item) => item.id === arr[index].id)[0]
file.status = 1 file.status = 1
@ -576,7 +577,7 @@ export default {
} }
file.curPath = path file.curPath = path
const fileData = await this.fileToBlob(file.file) const fileData = await this.fileToBlob(file.file)
let res = await this.fileToOss(path, fileData, file) let res = await this.fileToOss(path, fileData, file, uploadBatchId)
if (res) { if (res) {
file.status = 2 file.status = 2
this.successFileList.push({ this.successFileList.push({
@ -610,13 +611,13 @@ export default {
} }
let ind = arr.findIndex((item) => item.status === 0) let ind = arr.findIndex((item) => item.status === 0)
if (ind >= 0) { if (ind >= 0) {
return this.handleUploadTask(arr, ind) return this.handleUploadTask(arr, ind, uploadBatchId)
} else { } else {
return false return false
} }
}, },
// fileoss // fileoss
async fileToOss(path, file, item) { async fileToOss(path, file, item, uploadBatchId) {
try { try {
let res = await this.OSSclient.multipartUpload( let res = await this.OSSclient.multipartUpload(
{ {
@ -629,6 +630,17 @@ export default {
if (item.uploadFileSize > file.fileSize) { if (item.uploadFileSize > file.fileSize) {
item.uploadFileSize = file.fileSize > 0 ? file.fileSize : 1 item.uploadFileSize = file.fileSize > 0 ? file.fileSize : 1
} }
},
{
fileName: item.name,
fileSize: item.size,
fileType: item.fileType,
uploadBatchId: uploadBatchId,
batchDataType: 7,
trialId: this.$route.query.trialId,
subjectId: this.currentRow.SubjectId,
subjectVisitId: this.currentRow.SourceSubjectVisitId,
studyCode: this.SubjectCode
} }
) )
if (res) { if (res) {

View File

@ -0,0 +1,16 @@
import resize from './resize'
const install = function (Vue) {
// 绑定v-adaptive指令
Vue.directive('resize', resize)
}
// if (window.Vue) {
// window['adaptive'] = adaptive
// // eslint-disable-next-line no-undef
// Vue.use(install)
// }
resize.install = install
export default resize

View File

@ -0,0 +1,19 @@
const map = new WeakMap()
const ob = new ResizeObserver(entries => {
for (const entry of entries) {
const handler = map.get(entry.target)
if (handler) {
const { inlineSize, blockSize } = entry.contentBoxSize[0]
handler({ width: inlineSize, height: blockSize })
}
}
})
export default {
bind(el, binding) {
map.set(el, binding.value)
ob.observe(el)
},
unbind(el) {
ob.unobserve(el)
}
}

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1775115523115" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5347" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M458.105263 970.105263h-215.578947V264.084211h215.578947V970.105263z m-161.68421-53.894737h107.789473V317.978947h-107.789473V916.210526z" fill="#ffffff" p-id="5348"></path><path d="M296.421053 970.105263h-215.578948V479.663158h215.578948V970.105263z m-161.684211-53.894737h107.789474V533.557895h-107.789474V916.210526zM943.157895 970.105263h-215.578948V479.663158h215.578948V970.105263z m-161.684211-53.894737h107.789474V533.557895h-107.789474V916.210526zM619.789474 970.105263h-215.578948V53.894737h215.578948v916.210526z m-161.684211-53.894737h107.789474V107.789474h-107.789474v808.421052z" fill="#ffffff" p-id="5349"></path><path d="M781.473684 970.105263h-215.578947V264.084211h215.578947V970.105263z m-161.68421-53.894737h107.789473V317.978947h-107.789473V916.210526z" fill="#ffffff" p-id="5350"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -70,6 +70,9 @@ import FB from '@/components/feedBack/index'
Vue.use(FB) Vue.use(FB)
import FBT from '@/components/feedBackTable/index' import FBT from '@/components/feedBackTable/index'
Vue.use(FBT) Vue.use(FBT)
import resize from '@/directive/resize/index'
// 表格自适应指令
Vue.use(resize)
import adaptive from '@/directive/adaptive/index' import adaptive from '@/directive/adaptive/index'
// 表格自适应指令 // 表格自适应指令
Vue.use(adaptive) Vue.use(adaptive)

View File

@ -1,6 +1,6 @@
import Vue from 'vue' import Vue from 'vue'
import { anonymization } from './anonymization' import { anonymization } from './anonymization'
export const dcmUpload = async function (data, config, progressFn) { export const dcmUpload = async function (data, config, progressFn, fileInfo) {
return new Promise(async resolve => { return new Promise(async resolve => {
try { try {
// let blob = await encoder(file, config) // let blob = await encoder(file, config)
@ -8,7 +8,8 @@ export const dcmUpload = async function (data, config, progressFn) {
if (config) { if (config) {
blob = await anonymization(data.file, config) blob = await anonymization(data.file, config)
} }
let res = await Vue.prototype.OSSclient.multipartUpload(Object.assign(data, { file: blob.blob }), progressFn)
let res = await Vue.prototype.OSSclient.multipartUpload(Object.assign(data, { file: blob.blob }), progressFn, fileInfo)
resolve({ resolve({
...res, ...res,
image: blob.pixelDataElement image: blob.pixelDataElement

View File

@ -5,6 +5,7 @@ const stream = require('stream')
import Vue from 'vue' import Vue from 'vue'
import { customerHttp, OSSclose } from "@/utils/multipartUpload/oss" import { customerHttp, OSSclose } from "@/utils/multipartUpload/oss"
import { exist, AWSclose } from "@/utils/multipartUpload/aws" import { exist, AWSclose } from "@/utils/multipartUpload/aws"
import { addOrUpdateFileUploadRecord } from '@/api/file'
const { GetObjectStoreToken } = require('../api/user.js') const { GetObjectStoreToken } = require('../api/user.js')
const { const {
S3Client, S3Client,
@ -22,7 +23,6 @@ async function ossGenerateSTS() {
res = await GetObjectStoreToken() res = await GetObjectStoreToken()
localStorage.setItem('stsToken', JSON.stringify(res)) localStorage.setItem('stsToken', JSON.stringify(res))
} }
// res.Result.ObjectStoreUse = 'AWS'; // res.Result.ObjectStoreUse = 'AWS';
Vue.prototype.OSSclientConfig = { ...res.Result[res.Result.ObjectStoreUse] } Vue.prototype.OSSclientConfig = { ...res.Result[res.Result.ObjectStoreUse] }
Vue.prototype.OSSclientConfig.ObjectStoreUse = res.Result.ObjectStoreUse; Vue.prototype.OSSclientConfig.ObjectStoreUse = res.Result.ObjectStoreUse;
@ -34,7 +34,8 @@ async function ossGenerateSTS() {
Vue.prototype.OSSclientConfig.timeout = 10 * 60 * 1000 Vue.prototype.OSSclientConfig.timeout = 10 * 60 * 1000
let OSSclient = new OSS(Vue.prototype.OSSclientConfig) let OSSclient = new OSS(Vue.prototype.OSSclientConfig)
Vue.prototype.OSSclient = { Vue.prototype.OSSclient = {
put: async function (objectName, object) { put: async function (objectName, object, fileInfo = {}) {
OSSclient = await RefreshClient(OSSclient) OSSclient = await RefreshClient(OSSclient)
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
@ -52,6 +53,15 @@ async function ossGenerateSTS() {
} }
let res = await OSSclient.put(objectName, object) let res = await OSSclient.put(objectName, object)
if (res && res.url) { if (res && res.url) {
const urlParams = new URLSearchParams(window.location.search)
const trialId = urlParams.get('trialId')
if (Object.keys(fileInfo).length !== 0) {
let params = Object.assign({path: objectName}, fileInfo)
addOrUpdateFileUploadRecord(params)
} else if (trialId) {
let params = { trialId }
addOrUpdateFileUploadRecord(params)
}
resolve({ resolve({
name: objectName, name: objectName,
url: res.url url: res.url
@ -65,7 +75,7 @@ async function ossGenerateSTS() {
} }
}) })
}, },
multipartUpload: async (data, progress) => { multipartUpload: async (data, progress, fileInfo = {}) => {
OSSclient = await RefreshClient(OSSclient) OSSclient = await RefreshClient(OSSclient)
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
@ -95,6 +105,16 @@ async function ossGenerateSTS() {
} }
let res = await customerHttp(OSSclient, data, progress); let res = await customerHttp(OSSclient, data, progress);
if (res) { if (res) {
const urlParams = new URLSearchParams(window.location.search)
const trialId = urlParams.get('trialId')
if (Object.keys(fileInfo).length !== 0) {
let params = Object.assign({path: data.path}, fileInfo)
addOrUpdateFileUploadRecord(params)
} else if (trialId) {
let params = { trialId }
addOrUpdateFileUploadRecord(params)
}
resolve({ resolve({
name: data.path, name: data.path,
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(res.name) url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(res.name)
@ -169,17 +189,17 @@ async function ossGenerateSTS() {
} }
}); });
Vue.prototype.OSSclient = { Vue.prototype.OSSclient = {
put: async function (objectName, object) { put: async function (objectName, object, fileInfo = {}) {
let data = { let data = {
file: object, file: object,
path: objectName path: objectName
} }
aws = await RefreshClient(aws); aws = await RefreshClient(aws);
return uploadAWS(aws, data, () => { }); return uploadAWS(aws, data, () => { }, fileInfo);
}, },
multipartUpload: async (data, progress) => { multipartUpload: async (data, progress, fileInfo = {}) => {
aws = await RefreshClient(aws); aws = await RefreshClient(aws);
return uploadAWS(aws, data, progress); return uploadAWS(aws, data, progress, fileInfo);
}, },
close: () => { close: () => {
AWSclose(); AWSclose();
@ -189,7 +209,7 @@ async function ossGenerateSTS() {
return return
} }
// AWS上传函数 // AWS上传函数
function uploadAWS(aws, data, progress) { function uploadAWS(aws, data, progress, fileInfo) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
const { file, path } = data; const { file, path } = data;
@ -211,6 +231,16 @@ function uploadAWS(aws, data, progress) {
data.path = data.path.replace(`/${bucketName}/`, ''); data.path = data.path.replace(`/${bucketName}/`, '');
await exist(aws, bucketName, data, progress, (path, status) => { await exist(aws, bucketName, data, progress, (path, status) => {
if (status === 'success') { if (status === 'success') {
const urlParams = new URLSearchParams(window.location.search)
const trialId = urlParams.get('trialId')
if (Object.keys(fileInfo).length !== 0) {
let params = Object.assign({path: decodeUtf8(curPath)}, fileInfo)
addOrUpdateFileUploadRecord(params)
} else if (trialId) {
let params = { trialId }
addOrUpdateFileUploadRecord(params)
}
resolve({ resolve({
name: decodeUtf8(curPath), name: decodeUtf8(curPath),
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(curPath) url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(curPath)

View File

@ -2,8 +2,8 @@
<div ref="mapbox" class="map-wrapper" /> <div ref="mapbox" class="map-wrapper" />
</template> </template>
<script> <script>
import echarts from 'echarts' import * as echarts from 'echarts'
import 'modules/echarts/map/js/world.js' // import 'modules/echarts/map/js/world.js'
import { fontSize } from 'utils/fontsize' import { fontSize } from 'utils/fontsize'
export default { export default {
props: { props: {
@ -14,7 +14,7 @@ export default {
watch: { watch: {
area() { area() {
const that = this const that = this
this.$nextTick(function() { this.$nextTick(function () {
that.myChart.resize() that.myChart.resize()
}) })
} }
@ -56,7 +56,7 @@ export default {
} }
] ]
] ]
var convertData = function(data) { var convertData = function (data) {
var res = [] var res = []
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
var dataItem = data[i] var dataItem = data[i]
@ -77,7 +77,7 @@ export default {
return res return res
} }
var series = [] var series = []
;[['Shanghai', BJData]].forEach(function(item, i) { ;[['Shanghai', BJData]].forEach(function (item, i) {
series.push( series.push(
{ {
type: 'lines', type: 'lines',
@ -125,11 +125,11 @@ export default {
} }
}, },
symbol: 'circle', symbol: 'circle',
symbolSize: function(val) { symbolSize: function (val) {
return fontSize(0.08) // return fontSize(0.08) //
}, },
data: item[1].map(function(dataItem) { data: item[1].map(function (dataItem) {
return { return {
name: dataItem[0].name, name: dataItem[0].name,
value: geoCoordMap[dataItem[0].name] value: geoCoordMap[dataItem[0].name]
@ -161,7 +161,7 @@ export default {
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
fontSize: fontSize(0.16), fontSize: fontSize(0.16),
formatter: function(params) { formatter: function (params) {
if (typeof params.value === 'undefined') { if (typeof params.value === 'undefined') {
return '' return ''
} else { } else {

View File

@ -2,7 +2,7 @@
<div ref="trials_stats" style="width:100%;height:100%;" /> <div ref="trials_stats" style="width:100%;height:100%;" />
</template> </template>
<script> <script>
import echarts from 'echarts' import * as echarts from 'echarts'
import { getTrialCountRank } from '@/api/dashboard' import { getTrialCountRank } from '@/api/dashboard'
import { fontSize } from 'utils/fontsize' import { fontSize } from 'utils/fontsize'
const Count = 5 const Count = 5

View File

@ -2,7 +2,7 @@
<div ref="enroll_stats" style="width:100%;height:100%;" /> <div ref="enroll_stats" style="width:100%;height:100%;" />
</template> </template>
<script> <script>
import echarts from 'echarts' import * as echarts from 'echarts'
import { getEnrollDataByQuarter } from '@/api/dashboard' import { getEnrollDataByQuarter } from '@/api/dashboard'
import { fontSize } from 'utils/fontsize' import { fontSize } from 'utils/fontsize'
const Count = 6 const Count = 6

View File

@ -2,7 +2,7 @@
<div ref="reviewers_stats" style="width:100%;height:100%;padding:5px;" /> <div ref="reviewers_stats" style="width:100%;height:100%;padding:5px;" />
</template> </template>
<script> <script>
import echarts from 'echarts' import * as echarts from 'echarts'
import { getReviewersByRank } from '@/api/dashboard' import { getReviewersByRank } from '@/api/dashboard'
import { fontSize } from 'utils/fontsize' import { fontSize } from 'utils/fontsize'
export default { export default {

View File

@ -2,7 +2,7 @@
<div ref="monthly_reading_stats" style="width:100%;height:100%;" /> <div ref="monthly_reading_stats" style="width:100%;height:100%;" />
</template> </template>
<script> <script>
import echarts from 'echarts' import * as echarts from 'echarts'
import { getReadingDataByMonth } from '@/api/dashboard' import { getReadingDataByMonth } from '@/api/dashboard'
import { fontSize } from 'utils/fontsize' import { fontSize } from 'utils/fontsize'
const Count = 6 const Count = 6

View File

@ -2,7 +2,7 @@
<div ref="reading_rank" class="reading-rank" /> <div ref="reading_rank" class="reading-rank" />
</template> </template>
<script> <script>
import echarts from 'echarts' import * as echarts from 'echarts'
import { getReadingDataRank } from '@/api/dashboard' import { getReadingDataRank } from '@/api/dashboard'
import { fontSize } from 'utils/fontsize' import { fontSize } from 'utils/fontsize'
const Count = 5 const Count = 5

View File

@ -2,7 +2,7 @@
<div ref="reading_stats" style="width:100%;height:100%;padding-top:5px;" /> <div ref="reading_stats" style="width:100%;height:100%;padding-top:5px;" />
</template> </template>
<script> <script>
import echarts from 'echarts' import * as echarts from 'echarts'
import { getReadingDataByType } from '@/api/dashboard' import { getReadingDataByType } from '@/api/dashboard'
import { fontSize } from 'utils/fontsize' import { fontSize } from 'utils/fontsize'
export default { export default {

View File

@ -1,11 +1,7 @@
<template> <template>
<div class="adReview_wrapper"> <div class="adReview_wrapper">
<el-card <el-card v-if="isReadingShowSubjectInfo" shadow="never" :body-style="{ padding: '10px' }"
v-if="isReadingShowSubjectInfo" style="margin-bottom: 10px">
shadow="never"
:body-style="{ padding: '10px' }"
style="margin-bottom: 10px"
>
<h4> <h4>
<!-- 受试者 --> <!-- 受试者 -->
{{ $t("trials:adReview:title:subject") }} {{ $t("trials:adReview:title:subject") }}
@ -17,14 +13,11 @@
<!-- <div slot="header" class="clearfix"> <!-- <div slot="header" class="clearfix">
<span style="font-weight: bold;">评估结果</span> <span style="font-weight: bold;">评估结果</span>
</div> --> </div> -->
<div <div slot="header" style="
slot="header"
style="
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
" ">
>
<!-- 评估结果 --> <!-- 评估结果 -->
<div style="font-weight: bold"> <div style="font-weight: bold">
{{ $t("trials:adReview:title:result") }} {{ $t("trials:adReview:title:result") }}
@ -39,62 +32,45 @@
<el-table :data="adInfo.VisitInfoList" style="width: 100%"> <el-table :data="adInfo.VisitInfoList" style="width: 100%">
<!-- 访视名称 --> <!-- 访视名称 -->
<el-table-column <el-table-column prop="VisitName" :label="$t('trials:adReview:table:visitName')" show-overflow-tooltip
prop="VisitName" width="150" />
:label="$t('trials:adReview:table:visitName')"
show-overflow-tooltip
width="150"
/>
<!-- 评估结果 --> <!-- 评估结果 -->
<el-table-column <el-table-column v-for="j in judgeQuestion" :key="j.armEnum" :label="j.armEnum === 1
v-for="j in judgeQuestion"
:key="j.armEnum"
:label="
j.armEnum === 1
? $t('trials:adReview:table:viewR1') ? $t('trials:adReview:table:viewR1')
: j.armEnum === 2 : j.armEnum === 2
? $t('trials:adReview:table:viewR2') ? $t('trials:adReview:table:viewR2')
: $fd('ArmEnum', j.armEnum) : $fd('ArmEnum', j.armEnum)
" " align="center" prop="">
align="center"
prop=""
>
<template> <template>
<el-table-column <el-table-column v-for="(qs, i) in j.judgeQuestionList" :key="i" prop="" :label="qs" show-overflow-tooltip
v-for="(qs, i) in j.judgeQuestionList" width="150">
:key="i"
prop=""
:label="qs"
show-overflow-tooltip
width="150"
>
<template slot-scope="scope"> <template slot-scope="scope">
<div v-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].QuestionType === 1"> <div v-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].QuestionType === 1">
<span v-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].DictionaryCode"> <span v-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].DictionaryCode">
{{ $fd(scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].DictionaryCode,parseInt(scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer)) {{
$fd(scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].DictionaryCode,
parseInt(scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer))
}} }}
</span> </span>
<span v-else> <span v-else>
{{ scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer }} {{ scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer }}
</span> </span>
<span v-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Unit && !isNaN(parseFloat(scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer))">{{ $fd('ValueUnit', parseInt(scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Unit)) }}</span> <span
v-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Unit && !isNaN(parseFloat(scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer))">{{
$fd('ValueUnit', parseInt(scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Unit)) }}</span>
</div> </div>
<div v-else-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].QuestionType === 2"> <div v-else-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].QuestionType === 2">
<div v-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer"> <div v-if="scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer">
<span> <span>
{{ $fd("YesOrNo",scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer) }} {{ $fd("YesOrNo", scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i].Answer) }}
</span> </span>
<!-- 查看详情 --> <!-- 查看详情 -->
<el-button <el-button type="text" style="margin-left: 5px" @click="
type="text"
style="margin-left: 5px"
@click="
handleViewDetail( handleViewDetail(
scope.row.VisitTaskInfoList[j.index].GlobalVisitTaskId scope.row.VisitTaskInfoList[j.index].GlobalVisitTaskId
) )
" ">
>
{{ $t("trials:adReview:table:view") }} {{ $t("trials:adReview:table:view") }}
</el-button> </el-button>
</div> </div>
@ -119,60 +95,34 @@
</el-table-column> </el-table-column>
<!-- 查看详情 --> <!-- 查看详情 -->
<el-table-column <el-table-column :label="criterionType === 10
:label="
criterionType === 10
? $t('trials:adReview:table:visitInfoview') ? $t('trials:adReview:table:visitInfoview')
: $t('trials:adReview:table:view') : $t('trials:adReview:table:view')
" " width="200" :fixed="isFixed ? 'right' : false">
width="200"
:fixed="isFixed ? 'right' : false"
>
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 查看R1详情 --> <!-- 查看R1详情 -->
<el-button <el-button type="text" :title="$t('trials:adReview:table:viewR1')" @click="handleView(scope.row, 1)">
type="text"
:title="$t('trials:adReview:table:viewR1')"
@click="handleView(scope.row, 1)"
>
R1 R1
</el-button> </el-button>
<!-- 查看R2详情 --> <!-- 查看R2详情 -->
<el-button <el-button type="text" :title="$t('trials:adReview:table:viewR2')" @click="handleView(scope.row, 2)">
type="text"
:title="$t('trials:adReview:table:viewR2')"
@click="handleView(scope.row, 2)"
>
R2 R2
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
<!-- 全局详情 PCWG --> <!-- 全局详情 PCWG -->
<el-table-column <el-table-column v-if="criterionType === 10" prop="VisitName" :label="$t('trials:adReview:table:glInfo')"
v-if="criterionType === 10" show-overflow-tooltip width="150">
prop="VisitName"
:label="$t('trials:adReview:table:glInfo')"
show-overflow-tooltip
width="150"
>
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 查看R1详情 --> <!-- 查看R1详情 -->
<el-button <el-button v-if="scope.$index === adInfo.VisitInfoList.length - 1" type="text"
v-if="scope.$index === adInfo.VisitInfoList.length - 1" :title="$t('trials:adReview:table:viewR1')" @click="handleViewGl(scope.row, 1)">
type="text"
:title="$t('trials:adReview:table:viewR1')"
@click="handleViewGl(scope.row, 1)"
>
R1 R1
</el-button> </el-button>
<!-- 查看R2详情 --> <!-- 查看R2详情 -->
<el-button <el-button v-if="scope.$index === adInfo.VisitInfoList.length - 1" type="text"
v-if="scope.$index === adInfo.VisitInfoList.length - 1" :title="$t('trials:adReview:table:viewR2')" @click="handleViewGl(scope.row, 2)">
type="text"
:title="$t('trials:adReview:table:viewR2')"
@click="handleViewGl(scope.row, 2)"
>
R2 R2
</el-button> </el-button>
</template> </template>
@ -186,120 +136,64 @@
$t("trials:adReview:title:adResult") $t("trials:adReview:title:adResult")
}}</span> }}</span>
</div> </div>
<el-form <el-form ref="adForm" v-loading="loading" :model="adForm" style="width: 800px" label-width="100">
ref="adForm"
v-loading="loading"
:model="adForm"
style="width: 800px"
label-width="100"
>
<!-- 选择阅片人 --> <!-- 选择阅片人 -->
<el-form-item <el-form-item :label="$t('trials:adReview:title:choseReader')" prop="judgeResultTaskId" :rules="[
:label="$t('trials:adReview:title:choseReader')"
prop="judgeResultTaskId"
:rules="[
{ required: true, message: this.$t('common:ruleMessage:select') }, { required: true, message: this.$t('common:ruleMessage:select') },
]" ]">
> <el-radio-group v-model="adForm.judgeResultTaskId" :disabled="adInfo.ReadingTaskState >= 2">
<el-radio-group <el-radio v-for="t in visitTaskArmList" :key="t.VisitTaskId" :label="t.VisitTaskId"
v-model="adForm.judgeResultTaskId" @change="handleVisitTaskArmChange">
:disabled="adInfo.ReadingTaskState >= 2"
>
<el-radio
v-for="t in visitTaskArmList"
:key="t.VisitTaskId"
:label="t.VisitTaskId"
@change="handleVisitTaskArmChange"
>
{{ $fd("ArmEnum", t.ArmEnum) }} {{ $fd("ArmEnum", t.ArmEnum) }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!-- 裁判原因 --> <!-- 裁判原因 -->
<el-form-item <el-form-item :label="$t('trials:adReview:title:adReason')" prop="judgeResultRemark" :rules="[
:label="$t('trials:adReview:title:adReason')"
prop="judgeResultRemark"
:rules="[
{ required: true, message: this.$t('common:ruleMessage:specify') }, { required: true, message: this.$t('common:ruleMessage:specify') },
{ {
max: 500, max: 500,
message: `${this.$t('common:ruleMessage:maxLength')} 500`, message: `${this.$t('common:ruleMessage:maxLength')} 500`,
trigger: ['blur', 'change'], trigger: ['blur', 'change'],
}, },
]" ]">
>
<div style="position: relative"> <div style="position: relative">
<div <div style="
style="
position: absolute; position: absolute;
left: 0; left: 0;
top: 30px; top: 30px;
color: #606266; color: #606266;
font-size: 13px; font-size: 13px;
" ">
>
{{ remark }} {{ remark }}
</div> </div>
<el-input <el-input v-model="adForm.judgeResultRemark" type="textarea" :autosize="{ minRows: 4, maxRows: 6 }"
v-model="adForm.judgeResultRemark" :disabled="adInfo.ReadingTaskState >= 2" style="margin-top: 25px" />
type="textarea"
:autosize="{ minRows: 4, maxRows: 6 }"
:disabled="adInfo.ReadingTaskState >= 2"
style="margin-top: 25px"
/>
</div> </div>
</el-form-item> </el-form-item>
<!-- 截图说明 --> <!-- 截图说明 -->
<el-form-item :label="$t('trials:adReview:title:screenShot')"> <el-form-item :label="$t('trials:adReview:title:screenShot')">
<el-upload <el-upload action :accept="accept" :on-preview="handlePictureCardPreview" :before-upload="handleBeforeUpload"
action :http-request="uploadScreenshot" list-type="picture-card" :on-remove="handleRemove" :file-list="fileList"
:accept="accept" :class="{ disabled: adInfo.ReadingTaskState >= 2 }" :disabled="adInfo.ReadingTaskState >= 2">
:on-preview="handlePictureCardPreview"
:before-upload="handleBeforeUpload"
:http-request="uploadScreenshot"
list-type="picture-card"
:on-remove="handleRemove"
:file-list="fileList"
:class="{ disabled: adInfo.ReadingTaskState >= 2 }"
:disabled="adInfo.ReadingTaskState >= 2"
>
<i slot="default" class="el-icon-plus" /> <i slot="default" class="el-icon-plus" />
<div <div slot="file" slot-scope="{ file }" style="width: 100%; height: 100%">
slot="file" <viewer :ref="file.url" :images="images" style="
slot-scope="{ file }"
style="width: 100%; height: 100%"
>
<viewer
:ref="file.url"
:images="images"
style="
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
" ">
> <img class="el-upload-list__item-thumbnail" :src="OSSclientConfig.basePath + file.url" alt=""
<img crossorigin="anonymous" style="max-width: 100%; max-height: 100%">
class="el-upload-list__item-thumbnail"
:src="OSSclientConfig.basePath + file.url"
alt=""
crossorigin="anonymous"
style="max-width: 100%; max-height: 100%"
>
<span class="el-upload-list__item-actions"> <span class="el-upload-list__item-actions">
<span <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" /> <i class="el-icon-zoom-in" />
</span> </span>
<span <span v-if="adInfo.ReadingTaskState < 2" class="el-upload-list__item-delete"
v-if="adInfo.ReadingTaskState < 2" @click="handleRemove(file)">
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete" /> <i class="el-icon-delete" />
</span> </span>
</span> </span>
@ -324,10 +218,7 @@
</div> </div>
</el-card> </el-card>
<el-card <el-card v-if="isReadingShowPreviousResults" :body-style="{ padding: '10px' }">
v-if="isReadingShowPreviousResults"
:body-style="{ padding: '10px' }"
>
<div slot="header" class="clearfix"> <div slot="header" class="clearfix">
<!-- 既往裁判评估 --> <!-- 既往裁判评估 -->
<span style="font-weight: bold">{{ <span style="font-weight: bold">{{
@ -335,24 +226,12 @@
}}</span> }}</span>
</div> </div>
<el-table <el-table v-loading="priorLoading" :data="priorADList" style="width: 100%">
v-loading="priorLoading"
:data="priorADList"
style="width: 100%"
>
<!-- 裁判阅片 --> <!-- 裁判阅片 -->
<el-table-column <el-table-column prop="TaskBlindName" :label="$t('trials:adReview:table:adReading')" show-overflow-tooltip
prop="TaskBlindName" width="200" />
:label="$t('trials:adReview:table:adReading')" <el-table-column prop="JudgeResultArm" :label="$t('trials:adReview:table:adResult')" show-overflow-tooltip
show-overflow-tooltip width="200">
width="200"
/>
<el-table-column
prop="JudgeResultArm"
:label="$t('trials:adReview:table:adResult')"
show-overflow-tooltip
width="200"
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd("ArmEnum", scope.row.JudgeResultArm) }} {{ $fd("ArmEnum", scope.row.JudgeResultArm) }}
</template> </template>
@ -360,35 +239,22 @@
<el-table-column :label="$t('common:action:action')" width="200"> <el-table-column :label="$t('common:action:action')" width="200">
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 查看详情 --> <!-- 查看详情 -->
<el-button <el-button circle :title="$t('trials:adReview:table:view')" icon="el-icon-view"
circle @click="handleViewDetail(scope.row.VisitTaskId)" />
:title="$t('trials:adReview:table:view')"
icon="el-icon-view"
@click="handleViewDetail(scope.row.VisitTaskId)"
/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</el-card> </el-card>
<!-- 签名框 --> <!-- 签名框 -->
<el-dialog <el-dialog v-if="signVisible" :visible.sync="signVisible" :close-on-click-modal="false" width="600px"
v-if="signVisible" custom-class="base-dialog-wrapper">
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
custom-class="base-dialog-wrapper"
>
<div slot="title"> <div slot="title">
<span style="font-size: 18px">{{ $t("common:dialogTitle:sign") }}</span> <span style="font-size: 18px">{{ $t("common:dialogTitle:sign") }}</span>
<span style="font-size: 12px; margin-left: 5px">{{ <span style="font-size: 12px; margin-left: 5px">{{
`(${$t("common:label:sign")}${currentUser})` `(${$t("common:label:sign")}${currentUser})`
}}</span> }}</span>
</div> </div>
<SignForm <SignForm ref="signForm" :sign-code-enum="signCode" @closeDialog="closeSignDialog" />
ref="signForm"
:sign-code-enum="signCode"
@closeDialog="closeSignDialog"
/>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
@ -729,17 +595,13 @@ export default {
this.$router.currentRoute.query.TrialReadingCriterionId this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2 ) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${ path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId
this.trialId }&subjectCode=${this.subjectCode}&subjectId=${this.subjectId
}&subjectCode=${this.subjectCode}&subjectId=${
this.subjectId
}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` }&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${ path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId
this.trialId }&subjectCode=${this.subjectCode}&subjectId=${this.subjectId
}&subjectCode=${this.subjectCode}&subjectId=${
this.subjectId
}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` }&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} }
var routeData = this.$router.resolve({ path }) var routeData = this.$router.resolve({ path })
@ -766,21 +628,15 @@ export default {
this.$router.currentRoute.query.TrialReadingCriterionId this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2 ) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${ path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId
this.trialId }&subjectCode=${this.subjectCode}&subjectId=${this.subjectId
}&subjectCode=${this.subjectCode}&subjectId=${ }&visitTaskId=${task.VisitTaskId
this.subjectId
}&visitTaskId=${
task.VisitTaskId
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` }&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${ path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId
this.trialId }&subjectCode=${this.subjectCode}&subjectId=${this.subjectId
}&subjectCode=${this.subjectCode}&subjectId=${ }&visitTaskId=${task.VisitTaskId
this.subjectId
}&visitTaskId=${
task.VisitTaskId
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` }&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} }
var routeData = this.$router.resolve({ path }) var routeData = this.$router.resolve({ path })
@ -801,21 +657,15 @@ export default {
this.$router.currentRoute.query.TrialReadingCriterionId this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2 ) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${ path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId
this.trialId }&subjectCode=${this.subjectCode}&subjectId=${this.subjectId
}&subjectCode=${this.subjectCode}&subjectId=${ }&visitTaskId=${task.GlobalVisitTaskId
this.subjectId
}&visitTaskId=${
task.GlobalVisitTaskId
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` }&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${ path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId
this.trialId }&subjectCode=${this.subjectCode}&subjectId=${this.subjectId
}&subjectCode=${this.subjectCode}&subjectId=${ }&visitTaskId=${task.GlobalVisitTaskId
this.subjectId
}&visitTaskId=${
task.GlobalVisitTaskId
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` }&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} }
var routeData = this.$router.resolve({ path }) var routeData = this.$router.resolve({ path })
@ -932,17 +782,21 @@ export default {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
.box-mr { .box-mr {
margin: 10px 0; margin: 10px 0;
} }
.disabled { .disabled {
::v-deep .el-upload--picture-card { ::v-deep .el-upload--picture-card {
display: none; display: none;
} }
} }
::v-deep .el-upload-list__item { ::v-deep .el-upload-list__item {
transition: none !important; transition: none !important;
} }
::v-deep .el-upload-list__item-thumbnail { ::v-deep .el-upload-list__item-thumbnail {
/* 图片在方框内显示长边 */ /* 图片在方框内显示长边 */
object-fit: scale-down !important; object-fit: scale-down !important;

View File

@ -0,0 +1,116 @@
<template>
<div class="ContourViewport" ref="ContourViewport" id="ContourViewport"></div>
</template>
<script>
import {
getRenderingEngine,
CONSTANTS,
setVolumesForViewports,
eventTarget,
Enums,
utilities,
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
const {
Enums: csToolsEnums,
segmentation,
TrackballRotateTool,
ToolGroupManager
} = cornerstoneTools
const { MouseBindings, Events: toolsEvents } = csToolsEnums
export default {
name: "ContourViewport",
props: {
renderingEngineId: {
type: String,
required: true
},
viewportId: {
type: String,
required: true
},
visitInfo: {
type: Object,
default: () => {
return {}
}
},
// visible: {
// type: Boolean,
// default: false
// },
},
data() {
return {
volumeId: null,
}
},
mounted() {
eventTarget.addEventListener(Enums.Events.WEB_WORKER_PROGRESS, (evt) => {
const { progress } = evt.detail;
console.log(progress, 'countour_progress')
});
},
methods: {
async setSeriesInfo(obj) {
try {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
let { volumeId, segmentationId } = obj
this.volumeId = volumeId
await setVolumesForViewports(
renderingEngine,
[{ volumeId, callback: setCtTransferFunctionForVolumeActor }],
[this.viewportId]
);
// const volumeActor = viewport.getDefaultActor()
// .actor;
// utilities.applyPreset(
// volumeActor,
// CONSTANTS.VIEWPORT_PRESETS.find((preset) => preset.name === 'CT-Bone')
// );
// volumeActor.setVisibility(false);
viewport.render();
const toolGroup = ToolGroupManager.getToolGroup(this.viewportId)
toolGroup.setToolActive(TrackballRotateTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Primary,
},
],
});
let s = segmentation.getActiveSegmentation(this.viewportId)
if (s) {
await segmentation.removeSegmentationRepresentation(this.viewportId, {
segmentationId: s.segmentationId,
type: csToolsEnums.SegmentationRepresentations.Surface,
})
}
console.log("ContourLoading...")
await segmentation.addSegmentationRepresentations(this.viewportId, [
{
segmentationId,
type: csToolsEnums.SegmentationRepresentations.Contour,
},
]);
} catch (e) {
console.log(e)
}
},
}
}
</script>
<style lang="scss" scoped>
#ContourViewport {
width: 450px;
height: 300px;
position: fixed;
top: 100px;
z-index: -9999;
left: 100px;
}
</style>

View File

@ -76,9 +76,24 @@ import * as cornerstoneTools from '@cornerstonejs/tools'
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData' 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 setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
import { setCtMappingRange } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor' import { setCtMappingRange } 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 {
setPetTransferFunctionForVolumeActor
} from './helpers/index.js'
import { vec3, mat4 } from 'gl-matrix' import { vec3, mat4 } from 'gl-matrix'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
import {
renderSegmentation,
readingSegmentByConfig,
selectSegmentation,
selectSegment,
createSegmentationRepresentation,
viewSegmentation,
viewSegment,
jumpBidirectional,
viewBidirectional,
changeColor,
resetViewport
} from "./helpers/segmentations"
export default { export default {
name: 'MPRViewport', name: 'MPRViewport',
props: { props: {
@ -99,6 +114,36 @@ export default {
default: () => { default: () => {
return {} return {}
} }
},
histogramVisible: {
type: Boolean,
default: false
},
actionConfiguration: {
type: Object,
default: () => {
return {}
}
},
SegmentConfig: {
type: Object,
default: () => {
return {}
}
},
curSegSeries: {
type: Object,
default: () => {
return {}
}
},
segmentIndex: {
type: Number,
default: 0
},
segmentationId: {
type: String,
default: ''
} }
}, },
data() { data() {
@ -140,6 +185,7 @@ export default {
rotateAngle: 0, rotateAngle: 0,
rotateBarLeft: 0, rotateBarLeft: 0,
loading: false, loading: false,
toggleClipPlayTimer: null
} }
}, },
mounted() { mounted() {
@ -149,6 +195,39 @@ export default {
this.$nextTick(() => { this.$nextTick(() => {
this.initViewport() this.initViewport()
}) })
DicomEvent.$on('createSegmentationRepresentation', (segmentationId) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
createSegmentationRepresentation(this.viewportId, segmentationId)
})
DicomEvent.$on('viewSegmentation', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
viewSegmentation(obj, this.viewportId)
})
DicomEvent.$on('viewSegment', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
viewSegment(obj, this.viewportId)
})
DicomEvent.$on('jumpBidirectional', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
jumpBidirectional(obj, this.viewportId, this.volumeId)
})
DicomEvent.$on('viewBidirectional', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
viewBidirectional(obj, this.viewportId)
})
DicomEvent.$on('changeColor', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
changeColor(obj, this.viewportId)
})
DicomEvent.$on('resetViewport', () => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
resetViewport(this.viewportId)
})
DicomEvent.$on('renderSegmentation', async (viewportId) => {
// if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
if (this.viewportId !== viewportId) return false
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.renderingEngineId, null, this.actionConfiguration)
})
}, },
watch: { watch: {
MPRInfo: { MPRInfo: {
@ -167,6 +246,25 @@ export default {
} }
}, },
deep: true deep: true
},
SegmentConfig: {
handler() {
if (!this.segmentationId) return false
if (!this.series.TaskInfo) return false
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
},
deep: true
},
segmentIndex() {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
if (this.segmentIndex <= 0) return false
selectSegment(this.viewportId, this.segmentationId, this.segmentIndex)
},
segmentationId() {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
if (!this.segmentationId) return false
selectSegmentation(this.viewportId, this.segmentationId)
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
} }
}, },
methods: { methods: {
@ -183,6 +281,7 @@ export default {
this.element.addEventListener("CORNERSTONE_VOLUME_NEW_IMAGE", this.stackNewImage) this.element.addEventListener("CORNERSTONE_VOLUME_NEW_IMAGE", this.stackNewImage)
this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified) this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
this.element.addEventListener('wheel', (e) => { this.element.addEventListener('wheel', (e) => {
// if (this.histogramVisible) return false
// console.log('CORNERSTONE_STACK_VIEWPORT_SCROLL') // console.log('CORNERSTONE_STACK_VIEWPORT_SCROLL')
const renderingEngine = getRenderingEngine(this.renderingEngineId) const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId) const viewport = renderingEngine.getViewport(this.viewportId)
@ -285,6 +384,7 @@ export default {
this.imageInfo.sliceThickness = type === this.series.orientation ? spacing[2] : spacing[0] this.imageInfo.sliceThickness = type === this.series.orientation ? spacing[2] : spacing[0]
this.imageInfo.total = detail.numberOfSlices this.imageInfo.total = detail.numberOfSlices
this.getOrientationMarker() this.getOrientationMarker()
this.$emit("resetHistogram")
let properties = viewport.getProperties(this.volumeId) let properties = viewport.getProperties(this.volumeId)
if (properties && properties.voiRange) { if (properties && properties.voiRange) {
var { lower, upper } = properties.voiRange var { lower, upper } = properties.voiRange
@ -392,11 +492,20 @@ export default {
this.playClipState = isPlay this.playClipState = isPlay
const renderingEngine = getRenderingEngine(this.renderingEngineId) const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId) const viewport = renderingEngine.getViewport(this.viewportId)
if (isPlay) { if (isPlay) {
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: true }) this.toggleClipPlayTimer = setInterval(() => {
let index = this.series.SliceIndex + 1;
if (index > this.imageInfo.total - 1) index = 0
csUtils.jumpToSlice(viewport.element, { imageIndex: index });
}, framesPerSecond)
// cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: true })
} else { } else {
cornerstoneTools.utilities.cine.stopClip(viewport.element) if (this.toggleClipPlayTimer) {
clearInterval(this.toggleClipPlayTimer)
this.toggleClipPlayTimer = null
}
// cornerstoneTools.utilities.cine.stopClip(viewport.element)
} }
}, },
scrollPage(type) { scrollPage(type) {
@ -490,7 +599,7 @@ export default {
.setVolumes([{ .setVolumes([{
volumeId: this.volumeId, callback: (r) => { volumeId: this.volumeId, callback: (r) => {
if (this.series.Modality === 'PT') { if (this.series.Modality === 'PT') {
setPetColorMapTransferFunctionForVolumeActor(r, true) setPetTransferFunctionForVolumeActor(r)
} else { } else {
let volume = cache.getVolume(this.volumeId) let volume = cache.getVolume(this.volumeId)
const voi = metaData.get('voiLutModule', volume._imageIds[Math.ceil((volume._imageIds.length - 1) / 2)]) const voi = metaData.get('voiLutModule', volume._imageIds[Math.ceil((volume._imageIds.length - 1) / 2)])
@ -498,7 +607,6 @@ export default {
setCtTransferFunctionForVolumeActor(r) setCtTransferFunctionForVolumeActor(r)
} }
console.log("渲染成功") console.log("渲染成功")
DicomEvent.$emit("isloaded", { isChange: false })
} }
}]).then(r => { }]).then(r => {
if (data.isLocation || !this.imageInfo.zoom) { if (data.isLocation || !this.imageInfo.zoom) {
@ -506,6 +614,22 @@ export default {
} }
}) })
viewport.render() viewport.render()
if (this.series.Modality === 'PT') {
setTimeout(() => {
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
viewport.resetProperties()
viewport.setProperties({ voiRange: { upper: 5, lower: 0 } })
viewport.render()
renderingEngine.render()
}, 100)
}
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.renderingEngineId, null, this.actionConfiguration)
DicomEvent.$emit('SegmentationLoading', this.viewportId)
let volume = cache.getVolume(this.volumeId)
// console.log(volume, 'volume')
if (this.series.orientation === 'AXIAL' && this.series.curIndex) return this.setFullScreen(this.series.curIndex)
let index = this.series.orientation === 'AXIAL' ? Math.ceil((volume._imageIds.length - 1) / 2) - 1 : Math.ceil((volume.dimensions[0]) / 2) - 1
this.setFullScreen(index)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }
@ -680,6 +804,12 @@ export default {
return `NS: ${this.$store.state.trials.downloadTip}` return `NS: ${this.$store.state.trials.downloadTip}`
} }
}, },
destroyed() {
if (this.toggleClipPlayTimer) {
clearInterval(this.toggleClipPlayTimer)
this.toggleClipPlayTimer = null
}
}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -123,6 +123,10 @@ export default {
type: Number, type: Number,
required: true required: true
}, },
activeTool: {
type: String,
default: ''
},
}, },
data() { data() {
return { return {
@ -254,10 +258,15 @@ 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 toolGroup =
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId) cornerstoneTools.ToolGroupManager.getToolGroupForViewport(
this.viewportId,
this.renderingEngineId
) || cornerstoneTools.ToolGroupManager.getToolGroup(this.viewportId)
if (toolGroup) {
toolGroup.setToolEnabled('ScaleOverlay') toolGroup.setToolEnabled('ScaleOverlay')
} }
}
}, },
setFullScreen(index) { setFullScreen(index) {
@ -829,6 +838,7 @@ export default {
this.sliderInfo.isMove = false this.sliderInfo.isMove = false
}, },
handletoolsMouseWheel(e) { handletoolsMouseWheel(e) {
if (this.activeTool === 'Crosshairs') return
const { viewportId, wheel } = e.detail const { viewportId, wheel } = e.detail
if (this.isMip) { if (this.isMip) {
const container = document.getElementById('rotateBar') const container = document.getElementById('rotateBar')
@ -852,6 +862,7 @@ export default {
this.rotateBarInfo.isMove = false this.rotateBarInfo.isMove = false
}, },
rotateBarMousemove(e) { rotateBarMousemove(e) {
if (this.activeTool === 'Crosshairs') return
// //
if (!this.rotateBarInfo.isMove) return if (!this.rotateBarInfo.isMove) return
const container = document.getElementById('rotateBar') const container = document.getElementById('rotateBar')
@ -867,6 +878,7 @@ export default {
this.rotateBarLeft = x this.rotateBarLeft = x
}, },
rotateBarMousedown(e) { rotateBarMousedown(e) {
if (this.activeTool === 'Crosshairs') return
this.rotateBarInfo.initLeft = e.srcElement.offsetLeft this.rotateBarInfo.initLeft = e.srcElement.offsetLeft
this.rotateBarInfo.initX = e.clientX this.rotateBarInfo.initX = e.clientX
this.rotateBarInfo.isMove = true this.rotateBarInfo.isMove = true
@ -905,6 +917,7 @@ export default {
viewport.render() viewport.render()
}, },
clickRotate(e) { clickRotate(e) {
if (this.activeTool === 'Crosshairs') return
// console.log('clickRotate') // console.log('clickRotate')
const container = document.getElementById('rotateBar') const container = document.getElementById('rotateBar')
const containerWidth = container.offsetWidth const containerWidth = container.offsetWidth

View File

@ -14,8 +14,8 @@
<div v-for="s in visitTaskList" v-show="activeTaskId === s.VisitTaskId" :key="s.VisitTaskId" <div v-for="s in visitTaskList" v-show="activeTaskId === s.VisitTaskId" :key="s.VisitTaskId"
style="height:100%;"> style="height:100%;">
<study-list v-if="selectArr.includes(s.VisitTaskId) && s.StudyList.length > 0" :ref="s.VisitTaskId" <study-list v-if="selectArr.includes(s.VisitTaskId) && s.StudyList.length > 0" :ref="s.VisitTaskId"
:visit-task-info="s" :marked-series-ids="markedSeriesIds" @activeSeries="activeSeries" :visit-task-info="s" :marked-series-ids="markedSeriesIds" :readingTool="readingTool"
@showMultiFrame="showMultiFrame" /> @activeSeries="activeSeries" @showMultiFrame="showMultiFrame" />
</div> </div>
</div> </div>
@ -165,6 +165,11 @@
v-if="(criterionType === 0 && readingTool === 0) || this.readingTool === 3"> 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>
<!-- 直方图 -->
<div class="tool-item" :title="`${$t('trials:reading:button:histogram')}`" @click.prevent="openHistogram"
v-if="this.readingTool === 3">
<svg-icon icon-class="histogram" class="svg-icon" />
</div>
<!-- 十字准星 --> <!-- 十字准星 -->
<div :class="['tool-item', activeTool === 'Crosshairs' ? 'tool-item-active' : '']" v-if="isMPR" <div :class="['tool-item', activeTool === 'Crosshairs' ? 'tool-item-active' : '']" v-if="isMPR"
:title="$t('trials:reading:button:crosshairs')" @click.prevent="setToolActive('Crosshairs')"> :title="$t('trials:reading:button:crosshairs')" @click.prevent="setToolActive('Crosshairs')">
@ -175,6 +180,11 @@
@click.prevent="openFusion"> @click.prevent="openFusion">
<svg-icon icon-class="fusion" class="svg-icon" /> <svg-icon icon-class="fusion" class="svg-icon" />
</div> </div>
<div :class="['tool-item', activeTool === 'Crosshairs' ? 'tool-item-active' : '']"
v-if="readingTool === 2 && isFusion" :title="$t('trials:reading:button:crosshairs')"
@click.prevent="setToolActive('Crosshairs')">
<svg-icon icon-class="crosshairs" class="svg-icon" />
</div>
<div v-for="tool in tools" :key="tool.toolName" <div v-for="tool in tools" :key="tool.toolName"
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === tool.toolName ? 'tool-item-active' : '']" :class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === tool.toolName ? 'tool-item-active' : '']"
:style="{ cursor: tool.isDisabled ? 'not-allowed' : 'pointer' }" :style="{ cursor: tool.isDisabled ? 'not-allowed' : 'pointer' }"
@ -308,8 +318,13 @@
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)"> @dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
<VolumeViewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`" <VolumeViewport :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" :histogramVisible="histogramVisible" :actionConfiguration="actionConfiguration"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" v-if="readingTool === 3" /> :SegmentConfig="SegmentConfig" :segmentationId.sync="segId" :segmentIndex.sync="segIndex"
:curSegSeries.sync="curSegSeries" @activeViewport="activeViewport"
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
@resetViewport="resetViewport" @resetHistogram="resetHistogram" v-if="readingTool === 3"
v-resize="(e) => handleSizeChange(e, `viewport-${index}`)" />
<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"
@ -325,9 +340,13 @@
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)"> @dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
<MPRViewport :ref="`viewport-MPR-${index}`" :data-viewport-uid="`viewport-MPR-${index}`" <MPRViewport :ref="`viewport-MPR-${index}`" :data-viewport-uid="`viewport-MPR-${index}`"
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-MPR-${index}`" :rendering-engine-id="renderingEngineId" :viewport-id="`viewport-MPR-${index}`"
:viewport-index="index" :MPRInfo="MPRInfo" @activeViewport="activeViewport" @setMPRInfo="setMPRInfo" :viewport-index="index" :histogramVisible="histogramVisible"
:actionConfiguration="actionConfiguration" :SegmentConfig="SegmentConfig"
:segmentationId.sync="segId" :segmentIndex.sync="segIndex" :curSegSeries.sync="curSegSeries"
:MPRInfo="MPRInfo" @activeViewport="activeViewport" @setMPRInfo="setMPRInfo"
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" /> @renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
@resetHistogram="resetHistogram" v-resize="(e) => handleSizeChange(e, `viewport-MPR-${index}`)" />
</div> </div>
</div> </div>
<div v-if="readingTool === 2" <div v-if="readingTool === 2"
@ -335,15 +354,19 @@
:style="gridStyle"> :style="gridStyle">
<div v-for="(v, index) in cellsMax" v-show="index < cells.length" :key="`viewport-fusion-${index}`" <div v-for="(v, index) in cellsMax" v-show="index < cells.length" :key="`viewport-fusion-${index}`"
:class="['grid-cell', 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)"
@mouseenter="hoverFusionViewport(index)" @mouseleave="hoverFusionViewport(-1)">
<PetCtViewport :ref="`viewport-fusion-${index}`" :data-viewport-uid="`viewport-fusion-${index}`" <PetCtViewport :ref="`viewport-fusion-${index}`" :data-viewport-uid="`viewport-fusion-${index}`"
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-fusion-${index}`" :rendering-engine-id="renderingEngineId" :viewport-id="`viewport-fusion-${index}`"
:viewport-index="index" @activeViewport="activeViewport" :viewport-index="index" :active-tool="activeTool" @activeViewport="activeViewport"
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @upperRangeChange="upperRangeChange" @renderAnnotations="renderAnnotations" @upperRangeChange="upperRangeChange"
@contentMouseup="contentMouseup" /> @contentMouseup="contentMouseup" />
</div> </div>
</div> </div>
<div v-if="readingTool === 2" class="fusion-hidden-viewports">
<div ref="viewport-fusion-hidden-sag" class="fusion-hidden-viewport" />
</div>
</div> </div>
</div> </div>
<!-- 表单 --> <!-- 表单 -->
@ -352,9 +375,11 @@
<el-tab-pane :label="$t('trials:reading:dicom3D:tabs:segment')" name="segment"> <el-tab-pane :label="$t('trials:reading:dicom3D:tabs:segment')" name="segment">
<Segmentations ref="Segmentations" :visitInfo="taskInfo" :isMPR="isMPR" <Segmentations ref="Segmentations" :visitInfo="taskInfo" :isMPR="isMPR"
:volumeToolGroupId="volumeToolGroupId" :viewportKey="viewportKey" :global-loading.sync="loading" :volumeToolGroupId="volumeToolGroupId" :viewportKey="viewportKey" :global-loading.sync="loading"
:loadingText.sync="loadingText" :rendering-engine-id="renderingEngineId" :trialCriterion="trialCriterion" :loadingText.sync="loadingText"
:activeViewportIndex="activeViewportIndex" :activeTool.sync="activeTool" :rendering-engine-id="renderingEngineId" :SegmentConfig="SegmentConfig" :segId.sync="segId"
:actionConfiguration="actionConfiguration" @setToolsPassive="setToolsPassive" :segIndex.sync="segIndex" :curSegSeries.sync="curSegSeries" :activeViewportIndex="activeViewportIndex"
:activeTool.sync="activeTool" :actionConfiguration="actionConfiguration"
:histogramVisible="histogramVisible" @setToolsPassive="setToolsPassive"
@resetQuestion="resetQuestion" /> @resetQuestion="resetQuestion" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('trials:reading:dicom3D:tabs:ecrf')" name="ecrf"> <el-tab-pane :label="$t('trials:reading:dicom3D:tabs:ecrf')" name="ecrf">
@ -486,6 +511,14 @@
<SegmentForm ref="SegmentForm" v-if="segmentVisible" :visible.sync="segmentVisible" :visitInfo="segmentVisitInfo" <SegmentForm ref="SegmentForm" v-if="segmentVisible" :visible.sync="segmentVisible" :visitInfo="segmentVisitInfo"
@handleSegmentSave="handleSegmentSave" /> @handleSegmentSave="handleSegmentSave" />
</el-dialog> </el-dialog>
<!--直方图-->
<histogram ref="histogram" v-if="readingTool === 3" :visible.sync="histogramVisible" :activeTool.sync="activeTool"
:viewportKey="viewportKey" :rendering-engine-id="renderingEngineId" :activeViewportIndex="activeViewportIndex" />
<!--分割可视化窗口-->
<!-- <SurfaceViewport ref="surfaceViewport" viewportId="surfaceViewport" v-if="readingTool === 3"
:visible.sync="surfaceVisible" :renderingEngineId="renderingEngineId" :visitInfo="taskInfo" />
<ContourViewport ref="contourViewport" viewportId="contourViewport" v-if="readingTool === 3"
:renderingEngineId="renderingEngineId" :visitInfo="taskInfo" /> -->
<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" />
@ -504,6 +537,7 @@ import {
RenderingEngine, RenderingEngine,
Enums, Enums,
// imageLoader, // imageLoader,
// CONSTANTS,
metaData, metaData,
volumeLoader, volumeLoader,
getRenderingEngine, getRenderingEngine,
@ -524,6 +558,9 @@ import PetCtViewport from './PetCtViewport'
import MPRViewport from './MPRViewport' import MPRViewport from './MPRViewport'
import VolumeViewport from './VolumeViewport' import VolumeViewport from './VolumeViewport'
import Segmentations from './Segmentations' import Segmentations from './Segmentations'
import histogram from "./histogram"
// import SurfaceViewport from "./SurfaceViewport"
// import ContourViewport from "./ContourViewport"
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'
@ -554,6 +591,9 @@ const {
ToolGroupManager, ToolGroupManager,
Enums: csToolsEnums, Enums: csToolsEnums,
StackScrollTool, StackScrollTool,
TrackballRotateTool,
PlanarFreehandContourSegmentationTool,
SplineContourSegmentationTool,
// ScaleOverlayTool, // ScaleOverlayTool,
PanTool, PanTool,
ZoomTool, ZoomTool,
@ -615,6 +655,9 @@ export default {
MPRViewport, MPRViewport,
VolumeViewport, VolumeViewport,
Segmentations, Segmentations,
histogram,
// SurfaceViewport,
// ContourViewport,
mRecisit, mRecisit,
recisit, recisit,
customizeQuestionList, customizeQuestionList,
@ -648,7 +691,7 @@ export default {
activeTaskIndex: -1, activeTaskIndex: -1,
activeStudyIndex: -1, activeStudyIndex: -1,
activeSeriesIndex: -1, activeSeriesIndex: -1,
currentVisitInfo: null, currentVisitInfo: {},
layout: 1, layout: 1,
cellsMax: 4, cellsMax: 4,
rows: 1, rows: 1,
@ -729,6 +772,7 @@ export default {
isMPR: false, isMPR: false,
volumeToolGroupId: "share-viewport-volume", volumeToolGroupId: "share-viewport-volume",
fusionToolGroupId: "share-viewport-fusion",
MPRInfo: { MPRInfo: {
AXIAL: { AXIAL: {
imageNum: 0 imageNum: 0
@ -758,12 +802,28 @@ export default {
}, },
}, },
}, },
SegmentConfig: {
renderOutline: true,
renderFill: true,
fillAlpha: 0.5,
outlineWidth: 1,
InactiveSegmentations: {
show: true,
fillAlpha: 0.3,
}
},
segId: null,
segIndex: null,
curSegSeries: {},
fusionOverlayModality: null, fusionOverlayModality: null,
lastUpper: null, lastUpper: null,
hasFusionUpperInitialized: false, hasFusionUpperInitialized: false,
timer: null, timer: {},
FullTimerOut: null, FullTimerOut: null,
isDelay: false isDelay: false,
histogramVisible: false,
// surfaceVisible: false
} }
}, },
computed: { computed: {
@ -856,7 +916,38 @@ export default {
this.setToolsPassive() this.setToolsPassive()
} }
} }
} },
// histogramVisible: {
// handler() {
// if (this.readingTool !== 3) return false
// this.setToolsPassive()
// let viewportIds = ['viewport-0', 'viewport-1', 'viewport-2', 'viewport-3', this.volumeToolGroupId]
// // if (this.isMPR) {
// // viewportIds = [this.volumeToolGroupId]
// // }
// viewportIds.forEach(id => {
// const toolGroup = ToolGroupManager.getToolGroup(id)
// if (this.histogramVisible) {
// toolGroup.setToolEnabled(StackScrollTool.toolName)
// } else {
// toolGroup.setToolActive(StackScrollTool.toolName, {
// bindings: [{ mouseButton: MouseBindings.Wheel }]
// })
// let annotations = annotation.state.getAllAnnotations().filter(item => item.metadata.toolName.includes('histogram_'));
// annotations.forEach(item => {
// annotation.state.removeAnnotation(item.annotationUID)
// })
// for (let i = 0; i < this.cells.length; i++) {
// const viewportId = `${this.viewportKey}-${i}`
// let renderingEngine = getRenderingEngine(renderingEngineId)
// const viewport = renderingEngine.getViewport(viewportId)
// viewport.render()
// }
// }
// })
// }
// },
}, },
mounted() { mounted() {
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
@ -904,6 +995,36 @@ export default {
this.getSystemInfoReading(); this.getSystemInfoReading();
}, },
methods: { methods: {
resetHistogram() {
if (!this.histogramVisible) return false
if (this.timer['histogram']) {
clearTimeout(this.timer['histogram'])
this.timer['histogram'] = null
}
this.timer['histogram'] = setTimeout(() => {
if (this.$refs.histogram && this.histogramVisible) {
this.$refs.histogram.init()
}
clearTimeout(this.timer['histogram'])
this.timer['histogram'] = null
}, 500)
},
showSurface(obj) {
// this.surfaceVisible = true
// this.$refs.contourViewport.setSeriesInfo(obj)
// this.$refs.surfaceViewport.setSeriesInfo(obj)
},
async openHistogram() {
this.histogramVisible = true
this.setToolsPassive()
this.$refs.histogram.init()
},
handleSizeChange(e, viewportId) {
let index = this.$refs[viewportId][0].series.SliceIndex
this.resetRenderingEngine(viewportId, index)
},
resetQuestion() { resetQuestion() {
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].getQuestions(false) this.$refs[`ecrf_${this.lastViewportTaskId}`][0].getQuestions(false)
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].initSegmentBinding() this.$refs[`ecrf_${this.lastViewportTaskId}`][0].initSegmentBinding()
@ -1240,6 +1361,27 @@ export default {
} }
} }
] ]
// let element5 = this.$refs.surfaceViewport.$el
// let element6 = this.$refs.contourViewport.$el
// viewportInputArray.push({
// viewportId: 'surfaceViewport',
// type: ViewportType.VOLUME_3D,
// element: element5,
// defaultOptions: {
// orientation: Enums.OrientationAxis.CORONAL,
// background: [1, 1, 1]
// }
// })
// viewportInputArray.push({
// viewportId: 'contourViewport',
// type: ViewportType.ORTHOGRAPHIC,
// element: element6,
// defaultOptions: {
// orientation: Enums.OrientationAxis.AXIAL
// }
// })
// viewportIds.push('surfaceViewport')
// viewportIds.push('contourViewport')
} }
if ((this.criterionType === 0 && this.readingTool === 0) || this.readingTool === 3) { if ((this.criterionType === 0 && this.readingTool === 0) || this.readingTool === 3) {
const volumeElement1 = this.$refs['viewport-MPR-0'][0].$el const volumeElement1 = this.$refs['viewport-MPR-0'][0].$el
@ -1279,6 +1421,7 @@ export default {
const fusionElement2 = this.$refs['viewport-fusion-1'][0].$el const fusionElement2 = this.$refs['viewport-fusion-1'][0].$el
const fusionElement3 = this.$refs['viewport-fusion-2'][0].$el const fusionElement3 = this.$refs['viewport-fusion-2'][0].$el
const fusionElement4 = this.$refs['viewport-fusion-3'][0].$el const fusionElement4 = this.$refs['viewport-fusion-3'][0].$el
const fusionHiddenSag = this.$refs['viewport-fusion-hidden-sag']
const arr = [ const arr = [
{ {
viewportId: 'viewport-fusion-0', viewportId: 'viewport-fusion-0',
@ -1313,13 +1456,23 @@ export default {
orientation: Enums.OrientationAxis.CORONAL, orientation: Enums.OrientationAxis.CORONAL,
background: [1, 1, 1] background: [1, 1, 1]
} }
},
{
viewportId: 'viewport-fusion-hidden-sag',
type: ViewportType.ORTHOGRAPHIC,
element: fusionHiddenSag,
defaultOptions: {
orientation: Enums.OrientationAxis.SAGITTAL,
background: [1, 1, 1]
}
} }
] ]
viewportInputArray = [...viewportInputArray, ...arr] viewportInputArray = [...viewportInputArray, ...arr]
viewportIds = viewportIds.concat(fusionViewportIds) viewportIds = viewportIds.concat(fusionViewportIds, ['viewport-fusion-hidden-sag'])
} }
renderingEngine.setViewports(viewportInputArray) renderingEngine.setViewports(viewportInputArray)
this.addAnnotationListeners() this.addAnnotationListeners()
// cornerstoneTools.addTool(TrackballRotateTool)
cornerstoneTools.addTool(StackScrollTool) cornerstoneTools.addTool(StackScrollTool)
cornerstoneTools.addTool(PanTool) cornerstoneTools.addTool(PanTool)
cornerstoneTools.addTool(ZoomTool) cornerstoneTools.addTool(ZoomTool)
@ -1344,24 +1497,63 @@ export default {
cornerstoneTools.addTool(LabelMapEditWithContourTool) cornerstoneTools.addTool(LabelMapEditWithContourTool)
cornerstoneTools.addTool(BrushTool) cornerstoneTools.addTool(BrushTool)
cornerstoneTools.addTool(SegmentBidirectionalTool) cornerstoneTools.addTool(SegmentBidirectionalTool)
// cornerstoneTools.addTool(PlanarFreehandContourSegmentationTool);
// cornerstoneTools.addTool(SplineContourSegmentationTool);
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
} else if (viewportId.startsWith('viewport-fusion-')) {
toolGroupId = this.fusionToolGroupId
} }
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)
if (toolGroupId.includes('surface')) {
// toolGroup.addTool(TrackballRotateTool.toolName, {
// rotateSampleDistanceFactor: 0,
// });
// toolGroup.setToolActive(TrackballRotateTool.toolName, {
// bindings: [
// {
// mouseButton: MouseBindings.Primary,
// },
// ],
// });
} else if (toolGroupId.includes('contour')) {
// toolGroup.addTool(PlanarFreehandContourSegmentationTool.toolName);
// toolGroup.addTool(SplineContourSegmentationTool.toolName);
// toolGroup.setToolActive(PlanarFreehandContourSegmentationTool.toolName, {
// bindings: [
// {
// mouseButton: MouseBindings.Primary, // Middle Click
// },
// ],
// });
} else {
toolGroup.addTool(StackScrollTool.toolName, { toolGroup.addTool(StackScrollTool.toolName, {
loop: true, // loop: true, //
}) })
toolGroup.addTool(ScaleOverlayTool.toolName) toolGroup.addTool(ScaleOverlayTool.toolName)
toolGroup.addTool(PanTool.toolName) toolGroup.addTool(PanTool.toolName)
toolGroup.addTool(ZoomTool.toolName) toolGroup.addTool(ZoomTool.toolName)
toolGroup.addTool(BrushTool.toolName) toolGroup.addTool(BrushTool.toolName)
if (this.readingTool === 3 || toolGroupId === this.volumeToolGroupId) { if (this.readingTool === 3 || toolGroupId === this.volumeToolGroupId) {
toolGroup.addToolInstance(
'histogram_RectangleROI',
RectangleROITool.toolName,
);
toolGroup.addToolInstance(
'histogram_CircleROI',
CircleROITool.toolName,
);
toolGroup.addToolInstance(
'histogram_PlanarFreehandROI',
PlanarFreehandROITool.toolName,
);
toolGroup.addToolInstance( toolGroup.addToolInstance(
'CircularBrush', 'CircularBrush',
BrushTool.toolName, BrushTool.toolName,
@ -1409,6 +1601,11 @@ export default {
toolGroup.addTool(CrosshairsTool.toolName, { toolGroup.addTool(CrosshairsTool.toolName, {
getReferenceLineColor: this.setCrosshairsToolLineColor getReferenceLineColor: this.setCrosshairsToolLineColor
}); });
} else if (toolGroupId === this.fusionToolGroupId) {
toolGroup.addTool(CrosshairsTool.toolName, {
getReferenceLineColor: this.setCrosshairsToolLineColor,
getReferenceLineSlabThicknessControlsOn: (otherViewportId) => otherViewportId !== 'viewport-fusion-3'
});
} else { } else {
toolGroup.addTool(WindowLevelTool.toolName) toolGroup.addTool(WindowLevelTool.toolName)
} }
@ -1450,26 +1647,20 @@ export default {
toolGroup.addTool(EllipticalROITool.toolName, { toolGroup.addTool(EllipticalROITool.toolName, {
getTextLines: this.getEllipticalROIToolTextLines getTextLines: this.getEllipticalROIToolTextLines
}) })
toolGroup.addTool(FixedRadiusCircleROITool.toolName), { toolGroup.addTool(FixedRadiusCircleROITool.toolName, {
radius: Number.isFinite(this.taskInfo.CircleRadius) ? this.taskInfo.CircleRadius : 6,
getTextLines: this.getCircleROIToolTextLines getTextLines: this.getCircleROIToolTextLines
} })
toolGroup.addTool(AngleTool.toolName, { toolGroup.addTool(AngleTool.toolName, {
getTextLines: this.getAngleToolTextLines getTextLines: this.getAngleToolTextLines
}) })
toolGroup.addTool(CobbAngleTool.toolName, { toolGroup.addTool(CobbAngleTool.toolName, {
getTextLines: this.getCobbAngleToolTextLines getTextLines: this.getCobbAngleToolTextLines
}) })
if (toolGroupId === 'viewport-fusion-3') { if (viewportId === 'viewport-fusion-3') {
toolGroup.addTool(VolumeRotateTool.toolName) toolGroup.addTool(VolumeRotateTool.toolName)
toolGroup.setToolActive(VolumeRotateTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Wheel // mouse wheel
}
]
})
toolGroup.addTool(MIPJumpToClickTool.toolName, { toolGroup.addTool(MIPJumpToClickTool.toolName, {
targetViewportIds: fusionViewportIds.filter((id) => id !== toolGroupId) targetViewportIds: fusionViewportIds.filter((id) => id !== viewportId)
}) })
// Set the initial state of the tools, here we set one tool active on left click. // Set the initial state of the tools, here we set one tool active on left click.
@ -1482,6 +1673,7 @@ export default {
] ]
}) })
} }
toolGroup.setToolConfiguration( toolGroup.setToolConfiguration(
ScaleOverlayTool.toolName, ScaleOverlayTool.toolName,
{ {
@ -1501,7 +1693,6 @@ export default {
toolGroup.setToolPassive(WindowLevelTool.toolName) toolGroup.setToolPassive(WindowLevelTool.toolName)
toolGroup.setToolPassive(WindowLevelRegionTool.toolName) toolGroup.setToolPassive(WindowLevelRegionTool.toolName)
toolGroup.setToolPassive(PlanarRotateTool.toolName) toolGroup.setToolPassive(PlanarRotateTool.toolName)
if (this.readingTaskState < 2) { if (this.readingTaskState < 2) {
toolGroup.setToolPassive(ArrowAnnotateTool.toolName) toolGroup.setToolPassive(ArrowAnnotateTool.toolName)
toolGroup.setToolPassive(RectangleROITool.toolName) toolGroup.setToolPassive(RectangleROITool.toolName)
@ -1528,9 +1719,14 @@ 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(LabelMapEditWithContourTool.toolName) if (this.readingTool === 3) {
toolGroup.setToolEnabled(LabelMapEditWithContourTool.toolName)
toolGroup.setToolEnabled(SegmentBidirectionalTool.toolName);
}
} }
toolGroup.setToolPassive(EraserTool.toolName) toolGroup.setToolPassive(EraserTool.toolName)
}
}) })
eventTarget.addEventListener('cornerstoneimageloadprogress', this.imageLoadProgress) eventTarget.addEventListener('cornerstoneimageloadprogress', this.imageLoadProgress)
// console.log(Events, toolsEvents) // console.log(Events, toolsEvents)
@ -1570,6 +1766,10 @@ export default {
setNetWorkSpeedSizeAll(percentComplete, detail.total, imageId) setNetWorkSpeedSizeAll(percentComplete, detail.total, imageId)
} }
} }
if (this.readingTool === 3) {
getNetWorkSpeed()
setNetWorkSpeedSizeAll(percentComplete, detail.total, imageId)
}
if (percentComplete === 100) { if (percentComplete === 100) {
workSpeedclose() workSpeedclose()
} }
@ -1674,9 +1874,10 @@ export default {
annotationCompletedListener(e) { annotationCompletedListener(e) {
console.log('Completed') console.log('Completed')
if (this.readingTaskState === 2) return
const { annotation } = e.detail const { annotation } = e.detail
if (!annotation) return if (!annotation) return
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
if (this.readingTaskState === 2) 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) {
@ -1699,10 +1900,11 @@ export default {
}, },
annotationModifiedListener(e) { annotationModifiedListener(e) {
console.log('Modified') console.log('Modified')
if (this.readingTaskState === 2) return
const { annotation } = e.detail const { annotation } = e.detail
if (!annotation.highlighted) return
if (!annotation) return if (!annotation) return
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
if (this.readingTaskState === 2) return
if (!annotation.highlighted) 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) {
@ -1742,9 +1944,10 @@ export default {
} }
}, },
async customAnnotationCompletedListener(e) { async customAnnotationCompletedListener(e) {
if (this.readingTaskState === 2) return
const { annotation } = e.detail const { annotation } = e.detail
if (!annotation) return if (!annotation) return
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
if (this.readingTaskState === 2) 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) {
if (annotation.metadata.toolName !== LabelMapEditWithContourTool.toolName) this.setToolsPassive() if (annotation.metadata.toolName !== LabelMapEditWithContourTool.toolName) this.setToolsPassive()
@ -1829,10 +2032,11 @@ export default {
} }
}, },
customAnnotationModifiedListener(e) { customAnnotationModifiedListener(e) {
if (this.readingTaskState === 2) return
const { annotation } = e.detail const { annotation } = e.detail
if (!annotation.highlighted) return
if (!annotation) return if (!annotation) return
if (annotation.metadata.toolName.includes('histogram_')) return this.$refs.histogram.initToolValue(annotation)
if (this.readingTaskState === 2) return
if (!annotation.highlighted) 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) {
if (annotation.metadata.toolName !== LabelMapEditWithContourTool.toolName) this.setToolsPassive() if (annotation.metadata.toolName !== LabelMapEditWithContourTool.toolName) this.setToolsPassive()
@ -1864,8 +2068,14 @@ export default {
const errorMsg = { message: 'annotation Not allowed to operate' } const errorMsg = { message: 'annotation Not allowed to operate' }
throw errorMsg throw errorMsg
} }
if (this.activeTool !== 'Eraser') return false
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) {
if (annotation.metadata.toolName === SegmentBidirectionalTool.toolName) {
this.setToolsPassive()
const errorMsg = { message: 'SegmentBidirectionalTool Not remove' }
throw errorMsg
}
// //
return return
} }
@ -2315,21 +2525,61 @@ export default {
const factor = 10 ** precision const factor = 10 ** precision
return (Math.round(num * factor + 0.0000001) / factor).toFixed(precision) return (Math.round(num * factor + 0.0000001) / factor).toFixed(precision)
}, },
getActiveToolGroupId() {
if (this.isMPR) return this.volumeToolGroupId
if (this.isFusion) return this.fusionToolGroupId
return `${this.viewportKey}-${this.activeViewportIndex}`
},
getCurrentToolGroupIds() {
if (this.isMPR) return [this.volumeToolGroupId]
if (this.isFusion) return [this.fusionToolGroupId]
return [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`, `${this.viewportKey}-3`]
},
setFusionMipJumpEnabled(enabled) {
if (!this.isFusion) return
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
if (!toolGroup || !toolGroup.hasTool(MIPJumpToClickTool.toolName)) return
if (enabled) {
toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Primary }]
})
} else {
toolGroup.setToolDisabled(MIPJumpToClickTool.toolName)
}
},
setFusionMipRotateEnabled(enabled) {
if (!this.isFusion) return
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
if (!toolGroup || !toolGroup.hasTool(VolumeRotateTool.toolName)) return
if (enabled) {
toolGroup.setToolActive(VolumeRotateTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Wheel }]
})
} else {
toolGroup.setToolDisabled(VolumeRotateTool.toolName)
}
},
// //
setToolActive(toolName) { setToolActive(toolName) {
const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}` if (this.histogramVisible) return false
const toolGroupId = this.getActiveToolGroupId()
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
if (!toolGroup) return
if (this.activeTool === toolName) { if (this.activeTool === toolName) {
if (toolName === CrosshairsTool.toolName) { if (toolName === CrosshairsTool.toolName) {
toolGroup.setToolDisabled(this.activeTool) toolGroup.setToolDisabled(this.activeTool)
this.setFusionMipJumpEnabled(true)
this.setFusionMipRotateEnabled(true)
} else { } else {
toolGroup.setToolPassive(this.activeTool) toolGroup.setToolPassive(this.activeTool)
} }
this.activeTool = '' this.activeTool = ''
} else { } else {
if (this.activeTool) { if (this.activeTool) {
if (toolName === CrosshairsTool.toolName) { if (this.activeTool === CrosshairsTool.toolName) {
toolGroup.setToolDisabled(this.activeTool) toolGroup.setToolDisabled(this.activeTool)
this.setFusionMipJumpEnabled(true)
this.setFusionMipRotateEnabled(true)
} else { } else {
toolGroup.setToolPassive(this.activeTool) toolGroup.setToolPassive(this.activeTool)
} }
@ -2337,18 +2587,67 @@ export default {
toolGroup.setToolActive(toolName, { toolGroup.setToolActive(toolName, {
bindings: [{ mouseButton: MouseBindings.Primary }] bindings: [{ mouseButton: MouseBindings.Primary }]
}) })
if (toolName === CrosshairsTool.toolName) {
if (this.isFusion) {
const instance = toolGroup.getToolInstance?.(CrosshairsTool.toolName)
if (instance && !instance.__fusionSameForPatched) {
instance.__fusionSameForPatched = true
const original = instance._checkIfViewportsRenderingSameScene?.bind(instance)
instance._checkIfViewportsRenderingSameScene = (viewport, otherViewport) => {
try {
const a = viewport?.getFrameOfReferenceUID?.()
const b = otherViewport?.getFrameOfReferenceUID?.()
if (a && b && a === b) return true
} catch (e) { }
return original ? original(viewport, otherViewport) : true
}
}
}
this.setFusionMipJumpEnabled(false)
this.setFusionMipRotateEnabled(false)
}
this.activeTool = toolName this.activeTool = toolName
} }
}, },
hoverFusionViewport(index) {
if (!this.isFusion) return
if (this.activeTool === CrosshairsTool.toolName) return
const toolGroup = ToolGroupManager.getToolGroup(this.fusionToolGroupId)
if (!toolGroup) return
const isMip = index === 3
this.setFusionMipJumpEnabled(isMip)
if (isMip) {
if (toolGroup.hasTool(StackScrollTool.toolName)) {
toolGroup.setToolDisabled(StackScrollTool.toolName)
}
if (toolGroup.hasTool(VolumeRotateTool.toolName)) {
toolGroup.setToolActive(VolumeRotateTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Wheel }]
})
}
} else {
if (toolGroup.hasTool(VolumeRotateTool.toolName)) {
toolGroup.setToolDisabled(VolumeRotateTool.toolName)
}
if (toolGroup.hasTool(StackScrollTool.toolName)) {
toolGroup.setToolActive(StackScrollTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Wheel }]
})
}
}
},
// //
setAnnotateToolActive(toolName) { setAnnotateToolActive(toolName) {
// if (this.readingTaskState === 2) return // if (this.readingTaskState === 2) return
if (this.histogramVisible) return false
const toolObj = this.tools.find(i => i.toolName === toolName) const toolObj = this.tools.find(i => i.toolName === toolName)
if (!toolObj || toolObj.isDisabled) return if (!toolObj || toolObj.isDisabled) 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) {
const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}` const toolGroupId = this.getActiveToolGroupId()
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
if (!toolGroup) return
if (this.activeTool === toolName) { if (this.activeTool === toolName) {
if (toolName === CrosshairsTool.toolName) { if (toolName === CrosshairsTool.toolName) {
toolGroup.setToolDisabled(this.activeTool) toolGroup.setToolDisabled(this.activeTool)
@ -2379,8 +2678,9 @@ export default {
if (this.activeTool === toolName) return if (this.activeTool === toolName) 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) {
const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}` const toolGroupId = this.getActiveToolGroupId()
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
if (!toolGroup) return
if (this.activeTool) { if (this.activeTool) {
if (this.activeTool === CrosshairsTool.toolName) { if (this.activeTool === CrosshairsTool.toolName) {
toolGroup.setToolDisabled(this.activeTool) toolGroup.setToolDisabled(this.activeTool)
@ -2399,8 +2699,9 @@ export default {
if (this.activeTool && this.toolNames.includes(this.activeTool)) { if (this.activeTool && this.toolNames.includes(this.activeTool)) {
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) {
const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}` const toolGroupId = this.getActiveToolGroupId()
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
if (!toolGroup) return
if (this.activeTool === CrosshairsTool.toolName) { if (this.activeTool === CrosshairsTool.toolName) {
toolGroup.setToolDisabled(this.activeTool) toolGroup.setToolDisabled(this.activeTool)
} else { } else {
@ -2412,11 +2713,13 @@ export default {
}, },
setMoreToolActive(toolName) { setMoreToolActive(toolName) {
// if (this.readingTaskState === 2) return // if (this.readingTaskState === 2) return
if (this.histogramVisible) return false
this.setToolsPassive() this.setToolsPassive()
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) {
const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}` const toolGroupId = this.getActiveToolGroupId()
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
if (!toolGroup) return
toolGroup.setToolActive(toolName, { toolGroup.setToolActive(toolName, {
bindings: [{ mouseButton: MouseBindings.Primary }] bindings: [{ mouseButton: MouseBindings.Primary }]
}) })
@ -2425,13 +2728,10 @@ export default {
}, },
setToolsPassive() { setToolsPassive() {
if (!this.activeTool) return if (!this.activeTool) return
let toolGroupIds = [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`, `${this.viewportKey}-3`] const toolGroupIds = this.getCurrentToolGroupIds()
if (this.isMPR) {
// toolGroupIds = [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`]
toolGroupIds = [this.volumeToolGroupId]
}
toolGroupIds.forEach(toolGroupId => { toolGroupIds.forEach(toolGroupId => {
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
if (!toolGroup) return
if (this.activeTool === CrosshairsTool.toolName) { if (this.activeTool === CrosshairsTool.toolName) {
toolGroup.setToolDisabled(this.activeTool) toolGroup.setToolDisabled(this.activeTool)
} else { } else {
@ -2442,13 +2742,10 @@ export default {
}, },
setToolEnabled() { setToolEnabled() {
if (!this.activeTool) return if (!this.activeTool) return
let toolGroupIds = [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`, `${this.viewportKey}-3`] const toolGroupIds = this.getCurrentToolGroupIds()
if (this.isMPR) {
// toolGroupIds = [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`]
toolGroupIds = [this.volumeToolGroupId]
}
toolGroupIds.forEach(toolGroupId => { toolGroupIds.forEach(toolGroupId => {
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
if (!toolGroup) return
toolGroup.setToolEnabled(this.activeTool) toolGroup.setToolEnabled(this.activeTool)
}) })
this.activeTool = '' this.activeTool = ''
@ -2531,20 +2828,28 @@ export default {
const viewportId = `${this.viewportKey}-${this.activeViewportIndex}` const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
const viewport = renderingEngine.getViewport(viewportId) const viewport = renderingEngine.getViewport(viewportId)
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resetOrientationMarkers() this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resetOrientationMarkers()
let index = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series.SliceIndex
if (this.readingTool !== 3) {
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true }) viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
}
viewport.resetProperties() viewport.resetProperties()
if (this.isMPR) { if (this.isMPR) {
let volume = cache.getVolume(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].volumeId) let volume = cache.getVolume(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].volumeId)
const voi = metaData.get('voiLutModule', volume._imageIds[Math.ceil((volume._imageIds.length - 1) / 2)]) const voi = metaData.get('voiLutModule', volume._imageIds[Math.ceil((volume._imageIds.length - 1) / 2)])
const lower = voi.windowCenter[0] - voi.windowWidth[0] / 2 const lower = voi.windowCenter[0] - voi.windowWidth[0] / 2
const upper = voi.windowCenter[0] + voi.windowWidth[0] / 2 - 1 const upper = voi.windowCenter[0] + voi.windowWidth[0] / 2 - 1
console.log(lower, upper)
viewport.setProperties({ voiRange: { upper: upper, lower: lower } }) viewport.setProperties({ voiRange: { upper: upper, lower: lower } })
} }
if (this.readingTool === 3 && this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series.Modality === 'PT') {
viewport.setProperties({ voiRange: { upper: 5, lower: 0 } })
}
viewport.render() viewport.render()
renderingEngine.render() renderingEngine.render()
if (this.readingTool === 3) { if (this.readingTool === 3) {
DicomEvent.$emit('isloaded', { isChange: false }) DicomEvent.$emit('isloaded', { isChange: false, viewportId })
}
if (this.readingTool === 3 || this.isMPR) {
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index)
} }
}, },
// //
@ -2553,6 +2858,7 @@ export default {
this.fullScreenIndex = null this.fullScreenIndex = null
this.layout = v this.layout = v
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
let index = series.SliceIndex
const seriesArr = [] const seriesArr = []
if (v === 1) { if (v === 1) {
this.rows = 1 this.rows = 1
@ -2565,6 +2871,7 @@ export default {
this.rows = 1 this.rows = 1
this.cols = 2 this.cols = 2
this.activeViewportIndex = 1 this.activeViewportIndex = 1
series.curIndex = index
if (typeof series === 'object') { if (typeof series === 'object') {
seriesArr.push(series) seriesArr.push(series)
seriesArr.push(series) seriesArr.push(series)
@ -2614,6 +2921,7 @@ export default {
} else if (v === 4) { } else if (v === 4) {
this.rows = 2 this.rows = 2
this.cols = 2 this.cols = 2
series.curIndex = index
if (typeof series === 'object') { if (typeof series === 'object') {
seriesArr.push(series) seriesArr.push(series)
seriesArr.push(series) seriesArr.push(series)
@ -2676,19 +2984,22 @@ export default {
const renderingEngine = getRenderingEngine(renderingEngineId) const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(`${this.viewportKey}-${this.activeViewportIndex}`) const viewport = renderingEngine.getViewport(`${this.viewportKey}-${this.activeViewportIndex}`)
const { invert } = viewport.getProperties() const { invert } = viewport.getProperties()
if (this.isFusion) { if (this.isFusion || this.readingTool === 3) {
viewport.setProperties({ invert: !invert }, this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].volumeId) viewport.setProperties({ invert: !invert }, this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].volumeId)
} } else {
viewport.setProperties({ invert: !invert }) viewport.setProperties({ invert: !invert })
}
viewport.render() viewport.render()
}, },
// //
scrollPage(type) { scrollPage(type) {
// if (this.histogramVisible) return false
this.clipPlaying = false this.clipPlaying = false
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].scrollPage(type) this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].scrollPage(type)
}, },
// //
toggleClipPlay(isPlay) { toggleClipPlay(isPlay) {
// if (this.histogramVisible) return false
this.clipPlaying = !this.clipPlaying this.clipPlaying = !this.clipPlaying
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].toggleClipPlay(isPlay, this.fps) this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].toggleClipPlay(isPlay, this.fps)
}, },
@ -2821,20 +3132,26 @@ export default {
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(forceFitToWindow) this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(forceFitToWindow)
}, },
// //
resetRenderingEngine() { resetRenderingEngine(viewportId = null, i) {
if (this.timer) { if (this.timer[viewportId]) {
clearInterval(this.timer) clearInterval(this.timer[viewportId])
this.timer = null this.timer[viewportId] = null
} }
let index = null
this.timer = setTimeout(() => {
index = index || index === 0 ? index : this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series.SliceIndex
const renderingEngine = getRenderingEngine(renderingEngineId) const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(viewportId)
if (!viewport) return false
if (viewport.volumeIds.size <= 0) return false
let index = null
this.timer[viewportId] = setTimeout(() => {
index = i || i === 0 ? i : this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].series.SliceIndex
renderingEngine.resize(true, false) renderingEngine.resize(true, false)
renderingEngine.render() renderingEngine.render()
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index) this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index)
clearTimeout(this.timer) clearTimeout(this.timer[viewportId])
this.timer = null this.timer[viewportId] = null
if (this.readingTool === 3) {
DicomEvent.$emit('isloaded', { isChange: false, viewportId })
}
}, 100) }, 100)
}, },
setDelay(time) { setDelay(time) {
@ -2854,12 +3171,12 @@ export default {
if (this.readingTool === 3 || this.isMPR) { if (this.readingTool === 3 || this.isMPR) {
// this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series) // this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series)
this.$nextTick(() => { this.$nextTick(() => {
this.resetRenderingEngine() // this.resetRenderingEngine(`${this.viewportKey}-${index}`)
this.isDelay = true this.isDelay = true
this.setDelay(2000) this.setDelay(2000)
if (this.readingTool === 3) { // if (this.readingTool === 3) {
DicomEvent.$emit('isloaded', { isChange: false }) // DicomEvent.$emit('isloaded', { isChange: false })
} // }
}) })
} }
@ -2958,6 +3275,7 @@ export default {
const confirm = await this.$confirm(this.$t('trials:reading:confirm:changeStack')) const confirm = await this.$confirm(this.$t('trials:reading:confirm:changeStack'))
if (!confirm) return false if (!confirm) return false
} }
if (this.histogramVisible) this.$refs.histogram.close()
this.isFusion = false this.isFusion = false
this.setToolsPassive() this.setToolsPassive()
this.rows = 1 this.rows = 1
@ -2966,8 +3284,10 @@ export default {
this.fullScreenIndex = null this.fullScreenIndex = null
this.isMPR = false this.isMPR = false
obj.isChange = false obj.isChange = false
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(obj)
return this.$nextTick(() => { return this.$nextTick(() => {
DicomEvent.$emit('activeSeries', obj)
DicomEvent.$emit('changeMPR')
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(obj)
const renderingEngine = getRenderingEngine(renderingEngineId) const renderingEngine = getRenderingEngine(renderingEngineId)
renderingEngine.resize(true, false) renderingEngine.resize(true, false)
renderingEngine.render() renderingEngine.render()
@ -2977,6 +3297,7 @@ export default {
}) })
} }
if (this.histogramVisible) this.$refs.histogram.close()
if (!obj.IsDicom) { if (!obj.IsDicom) {
return this.previewNoneDicoms(obj) return this.previewNoneDicoms(obj)
} }
@ -3015,7 +3336,14 @@ export default {
this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex) this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
} }
} }
if (this.readingTool === 3) {
this.$nextTick(() => {
DicomEvent.$emit('SegmentationLoading', `${this.viewportKey}-${this.activeViewportIndex}`)
})
}
if (this.activeTool !== CrosshairsTool.toolName) {
this.setToolsPassive() this.setToolsPassive()
}
}, },
getRelatedSeries(visitTaskInfo, baselineSeries) { getRelatedSeries(visitTaskInfo, baselineSeries) {
let obj = {} let obj = {}
@ -3139,13 +3467,15 @@ export default {
if (i === -1) return if (i === -1) return
const studyList = this.visitTaskList[i].StudyList const studyList = this.visitTaskList[i].StudyList
let series = null let series = null
let curSeriesId = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series.Id
if (obj.segment) { if (obj.segment) {
let study = studyList.find(item => item.StudyId === obj.segmentGroup.StudyId) let study = studyList.find(item => item.StudyId === obj.segmentGroup.StudyId)
series = study.SeriesList.find(item => item.Id === obj.segmentGroup.SeriesId) let Series = study.SeriesList.find(item => item.Id === obj.segmentGroup.SeriesId)
series.SliceIndex = 0 Series.SliceIndex = 0
series.segment = obj.segment series = Object.assign(Series, { segment: obj.segment })
} else { } else {
series = this.getMarkedSeries(studyList, obj.annotation, true) series = this.getMarkedSeries(studyList, obj.annotation, true)
delete series.segment
} }
if (series) { if (series) {
@ -3188,7 +3518,7 @@ export default {
} }
} }
} }
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, obj.segment ? false : true) this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, series.segment || curSeriesId !== series.Id ? false : true)
this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex) this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
} }
}, },
@ -3380,8 +3710,9 @@ export default {
this.setToolsPassive() this.setToolsPassive()
} }
const toolGroupId = this.isMPR ? this.volumeToolGroupId : `${this.viewportKey}-${this.activeViewportIndex}` const toolGroupId = this.getActiveToolGroupId()
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
if (!toolGroup) return
toolGroup.setToolActive(toolName, { toolGroup.setToolActive(toolName, {
bindings: [{ mouseButton: MouseBindings.Primary }] bindings: [{ mouseButton: MouseBindings.Primary }]
}) })
@ -3656,6 +3987,8 @@ export default {
if (series.ImageIds.length <= 5) return this.$confirm(this.$t('trials:reading:confirm:smallNumberOfimage'), this.$t('system:menu:confirm:title:warning'), { if (series.ImageIds.length <= 5) return this.$confirm(this.$t('trials:reading:confirm:smallNumberOfimage'), this.$t('system:menu:confirm:title:warning'), {
type: 'warning' type: 'warning'
}) })
series.curIndex = series.SliceIndex
DicomEvent.$emit('changeMPR')
if (series.ImageIds.length > 500) { if (series.ImageIds.length > 500) {
let res = await this.getSystemInfo() let res = await this.getSystemInfo()
if (!res) return false if (!res) return false
@ -3740,6 +4073,7 @@ export default {
this.$refs[`viewport-fusion-1`][0].setSeriesInfo(ptData, false, { colorMap: false }) this.$refs[`viewport-fusion-1`][0].setSeriesInfo(ptData, false, { colorMap: false })
this.$refs[`viewport-fusion-2`][0].setSeriesInfo(fusionData, false, { isFusion: true, colorMap: true }) this.$refs[`viewport-fusion-2`][0].setSeriesInfo(fusionData, false, { isFusion: true, colorMap: true })
this.$refs[`viewport-fusion-3`][0].setSeriesInfo(ptData, false, { isMip: true, colorMap: false }) this.$refs[`viewport-fusion-3`][0].setSeriesInfo(ptData, false, { isMip: true, colorMap: false })
await this.initFusionHiddenSagViewport(pt)
// this.resetAnnotation = false // this.resetAnnotation = false
this.$nextTick(() => { this.$nextTick(() => {
this.$refs[`colorMap`].init() this.$refs[`colorMap`].init()
@ -3770,6 +4104,18 @@ export default {
} }
return false return false
}, },
async initFusionHiddenSagViewport(pt) {
const ptVolumeId = pt?.SeriesInstanceUid
if (!ptVolumeId || !cache.getVolume(ptVolumeId)) return
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const sagViewport = renderingEngine?.getViewport?.('viewport-fusion-hidden-sag')
if (!sagViewport) return
await sagViewport.setVolumes([{ volumeId: ptVolumeId }])
const midIndex = Math.max(0, Math.floor((pt.ImageIds?.length || 1) / 2))
await csUtils.jumpToSlice(sagViewport.element, { imageIndex: midIndex })
sagViewport.render()
},
async getVolume(serie, isFusion = false) { async getVolume(serie, isFusion = false) {
return new Promise(async res => { return new Promise(async res => {
let volumeId = `${isFusion ? 'fusion_' : ''}` + serie.SeriesInstanceUid; let volumeId = `${isFusion ? 'fusion_' : ''}` + serie.SeriesInstanceUid;
@ -3954,8 +4300,14 @@ export default {
this.saveCustomAnnotationTimer = null this.saveCustomAnnotationTimer = null
} }
if (this.timer) { if (this.timer) {
clearInterval(this.timer) Object.keys(this.timer).forEach(key => {
this.timer = null if (this.timer[key]) {
clearInterval(this.timer[key])
clearTimeout(this.timer[key])
this.timer[key] = null
}
})
this.timer = {}
} }
if (this.FullTimerOut) { if (this.FullTimerOut) {
clearTimeout(this.FullTimerOut) clearTimeout(this.FullTimerOut)
@ -4255,6 +4607,22 @@ export default {
position: relative; position: relative;
} }
.fusion-hidden-viewports {
position: absolute;
left: -100000px;
top: -100000px;
width: 512px;
height: 512px;
overflow: hidden;
opacity: 0;
pointer-events: none;
}
.fusion-hidden-viewport {
width: 512px;
height: 512px;
}
.viewports-box { .viewports-box {
display: grid; display: grid;
position: absolute; position: absolute;

View File

@ -2,21 +2,24 @@
<el-form ref="segmentForm" :model="form" label-width="120px" label-position="left" :rules="rules"> <el-form ref="segmentForm" :model="form" label-width="120px" label-position="left" :rules="rules">
<!-- 检查名称 --> <!-- 检查名称 -->
<el-form-item :label="$t('segment:form:label:studyName')" prop="taskBlindName"> <el-form-item :label="$t('segment:form:label:studyName')" prop="taskBlindName">
<el-select v-model="form.studyId" clearable @change="(e) => handleChange(e, 'study')"> <el-select v-model="form.studyId" clearable @change="(e) => handleChange(e, 'study')"
@clear="(e) => handleClear(e, 'study')">
<el-option v-for="item in studyList" :key="item.StudyId" :label="item.StudyCode" <el-option v-for="item in studyList" :key="item.StudyId" :label="item.StudyCode"
:value="item.StudyId" /> :value="item.StudyId" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 序列名称 --> <!-- 序列名称 -->
<el-form-item :label="$t('segment:form:label:seriesName')" prop="taskBlindName"> <el-form-item :label="$t('segment:form:label:seriesName')" prop="taskBlindName">
<el-select v-model="form.seriesId" clearable @change="(e) => handleChange(e, 'series')"> <el-select v-model="form.seriesId" clearable @change="(e) => handleChange(e, 'series')"
@clear="(e) => handleClear(e, 'series')">
<el-option v-for="item in seriesList" :key="item.Id" <el-option v-for="item in seriesList" :key="item.Id"
:label="`#${item.SeriesNumber}/${item.Modality}/${item.Description}`" :value="item.Id" /> :label="`#${item.SeriesNumber}/${item.Modality}/${item.Description}`" :value="item.Id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 分割组名称 --> <!-- 分割组名称 -->
<el-form-item :label="$t('segment:form:label:segmentGroupName')" prop="segmentGroupId"> <el-form-item :label="$t('segment:form:label:segmentGroupName')" prop="segmentGroupId">
<el-select v-model="form.segmentGroupId" clearable @change="(e) => handleChange(e, 'segmentGroup')"> <el-select v-model="form.segmentGroupId" clearable @change="(e) => handleChange(e, 'segmentGroup')"
@clear="(e) => handleClear(e, 'segmentGroup')">
<el-option v-for="item in segmentGroupList" :key="item.Id" :label="item.SegmentationName" <el-option v-for="item in segmentGroupList" :key="item.Id" :label="item.SegmentationName"
:value="item.Id" /> :value="item.Id" />
</el-select> </el-select>
@ -106,11 +109,22 @@ export default {
}) })
this.studyList = studyList this.studyList = studyList
if (this.visitInfo.operateStateEnum === 21) { if (this.visitInfo.operateStateEnum === 21) {
let find = studyList.some(item => item.StudyId === this.series.StudyId)
if (find) {
this.form.studyId = this.series.StudyId this.form.studyId = this.series.StudyId
this.handleChange(null, 'study') this.handleChange(null, 'study')
if (find.SeriesArr && find.SeriesArr.length > 0) {
let findSeries = find.SeriesArr.some(item => item.Id === this.form.seriesId)
if (findSeries) {
this.form.seriesId = this.series.Id this.form.seriesId = this.series.Id
this.handleChange(null, 'series') this.handleChange(null, 'series')
} }
}
}
}
if (this.visitInfo.operateStateEnum === 22) { if (this.visitInfo.operateStateEnum === 22) {
let o = {} let o = {}
if (this.isTableQuestion) { if (this.isTableQuestion) {
@ -132,6 +146,7 @@ export default {
}, },
async handleChange(e, key) { async handleChange(e, key) {
if (key === 'study') { if (key === 'study') {
console.log(this.studyList, 'this.studyList')
this.seriesList = this.studyList.find(item => item.StudyId === this.form.studyId).SeriesArr this.seriesList = this.studyList.find(item => item.StudyId === this.form.studyId).SeriesArr
} }
if (key === 'series') { if (key === 'series') {
@ -142,6 +157,20 @@ export default {
this.segmentList = list.filter(item => item.SegmentJson) this.segmentList = list.filter(item => item.SegmentJson)
} }
}, },
handleClear(e, key) {
if (key === 'study') {
this.form.seriesId = null
this.form.segmentGroupId = null
this.form.segmentId = null
}
if (key === 'series') {
this.form.segmentGroupId = null
this.form.segmentId = null
}
if (key === 'segmentGroup') {
this.form.segmentId = null
}
},
handleCancel() { handleCancel() {
this.$emit("update:visible", false) this.$emit("update:visible", false)
}, },

View File

@ -8,25 +8,26 @@
<div class="tool-frame"> <div class="tool-frame">
<div :title="$t('trials:Segmentations:tools:contour')" <div :title="$t('trials:Segmentations:tools:contour')"
:class="['tool-item', activeTool === 'LabelMapEditWithContour' && segmentList.length > 0 ? 'tool-item-active' : '']" :class="['tool-item', activeTool === 'LabelMapEditWithContour' && segmentList.length > 0 ? 'tool-item-active' : '']"
:style="{ cursor: segmentList.length <= 0 || (curSegment && curSegment.lock) ? 'not-allowed' : 'pointer' }" :style="{ cursor: segmentList.length <= 0 || (curSegment && curSegment.lock) || ['viewport-MPR-1', 'viewport-MPR-2'].includes(`${viewportKey}-${activeViewportIndex}`) ? 'not-allowed' : 'pointer' }"
@click.prevent="setToolActive('LabelMapEditWithContour')"> @click.prevent="setToolActive('LabelMapEditWithContour')">
<svg-icon icon-class="contour" class="svg-icon" /> <svg-icon icon-class="contour" class="svg-icon" />
</div> </div>
<div :title="$t('trials:Segmentations:tools:thresholecircle')" <div :title="$t('trials:Segmentations:tools:thresholecircle')"
:class="['tool-item', ThresholdTools.includes(activeTool) && segmentList.length > 0 ? 'tool-item-active' : '']" :class="['tool-item', ThresholdTools.includes(activeTool) && segmentList.length > 0 ? 'tool-item-active' : '']"
:style="{ cursor: segmentList.length <= 0 || (curSegment && curSegment.lock) ? 'not-allowed' : 'pointer' }" :style="{ cursor: segmentList.length <= 0 || (curSegment && curSegment.lock) || ['viewport-MPR-1', 'viewport-MPR-2'].includes(`${viewportKey}-${activeViewportIndex}`) ? 'not-allowed' : 'pointer' }"
@click.prevent="initThreshold"> @click.prevent="initThreshold">
<svg-icon icon-class="thresholecircle" class="svg-icon" /> <svg-icon icon-class="thresholecircle" class="svg-icon" />
</div> </div>
<div :title="$t('trials:Segmentations:tools:circularbrush')" <div :title="$t('trials:Segmentations:tools:circularbrush')"
:class="['tool-item', activeTool === 'CircularBrush' && segmentList.length > 0 ? 'tool-item-active' : '']" :class="['tool-item', activeTool === 'CircularBrush' && segmentList.length > 0 ? 'tool-item-active' : '']"
:style="{ cursor: segmentList.length <= 0 || (curSegment && curSegment.lock) ? 'not-allowed' : 'pointer' }" :style="{ cursor: segmentList.length <= 0 || (curSegment && curSegment.lock) || ['viewport-MPR-1', 'viewport-MPR-2'].includes(`${viewportKey}-${activeViewportIndex}`) ? 'not-allowed' : 'pointer' }"
@click.prevent="setToolActive('CircularBrush')"> @click.prevent="setToolActive('CircularBrush')">
<svg-icon icon-class="circularbrush" class="svg-icon" /> <svg-icon icon-class="circularbrush" class="svg-icon" />
</div> </div>
<div :class="['tool-item', activeTool === 'CircularEraser' && segmentList.length > 0 ? 'tool-item-active' : '']" <div :class="['tool-item', activeTool === 'CircularEraser' && segmentList.length > 0 ? 'tool-item-active' : '']"
:style="{ cursor: segmentList.length <= 0 || (curSegment && curSegment.lock) ? 'not-allowed' : 'pointer' }" :style="{ cursor: segmentList.length <= 0 || (curSegment && curSegment.lock) || ['viewport-MPR-1', 'viewport-MPR-2'].includes(`${viewportKey}-${activeViewportIndex}`) ? 'not-allowed' : 'pointer' }"
:title="$t('trials:Segmentations:tools:Eraser')" @click.prevent="setToolActive('CircularEraser')"> :title="$t('trials:Segmentations:tools:Eraser')"
@click.prevent="setToolActive('CircularEraser')">
<svg-icon icon-class="clear" class="svg-icon" /> <svg-icon icon-class="clear" class="svg-icon" />
</div> </div>
<!-- <div :class="['tool-item']"> <!-- <div :class="['tool-item']">
@ -79,7 +80,8 @@
@click.stop="changeShowSegmentConfig" /> @click.stop="changeShowSegmentConfig" />
</div> </div>
</template> </template>
<div class="addSegmentBox viewHover" @click.stop="addSegment" v-if="segmentList.length <= 0"> <div class="addSegmentBox viewHover" @click.stop="addSegment"
v-if="segmentList.length <= 0 && readingTaskState < 2">
<span><i class="el-icon-plus"></i> <span><i class="el-icon-plus"></i>
{{ $t('trials:reading:Segmentations:button:addSegmention') }} {{ $t('trials:reading:Segmentations:button:addSegmention') }}
</span> </span>
@ -123,16 +125,11 @@
$t('trials:reading:Segmentations:title:InactiveSegmentationsShow') $t('trials:reading:Segmentations:title:InactiveSegmentationsShow')
}}</span> }}</span>
</div> </div>
<!-- <div class="SegmentConfig" v-if="SegmentConfig.InactiveSegmentations.show">
<span>{{ $t('trials:reading:Segmentations:title:Opacity') }}</span>
<el-slider v-model="SegmentConfig.InactiveSegmentations.fillAlpha" show-input :step="0.1"
:max="1" input-size="mini" :show-input-controls="false" />
</div> -->
</div> </div>
<template v-if="segmentList.length > 0"> <template v-if="segmentList.length > 0">
<div class="SegmentGroupBox"> <div class="SegmentGroupBox">
<div style="display: flex;align-items: center;"> <div style="display: flex;align-items: center;">
<el-popover placement="left" width="40" trigger="click"> <el-popover placement="left" width="40" trigger="click" v-if="readingTaskState < 2">
<div class="SegmentGroupBtnBox"> <div class="SegmentGroupBtnBox">
<div class="SegmentGroupBtn" @click.stop="addSegmentGroup"> <div class="SegmentGroupBtn" @click.stop="addSegmentGroup">
{{ $t('trials:reading:Segmentations:button:addSegmentGroup') }} {{ $t('trials:reading:Segmentations:button:addSegmentGroup') }}
@ -149,13 +146,14 @@
</div> </div>
<i slot="reference" class="el-icon-more" style="cursor: pointer;color:#fff" /> <i slot="reference" class="el-icon-more" style="cursor: pointer;color:#fff" />
</el-popover> </el-popover>
<el-select v-model="segmentationId" placeholder="" @change="selectSegmentGroup()"> <el-select v-model="segmentationId" placeholder="" @change="selectSegmentGroup()"
:disabled="saveLoading">
<el-option v-for="item in segmentList" :key="`${item.segmentationId}`" <el-option v-for="item in segmentList" :key="`${item.segmentationId}`"
:label="item.name" :value="item.segmentationId"> :label="item.name" :value="item.segmentationId">
</el-option> </el-option>
</el-select> </el-select>
</div> </div>
<div style="display: flex;align-items: center;"> <div style="display: flex;align-items: center;" v-if="readingTaskState < 2">
<i class="el-icon-warning-outline" style="color:red;margin-right: 5px;" <i class="el-icon-warning-outline" style="color:red;margin-right: 5px;"
:title="$t('trials:reading:Segmentations:tip:segmentationIsNotSave')" :title="$t('trials:reading:Segmentations:tip:segmentationIsNotSave')"
v-if="!curSegmentGroup.isSaved"></i> v-if="!curSegmentGroup.isSaved"></i>
@ -166,7 +164,8 @@
</div> </div>
</div> </div>
<div class="addSegmentBox" @click.stop="addSegment" <div class="addSegmentBox" @click.stop="addSegment"
style="display: flex;align-items: center;justify-content: space-between;"> style="display: flex;align-items: center;justify-content: space-between;"
v-if="readingTaskState < 2">
<span><i class="el-icon-plus"></i> <span><i class="el-icon-plus"></i>
{{ $t('trials:reading:Segmentations:button:addSegment') }} {{ $t('trials:reading:Segmentations:button:addSegment') }}
</span> </span>
@ -219,7 +218,7 @@
<i class="el-icon-lock" v-if="item.lock" @click.stop="lockSegment(item, false)"></i> <i class="el-icon-lock" v-if="item.lock" @click.stop="lockSegment(item, false)"></i>
<el-popover placement="bottom" width="40" trigger="click" class="docShow" <el-popover placement="bottom" width="40" trigger="click" class="docShow"
:value="popoverId === `popover-${item.segmentationId}_${item.segmentIndex}`" :value="popoverId === `popover-${item.segmentationId}_${item.segmentIndex}`"
@show="handleClickPopover(item)"> @show="handleClickPopover(item)" v-if="readingTaskState < 2">
<div class="SegmentGroupBtnBox"> <div class="SegmentGroupBtnBox">
<div class="SegmentGroupBtn" @click.stop="rename('segment', item)"> <div class="SegmentGroupBtn" @click.stop="rename('segment', item)">
{{ $t('trials:reading:Segmentations:button:renameSegmentGroup') }} {{ $t('trials:reading:Segmentations:button:renameSegmentGroup') }}
@ -244,7 +243,7 @@
</template> </template>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<div class="saveBtnBox"> <div class="saveBtnBox" v-if="readingTaskState < 2">
<el-button type="success" size="small" :disabled="saveLoading" @click="saveSegmentGroup()"> <el-button type="success" size="small" :disabled="saveLoading" @click="saveSegmentGroup()">
{{ $t("trials:reading:Segmentations:button:saveAll") }} {{ $t("trials:reading:Segmentations:button:saveAll") }}
</el-button> </el-button>
@ -260,6 +259,8 @@ import * as cornerstoneAdapters from "@cornerstonejs/adapters";
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader' import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
import { getCustomizeStandardsSegmentDicomTools } from './toolConfig' import { getCustomizeStandardsSegmentDicomTools } from './toolConfig'
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
cornerstoneTools.init({ addons: { polySeg } })
const { const {
ToolGroupManager, ToolGroupManager,
Enums: csToolsEnums, Enums: csToolsEnums,
@ -270,6 +271,7 @@ const {
CrosshairsTool, CrosshairsTool,
utilities: CStUtils, utilities: CStUtils,
} = cornerstoneTools; } = cornerstoneTools;
const { MouseBindings, Events: toolsEvents } = csToolsEnums const { MouseBindings, Events: toolsEvents } = csToolsEnums
const { segmentation: segmentationUtils } = CStUtils; const { segmentation: segmentationUtils } = CStUtils;
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone; const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
@ -304,12 +306,38 @@ export default {
return {} return {}
} }
}, },
SegmentConfig: {
type: Object,
default: () => {
return {}
}
},
actionConfiguration: { actionConfiguration: {
type: Object, type: Object,
default: () => { default: () => {
return {} return {}
} }
}, },
curSegSeries: {
type: Object,
default: () => {
return {}
}
},
trialCriterion: {
type: Object,
default: () => {
return {}
}
},
segId: {
type: String,
default: ''
},
segIndex: {
type: Number,
default: 0
},
renderingEngineId: { renderingEngineId: {
type: String, type: String,
required: true required: true
@ -321,6 +349,10 @@ export default {
globalLoading: { globalLoading: {
type: Boolean, type: Boolean,
default: false default: false
},
histogramVisible: {
type: Boolean,
default: false
} }
}, },
data() { data() {
@ -338,16 +370,6 @@ export default {
ThresholdTools: ['ThresholdCircle', 'ThresholdSphere'], ThresholdTools: ['ThresholdCircle', 'ThresholdSphere'],
thresholdType: null, thresholdType: null,
showSegmentConfig: false, showSegmentConfig: false,
SegmentConfig: {
renderOutline: true,
renderFill: true,
fillAlpha: 0.5,
outlineWidth: 1,
InactiveSegmentations: {
show: true,
fillAlpha: 0.3,
}
},
segmentList: [], segmentList: [],
segmentationId: "", segmentationId: "",
segmentIndex: null, segmentIndex: null,
@ -363,7 +385,7 @@ export default {
'#ff994d', '#ff994d',
'#fb628b', '#fb628b',
], ],
viewprotIds: ['viewport-0', 'viewport-1', 'viewport-2', 'viewport-3', 'viewport-MPR-0', 'viewport-MPR-1', 'viewport-MPR-2'], // viewportIds: [], //
statsKey: [], statsKey: [],
drawing: false, // drawing: false, //
// isDel: false, // isDel: false,
@ -383,14 +405,30 @@ export default {
this.segmentationModifiedCallback this.segmentationModifiedCallback
); );
DicomEvent.$on('activeSeries', (series) => { DicomEvent.$on('activeSeries', (series) => {
console.log(series, 'series')
let { TaskInfo = {}, Id } = series
if (this.isMPR) return false
if (Id === this.series.Id && TaskInfo.VisitTaskId === this.visitInfo.VisitTaskId) return false
this.series = series this.series = series
this.$emit("update:curSegSeries", Object.assign(series, {}))
this.getSegmentationList()
}) })
DicomEvent.$on('isloaded', (data) => { DicomEvent.$on('isloaded', (data) => {
if (this.isloaded) return false let { segment, isChange = true, viewportId, series } = data
this.isloaded = true DicomEvent.$emit('renderSegmentation', viewportId)
let { segment, isChange = true } = data })
this.delAllSegment(isChange) DicomEvent.$on('SegmentationLoading', (viewportId) => {
this.getSegmentationList(segment) if (viewportId !== `${this.viewportKey}-${this.activeViewportIndex}`) return false
this.loading = false
})
DicomEvent.$on('changeMPR', () => {
if (this.loading) return false
// if (viewportId !== `${this.viewportKey}-${this.activeViewportIndex}`) return false
if (this.segmentList && this.segmentList.length > 0) {
this.segmentationId = this.segmentList[0].segmentationId
this.segmentIndex = this.segmentList[0] ? this.segmentList[0].segments[0].segmentIndex : null
}
}) })
const digitPlaces = Number(localStorage.getItem('digitPlaces')) const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
@ -409,12 +447,15 @@ export default {
s = this.curSegmentGroup.segments.find(item => item.segmentIndex === this.segmentIndex) s = this.curSegmentGroup.segments.find(item => item.segmentIndex === this.segmentIndex)
} }
return s return s
},
readingTaskState() {
return this.series.TaskInfo ? this.series.TaskInfo.ReadingTaskState : 0
} }
}, },
watch: { watch: {
SegmentConfig: { SegmentConfig: {
handler() { handler() {
this.readingSegmentByConfig() // this.readingSegmentByConfig()
}, },
deep: true deep: true
}, },
@ -429,9 +470,23 @@ export default {
this.setBrushThreshold() this.setBrushThreshold()
}, },
deep: true deep: true
},
segmentIndex() {
this.$emit('update:segIndex', this.segmentIndex)
},
segmentationId() {
this.$emit('update:segId', this.segmentationId)
} }
}, },
methods: { methods: {
showSurface(item) {
this.$emit("showSurface", {
segmentationId: item.segmentationId,
segmentIndex: item.segmentIndex,
volumeId: this.series.SeriesInstanceUid,
segmentations: this.curSegmentGroup
})
},
handleClickPopover(item) { handleClickPopover(item) {
this.popoverId = `popover-${item.segmentationId}_${item.segmentIndex}` this.popoverId = `popover-${item.segmentationId}_${item.segmentIndex}`
}, },
@ -499,7 +554,6 @@ export default {
segmentationId: list[0].segmentationId, segmentationId: list[0].segmentationId,
segmentIndices: list.map(item => item.segmentIndex), segmentIndices: list.map(item => item.segmentIndex),
}); });
console.log(bidirectionalData, list[0].segmentationId, 'bidirectionalData')
if (bidirectionalData.length <= 0) { if (bidirectionalData.length <= 0) {
list.forEach(item => { list.forEach(item => {
let annotations = annotation.state.getAllAnnotations().filter(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex); let annotations = annotation.state.getAllAnnotations().filter(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex);
@ -558,8 +612,11 @@ export default {
}, },
setToolActive(toolName) { setToolActive(toolName) {
// if (!this.series.TaskInfo || this.series.TaskInfo.VisitTaskId !== this.visitInfo.VisitTaskId) return false
if (this.segmentList.length <= 0) return false if (this.segmentList.length <= 0) return false
if (this.curSegment.lock) return false if (this.curSegment.lock) return false
if (this.histogramVisible && !this.ThresholdTools.includes(toolName)) return false
if (['viewport-MPR-1', 'viewport-MPR-2'].includes(`${this.viewportKey}-${this.activeViewportIndex}`)) return false
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)
if (this.activeTool === toolName) { if (this.activeTool === toolName) {
@ -596,71 +653,33 @@ export default {
viewBidirectional(arr, view) { viewBidirectional(arr, view) {
for (let j = 0; j < arr.length; j++) { for (let j = 0; j < arr.length; j++) {
let item = arr[j] let item = arr[j]
let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
item.bidirectionalView = view item.bidirectionalView = view
if (!bidirectional) continue // let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view) // item.bidirectionalView = view
// if (!bidirectional) continue
// annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
} }
this.resetViewport() DicomEvent.$emit('viewBidirectional', arr)
// this.resetViewport()
}, },
async jumpBidirectional(item) { async jumpBidirectional(item) {
if (item.bidirectional) { DicomEvent.$emit('jumpBidirectional', item)
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
console.log(an, 'an')
if (!an) return false
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
const viewport = renderingEngine.getViewport(viewportId)
let key = Object.keys(an.data.cachedStats)[0]; // referencedImageId
if (key) {
let sliceIndex = key.split("?")[1].split("&")[0].split("=")[1]
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIndex });
} else {
const points = an.data.handles.points;
const worldPoint = points[0]; //
let volume = cache.getVolume(this.series.SeriesInstanceUid)
let { imageData, numFrames } = volume
const ijk = imageData.worldToIndex(worldPoint);
const sliceIndex = Math.abs(Math.round(ijk[2]));
// console.log(sliceIndex, 'sliceIndex')
csUtils.jumpToSlice(viewport.element, { imageIndex: numFrames - sliceIndex - 1 });
}
}
}, },
viewSegmentGroup(item) { viewSegmentGroup(item) {
let view = !item.view item.view = !item.view
this.viewprotIds.forEach(id => {
segmentation.config.visibility.setSegmentationRepresentationVisibility(
id,
{
segmentationId: item.segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
view
);
})
item.view = view
item.segments.forEach(i => { item.segments.forEach(i => {
i.view = view i.view = item.view
// this.viewBidirectional(i, view)
}) })
this.viewBidirectional(item.segments, view) DicomEvent.$emit('viewSegmentation', item)
// this.viewBidirectional(item.segments, view)
}, },
viewSegment(item, view) { viewSegment(item, view) {
this.viewprotIds.forEach(id => {
segmentation.config.visibility.setSegmentIndexVisibility(id, {
segmentationId: item.segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
}, item.segmentIndex, view)
})
item.view = view item.view = view
this.viewBidirectional([item], view)
this.$emit('setToolsPassive') this.$emit('setToolsPassive')
DicomEvent.$emit('viewSegment', item)
}, },
lockSegment(item, lock) { lockSegment(item, lock) {
if (this.readingTaskState >= 2) return false
segmentation.segmentLocking.setSegmentIndexLocked(item.segmentationId, item.segmentIndex, lock) segmentation.segmentLocking.setSegmentIndexLocked(item.segmentationId, item.segmentIndex, lock)
item.lock = lock item.lock = lock
if (!lock) this.changeSegmentationSavedStatus(item.segmentationId, lock) if (!lock) this.changeSegmentationSavedStatus(item.segmentationId, lock)
@ -670,7 +689,7 @@ export default {
this.segmentationId = item.segmentationId; this.segmentationId = item.segmentationId;
this.segmentIndex = item.segmentIndex; this.segmentIndex = item.segmentIndex;
} }
segmentation.segmentIndex.setActiveSegmentIndex(item.segmentationId, item.segmentIndex); // segmentation.segmentIndex.setActiveSegmentIndex(item.segmentationId, item.segmentIndex);
if (isChange) { this.jumpBidirectional(item) } if (isChange) { this.jumpBidirectional(item) }
if (item.lock) { if (item.lock) {
@ -679,30 +698,57 @@ export default {
// this.resetViewport() // this.resetViewport()
}, },
selectSegmentGroup(s) { selectSegmentGroup(s) {
this.viewprotIds.forEach(id => { // segmentation.activeSegmentation.setActiveSegmentation(`${this.viewportKey}-${this.activeViewportIndex}`, this.segmentationId)
segmentation.activeSegmentation.setActiveSegmentation(id, this.segmentationId) this.$emit('setToolsPassive')
}) this.segmentIndex = null;
let segment = s ? s : this.segmentList.find(item => item.segmentationId === this.segmentationId).segments[0] let segment = s ? s : this.segmentList.find(item => item.segmentationId === this.segmentationId).segments[0]
this.selectSegment(segment, s ? false : true) this.$nextTick(() => {
this.readingSegmentByConfig() this.selectSegment(segment)
})
// this.segmentIndex = segment.segmentIndex
// this.selectSegment(segment, s ? false : true)
// this.readingSegmentByConfig()
},
getSegmentationName(num = 1) {
let defaultSegmentationName = this.trialCriterion.DefaultSegmentName.SegmentationName
let name = defaultSegmentationName
let has = this.segmentList.find(item => item.name === name)
if (has) {
name = defaultSegmentationName + num
has = this.segmentList.find(item => item.name === name)
num++
if (has) name = this.getSegmentationName(num)
}
return name
},
getSegmentName(arr, num = 1) {
let defaultSegmentName = arr[0].SegmentLabel
let name = defaultSegmentName + num
let has = arr.find(item => item.SegmentLabel === name)
num++
if (has) name = this.getSegmentName(arr, num)
return name
}, },
async addSegmentGroup() { async addSegmentGroup() {
let viewprotIds = this.viewprotIds
// let segmentationId = this.$guid(); // let segmentationId = this.$guid();
let obj = { let obj = {
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + (this.segmentList.length + 1), name: this.getSegmentationName(),
view: true, view: true,
segmentationId: null, segmentationId: null,
isSaved: false, isSaved: false,
segments: [] segments: []
} }
this.segmentIndex = null
let segmentationId = await this.addOrUpdateSegmentation({ name: obj.name }) let segmentationId = await this.addOrUpdateSegmentation({ name: obj.name })
obj.segmentationId = segmentationId obj.segmentationId = segmentationId
await this.createSegmentation(obj.segmentationId)
this.createSegmentationRepresentation(obj.segmentationId)
this.trialCriterion.DefaultSegmentName.SegmentNameList.forEach(async (SegmentName, index) => {
let o = { let o = {
segmentIndex: 1, segmentIndex: index + 1,
segmentationId, segmentationId,
SegmentLabel: 'Segment 1', SegmentLabel: SegmentName,
color: this.colors[0], color: this.colors[index],
stats: null, stats: null,
bidirectional: null, bidirectional: null,
bidirectionalView: true, bidirectionalView: true,
@ -711,33 +757,42 @@ export default {
} }
let id = await this.addOrUpdateSegment({ name: o.SegmentLabel, color: o.color, segmentIndex: o.segmentIndex, segmentationId: o.segmentationId }) let id = await this.addOrUpdateSegment({ name: o.SegmentLabel, color: o.color, segmentIndex: o.segmentIndex, segmentationId: o.segmentationId })
o.id = id o.id = id
obj.segments.push(o); obj.segments.splice(index, 0, o);
segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, index + 1);
this.changeColor(this.colors[index], { segmentationId: obj.segmentationId, segmentIndex: index + 1, color: this.colors[index] })
if (index === this.trialCriterion.DefaultSegmentName.SegmentNameList.length - 1) {
segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, 1);
}
})
this.segmentList.push(obj); this.segmentList.push(obj);
this.segmentationId = obj.segmentationId; this.segmentationId = obj.segmentationId;
await this.createSegmentation(obj.segmentationId)
this.createSegmentationRepresentation(obj.segmentationId)
this.segmentIndex = 1 this.segmentIndex = 1
viewprotIds.forEach(id => { // segmentation.segmentIndex.setActiveSegmentIndex(this.segmentationId, 1);
segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, 1, this.hex2Rgb(this.colors[0])) // viewportIds.forEach(id => {
}) // segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, 1, this.hex2Rgb(this.colors[0]))
this.selectSegmentGroup() // })
// this.selectSegmentGroup()
}, },
async addSegment() { async addSegment() {
let viewprotIds = this.viewprotIds; if (this.saveLoading) return false
if (this.segmentList.length <= 0) { if (this.segmentList.length <= 0) {
let obj = { let obj = {
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + 1, name: this.getSegmentationName(),
view: true, view: true,
isSaved: false, isSaved: false,
segments: [] segments: []
} }
this.segmentIndex = null
let segmentationId = await this.addOrUpdateSegmentation({ name: obj.name }) let segmentationId = await this.addOrUpdateSegmentation({ name: obj.name })
obj.segmentationId = segmentationId obj.segmentationId = segmentationId
await this.createSegmentation(segmentationId)
this.createSegmentationRepresentation(segmentationId)
this.trialCriterion.DefaultSegmentName.SegmentNameList.forEach(async (SegmentName, index) => {
let o = { let o = {
segmentIndex: 1, segmentIndex: index + 1,
segmentationId, segmentationId,
SegmentLabel: 'Segment 1', SegmentLabel: SegmentName,
color: this.colors[0], color: this.colors[index],
stats: null, stats: null,
bidirectional: null, bidirectional: null,
bidirectionalView: true, bidirectionalView: true,
@ -746,17 +801,22 @@ export default {
} }
let id = await this.addOrUpdateSegment({ name: o.SegmentLabel, color: o.color, segmentIndex: o.segmentIndex, segmentationId: o.segmentationId }) let id = await this.addOrUpdateSegment({ name: o.SegmentLabel, color: o.color, segmentIndex: o.segmentIndex, segmentationId: o.segmentationId })
o.id = id o.id = id
obj.segments.push(o); obj.segments.splice(index, 0, o);
this.segmentList.push(obj); segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, index + 1);
this.segmentationId = this.segmentList[0].segmentationId; this.changeColor(this.colors[index], { segmentationId: obj.segmentationId, segmentIndex: index + 1, color: this.colors[index] })
await this.createSegmentation(this.segmentationId) if (index === this.trialCriterion.DefaultSegmentName.SegmentNameList.length - 1) {
this.createSegmentationRepresentation(this.segmentationId) segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, 1);
this.segmentIndex = 1 }
segmentation.segmentIndex.setActiveSegmentIndex(this.segmentList[0].segmentationId, 1);
viewprotIds.forEach(id => {
segmentation.config.color.setSegmentIndexColor(id, this.segmentList[0].segmentationId, 1, this.hex2Rgb(this.colors[0]))
}) })
this.readingSegmentByConfig() this.segmentList.push(obj);
this.segmentationId = segmentationId;
this.segmentIndex = 1
// segmentation.segmentIndex.setActiveSegmentIndex(this.segmentList[0].segmentationId, 1);
// this.changeColor(this.colors[0], { segmentationId: this.segmentList[0].segmentationId, segmentIndex: 1, color: this.colors[0] })
// viewportIds.forEach(id => {
// segmentation.config.color.setSegmentIndexColor(id, this.segmentList[0].segmentationId, 1, this.hex2Rgb(this.colors[0]))
// })
// this.readingSegmentByConfig()
} else { } else {
let item = this.segmentList.find(i => i.segmentationId === this.segmentationId) let item = this.segmentList.find(i => i.segmentationId === this.segmentationId)
@ -765,7 +825,7 @@ export default {
let obj = { let obj = {
segmentIndex: segmentIndex, segmentIndex: segmentIndex,
segmentationId: this.segmentationId, segmentationId: this.segmentationId,
SegmentLabel: `Segment ${segmentIndex}`, SegmentLabel: this.getSegmentName(item.segments),
color: item.segments.length >= this.colors.length ? this.colors[0] : this.colors[item.segments.length], color: item.segments.length >= this.colors.length ? this.colors[0] : this.colors[item.segments.length],
stats: null, stats: null,
bidirectional: null, bidirectional: null,
@ -781,19 +841,22 @@ export default {
let id = await this.addOrUpdateSegment({ name: obj.SegmentLabel, color: obj.color, segmentIndex: obj.segmentIndex, segmentationId: obj.segmentationId }) let id = await this.addOrUpdateSegment({ name: obj.SegmentLabel, color: obj.color, segmentIndex: obj.segmentIndex, segmentationId: obj.segmentationId })
obj.id = id obj.id = id
item.segments.push(obj) item.segments.push(obj)
segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, obj.segmentIndex);
viewprotIds.forEach(id => {
segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, obj.segmentIndex, this.hex2Rgb(obj.color))
})
this.segmentIndex = obj.segmentIndex this.segmentIndex = obj.segmentIndex
// segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, obj.segmentIndex);
this.changeColor(obj.color, { segmentationId: obj.segmentationId, segmentIndex: obj.segmentIndex, color: obj.color })
// viewportIds.forEach(id => {
// segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, obj.segmentIndex, this.hex2Rgb(obj.color))
// })
} }
}, },
changeColor(e, item) { changeColor(e, item) {
this.viewprotIds.forEach(id => { DicomEvent.$emit('changeColor', item)
segmentation.config.color.setSegmentIndexColor(id, item.segmentationId, item.segmentIndex, this.hex2Rgb(e)) // this.viewportIds.forEach(id => {
}) // segmentation.config.color.setSegmentIndexColor(id, item.segmentationId, item.segmentIndex, this.hex2Rgb(e))
// })
}, },
// //
delAllSegment(isChange) { delAllSegment(isChange) {
@ -830,12 +893,13 @@ export default {
} else { } else {
this.segmentationId = '' this.segmentationId = ''
} }
this.readingSegmentByConfig() // this.readingSegmentByConfig()
this.resetViewport() this.resetViewport()
this.$emit('resetQuestion') this.$emit('resetQuestion')
}, },
// //
async delSegment(data) { async delSegment(data) {
this.popoverId = null;
let segmentIndex = data.segmentIndex let segmentIndex = data.segmentIndex
let confirm = await this.$confirm(this.$t('trials:reading:Segmentations:confirm:delSegment')) let confirm = await this.$confirm(this.$t('trials:reading:Segmentations:confirm:delSegment'))
if (!confirm) return false if (!confirm) return false
@ -862,15 +926,18 @@ export default {
}, },
resetViewport(passive = true) { resetViewport(passive = true) {
let renderingEngine = getRenderingEngine(this.renderingEngineId) DicomEvent.$emit('resetViewport')
this.viewprotIds.forEach(id => {
const viewport = renderingEngine.getViewport(id)
viewport.render()
})
if (passive) this.$emit('setToolsPassive') if (passive) this.$emit('setToolsPassive')
}, },
async rename(key, item) { async rename(key, item) {
let name = await this.customPrompt() let value = null
if (key === 'segmentGroup') {
let group = this.segmentList.find(i => i.segmentationId === this.segmentationId)
value = group.name
} else {
value = item.SegmentLabel
}
let name = await this.customPrompt(value)
if (!name) return false if (!name) return false
if (key === 'segmentGroup') { if (key === 'segmentGroup') {
let group = this.segmentList.find(i => i.segmentationId === this.segmentationId) let group = this.segmentList.find(i => i.segmentationId === this.segmentationId)
@ -881,7 +948,7 @@ export default {
this.addOrUpdateSegment({ name: item.SegmentLabel, color: item.color, segmentIndex: item.segmentIndex, segmentationId: item.segmentationId, segmentJson: JSON.stringify({ stats: item.stats, bidirectional: item.bidirectional }), id: item.id }) this.addOrUpdateSegment({ name: item.SegmentLabel, color: item.color, segmentIndex: item.segmentIndex, segmentationId: item.segmentationId, segmentJson: JSON.stringify({ stats: item.stats, bidirectional: item.bidirectional }), id: item.id })
} }
}, },
async customPrompt() { async customPrompt(name) {
try { try {
const that = this const that = this
// //
@ -893,6 +960,7 @@ export default {
showCancelButton: true, showCancelButton: true,
closeOnClickModal: false, closeOnClickModal: false,
closeOnPressEscape: false, closeOnPressEscape: false,
inputValue: name,
beforeClose: (action, instance, done) => { beforeClose: (action, instance, done) => {
if (action === 'confirm') { if (action === 'confirm') {
// const value = instance.inputValue // const value = instance.inputValue
@ -911,7 +979,7 @@ export default {
// //
changeInactiveSegmentShow() { changeInactiveSegmentShow() {
let segmentList = this.segmentList.filter(item => item.segmentationId !== this.segmentationId) let segmentList = this.segmentList.filter(item => item.segmentationId !== this.segmentationId)
this.viewprotIds.forEach(id => { this.viewportIds.forEach(id => {
segmentation.config.visibility.setSegmentationRepresentationVisibility( segmentation.config.visibility.setSegmentationRepresentationVisibility(
id, id,
{ {
@ -953,6 +1021,7 @@ export default {
this.exportSegmentation(this.segmentationId, group, true) this.exportSegmentation(this.segmentationId, group, true)
}, },
exportSegmentation(segmentationId, group, isFile = false) { exportSegmentation(segmentationId, group, isFile = false) {
try {
const segmentationIds = segmentation.state const segmentationIds = segmentation.state
.getSegmentations() .getSegmentations()
.map(x => x.segmentationId); .map(x => x.segmentationId);
@ -1060,6 +1129,10 @@ export default {
} else { } else {
this.downloadDICOMData(generatedSegmentation.dataset, `${group.name}.dcm`); this.downloadDICOMData(generatedSegmentation.dataset, `${group.name}.dcm`);
} }
} catch (err) {
console.log(err)
}
}, },
downloadDICOMData(bufferOrDataset, filename) { downloadDICOMData(bufferOrDataset, filename) {
let blob; let blob;
@ -1109,7 +1182,7 @@ export default {
const arrayBuffer = image.data.byteArray.buffer; const arrayBuffer = image.data.byteArray.buffer;
await this.loadSegmentation(arrayBuffer, obj.segmentationId); await this.loadSegmentation(arrayBuffer, obj.segmentationId);
this.createSegmentationRepresentation(obj.segmentationId); // this.createSegmentationRepresentation(obj.segmentationId);
}, },
async loadSegmentation(arrayBuffer, segmentationId) { async loadSegmentation(arrayBuffer, segmentationId) {
const generateToolState = const generateToolState =
@ -1292,17 +1365,11 @@ export default {
} }
}, },
createSegmentationRepresentation(segmentationId) { createSegmentationRepresentation(segmentationId) {
this.viewprotIds.forEach(id => { DicomEvent.$emit('createSegmentationRepresentation', segmentationId)
segmentation.addSegmentationRepresentations(id, [
{
segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
])
})
this.$emit('setToolsPassive') this.$emit('setToolsPassive')
}, },
contentMouseup() { contentMouseup() {
try {
// console.log("segment contentMouseup") // console.log("segment contentMouseup")
if (!this.drawing) return false if (!this.drawing) return false
if (this.timeoutId) { if (this.timeoutId) {
@ -1331,12 +1398,16 @@ export default {
} }
}, 500); }, 500);
} catch (err) {
console.log(err)
}
}, },
// //
async getSegmentBindingList(param = {}) { async getSegmentBindingList(param = {}) {
try { try {
let data = { let data = {
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
PageSize: 9999, PageSize: 9999,
PageIndex: 1, PageIndex: 1,
} }
@ -1353,7 +1424,7 @@ export default {
async saveSegmentBindingAndAnswer(list) { async saveSegmentBindingAndAnswer(list) {
try { try {
let data = { let data = {
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
BindingList: list BindingList: list
} }
let res = await saveSegmentBindingAndAnswer(data) let res = await saveSegmentBindingAndAnswer(data)
@ -1406,6 +1477,8 @@ export default {
}/${this.series.Id}/${segmentGroup.name}.dcm` }/${this.series.Id}/${segmentGroup.name}.dcm`
const result = await this.OSSclient.put(path, blob) const result = await this.OSSclient.put(path, blob)
segmentGroup.segUrl = this.$getObjectName(result.url) segmentGroup.segUrl = this.$getObjectName(result.url)
} else {
segmentGroup.segUrl = null
} }
this.addOrUpdateSegmentation({ name: segmentGroup.name, id: segmentGroup.segmentationId, url: segmentGroup.segUrl }) this.addOrUpdateSegmentation({ name: segmentGroup.name, id: segmentGroup.segmentationId, url: segmentGroup.segUrl })
@ -1443,7 +1516,6 @@ export default {
list.forEach(item => { list.forEach(item => {
this.createSegmentConfiguration(item.segmentIndex, item.segmentationId); this.createSegmentConfiguration(item.segmentIndex, item.segmentationId);
}) })
const renderingEngine = getRenderingEngine(this.renderingEngineId) const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewportId = `${this.viewportKey}-${this.activeViewportIndex}` const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
const viewport = renderingEngine.getViewport(viewportId); const viewport = renderingEngine.getViewport(viewportId);
@ -1468,7 +1540,7 @@ export default {
let bidirectional = bidirectionalData[0] let bidirectional = bidirectionalData[0]
const { segmentIndex } = bidirectional; const { segmentIndex } = bidirectional;
const { majorAxis, minorAxis, maxMajor, maxMinor } = bidirectional; const { majorAxis, minorAxis } = bidirectional;
let item = list.find(i => i.segmentIndex === segmentIndex) let item = list.find(i => i.segmentIndex === segmentIndex)
SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], { SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
segmentIndex, segmentIndex,
@ -1477,7 +1549,7 @@ export default {
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional"); let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
if (an) { if (an) {
annotation.locking.setAnnotationLocked(an.annotationUID, true) annotation.locking.setAnnotationLocked(an.annotationUID, true)
annotation.visibility.setAnnotationVisibility(an.annotationUID, item.bidirectionalView) annotation.visibility.setAnnotationVisibility(an.annotationUID, true)
} }
item.bidirectional = bidirectional item.bidirectional = bidirectional
reslove(true) reslove(true)
@ -1516,13 +1588,13 @@ export default {
answer = segment.stats && segment.stats[imageToolAttribute] ? Number((segment.stats[imageToolAttribute]).value).toFixed(this.digitPlaces) : '' answer = segment.stats && segment.stats[imageToolAttribute] ? Number((segment.stats[imageToolAttribute]).value).toFixed(this.digitPlaces) : ''
} }
let o = { let o = {
Answer: answer, Answer: answer === '-Infinity' || answer === 'NaN' ? null : answer,
QuestionId: item.QuestionId, QuestionId: item.QuestionId,
RowId: item.RowId, RowId: item.RowId,
SegmentId: item.SegmentId, SegmentId: item.SegmentId,
SegmentationId: item.SegmentationId, SegmentationId: item.SegmentationId,
TableQuestionId: item.TableQuestionId, TableQuestionId: item.TableQuestionId,
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
} }
bindingList.push(o) bindingList.push(o)
} }
@ -1540,7 +1612,7 @@ export default {
SubjectId: this.visitInfo.SubjectId, SubjectId: this.visitInfo.SubjectId,
SubjectVisitId: this.visitInfo.VisistId, SubjectVisitId: this.visitInfo.VisistId,
TrialId: this.$route.query.trialId, TrialId: this.$route.query.trialId,
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
} }
if (url) data.SegUrl = url; if (url) data.SegUrl = url;
if (id) data.Id = id; if (id) data.Id = id;
@ -1558,17 +1630,20 @@ export default {
// //
async getSegmentationList(SEGMENT = null) { async getSegmentationList(SEGMENT = null) {
try { try {
this.$emit('setToolsPassive')
let data = { let data = {
SeriesId: this.series.Id, SeriesId: this.series.Id,
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
PageSize: 9999, PageSize: 9999,
PageIndex: 1, PageIndex: 1,
} }
this.loading = true; this.loading = true;
let res = await getSegmentationList(data); let res = await getSegmentationList(data);
this.loading = false; // this.loading = false;
if (res.IsSuccess) { if (res.IsSuccess) {
this.segmentList = [] this.segmentList = []
this.segmentationId = null;
this.segmentIndex = null;
let list = res.Result.CurrentPageData; let list = res.Result.CurrentPageData;
for (let i = 0; i < list.length; i++) { for (let i = 0; i < list.length; i++) {
let item = list[i] let item = list[i]
@ -1583,12 +1658,6 @@ export default {
segments: [] segments: []
} }
this.segmentList.push(obj) this.segmentList.push(obj)
if (item.SEGUrl) {
await this.readSegmentation(obj)
} else {
await this.createSegmentation(obj.segmentationId)
this.createSegmentationRepresentation(obj.segmentationId)
}
} }
if (!this.segmentationId) { if (!this.segmentationId) {
this.segmentationId = obj.segmentationId this.segmentationId = obj.segmentationId
@ -1607,48 +1676,20 @@ export default {
bidirectional: SegmentJson.bidirectional, bidirectional: SegmentJson.bidirectional,
bidirectionalView: true, bidirectionalView: true,
view: true, view: true,
lock: item.locked, lock: true,
id: s.Id id: s.Id
} }
obj.segments.push(o) obj.segments.push(o)
this.selectSegment(o, false)
this.changeColor(s.ColorRgb, o)
this.lockSegment(o, true)
} }
if (!this.segmentIndex) { if (!this.segmentIndex) {
this.segmentIndex = s.SegmentNumber this.segmentIndex = s.SegmentNumber
} }
}) })
this.$nextTick(() => {
if (SEGMENT) {
// console.log(SEGMENT, 'SEGMENT')
return this.getBidirectional(obj.segments, SEGMENT)
}
this.getBidirectional(obj.segments, null, false)
})
}
if (this.segmentationId && this.segmentIndex && this.segmentList && this.segmentList.length > 0) {
let o = this.segmentList.find(item => item.segmentationId === this.segmentationId)
if (o) {
let s = o.segments.find(item => item.segmentIndex === this.segmentIndex)
this.selectSegmentGroup(s)
} else {
this.segmentationId = this.segmentList[0].segmentationId
this.segmentIndex = this.segmentationId ? this.segmentList[0].segments[0].segmentIndex : null
if (this.segmentationId && this.segmentIndex) {
this.selectSegmentGroup(this.segmentList[0].segments[0])
}
}
// console.log(segment, 'segment')
// this.selectSegment(segment)
} }
this.isloaded = false this.isloaded = false
this.readingSegmentByConfig()
} }
} catch (err) { } catch (err) {
this.loading = false // this.loading = false
console.log(err) console.log(err)
} }
}, },
@ -1674,7 +1715,7 @@ export default {
SegmentName: name, SegmentName: name,
SegmentNumber: segmentIndex, SegmentNumber: segmentIndex,
SegmentationId: segmentationId, SegmentationId: segmentationId,
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
SegmentJson: segmentJson SegmentJson: segmentJson
} }
if (id) data.Id = id if (id) data.Id = id
@ -1697,14 +1738,14 @@ export default {
PageSize: 9999, PageSize: 9999,
PageIndex: 1, PageIndex: 1,
} }
this.loading = true; // this.loading = true;
let res = await getSegmentList(data) let res = await getSegmentList(data)
this.loading = false; // this.loading = false;
if (res.IsSuccess) { if (res.IsSuccess) {
return res.Result.CurrentPageData return res.Result.CurrentPageData
} }
} catch (err) { } catch (err) {
this.loading = false // this.loading = false
console.log(err) console.log(err)
} }
}, },

View File

@ -10,9 +10,10 @@
</div> </div>
<div class="ps"> <div class="ps">
<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}`"> <template v-for="(study, index) in studyList">
<el-collapse-item :key="`${study.StudyId}`" :name="`${study.StudyId}`" v-if="!study.IsCriticalSequence">
<template slot="title"> <template slot="title">
<div v-if="!study.IsCriticalSequence" class="dicom-desc"> <div v-if="readingTool !== 3 || !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>
@ -53,7 +54,8 @@
style="position: absolute;right: 0;top: 0;"> style="position: absolute;right: 0;top: 0;">
<el-popover placement="right" trigger="hover" popper-class="instance_frame_wrapper"> <el-popover placement="right" trigger="hover" popper-class="instance_frame_wrapper">
<div class="frame_list"> <div class="frame_list">
<div v-for="(instance, idx) in series.InstanceInfoList" :key="instance.Id" class="frame_content" <div v-for="(instance, idx) in series.InstanceInfoList" :key="instance.Id"
class="frame_content"
:style="{ 'margin-bottom': idx < series.InstanceInfoList.length - 1 ? '5px' : '0px' }" :style="{ 'margin-bottom': idx < series.InstanceInfoList.length - 1 ? '5px' : '0px' }"
@click.stop="showMultiFrames(index, series, i, instance)"> @click.stop="showMultiFrames(index, series, i, instance)">
<div> <div>
@ -99,6 +101,8 @@
</div> </div>
</div> </div>
</el-collapse-item> </el-collapse-item>
</template>
</el-collapse> </el-collapse>
</div> </div>
</div> </div>
@ -119,6 +123,10 @@ export default {
default() { default() {
return [] return []
} }
},
readingTool: {
type: Number,
default: 2
} }
}, },
data() { data() {
@ -248,7 +256,8 @@ export default {
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;
} }
@ -299,7 +308,8 @@ export default {
} }
} }
::v-deep .el-collapse{
::v-deep .el-collapse {
border: none; border: none;
.el-collapse-item { .el-collapse-item {

View File

@ -0,0 +1,144 @@
<template>
<div class="SurfaceViewport" ref="SurfaceViewport" v-show="visible" id="SurfaceViewport"></div>
</template>
<script>
import {
getRenderingEngine,
CONSTANTS,
setVolumesForViewports,
eventTarget,
Enums,
utilities,
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
const {
Enums: csToolsEnums,
segmentation,
TrackballRotateTool,
ToolGroupManager
} = cornerstoneTools
const { MouseBindings, Events: toolsEvents } = csToolsEnums
export default {
name: "SurfaceViewport",
props: {
renderingEngineId: {
type: String,
required: true
},
viewportId: {
type: String,
required: true
},
visitInfo: {
type: Object,
default: () => {
return {}
}
},
visible: {
type: Boolean,
default: false
},
},
data() {
return {
volumeId: null,
info: null
}
},
mounted() {
eventTarget.addEventListener(Enums.Events.WEB_WORKER_PROGRESS, (evt) => {
const { progress } = evt.detail;
console.log(progress, 'progress')
});
},
methods: {
async setSeriesInfo(obj) {
try {
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
let { volumeId } = obj
this.info = obj
this.volumeId = volumeId
await setVolumesForViewports(
renderingEngine,
[{ volumeId, callback: setCtTransferFunctionForVolumeActor }],
[this.viewportId]
);
const volumeActor = viewport.getDefaultActor()
.actor;
utilities.applyPreset(
volumeActor,
CONSTANTS.VIEWPORT_PRESETS.find((preset) => preset.name === 'CT-Bone')
);
volumeActor.setVisibility(false);
viewport.render();
} catch (e) {
console.log(e)
}
},
async setSurface() {
let { segmentationId, segmentations } = this.info
const toolGroup = ToolGroupManager.getToolGroup(this.viewportId)
toolGroup.setToolActive(TrackballRotateTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Primary,
},
],
});
let s = segmentation.getActiveSegmentation(this.viewportId)
console.log(s)
if (s) {
await segmentation.removeSegmentationRepresentation(this.viewportId, {
segmentationId: s.segmentationId,
type: csToolsEnums.SegmentationRepresentations.Surface,
})
}
await segmentation.addSegmentationRepresentations(this.viewportId, [
{
segmentationId,
type: csToolsEnums.SegmentationRepresentations.Contour,
},
]);
console.log("loading...")
this.$nextTick(async () => {
await segmentation.addSegmentationRepresentations(this.viewportId, [
{
segmentationId,
type: csToolsEnums.SegmentationRepresentations.Surface,
},
]);
segmentations.segments.forEach(item => {
segmentation.config.color.setSegmentIndexColor(this.viewportId, item.segmentationId, item.segmentIndex, this.hex2Rgb(item.color))
})
})
},
hex2Rgb(hexValue, alpha = 1) {
const rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
const hex = hexValue.replace(rgx, (m, r, g, b) => r + r + g + g + b + b);
const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
if (!rgb) {
return hexValue;
}
const r = parseInt(rgb[1], 16),
g = parseInt(rgb[2], 16),
b = parseInt(rgb[3], 16);
return [r, g, b, alpha * 255];
},
}
}
</script>
<style lang="scss" scoped>
#SurfaceViewport {
width: 450px;
height: 300px;
position: fixed;
top: 100px;
z-index: 9999;
left: 100px;
}
</style>

View File

@ -14,6 +14,25 @@
<div v-if="imageInfo.total">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div> <div v-if="imageInfo.total">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div>
<div>{{ series.Modality }}</div> <div>{{ series.Modality }}</div>
</div> </div>
<div v-if="series && taskInfo && taskInfo.IsReadingTaskViewInOrder === 1" class="top-center-tool">
<div class="toggle-visit-container">
<div class="arrw_icon"
:style="{ cursor: series.TaskInfo && series.TaskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: series.TaskInfo && series.TaskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, -1)"
@dblclick.stop="preventDefault($event)">
<i class="el-icon-caret-left" />
</div>
<div class="arrow_text">
{{ series.TaskInfo ? series.TaskInfo.TaskBlindName : '' }}
</div>
<div class="arrw_icon"
:style="{ cursor: series.TaskInfo && series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: series.TaskInfo && series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, 1)"
@dblclick.stop="preventDefault($event)">
<i class="el-icon-caret-right" />
</div>
</div>
</div>
<div v-if="series" class="right-top-text"> <div v-if="series" class="right-top-text">
<div>{{ series.Description }}</div> <div>{{ series.Description }}</div>
</div> </div>
@ -78,9 +97,24 @@ import * as cornerstoneTools from '@cornerstonejs/tools'
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData' 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 setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
import { setCtMappingRange } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor' import { setCtMappingRange } 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 { vec3, mat4 } from 'gl-matrix'
import {
setPetTransferFunctionForVolumeActor
} from './helpers/index.js'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
import {
renderSegmentation,
readingSegmentByConfig,
selectSegmentation,
selectSegment,
createSegmentationRepresentation,
viewSegmentation,
viewSegment,
jumpBidirectional,
viewBidirectional,
changeColor,
resetViewport
} from "./helpers/segmentations"
export default { export default {
name: 'MPRViewport', name: 'MPRViewport',
props: { props: {
@ -96,6 +130,36 @@ export default {
type: Number, type: Number,
required: true required: true
}, },
histogramVisible: {
type: Boolean,
default: false
},
actionConfiguration: {
type: Object,
default: () => {
return {}
}
},
SegmentConfig: {
type: Object,
default: () => {
return {}
}
},
curSegSeries: {
type: Object,
default: () => {
return {}
}
},
segmentIndex: {
type: Number,
default: 0
},
segmentationId: {
type: String,
default: ''
}
}, },
data() { data() {
return { return {
@ -139,6 +203,7 @@ export default {
rotateAngle: 0, rotateAngle: 0,
rotateBarLeft: 0, rotateBarLeft: 0,
loading: false, loading: false,
toggleClipPlayTimer: null
} }
}, },
mounted() { mounted() {
@ -148,6 +213,39 @@ export default {
this.$nextTick(() => { this.$nextTick(() => {
this.initViewport() this.initViewport()
}) })
DicomEvent.$on('createSegmentationRepresentation', (segmentationId) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
createSegmentationRepresentation(this.viewportId, segmentationId)
})
DicomEvent.$on('viewSegmentation', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
viewSegmentation(obj, this.viewportId)
})
DicomEvent.$on('viewSegment', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
viewSegment(obj, this.viewportId)
})
DicomEvent.$on('jumpBidirectional', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
jumpBidirectional(obj, this.viewportId, this.volumeId)
})
DicomEvent.$on('viewBidirectional', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
viewBidirectional(obj, this.viewportId)
})
DicomEvent.$on('changeColor', (obj) => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
changeColor(obj, this.viewportId)
})
DicomEvent.$on('resetViewport', () => {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.TaskInfo.VisitTaskId !== this.series.TaskInfo.VisitTaskId) return false
resetViewport(this.viewportId)
})
DicomEvent.$on('renderSegmentation', async (viewportId) => {
// if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
if (this.viewportId !== viewportId) return false
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.renderingEngineId, null, this.actionConfiguration)
})
}, },
watch: { watch: {
MPRInfo: { MPRInfo: {
@ -166,6 +264,25 @@ export default {
} }
}, },
deep: true deep: true
},
SegmentConfig: {
handler() {
if (!this.segmentationId) return false
if (!this.series.TaskInfo) return false
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
},
deep: true
},
segmentIndex() {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
if (this.segmentIndex <= 0) return false
selectSegment(this.viewportId, this.segmentationId, this.segmentIndex)
},
segmentationId() {
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
if (!this.segmentationId) return false
selectSegmentation(this.viewportId, this.segmentationId)
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
} }
}, },
methods: { methods: {
@ -183,6 +300,7 @@ export default {
this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified) this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
this.element.addEventListener('CORNERSTONE_IMAGE_RENDERED', this.imageRendered) this.element.addEventListener('CORNERSTONE_IMAGE_RENDERED', this.imageRendered)
this.element.addEventListener('wheel', (e) => { this.element.addEventListener('wheel', (e) => {
// if (this.histogramVisible) return false
console.log('CORNERSTONE_STACK_VIEWPORT_SCROLL') console.log('CORNERSTONE_STACK_VIEWPORT_SCROLL')
const renderingEngine = getRenderingEngine(this.renderingEngineId) const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId) const viewport = renderingEngine.getViewport(this.viewportId)
@ -266,6 +384,7 @@ export default {
}, },
stackNewImage(e) { stackNewImage(e) {
const { detail } = e const { detail } = e
this.series.SliceIndex = detail.imageIndex this.series.SliceIndex = detail.imageIndex
this.sliderInfo.height = detail.imageIndex * 100 / detail.numberOfSlices this.sliderInfo.height = detail.imageIndex * 100 / detail.numberOfSlices
const renderingEngine = getRenderingEngine(this.renderingEngineId) const renderingEngine = getRenderingEngine(this.renderingEngineId)
@ -286,13 +405,14 @@ export default {
let spacing = volume ? volume.spacing : [] let spacing = volume ? volume.spacing : []
this.imageInfo.sliceThickness = type === 'AXIAL' ? spacing[2] : spacing[0] this.imageInfo.sliceThickness = type === 'AXIAL' ? spacing[2] : spacing[0]
this.getOrientationMarker() this.getOrientationMarker()
if (this.series && this.series.Id) { // if (this.series && this.series.Id) {
let annotations = cornerstoneTools.annotation.state.getAllAnnotations().filter(item => item.metadata.toolName !== 'ScaleOverlay' && item.metadata.volumeId !== this.volumeId && !item.metadata.segmentationId && item.seriesId !== this.series.Id) // let annotations = cornerstoneTools.annotation.state.getAllAnnotations().filter(item => item.metadata.toolName !== 'ScaleOverlay' && item.metadata.volumeId !== this.volumeId && !item.metadata.segmentationId && item.seriesId !== this.series.Id)
annotations.forEach(item => { // annotations.forEach(item => {
cornerstoneTools.annotation.state.removeAnnotation(item.annotationUID) // cornerstoneTools.annotation.state.removeAnnotation(item.annotationUID)
}) // })
} // }
this.$emit('renderAnnotations', this.series) this.$emit('renderAnnotations', this.series)
this.$emit("resetHistogram")
let properties = viewport.getProperties() let properties = viewport.getProperties()
if (this.isFusion) { if (this.isFusion) {
properties = viewport.getProperties(this.ptVolumeId) properties = viewport.getProperties(this.ptVolumeId)
@ -418,11 +538,20 @@ export default {
this.playClipState = isPlay this.playClipState = isPlay
const renderingEngine = getRenderingEngine(this.renderingEngineId) const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId) const viewport = renderingEngine.getViewport(this.viewportId)
if (isPlay) { if (isPlay) {
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: true }) this.toggleClipPlayTimer = setInterval(() => {
let index = this.series.SliceIndex + 1;
if (index > this.imageInfo.total - 1) index = 0
csUtils.jumpToSlice(viewport.element, { imageIndex: index });
}, framesPerSecond)
// cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: true })
} else { } else {
cornerstoneTools.utilities.cine.stopClip(viewport.element) if (this.toggleClipPlayTimer) {
clearInterval(this.toggleClipPlayTimer)
this.toggleClipPlayTimer = null
}
// cornerstoneTools.utilities.cine.stopClip(viewport.element)
} }
}, },
scrollPage(type) { scrollPage(type) {
@ -520,7 +649,6 @@ export default {
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)
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 });
@ -532,7 +660,8 @@ export default {
.setVolumes([{ .setVolumes([{
volumeId: this.volumeId, callback: (r) => { volumeId: this.volumeId, callback: (r) => {
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') { if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
setPetColorMapTransferFunctionForVolumeActor(r, true) setPetTransferFunctionForVolumeActor(r)
// viewport.setProperties({ voiRange: { upper: 5, lower: 0 } })
} else { } else {
const voi = metaData.get('voiLutModule', res.volume._imageIds[Math.ceil((res.volume._imageIds.length - 1) / 2)]) const voi = metaData.get('voiLutModule', res.volume._imageIds[Math.ceil((res.volume._imageIds.length - 1) / 2)])
setCtMappingRange(voi.windowWidth[0], voi.windowCenter[0]) setCtMappingRange(voi.windowWidth[0], voi.windowCenter[0])
@ -541,19 +670,28 @@ export default {
console.log("渲染成功") console.log("渲染成功")
} }
}]).then(r => { }]).then(r => {
if (data.segment) {
return DicomEvent.$emit("isloaded", { segment: data.segment, isChange: data.isChange })
}
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", { isChange: data.isChange })
}) })
res.volume.dimensionGroupNumber = 2;
viewport.render() viewport.render()
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
setTimeout(() => {
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
viewport.resetProperties()
viewport.setProperties({ voiRange: { upper: 5, lower: 0 } })
viewport.render()
renderingEngine.render()
}, 100)
}
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.renderingEngineId, data.segment, this.actionConfiguration)
DicomEvent.$emit('SegmentationLoading', this.viewportId)
if (this.series.hasOwnProperty('curIndex')) return this.setFullScreen(this.series.curIndex)
this.setFullScreen(Math.ceil((res.volume._imageIds.length - 1) / 2) - 1)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }
}, },
cornerstoneToolsMouseMove(e) { cornerstoneToolsMouseMove(e) {
const { currentPoints } = e.detail const { currentPoints } = e.detail
@ -723,6 +861,12 @@ export default {
return `NS: ${this.$store.state.trials.downloadTip}` return `NS: ${this.$store.state.trials.downloadTip}`
} }
}, },
destroyed() {
if (this.toggleClipPlayTimer) {
clearInterval(this.toggleClipPlayTimer)
this.toggleClipPlayTimer = null
}
}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1357,6 +1357,7 @@ export default {
await this.getQuestionCalculateRelation() await this.getQuestionCalculateRelation()
await this.getQuestions(true) await this.getQuestions(true)
this.$emit('resetAnnotations', this.visitTaskId) this.$emit('resetAnnotations', this.visitTaskId)
this.initSegmentBinding()
this.$nextTick(() => { this.$nextTick(() => {
this.rerender = true this.rerender = true
}) })

View File

@ -0,0 +1,436 @@
import * as cornerstoneTools from '@cornerstonejs/tools';
import * as cornerstone from "@cornerstonejs/core";
import dcmjs from '@/utils/dcmUpload/dcmjs'
import * as cornerstoneAdapters from "@cornerstonejs/adapters";
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
cornerstoneTools.init({ addons: { polySeg } })
import { getSegmentationList, getSegmentList } from '@/api/reading'
import Vue from 'vue'
const {
ToolGroupManager,
Enums: csToolsEnums,
segmentation,
annotation,
LabelMapEditWithContourTool,
SegmentBidirectionalTool,
CrosshairsTool,
utilities: CStUtils,
} = cornerstoneTools;
const { MouseBindings, Events: toolsEvents } = csToolsEnums
const { segmentation: segmentationUtils } = CStUtils;
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
const { Cornerstone3D } = cornerstoneAdapters.adaptersSEG;
let viewportInfo = {}
let renderingEngineId = null
async function createSegmentation(toolGroupId, volumeId, segmentationId) {
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) || ToolGroupManager.getToolGroup('share-viewport-volume')
toolGroup.setToolActive(
LabelMapEditWithContourTool.toolName,
);
if (!cache.getVolume(segmentationId)) {
await volumeLoader.createAndCacheDerivedLabelmapVolume(
volumeId,
{
volumeId: segmentationId
}
)
}
if (!segmentation.state.getSegmentation(segmentationId)) {
segmentation.addSegmentations([
{
segmentationId,
representation: {
type: cornerstoneTools.Enums.SegmentationRepresentations
.Labelmap,
data: {
volumeId: segmentationId
}
}
}
]);
}
}
async function createSegmentationRepresentation(viewportId, segmentationId) {
segmentation.addSegmentationRepresentations(viewportId, [
{
segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
])
}
async function readSegmentation(obj, series, segmentationId, isFile = false) {
let imageId = null
if (isFile) {
imageId = cornerstoneDICOMImageLoader.wadouri.fileManager.add(obj);
} else {
const imageIdObj = await cornerstoneDICOMImageLoader.wadouri.loadImage(`wadouri:${Vue.prototype.OSSclientConfig.basePath}${obj}`).promise
imageId = imageIdObj.imageId
}
const image = await imageLoader.loadAndCacheImage(imageId);
if (!image) {
return;
}
const instance = metaData.get("instance", imageId);
if (instance.Modality !== "SEG") {
console.error("This is not segmentation: " + file.name);
return;
}
const arrayBuffer = image.data.byteArray.buffer;
await loadSegmentation(arrayBuffer, series, segmentationId);
}
async function loadSegmentation(arrayBuffer, series, segmentationId) {
const generateToolState =
await Cornerstone3D.Segmentation.generateToolState(
series.ImageIds,
arrayBuffer,
metaData,
);
if (generateToolState.labelmapBufferArray.length !== 1) {
alert(
"Overlapping segments in your segmentation are not supported yet. You can turn on the skipOverlapping option but it will override the overlapping segments."
);
return;
}
// await createSegmentation(segmentationId);
let arr = []
generateToolState.segMetadata.data.forEach(item => {
if (item) {
let Target = JSON.parse(JSON.stringify(item))
arr.push(Target)
}
})
let mapping = {}
arr.forEach((item, index) => {
mapping[index + 1] = Number(item.SegmentNumber)
})
const megmentGroup =
segmentation.state.getSegmentation(segmentationId);
const { imageIds } = megmentGroup.representationData.Labelmap;
const derivedSegmentationImages = imageIds.map(imageId =>
cache.getImage(imageId)
);
const volumeScalarData = new Uint8Array(
generateToolState.labelmapBufferArray[0]
);
const remappedData = new Uint8Array(volumeScalarData.length);
for (let i = 0; i < volumeScalarData.length; i++) {
const value = volumeScalarData[i];
remappedData[i] = value === 0 ? 0 : (mapping[value] ? mapping[value] : value);
}
for (let i = 0; i < derivedSegmentationImages.length; i++) {
const voxelManager = derivedSegmentationImages[i].voxelManager;
const scalarData = voxelManager.getScalarData();
scalarData.set(
remappedData.slice(
i * scalarData.length,
(i + 1) * scalarData.length
)
);
voxelManager.setScalarData(scalarData);
}
}
function hex2Rgb(hexValue, alpha = 1) {
const rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
const hex = hexValue.replace(rgx, (m, r, g, b) => r + r + g + g + b + b);
const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
if (!rgb) {
return hexValue;
}
const r = parseInt(rgb[1], 16),
g = parseInt(rgb[2], 16),
b = parseInt(rgb[3], 16);
return [r, g, b, alpha * 255];
}
function removeSegmentFromViewport(viewportId) {
return new Promise(resolve => {
if (viewportInfo[viewportId] && viewportInfo[viewportId].length > 0) {
viewportInfo[viewportId].forEach(async segmentationId => {
segmentation.removeSegmentation(segmentationId)
segmentation.state.removeSegmentation(segmentationId)
let annotations = annotation.state.getAllAnnotations().filter(item => item.metadata.segmentationId && segmentationId === item.metadata.segmentationId && item.metadata.toolName === "SegmentBidirectional");
annotations.forEach(item => {
annotation.state.removeAnnotation(item.annotationUID)
})
})
resetViewport(viewportId)
}
viewportInfo[viewportId] = []
resolve(true)
})
}
function createSegmentConfiguration(segmentIndex, segmentationId, viewportId, actionConfiguration, otherSegments) {
const containedSegmentIndices = otherSegments
? { has: (segmentIndex) => otherSegments.indexOf(segmentIndex) !== -1 }
: undefined;
const colorConfig = segmentation.config.color.getSegmentIndexColor(
viewportId,
segmentationId,
segmentIndex
);
// Allow null style to skip style set
let color, activeColor;
if (colorConfig?.length) {
color = `rgb(${colorConfig.join(',')})`;
activeColor = color;
}
const style = {
color,
colorHighlightedActive: activeColor,
colorActive: activeColor,
textBoxColor: color,
textBoxColorActive: activeColor,
textBoxColorHighlightedActive: activeColor,
};
const label = otherSegments
? `Combined ${segmentIndex} with ${otherSegments.join(', ')}`
: `Segment ${segmentIndex}`;
actionConfiguration.contourBidirectional.data.segmentData.set(segmentIndex, {
containedSegmentIndices,
label,
style,
});
actionConfiguration.contourBidirectional.data.segmentationId = segmentationId
actionConfiguration.contourBidirectional.data.segmentIndex = segmentIndex
}
async function readingSegmentByConfig(series, visitInfo, viewportId, segmentationId, SegmentConfig) {
let data = {
SeriesId: series.Id,
VisitTaskId: visitInfo.VisitTaskId,
PageSize: 9999,
PageIndex: 1,
}
let res = await getSegmentationList(data);
if (res.IsSuccess) {
let list = res.Result.CurrentPageData;
changeInactiveSegmentShow(list, viewportId, segmentationId, SegmentConfig)
}
segmentation.config.style.setStyle(
{
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
{
renderFill: SegmentConfig.renderFill,
renderOutline: SegmentConfig.renderOutline,
outlineWidth: Number(SegmentConfig.outlineWidth),
fillAlpha: Number(SegmentConfig.fillAlpha),
}
)
}
function selectSegmentation(viewportId, segmentationId) {
segmentation.activeSegmentation.setActiveSegmentation(viewportId, segmentationId)
}
function selectSegment(viewportId, segmentationId, segmentIndex) {
selectSegmentation(viewportId, segmentationId)
segmentation.segmentIndex.setActiveSegmentIndex(segmentationId, segmentIndex);
}
async function changeInactiveSegmentShow(list, viewportId, segmentationId, SegmentConfig) {
let segmentList = list
segmentList.forEach(segment => {
segmentation.config.visibility.setSegmentationRepresentationVisibility(
viewportId,
{
segmentationId: segment.Id,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
SegmentConfig.InactiveSegmentations.show
);
})
segmentation.config.visibility.setSegmentationRepresentationVisibility(
viewportId,
{
segmentationId: segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
true
);
let arr = []
for (let i = 0; i < segmentList.length; i++) {
let item = segmentList[i]
let params = {
SegmentationId: item.Id,
PageSize: 9999,
PageIndex: 1,
}
let r = await getSegmentList(params)
if (r.IsSuccess) {
let segments = r.Result.CurrentPageData
segments.forEach(s => {
let obj = {
segmentationId: item.Id,
segmentIndex: s.SegmentNumber,
view: SegmentConfig.InactiveSegmentations.show
}
if (item.Id === segmentationId) {
obj.view = true
}
arr.push(obj)
})
}
}
viewBidirectional(arr, viewportId)
}
function viewSegmentation(item, viewportId) {
segmentation.config.visibility.setSegmentationRepresentationVisibility(
viewportId,
{
segmentationId: item.segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
item.view
);
viewBidirectional(item.segments, viewportId)
}
async function jumpBidirectional(item, viewportId, volumeId) {
// DicomEvent.$emit('jumpBidirectional', item)
if (item.bidirectional) {
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
console.log(an, 'an')
if (!an) return false
if (['viewport-MPR-1', 'viewport-MPR-2'].includes(viewportId)) return false
const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(viewportId)
let key = Object.keys(an.data.cachedStats)[0]; // referencedImageId
if (key) {
let sliceIndex = key.split("?")[1].split("&")[0].split("=")[1]
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIndex });
} else {
const points = an.data.handles.points;
const worldPoint = points[0]; // 取一个点
let volume = cache.getVolume(volumeId)
let { imageData, numFrames } = volume
const ijk = imageData.worldToIndex(worldPoint);
const sliceIndex = Math.abs(Math.round(ijk[2]));
// console.log(sliceIndex, 'sliceIndex')
csUtils.jumpToSlice(viewport.element, { imageIndex: numFrames - sliceIndex - 1 });
}
}
}
function viewSegment(item, viewportId) {
segmentation.config.visibility.setSegmentIndexVisibility(viewportId, {
segmentationId: item.segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
}, item.segmentIndex, item.view)
viewBidirectional([item], viewportId)
}
function viewBidirectional(arr, viewportId) {
for (let j = 0; j < arr.length; j++) {
let item = arr[j]
let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
// item.bidirectionalView = view
if (!bidirectional) continue
let view = item.view
if (item.hasOwnProperty('bidirectionalView')) view = item.bidirectionalView
annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
}
resetViewport(viewportId)
}
function resetViewport(viewportId) {
let renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(viewportId)
viewport.render()
}
function changeColor(item, viewportId) {
segmentation.config.color.setSegmentIndexColor(viewportId, item.segmentationId, item.segmentIndex, hex2Rgb(item.color))
}
async function renderSegmentation(series, visitInfo, viewportId, SegmentConfig, RenderingEngineId, Segment = null, actionConfiguration) {
try {
// console.log(segmentation, 'segmentation')
renderingEngineId = RenderingEngineId
await removeSegmentFromViewport(viewportId)
let data = {
SeriesId: series.Id,
VisitTaskId: visitInfo.VisitTaskId,
PageSize: 9999,
PageIndex: 1,
}
let segmentationId = null;
let segmentIndex = null;
let res = await getSegmentationList(data);
if (res.IsSuccess) {
let list = res.Result.CurrentPageData;
for (let i = 0; i < list.length; i++) {
let item = list[i]
if (!segmentationId) segmentationId = item.Id
await createSegmentation(viewportId, series.SeriesInstanceUid, item.Id)
if (item.SEGUrl) await readSegmentation(item.SEGUrl, series, item.Id)
createSegmentationRepresentation(viewportId, item.Id)
if (!viewportInfo[viewportId]) {
viewportInfo[viewportId] = [item.Id]
} else {
viewportInfo[viewportId].push(item.Id)
}
let params = {
SegmentationId: item.Id,
PageSize: 9999,
PageIndex: 1,
}
let r = await getSegmentList(params)
if (r.IsSuccess) {
let segments = r.Result.CurrentPageData
segments.forEach(s => {
if (!segmentIndex) segmentIndex = s.SegmentNumber
let SegmentJson = s.SegmentJson ? JSON.parse(s.SegmentJson) : {};
segmentation.segmentIndex.setActiveSegmentIndex(s.SegmentationId, s.SegmentNumber);
segmentation.config.color.setSegmentIndexColor(viewportId, s.SegmentationId, s.SegmentNumber, hex2Rgb(s.ColorRgb))
segmentation.segmentLocking.setSegmentIndexLocked(s.SegmentationId, s.SegmentNumber, true)
if (SegmentJson.bidirectional) {
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === s.SegmentationId && i.metadata.segmentIndex === SegmentJson.bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
if (!an) {
let { majorAxis, minorAxis } = SegmentJson.bidirectional
// createSegmentConfiguration(s.SegmentNumber, s.SegmentationId, viewportId, actionConfiguration)
SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
segmentIndex: s.SegmentNumber,
segmentationId: s.SegmentationId,
})
}
an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === s.SegmentationId && i.metadata.segmentIndex === SegmentJson.bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
if (an) {
annotation.locking.setAnnotationLocked(an.annotationUID, true)
annotation.visibility.setAnnotationVisibility(an.annotationUID, true)
}
console.log(an, 'an')
}
})
}
if (segmentationId && segmentIndex) {
selectSegment(viewportId, segmentationId, segmentIndex)
}
if (Segment) {
jumpBidirectional(Segment, viewportId, series.SeriesInstanceUid)
}
}
}
readingSegmentByConfig(series, visitInfo, viewportId, segmentationId, SegmentConfig)
} catch (err) {
console.log(err)
}
}
export {
createSegmentation,
createSegmentationRepresentation,
readSegmentation,
renderSegmentation,
readingSegmentByConfig,
selectSegment,
selectSegmentation,
viewSegmentation,
viewSegment,
jumpBidirectional,
viewBidirectional,
changeColor,
resetViewport
}

View File

@ -1,5 +1,6 @@
import vtkColorTransferFunction from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction"; import vtkColorTransferFunction from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction";
import vtkPiecewiseFunction from "@kitware/vtk.js/Common/DataModel/PiecewiseFunction"; import vtkPiecewiseFunction from "@kitware/vtk.js/Common/DataModel/PiecewiseFunction";
import { Scale } from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction/Constants";
import { cache, metaData, utilities } from "@cornerstonejs/core"; import { cache, metaData, utilities } from "@cornerstonejs/core";
const { getColormap } = utilities.colormap; const { getColormap } = utilities.colormap;
@ -14,7 +15,7 @@ function getWindowCenterFromVolumeId(volumeId) {
? voiLutModule.windowCenter[0] ? voiLutModule.windowCenter[0]
: voiLutModule?.windowCenter; : voiLutModule?.windowCenter;
const center = Number(rawCenter); const center = Number(rawCenter);
return Number.isFinite(center) ? center : null; return center;
} }
export default function setPetColorMapTransferFunctionForVolumeActor({ export default function setPetColorMapTransferFunctionForVolumeActor({
@ -33,7 +34,25 @@ export default function setPetColorMapTransferFunctionForVolumeActor({
const center = getWindowCenterFromVolumeId(volumeId); const center = getWindowCenterFromVolumeId(volumeId);
const upper = center > 1 ? center : 5; const upper = center > 1 ? center : 5;
cfun.setMappingRange(1, upper); const safeUpper = Number.isFinite(upper) && upper > 0 ? upper : 5;
const rangeMin = 0;
const rangeMax = safeUpper;
cfun.setScale(Scale.LOG10);
cfun.setMappingRange(rangeMin, rangeMax);
volumeActor.getProperty().setRGBTransferFunction(0, cfun); volumeActor.getProperty().setRGBTransferFunction(0, cfun);
//低信号更明显,系数可以更小
const thresholdValue0 = Math.max(rangeMin, rangeMax * 0.002);
const thresholdValue1 = Math.max(thresholdValue0, rangeMax * 0.02);
const delta = Math.abs(rangeMax - rangeMin) * 0.001;
const threshold0MinusDelta = Math.max(rangeMin, thresholdValue0 - delta);
const ofun = vtkPiecewiseFunction.newInstance();
ofun.addPoint(rangeMin, 0.0);
ofun.addPoint(threshold0MinusDelta, 0.0);
//低信号更明显,系数可以更小
ofun.addPoint(thresholdValue0, 0.08);
ofun.addPoint(thresholdValue1, 0.9);
ofun.addPoint(rangeMax, 1.0);
volumeActor.getProperty().setScalarOpacity(0, ofun);
} }

File diff suppressed because it is too large Load Diff

View File

@ -311,6 +311,15 @@ const config = {
'isDisabled': false, 'isDisabled': false,
'disabledReason': '' 'disabledReason': ''
}, },
{
'name': '定圆工具',
'icon': 'oval',
'toolName': 'FixedRadiusCircleROI',
'props': ['radius', 'area', 'mean', 'max', 'stdDev'],
'i18nKey': 'trials:reading:button:fixedCircle',
'isDisabled': false,
'disabledReason': ''
}
], ],
'customizeStandardsNoneDicom': [ 'customizeStandardsNoneDicom': [
{ {

View File

@ -28,10 +28,12 @@ class FixedRadiusCircleROITool extends cornerstoneTools.CircleROITool {
preventHandleOutsideImage: false, preventHandleOutsideImage: false,
storePointData: false, storePointData: false,
centerPointRadius: 0, centerPointRadius: 0,
radius: 10, // Default radius in mm calculateStats: true,
radius: 6, // Default radius in mm
radiusUnit: 'mm', radiusUnit: 'mm',
statsCalculator: BasicStatsCalculator, statsCalculator: BasicStatsCalculator,
getTextLines: defaultGetTextLines, getTextLines: defaultGetTextLines,
simplified: true,
}, },
} }
) { ) {
@ -67,9 +69,12 @@ class FixedRadiusCircleROITool extends cornerstoneTools.CircleROITool {
); );
const FrameOfReferenceUID = viewport.getFrameOfReferenceUID(); const FrameOfReferenceUID = viewport.getFrameOfReferenceUID();
const targetId = this.getTargetId(viewport);
// Calculate end point based on fixed radius // Calculate end point based on fixed radius
const radius = this.configuration.radius || 10; const radius = Number.isFinite(this.configuration.radius)
? this.configuration.radius
: 10;
// viewUp is a normalized vector. // viewUp is a normalized vector.
// We want a point 'radius' distance away from center. // We want a point 'radius' distance away from center.
// We can use viewUp or any vector in the plane. // We can use viewUp or any vector in the plane.
@ -106,7 +111,20 @@ class FixedRadiusCircleROITool extends cornerstoneTools.CircleROITool {
points: [[...worldPos], [...endPos]], points: [[...worldPos], [...endPos]],
activeHandleIndex: null, activeHandleIndex: null,
}, },
cachedStats: {}, cachedStats: {
[targetId]: {
Modality: null,
radius: null,
radiusUnit: null,
area: null,
mean: null,
stdDev: null,
max: null,
isEmptyArea: null,
areaUnit: null,
modalityUnit: null,
},
},
}, },
}; };
@ -180,9 +198,11 @@ class FixedRadiusCircleROITool extends cornerstoneTools.CircleROITool {
}; };
} }
export default FixedRadiusCircleROITool;
function defaultGetTextLines(data, targetId) { function defaultGetTextLines(data, targetId) {
const cachedVolumeStats = data.cachedStats[targetId]; const cachedVolumeStats = data?.cachedStats?.[targetId];
if (!cachedVolumeStats) {
return [];
}
const { const {
radius, radius,
radiusUnit, radiusUnit,
@ -195,32 +215,33 @@ function defaultGetTextLines(data, targetId) {
modalityUnit, modalityUnit,
} = cachedVolumeStats; } = cachedVolumeStats;
const textLines = []; const textLines = [];
if (csUtils.isNumber(radius)) {
if (radius) {
const radiusLine = isEmptyArea const radiusLine = isEmptyArea
? `Radius: Oblique not supported` ? `Radius: Oblique not supported`
: `Radius: ${csUtils.roundNumber(radius)} ${radiusUnit}`; : `Radius: ${csUtils.roundNumber(radius)} ${radiusUnit}`;
textLines.push(radiusLine); textLines.push(radiusLine);
} }
if (area) { if (csUtils.isNumber(area)) {
const areaLine = isEmptyArea const areaLine = isEmptyArea
? `Area: Oblique not supported` ? `Area: Oblique not supported`
: `Area: ${csUtils.roundNumber(area)} ${areaUnit}`; : `Area: ${csUtils.roundNumber(area)} ${areaUnit}`;
textLines.push(areaLine); textLines.push(areaLine);
} }
if (mean) { if (csUtils.isNumber(mean)) {
textLines.push(`Mean: ${csUtils.roundNumber(mean)} ${modalityUnit}`); textLines.push(`Mean: ${csUtils.roundNumber(mean)} ${modalityUnit}`);
} }
if (max) { if (csUtils.isNumber(max)) {
textLines.push(`Max: ${csUtils.roundNumber(max)} ${modalityUnit}`); textLines.push(`Max: ${csUtils.roundNumber(max)} ${modalityUnit}`);
} }
if (stdDev) { if (csUtils.isNumber(stdDev)) {
textLines.push(`Std Dev: ${csUtils.roundNumber(stdDev)} ${modalityUnit}`); textLines.push(`Std Dev: ${csUtils.roundNumber(stdDev)} ${modalityUnit}`);
} }
return textLines; return textLines;
} }
export default FixedRadiusCircleROITool;

View File

@ -302,7 +302,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2 ) { if (readingTool === 0 || readingTool === 2|| readingTool === 3 ) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`

View File

@ -358,7 +358,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2 ) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`

View File

@ -276,7 +276,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2) { if (readingTool === 0 || readingTool === 2|| readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/noneDicomReading?trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`

View File

@ -290,7 +290,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/noneDicomReading?trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`

View File

@ -1,31 +1,14 @@
<template> <template>
<el-form v-if="globalForm.taskList.length > 0" ref="globalRuleForm" :model="globalForm" class="global-form"> <el-form v-if="globalForm.taskList.length > 0" ref="globalRuleForm" :model="globalForm" class="global-form">
<el-table <el-table v-loading="loading" :data="globalForm.taskList">
v-loading="loading"
:data="globalForm.taskList"
>
<!-- 访视名称 --> <!-- 访视名称 -->
<el-table-column <el-table-column prop="BlindName" :label="$t('trials:globalReview:table:visitName')" show-overflow-tooltip
prop="BlindName" width="150" />
:label="$t('trials:globalReview:table:visitName')"
show-overflow-tooltip
width="150"
/>
<!-- 评估结果 --> <!-- 评估结果 -->
<el-table-column <el-table-column :label="$t('trials:globalReview:table:evaluationRes')" align="center" prop="">
:label="$t('trials:globalReview:table:evaluationRes')"
align="center"
prop=""
>
<template> <template>
<el-table-column <el-table-column v-for="(qs, index) in globalInfo.evaluationQsList" :key="index" prop="" :label="qs"
v-for="(qs,index) in globalInfo.evaluationQsList" show-overflow-tooltip width="150">
:key="index"
prop=""
:label="qs"
show-overflow-tooltip
width="150"
>
<!-- <template slot-scope="scope"> <!-- <template slot-scope="scope">
<div v-if="scope.row.BeforeQuestionList.length>index && scope.row.BeforeQuestionList[index].Answer" :style="{color: scope.row.BeforeQuestionList[index].IsGlobalAnswer ? '#f66' : null}"> <div v-if="scope.row.BeforeQuestionList.length>index && scope.row.BeforeQuestionList[index].Answer" :style="{color: scope.row.BeforeQuestionList[index].IsGlobalAnswer ? '#f66' : null}">
<span v-if="scope.row.BeforeQuestionList[index].DictionaryCode"> <span v-if="scope.row.BeforeQuestionList[index].DictionaryCode">
@ -35,10 +18,14 @@
</div> </div>
</template> --> </template> -->
<template slot-scope="scope"> <template slot-scope="scope">
<template v-if="(scope.row.IsBaseLine && (scope.row.BeforeQuestionList[index].GlobalReadingShowType ===1 || scope.row.BeforeQuestionList[index].GlobalReadingShowType ===5)) || (!scope.row.IsBaseLine && (scope.row.BeforeQuestionList[index].GlobalReadingShowType ===2 || scope.row.BeforeQuestionList[index].GlobalReadingShowType ===6)) || (scope.row.BeforeQuestionList[index].GlobalReadingShowType ===0 || scope.row.BeforeQuestionList[index].GlobalReadingShowType ===4)"> <template
<div v-if="scope.row.BeforeQuestionList.length>index && scope.row.BeforeQuestionList[index].Answer" :style="{color: scope.row.BeforeQuestionList[index].IsGlobalAnswer ? '#f66' : null}"> v-if="(scope.row.IsBaseLine && (scope.row.BeforeQuestionList[index].GlobalReadingShowType === 1 || scope.row.BeforeQuestionList[index].GlobalReadingShowType === 5)) || (!scope.row.IsBaseLine && (scope.row.BeforeQuestionList[index].GlobalReadingShowType === 2 || scope.row.BeforeQuestionList[index].GlobalReadingShowType === 6)) || (scope.row.BeforeQuestionList[index].GlobalReadingShowType === 0 || scope.row.BeforeQuestionList[index].GlobalReadingShowType === 4)">
<div v-if="scope.row.BeforeQuestionList.length > index && scope.row.BeforeQuestionList[index].Answer"
:style="{ color: scope.row.BeforeQuestionList[index].IsGlobalAnswer ? '#f66' : null }">
<span v-if="scope.row.BeforeQuestionList[index].DictionaryCode"> <span v-if="scope.row.BeforeQuestionList[index].DictionaryCode">
{{ $fd(scope.row.BeforeQuestionList[index].DictionaryCode,parseInt(scope.row.BeforeQuestionList[index].Answer)) }} {{
$fd(scope.row.BeforeQuestionList[index].DictionaryCode, parseInt(scope.row.BeforeQuestionList[index].Answer))
}}
</span> </span>
<span v-else>{{ scope.row.BeforeQuestionList[index].Answer }}</span> <span v-else>{{ scope.row.BeforeQuestionList[index].Answer }}</span>
</div> </div>
@ -49,211 +36,145 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- 是否同意访视结果 --> <!-- 是否同意访视结果 -->
<el-table-column <el-table-column prop="" :label="$t('trials:globalReview:table:isAgreeEvaluationRes')" show-overflow-tooltip
prop="" width="170">
:label="$t('trials:globalReview:table:isAgreeEvaluationRes')"
show-overflow-tooltip
width="170"
>
<template slot-scope="scope"> <template slot-scope="scope">
<el-form-item <el-form-item v-if="readingTaskState < 2" :prop="`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`"
v-if="readingTaskState<2" label="" :rules="[
:prop="`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`" { required: true, message: $t('common:ruleMessage:select'), trigger: ['change', 'blur'] },
label="" ]" class="form-item">
:rules="[ <el-radio-group v-model="globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]"
{ required: true,message: $t('common:ruleMessage:select'), trigger: ['change','blur']}, @change="handleAgreeOrNotChange(scope.$index, scope.row.AgreeOrNot[0].GlobalAnswerType)">
]" <el-radio v-for="item of $d.ReadingYesOrNo" :key="'AgreeOrNot' + item.value" :label="String(item.value)">
class="form-item"
>
<el-radio-group
v-model="globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]"
@change="handleAgreeOrNotChange(scope.$index,scope.row.AgreeOrNot[0].GlobalAnswerType)"
>
<el-radio
v-for="item of $d.ReadingYesOrNo"
:key="'AgreeOrNot' + item.value"
:label="String(item.value)"
>
{{ item.label }} {{ item.label }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-tag v-else-if="scope.row.AgreeOrNot.length > 0 && parseInt(scope.row.AgreeOrNot[0].Answer) === 1" type="primary"> <el-tag v-else-if="scope.row.AgreeOrNot.length > 0 && parseInt(scope.row.AgreeOrNot[0].Answer) === 1"
{{ $fd('ReadingYesOrNo',parseInt(scope.row.AgreeOrNot[0].Answer)) }} type="primary">
{{ $fd('ReadingYesOrNo', parseInt(scope.row.AgreeOrNot[0].Answer)) }}
</el-tag> </el-tag>
<el-tag v-else-if="scope.row.AgreeOrNot.length > 0 && parseInt(scope.row.AgreeOrNot[0].Answer) === 0" type="danger"> {{ $fd('ReadingYesOrNo',parseInt(scope.row.AgreeOrNot[0].Answer)) }}</el-tag> <el-tag v-else-if="scope.row.AgreeOrNot.length > 0 && parseInt(scope.row.AgreeOrNot[0].Answer) === 0"
type="danger"> {{ $fd('ReadingYesOrNo', parseInt(scope.row.AgreeOrNot[0].Answer)) }}</el-tag>
<span v-else /> <span v-else />
</template> </template>
</el-table-column> </el-table-column>
<!-- 调整后结果 --> <!-- 调整后结果 -->
<el-table-column <el-table-column :label="$t('trials:globalReview:table:adjustedRes')" align="center" prop="">
:label="$t('trials:globalReview:table:adjustedRes')" <template v-for="(qs, index) in globalInfo.adjustedQsList">
align="center" <el-table-column v-if="qs.isShow" :key="index" prop="" :label="qs.questionName" show-overflow-tooltip
prop="" :min-width="index === 3 ? '200' : '200'">
>
<template v-for="(qs,index) in globalInfo.adjustedQsList">
<el-table-column
v-if="qs.isShow"
:key="index"
prop=""
:label="qs.questionName"
show-overflow-tooltip
:min-width="index === 3 ? '200' : '200'"
>
<template slot-scope="scope"> <template slot-scope="scope">
<div v-if="readingTaskState<2 && (scope.row.AfterQuestionList[index].GlobalReadingShowType === 0 || (scope.row.IsBaseLine && scope.row.AfterQuestionList[index].GlobalReadingShowType === 1) || (!scope.row.IsBaseLine && scope.row.AfterQuestionList[index].GlobalReadingShowType === 2))"> <div
v-if="readingTaskState < 2 && (scope.row.AfterQuestionList[index].GlobalReadingShowType === 0 || (scope.row.IsBaseLine && scope.row.AfterQuestionList[index].GlobalReadingShowType === 1) || (!scope.row.IsBaseLine && scope.row.AfterQuestionList[index].GlobalReadingShowType === 2))">
<!-- <span v-if="(scope.row.IsBaseLine && scope.row.AfterQuestionList[index].LimitEdit === 2) || (!scope.row.IsBaseLine && scope.row.AfterQuestionList[index].LimitEdit === 1)"> <!-- <span v-if="(scope.row.IsBaseLine && scope.row.AfterQuestionList[index].LimitEdit === 2) || (!scope.row.IsBaseLine && scope.row.AfterQuestionList[index].LimitEdit === 1)">
{{ $fd(scope.row.AfterQuestionList[index].DictionaryCode, parseInt(scope.row.AfterQuestionList[index].VisitAnswer)) }} {{ $fd(scope.row.AfterQuestionList[index].DictionaryCode, parseInt(scope.row.AfterQuestionList[index].VisitAnswer)) }}
</span> --> </span> -->
<el-form-item <el-form-item style="margin-bottom: 0;"
style="margin-bottom: 0;" :prop="`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId ? scope.row.AfterQuestionList[index].QuestionId : scope.row.AfterQuestionList[index].GlobalAnswerType}`"
:prop="`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:scope.row.AfterQuestionList[index].GlobalAnswerType}`" label="" :rules="[
label="" { required: parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) === 0, message: $t('common:ruleMessage:specify'), trigger: ['change', 'blur'] },
:rules="[ ]">
{ required:parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) === 0,message: $t('common:ruleMessage:specify'), trigger: ['change','blur']}, <label
]" v-if="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) === 0" />
>
<label v-if="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) === 0" />
<!-- 裁判问题 --> <!-- 裁判问题 -->
<template v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 0 "> <template v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 0">
<el-tooltip v-if="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`], scope.row.AfterQuestionList[index])" class="item" effect="dark" :content="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`], scope.row.AfterQuestionList[index])" placement="top-start"> <el-tooltip
v-if="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId ? scope.row.AfterQuestionList[index].QuestionId : String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`], scope.row.AfterQuestionList[index])"
class="item" effect="dark"
:content="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId ? scope.row.AfterQuestionList[index].QuestionId : String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`], scope.row.AfterQuestionList[index])"
placement="top-start">
<el-select <el-select
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`]" v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId ? scope.row.AfterQuestionList[index].QuestionId : String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`]"
style="width:90%;" style="width:90%;"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0" :disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0">
>
<template v-if="scope.row.AfterQuestionList[index].TypeValue"> <template v-if="scope.row.AfterQuestionList[index].TypeValue">
<el-option <el-option v-for="val in scope.row.AfterQuestionList[index].TypeValue.split('|')" :key="val"
v-for="val in scope.row.AfterQuestionList[index].TypeValue.split('|')" :label="val" :value="val" />
:key="val"
:label="val"
:value="val"
/>
</template> </template>
<template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode && scope.row.AfterQuestionList[index].QuestionType === 13"> <template
<el-option v-else-if="scope.row.AfterQuestionList[index].DictionaryCode && scope.row.AfterQuestionList[index].QuestionType === 13">
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]" <el-option v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-show="item.value!==-1" v-show="item.value !== -1" :key="item.id" :value="String(item.value)" :label="item.label"
:key="item.id" :disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName, scope.row)) === String(item.value)" />
:value="String(item.value)"
:label="item.label"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
/>
</template> </template>
<template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode"> <template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode">
<el-option <el-option v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]" :key="item.id" :value="String(item.value)"
:key="item.id" :disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName, scope.row)) === String(item.value)"
:value="String(item.value)" :label="item.label" />
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
:label="item.label"
/>
</template> </template>
</el-select> </el-select>
</el-tooltip> </el-tooltip>
<el-select <el-select v-else
v-else v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId ? scope.row.AfterQuestionList[index].QuestionId : String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`]"
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`]"
style="width:90%;" style="width:90%;"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0" :disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0">
>
<template v-if="scope.row.AfterQuestionList[index].TypeValue"> <template v-if="scope.row.AfterQuestionList[index].TypeValue">
<el-option <el-option v-for="val in scope.row.AfterQuestionList[index].TypeValue.split('|')" :key="val"
v-for="val in scope.row.AfterQuestionList[index].TypeValue.split('|')" :label="val" :value="val" />
:key="val"
:label="val"
:value="val"
/>
</template> </template>
<template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode && scope.row.AfterQuestionList[index].QuestionType === 13"> <template
<template v-if="getLesionCount(scope.row.LesionCountList,0)"> v-else-if="scope.row.AfterQuestionList[index].DictionaryCode && scope.row.AfterQuestionList[index].QuestionType === 13">
<el-option <template v-if="getLesionCount(scope.row.LesionCountList, 0)">
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]" <el-option v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-show="item.value!==-1 && item.value !== 1 && item.value !== 3" v-show="item.value !== -1 && item.value !== 1 && item.value !== 3" :key="item.id"
:key="item.id" :value="String(item.value)" :label="item.label"
:value="String(item.value)" :disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName, scope.row)) === String(item.value)" />
:label="item.label"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
/>
</template> </template>
<template v-else-if="getLesionCount(scope.row.LesionCountList,1)"> <template v-else-if="getLesionCount(scope.row.LesionCountList, 1)">
<el-option <el-option v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]" v-show="item.value !== -1 && item.value !== 1 && item.value !== 6" :key="item.id"
v-show="item.value!==-1 && item.value !== 1 && item.value !== 6" :value="String(item.value)" :label="item.label"
:key="item.id" :disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName, scope.row)) === String(item.value)" />
:value="String(item.value)"
:label="item.label"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
/>
</template> </template>
<template v-else> <template v-else>
<el-option <el-option v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]" v-show="item.value === 1 || item.value === 2 || item.value === 4" :key="item.id"
v-show="item.value === 1 || item.value === 2 || item.value === 4" :value="String(item.value)" :label="item.label"
:key="item.id" :disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName, scope.row)) === String(item.value)" />
:value="String(item.value)"
:label="item.label"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
/>
</template> </template>
</template> </template>
<template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode"> <template v-else-if="scope.row.AfterQuestionList[index].DictionaryCode">
<el-option <el-option v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]"
v-for="item of $d[scope.row.AfterQuestionList[index].DictionaryCode]" v-show="item.value !== 6" :key="item.id" :value="String(item.value)"
v-show="item.value !== 6" :disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName, scope.row)) === String(item.value)"
:key="item.id" :label="item.label" />
:value="String(item.value)"
:disabled="String(getBeforeAnswer(scope.row.AfterQuestionList[index].QuestionName,scope.row)) === String(item.value)"
:label="item.label"
/>
</template> </template>
</el-select> </el-select>
</template> </template>
<!-- 评估更新类型 GlobalAnswerType:3 --> <!-- 评估更新类型 GlobalAnswerType:3 -->
<template v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 3"> <template v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 3">
<el-tooltip v-if="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`], scope.row.AfterQuestionList[index], scope.row.AfterQuestionList[index].GlobalAnswerType)" class="item" effect="dark" :content="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`], scope.row.AfterQuestionList[index], scope.row.AfterQuestionList[index].GlobalAnswerType)" placement="top-start"> <el-tooltip
v-if="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`], scope.row.AfterQuestionList[index], scope.row.AfterQuestionList[index].GlobalAnswerType)"
class="item" effect="dark"
:content="getText(globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`], scope.row.AfterQuestionList[index], scope.row.AfterQuestionList[index].GlobalAnswerType)"
placement="top-start">
<el-select <el-select
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`]" v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`]"
style="width:90%;" style="width:90%;"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0" :disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0">
> <el-option v-for="val in globalInfo.assessTypeList"
<el-option
v-for="val in globalInfo.assessTypeList"
v-show="(scope.row.IsBaseLine && val.IsBaseLineUse) || (!scope.row.IsBaseLine && val.IsFollowVisitUse)" v-show="(scope.row.IsBaseLine && val.IsBaseLineUse) || (!scope.row.IsBaseLine && val.IsFollowVisitUse)"
:key="val.Code" :key="val.Code" :label="language === 'en' ? val.Value : val.ValueCN" :value="val.Code" />
:label="language === 'en'?val.Value:val.ValueCN"
:value="val.Code"
/>
</el-select> </el-select>
</el-tooltip> </el-tooltip>
<el-select <el-select v-else
v-else
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`]" v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].GlobalAnswerType}`]"
style="width:90%;" style="width:90%;"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0" :disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0">
> <el-option v-for="val in globalInfo.assessTypeList"
<el-option
v-for="val in globalInfo.assessTypeList"
v-show="(scope.row.IsBaseLine && val.IsBaseLineUse) || (!scope.row.IsBaseLine && val.IsFollowVisitUse)" v-show="(scope.row.IsBaseLine && val.IsBaseLineUse) || (!scope.row.IsBaseLine && val.IsFollowVisitUse)"
:key="val.Code" :key="val.Code" :label="language === 'en' ? val.Value : val.ValueCN" :value="val.Code" />
:label="language === 'en'?val.Value:val.ValueCN"
:value="val.Code"
/>
</el-select> </el-select>
</template> </template>
<el-input <el-input v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 1"
v-if="scope.row.AfterQuestionList[index].GlobalAnswerType === 1" v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId ? scope.row.AfterQuestionList[index].QuestionId : String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`]"
v-model="globalForm[`${scope.$index}${scope.row.AfterQuestionList[index].QuestionId?scope.row.AfterQuestionList[index].QuestionId:String(scope.row.AfterQuestionList[index].GlobalAnswerType)}`]" type="textarea" maxlength="100" show-word-limit style="width:90%;" :autosize="{ minRows: 2 }"
type="textarea" :disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0" />
maxlength="100"
show-word-limit
style="width:90%;"
:autosize="{ minRows: 2 }"
:disabled="parseInt(globalForm[`${scope.$index}${scope.row.AgreeOrNot[0].GlobalAnswerType}`]) !== 0"
/>
</el-form-item> </el-form-item>
</div> </div>
<div v-else> <div v-else>
@ -262,7 +183,9 @@
{{ getAssessType(scope.row.AfterQuestionList[index].Answer) }} {{ getAssessType(scope.row.AfterQuestionList[index].Answer) }}
</span> </span>
<span v-else-if="scope.row.AfterQuestionList[index].DictionaryCode"> <span v-else-if="scope.row.AfterQuestionList[index].DictionaryCode">
{{ $fd(scope.row.AfterQuestionList[index].DictionaryCode,parseInt(scope.row.AfterQuestionList[index].Answer)) }} {{
$fd(scope.row.AfterQuestionList[index].DictionaryCode, parseInt(scope.row.AfterQuestionList[index].Answer))
}}
</span> </span>
<span v-else>{{ scope.row.AfterQuestionList[index].Answer }}</span> <span v-else>{{ scope.row.AfterQuestionList[index].Answer }}</span>
</div> </div>
@ -270,17 +193,10 @@
</el-table-column> </el-table-column>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column :label="$t('common:action:action')" width="100">
:label="$t('common:action:action')"
width="100"
>
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button circle :title="$t('trials:globalReview:table:view')" icon="el-icon-view"
circle @click="handleView(scope.row)" />
:title="$t('trials:globalReview:table:view')"
icon="el-icon-view"
@click="handleView(scope.row)"
/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -348,7 +264,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2 ) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
@ -375,16 +291,18 @@ export default {
if (i.QuestionId) { if (i.QuestionId) {
obj.questionId = i.QuestionId obj.questionId = i.QuestionId
obj.globalAnswerType = i.GlobalAnswerType obj.globalAnswerType = i.GlobalAnswerType
obj.answer = this.globalForm[ `${index}${i.QuestionId}`] obj.answer = this.globalForm[`${index}${i.QuestionId}`]
} else { } else {
obj.questionId = '' obj.questionId = ''
obj.globalAnswerType = i.GlobalAnswerType obj.globalAnswerType = i.GlobalAnswerType
obj.answer = this.globalForm[ `${index}${i.GlobalAnswerType}`] obj.answer = this.globalForm[`${index}${i.GlobalAnswerType}`]
} }
answerList.push(obj) answerList.push(obj)
}) })
answerList.push({ questionId: '', globalAnswerType: item.AgreeOrNot[0].GlobalAnswerType, answerList.push({
answer: this.globalForm[ `${index}${item.AgreeOrNot[0].GlobalAnswerType}`] }) questionId: '', globalAnswerType: item.AgreeOrNot[0].GlobalAnswerType,
answer: this.globalForm[`${index}${item.AgreeOrNot[0].GlobalAnswerType}`]
})
visitTaskAnswerList.push({ visitTaskId: item.VisitTaskId, answerList: answerList }) visitTaskAnswerList.push({ visitTaskId: item.VisitTaskId, answerList: answerList })
}) })
@ -405,7 +323,7 @@ export default {
} else { } else {
resolve(false) resolve(false)
} }
} catch(e) { } catch (e) {
console.log(e) console.log(e)
this.loading = false this.loading = false
resolve(false) resolve(false)
@ -462,18 +380,22 @@ export default {
color: #F56C6C; color: #F56C6C;
margin-right: 4px; margin-right: 4px;
} }
::v-deep .el-textarea .el-input__count{
background: rgba(0,0,0,0); ::v-deep .el-textarea .el-input__count {
background: rgba(0, 0, 0, 0);
line-height: normal; line-height: normal;
} }
::v-deep .el-form-item{
::v-deep .el-form-item {
margin-bottom: 0px; margin-bottom: 0px;
} }
.global-form{
::v-deep .el-form-item__content{ .global-form {
::v-deep .el-form-item__content {
padding-bottom: 10px; padding-bottom: 10px;
} }
::v-deep .form-item .el-form-item__error{
::v-deep .form-item .el-form-item__error {
top: 60%; top: 60%;
} }
} }

View File

@ -355,7 +355,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2 ) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`

View File

@ -349,7 +349,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2 ) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.globalInfo.trialId}&subjectCode=${this.globalInfo.subjectCode}&subjectId=${this.globalInfo.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`

View File

@ -404,7 +404,7 @@ export default {
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool) readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool)
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2) { if (readingTool === 0 || readingTool === 2|| readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`

View File

@ -250,7 +250,7 @@ export default {
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId; var trialReadingCriterionId = this.rowData.TrialReadingCriterionId;
var path = ""; var path = "";
if (readingTool === 0 || readingTool === 2) { if (readingTool === 0 || readingTool === 2|| readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode
}&subjectId=${this.rowData.SubjectId }&subjectId=${this.rowData.SubjectId
}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`; }&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`;
@ -273,7 +273,7 @@ export default {
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId; var trialReadingCriterionId = this.rowData.TrialReadingCriterionId;
var path = ""; var path = "";
if (readingTool === 0 || readingTool === 2) { if (readingTool === 0 || readingTool === 2|| readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode
}&subjectId=${this.rowData.SubjectId}&visitTaskId=${task.VisitTaskId }&subjectId=${this.rowData.SubjectId}&visitTaskId=${task.VisitTaskId
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`; }&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`;

View File

@ -258,7 +258,7 @@ export default {
var isReadingTaskViewInOrder = this.rowData.IsReadingTaskViewInOrder var isReadingTaskViewInOrder = this.rowData.IsReadingTaskViewInOrder
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId var trialReadingCriterionId = this.rowData.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2) { if (readingTool === 0 || readingTool === 2|| readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`

View File

@ -146,7 +146,7 @@ export default {
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId var trialReadingCriterionId = this.rowData.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2) { if (readingTool === 0 || readingTool === 2|| readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`

View File

@ -164,7 +164,7 @@ export default {
var trialReadingCriterionId = this.rowData.TrialReadingCriterionId var trialReadingCriterionId = this.rowData.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.rowData.SubjectCode}&subjectId=${this.rowData.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`

View File

@ -795,7 +795,7 @@ export default {
var trialReadingCriterionId = row.TrialReadingCriterionId var trialReadingCriterionId = row.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2 ) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`

View File

@ -452,7 +452,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = '' var path = ''
if (readingTool === 0 || readingTool === 2) { if (readingTool === 0 || readingTool === 2 || readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`

View File

@ -953,7 +953,7 @@ export default {
lookReadingResults(row) { lookReadingResults(row) {
var token = getToken() var token = getToken()
var path var path
if (row.ReadingTool === 0 || row.ReadingTool === 2) { if (row.ReadingTool === 0 || row.ReadingTool === 2|| row.ReadingTool === 3) {
path = `/readingDicoms?trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}` path = `/readingDicoms?trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}` path = `/noneDicomReading?trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`

View File

@ -435,7 +435,7 @@ export default {
window.localStorage.setItem('TrialReadingCriterionId', this.TrialReadingCriterionId) window.localStorage.setItem('TrialReadingCriterionId', this.TrialReadingCriterionId)
var token = getToken() var token = getToken()
var path = '' var path = ''
if (row.ReadingTool === 0 || row.ReadingTool === 2) { if (row.ReadingTool === 0 || row.ReadingTool === 2 || row.ReadingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`

View File

@ -32,7 +32,7 @@ export default {
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
var criterionType = this.$router.currentRoute.query.criterionType var criterionType = this.$router.currentRoute.query.criterionType
var path = '' var path = ''
if (this.readingTool === 0 || this.readingTool === 2 ) { if (this.readingTool === 0 || this.readingTool === 2 || this.readingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${TrialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${this.readingTool}&TokenKey=${this.token}` path = `/readingDicoms?TrialReadingCriterionId=${TrialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${this.readingTool}&TokenKey=${this.token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${TrialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${this.readingTool}&TokenKey=${this.token}` path = `/noneDicomReading?TrialReadingCriterionId=${TrialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${this.readingTool}&TokenKey=${this.token}`

View File

@ -368,7 +368,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) {
path = `/readingDicoms?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${this.trialId}&isReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}&criterionType=${this.criterionType}&readingTool=${this.readingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${this.trialId}&isReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}&criterionType=${this.criterionType}&readingTool=${this.readingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${this.trialId}&isReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}&criterionType=${this.criterionType}&readingTool=${this.readingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${this.trialId}&isReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}&criterionType=${this.criterionType}&readingTool=${this.readingTool}&TokenKey=${token}`

View File

@ -614,7 +614,7 @@ export default {
} }
var token = getToken() var token = getToken()
var path var path
if (row.ReadingTool === 0 || row.ReadingTool === 2) { if (row.ReadingTool === 0 || row.ReadingTool === 2|| row.ReadingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`

View File

@ -1202,7 +1202,7 @@ export default {
} }
var token = getToken() var token = getToken()
var path var path
if (row.ReadingTool === 0 || row.ReadingTool === 2) { if (row.ReadingTool === 0 || row.ReadingTool === 2 || row.ReadingTool === 3) {
path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}` path = `/readingDicoms?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`
} else { } else {
path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}` path = `/noneDicomReading?TrialReadingCriterionId=${row.TrialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${row.SubjectCode}&subjectId=${row.SubjectId}&visitTaskId=${row.Id}&isReadingTaskViewInOrder=${row.IsReadingTaskViewInOrder}&criterionType=${row.CriterionType}&readingTool=${row.ReadingTool}&TokenKey=${token}`

View File

@ -4,123 +4,63 @@
<template> <template>
<el-form v-loading="loading"> <el-form v-loading="loading">
<!-- 仲裁对象 --> <!-- 仲裁对象 -->
<el-form-item <el-form-item :label="$t('trials:adRules:title:arbitrationRule')" :label-width="'180px'">
:label="$t('trials:adRules:title:arbitrationRule')" <el-radio-group v-model="JudgyInfo.ArbitrationRule" :disabled="OtherInfo.IsSign">
:label-width="'180px'" <el-radio v-for="item of $d.ArbitrationRule" :key="item.id"
> :disabled="!JudgyInfo.IsReadingTaskViewInOrder || true" :label="item.value" @change="changeArbitrationRule">
<el-radio-group
v-model="JudgyInfo.ArbitrationRule"
:disabled="OtherInfo.IsSign"
>
<el-radio
v-for="item of $d.ArbitrationRule"
:key="item.id"
:disabled="!JudgyInfo.IsReadingTaskViewInOrder || true"
:label="item.value"
@change="changeArbitrationRule"
>
{{ item.label }} {{ item.label }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-collapse v-model="activeNames" style="border-top:none;"> <el-collapse v-model="activeNames" style="border-top:none;">
<el-collapse-item <el-collapse-item v-for="(item, index) of QuestionList" :key="item.ReadingQuestionTrialId"
v-for="(item, index) of QuestionList" style="position: relative;padding:0 10px;" :name="item.ReadingQuestionTrialId">
:key="item.ReadingQuestionTrialId"
style="position: relative;padding:0 10px;"
:name="item.ReadingQuestionTrialId"
>
<div slot="title"> <div slot="title">
{{ item.PageName }}Q{{ index + 1 }}{{ item.QuestionName }} {{ item.PageName }}Q{{ index + 1 }}{{ item.QuestionName }}
</div> </div>
<div style="position: relative"> <div style="position: relative">
<el-button <el-button v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']"
v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']" style="position: absolute; right: 0; top: 0; z-index: 10" size="mini" type="primary"
style="position: absolute; right: 0; top: 0; z-index: 10" :disabled="OtherInfo.IsSign" @click="apply(item.ReadingQuestionTrialId, index)">{{ $t('common:button:save')
size="mini" }}</el-button>
type="primary" <el-button v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']"
:disabled="OtherInfo.IsSign" style="position: absolute; right: 60px; top: 0; z-index: 10" size="mini" type="primary"
@click="apply(item.ReadingQuestionTrialId, index)" :disabled="OtherInfo.IsSign" @click="reset(item.ReadingQuestionTrialId, index)">{{ $t('common:button:reset')
>{{ $t('common:button:save') }}</el-button }}</el-button>
>
<el-button
v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']"
style="position: absolute; right: 60px; top: 0; z-index: 10"
size="mini"
type="primary"
:disabled="OtherInfo.IsSign"
@click="reset(item.ReadingQuestionTrialId, index)"
>{{ $t('common:button:reset') }}</el-button
>
<!-- 产生裁判阅片的条件 --> <!-- 产生裁判阅片的条件 -->
<el-form-item <el-form-item :label-width="'280px'" :label="$t('trials:adRules:title:judgeTypeEnum')" style="width: 95%">
:label-width="'280px'" <el-radio-group v-model="QuestionList[index].JudgeType" @input="(val) => JudgeTypeChange(val, index)">
:label="$t('trials:adRules:title:judgeTypeEnum')"
style="width: 95%"
>
<el-radio-group
v-model="QuestionList[index].JudgeType"
@input="(val) => JudgeTypeChange(val, index)"
>
<template v-for="item of $d.JudgeTypeEnum"> <template v-for="item of $d.JudgeTypeEnum">
<el-radio <el-radio style="margin-bottom: 5px" :key="item.id" :disabled="OtherInfo.IsSign ||
style="margin-bottom: 5px"
:key="item.id"
:disabled="
OtherInfo.IsSign ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) !hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
" " :label="item.value" v-if="
:label="item.value"
v-if="
item.value < 4 || item.value < 4 ||
(item.value > 3 && (item.value > 3 &&
(QuestionList[index].Type === 'number' || (QuestionList[index].Type === 'number' ||
QuestionList[index].Type === 'calculation')) QuestionList[index].Type === 'calculation'))
" ">
>
{{ item.label }} {{ item.label }}
</el-radio> </el-radio>
</template> </template>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</div> </div>
<div <div v-if="QuestionList[index].JudgeType === 3" style="text-align: right; margin: 10px 0">
v-if="QuestionList[index].JudgeType === 3"
style="text-align: right; margin: 10px 0"
>
<!-- 添加规则 --> <!-- 添加规则 -->
<el-button <el-button v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']" size="mini" type="primary"
v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']" :disabled="OtherInfo.IsSign" @click="addGroup(index, null)">{{ $t('trials:adRules:button:addRule')
size="mini" }}</el-button>
type="primary"
:disabled="OtherInfo.IsSign"
@click="addGroup(index, null)"
>{{ $t('trials:adRules:button:addRule') }}</el-button
>
</div> </div>
<el-table <el-table v-if="QuestionList[index].JudgeType === 3" v-loading="loading"
v-if="QuestionList[index].JudgeType === 3" :data="QuestionList[index].AnswerGroupList" border stripe>
v-loading="loading"
:data="QuestionList[index].AnswerGroupList"
border
stripe
>
<!-- 序号 --> <!-- 序号 -->
<el-table-column <el-table-column prop="AnswerGroupA" :label="$t('trials:adRules:title:order')" width="160">
prop="AnswerGroupA"
:label="$t('trials:adRules:title:order')"
width="160"
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ scope.$index + 1 }} {{ scope.$index + 1 }}
</template> </template>
</el-table-column> </el-table-column>
<!-- 阅片人A --> <!-- 阅片人A -->
<el-table-column <el-table-column prop="AnswerGroupA" :label="$t('trials:adRules:title:answerGroupA')" min-width="100">
prop="AnswerGroupA"
:label="$t('trials:adRules:title:answerGroupA')"
min-width="100"
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ {{
QuestionList[index].QuestionGenre === 3 QuestionList[index].QuestionGenre === 3
@ -132,11 +72,7 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- 阅片人B --> <!-- 阅片人B -->
<el-table-column <el-table-column prop="AnswerGroupB" :label="$t('trials:adRules:title:answerGroupB')" min-width="100">
prop="AnswerGroupB"
:label="$t('trials:adRules:title:answerGroupB')"
min-width="100"
>
<template slot-scope="scope"> <template slot-scope="scope">
{{ {{
QuestionList[index].QuestionGenre === 3 QuestionList[index].QuestionGenre === 3
@ -147,83 +83,48 @@
}} }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column prop="AnswerGroupB" :label="$t('common:action:action')" min-width="80">
prop="AnswerGroupB"
:label="$t('common:action:action')"
min-width="80"
>
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 编辑 --> <!-- 编辑 -->
<el-button <el-button icon="el-icon-edit" circle :title="$t('common:button:edit')" size="mini"
icon="el-icon-edit" :disabled="OtherInfo.IsSign" @click="addGroup(index, scope.$index)" />
circle
:title="$t('common:button:edit')"
size="mini"
:disabled="OtherInfo.IsSign"
@click="addGroup(index, scope.$index)"
/>
<!-- 删除 --> <!-- 删除 -->
<el-button <el-button icon="el-icon-delete" circle :title="$t('common:button:delete')" size="mini"
icon="el-icon-delete" :disabled="OtherInfo.IsSign" @click="tagClose(index, scope.$index)" />
circle
:title="$t('common:button:delete')"
size="mini"
:disabled="OtherInfo.IsSign"
@click="tagClose(index, scope.$index)"
/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div v-if="QuestionList[index].JudgeType === 2"> <div v-if="QuestionList[index].JudgeType === 2">
<div <div style="
style="
background: #f6f6f6; background: #f6f6f6;
border-radius: 20px; border-radius: 20px;
padding: 15px 20px; padding: 15px 20px;
margin-top: 10px; margin-top: 10px;
" ">
> <el-checkbox-group v-if="QuestionList[index].QuestionGenre === 3" v-model="QuestionList[index].grouping">
<el-checkbox-group
v-if="QuestionList[index].QuestionGenre === 3"
v-model="QuestionList[index].grouping"
>
<template v-for="item of $d[QuestionList[index].DictionaryCode]"> <template v-for="item of $d[QuestionList[index].DictionaryCode]">
<el-checkbox <el-checkbox v-if="item.value !== -1" :key="item.id" :disabled="OtherInfo.IsSign" :label="item.value">{{
v-if="item.value !== -1" item.label }}</el-checkbox>
:key="item.id"
:disabled="OtherInfo.IsSign"
:label="item.value"
>{{ item.label }}</el-checkbox
>
</template> </template>
</el-checkbox-group> </el-checkbox-group>
<el-checkbox-group v-else v-model="QuestionList[index].grouping"> <el-checkbox-group v-else v-model="QuestionList[index].grouping">
<el-checkbox <el-checkbox v-for="item of item.TypeValue.split('|')" :key="item" :disabled="OtherInfo.IsSign"
v-for="item of item.TypeValue.split('|')" :label="item">{{
:key="item" item }}</el-checkbox>
:disabled="OtherInfo.IsSign"
:label="item"
>{{ item }}</el-checkbox
>
</el-checkbox-group> </el-checkbox-group>
<div style="margin-top: 20px"> <div style="margin-top: 20px">
<!-- 当前选择答案分组: --> <!-- 当前选择答案分组: -->
{{ $t('trials:adRules:title:selectAnswerGroup') }} {{ $t('trials:adRules:title:selectAnswerGroup') }}
<el-tag <el-tag v-if="
v-if="
QuestionList[index].grouping.length > 0 && QuestionList[index].grouping.length > 0 &&
QuestionList[index].QuestionGenre !== 3 QuestionList[index].QuestionGenre !== 3
" ">{{
>{{
QuestionList[index].grouping.toString().replaceAll(',', '|') QuestionList[index].grouping.toString().replaceAll(',', '|')
}}</el-tag }}</el-tag>
> <el-tag v-if="
<el-tag
v-if="
QuestionList[index].grouping.length > 0 && QuestionList[index].grouping.length > 0 &&
QuestionList[index].QuestionGenre === 3 QuestionList[index].QuestionGenre === 3
" ">{{
>{{
QuestionList[index].grouping QuestionList[index].grouping
.map( .map(
(v) => (v) =>
@ -233,54 +134,31 @@
) )
.toString() .toString()
.replaceAll(',', '|') .replaceAll(',', '|')
}}</el-tag }}</el-tag>
> <el-button size="mini" type="primary" :disabled="OtherInfo.IsSign" @click="addGroup2(index)">
<el-button
size="mini"
type="primary"
:disabled="OtherInfo.IsSign"
@click="addGroup2(index)"
>
<!-- 添加分组 --> <!-- 添加分组 -->
{{ $t('trials:adRules:title:addGroup') }} {{ $t('trials:adRules:title:addGroup') }}
</el-button> </el-button>
</div> </div>
</div> </div>
<div <div v-if="QuestionList[index].QuestionGenre !== 3" style="margin-top: 20px">
v-if="QuestionList[index].QuestionGenre !== 3"
style="margin-top: 20px"
>
{{ $t('trials:adRules:title:group') }} {{ $t('trials:adRules:title:group') }}
<el-tag <el-tag v-for="itemA of QuestionList[index].AnswerGroup2List" :key="itemA" closable
v-for="itemA of QuestionList[index].AnswerGroup2List" style="margin-right: 10px" @close="
:key="itemA"
closable
style="margin-right: 10px"
@close="
() => { () => {
return tagClose2(index, indexA) return tagClose2(index, indexA)
} }
" ">{{ itemA }}</el-tag>
>{{ itemA }}</el-tag
>
</div> </div>
<div <div v-if="QuestionList[index].QuestionGenre === 3" style="margin-top: 20px">
v-if="QuestionList[index].QuestionGenre === 3"
style="margin-top: 20px"
>
<!-- 分组: --> <!-- 分组: -->
{{ $t('trials:adRules:title:group') }} {{ $t('trials:adRules:title:group') }}
<el-tag <el-tag v-for="itemA of QuestionList[index].AnswerGroup2List" :key="itemA" closable
v-for="itemA of QuestionList[index].AnswerGroup2List" style="margin-right: 10px" @close="
:key="itemA"
closable
style="margin-right: 10px"
@close="
() => { () => {
return tagClose2(index, indexA) return tagClose2(index, indexA)
} }
" ">
>
{{ {{
itemA itemA
.split('|') .split('|')
@ -292,58 +170,31 @@
</el-tag> </el-tag>
</div> </div>
</div> </div>
<div <div v-if="
v-if="
QuestionList[index].JudgeType === 4 || QuestionList[index].JudgeType === 4 ||
QuestionList[index].JudgeType === 5 QuestionList[index].JudgeType === 5
" ">
> <el-form :inline="true" :model="QuestionList[index]" class="demo-form-inline" :ref="'JudgeDifferenceValue' + QuestionList[index].JudgeType + index
<el-form " :rules="JudgeDifferenceValueQRules">
:inline="true" <el-form-item :label="$t(
:model="QuestionList[index]"
class="demo-form-inline"
:ref="
'JudgeDifferenceValue' + QuestionList[index].JudgeType + index
"
:rules="JudgeDifferenceValueQRules"
>
<el-form-item
:label="
$t(
`trials:trials-panel:setting:reading-unit:JudgeDifferenceType` `trials:trials-panel:setting:reading-unit:JudgeDifferenceType`
) )
" " prop="JudgeDifferenceType">
prop="JudgeDifferenceType" <el-select v-model="QuestionList[index].JudgeDifferenceType" placeholder="请选择"
> :disabled="OtherInfo.IsSign">
<el-select <el-option v-for="item of $d.JudgeDifferenceType" :key="item.id" :label="item.label"
v-model="QuestionList[index].JudgeDifferenceType" :value="item.value">
placeholder="请选择"
:disabled="OtherInfo.IsSign"
>
<el-option
v-for="item of $d.JudgeDifferenceType"
:key="item.id"
:label="item.label"
:value="item.value"
>
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item <el-form-item :label="$t(
:label="
$t(
`trials:trials-panel:setting:reading-unit:JudgeDifferenceValue${QuestionList[index].JudgeType}` `trials:trials-panel:setting:reading-unit:JudgeDifferenceValue${QuestionList[index].JudgeType}`
) )
" " prop="JudgeDifferenceValue">
prop="JudgeDifferenceValue"
>
<div style="display: flex"> <div style="display: flex">
<el-input <el-input v-model="QuestionList[index].JudgeDifferenceValue" clearable
v-model="QuestionList[index].JudgeDifferenceValue" :disabled="OtherInfo.IsSign"></el-input>
clearable <span style="margin-left: 10px" v-if="QuestionList[index].JudgeType !== 5">{{
:disabled="OtherInfo.IsSign"
></el-input>
<span style="margin-left: 10px">{{
$fd('ValueUnit', QuestionList[index].Unit) $fd('ValueUnit', QuestionList[index].Unit)
}}</span> }}</span>
</div> </div>
@ -355,124 +206,62 @@
<!-- </el-tab-pane>--> <!-- </el-tab-pane>-->
<!-- </el-tabs>--> <!-- </el-tabs>-->
<!-- 选择答案 --> <!-- 选择答案 -->
<el-dialog <el-dialog v-if="QuestionVisible" :title="$t('trials:adRules:title:selectAnswer')" :visible.sync="QuestionVisible"
v-if="QuestionVisible" width="800px" :close-on-click-modal="false" custom-class="base-dialog-wrapper" append-to-body>
:title="$t('trials:adRules:title:selectAnswer')"
:visible.sync="QuestionVisible"
width="800px"
:close-on-click-modal="false"
custom-class="base-dialog-wrapper"
append-to-body
>
<div class="base-dialog-body"> <div class="base-dialog-body">
<!-- 阅片人A --> <!-- 阅片人A -->
<el-form-item <el-form-item label-width="110px" :label="$t('trials:adRules:title:answerGroupA')">
label-width="110px"
:label="$t('trials:adRules:title:answerGroupA')"
>
<el-checkbox-group v-model="QuestionList[selectIndex].groupingA"> <el-checkbox-group v-model="QuestionList[selectIndex].groupingA">
<template <template v-for="item of QuestionList[selectIndex].TypeValue.split('|')">
v-for="item of QuestionList[selectIndex].TypeValue.split('|')" <el-checkbox v-if="QuestionList[selectIndex].QuestionGenre !== 3" :key="item" :label="item" :disabled="QuestionList[selectIndex].groupingB.length
>
<el-checkbox
v-if="QuestionList[selectIndex].QuestionGenre !== 3"
:key="item"
:label="item"
:disabled="
QuestionList[selectIndex].groupingB.length
? ~QuestionList[selectIndex].groupingB.indexOf(item) ? ~QuestionList[selectIndex].groupingB.indexOf(item)
: false : false
" ">{{ item }}</el-checkbox>
>{{ item }}</el-checkbox
>
</template> </template>
<template <template v-for="item of $d[QuestionList[selectIndex].DictionaryCode]">
v-for="item of $d[QuestionList[selectIndex].DictionaryCode]" <el-checkbox v-if="
>
<el-checkbox
v-if="
QuestionList[selectIndex].QuestionGenre === 3 && QuestionList[selectIndex].QuestionGenre === 3 &&
item.value !== -1 item.value !== -1
" " :key="item.id" :label="item.value" :disabled="QuestionList[selectIndex].groupingB.length
:key="item.id"
:label="item.value"
:disabled="
QuestionList[selectIndex].groupingB.length
? ~QuestionList[selectIndex].groupingB.indexOf(item.value) ? ~QuestionList[selectIndex].groupingB.indexOf(item.value)
: false : false
" ">{{ item.label }}</el-checkbox>
>{{ item.label }}</el-checkbox
>
</template> </template>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<!-- 阅片人B --> <!-- 阅片人B -->
<el-form-item <el-form-item label-width="110px" :label="$t('trials:adRules:title:answerGroupB')">
label-width="110px"
:label="$t('trials:adRules:title:answerGroupB')"
>
<el-checkbox-group v-model="QuestionList[selectIndex].groupingB"> <el-checkbox-group v-model="QuestionList[selectIndex].groupingB">
<template <template v-for="item of QuestionList[selectIndex].TypeValue.split('|')">
v-for="item of QuestionList[selectIndex].TypeValue.split('|')" <el-checkbox v-if="QuestionList[selectIndex].QuestionGenre !== 3" :key="item" :label="item" :disabled="QuestionList[selectIndex].groupingA.length
>
<el-checkbox
v-if="QuestionList[selectIndex].QuestionGenre !== 3"
:key="item"
:label="item"
:disabled="
QuestionList[selectIndex].groupingA.length
? ~QuestionList[selectIndex].groupingA.indexOf(item) ? ~QuestionList[selectIndex].groupingA.indexOf(item)
: false : false
" ">{{ item }}</el-checkbox>
>{{ item }}</el-checkbox
>
</template> </template>
<template <template v-for="item of $d[QuestionList[selectIndex].DictionaryCode]">
v-for="item of $d[QuestionList[selectIndex].DictionaryCode]" <el-checkbox v-if="
>
<el-checkbox
v-if="
QuestionList[selectIndex].QuestionGenre === 3 && QuestionList[selectIndex].QuestionGenre === 3 &&
item.value !== -1 item.value !== -1
" " :key="item.id" :label="item.value" :disabled="QuestionList[selectIndex].groupingA.length
:key="item.id"
:label="item.value"
:disabled="
QuestionList[selectIndex].groupingA.length
? ~QuestionList[selectIndex].groupingA.indexOf(item.value) ? ~QuestionList[selectIndex].groupingA.indexOf(item.value)
: false : false
" ">{{ item.label }}</el-checkbox>
>{{ item.label }}</el-checkbox
>
</template> </template>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
</div> </div>
<div <div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
class="base-dialog-footer"
style="text-align: right; margin-top: 10px"
>
<!-- 取消 --> <!-- 取消 -->
<el-button <el-button v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']" :disabled="btnLoading" size="small"
v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']" type="primary" @click="
:disabled="btnLoading"
size="small"
type="primary"
@click="
QuestionVisible = false QuestionVisible = false
$set(QuestionList[selectIndex], 'groupingA', []) $set(QuestionList[selectIndex], 'groupingA', [])
$set(QuestionList[selectIndex], 'groupingB', []) $set(QuestionList[selectIndex], 'groupingB', [])
" ">
>
{{ $t('common:button:cancel') }} {{ $t('common:button:cancel') }}
</el-button> </el-button>
<el-button <el-button v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']" :disabled="btnLoading" size="small"
v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']" type="primary" @click="save">
:disabled="btnLoading"
size="small"
type="primary"
@click="save"
>
{{ $t('common:button:save') }} {{ $t('common:button:save') }}
</el-button> </el-button>
</div> </div>

View File

@ -34,13 +34,22 @@
<el-form-item v-if="CriterionType === 0 && form.ReadingVersionEnum === 1" <el-form-item v-if="CriterionType === 0 && 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'])" @change="handleReadingToolListChange">
">
<el-checkbox v-for="tool in tools" :key="tool.toolName" :label="tool.toolName" name="ReadingToolList"> <el-checkbox v-for="tool in tools" :key="tool.toolName" :label="tool.toolName" name="ReadingToolList">
{{ $t(`${tool.i18nKey}`) }} {{ $t(`${tool.i18nKey}`) }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<!-- 定圆工具半径 -->
<el-form-item v-if="form.ReadingToolList.includes('FixedRadiusCircleROI')"
:label="$t('trials:readingUnit:readingRules:title:circleRadius')" prop="CircleRadius">
<el-input v-model="form.CircleRadius" @input="(val) => handleNumberInput(val, 'CircleRadius')" clearable
:disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
">
<template slot="append">mm</template>
</el-input>
</el-form-item>
<!--分割工具 && (form.ReadingTool === 0 || form.ReadingTool === 1 || form.ReadingTool === 2)--> <!--分割工具 && (form.ReadingTool === 0 || form.ReadingTool === 1 || form.ReadingTool === 2)-->
<el-form-item v-if="CriterionType === 0 && form.ReadingVersionEnum === 1 && form.ReadingTool === 3" <el-form-item v-if="CriterionType === 0 && form.ReadingVersionEnum === 1 && form.ReadingTool === 3"
:label="$t('trials:readingUnit:readingRules:title:segmentTool')"> :label="$t('trials:readingUnit:readingRules:title:segmentTool')">
@ -52,6 +61,22 @@
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<!-- 分割组名 -->
<el-form-item v-if="CriterionType === 0 && form.ReadingVersionEnum === 1 && form.ReadingTool === 3"
:label="$t('trials:readingUnit:readingRules:title:segmentations')" prop="DefaultSegmentName.SegmentationName">
<el-input v-model="form.DefaultSegmentName.SegmentationName" :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])" style="width: 80%">
</el-input>
</el-form-item>
<!-- 分割片段 -->
<el-form-item v-if="CriterionType === 0 && form.ReadingVersionEnum === 1 && form.ReadingTool === 3"
:label="$t('trials:readingUnit:readingRules:title:segment')" prop="DefaultSegmentName.SegmentNameList">
<el-input v-model="form.SegmentNameListStr" style="width: 80%" disabled>
</el-input>
<el-button :disabled="isConfirm ||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit'])
" icon="el-icon-plus" circle @click="segmentVisible = true" />
</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 ||
@ -392,6 +417,35 @@
</el-dialog> </el-dialog>
<attachmentPreview :visible.sync="perview_visible" :isView="true" :isExternal="true" :ExternalList="ExternalList" <attachmentPreview :visible.sync="perview_visible" :isView="true" :isExternal="true" :ExternalList="ExternalList"
v-if="perview_visible" /> v-if="perview_visible" />
<!-- 分割段编辑 -->
<el-dialog v-if="segmentVisible" :visible.sync="segmentVisible" :close-on-click-modal="false" width="600px"
:title="$t('trials:trialCfg:dialogTitle:addSegment')" custom-class="base-dialog-wrapper">
<div class="base-dialog-body">
<el-button @click.stop="addSegment" style="margin-bottom: 5px;" type="primary" size="small">{{
$t('common:button:new') }}</el-button>
<el-table :data="SegmentNameList" border style="width: 100%" size="small">
<el-table-column type="index" width="50" />
<el-table-column prop="name" :label="$t('trials:trialCfg:table:segmentName')" show-overflow-tooltip />
<el-table-column :label="$t('common:action:action')" align="left" fixed="right">
<template slot-scope="scope">
<el-button circle icon="el-icon-top" :title="$t('dictionary:template:keyDocList:button:up')"
@click.stop="sortSegment(scope, 'up')" :disabled="scope.$index === 0" />
<el-button circle icon="el-icon-bottom" :title="$t('dictionary:template:keyDocList:button:down')"
@click.stop="sortSegment(scope, 'down')" :disabled="scope.$index === SegmentNameList.length - 1" />
<el-button circle icon="el-icon-edit-outline" :title="$t('dictionary:template:keyDocList:button:update')"
@click.stop="updateSegment(scope)" />
<el-button circle icon="el-icon-delete" :title="$t('dictionary:template:keyDocList:button:del')"
@click.stop="delSegment(scope)" />
</template>
</el-table-column>
</el-table>
</div>
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
<el-button size="small" type="primary" @click="segmentVisible = false">
{{ $t('trials:trialCfg:button:confirmCfg') }}
</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
@ -420,6 +474,7 @@ export default {
}, },
data() { data() {
return { return {
segmentVisible: false,
perview_visible: false, perview_visible: false,
ExternalList: [], ExternalList: [],
keyDocVisible: false, keyDocVisible: false,
@ -432,6 +487,11 @@ export default {
ReadingVersionEnum: null, ReadingVersionEnum: null,
ReadingToolList: [], ReadingToolList: [],
SegmentToolList: [], SegmentToolList: [],
DefaultSegmentName: {
SegmentationName: null,
SegmentNameList: []
},
SegmentNameListStr: null,
ReadingTaskViewEnum: null, ReadingTaskViewEnum: null,
IsImageLabeled: null, IsImageLabeled: null,
IsReadingShowSubjectInfo: null, IsReadingShowSubjectInfo: null,
@ -460,7 +520,8 @@ export default {
ImageUploadEnum: null, ImageUploadEnum: null,
IsImageFilter: false, IsImageFilter: false,
KeyFileListStr: '', KeyFileListStr: '',
KeyFileList: [] KeyFileList: [],
CircleRadius: null
}, },
rules: { rules: {
IsAutoCreate: [ IsAutoCreate: [
@ -596,6 +657,21 @@ export default {
trigger: ['blur', 'change'], trigger: ['blur', 'change'],
}, },
], ],
'DefaultSegmentName.SegmentationName': [
{
required: true,
message: this.$t('common:ruleMessage:specify'),
trigger: ['blur', 'change'],
},
],
'DefaultSegmentName.SegmentNameList': [
{
required: true,
type: 'array',
message: this.$t('common:ruleMessage:select'),
trigger: ['blur', 'change'],
},
],
CriterionModalitys: [ CriterionModalitys: [
{ {
required: true, required: true,
@ -613,6 +689,10 @@ export default {
trigger: ['blur', 'change'], trigger: ['blur', 'change'],
}, },
], ],
CircleRadius: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'], },
{ pattern: /^(0|[1-9]\d*)(\.\d{1,2})?$/, message: '请输入正确的数值格式,最多两位小数', trigger: 'blur' }
]
// IsReadingTaskViewInOrder: [ // IsReadingTaskViewInOrder: [
// { required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur', 'change'] } // { required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur', 'change'] }
// ] // ]
@ -642,6 +722,16 @@ export default {
isUSA() { isUSA() {
return process.env.NODE_ENV === 'usa' return process.env.NODE_ENV === 'usa'
}, },
SegmentNameList() {
let arr = []
this.form.DefaultSegmentName.SegmentNameList.forEach(item => {
let obj = {
name: item
}
arr.push(obj)
})
return arr
}
}, },
watch: { watch: {
CriterionModalitys: { CriterionModalitys: {
@ -652,6 +742,76 @@ export default {
}, },
}, },
methods: { methods: {
sortSegment(row, key) {
let index = row.$index
let name = row.row.name
this.form.DefaultSegmentName.SegmentNameList.splice(index, 1)
if (key === 'up') {
this.form.DefaultSegmentName.SegmentNameList.splice(index - 1, 0, name)
} else {
this.form.DefaultSegmentName.SegmentNameList.splice(index + 1, 0, name)
}
},
async updateSegment(row) {
let name = await this.customPrompt(row.row.name)
if (!name) return false
let index = row.$index
this.form.DefaultSegmentName.SegmentNameList.splice(index, 1, name)
this.form.SegmentNameListStr = this.form.DefaultSegmentName.SegmentNameList.join("|")
},
delSegment(row) {
console.log(row)
let index = row.$index
this.form.DefaultSegmentName.SegmentNameList.splice(index, 1)
this.form.SegmentNameListStr = this.form.DefaultSegmentName.SegmentNameList.join("|")
},
async addSegment() {
let name = await this.customPrompt()
if (!name) return false
this.form.DefaultSegmentName.SegmentNameList.push(name)
this.form.SegmentNameListStr = this.form.DefaultSegmentName.SegmentNameList.join("|")
},
async customPrompt(name = null) {
try {
const that = this
//
let message = !name ? this.$t('trials:reading:Segmentations:message:add') : this.$t('trials:reading:Segmentations:message:upate')
const { value } = await this.$prompt(message, '', {
showClose: false,
cancelButtonText: this.$t('common:button:cancel'),
confirmButtonText: this.$t('common:button:save'),
showCancelButton: true,
closeOnClickModal: false,
closeOnPressEscape: false,
inputValue: name,
inputValidator: (value) => {
if (!value) {
return that.$t("trials:reading:Segmentations:message:notName")
} else if (value === name) {
return true
} else if (that.form.DefaultSegmentName.SegmentNameList.includes(value)) {
return that.$t("trials:reading:Segmentations:message:nameIsHas")
} else {
return true
}
},
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
// const value = instance.inputValue
done()
} else {
done()
}
}
})
return value
} catch (err) {
console.log(err)
return null
}
},
async viewManual() { async viewManual() {
try { try {
if (this.form.KeyFileList.length <= 0) return this.$message.warning(this.$t("trials:researchRecord:ImageManual:message:noImageManual")) if (this.form.KeyFileList.length <= 0) return this.$message.warning(this.$t("trials:researchRecord:ImageManual:message:noImageManual"))
@ -814,6 +974,7 @@ export default {
if (this.form.ReadingTool === 3) { if (this.form.ReadingTool === 3) {
this.segmentTools = [...config.customizeStandardsSegmentDicom] this.segmentTools = [...config.customizeStandardsSegmentDicom]
} }
this.form.SegmentNameListStr = res.Result.DefaultSegmentName.SegmentNameList.join(",")
} }
this.CriterionModalitys = this.form.CriterionModalitys this.CriterionModalitys = this.form.CriterionModalitys
? this.form.CriterionModalitys.split('|') ? this.form.CriterionModalitys.split('|')
@ -900,6 +1061,37 @@ export default {
}) })
}) })
}, },
handleReadingToolListChange(v) {
if (!v.includes('FixedRadiusCircleROI')) {
this.form.CircleRadius = null
}
},
handleNumberInput(value, field) {
if (!value) {
this.form[field] = ''
return
}
let val = value.toString()
// 1. .
val = val.replace(/[^\d.]/g, '')
// 2. .
val = val.replace(/^\./g, '')
// 3. .
val = val.replace(/\.{2,}/g, '.')
val = val.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.')
// 4.
val = val.replace(/^(\-)*(\d+)\.(\d{2}).*$/, '$1$2.$3')
// 5. 01 1
if (val.length > 1 && val[0] === '0' && val[1] !== '.') {
val = val.replace(/^0+/, '')
if (val === '') val = '0'
}
this.$nextTick(() => {
this.ruleForm[field] = val
});
},
}, },
} }
</script> </script>

View File

@ -3,6 +3,24 @@
<!-- 配置信息表单 --> <!-- 配置信息表单 -->
<el-form ref="processConfigForm" v-loading="loading" :model="form" label-width="300px" style="width: 800px" <el-form ref="processConfigForm" v-loading="loading" :model="form" label-width="300px" style="width: 800px"
:rules="rules" size="small"> :rules="rules" size="small">
<!-- 数据存储 -->
<el-form-item
:label="$t('trials:processCfg:form:trialDataStoreType')"
prop="TrialDataStoreType"
>
<el-radio-group
v-model="form.TrialDataStoreType"
:disabled="form.IsTrialProcessConfirmed && !isEdit"
>
<el-radio
v-for="item of $d.TrialDataStoreType"
:key="item.id"
:label="item.value"
>
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 阅片方式 --> <!-- 阅片方式 -->
<el-form-item :label="$t('trials:processCfg:form:readingMode')" prop="ReadingMode"> <el-form-item :label="$t('trials:processCfg:form:readingMode')" prop="ReadingMode">
<el-radio-group v-model="form.ReadingMode" :disabled="form.IsTrialProcessConfirmed && !isEdit"> <el-radio-group v-model="form.ReadingMode" :disabled="form.IsTrialProcessConfirmed && !isEdit">
@ -78,6 +96,7 @@
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<!-- 修约小数位数 --> <!-- 修约小数位数 -->
<!-- <el-form-item <!-- <el-form-item
:label="$t('trials:processCfg:form:digitPlaces')" :label="$t('trials:processCfg:form:digitPlaces')"
@ -724,6 +743,7 @@ export default {
VUE_IS_TEST: process.env.VUE_APP_IS_TEST, VUE_IS_TEST: process.env.VUE_APP_IS_TEST,
form: { form: {
TrialId: '', TrialId: '',
TrialDataStoreType: 0,
ClinicalInformationTransmissionEnum: 1, ClinicalInformationTransmissionEnum: 1,
ClinicalDataSetNames: [], ClinicalDataSetNames: [],
ClinicalDataTrialSetIds: [], ClinicalDataTrialSetIds: [],
@ -750,6 +770,13 @@ export default {
TrialCriterionIdEnums: [], TrialCriterionIdEnums: [],
}, },
rules: { rules: {
TrialDataStoreType: [
{
required: true,
message: this.$t('common:ruleMessage:select'),
trigger: 'blur',
},
],
ClinicalDataSetNamesStr: [ ClinicalDataSetNamesStr: [
{ {
required: true, required: true,
@ -1005,6 +1032,11 @@ export default {
// initialCriterions.push(this.$fd('ReadingStandard', id, 'id')) // initialCriterions.push(this.$fd('ReadingStandard', id, 'id'))
// }) // })
this.confirmData = [ this.confirmData = [
{
Name: this.$t('trials:processCfg:form:trialDataStoreType'), //
NewVal: this.$fd('TrialDataStoreType', this.form.TrialDataStoreType),
OldVal: this.$fd('TrialDataStoreType', this.initialForm.TrialDataStoreType),
},
{ {
Name: this.$t('trials:processCfg:form:readingMode'), // Name: this.$t('trials:processCfg:form:readingMode'), //
NewVal: this.$fd('ReadingMode', this.form.ReadingMode), NewVal: this.$fd('ReadingMode', this.form.ReadingMode),

View File

@ -261,12 +261,23 @@ export default {
uploadFilesAndSave() { uploadFilesAndSave() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
this.form.AddFileList = [] this.form.AddFileList = []
let uploadBatchId = this.$guid()
for (var i = 0; i < this.pendingUploadList.length; ++i) { for (var i = 0; i < this.pendingUploadList.length; ++i) {
// const file = await this.convertBase64ToBlob(this.pendingUploadList[i]) // const file = await this.convertBase64ToBlob(this.pendingUploadList[i])
const file = await this.fileToBlob(this.pendingUploadList[i]) const file = await this.fileToBlob(this.pendingUploadList[i])
const res = await this.OSSclient.put( const res = await this.OSSclient.put(
`/${this.data.TrialId}/ClinicalData/${this.pendingUploadList[i].name}`, `/${this.data.TrialId}/ClinicalData/${this.pendingUploadList[i].name}`,
file file,
{
fileName: this.pendingUploadList[i].name,
fileSize: this.pendingUploadList[i].size,
fileType: this.pendingUploadList[i].type,
uploadBatchId: uploadBatchId,
batchDataType: 4,
trialId: this.data.TrialId,
subjectId: this.data.SubjectId,
subjectVisitId: this.data.SubjectVisitId
}
) )
this.form.AddFileList.push({ this.form.AddFileList.push({
fileName: this.pendingUploadList[i].name, fileName: this.pendingUploadList[i].name,

View File

@ -551,6 +551,7 @@ export default {
IsVisit: this.data.IsVisit, IsVisit: this.data.IsVisit,
SubjectId: this.data.SubjectId, SubjectId: this.data.SubjectId,
IsBaseLine: this.data.IsBaseLine, IsBaseLine: this.data.IsBaseLine,
SubjectVisitId: this.data.SubjectVisitId
} }
) )
this.addOrUpdateCD.title = this.$t('common:button:new') this.addOrUpdateCD.title = this.$t('common:button:new')
@ -565,6 +566,7 @@ export default {
} }
this.currentData.IsVisit = this.data.IsVisit this.currentData.IsVisit = this.data.IsVisit
this.currentData.IsBaseLine = this.data.IsBaseLine this.currentData.IsBaseLine = this.data.IsBaseLine
this.currentData.SubjectVisitId = this.data.SubjectVisitId
this.addOrUpdateCD.title = this.$t('common:button:edit') this.addOrUpdateCD.title = this.$t('common:button:edit')
this.currentOption = [ this.currentOption = [
{ {

View File

@ -46,20 +46,49 @@ import {
getTrialCriterionList, getTrialCriterionList,
getReportsChartSummary getReportsChartSummary
} from '@/api/trials' } from '@/api/trials'
let echarts = require('echarts/lib/echarts'); import * as echarts from 'echarts/core';
import { LineChart } from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
DataZoomComponent,
LegendComponent,
DatasetComponent,
// (filter, sort)
TransformComponent
} from 'echarts/components';
//
import { LabelLayout, UniversalTransition } from 'echarts/features';
// Canvas CanvasRenderer SVGRenderer
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
DataZoomComponent,
LegendComponent,
LineChart,
LabelLayout,
UniversalTransition,
CanvasRenderer
]);
// let echarts = require('echarts/lib/echarts');
// //
// require('echarts/lib/chart/bar'); // require('echarts/lib/chart/bar');
require('echarts/lib/chart/line'); // require('echarts/lib/chart/line');
// require('echarts/lib/chart/pie'); // require('echarts/lib/chart/pie');
// require('echarts/lib/chart/scatter'); // require('echarts/lib/chart/scatter');
// //
require('echarts/lib/component/tooltip'); // require('echarts/lib/component/tooltip');
require('echarts/lib/component/title'); // require('echarts/lib/component/title');
require('echarts/lib/component/legend'); // require('echarts/lib/component/legend');
require('echarts/lib/component/grid'); // require('echarts/lib/component/grid');
require('echarts/lib/component/dataZoom'); // require('echarts/lib/component/dataZoom');
export default { export default {
name: "SubjectChart", name: "SubjectChart",
props: { props: {
@ -259,12 +288,19 @@ export default {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
}, },
grid: {
left: 30,
bottom: 30
},
xAxis: { xAxis: {
data: obj.visitName, data: obj.visitName,
}, },
yAxis: { yAxis: {
name: obj.unit, name: obj.unit,
type: 'value', type: 'value',
axisLine: {
show: true
}
}, },
series: obj.series series: obj.series
}; };

View File

@ -0,0 +1,442 @@
<template>
<BaseContainer>
<template slot="search-container">
<el-form :inline="true">
<!-- 文件名称 -->
<el-form-item label="文件名称" prop="FileName">
<el-input v-model="searchData.FileName" size="small" clearable style="width: 120px" />
</el-form-item>
<!-- 文件类型 -->
<el-form-item label="文件类型" prop="FileType">
<el-input v-model="searchData.FileType" size="small" clearable style="width: 120px" />
</el-form-item>
<!-- 源区域 -->
<el-form-item label="源区域" prop="UploadRegion">
<el-select v-model="searchData.UploadRegion" style="width: 120px">
<el-option
v-for="item in regionOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 源可用时间 -->
<el-form-item label="源可用时间">
<el-date-picker
v-model="uploadTimeRange"
:default-time="['00:00:00', '23:59:59']"
value-format="yyyy-MM-dd HH:mm:ss"
@change="handleUploadtimeChange"
style="width: 300px"
type="datetimerange">
</el-date-picker>
</el-form-item>
<!-- 目标区域 -->
<el-form-item label="目标区域" prop="TargetRegion">
<el-select v-model="searchData.TargetRegion" style="width: 120px">
<el-option
v-for="item in regionOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 目标可用时间 -->
<el-form-item label="目标可用时间">
<el-date-picker
v-model="SyncTimeRange"
:default-time="['00:00:00', '23:59:59']"
value-format="yyyy-MM-dd HH:mm:ss"
@change="handleSynctimeChange"
style="width: 300px"
type="datetimerange">
</el-date-picker>
</el-form-item>
<!-- 优先级 -->
<el-form-item label="优先级">
<el-input v-model="searchData.Priority" clearable style="width: 120px"></el-input>
</el-form-item>
<!-- 是否同步完成 -->
<el-form-item label="是否同步完成" prop="IsSync">
<el-select v-model="searchData.IsSync" clearable style="width: 120px">
<el-option
v-for="item of $d.YesOrNo"
:key="'IsSync' + item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<!-- 重置 -->
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
<!-- 批量编辑 -->
<el-button type="primary" icon="el-icon-edit" :disabled="selectedRows.length === 0" @click="handleBatchEdit">
批量编辑
</el-button>
</el-form-item>
</el-form>
</template>
<template slot="main-container">
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 70 }" height="100" :data="list"
class="table" @sort-change="handleSortByColumn" :default-sort="{ prop: 'CreateTime', order: 'descending' }" @selection-change="handleSelectionChange">
<el-table-column type="index" width="50" />
<el-table-column type="selection" width="50" :selectable="selectableRow"/>
<el-table-column label="文件名称" prop="FileName" min-width="90" show-overflow-tooltip sortable="custom">
</el-table-column>
<el-table-column label="文件大小" prop="FileSize" min-width="90" show-overflow-tooltip>
<template slot-scope="scope">
{{ fileSizeFormatter(scope.row.FileSize) }}
</template>
</el-table-column>
<el-table-column label="文件类型" prop="FileType" min-width="90" show-overflow-tooltip sortable="custom">
</el-table-column>
<el-table-column label="源区域" prop="UploadRegion" min-width="60" show-overflow-tooltip sortable="custom" />
<el-table-column label="源可用时间" prop="CreateTime" min-width="90" show-overflow-tooltip sortable="custom" />
<el-table-column label="路径" prop="Path" min-width="90" show-overflow-tooltip sortable="custom" />
<el-table-column label="是否需要同步" prop="IsNeedSync" min-width="90" show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsNeedSync" type="success">
{{ $fd('YesOrNo', scope.row.IsNeedSync) }}
</el-tag>
<el-tag v-else type="danger">
{{ $fd('YesOrNo', scope.row.IsNeedSync) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="目标区域" prop="TargetRegion" min-width="80" show-overflow-tooltip sortable="custom" />
<el-table-column label="目标可用时间" prop="SyncFinishedTime" min-width="90" show-overflow-tooltip sortable="custom" />
<el-table-column label="优先级" prop="Priority" min-width="60" show-overflow-tooltip sortable="custom" />
<el-table-column label="是否同步完成" prop="IsSync" min-width="90" show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsSync" type="success">
{{ $fd('YesOrNo', scope.row.IsSync) }}
</el-tag>
<el-tag v-else type="danger">
{{ $fd('YesOrNo', scope.row.IsSync) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="更新时间" prop="UpdateTime" min-width="90" show-overflow-tooltip sortable="custom" />
<el-table-column label="操作" width="240" show-overflow-tooltip fixed="right">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="handleOpenTaskTable(scope.row)">
详情
</el-button>
<el-button type="primary" size="mini" :disabled="!scope.row.IsNeedSync || !scope.row.IsSync" @click="execute(scope.row)">
重新同步
</el-button>
<el-button type="primary" size="mini" :disabled="scope.row.IsSync" @click="handleEdit(scope.row)">
编辑
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
</template>
<el-dialog v-if="editDialogVisible" title="编辑" :visible.sync="editDialogVisible" width="600px" :close-on-click-modal="false" append-to-body>
<el-form ref="editFormRef" :model="editForm" :rules="editRules" label-width="110px" v-loading="formLoading">
<el-form-item label="文件名称">
<el-input v-model="editForm.FileName" disabled />
</el-form-item>
<el-form-item label="文件大小">
<el-input :value="fileSizeFormatter(editForm.FileSize)" disabled />
</el-form-item>
<el-form-item label="文件类型">
<el-input v-model="editForm.FileType" disabled />
</el-form-item>
<el-form-item label="源区域">
<el-input v-model="editForm.UploadRegion" disabled />
</el-form-item>
<el-form-item label="目标区域">
<el-input v-model="editForm.TargetRegion" disabled />
</el-form-item>
<el-form-item label="是否需要同步" prop="IsNeedSync">
<el-select v-model="editForm.IsNeedSync" style="width: 100%">
<el-option
v-for="item of $d.YesOrNo"
:key="'IsNeedSync' + item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item label="更新时间">
<el-input v-model="editForm.UpdateTime" disabled />
</el-form-item>
<el-form-item label="路径">
<el-input v-model="editForm.Path" type="textarea" :rows="2" disabled />
</el-form-item>
<el-form-item label="优先级" prop="Priority">
<el-input-number v-model="editForm.Priority" :min="0" :controls="true" style="width: 100%" />
</el-form-item>
<el-form-item label="是否同步完成" prop="IsSync">
<el-select v-model="editForm.IsSync" style="width: 100%" disabled>
<el-option
v-for="item of $d.YesOrNo"
:key="'IsSync' + item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="editDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSaveEdit"></el-button>
</span>
</el-dialog>
<el-dialog v-if="batchEditDialogVisible" title="批量编辑" :visible.sync="batchEditDialogVisible" width="300px" :close-on-click-modal="false" append-to-body>
<el-form ref="batchEditFormRef" :model="batchEditForm" :rules="batchEditRules" label-width="80px" v-loading="formLoading">
<el-form-item label="优先级" prop="Priority">
<el-input-number v-model="batchEditForm.Priority" :min="0" :controls="true" style="width: 100%" />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="batchEditDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSaveBatchEdit"></el-button>
</span>
</el-dialog>
</BaseContainer>
</template>
<script>
import { getFileUploadRecordList, addOrUpdateFileUploadRecord, batchAddSyncFileTask } from '@/api/file'
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import moment from 'moment'
const searchDataDefault = () => {
return {
TrialId: '',
DataFileType: null,
SubjectCode: '',
VisitName: '',
StudyCode: '',
FileName: '',
UploadRegion: null,
TargetRegion: null,
IsSync: null,
UploadStartTime: null,
UploadEndTime: null,
SyncFinishedStartTime: null,
SyncFinishedEndTime: null,
Priority: null,
Asc: false,
SortField: 'UpdateTime',
PageIndex: 1,
PageSize: 20,
}
}
export default {
name: 'FileList',
components: { BaseContainer, Pagination },
props: {
rowInfo: {
type: Object,
required: true,
},
dataFileType: {
type: Number,
required: true,
},
},
data() {
return {
moment,
searchData: searchDataDefault(),
list: [],
total: 0,
loading: false,
uploadTimeRange: null,
SyncTimeRange: null,
regionOptions: [
{
value: 'CN',
label: 'CN'
}, {
value: 'US',
label: 'US'
}
],
editDialogVisible: false,
editForm: {
// Priority: null,
// IsSync: null,
},
editRules: {
Priority: [{ required: true, message: '请输入', trigger: 'change' }],
IsSync: [{ required: true, message: '请选择', trigger: 'change' }],
},
formLoading: false,
selectedRows: [],
batchEditDialogVisible: false,
batchEditForm: {
Priority: null,
},
batchEditRules: {
Priority: [{ required: true, message: '请输入', trigger: 'change' }],
},
}
},
mounted() {
this.getList()
},
methods: {
async getList() {
try {
this.loading = true
this.searchData.TrialId = this.$route.query.trialId
this.searchData.SubjectCode = this.rowInfo.SubjectCode
this.searchData.VisitName = this.rowInfo.VisitName
this.searchData.StudyCode = this.rowInfo.StudyCode
this.searchData.DataFileType = this.dataFileType
let res = await getFileUploadRecordList(this.searchData)
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
} catch(e) {
this.loading = false
console.log(e)
}
},
handleOpenTaskTable(row) {
this.$emit('openTaskTable', row)
},
handleEdit(row) {
this.editForm = {...row}
this.editDialogVisible = true
this.$nextTick(() => {
if (this.$refs.editFormRef) this.$refs.editFormRef.clearValidate()
})
},
async handleSaveEdit() {
try {
let valid = await this.$refs.editFormRef.validate()
if (!valid) return
this.formLoading = true
let res = await addOrUpdateFileUploadRecord(this.editForm)
this.formLoading = false
if (res.IsSuccess) {
this.editDialogVisible = false
this.getList()
}
} catch(e) {
console.log(e)
this.formLoading = false
}
},
async execute(row) {
try {
this.loading = true
let params = {
fileUploadRecordIdList: [row.Id]
}
let res = await batchAddSyncFileTask(params)
if (res.IsSuccess) {
this.$message.success('执行成功!')
}
this.loading = false
this.getList()
} catch(e) {
this.loading = false
console.log(e)
}
},
handleSelectionChange(rows) {
this.selectedRows = rows
},
selectableRow(row) {
return !row.IsSync
},
handleBatchEdit() {
if (!this.selectedRows.length) return
this.batchEditForm = {
Priority: null,
}
this.batchEditDialogVisible = true
this.$nextTick(() => {
if (this.$refs.batchEditFormRef) this.$refs.batchEditFormRef.clearValidate()
})
},
async handleSaveBatchEdit() {
try {
let valid = await this.$refs.batchEditFormRef.validate()
if (!valid) return
this.formLoading = true
let params = {
fileUploadRecordIdList: this.selectedRows,
priority: this.editForm.Priority
}
let res = await batchAddSyncFileTask(params)
this.formLoading = false
if (res.IsSuccess) {
this.batchEditDialogVisible = false
this.getList()
}
} catch(e) {
console.log(e)
this.formLoading = false
}
},
fileSizeFormatter(size) {
if (!size) return
return (size / Math.pow(1024, 2)).toFixed(3) + 'MB'
},
handleUploadtimeChange(val) {
if (val) {
this.searchData.UploadStartTime = val[0]
this.searchData.UploadEndTime = val[1]
} else {
this.searchData.UploadStartTime = ''
this.searchData.UploadEndTime = ''
}
},
handleSynctimeChange(val) {
if (val) {
this.searchData.SyncFinishedStartTime = val[0]
this.searchData.SyncFinishedEndTime = val[1]
} else {
this.searchData.SyncFinishedStartTime = ''
this.searchData.SyncFinishedEndTime = ''
}
},
handleSearch() {
this.searchData.PageIndex = 1
this.getList()
},
//
handleReset() {
this.uploadTimeRange = null
this.handleUploadtimeChange()
this.SyncTimeRange = null
this.handleSynctimeChange()
this.searchData = searchDataDefault()
this.getList()
},
//
handleSortByColumn(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
this.searchData.SortField = column.prop
this.searchData.PageIndex = 1
this.getList()
},
},
}
</script>

View File

@ -0,0 +1,351 @@
<template>
<BaseContainer>
<template slot="search-container">
<el-form :inline="true">
<!-- 受试者编号 -->
<el-form-item label="受试者编号" prop="SubjectCode">
<el-input v-model="searchData.SubjectCode" size="small" clearable style="width: 120px" />
</el-form-item>
<!-- 访视名称 -->
<el-form-item label="访视名称">
<el-select v-model="searchData.VisitName" style="width: 140px" clearable>
<el-option v-for="(item, index) of visitPlanOptions" :key="index" :label="item.VisitName"
:value="item.VisitNum">
<span style="float: left">{{ item.VisitName }}</span>
</el-option>
<!-- <el-option key="Other" label="Out of Plan" value="1.11" /> -->
</el-select>
</el-form-item>
<!-- 检查编号 -->
<el-form-item label="检查编号" prop="StudyCode">
<el-input v-model="searchData.StudyCode" size="small" clearable style="width: 120px" />
</el-form-item>
<!-- 源区域 -->
<el-form-item label="源区域" prop="UploadRegion">
<el-select v-model="searchData.UploadRegion" style="width: 120px">
<el-option
v-for="item in regionOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 源可用时间 -->
<!-- <el-form-item label="源可用时间">
<el-date-picker
v-model="uploadTimeRange"
:default-time="['00:00:00', '23:59:59']"
value-format="yyyy-MM-dd HH:mm:ss"
@change="handleUploadtimeChange"
style="width: 250px"
type="datetimerange">
</el-date-picker>
</el-form-item> -->
<!-- 目标区域 -->
<el-form-item label="目标区域" prop="TargetRegion">
<el-select v-model="searchData.TargetRegion" style="width: 120px">
<el-option
v-for="item in regionOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 目标可用时间 -->
<!-- <el-form-item label="目标可用时间">
<el-date-picker
v-model="SyncTimeRange"
:default-time="['00:00:00', '23:59:59']"
value-format="yyyy-MM-dd HH:mm:ss"
@change="handleSynctimeChange"
style="width: 250px"
type="datetimerange">
</el-date-picker>
</el-form-item> -->
<!-- 是否同步完成 -->
<el-form-item label="是否同步完成" prop="IsSync">
<el-select v-model="searchData.IsSync" clearable style="width: 120px">
<el-option
v-for="item of $d.YesOrNo"
:key="'IsSync' + item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<!-- 重置 -->
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
</el-form>
</template>
<template slot="main-container">
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 60 }" height="100" :data="list"
class="table" @sort-change="handleSortByColumn" :default-sort="{ prop: 'CreateTime', order: 'descending' }">
<el-table-column type="index" width="50" />
<el-table-column label="受试者编号" prop="SubjectCode" min-width="90" show-overflow-tooltip sortable="custom"/>
<el-table-column label="访视名称" prop="VisitName" min-width="90" show-overflow-tooltip sortable="custom"/>
<el-table-column label="检查编号" prop="StudyCode" min-width="90" show-overflow-tooltip sortable="custom"/>
<el-table-column label="文件数" prop="FileCount" min-width="90" show-overflow-tooltip/>
<el-table-column label="源区域" prop="UploadRegion" min-width="60" show-overflow-tooltip />
<el-table-column label="源可用时间" prop="CreateTime" min-width="90" show-overflow-tooltip />
<el-table-column label="目标区域" prop="TargetRegion" min-width="60" show-overflow-tooltip />
<el-table-column label="目标可用时间" prop="SyncFinishedTime" min-width="90" show-overflow-tooltip/>
<el-table-column label="是否同步完成" prop="IsSync" min-width="90" show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsSync" type="success">
{{ $fd('YesOrNo', scope.row.IsSync) }}
</el-tag>
<el-tag v-else type="danger">
{{ $fd('YesOrNo', scope.row.IsSync) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" min-width="80" show-overflow-tooltip>
<template slot-scope="scope">
<el-button type="primary" size="small" @click="openDetailTable(scope.row)">
详情
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
</template>
<el-dialog
v-if="detailDialog.visible"
:visible.sync="detailDialog.visible"
fullscreen
append-to-body
:close-on-click-modal="false"
class="detail-dialog"
>
<span slot="title">{{ detailDialog.title }}</span>
<span v-if="detailDialog.currentRow">{{`${detailDialog.currentRow.SubjectCode} / ${detailDialog.currentRow.VisitName} ${detailDialog.currentRow.StudyCode ? ' / ' + detailDialog.currentRow.StudyCode : ''} ${detailDialog.currentRow.UploadRegion} -> 目标${detailDialog.currentRow.TargetRegion}`}}</span>
<el-tabs class="detail-tabs" v-model="detailDialog.activeTab" @tab-click="handleDetailTabClick">
<el-tab-pane label="文件级别" name="file">
<FileList
v-if="detailDialog.activeTab === 'file'"
:dataFileType="1"
:rowInfo="detailDialog.currentRow"
@openTaskTable="openTaskTable"
/>
</el-tab-pane>
<el-tab-pane label="任务级别" name="task">
<TaskList
v-if="detailDialog.activeTab === 'task'"
:rowInfo="detailDialog.currentRow"
:fileUploadRecordId="fileUploadRecordId"
:path="path"
/>
</el-tab-pane>
</el-tabs>
</el-dialog>
</BaseContainer>
</template>
<script>
import { getSubjectUploadRecordList } from '@/api/file'
import { getTrialVisitStageSelect } from '@/api/trials'
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import FileList from './FileList'
import TaskList from './TaskList'
import moment from 'moment'
const searchDataDefault = () => {
return {
TrialId: '',
SubjectCode: '',
VisitName: null,
StudyCode: '',
UploadRegion: '',
TargetRegion: '',
IsSync: null,
// UploadStartTime: null,
// UploadEndTime: null,
// SyncFinishedStartTime: null,
// SyncFinishedEndTime: null,
PageIndex: 1,
PageSize: 20,
Asc: true,
SortField: 'StudyCode'
}
}
export default {
components: { BaseContainer, Pagination, FileList, TaskList },
data() {
return {
trialId: '',
moment,
searchData: searchDataDefault(),
list: [],
total: 0,
loading: false,
visitPlanOptions: [],
detailDialog: {
visible: false,
title: '详情',
activeTab: 'file',
currentRow: null
},
regionOptions: [
{
value: 'CN',
label: 'CN'
}, {
value: 'US',
label: 'US'
}
],
fileUploadRecordId: '',
path: '',
uploadTimeRange: null,
SyncTimeRange: null,
}
},
mounted() {
this.trialId = this.$route.query.trialId
this.getList()
this.getVisitPlanOptions()
},
methods: {
async getList() {
try {
this.loading = true
this.searchData.TrialId = this.trialId
let res = await getSubjectUploadRecordList(this.searchData)
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
} catch(e) {
this.loading = false
console.log(e)
}
},
openDetailTable(row) {
this.detailDialog.currentRow = row || null
this.detailDialog.activeTab = 'file'
this.detailDialog.visible = true
},
openTaskTable(row) {
this.fileUploadRecordId = row.Id
this.path = row.Path
this.detailDialog.activeTab = 'task'
},
handleDetailTabClick(tab) {
const name = tab.name
if (name === 'file') {
this.fileUploadRecordId = ''
this.path = ''
}
// if (name !== 'upload' && name !== 'sync') return
// if (this.detailDialog[name].list && this.detailDialog[name].list.length) return
// this.fetchDetailList(name)
},
// 访
async getVisitPlanOptions() {
try {
let res = await getTrialVisitStageSelect(this.trialId)
this.visitPlanOptions = res.Result
} catch(e) {
console.log(e)
}
},
handleUploadtimeChange(val) {
if (val) {
this.searchData.UploadStartTime = val[0]
this.searchData.UploadEndTime = val[1]
} else {
this.searchData.UploadStartTime = ''
this.searchData.UploadEndTime = ''
}
},
handleSynctimeChange(val) {
if (val) {
this.searchData.SyncFinishedStartTime = val[0]
this.searchData.SyncFinishedEndTime = val[1]
} else {
this.searchData.SyncFinishedStartTime = ''
this.searchData.SyncFinishedEndTime = ''
}
},
handleSearch() {
this.searchData.PageIndex = 1
this.getList()
},
//
handleReset() {
// this.uploadTimeRange = null
// this.handleUploadtimeChange()
// this.SyncTimeRange = null
// this.handleSynctimeChange()
this.searchData = searchDataDefault()
this.getList()
},
//
handleSortByColumn(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
this.searchData.SortField = column.prop
this.searchData.PageIndex = 1
this.getList()
},
},
}
</script>
<style lang="scss">
.detail-dialog {
margin: 0;
height: 100vh;
display: flex;
flex-direction: column;
.el-dialog__header {
flex: 0 0 auto;
padding-bottom: 0px;
}
.el-dialog__body {
padding-top: 10px;
flex: 1 1 auto;
overflow: hidden;
}
&.is-fullscreen {
.el-dialog__body {
margin-top: 10px;
height: calc(100% - 80px);
}
}
}
.detail-tabs {
height: 100%;
display: flex;
flex-direction: column;
.el-tabs__header {
flex: 0 0 auto;
margin: 0 0 8px;
}
.el-tabs__content {
flex: 1 1 auto;
overflow: hidden;
}
.el-tab-pane {
height: 100%;
}
}
</style>

View File

@ -0,0 +1,249 @@
<template>
<BaseContainer>
<template slot="search-container">
<el-form :inline="true">
<!-- 文件名称 -->
<el-form-item label="文件名称" prop="FileName">
<el-input v-model="searchData.FileName" size="small" clearable style="width: 120px" />
</el-form-item>
<!-- 文件路径 -->
<el-form-item label="文件路径" prop="Path">
<el-input v-model="searchData.Path" size="small" clearable />
</el-form-item>
<!-- 任务状态 -->
<el-form-item label="任务状态" prop="JobState">
<el-select v-model="searchData.JobState" clearable style="width: 120px">
<el-option
v-for="item of $d.JobState"
:key="'JobState' + item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<!-- 任务开始日期 -->
<el-form-item label="任务开始日期">
<el-date-picker
v-model="searchData.StartTime"
type="date"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
:picker-options="beginPickerOption"
style="width:140px;"
/>
</el-form-item>
<!-- 任务结束日期 -->
<el-form-item label="任务结束日期">
<el-date-picker
v-model="searchData.EndTime"
type="date"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
:picker-options="endpickerOption"
style="width:140px;"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<!-- 重置 -->
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
</el-form>
</template>
<template slot="main-container">
<el-table v-loading="loading" v-adaptive="{ bottomOffset: 70 }" height="100" :data="list"
class="table" @sort-change="handleSortByColumn" :default-sort="{ prop: 'CreateTime', order: 'descending' }">
<el-table-column type="index" width="50" />
<el-table-column label="Job编号" prop="Id" min-width="90" show-overflow-tooltip/>
<el-table-column label="文件名称" prop="FileName" min-width="90" show-overflow-tooltip sortable="custom">
</el-table-column>
<el-table-column label="路径" prop="Path" min-width="90" show-overflow-tooltip/>
<el-table-column label="任务状态" prop="JobState" min-width="90" show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.JobState === 1" type="infoinf0">
{{ $fd('JobState', scope.row.JobState) }}
</el-tag>
<el-tag v-else-if="scope.row.JobState === 1" type="warning">
{{ $fd('JobState', scope.row.JobState) }}
</el-tag>
<el-tag v-else-if="scope.row.JobState === 2" type="success">
{{ $fd('JobState', scope.row.JobState) }}
</el-tag>
<el-tag v-else-if="scope.row.JobState === 3" type="danger">
{{ $fd('JobState', scope.row.JobState) }}
</el-tag>
<el-tag v-else>{{ $fd('JobState', scope.row.JobState) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="任务开始时间" prop="StartTime" min-width="90" show-overflow-tooltip sortable="custom" />
<el-table-column label="任务结束时间" prop="EndTime" min-width="90" show-overflow-tooltip sortable="custom" />
<el-table-column label="创建时间" prop="CreateTime" min-width="90" show-overflow-tooltip sortable="custom" />
<el-table-column label="操作" min-width="80" show-overflow-tooltip>
<template slot-scope="scope">
<el-button type="primary" size="mini" :disabled="scope.row.JobState !== 3" @click="execute(scope.row)">
再次执行
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
</template>
</BaseContainer>
</template>
<script>
import { getUploadFileSyncRecordList, batchAddSyncFileTask } from '@/api/file'
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import moment from 'moment'
const searchDataDefault = () => {
return {
TrialId: '',
StudyCode: '',
SubjectCode: '',
VisitName: '',
FileUploadRecordId: '',
JobState: null,
FileName: '',
Path: '',
StartTime: '',
EndTime: '',
Asc: false,
SortField: '',
PageIndex: 1,
PageSize: 20,
}
}
export default {
name: 'TaskList',
components: { BaseContainer, Pagination },
props: {
fileUploadRecordId: {
type: String,
default: '',
},
path: {
type: String,
default: '',
},
rowInfo: {
type: Object,
required: true,
},
},
data() {
return {
moment,
searchData: searchDataDefault(),
list: [],
total: 0,
loading: false,
datetimerange: [],
beginPickerOption: {
disabledDate: time => {
if (this.searchData.EndTime) {
return time.getTime() >= new Date(this.searchData.EndTime).getTime()
} else {
return time.getTime() > Date.now()
}
}
},
endpickerOption: {
disabledDate: time => {
if (this.searchData.StartTime) {
return time.getTime() > Date.now() || time.getTime() <= new Date(this.searchData.StartTime).getTime() - 86400000
} else {
return time.getTime() > Date.now()
}
}
}
}
},
mounted() {
this.$nextTick(()=>{
this.searchData.Path = this.path
this.searchData.FileUploadRecordId = this.fileUploadRecordId
this.getList()
})
},
methods: {
async getList() {
try {
this.loading = true
this.searchData.TrialId = this.$route.query.trialId
this.searchData.StudyCode = this.rowInfo.StudyCode
this.searchData.SubjectCode = this.rowInfo.SubjectCode
this.searchData.VisitName = this.rowInfo.VisitName
let res = await getUploadFileSyncRecordList(this.searchData)
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
} catch(e) {
this.loading = false
console.log(e)
}
},
async execute(row) {
try {
this.loading = true
let params = {
fileUploadRecordIdList: [row.Id]
}
let res = await batchAddSyncFileTask(params)
if (res.IsSuccess) {
this.$message.success('执行成功!')
}
this.loading = false
this.getList()
} catch(e) {
this.loading = false
console.log(e)
}
},
fileSizeFormatter(size) {
if (!size) return
return (size / Math.pow(1024, 2)).toFixed(3) + 'MB'
},
handleDatetimeChange(val) {
if (val) {
this.searchData.BeginDate = val[0]
this.searchData.EndDate = val[1]
} else {
this.searchData.BeginDate = ''
this.searchData.EndDate = ''
}
},
handleSearch() {
this.searchData.PageIndex = 1
this.getList()
},
//
handleReset() {
this.datetimerange = null
this.searchData = searchDataDefault()
this.getList()
},
//
handleSortByColumn(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
this.searchData.SortField = column.prop
this.searchData.PageIndex = 1
this.getList()
},
},
}
</script>

View File

@ -0,0 +1,38 @@
<template>
<el-tabs class="data-sync-tabs" type="border-card" tab-position="left" v-model="activeTab" >
<el-tab-pane label="检查列表" name="study">
<StudyList />
</el-tab-pane>
<el-tab-pane label="其他" name="other">其他</el-tab-pane>
</el-tabs>
</template>
<script>
import StudyList from './components/StudyList'
export default {
name: 'DataSync',
components: {
StudyList
},
data(){
return {
activeTab: 'study'
}
}
}
</script>
<style lang="scss">
.data-sync-tabs{
height: 100%;
background-color: #fff;
.el-tabs__header {
height: 100%;
}
.el-tabs__content {
height: 100%;
overflow: auto;
}
.el-tab-pane {
height: 100%;
}
}
</style>

View File

@ -36,17 +36,49 @@
</template> </template>
<script> <script>
import BaseContainer from '@/components/BaseContainer' import BaseContainer from '@/components/BaseContainer'
let echarts = require('echarts/lib/echarts'); import * as echarts from 'echarts/core';
import { BarChart, FunnelChart } from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
DataZoomComponent,
LegendComponent,
MarkLineComponent,
DatasetComponent,
// (filter, sort)
TransformComponent
} from 'echarts/components';
//
import { LabelLayout, UniversalTransition } from 'echarts/features';
// Canvas CanvasRenderer SVGRenderer
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
DataZoomComponent,
MarkLineComponent,
LegendComponent,
BarChart,
FunnelChart,
LabelLayout,
UniversalTransition,
CanvasRenderer
]);
// let echarts = require('echarts/lib/echarts');
require('echarts/lib/component/markLine'); // require('echarts/lib/component/markLine');
require('echarts/lib/chart/funnel'); // require('echarts/lib/chart/funnel');
require('echarts/lib/chart/bar'); // require('echarts/lib/chart/bar');
// //
require('echarts/lib/component/tooltip'); // require('echarts/lib/component/tooltip');
require('echarts/lib/component/title'); // require('echarts/lib/component/title');
require('echarts/lib/component/legend'); // require('echarts/lib/component/legend');
require('echarts/lib/component/grid'); // require('echarts/lib/component/grid');
require('echarts/lib/component/dataZoom'); // require('echarts/lib/component/dataZoom');
import { import {
getTrialCriterionList, getTrialCriterionList,
getTrialVisitFinishedStatList, getTrialVisitFinishedStatList,
@ -178,8 +210,11 @@ export default {
this.chart_left = echarts.init(this.$refs.chartContainer_left); this.chart_left = echarts.init(this.$refs.chartContainer_left);
// ... // ...
const option = { const option = {
richInheritPlainLabel: false,
title: { title: {
text: obj.titleText text: obj.titleText,
left: 0,
top: 0
}, },
color: this.color, color: this.color,
tooltip: { tooltip: {
@ -316,7 +351,13 @@ export default {
// ... // ...
const option = { const option = {
title: { title: {
text: obj.titleText text: obj.titleText,
left: 0,
top: 0
},
grid: {
left: 80,
bottom: 50
}, },
toolbox: { toolbox: {
show: false show: false
@ -339,6 +380,9 @@ export default {
], ],
yAxis: [ yAxis: [
{ {
axisLine: {
show: true
},
name: obj.unit, name: obj.unit,
type: 'value' type: 'value'
} }
@ -424,12 +468,18 @@ export default {
// ... // ...
const option = { const option = {
title: { title: {
text: obj.titleText text: obj.titleText,
left: 0,
top: 0
}, },
toolbox: { toolbox: {
show: false show: false
}, },
color: this.color, color: this.color,
grid: {
left: 80,
bottom: 50
},
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: {
@ -441,6 +491,9 @@ export default {
data: obj.xAxisData data: obj.xAxisData
}, },
yAxis: { yAxis: {
axisLine: {
show: true
},
name: obj.unit, name: obj.unit,
type: 'value', type: 'value',
minInterval: 1 minInterval: 1
@ -474,11 +527,17 @@ export default {
// ... // ...
const option = { const option = {
title: { title: {
text: obj.titleText text: obj.titleText,
left: 0,
top: 0
}, },
toolbox: { toolbox: {
show: false show: false
}, },
grid: {
left: 80,
bottom: 50
},
color: this.color, color: this.color,
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
@ -498,8 +557,11 @@ export default {
yAxis: { yAxis: {
name: obj.unit, name: obj.unit,
type: 'value', type: 'value',
axisLine: {
show: true
},
axisLabel: { axisLabel: {
formatter: '{value}%' formatter: '{value}%',
} }
}, },
series: { series: {
@ -531,7 +593,13 @@ export default {
// ... // ...
const option = { const option = {
title: { title: {
text: obj.titleText text: obj.titleText,
left: 0,
top: 0
},
grid: {
left: 80,
bottom: 50
}, },
toolbox: { toolbox: {
show: false show: false
@ -550,7 +618,10 @@ export default {
}, },
yAxis: { yAxis: {
name: obj.unit, name: obj.unit,
type: 'value' type: 'value',
axisLine: {
show: true
}
}, },
series: { series: {
markLine: { markLine: {

View File

@ -382,6 +382,7 @@ export default {
size: files[i].size, size: files[i].size,
type: extendName.split('.')[1], type: extendName.split('.')[1],
file: files[i], file: files[i],
fileType: files[i].type
} }
this.fileList.push(obj); this.fileList.push(obj);
} }
@ -401,7 +402,17 @@ export default {
var timestamp = Date.now(); var timestamp = Date.now();
const res = await this.OSSclient.put( const res = await this.OSSclient.put(
`/${this.trialId}/ClinicalData/${timestamp}_${this.fileList[i].file.name}`, `/${this.trialId}/ClinicalData/${timestamp}_${this.fileList[i].file.name}`,
file file,
{
fileName: `${this.fileList[i].file.name}`,
fileSize: file.size,
fileType: this.fileList[i].fileType,
uploadBatchId: this.$guid(),
batchDataType: 4,
trialId: this.trialId,
subjectId: this.data.SubjectId,
subjectVisitId: this.subjectVisitId
}
); );
this.addFileList.push({ this.addFileList.push({
fileName: this.fileList[i].file.name, fileName: this.fileList[i].file.name,

View File

@ -1520,6 +1520,7 @@ export default {
}, },
} }
let arr = [] let arr = []
let uploadBatchId = scope.$guid()
for (let i = 0; i < seriesList.length; i++) { for (let i = 0; i < seriesList.length; i++) {
let v = seriesList[i] let v = seriesList[i]
let instanceList = [] let instanceList = []
@ -1587,6 +1588,7 @@ export default {
params.trialId params.trialId
)}` )}`
if (scope.isClose) return if (scope.isClose) return
console.log(o.file)
let res = await dcmUpload( let res = await dcmUpload(
{ {
path: path, path: path,
@ -1607,6 +1609,16 @@ export default {
) { ) {
dicomInfo.uploadFileSize = dicomInfo.fileSize dicomInfo.uploadFileSize = dicomInfo.fileSize
} }
},
{
fileName: o.file.name,
fileSize: o.file.size,
fileType: 'application/dicom',
uploadBatchId: uploadBatchId,
batchDataType: 1,
trialId: params.trialId,
subjectId: params.subjectId,
subjectVisitId: params.subjectVisitId
} }
) )
if (!res || !res.url) { if (!res || !res.url) {
@ -1623,11 +1635,22 @@ export default {
o.imageColumns, o.imageColumns,
o.imageRows o.imageRows
) )
let thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg` let thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
let OSSclient = scope.OSSclient let OSSclient = scope.OSSclient
let seriesRes = await OSSclient.put( let seriesRes = await OSSclient.put(
thumbnailPath, thumbnailPath,
blob blob,
{
fileName: `${v.seriesUid}.jpg`,
fileSize: blob.size,
fileType: 'image/jpeg',
uploadBatchId: uploadBatchId,
batchDataType: 2,
trialId: params.trialId,
subjectId: params.subjectId,
subjectVisitId: params.subjectVisitId
}
) )
if (seriesRes && seriesRes.url) { if (seriesRes && seriesRes.url) {
ImageResizePath = scope.$getObjectName( ImageResizePath = scope.$getObjectName(
@ -1762,7 +1785,20 @@ export default {
let thumbnailPath = `/${params.trialId}/Image/${params.trialSiteId}/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg` let thumbnailPath = `/${params.trialId}/Image/${params.trialSiteId}/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
let OSSclient = scope.OSSclient let OSSclient = scope.OSSclient
try { try {
let seriesRes = await OSSclient.put(thumbnailPath, blob) let seriesRes = await OSSclient.put(
thumbnailPath,
blob,
{
fileName: `${v.seriesUid}.jpg`,
fileSize: blob.size,
fileType: 'image/jpeg',
uploadBatchId: uploadBatchId,
batchDataType: 2,
trialId: params.trialId,
subjectId: params.subjectId,
subjectVisitId: params.subjectVisitId
}
)
if (seriesRes && seriesRes.url) { if (seriesRes && seriesRes.url) {
o.ImageResizePath = scope.$getObjectName(seriesRes.url) o.ImageResizePath = scope.$getObjectName(seriesRes.url)
} }
@ -1775,7 +1811,8 @@ export default {
params.study.instanceCount = dicomInfo.failedFileCount params.study.instanceCount = dicomInfo.failedFileCount
params.RecordPath = scope.$getObjectName(logRes.url) params.RecordPath = scope.$getObjectName(logRes.url)
if (scope.isClose) return false if (scope.isClose) return false
console.log(params)
params.UploadBatchId = uploadBatchId
addOrUpdateArchiveStudy(params) addOrUpdateArchiveStudy(params)
.then((res) => { .then((res) => {
if (dicomInfo.failedFileCount === dicomInfo.fileCount) { if (dicomInfo.failedFileCount === dicomInfo.fileCount) {

View File

@ -756,6 +756,7 @@ export default {
.substring(fileName.lastIndexOf('.')) .substring(fileName.lastIndexOf('.'))
.toLocaleLowerCase() .toLocaleLowerCase()
if (this.faccept.indexOf(extendName) !== -1) { if (this.faccept.indexOf(extendName) !== -1) {
files[i].fileName = files[i].name
files[i].id = `${files[i].lastModified}${files[i].name}` files[i].id = `${files[i].lastModified}${files[i].name}`
this.fileList.push(files[i]) this.fileList.push(files[i])
} }
@ -809,8 +810,9 @@ export default {
}) })
if (res.IsSuccess) { if (res.IsSuccess) {
this.studyMonitorId = res.Result this.studyMonitorId = res.Result
let uploadBatchId = this.$guid()
for (let i = 0; i < num; i++) { for (let i = 0; i < num; i++) {
funArr.push(this.handleUploadTask(this.selectArr, i)) funArr.push(this.handleUploadTask(this.selectArr, i, uploadBatchId))
} }
if (funArr.length > 0) { if (funArr.length > 0) {
let res = await Promise.all(funArr) let res = await Promise.all(funArr)
@ -821,17 +823,16 @@ export default {
} }
}, },
// //
async handleUploadTask(arr, index) { async handleUploadTask(arr, index, uploadBatchId) {
if (!this.uploadVisible) return if (!this.uploadVisible) return
let file = this.fileList.filter((item) => item.id === arr[index].id)[0] let file = this.fileList.filter((item) => item.id === arr[index].id)[0]
file.status = 1 file.status = 1
let fileName = `${this.$guid()}${file.name.substring(file.name.lastIndexOf('.')).toLocaleLowerCase()}`
let path = `/${this.trialId}/Image/${this.data.SubjectId}/${this.data.Id let path = `/${this.trialId}/Image/${this.data.SubjectId}/${this.data.Id
}/${this.$guid()}${file.name }/${fileName}`
.substring(file.name.lastIndexOf('.'))
.toLocaleLowerCase()}`
file.curPath = path file.curPath = path
const fileData = await this.fileToBlob(file.file) const fileData = await this.fileToBlob(file.file)
let res = await this.fileToOss(path, fileData, file) let res = await this.fileToOss(path, fileData, file, uploadBatchId)
if (res) { if (res) {
file.status = 2 file.status = 2
this.successFileList.push({ this.successFileList.push({
@ -865,13 +866,13 @@ export default {
} }
let ind = arr.findIndex((item) => item.status === 0) let ind = arr.findIndex((item) => item.status === 0)
if (ind >= 0) { if (ind >= 0) {
return this.handleUploadTask(arr, ind) return this.handleUploadTask(arr, ind, uploadBatchId)
} else { } else {
return false return false
} }
}, },
// fileoss // fileoss
async fileToOss(path, file, item) { async fileToOss(path, file, item, uploadBatchId) {
try { try {
let res = await this.OSSclient.multipartUpload( let res = await this.OSSclient.multipartUpload(
{ {
@ -884,6 +885,18 @@ export default {
if (item.uploadFileSize > file.fileSize) { if (item.uploadFileSize > file.fileSize) {
item.uploadFileSize = file.fileSize > 0 ? file.fileSize : 1 item.uploadFileSize = file.fileSize > 0 ? file.fileSize : 1
} }
},
{
fileName: item.name,
fileSize: item.size,
fileType: item.fileType,
uploadBatchId: uploadBatchId,
batchDataType: 3,
trialId: this.trialId,
subjectId: this.data.SubjectId,
subjectVisitId: this.subjectVisitId,
studyCode: this.currentRow.CodeView
} }
) )
if (res) { if (res) {

View File

@ -361,6 +361,7 @@ export default {
size: files[i].size, size: files[i].size,
type: extendName.split('.')[1], type: extendName.split('.')[1],
file: files[i], file: files[i],
fileType: files[i].type
} }
this.fileList.push(obj) this.fileList.push(obj)
} }
@ -380,7 +381,17 @@ export default {
var timestamp = Date.now() var timestamp = Date.now()
const res = await this.OSSclient.put( const res = await this.OSSclient.put(
`/${this.trialId}/ClinicalData/${timestamp}_${this.fileList[i].file.name}`, `/${this.trialId}/ClinicalData/${timestamp}_${this.fileList[i].file.name}`,
file file,
{
fileName: `${this.fileList[i].file.name}`,
fileSize: this.fileList[i].size,
fileType: this.fileList[i].fileType,
uploadBatchId: this.$guid(),
batchDataType: 4,
trialId: this.trialId,
subjectId: this.data.SubjectId,
subjectVisitId: this.subjectVisitId
}
) )
this.addFileList.push({ this.addFileList.push({
fileName: this.fileList[i].file.name, fileName: this.fileList[i].file.name,