Compare commits

..

2 Commits
main ... temp

Author SHA1 Message Date
caiyiling 4c642cd814 上传更改 2026-07-31 17:20:20 +08:00
caiyiling 9dcbad7616 数据处理更改 2026-07-31 16:40:37 +08:00
29 changed files with 667 additions and 569 deletions

View File

@ -4522,4 +4522,24 @@ export function addOrUpdateCommonUploadRecord(data) {
method: 'post', method: 'post',
data, data,
}) })
} }
export function getInspectionById(data) {
return request({
url: `/Inspection/getInspectionById`,
method: 'post',
data,
})
}
export function setJsonDetail(data) {
return request({
url: `/Inspection/setJsonDetail`,
method: 'post',
data,
})
}

View File

@ -80,7 +80,7 @@
import * as cornerstone from 'cornerstone-core' import * as cornerstone from 'cornerstone-core'
import * as cornerstoneMath from 'cornerstone-math' import * as cornerstoneMath from 'cornerstone-math'
import * as cornerstoneTools from 'cornerstone-tools' import * as cornerstoneTools from 'cornerstone-tools'
import metaDataProvider, { registerImageSharedCacheKey, unregisterImageSharedCacheKeys } from '@/utils/metaDataProvider' import metaDataProvider from '@/utils/metaDataProvider'
const scroll = cornerstoneTools.import('util/scrollToIndex') const scroll = cornerstoneTools.import('util/scrollToIndex')
import Hammer from 'hammerjs' import Hammer from 'hammerjs'
@ -211,9 +211,6 @@ export default {
this.stackScrollCallback this.stackScrollCallback
) )
}, },
beforeDestroy() {
unregisterImageSharedCacheKeys(this.stack?.imageIds)
},
methods: { methods: {
loadImageStack(dicomSeries, text = '') { loadImageStack(dicomSeries, text = '') {
@ -403,10 +400,6 @@ export default {
}, },
onNewImage(e) { onNewImage(e) {
e.detail.enabledElement.options = {} e.detail.enabledElement.options = {}
registerImageSharedCacheKey(
e.detail.image?.imageId,
e.detail.image?.sharedCacheKey
)
var data = e.detail.image.data var data = e.detail.image.data
this.dicomInfo.hospital = data.string('x00080080') this.dicomInfo.hospital = data.string('x00080080')
// let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === e.detail.image.imageId) // let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === e.detail.image.imageId)

View File

@ -477,10 +477,7 @@ export default {
let res = await getSubjectImageUploadList(params) let res = await getSubjectImageUploadList(params)
this.loading = false this.loading = false
if (res.IsSuccess) { if (res.IsSuccess) {
this.isDownloaded = this.Criterion && this.Criterion.CriterionType && ( this.isDownloaded = res.OtherInfo.IsIRImageDownloaded
this.Criterion.CriterionType == 19 ||
this.Criterion.CriterionType == 20
) ? res.OtherInfo.IsIRImageDownloaded : true
this.TrialModality = res.OtherInfo.TrialModality.split('|') this.TrialModality = res.OtherInfo.TrialModality.split('|')
this.IsReadingTaskViewInOrder = res.OtherInfo.IsReadingTaskViewInOrder || res.OtherInfo.IsReadingTaskViewInOrder === 0 ? res.OtherInfo.IsReadingTaskViewInOrder : 2 this.IsReadingTaskViewInOrder = res.OtherInfo.IsReadingTaskViewInOrder || res.OtherInfo.IsReadingTaskViewInOrder === 0 ? res.OtherInfo.IsReadingTaskViewInOrder : 2
this.StudyInstanceUidList = [] this.StudyInstanceUidList = []
@ -958,7 +955,7 @@ export default {
var instanceItem = instanceList.find(function (item) { var instanceItem = instanceList.find(function (item) {
return item.instanceUid === instanceUid return item.instanceUid === instanceUid
}) })
if (!instanceItem) { if (!false) {
var date = data.string('x00080023') var date = data.string('x00080023')
var time = data.string('x00080033') var time = data.string('x00080033')
var instanceTime = '' var instanceTime = ''
@ -1254,58 +1251,60 @@ export default {
try { try {
let o = v.instanceList[ii] let o = v.instanceList[ii]
let name = `${v.instanceList[ii].file.webkitRelativePath}_${v.instanceList[ii].instanceUid}` let name = `${v.instanceList[ii].file.webkitRelativePath}_${v.instanceList[ii].instanceUid}`
if (o.isReUpload) { // if (o.isReUpload) {
dicomInfo.failedFileCount++ // dicomInfo.failedFileCount++
dicomInfo.uploadFileSize += o.file.size // dicomInfo.uploadFileSize += o.file.size
Record.Existed.push(name) // Record.Existed.push(name)
Record.FileCount++ // Record.FileCount++
} else if (o.myPath) { // }
instanceList.push({ // else if (o.myPath) {
studyInstanceUid: dicomInfo.studyUid, // instanceList.push({
seriesInstanceUid: v.seriesUid, // studyInstanceUid: dicomInfo.studyUid,
SOPClassUID: o.SOPClassUID, // seriesInstanceUid: v.seriesUid,
TransferSytaxUID: o.TransferSytaxUID, // SOPClassUID: o.SOPClassUID,
MediaStorageSOPInstanceUID: // TransferSytaxUID: o.TransferSytaxUID,
o.MediaStorageSOPInstanceUID, // MediaStorageSOPInstanceUID:
MediaStorageSOPClassUID: // o.MediaStorageSOPInstanceUID,
o.MediaStorageSOPClassUID, // MediaStorageSOPClassUID:
sopInstanceUid: o.instanceUid, // o.MediaStorageSOPClassUID,
instanceNumber: o.instanceNumber, // sopInstanceUid: o.instanceUid,
instanceTime: o.instanceTime, // instanceNumber: o.instanceNumber,
imageRows: o.imageRows, // instanceTime: o.instanceTime,
imageColumns: o.imageColumns, // imageRows: o.imageRows,
sliceLocation: o.sliceLocation, // imageColumns: o.imageColumns,
sliceThickness: o.sliceThickness, // sliceLocation: o.sliceLocation,
numberOfFrames: o.numberOfFrames, // sliceThickness: o.sliceThickness,
pixelSpacing: o.pixelSpacing, // numberOfFrames: o.numberOfFrames,
imagerPixelSpacing: o.imagerPixelSpacing, // pixelSpacing: o.pixelSpacing,
frameOfReferenceUID: o.frameOfReferenceUID, // imagerPixelSpacing: o.imagerPixelSpacing,
windowCenter: o.windowCenter, // frameOfReferenceUID: o.frameOfReferenceUID,
windowWidth: o.windowWidth, // windowCenter: o.windowCenter,
path: o.myPath, // windowWidth: o.windowWidth,
FileSize: o.FileSize, // path: o.myPath,
// FileSize: o.FileSize,
PhotometricInterpretation: // PhotometricInterpretation:
o.PhotometricInterpretation, // o.PhotometricInterpretation,
BitsAllocated: o.BitsAllocated, // BitsAllocated: o.BitsAllocated,
PixelRepresentation: o.PixelRepresentation, // PixelRepresentation: o.PixelRepresentation,
RescaleIntercept: o.RescaleIntercept, // RescaleIntercept: o.RescaleIntercept,
RescaleSlope: o.RescaleSlope, // RescaleSlope: o.RescaleSlope,
ImagePositionPatient: o.ImagePositionPatient, // ImagePositionPatient: o.ImagePositionPatient,
ImageOrientationPatient: // ImageOrientationPatient:
o.ImageOrientationPatient, // o.ImageOrientationPatient,
SequenceOfUltrasoundRegions: // SequenceOfUltrasoundRegions:
o.SequenceOfUltrasoundRegions, // o.SequenceOfUltrasoundRegions,
FrameTime: o.FrameTime, // FrameTime: o.FrameTime,
CorrectedImage: o.CorrectedImage, // CorrectedImage: o.CorrectedImage,
Units: o.Units, // Units: o.Units,
DecayCorrection: o.DecayCorrection, // DecayCorrection: o.DecayCorrection,
EncapsulatedDocument: o.EncapsulatedDocument, // EncapsulatedDocument: o.EncapsulatedDocument,
}) // })
Record.Uploaded.push(name) // Record.Uploaded.push(name)
dicomInfo.failedFileCount++ // dicomInfo.failedFileCount++
Record.FileCount++ // Record.FileCount++
} else { // }
// else {
let path = `/${params.trialId}/Image/${params.subjectId let path = `/${params.trialId}/Image/${params.subjectId
}/${params.subjectVisitId}/${dicomInfo.visitTaskId }/${params.subjectVisitId}/${dicomInfo.visitTaskId
}/${scope.getGuid( }/${scope.getGuid(
@ -1446,7 +1445,7 @@ export default {
Record.Failed.push(name) Record.Failed.push(name)
Record.FileCount++ Record.FileCount++
} }
} // }
resolve1() resolve1()
} catch (e) { } catch (e) {
console.log(e) console.log(e)

View File

@ -104,7 +104,7 @@
<span v-else>{{ scope.row.UploadedFileCount }}</span> <span v-else>{{ scope.row.UploadedFileCount }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('common:action:action')" width="180"> <el-table-column :label="$t('common:action:action')" fixed="right" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<!--预览---> <!--预览--->
<el-button circle :disabled="scope.row.UploadedFileCount <= 0" icon="el-icon-view" <el-button circle :disabled="scope.row.UploadedFileCount <= 0" icon="el-icon-view"
@ -353,10 +353,7 @@ export default {
if (res.IsSuccess) { if (res.IsSuccess) {
this.list = res.Result this.list = res.Result
this.relationInfo = res.OtherInfo this.relationInfo = res.OtherInfo
this.isDownloaded = this.Criterion && this.Criterion.CriterionType && ( this.isDownloaded = res.OtherInfo.IsIRImageDownloaded
this.Criterion.CriterionType == 19 ||
this.Criterion.CriterionType == 20
) ? res.OtherInfo.IsIRImageDownloaded : true
this.faccept = [] this.faccept = []
this.relationInfo.ImageFormatList.forEach((item) => { this.relationInfo.ImageFormatList.forEach((item) => {
this.faccept.push(`.${item}`) this.faccept.push(`.${item}`)

View File

@ -119,25 +119,6 @@ function parseImageId(imageId) {
return { scheme, url, frame }; return { scheme, url, frame };
} }
const imageIdToSharedCacheKey = new Map();
export function registerImageSharedCacheKey(imageId, sharedCacheKey) {
if (!imageId || !sharedCacheKey) {
return;
}
imageIdToSharedCacheKey.set(imageId, sharedCacheKey);
}
export function unregisterImageSharedCacheKeys(imageIds) {
if (!Array.isArray(imageIds) || imageIds.length === 0) {
return;
}
imageIds.forEach((imageId) => {
if (imageId) {
imageIdToSharedCacheKey.delete(imageId);
}
});
}
function getNumberValues(dataSet, tag, minimumLength) { function getNumberValues(dataSet, tag, minimumLength) {
const values = []; const values = [];
const valueAsString = dataSet.string(tag); const valueAsString = dataSet.string(tag);
@ -276,20 +257,10 @@ function getSpacingBetweenSlices(dataSet) {
} }
function metaDataProvider(type, imageId) { function metaDataProvider(type, imageId) {
const parsedImageId = parseImageId(imageId); const parsedImageId = parseImageId(imageId);
let dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get( const dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(
parsedImageId.url parsedImageId.url
); );
if (!dataSet) {
const sharedCacheKey = imageIdToSharedCacheKey.get(imageId);
if (sharedCacheKey) {
dataSet = cornerstoneWADOImageLoader.wadouri.dataSetCacheManager.get(
sharedCacheKey
);
}
}
if (!dataSet) { if (!dataSet) {
return; return;
} }
@ -450,6 +421,7 @@ function metaDataProvider(type, imageId) {
let columnPixelSpacing = null; let columnPixelSpacing = null;
let rowPixelSpacing = null; let rowPixelSpacing = null;
if (pixelSpacing) { if (pixelSpacing) {
rowPixelSpacing = pixelSpacing[0]; rowPixelSpacing = pixelSpacing[0];
columnPixelSpacing = pixelSpacing[1]; columnPixelSpacing = pixelSpacing[1];

View File

@ -11,11 +11,10 @@ function zipFiles(zipName, files) {
store.dispatch('trials/setUnLock', true) store.dispatch('trials/setUnLock', true)
files = formatFiles(files) files = formatFiles(files)
// 创建压缩文件输出流 // 创建压缩文件输出流
let zipFileOutputStream = streamSaver.createWriteStream(zipName); const zipFileOutputStream = streamSaver.createWriteStream(zipName);
// 创建下载文件流 // 创建下载文件流
const fileIterator = files.values(); const fileIterator = files.values();
let Url = []; const readableZipStream = new ZIP({
let readableZipStream = new ZIP({
async pull(ctrl) { async pull(ctrl) {
const fileInfo = fileIterator.next(); const fileInfo = fileIterator.next();
if (fileInfo.done) {//迭代终止 if (fileInfo.done) {//迭代终止
@ -24,7 +23,6 @@ function zipFiles(zipName, files) {
let { name, url, IsEncapsulated = false } = fileInfo.value; let { name, url, IsEncapsulated = false } = fileInfo.value;
if (IsEncapsulated) { if (IsEncapsulated) {
url = await downloadFileToUrl(url) url = await downloadFileToUrl(url)
Url.push(url)
} }
// url = decodeUtf8(url); // 待定,可能做过特殊处理 // url = decodeUtf8(url); // 待定,可能做过特殊处理
return fetch(url).then(res => { return fetch(url).then(res => {
@ -42,31 +40,13 @@ function zipFiles(zipName, files) {
.pipeTo(zipFileOutputStream) .pipeTo(zipFileOutputStream)
.then(() => { .then(() => {
console.log("同步下载打包结束时间:" + new Date()); console.log("同步下载打包结束时间:" + new Date());
store.dispatch('trials/setUnLock', false)
resolve(true) resolve(true)
}).catch(err => { }).catch(err => {
console.log(err); console.log(err);
resolve(false) resolve(false)
}).finally(() => {
store.dispatch('trials/setUnLock', false)
readableZipStream = null;
zipFileOutputStream = null;
if (Url && Url.length > 0) {
Url.forEach(url => {
URL.revokeObjectURL(url)
})
Url = null
}
}); });
} else { } else {
store.dispatch('trials/setUnLock', false)
readableZipStream = null;
zipFileOutputStream = null;
if (Url && Url.length > 0) {
Url.forEach(url => {
URL.revokeObjectURL(url)
})
Url = null
}
resolve(false) resolve(false)
} }
} catch (err) { } catch (err) {
@ -81,17 +61,15 @@ async function updateFile(file, name) {
return new Promise(async resolve => { return new Promise(async resolve => {
try { try {
store.dispatch('trials/setUnLock', true) store.dispatch('trials/setUnLock', true)
let fileOutputStream = streamSaver.createWriteStream(name); const fileOutputStream = streamSaver.createWriteStream(name);
// file = decodeUtf8(file); // file = decodeUtf8(file);
let res = await fetch(file); let res = await fetch(file);
res.body.pipeTo(fileOutputStream).then(() => { res.body.pipeTo(fileOutputStream).then(() => {
store.dispatch('trials/setUnLock', true)
resolve(true) resolve(true)
}).catch(err => { }).catch(err => {
console.log(err) console.log(err)
resolve(false) resolve(false)
}).finally(() => {
store.dispatch('trials/setUnLock', false)
fileOutputStream = null;
}); });
} catch (err) { } catch (err) {
console.log(err) console.log(err)
@ -132,17 +110,13 @@ function downloadFileToUrl(url) {
xhr.open('GET', url); xhr.open('GET', url);
xhr.responseType = 'arraybuffer'; xhr.responseType = 'arraybuffer';
xhr.onload = function () { xhr.onload = function () {
try { const arraybuffer = xhr.response;
const arraybuffer = xhr.response; let dataset = dcmjs.data.DicomMessage.readFile(arraybuffer)
let dataset = dcmjs.data.DicomMessage.readFile(arraybuffer) let newDicomFile = dataset.write({ fragmentMultiframe: false, startOffset: false }) // fragmentMultiframe 原始数据是否进行分割
let newDicomFile = dataset.write({ fragmentMultiframe: false, startOffset: false }) // fragmentMultiframe 原始数据是否进行分割 const bufferArray = new Uint8Array(newDicomFile)
const bufferArray = new Uint8Array(newDicomFile) const blob = new Blob([bufferArray], { type: 'application/octet-stream' })
const blob = new Blob([bufferArray], { type: 'application/octet-stream' }) const href = URL.createObjectURL(blob)
const href = URL.createObjectURL(blob) resolve(href)
resolve(href)
} catch (err) {
reject(err);
}
}; };
xhr.send(); xhr.send();
}) })

View File

@ -133,7 +133,7 @@ import { mapGetters } from 'vuex'
import Contextmenu from 'vue-contextmenujs' import Contextmenu from 'vue-contextmenujs'
Vue.use(Contextmenu) Vue.use(Contextmenu)
import * as cornerstone from 'cornerstone-core' import * as cornerstone from 'cornerstone-core'
import metaDataProvider, { registerImageSharedCacheKey, unregisterImageSharedCacheKeys } from '@/utils/metaDataProvider' import metaDataProvider from '@/utils/metaDataProvider'
import * as cornerstoneMath from 'cornerstone-math' import * as cornerstoneMath from 'cornerstone-math'
import * as cornerstoneTools from 'cornerstone-tools' import * as cornerstoneTools from 'cornerstone-tools'
@ -480,7 +480,6 @@ export default {
}, },
beforeDestroy() { beforeDestroy() {
// Store.$off('getMeasureData') // Store.$off('getMeasureData')
unregisterImageSharedCacheKeys(this.stack?.imageIds)
DicomEvent.$off('setReadingState') DicomEvent.$off('setReadingState')
}, },
methods: { methods: {
@ -1280,7 +1279,6 @@ export default {
this.resetHideMeasureArr() this.resetHideMeasureArr()
} }
const { image } = e.detail const { image } = e.detail
registerImageSharedCacheKey(image?.imageId, image?.sharedCacheKey)
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
const imageId = image.imageId const imageId = image.imageId
ToolStateManager.clearImageIdToolState(imageId) ToolStateManager.clearImageIdToolState(imageId)

View File

@ -189,22 +189,11 @@
</template> </template>
<!-- 计算值 --> <!-- 计算值 -->
<Questions <Questions ref="ecrf2" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
ref="ecrf2" :group-classify="4" style="margin-top:20px" />
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="4"
:question-type="12"
style="margin-top:20px" />
<!-- 评估结果 --> <!-- 评估结果 -->
<Questions <Questions ref="ecrf3" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
ref="ecrf3"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:question-type="12"
:group-classify="5" /> :group-classify="5" />
<!-- 新增编辑弹窗 --> <!-- 新增编辑弹窗 -->
<el-dialog v-if="addOrEdit.visible" :visible.sync="addOrEdit.visible" :close-on-click-modal="false" <el-dialog v-if="addOrEdit.visible" :visible.sync="addOrEdit.visible" :close-on-click-modal="false"
@ -633,7 +622,7 @@ export default {
return v return v
} }
}, },
async handleSave(index, options = {}) { async handleSave(index) {
if (this.rowSaveLoadingMap[index]) return if (this.rowSaveLoadingMap[index]) return
const refName = `questions${index}` const refName = `questions${index}`
this.$set(this.rowSaveLoadingMap, index, true) this.$set(this.rowSaveLoadingMap, index, true)
@ -651,13 +640,9 @@ export default {
answers: answers answers: answers
} }
await saveTaskQuestion(12, params) await saveTaskQuestion(12, params)
if (!options.silentSuccess) { this.$message.success(this.$t('common:message:savedSuccessfully'))
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
DicomEvent.$emit('getReportInfo', true) DicomEvent.$emit('getReportInfo', true)
if (!options.skipRefresh) { this.refreshQuestions()
await this.refreshQuestions()
}
this.formChanged = false this.formChanged = false
} catch (e) { } catch (e) {
console.log(e) console.log(e)
@ -873,29 +858,9 @@ export default {
} }
}, },
async uploadDlgClose() { async uploadDlgClose() {
try { this.refreshQuestions()
await this.refreshQuestions() DicomEvent.$emit('getReportInfo', true)
const saveTasks = [] this.upload.visible = false
for (let index = 0; index < this.questions.length; index++) {
const qs = this.questions[index]
if (qs.GroupClassify === 6) {
saveTasks.push(() => this.handleSave(index, { silentSuccess: true, skipRefresh: true }))
}
}
saveTasks.push(() => this.$refs['ecrf2'] && this.$refs['ecrf2'].handleSave({ silentSuccess: true, skipRefresh: true }))
saveTasks.push(() => this.$refs['ecrf3'] && this.$refs['ecrf3'].handleSave({ silentSuccess: true, skipRefresh: true }))
for (const saveTask of saveTasks) {
try {
await saveTask()
} catch (e) {
console.log(e)
}
}
} catch (e) {
console.log(e)
} finally {
this.upload.visible = false
}
}, },
renderHeader(h, { column, $index }) { renderHeader(h, { column, $index }) {
const span = document.createElement('span') const span = document.createElement('span')

View File

@ -189,22 +189,11 @@
</template> </template>
<!-- 计算值 --> <!-- 计算值 -->
<Questions <Questions ref="ecrf2" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
ref="ecrf2" :group-classify="4" style="margin-top:20px" />
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="4"
:question-type="12"
style="margin-top:20px" />
<!-- 评估结果 --> <!-- 评估结果 -->
<Questions <Questions ref="ecrf3" :question-form-change-state="true" :question-form-change-num="0" :is-qulity-issues="false"
ref="ecrf3"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:question-type="12"
:group-classify="5" /> :group-classify="5" />
<el-dialog v-if="addOrEdit.visible" :visible.sync="addOrEdit.visible" :close-on-click-modal="false" <el-dialog v-if="addOrEdit.visible" :visible.sync="addOrEdit.visible" :close-on-click-modal="false"
:title="addOrEdit.title" width="500px"> :title="addOrEdit.title" width="500px">
@ -628,7 +617,7 @@ export default {
return v return v
} }
}, },
async handleSave(index, options = {}) { async handleSave(index) {
if (this.rowSaveLoadingMap[index]) return if (this.rowSaveLoadingMap[index]) return
const refName = `questions${index}` const refName = `questions${index}`
this.$set(this.rowSaveLoadingMap, index, true) this.$set(this.rowSaveLoadingMap, index, true)
@ -646,13 +635,9 @@ export default {
answers: answers answers: answers
} }
await saveTaskQuestion(12, params) await saveTaskQuestion(12, params)
if (!options.silentSuccess) { this.$message.success(this.$t('common:message:savedSuccessfully'))
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
DicomEvent.$emit('getReportInfo', true) DicomEvent.$emit('getReportInfo', true)
if (!options.skipRefresh) { this.refreshQuestions()
await this.refreshQuestions()
}
this.formChanged = false this.formChanged = false
} catch (e) { } catch (e) {
console.log(e) console.log(e)
@ -899,29 +884,9 @@ export default {
} }
}, },
async uploadDlgClose() { async uploadDlgClose() {
try { this.refreshQuestions()
await this.refreshQuestions() DicomEvent.$emit('getReportInfo', true)
const saveTasks = [] this.upload.visible = false
for (let index = 0; index < this.questions.length; index++) {
const qs = this.questions[index]
if (qs.GroupClassify === 6) {
saveTasks.push(() => this.handleSave(index, { silentSuccess: true, skipRefresh: true }))
}
}
saveTasks.push(() => this.$refs['ecrf2'] && this.$refs['ecrf2'].handleSave({ silentSuccess: true, skipRefresh: true }))
saveTasks.push(() => this.$refs['ecrf3'] && this.$refs['ecrf3'].handleSave({ silentSuccess: true, skipRefresh: true }))
for (const saveTask of saveTasks) {
try {
await saveTask()
} catch (e) {
console.log(e)
}
}
} catch (e) {
console.log(e)
} finally {
this.upload.visible = false
}
}, },
renderHeader(h, { column, $index }) { renderHeader(h, { column, $index }) {
const span = document.createElement('span') const span = document.createElement('span')

View File

@ -279,86 +279,84 @@ export default {
}) })
}, },
async handleSave(options = {}) { handleSave() {
if (this.saveLoading) return false if (this.saveLoading) return
this.saveLoading = true this.saveLoading = true
const valid = await new Promise(resolve => { this.$refs['questions'].validate(async (valid) => {
this.$refs['questions'].validate(v => resolve(v)) if (!valid) {
})
if (!valid) {
this.saveLoading = false
return false
}
// lugano
if ((this.criterionType === 2 || this.criterionType === 18) && this.groupClassify === 3) {
//
var existUnSave = this.checkAnnotationStatus(this.questions)
if (existUnSave) {
await this.$alert(this.$t('trials:lugano:message:saveWarning'), this.$t('trials:lugano:fusionDialog:warning'))
this.saveLoading = false this.saveLoading = false
return false return
} }
// lugano
if ((this.criterionType === 2 || this.criterionType === 18) && this.groupClassify === 3) {
//
var existUnSave = this.checkAnnotationStatus(this.questions)
if (existUnSave) {
this.$alert(this.$t('trials:lugano:message:saveWarning'), this.$t('trials:lugano:fusionDialog:warning'))
this.saveLoading = false
return
}
var currentSpleenStatus = this.questionForm[this.spleenStatusId] var currentSpleenStatus = this.questionForm[this.spleenStatusId]
var currentSpleenLength = this.questionForm[this.spleenLengthId] var currentSpleenLength = this.questionForm[this.spleenLengthId]
currentSpleenStatus = isNaN(parseInt(currentSpleenStatus)) ? null : parseInt(currentSpleenStatus) currentSpleenStatus = isNaN(parseInt(currentSpleenStatus)) ? null : parseInt(currentSpleenStatus)
var stIdx = this.measurements.findIndex(i => i.QuestionType === 60) var stIdx = this.measurements.findIndex(i => i.QuestionType === 60)
var slIdx = this.measurements.findIndex(i => i.QuestionType === 61) var slIdx = this.measurements.findIndex(i => i.QuestionType === 61)
if (currentSpleenLength && currentSpleenStatus === 5) { if (currentSpleenLength && currentSpleenStatus === 5) {
// '!' // '!'
await this.$alert(this.$t('trials:lugano:message:validSpleen1'), this.$t('trials:lugano:fusionDialog:warning'), { this.$alert(this.$t('trials:lugano:message:validSpleen1'), this.$t('trials:lugano:fusionDialog:warning'), {
callback: _ => { } callback: _ => { }
}) })
this.saveLoading = false this.saveLoading = false
return false } else if (currentSpleenStatus === 5 && ((stIdx > -1 && this.measurements[stIdx].MeasureData) || (slIdx > -1 && this.measurements[slIdx].MeasureData))) {
} else if (currentSpleenStatus === 5 && ((stIdx > -1 && this.measurements[stIdx].MeasureData) || (slIdx > -1 && this.measurements[slIdx].MeasureData))) { //
// this.$alert(this.$t('trials:lugano:message:validSpleen1'), this.$t('trials:lugano:fusionDialog:warning'), {
await this.$alert(this.$t('trials:lugano:message:validSpleen1'), this.$t('trials:lugano:fusionDialog:warning'), { callback: _ => { }
callback: _ => { } })
}) this.saveLoading = false
this.saveLoading = false } else if (((stIdx > -1 && this.measurements[stIdx].MeasureData) || (slIdx > -1 && this.measurements[slIdx].MeasureData)) && !currentSpleenLength) {
return false this.$alert(this.$t('trials:lugano:message:validSpleen2'), this.$t('trials:lugano:fusionDialog:warning'), {
} else if (((stIdx > -1 && this.measurements[stIdx].MeasureData) || (slIdx > -1 && this.measurements[slIdx].MeasureData)) && !currentSpleenLength) { callback: _ => { }
await this.$alert(this.$t('trials:lugano:message:validSpleen2'), this.$t('trials:lugano:fusionDialog:warning'), { })
callback: _ => { } this.saveLoading = false
}) } else {
this.saveLoading = false this.saveQuestionsList()
return false }
} } else if ((this.criterionType === 2 || this.criterionType === 18) && this.groupClassify === 1 && this.questionForm[this.imageQualityIssuesId] && parseInt(this.questionForm[this.imageQualityIssuesId]) === 6) {
return await this.saveQuestionsList(options) // PET-CT
} else if ((this.criterionType === 2 || this.criterionType === 18) && this.groupClassify === 1 && this.questionForm[this.imageQualityIssuesId] && parseInt(this.questionForm[this.imageQualityIssuesId]) === 6) { let res = null
// PET-CT if (this.criterionType === 18) {
let res = null res = await getCanChooseNotMergeNoPet({ visitTaskId: this.visitTaskId })
if (this.criterionType === 18) { } else {
res = await getCanChooseNotMergeNoPet({ visitTaskId: this.visitTaskId }) res = await getCanChooseNotMerge({ visitTaskId: this.visitTaskId })
}
if (res.IsSuccess && !res.Result.IsCanChooseNotMerge) {
// this.$alert(this.$t('trials:lugano:saveQuestions:warning1'), this.$t('trials:lugano:fusionDialog:warning'), {showCancelButton: false})
this.$alert(this.$t('trials:lugano:saveQuestions:warning1'), this.$t('trials:lugano:fusionDialog:warning'), {
showCancelButton: false,
callback: action => { }
})
this.saveLoading = false
return
} else {
// PET-CTFDG-PETNE
this.$confirm(this.$t('trials:lugano:saveQuestions:warning2'), {
type: 'warning',
distinguishCancelAndClose: true
})
.then(() => {
this.saveQuestionsList()
})
}
} else { } else {
res = await getCanChooseNotMerge({ visitTaskId: this.visitTaskId }) this.saveQuestionsList()
} }
// this.saveQuestionsList()
if (res.IsSuccess && !res.Result.IsCanChooseNotMerge) { })
await this.$alert(this.$t('trials:lugano:saveQuestions:warning1'), this.$t('trials:lugano:fusionDialog:warning'), {
showCancelButton: false,
callback: action => { }
})
this.saveLoading = false
return false
}
// PET-CTFDG-PETNE
const confirm = await this.$confirm(this.$t('trials:lugano:saveQuestions:warning2'), {
type: 'warning',
distinguishCancelAndClose: true
}).then(() => true).catch(() => false)
if (!confirm) {
this.saveLoading = false
return false
}
return await this.saveQuestionsList(options)
} else {
return await this.saveQuestionsList(options)
}
}, },
async saveQuestionsList(options = {}) { async saveQuestionsList() {
this.loading = true this.loading = true
var answers = [] var answers = []
var imageQuality = null var imageQuality = null
@ -384,22 +382,18 @@ export default {
// }) // })
// params.questionMarkInfoList = questionMarkInfoList // params.questionMarkInfoList = questionMarkInfoList
// } // }
try {
const res = await saveTaskQuestion(this.questionType, params) saveTaskQuestion(this.questionType, params).then(async res => {
if (this.imageQualityIssuesId) { if (this.imageQualityIssuesId) {
store.dispatch('reading/setImageQualityIssues', this.questionForm[this.imageQualityIssuesId]) store.dispatch('reading/setImageQualityIssues', this.questionForm[this.imageQualityIssuesId])
if (this.questionForm[this.imageQualityIssuesId] && parseInt(this.questionForm[this.imageQualityIssuesId]) === 6) { if (this.questionForm[this.imageQualityIssuesId] && parseInt(this.questionForm[this.imageQualityIssuesId]) === 6) {
DicomEvent.$emit('closePetct') DicomEvent.$emit('closePetct')
} }
} }
if (!options.silentSuccess) { this.$message.success(this.$t('common:message:savedSuccessfully'))
this.$message.success(this.$t('common:message:savedSuccessfully')) var trialId = this.$route.query.trialId
} await store.dispatch('reading/refreshDicomReadingQuestionAnswer', { trialId: trialId, visitTaskId: this.visitTaskId })
if (!options.skipRefresh) { this.getQuestions(this.visitTaskId, true)
var trialId = this.$route.query.trialId
await store.dispatch('reading/refreshDicomReadingQuestionAnswer', { trialId: trialId, visitTaskId: this.visitTaskId })
this.getQuestions(this.visitTaskId, true)
}
this.loading = false this.loading = false
if (this.isQulityIssues) { if (this.isQulityIssues) {
DicomEvent.$emit('questionFormChange', false) DicomEvent.$emit('questionFormChange', false)
@ -423,12 +417,10 @@ export default {
} }
this.formChanged = false this.formChanged = false
this.saveLoading = false this.saveLoading = false
return res }).catch(() => {
} catch (e) {
this.loading = false this.loading = false
this.saveLoading = false this.saveLoading = false
throw e })
}
}, },
checkAnnotationStatus(obj) { checkAnnotationStatus(obj) {
for (let i = 0; i < obj.length; i++) { for (let i = 0; i < obj.length; i++) {

View File

@ -126,7 +126,7 @@ import { mapGetters } from 'vuex'
import Contextmenu from 'vue-contextmenujs' import Contextmenu from 'vue-contextmenujs'
Vue.use(Contextmenu) Vue.use(Contextmenu)
import * as cornerstone from 'cornerstone-core' import * as cornerstone from 'cornerstone-core'
import metaDataProvider, { registerImageSharedCacheKey, unregisterImageSharedCacheKeys } from '@/utils/metaDataProvider' import metaDataProvider from '@/utils/metaDataProvider'
import * as cornerstoneMath from 'cornerstone-math' import * as cornerstoneMath from 'cornerstone-math'
import * as cornerstoneTools from 'cornerstone-tools' import * as cornerstoneTools from 'cornerstone-tools'
@ -473,7 +473,6 @@ export default {
}, },
beforeDestroy() { beforeDestroy() {
// Store.$off('getMeasureData') // Store.$off('getMeasureData')
unregisterImageSharedCacheKeys(this.stack?.imageIds)
DicomEvent.$off('setReadingState') DicomEvent.$off('setReadingState')
DicomEvent.$off('updateImage') DicomEvent.$off('updateImage')
}, },
@ -1187,7 +1186,6 @@ export default {
this.resetHideMeasureArr() this.resetHideMeasureArr()
} }
const { image } = e.detail const { image } = e.detail
registerImageSharedCacheKey(image?.imageId, image?.sharedCacheKey)
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
const imageId = image.imageId const imageId = image.imageId
ToolStateManager.clearImageIdToolState(imageId) ToolStateManager.clearImageIdToolState(imageId)

View File

@ -309,9 +309,10 @@
<div class="text">{{ $t('trials:reading:button:reset') }}</div> <div class="text">{{ $t('trials:reading:button:reset') }}</div>
</div> </div>
</el-tooltip> </el-tooltip>
<el-tooltip v-if=" <el-tooltip
trialCriterion.ImageUploadEnum > 0 && currentReadingTaskState < 2 v-if="trialCriterion.ImageUploadEnum > 0"
" v-hasPermi="['role:ir']" class="item" effect="dark" :content="$t('trials:reading:button:upload')" class="item" effect="dark"
:content="$t('trials:reading:button:upload')"
placement="bottom"> placement="bottom">
<div class="tool-wrapper"> <div class="tool-wrapper">
<div class="icon" @click.prevent="openUploadImage('upload')"> <div class="icon" @click.prevent="openUploadImage('upload')">
@ -411,7 +412,7 @@
<WL v-if="activeName === '2'" @getWwcTpl="getWwcTpl" /> <WL v-if="activeName === '2'" @getWwcTpl="getWwcTpl" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('trials:reading:tab:others')" name="3"> <el-tab-pane :label="$t('trials:reading:tab:others')" name="3">
<Others v-if="activeName === '3'" :imageToolType="1" /> <Others v-if="activeName === '3'" :imageToolType="1"/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</el-dialog> </el-dialog>
@ -448,10 +449,10 @@
/> --> /> -->
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :SubjectId="uploadSubjectId" :SubjectCode="uploadSubjectCode" <upload-dicom-and-nonedicom v-if="uploadImageVisible" :SubjectId="uploadSubjectId" :SubjectCode="uploadSubjectCode"
:Criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible" :VisitTaskId="taskId" :Criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible" :VisitTaskId="taskId"
:isReadingTaskViewInOrder="isReadingTaskViewInOrder" :isReading="true" /> :isReadingTaskViewInOrder="isReadingTaskViewInOrder" />
<download-dicom-and-nonedicom v-if="downloadImageVisible" :SubjectId="uploadSubjectId" <download-dicom-and-nonedicom v-if="downloadImageVisible" :SubjectId="uploadSubjectId"
:SubjectCode="uploadSubjectCode" :Criterion="uploadTrialCriterion" :TaskId="taskId" :SubjectCode="uploadSubjectCode" :Criterion="uploadTrialCriterion" :TaskId="taskId"
:visible.sync="downloadImageVisible" :isReading="true"/> :visible.sync="downloadImageVisible" />
</div> </div>
</template> </template>
<script> <script>

View File

@ -128,7 +128,7 @@ export default {
immediate: true, immediate: true,
handler(val) { handler(val) {
if (val) { if (val) {
this.readingTaskState = val this.readingTaskState = 1
} }
} }
} }
@ -169,7 +169,7 @@ export default {
if (i > -1) { if (i > -1) {
this.visitTaskId = this.visitTaskList[i].VisitTaskId this.visitTaskId = this.visitTaskList[i].VisitTaskId
this.taskBlindName = this.visitTaskList[i].TaskBlindName this.taskBlindName = this.visitTaskList[i].TaskBlindName
this.readingTaskState = this.visitTaskList[i].ReadingTaskState this.readingTaskState = 1
console.log(this.visitTaskList[i].IsInit) console.log(this.visitTaskList[i].IsInit)
if (!this.visitTaskList[i].IsInit) { if (!this.visitTaskList[i].IsInit) {
var loading = this.$loading({ fullscreen: true }) var loading = this.$loading({ fullscreen: true })
@ -306,9 +306,9 @@ export default {
} }
this.signVisible = false this.signVisible = false
// //
this.readingTaskState = 2 this.readingTaskState = 1
store.dispatch('reading/setVisitTaskReadingTaskState', { visitTaskId: this.visitTaskId, readingTaskState: 2 }) store.dispatch('reading/setVisitTaskReadingTaskState', { visitTaskId: this.visitTaskId, readingTaskState: 1 })
DicomEvent.$emit('setReadingState', 2) DicomEvent.$emit('setReadingState', 1)
window.opener.postMessage('refreshTaskList', window.location) window.opener.postMessage('refreshTaskList', window.location)
this.$confirm(this.$t('trials:oncologyReview:title:msg2'), { this.$confirm(this.$t('trials:oncologyReview:title:msg2'), {
type: 'warning', type: 'warning',

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-loading="loading" style="min-height: 500px;"> <div v-loading="loading" style="min-height: 500px;">
<el-form v-if="isRender" ref="questions" size="small" :model="questionForm" :disabled="readingTaskState >= 2"> <el-form v-if="isRender" ref="questions" size="small" :model="questionForm">
<template> <template>
<QuestionFormItem v-for="question of questions" :key="question.Id" :visitTaskId="visitTaskId" <QuestionFormItem v-for="question of questions" :key="question.Id" :visitTaskId="visitTaskId"
:question="question" :question-form="questionForm" :reading-task-state="readingTaskState" :question="question" :question-form="questionForm" :reading-task-state="readingTaskState"
@ -112,8 +112,8 @@ export default {
VisitTaskId: visitTaskId ? visitTaskId : this.visitTaskId VisitTaskId: visitTaskId ? visitTaskId : this.visitTaskId
}).then(res => { }).then(res => {
this.IsBaseline = res.OtherInfo.IsBaseline this.IsBaseline = res.OtherInfo.IsBaseline
this.readingTaskState = res.OtherInfo.ReadingTaskState this.readingTaskState = 1
DicomEvent.$emit('setReadingState', res.OtherInfo.ReadingTaskState) DicomEvent.$emit('setReadingState', 1)
res.Result.SinglePage.map((v) => { res.Result.SinglePage.map((v) => {
if (v.Type === 'group' && v.Childrens.length === 0) return if (v.Type === 'group' && v.Childrens.length === 0) return
if (!v.IsPage && v.Type !== 'group' && v.Type !== 'summary' && v.Type !== 'table' && v.Type !== 'basicTable' && v.Type !== 'number') { if (!v.IsPage && v.Type !== 'group' && v.Type !== 'summary' && v.Type !== 'table' && v.Type !== 'basicTable' && v.Type !== 'number') {

View File

@ -147,7 +147,7 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div style="text-align:right;margin-top: 10px;" v-if="!IsViewStudyPart"> <div style="text-align:right;margin-top: 10px;">
<!-- 确认 --> <!-- 确认 -->
<el-button type="primary" @click="handleConfirmBP">{{ $t('trials:reading:button:confirm') <el-button type="primary" @click="handleConfirmBP">{{ $t('trials:reading:button:confirm')
}}</el-button> }}</el-button>
@ -223,8 +223,7 @@ export default {
readingVersionEnum: null, readingVersionEnum: null,
dialogBodyPartVisible: false, dialogBodyPartVisible: false,
isReadKeyFile: true, isReadKeyFile: true,
isHaveKeyFile: false, isHaveKeyFile: false
IsViewStudyPart: true
} }
}, },
computed: { computed: {

View File

@ -160,17 +160,6 @@
<svg-icon v-if="forceFitToWindow" icon-class="fitToWindow" class="svg-icon" /> <svg-icon v-if="forceFitToWindow" icon-class="fitToWindow" class="svg-icon" />
<svg-icon v-else icon-class="fitToImage" class="svg-icon" /> <svg-icon v-else icon-class="fitToImage" class="svg-icon" />
</div> </div>
<!-- 同步切图 -->
<div v-if="!isFusion && !isMPR && cells.length > 1"
:class="['tool-item', isScrollSync ? 'tool-item-active' : '']"
:title="$t('trials:reading:button:imageIndexSync')" @click.prevent="setImageIndexSync">
<i v-if="isScrollSync" class="el-icon-lock svg-icon" />
<i v-else class="el-icon-unlock svg-icon" />
</div>
<!-- 截图 -->
<div class="tool-item" :title="$t('trials:reading:button:screenShot')" @click.prevent="saveImage">
<svg-icon icon-class="image" class="svg-icon" />
</div>
<!-- MPR --> <!-- MPR -->
<div class="tool-item" :title="`${$t('trials:reading:button:mpr')}`" @click.prevent="openMPRViewport()" <div class="tool-item" :title="`${$t('trials:reading:button:mpr')}`" @click.prevent="openMPRViewport()"
v-if="((criterionType === 0 && readingTool === 0) || this.readingTool === 3) && !isMPR"> v-if="((criterionType === 0 && readingTool === 0) || this.readingTool === 3) && !isMPR">
@ -331,7 +320,7 @@
</div> </div>
</div> </div>
<div class="tool-item" :title="$t('trials:reading:button:upload')" <div class="tool-item" :title="$t('trials:reading:button:upload')"
v-if="trialCriterion.ImageUploadEnum > 0 && readingTaskState < 2" v-hasPermi="['role:ir']"> v-if="trialCriterion.ImageUploadEnum > 0" v-hasPermi="['role:ir']">
<div class="tool-wrapper"> <div class="tool-wrapper">
<div class="icon" @click.prevent="openUploadImage('upload')"> <div class="icon" @click.prevent="openUploadImage('upload')">
<i class="el-icon-upload2 svg-icon" /> <i class="el-icon-upload2 svg-icon" />
@ -392,16 +381,13 @@
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="index" :rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="index"
:histogramVisible="histogramVisible" :actionConfiguration="actionConfiguration" :histogramVisible="histogramVisible" :actionConfiguration="actionConfiguration"
:SegmentConfig="SegmentConfig" :segmentationId.sync="segId" :segmentIndex.sync="segIndex" :SegmentConfig="SegmentConfig" :segmentationId.sync="segId" :segmentIndex.sync="segIndex"
:curSegSeries.sync="curSegSeries" :is-scroll-sync="isScrollSync" :curSegSeries.sync="curSegSeries" @activeViewport="activeViewport"
@activeViewport="activeViewport"
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" @renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
@resetViewport="resetViewport" @resetHistogram="resetHistogram" @resetViewport="resetViewport" @resetHistogram="resetHistogram" v-if="readingTool === 3"
@scrollSync="handleViewportScrollSync" v-if="readingTool === 3"
v-resize="(e) => handleSizeChange(e, `viewport-${index}`)" /> 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"
:is-scroll-sync="isScrollSync" @scrollSync="handleViewportScrollSync"
@activeViewport="activeViewport" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD" @activeViewport="activeViewport" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" v-else /> @renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" v-else />
</div> </div>
@ -813,7 +799,6 @@ export default {
activeViewportWC: null, activeViewportWC: null,
clipPlaying: false, clipPlaying: false,
fps: 15, fps: 15,
isScrollSync: false,
manualsDialog: { visible: false, isFullscreen: false, justKeyDoc: false }, manualsDialog: { visible: false, isFullscreen: false, justKeyDoc: false },
hotKeyList: [], hotKeyList: [],
forceFitToWindow: false, forceFitToWindow: false,
@ -3430,34 +3415,8 @@ export default {
scrollPage(type) { scrollPage(type) {
// if (this.histogramVisible) return false // if (this.histogramVisible) return false
this.clipPlaying = false this.clipPlaying = false
if (this.isScrollSync && !this.isFusion && !this.isMPR && this.cells.length > 1) {
for (let i = 0; i < this.cells.length; i++) {
const viewportRef = this.$refs[`${this.viewportKey}-${i}`]
if (viewportRef && viewportRef[0] && typeof viewportRef[0].scrollPage === 'function') {
viewportRef[0].scrollPage(type)
}
}
return
}
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].scrollPage(type) this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].scrollPage(type)
}, },
setImageIndexSync() {
this.isScrollSync = !this.isScrollSync
},
handleViewportScrollSync({ viewportIndex, type, direction }) {
if (!this.isScrollSync || this.isFusion || this.isMPR || this.cells.length <= 1) return
const syncType = type ?? direction
if (viewportIndex !== this.activeViewportIndex || ![-1, 1, 0, 99999].includes(syncType)) return
this.clipPlaying = false
for (let i = 0; i < this.cells.length; i++) {
if (i === viewportIndex) continue
const viewportRef = this.$refs[`${this.viewportKey}-${i}`]
if (viewportRef && viewportRef[0] && typeof viewportRef[0].scrollPage === 'function') {
viewportRef[0].scrollPage(syncType)
}
}
},
// //
toggleClipPlay(isPlay) { toggleClipPlay(isPlay) {
// if (this.histogramVisible) return false // if (this.histogramVisible) return false
@ -3764,7 +3723,7 @@ export default {
}) })
this.setToolsPassive() this.setToolsPassive()
}, },
async activeSeries(obj, isSave = false) { async activeSeries(obj) {
if (this.readingTool === 3) { if (this.readingTool === 3) {
let res = await this.changeScreenSave() let res = await this.changeScreenSave()
if (!res) return false if (!res) return false
@ -3776,7 +3735,6 @@ export default {
if (!confirm) return false if (!confirm) return false
this.$refs[`ecrf_${this.taskInfo.VisitTaskId}`][0].removeAllNoSaveAnnotation() this.$refs[`ecrf_${this.taskInfo.VisitTaskId}`][0].removeAllNoSaveAnnotation()
} else { } else {
if (isSave) return false
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
} }
@ -4064,7 +4022,7 @@ export default {
} }
let res = await this.openMPRViewport(series) let res = await this.openMPRViewport(series)
if (!res) { if (!res) {
this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex, true) this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
setTimeout(async () => { setTimeout(async () => {
const divForDownloadViewport = document.querySelector( const divForDownloadViewport = document.querySelector(
`div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]` `div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]`
@ -4576,7 +4534,7 @@ export default {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
this.setToolsPassive() this.setToolsPassive()
if (this.isMPR) { if (this.isMPR) {
this.activeSeries(this.$refs[`viewport-MPR-0`][0].series, true) this.activeSeries(this.$refs[`viewport-MPR-0`][0].series)
resolve(false) resolve(false)
if (!data) return resolve(false) if (!data) return resolve(false)
let viewportSeries = this.$refs[`viewport-MPR-0`][0].series let viewportSeries = this.$refs[`viewport-MPR-0`][0].series

View File

@ -804,16 +804,12 @@ export default {
toolGroup.setToolPassive(this.activeTool) toolGroup.setToolPassive(this.activeTool)
} }
this.$emit('update:activeTool', '') this.$emit('update:activeTool', '')
} else if (this.activeTool === name) {
toolGroup.setToolPassive(this.ThresholdTools[1])
this.$emit('update:activeTool', '')
} else { } else {
if (this.activeTool) { if (this.activeTool) {
if (toolName === CrosshairsTool.toolName) { if (toolName === CrosshairsTool.toolName) {
toolGroup.setToolDisabled(this.activeTool) toolGroup.setToolDisabled(this.activeTool)
} else { } else {
toolGroup.setToolPassive(this.activeTool) toolGroup.setToolPassive(this.activeTool)
toolGroup.setToolPassive(this.ThresholdTools[1])
} }
} }
toolGroup.setToolActive(toolName, { toolGroup.setToolActive(toolName, {

View File

@ -14,7 +14,7 @@
<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}`"> <el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`" :name="`${study.StudyId}`">
<template slot="title"> <template slot="title">
<div v-if="!study.IsCriticalSequence" class="dicom-desc"> <div v-if="!study.IsCriticalSequence" class="dicom-desc">
<div style="text-overflow: ellipsis;overflow: hidden;"> <div style="text-overflow: ellipsis;overflow: hidden;">
@ -24,8 +24,7 @@
</div> </div>
<div> <div>
<span class="study-meta-line" :title="study.Modalities"> <span class="study-meta-line" :title="study.Modalities">
<span v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder !== 0" class="study-code" <span v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder !== 0" class="study-code" :title="study.StudyCode">{{ study.StudyCode }}</span>
:title="study.StudyCode">{{ study.StudyCode }}</span>
<span class="study-modality">{{ `${study.Modalities}(${study.SeriesCount})` }}</span> <span class="study-modality">{{ `${study.Modalities}(${study.SeriesCount})` }}</span>
<span class="patient-info" v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities)"> <span class="patient-info" v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities)">
<el-popover placement="right-start" trigger="hover" popper-class="patient-info-popper"> <el-popover placement="right-start" trigger="hover" popper-class="patient-info-popper">
@ -82,7 +81,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"
:class="{ 'frame_content_active': activeInstanceId === instance.Id }" :class="{ 'frame_content_active': activeInstanceId === instance.Id }"
: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)">
@ -130,7 +130,7 @@
</div> </div>
</div> </div>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
</div> </div>
@ -205,19 +205,18 @@ export default {
this.activeStudyIndex = studyIndex this.activeStudyIndex = studyIndex
this.activeSeriesIndex = seriesIndex this.activeSeriesIndex = seriesIndex
this.activeInstanceId = null this.activeInstanceId = null
}, },
activeStudy(id) { activeStudy(id) {
console.log('activeStudy') console.log('activeStudy')
if (this.activeNames.indexOf(id) > -1) return if (this.activeNames.indexOf(id) > -1) return
this.activeNames.push(id) this.activeNames.push(id)
}, },
setSeriesActive(studyIndex, seriesIndex, isSave = false) { setSeriesActive(studyIndex, seriesIndex) {
this.activeStudyIndex = studyIndex this.activeStudyIndex = studyIndex
this.activeSeriesIndex = seriesIndex this.activeSeriesIndex = seriesIndex
const studyId = this.studyList[studyIndex].StudyId const studyId = this.studyList[studyIndex].StudyId
if (!studyId) return if (!studyId) return
this.activeStudy(studyId) this.activeStudy(studyId)
if (isSave) return false
DicomEvent.$emit('activeSeries', this.studyList[studyIndex].SeriesList[this.activeSeriesIndex]) DicomEvent.$emit('activeSeries', this.studyList[studyIndex].SeriesList[this.activeSeriesIndex])
}, },
showMultiFrames(studyIndex, series, seriesIndex, instance) { showMultiFrames(studyIndex, series, seriesIndex, instance) {
@ -483,29 +482,25 @@ export default {
<style lang="scss"> <style lang="scss">
.study-wrapper { .study-wrapper {
.instance_frame_wrapper { .instance_frame_wrapper{
min-width: 120px; min-width: 120px;
background-color: #2c2c2c; background-color: #2c2c2c;
border: 1px solid #2c2c2c; border: 1px solid #2c2c2c;
padding: 5px; padding: 5px;
} }
.frame_list{
.frame_list {
max-height: 500px; max-height: 500px;
overflow-y: auto; overflow-y: auto;
} }
.instance_frame_wrapper ::-webkit-scrollbar { .instance_frame_wrapper ::-webkit-scrollbar {
width: 7px; width: 7px;
height: 7px; height: 7px;
} }
.instance_frame_wrapper ::-webkit-scrollbar-thumb {
.instance_frame_wrapper ::-webkit-scrollbar-thumb {
border-radius: 10px; border-radius: 10px;
background: #d0d0d0; background: #d0d0d0;
} }
.frame_content{
.frame_content {
height: 50px; height: 50px;
padding: 5px; padding: 5px;
display: flex; display: flex;
@ -514,7 +509,6 @@ export default {
font-size: 12px; font-size: 12px;
border: 1px solid #404040; border: 1px solid #404040;
} }
.frame_content:hover { .frame_content:hover {
/* font-weight: bold; */ /* font-weight: bold; */
/* box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); */ /* box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); */
@ -523,10 +517,10 @@ export default {
border-color: #213a54 !important; border-color: #213a54 !important;
background-color: #213a54; background-color: #213a54;
} }
.frame_content_active { .frame_content_active {
border-color: #213a54 !important; border-color: #213a54 !important;
background-color: #213a54; background-color: #213a54;
} }
} }
</style> </style>

View File

@ -117,10 +117,6 @@ export default {
viewportIndex: { viewportIndex: {
type: Number, type: Number,
required: true required: true
},
isScrollSync: {
type: Boolean,
default: false
} }
}, },
data() { data() {
@ -195,7 +191,6 @@ export default {
this.element.oncontextmenu = (e) => e.preventDefault() this.element.oncontextmenu = (e) => e.preventDefault()
this.resizeObserver.observe(this.element) this.resizeObserver.observe(this.element)
this.element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage) this.element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
this.element.addEventListener('wheel', this.handleWheelSync)
// this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified) // this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
// this.element.addEventListener('CORNERSTONE_CAMERA_MODIFIED', this.cameraModified) // this.element.addEventListener('CORNERSTONE_CAMERA_MODIFIED', this.cameraModified)
@ -379,32 +374,6 @@ export default {
toolGroup.setToolEnabled('ScaleOverlay') toolGroup.setToolEnabled('ScaleOverlay')
} }
}, },
handleWheelSync(e) {
if (!this.isScrollSync) return
const deltaY = typeof e.deltaY === 'number' ? e.deltaY : -e.wheelDeltaY
if (!deltaY) return
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine && renderingEngine.getViewport(this.viewportId)
if (!viewport) return
const currentImageIdIndex = viewport.getCurrentImageIdIndex()
const numImages = viewport.getImageIds().length
if (numImages <= 1) return
const direction = deltaY > 0 ? 1 : -1
let type = direction
if (direction === 1 && currentImageIdIndex >= numImages - 1) {
type = 0
csUtils.jumpToSlice(viewport.element, { imageIndex: 0 })
} else if (direction === -1 && currentImageIdIndex <= 0) {
type = 99999
csUtils.jumpToSlice(viewport.element, { imageIndex: numImages - 1 })
}
this.$emit('scrollSync', { viewportIndex: this.viewportIndex, type })
},
scrollPage(type) { scrollPage(type) {
const renderingEngine = getRenderingEngine(this.renderingEngineId) const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId) const viewport = renderingEngine.getViewport(this.viewportId)
@ -414,9 +383,9 @@ export default {
if (type === 0) { if (type === 0) {
newImageIdIndex = 0 newImageIdIndex = 0
} else if (type === -1) { } else if (type === -1) {
newImageIdIndex = currentImageIdIndex === 0 ? numImages - 1 : currentImageIdIndex - 1 newImageIdIndex = currentImageIdIndex === 0 ? currentImageIdIndex : currentImageIdIndex - 1
} else if (type === 1) { } else if (type === 1) {
newImageIdIndex = currentImageIdIndex === numImages - 1 ? 0 : currentImageIdIndex + 1 newImageIdIndex = currentImageIdIndex === numImages - 1 ? currentImageIdIndex : currentImageIdIndex + 1
} else if (type === 99999) { } else if (type === 99999) {
newImageIdIndex = numImages - 1 newImageIdIndex = numImages - 1
} }

View File

@ -130,10 +130,6 @@ export default {
type: Number, type: Number,
required: true required: true
}, },
isScrollSync: {
type: Boolean,
default: false
},
histogramVisible: { histogramVisible: {
type: Boolean, type: Boolean,
default: false default: false
@ -308,7 +304,23 @@ 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('CORNERSTONE_IMAGE_RENDERED', this.imageRendered) this.element.addEventListener('CORNERSTONE_IMAGE_RENDERED', this.imageRendered)
this.element.addEventListener('wheel', this.handleWheelSync) this.element.addEventListener('wheel', (e) => {
// if (this.histogramVisible) return false
console.log('CORNERSTONE_STACK_VIEWPORT_SCROLL')
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const currentImageIdIndex = viewport.getCurrentImageIdIndex()
const totalImages = this.imageInfo.total;
//
if (currentImageIdIndex >= totalImages - 1 && e.wheelDeltaY < 0) {
//
csUtils.jumpToSlice(viewport.element, { imageIndex: 0 });
} else if (currentImageIdIndex <= 0 && e.wheelDeltaY > 0) {
//
csUtils.jumpToSlice(viewport.element, { imageIndex: totalImages - 1 });
}
});
this.element.addEventListener('CORNERSTONE_TOOLS_MOUSE_MOVE', this.cornerstoneToolsMouseMove) this.element.addEventListener('CORNERSTONE_TOOLS_MOUSE_MOVE', this.cornerstoneToolsMouseMove)
// this.element.addEventListener(cornerstoneTools.Enums.Events.MOUSE_WHEEL, this.handletoolsMouseWheel) // this.element.addEventListener(cornerstoneTools.Enums.Events.MOUSE_WHEEL, this.handletoolsMouseWheel)
this.element.addEventListener('mouseleave', () => { this.element.addEventListener('mouseleave', () => {
@ -378,30 +390,6 @@ export default {
setFilp(f = false) { setFilp(f = false) {
this.isFlip = f this.isFlip = f
}, },
handleWheelSync(e) {
const deltaY = typeof e.deltaY === 'number' ? e.deltaY : -e.wheelDeltaY
if (!deltaY) return
const renderingEngine = getRenderingEngine(this.renderingEngineId)
const viewport = renderingEngine.getViewport(this.viewportId)
const currentImageIdIndex = viewport.getCurrentImageIdIndex()
const totalImages = this.imageInfo.total
if (totalImages <= 1) return
const direction = deltaY > 0 ? 1 : -1
let type = direction
if (currentImageIdIndex >= totalImages - 1 && direction === 1) {
type = 0
csUtils.jumpToSlice(viewport.element, { imageIndex: 0 })
} else if (currentImageIdIndex <= 0 && direction === -1) {
type = 99999
csUtils.jumpToSlice(viewport.element, { imageIndex: totalImages - 1 })
}
if (this.isScrollSync) {
this.$emit('scrollSync', { viewportIndex: this.viewportIndex, type })
}
},
stackNewImage(e) { stackNewImage(e) {
if (this.isFlip) return this.isFlip = false if (this.isFlip) return this.isFlip = false
const { detail } = e const { detail } = e
@ -585,9 +573,9 @@ export default {
if (type === 0) { if (type === 0) {
newImageIdIndex = 0 newImageIdIndex = 0
} else if (type === -1) { } else if (type === -1) {
newImageIdIndex = currentImageIdIndex === 0 ? numImages - 1 : currentImageIdIndex - 1 newImageIdIndex = currentImageIdIndex === 0 ? currentImageIdIndex : currentImageIdIndex - 1
} else if (type === 1) { } else if (type === 1) {
newImageIdIndex = currentImageIdIndex === numImages - 1 ? 0 : currentImageIdIndex + 1 newImageIdIndex = currentImageIdIndex === numImages - 1 ? currentImageIdIndex : currentImageIdIndex + 1
} else if (type === 99999) { } else if (type === 99999) {
newImageIdIndex = numImages - 1 newImageIdIndex = numImages - 1
} }

View File

@ -24,7 +24,7 @@
<template v-if="rerender"> <template v-if="rerender">
<QuestionFormItem v-for="question of questions" :key="question.Id" :visit-task-id="visitTaskId" <QuestionFormItem v-for="question of questions" :key="question.Id" :visit-task-id="visitTaskId"
:isNoneDicom="isNoneDicom" :question="question" :question-form="questionForm" :isNoneDicom="isNoneDicom" :question="question" :question-form="questionForm"
:reading-task-state="readingTaskState" :criterion-id="criterionId" :calculation-list="calculationList" :reading-task-state="1" :criterion-id="criterionId" :calculation-list="calculationList"
:question-mark-info-list="questionMarkInfoList" :questions-mark-status="questionsMarkStatus" :question-mark-info-list="questionMarkInfoList" :questions-mark-status="questionsMarkStatus"
:questionsSegmentMarkStatus="questionsSegmentMarkStatus" :is-baseline="isBaseLineTask" :questionsSegmentMarkStatus="questionsSegmentMarkStatus" :is-baseline="isBaseLineTask"
@resetFormItemData="resetFormItemData" @setFormItemData="setFormItemData" @getQuestions="getQuestions" @resetFormItemData="resetFormItemData" @setFormItemData="setFormItemData" @getQuestions="getQuestions"
@ -32,7 +32,7 @@
@handleReadingChart="handleReadingChart" @saveSegmentBindingAndAnswer="saveSegmentBindingAndAnswer" /> @handleReadingChart="handleReadingChart" @saveSegmentBindingAndAnswer="saveSegmentBindingAndAnswer" />
</template> </template>
<el-form-item v-if="readingTaskState < 2"> <el-form-item>
<div class="action-bar"> <div class="action-bar">
<!-- <i class="el-icon-warning feedback-icon" @click="openFeedBackTable" <!-- <i class="el-icon-warning feedback-icon" @click="openFeedBackTable"
:style="{ color: taskInfo && taskInfo.IsExistUnprocessedFeedback ? '#ffeb3b' : '#fff' }" /> --> :style="{ color: taskInfo && taskInfo.IsExistUnprocessedFeedback ? '#ffeb3b' : '#fff' }" /> -->

View File

@ -88,21 +88,21 @@
: $t('trials:pendingReadingTasks:button:review') : $t('trials:pendingReadingTasks:button:review')
" icon="el-icon-edit-outline" @click="handleReadImage(scope.row)" /> " icon="el-icon-edit-outline" @click="handleReadImage(scope.row)" />
<!-- 上传 --> <!-- 上传 -->
<!-- <el-button v-if=" <el-button v-if="
item.ImageUploadEnum > 0 && item.ImageUploadEnum > 0 &&
item.IsReadingTaskViewInOrder > 1 && item.IsReadingTaskViewInOrder > 1 &&
!scope.row.IsSubjectJudge !scope.row.IsSubjectJudge
" v-hasPermi="['role:ir']" circle icon="el-icon-upload2" " v-hasPermi="['role:ir']" circle icon="el-icon-upload2"
:title="$t('trials:pendingReadingTasks:button:upload')" :title="$t('trials:pendingReadingTasks:button:upload')"
@click="openUploadImage(scope.row, item, 'upload')" /> --> @click="openUploadImage(scope.row, item, 'upload')" />
<!-- 下载 --> <!-- 下载 -->
<!-- <el-button v-if=" <el-button v-if="
item.ImageDownloadEnum > 0 && item.ImageDownloadEnum > 0 &&
item.IsReadingTaskViewInOrder > 1 && item.IsReadingTaskViewInOrder > 1 &&
!scope.row.IsSubjectJudge !scope.row.IsSubjectJudge
" v-hasPermi="['role:ir']" circle icon="el-icon-download" " v-hasPermi="['role:ir']" circle icon="el-icon-download"
:title="$t('trials:pendingReadingTasks:button:download')" :title="$t('trials:pendingReadingTasks:button:download')"
@click="openUploadImage(scope.row, item, 'download')" /> --> @click="openUploadImage(scope.row, item, 'download')" />
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>

View File

@ -1,35 +1,58 @@
<template> <template>
<el-form ref="subjectForm" v-loading="loading" :model="form" :rules="rules" size="small" label-width="200px"> <el-form
ref="subjectForm"
v-loading="loading"
:model="form"
:rules="rules"
size="small"
label-width="200px"
>
<div class="base-dialog-body"> <div class="base-dialog-body">
<!-- Site --> <!-- Site -->
<el-form-item :label="$t('trials:subject:table:site')" prop="TrialSiteId"> <el-form-item :label="$t('trials:subject:table:site')" prop="TrialSiteId">
<el-select v-model="form.TrialSiteId" clearable filterable style="width:100%" <el-select
:disabled="form.StudyCount > 0 || isEdit"> v-model="form.TrialSiteId"
<el-option v-for="item of siteOptions" :key="item.Id" :label="item.TrialSiteCode" :value="item.TrialSiteId" /> clearable
filterable
style="width:100%"
:disabled="form.StudyCount>0 || isEdit"
>
<el-option
v-for="item of siteOptions"
:key="item.Id"
:label="item.TrialSiteCode"
:value="item.TrialSiteId"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 受试者编号 --> <!-- 受试者编号 -->
<el-form-item :label="$t('trials:subject:table:subjectId')" prop="Code"> <el-form-item :label="$t('trials:subject:table:subjectId')" prop="Code">
<el-input v-model="form.Code" :disabled="form.StudyCount > 0 || isEdit" @input=" <el-input v-model="form.Code" :disabled="form.StudyCount > 0 || isEdit" />
form.Code = <span v-show="otherInfo.IsNoticeSubjectCodeRule" style="color:#F56C6C;font-size:12px;">{{ otherInfo.SubjectCodeRule }}</span>
form.Code.replace(/[^0-9a-zA-Z\_\-]/g, '')
" />
<span v-show="otherInfo.IsNoticeSubjectCodeRule" style="color:#F56C6C;font-size:12px;">{{
otherInfo.SubjectCodeRule }}</span>
</el-form-item> </el-form-item>
<!-- 受试者第二编号 --> <!-- 受试者第二编号 -->
<el-form-item v-if="otherInfo.IsSubjectSecondCodeView" :label="$t('trials:subject:table:medicalNo')" <el-form-item v-if="otherInfo.IsSubjectSecondCodeView" :label="$t('trials:subject:table:medicalNo')" prop="MedicalNo">
prop="MedicalNo">
<el-input v-model="form.MedicalNo" :disabled="form.StudyCount > 0 || isEdit" /> <el-input v-model="form.MedicalNo" :disabled="form.StudyCount > 0 || isEdit" />
</el-form-item> </el-form-item>
<!-- 访视基准日期 --> <!-- 访视基准日期 -->
<el-form-item v-show="otherInfo.IsHaveFirstGiveMedicineDate" <el-form-item
:label="$t('trials:subject:table:firstGiveMedicineTime')"> v-show="otherInfo.IsHaveFirstGiveMedicineDate"
<el-date-picker v-model="form.FirstGiveMedicineTime" type="date" :picker-options="pickerOption" :label="$t('trials:subject:table:firstGiveMedicineTime')"
value-format="yyyy-MM-dd" format="yyyy-MM-dd" /> >
<el-date-picker
v-model="form.FirstGiveMedicineTime"
type="date"
:picker-options="pickerOption"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
/>
</el-form-item> </el-form-item>
<!-- Age --> <!-- Age -->
<el-form-item v-if="otherInfo.IsHaveSubjectAge" :label="$t('trials:subject:table:age')" prop="Age"> <el-form-item
v-if="otherInfo.IsHaveSubjectAge"
:label="$t('trials:subject:table:age')"
prop="Age"
>
<el-input-number v-model="form.Age" controls-position="right" :min="0" /> <el-input-number v-model="form.Age" controls-position="right" :min="0" />
</el-form-item> </el-form-item>
<!-- Gender --> <!-- Gender -->
@ -50,7 +73,12 @@
<div class="base-dialog-footer" style="text-align:right;margin-top:10px;"> <div class="base-dialog-footer" style="text-align:right;margin-top:10px;">
<el-form-item> <el-form-item>
<!-- 取消 --> <!-- 取消 -->
<el-button :disabled="btnLoading" size="small" type="primary" @click="handleCancel"> <el-button
:disabled="btnLoading"
size="small"
type="primary"
@click="handleCancel"
>
{{ $t('common:button:cancel') }} {{ $t('common:button:cancel') }}
</el-button> </el-button>
<!-- 保存 --> <!-- 保存 -->

View File

@ -0,0 +1,142 @@
<template>
<div class="json-editor" v-loading="loading">
<div class="header">
<!-- <span class="title">JSON 编辑</span> -->
<el-button type="primary" size="mini" icon="el-icon-check" @click="save">
{{ $t('common:button:save') }}
</el-button>
</div>
<div class="json">
<json-node
:node-key="'root'"
:node-value="jsonData"
:is-root="true"
@update="handleUpdate"
/>
</div>
</div>
</template>
<script>
import { getInspectionById, setJsonDetail } from '@/api/trials'
import JsonNode from './JsonNode.vue'
export default {
name: 'JsonEditor',
components: { JsonNode },
props: {
id: {
type: String,
required: true
}
},
data() {
return {
loading: false,
jsonData: {}
}
},
mounted() {
this.getJsonData()
},
methods: {
handleUpdate({ path, value }) {
const target = this.getTarget(path.slice(0, -1))
this.$set(target, path[path.length - 1], value)
},
getTarget(path) {
let t = this.jsonData
path.forEach(k => { t = t[k] })
return t
},
parseValue(val) {
if (typeof val === 'string') {
try {
const parsed = JSON.parse(val)
if (parsed && typeof parsed === 'object') {
return JSON.parse(JSON.stringify(parsed))
}
} catch (e) {
console.warn(e.message)
}
return {}
}
return val ? JSON.parse(JSON.stringify(val)) : {}
},
async getJsonData() {
try {
this.loading = true
const res = await getInspectionById({ id: this.id })
if (res.IsSuccess) {
this.jsonData = this.parseValue(res.Result.JsonDetail)
}
} catch (err) {
console.log(err)
} finally {
this.loading = false
}
},
isValidJsonObject(obj) {
if (obj === null || typeof obj !== 'object') return false
try {
JSON.stringify(obj)
return true
} catch (e) {
console.warn(e.message)
return false
}
},
safeClone(obj) {
if (this.isValidJsonObject(obj)) {
return JSON.parse(JSON.stringify(obj))
}
return {}
},
async save() {
try {
this.loading = true
const result = this.safeClone(this.jsonData)
const res = await setJsonDetail({ id: this.id, jsonDetail: JSON.stringify(result) })
if (res.IsSuccess) {
this.$emit('getList')
this.$emit('close')
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
} catch (err) {
console.log(err)
} finally {
this.loading = false
}
}
}
}
</script>
<style scoped>
.json-editor {
font-family: Consolas, Monaco, monospace;
font-size: 13px;
line-height: 2;
padding: 12px;
background: #fafafa;
border-radius: 4px;
}
.header {
display: flex;
justify-content: flex-end;
align-items: center;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid #ebeef5;
}
.title {
font-weight: 600;
font-size: 14px;
color: #303133;
}
.json {
max-height: 50vh;
overflow: auto;
}
</style>

View File

@ -0,0 +1,136 @@
<template>
<div class="node" :style="{ paddingLeft: depth * 20 + 'px' }">
<span v-if="!isRoot" class="key">
{{ isArray ? `[${nodeKey}]` : `"${nodeKey}"` }}:
</span>
<!-- 对象 -->
<template v-if="isObject">
<span class="bracket">{</span>
<div class="children">
<json-node
v-for="(v, k) in nodeValue"
:key="k"
:node-key="k"
:node-value="v"
:depth="depth + 1"
:parent-path="currentPath"
@update="$emit('update', $event)"
/>
</div>
<span class="bracket">}</span>
</template>
<!-- 数组 -->
<template v-else-if="isArray">
<span class="bracket">[</span>
<div class="children">
<json-node
v-for="(item, i) in nodeValue"
:key="i"
:node-key="i"
:node-value="item"
:depth="depth + 1"
:parent-path="currentPath"
@update="$emit('update', $event)"
/>
</div>
<span class="bracket">]</span>
</template>
<!-- 文本 -->
<el-input
v-else-if="valueType === 'string'"
v-model="editVal"
size="mini"
style="width: 300px"
@blur="emitUpdate"
@keyup.enter.native="emitUpdate"
/>
<!-- 数字 -->
<el-input-number
v-else-if="valueType === 'number'"
v-model="editVal"
size="mini"
style="width: 140px"
@blur="emitUpdate"
/>
<!-- 布尔值 -->
<el-switch
v-else-if="valueType === 'boolean'"
v-model="editVal"
size="small"
@change="emitUpdate"
/>
<!-- null -->
<el-tag v-else size="mini" type="info">null</el-tag>
</div>
</template>
<script>
export default {
name: 'JsonNode',
props: {
nodeKey: [String, Number],
nodeValue: [Object, Array, String, Number, Boolean],
depth: {
type: Number,
default: 0
},
isRoot: {
type: Boolean,
default: false
},
parentPath: {
type: Array,
default: () => []
}
},
data() {
return { editVal: this.nodeValue }
},
computed: {
isObject() {
return this.nodeValue && typeof this.nodeValue === 'object' && !Array.isArray(this.nodeValue)
},
isArray() {
return Array.isArray(this.nodeValue)
},
valueType() {
if (this.nodeValue === null) return 'null'
return typeof this.nodeValue
},
currentPath() {
return this.isRoot ? [] : [...this.parentPath, this.nodeKey]
}
},
watch: {
nodeValue(v) { this.editVal = v }
},
methods: {
emitUpdate() {
this.$emit('update', { path: this.currentPath, value: this.editVal })
}
}
}
</script>
<style scoped>
.node {
padding-bottom: 5px;
}
.key {
color: #c7254e;
margin-right: 4px;
}
.bracket {
color: #e6a23c;
font-weight: bold;
}
.children {
padding-left: 4px;
}
</style>

View File

@ -194,6 +194,9 @@
<el-button type="text" @click="lookDetails(scope.row)"> <el-button type="text" @click="lookDetails(scope.row)">
{{ $t('trials:auditRecord:action:detail') }} {{ $t('trials:auditRecord:action:detail') }}
</el-button> </el-button>
<el-button type="text" @click="edit(scope.row)">
{{ $t('common:button:edit') }}
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -622,6 +625,20 @@
<!-- :src="openImageUrl"--> <!-- :src="openImageUrl"-->
<!-- style="width: 50px;height: 50px; cursor:pointer">--> <!-- style="width: 50px;height: 50px; cursor:pointer">-->
<!-- </div>--> <!-- </div>-->
<!-- <json-editor v-model="data" /> -->
<el-dialog
v-if="editDialogVisible"
:visible.sync="editDialogVisible"
:close-on-click-modal="false"
:title="$t('common:button:edit') + `${$i18n.locale === 'zh' ? '' + editRow.DescriptionCN + '' : '( ' + editRow.Description + ' )'}`"
width="720px"
custom-class="base-dialog-wrapper">
<json-editor
:id="editRow.Id"
@close="editDialogVisible = false"
@getList="getList"
/>
</el-dialog>
</template> </template>
</BaseContainer> </BaseContainer>
</template> </template>
@ -630,11 +647,12 @@
import { import {
getTrialSiteSelect, getTrialSiteSelect,
getTrialVisitStageSelect, getTrialVisitStageSelect,
getTrialCriterionList getTrialCriterionList,
} from '@/api/trials' } from '@/api/trials'
import { getInspectionList, getInspectionJsonDataList } from '@/api/trials/inspection' import { getInspectionList, getInspectionJsonDataList } from '@/api/trials/inspection'
import { getFrontAuditConfigList, getAuditConfigChildList, getModuleTypeDescriptionList, setInspectionEnumValue, getModuleTypeList } from '@/api/dictionary/checkConfig' import { getFrontAuditConfigList, getAuditConfigChildList, getModuleTypeDescriptionList, setInspectionEnumValue, getModuleTypeList } from '@/api/dictionary/checkConfig'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import JsonEditor from './components/JsonEditor'
import BaseContainer from '@/components/BaseContainer' import BaseContainer from '@/components/BaseContainer'
import BaseModel from '@/components/BaseModel' import BaseModel from '@/components/BaseModel'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
@ -670,7 +688,7 @@ const searchDataDefault = () => {
} }
} }
export default { export default {
components: { BaseContainer, Pagination, BaseModel }, components: { BaseContainer, Pagination, JsonEditor, BaseModel },
dicts: ['OptType', 'ModuleType', 'ChildrenType'], dicts: ['OptType', 'ModuleType', 'ChildrenType'],
data() { data() {
@ -708,7 +726,10 @@ export default {
imagesList: [], imagesList: [],
moduleTypeList: [], moduleTypeList: [],
list2_total: 0, list2_total: 0,
list2_searchData: {} list2_searchData: {},
editDialogVisible: false,
jsonData: null,
editRow: null
} }
}, },
mounted() { mounted() {
@ -1346,7 +1367,12 @@ export default {
}).catch(() => { }).catch(() => {
this.loading = false this.loading = false
}) })
} },
edit(row) {
this.editRow = Object.assign({}, row)
this.editDialogVisible = true
},
} }
} }
</script> </script>

View File

@ -1144,7 +1144,7 @@ export default {
var instanceItem = instanceList.find(function (item) { var instanceItem = instanceList.find(function (item) {
return item.instanceUid === instanceUid return item.instanceUid === instanceUid
}) })
if (!instanceItem) { if (!false) {
var date = data.string('x00080023') var date = data.string('x00080023')
var time = data.string('x00080033') var time = data.string('x00080033')
var instanceTime = '' var instanceTime = ''
@ -1572,58 +1572,60 @@ export default {
try { try {
let o = v.instanceList[ii] let o = v.instanceList[ii]
let name = `${v.instanceList[ii].file.webkitRelativePath}_${v.instanceList[ii].instanceUid}` let name = `${v.instanceList[ii].file.webkitRelativePath}_${v.instanceList[ii].instanceUid}`
if (o.isReUpload) { // if (o.isReUpload) {
dicomInfo.failedFileCount++ // dicomInfo.failedFileCount++
dicomInfo.uploadFileSize += o.file.size // dicomInfo.uploadFileSize += o.file.size
Record.Existed.push(name) // Record.Existed.push(name)
Record.FileCount++ // Record.FileCount++
} else if (o.myPath) { // }
instanceList.push({ // else if (o.myPath) {
studyInstanceUid: dicomInfo.studyUid, // instanceList.push({
seriesInstanceUid: v.seriesUid, // studyInstanceUid: dicomInfo.studyUid,
SOPClassUID: o.SOPClassUID, // seriesInstanceUid: v.seriesUid,
TransferSytaxUID: o.TransferSytaxUID, // SOPClassUID: o.SOPClassUID,
MediaStorageSOPInstanceUID: // TransferSytaxUID: o.TransferSytaxUID,
o.MediaStorageSOPInstanceUID, // MediaStorageSOPInstanceUID:
MediaStorageSOPClassUID: // o.MediaStorageSOPInstanceUID,
o.MediaStorageSOPClassUID, // MediaStorageSOPClassUID:
sopInstanceUid: o.instanceUid, // o.MediaStorageSOPClassUID,
instanceNumber: o.instanceNumber, // sopInstanceUid: o.instanceUid,
instanceTime: o.instanceTime, // instanceNumber: o.instanceNumber,
imageRows: o.imageRows, // instanceTime: o.instanceTime,
imageColumns: o.imageColumns, // imageRows: o.imageRows,
sliceLocation: o.sliceLocation, // imageColumns: o.imageColumns,
sliceThickness: o.sliceThickness, // sliceLocation: o.sliceLocation,
numberOfFrames: o.numberOfFrames, // sliceThickness: o.sliceThickness,
pixelSpacing: o.pixelSpacing, // numberOfFrames: o.numberOfFrames,
imagerPixelSpacing: o.imagerPixelSpacing, // pixelSpacing: o.pixelSpacing,
frameOfReferenceUID: o.frameOfReferenceUID, // imagerPixelSpacing: o.imagerPixelSpacing,
windowCenter: o.windowCenter, // frameOfReferenceUID: o.frameOfReferenceUID,
windowWidth: o.windowWidth, // windowCenter: o.windowCenter,
path: o.myPath, // windowWidth: o.windowWidth,
FileSize: o.FileSize, // path: o.myPath,
// FileSize: o.FileSize,
PhotometricInterpretation: // PhotometricInterpretation:
o.PhotometricInterpretation, // o.PhotometricInterpretation,
BitsAllocated: o.BitsAllocated, // BitsAllocated: o.BitsAllocated,
PixelRepresentation: o.PixelRepresentation, // PixelRepresentation: o.PixelRepresentation,
RescaleIntercept: o.RescaleIntercept, // RescaleIntercept: o.RescaleIntercept,
RescaleSlope: o.RescaleSlope, // RescaleSlope: o.RescaleSlope,
ImagePositionPatient: o.ImagePositionPatient, // ImagePositionPatient: o.ImagePositionPatient,
ImageOrientationPatient: // ImageOrientationPatient:
o.ImageOrientationPatient, // o.ImageOrientationPatient,
SequenceOfUltrasoundRegions: // SequenceOfUltrasoundRegions:
o.SequenceOfUltrasoundRegions, // o.SequenceOfUltrasoundRegions,
FrameTime: o.FrameTime, // FrameTime: o.FrameTime,
CorrectedImage: o.CorrectedImage, // CorrectedImage: o.CorrectedImage,
Units: o.Units, // Units: o.Units,
DecayCorrection: o.DecayCorrection, // DecayCorrection: o.DecayCorrection,
EncapsulatedDocument: o.EncapsulatedDocument, // EncapsulatedDocument: o.EncapsulatedDocument,
}) // })
Record.Uploaded.push(name) // Record.Uploaded.push(name)
dicomInfo.failedFileCount++ // dicomInfo.failedFileCount++
Record.FileCount++ // Record.FileCount++
} else { // }
// else {
let path = `/${params.trialId}/Image/${params.subjectId let path = `/${params.trialId}/Image/${params.subjectId
}/${params.subjectVisitId}/${dicomInfo.studyUid }/${params.subjectVisitId}/${dicomInfo.studyUid
}/${scope.getGuid( }/${scope.getGuid(
@ -1761,7 +1763,7 @@ export default {
Record.Failed.push(name) Record.Failed.push(name)
Record.FileCount++ Record.FileCount++
} }
} // }
resolve1() resolve1()
} catch (e) { } catch (e) {
console.log(e) console.log(e)

View File

@ -300,19 +300,7 @@
<!-- 审核完成时间 --> <!-- 审核完成时间 -->
<el-table-column prop="AuditTime" :label="$t('trials:crcUpload:table:auditTime')" show-overflow-tooltip <el-table-column prop="AuditTime" :label="$t('trials:crcUpload:table:auditTime')" show-overflow-tooltip
width="170" /> width="170" />
<el-table-column v-if=" <el-table-column :label="$t('common:action:action')" width="250" fixed="right">
hasPermi(
[
'trials:trials-panel:visit:crc-upload:upload',
'trials:trials-panel:visit:crc-upload:submit',
'trials:trials-panel:visit:crc-upload:edit',
'trials:trials-panel:visit:crc-upload:delete',
'trials:trials-panel:visit:crc-upload:back',
'trials:trials-panel:visit:crc-upload:authBack'
],
'||'
)
" :label="$t('common:action:action')" width="250" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 上传 --> <!-- 上传 -->
<el-button v-hasPermi="['trials:trials-panel:visit:crc-upload:upload']" icon="el-icon-upload2" :disabled="!isOCTorIVUS && (scope.row.SubmitState * 1 === 2 || <el-button v-hasPermi="['trials:trials-panel:visit:crc-upload:upload']" icon="el-icon-upload2" :disabled="!isOCTorIVUS && (scope.row.SubmitState * 1 === 2 ||
@ -320,10 +308,8 @@
scope.row.IsLostVisit || (scope.row.IsSubjectQuit && scope.row.SubmitState * 1 !== 2)) scope.row.IsLostVisit || (scope.row.IsSubjectQuit && scope.row.SubmitState * 1 !== 2))
" circle :title="$t('trials:crcUpload:action:upload')" @click="CRChandleUpload(scope.row)" /> " circle :title="$t('trials:crcUpload:action:upload')" @click="CRChandleUpload(scope.row)" />
<!-- 上传2 --> <!-- 上传2 -->
<el-button icon="el-icon-upload2" v-hasPermi="['trials:trials-panel:visit:crc-upload:upload2']" :disabled="!isOCTorIVUS && (scope.row.SubmitState * 1 === 2 || <el-button icon="el-icon-upload2"
scope.row.VisitExecuted === 2 || circle :title="$t('trials:crcUpload:action:upload')" @click="CRChandleUpload2(scope.row)" />
scope.row.IsLostVisit || (scope.row.IsSubjectQuit && scope.row.SubmitState * 1 !== 2))
" circle :title="$t('trials:crcUpload:action:upload')" @click="CRChandleUpload2(scope.row)" />
<!-- 提交 --> <!-- 提交 -->
<el-button v-hasPermi="['trials:trials-panel:visit:crc-upload:submit']" icon="el-icon-check" :disabled="scope.row.AuditState * 1 > 0 || <el-button v-hasPermi="['trials:trials-panel:visit:crc-upload:submit']" icon="el-icon-check" :disabled="scope.row.AuditState * 1 > 0 ||
scope.row.SubmitState * 1 !== 1 || scope.row.SubmitState * 1 !== 1 ||

View File

@ -644,7 +644,7 @@
<el-input v-model="studyForm.Modalities" disabled /> <el-input v-model="studyForm.Modalities" disabled />
</el-form-item> </el-form-item>
<!-- 检查类型 --> <!-- 检查类型 -->
<el-form-item v-else :label="$t('trials:audit:table:modality')" prop="Modality" :rules="[ <el-form-item v-else :label="$t('trials:audit:table:modality')" prop="Modalities" :rules="[
{ {
required: true, required: true,
message: $t('common:ruleMessage:specify'), message: $t('common:ruleMessage:specify'),