From db627afeda819388d7c6860bd40f1adbfeae5284 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Fri, 5 Jun 2026 18:15:19 +0800 Subject: [PATCH 001/159] 1 --- .../reading/dicoms3D/components/Segmentations.vue | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue index 36935e99..822dcd35 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue @@ -34,9 +34,9 @@ @click.prevent="setToolActive('CircularEraser')"> - +
{ if (item) { @@ -1464,6 +1464,7 @@ export default { ); voxelManager.setScalarData(scalarData); } + this.createSegmentationRepresentation(segmentationId) }, createSegmentGroupObj(name) { let flag = this.segmentList.some(item => item.name === name) From f38f1f465a8920a4f7372bc98fda2c48de018a57 Mon Sep 17 00:00:00 2001 From: "DESKTOP-775TN7O\\wxs" <825034831@qq.com> Date: Fri, 5 Jun 2026 21:53:04 +0800 Subject: [PATCH 002/159] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8F=91=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../setting/trial-config/components/logicalConfig.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/trials/trials-panel/setting/trial-config/components/logicalConfig.vue b/src/views/trials/trials-panel/setting/trial-config/components/logicalConfig.vue index 612c4a71..a18e147e 100644 --- a/src/views/trials/trials-panel/setting/trial-config/components/logicalConfig.vue +++ b/src/views/trials/trials-panel/setting/trial-config/components/logicalConfig.vue @@ -1325,7 +1325,7 @@ export default { let obj = { Name: item.Name, NewVal: item.TrialName, - OldVal: old.TrialName, + OldVal: old.TrialName, } this.confirmData.push(obj) }) From 1db50cff3b6e75a3e8eaac363b1ba0d6a4823133 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Mon, 8 Jun 2026 13:23:09 +0800 Subject: [PATCH 003/159] =?UTF-8?q?=E8=B4=A8=E6=8E=A7=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E5=AD=97=E6=AE=B5=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/trials/trials-panel/visit/qc-check/index.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/views/trials/trials-panel/visit/qc-check/index.vue b/src/views/trials/trials-panel/visit/qc-check/index.vue index 61990df9..52164d1f 100644 --- a/src/views/trials/trials-panel/visit/qc-check/index.vue +++ b/src/views/trials/trials-panel/visit/qc-check/index.vue @@ -33,7 +33,7 @@ - + @@ -658,7 +658,8 @@ const searchDataDefault = () => { EndAuditTime: null, PageIndex: 1, PageSize: 20, - IsSubjectQuit: '' + IsSubjectQuit: '', + SubjectStatus: null // SortField: '', // Asc: false } From 37257da722a42e778dd70673c075532c8a839c0a Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Mon, 8 Jun 2026 14:11:09 +0800 Subject: [PATCH 004/159] 1 --- src/views/trials/trials-panel/reading/read-task/index.vue | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/views/trials/trials-panel/reading/read-task/index.vue b/src/views/trials/trials-panel/reading/read-task/index.vue index 0d1f56bd..c754bb48 100644 --- a/src/views/trials/trials-panel/reading/read-task/index.vue +++ b/src/views/trials/trials-panel/reading/read-task/index.vue @@ -177,7 +177,9 @@ custom-class="base-dialog-wrapper"> -

{{ $t('trials:readTask:applyReread:title').replace('xxx', rowData.SubjectCode).replace('yyy', rowData.TaskName) }}

+

{{ $t('trials:readTask:applyReread:title').replace('xxx', rowData.SubjectCode).replace('yyy', + rowData.TaskName) + }}

{{ $t('trials:readTask:title:applyReason') }} @@ -378,6 +380,7 @@ export default { }, computed: { isTumor() { + return true let criterion = this.trialCriterionList.find(item => item.TrialReadingCriterionId === this.TrialReadingCriterionId) if (criterion) { return [1, 18, 2, 3, 7, 10, 17].includes(Number(criterion.CriterionType)) @@ -443,7 +446,7 @@ export default { } var routeData = this.$router.resolve({ path }) let imageToolType = row.ReadingTool === 1 ? 2 : 1 - const res = await getAutoCutNextTask({imageToolType}) + const res = await getAutoCutNextTask({ imageToolType }) let IsDoubleScreen = false if (res.IsSuccess) { IsDoubleScreen = res.Result.IsDoubleScreen From ebfbe27d0c0a5053e2679822f78efc4d431c2e12 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Mon, 8 Jun 2026 14:36:51 +0800 Subject: [PATCH 005/159] =?UTF-8?q?=E5=85=A8=E5=B1=80=E9=98=85=E7=89=87?= =?UTF-8?q?=E3=80=81=E8=A3=81=E5=88=A4=E9=98=85=E7=89=87=E6=97=B6=E4=B8=8D?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=A4=8D=E5=88=B6=E5=90=8E=E7=BB=AD=E8=AE=BF?= =?UTF-8?q?=E8=A7=86=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/trials/trials-panel/reading/read-task/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/trials/trials-panel/reading/read-task/index.vue b/src/views/trials/trials-panel/reading/read-task/index.vue index 0d1f56bd..7dbe6a8c 100644 --- a/src/views/trials/trials-panel/reading/read-task/index.vue +++ b/src/views/trials/trials-panel/reading/read-task/index.vue @@ -209,7 +209,7 @@
From 1a26d3885a053f92ccc70645e1846bb5deb0a8af Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Mon, 8 Jun 2026 15:42:58 +0800 Subject: [PATCH 006/159] 1 --- src/views/trials/trials-panel/reading/read-task/index.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/views/trials/trials-panel/reading/read-task/index.vue b/src/views/trials/trials-panel/reading/read-task/index.vue index 326b6800..8c0bcec2 100644 --- a/src/views/trials/trials-panel/reading/read-task/index.vue +++ b/src/views/trials/trials-panel/reading/read-task/index.vue @@ -380,7 +380,6 @@ export default { }, computed: { isTumor() { - return true let criterion = this.trialCriterionList.find(item => item.TrialReadingCriterionId === this.TrialReadingCriterionId) if (criterion) { return [1, 18, 2, 3, 7, 10, 17].includes(Number(criterion.CriterionType)) From 7325760c234a9d2c0b703863e6d5b129077db584 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Tue, 9 Jun 2026 13:39:02 +0800 Subject: [PATCH 007/159] =?UTF-8?q?=E5=9C=A8=E8=B4=A6=E5=8F=B7=E9=95=BF?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E6=9C=AA=E8=AE=BF=E9=97=AE=EF=BC=8C=E9=94=81?= =?UTF-8?q?=E5=AE=9A=E6=88=96=E8=80=85=E9=80=80=E5=87=BA=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E8=83=BD=E5=B1=95=E7=A4=BA=E9=A1=B5=E9=9D=A2=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 8 ++++---- src/main.js | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/App.vue b/src/App.vue index 3d5733f0..730b503a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -120,10 +120,10 @@ export default { mounted() { this.show = process.env.VUE_APP_OSS_PATH === '/test/dist' Vue.prototype.$openI18n = this.openI18n - // this.getIsLock() - // DicomEvent.$on("isLock", (isLock) => { - // this.isLock = isLock - // }) + this.getIsLock() + DicomEvent.$on("isLock", (isLock) => { + this.isLock = isLock + }) }, // watch: { // '$route.query': { diff --git a/src/main.js b/src/main.js index 9c67244c..83cb16e7 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,6 @@ import Vue from 'vue' -// import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' +import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' import 'normalize.css/normalize.css' // A modern alternative to CSS resets // import { createVersionPolling } from "@/utils/version-polling.esm.js"; import ElementUI, { MessageBox } from 'element-ui' @@ -452,7 +452,7 @@ async function VueInit() { isOpen = false isLock = null zzSessionStorage.removeItem('isLock') - // DicomEvent.$emit('isLock', false) + DicomEvent.$emit('isLock', false) router.push("/login") }).then(() => { // _vm.$alert(lang === 'zh' ? '由于您长时间未操作,为保护您的数据安全已强制将您下线,如果需要继续操作请重新登陆!' : 'No operation for a long time non-operation, you have been forced logout to protect data security. If continue to operate, please login again!', { @@ -473,7 +473,7 @@ async function VueInit() { if (_vm.$route.path === '/login') { zzSessionStorage.removeItem('lastWorkbench') zzSessionStorage.removeItem('isLock') - // DicomEvent.$emit('isLock', false) + DicomEvent.$emit('isLock', false) isLock = null } return @@ -483,7 +483,7 @@ async function VueInit() { } isOpen = true zzSessionStorage.setItem('isLock', 'true') - // DicomEvent.$emit('isLock', true) + DicomEvent.$emit('isLock', true) _vm.$msgbox({ title: _vm.$t("env:lock:msgBox:title"), confirmButtonText: _vm.$t("env:lock:msgBox:confirmButtonText"), @@ -516,7 +516,7 @@ async function VueInit() { count = 0; isLock = null zzSessionStorage.removeItem('isLock') - // DicomEvent.$emit('isLock', false) + DicomEvent.$emit('isLock', false) localStorage.setItem('count', '0') document.querySelector('#my_username').value = null document.querySelector('#my_password').value = null From 7fea4b938fab4062a18670a80ac5816cd42dd5bd Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Tue, 9 Jun 2026 13:43:20 +0800 Subject: [PATCH 008/159] =?UTF-8?q?=E9=9D=9EDICOM=E9=98=85=E7=89=87?= =?UTF-8?q?=E5=B7=A5=E5=85=B7-=E6=94=AF=E6=8C=81=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E9=98=85=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../visit-review/components/FileViewer.vue | 158 ++++++++++++++++-- .../visit-review/components/StudyList.vue | 10 +- 2 files changed, 152 insertions(+), 16 deletions(-) diff --git a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue index 73605664..61c12eb2 100644 --- a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue +++ b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue @@ -57,13 +57,13 @@
- +
@@ -130,7 +130,7 @@
-
-
+
+ +
+
+
+
+ +
+

+ {{ `${taskInfo.SubjectCode} ${v.taskInfo.TaskBlindName} ` }} +

+
{{ v.currentFileName }}
+
+
+
+
+ +
+
+ {{ v.taskInfo.TaskBlindName }} +
+
+ +
+
+
+
+
+ +
+ +
+
@@ -946,6 +988,12 @@ export default { // }) // }) }, + getCellStyle(index) { + return { + ...this.cellStyle, + display: index < this.cells.length ? this.cellStyle.display : 'none' + } + }, // 切换全屏 toggleFullScreen(e, index) { const i = this.viewportInfos.findIndex(i => i.index === index) @@ -1763,16 +1811,86 @@ export default { viewport.render() }, async saveImage() { - const divForDownloadViewport = document.querySelector( - `div[data-viewport-uid="canvas-${this.activeCanvasIndex}"]` - ) + const viewportIndex = this.viewportInfos.findIndex(v => v.index === this.activeCanvasIndex) + if (viewportIndex === -1) return + const currentViewport = this.viewportInfos[viewportIndex] + + let divForDownloadViewport = null + let tempImg = null + + if (currentViewport.fileType && currentViewport.fileType.includes('mp4')) { + divForDownloadViewport = this.$refs[`grid-cell-${this.activeCanvasIndex}`][0] + const videoEl = this.$refs[`videovideo-${this.activeCanvasIndex}`][0] + + if (videoEl) { + // 将视频帧画到 canvas 上生成图片 + const tempCanvas = document.createElement('canvas') + // 设置 canvas 尺寸为容器实际尺寸 + const containerWidth = videoEl.clientWidth + const containerHeight = videoEl.clientHeight + tempCanvas.width = containerWidth + tempCanvas.height = containerHeight + + const ctx = tempCanvas.getContext('2d') + // 填充黑色背景 + ctx.fillStyle = '#000' + ctx.fillRect(0, 0, containerWidth, containerHeight) + + // 计算视频保持比例的缩放尺寸和位置 (等同于 object-fit: contain) + const videoWidth = videoEl.videoWidth || containerWidth + const videoHeight = videoEl.videoHeight || containerHeight + + const scale = Math.min(containerWidth / videoWidth, containerHeight / videoHeight) + const drawWidth = videoWidth * scale + const drawHeight = videoHeight * scale + const offsetX = (containerWidth - drawWidth) / 2 + const offsetY = (containerHeight - drawHeight) / 2 + + // 将视频帧居中绘制 + ctx.drawImage(videoEl, offsetX, offsetY, drawWidth, drawHeight) + + const frameBase64 = tempCanvas.toDataURL('image/png') + + // 创建一个 img 标签遮盖在 video 上 + tempImg = document.createElement('img') + tempImg.src = frameBase64 + tempImg.style.position = 'absolute' + tempImg.style.top = '0' + tempImg.style.left = '0' + tempImg.style.width = '100%' + tempImg.style.height = '100%' + tempImg.style.zIndex = '99' + + const videoContainer = this.$refs[`video-content-main-${this.activeCanvasIndex}`][0] + videoContainer.style.position = 'relative' + videoContainer.appendChild(tempImg) + } + } else { + divForDownloadViewport = document.querySelector( + `div[data-viewport-uid="canvas-${this.activeCanvasIndex}"]` + ) + } + if (!divForDownloadViewport) return - const canvas = await html2canvas(divForDownloadViewport) + + // 等待 DOM 更新 + await this.$nextTick() + + const canvas = await html2canvas(divForDownloadViewport, { + useCORS: true, + backgroundColor: '#000000' // 指定截图背景为黑色 + }) + + // 截图后恢复 + if (tempImg) { + tempImg.remove() + } + const base64Str = canvas.toDataURL('image/png', 1) - const i = this.viewportInfos.findIndex(v => v.index === this.activeCanvasIndex) - const name = (i > -1 ? this.viewportInfos[i].currentFileName : '') || `screenshot-${Date.now()}` + const name = currentViewport.currentFileName || `screenshot-${Date.now()}` const safeName = String(name).replace(/[\\/:*?"<>|]/g, '_') const downloadName = safeName.toLowerCase().endsWith('.png') ? safeName : `${safeName}.png` + const a = document.createElement('a') a.href = base64Str a.download = downloadName @@ -2188,10 +2306,13 @@ export default { .grid-cell { border: 1px dashed #ccc; - ; display: flex; align-items: center; justify-content: center; + overflow: hidden; + min-width: 0; + min-height: 0; + z-index: 1; } .cell_active { @@ -2294,6 +2415,21 @@ export default { background: #9e9e9e; cursor: move } + + .content-main { + position: relative; + overflow: hidden; + background: #1e1e1e; + } + + video { + display: block; + width: 100%; + height: 100%; + object-fit: contain; + object-position: center center; + background: transparent; + } } } diff --git a/src/views/trials/trials-panel/reading/visit-review/components/StudyList.vue b/src/views/trials/trials-panel/reading/visit-review/components/StudyList.vue index 9cda8fc5..27bc7441 100644 --- a/src/views/trials/trials-panel/reading/visit-review/components/StudyList.vue +++ b/src/views/trials/trials-panel/reading/visit-review/components/StudyList.vue @@ -144,11 +144,11 @@ export default { }, // 切换文件 selectFile(study, studyIndex, fileIndex, item) { - if (item.FileType.includes('mp4')) return this.$preview({ - path: item.Path || item.FilePath, - type: 'mp4', - title: item.FileName, - }) + // if (item.FileType.includes('mp4')) return this.$preview({ + // path: item.Path || item.FilePath, + // type: 'mp4', + // title: item.FileName, + // }) this.activeStudyIndex = studyIndex this.activeFileIndex = fileIndex const fileList = study.NoneDicomStudyFileList From eda4b31ddaede0db1dc08f5e88097f0d50055d91 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Tue, 9 Jun 2026 14:57:38 +0800 Subject: [PATCH 009/159] =?UTF-8?q?DICOM=E5=88=86=E5=89=B2=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=9A=84=E4=B8=AA=E6=80=A7=E5=8C=96=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reading/dicoms3D/components/ReadPage.vue | 7 ++++++ .../dicoms3D/components/Segmentations.vue | 24 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue index 205d0398..3ab942af 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue @@ -988,6 +988,13 @@ export default { this.cols = 2 this.activeViewportIndex = 1 } + if (localStorage.getItem('SegmentConfig') && this.readingTool === 3) { + let obj = JSON.parse(localStorage.getItem('SegmentConfig')) + this.SegmentConfig.renderOutline = obj.renderOutline + this.SegmentConfig.renderFill = obj.renderFill + this.SegmentConfig.fillAlpha = obj.fillAlpha + this.SegmentConfig.outlineWidth = obj.outlineWidth + } this.$nextTick(() => { this.loadRelatedTasks() diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue index 822dcd35..61994fb3 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue @@ -137,7 +137,7 @@ {{ $t('trials:reading:Segmentations:title:InactiveSegmentationsShow') - }} + }}
- + - + + - + + - + + - + - + - + @@ -351,6 +359,7 @@ import { enrollBackOrOut, setEnrollReadingCategory, batchSetCriterionJoinJoinAnalysis, + getDoctorUserTrialReadingStat } from '@/api/trials' import { addDoctorCriterionFile } from '@/api/reviewers' import { uploadFile } from '@/api/attachment' @@ -470,6 +479,28 @@ export default { this.initPage() }, methods: { + async statistics(row, id) { + try { + let data = { + TrialId: this.$route.query.trialId, + TrialReadingCriterionId: id, + DoctoruserIdList: [row.DoctorUserId] + } + let res = await getDoctorUserTrialReadingStat(data) + if (res.IsSuccess && res.Result[0]) { + row.CriterionCategoryList.some((v) => { + if (v.TrialReadingCriterionId === id) { + v.PendingCount = res.Result[0].PendingCount + v.ComplectedCount = res.Result[0].ComplectedCount + v.TotalCount = res.Result[0].TotalCount + } + return v.TrialReadingCriterionId === id + }) + } + } catch (err) { + console.log(err) + } + }, // 预览 preview(row, TrialReadingCriterionId, key) { let file = row.CriterionCategoryList.find((v) => { From ee34e6cdc2494e3555d99ae0a9d5fe5f5f2b9603 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Tue, 9 Jun 2026 16:39:22 +0800 Subject: [PATCH 013/159] =?UTF-8?q?=E5=8F=97=E8=AF=95=E8=80=85=E9=98=85?= =?UTF-8?q?=E7=89=87=E7=BB=93=E6=9E=9C=E8=B6=8B=E5=8A=BF=E5=9B=BE=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../subject-list/components/SubjectChart.vue | 13 ++++++++++--- .../trials-panel/subject/subject-list/index.vue | 3 ++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/views/trials/trials-panel/subject/subject-list/components/SubjectChart.vue b/src/views/trials/trials-panel/subject/subject-list/components/SubjectChart.vue index f3756c28..0357f4dd 100644 --- a/src/views/trials/trials-panel/subject/subject-list/components/SubjectChart.vue +++ b/src/views/trials/trials-panel/subject/subject-list/components/SubjectChart.vue @@ -15,7 +15,7 @@ @@ -143,13 +143,15 @@ export default { this.tableKey = [ { title: this.$t(`subjectChart:table:label:visit`), - key: 'visit' + key: 'visit', + IsHighlight: false } ] Evaluation[0].forEach(key => { let obj = { title: key.Value, key: key.Value, + IsHighlight: key.IsHighlight } this.tableKey.push(obj) }) @@ -160,8 +162,8 @@ export default { if (index === 0) { obj[item.key] = 'R1' } else { - console.log(Evaluation[1][index - 1].DictionaryCode, Evaluation[1][index - 1].Value) obj[item.key] = Evaluation[1][index - 1].DictionaryCode ? this.$fd(Evaluation[1][index - 1].DictionaryCode, parseFloat(Evaluation[1][index - 1].Value)) : Evaluation[1][index - 1].Value + obj.IsHighlight = Evaluation[1][index - 1].IsHighlight } }) this.tableList.push(obj) @@ -170,6 +172,7 @@ export default { let obj = {} this.tableKey.forEach((item, index) => { obj[item.key] = index === 0 ? 'R2' : Evaluation[2][index - 1].DictionaryCode ? this.$fd(Evaluation[2][index - 1].DictionaryCode, parseFloat(Evaluation[2][index - 1].Value)) : Evaluation[2][index - 1].Value + obj.IsHighlight = index === 0 ? false : Evaluation[2][index - 1].IsHighlight }) this.tableList.push(obj) } @@ -317,6 +320,10 @@ export default { margin: auto; } +.IsHighlight { + color: red; +} + .chartBox { display: flex; diff --git a/src/views/trials/trials-panel/subject/subject-list/index.vue b/src/views/trials/trials-panel/subject/subject-list/index.vue index 5ec8e551..2c6176ee 100644 --- a/src/views/trials/trials-panel/subject/subject-list/index.vue +++ b/src/views/trials/trials-panel/subject/subject-list/index.vue @@ -141,7 +141,8 @@ :title="$t('trials:subject:title:report')" @click="handleMessage(scope.row)" /> + circle :title="$t('trials:subject:title:chart')" :disabled="!scope.row.IsHaveTaskFinished" + @click="handleopenSubjectChart(scope.row)" /> From e3be28ca17b13d94389a47a874e941621ebe0dcc Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Wed, 10 Jun 2026 10:31:35 +0800 Subject: [PATCH 014/159] =?UTF-8?q?=E9=9D=9Edicom=E9=98=85=E7=89=87?= =?UTF-8?q?=E6=88=AA=E5=9B=BE=E6=96=87=E4=BB=B6=E5=90=8D=E7=A7=B0=E6=9B=B4?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/reading.js | 9 +++++++++ .../reading/visit-review/components/FileViewer.vue | 4 +--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/api/reading.js b/src/api/reading.js index 5e6315fd..a3e01c28 100644 --- a/src/api/reading.js +++ b/src/api/reading.js @@ -447,4 +447,13 @@ export function restoreSegmentationVersion(data) { method: 'post', data }) +} + +// 获取标记信息 +export function getMarkList(data) { + return request({ + url: `/ReadingImageTask/getMarkList`, + method: 'post', + data + }) } \ No newline at end of file diff --git a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue index 61c12eb2..6b18fd18 100644 --- a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue +++ b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue @@ -1887,9 +1887,7 @@ export default { } const base64Str = canvas.toDataURL('image/png', 1) - const name = currentViewport.currentFileName || `screenshot-${Date.now()}` - const safeName = String(name).replace(/[\\/:*?"<>|]/g, '_') - const downloadName = safeName.toLowerCase().endsWith('.png') ? safeName : `${safeName}.png` + const downloadName = `screenshot_${Date.now()}.png` const a = document.createElement('a') a.href = base64Str From f7b5ab02813e783ea16c1d0e3d9479252a8e6204 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Wed, 10 Jun 2026 10:33:33 +0800 Subject: [PATCH 015/159] 1 --- .../trials-panel/reading/visit-review/components/FileViewer.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue index 6b18fd18..18c5a592 100644 --- a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue +++ b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue @@ -1887,7 +1887,7 @@ export default { } const base64Str = canvas.toDataURL('image/png', 1) - const downloadName = `screenshot_${Date.now()}.png` + const downloadName = `${Date.now()}.png` const a = document.createElement('a') a.href = base64Str From e7a13be6e4347788768d7c035c23068a74bf1ff1 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Wed, 10 Jun 2026 10:39:20 +0800 Subject: [PATCH 016/159] =?UTF-8?q?=E5=88=86=E5=89=B2=E6=A0=87=E8=AE=B0?= =?UTF-8?q?=E8=BE=B9=E6=A1=86=E8=B0=83=E8=8A=82=E5=88=BB=E5=BA=A6=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E4=B8=BA1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trials-panel/reading/dicoms3D/components/Segmentations.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue index 61994fb3..b55d7595 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/Segmentations.vue @@ -127,7 +127,7 @@
{{ $t('trials:reading:Segmentations:title:Border') }} -
From 0b87a1845cccd762152169d9c48f9f6742289922 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Wed, 10 Jun 2026 13:57:57 +0800 Subject: [PATCH 017/159] =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../setting/reading-unit/components/QuestionsForm.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/trials/trials-panel/setting/reading-unit/components/QuestionsForm.vue b/src/views/trials/trials-panel/setting/reading-unit/components/QuestionsForm.vue index a889039f..bda77edd 100644 --- a/src/views/trials/trials-panel/setting/reading-unit/components/QuestionsForm.vue +++ b/src/views/trials/trials-panel/setting/reading-unit/components/QuestionsForm.vue @@ -776,7 +776,7 @@ export default { MaxQuestionCount: null, IsCopyLesions: false, MaxAnswerLength: null, - AddDeleteTypeEnum: null, + AddDeleteTypeEnum: 0, FileType: [], DictionaryCode: null, GroupId: null, From d0d8819ab46666f6a9b49d78b8960e18d1dbd111 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Wed, 10 Jun 2026 13:58:25 +0800 Subject: [PATCH 018/159] =?UTF-8?q?=E5=85=B3=E9=94=AE=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reading/dicoms3D/components/ReadPage.vue | 212 +++++++++++++++++- 1 file changed, 207 insertions(+), 5 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue index 3ab942af..998d4f7f 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue @@ -171,6 +171,49 @@ v-if="((criterionType === 0 && readingTool === 0) || this.readingTool === 3) && isMPR"> + +
@@ -538,7 +581,7 @@ + diff --git a/src/views/system/notice/index.vue b/src/views/system/notice/index.vue index 93582b12..71072b45 100644 --- a/src/views/system/notice/index.vue +++ b/src/views/system/notice/index.vue @@ -57,14 +57,21 @@ {{ $t('common:button:add') }} - + - + - + @@ -74,46 +81,47 @@ {{ scope.row.NoticeContent }} - + - + - + - + - + - - - + - + + + + - + From 6629fc0a177be758aa5243de5d8f84c6feae08b1 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Thu, 11 Jun 2026 13:25:00 +0800 Subject: [PATCH 022/159] 1 --- src/views/trials/components/NoticeDetailDialog.vue | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/views/trials/components/NoticeDetailDialog.vue b/src/views/trials/components/NoticeDetailDialog.vue index 227fd5fb..9621b52f 100644 --- a/src/views/trials/components/NoticeDetailDialog.vue +++ b/src/views/trials/components/NoticeDetailDialog.vue @@ -28,10 +28,9 @@
- + {{ $t('common:button:close') }} Date: Thu, 11 Jun 2026 15:48:53 +0800 Subject: [PATCH 023/159] =?UTF-8?q?=E5=9B=BE=E6=A0=87=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trials-panel/reading/dicoms3D/components/ReadPage.vue | 3 ++- .../reading/visit-review/components/FileViewer.vue | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue index a028dc2d..f3008f28 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue @@ -221,7 +221,8 @@
- + +
diff --git a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue index 45598685..d1abb74e 100644 --- a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue +++ b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue @@ -77,7 +77,8 @@
- + +
From 83f73db692aebe8fcba82a2c0fa6a95dad263254 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Mon, 15 Jun 2026 09:27:41 +0800 Subject: [PATCH 024/159] =?UTF-8?q?=E4=B8=AD=E5=BF=83=E8=B0=83=E7=A0=94?= =?UTF-8?q?=E8=A1=A8=E8=AE=BE=E5=A4=87=E8=B0=83=E7=A0=94=E5=A4=87=E6=B3=A8?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E9=9D=9E=E5=BF=85=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/research/components/EquipmentForm.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/research/components/EquipmentForm.vue b/src/views/research/components/EquipmentForm.vue index 2f645ebb..16b0ced8 100644 --- a/src/views/research/components/EquipmentForm.vue +++ b/src/views/research/components/EquipmentForm.vue @@ -170,9 +170,9 @@ export default { Parameters: [ { required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'] } ], - Note: [ - { required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'] } - ], + // Note: [ + // { required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'] } + // ], ManufacturerType: [ { required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }, { From de7cd64c9b7b23cf5ab46a52f92a56565059eeb3 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Mon, 15 Jun 2026 13:53:04 +0800 Subject: [PATCH 025/159] =?UTF-8?q?=E5=85=B3=E9=94=AE=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E6=9B=B4=E6=94=B9=EF=BC=9Blugano=E6=A0=87=E5=87=86=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reading/dicoms/components/DicomViewer.vue | 218 ++++++++++++++++++ .../dicoms/components/Fusion/Questions.vue | 2 +- .../reading/dicoms/components/Questions.vue | 2 +- 3 files changed, 220 insertions(+), 2 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue index d7bdb6a0..bb042b64 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue @@ -219,6 +219,48 @@ + +
    +
  • + +
  • +
  • + {{ $t('trials:reading:keySeries:noData') }} +
  • +
  • +
    + + +
    +
    +
    +
    {{ $t('trials:reading:keySeries:annotationName') }}
    +
    + {{ kf.MarkName }} +
    +
    +
    +
    {{ $t('trials:reading:keySeries:sopUid') }}
    +
    + {{ kf.SopInstanceUid }} +
    +
    +
    +
    + +
    +
  • +
+
+
+ +
+
{{ $t('trials:reading:button:keySeries') }}
+
+
+
@@ -706,6 +748,7 @@ import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom' import SignForm from '@/views/trials/components/newSignForm' import { getCriterionReadingInfo, verifyVisitTaskQuestions, submitDicomVisitTask, setReadKeyFile } from '@/api/trials' import { setSkipReadingCache } from '@/api/reading' +import { getMarkList } from '@/api/reading' import { getAutoCutNextTask } from '@/api/user' import const_ from '@/const/sign-code' import { changeURLStatic } from '@/utils/history.js' @@ -903,6 +946,9 @@ export default { uploadTrialCriterion: {}, uploadStatus: 'upload', taskId: '', + keySeries: [], + keySeriesPopoverVisible: false, + keySeriesLoading: false, signVisible: false, signCode: null, currentUser: zzSessionStorage.getItem('userName'), @@ -1349,6 +1395,46 @@ export default { resetViewport() { this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetViewport() }, + getKeySeriesVisitTaskId() { + const currentCanvas = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`] + if (currentCanvas && currentCanvas[0] && currentCanvas[0].stack && currentCanvas[0].stack.visitTaskId) { + return currentCanvas[0].stack.visitTaskId + } + return this.activeSeries && this.activeSeries.visitTaskId ? this.activeSeries.visitTaskId : '' + }, + async showKeySeriesPanel() { + this.keySeries = [] + this.keySeriesLoading = true + const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask) + if (idx === -1) return + const visitTaskId = this.visitTaskList[idx].VisitTaskId + try { + const res = await getMarkList({ visitTaskId }) + if (res && res.Result) { + this.keySeries = res.Result + } + } catch (err) { + console.error(err) + } finally { + this.keySeriesLoading = false + } + }, + jumpToKeySeries(kf) { + this.keySeriesPopoverVisible = false + const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask) + if (idx === -1) return + const visitTaskId = this.visitTaskList[idx].VisitTaskId + if (!visitTaskId) return + let annotation = {} + try { + annotation = kf.MeasureData ? JSON.parse(kf.MeasureData) : {} + } catch (err) { + console.error(err) + } + const series = this.getSeriesInfoByMark(visitTaskId, {lesionName: kf.MarkName}) + if (!series) return + this.loadImageStack(series) + }, previewConfig() { this.activeName = '1' this.personalConfigDialog.visible = true @@ -3030,3 +3116,135 @@ export default { flex-grow: 1; } + diff --git a/src/views/trials/trials-panel/reading/dicoms/components/Fusion/Questions.vue b/src/views/trials/trials-panel/reading/dicoms/components/Fusion/Questions.vue index 9b4e9303..9fd7bc87 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/Fusion/Questions.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/Fusion/Questions.vue @@ -94,7 +94,7 @@ export default { this.resetSuvQuestions() }) FusionEvent.$on('addAnnotation', obj => { - this.$set(obj, 'SaveEnum', 1) + // this.$set(obj, 'SaveEnum', 1) this.addAnnotation(obj) }) FusionEvent.$on('removeAnnotation', obj => { diff --git a/src/views/trials/trials-panel/reading/dicoms/components/Questions.vue b/src/views/trials/trials-panel/reading/dicoms/components/Questions.vue index 2cc8b0dc..19d7fcd9 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/Questions.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/Questions.vue @@ -115,7 +115,7 @@ export default { }) if (this.groupClassify === 3) { DicomEvent.$on('addAnnotation', obj => { - this.$set(obj, 'SaveEnum', 1) + // this.$set(obj, 'SaveEnum', 1) this.addAnnotation(obj) }) DicomEvent.$on('removeAnnotation', obj => { From 05bcb982dd6aafa2c10434967ef573aba5d7e9dc Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Tue, 16 Jun 2026 13:30:41 +0800 Subject: [PATCH 026/159] =?UTF-8?q?=E5=BD=B1=E5=83=8F=E6=B1=87=E6=80=BB?= =?UTF-8?q?=E5=85=B3=E9=94=AE=E5=9B=BE=E4=B8=8B=E8=BD=BD=E5=8F=AF=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E5=88=86=E5=89=B2=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trials-panel/trial-summary/image-summary/index.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/trials/trials-panel/trial-summary/image-summary/index.vue b/src/views/trials/trials-panel/trial-summary/image-summary/index.vue index 3dce0dbf..15fc925e 100644 --- a/src/views/trials/trials-panel/trial-summary/image-summary/index.vue +++ b/src/views/trials/trials-panel/trial-summary/image-summary/index.vue @@ -70,10 +70,10 @@ @@ -286,7 +286,7 @@ export default { //项目研究方案号(评估标准)/中心ID/受试者ID/访视名/阅片人角色-裁判选择标记/文件名 name = `${this.$route.query.researchProgramNo}_${this.$t('trials:imageSummary:downloadname:keyImage')}_${Date.now()}.zip` row.forEach(item => { - ['QuestionMarkPictureList', 'TableQuestionRowPictureList', 'ReadingNoneDicomMarkPathList'].forEach(key => { + ['QuestionMarkPictureList', 'TableQuestionRowPictureList', 'ReadingNoneDicomMarkPathList', 'SegmentationFileList'].forEach(key => { if (item[key] && item[key].length > 0) { item[key].forEach(data => { ['PicturePath', 'otherPicturePath'].forEach(imgKey => { From 11c4df2852348221ce77fa5da5e0f64f2d6a3c38 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Tue, 16 Jun 2026 13:33:53 +0800 Subject: [PATCH 027/159] =?UTF-8?q?=E9=98=85=E7=89=87=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=B3=A8=E6=84=8F=E4=BA=8B=E9=A1=B9=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trials-panel/attachments/reReading-tracking/index.vue | 2 +- .../trials/trials-panel/reading/reReading-tracking/index.vue | 2 +- src/views/trials/trials-panel/reading/read-task/index.vue | 2 +- .../trials/trials-panel/reading/reading-tracking/index.vue | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/views/trials/trials-panel/attachments/reReading-tracking/index.vue b/src/views/trials/trials-panel/attachments/reReading-tracking/index.vue index 45c5e72f..7cb10aea 100644 --- a/src/views/trials/trials-panel/attachments/reReading-tracking/index.vue +++ b/src/views/trials/trials-panel/attachments/reReading-tracking/index.vue @@ -665,7 +665,7 @@ export default { async audit(row) { try { this.rowData = Object.assign({}, row) - this.rowData.title = `${row.ApplicantName} (${this.$fd('RequestReReadingType', row.RequestReReadingType)}) ${this.$t('trials:spmAudit:title:imageBack').replace('xxx', row.OriginalReReadingTask.SubjectCode).replace('yyy', row.OriginalReReadingTask.TaskName)}` + this.rowData.title = `${row.ApplicantName} (${this.$fd('RequestReReadingType', row.RequestReReadingType)}) ${this.$t('trials:spmAudit:title:imageBack').replace('xxx', row.OriginalReReadingTask.SubjectCode).replace('yyy', row.OriginalReReadingTask.TaskBlindName)}` Object.keys(this.form).forEach(key => { this.form[key] = null }) diff --git a/src/views/trials/trials-panel/reading/reReading-tracking/index.vue b/src/views/trials/trials-panel/reading/reReading-tracking/index.vue index a0eda895..8b0ee4cd 100644 --- a/src/views/trials/trials-panel/reading/reReading-tracking/index.vue +++ b/src/views/trials/trials-panel/reading/reReading-tracking/index.vue @@ -888,7 +888,7 @@ export default { async audit(row) { try { this.rowData = Object.assign({}, row) - this.rowData.title = `${row.ApplicantName} (${this.$fd('RequestReReadingType', row.RequestReReadingType)}) ${this.$t('trials:rereadTrack:title:imageBack').replace('xxx', row.OriginalReReadingTask.SubjectCode).replace('yyy', row.OriginalReReadingTask.TaskName)}` + this.rowData.title = `${row.ApplicantName} (${this.$fd('RequestReReadingType', row.RequestReReadingType)}) ${this.$t('trials:rereadTrack:title:imageBack').replace('xxx', row.OriginalReReadingTask.SubjectCode).replace('yyy', row.OriginalReReadingTask.TaskBlindName)}` Object.keys(this.form).forEach(key => { this.form[key] = null }) diff --git a/src/views/trials/trials-panel/reading/read-task/index.vue b/src/views/trials/trials-panel/reading/read-task/index.vue index 0d1f56bd..fe412eec 100644 --- a/src/views/trials/trials-panel/reading/read-task/index.vue +++ b/src/views/trials/trials-panel/reading/read-task/index.vue @@ -177,7 +177,7 @@ custom-class="base-dialog-wrapper"> -

{{ $t('trials:readTask:applyReread:title').replace('xxx', rowData.SubjectCode).replace('yyy', rowData.TaskName) }}

+

{{ $t('trials:readTask:applyReread:title').replace('xxx', rowData.SubjectCode).replace('yyy', rowData.TaskBlindName) }}

{{ $t('trials:readTask:title:applyReason') }} diff --git a/src/views/trials/trials-panel/reading/reading-tracking/index.vue b/src/views/trials/trials-panel/reading/reading-tracking/index.vue index b4ca06ac..4693abb9 100644 --- a/src/views/trials/trials-panel/reading/reading-tracking/index.vue +++ b/src/views/trials/trials-panel/reading/reading-tracking/index.vue @@ -460,7 +460,7 @@ custom-class="base-dialog-wrapper"> -

{{ $t('trials:reviewTrack:applyReread:title2').replace('xxx', rowData.SubjectCode).replace('yyy', rowData.TaskName) }}

+

{{ $t('trials:reviewTrack:applyReread:title2').replace('xxx', rowData.SubjectCode).replace('yyy', rowData.TaskBlindName) }}

{{ $t('trials:reviewTrack:applyReread:title:applyReason') }} @@ -625,7 +625,7 @@ custom-class="base-dialog-wrapper"> -

{{ $t('trials:reviewTrack:applyReread:title1').replace('xxx', rowData.SubjectCode).replace('yyy', rowData.TaskName) }}

+

{{ $t('trials:reviewTrack:applyReread:title1').replace('xxx', rowData.SubjectCode).replace('yyy', rowData.TaskBlindName) }}

{{ $t('trials:reviewTrack:applyReread:title:backReason') }} From 212a545aa995d1fdc43a1af06cc08cca5d656954 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Tue, 16 Jun 2026 13:45:00 +0800 Subject: [PATCH 028/159] =?UTF-8?q?=E6=BC=94=E7=A4=BA=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E6=B7=BB=E5=8A=A0=E8=99=9A=E6=8B=9F=E9=98=85?= =?UTF-8?q?=E7=89=87=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../attachments/enrollment/components/Selection.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/trials/trials-panel/attachments/enrollment/components/Selection.vue b/src/views/trials/trials-panel/attachments/enrollment/components/Selection.vue index 467e0d46..17519d1c 100644 --- a/src/views/trials/trials-panel/attachments/enrollment/components/Selection.vue +++ b/src/views/trials/trials-panel/attachments/enrollment/components/Selection.vue @@ -482,7 +482,7 @@ export default { } }, handleSelectTable(row) { - return row.DoctorTrialState !== 1 && row.ResumeStatus === 1 && row.AcceptingNewTrial && !row.IsVirtual && !row.IsVacation && row.CooperateStatus === 1 + return row.DoctorTrialState !== 1 && row.ResumeStatus === 1 && row.AcceptingNewTrial && ((!row.IsVirtual && this.$store.state.trials.config.TrialType === 0) || (row.IsVirtual && this.$store.state.trials.config.TrialType !== 0)) && !row.IsVacation && row.CooperateStatus === 1 }, handleDetail(row) { const { href } = this.$router.resolve({ From a4241bccf7a553188aad655a10866c480f3643e1 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Tue, 16 Jun 2026 14:22:17 +0800 Subject: [PATCH 029/159] =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=AD=97=E5=85=B8?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=BB=9F=E4=B8=80=E6=B7=BB=E5=8A=A0trialId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/request.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/utils/request.js b/src/utils/request.js index c16dc0a4..54c252d2 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -21,6 +21,16 @@ var path service.interceptors.request.use( async config => { + if (config.url.includes("/Dictionary/getBasicDataSelect")) { + let query = router && router.app && router.app._route && router.app._route.query + if (query.trialId) { + let str = config.url.split("?") + config.url = `${str[0]}?TrialId=${query.trialId}` + if (str[1]) { + config.url += `&${str[1]}` + } + } + } path = router && router.app && router.app._route && router.app._route.path config.headers['Content-Type'] = 'application/json;charset=UTF-8' // config.baseURL = process.env.NODE_ENV === 'prod' ? "https://api.irc.extimaging.com" : '/api' From b7d45456a677e2412b2cab1ee093ff2f3226054e Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Tue, 16 Jun 2026 14:23:22 +0800 Subject: [PATCH 030/159] =?UTF-8?q?=E6=BC=94=E7=A4=BA=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E6=B7=BB=E5=8A=A0=E8=99=9A=E6=8B=9F=E9=98=85?= =?UTF-8?q?=E7=89=87=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../attachments/enrollment/components/Selection.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/trials/trials-panel/attachments/enrollment/components/Selection.vue b/src/views/trials/trials-panel/attachments/enrollment/components/Selection.vue index 17519d1c..fdbb6b0e 100644 --- a/src/views/trials/trials-panel/attachments/enrollment/components/Selection.vue +++ b/src/views/trials/trials-panel/attachments/enrollment/components/Selection.vue @@ -482,7 +482,7 @@ export default { } }, handleSelectTable(row) { - return row.DoctorTrialState !== 1 && row.ResumeStatus === 1 && row.AcceptingNewTrial && ((!row.IsVirtual && this.$store.state.trials.config.TrialType === 0) || (row.IsVirtual && this.$store.state.trials.config.TrialType !== 0)) && !row.IsVacation && row.CooperateStatus === 1 + return row.DoctorTrialState !== 1 && row.ResumeStatus === 1 && row.AcceptingNewTrial && ((!row.IsVirtual && this.$store.state.trials.config.TrialType !== 0) || (row.IsVirtual && this.$store.state.trials.config.TrialType === 0)) && !row.IsVacation && row.CooperateStatus === 1 }, handleDetail(row) { const { href } = this.$router.resolve({ From 8b766672b5246d26e73cc533d5e51c07326fc511 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Tue, 16 Jun 2026 17:16:07 +0800 Subject: [PATCH 031/159] =?UTF-8?q?=E4=B8=AD=E5=BF=83=E8=B0=83=E7=A0=94?= =?UTF-8?q?=E8=A1=A8=E9=80=89=E6=8B=A9=E4=B8=AD=E5=BF=83=E6=97=B6=E5=8F=AF?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=A6=81=E7=94=A8=E4=B8=AD=E5=BF=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/trials.js | 5 +++-- src/views/research/components/BaseInfo.vue | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/api/trials.js b/src/api/trials.js index 82aa97ba..62f80680 100644 --- a/src/api/trials.js +++ b/src/api/trials.js @@ -357,10 +357,11 @@ export function getSubjectList(param) { }) } -export function getTrialSiteSelect(trialId) { +export function getTrialSiteSelect(trialId, params) { return request({ url: `/trialMaintenance/getTrialSiteSelect/${trialId}`, - method: 'get' + method: 'get', + params }) } diff --git a/src/views/research/components/BaseInfo.vue b/src/views/research/components/BaseInfo.vue index 0624c28f..4b896f15 100644 --- a/src/views/research/components/BaseInfo.vue +++ b/src/views/research/components/BaseInfo.vue @@ -366,7 +366,7 @@ export default { // 初始化 async initForm(trialInfo, trialSiteSurvey, notShowFieldList) { // 获取项目下的site - const { Result } = await getTrialSiteSelect(this.$route.query.trialId) + const { Result } = await getTrialSiteSelect(this.$route.query.trialId, { IgnoreDisable: true }) this.siteOptions = Result this.form.Id = trialSiteSurvey.Id this.form.Sponsor = trialInfo.Sponsor // 申办方 From b241682fa9fb99d940cfdc7e8c20279037b8e962 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Wed, 17 Jun 2026 13:31:00 +0800 Subject: [PATCH 032/159] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=AE=9A=E5=9C=86?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E6=A0=87=E6=B3=A8=E5=A4=8D=E5=88=B6=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dicoms3D/components/PetCtViewport.vue | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/PetCtViewport.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/PetCtViewport.vue index 1f77aabc..527d9103 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/PetCtViewport.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/PetCtViewport.vue @@ -302,36 +302,46 @@ export default { y: Math.min(Math.max(e.clientY - rect.top, padding), maxY), } }, + getInstanceInfo(imageId) { + const params = {} + if (imageId) { + const searchParams = new URLSearchParams(imageId.split('?')[1]) + for (const [key, value] of searchParams.entries()) { + params[key] = value + } + if (isNaN(params.frame)) { + params.frame = null + } + } + return params + }, getCircleAnnotationFromContextMenuEvent(e) { const viewport = this.getViewportInstance() if (!viewport || !this.element) return null const rect = this.element.getBoundingClientRect() const canvasPoint = [e.clientX - rect.left, e.clientY - rect.top] - const currentVisitTaskId = this.series?.TaskInfo?.VisitTaskId - const toolNames = ['CircleROI'] //FixedRadiusCircleROI看后期是不是要补充 - const candidates = [] - - toolNames.forEach((toolName) => { + const currentImageId = viewport.getCurrentImageId?.() + const currentInstanceId = this.getInstanceInfo(currentImageId).instanceId + const toolNames = ['CircleROI', 'FixedRadiusCircleROI'] + for (const toolName of toolNames) { const annotations = cornerstoneTools.annotation.state.getAnnotations(toolName, this.element) || [] - annotations.forEach((annotation) => { - if (!annotation?.data?.handles?.points?.length) return - if (currentVisitTaskId && annotation.visitTaskId && annotation.visitTaskId !== currentVisitTaskId) return + const selectedAnnotation = annotations.find((annotation) => { + if (!annotation?.highlighted) return false + if (!annotation?.data?.handles?.points?.length) return false + const annotationInstanceId = annotation.instanceId || this.getInstanceInfo(annotation.metadata?.referencedImageId).instanceId + if (currentInstanceId && annotationInstanceId && annotationInstanceId !== currentInstanceId) return false const hitInfo = this.getCircleAnnotationHitInfo(annotation, canvasPoint, viewport) - if (!hitInfo.hit || hitInfo.score === null) return - - candidates.push({ - annotation, - score: hitInfo.score, - }) + return hitInfo.hit }) - }) - if (!candidates.length) return null + if (selectedAnnotation) { + return selectedAnnotation + } + } - candidates.sort((a, b) => a.score - b.score) - return candidates[0].annotation + return null }, getCircleAnnotationHitInfo(annotation, canvasPoint, viewport) { const points = annotation?.data?.handles?.points || [] From 4d16ebb48888b3aa22a65d49cfa7fffb0a4e3ad9 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Wed, 17 Jun 2026 16:44:37 +0800 Subject: [PATCH 033/159] =?UTF-8?q?=E5=8F=97=E8=AF=95=E8=80=85=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=8F=98=E6=9B=B4=E8=A1=A8=E5=8D=95=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../subject/subject-list/components/SubjectStatusForm.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/views/trials/trials-panel/subject/subject-list/components/SubjectStatusForm.vue b/src/views/trials/trials-panel/subject/subject-list/components/SubjectStatusForm.vue index 81944f94..691d5337 100644 --- a/src/views/trials/trials-panel/subject/subject-list/components/SubjectStatusForm.vue +++ b/src/views/trials/trials-panel/subject/subject-list/components/SubjectStatusForm.vue @@ -3,7 +3,7 @@
- + {{ item.label }} @@ -115,6 +115,10 @@ export default { this.form.TrialId = this.trialId this.form.TrialSiteId = this.data.TrialSiteId + if (this.form.Status !== 2) { + this.form.VisitOverTime = '' + this.form.FinalSubjectVisitId = '' + } updateSubjectStatus(this.form).then(res => { this.btnLoading = false this.$emit('getList') From 8203b3d738ef5e2cfc20fb5b765247d6d557ade5 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Thu, 18 Jun 2026 09:58:04 +0800 Subject: [PATCH 034/159] =?UTF-8?q?=E5=85=B3=E9=94=AE=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reading/dicoms/components/DicomViewer.vue | 21 +++++----- .../reading/dicoms3D/components/ReadPage.vue | 20 ++++++---- .../visit-review/components/FileViewer.vue | 40 +++++++++++++++++-- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue index bb042b64..c5ac4c6b 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue @@ -1404,10 +1404,9 @@ export default { }, async showKeySeriesPanel() { this.keySeries = [] + const visitTaskId = this.getKeySeriesVisitTaskId() + if (!visitTaskId) return this.keySeriesLoading = true - const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask) - if (idx === -1) return - const visitTaskId = this.visitTaskList[idx].VisitTaskId try { const res = await getMarkList({ visitTaskId }) if (res && res.Result) { @@ -1421,16 +1420,14 @@ export default { }, jumpToKeySeries(kf) { this.keySeriesPopoverVisible = false - const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask) - if (idx === -1) return - const visitTaskId = this.visitTaskList[idx].VisitTaskId + const visitTaskId = this.getKeySeriesVisitTaskId() if (!visitTaskId) return - let annotation = {} - try { - annotation = kf.MeasureData ? JSON.parse(kf.MeasureData) : {} - } catch (err) { - console.error(err) - } + // let annotation = {} + // try { + // annotation = kf.MeasureData ? JSON.parse(kf.MeasureData) : {} + // } catch (err) { + // console.error(err) + // } const series = this.getSeriesInfoByMark(visitTaskId, {lesionName: kf.MarkName}) if (!series) return this.loadImageStack(series) diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue index f3008f28..c48e33cf 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue @@ -4298,11 +4298,14 @@ export default { async showKeySeriesPanel() { this.keySeries = [] this.keySeriesLoading = true - try { - let res = await getMarkList({ visitTaskId: this.taskInfo.VisitTaskId }) - if (res && res.Result) { - this.keySeries = res.Result + const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series + const visitTaskId = series?.TaskInfo?.VisitTaskId + if (visitTaskId) { + let res = await getMarkList({ visitTaskId: visitTaskId }) + if (res && res.Result) { + this.keySeries = res.Result + } } } catch (err) { console.error(err) @@ -4311,16 +4314,19 @@ export default { } }, jumpToKeySeries(kf) { - let tIdx = this.visitTaskList.findIndex(i=> i.VisitTaskId === this.taskInfo.VisitTaskId) + const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series + const visitTaskId = series?.TaskInfo?.VisitTaskId + if (!visitTaskId) return + let tIdx = this.visitTaskList.findIndex(i=> i.VisitTaskId === visitTaskId) if (tIdx < 0) return const task = this.visitTaskList[tIdx] const studyList = task.StudyList const annotation = kf.MeasureData ? JSON.parse(kf.MeasureData) : {} let targetSeries = this.getMarkedSeries(studyList, annotation, true) if (Object.keys(targetSeries).length === 0) return - this.activeTaskId = this.taskInfo.VisitTaskId + // this.activeTaskId = this.taskInfo.VisitTaskId this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(targetSeries, true) - this.$refs[this.taskInfo.VisitTaskId][0].setSeriesActive(targetSeries.StudyIndex, targetSeries.SeriesIndex) + this.$refs[visitTaskId][0].setSeriesActive(targetSeries.StudyIndex, targetSeries.SeriesIndex) }, showPanel(e, toolName) { if (toolName === 'layout' && (this.isFusion || this.isMPR)) return false diff --git a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue index d1abb74e..f83cc090 100644 --- a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue +++ b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue @@ -424,6 +424,30 @@ const { BidirectionalTool, // cursors } = cornerstoneTools +const newStyles = { + global: { + color: 'rgb(255, 0, 0)', + colorHighlighted: 'rgb(0, 255, 0)', + colorSelected: 'rgb(255, 0, 0)', + colorLocked: 'rgb(255, 0, 0)', + lineWidth: '1', + lineDash: '', + shadow: true, + textBoxVisibility: true, + textBoxFontFamily: 'Helvetica Neue, Helvetica, Arial, sans-serif', + textBoxFontSize: '14px', + textBoxColor: 'rgb(255, 0, 0)', + textBoxColorHighlighted: 'rgb(0, 255, 0)', + textBoxColorSelected: 'rgb(255, 0, 0)', + textBoxColorLocked: 'rgb(255, 0, 0)', + textBoxBackground: '', + textBoxLinkLineWidth: '1', + textBoxLinkLineDash: '2,3', + textBoxShadow: true, + markerSize: '10' + } +} +cornerstoneTools.annotation.config.style.setDefaultToolStyles(newStyles) const { MouseBindings, Events: toolsEvents } = csToolsEnums export default { name: 'ImageViewer', @@ -667,10 +691,15 @@ export default { this.keySeriesLoading = true try { - const res = await getNoneDicomMarkList({ visitTaskId: this.taskInfo.VisitTaskId }) - if (res && res.Result) { - this.keySeries = res.Result + const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex) + if (i > -1) { + const visitTaskId = this.viewportInfos[i].taskInfo.VisitTaskId + const res = await getNoneDicomMarkList({ visitTaskId: visitTaskId }) + if (res && res.Result) { + this.keySeries = res.Result + } } + } catch (err) { console.log(err) } finally { @@ -678,10 +707,13 @@ export default { } }, jumpToKeySeries(kf) { + const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex) + if (i === -1) return + const visitTaskId = this.viewportInfos[i].taskInfo.VisitTaskId this.$emit('selectFile', { path: kf.Path, studyId: kf.StudyId, - visitTaskId: this.taskInfo.VisitTaskId + visitTaskId: visitTaskId }) }, // 初始化加载器 From 2794cabdc8257ccfb79ea63809f68cde37770a99 Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Thu, 18 Jun 2026 11:28:50 +0800 Subject: [PATCH 035/159] =?UTF-8?q?=E5=85=B3=E9=94=AE=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E5=B1=95=E7=A4=BA=E4=BF=A1=E6=81=AF=E8=A1=A5?= =?UTF-8?q?=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reading/dicoms/components/DicomViewer.vue | 91 +++++++++++++++--- .../reading/dicoms3D/components/ReadPage.vue | 93 +++++++++++++++---- .../visit-review/components/FileViewer.vue | 93 +++++++++++++++---- 3 files changed, 226 insertions(+), 51 deletions(-) diff --git a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue index c5ac4c6b..c093f444 100644 --- a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue +++ b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue @@ -222,6 +222,16 @@
    +
  • +
    +
    + +
    + {{ keyStack.taskBlindName }} +
    +
    +
    +
  • @@ -237,13 +247,13 @@
    {{ $t('trials:reading:keySeries:annotationName') }}
    -
    +
    {{ kf.MarkName }}
    {{ $t('trials:reading:keySeries:sopUid') }}
    -
    +
    {{ kf.SopInstanceUid }}
    @@ -947,6 +957,7 @@ export default { uploadStatus: 'upload', taskId: '', keySeries: [], + keyStack: null, keySeriesPopoverVisible: false, keySeriesLoading: false, signVisible: false, @@ -1404,7 +1415,9 @@ export default { }, async showKeySeriesPanel() { this.keySeries = [] - const visitTaskId = this.getKeySeriesVisitTaskId() + const currentCanvas = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`] + this.keyStack = currentCanvas && currentCanvas[0] ? currentCanvas[0].stack : null + const visitTaskId = this.keyStack?.visitTaskId if (!visitTaskId) return this.keySeriesLoading = true try { @@ -1420,7 +1433,7 @@ export default { }, jumpToKeySeries(kf) { this.keySeriesPopoverVisible = false - const visitTaskId = this.getKeySeriesVisitTaskId() + const visitTaskId = this.keyStack?.visitTaskId if (!visitTaskId) return // let annotation = {} // try { @@ -3141,6 +3154,45 @@ export default { } } + .key-series-header { + padding: 5px 12px; + margin-bottom: 10px; + background: linear-gradient(180deg, rgba(64, 64, 64, 0.92) 0%, rgba(43, 43, 43, 0.98) 100%); + border: 1px solid #474747; + border-radius: 6px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 6px 18px rgba(0, 0, 0, 0.2); + } + + .key-series-header-top { + display: flex; + align-items: center; + justify-content: space-between; + } + + .key-series-header-title { + display: flex; + align-items: center; + min-width: 0; + } + + .key-series-header-dot { + width: 8px; + height: 8px; + margin-right: 8px; + border-radius: 50%; + background: linear-gradient(180deg, #ffd76a 0%, #f39c12 100%); + box-shadow: 0 0 8px rgba(243, 156, 18, 0.45); + } + + .key-series-task-name { + color: #fff; + font-size: 15px; + font-weight: 600; + line-height: 22px; + word-break: break-all; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + } + .key-series-empty { text-align: center; color: #999; @@ -3151,21 +3203,24 @@ export default { text-align: left; display: flex; align-items: center; - padding: 8px; + padding: 10px; cursor: pointer; - background-color: #2b2b2b; - border-radius: 4px; + background: linear-gradient(180deg, rgba(46, 46, 46, 0.96) 0%, rgba(40, 40, 40, 0.98) 100%); + border-radius: 6px; margin-bottom: 8px; - border: 1px solid transparent; - transition: all 0.2s ease; + border: 1px solid #353535; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12); + // transition: all 0.2s ease; &:last-child { margin-bottom: 0; } &:hover { - background-color: #363636; - border-color: #555; + background: linear-gradient(180deg, rgba(54, 54, 54, 0.98) 0%, rgba(46, 46, 46, 1) 100%); + border-color: #5a5a5a; + // transform: translateY(-1px); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18); } .key-series-img { @@ -3178,7 +3233,8 @@ export default { align-items: center; overflow: hidden; margin-right: 12px; - border-radius: 2px; + border-radius: 4px; + border: 1px solid #3a3a3a; img { width: 100%; @@ -3221,12 +3277,12 @@ export default { white-space: nowrap; } - .key-series-value { + .key-series-uid { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; - color: #ccc; + color: #ddd; line-height: 1.2; } } @@ -3236,10 +3292,15 @@ export default { display: flex; align-items: center; justify-content: center; + width: 28px; + height: 28px; + border-radius: 50%; + background: rgba(243, 156, 18, 0.08); + border: 1px solid rgba(243, 156, 18, 0.16); .svg-icon { color: #f39c12; - font-size: 18px; + font-size: 16px; } } } diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue index c48e33cf..6713942e 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue @@ -181,6 +181,16 @@ @show="showKeySeriesPanel" >
      +
    • +
      +
      + +
      + {{ keyTaskInfo.TaskBlindName }} +
      +
      +
      +
    • @@ -765,6 +775,7 @@ export default { fullScreenIndex: null, activeViewportIndex: 0, keySeries: [], + keyTaskInfo: null, keySeriesPopoverVisible: false, keySeriesLoading: false, activeTool: '', @@ -4300,9 +4311,9 @@ export default { this.keySeriesLoading = true try { const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series - const visitTaskId = series?.TaskInfo?.VisitTaskId - if (visitTaskId) { - let res = await getMarkList({ visitTaskId: visitTaskId }) + this.keyTaskInfo = series ? series.TaskInfo : null + if (this.keyTaskInfo) { + let res = await getMarkList({ visitTaskId: this.keyTaskInfo.VisitTaskId }) if (res && res.Result) { this.keySeries = res.Result } @@ -4314,10 +4325,8 @@ export default { } }, jumpToKeySeries(kf) { - const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series - const visitTaskId = series?.TaskInfo?.VisitTaskId - if (!visitTaskId) return - let tIdx = this.visitTaskList.findIndex(i=> i.VisitTaskId === visitTaskId) + + let tIdx = this.visitTaskList.findIndex(i=> i.VisitTaskId === this.keyTaskInfo.VisitTaskId) if (tIdx < 0) return const task = this.visitTaskList[tIdx] const studyList = task.StudyList @@ -4326,7 +4335,7 @@ export default { if (Object.keys(targetSeries).length === 0) return // this.activeTaskId = this.taskInfo.VisitTaskId this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(targetSeries, true) - this.$refs[visitTaskId][0].setSeriesActive(targetSeries.StudyIndex, targetSeries.SeriesIndex) + this.$refs[this.keyTaskInfo.VisitTaskId][0].setSeriesActive(targetSeries.StudyIndex, targetSeries.SeriesIndex) }, showPanel(e, toolName) { if (toolName === 'layout' && (this.isFusion || this.isMPR)) return false @@ -5374,6 +5383,45 @@ export default { } } + .key-series-header { + padding: 5px 12px; + margin-bottom: 10px; + background: linear-gradient(180deg, rgba(64, 64, 64, 0.92) 0%, rgba(43, 43, 43, 0.98) 100%); + border: 1px solid #474747; + border-radius: 6px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 6px 18px rgba(0, 0, 0, 0.2); + } + + .key-series-header-top { + display: flex; + align-items: center; + justify-content: space-between; + } + + .key-series-header-title { + display: flex; + align-items: center; + min-width: 0; + } + + .key-series-header-dot { + width: 8px; + height: 8px; + margin-right: 8px; + border-radius: 50%; + background: linear-gradient(180deg, #ffd76a 0%, #f39c12 100%); + box-shadow: 0 0 8px rgba(243, 156, 18, 0.45); + } + + .key-series-task-name { + color: #fff; + font-size: 15px; + font-weight: 600; + line-height: 22px; + word-break: break-all; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + } + .key-series-empty { text-align: center; color: #999; @@ -5384,21 +5432,24 @@ export default { text-align: left; display: flex; align-items: center; - padding: 8px; + padding: 10px; cursor: pointer; - background-color: #2b2b2b; - border-radius: 4px; + background: linear-gradient(180deg, rgba(46, 46, 46, 0.96) 0%, rgba(40, 40, 40, 0.98) 100%); + border-radius: 6px; margin-bottom: 8px; - border: 1px solid transparent; - transition: all 0.2s ease; + border: 1px solid #353535; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12); + // transition: all 0.2s ease; &:last-child { margin-bottom: 0; } &:hover { - background-color: #363636; - border-color: #555; + background: linear-gradient(180deg, rgba(54, 54, 54, 0.98) 0%, rgba(46, 46, 46, 1) 100%); + border-color: #5a5a5a; + // transform: translateY(-1px); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18); } .key-series-img { @@ -5411,7 +5462,8 @@ export default { align-items: center; overflow: hidden; margin-right: 12px; - border-radius: 2px; + border-radius: 4px; + border: 1px solid #3a3a3a; img { width: 100%; @@ -5459,7 +5511,7 @@ export default { text-overflow: ellipsis; white-space: nowrap; font-size: 13px; - color: #ccc; + color: #ddd; line-height: 1.2; } } @@ -5469,10 +5521,15 @@ export default { display: flex; align-items: center; justify-content: center; + width: 28px; + height: 28px; + border-radius: 50%; + background: rgba(243, 156, 18, 0.08); + border: 1px solid rgba(243, 156, 18, 0.16); .svg-icon { color: #f39c12; - font-size: 18px; + font-size: 16px; } } } diff --git a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue index f83cc090..43baf5c3 100644 --- a/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue +++ b/src/views/trials/trials-panel/reading/visit-review/components/FileViewer.vue @@ -40,6 +40,16 @@ @show="showKeySeriesPanel" >
        +
      • +
        +
        + +
        + {{ keyTaskInfo.TaskBlindName }} +
        +
        +
        +
      • @@ -59,14 +69,14 @@
        {{ $t('trials:reading:keySeries:annotationName') }}
        -
        +
        {{ kf.MarkName }}
        {{ $t('trials:reading:keySeries:fileName') }}
        -
        - {{ kf.FileName || '-' }} +
        + {{ kf.FileName }}
        @@ -537,6 +547,7 @@ export default { hotKeyList: [], isShowAnnotations: true, keySeries: [], + keyTaskInfo: null, keySeriesLoading: false, keySeriesPopoverVisible: false } @@ -693,13 +704,13 @@ export default { try { const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex) if (i > -1) { + this.keyTaskInfo = this.viewportInfos[i].taskInfo const visitTaskId = this.viewportInfos[i].taskInfo.VisitTaskId const res = await getNoneDicomMarkList({ visitTaskId: visitTaskId }) if (res && res.Result) { this.keySeries = res.Result } } - } catch (err) { console.log(err) } finally { @@ -707,9 +718,7 @@ export default { } }, jumpToKeySeries(kf) { - const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex) - if (i === -1) return - const visitTaskId = this.viewportInfos[i].taskInfo.VisitTaskId + const visitTaskId = this.keyTaskInfo.VisitTaskId this.$emit('selectFile', { path: kf.Path, studyId: kf.StudyId, @@ -2607,6 +2616,45 @@ export default { } } + .key-series-header { + padding: 5px 12px; + margin-bottom: 10px; + background: linear-gradient(180deg, rgba(64, 64, 64, 0.92) 0%, rgba(43, 43, 43, 0.98) 100%); + border: 1px solid #474747; + border-radius: 6px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 6px 18px rgba(0, 0, 0, 0.2); + } + + .key-series-header-top { + display: flex; + align-items: center; + justify-content: space-between; + } + + .key-series-header-title { + display: flex; + align-items: center; + min-width: 0; + } + + .key-series-header-dot { + width: 8px; + height: 8px; + margin-right: 8px; + border-radius: 50%; + background: linear-gradient(180deg, #ffd76a 0%, #f39c12 100%); + box-shadow: 0 0 8px rgba(243, 156, 18, 0.45); + } + + .key-series-task-name { + color: #fff; + font-size: 15px; + font-weight: 600; + line-height: 22px; + word-break: break-all; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + } + .key-series-empty { text-align: center; color: #999; @@ -2617,21 +2665,24 @@ export default { text-align: left; display: flex; align-items: center; - padding: 8px; + padding: 10px; cursor: pointer; - background-color: #2b2b2b; - border-radius: 4px; + background: linear-gradient(180deg, rgba(46, 46, 46, 0.96) 0%, rgba(40, 40, 40, 0.98) 100%); + border-radius: 6px; margin-bottom: 8px; - border: 1px solid transparent; - transition: all 0.2s ease; + border: 1px solid #353535; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12); + // transition: all 0.2s ease; &:last-child { margin-bottom: 0; } &:hover { - background-color: #363636; - border-color: #555; + background: linear-gradient(180deg, rgba(54, 54, 54, 0.98) 0%, rgba(46, 46, 46, 1) 100%); + border-color: #5a5a5a; + // transform: translateY(-1px); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18); } .key-series-img { @@ -2644,7 +2695,8 @@ export default { align-items: center; overflow: hidden; margin-right: 12px; - border-radius: 2px; + border-radius: 4px; + border: 1px solid #3a3a3a; img { width: 100%; @@ -2687,12 +2739,12 @@ export default { white-space: nowrap; } - .key-series-value { + .key-series-uid { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; - color: #ccc; + color: #ddd; line-height: 1.2; } } @@ -2702,10 +2754,15 @@ export default { display: flex; align-items: center; justify-content: center; + width: 28px; + height: 28px; + border-radius: 50%; + background: rgba(243, 156, 18, 0.08); + border: 1px solid rgba(243, 156, 18, 0.16); .svg-icon { color: #f39c12; - font-size: 18px; + font-size: 16px; } } } From 0631af4d9b0c2bf5d313c89b9ecb4b918d3a72bc Mon Sep 17 00:00:00 2001 From: caiyiling <1321909229@qq.com> Date: Thu, 18 Jun 2026 12:34:39 +0800 Subject: [PATCH 036/159] =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=88=87=E6=8D=A2bug?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trials-panel/reading/dicoms3D/components/Viewport.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/Viewport.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/Viewport.vue index dd0e6753..c84d2d5b 100644 --- a/src/views/trials/trials-panel/reading/dicoms3D/components/Viewport.vue +++ b/src/views/trials/trials-panel/reading/dicoms3D/components/Viewport.vue @@ -405,7 +405,8 @@ export default { obj.SliceIndex = this.series.SliceIndex } // if (isLocate && obj.SliceIndex === this.series.SliceIndex) return - if (this.series?.Stack && obj.Stack[obj.SliceIndex] === this.series.Stack[this.series.SliceIndex]) return + const isSameSeries = this.series && obj.Id === this.series.Id && obj.Description === this.series.Description + if (isSameSeries && this.series?.Stack && obj.Stack[obj.SliceIndex] === this.series.Stack[this.series.SliceIndex]) return this.toggleClipPlay(false) this.series = { ...obj } const renderingEngine = getRenderingEngine(this.renderingEngineId) From 97411b7eafdbd9df0854e04ba013db24f530fc01 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Thu, 18 Jun 2026 13:31:20 +0800 Subject: [PATCH 037/159] =?UTF-8?q?=E4=B8=AD=E5=BF=83=E8=B0=83=E7=A0=94?= =?UTF-8?q?=E4=BA=8C=E7=BB=B4=E7=A0=81=E5=92=8C=E9=93=BE=E6=8E=A5=E7=9A=84?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E6=9C=89=E6=95=88=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/trials.js | 32 ++ src/views/research/login.vue | 132 ++++++-- .../attachments/site-research/index.vue | 283 ++++++++++++++---- 3 files changed, 362 insertions(+), 85 deletions(-) diff --git a/src/api/trials.js b/src/api/trials.js index 709d4441..7699db50 100644 --- a/src/api/trials.js +++ b/src/api/trials.js @@ -4482,4 +4482,36 @@ export function getDoctorUserTrialReadingStat(data) { method: 'post', data, }) +} +// 设置项目链接过期时间 +export function setTrialLinkExpirationTime(data) { + return request({ + url: `/TrialConfig/setTrialLinkExpirationTime`, + method: 'post', + data, + }) +} +// 获取项目链接过期时间 +export function getTrialLinkExpirationTime(data) { + return request({ + url: `/TrialConfig/getTrialLinkExpirationTime`, + method: 'post', + data, + }) +} +// 获取项目链接时间是否过期 +export function getLinkLinkExpirationTime(data) { + return request({ + url: `/TrialConfig/getLinkLinkExpirationTime`, + method: 'post', + data, + }) +} +// 获取项目链接code是否有效 +export function getLinkVerificationCodeIsEffective(data) { + return request({ + url: `/TrialConfig/getLinkVerificationCodeIsEffective`, + method: 'post', + data, + }) } \ No newline at end of file diff --git a/src/views/research/login.vue b/src/views/research/login.vue index 6c2352af..e368eeb8 100644 --- a/src/views/research/login.vue +++ b/src/views/research/login.vue @@ -1,6 +1,7 @@