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.

508 lines
14 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
  1. <template>
  2. <div>
  3. <el-card>
  4. <div slot="header">医生工作量统计</div>
  5. <div :style="'display: block;width:' + (window.pageWidth - 45) + 'px;'">
  6. <div style="display: flex; flex-wrap: wrap; height: 35px">
  7. <div class="query">
  8. <span>医生</span>
  9. <el-select
  10. v-model="username"
  11. placeholder="请选择"
  12. size="small"
  13. multiple
  14. >
  15. <el-option
  16. v-for="item in registrardata"
  17. :key="item.id"
  18. :label="item.surname"
  19. :value="item.id"
  20. >
  21. </el-option>
  22. </el-select>
  23. </div>
  24. <div class="query">
  25. <span>开始日期</span>
  26. <el-date-picker
  27. type="date"
  28. placeholder="选择开始日期"
  29. size="small"
  30. v-model="startDate"
  31. value-format="yyyy-MM-dd"
  32. editable
  33. >
  34. </el-date-picker>
  35. </div>
  36. <div class="query">
  37. <span>结束日期</span>
  38. <el-date-picker
  39. type="date"
  40. placeholder="选择结束日期"
  41. size="small"
  42. v-model="endDate"
  43. value-format="yyyy-MM-dd"
  44. editable
  45. >
  46. </el-date-picker>
  47. </div>
  48. <div class="query">
  49. <el-button size="small" @click="onSubmit">查询</el-button>
  50. </div>
  51. <div class="query">
  52. <el-button size="small" @click="handleExport">导出excel</el-button>
  53. </div>
  54. <div class="query">
  55. <el-button size="small" @click="onPrint">打印</el-button>
  56. </div>
  57. <div class="query">
  58. <el-button size="small" @click="columnarChart">柱状图</el-button>
  59. </div>
  60. <div class="query">
  61. <el-button size="small" @click="peiChart">饼图</el-button>
  62. </div>
  63. </div>
  64. <div
  65. style="
  66. display: flex;
  67. justify-content: space-between;
  68. position: relative;
  69. margin-top: 5px;
  70. "
  71. id="domTable"
  72. >
  73. <div style="width: 49%" ref="imageDom">
  74. <!-- <h3 align="center">登记员工作量统计</h3>
  75. - 53-18
  76. <h5 align="right" style="margin-bottom: 5px;">
  77. 时间<span>{{ startDate }}</span
  78. ><span>{{ endDate }}</span>
  79. </h5> -->
  80. <el-table
  81. border
  82. :span-method="objectSpanMethod"
  83. :height="
  84. flag
  85. ? window.pageHeight < 600
  86. ? 415
  87. : window.pageHeight - 185 - 10
  88. : ''
  89. "
  90. :data="tableData"
  91. id="table"
  92. ref="table"
  93. style="width: 100%"
  94. :header-cell-class-name="headerStyle"
  95. >
  96. <el-table-column label="医生工作量统计">
  97. <el-table-column :label="'时间:' + startDate + '至' + endDate">
  98. <el-table-column
  99. prop="doctorName"
  100. label="医生"
  101. ></el-table-column>
  102. <el-table-column
  103. prop="asbitemName"
  104. label="组合项目"
  105. ></el-table-column>
  106. <el-table-column
  107. prop="checkCount"
  108. label="人数"
  109. ></el-table-column>
  110. <el-table-column prop="avgStandardPrice" label="标准价格">
  111. </el-table-column>
  112. <el-table-column prop="avgChargePrice" label="实际价格">
  113. </el-table-column>
  114. <el-table-column prop="sumStandardPrice" label="标准金额">
  115. </el-table-column>
  116. <el-table-column prop="sumChargePrice" label="实际金额">
  117. </el-table-column>
  118. </el-table-column>
  119. </el-table-column>
  120. </el-table>
  121. </div>
  122. <div
  123. :style="
  124. 'width: 49%;overflow: hidden;height:' +
  125. (window.pageHeight < 600 ? 415 : window.pageHeight - 185 - 5) +
  126. 'px;'
  127. "
  128. >
  129. <ChartBlock ref="chart2"></ChartBlock>
  130. </div>
  131. </div>
  132. </div>
  133. </el-card>
  134. </div>
  135. </template>
  136. <script>
  137. import { mapState, mapActions } from "vuex";
  138. import { getapi, postapi, putapi, deletapi } from "@/api/api";
  139. import ChartBlock from "../../components/workload/chartsBlock";
  140. import { exportToExcel } from "../../utlis/Export2Excel";
  141. import html2canvas from "html2canvas";
  142. import printJs from "print-js";
  143. export default {
  144. components: {
  145. ChartBlock,
  146. },
  147. data() {
  148. return {
  149. registrardata: [],
  150. username: [],
  151. startDate: "",
  152. endDate: "",
  153. tableData: [],
  154. seriesData: [],
  155. yAxisData: [],
  156. flag: true,
  157. arr1: [],
  158. pieData: [],
  159. };
  160. },
  161. created() {
  162. this.getList();
  163. },
  164. mounted() {
  165. this.getNowTime();
  166. },
  167. methods: {
  168. peiChart() {
  169. let option2 = {
  170. title: {
  171. text: "医生工作量统计",
  172. left: "center",
  173. },
  174. tooltip: {
  175. trigger: "item",
  176. confine: true,
  177. },
  178. legend: {
  179. data:this.yAxisData,
  180. orient: "horizontal",
  181. right: "3%",
  182. top: "3%",
  183. },
  184. grid: {
  185. show: false,
  186. left: "0%",
  187. right: "5%",
  188. top: "8%",
  189. bottom: "2%",
  190. containLabel: true,
  191. },
  192. series: [
  193. {
  194. type: "pie",
  195. label: {
  196. show: true,
  197. formatter: "{b} : {c}人 ({d}%)" // b代表名称,c代表对应值,d代表百分比
  198. },
  199. data: this.pieData
  200. }
  201. ],
  202. };
  203. this.$refs.chart2.setOption(option2);
  204. },
  205. columnarChart() {
  206. let option2 = {
  207. title: {
  208. text: "医生工作量统计",
  209. left: "center",
  210. },
  211. tooltip: {
  212. trigger: "axis",
  213. confine: true,
  214. },
  215. legend: {
  216. type: "scroll",
  217. orient: "horizontal",
  218. right: "3%",
  219. top: "3%",
  220. },
  221. grid: {
  222. show: false,
  223. left: "0%",
  224. right: "5%",
  225. top: "8%",
  226. bottom: "2%",
  227. containLabel: true,
  228. },
  229. xAxis: {
  230. type: "value",
  231. axisLabel: {
  232. textStyle: {
  233. fontSize: "14",
  234. },
  235. },
  236. axisLine: {
  237. show: true,
  238. },
  239. },
  240. yAxis: {
  241. type: "category",
  242. data: this.yAxisData,
  243. axisLabel: {
  244. textStyle: {
  245. fontSize: "14",
  246. },
  247. },
  248. },
  249. series: [
  250. {
  251. name: "人数",
  252. type: "bar",
  253. data: this.seriesData,
  254. },
  255. ],
  256. };
  257. this.$refs.chart2.setOption(option2);
  258. },
  259. headerStyle({ row, column, rowIndex, columnIndex }) {
  260. if (rowIndex === 1) {
  261. return "right-align";
  262. }
  263. },
  264. summarizeRegisterCount(param) {
  265. const { columns, data } = param;
  266. const sums = [];
  267. columns.forEach((column, index) => {
  268. if (index === 0) {
  269. sums[index] = "合计";
  270. return;
  271. }
  272. const values = data.map((item) => Number(item[column.property]));
  273. if (index === 1) {
  274. sums[index] = values.reduce((prev, curr) => {
  275. const value = Number(curr);
  276. if (!isNaN(value)) {
  277. return prev + curr;
  278. } else {
  279. return prev;
  280. }
  281. }, 0);
  282. sums[index] = "共" + sums[index] + "人";
  283. } else {
  284. sums[index] = "";
  285. }
  286. });
  287. return sums;
  288. },
  289. onPrint() {
  290. this.flag = false;
  291. this.$nextTick(() => {
  292. let width = this.$refs.imageDom.style.width;
  293. let cloneDom = this.$refs.imageDom.cloneNode(true);
  294. let imageDom = this.$refs.imageDom;
  295. cloneDom.style.position = "absolute";
  296. cloneDom.style.top = "0px";
  297. cloneDom.style.zIndex = "-1";
  298. cloneDom.style.width = width;
  299. console.log(cloneDom);
  300. imageDom.appendChild(cloneDom);
  301. html2canvas(cloneDom).then((canvas) => {
  302. // 转成图片,生成图片地址
  303. const url = canvas.toDataURL("image/png");
  304. printJs({
  305. printable: url,
  306. type: "image",
  307. documentTitle: "", // 标题
  308. style: "@page{size:auto;margin: 0cm 1cm 0cm 1cm;}", // 去除页眉页脚
  309. });
  310. });
  311. cloneDom.style.display = "none";
  312. this.flag = true;
  313. });
  314. },
  315. onSubmit() {
  316. let that = this;
  317. if (this.startDate == "") {
  318. return this.$message({
  319. message: "请先选择开始日期",
  320. type: "error",
  321. });
  322. }
  323. if (this.endDate == "") {
  324. return this.$message({
  325. message: "请先选择结束日期",
  326. type: "error",
  327. });
  328. }
  329. postapi("/api/app/internalreport/getdoctorpersonnelworkloadreport", {
  330. userIds: that.username,
  331. startDate: that.startDate,
  332. endDate: that.endDate,
  333. }).then((res) => {
  334. if (res.code != -1) {
  335. // that.tableData = res.data;
  336. that.computedTableData(res.data);
  337. }
  338. });
  339. },
  340. setdates(arr) {
  341. var obj = {},
  342. k,
  343. arr1 = [];
  344. this.arr1 = [];
  345. for (var i = 0, len = arr.length; i < len; i++) {
  346. k = arr[i].doctorName; //需要合并的字段
  347. if (obj[k]) obj[k]++;
  348. else obj[k] = 1;
  349. }
  350. //保存结果{el-'元素',count-出现次数}
  351. for (var o in obj) {
  352. for (let i = 0; i < obj[o]; i++) {
  353. if (i === 0) {
  354. this.arr1.push(obj[o]);
  355. } else {
  356. this.arr1.push(0);
  357. }
  358. }
  359. }
  360. },
  361. objectSpanMethod({ row, column, rowIndex, columnIndex }) {
  362. if (columnIndex === 0) {
  363. let _row = this.arr1[rowIndex];
  364. let _col = this.arr1[rowIndex] > 0 ? 1 : 0;
  365. return [_row, _col];
  366. }
  367. },
  368. getList() {
  369. getapi("/api/identity/users/getlist").then((res) => {
  370. if (res.code != -1) {
  371. this.registrardata = [...res.data.items];
  372. }
  373. });
  374. },
  375. getNowTime() {
  376. var now = new Date();
  377. var year = now.getFullYear(); // 得到年份
  378. var month = now.getMonth(); // 得到月份
  379. var date = now.getDate(); // 得到日期
  380. month = month + 1;
  381. month = month.toString().padStart(2, "0");
  382. date = date.toString().padStart(2, "0");
  383. var defaultDate = `${year}-${month}-${date}`;
  384. this.startDate = defaultDate;
  385. this.endDate = defaultDate;
  386. },
  387. ForwardRanking(data, p) {
  388. for (var i = 0; i < data.length - 1; i++) {
  389. for (var j = 0; j < data.length - 1 - i; j++) {
  390. var dd = data[j][p].localeCompare(data[j + 1][p], "zh"); //1---前者往后移,-1===位置不变
  391. if (dd > 0) {
  392. var temp = data[j];
  393. data[j] = data[j + 1];
  394. data[j + 1] = temp;
  395. }
  396. }
  397. }
  398. this.tableData = data;
  399. this.setdates(this.tableData);
  400. },
  401. computedTableData(tableData) {
  402. const newData = [...tableData]; // 创建一个新的数组,避免修改原始数据
  403. const totalRows = {
  404. doctorName: "",
  405. asbitemName: "合计",
  406. checkCount: 0,
  407. avgStandardPrice: 0,
  408. avgChargePrice: 0,
  409. sumStandardPrice: 0,
  410. sumChargePrice: 0,
  411. }; // 合计行的数据
  412. let pies = {
  413. name: "",
  414. value: 0,
  415. };
  416. let obj = {};
  417. for (let i = 0; i < tableData.length; i++) {
  418. var item = tableData[i].doctorName;
  419. obj[item] = obj[item] + 1 || 1;
  420. }
  421. Object.keys(obj).forEach((key) => {
  422. let totalRow = JSON.parse(JSON.stringify(totalRows));
  423. let pie = JSON.parse(JSON.stringify(pies));
  424. tableData.forEach((item) => {
  425. if (item.doctorName == key) {
  426. totalRow.doctorName = item.doctorName;
  427. pie.name = item.doctorName;
  428. totalRow.checkCount += item.checkCount;
  429. pie.value += item.checkCount;
  430. totalRow.avgStandardPrice =
  431. (totalRow.avgStandardPrice * 100000 +
  432. item.avgStandardPrice * 100000) /
  433. 100000;
  434. totalRow.avgChargePrice =
  435. (totalRow.avgChargePrice * 100000 +
  436. item.avgChargePrice * 100000) /
  437. 100000;
  438. totalRow.sumStandardPrice =
  439. (totalRow.sumStandardPrice * 100000 +
  440. item.sumStandardPrice * 100000) /
  441. 100000;
  442. totalRow.sumChargePrice =
  443. (totalRow.sumChargePrice * 100000 +
  444. item.sumChargePrice * 100000) /
  445. 100000;
  446. }
  447. });
  448. newData.push(totalRow);
  449. this.pieData.push(pie);
  450. this.yAxisData.push(totalRow.doctorName);
  451. this.seriesData.push(totalRow.checkCount);
  452. });
  453. this.ForwardRanking(newData, "doctorName");
  454. this.columnarChart();
  455. },
  456. handleExport() {
  457. exportToExcel("#table", "医生工作量统计");
  458. },
  459. },
  460. computed: {
  461. ...mapState(["window", "dict", "patientRegister", "report"]),
  462. },
  463. updated() {
  464. this.$nextTick(() => {
  465. this.$refs.table.doLayout();
  466. });
  467. },
  468. };
  469. </script>
  470. <style scoped>
  471. @import "../../assets/css/global_button.css";
  472. @import "../../assets/css/global_card.css";
  473. @import "../../assets/css/global_input.css";
  474. @import "../../assets/css/global_table.css";
  475. @import "../../assets/css/global.css";
  476. .query {
  477. margin-left: 10px;
  478. display: flex;
  479. justify-content: center;
  480. align-items: center;
  481. }
  482. :deep .right-align .cell {
  483. text-align: right !important;
  484. }
  485. ::v-deep .el-table__body-wrapper::-webkit-scrollbar {
  486. width: 0px;
  487. background: rgba(213, 215, 220, 0.3);
  488. border: none;
  489. }
  490. ::v-deep .el-table__body-wrapper::-webkit-scrollbar-track {
  491. border: none;
  492. }
  493. ::v-deep .el-table th.gutter {
  494. display: none;
  495. width: 0;
  496. }
  497. ::v-deep .el-table colgroup col[name="gutter"] {
  498. display: none;
  499. width: 0;
  500. }
  501. ::v-deep .el-table__body {
  502. width: 100% !important;
  503. }
  504. </style>