|
@@ -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>
|