caseIndexAnalysis.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. <template>
  2. <div class="box">
  3. <el-row :gutter="16">
  4. <!-- 左侧菜单 -->
  5. <el-col :span="8">
  6. <div class="box_wrapper" :style="{'height': boxWrapperHeight}">
  7. <el-input placeholder="输入关键字进行过滤" v-model="filterText"></el-input>
  8. <el-tree
  9. class="filter-tree"
  10. node-key="id"
  11. highlight-current
  12. :data="showMenus"
  13. :props="defaultProps"
  14. :filter-node-method="filterNode"
  15. ref="tree"
  16. @node-click="handleNodeClick"
  17. :current-node-key="ruleId"
  18. :default-expanded-keys="[ruleId]"
  19. >
  20. <span class="custom-tree-node" slot-scope="{ node }">
  21. <span>{{ node.label }}</span>
  22. </span>
  23. </el-tree>
  24. </div>
  25. </el-col>
  26. <!-- 右侧列表 -->
  27. <el-col :span="16">
  28. <div class="box_wrapper" :style="{'height': boxWrapperHeight}">
  29. <el-form :inline="true" :model="formInline" class="demo-form-inline">
  30. <el-form-item label="">
  31. <el-date-picker v-model="formInline.start_time" type="date" :picker-options="pickerOptions1" placeholder="开始日期"></el-date-picker>
  32. </el-form-item>
  33. <el-form-item label="">
  34. <el-date-picker v-model="formInline.end_time" type="date" :picker-options="pickerOptions2" placeholder="结束日期"></el-date-picker>
  35. </el-form-item>
  36. <el-form-item>
  37. <el-button type="primary" @click="onSearch">查询</el-button>
  38. </el-form-item>
  39. </el-form>
  40. <!-- 排名柱状图 -->
  41. <div class="rank-box">
  42. <Title :title="'Top 10'" style="margin-bottom: 0" />
  43. <div v-if="rankData.length" id="myChart1" style="width: 100%; height: 400px"></div>
  44. <el-empty v-else description="暂无排名数据"></el-empty>
  45. </div>
  46. <div class="table-box">
  47. <Title :title="'科室排名'" />
  48. <el-table :data="tableData" style="width: 100%">
  49. <el-table-column type="index" label="序号" width="80" align="center"></el-table-column>
  50. <el-table-column prop="dep_name" label="出院科室"></el-table-column>
  51. <el-table-column prop="" label="" align="center">
  52. <template slot="header" slot-scope="scope">
  53. <span>{{ scope._self.ruleName }}</span>
  54. </template>
  55. <template slot-scope="scope">
  56. <span>{{ (scope.row.res * 100).toFixed(2) + '%' }}</span>
  57. </template>
  58. </el-table-column>
  59. <el-table-column prop="numerator" label="正确病历数" align="center">
  60. <template slot-scope="scope">
  61. <span class="link" @click="toPage(scope.row, 1)">{{ scope.row.numerator }}</span>
  62. </template>
  63. </el-table-column>
  64. <el-table-column prop="denominator" label="病历总数" align="center">
  65. <template slot-scope="scope">
  66. <span class="link" @click="toPage(scope.row, 0)">{{ scope.row.denominator }}</span>
  67. </template>
  68. </el-table-column>
  69. </el-table>
  70. </div>
  71. </div>
  72. </el-col>
  73. </el-row>
  74. </div>
  75. </template>
  76. <script>
  77. import * as echarts from 'echarts';
  78. import Title from '@/components/Title';
  79. import { dateFormat } from '@/utils'
  80. export default {
  81. components: {
  82. Title,
  83. },
  84. data() {
  85. return {
  86. menus: [
  87. {
  88. id: 2,
  89. name: '二、病历书写时效性指标',
  90. children: [
  91. {
  92. id: 21,
  93. name: '指标四、入院记录 24 小时内完成率',
  94. },
  95. {
  96. id: 22,
  97. name: '指标五、手术记录24小时内完成率',
  98. },
  99. {
  100. id: 23,
  101. name: '指标六、出院记录24小时内完成率',
  102. },
  103. {
  104. id: 24,
  105. name: '指标七、病案首页24小时内完成率',
  106. },
  107. ],
  108. },
  109. {
  110. id: 3,
  111. name: '三、重大检查记录符合率',
  112. children: [
  113. {
  114. id: 31,
  115. name: '指标八、CT/MRI检查记录符合率',
  116. },
  117. {
  118. id: 32,
  119. name: '指标九、病理检查记录符合率',
  120. },
  121. {
  122. id: 33,
  123. name: '指标十、细菌培养检查记录符合率',
  124. },
  125. ],
  126. },
  127. {
  128. id: 4,
  129. name: '四、诊疗行为记录符合率',
  130. children: [
  131. {
  132. id: 41,
  133. name: '指标十一、抗菌药物使用记录符合率',
  134. },
  135. {
  136. id: 42,
  137. name: '指标十二、恶性肿瘤化学治疗记录符合率',
  138. },
  139. {
  140. id: 43,
  141. name: '指标十三、恶性肿瘤放射治疗记录符合率',
  142. },
  143. {
  144. id: 44,
  145. name: '指标十四、手术相关记录完整率',
  146. },
  147. {
  148. id: 45,
  149. name: '指标十五、植入物相关记录符合率',
  150. },
  151. {
  152. id: 46,
  153. name: '指标十六、临床用血相关记录符合率',
  154. },
  155. {
  156. id: 47,
  157. name: '指标十七、医师查房记录完整率',
  158. },
  159. {
  160. id: 48,
  161. name: '指标十八、患者抢救记录及时完成率',
  162. },
  163. {
  164. id: 49,
  165. name: 'MER-D&T-08-1 患者抢救成功率',
  166. },
  167. ],
  168. },
  169. {
  170. id: 5,
  171. name: '五、病历归档质量指标',
  172. children: [
  173. {
  174. id: 51,
  175. name: '指标十九、出院患者病历2日归档率',
  176. },
  177. {
  178. id: 52,
  179. name: '指标二十、出院患者病历归档完整率',
  180. },
  181. {
  182. id: 53,
  183. name: '指标二十一、主要诊断填写正确率',
  184. },
  185. {
  186. id: 54,
  187. name: '指标二十二、主要诊断编码正确率',
  188. },
  189. {
  190. id: 55,
  191. name: '指标二十三、主要手术填写正确率',
  192. },
  193. {
  194. id: 56,
  195. name: '指标二十四、主要手术编码正确率',
  196. },
  197. {
  198. id: 57,
  199. name: '指标二十五、不合理复制病历发生率',
  200. },
  201. {
  202. id: 58,
  203. name: '指标二十六、知情同意书规范签署率',
  204. },
  205. {
  206. id: 59,
  207. name: '指标二十七、甲级病历率',
  208. },
  209. ],
  210. },
  211. ],
  212. // 医院嵌入需显示指标4/6/7/8/10/11/12/13/15/16/18/20/22/24/26
  213. menus2: [
  214. {
  215. id: 2,
  216. name: '二、病历书写时效性指标',
  217. children: [
  218. {
  219. id: 21,
  220. name: '指标四、入院记录 24 小时内完成率',
  221. },
  222. {
  223. id: 23,
  224. name: '指标六、出院记录24小时内完成率',
  225. },
  226. {
  227. id: 24,
  228. name: '指标七、病案首页24小时内完成率',
  229. },
  230. ],
  231. },
  232. {
  233. id: 3,
  234. name: '三、重大检查记录符合率',
  235. children: [
  236. {
  237. id: 31,
  238. name: '指标八、CT/MRI检查记录符合率',
  239. },
  240. {
  241. id: 33,
  242. name: '指标十、细菌培养检查记录符合率',
  243. },
  244. ],
  245. },
  246. {
  247. id: 4,
  248. name: '四、诊疗行为记录符合率',
  249. children: [
  250. {
  251. id: 41,
  252. name: '指标十一、抗菌药物使用记录符合率',
  253. },
  254. {
  255. id: 42,
  256. name: '指标十二、恶性肿瘤化学治疗记录符合率',
  257. },
  258. {
  259. id: 43,
  260. name: '指标十三、恶性肿瘤放射治疗记录符合率',
  261. },
  262. {
  263. id: 45,
  264. name: '指标十五、植入物相关记录符合率',
  265. },
  266. {
  267. id: 46,
  268. name: '指标十六、临床用血相关记录符合率',
  269. },
  270. {
  271. id: 48,
  272. name: '指标十八、患者抢救记录及时完成率',
  273. },
  274. ],
  275. },
  276. {
  277. id: 5,
  278. name: '五、病历归档质量指标',
  279. children: [
  280. {
  281. id: 51,
  282. name: '指标十九、出院患者病历2日归档率',
  283. },
  284. {
  285. id: 53,
  286. name: '指标二十一、主要诊断填写正确率',
  287. },
  288. {
  289. id: 55,
  290. name: '指标二十三、主要手术填写正确率',
  291. },
  292. {
  293. id: 57,
  294. name: '指标二十五、不合理复制病历发生率',
  295. }
  296. ],
  297. },
  298. ],
  299. filterText: '',
  300. defaultProps: {
  301. children: 'children',
  302. label: 'name',
  303. },
  304. ruleId: '',
  305. ruleName: '--',
  306. pickerOptions1: {
  307. disabledDate: time => {
  308. if (this.formInline.end_time) {
  309. return time.getTime() > new Date(this.formInline.end_time).getTime();
  310. } else {
  311. return time.getTime() > Date.now();
  312. }
  313. },
  314. },
  315. pickerOptions2: {
  316. disabledDate: time => {
  317. if (this.formInline.start_time) {
  318. return time.getTime() < new Date(this.formInline.start_time).getTime();
  319. } else {
  320. return time.getTime() > Date.now();
  321. }
  322. },
  323. },
  324. formInline: {
  325. time: '',
  326. start_time: '',
  327. end_time: '',
  328. },
  329. tableData: [],
  330. rankData: [],
  331. myChart: ''
  332. };
  333. },
  334. created() {
  335. const currentYear = new Date().getFullYear().toString()
  336. this.formInline.start_time = new Date(`${currentYear}-01-01 00:00:00`)
  337. this.formInline.end_time = new Date()
  338. const menus = this.$route.path === '/embedIndex-home' ? this.menus2 : this.menus
  339. this.ruleId = menus[0].children[0].id
  340. this.ruleName = menus[0].children[0].name
  341. this.getList()
  342. this.getRankList()
  343. },
  344. computed: {
  345. boxWrapperHeight() {
  346. return this.$route.path === '/embedIndex-home' ? '815px' : '885px'
  347. },
  348. showMenus() {
  349. return this.$route.path === '/embedIndex-home' ? this.menus2 : this.menus
  350. }
  351. },
  352. activated() {
  353. if (this.myChart) {
  354. this.myChart.resize();
  355. }
  356. },
  357. methods: {
  358. // 菜单筛选
  359. filterNode(value, data) {
  360. if (!value) return true;
  361. return data.name.indexOf(value) !== -1;
  362. },
  363. // 菜单点击
  364. handleNodeClick(data) {
  365. const { id, name } = data;
  366. if (id > 10) {
  367. this.ruleId = id;
  368. this.ruleName = name.split('、')[1];
  369. this.getList();
  370. this.getRankList();
  371. }
  372. },
  373. // 搜索
  374. onSearch() {
  375. if (this.ruleId) {
  376. this.getList();
  377. this.getRankList();
  378. } else {
  379. this.$message.error('请选择指标!');
  380. }
  381. },
  382. // 获取科室排名
  383. getList() {
  384. const { start_time, end_time } = this.formInline;
  385. const params = {
  386. type: this.ruleId,
  387. page: 1,
  388. page_size: 1000,
  389. start_time: start_time ? dateFormat(start_time, 'YYYYMMDD') : '',
  390. end_time: end_time ? dateFormat(end_time, 'YYYYMMDD') : ''
  391. };
  392. this.$axios2.post('/dep_statistics', params).then(res => {
  393. if (Array.isArray(res.data.data)) {
  394. this.tableData = res.data.data;
  395. } else {
  396. this.tableData = [];
  397. }
  398. });
  399. },
  400. // 获取排名rank10
  401. getRankList() {
  402. const { start_time, end_time } = this.formInline;
  403. const params = {
  404. type: this.ruleId,
  405. page: 1,
  406. page_size: 10,
  407. start_time: start_time ? dateFormat(start_time, 'YYYYMMDD') : '',
  408. end_time: end_time ? dateFormat(end_time, 'YYYYMMDD') : ''
  409. };
  410. this.$axios2.post('/dep_statistics', params).then(res => {
  411. if (Array.isArray(res.data.data)) {
  412. this.rankData = res.data.data;
  413. } else {
  414. this.rankData = [];
  415. }
  416. if (this.rankData.length) {
  417. this.$nextTick(() => {
  418. this.initCharts1();
  419. });
  420. }
  421. });
  422. },
  423. // 柱状图
  424. initCharts1() {
  425. let dataName = [];
  426. let dataFleg = [];
  427. for (let item in this.rankData) {
  428. dataName.push(this.rankData[item].dep_name);
  429. dataFleg.push((this.rankData[item].res * 100).toFixed(2));
  430. }
  431. // 销毁上一次实例
  432. echarts.init(document.getElementById('myChart1')).dispose();
  433. // 构建新实例
  434. let myChart = echarts.init(document.getElementById('myChart1'));
  435. this.myChart = myChart
  436. window.addEventListener('resize', function () {
  437. myChart.resize();
  438. });
  439. if (this.rankData.length) {
  440. myChart.setOption({
  441. toolbox: {
  442. feature: {
  443. saveAsImage: {
  444. name: '科室排名',
  445. },
  446. },
  447. },
  448. tooltip: {
  449. trigger: 'axis',
  450. axisPointer: {
  451. type: 'cross',
  452. crossStyle: {
  453. color: '#999',
  454. },
  455. },
  456. },
  457. legend: {
  458. show: true,
  459. },
  460. xAxis: {
  461. type: 'category',
  462. data: dataName,
  463. axisLabel: {
  464. rotate: 15,
  465. },
  466. },
  467. grid: {
  468. left: '3%',
  469. right: '3%',
  470. bottom: '3%',
  471. containLabel: true,
  472. },
  473. yAxis: {
  474. type: 'value',
  475. axisLabel: {
  476. show: true,
  477. interval: 0,
  478. formatter: '{value} %',
  479. },
  480. },
  481. series: [
  482. {
  483. data: dataFleg,
  484. type: 'bar',
  485. showBackground: true,
  486. barMaxWidth: 30,
  487. label: {
  488. show: true,
  489. position: 'top',
  490. },
  491. name: this.ruleName,
  492. backgroundStyle: {
  493. color: 'rgba(180, 180, 180, 0.2)',
  494. },
  495. },
  496. ],
  497. });
  498. } else {
  499. myChart.setOption({
  500. title: {
  501. text: '暂无数据',
  502. x: 'center',
  503. y: 'center',
  504. textStyle: {
  505. fontSize: 14,
  506. fontWeight: 'normal',
  507. },
  508. },
  509. });
  510. }
  511. },
  512. // 跳转列表页
  513. toPage(row, status) {
  514. const { start_time, end_time } = this.formInline;
  515. let path
  516. if (this.$route.path === '/embedIndex-home') {
  517. path = 'embedIndex-caseIndexAnalysisList'
  518. } else {
  519. path = '/caseIndexAnalysisList'
  520. }
  521. this.$router.push({ path, query: { ruleId: this.ruleId, ruleName: this.ruleName, start: start_time ? dateFormat(start_time, 'YYYYMMDD') : '', end: end_time ? dateFormat(end_time, 'YYYYMMDD') : '', dep_name: row.dep_name, status } });
  522. },
  523. },
  524. };
  525. </script>
  526. <style lang="scss" scoped>
  527. .box {
  528. padding: 0 16px 16px 16px;
  529. .box_wrapper {
  530. padding: 16px;
  531. background: #fff;
  532. border-radius: 5px;
  533. overflow-x: hidden;
  534. overflow-y: auto;
  535. }
  536. }
  537. .filter-tree {
  538. margin-top: 16px;
  539. ::v-deep .el-tree-node__content {
  540. height: 36px;
  541. line-height: 36px;
  542. }
  543. }
  544. .rank-box {
  545. margin-bottom: 20px;
  546. }
  547. .table-box {
  548. .link {
  549. color: #409eff;
  550. font-weight: 600;
  551. cursor: pointer;
  552. }
  553. }
  554. ::v-deep.el-table .el-table__header tr th {
  555. background: #f1f6ff;
  556. color: #13171e;
  557. border-bottom: 0px;
  558. }
  559. ::v-deep.el-table .el-table__row td {
  560. color: #7e8bab;
  561. border-bottom: 1px solid #f4f4f4;
  562. }
  563. ::v-deep.el-table .el-table__header tr th:first-child {
  564. border-radius: 5px 0px 0px 5px;
  565. }
  566. ::v-deep.el-table .el-table__header tr th:nth-child(3) {
  567. border-radius: 0px 5px 5px 0px;
  568. }
  569. </style>