3 changed files with 486 additions and 3 deletions
-
9src/components/report/TurnoverReport.vue
-
7src/router/index.js
-
473src/views/doctorCheck/checkPicImport.vue
@ -0,0 +1,473 @@ |
|||
<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;"> |
|||
<el-button class="commonbutton" @click="btnImport" 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="280" sortable /> |
|||
<el-table-column prop="fileName" label="导入文件" min-width="180" sortable /> |
|||
</el-table> |
|||
</div> |
|||
</div> |
|||
|
|||
<!--弹窗--> |
|||
<div> |
|||
<!-- 选照片上传 --> |
|||
<el-dialog title="选择照片上传" :visible.sync="upPic.visible" width="800px" height="400" :close-on-click-modal="false" |
|||
:append-to-body="true"> |
|||
<div> |
|||
<div> |
|||
<el-upload action="#" multiple :file-list="fileList" accept=".jpg,.png,.bmp,.gif" list-type="picture-card" |
|||
:on-change="onChange" :auto-upload="false"> |
|||
<i slot="default" class="el-icon-plus"></i> |
|||
<div slot="file" slot-scope="{file}"> |
|||
<img class="el-upload-list__item-thumbnail" :src="file.url" :alt="file.name"> |
|||
<span class="el-upload-list__item-actions"> |
|||
<span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)"> |
|||
<i class="el-icon-zoom-in"></i> |
|||
</span> |
|||
<!-- 不需再下载 |
|||
<span |
|||
v-if="!disabled" |
|||
class="el-upload-list__item-delete" |
|||
@click="handleDownload(file)" |
|||
> |
|||
<i class="el-icon-download"></i> |
|||
</span> |
|||
--> |
|||
<span class="el-upload-list__item-delete" @click="handleRemove(file)"> |
|||
<i class="el-icon-delete"></i> |
|||
</span> |
|||
</span> |
|||
</div> |
|||
</el-upload> |
|||
</div> |
|||
<div style="display: flex;margin-top: 10px;justify-content:space-between;"> |
|||
<div> |
|||
<div style="display: flex;"> |
|||
<el-select v-model="upPic.getCheckNoMode" placeholder="截取检查号" filterable size="small" |
|||
style="width:180px;margin: 0 5px 0 0;"> |
|||
<el-option label="文件名即检查号" value="0" /> |
|||
<el-option label="文件名左侧 ? 个字符" value="1" /> |
|||
<el-option label="文件名右侧 ? 个字符" value="2" /> |
|||
<el-option label="文件名第 ? 至 ? 个字符" value="3" /> |
|||
</el-select> |
|||
<el-input v-model="upPic.startLen" style="width:150px;" size="small" |
|||
v-if="upPic.getCheckNoMode == '1' || upPic.getCheckNoMode == '2' || upPic.getCheckNoMode == '3'" /> |
|||
<span v-if="upPic.getCheckNoMode == '3'" style="padding: 5px 5px;">至</span> |
|||
<el-input v-model="upPic.endLen" style="width:150px;" size="small" v-if="upPic.getCheckNoMode == '3'" /> |
|||
</div> |
|||
</div> |
|||
<div> |
|||
<el-button type="primary" class="btnClass" @click="btnUpload">上传</el-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
<el-dialog :visible.sync="dialogVisible" :append-to-body="true"> |
|||
<img width="100%" :src="dialogImageUrl" alt=""> |
|||
</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 { |
|||
pagePriv: { |
|||
routeUrlorPageName: 'patientRegisterBatch', //当前页面归属路由或归属页面权限名称 |
|||
privs: [] // 页面权限 |
|||
}, |
|||
upPic: { |
|||
visible: false, |
|||
getCheckNoMode: '3', |
|||
startLen: null, |
|||
endLen: null |
|||
}, |
|||
tableData: [], |
|||
dialogImageUrl: '', |
|||
dialogVisible: false, |
|||
fileList: [], |
|||
}; |
|||
}, |
|||
|
|||
|
|||
//组件创建完成,一般页面初始布局放在这里 |
|||
created() { |
|||
//获取用户当前页面的权限 |
|||
let userPriv = window.sessionStorage.getItem('userPriv') |
|||
if (userPriv) this.pagePriv.privs = deepCopy(getPagePriv(this.pagePriv.routeUrlorPageName)) |
|||
|
|||
|
|||
|
|||
}, |
|||
|
|||
//页面挂载完成,一般页面渲染数据放在这里 |
|||
mounted() { |
|||
this.dictInit() |
|||
|
|||
}, |
|||
|
|||
computed: { |
|||
...mapState(["window", "dict", "elProgress", "patientRegister", "customerOrg"]), |
|||
}, |
|||
|
|||
methods: { |
|||
dddw, moment, checkPagePriv, |
|||
dictInit() { |
|||
|
|||
|
|||
//性别(查询 仅档案用) |
|||
getapi("/api/app/sex").then((res) => { |
|||
if (res.code == 1) { |
|||
this.dict.sex = res.data; |
|||
} |
|||
}); |
|||
|
|||
}, |
|||
|
|||
// 导入完后,状态统计 |
|||
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; |
|||
}, |
|||
|
|||
onChange(file, fileList) { |
|||
this.fileList = fileList; |
|||
console.log('file, fileList', file, fileList); |
|||
}, |
|||
|
|||
// 显示选文件与上传 |
|||
btnImport() { |
|||
this.upPic.visible = true |
|||
|
|||
}, |
|||
|
|||
// 上传 |
|||
btnUpload() { |
|||
console.log('that.registerCheckId', this.registerCheckId) |
|||
if (!(this.fileList && typeof this.fileList == 'object' && this.fileList.length > 0)) { |
|||
this.$message.warning({ showClose: true, message: "请选择要上传的文件!" }) |
|||
return |
|||
} |
|||
let checkSize = [] |
|||
this.fileList.forEach(e => { |
|||
if (e.size > 1024 * 1024 * 20) checkSize.push(e.name) |
|||
}); |
|||
|
|||
if (checkSize.length > 0) { |
|||
this.$message.error({ showClose: true, message: `所选文件大于 20MB ,文件过大无法上传` }) |
|||
return; |
|||
} |
|||
|
|||
let that = this; |
|||
let count = 0, err = ''; |
|||
console.log('this.fileList', this.fileList) |
|||
for (let i = 0; i < this.fileList.length; i++) { |
|||
let file = this.fileList[i] |
|||
console.log('file', file) |
|||
let reader = new FileReader(); |
|||
|
|||
// 定义读取文件 |
|||
reader.onload = (event) => { |
|||
let fileName = "" |
|||
let dotIndex = file.name.lastIndexOf('.'); |
|||
if (dotIndex > -1) fileName = file.name.substring(0, dotIndex); |
|||
let data = event.target.result; |
|||
// console.log('base64', data.length, data) |
|||
let checkRequestNo = fileName |
|||
switch (this.upPic.getCheckNoMode) { |
|||
case '1': |
|||
checkRequestNo = fileName.substring(0, this.upPic.startLen) |
|||
if (checkRequestNo.length != this.upPic.startLen) err = `从 ${fileName} 截取的 检查申请号长度不够` |
|||
break; |
|||
case '2': |
|||
checkRequestNo = fileName.substring(fileName.length - this.upPic.startLen) |
|||
if (checkRequestNo.length != this.upPic.startLen) err = `从 ${fileName} 截取的 检查申请号长度不够` |
|||
break; |
|||
case '3': |
|||
checkRequestNo = fileName.substring(this.upPic.startLen - 1, this.upPic.endLen) |
|||
if (checkRequestNo.length != Number(this.upPic.endLen - this.upPic.startLen) + Number(1)) err = `从 ${fileName} 截取的 检查申请号长度不够` |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
count++; |
|||
if (err) { |
|||
that.tableData.push({ |
|||
importState:'导入失败', |
|||
importDes:err, |
|||
fileName, |
|||
}) |
|||
} else { |
|||
let rd = { |
|||
importState:'导入失败', |
|||
importDes:err, |
|||
fileName, |
|||
} |
|||
let body = { |
|||
checkRequestNo, |
|||
pictureName: fileName, |
|||
pictureBase64: data |
|||
} |
|||
postapi('/api/app/RegisterCheckPicture/ImportRegisterCheckPicture', body) |
|||
.then(res => { |
|||
|
|||
if (res.code > -1) { |
|||
rd.importState = "导入成功" |
|||
rd.importDes = "" |
|||
} else { |
|||
rd.importDes = res.message |
|||
} |
|||
}) |
|||
.catch(error => { |
|||
rd.importDes = `${error}` |
|||
}) |
|||
.finally(() => { |
|||
that.tableData.push(rd) |
|||
if (count == that.fileList.length) { |
|||
that.closePicUpload() |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
// 错误处理 |
|||
reader.onerror = function (event) { |
|||
// 读取失败时执行的代码 |
|||
this.$message.error({ showClose: true, message: `文件转 base64 失败:${event.target.error}` }) |
|||
}; |
|||
|
|||
reader.readAsDataURL(file.raw); |
|||
// reader.readAsText(this.fileList[0].raw); |
|||
// reader.readAsBinaryString(this.fileList[0].raw); |
|||
}; |
|||
}, |
|||
|
|||
closePicUpload(){ |
|||
this.upPic.visible = false |
|||
|
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
//导入完后,导入状态显示 |
|||
importRowClassName({ row, rowIndex }) { |
|||
if (row.importState == '导入失败') { |
|||
return "danger"; |
|||
} else { |
|||
return ""; |
|||
} |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
//导入进行时 |
|||
// startRow : 从第几行开始导入,同名判断交互时,续接导入 |
|||
// startRowNameType : 续接导入的第1行,执行 同名判断模式, 3.不提示,按新人导入(前端不用管) |
|||
async importing(startRow, startRowNameType) { |
|||
let body = {} |
|||
for (let i = startRow; i < this.choosedData.length; i++) { |
|||
this.elProgress.percentage = Math.floor( |
|||
((i + 1) * 100) / this.choosedData.length |
|||
); |
|||
|
|||
// 结束导入 |
|||
if (i == this.choosedData.length - 1) { |
|||
this.elProgress.display = false; |
|||
this.seq = -1 |
|||
} |
|||
} |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
//通用导出 |
|||
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() |
|||
} |
|||
} |
|||
}, |
|||
|
|||
//所选体检次数改变时,自动获取登记日期 |
|||
"query.customerOrgRegister.id": { |
|||
// immediate: true, // 立即执行 |
|||
// deep: true, // 深度监听复杂类型内变化 |
|||
handler(newVal, oldVal) { |
|||
if (newVal && newVal != oldVal) { |
|||
this.query.startDate = new Date(this.query.customerOrgRegister.beginTime) |
|||
this.query.endDate = this.query.customerOrgRegister.isComplete == 'N' ? new Date() : new Date(this.query.customerOrgRegister.endTime) |
|||
} |
|||
} |
|||
}, |
|||
|
|||
//选体检新体检次数改变时,获取分组数据 |
|||
"customerOrgRegister.id": { |
|||
// immediate: true, // 立即执行 |
|||
// deep: true, // 深度监听复杂类型内变化 |
|||
handler(newVal, oldVal) { |
|||
if (newVal && newVal != oldVal) { |
|||
this.getGroups(newVal) |
|||
} |
|||
} |
|||
}, |
|||
|
|||
|
|||
}, |
|||
|
|||
|
|||
}; |
|||
</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.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 .menu_item { |
|||
line-height: 24px; |
|||
} |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue