504 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
			
		
		
	
	
			504 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
| <template>
 | |
|   <BaseContainer>
 | |
|     <!-- 搜索框 -->
 | |
|     <template slot="search-container">
 | |
|       <el-form :inline="true">
 | |
|         <!-- Site -->
 | |
|         <el-form-item :label="$t('trials:studyList:table:siteId')">
 | |
|           <el-select
 | |
|             v-model="searchData.SiteId"
 | |
|             clearable
 | |
|             filterable
 | |
|             style="width:150px"
 | |
|           >
 | |
|             <el-option
 | |
|               v-for="item of siteOptions"
 | |
|               :key="item.SiteId"
 | |
|               :label="item.TrialSiteCode"
 | |
|               :value="item.SiteId"
 | |
|             />
 | |
|           </el-select>
 | |
|         </el-form-item>
 | |
|         <!-- Subject -->
 | |
|         <el-form-item :label="$t('trials:studyList:table:subject')">
 | |
|           <el-input v-model="searchData.SubjectInfo" style="width:140px" />
 | |
|         </el-form-item>
 | |
|         <!-- Visit -->
 | |
|         <el-form-item :label="$t('trials:studyList:table:visit')">
 | |
|           <el-select
 | |
|             v-model="searchData.VisitPlanArray"
 | |
|             clearable
 | |
|             filterable
 | |
|             multiple
 | |
|             collapse-tags
 | |
|           >
 | |
|             <el-option
 | |
|               v-for="(item, index) of visitPlanOptions"
 | |
|               :key="index"
 | |
|               :label="item.VisitName"
 | |
|               :value="item.VisitNum"
 | |
|             >
 | |
|               <span style="float: left">{{ item.VisitName }}</span>
 | |
|             </el-option>
 | |
|             <el-option
 | |
|               key="Other"
 | |
|               label="OutPlan"
 | |
|               value="1.11"
 | |
|             />
 | |
|           </el-select>
 | |
|         </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-form>
 | |
| 
 | |
|     </template>
 | |
| 
 | |
|     <!-- 检查列表 -->
 | |
|     <template slot="main-container">
 | |
|       <el-table
 | |
|         v-loading="loading"
 | |
|         v-adaptive="{bottomOffset:60}"
 | |
|         :data="list"
 | |
|         stripe
 | |
|         height="100"
 | |
|         @sort-change="handleSortByColumn"
 | |
|       >
 | |
|         <el-table-column type="index" width="40" />
 | |
|         <!-- Study ID -->
 | |
|         <el-table-column
 | |
|           prop="StudyCode"
 | |
|           :label="$t('trials:studyList:table:studyId')"
 | |
|           show-overflow-tooltip
 | |
|           sortable="custom"
 | |
|           min-width="100"
 | |
|         />
 | |
|         <!-- Image Type -->
 | |
|         <el-table-column
 | |
|           prop="IsDicom"
 | |
|           :label="$t('trials:studyList:table:imageType')"
 | |
|           sortable="custom"
 | |
|           min-width="100"
 | |
|         >
 | |
|           <template slot-scope="scope">
 | |
|             <el-tag v-if="scope.row.IsDicom" type="primary">DICOM</el-tag>
 | |
|             <el-tag v-else type="danger">Non-DICOM</el-tag>
 | |
|           </template>
 | |
|         </el-table-column>
 | |
| 
 | |
|         <el-table-column
 | |
|           prop="StudyTime"
 | |
|           sortable="custom"
 | |
|           min-width="200"
 | |
|           show-overflow-tooltip
 | |
|         >
 | |
|           <template slot="header">
 | |
|             <el-tooltip placement="top">
 | |
|               <!-- Modality,Body Part Examined,Count,Study Date -->
 | |
|               <!-- Study Info -->
 | |
|               <div slot="content">
 | |
|                 {{ `${$t('trials:studyList:table:modality')}, ${$t('trials:studyList:table:bodyPart')}, ${$t('trials:studyList:table:studyDate')}, ${$t('trials:studyList:table:count')}` }}
 | |
|               </div>
 | |
|               <span>{{ $t('trials:studyList:table:studyInfo') }}</span>
 | |
|             </el-tooltip>
 | |
|           </template>
 | |
|           <template slot-scope="scope">
 | |
|             <div style="display: flex;align-items: center">
 | |
|               <div v-if="scope.row.Modalities">{{ scope.row.Modalities }}, </div>
 | |
|               <div v-else style="color:#f44336;">N/A, </div>
 | |
|               <div v-if="scope.row.Bodypart" style="margin:0 3px;">{{ scope.row.Bodypart }}, </div>
 | |
|               <div v-else style="color:#f44336;margin:0 3px;">N/A, </div>
 | |
|               <div v-if="scope.row.StudyTime">{{ moment(scope.row.StudyTime).format('YYYY-MM-DD') }}, </div>
 | |
|               <div v-else style="color:#f44336;">N/A, </div>
 | |
|               <div>
 | |
|                 <!-- <el-popover v-if="scope.row.Count && scope.row.IsDicom" trigger="click" placement="bottom">
 | |
|                   <el-table v-loading="seriesLoading" :data="seriesList" height="200" size="small" class="seriesListOfStudy">
 | |
|                     <el-table-column
 | |
|                       prop="SeriesNumber"
 | |
|                       :label="$t('trials:studyList:table:seriesNum')"
 | |
|                       width="120"
 | |
|                     />
 | |
|                     <el-table-column prop="Modality" :label="$t('trials:studyList:table:modality')" width="120" />
 | |
| 
 | |
|                     <el-table-column
 | |
|                       prop="Description"
 | |
|                       :label="$t('trials:studyList:table:description')"
 | |
|                       width="150"
 | |
|                       show-overflow-tooltip
 | |
|                     />
 | |
|                     <el-table-column
 | |
|                       prop="SliceThickness"
 | |
|                       :label="$t('trials:studyList:table:sliceThickness')"
 | |
|                       width="120"
 | |
|                     />
 | |
|                     <el-table-column
 | |
|                       prop="InstanceCount"
 | |
|                       :label="$t('trials:studyList:table:instanceCount')"
 | |
|                       width="120"
 | |
|                     />
 | |
| 
 | |
|                     <el-table-column :label="$t('common:action:action')" width="80">
 | |
|                       <template slot-scope="series">
 | |
|                         <router-link
 | |
|                           style="color: #00d1b2; padding: 2px 5px"
 | |
|                           tag="a"
 | |
|                           :to="{
 | |
|                             path: `/showdicom?studyId=${scope.row.Id}&studyCode=${scope.row.StudyCode}&modality=${scope.row.Modalities}&description=${scope.row.Description}&series=${JSON.stringify(series.row)}&type=Series&TokenKey=${tokenKey}`,
 | |
|                           }"
 | |
|                           target="_blank"
 | |
|                         >
 | |
|                           {{ $t('trials:studyList:button:view') }}
 | |
|                         </router-link>
 | |
|                       </template>
 | |
|                     </el-table-column>
 | |
|                   </el-table>
 | |
|                   <div slot="reference" class="name-wrapper">
 | |
|                     <span style="color:#00d1b2;cursor:pointer;" @click="handleGetseriesList(scope.row)">
 | |
|                       {{ `${scope.row.Count}` }}
 | |
|                     </span>
 | |
|                   </div>
 | |
|                 </el-popover>
 | |
|                 <el-button
 | |
|                   v-else-if="scope.row.Count && !scope.row.IsDicom"
 | |
|                   type="text"
 | |
|                   @click.native.prevent="handlePreviewNonDicom(scope.row)"
 | |
|                 >
 | |
|                   {{ scope.row.Count }}
 | |
|                 </el-button> -->
 | |
|                 <span>{{ scope.row.Count }}</span>
 | |
|                 <!-- <span v-else style="color:#f44336;">N/A</span> -->
 | |
| 
 | |
|               </div>
 | |
| 
 | |
|             </div>
 | |
|           </template>
 | |
|         </el-table-column>
 | |
| 
 | |
|         <el-table-column
 | |
|           min-width="100"
 | |
|           show-overflow-tooltip
 | |
|         >
 | |
|           <template slot="header">
 | |
|             <el-tooltip placement="top">
 | |
|               <div slot="content">
 | |
|                 {{ `${$t('trials:studyList:table:visitName')}, ${$t('trials:studyList:table:visitNum')}` }}<br>
 | |
|               </div>
 | |
|               <span>{{ $t('trials:studyList:table:visit') }}</span>
 | |
|             </el-tooltip>
 | |
|           </template>
 | |
|           <template slot-scope="scope">
 | |
|             <span v-if="scope.row.VisitName">{{ scope.row.VisitName }}, </span>
 | |
|             <span v-else style="color:#f44336;">N/A, </span>
 | |
|             <span>{{ scope.row.VisitNum }}</span>
 | |
|           </template>
 | |
|         </el-table-column>
 | |
|         <el-table-column
 | |
|           prop="SubjectCode"
 | |
|           :label="$t('trials:studyList:table:subject')"
 | |
|           sortable="custom"
 | |
|           show-overflow-tooltip
 | |
|         />
 | |
|         <el-table-column
 | |
|           min-width="100"
 | |
|           show-overflow-tooltip
 | |
|         >
 | |
|           <template slot="header">
 | |
|             <el-tooltip placement="top">
 | |
|               <div slot="content">
 | |
|                 {{ `${$t('trials:studyList:table:siteId')}, ${$t('trials:studyList:table:siteName')}` }}
 | |
|               </div>
 | |
|               <span>{{ $t('trials:studyList:table:site') }}</span>
 | |
|             </el-tooltip>
 | |
|           </template>
 | |
|           <template slot-scope="scope">
 | |
|             <span v-if="scope.row.TrialSiteCode">{{ scope.row.TrialSiteCode }}, </span>
 | |
|             <span v-else style="color:#f44336;">N/A, </span>
 | |
|             <span v-if="scope.row.TrialSiteAliasName">{{ scope.row.TrialSiteAliasName }}</span>
 | |
|             <span v-else style="color:#f44336;">N/A</span>
 | |
|           </template>
 | |
|         </el-table-column>
 | |
|         <el-table-column
 | |
|           prop="Uploader"
 | |
|           :label="$t('trials:studyList:table:uploader')"
 | |
|           show-overflow-tooltip
 | |
|           sortable="custom"
 | |
|           min-width="100"
 | |
|         />
 | |
|         <el-table-column
 | |
|           prop="UploadTime"
 | |
|           :label="$t('trials:studyList:table:uploadTime')"
 | |
|           show-overflow-tooltip
 | |
|           sortable="custom"
 | |
|           min-width="120"
 | |
|         />
 | |
| 
 | |
|         <el-table-column :label="$t('common:action:action')" min-width="100" fixed="right">
 | |
|           <template slot-scope="scope">
 | |
|             <!-- 查看 -->
 | |
|             <el-button
 | |
|               :disabled="!scope.row.Count"
 | |
|               circle
 | |
|               :title="$t('trials:studyList:button:view')"
 | |
|               icon="el-icon-view"
 | |
|               @click="handleViewStudy(scope.row)"
 | |
|             />
 | |
|             <!-- 分享检查 -->
 | |
|             <el-button
 | |
|               v-hasPermi="['trials:trials-panel:study:share']"
 | |
|               :disabled="!(scope.row.Count > 0 && scope.row.IsDicom)"
 | |
|               circle
 | |
|               :title="$t('trials:studyList:action:share')"
 | |
|               icon="el-icon-share"
 | |
|               @click="handleShareImage(scope.row)"
 | |
|             />
 | |
|           </template>
 | |
|         </el-table-column>
 | |
|       </el-table>
 | |
| 
 | |
|       <!-- 分页组件 -->
 | |
|       <pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize" @pagination="getList" />
 | |
|     </template>
 | |
| 
 | |
|     <base-model :config="share_model">
 | |
|       <template slot="dialog-body">
 | |
|         <div>
 | |
|           <i style="color:#00d1b2;" class="el-icon-success" />
 | |
|           <span>成功创建分享链接</span>
 | |
|         </div>
 | |
|         <div style="margin:10px 0;">
 | |
|           链接:<el-input v-model="shareLink" readonly style="width:420px;" />
 | |
|         </div>
 | |
|         <div style="margin-bottom:20px;">
 | |
|           提取码: <el-input v-model="extractionCode" style="width:100px;" readonly />
 | |
|         </div>
 | |
|         <div>
 | |
|           <el-button type="primary" round @click="copyCode">复制链接及提取码</el-button>
 | |
|         </div>
 | |
|       </template>
 | |
|     </base-model>
 | |
| 
 | |
|     <!-- 预览非Dicom影像 -->
 | |
|     <el-dialog
 | |
|       v-if="previewNonDicomVisible"
 | |
|       :visible.sync="previewNonDicomVisible"
 | |
|       :title="$t('trials:studyList:dialogTitle:view')"
 | |
|       :fullscreen="true"
 | |
|       append-to-body
 | |
|       custom-class="base-dialog-wrapper"
 | |
|     >
 | |
|       <div class="base-modal-body" style="border:2px solid #ccc;padding: 10px">
 | |
|         <NonDicomPreview v-if="previewNonDicomVisible" :none-dicom-id="rowData.Id" />
 | |
|       </div>
 | |
|     </el-dialog>
 | |
| 
 | |
|   </BaseContainer>
 | |
| </template>
 | |
| <script>
 | |
| import {
 | |
|   getDicomAndNoneDicomStudyList,
 | |
|   getTrialSiteSelect,
 | |
|   getSeriesList,
 | |
|   getTrialVisitStageSelect,
 | |
|   getNoneDicomStudyFileList
 | |
| 
 | |
| } from '@/api/trials'
 | |
| import { createImageShare } from '@/api/share'
 | |
| import BaseContainer from '@/components/BaseContainer'
 | |
| import Pagination from '@/components/Pagination'
 | |
| import BaseModel from '@/components/BaseModel'
 | |
| import NonDicomPreview from './components/nonDicomPreview'
 | |
| import moment from 'moment'
 | |
| import { getToken } from '@/utils/auth'
 | |
| const searchDataDefault = () => {
 | |
|   return {
 | |
|     SubjectInfo: '',
 | |
|     VisitPlanArray: [],
 | |
|     Status: '',
 | |
|     SiteId: '',
 | |
|     PageIndex: 1,
 | |
|     PageSize: 20
 | |
|   }
 | |
| }
 | |
| export default {
 | |
|   name: 'StudyList',
 | |
|   components: { BaseContainer, Pagination, BaseModel, NonDicomPreview },
 | |
|   data() {
 | |
|     return {
 | |
|       searchData: searchDataDefault(),
 | |
|       list: [],
 | |
|       loading: false,
 | |
|       total: 0,
 | |
|       siteOptions: [],
 | |
|       visitPlanOptions: [],
 | |
|       seriesList: [],
 | |
|       nonDicomfilesList: [],
 | |
|       rowData: {},
 | |
|       userTypeEnumInt: zzSessionStorage.getItem('userTypeEnumInt') * 1,
 | |
|       share_model: { visible: false, title: '影像分享', showClose: true, width: '500px' },
 | |
|       shareLink: '',
 | |
|       extractionCode: '',
 | |
|       moment,
 | |
|       filesLoading: '',
 | |
|       seriesLoading: '',
 | |
|       previewNonDicomVisible: false,
 | |
|       trialId: this.$route.query.trialId,
 | |
|       tokenKey: getToken()
 | |
|     }
 | |
|   },
 | |
|   mounted() {
 | |
|     this.getSite()
 | |
|     this.getVisitPlanOptions()
 | |
|     this.getList()
 | |
|   },
 | |
|   methods: {
 | |
|     // 获取检查列表数据
 | |
|     getList() {
 | |
|       this.loading = true
 | |
|       this.searchData.TrialId = this.trialId
 | |
|       getDicomAndNoneDicomStudyList(this.searchData)
 | |
|         .then((res) => {
 | |
|           this.loading = false
 | |
|           this.list = res.Result.CurrentPageData
 | |
|           this.total = res.Result.TotalCount
 | |
|         })
 | |
|         .catch(() => {
 | |
|           this.loading = false
 | |
|         })
 | |
|     },
 | |
|     // 获取某个Dicom检查下的序列信息
 | |
|     handleGetseriesList(row) {
 | |
|       this.seriesLoading = true
 | |
|       this.seriesList = []
 | |
|       getSeriesList(row.Id).then((res) => {
 | |
|         this.seriesLoading = false
 | |
|         this.seriesList = res.Result
 | |
|       }).catch(() => {
 | |
|         this.seriesLoading = false
 | |
|       })
 | |
|     },
 | |
|     // 获取某个非Dicom检查下的文件
 | |
|     handleGetFilesList(id) {
 | |
|       this.filesLoading = true
 | |
|       getNoneDicomStudyFileList(id).then(res => {
 | |
|         this.nonDicomfilesList = res.Result
 | |
|         this.filesLoading = false
 | |
|       }).catch(() => { this.filesLoading = false })
 | |
|     },
 | |
|     // 预览当前检查下的影像
 | |
|     handleViewStudy(row) {
 | |
|       if (row.IsDicom) {
 | |
|         const routeData = this.$router.resolve({
 | |
|           path: `/showdicom?studyId=${row.Id}&TokenKey=${this.tokenKey}&type=Study`
 | |
|         })
 | |
|         window.open(routeData.href, '_blank')
 | |
|       } else {
 | |
|         // this.rowData = { ...row }
 | |
|         // this.previewNonDicomVisible = true
 | |
|         const routeData = this.$router.resolve({
 | |
|           path: `/showNoneDicoms?subjectVisitId=${row.SubjectVisitId}&studyId=${row.Id}&TokenKey=${this.tokenKey}`
 | |
|         })
 | |
|         window.open(routeData.href, '_blank')
 | |
|       }
 | |
|     },
 | |
|     handlePreviewNonDicom(row) {
 | |
|       const routeData = this.$router.resolve({
 | |
|         path: `/showNoneDicoms?subjectVisitId=${row.SubjectVisitId}&studyId=${row.Id}&TokenKey=${this.tokenKey}`
 | |
|       })
 | |
|       window.open(routeData.href, '_blank')
 | |
|     },
 | |
|     // 预览
 | |
|     handlePreview(row) {
 | |
|       window.open(row.FullFilePath, '_blank')
 | |
|     },
 | |
|     // 格式化状态码
 | |
|     studyStatusFormatter(StudyStatus) {
 | |
|       if (StudyStatus === 5) return 'Uploaded'
 | |
|       else if (StudyStatus === 1) return 'Uploading'
 | |
|       else if (StudyStatus === 7) return 'QA Requested'
 | |
|       else if (StudyStatus === 10) return 'In QA'
 | |
|       else if (StudyStatus === 25) return 'QA-Passed'
 | |
|       else if (StudyStatus === 26) return 'QA-Failed'
 | |
|       else if (StudyStatus === 28) return 'Anonymizing'
 | |
|       else if (StudyStatus === 30) return 'Anonymized'
 | |
|       else if (StudyStatus === 32) return 'Anonymizing Failed'
 | |
|       else if (StudyStatus === 34) return 'Forwarding'
 | |
|       else if (StudyStatus === 36) return 'Forwarded'
 | |
|       else if (StudyStatus === 38) return 'Forwarding Failed'
 | |
|       else return ''
 | |
|     },
 | |
|     // 获取site下拉框数据
 | |
|     getSite() {
 | |
|       getTrialSiteSelect(this.trialId).then((res) => {
 | |
|         this.siteOptions = res.Result
 | |
|       })
 | |
|     },
 | |
|     // 获取visit下拉框数据
 | |
|     getVisitPlanOptions() {
 | |
|       getTrialVisitStageSelect(this.trialId)
 | |
|         .then((res) => {
 | |
|           this.visitPlanOptions = res.Result
 | |
|         })
 | |
|     },
 | |
|     // 分享影像链接
 | |
|     handleShareImage(row) {
 | |
|       this.shareLink = ''
 | |
|       this.extractionCode = ''
 | |
|       const params = {
 | |
|         TrialId: row.TrialId,
 | |
|         SiteId: row.SiteId,
 | |
|         SubjectId: row.SubjectId,
 | |
|         StudyId: row.Id
 | |
|       }
 | |
|       this.loading = true
 | |
|       createImageShare(params).then((res) => {
 | |
|         this.loading = false
 | |
|         if (res.IsSuccess) {
 | |
|           this.shareLink = `${window.location.origin}${window.location.pathname}#/imagesShare?id=${res.Result.ResourceId}`
 | |
|           this.extractionCode = res.Result.Password
 | |
|           this.share_model.visible = true
 | |
|         }
 | |
|       }).catch(() => { this.loading = false })
 | |
|     },
 | |
|     // 复制
 | |
|     copyCode() {
 | |
|       this.$copyText(`链接: ${this.shareLink} 提取码: ${this.extractionCode}`).then(
 | |
|         res => {
 | |
|           this.$message.success('复制成功')
 | |
|         }
 | |
|       ).catch(() => { this.$message.error('复制失败') })
 | |
|     },
 | |
|     onCopyError() {
 | |
|       this.$message.error('复制失败')
 | |
|     },
 | |
|     // 查询
 | |
|     handleSearch() {
 | |
|       this.searchData.PageIndex = 1
 | |
|       this.getList()
 | |
|     },
 | |
|     // 重置
 | |
|     handleReset() {
 | |
|       this.searchData = searchDataDefault()
 | |
|       this.getList()
 | |
|     },
 | |
|     // 排序
 | |
|     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()
 | |
|     }
 | |
|   }
 | |
| }
 | |
| </script>
 |