fix(fleet): preserve retry intent and restore inquiry editing
This commit is contained in:
@@ -1,20 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import AppDialog from '@/shared/components/AppDialog.vue'
|
||||
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||||
import { ApiResponseError, getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||||
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||||
import FleetQuotePartySelect from './FleetQuotePartySelect.vue'
|
||||
import { importFleetQuotes, saveFleetCsv, type FleetQuoteDraft, type FleetQuoteKind } from '../api/fleetQuotes'
|
||||
import { importFleetQuotes, saveFleetCsv, isFleetCommandRejected, type FleetQuoteDraft, type FleetQuoteKind } from '../api/fleetQuotes'
|
||||
import { fleetQuoteCsvHeader, parseFleetQuoteCsv } from '../fleetQuoteCsv'
|
||||
const open = defineModel<boolean>({ default: false }), props = defineProps<{ kind: FleetQuoteKind }>(), emit = defineEmits<{ saved: [] }>()
|
||||
const partyId = ref(''), rows = ref<FleetQuoteDraft[]>([]), source = ref(''), saving = ref(false), error = ref<ApiErrorDetails | null>(null)
|
||||
const pending = ref<{ key: string; rows: FleetQuoteDraft[] } | null>(null)
|
||||
const activeKind = computed(() => pending.value?.rows[0]?.kind || props.kind)
|
||||
let fileSequence = 0
|
||||
watch([partyId, () => props.kind], () => { if (!pending.value) preview() })
|
||||
function preview() { try { rows.value = source.value ? parseFleetQuoteCsv(source.value, props.kind, partyId.value) : []; error.value = null } catch (e) { rows.value = []; error.value = getApiErrorDetails(e, 'CSV校验失败') } }
|
||||
async function pick(event: Event) { const file = (event.target as HTMLInputElement).files?.[0]; if (!file) return; if (file.size > 500000) { error.value = getApiErrorDetails(new Error('CSV不能超过500KB')); return }; source.value = await file.text(); preview() }
|
||||
async function pick(event: Event) {
|
||||
if (saving.value || pending.value) return
|
||||
const file = (event.target as HTMLInputElement).files?.[0]; if (!file) return
|
||||
const current = ++fileSequence; rows.value = []; source.value = ''; error.value = null
|
||||
if (file.size > 500000) { error.value = getApiErrorDetails(new Error('CSV不能超过500KB')); return }
|
||||
try { const text = await file.text(); if (current !== fileSequence) return; source.value = text; preview() }
|
||||
catch (e) { if (current === fileSequence) error.value = getApiErrorDetails(e, 'CSV读取失败,请重新选择文件') }
|
||||
}
|
||||
function template() { saveFleetCsv(new Blob(['\uFEFF' + fleetQuoteCsvHeader.join(',') + '\r\n'], { type: 'text/csv;charset=utf-8' }), '车队报价模板.csv') }
|
||||
async function save() { saving.value = true; error.value = null; try { pending.value ??= { key: crypto.randomUUID(), rows: rows.value.map(r => ({ ...r })) }; await importFleetQuotes(pending.value.key, pending.value.rows); pending.value = null; rows.value = []; source.value = ''; open.value = false; emit('saved') } catch (e) { error.value = getApiErrorDetails(e, '整批导入失败,请核对报价库与目录后重试'); if (e instanceof ApiResponseError && ([400, 409, 422].includes(e.status || 0) || ['400', '409', '422', 'VALIDATION_FAILED', 'CONFLICT'].includes(e.code))) pending.value = null } finally { saving.value = false } }
|
||||
async function save() { if (saving.value || (!pending.value && (!rows.value.length || !partyId.value))) return; fileSequence++; saving.value = true; error.value = null; try { pending.value ??= { key: crypto.randomUUID(), rows: rows.value.map(r => ({ ...r })) }; await importFleetQuotes(pending.value.key, pending.value.rows); pending.value = null; rows.value = []; source.value = ''; open.value = false; emit('saved') } catch (e) { error.value = getApiErrorDetails(e, '整批导入失败,请核对报价库与目录后重试'); if (isFleetCommandRejected(e)) pending.value = null } finally { saving.value = false } }
|
||||
onBeforeUnmount(() => { fileSequence++ })
|
||||
</script>
|
||||
<template><AppDialog v-model="open" title="批量导入车队报价" width="1040px" class="admin-density-dialog" :close-on-click-modal="false">
|
||||
<p>本批{{ activeKind === 'PURCHASE' ? '采购' : '销售' }}报价使用同一往来单位;每批最多200条,服务端整批校验,任一失败全部不写入。</p>
|
||||
|
||||
Reference in New Issue
Block a user