Explorar o código

fix: 耗材预估

Tong %!s(int64=2) %!d(string=hai) anos
pai
achega
a0516bd157

+ 31 - 0
src/api/biz/inventory/estimateApi.ts

@@ -0,0 +1,31 @@
+import { defHttp } from '/@/utils/http/axios';
+import { setParams } from '/@/utils/index';
+
+enum Api {
+  estimateWardList = '/biz/consumableEstimate/estimate/ward',
+  estimateInWardList = '/biz/consumableEstimate/estimate/inWard',
+  estimatePrint = '/biz/consumableEstimate/statistics/query',
+  wardAndNumber = '/biz/consumableEstimate/wardAndNumber',
+}
+
+// 病区一级列表
+export const getestimateWardList = (params?: object) => {
+  return defHttp.post({ url: Api.estimateWardList, params: setParams(params) });
+};
+// 病区内二级列表
+export const getestimateInWardList = (params?: object) => {
+  return defHttp.post({ url: Api.estimateInWardList, params: setParams(params) });
+};
+
+// 病区内二级列表
+export const getWardAndNumber = () => {
+  return defHttp.get({ url: Api.wardAndNumber });
+};
+
+/**
+ * @description: 耗材统计单
+ * @method: POST
+ */
+export const estimatePrint = (params: object) => {
+  return defHttp.post({ url: Api.estimatePrint, params: params });
+};

+ 72 - 0
src/views/biz/inventory/estimate/data.ts

@@ -0,0 +1,72 @@
+import { BasicColumn } from '/@/components/Table';
+
+export const columns: BasicColumn[] = [
+  {
+    title: '病区',
+    dataIndex: 'inpatientWardName',
+    width: 100,
+  },
+  {
+    title: '透析器',
+    dataIndex: 'dialyzer',
+  },
+  {
+    title: '穿刺针',
+    dataIndex: 'punctureNeedle',
+  },
+  {
+    title: '导管',
+    dataIndex: 'conduit',
+  },
+  {
+    title: '抗凝剂',
+    dataIndex: 'drug',
+  },
+  {
+    title: '血管通路',
+    dataIndex: 'vascularAccess',
+  },
+];
+
+export const innerColumns: BasicColumn[] = [
+  {
+    title: '患者姓名',
+    dataIndex: 'name',
+  },
+  {
+    title: '床号',
+    dataIndex: 'badName',
+  },
+  {
+    title: '透析液流量',
+    dataIndex: 'flowRate',
+  },
+  {
+    title: '透析模式',
+    dataIndex: 'dialysisType',
+  },
+  {
+    title: '透析器',
+    dataIndex: 'dialyzer',
+  },
+  {
+    title: '透析时长',
+    dataIndex: 'dialysisTime',
+  },
+  {
+    title: '穿刺针',
+    dataIndex: 'punctureNeedle',
+  },
+  {
+    title: '导管',
+    dataIndex: 'conduit',
+  },
+  {
+    title: '抗凝剂',
+    dataIndex: 'supplies',
+  },
+  {
+    title: '血管通路',
+    dataIndex: 'vascularAccess',
+  },
+];

+ 271 - 0
src/views/biz/inventory/estimate/index.vue

@@ -0,0 +1,271 @@
+<template>
+  <div class="m-4 modals">
+    <div>
+      <XTTitle title="耗材预估" :right-data="titleData" @click="callTitleClick" />
+      <div class="flex items-center justify-between my-4">
+        <XTTab
+          type="illness"
+          :width="180"
+          :selected="tabSelected"
+          :data="typeOptions"
+          @item-click="callTab"
+        />
+        <XTForm :form-data="formData" @change="callForm" />
+      </div>
+    </div>
+    <BasicTable @register="registerTable">
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'dialyzer'">
+          <div v-for="(item, index) in record.consumable.dialyzer" :key="index">
+            {{ item.name + ':' + item.count + item.unit }}</div
+          >
+        </template>
+        <template v-if="column.key === 'punctureNeedle'">
+          <div v-for="(item, index) in record.consumable.punctureNeedle" :key="index">
+            {{ item.name + ':' + item.count + item.unit }}</div
+          >
+        </template>
+        <template v-if="column.key === 'conduit'">
+          <div v-for="(item, index) in record.consumable.conduit" :key="index">
+            {{ item.name + ':' + item.count + item.unit }}</div
+          >
+        </template>
+        <template v-if="column.key === 'drug'">
+          <div v-for="(item, index) in record.drug" :key="index">
+            {{ item.name + ':' + item.count + item.unit }}</div
+          >
+        </template>
+        <template v-if="column.key === 'vascularAccess'">
+          <div v-for="(item, index) in record.vascularAccess" :key="index">{{
+            item.name + ':' + item.count + item.unit
+          }}</div>
+        </template>
+      </template>
+      <template #expandedRowRender>
+        <BasicTable @register="registerTableInner">
+          <template #bodyCell="{ column, record }">
+            <template v-if="column.key === 'dialyzer'">
+              <div v-for="(item, index) in record.suppliesByType.dialyzer" :key="index">
+                {{ item.name + ':' + item.count + item.unit }}</div
+              >
+            </template>
+            <template v-if="column.key === 'punctureNeedle'">
+              <div v-for="(item, index) in record.suppliesByType.punctureNeedle" :key="index">
+                {{ item.name + ':' + item.count + item.unit }}</div
+              >
+            </template>
+            <template v-if="column.key === 'conduit'">
+              <div v-for="(item, index) in record.suppliesByType.conduit" :key="index">
+                {{ item.name + ':' + item.count + item.unit }}</div
+              >
+            </template>
+            <template v-if="column.key === 'supplies'">
+              <div v-for="(item, index) in record.supplies" :key="index">
+                {{ item.name + ':' + item.count + item.unit }}</div
+              >
+            </template>
+          </template>
+        </BasicTable>
+      </template>
+      <template #expandIcon>
+        <Icon icon="icon-right|iconfont" :size="14" />
+      </template>
+    </BasicTable>
+    <PrintModal @register="registerModal" />
+  </div>
+</template>
+<script lang="ts" setup>
+  import { onBeforeMount, ref } from 'vue';
+  import { BasicTable, useTable } from '/@/components/TableCard';
+  import { columns, innerColumns } from './data';
+  import {
+    getestimateWardList,
+    getWardAndNumber,
+    getestimateInWardList,
+  } from '/@/api/biz/inventory/estimateApi';
+
+  import Icon from '/@/components/Icon';
+  import { XTTitle } from '/@/components/XTTitle/index';
+  import { XTTab } from '/@/components/XTTab/index';
+  import { useModal } from '/@/components/Modal';
+  import PrintModal from './printModal.vue';
+  import { XTForm } from '/@/components/XTForm/index';
+  import dayjs from 'dayjs';
+
+  // 标题数据
+  const titleData = [
+    {
+      type: 'print',
+      icon: 'icon-xt-print_default',
+    },
+  ];
+  // formdata
+  const formData = [
+    {
+      name: 'shiftDate',
+      componentType: 'DatePicker',
+      format: 'YYYY-MM-DD',
+      valueFormat: 'YYYY-MM-DD',
+      placeholder: '请选择日期',
+      width: 240,
+      defaultValue: dayjs().format('YYYY-MM-DD'),
+    },
+    {
+      name: 'searchNames',
+      componentType: 'Input',
+      prefix: 'icon-xt-search',
+      placeholder: '请输入耗材名称',
+      width: 240,
+    },
+  ];
+  // tab 切换选中
+  const tabSelected = ref();
+  // 操作名称
+  const searchNames = ref('');
+  const shiftDate = ref([]);
+  const typeOptions = ref();
+  const innerTableList = ref([] as any);
+  const innerTableOpen = ref(false);
+
+  const [registerModal, { openModal }] = useModal();
+  onBeforeMount(async () => {
+    getTab();
+  });
+
+  const tableSort = ref([
+    {
+      field: 'create_time',
+      direction: 'DESC',
+    },
+  ]) as any;
+
+  const [registerTable, { reload, collapseAll }] = useTable({
+    api: getestimateWardList,
+    rowKey: 'inpatientWardId',
+    isTreeTable: true,
+    expandRowByClick: true,
+    columns,
+    showIndexColumn: false,
+    bordered: true,
+    onExpand: handleExpand,
+    beforeFetch: handleBeforeFetch,
+  });
+
+  const [registerTableInner, { setTableData }] = useTable({
+    // , { reload: reloadInner }
+    dataSource: innerTableList,
+    rowKey: 'inpatientWardId',
+    columns: innerColumns,
+    showIndexColumn: true,
+    bordered: true,
+    pagination: false,
+  });
+
+  // 新增按钮事件
+  function callTitleClick(data) {
+    if (data.type == 'print') {
+      console.log('打印中...');
+      openModal(true, {
+        suppliesName: searchNames.value == '' ? undefined : searchNames.value,
+        partWardId: tabSelected.value == '' ? undefined : tabSelected.value,
+        time: shiftDate.value.length <= 0 ? dayjs().format('YYYY-MM-DD') : shiftDate.value,
+      });
+    }
+  }
+
+  // 表格请求之前,对参数进行处理, 添加默认 排序
+  async function handleBeforeFetch(params) {
+    return {
+      ...params,
+      orders: tableSort.value,
+      suppliesName: searchNames.value == '' ? undefined : searchNames.value,
+      partWardId: tabSelected.value == '' ? undefined : tabSelected.value,
+      time: shiftDate.value.length <= 0 ? dayjs().format('YYYY-MM-DD') : shiftDate.value,
+    };
+  }
+  // 点击一级展示二级数据
+  async function handleExpand(expandedRows, record) {
+    if (expandedRows) {
+      const params = {
+        pageNum: 1,
+        pageSize: 999,
+        suppliesName: searchNames.value == '' ? undefined : searchNames.value,
+        partWardId: record.inpatientWardId,
+        time: shiftDate.value.length <= 0 ? dayjs().format('YYYY-MM-DD') : shiftDate.value,
+      };
+      const resList = await getestimateInWardList(params);
+      if (resList) {
+        innerTableList.value = resList;
+        setTableData(resList);
+      }
+      innerTableOpen.value = true;
+    }
+  }
+
+  // 切换病区事件
+  async function getTab() {
+    const typeNums = await getWardAndNumber(); // 获取各类型数量
+    const typeList = [];
+    typeNums.forEach(item => {
+      typeList.push({
+        key: item.inpatientWardId ? item.inpatientWardId : '',
+        label: item.inpatientWardName ? item.inpatientWardName : '全部',
+        value: item.arrangedNumber,
+        hasValue: true,
+        hasBracket: true,
+        toolTipTitle: '已排床:' + item.arrangedNumber + ' 空床位:' + item.emptyNumber,
+      });
+    });
+    typeOptions.value = typeList;
+    tabSelected.value = typeOptions.value[0].key;
+  }
+  // 选项卡组件回调
+  async function callTab(data) {
+    tabSelected.value = data.value;
+    await reload();
+    if (innerTableOpen.value) {
+      await collapseAll();
+    }
+  }
+
+  // 查询组件回调
+  async function callForm(data) {
+    shiftDate.value = data.shiftDate ? data.shiftDate : '';
+    searchNames.value = data.searchNames ? data.searchNames : '';
+    console.log('callForm:::', searchNames.value);
+    await reload();
+    if (innerTableOpen.value) {
+      await collapseAll();
+    }
+  }
+</script>
+<style lang="less" scoped>
+  .table-dot {
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    margin-right: 6px;
+    border-radius: 50%;
+  }
+
+  ::v-deep(.ant-btn-link) {
+    color: #3d4155;
+  }
+
+  ::v-deep(.ant-input-prefix) {
+    color: #8a99ac;
+  }
+
+  .colUpdateAvatar {
+    display: flex;
+    justify-content: center;
+    text-align: center;
+    line-height: 28px;
+  }
+
+  .colImg {
+    width: 28px;
+    height: 28px;
+    margin-right: 5px;
+  }
+</style>

+ 70 - 0
src/views/biz/inventory/estimate/printModal.vue

@@ -0,0 +1,70 @@
+<template>
+  <div class="modals">
+    <BasicModal
+      v-bind="$attrs"
+      destroyOnClose
+      @register="registerModal"
+      :title="getTitle"
+      @ok="handleSubmit"
+      okText="打印"
+      :width="600"
+      @cancel="handleCancel"
+    >
+      <div class="!pl-8 !pt-4 !pr-8" ref="printCard">
+        <div class="printTitle">耗材统计单</div>
+        <a-divider />
+        <div class="printRow" v-for="(item, index) in fromDatas" :key="index">
+          <div>{{ item.name }}</div>
+          <div>{{ item.count + item.unit }}</div>
+        </div>
+      </div>
+    </BasicModal>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { ref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+
+  import { estimatePrint } from '/@/api/biz/inventory/estimateApi';
+
+  const getTitle = ref('耗材统计单');
+  const fromDatas = ref([] as any);
+  const [registerModal, { closeModal }] = useModalInner(async data => {
+    console.log('datas:::', data);
+    const params = {
+      partWardId: data.partWardId,
+      time: data.time,
+      suppliesName: data.suppliesName,
+    };
+    fromDatas.value = await estimatePrint(params);
+  });
+
+  // 提交按钮事件
+  async function handleSubmit() {
+    console.log('print.......');
+  }
+  async function handleCancel() {
+    closeModal();
+  }
+</script>
+<style lang="less" scoped>
+  ::v-deep(.ant-modal) {
+    background-color: #000;
+  }
+
+  .printTitle {
+    font-size: 52px;
+    font-weight: 600;
+    text-align: center;
+    color: #000a18;
+  }
+
+  .printRow {
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+    font-size: 26px;
+    font-weight: 500;
+    color: #000a18;
+  }
+</style>