feat(pickup): 增加第三方单号补录功能并优化列表提号备注展示

- 后端支持补录/修改第三方单号接口 PUT /api/v1/admin/pickups/:id/third-party-order-no,记录流转事件与审计日志
- 前端线下提号主列表在第三方单号列后展示提号备注列
- 前端列表操作列及提号详情页增加补录/修改第三方单号操作入口与弹窗
- 通过 scripts/check.sh 全量门禁校验
This commit is contained in:
yml2213
2026-10-09 18:45:12 +08:00
parent 2c943027f0
commit b4d2d1e2f5
9 changed files with 345 additions and 1 deletions
@@ -134,6 +134,10 @@ export interface AdminPickupProfitUpdateRequest {
reason?: string
}
export interface AdminPickupThirdPartyOrderNoUpdateRequest {
third_party_order_no: string
}
export interface AdminPickupOfflineSettlementRequest {
remark?: string
}
@@ -308,6 +312,17 @@ export async function updateAdminPickupProfit(id: number, req: AdminPickupProfit
return data.data
}
export async function updateAdminPickupThirdPartyOrderNo(
id: number,
req: AdminPickupThirdPartyOrderNoUpdateRequest
) {
const { data } = await apiClient.put<ApiResponse<AdminPickup>>(
`/admin/pickups/${id}/third-party-order-no`,
req
)
return data.data
}
export async function createAdminPickupFinancialAdjustment(
id: number,
req: AdminPickupFinancialAdjustmentRequest
@@ -11,6 +11,7 @@ import {
createAdminPickupFinancialAdjustment,
settleAdminPickupFinancialAdjustment,
updateAdminPickupProfit,
updateAdminPickupThirdPartyOrderNo,
type AdminPickup,
type AdminPickupFinancialAdjustment,
type AdminPickupProcessEvent,
@@ -44,16 +45,20 @@ const financialAdjustments = ref<AdminPickupFinancialAdjustment[]>([])
const processEvents = ref<AdminPickupProcessEvent[]>([])
const profitDialogVisible = ref(false)
const financialAdjustmentDialogVisible = ref(false)
const thirdPartyOrderNoDialogVisible = ref(false)
const profitSaving = ref(false)
const financialAdjustmentSaving = ref(false)
const thirdPartyOrderNoSaving = ref(false)
const profitForm = reactive({ profit_amount: 0, reason: '' })
const financialAdjustmentForm = reactive({ profit_amount: 0, settle_amount: 0, reason: '' })
const thirdPartyOrderNoForm = reactive({ third_party_order_no: '' })
const listingCode = computed(() =>
pickup.value ? formatListingNo(pickup.value.listing_no, pickup.value.listing_id) : '-'
)
const canEditProfit = computed(() => pickup.value?.status === 'picking_up')
const canCreateFinancialAdjustment = computed(() => pickup.value?.status === 'completed')
const canUpdateThirdPartyOrderNo = computed(() => pickup.value?.status !== 'cancelled')
const snapshot = computed(() => normalizeRecord(pickup.value?.account_snapshot))
const assetSummary = computed(() => normalizeRecord(snapshot.value?.asset_summary))
const priceBreakdown = computed(() => normalizeRecord(assetSummary.value?.price_breakdown))
@@ -221,6 +226,35 @@ async function handleUpdateProfit() {
}
}
function openThirdPartyOrderNoDialog() {
if (!pickup.value) return
thirdPartyOrderNoForm.third_party_order_no = pickup.value.third_party_order_no || ''
thirdPartyOrderNoDialogVisible.value = true
}
async function handleSaveThirdPartyOrderNo() {
if (!pickup.value) return
const orderNo = thirdPartyOrderNoForm.third_party_order_no.trim()
if (!orderNo) {
ElMessage.warning('请输入第三方单号')
return
}
thirdPartyOrderNoSaving.value = true
try {
const updated = await updateAdminPickupThirdPartyOrderNo(pickup.value.id, {
third_party_order_no: orderNo,
})
pickup.value = updated
processEvents.value = await fetchAdminPickupProcessEvents(pickup.value.id)
thirdPartyOrderNoDialogVisible.value = false
ElMessage.success('第三方单号已更新')
} catch (e: unknown) {
ElMessage.error(errorMessage(e) || '保存失败')
} finally {
thirdPartyOrderNoSaving.value = false
}
}
function statusType(status: string) {
if (status === 'picking_up') return 'warning'
if (status === 'completed') return 'success'
@@ -359,6 +393,15 @@ function readSnapshotResources(summary: Record<string, unknown> | null): Snapsho
</p>
</div>
<div class="toolbar-actions">
<el-button
v-if="canUpdateThirdPartyOrderNo"
type="primary"
plain
:icon="EditPen"
@click="openThirdPartyOrderNoDialog"
>
{{ pickup.third_party_order_no ? '修改单号' : '补录单号' }}
</el-button>
<el-button
v-if="canEditProfit"
type="primary"
@@ -726,6 +769,41 @@ function readSnapshotResources(summary: Record<string, unknown> | null): Snapsho
</el-button>
</template>
</el-dialog>
<!-- 补录/修改第三方单号 -->
<el-dialog
v-model="thirdPartyOrderNoDialogVisible"
:title="pickup?.third_party_order_no ? '修改第三方单号' : '补录第三方单号'"
width="460px"
>
<el-form :model="thirdPartyOrderNoForm" label-width="110px">
<el-form-item label="提号单号">
<span class="text-muted">{{ pickup?.pickup_no }}</span>
</el-form-item>
<el-form-item label="当前单号">
<span>{{ pickup?.third_party_order_no || '(未录入)' }}</span>
</el-form-item>
<el-form-item label="第三方单号" required>
<el-input
v-model="thirdPartyOrderNoForm.third_party_order_no"
placeholder="请输入淘宝/拼多多/外部订单号"
maxlength="128"
show-word-limit
clearable
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="thirdPartyOrderNoDialogVisible = false">取消</el-button>
<el-button
type="primary"
:loading="thirdPartyOrderNoSaving"
@click="handleSaveThirdPartyOrderNo"
>
保存
</el-button>
</template>
</el-dialog>
</section>
</template>
@@ -12,6 +12,7 @@ import {
fetchAdminPickupShopOptions,
fetchAvailableListings,
updateAdminPickupProfit,
updateAdminPickupThirdPartyOrderNo,
type AdminPickup,
type AvailableListing,
type AvailableListingSourceType,
@@ -48,11 +49,14 @@ const createDialogVisible = ref(false)
const completeDialogVisible = ref(false)
const profitDialogVisible = ref(false)
const financialAdjustmentDialogVisible = ref(false)
const thirdPartyOrderNoDialogVisible = ref(false)
const shopMgrVisible = ref(false)
const activePickupId = ref(0)
const activePickup = ref<AdminPickup | null>(null)
const profitSaving = ref(false)
const financialAdjustmentSaving = ref(false)
const thirdPartyOrderNoSaving = ref(false)
const thirdPartyOrderNoForm = reactive({ third_party_order_no: '' })
const createForm = reactive({
listing_id: null as number | null,
@@ -280,6 +284,41 @@ async function handleConfirmOfflineSettlement(row: AdminPickup) {
}
}
function openThirdPartyOrderNoDialog(row: AdminPickup) {
activePickupId.value = row.id
activePickup.value = row
thirdPartyOrderNoForm.third_party_order_no = row.third_party_order_no || ''
thirdPartyOrderNoDialogVisible.value = true
}
async function handleSaveThirdPartyOrderNo() {
const orderNo = thirdPartyOrderNoForm.third_party_order_no.trim()
if (!orderNo) {
ElMessage.warning('请输入第三方单号')
return
}
if (!activePickupId.value) return
thirdPartyOrderNoSaving.value = true
try {
const updated = await updateAdminPickupThirdPartyOrderNo(activePickupId.value, {
third_party_order_no: orderNo,
})
ElMessage.success('第三方单号已更新')
thirdPartyOrderNoDialogVisible.value = false
if (activePickup.value) {
activePickup.value.third_party_order_no = updated.third_party_order_no
}
const target = items.value.find(item => item.id === activePickupId.value)
if (target) {
target.third_party_order_no = updated.third_party_order_no
}
} catch (e: unknown) {
ElMessage.error(errorMessage(e) || '保存失败')
} finally {
thirdPartyOrderNoSaving.value = false
}
}
function openProfitDialog(row: AdminPickup) {
activePickupId.value = row.id
profitForm.profit_amount = centToYuan(row.profit_amount_cent)
@@ -605,6 +644,12 @@ function listingOptionLabel(item: AvailableListing) {
<span v-else class="text-muted">-</span>
</template>
</el-table-column>
<el-table-column label="提号备注" min-width="140" show-overflow-tooltip>
<template #default="{ row }">
<span v-if="row.remark">{{ row.remark }}</span>
<span v-else class="text-muted">-</span>
</template>
</el-table-column>
<el-table-column label="店铺名称" min-width="130">
<template #default="{ row }">{{ row.shop_name || '-' }}</template>
</el-table-column>
@@ -652,12 +697,22 @@ function listingOptionLabel(item: AvailableListing) {
<el-table-column label="创建时间" width="170">
<template #default="{ row }">{{ formatDateTime(row.created_at) }}</template>
</el-table-column>
<el-table-column label="操作" width="340" fixed="right">
<el-table-column label="操作" width="380" fixed="right">
<template #default="{ row }">
<div class="action-buttons">
<RouterLink :to="adminPath(`pickup/${row.id}`)">
<el-button size="small">详情</el-button>
</RouterLink>
<el-button
v-if="row.status !== 'cancelled'"
:type="row.third_party_order_no ? '' : 'warning'"
size="small"
plain
:icon="EditPen"
@click="openThirdPartyOrderNoDialog(row)"
>
{{ row.third_party_order_no ? '改单号' : '补录单号' }}
</el-button>
<el-button
v-if="row.status === 'picking_up'"
type="success"
@@ -1057,6 +1112,41 @@ function listingOptionLabel(item: AvailableListing) {
</el-button>
</template>
</el-dialog>
<!-- 补录/修改第三方单号 -->
<el-dialog
v-model="thirdPartyOrderNoDialogVisible"
:title="activePickup?.third_party_order_no ? '修改第三方单号' : '补录第三方单号'"
width="460px"
>
<el-form :model="thirdPartyOrderNoForm" label-width="110px">
<el-form-item label="提号单号">
<span class="text-muted">{{ activePickup?.pickup_no }}</span>
</el-form-item>
<el-form-item label="当前单号">
<span>{{ activePickup?.third_party_order_no || '(未录入)' }}</span>
</el-form-item>
<el-form-item label="第三方单号" required>
<el-input
v-model="thirdPartyOrderNoForm.third_party_order_no"
placeholder="请输入淘宝/拼多多/外部订单号"
maxlength="128"
show-word-limit
clearable
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="thirdPartyOrderNoDialogVisible = false">取消</el-button>
<el-button
type="primary"
:loading="thirdPartyOrderNoSaving"
@click="handleSaveThirdPartyOrderNo"
>
保存
</el-button>
</template>
</el-dialog>
</section>
</template>