|
|
@@ -7,10 +7,10 @@ import { api } from '../api'
|
|
|
import { blankEntry } from '../utils/entry'
|
|
|
import { useUploads } from '../utils/uploads'
|
|
|
import type { Attachment, Entry } from '../api/indexType'
|
|
|
-import type { WmsLedgerAdminSummaryResponse, WmsLedgerFlowVO, WmsReversalPreCheckResponse, WmsReversalRecordResponse } from '../api/indexType'
|
|
|
+import type { WmsLedgerAdminSummaryResponse, WmsLedgerFlowVO, WmsReversalPreCheckResponse } from '../api/indexType'
|
|
|
import { dateTime, fieldErrors, report, reversalLimit, refreshAfterWrite } from '../utils/ui'
|
|
|
|
|
|
-type LedgerEntry = Entry & { recordId?: number; flowType?: number; alreadyReversedQty: number; reversalState?: number; originFlowDetail?: string }
|
|
|
+type LedgerEntry = Entry & { recordId?: number; flowType?: number; alreadyReversedQty: number; reversalState?: number; originFlowDetail?: string; relatedReversalFlows?: string[] }
|
|
|
type LedgerDetail = WmsLedgerFlowVO
|
|
|
const entries = ref<LedgerEntry[]>([])
|
|
|
const pendingUploads = useUploads()
|
|
|
@@ -34,6 +34,7 @@ function toEntry(item: LedgerDetail): LedgerEntry {
|
|
|
alreadyReversedQty: item.alreadyReversedQty ?? 0, reversalState: item.reversalStatus,
|
|
|
originalId: item.originFlowNo || '', createdAt: item.createTime || '', operator: item.updateUser || item.createUser || '',
|
|
|
originFlowDetail: item.originFlowDetail,
|
|
|
+ relatedReversalFlows: item.relatedReversalFlows,
|
|
|
remark: item.reversalReason || item.remark || '', orderType: item.orderType === 1 ? 'internal' : item.orderType === 2 ? 'external' : '',
|
|
|
so: item.soNo || '', company: item.expressCompany || '', tracking: item.expressNo || '',
|
|
|
evidence: (item.attachments || []).map((file, index) => ({ id: String(file.id ?? index), url: file.fileUrl || '', name: file.fileName || '凭证' })),
|
|
|
@@ -42,7 +43,9 @@ function toEntry(item: LedgerDetail): LedgerEntry {
|
|
|
}
|
|
|
}
|
|
|
const loading = ref(false)
|
|
|
+let listLoadVersion = 0
|
|
|
async function loadData() {
|
|
|
+ const version = ++listLoadVersion
|
|
|
loading.value = true
|
|
|
try {
|
|
|
const filter = applied.value
|
|
|
@@ -54,10 +57,12 @@ async function loadData() {
|
|
|
flowType: filter.direction ? Number(filter.direction) : undefined,
|
|
|
flowSource: filter.source || undefined, reversalStatus: reversalStates[filter.reversal],
|
|
|
})
|
|
|
+ if (version !== listLoadVersion) return
|
|
|
entries.value = (result.rows as WmsLedgerFlowVO[]).map(toEntry)
|
|
|
total.value = result.total
|
|
|
}
|
|
|
- finally { loading.value = false }
|
|
|
+ catch (error) { if (version === listLoadVersion) throw error }
|
|
|
+ finally { if (version === listLoadVersion) loading.value = false }
|
|
|
}
|
|
|
const filters = reactive({ keyword: '', direction: '', reversal: '', source: '' })
|
|
|
const applied = ref({ ...filters })
|
|
|
@@ -94,22 +99,6 @@ function filterRows() { applied.value = { ...filters }; page.value = 1; loadData
|
|
|
async function showDetail(entry: LedgerEntry) {
|
|
|
try {
|
|
|
if (entry.recordId == null || entry.flowType == null) throw new Error('接口未返回流水类型或记录 ID')
|
|
|
- if (entry.flowType === 3 || entry.source === 'reversal') {
|
|
|
- const result = await api.wmsApi.reversal.detail({ id: entry.recordId }) as WmsReversalRecordResponse
|
|
|
- if (!result || typeof result !== 'object') throw new Error('冲销详情格式不符合预期')
|
|
|
- const direction = result.reversalDirection === 1 ? 'inbound' : result.reversalDirection === 2 ? 'outbound'
|
|
|
- : result.originFlowType === 1 ? 'outbound' : result.originFlowType === 2 ? 'inbound' : entry.direction
|
|
|
- detail.value = {
|
|
|
- ...toEntry({
|
|
|
- ...result, flowNo: result.flowNo || entry.id, recordId: result.id ?? entry.recordId,
|
|
|
- flowType: 3, flowSource: 'REVERSAL', status: result.status ?? 1,
|
|
|
- skuName: result.skuNameSnapshot ?? entry.snapshot?.name,
|
|
|
- spec: result.specSnapshot ?? entry.snapshot?.spec,
|
|
|
- configDetail: result.configDetailSnapshot ?? entry.snapshot?.config,
|
|
|
- }), direction,
|
|
|
- }
|
|
|
- return
|
|
|
- }
|
|
|
const result = await api.wmsApi.ledger.flowDetail({ flowNo: entry.id, flowType: entry.flowType, recordId: entry.recordId })
|
|
|
if (!result || typeof result !== 'object') throw new Error('流水详情格式不符合预期')
|
|
|
detail.value = toEntry({ flowNo: entry.id, recordId: entry.recordId, flowType: entry.flowType, status: 1, ...result } as LedgerDetail)
|
|
|
@@ -148,7 +137,7 @@ async function submitReverse() {
|
|
|
<el-config-provider :empty-values="[null, undefined]">
|
|
|
<form class="ledger-filters" @submit.prevent="filterRows">
|
|
|
<el-input v-model="filters.keyword" placeholder="skuID / 商品 / 订单号" aria-label="skuID / 商品名称 / 订单号" clearable />
|
|
|
- <el-select v-model="filters.direction" aria-label="流水类型"><el-option label="流水类型:全部" value="" /><el-option label="入库" value="1" /><el-option label="出库" value="2" /><el-option label="冲销" value="3" /></el-select>
|
|
|
+ <el-select v-model="filters.direction" aria-label="出入库类型"><el-option label="出入库类型:全部" value="" /><el-option label="入库" value="1" /><el-option label="出库" value="2" /></el-select>
|
|
|
<el-select model-value="completed" aria-label="单据状态"><el-option label="单据状态:已完成" value="completed" /></el-select>
|
|
|
<el-select v-model="filters.reversal" aria-label="原流水状态"><el-option label="原流水状态:全部" value="" /><el-option v-for="value in ['未冲销', '部分冲销', '已全额冲销']" :key="value" :value="value" :label="value" /></el-select>
|
|
|
<el-select v-model="filters.source" aria-label="流水来源"><el-option label="流水来源:全部" value="" /><el-option label="正常录入" value="NORMAL" /><el-option label="冲销" value="REVERSAL" /></el-select>
|
|
|
@@ -190,6 +179,12 @@ async function submitReverse() {
|
|
|
<div class="ledger-evidence-label">关联原流水</div>
|
|
|
<div class="ledger-readonly">{{ detail.originFlowDetail }}</div>
|
|
|
</div>
|
|
|
+ <div v-if="detail.source === 'normal' && detail.relatedReversalFlows?.length" class="ledger-related-reversals">
|
|
|
+ <div class="ledger-evidence-label">关联冲销流水</div>
|
|
|
+ <div class="ledger-related-reversal-list">
|
|
|
+ <div v-for="flow in detail.relatedReversalFlows" :key="flow" class="ledger-related-reversal-item">{{ flow }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
<template #footer><el-button @click="detail = undefined">关闭</el-button><el-button v-if="detail && canReverse(detail)" type="warning" plain @click="openReverse(detail)">冲销 / 更正</el-button></template>
|
|
|
</el-dialog>
|
|
|
@@ -254,6 +249,8 @@ async function submitReverse() {
|
|
|
.ledger-evidence-item { display: flex; align-items: center; gap: 8px; max-width: 100%; }
|
|
|
.ledger-evidence-item .el-image { width: 44px; height: 40px; border-radius: 4px; flex-shrink: 0; cursor: zoom-in; }
|
|
|
.ledger-related { margin-top: 16px; overflow-wrap: anywhere; }
|
|
|
+.ledger-related-reversal-list { padding: 4px 10px; border: 1px solid #dce5e1; border-radius: 7px; background: #f2f6f4; }
|
|
|
+.ledger-related-reversal-item { min-height: 28px; padding: 4px 0; box-sizing: border-box; color: #80969d; font-size: 14px; line-height: 20px; overflow-wrap: anywhere; }
|
|
|
.ledger-stock-note { font-size: 12px; color: #7b8d91; margin: 0 0 14px; }
|
|
|
@media (max-width: 1100px) { .ledger-filters > * { flex-basis: calc(33.333% - 8px); } .ledger-filters > :nth-child(8) { flex-grow: 1; } }
|
|
|
@media (max-width: 600px) { .ledger-heading { align-items: flex-start; gap: 12px; } .ledger-heading h1 { font-size: 22px; } .ledger-stats { grid-template-columns: minmax(0, 1fr); } .ledger-filters > * { flex-basis: calc(50% - 8px); } .ledger-filters > .ledger-search { flex-basis: 100%; } .ledger-grid { grid-template-columns: minmax(0, 1fr); } }
|