You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1679 lines
62 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <template>
  2. <div>
  3. <el-card>
  4. <div slot="header">批量预登记</div>
  5. <div style="display: flex;margin-bottom: 10px;justify-content:space-between;">
  6. <div></div>
  7. <div style="display: flex;">
  8. <div>
  9. <a :underline="false" href="/files/单位体检人员名单导入模板.xlsx"><el-button class="btnClass">下载导入模版</el-button></a>
  10. </div>
  11. <div>
  12. <el-button class="btnClass" @click="seq = 0">导入</el-button>
  13. </div>
  14. <div>
  15. <el-button class="btnClass" @click="btnExport('tableData')">导入后结果状态导出</el-button>
  16. </div>
  17. </div>
  18. </div>
  19. <div id="tableData">
  20. <el-table :data="tableData" border v-if="mode=='10'" :row-class-name="importRowClassName"
  21. :height="window.pageHeight < 600 ? 405 : (window.pageHeight - 195)"
  22. highlight-current-row size="small" :summary-method="getSummaries" show-summary>
  23. <el-table-column type="index" label="序号" width="40" align="center"/>
  24. <el-table-column prop="importState" label="导入状态" min-width="80" sortable/>
  25. <el-table-column prop="importDes" label="导入描述" min-width="180" sortable/>
  26. <el-table-column v-for="(item,index) in importCols" :key="`col${index}`" :prop="item.dispLabel" align="center"
  27. :label="item.dataLabel || item.dispLabel" min-width="100"/>
  28. </el-table>
  29. <el-table :data="tableData" border v-if="mode=='20'" :row-class-name="importRowClassName"
  30. :height="window.pageHeight < 600 ? 405 : (window.pageHeight - 195)"
  31. highlight-current-row size="small" >
  32. <el-table-column type="index" label="序号" width="40" align="center"/>
  33. <el-table-column prop="importState" label="导入状态" min-width="80" sortable/>
  34. <el-table-column prop="importDes" label="导入描述" min-width="180" sortable/>
  35. <el-table-column prop="patientNo" align="center" label="档案号" min-width="80"/>
  36. <el-table-column prop="medicalTimes" align="center" label="体检次数" min-width="80"/>
  37. <el-table-column prop="patientName" align="center" label="姓名" min-width="80"/>
  38. <el-table-column prop="sexId" align="center" label="性别" min-width="40">
  39. <template slot-scope="scope">
  40. <div>{{ dddw(dict.sex, "id", scope.row.sexId, "displayName") }}</div>
  41. </template>
  42. </el-table-column>
  43. <el-table-column prop="birthDate" align="center" label="出生日期" min-width="80">
  44. <template slot-scope="scope">
  45. <div>{{ scope.row.birthDate ? moment(new Date(scope.row.birthDate)).format('yyyy-MM-DD'):'' }}</div>
  46. </template>
  47. </el-table-column>
  48. <el-table-column prop="age" align="center" label="年龄" min-width="40"/>
  49. <el-table-column prop="customerOrgParentName" align="center" label="单位" min-width="150"/>
  50. <el-table-column prop="customerOrgName" align="center" label="部门" min-width="120"/>
  51. <el-table-column prop="telephone" align="center" label="电话" min-width="100"/>
  52. <el-table-column prop="mobileTelephone" align="center" label="手机" min-width="100"/>
  53. <el-table-column prop="creatorName" align="center" label="登记人员" min-width="80"/>
  54. <el-table-column prop="creationTime" align="center" label="登记日期" min-width="80">
  55. <template slot-scope="scope">
  56. <div>{{ scope.row.birthDate ? moment(new Date(scope.row.creationTime)).format('yyyy-MM-DD'):'' }}</div>
  57. </template>
  58. </el-table-column>
  59. </el-table>
  60. </div>
  61. </el-card>
  62. <el-dialog title="请选择导入方式" :visible.sync="dialogGroup.mode" width="700px" :show-close="false"
  63. :append-to-body="true" :close-on-click-modal="false">
  64. <div style="height:400px;margin-left: 200px;">
  65. <br/><el-radio v-model="mode" label="10">从Excle导入</el-radio>
  66. <br/>
  67. <br/><el-radio v-model="mode" label="20">从以往体检资料中导入</el-radio>
  68. </div>
  69. <span slot="footer" class="dialog-footer">
  70. <el-button type="primary" @click="btnFirst">下一步</el-button>
  71. <el-button @click="seq = -1">关闭</el-button>
  72. </span>
  73. </el-dialog>
  74. <el-dialog title="导入EXCEL注意事项" :visible.sync="dialogGroup.fileReadme" width="700px" :show-close="false"
  75. :append-to-body="true" :close-on-click-modal="false">
  76. <div style="height:400px;padding: 0 20px; ">
  77. <br/>导入Excel时Excel的格式必须符合一定规范该格式的模板文件放在程序的执行目录下文件名为"单位体检人员名单导入模板.xls"
  78. <br/>注意事项如下:
  79. <br/>
  80. <div style="margin-left: 25px;">1姓名不能为空其余数据可根据实际情况选择是否填写
  81. <br/>2部门单位分组性别婚姻状况人员类别体检类别民族必须与本软件系统中的名称完全一致
  82. <br/>3年龄和出生日期可以只填一栏系统将自动对年龄和出生日期进行相互转换
  83. <br/>4Excel中标题列不能有单元格合并
  84. </div>
  85. </div>
  86. <span slot="footer" class="dialog-footer">
  87. <el-button type="primary" @click="seq--">上一步</el-button>
  88. <el-button type="primary" @click="seq++">下一步</el-button>
  89. <el-button @click="seq = -1">关闭</el-button>
  90. </span>
  91. </el-dialog>
  92. <el-dialog title="选择文件" :visible.sync="dialogGroup.fileChoose" width="700px" :show-close="false"
  93. :append-to-body="true" :close-on-click-modal="false">
  94. <div style="height:400px;padding: 0 50px; ">
  95. <!-- webkitdirectory 选择文件属性 multiple 多选属性-->
  96. <div><input ref="fileNames" type="file" accept=".xlsx,.xls" @change="changeFileChoose" @focus="fileGetFocus"/></div>
  97. <div style="margin: 5px 70px;width:240px;">
  98. <el-table :data="sheetNames" border ref="sheetNames"
  99. height="300" row-click="chooseSheetName"
  100. highlight-current-row size="small" >
  101. <el-table-column prop="sheetName" label="Excel表单名" min-width="200" align="center"/>
  102. </el-table>
  103. </div>
  104. <div style="display: flex;flex-wrap: wrap;">
  105. <span style="margin-top: 6px;">标题行 </span>
  106. <el-input type="number" id="fileNames" v-model="readDataOpts.titleRow" size="small" style="width:60px;margin: 0 5px;"/>
  107. <span style="margin-top: 6px;"></span>
  108. </div>
  109. </div>
  110. <span slot="footer" class="dialog-footer">
  111. <el-button type="primary" @click="seq--">上一步</el-button>
  112. <el-button type="primary" @click="seq++">下一步</el-button>
  113. <el-button @click="seq = -1">关闭</el-button>
  114. </span>
  115. </el-dialog>
  116. <el-dialog title="选择待导入的客户信息" :visible.sync="dialogGroup.fileDataOpr" width="700px" :show-close="false"
  117. :close-on-click-modal="false"> <!--:append-to-body="true" -->
  118. <div style="height:400px;">
  119. <div style="margin-top: -10px;">
  120. 1按住 Ctr1 Shift 键可进行多选在标题列右击鼠标可设置列名标题列有<br>
  121. 2身份证号有值且合法时将以身份证号为主自动换算性别出生日期及年龄<br>
  122. </div>
  123. <div style="margin: 5px 0px 0px;" @contextmenu.prevent=""> <!-- -->
  124. <el-table :data="excelData" border ref="excelData" @header-contextmenu="headerContextmenu"
  125. height="360" @row-click="chooseDataImport" row-key="id"
  126. highlight-current-row size="small" :row-class-name="handleRowClassName">
  127. <el-table-column type="index" align="center" label="序号" min-width="40"/>
  128. <!--
  129. <el-table-column prop="choosed" align="center" label="选中" min-width="40"/>
  130. -->
  131. <el-table-column v-for="(item,index) in excelCols" :key="`col_${index}`" :prop="item.dispLabel" align="center"
  132. :label="(item.val ? '√':'') + (item.dataLabel || item.dispLabel)" :min-width="100+index"/>
  133. </el-table>
  134. </div>
  135. </div>
  136. <span slot="footer" class="dialog-footer">
  137. <el-button type="primary" @click="btnChoose('excelData','all')">全选</el-button>
  138. <el-button type="primary" @click="btnChoose('excelData')" style="margin-right: 300px;">取消全选</el-button>
  139. <el-button type="primary" @click="seq--">上一步</el-button>
  140. <el-button type="primary" @click="seq++">下一步</el-button>
  141. <el-button @click="seq = -1">关闭</el-button>
  142. </span>
  143. </el-dialog>
  144. <el-dialog title="选择单位" :visible.sync="dialogGroup.fileDataOpts" width="700px" :show-close="false"
  145. :close-on-click-modal="false"> <!--:append-to-body="true" -->
  146. <div style="height:400px;">
  147. <div style="margin-top: -10px;">
  148. 选择的人员信息必须直接属于该单位或者是该单位的一级部门,如果人员信息直接属于该单位请将Exce1文件中该人员信息的部门名称设为空
  149. </div>
  150. <div style="display: flex;margin:20px;">
  151. <div>
  152. <span>体检单位</span>
  153. <el-cascader v-model="customerOrgIds" :options="customerOrgTree"
  154. style="width:200px;" @change="changeCustomerOrg" filterable :filter-method="filterMethod"
  155. :props="{ checkStrictly: true, expandTrigger: 'hover', ...customerOrg.treeprops, }"
  156. :show-all-levels="false" size="small">
  157. </el-cascader>
  158. </div>
  159. <div style="margin-left: 20px">
  160. <span>单位体检次数</span>
  161. <el-select
  162. v-model="customerOrgRegister"
  163. placeholder="次数"
  164. style="width: 60px; margin-left: 10px"
  165. size="small"
  166. value-key="id"
  167. >
  168. <el-option
  169. v-for="item in customerOrgRegisterList"
  170. :key="item.id"
  171. :label="item.medicalTimes"
  172. :value="item"
  173. />
  174. </el-select>
  175. </div>
  176. </div>
  177. <div style="display: flex;margin:20px;">
  178. <span>相同姓名的人员</span>
  179. <div style="display: flex;margin-top:20px;">
  180. <el-radio v-model="dataImportOpts.nameType" label="1">同名病人提示</el-radio>
  181. <el-radio v-model="dataImportOpts.nameType" label="2">本单位同名提示</el-radio>
  182. <el-radio v-model="dataImportOpts.nameType" label="3">不提示</el-radio>
  183. </div>
  184. </div>
  185. <div style="display: flex;margin:20px;">
  186. <span>登记状态</span>
  187. <div style="display: flex;margin-top:20px;">
  188. <el-radio v-model="dataImportOpts.completeFlag" label="0">预登记</el-radio>
  189. <el-radio v-model="dataImportOpts.completeFlag" label="1">正式登记</el-radio>
  190. </div>
  191. </div>
  192. <div style="display: flex;margin:20px;">
  193. <span>工卡号</span>
  194. <div style="display: block;margin-top:20px;">
  195. <div style="display: flex;">
  196. <el-checkbox v-model="dataImportOpts.isAutoCreatePatientNo" />
  197. <span style="margin-left:5px;">工卡号作为档案号</span>
  198. </div>
  199. <div style="display: flex;" v-if="dataImportOpts.isAutoCreatePatientNo">
  200. <span style="margin-top:6px;">工卡号开始位置</span>
  201. <el-input type="number" v-model="dataImportOpts.cardStartNum" size="small" style="width:60px;margin: 0 10px 0 0;"/>
  202. <span style="margin-top:6px;">长度</span>
  203. <el-input type="number" v-model="dataImportOpts.cardLength" size="small" style="width:60px;margin: 0 10px 0 0;" />
  204. <span style="margin-top:6px;"> 不足长度时前面补0</span>
  205. </div>
  206. </div>
  207. </div>
  208. <div style="display: flex;margin:20px;">
  209. <span>是否自动创建部门</span>
  210. <el-checkbox v-model="dataImportOpts.isAutoCreateDepartment" />
  211. </div>
  212. </div>
  213. <span slot="footer" class="dialog-footer">
  214. <el-button type="primary" @click="seq--">上一步</el-button>
  215. <el-button type="primary" @click="btnImport">确定导入</el-button>
  216. <el-button @click="seq = -1">关闭</el-button>
  217. </span>
  218. </el-dialog>
  219. <el-dialog title="同名人员信息确认" :visible.sync="dialogSameMan" width="500px" :show-close="false"
  220. :close-on-click-modal="false"> <!--:append-to-body="true" -->
  221. <div style="margin: 5px 0px 0px;" > <!-- -->
  222. <el-table :data="sameMans" border ref="sameMans"
  223. height="260" @row-click="rowClickSameMan" row-key="patientId"
  224. highlight-current-row size="small">
  225. <el-table-column type="index" align="center" label="序号" min-width="40"/>
  226. <el-table-column prop="patientNo" align="center" label="档案号" min-width="80"/>
  227. <el-table-column prop="displayName" align="center" label="姓名" min-width="80"/>
  228. <el-table-column prop="sexId" align="center" label="性别" min-width="40"/>
  229. <el-table-column prop="idNo" align="center" label="身份证号" min-width="150"/>
  230. <el-table-column prop="birthDate" align="center" label="出生日期" min-width="110"/>
  231. <el-table-column prop="telephone" align="center" label="电话" min-width="100"/>
  232. <el-table-column prop="mobileTelephone" align="center" label="手机" min-width="100"/>
  233. </el-table>
  234. </div>
  235. <span slot="footer" class="dialog-footer">
  236. <el-button type="primary" @click="btnOldMan">按档案人员导入</el-button>
  237. <el-button type="primary" @click="btnNewMan">按新人方式导入</el-button>
  238. </span>
  239. </el-dialog>
  240. <!--从历史数据库中查询导入-->
  241. <el-dialog title="选择单位查询条件" :visible.sync="dialogGroup.query" width="700px" :show-close="false"
  242. :close-on-click-modal="false"> <!--:append-to-body="true" -->
  243. <div style="height:400px;">
  244. <div style="margin-top: -10px;">
  245. 选择单位时必须选择其体检次数
  246. </div>
  247. <div style="display: flex;margin:20px;">
  248. <span class="spanLeftClass">体检单位</span>
  249. <el-cascader v-model="query.customerOrgIds" :options="customerOrgTree"
  250. style="width:200px;" @change="changeQueryCustomerOrg" filterable :filter-method="filterMethod"
  251. :props="{ checkStrictly: true, expandTrigger: 'hover', ...customerOrg.treeprops, }"
  252. :show-all-levels="false" size="small">
  253. </el-cascader>
  254. <div style="margin-left: 20px">
  255. <span>单位体检次数</span>
  256. <el-select
  257. v-model="query.customerOrgRegister"
  258. placeholder="次数"
  259. style="width: 60px; margin-left: 10px"
  260. size="small"
  261. value-key="id"
  262. >
  263. <el-option
  264. v-for="item in query.customerOrgRegisterList"
  265. :key="item.id"
  266. :label="item.medicalTimes"
  267. :value="item"
  268. />
  269. </el-select>
  270. </div>
  271. </div>
  272. <div style="display: flex;margin:20px;">
  273. <span class="spanLeftClass">登记日期</span>
  274. <el-date-picker v-model="query.startDate" type="date" placeholder="起始日期" size="small" style="width:130px;"/>
  275. <span class="spanMidClass"></span>
  276. <el-date-picker v-model="query.endDate" type="date" placeholder="截止日期" size="small" style="width:130px;"/>
  277. </div>
  278. <div style="display: flex;margin:20px;">
  279. <span class="spanLeftClass">档案号</span>
  280. <el-input placeholder="起始档案号" v-model="query.patientNoStart" size="small" clearable style="width: 130px" />
  281. <span class="spanMidClass"></span>
  282. <el-input placeholder="截止档案号" v-model="query.patientNoEnd" size="small" clearable style="width: 130px" />
  283. </div>
  284. <div style="display: flex;margin:20px;">
  285. <span class="spanLeftClass">姓名</span>
  286. <el-input placeholder="姓名" v-model="query.patientName" size="small" clearable style="width: 130px" />
  287. <span class="spanMidClass">性别</span>
  288. <el-select v-model="query.sexId" placeholder="请选择" style="width: 130px" size="small">
  289. <el-option v-for="item in dict.forSex" :key="item.id" :label="item.displayName" :value="item.id" />
  290. </el-select>
  291. </div>
  292. <div style="display: flex;margin:20px;">
  293. <span class="spanLeftClass">状态</span>
  294. <el-select v-model="query.completeFlag" placeholder="请选择" clearable style="width: 130px"
  295. size="small">
  296. <el-option v-for="item in dict.completeFlag" :key="item.id" :label="item.displayName" :value="item.id" />
  297. </el-select>
  298. </div>
  299. </div>
  300. <span slot="footer" class="dialog-footer">
  301. <el-button type="primary" @click="seq--">上一步</el-button>
  302. <el-button type="primary" @click="seq++">下一步</el-button>
  303. <el-button @click="seq = -1">关闭</el-button>
  304. </span>
  305. </el-dialog>
  306. <!--选择历史档案客户信息-->
  307. <el-dialog title="选择历史档案客户信息" :visible.sync="dialogGroup.oldMansChoose" width="700px" :show-close="false"
  308. :close-on-click-modal="false"> <!--:append-to-body="true" -->
  309. <div style="height:400px;">
  310. <div style="margin-top: -10px;">
  311. 按住 Ctr1 Shift 键可进行多选<br>
  312. </div>
  313. <div style="margin: 5px 0px 0px;" > <!-- -->
  314. <el-table :data="prList" border ref="prList"
  315. height="375" @row-click="rowClickPrList"
  316. highlight-current-row size="small" :row-class-name="handleRowClassName">
  317. <el-table-column type="index" align="center" label="序号" min-width="40"/>
  318. <el-table-column prop="patientNo" align="center" label="档案号" min-width="80"/>
  319. <el-table-column prop="medicalTimes" align="center" label="体检次数" min-width="80"/>
  320. <el-table-column prop="patientName" align="center" label="姓名" min-width="80"/>
  321. <el-table-column prop="sexId" align="center" label="性别" min-width="40">
  322. <template slot-scope="scope">
  323. <div>{{ dddw(dict.sex, "id", scope.row.sexId, "displayName") }}</div>
  324. </template>
  325. </el-table-column>
  326. <el-table-column prop="birthDate" align="center" label="出生日期" min-width="80">
  327. <template slot-scope="scope">
  328. <div>{{ scope.row.birthDate ? moment(new Date(scope.row.birthDate)).format('yyyy-MM-DD'):'' }}</div>
  329. </template>
  330. </el-table-column>
  331. <el-table-column prop="age" align="center" label="年龄" min-width="40"/>
  332. <el-table-column prop="customerOrgParentName" align="center" label="单位" min-width="150"/>
  333. <el-table-column prop="customerOrgName" align="center" label="部门" min-width="120"/>
  334. <el-table-column prop="telephone" align="center" label="电话" min-width="100"/>
  335. <el-table-column prop="mobileTelephone" align="center" label="手机" min-width="100"/>
  336. <el-table-column prop="creatorName" align="center" label="登记人员" min-width="80"/>
  337. <el-table-column prop="creationTime" align="center" label="登记日期" min-width="80">
  338. <template slot-scope="scope">
  339. <div>{{ scope.row.birthDate ? moment(new Date(scope.row.creationTime)).format('yyyy-MM-DD'):'' }}</div>
  340. </template>
  341. </el-table-column>
  342. <!--
  343. "patientRegisterNo": "T4724",
  344. "patientId": "3a0eeeeb-55b6-86d7-a578-a9c9e332e7ed",
  345. "medicalTimes": 1,
  346. "customerOrgId": "3a0eeeeb-5647-6fee-6052-c3c8cde65b92",
  347. "customerOrgGroupId": "3a0e77cf-dfb7-2c35-1310-982136ca6c0c",
  348. "medicalPackageId": null,
  349. "patientName": "刘一",
  350. "sexId": "M",
  351. "birthDate": "10/1/1967",
  352. "age": 57,
  353. "jobCardNo": null,
  354. "medicalCardNo": null,
  355. "maritalStatusId": "9",
  356. "medicalTypeId": null,
  357. "personnelTypeId": null,
  358. "jobPost": null,
  359. "jobTitle": null,
  360. "photo": null,
  361. "salesman": null,
  362. "sexHormoneTermId": null,
  363. "interposeMeasure": null,
  364. "medicalConclusionId": "00000000-0000-0000-0000-000000000000",
  365. "reportPrintTimes": 0,
  366. "isUpload": "N",
  367. "completeFlag": "0",
  368. "isMedicalStart": "N",
  369. "medicalStartDate": "11/16/2023",
  370. "isRecoverGuide": "N",
  371. "summaryDate": "",
  372. "summaryDoctor": null,
  373. "isAudit": "N",
  374. "auditDoctor": null,
  375. "auditDate": "",
  376. "isLock": "N",
  377. "isNameHide": "N",
  378. "isPhoneFollow": "N",
  379. "isVip": "N",
  380. "thirdInfo": null,
  381. "guidePrintTimes": null,
  382. "remark": null,
  383. "organizationUnitId": "68f2d834-2bf0-4978-ad54-d2133c12a333",
  384. "customerOrgRegisterId": "3a0d5dfa-3e3f-b781-6d82-779e872d1b2a",
  385. "patientNo": "T4719",
  386. "patientPassword": "",
  387. "displayName": "刘一",
  388. "nationId": null,
  389. "birthPlaceId": null,
  390. "idNo": null,
  391. "postalCode": null,
  392. "email": null,
  393. "telephone": "15510826***",
  394. "mobileTelephone": null,
  395. "address": null,
  396. "customerOrgName": "部1",
  397. "customerOrgParentId": "3a0c5101-a6a6-e48a-36ec-33e7567a99e6",
  398. "customerOrgParentName": "神豚集团",
  399. "creatorName": "",
  400. "lastModifierName": "",
  401. "lastModificationTime": "2023-11-17T18:05:53.63381",
  402. "lastModifierId": "3a0c4180-107c-0c89-b25b-0bd34666dcec",
  403. "creationTime": "2023-11-17T18:05:53.633769",
  404. "creatorId": "3a0c4180-107c-0c89-b25b-0bd34666dcec",
  405. "id": "3a0eeeeb-565d-8a44-a2b7-a1c81cf43f2d"
  406. -->
  407. </el-table>
  408. </div>
  409. </div>
  410. <span slot="footer" class="dialog-footer">
  411. <el-button type="primary" @click="btnChoose('prList','all')">全选</el-button>
  412. <el-button type="primary" @click="btnChoose('prList')" style="margin-right: 300px;">取消全选</el-button>
  413. <el-button type="primary" @click="seq--">上一步</el-button>
  414. <el-button type="primary" @click="seq++">下一步</el-button>
  415. <el-button @click="seq = -1">关闭</el-button>
  416. </span>
  417. </el-dialog>
  418. <el-dialog title="选择单位" :visible.sync="dialogGroup.oldMansOpts" width="700px" :show-close="false"
  419. :close-on-click-modal="false"> <!--:append-to-body="true" -->
  420. <div style="height:400px;">
  421. <div style="margin-top: -10px;margin-left: 20px;">
  422. 如果是新单位或部门选择的病人将直接导入该单位而不是其子单位
  423. </div>
  424. <div style="display: flex;margin:20px;">
  425. <div style="margin:7px 0;">
  426. <el-radio v-model="newCustomerOrgFlag" :label="false">单位或部门不变</el-radio>
  427. <el-radio v-model="newCustomerOrgFlag" :label="true">新单位或部门</el-radio>
  428. </div>
  429. <div style="margin-left:5px;" v-if="newCustomerOrgFlag">
  430. <el-cascader v-model="customerOrgIds" :options="customerOrgTree"
  431. style="width:200px;" @change="changeCustomerOrg" filterable :filter-method="filterMethod"
  432. :props="{ checkStrictly: true, expandTrigger: 'hover', ...customerOrg.treeprops, }"
  433. :show-all-levels="false" size="small">
  434. </el-cascader>
  435. </div>
  436. </div>
  437. <div style="margin-top: 20px;margin-left:20px;">
  438. <span>单位体检次数</span>
  439. <el-select
  440. v-model="customerOrgRegister"
  441. placeholder="次数"
  442. style="width: 80px;"
  443. size="small"
  444. value-key="id"
  445. >
  446. <el-option
  447. v-for="item in customerOrgRegisterList"
  448. :key="item.id"
  449. :label="item.medicalTimes"
  450. :value="item"
  451. />
  452. </el-select>
  453. </div>
  454. <div style="margin-top: 20px;margin-left:20px;">
  455. <span>单位体检分组</span>
  456. <el-select v-model="curGroup" filterable clearable value-key="id"
  457. style="width:192px;" placeholder="请选择分组" size="small"
  458. >
  459. <el-option v-for="item in groups" :key="item.id" :label="item.displayName"
  460. :value="item" />
  461. </el-select>
  462. </div>
  463. <div style="margin-top:20px;margin-left:20px;">
  464. <span>登记状态</span>
  465. <el-radio v-model="dataImportOpts.completeFlag" label="0">预登记</el-radio>
  466. <el-radio v-model="dataImportOpts.completeFlag" label="1">正式登记</el-radio>
  467. </div>
  468. <div style="margin-top:20px;margin-left:20px;">
  469. <span>支付方式</span>
  470. <el-select v-model="payTypeFlag" placeholder="请选择" style="width: 130px" size="small">
  471. <el-option v-for="item in dict.payType" :key="item.id" :label="item.displayName" :value="item.id" />
  472. </el-select>
  473. </div>
  474. </div>
  475. <span slot="footer" class="dialog-footer">
  476. <el-button type="primary" @click="seq--">上一步</el-button>
  477. <el-button type="primary" @click="btnImportFromDataBase">确定导入</el-button>
  478. <el-button @click="seq = -1">关闭</el-button>
  479. </span>
  480. </el-dialog>
  481. <!-- 通用进度条 -->
  482. <el-dialog
  483. title="数据处理中……"
  484. :visible.sync="elProgress.display"
  485. width="700px"
  486. height="400"
  487. :show-close="false"
  488. :close-on-click-modal="false"
  489. :append-to-body="true"
  490. >
  491. <ElProgressOCX />
  492. </el-dialog>
  493. </div>
  494. </template>
  495. <script>
  496. import moment from "moment"
  497. import { mapState, mapActions } from "vuex";
  498. import { read,readFile, utils } from "xlsx";
  499. import FileSaver from 'file-saver';
  500. import { getapi, postapi, putapi, deletapi } from "@/api/api";
  501. import { arrayExistObj ,arrayFilter ,dddw, tcdate } from '@/utlis/proFunc';
  502. import ElProgressOCX from "../../components/report/ElProgressOCX.vue";
  503. export default {
  504. components: {
  505. ElProgressOCX,
  506. },
  507. data() {
  508. return {
  509. customerOrgTree:[],
  510. customerOrgIds:[], //选中单位节点
  511. customerOrgRegisterList: [], //体检次数列表
  512. customerOrgRegister: {}, //体检次数
  513. peisid:null,
  514. startPoint: -1, // 多选起点 -1 表示未选择
  515. endPoint: -1, // 多选终点 -1 表示未选择
  516. rClickRow: null, //右击的行
  517. rClickColumn: null, //右击的列(预留)
  518. dialogGroup:{
  519. mode:true, //选模式 10 开始 文件导入,20开始 从数据库中导入
  520. fileReadme:false, //导入EXCEL注意事项
  521. fileChoose:false, //选择文件
  522. fileDataOpr:false, //文件数据分析操作
  523. fileDataOpts:false, //文件数据导入前参数设定
  524. query:false, //单位查询条件
  525. oldMansChoose:false, //选择历史数据导入
  526. oldMansOpts:false, //历史数据导入前参数设定
  527. },
  528. oldSeq:-2, //旧的步骤(辅助区分上一步,下一步)
  529. seq: 0, //当前显示窗口
  530. mode: '10', //模式 10 开始 文件导入,20开始 从数据库中导入
  531. excelCols: [{dispLabel:'',val:'',dataLabel:''}], //excel数据列名 {dispLabel:'',val:'',dataLabel:''}
  532. importCols:[], //实际导入的列(即有设置与 dataCols 匹配的列)
  533. excelData: [], //excel表格数据
  534. dataCols:[
  535. {dispLabel:'不设置',val:''},
  536. {dispLabel:'工卡号',val:'jobCardNo'},
  537. {dispLabel:'部门',val:'departmentName'},
  538. {dispLabel:'分组',val:'customerOrgGroupName'},
  539. {dispLabel:'姓名',val:'patientName'},
  540. {dispLabel:'性别',val:'sexName'},
  541. {dispLabel:'年龄',val:'age'},
  542. {dispLabel:'出生日期',val:'birthDate'},
  543. {dispLabel:'婚姻状况',val:'maritalStatusName'},
  544. {dispLabel:'民族',val:'nationName'},
  545. {dispLabel:'身份证号',val:'idNo'},
  546. {dispLabel:'体检卡号',val:'medicalCardNo'},
  547. {dispLabel:'电话',val:'telephone'},
  548. {dispLabel:'手机',val:'mobileTelephone'},
  549. {dispLabel:'电子邮件',val:'email'},
  550. {dispLabel:'邮编',val:'postalCode'},
  551. {dispLabel:'地址',val:'address'},
  552. {dispLabel:'职务',val:'jobPost'},
  553. {dispLabel:'职称',val:'jobTitle'},
  554. {dispLabel:'人员类别',val:'personnelTypeName'},
  555. {dispLabel:'体检类别',val:'medicalTypeName'},
  556. {dispLabel:'支付方式',val:'payTypeFlag'},
  557. ],
  558. /*
  559. photo string
  560. nullable: true
  561. 照片
  562. salesman string
  563. nullable: true
  564. 介绍人
  565. sexHormoneTermName string
  566. nullable: true
  567. 性激素期限
  568. isNameHide string
  569. nullable: true
  570. 隐藏姓名
  571. remark string
  572. nullable: true
  573. 备注
  574. interposeMeasure string
  575. nullable: true
  576. 干预措施
  577. medicalConclusionId string($uuid)
  578. nullable: true
  579. 体检结论
  580. birthPlaceName string
  581. nullable: true
  582. 出生地
  583. */
  584. tableData:[], //导入数据状态显示
  585. workBook:null, //EXCEL 工作薄
  586. sheetNames:[], //EXCEL 工作薄中的表单 {sheetName:}
  587. readDataOpts:{
  588. file:'', //选中的文件名
  589. sheetNameChoosed:'', //当前选中的表格
  590. titleRow:1, //标题行
  591. },
  592. readDataOptsInit:{},
  593. dataImportOpts:{
  594. customerOrgId:'', //单位ID
  595. nameType:'2', //同名病人处理(1.同名病人提示,只要存在同名就提示 2.本单位同名提示,单位内部同名就提示 3.不提示,所有数据创建)
  596. completeFlag:'0', //完成标志 0:预登记 1:未检 2:部份已检 3:已总检 默认未检
  597. isAutoCreateDepartment:true, // 是否自动创建部门 Y N( N:按名字查找部门,如果未找到就提示 Y:未找到就创建)
  598. isAutoCreatePatientNo:false, // 工卡号作为档案号 Y/N (根据工卡号生成,可以指定起始位置跟位数)
  599. cardStartNum:1,
  600. cardLength:6,
  601. startRow:0, //从 excelData 的第几行开始导入
  602. },
  603. dataImportOptsInit:{},
  604. dialogSameMan:false, //同名人员确认窗口
  605. sameMans:[], //同名人员列表
  606. choosedSameMan:{}, // 当前选中同名人员信息
  607. query:{ //单位查询条件
  608. customerOrgIds:[],
  609. customerOrgId:'',
  610. customerOrgRegisterList:[],
  611. customerOrgRegister:{},
  612. customerOrgRegisterId:'',
  613. startDate:null,
  614. endDate:null,
  615. startPatientNo:'',
  616. endPatientNo:'',
  617. patientName:'',
  618. sexId:'A',
  619. completeFlag:'',
  620. },
  621. prList:[], //查询出符合条件的历史档案人员信息
  622. groups:[], //体检分组列表
  623. curGroup:null, //当前选中要导入的分组 {}
  624. newCustomerOrgFlag:false, // [false]单位或部门不变 or [true]新单位或部门
  625. payTypeFlag:'1', // 默认单位
  626. };
  627. },
  628. //组件创建完成,一般页面初始布局放在这里
  629. created() {
  630. this.peisid = window.sessionStorage.getItem('peisid');
  631. if(!this.peisid || this.peisid == 'null'){
  632. this.seq = -1
  633. }
  634. this.readDataOptsInit = Object.assign({},this.readDataOpts)
  635. this.dataImportOptsInit = Object.assign({},this.dataImportOpts)
  636. },
  637. //页面挂载完成,一般页面渲染数据放在这里
  638. mounted() {
  639. this.dictInit()
  640. },
  641. computed: {
  642. ...mapState(["window", "dict", "elProgress", "patientRegister", "customerOrg"]),
  643. },
  644. methods: {
  645. dddw,moment,
  646. dictInit(){
  647. // 获取单位列表树
  648. getapi("/api/app/customerorg/getbycodeall").then((res) => {
  649. // console.log("res.data", res.data);
  650. if(res.code != -1){
  651. this.customerOrgTree = res.data;
  652. let lfind = arrayExistObj(this.customerOrgTree,'id',this.dict.personOrgId)
  653. if(lfind > -1) this.customerOrgTree.splice(lfind,1)
  654. tcdate(this.customerOrgTree)
  655. }
  656. });
  657. //性别(查询)
  658. getapi("/api/app/for-sex").then((res) => {
  659. if (res.code == 1) {
  660. this.dict.forSex = res.data;
  661. }
  662. });
  663. //性别(仅档案用)
  664. getapi("/api/app/sex").then((res) => {
  665. if (res.code == 1) {
  666. this.dict.sex = res.data;
  667. }
  668. });
  669. },
  670. //清空进度数据数据
  671. clearProcess(){
  672. this.workBook = null //EXCEL 工作薄
  673. this.sheetNames = [] //EXCEL 工作薄中的表单 {sheetName:}
  674. this.readDataOpts = Object.assign({},this.readDataOptsInit)
  675. this.dataImportOpts = Object.assign({},this.dataImportOptsInit)
  676. this.customerOrgIds = [] //选中单位节点
  677. this.customerOrgRegisterList = [] //体检次数列表
  678. this.customerOrgRegister = {} //体检次数
  679. this.startPoint = -1 // 多选起点 -1 表示未选择
  680. this.endPoint = -1 // 多选终点 -1 表示未选择
  681. },
  682. // 获取单位列表树
  683. getCustomerOrgTree() {
  684. getapi("/api/app/customerorg/getbycodeall").then((res) => {
  685. // console.log("res.data", res.data);
  686. if(res.code != -1){
  687. this.customerOrgTree = res.data;
  688. let lfind = arrayExistObj(this.customerOrgTree,'id',this.dict.personOrgId)
  689. if(lfind > -1) this.customerOrgTree.splice(lfind,1)
  690. tcdate(this.customerOrgTree)
  691. }
  692. });
  693. },
  694. //单位过滤 预留
  695. filterMethod(){
  696. },
  697. //选择单位
  698. changeCustomerOrg(v){
  699. this.chooseCustomerOrg(v)
  700. },
  701. //选择单位查询条件
  702. changeQueryCustomerOrg(v){
  703. this.chooseCustomerOrg(v,'query')
  704. },
  705. chooseCustomerOrg(v,obj) {
  706. let id = ''
  707. if(typeof v == 'string'){
  708. id = v
  709. }else{
  710. id = v[0]
  711. }
  712. getapi(
  713. `/api/app/customerorgregister/getlistincustomerorgid?CustomerOrgId=${id}`
  714. ).then((res) => {
  715. if (res.code != -1) {
  716. if(obj == 'query'){
  717. this.query.customerOrgRegisterList = res.data
  718. if (this.query.customerOrgRegisterList.length > 0) {
  719. this.query.customerOrgRegister = this.query.customerOrgRegisterList[this.query.customerOrgRegisterList.length - 1];
  720. } else {
  721. this.query.customerOrgRegister = {};
  722. // this.customerOrgGroups = [];
  723. }
  724. }
  725. this.customerOrgRegisterList = arrayFilter(res.data, 'isComplete', 'N') //不显示已完成的体检次数
  726. if (this.customerOrgRegisterList.length > 0) {
  727. this.customerOrgRegister = this.customerOrgRegisterList[this.customerOrgRegisterList.length - 1];
  728. // this.getCustomerOrgGroup(this.customerOrgRegister.id);
  729. } else {
  730. this.customerOrgRegister = {};
  731. // this.customerOrgGroups = [];
  732. }
  733. }
  734. });
  735. },
  736. //第一次点下一步
  737. btnFirst() {
  738. if(!this.peisid || this.peisid == 'null'){
  739. this.$message.warning("该用户未选归属体检中心,不能执行此操作!");
  740. return
  741. }
  742. this.seq = parseInt(this.mode)
  743. },
  744. // 导入过程 上一步,下一步
  745. async btnProcess(seq){
  746. let keys = Object.keys(this.dialogGroup)
  747. let count = 0 //选中待导入的人员数
  748. if(seq == 9){
  749. this.workBook = null
  750. this.sheetNameChoosed = ''
  751. seq =0
  752. }
  753. if(seq == 19) seq =0
  754. // console.log('keys',keys)
  755. switch (seq) {
  756. case -1:
  757. //关闭所有弹窗
  758. keys.forEach(e =>{
  759. this.dialogGroup[e] = false
  760. })
  761. this.clearProcess()
  762. break;
  763. case 0:
  764. //显示 选择导入方式
  765. keys.forEach(e =>{
  766. if(e == 'mode'){
  767. this.dialogGroup[e] = true
  768. }else{
  769. this.dialogGroup[e] = false
  770. }
  771. })
  772. this.excelCols = []
  773. this.tableData = []
  774. this.prList = []
  775. this.startPoint = -1 // 多选起点 -1 表示未选择
  776. this.endPoint = -1 // 多选终点 -1 表示未选择
  777. break;
  778. case 10:
  779. //显示 EXCEL 导入
  780. keys.forEach(e =>{
  781. if(e == 'fileReadme'){
  782. this.dialogGroup[e] = true
  783. }else{
  784. this.dialogGroup[e] = false
  785. }
  786. })
  787. break;
  788. case 11:
  789. //显示 文件选择 窗口
  790. keys.forEach(e =>{
  791. if(e == 'fileChoose'){
  792. this.dialogGroup[e] = true
  793. }else{
  794. this.dialogGroup[e] = false
  795. }
  796. })
  797. break;
  798. case 12:
  799. // 从后面退回时,无需读数据
  800. if(this.oldSeq < seq){
  801. if(!this.readData()){
  802. this.seq--
  803. break;
  804. }
  805. }
  806. //显示 数据分析操作 窗口
  807. keys.forEach(e =>{
  808. if(e == 'fileDataOpr'){
  809. this.dialogGroup[e] = true
  810. }else{
  811. this.dialogGroup[e] = false
  812. }
  813. })
  814. break;
  815. case 13:
  816. count = 0
  817. this.excelData.forEach(e =>{
  818. if(e.choosed) count++
  819. })
  820. if(count == 0){
  821. this.$message.warning("未选中要导入的记录")
  822. this.seq--
  823. break;
  824. }
  825. //显示 文件数据导入前参数设定 窗口
  826. keys.forEach(e =>{
  827. if(e == 'fileDataOpts'){
  828. this.dialogGroup[e] = true
  829. }else{
  830. this.dialogGroup[e] = false
  831. }
  832. })
  833. break;
  834. case 20:
  835. //显示 单位查询条件 导入
  836. keys.forEach(e =>{
  837. if(e == 'query'){
  838. this.dialogGroup[e] = true
  839. }else{
  840. this.dialogGroup[e] = false
  841. }
  842. })
  843. break;
  844. case 21:
  845. //显示 选择要导入的 档案人员
  846. if(this.oldSeq < seq){
  847. if(!await this.getPrList()){
  848. console.log('this.seq break',this.seq)
  849. this.seq--
  850. break
  851. }
  852. }
  853. keys.forEach(e =>{
  854. if(e == 'oldMansChoose'){
  855. this.dialogGroup[e] = true
  856. }else{
  857. this.dialogGroup[e] = false
  858. }
  859. })
  860. break;
  861. case 22:
  862. //显示 选择新的体检单位及分组
  863. count = 0
  864. this.prList.forEach(e =>{
  865. if(e.choosed) count++
  866. })
  867. if(count == 0){
  868. this.$message.warning("未选中要导入的记录")
  869. this.seq--
  870. break;
  871. }
  872. keys.forEach(e =>{
  873. if(e == 'oldMansOpts'){
  874. this.dialogGroup[e] = true
  875. }else{
  876. this.dialogGroup[e] = false
  877. }
  878. })
  879. break;
  880. default:
  881. break;
  882. }
  883. },
  884. //导入完后,导入状态显示
  885. importRowClassName({ row, rowIndex }) {
  886. if (row.importState == '导入失败') {
  887. return "danger";
  888. } else {
  889. return "";
  890. }
  891. },
  892. //多选 颜色标记
  893. handleRowClassName({ row, rowIndex }) {
  894. if (row.choosed) {
  895. return "current-row";
  896. } else {
  897. return "";
  898. }
  899. },
  900. // 导入完后,状态统计
  901. getSummaries(param) {
  902. const { columns, data } = param;
  903. const sumCol = [2]; //需合计的列
  904. const sums = [];
  905. let success = 0,fail = 0;
  906. columns.forEach((column, index) => {
  907. //显示合计列
  908. if (index === 1) {
  909. sums[index] = "合计";
  910. return;
  911. }
  912. //不合计的列
  913. if (sumCol.indexOf(index) == -1) {
  914. sums[index] = "";
  915. return;
  916. }
  917. data.forEach((item) => {
  918. if(item[column.property] == '导入成功'){
  919. success++
  920. }else{
  921. fail++
  922. }
  923. });
  924. });
  925. sums[2] = `导入 成功:${success} 条,失败:${fail} 条。`
  926. return sums;
  927. },
  928. //清除所选文件
  929. fileGetFocus(e){
  930. console.log('fileGetFocus(e)',e)
  931. e.value = '' //未起作用的
  932. // e.target.files = []
  933. },
  934. // 获取选择的文件
  935. changeFileChoose(e) {
  936. if(e.target.files.length <= 0) return;
  937. this.readDataOpts.file = e.target.files[0];
  938. // 调用导入Excel文件的方法
  939. // File {name: 'vulkan-1.dll',
  940. // console.log('file',file,file.type)
  941. let fileName = this.readDataOpts.file.name.split('.')
  942. let fileNameExt = fileName[fileName.length - 1].toLowerCase()
  943. if(fileNameExt != 'xls' && fileNameExt != 'xlsx'){
  944. this.$message.warning("你选的文件可能不是标准的Excel文件!")
  945. }
  946. this.readFile(this.readDataOpts.file);
  947. },
  948. //sheetjs 读取文件
  949. readFile(file){
  950. const reader = new FileReader();
  951. reader.readAsBinaryString(file);
  952. // reader.readAsArrayBuffer(file);
  953. reader.onload = (e) => {
  954. let data = e.target.result;
  955. // let typedArray = new Uint8Array(data);
  956. // var workBook = read(typedArray,{type:'array'})
  957. // this.workBook = read(data,{type:'binary',cellDates:true}) //日期将转成 标准 日期格式,显示会 undefined
  958. this.workBook = read(data,{type:'binary'})
  959. // var workBook = readFile(file); //后端读法
  960. this.sheetNames = []
  961. this.workBook.SheetNames.forEach(e =>{
  962. this.sheetNames.push({sheetName:e})
  963. })
  964. this.$nextTick(() =>{
  965. this.$refs['sheetNames'].setCurrentRow(this.sheetNames[0]);
  966. this.chooseSheetName(this.sheetNames[0])
  967. })
  968. }
  969. },
  970. //选择要导入的Excel表单名
  971. chooseSheetName(row){
  972. this.readDataOpts.sheetNameChoosed = row.sheetName
  973. },
  974. //读取数据
  975. readData(){
  976. let ret = 1
  977. if(!this.readDataOpts.file || !this.workBook || !this.readDataOpts.sheetNameChoosed){
  978. this.$message.warning("请选择文件及要导入的表格")
  979. return 0
  980. }
  981. if(this.readDataOpts.titleRow <= 0){
  982. this.$message.warning("标题行不能小于1")
  983. return 0
  984. }
  985. let worksheet = this.workBook.Sheets[this.readDataOpts.sheetNameChoosed];
  986. //分析标题信息
  987. let head = utils.sheet_to_json(worksheet,{header:1});
  988. this.excelCols = []
  989. head[this.readDataOpts.titleRow - 1].forEach(e => {
  990. let lfind = arrayExistObj(this.dataCols,'dispTitle',e),val = '',dataLabel = '';
  991. if(lfind > -1){
  992. val = this.dataCols[lfind].val
  993. dataLabel = this.dataCols[lfind].dataLabel
  994. }
  995. this.excelCols.push({
  996. dispLabel:e,
  997. val,
  998. dataLabel
  999. })
  1000. })
  1001. //console.log('head,',head,this.excelCols)
  1002. this.excelData = utils.sheet_to_json(worksheet,{raw:false,range:this.readDataOpts.titleRow - 1}); //raw:false,range:1 从第1行开始读取
  1003. this.excelData.forEach((e,index) => {
  1004. e.choosed = false;
  1005. e.index = index;
  1006. e.id = 'excelData' + index;
  1007. });
  1008. //console.log('this.excelCols',this.excelCols)
  1009. // console.log('sheet_to_json excelData',this.excelData)
  1010. // 导入后,批量分析Excel列 与 数据字段 的匹配关系
  1011. this.parseExcelData()
  1012. return ret
  1013. },
  1014. //选择要导入的数据
  1015. chooseDataImport(row) {
  1016. // console.log("this.excelData",this.excelData);
  1017. // 按住了shift键
  1018. if (this.window.shift) {
  1019. //清除所有选择
  1020. this.excelData.forEach((e,index) => {
  1021. e.choosed = false;
  1022. e.index = index;
  1023. });
  1024. if (this.startPoint == -1) {
  1025. this.excelData[row.index].choosed = true;
  1026. this.startPoint = row.index;
  1027. }else{
  1028. if (this.startPoint > row.index) {
  1029. for (let i = row.index; i <= this.startPoint; i++) {
  1030. this.excelData[i].choosed = true;
  1031. }
  1032. } else if (this.startPoint <= row.index) {
  1033. for (let i = this.startPoint; i <= row.index; i++) {
  1034. this.excelData[i].choosed = true;
  1035. }
  1036. }
  1037. }
  1038. }else if (this.window.ctrl) { // 按住了ctrl 键
  1039. this.excelData[row.index].choosed = true;
  1040. if (this.startPoint == -1){
  1041. this.startPoint = row.index;
  1042. }
  1043. }else{
  1044. // 未按住了ctrl 、shift 键
  1045. //清除所有选择
  1046. console.log("清除所有选择");
  1047. this.excelData.forEach((e,index) => {
  1048. e.choosed = false;
  1049. e.index = index;
  1050. });
  1051. // console.log(this.excelData,row.index);
  1052. // console.log(this.excelData[row.index].choosed);
  1053. this.excelData[row.index].choosed = true;
  1054. this.startPoint = row.index;
  1055. }
  1056. },
  1057. // 全选(取消全选)
  1058. btnChoose(refName,type){
  1059. let choosed = false
  1060. if(type && type == 'all'){
  1061. choosed = true
  1062. }
  1063. this[refName].forEach(e =>{
  1064. e.choosed = choosed
  1065. if(choosed){
  1066. this.$refs[refName].setCurrentRow(e)
  1067. }
  1068. })
  1069. if(!choosed){
  1070. this.$refs[refName].setCurrentRow()
  1071. }
  1072. },
  1073. //右击标题
  1074. headerContextmenu(column, event){
  1075. let chooseCol = column.minWidth - 100
  1076. let items = [] //菜单
  1077. this.dataCols.forEach(e =>{
  1078. items.push({
  1079. label:e.dispLabel,
  1080. onClick: () => {
  1081. this.setColumn(chooseCol,e)
  1082. },
  1083. })
  1084. })
  1085. //右击显示的菜单
  1086. this.$contextmenu({
  1087. items,
  1088. event,
  1089. //x: event.clientX,
  1090. //y: event.clientY,
  1091. customClass: "custom-class",
  1092. zIndex: 30000, //够大再能在最上面显示
  1093. minWidth: 80,
  1094. height:20
  1095. });
  1096. return false;
  1097. },
  1098. //设置真实数据字段列
  1099. setColumn(oldColNum,newColObj){
  1100. // console.log('oldColNum,newColObj',oldColNum,newColObj)
  1101. //如果数据字段已设置过,则将之前设置的先清空
  1102. if(newColObj.dispLabel != "不设置"){
  1103. let lfind = arrayExistObj(this.excelCols,'dataLabel',newColObj.dispLabel)
  1104. if(lfind > -1){
  1105. this.excelCols[lfind].dataLabel = ''
  1106. this.excelCols[lfind].val = ''
  1107. }
  1108. }
  1109. this.excelCols[oldColNum].dataLabel = newColObj.dispLabel
  1110. this.excelCols[oldColNum].val = newColObj.val
  1111. // console.log('newColObj.val',newColObj.val)
  1112. let tempDate = ''
  1113. if(newColObj.val == 'birthDate'){
  1114. this.excelData.forEach(e =>{
  1115. tempDate = e[this.excelCols[oldColNum].dispLabel]
  1116. // console.log('birthDate',tempDate)
  1117. e[this.excelCols[oldColNum].dispLabel] = tempDate ? moment(new Date(tempDate)).format('yyyy-MM-DD'):''
  1118. })
  1119. }
  1120. },
  1121. // 导入后,批量分析Excel列 与 数据字段 的匹配关系
  1122. parseExcelData(){
  1123. let lfind = -1
  1124. this.excelCols.forEach((e,i) =>{
  1125. lfind = arrayExistObj(this.dataCols,'dispLabel',e.dispLabel)
  1126. if(lfind > -1) this.setColumn(i,this.dataCols[lfind])
  1127. });
  1128. },
  1129. // 确定导入数据库
  1130. btnImport(){
  1131. if(!this.customerOrgIds || this.customerOrgIds.length == 0){
  1132. this.$message.warning("请选择单位")
  1133. return
  1134. }
  1135. if(!this.customerOrgRegister || !this.customerOrgRegister.id){
  1136. this.$message.warning("请选择单位体检次数")
  1137. return
  1138. }
  1139. this.elProgress.display = true;
  1140. this.elProgress.percentage = 0;
  1141. this.importCols = []
  1142. this.excelCols.forEach(e =>{
  1143. if(e.val){
  1144. this.importCols.push(e)
  1145. }
  1146. })
  1147. this.tableData = []
  1148. //导入进行中
  1149. this.importing(this.dataImportOpts.startRow,this.dataImportOpts.nameType)
  1150. },
  1151. //导入进行时
  1152. // startRow : 从第几行开始导入,同名判断交互时,续接导入
  1153. // startRowNameType : 续接导入的第1行,执行 同名判断模式, 3.不提示,按新人导入
  1154. async importing(startRow,startRowNameType){
  1155. let body = {}
  1156. for(let i=startRow;i<this.excelData.length;i++){
  1157. this.elProgress.percentage = Math.floor(
  1158. ((i + 1) * 100) / this.excelData.length
  1159. );
  1160. if(this.excelData[i].choosed){
  1161. body = this.excelDataToApiBody(this.excelData[i])
  1162. if(i == startRow) body.nameType = startRowNameType
  1163. if(this.choosedSameMan.patientId){
  1164. body.patientId = this.choosedSameMan.patientId
  1165. this.choosedSameMan = {} // 清除选择
  1166. }
  1167. console.log('this.excelData[i]',i,body)
  1168. try {
  1169. let res = await postapi('/api/app/patientregister/createpatientregisterexcel',body)
  1170. if(res.code != -1){
  1171. if(res.data.code == 1){
  1172. this.tableData.push(Object.assign({importState:'导入成功'},this.excelData[i]))
  1173. }else if(res.data.code == -2){
  1174. this.sameMans = res.data.details
  1175. this.dialogSameMan = true
  1176. this.dataImportOpts.startRow = i
  1177. break;
  1178. }else{
  1179. this.tableData.push(Object.assign({importState:'导入失败',importDes:res.data.msg},this.excelData[i]))
  1180. }
  1181. }else{
  1182. this.tableData.push(Object.assign({importState:'导入失败',importDes:res.message},this.excelData[i]))
  1183. }
  1184. } catch (error) {
  1185. break;
  1186. }
  1187. }
  1188. // 结束导入
  1189. if(i == this.excelData.length - 1){
  1190. this.elProgress.display = false;
  1191. this.seq = -1
  1192. }
  1193. }
  1194. },
  1195. //将Excel的数据转换成接口的数据
  1196. excelDataToApiBody(ExcelData){
  1197. let body = {
  1198. customerOrgId:this.customerOrgIds[this.customerOrgIds.length - 1],
  1199. customerOrgRegisterId:this.customerOrgRegister.id,
  1200. organizationUnitId:this.peisid,
  1201. nameType:this.dataImportOpts.nameType,
  1202. completeFlag:this.dataImportOpts.completeFlag,
  1203. isAutoCreateDepartment: this.dataImportOpts.isAutoCreateDepartment ? 'Y':'N',
  1204. isAutoCreatePatientNo:this.dataImportOpts.isAutoCreatePatientNo ? 'Y':'N',
  1205. cardStartNum:this.dataImportOpts.cardStartNum,
  1206. cardLength:this.dataImportOpts.cardLength
  1207. }
  1208. this.excelCols.forEach(e =>{
  1209. if(e.val){
  1210. switch (e.val) {
  1211. case 'age':
  1212. if(ExcelData[e.dispLabel]) body[e.val] = parseInt(ExcelData[e.dispLabel])
  1213. break;
  1214. // case 'birthDate':
  1215. // if(ExcelData[e.dispLabel]) body[e.val] = moment(new Date(ExcelData[e.dispLabel])).format('yyyy-MM-DD')
  1216. // break;
  1217. default:
  1218. body[e.val] = ExcelData[e.dispLabel]
  1219. break;
  1220. }
  1221. }
  1222. })
  1223. return body
  1224. },
  1225. //选中同名人员档案
  1226. rowClickSameMan(row){
  1227. this.choosedSameMan = Object.assign({},row)
  1228. },
  1229. // 同名人员,按档案人员导入
  1230. btnOldMan(){
  1231. if(!this.choosedSameMan.patientId){
  1232. this.$message.warning("请选择要导入的档案人员")
  1233. return
  1234. }
  1235. this.importing(this.dataImportOpts.startRow)
  1236. this.dialogSameMan = false
  1237. },
  1238. // 同名人员,按新人方式导入
  1239. btnNewMan(){
  1240. this.choosedSameMan = {}
  1241. this.importing(this.dataImportOpts.startRow,'3')
  1242. this.dialogSameMan = false
  1243. },
  1244. // 查询档案人员
  1245. async getPrList(){
  1246. let ret = false
  1247. if(!this.query.customerOrgIds || this.query.customerOrgIds.length == 0){
  1248. this.$message.warning("请选择单位或部门")
  1249. return false
  1250. }
  1251. if(!this.query.customerOrgRegister || !this.query.customerOrgRegister.id){
  1252. this.$message.warning("请选择单位体检次数")
  1253. return false
  1254. }
  1255. this.query.customerOrgId = this.query.customerOrgIds[this.query.customerOrgIds.length - 1]
  1256. this.query.customerOrgRegisterId = this.query.customerOrgRegister.id
  1257. let body = Object.assign({},this.query)
  1258. delete body.customerOrgIds
  1259. delete body.customerOrgRegister
  1260. delete body.customerOrgRegisterList
  1261. if(!body.completeFlag) delete body.completeFlag
  1262. if(!body.patientName) delete body.patientName
  1263. if(!body.startPatientNo && !body.endPatientNo){
  1264. delete body.startPatientNo
  1265. delete body.endPatientNo
  1266. }else if(!body.startPatientNo){
  1267. this.$message.warning("请填写起始档案号")
  1268. return false
  1269. }else if(!body.endPatientNo){
  1270. this.$message.warning("请填写截止档案号")
  1271. return false
  1272. }
  1273. if(!body.startDate && !body.endDate){
  1274. delete body.startDate
  1275. delete body.endDate
  1276. }else if(!body.startDate){
  1277. this.$message.warning("请填写起始登记日期")
  1278. return false
  1279. }else if(!body.endDate){
  1280. this.$message.warning("请填写截止登记日期")
  1281. return false
  1282. }else{
  1283. body.startDate = moment(new Date(body.startDate)).format('yyyy-MM-DD')
  1284. body.endDate = moment(new Date(body.endDate)).format('yyyy-MM-DD')
  1285. }
  1286. const loading = this.$loading({
  1287. lock: true,
  1288. text: "Loading",
  1289. spinner: "el-icon-loading",
  1290. background: "rgba(0, 0, 0, 0.7)",
  1291. });
  1292. try {
  1293. let res = await postapi('/api/patientregister/getpatientregisterimportlist',body)
  1294. if(res.code != -1){
  1295. this.prList = res.data
  1296. if(res.data.length == 0){
  1297. this.$message.warning("没有符合条件的数据")
  1298. }else{
  1299. ret = true
  1300. }
  1301. }
  1302. } catch (error) {
  1303. //
  1304. }
  1305. loading.close()
  1306. return ret
  1307. },
  1308. //选择要导入的数据
  1309. rowClickPrList(row) {
  1310. // console.log("this.excelData",this.excelData);
  1311. // 按住了shift键
  1312. if (this.window.shift) {
  1313. //清除所有选择
  1314. this.prList.forEach((e,index) => {
  1315. e.choosed = false;
  1316. e.index = index;
  1317. });
  1318. if (this.startPoint == -1) {
  1319. this.prList[row.index].choosed = true;
  1320. this.startPoint = row.index;
  1321. }else{
  1322. if (this.startPoint > row.index) {
  1323. for (let i = row.index; i <= this.startPoint; i++) {
  1324. this.prList[i].choosed = true;
  1325. }
  1326. } else if (this.startPoint <= row.index) {
  1327. for (let i = this.startPoint; i <= row.index; i++) {
  1328. this.prList[i].choosed = true;
  1329. }
  1330. }
  1331. }
  1332. }else if (this.window.ctrl) { // 按住了ctrl 键
  1333. this.prList[row.index].choosed = true;
  1334. if (this.startPoint == -1){
  1335. this.startPoint = row.index;
  1336. }
  1337. }else{
  1338. // 未按住了ctrl 、shift 键
  1339. //清除所有选择
  1340. console.log("清除所有选择");
  1341. this.prList.forEach((e,index) => {
  1342. e.choosed = false;
  1343. e.index = index;
  1344. });
  1345. // console.log(this.excelData,row.index);
  1346. // console.log(this.excelData[row.index].choosed);
  1347. this.prList[row.index].choosed = true;
  1348. this.startPoint = row.index;
  1349. }
  1350. },
  1351. //获取分组
  1352. getGroups(customerOrgRegisterId) {
  1353. ///api/app/customerorggroup/getlistinfilter?CustomerOrgRegisterId=3fa85f64-5717-4562-b3fc-2c963f66afa6
  1354. getapi(`/api/app/customerorggroup/getlistinfilter?CustomerOrgRegisterId=${customerOrgRegisterId}`).then(res => {
  1355. if (res.code != - 1) {
  1356. this.groups = res.data.items;
  1357. this.curGroup = null //清除已选分组
  1358. }
  1359. })
  1360. },
  1361. //确定从档案中导入数据
  1362. async btnImportFromDataBase(){
  1363. let customerOrgIds = []
  1364. let customerOrgId = ""
  1365. if(this.newCustomerOrgFlag){
  1366. customerOrgIds = this.customerOrgIds
  1367. }else{
  1368. customerOrgIds = this.query.customerOrgIds
  1369. }
  1370. if(customerOrgIds && customerOrgIds.length > 0) customerOrgId = customerOrgIds[customerOrgIds.length - 1]
  1371. if(!customerOrgId){
  1372. this.$message.warning("请选择新导入的体检单位或部门")
  1373. return
  1374. }
  1375. if(!this.curGroup || !this.customerOrgRegister){
  1376. this.$message.warning("请选择新导入的体检次数与分组")
  1377. return
  1378. }
  1379. let body = {
  1380. customerOrgRegisterId:this.customerOrgRegister.id,
  1381. customerOrgGroupId:this.curGroup.id,
  1382. completeFlag:this.dataImportOpts.completeFlag,
  1383. payTypeFlag:this.payTypeFlag,
  1384. organizationUnitId:this.peisid,
  1385. }
  1386. // {
  1387. // "patientRegisterId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  1388. // "customerOrgId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  1389. // "customerOrgRegisterId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  1390. // "customerOrgGroupId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  1391. // "completeFlag": "string",
  1392. // "payTypeFlag": "string",
  1393. // "organizationUnitId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  1394. // }
  1395. this.elProgress.display = true
  1396. this.elProgress.percentage = 0
  1397. for(let i=0;i<this.prList.length;i++){
  1398. this.elProgress.percentage = Math.floor(((i + 1) * 100) / this.prList.length);
  1399. if(!this.prList[i].choosed) continue
  1400. body.patientRegisterId = this.prList[i].id
  1401. body.customerOrgId = this.newCustomerOrgFlag ? customerOrgId:this.prList[i].customerOrgId
  1402. try {
  1403. let res = await postapi('/api/app/patientregister/createpatientregisterhistory',body)
  1404. if(res.code != -1){
  1405. if(res.data.code != -1){
  1406. this.tableData.push(Object.assign({importState:'导入成功'},this.prList[i]))
  1407. }else{
  1408. this.tableData.push(Object.assign({importState:'导入失败',importDes:res.data.msg},this.prList[i]))
  1409. }
  1410. }else{
  1411. this.tableData.push(Object.assign({importState:'导入失败',importDes:res.message},this.prList[i]))
  1412. }
  1413. } catch (error) {
  1414. this.tableData.push(Object.assign({importState:'导入失败',importDes:res.message},this.prList[i]))
  1415. }
  1416. }
  1417. this.elProgress.display = false
  1418. this.seq = -1
  1419. },
  1420. //通用导出
  1421. btnExport(elId){
  1422. let table = document.getElementById(elId);
  1423. let tableData = table.innerHTML
  1424. let fileName = moment(new Date()).format('yyyyMMDDHHmmss') + '.xls'
  1425. let blob = new Blob([tableData],{type:"text/plain;charset=utf-8"});
  1426. FileSaver.saveAs(blob, fileName);
  1427. },
  1428. },
  1429. watch: {
  1430. "seq":{
  1431. immediate: true, // 立即执行
  1432. // deep: true, // 深度监听复杂类型内变化
  1433. handler(newVal,oldVal){
  1434. console.log('watch:seq:',newVal,oldVal)
  1435. if(!oldVal && oldVal != 0){
  1436. this.oldSeq = -2
  1437. }else{
  1438. this.oldSeq = oldVal
  1439. }
  1440. if(newVal != oldVal){
  1441. this.btnProcess(newVal);
  1442. }
  1443. }
  1444. },
  1445. "readDataOpts.titleRow":{
  1446. // immediate: true, // 立即执行
  1447. deep: true, // 深度监听复杂类型内变化
  1448. handler(newVal,oldVal){
  1449. console.log('watch:readDataOpts.titleRow:',newVal,oldVal)
  1450. if(newVal && newVal != oldVal){
  1451. if(this.seq == 11) this.readData()
  1452. }
  1453. }
  1454. },
  1455. //所选体检次数改变时,自动获取登记日期
  1456. "query.customerOrgRegister.id":{
  1457. // immediate: true, // 立即执行
  1458. deep: true, // 深度监听复杂类型内变化
  1459. handler(newVal,oldVal){
  1460. if(newVal && newVal != oldVal){
  1461. this.query.startDate = new Date(this.query.customerOrgRegister.beginTime)
  1462. this.query.endDate = this.query.customerOrgRegister.isComplete == 'N' ? new Date(): new Date(this.query.customerOrgRegister.endTime)
  1463. }
  1464. }
  1465. },
  1466. //选体检新体检次数改变时,获取分组数据
  1467. "customerOrgRegister.id":{
  1468. // immediate: true, // 立即执行
  1469. deep: true, // 深度监听复杂类型内变化
  1470. handler(newVal,oldVal){
  1471. if(newVal && newVal != oldVal){
  1472. this.getGroups(newVal)
  1473. }
  1474. }
  1475. },
  1476. },
  1477. };
  1478. </script>
  1479. <style scoped>
  1480. @import '../../assets/css/global_button.css';
  1481. @import '../../assets/css/global_card.css';
  1482. @import '../../assets/css/global_dialog.css';
  1483. @import '../../assets/css/global_form.css';
  1484. @import '../../assets/css/global_input.css';
  1485. @import '../../assets/css/global_table.css';
  1486. @import '../../assets/css/global.css';
  1487. .btnClass{
  1488. margin-right: 10px;
  1489. }
  1490. .spanLeftClass{
  1491. margin-top:6px;
  1492. width: 70px;
  1493. }
  1494. .spanMidClass{
  1495. text-align: center;
  1496. margin-top:6px;
  1497. width: 50px;
  1498. }
  1499. /* type=number 显示微调按钮 */
  1500. ::v-deep input[type="number"]::-webkit-inner-spin-button,
  1501. input[type="number"]::-webkit-outer-spin-button {
  1502. -webkit-appearance: button !important;
  1503. margin: 0 -12px 0 0 !important;
  1504. }
  1505. </style>