fan 2 лет назад
Родитель
Сommit
2bd8821bad

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

@@ -32,6 +32,7 @@ import ApiTreeSelect from './components/ApiTreeSelect.vue';
 import ApiCascader from './components/ApiCascader.vue';
 import ApiTransfer from './components/ApiTransfer.vue';
 import { BasicUpload } from '/@/components/Upload';
+import { XTUpload } from '/@/components/XTUpload';
 import { IconPicker } from '/@/components/Icon';
 import { CountdownInput } from '/@/components/CountDown';
 import TextEditor from './components/TextEditor.vue';
@@ -86,6 +87,7 @@ componentMap.set('IconPicker', IconPicker);
 componentMap.set('InputCountDown', CountdownInput);
 
 componentMap.set('Upload', BasicUpload);
+componentMap.set('XTUpload', XTUpload);
 componentMap.set('Divider', Divider);
 
 export function add(compName: ComponentType, component: Component) {

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

@@ -124,4 +124,5 @@ export type ComponentType =
   | 'RadioDescGroup'
   | 'ApiComplex'
   | 'ApiInputDict'
+  | 'XTUpload'
   | 'Cron';

+ 97 - 0
src/views/biz/archives/medicalDocuments/FormModal.vue

@@ -0,0 +1,97 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    destroyOnClose
+    @register="registerModal"
+    :title="getTitle"
+    :width="width"
+    @ok="handleSubmit"
+    :showFooter="true"
+  >
+    <div class="!pl-8 !pt-4">
+      <BasicForm @register="registerForm" layout="vertical" />
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts" setup>
+  import { ref, computed, unref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, useForm } from '/@/components/Form';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { dataFormSchema } from './data';
+  import {
+    archivesMedicalDocumentsAdd,
+    archivesMedicalDocumentsEdit,
+    archivesMedicalDocumentsDetail,
+  } from '/@/api/biz/archives/medicalDocumentsApi';
+  import dayjs from 'dayjs';
+
+  const emit = defineEmits(['success', 'register']);
+
+  const getTitle = computed(() => (!unref(isUpdate) ? '新增文书' : '编辑文书'));
+  const width = '35%';
+  const isUpdate = ref(false);
+  const rowId = ref();
+  const patientBasicId = ref();
+
+  const { createMessage } = useMessage();
+  const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({
+    labelWidth: 100,
+    schemas: dataFormSchema,
+    showActionButtonGroup: false,
+    // baseColProps: {
+    //   span: 12,
+    // },
+    wrapperCol: {
+      span: 22,
+    },
+  });
+  const [registerModal, { setModalProps, closeModal }] = useModalInner(async data => {
+    await resetFields();
+    setModalProps({ confirmLoading: false });
+    isUpdate.value = data?.isUpdate;
+    patientBasicId.value = data.record.patientBasicId;
+    if (unref(isUpdate)) {
+      const resData = await archivesMedicalDocumentsDetail(data.record.id);
+      console.log('🚀 ~ file: FormModal.vue:58 ~ resData:', resData);
+      rowId.value = resData.id;
+      await setFieldsValue({
+        ...resData,
+      });
+    } else {
+      await setFieldsValue({
+        updateTime: dayjs().format('YYYY-MM-DD'),
+        files: [],
+      });
+    }
+  });
+
+  // 提交按钮事件
+  async function handleSubmit() {
+    try {
+      const values = await validate();
+      setModalProps({ confirmLoading: true });
+      values.patientBasicId = patientBasicId.value;
+      console.log('🚀 ~ file: FormModal.vue:71 ~ handleSubmit ~ values:', {
+        ...values,
+        id: rowId.value,
+      });
+      values.fileIds = values.files.map(ele => ele.id);
+      console.log('🚀 ~ file: FormModal.vue:71 ~ handleSubmit ~ values:', {
+        ...values,
+        id: rowId.value,
+      });
+      !unref(isUpdate)
+        ? await archivesMedicalDocumentsAdd({ ...values })
+        : await archivesMedicalDocumentsEdit({ ...values, id: rowId.value });
+      !unref(isUpdate) ? createMessage.success('新增成功!') : createMessage.success('编辑成功!');
+      closeModal();
+      emit('success', {
+        isUpdate: unref(isUpdate),
+        values: { ...values, id: rowId.value },
+      });
+    } finally {
+      setModalProps({ confirmLoading: false });
+    }
+  }
+</script>

+ 61 - 0
src/views/biz/archives/medicalDocuments/data.ts

@@ -0,0 +1,61 @@
+import { listDictModel, uploadApi } from '@/api/common';
+import { FormSchema } from '@/components/Form';
+// 表单新增编辑
+export const dataFormSchema: FormSchema[] = [
+  {
+    label: '上传日期',
+    field: 'updateTime',
+    required: true,
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD',
+      placeholder: '请输入上传日期',
+      getPopupContainer: () => document.body,
+      valueFormat: 'YYYY-MM-DD',
+      disabled: true,
+    },
+  },
+  {
+    label: '文书类型',
+    field: 'type',
+    required: true,
+    component: 'ApiSelect',
+    componentProps: {
+      api: listDictModel,
+      params: {
+        dictCode: 'md',
+      },
+      getPopupContainer: () => document.body,
+    },
+  },
+  // {
+  //   label: '文书上传',
+  //   field: 'files',
+  //   component: 'Upload',
+  //   componentProps: {
+  //     api: uploadApi,
+  //     maxSize: 10,
+  //     maxNumber: 5,
+  //     helpText: '仅支持上传jpg/png/pdf文件,文件大小不超过5M',
+  //     accept: ['image/*', '.pdf'],
+  //   },
+  //   colProps: {
+  //     span: 24,
+  //   },
+  // },
+  {
+    label: '文书上传',
+    field: 'files',
+    component: 'XTUpload',
+    componentProps: {
+      api: uploadApi,
+      maxSize: 10,
+      maxNumber: 5,
+      helpText: '仅支持上传jpg/png/pdf文件,文件大小不超过5M',
+      accept: ['image/*', '.pdf'],
+    },
+    colProps: {
+      span: 24,
+    },
+  },
+];

+ 182 - 0
src/views/biz/archives/medicalDocuments/index.vue

@@ -0,0 +1,182 @@
+<template>
+  <div class="flex doc">
+    <div class="doc-nav">
+      <div class="my-4 ml-4">
+        <a-button type="primary" @click="handleAdd">
+          <template #icon>
+            <PlusOutlined />
+          </template>
+          添加文书
+        </a-button>
+      </div>
+      <List
+        type="attachment"
+        :data="listData"
+        :selected="selected"
+        :width="320"
+        @itemClick="callItemClick"
+        @edit="callEdit"
+        @delete="callDelete"
+      />
+    </div>
+    <div class="flex justify-center px-4 pt-4 grow">
+      <div class="doc-cnt">
+        <div class="my-2 text-right">
+          <a-pagination
+            v-model:current="page.current"
+            :total="page.total"
+            :pageSize="page.size"
+            @change="handlePageChange"
+          />
+        </div>
+        <iframe :id="fileIds[page.current - 1]" class="doc-iframe" :src="previewUrl" />
+      </div>
+    </div>
+    <FormModal @register="registerModal" @success="callSuccess" />
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { onMounted, reactive, ref } from 'vue';
+  import List from '/@/components/XTList/src/List.vue';
+  import { PlusOutlined } from '@ant-design/icons-vue';
+  import { listDictModel, getPreviewUrl } from '/@/api/common';
+  import { formatDictValue } from '/@/utils';
+  import { useMessage } from '@/hooks/web/useMessage';
+  import { useModal } from '/@/components/Modal';
+
+  import {
+    archivesMedicalDocumentsQueryList,
+    archivesMedicalDocumentsRemove,
+  } from '/@/api/biz/archives/medicalDocumentsApi';
+  import FormModal from './FormModal.vue';
+
+  import dayjs from 'dayjs';
+  const props = defineProps({
+    info: {
+      type: Object,
+      default: () => {},
+    },
+  });
+  const bizDictOptions = reactive({
+    type: [],
+  });
+  const { createConfirm, createMessage } = useMessage();
+  const [registerModal, { openModal }] = useModal();
+
+  onMounted(async () => {
+    bizDictOptions.type = await listDictModel({ dictCode: 'md' });
+    await getData();
+  });
+  const listData = ref([]);
+  const selected = ref('');
+  const fileIds = ref([]);
+  const page = reactive({
+    size: 1,
+    total: 1,
+    current: 1,
+  });
+  const isFirstLoad = ref(true);
+  const previewUrl = ref('');
+  async function getData() {
+    const res = await archivesMedicalDocumentsQueryList(props.info?.id);
+    console.log('🚀 ~ file: index.vue:105 ~ getData ~ res:', res);
+    listData.value = res.map(ele => {
+      const obj = {
+        id: ele.id,
+        title: formatDictValue(bizDictOptions.type, ele.type),
+        doctor: ele.updatorName,
+        endTime: dayjs(ele.updateTime).format('YYYY-MM-DD'),
+        attachment: ele.fileCount,
+        patientBasicId: ele.patientBasicId,
+        fileIds: ele.fileIds,
+      };
+      return obj;
+    });
+    if (isFirstLoad.value) {
+      selected.value = listData.value[0]['id'];
+      page.total = listData.value[0]['attachment'] || 0;
+      fileIds.value = listData.value[0]['fileIds'];
+      await handlePreview(fileIds.value[0]);
+      isFirstLoad.value = false;
+    }
+  }
+
+  function handleAdd() {
+    const data = { patientBasicId: '' };
+    data.patientBasicId = props.info?.id;
+    openModal(true, {
+      isUpdate: false,
+      record: data,
+    });
+  }
+  async function handlePageChange(page) {
+    await handlePreview(fileIds.value[page - 1]);
+  }
+  // 预览文件地址
+  async function handlePreview(id) {
+    const res = await getPreviewUrl(id);
+    previewUrl.value = res;
+  }
+  // 回调
+  async function callItemClick(data) {
+    selected.value = data.id;
+    page.current = 1;
+    page.total = data.attachment;
+    fileIds.value = data.fileIds;
+    await handlePreview(fileIds.value[0]);
+  }
+  async function callEdit(data) {
+    data.patientBasicId = props.info?.id;
+    openModal(true, {
+      isUpdate: true,
+      record: data,
+    });
+  }
+  async function callDelete(data) {
+    console.log('🚀 ~ file: index.vue:131 ~ data:', data);
+    createConfirm({
+      content: '你确定要删除?',
+      iconType: 'warning',
+      onOk: async () => {
+        await archivesMedicalDocumentsRemove([data.id]);
+        createMessage.success('删除成功');
+        await getData();
+      },
+    });
+  }
+  async function callSuccess({ isUpdate, values }) {
+    if (isUpdate) {
+      selected.value = values.id;
+      page.current = 1;
+      page.total = values.fileIds.length;
+      fileIds.value = values.fileIds;
+      await handlePreview(fileIds.value[0]);
+    } else {
+      isFirstLoad.value = true;
+    }
+    await getData();
+  }
+</script>
+
+<style lang="less" scoped>
+  .doc {
+    position: relative;
+    top: -16px;
+
+    &-nav {
+      border-right: 1px solid #f6f8fa;
+    }
+
+    &-cnt {
+      // flex: auto;
+      width: 100%;
+    }
+
+    &-iframe {
+      min-width: 500px;
+      min-height: calc(100vh - 270px);
+      width: 100%;
+    }
+  }
+</style>

+ 1 - 1
src/views/biz/archives/patientBasic/index.vue

@@ -199,7 +199,7 @@
   }
 
   function getDiagnosisMulti(data, field) {
-    if (data.length) {
+    if (data && data.length) {
       data.forEach(detail => {
         detail['multiContent'].forEach(content => {
           const obj = {} as any;