Release/test #10

Merged
admin merged 40 commits from release/test into main 2026-09-28 15:59:06 +08:00
5 changed files with 29 additions and 7 deletions
Showing only changes of commit aa189146a0 - Show all commits
@@ -5,6 +5,7 @@ import { ArrowLeft, Plus, Trash2 } from '@lucide/vue'
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
import { useAuthStore } from '@/modules/auth/public'
import { useUnsavedWorkRegistration } from '@/navigation/workspace-tabs/unsavedWork'
import { createIdempotencyKey } from '@/utils/idempotencyKey'
import { createDeliveryOrder, type DeliveryOrderFee, type DeliveryTransferPayload } from '../api/deliveryOrders'
type DeliveryCreateForm = Omit<DeliveryTransferPayload, 'idempotencyKey'>
@@ -112,7 +113,7 @@ async function submit() {
submitError.value = ''
const valid = await formRef.value?.validate().catch(() => false)
if (!valid || !validateFees()) return
if (!pendingIdempotencyKey) pendingIdempotencyKey = crypto.randomUUID()
if (!pendingIdempotencyKey) pendingIdempotencyKey = createIdempotencyKey()
submitting.value = true
try {
const created = await createDeliveryOrder(requestPayload())
@@ -1,4 +1,5 @@
import { overseasApiRequest, overseasBlobRequest } from '@/api/overseasHttp'
import { createIdempotencyKey } from '@/utils/idempotencyKey'
export type RelabelDeliveryMethod = 'TRUCK' | 'EXPRESS' | 'TRUCK_PICKUP' | 'EXPRESS_PICKUP'
@@ -78,7 +79,7 @@ export function getRelabel(relabelNo: string) {
return overseasApiRequest<RelabelDetail>({ method: 'GET', url: `/merchant/v1/last-leg/relabel-applications/${encodeURIComponent(relabelNo)}` })
}
export function confirmTransferMeasurement(transferNo: string, remark?: string) {
return overseasApiRequest<Record<string, unknown>>({ method: 'POST', url: `/merchant/v1/last-leg/warehouse-transfers/${encodeURIComponent(transferNo)}/confirm-measurement`, data: { idempotencyKey: crypto.randomUUID(), remark } })
return overseasApiRequest<Record<string, unknown>>({ method: 'POST', url: `/merchant/v1/last-leg/warehouse-transfers/${encodeURIComponent(transferNo)}/confirm-measurement`, data: { idempotencyKey: createIdempotencyKey(), remark } })
}
export interface TransferCartonLabel { transferNo: string; cartons: Array<{ cartonMark: string; customerCartonMark?: string; cartonIndex: number; totalCartons: number; status: string }>; printableHtml: string }
export function getTransferCartonLabel(transferNo: string) {
@@ -109,7 +110,7 @@ export function uploadRelabelFile(relabelNo: string, scope: 'CARTON_TOTAL' | 'SK
return overseasApiRequest<RelabelDetail>({ method: 'POST', url: `/merchant/v1/last-leg/relabel-applications/${encodeURIComponent(relabelNo)}/files`, params: { scope, itemId }, data, headers: { 'Content-Type': 'multipart/form-data' } })
}
export function confirmRelabelCompletion(relabelNo: string, remark?: string) {
return overseasApiRequest<RelabelDetail>({ method: 'POST', url: `/merchant/v1/last-leg/relabel-applications/${encodeURIComponent(relabelNo)}/confirm-completion`, data: { idempotencyKey: crypto.randomUUID(), remark } })
return overseasApiRequest<RelabelDetail>({ method: 'POST', url: `/merchant/v1/last-leg/relabel-applications/${encodeURIComponent(relabelNo)}/confirm-completion`, data: { idempotencyKey: createIdempotencyKey(), remark } })
}
export function downloadRelabelCompletionPhoto(relabelNo: string, fileId: string) {
return overseasBlobRequest({ method: 'GET', url: `/merchant/v1/last-leg/relabel-applications/${encodeURIComponent(relabelNo)}/completion-photos/${encodeURIComponent(fileId)}/download` })
@@ -8,6 +8,7 @@ import DataTable, { type DataTableColumn } from '@/components/common/DataTable.v
import type { TableAction } from '@/components/common/tableActions'
import { useAuthStore } from '@/modules/auth/public'
import { getMerchantWarehouses, type MerchantWarehouse } from '@/modules/first-leg/public'
import { createIdempotencyKey } from '@/utils/idempotencyKey'
import { createReturnOrder, downloadReturnPhoto, getReturnOrder, listReturnOrders, updateReturnOrder, type ReturnOrderDetail, type ReturnOrderSummary, type ReturnReceipt } from '../api/returnOrders'
const props = withDefaults(defineProps<{ createPage?: boolean; detailPage?: boolean; returnNo?: string }>(), { createPage: false, detailPage: false, returnNo: '' })
@@ -185,7 +186,7 @@ async function submit() {
if (duplicateSkuIds.value.size) { ElMessage.warning('同一退货单不能重复填写相同 SKU'); return }
creating.value = true
try {
const payload = { overseasWarehouseId: form.overseasWarehouseId, warehouseContactName: form.warehouseContactName.trim(), warehouseContactPhone: form.warehouseContactPhone.trim(), customerReferenceNo: form.customerReferenceNo || undefined, remark: form.remark || undefined, needRelabel: form.needRelabel, idempotencyKey: crypto.randomUUID(), items: items.map(item => ({ ...item, productNameZh: item.productNameZh || undefined })) }
const payload = { overseasWarehouseId: form.overseasWarehouseId, warehouseContactName: form.warehouseContactName.trim(), warehouseContactPhone: form.warehouseContactPhone.trim(), customerReferenceNo: form.customerReferenceNo || undefined, remark: form.remark || undefined, needRelabel: form.needRelabel, idempotencyKey: createIdempotencyKey(), items: items.map(item => ({ ...item, productNameZh: item.productNameZh || undefined })) }
const detail = editingReturnNo.value ? await updateReturnOrder(editingReturnNo.value, payload) : await createReturnOrder(payload)
ElMessage.success(editingReturnNo.value ? '退货预报已更新' : '退货预报已创建'); showCreate.value = false; editingReturnNo.value = ''; resetForm(); await router.push({ name: 'overseas-return-relabel-detail', params: { returnNo: detail.order.returnNo } })
} finally { creating.value = false }
@@ -25,6 +25,7 @@ import {
type MerchantWarehouseDetail,
} from '@/modules/first-leg/api/firstLeg'
import { loadAllWarehouseRecords } from '@/modules/first-leg/utils/warehousePagination'
import { createIdempotencyKey } from '@/utils/idempotencyKey'
import { createReturnRelabel, uploadReturnRelabelFile } from '../api/returnOrders'
type ServiceType = 'labeling' | 'transfer' | 'disposal' | 'relabel'
@@ -914,7 +915,7 @@ async function submitReturnRelabel() {
destinationFbaWarehouseId: String(destination.id),
destinationFbaWarehouseCode: destination.warehouseCode,
cartonRemark: form.remark.trim() || undefined,
idempotencyKey: crypto.randomUUID(),
idempotencyKey: createIdempotencyKey(),
})
await uploadReturnRelabelFile(created.relabelNo, fileScope, selectedFile)
ElMessage.success(`贴标申请 ${created.relabelNo} 已提交,等待审核`)
@@ -1002,7 +1003,7 @@ async function submit(action: 'draft' | 'submit' = 'submit') {
}
saving.value = true
try {
const idempotencyKey = crypto.randomUUID()
const idempotencyKey = createIdempotencyKey()
if (props.service === 'labeling') {
const sourceInboundOrders = [...new Set(cargoRows.value.map((item) => item.sourceInboundOrderNo || item.sourceInboundCode).filter((value): value is string => Boolean(value)))].join('、').slice(0, 128)
const items = labelingMode.value === 'carton'
@@ -1260,7 +1261,7 @@ async function resubmitRejectedRelabel() {
selectedRelabelDetail.value = await resubmitRelabel(application.relabelNo, {
labelDeadline: application.labelDeadline || '', contactName: application.contactName || '',
contactPhone: application.contactPhone || '', remark: value?.trim() || undefined,
idempotencyKey: crypto.randomUUID(),
idempotencyKey: createIdempotencyKey(),
})
ElMessage.success('贴标单已重新提交审核')
} catch (error) {
+18
View File
@@ -0,0 +1,18 @@
export function createIdempotencyKey(prefix = 'client') {
const nativeUuid = globalThis.crypto?.randomUUID
if (typeof nativeUuid === 'function') return nativeUuid.call(globalThis.crypto)
const bytes = new Uint8Array(16)
if (typeof globalThis.crypto?.getRandomValues === 'function') {
globalThis.crypto.getRandomValues(bytes)
} else {
for (let index = 0; index < bytes.length; index += 1) {
bytes[index] = Math.floor(Math.random() * 256)
}
}
bytes[6] = (bytes[6] & 0x0f) | 0x40
bytes[8] = (bytes[8] & 0x3f) | 0x80
const hex = Array.from(bytes, value => value.toString(16).padStart(2, '0')).join('')
const uuid = `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`
return prefix ? `${prefix}-${uuid}` : uuid
}