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.

668 lines
19 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
  1. <template>
  2. <div class="box">
  3. <div>
  4. <div class="middlebox">
  5. <div class="contenttitle">
  6. 收费 /
  7. <span class="contenttitleBold">项目收费汇总</span>
  8. </div>
  9. </div>
  10. <div :style="'display: block;'">
  11. <div
  12. style="
  13. background-color: #fff;
  14. padding: 15px;
  15. border-radius: 8px;
  16. display: flex;
  17. flex-wrap: wrap;
  18. margin-bottom: 10px;
  19. height: 35px;
  20. margin-top: 7px;
  21. "
  22. >
  23. <div class="query">
  24. <span>科室</span>
  25. <el-cascader
  26. v-model="username"
  27. :options="registrardata"
  28. ref="example"
  29. popper-class="example"
  30. @change="ischangsItemTypeId"
  31. style="width: 100px"
  32. :props="{
  33. value: 'id',
  34. label: 'displayName',
  35. children: 'treeChildren',
  36. checkStrictly: true,
  37. expandTrigger: 'hover',
  38. }"
  39. size="small"
  40. >
  41. </el-cascader>
  42. <!-- <el-select
  43. v-model="username"
  44. placeholder="请选择"
  45. size="small"
  46. multiple
  47. >
  48. <el-option
  49. v-for="item in registrardata"
  50. :key="item.id"
  51. :label="item.surname"
  52. :value="item.id"
  53. >
  54. </el-option>
  55. </el-select> -->
  56. </div>
  57. <div class="query">
  58. <span>组合项目</span>
  59. <el-input
  60. placeholder="请选择组合项目"
  61. v-model="patientRegister.query.asbitemOCX"
  62. style="width: 200px"
  63. size="small"
  64. disabled
  65. >
  66. <el-button
  67. slot="append"
  68. icon="el-icon-search"
  69. @click="report.dialogAsbitemOCX = true"
  70. style="font-size: 20px"
  71. ></el-button>
  72. </el-input>
  73. </div>
  74. <div class="query">
  75. <span>开始日期</span>
  76. <el-date-picker
  77. type="date"
  78. placeholder="选择开始日期"
  79. size="small"
  80. v-model="startDate"
  81. value-format="yyyy-MM-dd"
  82. editable
  83. style="width:150px"
  84. >
  85. </el-date-picker>
  86. </div>
  87. <div class="query">
  88. <span>结束日期</span>
  89. <el-date-picker
  90. type="date"
  91. placeholder="选择结束日期"
  92. size="small"
  93. v-model="endDate"
  94. value-format="yyyy-MM-dd"
  95. editable
  96. style="width:150px"
  97. >
  98. </el-date-picker>
  99. </div>
  100. <div class="query">
  101. <el-button size="small" @click="onSubmit" class="commonbutton"
  102. >查询</el-button
  103. >
  104. </div>
  105. <div class="query">
  106. <el-button size="small" @click="handleExport" class="commonbutton"
  107. >导出excel</el-button
  108. >
  109. </div>
  110. <div class="query">
  111. <el-button size="small" @click="onPrint" class="commonbutton"
  112. >打印</el-button
  113. >
  114. </div>
  115. <div class="query">
  116. <el-button size="small" @click="columnarChart" class="commonbutton"
  117. >柱状图</el-button
  118. >
  119. </div>
  120. <div class="query">
  121. <el-button size="small" @click="peiChart" class="commonbutton"
  122. >饼图</el-button
  123. >
  124. </div>
  125. </div>
  126. <div
  127. style="
  128. display: flex;
  129. justify-content: space-between;
  130. position: relative;
  131. "
  132. id="domTable"
  133. >
  134. <div
  135. style="
  136. width: 47.7%;
  137. background-color: #fff;
  138. padding: 15px;
  139. border-radius: 8px;
  140. "
  141. ref="imageDom"
  142. >
  143. <!-- <h3 align="center">登记员工作量统计</h3>
  144. - 53-18
  145. <h5 align="right" style="margin-bottom: 5px;">
  146. 时间<span>{{ startDate }}</span
  147. ><span>{{ endDate }}</span>
  148. </h5> -->
  149. <el-table
  150. border
  151. show-summary
  152. :summary-method="summarizeRegisterCount"
  153. :span-method="objectStandardSpanMethod"
  154. :height="
  155. flag
  156. ? window.pageHeight < 600
  157. ? 415
  158. : window.pageHeight - 185 - 20
  159. : ''
  160. "
  161. :data="tableData"
  162. id="table"
  163. ref="table"
  164. style="width: 100%"
  165. :header-cell-class-name="headerStyle"
  166. :cell-style="tableRowClassName"
  167. >
  168. <el-table-column label="项目收费汇总">
  169. <el-table-column :label="'时间:' + startDate + '至' + endDate">
  170. <el-table-column
  171. :label="
  172. '应收总金额:' +
  173. sumChargeMoney +
  174. '折扣金额:' +
  175. sumDiscountMoney +
  176. '实收总金额:' +
  177. sumReceivedChargeMoney
  178. "
  179. >
  180. <el-table-column
  181. prop="itemTypeName"
  182. label="科室"
  183. ></el-table-column>
  184. <el-table-column
  185. prop="asbitemName"
  186. label="组合项目"
  187. ></el-table-column>
  188. <el-table-column
  189. prop="chargeMoney"
  190. label="应收金额"
  191. ></el-table-column>
  192. <el-table-column prop="discountMoney" label="折扣金额">
  193. </el-table-column>
  194. <el-table-column prop="receivedChargeMoney" label="实收金额">
  195. </el-table-column>
  196. </el-table-column>
  197. </el-table-column>
  198. </el-table-column>
  199. </el-table>
  200. </div>
  201. <div
  202. :style="
  203. 'width: 47.7%;overflow: hidden;height:' +
  204. (window.pageHeight < 600 ? 415 : window.pageHeight - 185 - 20) +
  205. 'px;background-color: #fff; padding: 15px; border-radius: 8px;'
  206. "
  207. >
  208. <div
  209. style="
  210. font-size: 20px;
  211. font-weight: 700;
  212. color: #232748;
  213. font-family: 'NotoSansSC-Bold';
  214. text-align: center;
  215. "
  216. >
  217. 项目收费汇总
  218. </div>
  219. <div
  220. :style="
  221. 'height:' +
  222. (window.pageHeight < 600 ? 387 : window.pageHeight - 185 - 48) +
  223. 'px;'
  224. "
  225. >
  226. <ChartBlock ref="chart2"></ChartBlock>
  227. </div>
  228. </div>
  229. </div>
  230. </div>
  231. </div>
  232. <!--通用选组合项目的控件-->
  233. <el-dialog
  234. title="组合项目选择"
  235. :visible.sync="report.dialogAsbitemOCX"
  236. :close-on-click-modal="false"
  237. width="700px"
  238. height="600px"
  239. >
  240. <AsbitemOCX />
  241. </el-dialog>
  242. </div>
  243. </template>
  244. <script>
  245. import { mapState, mapActions } from "vuex";
  246. import { getapi, postapi, putapi, deletapi } from "@/api/api";
  247. import ChartBlock from "../../components/workload/chartsBlock";
  248. import AsbitemOCX from "../../components/report/AsbitemOCX.vue";
  249. import { exportToExcel } from "../../utlis/Export2Excel";
  250. import html2canvas from "html2canvas";
  251. import printJs from "print-js";
  252. import { projectlist } from "@/request/commonapi";
  253. import {
  254. tcdate,
  255. } from "@/utlis/proFunc";
  256. export default {
  257. components: {
  258. ChartBlock,
  259. AsbitemOCX
  260. },
  261. data() {
  262. return {
  263. registrardata: [],
  264. username: [],
  265. startDate: "",
  266. endDate: "",
  267. tableData: [],
  268. seriesData: [],
  269. yAxisData: [],
  270. flag: true,
  271. pieData: [],
  272. sumChargeMoney: "",
  273. sumDiscountMoney: "",
  274. sumReceivedChargeMoney: "",
  275. };
  276. },
  277. created() {
  278. this.getList();
  279. this.dictInit()
  280. },
  281. mounted() {
  282. this.getNowTime();
  283. },
  284. methods: {
  285. //数据初始化
  286. dictInit() {
  287. // //体检类别
  288. // getapi("/api/app/medical-type/in-filter").then((res) => {
  289. // if (res.code == 1) {
  290. // this.dict.medicalType = res.data.items;
  291. // }
  292. // });
  293. // //体检类别 树结构
  294. getapi("/api/app/item-type/by-code-all").then((res) => {
  295. if (res.code == 1) {
  296. this.dict.itemTypeTree = res.data;
  297. tcdate(this.dict.itemTypeTree);
  298. }
  299. });
  300. },
  301. ischangsItemTypeId(v) {
  302. if (v.length > 1) {
  303. this.username = this.username.slice(-1)[0];
  304. } else {
  305. this.username = this.username[0];
  306. }
  307. this.$refs.example.toggleDropDownVisible();
  308. },
  309. headerStyle({ row, column, rowIndex, columnIndex }) {
  310. if (rowIndex === 1) {
  311. return "left-align";
  312. }
  313. if (rowIndex === 2) {
  314. return "left-align";
  315. }
  316. },
  317. summarizeRegisterCount(param) {
  318. const { columns, data } = param;
  319. const sums = [];
  320. columns.forEach((column, index) => {
  321. if (index === 0) {
  322. sums[index] = "合计";
  323. return;
  324. }
  325. if (index === 4) {
  326. sums[index] = this.sumReceivedChargeMoney+"元";
  327. return;
  328. }
  329. });
  330. return sums;
  331. },
  332. onPrint() {
  333. this.flag = false;
  334. this.$nextTick(() => {
  335. let width = this.$refs.imageDom.style.width;
  336. let cloneDom = this.$refs.imageDom.cloneNode(true);
  337. let imageDom = this.$refs.imageDom;
  338. cloneDom.style.position = "absolute";
  339. cloneDom.style.top = "0px";
  340. cloneDom.style.zIndex = "-1";
  341. cloneDom.style.width = width;
  342. imageDom.appendChild(cloneDom);
  343. html2canvas(cloneDom).then((canvas) => {
  344. // 转成图片,生成图片地址
  345. const url = canvas.toDataURL("image/png");
  346. printJs({
  347. printable: url,
  348. type: "image",
  349. documentTitle: "", // 标题
  350. style: "@page{size:auto;margin: 0cm 1cm 0cm 1cm;}", // 去除页眉页脚
  351. });
  352. });
  353. cloneDom.style.display = "none";
  354. this.flag = true;
  355. });
  356. },
  357. columnarChart() {
  358. let option2 = {
  359. // title: {
  360. // text: "登记员工作量统计",
  361. // left: "center",
  362. // },
  363. tooltip: {
  364. trigger: "axis",
  365. confine: true,
  366. },
  367. legend: {
  368. type: "scroll",
  369. orient: "horizontal", // 垂直
  370. right: "3%", // 左对齐
  371. top: "0%", // 位于顶部
  372. },
  373. grid: {
  374. show: false,
  375. left: "0%",
  376. right: "0%",
  377. top: "0%",
  378. bottom: "0%",
  379. containLabel: true,
  380. },
  381. xAxis: {
  382. type: "value",
  383. axisLabel: {
  384. textStyle: {
  385. fontSize: "14",
  386. },
  387. },
  388. axisLine: {
  389. show: true,
  390. },
  391. },
  392. yAxis: {
  393. type: "category",
  394. data: this.yAxisData,
  395. axisLabel: {
  396. textStyle: {
  397. fontSize: "14",
  398. },
  399. },
  400. },
  401. series: [
  402. {
  403. name: "实收金额",
  404. type: "bar",
  405. data: this.seriesData,
  406. },
  407. ],
  408. };
  409. this.$refs.chart2.setOption(option2);
  410. },
  411. peiChart() {
  412. let option2 = {
  413. // title: {
  414. // text: "登记员工作量统计",
  415. // left: "center",
  416. // },
  417. tooltip: {
  418. trigger: "item",
  419. confine: true,
  420. },
  421. legend: {
  422. data: this.yAxisData,
  423. orient: "horizontal",
  424. right: "3%",
  425. top: "0%",
  426. },
  427. grid: {
  428. show: false,
  429. left: "0%",
  430. right: "0%",
  431. top: "0%",
  432. bottom: "0%",
  433. containLabel: true,
  434. },
  435. series: [
  436. {
  437. type: "pie",
  438. label: {
  439. show: true,
  440. formatter: "{b} : {c} ({d}%)", // b代表名称,c代表对应值,d代表百分比
  441. },
  442. data: this.pieData,
  443. },
  444. ],
  445. };
  446. this.$refs.chart2.setOption(option2);
  447. },
  448. onSubmit() {
  449. let that = this;
  450. if (this.username == "" || this.username == []) {
  451. return this.$message({
  452. message: "请先选择科室",
  453. type: "error",
  454. });
  455. }
  456. if (this.startDate == "") {
  457. return this.$message({
  458. message: "请先选择开始日期",
  459. type: "error",
  460. });
  461. }
  462. if (this.endDate == "") {
  463. return this.$message({
  464. message: "请先选择结束日期",
  465. type: "error",
  466. });
  467. }
  468. let asbitemIds = [];
  469. if (this.report.dataAsbitemOCX.length > 0) {
  470. this.report.dataAsbitemOCX.forEach((e) => {
  471. asbitemIds.push(e.id);
  472. });
  473. }
  474. postapi(
  475. "/api/app/charge-report/get-project-fees-report",
  476. {
  477. itemTypeId: that.username,
  478. asbitems:asbitemIds,
  479. startDate: that.startDate,
  480. endDate: that.endDate,
  481. }
  482. ).then((res) => {
  483. if (res.code != -1) {
  484. // that.tableData = [...res.data.details];
  485. that.sumChargeMoney = res.data.sumChargeMoney;
  486. that.sumDiscountMoney = res.data.sumDiscountMoney;
  487. that.sumReceivedChargeMoney = res.data.sumReceivedChargeMoney;
  488. this.yAxisData = [];
  489. this.seriesData = [];
  490. this.pieData = [];
  491. that.computedStandardTableData(res.data.details)
  492. let pies = {
  493. name: "",
  494. value: 0,
  495. };
  496. for (let i = 0; i < res.data.details.length; i++) {
  497. let pie = JSON.parse(JSON.stringify(pies));
  498. this.yAxisData.push('('+res.data.details[i].itemTypeName+')'+res.data.details[i].asbitemName);
  499. this.seriesData.push(res.data.details[i].receivedChargeMoney);
  500. pie.name = '('+res.data.details[i].itemTypeName+')'+res.data.details[i].asbitemName
  501. pie.value = res.data.details[i].receivedChargeMoney;
  502. this.pieData.push(pie);
  503. }
  504. this.columnarChart();
  505. }
  506. });
  507. },
  508. computedStandardTableData(tableData) {
  509. const newData = [...tableData]; // 创建一个新的数组,避免修改原始数据
  510. const totalRows = {
  511. itemTypeName: "",
  512. asbitemName: "合计",
  513. chargeMoney: 0,
  514. discountMoney: 0,
  515. receivedChargeMoney: 0,
  516. }; // 合计行的数据
  517. // let pies = {
  518. // name: "",
  519. // value: 0,
  520. // };
  521. let obj = {};
  522. for (let i = 0; i < tableData.length; i++) {
  523. var item = tableData[i].itemTypeName;
  524. obj[item] = obj[item] + 1 || 1;
  525. }
  526. Object.keys(obj).forEach((key) => {
  527. let totalRow = JSON.parse(JSON.stringify(totalRows));
  528. // let pie = JSON.parse(JSON.stringify(pies));
  529. tableData.forEach((item) => {
  530. if (item.itemTypeName == key) {
  531. totalRow.itemTypeName = item.itemTypeName;
  532. totalRow.chargeMoney =(Number(totalRow.chargeMoney)+Number(item.chargeMoney)).toFixed(2)
  533. totalRow.discountMoney =(Number(totalRow.discountMoney)+Number(item.discountMoney)).toFixed(2)
  534. totalRow.receivedChargeMoney =(Number(totalRow.receivedChargeMoney)+Number(item.receivedChargeMoney)).toFixed(2)
  535. }
  536. // pie.name = '('+item.itemTypeName+')'+item.asbitemName;
  537. // pie.value = item.receivedChargeMoney;
  538. // this.yAxisData.push('('+item.itemTypeName+')'+item.asbitemName);
  539. // this.seriesData.push(item.receivedChargeMoney);
  540. });
  541. newData.push(totalRow);
  542. // this.pieData.push(pie);
  543. });
  544. this.ForwardStandardRanking(newData, "itemTypeName");
  545. this.columnarChart();
  546. },
  547. ForwardStandardRanking(data, p) {
  548. for (var i = 0; i < data.length - 1; i++) {
  549. for (var j = 0; j < data.length - 1 - i; j++) {
  550. var dd = data[j][p].localeCompare(data[j + 1][p], "zh"); //1---前者往后移,-1===位置不变
  551. if (dd > 0) {
  552. var temp = data[j];
  553. data[j] = data[j + 1];
  554. data[j + 1] = temp;
  555. }
  556. }
  557. }
  558. this.tableData = data;
  559. this.setStandardDates(this.tableData);
  560. },
  561. setStandardDates(arr) {
  562. var obj = {},
  563. k,
  564. arr1 = [];
  565. this.arr1 = [];
  566. for (var i = 0, len = arr.length; i < len; i++) {
  567. k = arr[i].itemTypeName; //需要合并的字段
  568. if (obj[k]) obj[k]++;
  569. else obj[k] = 1;
  570. }
  571. //保存结果{el-'元素',count-出现次数}
  572. for (var o in obj) {
  573. for (let i = 0; i < obj[o]; i++) {
  574. if (i === 0) {
  575. this.arr1.push(obj[o]);
  576. } else {
  577. this.arr1.push(0);
  578. }
  579. }
  580. }
  581. },
  582. objectStandardSpanMethod({ row, column, rowIndex, columnIndex }) {
  583. if (columnIndex === 0) {
  584. let _row = this.arr1[rowIndex];
  585. let _col = this.arr1[rowIndex] > 0 ? 1 : 0;
  586. return [_row, _col];
  587. }
  588. },
  589. tableRowClassName({ row, column, rowIndex, columnIndex }) {
  590. if (row.asbitemName == "合计") {
  591. return { backgroundColor: "#F5F7FA" };
  592. }
  593. },
  594. getList() {
  595. projectlist().then((res) => {
  596. if (res.code != -1) {
  597. this.registrardata = [...res.data];
  598. this.registrardata = this.formatData(this.registrardata);
  599. }
  600. });
  601. },
  602. formatData(dataList) {
  603. for (let i = 0; i < dataList.length; i++) {
  604. if (dataList[i].treeChildren.length < 1) {
  605. dataList[i].treeChildren = undefined;
  606. } else {
  607. this.formatData(dataList[i].treeChildren);
  608. }
  609. }
  610. return dataList;
  611. },
  612. getNowTime() {
  613. var now = new Date();
  614. var year = now.getFullYear(); // 得到年份
  615. var month = now.getMonth(); // 得到月份
  616. var date = now.getDate(); // 得到日期
  617. month = month + 1;
  618. month = month.toString().padStart(2, "0");
  619. date = date.toString().padStart(2, "0");
  620. var defaultDate = `${year}-${month}-${date}`;
  621. this.startDate = defaultDate;
  622. this.endDate = defaultDate;
  623. },
  624. handleExport() {
  625. exportToExcel("#table", "项目收费汇总", false);
  626. },
  627. },
  628. computed: {
  629. ...mapState(["window", "dict", "patientRegister", "report"]),
  630. },
  631. updated() {
  632. this.$nextTick(() => {
  633. this.$refs.table.doLayout();
  634. });
  635. },
  636. };
  637. </script>
  638. <style scoped>
  639. @import "../../assets/css/global_button.css";
  640. @import "../../assets/css/global_dialog.css";
  641. @import "../../assets/css/global_table.css";
  642. @import "../../assets/css/global_form.css";
  643. @import "../../assets/css/global_input.css";
  644. @import "../../assets/css/global.css";
  645. .query {
  646. margin-right: 10px;
  647. display: flex;
  648. justify-content: center;
  649. align-items: center;
  650. font-size: 14px;
  651. color: #232748;
  652. font-size: 400;
  653. font-family: "NotoSansSC-Regular";
  654. }
  655. .box {
  656. display: flex;
  657. flex-direction: column;
  658. }
  659. :deep .left-align .cell {
  660. text-align: left !important;
  661. }
  662. .query:last-child{
  663. margin-right: 0;
  664. }
  665. </style>