优化提交

This commit is contained in:
2026-09-28 17:26:50 +08:00
parent dd6ffd0ef6
commit a646ade658
5 changed files with 102 additions and 18 deletions
@@ -91,6 +91,7 @@ import { startScanBroadcast } from '@/utils/scan-broadcast.js'
import { bindWarehouseTransferPallet, deleteWarehouseTransferPallet, downloadWarehouseTransferMeasurementPhoto, downloadWarehouseTransferPalletLabel, generateWarehouseTransferPallet, getWarehouseTransferDetail, listWarehouseTransferCandidates, listWarehouseTransferMeasurementPhotos, palletizeWarehouseTransfer, saveWarehouseTransferPalletDraft, uploadWarehouseTransferMeasurementPhoto } from '@/api/warehouse-transfers.js'
const newPallet = () => ({ key: `${Date.now()}-${Math.random()}`, cartonCount: 0, lengthCm: null, widthCm: null, heightCm: null, grossWeightKg: null, generated: false, bound: false, collapsed: false, palletNo: '', fbaWarehouseCode: '', labelDownloadPath: '', bindCode: '', busy: false })
const MAX_MEASUREMENT_PHOTOS = 20
const restoredPallet = (value, index) => ({
key: `server-${value.draftId || value.id || index}`,
@@ -120,6 +121,7 @@ export default {
if (!Number.isInteger(Number(pallet.cartonCount))) return `托盘 ${index + 1} 的箱数必须是整数`
}
if (this.pallets.some((pallet) => !pallet.bound)) return '请先生成并扫描确认绑定全部托盘'
if (this.photoFileIds.length > MAX_MEASUREMENT_PHOTOS) return `测量现场照片最多 ${MAX_MEASUREMENT_PHOTOS} 张,请移除多余照片`
if (!this.photoFileIds.length) return '请至少拍摄 1 张测量现场照片'
return ''
},
@@ -207,30 +209,53 @@ export default {
addPallet() { this.pendingKey = ''; this.pallets.push(newPallet()) },
async removePallet(index) { const pallet = this.pallets[index]; if (!pallet || pallet.generated || pallet.busy) return; pallet.busy = true; try { if (pallet.draftId) await deleteWarehouseTransferPallet(this.selected.transferNo, pallet.draftId); this.pallets.splice(index, 1); this.pendingKey = '' } catch (error) { pallet.busy = false; this.error = error } },
async restorePhotos(transferNo, knownPhotos) {
this.photoFileIds = []; this.photoUrls = {}; this.photoNames = []
let photos
try {
const photos = Array.isArray(knownPhotos) ? knownPhotos : await listWarehouseTransferMeasurementPhotos(transferNo)
this.photoFileIds = photos.map((photo) => String(photo.fileId)); this.photoNames = photos.map((photo) => photo.fileName || '测量现场照片')
await Promise.all(photos.map(async (photo) => { try { this.photoUrls[String(photo.fileId)] = await downloadWarehouseTransferMeasurementPhoto(transferNo, photo.fileId) } catch (_) { /* 单张恢复失败不阻断补拍 */ } }))
} catch (error) { this.error = error }
// Detail responses contain submitted photos only. The PDA list endpoint
// is the authoritative source for uploads that have not been submitted.
photos = await listWarehouseTransferMeasurementPhotos(transferNo)
} catch (error) {
if (!Array.isArray(knownPhotos)) { this.error = error; return false }
photos = knownPhotos
}
const nextUrls = {}
await Promise.all(photos.map(async (photo) => { try { nextUrls[String(photo.fileId)] = await downloadWarehouseTransferMeasurementPhoto(transferNo, photo.fileId) } catch (_) { /* 单张恢复失败不阻断补拍 */ } }))
this.photoFileIds = photos.map((photo) => String(photo.fileId)); this.photoNames = photos.map((photo) => photo.fileName || '测量现场照片'); this.photoUrls = nextUrls
return true
},
takePhoto() {
if (!this.selected || this.uploadingPhoto || this.submitting || this.photoFileIds.length >= 20) return
if (!this.selected || this.uploadingPhoto || this.submitting || this.photoFileIds.length >= MAX_MEASUREMENT_PHOTOS) {
if (this.photoFileIds.length >= MAX_MEASUREMENT_PHOTOS) this.error = new Error(`测量现场照片最多 ${MAX_MEASUREMENT_PHOTOS} 张`)
return
}
const transferNo = this.selected.transferNo
uni.chooseImage({ count: Math.min(9, 20 - this.photoFileIds.length), sourceType: ['camera', 'album'], success: async ({ tempFilePaths, tempFiles }) => {
uni.chooseImage({ count: Math.min(9, MAX_MEASUREMENT_PHOTOS - this.photoFileIds.length), sourceType: ['camera', 'album'], success: async ({ tempFilePaths, tempFiles }) => {
const paths = (tempFilePaths || []).length ? tempFilePaths : (tempFiles || []).map((file) => file.path || file.tempFilePath).filter(Boolean)
if (this.selected?.transferNo !== transferNo) { this.error = new Error('所选转运单已切换,请重新拍摄'); return }
if (!paths.length) { this.error = new Error('未获取到可上传的照片路径,请重新拍摄'); return }
const remaining = MAX_MEASUREMENT_PHOTOS - this.photoFileIds.length
const uploadPaths = paths.slice(0, remaining)
const skipped = paths.length - uploadPaths.length
this.uploadingPhoto = true; this.error = null
try {
for (const [index, path] of paths.entries()) {
for (const [index, path] of uploadPaths.entries()) {
if (this.photoFileIds.length >= MAX_MEASUREMENT_PHOTOS) throw new Error(`测量现场照片最多 ${MAX_MEASUREMENT_PHOTOS} 张`)
if (Number(tempFiles?.[index]?.size || 0) > 10 * 1024 * 1024) throw new Error('照片不能超过 10MB')
const file = await uploadWarehouseTransferMeasurementPhoto(transferNo, path)
if (this.selected?.transferNo !== transferNo) throw new Error('所选转运单已切换,请重新拍摄')
const fileId = String(file.fileId); this.photoUrls[fileId] = path; this.photoFileIds.push(fileId); this.photoNames.push(file.fileName || '测量现场照片')
}
if (skipped > 0) this.error = new Error(`最多上传 ${MAX_MEASUREMENT_PHOTOS} 张测量现场照片,已忽略超出的 ${skipped} 张`)
this.pendingKey = ''
} catch (error) { this.error = error } finally { this.uploadingPhoto = false }
} catch (error) {
this.error = error
// Another window/device may have filled the remaining slots. Re-read
// server state so a refresh cannot reset the UI back to 0/20.
if (/at most 20|最多.?20|supports at most/i.test(String(error?.message || ''))) {
await this.restorePhotos(transferNo)
this.error = error
}
} finally { this.uploadingPhoto = false }
}, fail: (cause) => { if (!/cancel/i.test(String(cause?.errMsg || ''))) this.error = new Error(cause?.errMsg || '选择照片失败,请重试') } })
},
previewPhoto(fileId) { const urls = this.photoFileIds.map((id) => this.photoUrls[id]).filter(Boolean); if (this.photoUrls[fileId]) uni.previewImage({ current: this.photoUrls[fileId], urls }) },