index.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <template>
  2. <div class="flex doc">
  3. <div class="doc-nav">
  4. <div class="my-4 ml-4">
  5. <a-button type="primary" @click="handleAdd">
  6. <template #icon>
  7. <PlusOutlined />
  8. </template>
  9. 添加文书
  10. </a-button>
  11. </div>
  12. <List
  13. type="attachment"
  14. :data="listData"
  15. :selected="selected"
  16. :width="320"
  17. @itemClick="callItemClick"
  18. @edit="callEdit"
  19. @delete="callDelete"
  20. />
  21. </div>
  22. <div class="flex justify-center px-4 pt-4 grow">
  23. <div class="doc-cnt">
  24. <div class="my-2 text-right">
  25. <a-pagination
  26. v-model:current="page.current"
  27. :total="page.total"
  28. :pageSize="page.size"
  29. :hideOnSinglePage="true"
  30. @change="handlePageChange"
  31. />
  32. </div>
  33. <iframe
  34. v-if="fileIds.length && previewUrl"
  35. :id="fileIds[page.current - 1]"
  36. class="doc-iframe"
  37. :src="previewUrl"
  38. />
  39. <div class="doc-cnt doc-cnt--empty" v-else>
  40. <a-empty />
  41. </div>
  42. </div>
  43. </div>
  44. <FormModal @register="registerModal" @success="callSuccess" />
  45. </div>
  46. </template>
  47. <script setup lang="ts">
  48. import { nextTick, onMounted, reactive, ref } from 'vue';
  49. import List from '/@/components/XTList/src/List.vue';
  50. import { PlusOutlined } from '@ant-design/icons-vue';
  51. import { listDictModel, getPreviewUrl } from '/@/api/common';
  52. import { formatDictValue } from '/@/utils';
  53. import { useMessage } from '@/hooks/web/useMessage';
  54. import { useModal } from '/@/components/Modal';
  55. import {
  56. archivesMedicalDocumentsQueryList,
  57. archivesMedicalDocumentsRemove,
  58. } from '/@/api/biz/archives/medicalDocumentsApi';
  59. import FormModal from './FormModal.vue';
  60. import dayjs from 'dayjs';
  61. const props = defineProps({
  62. info: {
  63. type: Object,
  64. default: () => {},
  65. },
  66. });
  67. const bizDictOptions = reactive({
  68. type: [],
  69. });
  70. const { createConfirm, createMessage } = useMessage();
  71. const [registerModal, { openModal }] = useModal();
  72. onMounted(async () => {
  73. bizDictOptions.type = await listDictModel({ dictCode: 'md' });
  74. await getData();
  75. });
  76. const listData = ref([]);
  77. const selected = ref('');
  78. const fileIds = ref([]);
  79. const page = reactive({
  80. size: 1,
  81. total: 1,
  82. current: 1,
  83. });
  84. const isFirstLoad = ref(true);
  85. const previewUrl = ref('');
  86. async function getData() {
  87. const res = await archivesMedicalDocumentsQueryList(props.info?.id);
  88. listData.value = res.map(ele => {
  89. const obj = {
  90. id: ele.id,
  91. title: formatDictValue(bizDictOptions.type, ele.type),
  92. doctor: ele.updatorName,
  93. endTime: dayjs(ele.updateTime).format('YYYY-MM-DD'),
  94. attachment: ele.fileCount,
  95. patientBasicId: ele.patientBasicId,
  96. fileIds: ele.fileIds,
  97. };
  98. return obj;
  99. });
  100. if (isFirstLoad.value && listData.value.length) {
  101. selected.value = listData.value[0]['id'];
  102. page.total = listData.value[0]['attachment'] || 0;
  103. fileIds.value = listData.value[0]['fileIds'];
  104. if (fileIds.value.length) {
  105. await handlePreview(fileIds.value[0]);
  106. }
  107. isFirstLoad.value = false;
  108. }
  109. }
  110. function handleAdd() {
  111. const data = { patientBasicId: '' };
  112. data.patientBasicId = props.info?.id;
  113. openModal(true, {
  114. isUpdate: false,
  115. record: data,
  116. });
  117. }
  118. async function handlePageChange(page) {
  119. await handlePreview(fileIds.value[page - 1]);
  120. }
  121. // 预览文件地址
  122. async function handlePreview(id) {
  123. console.log('🚀 ~ file: index.vue:128 ~ handlePreview ~ id:', id);
  124. if (id == undefined) {
  125. previewUrl.value = '';
  126. return;
  127. }
  128. try {
  129. const res = await getPreviewUrl(id);
  130. previewUrl.value = res || '';
  131. await nextTick();
  132. } catch (error) {
  133. previewUrl.value = '';
  134. }
  135. }
  136. // 回调
  137. async function callItemClick(data) {
  138. console.log('🚀 ~ file: index.vue:141 ~ callItemClick ~ data:', data);
  139. selected.value = data.id;
  140. page.current = 1;
  141. page.total = data.attachment;
  142. fileIds.value = data.fileIds;
  143. await handlePreview(fileIds.value[0]);
  144. }
  145. async function callEdit(data) {
  146. data.patientBasicId = props.info?.id;
  147. openModal(true, {
  148. isUpdate: true,
  149. record: data,
  150. });
  151. }
  152. async function callDelete(data) {
  153. createConfirm({
  154. content: '你确定要删除?',
  155. iconType: 'warning',
  156. onOk: async () => {
  157. await archivesMedicalDocumentsRemove([data.id]);
  158. createMessage.success('删除成功');
  159. await getData();
  160. if (listData.value.length) {
  161. await callItemClick(listData.value[0]);
  162. } else {
  163. await handlePreview(undefined);
  164. }
  165. },
  166. });
  167. }
  168. async function callSuccess({ isUpdate, values }) {
  169. console.log('🚀 ~ file: index.vue:166 ~ callSuccess ~ values:', values);
  170. if (isUpdate) {
  171. selected.value = values.id;
  172. page.current = 1;
  173. page.total = values.fileIds.length;
  174. fileIds.value = values.fileIds;
  175. await handlePreview(fileIds.value[0]);
  176. } else {
  177. isFirstLoad.value = true;
  178. }
  179. await getData();
  180. }
  181. </script>
  182. <style lang="less" scoped>
  183. .doc {
  184. position: relative;
  185. top: -16px;
  186. &-nav {
  187. border-right: 1px solid #f6f8fa;
  188. }
  189. &-cnt {
  190. // flex: auto;
  191. width: 100%;
  192. }
  193. &-iframe {
  194. min-width: 500px;
  195. min-height: calc(100vh - 270px);
  196. width: 100%;
  197. }
  198. }
  199. </style>