57 Commits

Author SHA1 Message Date
wangxiaoshuang 474c0dca70 医学审核问题配置查询条件可清除
continuous-integration/drone/push Build encountered an error
2025-08-13 14:35:29 +08:00
wangxiaoshuang a7806d07bb 自定义标准(旧)报告数值问题默认值修改
continuous-integration/drone/push Build is passing
2025-08-12 17:55:37 +08:00
wangxiaoshuang f6e87596ee 1
continuous-integration/drone/push Build is passing
2025-08-12 17:18:55 +08:00
wangxiaoshuang d1448d4cc6 质控下载工具
continuous-integration/drone/push Build is passing
2025-08-12 14:44:52 +08:00
wangxiaoshuang bf985bcbc8 添加工具文件上传
continuous-integration/drone/push Build is passing
2025-08-12 14:26:22 +08:00
wangxiaoshuang 70db0d9258 简历部分信息修改
continuous-integration/drone/push Build is passing
2025-08-12 09:47:45 +08:00
wangxiaoshuang 8f1ab432b2 自定义表格问题数值下拉框自动计算修改
continuous-integration/drone/push Build is passing
2025-08-12 09:20:53 +08:00
wangxiaoshuang 3f0573eeb3 简历日期添加修改
continuous-integration/drone/push Build is passing
2025-08-11 16:59:53 +08:00
wangxiaoshuang 2ed051e25b 下载文件转换
continuous-integration/drone/push Build is passing
2025-08-11 16:06:48 +08:00
wangxiaoshuang dde53103f9 自定义提示信息修改
continuous-integration/drone/push Build is passing
2025-08-11 15:50:37 +08:00
wangxiaoshuang 042a5fe59b 表单必填项校验修改
continuous-integration/drone/push Build is passing
2025-08-11 15:37:09 +08:00
wangxiaoshuang 8dda50f78e 影像汇总dicom下载路径修改
continuous-integration/drone/push Build is passing
2025-08-11 13:46:40 +08:00
wangxiaoshuang 7c06c94177 1
continuous-integration/drone/push Build is passing
2025-08-08 17:34:56 +08:00
wangxiaoshuang 42652cd9ee 后处理下载处理
continuous-integration/drone/push Build is passing
2025-08-08 17:30:20 +08:00
wangxiaoshuang 2370c25ed7 质控下载修改
continuous-integration/drone/push Build is passing
2025-08-08 17:08:26 +08:00
wangxiaoshuang cdefe6d640 1
continuous-integration/drone/push Build is passing
2025-08-08 14:11:35 +08:00
wangxiaoshuang 9ef348efbf 1
continuous-integration/drone/push Build is passing
2025-08-07 17:42:39 +08:00
wangxiaoshuang 06e876619f 影像汇总新增阅片影像大小字段、导出阅片影像功能
continuous-integration/drone/push Build is passing
2025-08-07 15:51:56 +08:00
wangxiaoshuang 3334e24c66 上传影像添加字段
continuous-integration/drone/push Build is passing
2025-08-07 15:24:34 +08:00
wangxiaoshuang 9b3e169ef2 阅片单元外层问题添加配置排除访视显示
continuous-integration/drone/push Build is passing
2025-08-07 13:53:49 +08:00
wangxiaoshuang fa30c68153 阅片页面提交时自动保存
continuous-integration/drone/push Build is passing
2025-08-06 15:33:21 +08:00
wangxiaoshuang e08f094435 质控下载影像按钮不与复核状态相关联
continuous-integration/drone/push Build is passing
2025-08-06 15:05:17 +08:00
wangxiaoshuang d047df807e 1
continuous-integration/drone/push Build is passing
2025-08-06 14:18:33 +08:00
wangxiaoshuang 2c5e33903d 邮箱校验规则默认值问题
continuous-integration/drone/push Build is passing
2025-08-06 13:52:14 +08:00
wangxiaoshuang b024252f98 1
continuous-integration/drone/push Build is passing
2025-08-06 10:18:23 +08:00
wangxiaoshuang c1be3bbf4d 稽查修改
continuous-integration/drone/push Build is passing
2025-08-06 09:54:50 +08:00
wangxiaoshuang f2b07131aa 部分页面增加排序
continuous-integration/drone/push Build is passing
2025-08-05 17:17:15 +08:00
wangxiaoshuang 6c71803a11 影像指控添加导出质控问题功能
continuous-integration/drone/push Build is passing
2025-08-05 14:07:10 +08:00
wangxiaoshuang 91078abd15 影像统计小于等于0时默认赋值为0
continuous-integration/drone/push Build is passing
2025-08-05 10:34:00 +08:00
wangxiaoshuang 04f8a938c3 阅片报告预览其他访视时切换关闭问题
continuous-integration/drone/push Build is passing
2025-08-04 17:53:45 +08:00
wangxiaoshuang 2c85013008 部分问题修复
continuous-integration/drone/push Build is passing
2025-08-04 17:39:51 +08:00
wangxiaoshuang 9d839e46cd 标记保存名称未填写校验
continuous-integration/drone/push Build is passing
2025-08-04 15:10:14 +08:00
wangxiaoshuang 509f8f02b6 已阅片后阅片页面可添加临时标记
continuous-integration/drone/push Build is passing
2025-08-04 14:51:34 +08:00
wangxiaoshuang 9cc1962b3b 1
continuous-integration/drone/push Build is passing
2025-08-04 14:01:47 +08:00
wangxiaoshuang 774ab78a7c CDISC导出配置修改
continuous-integration/drone/push Build is running
2025-08-04 14:00:30 +08:00
wangxiaoshuang 16794dfe1d 医学审核问题导表
continuous-integration/drone/push Build is passing
2025-08-04 13:49:49 +08:00
wangxiaoshuang 1c69ed08cd 1
continuous-integration/drone/push Build is passing
2025-08-04 13:37:01 +08:00
wangxiaoshuang 833324e1ac 全局替换IRC规则修改
continuous-integration/drone/push Build is passing
2025-08-04 13:14:42 +08:00
wangxiaoshuang f36a00cf81 部分问题修复
continuous-integration/drone/push Build is passing
2025-08-04 11:46:52 +08:00
wangxiaoshuang 233bcbb1d0 培训文件限制只能上传pdf
continuous-integration/drone/push Build is passing
2025-08-01 17:02:55 +08:00
wangxiaoshuang b644098203 阅片导入接口修改
continuous-integration/drone/push Build is passing
2025-08-01 16:57:02 +08:00
wangxiaoshuang 424a59c4d9 质控质疑提交后刷新外部列表
continuous-integration/drone/push Build is passing
2025-08-01 16:20:36 +08:00
wangxiaoshuang a3e3db3d5b 复核任务自动跳转下一个任务功能开启
continuous-integration/drone/push Build is passing
2025-08-01 11:31:52 +08:00
wangxiaoshuang a803ee2c00 1
continuous-integration/drone/push Build is passing
2025-07-31 16:16:43 +08:00
wangxiaoshuang 5a8ec13c2f 在影像质控完成后,可以更正影像检查的基本信息,并且需要签名
continuous-integration/drone/push Build is passing
2025-07-31 16:09:44 +08:00
wangxiaoshuang d911d55129 【一致性分析】ir申请重阅一致性分析任务后,pm在重阅跟踪看到该任务的受试者编号为原始编号而不是虚拟编号
continuous-integration/drone/push Build is passing
2025-07-31 14:46:04 +08:00
wangxiaoshuang ebedae85e7 稽查附件展示
continuous-integration/drone/push Build is passing
2025-07-31 14:33:44 +08:00
wangxiaoshuang d54dfae99f 1
continuous-integration/drone/push Build is passing
2025-07-31 09:31:41 +08:00
wangxiaoshuang 00396f3c9d 问题测量时点击取消清除标记
continuous-integration/drone/push Build is passing
2025-07-30 16:02:55 +08:00
wangxiaoshuang 2138bd3345 自定义标记名称保存提示信息位置更改
continuous-integration/drone/push Build is passing
2025-07-30 15:59:45 +08:00
wangxiaoshuang 0416b1bca8 1
continuous-integration/drone/push Build is passing
2025-07-30 15:37:09 +08:00
wangxiaoshuang 6dd579e910 复核质控去除重传功能
continuous-integration/drone/push Build is passing
2025-07-30 14:26:15 +08:00
wangxiaoshuang 98dc6beba5 自定义外层问题上传报错
continuous-integration/drone/push Build is passing
2025-07-30 13:56:38 +08:00
wangxiaoshuang f7a62b2016 自定义dicom增加自由曲线工具
continuous-integration/drone/push Build is passing
2025-07-30 11:48:58 +08:00
wangxiaoshuang eb50f24204 画标记增加提示语
continuous-integration/drone/push Build is passing
2025-07-30 11:45:02 +08:00
wangxiaoshuang 3c4cce70c5 用户列表增加用户参与项目的统计数字
continuous-integration/drone/push Build is passing
2025-07-30 11:28:34 +08:00
wangxiaoshuang a566c1a0b8 重传审批新增导出功能
continuous-integration/drone/push Build is passing
2025-07-30 11:24:17 +08:00
62 changed files with 1968 additions and 1239 deletions
+8
View File
@@ -11,6 +11,14 @@
<meta http-equiv="Cache-control" content="no-store,no-cache,must-revalidate"> <meta http-equiv="Cache-control" content="no-store,no-cache,must-revalidate">
<meta http-equiv="Cache" content="no-cache"> <meta http-equiv="Cache" content="no-cache">
<title><%= webpackConfig.name %></title> <title><%= webpackConfig.name %></title>
<style>
.customPromptTip {
position: absolute;
left: 0;
bottom: -100px;
z-index: 99999;
}
</style>
<% if (eval(process.env.VUE_APP_LOGIN_FOR_PERMISSION)) { %> <% if (eval(process.env.VUE_APP_LOGIN_FOR_PERMISSION)) { %>
<script> <script>
window.zzSessionStorage = { window.zzSessionStorage = {
+7 -1
View File
@@ -281,7 +281,13 @@ export function getCommonDocumentList(param) {
data: param data: param
}) })
} }
export function getCommonDocument(param) {
return request({
url: `/CommonDocument/getCommonDocument`,
method: 'get',
params: param
})
}
export function addOrUpdateCommonDocument(param) { export function addOrUpdateCommonDocument(param) {
return request({ return request({
url: `/CommonDocument/addOrUpdateCommonDocument`, url: `/CommonDocument/addOrUpdateCommonDocument`,
+27
View File
@@ -203,6 +203,15 @@ export function qCVisitList_Export(data) {
data data
}) })
} }
// 导出影像指控问题和答案
export function GetTrialQCQuestionAnserList_Export(data) {
return requestDownload({
url: `/ExcelExport/GetTrialQCQuestionAnserList_Export`,
responseType: 'blob',
method: 'post',
data
})
}
// 导出下载记录 // 导出下载记录
export function getTrialDownloadList_Export(data) { export function getTrialDownloadList_Export(data) {
return requestDownload({ return requestDownload({
@@ -273,3 +282,21 @@ export function GetEmailNoticeConfigList_Export(data) {
data data
}) })
} }
// 导出重传审批
export function GetImageBackList_Export(data) {
return requestDownload({
url: `/ExcelExport/GetImageBackList_Export`,
responseType: 'blob',
method: 'post',
data
})
}
// 导出医学审核配置
export function GetReadingMedicineSystemQuestionList_Export(data) {
return requestDownload({
url: `/ExcelExport/GetReadingMedicineSystemQuestionList_Export`,
responseType: 'blob',
method: 'post',
data
})
}
+8 -1
View File
@@ -286,4 +286,11 @@ export function deleteSingleTableQuestionMark(param, type) {
}) })
} }
// 阅片导入
export function readingImport(param) {
return request({
url: `/ReadingCalculate/readingImport`,
method: 'post',
data: param
})
}
+24
View File
@@ -4204,4 +4204,28 @@ export function getExportSubjectVisitImageList(data) {
method: 'post', method: 'post',
data data
}) })
}
// 影像质控-更正dicom
export function updateDicomStudyInfo(data) {
return request({
url: `/Inspection/QCOperation/UpdateDicomStudyInfo`,
method: 'post',
data
})
}
// 影像质控-更正非dicom
export function updateNoneDicomStudy(data) {
return request({
url: `/Inspection/NoneDicomStudy/UpdateNoneDicomStudy`,
method: 'post',
data
})
}
// 阅片单元-获取访视计划
export function getVisitStage(data) {
return request({
url: `/VisitPlan/getVisitStage`,
method: 'post',
data
})
} }
@@ -24,8 +24,7 @@
</div> </div>
<!--上传列表@selection-change="handleSelectionChange" @sort-change="handleSortByColumn"--> <!--上传列表@selection-change="handleSelectionChange" @sort-change="handleSortByColumn"-->
<el-table ref="dicomFilesTable" v-adaptive="{ bottomOffset: 85 }" height="100" :data="list" :loading="loading" <el-table ref="dicomFilesTable" v-adaptive="{ bottomOffset: 85 }" height="100" :data="list" :loading="loading"
class="dicomFiles-table" class="dicomFiles-table" :default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
<!-- <el-table-column <!-- <el-table-column
type="selection" type="selection"
width="55" width="55"
@@ -298,24 +297,47 @@ export default {
if (data.StudyList && data.StudyList.length > 0) { if (data.StudyList && data.StudyList.length > 0) {
let StudyList = data.StudyList let StudyList = data.StudyList
StudyList.forEach((study) => { StudyList.forEach((study) => {
if (study.StudyDIRPath) {
let obj = {
name: `${data.SubjectCode}/${data.TaskBlindName
}/${this.$fd('IsDicom', true)}/${study.StudyCode
}/DICOMDIR`,
url: this.OSSclientConfig.basePath + study.StudyDIRPath,
}
if (this.IsReadingTaskViewInOrder === 0) {
obj = {
name: `${data.TaskBlindName}/${this.$fd(
'IsDicom',
true
)}/DICOMDIR`,
url: this.OSSclientConfig.basePath + study.StudyDIRPath,
}
}
files.push(obj)
}
if (study.SeriesList.length > 0) { if (study.SeriesList.length > 0) {
study.SeriesList.forEach((series) => { study.SeriesList.forEach((series) => {
if (series.InstancePathList.length > 0) { if (series.InstanceList.length > 0) {
series.InstancePathList.forEach((instance) => { series.InstanceList.forEach((instance) => {
let fileName = instance.Path.split('/').pop() let fileName = instance.Path.split('/').pop()
if (instance.FileName) {
fileName = instance.FileName
}
let obj = { let obj = {
name: `${data.SubjectCode}/${data.TaskBlindName name: `${data.SubjectCode}/${data.TaskBlindName
}/${this.$fd('IsDicom', true)}/${study.StudyCode }/${this.$fd('IsDicom', true)}/${study.StudyCode
}/${fileName}`, }/IMAGE/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path, url: this.OSSclientConfig.basePath + instance.Path,
IsEncapsulated: instance.IsEncapsulated
} }
if (this.IsReadingTaskViewInOrder === 0) { if (this.IsReadingTaskViewInOrder === 0) {
obj = { obj = {
name: `${data.TaskBlindName}/${this.$fd( name: `${data.TaskBlindName}/${this.$fd(
'IsDicom', 'IsDicom',
true true
)}/${fileName}`, )}/IMAGE/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path, url: this.OSSclientConfig.basePath + instance.Path,
IsEncapsulated: instance.IsEncapsulated
} }
} }
files.push(obj) files.push(obj)
@@ -731,6 +731,8 @@ export default {
fileList: [], fileList: [],
dicomInfo: { dicomInfo: {
studyId: data.string('x00200010'), studyId: data.string('x00200010'),
DicomStudyDate: data.string('x00080020'),
DicomStudyTime: data.string('x00080030'),
studyUid: studyUid, studyUid: studyUid,
patientId: data.string('x00100020'), patientId: data.string('x00100020'),
patientName: patientNameStr, patientName: patientNameStr,
@@ -841,6 +843,8 @@ export default {
) )
seriesItem = { seriesItem = {
seriesUid: seriesUid, seriesUid: seriesUid,
DicomSeriesDate: data.string('x00080021'),
DicomSeriesTime: data.string('x00080031'),
seriesNumber: data.intString('x00200011') || 1, seriesNumber: data.intString('x00200011') || 1,
modality: data.string('x00080060') || '', modality: data.string('x00080060') || '',
description: seriesDescriptionStr, description: seriesDescriptionStr,
@@ -880,6 +884,10 @@ export default {
} }
instanceItem = { instanceItem = {
instanceUid: instanceUid, instanceUid: instanceUid,
SOPClassUID: data.string('x00080016'),
TransferSytaxUID: data.string('x00020010'),
MediaStorageSOPInstanceUID: instanceUid,
MediaStorageSOPClassUID: data.string('x00080016'),
instanceNumber: data.intString('x00200013') || 1, instanceNumber: data.intString('x00200013') || 1,
frameCount: data.intString('x00280008') || 1, frameCount: data.intString('x00280008') || 1,
instanceTime: instanceTime, instanceTime: instanceTime,
@@ -1088,6 +1096,8 @@ export default {
acquisitionNumber: dicomInfo.acquisitionNumber, acquisitionNumber: dicomInfo.acquisitionNumber,
triggerTime: dicomInfo.triggerTime, triggerTime: dicomInfo.triggerTime,
bodyPartExamined: '', bodyPartExamined: '',
DicomStudyDate: dicomInfo.DicomStudyDate,
DicomStudyTime: dicomInfo.DicomStudyTime,
seriesList: [], seriesList: [],
}, },
} }
@@ -1112,6 +1122,10 @@ export default {
instanceList.push({ instanceList.push({
studyInstanceUid: dicomInfo.studyUid, studyInstanceUid: dicomInfo.studyUid,
seriesInstanceUid: v.seriesUid, seriesInstanceUid: v.seriesUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
sopInstanceUid: o.instanceUid, sopInstanceUid: o.instanceUid,
instanceNumber: o.instanceNumber, instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime, instanceTime: o.instanceTime,
@@ -1193,6 +1207,10 @@ export default {
studyInstanceUid: dicomInfo.studyUid, studyInstanceUid: dicomInfo.studyUid,
seriesInstanceUid: v.seriesUid, seriesInstanceUid: v.seriesUid,
sopInstanceUid: o.instanceUid, sopInstanceUid: o.instanceUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
instanceNumber: o.instanceNumber, instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime, instanceTime: o.instanceTime,
imageRows: o.imageRows, imageRows: o.imageRows,
@@ -1238,6 +1256,8 @@ export default {
seriesInstanceUid: v.seriesUid, seriesInstanceUid: v.seriesUid,
seriesNumber: v.seriesNumber, seriesNumber: v.seriesNumber,
seriesTime: v.seriesTime, seriesTime: v.seriesTime,
DicomSeriesDate: v.DicomSeriesDate,
DicomSeriesTime: v.DicomSeriesTime,
sliceThickness: v.sliceThickness, sliceThickness: v.sliceThickness,
imagePositionPatient: v.imagePositionPatient, imagePositionPatient: v.imagePositionPatient,
imageOrientationPatient: v.imageOrientationPatient, imageOrientationPatient: v.imageOrientationPatient,
+1 -1
View File
@@ -32,7 +32,7 @@ export default {
ResetImageQualityControlQuestion: 112, // 重置影像质控问题 ResetImageQualityControlQuestion: 112, // 重置影像质控问题
CreateReviewTask: 113, // 生成复核任务 CreateReviewTask: 113, // 生成复核任务
ReviewImageQualityControlQuestion: 219, // 复核质控问题 ReviewImageQualityControlQuestion: 219, // 复核质控问题
CorrectImageExaminationInformation: 220, // 更正影像检查信息
}, },
}; };
</script> </script>
+11 -3
View File
@@ -202,6 +202,7 @@ async function VueInit() {
// 获取版本信息 // 获取版本信息
let PublishInfo = await getCurrentPublishInfo(); let PublishInfo = await getCurrentPublishInfo();
Vue.prototype.$version = PublishInfo.Result; Vue.prototype.$version = PublishInfo.Result;
Vue.prototype.$companyInfo = PublishInfo.OtherInfo;
// 获取检查部位 // 获取检查部位
Vue.prototype.$getBodyPart = (id) => { Vue.prototype.$getBodyPart = (id) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
@@ -278,9 +279,16 @@ async function VueInit() {
Vue.prototype.$reg = () => { Vue.prototype.$reg = () => {
if (localStorage.getItem('CompanyInfo')) { if (localStorage.getItem('CompanyInfo')) {
let { EmailRegexStr } = JSON.parse(localStorage.getItem('CompanyInfo')) let { EmailRegexStr } = JSON.parse(localStorage.getItem('CompanyInfo'))
return { EmailRegexStr } if (EmailRegexStr) {
return { EmailRegexStr }
}
} else if (Vue.prototype.$companyInfo) {
let { EmailRegexStr } = Vue.prototype.$companyInfo
if (EmailRegexStr) {
return { EmailRegexStr }
}
} }
return { EmailRegexStr: '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/' }; return { EmailRegexStr: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$' };
} }
Vue.prototype.$updateDictionary = function () { Vue.prototype.$updateDictionary = function () {
Vue.prototype.$d = function (code) { Vue.prototype.$d = function (code) {
@@ -323,7 +331,7 @@ async function VueInit() {
}) })
} }
let CompanyInfo = JSON.parse(localStorage.getItem('CompanyInfo')) let CompanyInfo = JSON.parse(localStorage.getItem('CompanyInfo'))
if (CompanyInfo && CompanyInfo.SystemShortName) { if (CompanyInfo && CompanyInfo.SystemShortName && text.toUpperCase() !== "CIRCLE") {
let test = new RegExp('IRC', 'ig') let test = new RegExp('IRC', 'ig')
text = text.replace(test, CompanyInfo.SystemShortName) text = text.replace(test, CompanyInfo.SystemShortName)
} }
+2 -2
View File
@@ -44,7 +44,7 @@ export const anonymization = function (file, config) {
} }
} else { } else {
if (dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element]) { if (dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element]) {
dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element].Value[0] = DicomStoreInfo[AnonymizeNotFixed.ReplaceValue] ? DicomStoreInfo[AnonymizeNotFixed.ReplaceValue].toString() : '' dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element].Value[0] = DicomStoreInfo[AnonymizeNotFixed.ReplaceValue] || Number(DicomStoreInfo[AnonymizeNotFixed.ReplaceValue]) === 0 ? DicomStoreInfo[AnonymizeNotFixed.ReplaceValue].toString() : ''
} else { } else {
dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element] = { dataset.dict[AnonymizeNotFixed.Group + AnonymizeNotFixed.Element] = {
vr: AnonymizeNotFixed.ValueRepresentation, vr: AnonymizeNotFixed.ValueRepresentation,
@@ -57,7 +57,7 @@ export const anonymization = function (file, config) {
} }
try { try {
let newDicomFile = dataset.write({ fragmentMultiframe: false }) // fragmentMultiframe 原始数据是否进行分割 let newDicomFile = dataset.write() // fragmentMultiframe 原始数据是否进行分割
const bufferArray = new Uint8Array(newDicomFile) const bufferArray = new Uint8Array(newDicomFile)
const blob = new Blob([bufferArray], { type: 'application/octet-stream' }) const blob = new Blob([bufferArray], { type: 'application/octet-stream' })
resolve({ blob, pixelDataElement }) resolve({ blob, pixelDataElement })
+23 -1
View File
@@ -1,6 +1,7 @@
import streamSaver from "streamsaver"; import streamSaver from "streamsaver";
import "streamsaver/examples/zip-stream.js"; import "streamsaver/examples/zip-stream.js";
import store from '@/store' import store from '@/store'
import dcmjs from './dcmUpload/dcmjs'
streamSaver.mitm = `${window.location.origin}/mitm.html?version=2.0.0` streamSaver.mitm = `${window.location.origin}/mitm.html?version=2.0.0`
// 下载文件并压缩 // 下载文件并压缩
function zipFiles(zipName, files) { function zipFiles(zipName, files) {
@@ -19,7 +20,10 @@ function zipFiles(zipName, files) {
if (fileInfo.done) {//迭代终止 if (fileInfo.done) {//迭代终止
ctrl.close(); ctrl.close();
} else { } else {
let { name, url } = fileInfo.value; let { name, url, IsEncapsulated = false } = fileInfo.value;
if (IsEncapsulated) {
url = await downloadFileToUrl(url)
}
// url = decodeUtf8(url); // 待定,可能做过特殊处理 // url = decodeUtf8(url); // 待定,可能做过特殊处理
return fetch(url).then(res => { return fetch(url).then(res => {
ctrl.enqueue({ ctrl.enqueue({
@@ -99,6 +103,24 @@ function decodeUtf8(bytes) {
str2.pop(); str2.pop();
return str2.join("/") + '/' + name; return str2.join("/") + '/' + name;
} }
// 下载文件进行修改并输出本地url
function downloadFileToUrl(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
const arraybuffer = xhr.response;
let dataset = dcmjs.data.DicomMessage.readFile(arraybuffer)
let newDicomFile = dataset.write({ fragmentMultiframe: false }) // fragmentMultiframe 原始数据是否进行分割
const bufferArray = new Uint8Array(newDicomFile)
const blob = new Blob([bufferArray], { type: 'application/octet-stream' })
const href = URL.createObjectURL(blob)
resolve(href)
};
xhr.send();
})
}
export async function downLoadFile(file, name, type = 'file') { export async function downLoadFile(file, name, type = 'file') {
if (type === 'zip') return await zipFiles(name, file); if (type === 'zip') return await zipFiles(name, file);
return await updateFile(file, name) return await updateFile(file, name)
@@ -0,0 +1,269 @@
<template>
<el-form ref="sysTemplateFrom" v-loading="loading" :model="form" label-width="140px" size="small" :rules="rules"
class="upload-temporary-file">
<div class="base-dialog-body">
<el-form-item :label="$t('dictionary:attachment:label:code')" prop="Code">
<el-input v-model="form.Code" />
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:label:businessScenario')" prop="BusinessScenarioEnum">
<el-select v-model="form.BusinessScenarioEnum" style="width: 100%" size="small" filterable>
<el-option v-for="item of $d.Common_File_BusinessScenario" :key="item.id" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:label:file')">
<div class="upload-container">
<el-upload class="upload-demo" action accept="" :before-upload="beforeUpload" :http-request="handleUploadFile"
:on-preview="handlePreview" :on-remove="handleRemoveFile" :show-file-list="true" :file-list="fileList"
:limit="1" :on-exceed="handleExceed" :disabled="(!form.FileTypeEnum && form.FileTypeEnum !== 0)">
<el-button size="small" type="primary" :disabled="(!form.FileTypeEnum && form.FileTypeEnum !== 0)"
:loading="btnLoading">Select</el-button>
<!-- <span slot="tip" style="margin-left: 10px" class="el-upload__tip">
(must be in xlsx/xls/doc/docx format)
</span> -->
</el-upload>
</div>
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:label:name')" prop="Name">
<el-input v-model="form.Name" />
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:export:form:nameCN')" prop="NameCN">
<el-input v-model="form.NameCN" />
</el-form-item>
<el-form-item v-if="form.Id !== ''" :label="$t('dictionary:attachment:label:isDeleted')">
<el-radio-group v-model="form.IsDeleted">
<el-radio v-for="item of $d.YesOrNo" :label="item.value" :key="item.id">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('dictionary:attachment:label:description')">
<el-input v-model="form.Description" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" />
</el-form-item>
</div>
<div class="base-dialog-footer" style="text-align: right; margin-top: 10px">
<el-form-item style="text-align: right">
<el-button size="small" type="primary" :disabled="(!form.FileTypeEnum && form.FileTypeEnum !== 0)"
:loading="saveBtnLoading" @click="handleSave">{{ $t('common:button:save') }}</el-button>
</el-form-item>
</div>
</el-form>
</template>
<script>
import {
addOrUpdateCommonDocument,
uploadCommonDoc,
Upload,
} from '@/api/dictionary'
import { getBasicDataSelects } from '@/api/dictionary/dictionary'
export default {
name: 'TemplateForm',
props: {
data: {
type: Object,
default() {
return {}
},
},
},
data() {
return {
form: {
Id: '',
Code: '',
FileTypeEnum: 0,
BusinessScenarioEnum: null,
Name: '',
NameCN: '',
Path: '',
Description: '',
IsDeleted: false,
},
rules: {
Code: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
],
Name: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
],
NameCN: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
],
BusinessScenarioEnum: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
],
},
fileList: [],
btnLoading: false,
saveBtnLoading: false,
loading: false,
dictionaryList: {},
}
},
mounted() {
this.initForm()
},
methods: {
async initForm() {
await this.getDicData()
if (Object.keys(this.data).length > 0) {
if (this.data.Path) {
this.fileList = [
{
name: this.data.Name,
path: this.data.Path,
url: this.data.Path,
type: this.data.Type,
},
]
}
for (const k in this.form) {
if (this.data.hasOwnProperty(k)) {
this.form[k] = this.data[k]
}
}
}
},
// 获取文件类型下拉框
getDicData() {
this.loading = true
getBasicDataSelects(['Common_File_ModuleType', 'Common_File_Type'])
.then((res) => {
this.dictionaryList = { ...res.Result }
this.loading = false
})
.catch(() => {
this.loading = false
})
},
beforeUpload(file) {
// 检测文件类型是否符合要求
if (this.checkFileSuffix(file.name)) {
this.fileList = []
return true
} else {
this.$alert(this.$t('dictionary:attachment:export:alert:formatFile'))
return false
}
},
async handleUploadFile(param) {
this.loading = true
this.form.FileName = param.file.name
let extendName = param.file.name
.substring(param.file.name.lastIndexOf('.'))
.toLocaleLowerCase()
let file = await this.fileToBlob(param.file)
let res = await this.OSSclient.put(`/System/Tools/${this.$guid()}${extendName}`, file)
this.form.Path = this.$getObjectName(res.url)
this.form.NameCN = param.file.name
this.fileList.push({
name: param.file.name,
path: this.form.Path,
fullPath: this.form.Path,
url: this.form.Path,
})
this.loading = false
this.btnLoading = false
// Upload(formData, 1).then((res) => {
// this.fileList.push({
// name: param.file.name,
// path: res.Result.FilePath,
// fullPath: res.Result.FullFilePath,
// url: res.Result.FilePath,
// })
// })
},
fileToBlob(file) {
// 创建 FileReader 对象
const reader = new FileReader()
return new Promise((resolve) => {
// FileReader 添加 load 事件
reader.addEventListener('load', (e) => {
let blob
if (typeof e.target.result === 'object') {
blob = new Blob([e.target.result])
} else {
blob = e.target.result
}
resolve(blob)
})
// FileReader 以 ArrayBuffer 格式 读取 File 对象中数据
reader.readAsArrayBuffer(file)
})
},
handleSave() {
this.$refs.sysTemplateFrom.validate((valid) => {
if (!valid) return
if (!this.form.Name) {
this.$alert(this.$t('dictionary:attachment:message:msg1'))
return
}
this.saveBtnLoading = true
addOrUpdateCommonDocument(this.form)
.then((res) => {
this.saveBtnLoading = false
this.$emit('closeDialog')
this.$emit('getList')
this.$message.success(this.$t('common:message:savedSuccessfully'))
})
.catch(() => {
this.saveBtnLoading = false
})
})
},
handleRemoveFile() {
this.fileList = []
this.form.Path = ''
this.form.NameCN = ''
this.form.Name = ''
},
handlePreview(file) {
if (file.fullPath) {
window.open(file.fullPath, '_blank')
}
},
handleExceed(files, fileList) {
this.$message.warning(this.$t('upload:rule:maxFile1'))
},
checkFileSuffix(fileName) {
return true
var typeArr = ['xls', 'xlsx', 'doc', 'docx']
var extendName = fileName
.substring(fileName.lastIndexOf('.') + 1)
.toLocaleLowerCase()
if (typeArr.indexOf(extendName) !== -1) {
return true
} else {
return false
}
},
},
}
</script>
<style lang="scss">
.upload-temporary-file {
.upload-container .el-upload--text {
border: none;
width: 80px;
height: 40px;
}
.upload-container .el-input--small {
margin-bottom: 5px;
}
.upload-container .el-icon-circle-check {
color: #428bca;
font-size: 13px;
}
.account_item_clear {
.el-tag__close {
display: none !important;
}
}
}
</style>
@@ -0,0 +1,238 @@
<template>
<BaseContainer>
<template slot="search-container">
<el-form :inline="true" size="small">
<!-- 业务场景 -->
<el-form-item :label="$t('dictionary:attachment:label:businessScenario')">
<el-select v-model="searchData.BusinessScenarioEnum" style="width: 150px">
<el-option v-for="item of $d.Common_File_BusinessScenario" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<!-- 文件名称 -->
<el-form-item :label="$t('dictionary:attachment:label:name')">
<el-input v-model="searchData.Name" style="width: 130px" clearable />
</el-form-item>
<el-form-item>
<!-- 查询 -->
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<!-- 重置 -->
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
</el-form-item>
<el-button type="primary" style="float: right" size="small" @click="handleAdd">
{{ $t('common:button:new') }}
</el-button>
</el-form>
</template>
<template slot="main-container">
<el-table v-adaptive="{ bottomOffset: 60 }" v-loading="loading" :data="list" stripe height="100"
@sort-change="handleSortChange">
<el-table-column type="index" width="40" />
<el-table-column prop="Code" :label="$t('dictionary:attachment:label:code')" show-overflow-tooltip
sortable="custom" />
<!-- 业务场景 -->
<el-table-column prop="BusinessScenarioEnum" :label="$t('dictionary:attachment:label:businessScenario')"
show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
{{
$fd(
'Common_File_BusinessScenario',
scope.row.BusinessScenarioEnum
)
}}
</template>
</el-table-column>
<!-- 文件名称 -->
<el-table-column prop="Name" :label="$t('dictionary:attachment:label:name')" show-overflow-tooltip
sortable="custom" />
<el-table-column prop="NameCN" :label="$t('dictionary:attachment:upload:table:nameCN')" show-overflow-tooltip
sortable="custom" />
<!-- 描述 -->
<el-table-column prop="Description" :label="$t('dictionary:attachment:label:description')"
show-overflow-tooltip />
<!-- 是否废除 -->
<el-table-column prop="IsDeleted" :label="$t('dictionary:attachment:label:isDeleted')" show-overflow-tooltip
sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsDeleted" type="danger">{{
$fd('YesOrNo', scope.row.IsDeleted)
}}</el-tag>
<el-tag v-else type="primary">{{
$fd('YesOrNo', scope.row.IsDeleted)
}}</el-tag>
</template>
</el-table-column>
<!-- 上传时间 -->
<el-table-column prop="UpdateTime" :label="$t('dictionary:attachment:label:updateTime')" show-overflow-tooltip
sortable="custom" />
<el-table-column :label="$t('common:action:action')" width="300">
<template slot-scope="scope">
<!-- <el-button type="text" @click="PreviewFile(scope.row)">
{{ $t('common:button:preview') }}
</el-button> -->
<el-button type="text" @click="handleDownload(scope.row)">
{{ $t('common:button:download') }}
</el-button>
<el-button type="text" @click="handleEdit(scope.row)">
{{ $t('common:button:edit') }}
</el-button>
<el-button type="text" @click="handleDelete(scope.row)">
{{ $t('common:button:delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<!-- 新增/编辑 -->
<el-dialog v-if="editDialog.visible" :visible.sync="editDialog.visible" :close-on-click-modal="false"
:title="editDialog.title" width="600px" custom-class="base-dialog-wrapper">
<TemplateForm :data="currentRow" @closeDialog="closeDialog" @getList="getList" />
</el-dialog>
</template>
</BaseContainer>
</template>
<script>
import {
getCommonDocumentList,
DownloadCommonDoc,
deleteCommonDocument,
} from '@/api/dictionary'
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import TemplateForm from './TemplateForm'
import { downLoadFile } from '@/utils/stream.js'
const FileTypeEnum = 0
const searchDataDefault = () => {
return {
FileTypeEnum: FileTypeEnum,
BusinessScenarioEnum: null,
Name: '',
PageIndex: 1,
PageSize: 20,
}
}
export default {
name: 'ToolsTemplate',
components: { BaseContainer, Pagination, TemplateForm },
data() {
return {
searchData: searchDataDefault(),
list: [],
total: 0,
currentRow: {},
editDialog: { title: '', visible: false },
loading: false,
}
},
mounted() {
this.getList()
},
computed: {
isEN() {
return this.$i18n.locale !== 'zh'
},
},
methods: {
handleDelete(row) {
// 确定删除该模版?
this.$confirm(this.$t('dictionary:attachment:message:msg1')).then(() => {
deleteCommonDocument(row.Id).then(() => {
this.$message.success(this.$t('common:message:deletedSuccessfully'))
this.getList()
})
}).catch(() => { })
},
PreviewFile(row) {
let basePath = window.location.origin
if (window.location.protocol !== 'https:') {
basePath = 'https://irc.test.extimaging.com'
}
let data = {
name: row.NameCN,
path: basePath + row.Path,
}
this.$emit('PreviewFile', data)
},
getList() {
this.loading = true
getCommonDocumentList(this.searchData)
.then((res) => {
this.loading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
})
.catch(() => {
this.loading = false
})
},
// 新增
handleAdd() {
this.editDialog.title = this.$t('common:button:new')
this.currentRow = { FileTypeEnum: FileTypeEnum }
this.editDialog.visible = true
},
// 下载
async handleDownload(row) {
try {
this.loading = true
let fileName = this.isEN ? row.Name : row.NameCN;
let type = fileName
.substring(fileName.lastIndexOf('.'))
.toLocaleLowerCase()
if (!type) {
let extendName = row.Path
.substring(row.Path.lastIndexOf('.'))
.toLocaleLowerCase()
fileName += extendName
}
let res = await downLoadFile(this.OSSclientConfig.basePath + row.Path, fileName)
this.loading = false
} catch (err) {
this.loading = false
}
},
// 编辑
handleEdit(row) {
this.editDialog.title = this.$t('common:button:edit')
this.currentRow = { ...row }
this.editDialog.visible = true
},
handleSearch() {
this.searchData.PageIndex = 1
this.getList()
},
handleReset() {
this.searchData = searchDataDefault()
this.getList()
},
closeDialog() {
this.editDialog.visible = false
},
// 排序
handleSortChange(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
this.searchData.SortField = column.prop
this.searchData.PageIndex = 1
this.getList()
},
},
}
</script>
<style lang="scss" scoped>
::v-deep .search {
display: block;
}
</style>
+16 -42
View File
@@ -1,52 +1,22 @@
<template> <template>
<div class="attachment-wrapper"> <div class="attachment-wrapper">
<el-tabs v-model="activeTab" @tab-click="clickTab"> <el-tabs v-model="activeTab" @tab-click="clickTab">
<el-tab-pane <el-tab-pane v-for="item in $d.Common_File_Type" :key="item.value" :label="item.label" :name="String(item.value)">
v-for="item in $d.Common_File_Type" <UploadTemplate v-if="activeTab === '1' && item.value == activeTab" @PreviewFile="PreviewFile" />
:key="item.value" <ExportTemplate v-if="activeTab === '2' && item.value == activeTab" @PreviewFile="PreviewFile" />
:label="item.label"
:name="String(item.value)"
>
<UploadTemplate
v-if="activeTab === '1' && item.value == activeTab"
@PreviewFile="PreviewFile"
/>
<ExportTemplate
v-if="activeTab === '2' && item.value == activeTab"
@PreviewFile="PreviewFile"
/>
<EmailTemplate v-if="activeTab === '3' && item.value == activeTab" /> <EmailTemplate v-if="activeTab === '3' && item.value == activeTab" />
<CommonTemplate v-if="activeTab === '4' && item.value == activeTab" /> <CommonTemplate v-if="activeTab === '4' && item.value == activeTab" />
<SignatureTemplate <SignatureTemplate v-if="activeTab === '5' && item.value == activeTab" />
v-if="activeTab === '5' && item.value == activeTab" <ToolsTemplate v-if="activeTab === '0' && item.value == activeTab" />
/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<!-- 预览 --> <!-- 预览 -->
<el-dialog <el-dialog v-if="Preview.visible" :visible.sync="Preview.visible" :close-on-click-modal="false" :fullscreen="true"
v-if="Preview.visible" :title="Preview.title" width="600px" custom-class="base-dialog-wrapper">
:visible.sync="Preview.visible" <vue-office-docx v-if="docxTypes.includes(Preview.type)" :src="Preview.path" style="height: calc(100vh - 70px)"
:close-on-click-modal="false" @rendered="renderedHandler" @error="errorHandler" />
:fullscreen="true" <vue-office-excel v-else-if="excelTypes.includes(Preview.type)" :src="Preview.path" :options="options"
:title="Preview.title" style="height: calc(100vh - 70px)" @rendered="renderedHandler" @error="errorHandler" />
width="600px"
custom-class="base-dialog-wrapper"
>
<vue-office-docx
v-if="docxTypes.includes(Preview.type)"
:src="Preview.path"
style="height: calc(100vh - 70px)"
@rendered="renderedHandler"
@error="errorHandler"
/>
<vue-office-excel
v-else-if="excelTypes.includes(Preview.type)"
:src="Preview.path"
:options="options"
style="height: calc(100vh - 70px)"
@rendered="renderedHandler"
@error="errorHandler"
/>
<PreviewFile v-else :file-path="Preview.path" :file-type="Preview.type" /> <PreviewFile v-else :file-path="Preview.path" :file-type="Preview.type" />
</el-dialog> </el-dialog>
</div> </div>
@@ -57,6 +27,7 @@ import ExportTemplate from './components/ExportTemplate'
import EmailTemplate from './components/EmailTemplate' import EmailTemplate from './components/EmailTemplate'
import CommonTemplate from './components/CommonTemplate' import CommonTemplate from './components/CommonTemplate'
import SignatureTemplate from './components/SignatureTemplate' import SignatureTemplate from './components/SignatureTemplate'
import ToolsTemplate from './components/ToolsTemplate'
import VueOfficeDocx from '@vue-office/docx' import VueOfficeDocx from '@vue-office/docx'
import '@vue-office/docx/lib/index.css' import '@vue-office/docx/lib/index.css'
import VueOfficeExcel from '@vue-office/excel' import VueOfficeExcel from '@vue-office/excel'
@@ -73,6 +44,7 @@ export default {
VueOfficeDocx, VueOfficeDocx,
VueOfficeExcel, VueOfficeExcel,
PreviewFile, PreviewFile,
ToolsTemplate
}, },
data() { data() {
return { return {
@@ -142,16 +114,18 @@ export default {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.el-tabs__header { .el-tabs__header {
height: 40px; height: 40px;
margin-bottom: 5px; margin-bottom: 5px;
} }
.el-tabs__content { .el-tabs__content {
flex: 1; flex: 1;
.el-tab-pane { .el-tab-pane {
height: 100%; height: 100%;
} }
} }
} }
</style> </style>
@@ -43,6 +43,7 @@
:data="list" :data="list"
stripe stripe
height="100" height="100"
@sort-change="handleSortByColumn"
> >
<el-table-column type="index" width="60" /> <el-table-column type="index" width="60" />
<!-- Group --> <!-- Group -->
@@ -50,6 +51,7 @@
prop="Group" prop="Group"
:label="$t('template:anonymization:label:group')" :label="$t('template:anonymization:label:group')"
show-overflow-tooltip show-overflow-tooltip
sortable="custom"
/> />
<!-- Element --> <!-- Element -->
<el-table-column <el-table-column
@@ -57,24 +59,28 @@
:label="$t('template:anonymization:label:element')" :label="$t('template:anonymization:label:element')"
show-overflow-tooltip show-overflow-tooltip
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Tag Description --> <!-- Tag Description -->
<el-table-column <el-table-column
prop="TagDescription" prop="TagDescription"
:label="$t('template:anonymization:label:tagDescription')" :label="$t('template:anonymization:label:tagDescription')"
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Tag DescriptionCN --> <!-- Tag DescriptionCN -->
<el-table-column <el-table-column
prop="TagDescriptionCN" prop="TagDescriptionCN"
:label="$t('template:anonymization:label:tagDescriptionCN')" :label="$t('template:anonymization:label:tagDescriptionCN')"
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Value Representation --> <!-- Value Representation -->
<el-table-column <el-table-column
prop="ValueRepresentation" prop="ValueRepresentation"
:label="$t('template:anonymization:label:valueRepresentation')" :label="$t('template:anonymization:label:valueRepresentation')"
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Is Fixed --> <!-- Is Fixed -->
<el-table-column :label="$t('template:anonymization:label:isFixed')" width="100"> <el-table-column :label="$t('template:anonymization:label:isFixed')" width="100">
@@ -92,6 +98,7 @@
prop="ReplaceValue" prop="ReplaceValue"
:label="$t('template:anonymization:label:valueReplace')" :label="$t('template:anonymization:label:valueReplace')"
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Is Enable --> <!-- Is Enable -->
<el-table-column :label="$t('template:anonymization:label:isEnable')" width="100" fixed="right"> <el-table-column :label="$t('template:anonymization:label:isEnable')" width="100" fixed="right">
@@ -139,7 +146,9 @@ const searchDataDefault = () => {
IsAdd: false, IsAdd: false,
TagDescriptionCN: '', TagDescriptionCN: '',
PageIndex: 1, PageIndex: 1,
PageSize: 500 PageSize: 500,
Asc: false,
SortField: ''
} }
} }
export default { export default {
@@ -159,6 +168,17 @@ export default {
this.getList() this.getList()
}, },
methods: { methods: {
// 排序
handleSortByColumn(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
this.searchData.SortField = column.prop
this.searchData.PageIndex = 1
this.getList()
},
switchChange(event, item) { switchChange(event, item) {
this.loading = true this.loading = true
addOrUpdateSystemAnonymization(item).then(res => { addOrUpdateSystemAnonymization(item).then(res => {
@@ -43,6 +43,7 @@
:data="list" :data="list"
stripe stripe
height="100" height="100"
@sort-change="handleSortByColumn"
> >
<el-table-column type="index" width="60" /> <el-table-column type="index" width="60" />
<!-- Group --> <!-- Group -->
@@ -50,6 +51,7 @@
prop="Group" prop="Group"
:label="$t('template:anonymization:label:group')" :label="$t('template:anonymization:label:group')"
show-overflow-tooltip show-overflow-tooltip
sortable="custom"
/> />
<!-- Element --> <!-- Element -->
<el-table-column <el-table-column
@@ -57,24 +59,28 @@
:label="$t('template:anonymization:label:element')" :label="$t('template:anonymization:label:element')"
show-overflow-tooltip show-overflow-tooltip
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Tag Description --> <!-- Tag Description -->
<el-table-column <el-table-column
prop="TagDescription" prop="TagDescription"
:label="$t('template:anonymization:label:tagDescription')" :label="$t('template:anonymization:label:tagDescription')"
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Tag DescriptionCN --> <!-- Tag DescriptionCN -->
<el-table-column <el-table-column
prop="TagDescriptionCN" prop="TagDescriptionCN"
:label="$t('template:anonymization:label:tagDescriptionCN')" :label="$t('template:anonymization:label:tagDescriptionCN')"
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Value Representation --> <!-- Value Representation -->
<el-table-column <el-table-column
prop="ValueRepresentation" prop="ValueRepresentation"
:label="$t('template:anonymization:label:valueRepresentation')" :label="$t('template:anonymization:label:valueRepresentation')"
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Is Fixed --> <!-- Is Fixed -->
<el-table-column :label="$t('template:anonymization:label:isFixed')" width="100"> <el-table-column :label="$t('template:anonymization:label:isFixed')" width="100">
@@ -92,6 +98,7 @@
prop="ReplaceValue" prop="ReplaceValue"
:label="$t('template:anonymization:label:valueReplace')" :label="$t('template:anonymization:label:valueReplace')"
min-width="110" min-width="110"
sortable="custom"
/> />
<!-- Is Enable --> <!-- Is Enable -->
<el-table-column :label="$t('template:anonymization:label:isEnable')" width="100" fixed="right"> <el-table-column :label="$t('template:anonymization:label:isEnable')" width="100" fixed="right">
@@ -138,7 +145,9 @@ const searchDataDefault = () => {
TagDescriptionCN: '', TagDescriptionCN: '',
IsAdd: true, IsAdd: true,
PageIndex: 1, PageIndex: 1,
PageSize: 500 PageSize: 500,
Asc: false,
SortField: ''
} }
} }
export default { export default {
@@ -158,6 +167,17 @@ export default {
this.getList() this.getList()
}, },
methods: { methods: {
// 排序
handleSortByColumn(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
this.searchData.SortField = column.prop
this.searchData.PageIndex = 1
this.getList()
},
switchChange(event, item) { switchChange(event, item) {
this.loading = true this.loading = true
addOrUpdateSystemAnonymization(item).then(res => { addOrUpdateSystemAnonymization(item).then(res => {
@@ -30,13 +30,13 @@
<el-form-item <el-form-item
:label="$t('trials:auditRecord:table:criterion')" :label="$t('trials:auditRecord:table:criterion')"
> >
<el-select v-model="searchData.CriterionTypeEnum"> <el-select v-model="searchData.CriterionTypeEnum" clearable>
<el-option v-for="item of $d.CriterionType" :key="item.id" :value="item.value" :label="item.label" /> <el-option v-for="item of $d.CriterionType" :key="item.id" :value="item.value" :label="item.label" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 是否通用 --> <!-- 是否通用 -->
<el-form-item :label="$t('dictionary:medicalAudit:label:IsGeneral')"> <el-form-item :label="$t('dictionary:medicalAudit:label:IsGeneral')">
<el-select v-model="searchData.IsGeneral"> <el-select v-model="searchData.IsGeneral" clearable>
<el-option v-for="item of $d.YesOrNo" :key="item.id" :value="item.value" :label="item.label" /> <el-option v-for="item of $d.YesOrNo" :key="item.id" :value="item.value" :label="item.label" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -51,6 +51,9 @@
> >
{{ $t('common:button:reset') }} {{ $t('common:button:reset') }}
</el-button> </el-button>
<el-button type="primary" @click="handleExport">
{{ $t('common:button:export') }}
</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<span style="margin-left:auto"> <span style="margin-left:auto">
@@ -66,6 +69,7 @@
:data="list" :data="list"
stripe stripe
height="100" height="100"
@sort-change="handleSortByColumn"
> >
<!-- 序号 --> <!-- 序号 -->
<el-table-column <el-table-column
@@ -79,6 +83,7 @@
:label="$t('trials:MIMqcCfg:table:questionName')" :label="$t('trials:MIMqcCfg:table:questionName')"
show-overflow-tooltip show-overflow-tooltip
min-width="140" min-width="140"
sortable="custom"
/> />
<!-- 审核问题 --> <!-- 审核问题 -->
<el-table-column <el-table-column
@@ -86,6 +91,7 @@
:label="$t('common:title:languageType')" :label="$t('common:title:languageType')"
show-overflow-tooltip show-overflow-tooltip
min-width="160" min-width="160"
sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('LanguageType', scope.row.LanguageType) }} {{ $fd('LanguageType', scope.row.LanguageType) }}
@@ -97,6 +103,7 @@
:label="$t('trials:qcCfg:table:type')" :label="$t('trials:qcCfg:table:type')"
show-overflow-tooltip show-overflow-tooltip
min-width="140" min-width="140"
sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('QcType', scope.row.Type) }} {{ $fd('QcType', scope.row.Type) }}
@@ -108,6 +115,7 @@
:label="$t('trials:qcCfg:table:typeValue')" :label="$t('trials:qcCfg:table:typeValue')"
show-overflow-tooltip show-overflow-tooltip
min-width="140" min-width="140"
sortable="custom"
/> />
<!-- 任务类型 --> <!-- 任务类型 -->
<el-table-column <el-table-column
@@ -115,6 +123,7 @@
:label="$t('trials:medicalFeedbackCfg:title:taskType')" :label="$t('trials:medicalFeedbackCfg:title:taskType')"
show-overflow-tooltip show-overflow-tooltip
min-width="140" min-width="140"
sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-if="scope.row.ReadingCategory === 1" type="primary"> <el-tag v-if="scope.row.ReadingCategory === 1" type="primary">
@@ -136,6 +145,7 @@
:label="$t('trials:auditRecord:table:criterion')" :label="$t('trials:auditRecord:table:criterion')"
min-width="160" min-width="160"
show-overflow-tooltip show-overflow-tooltip
sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<div> <div>
@@ -148,6 +158,7 @@
:label="$t('dictionary:medicalAudit:label:IsGeneral')" :label="$t('dictionary:medicalAudit:label:IsGeneral')"
min-width="120" min-width="120"
show-overflow-tooltip show-overflow-tooltip
sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<div> <div>
@@ -161,6 +172,7 @@
:label="$t('trials:qcCfg:table:parentQs')" :label="$t('trials:qcCfg:table:parentQs')"
show-overflow-tooltip show-overflow-tooltip
min-width="140" min-width="140"
sortable="custom"
/> />
<!-- 父问题触发值 --> <!-- 父问题触发值 -->
<el-table-column <el-table-column
@@ -168,12 +180,14 @@
:label="$t('trials:qcCfg:table:parentTriggerValue')" :label="$t('trials:qcCfg:table:parentTriggerValue')"
show-overflow-tooltip show-overflow-tooltip
min-width="160" min-width="160"
sortable="custom"
/> />
<!-- 是否必填 --> <!-- 是否必填 -->
<el-table-column <el-table-column
prop="IsRequired" prop="IsRequired"
:label="$t('trials:qcCfg:table:isRequired')" :label="$t('trials:qcCfg:table:isRequired')"
min-width="120" min-width="120"
sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('YesOrNo', scope.row.IsRequired) }} {{ $fd('YesOrNo', scope.row.IsRequired) }}
@@ -184,6 +198,7 @@
prop="IsEnable" prop="IsEnable"
:label="$t('trials:qcCfg:table:isEnable')" :label="$t('trials:qcCfg:table:isEnable')"
min-width="120" min-width="120"
sortable="custom"
> >
<template slot-scope="scope"> <template slot-scope="scope">
{{ $fd('YesOrNo', scope.row.IsEnable) }} {{ $fd('YesOrNo', scope.row.IsEnable) }}
@@ -215,7 +230,7 @@
</template> </template>
<script> <script>
import { getReadingMedicineSystemQuestionList, deleteReadingMedicineSystemQuestion } from '@/api/dictionary' import { getReadingMedicineSystemQuestionList, deleteReadingMedicineSystemQuestion } from '@/api/dictionary'
import { GetReadingMedicineSystemQuestionList_Export } from '@/api/export'
import BoxContent from '@/components/BoxContent' import BoxContent from '@/components/BoxContent'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import MedicalAuditForm from './MedicalAuditForm' import MedicalAuditForm from './MedicalAuditForm'
@@ -228,7 +243,9 @@ const searchDataDefault = () => {
LanguageType: null, LanguageType: null,
Type: '', Type: '',
CriterionTypeEnum: null, CriterionTypeEnum: null,
IsGeneral: null IsGeneral: null,
Asc: false,
SortField: ''
} }
} }
export default { export default {
@@ -248,6 +265,20 @@ export default {
this.getList() this.getList()
}, },
methods: { methods: {
async handleExport() {
await GetReadingMedicineSystemQuestionList_Export(this.searchData)
},
// 排序
handleSortByColumn(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
this.searchData.SortField = column.prop
this.searchData.PageIndex = 1
this.getList()
},
// 获取受试者列表信息 // 获取受试者列表信息
getList() { getList() {
this.loading = true this.loading = true
@@ -254,7 +254,7 @@
<el-date-picker <el-date-picker
v-model="form.StartTime" v-model="form.StartTime"
type="year" type="year"
value-format="yyyy-MM-DD" value-format="yyyy"
> >
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
@@ -265,7 +265,7 @@
<el-date-picker <el-date-picker
v-model="form.EndTime" v-model="form.EndTime"
type="year" type="year"
value-format="yyyy-MM-DD" value-format="yyyy"
> >
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
@@ -904,12 +904,23 @@ export default {
try { try {
if (key === 'clinicalTrials') { if (key === 'clinicalTrials') {
let validate = await this.$refs.clinicalTrialsFrom.validate() let validate = await this.$refs.clinicalTrialsFrom.validate()
console.log(validate, 'validate')
if (!validate) return false if (!validate) return false
this.form.DoctorId = this.reviewerId this.form.DoctorId = this.reviewerId
if (this.trialId) { if (this.trialId) {
this.form.TrialId = this.trialId this.form.TrialId = this.trialId
} }
if (this.form.StartTime) {
let arr = this.form.StartTime.split("-")
if (arr.length <= 1) {
this.form.StartTime = `${this.form.StartTime}-01-01`
}
}
if (this.form.EndTime) {
let arr = this.form.EndTime.split("-")
if (arr.length <= 1) {
this.form.EndTime = `${this.form.EndTime}-12-31`
}
}
this.loading = true this.loading = true
let res = await addOrUpdateTrialExperience(this.form) let res = await addOrUpdateTrialExperience(this.form)
this.loading = false this.loading = false
@@ -38,7 +38,11 @@
<span v-if="isEN">{{ DATA.DepartmentOther }}</span> <span v-if="isEN">{{ DATA.DepartmentOther }}</span>
<span v-else>{{ DATA.DepartmentOtherCN }}</span> <span v-else>{{ DATA.DepartmentOtherCN }}</span>
</span> </span>
<span class="el-icon-user" v-if="DATA.Rank || DATA.RankCN"> <span class="el-icon-user" v-if="DATA.RankOther || DATA.RankOtherCN">
<span v-if="isEN">{{ DATA.RankOther }}</span>
<span v-else>{{ DATA.RankOtherCN }}</span>
</span>
<span class="el-icon-user" v-else-if="DATA.Rank || DATA.RankCN">
<span v-if="isEN">{{ DATA.Rank }}</span> <span v-if="isEN">{{ DATA.Rank }}</span>
<span v-else>{{ DATA.RankCN }}</span> <span v-else>{{ DATA.RankCN }}</span>
</span> </span>
@@ -327,7 +331,13 @@
:label="$t('curriculumVitae:info:form:physician')" :label="$t('curriculumVitae:info:form:physician')"
prop="RankId" prop="RankId"
> >
<el-select v-model="form.RankId" clearable placeholder=""> <el-select v-model="form.RankId" clearable placeholder="" @change="()=>{
if($fd('Rank', form.RankId, 'id') !==
$t('curriculumVitae:selectLabel:Other')){
form.RankOther = null
form.RankOtherCN = null
}
}">
<el-option <el-option
v-for="item in $d.Rank" v-for="item in $d.Rank"
:key="item.id" :key="item.id"
@@ -72,7 +72,11 @@
reviewerData.EmploymentView.DepartmentOtherCN reviewerData.EmploymentView.DepartmentOtherCN
}}</span> }}</span>
</span> </span>
<span class="el-icon-user" <span class="el-icon-user" v-if="reviewerData.EmploymentView.RankOther || reviewerData.EmploymentView.RankOtherCN">
<span v-if="isEN">{{ reviewerData.EmploymentView.RankOther }}</span>
<span v-else>{{ reviewerData.EmploymentView.RankOtherCN }}</span>
</span>
<span class="el-icon-user" v-else
><span v-if="isEN">{{ reviewerData.EmploymentView.Rank }}</span> ><span v-if="isEN">{{ reviewerData.EmploymentView.Rank }}</span>
<span v-else>{{ reviewerData.EmploymentView.RankCN }}</span></span <span v-else>{{ reviewerData.EmploymentView.RankCN }}</span></span
> >
@@ -417,7 +421,12 @@
v-if="true" v-if="true"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ $fd('Indication', scope.row.IndicationEnum) }}</span> <span v-if="scope.row.EvaluationContent">
{{ scope.row.EvaluationContent }}
</span>
<span v-else>
{{ $fd('Indication', scope.row.IndicationEnum) }}
</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
+7
View File
@@ -219,6 +219,13 @@ export default {
sortable: 'custom', sortable: 'custom',
showOverflowTooltip: true, showOverflowTooltip: true,
}, },
{
prop: 'JoinedTrialCount',
label: this.$t('system:userlist:table:JoinedTrialCount'),
minWidth: 150,
sortable: 'custom',
showOverflowTooltip: true,
},
{ {
prop: 'LastLoginTime', prop: 'LastLoginTime',
label: this.$t('system:userlist:table:LastLoginTime'), label: this.$t('system:userlist:table:LastLoginTime'),
@@ -37,7 +37,7 @@
<div class="add-icon" @click.prevent="downloadTpl"> <div class="add-icon" @click.prevent="downloadTpl">
<i class="el-icon-download" /> <i class="el-icon-download" />
</div> </div>
<div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType)"> <div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType, item.QuestionName)">
<i class="el-icon-upload2" /> <i class="el-icon-upload2" />
</div> </div>
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)"> <div class="add-icon" @click.prevent="handleAddOrEdit('add', item)">
@@ -174,7 +174,7 @@
<!-- 导入 --> <!-- 导入 -->
<el-dialog v-if="upload.visible" :visible.sync="upload.visible" :close-on-click-modal="false" <el-dialog v-if="upload.visible" :visible.sync="upload.visible" :close-on-click-modal="false"
:title="upload.title" width="500px"> :title="upload.title" width="500px">
<UploadExcel :visit-task-id="visitTaskId" @close="uploadDlgClose" /> <UploadExcel :visit-task-id="visitTaskId" :TableName="upload.TableName" @close="uploadDlgClose" />
</el-dialog> </el-dialog>
</div> </div>
</div> </div>
@@ -233,7 +233,7 @@ export default {
formChanged: false, formChanged: false,
digitPlaces: 2, digitPlaces: 2,
addOrEdit: { visible: false, title: '' }, addOrEdit: { visible: false, title: '' },
upload: { visible: false, title: '' }, upload: { visible: false, title: '', TableName: '' },
qsList: [], qsList: [],
answersList: [], answersList: [],
qsForm: {}, qsForm: {},
@@ -668,7 +668,8 @@ export default {
console.log(e) console.log(e)
} }
}, },
uploadTpl(lesionType) { uploadTpl(lesionType, TableName) {
this.upload.TableName = TableName
this.upload.title = `导入( ${this.$fd('LesionType', lesionType)} ` this.upload.title = `导入( ${this.$fd('LesionType', lesionType)} `
this.upload.visible = true this.upload.visible = true
}, },
@@ -33,12 +33,16 @@
</el-form> </el-form>
</template> </template>
<script> <script>
import { uploadIVUSTemplate } from '@/api/reading' import { readingImport } from '@/api/reading'
export default { export default {
props: { props: {
visitTaskId: { visitTaskId: {
type: String, type: String,
required: true required: true
},
TableName: {
type: String,
default: ''
} }
}, },
data() { data() {
@@ -63,7 +67,9 @@ export default {
var data = new FormData() var data = new FormData()
data.append('file', param.file) data.append('file', param.file)
data.append('visitTaskId', this.visitTaskId) data.append('visitTaskId', this.visitTaskId)
await uploadIVUSTemplate(data) data.append('readingImportType', 0)
data.append('TableName', this.TableName)
await readingImport(data)
this.$emit('close') this.$emit('close')
this.$message.success('导入成功!') this.$message.success('导入成功!')
loading.close() loading.close()
@@ -37,7 +37,7 @@
<div class="add-icon" @click.prevent="downloadTpl(item.LesionType)"> <div class="add-icon" @click.prevent="downloadTpl(item.LesionType)">
<i class="el-icon-download" /> <i class="el-icon-download" />
</div> </div>
<div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType)"> <div class="add-icon" style="margin: 0 5px;" @click.prevent="uploadTpl(item.LesionType, item.QuestionName)">
<i class="el-icon-upload2" /> <i class="el-icon-upload2" />
</div> </div>
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)"> <div class="add-icon" @click.prevent="handleAddOrEdit('add', item)">
@@ -169,7 +169,7 @@
<!-- 导入 --> <!-- 导入 -->
<el-dialog v-if="upload.visible" :visible.sync="upload.visible" :close-on-click-modal="false" <el-dialog v-if="upload.visible" :visible.sync="upload.visible" :close-on-click-modal="false"
:title="upload.title" width="500px"> :title="upload.title" width="500px">
<UploadExcel :visit-task-id="visitTaskId" :lesion-type="upload.lesionType" @close="uploadDlgClose" /> <UploadExcel :visit-task-id="visitTaskId" :lesion-type="upload.lesionType" :TableName="upload.TableName" @close="uploadDlgClose" />
</el-dialog> </el-dialog>
</div> </div>
</div> </div>
@@ -228,7 +228,7 @@ export default {
formChanged: false, formChanged: false,
digitPlaces: 2, digitPlaces: 2,
addOrEdit: { visible: false, title: '', lesionType: null }, addOrEdit: { visible: false, title: '', lesionType: null },
upload: { visible: false, title: '', lesionType: null }, upload: { visible: false, title: '', lesionType: null, TableName: '', },
qsList: [], qsList: [],
answersList: [], answersList: [],
qsForm: {}, qsForm: {},
@@ -669,8 +669,9 @@ export default {
console.log(e) console.log(e)
} }
}, },
uploadTpl(lesionType) { uploadTpl(lesionType, TableName) {
this.upload.lesionType = lesionType this.upload.lesionType = lesionType
this.upload.TableName = TableName
this.upload.title = `导入( ${this.$fd('LesionType', lesionType)} ` this.upload.title = `导入( ${this.$fd('LesionType', lesionType)} `
this.upload.visible = true this.upload.visible = true
}, },
@@ -33,7 +33,7 @@
</el-form> </el-form>
</template> </template>
<script> <script>
import { uploadOCTFCTTemplate, uploadOCTLipidAngleTemplate } from '@/api/reading' import { readingImport } from '@/api/reading'
export default { export default {
props: { props: {
visitTaskId: { visitTaskId: {
@@ -43,6 +43,10 @@ export default {
lesionType: { lesionType: {
type: Number, type: Number,
required: true required: true
},
TableName: {
type: String,
default: ''
} }
}, },
data() { data() {
@@ -67,10 +71,13 @@ export default {
var data = new FormData() var data = new FormData()
data.append('file', param.file) data.append('file', param.file)
data.append('visitTaskId', this.visitTaskId) data.append('visitTaskId', this.visitTaskId)
data.append('TableName', this.TableName)
if (this.lesionType === 112) { if (this.lesionType === 112) {
await uploadOCTFCTTemplate(data) data.append('readingImportType', 1)
await readingImport(data)
} else { } else {
await uploadOCTLipidAngleTemplate(data) data.append('readingImportType', 2)
await readingImport(data)
} }
this.$emit('close') this.$emit('close')
this.$message.success('导入成功!') this.$message.success('导入成功!')
@@ -353,7 +353,7 @@ export default {
validatorNumberInput(rule, value, callback) { validatorNumberInput(rule, value, callback) {
let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g') let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g')
if (value === '') { if (value === '') {
callback(new Error(this.$t('common:ruleMessage:specify'))); callback();
} else { } else {
if (!reg.test(value)) { if (!reg.test(value)) {
callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput'))); callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput')));
@@ -261,7 +261,7 @@ export default {
validatorNumberInput(rule, value, callback) { validatorNumberInput(rule, value, callback) {
let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g') let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g')
if (value === '') { if (value === '') {
callback(new Error(this.$t('common:ruleMessage:specify'))); callback();
} else { } else {
if (!reg.test(value)) { if (!reg.test(value)) {
callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput'))); callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput')));
@@ -407,7 +407,8 @@ export default {
// this.$set(v, 'xfIndex', i) // this.$set(v, 'xfIndex', i)
} }
if (v.Type === 'number') { if (v.Type === 'number') {
this.$set(this.questionForm, v.QuestionId, v.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : v.Answers[this.visitTaskId]) // this.$set(this.questionForm, v.QuestionId, v.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : v.Answers[this.visitTaskId])
this.$set(this.questionForm, v.QuestionId, v.Answers[this.visitTaskId])
} }
if (v.Childrens.length > 0) { if (v.Childrens.length > 0) {
this.setChild(v.Childrens) this.setChild(v.Childrens)
@@ -425,7 +426,8 @@ export default {
this.$set(this.questionForm, i.QuestionId, tableAnswers) this.$set(this.questionForm, i.QuestionId, tableAnswers)
} }
if (i.Type === 'number') { if (i.Type === 'number') {
this.$set(this.questionForm, i.QuestionId, i.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : i.Answers[this.visitTaskId]) // this.$set(this.questionForm, i.QuestionId, i.Answers[this.visitTaskId] === '' ? parseFloat(0).toFixed(this.digitPlaces) : i.Answers[this.visitTaskId])
this.$set(this.questionForm, i.QuestionId, i.Answers[this.visitTaskId])
} }
if (i.Childrens && i.Childrens.length > 0 && i.Type !== 'table' && i.Type !== 'basicTable') { if (i.Childrens && i.Childrens.length > 0 && i.Type !== 'table' && i.Type !== 'basicTable') {
this.setChild(i.Childrens) this.setChild(i.Childrens)
@@ -346,6 +346,7 @@ export default {
localStorage.setItem('digitPlaces', res.Result.DigitPlaces) localStorage.setItem('digitPlaces', res.Result.DigitPlaces)
localStorage.setItem('IsExistUnprocessedFeedback', res.Result.IsExistUnprocessedFeedback) localStorage.setItem('IsExistUnprocessedFeedback', res.Result.IsExistUnprocessedFeedback)
localStorage.setItem('taskInfo', JSON.stringify(res.Result)) localStorage.setItem('taskInfo', JSON.stringify(res.Result))
sessionStorage.setItem('taskInfo', JSON.stringify(res.Result))
this.readingCategory = res.Result.ReadingCategory this.readingCategory = res.Result.ReadingCategory
this.readingVersionEnum = res.Result.ReadingVersionEnum this.readingVersionEnum = res.Result.ReadingVersionEnum
this.questionFormChangeState = false this.questionFormChangeState = false
@@ -190,7 +190,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces')) const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.$nextTick(() => { this.$nextTick(() => {
@@ -280,11 +280,11 @@
> >
<svg-icon icon-class="refresh" class="svg-icon" /> <svg-icon icon-class="refresh" class="svg-icon" />
</div> </div>
<!-- 更多 --> <!-- 更多 :class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '']" -->
<div <div
v-if="criterionType === 0" v-if="criterionType === 0"
:title="$t('trials:reading:button:more')" :title="$t('trials:reading:button:more')"
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '']" :class="['tool-item']"
@click.stop="showPanel($event)" @click.stop="showPanel($event)"
@mouseleave="toolMouseout" @mouseleave="toolMouseout"
> >
@@ -297,7 +297,8 @@
<i class="el-icon-arrow-down" style="color:#fff;" /> <i class="el-icon-arrow-down" style="color:#fff;" />
</div> </div>
<div class="dropdown-content"> <div class="dropdown-content">
<ul v-if="readingTaskState < 2" style="width:100px;"> <!--v-if="readingTaskState < 2"-->
<ul style="width:100px;">
<li v-for="i in customizeStandards" :key="i.toolName" style="text-align:left;"> <li v-for="i in customizeStandards" :key="i.toolName" style="text-align:left;">
<a href="#" @click.prevent="setMoreToolActive(i.toolName)"> <a href="#" @click.prevent="setMoreToolActive(i.toolName)">
<svg-icon :icon-class="i.icon" class="svg-icon" style="margin-right: 5px;" /> <svg-icon :icon-class="i.icon" class="svg-icon" style="margin-right: 5px;" />
@@ -873,7 +874,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.isReadingTaskViewInOrder = this.taskInfo.IsReadingTaskViewInOrder this.isReadingTaskViewInOrder = this.taskInfo.IsReadingTaskViewInOrder
this.criterionType = this.taskInfo.CriterionType this.criterionType = this.taskInfo.CriterionType
const digitPlaces = Number(localStorage.getItem('digitPlaces')) const digitPlaces = Number(localStorage.getItem('digitPlaces'))
@@ -882,6 +883,7 @@ export default {
this.tools = getCustomizeStandardsTools(this.taskInfo.ReadingToolList) this.tools = getCustomizeStandardsTools(this.taskInfo.ReadingToolList)
const toolNames = this.tools.map(i => i.toolName) const toolNames = this.tools.map(i => i.toolName)
this.customizeStandards = config.customizeStandards.filter(item => !toolNames.includes(item.toolName)) this.customizeStandards = config.customizeStandards.filter(item => !toolNames.includes(item.toolName))
console.log(this.customizeStandards,'this.customizeStandards')
} else { } else {
this.tools = getTools(this.criterionType) this.tools = getTools(this.criterionType)
} }
@@ -1363,10 +1365,12 @@ export default {
const isCriticalSequence = this.visitTaskList[taskIndex].StudyList[studyIndex].IsCriticalSequence const isCriticalSequence = this.visitTaskList[taskIndex].StudyList[studyIndex].IsCriticalSequence
const keyImages = this.visitTaskList[taskIndex].KeyImages const keyImages = this.visitTaskList[taskIndex].KeyImages
const series = this.visitTaskList[taskIndex].StudyList[studyIndex].SeriesList[seriesIndex] const series = this.visitTaskList[taskIndex].StudyList[studyIndex].SeriesList[seriesIndex]
let file = series.find(item => item.ImageId === imageId) if (series && series.length > 0) {
if (file) { let file = series.find(item => item.ImageId === imageId)
getNetWorkSpeed() if (file) {
setNetWorkSpeedSizeAll(percentComplete, detail.total, imageId) getNetWorkSpeed()
setNetWorkSpeedSizeAll(percentComplete, detail.total, imageId)
}
} }
if (percentComplete === 100) { if (percentComplete === 100) {
workSpeedclose() workSpeedclose()
@@ -1508,14 +1512,32 @@ export default {
this.setToolsPassive() this.setToolsPassive()
}, },
annotationRemovedListener(e) { annotationRemovedListener(e) {
if (this.readingTaskState === 2) return
const { annotation } = e.detail const { annotation } = e.detail
if (!annotation) return try{
if (annotation.visitTaskId === this.taskInfo.VisitTaskId && annotation.seriesId) { if (!annotation) return
const index = this.markedSeriesIds.indexOf(annotation.seriesId) if (this. readingTaskState === 2 && !annotation.data.label) return false
if (index !== -1) { if (this.readingTaskState === 2) {
this.markedSeriesIds.splice(index, 1) const errorMsg = { message: 'annotation Not allowed to operate' }
throw errorMsg
} }
if (annotation.visitTaskId === this.taskInfo.VisitTaskId && annotation.seriesId) {
const index = this.markedSeriesIds.indexOf(annotation.seriesId)
if (index !== -1) {
this.markedSeriesIds.splice(index, 1)
}
} else {
const errorMsg = { message: 'annotation Not allowed to operate' }
throw errorMsg
}
} catch (e) {
cornerstoneTools.annotation.state.addAnnotation(annotation)
const renderingEngine = getRenderingEngine(renderingEngineId)
for (let i = 0; i < this.cells.length; i++) {
const viewportId = `${this.viewportKey}-${i}`
const viewport = renderingEngine.getViewport(viewportId)
viewport.render()
}
console.log(e)
} }
}, },
async customAnnotationCompletedListener(e) { async customAnnotationCompletedListener(e) {
@@ -1557,6 +1579,10 @@ export default {
} }
this.saveCustomAnnotationTimer = setTimeout(()=>{this.saveCustomAnnotation(annotation)},500) this.saveCustomAnnotationTimer = setTimeout(()=>{this.saveCustomAnnotation(annotation)},500)
} }
} else {
// if (this.isNumber(operateStateEnum)) {
// this.removeAnnotation(annotation)
// }
} }
} }
@@ -1631,6 +1657,7 @@ export default {
try { try {
// if ( this.resetAnnotation && this.isFusion ) return false // if ( this.resetAnnotation && this.isFusion ) return false
if (!annotation) return false if (!annotation) return false
if (this.readingTaskState === 2 && !annotation.data.label) return false
if (this.readingTaskState === 2) { if (this.readingTaskState === 2) {
const errorMsg = { message: 'annotation Not allowed to operate' } const errorMsg = { message: 'annotation Not allowed to operate' }
throw errorMsg throw errorMsg
@@ -1659,10 +1686,10 @@ export default {
) )
if (annotation.markId) { if (annotation.markId) {
let res = await deleteCustomTag(annotation.markId) let res = await deleteCustomTag(annotation.markId)
if (!res.IsSuccess) return false if (!res.IsSuccess) throw ''
}else if (annotation.id) { }else if (annotation.id) {
let res = await deleteCustomTag(annotation.id) let res = await deleteCustomTag(annotation.id)
if (!res.IsSuccess) return false if (!res.IsSuccess) throw ''
} }
} }
const index = this.markedSeriesIds.indexOf(annotation.seriesId) const index = this.markedSeriesIds.indexOf(annotation.seriesId)
@@ -2034,7 +2061,7 @@ export default {
}, },
// //
setAnnotateToolActive(toolName) { setAnnotateToolActive(toolName) {
if (this.readingTaskState === 2) return // if (this.readingTaskState === 2) return
const toolObj = this.tools.find(i => i.toolName === toolName) const toolObj = this.tools.find(i => i.toolName === toolName)
if (!toolObj || toolObj.isDisabled) return if (!toolObj || toolObj.isDisabled) return
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
@@ -2087,7 +2114,7 @@ export default {
} }
}, },
setMoreToolActive(toolName) { setMoreToolActive(toolName) {
if (this.readingTaskState === 2) return // if (this.readingTaskState === 2) return
this.setToolsPassive() this.setToolsPassive()
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) { if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
@@ -2124,7 +2151,10 @@ export default {
const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
const isCurrentTask = series.TaskInfo.IsCurrentTask const isCurrentTask = series.TaskInfo.IsCurrentTask
const readingTaskState = this.readingTaskState const readingTaskState = this.readingTaskState
if (!isCurrentTask || readingTaskState >= 2) { if (isCurrentTask && readingTaskState >= 2) {
this.tools[i].isDisabled = false
e.target.style.cursor = 'pointer'
} else if (!isCurrentTask || readingTaskState >= 2) {
this.tools[i].isDisabled = true this.tools[i].isDisabled = true
e.target.style.cursor = 'not-allowed' e.target.style.cursor = 'not-allowed'
if (this.activeTool) { if (this.activeTool) {
@@ -2941,11 +2971,22 @@ export default {
try { try {
const that = this const that = this
// //
const { value } = await this.$prompt(this.$t('trials:noneDicom:message:msg1'), '', { let message = this.$t('trials:noneDicom:message:msg1')
// if (isShowCancelButton) {
// message = `<div><p>${this.$t('trials:noneDicom:message:msg1')}</p><p style='font-size:12px' class='customPromptTip'>${this.$t('trials:noneDicom:message:saveTip')}</p></div>`
// }
const { value } = await this.$prompt( message, '', {
showClose: false, showClose: false,
cancelButtonText: isShowCancelButton ? this.$t('trials:reading:button:temporarySave') : this.$t('common:button:cancel'), cancelButtonText: isShowCancelButton ? this.$t('trials:reading:button:temporarySave') : this.$t('common:button:cancel'),
confirmButtonText: isShowCancelButton ? this.$t('trials:reading:button:enduringSave') : this.$t('trials:reading:button:relevancy'), confirmButtonText: isShowCancelButton ? this.$t('trials:reading:button:enduringSave') : this.$t('trials:reading:button:relevancy'),
// showCancelButton: isShowCancelButton, // showCancelButton: isShowCancelButton,
// dangerouslyUseHTMLString: isShowCancelButton,
inputValidator: (res) => {
if (!res) {
return isShowCancelButton ? this.$t('trials:noneDicom:message:saveTip') : this.$t('trials:noneDicom:message:saveTipByRelevancy')
}
},
inputErrorMessage: this.$t('trials:noneDicom:message:saveTip'),
showCancelButton: true, showCancelButton: true,
closeOnClickModal: false, closeOnClickModal: false,
closeOnPressEscape: false, closeOnPressEscape: false,
@@ -2965,7 +3006,8 @@ export default {
} }
}) })
return value return value
} catch { } catch(err) {
console.log(err)
return null return null
} }
}, },
@@ -3204,7 +3246,7 @@ export default {
try { try {
file = this.convertBase64ToBlob(file) file = this.convertBase64ToBlob(file)
const trialId = this.$route.query.trialId const trialId = this.$route.query.trialId
const taskInfo = JSON.parse(localStorage.getItem('taskInfo')) const taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const subjectId = taskInfo.SubjectId const subjectId = taskInfo.SubjectId
const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file) const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}.png`, file)
return { isSuccess: true, result: result } return { isSuccess: true, result: result }
@@ -235,7 +235,7 @@ export default {
mounted() { mounted() {
this.trialId = this.$route.query.trialId this.trialId = this.$route.query.trialId
this.visitTaskId = this.visitInfo.VisitTaskId this.visitTaskId = this.visitInfo.VisitTaskId
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.isBaseLineTask = this.taskInfo.IsBaseLine this.isBaseLineTask = this.taskInfo.IsBaseLine
this.criterionType = this.taskInfo.CriterionType this.criterionType = this.taskInfo.CriterionType
const digitPlaces = Number(localStorage.getItem('digitPlaces')) const digitPlaces = Number(localStorage.getItem('digitPlaces'))
@@ -327,7 +327,7 @@ export default {
}, },
created() { this.getTableHeight() }, created() { this.getTableHeight() },
mounted() { mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.criterionType = this.taskInfo.CriterionType this.criterionType = this.taskInfo.CriterionType
this.visitTaskId = this.taskInfo.VisitTaskId this.visitTaskId = this.taskInfo.VisitTaskId
this.isBaselineTask = this.taskInfo.IsBaseLine this.isBaselineTask = this.taskInfo.IsBaseLine
@@ -367,7 +367,7 @@ export default {
getTableHeight() { getTableHeight() {
this.height = window.innerHeight - 170 this.height = window.innerHeight - 170
}, },
async getReportInfo(IsCalculate) { async getReportInfo(IsCalculate = true) {
this.loading = true this.loading = true
try { try {
var params = { var params = {
@@ -153,7 +153,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces')) const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.studyList = this.visitTaskInfo.StudyList this.studyList = this.visitTaskInfo.StudyList
@@ -174,7 +174,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const digitPlaces = Number(localStorage.getItem('digitPlaces')) const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
this.$nextTick(() => { this.$nextTick(() => {
@@ -1,6 +1,6 @@
<template> <template>
<div class="visit-review-container"> <div class="visit-review-container">
<el-tabs v-model="activeName"> <el-tabs v-model="activeName" @tab-click="handleClick">
<!-- 阅片 --> <!-- 阅片 -->
<el-tab-pane v-if="taskInfo" :label="$t('trials:reading:tabTitle:review')" name="read"> <el-tab-pane v-if="taskInfo" :label="$t('trials:reading:tabTitle:review')" name="read">
<read-page ref="readPage" :reading-tool="readingTool" /> <read-page ref="readPage" :reading-tool="readingTool" />
@@ -12,11 +12,13 @@
name="report" name="report"
> >
<report-page <report-page
v-if="activeName === 'report' && taskInfo.CriterionType !== 0" v-if="taskInfo.CriterionType !== 0"
ref="reportPage"
@setReadingTaskState="setReadingTaskState" @setReadingTaskState="setReadingTaskState"
/> />
<customize-report-page <customize-report-page
v-if="activeName === 'report' && taskInfo.CriterionType === 0" v-if="taskInfo.CriterionType === 0"
ref="reportPage"
@setReadingTaskState="setReadingTaskState" @setReadingTaskState="setReadingTaskState"
/> />
</el-tab-pane> </el-tab-pane>
@@ -47,12 +49,16 @@ export default {
} }
}, },
mounted() { mounted() {
console.log(this.readingTool) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
}, },
methods: { methods: {
setReadingTaskState(state) { setReadingTaskState(state) {
this.$refs['readPage'].setReadingTaskState(state) this.$refs['readPage'].setReadingTaskState(state)
},
handleClick(tab) {
if (tab.name === 'report') {
this.$refs['reportPage'].getReportInfo()
}
} }
} }
} }
@@ -166,7 +166,7 @@
@input="numberInput(question.Id)" @input="numberInput(question.Id)"
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)" @blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
v-model="questionForm[question.Id]" v-model="questionForm[question.Id]"
:title="questionsMarkStatus[question.Id] ? questionsMarkStatus[question.Id].OrderMarkName : ''" :title="questionsMarkStatus[question.Id] ? questionsMarkStatus[question.Id].OrderMarkName : question.Remark"
:disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1" :disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1"
style="width: 150px;margin-right: 5px;"> style="width: 150px;margin-right: 5px;">
<template v-if="question.Unit !== 0" slot="append"> <template v-if="question.Unit !== 0" slot="append">
@@ -1255,18 +1255,22 @@ export default {
text: 'Loading', text: 'Loading',
spinner: 'el-icon-loading' spinner: 'el-icon-loading'
}) })
var fileName = param.file.name try {
var index = fileName.lastIndexOf('.') var fileName = param.file.name
var suffix = fileName.substring(index + 1, url.length) var index = fileName.lastIndexOf('.')
let file = await this.fileToBlob(param.file) var suffix = fileName.substring(index + 1, fileName.length)
// let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Customize/${this.visitTaskId}/${fileName}`, file) let file = await this.fileToBlob(param.file)
const taskInfo = JSON.parse(localStorage.getItem('taskInfo')) // let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Customize/${this.visitTaskId}/${fileName}`, file)
const subjectId = taskInfo.SubjectId const taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}`, file) const subjectId = taskInfo.SubjectId
this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${this.fileList.length + 1}(${suffix})`, url: this.$getObjectName(res.url) }) let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}`, file)
this.urls.push(this.$getObjectName(res.url)) this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${this.fileList.length + 1}(${suffix})`, url: this.$getObjectName(res.url) })
this.$emit("setFormItemData", { key: this.question.Id, val: this.urls.length > 0 ? this.urls.join('|') : '', question: this.question }) this.urls.push(this.$getObjectName(res.url))
this.$set(this.QuestionsForm, this.question.Id, this.urls.length > 0 ? this.urls.join('|') : '') this.$emit("setFormItemData", { key: this.question.Id, val: this.urls.length > 0 ? this.urls.join('|') : '', question: this.question })
this.$set(this.QuestionsForm, this.question.Id, this.urls.length > 0 ? this.urls.join('|') : '')
} catch (err) {
console.log(err)
}
loading.close() loading.close()
// uploadReadingAnswerImage(this.$route.query.trialId, this.visitTaskId, formData).then(res => { // uploadReadingAnswerImage(this.$route.query.trialId, this.visitTaskId, formData).then(res => {
// if (res.IsSuccess) { // if (res.IsSuccess) {
@@ -114,7 +114,7 @@ export default {
window.addEventListener('message', this.receiveMsg) window.addEventListener('message', this.receiveMsg)
this.trialId = this.$route.query.trialId this.trialId = this.$route.query.trialId
this.visitTaskId = this.visitInfo.VisitTaskId this.visitTaskId = this.visitInfo.VisitTaskId
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.isBaseLineTask = this.taskInfo.IsBaseLine this.isBaseLineTask = this.taskInfo.IsBaseLine
this.criterionId = this.taskInfo.TrialReadingCriterionId this.criterionId = this.taskInfo.TrialReadingCriterionId
const digitPlaces = Number(localStorage.getItem('digitPlaces')) const digitPlaces = Number(localStorage.getItem('digitPlaces'))
@@ -242,6 +242,7 @@ export default {
async handleSubmit() { async handleSubmit() {
const valid = await this.$refs['questions'].validate() const valid = await this.$refs['questions'].validate()
if (!valid) return if (!valid) return
await this.handleSave(false)
await verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId }) await verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId })
const { ImageAssessmentReportConfirmation } = const_.processSignature const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation this.signCode = ImageAssessmentReportConfirmation
@@ -85,7 +85,7 @@
@input="numberInput(question.Id)" @input="numberInput(question.Id)"
@blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)" @blur="questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked ? () => { } : handleMarkedQsBlur(questionForm[question.Id], questionForm, question.Id, question)"
v-model="questionForm[question.Id]" v-model="questionForm[question.Id]"
:title="questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].OrderMarkName : ''" :title="questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id] ? questionsMarkStatus[rowId ? `${rowId}_${question.Id}` : question.Id].OrderMarkName : question.Remark"
:disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1" :disabled="(questionsMarkStatus[question.Id] && questionsMarkStatus[question.Id].isMarked && question.ImageMarkEnum === 2) || question.ImageMarkEnum === 1"
style="width: 150px;margin-right: 5px;"> style="width: 150px;margin-right: 5px;">
<template v-if="question.Unit !== 0" slot="append"> <template v-if="question.Unit !== 0" slot="append">
@@ -308,7 +308,7 @@ export default {
validatorNumberInput(rule, value, callback) { validatorNumberInput(rule, value, callback) {
let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g') let reg = new RegExp(/^(?:-?(?:(?:0|[1-9]\d*)(?:\.\d+)?|\.\d+)|NE)$/, 'g')
if (value === '') { if (value === '') {
callback(new Error(this.$t('common:ruleMessage:specify'))); callback();
} else { } else {
if (!reg.test(value)) { if (!reg.test(value)) {
callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput'))); callback(new Error(this.$t('trials:reading:ruleMessage:validatorNumberInput')));
@@ -344,6 +344,7 @@ export default {
} else { } else {
this.$emit('setFormItemData', { key: question.Id, val: v, question: question }) this.$emit('setFormItemData', { key: question.Id, val: v, question: question })
} }
this.$emit('formItemTableNumberChange', v, question)
}, },
handleBlur(value, a, b) { handleBlur(value, a, b) {
if (!value) return false if (!value) return false
@@ -562,7 +563,7 @@ export default {
var suffix = fileName.substring(index + 1, fileName.length) var suffix = fileName.substring(index + 1, fileName.length)
var file = await this.fileToBlob(param.file) var file = await this.fileToBlob(param.file)
// let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Customize/${this.visitTaskId}/${fileName}`, file) // let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Customize/${this.visitTaskId}/${fileName}`, file)
const taskInfo = JSON.parse(localStorage.getItem('taskInfo')) const taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
const subjectId = taskInfo.SubjectId const subjectId = taskInfo.SubjectId
let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}`, file) let res = await this.OSSclient.put(`/${this.$route.query.trialId}/Read/${subjectId}/${this.visitTaskId}/${fileName}`, file)
this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${this.fileList.length + 1}(${suffix})`, url: this.$getObjectName(res.url) }) this.fileList.push({ name: `${this.$t('trials:emailManageCfg:title:fileName')}${this.fileList.length + 1}(${suffix})`, url: this.$getObjectName(res.url) })
@@ -275,7 +275,7 @@ export default {
} }
}, },
async mounted() { async mounted() {
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.trialId = this.$route.query.trialId this.trialId = this.$route.query.trialId
this.visitTaskId = this.taskInfo.VisitTaskId this.visitTaskId = this.taskInfo.VisitTaskId
this.subjectId = this.taskInfo.SubjectId this.subjectId = this.taskInfo.SubjectId
@@ -263,7 +263,7 @@ export default {
} }
}, },
mounted() { mounted() {
let digitPlaces = Number(localStorage.getItem('digitPlaces')) let digitPlaces = Number(sessionStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
}, },
methods: { methods: {
@@ -276,7 +276,7 @@ export default {
mounted() { mounted() {
this.trialId = this.$route.query.trialId this.trialId = this.$route.query.trialId
this.visitTaskId = this.visitInfo.VisitTaskId this.visitTaskId = this.visitInfo.VisitTaskId
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo')) this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
this.isBaseLineTask = this.taskInfo.IsBaseLine this.isBaseLineTask = this.taskInfo.IsBaseLine
this.criterionType = this.taskInfo.CriterionType this.criterionType = this.taskInfo.CriterionType
const digitPlaces = Number(localStorage.getItem('digitPlaces')) const digitPlaces = Number(localStorage.getItem('digitPlaces'))
@@ -292,7 +292,16 @@ const config = {
'i18nKey': 'trials:reading:button:CobbAngle', 'i18nKey': 'trials:reading:button:CobbAngle',
'isDisabled': false, 'isDisabled': false,
'disabledReason': '' 'disabledReason': ''
} },
{
'name': '自由曲线',
'icon': 'polygon',
'toolName': 'PlanarFreehandROI',
'props': ['radius', 'area', 'mean', 'max', 'stdDev'],
'i18nKey': 'trials:reading:button:planarFreehandROI',
'isDisabled': false,
'disabledReason': ''
},
], ],
'customizeStandardsNoneDicom': [ 'customizeStandardsNoneDicom': [
{ {
@@ -70,6 +70,7 @@ export default {
} }
const res = await getNextTask(params) const res = await getNextTask(params)
this.taskInfo = res.Result this.taskInfo = res.Result
sessionStorage.setItem('taskInfo', JSON.stringify(res.Result))
localStorage.setItem('taskInfo', JSON.stringify(res.Result)) localStorage.setItem('taskInfo', JSON.stringify(res.Result))
localStorage.setItem('digitPlaces', JSON.stringify(res.Result.DigitPlaces)) localStorage.setItem('digitPlaces', JSON.stringify(res.Result.DigitPlaces))
this.loading = false this.loading = false
@@ -285,6 +285,7 @@ export default {
async handleSubmit() { async handleSubmit() {
const valid = await this.$refs['questions'].validate() const valid = await this.$refs['questions'].validate()
if (!valid) return if (!valid) return
await this.handleSave()
const { ImageAssessmentReportConfirmation } = const_.processSignature const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation this.signCode = ImageAssessmentReportConfirmation
this.signVisible = true this.signVisible = true
@@ -93,6 +93,7 @@ export default {
const res = await getNextTask(params) const res = await getNextTask(params)
this.taskInfo = res.Result this.taskInfo = res.Result
localStorage.setItem('taskInfo', JSON.stringify(res.Result)) localStorage.setItem('taskInfo', JSON.stringify(res.Result))
sessionStorage.setItem('taskInfo', JSON.stringify(res.Result))
localStorage.setItem('digitPlaces', JSON.stringify(res.Result.DigitPlaces)) localStorage.setItem('digitPlaces', JSON.stringify(res.Result.DigitPlaces))
this.loading = false this.loading = false
this.$nextTick(() => { this.$nextTick(() => {
@@ -130,18 +130,9 @@
<el-table-column prop="OriginalReReadingTask.SubjectCode" :label="$t('trials:rereadTrack:table:subjectCode')" <el-table-column prop="OriginalReReadingTask.SubjectCode" :label="$t('trials:rereadTrack:table:subjectCode')"
min-width="120" sortable="custom" show-overflow-tooltip> min-width="120" sortable="custom" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<span v-if=" <span>
scope.row.OriginalReReadingTask.MedicalNo && {{ getSubjectCode(scope.row.OriginalReReadingTask) }}
scope.row.OriginalReReadingTask.MedicalNo !==
scope.row.OriginalReReadingTask.SubjectCode
">
{{
`${scope.row.OriginalReReadingTask.SubjectCode}/${scope.row.OriginalReReadingTask.MedicalNo}`
}}
</span> </span>
<span v-else>{{
scope.row.OriginalReReadingTask.SubjectCode
}}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 任务名称 --> <!-- 任务名称 -->
@@ -385,7 +376,8 @@
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item :label="$t('trials:reviewTrack:dialog:backImpactList')" /> <el-form-item :label="$t('trials:reviewTrack:dialog:backImpactList')" />
<el-table v-loading="loading" :data="InfluenceTaskList" stripe height="100" style="min-height:200px;max-height: 300px"> <el-table v-loading="loading" :data="InfluenceTaskList" stripe height="100"
style="min-height:200px;max-height: 300px">
<!-- 任务编号 --> <!-- 任务编号 -->
<el-table-column prop="TaskCode" :label="$t('trials:reviewTrack:table:taskCode')" min-width="100" <el-table-column prop="TaskCode" :label="$t('trials:reviewTrack:table:taskCode')" min-width="100"
show-overflow-tooltip /> show-overflow-tooltip />
@@ -873,6 +865,16 @@ export default {
this.getTrialCriterionList() this.getTrialCriterionList()
}, },
methods: { methods: {
getSubjectCode(obj) {
let str = obj.SubjectCode
if (obj.MedicalNo && obj.MedicalNo !== obj.SubjectCode) {
str += `/${obj.MedicalNo}`
}
if (obj.BlindSubjectCode && obj.BlindSubjectCode !== obj.SubjectCode) {
str += `/${obj.BlindSubjectCode}`
}
return str
},
async auditImageBack() { async auditImageBack() {
try { try {
console.log(this.form) console.log(this.form)
@@ -45,7 +45,7 @@
<el-input <el-input
v-model="scope.row.CDISCCode" v-model="scope.row.CDISCCode"
size="mini" size="mini"
:disabled="scope.row.HasChildren || (scope.row.IsTableQuestion && exportInfo.CriterionType !== 0)" :disabled="scope.row.HasChildren || (scope.row.IsTableQuestion && exportInfo.CriterionType !== 0 && exportInfo.CriterionGroup !== 0)"
v-show="!scope.row.IsGroup || !scope.row.HasChildren" v-show="!scope.row.IsGroup || !scope.row.HasChildren"
> >
</el-input> </el-input>
@@ -152,7 +152,7 @@ export default {
} else if ((this.exportInfo.CriterionGroup === 0 || this.exportInfo.CriterionType === 0 ) && item.Code === 1 && (row.HasChildren || row.IsTableQuestion)) { } else if ((this.exportInfo.CriterionGroup === 0 || this.exportInfo.CriterionType === 0 ) && item.Code === 1 && (row.HasChildren || row.IsTableQuestion)) {
// (1) // (1)
return true return true
} else if (item.Code === 8 && (row.HasChildren || (row.IsTableQuestion && this.exportInfo.CriterionType !== 0))) { } else if ( item.Code === 8 && (row.HasChildren || (row.IsTableQuestion && this.exportInfo.CriterionType !== 0 && this.exportInfo.CriterionGroup !== 0) )) {
// else if (item.Code === 8 && (row.HasChildren || row.IsTableQuestion)) // else if (item.Code === 8 && (row.HasChildren || row.IsTableQuestion))
// CDISC // CDISC
return true return true
@@ -340,7 +340,7 @@
<el-table-column fixed="right" :label="$t('common:action:action')" width="220"> <el-table-column fixed="right" :label="$t('common:action:action')" width="220">
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 查看阅片结果 --> <!-- 查看阅片结果 -->
<el-button :disabled="scope.row.ReadingTaskState !== 2 && scope.row.IsSubjectQuit" icon="el-icon-view" <el-button :disabled="scope.row.ReadingTaskState !== 2" icon="el-icon-view"
circle :title="$t('trials:reviewTrack:action:viewResults')" @click="lookReadingResults(scope.row)" /> circle :title="$t('trials:reviewTrack:action:viewResults')" @click="lookReadingResults(scope.row)" />
<!-- 申请重阅 --> <!-- 申请重阅 -->
<el-button :disabled="scope.row.ReadingCategory !== 1 || <el-button :disabled="scope.row.ReadingCategory !== 1 ||
@@ -215,6 +215,7 @@ export default {
async handleSubmit() { async handleSubmit() {
const valid = await this.$refs['questions'].validate() const valid = await this.$refs['questions'].validate()
if (!valid) return if (!valid) return
await this.handleSave(false)
await verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId }) await verifyVisitTaskQuestions({ visitTaskId: this.visitTaskId })
const { ImageAssessmentReportConfirmation } = const_.processSignature const { ImageAssessmentReportConfirmation } = const_.processSignature
this.signCode = ImageAssessmentReportConfirmation this.signCode = ImageAssessmentReportConfirmation
@@ -45,9 +45,8 @@
> >
<svg-icon icon-class="polygon" class="svg-icon" /> <svg-icon icon-class="polygon" class="svg-icon" />
</div> --> </div> -->
<!--readingTaskState === 2 ? 'tool-disabled' : '',-->
<div <div :class="['tool-item', activeTool === 'Eraser' ? 'tool-item-active' : '']"
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Eraser' ? 'tool-item-active' : '']"
:title="$t('trials:dicom-show:Eraser')" @click.prevent="setAnnotateToolActive('Eraser')"> :title="$t('trials:dicom-show:Eraser')" @click.prevent="setAnnotateToolActive('Eraser')">
<svg-icon icon-class="clear" class="svg-icon" /> <svg-icon icon-class="clear" class="svg-icon" />
</div> </div>
@@ -69,17 +68,17 @@
<div class="tool-item" :title="$t('trials:reading:button:reset')" @click.prevent="resetViewport"> <div class="tool-item" :title="$t('trials:reading:button:reset')" @click.prevent="resetViewport">
<svg-icon icon-class="refresh" class="svg-icon" /> <svg-icon icon-class="refresh" class="svg-icon" />
</div> </div>
<!-- 更多 --> <!-- 更多:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '']" -->
<div v-if="criterionType === 0" :title="$t('trials:reading:button:more')" <div v-if="criterionType === 0" :title="$t('trials:reading:button:more')" :class="['tool-item']"
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '']" @click.stop="showPanel($event)" @click.stop="showPanel($event)" @mouseleave="toolMouseout">
@mouseleave="toolMouseout">
<div class="dropdown"> <div class="dropdown">
<div class="icon" data-tool="more"> <div class="icon" data-tool="more">
<svg-icon icon-class="more" class="svg-icon" /> <svg-icon icon-class="more" class="svg-icon" />
<i class="el-icon-arrow-down" style="color:#fff;" /> <i class="el-icon-arrow-down" style="color:#fff;" />
</div> </div>
<div class="dropdown-content"> <div class="dropdown-content">
<ul v-if="readingTaskState < 2" style="width:100px;"> <!--v-if="readingTaskState < 2"-->
<ul style="width:100px;">
<li v-for="i in customizeStandardsNoneDicom" :key="i.toolName" style="text-align:left;"> <li v-for="i in customizeStandardsNoneDicom" :key="i.toolName" style="text-align:left;">
<a href="#" @click.prevent="setAnnotateToolActive(i.toolName)"> <a href="#" @click.prevent="setAnnotateToolActive(i.toolName)">
<svg-icon :icon-class="i.icon" class="svg-icon" style="margin-right: 5px;" /> <svg-icon :icon-class="i.icon" class="svg-icon" style="margin-right: 5px;" />
@@ -854,7 +853,8 @@ export default {
}, },
// //
setAnnotateToolActive(toolName) { setAnnotateToolActive(toolName) {
if (this.readingTaskState === 2) return // if (this.readingTaskState === 2) return
if (this.readingTaskState === 2 && toolName === 'Lengthscale') return
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex) const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
if (i === -1) return if (i === -1) return
if (this.viewportInfos[i].taskInfo.VisitTaskId === this.taskInfo.VisitTaskId) { if (this.viewportInfos[i].taskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
@@ -921,25 +921,41 @@ export default {
) )
}, },
async annotationRemovedListener(e) { async annotationRemovedListener(e) {
if (this.readingTaskState === 2) return
const { annotation } = e.detail const { annotation } = e.detail
if (!annotation) return try {
if (annotation.annotationId) { if (!annotation) return
await deleteTrialFileType(annotation.annotationId) if (this.readingTaskState === 2 && !annotation.annotationId) {
} else { cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID) return false
} }
const renderingEngine = getRenderingEngine(renderingEngineId) if (this.readingTaskState === 2) {
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`) const errorMsg = { message: 'annotation Not allowed to operate' }
viewport.render() throw errorMsg
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex) }
const imageId = annotation.metadata.referencedImageId if (annotation.annotationId) {
const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1] await deleteTrialFileType(annotation.annotationId)
const fileList = this.viewportInfos[i].fileList } else {
const fileIndex = fileList.findIndex(f => f.Path === path) cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
if (annotation.metadata.toolName === 'Lengthscale') { }
this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: null }) const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
viewport.render()
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
const imageId = annotation.metadata.referencedImageId
const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
const fileList = this.viewportInfos[i].fileList
const fileIndex = fileList.findIndex(f => f.Path === path)
if (annotation.metadata.toolName === 'Lengthscale') {
this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: null })
}
} catch (e) {
cornerstoneTools.annotation.state.addAnnotation(annotation)
const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
viewport.render()
console.log(e)
} }
}, },
async annotationModifiedListener(e) { async annotationModifiedListener(e) {
console.log('Modified') console.log('Modified')
@@ -12,7 +12,7 @@
<!-- 文件 --> <!-- 文件 -->
<el-form-item :label="$t('trials:attachment:form:file')"> <el-form-item :label="$t('trials:attachment:form:file')">
<div class="upload-container"> <div class="upload-container">
<el-upload class="upload-demo" action accept=".pdf,.mp4" :before-upload="beforeUpload" <el-upload class="upload-demo" action accept=".pdf" :before-upload="beforeUpload"
:http-request="handleUploadFile" :on-remove="handleRemoveFile" :show-file-list="true" :file-list="fileList" :http-request="handleUploadFile" :on-remove="handleRemoveFile" :show-file-list="true" :file-list="fileList"
:limit="1" :on-exceed="handleExceed" :disabled="form.FileTypeId === ''"> :limit="1" :on-exceed="handleExceed" :disabled="form.FileTypeId === ''">
<el-button size="small" type="primary" :disabled="form.FileTypeId === '' || saveBtnLoading" <el-button size="small" type="primary" :disabled="form.FileTypeId === '' || saveBtnLoading"
@@ -218,7 +218,7 @@ export default {
}, },
// pdf // pdf
checkFileSuffix(fileName) { checkFileSuffix(fileName) {
var typeArr = ['pdf', 'mp4'] var typeArr = ['pdf']
var extendName = fileName.substring(fileName.lastIndexOf('.') + 1).toLocaleLowerCase() var extendName = fileName.substring(fileName.lastIndexOf('.') + 1).toLocaleLowerCase()
if (typeArr.indexOf(extendName) !== -1) { if (typeArr.indexOf(extendName) !== -1) {
return true return true
@@ -143,6 +143,7 @@ export default {
},] },]
}, },
NODE_ENV: process.env.NODE_ENV, NODE_ENV: process.env.NODE_ENV,
VUE_APP_OSS_PATH: process.env.VUE_APP_OSS_PATH,
} }
}, },
// watch: { // watch: {
@@ -151,10 +152,20 @@ export default {
// } // }
// }, // },
created() { created() {
if(this.NODE_ENV === 'production'){ if(this.VUE_APP_OSS_PATH === '/uat/dist'){
this.form= {
EmailFromEmail: 'uat@extimaging.com',
EmailFromName: 'Uat IRC Imaging System',
EmailAuthorizationCode: 'SHzyyl2021',
EmailSMTPServerAddress: 'smtp.qiye.aliyun.com',
EmailSMTPServerPort: 465,
IsConfigureEmail: true
};
}
if(this.VUE_APP_OSS_PATH === '/test/dist'){
this.form= { this.form= {
EmailFromEmail: 'test@extimaging.com', EmailFromEmail: 'test@extimaging.com',
EmailFromName: 'Test_IRC', EmailFromName: 'Test IRC Imaging System',
EmailAuthorizationCode: 'SHzyyl2021', EmailAuthorizationCode: 'SHzyyl2021',
EmailSMTPServerAddress: 'smtp.qiye.aliyun.com', EmailSMTPServerAddress: 'smtp.qiye.aliyun.com',
EmailSMTPServerPort: 465, EmailSMTPServerPort: 465,
File diff suppressed because it is too large Load Diff
@@ -245,6 +245,10 @@
v-show="false" crossorigin="anonymous" alt=""> v-show="false" crossorigin="anonymous" alt="">
</viewer> </viewer>
<div v-else-if="scope.row.DataType === 'Dialog'" v-html="scope.row.oldValue"></div> <div v-else-if="scope.row.DataType === 'Dialog'" v-html="scope.row.oldValue"></div>
<el-button v-else-if="isFile(scope.row.oldValue)" type="text" size="small"
@click.stop="download(scope.row.oldValue)">
{{ $t('common:button:download') }}
</el-button>
<span v-else> <span v-else>
{{ scope.row.oldValue }} {{ scope.row.oldValue }}
</span> </span>
@@ -284,6 +288,10 @@
<!-- <img :src="scope.row.newValue" v-show="false" crossorigin="anonymous" alt="">--> <!-- <img :src="scope.row.newValue" v-show="false" crossorigin="anonymous" alt="">-->
</viewer> </viewer>
<div v-else-if="scope.row.DataType === 'Dialog'" v-html="scope.row.newValue"></div> <div v-else-if="scope.row.DataType === 'Dialog'" v-html="scope.row.newValue"></div>
<el-button v-else-if="isFile(scope.row.newValue)" type="text" size="small"
@click.stop="download(scope.row.newValue)">
{{ $t('common:button:download') }}
</el-button>
<span v-else>{{ scope.row.newValue }}</span> <span v-else>{{ scope.row.newValue }}</span>
</span> </span>
</template> </template>
@@ -630,6 +638,7 @@ import Pagination from '@/components/Pagination'
import BaseContainer from '@/components/BaseContainer' import BaseContainer from '@/components/BaseContainer'
import BaseModel from '@/components/BaseModel' import BaseModel from '@/components/BaseModel'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { downLoadFile } from '@/utils/stream.js'
const searchDataDefault = () => { const searchDataDefault = () => {
return { return {
SortField: 'CreateTime', SortField: 'CreateTime',
@@ -711,6 +720,22 @@ export default {
this.getModuleTypeList() this.getModuleTypeList()
}, },
methods: { methods: {
isFile(str) {
return str && Object.prototype.toString.call(str) === "[object String]" && !!~str.indexOf('❄❅❆❇❈❉❊')
},
async download(str) {
str = str.replace("❄❅❆❇❈❉❊", '')
let urls = str.split("|")
let name = `${Date.now()}.zip`, files = []
urls.forEach(url => {
let obj = {
url: this.OSSclientConfig.basePath + url,
name: url.split("/")[url.split("/").length - 1]
}
files.push(obj)
})
await downLoadFile(files, name, 'zip')
},
openImage(url, type) { openImage(url, type) {
console.log(url) console.log(url)
@@ -33,6 +33,10 @@
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportImage'])"> v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportImage'])">
{{ $t('trials:imageSummary:button:export_dicom') }} {{ $t('trials:imageSummary:button:export_dicom') }}
</el-button> </el-button>
<el-button type="primary" @click="handleExportImage(false, true)" :disabled="selectArr.length <= 0"
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportImage'])">
{{ $t('trials:imageSummary:button:export_readingDicom') }}
</el-button>
<el-button type="primary" @click="handleExportImage(true)" :disabled="selectArr.length <= 0" <el-button type="primary" @click="handleExportImage(true)" :disabled="selectArr.length <= 0"
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportKeyImage'])"> v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportKeyImage'])">
{{ $t('trials:imageSummary:button:export_image') }} {{ $t('trials:imageSummary:button:export_image') }}
@@ -66,10 +70,10 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-if="scope.row.IsHaveDicom" type="primary">{{ <el-tag v-if="scope.row.IsHaveDicom" type="primary">{{
$fd('IsDicom', true) $fd('IsDicom', true)
}}</el-tag> }}</el-tag>
<el-tag v-if="scope.row.IsHaveNoneDicom" type="primary">{{ <el-tag v-if="scope.row.IsHaveNoneDicom" type="primary">{{
$fd('IsDicom', false) $fd('IsDicom', false)
}}</el-tag> }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<!-- 影像数量 --> <!-- 影像数量 -->
@@ -79,6 +83,10 @@
<el-table-column prop="TotalImageSizeStr" min-width="120" <el-table-column prop="TotalImageSizeStr" min-width="120"
:label="$t('trials:imageSummary:table:TotalImageSizeStr')" show-overflow-tooltip :label="$t('trials:imageSummary:table:TotalImageSizeStr')" show-overflow-tooltip
sortable="custom" /> sortable="custom" />
<!-- 阅片影像大小 -->
<el-table-column prop="TotalReadingImageSizeStr" min-width="120"
:label="$t('trials:imageSummary:table:TotalReadingImageSizeStr')" show-overflow-tooltip
sortable="custom" />
<!-- 最早拍片日期 --> <!-- 最早拍片日期 -->
<el-table-column prop="EarliestScanDate" min-width="120" <el-table-column prop="EarliestScanDate" min-width="120"
:label="$t('trials:imageSummary:table:EarliestScanDate')" show-overflow-tooltip sortable="custom" /> :label="$t('trials:imageSummary:table:EarliestScanDate')" show-overflow-tooltip sortable="custom" />
@@ -102,7 +110,9 @@
<span>{{ $t('trials:imageSummary:remark:SubjectImageAVGSizeStr') }}</span> <span>{{ $t('trials:imageSummary:remark:SubjectImageAVGSizeStr') }}</span>
<span class="size">{{ image_size.SubjectImageAVGSizeStr }} </span>, <span class="size">{{ image_size.SubjectImageAVGSizeStr }} </span>,
<span>{{ $t('trials:imageSummary:remark:SubjectVisitImageAVGSizeStr') }}</span> <span>{{ $t('trials:imageSummary:remark:SubjectVisitImageAVGSizeStr') }}</span>
<span class="size">{{ image_size.SubjectVisitImageAVGSizeStr }}</span>, <span class="size">{{ image_size.SubjectVisitImageAVGSizeStr }}</span><span>{{ `; ` }}</span>
<span>{{ $t('trials:imageSummary:remark:TotalReadingImageSizeStr') }}</span>
<span class="size">{{ image_size.TotalReadingImageSizeStr }} </span><span>{{ `; ` }}</span>
<span>{{ $t('trials:imageSummary:remark:CheckImageSize') }}</span> <span>{{ $t('trials:imageSummary:remark:CheckImageSize') }}</span>
<span class="size">{{ image_size.CheckImageSize }} </span> <span class="size">{{ image_size.CheckImageSize }} </span>
</div> </div>
@@ -144,6 +154,7 @@ export default {
TotalImageSizeStr: null, TotalImageSizeStr: null,
SubjectImageAVGSizeStr: null, SubjectImageAVGSizeStr: null,
SubjectVisitImageAVGSizeStr: null, SubjectVisitImageAVGSizeStr: null,
TotalReadingImageSizeStr: null,
CheckImageSize: null CheckImageSize: null
} }
} }
@@ -179,11 +190,12 @@ export default {
} }
}, },
// //
async handleExportImage(IsKeyImage = false) { async handleExportImage(IsKeyImage = false, IsExportReading = false) {
try { try {
let data = { let data = {
TrialId: this.$route.query.trialId, TrialId: this.$route.query.trialId,
IsKeyImage IsKeyImage,
IsExportReading
} }
data.SubjectVisitIdList = this.selectArr.map(item => item.SubjectVisitId) data.SubjectVisitIdList = this.selectArr.map(item => item.SubjectVisitId)
if (!IsKeyImage) { if (!IsKeyImage) {
@@ -223,8 +235,9 @@ export default {
serie.InstancePathList.forEach(instance => { serie.InstancePathList.forEach(instance => {
let instanceArr = instance.Path.split("/") let instanceArr = instance.Path.split("/")
let fileName = instanceArr[instanceArr.length - 1] let fileName = instanceArr[instanceArr.length - 1]
let time = study.StudyTime.split(' ')[0]
let obj = { let obj = {
name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${study.StudyCode}_${study.StudyTime}_${serie.Modality}/${fileName}`, name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${study.StudyCode}_${time}_${serie.Modality}/IMAGE/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path, url: this.OSSclientConfig.basePath + instance.Path,
} }
files.push(obj) files.push(obj)
@@ -238,8 +251,9 @@ export default {
visit.NoneDicomStudyList.forEach(noneDicomStudy => { visit.NoneDicomStudyList.forEach(noneDicomStudy => {
if (noneDicomStudy.FileList && noneDicomStudy.FileList.length > 0) { if (noneDicomStudy.FileList && noneDicomStudy.FileList.length > 0) {
noneDicomStudy.FileList.forEach(file => { noneDicomStudy.FileList.forEach(file => {
let time = noneDicomStudy.ImageDate.split(' ')[0]
let obj = { let obj = {
name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${noneDicomStudy.StudyCode}_${noneDicomStudy.ImageDate}_${noneDicomStudy.Modality}/${file.FileName}`, name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${noneDicomStudy.StudyCode}_${time}_${noneDicomStudy.Modality}/${file.FileName}`,
url: this.OSSclientConfig.basePath + file.Path, url: this.OSSclientConfig.basePath + file.Path,
} }
files.push(obj) files.push(obj)
@@ -287,6 +301,7 @@ export default {
this.image_size.TotalImageSizeStr = res.Result.TotalImageSizeStr; this.image_size.TotalImageSizeStr = res.Result.TotalImageSizeStr;
this.image_size.SubjectImageAVGSizeStr = res.Result.SubjectImageAVGSizeStr; this.image_size.SubjectImageAVGSizeStr = res.Result.SubjectImageAVGSizeStr;
this.image_size.SubjectVisitImageAVGSizeStr = res.Result.SubjectVisitImageAVGSizeStr; this.image_size.SubjectVisitImageAVGSizeStr = res.Result.SubjectVisitImageAVGSizeStr;
this.image_size.TotalReadingImageSizeStr = res.Result.TotalReadingImageSizeStr;
} }
} catch (err) { } catch (err) {
this.loading = false this.loading = false
@@ -307,7 +322,7 @@ export default {
handleSelectionChange(selection) { handleSelectionChange(selection) {
this.selectArr = selection this.selectArr = selection
let num = this.selectArr.reduce((sum, item) => sum + item.TotalImageSize, 0) let num = this.selectArr.reduce((sum, item) => sum + item.TotalImageSize, 0)
if (num <= 0) return this.image_size.CheckImageSize = null if (num <= 0) return this.image_size.CheckImageSize = `0MB`
this.image_size.CheckImageSize = this.$FormatSize(num) this.image_size.CheckImageSize = this.$FormatSize(num)
}, },
// site // site
@@ -89,7 +89,7 @@
<div class="function"> <div class="function">
<!-- 申请重传 --> <!-- 申请重传 -->
<el-button <el-button
v-show="ReuploadEnum === 0 || ReuploadEnum === 3" v-show="(ReuploadEnum === 0 || ReuploadEnum === 3) && data.SecondReviewState !== 1"
v-hasPermi="['trials:trials-panel:visit:crc-upload:apply-reupload']" v-hasPermi="['trials:trials-panel:visit:crc-upload:apply-reupload']"
type="primary" type="primary"
@click="handleCRCApplyReupload" @click="handleCRCApplyReupload"
@@ -98,7 +98,7 @@
</el-button> </el-button>
<!-- 重传 --> <!-- 重传 -->
<el-button <el-button
v-show="ReuploadEnum === 2" v-show="ReuploadEnum === 2 && data.SecondReviewState !== 1"
v-hasPermi="['trials:trials-panel:visit:crc-upload:reupload']" v-hasPermi="['trials:trials-panel:visit:crc-upload:reupload']"
type="primary" type="primary"
:loading="uploadBtnLoading" :loading="uploadBtnLoading"
@@ -90,7 +90,7 @@
<div class="function"> <div class="function">
<!-- 申请重传 --> <!-- 申请重传 -->
<el-button <el-button
v-show="item.ReuploadEnum === 0 || item.ReuploadEnum === 3" v-show="(item.ReuploadEnum === 0 || item.ReuploadEnum === 3) && item.SecondReviewState !== 1"
v-hasPermi="[ v-hasPermi="[
'trials:trials-panel:visit:crc-upload:apply-reupload', 'trials:trials-panel:visit:crc-upload:apply-reupload',
]" ]"
@@ -102,7 +102,7 @@
</el-button> </el-button>
<!-- 重传 --> <!-- 重传 -->
<el-button <el-button
v-show="item.ReuploadEnum === 2" v-show="item.ReuploadEnum === 2 && item.SecondReviewState !== 1"
v-hasPermi="['trials:trials-panel:visit:crc-upload:reupload']" v-hasPermi="['trials:trials-panel:visit:crc-upload:reupload']"
type="primary" type="primary"
:loading="uploadBtnLoading" :loading="uploadBtnLoading"
@@ -398,6 +398,7 @@ export default {
Content: item.Content, Content: item.Content,
DeadlineTime: item.DeadlineTime, DeadlineTime: item.DeadlineTime,
IsOverTime: item.IsOverTime, IsOverTime: item.IsOverTime,
SecondReviewState: item.SecondReviewState
}) })
this.list = Object.assign({}, list) this.list = Object.assign({}, list)
this.loading = false this.loading = false
@@ -900,6 +900,8 @@ export default {
fileList: [], fileList: [],
dicomInfo: { dicomInfo: {
studyId: data.string('x00200010'), studyId: data.string('x00200010'),
DicomStudyDate: data.string('x00080020'),
DicomStudyTime: data.string('x00080030'),
studyUid: studyUid, studyUid: studyUid,
patientId: data.string('x00100020'), patientId: data.string('x00100020'),
patientName: patientNameStr, patientName: patientNameStr,
@@ -1008,6 +1010,8 @@ export default {
) )
seriesItem = { seriesItem = {
seriesUid: seriesUid, seriesUid: seriesUid,
DicomSeriesDate: data.string('x00080021'),
DicomSeriesTime: data.string('x00080031'),
seriesNumber: data.intString('x00200011') || 1, seriesNumber: data.intString('x00200011') || 1,
modality: data.string('x00080060') || '', modality: data.string('x00080060') || '',
description: seriesDescriptionStr, description: seriesDescriptionStr,
@@ -1047,6 +1051,10 @@ export default {
} }
instanceItem = { instanceItem = {
instanceUid: instanceUid, instanceUid: instanceUid,
SOPClassUID: data.string('x00080016'),
TransferSytaxUID: data.string('x00020010'),
MediaStorageSOPInstanceUID: instanceUid,
MediaStorageSOPClassUID: data.string('x00080016'),
instanceNumber: data.intString('x00200013') || 1, instanceNumber: data.intString('x00200013') || 1,
frameCount: data.intString('x00280008') || 1, frameCount: data.intString('x00280008') || 1,
instanceTime: instanceTime, instanceTime: instanceTime,
@@ -1405,6 +1413,8 @@ export default {
acquisitionNumber: dicomInfo.acquisitionNumber, acquisitionNumber: dicomInfo.acquisitionNumber,
triggerTime: dicomInfo.triggerTime, triggerTime: dicomInfo.triggerTime,
bodyPartExamined: '', bodyPartExamined: '',
DicomStudyDate: dicomInfo.DicomStudyDate,
DicomStudyTime: dicomInfo.DicomStudyTime,
seriesList: [], seriesList: [],
}, },
} }
@@ -1429,6 +1439,10 @@ export default {
instanceList.push({ instanceList.push({
studyInstanceUid: dicomInfo.studyUid, studyInstanceUid: dicomInfo.studyUid,
seriesInstanceUid: v.seriesUid, seriesInstanceUid: v.seriesUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
sopInstanceUid: o.instanceUid, sopInstanceUid: o.instanceUid,
instanceNumber: o.instanceNumber, instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime, instanceTime: o.instanceTime,
@@ -1514,6 +1528,10 @@ export default {
instanceList.push({ instanceList.push({
studyInstanceUid: dicomInfo.studyUid, studyInstanceUid: dicomInfo.studyUid,
seriesInstanceUid: v.seriesUid, seriesInstanceUid: v.seriesUid,
SOPClassUID: o.SOPClassUID,
TransferSytaxUID: o.TransferSytaxUID,
MediaStorageSOPInstanceUID:o.MediaStorageSOPInstanceUID,
MediaStorageSOPClassUID: o.MediaStorageSOPClassUID,
sopInstanceUid: o.instanceUid, sopInstanceUid: o.instanceUid,
instanceNumber: o.instanceNumber, instanceNumber: o.instanceNumber,
instanceTime: o.instanceTime, instanceTime: o.instanceTime,
@@ -1560,6 +1578,8 @@ export default {
seriesInstanceUid: v.seriesUid, seriesInstanceUid: v.seriesUid,
seriesNumber: v.seriesNumber, seriesNumber: v.seriesNumber,
seriesTime: v.seriesTime, seriesTime: v.seriesTime,
DicomSeriesDate: v.DicomSeriesDate,
DicomSeriesTime: v.DicomSeriesTime,
sliceThickness: v.sliceThickness, sliceThickness: v.sliceThickness,
imagePositionPatient: v.imagePositionPatient, imagePositionPatient: v.imagePositionPatient,
imageOrientationPatient: v.imageOrientationPatient, imageOrientationPatient: v.imageOrientationPatient,
@@ -1579,7 +1599,7 @@ export default {
} }
let text = JSON.stringify(Record) let text = JSON.stringify(Record)
let logJsonBlob = scope.generateTxtFile(text) let logJsonBlob = scope.generateTxtFile(text)
let logJsonObjectName = `/${params.trialId}/Image/${params.trialSiteId}/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.studyUid}/${params.studyMonitorId}.txt` let logJsonObjectName = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.studyUid}/${params.studyMonitorId}.txt`
let logRes let logRes
try { try {
logRes = await scope.OSSclient.put( logRes = await scope.OSSclient.put(
@@ -49,10 +49,18 @@
<el-button v-if=" <el-button v-if="
$store.state.trials.config.IsSupportQCDownloadImage && $store.state.trials.config.IsSupportQCDownloadImage &&
!hasPermi(['role:spm']) !hasPermi(['role:spm'])
" :loading="downloading" :disabled="selectTableDicom.length <= 0 || SecondReviewState > 0" size="small" " :loading="downloading" :disabled="selectTableDicom.length <= 0" size="small" type="primary"
type="primary" style="margin-left: 10px" @click="getCRCUploadedStudyInfo('dicom')"> style="margin-left: 10px" @click="getCRCUploadedStudyInfo('dicom')">
{{ $t('trials:audit:button:downLoadAllDiocms') }} {{ $t('trials:audit:button:downLoadAllDiocms') }}
</el-button> </el-button>
<!-- 下载工具 -->
<el-button v-if="
$store.state.trials.config.IsSupportQCDownloadImage &&
!hasPermi(['role:spm'])
" :loading="downloading" size="small" type="primary" style="margin-left: 10px"
@click="getCRCUploadedStudyInfo('tools')">
{{ $t('trials:audit:button:downLoadTools') }}
</el-button>
<!-- 预览所有影像 --> <!-- 预览所有影像 -->
<el-button size="small" type="primary" style="margin-left: 10px" @click="handleViewImages"> <el-button size="small" type="primary" style="margin-left: 10px" @click="handleViewImages">
{{ $t('trials:audit:button:previewAllDiocms') }} {{ $t('trials:audit:button:previewAllDiocms') }}
@@ -129,7 +137,7 @@
<!-- 上传时间 --> <!-- 上传时间 -->
<el-table-column prop="UploadedTime" :label="$t('trials:audit:table:seriesOfUploadedDate')" <el-table-column prop="UploadedTime" :label="$t('trials:audit:table:seriesOfUploadedDate')"
min-width="120" sortable show-overflow-tooltip /> min-width="120" sortable show-overflow-tooltip />
<el-table-column :label="$t('common:action:action')"> <el-table-column :label="$t('common:action:action')" min-width="160">
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 预览 --> <!-- 预览 -->
<el-button icon="el-icon-view" :title="$t('trials:audit:action:preview')" circle <el-button icon="el-icon-view" :title="$t('trials:audit:action:preview')" circle
@@ -145,6 +153,9 @@
scope.row.Modalities scope.row.Modalities
) && IsHaveStudyClinicalData ) && IsHaveStudyClinicalData
" circle :disabled="scope.row.IsDeleted" @click="handlePreviewClinicalData(scope.row)" /> " circle :disabled="scope.row.IsDeleted" @click="handlePreviewClinicalData(scope.row)" />
<!-- 质控后编辑 -->
<el-button icon="el-icon-edit" :title="$t('trials:audit:action:Correction')" circle
v-if="isAuditToEdit" @click="handleEditStudy(scope.row)" />
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -244,8 +255,8 @@
<el-button v-if=" <el-button v-if="
$store.state.trials.config.IsSupportQCDownloadImage && $store.state.trials.config.IsSupportQCDownloadImage &&
!hasPermi(['role:spm']) !hasPermi(['role:spm'])
" :loading="downloading" :disabled="selectTableNonedicom.length <= 0 || SecondReviewState > 0" " :loading="downloading" :disabled="selectTableNonedicom.length <= 0" size="small" type="primary"
size="small" type="primary" style="margin-left: 10px" @click="getCRCUploadedStudyInfo('noneDicom')"> style="margin-left: 10px" @click="getCRCUploadedStudyInfo('noneDicom')">
{{ $t('trials:audit:button:downLoadAllNonDiocms') }} {{ $t('trials:audit:button:downLoadAllNonDiocms') }}
</el-button> </el-button>
<!-- 预览 --> <!-- 预览 -->
@@ -354,7 +365,7 @@
:inactive-text="$fd('YesOrNo', false)" /> :inactive-text="$fd('YesOrNo', false)" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('common:action:action')"> <el-table-column :label="$t('common:action:action')" min-width="160">
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 预览 --> <!-- 预览 -->
<el-button icon="el-icon-view" :title="$t('trials:audit:button:nonDicomsPreview')" circle <el-button icon="el-icon-view" :title="$t('trials:audit:button:nonDicomsPreview')" circle
@@ -365,6 +376,9 @@
<el-button icon="el-icon-edit-outline" :title="$t('trials:audit:button:nonDicomsEdit')" circle <el-button icon="el-icon-edit-outline" :title="$t('trials:audit:button:nonDicomsEdit')" circle
:disabled="isAudit || SecondReviewState > 0" :disabled="isAudit || SecondReviewState > 0"
@click.native.prevent="handleEditNoneDicomInfo(scope.row)" /> @click.native.prevent="handleEditNoneDicomInfo(scope.row)" />
<!-- 质控后编辑 -->
<el-button icon="el-icon-edit" :title="$t('trials:audit:action:Correction')" circle
v-if="isAuditToEdit" @click="handleEditNoneDicomInfo(scope.row)" />
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -633,18 +647,28 @@
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<!-- 序列数量 --> <!-- 序列数量 -->
<el-form-item :label="$t('trials:audit:table:seriesCount')"> <el-form-item :label="$t('trials:audit:table:seriesCount')" v-if="!isAuditToEdit">
<el-input v-model="studyForm.SeriesCount" disabled /> <el-input v-model="studyForm.SeriesCount" disabled />
</el-form-item> </el-form-item>
<!-- 图像数量 --> <!-- 图像数量 -->
<el-form-item v-if="studyForm.InstanceCount" :label="$t('trials:audit:table:instanceCount')"> <el-form-item v-if="studyForm.InstanceCount && !isAuditToEdit"
:label="$t('trials:audit:table:instanceCount')">
<el-input v-model="studyForm.InstanceCount" disabled /> <el-input v-model="studyForm.InstanceCount" disabled />
</el-form-item> </el-form-item>
<!-- 检查日期 --> <!-- 检查日期 -->
<el-form-item :label="$t('trials:audit:table:studyDate')"> <el-form-item :label="$t('trials:audit:table:studyDate')" v-if="!isAuditToEdit">
<el-date-picker v-model="studyForm.StudyTime" disabled type="date" value-format="yyyy-MM-dd" <el-date-picker v-model="studyForm.StudyTime" disabled type="date" value-format="yyyy-MM-dd"
format="yyyy-MM-dd" style="width: 100%" /> format="yyyy-MM-dd" style="width: 100%" />
</el-form-item> </el-form-item>
<!-- 修改原因 -->
<el-form-item v-if="isAuditToEdit" :label="$t('trials:audit:table:Reason')" prop="ModifyReason" :rules="[
{
required: true,
message: $t('common:ruleMessage:specify'),
trigger: 'blur',
}]">
<el-input v-model="studyForm.ModifyReason" type="textarea" />
</el-form-item>
</el-form> </el-form>
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
@@ -730,10 +754,29 @@
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<!-- 检查日期 --> <!-- 检查日期 -->
<el-form-item :label="$t('trials:audit:table:nonDicomsStudyDate')" prop="ImageDate"> <el-form-item :label="$t('trials:audit:table:nonDicomsStudyDate')" prop="ImageDate" :rules="[
{
required: true,
message: $t('common:ruleMessage:specify'),
trigger: 'blur',
}]" v-if="isAuditToEdit">
<el-date-picker v-model="noneDicomForm.ImageDate" type="date" :picker-options="pickerOption"
value-format="yyyy-MM-dd" format="yyyy-MM-dd" style="width: 100%" />
</el-form-item>
<!-- 检查日期 -->
<el-form-item :label="$t('trials:audit:table:nonDicomsStudyDate')" prop="ImageDate" v-else>
<el-date-picker v-model="noneDicomForm.ImageDate" disabled type="date" :picker-options="pickerOption" <el-date-picker v-model="noneDicomForm.ImageDate" disabled type="date" :picker-options="pickerOption"
value-format="yyyy-MM-dd" format="yyyy-MM-dd" style="width: 100%" /> value-format="yyyy-MM-dd" format="yyyy-MM-dd" style="width: 100%" />
</el-form-item> </el-form-item>
<!-- 修改原因 -->
<el-form-item v-if="isAuditToEdit" :label="$t('trials:audit:table:Reason')" prop="ModifyReason" :rules="[
{
required: true,
message: $t('common:ruleMessage:specify'),
trigger: 'blur',
}]">
<el-input v-model="noneDicomForm.ModifyReason" type="textarea" />
</el-form-item>
</el-form> </el-form>
</div> </div>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
@@ -882,7 +925,9 @@ import {
updateModality, updateModality,
getQCChallengeDialogList, getQCChallengeDialogList,
replaceQCTaskActionUser, replaceQCTaskActionUser,
getTrialUserRoleList getTrialUserRoleList,
updateNoneDicomStudy,
updateDicomStudyInfo
} from '@/api/trials' } from '@/api/trials'
import { qCPassedOrFailed } from '@/api/trials/visit' import { qCPassedOrFailed } from '@/api/trials/visit'
import { getBasicDataSelects } from '@/api/dictionary/dictionary' import { getBasicDataSelects } from '@/api/dictionary/dictionary'
@@ -896,6 +941,9 @@ import const_ from '@/const/sign-code'
import uploadPetClinicalData from '@/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue' import uploadPetClinicalData from '@/views/trials/trials-panel/visit/crc-upload/components/uploadPetClinicalData.vue'
import { downLoadFile } from '@/utils/stream.js' import { downLoadFile } from '@/utils/stream.js'
import { getCRCUploadedStudyInfo, downloadImageSuccess } from '@/api/load.js' import { getCRCUploadedStudyInfo, downloadImageSuccess } from '@/api/load.js'
import {
getCommonDocument,
} from '@/api/dictionary'
import store from '@/store' import store from '@/store'
export default { export default {
name: 'QualityAssurance', name: 'QualityAssurance',
@@ -924,12 +972,19 @@ export default {
SecondReviewState: { SecondReviewState: {
type: Number, type: Number,
default: 0, default: 0,
},
auditorId: {
type: String,
default: ''
} }
}, },
computed: { computed: {
isEN() { isEN() {
return this.$i18n.locale !== 'zh' return this.$i18n.locale !== 'zh'
}, },
isAuditToEdit() {
return this.isAudit && this.auditorId === this.userId
}
}, },
data() { data() {
return { return {
@@ -963,6 +1018,7 @@ export default {
BodyPartForEdit: [], BodyPartForEdit: [],
SeriesCount: null, SeriesCount: null,
StudyTime: '', StudyTime: '',
ModifyReason: ''
}, },
currentQCRow: {}, currentQCRow: {},
isAudit: false, // isAudit: false, //
@@ -981,6 +1037,7 @@ export default {
Modality: '', Modality: '',
ImageDate: '', ImageDate: '',
StudyName: '', StudyName: '',
ModifyReason: ''
}, },
subjectClinicalData: {}, subjectClinicalData: {},
moment, moment,
@@ -1035,7 +1092,8 @@ export default {
secondReviewList: [], secondReviewList: [],
secondReviewActiveName: null, secondReviewActiveName: null,
SecondReviewTime: '', SecondReviewTime: '',
IsSecondPass: false IsSecondPass: false,
userId: zzSessionStorage.getItem('userId'),
} }
}, },
async mounted() { async mounted() {
@@ -1079,6 +1137,9 @@ export default {
NoneDicomStudyIdList: [], NoneDicomStudyIdList: [],
DicomStudyIdList: [], DicomStudyIdList: [],
} }
if (type === 'tools') {
return this.handleDownload()
}
if (type === 'dicom') { if (type === 'dicom') {
data.DicomStudyIdList = this.selectTableDicom.map( data.DicomStudyIdList = this.selectTableDicom.map(
(item) => item.StudyId (item) => item.StudyId
@@ -1092,6 +1153,7 @@ export default {
this.downloading = true this.downloading = true
let res = await getCRCUploadedStudyInfo(data) let res = await getCRCUploadedStudyInfo(data)
this.downloading = false this.downloading = false
// return
if (res.IsSuccess) { if (res.IsSuccess) {
this.downloadId = res.OtherInfo this.downloadId = res.OtherInfo
this.downloadImage(res.Result, type) this.downloadImage(res.Result, type)
@@ -1101,6 +1163,30 @@ export default {
console.log(err) console.log(err)
} }
}, },
//
async handleDownload() {
try {
this.downloading = true
let res = await getCommonDocument({ Code: 'TrialImageConvert_Soft' })
if (res.IsSuccess) {
let row = res.Result
let fileName = this.isEN ? row.Name : row.NameCN;
let type = fileName
.substring(fileName.lastIndexOf('.'))
.toLocaleLowerCase()
if (!type) {
let extendName = row.Path
.substring(row.Path.lastIndexOf('.'))
.toLocaleLowerCase()
fileName += extendName
}
res = await downLoadFile(this.OSSclientConfig.basePath + row.Path, fileName)
}
this.downloading = false
} catch (err) {
this.downloading = false
}
},
// //
async downloadImage(data, type) { async downloadImage(data, type) {
try { try {
@@ -1129,18 +1215,31 @@ export default {
)}.zip` )}.zip`
let StudyList = data.StudyList let StudyList = data.StudyList
StudyList.forEach((study) => { StudyList.forEach((study) => {
if (study.StudyDIRPath) {
let obj = {
name: `${data.SubjectCode}_${data.VisitName}_${this.$fd(
'IsDicom',
true
)}/${study.StudyCode}_${study.StudyTime.split(' ')[0]}/DICOMDIR`,
url: this.OSSclientConfig.basePath + study.StudyDIRPath,
}
files.push(obj)
}
if (study.SeriesList.length > 0) { if (study.SeriesList.length > 0) {
study.SeriesList.forEach((series) => { study.SeriesList.forEach((series) => {
if (series.InstanceList.length > 0) { if (series.InstanceList.length > 0) {
series.InstanceList.forEach((instance) => { series.InstanceList.forEach((instance) => {
let fileName = instance.Path.split('/').pop() let fileName = instance.Path.split('/').pop()
if (instance.FileName) {
fileName = instance.FileName
}
let obj = { let obj = {
name: `${data.SubjectCode}_${data.VisitName}_${this.$fd( name: `${data.SubjectCode}_${data.VisitName}_${this.$fd(
'IsDicom', 'IsDicom',
true true
)}/${study.StudyCode}_${study.StudyTime.split(' ')[0]}_${series.Modality )}/${study.StudyCode}_${study.StudyTime.split(' ')[0]}/IMAGE/${fileName}`,
}/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path, url: this.OSSclientConfig.basePath + instance.Path,
IsEncapsulated: instance.IsEncapsulated
} }
files.push(obj) files.push(obj)
}) })
@@ -1444,6 +1543,7 @@ export default {
this.qcVisible = false this.qcVisible = false
this.relationInfo.TotalChallengeCount++ this.relationInfo.TotalChallengeCount++
this.relationInfo.NotClosedChallengeCount++ this.relationInfo.NotClosedChallengeCount++
this.$emit('getList')
} }
}) })
.catch(() => { .catch(() => {
@@ -1935,7 +2035,17 @@ export default {
// //
closeSignDialog(isSign, signInfo) { closeSignDialog(isSign, signInfo) {
if (isSign) { if (isSign) {
this.setQCStatus(signInfo) if (this.isAuditToEdit) {
if (this.editStudyInfoVisible) {
// dicom
this.updateDicomStudyInfo(signInfo)
} else if (this.editNoneDicomVisible) {
// dicom
this.updateNoneDicomStudy(signInfo)
}
} else {
this.setQCStatus(signInfo)
}
} else { } else {
this.signVisible = false this.signVisible = false
} }
@@ -1963,7 +2073,7 @@ export default {
this.isAudit = true this.isAudit = true
if (this.signCode === 219) { if (this.signCode === 219) {
this.$emit('getList') this.$emit('getList')
return this.getQCInfo() this.getQCInfo()
} }
if (!this.$store.state.trials.config.IsIQCAutoNextTask) return this.$emit('getList') if (!this.$store.state.trials.config.IsIQCAutoNextTask) return this.$emit('getList')
this.$forceUpdate() this.$forceUpdate()
@@ -2045,6 +2155,7 @@ export default {
this.$set(this.studyForm, 'Modality', row.ModalityForEdit) this.$set(this.studyForm, 'Modality', row.ModalityForEdit)
// this.studyForm.Modality = row.ModalityForEdit // this.studyForm.Modality = row.ModalityForEdit
this.studyForm.BodyPartForEdit = bodyPart this.studyForm.BodyPartForEdit = bodyPart
this.$set(this.studyForm, 'ModifyReason', '')
}, },
// / // /
handleUpdateStudyInfo() { handleUpdateStudyInfo() {
@@ -2061,20 +2172,59 @@ export default {
bodyPart: this.studyForm.BodyPart, bodyPart: this.studyForm.BodyPart,
StudyName: this.studyForm.StudyName, StudyName: this.studyForm.StudyName,
} }
updateModality(this.data.TrialId, params) if (this.isAuditToEdit) {
.then((res) => { this.btnLoading = false
this.btnLoading = false const { CorrectImageExaminationInformation } = const_.processSignature
if (res.IsSuccess) { this.signCode = CorrectImageExaminationInformation
this.getStudyInfo() this.signVisible = true
this.$message.success(this.$t('common:message:savedSuccessfully')) } else {
this.editStudyInfoVisible = false updateModality(this.data.TrialId, params)
} .then((res) => {
}) this.btnLoading = false
.catch(() => { if (res.IsSuccess) {
this.btnLoading = false this.getStudyInfo()
}) this.$message.success(this.$t('common:message:savedSuccessfully'))
this.editStudyInfoVisible = false
}
})
.catch(() => {
this.btnLoading = false
})
}
}) })
}, },
// dicom
async updateDicomStudyInfo(signInfo) {
try {
this.loading = true
let data = {
data: {
Id: this.studyForm.StudyId,
SubjectVisitId: this.data.Id,
StudyName: this.studyForm.StudyName,
ModifyReason: this.studyForm.ModifyReason,
Modality: this.studyForm.Modality,
BodyPart: this.studyForm.BodyPart,
},
signInfo
}
let res = await updateDicomStudyInfo(data)
this.loading = false
this.btnLoading = false
this.signVisible = false
if (res.IsSuccess) {
this.getStudyInfo()
this.$message.success(this.$t('common:message:savedSuccessfully'))
this.editStudyInfoVisible = false
}
} catch (err) {
console.log(err)
this.btnLoading = false
this.loading = false
this.signVisible = false
}
},
// //
refreshList() { refreshList() {
// //
@@ -2101,6 +2251,7 @@ export default {
this.noneDicomForm.Modality = Modality this.noneDicomForm.Modality = Modality
this.noneDicomForm.ImageDate = ImageDate this.noneDicomForm.ImageDate = ImageDate
this.noneDicomForm.BodyParts = BodyPart.split(', ') this.noneDicomForm.BodyParts = BodyPart.split(', ')
this.noneDicomForm.ModifyReason = null
this.editNoneDicomVisible = true this.editNoneDicomVisible = true
}, },
// Dicom/ // Dicom/
@@ -2113,20 +2264,59 @@ export default {
this.noneDicomForm.TrialSiteId = this.data.TrialSiteId this.noneDicomForm.TrialSiteId = this.data.TrialSiteId
this.noneDicomForm.SubjectId = this.data.SubjectId this.noneDicomForm.SubjectId = this.data.SubjectId
this.noneDicomForm.SubjectVisitId = this.data.Id this.noneDicomForm.SubjectVisitId = this.data.Id
addOrUpdateNoneDicomStudy(this.noneDicomForm) if (this.isAuditToEdit) {
.then((res) => { this.btnLoading = false
this.btnLoading = false const { CorrectImageExaminationInformation } = const_.processSignature
if (res.IsSuccess) { this.signCode = CorrectImageExaminationInformation
this.getNoneDicomList() this.signVisible = true
this.$message.success(this.$t('common:message:savedSuccessfully')) } else {
this.editNoneDicomVisible = false addOrUpdateNoneDicomStudy(this.noneDicomForm)
} .then((res) => {
}) this.btnLoading = false
.catch(() => { if (res.IsSuccess) {
this.btnLoading = false this.getNoneDicomList()
}) this.$message.success(this.$t('common:message:savedSuccessfully'))
this.editNoneDicomVisible = false
}
})
.catch(() => {
this.btnLoading = false
})
}
}) })
}, },
// dicom
async updateNoneDicomStudy(signInfo) {
try {
this.loading = true
let data = {
data: {
Id: this.noneDicomForm.Id,
SubjectVisitId: this.data.Id,
StudyName: this.noneDicomForm.StudyName,
ModifyReason: this.noneDicomForm.ModifyReason,
Modality: this.noneDicomForm.Modality,
BodyPart: this.noneDicomForm.BodyParts.join(', '),
ImageDate: this.noneDicomForm.ImageDate
},
signInfo
}
let res = await updateNoneDicomStudy(data)
this.loading = false
this.btnLoading = false
this.signVisible = false
if (res.IsSuccess) {
this.getNoneDicomList()
this.$message.success(this.$t('common:message:savedSuccessfully'))
this.editNoneDicomVisible = false
}
} catch (err) {
console.log(err)
this.btnLoading = false
this.loading = false
this.signVisible = false
}
},
// Dicom // Dicom
getNoneDicomList() { getNoneDicomList() {
this.loading = true this.loading = true
@@ -82,6 +82,10 @@
<el-button type="primary" icon="el-icon-download" :loading="exportLoading" @click="handleExport"> <el-button type="primary" icon="el-icon-download" :loading="exportLoading" @click="handleExport">
{{ $t('common:button:export') }} {{ $t('common:button:export') }}
</el-button> </el-button>
<!-- 导出质控问题和答案 -->
<el-button type="primary" :loading="exportLoading" @click="handleExportQuestion">
{{ $t('trials:qcCheck:button:exportQuestion') }}
</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
@@ -478,7 +482,8 @@
<div class="qc-dialog-body"> <div class="qc-dialog-body">
<quality-assurance v-if="qcVisible" :data="rowData" :disabled="rowData.disabled ? rowData.disabled : false" <quality-assurance v-if="qcVisible" :data="rowData" :disabled="rowData.disabled ? rowData.disabled : false"
:SecondReviewState="rowData.SecondReviewState" :q-type="rowData.qcType ? rowData.qcType : 1" :SecondReviewState="rowData.SecondReviewState" :q-type="rowData.qcType ? rowData.qcType : 1"
@getList="getList" @nextTask="nextTask" @openManuals="openManuals" @close="qcVisible = false" /> :auditorId="auditorId" @getList="getList" @nextTask="nextTask" @openManuals="openManuals"
@close="qcVisible = false" />
</div> </div>
</el-dialog> </el-dialog>
<!-- 手册 --> <!-- 手册 -->
@@ -621,7 +626,7 @@ import {
isQCCanOpt, isQCCanOpt,
getNextQCInfo, getNextQCInfo,
} from '@/api/trials' } from '@/api/trials'
import { qCVisitList_Export } from '@/api/export' import { qCVisitList_Export, GetTrialQCQuestionAnserList_Export } from '@/api/export'
import BaseContainer from '@/components/BaseContainer' import BaseContainer from '@/components/BaseContainer'
import QualityAssurance from './components/qualityAssurance' import QualityAssurance from './components/qualityAssurance'
import Manuals from './components/manuals' import Manuals from './components/manuals'
@@ -692,12 +697,18 @@ export default {
isFullscreen: false, isFullscreen: false,
timeList: [], timeList: [],
exportLoading: false, exportLoading: false,
auditorId: null
} }
}, },
watch: { watch: {
list(val) { list(val) {
this.doLayout() this.doLayout()
}, },
qcVisible() {
if (!this.qcVisible) {
this.auditorId = null
}
}
}, },
mounted() { mounted() {
this.query = this.$route.query this.query = this.$route.query
@@ -742,6 +753,19 @@ export default {
console.log(err) console.log(err)
} }
}, },
handleExportQuestion() {
this.exportLoading = true
let data = {
TrialId: this.$route.query.trialId
}
GetTrialQCQuestionAnserList_Export(data)
.then(() => {
this.exportLoading = false
})
.catch((err) => {
this.exportLoading = false
})
},
handleExport() { handleExport() {
this.exportLoading = true this.exportLoading = true
qCVisitList_Export(this.searchData) qCVisitList_Export(this.searchData)
@@ -889,12 +913,14 @@ export default {
this.rowData.disabled = true this.rowData.disabled = true
this.rowData.qcType = 1 this.rowData.qcType = 1
this.qcVisible = true this.qcVisible = true
this.auditorId = row.PreliminaryAuditUserId
}, },
handleViewReviewQC(row) { handleViewReviewQC(row) {
this.rowData = { ...row } this.rowData = { ...row }
this.rowData.disabled = true this.rowData.disabled = true
this.rowData.qcType = 2 this.rowData.qcType = 2
this.qcVisible = true this.qcVisible = true
this.auditorId = row.ReviewAuditUserId
}, },
// //
handleViewImages() { handleViewImages() {
@@ -70,6 +70,10 @@
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset"> <el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }} {{ $t('common:button:reset') }}
</el-button> </el-button>
<el-button type="primary" @click="handleExport"
v-if="hasPermi(['trials:trials-panel:visit:reupload-audit:export'])">
{{ $t('common:button:export') }}
</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
@@ -236,7 +240,7 @@ import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination' import Pagination from '@/components/Pagination'
import moment from 'moment' import moment from 'moment'
import baseModel from '@/components/BaseModel' import baseModel from '@/components/BaseModel'
import { GetImageBackList_Export } from '@/api/export'
const searchDataDefault = () => { const searchDataDefault = () => {
return { return {
TrialId: null, TrialId: null,
@@ -434,7 +438,9 @@ export default {
this.searchData.ApplyEndTime = null this.searchData.ApplyEndTime = null
} }
}, },
handleExport() {
return GetImageBackList_Export(this.searchData)
}
}, },
} }
</script> </script>