Browse Source

feat: 耗材用量统计完成

Tong 2 years ago
parent
commit
3d2ba235e3

+ 16 - 0
src/api/biz/stats/suppliesStatsApi.ts

@@ -2,6 +2,8 @@ import { defHttp } from '/@/utils/http/axios';
 
 enum Api {
   drugStats = '/biz/SuppliesStats/drugStats',
+  suppliesTypeStats = '/biz/SuppliesStats/typeStats',
+  suppliesMarksStats = '/biz/SuppliesStats/makersStats',
 }
 // 查询药品用量API
 export const getDrugStats = (params?: object) => {
@@ -10,3 +12,17 @@ export const getDrugStats = (params?: object) => {
     params,
   });
 };
+
+export const getSuppliesTypeStats = (params?: object) => {
+  return defHttp.post({
+    url: Api.suppliesTypeStats,
+    params,
+  });
+};
+
+export const getSuppliesMarksStats = (params?: object) => {
+  return defHttp.post({
+    url: Api.suppliesMarksStats,
+    params,
+  });
+};

+ 4 - 1
src/views/biz/stats/supplies/index.vue

@@ -12,7 +12,9 @@
           :class="'tab-' + item.key"
         >
           <!-- 耗材用量 0 -->
-          <div v-if="item.value == 0 && info.id"> 耗材用量 </div>
+          <div v-if="item.value == 0 && info.id">
+            <SuppliesStats />
+          </div>
           <!-- 药品用量 1 -->
           <div v-if="item.value == 1 && info.id">
             <PharmaceuticalsStats />
@@ -27,6 +29,7 @@
   import { ref } from 'vue';
   import { BasicTab, BasicTabActive } from './data';
   import PharmaceuticalsStats from './pharmaceuticalsStats/index.vue';
+  import SuppliesStats from './suppliesStats/index.vue';
   import { useRoute } from 'vue-router';
   import { XTTitle } from '/@/components/XTTitle/index';
 

+ 55 - 0
src/views/biz/stats/supplies/suppliesStats/data.ts

@@ -0,0 +1,55 @@
+import { BasicColumn } from '/@/components/Table';
+
+export const typeColumns: BasicColumn[] = [
+  {
+    title: '耗材类型',
+    dataIndex: 'type',
+    align: 'left',
+  },
+  {
+    title: '数量',
+    dataIndex: 'sum',
+    align: 'left',
+  },
+  {
+    title: '占比',
+    dataIndex: 'proportion',
+    align: 'left',
+  },
+];
+
+export const marksColumns: BasicColumn[] = [
+  {
+    title: '耗材厂商',
+    dataIndex: 'type',
+    align: 'left',
+  },
+  {
+    title: '数量',
+    dataIndex: 'sum',
+    align: 'left',
+  },
+  {
+    title: '占比',
+    dataIndex: 'proportion',
+    align: 'left',
+  },
+];
+
+export const detailColumns: BasicColumn[] = [
+  {
+    title: '药品名称',
+    dataIndex: 'type',
+    align: 'left',
+  },
+  {
+    title: '数量',
+    dataIndex: 'sum',
+    align: 'left',
+  },
+  {
+    title: '占比',
+    dataIndex: 'proportion',
+    align: 'left',
+  },
+];

+ 246 - 0
src/views/biz/stats/supplies/suppliesStats/index.vue

@@ -0,0 +1,246 @@
+<template>
+  <div class="flex items-center xt-form">
+    <XTForm :form-data="formData" @change="callForm" />
+    <Button type="default" @click="handleDownload"
+      ><Icon icon="icon-xt-download-download_default|iconfont" :size="14" />
+    </Button>
+  </div>
+  <!-- 耗材类型统计 -->
+  <div class="mb-4">
+    <XTTitle :title="typeTitle" :go-back="false" />
+  </div>
+  <Row style="max-height: 400px">
+    <Col :span="16">
+      <Pie :data="typePieData" />
+    </Col>
+    <Col :span="8">
+      <BasicTable @register="registerTypeTable">
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'type'">
+            <span> {{ formatDictValue(suppliesTypeOptions, record.type) }}</span>
+          </template>
+        </template>
+      </BasicTable>
+    </Col>
+  </Row>
+  <!-- 耗材厂商统计 -->
+  <div class="mb-4">
+    <XTTitle :title="makerTitle" :go-back="false" />
+  </div>
+  <Row style="max-height: 400px">
+    <Col :span="16">
+      <Pie :data="marksPieData" />
+    </Col>
+    <Col :span="8">
+      <BasicTable @register="registerMarksTable">
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'sum'">
+            <a @click="handleDetail(record)">{{ record.sum }}</a>
+          </template>
+        </template>
+      </BasicTable>
+    </Col>
+  </Row>
+  <!-- 底部详情统计 -->
+  <Row style="max-height: 200px">
+    <Col :span="24">
+      <BasicTable @register="registerDetailTable">
+        <template #headerCell="{ column }">
+          <template v-if="column.key === 'type'"> {{ detailName }} </template>
+          <template v-if="column.key === 'sum'"> 数量 </template>
+          <template v-if="column.key === 'proportion'"> 占比 </template>
+        </template>
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'type'">
+            <span> {{ formatDictValue(suppliesTypeOptions, record.type) }}</span>
+          </template>
+        </template>
+      </BasicTable>
+    </Col>
+  </Row>
+</template>
+
+<script setup lang="ts">
+  import { onMounted, ref } from 'vue';
+  import { Row, Col, Button } from 'ant-design-vue';
+  import { XTForm } from '/@/components/XTForm/index';
+  import { XTTitle } from '/@/components/XTTitle/index';
+  import { getSuppliesTypeStats, getSuppliesMarksStats } from '/@/api/biz/stats/suppliesStatsApi';
+  import { BasicTable, useTable } from '@/components/Table';
+  import { typeColumns, marksColumns, detailColumns } from './data';
+  import { Icon } from '/@/components/Icon';
+  import { formatDictValue } from '/@/utils';
+  import { listDictModel } from '/@/api/common';
+  import Pie from '../../chart/pie.vue';
+  // formdata
+  const typeTitle = ref('耗材类型统计'); // 耗材类型统计
+  const makerTitle = ref('耗材厂商统计'); // 耗材厂商统计
+  const typePieData = ref({} as any); // Echart图表组件赋值变量
+  const marksPieData = ref({} as any); // Echart图表组件赋值变量
+  const typeTableData = ref([]); // 药品类型统计数据
+  const marksTableData = ref([]); // 耗材厂商统计数据
+  const detailTableData = ref([]); // 详情统计类型数据
+  const patrolTime = ref([]); // 时间查询参数
+  const detailName = ref('');
+  const formData = [
+    {
+      name: 'patrolTime',
+      componentType: 'RangePicker',
+      placeholder: '请选择维修时间',
+      format: 'YYYY-MM-DD',
+      valueFormat: 'YYYY-MM-DD',
+    },
+    {},
+  ];
+  // 耗材类型统计表格配置
+  const [registerTypeTable, { setTableData: setTypeTable }] = useTable({
+    showIndexColumn: false,
+    bordered: true,
+    striped: false,
+    showSummary: true,
+    summaryFunc: handleSummary,
+    pagination: false,
+    maxHeight: 200,
+    dataSource: typeTableData.value,
+    columns: typeColumns,
+  });
+
+  // 耗材厂商统计表格配置
+  const [registerMarksTable, { setTableData: setMarksTable }] = useTable({
+    showIndexColumn: false,
+    bordered: true,
+    showSummary: true,
+    summaryFunc: handleSummary,
+    striped: false,
+    pagination: false,
+    maxHeight: 200,
+    dataSource: marksTableData.value,
+    columns: marksColumns,
+  });
+
+  // 药品类型统计表格配置
+  const [registerDetailTable, { setTableData: setDetailTableData }] = useTable({
+    showIndexColumn: false,
+    bordered: true,
+    striped: false,
+    pagination: false,
+    maxHeight: 200,
+    dataSource: detailTableData.value,
+    columns: detailColumns,
+  });
+
+  const suppliesTypeOptions = ref();
+  onMounted(async () => {
+    suppliesTypeOptions.value = await listDictModel({ dictCode: 'ct' }); // 查询药品类型字典数据
+    getAllDatas(); // 执行获取统计数据方法
+  });
+
+  // 查询组件回调
+  async function callForm(data) {
+    patrolTime.value = data.patrolTime || [];
+    getAllDatas();
+  }
+  // 获取统计数据
+  async function getAllDatas() {
+    const params = {
+      statsTime: patrolTime.value,
+    };
+
+    // 获取设置耗材类型数据
+    const typeRes = await getSuppliesTypeStats(params); // 请求药品统计接口
+    typeTableData.value = typeRes.data;
+    await setTypeTable(typeRes.data); // 右侧统计数据表格赋值
+    // 组合Echart图表数据格式
+    const typeDataList = {
+      content: [],
+      description: typeTitle.value,
+    };
+    typeRes.data.forEach(item => {
+      typeDataList.content.push({
+        name: formatDictValue(suppliesTypeOptions.value, item.type),
+        value: item.sum,
+      });
+    });
+    typePieData.value = typeDataList; // Echart图表赋值
+
+    // 获取设置耗材厂商数据
+    const marksRes = await getSuppliesMarksStats(params); // 请求药品统计接口
+    marksTableData.value = marksRes.data;
+    await setMarksTable(marksRes.data); // 右侧统计数据表格赋值
+    // 组合Echart图表数据格式
+    const marksDataList = {
+      content: [],
+      description: typeTitle.value,
+    };
+    marksRes.data.forEach(item => {
+      marksDataList.content.push({
+        name: item.type,
+        value: item.sum,
+      });
+    });
+    marksPieData.value = marksDataList; // Echart图表赋值
+
+    // 默认耗材类型第一个为详情数据父级
+    handleDetail(marksTableData.value[0]);
+  }
+  // 统计下载事件
+  function handleDownload() {
+    console.log('下载按钮');
+  }
+
+  // 点击表格中数字
+  async function handleDetail(record) {
+    const params = {
+      statsTime: patrolTime.value,
+      makers: record.type,
+    };
+    const res = await getSuppliesTypeStats(params); // 请求药品统计接口
+    detailName.value = record.type;
+    await setDetailTableData(res.data);
+  }
+
+  function handleSummary(tableData: any[]) {
+    console.log(tableData);
+    let totalT5 = 0;
+    let totalT6 = 0;
+    tableData.forEach(item => {
+      totalT5 += item.sum;
+      totalT6 += parseFloat(parseFloat(item.proportion.split('%')[0]).toFixed(2));
+    });
+    return [
+      {
+        type: '总计',
+        sum: totalT5,
+        proportion: totalT6 + '%',
+      },
+    ];
+  }
+</script>
+
+<style lang="less" scoped>
+  ::v-deep(.xt-title) {
+    padding-left: 40px;
+    background-color: #f6f8fa;
+  }
+
+  .xt-form {
+    justify-content: flex-end;
+    margin-right: 20px;
+  }
+
+  ::v-deep(.ant-row) {
+    max-height: 460px;
+  }
+
+  ::v-deep(.ant-table-body) {
+    height: auto !important;
+  }
+
+  ::v-deep(.ant-table-footer) {
+    padding: 0 !important;
+
+    .ant-table-tbody {
+      background-color: #f6f8fa !important;
+    }
+  }
+</style>