数据处理更改

temp
caiyiling 2026-07-31 16:40:37 +08:00
parent 197b3213e7
commit 9dcbad7616
12 changed files with 443 additions and 128 deletions

View File

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

View File

@ -1256,53 +1256,55 @@ export default {
dicomInfo.uploadFileSize += o.file.size
Record.Existed.push(name)
Record.FileCount++
} else if (o.myPath) {
instanceList.push({
studyInstanceUid: dicomInfo.studyUid,
seriesInstanceUid: v.seriesUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:
o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID:
o.MediaStorageSOPClassUID,
sopInstanceUid: o.instanceUid,
instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime,
imageRows: o.imageRows,
imageColumns: o.imageColumns,
sliceLocation: o.sliceLocation,
sliceThickness: o.sliceThickness,
numberOfFrames: o.numberOfFrames,
pixelSpacing: o.pixelSpacing,
imagerPixelSpacing: o.imagerPixelSpacing,
frameOfReferenceUID: o.frameOfReferenceUID,
windowCenter: o.windowCenter,
windowWidth: o.windowWidth,
path: o.myPath,
FileSize: o.FileSize,
}
// else if (o.myPath) {
// instanceList.push({
// studyInstanceUid: dicomInfo.studyUid,
// seriesInstanceUid: v.seriesUid,
// SOPClassUID: o.SOPClassUID,
// TransferSytaxUID: o.TransferSytaxUID,
// MediaStorageSOPInstanceUID:
// o.MediaStorageSOPInstanceUID,
// MediaStorageSOPClassUID:
// o.MediaStorageSOPClassUID,
// sopInstanceUid: o.instanceUid,
// instanceNumber: o.instanceNumber,
// instanceTime: o.instanceTime,
// imageRows: o.imageRows,
// imageColumns: o.imageColumns,
// sliceLocation: o.sliceLocation,
// sliceThickness: o.sliceThickness,
// numberOfFrames: o.numberOfFrames,
// pixelSpacing: o.pixelSpacing,
// imagerPixelSpacing: o.imagerPixelSpacing,
// frameOfReferenceUID: o.frameOfReferenceUID,
// windowCenter: o.windowCenter,
// windowWidth: o.windowWidth,
// path: o.myPath,
// FileSize: o.FileSize,
PhotometricInterpretation:
o.PhotometricInterpretation,
BitsAllocated: o.BitsAllocated,
PixelRepresentation: o.PixelRepresentation,
RescaleIntercept: o.RescaleIntercept,
RescaleSlope: o.RescaleSlope,
ImagePositionPatient: o.ImagePositionPatient,
ImageOrientationPatient:
o.ImageOrientationPatient,
SequenceOfUltrasoundRegions:
o.SequenceOfUltrasoundRegions,
FrameTime: o.FrameTime,
CorrectedImage: o.CorrectedImage,
Units: o.Units,
DecayCorrection: o.DecayCorrection,
EncapsulatedDocument: o.EncapsulatedDocument,
})
Record.Uploaded.push(name)
dicomInfo.failedFileCount++
Record.FileCount++
} else {
// PhotometricInterpretation:
// o.PhotometricInterpretation,
// BitsAllocated: o.BitsAllocated,
// PixelRepresentation: o.PixelRepresentation,
// RescaleIntercept: o.RescaleIntercept,
// RescaleSlope: o.RescaleSlope,
// ImagePositionPatient: o.ImagePositionPatient,
// ImageOrientationPatient:
// o.ImageOrientationPatient,
// SequenceOfUltrasoundRegions:
// o.SequenceOfUltrasoundRegions,
// FrameTime: o.FrameTime,
// CorrectedImage: o.CorrectedImage,
// Units: o.Units,
// DecayCorrection: o.DecayCorrection,
// EncapsulatedDocument: o.EncapsulatedDocument,
// })
// Record.Uploaded.push(name)
// dicomInfo.failedFileCount++
// Record.FileCount++
// }
else {
let path = `/${params.trialId}/Image/${params.subjectId
}/${params.subjectVisitId}/${dicomInfo.visitTaskId
}/${scope.getGuid(

View File

@ -309,9 +309,10 @@
<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')"
<el-tooltip
v-if="trialCriterion.ImageUploadEnum > 0"
class="item" effect="dark"
:content="$t('trials:reading:button:upload')"
placement="bottom">
<div class="tool-wrapper">
<div class="icon" @click.prevent="openUploadImage('upload')">

View File

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

View File

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

View File

@ -320,7 +320,7 @@
</div>
</div>
<div class="tool-item" :title="$t('trials:reading:button:upload')"
v-if="trialCriterion.ImageUploadEnum > 0 && readingTaskState < 2" v-hasPermi="['role:ir']">
v-if="trialCriterion.ImageUploadEnum > 0" v-hasPermi="['role:ir']">
<div class="tool-wrapper">
<div class="icon" @click.prevent="openUploadImage('upload')">
<i class="el-icon-upload2 svg-icon" />

View File

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

View File

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

View File

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

View File

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

View File

@ -1577,53 +1577,55 @@ export default {
dicomInfo.uploadFileSize += o.file.size
Record.Existed.push(name)
Record.FileCount++
} else if (o.myPath) {
instanceList.push({
studyInstanceUid: dicomInfo.studyUid,
seriesInstanceUid: v.seriesUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:
o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID:
o.MediaStorageSOPClassUID,
sopInstanceUid: o.instanceUid,
instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime,
imageRows: o.imageRows,
imageColumns: o.imageColumns,
sliceLocation: o.sliceLocation,
sliceThickness: o.sliceThickness,
numberOfFrames: o.numberOfFrames,
pixelSpacing: o.pixelSpacing,
imagerPixelSpacing: o.imagerPixelSpacing,
frameOfReferenceUID: o.frameOfReferenceUID,
windowCenter: o.windowCenter,
windowWidth: o.windowWidth,
path: o.myPath,
FileSize: o.FileSize,
}
// else if (o.myPath) {
// instanceList.push({
// studyInstanceUid: dicomInfo.studyUid,
// seriesInstanceUid: v.seriesUid,
// SOPClassUID: o.SOPClassUID,
// TransferSytaxUID: o.TransferSytaxUID,
// MediaStorageSOPInstanceUID:
// o.MediaStorageSOPInstanceUID,
// MediaStorageSOPClassUID:
// o.MediaStorageSOPClassUID,
// sopInstanceUid: o.instanceUid,
// instanceNumber: o.instanceNumber,
// instanceTime: o.instanceTime,
// imageRows: o.imageRows,
// imageColumns: o.imageColumns,
// sliceLocation: o.sliceLocation,
// sliceThickness: o.sliceThickness,
// numberOfFrames: o.numberOfFrames,
// pixelSpacing: o.pixelSpacing,
// imagerPixelSpacing: o.imagerPixelSpacing,
// frameOfReferenceUID: o.frameOfReferenceUID,
// windowCenter: o.windowCenter,
// windowWidth: o.windowWidth,
// path: o.myPath,
// FileSize: o.FileSize,
PhotometricInterpretation:
o.PhotometricInterpretation,
BitsAllocated: o.BitsAllocated,
PixelRepresentation: o.PixelRepresentation,
RescaleIntercept: o.RescaleIntercept,
RescaleSlope: o.RescaleSlope,
ImagePositionPatient: o.ImagePositionPatient,
ImageOrientationPatient:
o.ImageOrientationPatient,
SequenceOfUltrasoundRegions:
o.SequenceOfUltrasoundRegions,
FrameTime: o.FrameTime,
CorrectedImage: o.CorrectedImage,
Units: o.Units,
DecayCorrection: o.DecayCorrection,
EncapsulatedDocument: o.EncapsulatedDocument,
})
Record.Uploaded.push(name)
dicomInfo.failedFileCount++
Record.FileCount++
} else {
// PhotometricInterpretation:
// o.PhotometricInterpretation,
// BitsAllocated: o.BitsAllocated,
// PixelRepresentation: o.PixelRepresentation,
// RescaleIntercept: o.RescaleIntercept,
// RescaleSlope: o.RescaleSlope,
// ImagePositionPatient: o.ImagePositionPatient,
// ImageOrientationPatient:
// o.ImageOrientationPatient,
// SequenceOfUltrasoundRegions:
// o.SequenceOfUltrasoundRegions,
// FrameTime: o.FrameTime,
// CorrectedImage: o.CorrectedImage,
// Units: o.Units,
// DecayCorrection: o.DecayCorrection,
// EncapsulatedDocument: o.EncapsulatedDocument,
// })
// Record.Uploaded.push(name)
// dicomInfo.failedFileCount++
// Record.FileCount++
// }
else {
let path = `/${params.trialId}/Image/${params.subjectId
}/${params.subjectVisitId}/${dicomInfo.studyUid
}/${scope.getGuid(

View File

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