irc_web/.svn/pristine/70/70a102e255aec3a1bc19df2679c...

512 lines
16 KiB
Plaintext

<template>
<box-content class="stats-wrapper">
<div class="search">
<SearchForm
size="mini"
:that="this"
:search-data="searchData"
:search-form="workloadStats_form"
:search-handle="workloadStats_handle"
@search="handleSearch"
@reset="handleReset"
@export="handleExportExcel"
>
<!-- 选择自定义slot -->
<template slot="croSlot">
<el-select
ref="CROSelection"
v-model="searchData.CROId"
style="width:120px"
clearable
>
<el-option
v-for="(item) of croList"
:key="item.Id"
:label="item.CROName"
:value="item.Id"
/>
</el-select>
</template>
<template slot="hospitalSlot">
<el-select
v-model="searchData.HospitalId"
style="width:120px"
clearable
>
<el-option
v-for="(item,index) in hospitalList"
:key="index"
:label="item.HospitalName"
:value="item.Id"
/>
</el-select>
</template>
<template slot="beginDateSlot">
<el-date-picker
v-model="searchData.BeginDate"
placeholder="Beginning Month"
type="month"
value-format="yyyy-MM"
format="yyyy-MM"
style="width:120px;"
:picker-options="beginPickerOption"
:clearable="false"
/>
</template>
<template slot="endDateSlot">
<el-date-picker
v-model="searchData.EndDate"
size="small"
placeholder="End Month"
type="month"
value-format="yyyy-MM"
format="yyyy-MM"
style="width:120px;"
:picker-options="endpickerOption"
:clearable="false"
/>
</template>
<template slot="exportSlot">
<el-button
type="primary"
:disabled="arrID.length==0"
@click="handleExportExcel"
>Export Excel</el-button>
</template>
</SearchForm>
</div>
<el-table
ref="workloadStats"
v-adaptive="{bottomOffset:45}"
v-loading="listLoading"
stripe
height="100"
:data="list"
:summary-method="getSummaries"
show-summary
@sort-change="sortByColumn"
@selection-change="handleSelectChange"
>
<el-table-column type="selection" />
<el-table-column type="index" width="40" />
<el-table-column
prop="TrialCode"
sortable="custom"
label="Trial ID"
min-width="150"
show-overflow-tooltip
/>
<el-table-column
prop="Indication"
sortable="custom"
label="Indication"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
prop="Cro"
sortable="custom"
label="CRO"
min-width="90"
show-overflow-tooltip
/>
<el-table-column
label="Name"
show-overflow-tooltip
min-width="100"
prop="FirstName"
sortable="custom"
>
<template slot-scope="scope">{{ scope.row.LastName }} / {{ scope.row.FirstName }}</template>
</el-table-column>
<el-table-column
prop="ChineseName"
sortable="custom"
label="Name CN"
min-width="110"
show-overflow-tooltip
/>
<el-table-column
prop="ReviewerCode"
label="Reviewer ID"
min-width="130"
sortable="custom"
show-overflow-tooltip
/>
<el-table-column prop="Training" sortable="custom" label="Training" min-width="100" show-overflow-tooltip />
<el-table-column prop="RefresherTraining" label="Refresher Training" min-width="170" show-overflow-tooltip sortable="custom" />
<el-table-column label="Timepoint" align="center">
<el-table-column prop="Timepoint" label="Regular" min-width="100" show-overflow-tooltip sortable="custom" />
<el-table-column prop="TimepointIn48H" label="48-hour" min-width="100" show-overflow-tooltip sortable="custom" />
<el-table-column prop="TimepointIn24H" label="24-hour" min-width="100" show-overflow-tooltip sortable="custom" />
</el-table-column>
<el-table-column label="Adjudication" align="center">
<el-table-column prop="Adjudication" label="Regular" min-width="100" show-overflow-tooltip sortable="custom" />
<el-table-column
prop="AdjudicationIn48H"
label="48-hour"
min-width="100"
show-overflow-tooltip
sortable="custom"
/>
<el-table-column
prop="AdjudicationIn24H"
label="24-hour"
min-width="100"
show-overflow-tooltip
sortable="custom"
/>
</el-table-column>
<el-table-column prop="Global" label="Global" min-width="90" show-overflow-tooltip sortable="custom" />
<el-table-column prop="Downtime" label="Downtime" min-width="120" show-overflow-tooltip sortable="custom" />
<el-table-column prop="PersonalTotal" label="Reading Total" min-width="140" show-overflow-tooltip sortable="custom" />
</el-table>
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize" @pagination="getList" />
</box-content>
</template>
<script>
import { getWorkloadByTrialAndReviewer } from '@/api/statistics'
import store from '@/store'
import { mapGetters } from 'vuex'
import { FormatTime } from '@/utils/formatter'
import Excel from 'exceljs'
import { workloadStats_form, workloadStats_handle } from '../statistics'
import Pagination from '@/components/Pagination'
import BoxContent from '@/components/BoxContent'
import SearchForm from '@/components/BaseForm/search-form'
const searchDataDefault = () => {
return {
PageSize: 20,
PageIndex: 1,
Asc: true,
SortField: '',
CROId: '',
TrialCode: '',
Reviewer: '',
BeginDate: FormatTime(new Date(new Date().setMonth(new Date().getMonth() - 5)), 'yyyy-MM'),
EndDate: FormatTime(new Date(), 'yyyy-MM')
}
}
export default {
name: 'WorkloadStats',
components: { Pagination, BoxContent, SearchForm },
data() {
return {
workloadStats_form,
workloadStats_handle,
searchData: searchDataDefault(),
list: [],
listLoading: false,
total: 0,
arrID: [],
beginPickerOption: {
disabledDate: time => {
if (this.searchData.EndDate) {
return time.getTime() > new Date(this.searchData.EndDate).getTime()
} else {
return time.getTime() > Date.now()
}
}
},
endpickerOption: {
disabledDate: time => {
if (this.searchData.BeginDate) {
return time.getTime() > Date.now() || time.getTime() <= new Date(this.searchData.BeginDate).getTime()
} else {
return time.getTime() > Date.now()
}
}
}
}
},
computed: {
...mapGetters(['croList', 'hospitalList'])
},
mounted() {
this.getList()
store.dispatch('global/getCROList')
store.dispatch('global/getHospital')
},
methods: {
// 获取工作量统计列表数据
getList() {
this.listLoading = true
getWorkloadByTrialAndReviewer(this.searchData).then(res => {
this.listLoading = false
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
}).catch(() => { this.listLoading = false })
},
// 查询
handleSearch() {
this.searchData.PageIndex = 1
this.getList()
},
// 重置列表查询
handleReset() {
this.searchData = searchDataDefault()
this.getList()
},
// 统计
getSummaries(param) {
this.$nextTick(() => {
this.$refs.workloadStats.doLayout()
})
const { columns, data } = param
const sums = []
columns.forEach((column, index) => {
if (index === 2) {
sums[index] = 'Total (Current Page)'
return
}
if (column.property === 'TrialCode' || column.property === 'Indication') return
const values = data.map(item => Number(item[column.property]))
if (!values.every(value => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
// sums[index] += ' ?';
} else {
// sums[index] = 'N/A';
}
})
return sums
},
// 排序
sortByColumn(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()
},
// 获取选中行ID
handleSelectChange(val) {
const arr = []
for (let index = 0; index < val.length; index++) {
arr.push(val[index].Id)
}
this.arrID = arr
},
// 导表
handleExportExcel() {
const sheetName = `${this.searchData.BeginDate}~${this.searchData.EndDate}`
const columns = [
{ key: 'Index', width: 5 },
{ key: 'TrialCode', width: 20 },
{ key: 'Indication', width: 15 },
{ key: 'Cro', width: 10 },
{ key: 'LastName', width: 15 },
{ key: 'FirstName', width: 15 },
{ key: 'ChineseName', width: 10 },
{ key: 'ReviewerCode', width: 15 },
{ key: 'Training', width: 10 },
{ key: 'RefresherTraining', width: 22 },
{ key: 'Timepoint', width: 10 },
{ key: 'TimepointIn48H', width: 10 },
{ key: 'TimepointIn24H', width: 10 },
{ key: 'Adjudication', width: 10 },
{ key: 'AdjudicationIn48H', width: 10 },
{ key: 'AdjudicationIn24H', width: 10 },
{ key: 'Global', width: 10 },
{ key: 'Downtime', width: 10 },
{ key: 'PersonalTotal', width: 10 }
]
var workbook = new Excel.Workbook()
var sheet = workbook.addWorksheet(sheetName)
sheet.columns = columns
const maxColCode = String.fromCharCode(64 + columns.length)
// 处理标题
sheet.mergeCells(`A1:${maxColCode}2`)
sheet.getCell('A1').value = 'Workload Statistics'
sheet.getCell('A1').alignment = { vertical: 'middle', horizontal: 'center' }
sheet.getCell('A1').font = { name: 'SimSun', family: 4, size: 13, bold: true }
sheet.mergeCells(`A3:${maxColCode}3`)
let conditional = `Beginning Month:${this.searchData.BeginDate} End Month:${this.searchData.EndDate}`
if (this.$refs.CROSelection.selectedLabel) {
conditional = `CRO:${this.$refs.CROSelection.selectedLabel} Beginning Month:${this.searchData.BeginDate} End Month:${this.searchData.EndDate}`
}
sheet.getCell('A3').value = conditional
sheet.getCell('A3').alignment = { vertical: 'middle', horizontal: 'right' }
// 列头
sheet.getRow(4).values = [
'',
'Trial ID',
'Indication',
'CRO',
'Surname',
'Given Name',
'Name CN',
'Reviewer ID',
'Training',
'Refresher Training',
'Timepoint',
'',
'',
'Adjudication',
'',
'',
'Global',
'Downtime',
'Total'
]
sheet.getRow(4).font = { name: 'SimSun', family: 4, size: 11, bold: true }
sheet.getRow(4).alignment = { vertical: 'middle', horizontal: 'left' }
sheet.getRow(5).values = [
'',
'Trial ID',
'Indication',
'CRO',
'Surname',
'Given Name',
'Name CN',
'Reviewer ID',
'Training',
'Refresher Training',
'Regular',
'48-hour',
'24-hour',
'Regular',
'48-hour',
'24-hour',
'Global',
'Downtime',
'Total'
]
sheet.getRow(5).font = { name: 'SimSun', family: 4, size: 11, bold: true }
sheet.getRow(5).alignment = { vertical: 'middle', horizontal: 'left' }
// 合并单元格
sheet.mergeCells('K4:M4')
sheet.mergeCells('N4:P4')
sheet.mergeCells(`A4:A5`)
sheet.mergeCells(`B4:B5`)
sheet.mergeCells('C4:C5')
sheet.mergeCells('D4:D5')
sheet.mergeCells('E4:E5')
sheet.mergeCells('F4:F5')
sheet.mergeCells('G4:G5')
sheet.mergeCells('H4:H5')
sheet.mergeCells('I4:I5')
sheet.mergeCells('J4:J5')
sheet.mergeCells('Q4:Q5')
sheet.mergeCells('R4:R5')
sheet.mergeCells('S4:S5')
var totalParam = {
training: 0,
refreshertraining: 0,
tp: 0,
tp48: 0,
tp24: 0,
aj: 0,
aj48: 0,
aj24: 0,
global: 0,
downtime: 0,
total: 0
}
let index = 1
var exportExcelData = this.list.filter(item => this.arrID.indexOf(item.Id) > -1)
exportExcelData.forEach(element => {
element.Index = index++
totalParam.training += element.Training
totalParam.refreshertraining += element.RefresherTraining
totalParam.tp += element.Timepoint
totalParam.tp48 += element.TimepointIn48H
totalParam.tp24 += element.TimepointIn24H
totalParam.aj += element.Adjudication
totalParam.aj48 += element.AdjudicationIn48H
totalParam.aj24 += element.AdjudicationIn24H
totalParam.global += element.Global
totalParam.downtime += element.Downtime
totalParam.total += element.PersonalTotal
})
sheet.addRows(exportExcelData)
sheet.addRow([
'',
'Total',
'',
'',
'',
'',
'',
'',
totalParam.training,
totalParam.refreshertraining,
totalParam.tp,
totalParam.tp48,
totalParam.tp24,
totalParam.aj,
totalParam.aj48,
totalParam.aj24,
totalParam.global,
totalParam.downtime,
totalParam.total
])
sheet.getRow(exportExcelData.length + 6).font = { name: 'SimSun', family: 4, size: 11, bold: true }
sheet.getColumn(9).numFmt = '#,##0.00'
sheet.getColumn(10).numFmt = '#,##0.00'
sheet.getColumn(11).numFmt = '#,##0.00'
sheet.getColumn(12).numFmt = '#,##0.00'
sheet.getColumn(13).numFmt = '#,##0.00'
sheet.getColumn(14).numFmt = '#,##0.00'
sheet.getColumn(15).numFmt = '#,##0.00'
sheet.getColumn(16).numFmt = '#,##0.00'
sheet.getColumn(17).numFmt = '#,##0.00'
sheet.getColumn(18).numFmt = '#,##0.00'
sheet.getColumn(19).numFmt = '#,##0.00'
sheet.eachRow((row, number) => {
if (number > 3) {
row.eachCell(cell => {
cell.alignment = { vertical: 'center', horizontal: 'left' }
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
}
})
}
})
workbook.xlsx
.writeBuffer({
base64: true
})
.then(function(xls64) {
var data = new Blob([xls64], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
if ('msSaveOrOpenBlob' in navigator) {
window.navigator.msSaveOrOpenBlob(data, `${sheetName} Workload Statistics.xlsx`)
} else {
var a = document.createElement('a')
var url = URL.createObjectURL(data)
a.href = url
a.download = `${sheetName} Workload Statistics.xlsx`
document.body.appendChild(a)
a.click()
setTimeout(function() {
document.body.removeChild(a)
window.URL.revokeObjectURL(url)
}, 0)
}
})
}
}
}
</script>