2 changed files with 1004 additions and 0 deletions
@ -0,0 +1,998 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<!--主体--> |
||||
|
<div> |
||||
|
<div class="middlebox"> |
||||
|
<div class="contenttitle"> |
||||
|
体检 / |
||||
|
<span class="contenttitleBold">从文件导入检验结果</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="margin-bottom: 15px;display: flex;justify-content: space-between; |
||||
|
background-color: #fff;border-radius: 8px;padding: 15px;margin-top: 7px;"> |
||||
|
<div></div> |
||||
|
<div style="display: flex;"> |
||||
|
<div style="padding: 0 5px;"> |
||||
|
<a :underline="false" href="/files/检验结果导入模板_纵向.xls"><el-button class="commonbutton" |
||||
|
size="small">下载纵向模版</el-button></a> |
||||
|
</div> |
||||
|
<div style="padding: 0 5px;"> |
||||
|
<a :underline="false" href="/files/检验结果导入模板_横向.xls"><el-button class="commonbutton" |
||||
|
size="small">下载横向模版</el-button></a> |
||||
|
</div> |
||||
|
<div style="padding: 0 5px;"> |
||||
|
<el-button class="commonbutton" @click="seq = 10" size="small">导入</el-button> |
||||
|
</div> |
||||
|
<div style="padding: 0 5px;"> |
||||
|
<el-button class="commonbutton" @click="btnExport('tableData')" size="small" |
||||
|
style="width:140px;">导入后结果状态导出</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div id="tableData" style="padding: 15px;background-color: #fff;border-radius: 8px;"> |
||||
|
<el-table :data="tableData" :row-class-name="importRowClassName" |
||||
|
:height="window.pageHeight < 600 ? 440 : (window.pageHeight - 210)" highlight-current-row size="small" |
||||
|
:summary-method="getSummaries" show-summary> |
||||
|
<el-table-column type="index" label="序号" width="40" align="center" /> |
||||
|
<el-table-column prop="importState" label="导入状态" min-width="80" sortable /> |
||||
|
<el-table-column prop="importDes" label="导入描述" min-width="180" sortable /> |
||||
|
<el-table-column v-for="(item, index) in importCols" :key="`col${index}`" :prop="item.dispLabel" |
||||
|
align="center" :label="item.dataLabel || item.dispLabel" min-width="100" /> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!--弹窗--> |
||||
|
<div> |
||||
|
<el-dialog title="导入EXCEL注意事项" :visible.sync="dialogGroup.fileReadme" width="700px" :show-close="false" |
||||
|
:append-to-body="true" :close-on-click-modal="false"> |
||||
|
<div style="height:400px;padding: 0 20px; "> |
||||
|
<br />导入Excel时,Excel的格式必须符合一定规范,该格式的模板文件可通过下载模板获取。 |
||||
|
<br />注意事项如下: |
||||
|
<br /> |
||||
|
<div style="margin-left: 25px;">1、条码号不能为空,当条码号为检查项目条码时,姓名可以为空,否则不能为空; |
||||
|
<br />2、从仪器导出的数据可能含有标本号与仪器通道,但标本号与仪器通道不参与数据导入; |
||||
|
<br />3、Excel结果纵向排列时,须检查项目与结果的匹配,横向排列时自动匹配; |
||||
|
<br />4、Excel中标题列不能有单元格合并。 |
||||
|
</div> |
||||
|
</div> |
||||
|
<span slot="footer" class="dialog-footer"> |
||||
|
<el-button class="commonbutton" type="primary" @click="seq++">下一步</el-button> |
||||
|
<el-button class="commonbutton" @click="seq = -1">关闭</el-button> |
||||
|
</span> |
||||
|
</el-dialog> |
||||
|
|
||||
|
<el-dialog title="选择文件" :visible.sync="dialogGroup.fileChoose" width="700px" :show-close="false" |
||||
|
:append-to-body="true" :close-on-click-modal="false"> |
||||
|
<div style="height:400px;padding: 0 50px;"> |
||||
|
<!-- webkitdirectory 选择文件属性, multiple 多选属性--> |
||||
|
<div><input id="fileNames" type="file" accept=".xlsx,.xls" @change="changeFileChoose" @focus="fileGetFocus" /> |
||||
|
</div> |
||||
|
<div style="margin: 5px 70px;width:240px;"> |
||||
|
<el-table :data="sheetNames" border ref="sheetNames" height="260" row-click="chooseSheetName" |
||||
|
highlight-current-row size="small"> |
||||
|
<el-table-column prop="sheetName" label="Excel表单名" min-width="200" align="center" /> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
<div style="display: flex;flex-wrap: wrap;"> |
||||
|
<span style="margin-top: 6px;">标题行: 第</span> |
||||
|
<el-input type="number" v-model="readDataOpts.titleRow" size="small" style="width:60px;margin: 0 5px;" /> |
||||
|
<span style="margin-top: 6px;">行</span> |
||||
|
</div> |
||||
|
<div style="margin-top: 7px;display: flex;flex-wrap: wrap;"> |
||||
|
<span style="margin-top: -1px;">Excel结果排列方式:</span> |
||||
|
<el-radio v-model="readDataOpts.resultMode" label="V">纵向排列</el-radio> |
||||
|
<el-radio v-model="readDataOpts.resultMode" label="H">横向排列</el-radio> |
||||
|
</div> |
||||
|
<div style="margin-top: 7px;display: flex;flex-wrap: wrap;"> |
||||
|
<span style="margin-top: -1px;">条码方式:</span> |
||||
|
<el-radio v-model="dataImportOpts.barcodeMode" label="0">人员条码</el-radio> |
||||
|
<el-radio v-model="dataImportOpts.barcodeMode" label="1">项目条码</el-radio> |
||||
|
</div> |
||||
|
<div style="display: flex;flex-wrap: wrap;"> |
||||
|
<span style="margin-top: 6px;">未填检查时间时起始检查时间:</span> |
||||
|
<el-date-picker v-model="dataImportOpts.startCheckDate" type="datetime" placeholder="选择起始检查时间" align="right" |
||||
|
:picker-options="pickerOptions" value-format="yyyy-MM-dd HH:mm:ss" style="width:160px;" size="small"> |
||||
|
</el-date-picker> |
||||
|
<span style="margin-top: 6px;">标本间隔时间:</span> |
||||
|
<el-input type="number" v-model="dataImportOpts.checkInterval" size="small" |
||||
|
style="width:60px;margin: 0 5px;"> |
||||
|
<template slot="append">秒</template> |
||||
|
</el-input> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<span slot="footer" class="dialog-footer"> |
||||
|
<el-button class="commonbutton" type="primary" @click="seq--">上一步</el-button> |
||||
|
<el-button class="commonbutton" type="primary" @click="seq++">下一步</el-button> |
||||
|
<el-button class="commonbutton" @click="seq = -1">关闭</el-button> |
||||
|
</span> |
||||
|
</el-dialog> |
||||
|
|
||||
|
<el-dialog title="选择待导入的结果信息,并执行导入" :visible.sync="dialogGroup.fileDataOpr" width="700px" :show-close="false" |
||||
|
:close-on-click-modal="false"> <!--:append-to-body="true" --> |
||||
|
<div style="height:400px;"> |
||||
|
<div style="margin-top: -10px;"> |
||||
|
1、在标题列右击鼠标可设置实际导入数据的列名,即:标题列有√;(横向排列时,项目列不显示√)<br> |
||||
|
2、按住 Ctr1 或 Shift 键可进行多选;<br> |
||||
|
</div> |
||||
|
<div style="margin: 5px 0px 0px;" @contextmenu.prevent=""> <!-- --> |
||||
|
<el-table :data="excelData" border ref="excelData" @header-contextmenu="headerContextmenu" height="360" |
||||
|
@row-click="chooseDataImport" row-key="id" highlight-current-row size="small" |
||||
|
:row-class-name="handleRowClassName"> |
||||
|
<el-table-column type="index" align="center" label="序号" min-width="40" /> |
||||
|
<!-- |
||||
|
<el-table-column prop="choosed" align="center" label="选中" min-width="40"/> |
||||
|
--> |
||||
|
<el-table-column v-for="(item, index) in excelCols" :key="`col_${index}`" :prop="item.dispLabel" |
||||
|
align="center" :label="(item.val ? '√ ' : '') + (item.dataLabel || item.dispLabel)" |
||||
|
:min-width="100 + index" /> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
</div> |
||||
|
<span slot="footer" class="dialog-footer"> |
||||
|
<div style="display: flex;justify-content: space-between;"> |
||||
|
<div style="display: flex;"> |
||||
|
<el-button class="commonbutton" type="primary" @click="btnChoose('excelData', 'all')">全选</el-button> |
||||
|
<el-button class="commonbutton" type="primary" @click="btnChoose('excelData')">取消全选</el-button> |
||||
|
</div> |
||||
|
<div style="display: flex;"> |
||||
|
<el-button class="commonbutton" type="primary" @click="seq--">上一步</el-button> |
||||
|
<el-button class="commonbutton" type="primary" @click="btnImport">确定导入</el-button> |
||||
|
<el-button class="commonbutton" @click="seq = -1">关闭</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</span> |
||||
|
</el-dialog> |
||||
|
|
||||
|
<!-- 通用进度条 --> |
||||
|
<el-dialog title="数据处理中……" :visible.sync="elProgress.display" width="700px" height="400" :show-close="false" |
||||
|
:close-on-click-modal="false" :append-to-body="true"> |
||||
|
<ElProgressOCX /> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script> |
||||
|
import moment from "moment" |
||||
|
import { mapState, mapActions } from "vuex"; |
||||
|
import { read, readFile, utils } from "xlsx"; |
||||
|
import FileSaver from 'file-saver'; |
||||
|
|
||||
|
import { getapi, postapi, putapi, deletapi } from "@/api/api"; |
||||
|
import { getPagePriv, checkPagePriv, deepCopy, arrayExistObj, arrayFilter, dddw, tcdate } from '../../utlis/proFunc'; |
||||
|
import ElProgressOCX from "../../components/report/ElProgressOCX.vue"; |
||||
|
|
||||
|
|
||||
|
export default { |
||||
|
components: { |
||||
|
ElProgressOCX, |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
|
||||
|
startPoint: -1, // 多选起点 -1 表示未选择 |
||||
|
endPoint: -1, // 多选终点 -1 表示未选择 |
||||
|
rClickRow: null, //右击的行 |
||||
|
rClickColumn: null, //右击的列(预留) |
||||
|
|
||||
|
dialogGroup: { |
||||
|
fileReadme: true, //导入EXCEL注意事项 |
||||
|
fileChoose: false, //选择文件 |
||||
|
fileDataOpr: false, //文件数据分析操作 及导入 |
||||
|
}, |
||||
|
oldSeq: -2, //旧的步骤(辅助区分上一步,下一步) |
||||
|
seq: 10, //当前显示窗口 |
||||
|
|
||||
|
excelCols: [{ dispLabel: '', val: '', dataLabel: '' }], //excel数据列名 {dispLabel:'',val:'',dataLabel:''} |
||||
|
importCols: [], // 实际导入的列(即有设置与 dataCols 匹配的列) |
||||
|
excelData: [], // excel表格数据 |
||||
|
choosedData: [], // 选中的待导入的数据 |
||||
|
toApiBodys: [], // api需要的数据格式 |
||||
|
dataCols: [ |
||||
|
{ dispLabel: '不设置', val: '' }, |
||||
|
{ dispLabel: '条码号', val: 'barcode' }, |
||||
|
{ dispLabel: '姓名', val: 'patientName' }, |
||||
|
{ dispLabel: '标本号', val: 'sampleNo' }, |
||||
|
{ dispLabel: '仪器通道', val: 'deviceChannel' }, |
||||
|
{ dispLabel: '检查时间', val: 'checkDate' }, |
||||
|
{ dispLabel: '检查医生', val: 'checkDoctorName' }, |
||||
|
{ dispLabel: '项目', val: 'itemName' }, |
||||
|
{ dispLabel: '结果', val: 'itemResult' } |
||||
|
], |
||||
|
preBarcode: '', // 上一人条码号 |
||||
|
curCheckDate: '', // 当前检查时间 |
||||
|
|
||||
|
tableData: [], //导入数据状态显示 |
||||
|
|
||||
|
workBook: null, //EXCEL 工作薄 |
||||
|
sheetNames: [], //EXCEL 工作薄中的表单 {sheetName:} |
||||
|
readDataOpts: { |
||||
|
file: '', //选中的文件名 |
||||
|
sheetNameChoosed: '', //当前选中的表格 |
||||
|
titleRow: 1, //标题行 |
||||
|
resultMode: 'V', //Excel 结果排列方式 H:横向 V:纵向 |
||||
|
}, |
||||
|
readDataOptsInit: {}, |
||||
|
|
||||
|
dataImportOpts: { |
||||
|
barcodeMode: '1', // 条码方式: '0'/人员条码;'1'/项目条码 |
||||
|
startCheckDate: '', // 检查起始时间 |
||||
|
checkInterval: 30, // 标本间隔时间(秒) |
||||
|
}, |
||||
|
dataImportOptsInit: {}, |
||||
|
|
||||
|
pickerOptions: { |
||||
|
shortcuts: [{ |
||||
|
text: '今天', |
||||
|
onClick(picker) { |
||||
|
picker.$emit('pick', new Date()); |
||||
|
} |
||||
|
}, { |
||||
|
text: '昨天', |
||||
|
onClick(picker) { |
||||
|
const date = new Date(); |
||||
|
date.setTime(date.getTime() - 3600 * 1000 * 24); |
||||
|
picker.$emit('pick', date); |
||||
|
} |
||||
|
}, { |
||||
|
text: '前天', |
||||
|
onClick(picker) { |
||||
|
const date = new Date(); |
||||
|
date.setTime(date.getTime() - 3600 * 1000 * 48); |
||||
|
picker.$emit('pick', date); |
||||
|
} |
||||
|
}, { |
||||
|
text: '一周前', |
||||
|
onClick(picker) { |
||||
|
const date = new Date(); |
||||
|
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); |
||||
|
picker.$emit('pick', date); |
||||
|
} |
||||
|
}] |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
//组件创建完成,一般页面初始布局放在这里 |
||||
|
created() { |
||||
|
this.seq = 10 |
||||
|
this.readDataOptsInit = Object.assign({}, this.readDataOpts) |
||||
|
this.dataImportOptsInit = Object.assign({}, this.dataImportOpts) |
||||
|
}, |
||||
|
|
||||
|
//页面挂载完成,一般页面渲染数据放在这里 |
||||
|
mounted() { |
||||
|
this.dictInit() |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
computed: { |
||||
|
...mapState(["window", "dict", "elProgress", "patientRegister", "customerOrg"]), |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
dddw, moment, checkPagePriv, |
||||
|
dictInit() { |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
//清空进度数据数据 |
||||
|
clearProcess() { |
||||
|
|
||||
|
let elo = document.getElementById('fileNames') |
||||
|
if (elo) elo.value = ''; // 清空选择的文件 |
||||
|
|
||||
|
this.workBook = null //EXCEL 工作薄 |
||||
|
this.sheetNames = [] //EXCEL 工作薄中的表单 {sheetName:} |
||||
|
|
||||
|
this.readDataOpts = Object.assign({}, this.readDataOptsInit) |
||||
|
this.dataImportOpts = Object.assign({}, this.dataImportOptsInit) |
||||
|
|
||||
|
this.startPoint = -1 // 多选起点 -1 表示未选择 |
||||
|
this.endPoint = -1 // 多选终点 -1 表示未选择 |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
//第一次点下一步 |
||||
|
btnFirst() { |
||||
|
if (!this.peisid || this.peisid == 'null') { |
||||
|
this.$message.warning("该用户未选归属体检中心,不能执行此操作!"); |
||||
|
return |
||||
|
} |
||||
|
this.seq = 11 |
||||
|
}, |
||||
|
|
||||
|
// 导入过程 上一步,下一步 |
||||
|
async btnProcess(seq) { |
||||
|
let keys = Object.keys(this.dialogGroup) |
||||
|
let count = 0 //选中待导入的人员数 |
||||
|
|
||||
|
if (seq == 9 || seq == 29) { |
||||
|
this.workBook = null |
||||
|
this.sheetNameChoosed = '' |
||||
|
seq = 0 |
||||
|
} |
||||
|
if (seq == 19) seq = 0 |
||||
|
|
||||
|
// console.log('keys',keys) |
||||
|
switch (seq) { |
||||
|
case -1: |
||||
|
//关闭所有弹窗 |
||||
|
keys.forEach(e => { |
||||
|
this.dialogGroup[e] = false |
||||
|
}) |
||||
|
this.clearProcess() |
||||
|
break; |
||||
|
case 10: |
||||
|
this.excelCols = [] |
||||
|
this.tableData = [] |
||||
|
this.startPoint = -1 // 多选起点 -1 表示未选择 |
||||
|
this.endPoint = -1 // 多选终点 -1 表示未选择 |
||||
|
//显示 EXCEL 导入 |
||||
|
keys.forEach(e => { |
||||
|
if (e == 'fileReadme') { |
||||
|
this.dialogGroup[e] = true |
||||
|
} else { |
||||
|
this.dialogGroup[e] = false |
||||
|
} |
||||
|
}) |
||||
|
break; |
||||
|
case 11: |
||||
|
//显示 文件选择 窗口 |
||||
|
keys.forEach(e => { |
||||
|
if (e == 'fileChoose') { |
||||
|
this.dialogGroup[e] = true |
||||
|
} else { |
||||
|
this.dialogGroup[e] = false |
||||
|
} |
||||
|
}) |
||||
|
break; |
||||
|
case 12: |
||||
|
// 从后面退回时,无需读数据 |
||||
|
if (this.oldSeq < seq) { |
||||
|
if (!this.readData()) { |
||||
|
this.seq-- |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
//显示 数据分析操作 窗口 |
||||
|
|
||||
|
if (!this.dataImportOpts.startCheckDate) { |
||||
|
this.$message.warning({ showClose: true, message: '请选择起始检查时间' }) |
||||
|
break; |
||||
|
} |
||||
|
if (!this.dataImportOpts.checkInterval) { |
||||
|
this.$message.warning({ showClose: true, message: '请填写标本间隔时间' }) |
||||
|
break; |
||||
|
} else { |
||||
|
try { |
||||
|
Number(this.dataImportOpts.checkInterval) |
||||
|
} catch (error) { |
||||
|
this.$message.warning({ showClose: true, message: '标本间隔时间只能填写数字' }) |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
keys.forEach(e => { |
||||
|
if (e == 'fileDataOpr') { |
||||
|
this.dialogGroup[e] = true |
||||
|
} else { |
||||
|
this.dialogGroup[e] = false |
||||
|
} |
||||
|
}) |
||||
|
break; |
||||
|
case 13: |
||||
|
count = 0 |
||||
|
this.excelData.forEach(e => { |
||||
|
if (e.choosed) count++ |
||||
|
}) |
||||
|
if (count == 0) { |
||||
|
this.$message.warning("未选中要导入的记录") |
||||
|
this.seq-- |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
//显示 文件数据导入前参数设定 窗口 |
||||
|
keys.forEach(e => { |
||||
|
if (e == 'fileDataOpts') { |
||||
|
this.dialogGroup[e] = true |
||||
|
} else { |
||||
|
this.dialogGroup[e] = false |
||||
|
} |
||||
|
}) |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
//导入完后,导入状态显示 |
||||
|
importRowClassName({ row, rowIndex }) { |
||||
|
if (row.importState == '导入失败') { |
||||
|
return "danger"; |
||||
|
} else { |
||||
|
return ""; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
//多选 颜色标记 |
||||
|
handleRowClassName({ row, rowIndex }) { |
||||
|
if (row.choosed) { |
||||
|
return "current-row"; |
||||
|
} else { |
||||
|
return ""; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 导入完后,状态统计 |
||||
|
getSummaries(param) { |
||||
|
const { columns, data } = param; |
||||
|
const sumCol = [2]; //需合计的列 |
||||
|
const sums = []; |
||||
|
let success = 0, fail = 0; |
||||
|
|
||||
|
columns.forEach((column, index) => { |
||||
|
//显示合计列 |
||||
|
if (index === 1) { |
||||
|
sums[index] = "导入合计"; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
//不合计的列 |
||||
|
if (sumCol.indexOf(index) == -1) { |
||||
|
sums[index] = ""; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
data.forEach((item) => { |
||||
|
console.log('item,column.property', item, column.property) |
||||
|
if (item[column.property]) { |
||||
|
fail++ |
||||
|
} else { |
||||
|
success++ |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
}); |
||||
|
sums[2] = `成功:${success} 条,失败:${fail} 条。` |
||||
|
|
||||
|
return sums; |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
//清除所选文件 |
||||
|
fileGetFocus(e) { |
||||
|
console.log('fileGetFocus(e)', e) |
||||
|
e.value = '' //未起作用的 |
||||
|
// e.target.files = [] |
||||
|
}, |
||||
|
|
||||
|
// 获取选择的文件 |
||||
|
changeFileChoose(e) { |
||||
|
if (e.target.files.length <= 0) return; |
||||
|
// console.log('file',e.target.files[0]) |
||||
|
this.readDataOpts.file = e.target.files[0]; |
||||
|
// 调用导入Excel文件的方法 |
||||
|
// File {name: 'vulkan-1.dll', |
||||
|
// console.log('file',file,file.type) |
||||
|
let fileName = this.readDataOpts.file.name.split('.') |
||||
|
let fileNameExt = fileName[fileName.length - 1].toLowerCase() |
||||
|
if (fileNameExt != 'xls' && fileNameExt != 'xlsx') { |
||||
|
this.$message.warning("你选的文件可能不是标准的Excel文件!") |
||||
|
} |
||||
|
this.readFile(this.readDataOpts.file); |
||||
|
}, |
||||
|
|
||||
|
//sheetjs 读取文件 |
||||
|
readFile(file) { |
||||
|
const reader = new FileReader(); |
||||
|
|
||||
|
// reader.readAsArrayBuffer(file); |
||||
|
// 定义读取文件 |
||||
|
reader.onload = (e) => { |
||||
|
let data = e.target.result; |
||||
|
// let typedArray = new Uint8Array(data); |
||||
|
// var workBook = read(typedArray,{type:'array'}) |
||||
|
// this.workBook = read(data,{type:'binary',cellDates:true}) //日期将转成 标准 日期格式,显示会 undefined |
||||
|
this.workBook = read(data, { type: 'binary' }) |
||||
|
// var workBook = readFile(file); //后端读法 |
||||
|
|
||||
|
this.sheetNames = [] |
||||
|
this.workBook.SheetNames.forEach(e => { |
||||
|
this.sheetNames.push({ sheetName: e }) |
||||
|
}) |
||||
|
|
||||
|
this.$nextTick(() => { |
||||
|
this.$refs['sheetNames'].setCurrentRow(this.sheetNames[0]); |
||||
|
this.chooseSheetName(this.sheetNames[0]) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 错误处理 |
||||
|
reader.onerror = function (event) { |
||||
|
// 读取失败时执行的代码 |
||||
|
console.error("File could not be read!" + event.target.error); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
reader.readAsBinaryString(file); |
||||
|
}, |
||||
|
|
||||
|
//选择要导入的Excel表单名 |
||||
|
chooseSheetName(row) { |
||||
|
this.readDataOpts.sheetNameChoosed = row.sheetName |
||||
|
}, |
||||
|
|
||||
|
//读取数据 |
||||
|
readData() { |
||||
|
let ret = 1 |
||||
|
if (!this.readDataOpts.file || !this.workBook || !this.readDataOpts.sheetNameChoosed) { |
||||
|
this.$message.warning("请选择文件及要导入的表格") |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
if (this.readDataOpts.titleRow <= 0) { |
||||
|
this.$message.warning("标题行不能小于1") |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
|
||||
|
let worksheet = this.workBook.Sheets[this.readDataOpts.sheetNameChoosed]; |
||||
|
|
||||
|
//分析标题信息 |
||||
|
let head = utils.sheet_to_json(worksheet, { header: 1 }); |
||||
|
|
||||
|
this.excelCols = [] |
||||
|
head[this.readDataOpts.titleRow - 1].forEach(e => { |
||||
|
let lfind = arrayExistObj(this.dataCols, 'dispTitle', e), val = '', dataLabel = ''; |
||||
|
if (lfind > -1) { |
||||
|
val = this.dataCols[lfind].val |
||||
|
dataLabel = this.dataCols[lfind].dataLabel |
||||
|
} |
||||
|
this.excelCols.push({ |
||||
|
dispLabel: e, |
||||
|
val, |
||||
|
dataLabel |
||||
|
}) |
||||
|
}) |
||||
|
//console.log('head,',head,this.excelCols) |
||||
|
|
||||
|
this.excelData = utils.sheet_to_json(worksheet, { raw: false, range: this.readDataOpts.titleRow - 1 }); //raw:false,range:1 从第1行开始读取 |
||||
|
this.excelData.forEach((e, index) => { |
||||
|
e.choosed = false; |
||||
|
e.index = index; |
||||
|
e.id = 'excelData' + index; |
||||
|
|
||||
|
}); |
||||
|
//console.log('this.excelCols',this.excelCols) |
||||
|
// console.log('sheet_to_json excelData',this.excelData) |
||||
|
|
||||
|
// 导入后,批量分析Excel列 与 数据字段 的匹配关系 |
||||
|
this.parseExcelData() |
||||
|
|
||||
|
return ret |
||||
|
}, |
||||
|
|
||||
|
//选择要导入的数据 |
||||
|
chooseDataImport(row) { |
||||
|
// console.log("this.excelData",this.excelData); |
||||
|
|
||||
|
// 按住了shift键 |
||||
|
if (this.window.shift) { |
||||
|
//清除所有选择 |
||||
|
this.excelData.forEach((e, index) => { |
||||
|
e.choosed = false; |
||||
|
e.index = index; |
||||
|
}); |
||||
|
|
||||
|
if (this.startPoint == -1) { |
||||
|
this.excelData[row.index].choosed = true; |
||||
|
this.startPoint = row.index; |
||||
|
} else { |
||||
|
if (this.startPoint > row.index) { |
||||
|
for (let i = row.index; i <= this.startPoint; i++) { |
||||
|
this.excelData[i].choosed = true; |
||||
|
} |
||||
|
} else if (this.startPoint <= row.index) { |
||||
|
for (let i = this.startPoint; i <= row.index; i++) { |
||||
|
this.excelData[i].choosed = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} else if (this.window.ctrl) { // 按住了ctrl 键 |
||||
|
this.excelData[row.index].choosed = true; |
||||
|
if (this.startPoint == -1) { |
||||
|
this.startPoint = row.index; |
||||
|
} |
||||
|
} else { |
||||
|
// 未按住了ctrl 、shift 键 |
||||
|
//清除所有选择 |
||||
|
console.log("清除所有选择"); |
||||
|
this.excelData.forEach((e, index) => { |
||||
|
e.choosed = false; |
||||
|
e.index = index; |
||||
|
}); |
||||
|
// console.log(this.excelData,row.index); |
||||
|
// console.log(this.excelData[row.index].choosed); |
||||
|
|
||||
|
this.excelData[row.index].choosed = true; |
||||
|
this.startPoint = row.index; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 全选(取消全选) |
||||
|
btnChoose(refName, type) { |
||||
|
let choosed = false |
||||
|
if (type && type == 'all') { |
||||
|
choosed = true |
||||
|
} |
||||
|
this[refName].forEach(e => { |
||||
|
e.choosed = choosed |
||||
|
if (choosed) { |
||||
|
this.$refs[refName].setCurrentRow(e) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
if (!choosed) { |
||||
|
this.$refs[refName].setCurrentRow() |
||||
|
} |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
//右击标题 |
||||
|
headerContextmenu(column, event) { |
||||
|
let chooseCol = column.minWidth - 100 |
||||
|
let items = [] //菜单 |
||||
|
|
||||
|
this.dataCols.forEach(e => { |
||||
|
if (!(this.readDataOpts.resultMode == 'H' && (e.val == 'itemResult' || e.val == 'itemName'))) { |
||||
|
items.push({ |
||||
|
label: e.dispLabel, |
||||
|
onClick: () => { |
||||
|
this.setColumn(chooseCol, e) |
||||
|
}, |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
//右击显示的菜单 |
||||
|
this.$contextmenu({ |
||||
|
items, |
||||
|
event, |
||||
|
//x: event.clientX, |
||||
|
//y: event.clientY, |
||||
|
customClass: "custom-class", |
||||
|
zIndex: 30000, //够大再能在最上面显示 |
||||
|
minWidth: 80, |
||||
|
height: 20 |
||||
|
}); |
||||
|
|
||||
|
return false; |
||||
|
}, |
||||
|
|
||||
|
//设置真实数据字段列 |
||||
|
setColumn(oldColNum, newColObj) { |
||||
|
// console.log('oldColNum,newColObj',oldColNum,newColObj) |
||||
|
//如果数据字段已设置过,则将之前设置的先清空 |
||||
|
if (newColObj.dispLabel != "不设置") { |
||||
|
let lfind = arrayExistObj(this.excelCols, 'dataLabel', newColObj.dispLabel) |
||||
|
if (lfind > -1) { |
||||
|
this.excelCols[lfind].dataLabel = '' |
||||
|
this.excelCols[lfind].val = '' |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.excelCols[oldColNum].dataLabel = newColObj.dispLabel |
||||
|
this.excelCols[oldColNum].val = newColObj.val |
||||
|
// console.log('newColObj.val',newColObj.val) |
||||
|
let tempDate = '' |
||||
|
if (newColObj.val == 'birthDate') { |
||||
|
this.excelData.forEach(e => { |
||||
|
tempDate = e[this.excelCols[oldColNum].dispLabel] |
||||
|
// console.log('birthDate',tempDate) |
||||
|
e[this.excelCols[oldColNum].dispLabel] = tempDate ? moment(new Date(tempDate)).format('yyyy-MM-DD') : '' |
||||
|
}) |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 选择EXCEL文件后,批量分析Excel列 与 数据字段 的匹配关系 |
||||
|
parseExcelData() { |
||||
|
let lfind = -1 |
||||
|
this.excelCols.forEach((e, i) => { |
||||
|
lfind = arrayExistObj(this.dataCols, 'dispLabel', e.dispLabel) |
||||
|
if (lfind > -1) this.setColumn(i, this.dataCols[lfind]) |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 确定导入数据库 |
||||
|
btnImport() { |
||||
|
|
||||
|
this.elProgress.display = true; |
||||
|
this.elProgress.percentage = 0; |
||||
|
|
||||
|
this.importCols = [] |
||||
|
this.excelCols.forEach(e => { |
||||
|
if (e.val) { |
||||
|
this.importCols.push(e) |
||||
|
} |
||||
|
}) |
||||
|
this.tableData = [] // 记录导入后结果状态 |
||||
|
this.choosedData = [] //选中待导入的数据 |
||||
|
this.excelData.forEach(e => { |
||||
|
if (e.choosed) this.choosedData.push(e) |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
//导入进行中 |
||||
|
this.importing() |
||||
|
// 开始导入时,清除选择的 文件 |
||||
|
document.getElementById('fileNames').value = ''; |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
//导入进行时 |
||||
|
async importing() { |
||||
|
|
||||
|
// 将Excel的数据转换成接口的数据 |
||||
|
this.excelDataToApiBodys(this.choosedData) |
||||
|
console.log('this.toApiBodys', this.toApiBodys) |
||||
|
|
||||
|
// 旧接口:/api/app/patientregister/createpatientregisterexcel |
||||
|
for (let i = 0; i < this.toApiBodys.length; i++) { |
||||
|
this.elProgress.percentage = Math.floor( |
||||
|
((i + 1) * 100) / this.choosedData.length |
||||
|
); |
||||
|
|
||||
|
let res = await postapi('/api/app/ImportRegularResult/ImportRegularItemResultExcel', this.toApiBodys[i]) |
||||
|
if (res.code >= 0) { |
||||
|
this.tableData.push(Object.assign({ importState: '导入成功' }, this.toApiBodys[i])) |
||||
|
} else { |
||||
|
this.tableData.push(Object.assign({ importState: '导入失败', importDes: res.message }, this.toApiBodys[i])) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 结束导入 |
||||
|
this.elProgress.display = false; |
||||
|
this.seq = -1 |
||||
|
}, |
||||
|
|
||||
|
//将Excel的数据转换成接口的数据 |
||||
|
excelDataToApiBodys(ExcelAllChoosedData) { |
||||
|
this.toApiBodys = [] |
||||
|
ExcelAllChoosedData.forEach(e => { |
||||
|
this.excelDataToApiBody(e) |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
//将Excel的数据转换成接口的数据 |
||||
|
excelDataToApiBody(ExcelData) { |
||||
|
console.log('ExcelData,this.excelCols', ExcelData, this.excelCols) |
||||
|
let body = { |
||||
|
barcodeMode: this.dataImportOpts.barcodeMode |
||||
|
} |
||||
|
// 纵向数据 |
||||
|
if (this.readDataOpts.resultMode == 'V') { |
||||
|
|
||||
|
this.excelCols.forEach(e => { |
||||
|
if (e.val) { |
||||
|
switch (e.val) { |
||||
|
// case 'age': |
||||
|
// if (ExcelData[e.dispLabel]) body[e.val] = parseInt(ExcelData[e.dispLabel]) |
||||
|
// break; |
||||
|
// case 'birthDate': |
||||
|
// if(ExcelData[e.dispLabel]) body[e.val] = moment(new Date(ExcelData[e.dispLabel])).format('yyyy-MM-DD') |
||||
|
// break; |
||||
|
// case 'poisons': |
||||
|
// if (ExcelData[e.dispLabel]) body[e.val] = ExcelData[e.dispLabel].replaceAll(",", ",").split(",") |
||||
|
// break; |
||||
|
default: |
||||
|
body[e.val] = ExcelData[e.dispLabel] |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
if (!body.checkDate) { |
||||
|
// console.log('body.checkDate,this.preBarcode,this.curCheckDate',body.checkDate,this.preBarcode,this.curCheckDate) |
||||
|
if (!this.preBarcode) { |
||||
|
this.preBarcode = body.barcode |
||||
|
this.curCheckDate = this.dataImportOpts.startCheckDate |
||||
|
} |
||||
|
|
||||
|
if (this.preBarcode != body.barcode) { |
||||
|
this.preBarcode = body.barcode |
||||
|
this.curCheckDate = moment(new Date(new Date(this.curCheckDate).getTime() + Number(this.dataImportOpts.checkInterval) * 1000)).format('yyyy-MM-DD HH:mm:ss') |
||||
|
} |
||||
|
body.checkDate = this.curCheckDate |
||||
|
} |
||||
|
if (body.deviceChannel == undefined) delete body.deviceChannel |
||||
|
if (body.sampleNo == undefined) delete body.sampleNo |
||||
|
|
||||
|
let lfind = arrayExistObj(this.toApiBodys,'barcode',body.barcode) |
||||
|
let detail = { itemName: body.itemName, itemResult: body.itemResult, checkDate: body.checkDate } |
||||
|
if(body.checkDoctorName) detail.checkDoctorName = body.checkDoctorName |
||||
|
if(lfind == -1){ |
||||
|
this.toApiBodys.push(Object.assign({},body,{details:[detail]})) |
||||
|
}else{ |
||||
|
this.toApiBodys[this.toApiBodys.length - 1].details.push(detail) |
||||
|
} |
||||
|
} else { |
||||
|
// 横向数据 |
||||
|
// { dataLabel: "", dispLabel: "P LCR", val: "" } |
||||
|
body = { |
||||
|
barcode: ExcelData['条码号'], |
||||
|
barcodeMode: this.dataImportOpts.barcodeMode, |
||||
|
patientName: ExcelData['姓名'], |
||||
|
sampleNo: ExcelData['标本号'], |
||||
|
deviceChannel: ExcelData['仪器通道'], |
||||
|
checkDate: ExcelData['检查时间'], |
||||
|
checkDoctorName: ExcelData['检查医生'], |
||||
|
details: [] |
||||
|
} |
||||
|
|
||||
|
|
||||
|
if (!body.checkDate) { |
||||
|
// console.log('body.checkDate,this.preBarcode,this.curCheckDate',body.checkDate,this.preBarcode,this.curCheckDate) |
||||
|
if (!this.preBarcode) { |
||||
|
this.preBarcode = body.barcode |
||||
|
this.curCheckDate = this.dataImportOpts.startCheckDate |
||||
|
} |
||||
|
|
||||
|
if (this.preBarcode != body.barcode) { |
||||
|
this.preBarcode = body.barcode |
||||
|
this.curCheckDate = moment(new Date(new Date(this.curCheckDate).getTime() + Number(this.dataImportOpts.checkInterval) * 1000)).format('yyyy-MM-DD HH:mm:ss') |
||||
|
} |
||||
|
body.checkDate = this.curCheckDate |
||||
|
} |
||||
|
|
||||
|
if (body.deviceChannel == undefined) delete body.deviceChannel |
||||
|
if (body.sampleNo == undefined) delete body.sampleNo |
||||
|
// [ |
||||
|
// { dispLabel: '条码号', val: 'barcode' }, |
||||
|
// { dispLabel: '姓名', val: 'patientName' }, |
||||
|
// { dispLabel: '标本号', val: 'sampleNo' }, |
||||
|
// { dispLabel: '仪器通道', val: 'deviceChannel' }, |
||||
|
// { dispLabel: '检查时间', val: 'checkDate' }, |
||||
|
// { dispLabel: '项目', val: 'itemName' }, |
||||
|
// { dispLabel: '结果', val: 'itemResult' } |
||||
|
// ] |
||||
|
this.excelCols.forEach(e => { |
||||
|
if (!e.dataLabel && !e.val) { |
||||
|
let detail = { itemName: e.dispLabel, itemResult: ExcelData[e.dispLabel], checkDate: body.checkDate } |
||||
|
if(body.checkDoctorName) detail.checkDoctorName = body.checkDoctorName |
||||
|
body.details.push(detail) |
||||
|
} |
||||
|
}) |
||||
|
this.toApiBodys.push(body) |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
|
||||
|
//选择要导入的数据 |
||||
|
rowClickPrList(row) { |
||||
|
// console.log("this.excelData",this.excelData); |
||||
|
|
||||
|
// 按住了shift键 |
||||
|
if (this.window.shift) { |
||||
|
//清除所有选择 |
||||
|
this.prList.forEach((e, index) => { |
||||
|
e.choosed = false; |
||||
|
e.index = index; |
||||
|
}); |
||||
|
|
||||
|
if (this.startPoint == -1) { |
||||
|
this.prList[row.index].choosed = true; |
||||
|
this.startPoint = row.index; |
||||
|
} else { |
||||
|
if (this.startPoint > row.index) { |
||||
|
for (let i = row.index; i <= this.startPoint; i++) { |
||||
|
this.prList[i].choosed = true; |
||||
|
} |
||||
|
} else if (this.startPoint <= row.index) { |
||||
|
for (let i = this.startPoint; i <= row.index; i++) { |
||||
|
this.prList[i].choosed = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} else if (this.window.ctrl) { // 按住了ctrl 键 |
||||
|
this.prList[row.index].choosed = true; |
||||
|
if (this.startPoint == -1) { |
||||
|
this.startPoint = row.index; |
||||
|
} |
||||
|
} else { |
||||
|
// 未按住了ctrl 、shift 键 |
||||
|
//清除所有选择 |
||||
|
console.log("清除所有选择"); |
||||
|
this.prList.forEach((e, index) => { |
||||
|
e.choosed = false; |
||||
|
e.index = index; |
||||
|
}); |
||||
|
// console.log(this.excelData,row.index); |
||||
|
// console.log(this.excelData[row.index].choosed); |
||||
|
|
||||
|
this.prList[row.index].choosed = true; |
||||
|
this.startPoint = row.index; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
//通用导出 |
||||
|
btnExport(elId) { |
||||
|
let table = document.getElementById(elId); |
||||
|
let tableData = table.innerHTML |
||||
|
let fileName = moment(new Date()).format('yyyyMMDDHHmmss') + '.xls' |
||||
|
let blob = new Blob([tableData], { type: "text/plain;charset=utf-8" }); |
||||
|
FileSaver.saveAs(blob, fileName); |
||||
|
}, |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
watch: { |
||||
|
"seq": { |
||||
|
immediate: true, // 立即执行 |
||||
|
// // deep: true, // 深度监听复杂类型内变化 |
||||
|
handler(newVal, oldVal) { |
||||
|
console.log('watch:seq:', newVal, oldVal) |
||||
|
if (!oldVal && oldVal != 0) { |
||||
|
this.oldSeq = -2 |
||||
|
} else { |
||||
|
this.oldSeq = oldVal |
||||
|
} |
||||
|
if (newVal != oldVal) { |
||||
|
this.btnProcess(newVal); |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
"readDataOpts.titleRow": { |
||||
|
// immediate: true, // 立即执行 |
||||
|
// deep: true, // 深度监听复杂类型内变化 |
||||
|
handler(newVal, oldVal) { |
||||
|
console.log('watch:readDataOpts.titleRow:', newVal, oldVal) |
||||
|
if (newVal && newVal != oldVal) { |
||||
|
if (this.seq == 11) this.readData() |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
}; |
||||
|
</script> |
||||
|
<style scoped> |
||||
|
@import '../../assets/css/global_button.css'; |
||||
|
@import '../../assets/css/global_card.css'; |
||||
|
@import '../../assets/css/global_dialog.css'; |
||||
|
@import '../../assets/css/global_form.css'; |
||||
|
@import '../../assets/css/global_input.css'; |
||||
|
@import '../../assets/css/global_table.css'; |
||||
|
@import '../../assets/css/global_menu.css'; |
||||
|
@import '../../assets/css/global.css'; |
||||
|
|
||||
|
|
||||
|
.spanLeftClass { |
||||
|
margin-top: 6px; |
||||
|
width: 70px; |
||||
|
} |
||||
|
|
||||
|
.spanMidClass { |
||||
|
text-align: center; |
||||
|
margin-top: 6px; |
||||
|
width: 50px; |
||||
|
} |
||||
|
|
||||
|
/* type=number 显示微调按钮 */ |
||||
|
::v-deep input[type="number"]::-webkit-inner-spin-button, |
||||
|
input[type="number"]::-webkit-outer-spin-button { |
||||
|
-webkit-appearance: button !important; |
||||
|
margin: 0 -12px 0 0 !important; |
||||
|
} |
||||
|
|
||||
|
::v-deep .el-table__header th { |
||||
|
font-family: "Microsoft YaHei"; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue