DeptPeriodReport.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. <template>
  2. <page-layer>
  3. <template #header>
  4. <span style="margin-left: 0">日期范围:</span>
  5. <el-date-picker
  6. v-model="requestParam.datePeriod"
  7. type="daterange"
  8. range-separator="至"
  9. start-placeholder="开始日期"
  10. end-placeholder="结束日期"
  11. :shortcuts="shortcuts"
  12. style="width: 240px"
  13. >
  14. </el-date-picker>
  15. <span>科室:</span>
  16. <el-select v-model="requestParam.depts" multiple collapse-tags style="width: 245px" placeholder="请选择" @change="handleSelect">
  17. <el-checkbox v-model="data.selectAll" @change="selectAllWards" style="float: right; margin-right: 20px">全选</el-checkbox>
  18. <el-option v-for="item in data.allWards" :key="item.code" :value="item.code" :label="item.name"></el-option>
  19. </el-select>
  20. <el-button type="primary" style="margin-left: 10px" icon="Search" @click="queryDeptData"> 查询 </el-button>
  21. <el-button type="primary" icon="Upload" @click="exportExcel(1)"> 导出 Excel </el-button>
  22. </template>
  23. <template #main>
  24. <el-table
  25. :data="data.deptEarn.list.slice((currentPage - 1) * pageSize, currentPage * pageSize)"
  26. stripe
  27. highlight-current-row
  28. empty-text="没有数据"
  29. :height="mainTableHeight"
  30. @row-dblclick="queryDoctorData"
  31. >
  32. <el-table-column prop="deptName" label="科室" sortable></el-table-column>
  33. <el-table-column prop="doctorName" label="姓名"></el-table-column>
  34. <el-table-column prop="doctorCode" label="编号"></el-table-column>
  35. <el-table-column prop="totalCharge" label="营收额" sortable></el-table-column>
  36. </el-table>
  37. <div style="margin: 5px 10px; display: flex">
  38. <el-pagination
  39. @size-change="handleSizeChange"
  40. @current-change="handleCurrentChange"
  41. :current-page="currentPage"
  42. :page-sizes="[15, 30, 45, 60]"
  43. :page-size="pageSize"
  44. layout="total, sizes, prev, pager, next, jumper"
  45. background
  46. :total="data.deptEarn.list.length"
  47. >
  48. </el-pagination>
  49. <el-tag type="danger" style="margin-left: 30px; font-size: 14px; font-weight: bold"> 合计:¥{{ data.deptEarn.sum }} </el-tag>
  50. </div>
  51. <div v-show="showDoctorEarn" class="wrapper">
  52. <div class="center-box" style="width: 75%">
  53. <div>
  54. <el-tag type="success" effect="dark">{{ doctorEarnTitle }}</el-tag>
  55. <el-button type="warning" icon="Close" style="margin-left: 10px" @click="showDoctorEarn = false"> 关闭 </el-button>
  56. <el-button type="primary" icon="Upload" @click="exportExcel(2)"> 导出 Excel </el-button>
  57. </div>
  58. <el-table :data="data.doctorEarn.list" stripe highlight-current-row :height="mainTableHeight - 150" empty-text="没有数据" @row-dblclick="queryPatientBill">
  59. <el-table-column prop="inpatientNo" label="住院号"></el-table-column>
  60. <el-table-column prop="admissTimes" label="住院次数"></el-table-column>
  61. <el-table-column prop="patientName" label="姓名"></el-table-column>
  62. <el-table-column prop="chargeFee" label="发生费用" sortable></el-table-column>
  63. </el-table>
  64. <el-tag type="danger" style="margin-top: 15px; font-size: 14px; font-weight: bold" v-show="data.doctorEarn.sum > 0"> 合计:¥{{ data.doctorEarn.sum }} </el-tag>
  65. </div>
  66. </div>
  67. <div v-show="showPatientBill" class="wrapper">
  68. <div class="center-box" style="width: 50%">
  69. <div>
  70. <el-tag type="success" effect="dark">{{ patientBillTitle }}</el-tag>
  71. <el-button type="warning" icon="Close" style="margin-left: 10px" @click="showPatientBill = false"> 关闭 </el-button>
  72. <el-button type="primary" icon="Upload" @click="exportExcel(3)"> 导出 Excel </el-button>
  73. </div>
  74. <el-table :data="data.patientBill.list" stripe highlight-current-row :height="mainTableHeight - 200" empty-text="没有数据">
  75. <el-table-column prop="chargeName" label="项目/药品"></el-table-column>
  76. <el-table-column prop="orderNo" label="医嘱号"></el-table-column>
  77. <el-table-column prop="amount" label="数量"></el-table-column>
  78. <el-table-column prop="chargeFee" label="金额" sortable></el-table-column>
  79. </el-table>
  80. <el-tag type="danger" style="margin-top: 15px; font-size: 14px; font-weight: bold" v-show="data.patientBill.sum > 0"> 合计:¥{{ data.patientBill.sum }} </el-tag>
  81. </div>
  82. </div>
  83. </template>
  84. </page-layer>
  85. </template>
  86. <script>
  87. import store from '@/store'
  88. import {computed, reactive, ref} from 'vue'
  89. import {ElMessage} from 'element-plus'
  90. import {getAllWards, getDeptEarn, getDoctorEarn, getPatientBill} from '@/api/reports/dept-period-report'
  91. import {createWorkSheet, writeExcelFile} from '@/utils/excel'
  92. import {formatDate, getOneMonthOffset} from '@/utils/date'
  93. import {shortcuts} from '@/data/shortcuts'
  94. import PageLayer from "@/layout/PageLayer";
  95. export default {
  96. components: {PageLayer},
  97. setup() {
  98. const windowSize = store.state.app.windowSize
  99. const requestParam = initRequestParam()
  100. const { data, doctorEarnTitle, patientBillTitle } = initData()
  101. const { showDoctorEarn, showPatientBill } = initVisibilities()
  102. const mainTableHeight = windowSize.h - 50
  103. const handleSelect = (val) => {
  104. data.selectAll = val.length === data.allWards.length
  105. }
  106. const selectAllWards = () => {
  107. requestParam.depts = []
  108. if (data.selectAll) {
  109. data.allWards.forEach((item) => {
  110. requestParam.depts.push(item.code)
  111. })
  112. } else {
  113. requestParam.depts = []
  114. }
  115. }
  116. const pageSize = ref(15)
  117. const currentPage = ref(1)
  118. const handleCurrentChange = (val) => {
  119. currentPage.value = val
  120. }
  121. const handleSizeChange = (val) => {
  122. pageSize.value = val
  123. }
  124. const queryDeptData = () => {
  125. if (requestParam.depts.length === 0) {
  126. ElMessage({
  127. type: 'warning',
  128. message: '请先选择要查询的科室!',
  129. showClose: true,
  130. })
  131. } else {
  132. requestParam.start = formatDate(requestParam.datePeriod[0])
  133. requestParam.end = formatDate(requestParam.datePeriod[1])
  134. getDeptEarn(requestParam).then((res) => {
  135. data.deptEarn = res
  136. })
  137. }
  138. }
  139. const queryDoctorData = (row) => {
  140. row.start = requestParam.start
  141. row.end = requestParam.end
  142. getDoctorEarn(row).then((res) => {
  143. data.doctorEarn = res
  144. showDoctorEarn.value = true
  145. })
  146. }
  147. const queryPatientBill = (row) => {
  148. row.start = requestParam.start
  149. row.end = requestParam.end
  150. getPatientBill(row).then((res) => {
  151. data.patientBill = res
  152. showPatientBill.value = true
  153. })
  154. }
  155. const exportExcel = (flag) => {
  156. if (flag === 1 && data.deptEarn.list.length > 0) {
  157. store.commit('app/setLoading', true)
  158. setTimeout(() => {
  159. const title = {
  160. deptCode: '科室编码',
  161. deptName: '科室名称',
  162. doctorCode: '医生编号',
  163. doctorName: '医生姓名',
  164. totalCharge: '营收额',
  165. }
  166. const fields = ['deptCode', 'deptName', 'doctorCode', 'doctorName', 'totalCharge']
  167. const workSheet = createWorkSheet(data.deptEarn.list, fields, title)
  168. const fileName = '科室时段报表(' + requestParam.start + ' - ' + requestParam.end + ').xlsx'
  169. writeExcelFile(workSheet, fileName)
  170. }, 50)
  171. } else if (flag === 2 && data.doctorEarn.list.length > 0) {
  172. store.commit('app/setLoading', true)
  173. setTimeout(() => {
  174. const title = {
  175. deptCode: '科室编码',
  176. deptName: '科室名称',
  177. doctorCode: '医生编号',
  178. doctorName: '医生姓名',
  179. inpatientNo: '住院号',
  180. admissTimes: '住院次数',
  181. patientName: '姓名',
  182. chargeFee: '发生费用',
  183. }
  184. const fields = ['deptCode', 'deptName', 'doctorName', 'doctorCode', 'inpatientNo', 'admissTimes', 'patientName', 'chargeFee']
  185. const workSheet = createWorkSheet(data.doctorEarn.list, fields, title)
  186. const fileName = '医生报表(' + data.doctorEarn.doctorName + ')(' + requestParam.start + ' - ' + requestParam.end + ').xlsx'
  187. writeExcelFile(workSheet, fileName)
  188. }, 50)
  189. } else if (flag === 3 && data.patientBill.list.length > 0) {
  190. store.commit('app/setLoading', true)
  191. setTimeout(() => {
  192. const title = {
  193. chargeName: '项目/药品名称',
  194. orderNo: '医嘱号',
  195. amount: '数量',
  196. chargeFee: '金额',
  197. }
  198. const fields = ['chargeName', 'orderNo', 'amount', 'chargeFee']
  199. const workSheet = createWorkSheet(data.patientBill.list, fields, title)
  200. const fileName = '患者费用报表(' + data.patientBill.patientName + ')(' + requestParam.start + ' - ' + requestParam.end + ').xlsx'
  201. writeExcelFile(workSheet, fileName)
  202. }, 50)
  203. } else {
  204. store.commit('app/setLoading', false)
  205. ElMessage({
  206. type: 'warning',
  207. message: '没有数据!',
  208. showClose: true,
  209. })
  210. }
  211. }
  212. return {
  213. windowSize,
  214. shortcuts,
  215. mainTableHeight,
  216. showDoctorEarn,
  217. showPatientBill,
  218. requestParam,
  219. handleSelect,
  220. selectAllWards,
  221. data,
  222. queryDeptData,
  223. queryDoctorData,
  224. queryPatientBill,
  225. exportExcel,
  226. doctorEarnTitle,
  227. patientBillTitle,
  228. pageSize,
  229. currentPage,
  230. handleCurrentChange,
  231. handleSizeChange,
  232. }
  233. },
  234. }
  235. function initRequestParam() {
  236. const { start, end } = getOneMonthOffset()
  237. return reactive({
  238. datePeriod: [start, end],
  239. start: start,
  240. end: end,
  241. depts: [],
  242. })
  243. }
  244. function initData() {
  245. const data = reactive({
  246. selectAll: false,
  247. allWards: [],
  248. deptEarn: {
  249. list: [],
  250. sum: 0,
  251. },
  252. doctorEarn: {
  253. list: [],
  254. sum: 0,
  255. doctorName: '',
  256. },
  257. patientBill: {
  258. list: [],
  259. sum: 0,
  260. doctorName: '',
  261. patientName: '',
  262. },
  263. })
  264. getAllWards().then((res) => {
  265. data.allWards = res
  266. })
  267. const doctorEarnTitle = computed(() => {
  268. return '收治病人' + data.doctorEarn.list.length + '位(医生:' + data.doctorEarn.doctorName + ' ,营收额:¥' + data.doctorEarn.sum + ')'
  269. })
  270. const patientBillTitle = computed(() => {
  271. return (
  272. '共' +
  273. data.patientBill.list.length +
  274. '条(患者:' +
  275. data.patientBill.patientName +
  276. ' ,医生:' +
  277. data.patientBill.doctorName +
  278. ' ,诊疗费用:¥' +
  279. data.patientBill.sum +
  280. ')'
  281. )
  282. })
  283. return { data, doctorEarnTitle, patientBillTitle }
  284. }
  285. function initVisibilities() {
  286. const showDoctorEarn = ref(false)
  287. const showPatientBill = ref(false)
  288. return { showDoctorEarn, showPatientBill }
  289. }
  290. </script>
  291. <style scoped>
  292. .wrapper {
  293. position: fixed;
  294. top: 0;
  295. bottom: 0;
  296. left: 0;
  297. right: 0;
  298. text-align: center;
  299. background-color: rgba(0, 0, 0, 0.6);
  300. z-index: 2000;
  301. }
  302. .wrapper::after {
  303. content: '';
  304. display: inline-block;
  305. height: 100%;
  306. width: 0;
  307. vertical-align: middle;
  308. }
  309. .center-box {
  310. display: inline-block;
  311. padding: 15px 20px 10px 20px;
  312. vertical-align: middle;
  313. background-color: #fff;
  314. border-radius: 10px;
  315. border: 1px solid #ebeef5;
  316. box-shadow: 0 3px 5px #fff;
  317. text-align: left;
  318. overflow: hidden;
  319. -webkit-backface-visibility: hidden;
  320. backface-visibility: hidden;
  321. }
  322. </style>