Kaynağa Gözat

Merge branch 'master' of http://192.168.100.32:3000/fanfan/xt-front

lxz 2 yıl önce
ebeveyn
işleme
49f08166cc

+ 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 });
+};

+ 40 - 0
src/api/biz/mission/articleApi.ts

@@ -0,0 +1,40 @@
+import { defHttp } from '/@/utils/http/axios';
+
+import { setParams } from '/@/utils/index';
+
+enum Api {
+  articleNumber = '/biz/educationLibrary/statusNumber',
+  articleStatus = '/biz/educationLibrary/status',
+  articleList = '/biz/educationLibrary/query/page',
+  articleDel = '/biz/educationLibrary/removeByIds',
+  articleAdd = 'biz/educationLibrary/add',
+  articleEdit = '/biz/educationLibrary/edit',
+  articleById = '/biz/educationLibrary/detail',
+}
+
+export const articleList = (params?: object) => {
+  return defHttp.post({ url: Api.articleList, params: setParams(params) });
+};
+
+export const articleStatus = (id?: String) => {
+  return defHttp.get({ url: Api.articleStatus + '/' + id });
+};
+
+export const articleDel = (params?: object) => {
+  return defHttp.post({ url: Api.articleDel, params: params });
+};
+export const articleNumber = () => {
+  return defHttp.get({ url: Api.articleNumber });
+};
+
+export const articleAdd = (params?: object) => {
+  return defHttp.post({ url: Api.articleAdd, params: params });
+};
+
+export const articleEdit = (params?: object) => {
+  return defHttp.post({ url: Api.articleEdit, params: params });
+};
+
+export const articleById = (id: string) => {
+  return defHttp.get({ url: Api.articleById + '/' + id });
+};

+ 26 - 0
src/api/biz/mission/recordApi.ts

@@ -0,0 +1,26 @@
+import { defHttp } from '/@/utils/http/axios';
+
+import { setParams } from '/@/utils/index';
+
+enum Api {
+  recordNumber = '/biz/educationRecord/statusNumber',
+  recordList = '/biz/educationRecord/query/page',
+  recordDel = '/biz/educationRecord/removeByIds',
+  recordAdd = 'biz/educationRecord/add',
+}
+
+export const getrecordList = (params?: object) => {
+  return defHttp.post({ url: Api.recordList, params: setParams(params) });
+};
+
+export const recordDel = (id?: String) => {
+  return defHttp.post({ url: Api.recordDel + '/' + id });
+};
+
+export const recordNumber = () => {
+  return defHttp.get({ url: Api.recordNumber });
+};
+
+export const recordAdd = (params?: object) => {
+  return defHttp.post({ url: Api.recordAdd, params: params });
+};

+ 29 - 111
src/api/biz/visit/checkApi.ts

@@ -2,132 +2,50 @@ import { defHttp } from '/@/utils/http/axios';
 import { setParams } from '/@/utils/index';
 
 enum Api {
-  archivesPatrolWardQueryPage = '/archives/patrolWard/query/page',
-  archivesPatrolWardDetail = '/archives/patrolWard/detail',
-  archivesPatrolWardAdd = '/archives/patrolWard/add',
-  archivesPatrolWardEdit = '/archives/patrolWard/edit',
-  archivesPatrolWardRemove = '/archives/patrolWard/removeByIds',
-  archivesPatrolWardQueryCheckRoomRecord = '/archives/patrolWard/queryCheckRoomRecord',
-  archivesPatrolWardQueryPersonNumber = '/archives/patrolWard/queryPersonNumber',
-  archivesPatrolWardFollowOrNo = '/archives/patrolWard/followOrNo',
+  checkQueryPage = '/archives/patrolWard/query/page',
+  checkDetail = '/archives/patrolWard/detail',
+  checkAdd = '/archives/patrolWard/add',
+  checkEdit = '/archives/patrolWard/edit',
+  checkRemove = '/archives/patrolWard/removeByIds',
+  checkQueryCheckRoomRecord = '/archives/patrolWard/queryCheckRoomRecord',
+  checkQueryPersonNumber = '/archives/patrolWard/queryPersonNumber',
+  checkFollowOrNo = '/archives/patrolWard/followOrNo',
 }
 
-/**
- *
- * @author  fan
- * @date  2023/06/30 17:39
- * @description: 根据条件查询查房列表,权限 - biz:patrolward:query
- * @method: POST
- * @param:
- *       {String}  updatorName     updator_name
- * @return:
- *       {String}  patientBasicId  基础病历id
- *       {String}  scheduledId  排床id
- *       {Date}  patrolTime  查房时间
- *       {String}  content  查房内容
- *       {String}  updatorName  updator_name
- */
-
-export const archivesPatrolWardQueryCheckRoomRecord = (params?: object) => {
+export const checkQueryCheckRoomRecord = (params?: object) => {
   return defHttp.post({
-    url: Api.archivesPatrolWardQueryCheckRoomRecord,
+    url: Api.checkQueryCheckRoomRecord,
     params: setParams(params),
   });
 };
-/**
- *
- * @author fan
- * @date  2023/06/30 17:39
- * @description: 根据条件查询查房列表,权限 - biz:patrolward:query
- * @method: POST
- * @param:
- *       {String}  updatorName     updator_name
- * @return:
- *       {String}  patientBasicId  基础病历id
- *       {String}  scheduledId  排床id
- *       {Date}  patrolTime  查房时间
- *       {String}  content  查房内容
- *       {String}  updatorName  updator_name
- */
 
-export const archivesPatrolWardQueryPage = (params?: object) => {
-  return defHttp.post({ url: Api.archivesPatrolWardQueryPage, params: setParams(params) });
+export const checkQueryPage = (params?: object) => {
+  return defHttp.post({
+    url: Api.checkQueryPage,
+    params: setParams(params),
+  });
 };
-/**
- *
- * @author fan
- * @date  2023/06/30 17:39
- * @description: 根据id查询查房详细信息,权限 - biz:patrolward:query
- * @method: GET
- * @param:  id 查房主键id
- * @return:
- *       {String}  patientBasicId  基础病历id
- *       {String}  scheduledId  排床id
- *       {Date}  patrolTime  查房时间
- *       {String}  content  查房内容
- *       {String}  updatorName  updator_name
- */
-export const archivesPatrolWardDetail = (id: string) => {
-  return defHttp.get({ url: Api.archivesPatrolWardDetail + '/' + id });
+
+export const checkDetail = (id: string) => {
+  return defHttp.get({ url: Api.checkDetail + '/' + id });
 };
 
-/**
- *
- * @author fan
- * @date  2023/06/30 17:39
- * @description: 添加查房,权限 - biz:patrolward:add
- * @method: POST
- * @param:
- *       {String}  patientBasicId  基础病历id
- *       {String}  scheduledId  排床id
- *       {Date}  patrolTime  查房时间
- *       {String}  content  查房内容
- * @return:
- *       0 添加失败
- *       1 添加成功
- */
-export const archivesPatrolWardAdd = (params?: object) => {
-  return defHttp.post({ url: Api.archivesPatrolWardAdd, params: params });
+export const checkAdd = (params?: object) => {
+  return defHttp.post({ url: Api.checkAdd, params: params });
 };
 
-/**
- *
- * @author fan
- * @date  2023/06/30 17:39
- * @description: 通过主键id编辑查房,权限 - biz:patrolward:edit
- * @method: POST
- * @param:
- *       {String}  patientBasicId  基础病历id
- *       {String}  scheduledId  排床id
- *       {Date}  patrolTime  查房时间
- *       {String}  content  查房内容
- * @return:
- *       0 编辑失败
- *       1 编辑成功
- */
-export const archivesPatrolWardEdit = (params?: object) => {
-  return defHttp.post({ url: Api.archivesPatrolWardEdit, params: params });
+export const checkEdit = (params?: object) => {
+  return defHttp.post({ url: Api.checkEdit, params: params });
 };
 
-/**
- * @description: 删除,权限 - biz:patrolward:remove
- * @method: POST
- */
-export const archivesPatrolWardRemove = (params: Array<string | number>) => {
-  return defHttp.post({ url: Api.archivesPatrolWardRemove, params: params });
+export const checkRemove = (params: Array<string | number>) => {
+  return defHttp.post({ url: Api.checkRemove, params: params });
 };
 
-/**
- * @description: 查房页面各条件人员数量,权限 - biz:patrolward:querypersonnumber
- * @method: get
- */
-export const archivesPatrolWardQueryPersonNumber = () => {
-  return defHttp.get({ url: Api.archivesPatrolWardQueryPersonNumber });
+export const checkQueryPersonNumber = () => {
+  return defHttp.get({ url: Api.checkQueryPersonNumber });
 };
-/**
- * @description: 关注或取消关注,权限 - biz:patrolward:followOrNo
- * @method: get
- */
-export const archivesPatrolWardFollowOrNo = () => {
-  return defHttp.post({ url: Api.archivesPatrolWardFollowOrNo });
+
+export const checkFollowOrNo = (id?: string) => {
+  return defHttp.post({ url: Api.checkFollowOrNo + '/' + id });
 };

+ 2 - 1
src/components/Form/src/componentMap.ts

@@ -41,6 +41,7 @@ import Cron from './components/Cron.vue';
 import FormColorPicker from './components/FormColorPicker.vue';
 import InputNumberGroup from './components/InputNumberGroup.vue';
 import RadioDescGroup from './components/RadioDescGroup.vue';
+import Editor from '@/components/Editor';
 
 const componentMap = new Map<ComponentType, Component>();
 
@@ -51,7 +52,7 @@ componentMap.set('InputSearch', Input.Search);
 componentMap.set('InputTextArea', Input.TextArea);
 componentMap.set('InputNumber', InputNumber);
 componentMap.set('AutoComplete', AutoComplete);
-
+componentMap.set('Editor', Editor);
 componentMap.set('Select', Select);
 componentMap.set('ApiComplex', ApiComplex);
 componentMap.set('ApiSelect', ApiSelect);

+ 1 - 0
src/components/Form/src/types/index.ts

@@ -81,6 +81,7 @@ export interface ColEx {
 }
 
 export type ComponentType =
+  | 'Editor'
   | 'Input'
   | 'InputGroup'
   | 'InputPassword'

+ 37 - 14
src/components/XTTab/src/XTTab.vue

@@ -12,20 +12,41 @@
         @click="handleClick(item)"
         :style="{ minWidth: width + 'px' }"
       >
-        <div
-          v-if="item.prefixColor"
-          class="tab-list_item-prefix"
-          :style="{ backgroundColor: item.prefixColor }"
-        />
-        <div :class="['tab-list_item-cnt']">
-          <span>{{ item.label }}</span>
-          <span
-            v-if="item.hasValue"
-            :style="{ color: selected == item.key ? '#ffffff' : item.valueColor || '#273240' }"
-          >
-            <span v-if="item.hasBracket">({{ item.value }})</span>
-          </span>
-        </div>
+        <a-tooltip placement="top" v-if="item.toolTipTitle">
+          <template #title>
+            <span>{{ item.toolTipTitle }}</span>
+          </template>
+          <div
+            v-if="item.prefixColor"
+            class="tab-list_item-prefix"
+            :style="{ backgroundColor: item.prefixColor }"
+          />
+          <div :class="['tab-list_item-cnt']">
+            <span>{{ item.label }}</span>
+            <span
+              v-if="item.hasValue"
+              :style="{ color: selected == item.key ? '#ffffff' : item.valueColor || '#273240' }"
+            >
+              <span v-if="item.hasBracket">({{ item.value }})</span>
+            </span>
+          </div>
+        </a-tooltip>
+        <template v-else>
+          <div
+            v-if="item.prefixColor"
+            class="tab-list_item-prefix"
+            :style="{ backgroundColor: item.prefixColor }"
+          />
+          <div :class="['tab-list_item-cnt']">
+            <span>{{ item.label }}</span>
+            <span
+              v-if="item.hasValue"
+              :style="{ color: selected == item.key ? '#ffffff' : item.valueColor || '#273240' }"
+            >
+              <span v-if="item.hasBracket">({{ item.value }})</span>
+            </span>
+          </div>
+        </template>
       </div>
     </div>
   </div>
@@ -57,6 +78,8 @@
       prefixColor?: string | unknown;
       // 后缀值颜色
       valueColor?: string | unknown;
+      // 标头提示内容
+      toolTipTitle?: string | unknown;
     }>;
   }
   const props = withDefaults(defineProps<Props>(), {

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

+ 81 - 0
src/views/biz/mission/article/data.ts

@@ -0,0 +1,81 @@
+import { BasicColumn, FormSchema } from '/@/components/Table';
+import { listDictModel, uploadApi } from '/@/api/common';
+
+export const columns: BasicColumn[] = [
+  {
+    title: '封面',
+    dataIndex: 'cover',
+  },
+  {
+    title: '标题',
+    dataIndex: 'title',
+  },
+  {
+    title: '分类',
+    dataIndex: 'type',
+  },
+  {
+    title: '上传时间',
+    dataIndex: 'updateTime',
+  },
+  {
+    title: '上传人',
+    dataIndex: 'updatorName',
+  },
+  {
+    title: '状态',
+    dataIndex: 'disable',
+  },
+];
+// 表单新增编辑
+export const dataFormSchema: FormSchema[] = [
+  {
+    label: '宣教标题',
+    field: 'title',
+    component: 'Input',
+    componentProps: {},
+  },
+  {
+    label: '宣教分类',
+    field: 'type',
+    required: true,
+    component: 'ApiSelect',
+    componentProps: {
+      api: listDictModel,
+      params: {
+        dictCode: 'het',
+      },
+      placeholder: '请选择宣教分类',
+    },
+  },
+
+  {
+    label: '封面',
+    field: 'cover',
+    component: 'XTUpload',
+    componentProps: ({ formModel, schema }) => {
+      return {
+        api: uploadApi,
+        maxSize: 10,
+        maxNumber: 5,
+        helpText: '仅支持上传jpg/png/pdf文件,文件大小不超过2M',
+        accept: ['image/*', '.pdf', '.doc', 'docx', 'xls'],
+        onChange: data => {
+          console.log('🚀 ~ file: data.ts:57 ~ data:', data);
+          formModel[schema.field] = data;
+        },
+      };
+    },
+    colProps: {
+      span: 22,
+    },
+  },
+  {
+    label: '宣教内容',
+    field: 'content',
+    component: 'Editor',
+    colProps: {
+      span: 24,
+    },
+  },
+];

+ 77 - 0
src/views/biz/mission/article/formDrawer.vue

@@ -0,0 +1,77 @@
+<template>
+  <div class="modals">
+    <BasicDrawer
+      v-bind="$attrs"
+      destroyOnClose
+      @register="registerDrawer"
+      :title="getTitle"
+      @ok="handleSubmit"
+      :width="780"
+      :showFooter="true"
+    >
+      <div class="!pl-8 !pt-4">
+        <BasicForm @register="registerForm" />
+      </div>
+    </BasicDrawer>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { ref, computed, unref } from 'vue';
+  import { BasicForm, useForm } from '/@/components/Form';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { dataFormSchema } from './data';
+
+  import { articleAdd, articleById, articleEdit } from '/@/api/biz/mission/articleApi';
+  import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
+
+  const emit = defineEmits(['success', 'register']);
+
+  const getTitle = computed(() => (!unref(isUpdate) ? '新增宣教' : '编辑宣教'));
+  const isUpdate = ref(false);
+  const rowId = ref();
+
+  const { createMessage } = useMessage();
+  const [registerForm, { resetFields, validate, setFieldsValue }] = useForm({
+    layout: 'vertical',
+    showResetButton: true,
+    labelWidth: 100,
+    schemas: dataFormSchema,
+    showActionButtonGroup: false,
+    actionColOptions: {
+      span: 24,
+    },
+    baseColProps: {
+      span: 12,
+    },
+  });
+  const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async data => {
+    await resetFields();
+    setDrawerProps({ confirmLoading: false });
+    isUpdate.value = !!data?.isUpdate;
+
+    if (unref(isUpdate)) {
+      rowId.value = data.record.id;
+      const resData = await articleById(data.record.id);
+      console.log('resData::::', resData);
+      await setFieldsValue({
+        ...resData,
+      });
+    }
+  });
+
+  // 提交按钮事件
+  async function handleSubmit() {
+    try {
+      const values = await validate();
+      setDrawerProps({ confirmLoading: true });
+      !unref(isUpdate)
+        ? await articleAdd({ ...values })
+        : await articleEdit({ ...values, id: rowId.value });
+      !unref(isUpdate) ? createMessage.success('新增成功!') : createMessage.success('编辑成功!');
+      closeDrawer();
+      emit('success', { isUpdate: unref(isUpdate), values: { ...values, id: rowId.value } });
+    } finally {
+      setDrawerProps({ confirmLoading: false });
+    }
+  }
+</script>

+ 318 - 3
src/views/biz/mission/article/index.vue

@@ -1,7 +1,322 @@
 <template>
-  <div> 占位符 </div>
+  <div class="m-4 modals">
+    <div>
+      <XTTitle title="宣教库" :right-data="titleData" @click="callTitleClick" />
+      <div class="flex items-center justify-between my-4">
+        <XTTab
+          type="article"
+          :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 === 'disable'">
+          <span
+            :class="['table-dot']"
+            :style="{ backgroundColor: formatDictPreColor(responseDisableOptions, record.disable) }"
+          />
+          <span> {{ formatDictValue(responseDisableOptions, record.disable) }}</span>
+        </template>
+        <template v-if="column.key === 'type'">
+          <span> {{ formatDictValue(responseTypeOptions, record.type) }}</span>
+        </template>
+        <template v-if="column.key === 'action'">
+          <TableAction
+            :actions="[
+              {
+                auth: 'biz:educationLibrary:edit',
+                icon: 'icon-xt-details_edit_default|iconfont',
+                tooltip: '编辑',
+                onClick: handleEdit.bind(null, record),
+              },
+              {
+                auth: 'biz:education:edit',
+                icon: 'icon-tingyong-moren|iconfont',
+                tooltip: '停用',
+                ifShow: record.disable === 0,
+                popConfirm: {
+                  title: '是否确认停用',
+                  placement: 'left',
+                  confirm: handleClick.bind(null, record),
+                },
+              },
+              {
+                auth: 'biz:education:edit',
+                icon: 'icon-xt-revocation_default|iconfont',
+                tooltip: '启用',
+                ifShow: record.disable === 1,
+                popConfirm: {
+                  title: '是否确认启用',
+                  placement: 'left',
+                  confirm: handleClick.bind(null, record),
+                },
+              },
+              {
+                auth: 'biz:educationLibrary:remove',
+                icon: 'icon-xt-details_delete_default|iconfont',
+                tooltip: '删除',
+                onClick: handleDelete.bind(null, record),
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+    <FormDrawer @register="registerDrawer" @success="callSuccess" @cancel="handleCancel" />
+    <ImportModal @register="registerImpModal" />
+  </div>
 </template>
+<script lang="ts" setup>
+  import { onBeforeMount, ref } from 'vue';
+  import { BasicTable, useTable, TableAction } from '/@/components/TableCard';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import FormDrawer from './formDrawer.vue';
+  import { ImportModal } from '/@/components/XTImport/index';
 
-<script setup lang="ts"></script>
+  import { formatDictValue, formatDictPreColor } from '/@/utils';
+  import { columns } from './data';
 
-<style lang="less" scoped></style>
+  import {
+    articleList,
+    articleStatus,
+    articleNumber,
+    articleDel,
+  } from '/@/api/biz/mission/articleApi';
+  import { listDictModel } from '/@/api/common';
+  // import { useModal } from '/@/components/Modal';
+  import { XTTitle } from '/@/components/XTTitle/index';
+  import { XTTab } from '/@/components/XTTab/index';
+  import { XTForm } from '/@/components/XTForm/index';
+  import { useDrawer } from '@/components/Drawer';
+  import { useModal } from '@/components/Modal';
+
+  // 标题数据
+  const titleData = [
+    {
+      type: 'print',
+      icon: 'icon-xt-print_default',
+    },
+    {
+      type: 'import',
+      auth: ['archives:drug:import'],
+      icon: 'icon-xt-import_default',
+    },
+    {
+      type: 'add',
+      auth: ['biz:drug:add'],
+      btnIcon: 'icon-xt-add_default',
+      btnText: '新增宣教',
+    },
+  ];
+  // formdata
+  const formData = [
+    {
+      name: 'tableSort',
+      componentType: 'Select',
+      placeholder: '请选择',
+      width: 120,
+      defaultValue: 'patrolTime',
+      dicts: [
+        { label: '全部', value: 'patrolTime' },
+        { label: '正常', value: 'disable ="0"' },
+        { label: '停用', value: 'disable ="1"' },
+      ],
+    },
+    {
+      name: 'title',
+      componentType: 'Input',
+      prefix: 'icon-xt-search',
+      placeholder: '请输入宣教标题',
+      width: 240,
+    },
+  ];
+  // tab 切换选中
+  const tabSelected = ref();
+  // 操作名称
+  const searchNames = ref('');
+  const shiftDate = ref([]);
+
+  const typeOptions = ref();
+  const responseDisableOptions = ref();
+  const responseTypeOptions = ref();
+  onBeforeMount(async () => {
+    responseDisableOptions.value = await listDictModel({ dictCode: 'sys_disable_type' });
+    responseTypeOptions.value = await listDictModel({ dictCode: 'het' });
+    getTab();
+  });
+
+  const { createMessage } = useMessage();
+  const [registerDrawer, { openDrawer }] = useDrawer();
+  const [registerImpModal, { openModal: openImpModal }] = useModal();
+
+  // const tableSort = ref([
+  //   {
+  //     field: 'create_time',
+  //     direction: 'DESC',
+  //   },
+  // ]) as any;
+
+  const [registerTable, { reload, clearSelectedRowKeys }] = useTable({
+    api: articleList,
+    batchDelApi: articleStatus,
+    // batchExportApi: pharmaceuticalsExport,
+    delAuthList: ['biz:educationLibrary:remove'],
+    rowKey: 'id',
+    columns,
+    showIndexColumn: true,
+    bordered: true,
+    actionColumn: {
+      width: 200,
+      title: '操作',
+      dataIndex: 'action',
+    },
+    beforeFetch: handleBeforeFetch,
+  });
+
+  // 编辑按钮事件
+  function handleEdit(record) {
+    openDrawer(true, {
+      record,
+      isUpdate: true,
+    });
+  }
+
+  // 新增按钮事件
+  function callTitleClick(data) {
+    if (data.type == 'add') {
+      openDrawer(true, {
+        isUpdate: false,
+        record: data,
+      });
+    } else if (data.type == 'print') {
+      console.log('打印中...');
+    } else if (data.type == 'import') {
+      openImpModal(true, {
+        title: '导入宣教',
+      });
+    }
+  }
+
+  // 删除按钮事件
+  async function handleDelete(record: Recordable) {
+    console.log('🚀 ~ file: index.vue:141 ~ handleDelete ~ record', record);
+    await articleDel([record.id]);
+    createMessage.success('删除成功!');
+    await reload();
+  }
+  // 启用停用按钮事件
+  async function handleClick(record: Recordable) {
+    if (record) {
+      await articleStatus(record.id);
+      createMessage.success('停用成功!');
+      clearSelectedRowKeys();
+      await reload();
+      await getTab();
+    }
+  }
+
+  // 表格请求之前,对参数进行处理, 添加默认 排序
+  async function handleBeforeFetch(params) {
+    console.log('searchNames:::', searchNames.value);
+    return {
+      ...params,
+      // orders: tableSort.value,
+      name: searchNames.value == '' ? undefined : searchNames.value,
+      status: tabSelected.value == '' ? undefined : tabSelected.value,
+      time: shiftDate.value.length <= 0 ? undefined : shiftDate.value,
+    };
+  }
+
+  async function getTab() {
+    typeOptions.value = await listDictModel({ dictCode: 'sys_disable_type' });
+    const typeNums = await articleNumber(); // 获取各类型数量
+    let typeList = [];
+    typeOptions.value.forEach(ele => {
+      // 变量各类型放置对应数量
+      let typeData = {};
+      Object.keys(typeNums).forEach(numKey => {
+        if (ele.value == numKey) {
+          typeData = {
+            key: ele.value,
+            label: ele.label,
+            value: typeNums[numKey],
+            hasValue: true,
+            prefixColor: ele.prefixColor,
+            hasBracket: true,
+          };
+          typeList.push(typeData);
+        }
+      });
+    });
+    typeList = typeList.reverse();
+    typeList.splice(0, 0, {
+      key: '',
+      label: '全部',
+      value: typeNums.total,
+      hasValue: true,
+      hasBracket: true,
+    });
+    typeOptions.value = typeList;
+    tabSelected.value = typeOptions.value[0].key;
+  }
+
+  //取消按钮事件
+  async function handleCancel() {
+    clearSelectedRowKeys();
+    await reload();
+    await getTab();
+  }
+
+  // 弹窗回调事件
+  async function callSuccess({ isUpdate, values }) {
+    console.log(isUpdate);
+    console.log(values);
+    await reload();
+    await getTab();
+  }
+  // 选项卡组件回调
+  async function callTab(data) {
+    tabSelected.value = data.value;
+    await reload();
+  }
+
+  // 查询组件回调
+  async function callForm(data) {
+    shiftDate.value = data.shiftDate ? data.shiftDate : '';
+    searchNames.value = data.searchNames ? data.searchNames : '';
+    console.log('callForm:::', searchNames.value);
+    await reload();
+  }
+</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;
+  }
+
+  .colUpdateAvatar {
+    display: flex;
+    justify-content: center;
+    text-align: center;
+    line-height: 28px;
+  }
+
+  .colImg {
+    width: 28px;
+    height: 28px;
+    margin-right: 5px;
+  }
+</style>
+../../../../api/biz/mission/articleApi

+ 24 - 0
src/views/biz/mission/record/data.ts

@@ -0,0 +1,24 @@
+import { BasicColumn } from '/@/components/Table';
+
+export const columns: BasicColumn[] = [
+  {
+    title: '宣教时间',
+    dataIndex: 'updateTime',
+  },
+  {
+    title: '治疗阶段',
+    dataIndex: 'treatmentStage',
+  },
+  {
+    title: '患者姓名',
+    dataIndex: 'name',
+  },
+  {
+    title: '宣教标题',
+    dataIndex: 'title',
+  },
+  {
+    title: '宣教人',
+    dataIndex: 'updatorName',
+  },
+];

+ 212 - 3
src/views/biz/mission/record/index.vue

@@ -1,7 +1,216 @@
 <template>
-  <div> 占位符 </div>
+  <div class="m-4 modals">
+    <div>
+      <XTTitle title="宣教记录" />
+      <div class="flex items-center justify-between my-4">
+        <XTTab
+          type="record"
+          :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 === 'treatmentStage'">
+          <span
+            :class="['table-dot']"
+            :style="{
+              backgroundColor: formatDictPreColor(responseTypeOptions, record.treatmentStage),
+            }"
+          />
+          <span> {{ formatDictValue(responseTypeOptions, record.treatmentStage) }}</span>
+        </template>
+        <!-- <template v-if="column.key === 'supplierCategory'">
+          <span>
+            {{ formatDictValue(responsesupplierCategoryOptions, record.supplierCategory) }}</span
+          >
+        </template> -->
+        <template v-if="column.key === 'action'">
+          <TableAction
+            :actions="[
+              {
+                auth: 'biz:drug:edit',
+                icon: 'icon-xt-details_delete_default|iconfont',
+                tooltip: '删除',
+                onClick: handleDelete.bind(null, record),
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+  </div>
 </template>
+<script lang="ts" setup>
+  import { onBeforeMount, ref } from 'vue';
+  import { BasicTable, useTable, TableAction } from '/@/components/TableCard';
+  import { useMessage } from '/@/hooks/web/useMessage';
 
-<script setup lang="ts"></script>
+  import { formatDictValue, formatDictPreColor } from '/@/utils';
+  import { columns } from './data';
 
-<style lang="less" scoped></style>
+  import { getrecordList, recordNumber, recordDel } from '/@/api/biz/mission/recordApi';
+  import { listDictModel } from '/@/api/common';
+  import { XTTitle } from '/@/components/XTTitle/index';
+  import { XTTab } from '/@/components/XTTab/index';
+  import { XTForm } from '/@/components/XTForm/index';
+
+  // formdata
+  const formData = [
+    {
+      name: 'shiftDate',
+      componentType: 'RangePicker',
+      format: 'YYYY-MM-DD',
+      valueFormat: 'YYYY-MM-DD',
+      placeholder: '请选择日期',
+      width: 240,
+    },
+    {
+      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 responseTypeOptions = ref();
+  const responsesupplierCategoryOptions = ref();
+  onBeforeMount(async () => {
+    responseTypeOptions.value = await listDictModel({ dictCode: 'sys_disable_type' });
+    responsesupplierCategoryOptions.value = await listDictModel({ dictCode: 'd' });
+    getTab();
+  });
+
+  const { createMessage } = useMessage();
+
+  // const tableSort = ref([
+  //   {
+  //     field: 'create_time',
+  //     direction: 'DESC',
+  //   },
+  // ]) as any;
+
+  const [registerTable, { reload, clearSelectedRowKeys }] = useTable({
+    api: getrecordList,
+    batchDelApi: recordDel,
+    // batchExportApi: pharmaceuticalsExport,
+    delAuthList: ['biz:consumable:remove'],
+    rowKey: 'id',
+    columns,
+    showIndexColumn: true,
+    bordered: true,
+    actionColumn: {
+      width: 200,
+      title: '操作',
+      dataIndex: 'action',
+    },
+    beforeFetch: handleBeforeFetch,
+  });
+
+  // 删除按钮事件
+  async function handleDelete(record: Recordable) {
+    if (record) {
+      await recordDel(record.id);
+      createMessage.success('删除成功!');
+      clearSelectedRowKeys();
+      await reload();
+      await getTab();
+    }
+  }
+
+  // 表格请求之前,对参数进行处理, 添加默认 排序
+  async function handleBeforeFetch(params) {
+    console.log('searchNames:::', searchNames.value);
+    return {
+      ...params,
+      // orders: tableSort.value,
+      name: searchNames.value == '' ? undefined : searchNames.value,
+      status: tabSelected.value == '' ? undefined : tabSelected.value,
+      time: shiftDate.value.length <= 0 ? undefined : shiftDate.value,
+    };
+  }
+
+  async function getTab() {
+    typeOptions.value = await listDictModel({ dictCode: 'sys_disable_type' });
+    const typeNums = await recordNumber(); // 获取各类型数量
+    let typeList = [];
+    typeOptions.value.forEach(ele => {
+      // 变量各类型放置对应数量
+      let typeData = {};
+      Object.keys(typeNums).forEach(numKey => {
+        if (ele.value == numKey) {
+          typeData = {
+            key: ele.value,
+            label: ele.label,
+            value: typeNums[numKey],
+            hasValue: true,
+            prefixColor: ele.prefixColor,
+            hasBracket: true,
+          };
+          typeList.push(typeData);
+        }
+      });
+    });
+    typeList = typeList.reverse();
+    typeList.splice(0, 0, {
+      key: '',
+      label: '全部',
+      value: typeNums.total,
+      hasValue: true,
+      hasBracket: true,
+    });
+    typeOptions.value = typeList;
+    tabSelected.value = typeOptions.value[0].key;
+  }
+
+  // 选项卡组件回调
+  async function callTab(data) {
+    tabSelected.value = data.value;
+    await reload();
+  }
+
+  // 查询组件回调
+  async function callForm(data) {
+    shiftDate.value = data.shiftDate ? data.shiftDate : '';
+    searchNames.value = data.searchNames ? data.searchNames : '';
+    console.log('callForm:::', searchNames.value);
+    await reload();
+  }
+</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;
+  }
+
+  .colUpdateAvatar {
+    display: flex;
+    justify-content: center;
+    text-align: center;
+    line-height: 28px;
+  }
+
+  .colImg {
+    width: 28px;
+    height: 28px;
+    margin-right: 5px;
+  }
+</style>

+ 23 - 10
src/views/biz/visit/check/data.ts

@@ -45,35 +45,36 @@ export const BasicTab = [
 ];
 export const BasicTabActive = BasicTab[0].key;
 
-export const columns: BasicColumn[] = [
+export const checkColumns: BasicColumn[] = [
   {
     title: '姓名',
     dataIndex: 'name',
-    width: 150,
-    align: 'left',
   },
   {
     title: '信息',
     dataIndex: 'gender',
-    width: 150,
-    align: 'left',
   },
   {
     title: '查房时间',
     dataIndex: 'patrolTime',
-    width: 200,
-    align: 'left',
   },
   {
     title: '最新查房内容',
     dataIndex: 'content',
-    align: 'left',
   },
   {
     title: '记录人',
     dataIndex: 'recorder',
-    width: 120,
-    align: 'left',
+  },
+];
+export const columns: BasicColumn[] = [
+  {
+    title: '查房时间',
+    dataIndex: 'patrolTime',
+  },
+  {
+    title: '查房内容',
+    dataIndex: 'content',
   },
 ];
 
@@ -96,6 +97,7 @@ export const dataFormSchema: FormSchema[] = [
       };
     },
   },
+
   {
     label: '记录',
     field: 'content',
@@ -118,3 +120,14 @@ export const viewSchema: DescItem[] = [
     field: 'content',
   },
 ];
+// 历史记录查看
+export const data: DescItem[] = [
+  {
+    label: '查房时间',
+    field: 'patrolTime',
+  },
+  {
+    label: '查房内容',
+    field: 'content',
+  },
+];

+ 14 - 13
src/views/biz/visit/check/formModal.vue

@@ -13,24 +13,21 @@
 </template>
 <script lang="ts" setup>
   import { ref, computed, unref } from 'vue';
-  import { BasicModal } from '/@/components/Modal';
-  import { useModalInner } from '/@/components/Modal';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
   import { BasicForm, useForm } from '/@/components/Form';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { dataFormSchema } from './data';
 
-  import {
-    archivesPatrolWardAdd,
-    archivesPatrolWardEdit,
-    archivesPatrolWardDetail,
-  } from '/@/api/biz/visit/checkApi';
+  import { checkAdd, checkEdit, checkDetail } from '/@/api/biz/visit/checkApi';
+  import dayjs from 'dayjs';
 
   const emit = defineEmits(['success', 'register']);
 
   const getTitle = computed(() => (!unref(isUpdate) ? '新增查房' : '编辑查房'));
-  const width = '45%';
+  const width = '35%';
   const isUpdate = ref(false);
   const rowId = ref();
+  const patientBasicId = ref('');
 
   const { createMessage } = useMessage();
   const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({
@@ -45,9 +42,12 @@
     await resetFields();
     setModalProps({ confirmLoading: false });
     isUpdate.value = !!data?.isUpdate;
-
+    patientBasicId.value = data.record?.patientBasicId;
+    await setFieldsValue({
+      patrolTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+    });
     if (unref(isUpdate)) {
-      const resData = await archivesPatrolWardDetail(data.record.id);
+      const resData = await checkDetail(data.record.id);
       rowId.value = resData.id;
       await setFieldsValue({
         ...resData,
@@ -55,14 +55,15 @@
     }
   });
 
-  //提交按钮事件
+  // 提交按钮事件
   async function handleSubmit() {
     try {
       const values = await validate();
       setModalProps({ confirmLoading: true });
+      values.patientBasicId = patientBasicId.value;
       !unref(isUpdate)
-        ? await archivesPatrolWardAdd({ ...values })
-        : await archivesPatrolWardEdit({ ...values, id: rowId.value });
+        ? await checkAdd({ ...values })
+        : await checkEdit({ ...values, id: rowId.value });
       !unref(isUpdate) ? createMessage.success('新增成功!') : createMessage.success('编辑成功!');
       closeModal();
       emit('success', {

+ 112 - 42
src/views/biz/visit/check/index.vue

@@ -12,15 +12,24 @@
         />
         <XTForm :form-data="formData" @change="callFormChange" @click="callFormClick" />
       </div>
-      <div class="flex mb-2" v-if="siftData.length">
-        <Sift :data="siftData" @close="callClose" />
-      </div>
       <BasicTable @register="registerTable">
         <template #bodyCell="{ column, record }">
           <template v-if="column.key === 'name'">
             <span :class="['table-dot', 'table-dot--' + record.status]" />
             <span>{{ record.name }}</span>
           </template>
+          <template v-if="column.key === 'gender'">
+            <Icon
+              v-if="record.gender == 'pb_sex_man'"
+              icon="icon-xt-male_sm|iconfont"
+              color="#0057FF"
+            />
+            <Icon
+              v-if="record.gender == 'pb_sex_woman'"
+              icon="icon-xt-female_sm|iconfont"
+              color="#FF0066"
+            />({{ record.age }})</template
+          >
           <template v-if="column.key === 'patrolTime'">
             {{ record.patrolTime ? dayjs(record.patrolTime).format('YYYY-MM-DD') : '' }}
           </template>
@@ -29,35 +38,46 @@
             <TableAction
               :dropDownActions="[
                 {
-                  auth: 'storage:config:edit',
+                  auth: 'storage:config:query',
                   tooltip: '查房记录',
                   label: '查房记录',
-                  ifShow: !record.master,
+                  onClick: handleDetail.bind(null, record),
+                  // ifShow: !record.master,
                 },
                 {
-                  auth: 'storage:config:edit',
+                  auth: 'archives:patrolWard:edit',
                   tooltip: '编辑',
                   label: '编辑',
                   onClick: handleEdit.bind(null, record),
                 },
+                {
+                  auth: 'storage:config:remove',
+                  tooltip: '关注',
+                  label: '关注',
+                  color: 'error',
+                  popConfirm: {
+                    title: '是否确定要关注?',
+                    placement: 'left',
+                    confirm: handleCancel.bind(null, record),
+                  },
+                },
                 {
                   auth: 'storage:config:remove',
                   tooltip: '取消关注',
                   label: '取消关注',
                   color: 'error',
-                  // popConfirm: {
-                  //   title: '是否确定要取消关注?',
-                  //   placement: 'left',
-                  //   confirm: handleDelete.bind(null, record),
-                  // },
+                  popConfirm: {
+                    title: '是否确定要取消关注?',
+                    placement: 'left',
+                    confirm: handleCancel.bind(null, record),
+                  },
                 },
               ]"
               :actions="[
                 {
-                  auth: 'sys:log:query',
-                  // icon: 'icon-eye|iconfont',
+                  auth: 'archives:patrolWard:query',
+                  icon: 'icon-eye|iconfont',
                   tooltip: '查房',
-                  label: '查房',
                   onClick: handleView.bind(null, record),
                 },
               ]"
@@ -68,6 +88,7 @@
     </div>
     <FormModal @register="registerModal" @success="handleSuccess" />
     <ViewDrawer @register="registerDrawerView" @success="handleSuccess" />
+    <!-- <DatailModal @register="registerModalView" /> -->
   </div>
 </template>
 
@@ -75,16 +96,18 @@
   import { XTTitle } from '/@/components/XTTitle/index';
   import { XTTab } from '/@/components/XTTab/index';
   import { XTForm } from '/@/components/XTForm/index';
-  import { Sift } from '/@/components/XTList/index';
+  import { Icon } from '/@/components/Icon';
   import { BasicTable, useTable, TableAction } from '/@/components/TableCard';
-  import { BasicTab, BasicTabActive, columns } from './data';
+  import { BasicTab, BasicTabActive, checkColumns } from './data';
   import { ref } from 'vue';
-  // import { useRouter } from 'vue-router';
+  import { useRouter } from 'vue-router';
+
   import {
-    archivesPatrolWardQueryCheckRoomRecord,
-    archivesPatrolWardQueryPersonNumber,
+    checkQueryCheckRoomRecord,
+    checkQueryPersonNumber,
+    checkFollowOrNo,
   } from '/@/api/biz/visit/checkApi';
-  // import { formatDictColor, formatDictFontColor, formatDictValue } from '/@/utils';
+
   import { onMounted, reactive } from 'vue';
   import dayjs from 'dayjs';
   import { useModal } from '/@/components/Modal';
@@ -92,42 +115,44 @@
   import ViewDrawer from './viewDrawer.vue';
   import { useDrawer } from '@/components/Drawer';
 
-  // const bizDictOptions = reactive<any>({});
+  import { useMessage } from '/@/hooks/web/useMessage';
+
   //路由跳转
-  // const router = useRouter();
+
+  const router = useRouter();
   const activeKey = ref(BasicTabActive);
   const tabData = ref(BasicTab);
   const [registerModal, { openModal }] = useModal();
   const [registerDrawerView, { openDrawer, openDrawer: openDrawerView }] = useDrawer();
 
   onMounted(async () => {
-    const personNumber = await archivesPatrolWardQueryPersonNumber();
-    console.log('🚀 ~ file: index.vue:104 ~ onMounted ~ stats:', personNumber);
+    const stats = await checkQueryPersonNumber();
+    console.log('🚀 ~ file: index.vue:104 ~ onMounted ~ stats:', stats);
     tabData.value = tabData.value.map(ele => {
       if (ele.key == '0') {
-        ele.value = personNumber.all;
+        ele.value = stats.all;
       }
       if (ele.key == '1') {
-        ele.value = personNumber.dialysisPatients;
+        ele.value = stats.dialysisPatients;
       }
       if (ele.key == '2') {
-        ele.value = personNumber.noDialysisPatients;
+        ele.value = stats.noDialysisPatients;
       }
       if (ele.key == '3') {
-        ele.value = personNumber.newPatient;
+        ele.value = stats.newPatient;
       }
       if (ele.key == '4') {
-        ele.value = personNumber.attention;
+        ele.value = stats.attention;
       }
       return ele;
     });
     console.log('🚀 ~ file: index.vue:118 ~ onMounted ~ tabData.value:', tabData.value);
   });
   const [registerTable, { reload }] = useTable({
-    api: archivesPatrolWardQueryCheckRoomRecord,
+    api: checkQueryCheckRoomRecord,
     // exportAuthList: ['sys:log:export'],
     rowKey: 'id',
-    columns,
+    columns: checkColumns,
     showIndexColumn: true,
     bordered: true,
     actionColumn: {
@@ -138,6 +163,7 @@
     beforeFetch: handleBeforeFetch,
     afterFetch: handleAfterFetch,
   });
+
   // 筛选数据
   const siftData = ref([]);
 
@@ -185,6 +211,9 @@
   }
 
   function handleAfterFetch(data) {
+    // data.forEach(item => {
+    //   item.status = 2;
+    // });
     return data;
   }
 
@@ -196,6 +225,22 @@
     });
   }
 
+  //查房记录事件
+  function handleDetail(record: Recordable) {
+    router.push({
+      path: '../../bizArchives/detail',
+      query: {
+        id: record.id,
+        accessId: record.accessId,
+        name: record.name,
+        gender: record.gender,
+        age: record.age,
+      },
+    });
+  }
+
+  const { createMessage } = useMessage();
+
   // 编辑按钮事件
   function handleEdit(record: Recordable) {
     openModal(true, {
@@ -204,6 +249,15 @@
     });
   }
 
+  // 取消按钮事件
+  async function handleCancel(record) {
+    // clearSelectedRowKeys();
+    await checkFollowOrNo(record.id);
+    createMessage.success('操作成功!');
+    await reload();
+    // await getTab();
+  }
+
   // 弹窗回调事件
   async function handleSuccess({ isUpdate, values }) {
     console.log(isUpdate);
@@ -248,18 +302,34 @@
       });
     }
   }
+</script>
 
-  async function callClose(data) {
-    if (data.type == 'clear') {
-      console.log('清空全部');
-      siftData.value = [];
+<style lang="less" scoped>
+  .table-dot {
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    margin-right: 6px;
+    border-radius: 50%;
+
+    &hb--1 {
+      background-color: #1bc1b3;
     }
-    if (data.type == 'close') {
-      console.log('删除部分条件');
-      siftData.value = siftData.value.filter(ele => {
-        return ele.field != data.item?.field;
-      });
+
+    &--2 {
+      background-color: #d3d8dd;
+    }
+
+    &--3 {
+      background-color: #f7b500;
+    }
+
+    &--4 {
+      background-color: #3cf;
     }
-    await reload();
   }
-</script>
+
+  ::v-deep(.ant-btn-link) {
+    color: rgb(61 65 85 / 100%);
+  }
+</style>

+ 125 - 15
src/views/biz/visit/check/viewDrawer.vue

@@ -8,54 +8,112 @@
       :width="width"
     >
       <Description @register="registerDesc" :data="descData" />
-    </BasicDrawer>
+      <div>
+        <a-button type="primary" size="large" class="btn-add" @click="handleCreate">新增</a-button>
+      </div>
 
-    <Button
-      v-auth="['storage:config:add']"
-      type="primary"
-      @click="handleCreate"
-      preIcon="icon-plus|iconfont"
-    >
-      新增
-    </Button>
-    <FormModal @register="registerModal" @success="handleSuccess" />
+      <BasicTable @register="registerTable">
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'action'">
+            <TableAction
+              :actions="[
+                {
+                  auth: 'archives:patrolWard:edit',
+                  icon: 'icon-edit|iconfont',
+                  // label: '编辑',
+                  onClick: handleEdit.bind(null, record),
+                },
+                {
+                  auth: 'visit:handoverShifts:edit',
+                  icon: 'icon-xt-details_delete_default|iconfont',
+                  tooltip: '删除',
+                  popConfirm: {
+                    title: '是否确认删除',
+                    placement: 'left',
+                    confirm: handleDelete.bind(null, record),
+                  },
+                },
+              ]"
+            />
+          </template>
+        </template>
+      </BasicTable>
+      <FormModal @register="registerModal" @success="handleSuccess" />
+    </BasicDrawer>
   </div>
 </template>
 <script lang="ts" setup>
-  import { onBeforeMount, ref } from 'vue'; // onBeforeMount,
+  import { onBeforeMount, ref, nextTick } from 'vue'; // onBeforeMount,
   import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
   import { Description, useDescription } from '/@/components/Description';
-  import { viewSchema } from './data';
+  import { viewSchema, columns } from './data';
 
-  import { archivesPatrolWardDetail } from '/@/api/biz/visit/checkApi';
+  import { checkDetail, checkRemove, checkQueryPage } from '/@/api/biz/visit/checkApi';
   import { listDictModel } from '/@/api/common';
+  import { useMessage } from '/@/hooks/web/useMessage';
   import FormModal from './formModal.vue';
+  import { BasicTable, useTable, TableAction } from '/@/components/TableCard';
   import { formatDictValue } from '/@/utils';
   import { useModal } from '/@/components/Modal';
 
   const descData = ref({});
+  const lists = ref([]);
   const getTitle = '查看查房记录';
+
   const width = '45%';
   const [registerModal, { openModal }] = useModal();
+  const { createMessage } = useMessage();
+  // const siftData = ref([]);
+  // const activeKey = ref();
+  const patientBasicId = ref();
 
   const typeOptions = ref();
   onBeforeMount(async () => {
     typeOptions.value = await listDictModel({ dictCode: 'sys_login_log_type' });
   });
   // 新增按钮事件
-  function handleCreate() {
+
+  function handleCreate(data) {
     openModal(true, {
       isUpdate: false,
+      record: data,
     });
   }
   const [registerDrawer] = useDrawerInner(async data => {
     console.log('::::::::::', data.record);
-    const resData = await archivesPatrolWardDetail(data.record.id);
+    const resData = await checkDetail(data.record.id);
+    patientBasicId.value = resData.patientBasicId;
     descData.value = {
       ...resData,
       type: formatDictValue(typeOptions.value, resData.type),
     };
+    const params = {
+      pageNum: 1,
+      pageSize: 999,
+      patientBasicId: resData.patientBasicId,
+    };
+    const list = await checkQueryPage(params);
+    console.log(list);
+    if (list && list.data) {
+      lists.value = list.data;
+    }
+    await nextTick();
+    await setTableData(lists.value);
+  });
+  const [registerTable, { reload, setTableData }] = useTable({
+    dataSource: lists.value,
+    rowKey: 'id',
+    columns,
+    showIndexColumn: false,
+    bordered: true,
+    actionColumn: {
+      width: 200,
+      title: '操作',
+      dataIndex: 'action',
+    },
+    afterFetch: handleAfterFetch,
   });
+
   const [registerDesc] = useDescription({
     schema: viewSchema,
     column: 1,
@@ -64,9 +122,61 @@
       width: '120px',
     },
   });
+
+  // 编辑按钮事件
+  function handleEdit(record: Recordable) {
+    openModal(true, {
+      record,
+      isUpdate: true,
+    });
+  }
+
+  // 删除按钮事件
+  // async function handleDelete(record: Recordable) {
+  //   if (record) {
+  //     await archivesPatrolWardRemove([record.id]);
+  //     createMessage.success('删除成功!');
+  //     clearSelectedRowKeys();
+  //     await reload();
+  //   } else {
+  //     createConfirm({
+  //       content: '你确定要删除?',
+  //       iconType: 'warning',
+  //       onOk: async () => {
+  //         const keys = getSelectRowKeys();
+  //         await archivesPatrolWardRemove(keys);
+  //         createMessage.success('删除成功!');
+  //         await reload();
+  //       },
+  //     });
+  //   }
+  // }
+  function handleAfterFetch(data) {
+    // data.forEach(item => {
+    //   item.status = 2;
+    // });
+    return data;
+  }
+  // 删除按钮事件
+  async function handleDelete(record: Recordable) {
+    console.log('🚀 ~ file: index.vue:141 ~ handleDelete ~ record', record);
+    await checkRemove([record.id]);
+    createMessage.success('删除成功!');
+    await reload();
+  }
+
   // 弹窗回调事件
   async function handleSuccess({ isUpdate, values }) {
     console.log(isUpdate);
     console.log(values);
   }
 </script>
+
+<style lang="less" scoped>
+  .btn-add {
+    margin: 2%;
+    float: right;
+    width: 100px;
+    border-radius: 4px;
+  }
+</style>