BaseStationImportModal.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <BasicModal
  3. :open="open"
  4. title="导入基站数据"
  5. okText="导入"
  6. :confirmLoading="submitting"
  7. :maskClosable="false"
  8. :keyboard="false"
  9. :width="520"
  10. :minHeight="180"
  11. wrapClassName="ai-base-station-import-modal"
  12. @update:open="handleOpenChange"
  13. @ok="handleSubmit"
  14. @cancel="handleCancel"
  15. >
  16. <div class="base-station-import-modal">
  17. <div class="base-station-import-modal__toolbar">
  18. <span class="base-station-import-modal__tip">仅支持导入 `.xls` 格式文件,单次仅允许选择一个文件。</span>
  19. <Button type="link" class="base-station-import-modal__template" @click="emit('fetch-template')">
  20. 获取导入模版
  21. </Button>
  22. </div>
  23. <Upload
  24. accept=".xls"
  25. :file-list="fileList"
  26. :before-upload="beforeUpload"
  27. @remove="handleRemove"
  28. >
  29. <Button>
  30. <template #icon><UploadOutlined /></template>
  31. 选择文件
  32. </Button>
  33. </Upload>
  34. <div v-if="uploadInfo" class="base-station-import-modal__progress">{{ uploadInfo }}</div>
  35. </div>
  36. </BasicModal>
  37. </template>
  38. <script lang="ts" setup>
  39. import { ref, watch } from 'vue';
  40. import { Button, Upload } from 'ant-design-vue';
  41. import type { FileType } from 'ant-design-vue/es/upload/interface';
  42. import type { AxiosProgressEvent } from 'axios';
  43. import { UploadOutlined } from '@ant-design/icons-vue';
  44. import { BasicModal } from '@jeesite/core/components/Modal';
  45. import { useMessage } from '@jeesite/core/hooks/web/useMessage';
  46. import { useUserStoreWithOut } from '@jeesite/core/store/modules/case';
  47. import {
  48. importBaseStationFile,
  49. type BaseStationImportPayload,
  50. type BaseStationImportResponse,
  51. } from '@jeesite/trans/api/baseStationQueryApi';
  52. type BaseStationImportSuccessPayload = BaseStationImportPayload | string | Recordable | null | undefined;
  53. const props = defineProps<{
  54. open: boolean;
  55. }>();
  56. const emit = defineEmits<{
  57. (e: 'update:open', value: boolean): void;
  58. (e: 'success', payload: BaseStationImportSuccessPayload): void;
  59. (e: 'fetch-template'): void;
  60. }>();
  61. const { createMessage } = useMessage();
  62. const fileList = ref<FileType[]>([]);
  63. const uploadInfo = ref('');
  64. const submitting = ref(false);
  65. const resetState = () => {
  66. fileList.value = [];
  67. uploadInfo.value = '';
  68. submitting.value = false;
  69. };
  70. watch(
  71. () => props.open,
  72. (open) => {
  73. if (!open) {
  74. resetState();
  75. }
  76. },
  77. );
  78. const beforeUpload = (file: FileType) => {
  79. const fileName = String(file.name || '');
  80. if (!/\.xls$/i.test(fileName)) {
  81. createMessage.warning('请选择 .xls 格式文件');
  82. fileList.value = [];
  83. return false;
  84. }
  85. fileList.value = [file];
  86. return false;
  87. };
  88. const handleRemove = () => {
  89. fileList.value = [];
  90. };
  91. const handleOpenChange = (value: boolean) => {
  92. emit('update:open', value);
  93. };
  94. const handleCancel = () => {
  95. emit('update:open', false);
  96. };
  97. const handleUploadProgress = (progressEvent: AxiosProgressEvent) => {
  98. const total = Number(progressEvent.total || 0);
  99. if (!total) return;
  100. const percent = Math.min(100, Math.floor((Number(progressEvent.loaded || 0) / total) * 100));
  101. uploadInfo.value = percent >= 100 ? '' : `正在导入,请稍候 ${percent}%...`;
  102. };
  103. const getCaseId = () => {
  104. const caseId = useUserStoreWithOut().getCaseInfo?.id;
  105. if (caseId !== undefined && caseId !== null && String(caseId).trim()) {
  106. return caseId;
  107. }
  108. const localCaseId = window.localStorage.getItem('caseId');
  109. return localCaseId && localCaseId.trim() ? localCaseId.trim() : undefined;
  110. };
  111. const handleSubmit = async () => {
  112. const currentFile = fileList.value[0];
  113. if (!currentFile) {
  114. createMessage.warning('请先选择要导入的基站文件');
  115. return;
  116. }
  117. try {
  118. submitting.value = true;
  119. const file = ((currentFile as any).originFileObj || currentFile) as File;
  120. const payload = (await importBaseStationFile({ file }, handleUploadProgress, getCaseId())) as BaseStationImportResponse;
  121. const code = Number(payload.code || 0);
  122. const message = payload.message || payload.msg || (code === 200 ? '导入成功' : '导入失败');
  123. if (code !== 200) {
  124. createMessage.error(message);
  125. return;
  126. }
  127. emit('success', payload.data ?? payload);
  128. emit('update:open', false);
  129. createMessage.success(message);
  130. } catch (error: any) {
  131. createMessage.error(error?.message || '导入基站数据失败');
  132. } finally {
  133. submitting.value = false;
  134. uploadInfo.value = '';
  135. }
  136. };
  137. </script>
  138. <style lang="less">
  139. .ai-base-station-import-modal {
  140. .ant-modal-body {
  141. padding: 20px 24px 24px;
  142. }
  143. }
  144. .base-station-import-modal {
  145. display: flex;
  146. flex-direction: column;
  147. gap: 16px;
  148. .base-station-import-modal__toolbar {
  149. display: flex;
  150. align-items: flex-start;
  151. justify-content: space-between;
  152. gap: 12px;
  153. }
  154. .base-station-import-modal__tip {
  155. color: #6b7280;
  156. font-size: 13px;
  157. line-height: 20px;
  158. }
  159. .base-station-import-modal__template {
  160. padding-right: 0;
  161. white-space: nowrap;
  162. }
  163. .base-station-import-modal__progress {
  164. color: #2563eb;
  165. font-size: 12px;
  166. line-height: 18px;
  167. }
  168. }
  169. </style>