Merge branch 'main' of http://192.168.3.68:2000/XCKJ/irc_web
continuous-integration/drone/push Build is running
Details
continuous-integration/drone/push Build is running
Details
commit
b8478e6451
|
|
@ -27,6 +27,7 @@
|
|||
"axios": "0.18.1",
|
||||
"babel-eslint": "7.2.3",
|
||||
"copy-webpack-plugin": "^4.5.2",
|
||||
"@aws-sdk/client-s3": "^3.370.0",
|
||||
"core-js": "^3.8.3",
|
||||
"cornerstone-core": "^2.6.1",
|
||||
"cornerstone-math": "^0.1.10",
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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' })
|
||||
}
|
||||
|
|
@ -8,11 +8,11 @@ export function requestPackageAndAnonymizImage(params) {
|
|||
})
|
||||
}
|
||||
// 获取影像上传列表
|
||||
export function getSubjectImageUploadList(params) {
|
||||
export function getSubjectImageUploadList(data) {
|
||||
return request({
|
||||
url: '/DownloadAndUpload/getSubjectImageUploadList',
|
||||
method: 'get',
|
||||
params
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 预上传
|
||||
|
|
@ -40,3 +40,43 @@ export function deleteTaskStudy(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
|
||||
})
|
||||
}
|
||||
|
|
@ -194,3 +194,10 @@ export function resetReadingTask(param) {
|
|||
data: param
|
||||
})
|
||||
}
|
||||
export function getTaskUploadedDicomStudyList(param) {
|
||||
return request({
|
||||
url: `/DownloadAndUpload/getTaskUploadedDicomStudyList`,
|
||||
method: 'post',
|
||||
data: param
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
url: `/NoneDicomStudy/getNoneDicomStudyList?subjectVisitId=${subjectVisitId}&nonedicomStudyId=${sudyId}&isFilterZip=${isFilterZip}`,
|
||||
url: `/NoneDicomStudy/getNoneDicomStudyList?subjectVisitId=${subjectVisitId}&nonedicomStudyId=${sudyId}&isFilterZip=${isFilterZip}&visitTaskId=${visitTaskId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,16 +81,25 @@
|
|||
<!-- <div v-show="stack.firstImageLoading" class="load-indicator">
|
||||
Loading Series #{{ stack.seriesNumber }}...
|
||||
</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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import Contextmenu from 'vue-contextmenujs'
|
||||
Vue.use(Contextmenu)
|
||||
import * as cornerstone from 'cornerstone-core'
|
||||
import * as cornerstoneMath from 'cornerstone-math'
|
||||
import * as cornerstoneTools from 'cornerstone-tools'
|
||||
|
||||
const scroll = cornerstoneTools.import('util/scrollToIndex')
|
||||
import Hammer from 'hammerjs'
|
||||
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()
|
||||
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
|
||||
import DicomTags from './DicomTags'
|
||||
export default {
|
||||
name: 'DicomCanvas',
|
||||
components: { DicomTags },
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
|
@ -164,7 +175,8 @@ export default {
|
|||
mousePosition: { x: '', y: '', mo: '' },
|
||||
markers: { top: '', right: '', bottom: '', left: '' },
|
||||
orientationMarkers: [],
|
||||
originalMarkers: []
|
||||
originalMarkers: [],
|
||||
dcmTag: { visible: false, title: this.$t('trials:dicom-tag:title') }
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -364,8 +376,8 @@ export default {
|
|||
if (this.dicomInfo.thick) {
|
||||
this.dicomInfo.thick = this.dicomInfo.thick.toFixed(2)
|
||||
}
|
||||
let newImageIdIndex = this.stack.imageIds.findIndex(i=>i===e.detail.image.imageId)
|
||||
if(newImageIdIndex === -1) return
|
||||
const newImageIdIndex = this.stack.imageIds.findIndex(i => i === e.detail.image.imageId)
|
||||
if (newImageIdIndex === -1) return
|
||||
this.stack.currentImageIdIndex = newImageIdIndex
|
||||
this.stack.imageIdIndex = newImageIdIndex
|
||||
this.series.imageIdIndex = newImageIdIndex
|
||||
|
|
@ -636,7 +648,7 @@ export default {
|
|||
enabledElement.renderingTools.renderCanvasData = renderCanvasData
|
||||
},
|
||||
scrollPage(offset) {
|
||||
if(this.loading) return
|
||||
if (this.loading) return
|
||||
var index = this.stack.currentImageIdIndex + offset
|
||||
if (index < 0) index = 0
|
||||
else if (index >= this.stack.imageIds.length) {
|
||||
|
|
@ -648,7 +660,7 @@ export default {
|
|||
},
|
||||
|
||||
toggleClipPlay() {
|
||||
if(this.loading) return
|
||||
if (this.loading) return
|
||||
if (this.toolState.clipPlaying) {
|
||||
cornerstoneTools.stopClip(this.canvas)
|
||||
this.toolState.clipPlaying = false
|
||||
|
|
@ -668,7 +680,7 @@ export default {
|
|||
resetWwwc() {
|
||||
this.toolState.viewportInvert = false
|
||||
var viewport = cornerstone.getViewport(this.canvas)
|
||||
viewport.invert = false
|
||||
// viewport.invert = false
|
||||
var image = cornerstone.getImage(this.canvas)
|
||||
viewport.voi.windowWidth = image.windowWidth
|
||||
viewport.voi.windowCenter = image.windowCenter
|
||||
|
|
@ -747,6 +759,9 @@ export default {
|
|||
var uid = cornerstone.getImage(this.canvas).data.string('x00080018')
|
||||
cornerstoneTools.SaveAs(this.canvas, `${uid}.png`)
|
||||
},
|
||||
showTags() {
|
||||
this.dcmTag.visible = true
|
||||
},
|
||||
fitToWindow() {
|
||||
if (this.stack.seriesNumber) {
|
||||
cornerstone.fitToWindow(this.canvas)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -233,6 +233,10 @@
|
|||
<button :title="$t('trials:dicom-show:image')" class="btn-link" @click="currentDicomCanvas.saveImage()">
|
||||
<svg-icon icon-class="image" style="font-size:20px;" />
|
||||
</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 class="measureTool-wrapper">
|
||||
|
|
@ -405,7 +409,7 @@ export default {
|
|||
loadImageStack(dicomSeries) {
|
||||
this.currentDicomCanvas.toolState.clipPlaying = false
|
||||
this.$nextTick(() => {
|
||||
let series = Object.assign({}, dicomSeries)
|
||||
const series = Object.assign({}, dicomSeries)
|
||||
this.currentDicomCanvas.loadImageStack(series)
|
||||
})
|
||||
},
|
||||
|
|
@ -416,7 +420,7 @@ export default {
|
|||
Array.from(elements).forEach((element, index) => {
|
||||
const canvasIndex = element.getAttribute('data-index')
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
}
|
||||
},
|
||||
// file上传到oss
|
||||
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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -102,7 +102,6 @@
|
|||
import uploadList from "./components/upload-list.vue";
|
||||
import studyView from "./components/study-view.vue";
|
||||
import { getSubjectImageUploadList, deleteTaskStudy } from "@/api/load.js";
|
||||
import { downloadImage } from "@/utils/uploadZip.js";
|
||||
import store from "@/store";
|
||||
export default {
|
||||
name: "uploadImage",
|
||||
|
|
@ -591,7 +590,7 @@ export default {
|
|||
files.push(obj);
|
||||
}
|
||||
store.dispatch("trials/setUnLock", true);
|
||||
let res = await downloadImage(zipName, files);
|
||||
// let res = await downloadImage(zipName, files);
|
||||
store.dispatch("trials/setUnLock", false);
|
||||
},
|
||||
},
|
||||
|
|
|
|||
35
src/main.js
35
src/main.js
|
|
@ -28,25 +28,22 @@ Vue.use(permission)
|
|||
|
||||
import Viewer from 'v-viewer'
|
||||
import './assets/css/viewer.css'
|
||||
|
||||
Vue.use(Viewer)
|
||||
Viewer.setDefaults({
|
||||
Options: {
|
||||
'inline': true,
|
||||
'button': true,
|
||||
'navbar': true,
|
||||
'title': true,
|
||||
'toolbar': true,
|
||||
'tooltip': true,
|
||||
'movable': true,
|
||||
'zoomable': true,
|
||||
'rotatable': true,
|
||||
'scalable': true,
|
||||
'transition': true,
|
||||
'keyboard': true,
|
||||
'url': 'data-source'
|
||||
// navbar: true, //底部缩略图
|
||||
toolbar: {
|
||||
zoomIn: true,
|
||||
zoomOut: true,
|
||||
reset: true,
|
||||
prev: true,
|
||||
next: true,
|
||||
rotateLeft: true,
|
||||
rotateRight: true,
|
||||
flipHorizontal: true,
|
||||
flipVertical: true,
|
||||
}
|
||||
})
|
||||
Vue.use(Viewer)
|
||||
|
||||
|
||||
import hasPermi from './directive/permission'
|
||||
Vue.use(hasPermi)
|
||||
|
|
@ -148,6 +145,12 @@ Vue.config.productionTip = false
|
|||
Vue.prototype.$upload = () => {
|
||||
_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) => {
|
||||
// 创建 FileReader 对象
|
||||
const reader = new FileReader()
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ import 'nprogress/nprogress.css'
|
|||
import { getToken } from '@/utils/auth'
|
||||
import Vue from 'vue'
|
||||
import { OSSclient } from './utils/oss'
|
||||
import WHITELIST from "./utils/whiteList"
|
||||
// import getPageTitle from '@/utils/get-page-title'
|
||||
|
||||
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;
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
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 === '/ReviewersResearch') {
|
||||
await this.$store.dispatch('user/logout')
|
||||
OSSclient()
|
||||
await OSSclient()
|
||||
}
|
||||
if (to.path === '/ReviewersResearchForm') {
|
||||
OSSclient()
|
||||
await OSSclient()
|
||||
}
|
||||
next()
|
||||
NProgress.done()
|
||||
} else {
|
||||
OSSclient()
|
||||
await OSSclient()
|
||||
const hasGetUserInfo = store.getters.userId
|
||||
if (hasGetUserInfo) {
|
||||
next()
|
||||
|
|
@ -66,7 +67,7 @@ router.beforeEach(async (to, from, next) => {
|
|||
} else {
|
||||
// 在免登录whiteList中,直接进入
|
||||
if (to.path === '/readingDicoms' || to.path === '/noneDicomReading') {
|
||||
OSSclient()
|
||||
await OSSclient()
|
||||
}
|
||||
next()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,26 +35,50 @@ const getDefaultState = () => {
|
|||
}
|
||||
}
|
||||
function getQuestions(questions) {
|
||||
const criterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||
questions.forEach(item => {
|
||||
if (item.Type === 'table' && item.TableQuestions && item.TableQuestions.Answers.length > 0) {
|
||||
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'
|
||||
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) {
|
||||
var idx = item.TableQuestions.Questions.findIndex(i => i.QuestionMark === 11)
|
||||
if (idx > -1) {
|
||||
if (criterionType === 10) {
|
||||
// pcwg
|
||||
var lesionNum = getQuestionAnswer(item.TableQuestions.Questions, 11, answerObj)
|
||||
answerObj.lesionNum = lesionNum
|
||||
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 {
|
||||
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
|
||||
}
|
||||
} else {
|
||||
|
|
@ -811,9 +835,16 @@ const actions = {
|
|||
// }
|
||||
series.InstanceInfoList.forEach(instance => {
|
||||
if (instance.NumberOfFrames && instance.NumberOfFrames > 1) {
|
||||
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)
|
||||
if (study.IsCriticalSequence && instance.KeyFramesList.length > 0) {
|
||||
instance.KeyFramesList.map(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)
|
||||
})
|
||||
} 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}`
|
||||
} else {
|
||||
|
|
@ -1053,7 +1084,10 @@ const actions = {
|
|||
return new Promise(resolve => {
|
||||
var isReadingTaskViewInOrder = localStorage.getItem('isReadingTaskViewInOrder')
|
||||
if (parseInt(isReadingTaskViewInOrder) === 2) {
|
||||
if (!state.lastCanvasTaskId) state.lastCanvasTaskId = taskId
|
||||
if (!state.lastCanvasTaskId) {
|
||||
console.log('setLastCanvasTaskId')
|
||||
state.lastCanvasTaskId = taskId
|
||||
}
|
||||
} else {
|
||||
state.lastCanvasTaskId = taskId
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const getDefaultState = () => {
|
|||
studyListQuery: null,
|
||||
unlock: false,
|
||||
config: {},
|
||||
uploadTip: null,
|
||||
uploadTip: '0.00KB/s',
|
||||
timer: null,
|
||||
whiteList: [],
|
||||
checkTaskId: null
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import Vue from 'vue'
|
||||
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 => {
|
||||
try {
|
||||
// let blob = await encoder(file, config)
|
||||
let blob = await fileToBlob(file)
|
||||
let blob = await fileToBlob(data.file)
|
||||
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({
|
||||
...res,
|
||||
image: blob.pixelDataElement
|
||||
|
|
@ -19,7 +19,7 @@ export const dcmUpload = async function (name, file, config) {
|
|||
|
||||
|
||||
} catch (e) {
|
||||
console.log(file, 'warning')
|
||||
console.log(data.file, 'warning')
|
||||
resolve(false)
|
||||
console.log(e)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
@ -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
232
src/utils/oss.js
232
src/utils/oss.js
|
|
@ -3,30 +3,32 @@ const router = require('@/router');
|
|||
const Minio = require('minio')
|
||||
const stream = require('stream')
|
||||
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 {
|
||||
S3Client,
|
||||
} = require("@aws-sdk/client-s3");
|
||||
|
||||
Vue.prototype.OSSclientConfig = {
|
||||
}
|
||||
|
||||
function blobToBuffer(blob, fileName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = new File([blob], fileName);
|
||||
resolve(file)
|
||||
})
|
||||
}
|
||||
|
||||
async function ossGenerateSTS() {
|
||||
let res = await GetObjectStoreToken()
|
||||
// res.Result.ObjectStoreUse = 'AWS';
|
||||
Vue.prototype.OSSclientConfig = { ...res.Result[res.Result.ObjectStoreUse] }
|
||||
Vue.prototype.OSSclientConfig.ObjectStoreUse = res.Result.ObjectStoreUse;
|
||||
Vue.prototype.OSSclientConfig.basePath = Vue.prototype.OSSclientConfig.viewEndpoint
|
||||
switch (res.Result.ObjectStoreUse) {
|
||||
case 'AliyunOSS':
|
||||
Vue.prototype.OSSclientConfig.bucket = Vue.prototype.OSSclientConfig.bucketName
|
||||
Vue.prototype.OSSclientConfig.stsToken = Vue.prototype.OSSclientConfig.securityToken
|
||||
Vue.prototype.OSSclientConfig.timeout = 10 * 60 * 1000
|
||||
let OSSclient = new OSS(Vue.prototype.OSSclientConfig)
|
||||
Vue.prototype.OSSclient = {
|
||||
put: function (objectName, object) {
|
||||
put: async function (objectName, object) {
|
||||
OSSclient = await RefreshClient(OSSclient)
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
let _vm = router.default.app
|
||||
|
|
@ -49,6 +51,46 @@ async function ossGenerateSTS() {
|
|||
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
|
||||
|
|
@ -86,49 +128,118 @@ async function ossGenerateSTS() {
|
|||
console.log(e)
|
||||
}
|
||||
})
|
||||
},
|
||||
close: () => {
|
||||
return false
|
||||
}
|
||||
}
|
||||
break
|
||||
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 = {
|
||||
put: function (objectName, object) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
var name = objectName.split('/')[objectName.split('/').length - 1]
|
||||
let _vm = router.default.app
|
||||
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload') {
|
||||
var objectItem = objectName.split('/')
|
||||
objectItem[objectItem.length - 1] = new Date().getTime() + '_' + objectItem[objectItem.length - 1]
|
||||
objectName = objectItem.join('/')
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = (ex) => {
|
||||
const bufferStream = new stream.PassThrough()
|
||||
bufferStream.end(Buffer.from(ex.target.result))
|
||||
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)
|
||||
}
|
||||
})
|
||||
put: async function (objectName, object) {
|
||||
let data = {
|
||||
file: object,
|
||||
path: objectName
|
||||
}
|
||||
aws = await RefreshClient(aws);
|
||||
return uploadAWS(aws, data, () => { });
|
||||
},
|
||||
multipartUpload: async (data, progress) => {
|
||||
aws = await RefreshClient(aws);
|
||||
return uploadAWS(aws, data, progress);
|
||||
},
|
||||
close: () => {
|
||||
AWSclose();
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
let str = bytes.split('?');
|
||||
let str2 = str[0].split('/');
|
||||
|
|
@ -138,6 +249,47 @@ function decodeUtf8(bytes) {
|
|||
str2.pop();
|
||||
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
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import axios from 'axios'
|
|||
import { Message, MessageBox, Alert } from 'element-ui'
|
||||
import store from '@/store'
|
||||
import router from '@/router'
|
||||
import Vue from 'vue'
|
||||
import WHITELIST from "./whiteList"
|
||||
import moment from 'moment-timezone';
|
||||
console.log(moment.tz.guess())
|
||||
axios.defaults.withCredentials = false
|
||||
|
|
@ -27,7 +27,10 @@ service.interceptors.request.use(
|
|||
}
|
||||
try {
|
||||
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
|
||||
}
|
||||
if (store.state.user.userId !== zzSessionStorage.getItem('userId')) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
})
|
||||
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<div class="sidePanelThumbs">
|
||||
<el-tabs v-model="activeName" type="border-card" @tab-click="handleTabClick">
|
||||
<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 }}
|
||||
</div>
|
||||
<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 { getVisitStudyList, getAllRelationStudyList, getSeriesList } from '@/api/reading'
|
||||
import { setSeriesStatus } from '@/api/trials'
|
||||
import { getTaskUploadedDicomStudyList } from '@/api/reading'
|
||||
import requestPoolManager from '@/utils/request-pool'
|
||||
import store from '@/store'
|
||||
import { changeURLStatic } from '@/utils/history.js'
|
||||
|
|
@ -301,7 +302,8 @@ export default {
|
|||
relationActiveName: [],
|
||||
showSeriesList: [],
|
||||
currentLoadIns: [],
|
||||
isFromCRCUpload: false
|
||||
isFromCRCUpload: false,
|
||||
visitTaskId: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -318,6 +320,7 @@ export default {
|
|||
this.isReading = this.$router.currentRoute.query.isReading ? this.$router.currentRoute.query.isReading * 1 : 0
|
||||
this.showDelete = parseInt(this.$router.currentRoute.query.showDelete)
|
||||
this.isFromCRCUpload = !!this.$router.currentRoute.query.isFromCRCUpload
|
||||
this.visitTaskId = this.$router.currentRoute.query.visitTaskId
|
||||
// cornerstone.events.addEventListener('cornerstoneimageloaded', this.cornerstoneImageLoaded)
|
||||
this.getStudiesInfo()
|
||||
cornerstone.events.addEventListener('cornerstoneimageloadprogress', this.cornerstoneimageloadprogress)
|
||||
|
|
@ -338,7 +341,12 @@ export default {
|
|||
async getStudiesInfo() {
|
||||
this.studyList = []
|
||||
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) {
|
||||
res.Result.forEach((study, studyIndex) => {
|
||||
const data = {}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
ref="sysTemplateFrom"
|
||||
v-loading="loading"
|
||||
:model="form"
|
||||
label-width="90px"
|
||||
label-width="140px"
|
||||
size="small"
|
||||
:rules="rules"
|
||||
class="upload-temporary-file"
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
<el-form-item label="业务场景: " prop="BusinessScenarioEnum">
|
||||
<el-select
|
||||
v-model="form.BusinessScenarioEnum"
|
||||
style="width:100%;"
|
||||
style="width: 100%"
|
||||
size="small"
|
||||
filterable
|
||||
>
|
||||
|
|
@ -44,12 +44,14 @@
|
|||
:on-exceed="handleExceed"
|
||||
:disabled="!form.FileTypeEnum || !form.BusinessScenarioEnum"
|
||||
>
|
||||
<el-button size="small" type="primary" :disabled="!form.FileTypeEnum || !form.BusinessScenarioEnum" :loading="btnLoading">Select</el-button>
|
||||
<span
|
||||
slot="tip"
|
||||
style="margin-left:10px;"
|
||||
class="el-upload__tip"
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
:disabled="!form.FileTypeEnum || !form.BusinessScenarioEnum"
|
||||
:loading="btnLoading"
|
||||
>Select</el-button
|
||||
>
|
||||
<span slot="tip" style="margin-left: 10px" class="el-upload__tip">
|
||||
(must be in xlsx/xls/doc/docx format)
|
||||
</span>
|
||||
</el-upload>
|
||||
|
|
@ -58,37 +60,61 @@
|
|||
<el-form-item label="文件名" prop="Name">
|
||||
<el-input v-model="form.Name" />
|
||||
</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-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-form-item>
|
||||
<el-form-item label="描述">
|
||||
<el-input
|
||||
v-model="form.Description"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 4}"
|
||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
||||
placeholder="请输入内容"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="base-dialog-footer" style="text-align:right;margin-top:10px;">
|
||||
<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>
|
||||
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
|
||||
<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-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
<script>
|
||||
import { addOrUpdateCommonDocument, uploadCommonDoc, Upload } from '@/api/dictionary'
|
||||
import {
|
||||
addOrUpdateCommonDocument,
|
||||
uploadCommonDoc,
|
||||
Upload,
|
||||
} from '@/api/dictionary'
|
||||
import { getBasicDataSelects } from '@/api/dictionary/dictionary'
|
||||
export default {
|
||||
name: 'TemplateForm',
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default() { return {} }
|
||||
}
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
@ -99,20 +125,30 @@ export default {
|
|||
FileTypeEnum: null,
|
||||
BusinessScenarioEnum: null,
|
||||
Name: '',
|
||||
NameCN: '',
|
||||
Path: '',
|
||||
Description: '',
|
||||
IsDeleted: false
|
||||
IsDeleted: false,
|
||||
},
|
||||
rules: {
|
||||
Code: [{ required: true, message: 'Please specify', trigger: ['blur'] }],
|
||||
Name: [{ required: true, message: 'Please specify', trigger: ['blur'] }],
|
||||
BusinessScenarioEnum: [{ required: true, message: 'Please select', trigger: ['blur'] }]
|
||||
Code: [
|
||||
{ required: true, message: 'Please specify', 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: [],
|
||||
btnLoading: false,
|
||||
saveBtnLoading: false,
|
||||
loading: false,
|
||||
dictionaryList: {}
|
||||
dictionaryList: {},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -128,8 +164,8 @@ export default {
|
|||
name: this.data.Name,
|
||||
path: this.data.Path,
|
||||
url: this.data.Path,
|
||||
type: this.data.Type
|
||||
}
|
||||
type: this.data.Type,
|
||||
},
|
||||
]
|
||||
}
|
||||
for (const k in this.form) {
|
||||
|
|
@ -142,12 +178,14 @@ export default {
|
|||
// 获取文件类型下拉框
|
||||
getDicData() {
|
||||
this.loading = true
|
||||
getBasicDataSelects(['Common_File_ModuleType', 'Common_File_Type']).then(res => {
|
||||
this.dictionaryList = { ...res.Result }
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
getBasicDataSelects(['Common_File_ModuleType', 'Common_File_Type'])
|
||||
.then((res) => {
|
||||
this.dictionaryList = { ...res.Result }
|
||||
this.loading = false
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
beforeUpload(file) {
|
||||
// 检测文件类型是否符合要求
|
||||
|
|
@ -165,35 +203,43 @@ export default {
|
|||
const formData = new FormData()
|
||||
formData.append('file', param.file)
|
||||
this.form.FileName = param.file.name
|
||||
Upload(formData, 1).then(res => {
|
||||
this.fileList.push({ name: param.file.name, path: res.Result.FilePath, fullPath: res.Result.FullFilePath, url: res.Result.FilePath })
|
||||
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.form.Path = res.Result.FilePath
|
||||
this.form.Name = param.file.name
|
||||
this.form.NameCN = param.file.name
|
||||
this.loading = false
|
||||
this.btnLoading = false
|
||||
})
|
||||
},
|
||||
handleSave() {
|
||||
this.$refs.sysTemplateFrom.validate(valid => {
|
||||
this.$refs.sysTemplateFrom.validate((valid) => {
|
||||
if (!valid) return
|
||||
if (!this.form.Name) {
|
||||
this.$alert('Please select file.')
|
||||
return
|
||||
}
|
||||
this.saveBtnLoading = true
|
||||
addOrUpdateCommonDocument(this.form).then(res => {
|
||||
this.saveBtnLoading = false
|
||||
this.$emit('closeDialog')
|
||||
this.$emit('getList')
|
||||
this.$message.success('Uploaded successfully')
|
||||
}).catch(() => {
|
||||
this.saveBtnLoading = false
|
||||
})
|
||||
addOrUpdateCommonDocument(this.form)
|
||||
.then((res) => {
|
||||
this.saveBtnLoading = false
|
||||
this.$emit('closeDialog')
|
||||
this.$emit('getList')
|
||||
this.$message.success('Uploaded successfully')
|
||||
})
|
||||
.catch(() => {
|
||||
this.saveBtnLoading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
handleRemoveFile() {
|
||||
this.fileList = []
|
||||
this.form.Path = ''
|
||||
this.form.NameCN = ''
|
||||
this.form.Name = ''
|
||||
},
|
||||
handlePreview(file) {
|
||||
|
|
@ -206,19 +252,21 @@ export default {
|
|||
},
|
||||
checkFileSuffix(fileName) {
|
||||
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) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.upload-temporary-file{
|
||||
.upload-temporary-file {
|
||||
.upload-container .el-upload--text {
|
||||
border: none;
|
||||
width: 80px;
|
||||
|
|
@ -231,8 +279,8 @@ export default {
|
|||
color: #428bca;
|
||||
font-size: 13px;
|
||||
}
|
||||
.account_item_clear{
|
||||
.el-tag__close{
|
||||
.account_item_clear {
|
||||
.el-tag__close {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<el-form-item label="业务场景">
|
||||
<el-select
|
||||
v-model="searchData.BusinessScenarioEnum"
|
||||
style="width:150px;"
|
||||
style="width: 150px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item of $d.Common_File_BusinessScenario"
|
||||
|
|
@ -13,15 +13,10 @@
|
|||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="文件名称">
|
||||
<el-input
|
||||
v-model="searchData.Name"
|
||||
style="width:130px;"
|
||||
clearable
|
||||
/>
|
||||
<el-input v-model="searchData.Name" style="width: 130px" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
|
|
@ -30,24 +25,28 @@
|
|||
{{ $t('common:button:search') }}
|
||||
</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') }}
|
||||
</el-button>
|
||||
</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-button
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
style="margin-left:auto;"
|
||||
size="small"
|
||||
@click="handleAdd"
|
||||
>
|
||||
{{ $t('common:button:new') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<template slot="main-container">
|
||||
<el-table
|
||||
v-adaptive="{bottomOffset:60}"
|
||||
v-adaptive="{ bottomOffset: 60 }"
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
stripe
|
||||
|
|
@ -69,9 +68,13 @@
|
|||
sortable="custom"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
{{ $fd('Common_File_BusinessScenario',scope.row.BusinessScenarioEnum) }}
|
||||
{{
|
||||
$fd(
|
||||
'Common_File_BusinessScenario',
|
||||
scope.row.BusinessScenarioEnum
|
||||
)
|
||||
}}
|
||||
</template>
|
||||
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
|
|
@ -80,6 +83,12 @@
|
|||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="NameCN"
|
||||
:label="$t('dictionary:attachment:upload:table:nameCN')"
|
||||
show-overflow-tooltip
|
||||
sortable="custom"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="Description"
|
||||
label="描述"
|
||||
|
|
@ -92,8 +101,12 @@
|
|||
sortable="custom"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.IsDeleted" type="danger">{{ $fd('YesOrNo', scope.row.IsDeleted) }}</el-tag>
|
||||
<el-tag v-else type="primary">{{ $fd('YesOrNo', scope.row.IsDeleted) }}</el-tag>
|
||||
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
|
||||
$fd('YesOrNo', scope.row.IsDeleted)
|
||||
}}</el-tag>
|
||||
<el-tag v-else type="primary">{{
|
||||
$fd('YesOrNo', scope.row.IsDeleted)
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
|
|
@ -105,29 +118,26 @@
|
|||
|
||||
<el-table-column label="Action">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleDownload(scope.row)"
|
||||
>
|
||||
<el-button type="text" @click="handleDownload(scope.row)">
|
||||
下载
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
<el-button type="text" @click="handleEdit(scope.row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@click="handleDelete(scope.row)"
|
||||
>
|
||||
<el-button type="text" @click="handleDelete(scope.row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize" @pagination="getList" />
|
||||
<pagination
|
||||
class="page"
|
||||
:total="total"
|
||||
:page.sync="searchData.PageIndex"
|
||||
:limit.sync="searchData.PageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 新增/编辑 -->
|
||||
<el-dialog
|
||||
|
|
@ -138,13 +148,21 @@
|
|||
width="600px"
|
||||
custom-class="base-dialog-wrapper"
|
||||
>
|
||||
<TemplateForm :data="currentRow" @closeDialog="closeDialog" @getList="getList" />
|
||||
<TemplateForm
|
||||
:data="currentRow"
|
||||
@closeDialog="closeDialog"
|
||||
@getList="getList"
|
||||
/>
|
||||
</el-dialog>
|
||||
</template>
|
||||
</BaseContainer>
|
||||
</template>
|
||||
<script>
|
||||
import { getCommonDocumentList, DownloadCommonDoc, deleteCommonDocument } from '@/api/dictionary'
|
||||
import {
|
||||
getCommonDocumentList,
|
||||
DownloadCommonDoc,
|
||||
deleteCommonDocument,
|
||||
} from '@/api/dictionary'
|
||||
import BaseContainer from '@/components/BaseContainer'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import TemplateForm from './TemplateForm'
|
||||
|
|
@ -155,7 +173,7 @@ const searchDataDefault = () => {
|
|||
BusinessScenarioEnum: null,
|
||||
Name: '',
|
||||
PageIndex: 1,
|
||||
PageSize: 20
|
||||
PageSize: 20,
|
||||
}
|
||||
}
|
||||
export default {
|
||||
|
|
@ -168,7 +186,7 @@ export default {
|
|||
total: 0,
|
||||
currentRow: {},
|
||||
editDialog: { title: '', visible: false },
|
||||
loading: false
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -185,13 +203,15 @@ export default {
|
|||
},
|
||||
getList() {
|
||||
this.loading = true
|
||||
getCommonDocumentList(this.searchData).then(res => {
|
||||
this.loading = false
|
||||
this.list = res.Result.CurrentPageData
|
||||
this.total = res.Result.TotalCount
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
getCommonDocumentList(this.searchData)
|
||||
.then((res) => {
|
||||
this.loading = false
|
||||
this.list = res.Result.CurrentPageData
|
||||
this.total = res.Result.TotalCount
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 新增
|
||||
handleAdd() {
|
||||
|
|
@ -202,9 +222,13 @@ export default {
|
|||
// 下载
|
||||
handleDownload(row) {
|
||||
this.loading = true
|
||||
DownloadCommonDoc(row.Code).then(data => {
|
||||
this.loading = false
|
||||
}).catch(() => { this.loading = false })
|
||||
DownloadCommonDoc(row.Code)
|
||||
.then((data) => {
|
||||
this.loading = false
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 编辑
|
||||
handleEdit(row) {
|
||||
|
|
@ -233,7 +257,12 @@ export default {
|
|||
this.searchData.SortField = column.prop
|
||||
this.searchData.PageIndex = 1
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .search {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||
<el-row>
|
||||
<el-col v-show="title !== '复制'" :span="24">
|
||||
<el-divider content-position="left">基本信息</el-divider>
|
||||
|
|
@ -142,11 +142,16 @@
|
|||
<el-input v-model="form.Identification" placeholder="请输入标识" />
|
||||
</el-form-item>
|
||||
</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-input v-model="form.Code" placeholder="请输入字段key" />
|
||||
</el-form-item>
|
||||
</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-form-item label="字段英文">
|
||||
<el-input v-model="form.Value" placeholder="请输入字段英文" />
|
||||
|
|
@ -392,6 +397,16 @@
|
|||
<el-input :disabled="scope.row.IsFixedColumn" v-model="scope.row.ColumnName" placeholder="列字段名"/>
|
||||
</template>
|
||||
</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
|
||||
prop="ColumnValue"
|
||||
min-width="120"
|
||||
|
|
@ -509,6 +524,14 @@
|
|||
<el-input v-model="form.ChildDataLabel" placeholder="请输入子数据Lable" />
|
||||
</el-form-item>
|
||||
</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-form-item>
|
||||
<span slot="label">
|
||||
|
|
@ -668,6 +691,7 @@
|
|||
height="100"
|
||||
>
|
||||
<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="ValueCN" label="字段中文" min-width="120px" :show-overflow-tooltip="true" />
|
||||
<el-table-column
|
||||
|
|
@ -848,6 +872,7 @@ export default {
|
|||
FixedColumnName: null,
|
||||
FixedColumnEnName: null,
|
||||
ColumnName: null,
|
||||
ColumnEnName: null,
|
||||
ColumnValue: null,
|
||||
IsMerge: false,
|
||||
MergeColumnName: null,
|
||||
|
|
@ -1124,6 +1149,7 @@ export default {
|
|||
IsShowParent: 0,
|
||||
Sort: 0,
|
||||
Code: null,
|
||||
CodeEn: null,
|
||||
Value: null,
|
||||
ValueCN: null,
|
||||
EnumType: '',
|
||||
|
|
@ -1138,6 +1164,7 @@ export default {
|
|||
IsSpecialType: false,
|
||||
DataType: '',
|
||||
ChildDataLabel: null,
|
||||
ChildDataEnLabel: null,
|
||||
ChildDataValue: null,
|
||||
DateType: null,
|
||||
DictionaryCode: null,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,15 @@
|
|||
>
|
||||
<div class="base-dialog-body">
|
||||
<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
|
||||
v-for="item of $d.Criterion_Question_Type"
|
||||
:key="item.value"
|
||||
|
|
@ -31,10 +39,7 @@
|
|||
v-if="form.Type === 'group'"
|
||||
prop="GroupClassify"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.GroupClassify"
|
||||
clearable
|
||||
>
|
||||
<el-select v-model="form.GroupClassify" clearable>
|
||||
<el-option
|
||||
v-for="item of groupClassifyList"
|
||||
:key="item.Id"
|
||||
|
|
@ -70,13 +75,9 @@
|
|||
v-if="form.Type === 'number' || form.Type === 'calculation'"
|
||||
label="数值类型"
|
||||
prop="ValueType"
|
||||
:rules="[
|
||||
{ required: true, message: '请选择'}
|
||||
]"
|
||||
:rules="[{ required: true, message: '请选择' }]"
|
||||
>
|
||||
<el-radio-group
|
||||
v-model="form.ValueType"
|
||||
>
|
||||
<el-radio-group v-model="form.ValueType">
|
||||
<el-radio
|
||||
v-for="item of $d.ValueType"
|
||||
:key="item.id"
|
||||
|
|
@ -92,9 +93,7 @@
|
|||
v-if="form.Type === 'number' || form.Type === 'calculation'"
|
||||
label="单位"
|
||||
>
|
||||
<el-radio-group
|
||||
v-model="form.Unit"
|
||||
>
|
||||
<el-radio-group v-model="form.Unit">
|
||||
<el-radio
|
||||
v-for="item of $d.ValueUnit"
|
||||
:key="item.id"
|
||||
|
|
@ -109,15 +108,12 @@
|
|||
label="表格类型标识"
|
||||
prop="LesionType"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.LesionType"
|
||||
clearable
|
||||
>
|
||||
<el-select v-model="form.LesionType" clearable>
|
||||
<el-option
|
||||
v-for="item of lesionTypes"
|
||||
:key="item.Code"
|
||||
:value="parseInt(item.Code)"
|
||||
:label="$fd('LesionType',parseInt(item.Code))"
|
||||
:label="$fd('LesionType', parseInt(item.Code))"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
|
@ -133,25 +129,27 @@
|
|||
</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="选项类型"
|
||||
prop="QuestionGenre"
|
||||
:rules="[
|
||||
{ required: form.Type !== 'calculation', message: '请选择'}
|
||||
]"
|
||||
:rules="[{ required: form.Type !== 'calculation', message: '请选择' }]"
|
||||
>
|
||||
<el-radio-group
|
||||
v-model="form.QuestionGenre"
|
||||
@change="((val)=>{questionGenreChange(val, form)})"
|
||||
@change="
|
||||
(val) => {
|
||||
questionGenreChange(val, form)
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-radio
|
||||
:label="-1"
|
||||
>
|
||||
无
|
||||
</el-radio>
|
||||
<el-radio :label="-1"> 无 </el-radio>
|
||||
<el-radio
|
||||
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"
|
||||
:label="item.value"
|
||||
>
|
||||
|
|
@ -183,13 +181,8 @@
|
|||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="转化显示类型"
|
||||
prop="ConvertShowType"
|
||||
>
|
||||
<el-radio-group
|
||||
v-model="form.ConvertShowType"
|
||||
>
|
||||
<el-form-item label="转化显示类型" prop="ConvertShowType">
|
||||
<el-radio-group v-model="form.ConvertShowType">
|
||||
<el-radio
|
||||
v-for="item of $d.ConvertShowType"
|
||||
:key="item.id"
|
||||
|
|
@ -200,11 +193,19 @@
|
|||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="form.QuestionGenre === 3 "
|
||||
v-if="form.QuestionGenre === 3"
|
||||
label="关联字典"
|
||||
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
|
||||
v-for="item of dicList"
|
||||
:key="item.Id"
|
||||
|
|
@ -213,10 +214,7 @@
|
|||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="form.QuestionGenre === 3 "
|
||||
label="默认值"
|
||||
>
|
||||
<el-form-item v-if="form.QuestionGenre === 3" label="默认值">
|
||||
<el-select v-model="form.DefaultValue" clearable>
|
||||
<el-option
|
||||
v-for="item of form.DictionaryCode ? $d[form.DictionaryCode] : []"
|
||||
|
|
@ -226,10 +224,7 @@
|
|||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="form.QuestionGenre === 0 "
|
||||
label="默认值"
|
||||
>
|
||||
<el-form-item v-if="form.QuestionGenre === 0" label="默认值">
|
||||
<el-select v-model="form.DefaultValue" clearable>
|
||||
<el-option
|
||||
v-for="item of form.TypeValue ? form.TypeValue.split('|') : []"
|
||||
|
|
@ -240,10 +235,18 @@
|
|||
</el-select>
|
||||
</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
|
||||
v-model="form.ShowQuestion"
|
||||
@change="((val)=>{isShowQuestionChange(val, form)})"
|
||||
@change="
|
||||
(val) => {
|
||||
isShowQuestionChange(val, form)
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-radio
|
||||
v-for="item of $d.ShowQuestion"
|
||||
|
|
@ -257,14 +260,18 @@
|
|||
|
||||
<!-- 显示时依赖父问题 -->
|
||||
<el-form-item
|
||||
v-if="form.Type !== 'group' && form.ShowQuestion===1"
|
||||
v-if="form.Type !== 'group' && form.ShowQuestion === 1"
|
||||
label="显示依赖父问题"
|
||||
prop="ParentId"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.ParentId"
|
||||
clearable
|
||||
@change="((val)=>{parentQuestionChange(val, form)})"
|
||||
@change="
|
||||
(val) => {
|
||||
parentQuestionChange(val, form)
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-option
|
||||
v-for="item of parentOptions"
|
||||
|
|
@ -275,15 +282,19 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 显示时依赖父问题触发值 -->
|
||||
<el-form-item v-if="form.ParentId && form.ShowQuestion===1" label="显示触发值" prop="ParentTriggerValueList">
|
||||
<!-- <el-select v-model="form.ParentTriggerValue" clearable>-->
|
||||
<!-- <el-option-->
|
||||
<!-- v-for="item of parentTriggerValOptions"-->
|
||||
<!-- :key="item.id"-->
|
||||
<!-- :label="item.label"-->
|
||||
<!-- :value="item.value.toString()"-->
|
||||
<!-- />-->
|
||||
<!-- </el-select>-->
|
||||
<el-form-item
|
||||
v-if="form.ParentId && form.ShowQuestion === 1"
|
||||
label="显示触发值"
|
||||
prop="ParentTriggerValueList"
|
||||
>
|
||||
<!-- <el-select v-model="form.ParentTriggerValue" clearable>-->
|
||||
<!-- <el-option-->
|
||||
<!-- v-for="item of parentTriggerValOptions"-->
|
||||
<!-- :key="item.id"-->
|
||||
<!-- :label="item.label"-->
|
||||
<!-- :value="item.value.toString()"-->
|
||||
<!-- />-->
|
||||
<!-- </el-select>-->
|
||||
<el-select v-model="form.ParentTriggerValueList" clearable multiple>
|
||||
<el-option
|
||||
v-for="item of parentTriggerValOptions"
|
||||
|
|
@ -293,16 +304,44 @@
|
|||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.Type === 'select' || form.Type === 'radio' || form.Type === 'calculation'" 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-form-item
|
||||
v-if="
|
||||
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-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
|
||||
v-model="form.IsRequired"
|
||||
:disabled="form.IsJudgeQuestion===true || form.ShowQuestion===2"
|
||||
@change="((val)=>{isRequiredChange(val, form)})"
|
||||
:disabled="form.IsJudgeQuestion === true || form.ShowQuestion === 2"
|
||||
@change="
|
||||
(val) => {
|
||||
isRequiredChange(val, form)
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-radio
|
||||
v-for="item of $d.QuestionRequired"
|
||||
|
|
@ -323,7 +362,11 @@
|
|||
<el-select
|
||||
v-model="form.RelevanceId"
|
||||
clearable
|
||||
@change="((val)=>{relevanceQuestionChange(val, form)})"
|
||||
@change="
|
||||
(val) => {
|
||||
relevanceQuestionChange(val, form)
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-option
|
||||
v-for="item of parentOptions"
|
||||
|
|
@ -339,14 +382,14 @@
|
|||
label="必填触发值"
|
||||
prop="RelevanceValueList"
|
||||
>
|
||||
<!-- <el-select v-model="form.RelevanceValue" clearable>-->
|
||||
<!-- <el-option-->
|
||||
<!-- v-for="item of reParentTriggerValOptions"-->
|
||||
<!-- :key="item.id"-->
|
||||
<!-- :label="item.label"-->
|
||||
<!-- :value="item.value.toString()"-->
|
||||
<!-- />-->
|
||||
<!-- </el-select>-->
|
||||
<!-- <el-select v-model="form.RelevanceValue" clearable>-->
|
||||
<!-- <el-option-->
|
||||
<!-- v-for="item of reParentTriggerValOptions"-->
|
||||
<!-- :key="item.id"-->
|
||||
<!-- :label="item.label"-->
|
||||
<!-- :value="item.value.toString()"-->
|
||||
<!-- />-->
|
||||
<!-- </el-select>-->
|
||||
<el-select v-model="form.RelevanceValueList" clearable multiple>
|
||||
<el-option
|
||||
v-for="item of reParentTriggerValOptions"
|
||||
|
|
@ -385,7 +428,11 @@
|
|||
</el-form-item> -->
|
||||
|
||||
<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
|
||||
v-for="group of groupOptions"
|
||||
:key="group.GroupId"
|
||||
|
|
@ -396,12 +443,22 @@
|
|||
</el-form-item>
|
||||
<el-form-item label="限制编辑">
|
||||
<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-form-item>
|
||||
<el-form-item label="全局阅片是否显示">
|
||||
<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-form-item>
|
||||
<el-form-item
|
||||
|
|
@ -409,10 +466,7 @@
|
|||
v-if="form.Type !== 'group'"
|
||||
prop="QuestionType"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.QuestionType"
|
||||
clearable
|
||||
>
|
||||
<el-select v-model="form.QuestionType" clearable>
|
||||
<el-option
|
||||
v-for="item of CriterionDictionaryList.QuestionType"
|
||||
:key="item.Id"
|
||||
|
|
@ -428,9 +482,18 @@
|
|||
</el-radio-group>
|
||||
</el-form-item> -->
|
||||
<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 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>
|
||||
<template v-if="form.TypeValue">
|
||||
<el-option
|
||||
|
|
@ -471,20 +534,23 @@
|
|||
|
||||
<el-form-item label="是否在阅片页面显示">
|
||||
<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-form-item>
|
||||
<el-form-item
|
||||
:label="$t('trials:readingUnit:qsList:title:Remark')"
|
||||
prop="Remark"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.Remark"
|
||||
/>
|
||||
<el-input v-model="form.Remark" />
|
||||
</el-form-item>
|
||||
</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-button
|
||||
|
|
@ -496,7 +562,12 @@
|
|||
{{ $t('common:button:cancel') }}
|
||||
</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') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
|
@ -504,19 +575,30 @@
|
|||
</el-form>
|
||||
</template>
|
||||
<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'
|
||||
export default {
|
||||
name: 'AddOrUpdateClinicalData',
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default() { return {} }
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default() { return '' }
|
||||
}
|
||||
default() {
|
||||
return ''
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
var validateTypeVal = (rule, value, callback) => {
|
||||
|
|
@ -553,7 +635,7 @@ export default {
|
|||
IsJudgeQuestion: false,
|
||||
GroupName: '',
|
||||
GroupEnName: '',
|
||||
GroupClassify:null,
|
||||
GroupClassify: null,
|
||||
Remark: '',
|
||||
ImageCount: 1,
|
||||
RelevanceId: '',
|
||||
|
|
@ -570,32 +652,38 @@ export default {
|
|||
GroupId: null,
|
||||
ConvertShowType: 0,
|
||||
QuestionClassify: null,
|
||||
HighlightAnswerList: []
|
||||
HighlightAnswerList: [],
|
||||
},
|
||||
rules: {
|
||||
Type: [
|
||||
{ required: true, message: '请选择', trigger: 'blur' }
|
||||
Type: [{ 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' }],
|
||||
TypeValue: [{ required: true, message: '请注明', trigger: 'blur' },
|
||||
TypeValue: [
|
||||
{ required: true, message: '请注明', trigger: 'blur' },
|
||||
{ validator: validateTypeVal, trigger: 'blur' },
|
||||
{ max: 500, message: '最大长度为 500' }],
|
||||
DictionaryCode: [{ required: true, message: '请选择', trigger: 'blur' }],
|
||||
{ max: 500, message: '最大长度为 500' },
|
||||
],
|
||||
DictionaryCode: [
|
||||
{ required: true, message: '请选择', trigger: 'blur' },
|
||||
],
|
||||
ShowQuestion: [{ required: true, message: '请选择', trigger: 'blur' }],
|
||||
IsRequired: [{ required: true, message: '请选择', trigger: 'blur' }],
|
||||
ParentId: [{ required: true, message: '请选择', trigger: 'blur' }],
|
||||
ParentTriggerValueList: [
|
||||
{ required: true, message: '请选择', trigger: 'blur' }
|
||||
{ required: true, message: '请选择', trigger: 'blur' },
|
||||
],
|
||||
RelevanceId: [{ required: true, message: '请选择', trigger: 'blur' }],
|
||||
RelevanceValueList: [{ required: true, message: '请选择', trigger: 'blur' }],
|
||||
GroupName: [{ required: true, message: '请注明', trigger: 'blur' },
|
||||
{ max: 50, message: '最大长度为 50' }]
|
||||
RelevanceValueList: [
|
||||
{ required: true, message: '请选择', trigger: 'blur' },
|
||||
],
|
||||
GroupName: [
|
||||
{ required: true, message: '请注明', trigger: 'blur' },
|
||||
{ max: 50, message: '最大长度为 50' },
|
||||
],
|
||||
},
|
||||
loading: false,
|
||||
btnLoading: false,
|
||||
|
|
@ -606,8 +694,8 @@ export default {
|
|||
lesionTypes: [],
|
||||
dicList: [],
|
||||
CriterionDictionaryList: [],
|
||||
groupClassifyList:[],
|
||||
highlightAnswers: []
|
||||
groupClassifyList: [],
|
||||
highlightAnswers: [],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -622,14 +710,14 @@ export default {
|
|||
}
|
||||
let res = await getCriterionDictionary({
|
||||
ReadingCriterionId: this.data.ReadingQuestionCriterionSystemId,
|
||||
DictionaryCode: this.form.DictionaryCode
|
||||
DictionaryCode: this.form.DictionaryCode,
|
||||
})
|
||||
this.highlightAnswers = res.Result[this.form.DictionaryCode]
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initForm()
|
||||
|
|
@ -638,16 +726,16 @@ export default {
|
|||
getCriterionDictionary() {
|
||||
getCriterionDictionary({
|
||||
ReadingCriterionId: this.data.ReadingQuestionCriterionSystemId,
|
||||
DictionaryCode: 'QuestionType'
|
||||
}).then(res => {
|
||||
DictionaryCode: 'QuestionType',
|
||||
}).then((res) => {
|
||||
this.CriterionDictionaryList = res.Result
|
||||
})
|
||||
},
|
||||
getGroupClassifyDictionary() {
|
||||
getCriterionDictionary({
|
||||
ReadingCriterionId: this.data.ReadingQuestionCriterionSystemId,
|
||||
DictionaryCode: 'GroupClassify'
|
||||
}).then(res => {
|
||||
DictionaryCode: 'GroupClassify',
|
||||
}).then((res) => {
|
||||
this.groupClassifyList = res.Result.GroupClassify
|
||||
})
|
||||
},
|
||||
|
|
@ -661,37 +749,47 @@ export default {
|
|||
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
|
||||
}
|
||||
if (this.form.ParentId) {
|
||||
var index = this.parentOptions.findIndex(item => {
|
||||
var index = this.parentOptions.findIndex((item) => {
|
||||
return item.QuestionId === this.form.ParentId
|
||||
})
|
||||
if (index !== -1) {
|
||||
if (this.parentOptions[index].QuestionGenre === 3) {
|
||||
this.parentTriggerValOptions = this.$d[this.parentOptions[index].DictionaryCode]
|
||||
this.parentTriggerValOptions =
|
||||
this.$d[this.parentOptions[index].DictionaryCode]
|
||||
} else {
|
||||
const options = []
|
||||
this.parentOptions[index].TypeValue.split('|').forEach((item, index) => {
|
||||
options.push({ id: index, label: item, value: item })
|
||||
})
|
||||
this.parentOptions[index].TypeValue.split('|').forEach(
|
||||
(item, index) => {
|
||||
options.push({ id: index, label: item, value: item })
|
||||
}
|
||||
)
|
||||
this.parentTriggerValOptions = options
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.form.RelevanceId) {
|
||||
var index = this.parentOptions.findIndex(item => {
|
||||
var index = this.parentOptions.findIndex((item) => {
|
||||
return item.QuestionId === this.form.RelevanceId
|
||||
})
|
||||
if (index !== -1) {
|
||||
if (this.parentOptions[index].QuestionGenre === 3) {
|
||||
this.reParentTriggerValOptions = this.$d[this.parentOptions[index].DictionaryCode]
|
||||
this.reParentTriggerValOptions =
|
||||
this.$d[this.parentOptions[index].DictionaryCode]
|
||||
} else {
|
||||
const options = []
|
||||
this.parentOptions[index].TypeValue.split('|').forEach((item, index) => {
|
||||
options.push({ id: index, label: item, value: item })
|
||||
})
|
||||
this.parentOptions[index].TypeValue.split('|').forEach(
|
||||
(item, index) => {
|
||||
options.push({ id: index, label: item, value: item })
|
||||
}
|
||||
)
|
||||
this.reParentTriggerValOptions = options
|
||||
}
|
||||
}
|
||||
|
|
@ -701,18 +799,19 @@ export default {
|
|||
this.getGroupClassifyDictionary()
|
||||
},
|
||||
save() {
|
||||
this.$refs.clinicalDataForm.validate(valid => {
|
||||
this.$refs.clinicalDataForm.validate((valid) => {
|
||||
if (!valid) return
|
||||
this.btnLoading = true
|
||||
if (this.form.Type !== 'upload') {
|
||||
this.form.ImageCount = 0
|
||||
}
|
||||
addOrUpdateReadingQuestionSystem(this.form).then(res => {
|
||||
this.btnLoading = false
|
||||
this.$emit('getList')
|
||||
this.$emit('close')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
})
|
||||
addOrUpdateReadingQuestionSystem(this.form)
|
||||
.then((res) => {
|
||||
this.btnLoading = false
|
||||
this.$emit('getList')
|
||||
this.$emit('close')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
})
|
||||
.catch(() => {
|
||||
this.btnLoading = false
|
||||
})
|
||||
|
|
@ -722,33 +821,38 @@ export default {
|
|||
return new Promise((resolve, reject) => {
|
||||
this.loading = true
|
||||
var param = {
|
||||
criterionId: this.data.ReadingQuestionCriterionSystemId
|
||||
criterionId: this.data.ReadingQuestionCriterionSystemId,
|
||||
}
|
||||
getSystemGroupNameList(param).then(res => {
|
||||
this.groupOptions = res.Result
|
||||
this.loading = false
|
||||
resolve()
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
reject()
|
||||
})
|
||||
getSystemGroupNameList(param)
|
||||
.then((res) => {
|
||||
this.groupOptions = res.Result
|
||||
this.loading = false
|
||||
resolve()
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
reject()
|
||||
})
|
||||
})
|
||||
},
|
||||
getParentQuestions() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.loading = true
|
||||
var param = {
|
||||
readingQuestionCriterionSystemId: this.data.ReadingQuestionCriterionSystemId,
|
||||
id: this.data.Id
|
||||
readingQuestionCriterionSystemId:
|
||||
this.data.ReadingQuestionCriterionSystemId,
|
||||
id: this.data.Id,
|
||||
}
|
||||
getSystemCriterionOtherQuestion(param).then(res => {
|
||||
this.parentOptions = res.Result
|
||||
this.loading = false
|
||||
resolve()
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
reject()
|
||||
})
|
||||
getSystemCriterionOtherQuestion(param)
|
||||
.then((res) => {
|
||||
this.parentOptions = res.Result
|
||||
this.loading = false
|
||||
resolve()
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
reject()
|
||||
})
|
||||
})
|
||||
},
|
||||
questionGenreChange(val, form) {
|
||||
|
|
@ -819,17 +923,20 @@ export default {
|
|||
parentQuestionChange(val, form) {
|
||||
this.isParentExistGroup = false
|
||||
if (val) {
|
||||
var index = this.parentOptions.findIndex(item => {
|
||||
var index = this.parentOptions.findIndex((item) => {
|
||||
return item.QuestionId === val
|
||||
})
|
||||
if (index !== -1) {
|
||||
if (this.parentOptions[index].QuestionGenre === 3) {
|
||||
this.parentTriggerValOptions = this.$d[this.parentOptions[index].DictionaryCode]
|
||||
this.parentTriggerValOptions =
|
||||
this.$d[this.parentOptions[index].DictionaryCode]
|
||||
} else {
|
||||
var options = []
|
||||
this.parentOptions[index].TypeValue.split('|').forEach((item, index) => {
|
||||
options.push({ id: index, label: item, value: item })
|
||||
})
|
||||
this.parentOptions[index].TypeValue.split('|').forEach(
|
||||
(item, index) => {
|
||||
options.push({ id: index, label: item, value: item })
|
||||
}
|
||||
)
|
||||
this.parentTriggerValOptions = options
|
||||
}
|
||||
if (this.parentOptions[index].GroupName) {
|
||||
|
|
@ -845,17 +952,20 @@ export default {
|
|||
},
|
||||
relevanceQuestionChange(val, form) {
|
||||
if (val) {
|
||||
var index = this.parentOptions.findIndex(item => {
|
||||
var index = this.parentOptions.findIndex((item) => {
|
||||
return item.QuestionId === val
|
||||
})
|
||||
if (index !== -1) {
|
||||
if (this.parentOptions[index].QuestionGenre === 3) {
|
||||
this.reParentTriggerValOptions = this.$d[this.parentOptions[index].DictionaryCode]
|
||||
this.reParentTriggerValOptions =
|
||||
this.$d[this.parentOptions[index].DictionaryCode]
|
||||
} else {
|
||||
var options = []
|
||||
this.parentOptions[index].TypeValue.split('|').forEach((item, index) => {
|
||||
options.push({ id: index, label: item, value: item })
|
||||
})
|
||||
this.parentOptions[index].TypeValue.split('|').forEach(
|
||||
(item, index) => {
|
||||
options.push({ id: index, label: item, value: item })
|
||||
}
|
||||
)
|
||||
this.reParentTriggerValOptions = options
|
||||
}
|
||||
}
|
||||
|
|
@ -871,23 +981,24 @@ export default {
|
|||
return new Promise((resolve, reject) => {
|
||||
this.loading = true
|
||||
var param = {
|
||||
SystemCriterionId: this.data.ReadingQuestionCriterionSystemId
|
||||
SystemCriterionId: this.data.ReadingQuestionCriterionSystemId,
|
||||
}
|
||||
getCriterionLesionType(param).then(res => {
|
||||
this.lesionTypes = res.Result
|
||||
this.loading = false
|
||||
resolve()
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
reject()
|
||||
})
|
||||
getCriterionLesionType(param)
|
||||
.then((res) => {
|
||||
this.lesionTypes = res.Result
|
||||
this.loading = false
|
||||
resolve()
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
reject()
|
||||
})
|
||||
})
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
>{{ item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="序号">
|
||||
<el-form-item label="序号" prop="ShowOrder">
|
||||
<el-input v-model="form.ShowOrder" type="number" />
|
||||
</el-form-item>
|
||||
<!-- 描述 -->
|
||||
|
|
@ -135,7 +135,8 @@ export default {
|
|||
Part: [{ 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'] }],
|
||||
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: [],
|
||||
loading: false,
|
||||
|
|
|
|||
|
|
@ -2,52 +2,65 @@
|
|||
<div v-loading="loading" class="img-container">
|
||||
<el-card class="box-card left">
|
||||
<div class="title">
|
||||
{{$t('trials:none-dicom-show:fileList')}}
|
||||
{{ $t('trials:none-dicom-show:fileList') }}
|
||||
</div>
|
||||
<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">
|
||||
<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>
|
||||
</div>
|
||||
<!-- 文件层级 -->
|
||||
<div v-if="study.NoneDicomStudyFileList.length === 0" class="empty-text">
|
||||
<slot name="empty">暂无数据</slot>
|
||||
<div
|
||||
v-if="study.NoneDicomStudyFileList.length === 0"
|
||||
class="empty-text"
|
||||
>
|
||||
<slot name="empty">{{ $t('trials:audit:message:noData') }}</slot>
|
||||
</div>
|
||||
<div v-else id="imgList" style="height:100%;overflow: hidden">
|
||||
<div v-else id="imgList" style="height: 100%; overflow: hidden">
|
||||
<div
|
||||
v-for="(item,j) in study.NoneDicomStudyFileList"
|
||||
v-for="(item, j) in study.NoneDicomStudyFileList"
|
||||
:id="`img${item.Id}`"
|
||||
:key="item.Id"
|
||||
:class="{
|
||||
'is-boxActive': item.Id === currentFileId
|
||||
'is-boxActive': item.Id === currentFileId,
|
||||
}"
|
||||
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>
|
||||
|
||||
</el-card>
|
||||
<!-- 预览图像 -->
|
||||
<el-card class="box-card right">
|
||||
<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" />
|
||||
<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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
|
||||
<!-- <el-card class="box-card" style="width:300px;height:100%;padding: 10px;margin-left:10px;">
|
||||
<CheckForm />
|
||||
</el-card> -->
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -59,7 +72,7 @@ import Preview from './components/preview'
|
|||
export default {
|
||||
name: 'Notice',
|
||||
components: {
|
||||
Preview
|
||||
Preview,
|
||||
// CheckForm
|
||||
},
|
||||
data() {
|
||||
|
|
@ -76,18 +89,18 @@ export default {
|
|||
popup: true, // 弹窗的显示隐藏
|
||||
studyCode: '',
|
||||
modality: '',
|
||||
bodyPart: ''
|
||||
bodyPart: '',
|
||||
},
|
||||
previewVisible: false,
|
||||
studyList: [],
|
||||
subjectVisitId: '',
|
||||
sudyId: '',
|
||||
loading: false,
|
||||
bp:[]
|
||||
bp: [],
|
||||
}
|
||||
},
|
||||
async created(){
|
||||
this.bp = await this.$getBodyPart(this.$route.query.trialId);
|
||||
async created() {
|
||||
this.bp = await this.$getBodyPart(this.$route.query.trialId)
|
||||
},
|
||||
async mounted() {
|
||||
if (this.$router.currentRoute.query.TokenKey) {
|
||||
|
|
@ -112,31 +125,47 @@ export default {
|
|||
separator = ','
|
||||
}
|
||||
var arr = bodyPart.split(separator)
|
||||
var newArr = arr.map(i => {
|
||||
return this.$fd('Bodypart', i.trim(),'Code',{Bodypart:this.bp},'Name')
|
||||
var newArr = arr.map((i) => {
|
||||
return this.$fd(
|
||||
'Bodypart',
|
||||
i.trim(),
|
||||
'Code',
|
||||
{ Bodypart: this.bp },
|
||||
'Name'
|
||||
)
|
||||
})
|
||||
console.log(newArr,this.bp)
|
||||
console.log(newArr, this.bp)
|
||||
return newArr.join(' | ')
|
||||
},
|
||||
// 获取非Dicom检查信息
|
||||
getNoneDicomList() {
|
||||
this.loading = true
|
||||
getNoneDicomStudyList(this.subjectVisitId, this.studyId).then(res => {
|
||||
this.studyList = res.Result
|
||||
this.loading = false
|
||||
const studyIndex = this.studyList.findIndex(item => {
|
||||
return item.NoneDicomStudyFileList.length > 0
|
||||
getNoneDicomStudyList(
|
||||
this.subjectVisitId,
|
||||
this.studyId,
|
||||
false,
|
||||
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) {
|
||||
this.currentFileId = file.Id
|
||||
this.currentStudyIndex = studyIndex
|
||||
this.previewImage.imgList = this.studyList[studyIndex].NoneDicomStudyFileList
|
||||
this.previewImage.imgList =
|
||||
this.studyList[studyIndex].NoneDicomStudyFileList
|
||||
this.currentStudyFileIndex = fileIndex
|
||||
this.previewImage.index = fileIndex
|
||||
this.previewImage.studyCode = this.studyList[studyIndex].CodeView
|
||||
|
|
@ -151,11 +180,17 @@ export default {
|
|||
selectedImg(fileIndex) {
|
||||
if (this.studyList.length > 0) {
|
||||
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.studyCode = this.studyList[this.currentStudyIndex].CodeView
|
||||
this.previewImage.bodyPart = this.studyList[this.currentStudyIndex].BodyPart
|
||||
this.previewImage.modality = this.studyList[this.currentStudyIndex].Modality
|
||||
this.previewImage.studyCode =
|
||||
this.studyList[this.currentStudyIndex].CodeView
|
||||
this.previewImage.bodyPart =
|
||||
this.studyList[this.currentStudyIndex].BodyPart
|
||||
this.previewImage.modality =
|
||||
this.studyList[this.currentStudyIndex].Modality
|
||||
this.$nextTick(() => {
|
||||
const target = document.getElementById(`img${this.currentFileId}`)
|
||||
const parent = document.getElementsByClassName('left-content')[0]
|
||||
|
|
@ -165,14 +200,13 @@ export default {
|
|||
},
|
||||
preview() {
|
||||
this.previewVisible = true
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.img-container{
|
||||
.img-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
@ -186,27 +220,27 @@ export default {
|
|||
border-radius: 10px;
|
||||
background: #d0d0d0;
|
||||
}
|
||||
/deep/ .el-card__body{
|
||||
/deep/ .el-card__body {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
.study-desc{
|
||||
.study-desc {
|
||||
padding: 15px 5px;
|
||||
line-height: 20px;
|
||||
background-color: #d5d5d5;
|
||||
font-weight: 500;
|
||||
}
|
||||
.left{
|
||||
width:220px;
|
||||
.left {
|
||||
width: 220px;
|
||||
height: 100%;
|
||||
|
||||
/deep/ .el-card__body{
|
||||
/deep/ .el-card__body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.title{
|
||||
.title {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border: 1ppx solid;
|
||||
|
|
@ -215,7 +249,7 @@ export default {
|
|||
background-color: #4e4e4e;
|
||||
color: #ffffff;
|
||||
}
|
||||
.left-content{
|
||||
.left-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
|
@ -231,21 +265,26 @@ export default {
|
|||
// overflow-y: auto;
|
||||
// padding: 0;
|
||||
// }
|
||||
.img-box{
|
||||
.img-box {
|
||||
// position: relative;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2px solid #f3f3f3;
|
||||
width: 180px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
|
||||
cursor: pointer;
|
||||
// margin-bottom: 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;
|
||||
}
|
||||
.img-box:nth-last-child(1){
|
||||
.img-box:nth-last-child(1) {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.is-boxActive {
|
||||
|
|
@ -256,14 +295,13 @@ export default {
|
|||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.right{
|
||||
.right {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
margin-left: 10px;
|
||||
/deep/ .el-card__body{
|
||||
/deep/ .el-card__body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,76 +1,130 @@
|
|||
<template>
|
||||
<div style="display: flex;justify-content: center">
|
||||
<div 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;">
|
||||
<div style="display: flex; justify-content: center">
|
||||
<div
|
||||
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') }}
|
||||
</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-input v-model="password.NewUserName" />
|
||||
</el-form-item>
|
||||
<!-- 旧密码 -->
|
||||
<el-form-item :label="$t('recompose:form:oldPassword')" prop="OldPassWord">
|
||||
<el-input v-model="password.OldPassWord" type="password" show-password auto-complete="new-password" />
|
||||
<el-form-item
|
||||
: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 :label="$t('recompose:form:newPassword')" prop="NewPassWord">
|
||||
<el-input v-model="password.NewPassWord" type="password" show-password auto-complete="new-password" />
|
||||
<el-form-item
|
||||
: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 :label="$t('recompose:form:confirmPassword')" prop="ConfirmPassWord">
|
||||
<el-input v-model="password.ConfirmPassWord" type="password" show-password auto-complete="new-password" />
|
||||
<el-form-item
|
||||
: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 style="text-align:right">
|
||||
<el-form-item style="text-align: right">
|
||||
<!-- 取消 -->
|
||||
<el-button
|
||||
size="small"
|
||||
@click="cancel"
|
||||
>
|
||||
<el-button size="small" @click="cancel">
|
||||
{{ $t('recompose:button:cancel') }}
|
||||
</el-button>
|
||||
<!-- 保存 -->
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="save"
|
||||
>
|
||||
<el-button type="primary" size="small" @click="save">
|
||||
{{ $t('recompose:button:save') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { modifyPassword } from '@/api/admin.js'
|
||||
import md5 from 'js-md5'
|
||||
import {mapMutations} from "vuex";
|
||||
import { mapMutations } from 'vuex'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
password: {
|
||||
NewUserName: null
|
||||
NewUserName: null,
|
||||
},
|
||||
passwordFormRules: {
|
||||
NewUserName: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }],
|
||||
OldPassWord: [{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' }],
|
||||
NewUserName: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t('common:ruleMessage:specify'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
OldPassWord: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t('common:ruleMessage:specify'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
NewPassWord: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: this.$t('common:ruleMessage:specify'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
required: true,
|
||||
trigger: 'blur',
|
||||
validator: this.$validatePassword
|
||||
validator: this.$validatePassword,
|
||||
},
|
||||
],
|
||||
ConfirmPassWord: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
||||
]
|
||||
{
|
||||
required: true,
|
||||
message: this.$t('common:ruleMessage:specify'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
userId: null,
|
||||
loading: false
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -78,7 +132,6 @@ export default {
|
|||
if (!this.password.NewUserName) {
|
||||
// 该页面只提供给首次进入系统的用户使用
|
||||
this.$alert(this.$t('recompose:message:warning'))
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -96,7 +149,7 @@ export default {
|
|||
this.$updateDictionary()
|
||||
},
|
||||
save() {
|
||||
this.$refs.passwordForm.validate(valid => {
|
||||
this.$refs.passwordForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.password.NewPassWord !== this.password.ConfirmPassWord) {
|
||||
// 两次密码输入不一致
|
||||
|
|
@ -106,58 +159,64 @@ export default {
|
|||
const param = {
|
||||
NewUserName: this.password.NewUserName,
|
||||
NewPassWord: md5(this.password.NewPassWord),
|
||||
OldPassWord: md5(this.password.OldPassWord)
|
||||
OldPassWord: md5(this.password.OldPassWord),
|
||||
}
|
||||
this.loading = true
|
||||
modifyPassword(param).then(res => {
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
// 修改成功,请重新登录账号
|
||||
this.$message.success(this.$t('recompose:message:updatedSuccessfully'))
|
||||
setTimeout(() => {
|
||||
this.logout()
|
||||
}, 500)
|
||||
}
|
||||
}).catch(() => { this.loading = false })
|
||||
modifyPassword(param)
|
||||
.then((res) => {
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
// 修改成功,请重新登录账号
|
||||
this.$message.success(
|
||||
this.$t('recompose:message:updatedSuccessfully')
|
||||
)
|
||||
setTimeout(() => {
|
||||
this.logout()
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
cancel() {
|
||||
this.$refs['passwordForm'].resetFields()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.reset-wrapper {
|
||||
padding: 20px;
|
||||
}
|
||||
.reset-wrapper .el-page-header {
|
||||
line-height: 50px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.reset-wrapper .box-wrapper {
|
||||
width: 60%;
|
||||
margin: 20px auto;
|
||||
padding: 10px;
|
||||
color: #303133;
|
||||
}
|
||||
.reset-wrapper {
|
||||
padding: 20px;
|
||||
}
|
||||
.reset-wrapper .el-page-header {
|
||||
line-height: 50px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.reset-wrapper .box-wrapper {
|
||||
width: 60%;
|
||||
margin: 20px auto;
|
||||
padding: 10px;
|
||||
color: #303133;
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
::v-deep .is-error{
|
||||
::v-deep .is-error {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
input:-webkit-autofill {
|
||||
-webkit-text-fill-color: #ededed !important;
|
||||
box-shadow: 0 0 0px 1000px transparent inset !important;
|
||||
background-color:transparent;
|
||||
box-shadow: 0 0 0px 1000px transparent inset !important;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
transition: background-color 50000s ease-in-out 0s;
|
||||
}
|
||||
input {
|
||||
background-color:transparent;
|
||||
background-color: transparent;
|
||||
caret-color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@
|
|||
</el-form-item>
|
||||
<!-- 阅片标准 -->
|
||||
<el-form-item
|
||||
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')"
|
||||
v-if="hasPermi(['role:ir'])"
|
||||
:label="$t('trials:trials-list:table:IR_ReadingCriterionList')"
|
||||
>
|
||||
<el-select
|
||||
v-model="searchData.CriterionType"
|
||||
|
|
@ -59,8 +59,8 @@
|
|||
</el-form-item>
|
||||
<!-- 联系人 -->
|
||||
<el-form-item
|
||||
:label="$t('trials:trials-list:table:IR_PMEmailList')"
|
||||
v-if="hasPermi(['role:ir'])"
|
||||
:label="$t('trials:trials-list:table:IR_PMEmailList')"
|
||||
>
|
||||
<el-input
|
||||
v-model="searchData.PM_EMail"
|
||||
|
|
@ -293,9 +293,10 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSelectSearch"
|
||||
>Search</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleSelectSearch"
|
||||
>Search</el-button>
|
||||
<el-button type="primary" @click="handleReset">Reset</el-button>
|
||||
<el-button type="primary" @click="isShow = false">Back</el-button>
|
||||
</el-form-item>
|
||||
|
|
@ -357,23 +358,19 @@
|
|||
<el-tag
|
||||
v-if="scope.row.TrialStatusStr === 'Initializing'"
|
||||
type="info"
|
||||
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag
|
||||
>
|
||||
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag>
|
||||
<el-tag
|
||||
v-if="scope.row.TrialStatusStr === 'Ongoing'"
|
||||
type="primary"
|
||||
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag
|
||||
>
|
||||
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag>
|
||||
<el-tag
|
||||
v-if="scope.row.TrialStatusStr === 'Completed'"
|
||||
type="warning"
|
||||
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag
|
||||
>
|
||||
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag>
|
||||
<el-tag
|
||||
v-if="scope.row.TrialStatusStr === 'Stopped'"
|
||||
type="danger"
|
||||
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag
|
||||
>
|
||||
>{{ $fd("TrialStatusEnum", scope.row.TrialStatusStr) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
|
|
@ -582,7 +579,7 @@
|
|||
:disabled="
|
||||
(scope.row.TrialStatusStr === 'Initializing' &&
|
||||
!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')"
|
||||
@click.stop="handleDetail(scope.row)"
|
||||
|
|
@ -612,7 +609,7 @@
|
|||
icon="el-icon-delete"
|
||||
:disabled="
|
||||
scope.row.IsDeleted ||
|
||||
scope.row.TrialStatusStr !== 'Initializing'
|
||||
scope.row.TrialStatusStr !== 'Initializing'
|
||||
"
|
||||
:title="$t('trials:trials-list:action:abolition')"
|
||||
@click.stop="handleAbandon(scope.row)"
|
||||
|
|
@ -693,54 +690,54 @@
|
|||
import {
|
||||
abandonTrial,
|
||||
ifTrialCanOngoing,
|
||||
getTrialToBeDoneList,
|
||||
} from "@/api/trials";
|
||||
import { getTrialList_Export } from "@/api/export";
|
||||
import store from "@/store";
|
||||
import { mapGetters } from "vuex";
|
||||
import BaseContainer from "@/components/BaseContainer";
|
||||
import Pagination from "@/components/Pagination";
|
||||
import TrialForm from "./components/TrialForm";
|
||||
import TrialStatusForm from "./components/TrialStatusForm";
|
||||
import DoneList from "./components/DoneList";
|
||||
getTrialToBeDoneList
|
||||
} from '@/api/trials'
|
||||
import { getTrialList_Export } from '@/api/export'
|
||||
import store from '@/store'
|
||||
import { mapGetters } from 'vuex'
|
||||
import BaseContainer from '@/components/BaseContainer'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import TrialForm from './components/TrialForm'
|
||||
import TrialStatusForm from './components/TrialStatusForm'
|
||||
import DoneList from './components/DoneList'
|
||||
const searchDataDefault = () => {
|
||||
return {
|
||||
Code: "",
|
||||
Code: '',
|
||||
CriterionIds: [],
|
||||
SponsorId: "",
|
||||
SponsorId: '',
|
||||
ReviewTypeIds: [],
|
||||
CROId: "",
|
||||
Expedited: "",
|
||||
Indication: "",
|
||||
Phase: "",
|
||||
CROId: '',
|
||||
Expedited: '',
|
||||
Indication: '',
|
||||
Phase: '',
|
||||
ModalityIds: [],
|
||||
BeginDate: "",
|
||||
EndDate: "",
|
||||
AttendedReviewerType: "",
|
||||
ResearchProgramNo: "",
|
||||
ExperimentName: "",
|
||||
BeginDate: '',
|
||||
EndDate: '',
|
||||
AttendedReviewerType: '',
|
||||
ResearchProgramNo: '',
|
||||
ExperimentName: '',
|
||||
PageIndex: 1,
|
||||
PageSize: 20,
|
||||
Asc: false,
|
||||
SortField: "",
|
||||
SortField: '',
|
||||
CriterionType: null,
|
||||
PM_EMail: null,
|
||||
};
|
||||
};
|
||||
PM_EMail: null
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: "Trials",
|
||||
name: 'Trials',
|
||||
components: {
|
||||
Pagination,
|
||||
BaseContainer,
|
||||
TrialForm,
|
||||
TrialStatusForm,
|
||||
DoneList,
|
||||
DoneList
|
||||
},
|
||||
dicts: ["ReadingStandard", "ReviewType", "ReadingType"],
|
||||
dicts: ['ReadingStandard', 'ReviewType', 'ReadingType'],
|
||||
data() {
|
||||
return {
|
||||
exportLoading: false,
|
||||
userTypeEnumInt: zzSessionStorage.getItem("userTypeEnumInt") * 1,
|
||||
userTypeEnumInt: zzSessionStorage.getItem('userTypeEnumInt') * 1,
|
||||
doneDialogVisible: false,
|
||||
doneTitle: null,
|
||||
selectArr: [],
|
||||
|
|
@ -750,26 +747,26 @@ export default {
|
|||
total: 0,
|
||||
isShow: false,
|
||||
dialogVisible: false,
|
||||
title: "",
|
||||
currentId: "",
|
||||
title: '',
|
||||
currentId: '',
|
||||
statusVisible: false,
|
||||
currentRow: {},
|
||||
currentUser: zzSessionStorage.getItem("userName"),
|
||||
currentUser: zzSessionStorage.getItem('userName'),
|
||||
phaseOptions: [
|
||||
{ value: "I" },
|
||||
{ value: "II" },
|
||||
{ value: "III" },
|
||||
{ value: "IV" },
|
||||
{ value: 'I' },
|
||||
{ value: 'II' },
|
||||
{ value: 'III' },
|
||||
{ value: 'IV' }
|
||||
],
|
||||
expeditedOption: this.$d.TrialExpeditedState,
|
||||
beginPickerOption: {
|
||||
disabledDate: (time) => {
|
||||
if (this.searchData.EndDate) {
|
||||
return time.getTime() > new Date(this.searchData.EndDate).getTime();
|
||||
return time.getTime() > new Date(this.searchData.EndDate).getTime()
|
||||
} else {
|
||||
return time.getTime() > Date.now();
|
||||
return time.getTime() > Date.now()
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
endpickerOption: {
|
||||
disabledDate: (time) => {
|
||||
|
|
@ -777,306 +774,189 @@ export default {
|
|||
return (
|
||||
time.getTime() > Date.now() ||
|
||||
time.getTime() <= new Date(this.searchData.BeginDate).getTime()
|
||||
);
|
||||
)
|
||||
} else {
|
||||
return time.getTime() > Date.now();
|
||||
return time.getTime() > Date.now()
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["sponsorList", "croList"]),
|
||||
...mapGetters(['sponsorList', 'croList'])
|
||||
},
|
||||
created() {
|
||||
this.initPage();
|
||||
this.initPage()
|
||||
},
|
||||
methods: {
|
||||
initPage() {
|
||||
this.getList();
|
||||
store.dispatch("global/getSponsorList");
|
||||
store.dispatch("global/getCROList");
|
||||
this.getList()
|
||||
store.dispatch('global/getSponsorList')
|
||||
store.dispatch('global/getCROList')
|
||||
},
|
||||
// 获取项目列表信息
|
||||
getList() {
|
||||
this.listLoading = true;
|
||||
this.listLoading = true
|
||||
getTrialToBeDoneList(this.searchData)
|
||||
.then((res) => {
|
||||
this.list = res.Result.CurrentPageData;
|
||||
this.total = res.Result.TotalCount;
|
||||
this.listLoading = false;
|
||||
this.list = res.Result.CurrentPageData
|
||||
this.total = res.Result.TotalCount
|
||||
this.listLoading = false
|
||||
})
|
||||
.catch(() => {
|
||||
this.listLoading = false;
|
||||
});
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 查询
|
||||
handleSearch() {
|
||||
this.searchData.PageIndex = 1;
|
||||
this.getList();
|
||||
this.searchData.PageIndex = 1
|
||||
this.getList()
|
||||
},
|
||||
// 查询
|
||||
handleSelectSearch() {
|
||||
this.searchData.PageIndex = 1;
|
||||
this.getList();
|
||||
this.isShow = false;
|
||||
this.searchData.PageIndex = 1
|
||||
this.getList()
|
||||
this.isShow = false
|
||||
},
|
||||
// 重置
|
||||
handleReset() {
|
||||
this.searchData = searchDataDefault();
|
||||
this.getList();
|
||||
this.searchData = searchDataDefault()
|
||||
this.getList()
|
||||
},
|
||||
// 新增项目
|
||||
handleNew() {
|
||||
// this.$router.push({ name: 'CreateTrial' })
|
||||
this.title = this.$t("trials:trials-list:dialogTitle:new");
|
||||
this.currentId = "";
|
||||
this.dialogVisible = true;
|
||||
this.title = this.$t('trials:trials-list:dialogTitle:new')
|
||||
this.currentId = ''
|
||||
this.dialogVisible = true
|
||||
},
|
||||
// 编辑项目
|
||||
handleEdit(row) {
|
||||
this.title = this.$t("trials:trials-list:dialogTitle:edit");
|
||||
this.currentId = row.Id;
|
||||
this.dialogVisible = true;
|
||||
this.title = this.$t('trials:trials-list:dialogTitle:edit')
|
||||
this.currentId = row.Id
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleCommission(row) {
|
||||
this.doneTitle = this.$t("trials:trials-list:dialogTitle:doneTitle");
|
||||
this.currentId = row.Id;
|
||||
this.doneDialogVisible = true;
|
||||
this.doneTitle = this.$t('trials:trials-list:dialogTitle:doneTitle')
|
||||
this.currentId = row.Id
|
||||
this.doneDialogVisible = true
|
||||
},
|
||||
closeDialog() {
|
||||
this.dialogVisible = false;
|
||||
this.dialogVisible = false
|
||||
},
|
||||
// 状态
|
||||
handleStatus(row) {
|
||||
if (row.TrialStatusStr === "Initializing") {
|
||||
this.listLoading = true;
|
||||
if (row.TrialStatusStr === 'Initializing') {
|
||||
this.listLoading = true
|
||||
ifTrialCanOngoing(row.Id)
|
||||
.then((res) => {
|
||||
this.listLoading = false;
|
||||
this.listLoading = false
|
||||
if (res.Result) {
|
||||
this.currentRow = { ...row };
|
||||
this.statusVisible = true;
|
||||
this.currentRow = { ...row }
|
||||
this.statusVisible = true
|
||||
} else {
|
||||
this.$confirm(res.ErrorMessage, {
|
||||
type: "warning",
|
||||
type: 'warning',
|
||||
showCancelButton: false,
|
||||
callback: (action) => {},
|
||||
});
|
||||
callback: (action) => {}
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.listLoading = false;
|
||||
});
|
||||
this.listLoading = false
|
||||
})
|
||||
} else {
|
||||
this.currentRow = { ...row };
|
||||
this.statusVisible = true;
|
||||
this.currentRow = { ...row }
|
||||
this.statusVisible = true
|
||||
}
|
||||
},
|
||||
closeStatusDialog() {
|
||||
this.statusVisible = false;
|
||||
this.statusVisible = false
|
||||
},
|
||||
// 废除
|
||||
handleAbandon(row) {
|
||||
this.$confirm(this.$t("trials:trials-list:message:abolition"), {
|
||||
type: "warning",
|
||||
distinguishCancelAndClose: true,
|
||||
this.$confirm(this.$t('trials:trials-list:message:abolition'), {
|
||||
type: 'warning',
|
||||
distinguishCancelAndClose: true
|
||||
})
|
||||
.then(() => {
|
||||
this.currentRow = { ...row };
|
||||
this.abandonTrial();
|
||||
this.currentRow = { ...row }
|
||||
this.abandonTrial()
|
||||
})
|
||||
.catch(() => {});
|
||||
.catch(() => {})
|
||||
},
|
||||
// 废除项目
|
||||
abandonTrial() {
|
||||
this.listLoading = true;
|
||||
this.listLoading = true
|
||||
abandonTrial(this.currentRow.Id, true)
|
||||
.then((res) => {
|
||||
this.listLoading = false;
|
||||
this.listLoading = false
|
||||
if (res.IsSuccess) {
|
||||
this.getList();
|
||||
this.getList()
|
||||
this.$message.success(
|
||||
this.$t("trials:trials-list:message:abolitionSuccessfully")
|
||||
);
|
||||
this.$t('trials:trials-list:message:abolitionSuccessfully')
|
||||
)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.listLoading = false;
|
||||
});
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
rowClick(row, col) {
|
||||
if (
|
||||
(row.TrialStatusStr === "Initializing" &&
|
||||
!this.hasPermi(["role:pm"])) ||
|
||||
row.IsDeleted
|
||||
)
|
||||
return;
|
||||
if ((row.TrialStatusStr === 'Initializing' && !this.hasPermi(['role:pm'])) || row.IsDeleted) {
|
||||
return
|
||||
} else if ((row.TrialStatusStr === 'Completed' || row.TrialStatusStr === 'Stopped') && !(this.hasPermi(['role:qa']) || this.hasPermi(['role:ea']) || this.hasPermi(['role:pm']))) {
|
||||
return
|
||||
}
|
||||
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
|
||||
handleDetail(row) {
|
||||
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) {
|
||||
const arr = [];
|
||||
const arr = []
|
||||
for (let index = 0; index < val.length; index++) {
|
||||
arr.push(val[index]);
|
||||
arr.push(val[index])
|
||||
}
|
||||
this.selectArr = arr;
|
||||
this.selectArr = arr
|
||||
},
|
||||
// 排序
|
||||
handleSortChange(column) {
|
||||
if (column.order === "ascending") {
|
||||
this.searchData.Asc = true;
|
||||
if (column.order === 'ascending') {
|
||||
this.searchData.Asc = true
|
||||
} else {
|
||||
this.searchData.Asc = false;
|
||||
this.searchData.Asc = false
|
||||
}
|
||||
if (column.prop === "Criterion") {
|
||||
this.searchData.SortField = "CriterionId";
|
||||
if (column.prop === 'Criterion') {
|
||||
this.searchData.SortField = 'CriterionId'
|
||||
} else {
|
||||
this.searchData.SortField = column.prop;
|
||||
this.searchData.SortField = column.prop
|
||||
}
|
||||
this.searchData.PageIndex = 1;
|
||||
this.getList();
|
||||
this.searchData.PageIndex = 1
|
||||
this.getList()
|
||||
},
|
||||
// 导出Excel表格
|
||||
handleExportTrial() {
|
||||
this.exportLoading = true;
|
||||
let data = {
|
||||
...this.searchData,
|
||||
};
|
||||
data.TrialIdList = this.selectArr.map((item) => item.Id);
|
||||
this.exportLoading = true
|
||||
const data = {
|
||||
...this.searchData
|
||||
}
|
||||
data.TrialIdList = this.selectArr.map((item) => item.Id)
|
||||
return getTrialList_Export(data)
|
||||
.then((res) => {
|
||||
this.exportLoading = false;
|
||||
this.exportLoading = false
|
||||
})
|
||||
.catch(() => {
|
||||
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,
|
||||
this.exportLoading = false
|
||||
})
|
||||
.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>
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@
|
|||
j.armEnum === 1
|
||||
? $t('trials:adReview:table:viewR1')
|
||||
: j.armEnum === 2
|
||||
? $t('trials:adReview:table:viewR2')
|
||||
: $fd('ArmEnum', j.armEnum)
|
||||
? $t('trials:adReview:table:viewR2')
|
||||
: $fd('ArmEnum', j.armEnum)
|
||||
"
|
||||
align="center"
|
||||
prop=""
|
||||
|
|
@ -81,18 +81,17 @@
|
|||
scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i]
|
||||
.DictionaryCode
|
||||
"
|
||||
>{{
|
||||
$fd(
|
||||
scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[
|
||||
i
|
||||
].DictionaryCode,
|
||||
parseInt(
|
||||
scope.row.VisitTaskInfoList[j.index]
|
||||
.JudgeQuestionList[i].Answer
|
||||
)
|
||||
>{{
|
||||
$fd(
|
||||
scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[
|
||||
i
|
||||
].DictionaryCode,
|
||||
parseInt(
|
||||
scope.row.VisitTaskInfoList[j.index]
|
||||
.JudgeQuestionList[i].Answer
|
||||
)
|
||||
}}</span
|
||||
>
|
||||
)
|
||||
}}</span>
|
||||
<span v-else>{{
|
||||
scope.row.VisitTaskInfoList[j.index].JudgeQuestionList[i]
|
||||
.Answer
|
||||
|
|
@ -321,7 +320,7 @@
|
|||
alt=""
|
||||
crossorigin="anonymous"
|
||||
style="max-width: 100%; max-height: 100%"
|
||||
/>
|
||||
>
|
||||
<span class="el-upload-list__item-actions">
|
||||
<span
|
||||
class="el-upload-list__item-preview"
|
||||
|
|
@ -435,88 +434,87 @@ import {
|
|||
// uploadJudgeTaskImage,
|
||||
saveJudgeVisitTaskResult,
|
||||
submitJudgeVisitTaskResult,
|
||||
getReadingPastResultList,
|
||||
} from "@/api/trials";
|
||||
import { getAutoCutNextTask } from "@/api/user";
|
||||
import { setSkipReadingCache } from "@/api/reading";
|
||||
import const_ from "@/const/sign-code";
|
||||
import { getToken } from "@/utils/auth";
|
||||
import SignForm from "@/views/trials/components/newSignForm";
|
||||
import DicomEvent from "@/views/trials/trials-panel/reading/dicoms/components/DicomEvent";
|
||||
getReadingPastResultList
|
||||
} from '@/api/trials'
|
||||
import { getAutoCutNextTask } from '@/api/user'
|
||||
import { setSkipReadingCache } from '@/api/reading'
|
||||
import const_ from '@/const/sign-code'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import SignForm from '@/views/trials/components/newSignForm'
|
||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||
// import store from '@/store'
|
||||
import { changeURLStatic } from "@/utils/history.js";
|
||||
import Viewer from "v-viewer";
|
||||
import { changeURLStatic } from '@/utils/history.js'
|
||||
export default {
|
||||
name: "AdReview",
|
||||
name: 'AdReview',
|
||||
components: { SignForm },
|
||||
props: {
|
||||
trialId: {
|
||||
type: String,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
subjectId: {
|
||||
type: String,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
visitTaskId: {
|
||||
type: String,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
readingCategory: {
|
||||
type: Number,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
subjectCode: {
|
||||
type: String,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
taskBlindName: {
|
||||
type: String,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
isReadingShowSubjectInfo: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
isReadingShowPreviousResults: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
isExistsClinicalData: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
adInfo: {},
|
||||
judgeQuestion: [],
|
||||
adForm: {
|
||||
visitTaskId: "",
|
||||
judgeResultTaskId: "",
|
||||
judgeResultRemark: "",
|
||||
visitTaskId: '',
|
||||
judgeResultTaskId: '',
|
||||
judgeResultRemark: '',
|
||||
// judgeResultImagePath: ''
|
||||
judgeResultImagePathList: [],
|
||||
judgeResultImagePathList: []
|
||||
},
|
||||
currentUser: zzSessionStorage.getItem("userName"),
|
||||
currentUser: zzSessionStorage.getItem('userName'),
|
||||
signVisible: false,
|
||||
signCode: null,
|
||||
accept: ".png,.jpg,.jpeg",
|
||||
accept: '.png,.jpg,.jpeg',
|
||||
imgVisible: false,
|
||||
imageUrl: "",
|
||||
imageUrl: '',
|
||||
uploadDisabled: false,
|
||||
fileList: [],
|
||||
loading: false,
|
||||
visitTaskArmList: [],
|
||||
priorADList: [],
|
||||
priorLoading: false,
|
||||
judgeResultArmEnum: "",
|
||||
judgeResultArmEnum: '',
|
||||
criterionType: null,
|
||||
openWindow: null,
|
||||
isFixed: false,
|
||||
images: [],
|
||||
remark: "",
|
||||
};
|
||||
remark: ''
|
||||
}
|
||||
},
|
||||
// watch: {
|
||||
// visitTaskId: {
|
||||
|
|
@ -532,261 +530,260 @@ export default {
|
|||
// }
|
||||
// },
|
||||
mounted() {
|
||||
this.initializeViewer();
|
||||
this.criterionType = parseInt(this.$route.query.criterionType);
|
||||
this.getAdInfo();
|
||||
this.criterionType = parseInt(this.$route.query.criterionType)
|
||||
this.getAdInfo()
|
||||
if (this.isReadingShowPreviousResults) {
|
||||
this.getPriorAdList();
|
||||
this.getPriorAdList()
|
||||
}
|
||||
DicomEvent.$on("resetOpenWindow", () => {
|
||||
DicomEvent.$on('resetOpenWindow', () => {
|
||||
if (this.openWindow) {
|
||||
this.openWindow.close();
|
||||
this.openWindow.close()
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
DicomEvent.$off("resetOpenWindow");
|
||||
DicomEvent.$off('resetOpenWindow')
|
||||
if (this.openWindow) {
|
||||
this.openWindow.close();
|
||||
this.openWindow.close()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getAdInfo() {
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await getJudgeReadingInfo({
|
||||
visitTaskId: this.visitTaskId,
|
||||
});
|
||||
visitTaskId: this.visitTaskId
|
||||
})
|
||||
if (res.IsSuccess) {
|
||||
var judgeQS = [];
|
||||
var judgeQS = []
|
||||
if (res.Result.VisitInfoList.length > 0) {
|
||||
res.Result.VisitInfoList[0].VisitTaskInfoList.map((v, index) => {
|
||||
var qsObj = {
|
||||
armEnum: v.ArmEnum,
|
||||
judgeQuestionList: [],
|
||||
index: index,
|
||||
};
|
||||
index: index
|
||||
}
|
||||
v.JudgeQuestionList.map((q) => {
|
||||
if (q.QuestionType === 1) {
|
||||
qsObj.judgeQuestionList.push(q.QuestionName);
|
||||
qsObj.judgeQuestionList.push(q.QuestionName)
|
||||
} else if (q.QuestionType === 3 && this.criterionType === 10) {
|
||||
qsObj.judgeQuestionList.push(
|
||||
this.$t("trials:globalReview:table:visitRemark")
|
||||
);
|
||||
this.$t('trials:globalReview:table:visitRemark')
|
||||
)
|
||||
} else {
|
||||
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.judgeQuestion.length > 0 &&
|
||||
this.judgeQuestion[0].judgeQuestionList.length > 4;
|
||||
this.adInfo = res.Result;
|
||||
this.adForm.judgeResultTaskId = res.Result.JudgeResultTaskId;
|
||||
this.judgeQuestion[0].judgeQuestionList.length > 4
|
||||
this.adInfo = res.Result
|
||||
this.adForm.judgeResultTaskId = res.Result.JudgeResultTaskId
|
||||
|
||||
this.fileList = [];
|
||||
this.fileList = []
|
||||
if (res.Result.JudgeResultImagePathList) {
|
||||
res.Result.JudgeResultImagePathList.map((url) => {
|
||||
if (url) {
|
||||
this.fileList.push({ name: "", url: url });
|
||||
this.fileList.push({ name: '', url: url })
|
||||
}
|
||||
});
|
||||
})
|
||||
this.adForm.judgeResultImagePathList =
|
||||
res.Result.JudgeResultImagePathList;
|
||||
res.Result.JudgeResultImagePathList
|
||||
}
|
||||
this.visitTaskArmList = res.Result.VisitTaskArmList;
|
||||
this.visitTaskArmList = res.Result.VisitTaskArmList
|
||||
var i = this.visitTaskArmList.findIndex(
|
||||
(i) => i.VisitTaskId === this.adForm.judgeResultTaskId
|
||||
);
|
||||
)
|
||||
if (i > -1) {
|
||||
// 本人已完整查看两位独立阅片人的全部相关影像和评估数据,经过综合研判,更认同第一阅片人(R1)对该病例的整体评估,原因是:
|
||||
this.judgeResultArmEnum = this.visitTaskArmList[i].ArmEnum;
|
||||
var msg = "";
|
||||
this.judgeResultArmEnum = this.visitTaskArmList[i].ArmEnum
|
||||
var msg = ''
|
||||
if (this.judgeResultArmEnum === 1) {
|
||||
msg = this.$t("trials:adReview:title:msg1");
|
||||
msg = this.$t('trials:adReview:title:msg1')
|
||||
} else if (this.judgeResultArmEnum === 2) {
|
||||
msg = this.$t("trials:adReview:title:msg3");
|
||||
msg = this.$t('trials:adReview:title:msg3')
|
||||
}
|
||||
this.remark = msg;
|
||||
this.adForm.judgeResultRemark = res.Result.JudgeResultRemark;
|
||||
this.remark = msg
|
||||
this.adForm.judgeResultRemark = res.Result.JudgeResultRemark
|
||||
}
|
||||
}
|
||||
this.loading = false;
|
||||
this.loading = false
|
||||
} catch (e) {
|
||||
this.loading = false;
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async getPriorAdList() {
|
||||
this.priorLoading = true;
|
||||
this.priorLoading = true
|
||||
try {
|
||||
const res = await getReadingPastResultList({
|
||||
visitTaskId: this.visitTaskId,
|
||||
});
|
||||
visitTaskId: this.visitTaskId
|
||||
})
|
||||
if (res.IsSuccess) {
|
||||
this.priorADList = res.Result;
|
||||
this.priorADList = res.Result
|
||||
}
|
||||
this.priorLoading = false;
|
||||
this.priorLoading = false
|
||||
} catch (e) {
|
||||
this.priorLoading = false;
|
||||
this.priorLoading = false
|
||||
}
|
||||
},
|
||||
handleVisitTaskArmChange(v) {
|
||||
var i = this.visitTaskArmList.findIndex((i) => i.VisitTaskId === v);
|
||||
var i = this.visitTaskArmList.findIndex((i) => i.VisitTaskId === v)
|
||||
if (i > -1) {
|
||||
// 本人已完整查看两位独立阅片人的全部相关影像和评估数据,经过综合研判,更认同第一阅片人(R1)对该病例的整体评估,原因是:
|
||||
this.judgeResultArmEnum = this.visitTaskArmList[i].ArmEnum;
|
||||
var msg = "";
|
||||
this.judgeResultArmEnum = this.visitTaskArmList[i].ArmEnum
|
||||
var msg = ''
|
||||
if (this.judgeResultArmEnum === 1) {
|
||||
msg = this.$t("trials:adReview:title:msg1");
|
||||
msg = this.$t('trials:adReview:title:msg1')
|
||||
} else {
|
||||
msg = this.$t("trials:adReview:title:msg3");
|
||||
msg = this.$t('trials:adReview:title:msg3')
|
||||
}
|
||||
// this.adForm.judgeResultRemark = `本人已完整查看两位独立阅片人的全部相关影像和评估数据,经过综合研判,更认同${this.$fd('ArmEnum', this.judgeResultArmEnum)}对该病例的整体评估,原因是:`
|
||||
this.remark = msg;
|
||||
this.adForm.judgeResultRemark = "";
|
||||
this.remark = msg
|
||||
this.adForm.judgeResultRemark = ''
|
||||
} else {
|
||||
this.judgeResultArmEnum = "";
|
||||
this.remark = "";
|
||||
this.adForm.judgeResultRemark = "";
|
||||
this.judgeResultArmEnum = ''
|
||||
this.remark = ''
|
||||
this.adForm.judgeResultRemark = ''
|
||||
}
|
||||
},
|
||||
previewCD() {
|
||||
var token = getToken();
|
||||
var token = getToken()
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/clinicalData?subjectId=${this.subjectId}&trialId=${this.trialId}&visitTaskId=${this.visitTaskId}&TokenKey=${token}`,
|
||||
});
|
||||
window.open(routeData.href, "_blank");
|
||||
path: `/clinicalData?subjectId=${this.subjectId}&trialId=${this.trialId}&visitTaskId=${this.visitTaskId}&TokenKey=${token}`
|
||||
})
|
||||
window.open(routeData.href, '_blank')
|
||||
},
|
||||
async handleSave() {
|
||||
const valid = await this.$refs["adForm"].validate();
|
||||
if (!valid) return;
|
||||
this.loading = true;
|
||||
var paths = [];
|
||||
const valid = await this.$refs['adForm'].validate()
|
||||
if (!valid) return
|
||||
this.loading = true
|
||||
var paths = []
|
||||
this.fileList.map((file) => {
|
||||
if (file.url) {
|
||||
paths.push(file.url);
|
||||
paths.push(file.url)
|
||||
}
|
||||
});
|
||||
this.adForm.judgeResultImagePathList = paths;
|
||||
this.adForm.visitTaskId = this.visitTaskId;
|
||||
})
|
||||
this.adForm.judgeResultImagePathList = paths
|
||||
this.adForm.visitTaskId = this.visitTaskId
|
||||
try {
|
||||
await saveJudgeVisitTaskResult(this.adForm);
|
||||
this.$message.success(this.$t("common:message:savedSuccessfully"));
|
||||
this.loading = false;
|
||||
await saveJudgeVisitTaskResult(this.adForm)
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.loading = false
|
||||
} catch (e) {
|
||||
this.loading = false;
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async handleSubmit() {
|
||||
const valid = await this.$refs["adForm"].validate();
|
||||
if (!valid) return;
|
||||
const { ImageAssessmentReportConfirmation } = const_.processSignature;
|
||||
this.signCode = ImageAssessmentReportConfirmation;
|
||||
this.signVisible = true;
|
||||
const valid = await this.$refs['adForm'].validate()
|
||||
if (!valid) return
|
||||
const { ImageAssessmentReportConfirmation } = const_.processSignature
|
||||
this.signCode = ImageAssessmentReportConfirmation
|
||||
this.signVisible = true
|
||||
},
|
||||
// 关闭签名框
|
||||
closeSignDialog(isSign, signInfo) {
|
||||
if (isSign) {
|
||||
this.signConfirm(signInfo);
|
||||
this.signConfirm(signInfo)
|
||||
} else {
|
||||
this.signVisible = false;
|
||||
this.signVisible = false
|
||||
}
|
||||
},
|
||||
// 签名并确认
|
||||
async signConfirm(signInfo) {
|
||||
this.loading = true;
|
||||
var paths = [];
|
||||
this.loading = true
|
||||
var paths = []
|
||||
this.fileList.map((file) => {
|
||||
paths.push(file.url);
|
||||
});
|
||||
paths.push(file.url)
|
||||
})
|
||||
var params = {
|
||||
data: {
|
||||
visitTaskId: this.visitTaskId,
|
||||
judgeResultTaskId: this.adForm.judgeResultTaskId,
|
||||
judgeResultRemark: this.adForm.judgeResultRemark,
|
||||
judgeResultImagePathList: paths,
|
||||
judgeResultImagePathList: paths
|
||||
},
|
||||
signInfo: signInfo,
|
||||
};
|
||||
signInfo: signInfo
|
||||
}
|
||||
try {
|
||||
const res = await submitJudgeVisitTaskResult(params);
|
||||
const res = await submitJudgeVisitTaskResult(params)
|
||||
if (res.IsSuccess) {
|
||||
this.$message.success(this.$t("common:message:savedSuccessfully"));
|
||||
this.isEdit = false;
|
||||
this.$refs["signForm"].btnLoading = false;
|
||||
this.signVisible = false;
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.isEdit = false
|
||||
this.$refs['signForm'].btnLoading = false
|
||||
this.signVisible = false
|
||||
// window.location.reload()
|
||||
// window.opener.postMessage('refreshTaskList', window.location)
|
||||
// 设置当前任务阅片状态为已读
|
||||
this.adInfo.ReadingTaskState = 2;
|
||||
const res = await getAutoCutNextTask();
|
||||
var isAutoTask = res.Result.AutoCutNextTask;
|
||||
this.adInfo.ReadingTaskState = 2
|
||||
const res = await getAutoCutNextTask()
|
||||
var isAutoTask = res.Result.AutoCutNextTask
|
||||
if (isAutoTask) {
|
||||
// store.dispatch('reading/resetVisitTasks')
|
||||
window.location.reload();
|
||||
window.location.reload()
|
||||
} else {
|
||||
// '当前阅片任务已完成,是否进入下一个阅片任务?'
|
||||
const confirm = await this.$confirm(
|
||||
this.$t("trials:adReview:title:msg2"),
|
||||
this.$t('trials:adReview:title:msg2'),
|
||||
{
|
||||
type: "warning",
|
||||
distinguishCancelAndClose: true,
|
||||
type: 'warning',
|
||||
distinguishCancelAndClose: true
|
||||
}
|
||||
);
|
||||
if (confirm === "confirm") {
|
||||
)
|
||||
if (confirm === 'confirm') {
|
||||
// store.dispatch('reading/resetVisitTasks')
|
||||
// DicomEvent.$emit('getNextTask')
|
||||
window.location.reload();
|
||||
window.location.reload()
|
||||
} 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) {
|
||||
this.loading = false;
|
||||
this.$refs["signForm"].btnLoading = false;
|
||||
this.loading = false
|
||||
this.$refs['signForm'].btnLoading = false
|
||||
}
|
||||
},
|
||||
handleViewDetail(visitTaskId) {
|
||||
if (this.openWindow) {
|
||||
this.openWindow.close();
|
||||
this.openWindow.close()
|
||||
}
|
||||
var token = getToken();
|
||||
var criterionType = parseInt(localStorage.getItem("CriterionType"));
|
||||
var readingTool = this.$router.currentRoute.query.readingTool;
|
||||
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool);
|
||||
var token = getToken()
|
||||
var criterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||
var readingTool = this.$router.currentRoute.query.readingTool
|
||||
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool)
|
||||
var isReadingTaskViewInOrder =
|
||||
this.$router.currentRoute.query.isReadingTaskViewInOrder;
|
||||
this.$router.currentRoute.query.isReadingTaskViewInOrder
|
||||
var trialReadingCriterionId =
|
||||
this.$router.currentRoute.query.TrialReadingCriterionId;
|
||||
this.$router.currentRoute.query.TrialReadingCriterionId
|
||||
|
||||
var path = "";
|
||||
var path = ''
|
||||
if (readingTool === 0) {
|
||||
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
|
||||
this.trialId
|
||||
}&subjectCode=${this.subjectCode}&subjectId=${
|
||||
this.subjectId
|
||||
}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`;
|
||||
}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
|
||||
} else {
|
||||
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
|
||||
this.trialId
|
||||
}&subjectCode=${this.subjectCode}&subjectId=${
|
||||
this.subjectId
|
||||
}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`;
|
||||
}&visitTaskId=${visitTaskId}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
|
||||
}
|
||||
var routeData = this.$router.resolve({ path });
|
||||
this.openWindow = window.open(routeData.href, "_blank");
|
||||
var routeData = this.$router.resolve({ path })
|
||||
this.openWindow = window.open(routeData.href, '_blank')
|
||||
},
|
||||
handleView(row, armEnum) {
|
||||
if (this.openWindow) {
|
||||
this.openWindow.close();
|
||||
this.openWindow.close()
|
||||
}
|
||||
// var token = getToken()
|
||||
// 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`
|
||||
// })
|
||||
// window.open(routeData.href, '_blank')
|
||||
var token = getToken();
|
||||
var task = row.VisitTaskInfoList.find((item) => item.ArmEnum === armEnum);
|
||||
var criterionType = this.$router.currentRoute.query.criterionType;
|
||||
var readingTool = this.$router.currentRoute.query.readingTool;
|
||||
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool);
|
||||
var token = getToken()
|
||||
var task = row.VisitTaskInfoList.find((item) => item.ArmEnum === armEnum)
|
||||
var criterionType = this.$router.currentRoute.query.criterionType
|
||||
var readingTool = this.$router.currentRoute.query.readingTool
|
||||
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool)
|
||||
var isReadingTaskViewInOrder =
|
||||
this.$router.currentRoute.query.isReadingTaskViewInOrder;
|
||||
this.$router.currentRoute.query.isReadingTaskViewInOrder
|
||||
var trialReadingCriterionId =
|
||||
this.$router.currentRoute.query.TrialReadingCriterionId;
|
||||
this.$router.currentRoute.query.TrialReadingCriterionId
|
||||
|
||||
var path = "";
|
||||
var path = ''
|
||||
if (readingTool === 0) {
|
||||
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
|
||||
this.trialId
|
||||
|
|
@ -812,7 +809,7 @@ export default {
|
|||
this.subjectId
|
||||
}&visitTaskId=${
|
||||
task.VisitTaskId
|
||||
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`;
|
||||
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
|
||||
} else {
|
||||
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
|
||||
this.trialId
|
||||
|
|
@ -820,26 +817,26 @@ export default {
|
|||
this.subjectId
|
||||
}&visitTaskId=${
|
||||
task.VisitTaskId
|
||||
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`;
|
||||
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
|
||||
}
|
||||
var routeData = this.$router.resolve({ path });
|
||||
this.openWindow = window.open(routeData.href, "_blank");
|
||||
var routeData = this.$router.resolve({ path })
|
||||
this.openWindow = window.open(routeData.href, '_blank')
|
||||
},
|
||||
handleViewGl(row, armEnum) {
|
||||
if (this.openWindow) {
|
||||
this.openWindow.close();
|
||||
this.openWindow.close()
|
||||
}
|
||||
var token = getToken();
|
||||
var task = row.VisitTaskInfoList.find((item) => item.ArmEnum === armEnum);
|
||||
var criterionType = this.$router.currentRoute.query.criterionType;
|
||||
var readingTool = this.$router.currentRoute.query.readingTool;
|
||||
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool);
|
||||
var token = getToken()
|
||||
var task = row.VisitTaskInfoList.find((item) => item.ArmEnum === armEnum)
|
||||
var criterionType = this.$router.currentRoute.query.criterionType
|
||||
var readingTool = this.$router.currentRoute.query.readingTool
|
||||
readingTool = isNaN(parseInt(readingTool)) ? null : parseInt(readingTool)
|
||||
var isReadingTaskViewInOrder =
|
||||
this.$router.currentRoute.query.isReadingTaskViewInOrder;
|
||||
this.$router.currentRoute.query.isReadingTaskViewInOrder
|
||||
var trialReadingCriterionId =
|
||||
this.$router.currentRoute.query.TrialReadingCriterionId;
|
||||
this.$router.currentRoute.query.TrialReadingCriterionId
|
||||
|
||||
var path = "";
|
||||
var path = ''
|
||||
if (readingTool === 0) {
|
||||
path = `/readingDicoms?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
|
||||
this.trialId
|
||||
|
|
@ -847,7 +844,7 @@ export default {
|
|||
this.subjectId
|
||||
}&visitTaskId=${
|
||||
task.GlobalVisitTaskId
|
||||
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`;
|
||||
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
|
||||
} else {
|
||||
path = `/noneDicomReading?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${
|
||||
this.trialId
|
||||
|
|
@ -855,10 +852,10 @@ export default {
|
|||
this.subjectId
|
||||
}&visitTaskId=${
|
||||
task.GlobalVisitTaskId
|
||||
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`;
|
||||
}&isReadingTaskViewInOrder=${isReadingTaskViewInOrder}&criterionType=${criterionType}&readingTool=${readingTool}&TokenKey=${token}&key=${new Date().getTime()}`
|
||||
}
|
||||
var routeData = this.$router.resolve({ path });
|
||||
this.openWindow = window.open(routeData.href, "_blank");
|
||||
var routeData = this.$router.resolve({ path })
|
||||
this.openWindow = window.open(routeData.href, '_blank')
|
||||
},
|
||||
// uploadScreenshot(param) {
|
||||
// this.loading = true
|
||||
|
|
@ -876,105 +873,93 @@ export default {
|
|||
// })
|
||||
// },
|
||||
async uploadScreenshot(param) {
|
||||
this.loading = true;
|
||||
this.uploadDisabled = false;
|
||||
var trialId = this.$route.query.trialId;
|
||||
var file = await this.fileToBlob(param.file);
|
||||
this.loading = true
|
||||
this.uploadDisabled = false
|
||||
var trialId = this.$route.query.trialId
|
||||
var file = await this.fileToBlob(param.file)
|
||||
const res = await this.OSSclient.put(
|
||||
`/${trialId}/Read/${this.subjectId}/visit/${param.file.name}`,
|
||||
file
|
||||
);
|
||||
console.log(res);
|
||||
)
|
||||
console.log(res)
|
||||
this.fileList.push({
|
||||
name: param.file.name,
|
||||
url: this.$getObjectName(res.url),
|
||||
});
|
||||
this.loading = false;
|
||||
this.uploadDisabled = true;
|
||||
url: this.$getObjectName(res.url)
|
||||
})
|
||||
this.loading = false
|
||||
this.uploadDisabled = true
|
||||
},
|
||||
handleBeforeUpload(file) {
|
||||
// 检测文件类型是否符合要求
|
||||
if (this.checkFileSuffix(file.name)) {
|
||||
return true;
|
||||
return true
|
||||
} else {
|
||||
const msg = this.$t("trials:adReview:title:msg4").replace(
|
||||
"xxx",
|
||||
const msg = this.$t('trials:adReview:title:msg4').replace(
|
||||
'xxx',
|
||||
this.accept
|
||||
);
|
||||
this.$alert(msg);
|
||||
return false;
|
||||
)
|
||||
this.$alert(msg)
|
||||
return false
|
||||
}
|
||||
},
|
||||
checkFileSuffix(fileName) {
|
||||
var index = fileName.lastIndexOf(".");
|
||||
var suffix = fileName.substring(index + 1, fileName.length);
|
||||
var index = fileName.lastIndexOf('.')
|
||||
var suffix = fileName.substring(index + 1, fileName.length)
|
||||
if (
|
||||
this.accept.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) ===
|
||||
-1
|
||||
) {
|
||||
return false;
|
||||
return false
|
||||
} else {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
},
|
||||
// 图片清空
|
||||
removeImage() {
|
||||
this.imageUrl = "";
|
||||
this.fileList = [];
|
||||
this.adForm.judgeResultImagePath = "";
|
||||
this.imageUrl = ''
|
||||
this.fileList = []
|
||||
this.adForm.judgeResultImagePath = ''
|
||||
},
|
||||
// 预览图片
|
||||
handlePictureCardPreview(file) {
|
||||
this.images = this.fileList.map(
|
||||
(f) => this.OSSclientConfig.basePath + f.url
|
||||
);
|
||||
)
|
||||
// this.imageUrl = this.OSSclientConfig.basePath + file.url
|
||||
this.$refs[file.url].$viewer.show();
|
||||
this.$refs[file.url].$viewer.show()
|
||||
},
|
||||
// 删除图片
|
||||
handleRemove(file, fileList) {
|
||||
var idx = this.fileList.findIndex((i) => i.url === file.url);
|
||||
if (idx === -1) return;
|
||||
this.fileList.splice(idx, 1);
|
||||
var idx = this.fileList.findIndex((i) => i.url === file.url)
|
||||
if (idx === -1) return
|
||||
this.fileList.splice(idx, 1)
|
||||
},
|
||||
async skipTask() {
|
||||
try {
|
||||
// 是否确认跳过?
|
||||
const confirm = await this.$confirm(
|
||||
this.$t("trials:readingReport:message:skipConfirm"),
|
||||
this.$t('trials:readingReport:message:skipConfirm'),
|
||||
{
|
||||
type: "warning",
|
||||
distinguishCancelAndClose: true,
|
||||
type: 'warning',
|
||||
distinguishCancelAndClose: true
|
||||
}
|
||||
);
|
||||
if (confirm !== "confirm") return;
|
||||
this.loading = true;
|
||||
)
|
||||
if (confirm !== 'confirm') return
|
||||
this.loading = true
|
||||
const res = await setSkipReadingCache({
|
||||
visitTaskId: this.visitTaskId,
|
||||
});
|
||||
this.loading = false;
|
||||
visitTaskId: this.visitTaskId
|
||||
})
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
window.location.reload();
|
||||
window.location.reload()
|
||||
}
|
||||
} catch (e) {
|
||||
this.loading = false;
|
||||
console.log(e);
|
||||
this.loading = false
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
initializeViewer() {
|
||||
Viewer.setDefaults({
|
||||
toolbar: {
|
||||
zoomIn: true,
|
||||
zoomOut: true,
|
||||
rotateLeft: true,
|
||||
rotateRight: true,
|
||||
flipHorizontal: true,
|
||||
flipVertical: true,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.adReview_wrapper {
|
||||
|
|
|
|||
|
|
@ -1654,7 +1654,7 @@ export default {
|
|||
resetWwwc() {
|
||||
this.toolState.viewportInvert = false
|
||||
var viewport = cornerstone.getViewport(this.canvas)
|
||||
viewport.invert = false
|
||||
// viewport.invert = false
|
||||
var image = cornerstone.getImage(this.canvas)
|
||||
viewport.voi.windowWidth = image.windowWidth
|
||||
viewport.voi.windowCenter = image.windowCenter
|
||||
|
|
|
|||
|
|
@ -352,7 +352,44 @@
|
|||
<div class="text">{{ $t('trials:reading:button:reset') }}</div>
|
||||
</div>
|
||||
</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="padding:5px">
|
||||
<!-- 手册 -->
|
||||
|
|
@ -433,13 +470,34 @@
|
|||
/>
|
||||
|
||||
<RecistQuestionList
|
||||
v-else-if="CriterionType !== 17"
|
||||
v-else-if="CriterionType === 1"
|
||||
ref="measurementList"
|
||||
:question-form-change-state="questionFormChangeState"
|
||||
:question-form-change-num="questionFormChangeNum"
|
||||
:is-show="isShow"
|
||||
: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>
|
||||
|
||||
|
|
@ -655,6 +713,21 @@
|
|||
</el-form-item>
|
||||
</el-form>
|
||||
</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>
|
||||
</template>
|
||||
<script>
|
||||
|
|
@ -677,6 +750,8 @@ import RecistBMQuestionList from './RecistBM/QuestionList'
|
|||
import IRecistQuestionList from './IRecist/QuestionList'
|
||||
import PCWGQuestionList from './PCWG/QuestionList'
|
||||
import LuganoQuestionList from './Lugano/QuestionList'
|
||||
import IVUSList from './IVUS/QuestionList'
|
||||
import OCTList from './OCT/QuestionList'
|
||||
import CustomWwwcForm from './CustomWwwcForm'
|
||||
import Manuals from './Manuals'
|
||||
import Hotkeys from './Hotkeys'
|
||||
|
|
@ -684,6 +759,9 @@ import WL from './WL'
|
|||
import Others from './Others'
|
||||
import DicomEvent from './DicomEvent'
|
||||
import html2canvas from 'html2canvas'
|
||||
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
|
||||
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
|
||||
import { getCriterionReadingInfo } from '@/api/trials'
|
||||
export default {
|
||||
name: 'DicomViewer',
|
||||
components: {
|
||||
|
|
@ -698,7 +776,12 @@ export default {
|
|||
PCWGQuestionList,
|
||||
RecistBMQuestionList,
|
||||
IRecistQuestionList,
|
||||
LuganoQuestionList },
|
||||
LuganoQuestionList,
|
||||
IVUSList,
|
||||
OCTList,
|
||||
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
|
||||
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
|
||||
},
|
||||
props: {
|
||||
isShow: {
|
||||
type: Boolean,
|
||||
|
|
@ -839,7 +922,16 @@ export default {
|
|||
activeCanvasWC: null,
|
||||
activeTaskInfo: {},
|
||||
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() {
|
||||
this.getHotKeys()
|
||||
this.getWwcTpl()
|
||||
this.getTrialCriterion()
|
||||
// cornerstone.imageCache.setMaximumSizeBytes(0)
|
||||
|
||||
// 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: '' }]
|
||||
} 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: '' }]
|
||||
} else if (this.CriterionType === 19) {
|
||||
this.measuredTools = []
|
||||
} else if (this.CriterionType === 20) {
|
||||
this.measuredTools = []
|
||||
}
|
||||
this.rotateList[0] = '1'
|
||||
this.colorList[0] = ''
|
||||
|
|
@ -1062,6 +1159,27 @@ export default {
|
|||
})
|
||||
},
|
||||
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() {
|
||||
// const loading = this.$loading({ fullscreen: true })
|
||||
try {
|
||||
|
|
@ -2072,15 +2190,15 @@ export default {
|
|||
},
|
||||
handleFusion() {
|
||||
// https 或者 本地开发环境才是安全上下文
|
||||
if (!window.isSecureContext) {
|
||||
this.$alert(this.$t('components:uploadvideo:message:xf3'))
|
||||
return
|
||||
}
|
||||
// 顶部文档是否开启跨源隔离
|
||||
if (!window.crossOriginIsolated) {
|
||||
this.$alert(this.$t('components:uploadvideo:message:xf4'))
|
||||
return
|
||||
}
|
||||
// if (!window.isSecureContext) {
|
||||
// this.$alert(this.$t('components:uploadvideo:message:xf3'))
|
||||
// return
|
||||
// }
|
||||
// // 顶部文档是否开启跨源隔离
|
||||
// if (!window.crossOriginIsolated) {
|
||||
// this.$alert(this.$t('components:uploadvideo:message:xf4'))
|
||||
// return
|
||||
// }
|
||||
if (this.imageQualityIssues && parseInt(this.imageQualityIssues) === 6) {
|
||||
this.$alert(this.$t('trials:lugano:message:fusionWarn'))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -276,7 +276,6 @@ import { submitTableQuestion, deleteReadingRowAnswer, getIsSuvMaxLesion } from '
|
|||
// import { uploadPrintscreen } from '@/api/reading'
|
||||
import DicomEvent from './../DicomEvent'
|
||||
import store from '@/store'
|
||||
import Viewer from 'v-viewer'
|
||||
export default {
|
||||
name: 'MeasurementForm',
|
||||
props: {
|
||||
|
|
@ -353,7 +352,6 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initializeViewer()
|
||||
this.trialId = this.$route.query.trialId
|
||||
this.initForm()
|
||||
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() {
|
||||
this.$refs.viewer[0].$viewer.show()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
{ 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']},
|
||||
]"
|
||||
: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">
|
||||
<div style="display: flex;flex-direction: row;justify-content: flex-start;align-items: center;">
|
||||
|
|
@ -211,16 +211,40 @@
|
|||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<!-- 数值 -->
|
||||
<el-input-number
|
||||
<!-- <el-input-number
|
||||
v-else-if="question.Type==='number'"
|
||||
v-model="questionForm[question.Id]"
|
||||
: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
|
||||
v-else-if="question.Type==='calculation'"
|
||||
v-model="questionForm[question.Id]"
|
||||
disabled
|
||||
/>
|
||||
>
|
||||
<template v-if="question.Unit" slot="append">
|
||||
{{ $fd('ValueUnit', parseInt(question.Unit)) }}
|
||||
</template>
|
||||
</el-input>
|
||||
<!-- 上传图像 -->
|
||||
<el-upload
|
||||
v-else-if="question.Type==='upload'"
|
||||
|
|
@ -326,7 +350,8 @@ export default {
|
|||
accept: '.png,.jpg,.jpeg',
|
||||
imgVisible: false,
|
||||
imageUrl: '',
|
||||
urls: []
|
||||
urls: [],
|
||||
digitPlaces: 2
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -352,6 +377,8 @@ export default {
|
|||
})
|
||||
}
|
||||
}
|
||||
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
||||
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
||||
},
|
||||
methods: {
|
||||
formItemChange(v, question) {
|
||||
|
|
@ -461,7 +488,7 @@ export default {
|
|||
}
|
||||
.uploadWrapper{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: column !important;
|
||||
align-items: flex-start;
|
||||
}
|
||||
/deep/ .el-input.is-disabled .el-input__inner{
|
||||
|
|
@ -470,6 +497,9 @@ export default {
|
|||
/deep/ .el-input-group__append, .el-input-group__prepend{
|
||||
padding: 0 10px;
|
||||
}
|
||||
/deep/ .el-form-item__content {
|
||||
width: 100%;
|
||||
}
|
||||
/deep/ .el-select.is-disabled .el-input__inner{
|
||||
background-color: #646464a1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export default {
|
|||
spleenInfo: null,
|
||||
calculateSpleenStatus: '',
|
||||
formChanged: false,
|
||||
digitPlaces: null
|
||||
digitPlaces: 2
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -374,7 +374,8 @@ export default {
|
|||
DicomEvent.$emit('getReportInfo', true)
|
||||
// DicomEvent.$emit('readingPageUpdate', {})
|
||||
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) {
|
||||
this.$confirm(this.$t('trials:reading:warnning:unableEvaluate'), '', {
|
||||
type: 'warning'
|
||||
|
|
@ -856,6 +857,7 @@ export default {
|
|||
.ecrf-wrapper{
|
||||
/deep/ .el-form-item__label{
|
||||
color: #c3c3c3;
|
||||
text-align: left;
|
||||
}
|
||||
/deep/ .el-input__inner{
|
||||
background-color: transparent;
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<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.IsBaseLine && scope.row.QuestionType=== 15">
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@
|
|||
>
|
||||
<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>
|
||||
|
|
@ -294,7 +294,14 @@ export default {
|
|||
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) {
|
||||
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||
if (idx > -1) {
|
||||
|
|
@ -342,8 +349,9 @@ export default {
|
|||
this.studyList = this.visitTaskList[idx].StudyList
|
||||
var sIdx = this.studyList.findIndex(s => s.IsDicom)
|
||||
if (sIdx > -1) {
|
||||
this.studyIndex = sIdx
|
||||
this.seriesIndex = 0
|
||||
console.log(this.studyIndex, this.studyIndex)
|
||||
// this.studyIndex = sIdx
|
||||
// c = 0
|
||||
this.activeNames = [`${this.studyList[sIdx].StudyId}`]
|
||||
// 下载关键序列
|
||||
const i = this.studyList.findIndex(i => i.IsCriticalSequence)
|
||||
|
|
@ -377,8 +385,23 @@ export default {
|
|||
var isReadingTaskViewInOrder = parseInt(this.$router.currentRoute.query.isReadingTaskViewInOrder)
|
||||
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||
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])
|
||||
if (Object.keys(obj).length !== 0) {
|
||||
this.studyIndex = obj.studyIndex
|
||||
|
|
@ -668,7 +691,11 @@ export default {
|
|||
this.currentSeriesIndex = seriesIndex
|
||||
var idx = this.visitTaskIdx
|
||||
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++) {
|
||||
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}`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1637,7 +1637,7 @@ export default {
|
|||
resetWwwc() {
|
||||
this.toolState.viewportInvert = false
|
||||
var viewport = cornerstone.getViewport(this.canvas)
|
||||
viewport.invert = false
|
||||
// viewport.invert = false
|
||||
var image = cornerstone.getImage(this.canvas)
|
||||
viewport.voi.windowWidth = image.windowWidth
|
||||
viewport.voi.windowCenter = image.windowCenter
|
||||
|
|
|
|||
|
|
@ -106,7 +106,8 @@
|
|||
v-if="item.val === 1"
|
||||
class="divider"
|
||||
content-position="center"
|
||||
>{{ ` ${$t("trials:reading:title:preset")}` }}</el-divider>
|
||||
>{{ ` ${$t('trials:reading:title:preset')}` }}</el-divider
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -163,7 +164,7 @@
|
|||
<svg-icon icon-class="magnifier" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 缩放 -->
|
||||
<div class="text">{{ $t("trials:reading:button:zoom") }}</div>
|
||||
<div class="text">{{ $t('trials:reading:button:zoom') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
|
|
@ -183,7 +184,7 @@
|
|||
<svg-icon icon-class="move" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 移动 -->
|
||||
<div class="text">{{ $t("trials:reading:button:move") }}</div>
|
||||
<div class="text">{{ $t('trials:reading:button:move') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
|
|
@ -210,7 +211,7 @@
|
|||
</div>
|
||||
<!-- 旋转 -->
|
||||
<div class="text">
|
||||
{{ $t("trials:reading:button:rotate")
|
||||
{{ $t('trials:reading:button:rotate')
|
||||
}}<i class="el-icon-caret-bottom" />
|
||||
</div>
|
||||
<div class="dropdown-content">
|
||||
|
|
@ -223,7 +224,8 @@
|
|||
<a
|
||||
href="#"
|
||||
@click.prevent="setDicomCanvasRotate(rotate.val)"
|
||||
>{{ rotate.label }}</a>
|
||||
>{{ rotate.label }}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -258,8 +260,8 @@
|
|||
<div class="text">
|
||||
{{
|
||||
fitType === 1
|
||||
? $t("trials:reading:button:fitWindow")
|
||||
: $t("trials:reading:button:fitImage")
|
||||
? $t('trials:reading:button:fitWindow')
|
||||
: $t('trials:reading:button:fitImage')
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -282,7 +284,7 @@
|
|||
</div>
|
||||
<!-- 同步 -->
|
||||
<div class="text">
|
||||
{{ $t("trials:reading:button:imageIndexSync") }}
|
||||
{{ $t('trials:reading:button:imageIndexSync') }}
|
||||
</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
|
@ -307,7 +309,7 @@
|
|||
<svg-icon icon-class="image" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 截屏 -->
|
||||
<div class="text">{{ $t("trials:reading:button:screenShot") }}</div>
|
||||
<div class="text">{{ $t('trials:reading:button:screenShot') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
|
|
@ -316,7 +318,7 @@
|
|||
<div slot="content">
|
||||
<div v-if="tool.disabledReason">
|
||||
<h4 style="margin: 0; padding-bottom: 2px">{{ tool.text }}</h4>
|
||||
<br>{{ tool.disabledReason }}
|
||||
<br />{{ tool.disabledReason }}
|
||||
</div>
|
||||
<div v-else>{{ tool.text }}</div>
|
||||
</div>
|
||||
|
|
@ -365,7 +367,7 @@
|
|||
<svg-icon icon-class="clear" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 缩放 -->
|
||||
<div class="text">{{ $t("trials:dicom-show:Eraser") }}</div>
|
||||
<div class="text">{{ $t('trials:dicom-show:Eraser') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<div class="tool-frame">
|
||||
|
|
@ -467,11 +469,11 @@
|
|||
<div class="icon" @click.prevent="resetViewport">
|
||||
<svg-icon icon-class="refresh" class="svg-icon" />
|
||||
</div>
|
||||
<div class="text">{{ $t("trials:reading:button:reset") }}</div>
|
||||
<div class="text">{{ $t('trials:reading:button:reset') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="trialCriterion.ImageUploadEnum > 0"
|
||||
v-if="trialCriterion.ImageUploadEnum > 0 && currentReadingTaskState < 2"
|
||||
v-hasPermi="['role:ir']"
|
||||
class="item"
|
||||
effect="dark"
|
||||
|
|
@ -482,7 +484,7 @@
|
|||
<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 class="text">{{ $t('trials:reading:button:upload') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
|
|
@ -505,7 +507,7 @@
|
|||
<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 class="text">{{ $t('trials:reading:button:download') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
|
|
@ -515,17 +517,19 @@
|
|||
v-if="isExistsManual"
|
||||
type="text"
|
||||
@click="previewManuals"
|
||||
>{{ $t("trials:reading:button:handbooks") }}</el-button>
|
||||
>{{ $t('trials:reading:button:handbooks') }}</el-button
|
||||
>
|
||||
<!-- 临床数据 -->
|
||||
<el-button
|
||||
v-if="isExistsClinicalData"
|
||||
type="text"
|
||||
@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 type="text" @click="previewConfig">{{
|
||||
$t("trials:reading:button:customCfg")
|
||||
$t('trials:reading:button:customCfg')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -625,7 +629,7 @@
|
|||
:fullscreen="isFullscreen"
|
||||
>
|
||||
<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">
|
||||
<svg-icon
|
||||
: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')">-->
|
||||
<!-- <svg-icon icon-class="clear" style="font-size:20px;" />-->
|
||||
<!-- </button>-->
|
||||
<upload-image
|
||||
<!-- <upload-image
|
||||
v-if="uploadImageVisible"
|
||||
:visible.sync="uploadImageVisible"
|
||||
:subject-id="subjectId"
|
||||
:criterion="trialCriterion"
|
||||
: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>
|
||||
</template>
|
||||
|
|
@ -676,7 +695,8 @@ import DicomEvent from './../components/DicomEvent'
|
|||
import { mapGetters } from 'vuex'
|
||||
import store from '@/store'
|
||||
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'
|
||||
export default {
|
||||
name: 'DicomViewer',
|
||||
|
|
@ -688,48 +708,49 @@ export default {
|
|||
Others,
|
||||
Manuals,
|
||||
MeasurementList,
|
||||
'upload-image': uploadImage
|
||||
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
|
||||
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
|
||||
},
|
||||
props: {
|
||||
isExistsClinicalData: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
default: false,
|
||||
},
|
||||
isExistsNoDicomFile: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
default: false,
|
||||
},
|
||||
isExistsManual: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
isReadingShowSubjectInfo: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
isReadingTaskViewInOrder: {
|
||||
type: Number,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
IseCRFShowInDicomReading: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
subjectId: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: ''
|
||||
default: '',
|
||||
},
|
||||
trialReadingCriterionId: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: ''
|
||||
default: '',
|
||||
},
|
||||
trialId: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: ''
|
||||
}
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -738,7 +759,7 @@ export default {
|
|||
{ index: 0, row: 1, col: 1, name: 'A' },
|
||||
{ index: 1, row: 1, col: 2, name: 'A|A' },
|
||||
{ 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: 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:rotateHorizontal'), val: 3 }, // 水平翻转
|
||||
{ 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,
|
||||
layoutRow: 1,
|
||||
|
|
@ -755,8 +776,8 @@ export default {
|
|||
currentDicomCanvasIndex: 0,
|
||||
currentDicomCanvas: {
|
||||
toolState: {
|
||||
clipPlaying: false
|
||||
}
|
||||
clipPlaying: false,
|
||||
},
|
||||
},
|
||||
colormapsList: [],
|
||||
rotateList: [],
|
||||
|
|
@ -773,7 +794,7 @@ export default {
|
|||
text: this.$t('trials:reading:button:length'),
|
||||
icon: 'length',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
disabledReason: '',
|
||||
},
|
||||
// 长短径测量
|
||||
{
|
||||
|
|
@ -781,7 +802,7 @@ export default {
|
|||
text: this.$t('trials:reading:button:bidirectional'),
|
||||
icon: 'bidirection',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
disabledReason: '',
|
||||
},
|
||||
// 矩形工具
|
||||
{
|
||||
|
|
@ -789,7 +810,7 @@ export default {
|
|||
text: this.$t('trials:reading:button:rectangle'),
|
||||
icon: 'rectangle',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
disabledReason: '',
|
||||
},
|
||||
// 圆形工具
|
||||
{
|
||||
|
|
@ -797,7 +818,7 @@ export default {
|
|||
text: this.$t('trials:reading:button:elliptical'),
|
||||
icon: 'oval',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
disabledReason: '',
|
||||
},
|
||||
// 箭头工具
|
||||
{
|
||||
|
|
@ -805,8 +826,8 @@ export default {
|
|||
text: this.$t('trials:reading:button:arrowAnnotate'),
|
||||
icon: 'arrow',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
}
|
||||
disabledReason: '',
|
||||
},
|
||||
],
|
||||
|
||||
fitType: 0,
|
||||
|
|
@ -818,25 +839,25 @@ export default {
|
|||
label: this.$t('trials:reading:button:wwwcDefault'),
|
||||
val: -1,
|
||||
ww: null,
|
||||
wc: null
|
||||
wc: null,
|
||||
}, // 默认值
|
||||
{
|
||||
label: this.$t('trials:reading:button:wwwcCustom'),
|
||||
val: 0,
|
||||
ww: null,
|
||||
wc: null
|
||||
wc: null,
|
||||
}, // 自定义
|
||||
{
|
||||
label: this.$t('trials:reading:button:wwwcRegion'),
|
||||
val: 1,
|
||||
ww: null,
|
||||
wc: null
|
||||
wc: null,
|
||||
}, // 区域窗宽
|
||||
{ label: 'CT Brain', wc: 40, ww: 80 },
|
||||
{ label: 'CT Lungs', wc: -400, ww: 1500 },
|
||||
{ label: 'CT Abdomen', wc: 60, ww: 400 },
|
||||
{ label: 'CT Liver', wc: 40, ww: 400 },
|
||||
{ label: 'CT Bone', wc: 300, ww: 1500 }
|
||||
{ label: 'CT Bone', wc: 300, ww: 1500 },
|
||||
],
|
||||
activeSeries: {},
|
||||
seriesStack: [],
|
||||
|
|
@ -844,13 +865,13 @@ export default {
|
|||
isScrollSync: false,
|
||||
imageIndexSync: {
|
||||
sourceCanvas: '',
|
||||
targetCanvas: []
|
||||
targetCanvas: [],
|
||||
},
|
||||
isFirstRender: false,
|
||||
customWwc: { visible: false, title: null }, // 自定义调窗
|
||||
personalConfigDialog: {
|
||||
visible: false,
|
||||
title: this.$t('trials:reading:button:customCfg')
|
||||
title: this.$t('trials:reading:button:customCfg'),
|
||||
}, // 个性化配置
|
||||
layout: '',
|
||||
isFirstNotLinked: false,
|
||||
|
|
@ -861,15 +882,20 @@ export default {
|
|||
manualsDialog: { visible: false },
|
||||
clipPlaying: false,
|
||||
fps: 15,
|
||||
// 上传
|
||||
uploadImageVisible: false,
|
||||
trialCriterion: {},
|
||||
uploadStatus: 'upload'
|
||||
// 上传
|
||||
downloadImageVisible: false,
|
||||
uploadImageVisible: false,
|
||||
uploadSubjectId: null,
|
||||
uploadSubjectCode: null,
|
||||
uploadTrialCriterion: {},
|
||||
uploadStatus: 'upload',
|
||||
taskId: ''
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters(['visitTaskList', 'currentReadingTaskState'])
|
||||
...mapGetters(['visitTaskList', 'currentReadingTaskState']),
|
||||
},
|
||||
watch: {
|
||||
currentReadingTaskState: {
|
||||
|
|
@ -888,7 +914,7 @@ export default {
|
|||
this.activeTool = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
currentDicomCanvasIndex: {
|
||||
immediate: true,
|
||||
|
|
@ -905,8 +931,8 @@ export default {
|
|||
this.clipPlaying = false
|
||||
this.fps = 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getTrialCriterion()
|
||||
|
|
@ -919,7 +945,7 @@ export default {
|
|||
// cornerstone.imageCache.setMaximumSizeBytes(maximumSizeInBytes)
|
||||
this.customWwc = {
|
||||
visible: false,
|
||||
title: this.$t('trials:reading:dagTitle:wwwcCustom')
|
||||
title: this.$t('trials:reading:dagTitle:wwwcCustom'),
|
||||
}
|
||||
this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
|
||||
if (this.CriterionType === 10) {
|
||||
|
|
@ -929,15 +955,15 @@ export default {
|
|||
text: this.$t('trials:reading:button:arrowAnnotate'),
|
||||
icon: 'arrow',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
disabledReason: '',
|
||||
},
|
||||
{
|
||||
toolName: 'RectangleRoi',
|
||||
text: this.$t('trials:reading:button:rectangle'),
|
||||
icon: 'rectangle',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
}
|
||||
disabledReason: '',
|
||||
},
|
||||
]
|
||||
} else if (this.CriterionType === 17) {
|
||||
this.measuredTools = [
|
||||
|
|
@ -946,22 +972,22 @@ export default {
|
|||
text: this.$t('trials:reading:button:length'),
|
||||
icon: 'length',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
disabledReason: '',
|
||||
},
|
||||
{
|
||||
toolName: 'RectangleRoi',
|
||||
text: this.$t('trials:reading:button:rectangle'),
|
||||
icon: 'rectangle',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
disabledReason: '',
|
||||
},
|
||||
{
|
||||
toolName: 'ArrowAnnotate',
|
||||
text: this.$t('trials:reading:button:arrowAnnotate'),
|
||||
icon: 'arrow',
|
||||
isDisabled: false,
|
||||
disabledReason: ''
|
||||
}
|
||||
disabledReason: '',
|
||||
},
|
||||
]
|
||||
}
|
||||
this.rotateList[0] = '1'
|
||||
|
|
@ -1041,7 +1067,7 @@ export default {
|
|||
getTrialCriterion() {
|
||||
getCriterionReadingInfo({
|
||||
TrialId: this.trialId,
|
||||
TrialReadingCriterionId: this.trialReadingCriterionId
|
||||
TrialReadingCriterionId: this.trialReadingCriterionId,
|
||||
})
|
||||
.then((res) => {
|
||||
this.trialCriterion = res.Result
|
||||
|
|
@ -1049,26 +1075,32 @@ export default {
|
|||
.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.uploadImageVisible = true
|
||||
this[`${status}ImageVisible`] = true
|
||||
},
|
||||
async getWwcTpl() {
|
||||
// const loading = this.$loading({ fullscreen: true })
|
||||
try {
|
||||
let res = await getUserWLTemplateList()
|
||||
this.customWwcTpl = []
|
||||
res.Result.map((i) => {
|
||||
this.customWwcTpl.push({
|
||||
label: i.TemplateName,
|
||||
wc: i.WL,
|
||||
ww: i.WW
|
||||
})
|
||||
res.Result.map((i) => {
|
||||
this.customWwcTpl.push({
|
||||
label: i.TemplateName,
|
||||
wc: i.WL,
|
||||
ww: i.WW,
|
||||
})
|
||||
this.wwwcArr = [...this.defaultWwwc, ...this.customWwcTpl]
|
||||
} catch(e) {
|
||||
})
|
||||
this.wwwcArr = [...this.defaultWwwc, ...this.customWwcTpl]
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
},
|
||||
async getHotKeys() {
|
||||
// const loading = this.$loading({ fullscreen: true })
|
||||
|
|
@ -1084,11 +1116,11 @@ export default {
|
|||
key: item.Keyboardkey,
|
||||
code: item.Code,
|
||||
text: item.Text,
|
||||
shortcutKeyEnum: item.ShortcutKeyEnum
|
||||
shortcutKeyEnum: item.ShortcutKeyEnum,
|
||||
})
|
||||
})
|
||||
this.bindHotKey()
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
|
|
@ -1105,7 +1137,7 @@ export default {
|
|||
key: item.keys.controlKey.key,
|
||||
code: item.keys.controlKey.code,
|
||||
text: item.keys.text,
|
||||
shortcutKeyEnum: item.label
|
||||
shortcutKeyEnum: item.label,
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -1148,7 +1180,7 @@ export default {
|
|||
DicomEvent.$emit('selectSeries', {
|
||||
seriesId: series.seriesId,
|
||||
studyId: series.studyId,
|
||||
offset: -1
|
||||
offset: -1,
|
||||
})
|
||||
} else if (shortcutKeyEnum === 4) {
|
||||
// 下一个序列
|
||||
|
|
@ -1157,7 +1189,7 @@ export default {
|
|||
DicomEvent.$emit('selectSeries', {
|
||||
seriesId: series.seriesId,
|
||||
studyId: series.studyId,
|
||||
offset: 1
|
||||
offset: 1,
|
||||
})
|
||||
} else if (shortcutKeyEnum === 5) {
|
||||
// 上一张图像
|
||||
|
|
@ -1287,7 +1319,7 @@ export default {
|
|||
top: '72px',
|
||||
left: '205px',
|
||||
right: '350px',
|
||||
zIndex: 10
|
||||
zIndex: 10,
|
||||
}
|
||||
this.canvasW = window.innerWidth - 570 + 'px'
|
||||
this.canvasH = window.innerHeight - 130 + 'px'
|
||||
|
|
@ -1387,10 +1419,7 @@ export default {
|
|||
// this.$refs['measurementList'].initPage(dicomSeries)
|
||||
store.dispatch('reading/setActiveSeries', dicomSeries)
|
||||
if (this.currentDicomCanvasIndex === this.maxCanvas - 1) {
|
||||
store.dispatch(
|
||||
'reading/setLastCanvasTaskId',
|
||||
dicomSeries.visitTaskId
|
||||
)
|
||||
store.dispatch('reading/setLastCanvasTaskId', dicomSeries.visitTaskId)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
|
@ -1421,10 +1450,7 @@ export default {
|
|||
|
||||
store.dispatch('reading/setActiveSeries', dicomSeries)
|
||||
if (this.currentDicomCanvasIndex === this.maxCanvas - 1) {
|
||||
store.dispatch(
|
||||
'reading/setLastCanvasTaskId',
|
||||
dicomSeries.visitTaskId
|
||||
)
|
||||
store.dispatch('reading/setLastCanvasTaskId', dicomSeries.visitTaskId)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
|
@ -1474,7 +1500,7 @@ export default {
|
|||
visitTaskId = this.visitTaskList[i].VisitTaskId
|
||||
}
|
||||
this.getFirstSeries(activeSeries, visitTaskId).then(
|
||||
async(baseSerires) => {
|
||||
async (baseSerires) => {
|
||||
this.seriesStack = [baseSerires, activeSeries]
|
||||
this.currentDicomCanvasIndex = 1
|
||||
store.dispatch(
|
||||
|
|
@ -1502,7 +1528,7 @@ export default {
|
|||
activeSeries,
|
||||
activeSeries,
|
||||
activeSeries,
|
||||
activeSeries
|
||||
activeSeries,
|
||||
]
|
||||
this.currentDicomCanvasIndex = 3
|
||||
store.dispatch(
|
||||
|
|
@ -1521,9 +1547,7 @@ export default {
|
|||
for (let i = 0; i < this.maxCanvas && i < seriesStack.length; i++) {
|
||||
this.canvasObj[i] = seriesStack[i]
|
||||
let s = Object.assign({}, seriesStack[i])
|
||||
promiseArr.push(
|
||||
this.$refs[`dicomCanvas${i}`][0].loadImageStack(s)
|
||||
)
|
||||
promiseArr.push(this.$refs[`dicomCanvas${i}`][0].loadImageStack(s))
|
||||
}
|
||||
Promise.all(promiseArr)
|
||||
.then(() => {
|
||||
|
|
@ -1585,24 +1609,24 @@ export default {
|
|||
trialId: this.trialId,
|
||||
subjectVisitId: this.visitTaskList[taskIdx].VisitId,
|
||||
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId,
|
||||
taskBlindName: this.visitTaskList[taskIdx].TaskBlindName
|
||||
taskBlindName: this.visitTaskList[taskIdx].TaskBlindName,
|
||||
})
|
||||
}
|
||||
if (!this.visitTaskList[taskIdx].readingQuestionsInit) {
|
||||
await store.dispatch('reading/getReadingQuestionAndAnswer', {
|
||||
trialId: this.trialId,
|
||||
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId
|
||||
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId,
|
||||
})
|
||||
}
|
||||
if (!this.visitTaskList[taskIdx].questionsInit) {
|
||||
await store.dispatch('reading/getDicomReadingQuestionAnswer', {
|
||||
trialId: this.trialId,
|
||||
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId
|
||||
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId,
|
||||
})
|
||||
}
|
||||
|
||||
await store.dispatch('reading/setStatus', {
|
||||
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId
|
||||
visitTaskId: this.visitTaskList[taskIdx].VisitTaskId,
|
||||
})
|
||||
}
|
||||
firstAddSeries = this.getSeriesInfoByMark(firstAddVisitTaskId, obj)
|
||||
|
|
@ -1696,8 +1720,7 @@ export default {
|
|||
var studyList = this.visitTaskList[index].StudyList
|
||||
var studyId = this.visitTaskList[index].MeasureData[idx].StudyId
|
||||
var seriesId = this.visitTaskList[index].MeasureData[idx].SeriesId
|
||||
var instanceId =
|
||||
this.visitTaskList[index].MeasureData[idx].InstanceId
|
||||
var instanceId = this.visitTaskList[index].MeasureData[idx].InstanceId
|
||||
var studyIdx = studyList.findIndex(
|
||||
(study) => study.StudyId === studyId
|
||||
)
|
||||
|
|
@ -1706,10 +1729,15 @@ export default {
|
|||
(s) => s.seriesId === seriesId
|
||||
)
|
||||
if (seriesIdx > -1) {
|
||||
var series = studyList[studyIdx].SeriesList[seriesIdx];
|
||||
let frame = this.visitTaskList[index].MeasureData[idx].MeasureData.frame
|
||||
let filterStr = series.isExistMutiFrames ? `frame=${frame}&instanceId=${instanceId}` : `instanceId=${instanceId}`
|
||||
var instanceIdx = series.imageIds.findIndex(imageId => imageId.includes(filterStr))
|
||||
var series = studyList[studyIdx].SeriesList[seriesIdx]
|
||||
let frame =
|
||||
this.visitTaskList[index].MeasureData[idx].MeasureData.frame
|
||||
let filterStr = series.isExistMutiFrames
|
||||
? `frame=${frame}&instanceId=${instanceId}`
|
||||
: `instanceId=${instanceId}`
|
||||
var instanceIdx = series.imageIds.findIndex((imageId) =>
|
||||
imageId.includes(filterStr)
|
||||
)
|
||||
// var instanceIdx = series.instanceList.findIndex(
|
||||
// (imageId) => !!~imageId.indexOf(instanceId)
|
||||
// );
|
||||
|
|
@ -1738,16 +1766,14 @@ export default {
|
|||
i.description,
|
||||
baseSeries.description
|
||||
),
|
||||
index
|
||||
index,
|
||||
}
|
||||
})
|
||||
similarArr = similarArr.sort((a, b) => {
|
||||
return b.similar - a.similar
|
||||
})
|
||||
const i =
|
||||
similarArr[0] && similarArr[0].similar > 0.85
|
||||
? similarArr[0].index
|
||||
: -1
|
||||
similarArr[0] && similarArr[0].similar > 0.85 ? similarArr[0].index : -1
|
||||
if (i > -1) {
|
||||
obj = seriesList[i]
|
||||
}
|
||||
|
|
@ -1822,7 +1848,7 @@ export default {
|
|||
trialId: this.trialId,
|
||||
subjectVisitId: this.visitTaskList[index].VisitId,
|
||||
visitTaskId: this.visitTaskList[index].VisitTaskId,
|
||||
taskBlindName: this.visitTaskList[index].TaskBlindName
|
||||
taskBlindName: this.visitTaskList[index].TaskBlindName,
|
||||
})
|
||||
|
||||
await store.dispatch(
|
||||
|
|
@ -1841,16 +1867,14 @@ export default {
|
|||
i.description,
|
||||
baseSeries.description
|
||||
),
|
||||
index
|
||||
index,
|
||||
}
|
||||
})
|
||||
similarArr = similarArr.sort((a, b) => {
|
||||
return b.similar - a.similar
|
||||
})
|
||||
const i =
|
||||
similarArr[0] && similarArr[0].similar > 0.85
|
||||
? similarArr[0].index
|
||||
: -1
|
||||
similarArr[0] && similarArr[0].similar > 0.85 ? similarArr[0].index : -1
|
||||
if (i > -1) {
|
||||
obj = seriesList[i]
|
||||
}
|
||||
|
|
@ -2025,9 +2049,7 @@ export default {
|
|||
},
|
||||
// 鼠标移入测量工具时,判断工具是否可激活
|
||||
enter(e, toolName) {
|
||||
var i = this.measuredTools.findIndex(
|
||||
(item) => item.toolName === toolName
|
||||
)
|
||||
var i = this.measuredTools.findIndex((item) => item.toolName === toolName)
|
||||
if (i === -1) return
|
||||
var isCurrentTask =
|
||||
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0]
|
||||
|
|
@ -2089,8 +2111,11 @@ export default {
|
|||
`dicomCanvas${this.currentDicomCanvasIndex}`
|
||||
][0].setToolActive(toolName)
|
||||
}
|
||||
} else if (dicomSeries.isCurrentTask &&
|
||||
isMeasuredTool && dicomSeries.readingTaskState >= 2) {
|
||||
} else if (
|
||||
dicomSeries.isCurrentTask &&
|
||||
isMeasuredTool &&
|
||||
dicomSeries.readingTaskState >= 2
|
||||
) {
|
||||
if (this.activeTool === toolName) {
|
||||
this.$refs[
|
||||
`dicomCanvas${this.currentDicomCanvasIndex}`
|
||||
|
|
@ -2162,9 +2187,7 @@ export default {
|
|||
][0].fitToWindow()
|
||||
} else if (toolName === 'fitToImage') {
|
||||
this.fitType = 1
|
||||
this.$refs[
|
||||
`dicomCanvas${this.currentDicomCanvasIndex}`
|
||||
][0].fitToImage()
|
||||
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].fitToImage()
|
||||
}
|
||||
this.activeTool = toolName
|
||||
},
|
||||
|
|
@ -2181,7 +2204,9 @@ export default {
|
|||
const isLoaded = this.getSeriesLoadStatus()
|
||||
if (!isLoaded) return
|
||||
this.clipPlaying = isPlay
|
||||
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setFps(this.fps)
|
||||
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setFps(
|
||||
this.fps
|
||||
)
|
||||
this.$refs[
|
||||
`dicomCanvas${this.currentDicomCanvasIndex}`
|
||||
][0].toggleClipPlay(isPlay)
|
||||
|
|
@ -2297,8 +2322,8 @@ export default {
|
|||
previewManuals() {
|
||||
this.isFullscreen = false
|
||||
this.manualsDialog.visible = true
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
|
|
@ -244,6 +244,7 @@ export default {
|
|||
params.StudyId = params.questionInfo.StudyId
|
||||
params.SeriesId = params.questionInfo.SeriesId
|
||||
params.InstanceId = params.questionInfo.InstanceId
|
||||
params.NumberOfFrames = measureData.frame
|
||||
submitCustomTag(params).then(() => {
|
||||
this.measuredDataVisible = false
|
||||
DicomEvent.$emit('updateImage')
|
||||
|
|
@ -282,6 +283,7 @@ export default {
|
|||
} else {
|
||||
let params = JSON.parse(JSON.stringify(this.measureData))
|
||||
params.measureData = JSON.stringify(this.measureData)
|
||||
params.NumberOfFrames = this.measureData.frame
|
||||
submitCustomTag(params).then(async (res) => {
|
||||
this.measuredDataVisible = false
|
||||
this.form.measuredDataName = ''
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@
|
|||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
</el-upload>
|
||||
<el-dialog
|
||||
<!-- <el-dialog
|
||||
v-if="question.Type==='upload'"
|
||||
append-to-body
|
||||
:visible.sync="imgVisible"
|
||||
|
|
@ -250,7 +250,20 @@
|
|||
加载中<span class="dot">...</span>
|
||||
</div>
|
||||
</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>
|
||||
</template>
|
||||
|
||||
|
|
@ -801,6 +814,9 @@ export default {
|
|||
}else{
|
||||
this.imageUrl = this.OSSclientConfig.basePath + file.url
|
||||
this.imgVisible = true
|
||||
this.$nextTick(()=>{
|
||||
this.$refs[this.imageUrl].$viewer.show()
|
||||
})
|
||||
}
|
||||
},
|
||||
// 删除图片
|
||||
|
|
|
|||
|
|
@ -138,27 +138,41 @@
|
|||
>
|
||||
<i slot="default" class="el-icon-plus" />
|
||||
<div slot="file" slot-scope="{file}">
|
||||
<img
|
||||
class="el-upload-list__item-thumbnail"
|
||||
:src="OSSclientConfig.basePath + file.url"
|
||||
alt=""
|
||||
<viewer
|
||||
:ref="file.url"
|
||||
:images="[imageUrl]"
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
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>
|
||||
<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
|
||||
v-if="readingTaskState < 2"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleRemove(file)"
|
||||
>
|
||||
<i class="el-icon-delete" />
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</viewer>
|
||||
</div>
|
||||
</el-upload>
|
||||
<el-dialog
|
||||
|
|
@ -308,7 +322,7 @@ export default {
|
|||
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();
|
||||
}
|
||||
},
|
||||
// 删除图片
|
||||
|
|
|
|||
|
|
@ -148,27 +148,41 @@
|
|||
>
|
||||
<i slot="default" class="el-icon-plus" />
|
||||
<div slot="file" slot-scope="{file}">
|
||||
<img
|
||||
class="el-upload-list__item-thumbnail"
|
||||
:src="OSSclientConfig.basePath + file.url"
|
||||
alt=""
|
||||
<viewer
|
||||
:ref="file.url"
|
||||
:images="[imageUrl]"
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
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>
|
||||
<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
|
||||
v-if="readingTaskState < 2"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleRemove(file)"
|
||||
>
|
||||
<i class="el-icon-delete" />
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</viewer>
|
||||
</div>
|
||||
</el-upload>
|
||||
<el-dialog
|
||||
|
|
@ -492,7 +506,8 @@ export default {
|
|||
window.open(this.OSSclientConfig.basePath + file.url,'_blank')
|
||||
}else{
|
||||
this.imageUrl = this.OSSclientConfig.basePath + file.url
|
||||
this.imgVisible = true
|
||||
// this.imgVisible = true
|
||||
this.$refs[file.url].$viewer.show()
|
||||
}
|
||||
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,41 +14,43 @@
|
|||
>
|
||||
<i slot="default" class="el-icon-plus" />
|
||||
<div slot="file" slot-scope="{file}">
|
||||
<img
|
||||
class="el-upload-list__item-thumbnail"
|
||||
crossOrigin="Anonymous"
|
||||
:src="OSSclientConfig.basePath + file.url"
|
||||
alt=""
|
||||
<viewer
|
||||
:ref="file.url"
|
||||
:images="[imageUrl]"
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
|
|
@ -142,7 +144,8 @@ name: "CustomizeReportPageUpload",
|
|||
window.open(this.OSSclientConfig.basePath + file.url,'_blank')
|
||||
}else{
|
||||
this.imageUrl = this.OSSclientConfig.basePath + file.url
|
||||
this.imgVisible = true
|
||||
// this.imgVisible = true
|
||||
this.$refs[file.url].$viewer.show()
|
||||
}
|
||||
},
|
||||
// 删除图片
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@
|
|||
</div> -->
|
||||
<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>
|
||||
|
|
@ -279,7 +279,14 @@ export default {
|
|||
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) {
|
||||
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||
if (idx > -1) {
|
||||
|
|
@ -356,7 +363,22 @@ export default {
|
|||
var isReadingTaskViewInOrder = JSON.parse(this.$router.currentRoute.query.isReadingTaskViewInOrder)
|
||||
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||
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])
|
||||
if (Object.keys(obj).length !== 0) {
|
||||
|
|
@ -652,7 +674,11 @@ export default {
|
|||
this.studyList[studyIndex].SeriesList[seriesIndex].measureData = this.measureData
|
||||
var dicomStatck = Object.assign({},this.studyList[studyIndex].SeriesList[seriesIndex])
|
||||
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++) {
|
||||
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}`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ export default {
|
|||
// this.readingTool = this.$router.currentRoute.query.readingTool
|
||||
this.TrialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
|
||||
// this.isNewSubject = this.$router.currentRoute.query.isNewSubject
|
||||
localStorage.setItem('isReadingTaskViewInOrder', this.isReadingTaskViewInOrder)
|
||||
|
||||
// if (this.isNewSubject && this.isReadingTaskViewInOrder !== 0) {
|
||||
// // 已开始受试者${this.subjectCode}阅片任务
|
||||
// var msg = this.$t('trials:reading:warnning:msg1')
|
||||
|
|
@ -332,6 +332,7 @@ export default {
|
|||
this.digitPlaces = res.Result.DigitPlaces
|
||||
this.IseCRFShowInDicomReading = res.Result.IseCRFShowInDicomReading
|
||||
this.isReadingTaskViewInOrder = res.Result.IsReadingTaskViewInOrder
|
||||
localStorage.setItem('isReadingTaskViewInOrder', this.isReadingTaskViewInOrder)
|
||||
localStorage.setItem('CriterionType', res.Result.CriterionType)
|
||||
localStorage.setItem('digitPlaces', res.Result.DigitPlaces)
|
||||
this.readingCategory = res.Result.ReadingCategory
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
</div>
|
||||
<!-- 文件层级 -->
|
||||
<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 v-else id="imgList" style="height:100%;">
|
||||
<div
|
||||
|
|
@ -28,7 +28,14 @@
|
|||
class="img-box"
|
||||
@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>
|
||||
|
|
@ -96,7 +103,7 @@ export default {
|
|||
visistTaskId: '',
|
||||
taskBlindName: '',
|
||||
readingTaskState: 2,
|
||||
bp:[]
|
||||
bp: []
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
|
|
@ -188,7 +195,7 @@ export default {
|
|||
}
|
||||
var arr = bodyPart.split(separator)
|
||||
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(' | ')
|
||||
}
|
||||
|
|
@ -265,13 +272,19 @@ export default {
|
|||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2px solid #f3f3f3;
|
||||
width: 180px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
cursor: pointer;
|
||||
// margin-bottom: 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){
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,6 @@ import { getMedicalReviewDialog } from '@/api/trials'
|
|||
import FeedbackForm from './FeedbackForm'
|
||||
import mimAvatar from '@/assets/MIM.png'
|
||||
import irAvatar from '@/assets/IR.png'
|
||||
import Viewer from 'v-viewer'
|
||||
export default {
|
||||
name: 'ChatForm',
|
||||
components: { FeedbackForm },
|
||||
|
|
@ -177,7 +176,6 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initializeViewer()
|
||||
this.getMessageList()
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -213,11 +211,6 @@ export default {
|
|||
this.imagePath = `${this.OSSclientConfig.basePath}${path}`
|
||||
this.previewDialog = true
|
||||
this.$refs[path][0].$viewer.show()
|
||||
},
|
||||
initializeViewer() {
|
||||
Viewer.setDefaults({
|
||||
toolbar: { zoomIn: true, zoomOut: true, rotateLeft: true, rotateRight: true, flipHorizontal: true, flipVertical: true }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,7 +171,6 @@ import { getMedicalReviewDialog, sendMedicalReviewDialog } from '@/api/trials'
|
|||
import FeedbackForm from '@/views/trials/trials-panel/reading/medical-feedback/components/FeedbackForm'
|
||||
import mimAvatar from '@/assets/MIM.png'
|
||||
import irAvatar from '@/assets/IR.png'
|
||||
import Viewer from 'v-viewer'
|
||||
export default {
|
||||
name: 'ChatForm',
|
||||
components: {
|
||||
|
|
@ -207,7 +206,6 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initializeViewer()
|
||||
this.getMessageList()
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -261,11 +259,6 @@ export default {
|
|||
this.irFeedbackForm.title = this.$t('trials:medicalFeedback:title:feedback')
|
||||
|
||||
this.irFeedbackForm.visible = true
|
||||
},
|
||||
initializeViewer() {
|
||||
Viewer.setDefaults({
|
||||
toolbar: { zoomIn: true, zoomOut: true, rotateLeft: true, rotateRight: true, flipHorizontal: true, flipVertical: true }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@
|
|||
import { saveMedicalReviewInfo } from "@/api/trials";
|
||||
import ChatForm from "./ChatForm";
|
||||
import CloseQC from "./CloseQC";
|
||||
import Viewer from "v-viewer";
|
||||
export default {
|
||||
name: "AuditConclusions",
|
||||
components: {
|
||||
|
|
@ -253,7 +252,6 @@ export default {
|
|||
};
|
||||
},
|
||||
mounted() {
|
||||
this.initializeViewer();
|
||||
this.initForm();
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -435,21 +433,9 @@ export default {
|
|||
var idx = this.fileList.findIndex((i) => i.url === file.url);
|
||||
if (idx === -1) return;
|
||||
this.fileList.splice(idx, 1);
|
||||
},
|
||||
initializeViewer() {
|
||||
Viewer.setDefaults({
|
||||
toolbar: {
|
||||
zoomIn: true,
|
||||
zoomOut: true,
|
||||
rotateLeft: true,
|
||||
rotateRight: true,
|
||||
flipHorizontal: true,
|
||||
flipVertical: true,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.conclusions {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
<template>
|
||||
<!-- <el-tabs v-model="activeName" v-loading="loading" style="min-height:500px">-->
|
||||
<!-- <el-tab-pane-->
|
||||
<!-- v-for="criterion in criterions"-->
|
||||
<!-- :key="criterion.ReadingQuestionCriterionTrialId"-->
|
||||
<!-- :label="criterion.ReadingQuestionCriterionTrialName"-->
|
||||
<!-- :name="criterion.ReadingQuestionCriterionTrialId"-->
|
||||
<!-- >-->
|
||||
<div v-loading="loading" style="min-height:500px">
|
||||
<div style="min-height:500px">
|
||||
<h3 v-if="isReadingShowSubjectInfo" style="padding: 5px 0px;margin: 0;">
|
||||
<span v-if="subjectCode">{{ subjectCode }} </span>
|
||||
<span style="margin-left:5px;">{{ taskBlindName }}</span>
|
||||
</h3>
|
||||
<ECRF
|
||||
:trial-id="trialId"
|
||||
:subject-id="subjectId"
|
||||
:criterion-id="criterionId"
|
||||
:visit-task-id="visitTaskId"
|
||||
:iseCRFShowInDicomReading="iseCRFShowInDicomReading"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -43,6 +41,22 @@ export default {
|
|||
criterionId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
subjectCode: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
taskBlindName: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
isReadingShowSubjectInfo: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
iseCRFShowInDicomReading: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
|||
|
|
@ -77,13 +77,13 @@
|
|||
|
||||
<el-form-item v-if="readingTaskState < 2">
|
||||
<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') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleSave">
|
||||
{{ $t('common:button:save') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">
|
||||
<el-button type="primary" @click="handleSubmit" v-if="iseCRFShowInDicomReading">
|
||||
{{ $t('common:button:submit') }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
|
@ -116,7 +116,7 @@ import const_ from '@/const/sign-code'
|
|||
import FormItem from './FormItem'
|
||||
import SignForm from '@/views/trials/components/newSignForm'
|
||||
// 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 {
|
||||
name: 'ECRF',
|
||||
components: {
|
||||
|
|
@ -139,6 +139,10 @@ export default {
|
|||
visitTaskId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
iseCRFShowInDicomReading: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
@ -158,6 +162,9 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
this.getQuestions()
|
||||
DicomEvent.$on('refreshQuestionAnswer', _ => {
|
||||
this.getQuestions()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
async getQuestions() {
|
||||
|
|
@ -243,6 +250,7 @@ export default {
|
|||
try {
|
||||
const res = await saveVisitTaskQuestions(params)
|
||||
if (res.IsSuccess) {
|
||||
DicomEvent.$emit('getReportInfo', true)
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
}
|
||||
this.loading = false
|
||||
|
|
@ -285,6 +293,7 @@ export default {
|
|||
const res = await submitVisitTaskQuestionsInDto(params)
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
DicomEvent.$emit('getReportInfo', true)
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
this.isEdit = false
|
||||
this.$refs['signForm'].btnLoading = false
|
||||
|
|
|
|||
|
|
@ -120,11 +120,26 @@
|
|||
</el-checkbox-group>
|
||||
<!-- 数值 -->
|
||||
<!-- :precision="2" :step="0.1" :max="10" -->
|
||||
<el-input-number
|
||||
v-if="question.Type==='number'"
|
||||
v-model="questionForm[question.Id]"
|
||||
:disabled="readingTaskState >= 2"
|
||||
/>
|
||||
<template v-if="question.Type==='number'">
|
||||
<el-input-number
|
||||
v-if="question.ValueType === 0"
|
||||
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
|
||||
v-if="question.Type==='upload'"
|
||||
|
|
@ -222,7 +237,8 @@ export default {
|
|||
accept: '.png,.jpg,.jpeg',
|
||||
imgVisible: false,
|
||||
imageUrl: '',
|
||||
urls: []
|
||||
urls: [],
|
||||
digitPlaces: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -245,6 +261,7 @@ export default {
|
|||
})
|
||||
}
|
||||
}
|
||||
this.digitPlaces = parseInt(localStorage.getItem('digitPlaces'))
|
||||
},
|
||||
methods: {
|
||||
formItemChange(v, question) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
// find的自动计算值number
|
||||
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
|
||||
})
|
||||
// find的自动计算值number
|
||||
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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div v-loading="loading" class="img-container">
|
||||
<el-card class="box-card left">
|
||||
<div v-if="otherInfo && otherInfo.IsReadingShowSubjectInfo" class="title">
|
||||
<span>{{ $t('trials:auditRecord:table:subject') }}:{{ otherInfo.SubjectCode }} </span>
|
||||
<span>({{ otherInfo.TaskBlindName }})</span>
|
||||
<div class="img-container">
|
||||
<el-card v-loading="loading" class="box-card left">
|
||||
<div v-if="isReadingShowSubjectInfo" class="title">
|
||||
<h4>{{ subjectCode }} </h4>
|
||||
<h4>{{ taskBlindName }}</h4>
|
||||
</div>
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane :label="$t('trials:clinicaldara:title:currentTask')" name="first" class="left-content">
|
||||
|
|
@ -30,7 +30,14 @@
|
|||
class="img-box"
|
||||
@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>
|
||||
|
|
@ -53,9 +60,15 @@
|
|||
class="img-box"
|
||||
@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>
|
||||
</el-tab-pane>
|
||||
|
|
@ -63,7 +76,7 @@
|
|||
|
||||
</el-card>
|
||||
<!-- 预览图像 -->
|
||||
<el-card class="box-card right">
|
||||
<el-card v-loading="loading" class="box-card right">
|
||||
<div style="width:100%;height: 100%;">
|
||||
<Preview
|
||||
v-if="previewImage.imgList.length > 0"
|
||||
|
|
@ -93,6 +106,10 @@
|
|||
:subject-id="subjectId"
|
||||
:visit-task-id="visitTaskId"
|
||||
: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>
|
||||
</div>
|
||||
|
|
@ -127,9 +144,33 @@ export default {
|
|||
type: String,
|
||||
required: true
|
||||
},
|
||||
taskBlindName: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
readingCategory: {
|
||||
type: Number,
|
||||
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() {
|
||||
|
|
@ -156,7 +197,8 @@ export default {
|
|||
currentTaskId: '',
|
||||
otherInfo: null,
|
||||
isReadingShowPreviousResults: false,
|
||||
bp: []
|
||||
bp: [],
|
||||
openWindow: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -170,6 +212,11 @@ export default {
|
|||
|
||||
this.getNoneDicomList(this.isReadingShowPreviousResults)
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.openWindow) {
|
||||
this.openWindow.close()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取非Dicom检查信息
|
||||
getNoneDicomList() {
|
||||
|
|
@ -250,18 +297,21 @@ export default {
|
|||
})
|
||||
},
|
||||
handleImageRead(task) {
|
||||
if (this.openWindow) {
|
||||
this.openWindow.close()
|
||||
}
|
||||
this.currentTaskId = task.VisitTaskId
|
||||
var criterionType = this.$router.currentRoute.query.criterionType
|
||||
var readingTool = this.$router.currentRoute.query.readingTool
|
||||
var isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder
|
||||
var criterionType = this.criterionType
|
||||
var readingTool = this.readingTool
|
||||
var isReadingTaskViewInOrder = this.isReadingTaskViewInOrder
|
||||
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
|
||||
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({
|
||||
// path: `/readingPage?subjectId=${this.subjectId}&trialId=${this.trialId}&visitTaskId=${task.VisitTaskId}&TokenKey=${token}`
|
||||
// })
|
||||
const routeData = this.$router.resolve({ path })
|
||||
window.open(routeData.href, '_blank')
|
||||
this.openWindow = window.open(routeData.href, '_blank')
|
||||
},
|
||||
previewCD() {
|
||||
var token = getToken()
|
||||
|
|
@ -295,7 +345,7 @@ export default {
|
|||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
padding-bottom: 10px;
|
||||
display: flex;
|
||||
::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
|
|
@ -326,13 +376,19 @@ export default {
|
|||
flex-direction: column;
|
||||
}
|
||||
.title{
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
// height: 40px;
|
||||
// line-height: 40px;
|
||||
border: 1ppx solid;
|
||||
border: 1px solid #ebe7e7;
|
||||
padding-left: 10px;
|
||||
// padding-left: 10px;
|
||||
background-color: #4e4e4e;
|
||||
color: #ffffff;
|
||||
h4{
|
||||
padding: 5px 0px;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
background-color: #4c4c4c;
|
||||
}
|
||||
}
|
||||
.left-content{
|
||||
flex: 1;
|
||||
|
|
@ -359,13 +415,19 @@ export default {
|
|||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2px solid #f3f3f3;
|
||||
width: 180px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
cursor: pointer;
|
||||
// margin-bottom: 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){
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,40 @@
|
|||
<template>
|
||||
<div ref="container" v-loading="loading" class="none-dicom-reading-container">
|
||||
<!-- 访视阅片 -->
|
||||
<VisitReview
|
||||
v-if="isShow && readingCategory && readingCategory=== 1"
|
||||
:trial-id="trialId"
|
||||
:subject-id="subjectId"
|
||||
:subject-code="subjectCode"
|
||||
:visit-task-id="visitTaskId"
|
||||
:reading-category="readingCategory"
|
||||
:is-exists-clinical-data="isExistsClinicalData"
|
||||
/>
|
||||
<div v-if="isShow && readingCategory && readingCategory=== 1" class="reading-wrapper">
|
||||
<el-tabs v-model="activeName" :before-leave="beforeLeave">
|
||||
<!-- 阅片 -->
|
||||
<el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
|
||||
<VisitReview
|
||||
:trial-id="trialId"
|
||||
:subject-id="subjectId"
|
||||
: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
|
||||
v-else-if="isShow && readingCategory && readingCategory === 2"
|
||||
|
|
@ -83,6 +108,7 @@ import { getNextTask, readClinicalData } from '@/api/trials'
|
|||
import store from '@/store'
|
||||
import { changeURLStatic } from '@/utils/history.js'
|
||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||
import Report from './components/Report'
|
||||
import VisitReview from './components/VisitReview'
|
||||
import GlobalReview from '@/views/trials/trials-panel/reading/global-review'
|
||||
import AdReview from '@/views/trials/trials-panel/reading/ad-review'
|
||||
|
|
@ -93,6 +119,7 @@ export default {
|
|||
name: 'NoneDicomReading',
|
||||
components: {
|
||||
VisitReview,
|
||||
Report,
|
||||
AdReview,
|
||||
GlobalReview,
|
||||
OncologyReview,
|
||||
|
|
@ -113,12 +140,15 @@ export default {
|
|||
isExistsClinicalData: false,
|
||||
isNeedReadClinicalData: false,
|
||||
isReadClinicalData: false,
|
||||
iseCRFShowInDicomReading: false,
|
||||
criterionType: null,
|
||||
readingTool: null,
|
||||
isNewSubject: null,
|
||||
dialogVisible: false,
|
||||
dialogH: 0,
|
||||
isShow: false
|
||||
isShow: false,
|
||||
activeName:'',
|
||||
tabs: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -169,6 +199,10 @@ export default {
|
|||
// 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}`
|
||||
// }
|
||||
if (res.Result.ReadingCategory === 1) {
|
||||
this.activeName = 'read'
|
||||
this.tabs = [this.activeName]
|
||||
}
|
||||
this.subjectId = res.Result.SubjectId
|
||||
this.visitTaskId = res.Result.VisitTaskId
|
||||
this.subjectCode = res.Result.SubjectCode
|
||||
|
|
@ -176,7 +210,8 @@ export default {
|
|||
this.isExistsClinicalData = res.Result.IsExistsClinicalData
|
||||
this.isReadClinicalData = res.Result.IsReadClinicalData
|
||||
this.isNeedReadClinicalData = res.Result.IsNeedReadClinicalData
|
||||
|
||||
this.iseCRFShowInDicomReading = res.Result.IseCRFShowInDicomReading
|
||||
this.isReadingTaskViewInOrder = res.Result.IsReadingTaskViewInOrder
|
||||
this.isReadingShowSubjectInfo = res.Result.IsReadingShowSubjectInfo
|
||||
this.isReadingShowPreviousResults = res.Result.IsReadingShowPreviousResults
|
||||
this.digitPlaces = res.Result.DigitPlaces
|
||||
|
|
@ -201,7 +236,21 @@ export default {
|
|||
} catch (e) {
|
||||
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>
|
||||
|
|
@ -221,7 +270,38 @@ export default {
|
|||
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{
|
||||
margin-top: 50px !important;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
v-if="
|
||||
(isReadingTaskViewInOrder === 1 ||
|
||||
isReadingTaskViewInOrder === 2) &&
|
||||
TrialReadingCriterionId === item.TrialReadingCriterionId
|
||||
TrialReadingCriterionId === item.TrialReadingCriterionId
|
||||
"
|
||||
>
|
||||
<div slot="search-container">
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
icon="el-icon-search"
|
||||
@click="handleSearch"
|
||||
>
|
||||
{{ $t("common:button:search") }}
|
||||
{{ $t('common:button:search') }}
|
||||
</el-button>
|
||||
<!-- 重置 -->
|
||||
<el-button
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
icon="el-icon-refresh-left"
|
||||
@click="handleReset"
|
||||
>
|
||||
{{ $t("common:button:reset") }}
|
||||
{{ $t('common:button:reset') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
|
@ -75,10 +75,11 @@
|
|||
scope.row.UrgentColor === 1
|
||||
? 'danger'
|
||||
: scope.row.UrgentColor === 2
|
||||
? 'warning'
|
||||
: 'primary'
|
||||
? 'warning'
|
||||
: 'primary'
|
||||
"
|
||||
>{{ $fd("YesOrNo", scope.row.IsUrgent) }}</el-tag>
|
||||
>{{ $fd('YesOrNo', scope.row.IsUrgent) }}</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 受试者编号 -->
|
||||
|
|
@ -113,10 +114,11 @@
|
|||
scope.row.UrgentColor === 1
|
||||
? '#F56C6C'
|
||||
: scope.row.UrgentColor === 2
|
||||
? '#E6A23C'
|
||||
: '#409EFF',
|
||||
? '#E6A23C'
|
||||
: '#409EFF',
|
||||
}"
|
||||
>{{ scope.row.UrgentCount }}</span>
|
||||
>{{ scope.row.UrgentCount }}</span
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 建议完成时间 -->
|
||||
|
|
@ -130,7 +132,7 @@
|
|||
sortable="custom"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.SuggesteFinishedTime.split(":")[0] + ":00:00" }}
|
||||
{{ scope.row.SuggesteFinishedTime.split(':')[0] + ':00:00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
|
|
@ -146,8 +148,8 @@
|
|||
:title="
|
||||
scope.row.ExistReadingApply
|
||||
? $t(
|
||||
'trials:pendingReadingTasks:button:ExistReadingApply'
|
||||
)
|
||||
'trials:pendingReadingTasks:button:ExistReadingApply'
|
||||
)
|
||||
: $t('trials:pendingReadingTasks:button:review')
|
||||
"
|
||||
icon="el-icon-edit-outline"
|
||||
|
|
@ -156,9 +158,9 @@
|
|||
<!-- 上传 -->
|
||||
<el-button
|
||||
v-if="
|
||||
item.CriterionType === 0 &&
|
||||
item.ImageUploadEnum > 0 &&
|
||||
item.IsReadingTaskViewInOrder > 0
|
||||
item.ImageUploadEnum > 0 &&
|
||||
item.IsReadingTaskViewInOrder > 0 &&
|
||||
!scope.row.IsSubjectJudge
|
||||
"
|
||||
v-hasPermi="['role:ir']"
|
||||
circle
|
||||
|
|
@ -169,9 +171,9 @@
|
|||
<!-- 下载 -->
|
||||
<el-button
|
||||
v-if="
|
||||
item.CriterionType === 0 &&
|
||||
item.ImageDownloadEnum === 1 &&
|
||||
item.IsReadingTaskViewInOrder > 0
|
||||
item.ImageDownloadEnum > 0 &&
|
||||
item.IsReadingTaskViewInOrder > 0 &&
|
||||
!scope.row.IsSubjectJudge
|
||||
"
|
||||
v-hasPermi="['role:ir']"
|
||||
circle
|
||||
|
|
@ -194,7 +196,7 @@
|
|||
<div
|
||||
v-else-if="
|
||||
isReadingTaskViewInOrder === 0 &&
|
||||
TrialReadingCriterionId === item.TrialReadingCriterionId
|
||||
TrialReadingCriterionId === item.TrialReadingCriterionId
|
||||
"
|
||||
>
|
||||
<el-descriptions :column="2" border style="width: 800px">
|
||||
|
|
@ -248,48 +250,65 @@
|
|||
:disabled="
|
||||
randomReadInfo.UnReadTaskCount +
|
||||
randomReadInfo.UnReadJudgeTaskCount ===
|
||||
0
|
||||
0
|
||||
"
|
||||
@click="handleOutOfOrderReading"
|
||||
>
|
||||
{{ $t("trials:pendingReadingTasks:button:beginRandomReview") }}
|
||||
{{ $t('trials:pendingReadingTasks:button:beginRandomReview') }}
|
||||
</el-button>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<upload-image
|
||||
<!-- <upload-image
|
||||
v-if="uploadImageVisible"
|
||||
:visible.sync="uploadImageVisible"
|
||||
:subject-id="uploadSubjectId"
|
||||
:criterion="uploadTrialCriterion"
|
||||
:status="uploadStatus"
|
||||
@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>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getIRUnReadSubjectTaskList,
|
||||
verifyReadingRestTime
|
||||
} from '@/api/trials'
|
||||
import { getIRUnReadSubjectTaskList, verifyReadingRestTime } from '@/api/trials'
|
||||
import { getTrialCriterionList } from '@/api/trials/reading'
|
||||
import { clearSkipReadingCache } from '@/api/reading'
|
||||
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 { getToken } from '@/utils/auth'
|
||||
const searchDataDefault = () => {
|
||||
return {
|
||||
SubjectCode: '',
|
||||
PageIndex: 1,
|
||||
PageSize: 20
|
||||
PageSize: 20,
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'ReadingTaskList',
|
||||
components: { BaseContainer, Pagination, 'upload-image': uploadImage },
|
||||
components: {
|
||||
BaseContainer,
|
||||
Pagination,
|
||||
'upload-dicom-and-nonedicom': uploadDicomAndNonedicom,
|
||||
'download-dicom-and-nonedicom': downloadDicomAndNonedicom,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchData: searchDataDefault(),
|
||||
|
|
@ -308,10 +327,12 @@ export default {
|
|||
openWindow: null,
|
||||
|
||||
// 上传
|
||||
downloadImageVisible: false,
|
||||
uploadImageVisible: false,
|
||||
uploadSubjectId: null,
|
||||
uploadSubjectCode: null,
|
||||
uploadTrialCriterion: {},
|
||||
uploadStatus: 'upload'
|
||||
uploadStatus: 'upload',
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -319,7 +340,7 @@ export default {
|
|||
if (v) {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('message', this.receiveMsg)
|
||||
|
|
@ -335,10 +356,11 @@ export default {
|
|||
methods: {
|
||||
// 打开上传下载弹框
|
||||
openUploadImage(item, trialCriterion, status) {
|
||||
this.uploadSubjectCode = item.SubjectCode
|
||||
this.uploadSubjectId = item.SubjectId
|
||||
this.uploadTrialCriterion = trialCriterion
|
||||
this.uploadStatus = status
|
||||
this.uploadImageVisible = true
|
||||
this[`${status}ImageVisible`] = true
|
||||
},
|
||||
async getTrialCriterionList() {
|
||||
try {
|
||||
|
|
@ -360,8 +382,7 @@ export default {
|
|||
this.isRender = false
|
||||
const res = await getIRUnReadSubjectTaskList(this.searchData)
|
||||
if (res.IsSuccess) {
|
||||
this.isReadingTaskViewInOrder =
|
||||
res.OtherInfo.IsReadingTaskViewInOrder
|
||||
this.isReadingTaskViewInOrder = res.OtherInfo.IsReadingTaskViewInOrder
|
||||
this.readingTool = res.OtherInfo.ReadingTool
|
||||
this.criterionType = res.OtherInfo.CriterionType
|
||||
if (res.OtherInfo.IsReadingTaskViewInOrder) {
|
||||
|
|
@ -395,7 +416,10 @@ export default {
|
|||
await clearSkipReadingCache()
|
||||
await verifyReadingRestTime()
|
||||
this.loading = false
|
||||
window.localStorage.setItem('TrialReadingCriterionId', this.TrialReadingCriterionId)
|
||||
window.localStorage.setItem(
|
||||
'TrialReadingCriterionId',
|
||||
this.TrialReadingCriterionId
|
||||
)
|
||||
var token = getToken()
|
||||
var path = ''
|
||||
if (this.readingTool === 0) {
|
||||
|
|
@ -420,7 +444,10 @@ export default {
|
|||
await clearSkipReadingCache()
|
||||
await verifyReadingRestTime()
|
||||
this.loading = false
|
||||
window.localStorage.setItem('TrialReadingCriterionId', this.TrialReadingCriterionId)
|
||||
window.localStorage.setItem(
|
||||
'TrialReadingCriterionId',
|
||||
this.TrialReadingCriterionId
|
||||
)
|
||||
var token = getToken()
|
||||
var path = ''
|
||||
if (this.readingTool === 0) {
|
||||
|
|
@ -450,7 +477,7 @@ export default {
|
|||
this.searchData.SortField = column.prop
|
||||
this.searchData.PageIndex = 1
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@
|
|||
/>
|
||||
<!-- 退回 -->
|
||||
<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'])"
|
||||
icon="el-icon-back"
|
||||
circle
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@
|
|||
</el-button>
|
||||
<!-- 预览 -->
|
||||
<el-button
|
||||
:disabled="otherInfo.QuestionCount===0"
|
||||
:disabled="!otherInfo.IsHaveQuestion"
|
||||
type="primary"
|
||||
icon="el-icon-view"
|
||||
@click="preview.visible = true"
|
||||
|
|
@ -118,7 +118,7 @@
|
|||
</el-button>
|
||||
<el-button
|
||||
v-if="!otherInfo.IsConfirmMedicineQuestion && hasPermi(['trials:trials-panel:setting:medical-audit:confirm'])"
|
||||
:disabled="otherInfo.QuestionCount===0"
|
||||
:disabled="!otherInfo.IsHaveQuestion"
|
||||
type="danger"
|
||||
icon="el-icon-circle-check"
|
||||
@click="handleConfirm"
|
||||
|
|
@ -443,7 +443,7 @@ export default {
|
|||
this.list = res.Result.CurrentPageData
|
||||
this.total = res.Result.TotalCount
|
||||
this.isShow = true
|
||||
this.otherInfo.IsConfirmMedicineQuestion = false
|
||||
// this.otherInfo.IsConfirmMedicineQuestion = false
|
||||
this.otherInfo = res.OtherInfo
|
||||
}).catch(() => { this.loading = false })
|
||||
},
|
||||
|
|
@ -503,7 +503,7 @@ export default {
|
|||
|
||||
// 确认前签名
|
||||
handleConfirm() {
|
||||
if (this.otherInfo.QuestionCount === 0) {
|
||||
if (!this.otherInfo.IsHaveQuestion) {
|
||||
// '请先配置医学审核问题再进行确认!'
|
||||
this.$alert(this.$t('trials:medicalFeedbackCfg:message:msg1'))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@
|
|||
<el-button
|
||||
circle
|
||||
icon="el-icon-delete"
|
||||
:disabled="scope.row.IsJoin"
|
||||
:title="$t('trials:externalStaff:button:delete')"
|
||||
@click="deleteTrialExternalUser(scope.row)"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
type="primary"
|
||||
:disabled="OtherInfo.IsSign"
|
||||
@click="apply(item.ReadingQuestionTrialId, index)"
|
||||
>{{ $t("common:button:save") }}</el-button
|
||||
>{{ $t('common:button:save') }}</el-button
|
||||
>
|
||||
<el-button
|
||||
v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']"
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
type="primary"
|
||||
:disabled="OtherInfo.IsSign"
|
||||
@click="reset(item.ReadingQuestionTrialId, index)"
|
||||
>{{ $t("common:button:reset") }}</el-button
|
||||
>{{ $t('common:button:reset') }}</el-button
|
||||
>
|
||||
<!-- 产生裁判阅片的条件 -->
|
||||
<el-form-item
|
||||
|
|
@ -71,13 +71,16 @@
|
|||
:label="item.value"
|
||||
v-if="
|
||||
(JudgyInfo.ArbitrationRule === 1 &&
|
||||
QuestionList[index].Type === 'number' &&
|
||||
(QuestionList[index].Type === 'number' ||
|
||||
QuestionList[index].Type === 'calculation') &&
|
||||
item.value !== 2 &&
|
||||
item.value !== 3) ||
|
||||
(JudgyInfo.ArbitrationRule === 2 &&
|
||||
QuestionList[index].Type === 'number' &&
|
||||
(QuestionList[index].Type === 'number' ||
|
||||
QuestionList[index].Type === 'calculation') &&
|
||||
item.value === 1) ||
|
||||
(QuestionList[index].Type !== 'number' &&
|
||||
((QuestionList[index].Type === 'number' ||
|
||||
QuestionList[index].Type === 'calculation') &&
|
||||
item.value !== 4 &&
|
||||
item.value !== 5)
|
||||
"
|
||||
|
|
@ -98,7 +101,7 @@
|
|||
type="primary"
|
||||
:disabled="OtherInfo.IsSign"
|
||||
@click="addGroup(index, null)"
|
||||
>{{ $t("trials:adRules:button:addRule") }}</el-button
|
||||
>{{ $t('trials:adRules:button:addRule') }}</el-button
|
||||
>
|
||||
</div>
|
||||
<el-table
|
||||
|
|
@ -211,14 +214,14 @@
|
|||
</el-checkbox-group>
|
||||
<div style="margin-top: 20px">
|
||||
<!-- 当前选择答案分组: -->
|
||||
{{ $t("trials:adRules:title:selectAnswerGroup") }}
|
||||
{{ $t('trials:adRules:title:selectAnswerGroup') }}
|
||||
<el-tag
|
||||
v-if="
|
||||
QuestionList[index].grouping.length > 0 &&
|
||||
QuestionList[index].QuestionGenre !== 3
|
||||
"
|
||||
>{{
|
||||
QuestionList[index].grouping.toString().replaceAll(",", "|")
|
||||
QuestionList[index].grouping.toString().replaceAll(',', '|')
|
||||
}}</el-tag
|
||||
>
|
||||
<el-tag
|
||||
|
|
@ -235,7 +238,7 @@
|
|||
).label
|
||||
)
|
||||
.toString()
|
||||
.replaceAll(",", "|")
|
||||
.replaceAll(',', '|')
|
||||
}}</el-tag
|
||||
>
|
||||
<el-button
|
||||
|
|
@ -245,7 +248,7 @@
|
|||
@click="addGroup2(index)"
|
||||
>
|
||||
<!-- 添加分组 -->
|
||||
{{ $t("trials:adRules:title:addGroup") }}
|
||||
{{ $t('trials:adRules:title:addGroup') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -253,7 +256,7 @@
|
|||
v-if="QuestionList[index].QuestionGenre !== 3"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
{{ $t("trials:adRules:title:group") }}
|
||||
{{ $t('trials:adRules:title:group') }}
|
||||
<el-tag
|
||||
v-for="itemA of QuestionList[index].AnswerGroup2List"
|
||||
:key="itemA"
|
||||
|
|
@ -261,7 +264,7 @@
|
|||
style="margin-right: 10px"
|
||||
@close="
|
||||
() => {
|
||||
return tagClose2(index, indexA);
|
||||
return tagClose2(index, indexA)
|
||||
}
|
||||
"
|
||||
>{{ itemA }}</el-tag
|
||||
|
|
@ -272,7 +275,7 @@
|
|||
style="margin-top: 20px"
|
||||
>
|
||||
<!-- 分组: -->
|
||||
{{ $t("trials:adRules:title:group") }}
|
||||
{{ $t('trials:adRules:title:group') }}
|
||||
<el-tag
|
||||
v-for="itemA of QuestionList[index].AnswerGroup2List"
|
||||
:key="itemA"
|
||||
|
|
@ -280,17 +283,17 @@
|
|||
style="margin-right: 10px"
|
||||
@close="
|
||||
() => {
|
||||
return tagClose2(index, indexA);
|
||||
return tagClose2(index, indexA)
|
||||
}
|
||||
"
|
||||
>
|
||||
{{
|
||||
itemA
|
||||
.split("|")
|
||||
.split('|')
|
||||
.map((v) =>
|
||||
$fd(QuestionList[index].DictionaryCode, parseInt(v))
|
||||
)
|
||||
.join("|")
|
||||
.join('|')
|
||||
}}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
|
@ -340,11 +343,16 @@
|
|||
"
|
||||
prop="JudgeDifferenceValue"
|
||||
>
|
||||
<el-input
|
||||
v-model="QuestionList[index].JudgeDifferenceValue"
|
||||
clearable
|
||||
:disabled="OtherInfo.IsSign"
|
||||
></el-input>
|
||||
<div style="display: flex">
|
||||
<el-input
|
||||
v-model="QuestionList[index].JudgeDifferenceValue"
|
||||
clearable
|
||||
:disabled="OtherInfo.IsSign"
|
||||
></el-input>
|
||||
<span style="margin-left: 10px">{{
|
||||
$fd('ValueUnit', QuestionList[index].Unit)
|
||||
}}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
|
@ -457,12 +465,12 @@
|
|||
size="small"
|
||||
type="primary"
|
||||
@click="
|
||||
QuestionVisible = false;
|
||||
$set(QuestionList[selectIndex], 'groupingA', []);
|
||||
$set(QuestionList[selectIndex], 'groupingB', []);
|
||||
QuestionVisible = false
|
||||
$set(QuestionList[selectIndex], 'groupingA', [])
|
||||
$set(QuestionList[selectIndex], 'groupingB', [])
|
||||
"
|
||||
>
|
||||
{{ $t("common:button:cancel") }}
|
||||
{{ $t('common:button:cancel') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-hasPermi="['trials:trials-panel:setting:reading-unit:edit']"
|
||||
|
|
@ -471,7 +479,7 @@
|
|||
type="primary"
|
||||
@click="save"
|
||||
>
|
||||
{{ $t("common:button:save") }}
|
||||
{{ $t('common:button:save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
|
@ -482,13 +490,13 @@ import {
|
|||
getTrialConfirmCriterionList,
|
||||
getTrialCriterionJudgeQuestionList,
|
||||
setTrialCriterionJudgeQuestionAnswerGroup,
|
||||
} from "@/api/trials/reading";
|
||||
import { setTrialJudgyInfo, getTrialJudgyInfo } from "@/api/trials/setting";
|
||||
} from '@/api/trials/reading'
|
||||
import { setTrialJudgyInfo, getTrialJudgyInfo } from '@/api/trials/setting'
|
||||
export default {
|
||||
props: {
|
||||
trialReadingCriterionId: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
|
@ -512,23 +520,23 @@ export default {
|
|||
{
|
||||
required: true,
|
||||
message: this.$t(
|
||||
"trials:trials-list:setitng:JudgeDifferenceTypeRequired"
|
||||
'trials:trials-list:setitng:JudgeDifferenceTypeRequired'
|
||||
),
|
||||
trigger: "blur",
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
JudgeDifferenceValue: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t(
|
||||
"trials:trials-list:setitng:JudgeDifferenceValueRequired"
|
||||
'trials:trials-list:setitng:JudgeDifferenceValueRequired'
|
||||
),
|
||||
trigger: "blur",
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
pattern: /^[0-9]+(.[0-9]{2})?$/,
|
||||
message: this.$t("trials:trials-list:setitng:JudgeDifferenceValue"),
|
||||
trigger: "blur",
|
||||
message: this.$t('trials:trials-list:setitng:JudgeDifferenceValue'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
|
|
@ -536,115 +544,115 @@ export default {
|
|||
callback(
|
||||
new Error(
|
||||
this.$t(
|
||||
"trials:trials-list:setitng:JudgeDifferenceValueMin"
|
||||
'trials:trials-list:setitng:JudgeDifferenceValueMin'
|
||||
)
|
||||
)
|
||||
);
|
||||
)
|
||||
} else {
|
||||
callback();
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
TrialReadingCriterionId(v) {
|
||||
if (v === null) return;
|
||||
this.loading = true;
|
||||
if (v === null) return
|
||||
this.loading = true
|
||||
getTrialCriterionJudgeQuestionList({
|
||||
TrialId: this.$route.query.trialId,
|
||||
// ReadingQuestionCriterionTrialId: v,
|
||||
TrialReadingCriterionId: this.trialReadingCriterionId,
|
||||
})
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
this.QuestionList = res.Result;
|
||||
this.OtherInfo = res.OtherInfo;
|
||||
this.loading = false
|
||||
this.QuestionList = res.Result
|
||||
this.OtherInfo = res.OtherInfo
|
||||
this.activeNames = this.QuestionList.map(
|
||||
(v) => v.ReadingQuestionTrialId
|
||||
);
|
||||
)
|
||||
this.QuestionList.forEach((v) => {
|
||||
this.$set(v, "grouping", []);
|
||||
this.$set(v, "groupingA", []);
|
||||
this.$set(v, "groupingB", []);
|
||||
this.$set(v, 'grouping', [])
|
||||
this.$set(v, 'groupingA', [])
|
||||
this.$set(v, 'groupingB', [])
|
||||
this.$set(
|
||||
v,
|
||||
"AnswerGroupList",
|
||||
'AnswerGroupList',
|
||||
Object.assign([], v.AnswerCombination)
|
||||
);
|
||||
this.$set(v, "AnswerGroup2List", Object.assign([], v.AnswerGroup));
|
||||
});
|
||||
)
|
||||
this.$set(v, 'AnswerGroup2List', Object.assign([], v.AnswerGroup))
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
this.btnLoading = false;
|
||||
this.loading = false;
|
||||
});
|
||||
this.btnLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getList();
|
||||
this.getTrialJudgyInfo();
|
||||
this.getList()
|
||||
this.getTrialJudgyInfo()
|
||||
},
|
||||
methods: {
|
||||
// 修改仲裁规则
|
||||
changeArbitrationRule(value) {
|
||||
if (value !== 1) {
|
||||
this.QuestionList.forEach((item) => {
|
||||
item.JudgeDifferenceValue = 0;
|
||||
item.JudgeDifferenceType = 0;
|
||||
});
|
||||
item.JudgeDifferenceValue = 0
|
||||
item.JudgeDifferenceType = 0
|
||||
})
|
||||
}
|
||||
},
|
||||
JudgeTypeChange(value, index) {
|
||||
this.$nextTick(() => {
|
||||
if (value === 4 || value === 5) {
|
||||
if (this.$refs["JudgeDifferenceValue" + value + index][0]) {
|
||||
this.$refs["JudgeDifferenceValue" + value + index][0].resetFields();
|
||||
if (this.$refs['JudgeDifferenceValue' + value + index][0]) {
|
||||
this.$refs['JudgeDifferenceValue' + value + index][0].resetFields()
|
||||
// this.QuestionList[index].JudgeDifferenceValue = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
saveAllSync() {
|
||||
return new Promise((resolve, reject) => {
|
||||
var arr = [];
|
||||
var arr = []
|
||||
this.QuestionList.forEach((v, i) => {
|
||||
arr.push(this.applySync(v.ReadingQuestionTrialId, i));
|
||||
});
|
||||
arr.push(this.applySync(v.ReadingQuestionTrialId, i))
|
||||
})
|
||||
Promise.all(arr)
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
resolve(true);
|
||||
console.log(res)
|
||||
resolve(true)
|
||||
})
|
||||
.catch((res) => {
|
||||
console.log("进入catch");
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
console.log('进入catch')
|
||||
resolve(false)
|
||||
})
|
||||
})
|
||||
},
|
||||
applySync(ReadingQuestionTrialId, index) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
console.log(this.QuestionList[index].JudgeType);
|
||||
console.log(this.QuestionList[index].JudgeType)
|
||||
if (this.QuestionList[index].JudgeType === 0) {
|
||||
reject(false);
|
||||
return;
|
||||
reject(false)
|
||||
return
|
||||
}
|
||||
if (
|
||||
this.QuestionList[index].JudgeType === 2 &&
|
||||
this.QuestionList[index].AnswerGroup2List.length === 0
|
||||
) {
|
||||
reject(false);
|
||||
return;
|
||||
reject(false)
|
||||
return
|
||||
}
|
||||
if (
|
||||
this.QuestionList[index].JudgeType === 3 &&
|
||||
this.QuestionList[index].AnswerGroupList.length === 0
|
||||
) {
|
||||
reject(false);
|
||||
return;
|
||||
reject(false)
|
||||
return
|
||||
}
|
||||
if (
|
||||
this.QuestionList[index].JudgeType === 4 ||
|
||||
|
|
@ -652,17 +660,17 @@ export default {
|
|||
) {
|
||||
try {
|
||||
let validate = await this.$refs[
|
||||
"JudgeDifferenceValue" +
|
||||
'JudgeDifferenceValue' +
|
||||
this.QuestionList[index].JudgeType +
|
||||
index
|
||||
][0].validate();
|
||||
if (!validate) return reject(false);
|
||||
][0].validate()
|
||||
if (!validate) return reject(false)
|
||||
} catch (err) {
|
||||
return reject(false);
|
||||
return reject(false)
|
||||
}
|
||||
}
|
||||
this.btnLoading = true;
|
||||
this.loading = true;
|
||||
this.btnLoading = true
|
||||
this.loading = true
|
||||
setTrialCriterionJudgeQuestionAnswerGroup({
|
||||
ReadingQuestionTrialId: ReadingQuestionTrialId,
|
||||
AnswerGroup: this.QuestionList[index].AnswerGroup2List,
|
||||
|
|
@ -676,126 +684,126 @@ export default {
|
|||
),
|
||||
})
|
||||
.then((res) => {
|
||||
resolve();
|
||||
this.btnLoading = false;
|
||||
this.loading = false;
|
||||
resolve()
|
||||
this.btnLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
.catch(() => {
|
||||
reject(false);
|
||||
this.btnLoading = false;
|
||||
this.loading = false;
|
||||
});
|
||||
});
|
||||
reject(false)
|
||||
this.btnLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
setTrialJudgyInfo() {
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
setTrialJudgyInfo({
|
||||
TrialId: this.$route.query.trialId,
|
||||
ArbitrationRule: this.JudgyInfo.ArbitrationRule,
|
||||
TrialReadingCriterionId: this.trialReadingCriterionId,
|
||||
})
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
this.$message.success(this.$t("common:message:savedSuccessfully")); // '保存成功'
|
||||
this.loading = false
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully')) // '保存成功'
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
getTrialJudgyInfo() {
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
getTrialJudgyInfo({
|
||||
TrialId: this.$route.query.trialId,
|
||||
TrialReadingCriterionId: this.trialReadingCriterionId,
|
||||
})
|
||||
.then((res) => {
|
||||
this.JudgyInfo = res.Result;
|
||||
this.loading = false;
|
||||
this.JudgyInfo = res.Result
|
||||
this.loading = false
|
||||
})
|
||||
.catch((v) => {
|
||||
this.loading = false;
|
||||
});
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
tagClose2(index, indexA) {
|
||||
// '删除该规则组?'
|
||||
this.$confirm(this.$t("trials:adRules:message:msg1")).then(() => {
|
||||
this.QuestionList[index].AnswerGroup2List.splice(indexA, 1);
|
||||
});
|
||||
this.$confirm(this.$t('trials:adRules:message:msg1')).then(() => {
|
||||
this.QuestionList[index].AnswerGroup2List.splice(indexA, 1)
|
||||
})
|
||||
},
|
||||
tagClose(index, indexA) {
|
||||
// '删除该规则组?'
|
||||
this.$confirm(this.$t("trials:adRules:message:msg1")).then(() => {
|
||||
this.QuestionList[index].AnswerGroupList.splice(indexA, 1);
|
||||
});
|
||||
this.$confirm(this.$t('trials:adRules:message:msg1')).then(() => {
|
||||
this.QuestionList[index].AnswerGroupList.splice(indexA, 1)
|
||||
})
|
||||
},
|
||||
save() {
|
||||
var index = this.selectIndex;
|
||||
var indexA = this.indexA;
|
||||
var index = this.selectIndex
|
||||
var indexA = this.indexA
|
||||
if (this.QuestionList[index].groupingA.length === 0) {
|
||||
this.$alert(this.$t("trials:adRules:message:msg2")); // '请先选择答案A'
|
||||
return;
|
||||
this.$alert(this.$t('trials:adRules:message:msg2')) // '请先选择答案A'
|
||||
return
|
||||
}
|
||||
if (this.QuestionList[index].groupingB.length === 0) {
|
||||
this.$alert(this.$t("trials:adRules:message:msg3")); // '请先选择答案B'
|
||||
return;
|
||||
this.$alert(this.$t('trials:adRules:message:msg3')) // '请先选择答案B'
|
||||
return
|
||||
}
|
||||
if (this.type === "add") {
|
||||
if (this.type === 'add') {
|
||||
this.QuestionList[index].AnswerGroupList.push({
|
||||
AnswerGroupA: this.QuestionList[index].groupingA,
|
||||
AnswerGroupB: this.QuestionList[index].groupingB,
|
||||
});
|
||||
})
|
||||
} else {
|
||||
this.$set(
|
||||
this.QuestionList[index].AnswerGroupList[indexA],
|
||||
"AnswerGroupA",
|
||||
'AnswerGroupA',
|
||||
this.QuestionList[index].groupingA
|
||||
);
|
||||
)
|
||||
this.$set(
|
||||
this.QuestionList[index].AnswerGroupList[indexA],
|
||||
"AnswerGroupB",
|
||||
'AnswerGroupB',
|
||||
this.QuestionList[index].groupingB
|
||||
);
|
||||
)
|
||||
}
|
||||
this.$set(this.QuestionList[index], "groupingA", []);
|
||||
this.$set(this.QuestionList[index], "groupingB", []);
|
||||
this.$message.success(this.$t("trials:adRules:message:msg4")); // '成功新增答案规则'
|
||||
this.QuestionVisible = false;
|
||||
this.$set(this.QuestionList[index], 'groupingA', [])
|
||||
this.$set(this.QuestionList[index], 'groupingB', [])
|
||||
this.$message.success(this.$t('trials:adRules:message:msg4')) // '成功新增答案规则'
|
||||
this.QuestionVisible = false
|
||||
},
|
||||
addGroup2(index) {
|
||||
if (this.QuestionList[index].grouping.length === 0) {
|
||||
this.$alert(this.$t("trials:adRules:message:msg5")); // '请先选择答案,再添加分组'
|
||||
return;
|
||||
this.$alert(this.$t('trials:adRules:message:msg5')) // '请先选择答案,再添加分组'
|
||||
return
|
||||
}
|
||||
var grouping = this.QuestionList[index].grouping
|
||||
.toString()
|
||||
.replaceAll(",", "|");
|
||||
this.QuestionList[index].AnswerGroup2List.push(`|${grouping}|`);
|
||||
this.$set(this.QuestionList[index], "grouping", []);
|
||||
.replaceAll(',', '|')
|
||||
this.QuestionList[index].AnswerGroup2List.push(`|${grouping}|`)
|
||||
this.$set(this.QuestionList[index], 'grouping', [])
|
||||
},
|
||||
addGroup(index, indexA) {
|
||||
this.selectIndex = index;
|
||||
this.type = "add";
|
||||
this.selectIndex = index
|
||||
this.type = 'add'
|
||||
if (indexA !== null) {
|
||||
this.indexA = indexA;
|
||||
this.type = "edit";
|
||||
this.indexA = indexA
|
||||
this.type = 'edit'
|
||||
this.$set(
|
||||
this.QuestionList[index],
|
||||
"groupingA",
|
||||
'groupingA',
|
||||
this.QuestionList[index].AnswerGroupList[indexA].AnswerGroupA
|
||||
);
|
||||
)
|
||||
this.$set(
|
||||
this.QuestionList[index],
|
||||
"groupingB",
|
||||
'groupingB',
|
||||
this.QuestionList[index].AnswerGroupList[indexA].AnswerGroupB
|
||||
);
|
||||
)
|
||||
}
|
||||
this.QuestionVisible = true;
|
||||
this.QuestionVisible = true
|
||||
},
|
||||
reset(ReadingQuestionTrialId, index) {
|
||||
// '确定重置当前设置的裁判任务生成规则吗?'
|
||||
this.$confirm(this.$t("trials:adRules:message:msg6")).then(() => {
|
||||
this.btnLoading = true;
|
||||
this.loading = true;
|
||||
this.$confirm(this.$t('trials:adRules:message:msg6')).then(() => {
|
||||
this.btnLoading = true
|
||||
this.loading = true
|
||||
setTrialCriterionJudgeQuestionAnswerGroup({
|
||||
ReadingQuestionTrialId: ReadingQuestionTrialId,
|
||||
AnswerGroup: [],
|
||||
|
|
@ -805,39 +813,39 @@ export default {
|
|||
JudgeDifferenceType: 0,
|
||||
})
|
||||
.then((res) => {
|
||||
this.$set(this.QuestionList[index], "AnswerGroup2List", []);
|
||||
this.$set(this.QuestionList[index], "AnswerGroupList", []);
|
||||
this.$set(this.QuestionList[index], "JudgeType", 0);
|
||||
this.$set(this.QuestionList[index], "JudgeDifferenceValue", 0);
|
||||
this.$set(this.QuestionList[index], "JudgeDifferenceType", 0);
|
||||
this.$message.success(this.$t("trials:adRules:message:msg7")); // '重置成功'
|
||||
this.btnLoading = false;
|
||||
this.loading = false;
|
||||
this.$set(this.QuestionList[index], 'AnswerGroup2List', [])
|
||||
this.$set(this.QuestionList[index], 'AnswerGroupList', [])
|
||||
this.$set(this.QuestionList[index], 'JudgeType', 0)
|
||||
this.$set(this.QuestionList[index], 'JudgeDifferenceValue', 0)
|
||||
this.$set(this.QuestionList[index], 'JudgeDifferenceType', 0)
|
||||
this.$message.success(this.$t('trials:adRules:message:msg7')) // '重置成功'
|
||||
this.btnLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
.catch(() => {
|
||||
this.btnLoading = false;
|
||||
this.loading = false;
|
||||
});
|
||||
});
|
||||
this.btnLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
async apply(ReadingQuestionTrialId, index) {
|
||||
if (this.QuestionList[index].JudgeType === 0) {
|
||||
this.$alert(this.$t("trials:adRules:message:msg8")); // '请先配置规则才能应用'
|
||||
return;
|
||||
this.$alert(this.$t('trials:adRules:message:msg8')) // '请先配置规则才能应用'
|
||||
return
|
||||
}
|
||||
if (
|
||||
this.QuestionList[index].JudgeType === 2 &&
|
||||
this.QuestionList[index].AnswerGroup2List.length === 0
|
||||
) {
|
||||
this.$alert(this.$t("trials:adRules:message:msg8")); // '请先配置规则才能应用'
|
||||
return;
|
||||
this.$alert(this.$t('trials:adRules:message:msg8')) // '请先配置规则才能应用'
|
||||
return
|
||||
}
|
||||
if (
|
||||
this.QuestionList[index].JudgeType === 3 &&
|
||||
this.QuestionList[index].AnswerGroupList.length === 0
|
||||
) {
|
||||
this.$alert(this.$t("trials:adRules:message:msg8"));
|
||||
return;
|
||||
this.$alert(this.$t('trials:adRules:message:msg8'))
|
||||
return
|
||||
}
|
||||
if (
|
||||
this.QuestionList[index].JudgeType === 4 ||
|
||||
|
|
@ -845,15 +853,15 @@ export default {
|
|||
) {
|
||||
try {
|
||||
let validate = await this.$refs[
|
||||
"JudgeDifferenceValue" + this.QuestionList[index].JudgeType + index
|
||||
][0].validate();
|
||||
if (!validate) return;
|
||||
'JudgeDifferenceValue' + this.QuestionList[index].JudgeType + index
|
||||
][0].validate()
|
||||
if (!validate) return
|
||||
} catch (err) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
}
|
||||
this.btnLoading = true;
|
||||
this.loading = true;
|
||||
this.btnLoading = true
|
||||
this.loading = true
|
||||
setTrialCriterionJudgeQuestionAnswerGroup({
|
||||
ReadingQuestionTrialId: ReadingQuestionTrialId,
|
||||
AnswerGroup: this.QuestionList[index].AnswerGroup2List,
|
||||
|
|
@ -867,49 +875,49 @@ export default {
|
|||
),
|
||||
})
|
||||
.then((res) => {
|
||||
this.$message.success(this.$t("trials:adRules:message:msg9")); // '应用成功'
|
||||
this.btnLoading = false;
|
||||
this.loading = false;
|
||||
this.$message.success(this.$t('trials:adRules:message:msg9')) // '应用成功'
|
||||
this.btnLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
.catch(() => {
|
||||
this.btnLoading = false;
|
||||
this.loading = false;
|
||||
});
|
||||
this.btnLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
tabClick(v) {
|
||||
this.ReadingQuestionCriterionTrialId =
|
||||
this.CriterionList[this.index].ReadingQuestionCriterionTrialId;
|
||||
this.CriterionList[this.index].ReadingQuestionCriterionTrialId
|
||||
},
|
||||
getList() {
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
getTrialCriterionJudgeQuestionList({
|
||||
TrialId: this.$route.query.trialId,
|
||||
TrialReadingCriterionId: this.trialReadingCriterionId,
|
||||
})
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
this.QuestionList = res.Result;
|
||||
this.OtherInfo = res.OtherInfo;
|
||||
this.loading = false
|
||||
this.QuestionList = res.Result
|
||||
this.OtherInfo = res.OtherInfo
|
||||
this.activeNames = this.QuestionList.map(
|
||||
(v) => v.ReadingQuestionTrialId
|
||||
);
|
||||
)
|
||||
this.QuestionList.forEach((v) => {
|
||||
this.$set(v, "grouping", []);
|
||||
this.$set(v, "groupingA", []);
|
||||
this.$set(v, "groupingB", []);
|
||||
this.$set(v, 'grouping', [])
|
||||
this.$set(v, 'groupingA', [])
|
||||
this.$set(v, 'groupingB', [])
|
||||
this.$set(
|
||||
v,
|
||||
"AnswerGroupList",
|
||||
'AnswerGroupList',
|
||||
Object.assign([], v.AnswerCombination)
|
||||
);
|
||||
this.$set(v, "AnswerGroup2List", Object.assign([], v.AnswerGroup));
|
||||
});
|
||||
)
|
||||
this.$set(v, 'AnswerGroup2List', Object.assign([], v.AnswerGroup))
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
this.btnLoading = false;
|
||||
this.loading = false;
|
||||
});
|
||||
this.btnLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
<!-- '表单问题' -->
|
||||
<el-form-item :label="$t('trials:readingUnit:readingCriterion:title:formQs')">
|
||||
<QuestionsList
|
||||
:ref="`questionList${trialReadingCriterionId}`"
|
||||
v-if="form.FormType===1"
|
||||
:trial-reading-criterion-id="trialReadingCriterionId"
|
||||
:list="readingInfo.TrialQuestionList"
|
||||
|
|
@ -170,6 +171,9 @@ export default {
|
|||
})
|
||||
})
|
||||
},
|
||||
getQuestionLength() {
|
||||
return this.$refs['questionList' + this.trialReadingCriterionId].tblList.length
|
||||
},
|
||||
reloadArbitrationRules() {
|
||||
this.$emit('reloadArbitrationRules')
|
||||
},
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
:label="item.value"
|
||||
v-for="item in $d.YesOrNoModality"
|
||||
:key="item.id"
|
||||
>
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
|
|
@ -103,7 +103,13 @@
|
|||
@click.stop="handleCheckAllChange"
|
||||
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-form-item>
|
||||
|
|
@ -131,6 +137,7 @@
|
|||
<el-form-item
|
||||
:label="$t('trials:processCfg:form:IsAdditionalAssessment')"
|
||||
prop="IsAdditionalAssessment"
|
||||
v-if="CriterionType === 1"
|
||||
>
|
||||
<el-radio-group
|
||||
v-model="form.IsAdditionalAssessment"
|
||||
|
|
@ -182,7 +189,7 @@
|
|||
"
|
||||
@change="
|
||||
() => {
|
||||
form.IsArbitrationReading = false;
|
||||
form.IsArbitrationReading = false
|
||||
}
|
||||
"
|
||||
>
|
||||
|
|
@ -232,8 +239,8 @@
|
|||
@change="
|
||||
(v) => {
|
||||
if (!v) {
|
||||
form.IsGlobalReading = v;
|
||||
form.IsOncologyReading = v;
|
||||
form.IsGlobalReading = v
|
||||
form.IsOncologyReading = v
|
||||
}
|
||||
}
|
||||
"
|
||||
|
|
@ -306,15 +313,15 @@
|
|||
"
|
||||
@change="
|
||||
(v) => {
|
||||
form.ImageDownloadEnum = 0;
|
||||
form.ImageUploadEnum = 0;
|
||||
form.ImageDownloadEnum = 0
|
||||
form.ImageUploadEnum = 0
|
||||
if (v) {
|
||||
form.IsReadingShowSubjectInfo = true;
|
||||
form.IsReadingShowPreviousResults = true;
|
||||
form.ReadingTaskViewEnum = 0;
|
||||
form.IseCRFShowInDicomReading = false;
|
||||
form.IsReadingShowSubjectInfo = true
|
||||
form.IsReadingShowPreviousResults = true
|
||||
form.ReadingTaskViewEnum = 0
|
||||
form.IseCRFShowInDicomReading = false
|
||||
} else {
|
||||
form.ReadingTaskViewEnum = 2;
|
||||
form.ReadingTaskViewEnum = 2
|
||||
}
|
||||
}
|
||||
"
|
||||
|
|
@ -351,11 +358,10 @@
|
|||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!--支持影像下载-->
|
||||
<!--支持影像下载v-if="CriterionType === 0"-->
|
||||
<el-form-item
|
||||
:label="$t('trials:processCfg:form:ImageDownloadEnum')"
|
||||
prop="ImageDownloadEnum"
|
||||
v-if="CriterionType === 0"
|
||||
>
|
||||
<el-radio-group
|
||||
v-model="form.ImageDownloadEnum"
|
||||
|
|
@ -379,7 +385,6 @@
|
|||
<el-form-item
|
||||
:label="$t('trials:processCfg:form:ImageUploadEnum')"
|
||||
prop="ImageUploadEnum"
|
||||
v-if="CriterionType === 0"
|
||||
>
|
||||
<el-radio-group
|
||||
v-model="form.ImageUploadEnum"
|
||||
|
|
@ -442,7 +447,7 @@
|
|||
@change="
|
||||
(v) => {
|
||||
if (!v) {
|
||||
form.IseCRFShowInDicomReading = true;
|
||||
form.IseCRFShowInDicomReading = true
|
||||
}
|
||||
}
|
||||
"
|
||||
|
|
@ -541,7 +546,7 @@
|
|||
"
|
||||
@change="
|
||||
(v) => {
|
||||
$set(form, 'AdditionalAssessmentType' + item.Id, v);
|
||||
$set(form, 'AdditionalAssessmentType' + item.Id, v)
|
||||
}
|
||||
"
|
||||
>
|
||||
|
|
@ -563,21 +568,21 @@
|
|||
>
|
||||
<!-- 保存 -->
|
||||
<el-button type="primary" @click="handleSave(true)">
|
||||
{{ $t("common:button:save") }}
|
||||
{{ $t('common:button:save') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getCriterionReadingInfo, setCriterionReadingInfo } from "@/api/trials";
|
||||
import { getCriterionReadingInfo, setCriterionReadingInfo } from '@/api/trials'
|
||||
export default {
|
||||
name: "ReadingRules",
|
||||
name: 'ReadingRules',
|
||||
props: {
|
||||
trialReadingCriterionId: {
|
||||
type: String,
|
||||
default() {
|
||||
return "";
|
||||
return ''
|
||||
},
|
||||
},
|
||||
CriterionType: {
|
||||
|
|
@ -589,7 +594,7 @@ export default {
|
|||
return {
|
||||
additionalAssessmentOptionList: [],
|
||||
form: {
|
||||
TrialId: "",
|
||||
TrialId: '',
|
||||
ImagePlatform: null,
|
||||
ReadingTool: 0,
|
||||
ReadingTaskViewEnum: null,
|
||||
|
|
@ -624,151 +629,151 @@ export default {
|
|||
IsAutoCreate: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsAdditionalAssessment: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
ImagePlatform: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
ReadingTool: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
ImageDownloadEnum: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
ImageUploadEnum: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsImageFilter: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
ReadingTaskViewEnum: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsImageLabeled: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsReadingShowSubjectInfo: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsReadingShowPreviousResults: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
ReadingType: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsReadingTaskViewInOrder: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsGlobalReading: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsArbitrationReading: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsOncologyReading: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
DigitPlaces: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IseCRFShowInDicomReading: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsReadingPeriod: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
CriterionModalitys: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
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 {
|
||||
callback();
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: ["blur", "change"],
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
// IsReadingTaskViewInOrder: [
|
||||
|
|
@ -785,15 +790,15 @@ export default {
|
|||
modalityList: [],
|
||||
CriterionModalitys: [],
|
||||
modalityIsCheck: false, // 是否允许影像筛选
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initPage();
|
||||
this.initPage()
|
||||
},
|
||||
watch: {
|
||||
CriterionModalitys: {
|
||||
handler() {
|
||||
this.form.CriterionModalitys = this.CriterionModalitys.join("|");
|
||||
this.form.CriterionModalitys = this.CriterionModalitys.join('|')
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
|
|
@ -802,19 +807,19 @@ export default {
|
|||
// 检查类型筛选值变更
|
||||
IsImageFilterChange(data) {
|
||||
if (data) {
|
||||
this.CriterionModalitys = this.modalityList;
|
||||
this.CriterionModalitys = this.modalityList
|
||||
} else {
|
||||
this.CriterionModalitys = [];
|
||||
this.CriterionModalitys = []
|
||||
}
|
||||
},
|
||||
// 影像模态全选
|
||||
handleCheckAllChange() {
|
||||
this.CriterionModalitys =
|
||||
this.CriterionModalitys.length <= 0 ? this.modalityList : [];
|
||||
this.CriterionModalitys.length <= 0 ? this.modalityList : []
|
||||
},
|
||||
initPage() {
|
||||
this.loading = true;
|
||||
const trialId = this.$route.query.trialId;
|
||||
this.loading = true
|
||||
const trialId = this.$route.query.trialId
|
||||
// getTrialCriterionAdditionalAssessmentOptionList(this.trialReadingCriterionId).then(res => {
|
||||
// this.additionalAssessmentOptionList = res.Result
|
||||
// if (this.additionalAssessmentOptionList.length > 0) {
|
||||
|
|
@ -827,46 +832,46 @@ export default {
|
|||
TrialReadingCriterionId: this.trialReadingCriterionId,
|
||||
})
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
this.modalityList = res.Result.TrialModalitys.split("|").filter(
|
||||
this.loading = false
|
||||
this.modalityList = res.Result.TrialModalitys.split('|').filter(
|
||||
(item) => item && item.trim()
|
||||
);
|
||||
)
|
||||
for (const k in this.form) {
|
||||
if (res.Result.hasOwnProperty(k)) {
|
||||
this.form[k] = res.Result[k];
|
||||
this.form[k] = res.Result[k]
|
||||
}
|
||||
}
|
||||
this.CriterionModalitys = this.form.CriterionModalitys
|
||||
? this.form.CriterionModalitys.split("|")
|
||||
: [];
|
||||
? this.form.CriterionModalitys.split('|')
|
||||
: []
|
||||
this.form.TrialCriterionAdditionalAssessmentTypeList.forEach((v) => {
|
||||
this.$set(v, "IsSelected", v.IsSelected || false);
|
||||
this.$set(v, 'IsSelected', v.IsSelected || false)
|
||||
this.$set(
|
||||
this.form,
|
||||
"AdditionalAssessmentType" + v.Id,
|
||||
'AdditionalAssessmentType' + v.Id,
|
||||
v.IsSelected
|
||||
);
|
||||
});
|
||||
this.isReadingTaskViewInOrder = res.Result.IsReadingTaskViewInOrder;
|
||||
this.isConfirm = res.Result.IsSign;
|
||||
this.IsMustGlobalReading = res.Result.IsMustGlobalReading;
|
||||
this.$emit("setConfirm", res.Result.IsSign);
|
||||
this.$emit("setArbitrationReading", res.Result.IsArbitrationReading);
|
||||
)
|
||||
})
|
||||
this.isReadingTaskViewInOrder = res.Result.IsReadingTaskViewInOrder
|
||||
this.isConfirm = res.Result.IsSign
|
||||
this.IsMustGlobalReading = res.Result.IsMustGlobalReading
|
||||
this.$emit('setConfirm', res.Result.IsSign)
|
||||
this.$emit('setArbitrationReading', res.Result.IsArbitrationReading)
|
||||
this.$emit(
|
||||
"setAdditionalAssessment",
|
||||
'setAdditionalAssessment',
|
||||
this.form.IsAdditionalAssessment
|
||||
);
|
||||
this.$emit("setIsClinicalReading", res.Result.IsClinicalReading);
|
||||
this.$emit("setGlobalReading", res.Result.IsGlobalReading);
|
||||
this.$emit("setOncologyReading", res.Result.IsOncologyReading);
|
||||
this.$emit("setDigitPlaces", res.Result.DigitPlaces);
|
||||
)
|
||||
this.$emit('setIsClinicalReading', res.Result.IsClinicalReading)
|
||||
this.$emit('setGlobalReading', res.Result.IsGlobalReading)
|
||||
this.$emit('setOncologyReading', res.Result.IsOncologyReading)
|
||||
this.$emit('setDigitPlaces', res.Result.DigitPlaces)
|
||||
if (res.Result.ReadingType === 1) {
|
||||
this.$emit("setArbitrationReading", false);
|
||||
this.$emit('setArbitrationReading', false)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
this.loading = false
|
||||
})
|
||||
// }).catch(() => {
|
||||
// this.loading = false
|
||||
// })
|
||||
|
|
@ -874,52 +879,52 @@ export default {
|
|||
// 配置信息保存
|
||||
handleSave(isPrompt = true) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$refs["readingRulesForm"].validate((valid) => {
|
||||
this.$refs['readingRulesForm'].validate((valid) => {
|
||||
if (!valid) {
|
||||
resolve(false);
|
||||
resolve(false)
|
||||
} else {
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
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)
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
this.$emit("reloadArbitrationRules");
|
||||
this.loading = false
|
||||
this.$emit('reloadArbitrationRules')
|
||||
this.$emit(
|
||||
"setArbitrationReading",
|
||||
'setArbitrationReading',
|
||||
this.form.IsArbitrationReading
|
||||
);
|
||||
)
|
||||
this.$emit(
|
||||
"setAdditionalAssessment",
|
||||
'setAdditionalAssessment',
|
||||
this.form.IsAdditionalAssessment
|
||||
);
|
||||
this.$emit("setIsClinicalReading", this.form.IsClinicalReading);
|
||||
this.$emit("setGlobalReading", this.form.IsGlobalReading);
|
||||
this.$emit("setOncologyReading", this.form.IsOncologyReading);
|
||||
this.$emit("setDigitPlaces", this.form.DigitPlaces);
|
||||
)
|
||||
this.$emit('setIsClinicalReading', this.form.IsClinicalReading)
|
||||
this.$emit('setGlobalReading', this.form.IsGlobalReading)
|
||||
this.$emit('setOncologyReading', this.form.IsOncologyReading)
|
||||
this.$emit('setDigitPlaces', this.form.DigitPlaces)
|
||||
if (this.form.ReadingType === 1) {
|
||||
this.$emit("setArbitrationReading", false);
|
||||
this.$emit('setArbitrationReading', false)
|
||||
}
|
||||
if (res.IsSuccess && isPrompt) {
|
||||
this.$message.success(
|
||||
this.$t("common:message:savedSuccessfully")
|
||||
);
|
||||
this.$t('common:message:savedSuccessfully')
|
||||
)
|
||||
}
|
||||
resolve(true);
|
||||
resolve(true)
|
||||
})
|
||||
.catch((_) => {
|
||||
this.loading = false;
|
||||
resolve(false);
|
||||
});
|
||||
this.loading = false
|
||||
resolve(false)
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.reading-rule-config-form {
|
||||
|
|
|
|||
|
|
@ -370,11 +370,11 @@ export default {
|
|||
isCheck: readingRules,
|
||||
msg: this.$t("trials:readingUnit:readingRules"), // '阅片规则'
|
||||
});
|
||||
// var readingCriterions = await this.$refs['readingCriterions' + this.TrialReadingCriterionId][0].handleSave(false)
|
||||
// isCheckList.push({
|
||||
// isCheck: readingCriterions,
|
||||
// msg: '阅片标准'
|
||||
// })
|
||||
var qsLength = this.$refs['readingCriterions' + this.TrialReadingCriterionId][0].getQuestionLength()
|
||||
isCheckList.push({
|
||||
isCheck: qsLength > 0,
|
||||
msg: this.$t('trials:readingUnit:readingCriterion')
|
||||
})
|
||||
if (
|
||||
this.$refs["globalReading" + this.TrialReadingCriterionId] &&
|
||||
this.$refs["globalReading" + this.TrialReadingCriterionId]
|
||||
|
|
@ -497,12 +497,16 @@ export default {
|
|||
});
|
||||
},
|
||||
reloadArbitrationRules() {
|
||||
this.$refs[
|
||||
if (this.$refs[
|
||||
"arbitrationRules" + this.TrialReadingCriterionId
|
||||
][0].getList();
|
||||
this.$refs[
|
||||
"arbitrationRules" + this.TrialReadingCriterionId
|
||||
][0].getTrialJudgyInfo();
|
||||
]) {
|
||||
this.$refs[
|
||||
"arbitrationRules" + this.TrialReadingCriterionId
|
||||
][0].getList();
|
||||
this.$refs[
|
||||
"arbitrationRules" + this.TrialReadingCriterionId
|
||||
][0].getTrialJudgyInfo();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
type="text"
|
||||
@click="handleDownloadTpl"
|
||||
>
|
||||
{{ $t("trials:readingPeriod:cd:title:downloadTpl") }}
|
||||
{{ $t('trials:readingPeriod:cd:title:downloadTpl') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
"
|
||||
>
|
||||
<el-button type="primary" style="width: 56px" size="small">
|
||||
{{ $t("trials:uploadClinicalData:button:selectFile") }}
|
||||
{{ $t('trials:uploadClinicalData:button:selectFile') }}
|
||||
</el-button>
|
||||
<input
|
||||
type="file"
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
@change="beginScanFiles($event)"
|
||||
/>
|
||||
<span style="margin-left: 10px">{{
|
||||
$t("trials:attachment:message:pdf")
|
||||
$t('trials:attachment:message:pdf')
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
type="primary"
|
||||
@click="close"
|
||||
>
|
||||
{{ $t("common:button:cancel") }}
|
||||
{{ $t('common:button:cancel') }}
|
||||
</el-button>
|
||||
<!-- 保存 -->
|
||||
<el-button
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
:loading="btnLoading"
|
||||
@click="save"
|
||||
>
|
||||
{{ $t("common:button:save") }}
|
||||
{{ $t('common:button:save') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
|
@ -159,23 +159,23 @@ import {
|
|||
getTrialClinicalDataSelect,
|
||||
addOrUpdateReadingClinicalData,
|
||||
addOrUpdateConsistencyAnalysisReadingClinicalData,
|
||||
} from "@/api/trials";
|
||||
import { fileDownload } from "@/utils/uploadZip.js";
|
||||
} from '@/api/trials'
|
||||
import { downLoadFile } from '@/utils/stream.js'
|
||||
export default {
|
||||
name: "AddOrUpdateClinicalData",
|
||||
name: 'AddOrUpdateClinicalData',
|
||||
props: {
|
||||
trialReadingCriterionId: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
return {}
|
||||
},
|
||||
},
|
||||
type: {
|
||||
default: "readingPeriod",
|
||||
default: 'readingPeriod',
|
||||
},
|
||||
option: {
|
||||
default: () => [],
|
||||
|
|
@ -185,13 +185,13 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
fileList: [],
|
||||
faccept: [".pdf"],
|
||||
faccept: ['.pdf'],
|
||||
form: {
|
||||
Id: "",
|
||||
TrialId: "",
|
||||
SubjectId: "",
|
||||
ReadingId: "",
|
||||
ClinicalDataTrialSetId: "",
|
||||
Id: '',
|
||||
TrialId: '',
|
||||
SubjectId: '',
|
||||
ReadingId: '',
|
||||
ClinicalDataTrialSetId: '',
|
||||
IsVisist: true,
|
||||
AddFileList: [],
|
||||
DeleteFileIds: [],
|
||||
|
|
@ -201,8 +201,8 @@ export default {
|
|||
ClinicalDataTrialSetId: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ["blur", "change"],
|
||||
message: this.$t('common:ruleMessage:select'),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -211,194 +211,190 @@ export default {
|
|||
clinicalDatas: [],
|
||||
pendingUploadList: [],
|
||||
pendingDeleteList: [],
|
||||
currentTpl: { id: "", isExist: false },
|
||||
};
|
||||
currentTpl: { id: '', isExist: false },
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initForm();
|
||||
this.initForm()
|
||||
},
|
||||
methods: {
|
||||
// 下载临床数据
|
||||
handleUploadFile(row) {
|
||||
let href = this.OSSclientConfig.basePath + row.Path;
|
||||
let name = row.FileName;
|
||||
fileDownload(href, name);
|
||||
let href = this.OSSclientConfig.basePath + row.Path
|
||||
let name = row.FileName
|
||||
downLoadFile(href, name)
|
||||
},
|
||||
async initForm() {
|
||||
if (this.type === "readingPeriod") {
|
||||
await this.getClinicalDatas();
|
||||
if (this.type === 'readingPeriod') {
|
||||
await this.getClinicalDatas()
|
||||
} else {
|
||||
this.clinicalDatas = this.option;
|
||||
this.clinicalDatas = this.option
|
||||
}
|
||||
if (Object.keys(this.data).length > 0) {
|
||||
for (const k in this.form) {
|
||||
if (this.data.hasOwnProperty(k)) {
|
||||
this.form[k] = this.data[k];
|
||||
this.form[k] = this.data[k]
|
||||
}
|
||||
}
|
||||
this.handleClinicalDataSetChange(this.form.ClinicalDataTrialSetId);
|
||||
this.fileList = this.form.FileList.concat();
|
||||
this.handleClinicalDataSetChange(this.form.ClinicalDataTrialSetId)
|
||||
this.fileList = this.form.FileList.concat()
|
||||
}
|
||||
},
|
||||
save() {
|
||||
this.$refs.clinicalDataForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
if (!valid) return
|
||||
if (this.fileList.length === 0) {
|
||||
// 请上传文件!
|
||||
this.$alert(this.$t("trials:readingPeriod:cd:message:uploadFile"));
|
||||
return;
|
||||
this.$alert(this.$t('trials:readingPeriod:cd:message:uploadFile'))
|
||||
return
|
||||
}
|
||||
this.pendingUploadList = [];
|
||||
this.pendingUploadList = []
|
||||
for (let i = 0; i < this.fileList.length; ++i) {
|
||||
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) {
|
||||
this.uploadFilesAndSave();
|
||||
this.uploadFilesAndSave()
|
||||
} else {
|
||||
this.saveClinicalData();
|
||||
this.saveClinicalData()
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
uploadFilesAndSave() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
this.form.AddFileList = [];
|
||||
this.form.AddFileList = []
|
||||
for (var i = 0; i < this.pendingUploadList.length; ++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(
|
||||
`/${this.data.TrialId}/ClinicalData/${this.pendingUploadList[i].name}`,
|
||||
file
|
||||
);
|
||||
)
|
||||
this.form.AddFileList.push({
|
||||
fileName: this.pendingUploadList[i].name,
|
||||
path: this.$getObjectName(res.url),
|
||||
size: this.pendingUploadList[i].size,
|
||||
type: this.pendingUploadList[i].type,
|
||||
});
|
||||
})
|
||||
}
|
||||
this.saveClinicalData(this.form.AddFileList);
|
||||
resolve();
|
||||
});
|
||||
this.saveClinicalData(this.form.AddFileList)
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
saveClinicalData() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.btnLoading = true;
|
||||
this.form.DeleteFileIds = this.pendingDeleteList;
|
||||
if (this.type === "consistencyAnalysis") {
|
||||
this.btnLoading = true
|
||||
this.form.DeleteFileIds = this.pendingDeleteList
|
||||
if (this.type === 'consistencyAnalysis') {
|
||||
addOrUpdateConsistencyAnalysisReadingClinicalData(this.form)
|
||||
.then((response) => {
|
||||
this.btnLoading = false;
|
||||
this.$emit("getList");
|
||||
this.$emit("close");
|
||||
this.$message.success(
|
||||
this.$t("common:message:savedSuccessfully")
|
||||
);
|
||||
resolve();
|
||||
this.btnLoading = false
|
||||
this.$emit('getList')
|
||||
this.$emit('close')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
resolve()
|
||||
})
|
||||
.catch(() => {
|
||||
this.btnLoading = false;
|
||||
reject();
|
||||
});
|
||||
this.btnLoading = false
|
||||
reject()
|
||||
})
|
||||
} else {
|
||||
addOrUpdateReadingClinicalData(this.form)
|
||||
.then((response) => {
|
||||
this.btnLoading = false;
|
||||
this.$emit("getList");
|
||||
this.$emit("close");
|
||||
this.$message.success(
|
||||
this.$t("common:message:savedSuccessfully")
|
||||
);
|
||||
resolve();
|
||||
this.btnLoading = false
|
||||
this.$emit('getList')
|
||||
this.$emit('close')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
resolve()
|
||||
})
|
||||
.catch(() => {
|
||||
this.btnLoading = false;
|
||||
reject();
|
||||
});
|
||||
this.btnLoading = false
|
||||
reject()
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
getClinicalDatas() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
var param = {
|
||||
trialId: this.data.TrialId,
|
||||
IsVisit: this.data.IsVisit,
|
||||
ReadingId: this.data.ReadingId,
|
||||
SubjectId: this.data.SubjectId,
|
||||
ReadingClinicalDataId: this.data.Id ? this.data.Id : "",
|
||||
ReadingClinicalDataId: this.data.Id ? this.data.Id : '',
|
||||
IsBaseLine: this.data.IsBaseLine,
|
||||
TrialReadingCriterionId: this.trialReadingCriterionId,
|
||||
};
|
||||
}
|
||||
getTrialClinicalDataSelect(param)
|
||||
.then((res) => {
|
||||
this.clinicalDatas = res.Result;
|
||||
this.loading = false;
|
||||
resolve();
|
||||
this.clinicalDatas = res.Result
|
||||
this.loading = false
|
||||
resolve()
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
reject();
|
||||
});
|
||||
});
|
||||
this.loading = false
|
||||
reject()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteFile(index, row) {
|
||||
this.$confirm(this.$t("trials:readingPeriod:cd:message:delete"), {
|
||||
type: "warning",
|
||||
this.$confirm(this.$t('trials:readingPeriod:cd:message:delete'), {
|
||||
type: 'warning',
|
||||
distinguishCancelAndClose: true,
|
||||
})
|
||||
.then(() => {
|
||||
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) {
|
||||
var files = e.target.files;
|
||||
var files = e.target.files
|
||||
for (var i = 0; i < files.length; ++i) {
|
||||
const fileName = files[i].name;
|
||||
const fileName = files[i].name
|
||||
var extendName = fileName
|
||||
.substring(fileName.lastIndexOf("."))
|
||||
.toLocaleLowerCase();
|
||||
.substring(fileName.lastIndexOf('.'))
|
||||
.toLocaleLowerCase()
|
||||
if (this.faccept.indexOf(extendName) !== -1) {
|
||||
this.fileList.push({
|
||||
FileName: fileName,
|
||||
Path: "",
|
||||
Path: '',
|
||||
Status: 0,
|
||||
Files: files[i],
|
||||
size: files[i].size,
|
||||
type: fileName.split(".")[1],
|
||||
});
|
||||
type: fileName.split('.')[1],
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
handleClinicalDataSetChange(v) {
|
||||
var index = this.clinicalDatas.findIndex((item) => item.Id === v);
|
||||
var index = this.clinicalDatas.findIndex((item) => item.Id === v)
|
||||
if (index > -1) {
|
||||
this.currentTpl.id = this.clinicalDatas[index].Id;
|
||||
this.currentTpl.path = this.clinicalDatas[index].Path;
|
||||
this.currentTpl.isExist = !!this.clinicalDatas[index].FileName;
|
||||
this.currentTpl.id = this.clinicalDatas[index].Id
|
||||
this.currentTpl.path = this.clinicalDatas[index].Path
|
||||
this.currentTpl.isExist = !!this.clinicalDatas[index].FileName
|
||||
}
|
||||
},
|
||||
handleDownloadTpl() {
|
||||
this.loading = true;
|
||||
this.loading = true
|
||||
window.open(
|
||||
this.OSSclientConfig.basePath + this.currentTpl.path,
|
||||
"_blank"
|
||||
);
|
||||
this.loading = false;
|
||||
'_blank'
|
||||
)
|
||||
this.loading = false
|
||||
// DownloadTrialClinicalFile(this.currentTpl.id).then(data => {
|
||||
// this.loading = false
|
||||
// }).catch(() => { this.loading = false })
|
||||
},
|
||||
close() {
|
||||
this.$emit("close");
|
||||
this.$emit('close')
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -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;">
|
||||
{{$t('trials:auditRecord:title:viewDetail')}}
|
||||
</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">
|
||||
<img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt="">
|
||||
</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;">
|
||||
{{$t('trials:auditRecord:title:viewDetail')}}
|
||||
</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">
|
||||
<img v-if="scope.row.DataType === 'ImageList'" :key="item" :src="OSSclientConfig.basePath + item" v-show="false" crossorigin="anonymous" alt="">
|
||||
</template>
|
||||
|
|
@ -409,9 +409,9 @@
|
|||
:key="'tableList' + index"
|
||||
>
|
||||
<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="">
|
||||
</viewer>
|
||||
<span v-else>{{scope.row[item.ColumnValue]}}</span>
|
||||
|
|
@ -426,9 +426,9 @@
|
|||
:key="'ChildrenList' + index"
|
||||
>
|
||||
<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')}}
|
||||
</span>
|
||||
<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' ? '删除前' : '修改前' -->
|
||||
<el-table-column
|
||||
v-if="OptType !== 'Add' && OptType !== 'Upload' && OptType !== 'Init'"
|
||||
v-if="OptType2 !== 'Add' && OptType2 !== 'Upload' && OptType2 !== 'Init'"
|
||||
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
|
||||
>
|
||||
<!-- <template slot-scope="scope">
|
||||
|
|
@ -692,7 +692,7 @@
|
|||
<!-- OptType === 'Add' || OptType === 'Init' ? '值' : OptType === 'Delete' ? '删除后' : '修改后' -->
|
||||
<el-table-column
|
||||
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
|
||||
>
|
||||
<!-- <template slot-scope="scope">
|
||||
|
|
@ -876,6 +876,7 @@ export default {
|
|||
siteOptions: [],
|
||||
visitPlanOptions: [],
|
||||
OptType: null,
|
||||
OptType2: null,
|
||||
trialId: this.$route.query.trialId,
|
||||
configList2: [],
|
||||
otherData2: [],
|
||||
|
|
@ -896,19 +897,22 @@ export default {
|
|||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
openImage(url) {
|
||||
openImage(url, type) {
|
||||
console.log(url)
|
||||
|
||||
this.$nextTick(()=>{
|
||||
if (url instanceof Array) {
|
||||
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 {
|
||||
this.imagesList = [this.OSSclientConfig.basePath + url]
|
||||
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{
|
||||
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[auditData] = []
|
||||
config.forEach(v => {
|
||||
v.Code = this.$i18n.locale === 'zh' ? v.Code : v.CodeEn ? v.CodeEn : v.Code
|
||||
|
||||
var item
|
||||
if (!v.IsEnable) return
|
||||
if (v.IsShowByTrialConfig) {
|
||||
|
|
@ -989,18 +995,18 @@ export default {
|
|||
let uo = upObj[v.TableFiledName][i]
|
||||
if (row.OptType === 'Add' || row.OptType === 'Init') {
|
||||
item = {
|
||||
newValue: o[v.Code] ? (o[v.Code] ? o[v.Code] : '--') : '--',
|
||||
newValue: o[v.Code] ? o[v.Code] : '--',
|
||||
oldValue: ''
|
||||
}
|
||||
} else if (row.OptType === 'Delete') {
|
||||
item = {
|
||||
oldValue: o[v.Code] ? (o[v.Code] ? o[v.Code] : '--') : '--',
|
||||
oldValue: o[v.Code] ? o[v.Code] : '--',
|
||||
newValue: '--'
|
||||
}
|
||||
} else {
|
||||
item = {
|
||||
newValue: o[v.Code] ? (o[v.Code] ? o[v.Code] : '--') : '--',
|
||||
oldValue: uo ? uo[v.Code] : '--'
|
||||
newValue: o[v.Code] ? o[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] : '--') : '--'
|
||||
|
|
@ -1019,21 +1025,21 @@ export default {
|
|||
if (row.OptType === 'Add' || row.OptType === 'Init') {
|
||||
item = {
|
||||
key: v.Code,
|
||||
Enum: v.ValueCN,
|
||||
Enum: this.$i18n.locale === 'zh' ? v.ValueCN : v.Value,
|
||||
newValue: obj[v.Code] ? obj[v.Code] : '--',
|
||||
oldValue: ''
|
||||
}
|
||||
} else if (row.OptType === 'Delete') {
|
||||
item = {
|
||||
key: v.Code,
|
||||
Enum: v.ValueCN,
|
||||
Enum: this.$i18n.locale === 'zh' ? v.ValueCN : v.Value,
|
||||
oldValue: obj[v.Code] ? obj[v.Code] : '--',
|
||||
newValue: '--'
|
||||
}
|
||||
} else {
|
||||
item = {
|
||||
key: v.Code,
|
||||
Enum: v.ValueCN,
|
||||
Enum: this.$i18n.locale === 'zh' ? v.ValueCN : v.Value,
|
||||
newValue: obj[v.Code] ? obj[v.Code] : '--',
|
||||
oldValue: upObj[v.Code].length > 0 ? upObj[v.Code] : '--'
|
||||
}
|
||||
|
|
@ -1051,23 +1057,23 @@ export default {
|
|||
if (row.OptType === 'Add' || row.OptType === 'Init') {
|
||||
item = {
|
||||
key: o[v.ChildDataLabel],
|
||||
Enum: o[v.ChildDataLabel],
|
||||
newValue: o[v.ChildDataValue] ? (o[v.ChildDataValue] ? o[v.ChildDataValue] : '--') : '--',
|
||||
Enum: this.$i18n.locale === 'zh' ? o[v.ChildDataLabel] : o[v.ChildDataEnLabel] ? o[v.ChildDataEnLabel] : o[v.ChildDataLabel],
|
||||
newValue: o[v.ChildDataValue] ? o[v.ChildDataValue] : '--',
|
||||
oldValue: ''
|
||||
}
|
||||
} else if (row.OptType === 'Delete') {
|
||||
item = {
|
||||
key: o[v.ChildDataLabel],
|
||||
Enum: o[v.ChildDataLabel],
|
||||
oldValue: o[v.ChildDataValue] ? (o[v.ChildDataValue] ? o[v.ChildDataValue] : '--') : '--',
|
||||
Enum: this.$i18n.locale === 'zh' ? o[v.ChildDataLabel] : o[v.ChildDataEnLabel] ? o[v.ChildDataEnLabel] : o[v.ChildDataLabel],
|
||||
oldValue: o[v.ChildDataValue] ? o[v.ChildDataValue] : '--',
|
||||
newValue: '--'
|
||||
}
|
||||
} else {
|
||||
item = {
|
||||
key: o[v.ChildDataLabel],
|
||||
Enum: o[v.ChildDataLabel],
|
||||
newValue: o[v.ChildDataValue] ? (o[v.ChildDataValue] ? o[v.ChildDataValue] : '--') : '--',
|
||||
oldValue: uo ? uo[v.ChildDataValue] : '--'
|
||||
Enum: this.$i18n.locale === 'zh' ? o[v.ChildDataLabel] : o[v.ChildDataEnLabel] ? o[v.ChildDataEnLabel] : o[v.ChildDataLabel],
|
||||
newValue: o[v.ChildDataValue] ? o[v.ChildDataValue] : '--',
|
||||
oldValue: uo ? uo[v.ChildDataValue] ? uo[v.ChildDataValue] : '--' : '--'
|
||||
}
|
||||
}
|
||||
this[auditData].push(item)
|
||||
|
|
@ -1084,7 +1090,7 @@ export default {
|
|||
a = getToken()
|
||||
}
|
||||
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 + '?' +
|
||||
v.UrlConfig.ParameterList.map((v) => {
|
||||
let a = obj[v.UrlParameterValueName] ? obj[v.UrlParameterValueName] : parentRow[v.UrlParameterValueName]
|
||||
|
|
@ -1092,7 +1098,7 @@ export default {
|
|||
a = getToken()
|
||||
}
|
||||
return v.UrlParameterName + '=' + a + '&'
|
||||
}).toString().replaceAll(',', '') : v.UrlConfig.RoutePath
|
||||
}).toString().replaceAll(',', '') + 'zh='+this.$i18n.locale : v.UrlConfig.RoutePath
|
||||
}
|
||||
console.log(item)
|
||||
item.IsTableFiled = v.IsTableFiled
|
||||
|
|
@ -1111,10 +1117,10 @@ export default {
|
|||
} else {
|
||||
if (j.ListName) {
|
||||
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 {
|
||||
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) {
|
||||
this.OptType2 = row.OptType
|
||||
var Json = await this.getJSON(row)
|
||||
var JsonDetail = Json[0] ? JSON.parse(Json[0]) : null
|
||||
var ParentJson = Json[1] ? JSON.parse(Json[1]) : null
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<el-upload
|
||||
class="upload-demo"
|
||||
action
|
||||
accept=".xlsx,.xls,.csv"
|
||||
accept=".xlsx,.xls"
|
||||
:before-upload="beforeUpload"
|
||||
:http-request="handleUploadFile"
|
||||
:on-preview="handlePreview"
|
||||
|
|
@ -72,7 +72,7 @@ export default {
|
|||
this.$message.warning(this.$t('trials:consistencyCheck:message:onlyOneFile'))
|
||||
},
|
||||
checkFileSuffix(fileName) {
|
||||
var typeArr = ['xls', 'xlsx', 'csv']
|
||||
var typeArr = ['xls', 'xlsx']
|
||||
var extendName = fileName.substring(fileName.lastIndexOf('.') + 1).toLocaleLowerCase()
|
||||
if (typeArr.indexOf(extendName) !== -1) {
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<span style="font-weight:700;">{{ record.CreateUserName }} </span>
|
||||
<span>({{ record.CreateTime }}) </span>
|
||||
</p>
|
||||
<div class="info-content" v-html="record.TalkContent" />
|
||||
<div class="info-content" v-html="formattedText(record.TalkContent)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
<span style="font-weight:700;">{{ record.CreateUserName }} </span>
|
||||
<span>({{ record.CreateTime }}) </span>
|
||||
</p>
|
||||
<div class="info-content" v-html="record.TalkContent" />
|
||||
<div class="info-content" v-html="formattedText(record.TalkContent)" />
|
||||
</div>
|
||||
<!-- <img :src="record.headUrl"> -->
|
||||
<img v-if="record.UserTypeEnum*1 === 8" :src="adminAvatar" alt="Admin">
|
||||
|
|
@ -231,6 +231,9 @@ export default {
|
|||
this.getMessageList()
|
||||
},
|
||||
methods: {
|
||||
formattedText(text) {
|
||||
return text.replace(/\n/g, '<br>')
|
||||
},
|
||||
// 初始化聊天信息
|
||||
getMessageList() {
|
||||
var recordContent = []
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@
|
|||
</div>
|
||||
<!-- PDF录入 -->
|
||||
<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
|
||||
v-if="cd.Path"
|
||||
|
|
@ -271,6 +271,7 @@
|
|||
position: relative;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
margin-left:10px
|
||||
"
|
||||
>
|
||||
<!-- 新增 -->
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -654,6 +654,7 @@ export default {
|
|||
this.loading = true;
|
||||
this.data.TrialId = this.$route.query.trialId;
|
||||
var param = {
|
||||
SubjectVisitId: this.studyData.SubjectVisitId,
|
||||
StudyId: this.studyData.StudyId,
|
||||
TrialId: this.$route.query.trialId,
|
||||
SubjectId: this.studyData.SubjectId,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<span style="font-weight:700;">{{ record.CreateUserName }} </span>
|
||||
<span>({{ record.CreateTime }}) </span>
|
||||
</p>
|
||||
<div class="info-content" v-html="record.TalkContent" />
|
||||
<div class="info-content" v-html="formattedText(record.TalkContent)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
<span style="font-weight:700;">{{ record.CreateUserName }} </span>
|
||||
<span>({{ record.CreateTime }}) </span>
|
||||
</p>
|
||||
<div class="info-content" v-html="record.TalkContent" />
|
||||
<div class="info-content" v-html="formattedText(record.TalkContent)" />
|
||||
</div>
|
||||
<!-- <img :src="record.headUrl"> -->
|
||||
<img v-if="record.UserTypeEnum*1 === 8" :src="adminAvatar" alt="Admin">
|
||||
|
|
@ -153,6 +153,9 @@ export default {
|
|||
close() {
|
||||
this.$emit('close')
|
||||
},
|
||||
formattedText(text) {
|
||||
return text.replace(/\n/g, '<br>')
|
||||
},
|
||||
// 初始化聊天信息
|
||||
getMessageList() {
|
||||
var recordContent = []
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -16,7 +16,7 @@ const name = process.env.NODE_ENV === 'usa' ? 'LILI' : defaultSettings.title ||
|
|||
// eslint-disable-next-line no-undef
|
||||
module.exports = {
|
||||
// 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: '/',
|
||||
outputDir: 'dist',
|
||||
|
|
|
|||
Loading…
Reference in New Issue