| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { FileType } from 'ant-design-vue/es/upload/interface'; |
| | | import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart } from '@vben/utils'; |
| | | |
| | | import { Button, message, Progress, Upload } from 'ant-design-vue'; |
| | | |
| | | import { |
| | | importMaterialStock, |
| | | importMaterialStockTemplate, |
| | | } from '#/api/mes/wm/materialstock'; |
| | | |
| | | defineOptions({ name: 'WmMaterialStockImportModal' }); |
| | | |
| | | const emit = defineEmits<{ success: [] }>(); |
| | | |
| | | const fileList = ref<FileType[]>([]); |
| | | const importResult = ref<MesWmMaterialStockApi.ImportResult>(); |
| | | const importing = ref(false); |
| | | const progressPercent = ref(0); |
| | | let progressTimer: ReturnType<typeof setInterval> | undefined; |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | if (fileList.value.length === 0) { |
| | | message.warning('è¯·éæ©è¦å¯¼å
¥çæä»¶'); |
| | | return; |
| | | } |
| | | if (importing.value) return; |
| | | modalApi.lock(); |
| | | importing.value = true; |
| | | startMockProgress(); |
| | | try { |
| | | importResult.value = await importMaterialStock(fileList.value[0] as File); |
| | | // 宿ï¼è¿åº¦æ¡èµ°æ»¡ |
| | | stopMockProgress(); |
| | | progressPercent.value = 100; |
| | | await delay(500); |
| | | message.success('导å
¥å®æ'); |
| | | emit('success'); |
| | | } finally { |
| | | stopMockProgress(); |
| | | importing.value = false; |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | |
| | | /** 模æè¿åº¦æ¡ï¼è¯·æ±æé´ä» 0 èµ°å° 90% */ |
| | | function startMockProgress() { |
| | | progressPercent.value = 0; |
| | | progressTimer = setInterval(() => { |
| | | if (progressPercent.value < 90) { |
| | | progressPercent.value = Math.min( |
| | | 90, |
| | | progressPercent.value + Math.random() * 12, |
| | | ); |
| | | } |
| | | }, 300); |
| | | } |
| | | |
| | | function stopMockProgress() { |
| | | if (progressTimer) { |
| | | clearInterval(progressTimer); |
| | | progressTimer = undefined; |
| | | } |
| | | } |
| | | |
| | | function delay(ms: number) { |
| | | return new Promise((resolve) => setTimeout(resolve, ms)); |
| | | } |
| | | |
| | | function beforeUpload(file: FileType) { |
| | | fileList.value = [file]; |
| | | importResult.value = undefined; |
| | | return false; |
| | | } |
| | | |
| | | function handleRemove() { |
| | | fileList.value = []; |
| | | importResult.value = undefined; |
| | | } |
| | | |
| | | async function handleDownloadTemplate() { |
| | | const data = await importMaterialStockTemplate(); |
| | | downloadFileFromBlobPart({ fileName: 'åºåç°æé导å
¥æ¨¡æ¿.xls', source: data }); |
| | | } |
| | | |
| | | const createCount = computed(() => importResult.value?.createNames?.length ?? 0); |
| | | const updateCount = computed(() => importResult.value?.updateNames?.length ?? 0); |
| | | const failureCount = computed( |
| | | () => Object.keys(importResult.value?.failureNames ?? {}).length, |
| | | ); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal title="导å
¥åºåç°æé" class="w-[640px]"> |
| | | <div class="mx-4"> |
| | | <Upload |
| | | :max-count="1" |
| | | accept=".xls,.xlsx" |
| | | :file-list="fileList" |
| | | :before-upload="beforeUpload" |
| | | @remove="handleRemove" |
| | | > |
| | | <Button type="primary">éæ© Excel æä»¶</Button> |
| | | </Upload> |
| | | <div |
| | | class="mt-3 rounded-md border border-gray-200 bg-gray-50 p-3 text-sm leading-6 text-gray-600" |
| | | > |
| | | 模æ¿åï¼ç©æç¼ç ãä»åºãåºåºãåºä½ãæ¹æ¬¡å·ãä¾åºåã<b>æä½ç±»å</b>ã<b>å¨åºæ°é</b>ã<br /> |
| | | æä½ç±»åå¿
å¡«ï¼ |
| | | <b class="text-gray-800">å¢å </b> / <b class="text-gray-800">åå°</b> |
| | | æ"å¨åºæ°é"ä½ä¸ºæ¬æ¬¡åå¨éå ååºåï¼ |
| | | <b class="text-gray-800">è¦ç</b> |
| | | æè¯¥è®°å½å¨åºæ°éç´æ¥è®¾ä¸º"å¨åºæ°é"ï¼æå建账æ¨èï¼ï¼å·²åå¨è®°å½èªå¨æå·®é¢è°æ´ã<br /> |
| | | ä»åº/åºåº/åºä½/ä¾åºåå¯å¡«ç¼ç æåç§°ï¼ç©æå¯ç¨æ¹æ¬¡ç®¡çæ¶æ¹æ¬¡å·å¿
å¡«ï¼æ¯è¡ç¬ç«æ§è¡ï¼å¤±è´¥è¡ä¸å½±åå
¶å®è¡ï¼ä»
æ¯æ |
| | | xlsãxlsx æä»¶ |
| | | </div> |
| | | <!-- 导å
¥è¿åº¦æ¡ --> |
| | | <div v-if="importing" class="mt-4"> |
| | | <div class="mb-2 text-sm text-gray-600">æ£å¨å¯¼å
¥åºåæ°æ®ï¼è¯·ç¨å...</div> |
| | | <Progress :percent="progressPercent" status="active" /> |
| | | </div> |
| | | <!-- 导å
¥ç»æ --> |
| | | <div |
| | | v-if="importResult" |
| | | class="mt-4 rounded-md border border-gray-200 bg-gray-50 p-3" |
| | | > |
| | | <div class="mb-2 font-medium">导å
¥ç»æ</div> |
| | | <div class="mb-2 flex flex-wrap gap-4"> |
| | | <span class="text-green-600">æåæ°å»ºï¼{{ createCount }} æ¡</span> |
| | | <span class="text-blue-600">æåæ´æ°ï¼{{ updateCount }} æ¡</span> |
| | | <span class="text-red-600">失败ï¼{{ failureCount }} æ¡</span> |
| | | </div> |
| | | <div v-if="createCount > 0" class="max-h-32 overflow-y-auto text-sm leading-6 text-green-600"> |
| | | <div v-for="name in importResult.createNames" :key="`c-${name}`"> |
| | | {{ name }} |
| | | </div> |
| | | </div> |
| | | <div v-if="updateCount > 0" class="max-h-32 overflow-y-auto text-sm leading-6 text-blue-600"> |
| | | <div v-for="name in importResult.updateNames" :key="`u-${name}`"> |
| | | {{ name }} |
| | | </div> |
| | | </div> |
| | | <div v-if="failureCount > 0" class="max-h-40 overflow-y-auto"> |
| | | <div |
| | | v-for="(reason, name) in importResult.failureNames" |
| | | :key="`f-${name}`" |
| | | class="text-sm leading-6 text-red-500" |
| | | > |
| | | {{ name }}ï¼{{ reason }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <template #prepend-footer> |
| | | <Button @click="handleDownloadTemplate">ä¸è½½å¯¼å
¥æ¨¡æ¿</Button> |
| | | </template> |
| | | </Modal> |
| | | </template> |