Merge branch 'main' of http://192.168.3.68:2000/XCKJ/irc_web
continuous-integration/drone/push Build is running Details

uat_us
he 2024-09-11 17:00:56 +08:00
commit b8478e6451
89 changed files with 16218 additions and 3412 deletions

View File

@ -27,6 +27,7 @@
"axios": "0.18.1", "axios": "0.18.1",
"babel-eslint": "7.2.3", "babel-eslint": "7.2.3",
"copy-webpack-plugin": "^4.5.2", "copy-webpack-plugin": "^4.5.2",
"@aws-sdk/client-s3": "^3.370.0",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"cornerstone-core": "^2.6.1", "cornerstone-core": "^2.6.1",
"cornerstone-math": "^0.1.10", "cornerstone-math": "^0.1.10",

167
public/mitm.html Normal file
View File

@ -0,0 +1,167 @@
<!--
mitm.html is the lite "man in the middle"
This is only meant to signal the opener's messageChannel to
the service worker - when that is done this mitm can be closed
but it's better to keep it alive since this also stops the sw
from restarting
The service worker is capable of intercepting all request and fork their
own "fake" response - wish we are going to craft
when the worker then receives a stream then the worker will tell the opener
to open up a link that will start the download
-->
<script>
// This will prevent the sw from restarting
let keepAlive = () => {
keepAlive = () => {}
var ping = location.href.substr(0, location.href.lastIndexOf('/')) + '/ping'
var interval = setInterval(() => {
if (sw) {
sw.postMessage('ping')
} else {
fetch(ping).then(res => res.text(!res.ok && clearInterval(interval)))
}
}, 10000)
}
// message event is the first thing we need to setup a listner for
// don't want the opener to do a random timeout - instead they can listen for
// the ready event
// but since we need to wait for the Service Worker registration, we store the
// message for later
let messages = []
window.onmessage = evt => messages.push(evt)
let sw = null
let scope = ''
function registerWorker() {
return navigator.serviceWorker.getRegistration('./').then(swReg => {
return swReg || navigator.serviceWorker.register('sw.js', { scope: './' })
}).then(swReg => {
const swRegTmp = swReg.installing || swReg.waiting
scope = swReg.scope
return (sw = swReg.active) || new Promise(resolve => {
swRegTmp.addEventListener('statechange', fn = () => {
if (swRegTmp.state === 'activated') {
swRegTmp.removeEventListener('statechange', fn)
sw = swReg.active
resolve()
}
})
})
})
}
// Now that we have the Service Worker registered we can process messages
function onMessage (event) {
let { data, ports, origin } = event
// It's important to have a messageChannel, don't want to interfere
// with other simultaneous downloads
if (!ports || !ports.length) {
throw new TypeError("[StreamSaver] You didn't send a messageChannel")
}
if (typeof data !== 'object') {
throw new TypeError("[StreamSaver] You didn't send a object")
}
// the default public service worker for StreamSaver is shared among others.
// so all download links needs to be prefixed to avoid any other conflict
data.origin = origin
// if we ever (in some feature versoin of streamsaver) would like to
// redirect back to the page of who initiated a http request
data.referrer = data.referrer || document.referrer || origin
// pass along version for possible backwards compatibility in sw.js
data.streamSaverVersion = new URLSearchParams(location.search).get('version')
if (data.streamSaverVersion === '1.2.0') {
console.warn('[StreamSaver] please update streamsaver')
}
/** @since v2.0.0 */
if (!data.headers) {
console.warn("[StreamSaver] pass `data.headers` that you would like to pass along to the service worker\nit should be a 2D array or a key/val object that fetch's Headers api accepts")
} else {
// test if it's correct
// should thorw a typeError if not
new Headers(data.headers)
}
/** @since v2.0.0 */
if (typeof data.filename === 'string') {
console.warn("[StreamSaver] You shouldn't send `data.filename` anymore. It should be included in the Content-Disposition header option")
// Do what File constructor do with fileNames
data.filename = data.filename.replace(/\//g, ':')
}
/** @since v2.0.0 */
if (data.size) {
console.warn("[StreamSaver] You shouldn't send `data.size` anymore. It should be included in the content-length header option")
}
/** @since v2.0.0 */
if (data.readableStream) {
console.warn("[StreamSaver] You should send the readableStream in the messageChannel, not throught mitm")
}
/** @since v2.0.0 */
if (!data.pathname) {
console.warn("[StreamSaver] Please send `data.pathname` (eg: /pictures/summer.jpg)")
data.pathname = Math.random().toString().slice(-6) + '/' + data.filename
}
// remove all leading slashes
data.pathname = data.pathname.replace(/^\/+/g, '')
// remove protocol
let org = origin.replace(/(^\w+:|^)\/\//, '')
// set the absolute pathname to the download url.
data.url = new URL(`${scope + org}/${data.pathname}`).toString()
if (!data.url.startsWith(`${scope + org}/`)) {
throw new TypeError('[StreamSaver] bad `data.pathname`')
}
// This sends the message data as well as transferring
// messageChannel.port2 to the service worker. The service worker can
// then use the transferred port to reply via postMessage(), which
// will in turn trigger the onmessage handler on messageChannel.port1.
const transferable = data.readableStream
? [ ports[0], data.readableStream ]
: [ ports[0] ]
if (!(data.readableStream || data.transferringReadable)) {
keepAlive()
}
return sw.postMessage(data, transferable)
}
if (window.opener) {
// The opener can't listen to onload event, so we need to help em out!
// (telling them that we are ready to accept postMessage's)
window.opener.postMessage('StreamSaver::loadedPopup', '*')
}
if (navigator.serviceWorker) {
registerWorker().then(() => {
window.onmessage = onMessage
messages.forEach(window.onmessage)
})
}
// FF v102 just started to supports transferable streams, but still needs to ping sw.js
// even tough the service worker dose not have to do any kind of work and listen to any
// messages... #305
keepAlive()
</script>

130
public/sw.js Normal file
View File

@ -0,0 +1,130 @@
/* global self ReadableStream Response */
self.addEventListener('install', () => {
self.skipWaiting()
})
self.addEventListener('activate', event => {
event.waitUntil(self.clients.claim())
})
const map = new Map()
// This should be called once per download
// Each event has a dataChannel that the data will be piped through
self.onmessage = event => {
// We send a heartbeat every x second to keep the
// service worker alive if a transferable stream is not sent
if (event.data === 'ping') {
return
}
const data = event.data
const downloadUrl = data.url || self.registration.scope + Math.random() + '/' + (typeof data === 'string' ? data : data.filename)
const port = event.ports[0]
const metadata = new Array(3) // [stream, data, port]
metadata[1] = data
metadata[2] = port
// Note to self:
// old streamsaver v1.2.0 might still use `readableStream`...
// but v2.0.0 will always transfer the stream through MessageChannel #94
if (event.data.readableStream) {
metadata[0] = event.data.readableStream
} else if (event.data.transferringReadable) {
port.onmessage = evt => {
port.onmessage = null
metadata[0] = evt.data.readableStream
}
} else {
metadata[0] = createStream(port)
}
map.set(downloadUrl, metadata)
port.postMessage({ download: downloadUrl })
}
function createStream (port) {
// ReadableStream is only supported by chrome 52
return new ReadableStream({
start (controller) {
// When we receive data on the messageChannel, we write
port.onmessage = ({ data }) => {
if (data === 'end') {
return controller.close()
}
if (data === 'abort') {
controller.error('Aborted the download')
return
}
controller.enqueue(data)
}
},
cancel (reason) {
console.log('user aborted', reason)
port.postMessage({ abort: true })
}
})
}
self.onfetch = event => {
const url = event.request.url
// this only works for Firefox
if (url.endsWith('/ping')) {
return event.respondWith(new Response('pong'))
}
const hijacke = map.get(url)
if (!hijacke) return null
const [ stream, data, port ] = hijacke
map.delete(url)
// Not comfortable letting any user control all headers
// so we only copy over the length & disposition
const responseHeaders = new Headers({
'Content-Type': 'application/octet-stream; charset=utf-8',
// To be on the safe side, The link can be opened in a iframe.
// but octet-stream should stop it.
'Content-Security-Policy': "default-src 'none'",
'X-Content-Security-Policy': "default-src 'none'",
'X-WebKit-CSP': "default-src 'none'",
'X-XSS-Protection': '1; mode=block',
'Cross-Origin-Embedder-Policy': 'require-corp'
})
let headers = new Headers(data.headers || {})
if (headers.has('Content-Length')) {
responseHeaders.set('Content-Length', headers.get('Content-Length'))
}
if (headers.has('Content-Disposition')) {
responseHeaders.set('Content-Disposition', headers.get('Content-Disposition'))
}
// data, data.filename and size should not be used anymore
if (data.size) {
console.warn('Depricated')
responseHeaders.set('Content-Length', data.size)
}
let fileName = typeof data === 'string' ? data : data.filename
if (fileName) {
console.warn('Depricated')
// Make filename RFC5987 compatible
fileName = encodeURIComponent(fileName).replace(/['()]/g, escape).replace(/\*/g, '%2A')
responseHeaders.set('Content-Disposition', "attachment; filename*=UTF-8''" + fileName)
}
event.respondWith(new Response(stream, { headers: responseHeaders }))
port.postMessage({ debug: 'Download started' })
}

View File

@ -8,11 +8,11 @@ export function requestPackageAndAnonymizImage(params) {
}) })
} }
// 获取影像上传列表 // 获取影像上传列表
export function getSubjectImageUploadList(params) { export function getSubjectImageUploadList(data) {
return request({ return request({
url: '/DownloadAndUpload/getSubjectImageUploadList', url: '/DownloadAndUpload/getSubjectImageUploadList',
method: 'get', method: 'post',
params data
}) })
} }
// 预上传 // 预上传
@ -40,3 +40,43 @@ export function deleteTaskStudy(params) {
params params
}) })
} }
// 获取iqc下载文件信息
export function getCRCUploadedStudyInfo(data) {
return request({
url: '/DownloadAndUpload/getCRCUploadedStudyInfo',
method: 'post',
data
})
}
// 获取ir阅片和任务列表
export function getSubjectImageDownloadSelectList(data) {
return request({
url: '/DownloadAndUpload/getSubjectImageDownloadSelectList',
method: 'post',
data
})
}
// 获取ir阅片和任务下载文件信息
export function getIRReadingDownloadStudyInfo(data) {
return request({
url: '/DownloadAndUpload/getIRReadingDownloadStudyInfo',
method: 'post',
data
})
}
// 获取ir阅片和任务非dicom上传列表
export function getIRUploadTaskNoneDicomStudyList(data) {
return request({
url: '/DownloadAndUpload/getIRUploadTaskNoneDicomStudyList',
method: 'post',
data
})
}
// 校验上传影像
export function verifyIRStudyAllowUpload(data) {
return request({
url: '/DownloadAndUpload/verifyIRStudyAllowUpload',
method: 'post',
data
})
}

View File

@ -194,3 +194,10 @@ export function resetReadingTask(param) {
data: param data: param
}) })
} }
export function getTaskUploadedDicomStudyList(param) {
return request({
url: `/DownloadAndUpload/getTaskUploadedDicomStudyList`,
method: 'post',
data: param
})
}

View File

@ -1364,9 +1364,9 @@ export function getForwardList(param) {
}) })
} }
export function getNoneDicomStudyList(subjectVisitId, sudyId = '', isFilterZip = false) { export function getNoneDicomStudyList(subjectVisitId, sudyId = '', isFilterZip = false, visitTaskId = '') {
return request({ return request({
url: `/NoneDicomStudy/getNoneDicomStudyList?subjectVisitId=${subjectVisitId}&nonedicomStudyId=${sudyId}&isFilterZip=${isFilterZip}`, url: `/NoneDicomStudy/getNoneDicomStudyList?subjectVisitId=${subjectVisitId}&nonedicomStudyId=${sudyId}&isFilterZip=${isFilterZip}&visitTaskId=${visitTaskId}`,
method: 'get' method: 'get'
}) })
} }

View File

@ -81,16 +81,25 @@
<!-- <div v-show="stack.firstImageLoading" class="load-indicator"> <!-- <div v-show="stack.firstImageLoading" class="load-indicator">
Loading Series #{{ stack.seriesNumber }}... Loading Series #{{ stack.seriesNumber }}...
</div>--> </div>-->
<el-dialog
v-if="dcmTag.visible"
:visible.sync="dcmTag.visible"
:close-on-click-modal="false"
:title="dcmTag.title"
width="1000px"
custom-class="base-dialog-wrapper"
append-to-body
>
<DicomTags :image-id="stack.imageIds[stack.currentImageIdIndex]" @close="dcmTag.visible = false" />
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import Vue from 'vue'
import Contextmenu from 'vue-contextmenujs'
Vue.use(Contextmenu)
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'
const scroll = cornerstoneTools.import('util/scrollToIndex') const scroll = cornerstoneTools.import('util/scrollToIndex')
import Hammer from 'hammerjs' import Hammer from 'hammerjs'
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString' import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
@ -108,8 +117,10 @@ cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)')
// cornerstoneTools.init({ showSVGCursors: true }) // cornerstoneTools.init({ showSVGCursors: true })
cornerstoneTools.init() cornerstoneTools.init()
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
import DicomTags from './DicomTags'
export default { export default {
name: 'DicomCanvas', name: 'DicomCanvas',
components: { DicomTags },
data() { data() {
return { return {
loading: false, loading: false,
@ -164,7 +175,8 @@ export default {
mousePosition: { x: '', y: '', mo: '' }, mousePosition: { x: '', y: '', mo: '' },
markers: { top: '', right: '', bottom: '', left: '' }, markers: { top: '', right: '', bottom: '', left: '' },
orientationMarkers: [], orientationMarkers: [],
originalMarkers: [] originalMarkers: [],
dcmTag: { visible: false, title: this.$t('trials:dicom-tag:title') }
} }
}, },
@ -364,8 +376,8 @@ export default {
if (this.dicomInfo.thick) { if (this.dicomInfo.thick) {
this.dicomInfo.thick = this.dicomInfo.thick.toFixed(2) this.dicomInfo.thick = this.dicomInfo.thick.toFixed(2)
} }
let newImageIdIndex = this.stack.imageIds.findIndex(i=>i===e.detail.image.imageId) const newImageIdIndex = this.stack.imageIds.findIndex(i => i === e.detail.image.imageId)
if(newImageIdIndex === -1) return if (newImageIdIndex === -1) return
this.stack.currentImageIdIndex = newImageIdIndex this.stack.currentImageIdIndex = newImageIdIndex
this.stack.imageIdIndex = newImageIdIndex this.stack.imageIdIndex = newImageIdIndex
this.series.imageIdIndex = newImageIdIndex this.series.imageIdIndex = newImageIdIndex
@ -636,7 +648,7 @@ export default {
enabledElement.renderingTools.renderCanvasData = renderCanvasData enabledElement.renderingTools.renderCanvasData = renderCanvasData
}, },
scrollPage(offset) { scrollPage(offset) {
if(this.loading) return if (this.loading) return
var index = this.stack.currentImageIdIndex + offset var index = this.stack.currentImageIdIndex + offset
if (index < 0) index = 0 if (index < 0) index = 0
else if (index >= this.stack.imageIds.length) { else if (index >= this.stack.imageIds.length) {
@ -648,7 +660,7 @@ export default {
}, },
toggleClipPlay() { toggleClipPlay() {
if(this.loading) return if (this.loading) return
if (this.toolState.clipPlaying) { if (this.toolState.clipPlaying) {
cornerstoneTools.stopClip(this.canvas) cornerstoneTools.stopClip(this.canvas)
this.toolState.clipPlaying = false this.toolState.clipPlaying = false
@ -668,7 +680,7 @@ export default {
resetWwwc() { resetWwwc() {
this.toolState.viewportInvert = false this.toolState.viewportInvert = false
var viewport = cornerstone.getViewport(this.canvas) var viewport = cornerstone.getViewport(this.canvas)
viewport.invert = false // viewport.invert = false
var image = cornerstone.getImage(this.canvas) var image = cornerstone.getImage(this.canvas)
viewport.voi.windowWidth = image.windowWidth viewport.voi.windowWidth = image.windowWidth
viewport.voi.windowCenter = image.windowCenter viewport.voi.windowCenter = image.windowCenter
@ -747,6 +759,9 @@ export default {
var uid = cornerstone.getImage(this.canvas).data.string('x00080018') var uid = cornerstone.getImage(this.canvas).data.string('x00080018')
cornerstoneTools.SaveAs(this.canvas, `${uid}.png`) cornerstoneTools.SaveAs(this.canvas, `${uid}.png`)
}, },
showTags() {
this.dcmTag.visible = true
},
fitToWindow() { fitToWindow() {
if (this.stack.seriesNumber) { if (this.stack.seriesNumber) {
cornerstone.fitToWindow(this.canvas) cornerstone.fitToWindow(this.canvas)

View File

@ -0,0 +1,287 @@
<template>
<div class="dcm-tag">
<el-input
v-model="search"
size="mini"
:placeholder="$t('trials:dicom-tag:keywords')"
style="width:200px"
/>
<el-table
:data="filterList(list)"
row-key="id"
default-expand-all
:tree-props="{children: 'child', hasChildren: 'hasChildren'}"
:default-sort="{prop: 'tagCode', order: 'ascending'}"
height="500"
>
<el-table-column
prop="tagCode"
label="Tag"
min-width="120"
sortable
/>
<el-table-column
prop="tagName"
label="Description"
min-width="150"
show-overflow-tooltip
sortable
/>
<el-table-column
prop="vr"
label="VR"
min-width="50"
show-overflow-tooltip
sortable
/>
<el-table-column
prop="tagLength"
label="Length"
min-width="80"
show-overflow-tooltip
sortable
/>
<el-table-column
prop="value"
label="Value"
min-width="200"
show-overflow-tooltip
sortable
/>
</el-table>
</div>
</template>
<script>
import TAG_DICT from './dataDictionary'
import * as cornerstone from 'cornerstone-core'
import dicomParser from 'dicom-parser'
export default {
name: 'DicomTags',
props: {
imageId: {
type: String,
required: true
}
},
data() {
return {
list: [],
idx: 0,
search: ''
}
},
async mounted() {
const image = await cornerstone.loadAndCacheImage(this.imageId)
var dataSet = dicomParser.parseDicom(image.data.byteArray)
var output = []
this.dumpDataSet(dataSet, output)
this.list = output
},
methods: {
filterList(list) {
if (list.length === 0) return []
if (!this.search) {
return list
} else {
const search = isNaN(parseFloat(this.search)) ? this.search.toLowerCase() : String(this.search)
const arr = list.filter(data => {
if (data.tagCode && data.tagCode.toLowerCase().includes(search)) {
return data
} else if (data.tagName && data.tagName.toLowerCase().includes(search)) {
return data
} else if (data.value) {
let v = ''
if (!isNaN(parseFloat(data.value))) {
v = String(data.value)
} else {
v = data.value.toLowerCase()
}
if (v.includes(search)) {
return data
}
}
})
return arr
}
},
dumpDataSet(dataSet, output) {
try {
for (const propertyName in dataSet.elements) {
const elementObject = {}
const element = dataSet.elements[propertyName]
const tag = this.getTag(element.tag)
elementObject.id = `${this.idx++}${new Date().getTime()}`
if (!tag) {
const group = element.tag.substring(1, 5)
const el = element.tag.substring(5, 9)
elementObject.tagCode = ('(' + group + ',' + el + ')').toUpperCase()
} else {
elementObject.tagCode = tag ? tag.tag : ''
elementObject.tagName = tag ? tag.name : ''
}
elementObject.tagLength = element.length
elementObject.value = ''
elementObject.child = []
if (element.items) {
element.items.forEach(item => {
const childOutput = []
this.dumpDataSet(item.dataSet, childOutput)
elementObject.child.push(...childOutput)
})
} else if (element.fragments) {
//
} else {
var vr
if (element.vr !== undefined) {
vr = element.vr
} else {
if (tag !== undefined) {
vr = tag.vr
}
}
elementObject.vr = vr
if (element.length < 128) {
// const str = dataSet.string(propertyName)
// if (elementObject.tagCode === 'x00280010') {
// console.log(str)
// }
// const stringIsAscii = this.isASCII(str)
// if (stringIsAscii && str !== undefined) {
// elementObject.value = str
// }
if (element.vr === undefined && tag === undefined) {
if (element.length === 2) {
elementObject.value = dataSet.uint16(propertyName)
} else if (element.length === 4) {
elementObject.value = dataSet.uint32(propertyName)
}
const str = dataSet.string(propertyName)
const stringIsAscii = this.isASCII(str)
if (stringIsAscii) {
if (str !== undefined) {
elementObject.value = str
}
} else {
if (element.length !== 2 && element.length !== 4) {
// elementObject.value = 'binary data'
}
}
} else {
if (this.isStringVr(vr)) {
const str = dataSet.string(propertyName)
const stringIsAscii = this.isASCII(str)
if (stringIsAscii) {
if (str !== undefined) {
elementObject.value = str
}
} else {
if (element.length !== 2 && element.length !== 4) {
// elementObject.value = 'binary data'
}
}
} else if (vr === 'US') {
let text = dataSet.uint16(propertyName)
for (let i = 1; i < dataSet.elements[propertyName].length / 2; i++) {
text += '\\' + dataSet.uint16(propertyName, i)
}
elementObject.value = text
} else if (vr === 'SS') {
let text = dataSet.int16(propertyName)
for (let i = 1; i < dataSet.elements[propertyName].length / 2; i++) {
text += '\\' + dataSet.int16(propertyName, i)
}
elementObject.value = text
} else if (vr === 'UL') {
let text = dataSet.uint32(propertyName)
for (let i = 1; i < dataSet.elements[propertyName].length / 4; i++) {
text += '\\' + dataSet.uint32(propertyName, i)
}
elementObject.value = text
} else if (vr === 'SL') {
let text = dataSet.int32(propertyName)
for (let i = 1; i < dataSet.elements[propertyName].length / 4; i++) {
text += '\\' + dataSet.int32(propertyName, i)
}
elementObject.value = text
} else if (vr === 'FD') {
let text = dataSet.double(propertyName)
for (let i = 1; i < dataSet.elements[propertyName].length / 8; i++) {
text += '\\' + dataSet.double(propertyName, i)
}
elementObject.value = text
} else if (vr === 'FL') {
let text = dataSet.float(propertyName)
for (let i = 1; i < dataSet.elements[propertyName].length / 4; i++) {
text += '\\' + dataSet.float(propertyName, i)
}
elementObject.value = text
} else if (vr === 'OB' || vr === 'OW' || vr === 'UN' || vr === 'OF' || vr === 'UT') {
if (element.length === 2) {
elementObject.value = dataSet.uint16(propertyName)
} else if (element.length === 4) {
elementObject.value = dataSet.uint32(propertyName)
} else {
}
} else if (vr === 'AT') {
// var group = dataSet.uint16(propertyName, 0);
// var groupHexStr = ("0000" + group.toString(16)).substr(-4);
// var element = dataSet.uint16(propertyName, 1);
// var elementHexStr = ("0000" + element.toString(16)).substr(-4);
// text += "x" + groupHexStr + elementHexStr;
} else if (vr === 'SQ') {
} else {
// no display code for VR yet, sorry!
}
}
}
}
output.push(elementObject)
}
} catch (err) {
const ex = {
exception: err,
output: output
}
console.log(ex)
}
},
getTag(tag) {
var group = tag.substring(1, 5)
var element = tag.substring(5, 9)
var tagIndex = ('(' + group + ',' + element + ')').toUpperCase()
var attr = TAG_DICT[tagIndex]
return attr
},
isASCII(str) {
return /^[\x00-\x7F]*$/.test(str)
},
isStringVr(vr) {
if (vr === 'AT' || vr === 'FL' || vr === 'FD' || vr === 'OB' || vr === 'OF' || vr === 'OW' || vr === 'SI' || vr === 'SQ' || vr === 'SS' || vr === 'UL' || vr === 'US') {
return false
}
return true
}
}
}
</script>
<style lang="scss" scoped>
.dcm-tag{
// user-select: none;
::-webkit-scrollbar {
width: 8px;
height: 15px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
}
</style>

View File

@ -233,6 +233,10 @@
<button :title="$t('trials:dicom-show:image')" class="btn-link" @click="currentDicomCanvas.saveImage()"> <button :title="$t('trials:dicom-show:image')" class="btn-link" @click="currentDicomCanvas.saveImage()">
<svg-icon icon-class="image" style="font-size:20px;" /> <svg-icon icon-class="image" style="font-size:20px;" />
</button> </button>
<!-- 标签 -->
<button :title="$t('trials:dicom-show:tags')" class="btn-link" @click="currentDicomCanvas.showTags()">
<svg-icon icon-class="dictionary" style="font-size:20px;" />
</button>
</div> </div>
</div> </div>
<div class="measureTool-wrapper"> <div class="measureTool-wrapper">
@ -405,7 +409,7 @@ export default {
loadImageStack(dicomSeries) { loadImageStack(dicomSeries) {
this.currentDicomCanvas.toolState.clipPlaying = false this.currentDicomCanvas.toolState.clipPlaying = false
this.$nextTick(() => { this.$nextTick(() => {
let series = Object.assign({}, dicomSeries) const series = Object.assign({}, dicomSeries)
this.currentDicomCanvas.loadImageStack(series) this.currentDicomCanvas.loadImageStack(series)
}) })
}, },
@ -416,7 +420,7 @@ export default {
Array.from(elements).forEach((element, index) => { Array.from(elements).forEach((element, index) => {
const canvasIndex = element.getAttribute('data-index') const canvasIndex = element.getAttribute('data-index')
if (index < seriesList.length && element.style.display !== 'none') { if (index < seriesList.length && element.style.display !== 'none') {
let series = Object.assign({}, seriesList[index]) const series = Object.assign({}, seriesList[index])
this.$refs[`dicomCanvas${canvasIndex}`].loadImageStack(series) this.$refs[`dicomCanvas${canvasIndex}`].loadImageStack(series)
} }
}) })

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,450 @@
<template>
<el-dialog
:visible.sync="visible"
:fullscreen="true"
:close-on-click-modal="false"
:before-close="beforeClose"
:append-to-body="true"
v-loading="btnLoading"
class="downloadDicomAndNonedicom"
>
<span slot="title">{{ title }}</span>
<div class="top">
<span>{{ $t('download:top:title') }}</span>
<div class="btnBox">
<el-button
type="primary"
size="mini"
v-if="hasDicom"
@click.stop="getIRReadingDownloadStudyInfo('dicom')"
>
{{ $t('download:button:downloadDicom') }}
</el-button>
<el-button
type="primary"
size="mini"
v-if="hasNonedicom"
@click.stop="getIRReadingDownloadStudyInfo('noneDicom')"
>
{{ $t('download:button:downloadNonedicom') }}
</el-button>
<el-button
type="primary"
size="mini"
@click.stop="getIRReadingDownloadStudyInfo('all')"
>
{{ $t('download:button:downloadAll') }}
</el-button>
</div>
</div>
<!--上传列表@selection-change="handleSelectionChange"-->
<el-table
ref="dicomFilesTable"
v-adaptive="{ bottomOffset: 85 }"
height="100"
:data="list"
:loading="loading"
class="dicomFiles-table"
@sort-change="handleSortByColumn"
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }"
>
<!-- <el-table-column
type="selection"
width="55"
:selectable="handleSelectable"
/> -->
<el-table-column type="index" width="40" />
<!--受试者-->
<el-table-column
:label="$t('download:table:subjectCode')"
min-width="130"
prop="SubjectCode"
show-overflow-tooltip
/>
<!--任务名称-->
<el-table-column
:label="$t('download:table:taskName')"
min-width="130"
show-overflow-tooltip
prop="TaskBlindName"
sortable="custom"
/>
<!--检查类型-->
<el-table-column
:label="$t('download:table:studyType')"
min-width="130"
show-overflow-tooltip
prop="IsDicom"
sortable="custom"
>
<template slot-scope="scope">
<span>{{ $fd('IsDicom', scope.row.IsDicom) }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('download:table:orginalStudyListNum')"
min-width="150"
show-overflow-tooltip
>
<template slot-scope="scope">
<el-button
v-if="
(scope.row.IsDicom &&
scope.row.DicomStudyList &&
scope.row.DicomStudyList.length >= 1) ||
(!scope.row.IsDicom &&
scope.row.NoneDicomStudyList &&
scope.row.NoneDicomStudyList.length >= 1)
"
type="text"
@click="handleOpenDialog(scope.row)"
>
<span>{{
scope.row.IsDicom
? scope.row.DicomStudyList.length
: scope.row.NoneDicomStudyList.length
}}</span>
</el-button>
<span v-else>0</span>
</template>
</el-table-column>
<el-table-column
:label="$t('common:action:action')"
fixed="right"
width="150"
>
<template slot-scope="scope">
<!--预览--->
<el-button
circle
icon="el-icon-view"
:title="$t('download:button:preview')"
@click.stop="preview(scope.row)"
/>
<!--下载--->
<el-button
circle
icon="el-icon-download"
:title="$t('download:button:download')"
@click.stop="getIRReadingDownloadStudyInfo('one', scope.row)"
/>
</template>
</el-table-column>
</el-table>
<study-view
v-if="model_cfg.visible"
:model_cfg="model_cfg"
:modelList="modelList"
:IsDicom="IsDicom"
/>
</el-dialog>
</template>
<script>
import {
getSubjectImageDownloadSelectList,
getIRReadingDownloadStudyInfo,
} from '@/api/load.js'
import studyView from '@/components/uploadDicomAndNonedicom/study-view.vue'
import store from '@/store'
import { downLoadFile } from '@/utils/stream.js'
import { getToken } from '@/utils/auth'
let defaultSearchData = () => {
return {
SubjectId: null,
TrialReadingCriterionId: null,
SubjectCode: null,
Asc: false,
SortField: 'TaskBlindName',
}
}
export default {
name: 'downloadDicomAndNonedicom',
components: {
'study-view': studyView,
},
props: {
visible: {
required: true,
type: Boolean,
default: false,
},
SubjectId: {
type: String,
default: '',
},
TaskId: {
type: String,
default: '',
},
SubjectCode: {
type: String,
default: '',
},
Criterion: {
type: Object,
default: () => {
return {}
},
},
},
data() {
return {
title: null,
loading: false,
list: [],
searchData: defaultSearchData(),
btnLoading: false,
hasDicom: false,
hasNonedicom: false,
//
model_cfg: {
visible: false,
showClose: true,
width: '1000px',
title: '',
appendToBody: true,
},
modelList: [],
IsDicom: true,
open: null,
}
},
mounted() {
this.getList()
this.title = `Download Images${this.SubjectCode}${this.Criterion.TrialReadingCriterionName}`
},
beforeDestroy() {
store.dispatch('trials/setUnLock', false)
},
methods: {
beforeClose() {
this.$emit('update:visible', false)
},
//
async getList() {
try {
this.searchData.SubjectId = this.SubjectId
this.searchData.TrialReadingCriterionId =
this.Criterion.TrialReadingCriterionId
this.searchData.SubjectCode = this.SubjectCode
if (this.TaskId) {
this.searchData.VisitTaskId = this.TaskId
}
this.loading = true
let res = await getSubjectImageDownloadSelectList(this.searchData)
this.loading = false
if (res.IsSuccess) {
this.list = res.Result
this.hasDicom = this.list.some((item) => item.IsDicom)
this.hasNonedicom = this.list.some((item) => !item.IsDicom)
}
} catch (err) {
this.loading = false
console.log(err)
}
},
//
async getIRReadingDownloadStudyInfo(type, row) {
try {
let data = {
SubjectId: this.SubjectId,
TrialReadingCriterionId: this.Criterion.TrialReadingCriterionId,
SubjectCode: this.SubjectCode,
SubjectVisitTaskList: [],
DicomStudyIdList: [],
NoneDicomStudyIdList: [],
}
if (type === 'dicom' || type === 'all') {
this.list.forEach((item) => {
if (
item.IsDicom &&
item.DicomStudyList &&
item.DicomStudyList.length > 0
) {
data.SubjectVisitTaskList.push({
SubjectvisitId: item.SourceSubjectVisitId,
TaskId: item.VisitTaskId,
})
let arr = item.DicomStudyList.map((d) => d.Id)
data.DicomStudyIdList = [...data.DicomStudyIdList, ...arr]
}
})
}
if (type === 'noneDicom' || type === 'all') {
this.list.forEach((item) => {
if (
!item.IsDicom &&
item.NoneDicomStudyList &&
item.NoneDicomStudyList.length > 0
) {
data.SubjectVisitTaskList.push({
SubjectvisitId: item.SourceSubjectVisitId,
TaskId: item.VisitTaskId,
})
let arr = item.NoneDicomStudyList.map((d) => d.Id)
data.NoneDicomStudyIdList = [...data.NoneDicomStudyIdList, ...arr]
}
})
}
if (type === 'one') {
if (
row.IsDicom &&
row.DicomStudyList &&
row.DicomStudyList.length > 0
) {
data.SubjectVisitTaskList.push({
SubjectvisitId: row.SourceSubjectVisitId,
TaskId: row.VisitTaskId,
})
let arr = row.DicomStudyList.map((d) => d.Id)
data.DicomStudyIdList = [...data.DicomStudyIdList, ...arr]
}
if (
!row.IsDicom &&
row.NoneDicomStudyList &&
row.NoneDicomStudyList.length > 0
) {
data.SubjectVisitTaskList.push({
SubjectvisitId: row.SourceSubjectVisitId,
TaskId: row.VisitTaskId,
})
let arr = row.NoneDicomStudyList.map((d) => d.Id)
data.NoneDicomStudyIdList = [...data.NoneDicomStudyIdList, ...arr]
}
}
this.btnLoading = true
let res = await getIRReadingDownloadStudyInfo(data)
this.btnLoading = false
if (res.IsSuccess) {
this.downloadImage(res.Result)
}
} catch (err) {
this.btnLoading = false
console.log(err)
}
},
//
async downloadImage(data) {
try {
let { files, name, fileType } = this.formatDownloadFile(data)
await downLoadFile(files, name, 'zip')
} catch (err) {
console.log(err)
}
},
//
formatDownloadFile(list) {
let files = [],
name = `${list[0].SubjectCode}_${new Date().getTime()}.zip`
list.forEach((data) => {
if (data.StudyList && data.StudyList.length > 0) {
let StudyList = data.StudyList
StudyList.forEach((study) => {
if (study.SeriesList.length > 0) {
study.SeriesList.forEach((series) => {
if (series.InstancePathList.length > 0) {
series.InstancePathList.forEach((instance) => {
let fileName = instance.Path.split('/').pop()
let obj = {
name: `${data.SubjectCode}/${
data.TaskBlindName
}/${this.$fd('IsDicom', true)}/${
study.StudyCode
}/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path,
}
files.push(obj)
})
}
})
}
})
}
if (data.NoneDicomStudyList && data.NoneDicomStudyList.length > 0) {
let NoneDicomStudyList = data.NoneDicomStudyList
//
NoneDicomStudyList.forEach((study) => {
if (study.FileList.length > 0) {
study.FileList.forEach((item) => {
let obj = {
name: `${data.SubjectCode}/${data.TaskBlindName}/${this.$fd(
'IsDicom',
false
)}/${study.StudyCode}/${item.FileName}`,
url: this.OSSclientConfig.basePath + item.Path,
}
files.push(obj)
})
}
})
}
})
return { files, name }
},
handleOpenDialog(item) {
this.model_cfg.title = `${item.SubjectCode || ''} > ${item.TaskBlindName}`
if (item.IsDicom) {
this.modelList = item.DicomStudyList
} else {
this.modelList = item.NoneDicomStudyList
this.modelList.forEach((data) => {
data.SourceSubjectVisitId = item.SourceSubjectVisitId
})
}
this.IsDicom = item.IsDicom
this.model_cfg.visible = true
},
//
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()
},
preview(row) {
if (!row.IsDicom) {
this.handlePreviewNoneDicomFiles(row)
} else {
this.handleViewReadingImages(row)
}
},
// Dicom
handlePreviewNoneDicomFiles(row) {
if (this.open) {
this.open.close()
}
let trialId = this.$route.query.trialId
var token = getToken()
const routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&visitTaskId=${row.VisitTaskId}&TokenKey=${token}`,
})
this.open = window.open(routeData.href, '_blank')
},
//
handleViewReadingImages(row) {
if (this.open) {
this.open.close()
}
var token = getToken()
let trialId = this.$route.query.trialId
const routeData = this.$router.resolve({
path: `/showvisitdicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}`,
})
this.open = window.open(routeData.href, '_blank')
},
},
}
</script>
<style lang="scss" scoped>
.top {
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 0;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
<template>
<el-dialog
:visible.sync="visible"
:fullscreen="true"
:close-on-click-modal="false"
:before-close="beforeClose"
:append-to-body="true"
class="uploadDicomAndNonedicom"
>
<span slot="title">{{ title }}</span>
<el-tabs type="border-card" v-model="activeName">
<el-tab-pane
:label="$t('uploadDicomAndNonedicom:label:dicom')"
name="dicom"
>
<dicomFile
v-if="activeName === 'dicom'"
:SubjectId="SubjectId"
:SubjectCode="SubjectCode"
:Criterion="Criterion"
/>
</el-tab-pane>
<el-tab-pane
:label="$t('uploadDicomAndNonedicom:label:nonedicom')"
name="nonedicom"
>
<nonedicomFile
v-if="activeName === 'nonedicom'"
:SubjectId="SubjectId"
:SubjectCode="SubjectCode"
:Criterion="Criterion"
/>
</el-tab-pane>
</el-tabs>
</el-dialog>
</template>
<script>
import dicomFile from './dicomFile.vue'
import nonedicomFile from './nonedicomFile.vue'
export default {
name: 'uploadDicomAndNonedicom',
components: { dicomFile, nonedicomFile },
props: {
visible: {
required: true,
type: Boolean,
default: false,
},
SubjectId: {
type: String,
default: '',
},
SubjectCode: {
type: String,
default: '',
},
Criterion: {
type: Object,
default: () => {
return {}
},
},
},
data() {
return {
title: '',
activeName: 'dicom',
}
},
mounted() {
this.title = `Upload Images${this.SubjectCode}${this.Criterion.TrialReadingCriterionName}`
},
methods: {
beforeClose() {
this.$emit('update:visible', false)
},
},
}
</script>
<style lang="scss" scoped>
::v-deep.el-tabs--left .el-tabs__header.is-left {
margin-right: 0;
}
.uploadDicomAndNonedicom {
::v-deep.el-tabs--border-card > .el-tabs__header .el-tabs__item {
color: #909399;
}
::v-deep.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active {
color: #428bca;
background-color: #fff;
border-right-color: #dcdfe6;
border-left-color: #dcdfe6;
}
}
</style>

View File

@ -0,0 +1,788 @@
<template>
<div class="nonedicomFile">
<div class="top">
<span>{{ $t('upload:nonedicom:title') }}</span>
</div>
<!--检查列表-->
<el-table
:data="list"
style="width: 100%"
v-adaptive="{ bottomOffset: 40 }"
:loading="loading"
@sort-change="handleSortByColumn"
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }"
>
<!--受试者-->
<el-table-column
prop="SubjectCode"
:label="$t('upload:nonedicom:table:subject')"
/>
<!--任务名称-->
<el-table-column
prop="TaskBlindName"
:label="$t('upload:nonedicom:table:taskName')"
sortable="custom"
/>
<!--检查类型-->
<el-table-column
prop="Modality"
:label="$t('upload:nonedicom:table:molityType')"
sortable="custom"
>
</el-table-column>
<!--检查部位-->
<el-table-column
prop="BodyPart"
:label="$t('upload:nonedicom:table:bodyPart')"
sortable="custom"
/>
<!--原文件数-->
<el-table-column
prop="FileCount"
:label="$t('upload:nonedicom:table:fileCount')"
>
<template slot-scope="scope">
<el-popover
v-if="scope.row.FileCount"
trigger="click"
placement="bottom"
>
<el-table :data="scope.row.FileList" height="300" size="small">
<!-- 文件名称 -->
<el-table-column
prop="FileName"
:label="$t('trials:audit:table:nonDicomsFileName')"
width="200"
/>
<el-table-column :label="$t('common:action:action')" width="120">
<template slot-scope="files">
<!-- 预览 -->
<el-button
type="text"
:disabled="
files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
"
@click.native.prevent="previewFile(files.row)"
>
{{ $t('trials:audit:button:nonDicomsPreview') }}
</el-button>
</template>
</el-table-column>
</el-table>
<div slot="reference" class="name-wrapper">
<el-button type="text">
{{ scope.row.FileCount }}
</el-button>
</div>
</el-popover>
<span v-else>{{ scope.row.FileCount }}</span>
</template>
</el-table-column>
<!--后处理文件数-->
<el-table-column
prop="UploadedFileCount"
:label="$t('upload:nonedicom:table:uploadFileCount')"
>
<template slot-scope="scope">
<el-popover
v-if="scope.row.UploadedFileCount"
trigger="click"
placement="bottom"
>
<el-table
:data="scope.row.UploadedFileList"
height="300"
size="small"
>
<!-- 文件名称 -->
<el-table-column
prop="FileName"
:label="$t('trials:audit:table:nonDicomsFileName')"
width="200"
/>
<el-table-column :label="$t('common:action:action')" width="120">
<template slot-scope="files">
<!-- 预览 -->
<el-button
type="text"
:disabled="
files.row.FileType &&
files.row.FileType.indexOf('zip') >= 0
"
@click.native.prevent="previewFile(files.row)"
>
{{ $t('trials:audit:button:nonDicomsPreview') }}
</el-button>
</template>
</el-table-column>
</el-table>
<div slot="reference" class="name-wrapper">
<el-button type="text">
{{ scope.row.UploadedFileCount }}
</el-button>
</div>
</el-popover>
<span v-else>{{ scope.row.UploadedFileCount }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('common:action:action')"
fixed="right"
width="180"
>
<template slot-scope="scope">
<!--预览--->
<el-button
circle
:disabled="scope.row.UploadedFileCount <= 0"
icon="el-icon-view"
:title="$t('upload:nonedicom:button:preview')"
@click.stop="handlePreviewNoneDicomFiles(scope.row)"
/>
<!--上传--->
<el-button
circle
icon="el-icon-upload2"
:title="$t('upload:nonedicom:button:upload')"
@click.native.prevent="handleUpload(scope.row)"
/>
<!--删除--->
<el-button
:disabled="scope.row.UploadedFileCount <= 0"
circle
icon="el-icon-delete"
:title="$t('upload:nonedicom:button:delete')"
@click.stop="remove(scope.row)"
/>
</template>
</el-table-column>
</el-table>
<!-- 预览单个图像 -->
<el-dialog
v-if="imgObj.visible"
:visible.sync="imgObj.visible"
:title="$t('upload:nonedicom:dialogTitle:preview')"
append-to-body
width="565px"
>
<div
v-loading="imgObj.loading"
class="base-modal-body"
style="border: 2px solid #ccc; padding: 10px"
>
<el-image
:src="`${OSSclientConfig.basePath}${imgObj.url}`"
crossorigin="anonymous"
fit="fit"
style="height: 500px; width: 500px"
@error="imgObj.loading = false"
@load="imgObj.loading = false"
/>
</div>
</el-dialog>
<!-- 上传非dicom文件 -->
<el-dialog
v-if="uploadVisible"
:visible.sync="uploadVisible"
:close-on-click-modal="false"
:title="$t('trials:uploadNonDicoms:dialogTitle:upload')"
width="800px"
append-to-body
custom-class="base-dialog-wrapper"
@close="resetFileDiaolg"
>
<!-- 多文件上传 -->
<form id="inputForm" ref="uploadForm">
<el-divider content-position="left">{{
$t('trials:uploadNonDicoms:label:fileType')
}}</el-divider>
<div class="form-group">
<div class="upload" style="margin-right: 10px">
<input
multiple="multiple"
webkitdirectory=""
directory
accept="*/*"
type="file"
name="uploadFolder"
class="select-file"
title=""
@change="beginScanFiles($event)"
v-if="!btnLoading"
/>
<div class="btn-select">
{{ $t('trials:uploadNonDicoms:button:selectFolder') }}
</div>
</div>
<div class="upload">
<input
class="select-file"
multiple=""
:accept="faccept.join(',')"
type="file"
name="uploadFile"
title=""
@change="beginScanFiles($event)"
v-if="!btnLoading"
/>
<div class="btn-select">
{{ $t('trials:uploadNonDicoms:button:select') }}
</div>
</div>
<!-- <span style="margin-left: 10px">{{
$store.state.trials.uploadTip
}}</span> -->
</div>
</form>
<!-- 文件列表 -->
<el-table
ref="filesTable"
:data="fileList"
class="dicomFiles-table"
height="300"
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55"
:selectable="(row, index) => row.status !== 2 && !btnLoading"
/>
<el-table-column type="index" width="50" />
<!-- 文件名称 -->
<el-table-column
prop="name"
:label="$t('trials:uploadNonDicoms:table:fileName')"
min-width="100"
/>
<!-- 文件大小 -->
<el-table-column
prop="size"
:label="$t('trials:uploadNonDicoms:table:fileSize')"
>
<template slot-scope="scope">
<span>{{
scope.row.size && scope.row.size > 0
? `${(scope.row.size / 1024 / 1024).toFixed(2)}MB`
: 0
}}</span>
</template>
</el-table-column>
<!-- 文件类型 -->
<el-table-column
prop="type"
:label="$t('trials:uploadNonDicoms:table:fileType')"
/>
<!-- 上传状态 -->
<el-table-column
prop="status"
:label="$t('trials:uploadNonDicoms:table:uploadStatus')"
min-width="100"
>
<template slot-scope="scope">
<el-tag
:type="['warning', 'info', 'success', 'danger'][scope.row.status]"
v-if="scope.row.status || scope.row.status === 0"
>{{ $fd('NoneDicomUploadStatus', scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
:label="$t('trials:uploadNonDicoms:table:failedFileCount')"
min-width="150"
show-overflow-tooltip
>
<template slot-scope="scope">
<el-progress
color="#409eff"
:percentage="
((scope.row.uploadFileSize * 100) / scope.row.size).toFixed(2) *
1
"
/>
</template>
</el-table-column>
<el-table-column :label="$t('common:action:action')">
<template slot-scope="scope">
<el-button
size="mini"
icon="el-icon-delete"
circle
:disabled="btnLoading"
:title="$t('trials:crcUpload:action:delete')"
@click="handleRemoveFile(scope.row)"
/>
</template>
</el-table-column>
</el-table>
<div style="text-align: right; padding: 10px 0px">
<span style="margin-right: 10px">{{
$store.state.trials.uploadTip
}}</span>
<el-button
size="small"
type="primary"
:disabled="selectArr.length == 0"
:loading="btnLoading"
@click="beginUpload"
>
{{ $t('trials:uploadNonDicoms:action:upload') }}
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getIRUploadTaskNoneDicomStudyList,
deleteTaskStudy,
} from '@/api/load.js'
import { preArchiveStudy, uploadNoneDicomFile } from '@/api/trials'
import store from '@/store'
import { getToken } from '@/utils/auth'
let defaultSearchData = () => {
return {
SubjectId: null,
TrialReadingCriterionId: null,
SubjectCode: null,
Asc: false,
SortField: 'TaskBlindName',
}
}
export default {
name: 'nonedicomFile',
props: {
SubjectId: {
type: String,
default: '',
},
SubjectCode: {
type: String,
default: '',
},
Criterion: {
type: Object,
default: () => {
return {}
},
},
},
data() {
return {
loading: false,
list: [],
searchData: defaultSearchData(),
imgObj: { url: '', visible: false, loading: false },
uploadVisible: false,
fileList: [],
selectArr: [],
successFileList: [],
isFail: false,
faccept: ['.jpg', '.jpeg', '.png', '.bmp', '.zip'],
fCount: 0,
btnLoading: false,
currentRow: {},
studyMonitorId: null,
open: null,
}
},
watch: {
isFail() {
if (this.isFail) {
this.$confirm(
this.$t('trials:visit:crcUpload:nomDicomFiles:failUpload'),
{
type: 'warning',
distinguishCancelAndClose: true,
confirmButtonText: this.$t('common:button:confirm'),
cancelButtonText: this.$t('common:button:cancel'),
}
)
.then(() => {
this.beginUpload()
})
.catch((err) => {
this.btnLoading = false
console.log(err)
})
}
},
btnLoading() {
store.dispatch('trials/setUnLock', this.btnLoading)
},
},
created() {
this.getList()
},
beforeDestroy() {
store.dispatch('trials/setUnLock', false)
},
methods: {
async getList() {
try {
this.searchData.SubjectId = this.SubjectId
this.searchData.TrialReadingCriterionId =
this.Criterion.TrialReadingCriterionId
this.searchData.SubjectCode = this.SubjectCode
this.loading = true
let res = await getIRUploadTaskNoneDicomStudyList(this.searchData)
this.loading = false
if (res.IsSuccess) {
this.list = res.Result
}
} catch (err) {
this.loading = false
console.log(err)
}
},
//
beginScanFiles(e) {
var files = [...e.target.files]
var sameFiles = []
files.forEach((file) => {
var extendName = file.name
.substring(file.name.lastIndexOf('.'))
.toLocaleLowerCase()
if (
this.faccept.indexOf(extendName) !== -1 &&
this.fileList.findIndex((v) => v.name === file.name) > -1
) {
sameFiles.push(file.name)
}
})
var scope = this
if (sameFiles.length > 0) {
const h = this.$createElement
var msg = this.$t(
'trials:uploadNonDicoms:message:exsitSameFile'
).replace('xxx', sameFiles.join(', '))
this.$msgbox({
message: h('div', { style: 'maxHeight:300px;overflow: auto;' }, [
h('p', null, msg),
h(
'p',
null,
this.$t('trials:uploadNonDicoms:message:isContinueUpload')
),
]),
type: 'warning',
showCancelButton: true,
})
.then(() => {
scope.pendingUploadQuene(files)
})
.catch(() => {
scope.resetUploadForm()
})
} else {
scope.pendingUploadQuene(files)
}
},
pendingUploadQuene(files) {
for (var i = 0; i < files.length; ++i) {
const fileName = files[i].name
var extendName = fileName
.substring(fileName.lastIndexOf('.'))
.toLocaleLowerCase()
if (this.faccept.indexOf(extendName) !== -1) {
files[i].id = `${files[i].lastModified}${files[i].name}`
let obj = {
name: files[i].name,
size: files[i].size,
type: extendName.split('.')[1],
status: 0,
file: files[i],
id: `${files[i].lastModified}${files[i].name}`,
fileType: files[i].type,
uploadFileSize: 0,
}
this.fileList.push(obj)
this.$refs.filesTable.toggleRowSelection(obj, true)
}
}
this.resetUploadForm()
},
handleRemoveFile(row) {
this.$confirm(this.$t('trials:uploadNonDicoms:message:delete'), {
type: 'warning',
distinguishCancelAndClose: true,
})
.then(() => {
this.fileList.splice(
this.fileList.findIndex((item) => item.id === row.id),
1
)
let flag = this.successFileList.some((item) => item.id === row.id)
if (flag) {
this.successFileList.splice(
this.successFileList.findIndex((item) => item.id === row.id),
1
)
}
})
.catch(() => {})
},
resetUploadForm() {
this.$nextTick(() => {
this.$refs.uploadForm.reset()
})
},
//
handleUpload(row) {
this.fileList = []
this.uploadVisible = true
this.fCount = 0
this.currentRow = { ...row }
},
resetFileDiaolg() {
this.btnLoading = false
this.uploadVisible = false
this.selectArr = []
this.successFileList = []
this.OSSclient.close()
},
//
previewFile(row) {
// window.open(row.FullFilePath, '_blank')
this.imgObj.url = row.FullFilePath || row.Path
this.imgObj.loading = true
this.imgObj.visible = true
},
// Dicom
handlePreviewNoneDicomFiles(row) {
if (this.open) {
this.open.close()
}
let trialId = this.$route.query.trialId
var token = getToken()
const routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&studyId=${row.Id}&visitTaskId=${row.VisitTaskId}&TokenKey=${token}`,
})
this.open = window.open(routeData.href, '_blank')
},
//
async remove(item) {
try {
let confirm = await this.$confirm(
this.$t('upload:nonedicom:confirm:delMessage'),
{
type: 'warning',
distinguishCancelAndClose: true,
confirmButtonText: this.$t('common:button:confirm'),
cancelButtonText: this.$t('common:button:cancel'),
}
)
if (confirm !== 'confirm') return
let params = {
VisitTaskId: item.VisitTaskId,
IsDicom: false,
NoneDicomStudyId: item.Id,
}
let res = await deleteTaskStudy(params)
if (res.IsSuccess) {
this.getList()
this.$message.success(
this.$t('trials:uploadImage:message:delSuccess')
)
}
} catch (err) {
console.log(err)
}
},
//
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()
},
//
handleSelectionChange(selection) {
this.selectArr = selection
},
//
async beginUpload() {
this.btnLoading = true
this.isFail = false
const fileMaxSize = 1024 * 1024 * 1024 * 1 // 1G
var currentFilesSize = 0
this.selectArr.forEach((item) => {
currentFilesSize += item.size
})
if (currentFilesSize / fileMaxSize > 1) {
// 'Upload file size cannot exceed 1G'
this.$alert(this.$t('trials:uploadNonDicoms:message:uploadSize'))
this.btnLoading = false
} else {
this.selectArr.forEach((item) => (item.status = 0))
let num = this.selectArr.length > 6 ? 6 : this.selectArr.length
let funArr = []
let res = await preArchiveStudy({
subjectVisitId: this.currentRow.SourceSubjectVisitId,
isDicom: false,
})
if (res.IsSuccess) {
this.studyMonitorId = res.Result
for (let i = 0; i < num; i++) {
funArr.push(this.handleUploadTask(this.selectArr, i))
}
if (funArr.length > 0) {
let res = await Promise.all(funArr)
}
} else {
this.isFail = true
}
}
},
//
async handleUploadTask(arr, index) {
if (!this.uploadVisible) return
let file = this.fileList.filter((item) => item.id === arr[index].id)[0]
file.status = 1
console.log(file)
let path = `/${this.$route.query.trialId}/TaskImage/${
this.currentRow.SubjectId
}/${this.currentRow.VisitTaskId}/${this.$guid()}${file.name
.substring(file.name.lastIndexOf('.'))
.toLocaleLowerCase()}`
console.log(path)
const fileData = await this.fileToBlob(file.file)
let res = await this.fileToOss(path, fileData, file)
if (res) {
file.status = 2
this.successFileList.push({
fileName: file.name,
filePath: this.$getObjectName(res.url),
fileFize: file.size,
fileType: file.fileType,
})
let flag = arr.every((item) => item.status === 2)
if (flag) {
return this.submitFile(this.successFileList)
}
} else {
file.status = 3
}
let flag = arr.every((item) => item.status > 1)
if (flag) {
let failFileList = arr.filter((item) => item.status === 3)
if (failFileList && failFileList.length > 0) {
this.$refs.filesTable.clearSelection()
failFileList.forEach((row) => {
row.uploadFileSize = 0
this.$refs.filesTable.toggleRowSelection(row)
})
this.isFail = true
return false
}
}
let ind = arr.findIndex((item) => item.status === 0)
if (ind >= 0) {
return this.handleUploadTask(arr, ind)
} else {
return false
}
},
// fileoss
async fileToOss(path, file, item) {
try {
let res = await this.OSSclient.multipartUpload(
{
path,
file,
speed: true,
},
(percentage, checkpoint, lastPer) => {
item.uploadFileSize += checkpoint.size * (percentage - lastPer)
if (item.uploadFileSize > file.fileSize) {
item.uploadFileSize = file.fileSize
}
}
)
if (res) {
return res
} else {
return false
}
} catch (err) {
console.log(err)
return false
}
},
// Dicom
submitFile(uploadedFileList) {
if (!this.uploadVisible) return
this.btnLoading = true
var params = {
trialId: this.$route.query.trialId,
subjectVisitId: this.currentRow.SourceSubjectVisitId,
noneDicomStudyId: this.currentRow.Id,
studyMonitorId: this.studyMonitorId,
VisitTaskId: this.currentRow.VisitTaskId,
uploadedFileList: uploadedFileList,
}
uploadNoneDicomFile(params)
.then((res) => {
this.resetFileDiaolg()
this.getList()
//
this.$emit('getList')
this.$message.success(
this.$t('trials:uploadNonDicoms:message:uploadedSuccessfully')
)
})
.catch(() => {
this.btnLoading = false
})
},
},
}
</script>
<style lang="scss" scoped>
.top {
margin: 10px 0;
}
.upload {
display: inline-block;
height: 30px;
width: 90px;
padding: 2px 10px;
line-height: 23px;
position: relative;
text-decoration: none;
border-radius: 3px;
overflow: hidden;
text-align: center;
background: #428bca;
border-color: #428bca;
color: #fff;
.select-file {
height: 30px;
width: 90px;
position: absolute;
overflow: hidden;
left: 0;
top: 0;
opacity: 0;
font-size: 0;
}
.btn-select {
//
width: 90px;
height: 30px;
line-height: 30px;
text-align: center;
cursor: pointer;
border-radius: 24px;
overflow: hidden;
position: absolute;
top: 0;
left: 0;
pointer-events: none; //pointer-events:none穿
}
}
</style>

View File

@ -0,0 +1,140 @@
<template>
<base-model :config="model_cfg">
<div slot="dialog-body">
<el-table :data="modelList" style="width: 100%" height="300">
<!--检查编号-->
<el-table-column
prop="StudyCode"
:label="$t('trials:uploadImage:table:StudyCode')"
/>
<!--检查类型-->
<el-table-column
prop="ModalityForEdit"
:label="$t('trials:uploadImage:table:ModalityForEdit')"
v-if="IsDicom"
/>
<!--检查模态-->
<el-table-column
prop="Modalities"
:label="$t('trials:uploadImage:table:Modalities')"
v-if="IsDicom"
/>
<!--检查部位-->
<el-table-column
prop="BodyPartForEdit"
:label="$t('trials:uploadImage:table:BodyPartForEdit')"
v-if="IsDicom"
/>
<!--序列数量-->
<el-table-column
prop="SeriesCount"
:label="$t('trials:uploadImage:table:SeriesCount')"
v-if="IsDicom"
/>
<!--图像数量-->
<el-table-column
prop="InstanceCount"
:label="$t('trials:uploadImage:table:InstanceCount')"
v-if="IsDicom"
/>
<!--检查时间-->
<el-table-column
prop="StudyTime"
:label="$t('trials:uploadImage:table:StudyTime')"
v-if="IsDicom"
min-width="130"
/>
<!--检查模态-->
<el-table-column
prop="Modality"
:label="$t('trials:uploadImage:table:Modalities')"
v-if="!IsDicom"
/>
<!--检查部位-->
<el-table-column
prop="BodyPart"
:label="$t('trials:uploadImage:table:BodyPartForEdit')"
v-if="!IsDicom"
/>
<!--文件数量-->
<el-table-column
prop="FileCount"
:label="$t('trials:uploadImage:table:FileCount')"
v-if="!IsDicom"
/>
<!--检查时间-->
<el-table-column
prop="ImageDate"
:label="$t('trials:uploadImage:table:StudyTime')"
v-if="!IsDicom"
min-width="130"
/>
<el-table-column
:label="$t('common:action:action')"
fixed="right"
width="80"
>
<template slot-scope="scope">
<!--预览--->
<el-button
circle
icon="el-icon-view"
:title="$t('trials:uploadImage:button:download')"
@click.stop="preview(scope.row)"
/>
</template>
</el-table-column>
</el-table>
</div>
</base-model>
</template>
<script>
import baseModel from '@/components/BaseModel'
import { getToken } from '@/utils/auth'
export default {
name: 'studyView',
props: {
model_cfg: {
type: Object,
default: () => {
return {}
},
},
modelList: {
type: Array,
default: () => {
return []
},
},
IsDicom: {
required: true,
type: Boolean,
default: true,
},
},
components: {
'base-model': baseModel,
},
methods: {
//
preview(row) {
let routeData = null
if (this.IsDicom) {
var token = getToken()
routeData = this.$router.resolve({
path: `/showdicom?studyId=${row.Id}&TokenKey=${token}&type=Study`,
})
} else {
let trialId = this.$route.query.trialId
var token = getToken()
routeData = this.$router.resolve({
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&studyId=${row.Id}&TokenKey=${token}`,
})
}
window.open(routeData.href, '_blank')
},
},
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -102,7 +102,6 @@
import uploadList from "./components/upload-list.vue"; import uploadList from "./components/upload-list.vue";
import studyView from "./components/study-view.vue"; import studyView from "./components/study-view.vue";
import { getSubjectImageUploadList, deleteTaskStudy } from "@/api/load.js"; import { getSubjectImageUploadList, deleteTaskStudy } from "@/api/load.js";
import { downloadImage } from "@/utils/uploadZip.js";
import store from "@/store"; import store from "@/store";
export default { export default {
name: "uploadImage", name: "uploadImage",
@ -591,7 +590,7 @@ export default {
files.push(obj); files.push(obj);
} }
store.dispatch("trials/setUnLock", true); store.dispatch("trials/setUnLock", true);
let res = await downloadImage(zipName, files); // let res = await downloadImage(zipName, files);
store.dispatch("trials/setUnLock", false); store.dispatch("trials/setUnLock", false);
}, },
}, },

View File

@ -28,25 +28,22 @@ Vue.use(permission)
import Viewer from 'v-viewer' import Viewer from 'v-viewer'
import './assets/css/viewer.css' import './assets/css/viewer.css'
Vue.use(Viewer)
Viewer.setDefaults({ Viewer.setDefaults({
Options: { // navbar: true, //底部缩略图
'inline': true, toolbar: {
'button': true, zoomIn: true,
'navbar': true, zoomOut: true,
'title': true, reset: true,
'toolbar': true, prev: true,
'tooltip': true, next: true,
'movable': true, rotateLeft: true,
'zoomable': true, rotateRight: true,
'rotatable': true, flipHorizontal: true,
'scalable': true, flipVertical: true,
'transition': true,
'keyboard': true,
'url': 'data-source'
} }
}) })
Vue.use(Viewer)
import hasPermi from './directive/permission' import hasPermi from './directive/permission'
Vue.use(hasPermi) Vue.use(hasPermi)
@ -148,6 +145,12 @@ Vue.config.productionTip = false
Vue.prototype.$upload = () => { Vue.prototype.$upload = () => {
_vm.$forceUpdate() _vm.$forceUpdate()
} }
Vue.prototype.$guid = () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
Vue.prototype.fileToBlob = (file) => { Vue.prototype.fileToBlob = (file) => {
// 创建 FileReader 对象 // 创建 FileReader 对象
const reader = new FileReader() const reader = new FileReader()

View File

@ -6,11 +6,12 @@ import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import Vue from 'vue' import Vue from 'vue'
import { OSSclient } from './utils/oss' import { OSSclient } from './utils/oss'
import WHITELIST from "./utils/whiteList"
// import getPageTitle from '@/utils/get-page-title' // import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) NProgress.configure({ showSpinner: false })
const whiteList = ['/ReviewersResearch', '/login', '/error', '/resetpassword', '/recompose', '/email-recompose', '/trialStats', '/showdicom', '/imagesShare', '/audit', '/preview', '/researchLogin', '/researchLogin_m', '/blindResumeInfo', '/trialsResume', '/joinVerify', '/showNoneDicoms', '/noneDicomReading', '/clinicalData', '/readingDicoms', '/readingPage', '/visitDicomReview', '/visitNondicomReview', '/globalReview', '/adReview', '/oncologyReview', '/nonedicoms'] const whiteList = WHITELIST
store.state.trials.whiteList = whiteList; store.state.trials.whiteList = whiteList;
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start() NProgress.start()
@ -25,15 +26,15 @@ router.beforeEach(async (to, from, next) => {
if (to.path === '/login' || to.path === '/recompose' || to.path === '/email-recompose' || to.path === '/error' || to.path === '/ReviewersResearchForm' || to.path === '/ReviewersResearch') { if (to.path === '/login' || to.path === '/recompose' || to.path === '/email-recompose' || to.path === '/error' || to.path === '/ReviewersResearchForm' || to.path === '/ReviewersResearch') {
if (to.path === '/ReviewersResearch') { if (to.path === '/ReviewersResearch') {
await this.$store.dispatch('user/logout') await this.$store.dispatch('user/logout')
OSSclient() await OSSclient()
} }
if (to.path === '/ReviewersResearchForm') { if (to.path === '/ReviewersResearchForm') {
OSSclient() await OSSclient()
} }
next() next()
NProgress.done() NProgress.done()
} else { } else {
OSSclient() await OSSclient()
const hasGetUserInfo = store.getters.userId const hasGetUserInfo = store.getters.userId
if (hasGetUserInfo) { if (hasGetUserInfo) {
next() next()
@ -66,7 +67,7 @@ router.beforeEach(async (to, from, next) => {
} else { } else {
// 在免登录whiteList中直接进入 // 在免登录whiteList中直接进入
if (to.path === '/readingDicoms' || to.path === '/noneDicomReading') { if (to.path === '/readingDicoms' || to.path === '/noneDicomReading') {
OSSclient() await OSSclient()
} }
next() next()
} }

View File

@ -35,26 +35,50 @@ const getDefaultState = () => {
} }
} }
function getQuestions(questions) { function getQuestions(questions) {
const criterionType = parseInt(localStorage.getItem('CriterionType'))
questions.forEach(item => { questions.forEach(item => {
if (item.Type === 'table' && item.TableQuestions && item.TableQuestions.Answers.length > 0) { if (item.Type === 'table' && item.TableQuestions && item.TableQuestions.Answers.length > 0) {
item.TableQuestions.Answers.forEach(answerObj => { item.TableQuestions.Answers.forEach(answerObj => {
answerObj.lesionPart = getQuestionAnswer(item.TableQuestions.Questions, 8, answerObj)
answerObj.loctation = getQuestionAnswer(item.TableQuestions.Questions, 6, answerObj)
answerObj.lesionLength = getQuestionAnswer(item.TableQuestions.Questions, 0, answerObj)
answerObj.lesionShort = getQuestionAnswer(item.TableQuestions.Questions, 1, answerObj)
answerObj.isDicomReading = answerObj.IsDicomReading === 'True' answerObj.isDicomReading = answerObj.IsDicomReading === 'True'
var isLymphLesion = getQuestionAnswer(item.TableQuestions.Questions, 2, answerObj)
isLymphLesion = isLymphLesion ? parseInt(isLymphLesion) : null
answerObj.isLymphLesion = isLymphLesion
answerObj.lesionState = getQuestionAnswer(item.TableQuestions.Questions, 7, answerObj)
var lesionNum = getQuestionAnswer(item.TableQuestions.Questions, 11, answerObj)
answerObj.lesionNum = lesionNum
if (answerObj.RowId) { if (answerObj.RowId) {
var idx = item.TableQuestions.Questions.findIndex(i => i.QuestionMark === 11) if (criterionType === 10) {
if (idx > -1) {
// pcwg // pcwg
var lesionNum = getQuestionAnswer(item.TableQuestions.Questions, 11, answerObj)
answerObj.lesionNum = lesionNum
answerObj.saveTypeEnum = isNaN(parseInt(answerObj.lesionNum)) ? 1 : 2 answerObj.saveTypeEnum = isNaN(parseInt(answerObj.lesionNum)) ? 1 : 2
} else if (criterionType === 19) {
// ivus
answerObj.area1 = getQuestionAnswer(item.TableQuestions.Questions, 1001, answerObj)
answerObj.area2 = getQuestionAnswer(item.TableQuestions.Questions, 1002, answerObj)
const v = getQuestionAnswer(item.TableQuestions.Questions, 1003, answerObj)
answerObj.diff = v
answerObj.saveTypeEnum = isNaN(parseFloat(v)) ? 1 : 2
} else if (criterionType === 20) {
// oct
if (item.LesionType === 101) {
answerObj.l1 = getQuestionAnswer(item.TableQuestions.Questions, 1011, answerObj)
answerObj.l2 = getQuestionAnswer(item.TableQuestions.Questions, 1012, answerObj)
answerObj.l3 = getQuestionAnswer(item.TableQuestions.Questions, 1013, answerObj)
const min = getQuestionAnswer(item.TableQuestions.Questions, 1014, answerObj)
answerObj.min = min
const mean = getQuestionAnswer(item.TableQuestions.Questions, 1015, answerObj)
answerObj.mean = mean
answerObj.saveTypeEnum = (isNaN(parseFloat(min)) || isNaN(parseFloat(mean))) ? 1 : 2
} else if (item.LesionType === 103) {
const angle = getQuestionAnswer(item.TableQuestions.Questions, 1016, answerObj)
answerObj.angle = angle
answerObj.saveTypeEnum = isNaN(parseFloat(angle)) ? 1 : 2
}
} else { } else {
answerObj.lesionPart = getQuestionAnswer(item.TableQuestions.Questions, 8, answerObj)
answerObj.loctation = getQuestionAnswer(item.TableQuestions.Questions, 6, answerObj)
answerObj.lesionLength = getQuestionAnswer(item.TableQuestions.Questions, 0, answerObj)
answerObj.lesionShort = getQuestionAnswer(item.TableQuestions.Questions, 1, answerObj)
let isLymphLesion = getQuestionAnswer(item.TableQuestions.Questions, 2, answerObj)
isLymphLesion = isLymphLesion ? parseInt(isLymphLesion) : null
answerObj.isLymphLesion = isLymphLesion
answerObj.lesionState = getQuestionAnswer(item.TableQuestions.Questions, 7, answerObj)
answerObj.saveTypeEnum = isNaN(parseInt(answerObj.lesionState)) ? 1 : 2 answerObj.saveTypeEnum = isNaN(parseInt(answerObj.lesionState)) ? 1 : 2
} }
} else { } else {
@ -811,9 +835,16 @@ const actions = {
// } // }
series.InstanceInfoList.forEach(instance => { series.InstanceInfoList.forEach(instance => {
if (instance.NumberOfFrames && instance.NumberOfFrames > 1) { if (instance.NumberOfFrames && instance.NumberOfFrames > 1) {
for (let i = 0; i < instance.NumberOfFrames; i++) { if (study.IsCriticalSequence && instance.KeyFramesList.length > 0) {
const imageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? Vue.prototype.OSSclientConfig.basePath : Vue.prototype.OSSclientConfig.basePath}${instance.Path}?frame=${i}&instanceId=${instance.Id}&visitTaskId=${obj.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${index}` instance.KeyFramesList.map(i => {
imageIds.push(imageId) const imageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? Vue.prototype.OSSclientConfig.basePath : Vue.prototype.OSSclientConfig.basePath}${instance.Path}?frame=${i}&instanceId=${instance.Id}&visitTaskId=${obj.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${index}`
imageIds.push(imageId)
})
} else {
for (let i = 0; i < instance.NumberOfFrames; i++) {
const imageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? Vue.prototype.OSSclientConfig.basePath : Vue.prototype.OSSclientConfig.basePath}${instance.Path}?frame=${i}&instanceId=${instance.Id}&visitTaskId=${obj.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${index}`
imageIds.push(imageId)
}
} }
instance.ImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? Vue.prototype.OSSclientConfig.basePath : Vue.prototype.OSSclientConfig.basePath}${instance.Path}?frame=${0}&instanceId=${instance.Id}&visitTaskId=${obj.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${index}` instance.ImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? Vue.prototype.OSSclientConfig.basePath : Vue.prototype.OSSclientConfig.basePath}${instance.Path}?frame=${0}&instanceId=${instance.Id}&visitTaskId=${obj.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${index}`
} else { } else {
@ -1053,7 +1084,10 @@ const actions = {
return new Promise(resolve => { return new Promise(resolve => {
var isReadingTaskViewInOrder = localStorage.getItem('isReadingTaskViewInOrder') var isReadingTaskViewInOrder = localStorage.getItem('isReadingTaskViewInOrder')
if (parseInt(isReadingTaskViewInOrder) === 2) { if (parseInt(isReadingTaskViewInOrder) === 2) {
if (!state.lastCanvasTaskId) state.lastCanvasTaskId = taskId if (!state.lastCanvasTaskId) {
console.log('setLastCanvasTaskId')
state.lastCanvasTaskId = taskId
}
} else { } else {
state.lastCanvasTaskId = taskId state.lastCanvasTaskId = taskId
} }

View File

@ -9,7 +9,7 @@ const getDefaultState = () => {
studyListQuery: null, studyListQuery: null,
unlock: false, unlock: false,
config: {}, config: {},
uploadTip: null, uploadTip: '0.00KB/s',
timer: null, timer: null,
whiteList: [], whiteList: [],
checkTaskId: null checkTaskId: null

View File

@ -1,14 +1,14 @@
import Vue from 'vue' import Vue from 'vue'
import { anonymization } from './anonymization' import { anonymization } from './anonymization'
export const dcmUpload = async function (name, file, config) { export const dcmUpload = async function (data, config, progressFn) {
return new Promise(async resolve => { return new Promise(async resolve => {
try { try {
// let blob = await encoder(file, config) // let blob = await encoder(file, config)
let blob = await fileToBlob(file) let blob = await fileToBlob(data.file)
if (config) { if (config) {
blob = await anonymization(file, config) blob = await anonymization(data.file, config)
} }
let res = await Vue.prototype.OSSclient.put(name, blob.blob) let res = await Vue.prototype.OSSclient.multipartUpload(Object.assign(data, { file: blob.blob }), progressFn)
resolve({ resolve({
...res, ...res,
image: blob.pixelDataElement image: blob.pixelDataElement
@ -19,7 +19,7 @@ export const dcmUpload = async function (name, file, config) {
} catch (e) { } catch (e) {
console.log(file, 'warning') console.log(data.file, 'warning')
resolve(false) resolve(false)
console.log(e) console.log(e)
} }

View File

@ -0,0 +1,457 @@
const {
CreateMultipartUploadCommand,
UploadPartCommand,
CompleteMultipartUploadCommand,
ListMultipartUploadsCommand,//bucket中正在上传的文件列表
ListPartsCommand,//列出文件已上传的分片
GetObjectCommand,//获取文件
} = require("@aws-sdk/client-s3");
import SparkMD5 from "./spark-md5.min.js";
import store from "@/store";
let timer = null, // 网速定时器
bytesReceivedPerSecond = {}; // 时间节点上传文件总量
export function AWSclose() {
if (timer) {
clearInterval(timer);
timer = null;
store.state.trials.uploadTip = '0KB/s'
}
bytesReceivedPerSecond = {};
}
//查询文件是否存在于bucket或者正在上传
export async function exist(s3, bucket, fileInformation, progressFn, changeStatus) {
// 拿到上传到的file
const File = fileInformation.file;
// 拿到上传的size
const uploadFileSize = File.size; // 这里拿到的单位是字节(uploadFileSize/ 1024 / 1024
// = 多少兆)
// 设置每一片的大小,shardSize 指定上传的每个分片的大小范围为100 KB~5 GB。
// 分片标准为5MB,文件总大小大于5GB分片为20MB
let shardSize = 5 * 1024 * 1024;
if (uploadFileSize < shardSize) {
shardSize = uploadFileSize;
}
if (uploadFileSize > 5 * 1024 * 1024 * 1024) {
shardSize = 20 * 1024 * 1024;
}
fileInformation = Object.assign({
shardSize,
sharding: []
}, fileInformation)
if (fileInformation.speed) {
setTimer();
}
// 1、查询该文件是否已上传到bucket
//判断sharding里面是否有东西有东西证明已经上传过分片了不需要再进行检测
if (fileInformation.sharding.length === 0) {
let existBucket = await existInBucket({ s3, bucket, fileInformation: fileInformation });
if (existBucket === 'true') {
progressFn(0, fileInformation.file, 1);
changeStatus(fileInformation.path, 'success');//直接告诉前端,状态
return;
} else if (existBucket === 'same key') {
console.log(fileInformation.path + " bucket中存在同名不同内容的文件");
} else if (existBucket === 'not exist') {
console.log(fileInformation.path + " bucket中不存在该文件");
}
//2、查询该文件是否存在上传事件
let upload = await existUpload({ s3, bucket: bucket, fileInformation: fileInformation });
if (upload.code === 0) {
//存在该上传事件并且已经上传了多个分片
console.log(fileInformation.path + " 存在上传事件,并已经上传多个分片");
//将分片存入sharding
const uploadId = upload.uploadId;
let parts = upload.parts;
let SIZE = 0;
for (let i = 0; i < parts.length; i++) {
SIZE += parts[i].Size;
fileInformation.sharding.push({ ETag: parts[i].ETag, PartNumber: parts[i].PartNumber, Size: parts[i].Size, UploadId: uploadId });
}
progressFn(SIZE / uploadFileSize, { fileSize: uploadFileSize }, 0);//告诉前端,加入分片
//重新上传
await uploadFile({ fileInformation: fileInformation, uploadId: uploadId, bucket, changeStatus, getSuspend, progressFn });
} else if (upload.code === 1) {
// //重名但是不同文件
console.log('err 重名文件')
changeStatus(fileInformation.path, 'same key');
} else if (upload.code === 2) {
//没有上传事件
console.log(fileInformation.path + " 不存在上传事件");
//建立分段上传事件
const connect = await createMultipartUpload({ s3, bucket: bucket, key: fileInformation.path, type: fileInformation.file.type });
//上传整个文件
await uploadFile({ s3, fileInformation: fileInformation, uploadId: connect.UploadId, bucket: bucket, changeStatus, progressFn });
}
} else {
//分片组里面有东西
//重新上传
await uploadFile({ s3, fileInformation: fileInformation, uploadId: fileInformation.sharding[0].UploadId, bucket, changeStatus, progressFn });
}
}
//上传文件未上传的所有分片
async function uploadFile({ s3, fileInformation, uploadId, bucket, changeStatus, progressFn }) {// file:上传文件, uploadId parts:已上传的分片
const chunkCount = Math.ceil(fileInformation.file.size / fileInformation.shardSize)//总分片数
//循环切片并上传
for (let i = 0; i < chunkCount; i++) {
let start = i * fileInformation.shardSize;//文件分片开始位置
let end = Math.min(fileInformation.file.size, start + fileInformation.shardSize)//文件分片结束位置
let _chunkFile = fileInformation.file.slice(start, end);//切片文件 即 待上传文件分片
//判断parts中是否存在该分片
let res1 = fileInformation.sharding.filter((part) => {
return part.PartNumber === (i + 1);
});
if (res1.length === 0) {
//不包含该分片
const upload = await uploadPart({ s3, f: _chunkFile, uploadId: uploadId, key: fileInformation.path, bucket: bucket, num: i + 1 });//将分片上传
//判断sharding中是否存在该分片如果不存在的话才判错
let res2 = fileInformation.sharding.filter((part) => {
return part.PartNumber === (i + 1);
});
if (res2.length === 0) {
if (upload !== 'err') {//上传分片成功,并且没有暂停上传
//判断是否存在该分片
//判断parts中是否存在该分片
let res3 = fileInformation.sharding.filter((part) => {
return part.PartNumber === (i + 1);
});
if (res3.length === 0) {
let LASTSIZE = fileInformation.sharding.reduce((sum, item) => sum + item.Size, 0)
fileInformation.sharding.push({ ETag: upload.ETag, PartNumber: i + 1, Size: _chunkFile.size, UploadId: uploadId });//上传成功存到sharding
let SIZE = fileInformation.sharding.reduce((sum, item) => sum + item.Size, 0)
let lastPercentage = LASTSIZE / fileInformation.file.size, percentage = SIZE / fileInformation.file.size;
progressFn(percentage, fileInformation.file, lastPercentage);
if (fileInformation.speed) {
let time = new Date().getTime();
let timeList = Object.keys(bytesReceivedPerSecond).sort((a, b) => a - b);
let bytesTime = timeList.find(item => time - item < 1000);
if (bytesTime) {
bytesReceivedPerSecond[bytesTime] += fileInformation.file.size * (percentage - lastPercentage);
} else {
console.log("未查询到时间")
if (timeList.length > 0) {
bytesReceivedPerSecond[timeList[timeList.length - 1]] += fileInformation.file.size * (percentage - lastPercentage);
} else {
bytesReceivedPerSecond[time] = fileInformation.file.size * (percentage - lastPercentage);
}
}
}
}
} else if (upload === 'err') {
changeStatus(fileInformation.path, 'err');
return;
}
}
}
}//for
if (fileInformation.sharding.length === chunkCount) {
//合并分片
const complete = await completeMultipartUpload({ s3, bucket: bucket, key: fileInformation.path, sharding: fileInformation.sharding, uploadId: uploadId });
if (complete !== 'err') {
changeStatus(fileInformation.path, 'success');//通知前端,上传成功
} else {
changeStatus(fileInformation.path, 'err');//通知前端,上传失败
}
}
}
// 判断该文件是否已经存在于bucket
// bucket file:上传文件
// 返回值 'same key':同名不同文件 'not exist':不存在该文件 'true':该文件已存在bucket中
async function existInBucket({ s3, bucket, fileInformation }) {
if (s3 === null) {
return console.log("未创建s3客户端请先调用init事件");
}
//getObject 每次最多传回767448b的数据所以要分段请求
let bucketFileUniArray = [];
// 分段
let count = Math.ceil(fileInformation.file.size / 767448);
if (count > 4) {
count = 4;
}
for (let i = 0; i < count; i++) {
const obj = await getObject({ s3, bucket: bucket, fileInformation: fileInformation, count: i });
if (obj !== 'err') {
//获取文件的文件体 计算某个分片的md5
const fileBody = obj.Body;
let fileUnitArray = await fileBody.transformToByteArray();
bucketFileUniArray = [...bucketFileUniArray, ...fileUnitArray];
} else {
return 'not exist';
}
}
let bucketFileBufferArray = new Uint8Array(bucketFileUniArray);
// 将传入文件的fileReader 转成 arrayBuffer
let fileArrayBuff = null;
fileArrayBuff = await new Promise((resolve) => {
let fileReader = new FileReader();
fileReader.readAsArrayBuffer(fileInformation.file.slice(0, count * 767448));
fileReader.onload = (e) => {
resolve(e.target.result);
};
});
if (fileArrayBuff.byteLength > count * 767448) {
fileArrayBuff = fileArrayBuff.slice(0, count * 767448);
}
let bodyMD5 = await getMD5({ arrayBuffer: bucketFileBufferArray.buffer });
let fileMD5 = await getMD5({ arrayBuffer: fileArrayBuff });
if (bodyMD5 === fileMD5) {
//证明是同一个文件 秒传
return 'true';
} else {
return 'same key';
}
}
//判断该文件是否正在上传
// bucket:bucket file:上传文件
//返回值 'not exist upload':不存在上传事件 'same key':同名不同文件
async function existUpload({ s3, bucket, fileInformation }) {
//判断该文件是否有上传事件
const listUploads = await listMultipartUploadsCommand({ s3, bucket: bucket, key: fileInformation.path });
if (listUploads !== 'err') {
if (listUploads.Uploads !== undefined && listUploads.Uploads.length > 0) {
//存在上传事件 获取上传的第一个分片的eTag计算传入文件md5相比较是否相同
const uploads = listUploads.Uploads;
for (const one in uploads) {//可能存在多个连接
let uploadOne = uploads[one];
const uploadId = uploadOne.UploadId;//UploadId
const key = uploadOne.Key;//key
//查询该文件已上传分片
const listParts = await listPartsCommand({ s3, bucket: bucket, key: key, uploadId: uploadId });
if (listParts !== 'err') {
if (listParts.Parts !== undefined && listParts.Parts.length !== 0) {
//存在分片
let etag = listParts.Parts[0].ETag;
//计算文件的第一个分片的md5
let fileSlice = null;
if (fileInformation.file.size > fileInformation.shardSize) {
fileSlice = fileInformation.file.slice(0, fileInformation.shardSize);
} else {
fileSlice = fileInformation.file;
}
let fileMD5 = await new Promise((resolve) => {
const fileReader = new FileReader();
var spark = new SparkMD5.ArrayBuffer();
fileReader.readAsArrayBuffer(fileSlice);
fileReader.onload = (e) => {
spark.append(e.target.result);
var m = spark.end();
resolve(m);
};
});
if (etag.split('"')[1] === fileMD5) {
//是同一个文件上传
return {
code: 0,
message: 'true',
uploadId: uploadId,
key: key,
parts: listParts.Parts
}
} else {
//同名不同文件
continue;
}
} else {
//该文件有进行上传,但没有上传完成一个分片
continue;
}
} else {
//有连接,没上传分片
continue;
}
}//for
return {
code: 1,
message: 'same key'
}
} else {
//无连接
return {
code: 2,
message: 'not exist upload'
};
}
} else {
//无连接
return {
code: 2,
message: 'not exist upload'
};
}
}
//计算arrayBuffer的md5值
async function getMD5({ arrayBuffer }) {
return await new Promise((resolve) => {
const spark = new SparkMD5.ArrayBuffer();
spark.append(arrayBuffer);
const m = spark.end();
resolve(m);
});
}
//建立文件上传事件
async function createMultipartUpload({ s3, bucket, key, type }) {//bucket:bucket key:文件名 type文件类型
if (s3 === null) {
return console.log("未创建s3客户端请先调用init事件");
}
const params = {
Bucket: bucket,
Key: key,
ContentType: type
};
const res = async () => {
try {
return await s3.send(new CreateMultipartUploadCommand(params));
} catch (err) {
console.log('建立上传事件失败:', err.message)
return 'err';
}
}
return res();
}
//上传一个分片
async function uploadPart({ s3, f, uploadId, key, bucket, num }) { //f:文件分片num分片标号
if (s3 === null) {
return console.log("未创建s3客户端请先调用init事件");
}
const params = {
Bucket: bucket,
Key: key,
PartNumber: num,
UploadId: uploadId,
Body: f,
// ContentDisposition: "attachment; filename=hahaha.dcm"
};
const res = async () => {
try {
return await s3.send(new UploadPartCommand(params));
} catch (err) {
console.log('上传分片第 ' + num + ' 片错误信息', err.message)
return 'err';
}
}
return res();
}
//将分片合并
async function completeMultipartUpload({ s3, bucket, key, sharding, uploadId }) {
if (s3 === null) {
return console.log("未创建s3客户端请先调用init事件");
}
let parts = [];
for (let i = 0; i < sharding.length; i++) {
parts.push({
"ETag": sharding[i].ETag,
"PartNumber": sharding[i].PartNumber,
})
}
const params = {
Bucket: bucket,
Key: key,
MultipartUpload: {
Parts: parts
},
UploadId: uploadId
};
const res = async () => {
try {
return await s3.send(new CompleteMultipartUploadCommand(params))
} catch (err) {
console.log("合并分片失败: ", err.message);
return 'err';
}
}
return res();
}
//查询某个文件已经上传的所有分片
async function listPartsCommand({ s3, bucket, key, uploadId }) {
if (s3 === null) {
return console.log("未创建s3客户端请先调用init事件");
}
const params = {
Bucket: bucket,
Key: key,
UploadId: uploadId
};
const res = async () => {
try {
return await s3.send(new ListPartsCommand(params));
} catch (err) {
console.log("查询该文件已上传分片失败: " + err.message);
return 'err';
}
}
return res();
}
//查询该文件是否存在上传事件
async function listMultipartUploadsCommand({ s3, bucket, key }) {
if (s3 === null) {
return console.log("未创建s3客户端请先调用init事件");
}
const params = {
Bucket: bucket,
Delimiter: '',
MaxUploads: 1000,
Prefix: key
};
const res = async () => {
try {
return await s3.send(new ListMultipartUploadsCommand(params));
} catch (err) {
console.log("查询 " + key + " 文件是否存在上传事件失败: " + err.message);
return 'err';
}
}
return res();
}
//获取文件
async function getObject({ s3, bucket, fileInformation, count }) {
//一次请求最多 767448
if (s3 === null) {
return console.log("未创建s3客户端请先调用init事件");
}
let byte1 = ((count + 1) * 767448 - 1) > fileInformation.file.size ? fileInformation.file.size : ((count + 1) * 767448 - 1);
let byte2 = (count * 767448) > fileInformation.file.size ? fileInformation.file.size : (count * 767448);
let range = "bytes=" + byte2 + "-" + byte1;
const params = {
Bucket: bucket,
Key: fileInformation.path,
Range: range
};
const res = async () => {
try {
return await s3.send(new GetObjectCommand(params));
} catch (err) {
console.log('获取 ' + fileInformation.path + ' 文件失败:', err.message);
return 'err';
}
}
return res();
}
function setTimer() {
if (timer) return false;
timer = setInterval(() => {
let timeList = Object.keys(bytesReceivedPerSecond).sort((a, b) => a - b);
if (timeList.length > 0) {
let totalBytes = timeList.reduce((sum, bytes) => sum + bytesReceivedPerSecond[bytes], 0) / (5 * 1024);
let unit = 'KB/s';
if (totalBytes > 1024) {
totalBytes = totalBytes / 1024;
unit = "MB/s";
}
store.state.trials.uploadTip = totalBytes.toFixed(2) + unit;
}
if (timeList.length >= 5) {
delete bytesReceivedPerSecond[timeList[0]]
}
let time = new Date().getTime();
bytesReceivedPerSecond[time] = 0;
}, 1000)
}

View File

@ -0,0 +1,156 @@
import moment from "moment";
import store from "@/store";
let savaData = {},
checkData = {}, // 当前上传的节点文件和上一次提交进度
timer = null, // 网速定时器
bytesReceivedPerSecond = {}; // 时间节点上传文件总量
export function OSSclose() {
if (timer) {
clearInterval(timer);
timer = null;
store.state.trials.uploadTip = '0KB/s'
}
bytesReceivedPerSecond = {};
savaData = {};
checkData = {};
saveFinishedData(savaData);
}
export async function customerHttp(OSSclient, data, progressFn) {
// 拿到上传到的file
const uploadFile = data.file;
// 拿到上传的size
const uploadFileSize = uploadFile.size; // 这里拿到的单位是字节(uploadFileSize/ 1024 / 1024
// = 多少兆)
// 设置每一片的大小,partSize 指定上传的每个分片的大小范围为100 KB~5 GB。
// 分片标准为5MB,文件总大小大于5GB分片为20MB
let partSize = 5 * 1024 * 1024;
if (uploadFileSize < partSize) {
partSize = uploadFileSize;
}
if (uploadFileSize > 5 * 1024 * 1024 * 1024) {
partSize = 20 * 1024 * 1024;
}
// 设置所有的文件上传所有的唯一的saveFileId
const saveFileId = `${uploadFileSize}_${data.path}`;
if (data.speed) {
setTimer();
}
initPage();
let res = await multipartUpload(OSSclient, partSize, saveFileId, uploadFile, data, progressFn);
return res;
}
async function multipartUpload(OSSclient, partSize, saveFileId, uploadFile, data, progressFn) {
try {
// object-name目前我是用的uploadFile.name,其实也是要根据你们的项目而定,
// 有没有具体的规定, 要不要加项目名, 要不要加对应的环境;
// 上传的参数
const uploadParams = {
partSize,
progress: (percentage, checkpoint) => {
savaData[saveFileId] = checkpoint;
if (!checkData[saveFileId]) {
checkData[saveFileId] = 0
}
if (data.speed) {
let time = new Date().getTime();
let timeList = Object.keys(bytesReceivedPerSecond).sort((a, b) => a - b);
let bytesTime = timeList.find(item => time - item < 1000);
if (bytesTime) {
bytesReceivedPerSecond[bytesTime] += data.file.size * (percentage - checkData[saveFileId]);
} else {
// console.log("未查询到时间")
if (timeList.length > 0) {
bytesReceivedPerSecond[timeList[timeList.length - 1]] += data.file.size * (percentage - checkData[saveFileId]);
} else {
bytesReceivedPerSecond[time] = data.file.size * (percentage - checkData[saveFileId]);
}
}
}
savaData["lastSaveTime"] = new Date();
progressFn(percentage, data.file, checkData[saveFileId])
checkData[saveFileId] = percentage;
if (percentage === 1) {
delete checkData[saveFileId]
}
// 在上传过程中,把已经上传的数据存储下来
saveFinishedData(savaData);
},
// headers: {
// "Content-Disposition": `attachment; filename=hahaha.dcm`,
// "Cache-Control": "public, no-cache"
// }
};
// 断点续传
await resumeUpload(uploadParams, saveFileId);
const res = await OSSclient.multipartUpload(
data.path,
uploadFile,
uploadParams
);
if (res.res.status === 200) {
// 重新去掉某个缓存进行设置
delete savaData[saveFileId];
saveFinishedData(savaData);
}
return res;
} catch (e) {
console.log(e);
// 捕获超时异常。
if (e.code === "ConnectionTimeoutError") {
console.log("TimeoutError");
// do ConnectionTimeoutError operation
}
return false;
}
}
async function resumeUpload(uploadParams, saveFileId) {
if (localStorage.getItem("upload-function-name")) {
const obj = JSON.parse(localStorage.getItem("upload-function-name"));
if (Object.keys(obj).includes(saveFileId)) {
uploadParams.checkpoint = obj[saveFileId];
}
}
}
// 存储到内存
function saveFinishedData(finishedData) {
localStorage.setItem(
"upload-function-name",
JSON.stringify(finishedData)
);
}
function initPage() {
// 判断是不是有缓存
const localData = localStorage.getItem("upload-function-name");
if (!localData) return;
savaData = JSON.parse(localData);
// 当前时间 > 存储时间(1000 * 60 * 60表示1h,意思就是这些数据你要存多久,
// 可以是1h也可以是多少天,随意)
if (
moment(new Date()).diff(moment(savaData.lastSaveTime)) >
1000 * 60 * 60
) {
localStorage.removeItem("upload-function-name");
}
}
function setTimer() {
if (timer) return false;
timer = setInterval(() => {
// console.log(Object.assign({}, bytesReceivedPerSecond))
let timeList = Object.keys(bytesReceivedPerSecond).sort((a, b) => a - b);
if (timeList.length > 0) {
let totalBytes = timeList.reduce((sum, bytes) => sum + bytesReceivedPerSecond[bytes], 0) / (5 * 1024);
let unit = 'KB/s';
if (totalBytes > 1024) {
totalBytes = totalBytes / 1024;
unit = "MB/s";
}
store.state.trials.uploadTip = totalBytes.toFixed(2) + unit;
}
if (timeList.length >= 5) {
delete bytesReceivedPerSecond[timeList[0]]
}
let time = new Date().getTime();
bytesReceivedPerSecond[time] = 0;
}, 1000)
}

File diff suppressed because one or more lines are too long

View File

@ -3,30 +3,32 @@ const router = require('@/router');
const Minio = require('minio') const Minio = require('minio')
const stream = require('stream') const stream = require('stream')
import Vue from 'vue' import Vue from 'vue'
import { customerHttp, OSSclose } from "@/utils/multipartUpload/oss"
import { exist, AWSclose } from "@/utils/multipartUpload/aws"
const { GetObjectStoreToken } = require('../api/user.js') const { GetObjectStoreToken } = require('../api/user.js')
const {
S3Client,
} = require("@aws-sdk/client-s3");
Vue.prototype.OSSclientConfig = { Vue.prototype.OSSclientConfig = {
} }
function blobToBuffer(blob, fileName) {
return new Promise((resolve, reject) => {
const file = new File([blob], fileName);
resolve(file)
})
}
async function ossGenerateSTS() { async function ossGenerateSTS() {
let res = await GetObjectStoreToken() let res = await GetObjectStoreToken()
// 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;
Vue.prototype.OSSclientConfig.basePath = Vue.prototype.OSSclientConfig.viewEndpoint Vue.prototype.OSSclientConfig.basePath = Vue.prototype.OSSclientConfig.viewEndpoint
switch (res.Result.ObjectStoreUse) { switch (res.Result.ObjectStoreUse) {
case 'AliyunOSS': case 'AliyunOSS':
Vue.prototype.OSSclientConfig.bucket = Vue.prototype.OSSclientConfig.bucketName Vue.prototype.OSSclientConfig.bucket = Vue.prototype.OSSclientConfig.bucketName
Vue.prototype.OSSclientConfig.stsToken = Vue.prototype.OSSclientConfig.securityToken
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: function (objectName, object) { put: async function (objectName, object) {
OSSclient = await RefreshClient(OSSclient)
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
let _vm = router.default.app let _vm = router.default.app
@ -49,6 +51,46 @@ async function ossGenerateSTS() {
reject() reject()
} }
}) })
},
multipartUpload: async (data, progress) => {
OSSclient = await RefreshClient(OSSclient)
return new Promise(async (resolve, reject) => {
try {
const { file, path } = data;
if (!file || !path) return reject('file and path be required');
let config = await getSTSToken(Vue.prototype.OSSclientConfig.expiration);
if (config) {
Vue.prototype.OSSclientConfig = { ...config.Result[config.Result.ObjectStoreUse] }
Vue.prototype.OSSclientConfig.ObjectStoreUse = config.Result.ObjectStoreUse;
Vue.prototype.OSSclientConfig.basePath = Vue.prototype.OSSclientConfig.viewEndpoint;
Vue.prototype.OSSclientConfig.bucket = Vue.prototype.OSSclientConfig.bucketName
Vue.prototype.OSSclientConfig.stsToken = Vue.prototype.OSSclientConfig.securityToken
Vue.prototype.OSSclientConfig.timeout = 10 * 60 * 1000
OSSclient = new OSS(Vue.prototype.OSSclientConfig);
}
let _vm = router.default.app
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload') {
var objectItem = data.path.split('/')
objectItem[objectItem.length - 1] = new Date().getTime() + '_' + objectItem[objectItem.length - 1]
data.path = objectItem.join('/')
}
let res = await customerHttp(OSSclient, data, progress);
if (res) {
resolve({
name: data.path,
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(res.name)
})
} else {
reject()
}
} catch (err) {
console.log(err)
reject(err)
}
})
},
close: () => {
OSSclose();
} }
} }
break break
@ -86,49 +128,118 @@ async function ossGenerateSTS() {
console.log(e) console.log(e)
} }
}) })
},
close: () => {
return false
} }
} }
break break
case 'AWS': case 'AWS':
let aws = new Minio.Client(Vue.prototype.OSSclientConfig); Vue.prototype.OSSclientConfig.bucket = Vue.prototype.OSSclientConfig.bucketName
let aws = new S3Client({
endpoint: Vue.prototype.OSSclientConfig.viewEndpoint,
region: Vue.prototype.OSSclientConfig.region,
s3ForcePathStyle: true,
signatureVersion: 'v4',
forcePathStyle: true,
// SessionToken: '',
credentials: {
accessKeyId: Vue.prototype.OSSclientConfig.accessKeyId,
secretAccessKey: Vue.prototype.OSSclientConfig.secretAccessKey,
sessionToken: Vue.prototype.OSSclientConfig.sessionToken
}
});
Vue.prototype.OSSclient = { Vue.prototype.OSSclient = {
put: function (objectName, object) { put: async function (objectName, object) {
return new Promise(async (resolve, reject) => { let data = {
try { file: object,
var name = objectName.split('/')[objectName.split('/').length - 1] path: objectName
let _vm = router.default.app }
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload') { aws = await RefreshClient(aws);
var objectItem = objectName.split('/') return uploadAWS(aws, data, () => { });
objectItem[objectItem.length - 1] = new Date().getTime() + '_' + objectItem[objectItem.length - 1] },
objectName = objectItem.join('/') multipartUpload: async (data, progress) => {
} aws = await RefreshClient(aws);
const reader = new FileReader(); return uploadAWS(aws, data, progress);
reader.onload = (ex) => { },
const bufferStream = new stream.PassThrough() close: () => {
bufferStream.end(Buffer.from(ex.target.result)) AWSclose();
aws.putObject(Vue.prototype.OSSclientConfig.bucketName, objectName, bufferStream, function (err, etag) {
if (err) {
console.log(err)
reject()
} else {
console.log(objectName);
resolve({
name: objectName,
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(objectName)
})
}
})
};
reader.readAsArrayBuffer(object);
} catch (e) {
console.log(e)
}
})
} }
} }
} }
return return
} }
// AWS上传函数
function uploadAWS(aws, data, progress) {
return new Promise(async (resolve, reject) => {
try {
const { file, path } = data;
if (!file || !path) return reject('file and path be required');
let _vm = router.default.app
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload') {
var objectItem = data.path.split('/')
objectItem[objectItem.length - 1] = new Date().getTime() + '_' + objectItem[objectItem.length - 1]
data.path = objectItem.join('/')
}
await exist(aws, Vue.prototype.OSSclientConfig.bucket, data, progress, (path, status) => {
if (status === 'success') {
resolve({
name: Vue.prototype.OSSclientConfig.bucket + "/" + decodeUtf8(path),
url: Vue.prototype.OSSclientConfig.viewEndpoint + Vue.prototype.OSSclientConfig.bucket + "/" + decodeUtf8(path)
})
} else {
reject()
}
});
} catch (err) {
console.log(err)
reject(err)
}
})
}
// client过期刷新
async function RefreshClient(client) {
let config = await getSTSToken(Vue.prototype.OSSclientConfig.expiration);
if (config) {
// config.Result.ObjectStoreUse = 'AWS'
switch (config.Result.ObjectStoreUse) {
case 'AliyunOSS': {
Vue.prototype.OSSclientConfig = { ...config.Result[config.Result.ObjectStoreUse] }
Vue.prototype.OSSclientConfig.ObjectStoreUse = config.Result.ObjectStoreUse;
Vue.prototype.OSSclientConfig.basePath = Vue.prototype.OSSclientConfig.viewEndpoint;
Vue.prototype.OSSclientConfig.bucket = Vue.prototype.OSSclientConfig.bucketName
Vue.prototype.OSSclientConfig.stsToken = Vue.prototype.OSSclientConfig.securityToken
Vue.prototype.OSSclientConfig.timeout = 10 * 60 * 1000
return new OSS(Vue.prototype.OSSclientConfig);
}
case "MinIO": {
return client;
}
case "AWS": {
Vue.prototype.OSSclientConfig = { ...config.Result[config.Result.ObjectStoreUse] }
Vue.prototype.OSSclientConfig.ObjectStoreUse = config.Result.ObjectStoreUse;
Vue.prototype.OSSclientConfig.basePath = Vue.prototype.OSSclientConfig.viewEndpoint;
Vue.prototype.OSSclientConfig.bucket = Vue.prototype.OSSclientConfig.bucketName
return new S3Client({
endpoint: Vue.prototype.OSSclientConfig.viewEndpoint,
region: Vue.prototype.OSSclientConfig.region,
s3ForcePathStyle: true,
signatureVersion: 'v4',
forcePathStyle: true,
credentials: {
accessKeyId: Vue.prototype.OSSclientConfig.accessKeyId,
secretAccessKey: Vue.prototype.OSSclientConfig.secretAccessKey,
sessionToken: Vue.prototype.OSSclientConfig.sessionToken
}
});
}
}
} else {
return client;
}
}
function decodeUtf8(bytes) { function decodeUtf8(bytes) {
let str = bytes.split('?'); let str = bytes.split('?');
let str2 = str[0].split('/'); let str2 = str[0].split('/');
@ -138,6 +249,47 @@ function decodeUtf8(bytes) {
str2.pop(); str2.pop();
return str2.join("/") + '/' + name; return str2.join("/") + '/' + name;
} }
const queue = []
let loading = false;
// 获取凭证
function getSTSToken(credentials) {
return new Promise(async (resolve, reject) => {
let isExpired = isCredentialsExpired(credentials);
if (isExpired) {
if (loading) {
queue.push({ resolve, reject })
}
if (!loading) {
loading = true;
let res = await GetObjectStoreToken();
loading = false;
resolve(res)
let p = queue.shift();
while (p) {
p.resolve(res)
p = queue.shift();
}
}
} else {
// console.log("凭证未过期");
resolve(false)
}
})
}
/**
* oss判断临时凭证是否到期
**/
function isCredentialsExpired(credentials) {
if (!credentials) {
return true;
}
const expireDate = new Date(credentials);
const now = new Date();
// 如果有效期不足五分钟,视为过期。
return expireDate.getTime() - now.getTime() <= 300000;
}
export const OSSclient = ossGenerateSTS export const OSSclient = ossGenerateSTS

View File

@ -2,7 +2,7 @@ import axios from 'axios'
import { Message, MessageBox, Alert } from 'element-ui' import { Message, MessageBox, Alert } from 'element-ui'
import store from '@/store' import store from '@/store'
import router from '@/router' import router from '@/router'
import Vue from 'vue' import WHITELIST from "./whiteList"
import moment from 'moment-timezone'; import moment from 'moment-timezone';
console.log(moment.tz.guess()) console.log(moment.tz.guess())
axios.defaults.withCredentials = false axios.defaults.withCredentials = false
@ -27,7 +27,10 @@ service.interceptors.request.use(
} }
try { try {
if (eval(process.env.VUE_APP_LOGIN_FOR_PERMISSION)) { if (eval(process.env.VUE_APP_LOGIN_FOR_PERMISSION)) {
if (!path || path === '/ReviewersResearchForm' || path === '/ReviewersResearch' || path === '/login' || path === '/researchForm' || path === '/researchDetail_m' || path === '/researchLogin_m' || path === '/researchLogin' || path === '/email-recompose' || path === '/recompose' || path === '/resetpassword' || path === '/error') { // if (!path || path === '/ReviewersResearchForm' || path === '/ReviewersResearch' || path === '/login' || path === '/researchForm' || path === '/researchDetail_m' || path === '/researchLogin_m' || path === '/researchLogin' || path === '/email-recompose' || path === '/recompose' || path === '/resetpassword' || path === '/error') {
// return config
// }
if (!path || WHITELIST.some(item => item === path)) {
return config return config
} }
if (store.state.user.userId !== zzSessionStorage.getItem('userId')) { if (store.state.user.userId !== zzSessionStorage.getItem('userId')) {

85
src/utils/stream.js Normal file
View File

@ -0,0 +1,85 @@
import streamSaver from "streamsaver";
import "streamsaver/examples/zip-stream.js";
import store from '@/store'
streamSaver.mitm = `${window.location.origin}/mitm.html?version=2.0.0`
// 下载文件并压缩
function zipFiles(zipName, files) {
console.log("同步下载打包开始时间:" + new Date());
store.dispatch('trials/setUnLock', true)
files = formatFiles(files)
// 创建压缩文件输出流
const zipFileOutputStream = streamSaver.createWriteStream(zipName);
// 创建下载文件流
const fileIterator = files.values();
const readableZipStream = new ZIP({
async pull(ctrl) {
const fileInfo = fileIterator.next();
if (fileInfo.done) {//迭代终止
ctrl.close();
} else {
let { name, url } = fileInfo.value;
url = decodeUtf8(url);
return fetch(url).then(res => {
ctrl.enqueue({
name,
stream: () => res.body
});
})
}
}
});
if (window.WritableStream && readableZipStream.pipeTo) {
// 开始下载
readableZipStream
.pipeTo(zipFileOutputStream)
.then(() => {
console.log("同步下载打包结束时间:" + new Date());
store.dispatch('trials/setUnLock', false)
});
}
}
// 下载文件并修改名称
async function updateFile(file, name) {
try {
store.dispatch('trials/setUnLock', true)
const fileOutputStream = streamSaver.createWriteStream(name);
file = decodeUtf8(file);
let res = await fetch(file);
res.body.pipeTo(fileOutputStream).then(() => {
store.dispatch('trials/setUnLock', true)
});
} catch (err) {
console.log(err)
}
}
// 同名文件修改名称
function formatFiles(files) {
let fileObj = {};
files.forEach(file => {
let arr = Object.keys(fileObj);
if (!~arr.indexOf(file.name)) {
fileObj[file.name] = 1;
} else {
let name = file.name;
file.name = name.split(".")[0] + `(${fileObj[name]})` + name
.substring(name.lastIndexOf('.'))
.toLocaleLowerCase()
fileObj[name]++;
}
})
return files;
}
function decodeUtf8(bytes) {
let str = bytes.split('?');
let str2 = str[0].split('/');
let name = str2[str2.length - 1];
name = encodeURIComponent(name);
str.shift();
str2.pop();
return str2.join("/") + '/' + name;
}
export function downLoadFile(file, name, type = 'file') {
if (type === 'zip') return zipFiles(name, file);
return updateFile(file, name)
}

View File

@ -1,168 +0,0 @@
import Vue from 'vue';
import store from "@/store";
import {
requestPackageAndAnonymizImage,
} from "@/api/load.js";
import streamSaver from "streamsaver";
import "streamsaver/examples/zip-stream.js"
let flag = {};
export const resetFlag = () => {
flag = {};
store.state.trials.uploadTip = null;
if (store.state.trials.timer) {
clearInterval(store.state.trials.timer);
store.state.trials.timer = null;
}
store.dispatch("trials/setUnLock", false);
}
export const downloadImage = async (id, id2, IsDicom = true) => {
// if (flag[`${id2}_${IsDicom}`]) return Vue.prototype.$message.warning(Vue.prototype.$t('trials:upload:tip:uploading'));
if (flag[`${id2}_${IsDicom}`]) return false;
flag[`${id2}_${IsDicom}`] = true
try {
let params = {
TrialId: id,
SubjectVisitId: id2,
IsDicom: IsDicom
}
store.dispatch("trials/setUnLock", true);
let res = await requestPackageAndAnonymizImage(params);
if (res.IsSuccess) {
if (!res.Result) {
flag[`${id2}_${IsDicom}`] = false;
// Vue.prototype.$message.warning(Vue.prototype.$t("trials:upload:message:not"))
let message = Vue.prototype.$t('trials:upload:tip:uploading').replace("xxx", res.OtherInfo.FileName);
store.state.trials.uploadTip = message;
if (!store.state.trials.timer) {
store.state.trials.timer = setInterval(() => {
downloadImage(id, id2, IsDicom);
}, 2000);
}
return false;
}
if (store.state.trials.timer) {
clearInterval(store.state.trials.timer);
store.state.trials.timer = null;
}
let fileName = res.Result.split("/").pop();
let href = Vue.prototype.OSSclientConfig.basePath + res.Result;
if (fileName !== res.OtherInfo.FileName) {
let message = Vue.prototype.$t('trials:upload:tip:uploading').replace("xxx", res.OtherInfo.FileName);
store.state.trials.uploadTip = message;
// Vue.prototype.$message.success(Vue.prototype.$t("trials:upload:message:startUpload"));
return download(href, res.OtherInfo.FileName, { id2, IsDicom });
}
let a = document.createElement("a");
a.download = res.OtherInfo.FileName;
a.href = href;
a.click();
URL.revokeObjectURL(href);
let timer = setTimeout(() => {
a = null;
href = null;
timer = null;
}, 500)
store.state.trials.uploadTip = null;
return true;
} else {
flag[`${id2}_${IsDicom}`] = false;
return false;
}
} catch (err) {
flag[`${id2}_${IsDicom}`] = false;
console.log(err);
}
};
export const fileDownload = (content, filename) => {
const eleLink = document.createElement("a");
eleLink.download = filename;
eleLink.style.display = "none";
const blob = new Blob([content]);
eleLink.href = URL.createObjectURL(blob);
document.body.appendChild(eleLink);
eleLink.click();
document.body.removeChild(eleLink);
};
let download = async (downloadUrl, downloadFileName, res) => {
const blob = await getBlob(downloadUrl);
flag[`${res.id2}_${res.IsDicom}`] = false;
store.state.trials.uploadTip = null;
store.dispatch("trials/setUnLock", false);
saveAsB(blob, downloadFileName);
return true;
}
let getBlob = (url) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = () => {
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(new Error(`Request failed with status ${xhr.status}`));
}
};
xhr.onerror = () => {
reject(new Error('Request failed'));
};
xhr.send();
});
}
let saveAsB = (blob, filename) => {
const link = document.createElement('a');
const body = document.body;
link.href = window.URL.createObjectURL(blob);
link.download = filename;
// hide the link
link.style.display = 'none';
body.appendChild(link);
link.click();
body.removeChild(link);
window.URL.revokeObjectURL(link.href);
}
// 前端流式打包下载
const handleBatchDown = async (item, zip) => {
return new Promise((resolve) => {
console.log("同步下载打包开始时间:" + new Date());
// 创建压缩文件输出流
const zipFileOutputStream = streamSaver.createWriteStream(zipName);
// 创建下载文件流
const fileIterator = files.values();
const readableZipStream = new window.ZIP({
async pull(ctrl) {
const fileInfo = fileIterator.next();
if (fileInfo.done) {//迭代终止
ctrl.close();
} else {
const { name, url } = fileInfo.value;
return fetch(url).then(res => {
ctrl.enqueue({
name,
stream: () => res.body
})
})
}
}
});
if (window.WritableStream && readableZipStream.pipeTo) {
// 开始下载
readableZipStream
.pipeTo(zipFileOutputStream)
.then(() => { console.log("同步下载打包结束时间:" + new Date()); resolve(true) })
} else {
resolve(false);
}
})
};

2
src/utils/whiteList.js Normal file
View File

@ -0,0 +1,2 @@
const WHITELIST = ['/', '/ReviewersResearch', '/login', '/error', '/resetpassword', '/recompose', '/email-recompose', '/trialStats', '/showdicom', '/imagesShare', '/audit', '/preview', '/researchLogin', '/researchLogin_m', '/blindResumeInfo', '/trialsResume', '/joinVerify', '/showNoneDicoms', '/noneDicomReading', '/clinicalData', '/readingDicoms', '/readingPage', '/visitDicomReview', '/visitNondicomReview', '/globalReview', '/adReview', '/oncologyReview', '/nonedicoms']
export default WHITELIST

View File

@ -6,7 +6,7 @@
<div class="sidePanelThumbs"> <div class="sidePanelThumbs">
<el-tabs v-model="activeName" type="border-card" @tab-click="handleTabClick"> <el-tabs v-model="activeName" type="border-card" @tab-click="handleTabClick">
<el-tab-pane :label="$t('trials:dicom-show:currentVisit')" name="current-study"> <el-tab-pane :label="$t('trials:dicom-show:currentVisit')" name="current-study">
<div class="text-desc" style="background:rgb(55 55 55);"> <div v-if="visitInfo" class="text-desc" style="background:rgb(55 55 55);">
{{ visitInfo }} {{ visitInfo }}
</div> </div>
<div class="viewerSidethumbs ps" style="position: relative;"> <div class="viewerSidethumbs ps" style="position: relative;">
@ -261,6 +261,7 @@ import * as cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
import dicomViewer from '@/components/Dicom/DicomViewer' import dicomViewer from '@/components/Dicom/DicomViewer'
import { getVisitStudyList, getAllRelationStudyList, getSeriesList } from '@/api/reading' import { getVisitStudyList, getAllRelationStudyList, getSeriesList } from '@/api/reading'
import { setSeriesStatus } from '@/api/trials' import { setSeriesStatus } from '@/api/trials'
import { getTaskUploadedDicomStudyList } from '@/api/reading'
import requestPoolManager from '@/utils/request-pool' import requestPoolManager from '@/utils/request-pool'
import store from '@/store' import store from '@/store'
import { changeURLStatic } from '@/utils/history.js' import { changeURLStatic } from '@/utils/history.js'
@ -301,7 +302,8 @@ export default {
relationActiveName: [], relationActiveName: [],
showSeriesList: [], showSeriesList: [],
currentLoadIns: [], currentLoadIns: [],
isFromCRCUpload: false isFromCRCUpload: false,
visitTaskId: null
} }
}, },
mounted() { mounted() {
@ -318,6 +320,7 @@ export default {
this.isReading = this.$router.currentRoute.query.isReading ? this.$router.currentRoute.query.isReading * 1 : 0 this.isReading = this.$router.currentRoute.query.isReading ? this.$router.currentRoute.query.isReading * 1 : 0
this.showDelete = parseInt(this.$router.currentRoute.query.showDelete) this.showDelete = parseInt(this.$router.currentRoute.query.showDelete)
this.isFromCRCUpload = !!this.$router.currentRoute.query.isFromCRCUpload this.isFromCRCUpload = !!this.$router.currentRoute.query.isFromCRCUpload
this.visitTaskId = this.$router.currentRoute.query.visitTaskId
// cornerstone.events.addEventListener('cornerstoneimageloaded', this.cornerstoneImageLoaded) // cornerstone.events.addEventListener('cornerstoneimageloaded', this.cornerstoneImageLoaded)
this.getStudiesInfo() this.getStudiesInfo()
cornerstone.events.addEventListener('cornerstoneimageloadprogress', this.cornerstoneimageloadprogress) cornerstone.events.addEventListener('cornerstoneimageloadprogress', this.cornerstoneimageloadprogress)
@ -338,7 +341,12 @@ export default {
async getStudiesInfo() { async getStudiesInfo() {
this.studyList = [] this.studyList = []
try { try {
const res = await getVisitStudyList(this.trialId, this.subjectVisitId, this.isReading) let res = null
if (this.visitTaskId) {
res = await getTaskUploadedDicomStudyList({ visitTaskId: this.visitTaskId })
} else {
res = await getVisitStudyList(this.trialId, this.subjectVisitId, this.isReading)
}
if (res.IsSuccess) { if (res.IsSuccess) {
res.Result.forEach((study, studyIndex) => { res.Result.forEach((study, studyIndex) => {
const data = {} const data = {}

View File

@ -3,7 +3,7 @@
ref="sysTemplateFrom" ref="sysTemplateFrom"
v-loading="loading" v-loading="loading"
:model="form" :model="form"
label-width="90px" label-width="140px"
size="small" size="small"
:rules="rules" :rules="rules"
class="upload-temporary-file" class="upload-temporary-file"
@ -15,7 +15,7 @@
<el-form-item label="业务场景: " prop="BusinessScenarioEnum"> <el-form-item label="业务场景: " prop="BusinessScenarioEnum">
<el-select <el-select
v-model="form.BusinessScenarioEnum" v-model="form.BusinessScenarioEnum"
style="width:100%;" style="width: 100%"
size="small" size="small"
filterable filterable
> >
@ -44,12 +44,14 @@
:on-exceed="handleExceed" :on-exceed="handleExceed"
:disabled="!form.FileTypeEnum || !form.BusinessScenarioEnum" :disabled="!form.FileTypeEnum || !form.BusinessScenarioEnum"
> >
<el-button size="small" type="primary" :disabled="!form.FileTypeEnum || !form.BusinessScenarioEnum" :loading="btnLoading">Select</el-button> <el-button
<span size="small"
slot="tip" type="primary"
style="margin-left:10px;" :disabled="!form.FileTypeEnum || !form.BusinessScenarioEnum"
class="el-upload__tip" :loading="btnLoading"
>Select</el-button
> >
<span slot="tip" style="margin-left: 10px" class="el-upload__tip">
(must be in xlsx/xls/doc/docx format) (must be in xlsx/xls/doc/docx format)
</span> </span>
</el-upload> </el-upload>
@ -58,37 +60,61 @@
<el-form-item label="文件名" prop="Name"> <el-form-item label="文件名" prop="Name">
<el-input v-model="form.Name" /> <el-input v-model="form.Name" />
</el-form-item> </el-form-item>
<el-form-item
:label="$t('dictionary:attachment:export:form:nameCN')"
prop="NameCN"
>
<el-input v-model="form.NameCN" />
</el-form-item>
<el-form-item v-if="form.Id !== ''" label="是否废除: "> <el-form-item v-if="form.Id !== ''" label="是否废除: ">
<el-radio-group v-model="form.IsDeleted"> <el-radio-group v-model="form.IsDeleted">
<el-radio v-for="item of $d.YesOrNo" :label="item.value">{{item.label}}</el-radio> <el-radio
v-for="item of $d.YesOrNo"
:label="item.value"
:key="item.id"
>{{ item.label }}</el-radio
>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="描述"> <el-form-item label="描述">
<el-input <el-input
v-model="form.Description" v-model="form.Description"
type="textarea" type="textarea"
:autosize="{ minRows: 2, maxRows: 4}" :autosize="{ minRows: 2, maxRows: 4 }"
placeholder="请输入内容" placeholder="请输入内容"
/> />
</el-form-item> </el-form-item>
</div> </div>
<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 style="text-align:right;"> <el-form-item style="text-align: right">
<el-button size="small" type="primary" :disabled="!form.FileTypeEnum || !form.BusinessScenarioEnum" :loading="saveBtnLoading" @click="handleSave">Save</el-button> <el-button
size="small"
type="primary"
:disabled="!form.FileTypeEnum || !form.BusinessScenarioEnum"
:loading="saveBtnLoading"
@click="handleSave"
>Save</el-button
>
</el-form-item> </el-form-item>
</div> </div>
</el-form> </el-form>
</template> </template>
<script> <script>
import { addOrUpdateCommonDocument, uploadCommonDoc, Upload } from '@/api/dictionary' import {
addOrUpdateCommonDocument,
uploadCommonDoc,
Upload,
} from '@/api/dictionary'
import { getBasicDataSelects } from '@/api/dictionary/dictionary' import { getBasicDataSelects } from '@/api/dictionary/dictionary'
export default { export default {
name: 'TemplateForm', name: 'TemplateForm',
props: { props: {
data: { data: {
type: Object, type: Object,
default() { return {} } default() {
} return {}
},
},
}, },
data() { data() {
@ -99,20 +125,30 @@ export default {
FileTypeEnum: null, FileTypeEnum: null,
BusinessScenarioEnum: null, BusinessScenarioEnum: null,
Name: '', Name: '',
NameCN: '',
Path: '', Path: '',
Description: '', Description: '',
IsDeleted: false IsDeleted: false,
}, },
rules: { rules: {
Code: [{ required: true, message: 'Please specify', trigger: ['blur'] }], Code: [
Name: [{ required: true, message: 'Please specify', trigger: ['blur'] }], { required: true, message: 'Please specify', trigger: ['blur'] },
BusinessScenarioEnum: [{ required: true, message: 'Please select', trigger: ['blur'] }] ],
Name: [
{ required: true, message: 'Please specify', trigger: ['blur'] },
],
NameCN: [
{ required: true, message: 'Please specify', trigger: ['blur'] },
],
BusinessScenarioEnum: [
{ required: true, message: 'Please select', trigger: ['blur'] },
],
}, },
fileList: [], fileList: [],
btnLoading: false, btnLoading: false,
saveBtnLoading: false, saveBtnLoading: false,
loading: false, loading: false,
dictionaryList: {} dictionaryList: {},
} }
}, },
mounted() { mounted() {
@ -128,8 +164,8 @@ export default {
name: this.data.Name, name: this.data.Name,
path: this.data.Path, path: this.data.Path,
url: this.data.Path, url: this.data.Path,
type: this.data.Type type: this.data.Type,
} },
] ]
} }
for (const k in this.form) { for (const k in this.form) {
@ -142,12 +178,14 @@ export default {
// //
getDicData() { getDicData() {
this.loading = true this.loading = true
getBasicDataSelects(['Common_File_ModuleType', 'Common_File_Type']).then(res => { getBasicDataSelects(['Common_File_ModuleType', 'Common_File_Type'])
this.dictionaryList = { ...res.Result } .then((res) => {
this.loading = false this.dictionaryList = { ...res.Result }
}).catch(() => { this.loading = false
this.loading = false })
}) .catch(() => {
this.loading = false
})
}, },
beforeUpload(file) { beforeUpload(file) {
// //
@ -165,35 +203,43 @@ export default {
const formData = new FormData() const formData = new FormData()
formData.append('file', param.file) formData.append('file', param.file)
this.form.FileName = param.file.name this.form.FileName = param.file.name
Upload(formData, 1).then(res => { Upload(formData, 1).then((res) => {
this.fileList.push({ name: param.file.name, path: res.Result.FilePath, fullPath: res.Result.FullFilePath, url: res.Result.FilePath }) this.fileList.push({
name: param.file.name,
path: res.Result.FilePath,
fullPath: res.Result.FullFilePath,
url: res.Result.FilePath,
})
this.form.Path = res.Result.FilePath this.form.Path = res.Result.FilePath
this.form.Name = param.file.name this.form.NameCN = param.file.name
this.loading = false this.loading = false
this.btnLoading = false this.btnLoading = false
}) })
}, },
handleSave() { handleSave() {
this.$refs.sysTemplateFrom.validate(valid => { this.$refs.sysTemplateFrom.validate((valid) => {
if (!valid) return if (!valid) return
if (!this.form.Name) { if (!this.form.Name) {
this.$alert('Please select file.') this.$alert('Please select file.')
return return
} }
this.saveBtnLoading = true this.saveBtnLoading = true
addOrUpdateCommonDocument(this.form).then(res => { addOrUpdateCommonDocument(this.form)
this.saveBtnLoading = false .then((res) => {
this.$emit('closeDialog') this.saveBtnLoading = false
this.$emit('getList') this.$emit('closeDialog')
this.$message.success('Uploaded successfully') this.$emit('getList')
}).catch(() => { this.$message.success('Uploaded successfully')
this.saveBtnLoading = false })
}) .catch(() => {
this.saveBtnLoading = false
})
}) })
}, },
handleRemoveFile() { handleRemoveFile() {
this.fileList = [] this.fileList = []
this.form.Path = '' this.form.Path = ''
this.form.NameCN = ''
this.form.Name = '' this.form.Name = ''
}, },
handlePreview(file) { handlePreview(file) {
@ -206,19 +252,21 @@ export default {
}, },
checkFileSuffix(fileName) { checkFileSuffix(fileName) {
var typeArr = ['xls', 'xlsx', 'doc', 'docx'] var typeArr = ['xls', 'xlsx', 'doc', 'docx']
var extendName = fileName.substring(fileName.lastIndexOf('.') + 1).toLocaleLowerCase() var extendName = fileName
.substring(fileName.lastIndexOf('.') + 1)
.toLocaleLowerCase()
if (typeArr.indexOf(extendName) !== -1) { if (typeArr.indexOf(extendName) !== -1) {
return true return true
} else { } else {
return false return false
} }
} },
} },
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.upload-temporary-file{ .upload-temporary-file {
.upload-container .el-upload--text { .upload-container .el-upload--text {
border: none; border: none;
width: 80px; width: 80px;
@ -231,8 +279,8 @@ export default {
color: #428bca; color: #428bca;
font-size: 13px; font-size: 13px;
} }
.account_item_clear{ .account_item_clear {
.el-tag__close{ .el-tag__close {
display: none !important; display: none !important;
} }
} }

View File

@ -5,7 +5,7 @@
<el-form-item label="业务场景"> <el-form-item label="业务场景">
<el-select <el-select
v-model="searchData.BusinessScenarioEnum" v-model="searchData.BusinessScenarioEnum"
style="width:150px;" style="width: 150px"
> >
<el-option <el-option
v-for="item of $d.Common_File_BusinessScenario" v-for="item of $d.Common_File_BusinessScenario"
@ -13,15 +13,10 @@
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="文件名称"> <el-form-item label="文件名称">
<el-input <el-input v-model="searchData.Name" style="width: 130px" clearable />
v-model="searchData.Name"
style="width:130px;"
clearable
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
@ -30,24 +25,28 @@
{{ $t('common:button:search') }} {{ $t('common:button:search') }}
</el-button> </el-button>
<!-- 重置 --> <!-- 重置 -->
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset"> <el-button
type="primary"
icon="el-icon-refresh-left"
@click="handleReset"
>
{{ $t('common:button:reset') }} {{ $t('common:button:reset') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
<el-button
type="primary"
icon="el-icon-plus"
style="float: right"
size="small"
@click="handleAdd"
>
{{ $t('common:button:new') }}
</el-button>
</el-form> </el-form>
<el-button
type="primary"
icon="el-icon-plus"
style="margin-left:auto;"
size="small"
@click="handleAdd"
>
{{ $t('common:button:new') }}
</el-button>
</template> </template>
<template slot="main-container"> <template slot="main-container">
<el-table <el-table
v-adaptive="{bottomOffset:60}" v-adaptive="{ bottomOffset: 60 }"
v-loading="loading" v-loading="loading"
:data="list" :data="list"
stripe stripe
@ -69,9 +68,13 @@
sortable="custom" sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('Common_File_BusinessScenario',scope.row.BusinessScenarioEnum) }} {{
$fd(
'Common_File_BusinessScenario',
scope.row.BusinessScenarioEnum
)
}}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -80,6 +83,12 @@
show-overflow-tooltip show-overflow-tooltip
sortable="custom" sortable="custom"
/> />
<el-table-column
prop="NameCN"
:label="$t('dictionary:attachment:upload:table:nameCN')"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column <el-table-column
prop="Description" prop="Description"
label="描述" label="描述"
@ -92,8 +101,12 @@
sortable="custom" sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-if="scope.row.IsDeleted" type="danger">{{ $fd('YesOrNo', scope.row.IsDeleted) }}</el-tag> <el-tag v-if="scope.row.IsDeleted" type="danger">{{
<el-tag v-else type="primary">{{ $fd('YesOrNo', scope.row.IsDeleted) }}</el-tag> $fd('YesOrNo', scope.row.IsDeleted)
}}</el-tag>
<el-tag v-else type="primary">{{
$fd('YesOrNo', scope.row.IsDeleted)
}}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -105,29 +118,26 @@
<el-table-column label="Action"> <el-table-column label="Action">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button type="text" @click="handleDownload(scope.row)">
type="text"
@click="handleDownload(scope.row)"
>
下载 下载
</el-button> </el-button>
<el-button <el-button type="text" @click="handleEdit(scope.row)">
type="text"
@click="handleEdit(scope.row)"
>
编辑 编辑
</el-button> </el-button>
<el-button <el-button type="text" @click="handleDelete(scope.row)">
type="text"
@click="handleDelete(scope.row)"
>
删除 删除
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页组件 --> <!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize" @pagination="getList" /> <pagination
class="page"
:total="total"
:page.sync="searchData.PageIndex"
:limit.sync="searchData.PageSize"
@pagination="getList"
/>
<!-- 新增/编辑 --> <!-- 新增/编辑 -->
<el-dialog <el-dialog
@ -138,13 +148,21 @@
width="600px" width="600px"
custom-class="base-dialog-wrapper" custom-class="base-dialog-wrapper"
> >
<TemplateForm :data="currentRow" @closeDialog="closeDialog" @getList="getList" /> <TemplateForm
:data="currentRow"
@closeDialog="closeDialog"
@getList="getList"
/>
</el-dialog> </el-dialog>
</template> </template>
</BaseContainer> </BaseContainer>
</template> </template>
<script> <script>
import { getCommonDocumentList, DownloadCommonDoc, deleteCommonDocument } from '@/api/dictionary' import {
getCommonDocumentList,
DownloadCommonDoc,
deleteCommonDocument,
} from '@/api/dictionary'
import BaseContainer from '@/components/BaseContainer' import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import TemplateForm from './TemplateForm' import TemplateForm from './TemplateForm'
@ -155,7 +173,7 @@ const searchDataDefault = () => {
BusinessScenarioEnum: null, BusinessScenarioEnum: null,
Name: '', Name: '',
PageIndex: 1, PageIndex: 1,
PageSize: 20 PageSize: 20,
} }
} }
export default { export default {
@ -168,7 +186,7 @@ export default {
total: 0, total: 0,
currentRow: {}, currentRow: {},
editDialog: { title: '', visible: false }, editDialog: { title: '', visible: false },
loading: false loading: false,
} }
}, },
mounted() { mounted() {
@ -185,13 +203,15 @@ export default {
}, },
getList() { getList() {
this.loading = true this.loading = true
getCommonDocumentList(this.searchData).then(res => { getCommonDocumentList(this.searchData)
this.loading = false .then((res) => {
this.list = res.Result.CurrentPageData this.loading = false
this.total = res.Result.TotalCount this.list = res.Result.CurrentPageData
}).catch(() => { this.total = res.Result.TotalCount
this.loading = false })
}) .catch(() => {
this.loading = false
})
}, },
// //
handleAdd() { handleAdd() {
@ -202,9 +222,13 @@ export default {
// //
handleDownload(row) { handleDownload(row) {
this.loading = true this.loading = true
DownloadCommonDoc(row.Code).then(data => { DownloadCommonDoc(row.Code)
this.loading = false .then((data) => {
}).catch(() => { this.loading = false }) this.loading = false
})
.catch(() => {
this.loading = false
})
}, },
// //
handleEdit(row) { handleEdit(row) {
@ -233,7 +257,12 @@ export default {
this.searchData.SortField = column.prop this.searchData.SortField = column.prop
this.searchData.PageIndex = 1 this.searchData.PageIndex = 1
this.getList() this.getList()
} },
} },
} }
</script> </script>
<style lang="scss" scoped>
::v-deep .search {
display: block;
}
</style>

View File

@ -110,7 +110,7 @@
<!-- 添加或修改菜单对话框 --> <!-- 添加或修改菜单对话框 -->
<el-dialog :title="title" top="100px" :close-on-click-modal="false" id="check_config" :visible.sync="open" :width="form.DataType === 'Table' ? '1280px' : '680px'" append-to-body> <el-dialog :title="title" top="100px" :close-on-click-modal="false" id="check_config" :visible.sync="open" :width="form.DataType === 'Table' ? '1280px' : '680px'" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px"> <el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-row> <el-row>
<el-col v-show="title !== '复制'" :span="24"> <el-col v-show="title !== '复制'" :span="24">
<el-divider content-position="left">基本信息</el-divider> <el-divider content-position="left">基本信息</el-divider>
@ -142,11 +142,16 @@
<el-input v-model="form.Identification" placeholder="请输入标识" /> <el-input v-model="form.Identification" placeholder="请输入标识" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col v-show="form.ConfigType === 'C' && title !== '复制'" :span="24"> <el-col v-show="form.ConfigType === 'C' && title !== '复制'" :span="12">
<el-form-item label="字段key"> <el-form-item label="字段key">
<el-input v-model="form.Code" placeholder="请输入字段key" /> <el-input v-model="form.Code" placeholder="请输入字段key" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col v-show="form.ConfigType === 'C' && title !== '复制'" :span="12">
<el-form-item label="字段key英文">
<el-input v-model="form.CodeEn" placeholder="请输入字段key英文" />
</el-form-item>
</el-col>
<el-col v-show="form.ConfigType === 'C' && title !== '复制'" :span="12"> <el-col v-show="form.ConfigType === 'C' && title !== '复制'" :span="12">
<el-form-item label="字段英文"> <el-form-item label="字段英文">
<el-input v-model="form.Value" placeholder="请输入字段英文" /> <el-input v-model="form.Value" placeholder="请输入字段英文" />
@ -392,6 +397,16 @@
<el-input :disabled="scope.row.IsFixedColumn" v-model="scope.row.ColumnName" placeholder="列字段名"/> <el-input :disabled="scope.row.IsFixedColumn" v-model="scope.row.ColumnName" placeholder="列字段名"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
prop="ColumnEnName"
min-width="120"
label="列字段名En"
show-overflow-tooltip
>
<template slot-scope="scope">
<el-input :disabled="scope.row.IsFixedColumn" v-model="scope.row.ColumnEnName" placeholder="列字段名En"/>
</template>
</el-table-column>
<el-table-column <el-table-column
prop="ColumnValue" prop="ColumnValue"
min-width="120" min-width="120"
@ -509,6 +524,14 @@
<el-input v-model="form.ChildDataLabel" placeholder="请输入子数据Lable" /> <el-input v-model="form.ChildDataLabel" placeholder="请输入子数据Lable" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col v-show="form.ConfigType === 'C' && title !== '复制' && form.DataType === 'Array'" :span="12">
<el-form-item>
<span slot="label">
子数据LableEN
</span>
<el-input v-model="form.ChildDataEnLabel" placeholder="请输入子数据LableEN" />
</el-form-item>
</el-col>
<el-col v-show="form.ConfigType === 'C' && title !== '复制' && form.DataType === 'Array'" :span="12"> <el-col v-show="form.ConfigType === 'C' && title !== '复制' && form.DataType === 'Array'" :span="12">
<el-form-item> <el-form-item>
<span slot="label"> <span slot="label">
@ -668,6 +691,7 @@
height="100" height="100"
> >
<el-table-column prop="Code" label="字段名" min-width="120px" :show-overflow-tooltip="true" /> <el-table-column prop="Code" label="字段名" min-width="120px" :show-overflow-tooltip="true" />
<el-table-column prop="CodeEn" label="字段名英文" min-width="120px" :show-overflow-tooltip="true" />
<el-table-column prop="Value" label="字段英文" min-width="120px" :show-overflow-tooltip="true" /> <el-table-column prop="Value" label="字段英文" min-width="120px" :show-overflow-tooltip="true" />
<el-table-column prop="ValueCN" label="字段中文" min-width="120px" :show-overflow-tooltip="true" /> <el-table-column prop="ValueCN" label="字段中文" min-width="120px" :show-overflow-tooltip="true" />
<el-table-column <el-table-column
@ -848,6 +872,7 @@ export default {
FixedColumnName: null, FixedColumnName: null,
FixedColumnEnName: null, FixedColumnEnName: null,
ColumnName: null, ColumnName: null,
ColumnEnName: null,
ColumnValue: null, ColumnValue: null,
IsMerge: false, IsMerge: false,
MergeColumnName: null, MergeColumnName: null,
@ -1124,6 +1149,7 @@ export default {
IsShowParent: 0, IsShowParent: 0,
Sort: 0, Sort: 0,
Code: null, Code: null,
CodeEn: null,
Value: null, Value: null,
ValueCN: null, ValueCN: null,
EnumType: '', EnumType: '',
@ -1138,6 +1164,7 @@ export default {
IsSpecialType: false, IsSpecialType: false,
DataType: '', DataType: '',
ChildDataLabel: null, ChildDataLabel: null,
ChildDataEnLabel: null,
ChildDataValue: null, ChildDataValue: null,
DateType: null, DateType: null,
DictionaryCode: null, DictionaryCode: null,

View File

@ -10,7 +10,15 @@
> >
<div class="base-dialog-body"> <div class="base-dialog-body">
<el-form-item label="类型" prop="Type"> <el-form-item label="类型" prop="Type">
<el-select v-model="form.Type" clearable @change="((val)=>{typeChange(val, form)})"> <el-select
v-model="form.Type"
clearable
@change="
(val) => {
typeChange(val, form)
}
"
>
<el-option <el-option
v-for="item of $d.Criterion_Question_Type" v-for="item of $d.Criterion_Question_Type"
:key="item.value" :key="item.value"
@ -31,10 +39,7 @@
v-if="form.Type === 'group'" v-if="form.Type === 'group'"
prop="GroupClassify" prop="GroupClassify"
> >
<el-select <el-select v-model="form.GroupClassify" clearable>
v-model="form.GroupClassify"
clearable
>
<el-option <el-option
v-for="item of groupClassifyList" v-for="item of groupClassifyList"
:key="item.Id" :key="item.Id"
@ -70,13 +75,9 @@
v-if="form.Type === 'number' || form.Type === 'calculation'" v-if="form.Type === 'number' || form.Type === 'calculation'"
label="数值类型" label="数值类型"
prop="ValueType" prop="ValueType"
:rules="[ :rules="[{ required: true, message: '请选择' }]"
{ required: true, message: '请选择'}
]"
> >
<el-radio-group <el-radio-group v-model="form.ValueType">
v-model="form.ValueType"
>
<el-radio <el-radio
v-for="item of $d.ValueType" v-for="item of $d.ValueType"
:key="item.id" :key="item.id"
@ -92,9 +93,7 @@
v-if="form.Type === 'number' || form.Type === 'calculation'" v-if="form.Type === 'number' || form.Type === 'calculation'"
label="单位" label="单位"
> >
<el-radio-group <el-radio-group v-model="form.Unit">
v-model="form.Unit"
>
<el-radio <el-radio
v-for="item of $d.ValueUnit" v-for="item of $d.ValueUnit"
:key="item.id" :key="item.id"
@ -109,15 +108,12 @@
label="表格类型标识" label="表格类型标识"
prop="LesionType" prop="LesionType"
> >
<el-select <el-select v-model="form.LesionType" clearable>
v-model="form.LesionType"
clearable
>
<el-option <el-option
v-for="item of lesionTypes" v-for="item of lesionTypes"
:key="item.Code" :key="item.Code"
:value="parseInt(item.Code)" :value="parseInt(item.Code)"
:label="$fd('LesionType',parseInt(item.Code))" :label="$fd('LesionType', parseInt(item.Code))"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -133,25 +129,27 @@
</el-form-item> --> </el-form-item> -->
<!-- 选项类型 --> <!-- 选项类型 -->
<el-form-item <el-form-item
v-if="form.Type === 'select' || form.Type === 'radio' || form.Type === 'calculation'" v-if="
form.Type === 'select' ||
form.Type === 'radio' ||
form.Type === 'calculation'
"
label="选项类型" label="选项类型"
prop="QuestionGenre" prop="QuestionGenre"
:rules="[ :rules="[{ required: form.Type !== 'calculation', message: '请选择' }]"
{ required: form.Type !== 'calculation', message: '请选择'}
]"
> >
<el-radio-group <el-radio-group
v-model="form.QuestionGenre" v-model="form.QuestionGenre"
@change="((val)=>{questionGenreChange(val, form)})" @change="
(val) => {
questionGenreChange(val, form)
}
"
> >
<el-radio <el-radio :label="-1"> </el-radio>
:label="-1"
>
</el-radio>
<el-radio <el-radio
v-for="item of $d.TableQuestionType" v-for="item of $d.TableQuestionType"
v-show="item.value===0 || item.value===3" v-show="item.value === 0 || item.value === 3"
:key="item.id" :key="item.id"
:label="item.value" :label="item.value"
> >
@ -183,13 +181,8 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item <el-form-item label="转化显示类型" prop="ConvertShowType">
label="转化显示类型" <el-radio-group v-model="form.ConvertShowType">
prop="ConvertShowType"
>
<el-radio-group
v-model="form.ConvertShowType"
>
<el-radio <el-radio
v-for="item of $d.ConvertShowType" v-for="item of $d.ConvertShowType"
:key="item.id" :key="item.id"
@ -200,11 +193,19 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
v-if="form.QuestionGenre === 3 " v-if="form.QuestionGenre === 3"
label="关联字典" label="关联字典"
prop="DictionaryCode" prop="DictionaryCode"
> >
<el-select v-model="form.DictionaryCode" clearable @change="() => {form.DefaultValue = null}"> <el-select
v-model="form.DictionaryCode"
clearable
@change="
() => {
form.DefaultValue = null
}
"
>
<el-option <el-option
v-for="item of dicList" v-for="item of dicList"
:key="item.Id" :key="item.Id"
@ -213,10 +214,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item <el-form-item v-if="form.QuestionGenre === 3" label="默认值">
v-if="form.QuestionGenre === 3 "
label="默认值"
>
<el-select v-model="form.DefaultValue" clearable> <el-select v-model="form.DefaultValue" clearable>
<el-option <el-option
v-for="item of form.DictionaryCode ? $d[form.DictionaryCode] : []" v-for="item of form.DictionaryCode ? $d[form.DictionaryCode] : []"
@ -226,10 +224,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item <el-form-item v-if="form.QuestionGenre === 0" label="默认值">
v-if="form.QuestionGenre === 0 "
label="默认值"
>
<el-select v-model="form.DefaultValue" clearable> <el-select v-model="form.DefaultValue" clearable>
<el-option <el-option
v-for="item of form.TypeValue ? form.TypeValue.split('|') : []" v-for="item of form.TypeValue ? form.TypeValue.split('|') : []"
@ -240,10 +235,18 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-if="form.Type !== 'group'" label="是否显示" prop="ShowQuestion"> <el-form-item
v-if="form.Type !== 'group'"
label="是否显示"
prop="ShowQuestion"
>
<el-radio-group <el-radio-group
v-model="form.ShowQuestion" v-model="form.ShowQuestion"
@change="((val)=>{isShowQuestionChange(val, form)})" @change="
(val) => {
isShowQuestionChange(val, form)
}
"
> >
<el-radio <el-radio
v-for="item of $d.ShowQuestion" v-for="item of $d.ShowQuestion"
@ -257,14 +260,18 @@
<!-- 显示时依赖父问题 --> <!-- 显示时依赖父问题 -->
<el-form-item <el-form-item
v-if="form.Type !== 'group' && form.ShowQuestion===1" v-if="form.Type !== 'group' && form.ShowQuestion === 1"
label="显示依赖父问题" label="显示依赖父问题"
prop="ParentId" prop="ParentId"
> >
<el-select <el-select
v-model="form.ParentId" v-model="form.ParentId"
clearable clearable
@change="((val)=>{parentQuestionChange(val, form)})" @change="
(val) => {
parentQuestionChange(val, form)
}
"
> >
<el-option <el-option
v-for="item of parentOptions" v-for="item of parentOptions"
@ -275,15 +282,19 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 显示时依赖父问题触发值 --> <!-- 显示时依赖父问题触发值 -->
<el-form-item v-if="form.ParentId && form.ShowQuestion===1" label="显示触发值" prop="ParentTriggerValueList"> <el-form-item
<!-- <el-select v-model="form.ParentTriggerValue" clearable>--> v-if="form.ParentId && form.ShowQuestion === 1"
<!-- <el-option--> label="显示触发值"
<!-- v-for="item of parentTriggerValOptions"--> prop="ParentTriggerValueList"
<!-- :key="item.id"--> >
<!-- :label="item.label"--> <!-- <el-select v-model="form.ParentTriggerValue" clearable>-->
<!-- :value="item.value.toString()"--> <!-- <el-option-->
<!-- />--> <!-- v-for="item of parentTriggerValOptions"-->
<!-- </el-select>--> <!-- :key="item.id"-->
<!-- :label="item.label"-->
<!-- :value="item.value.toString()"-->
<!-- />-->
<!-- </el-select>-->
<el-select v-model="form.ParentTriggerValueList" clearable multiple> <el-select v-model="form.ParentTriggerValueList" clearable multiple>
<el-option <el-option
v-for="item of parentTriggerValOptions" v-for="item of parentTriggerValOptions"
@ -293,16 +304,44 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-if="form.Type === 'select' || form.Type === 'radio' || form.Type === 'calculation'" label="是否裁判问题"> <el-form-item
<el-radio-group v-model="form.IsJudgeQuestion" @change="((val)=>{isJudgeQuestionChange(val, form)})"> v-if="
<el-radio v-for="item of $d.YesOrNo" :key="`YesOrNo${item.value}`" :label="item.value">{{ item.label }}</el-radio> form.Type === 'select' ||
form.Type === 'radio' ||
form.Type === 'calculation' ||
form.Type === 'number'
"
label="是否裁判问题"
>
<el-radio-group
v-model="form.IsJudgeQuestion"
@change="
(val) => {
isJudgeQuestionChange(val, form)
}
"
>
<el-radio
v-for="item of $d.YesOrNo"
:key="`YesOrNo${item.value}`"
:label="item.value"
>{{ item.label }}</el-radio
>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item v-if="form.Type !== 'group' && form.Type !== 'table'" label="是否必填" prop="IsRequired"> <el-form-item
v-if="form.Type !== 'group' && form.Type !== 'table'"
label="是否必填"
prop="IsRequired"
>
<el-radio-group <el-radio-group
v-model="form.IsRequired" v-model="form.IsRequired"
:disabled="form.IsJudgeQuestion===true || form.ShowQuestion===2" :disabled="form.IsJudgeQuestion === true || form.ShowQuestion === 2"
@change="((val)=>{isRequiredChange(val, form)})" @change="
(val) => {
isRequiredChange(val, form)
}
"
> >
<el-radio <el-radio
v-for="item of $d.QuestionRequired" v-for="item of $d.QuestionRequired"
@ -323,7 +362,11 @@
<el-select <el-select
v-model="form.RelevanceId" v-model="form.RelevanceId"
clearable clearable
@change="((val)=>{relevanceQuestionChange(val, form)})" @change="
(val) => {
relevanceQuestionChange(val, form)
}
"
> >
<el-option <el-option
v-for="item of parentOptions" v-for="item of parentOptions"
@ -339,14 +382,14 @@
label="必填触发值" label="必填触发值"
prop="RelevanceValueList" prop="RelevanceValueList"
> >
<!-- <el-select v-model="form.RelevanceValue" clearable>--> <!-- <el-select v-model="form.RelevanceValue" clearable>-->
<!-- <el-option--> <!-- <el-option-->
<!-- v-for="item of reParentTriggerValOptions"--> <!-- v-for="item of reParentTriggerValOptions"-->
<!-- :key="item.id"--> <!-- :key="item.id"-->
<!-- :label="item.label"--> <!-- :label="item.label"-->
<!-- :value="item.value.toString()"--> <!-- :value="item.value.toString()"-->
<!-- />--> <!-- />-->
<!-- </el-select>--> <!-- </el-select>-->
<el-select v-model="form.RelevanceValueList" clearable multiple> <el-select v-model="form.RelevanceValueList" clearable multiple>
<el-option <el-option
v-for="item of reParentTriggerValOptions" v-for="item of reParentTriggerValOptions"
@ -385,7 +428,11 @@
</el-form-item> --> </el-form-item> -->
<el-form-item v-if="form.Type !== 'group'" label="问题分组"> <el-form-item v-if="form.Type !== 'group'" label="问题分组">
<el-select v-model="form.GroupId" clearable :disabled="isParentExistGroup"> <el-select
v-model="form.GroupId"
clearable
:disabled="isParentExistGroup"
>
<el-option <el-option
v-for="group of groupOptions" v-for="group of groupOptions"
:key="group.GroupId" :key="group.GroupId"
@ -396,12 +443,22 @@
</el-form-item> </el-form-item>
<el-form-item label="限制编辑"> <el-form-item label="限制编辑">
<el-radio-group v-model="form.LimitEdit"> <el-radio-group v-model="form.LimitEdit">
<el-radio v-for="item of $d.LimitEdit" :key="`LimitEdit${item.value}`" :label="item.value">{{ item.label }}</el-radio> <el-radio
v-for="item of $d.LimitEdit"
:key="`LimitEdit${item.value}`"
:label="item.value"
>{{ item.label }}</el-radio
>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="全局阅片是否显示"> <el-form-item label="全局阅片是否显示">
<el-radio-group v-model="form.GlobalReadingShowType"> <el-radio-group v-model="form.GlobalReadingShowType">
<el-radio v-for="item of $d.GlobalReadingShowType" :key="item.id" :label="item.value">{{ item.label }}</el-radio> <el-radio
v-for="item of $d.GlobalReadingShowType"
:key="item.id"
:label="item.value"
>{{ item.label }}</el-radio
>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -409,10 +466,7 @@
v-if="form.Type !== 'group'" v-if="form.Type !== 'group'"
prop="QuestionType" prop="QuestionType"
> >
<el-select <el-select v-model="form.QuestionType" clearable>
v-model="form.QuestionType"
clearable
>
<el-option <el-option
v-for="item of CriterionDictionaryList.QuestionType" v-for="item of CriterionDictionaryList.QuestionType"
:key="item.Id" :key="item.Id"
@ -428,9 +482,18 @@
</el-radio-group> </el-radio-group>
</el-form-item> --> </el-form-item> -->
<el-form-item v-if="form.Type === 'upload'" label="最大上传个数"> <el-form-item v-if="form.Type === 'upload'" label="最大上传个数">
<el-input-number v-model="form.ImageCount" controls-position="right" :min="1" :max="10" /> <el-input-number
v-model="form.ImageCount"
controls-position="right"
:min="1"
:max="10"
/>
</el-form-item> </el-form-item>
<el-form-item v-if="form.Type === 'select' || form.Type === 'radio'" label="高亮标记值" prop="HighlightAnswerList"> <el-form-item
v-if="form.Type === 'select' || form.Type === 'radio'"
label="高亮标记值"
prop="HighlightAnswerList"
>
<el-select v-model="form.HighlightAnswerList" clearable multiple> <el-select v-model="form.HighlightAnswerList" clearable multiple>
<template v-if="form.TypeValue"> <template v-if="form.TypeValue">
<el-option <el-option
@ -471,20 +534,23 @@
<el-form-item label="是否在阅片页面显示"> <el-form-item label="是否在阅片页面显示">
<el-radio-group v-model="form.IsShowInDicom"> <el-radio-group v-model="form.IsShowInDicom">
<el-radio v-for="item of $d.YesOrNo" :key="`YesOrNo${item.value}`" :label="item.value">{{ item.label }}</el-radio> <el-radio
v-for="item of $d.YesOrNo"
:key="`YesOrNo${item.value}`"
:label="item.value"
>{{ item.label }}</el-radio
>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
:label="$t('trials:readingUnit:qsList:title:Remark')" :label="$t('trials:readingUnit:qsList:title:Remark')"
prop="Remark" prop="Remark"
> >
<el-input <el-input v-model="form.Remark" />
v-model="form.Remark"
/>
</el-form-item> </el-form-item>
</div> </div>
<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 <el-button
@ -496,7 +562,12 @@
{{ $t('common:button:cancel') }} {{ $t('common:button:cancel') }}
</el-button> </el-button>
<!-- 保存 --> <!-- 保存 -->
<el-button size="small" type="primary" :loading="btnLoading" @click="save"> <el-button
size="small"
type="primary"
:loading="btnLoading"
@click="save"
>
{{ $t('common:button:save') }} {{ $t('common:button:save') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
@ -504,19 +575,30 @@
</el-form> </el-form>
</template> </template>
<script> <script>
import { getBasicConfigSelect, addOrUpdateReadingQuestionSystem, getSystemCriterionOtherQuestion, getSystemGroupNameList, getCriterionDictionary, getCriterionDictionaryList } from '@/api/dictionary' import {
getBasicConfigSelect,
addOrUpdateReadingQuestionSystem,
getSystemCriterionOtherQuestion,
getSystemGroupNameList,
getCriterionDictionary,
getCriterionDictionaryList,
} from '@/api/dictionary'
import { getCriterionLesionType } from '@/api/trials' import { getCriterionLesionType } from '@/api/trials'
export default { export default {
name: 'AddOrUpdateClinicalData', name: 'AddOrUpdateClinicalData',
props: { props: {
data: { data: {
type: Object, type: Object,
default() { return {} } default() {
return {}
},
}, },
type: { type: {
type: String, type: String,
default() { return '' } default() {
} return ''
},
},
}, },
data() { data() {
var validateTypeVal = (rule, value, callback) => { var validateTypeVal = (rule, value, callback) => {
@ -553,7 +635,7 @@ export default {
IsJudgeQuestion: false, IsJudgeQuestion: false,
GroupName: '', GroupName: '',
GroupEnName: '', GroupEnName: '',
GroupClassify:null, GroupClassify: null,
Remark: '', Remark: '',
ImageCount: 1, ImageCount: 1,
RelevanceId: '', RelevanceId: '',
@ -570,32 +652,38 @@ export default {
GroupId: null, GroupId: null,
ConvertShowType: 0, ConvertShowType: 0,
QuestionClassify: null, QuestionClassify: null,
HighlightAnswerList: [] HighlightAnswerList: [],
}, },
rules: { rules: {
Type: [ Type: [{ required: true, message: '请选择', trigger: 'blur' }],
{ required: true, message: '请选择', trigger: 'blur' } LesionType: [{ required: true, message: '请选择', trigger: 'blur' }],
QuestionName: [
{ required: true, message: '请注明', trigger: 'blur' },
{ max: 300, message: '最大长度为 300' },
], ],
LesionType: [
{ required: true, message: '请选择', trigger: 'blur' }
],
QuestionName: [{ required: true, message: '请注明', trigger: 'blur' },
{ max: 300, message: '最大长度为 300' }],
QuestionGenre: [{ required: true, message: '请选择', trigger: 'blur' }], QuestionGenre: [{ required: true, message: '请选择', trigger: 'blur' }],
TypeValue: [{ required: true, message: '请注明', trigger: 'blur' }, TypeValue: [
{ required: true, message: '请注明', trigger: 'blur' },
{ validator: validateTypeVal, trigger: 'blur' }, { validator: validateTypeVal, trigger: 'blur' },
{ max: 500, message: '最大长度为 500' }], { max: 500, message: '最大长度为 500' },
DictionaryCode: [{ required: true, message: '请选择', trigger: 'blur' }], ],
DictionaryCode: [
{ required: true, message: '请选择', trigger: 'blur' },
],
ShowQuestion: [{ required: true, message: '请选择', trigger: 'blur' }], ShowQuestion: [{ required: true, message: '请选择', trigger: 'blur' }],
IsRequired: [{ required: true, message: '请选择', trigger: 'blur' }], IsRequired: [{ required: true, message: '请选择', trigger: 'blur' }],
ParentId: [{ required: true, message: '请选择', trigger: 'blur' }], ParentId: [{ required: true, message: '请选择', trigger: 'blur' }],
ParentTriggerValueList: [ ParentTriggerValueList: [
{ required: true, message: '请选择', trigger: 'blur' } { required: true, message: '请选择', trigger: 'blur' },
], ],
RelevanceId: [{ required: true, message: '请选择', trigger: 'blur' }], RelevanceId: [{ required: true, message: '请选择', trigger: 'blur' }],
RelevanceValueList: [{ required: true, message: '请选择', trigger: 'blur' }], RelevanceValueList: [
GroupName: [{ required: true, message: '请注明', trigger: 'blur' }, { required: true, message: '请选择', trigger: 'blur' },
{ max: 50, message: '最大长度为 50' }] ],
GroupName: [
{ required: true, message: '请注明', trigger: 'blur' },
{ max: 50, message: '最大长度为 50' },
],
}, },
loading: false, loading: false,
btnLoading: false, btnLoading: false,
@ -606,8 +694,8 @@ export default {
lesionTypes: [], lesionTypes: [],
dicList: [], dicList: [],
CriterionDictionaryList: [], CriterionDictionaryList: [],
groupClassifyList:[], groupClassifyList: [],
highlightAnswers: [] highlightAnswers: [],
} }
}, },
watch: { watch: {
@ -622,14 +710,14 @@ export default {
} }
let res = await getCriterionDictionary({ let res = await getCriterionDictionary({
ReadingCriterionId: this.data.ReadingQuestionCriterionSystemId, ReadingCriterionId: this.data.ReadingQuestionCriterionSystemId,
DictionaryCode: this.form.DictionaryCode DictionaryCode: this.form.DictionaryCode,
}) })
this.highlightAnswers = res.Result[this.form.DictionaryCode] this.highlightAnswers = res.Result[this.form.DictionaryCode]
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }
} },
} },
}, },
mounted() { mounted() {
this.initForm() this.initForm()
@ -638,16 +726,16 @@ export default {
getCriterionDictionary() { getCriterionDictionary() {
getCriterionDictionary({ getCriterionDictionary({
ReadingCriterionId: this.data.ReadingQuestionCriterionSystemId, ReadingCriterionId: this.data.ReadingQuestionCriterionSystemId,
DictionaryCode: 'QuestionType' DictionaryCode: 'QuestionType',
}).then(res => { }).then((res) => {
this.CriterionDictionaryList = res.Result this.CriterionDictionaryList = res.Result
}) })
}, },
getGroupClassifyDictionary() { getGroupClassifyDictionary() {
getCriterionDictionary({ getCriterionDictionary({
ReadingCriterionId: this.data.ReadingQuestionCriterionSystemId, ReadingCriterionId: this.data.ReadingQuestionCriterionSystemId,
DictionaryCode: 'GroupClassify' DictionaryCode: 'GroupClassify',
}).then(res => { }).then((res) => {
this.groupClassifyList = res.Result.GroupClassify this.groupClassifyList = res.Result.GroupClassify
}) })
}, },
@ -661,37 +749,47 @@ export default {
this.form[k] = this.data[k] this.form[k] = this.data[k]
} }
} }
if (this.form.ParentId !== '' && this.form.ParentId !== null && this.form.GroupName !== '') { if (
this.form.ParentId !== '' &&
this.form.ParentId !== null &&
this.form.GroupName !== ''
) {
this.isParentExistGroup = true this.isParentExistGroup = true
} }
if (this.form.ParentId) { if (this.form.ParentId) {
var index = this.parentOptions.findIndex(item => { var index = this.parentOptions.findIndex((item) => {
return item.QuestionId === this.form.ParentId return item.QuestionId === this.form.ParentId
}) })
if (index !== -1) { if (index !== -1) {
if (this.parentOptions[index].QuestionGenre === 3) { if (this.parentOptions[index].QuestionGenre === 3) {
this.parentTriggerValOptions = this.$d[this.parentOptions[index].DictionaryCode] this.parentTriggerValOptions =
this.$d[this.parentOptions[index].DictionaryCode]
} else { } else {
const options = [] const options = []
this.parentOptions[index].TypeValue.split('|').forEach((item, index) => { this.parentOptions[index].TypeValue.split('|').forEach(
options.push({ id: index, label: item, value: item }) (item, index) => {
}) options.push({ id: index, label: item, value: item })
}
)
this.parentTriggerValOptions = options this.parentTriggerValOptions = options
} }
} }
} }
if (this.form.RelevanceId) { if (this.form.RelevanceId) {
var index = this.parentOptions.findIndex(item => { var index = this.parentOptions.findIndex((item) => {
return item.QuestionId === this.form.RelevanceId return item.QuestionId === this.form.RelevanceId
}) })
if (index !== -1) { if (index !== -1) {
if (this.parentOptions[index].QuestionGenre === 3) { if (this.parentOptions[index].QuestionGenre === 3) {
this.reParentTriggerValOptions = this.$d[this.parentOptions[index].DictionaryCode] this.reParentTriggerValOptions =
this.$d[this.parentOptions[index].DictionaryCode]
} else { } else {
const options = [] const options = []
this.parentOptions[index].TypeValue.split('|').forEach((item, index) => { this.parentOptions[index].TypeValue.split('|').forEach(
options.push({ id: index, label: item, value: item }) (item, index) => {
}) options.push({ id: index, label: item, value: item })
}
)
this.reParentTriggerValOptions = options this.reParentTriggerValOptions = options
} }
} }
@ -701,18 +799,19 @@ export default {
this.getGroupClassifyDictionary() this.getGroupClassifyDictionary()
}, },
save() { save() {
this.$refs.clinicalDataForm.validate(valid => { this.$refs.clinicalDataForm.validate((valid) => {
if (!valid) return if (!valid) return
this.btnLoading = true this.btnLoading = true
if (this.form.Type !== 'upload') { if (this.form.Type !== 'upload') {
this.form.ImageCount = 0 this.form.ImageCount = 0
} }
addOrUpdateReadingQuestionSystem(this.form).then(res => { addOrUpdateReadingQuestionSystem(this.form)
this.btnLoading = false .then((res) => {
this.$emit('getList') this.btnLoading = false
this.$emit('close') this.$emit('getList')
this.$message.success(this.$t('common:message:savedSuccessfully')) this.$emit('close')
}) this.$message.success(this.$t('common:message:savedSuccessfully'))
})
.catch(() => { .catch(() => {
this.btnLoading = false this.btnLoading = false
}) })
@ -722,33 +821,38 @@ export default {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.loading = true this.loading = true
var param = { var param = {
criterionId: this.data.ReadingQuestionCriterionSystemId criterionId: this.data.ReadingQuestionCriterionSystemId,
} }
getSystemGroupNameList(param).then(res => { getSystemGroupNameList(param)
this.groupOptions = res.Result .then((res) => {
this.loading = false this.groupOptions = res.Result
resolve() this.loading = false
}).catch(() => { resolve()
this.loading = false })
reject() .catch(() => {
}) this.loading = false
reject()
})
}) })
}, },
getParentQuestions() { getParentQuestions() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.loading = true this.loading = true
var param = { var param = {
readingQuestionCriterionSystemId: this.data.ReadingQuestionCriterionSystemId, readingQuestionCriterionSystemId:
id: this.data.Id this.data.ReadingQuestionCriterionSystemId,
id: this.data.Id,
} }
getSystemCriterionOtherQuestion(param).then(res => { getSystemCriterionOtherQuestion(param)
this.parentOptions = res.Result .then((res) => {
this.loading = false this.parentOptions = res.Result
resolve() this.loading = false
}).catch(() => { resolve()
this.loading = false })
reject() .catch(() => {
}) this.loading = false
reject()
})
}) })
}, },
questionGenreChange(val, form) { questionGenreChange(val, form) {
@ -819,17 +923,20 @@ export default {
parentQuestionChange(val, form) { parentQuestionChange(val, form) {
this.isParentExistGroup = false this.isParentExistGroup = false
if (val) { if (val) {
var index = this.parentOptions.findIndex(item => { var index = this.parentOptions.findIndex((item) => {
return item.QuestionId === val return item.QuestionId === val
}) })
if (index !== -1) { if (index !== -1) {
if (this.parentOptions[index].QuestionGenre === 3) { if (this.parentOptions[index].QuestionGenre === 3) {
this.parentTriggerValOptions = this.$d[this.parentOptions[index].DictionaryCode] this.parentTriggerValOptions =
this.$d[this.parentOptions[index].DictionaryCode]
} else { } else {
var options = [] var options = []
this.parentOptions[index].TypeValue.split('|').forEach((item, index) => { this.parentOptions[index].TypeValue.split('|').forEach(
options.push({ id: index, label: item, value: item }) (item, index) => {
}) options.push({ id: index, label: item, value: item })
}
)
this.parentTriggerValOptions = options this.parentTriggerValOptions = options
} }
if (this.parentOptions[index].GroupName) { if (this.parentOptions[index].GroupName) {
@ -845,17 +952,20 @@ export default {
}, },
relevanceQuestionChange(val, form) { relevanceQuestionChange(val, form) {
if (val) { if (val) {
var index = this.parentOptions.findIndex(item => { var index = this.parentOptions.findIndex((item) => {
return item.QuestionId === val return item.QuestionId === val
}) })
if (index !== -1) { if (index !== -1) {
if (this.parentOptions[index].QuestionGenre === 3) { if (this.parentOptions[index].QuestionGenre === 3) {
this.reParentTriggerValOptions = this.$d[this.parentOptions[index].DictionaryCode] this.reParentTriggerValOptions =
this.$d[this.parentOptions[index].DictionaryCode]
} else { } else {
var options = [] var options = []
this.parentOptions[index].TypeValue.split('|').forEach((item, index) => { this.parentOptions[index].TypeValue.split('|').forEach(
options.push({ id: index, label: item, value: item }) (item, index) => {
}) options.push({ id: index, label: item, value: item })
}
)
this.reParentTriggerValOptions = options this.reParentTriggerValOptions = options
} }
} }
@ -871,23 +981,24 @@ export default {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.loading = true this.loading = true
var param = { var param = {
SystemCriterionId: this.data.ReadingQuestionCriterionSystemId SystemCriterionId: this.data.ReadingQuestionCriterionSystemId,
} }
getCriterionLesionType(param).then(res => { getCriterionLesionType(param)
this.lesionTypes = res.Result .then((res) => {
this.loading = false this.lesionTypes = res.Result
resolve() this.loading = false
}).catch(() => { resolve()
this.loading = false })
reject() .catch(() => {
}) this.loading = false
reject()
})
}) })
}, },
close() { close() {
this.$emit('close') this.$emit('close')
} },
},
}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -69,7 +69,7 @@
>{{ item.label }}</el-radio> >{{ item.label }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="序号"> <el-form-item label="序号" prop="ShowOrder">
<el-input v-model="form.ShowOrder" type="number" /> <el-input v-model="form.ShowOrder" type="number" />
</el-form-item> </el-form-item>
<!-- 描述 --> <!-- 描述 -->
@ -135,7 +135,8 @@ export default {
Part: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] }], Part: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] }],
TULOC: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] }], TULOC: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] }],
Remark: [{ max: 500, message: `${this.$t('common:ruleMessage:maxLength')} 500`, trigger: ['blur', 'change'] }], Remark: [{ max: 500, message: `${this.$t('common:ruleMessage:maxLength')} 500`, trigger: ['blur', 'change'] }],
IsLymphNodes: [{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] }] IsLymphNodes: [{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] }],
ShowOrder: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] }]
}, },
lesionTypes: [], lesionTypes: [],
loading: false, loading: false,

View File

@ -2,52 +2,65 @@
<div v-loading="loading" class="img-container"> <div v-loading="loading" class="img-container">
<el-card class="box-card left"> <el-card class="box-card left">
<div class="title"> <div class="title">
{{$t('trials:none-dicom-show:fileList')}} {{ $t('trials:none-dicom-show:fileList') }}
</div> </div>
<div class="left-content"> <div class="left-content">
<!-- 检查层级 --> <!-- 检查层级 -->
<div v-for="(study,i) in studyList" :key="study.CodeView"> <div v-for="(study, i) in studyList" :key="study.CodeView">
<div class="study-desc"> <div class="study-desc">
<span>{{ study.CodeView }}</span> <span>{{ study.CodeView }}</span>
<span style="margin:0 5px">{{ study.Modality }}</span> <span style="margin: 0 5px">{{ study.Modality }}</span>
<span>{{ getBodyPart(study.BodyPart) }}</span> <span>{{ getBodyPart(study.BodyPart) }}</span>
</div> </div>
<!-- 文件层级 --> <!-- 文件层级 -->
<div v-if="study.NoneDicomStudyFileList.length === 0" class="empty-text"> <div
<slot name="empty">暂无数据</slot> v-if="study.NoneDicomStudyFileList.length === 0"
class="empty-text"
>
<slot name="empty">{{ $t('trials:audit:message:noData') }}</slot>
</div> </div>
<div v-else id="imgList" style="height:100%;overflow: hidden"> <div v-else id="imgList" style="height: 100%; overflow: hidden">
<div <div
v-for="(item,j) in study.NoneDicomStudyFileList" v-for="(item, j) in study.NoneDicomStudyFileList"
:id="`img${item.Id}`" :id="`img${item.Id}`"
:key="item.Id" :key="item.Id"
:class="{ :class="{
'is-boxActive': item.Id === currentFileId 'is-boxActive': item.Id === currentFileId,
}" }"
class="img-box" class="img-box"
@click="selected(item,i,j,true)" @click="selected(item, i, j, true)"
> >
{{ `${j+1}. ${item.FileName}` }} <div v-if="item.FileName.length < 15" class="img-text">
{{ `${j + 1}. ${item.FileName}` }}
</div>
<el-tooltip v-else :content="item.FileName" placement="bottom">
<div class="img-text">
{{ `${j + 1}. ${item.FileName}` }}
</div>
</el-tooltip>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</el-card> </el-card>
<!-- 预览图像 --> <!-- 预览图像 -->
<el-card class="box-card right"> <el-card class="box-card right">
<div style="width:100%;height: 100%;"> <div style="width: 100%; height: 100%">
<Preview v-if="previewImage.imgList.length > 0" ref="previewImage" style="width:100%;" :preview-image="previewImage" :value="currentStudyFileIndex" @selectedImg="selectedImg" /> <Preview
v-if="previewImage.imgList.length > 0"
ref="previewImage"
style="width: 100%"
:preview-image="previewImage"
:value="currentStudyFileIndex"
@selectedImg="selectedImg"
/>
</div> </div>
</el-card> </el-card>
<!-- <el-card class="box-card" style="width:300px;height:100%;padding: 10px;margin-left:10px;"> <!-- <el-card class="box-card" style="width:300px;height:100%;padding: 10px;margin-left:10px;">
<CheckForm /> <CheckForm />
</el-card> --> </el-card> -->
</div> </div>
</template> </template>
<script> <script>
@ -59,7 +72,7 @@ import Preview from './components/preview'
export default { export default {
name: 'Notice', name: 'Notice',
components: { components: {
Preview Preview,
// CheckForm // CheckForm
}, },
data() { data() {
@ -76,18 +89,18 @@ export default {
popup: true, // popup: true, //
studyCode: '', studyCode: '',
modality: '', modality: '',
bodyPart: '' bodyPart: '',
}, },
previewVisible: false, previewVisible: false,
studyList: [], studyList: [],
subjectVisitId: '', subjectVisitId: '',
sudyId: '', sudyId: '',
loading: false, loading: false,
bp:[] bp: [],
} }
}, },
async created(){ async created() {
this.bp = await this.$getBodyPart(this.$route.query.trialId); this.bp = await this.$getBodyPart(this.$route.query.trialId)
}, },
async mounted() { async mounted() {
if (this.$router.currentRoute.query.TokenKey) { if (this.$router.currentRoute.query.TokenKey) {
@ -112,31 +125,47 @@ export default {
separator = '' separator = ''
} }
var arr = bodyPart.split(separator) var arr = bodyPart.split(separator)
var newArr = arr.map(i => { var newArr = arr.map((i) => {
return this.$fd('Bodypart', i.trim(),'Code',{Bodypart:this.bp},'Name') return this.$fd(
'Bodypart',
i.trim(),
'Code',
{ Bodypart: this.bp },
'Name'
)
}) })
console.log(newArr,this.bp) console.log(newArr, this.bp)
return newArr.join(' | ') return newArr.join(' | ')
}, },
// Dicom // Dicom
getNoneDicomList() { getNoneDicomList() {
this.loading = true this.loading = true
getNoneDicomStudyList(this.subjectVisitId, this.studyId).then(res => { getNoneDicomStudyList(
this.studyList = res.Result this.subjectVisitId,
this.loading = false this.studyId,
const studyIndex = this.studyList.findIndex(item => { false,
return item.NoneDicomStudyFileList.length > 0 this.$route.query.visitTaskId
)
.then((res) => {
this.studyList = res.Result
this.loading = false
const studyIndex = this.studyList.findIndex((item) => {
return item.NoneDicomStudyFileList.length > 0
})
if (studyIndex > -1) {
var fileObj = this.studyList[studyIndex]['NoneDicomStudyFileList']
this.selected(fileObj[0], studyIndex, 0, true)
}
})
.catch(() => {
this.loading = false
}) })
if (studyIndex > -1) {
var fileObj = this.studyList[studyIndex]['NoneDicomStudyFileList']
this.selected(fileObj[0], studyIndex, 0, true)
}
}).catch(() => { this.loading = false })
}, },
selected(file, studyIndex, fileIndex, isChangeSub = false) { selected(file, studyIndex, fileIndex, isChangeSub = false) {
this.currentFileId = file.Id this.currentFileId = file.Id
this.currentStudyIndex = studyIndex this.currentStudyIndex = studyIndex
this.previewImage.imgList = this.studyList[studyIndex].NoneDicomStudyFileList this.previewImage.imgList =
this.studyList[studyIndex].NoneDicomStudyFileList
this.currentStudyFileIndex = fileIndex this.currentStudyFileIndex = fileIndex
this.previewImage.index = fileIndex this.previewImage.index = fileIndex
this.previewImage.studyCode = this.studyList[studyIndex].CodeView this.previewImage.studyCode = this.studyList[studyIndex].CodeView
@ -151,11 +180,17 @@ export default {
selectedImg(fileIndex) { selectedImg(fileIndex) {
if (this.studyList.length > 0) { if (this.studyList.length > 0) {
this.currentStudyFileIndex = fileIndex this.currentStudyFileIndex = fileIndex
this.currentFileId = this.studyList[this.currentStudyIndex].NoneDicomStudyFileList[fileIndex].Id this.currentFileId =
this.studyList[this.currentStudyIndex].NoneDicomStudyFileList[
fileIndex
].Id
this.previewImage.index = fileIndex this.previewImage.index = fileIndex
this.previewImage.studyCode = this.studyList[this.currentStudyIndex].CodeView this.previewImage.studyCode =
this.previewImage.bodyPart = this.studyList[this.currentStudyIndex].BodyPart this.studyList[this.currentStudyIndex].CodeView
this.previewImage.modality = this.studyList[this.currentStudyIndex].Modality this.previewImage.bodyPart =
this.studyList[this.currentStudyIndex].BodyPart
this.previewImage.modality =
this.studyList[this.currentStudyIndex].Modality
this.$nextTick(() => { this.$nextTick(() => {
const target = document.getElementById(`img${this.currentFileId}`) const target = document.getElementById(`img${this.currentFileId}`)
const parent = document.getElementsByClassName('left-content')[0] const parent = document.getElementsByClassName('left-content')[0]
@ -165,14 +200,13 @@ export default {
}, },
preview() { preview() {
this.previewVisible = true this.previewVisible = true
} },
},
}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.img-container{ .img-container {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -186,27 +220,27 @@ export default {
border-radius: 10px; border-radius: 10px;
background: #d0d0d0; background: #d0d0d0;
} }
/deep/ .el-card__body{ /deep/ .el-card__body {
padding: 0px; padding: 0px;
} }
} }
.study-desc{ .study-desc {
padding: 15px 5px; padding: 15px 5px;
line-height: 20px; line-height: 20px;
background-color: #d5d5d5; background-color: #d5d5d5;
font-weight: 500; font-weight: 500;
} }
.left{ .left {
width:220px; width: 220px;
height: 100%; height: 100%;
/deep/ .el-card__body{ /deep/ .el-card__body {
height: 100%; height: 100%;
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.title{ .title {
height: 40px; height: 40px;
line-height: 40px; line-height: 40px;
border: 1ppx solid; border: 1ppx solid;
@ -215,7 +249,7 @@ export default {
background-color: #4e4e4e; background-color: #4e4e4e;
color: #ffffff; color: #ffffff;
} }
.left-content{ .left-content {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
} }
@ -231,21 +265,26 @@ export default {
// overflow-y: auto; // overflow-y: auto;
// padding: 0; // padding: 0;
// } // }
.img-box{ .img-box {
// position: relative; // position: relative;
display: inline-block; display: inline-block;
box-sizing: border-box; box-sizing: border-box;
border-bottom: 2px solid #f3f3f3; border-bottom: 2px solid #f3f3f3;
width: 180px;
height: 50px;
line-height: 50px;
cursor: pointer; cursor: pointer;
// margin-bottom: 5px; // margin-bottom: 5px;
padding-left: 5px; padding-left: 5px;
text-overflow:ellipsis; }
.img-text {
display: inline-block;
width: 200px;
height: 50px;
line-height: 50px;
overflow: hidden;
text-overflow: ellipsis; /* 用省略号表示溢出的文本 */
white-space: nowrap; white-space: nowrap;
} }
.img-box:nth-last-child(1){ .img-box:nth-last-child(1) {
margin-bottom: 0px; margin-bottom: 0px;
} }
.is-boxActive { .is-boxActive {
@ -256,14 +295,13 @@ export default {
opacity: 0; opacity: 0;
} }
} }
.right{ .right {
flex: 1; flex: 1;
height: 100%; height: 100%;
margin-left: 10px; margin-left: 10px;
/deep/ .el-card__body{ /deep/ .el-card__body {
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
} }
</style> </style>

View File

@ -1,76 +1,130 @@
<template> <template>
<div style="display: flex;justify-content: center"> <div style="display: flex; justify-content: center">
<div style="width: 600px;text-align: center;border: 1px solid #e6e6e6;margin-top:40px;padding:10px;"> <div
<div class="trial-myinfo-head" style="font-size: 30px;line-height: 120px;"> style="
width: 600px;
text-align: center;
border: 1px solid #e6e6e6;
margin-top: 40px;
padding: 10px;
"
>
<div
class="trial-myinfo-head"
style="font-size: 30px; line-height: 120px"
>
<!-- 首次登录修改密码 --> <!-- 首次登录修改密码 -->
{{ $t('recompose:title:init') }} {{ $t('recompose:title:init') }}
</div> </div>
<el-form ref="passwordForm" v-loading="loading" label-position="right" :model="password" :rules="passwordFormRules" label-width="120px"> <el-form
ref="passwordForm"
v-loading="loading"
label-position="right"
:model="password"
:rules="passwordFormRules"
:label-width="$i18n.locale === 'en' ? '180px' : '120px'"
>
<!-- 用户名 --> <!-- 用户名 -->
<el-form-item :label="$t('recompose:form:userName')" prop="NewUserName"> <el-form-item :label="$t('recompose:form:userName')" prop="NewUserName">
<el-input v-model="password.NewUserName" /> <el-input v-model="password.NewUserName" />
</el-form-item> </el-form-item>
<!-- 旧密码 --> <!-- 旧密码 -->
<el-form-item :label="$t('recompose:form:oldPassword')" prop="OldPassWord"> <el-form-item
<el-input v-model="password.OldPassWord" type="password" show-password auto-complete="new-password" /> :label="$t('recompose:form:oldPassword')"
prop="OldPassWord"
>
<el-input
v-model="password.OldPassWord"
type="password"
show-password
auto-complete="new-password"
/>
</el-form-item> </el-form-item>
<!-- 新密码 --> <!-- 新密码 -->
<el-form-item :label="$t('recompose:form:newPassword')" prop="NewPassWord"> <el-form-item
<el-input v-model="password.NewPassWord" type="password" show-password auto-complete="new-password" /> :label="$t('recompose:form:newPassword')"
prop="NewPassWord"
>
<el-input
v-model="password.NewPassWord"
type="password"
show-password
auto-complete="new-password"
/>
</el-form-item> </el-form-item>
<!-- 确认密码 --> <!-- 确认密码 -->
<el-form-item :label="$t('recompose:form:confirmPassword')" prop="ConfirmPassWord"> <el-form-item
<el-input v-model="password.ConfirmPassWord" type="password" show-password auto-complete="new-password" /> :label="$t('recompose:form:confirmPassword')"
prop="ConfirmPassWord"
>
<el-input
v-model="password.ConfirmPassWord"
type="password"
show-password
auto-complete="new-password"
/>
</el-form-item> </el-form-item>
<el-form-item style="text-align:right"> <el-form-item style="text-align: right">
<!-- 取消 --> <!-- 取消 -->
<el-button <el-button size="small" @click="cancel">
size="small"
@click="cancel"
>
{{ $t('recompose:button:cancel') }} {{ $t('recompose:button:cancel') }}
</el-button> </el-button>
<!-- 保存 --> <!-- 保存 -->
<el-button <el-button type="primary" size="small" @click="save">
type="primary"
size="small"
@click="save"
>
{{ $t('recompose:button:save') }} {{ $t('recompose:button:save') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { modifyPassword } from '@/api/admin.js' import { modifyPassword } from '@/api/admin.js'
import md5 from 'js-md5' import md5 from 'js-md5'
import {mapMutations} from "vuex"; import { mapMutations } from 'vuex'
export default { export default {
data() { data() {
return { return {
password: { password: {
NewUserName: null NewUserName: null,
}, },
passwordFormRules: { passwordFormRules: {
NewUserName: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }], NewUserName: [
OldPassWord: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }], {
required: true,
message: this.$t('common:ruleMessage:specify'),
trigger: 'blur',
},
],
OldPassWord: [
{
required: true,
message: this.$t('common:ruleMessage:specify'),
trigger: 'blur',
},
],
NewPassWord: [ NewPassWord: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }, {
required: true,
message: this.$t('common:ruleMessage:specify'),
trigger: 'blur',
},
{ {
required: true, required: true,
trigger: 'blur', trigger: 'blur',
validator: this.$validatePassword validator: this.$validatePassword,
}, },
], ],
ConfirmPassWord: [ ConfirmPassWord: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }, {
] required: true,
message: this.$t('common:ruleMessage:specify'),
trigger: 'blur',
},
],
}, },
userId: null, userId: null,
loading: false loading: false,
} }
}, },
mounted() { mounted() {
@ -78,7 +132,6 @@ export default {
if (!this.password.NewUserName) { if (!this.password.NewUserName) {
// 使 // 使
this.$alert(this.$t('recompose:message:warning')) this.$alert(this.$t('recompose:message:warning'))
} }
}, },
methods: { methods: {
@ -96,7 +149,7 @@ export default {
this.$updateDictionary() this.$updateDictionary()
}, },
save() { save() {
this.$refs.passwordForm.validate(valid => { this.$refs.passwordForm.validate((valid) => {
if (valid) { if (valid) {
if (this.password.NewPassWord !== this.password.ConfirmPassWord) { if (this.password.NewPassWord !== this.password.ConfirmPassWord) {
// //
@ -106,58 +159,64 @@ export default {
const param = { const param = {
NewUserName: this.password.NewUserName, NewUserName: this.password.NewUserName,
NewPassWord: md5(this.password.NewPassWord), NewPassWord: md5(this.password.NewPassWord),
OldPassWord: md5(this.password.OldPassWord) OldPassWord: md5(this.password.OldPassWord),
} }
this.loading = true this.loading = true
modifyPassword(param).then(res => { modifyPassword(param)
this.loading = false .then((res) => {
if (res.IsSuccess) { this.loading = false
// , if (res.IsSuccess) {
this.$message.success(this.$t('recompose:message:updatedSuccessfully')) // ,
setTimeout(() => { this.$message.success(
this.logout() this.$t('recompose:message:updatedSuccessfully')
}, 500) )
} setTimeout(() => {
}).catch(() => { this.loading = false }) this.logout()
}, 500)
}
})
.catch(() => {
this.loading = false
})
} }
}) })
}, },
cancel() { cancel() {
this.$refs['passwordForm'].resetFields() this.$refs['passwordForm'].resetFields()
} },
} },
} }
</script> </script>
<style> <style>
.reset-wrapper { .reset-wrapper {
padding: 20px; padding: 20px;
} }
.reset-wrapper .el-page-header { .reset-wrapper .el-page-header {
line-height: 50px; line-height: 50px;
border: 1px solid #ebeef5; border: 1px solid #ebeef5;
border-radius: 4px; border-radius: 4px;
background-color: #fff; background-color: #fff;
} }
.reset-wrapper .box-wrapper { .reset-wrapper .box-wrapper {
width: 60%; width: 60%;
margin: 20px auto; margin: 20px auto;
padding: 10px; padding: 10px;
color: #303133; color: #303133;
} }
</style> </style>
<style scoped> <style scoped>
::v-deep .is-error{ ::v-deep .is-error {
margin-bottom: 40px; margin-bottom: 40px;
} }
input:-webkit-autofill { input:-webkit-autofill {
-webkit-text-fill-color: #ededed !important; -webkit-text-fill-color: #ededed !important;
box-shadow: 0 0 0px 1000px transparent inset !important; box-shadow: 0 0 0px 1000px transparent inset !important;
background-color:transparent; background-color: transparent;
background-image: none; background-image: none;
transition: background-color 50000s ease-in-out 0s; transition: background-color 50000s ease-in-out 0s;
} }
input { input {
background-color:transparent; background-color: transparent;
caret-color: #fff; caret-color: #fff;
} }
</style> </style>

View File

@ -41,8 +41,8 @@
</el-form-item> </el-form-item>
<!-- 阅片标准 --> <!-- 阅片标准 -->
<el-form-item <el-form-item
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')"
v-if="hasPermi(['role:ir'])" v-if="hasPermi(['role:ir'])"
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')"
> >
<el-select <el-select
v-model="searchData.CriterionType" v-model="searchData.CriterionType"
@ -59,8 +59,8 @@
</el-form-item> </el-form-item>
<!-- 联系人 --> <!-- 联系人 -->
<el-form-item <el-form-item
:label="$t('trials:trials-list:table:IR_PMEmailList')"
v-if="hasPermi(['role:ir'])" v-if="hasPermi(['role:ir'])"
:label="$t('trials:trials-list:table:IR_PMEmailList')"
> >
<el-input <el-input
v-model="searchData.PM_EMail" v-model="searchData.PM_EMail"
@ -293,9 +293,10 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="handleSelectSearch" <el-button
>Search</el-button type="primary"
> @click="handleSelectSearch"
>Search</el-button>
<el-button type="primary" @click="handleReset">Reset</el-button> <el-button type="primary" @click="handleReset">Reset</el-button>
<el-button type="primary" @click="isShow = false">Back</el-button> <el-button type="primary" @click="isShow = false">Back</el-button>
</el-form-item> </el-form-item>
@ -357,23 +358,19 @@
<el-tag <el-tag
v-if="scope.row.TrialStatusStr === 'Initializing'" v-if="scope.row.TrialStatusStr === 'Initializing'"
type="info" type="info"
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag >{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag>
>
<el-tag <el-tag
v-if="scope.row.TrialStatusStr === 'Ongoing'" v-if="scope.row.TrialStatusStr === 'Ongoing'"
type="primary" type="primary"
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag >{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag>
>
<el-tag <el-tag
v-if="scope.row.TrialStatusStr === 'Completed'" v-if="scope.row.TrialStatusStr === 'Completed'"
type="warning" type="warning"
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag >{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag>
>
<el-tag <el-tag
v-if="scope.row.TrialStatusStr === 'Stopped'" v-if="scope.row.TrialStatusStr === 'Stopped'"
type="danger" type="danger"
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag >{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag>
>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -582,7 +579,7 @@
:disabled=" :disabled="
(scope.row.TrialStatusStr === 'Initializing' && (scope.row.TrialStatusStr === 'Initializing' &&
!hasPermi(['role:pm'])) || !hasPermi(['role:pm'])) ||
scope.row.IsDeleted scope.row.IsDeleted || ((scope.row.TrialStatusStr === 'Completed' || scope.row.TrialStatusStr === 'Stopped') && !(hasPermi(['role:qa']) || hasPermi(['role:ea']) || hasPermi(['role:pm'])))
" "
:title="$t('trials:trials-list:action:panel')" :title="$t('trials:trials-list:action:panel')"
@click.stop="handleDetail(scope.row)" @click.stop="handleDetail(scope.row)"
@ -612,7 +609,7 @@
icon="el-icon-delete" icon="el-icon-delete"
:disabled=" :disabled="
scope.row.IsDeleted || scope.row.IsDeleted ||
scope.row.TrialStatusStr !== 'Initializing' scope.row.TrialStatusStr !== 'Initializing'
" "
:title="$t('trials:trials-list:action:abolition')" :title="$t('trials:trials-list:action:abolition')"
@click.stop="handleAbandon(scope.row)" @click.stop="handleAbandon(scope.row)"
@ -693,54 +690,54 @@
import { import {
abandonTrial, abandonTrial,
ifTrialCanOngoing, ifTrialCanOngoing,
getTrialToBeDoneList, getTrialToBeDoneList
} from "@/api/trials"; } from '@/api/trials'
import { getTrialList_Export } from "@/api/export"; import { getTrialList_Export } from '@/api/export'
import store from "@/store"; import store from '@/store'
import { mapGetters } from "vuex"; import { mapGetters } from 'vuex'
import BaseContainer from "@/components/BaseContainer"; import BaseContainer from '@/components/BaseContainer'
import Pagination from "@/components/Pagination"; import Pagination from '@/components/Pagination'
import TrialForm from "./components/TrialForm"; import TrialForm from './components/TrialForm'
import TrialStatusForm from "./components/TrialStatusForm"; import TrialStatusForm from './components/TrialStatusForm'
import DoneList from "./components/DoneList"; import DoneList from './components/DoneList'
const searchDataDefault = () => { const searchDataDefault = () => {
return { return {
Code: "", Code: '',
CriterionIds: [], CriterionIds: [],
SponsorId: "", SponsorId: '',
ReviewTypeIds: [], ReviewTypeIds: [],
CROId: "", CROId: '',
Expedited: "", Expedited: '',
Indication: "", Indication: '',
Phase: "", Phase: '',
ModalityIds: [], ModalityIds: [],
BeginDate: "", BeginDate: '',
EndDate: "", EndDate: '',
AttendedReviewerType: "", AttendedReviewerType: '',
ResearchProgramNo: "", ResearchProgramNo: '',
ExperimentName: "", ExperimentName: '',
PageIndex: 1, PageIndex: 1,
PageSize: 20, PageSize: 20,
Asc: false, Asc: false,
SortField: "", SortField: '',
CriterionType: null, CriterionType: null,
PM_EMail: null, PM_EMail: null
}; }
}; }
export default { export default {
name: "Trials", name: 'Trials',
components: { components: {
Pagination, Pagination,
BaseContainer, BaseContainer,
TrialForm, TrialForm,
TrialStatusForm, TrialStatusForm,
DoneList, DoneList
}, },
dicts: ["ReadingStandard", "ReviewType", "ReadingType"], dicts: ['ReadingStandard', 'ReviewType', 'ReadingType'],
data() { data() {
return { return {
exportLoading: false, exportLoading: false,
userTypeEnumInt: zzSessionStorage.getItem("userTypeEnumInt") * 1, userTypeEnumInt: zzSessionStorage.getItem('userTypeEnumInt') * 1,
doneDialogVisible: false, doneDialogVisible: false,
doneTitle: null, doneTitle: null,
selectArr: [], selectArr: [],
@ -750,26 +747,26 @@ export default {
total: 0, total: 0,
isShow: false, isShow: false,
dialogVisible: false, dialogVisible: false,
title: "", title: '',
currentId: "", currentId: '',
statusVisible: false, statusVisible: false,
currentRow: {}, currentRow: {},
currentUser: zzSessionStorage.getItem("userName"), currentUser: zzSessionStorage.getItem('userName'),
phaseOptions: [ phaseOptions: [
{ value: "I" }, { value: 'I' },
{ value: "II" }, { value: 'II' },
{ value: "III" }, { value: 'III' },
{ value: "IV" }, { value: 'IV' }
], ],
expeditedOption: this.$d.TrialExpeditedState, expeditedOption: this.$d.TrialExpeditedState,
beginPickerOption: { beginPickerOption: {
disabledDate: (time) => { disabledDate: (time) => {
if (this.searchData.EndDate) { if (this.searchData.EndDate) {
return time.getTime() > new Date(this.searchData.EndDate).getTime(); return time.getTime() > new Date(this.searchData.EndDate).getTime()
} else { } else {
return time.getTime() > Date.now(); return time.getTime() > Date.now()
} }
}, }
}, },
endpickerOption: { endpickerOption: {
disabledDate: (time) => { disabledDate: (time) => {
@ -777,306 +774,189 @@ export default {
return ( return (
time.getTime() > Date.now() || time.getTime() > Date.now() ||
time.getTime() <= new Date(this.searchData.BeginDate).getTime() time.getTime() <= new Date(this.searchData.BeginDate).getTime()
); )
} else { } else {
return time.getTime() > Date.now(); return time.getTime() > Date.now()
} }
}, }
}, }
}; }
}, },
computed: { computed: {
...mapGetters(["sponsorList", "croList"]), ...mapGetters(['sponsorList', 'croList'])
}, },
created() { created() {
this.initPage(); this.initPage()
}, },
methods: { methods: {
initPage() { initPage() {
this.getList(); this.getList()
store.dispatch("global/getSponsorList"); store.dispatch('global/getSponsorList')
store.dispatch("global/getCROList"); store.dispatch('global/getCROList')
}, },
// //
getList() { getList() {
this.listLoading = true; this.listLoading = true
getTrialToBeDoneList(this.searchData) getTrialToBeDoneList(this.searchData)
.then((res) => { .then((res) => {
this.list = res.Result.CurrentPageData; this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount; this.total = res.Result.TotalCount
this.listLoading = false; this.listLoading = false
}) })
.catch(() => { .catch(() => {
this.listLoading = false; this.listLoading = false
}); })
}, },
// //
handleSearch() { handleSearch() {
this.searchData.PageIndex = 1; this.searchData.PageIndex = 1
this.getList(); this.getList()
}, },
// //
handleSelectSearch() { handleSelectSearch() {
this.searchData.PageIndex = 1; this.searchData.PageIndex = 1
this.getList(); this.getList()
this.isShow = false; this.isShow = false
}, },
// //
handleReset() { handleReset() {
this.searchData = searchDataDefault(); this.searchData = searchDataDefault()
this.getList(); this.getList()
}, },
// //
handleNew() { handleNew() {
// this.$router.push({ name: 'CreateTrial' }) // this.$router.push({ name: 'CreateTrial' })
this.title = this.$t("trials:trials-list:dialogTitle:new"); this.title = this.$t('trials:trials-list:dialogTitle:new')
this.currentId = ""; this.currentId = ''
this.dialogVisible = true; this.dialogVisible = true
}, },
// //
handleEdit(row) { handleEdit(row) {
this.title = this.$t("trials:trials-list:dialogTitle:edit"); this.title = this.$t('trials:trials-list:dialogTitle:edit')
this.currentId = row.Id; this.currentId = row.Id
this.dialogVisible = true; this.dialogVisible = true
}, },
handleCommission(row) { handleCommission(row) {
this.doneTitle = this.$t("trials:trials-list:dialogTitle:doneTitle"); this.doneTitle = this.$t('trials:trials-list:dialogTitle:doneTitle')
this.currentId = row.Id; this.currentId = row.Id
this.doneDialogVisible = true; this.doneDialogVisible = true
}, },
closeDialog() { closeDialog() {
this.dialogVisible = false; this.dialogVisible = false
}, },
// //
handleStatus(row) { handleStatus(row) {
if (row.TrialStatusStr === "Initializing") { if (row.TrialStatusStr === 'Initializing') {
this.listLoading = true; this.listLoading = true
ifTrialCanOngoing(row.Id) ifTrialCanOngoing(row.Id)
.then((res) => { .then((res) => {
this.listLoading = false; this.listLoading = false
if (res.Result) { if (res.Result) {
this.currentRow = { ...row }; this.currentRow = { ...row }
this.statusVisible = true; this.statusVisible = true
} else { } else {
this.$confirm(res.ErrorMessage, { this.$confirm(res.ErrorMessage, {
type: "warning", type: 'warning',
showCancelButton: false, showCancelButton: false,
callback: (action) => {}, callback: (action) => {}
}); })
} }
}) })
.catch(() => { .catch(() => {
this.listLoading = false; this.listLoading = false
}); })
} else { } else {
this.currentRow = { ...row }; this.currentRow = { ...row }
this.statusVisible = true; this.statusVisible = true
} }
}, },
closeStatusDialog() { closeStatusDialog() {
this.statusVisible = false; this.statusVisible = false
}, },
// //
handleAbandon(row) { handleAbandon(row) {
this.$confirm(this.$t("trials:trials-list:message:abolition"), { this.$confirm(this.$t('trials:trials-list:message:abolition'), {
type: "warning", type: 'warning',
distinguishCancelAndClose: true, distinguishCancelAndClose: true
}) })
.then(() => { .then(() => {
this.currentRow = { ...row }; this.currentRow = { ...row }
this.abandonTrial(); this.abandonTrial()
}) })
.catch(() => {}); .catch(() => {})
}, },
// //
abandonTrial() { abandonTrial() {
this.listLoading = true; this.listLoading = true
abandonTrial(this.currentRow.Id, true) abandonTrial(this.currentRow.Id, true)
.then((res) => { .then((res) => {
this.listLoading = false; this.listLoading = false
if (res.IsSuccess) { if (res.IsSuccess) {
this.getList(); this.getList()
this.$message.success( this.$message.success(
this.$t("trials:trials-list:message:abolitionSuccessfully") this.$t('trials:trials-list:message:abolitionSuccessfully')
); )
} }
}) })
.catch(() => { .catch(() => {
this.listLoading = false; this.listLoading = false
}); })
}, },
rowClick(row, col) { rowClick(row, col) {
if ( if ((row.TrialStatusStr === 'Initializing' && !this.hasPermi(['role:pm'])) || row.IsDeleted) {
(row.TrialStatusStr === "Initializing" && return
!this.hasPermi(["role:pm"])) || } else if ((row.TrialStatusStr === 'Completed' || row.TrialStatusStr === 'Stopped') && !(this.hasPermi(['role:qa']) || this.hasPermi(['role:ea']) || this.hasPermi(['role:pm']))) {
row.IsDeleted return
) }
return;
this.$router.push({ this.$router.push({
path: `/trials/trials-panel?trialId=${row.Id}&trialCode=${row.TrialCode}&researchProgramNo=${row.ResearchProgramNo}`, path: `/trials/trials-panel?trialId=${row.Id}&trialCode=${row.TrialCode}&researchProgramNo=${row.ResearchProgramNo}`
}); })
}, },
// panel // panel
handleDetail(row) { handleDetail(row) {
this.$router.push({ this.$router.push({
path: `/trials/trials-panel?trialId=${row.Id}&trialCode=${row.TrialCode}&researchProgramNo=${row.ResearchProgramNo}`, path: `/trials/trials-panel?trialId=${row.Id}&trialCode=${row.TrialCode}&researchProgramNo=${row.ResearchProgramNo}`
}); })
}, },
// //
handleSelectChange(val) { handleSelectChange(val) {
const arr = []; const arr = []
for (let index = 0; index < val.length; index++) { for (let index = 0; index < val.length; index++) {
arr.push(val[index]); arr.push(val[index])
} }
this.selectArr = arr; this.selectArr = arr
}, },
// //
handleSortChange(column) { handleSortChange(column) {
if (column.order === "ascending") { if (column.order === 'ascending') {
this.searchData.Asc = true; this.searchData.Asc = true
} else { } else {
this.searchData.Asc = false; this.searchData.Asc = false
} }
if (column.prop === "Criterion") { if (column.prop === 'Criterion') {
this.searchData.SortField = "CriterionId"; this.searchData.SortField = 'CriterionId'
} else { } else {
this.searchData.SortField = column.prop; this.searchData.SortField = column.prop
} }
this.searchData.PageIndex = 1; this.searchData.PageIndex = 1
this.getList(); this.getList()
}, },
// Excel // Excel
handleExportTrial() { handleExportTrial() {
this.exportLoading = true; this.exportLoading = true
let data = { const data = {
...this.searchData, ...this.searchData
}; }
data.TrialIdList = this.selectArr.map((item) => item.Id); data.TrialIdList = this.selectArr.map((item) => item.Id)
return getTrialList_Export(data) return getTrialList_Export(data)
.then((res) => { .then((res) => {
this.exportLoading = false; this.exportLoading = false
}) })
.catch(() => { .catch(() => {
this.exportLoading = false; this.exportLoading = false
});
this.selectArr.forEach((element, index) => {
// element.ExpeditedStr = element.Expedited === 0 ? 'No' : element.Expedited === 1 ? '24H' : '48H'
// element.ModalityListStr = element.ModalityList.join(', ')
// element.CreateTimeStr = element.CreateTime
// element.Criterion = element.CriterionList.join(', ')
element.Deleted = element.IsDeleted ? "Yes" : "No";
element.Index = index + 1;
});
var workbook = new Excel.Workbook();
var sheet = workbook.addWorksheet("Trials");
sheet.properties.defaultRowHeight = 22;
// sheet.columns = [
// { key: 'Index', width: 5 },
// { key: 'Code', width: 15 },
// { key: 'ExpeditedStr', width: 13 },
// { key: 'TrialStatusStr', width: 10 },
// { key: 'Indication', width: 25 },
// { key: 'Phase', width: 10 },
// { key: 'ReviewType', width: 20 },
// { key: 'Criterion', width: 15 },
// { key: 'ModalityListStr', width: 30 },
// { key: 'CRO', width: 10 },
// { key: 'Sponsor', width: 20 },
// { key: 'CreateTimeStr', width: 18 }
// ]
sheet.columns = [
{ key: "Index", width: 5 },
{ key: "TrialCode", width: 25 },
{ key: "ExperimentName", width: 25 },
{ key: "ResearchProgramNo", width: 25 },
{ key: "Sponsor", width: 25 },
{ key: "Deleted", width: 10 },
{ key: "CreateTime", width: 25 },
];
//
sheet.mergeCells("A1", "G2");
sheet.getCell("A1").value = "Trials";
sheet.getCell("A1").alignment = {
vertical: "middle",
horizontal: "center",
};
sheet.getCell("A1").font = {
name: "SimSun",
family: 4,
size: 13,
bold: true,
};
sheet.mergeCells("A3", "G3");
var now = new Date();
sheet.getCell("A3").value = now.toLocaleDateString();
sheet.getCell("A3").alignment = {
vertical: "middle",
horizontal: "right",
};
sheet.getRow(4).values = [
"NO.",
"Trial ID",
"试验名称",
"研究方案号",
"申办方",
"是否废除",
"Date Created",
];
sheet.getRow(4).font = {
name: "SimSun",
family: 4,
size: 11,
bold: true,
};
sheet.getRow(4).alignment = { vertical: "middle", horizontal: "left" };
sheet.addRows(this.selectArr);
sheet.eachRow((row, number) => {
if (number > 3) {
row.eachCell((cell, rowNumber) => {
cell.alignment = { vertical: "center", horizontal: "left" };
cell.border = {
top: { style: "thin" },
left: { style: "thin" },
bottom: { style: "thin" },
right: { style: "thin" },
};
});
}
});
workbook.xlsx
.writeBuffer({
base64: true,
}) })
.then(function (xls64) { }
var data = new Blob([xls64], { }
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }
});
if ("msSaveOrOpenBlob" in navigator) {
// ie使
window.navigator.msSaveOrOpenBlob(data, "Trials" + ".xlsx");
} else {
var a = document.createElement("a");
var url = URL.createObjectURL(data);
a.href = url;
a.download = "Trials" + ".xlsx";
document.body.appendChild(a);
a.click();
setTimeout(function () {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
});
},
},
};
</script> </script>

View File

@ -54,8 +54,8 @@
j.armEnum === 1 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" align="center"
prop="" prop=""
@ -81,18 +81,17 @@
scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i] scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i]
.DictionaryCode .DictionaryCode
" "
>{{ >{{
$fd( $fd(
scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[ scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[
i i
].DictionaryCode, ].DictionaryCode,
parseInt( parseInt(
scope.row.VisitTaskInfoList[j.index] scope.row.VisitTaskInfoList[j.index]
.JudgeQuestionList[i].Answer .JudgeQuestionList[i].Answer
)
) )
}}</span )
> }}</span>
<span v-else>{{ <span v-else>{{
scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i] scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i]
.Answer .Answer
@ -321,7 +320,7 @@
alt="" alt=""
crossorigin="anonymous" crossorigin="anonymous"
style="max-width: 100%; max-height: 100%" 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" class="el-upload-list__item-preview"
@ -435,88 +434,87 @@ import {
// uploadJudgeTaskImage, // uploadJudgeTaskImage,
saveJudgeVisitTaskResult, saveJudgeVisitTaskResult,
submitJudgeVisitTaskResult, submitJudgeVisitTaskResult,
getReadingPastResultList, getReadingPastResultList
} from "@/api/trials"; } from '@/api/trials'
import { getAutoCutNextTask } from "@/api/user"; import { getAutoCutNextTask } from '@/api/user'
import { setSkipReadingCache } from "@/api/reading"; import { setSkipReadingCache } from '@/api/reading'
import const_ from "@/const/sign-code"; import const_ from '@/const/sign-code'
import { getToken } from "@/utils/auth"; import { getToken } from '@/utils/auth'
import SignForm from "@/views/trials/components/newSignForm"; import SignForm from '@/views/trials/components/newSignForm'
import DicomEvent from "@/views/trials/trials-panel/reading/dicoms/components/DicomEvent"; import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
// import store from '@/store' // import store from '@/store'
import { changeURLStatic } from "@/utils/history.js"; import { changeURLStatic } from '@/utils/history.js'
import Viewer from "v-viewer";
export default { export default {
name: "AdReview", name: 'AdReview',
components: { SignForm }, components: { SignForm },
props: { props: {
trialId: { trialId: {
type: String, type: String,
required: true, required: true
}, },
subjectId: { subjectId: {
type: String, type: String,
required: true, required: true
}, },
visitTaskId: { visitTaskId: {
type: String, type: String,
required: true, required: true
}, },
readingCategory: { readingCategory: {
type: Number, type: Number,
required: true, required: true
}, },
subjectCode: { subjectCode: {
type: String, type: String,
required: true, required: true
}, },
taskBlindName: { taskBlindName: {
type: String, type: String,
required: true, required: true
}, },
isReadingShowSubjectInfo: { isReadingShowSubjectInfo: {
type: Boolean, type: Boolean,
required: true, required: true
}, },
isReadingShowPreviousResults: { isReadingShowPreviousResults: {
type: Boolean, type: Boolean,
required: true, required: true
}, },
isExistsClinicalData: { isExistsClinicalData: {
type: Boolean, type: Boolean,
required: true, required: true
}, }
}, },
data() { data() {
return { return {
adInfo: {}, adInfo: {},
judgeQuestion: [], judgeQuestion: [],
adForm: { adForm: {
visitTaskId: "", visitTaskId: '',
judgeResultTaskId: "", judgeResultTaskId: '',
judgeResultRemark: "", judgeResultRemark: '',
// judgeResultImagePath: '' // judgeResultImagePath: ''
judgeResultImagePathList: [], judgeResultImagePathList: []
}, },
currentUser: zzSessionStorage.getItem("userName"), currentUser: zzSessionStorage.getItem('userName'),
signVisible: false, signVisible: false,
signCode: null, signCode: null,
accept: ".png,.jpg,.jpeg", accept: '.png,.jpg,.jpeg',
imgVisible: false, imgVisible: false,
imageUrl: "", imageUrl: '',
uploadDisabled: false, uploadDisabled: false,
fileList: [], fileList: [],
loading: false, loading: false,
visitTaskArmList: [], visitTaskArmList: [],
priorADList: [], priorADList: [],
priorLoading: false, priorLoading: false,
judgeResultArmEnum: "", judgeResultArmEnum: '',
criterionType: null, criterionType: null,
openWindow: null, openWindow: null,
isFixed: false, isFixed: false,
images: [], images: [],
remark: "", remark: ''
}; }
}, },
// watch: { // watch: {
// visitTaskId: { // visitTaskId: {
@ -532,261 +530,260 @@ export default {
// } // }
// }, // },
mounted() { mounted() {
this.initializeViewer(); this.criterionType = parseInt(this.$route.query.criterionType)
this.criterionType = parseInt(this.$route.query.criterionType); this.getAdInfo()
this.getAdInfo();
if (this.isReadingShowPreviousResults) { if (this.isReadingShowPreviousResults) {
this.getPriorAdList(); this.getPriorAdList()
} }
DicomEvent.$on("resetOpenWindow", () => { DicomEvent.$on('resetOpenWindow', () => {
if (this.openWindow) { if (this.openWindow) {
this.openWindow.close(); this.openWindow.close()
} }
}); })
}, },
beforeDestroy() { beforeDestroy() {
DicomEvent.$off("resetOpenWindow"); DicomEvent.$off('resetOpenWindow')
if (this.openWindow) { if (this.openWindow) {
this.openWindow.close(); this.openWindow.close()
} }
}, },
methods: { methods: {
async getAdInfo() { async getAdInfo() {
this.loading = true; this.loading = true
try { try {
const res = await getJudgeReadingInfo({ const res = await getJudgeReadingInfo({
visitTaskId: this.visitTaskId, visitTaskId: this.visitTaskId
}); })
if (res.IsSuccess) { if (res.IsSuccess) {
var judgeQS = []; var judgeQS = []
if (res.Result.VisitInfoList.length > 0) { if (res.Result.VisitInfoList.length > 0) {
res.Result.VisitInfoList[0].VisitTaskInfoList.map((v, index) => { res.Result.VisitInfoList[0].VisitTaskInfoList.map((v, index) => {
var qsObj = { var qsObj = {
armEnum: v.ArmEnum, armEnum: v.ArmEnum,
judgeQuestionList: [], judgeQuestionList: [],
index: index, index: index
}; }
v.JudgeQuestionList.map((q) => { v.JudgeQuestionList.map((q) => {
if (q.QuestionType === 1) { if (q.QuestionType === 1) {
qsObj.judgeQuestionList.push(q.QuestionName); qsObj.judgeQuestionList.push(q.QuestionName)
} else if (q.QuestionType === 3 && this.criterionType === 10) { } else if (q.QuestionType === 3 && this.criterionType === 10) {
qsObj.judgeQuestionList.push( qsObj.judgeQuestionList.push(
this.$t("trials:globalReview:table:visitRemark") this.$t('trials:globalReview:table:visitRemark')
); )
} else { } else {
qsObj.judgeQuestionList.push( qsObj.judgeQuestionList.push(
this.$fd("JudgeReadingQuestionType", q.QuestionType) this.$fd('JudgeReadingQuestionType', q.QuestionType)
); )
} }
}); })
judgeQS.push(qsObj); judgeQS.push(qsObj)
}); })
} }
this.judgeQuestion = judgeQS; this.judgeQuestion = judgeQS
this.isFixed = this.isFixed =
this.judgeQuestion.length > 0 && this.judgeQuestion.length > 0 &&
this.judgeQuestion[0].judgeQuestionList.length > 4; this.judgeQuestion[0].judgeQuestionList.length > 4
this.adInfo = res.Result; this.adInfo = res.Result
this.adForm.judgeResultTaskId = res.Result.JudgeResultTaskId; this.adForm.judgeResultTaskId = res.Result.JudgeResultTaskId
this.fileList = []; this.fileList = []
if (res.Result.JudgeResultImagePathList) { if (res.Result.JudgeResultImagePathList) {
res.Result.JudgeResultImagePathList.map((url) => { res.Result.JudgeResultImagePathList.map((url) => {
if (url) { if (url) {
this.fileList.push({ name: "", url: url }); this.fileList.push({ name: '', url: url })
} }
}); })
this.adForm.judgeResultImagePathList = this.adForm.judgeResultImagePathList =
res.Result.JudgeResultImagePathList; res.Result.JudgeResultImagePathList
} }
this.visitTaskArmList = res.Result.VisitTaskArmList; this.visitTaskArmList = res.Result.VisitTaskArmList
var i = this.visitTaskArmList.findIndex( var i = this.visitTaskArmList.findIndex(
(i) => i.VisitTaskId === this.adForm.judgeResultTaskId (i) => i.VisitTaskId === this.adForm.judgeResultTaskId
); )
if (i > -1) { if (i > -1) {
// R1 // R1
this.judgeResultArmEnum = this.visitTaskArmList[i].ArmEnum; this.judgeResultArmEnum = this.visitTaskArmList[i].ArmEnum
var msg = ""; var msg = ''
if (this.judgeResultArmEnum === 1) { if (this.judgeResultArmEnum === 1) {
msg = this.$t("trials:adReview:title:msg1"); msg = this.$t('trials:adReview:title:msg1')
} else if (this.judgeResultArmEnum === 2) { } else if (this.judgeResultArmEnum === 2) {
msg = this.$t("trials:adReview:title:msg3"); msg = this.$t('trials:adReview:title:msg3')
} }
this.remark = msg; this.remark = msg
this.adForm.judgeResultRemark = res.Result.JudgeResultRemark; this.adForm.judgeResultRemark = res.Result.JudgeResultRemark
} }
} }
this.loading = false; this.loading = false
} catch (e) { } catch (e) {
this.loading = false; this.loading = false
} }
}, },
async getPriorAdList() { async getPriorAdList() {
this.priorLoading = true; this.priorLoading = true
try { try {
const res = await getReadingPastResultList({ const res = await getReadingPastResultList({
visitTaskId: this.visitTaskId, visitTaskId: this.visitTaskId
}); })
if (res.IsSuccess) { if (res.IsSuccess) {
this.priorADList = res.Result; this.priorADList = res.Result
} }
this.priorLoading = false; this.priorLoading = false
} catch (e) { } catch (e) {
this.priorLoading = false; this.priorLoading = false
} }
}, },
handleVisitTaskArmChange(v) { handleVisitTaskArmChange(v) {
var i = this.visitTaskArmList.findIndex((i) => i.VisitTaskId === v); var i = this.visitTaskArmList.findIndex((i) => i.VisitTaskId === v)
if (i > -1) { if (i > -1) {
// R1 // R1
this.judgeResultArmEnum = this.visitTaskArmList[i].ArmEnum; this.judgeResultArmEnum = this.visitTaskArmList[i].ArmEnum
var msg = ""; var msg = ''
if (this.judgeResultArmEnum === 1) { if (this.judgeResultArmEnum === 1) {
msg = this.$t("trials:adReview:title:msg1"); msg = this.$t('trials:adReview:title:msg1')
} else { } else {
msg = this.$t("trials:adReview:title:msg3"); msg = this.$t('trials:adReview:title:msg3')
} }
// this.adForm.judgeResultRemark = `${this.$fd('ArmEnum', this.judgeResultArmEnum)}` // this.adForm.judgeResultRemark = `${this.$fd('ArmEnum', this.judgeResultArmEnum)}`
this.remark = msg; this.remark = msg
this.adForm.judgeResultRemark = ""; this.adForm.judgeResultRemark = ''
} else { } else {
this.judgeResultArmEnum = ""; this.judgeResultArmEnum = ''
this.remark = ""; this.remark = ''
this.adForm.judgeResultRemark = ""; this.adForm.judgeResultRemark = ''
} }
}, },
previewCD() { previewCD() {
var token = getToken(); var token = getToken()
const routeData = this.$router.resolve({ const routeData = this.$router.resolve({
path: `/clinicalData?subjectId=${this.subjectId}&trialId=${this.trialId}&visitTaskId=${this.visitTaskId}&TokenKey=${token}`, path: `/clinicalData?subjectId=${this.subjectId}&trialId=${this.trialId}&visitTaskId=${this.visitTaskId}&TokenKey=${token}`
}); })
window.open(routeData.href, "_blank"); window.open(routeData.href, '_blank')
}, },
async handleSave() { async handleSave() {
const valid = await this.$refs["adForm"].validate(); const valid = await this.$refs['adForm'].validate()
if (!valid) return; if (!valid) return
this.loading = true; this.loading = true
var paths = []; var paths = []
this.fileList.map((file) => { this.fileList.map((file) => {
if (file.url) { if (file.url) {
paths.push(file.url); paths.push(file.url)
} }
}); })
this.adForm.judgeResultImagePathList = paths; this.adForm.judgeResultImagePathList = paths
this.adForm.visitTaskId = this.visitTaskId; this.adForm.visitTaskId = this.visitTaskId
try { try {
await saveJudgeVisitTaskResult(this.adForm); await saveJudgeVisitTaskResult(this.adForm)
this.$message.success(this.$t("common:message:savedSuccessfully")); this.$message.success(this.$t('common:message:savedSuccessfully'))
this.loading = false; this.loading = false
} catch (e) { } catch (e) {
this.loading = false; this.loading = false
} }
}, },
async handleSubmit() { async handleSubmit() {
const valid = await this.$refs["adForm"].validate(); const valid = await this.$refs['adForm'].validate()
if (!valid) return; if (!valid) return
const { ImageAssessmentReportConfirmation } = const_.processSignature; const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation; this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true; this.signVisible = true
}, },
// //
closeSignDialog(isSign, signInfo) { closeSignDialog(isSign, signInfo) {
if (isSign) { if (isSign) {
this.signConfirm(signInfo); this.signConfirm(signInfo)
} else { } else {
this.signVisible = false; this.signVisible = false
} }
}, },
// //
async signConfirm(signInfo) { async signConfirm(signInfo) {
this.loading = true; this.loading = true
var paths = []; var paths = []
this.fileList.map((file) => { this.fileList.map((file) => {
paths.push(file.url); paths.push(file.url)
}); })
var params = { var params = {
data: { data: {
visitTaskId: this.visitTaskId, visitTaskId: this.visitTaskId,
judgeResultTaskId: this.adForm.judgeResultTaskId, judgeResultTaskId: this.adForm.judgeResultTaskId,
judgeResultRemark: this.adForm.judgeResultRemark, judgeResultRemark: this.adForm.judgeResultRemark,
judgeResultImagePathList: paths, judgeResultImagePathList: paths
}, },
signInfo: signInfo, signInfo: signInfo
}; }
try { try {
const res = await submitJudgeVisitTaskResult(params); const res = await submitJudgeVisitTaskResult(params)
if (res.IsSuccess) { if (res.IsSuccess) {
this.$message.success(this.$t("common:message:savedSuccessfully")); this.$message.success(this.$t('common:message:savedSuccessfully'))
this.isEdit = false; this.isEdit = false
this.$refs["signForm"].btnLoading = false; this.$refs['signForm'].btnLoading = false
this.signVisible = false; this.signVisible = false
// window.location.reload() // window.location.reload()
// window.opener.postMessage('refreshTaskList', window.location) // window.opener.postMessage('refreshTaskList', window.location)
// //
this.adInfo.ReadingTaskState = 2; this.adInfo.ReadingTaskState = 2
const res = await getAutoCutNextTask(); const res = await getAutoCutNextTask()
var isAutoTask = res.Result.AutoCutNextTask; var isAutoTask = res.Result.AutoCutNextTask
if (isAutoTask) { if (isAutoTask) {
// store.dispatch('reading/resetVisitTasks') // store.dispatch('reading/resetVisitTasks')
window.location.reload(); window.location.reload()
} else { } else {
// '' // ''
const confirm = await this.$confirm( const confirm = await this.$confirm(
this.$t("trials:adReview:title:msg2"), this.$t('trials:adReview:title:msg2'),
{ {
type: "warning", type: 'warning',
distinguishCancelAndClose: true, distinguishCancelAndClose: true
} }
); )
if (confirm === "confirm") { if (confirm === 'confirm') {
// store.dispatch('reading/resetVisitTasks') // store.dispatch('reading/resetVisitTasks')
// DicomEvent.$emit('getNextTask') // DicomEvent.$emit('getNextTask')
window.location.reload(); window.location.reload()
} else { } else {
changeURLStatic("visitTaskId", this.visitTaskId); changeURLStatic('visitTaskId', this.visitTaskId)
} }
} }
window.opener.postMessage("refreshTaskList", window.location); window.opener.postMessage('refreshTaskList', window.location)
} }
this.loading = false; this.loading = false
} catch (e) { } catch (e) {
this.loading = false; this.loading = false
this.$refs["signForm"].btnLoading = false; this.$refs['signForm'].btnLoading = false
} }
}, },
handleViewDetail(visitTaskId) { handleViewDetail(visitTaskId) {
if (this.openWindow) { if (this.openWindow) {
this.openWindow.close(); this.openWindow.close()
} }
var token = getToken(); var token = getToken()
var criterionType = parseInt(localStorage.getItem("CriterionType")); var criterionType = parseInt(localStorage.getItem('CriterionType'))
var readingTool = this.$router.currentRoute.query.readingTool; var readingTool = this.$router.currentRoute.query.readingTool
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool); readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool)
var isReadingTaskViewInOrder = var isReadingTaskViewInOrder =
this.$router.currentRoute.query.isReadingTaskViewInOrder; this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = var trialReadingCriterionId =
this.$router.currentRoute.query.TrialReadingCriterionId; this.$router.currentRoute.query.TrialReadingCriterionId
var path = ""; var path = ''
if (readingTool === 0) { if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${ path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
this.trialId this.trialId
}&subjectCode=${this.subjectCode}&subjectId=${ }&subjectCode=${this.subjectCode}&subjectId=${
this.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=${ }&subjectCode=${this.subjectCode}&subjectId=${
this.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 })
this.openWindow = window.open(routeData.href, "_blank"); this.openWindow = window.open(routeData.href, '_blank')
}, },
handleView(row, armEnum) { handleView(row, armEnum) {
if (this.openWindow) { if (this.openWindow) {
this.openWindow.close(); this.openWindow.close()
} }
// var token = getToken() // var token = getToken()
// var task = row.VisitTaskInfoList.find(item => item.ArmEnum === armEnum) // var task = row.VisitTaskInfoList.find(item => item.ArmEnum === armEnum)
@ -794,17 +791,17 @@ export default {
// path: `/readingPage?trialId=${this.trialId}&visitTaskId=${task.VisitTaskId}&TokenKey=${token}&isReadingShowPreviousResults=false` // path: `/readingPage?trialId=${this.trialId}&visitTaskId=${task.VisitTaskId}&TokenKey=${token}&isReadingShowPreviousResults=false`
// }) // })
// window.open(routeData.href, '_blank') // window.open(routeData.href, '_blank')
var token = getToken(); var token = getToken()
var task = row.VisitTaskInfoList.find((item) => item.ArmEnum === armEnum); var task = row.VisitTaskInfoList.find((item) => item.ArmEnum === armEnum)
var criterionType = this.$router.currentRoute.query.criterionType; var criterionType = this.$router.currentRoute.query.criterionType
var readingTool = this.$router.currentRoute.query.readingTool; var readingTool = this.$router.currentRoute.query.readingTool
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool); readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool)
var isReadingTaskViewInOrder = var isReadingTaskViewInOrder =
this.$router.currentRoute.query.isReadingTaskViewInOrder; this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = var trialReadingCriterionId =
this.$router.currentRoute.query.TrialReadingCriterionId; this.$router.currentRoute.query.TrialReadingCriterionId
var path = ""; var path = ''
if (readingTool === 0) { if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${ path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
this.trialId this.trialId
@ -812,7 +809,7 @@ export default {
this.subjectId this.subjectId
}&visitTaskId=${ }&visitTaskId=${
task.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
@ -820,26 +817,26 @@ export default {
this.subjectId this.subjectId
}&visitTaskId=${ }&visitTaskId=${
task.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 })
this.openWindow = window.open(routeData.href, "_blank"); this.openWindow = window.open(routeData.href, '_blank')
}, },
handleViewGl(row, armEnum) { handleViewGl(row, armEnum) {
if (this.openWindow) { if (this.openWindow) {
this.openWindow.close(); this.openWindow.close()
} }
var token = getToken(); var token = getToken()
var task = row.VisitTaskInfoList.find((item) => item.ArmEnum === armEnum); var task = row.VisitTaskInfoList.find((item) => item.ArmEnum === armEnum)
var criterionType = this.$router.currentRoute.query.criterionType; var criterionType = this.$router.currentRoute.query.criterionType
var readingTool = this.$router.currentRoute.query.readingTool; var readingTool = this.$router.currentRoute.query.readingTool
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool); readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool)
var isReadingTaskViewInOrder = var isReadingTaskViewInOrder =
this.$router.currentRoute.query.isReadingTaskViewInOrder; this.$router.currentRoute.query.isReadingTaskViewInOrder
var trialReadingCriterionId = var trialReadingCriterionId =
this.$router.currentRoute.query.TrialReadingCriterionId; this.$router.currentRoute.query.TrialReadingCriterionId
var path = ""; var path = ''
if (readingTool === 0) { if (readingTool === 0) {
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${ path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
this.trialId this.trialId
@ -847,7 +844,7 @@ export default {
this.subjectId this.subjectId
}&visitTaskId=${ }&visitTaskId=${
task.GlobalVisitTaskId 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
@ -855,10 +852,10 @@ export default {
this.subjectId this.subjectId
}&visitTaskId=${ }&visitTaskId=${
task.GlobalVisitTaskId 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 })
this.openWindow = window.open(routeData.href, "_blank"); this.openWindow = window.open(routeData.href, '_blank')
}, },
// uploadScreenshot(param) { // uploadScreenshot(param) {
// this.loading = true // this.loading = true
@ -876,105 +873,93 @@ export default {
// }) // })
// }, // },
async uploadScreenshot(param) { async uploadScreenshot(param) {
this.loading = true; this.loading = true
this.uploadDisabled = false; this.uploadDisabled = false
var trialId = this.$route.query.trialId; var trialId = this.$route.query.trialId
var file = await this.fileToBlob(param.file); var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put( const res = await this.OSSclient.put(
`/${trialId}/Read/${this.subjectId}/visit/${param.file.name}`, `/${trialId}/Read/${this.subjectId}/visit/${param.file.name}`,
file file
); )
console.log(res); console.log(res)
this.fileList.push({ this.fileList.push({
name: param.file.name, name: param.file.name,
url: this.$getObjectName(res.url), url: this.$getObjectName(res.url)
}); })
this.loading = false; this.loading = false
this.uploadDisabled = true; this.uploadDisabled = true
}, },
handleBeforeUpload(file) { handleBeforeUpload(file) {
// //
if (this.checkFileSuffix(file.name)) { if (this.checkFileSuffix(file.name)) {
return true; return true
} else { } else {
const msg = this.$t("trials:adReview:title:msg4").replace( const msg = this.$t('trials:adReview:title:msg4').replace(
"xxx", 'xxx',
this.accept this.accept
); )
this.$alert(msg); this.$alert(msg)
return false; return false
} }
}, },
checkFileSuffix(fileName) { checkFileSuffix(fileName) {
var index = fileName.lastIndexOf("."); var index = fileName.lastIndexOf('.')
var suffix = fileName.substring(index + 1, fileName.length); var suffix = fileName.substring(index + 1, fileName.length)
if ( if (
this.accept.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === this.accept.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) ===
-1 -1
) { ) {
return false; return false
} else { } else {
return true; return true
} }
}, },
// //
removeImage() { removeImage() {
this.imageUrl = ""; this.imageUrl = ''
this.fileList = []; this.fileList = []
this.adForm.judgeResultImagePath = ""; this.adForm.judgeResultImagePath = ''
}, },
// //
handlePictureCardPreview(file) { handlePictureCardPreview(file) {
this.images = this.fileList.map( this.images = this.fileList.map(
(f) => this.OSSclientConfig.basePath + f.url (f) => this.OSSclientConfig.basePath + f.url
); )
// this.imageUrl = this.OSSclientConfig.basePath + file.url // this.imageUrl = this.OSSclientConfig.basePath + file.url
this.$refs[file.url].$viewer.show(); this.$refs[file.url].$viewer.show()
}, },
// //
handleRemove(file, fileList) { handleRemove(file, fileList) {
var idx = this.fileList.findIndex((i) => i.url === file.url); var idx = this.fileList.findIndex((i) => i.url === file.url)
if (idx === -1) return; if (idx === -1) return
this.fileList.splice(idx, 1); this.fileList.splice(idx, 1)
}, },
async skipTask() { async skipTask() {
try { try {
// //
const confirm = await this.$confirm( const confirm = await this.$confirm(
this.$t("trials:readingReport:message:skipConfirm"), this.$t('trials:readingReport:message:skipConfirm'),
{ {
type: "warning", type: 'warning',
distinguishCancelAndClose: true, distinguishCancelAndClose: true
} }
); )
if (confirm !== "confirm") return; if (confirm !== 'confirm') return
this.loading = true; this.loading = true
const res = await setSkipReadingCache({ const res = await setSkipReadingCache({
visitTaskId: this.visitTaskId, visitTaskId: this.visitTaskId
}); })
this.loading = false; this.loading = false
if (res.IsSuccess) { if (res.IsSuccess) {
window.location.reload(); window.location.reload()
} }
} catch (e) { } catch (e) {
this.loading = false; this.loading = false
console.log(e); console.log(e)
} }
}, }
initializeViewer() { }
Viewer.setDefaults({ }
toolbar: {
zoomIn: true,
zoomOut: true,
rotateLeft: true,
rotateRight: true,
flipHorizontal: true,
flipVertical: true,
},
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.adReview_wrapper { .adReview_wrapper {

View File

@ -1654,7 +1654,7 @@ export default {
resetWwwc() { resetWwwc() {
this.toolState.viewportInvert = false this.toolState.viewportInvert = false
var viewport = cornerstone.getViewport(this.canvas) var viewport = cornerstone.getViewport(this.canvas)
viewport.invert = false // viewport.invert = false
var image = cornerstone.getImage(this.canvas) var image = cornerstone.getImage(this.canvas)
viewport.voi.windowWidth = image.windowWidth viewport.voi.windowWidth = image.windowWidth
viewport.voi.windowCenter = image.windowCenter viewport.voi.windowCenter = image.windowCenter

View File

@ -352,7 +352,44 @@
<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="trialCriterion.ImageUploadEnum > 0 && currentReadingTaskState < 2"
v-hasPermi="['role:ir']"
class="item"
effect="dark"
:content="$t('trials:reading:button:upload')"
placement="bottom"
>
<div class="tool-wrapper">
<div class="icon" @click.prevent="openUploadImage('upload')">
<i class="el-icon-upload2 svg-icon" />
</div>
<div class="text">{{ $t('trials:reading:button:upload') }}</div>
</div>
</el-tooltip>
<el-tooltip
v-if="trialCriterion.ImageDownloadEnum > 0"
v-hasPermi="[
'role:ir',
'role:mim',
'role:mc',
'role:pm',
'role:apm',
'role:ea',
'role:qa',
]"
class="item"
effect="dark"
:content="$t('trials:reading:button:download')"
placement="bottom"
>
<div class="tool-wrapper">
<div class="icon" @click.prevent="openUploadImage('download')">
<i class="el-icon-download svg-icon" />
</div>
<div class="text">{{ $t('trials:reading:button:download') }}</div>
</div>
</el-tooltip>
<div style="margin-left:auto;"> <div style="margin-left:auto;">
<div style="padding:5px"> <div style="padding:5px">
<!-- 手册 --> <!-- 手册 -->
@ -433,13 +470,34 @@
/> />
<RecistQuestionList <RecistQuestionList
v-else-if="CriterionType !== 17" v-else-if="CriterionType === 1"
ref="measurementList" ref="measurementList"
:question-form-change-state="questionFormChangeState" :question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum" :question-form-change-num="questionFormChangeNum"
:is-show="isShow" :is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo" :is-reading-show-subject-info="isReadingShowSubjectInfo"
/> />
<IVUSList
v-else-if="CriterionType === 19"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<OCTList
v-else-if="CriterionType === 20"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<h2 v-else style="color:#ddd">
Developing...
</h2>
</div> </div>
</div> </div>
@ -655,6 +713,21 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-dialog> </el-dialog>
<upload-dicom-and-nonedicom
v-if="uploadImageVisible"
:SubjectId="uploadSubjectId"
:SubjectCode="uploadSubjectCode"
:Criterion="uploadTrialCriterion"
:visible.sync="uploadImageVisible"
/>
<download-dicom-and-nonedicom
v-if="downloadImageVisible"
:SubjectId="uploadSubjectId"
:SubjectCode="uploadSubjectCode"
:Criterion="uploadTrialCriterion"
:TaskId="taskId"
:visible.sync="downloadImageVisible"
/>
</div> </div>
</template> </template>
<script> <script>
@ -677,6 +750,8 @@ import RecistBMQuestionList from './RecistBM/QuestionList'
import IRecistQuestionList from './IRecist/QuestionList' import IRecistQuestionList from './IRecist/QuestionList'
import PCWGQuestionList from './PCWG/QuestionList' import PCWGQuestionList from './PCWG/QuestionList'
import LuganoQuestionList from './Lugano/QuestionList' import LuganoQuestionList from './Lugano/QuestionList'
import IVUSList from './IVUS/QuestionList'
import OCTList from './OCT/QuestionList'
import CustomWwwcForm from './CustomWwwcForm' import CustomWwwcForm from './CustomWwwcForm'
import Manuals from './Manuals' import Manuals from './Manuals'
import Hotkeys from './Hotkeys' import Hotkeys from './Hotkeys'
@ -684,6 +759,9 @@ import WL from './WL'
import Others from './Others' import Others from './Others'
import DicomEvent from './DicomEvent' import DicomEvent from './DicomEvent'
import html2canvas from 'html2canvas' import html2canvas from 'html2canvas'
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
import { getCriterionReadingInfo } from '@/api/trials'
export default { export default {
name: 'DicomViewer', name: 'DicomViewer',
components: { components: {
@ -698,7 +776,12 @@ export default {
PCWGQuestionList, PCWGQuestionList,
RecistBMQuestionList, RecistBMQuestionList,
IRecistQuestionList, IRecistQuestionList,
LuganoQuestionList }, LuganoQuestionList,
IVUSList,
OCTList,
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
},
props: { props: {
isShow: { isShow: {
type: Boolean, type: Boolean,
@ -839,7 +922,16 @@ export default {
activeCanvasWC: null, activeCanvasWC: null,
activeTaskInfo: {}, activeTaskInfo: {},
clipPlaying: false, clipPlaying: false,
fps: 15 fps: 15,
trialCriterion: {},
//
downloadImageVisible: false,
uploadImageVisible: false,
uploadSubjectId: null,
uploadSubjectCode: null,
uploadTrialCriterion: {},
uploadStatus: 'upload',
taskId: ''
} }
}, },
@ -912,6 +1004,7 @@ export default {
mounted() { mounted() {
this.getHotKeys() this.getHotKeys()
this.getWwcTpl() this.getWwcTpl()
this.getTrialCriterion()
// cornerstone.imageCache.setMaximumSizeBytes(0) // cornerstone.imageCache.setMaximumSizeBytes(0)
// const maximumSizeInBytes = 1024 * 1024 * 1024 // 1 GB // const maximumSizeInBytes = 1024 * 1024 * 1024 // 1 GB
@ -923,6 +1016,10 @@ export default {
this.measuredTools = [{ toolName: 'ArrowAnnotate', text: this.$t('trials:reading:button:arrowAnnotate'), icon: 'arrow', isDisabled: false, disabledReason: '' }, { toolName: 'RectangleRoi', text: this.$t('trials:reading:button:rectangle'), icon: 'rectangle', isDisabled: false, disabledReason: '' }] this.measuredTools = [{ toolName: 'ArrowAnnotate', text: this.$t('trials:reading:button:arrowAnnotate'), icon: 'arrow', isDisabled: false, disabledReason: '' }, { toolName: 'RectangleRoi', text: this.$t('trials:reading:button:rectangle'), icon: 'rectangle', isDisabled: false, disabledReason: '' }]
} else if (this.CriterionType === 17) { } else if (this.CriterionType === 17) {
this.measuredTools = [{ toolName: 'Length', text: this.$t('trials:reading:button:length'), icon: 'length', isDisabled: false, disabledReason: '' }, { toolName: 'RectangleRoi', text: this.$t('trials:reading:button:rectangle'), icon: 'rectangle', isDisabled: false, disabledReason: '' }, { toolName: 'ArrowAnnotate', text: this.$t('trials:reading:button:arrowAnnotate'), icon: 'arrow', isDisabled: false, disabledReason: '' }] this.measuredTools = [{ toolName: 'Length', text: this.$t('trials:reading:button:length'), icon: 'length', isDisabled: false, disabledReason: '' }, { toolName: 'RectangleRoi', text: this.$t('trials:reading:button:rectangle'), icon: 'rectangle', isDisabled: false, disabledReason: '' }, { toolName: 'ArrowAnnotate', text: this.$t('trials:reading:button:arrowAnnotate'), icon: 'arrow', isDisabled: false, disabledReason: '' }]
} else if (this.CriterionType === 19) {
this.measuredTools = []
} else if (this.CriterionType === 20) {
this.measuredTools = []
} }
this.rotateList[0] = '1' this.rotateList[0] = '1'
this.colorList[0] = '' this.colorList[0] = ''
@ -1062,6 +1159,27 @@ export default {
}) })
}, },
methods: { methods: {
getTrialCriterion() {
getCriterionReadingInfo({
TrialId: this.trialId || this.$route.query.trialId,
TrialReadingCriterionId: this.trialReadingCriterionId || this.$route.query.TrialReadingCriterionId,
})
.then((res) => {
this.trialCriterion = res.Result
})
.catch(() => {})
},
openUploadImage(status) {
const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask)
if (idx > -1) {
this.taskId = this.visitTaskList[idx].VisitTaskId
}
this.uploadSubjectCode = this.$route.query.subjectCode
this.uploadSubjectId = this.$route.query.subjectId
this.uploadTrialCriterion = this.trialCriterion
this.uploadStatus = status
this[`${status}ImageVisible`] = true
},
async getWwcTpl() { async getWwcTpl() {
// const loading = this.$loading({ fullscreen: true }) // const loading = this.$loading({ fullscreen: true })
try { try {
@ -2072,15 +2190,15 @@ export default {
}, },
handleFusion() { handleFusion() {
// https // https
if (!window.isSecureContext) { // if (!window.isSecureContext) {
this.$alert(this.$t('components:uploadvideo:message:xf3')) // this.$alert(this.$t('components:uploadvideo:message:xf3'))
return // return
} // }
// // //
if (!window.crossOriginIsolated) { // if (!window.crossOriginIsolated) {
this.$alert(this.$t('components:uploadvideo:message:xf4')) // this.$alert(this.$t('components:uploadvideo:message:xf4'))
return // return
} // }
if (this.imageQualityIssues && parseInt(this.imageQualityIssues) === 6) { if (this.imageQualityIssues && parseInt(this.imageQualityIssues) === 6) {
this.$alert(this.$t('trials:lugano:message:fusionWarn')) this.$alert(this.$t('trials:lugano:message:fusionWarn'))
return return

View File

@ -0,0 +1,506 @@
<template>
<el-form
v-if="isRender"
ref="measurementForm"
v-loading="loading"
:model="questionForm"
size="mini"
class="measurement-form"
>
<div class="base-dialog-body">
<div style="display: flex;justify-content: space-between;">
<h3 v-if="questionName" style="color: #ddd;padding: 5px 0px;margin: 0;">
<!-- {{ `${questionName} (${orderMark}${String(rowIndex).padStart(2, '0')})` }} -->
{{ lesionName }}
</h3>
<!-- 关闭 -->
<div>
<i class="el-icon-circle-close" style="font-size: 25px;cursor: pointer;" @click="handleClose" />
</div>
</div>
<el-form-item
v-for="qs in questions"
v-show="qs.ShowQuestion!==2"
:key="qs.Id"
:label="`${qs.QuestionName}`"
:prop="qs.Id"
:rules="[
{ required: (qs.IsRequired === 0 || (qs.IsRequired ===1 && qs.RelevanceId && (questionForm[qs.RelevanceId] === qs.RelevanceValue))) && qs.Type!=='group' && qs.Type!=='summary',
message:['radio', 'select', 'checkbox'].includes(qs.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur','change']},
]"
>
<!-- 输入框 -->
<template v-if="qs.Type==='input'">
<el-input
v-model="questionForm[qs.Id]"
:disabled="!isCurrentTask || readingTaskState>=2 "
@change="((val)=>{formItemChange(val, qs)})"
/>
</template>
<!-- 数值类型 -->
<template v-if="qs.Type==='number'">
<el-input
v-model="questionForm[qs.Id]"
:disabled="!isCurrentTask || readingTaskState>=2 "
@change="((val)=>{formItemChange(val, qs)})"
@blur="limitBlur(qs.Id, qs.ValueType)"
>
<template v-if="qs.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
</template>
</el-input>
</template>
<!-- 自动计算 -->
<template v-if="qs.Type==='calculation'">
<el-input
v-model="questionForm[qs.Id]"
disabled
@change="((val)=>{formItemChange(val, qs)})"
>
<template v-if="qs.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
</template>
</el-input>
</template>
<!-- 多行文本输入框 -->
<el-input
v-if="qs.Type==='textarea'"
v-model="questionForm[qs.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:disabled="!isCurrentTask || readingTaskState>=2"
@change="((val)=>{formItemChange(val, qs)})"
/>
<el-select
v-if="qs.Type==='select'"
v-model="questionForm[qs.Id]"
filterable
:placeholder="$t('common:placeholder:select')"
:disabled="!isCurrentTask || readingTaskState>=2"
@change="((val)=>{formItemChange(val, qs)})"
>
<template v-if="qs.DictionaryCode">
<el-option
v-for="item of $d[qs.DictionaryCode]"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="val in qs.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<!-- 单选 -->
<el-radio-group
v-if="qs.Type==='radio'"
v-model="questionForm[qs.id]"
:disabled="!isCurrentTask || readingTaskState>=2"
>
<el-radio
v-for="val in qs.options.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div
v-if="isCurrentTask && readingTaskState<2"
class="base-dialog-footer"
style="text-align:right;margin-top:10px;"
>
<!-- 删除 -->
<el-button
v-if="isCurrentTaskAdd !== 'False'"
size="mini"
@click="handleDelete"
>
{{ $t('common:button:delete') }}
</el-button>
<!-- 保存 -->
<el-button
size="mini"
@click="handleSave"
>
{{ $t('common:button:save') }}
</el-button>
</div>
</el-form>
</template>
<script>
import { submitTableQuestion, deleteReadingRowAnswer } from '@/api/trials'
import DicomEvent from './../DicomEvent'
// import store from '@/store'
export default {
name: 'MeasurementForm',
props: {
questions: {
type: Array,
default() { return [] }
},
answers: {
type: Object,
default() { return {} }
},
lesionType: {
type: Number,
required: true
},
visitTaskId: {
type: String,
required: true
},
parentQsId: {
type: String,
required: true
},
isCurrentTask: {
type: Boolean,
required: true
},
readingTaskState: {
type: Number,
required: true
},
isBaseLineTask: {
type: Boolean,
required: true
},
orderMark: {
type: String,
default: ''
},
questionName: {
type: String,
required: true
},
rowIndex: {
type: String,
required: true
},
tableQuestions: {
type: Array,
default() { return [] }
}
},
data() {
return {
questionForm: {},
loading: false,
trialId: '',
originalQuestionForm: {},
isRender: false,
toolType: '',
lesionName: '',
isCurrentTaskAdd: 'False',
lesionMark: '',
pictureBaseStr: '',
digitPlaces: 2
}
},
mounted() {
this.trialId = this.$route.query.trialId
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.initForm()
DicomEvent.$on('handleImageQualityAbnormal', () => {
})
},
beforeDestroy() {
DicomEvent.$off('handleImageQualityAbnormal')
},
methods: {
async initForm() {
const loading = this.$loading({ fullscreen: true })
this.questions.forEach(item => {
var val = this.answers[item.Id]
if (item.DictionaryCode) {
val = isNaN(parseInt(this.answers[item.Id])) ? this.answers[item.Id] : parseInt(this.answers[item.Id])
}
this.$set(this.questionForm, item.Id, val)
})
this.$set(this.questionForm, 'RowIndex', this.answers.RowIndex ? this.answers.RowIndex : '')
this.$set(this.questionForm, 'RowId', this.answers.RowId ? this.answers.RowId : '')
if (this.questionForm.RowId) {
this.$set(this.questionForm, 'saveTypeEnum', 2)
} else {
this.$set(this.questionForm, 'saveTypeEnum', 0)
}
this.$set(this.questionForm, 'IsDicomReading', this.answers.IsDicomReading !== 'False')
if (!this.questionForm.LesionType) {
this.$set(this.questionForm, 'LesionType', this.lesionType)
}
this.lesionName = this.getLesionInfo(this.orderMark, this.rowIndex)
this.isCurrentTaskAdd = this.answers.IsCurrentTaskAdd ? this.answers.IsCurrentTaskAdd : 'True'
this.lesionMark = this.getLesionName(this.orderMark, this.questionForm.RowIndex)
this.originalQuestionForm = { ...this.questionForm }
this.isRender = true
loading.close()
},
getLesionName(orderMark, rowIndex) {
var lessionName = ''
var rowIndexArr = rowIndex.split('.')
var x = parseInt(rowIndexArr[0])
var y = parseInt(rowIndexArr[1])
if (y > 0) {
y = String.fromCharCode(parseInt(rowIndexArr[1]) - 1 + 65 + 32)
lessionName = `${orderMark}${String(x).padStart(2, '0')}${y}`
} else {
lessionName = `${orderMark}${String(x).padStart(2, '0')}`
}
return lessionName
},
getLesionInfo(orderMark, rowIndex) {
var arr = []
var lessionName = ''
var rowIndexArr = rowIndex.split('.')
var x = parseInt(rowIndexArr[0])
var y = parseInt(rowIndexArr[1])
if (y > 0) {
y = String.fromCharCode(parseInt(rowIndexArr[1]) - 1 + 65 + 32)
lessionName = `${orderMark}${String(x).padStart(2, '0')}${y}`
arr.push(lessionName)
} else {
lessionName = `${orderMark}${String(x).padStart(2, '0')}`
arr.push(lessionName)
}
return arr.join(' ')
},
getQuestionId(questionMark) {
var idx = this.questions.findIndex(i => i.QuestionMark === questionMark)
if (idx > -1) {
return this.questions[idx].Id
} else {
return ''
}
},
async formItemChange(v, question) {
if (this.questionForm.RowId) {
this.$set(this.questionForm, 'saveTypeEnum', 1)
} else {
this.$set(this.questionForm, 'saveTypeEnum', 0)
}
if (question.QuestionMark === 1001 || question.QuestionMark === 1002) {
this.questionForm[this.getQuestionId(1003)] = this.calculate([1001, 1002], '-')
}
const area1 = this.getQuestionVal(1001)
const area2 = this.getQuestionVal(1002)
const diff = this.getQuestionVal(1003)
this.$emit('resetQuestions', { area1, area2, diff, saveTypeEnum: this.questionForm.saveTypeEnum, rowIndex: this.rowIndex, questionId: this.parentQsId, anwsers: this.questionForm })
},
calculate(qsMarkArr, type) {
var num = 0
for (let i = 0; i < qsMarkArr.length; i++) {
const mark = qsMarkArr[i]
const v = this.questionForm[this.getQuestionId(mark)]
if (isNaN(parseFloat(v))) {
num = null
break
}
if (i === 0) {
num = parseFloat(v)
} else {
switch (type) {
case '-':
num -= parseFloat(v)
break
}
}
}
return num === null ? num : num.toFixed(this.digitPlaces)
},
limitBlur(qId, valueType) {
const value = this.questionForm[qId]
if (isNaN(parseInt(value))) return
if (valueType === 0) {
this.$set(this.questionForm, qId, parseInt(value))
} else if (valueType === 3) {
this.$set(this.questionForm, qId, parseFloat(value))
} else {
this.$set(this.questionForm, qId, parseFloat(value).toFixed(this.digitPlaces))
}
},
returnFloat(num) {
if (num) return
var value = Math.round(parseFloat(num) * 100) / 100
var s = value.toString().split('.')
if (s.length === 1) {
value = value.toString() + '.00'
return value
}
if (s.length > 1) {
if (s[1].length < 2) {
value = value.toString() + '0'
}
return value
}
},
getQuestionVal(questionMark) {
const idx = this.questions.findIndex(i => i.QuestionMark === questionMark)
if (idx > -1) {
const questionId = this.questions[idx].Id
const answer = this.questionForm[questionId]
if (isNaN(parseFloat(answer))) {
return answer
} else {
return parseFloat(answer)
}
} else {
return ''
}
},
async handleSave() {
const valid = await this.$refs.measurementForm.validate()
if (!valid) return
const loading = this.$loading({ fullscreen: true })
try {
var answers = []
var reg = new RegExp(/^[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}$/)
for (const k in this.questionForm) {
if (reg.test(k)) {
if (answers.findIndex(i => i.tableQuestionId === k) === -1) {
answers.push({ tableQuestionId: k, answer: this.questionForm[k] })
}
}
}
var params = {
questionId: this.parentQsId,
rowId: this.questionForm.RowId,
rowIndex: this.answers.RowIndex,
visitTaskId: this.visitTaskId,
trialId: this.trialId,
answerList: answers
}
const res = await submitTableQuestion(params)
if (res.IsSuccess) {
//
this.$message.success(this.$t('common:message:savedSuccessfully'))
this.$set(this.questionForm, 'saveTypeEnum', 2)
this.originalQuestionForm = { ...this.questionForm }
this.$set(this.questionForm, 'RowId', res.Result.RowId)
const area1 = this.getQuestionVal(1001)
const area2 = this.getQuestionVal(1002)
const diff = this.getQuestionVal(1003)
this.$emit('resetQuestions', { area1, area2, diff, saveTypeEnum: this.questionForm.saveTypeEnum, rowIndex: this.rowIndex, questionId: this.parentQsId, anwsers: this.questionForm })
this.$emit('close')
DicomEvent.$emit('refreshQuestions')
DicomEvent.$emit('getReportInfo', true)
}
loading.close()
} catch (e) {
console.log(e)
loading.close()
}
},
async handleDelete() {
const loading = this.$loading({ fullscreen: true })
try {
const confirm = await this.$confirm(
this.$t('trials:reading:warnning:msg48'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
if (this.questionForm.RowId) {
var param = {
visitTaskId: this.visitTaskId,
questionId: this.parentQsId,
rowId: this.questionForm.RowId
}
const res = await deleteReadingRowAnswer(param)
if (res.IsSuccess) {
this.$emit('close', { lesionType: this.lesionType, rowIndex: this.rowIndex, visitTaskId: this.visitTaskId })
DicomEvent.$emit('getReportInfo', true)
// ''
this.$message.success(this.$t('common:message:deletedSuccessfully'))
}
} else {
this.$emit('close', { lesionType: this.lesionType, rowIndex: this.rowIndex, visitTaskId: this.visitTaskId })
}
loading.close()
} catch (e) {
loading.close()
console.log(e)
}
},
async handleClose() {
if (!this.questionForm.RowId) {
// ''
const confirm = await this.$confirm(
this.$t('trials:reading:warnning:msg60'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
this.$emit('close', { lesionType: this.lesionType, rowIndex: this.rowIndex, visitTaskId: this.visitTaskId })
} else {
this.$emit('close')
}
}
}
}
</script>
<style lang="scss" scoped>
.measurement-form{
/deep/ .el-form-item__label{
color: #c3c3c3;
text-align: left;
}
/deep/ .el-input .el-input__inner{
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
/deep/ .el-form-item{
display: flex;
flex-direction: row;
justify-content: flex-start;
}
/deep/ .el-form-item__content{
flex: 1;
}
/deep/ .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
/deep/ .el-select.is-disabled .el-input__inner{
background-color: #646464a1;
}
/deep/ .el-button--mini, .el-button--mini.is-round {
padding: 7px 10px;
}
.el-form-item__content
.el-select{
width: 100%;
}
.input-width1{
width: calc(100% -60px)!important;
}
.input-width2{
width: 100% !important;
}
}
</style>

View File

@ -0,0 +1,768 @@
<template>
<div class="measurement-wrapper" :style="{'height':height+10+'px'}">
<div class="container" :style="{'height':height+'px'}">
<div class="basic-info">
<h3 v-if="isReadingShowSubjectInfo">
<span v-if="subjectCode">{{ subjectCode }} </span>
<span style="margin-left:5px;">{{ taskBlindName }}</span>
</h3>
<div v-if="readingTaskState < 2">
<el-tooltip class="item" effect="dark" :content="$t('trials:dicomReading:message:confirmReset')" placement="bottom">
<i
class="el-icon-refresh-left"
@click="resetMeasuredData"
/>
</el-tooltip>
</div>
</div>
<!-- 影像质量问题 -->
<div class="lesions">
<Questions
ref="ecrf"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="1"
/>
</div>
<!-- 测量问题 -->
<template v-if="questions.length > 0 && CriterionType !== 10">
<div v-for="(qs,index) in questions" :key="index" v-loading="loading" class="lesions lesions_wrapper">
<h4 v-if="qs.Type === 'group'" style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ language==='en'?qs.GroupEnName:qs.GroupName }}
</h4>
<div class="lesion_list">
<el-form
v-if="questions.length > 0"
:ref="`questions${index}`"
size="small"
:model="questionForm"
>
<div class="base-dialog-body">
<div v-for="item in qs.Childrens" :key="item.Id">
<div v-if="item.Type === 'table'" class="flex-row" style="margin:3px 0;">
<div class="title">{{ item.QuestionName }}</div>
<div v-if="readingTaskState < 2" class="add-icon" @click.prevent="handleAdd(item)">
<i class="el-icon-plus" />
</div>
</div>
<el-collapse
v-if="item.Type === 'table' && item.TableQuestions"
v-model="activeName"
accordion
style="margin-bottom: 10px;"
@change="handleCollapseChange"
>
<el-collapse-item
v-for="(q,i) in item.TableQuestions.Answers"
:key="`${item.Id}_${q.RowIndex}`"
:name="`${item.Id}_${q.RowIndex}`"
>
<template slot="title">
<div style="width:300px;position: relative;" :style="{color:(activeName===item.Id+q.RowIndex?'#ffeb3b':'#fff')}">
{{ getLesionName(item.OrderMark,q.RowIndex) }}
<!-- 未保存 -->
<el-tooltip v-if="readingTaskState<2 && parseInt(item.TableQuestions.Answers[i].saveTypeEnum) === 0" class="item" effect="dark" :content="$t('trials:reading:button:unsaved')" placement="bottom">
<i class="el-icon-warning" style="color:red" />
</el-tooltip>
<!-- 信息不完整 -->
<el-tooltip v-if="readingTaskState<2 && parseInt(item.TableQuestions.Answers[i].saveTypeEnum) ===1" class="item" effect="dark" :content="$t('trials:reading:button:incompleteInfor')" placement="bottom">
<i class="el-icon-warning" style="color:#ff9800" />
</el-tooltip>
<div style="position: absolute;left: 60px;top: 2px;">
<div style="display: flex;flex-direction: row;font-size: 11px;width:200px;height: 30px;">
<div style="margin-left:10px;">
{{ numberToFixed(item.TableQuestions.Answers[i].area1,'m㎡') }}
</div>
<div style="margin-left:10px;">
{{ numberToFixed(item.TableQuestions.Answers[i].area2,'m㎡') }}
</div>
<div style="margin-left:10px;margin-bottom:5px;">
{{ numberToFixed(item.TableQuestions.Answers[i].diff, 'm㎡') }}
</div>
</div>
</div>
</div>
</template>
<QuestionForm
:ref="`${item.Id}_${q.RowIndex}`"
:questions="item.TableQuestions.Questions"
:answers="item.TableQuestions.Answers[i]"
:lesion-type="item.LesionType"
:order-mark="item.OrderMark"
:table-questions="tableQuestions"
:row-index="String(q.RowIndex)"
:question-name="item.QuestionName"
:parent-qs-id="item.Id"
:visit-task-id="visitTaskId"
:is-current-task="isCurrentTask"
:reading-task-state="readingTaskState"
:is-base-line-task="isBaseLineTask"
@getReadingQuestionAndAnswer="getReadingQuestionAndAnswer"
@resetQuestions="resetQuestions"
@close="close"
/>
</el-collapse-item>
</el-collapse>
<template v-else>
<!-- 数值 -->
<el-form-item
v-if="item.ShowQuestion!==2"
:key="item.Id"
:label="`${item.QuestionName}`"
:prop="item.Id"
:rules="[
{ required: (item.IsRequired === 0 || (item.IsRequired ===1 && item.RelevanceId && (item.RelevanceValue.includes(questionForm[item.RelevanceId])))) && item.Type!=='group' && item.Type!=='summary',
message:['radio', 'select', 'checkbox'].includes(item.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur','change']},
]"
>
<!-- 数值类型 -->
<template v-if="item.Type==='number'">
<el-input
v-model="questionForm[item.Id]"
:disabled="!isCurrentTask || readingTaskState>=2 "
@change="((val)=>{formItemChange(val, item)})"
@blur="limitBlur(item.Id, item.ValueType)"
>
<template v-if="item.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(item.Unit)) }}
</template>
</el-input>
</template>
</el-form-item>
</template>
</div>
<div
v-if="isCurrentTask && readingTaskState<2"
class="base-dialog-footer"
style="text-align:right;margin-top:10px;"
>
<!-- 保存 -->
<el-button
type="primary"
size="mini"
:disabled="!formChanged"
@click="handleSave(index)"
>
{{ $t('common:button:save') }}
</el-button>
</div>
</div>
</el-form>
</div>
</div>
</template>
<!-- 计算值 -->
<Questions
ref="ecrf2"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="4"
style="margin-top:20px"
/>
<!-- 评估结果 -->
<Questions
ref="ecrf3"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="5"
/>
</div>
</div>
</template>
<script>
import { saveTaskQuestion } from '@/api/trials'
import { resetReadingTask } from '@/api/reading'
import DicomEvent from './../DicomEvent'
import store from '@/store'
import { mapGetters } from 'vuex'
import Questions from './../Questions'
import QuestionForm from './QuestionForm'
export default {
name: 'MeasurementList',
components: {
Questions,
QuestionForm
},
props: {
isShow: {
type: Boolean,
required: true
},
isReadingShowSubjectInfo: {
type: Boolean,
required: true
},
questionFormChangeState: {
type: Boolean,
default() {
return false
}
},
questionFormChangeNum: {
type: Number,
default() {
return 0
}
}
},
data() {
return {
height: window.innerHeight - 140,
questions: [],
activeName: '',
activeItem: {
activeRowIndex: null,
activeCollapseId: null
},
visitTaskId: '',
isCurrentTask: false,
loading: false,
unSaveTargets: [],
temporaryLesions: [],
readingTaskState: 2,
isBaseLineTask: false,
taskBlindName: '',
tableQuestions: [],
isFirstRender: false,
CriterionType: null,
subjectCode: '',
questionForm: {},
formChanged: false,
digitPlaces: 2
}
},
computed: {
...mapGetters(['visitTaskList', 'language', 'lastCanvasTaskId', 'currentReadingTaskState'])
},
watch: {
lastCanvasTaskId: {
immediate: true,
handler(val) {
if (val) {
this.initList()
}
}
},
currentReadingTaskState: {
immediate: true,
handler(val) {
if (val) {
this.readingTaskState = val
}
}
}
},
mounted() {
// this.subjectCode = this.$router.currentRoute.query.subjectCode
this.subjectCode = localStorage.getItem('subjectCode')
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
window.addEventListener('message', this.receiveMsg)
this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
DicomEvent.$on('setCollapseActive', measureData => {
this.setCollapseActive(measureData)
console.log('setCollapseActive')
})
DicomEvent.$on('getAllUnSaveLesions', (callback) => {
callback([])
})
DicomEvent.$on('refreshQuestions', _ => {
this.refreshQuestions()
})
window.addEventListener('resize', this.setHeight)
},
beforeDestroy() {
DicomEvent.$off('setCollapseActive')
DicomEvent.$off('getUnSaveTarget')
DicomEvent.$off('refreshQuestions')
},
methods: {
async initList() {
var i = this.visitTaskList.findIndex(i => i.VisitTaskId === this.lastCanvasTaskId)
if (i > -1) {
this.visitTaskId = this.visitTaskList[i].VisitTaskId
this.taskBlindName = this.visitTaskList[i].TaskBlindName
this.readingTaskState = this.visitTaskList[i].ReadingTaskState
this.isBaseLineTask = this.visitTaskList[i].IsBaseLineTask
this.isCurrentTask = this.visitTaskList[i].IsCurrentTask
this.activeName = ''
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
if (!this.visitTaskList[i].IsInit) {
var loading = this.$loading({ fullscreen: true })
var triald = this.trialId = this.$router.currentRoute.query.trialId
if (!this.visitTaskList[i].studyListInit) {
await store.dispatch('reading/getStudyInfo', { trialId: triald, subjectVisitId: this.visitTaskList[i].VisitId, visitTaskId: this.visitTaskList[i].VisitTaskId, taskBlindName: this.visitTaskList[i].TaskBlindName })
}
if (!this.visitTaskList[i].readingQuestionsInit) {
await store.dispatch('reading/getReadingQuestionAndAnswer', { trialId: triald, visitTaskId: this.visitTaskList[i].VisitTaskId })
}
if (!this.visitTaskList[i].questionsInit) {
await store.dispatch('reading/getDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskList[i].VisitTaskId })
}
await store.dispatch('reading/setStatus', { visitTaskId: this.visitTaskList[i].VisitTaskId })
loading.close()
}
this.questions = this.visitTaskList[i].ReadingQuestions
this.setQuestionForm(this.questions)
this.$nextTick(() => {
this.$refs['ecrf'].getQuestions(this.visitTaskId)
this.$refs['ecrf2'].getQuestions(this.visitTaskId)
this.$refs['ecrf3'].getQuestions(this.visitTaskId)
this.getTableQuestions()
this.tableQuestions.forEach(item => {
item.TableQuestions.Answers.forEach(i => {
var refName = `${item.Id}_${i.RowIndex}`
this.$refs[refName] && this.$refs[refName][0].initForm()
})
})
})
}
},
setQuestionForm(questions) {
const type = ['number', 'radio', 'select', 'input', 'textarea', 'calculation']
questions.forEach(item => {
if (type.includes(item.Type)) {
const answer = item.Type === 'number' || item.Type === 'calculation' ? isNaN(parseFloat(item.Answer)) ? null : parseFloat(item.Answer) : item.Answer
this.$set(this.questionForm, item.Id, answer)
}
if (item.Childrens.length > 0) {
this.setQuestionForm(item.Childrens)
}
})
},
async resetQuestions(obj) {
this.setQuestions(this.questions, obj)
await store.dispatch('reading/setReadingQuestionAndAnswer', { questions: this.questions, visitTaskId: this.visitTaskId })
this.getTableQuestions()
},
setQuestions(questions, obj) {
questions.forEach(item => {
if (item.Type === 'table' && item.Id === obj.questionId) {
var idx = item.TableQuestions.Answers.findIndex(i => i.RowIndex === obj.rowIndex)
item.TableQuestions.Answers[idx].saveTypeEnum = obj.saveTypeEnum
item.TableQuestions.Answers[idx].area1 = obj.area1
item.TableQuestions.Answers[idx].area2 = obj.area2
item.TableQuestions.Answers[idx].diff = obj.diff
for (const i in obj.anwsers) {
item.TableQuestions.Answers[idx][i] = String(obj.anwsers[i])
}
}
if (item.Childrens.length > 0) {
this.setQuestions(item.Childrens, obj)
}
})
},
getQuestions(questions) {
questions.forEach(item => {
if (item.Type === 'table' && item.TableQuestions && item.TableQuestions.Answers.length > 0) {
item.TableQuestions.Answers.forEach(answerObj => {
if (answerObj.RowId) {
var diffVal = this.getQuestionAnswer(item.TableQuestions.Questions, 1003, answerObj)
this.$set(answerObj, 'saveTypeEnum', isNaN(parseFloat(diffVal)) ? 1 : 2)
} else {
this.$set(answerObj, 'saveTypeEnum', 0)
}
})
}
if (item.Childrens.length > 0) {
this.getQuestions(item.Childrens)
}
})
return questions
},
getTableQuestions() {
this.tableQuestions = []
this.questions.map(item => {
if (item.Type === 'table') {
this.tableQuestions.push(item)
}
if (item.Childrens.length > 0) {
this.getTableQuestionsChild(item.Childrens)
}
})
},
getTableQuestionsChild(obj) {
obj.map(item => {
if (item.Type === 'table') {
this.tableQuestions.push(item)
}
if (item.Childrens.length > 0) {
this.getTableQuestionsChild(item.Childrens)
}
})
},
refreshReadingQuestionAndAnswer(type) {
if (type === 0) {
//
this.activeName = ''
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
}
this.getReadingQuestionAndAnswer(this.visitTaskId)
},
getReadingQuestionAndAnswer() {
return new Promise(async resolve => {
try {
const loading = this.$loading({ fullscreen: true })
await store.dispatch('reading/refreshReadingQuestionAndAnswer', { trialId: this.$router.currentRoute.query.trialId, visitTaskId: this.visitTaskId }).then(() => {
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
if (idx > -1) {
if (this.visitTaskList[idx].ReadingQuestions.length > 0) {
this.questions = this.visitTaskList[idx].ReadingQuestions
this.setQuestionForm(this.questions)
}
this.readingTaskState = this.visitTaskList[idx].ReadingTaskState
this.isBaseLineTask = this.visitTaskList[idx].IsBaseLineTask
this.isCurrentTask = this.visitTaskList[idx].IsCurrentTask
}
this.getTableQuestions()
this.$nextTick(() => {
this.tableQuestions.forEach(item => {
item.TableQuestions.Answers.forEach(i => {
var refName = `${item.Id}_${i.RowIndex}`
this.$refs[refName] && this.$refs[refName][0].initForm()
})
})
})
})
loading.close()
resolve()
} catch (e) { console.log(e) }
})
},
setHeight() {
this.height = window.innerHeight - 140
},
getQuestionAnswer(questions, questionMark, answers) {
var idx = questions.findIndex(i => i.QuestionMark === questionMark)
if (idx > -1) {
var questionId = questions[idx].Id
return answers[questionId]
} else {
return ''
}
},
isCanActiveTool(toolName) {
return { isCanActiveTool: true, reason: '' }
},
async handleAdd(qs) {
if (!!qs.MaxQuestionCount && qs.MaxQuestionCount <= qs.TableQuestions.Answers.length) {
let msg = this.$t('trials:reading:warnning:msg14')
// msg = msg.replace('xxx', qs.QuestionName)
msg = msg.replace('xxx', qs.MaxQuestionCount)
this.$confirm(msg, {
type: 'warning',
showCancelButton: false,
callback: action => {}
})
} else {
// saveTypeEnum: 0
var obj = { saveTypeEnum: 0 }
// var questions = qs.TableQuestions.Questions.find(item => item.QuestionMark === 3)
// if (questions) {
// console.log(questions)
// var maxIndex = this.getMaxRowIndex(qs.TableQuestions.Answers)
// obj.RowIndex = `${maxIndex + 1}.00`
// obj[questions.Id] = `${qs.OrderMark}${String(maxIndex + 1).padStart(2, '0')}`
// }
var maxIndex = this.getMaxRowIndex(qs.TableQuestions.Answers)
obj.RowIndex = `${maxIndex + 1}.00`
obj.IsDicomReading = true
await store.dispatch('reading/addReadingQuestionAndAnswer', { lesionType: qs.LesionType, visitTaskId: this.visitTaskId, lesionObj: obj })
this.activeItem.activeRowIndex = String(obj.RowIndex)
this.activeItem.activeCollapseId = qs.Id
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
}
},
getMaxRowIndex(answerList) {
if (answerList.length > 0) {
var arr = []
answerList.forEach(item => {
var rowIndex = item.RowIndex
arr.push(parseInt(rowIndex))
})
var max = Math.max.apply(null, arr)
return max
} else {
return 0
}
},
getLesionName(orderMark, rowIndex) {
var lessionName = ''
var rowIndexArr = rowIndex.split('.')
var x = parseInt(rowIndexArr[0])
var y = parseInt(rowIndexArr[1])
if (y > 0) {
y = String.fromCharCode(parseInt(rowIndexArr[1]) - 1 + 65 + 32)
lessionName = `${orderMark}${String(x).padStart(2, '0')}${y}`
} else {
lessionName = `${orderMark}${String(x).padStart(2, '0')}`
}
return lessionName
},
handleCollapseChange(val) {
if (this.activeName) {
var arr = this.activeName.split('_')
this.activeItem.activeRowIndex = arr[1]
this.activeItem.activeCollapseId = arr[0]
} else {
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
}
},
collapseRightClick(e, obj, activeCollapseId, activeRowIndex) {
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
},
setCollapseActive(measureData) {
},
modifyMeasuredData(measureObj) {
},
//
setMeasuredData(measureData) {
},
formItemChange() {
this.formChanged = true
},
limitBlur(qId, valueType) {
const value = this.questionForm[qId]
if (isNaN(parseInt(value))) return
if (valueType === 0) {
this.$set(this.questionForm, qId, parseInt(value))
} else if (valueType === 3) {
this.$set(this.questionForm, qId, parseFloat(value))
} else {
this.$set(this.questionForm, qId, parseFloat(value).toFixed(this.digitPlaces))
}
},
numberToFixed(v, unit) {
return isNaN(parseFloat(v)) ? null : `${parseFloat(v).toFixed(this.digitPlaces)}${unit}`
},
async handleSave(index) {
const refName = `questions${index}`
const valid = await this.$refs[refName][0].validate()
if (!valid) return
const loading = this.$loading({ fullscreen: true })
var answers = []
for (const k in this.questionForm) {
answers.push({ id: k, answer: this.questionForm[k] })
}
var params = {
visitTaskId: this.visitTaskId,
answers: answers
}
try {
await saveTaskQuestion(8, params)
this.$message.success(this.$t('common:message:savedSuccessfully'))
loading.close()
DicomEvent.$emit('getReportInfo', true)
this.refreshQuestions()
this.formChanged = false
} catch (e) {
console.log(e)
loading.close()
}
},
async close(questionsObj) {
if (questionsObj) {
this.getReadingQuestionAndAnswer(questionsObj.visitTaskId)
this.refreshQuestions()
}
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
this.activeName = ''
},
getECRFQuestions(obj) {
this.$refs['ecrf'].getQuestions(obj.visitTaskId)
this.$refs['ecrf2'].getQuestions(obj.visitTaskId)
this.$refs['ecrf3'].getQuestions(obj.visitTaskId)
},
async resetMeasuredData() {
const confirm = await this.$confirm(
this.$t('trials:dicomReading:message:confirmReset1'),
this.$t('trials:dicomReading:message:confirmReset2'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
const loading = this.$loading({ fullscreen: true })
try {
const res = await resetReadingTask({ visitTaskId: this.visitTaskId })
this.loading = false
if (res.IsSuccess) {
//
this.activeName = ''
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
await this.getReadingQuestionAndAnswer(this.visitTaskId)
const triald = this.$router.currentRoute.query.trialId
await store.dispatch('reading/refreshDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskId })
this.$refs['ecrf'].getQuestions(this.visitTaskId, true)
this.$refs['ecrf2'].getQuestions(this.visitTaskId, true)
this.$refs['ecrf3'].getQuestions(this.visitTaskId, true)
DicomEvent.$emit('getReportInfo', true)
}
loading.close()
} catch (e) {
loading.close()
console.log(e)
}
},
async refreshQuestions() {
const triald = this.$router.currentRoute.query.trialId
await store.dispatch('reading/refreshDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskId })
this.$refs['ecrf'].getQuestions(this.visitTaskId, true)
this.$refs['ecrf2'].getQuestions(this.visitTaskId, true)
this.$refs['ecrf3'].getQuestions(this.visitTaskId, true)
},
receiveMsg(event) {
}
}
}
</script>
<style lang="scss" scoped>
.measurement-wrapper{
overflow-y: auto;
// overflow: hidden;
.container{
padding: 10px;
.basic-info{
display: flex;
justify-content: space-between;
align-items: center;
h3{
color: #ddd;
padding: 5px 0px;
margin: 0;
}
i{
color: #fff;
font-size: 22px;
font-weight: bold;
cursor: pointer;
}
}
}
.title{
padding: 5px;
font-weight: bold;
color: #ddd;
font-size: 15px;
}
.add-icon{
padding: 5px;
font-weight: bold;
color: #ddd;
font-size: 15px;
border: 1px solid #938b8b;
margin-bottom: 2px;
cursor: pointer;
}
.add-icon:hover{
background-color: #607d8b;
}
.flex-row{
display: flex;
flex-direction: row;
justify-content: space-between;
background-color: #424242;
}
.lesion_list{
position: relative;
/deep/ .el-form-item__label{
color: #c3c3c3;
text-align: left;
}
/deep/ .el-input .el-input__inner{
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
/deep/ .el-form-item{
display: flex;
flex-direction: column;
justify-content: flex-start;
}
/deep/ .el-form-item__content{
flex: 1;
}
/deep/ .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
/deep/ .el-select.is-disabled .el-input__inner{
background-color: #646464a1;
}
/deep/ .el-button--mini, .el-button--mini.is-round {
padding: 7px 10px;
}
.el-form-item__content
.el-select{
width: 100%;
}
}
.el-collapse{
border-bottom:none;
border-top:none;
/deep/ .el-collapse-item{
background-color: #000!important;
color: #ddd;
}
/deep/ .el-collapse-item__header{
background-color: #000!important;
color: #ddd;
border-bottom-color:#5a5a5a;
padding-left: 5px;
height: 35px;
line-height: 35px;
}
/deep/ .el-collapse-item__wrap{
background-color: #000!important;
color: #ddd;
}
/deep/ .el-collapse-item__content{
width:260px;
position: absolute;
top: 0px;
right: 0px;
// border: 1px solid #ffeb3b;
border: 1px solid #fff;
z-index: 1;
color: #ddd;
padding: 5px;
background-color:#1e1e1e;
}
}
}
</style>

View File

@ -276,7 +276,6 @@ import { submitTableQuestion, deleteReadingRowAnswer, getIsSuvMaxLesion } from '
// import { uploadPrintscreen } from '@/api/reading' // import { uploadPrintscreen } from '@/api/reading'
import DicomEvent from './../DicomEvent' import DicomEvent from './../DicomEvent'
import store from '@/store' import store from '@/store'
import Viewer from 'v-viewer'
export default { export default {
name: 'MeasurementForm', name: 'MeasurementForm',
props: { props: {
@ -353,7 +352,6 @@ export default {
} }
}, },
mounted() { mounted() {
this.initializeViewer()
this.trialId = this.$route.query.trialId this.trialId = this.$route.query.trialId
this.initForm() this.initForm()
DicomEvent.$on('handleImageQualityAbnormal', () => { DicomEvent.$on('handleImageQualityAbnormal', () => {
@ -380,11 +378,6 @@ export default {
} }
} }
}, },
initializeViewer() {
Viewer.setDefaults({
toolbar: { zoomIn: true, zoomOut: true, rotateLeft: true, rotateRight: true, flipHorizontal: true, flipVertical: true }
})
},
previewImage() { previewImage() {
this.$refs.viewer[0].$viewer.show() this.$refs.viewer[0].$viewer.show()
}, },

View File

@ -0,0 +1,534 @@
<template>
<el-form
v-if="isRender"
ref="measurementForm"
v-loading="loading"
:model="questionForm"
size="mini"
class="measurement-form"
>
<div class="base-dialog-body">
<div style="display: flex;justify-content: space-between;">
<h3 v-if="questionName" style="color: #ddd;padding: 5px 0px;margin: 0;">
<!-- {{ `${questionName} (${orderMark}${String(rowIndex).padStart(2, '0')})` }} -->
{{ lesionName }}
</h3>
<!-- 关闭 -->
<div>
<i class="el-icon-circle-close" style="font-size: 25px;cursor: pointer;" @click="handleClose" />
</div>
</div>
<el-form-item
v-for="qs in questions"
v-show="qs.ShowQuestion!==2"
:key="qs.Id"
:label="`${qs.QuestionName}`"
:prop="qs.Id"
:rules="[
{ required: (qs.IsRequired === 0 || (qs.IsRequired ===1 && qs.RelevanceId && (questionForm[qs.RelevanceId] === qs.RelevanceValue))) && qs.Type!=='group' && qs.Type!=='summary',
message:['radio', 'select', 'checkbox'].includes(qs.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur','change']},
]"
>
<!-- 输入框 -->
<template v-if="qs.Type==='input'">
<el-input
v-model="questionForm[qs.Id]"
:disabled="!isCurrentTask || readingTaskState>=2 "
@change="((val)=>{formItemChange(val, qs)})"
/>
</template>
<!-- 数值类型 -->
<template v-if="qs.Type==='number'">
<el-input
v-model="questionForm[qs.Id]"
:disabled="!isCurrentTask || readingTaskState>=2 "
@change="((val)=>{formItemChange(val, qs)})"
@blur="limitBlur(qs.Id, qs.ValueType)"
>
<template v-if="qs.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
</template>
</el-input>
</template>
<!-- 自动计算 -->
<template v-if="qs.Type==='calculation'">
<el-input
v-model="questionForm[qs.Id]"
disabled
@change="((val)=>{formItemChange(val, qs)})"
>
<template v-if="qs.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(qs.Unit)) }}
</template>
</el-input>
</template>
<!-- 多行文本输入框 -->
<el-input
v-if="qs.Type==='textarea'"
v-model="questionForm[qs.Id]"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:disabled="!isCurrentTask || readingTaskState>=2"
@change="((val)=>{formItemChange(val, qs)})"
/>
<el-select
v-if="qs.Type==='select'"
v-model="questionForm[qs.Id]"
filterable
:placeholder="$t('common:placeholder:select')"
:disabled="!isCurrentTask || readingTaskState>=2"
@change="((val)=>{formItemChange(val, qs)})"
>
<template v-if="qs.DictionaryCode">
<el-option
v-for="item of $d[qs.DictionaryCode]"
:key="item.id"
:value="item.value"
:label="item.label"
/>
</template>
<template v-else>
<el-option
v-for="val in qs.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<!-- 单选 -->
<el-radio-group
v-if="qs.Type==='radio'"
v-model="questionForm[qs.id]"
:disabled="!isCurrentTask || readingTaskState>=2"
>
<el-radio
v-for="val in qs.options.split('|')"
:key="val"
:label="val"
>
{{ val }}
</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div
v-if="isCurrentTask && readingTaskState<2"
class="base-dialog-footer"
style="text-align:right;margin-top:10px;"
>
<!-- 删除 -->
<el-button
v-if="isCurrentTaskAdd !== 'False'"
size="mini"
@click="handleDelete"
>
{{ $t('common:button:delete') }}
</el-button>
<!-- 保存 -->
<el-button
size="mini"
@click="handleSave"
>
{{ $t('common:button:save') }}
</el-button>
</div>
</el-form>
</template>
<script>
import { submitTableQuestion, deleteReadingRowAnswer } from '@/api/trials'
import DicomEvent from './../DicomEvent'
// import store from '@/store'
export default {
name: 'MeasurementForm',
props: {
questions: {
type: Array,
default() { return [] }
},
answers: {
type: Object,
default() { return {} }
},
lesionType: {
type: Number,
required: true
},
visitTaskId: {
type: String,
required: true
},
parentQsId: {
type: String,
required: true
},
isCurrentTask: {
type: Boolean,
required: true
},
readingTaskState: {
type: Number,
required: true
},
isBaseLineTask: {
type: Boolean,
required: true
},
orderMark: {
type: String,
default: ''
},
questionName: {
type: String,
required: true
},
rowIndex: {
type: String,
required: true
},
tableQuestions: {
type: Array,
default() { return [] }
}
},
data() {
return {
questionForm: {},
loading: false,
trialId: '',
originalQuestionForm: {},
isRender: false,
toolType: '',
lesionName: '',
isCurrentTaskAdd: 'False',
lesionMark: '',
pictureBaseStr: '',
digitPlaces: 2
}
},
mounted() {
this.trialId = this.$route.query.trialId
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.initForm()
DicomEvent.$on('handleImageQualityAbnormal', () => {
})
},
beforeDestroy() {
DicomEvent.$off('handleImageQualityAbnormal')
},
methods: {
async initForm() {
const loading = this.$loading({ fullscreen: true })
this.questions.forEach(item => {
var val = this.answers[item.Id]
if (item.DictionaryCode) {
val = isNaN(parseInt(this.answers[item.Id])) ? this.answers[item.Id] : parseInt(this.answers[item.Id])
}
this.$set(this.questionForm, item.Id, val)
})
this.$set(this.questionForm, 'RowIndex', this.answers.RowIndex ? this.answers.RowIndex : '')
this.$set(this.questionForm, 'RowId', this.answers.RowId ? this.answers.RowId : '')
if (this.questionForm.RowId) {
this.$set(this.questionForm, 'saveTypeEnum', 2)
} else {
this.$set(this.questionForm, 'saveTypeEnum', 0)
}
this.$set(this.questionForm, 'IsDicomReading', this.answers.IsDicomReading !== 'False')
if (!this.questionForm.LesionType) {
this.$set(this.questionForm, 'LesionType', this.lesionType)
}
this.lesionName = this.getLesionInfo(this.orderMark, this.rowIndex)
this.isCurrentTaskAdd = this.answers.IsCurrentTaskAdd ? this.answers.IsCurrentTaskAdd : 'True'
this.lesionMark = this.getLesionName(this.orderMark, this.questionForm.RowIndex)
this.originalQuestionForm = { ...this.questionForm }
this.isRender = true
loading.close()
},
getLesionName(orderMark, rowIndex) {
var lessionName = ''
var rowIndexArr = rowIndex.split('.')
var x = parseInt(rowIndexArr[0])
var y = parseInt(rowIndexArr[1])
if (y > 0) {
y = String.fromCharCode(parseInt(rowIndexArr[1]) - 1 + 65 + 32)
lessionName = `${orderMark}${String(x).padStart(2, '0')}${y}`
} else {
lessionName = `${orderMark}${String(x).padStart(2, '0')}`
}
return lessionName
},
getLesionInfo(orderMark, rowIndex) {
var arr = []
var lessionName = ''
var rowIndexArr = rowIndex.split('.')
var x = parseInt(rowIndexArr[0])
var y = parseInt(rowIndexArr[1])
if (y > 0) {
y = String.fromCharCode(parseInt(rowIndexArr[1]) - 1 + 65 + 32)
lessionName = `${orderMark}${String(x).padStart(2, '0')}${y}`
arr.push(lessionName)
} else {
lessionName = `${orderMark}${String(x).padStart(2, '0')}`
arr.push(lessionName)
}
return arr.join(' ')
},
getQuestionId(questionMark) {
var idx = this.questions.findIndex(i => i.QuestionMark === questionMark)
if (idx > -1) {
return this.questions[idx].Id
} else {
return ''
}
},
async formItemChange(v, question) {
if (this.questionForm.RowId) {
this.$set(this.questionForm, 'saveTypeEnum', 1)
} else {
this.$set(this.questionForm, 'saveTypeEnum', 0)
}
if (question.QuestionMark === 1011 || question.QuestionMark === 1012 || question.QuestionMark === 1013) {
//
this.questionForm[this.getQuestionId(1014)] = this.calculate([1011, 1012, 1013], 'min')
//
this.questionForm[this.getQuestionId(1015)] = this.calculate([1011, 1012, 1013], 'avg')
}
let l1, l2, l3, min, mean, angle
if (this.lesionType === 101) {
l1 = this.getQuestionVal(1011)
l2 = this.getQuestionVal(1012)
l3 = this.getQuestionVal(1013)
min = this.getQuestionVal(1014)
mean = this.getQuestionVal(1015)
} else if (this.lesionType === 103) {
angle = this.getQuestionVal(1016)
}
this.$emit('resetQuestions', { l1, l2, l3, min, mean, angle, saveTypeEnum: this.questionForm.saveTypeEnum, rowIndex: this.rowIndex, questionId: this.parentQsId, anwsers: this.questionForm })
},
calculate(qsMarkArr, type) {
var num = 0
const arr = []
for (let i = 0; i < qsMarkArr.length; i++) {
const mark = qsMarkArr[i]
let v = this.questionForm[this.getQuestionId(mark)]
if (isNaN(parseFloat(v))) {
num = null
break
}
v = parseFloat(v)
if (i === 0) {
num = v
arr.push(v)
} else {
switch (type) {
case 'min':
num = num > v ? v : num
break
case 'avg':
arr.push(v)
if (arr.length === qsMarkArr.length) {
num = arr.reduce((acc, curr) => {
return acc + curr
}, 0) / arr.length
}
break
}
}
}
return num === null ? num : num.toFixed(this.digitPlaces)
},
limitBlur(qId, valueType) {
const value = this.questionForm[qId]
if (isNaN(parseInt(value))) return
if (valueType === 0) {
this.$set(this.questionForm, qId, parseInt(value))
} else if (valueType === 3) {
this.$set(this.questionForm, qId, parseFloat(value))
} else {
this.$set(this.questionForm, qId, parseFloat(value).toFixed(this.digitPlaces))
}
},
returnFloat(num) {
if (num) return
var value = Math.round(parseFloat(num) * 100) / 100
var s = value.toString().split('.')
if (s.length === 1) {
value = value.toString() + '.00'
return value
}
if (s.length > 1) {
if (s[1].length < 2) {
value = value.toString() + '0'
}
return value
}
},
getQuestionVal(questionMark) {
const idx = this.questions.findIndex(i => i.QuestionMark === questionMark)
if (idx > -1) {
const questionId = this.questions[idx].Id
const answer = this.questionForm[questionId]
if (isNaN(parseFloat(answer))) {
return answer
} else {
return parseFloat(answer)
}
} else {
return ''
}
},
async handleSave() {
const valid = await this.$refs.measurementForm.validate()
if (!valid) return
const loading = this.$loading({ fullscreen: true })
try {
var answers = []
var reg = new RegExp(/^[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}$/)
for (const k in this.questionForm) {
if (reg.test(k)) {
if (answers.findIndex(i => i.tableQuestionId === k) === -1) {
answers.push({ tableQuestionId: k, answer: this.questionForm[k] })
}
}
}
var params = {
questionId: this.parentQsId,
rowId: this.questionForm.RowId,
rowIndex: this.answers.RowIndex,
visitTaskId: this.visitTaskId,
trialId: this.trialId,
answerList: answers
}
const res = await submitTableQuestion(params)
if (res.IsSuccess) {
//
this.$message.success(this.$t('common:message:savedSuccessfully'))
this.$set(this.questionForm, 'saveTypeEnum', 2)
this.originalQuestionForm = { ...this.questionForm }
this.$set(this.questionForm, 'RowId', res.Result.RowId)
let l1, l2, l3, min, mean, angle
if (this.lesionType === 101) {
l1 = this.getQuestionVal(1011)
l2 = this.getQuestionVal(1012)
l3 = this.getQuestionVal(1013)
min = this.getQuestionVal(1014)
mean = this.getQuestionVal(1015)
} else if (this.lesionType === 103) {
angle = this.getQuestionVal(1016)
}
this.$emit('resetQuestions', { l1, l2, l3, min, mean, angle, saveTypeEnum: this.questionForm.saveTypeEnum, rowIndex: this.rowIndex, questionId: this.parentQsId, anwsers: this.questionForm })
this.$emit('close')
DicomEvent.$emit('refreshQuestions')
DicomEvent.$emit('getReportInfo', true)
}
loading.close()
} catch (e) {
console.log(e)
loading.close()
}
},
async handleDelete() {
const loading = this.$loading({ fullscreen: true })
try {
const confirm = await this.$confirm(
this.$t('trials:reading:warnning:msg48'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
if (this.questionForm.RowId) {
var param = {
visitTaskId: this.visitTaskId,
questionId: this.parentQsId,
rowId: this.questionForm.RowId
}
const res = await deleteReadingRowAnswer(param)
if (res.IsSuccess) {
this.$emit('close', { lesionType: this.lesionType, rowIndex: this.rowIndex, visitTaskId: this.visitTaskId })
DicomEvent.$emit('getReportInfo', true)
// ''
this.$message.success(this.$t('common:message:deletedSuccessfully'))
}
} else {
this.$emit('close', { lesionType: this.lesionType, rowIndex: this.rowIndex, visitTaskId: this.visitTaskId })
}
loading.close()
} catch (e) {
loading.close()
console.log(e)
}
},
async handleClose() {
if (!this.questionForm.RowId) {
// ''
const confirm = await this.$confirm(
this.$t('trials:reading:warnning:msg60'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
this.$emit('close', { lesionType: this.lesionType, rowIndex: this.rowIndex, visitTaskId: this.visitTaskId })
} else {
this.$emit('close')
}
}
}
}
</script>
<style lang="scss" scoped>
.measurement-form{
/deep/ .el-form-item__label{
color: #c3c3c3;
text-align: left;
}
/deep/ .el-input .el-input__inner{
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
/deep/ .el-form-item{
display: flex;
flex-direction: row;
justify-content: flex-start;
}
/deep/ .el-form-item__content{
flex: 1;
}
/deep/ .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
/deep/ .el-select.is-disabled .el-input__inner{
background-color: #646464a1;
}
/deep/ .el-button--mini, .el-button--mini.is-round {
padding: 7px 10px;
}
.el-form-item__content
.el-select{
width: 100%;
}
.input-width1{
width: calc(100% -60px)!important;
}
.input-width2{
width: 100% !important;
}
}
</style>

View File

@ -0,0 +1,780 @@
<template>
<div class="measurement-wrapper" :style="{'height':height+10+'px'}">
<div class="container" :style="{'height':height+'px'}">
<div class="basic-info">
<h3 v-if="isReadingShowSubjectInfo">
<span v-if="subjectCode">{{ subjectCode }} </span>
<span style="margin-left:5px;">{{ taskBlindName }}</span>
</h3>
<div v-if="readingTaskState < 2">
<el-tooltip class="item" effect="dark" :content="$t('trials:dicomReading:message:confirmReset')" placement="bottom">
<i
class="el-icon-refresh-left"
@click="resetMeasuredData"
/>
</el-tooltip>
</div>
</div>
<!-- 影像质量问题 -->
<div class="lesions">
<Questions
ref="ecrf"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="1"
/>
</div>
<!-- 测量问题 -->
<template v-if="questions.length > 0 && CriterionType !== 10">
<div v-for="(qs,index) in questions" :key="index" v-loading="loading" class="lesions lesions_wrapper">
<h4 v-if="qs.Type === 'group'" style="color: #ddd;padding: 5px 0px;margin: 0;">
{{ language==='en'?qs.GroupEnName:qs.GroupName }}
</h4>
<div class="lesion_list">
<el-form
v-if="questions.length > 0"
:ref="`questions${index}`"
size="small"
:model="questionForm"
>
<div class="base-dialog-body">
<div v-for="item in qs.Childrens" :key="item.Id">
<div v-if="item.Type === 'table'" class="flex-row" style="margin:3px 0;">
<div class="title">{{ item.QuestionName }}</div>
<div v-if="readingTaskState < 2" class="add-icon" @click.prevent="handleAdd(item)">
<i class="el-icon-plus" />
</div>
</div>
<el-collapse
v-if="item.Type === 'table' && item.TableQuestions"
v-model="activeName"
accordion
style="margin-bottom: 10px;"
@change="handleCollapseChange"
>
<el-collapse-item
v-for="(q,i) in item.TableQuestions.Answers"
:key="`${item.Id}_${q.RowIndex}`"
:name="`${item.Id}_${q.RowIndex}`"
>
<template slot="title">
<div style="width:300px;position: relative;" :style="{color:(activeName===item.Id+q.RowIndex?'#ffeb3b':'#fff')}">
{{ getLesionName(item.OrderMark,q.RowIndex) }}
<!-- 未保存 -->
<el-tooltip v-if="readingTaskState<2 && parseInt(item.TableQuestions.Answers[i].saveTypeEnum) === 0" class="item" effect="dark" :content="$t('trials:reading:button:unsaved')" placement="bottom">
<i class="el-icon-warning" style="color:red" />
</el-tooltip>
<!-- 信息不完整 -->
<el-tooltip v-if="readingTaskState<2 && parseInt(item.TableQuestions.Answers[i].saveTypeEnum) ===1" class="item" effect="dark" :content="$t('trials:reading:button:incompleteInfor')" placement="bottom">
<i class="el-icon-warning" style="color:#ff9800" />
</el-tooltip>
<div style="position: absolute;left: 60px;top: 2px;">
<div style="display: flex;flex-direction: row;font-size: 11px;width:200px;height: 30px;">
<div v-show="item.LesionType === 101" style="margin-left:10px;">
min: {{ numberToFixed(item.TableQuestions.Answers[i].min,'μm') }}
</div>
<div v-show="item.LesionType === 101" style="margin-left:10px;">
mean: {{ numberToFixed(item.TableQuestions.Answers[i].mean,'μm') }}
</div>
<div v-show="item.LesionType === 103" style="margin-left:10px;">
{{ numberToFixed(item.TableQuestions.Answers[i].angle,'°') }}
</div>
</div>
</div>
</div>
</template>
<QuestionForm
:ref="`${item.Id}_${q.RowIndex}`"
:questions="item.TableQuestions.Questions"
:answers="item.TableQuestions.Answers[i]"
:lesion-type="item.LesionType"
:order-mark="item.OrderMark"
:table-questions="tableQuestions"
:row-index="String(q.RowIndex)"
:question-name="item.QuestionName"
:parent-qs-id="item.Id"
:visit-task-id="visitTaskId"
:is-current-task="isCurrentTask"
:reading-task-state="readingTaskState"
:is-base-line-task="isBaseLineTask"
@getReadingQuestionAndAnswer="getReadingQuestionAndAnswer"
@resetQuestions="resetQuestions"
@close="close"
/>
</el-collapse-item>
</el-collapse>
<template v-else>
<!-- 数值 -->
<el-form-item
v-if="item.ShowQuestion!==2"
:key="item.Id"
:label="`${item.QuestionName}`"
:prop="item.Id"
:rules="[
{ required: (item.IsRequired === 0 || (item.IsRequired ===1 && item.RelevanceId && (item.RelevanceValue.includes(questionForm[item.RelevanceId])))) && item.Type!=='group' && item.Type!=='summary',
message:['radio', 'select', 'checkbox'].includes(item.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur','change']},
]"
>
<!-- 数值类型 -->
<template v-if="item.Type==='number'">
<el-input
v-model="questionForm[item.Id]"
:disabled="!isCurrentTask || readingTaskState>=2 "
@change="((val)=>{formItemChange(val, item)})"
@blur="limitBlur(item.Id, item.ValueType)"
>
<template v-if="item.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(item.Unit)) }}
</template>
</el-input>
</template>
</el-form-item>
</template>
</div>
<div
v-if="isCurrentTask && readingTaskState<2"
class="base-dialog-footer"
style="text-align:right;margin-top:10px;"
>
<!-- 保存 -->
<el-button
type="primary"
size="mini"
:disabled="!formChanged"
@click="handleSave(index)"
>
{{ $t('common:button:save') }}
</el-button>
</div>
</div>
</el-form>
</div>
</div>
</template>
<!-- 计算值 -->
<Questions
ref="ecrf2"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="4"
style="margin-top:20px"
/>
<!-- 评估结果 -->
<Questions
ref="ecrf3"
:question-form-change-state="true"
:question-form-change-num="0"
:is-qulity-issues="false"
:group-classify="5"
/>
</div>
</div>
</template>
<script>
// import { saveTaskQuestion } from '@/api/trials'
import { resetReadingTask } from '@/api/reading'
import DicomEvent from './../DicomEvent'
import store from '@/store'
import { mapGetters } from 'vuex'
import Questions from './../Questions'
import QuestionForm from './QuestionForm'
export default {
name: 'MeasurementList',
components: {
Questions,
QuestionForm
},
props: {
isShow: {
type: Boolean,
required: true
},
isReadingShowSubjectInfo: {
type: Boolean,
required: true
},
questionFormChangeState: {
type: Boolean,
default() {
return false
}
},
questionFormChangeNum: {
type: Number,
default() {
return 0
}
}
},
data() {
return {
height: window.innerHeight - 140,
questions: [],
activeName: '',
activeItem: {
activeRowIndex: null,
activeCollapseId: null
},
visitTaskId: '',
isCurrentTask: false,
loading: false,
unSaveTargets: [],
temporaryLesions: [],
readingTaskState: 2,
isBaseLineTask: false,
taskBlindName: '',
tableQuestions: [],
isFirstRender: false,
CriterionType: null,
subjectCode: '',
questionForm: {},
formChanged: false,
digitPlaces: 2
}
},
computed: {
...mapGetters(['visitTaskList', 'language', 'lastCanvasTaskId', 'currentReadingTaskState'])
},
watch: {
lastCanvasTaskId: {
immediate: true,
handler(val) {
if (val) {
this.initList()
}
}
},
currentReadingTaskState: {
immediate: true,
handler(val) {
if (val) {
this.readingTaskState = val
}
}
}
},
mounted() {
// this.subjectCode = this.$router.currentRoute.query.subjectCode
this.subjectCode = localStorage.getItem('subjectCode')
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
window.addEventListener('message', this.receiveMsg)
this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
DicomEvent.$on('setCollapseActive', measureData => {
this.setCollapseActive(measureData)
console.log('setCollapseActive')
})
DicomEvent.$on('getAllUnSaveLesions', (callback) => {
callback([])
})
DicomEvent.$on('refreshQuestions', _ => {
this.refreshQuestions()
})
window.addEventListener('resize', this.setHeight)
},
beforeDestroy() {
DicomEvent.$off('setCollapseActive')
DicomEvent.$off('getUnSaveTarget')
DicomEvent.$off('refreshQuestions')
},
methods: {
async initList() {
var i = this.visitTaskList.findIndex(i => i.VisitTaskId === this.lastCanvasTaskId)
if (i > -1) {
this.visitTaskId = this.visitTaskList[i].VisitTaskId
this.taskBlindName = this.visitTaskList[i].TaskBlindName
this.readingTaskState = this.visitTaskList[i].ReadingTaskState
this.isBaseLineTask = this.visitTaskList[i].IsBaseLineTask
this.isCurrentTask = this.visitTaskList[i].IsCurrentTask
this.activeName = ''
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
if (!this.visitTaskList[i].IsInit) {
var loading = this.$loading({ fullscreen: true })
var triald = this.trialId = this.$router.currentRoute.query.trialId
if (!this.visitTaskList[i].studyListInit) {
await store.dispatch('reading/getStudyInfo', { trialId: triald, subjectVisitId: this.visitTaskList[i].VisitId, visitTaskId: this.visitTaskList[i].VisitTaskId, taskBlindName: this.visitTaskList[i].TaskBlindName })
}
if (!this.visitTaskList[i].readingQuestionsInit) {
await store.dispatch('reading/getReadingQuestionAndAnswer', { trialId: triald, visitTaskId: this.visitTaskList[i].VisitTaskId })
}
if (!this.visitTaskList[i].questionsInit) {
await store.dispatch('reading/getDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskList[i].VisitTaskId })
}
await store.dispatch('reading/setStatus', { visitTaskId: this.visitTaskList[i].VisitTaskId })
loading.close()
}
this.questions = this.visitTaskList[i].ReadingQuestions
this.setQuestionForm(this.questions)
this.$nextTick(() => {
this.$refs['ecrf'].getQuestions(this.visitTaskId)
this.$refs['ecrf2'].getQuestions(this.visitTaskId)
this.$refs['ecrf3'].getQuestions(this.visitTaskId)
this.getTableQuestions()
this.tableQuestions.forEach(item => {
item.TableQuestions.Answers.forEach(i => {
var refName = `${item.Id}_${i.RowIndex}`
this.$refs[refName] && this.$refs[refName][0].initForm()
})
})
})
}
},
setQuestionForm(questions) {
const type = ['number', 'radio', 'select', 'input', 'textarea', 'calculation']
questions.forEach(item => {
if (type.includes(item.Type)) {
const answer = item.Type === 'number' || item.Type === 'calculation' ? isNaN(parseFloat(item.Answer)) ? null : parseFloat(item.Answer) : item.Answer
this.$set(this.questionForm, item.Id, answer)
}
if (item.Childrens.length > 0) {
this.setQuestionForm(item.Childrens)
}
})
},
async resetQuestions(obj) {
this.setQuestions(this.questions, obj)
await store.dispatch('reading/setReadingQuestionAndAnswer', { questions: this.questions, visitTaskId: this.visitTaskId })
this.getTableQuestions()
},
setQuestions(questions, obj) {
questions.forEach(item => {
if (item.Type === 'table' && item.Id === obj.questionId) {
var idx = item.TableQuestions.Answers.findIndex(i => i.RowIndex === obj.rowIndex)
item.TableQuestions.Answers[idx].saveTypeEnum = obj.saveTypeEnum
if (item.LesionType === 101) {
item.TableQuestions.Answers[idx].l1 = obj.l1
item.TableQuestions.Answers[idx].l2 = obj.l2
item.TableQuestions.Answers[idx].l3 = obj.l3
item.TableQuestions.Answers[idx].min = obj.min
item.TableQuestions.Answers[idx].mean = obj.mean
} else if (item.LesionType === 103) {
item.TableQuestions.Answers[idx].angle = obj.angle
}
for (const i in obj.anwsers) {
item.TableQuestions.Answers[idx][i] = String(obj.anwsers[i])
}
}
if (item.Childrens.length > 0) {
this.setQuestions(item.Childrens, obj)
}
})
},
getQuestions(questions) {
questions.forEach(item => {
if (item.Type === 'table' && item.TableQuestions && item.TableQuestions.Answers.length > 0) {
item.TableQuestions.Answers.forEach(answerObj => {
if (answerObj.RowId) {
if (item.LesionType === 101) {
var min = this.getQuestionAnswer(item.TableQuestions.Questions, 1014, answerObj)
var mean = this.getQuestionAnswer(item.TableQuestions.Questions, 1015, answerObj)
this.$set(answerObj, 'saveTypeEnum', (isNaN(parseFloat(min)) || isNaN(parseFloat(mean))) ? 1 : 2)
} else if (item.LesionType === 103) {
var angle = this.getQuestionAnswer(item.TableQuestions.Questions, 1016, answerObj)
this.$set(answerObj, 'saveTypeEnum', isNaN(parseFloat(angle)) ? 1 : 2)
}
} else {
this.$set(answerObj, 'saveTypeEnum', 0)
}
})
}
if (item.Childrens.length > 0) {
this.getQuestions(item.Childrens)
}
})
return questions
},
getTableQuestions() {
this.tableQuestions = []
this.questions.map(item => {
if (item.Type === 'table') {
this.tableQuestions.push(item)
}
if (item.Childrens.length > 0) {
this.getTableQuestionsChild(item.Childrens)
}
})
},
getTableQuestionsChild(obj) {
obj.map(item => {
if (item.Type === 'table') {
this.tableQuestions.push(item)
}
if (item.Childrens.length > 0) {
this.getTableQuestionsChild(item.Childrens)
}
})
},
refreshReadingQuestionAndAnswer(type) {
if (type === 0) {
//
this.activeName = ''
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
}
this.getReadingQuestionAndAnswer(this.visitTaskId)
},
getReadingQuestionAndAnswer() {
return new Promise(async resolve => {
try {
const loading = this.$loading({ fullscreen: true })
await store.dispatch('reading/refreshReadingQuestionAndAnswer', { trialId: this.$router.currentRoute.query.trialId, visitTaskId: this.visitTaskId }).then(() => {
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
if (idx > -1) {
if (this.visitTaskList[idx].ReadingQuestions.length > 0) {
this.questions = this.visitTaskList[idx].ReadingQuestions
this.setQuestionForm(this.questions)
}
this.readingTaskState = this.visitTaskList[idx].ReadingTaskState
this.isBaseLineTask = this.visitTaskList[idx].IsBaseLineTask
this.isCurrentTask = this.visitTaskList[idx].IsCurrentTask
}
this.getTableQuestions()
this.$nextTick(() => {
this.tableQuestions.forEach(item => {
item.TableQuestions.Answers.forEach(i => {
var refName = `${item.Id}_${i.RowIndex}`
this.$refs[refName] && this.$refs[refName][0].initForm()
})
})
})
})
loading.close()
resolve()
} catch (e) { console.log(e) }
})
},
setHeight() {
this.height = window.innerHeight - 140
},
getQuestionAnswer(questions, questionMark, answers) {
var idx = questions.findIndex(i => i.QuestionMark === questionMark)
if (idx > -1) {
var questionId = questions[idx].Id
return answers[questionId]
} else {
return ''
}
},
isCanActiveTool(toolName) {
return { isCanActiveTool: true, reason: '' }
},
async handleAdd(qs) {
if (!!qs.MaxQuestionCount && qs.MaxQuestionCount <= qs.TableQuestions.Answers.length) {
let msg = this.$t('trials:reading:warnning:msg14')
// msg = msg.replace('xxx', qs.QuestionName)
msg = msg.replace('xxx', qs.MaxQuestionCount)
this.$confirm(msg, {
type: 'warning',
showCancelButton: false,
callback: action => {}
})
} else {
// saveTypeEnum: 0
var obj = { saveTypeEnum: 0 }
// var questions = qs.TableQuestions.Questions.find(item => item.QuestionMark === 3)
// if (questions) {
// console.log(questions)
// var maxIndex = this.getMaxRowIndex(qs.TableQuestions.Answers)
// obj.RowIndex = `${maxIndex + 1}.00`
// obj[questions.Id] = `${qs.OrderMark}${String(maxIndex + 1).padStart(2, '0')}`
// }
var maxIndex = this.getMaxRowIndex(qs.TableQuestions.Answers)
obj.RowIndex = `${maxIndex + 1}.00`
obj.IsDicomReading = true
await store.dispatch('reading/addReadingQuestionAndAnswer', { lesionType: qs.LesionType, visitTaskId: this.visitTaskId, lesionObj: obj })
this.activeItem.activeRowIndex = String(obj.RowIndex)
this.activeItem.activeCollapseId = qs.Id
this.activeName = `${this.activeItem.activeCollapseId}_${this.activeItem.activeRowIndex}`
}
},
getMaxRowIndex(answerList) {
if (answerList.length > 0) {
var arr = []
answerList.forEach(item => {
var rowIndex = item.RowIndex
arr.push(parseInt(rowIndex))
})
var max = Math.max.apply(null, arr)
return max
} else {
return 0
}
},
getLesionName(orderMark, rowIndex) {
var lessionName = ''
var rowIndexArr = rowIndex.split('.')
var x = parseInt(rowIndexArr[0])
var y = parseInt(rowIndexArr[1])
if (y > 0) {
y = String.fromCharCode(parseInt(rowIndexArr[1]) - 1 + 65 + 32)
lessionName = `${orderMark}${String(x).padStart(2, '0')}${y}`
} else {
lessionName = `${orderMark}${String(x).padStart(2, '0')}`
}
return lessionName
},
handleCollapseChange(val) {
if (this.activeName) {
var arr = this.activeName.split('_')
this.activeItem.activeRowIndex = arr[1]
this.activeItem.activeCollapseId = arr[0]
} else {
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
}
},
collapseRightClick(e, obj, activeCollapseId, activeRowIndex) {
e.stopImmediatePropagation()
e.stopPropagation()
e.preventDefault()
},
setCollapseActive(measureData) {
},
modifyMeasuredData(measureObj) {
},
//
setMeasuredData(measureData) {
},
formItemChange() {
this.formChanged = true
},
limitBlur(qId, valueType) {
const value = this.questionForm[qId]
if (isNaN(parseInt(value))) return
if (valueType === 0) {
this.$set(this.questionForm, qId, parseInt(value))
} else if (valueType === 3) {
this.$set(this.questionForm, qId, parseFloat(value))
} else {
this.$set(this.questionForm, qId, parseFloat(value).toFixed(this.digitPlaces))
}
},
numberToFixed(v, unit) {
return isNaN(parseFloat(v)) ? null : `${parseFloat(v).toFixed(this.digitPlaces)}${unit}`
},
async handleSave(index) {
// const refName = `questions${index}`
// const valid = await this.$refs[refName][0].validate()
// if (!valid) return
// const loading = this.$loading({ fullscreen: true })
// var answers = []
// for (const k in this.questionForm) {
// answers.push({ id: k, answer: this.questionForm[k] })
// }
// var params = {
// visitTaskId: this.visitTaskId,
// answers: answers
// }
// try {
// await saveTaskQuestion(8, params)
// this.$message.success(this.$t('common:message:savedSuccessfully'))
// loading.close()
// DicomEvent.$emit('getReportInfo', true)
// this.refreshQuestions()
// this.formChanged = false
// } catch (e) {
// console.log(e)
// loading.close()
// }
},
async close(questionsObj) {
if (questionsObj) {
this.getReadingQuestionAndAnswer(questionsObj.visitTaskId)
this.refreshQuestions()
}
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
this.activeName = ''
},
getECRFQuestions(obj) {
this.$refs['ecrf'].getQuestions(obj.visitTaskId)
this.$refs['ecrf2'].getQuestions(obj.visitTaskId)
this.$refs['ecrf3'].getQuestions(obj.visitTaskId)
},
async resetMeasuredData() {
const confirm = await this.$confirm(
this.$t('trials:dicomReading:message:confirmReset1'),
this.$t('trials:dicomReading:message:confirmReset2'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
const loading = this.$loading({ fullscreen: true })
try {
const res = await resetReadingTask({ visitTaskId: this.visitTaskId })
this.loading = false
if (res.IsSuccess) {
//
this.activeName = ''
this.activeItem.activeRowIndex = null
this.activeItem.activeCollapseId = null
await this.getReadingQuestionAndAnswer(this.visitTaskId)
const triald = this.$router.currentRoute.query.trialId
await store.dispatch('reading/refreshDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskId })
this.$refs['ecrf'].getQuestions(this.visitTaskId, true)
this.$refs['ecrf2'].getQuestions(this.visitTaskId, true)
this.$refs['ecrf3'].getQuestions(this.visitTaskId, true)
DicomEvent.$emit('getReportInfo', true)
}
loading.close()
} catch (e) {
loading.close()
console.log(e)
}
},
async refreshQuestions() {
const triald = this.$router.currentRoute.query.trialId
await store.dispatch('reading/refreshDicomReadingQuestionAnswer', { trialId: triald, visitTaskId: this.visitTaskId })
this.$refs['ecrf'].getQuestions(this.visitTaskId, true)
this.$refs['ecrf2'].getQuestions(this.visitTaskId, true)
this.$refs['ecrf3'].getQuestions(this.visitTaskId, true)
},
receiveMsg(event) {
}
}
}
</script>
<style lang="scss" scoped>
.measurement-wrapper{
overflow-y: auto;
// overflow: hidden;
.container{
padding: 10px;
.basic-info{
display: flex;
justify-content: space-between;
align-items: center;
h3{
color: #ddd;
padding: 5px 0px;
margin: 0;
}
i{
color: #fff;
font-size: 22px;
font-weight: bold;
cursor: pointer;
}
}
}
.title{
padding: 5px;
font-weight: bold;
color: #ddd;
font-size: 15px;
}
.add-icon{
padding: 5px;
font-weight: bold;
color: #ddd;
font-size: 15px;
border: 1px solid #938b8b;
margin-bottom: 2px;
cursor: pointer;
}
.add-icon:hover{
background-color: #607d8b;
}
.flex-row{
display: flex;
flex-direction: row;
justify-content: space-between;
background-color: #424242;
}
.lesion_list{
position: relative;
/deep/ .el-form-item__label{
color: #c3c3c3;
text-align: left;
}
/deep/ .el-input .el-input__inner{
background-color: transparent;
color: #ddd;
border: 1px solid #5e5e5e;
}
/deep/ .el-form-item{
display: flex;
flex-direction: row;
justify-content: flex-start;
}
/deep/ .el-form-item__content{
flex: 1;
}
/deep/ .el-input.is-disabled .el-input__inner{
background-color: #646464a1;
}
/deep/ .el-select.is-disabled .el-input__inner{
background-color: #646464a1;
}
/deep/ .el-button--mini, .el-button--mini.is-round {
padding: 7px 10px;
}
.el-form-item__content
.el-select{
width: 100%;
}
}
.el-collapse{
border-bottom:none;
border-top:none;
/deep/ .el-collapse-item{
background-color: #000!important;
color: #ddd;
}
/deep/ .el-collapse-item__header{
background-color: #000!important;
color: #ddd;
border-bottom-color:#5a5a5a;
padding-left: 5px;
height: 35px;
line-height: 35px;
}
/deep/ .el-collapse-item__wrap{
background-color: #000!important;
color: #ddd;
}
/deep/ .el-collapse-item__content{
width:260px;
position: absolute;
top: 0px;
right: 0px;
// border: 1px solid #ffeb3b;
border: 1px solid #fff;
z-index: 1;
color: #ddd;
padding: 5px;
background-color:#1e1e1e;
}
}
}
</style>

View File

@ -24,7 +24,7 @@
{ required: (question.IsRequired === 0 || (question.IsRequired ===1 && question.RelevanceId && (questionForm[question.RelevanceId] === question.RelevanceValue))) && question.Type!=='group' && question.Type!=='summary', { required: (question.IsRequired === 0 || (question.IsRequired ===1 && question.RelevanceId && (questionForm[question.RelevanceId] === question.RelevanceValue))) && question.Type!=='group' && question.Type!=='summary',
message: ['radio', 'select', 'checkbox'].includes(question.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']}, message: ['radio', 'select', 'checkbox'].includes(question.Type) ? $t('common:ruleMessage:select') : $t('common:ruleMessage:specify'), trigger: ['blur', 'change']},
]" ]"
:class="[question.Type==='group'?'mb':question.Type==='upload'?'uploadWrapper':'']" :class="[question.Type==='group' ? 'mb' : (question.Type==='upload' || question.QuestionName.length > 15) ?'uploadWrapper' : '']"
> >
<template v-if="question.QuestionType === 60 || question.QuestionType === 61"> <template v-if="question.QuestionType === 60 || question.QuestionType === 61">
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;"> <div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;">
@ -211,16 +211,40 @@
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
<!-- 数值 --> <!-- 数值 -->
<el-input-number <!-- <el-input-number
v-else-if="question.Type==='number'" v-else-if="question.Type==='number'"
v-model="questionForm[question.Id]" v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2 || isFirstChangeTask" :disabled="readingTaskState >= 2 || isFirstChangeTask"
/> :precision="2"
/> -->
<template v-else-if="question.Type==='number'">
<el-input-number
v-if="question.ValueType === 0"
v-model="questionForm[question.Id]"
precision="0"
:disabled="readingTaskState >= 2 || isFirstChangeTask"
/>
<el-input-number
v-else-if="question.ValueType === 3"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2 || isFirstChangeTask"
/>
<el-input-number
v-else-if="question.ValueType === 1 || question.ValueType === 2"
v-model="questionForm[question.Id]"
:precision="digitPlaces"
:disabled="readingTaskState >= 2 || isFirstChangeTask"
/>
</template>
<el-input <el-input
v-else-if="question.Type==='calculation'" v-else-if="question.Type==='calculation'"
v-model="questionForm[question.Id]" v-model="questionForm[question.Id]"
disabled disabled
/> >
<template v-if="question.Unit" slot="append">
{{ $fd('ValueUnit', parseInt(question.Unit)) }}
</template>
</el-input>
<!-- 上传图像 --> <!-- 上传图像 -->
<el-upload <el-upload
v-else-if="question.Type==='upload'" v-else-if="question.Type==='upload'"
@ -326,7 +350,8 @@ export default {
accept: '.png,.jpg,.jpeg', accept: '.png,.jpg,.jpeg',
imgVisible: false, imgVisible: false,
imageUrl: '', imageUrl: '',
urls: [] urls: [],
digitPlaces: 2
} }
}, },
computed: { computed: {
@ -352,6 +377,8 @@ export default {
}) })
} }
} }
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
}, },
methods: { methods: {
formItemChange(v, question) { formItemChange(v, question) {
@ -461,7 +488,7 @@ export default {
} }
.uploadWrapper{ .uploadWrapper{
display: flex; display: flex;
flex-direction: column; flex-direction: column !important;
align-items: flex-start; align-items: flex-start;
} }
/deep/ .el-input.is-disabled .el-input__inner{ /deep/ .el-input.is-disabled .el-input__inner{
@ -470,6 +497,9 @@ export default {
/deep/ .el-input-group__append, .el-input-group__prepend{ /deep/ .el-input-group__append, .el-input-group__prepend{
padding: 0 10px; padding: 0 10px;
} }
/deep/ .el-form-item__content {
width: 100%;
}
/deep/ .el-select.is-disabled .el-input__inner{ /deep/ .el-select.is-disabled .el-input__inner{
background-color: #646464a1; background-color: #646464a1;
} }

View File

@ -88,7 +88,7 @@ export default {
spleenInfo: null, spleenInfo: null,
calculateSpleenStatus: '', calculateSpleenStatus: '',
formChanged: false, formChanged: false,
digitPlaces: null digitPlaces: 2
} }
}, },
computed: { computed: {
@ -374,7 +374,8 @@ export default {
DicomEvent.$emit('getReportInfo', true) DicomEvent.$emit('getReportInfo', true)
// DicomEvent.$emit('readingPageUpdate', {}) // DicomEvent.$emit('readingPageUpdate', {})
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId) var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
if (idx > -1 && !this.visitTaskList[idx].IsBaseLineTask) { const criterionType = parseInt(localStorage.getItem('CriterionType'))
if (idx > -1 && !this.visitTaskList[idx].IsBaseLineTask && (criterionType === 1 || criterionType === 2 || criterionType === 3 || criterionType === 17)) {
if (parseInt(imageQuality) === 2) { if (parseInt(imageQuality) === 2) {
this.$confirm(this.$t('trials:reading:warnning:unableEvaluate'), '', { this.$confirm(this.$t('trials:reading:warnning:unableEvaluate'), '', {
type: 'warning' type: 'warning'
@ -856,6 +857,7 @@ export default {
.ecrf-wrapper{ .ecrf-wrapper{
/deep/ .el-form-item__label{ /deep/ .el-form-item__label{
color: #c3c3c3; color: #c3c3c3;
text-align: left;
} }
/deep/ .el-input__inner{ /deep/ .el-input__inner{
background-color: transparent; background-color: transparent;

View File

@ -102,7 +102,7 @@
</div> </div>
</template> </template>
<template slot-scope="scope"> <template slot-scope="scope">
<span :style="{color: ((scope.row.isLymphNodes === 1 && scope.row.QuestionMark === 1) || (scope.row.isLymphNodes === 0 && scope.row.QuestionMark === 0)) && (scope.row.LesionType === 0 || scope.row.LesionType === 5) || (scope.row.QuestionMark === 12) || scope.row.HighlightAnswerList.includes(`${scope.row.Answers[task.VisitTaskId]}`) ? '#f66' : '#fff'}" > <span :style="{color: ((scope.row.isLymphNodes === 1 && scope.row.QuestionMark === 1) || (scope.row.isLymphNodes === 0 && scope.row.QuestionMark === 0)) && (scope.row.LesionType === 0 || scope.row.LesionType === 5) || (scope.row.QuestionMark === 12) || scope.row.HighlightAnswerList.includes(`${scope.row.Answers[task.VisitTaskId]}`) ? '#f66' : '#fff'}">
<template v-if="task.VisitTaskId === visitTaskId && readingTaskState < 2 && [13,14,15,42].includes(scope.row.QuestionType)"> <template v-if="task.VisitTaskId === visitTaskId && readingTaskState < 2 && [13,14,15,42].includes(scope.row.QuestionType)">
<!-- 是否存在疾病基线时可修改 --> <!-- 是否存在疾病基线时可修改 -->
<template v-if="task.IsBaseLine && scope.row.QuestionType=== 15"> <template v-if="task.IsBaseLine && scope.row.QuestionType=== 15">

View File

@ -77,7 +77,7 @@
> >
<div> <div>
<div>{{ instance.InstanceNumber }}</div> <div>{{ instance.InstanceNumber }}</div>
<div>{{ `${instance.NumberOfFrames > 0 ? instance.NumberOfFrames : 1} frame` }}</div> <div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ? instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
</div> </div>
</div> </div>
@ -294,7 +294,14 @@ export default {
store.dispatch('reading/setImageloadedInfo', item) store.dispatch('reading/setImageloadedInfo', item)
} }
}) })
var i = res.findIndex(s => s.isCurrentTask) var i = -1
var isReadingTaskViewInOrder = parseInt(this.$router.currentRoute.query.isReadingTaskViewInOrder)
if (isReadingTaskViewInOrder === 2) {
//
i = res.length === 2 ? 1 : -1
} else {
i = res.findIndex(s => s.isCurrentTask)
}
if (i > -1) { if (i > -1) {
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId) var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
if (idx > -1) { if (idx > -1) {
@ -342,8 +349,9 @@ export default {
this.studyList = this.visitTaskList[idx].StudyList this.studyList = this.visitTaskList[idx].StudyList
var sIdx = this.studyList.findIndex(s => s.IsDicom) var sIdx = this.studyList.findIndex(s => s.IsDicom)
if (sIdx > -1) { if (sIdx > -1) {
this.studyIndex = sIdx console.log(this.studyIndex, this.studyIndex)
this.seriesIndex = 0 // this.studyIndex = sIdx
// c = 0
this.activeNames = [`${this.studyList[sIdx].StudyId}`] this.activeNames = [`${this.studyList[sIdx].StudyId}`]
// //
const i = this.studyList.findIndex(i => i.IsCriticalSequence) const i = this.studyList.findIndex(i => i.IsCriticalSequence)
@ -377,8 +385,23 @@ export default {
var isReadingTaskViewInOrder = parseInt(this.$router.currentRoute.query.isReadingTaskViewInOrder) var isReadingTaskViewInOrder = parseInt(this.$router.currentRoute.query.isReadingTaskViewInOrder)
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId) var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
this.studyList = this.visitTaskList[idx].StudyList this.studyList = this.visitTaskList[idx].StudyList
if (this.visitTaskList[idx].IsBaseLineTask || isReadingTaskViewInOrder !== 1) { if (isReadingTaskViewInOrder === 2) {
// 线 //
const studyList = this.visitTaskList[idx].StudyList.filter(i => i.IsDicom)
const seriesArr = studyList.map(s => s.SeriesList).flat()
if (seriesArr.length === 1) {
seriesList.push(seriesArr[0], seriesArr[0])
this.studyIndex = seriesArr[0].studyIndex
this.seriesIndex = seriesArr[0].seriesIndex
this.activeNames = [`${seriesArr[0].studyId}`]
} else if (seriesArr.length > 1) {
seriesList.push(seriesArr[0], seriesArr[1])
this.studyIndex = seriesArr[1].studyIndex
this.seriesIndex = seriesArr[1].seriesIndex
this.activeNames = [`${seriesArr[1].studyId}`]
}
} else if (this.visitTaskList[idx].IsBaseLineTask || isReadingTaskViewInOrder === 0) {
// 线
const obj = this.getFirstMarkedSeries(this.visitTaskList[idx].MeasureData, [...this.visitTaskList[idx].StudyList]) const obj = this.getFirstMarkedSeries(this.visitTaskList[idx].MeasureData, [...this.visitTaskList[idx].StudyList])
if (Object.keys(obj).length !== 0) { if (Object.keys(obj).length !== 0) {
this.studyIndex = obj.studyIndex this.studyIndex = obj.studyIndex
@ -668,7 +691,11 @@ export default {
this.currentSeriesIndex = seriesIndex this.currentSeriesIndex = seriesIndex
var idx = this.visitTaskIdx var idx = this.visitTaskIdx
const imageIds = [] const imageIds = []
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) { if (instanceInfo.KeyFramesList.length > 0) {
instanceInfo.KeyFramesList.map(i => {
imageIds.push(`wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${instanceInfo.Path}?frame=${i}&instanceId=${instanceInfo.Id}&visitTaskId=${this.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${idx}`)
})
} else if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) { for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
imageIds.push(`wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${instanceInfo.Path}?frame=${j}&instanceId=${instanceInfo.Id}&visitTaskId=${this.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${idx}`) imageIds.push(`wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${instanceInfo.Path}?frame=${j}&instanceId=${instanceInfo.Id}&visitTaskId=${this.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${idx}`)
} }

View File

@ -1637,7 +1637,7 @@ export default {
resetWwwc() { resetWwwc() {
this.toolState.viewportInvert = false this.toolState.viewportInvert = false
var viewport = cornerstone.getViewport(this.canvas) var viewport = cornerstone.getViewport(this.canvas)
viewport.invert = false // viewport.invert = false
var image = cornerstone.getImage(this.canvas) var image = cornerstone.getImage(this.canvas)
viewport.voi.windowWidth = image.windowWidth viewport.voi.windowWidth = image.windowWidth
viewport.voi.windowCenter = image.windowCenter viewport.voi.windowCenter = image.windowCenter

View File

@ -106,7 +106,8 @@
v-if="item.val === 1" v-if="item.val === 1"
class="divider" class="divider"
content-position="center" content-position="center"
>{{ ` ${$t("trials:reading:title:preset")}` }}</el-divider> >{{ ` ${$t('trials:reading:title:preset')}` }}</el-divider
>
</li> </li>
</ul> </ul>
</div> </div>
@ -163,7 +164,7 @@
<svg-icon icon-class="magnifier" class="svg-icon" /> <svg-icon icon-class="magnifier" class="svg-icon" />
</div> </div>
<!-- 缩放 --> <!-- 缩放 -->
<div class="text">{{ $t("trials:reading:button:zoom") }}</div> <div class="text">{{ $t('trials:reading:button:zoom') }}</div>
</div> </div>
</el-tooltip> </el-tooltip>
@ -183,7 +184,7 @@
<svg-icon icon-class="move" class="svg-icon" /> <svg-icon icon-class="move" class="svg-icon" />
</div> </div>
<!-- 移动 --> <!-- 移动 -->
<div class="text">{{ $t("trials:reading:button:move") }}</div> <div class="text">{{ $t('trials:reading:button:move') }}</div>
</div> </div>
</el-tooltip> </el-tooltip>
@ -210,7 +211,7 @@
</div> </div>
<!-- 旋转 --> <!-- 旋转 -->
<div class="text"> <div class="text">
{{ $t("trials:reading:button:rotate") {{ $t('trials:reading:button:rotate')
}}<i class="el-icon-caret-bottom" /> }}<i class="el-icon-caret-bottom" />
</div> </div>
<div class="dropdown-content"> <div class="dropdown-content">
@ -223,7 +224,8 @@
<a <a
href="#" href="#"
@click.prevent="setDicomCanvasRotate(rotate.val)" @click.prevent="setDicomCanvasRotate(rotate.val)"
>{{ rotate.label }}</a> >{{ rotate.label }}</a
>
</li> </li>
</ul> </ul>
</div> </div>
@ -258,8 +260,8 @@
<div class="text"> <div class="text">
{{ {{
fitType === 1 fitType === 1
? $t("trials:reading:button:fitWindow") ? $t('trials:reading:button:fitWindow')
: $t("trials:reading:button:fitImage") : $t('trials:reading:button:fitImage')
}} }}
</div> </div>
</div> </div>
@ -282,7 +284,7 @@
</div> </div>
<!-- 同步 --> <!-- 同步 -->
<div class="text"> <div class="text">
{{ $t("trials:reading:button:imageIndexSync") }} {{ $t('trials:reading:button:imageIndexSync') }}
</div> </div>
</div> </div>
</el-tooltip> </el-tooltip>
@ -307,7 +309,7 @@
<svg-icon icon-class="image" class="svg-icon" /> <svg-icon icon-class="image" class="svg-icon" />
</div> </div>
<!-- 截屏 --> <!-- 截屏 -->
<div class="text">{{ $t("trials:reading:button:screenShot") }}</div> <div class="text">{{ $t('trials:reading:button:screenShot') }}</div>
</div> </div>
</el-tooltip> </el-tooltip>
@ -316,7 +318,7 @@
<div slot="content"> <div slot="content">
<div v-if="tool.disabledReason"> <div v-if="tool.disabledReason">
<h4 style="margin: 0; padding-bottom: 2px">{{ tool.text }}</h4> <h4 style="margin: 0; padding-bottom: 2px">{{ tool.text }}</h4>
<br>{{ tool.disabledReason }} <br />{{ tool.disabledReason }}
</div> </div>
<div v-else>{{ tool.text }}</div> <div v-else>{{ tool.text }}</div>
</div> </div>
@ -365,7 +367,7 @@
<svg-icon icon-class="clear" class="svg-icon" /> <svg-icon icon-class="clear" class="svg-icon" />
</div> </div>
<!-- 缩放 --> <!-- 缩放 -->
<div class="text">{{ $t("trials:dicom-show:Eraser") }}</div> <div class="text">{{ $t('trials:dicom-show:Eraser') }}</div>
</div> </div>
</el-tooltip> </el-tooltip>
<div class="tool-frame"> <div class="tool-frame">
@ -467,11 +469,11 @@
<div class="icon" @click.prevent="resetViewport"> <div class="icon" @click.prevent="resetViewport">
<svg-icon icon-class="refresh" class="svg-icon" /> <svg-icon icon-class="refresh" class="svg-icon" />
</div> </div>
<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 <el-tooltip
v-if="trialCriterion.ImageUploadEnum > 0" v-if="trialCriterion.ImageUploadEnum > 0 && currentReadingTaskState < 2"
v-hasPermi="['role:ir']" v-hasPermi="['role:ir']"
class="item" class="item"
effect="dark" effect="dark"
@ -482,7 +484,7 @@
<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" />
</div> </div>
<div class="text">{{ $t("trials:reading:button:upload") }}</div> <div class="text">{{ $t('trials:reading:button:upload') }}</div>
</div> </div>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip
@ -505,7 +507,7 @@
<div class="icon" @click.prevent="openUploadImage('download')"> <div class="icon" @click.prevent="openUploadImage('download')">
<i class="el-icon-download svg-icon" /> <i class="el-icon-download svg-icon" />
</div> </div>
<div class="text">{{ $t("trials:reading:button:download") }}</div> <div class="text">{{ $t('trials:reading:button:download') }}</div>
</div> </div>
</el-tooltip> </el-tooltip>
@ -515,17 +517,19 @@
v-if="isExistsManual" v-if="isExistsManual"
type="text" type="text"
@click="previewManuals" @click="previewManuals"
>{{ $t("trials:reading:button:handbooks") }}</el-button> >{{ $t('trials:reading:button:handbooks') }}</el-button
>
<!-- 临床数据 --> <!-- 临床数据 -->
<el-button <el-button
v-if="isExistsClinicalData" v-if="isExistsClinicalData"
type="text" type="text"
@click="previewCD" @click="previewCD"
>{{ $t("trials:reading:button:clinicalData") }}</el-button> >{{ $t('trials:reading:button:clinicalData') }}</el-button
>
<!-- <el-button v-if="isExistsNoDicomFile" type="text" @click="previewNoneDicoms">Dicom</el-button> --> <!-- <el-button v-if="isExistsNoDicomFile" type="text" @click="previewNoneDicoms">Dicom</el-button> -->
<el-button type="text" @click="previewConfig">{{ <el-button type="text" @click="previewConfig">{{
$t("trials:reading:button:customCfg") $t('trials:reading:button:customCfg')
}}</el-button> }}</el-button>
</div> </div>
</div> </div>
@ -625,7 +629,7 @@
:fullscreen="isFullscreen" :fullscreen="isFullscreen"
> >
<span slot="title" class="dialog-footer"> <span slot="title" class="dialog-footer">
<span>{{ $t("trials:reading:button:handbooks") }}</span> <span>{{ $t('trials:reading:button:handbooks') }}</span>
<span style="position: absolute; right: 20px; font-size: 20px"> <span style="position: absolute; right: 20px; font-size: 20px">
<svg-icon <svg-icon
:icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'" :icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'"
@ -646,12 +650,27 @@
<!-- <button :title="$t('trials:dicom-show:Eraser')" class="btn-link" data-tool="Eraser" @click="setToolActive($event,'Eraser')">--> <!-- <button :title="$t('trials:dicom-show:Eraser')" class="btn-link" data-tool="Eraser" @click="setToolActive($event,'Eraser')">-->
<!-- <svg-icon icon-class="clear" style="font-size:20px;" />--> <!-- <svg-icon icon-class="clear" style="font-size:20px;" />-->
<!-- </button>--> <!-- </button>-->
<upload-image <!-- <upload-image
v-if="uploadImageVisible" v-if="uploadImageVisible"
:visible.sync="uploadImageVisible" :visible.sync="uploadImageVisible"
:subject-id="subjectId" :subject-id="subjectId"
:criterion="trialCriterion" :criterion="trialCriterion"
:status="uploadStatus" :status="uploadStatus"
/> -->
<upload-dicom-and-nonedicom
v-if="uploadImageVisible"
:SubjectId="uploadSubjectId"
:SubjectCode="uploadSubjectCode"
:Criterion="uploadTrialCriterion"
:visible.sync="uploadImageVisible"
/>
<download-dicom-and-nonedicom
v-if="downloadImageVisible"
:SubjectId="uploadSubjectId"
:SubjectCode="uploadSubjectCode"
:Criterion="uploadTrialCriterion"
:TaskId="taskId"
:visible.sync="downloadImageVisible"
/> />
</div> </div>
</template> </template>
@ -676,7 +695,8 @@ import DicomEvent from './../components/DicomEvent'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import store from '@/store' import store from '@/store'
import { getDoctorShortcutKey, getUserWLTemplateList } from '@/api/user' import { getDoctorShortcutKey, getUserWLTemplateList } from '@/api/user'
import uploadImage from '@/components/uploadImage' import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
import { getCriterionReadingInfo } from '@/api/trials' import { getCriterionReadingInfo } from '@/api/trials'
export default { export default {
name: 'DicomViewer', name: 'DicomViewer',
@ -688,48 +708,49 @@ export default {
Others, Others,
Manuals, Manuals,
MeasurementList, MeasurementList,
'upload-image': uploadImage 'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
}, },
props: { props: {
isExistsClinicalData: { isExistsClinicalData: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
isExistsNoDicomFile: { isExistsNoDicomFile: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
isExistsManual: { isExistsManual: {
type: Boolean, type: Boolean,
required: true required: true,
}, },
isReadingShowSubjectInfo: { isReadingShowSubjectInfo: {
type: Boolean, type: Boolean,
required: true required: true,
}, },
isReadingTaskViewInOrder: { isReadingTaskViewInOrder: {
type: Number, type: Number,
required: true required: true,
}, },
IseCRFShowInDicomReading: { IseCRFShowInDicomReading: {
type: Boolean, type: Boolean,
required: true required: true,
}, },
subjectId: { subjectId: {
type: String, type: String,
required: true, required: true,
default: '' default: '',
}, },
trialReadingCriterionId: { trialReadingCriterionId: {
type: String, type: String,
required: true, required: true,
default: '' default: '',
}, },
trialId: { trialId: {
type: String, type: String,
required: true, required: true,
default: '' default: '',
} },
}, },
data() { data() {
return { return {
@ -738,7 +759,7 @@ export default {
{ index: 0, row: 1, col: 1, name: 'A' }, { index: 0, row: 1, col: 1, name: 'A' },
{ index: 1, row: 1, col: 2, name: 'A|A' }, { index: 1, row: 1, col: 2, name: 'A|A' },
{ index: 2, row: 1, col: 2, name: 'A|B' }, { index: 2, row: 1, col: 2, name: 'A|B' },
{ index: 3, row: 2, col: 2, name: 'A|A|A|A' } { index: 3, row: 2, col: 2, name: 'A|A|A|A' },
// { index: 2, row: 2, col: 1 }, // { index: 2, row: 2, col: 1 },
// { index: 3, row: 2, col: 2 } // { index: 3, row: 2, col: 2 }
], ],
@ -747,7 +768,7 @@ export default {
{ label: this.$t('trials:reading:button:rotateVertical'), val: 2 }, // { label: this.$t('trials:reading:button:rotateVertical'), val: 2 }, //
{ label: this.$t('trials:reading:button:rotateHorizontal'), val: 3 }, // { label: this.$t('trials:reading:button:rotateHorizontal'), val: 3 }, //
{ label: this.$t('trials:reading:button:rotateTurnLeft'), val: 4 }, // 90 { label: this.$t('trials:reading:button:rotateTurnLeft'), val: 4 }, // 90
{ label: this.$t('trials:reading:button:rotateTurnRight'), val: 5 } // 90 { label: this.$t('trials:reading:button:rotateTurnRight'), val: 5 }, // 90
], ],
maxCanvas: 1, maxCanvas: 1,
layoutRow: 1, layoutRow: 1,
@ -755,8 +776,8 @@ export default {
currentDicomCanvasIndex: 0, currentDicomCanvasIndex: 0,
currentDicomCanvas: { currentDicomCanvas: {
toolState: { toolState: {
clipPlaying: false clipPlaying: false,
} },
}, },
colormapsList: [], colormapsList: [],
rotateList: [], rotateList: [],
@ -773,7 +794,7 @@ export default {
text: this.$t('trials:reading:button:length'), text: this.$t('trials:reading:button:length'),
icon: 'length', icon: 'length',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
}, },
// //
{ {
@ -781,7 +802,7 @@ export default {
text: this.$t('trials:reading:button:bidirectional'), text: this.$t('trials:reading:button:bidirectional'),
icon: 'bidirection', icon: 'bidirection',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
}, },
// //
{ {
@ -789,7 +810,7 @@ export default {
text: this.$t('trials:reading:button:rectangle'), text: this.$t('trials:reading:button:rectangle'),
icon: 'rectangle', icon: 'rectangle',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
}, },
// //
{ {
@ -797,7 +818,7 @@ export default {
text: this.$t('trials:reading:button:elliptical'), text: this.$t('trials:reading:button:elliptical'),
icon: 'oval', icon: 'oval',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
}, },
// //
{ {
@ -805,8 +826,8 @@ export default {
text: this.$t('trials:reading:button:arrowAnnotate'), text: this.$t('trials:reading:button:arrowAnnotate'),
icon: 'arrow', icon: 'arrow',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
} },
], ],
fitType: 0, fitType: 0,
@ -818,25 +839,25 @@ export default {
label: this.$t('trials:reading:button:wwwcDefault'), label: this.$t('trials:reading:button:wwwcDefault'),
val: -1, val: -1,
ww: null, ww: null,
wc: null wc: null,
}, // }, //
{ {
label: this.$t('trials:reading:button:wwwcCustom'), label: this.$t('trials:reading:button:wwwcCustom'),
val: 0, val: 0,
ww: null, ww: null,
wc: null wc: null,
}, // }, //
{ {
label: this.$t('trials:reading:button:wwwcRegion'), label: this.$t('trials:reading:button:wwwcRegion'),
val: 1, val: 1,
ww: null, ww: null,
wc: null wc: null,
}, // }, //
{ label: 'CT Brain', wc: 40, ww: 80 }, { label: 'CT Brain', wc: 40, ww: 80 },
{ label: 'CT Lungs', wc: -400, ww: 1500 }, { label: 'CT Lungs', wc: -400, ww: 1500 },
{ label: 'CT Abdomen', wc: 60, ww: 400 }, { label: 'CT Abdomen', wc: 60, ww: 400 },
{ label: 'CT Liver', wc: 40, ww: 400 }, { label: 'CT Liver', wc: 40, ww: 400 },
{ label: 'CT Bone', wc: 300, ww: 1500 } { label: 'CT Bone', wc: 300, ww: 1500 },
], ],
activeSeries: {}, activeSeries: {},
seriesStack: [], seriesStack: [],
@ -844,13 +865,13 @@ export default {
isScrollSync: false, isScrollSync: false,
imageIndexSync: { imageIndexSync: {
sourceCanvas: '', sourceCanvas: '',
targetCanvas: [] targetCanvas: [],
}, },
isFirstRender: false, isFirstRender: false,
customWwc: { visible: false, title: null }, // customWwc: { visible: false, title: null }, //
personalConfigDialog: { personalConfigDialog: {
visible: false, visible: false,
title: this.$t('trials:reading:button:customCfg') title: this.$t('trials:reading:button:customCfg'),
}, // }, //
layout: '', layout: '',
isFirstNotLinked: false, isFirstNotLinked: false,
@ -861,15 +882,20 @@ export default {
manualsDialog: { visible: false }, manualsDialog: { visible: false },
clipPlaying: false, clipPlaying: false,
fps: 15, fps: 15,
//
uploadImageVisible: false,
trialCriterion: {}, trialCriterion: {},
uploadStatus: 'upload' //
downloadImageVisible: false,
uploadImageVisible: false,
uploadSubjectId: null,
uploadSubjectCode: null,
uploadTrialCriterion: {},
uploadStatus: 'upload',
taskId: ''
} }
}, },
computed: { computed: {
...mapGetters(['visitTaskList', 'currentReadingTaskState']) ...mapGetters(['visitTaskList', 'currentReadingTaskState']),
}, },
watch: { watch: {
currentReadingTaskState: { currentReadingTaskState: {
@ -888,7 +914,7 @@ export default {
this.activeTool = '' this.activeTool = ''
} }
} }
} },
}, },
currentDicomCanvasIndex: { currentDicomCanvasIndex: {
immediate: true, immediate: true,
@ -905,8 +931,8 @@ export default {
this.clipPlaying = false this.clipPlaying = false
this.fps = 15 this.fps = 15
} }
} },
} },
}, },
mounted() { mounted() {
this.getTrialCriterion() this.getTrialCriterion()
@ -919,7 +945,7 @@ export default {
// cornerstone.imageCache.setMaximumSizeBytes(maximumSizeInBytes) // cornerstone.imageCache.setMaximumSizeBytes(maximumSizeInBytes)
this.customWwc = { this.customWwc = {
visible: false, visible: false,
title: this.$t('trials:reading:dagTitle:wwwcCustom') title: this.$t('trials:reading:dagTitle:wwwcCustom'),
} }
this.CriterionType = parseInt(localStorage.getItem('CriterionType')) this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
if (this.CriterionType === 10) { if (this.CriterionType === 10) {
@ -929,15 +955,15 @@ export default {
text: this.$t('trials:reading:button:arrowAnnotate'), text: this.$t('trials:reading:button:arrowAnnotate'),
icon: 'arrow', icon: 'arrow',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
}, },
{ {
toolName: 'RectangleRoi', toolName: 'RectangleRoi',
text: this.$t('trials:reading:button:rectangle'), text: this.$t('trials:reading:button:rectangle'),
icon: 'rectangle', icon: 'rectangle',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
} },
] ]
} else if (this.CriterionType === 17) { } else if (this.CriterionType === 17) {
this.measuredTools = [ this.measuredTools = [
@ -946,22 +972,22 @@ export default {
text: this.$t('trials:reading:button:length'), text: this.$t('trials:reading:button:length'),
icon: 'length', icon: 'length',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
}, },
{ {
toolName: 'RectangleRoi', toolName: 'RectangleRoi',
text: this.$t('trials:reading:button:rectangle'), text: this.$t('trials:reading:button:rectangle'),
icon: 'rectangle', icon: 'rectangle',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
}, },
{ {
toolName: 'ArrowAnnotate', toolName: 'ArrowAnnotate',
text: this.$t('trials:reading:button:arrowAnnotate'), text: this.$t('trials:reading:button:arrowAnnotate'),
icon: 'arrow', icon: 'arrow',
isDisabled: false, isDisabled: false,
disabledReason: '' disabledReason: '',
} },
] ]
} }
this.rotateList[0] = '1' this.rotateList[0] = '1'
@ -1041,7 +1067,7 @@ export default {
getTrialCriterion() { getTrialCriterion() {
getCriterionReadingInfo({ getCriterionReadingInfo({
TrialId: this.trialId, TrialId: this.trialId,
TrialReadingCriterionId: this.trialReadingCriterionId TrialReadingCriterionId: this.trialReadingCriterionId,
}) })
.then((res) => { .then((res) => {
this.trialCriterion = res.Result this.trialCriterion = res.Result
@ -1049,26 +1075,32 @@ export default {
.catch(() => {}) .catch(() => {})
}, },
openUploadImage(status) { openUploadImage(status) {
const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask)
if (idx > -1) {
this.taskId = this.visitTaskList[idx].VisitTaskId
}
this.uploadSubjectCode = this.$route.query.subjectCode
this.uploadSubjectId = this.$route.query.subjectId
this.uploadTrialCriterion = this.trialCriterion
this.uploadStatus = status this.uploadStatus = status
this.uploadImageVisible = true this[`${status}ImageVisible`] = true
}, },
async getWwcTpl() { async getWwcTpl() {
// const loading = this.$loading({ fullscreen: true }) // const loading = this.$loading({ fullscreen: true })
try { try {
let res = await getUserWLTemplateList() let res = await getUserWLTemplateList()
this.customWwcTpl = [] this.customWwcTpl = []
res.Result.map((i) => { res.Result.map((i) => {
this.customWwcTpl.push({ this.customWwcTpl.push({
label: i.TemplateName, label: i.TemplateName,
wc: i.WL, wc: i.WL,
ww: i.WW ww: i.WW,
})
}) })
this.wwwcArr = [...this.defaultWwwc, ...this.customWwcTpl] })
} catch(e) { this.wwwcArr = [...this.defaultWwwc, ...this.customWwcTpl]
} catch (e) {
console.log(e) console.log(e)
} }
}, },
async getHotKeys() { async getHotKeys() {
// const loading = this.$loading({ fullscreen: true }) // const loading = this.$loading({ fullscreen: true })
@ -1084,11 +1116,11 @@ export default {
key: item.Keyboardkey, key: item.Keyboardkey,
code: item.Code, code: item.Code,
text: item.Text, text: item.Text,
shortcutKeyEnum: item.ShortcutKeyEnum shortcutKeyEnum: item.ShortcutKeyEnum,
}) })
}) })
this.bindHotKey() this.bindHotKey()
} catch(e) { } catch (e) {
console.log(e) console.log(e)
} }
}, },
@ -1105,7 +1137,7 @@ export default {
key: item.keys.controlKey.key, key: item.keys.controlKey.key,
code: item.keys.controlKey.code, code: item.keys.controlKey.code,
text: item.keys.text, text: item.keys.text,
shortcutKeyEnum: item.label shortcutKeyEnum: item.label,
}) })
}) })
@ -1148,7 +1180,7 @@ export default {
DicomEvent.$emit('selectSeries', { DicomEvent.$emit('selectSeries', {
seriesId: series.seriesId, seriesId: series.seriesId,
studyId: series.studyId, studyId: series.studyId,
offset: -1 offset: -1,
}) })
} else if (shortcutKeyEnum === 4) { } else if (shortcutKeyEnum === 4) {
// //
@ -1157,7 +1189,7 @@ export default {
DicomEvent.$emit('selectSeries', { DicomEvent.$emit('selectSeries', {
seriesId: series.seriesId, seriesId: series.seriesId,
studyId: series.studyId, studyId: series.studyId,
offset: 1 offset: 1,
}) })
} else if (shortcutKeyEnum === 5) { } else if (shortcutKeyEnum === 5) {
// //
@ -1287,7 +1319,7 @@ export default {
top: '72px', top: '72px',
left: '205px', left: '205px',
right: '350px', right: '350px',
zIndex: 10 zIndex: 10,
} }
this.canvasW = window.innerWidth - 570 + 'px' this.canvasW = window.innerWidth - 570 + 'px'
this.canvasH = window.innerHeight - 130 + 'px' this.canvasH = window.innerHeight - 130 + 'px'
@ -1387,10 +1419,7 @@ export default {
// this.$refs['measurementList'].initPage(dicomSeries) // this.$refs['measurementList'].initPage(dicomSeries)
store.dispatch('reading/setActiveSeries', dicomSeries) store.dispatch('reading/setActiveSeries', dicomSeries)
if (this.currentDicomCanvasIndex === this.maxCanvas - 1) { if (this.currentDicomCanvasIndex === this.maxCanvas - 1) {
store.dispatch( store.dispatch('reading/setLastCanvasTaskId', dicomSeries.visitTaskId)
'reading/setLastCanvasTaskId',
dicomSeries.visitTaskId
)
} }
}) })
}, },
@ -1421,10 +1450,7 @@ export default {
store.dispatch('reading/setActiveSeries', dicomSeries) store.dispatch('reading/setActiveSeries', dicomSeries)
if (this.currentDicomCanvasIndex === this.maxCanvas - 1) { if (this.currentDicomCanvasIndex === this.maxCanvas - 1) {
store.dispatch( store.dispatch('reading/setLastCanvasTaskId', dicomSeries.visitTaskId)
'reading/setLastCanvasTaskId',
dicomSeries.visitTaskId
)
} }
}) })
}, },
@ -1474,7 +1500,7 @@ export default {
visitTaskId = this.visitTaskList[i].VisitTaskId visitTaskId = this.visitTaskList[i].VisitTaskId
} }
this.getFirstSeries(activeSeries, visitTaskId).then( this.getFirstSeries(activeSeries, visitTaskId).then(
async(baseSerires) => { async (baseSerires) => {
this.seriesStack = [baseSerires, activeSeries] this.seriesStack = [baseSerires, activeSeries]
this.currentDicomCanvasIndex = 1 this.currentDicomCanvasIndex = 1
store.dispatch( store.dispatch(
@ -1502,7 +1528,7 @@ export default {
activeSeries, activeSeries,
activeSeries, activeSeries,
activeSeries, activeSeries,
activeSeries activeSeries,
] ]
this.currentDicomCanvasIndex = 3 this.currentDicomCanvasIndex = 3
store.dispatch( store.dispatch(
@ -1521,9 +1547,7 @@ export default {
for (let i = 0; i < this.maxCanvas && i < seriesStack.length; i++) { for (let i = 0; i < this.maxCanvas && i < seriesStack.length; i++) {
this.canvasObj[i] = seriesStack[i] this.canvasObj[i] = seriesStack[i]
let s = Object.assign({}, seriesStack[i]) let s = Object.assign({}, seriesStack[i])
promiseArr.push( promiseArr.push(this.$refs[`dicomCanvas${i}`][0].loadImageStack(s))
this.$refs[`dicomCanvas${i}`][0].loadImageStack(s)
)
} }
Promise.all(promiseArr) Promise.all(promiseArr)
.then(() => { .then(() => {
@ -1585,24 +1609,24 @@ export default {
trialId: this.trialId, trialId: this.trialId,
subjectVisitId: this.visitTaskList[taskIdx].VisitId, subjectVisitId: this.visitTaskList[taskIdx].VisitId,
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId, visitTaskId: this.visitTaskList[taskIdx].VisitTaskId,
taskBlindName: this.visitTaskList[taskIdx].TaskBlindName taskBlindName: this.visitTaskList[taskIdx].TaskBlindName,
}) })
} }
if (!this.visitTaskList[taskIdx].readingQuestionsInit) { if (!this.visitTaskList[taskIdx].readingQuestionsInit) {
await store.dispatch('reading/getReadingQuestionAndAnswer', { await store.dispatch('reading/getReadingQuestionAndAnswer', {
trialId: this.trialId, trialId: this.trialId,
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId visitTaskId: this.visitTaskList[taskIdx].VisitTaskId,
}) })
} }
if (!this.visitTaskList[taskIdx].questionsInit) { if (!this.visitTaskList[taskIdx].questionsInit) {
await store.dispatch('reading/getDicomReadingQuestionAnswer', { await store.dispatch('reading/getDicomReadingQuestionAnswer', {
trialId: this.trialId, trialId: this.trialId,
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId visitTaskId: this.visitTaskList[taskIdx].VisitTaskId,
}) })
} }
await store.dispatch('reading/setStatus', { await store.dispatch('reading/setStatus', {
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId visitTaskId: this.visitTaskList[taskIdx].VisitTaskId,
}) })
} }
firstAddSeries = this.getSeriesInfoByMark(firstAddVisitTaskId, obj) firstAddSeries = this.getSeriesInfoByMark(firstAddVisitTaskId, obj)
@ -1696,8 +1720,7 @@ export default {
var studyList = this.visitTaskList[index].StudyList var studyList = this.visitTaskList[index].StudyList
var studyId = this.visitTaskList[index].MeasureData[idx].StudyId var studyId = this.visitTaskList[index].MeasureData[idx].StudyId
var seriesId = this.visitTaskList[index].MeasureData[idx].SeriesId var seriesId = this.visitTaskList[index].MeasureData[idx].SeriesId
var instanceId = var instanceId = this.visitTaskList[index].MeasureData[idx].InstanceId
this.visitTaskList[index].MeasureData[idx].InstanceId
var studyIdx = studyList.findIndex( var studyIdx = studyList.findIndex(
(study) => study.StudyId === studyId (study) => study.StudyId === studyId
) )
@ -1706,10 +1729,15 @@ export default {
(s) => s.seriesId === seriesId (s) => s.seriesId === seriesId
) )
if (seriesIdx > -1) { if (seriesIdx > -1) {
var series = studyList[studyIdx].SeriesList[seriesIdx]; var series = studyList[studyIdx].SeriesList[seriesIdx]
let frame = this.visitTaskList[index].MeasureData[idx].MeasureData.frame let frame =
let filterStr = series.isExistMutiFrames ? `frame=${frame}&instanceId=${instanceId}` : `instanceId=${instanceId}` this.visitTaskList[index].MeasureData[idx].MeasureData.frame
var instanceIdx = series.imageIds.findIndex(imageId => imageId.includes(filterStr)) let filterStr = series.isExistMutiFrames
? `frame=${frame}&instanceId=${instanceId}`
: `instanceId=${instanceId}`
var instanceIdx = series.imageIds.findIndex((imageId) =>
imageId.includes(filterStr)
)
// var instanceIdx = series.instanceList.findIndex( // var instanceIdx = series.instanceList.findIndex(
// (imageId) => !!~imageId.indexOf(instanceId) // (imageId) => !!~imageId.indexOf(instanceId)
// ); // );
@ -1738,16 +1766,14 @@ export default {
i.description, i.description,
baseSeries.description baseSeries.description
), ),
index index,
} }
}) })
similarArr = similarArr.sort((a, b) => { similarArr = similarArr.sort((a, b) => {
return b.similar - a.similar return b.similar - a.similar
}) })
const i = const i =
similarArr[0] && similarArr[0].similar > 0.85 similarArr[0] && similarArr[0].similar > 0.85 ? similarArr[0].index : -1
? similarArr[0].index
: -1
if (i > -1) { if (i > -1) {
obj = seriesList[i] obj = seriesList[i]
} }
@ -1822,7 +1848,7 @@ export default {
trialId: this.trialId, trialId: this.trialId,
subjectVisitId: this.visitTaskList[index].VisitId, subjectVisitId: this.visitTaskList[index].VisitId,
visitTaskId: this.visitTaskList[index].VisitTaskId, visitTaskId: this.visitTaskList[index].VisitTaskId,
taskBlindName: this.visitTaskList[index].TaskBlindName taskBlindName: this.visitTaskList[index].TaskBlindName,
}) })
await store.dispatch( await store.dispatch(
@ -1841,16 +1867,14 @@ export default {
i.description, i.description,
baseSeries.description baseSeries.description
), ),
index index,
} }
}) })
similarArr = similarArr.sort((a, b) => { similarArr = similarArr.sort((a, b) => {
return b.similar - a.similar return b.similar - a.similar
}) })
const i = const i =
similarArr[0] && similarArr[0].similar > 0.85 similarArr[0] && similarArr[0].similar > 0.85 ? similarArr[0].index : -1
? similarArr[0].index
: -1
if (i > -1) { if (i > -1) {
obj = seriesList[i] obj = seriesList[i]
} }
@ -2025,9 +2049,7 @@ export default {
}, },
// //
enter(e, toolName) { enter(e, toolName) {
var i = this.measuredTools.findIndex( var i = this.measuredTools.findIndex((item) => item.toolName === toolName)
(item) => item.toolName === toolName
)
if (i === -1) return if (i === -1) return
var isCurrentTask = var isCurrentTask =
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0] this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0]
@ -2089,8 +2111,11 @@ export default {
`dicomCanvas${this.currentDicomCanvasIndex}` `dicomCanvas${this.currentDicomCanvasIndex}`
][0].setToolActive(toolName) ][0].setToolActive(toolName)
} }
} else if (dicomSeries.isCurrentTask && } else if (
isMeasuredTool && dicomSeries.readingTaskState >= 2) { dicomSeries.isCurrentTask &&
isMeasuredTool &&
dicomSeries.readingTaskState >= 2
) {
if (this.activeTool === toolName) { if (this.activeTool === toolName) {
this.$refs[ this.$refs[
`dicomCanvas${this.currentDicomCanvasIndex}` `dicomCanvas${this.currentDicomCanvasIndex}`
@ -2162,9 +2187,7 @@ export default {
][0].fitToWindow() ][0].fitToWindow()
} else if (toolName === 'fitToImage') { } else if (toolName === 'fitToImage') {
this.fitType = 1 this.fitType = 1
this.$refs[ this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].fitToImage()
`dicomCanvas${this.currentDicomCanvasIndex}`
][0].fitToImage()
} }
this.activeTool = toolName this.activeTool = toolName
}, },
@ -2181,7 +2204,9 @@ export default {
const isLoaded = this.getSeriesLoadStatus() const isLoaded = this.getSeriesLoadStatus()
if (!isLoaded) return if (!isLoaded) return
this.clipPlaying = isPlay this.clipPlaying = isPlay
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setFps(this.fps) this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setFps(
this.fps
)
this.$refs[ this.$refs[
`dicomCanvas${this.currentDicomCanvasIndex}` `dicomCanvas${this.currentDicomCanvasIndex}`
][0].toggleClipPlay(isPlay) ][0].toggleClipPlay(isPlay)
@ -2297,8 +2322,8 @@ export default {
previewManuals() { previewManuals() {
this.isFullscreen = false this.isFullscreen = false
this.manualsDialog.visible = true this.manualsDialog.visible = true
} },
} },
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -244,6 +244,7 @@ export default {
params.StudyId = params.questionInfo.StudyId params.StudyId = params.questionInfo.StudyId
params.SeriesId = params.questionInfo.SeriesId params.SeriesId = params.questionInfo.SeriesId
params.InstanceId = params.questionInfo.InstanceId params.InstanceId = params.questionInfo.InstanceId
params.NumberOfFrames = measureData.frame
submitCustomTag(params).then(() => { submitCustomTag(params).then(() => {
this.measuredDataVisible = false this.measuredDataVisible = false
DicomEvent.$emit('updateImage') DicomEvent.$emit('updateImage')
@ -282,6 +283,7 @@ export default {
} else { } else {
let params = JSON.parse(JSON.stringify(this.measureData)) let params = JSON.parse(JSON.stringify(this.measureData))
params.measureData = JSON.stringify(this.measureData) params.measureData = JSON.stringify(this.measureData)
params.NumberOfFrames = this.measureData.frame
submitCustomTag(params).then(async (res) => { submitCustomTag(params).then(async (res) => {
this.measuredDataVisible = false this.measuredDataVisible = false
this.form.measuredDataName = '' this.form.measuredDataName = ''

View File

@ -239,7 +239,7 @@
<!-- </span>--> <!-- </span>-->
<!-- </div>--> <!-- </div>-->
</el-upload> </el-upload>
<el-dialog <!-- <el-dialog
v-if="question.Type==='upload'" v-if="question.Type==='upload'"
append-to-body append-to-body
:visible.sync="imgVisible" :visible.sync="imgVisible"
@ -250,7 +250,20 @@
加载中<span class="dot">...</span> 加载中<span class="dot">...</span>
</div> </div>
</el-image> </el-image>
</el-dialog> </el-dialog> -->
<viewer
v-if="question.Type==='upload' && imgVisible"
:ref="imageUrl"
style="margin:0 10px;"
:images="[imageUrl]"
>
<img
v-show="false"
crossorigin="anonymous"
:src="imageUrl"
alt="Image"
>
</viewer>
</el-form-item> </el-form-item>
</template> </template>
@ -801,6 +814,9 @@ export default {
}else{ }else{
this.imageUrl = this.OSSclientConfig.basePath + file.url this.imageUrl = this.OSSclientConfig.basePath + file.url
this.imgVisible = true this.imgVisible = true
this.$nextTick(()=>{
this.$refs[this.imageUrl].$viewer.show()
})
} }
}, },
// //

View File

@ -138,27 +138,41 @@
> >
<i slot="default" class="el-icon-plus" /> <i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{file}"> <div slot="file" slot-scope="{file}">
<img <viewer
class="el-upload-list__item-thumbnail" :ref="file.url"
:src="OSSclientConfig.basePath + file.url" :images="[imageUrl]"
alt="" style="
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
"
> >
<span class="el-upload-list__item-actions"> <img
<span class="el-upload-list__item-thumbnail"
class="el-upload-list__item-preview" :src="OSSclientConfig.basePath + file.url"
@click="handlePictureCardPreview(file)" crossOrigin="anonymous"
> alt=""
<i class="el-icon-zoom-in" /> style="max-width: 100%; max-height: 100%"
</span> />
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span <span
v-if="readingTaskState < 2" v-if="readingTaskState < 2"
class="el-upload-list__item-delete" class="el-upload-list__item-delete"
@click="handleRemove(file)" @click="handleRemove(file)"
> >
<i class="el-icon-delete" /> <i class="el-icon-delete" />
</span>
</span> </span>
</span> </viewer>
</div> </div>
</el-upload> </el-upload>
<el-dialog <el-dialog
@ -308,7 +322,7 @@ export default {
window.open(this.OSSclientConfig.basePath + file.url,'_blank') window.open(this.OSSclientConfig.basePath + file.url,'_blank')
}else{ }else{
this.imageUrl = this.OSSclientConfig.basePath + file.url this.imageUrl = this.OSSclientConfig.basePath + file.url
this.imgVisible = true this.$refs[file.url].$viewer.show();
} }
}, },
// //

View File

@ -148,27 +148,41 @@
> >
<i slot="default" class="el-icon-plus" /> <i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{file}"> <div slot="file" slot-scope="{file}">
<img <viewer
class="el-upload-list__item-thumbnail" :ref="file.url"
:src="OSSclientConfig.basePath + file.url" :images="[imageUrl]"
alt="" style="
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
"
> >
<span class="el-upload-list__item-actions"> <img
<span class="el-upload-list__item-thumbnail"
class="el-upload-list__item-preview" :src="OSSclientConfig.basePath + file.url"
@click="handlePictureCardPreview(file)" crossOrigin="anonymous"
> alt=""
<i class="el-icon-zoom-in" /> style="max-width: 100%; max-height: 100%"
</span> />
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span <span
v-if="readingTaskState < 2" v-if="readingTaskState < 2"
class="el-upload-list__item-delete" class="el-upload-list__item-delete"
@click="handleRemove(file)" @click="handleRemove(file)"
> >
<i class="el-icon-delete" /> <i class="el-icon-delete" />
</span>
</span> </span>
</span> </viewer>
</div> </div>
</el-upload> </el-upload>
<el-dialog <el-dialog
@ -492,7 +506,8 @@ export default {
window.open(this.OSSclientConfig.basePath + file.url,'_blank') window.open(this.OSSclientConfig.basePath + file.url,'_blank')
}else{ }else{
this.imageUrl = this.OSSclientConfig.basePath + file.url this.imageUrl = this.OSSclientConfig.basePath + file.url
this.imgVisible = true // this.imgVisible = true
this.$refs[file.url].$viewer.show()
} }
}, },

View File

@ -14,41 +14,43 @@
> >
<i slot="default" class="el-icon-plus" /> <i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{file}"> <div slot="file" slot-scope="{file}">
<img <viewer
class="el-upload-list__item-thumbnail" :ref="file.url"
crossOrigin="Anonymous" :images="[imageUrl]"
:src="OSSclientConfig.basePath + file.url" style="
alt="" display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
"
> >
<span class="el-upload-list__item-actions"> <img
<span class="el-upload-list__item-thumbnail"
class="el-upload-list__item-preview" :src="OSSclientConfig.basePath + file.url"
@click="handlePictureCardPreview(file)" crossOrigin="anonymous"
> alt=""
<i class="el-icon-zoom-in" /> style="max-width: 100%; max-height: 100%"
</span> />
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span <span
v-if="readingTaskState < 2" v-if="readingTaskState < 2"
class="el-upload-list__item-delete" class="el-upload-list__item-delete"
@click="handleRemove(file)" @click="handleRemove(file)"
> >
<i class="el-icon-delete" /> <i class="el-icon-delete" />
</span> </span>
</span> </span>
</viewer>
</div> </div>
</el-upload> </el-upload>
<el-dialog
append-to-body
:visible.sync="imgVisible"
width="600px"
>
<el-image :src="imageUrl" width="100%" crossOrigin="Anonymous">
<div slot="placeholder" class="image-slot">
加载中<span class="dot">...</span>
</div>
</el-image>
</el-dialog>
</div> </div>
</template> </template>
@ -142,7 +144,8 @@ name: "CustomizeReportPageUpload",
window.open(this.OSSclientConfig.basePath + file.url,'_blank') window.open(this.OSSclientConfig.basePath + file.url,'_blank')
}else{ }else{
this.imageUrl = this.OSSclientConfig.basePath + file.url this.imageUrl = this.OSSclientConfig.basePath + file.url
this.imgVisible = true // this.imgVisible = true
this.$refs[file.url].$viewer.show()
} }
}, },
// //

View File

@ -87,7 +87,7 @@
</div> --> </div> -->
<div> <div>
<div>{{ instance.InstanceNumber }}</div> <div>{{ instance.InstanceNumber }}</div>
<div>{{ `${instance.NumberOfFrames > 0 ? instance.NumberOfFrames : 1} frame` }}</div> <div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ? instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
</div> </div>
</div> </div>
@ -279,7 +279,14 @@ export default {
store.dispatch('reading/setImageloadedInfo', item) store.dispatch('reading/setImageloadedInfo', item)
} }
}) })
var i = res.findIndex(s => s.isCurrentTask) var i = -1
var isReadingTaskViewInOrder = parseInt(this.$router.currentRoute.query.isReadingTaskViewInOrder)
if (isReadingTaskViewInOrder === 2) {
//
i = res.length === 2 ? 1 : -1
} else {
i = res.findIndex(s => s.isCurrentTask)
}
if (i > -1) { if (i > -1) {
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId) var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
if (idx > -1) { if (idx > -1) {
@ -356,7 +363,22 @@ export default {
var isReadingTaskViewInOrder = JSON.parse(this.$router.currentRoute.query.isReadingTaskViewInOrder) var isReadingTaskViewInOrder = JSON.parse(this.$router.currentRoute.query.isReadingTaskViewInOrder)
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId) var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
this.studyList = this.visitTaskList[idx].StudyList this.studyList = this.visitTaskList[idx].StudyList
if (this.visitTaskList[idx].IsBaseLineTask || isReadingTaskViewInOrder !== 1) { if (isReadingTaskViewInOrder === 2) {
//
const studyList = this.visitTaskList[idx].StudyList.filter(i => i.IsDicom)
const seriesArr = studyList.map(s => s.SeriesList).flat()
if (seriesArr.length === 1) {
seriesList.push(seriesArr[0], seriesArr[0])
this.studyIndex = seriesArr[0].studyIndex
this.seriesIndex = seriesArr[0].seriesIndex
this.activeNames = [`${seriesArr[0].studyId}`]
} else if (seriesArr.length > 1) {
seriesList.push(seriesArr[0], seriesArr[1])
this.studyIndex = seriesArr[1].studyIndex
this.seriesIndex = seriesArr[1].seriesIndex
this.activeNames = [`${seriesArr[1].studyId}`]
}
} else if (this.visitTaskList[idx].IsBaseLineTask || isReadingTaskViewInOrder === 0){
// 线 // 线
const obj = this.getFirstMarkedSeries(this.visitTaskList[idx].MeasureData, [...this.visitTaskList[idx].StudyList]) const obj = this.getFirstMarkedSeries(this.visitTaskList[idx].MeasureData, [...this.visitTaskList[idx].StudyList])
if (Object.keys(obj).length !== 0) { if (Object.keys(obj).length !== 0) {
@ -652,7 +674,11 @@ export default {
this.studyList[studyIndex].SeriesList[seriesIndex].measureData = this.measureData this.studyList[studyIndex].SeriesList[seriesIndex].measureData = this.measureData
var dicomStatck = Object.assign({},this.studyList[studyIndex].SeriesList[seriesIndex]) var dicomStatck = Object.assign({},this.studyList[studyIndex].SeriesList[seriesIndex])
const imageIds = [] const imageIds = []
if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) { if (instanceInfo.KeyFramesList.length > 0) {
instanceInfo.KeyFramesList.map(i => {
imageIds.push(`wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${instanceInfo.Path}?frame=${i}&instanceId=${instanceInfo.Id}&visitTaskId=${this.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${idx}`)
})
} else if (instanceInfo.NumberOfFrames && instanceInfo.NumberOfFrames > 1) {
for (let j = 0; j < instanceInfo.NumberOfFrames; j++) { for (let j = 0; j < instanceInfo.NumberOfFrames; j++) {
imageIds.push(`wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${instanceInfo.Path}?frame=${j}&instanceId=${instanceInfo.Id}&visitTaskId=${this.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${idx}`) imageIds.push(`wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${instanceInfo.Path}?frame=${j}&instanceId=${instanceInfo.Id}&visitTaskId=${this.visitTaskId}&idx=${studyIndex}|${seriesIndex}|${idx}`)
} }

View File

@ -267,7 +267,7 @@ export default {
// this.readingTool = this.$router.currentRoute.query.readingTool // this.readingTool = this.$router.currentRoute.query.readingTool
this.TrialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId this.TrialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
// this.isNewSubject = this.$router.currentRoute.query.isNewSubject // this.isNewSubject = this.$router.currentRoute.query.isNewSubject
localStorage.setItem('isReadingTaskViewInOrder', this.isReadingTaskViewInOrder)
// if (this.isNewSubject && this.isReadingTaskViewInOrder !== 0) { // if (this.isNewSubject && this.isReadingTaskViewInOrder !== 0) {
// // ${this.subjectCode} // // ${this.subjectCode}
// var msg = this.$t('trials:reading:warnning:msg1') // var msg = this.$t('trials:reading:warnning:msg1')
@ -332,6 +332,7 @@ export default {
this.digitPlaces = res.Result.DigitPlaces this.digitPlaces = res.Result.DigitPlaces
this.IseCRFShowInDicomReading = res.Result.IseCRFShowInDicomReading this.IseCRFShowInDicomReading = res.Result.IseCRFShowInDicomReading
this.isReadingTaskViewInOrder = res.Result.IsReadingTaskViewInOrder this.isReadingTaskViewInOrder = res.Result.IsReadingTaskViewInOrder
localStorage.setItem('isReadingTaskViewInOrder', this.isReadingTaskViewInOrder)
localStorage.setItem('CriterionType', res.Result.CriterionType) localStorage.setItem('CriterionType', res.Result.CriterionType)
localStorage.setItem('digitPlaces', res.Result.DigitPlaces) localStorage.setItem('digitPlaces', res.Result.DigitPlaces)
this.readingCategory = res.Result.ReadingCategory this.readingCategory = res.Result.ReadingCategory

View File

@ -15,7 +15,7 @@
</div> </div>
<!-- 文件层级 --> <!-- 文件层级 -->
<div v-if="study.NoneDicomStudyFileList.length === 0" class="empty-text"> <div v-if="study.NoneDicomStudyFileList.length === 0" class="empty-text">
<slot name="empty">暂无数据</slot> <slot name="empty">{{ $t('trials:audit:message:noData') }}</slot>
</div> </div>
<div v-else id="imgList" style="height:100%;"> <div v-else id="imgList" style="height:100%;">
<div <div
@ -28,7 +28,14 @@
class="img-box" class="img-box"
@click="selected(item,i,j,true)" @click="selected(item,i,j,true)"
> >
{{ `${j+1}. ${item.FileName}` }} <div v-if="item.FileName.length < 15" class="img-text">
{{ `${j+1}. ${item.FileName}` }}
</div>
<el-tooltip v-else :content="item.FileName" placement="bottom">
<div class="img-text">
{{ `${j+1}. ${item.FileName}` }}
</div>
</el-tooltip>
</div> </div>
</div> </div>
@ -96,7 +103,7 @@ export default {
visistTaskId: '', visistTaskId: '',
taskBlindName: '', taskBlindName: '',
readingTaskState: 2, readingTaskState: 2,
bp:[] bp: []
} }
}, },
async mounted() { async mounted() {
@ -188,7 +195,7 @@ export default {
} }
var arr = bodyPart.split(separator) var arr = bodyPart.split(separator)
var newArr = arr.map(i => { var newArr = arr.map(i => {
return this.$fd('Bodypart', i.trim(),'Code',{Bodypart:this.bp},'Name') return this.$fd('Bodypart', i.trim(), 'Code', { Bodypart: this.bp }, 'Name')
}) })
return newArr.join(' | ') return newArr.join(' | ')
} }
@ -265,13 +272,19 @@ export default {
display: inline-block; display: inline-block;
box-sizing: border-box; box-sizing: border-box;
border-bottom: 2px solid #f3f3f3; border-bottom: 2px solid #f3f3f3;
width: 180px;
height: 50px;
line-height: 50px;
cursor: pointer; cursor: pointer;
// margin-bottom: 5px; // margin-bottom: 5px;
padding-left: 5px; padding-left: 5px;
} }
.img-text{
display: inline-block;
width: 200px;
height: 50px;
line-height: 50px;
overflow: hidden;
text-overflow: ellipsis; /* 用省略号表示溢出的文本 */
white-space: nowrap;
}
.img-box:nth-last-child(1){ .img-box:nth-last-child(1){
margin-bottom: 0px; margin-bottom: 0px;
} }

View File

@ -143,7 +143,6 @@ import { getMedicalReviewDialog } from '@/api/trials'
import FeedbackForm from './FeedbackForm' import FeedbackForm from './FeedbackForm'
import mimAvatar from '@/assets/MIM.png' import mimAvatar from '@/assets/MIM.png'
import irAvatar from '@/assets/IR.png' import irAvatar from '@/assets/IR.png'
import Viewer from 'v-viewer'
export default { export default {
name: 'ChatForm', name: 'ChatForm',
components: { FeedbackForm }, components: { FeedbackForm },
@ -177,7 +176,6 @@ export default {
} }
}, },
mounted() { mounted() {
this.initializeViewer()
this.getMessageList() this.getMessageList()
}, },
methods: { methods: {
@ -213,11 +211,6 @@ export default {
this.imagePath = `${this.OSSclientConfig.basePath}${path}` this.imagePath = `${this.OSSclientConfig.basePath}${path}`
this.previewDialog = true this.previewDialog = true
this.$refs[path][0].$viewer.show() this.$refs[path][0].$viewer.show()
},
initializeViewer() {
Viewer.setDefaults({
toolbar: { zoomIn: true, zoomOut: true, rotateLeft: true, rotateRight: true, flipHorizontal: true, flipVertical: true }
})
} }
} }

View File

@ -171,7 +171,6 @@ import { getMedicalReviewDialog, sendMedicalReviewDialog } from '@/api/trials'
import FeedbackForm from '@/views/trials/trials-panel/reading/medical-feedback/components/FeedbackForm' import FeedbackForm from '@/views/trials/trials-panel/reading/medical-feedback/components/FeedbackForm'
import mimAvatar from '@/assets/MIM.png' import mimAvatar from '@/assets/MIM.png'
import irAvatar from '@/assets/IR.png' import irAvatar from '@/assets/IR.png'
import Viewer from 'v-viewer'
export default { export default {
name: 'ChatForm', name: 'ChatForm',
components: { components: {
@ -207,7 +206,6 @@ export default {
} }
}, },
mounted() { mounted() {
this.initializeViewer()
this.getMessageList() this.getMessageList()
}, },
methods: { methods: {
@ -261,11 +259,6 @@ export default {
this.irFeedbackForm.title = this.$t('trials:medicalFeedback:title:feedback') this.irFeedbackForm.title = this.$t('trials:medicalFeedback:title:feedback')
this.irFeedbackForm.visible = true this.irFeedbackForm.visible = true
},
initializeViewer() {
Viewer.setDefaults({
toolbar: { zoomIn: true, zoomOut: true, rotateLeft: true, rotateRight: true, flipHorizontal: true, flipVertical: true }
})
} }
} }

View File

@ -197,7 +197,6 @@
import { saveMedicalReviewInfo } from "@/api/trials"; import { saveMedicalReviewInfo } from "@/api/trials";
import ChatForm from "./ChatForm"; import ChatForm from "./ChatForm";
import CloseQC from "./CloseQC"; import CloseQC from "./CloseQC";
import Viewer from "v-viewer";
export default { export default {
name: "AuditConclusions", name: "AuditConclusions",
components: { components: {
@ -253,7 +252,6 @@ export default {
}; };
}, },
mounted() { mounted() {
this.initializeViewer();
this.initForm(); this.initForm();
}, },
methods: { methods: {
@ -435,21 +433,9 @@ export default {
var idx = this.fileList.findIndex((i) => i.url === file.url); var idx = this.fileList.findIndex((i) => i.url === file.url);
if (idx === -1) return; if (idx === -1) return;
this.fileList.splice(idx, 1); this.fileList.splice(idx, 1);
}, }
initializeViewer() { }
Viewer.setDefaults({ }
toolbar: {
zoomIn: true,
zoomOut: true,
rotateLeft: true,
rotateRight: true,
flipHorizontal: true,
flipVertical: true,
},
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.conclusions { .conclusions {

View File

@ -1,17 +1,15 @@
<template> <template>
<!-- <el-tabs v-model="activeName" v-loading="loading" style="min-height:500px">--> <div style="min-height:500px">
<!-- <el-tab-pane--> <h3 v-if="isReadingShowSubjectInfo" style="padding: 5px 0px;margin: 0;">
<!-- v-for="criterion in criterions"--> <span v-if="subjectCode">{{ subjectCode }} </span>
<!-- :key="criterion.ReadingQuestionCriterionTrialId"--> <span style="margin-left:5px;">{{ taskBlindName }}</span>
<!-- :label="criterion.ReadingQuestionCriterionTrialName"--> </h3>
<!-- :name="criterion.ReadingQuestionCriterionTrialId"-->
<!-- >-->
<div v-loading="loading" style="min-height:500px">
<ECRF <ECRF
:trial-id="trialId" :trial-id="trialId"
:subject-id="subjectId" :subject-id="subjectId"
:criterion-id="criterionId" :criterion-id="criterionId"
:visit-task-id="visitTaskId" :visit-task-id="visitTaskId"
:iseCRFShowInDicomReading="iseCRFShowInDicomReading"
/> />
</div> </div>
@ -43,6 +41,22 @@ export default {
criterionId: { criterionId: {
type: String, type: String,
required: true required: true
},
subjectCode: {
type: String,
required: true
},
taskBlindName: {
type: String,
required: true
},
isReadingShowSubjectInfo: {
type: Boolean,
required: true
},
iseCRFShowInDicomReading: {
type: Boolean,
required: true
} }
}, },
data() { data() {

View File

@ -77,13 +77,13 @@
<el-form-item v-if="readingTaskState < 2"> <el-form-item v-if="readingTaskState < 2">
<div style="text-align:center;"> <div style="text-align:center;">
<el-button type="primary" @click="skipTask"> <el-button type="primary" @click="skipTask" v-if="iseCRFShowInDicomReading">
{{ $t('trials:readingReport:button:skip') }} {{ $t('trials:readingReport:button:skip') }}
</el-button> </el-button>
<el-button type="primary" @click="handleSave"> <el-button type="primary" @click="handleSave">
{{ $t('common:button:save') }} {{ $t('common:button:save') }}
</el-button> </el-button>
<el-button type="primary" @click="handleSubmit"> <el-button type="primary" @click="handleSubmit" v-if="iseCRFShowInDicomReading">
{{ $t('common:button:submit') }} {{ $t('common:button:submit') }}
</el-button> </el-button>
</div> </div>
@ -116,7 +116,7 @@ import const_ from '@/const/sign-code'
import FormItem from './FormItem' import FormItem from './FormItem'
import SignForm from '@/views/trials/components/newSignForm' import SignForm from '@/views/trials/components/newSignForm'
// import { getToken } from '@/utils/auth' // import { getToken } from '@/utils/auth'
// import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
export default { export default {
name: 'ECRF', name: 'ECRF',
components: { components: {
@ -139,6 +139,10 @@ export default {
visitTaskId: { visitTaskId: {
type: String, type: String,
required: true required: true
},
iseCRFShowInDicomReading: {
type: Boolean,
required: true
} }
}, },
data() { data() {
@ -158,6 +162,9 @@ export default {
}, },
mounted() { mounted() {
this.getQuestions() this.getQuestions()
DicomEvent.$on('refreshQuestionAnswer', _ => {
this.getQuestions()
})
}, },
methods: { methods: {
async getQuestions() { async getQuestions() {
@ -243,6 +250,7 @@ export default {
try { try {
const res = await saveVisitTaskQuestions(params) const res = await saveVisitTaskQuestions(params)
if (res.IsSuccess) { if (res.IsSuccess) {
DicomEvent.$emit('getReportInfo', true)
this.$message.success(this.$t('common:message:savedSuccessfully')) this.$message.success(this.$t('common:message:savedSuccessfully'))
} }
this.loading = false this.loading = false
@ -285,6 +293,7 @@ export default {
const res = await submitVisitTaskQuestionsInDto(params) const res = await submitVisitTaskQuestionsInDto(params)
this.loading = false this.loading = false
if (res.IsSuccess) { if (res.IsSuccess) {
DicomEvent.$emit('getReportInfo', true)
this.$message.success(this.$t('common:message:savedSuccessfully')) this.$message.success(this.$t('common:message:savedSuccessfully'))
this.isEdit = false this.isEdit = false
this.$refs['signForm'].btnLoading = false this.$refs['signForm'].btnLoading = false

View File

@ -120,11 +120,26 @@
</el-checkbox-group> </el-checkbox-group>
<!-- 数值 --> <!-- 数值 -->
<!-- :precision="2" :step="0.1" :max="10" --> <!-- :precision="2" :step="0.1" :max="10" -->
<el-input-number <template v-if="question.Type==='number'">
v-if="question.Type==='number'" <el-input-number
v-model="questionForm[question.Id]" v-if="question.ValueType === 0"
:disabled="readingTaskState >= 2" v-model="questionForm[question.Id]"
/> precision="0"
:disabled="readingTaskState >= 2"
/>
<el-input-number
v-else-if="question.ValueType === 3"
v-model="questionForm[question.Id]"
:disabled="readingTaskState >= 2"
/>
<el-input-number
v-else-if="question.ValueType === 1 || question.ValueType === 2"
v-model="questionForm[question.Id]"
:precision="digitPlaces"
:disabled="readingTaskState >= 2"
/>
</template>
<!-- 上传图像 --> <!-- 上传图像 -->
<el-upload <el-upload
v-if="question.Type==='upload'" v-if="question.Type==='upload'"
@ -222,7 +237,8 @@ export default {
accept: '.png,.jpg,.jpeg', accept: '.png,.jpg,.jpeg',
imgVisible: false, imgVisible: false,
imageUrl: '', imageUrl: '',
urls: [] urls: [],
digitPlaces: null
} }
}, },
watch: { watch: {
@ -245,6 +261,7 @@ export default {
}) })
} }
} }
this.digitPlaces = parseInt(localStorage.getItem('digitPlaces'))
}, },
methods: { methods: {
formItemChange(v, question) { formItemChange(v, question) {

View File

@ -0,0 +1,956 @@
<template>
<div class="report-wrapper">
<el-card v-loading="loading" shadow="never" style="display:flex;flex-direction: column;">
<div slot="header" class="clearfix report-header">
<h3 style="margin:0;padding:0;">{{ $t('trials:readingReport:title:eicrf') }}</h3>
<div style="margin-left:auto">
<!-- <el-switch
v-model="isShowDetail"
:active-text="$t('trials:readingReport:title:expandDetails')"
:inactive-text="$t('trials:readingReport:title:collapseDetails')"
style="margin-right:5px"
@change="handleShowDetail"
/> -->
<el-button
v-if="readingTaskState<2"
type="primary"
size="small"
@click="skipTask"
>
<!-- 跳过 -->
{{ $t('trials:readingReport:button:skip') }}
</el-button>
<el-button v-if="readingTaskState<2" type="primary" size="small" @click="getReportInfo">{{ $t('trials:readingReport:button:refresh') }}</el-button>
<el-button v-if="readingTaskState<2" type="primary" size="small" @click="handleSave(true)">{{ $t('common:button:save') }}</el-button>
<el-button v-if="readingTaskState<2" type="primary" size="small" @click="handleConfirm">{{ $t('common:button:submit') }}</el-button>
</div>
</div>
<div style="flex: 1">
<el-table
v-if="taskQuestions.length > 0"
ref="reportList"
v-adaptive="{bottomOffset:0}"
:data="taskQuestions"
row-key="Id"
border
default-expand-all
height="100"
:tree-props="{children: 'Childrens', hasChildren: 'hasChildren'}"
size="mini"
>
<el-table-column
prop=""
label=""
show-overflow-tooltip
width="350px"
>
<template slot-scope="scope">
<span v-if="scope.row.QuestionName">{{ scope.row.BlindName ? scope.row.QuestionName : scope.row.QuestionName }}</span>
<span
v-else
style="font-weight: bold;font-size: 16px;color: #f44336;"
>
{{ scope.row.GroupName }}
</span>
</template>
</el-table-column>
<el-table-column
v-for="task in visitTaskList"
:key="task.VisitTaskId"
prop="date"
show-overflow-tooltip
width="200px"
>
<template slot="header">
<div v-if="task.IsCurrentTask">
{{ task.BlindName }}
</div>
<div v-else>
<div>
{{ task.BlindName }}
<el-button type="text" size="small" @click="previewDicoms(task)">
<span class="el-icon-view" />
</el-button>
</div>
<!-- <div v-if="task.LatestScanDate">-->
<!-- {{ task.LatestScanDate.split(' ')[0] }}-->
<!-- </div>-->
<!-- {{ `(影像点击跳转)` }} -->
<!-- {{ $t('trials:readingReport:button:jump') }}-->
</div>
</template>
<template slot-scope="scope">
<template v-if="readingTaskState<2 && task.VisitTaskId === visitTaskId && (scope.row.Type==='input' || scope.row.Type==='number' || scope.row.Type==='select' || scope.row.Type==='textarea' || scope.row.Type==='radio')">
<template>
<!-- 输入框 -->
<div>
<template v-if="!((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)" />
<el-input
v-else-if="questionForm[scope.row.QuestionId] instanceof Array && (scope.row.Type==='input' || scope.row.Type==='textarea') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]"
size="mini"
/>
<span v-else-if="questionForm[scope.row.QuestionId] instanceof Array && (scope.row.Type==='input' || scope.row.Type==='textarea')">
{{ questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId] }}
</span>
<el-input
v-else-if="(scope.row.Type==='input' || scope.row.Type==='textarea') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId]"
size="mini"
/>
<span v-else-if="scope.row.Type==='input' || scope.row.Type==='textarea'">
{{ questionForm[scope.row.QuestionId] }}
</span>
<el-select
v-else-if="questionForm[scope.row.QuestionId] instanceof Array && (scope.row.Type==='select' || scope.row.Type==='radio') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]"
size="mini"
clearable
>
<template>
<el-option
v-for="val in scope.row.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<span v-else-if="questionForm[scope.row.QuestionId] instanceof Array && scope.row.Type==='select'">
{{ questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId] }}
</span>
<el-select
v-else-if="(scope.row.Type==='select' || scope.row.Type==='radio') && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId]"
size="mini"
clearable
>
<template>
<el-option
v-for="val in scope.row.TypeValue.split('|')"
:key="val"
:label="val"
:value="val"
/>
</template>
</el-select>
<span v-else-if="scope.row.Type==='select' || scope.row.Type==='radio'">
{{ questionForm[scope.row.QuestionId] }}
</span>
<el-input
v-else-if="scope.row.DataSource !== 1 && questionForm[scope.row.QuestionId] instanceof Array && scope.row.Type==='number' && (scope.row.xfIndex || scope.row.xfIndex === 0) && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]"
:disabled="scope.row.DataSource === 1"
size="mini"
@blur="limitBlur(questionForm[scope.row.QuestionId][scope.row.xfIndex], scope.row.TableQuestionId, scope.row.ValueType)"
@focus="() => {questionId = scope.row.QuestionId}"
>
<template v-if="scope.row.Unit !== 0" slot="append">{{ scope.row.Unit !== 4 ? $fd('ValueUnit', scope.row.Unit) : scope.row.CustomUnit }}</template>
<template v-else-if="scope.row.ValueType === 2" slot="append">%</template>
</el-input>
<span v-else-if="questionForm[scope.row.QuestionId] instanceof Array && scope.row.Type==='number' && (scope.row.xfIndex || scope.row.xfIndex === 0)">
<template v-if="(scope.row.ValueType === 0 || scope.row.ValueType === 1) && scope.row.Unit">
{{ isNaN(parseInt(questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]))? questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]:`${questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]} ${scope.row.Unit !== 4 ? $fd('ValueUnit',scope.row.Unit) : scope.row.CustomUnit}` }}
</template>
<template v-else-if="scope.row.ValueType === 2">
{{ isNaN(parseInt(questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId])) ? questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]:`${questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]} %` }}
</template>
<template v-else>
{{ isNaN(parseInt(questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId])) ? questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]:`${questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]}` }}
</template>
</span>
<el-input
v-else-if="scope.row.DataSource !== 1 && scope.row.Type==='number' && !scope.row.IsShowInDicom && ((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)"
v-model="questionForm[scope.row.QuestionId]"
:disabled="scope.row.DataSource === 1"
size="mini"
@blur="limitBlur(questionForm, scope.row.QuestionId, scope.row.ValueType)"
@focus="() => {questionId = scope.row.QuestionId}"
>
<template v-if="scope.row.Unit !== 0" slot="append">{{ scope.row.Unit !== 4 ? $fd('ValueUnit', scope.row.Unit) : scope.row.CustomUnit }}</template>
<template v-else-if="scope.row.ValueType === 2" slot="append">%</template>
</el-input>
<span v-else-if="scope.row.Type==='number'">
<template v-if="(scope.row.ValueType === 0 || scope.row.ValueType === 1) && scope.row.Unit">
{{ isNaN(parseInt(questionForm[scope.row.QuestionId]))? questionForm[scope.row.QuestionId]:`${questionForm[scope.row.QuestionId]} ${scope.row.Unit !== 4 ? $fd('ValueUnit',scope.row.Unit) : scope.row.CustomUnit}` }}
</template>
<template v-else-if="scope.row.ValueType === 2">
{{ isNaN(parseInt(questionForm[scope.row.QuestionId])) ? questionForm[scope.row.QuestionId]:`${questionForm[scope.row.QuestionId]} %` }}
</template>
<template v-else>
{{ isNaN(parseInt(questionForm[scope.row.QuestionId])) ? questionForm[scope.row.QuestionId] : questionForm[scope.row.QuestionId] }}
</template>
</span>
</div>
</template>
</template>
<template v-else-if="task.VisitTaskId === visitTaskId && scope.row.Type === 'upload'">
<UploadFile
v-if="scope.row.Type==='upload' && (scope.row.xfIndex || scope.row.xfIndex === 0)"
:visit-task-id="visitTaskId"
:question="scope.row"
:task="task"
:reading-task-state="readingTaskState"
:init-url="questionForm[scope.row.QuestionId][scope.row.xfIndex][scope.row.TableQuestionId]"
@setImageUrl="(url) => {setImageUrl(scope.row.QuestionId, scope.row.xfIndex, scope.row.TableQuestionId, url, scope.row.RowId)}"
/>
<UploadFile
v-else-if="scope.row.Type==='upload'"
:visit-task-id="visitTaskId"
:question="scope.row"
:task="task"
:reading-task-state="readingTaskState"
:init-url="questionForm[scope.row.QuestionId]"
@setImageUrl="(url) => {setImageUrl(scope.row.QuestionId, scope.row.xfIndex, scope.row.TableQuestionId, url)}"
/>
</template>
<template v-else-if="scope.row.Type === 'upload'">
<UploadFile
v-if="scope.row.Type==='upload' && (scope.row.xfIndex || scope.row.xfIndex === 0)"
:visit-task-id="visitTaskId"
:question="scope.row"
:task="task"
:reading-task-state="readingTaskState"
:init-url="scope.row.Answers[task.VisitTaskId]"
/>
<UploadFile
v-else-if="scope.row.Type==='upload'"
:visit-task-id="visitTaskId"
:question="scope.row"
:task="task"
:reading-task-state="readingTaskState"
:init-url="scope.row.Answers[task.VisitTaskId]"
/>
</template>
<template v-else-if="scope.row.QuestionType=== 22">
{{ scope.row.Answers[task.VisitTaskId] === '-1' ? '未知' : scope.row.Answers[task.VisitTaskId] }}
</template>
<template v-else-if="scope.row.DictionaryCode">
{{ $fd(scope.row.DictionaryCode, scope.row.Answers[task.VisitTaskId]) }}
</template>
<template v-else-if="CriterionType === 10">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))?scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]}` }}
</template>
<template v-else-if="!((task.IsBaseLine && scope.row.LimitEdit === 1) || (!task.IsBaseLine && scope.row.LimitEdit === 2) || scope.row.LimitEdit === 0)" />
<template v-else-if="(scope.row.ValueType === 0 || scope.row.ValueType === 1) && scope.row.Unit">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId]))?scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]} ${scope.row.Unit !== 4 ? $fd('ValueUnit',scope.row.Unit) : scope.row.CustomUnit}` }}
</template>
<template v-else-if="scope.row.ValueType === 2">
{{ isNaN(parseInt(scope.row.Answers[task.VisitTaskId])) ? scope.row.Answers[task.VisitTaskId]:`${scope.row.Answers[task.VisitTaskId]} %` }}
</template>
<template v-else-if="scope.row.Answers && scope.row.Answers.hasOwnProperty(task.VisitTaskId)">
{{ scope.row.Answers[task.VisitTaskId] }}
</template>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
<!-- 签名框 -->
<el-dialog
v-if="signVisible"
:visible.sync="signVisible"
:close-on-click-modal="false"
width="600px"
custom-class="base-dialog-wrapper"
>
<div slot="title">
<span style="font-size:18px;">{{ $t('common:dialogTitle:sign') }}</span>
<span style="font-size:12px;margin-left:5px">{{ `(${$t('common:label:sign')}${ currentUser })` }}</span>
</div>
<SignForm ref="signForm" :sign-code-enum="signCode" @closeDialog="closeSignDialog" />
</el-dialog>
</div>
</template>
<script>
import { changeCalculationAnswer, getReadingReportEvaluation, submitDicomVisitTask, verifyVisitTaskQuestions, getQuestionCalculateRelation } from '@/api/trials'
import { setSkipReadingCache } from '@/api/reading'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
import UploadFile from './UploadFile'
import const_ from '@/const/sign-code'
import SignForm from '@/views/trials/components/newSignForm'
import { getToken } from '@/utils/auth'
import store from '@/store'
export default {
name: 'Report',
components: { SignForm, UploadFile },
props: {
trialId: {
type: String,
required: true
},
visitTaskId: {
type: String,
required: true
},
subjectId: {
type: String,
required: true
},
readingTool: {
type: String,
required: true
},
criterionType: {
type: String,
required: true
},
isReadingTaskViewInOrder: {
type: Number,
required: true
}
},
data() {
return {
currentUser: zzSessionStorage.getItem('userName'),
signVisible: false,
signCode: null,
visitTaskList: [],
taskQuestions: [],
loading: false,
answers: [],
readingTaskState: 2,
tumorEvaluate: null,
currentEvaluateResult: null,
isExistDisease: null,
currentExistDisease: null,
currentTaskReason: '',
answerArr: [],
questions: [],
isShowDetail: false,
CriterionType: 0,
CalculationList: [],
TrialReadingCriterionId: null,
tableAnswers: {},
questionForm: {},
questionId: null
}
},
watch: {
questionForm: {
deep: true,
immediate: true,
handler(v, oldv) {
try {
if (!v[this.questionId] || !oldv[this.questionId]) return
} catch (e) {
}
this.formItemNumberChange(this.questionId, false)
}
},
taskQuestions() {
this.$nextTick(() => {
this.setScrollTop()
})
}
},
async mounted() {
this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
this.digitPlaces = parseInt(localStorage.getItem('digitPlaces'))
this.TrialReadingCriterionId = this.$route.query.TrialReadingCriterionId
window.addEventListener('resize', () => {
this.handleResize()
this.setScrollTop()
})
DicomEvent.$on('getReportInfo', isRefresh => {
if (!isRefresh) return
this.getReportInfo()
})
await this.getQuestionCalculateRelation()
this.getReportInfo()
},
beforeDestroy() {
DicomEvent.$off('getReportInfo')
},
methods: {
limitBlur(questionForm, id, valueType) {
const value = questionForm[id]
if (valueType === 0) {
this.$set(questionForm, id, parseInt(value))
} else if (valueType === 3) {
this.$set(questionForm, id, parseFloat(value))
} else {
this.$set(questionForm, id, parseFloat(value).toFixed(this.digitPlaces))
}
},
setImageUrl(qid, index, tqid, url, RowId) {
if (index || index === 0) {
//
this.$set(this.questionForm[qid][index], tqid, url)
this.$set(this.questionForm[qid][index], tqid + '_RowId', RowId)
// this.questionForm[qid][index][tqid] = url
} else {
//
this.questionForm[qid] = url
}
},
getTagterAnswers(list, questionId) {
list.forEach(v => {
if (v.QuestionId === questionId) {
return Object.assign({}, v.Answers)
} else if (v.Childrens.length > 0) {
return this.getTagterAnswers(v.Childrens, questionId)
}
})
},
formItemNumberChange(questionId, isTable) {
if (isTable) {
this.CalculationList.forEach((v, i) => {
var find = v.CalculateQuestionList.filter(o => {
return o.QuestionId === questionId
})
// findnumber
if (find) {
var num = this.logic(v)
if (num !== false) {
this.$set(this.questionForm, v.QuestionId, num)
// this.$emit('setFormItemData', { key: v.QuestionId, val: num })
}
}
})
} else {
this.CalculationList.forEach(v => {
var find = v.CalculateQuestionList.filter(o => {
return o.TableQuestionId === questionId
})
// findnumber
if (find) {
var num = this.logic(v)
if (num !== false) {
this.$set(this.questionForm, v.QuestionId, num)
// this.$emit('setFormItemData', { key: v.QuestionId, val: num })
}
}
})
}
// this.$emit('formItemNumberChange')
},
getTableAnswers(QuestionId, list) {
var arr = []
window.xfList = list
list.forEach((v, i) => {
var obj = {}
v.Childrens.forEach((o) => {
this.$set(o, 'xfIndex', i)
obj[o.TableQuestionId + '_RowId'] = o.RowId
obj[o.TableQuestionId] = o.Answers[this.visitTaskId]
})
arr.push(obj)
})
return arr
},
InitVisitTaskQuestionForm() {
this.taskQuestions.map((v, i) => {
if (v.Type === 'group' && v.Childrens.length === 0 && v.Type !== 'table') return
if (!v.IsPage && v.Type !== 'group' && v.Type !== 'summary' && v.Type !== 'table' && v.Type !== 'number') {
this.$set(this.questionForm, v.QuestionId, v.Answers[this.visitTaskId])
}
if (v.Type === 'table') {
var tableAnswers = this.getTableAnswers(v.QuestionId, v.Childrens, i)
this.$set(this.questionForm, v.QuestionId, tableAnswers)
// this.$set(v, 'xfIndex', i)
}
if (v.Type === 'number') {
let val = null
if (v.ValueType === 0) {
val = parseInt(v.Answers[this.visitTaskId])
} else if (v.ValueType === 3) {
val = v.Answers[this.visitTaskId]
} else {
val = v.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : v.Answers[this.visitTaskId]
}
this.$set(this.questionForm, v.QuestionId, val)
}
if (v.Childrens.length > 0) {
this.setChild(v.Childrens)
}
})
this.formItemNumberChange(this.questionId, false)
},
setChild(obj) {
obj.forEach((i, index) => {
if (i.Type !== 'group' && i.Type !== 'summary' && i.Id && i.Type !== 'table') {
this.$set(this.questionForm, i.QuestionId, i.Answers[this.visitTaskId])
}
if (i.Type === 'table') {
var tableAnswers = this.getTableAnswers(i.QuestionId, i.Childrens, index)
this.$set(this.questionForm, i.QuestionId, tableAnswers)
}
if (i.Type === 'number') {
let val = null
if (i.ValueType === 0) {
val = parseInt(i.Answers[this.visitTaskId])
} else if (i.ValueType === 3) {
val = i.Answers[this.visitTaskId]
} else {
val = i.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : i.Answers[this.visitTaskId]
}
this.$set(this.questionForm, i.QuestionId, val)
}
if (i.Childrens && i.Childrens.length > 0 && i.Type !== 'table') {
this.setChild(i.Childrens)
}
})
},
getQuestionCalculateRelation() {
return new Promise(resolve => {
getQuestionCalculateRelation({
TrialReadingCriterionId: this.TrialReadingCriterionId
}).then(res => {
this.CalculationList = res.Result
resolve()
})
})
},
logic(rules, num = 0) {
try {
if (rules.CalculateQuestionList.length === 0) {
return false
}
rules.CalculateQuestionList.forEach((o, i) => {
if (i === 0) {
if (rules.CustomCalculateMark > 4) {
switch (rules.CustomCalculateMark) {
case 5:
this.questionForm[o.QuestionId].forEach((q, qi) => {
if (qi === 0) {
num = parseFloat(q[o.TableQuestionId])
} else {
num *= parseFloat(q[o.TableQuestionId])
}
})
break
case 6:
this.questionForm[o.QuestionId].forEach((q, qi) => {
if (qi === 0) {
num = isNaN(parseFloat(q[o.TableQuestionId])) ? null : parseFloat(q[o.TableQuestionId])
} else {
num += isNaN(parseFloat(q[o.TableQuestionId])) ? null : parseFloat(q[o.TableQuestionId])
}
})
break
case 7:
this.questionForm[o.QuestionId].forEach((q, qi) => {
if (qi === 0) {
num = parseFloat(q[o.TableQuestionId])
} else {
num += parseFloat(q[o.TableQuestionId])
}
})
num = this.questionForm[o.QuestionId].length === 0 ? 0 : num / this.questionForm[o.QuestionId].length
break
case 8:
var arr = []
this.questionForm[o.QuestionId].forEach(q => {
arr.push(q[o.TableQuestionId])
})
num = arr.length === 0 ? 0 : Math.max(...arr)
break
case 9:
// eslint-disable-next-line no-redeclare
var arr = []
this.questionForm[o.QuestionId].forEach(q => {
arr.push(q[o.TableQuestionId])
})
num = arr.length === 0 ? 0 : Math.min(...arr)
break
}
} else {
num = parseFloat(this.questionForm[o.TableQuestionId])
}
} else {
switch (rules.CustomCalculateMark) {
case 1:
num += parseFloat(this.questionForm[o.TableQuestionId])
break
case 2:
num -= parseFloat(this.questionForm[o.TableQuestionId])
break
case 3:
num *= parseFloat(this.questionForm[o.TableQuestionId])
break
case 4:
num /= parseFloat(this.questionForm[o.TableQuestionId])
// num /= parseFloat(this.questionForm[o.TableQuestionId])
break
}
}
})
} catch (e) {
console.log(e)
}
var digitPlaces = parseInt(localStorage.getItem('digitPlaces'))
if (rules.ValueType === 2) {
num = num * 100
}
return isNaN(num) ? '' : isFinite(num) ? num.toFixed(digitPlaces) : '∞'
},
getReportInfo() {
this.loading = true
var params = {
visitTaskId: this.visitTaskId,
trialId: this.$router.currentRoute.query.trialId
}
this.taskQuestions = []
getReadingReportEvaluation(params).then(res => {
this.readingTaskState = res.Result.ReadingTaskState
this.tumorEvaluate = res.Result.CalculateResult.TumorEvaluate ? parseInt(res.Result.CalculateResult.TumorEvaluate) : null
this.isExistDisease = res.Result.CalculateResult.IsExistDisease ? parseInt(res.Result.CalculateResult.IsExistDisease) : null
this.answerArr = []
this.questions = res.Result.TaskQuestions.concat()
var taskQuestions = this.getQuestions(res.Result.TaskQuestions, !this.isShowDetail, null, null)
taskQuestions.forEach(item => {
this.$set(this.taskQuestions, this.taskQuestions.length, item)
})
this.visitTaskList = res.Result.VisitTaskList
this.InitVisitTaskQuestionForm()
this.handleResize()
this.setScrollTop()
this.loading = false
}).catch(() => { this.loading = false })
},
setScrollTop(a) {
setTimeout(() => {
this.$nextTick(() => {
if (this.$refs.reportList) {
this.$refs.reportList.bodyWrapper.scrollTop = this.$refs.reportList.bodyWrapper.scrollHeight
this.$refs.reportList.bodyWrapper.scrollTop = this.$refs.reportList.bodyWrapper.scrollHeight
}
})
}, 50)
},
getQuestions(questions, isNTFilterLength, lesionType, isLymphNodes) {
const arr = []
if (questions.length !== 0) {
questions.forEach((item) => {
//
//
//
lesionType = item.LesionType
var filterArr = []
if ((item.LesionType === 1 || item.LesionType === 2) && isNTFilterLength) {
filterArr = [0, 1, 3, 4, 5, 6, 2, 8, 10]
} else {
filterArr = [3, 4, 5, 6, 2, 8, 10]
}
if (lesionType === 0 && isLymphNodes === 0 && !this.isShowDetail && this.CriterionType === 1) {
filterArr.push(1)
}
if (!(filterArr.includes(item.QuestionMark))) {
const obj = item
this.$set(obj, 'Answers', {})
// obj.Answers = {}
if (item.RowIndex > 0) {
var idx = item.Childrens.findIndex(i => i.QuestionMark === 8)
var idxLoc = item.Childrens.findIndex(i => i.QuestionMark === 10)
if (idx > -1) {
if (item.Childrens[idx].Answer.length > 0) {
var k = item.Childrens[idx].Answer.findIndex(v => v.Answer !== '')
var part = ''
if (obj.IsCanEditPosition) {
part = `${item.Childrens[idx].Answer[k].Answer}--${item.Childrens[idxLoc].Answer[k].Answer}`
} else {
part = `${item.Childrens[idx].Answer[k].Answer}`
}
if (item.SplitOrMergeLesionName && k > -1) {
obj.QuestionName = `${obj.QuestionName} --${part} (Split from ${item.SplitOrMergeLesionName})`
// obj.QuestionName = `${obj.QuestionName} `
} else if (!item.SplitOrMergeLesionName && k > -1) {
obj.QuestionName = `${obj.QuestionName} --${part}`
// obj.QuestionName = `${obj.QuestionName} `
} else {
obj.QuestionName = `${obj.QuestionName} `
}
if (this.CriterionType === 1) {
var idxLymphNode = item.Childrens.findIndex(i => i.QuestionMark === 2)
if (idxLymphNode > -1) {
isLymphNodes = item.Childrens[idxLymphNode].Answer[k].Answer ? parseInt(item.Childrens[idxLymphNode].Answer[k].Answer) : null
}
}
}
}
}
var digitPlaces = parseInt(localStorage.getItem('digitPlaces')) || 0
item.Answer.forEach(i => {
if (item.DictionaryCode) {
this.$set(obj.Answers, i.VisitTaskId, i.Answer ? parseInt(i.Answer) : null)
// obj.Answers[i.VisitTaskId] = i.Answer ? parseInt(i.Answer) : null
} else {
if (item.Type === 'number') {
let val = null
if (item.ValueType === 0) {
val = parseInt(i.Answer)
} else if (item.ValueType === 3) {
val = i.Answer
} else {
val = isNaN(parseFloat(i.Answer)) ? i.Answer : parseFloat(i.Answer).toFixed(digitPlaces)
}
this.$set(obj.Answers, i.VisitTaskId, val)
} else {
this.$set(obj.Answers, i.VisitTaskId, i.Answer)
}
// obj.Answers[i.VisitTaskId] = i.Answer
}
})
if (item.Childrens.length >= 1) {
obj.Childrens = this.getQuestions(item.Childrens, isNTFilterLength, lesionType, isLymphNodes)
}
arr.push(obj)
}
})
}
return arr
},
handleShowDetail(val) {
this.getReportInfo()
// this.taskQuestions = this.getQuestions(res.Result.TaskQuestions, !this.isShowDetail, null)
},
handleExistDiseaseChange(val) {
// this.currentExistDisease = parseInt(val)
if (val === this.isExistDisease && this.tumorEvaluate === this.currentEvaluateResult) {
this.currentTaskReason = ''
this.evaluateReasonChange('')
}
var idx = this.answerArr.findIndex(i => i.questionType === 15)
if (idx > -1) {
this.answerArr[idx].answer = val
}
},
handleEvaluateResultChange(val) {
// this.currentEvaluateResult = parseInt(val)
if (val === this.tumorEvaluate && this.isExistDisease === this.currentExistDisease) {
this.currentTaskReason = ''
this.evaluateReasonChange('')
}
var idx = this.answerArr.findIndex(i => i.questionType === 13)
if (idx > -1) {
this.answerArr[idx].answer = val
}
},
evaluateReasonChange(val) {
var idx = this.answerArr.findIndex(i => i.questionType === 14)
if (idx > -1) {
this.answerArr[idx].answer = val
}
},
async handleConfirm() {
await this.handleSave(false)
await this.verifyVisitTaskQuestions()
const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true
},
verifyVisitTaskQuestions() {
return new Promise((resolve, reject) => {
this.loading = true
verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId }).then(res => {
this.loading = false
resolve()
}).catch(() => {
this.loading = false
reject()
})
})
},
handleResize() {
this.$nextTick(() => {
this.$refs.reportList ? this.$refs.reportList.doLayout() : ''
})
},
//
closeSignDialog(isSign, signInfo) {
if (isSign) {
this.signConfirm(signInfo)
} else {
this.signVisible = false
}
},
//
signConfirm(signInfo) {
this.loading = true
var params = {
data: {
visitTaskId: this.visitTaskId
},
signInfo: signInfo
}
submitDicomVisitTask(params).then(res => {
if (res.IsSuccess) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
if (this.$refs['signForm']) {
this.$refs['signForm'].btnLoading = false
}
this.signVisible = false
// window.location.reload()
// window.opener.postMessage('refreshTaskList', window.location)
//
this.readingTaskState = 2
store.dispatch('reading/setVisitTaskReadingTaskState', { visitTaskId: this.visitTaskId, readingTaskState: 2 })
DicomEvent.$emit('setReadingState', 2)
window.opener.postMessage('refreshTaskList', window.location)
this.$confirm(this.$t('trials:oncologyReview:title:msg2'), {
type: 'warning',
distinguishCancelAndClose: true
})
.then(() => {
// var token = getToken()
// var subjectCode = this.$router.currentRoute.query.subjectCode
// var subjectId = this.$router.currentRoute.query.subjectId
// var trialId = this.$router.currentRoute.query.trialId
// this.$router.push({
// path: `/readingPage?subjectCode=${subjectCode}&subjectId=${subjectId}&trialId=${trialId}&TokenKey=${token}`
// })
// DicomEvent.$emit('getNextTask')
window.location.reload()
})
.catch(action => {
})
}
this.loading = false
}).catch(() => {
this.loading = false
if (this.$refs['signForm'] && this.$refs['signForm'].btnLoading) {
this.$refs['signForm'].btnLoading = false
}
})
},
previewDicoms(task) {
var token = getToken()
// var subjectCode = this.$router.currentRoute.query.subjectCode
var subjectCode = localStorage.getItem('subjectCode')
var subjectId = this.subjectId
var trialId = this.trialId
var isReadingTaskViewInOrder = this.isReadingTaskViewInOrder
var criterionType = this.criterionType
var readingTool = this.readingTool
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&subjectCode=${subjectCode}&subjectId=${subjectId}&visitTaskId=${task.VisitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
const routeData = this.$router.resolve({ path })
window.open(routeData.href, '_blank')
},
handleSave(isPrompt) {
return new Promise((resolve, reject) => {
this.loading = true
var answers = []
var tableQuestionAnswer = []
for (const k in this.questionForm) {
if (this.questionForm[k] instanceof Array) {
this.questionForm[k].forEach((v, i) => {
Object.keys(v).forEach(o => {
if (o.indexOf('_RowId') === -1) {
tableQuestionAnswer.push({
questionId: k,
answer: v[o],
tableQuestionId: o,
rowId: v[o + '_RowId']
})
}
})
})
// tableQuestionAnswer.push({})
} else {
answers.push({ questionId: k, answer: this.questionForm[k].toString() })
}
}
var params = {
visitTaskId: this.visitTaskId,
questionAnswer: answers,
tableQuestionAnswer: tableQuestionAnswer
}
changeCalculationAnswer(params).then(res => {
if (isPrompt) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
}
DicomEvent.$emit('refreshQuestionAnswer')
this.loading = false
resolve()
}).catch(() => {
this.loading = false
reject()
})
})
},
async skipTask() {
try {
//
const confirm = await this.$confirm(
this.$t('trials:readingReport:message:skipConfirm'),
{
type: 'warning',
distinguishCancelAndClose: true
}
)
if (confirm !== 'confirm') return
this.loading = true
const res = await setSkipReadingCache({ visitTaskId: this.visitTaskId })
this.loading = false
if (res.IsSuccess) {
window.location.reload()
}
} catch (e) {
this.loading = false
console.log(e)
}
}
}
}
</script>
<style lang="scss" scoped>
.report-wrapper{
height: 100%;
// background-color: #fff;
// background-color: #000;
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
// background: #d0d0d0;
}
.report-header{
display: flex;
}
.el-card{
// background-color: #000;
// color: #ffffff;
border:none;
}
/deep/ .el-table--border th.gutter:last-of-type{
border: none;
}
/deep/ .el-card__header{
border: none;
padding: 10px;
}
/deep/ .el-upload-list--picture-card .el-upload-list__item{
width: 30px;
height: 30px;
}
/deep/ .el-upload--picture-card{
width: 30px;
height: 30px;
line-height: 40px;
}
}
/deep/ .el-switch__label.is-active{
color: #428bca;
}
.uploadWrapper{
display: flex;
flex-direction: column;
align-items: flex-start;
}
</style>

View File

@ -0,0 +1,167 @@
<template>
<div>
<el-upload
:action="accept"
:limit="question.ImageCount"
:on-preview="handlePictureCardPreview"
:before-upload="handleBeforeUpload"
:http-request="uploadScreenshot"
list-type="picture-card"
:on-remove="handleRemove"
:file-list="fileList"
:class="{disabled:readingTaskState >= 2 || (fileList.length >= question.ImageCount) || (task.VisitTaskId !== visitTaskId) || question.IsShowInDicom || ((task.IsBaseLine && question.LimitEdit === 2) || (!task.IsBaseLine && question.LimitEdit === 1))}"
:disabled="readingTaskState >= 2 || task.VisitTaskId !== visitTaskId || question.IsShowInDicom || ((task.IsBaseLine && question.LimitEdit === 2) || (!task.IsBaseLine && question.LimitEdit === 1))"
>
<i slot="default" class="el-icon-plus" />
<div slot="file" slot-scope="{file}">
<viewer
:ref="file.url"
:images="[imageUrl]"
style="
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
"
>
<img
class="el-upload-list__item-thumbnail"
:src="OSSclientConfig.basePath + file.url"
crossOrigin="anonymous"
alt=""
style="max-width: 100%; max-height: 100%"
/>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in" />
</span>
<span
v-if="readingTaskState < 2"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete" />
</span>
</span>
</viewer>
</div>
</el-upload>
</div>
</template>
<script>
export default {
name: "UploadFile",
props: {
task: {
Type: Object,
required: true
},
question: {
Type: Object,
required: true
},
visitTaskId: {
type: String,
required: true
},
readingTaskState: {
type: Number,
required: true
},
initUrl: {
type: String,
default: ''
}
},
data () {
return {
imgVisible: false,
imageUrl: null,
accept: '.png,.jpg,.jpeg',
fileList: [],
}
},
mounted() {
this.urls = this.initUrl === '' ? [] : this.initUrl.split('|')
console.log(this.visitTaskId, this.urls)
this.fileList = []
this.urls.map(url => {
this.fileList.push({ name: '', url: `${url}` })
})
console.log(this.fileList)
},
methods: {
checkFileSuffix(fileName) {
var index = fileName.lastIndexOf('.')
var suffix = fileName.substring(index + 1, fileName.length)
if (this.accept.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === -1) {
return false
} else {
return true
}
},
async uploadScreenshot(param) {
if (!this.visitTaskId) return
const loading = this.$loading({
target: document.querySelector('.ecrf-wrapper'),
fullscreen: false,
lock: true,
text: 'Loading',
spinner: 'el-icon-loading'
})
var trialId = this.$route.query.trialId
var subjectId = this.$route.query.trialId
var file = await this.fileToBlob(param.file)
const res = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${param.file.name}`, file)
console.log(res)
this.fileList.push({ name: param.file.name, path: this.$getObjectName(res.url), url: this.$getObjectName(res.url)})
this.urls.push(this.$getObjectName(res.url))
this.$emit('setImageUrl', this.urls.length > 0 ? this.urls.join('|') : '')
loading.close()
},
handleBeforeUpload(file) {
//
if (this.checkFileSuffix(file.name)) {
// this.fileList = []
return true
} else {
this.$alert(`必须是 ${this.accept} 格式`)
return false
}
},
//
handlePictureCardPreview(file) {
var suffix = file.url.substring(file.url.lastIndexOf(".")+1)
suffix = suffix ? suffix.toLowerCase() : ''
if (suffix === 'doc' || suffix === 'docx' || suffix === 'pdf'){
window.open(this.OSSclientConfig.basePath + file.url,'_blank')
}else{
this.imageUrl = this.OSSclientConfig.basePath + file.url
// this.imgVisible = true
this.$refs[file.url].$viewer.show()
}
},
//
handleRemove(file, fileList) {
this.imageUrl = ''
this.fileList.splice(this.fileList.findIndex(f => f.url === file.url), 1)
this.urls.splice(this.fileList.findIndex(f => f === file.url), 1)
this.$emit('setFormItemData', { key: this.question.Id, val: this.urls.length > 0 ? this.urls.join('|') : '' })
},
}
}
</script>
<style lang="scss" scoped>
.disabled{
/deep/ .el-upload--picture-card {
display: none;
}
}
</style>

View File

@ -1,9 +1,9 @@
<template> <template>
<div v-loading="loading" class="img-container"> <div class="img-container">
<el-card class="box-card left"> <el-card v-loading="loading" class="box-card left">
<div v-if="otherInfo && otherInfo.IsReadingShowSubjectInfo" class="title"> <div v-if="isReadingShowSubjectInfo" class="title">
<span>{{ $t('trials:auditRecord:table:subject') }}{{ otherInfo.SubjectCode }} </span> <h4>{{ subjectCode }} </h4>
<span>({{ otherInfo.TaskBlindName }})</span> <h4>{{ taskBlindName }}</h4>
</div> </div>
<el-tabs v-model="activeName" @tab-click="handleClick"> <el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane :label="$t('trials:clinicaldara:title:currentTask')" name="first" class="left-content"> <el-tab-pane :label="$t('trials:clinicaldara:title:currentTask')" name="first" class="left-content">
@ -30,7 +30,14 @@
class="img-box" class="img-box"
@click="selected(item,i,j,true)" @click="selected(item,i,j,true)"
> >
{{ `${j+1}. ${item.FileName}` }} <div v-if="item.FileName.length < 15" class="img-text">
{{ `${j+1}. ${item.FileName}` }}
</div>
<el-tooltip v-else :content="item.FileName" placement="bottom">
<div class="img-text">
{{ `${j+1}. ${item.FileName}` }}
</div>
</el-tooltip>
</div> </div>
</div> </div>
@ -53,9 +60,15 @@
class="img-box" class="img-box"
@click="handleImageRead(task)" @click="handleImageRead(task)"
> >
{{ `${j+1}. ${task.TaskBlindName}` }} <div v-if="task.TaskBlindName.length < 15" class="img-text">
{{ `${j+1}. ${task.TaskBlindName}` }}
</div>
<el-tooltip v-else :content="task.TaskBlindName" placement="bottom">
<div class="img-text">
{{ `${j+1}. ${task.TaskBlindName}` }}
</div>
</el-tooltip>
</div> </div>
</div> </div>
</div> </div>
</el-tab-pane> </el-tab-pane>
@ -63,7 +76,7 @@
</el-card> </el-card>
<!-- 预览图像 --> <!-- 预览图像 -->
<el-card class="box-card right"> <el-card v-loading="loading" class="box-card right">
<div style="width:100%;height: 100%;"> <div style="width:100%;height: 100%;">
<Preview <Preview
v-if="previewImage.imgList.length > 0" v-if="previewImage.imgList.length > 0"
@ -93,6 +106,10 @@
:subject-id="subjectId" :subject-id="subjectId"
:visit-task-id="visitTaskId" :visit-task-id="visitTaskId"
:criterion-id="otherInfo.TrialCriterionId" :criterion-id="otherInfo.TrialCriterionId"
:subject-code="subjectCode"
:task-blind-name="taskBlindName"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
:ise-c-r-f-show-in-dicom-reading="iseCRFShowInDicomReading"
/> />
</el-card> </el-card>
</div> </div>
@ -127,9 +144,33 @@ export default {
type: String, type: String,
required: true required: true
}, },
taskBlindName: {
type: String,
required: true
},
readingCategory: { readingCategory: {
type: Number, type: Number,
required: true required: true
},
isReadingShowSubjectInfo: {
type: Boolean,
required: true
},
readingTool: {
type: String,
required: true
},
criterionType: {
type: String,
required: true
},
isReadingTaskViewInOrder: {
type: Number,
required: true
},
iseCRFShowInDicomReading: {
type: Boolean,
required: true
} }
}, },
data() { data() {
@ -156,7 +197,8 @@ export default {
currentTaskId: '', currentTaskId: '',
otherInfo: null, otherInfo: null,
isReadingShowPreviousResults: false, isReadingShowPreviousResults: false,
bp: [] bp: [],
openWindow: null
} }
}, },
computed: { computed: {
@ -170,6 +212,11 @@ export default {
this.getNoneDicomList(this.isReadingShowPreviousResults) this.getNoneDicomList(this.isReadingShowPreviousResults)
}, },
beforeDestroy() {
if (this.openWindow) {
this.openWindow.close()
}
},
methods: { methods: {
// Dicom // Dicom
getNoneDicomList() { getNoneDicomList() {
@ -250,18 +297,21 @@ export default {
}) })
}, },
handleImageRead(task) { handleImageRead(task) {
if (this.openWindow) {
this.openWindow.close()
}
this.currentTaskId = task.VisitTaskId this.currentTaskId = task.VisitTaskId
var criterionType = this.$router.currentRoute.query.criterionType var criterionType = this.criterionType
var readingTool = this.$router.currentRoute.query.readingTool var readingTool = this.readingTool
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder var isReadingTaskViewInOrder = this.isReadingTaskViewInOrder
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
var token = getToken() var token = getToken()
const path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}` const path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${this.trialId}&visitTaskId=${task.VisitTaskId}&subjectCode=${this.subjectCode}&subjectId=${this.subjectId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}`
// const routeData = this.$router.resolve({ // const routeData = this.$router.resolve({
// path: `/readingPage?subjectId=${this.subjectId}&trialId=${this.trialId}&visitTaskId=${task.VisitTaskId}&TokenKey=${token}` // path: `/readingPage?subjectId=${this.subjectId}&trialId=${this.trialId}&visitTaskId=${task.VisitTaskId}&TokenKey=${token}`
// }) // })
const routeData = this.$router.resolve({ path }) const routeData = this.$router.resolve({ path })
window.open(routeData.href, '_blank') this.openWindow = window.open(routeData.href, '_blank')
}, },
previewCD() { previewCD() {
var token = getToken() var token = getToken()
@ -295,7 +345,7 @@ export default {
flex: 1; flex: 1;
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 10px; padding-bottom: 10px;
display: flex; display: flex;
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 7px; width: 7px;
@ -326,13 +376,19 @@ export default {
flex-direction: column; flex-direction: column;
} }
.title{ .title{
height: 40px; // height: 40px;
line-height: 40px; // line-height: 40px;
border: 1ppx solid; border: 1ppx solid;
border: 1px solid #ebe7e7; border: 1px solid #ebe7e7;
padding-left: 10px; // padding-left: 10px;
background-color: #4e4e4e; background-color: #4e4e4e;
color: #ffffff; color: #ffffff;
h4{
padding: 5px 0px;
margin: 0;
text-align: center;
background-color: #4c4c4c;
}
} }
.left-content{ .left-content{
flex: 1; flex: 1;
@ -359,13 +415,19 @@ export default {
display: inline-block; display: inline-block;
box-sizing: border-box; box-sizing: border-box;
border-bottom: 2px solid #f3f3f3; border-bottom: 2px solid #f3f3f3;
width: 180px;
height: 50px;
line-height: 50px;
cursor: pointer; cursor: pointer;
// margin-bottom: 5px; // margin-bottom: 5px;
padding-left: 5px; padding-left: 5px;
} }
.img-text{
display: inline-block;
width: 200px;
height: 50px;
line-height: 50px;
overflow: hidden;
text-overflow: ellipsis; /* 用省略号表示溢出的文本 */
white-space: nowrap;
}
.img-box:nth-last-child(1){ .img-box:nth-last-child(1){
margin-bottom: 0px; margin-bottom: 0px;
} }

View File

@ -1,15 +1,40 @@
<template> <template>
<div ref="container" v-loading="loading" class="none-dicom-reading-container"> <div ref="container" v-loading="loading" class="none-dicom-reading-container">
<!-- 访视阅片 --> <!-- 访视阅片 -->
<VisitReview <div v-if="isShow && readingCategory && readingCategory=== 1" class="reading-wrapper">
v-if="isShow && readingCategory && readingCategory=== 1" <el-tabs v-model="activeName" :before-leave="beforeLeave">
:trial-id="trialId" <!-- 阅片 -->
:subject-id="subjectId" <el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
:subject-code="subjectCode" <VisitReview
:visit-task-id="visitTaskId" :trial-id="trialId"
:reading-category="readingCategory" :subject-id="subjectId"
:is-exists-clinical-data="isExistsClinicalData" :subject-code="subjectCode"
/> :visit-task-id="visitTaskId"
:task-blind-name="taskBlindName"
:reading-category="readingCategory"
:readingTool="readingTool"
:criterionType="criterionType"
:isReadingShowSubjectInfo="isReadingShowSubjectInfo"
:is-reading-task-view-in-order="isReadingTaskViewInOrder"
:iseCRFShowInDicomReading="iseCRFShowInDicomReading"
/>
</el-tab-pane>
<!-- 报告 -->
<el-tab-pane :label="$t('trials:reading:tabTitle:report')" name="report" v-if="!iseCRFShowInDicomReading">
<Report
v-if="tabs.includes('report')"
ref="reportPage"
:trialId="trialId"
:visit-task-id="visitTaskId"
:subject-id="subjectId"
:readingTool="readingTool"
:criterionType="criterionType"
:is-reading-task-view-in-order="isReadingTaskViewInOrder"
/>
</el-tab-pane>
</el-tabs>
</div>
<!-- 全局阅片 --> <!-- 全局阅片 -->
<GlobalReview <GlobalReview
v-else-if="isShow && readingCategory && readingCategory === 2" v-else-if="isShow && readingCategory && readingCategory === 2"
@ -83,6 +108,7 @@ import { getNextTask, readClinicalData } from '@/api/trials'
import store from '@/store' import store from '@/store'
import { changeURLStatic } from '@/utils/history.js' import { changeURLStatic } from '@/utils/history.js'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
import Report from './components/Report'
import VisitReview from './components/VisitReview' import VisitReview from './components/VisitReview'
import GlobalReview from '@/views/trials/trials-panel/reading/global-review' import GlobalReview from '@/views/trials/trials-panel/reading/global-review'
import AdReview from '@/views/trials/trials-panel/reading/ad-review' import AdReview from '@/views/trials/trials-panel/reading/ad-review'
@ -93,6 +119,7 @@ export default {
name: 'NoneDicomReading', name: 'NoneDicomReading',
components: { components: {
VisitReview, VisitReview,
Report,
AdReview, AdReview,
GlobalReview, GlobalReview,
OncologyReview, OncologyReview,
@ -113,12 +140,15 @@ export default {
isExistsClinicalData: false, isExistsClinicalData: false,
isNeedReadClinicalData: false, isNeedReadClinicalData: false,
isReadClinicalData: false, isReadClinicalData: false,
iseCRFShowInDicomReading: false,
criterionType: null, criterionType: null,
readingTool: null, readingTool: null,
isNewSubject: null, isNewSubject: null,
dialogVisible: false, dialogVisible: false,
dialogH: 0, dialogH: 0,
isShow: false isShow: false,
activeName:'',
tabs: []
} }
}, },
mounted() { mounted() {
@ -169,6 +199,10 @@ export default {
// var token = getToken() // var token = getToken()
// window.location.href = `/noneDicomReading?trialId=${this.trialId}&subjectCode=${res.Result.SubjectCode}&subjectId=${res.Result.SubjectId}&isReadingShowPreviousResults=${this.isReadingShowPreviousResults}&isReadingShowSubjectInfo=${this.isReadingShowSubjectInfo}&criterionType=${this.criterionType}&readingTool=${this.readingTool}&isNewSubject=1&isReadingTaskViewInOrder=${res.Result.IsReadingTaskViewInOrder}&TokenKey=${token}` // window.location.href = `/noneDicomReading?trialId=${this.trialId}&subjectCode=${res.Result.SubjectCode}&subjectId=${res.Result.SubjectId}&isReadingShowPreviousResults=${this.isReadingShowPreviousResults}&isReadingShowSubjectInfo=${this.isReadingShowSubjectInfo}&criterionType=${this.criterionType}&readingTool=${this.readingTool}&isNewSubject=1&isReadingTaskViewInOrder=${res.Result.IsReadingTaskViewInOrder}&TokenKey=${token}`
// } // }
if (res.Result.ReadingCategory === 1) {
this.activeName = 'read'
this.tabs = [this.activeName]
}
this.subjectId = res.Result.SubjectId this.subjectId = res.Result.SubjectId
this.visitTaskId = res.Result.VisitTaskId this.visitTaskId = res.Result.VisitTaskId
this.subjectCode = res.Result.SubjectCode this.subjectCode = res.Result.SubjectCode
@ -176,7 +210,8 @@ export default {
this.isExistsClinicalData = res.Result.IsExistsClinicalData this.isExistsClinicalData = res.Result.IsExistsClinicalData
this.isReadClinicalData = res.Result.IsReadClinicalData this.isReadClinicalData = res.Result.IsReadClinicalData
this.isNeedReadClinicalData = res.Result.IsNeedReadClinicalData this.isNeedReadClinicalData = res.Result.IsNeedReadClinicalData
this.iseCRFShowInDicomReading = res.Result.IseCRFShowInDicomReading
this.isReadingTaskViewInOrder = res.Result.IsReadingTaskViewInOrder
this.isReadingShowSubjectInfo = res.Result.IsReadingShowSubjectInfo this.isReadingShowSubjectInfo = res.Result.IsReadingShowSubjectInfo
this.isReadingShowPreviousResults = res.Result.IsReadingShowPreviousResults this.isReadingShowPreviousResults = res.Result.IsReadingShowPreviousResults
this.digitPlaces = res.Result.DigitPlaces this.digitPlaces = res.Result.DigitPlaces
@ -201,7 +236,21 @@ export default {
} catch (e) { } catch (e) {
this.loading = false this.loading = false
} }
} },
beforeLeave(activeName, oldActiveName) {
if (!this.tabs.includes(activeName)) {
this.tabs.push(activeName)
}
if (oldActiveName === 'read') {
this.$nextTick(() => {
if (this.$refs.reportPage) {
// DicomEvent.$emit('getReportInfo', true)
this.$refs.reportPage.setScrollTop(1)
}
})
}
return Promise.resolve(true)
},
} }
} }
</script> </script>
@ -221,7 +270,38 @@ export default {
padding: 10px; padding: 10px;
} }
} }
.reading-wrapper{
width: 100%;
height: 100%;
padding: 0 10px;
box-sizing: border-box;
/deep/.el-tabs{
box-sizing: border-box;
height: 100%;
display: flex;
flex-direction: column;
.el-tabs__item{
// color: #fff;
}
.el-tabs__header{
height: 50px;
margin:0px;
box-sizing: border-box;
}
.el-tabs__content{
flex: 1;
margin:0px;
box-sizing: border-box;
}
.el-tabs__item{
// color: #fff;
}
.el-tab-pane{
height: 100%;
}
}
}
/deep/ .dialog-container{ /deep/ .dialog-container{
margin-top: 50px !important; margin-top: 50px !important;

View File

@ -18,7 +18,7 @@
v-if=" v-if="
(isReadingTaskViewInOrder === 1 || (isReadingTaskViewInOrder === 1 ||
isReadingTaskViewInOrder === 2) && isReadingTaskViewInOrder === 2) &&
TrialReadingCriterionId === item.TrialReadingCriterionId TrialReadingCriterionId === item.TrialReadingCriterionId
" "
> >
<div slot="search-container"> <div slot="search-container">
@ -41,7 +41,7 @@
icon="el-icon-search" icon="el-icon-search"
@click="handleSearch" @click="handleSearch"
> >
{{ $t("common:button:search") }} {{ $t('common:button:search') }}
</el-button> </el-button>
<!-- 重置 --> <!-- 重置 -->
<el-button <el-button
@ -49,7 +49,7 @@
icon="el-icon-refresh-left" icon="el-icon-refresh-left"
@click="handleReset" @click="handleReset"
> >
{{ $t("common:button:reset") }} {{ $t('common:button:reset') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -75,10 +75,11 @@
scope.row.UrgentColor === 1 scope.row.UrgentColor === 1
? 'danger' ? 'danger'
: scope.row.UrgentColor === 2 : scope.row.UrgentColor === 2
? 'warning' ? 'warning'
: 'primary' : 'primary'
" "
>{{ $fd("YesOrNo", scope.row.IsUrgent) }}</el-tag> >{{ $fd('YesOrNo', scope.row.IsUrgent) }}</el-tag
>
</template> </template>
</el-table-column> </el-table-column>
<!-- 受试者编号 --> <!-- 受试者编号 -->
@ -113,10 +114,11 @@
scope.row.UrgentColor === 1 scope.row.UrgentColor === 1
? '#F56C6C' ? '#F56C6C'
: scope.row.UrgentColor === 2 : scope.row.UrgentColor === 2
? '#E6A23C' ? '#E6A23C'
: '#409EFF', : '#409EFF',
}" }"
>{{ scope.row.UrgentCount }}</span> >{{ scope.row.UrgentCount }}</span
>
</template> </template>
</el-table-column> </el-table-column>
<!-- 建议完成时间 --> <!-- 建议完成时间 -->
@ -130,7 +132,7 @@
sortable="custom" sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
{{ scope.row.SuggesteFinishedTime.split(":")[0] + ":00:00" }} {{ scope.row.SuggesteFinishedTime.split(':')[0] + ':00:00' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -146,8 +148,8 @@
:title=" :title="
scope.row.ExistReadingApply scope.row.ExistReadingApply
? $t( ? $t(
'trials:pendingReadingTasks:button:ExistReadingApply' 'trials:pendingReadingTasks:button:ExistReadingApply'
) )
: $t('trials:pendingReadingTasks:button:review') : $t('trials:pendingReadingTasks:button:review')
" "
icon="el-icon-edit-outline" icon="el-icon-edit-outline"
@ -156,9 +158,9 @@
<!-- 上传 --> <!-- 上传 -->
<el-button <el-button
v-if=" v-if="
item.CriterionType === 0 && item.ImageUploadEnum > 0 &&
item.ImageUploadEnum > 0 && item.IsReadingTaskViewInOrder > 0 &&
item.IsReadingTaskViewInOrder > 0 !scope.row.IsSubjectJudge
" "
v-hasPermi="['role:ir']" v-hasPermi="['role:ir']"
circle circle
@ -169,9 +171,9 @@
<!-- 下载 --> <!-- 下载 -->
<el-button <el-button
v-if=" v-if="
item.CriterionType === 0 && item.ImageDownloadEnum > 0 &&
item.ImageDownloadEnum === 1 && item.IsReadingTaskViewInOrder > 0 &&
item.IsReadingTaskViewInOrder > 0 !scope.row.IsSubjectJudge
" "
v-hasPermi="['role:ir']" v-hasPermi="['role:ir']"
circle circle
@ -194,7 +196,7 @@
<div <div
v-else-if=" v-else-if="
isReadingTaskViewInOrder === 0 && isReadingTaskViewInOrder === 0 &&
TrialReadingCriterionId === item.TrialReadingCriterionId TrialReadingCriterionId === item.TrialReadingCriterionId
" "
> >
<el-descriptions :column="2" border style="width: 800px"> <el-descriptions :column="2" border style="width: 800px">
@ -248,48 +250,65 @@
:disabled=" :disabled="
randomReadInfo.UnReadTaskCount + randomReadInfo.UnReadTaskCount +
randomReadInfo.UnReadJudgeTaskCount === randomReadInfo.UnReadJudgeTaskCount ===
0 0
" "
@click="handleOutOfOrderReading" @click="handleOutOfOrderReading"
> >
{{ $t("trials:pendingReadingTasks:button:beginRandomReview") }} {{ $t('trials:pendingReadingTasks:button:beginRandomReview') }}
</el-button> </el-button>
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
</div> </div>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<upload-image <!-- <upload-image
v-if="uploadImageVisible" v-if="uploadImageVisible"
:visible.sync="uploadImageVisible" :visible.sync="uploadImageVisible"
:subject-id="uploadSubjectId" :subject-id="uploadSubjectId"
:criterion="uploadTrialCriterion" :criterion="uploadTrialCriterion"
:status="uploadStatus" :status="uploadStatus"
@getList="getList" @getList="getList"
/> -->
<upload-dicom-and-nonedicom
v-if="uploadImageVisible"
:SubjectId="uploadSubjectId"
:SubjectCode="uploadSubjectCode"
:Criterion="uploadTrialCriterion"
:visible.sync="uploadImageVisible"
/>
<download-dicom-and-nonedicom
v-if="downloadImageVisible"
:SubjectId="uploadSubjectId"
:SubjectCode="uploadSubjectCode"
:Criterion="uploadTrialCriterion"
:visible.sync="downloadImageVisible"
/> />
</BaseContainer> </BaseContainer>
</template> </template>
<script> <script>
import { import { getIRUnReadSubjectTaskList, verifyReadingRestTime } from '@/api/trials'
getIRUnReadSubjectTaskList,
verifyReadingRestTime
} from '@/api/trials'
import { getTrialCriterionList } from '@/api/trials/reading' import { getTrialCriterionList } from '@/api/trials/reading'
import { clearSkipReadingCache } from '@/api/reading' import { clearSkipReadingCache } from '@/api/reading'
import BaseContainer from '@/components/BaseContainer' import BaseContainer from '@/components/BaseContainer'
import uploadImage from '@/components/uploadImage' import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
const searchDataDefault = () => { const searchDataDefault = () => {
return { return {
SubjectCode: '', SubjectCode: '',
PageIndex: 1, PageIndex: 1,
PageSize: 20 PageSize: 20,
} }
} }
export default { export default {
name: 'ReadingTaskList', name: 'ReadingTaskList',
components: { BaseContainer, Pagination, 'upload-image': uploadImage }, components: {
BaseContainer,
Pagination,
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
},
data() { data() {
return { return {
searchData: searchDataDefault(), searchData: searchDataDefault(),
@ -308,10 +327,12 @@ export default {
openWindow: null, openWindow: null,
// //
downloadImageVisible: false,
uploadImageVisible: false, uploadImageVisible: false,
uploadSubjectId: null, uploadSubjectId: null,
uploadSubjectCode: null,
uploadTrialCriterion: {}, uploadTrialCriterion: {},
uploadStatus: 'upload' uploadStatus: 'upload',
} }
}, },
watch: { watch: {
@ -319,7 +340,7 @@ export default {
if (v) { if (v) {
this.getList() this.getList()
} }
} },
}, },
mounted() { mounted() {
window.addEventListener('message', this.receiveMsg) window.addEventListener('message', this.receiveMsg)
@ -335,10 +356,11 @@ export default {
methods: { methods: {
// //
openUploadImage(item, trialCriterion, status) { openUploadImage(item, trialCriterion, status) {
this.uploadSubjectCode = item.SubjectCode
this.uploadSubjectId = item.SubjectId this.uploadSubjectId = item.SubjectId
this.uploadTrialCriterion = trialCriterion this.uploadTrialCriterion = trialCriterion
this.uploadStatus = status this.uploadStatus = status
this.uploadImageVisible = true this[`${status}ImageVisible`] = true
}, },
async getTrialCriterionList() { async getTrialCriterionList() {
try { try {
@ -360,8 +382,7 @@ export default {
this.isRender = false this.isRender = false
const res = await getIRUnReadSubjectTaskList(this.searchData) const res = await getIRUnReadSubjectTaskList(this.searchData)
if (res.IsSuccess) { if (res.IsSuccess) {
this.isReadingTaskViewInOrder = this.isReadingTaskViewInOrder = res.OtherInfo.IsReadingTaskViewInOrder
res.OtherInfo.IsReadingTaskViewInOrder
this.readingTool = res.OtherInfo.ReadingTool this.readingTool = res.OtherInfo.ReadingTool
this.criterionType = res.OtherInfo.CriterionType this.criterionType = res.OtherInfo.CriterionType
if (res.OtherInfo.IsReadingTaskViewInOrder) { if (res.OtherInfo.IsReadingTaskViewInOrder) {
@ -395,7 +416,10 @@ export default {
await clearSkipReadingCache() await clearSkipReadingCache()
await verifyReadingRestTime() await verifyReadingRestTime()
this.loading = false this.loading = false
window.localStorage.setItem('TrialReadingCriterionId', this.TrialReadingCriterionId) window.localStorage.setItem(
'TrialReadingCriterionId',
this.TrialReadingCriterionId
)
var token = getToken() var token = getToken()
var path = '' var path = ''
if (this.readingTool === 0) { if (this.readingTool === 0) {
@ -420,7 +444,10 @@ export default {
await clearSkipReadingCache() await clearSkipReadingCache()
await verifyReadingRestTime() await verifyReadingRestTime()
this.loading = false this.loading = false
window.localStorage.setItem('TrialReadingCriterionId', this.TrialReadingCriterionId) window.localStorage.setItem(
'TrialReadingCriterionId',
this.TrialReadingCriterionId
)
var token = getToken() var token = getToken()
var path = '' var path = ''
if (this.readingTool === 0) { if (this.readingTool === 0) {
@ -450,7 +477,7 @@ export default {
this.searchData.SortField = column.prop this.searchData.SortField = column.prop
this.searchData.PageIndex = 1 this.searchData.PageIndex = 1
this.getList() this.getList()
} },
} },
} }
</script> </script>

View File

@ -381,7 +381,7 @@
/> />
<!-- 退回 --> <!-- 退回 -->
<el-button <el-button
:disabled="scope.row.ReadingTaskState === 2 || scope.row.ReadingCategory !== 1 || scope.row.TaskState !== 0" :disabled="scope.row.ReadingTaskState === 2 || scope.row.ReadingCategory !== 1 || scope.row.TaskState !== 0 || scope.row.IsManualGeneration"
v-if="hasPermi(['trials:trials-panel:readingTracking:edit'])" v-if="hasPermi(['trials:trials-panel:readingTracking:edit'])"
icon="el-icon-back" icon="el-icon-back"
circle circle

View File

@ -84,7 +84,7 @@
</el-button> </el-button>
<!-- 预览 --> <!-- 预览 -->
<el-button <el-button
:disabled="otherInfo.QuestionCount===0" :disabled="!otherInfo.IsHaveQuestion"
type="primary" type="primary"
icon="el-icon-view" icon="el-icon-view"
@click="preview.visible = true" @click="preview.visible = true"
@ -118,7 +118,7 @@
</el-button> </el-button>
<el-button <el-button
v-if="!otherInfo.IsConfirmMedicineQuestion && hasPermi(['trials:trials-panel:setting:medical-audit:confirm'])" v-if="!otherInfo.IsConfirmMedicineQuestion && hasPermi(['trials:trials-panel:setting:medical-audit:confirm'])"
:disabled="otherInfo.QuestionCount===0" :disabled="!otherInfo.IsHaveQuestion"
type="danger" type="danger"
icon="el-icon-circle-check" icon="el-icon-circle-check"
@click="handleConfirm" @click="handleConfirm"
@ -443,7 +443,7 @@ export default {
this.list = res.Result.CurrentPageData this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount this.total = res.Result.TotalCount
this.isShow = true this.isShow = true
this.otherInfo.IsConfirmMedicineQuestion = false // this.otherInfo.IsConfirmMedicineQuestion = false
this.otherInfo = res.OtherInfo this.otherInfo = res.OtherInfo
}).catch(() => { this.loading = false }) }).catch(() => { this.loading = false })
}, },
@ -503,7 +503,7 @@ export default {
// //
handleConfirm() { handleConfirm() {
if (this.otherInfo.QuestionCount === 0) { if (!this.otherInfo.IsHaveQuestion) {
// '' // ''
this.$alert(this.$t('trials:medicalFeedbackCfg:message:msg1')) this.$alert(this.$t('trials:medicalFeedbackCfg:message:msg1'))
return return

View File

@ -103,6 +103,7 @@
<el-button <el-button
circle circle
icon="el-icon-delete" icon="el-icon-delete"
:disabled="scope.row.IsJoin"
:title="$t('trials:externalStaff:button:delete')" :title="$t('trials:externalStaff:button:delete')"
@click="deleteTrialExternalUser(scope.row)" @click="deleteTrialExternalUser(scope.row)"
/> />

View File

@ -41,7 +41,7 @@
type="primary" type="primary"
:disabled="OtherInfo.IsSign" :disabled="OtherInfo.IsSign"
@click="apply(item.ReadingQuestionTrialId, index)" @click="apply(item.ReadingQuestionTrialId, index)"
>{{ $t("common:button:save") }}</el-button >{{ $t('common:button:save') }}</el-button
> >
<el-button <el-button
v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']" v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']"
@ -50,7 +50,7 @@
type="primary" type="primary"
:disabled="OtherInfo.IsSign" :disabled="OtherInfo.IsSign"
@click="reset(item.ReadingQuestionTrialId, index)" @click="reset(item.ReadingQuestionTrialId, index)"
>{{ $t("common:button:reset") }}</el-button >{{ $t('common:button:reset') }}</el-button
> >
<!-- 产生裁判阅片的条件 --> <!-- 产生裁判阅片的条件 -->
<el-form-item <el-form-item
@ -71,13 +71,16 @@
:label="item.value" :label="item.value"
v-if=" v-if="
(JudgyInfo.ArbitrationRule === 1 && (JudgyInfo.ArbitrationRule === 1 &&
QuestionList[index].Type === 'number' && (QuestionList[index].Type === 'number' ||
QuestionList[index].Type === 'calculation') &&
item.value !== 2 && item.value !== 2 &&
item.value !== 3) || item.value !== 3) ||
(JudgyInfo.ArbitrationRule === 2 && (JudgyInfo.ArbitrationRule === 2 &&
QuestionList[index].Type === 'number' && (QuestionList[index].Type === 'number' ||
QuestionList[index].Type === 'calculation') &&
item.value === 1) || item.value === 1) ||
(QuestionList[index].Type !== 'number' && ((QuestionList[index].Type === 'number' ||
QuestionList[index].Type === 'calculation') &&
item.value !== 4 && item.value !== 4 &&
item.value !== 5) item.value !== 5)
" "
@ -98,7 +101,7 @@
type="primary" type="primary"
:disabled="OtherInfo.IsSign" :disabled="OtherInfo.IsSign"
@click="addGroup(index, null)" @click="addGroup(index, null)"
>{{ $t("trials:adRules:button:addRule") }}</el-button >{{ $t('trials:adRules:button:addRule') }}</el-button
> >
</div> </div>
<el-table <el-table
@ -211,14 +214,14 @@
</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 <el-tag
@ -235,7 +238,7 @@
).label ).label
) )
.toString() .toString()
.replaceAll(",", "|") .replaceAll(',', '|')
}}</el-tag }}</el-tag
> >
<el-button <el-button
@ -245,7 +248,7 @@
@click="addGroup2(index)" @click="addGroup2(index)"
> >
<!-- 添加分组 --> <!-- 添加分组 -->
{{ $t("trials:adRules:title:addGroup") }} {{ $t('trials:adRules:title:addGroup') }}
</el-button> </el-button>
</div> </div>
</div> </div>
@ -253,7 +256,7 @@
v-if="QuestionList[index].QuestionGenre !== 3" v-if="QuestionList[index].QuestionGenre !== 3"
style="margin-top: 20px" 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" v-for="itemA of QuestionList[index].AnswerGroup2List"
:key="itemA" :key="itemA"
@ -261,7 +264,7 @@
style="margin-right: 10px" style="margin-right: 10px"
@close=" @close="
() => { () => {
return tagClose2(index, indexA); return tagClose2(index, indexA)
} }
" "
>{{ itemA }}</el-tag >{{ itemA }}</el-tag
@ -272,7 +275,7 @@
style="margin-top: 20px" 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" v-for="itemA of QuestionList[index].AnswerGroup2List"
:key="itemA" :key="itemA"
@ -280,17 +283,17 @@
style="margin-right: 10px" style="margin-right: 10px"
@close=" @close="
() => { () => {
return tagClose2(index, indexA); return tagClose2(index, indexA)
} }
" "
> >
{{ {{
itemA itemA
.split("|") .split('|')
.map((v) => .map((v) =>
$fd(QuestionList[index].DictionaryCode, parseInt(v)) $fd(QuestionList[index].DictionaryCode, parseInt(v))
) )
.join("|") .join('|')
}} }}
</el-tag> </el-tag>
</div> </div>
@ -340,11 +343,16 @@
" "
prop="JudgeDifferenceValue" prop="JudgeDifferenceValue"
> >
<el-input <div style="display: flex">
v-model="QuestionList[index].JudgeDifferenceValue" <el-input
clearable v-model="QuestionList[index].JudgeDifferenceValue"
:disabled="OtherInfo.IsSign" clearable
></el-input> :disabled="OtherInfo.IsSign"
></el-input>
<span style="margin-left: 10px">{{
$fd('ValueUnit', QuestionList[index].Unit)
}}</span>
</div>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
@ -457,12 +465,12 @@
size="small" size="small"
type="primary" type="primary"
@click=" @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']" v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']"
@ -471,7 +479,7 @@
type="primary" type="primary"
@click="save" @click="save"
> >
{{ $t("common:button:save") }} {{ $t('common:button:save') }}
</el-button> </el-button>
</div> </div>
</el-dialog> </el-dialog>
@ -482,13 +490,13 @@ import {
getTrialConfirmCriterionList, getTrialConfirmCriterionList,
getTrialCriterionJudgeQuestionList, getTrialCriterionJudgeQuestionList,
setTrialCriterionJudgeQuestionAnswerGroup, setTrialCriterionJudgeQuestionAnswerGroup,
} from "@/api/trials/reading"; } from '@/api/trials/reading'
import { setTrialJudgyInfo, getTrialJudgyInfo } from "@/api/trials/setting"; import { setTrialJudgyInfo, getTrialJudgyInfo } from '@/api/trials/setting'
export default { export default {
props: { props: {
trialReadingCriterionId: { trialReadingCriterionId: {
type: String, type: String,
default: "", default: '',
}, },
}, },
data() { data() {
@ -512,23 +520,23 @@ export default {
{ {
required: true, required: true,
message: this.$t( message: this.$t(
"trials:trials-list:setitng:JudgeDifferenceTypeRequired" 'trials:trials-list:setitng:JudgeDifferenceTypeRequired'
), ),
trigger: "blur", trigger: 'blur',
}, },
], ],
JudgeDifferenceValue: [ JudgeDifferenceValue: [
{ {
required: true, required: true,
message: this.$t( message: this.$t(
"trials:trials-list:setitng:JudgeDifferenceValueRequired" 'trials:trials-list:setitng:JudgeDifferenceValueRequired'
), ),
trigger: "blur", trigger: 'blur',
}, },
{ {
pattern: /^[0-9]+(.[0-9]{2})?$/, pattern: /^[0-9]+(.[0-9]{2})?$/,
message: this.$t("trials:trials-list:setitng:JudgeDifferenceValue"), message: this.$t('trials:trials-list:setitng:JudgeDifferenceValue'),
trigger: "blur", trigger: 'blur',
}, },
{ {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
@ -536,115 +544,115 @@ export default {
callback( callback(
new Error( new Error(
this.$t( this.$t(
"trials:trials-list:setitng:JudgeDifferenceValueMin" 'trials:trials-list:setitng:JudgeDifferenceValueMin'
) )
) )
); )
} else { } else {
callback(); callback()
} }
}, },
trigger: "blur", trigger: 'blur',
}, },
], ],
}, },
}; }
}, },
watch: { watch: {
TrialReadingCriterionId(v) { TrialReadingCriterionId(v) {
if (v === null) return; if (v === null) return
this.loading = true; this.loading = true
getTrialCriterionJudgeQuestionList({ getTrialCriterionJudgeQuestionList({
TrialId: this.$route.query.trialId, TrialId: this.$route.query.trialId,
// ReadingQuestionCriterionTrialId: v, // ReadingQuestionCriterionTrialId: v,
TrialReadingCriterionId: this.trialReadingCriterionId, TrialReadingCriterionId: this.trialReadingCriterionId,
}) })
.then((res) => { .then((res) => {
this.loading = false; this.loading = false
this.QuestionList = res.Result; this.QuestionList = res.Result
this.OtherInfo = res.OtherInfo; this.OtherInfo = res.OtherInfo
this.activeNames = this.QuestionList.map( this.activeNames = this.QuestionList.map(
(v) => v.ReadingQuestionTrialId (v) => v.ReadingQuestionTrialId
); )
this.QuestionList.forEach((v) => { this.QuestionList.forEach((v) => {
this.$set(v, "grouping", []); this.$set(v, 'grouping', [])
this.$set(v, "groupingA", []); this.$set(v, 'groupingA', [])
this.$set(v, "groupingB", []); this.$set(v, 'groupingB', [])
this.$set( this.$set(
v, v,
"AnswerGroupList", 'AnswerGroupList',
Object.assign([], v.AnswerCombination) Object.assign([], v.AnswerCombination)
); )
this.$set(v, "AnswerGroup2List", Object.assign([], v.AnswerGroup)); this.$set(v, 'AnswerGroup2List', Object.assign([], v.AnswerGroup))
}); })
}) })
.catch(() => { .catch(() => {
this.btnLoading = false; this.btnLoading = false
this.loading = false; this.loading = false
}); })
}, },
}, },
mounted() { mounted() {
this.getList(); this.getList()
this.getTrialJudgyInfo(); this.getTrialJudgyInfo()
}, },
methods: { methods: {
// //
changeArbitrationRule(value) { changeArbitrationRule(value) {
if (value !== 1) { if (value !== 1) {
this.QuestionList.forEach((item) => { this.QuestionList.forEach((item) => {
item.JudgeDifferenceValue = 0; item.JudgeDifferenceValue = 0
item.JudgeDifferenceType = 0; item.JudgeDifferenceType = 0
}); })
} }
}, },
JudgeTypeChange(value, index) { JudgeTypeChange(value, index) {
this.$nextTick(() => { this.$nextTick(() => {
if (value === 4 || value === 5) { if (value === 4 || value === 5) {
if (this.$refs["JudgeDifferenceValue" + value + index][0]) { if (this.$refs['JudgeDifferenceValue' + value + index][0]) {
this.$refs["JudgeDifferenceValue" + value + index][0].resetFields(); this.$refs['JudgeDifferenceValue' + value + index][0].resetFields()
// this.QuestionList[index].JudgeDifferenceValue = 0; // this.QuestionList[index].JudgeDifferenceValue = 0;
} }
} }
}); })
}, },
saveAllSync() { saveAllSync() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var arr = []; var arr = []
this.QuestionList.forEach((v, i) => { this.QuestionList.forEach((v, i) => {
arr.push(this.applySync(v.ReadingQuestionTrialId, i)); arr.push(this.applySync(v.ReadingQuestionTrialId, i))
}); })
Promise.all(arr) Promise.all(arr)
.then((res) => { .then((res) => {
console.log(res); console.log(res)
resolve(true); resolve(true)
}) })
.catch((res) => { .catch((res) => {
console.log("进入catch"); console.log('进入catch')
resolve(false); resolve(false)
}); })
}); })
}, },
applySync(ReadingQuestionTrialId, index) { applySync(ReadingQuestionTrialId, index) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
console.log(this.QuestionList[index].JudgeType); console.log(this.QuestionList[index].JudgeType)
if (this.QuestionList[index].JudgeType === 0) { if (this.QuestionList[index].JudgeType === 0) {
reject(false); reject(false)
return; return
} }
if ( if (
this.QuestionList[index].JudgeType === 2 && this.QuestionList[index].JudgeType === 2 &&
this.QuestionList[index].AnswerGroup2List.length === 0 this.QuestionList[index].AnswerGroup2List.length === 0
) { ) {
reject(false); reject(false)
return; return
} }
if ( if (
this.QuestionList[index].JudgeType === 3 && this.QuestionList[index].JudgeType === 3 &&
this.QuestionList[index].AnswerGroupList.length === 0 this.QuestionList[index].AnswerGroupList.length === 0
) { ) {
reject(false); reject(false)
return; return
} }
if ( if (
this.QuestionList[index].JudgeType === 4 || this.QuestionList[index].JudgeType === 4 ||
@ -652,17 +660,17 @@ export default {
) { ) {
try { try {
let validate = await this.$refs[ let validate = await this.$refs[
"JudgeDifferenceValue" + 'JudgeDifferenceValue' +
this.QuestionList[index].JudgeType + this.QuestionList[index].JudgeType +
index index
][0].validate(); ][0].validate()
if (!validate) return reject(false); if (!validate) return reject(false)
} catch (err) { } catch (err) {
return reject(false); return reject(false)
} }
} }
this.btnLoading = true; this.btnLoading = true
this.loading = true; this.loading = true
setTrialCriterionJudgeQuestionAnswerGroup({ setTrialCriterionJudgeQuestionAnswerGroup({
ReadingQuestionTrialId: ReadingQuestionTrialId, ReadingQuestionTrialId: ReadingQuestionTrialId,
AnswerGroup: this.QuestionList[index].AnswerGroup2List, AnswerGroup: this.QuestionList[index].AnswerGroup2List,
@ -676,126 +684,126 @@ export default {
), ),
}) })
.then((res) => { .then((res) => {
resolve(); resolve()
this.btnLoading = false; this.btnLoading = false
this.loading = false; this.loading = false
}) })
.catch(() => { .catch(() => {
reject(false); reject(false)
this.btnLoading = false; this.btnLoading = false
this.loading = false; this.loading = false
}); })
}); })
}, },
setTrialJudgyInfo() { setTrialJudgyInfo() {
this.loading = true; this.loading = true
setTrialJudgyInfo({ setTrialJudgyInfo({
TrialId: this.$route.query.trialId, TrialId: this.$route.query.trialId,
ArbitrationRule: this.JudgyInfo.ArbitrationRule, ArbitrationRule: this.JudgyInfo.ArbitrationRule,
TrialReadingCriterionId: this.trialReadingCriterionId, TrialReadingCriterionId: this.trialReadingCriterionId,
}) })
.then((res) => { .then((res) => {
this.loading = false; this.loading = false
this.$message.success(this.$t("common:message:savedSuccessfully")); // '' this.$message.success(this.$t('common:message:savedSuccessfully')) // ''
}) })
.catch(() => { .catch(() => {
this.loading = false; this.loading = false
}); })
}, },
getTrialJudgyInfo() { getTrialJudgyInfo() {
this.loading = true; this.loading = true
getTrialJudgyInfo({ getTrialJudgyInfo({
TrialId: this.$route.query.trialId, TrialId: this.$route.query.trialId,
TrialReadingCriterionId: this.trialReadingCriterionId, TrialReadingCriterionId: this.trialReadingCriterionId,
}) })
.then((res) => { .then((res) => {
this.JudgyInfo = res.Result; this.JudgyInfo = res.Result
this.loading = false; this.loading = false
}) })
.catch((v) => { .catch((v) => {
this.loading = false; this.loading = false
}); })
}, },
tagClose2(index, indexA) { tagClose2(index, indexA) {
// '' // ''
this.$confirm(this.$t("trials:adRules:message:msg1")).then(() => { this.$confirm(this.$t('trials:adRules:message:msg1')).then(() => {
this.QuestionList[index].AnswerGroup2List.splice(indexA, 1); this.QuestionList[index].AnswerGroup2List.splice(indexA, 1)
}); })
}, },
tagClose(index, indexA) { tagClose(index, indexA) {
// '' // ''
this.$confirm(this.$t("trials:adRules:message:msg1")).then(() => { this.$confirm(this.$t('trials:adRules:message:msg1')).then(() => {
this.QuestionList[index].AnswerGroupList.splice(indexA, 1); this.QuestionList[index].AnswerGroupList.splice(indexA, 1)
}); })
}, },
save() { save() {
var index = this.selectIndex; var index = this.selectIndex
var indexA = this.indexA; var indexA = this.indexA
if (this.QuestionList[index].groupingA.length === 0) { if (this.QuestionList[index].groupingA.length === 0) {
this.$alert(this.$t("trials:adRules:message:msg2")); // 'A' this.$alert(this.$t('trials:adRules:message:msg2')) // 'A'
return; return
} }
if (this.QuestionList[index].groupingB.length === 0) { if (this.QuestionList[index].groupingB.length === 0) {
this.$alert(this.$t("trials:adRules:message:msg3")); // 'B' this.$alert(this.$t('trials:adRules:message:msg3')) // 'B'
return; return
} }
if (this.type === "add") { if (this.type === 'add') {
this.QuestionList[index].AnswerGroupList.push({ this.QuestionList[index].AnswerGroupList.push({
AnswerGroupA: this.QuestionList[index].groupingA, AnswerGroupA: this.QuestionList[index].groupingA,
AnswerGroupB: this.QuestionList[index].groupingB, AnswerGroupB: this.QuestionList[index].groupingB,
}); })
} else { } else {
this.$set( this.$set(
this.QuestionList[index].AnswerGroupList[indexA], this.QuestionList[index].AnswerGroupList[indexA],
"AnswerGroupA", 'AnswerGroupA',
this.QuestionList[index].groupingA this.QuestionList[index].groupingA
); )
this.$set( this.$set(
this.QuestionList[index].AnswerGroupList[indexA], this.QuestionList[index].AnswerGroupList[indexA],
"AnswerGroupB", 'AnswerGroupB',
this.QuestionList[index].groupingB this.QuestionList[index].groupingB
); )
} }
this.$set(this.QuestionList[index], "groupingA", []); this.$set(this.QuestionList[index], 'groupingA', [])
this.$set(this.QuestionList[index], "groupingB", []); this.$set(this.QuestionList[index], 'groupingB', [])
this.$message.success(this.$t("trials:adRules:message:msg4")); // '' this.$message.success(this.$t('trials:adRules:message:msg4')) // ''
this.QuestionVisible = false; this.QuestionVisible = false
}, },
addGroup2(index) { addGroup2(index) {
if (this.QuestionList[index].grouping.length === 0) { if (this.QuestionList[index].grouping.length === 0) {
this.$alert(this.$t("trials:adRules:message:msg5")); // ',' this.$alert(this.$t('trials:adRules:message:msg5')) // ','
return; return
} }
var grouping = this.QuestionList[index].grouping var grouping = this.QuestionList[index].grouping
.toString() .toString()
.replaceAll(",", "|"); .replaceAll(',', '|')
this.QuestionList[index].AnswerGroup2List.push(`|${grouping}|`); this.QuestionList[index].AnswerGroup2List.push(`|${grouping}|`)
this.$set(this.QuestionList[index], "grouping", []); this.$set(this.QuestionList[index], 'grouping', [])
}, },
addGroup(index, indexA) { addGroup(index, indexA) {
this.selectIndex = index; this.selectIndex = index
this.type = "add"; this.type = 'add'
if (indexA !== null) { if (indexA !== null) {
this.indexA = indexA; this.indexA = indexA
this.type = "edit"; this.type = 'edit'
this.$set( this.$set(
this.QuestionList[index], this.QuestionList[index],
"groupingA", 'groupingA',
this.QuestionList[index].AnswerGroupList[indexA].AnswerGroupA this.QuestionList[index].AnswerGroupList[indexA].AnswerGroupA
); )
this.$set( this.$set(
this.QuestionList[index], this.QuestionList[index],
"groupingB", 'groupingB',
this.QuestionList[index].AnswerGroupList[indexA].AnswerGroupB this.QuestionList[index].AnswerGroupList[indexA].AnswerGroupB
); )
} }
this.QuestionVisible = true; this.QuestionVisible = true
}, },
reset(ReadingQuestionTrialId, index) { reset(ReadingQuestionTrialId, index) {
// '' // ''
this.$confirm(this.$t("trials:adRules:message:msg6")).then(() => { this.$confirm(this.$t('trials:adRules:message:msg6')).then(() => {
this.btnLoading = true; this.btnLoading = true
this.loading = true; this.loading = true
setTrialCriterionJudgeQuestionAnswerGroup({ setTrialCriterionJudgeQuestionAnswerGroup({
ReadingQuestionTrialId: ReadingQuestionTrialId, ReadingQuestionTrialId: ReadingQuestionTrialId,
AnswerGroup: [], AnswerGroup: [],
@ -805,39 +813,39 @@ export default {
JudgeDifferenceType: 0, JudgeDifferenceType: 0,
}) })
.then((res) => { .then((res) => {
this.$set(this.QuestionList[index], "AnswerGroup2List", []); this.$set(this.QuestionList[index], 'AnswerGroup2List', [])
this.$set(this.QuestionList[index], "AnswerGroupList", []); this.$set(this.QuestionList[index], 'AnswerGroupList', [])
this.$set(this.QuestionList[index], "JudgeType", 0); this.$set(this.QuestionList[index], 'JudgeType', 0)
this.$set(this.QuestionList[index], "JudgeDifferenceValue", 0); this.$set(this.QuestionList[index], 'JudgeDifferenceValue', 0)
this.$set(this.QuestionList[index], "JudgeDifferenceType", 0); this.$set(this.QuestionList[index], 'JudgeDifferenceType', 0)
this.$message.success(this.$t("trials:adRules:message:msg7")); // '' this.$message.success(this.$t('trials:adRules:message:msg7')) // ''
this.btnLoading = false; this.btnLoading = false
this.loading = false; this.loading = false
}) })
.catch(() => { .catch(() => {
this.btnLoading = false; this.btnLoading = false
this.loading = false; this.loading = false
}); })
}); })
}, },
async apply(ReadingQuestionTrialId, index) { async apply(ReadingQuestionTrialId, index) {
if (this.QuestionList[index].JudgeType === 0) { if (this.QuestionList[index].JudgeType === 0) {
this.$alert(this.$t("trials:adRules:message:msg8")); // '' this.$alert(this.$t('trials:adRules:message:msg8')) // ''
return; return
} }
if ( if (
this.QuestionList[index].JudgeType === 2 && this.QuestionList[index].JudgeType === 2 &&
this.QuestionList[index].AnswerGroup2List.length === 0 this.QuestionList[index].AnswerGroup2List.length === 0
) { ) {
this.$alert(this.$t("trials:adRules:message:msg8")); // '' this.$alert(this.$t('trials:adRules:message:msg8')) // ''
return; return
} }
if ( if (
this.QuestionList[index].JudgeType === 3 && this.QuestionList[index].JudgeType === 3 &&
this.QuestionList[index].AnswerGroupList.length === 0 this.QuestionList[index].AnswerGroupList.length === 0
) { ) {
this.$alert(this.$t("trials:adRules:message:msg8")); this.$alert(this.$t('trials:adRules:message:msg8'))
return; return
} }
if ( if (
this.QuestionList[index].JudgeType === 4 || this.QuestionList[index].JudgeType === 4 ||
@ -845,15 +853,15 @@ export default {
) { ) {
try { try {
let validate = await this.$refs[ let validate = await this.$refs[
"JudgeDifferenceValue" + this.QuestionList[index].JudgeType + index 'JudgeDifferenceValue' + this.QuestionList[index].JudgeType + index
][0].validate(); ][0].validate()
if (!validate) return; if (!validate) return
} catch (err) { } catch (err) {
return; return
} }
} }
this.btnLoading = true; this.btnLoading = true
this.loading = true; this.loading = true
setTrialCriterionJudgeQuestionAnswerGroup({ setTrialCriterionJudgeQuestionAnswerGroup({
ReadingQuestionTrialId: ReadingQuestionTrialId, ReadingQuestionTrialId: ReadingQuestionTrialId,
AnswerGroup: this.QuestionList[index].AnswerGroup2List, AnswerGroup: this.QuestionList[index].AnswerGroup2List,
@ -867,49 +875,49 @@ export default {
), ),
}) })
.then((res) => { .then((res) => {
this.$message.success(this.$t("trials:adRules:message:msg9")); // '' this.$message.success(this.$t('trials:adRules:message:msg9')) // ''
this.btnLoading = false; this.btnLoading = false
this.loading = false; this.loading = false
}) })
.catch(() => { .catch(() => {
this.btnLoading = false; this.btnLoading = false
this.loading = false; this.loading = false
}); })
}, },
tabClick(v) { tabClick(v) {
this.ReadingQuestionCriterionTrialId = this.ReadingQuestionCriterionTrialId =
this.CriterionList[this.index].ReadingQuestionCriterionTrialId; this.CriterionList[this.index].ReadingQuestionCriterionTrialId
}, },
getList() { getList() {
this.loading = true; this.loading = true
getTrialCriterionJudgeQuestionList({ getTrialCriterionJudgeQuestionList({
TrialId: this.$route.query.trialId, TrialId: this.$route.query.trialId,
TrialReadingCriterionId: this.trialReadingCriterionId, TrialReadingCriterionId: this.trialReadingCriterionId,
}) })
.then((res) => { .then((res) => {
this.loading = false; this.loading = false
this.QuestionList = res.Result; this.QuestionList = res.Result
this.OtherInfo = res.OtherInfo; this.OtherInfo = res.OtherInfo
this.activeNames = this.QuestionList.map( this.activeNames = this.QuestionList.map(
(v) => v.ReadingQuestionTrialId (v) => v.ReadingQuestionTrialId
); )
this.QuestionList.forEach((v) => { this.QuestionList.forEach((v) => {
this.$set(v, "grouping", []); this.$set(v, 'grouping', [])
this.$set(v, "groupingA", []); this.$set(v, 'groupingA', [])
this.$set(v, "groupingB", []); this.$set(v, 'groupingB', [])
this.$set( this.$set(
v, v,
"AnswerGroupList", 'AnswerGroupList',
Object.assign([], v.AnswerCombination) Object.assign([], v.AnswerCombination)
); )
this.$set(v, "AnswerGroup2List", Object.assign([], v.AnswerGroup)); this.$set(v, 'AnswerGroup2List', Object.assign([], v.AnswerGroup))
}); })
}) })
.catch(() => { .catch(() => {
this.btnLoading = false; this.btnLoading = false
this.loading = false; this.loading = false
}); })
}, },
}, },
}; }
</script> </script>

View File

@ -11,6 +11,7 @@
<!-- '表单问题' --> <!-- '表单问题' -->
<el-form-item :label="$t('trials:readingUnit:readingCriterion:title:formQs')"> <el-form-item :label="$t('trials:readingUnit:readingCriterion:title:formQs')">
<QuestionsList <QuestionsList
:ref="`questionList${trialReadingCriterionId}`"
v-if="form.FormType===1" v-if="form.FormType===1"
:trial-reading-criterion-id="trialReadingCriterionId" :trial-reading-criterion-id="trialReadingCriterionId"
:list="readingInfo.TrialQuestionList" :list="readingInfo.TrialQuestionList"
@ -170,6 +171,9 @@ export default {
}) })
}) })
}, },
getQuestionLength() {
return this.$refs['questionList' + this.trialReadingCriterionId].tblList.length
},
reloadArbitrationRules() { reloadArbitrationRules() {
this.$emit('reloadArbitrationRules') this.$emit('reloadArbitrationRules')
}, },

View File

@ -70,7 +70,7 @@
:label="item.value" :label="item.value"
v-for="item in $d.YesOrNoModality" v-for="item in $d.YesOrNoModality"
:key="item.id" :key="item.id"
> >
{{ item.label }} {{ item.label }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
@ -103,7 +103,13 @@
@click.stop="handleCheckAllChange" @click.stop="handleCheckAllChange"
type="success" type="success"
>{{ >{{
$t("trials:readingUnit:readingRules:title:CriterionModalitysAll") CriterionModalitys.length === modalityList.length
? $t(
'trials:readingUnit:readingRules:title:CriterionModalitysCancel'
)
: $t(
'trials:readingUnit:readingRules:title:CriterionModalitysAll'
)
}}</el-button }}</el-button
> >
</el-form-item> </el-form-item>
@ -131,6 +137,7 @@
<el-form-item <el-form-item
:label="$t('trials:processCfg:form:IsAdditionalAssessment')" :label="$t('trials:processCfg:form:IsAdditionalAssessment')"
prop="IsAdditionalAssessment" prop="IsAdditionalAssessment"
v-if="CriterionType === 1"
> >
<el-radio-group <el-radio-group
v-model="form.IsAdditionalAssessment" v-model="form.IsAdditionalAssessment"
@ -182,7 +189,7 @@
" "
@change=" @change="
() => { () => {
form.IsArbitrationReading = false; form.IsArbitrationReading = false
} }
" "
> >
@ -232,8 +239,8 @@
@change=" @change="
(v) => { (v) => {
if (!v) { if (!v) {
form.IsGlobalReading = v; form.IsGlobalReading = v
form.IsOncologyReading = v; form.IsOncologyReading = v
} }
} }
" "
@ -306,15 +313,15 @@
" "
@change=" @change="
(v) => { (v) => {
form.ImageDownloadEnum = 0; form.ImageDownloadEnum = 0
form.ImageUploadEnum = 0; form.ImageUploadEnum = 0
if (v) { if (v) {
form.IsReadingShowSubjectInfo = true; form.IsReadingShowSubjectInfo = true
form.IsReadingShowPreviousResults = true; form.IsReadingShowPreviousResults = true
form.ReadingTaskViewEnum = 0; form.ReadingTaskViewEnum = 0
form.IseCRFShowInDicomReading = false; form.IseCRFShowInDicomReading = false
} else { } else {
form.ReadingTaskViewEnum = 2; form.ReadingTaskViewEnum = 2
} }
} }
" "
@ -351,11 +358,10 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!--支持影像下载--> <!--支持影像下载v-if="CriterionType === 0"-->
<el-form-item <el-form-item
:label="$t('trials:processCfg:form:ImageDownloadEnum')" :label="$t('trials:processCfg:form:ImageDownloadEnum')"
prop="ImageDownloadEnum" prop="ImageDownloadEnum"
v-if="CriterionType === 0"
> >
<el-radio-group <el-radio-group
v-model="form.ImageDownloadEnum" v-model="form.ImageDownloadEnum"
@ -379,7 +385,6 @@
<el-form-item <el-form-item
:label="$t('trials:processCfg:form:ImageUploadEnum')" :label="$t('trials:processCfg:form:ImageUploadEnum')"
prop="ImageUploadEnum" prop="ImageUploadEnum"
v-if="CriterionType === 0"
> >
<el-radio-group <el-radio-group
v-model="form.ImageUploadEnum" v-model="form.ImageUploadEnum"
@ -442,7 +447,7 @@
@change=" @change="
(v) => { (v) => {
if (!v) { if (!v) {
form.IseCRFShowInDicomReading = true; form.IseCRFShowInDicomReading = true
} }
} }
" "
@ -541,7 +546,7 @@
" "
@change=" @change="
(v) => { (v) => {
$set(form, 'AdditionalAssessmentType' + item.Id, v); $set(form, 'AdditionalAssessmentType' + item.Id, v)
} }
" "
> >
@ -563,21 +568,21 @@
> >
<!-- 保存 --> <!-- 保存 -->
<el-button type="primary" @click="handleSave(true)"> <el-button type="primary" @click="handleSave(true)">
{{ $t("common:button:save") }} {{ $t('common:button:save') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
</template> </template>
<script> <script>
import { getCriterionReadingInfo, setCriterionReadingInfo } from "@/api/trials"; import { getCriterionReadingInfo, setCriterionReadingInfo } from '@/api/trials'
export default { export default {
name: "ReadingRules", name: 'ReadingRules',
props: { props: {
trialReadingCriterionId: { trialReadingCriterionId: {
type: String, type: String,
default() { default() {
return ""; return ''
}, },
}, },
CriterionType: { CriterionType: {
@ -589,7 +594,7 @@ export default {
return { return {
additionalAssessmentOptionList: [], additionalAssessmentOptionList: [],
form: { form: {
TrialId: "", TrialId: '',
ImagePlatform: null, ImagePlatform: null,
ReadingTool: 0, ReadingTool: 0,
ReadingTaskViewEnum: null, ReadingTaskViewEnum: null,
@ -624,151 +629,151 @@ export default {
IsAutoCreate: [ IsAutoCreate: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsAdditionalAssessment: [ IsAdditionalAssessment: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
ImagePlatform: [ ImagePlatform: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
ReadingTool: [ ReadingTool: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
ImageDownloadEnum: [ ImageDownloadEnum: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
ImageUploadEnum: [ ImageUploadEnum: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsImageFilter: [ IsImageFilter: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
ReadingTaskViewEnum: [ ReadingTaskViewEnum: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsImageLabeled: [ IsImageLabeled: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsReadingShowSubjectInfo: [ IsReadingShowSubjectInfo: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsReadingShowPreviousResults: [ IsReadingShowPreviousResults: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
ReadingType: [ ReadingType: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsReadingTaskViewInOrder: [ IsReadingTaskViewInOrder: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsGlobalReading: [ IsGlobalReading: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsArbitrationReading: [ IsArbitrationReading: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsOncologyReading: [ IsOncologyReading: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
DigitPlaces: [ DigitPlaces: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IseCRFShowInDicomReading: [ IseCRFShowInDicomReading: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
IsReadingPeriod: [ IsReadingPeriod: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
CriterionModalitys: [ CriterionModalitys: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
{ {
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
if (value && Array.isArray(value) && value.length < 0) { if (value && Array.isArray(value) && value.length < 0) {
callback(new Error(this.$t("common:ruleMessage:select"))); callback(new Error(this.$t('common:ruleMessage:select')))
} else { } else {
callback(); callback()
} }
}, },
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
// IsReadingTaskViewInOrder: [ // IsReadingTaskViewInOrder: [
@ -785,15 +790,15 @@ export default {
modalityList: [], modalityList: [],
CriterionModalitys: [], CriterionModalitys: [],
modalityIsCheck: false, // modalityIsCheck: false, //
}; }
}, },
mounted() { mounted() {
this.initPage(); this.initPage()
}, },
watch: { watch: {
CriterionModalitys: { CriterionModalitys: {
handler() { handler() {
this.form.CriterionModalitys = this.CriterionModalitys.join("|"); this.form.CriterionModalitys = this.CriterionModalitys.join('|')
}, },
deep: true, deep: true,
}, },
@ -802,19 +807,19 @@ export default {
// //
IsImageFilterChange(data) { IsImageFilterChange(data) {
if (data) { if (data) {
this.CriterionModalitys = this.modalityList; this.CriterionModalitys = this.modalityList
} else { } else {
this.CriterionModalitys = []; this.CriterionModalitys = []
} }
}, },
// //
handleCheckAllChange() { handleCheckAllChange() {
this.CriterionModalitys = this.CriterionModalitys =
this.CriterionModalitys.length <= 0 ? this.modalityList : []; this.CriterionModalitys.length <= 0 ? this.modalityList : []
}, },
initPage() { initPage() {
this.loading = true; this.loading = true
const trialId = this.$route.query.trialId; const trialId = this.$route.query.trialId
// getTrialCriterionAdditionalAssessmentOptionList(this.trialReadingCriterionId).then(res => { // getTrialCriterionAdditionalAssessmentOptionList(this.trialReadingCriterionId).then(res => {
// this.additionalAssessmentOptionList = res.Result // this.additionalAssessmentOptionList = res.Result
// if (this.additionalAssessmentOptionList.length > 0) { // if (this.additionalAssessmentOptionList.length > 0) {
@ -827,46 +832,46 @@ export default {
TrialReadingCriterionId: this.trialReadingCriterionId, TrialReadingCriterionId: this.trialReadingCriterionId,
}) })
.then((res) => { .then((res) => {
this.loading = false; this.loading = false
this.modalityList = res.Result.TrialModalitys.split("|").filter( this.modalityList = res.Result.TrialModalitys.split('|').filter(
(item) => item && item.trim() (item) => item && item.trim()
); )
for (const k in this.form) { for (const k in this.form) {
if (res.Result.hasOwnProperty(k)) { if (res.Result.hasOwnProperty(k)) {
this.form[k] = res.Result[k]; this.form[k] = res.Result[k]
} }
} }
this.CriterionModalitys = this.form.CriterionModalitys this.CriterionModalitys = this.form.CriterionModalitys
? this.form.CriterionModalitys.split("|") ? this.form.CriterionModalitys.split('|')
: []; : []
this.form.TrialCriterionAdditionalAssessmentTypeList.forEach((v) => { this.form.TrialCriterionAdditionalAssessmentTypeList.forEach((v) => {
this.$set(v, "IsSelected", v.IsSelected || false); this.$set(v, 'IsSelected', v.IsSelected || false)
this.$set( this.$set(
this.form, this.form,
"AdditionalAssessmentType" + v.Id, 'AdditionalAssessmentType' + v.Id,
v.IsSelected v.IsSelected
); )
}); })
this.isReadingTaskViewInOrder = res.Result.IsReadingTaskViewInOrder; this.isReadingTaskViewInOrder = res.Result.IsReadingTaskViewInOrder
this.isConfirm = res.Result.IsSign; this.isConfirm = res.Result.IsSign
this.IsMustGlobalReading = res.Result.IsMustGlobalReading; this.IsMustGlobalReading = res.Result.IsMustGlobalReading
this.$emit("setConfirm", res.Result.IsSign); this.$emit('setConfirm', res.Result.IsSign)
this.$emit("setArbitrationReading", res.Result.IsArbitrationReading); this.$emit('setArbitrationReading', res.Result.IsArbitrationReading)
this.$emit( this.$emit(
"setAdditionalAssessment", 'setAdditionalAssessment',
this.form.IsAdditionalAssessment this.form.IsAdditionalAssessment
); )
this.$emit("setIsClinicalReading", res.Result.IsClinicalReading); this.$emit('setIsClinicalReading', res.Result.IsClinicalReading)
this.$emit("setGlobalReading", res.Result.IsGlobalReading); this.$emit('setGlobalReading', res.Result.IsGlobalReading)
this.$emit("setOncologyReading", res.Result.IsOncologyReading); this.$emit('setOncologyReading', res.Result.IsOncologyReading)
this.$emit("setDigitPlaces", res.Result.DigitPlaces); this.$emit('setDigitPlaces', res.Result.DigitPlaces)
if (res.Result.ReadingType === 1) { if (res.Result.ReadingType === 1) {
this.$emit("setArbitrationReading", false); this.$emit('setArbitrationReading', false)
} }
}) })
.catch(() => { .catch(() => {
this.loading = false; this.loading = false
}); })
// }).catch(() => { // }).catch(() => {
// this.loading = false // this.loading = false
// }) // })
@ -874,52 +879,52 @@ export default {
// //
handleSave(isPrompt = true) { handleSave(isPrompt = true) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.$refs["readingRulesForm"].validate((valid) => { this.$refs['readingRulesForm'].validate((valid) => {
if (!valid) { if (!valid) {
resolve(false); resolve(false)
} else { } else {
this.loading = true; this.loading = true
if (this.form.ReadingType === 1) { if (this.form.ReadingType === 1) {
this.form.IsArbitrationReading = false; this.form.IsArbitrationReading = false
} }
// //
this.form.TrialReadingCriterionId = this.trialReadingCriterionId; this.form.TrialReadingCriterionId = this.trialReadingCriterionId
setCriterionReadingInfo(this.form) setCriterionReadingInfo(this.form)
.then((res) => { .then((res) => {
this.loading = false; this.loading = false
this.$emit("reloadArbitrationRules"); this.$emit('reloadArbitrationRules')
this.$emit( this.$emit(
"setArbitrationReading", 'setArbitrationReading',
this.form.IsArbitrationReading this.form.IsArbitrationReading
); )
this.$emit( this.$emit(
"setAdditionalAssessment", 'setAdditionalAssessment',
this.form.IsAdditionalAssessment this.form.IsAdditionalAssessment
); )
this.$emit("setIsClinicalReading", this.form.IsClinicalReading); this.$emit('setIsClinicalReading', this.form.IsClinicalReading)
this.$emit("setGlobalReading", this.form.IsGlobalReading); this.$emit('setGlobalReading', this.form.IsGlobalReading)
this.$emit("setOncologyReading", this.form.IsOncologyReading); this.$emit('setOncologyReading', this.form.IsOncologyReading)
this.$emit("setDigitPlaces", this.form.DigitPlaces); this.$emit('setDigitPlaces', this.form.DigitPlaces)
if (this.form.ReadingType === 1) { if (this.form.ReadingType === 1) {
this.$emit("setArbitrationReading", false); this.$emit('setArbitrationReading', false)
} }
if (res.IsSuccess && isPrompt) { if (res.IsSuccess && isPrompt) {
this.$message.success( this.$message.success(
this.$t("common:message:savedSuccessfully") this.$t('common:message:savedSuccessfully')
); )
} }
resolve(true); resolve(true)
}) })
.catch((_) => { .catch((_) => {
this.loading = false; this.loading = false
resolve(false); resolve(false)
}); })
} }
}); })
}); })
}, },
}, },
}; }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.reading-rule-config-form { .reading-rule-config-form {

View File

@ -370,11 +370,11 @@ export default {
isCheck: readingRules, isCheck: readingRules,
msg: this.$t("trials:readingUnit:readingRules"), // '' msg: this.$t("trials:readingUnit:readingRules"), // ''
}); });
// var readingCriterions = await this.$refs['readingCriterions' + this.TrialReadingCriterionId][0].handleSave(false) var qsLength = this.$refs['readingCriterions' + this.TrialReadingCriterionId][0].getQuestionLength()
// isCheckList.push({ isCheckList.push({
// isCheck: readingCriterions, isCheck: qsLength > 0,
// msg: '' msg: this.$t('trials:readingUnit:readingCriterion')
// }) })
if ( if (
this.$refs["globalReading" + this.TrialReadingCriterionId] && this.$refs["globalReading" + this.TrialReadingCriterionId] &&
this.$refs["globalReading" + this.TrialReadingCriterionId] this.$refs["globalReading" + this.TrialReadingCriterionId]
@ -497,12 +497,16 @@ export default {
}); });
}, },
reloadArbitrationRules() { reloadArbitrationRules() {
this.$refs[ if (this.$refs[
"arbitrationRules" + this.TrialReadingCriterionId "arbitrationRules" + this.TrialReadingCriterionId
][0].getList(); ]) {
this.$refs[ this.$refs[
"arbitrationRules" + this.TrialReadingCriterionId "arbitrationRules" + this.TrialReadingCriterionId
][0].getTrialJudgyInfo(); ][0].getList();
this.$refs[
"arbitrationRules" + this.TrialReadingCriterionId
][0].getTrialJudgyInfo();
}
}, },
}, },
}; };

View File

@ -34,7 +34,7 @@
type="text" type="text"
@click="handleDownloadTpl" @click="handleDownloadTpl"
> >
{{ $t("trials:readingPeriod:cd:title:downloadTpl") }} {{ $t('trials:readingPeriod:cd:title:downloadTpl') }}
</el-button> </el-button>
</el-col> </el-col>
</el-form-item> </el-form-item>
@ -53,7 +53,7 @@
" "
> >
<el-button type="primary" style="width: 56px" size="small"> <el-button type="primary" style="width: 56px" size="small">
{{ $t("trials:uploadClinicalData:button:selectFile") }} {{ $t('trials:uploadClinicalData:button:selectFile') }}
</el-button> </el-button>
<input <input
type="file" type="file"
@ -72,7 +72,7 @@
@change="beginScanFiles($event)" @change="beginScanFiles($event)"
/> />
<span style="margin-left: 10px">{{ <span style="margin-left: 10px">{{
$t("trials:attachment:message:pdf") $t('trials:attachment:message:pdf')
}}</span> }}</span>
</div> </div>
</div> </div>
@ -139,7 +139,7 @@
type="primary" type="primary"
@click="close" @click="close"
> >
{{ $t("common:button:cancel") }} {{ $t('common:button:cancel') }}
</el-button> </el-button>
<!-- 保存 --> <!-- 保存 -->
<el-button <el-button
@ -148,7 +148,7 @@
:loading="btnLoading" :loading="btnLoading"
@click="save" @click="save"
> >
{{ $t("common:button:save") }} {{ $t('common:button:save') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
</div> </div>
@ -159,23 +159,23 @@ import {
getTrialClinicalDataSelect, getTrialClinicalDataSelect,
addOrUpdateReadingClinicalData, addOrUpdateReadingClinicalData,
addOrUpdateConsistencyAnalysisReadingClinicalData, addOrUpdateConsistencyAnalysisReadingClinicalData,
} from "@/api/trials"; } from '@/api/trials'
import { fileDownload } from "@/utils/uploadZip.js"; import { downLoadFile } from '@/utils/stream.js'
export default { export default {
name: "AddOrUpdateClinicalData", name: 'AddOrUpdateClinicalData',
props: { props: {
trialReadingCriterionId: { trialReadingCriterionId: {
type: String, type: String,
default: "", default: '',
}, },
data: { data: {
type: Object, type: Object,
default() { default() {
return {}; return {}
}, },
}, },
type: { type: {
default: "readingPeriod", default: 'readingPeriod',
}, },
option: { option: {
default: () => [], default: () => [],
@ -185,13 +185,13 @@ export default {
data() { data() {
return { return {
fileList: [], fileList: [],
faccept: [".pdf"], faccept: ['.pdf'],
form: { form: {
Id: "", Id: '',
TrialId: "", TrialId: '',
SubjectId: "", SubjectId: '',
ReadingId: "", ReadingId: '',
ClinicalDataTrialSetId: "", ClinicalDataTrialSetId: '',
IsVisist: true, IsVisist: true,
AddFileList: [], AddFileList: [],
DeleteFileIds: [], DeleteFileIds: [],
@ -201,8 +201,8 @@ export default {
ClinicalDataTrialSetId: [ ClinicalDataTrialSetId: [
{ {
required: true, required: true,
message: this.$t("common:ruleMessage:select"), message: this.$t('common:ruleMessage:select'),
trigger: ["blur", "change"], trigger: ['blur', 'change'],
}, },
], ],
}, },
@ -211,194 +211,190 @@ export default {
clinicalDatas: [], clinicalDatas: [],
pendingUploadList: [], pendingUploadList: [],
pendingDeleteList: [], pendingDeleteList: [],
currentTpl: { id: "", isExist: false }, currentTpl: { id: '', isExist: false },
}; }
}, },
mounted() { mounted() {
this.initForm(); this.initForm()
}, },
methods: { methods: {
// //
handleUploadFile(row) { handleUploadFile(row) {
let href = this.OSSclientConfig.basePath + row.Path; let href = this.OSSclientConfig.basePath + row.Path
let name = row.FileName; let name = row.FileName
fileDownload(href, name); downLoadFile(href, name)
}, },
async initForm() { async initForm() {
if (this.type === "readingPeriod") { if (this.type === 'readingPeriod') {
await this.getClinicalDatas(); await this.getClinicalDatas()
} else { } else {
this.clinicalDatas = this.option; this.clinicalDatas = this.option
} }
if (Object.keys(this.data).length > 0) { if (Object.keys(this.data).length > 0) {
for (const k in this.form) { for (const k in this.form) {
if (this.data.hasOwnProperty(k)) { if (this.data.hasOwnProperty(k)) {
this.form[k] = this.data[k]; this.form[k] = this.data[k]
} }
} }
this.handleClinicalDataSetChange(this.form.ClinicalDataTrialSetId); this.handleClinicalDataSetChange(this.form.ClinicalDataTrialSetId)
this.fileList = this.form.FileList.concat(); this.fileList = this.form.FileList.concat()
} }
}, },
save() { save() {
this.$refs.clinicalDataForm.validate((valid) => { this.$refs.clinicalDataForm.validate((valid) => {
if (!valid) return; if (!valid) return
if (this.fileList.length === 0) { if (this.fileList.length === 0) {
// //
this.$alert(this.$t("trials:readingPeriod:cd:message:uploadFile")); this.$alert(this.$t('trials:readingPeriod:cd:message:uploadFile'))
return; return
} }
this.pendingUploadList = []; this.pendingUploadList = []
for (let i = 0; i < this.fileList.length; ++i) { for (let i = 0; i < this.fileList.length; ++i) {
if (this.fileList[i].Status === 0) { if (this.fileList[i].Status === 0) {
this.pendingUploadList.push(this.fileList[i].Files); this.pendingUploadList.push(this.fileList[i].Files)
} }
} }
if (this.pendingUploadList.length > 0) { if (this.pendingUploadList.length > 0) {
this.uploadFilesAndSave(); this.uploadFilesAndSave()
} else { } else {
this.saveClinicalData(); this.saveClinicalData()
} }
}); })
}, },
uploadFilesAndSave() { uploadFilesAndSave() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
this.form.AddFileList = []; this.form.AddFileList = []
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
); )
this.form.AddFileList.push({ this.form.AddFileList.push({
fileName: this.pendingUploadList[i].name, fileName: this.pendingUploadList[i].name,
path: this.$getObjectName(res.url), path: this.$getObjectName(res.url),
size: this.pendingUploadList[i].size, size: this.pendingUploadList[i].size,
type: this.pendingUploadList[i].type, type: this.pendingUploadList[i].type,
}); })
} }
this.saveClinicalData(this.form.AddFileList); this.saveClinicalData(this.form.AddFileList)
resolve(); resolve()
}); })
}, },
saveClinicalData() { saveClinicalData() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.btnLoading = true; this.btnLoading = true
this.form.DeleteFileIds = this.pendingDeleteList; this.form.DeleteFileIds = this.pendingDeleteList
if (this.type === "consistencyAnalysis") { if (this.type === 'consistencyAnalysis') {
addOrUpdateConsistencyAnalysisReadingClinicalData(this.form) addOrUpdateConsistencyAnalysisReadingClinicalData(this.form)
.then((response) => { .then((response) => {
this.btnLoading = false; this.btnLoading = false
this.$emit("getList"); this.$emit('getList')
this.$emit("close"); this.$emit('close')
this.$message.success( this.$message.success(this.$t('common:message:savedSuccessfully'))
this.$t("common:message:savedSuccessfully") resolve()
);
resolve();
}) })
.catch(() => { .catch(() => {
this.btnLoading = false; this.btnLoading = false
reject(); reject()
}); })
} else { } else {
addOrUpdateReadingClinicalData(this.form) addOrUpdateReadingClinicalData(this.form)
.then((response) => { .then((response) => {
this.btnLoading = false; this.btnLoading = false
this.$emit("getList"); this.$emit('getList')
this.$emit("close"); this.$emit('close')
this.$message.success( this.$message.success(this.$t('common:message:savedSuccessfully'))
this.$t("common:message:savedSuccessfully") resolve()
);
resolve();
}) })
.catch(() => { .catch(() => {
this.btnLoading = false; this.btnLoading = false
reject(); reject()
}); })
} }
}); })
}, },
getClinicalDatas() { getClinicalDatas() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.loading = true; this.loading = true
var param = { var param = {
trialId: this.data.TrialId, trialId: this.data.TrialId,
IsVisit: this.data.IsVisit, IsVisit: this.data.IsVisit,
ReadingId: this.data.ReadingId, ReadingId: this.data.ReadingId,
SubjectId: this.data.SubjectId, SubjectId: this.data.SubjectId,
ReadingClinicalDataId: this.data.Id ? this.data.Id : "", ReadingClinicalDataId: this.data.Id ? this.data.Id : '',
IsBaseLine: this.data.IsBaseLine, IsBaseLine: this.data.IsBaseLine,
TrialReadingCriterionId: this.trialReadingCriterionId, TrialReadingCriterionId: this.trialReadingCriterionId,
}; }
getTrialClinicalDataSelect(param) getTrialClinicalDataSelect(param)
.then((res) => { .then((res) => {
this.clinicalDatas = res.Result; this.clinicalDatas = res.Result
this.loading = false; this.loading = false
resolve(); resolve()
}) })
.catch(() => { .catch(() => {
this.loading = false; this.loading = false
reject(); reject()
}); })
}); })
}, },
handleDeleteFile(index, row) { handleDeleteFile(index, row) {
this.$confirm(this.$t("trials:readingPeriod:cd:message:delete"), { this.$confirm(this.$t('trials:readingPeriod:cd:message:delete'), {
type: "warning", type: 'warning',
distinguishCancelAndClose: true, distinguishCancelAndClose: true,
}) })
.then(() => { .then(() => {
if (row.Id) { if (row.Id) {
this.pendingDeleteList.push(row.Id); this.pendingDeleteList.push(row.Id)
} }
this.fileList.splice(index, 1); this.fileList.splice(index, 1)
}) })
.catch(() => {}); .catch(() => {})
}, },
beginScanFiles(e) { beginScanFiles(e) {
var files = e.target.files; var files = e.target.files
for (var i = 0; i < files.length; ++i) { for (var i = 0; i < files.length; ++i) {
const fileName = files[i].name; const fileName = files[i].name
var extendName = fileName var extendName = fileName
.substring(fileName.lastIndexOf(".")) .substring(fileName.lastIndexOf('.'))
.toLocaleLowerCase(); .toLocaleLowerCase()
if (this.faccept.indexOf(extendName) !== -1) { if (this.faccept.indexOf(extendName) !== -1) {
this.fileList.push({ this.fileList.push({
FileName: fileName, FileName: fileName,
Path: "", Path: '',
Status: 0, Status: 0,
Files: files[i], Files: files[i],
size: files[i].size, size: files[i].size,
type: fileName.split(".")[1], type: fileName.split('.')[1],
}); })
} }
} }
}, },
handleClinicalDataSetChange(v) { handleClinicalDataSetChange(v) {
var index = this.clinicalDatas.findIndex((item) => item.Id === v); var index = this.clinicalDatas.findIndex((item) => item.Id === v)
if (index > -1) { if (index > -1) {
this.currentTpl.id = this.clinicalDatas[index].Id; this.currentTpl.id = this.clinicalDatas[index].Id
this.currentTpl.path = this.clinicalDatas[index].Path; this.currentTpl.path = this.clinicalDatas[index].Path
this.currentTpl.isExist = !!this.clinicalDatas[index].FileName; this.currentTpl.isExist = !!this.clinicalDatas[index].FileName
} }
}, },
handleDownloadTpl() { handleDownloadTpl() {
this.loading = true; this.loading = true
window.open( window.open(
this.OSSclientConfig.basePath + this.currentTpl.path, this.OSSclientConfig.basePath + this.currentTpl.path,
"_blank" '_blank'
); )
this.loading = false; this.loading = false
// DownloadTrialClinicalFile(this.currentTpl.id).then(data => { // DownloadTrialClinicalFile(this.currentTpl.id).then(data => {
// this.loading = false // this.loading = false
// }).catch(() => { this.loading = false }) // }).catch(() => { this.loading = false })
}, },
close() { close() {
this.$emit("close"); this.$emit('close')
}, },
}, },
}; }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>

View File

@ -347,9 +347,9 @@
<a v-else-if="(scope.row.DataType === 'Link' || scope.row.DataType === 'Router') && scope.row.oldValue && scope.row.oldValue !== '--'" target="_blank" :href="scope.row.oldValue" style="color:#409eff;"> <a v-else-if="(scope.row.DataType === 'Link' || scope.row.DataType === 'Router') && scope.row.oldValue && scope.row.oldValue !== '--'" target="_blank" :href="scope.row.oldValue" style="color:#409eff;">
{{$t('trials:auditRecord:title:viewDetail')}} {{$t('trials:auditRecord:title:viewDetail')}}
</a> </a>
<viewer v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList') && scope.row.oldValue && scope.row.oldValue !== '--'" :ref="scope.row.oldValue instanceof Array ? scope.row.oldValue[0] : scope.row.oldValue" :images="imagesList"> <viewer v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList') && scope.row.oldValue && scope.row.oldValue !== '--'" :ref="`${scope.row.oldValue instanceof Array ? scope.row.oldValue[0] : scope.row.oldValue}_modelCfg`" :images="imagesList">
<!-- 查看图片 --> <!-- 查看图片 -->
<span style="color:#409eff;cursor: pointer" @click="openImage(scope.row.oldValue)">{{$t('trials:auditRecord:title:viewImage')}}{{scope.row.oldValue instanceof Array ? `(${scope.row.oldValue.length})` : ''}}</span> <span style="color:#409eff;cursor: pointer" @click="openImage(scope.row.oldValue, 'modelCfg')">{{$t('trials:auditRecord:title:viewImage')}}{{scope.row.oldValue instanceof Array ? `(${scope.row.oldValue.length})` : ''}}</span>
<template v-for="item of scope.row.oldValue"> <template v-for="item of scope.row.oldValue">
<img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt=""> <img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt="">
</template> </template>
@ -378,9 +378,9 @@
<a v-else-if="(scope.row.DataType === 'Link' || scope.row.DataType === 'Router') && scope.row.newValue && scope.row.newValue !== '--'" target="_blank" :href="scope.row.newValue" style="color:#409eff;"> <a v-else-if="(scope.row.DataType === 'Link' || scope.row.DataType === 'Router') && scope.row.newValue && scope.row.newValue !== '--'" target="_blank" :href="scope.row.newValue" style="color:#409eff;">
{{$t('trials:auditRecord:title:viewDetail')}} {{$t('trials:auditRecord:title:viewDetail')}}
</a> </a>
<viewer v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList') && scope.row.newValue && scope.row.newValue !== '--'" :ref="scope.row.newValue instanceof Array ? scope.row.newValue[0] : scope.row.newValue" :images="imagesList"> <viewer v-else-if="(scope.row.DataType === 'Image' || scope.row.DataType === 'ImageList') && scope.row.newValue && scope.row.newValue !== '--'" :ref="`${scope.row.newValue instanceof Array ? scope.row.newValue[0] : scope.row.newValue}_modelcfg`" :images="imagesList">
<!-- 查看图片 --> <!-- 查看图片 -->
<span style="color:#409eff;cursor: pointer" @click="openImage(scope.row.newValue)">{{$t('trials:auditRecord:title:viewImage')}}{{scope.row.newValue instanceof Array ? `(${scope.row.newValue.length})` : ''}}</span> <span style="color:#409eff;cursor: pointer" @click="openImage(scope.row.newValue, 'modelcfg')">{{$t('trials:auditRecord:title:viewImage')}}{{scope.row.newValue instanceof Array ? `(${scope.row.newValue.length})` : ''}}</span>
<template v-for="item of scope.row.newValue"> <template v-for="item of scope.row.newValue">
<img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt=""> <img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt="">
</template> </template>
@ -409,9 +409,9 @@
:key="'tableList' + index" :key="'tableList' + index"
> >
<template v-if="!item.IsMerge" slot-scope="scope"> <template v-if="!item.IsMerge" slot-scope="scope">
<viewer v-if="item.IsPicture" :images="imagesList" :ref="scope.row[item.ColumnValue]"> <viewer v-if="item.IsPicture" :images="imagesList" :ref="`${scope.row[item.ColumnValue]}_modelcfg`">
<!-- 查看图片 --> <!-- 查看图片 -->
<span style="color:#409eff;cursor: pointer" @click="openImage(scope.row[item.ColumnValue])">{{$t('trials:auditRecord:title:viewImage')}}</span> <span style="color:#409eff;cursor: pointer" @click="openImage(scope.row[item.ColumnValue],'modelcfg')">{{$t('trials:auditRecord:title:viewImage')}}</span>
<img :src="OSSclientConfig.basePath + scope.row[item.ColumnValue]" v-show="false" crossorigin="anonymous" alt=""> <img :src="OSSclientConfig.basePath + scope.row[item.ColumnValue]" v-show="false" crossorigin="anonymous" alt="">
</viewer> </viewer>
<span v-else>{{scope.row[item.ColumnValue]}}</span> <span v-else>{{scope.row[item.ColumnValue]}}</span>
@ -426,9 +426,9 @@
:key="'ChildrenList' + index" :key="'ChildrenList' + index"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<viewer v-if="item.IsPicture" :images="imagesList" :ref="scope.row[ite.ListName ? ite.ListName + ite.ColumnValue + index : ite.ColumnValue]"> <viewer v-if="item.IsPicture" :images="imagesList" :ref="`${scope.row[ite.ListName ? ite.ListName + ite.ColumnValue + index : ite.ColumnValue]}_modelcfg`">
<!-- 查看图片 --> <!-- 查看图片 -->
<span style="color:#409eff;cursor: pointer" @click="openImage(scope.row[ite.ListName ? ite.ListName + ite.ColumnValue + index : ite.ColumnValue])"> <span style="color:#409eff;cursor: pointer" @click="openImage(scope.row[ite.ListName ? ite.ListName + ite.ColumnValue + index : ite.ColumnValue], 'modelcfg')">
{{$t('trials:auditRecord:title:viewImage')}} {{$t('trials:auditRecord:title:viewImage')}}
</span> </span>
<img :src="OSSclientConfig.basePath + scope.row[ite.ListName ? ite.ListName + ite.ColumnValue + index : ite.ColumnValue]" v-show="false" crossorigin="anonymous" alt=""> <img :src="OSSclientConfig.basePath + scope.row[ite.ListName ? ite.ListName + ite.ColumnValue + index : ite.ColumnValue]" v-show="false" crossorigin="anonymous" alt="">
@ -652,9 +652,9 @@
/> />
<!-- OptType === 'Add' ? '值' : OptType === 'Delete' ? '删除前' : '修改前' --> <!-- OptType === 'Add' ? '值' : OptType === 'Delete' ? '删除前' : '修改前' -->
<el-table-column <el-table-column
v-if="OptType !== 'Add' && OptType !== 'Upload' && OptType !== 'Init'" v-if="OptType2 !== 'Add' && OptType2 !== 'Upload' && OptType2 !== 'Init'"
prop="oldValue" prop="oldValue"
:label="OptType === 'Add' ? $t('trials:auditRecord:title:fieldValue') : OptType === 'Delete' ? $t('trials:auditRecord:title:beforeDeletion') : $t('trials:auditRecord:title:beforeModification')" :label="OptType2 === 'Add' ? $t('trials:auditRecord:title:fieldValue') : OptType2 === 'Delete' ? $t('trials:auditRecord:title:beforeDeletion') : $t('trials:auditRecord:title:beforeModification')"
show-overflow-tooltip show-overflow-tooltip
> >
<!-- <template slot-scope="scope"> <!-- <template slot-scope="scope">
@ -692,7 +692,7 @@
<!-- OptType === 'Add' || OptType === 'Init' ? '值' : OptType === 'Delete' ? '删除后' : '修改后' --> <!-- OptType === 'Add' || OptType === 'Init' ? '值' : OptType === 'Delete' ? '删除后' : '修改后' -->
<el-table-column <el-table-column
prop="newValue" prop="newValue"
:label="OptType === 'Add' || OptType === 'Init' ? $t('trials:auditRecord:title:fieldValue') : OptType === 'Delete' ? $t('trials:auditRecord:title:afterDeletion') : $t('trials:auditRecord:title:afterModification')" :label="OptType2 === 'Add' || OptType2 === 'Init' ? $t('trials:auditRecord:title:fieldValue') : OptType2 === 'Delete' ? $t('trials:auditRecord:title:afterDeletion') : $t('trials:auditRecord:title:afterModification')"
show-overflow-tooltip show-overflow-tooltip
> >
<!-- <template slot-scope="scope"> <!-- <template slot-scope="scope">
@ -876,6 +876,7 @@ export default {
siteOptions: [], siteOptions: [],
visitPlanOptions: [], visitPlanOptions: [],
OptType: null, OptType: null,
OptType2: null,
trialId: this.$route.query.trialId, trialId: this.$route.query.trialId,
configList2: [], configList2: [],
otherData2: [], otherData2: [],
@ -896,19 +897,22 @@ export default {
this.getList() this.getList()
}, },
methods: { methods: {
openImage(url) { openImage(url, type) {
console.log(url) console.log(url)
this.$nextTick(()=>{ this.$nextTick(()=>{
if (url instanceof Array) { if (url instanceof Array) {
this.imagesList = url.map(v => this.OSSclientConfig.basePath + v) this.imagesList = url.map(v => this.OSSclientConfig.basePath + v)
this.$refs[url[0]].$viewer.show() let refName = type ? `${url[0]}_${type}` : url[0]
this.$refs[refName].$viewer.show()
} else { } else {
this.imagesList = [this.OSSclientConfig.basePath + url] this.imagesList = [this.OSSclientConfig.basePath + url]
if(this.$refs[url] instanceof Array){ if(this.$refs[url] instanceof Array){
this.$refs[url][0].$viewer.show() let refName = type ? `${url}_${type}` : url
this.$refs[refName][0].$viewer.show()
}else{ }else{
this.$refs[url].$viewer.show() let refName = type ? `${url}_${type}` : url
this.$refs[refName].$viewer.show()
} }
} }
}) })
@ -978,6 +982,8 @@ export default {
this.tableListData = [] this.tableListData = []
this[auditData] = [] this[auditData] = []
config.forEach(v => { config.forEach(v => {
v.Code = this.$i18n.locale === 'zh' ? v.Code : v.CodeEn ? v.CodeEn : v.Code
var item var item
if (!v.IsEnable) return if (!v.IsEnable) return
if (v.IsShowByTrialConfig) { if (v.IsShowByTrialConfig) {
@ -989,18 +995,18 @@ export default {
let uo = upObj[v.TableFiledName][i] let uo = upObj[v.TableFiledName][i]
if (row.OptType === 'Add' || row.OptType === 'Init') { if (row.OptType === 'Add' || row.OptType === 'Init') {
item = { item = {
newValue: o[v.Code] ? (o[v.Code] ? o[v.Code] : '--') : '--', newValue: o[v.Code] ? o[v.Code] : '--',
oldValue: '' oldValue: ''
} }
} else if (row.OptType === 'Delete') { } else if (row.OptType === 'Delete') {
item = { item = {
oldValue: o[v.Code] ? (o[v.Code] ? o[v.Code] : '--') : '--', oldValue: o[v.Code] ? o[v.Code] : '--',
newValue: '--' newValue: '--'
} }
} else { } else {
item = { item = {
newValue: o[v.Code] ? (o[v.Code] ? o[v.Code] : '--') : '--', newValue: o[v.Code] ? o[v.Code] : '--',
oldValue: uo ? uo[v.Code] : '--' oldValue: uo ? uo[v.Code] ? uo[v.Code] : '--' : '--'
} }
} }
item.key = o ? ((o[v.Code] && o[v.Code] !== null && o[v.Code] !== '' || o[v.Code] !== 0) ? o[v.Code] : '--') : '--' item.key = o ? ((o[v.Code] && o[v.Code] !== null && o[v.Code] !== '' || o[v.Code] !== 0) ? o[v.Code] : '--') : '--'
@ -1019,21 +1025,21 @@ export default {
if (row.OptType === 'Add' || row.OptType === 'Init') { if (row.OptType === 'Add' || row.OptType === 'Init') {
item = { item = {
key: v.Code, key: v.Code,
Enum: v.ValueCN, Enum: this.$i18n.locale === 'zh' ? v.ValueCN : v.Value,
newValue: obj[v.Code] ? obj[v.Code] : '--', newValue: obj[v.Code] ? obj[v.Code] : '--',
oldValue: '' oldValue: ''
} }
} else if (row.OptType === 'Delete') { } else if (row.OptType === 'Delete') {
item = { item = {
key: v.Code, key: v.Code,
Enum: v.ValueCN, Enum: this.$i18n.locale === 'zh' ? v.ValueCN : v.Value,
oldValue: obj[v.Code] ? obj[v.Code] : '--', oldValue: obj[v.Code] ? obj[v.Code] : '--',
newValue: '--' newValue: '--'
} }
} else { } else {
item = { item = {
key: v.Code, key: v.Code,
Enum: v.ValueCN, Enum: this.$i18n.locale === 'zh' ? v.ValueCN : v.Value,
newValue: obj[v.Code] ? obj[v.Code] : '--', newValue: obj[v.Code] ? obj[v.Code] : '--',
oldValue: upObj[v.Code].length > 0 ? upObj[v.Code] : '--' oldValue: upObj[v.Code].length > 0 ? upObj[v.Code] : '--'
} }
@ -1051,23 +1057,23 @@ export default {
if (row.OptType === 'Add' || row.OptType === 'Init') { if (row.OptType === 'Add' || row.OptType === 'Init') {
item = { item = {
key: o[v.ChildDataLabel], key: o[v.ChildDataLabel],
Enum: o[v.ChildDataLabel], Enum: this.$i18n.locale === 'zh' ? o[v.ChildDataLabel] : o[v.ChildDataEnLabel] ? o[v.ChildDataEnLabel] : o[v.ChildDataLabel],
newValue: o[v.ChildDataValue] ? (o[v.ChildDataValue] ? o[v.ChildDataValue] : '--') : '--', newValue: o[v.ChildDataValue] ? o[v.ChildDataValue] : '--',
oldValue: '' oldValue: ''
} }
} else if (row.OptType === 'Delete') { } else if (row.OptType === 'Delete') {
item = { item = {
key: o[v.ChildDataLabel], key: o[v.ChildDataLabel],
Enum: o[v.ChildDataLabel], Enum: this.$i18n.locale === 'zh' ? o[v.ChildDataLabel] : o[v.ChildDataEnLabel] ? o[v.ChildDataEnLabel] : o[v.ChildDataLabel],
oldValue: o[v.ChildDataValue] ? (o[v.ChildDataValue] ? o[v.ChildDataValue] : '--') : '--', oldValue: o[v.ChildDataValue] ? o[v.ChildDataValue] : '--',
newValue: '--' newValue: '--'
} }
} else { } else {
item = { item = {
key: o[v.ChildDataLabel], key: o[v.ChildDataLabel],
Enum: o[v.ChildDataLabel], Enum: this.$i18n.locale === 'zh' ? o[v.ChildDataLabel] : o[v.ChildDataEnLabel] ? o[v.ChildDataEnLabel] : o[v.ChildDataLabel],
newValue: o[v.ChildDataValue] ? (o[v.ChildDataValue] ? o[v.ChildDataValue] : '--') : '--', newValue: o[v.ChildDataValue] ? o[v.ChildDataValue] : '--',
oldValue: uo ? uo[v.ChildDataValue] : '--' oldValue: uo ? uo[v.ChildDataValue] ? uo[v.ChildDataValue] : '--' : '--'
} }
} }
this[auditData].push(item) this[auditData].push(item)
@ -1084,7 +1090,7 @@ export default {
a = getToken() a = getToken()
} }
return v.UrlParameterName + '=' + a + '&' return v.UrlParameterName + '=' + a + '&'
}).toString().replaceAll(',', '') : v.UrlConfig.RoutePath, }).toString().replaceAll(',', '') + 'zh='+this.$i18n.locale : v.UrlConfig.RoutePath,
newValue: v.UrlConfig.IsHaveParameters ? v.UrlConfig.RoutePath + '?' + newValue: v.UrlConfig.IsHaveParameters ? v.UrlConfig.RoutePath + '?' +
v.UrlConfig.ParameterList.map((v) => { v.UrlConfig.ParameterList.map((v) => {
let a = obj[v.UrlParameterValueName] ? obj[v.UrlParameterValueName] : parentRow[v.UrlParameterValueName] let a = obj[v.UrlParameterValueName] ? obj[v.UrlParameterValueName] : parentRow[v.UrlParameterValueName]
@ -1092,7 +1098,7 @@ export default {
a = getToken() a = getToken()
} }
return v.UrlParameterName + '=' + a + '&' return v.UrlParameterName + '=' + a + '&'
}).toString().replaceAll(',', '') : v.UrlConfig.RoutePath }).toString().replaceAll(',', '') + 'zh='+this.$i18n.locale : v.UrlConfig.RoutePath
} }
console.log(item) console.log(item)
item.IsTableFiled = v.IsTableFiled item.IsTableFiled = v.IsTableFiled
@ -1111,10 +1117,10 @@ export default {
} else { } else {
if (j.ListName) { if (j.ListName) {
obj[v.Code][0][j.ListName].forEach((x, o) => { obj[v.Code][0][j.ListName].forEach((x, o) => {
head.push({IsPicture: j.IsPicture, headName: x[j.ColumnName], IsMerge: j.IsMerge, ColumnName: j.ColumnName, ColumnValue: j.ColumnValue, ListName: j.ListName, MergeColumnName: j.IsMerge ? this.$i18n.locale === 'zh' ? j.MergeColumnName : j.MergeColumnEnName : null, ChildrenList: []}) head.push({IsPicture: j.IsPicture, headName: x[this.$i18n.locale === 'zh' ? j.ColumnName : j.ColumnEnName ? j.ColumnEnName : j.ColumnName], IsMerge: j.IsMerge, ColumnName: j.ColumnName, ColumnValue: j.ColumnValue, ListName: j.ListName, MergeColumnName: j.IsMerge ? this.$i18n.locale === 'zh' ? j.MergeColumnName : j.MergeColumnEnName : null, ChildrenList: []})
}) })
} else { } else {
head.push({IsPicture: j.IsPicture, headName: j.ColumnName, IsMerge: j.IsMerge, ColumnName: j.ColumnName, ColumnValue: j.ColumnValue, ListName: j.ListName, MergeColumnName: j.IsMerge ? this.$i18n.locale === 'zh' ? j.MergeColumnName : j.MergeColumnEnName : null, ChildrenList: []}) head.push({IsPicture: j.IsPicture, headName: this.$i18n.locale === 'zh' ? j.ColumnName : j.ColumnEnName ? j.ColumnEnName : j.ColumnName, IsMerge: j.IsMerge, ColumnName: j.ColumnName, ColumnValue: j.ColumnValue, ListName: j.ListName, MergeColumnName: j.IsMerge ? this.$i18n.locale === 'zh' ? j.MergeColumnName : j.MergeColumnEnName : null, ChildrenList: []})
} }
} }
}) })
@ -1254,6 +1260,7 @@ export default {
}) })
}, },
async lookDetails2(row) { async lookDetails2(row) {
this.OptType2 = row.OptType
var Json = await this.getJSON(row) var Json = await this.getJSON(row)
var JsonDetail = Json[0] ? JSON.parse(Json[0]) : null var JsonDetail = Json[0] ? JSON.parse(Json[0]) : null
var ParentJson = Json[1] ? JSON.parse(Json[1]) : null var ParentJson = Json[1] ? JSON.parse(Json[1]) : null

View File

@ -9,7 +9,7 @@
<el-upload <el-upload
class="upload-demo" class="upload-demo"
action action
accept=".xlsx,.xls,.csv" accept=".xlsx,.xls"
:before-upload="beforeUpload" :before-upload="beforeUpload"
:http-request="handleUploadFile" :http-request="handleUploadFile"
:on-preview="handlePreview" :on-preview="handlePreview"
@ -72,7 +72,7 @@ export default {
this.$message.warning(this.$t('trials:consistencyCheck:message:onlyOneFile')) this.$message.warning(this.$t('trials:consistencyCheck:message:onlyOneFile'))
}, },
checkFileSuffix(fileName) { checkFileSuffix(fileName) {
var typeArr = ['xls', 'xlsx', 'csv'] var typeArr = ['xls', 'xlsx']
var extendName = fileName.substring(fileName.lastIndexOf('.') + 1).toLocaleLowerCase() var extendName = fileName.substring(fileName.lastIndexOf('.') + 1).toLocaleLowerCase()
if (typeArr.indexOf(extendName) !== -1) { if (typeArr.indexOf(extendName) !== -1) {
return true return true

View File

@ -13,7 +13,7 @@
<span style="font-weight:700;">{{ record.CreateUserName }} </span> <span style="font-weight:700;">{{ record.CreateUserName }} </span>
<span>({{ record.CreateTime }}) </span> <span>({{ record.CreateTime }}) </span>
</p> </p>
<div class="info-content" v-html="record.TalkContent" /> <div class="info-content" v-html="formattedText(record.TalkContent)" />
</div> </div>
</div> </div>
@ -23,7 +23,7 @@
<span style="font-weight:700;">{{ record.CreateUserName }} </span> <span style="font-weight:700;">{{ record.CreateUserName }} </span>
<span>({{ record.CreateTime }}) </span> <span>({{ record.CreateTime }}) </span>
</p> </p>
<div class="info-content" v-html="record.TalkContent" /> <div class="info-content" v-html="formattedText(record.TalkContent)" />
</div> </div>
<!-- <img :src="record.headUrl"> --> <!-- <img :src="record.headUrl"> -->
<img v-if="record.UserTypeEnum*1 === 8" :src="adminAvatar" alt="Admin"> <img v-if="record.UserTypeEnum*1 === 8" :src="adminAvatar" alt="Admin">
@ -231,6 +231,9 @@ export default {
this.getMessageList() this.getMessageList()
}, },
methods: { methods: {
formattedText(text) {
return text.replace(/\n/g, '<br>')
},
// //
getMessageList() { getMessageList() {
var recordContent = [] var recordContent = []

View File

@ -252,7 +252,7 @@
</div> </div>
<!-- PDF录入 --> <!-- PDF录入 -->
<div v-if="cd.ClinicalUploadType === 1"> <div v-if="cd.ClinicalUploadType === 1">
<div v-if="allowAddOrEdit" style="text-align: right"> <div v-if="allowAddOrEdit" style="display:flex;align-items:center;justify-content: flex-end;">
<!-- 下载模板 --> <!-- 下载模板 -->
<el-button <el-button
v-if="cd.Path" v-if="cd.Path"
@ -271,6 +271,7 @@
position: relative; position: relative;
overflow: hidden; overflow: hidden;
display: inline-block; display: inline-block;
margin-left:10px
" "
> >
<!-- 新增 --> <!-- 新增 -->

View File

@ -654,6 +654,7 @@ export default {
this.loading = true; this.loading = true;
this.data.TrialId = this.$route.query.trialId; this.data.TrialId = this.$route.query.trialId;
var param = { var param = {
SubjectVisitId: this.studyData.SubjectVisitId,
StudyId: this.studyData.StudyId, StudyId: this.studyData.StudyId,
TrialId: this.$route.query.trialId, TrialId: this.$route.query.trialId,
SubjectId: this.studyData.SubjectId, SubjectId: this.studyData.SubjectId,

View File

@ -13,7 +13,7 @@
<span style="font-weight:700;">{{ record.CreateUserName }} </span> <span style="font-weight:700;">{{ record.CreateUserName }} </span>
<span>({{ record.CreateTime }}) </span> <span>({{ record.CreateTime }}) </span>
</p> </p>
<div class="info-content" v-html="record.TalkContent" /> <div class="info-content" v-html="formattedText(record.TalkContent)" />
</div> </div>
</div> </div>
@ -23,7 +23,7 @@
<span style="font-weight:700;">{{ record.CreateUserName }} </span> <span style="font-weight:700;">{{ record.CreateUserName }} </span>
<span>({{ record.CreateTime }}) </span> <span>({{ record.CreateTime }}) </span>
</p> </p>
<div class="info-content" v-html="record.TalkContent" /> <div class="info-content" v-html="formattedText(record.TalkContent)" />
</div> </div>
<!-- <img :src="record.headUrl"> --> <!-- <img :src="record.headUrl"> -->
<img v-if="record.UserTypeEnum*1 === 8" :src="adminAvatar" alt="Admin"> <img v-if="record.UserTypeEnum*1 === 8" :src="adminAvatar" alt="Admin">
@ -153,6 +153,9 @@ export default {
close() { close() {
this.$emit('close') this.$emit('close')
}, },
formattedText(text) {
return text.replace(/\n/g, '<br>')
},
// //
getMessageList() { getMessageList() {
var recordContent = [] var recordContent = []

View File

@ -16,7 +16,7 @@ const name = process.env.NODE_ENV === 'usa' ? 'LILI' : defaultSettings.title ||
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
module.exports = { module.exports = {
// lintOnSave: false, // lintOnSave: false,
transpileDependencies: ['@cornerstonejs', 'minio'], transpileDependencies: ['@cornerstonejs', 'minio', '@aws-sdk', '@smithy'],
publicPath: process.env.NODE_ENV === 'development' || process.env.VUE_APP_OSS_CONFIG_BUCKET === 'zyypacs-usa' ? process.env.VUE_APP_BASE_PATH : `${process.env.VUE_FILE_PATH}${process.env.VUE_APP_OSS_PATH}${distDate}/`, publicPath: process.env.NODE_ENV === 'development' || process.env.VUE_APP_OSS_CONFIG_BUCKET === 'zyypacs-usa' ? process.env.VUE_APP_BASE_PATH : `${process.env.VUE_FILE_PATH}${process.env.VUE_APP_OSS_PATH}${distDate}/`,
// publicPath: '/', // publicPath: '/',
outputDir: 'dist', outputDir: 'dist',