58 lines
11 KiB
Vue
58 lines
11 KiB
Vue
<script setup lang="ts">
|
|
import { useExportTask } from '@/modules/downloads'
|
|
import '@/styles/adminDensity.css'
|
|
import { computed, onMounted, ref } from 'vue'
|
|
import { ArrowLeft, Download } from '@lucide/vue'
|
|
import { ElMessage } from 'element-plus'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
|
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
|
import AdminPage from '@/shared/components/AdminPage.vue'; import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'; import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'; import ListPageLayout from '@/shared/components/ListPageLayout.vue'; import LoadErrorState from '@/shared/components/LoadErrorState.vue'; import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
|
import InboundCodeRelationshipDialog from '@/shared/components/InboundCodeRelationshipDialog.vue'
|
|
import { listInventoryLedger } from '../api/inventory'; import { formatOverseasDateTime, inventoryBusinessTypeLabel } from '../lastMilePresentation'; import { overseasWarehousePermissions as permission } from '../permissions'; import type { InventoryTransactionListItem } from '../types'
|
|
|
|
const submitExport = useExportTask()
|
|
const route = useRoute(); const router = useRouter(); const access = useAccessPreviewStore(); const rows = ref<InventoryTransactionListItem[]>([]); const page = ref(1); const pageSize = ref(10); const total = ref(0); const loading = ref(false); const loadError = ref<ApiErrorDetails | null>(null)
|
|
const exportLoading = ref(false)
|
|
const relationshipDialogOpen = ref(false); const relationshipDialogInboundCode = ref('')
|
|
const filters = ref<QueryModel>({ occurredDate: [], customerName: '', warehouse: '', sku: '', businessType: '', businessOrderNo: '', inboundCode: '', inboundOrderNo: '', outboundOrderNo: '' })
|
|
const fields = computed<QueryField[]>(() => [
|
|
{ key: 'occurredDate', type: 'daterange', label: '发生日期', width: 260 },
|
|
{ key: 'customerName', type: 'input', label: '客户名称', placeholder: '请输入客户名称', width: 190 },
|
|
{ key: 'warehouse', type: 'input', label: '目的仓代码', placeholder: '请输入目的仓代码', width: 190 }, { key: 'sku', type: 'input', label: 'SKU编码', placeholder: '请输入 SKU 编码', width: 170 },
|
|
{ key: 'businessType', type: 'select', label: '业务类型', placeholder: '全部业务类型', width: 170, options: [
|
|
{ label: '在途入账', value: 'IN_TRANSIT' }, { label: '入库', value: 'STOCK_IN' }, { label: '库存暂扣', value: 'HOLD' }, { label: '解除暂扣', value: 'RELEASE' },
|
|
{ label: '库存分配', value: 'ALLOCATE' }, { label: '取消分配', value: 'UNALLOCATE' }, { label: '拣货', value: 'PICK' }, { label: '出库', value: 'SHIP' },
|
|
{ label: '库存调整', value: 'ADJUST' }, { label: '盘点调整', value: 'STOCKTAKE_ADJUST' }, { label: '组托', value: 'PALLET_ASSEMBLE' },
|
|
{ label: '拆托', value: 'PALLET_DISASSEMBLE' }, { label: '换托', value: 'PALLET_SWAP' }, { label: '解托', value: 'PALLET_UNBIND' },
|
|
] }, { key: 'businessOrderNo', type: 'input', label: '业务订单号', placeholder: '请输入业务订单号', width: 180 },
|
|
{ key: 'inboundCode', type: 'input', label: '入仓码', placeholder: '请输入入仓码', width: 190 }, { key: 'inboundOrderNo', type: 'input', label: '入库单号', placeholder: '请输入入库单号', width: 180 }, { key: 'outboundOrderNo', type: 'input', label: '出库单号', placeholder: '只读关联筛选', width: 180 },
|
|
])
|
|
const columns: DataTableColumn[] = [
|
|
{ key: 'actions', label: '操作', width: 108, fixed: 'left', slotName: 'actions' },
|
|
{ key: 'occurredAt', prop: 'occurredAt', label: '发生时间', minWidth: 160 }, { key: 'owner', prop: 'owner', label: '客户', minWidth: 160 }, { key: 'warehouse', prop: 'warehouse', label: '目的仓编码', minWidth: 180 },
|
|
{ key: 'sku', prop: 'sku', label: 'SKU编码', minWidth: 150 }, { key: 'productName', prop: 'productName', label: '中文品名', minWidth: 180 }, { key: 'businessType', prop: 'businessType', label: '业务类型', width: 120 },
|
|
{ key: 'businessOrderNo', prop: 'businessOrderNo', label: '业务订单号', minWidth: 170 }, { key: 'inboundCode', prop: 'inboundCode', label: '入仓码', minWidth: 170 }, { key: 'inboundOrderNo', prop: 'inboundOrderNo', label: '入库单号', minWidth: 160 }, { key: 'outboundOrderNo', prop: 'outboundOrderNo', label: '出库单号', minWidth: 160 },
|
|
{ key: 'inboundQuantity', prop: 'inboundQuantity', label: '入库数量', width: 110, align: 'right' }, { key: 'outboundQuantity', prop: 'outboundQuantity', label: '出库数量', width: 110, align: 'right' }, { key: 'balance', prop: 'balance', label: '结存', width: 100, align: 'right' },
|
|
{ key: 'operator', prop: 'operator', label: '操作人', minWidth: 120 }, { key: 'remark', prop: 'remark', label: '备注', minWidth: 180 },
|
|
]
|
|
function text(value: unknown) { return String(value ?? '').trim() || '—' }
|
|
function openRelationship(row: InventoryTransactionListItem) { if (row.inboundCode === '—') return; relationshipDialogInboundCode.value = row.inboundCode; relationshipDialogOpen.value = true }
|
|
async function load(model: QueryModel = filters.value) { Object.assign(filters.value, model); const range = Array.isArray(filters.value.occurredDate) ? filters.value.occurredDate.map(String) : []; loading.value = true; loadError.value = null; try { const result = await listInventoryLedger({ page: page.value, size: pageSize.value, customerName: String(filters.value.customerName || '').trim() || undefined, destinationWarehouseCode: String(filters.value.warehouse || '').trim() || undefined, skuCode: String(filters.value.sku || '').trim() || undefined, businessType: String(filters.value.businessType || '').trim() || undefined, businessOrderNo: String(filters.value.businessOrderNo || '').trim() || undefined, inboundCode: String(filters.value.inboundCode || '').trim() || undefined, inboundOrderNo: String(filters.value.inboundOrderNo || '').trim() || undefined, outboundOrderNo: String(filters.value.outboundOrderNo || '').trim() || undefined, occurredFrom: range[0] ? `${range[0]}T00:00:00` : undefined, occurredTo: range[1] ? `${range[1]}T23:59:59` : undefined }); rows.value = result.records.map((item) => ({ id: String(item.id), occurredAt: formatOverseasDateTime(item.occurredAt), owner: text(item.customerName), warehouse: text(item.destinationWarehouseCode), sku: text(item.skuCode), productName: '—', businessType: inventoryBusinessTypeLabel(item.businessType), businessOrderNo: text(item.businessOrderNo), inboundCode: text(item.inboundCode), inboundOrderNo: text(item.inboundOrderNo), outboundOrderNo: text(item.outboundOrderNo), inboundQuantity: item.deltaPackages > 0 ? item.deltaPackages : 0, outboundQuantity: item.deltaPackages < 0 ? Math.abs(item.deltaPackages) : 0, balance: Number(item.afterPackages || 0), operator: '—', remark: text(item.remark) })); total.value = result.total } catch (error) { rows.value = []; total.value = 0; loadError.value = getApiErrorDetails(error, '进销存记录加载失败,请重试') } finally { loading.value = false } }
|
|
function search(model: QueryModel) { page.value = 1; void load(model) }; function reset(model: QueryModel) { page.value = 1; void load(model) }; function back() { void router.push({ name: 'overseas-inventory' }) }; onMounted(load)
|
|
async function exportLedger() { exportLoading.value = true; try { const range = Array.isArray(filters.value.occurredDate) ? filters.value.occurredDate.map(String) : []; await submitExport('OVERSEAS_INVENTORY_LEDGER', '进销存记录', { customerName: String(filters.value.customerName || '').trim() || undefined, destinationWarehouseCode: String(filters.value.warehouse || '').trim() || undefined, skuCode: String(filters.value.sku || '').trim() || undefined, businessType: String(filters.value.businessType || '').trim() || undefined, businessOrderNo: String(filters.value.businessOrderNo || '').trim() || undefined, inboundCode: String(filters.value.inboundCode || '').trim() || undefined, inboundOrderNo: String(filters.value.inboundOrderNo || '').trim() || undefined, outboundOrderNo: String(filters.value.outboundOrderNo || '').trim() || undefined, occurredFrom: range[0] ? `${range[0]}T00:00:00` : undefined, occurredTo: range[1] ? `${range[1]}T23:59:59` : undefined }) } catch { ElMessage.error('进销存导出失败,请重试') } finally { exportLoading.value = false } }
|
|
</script>
|
|
|
|
<template><AdminPage class="admin-density"><ListPageLayout aria-label="进销存记录列表">
|
|
|
|
|
|
<section><DataTable appearance="integrated" :stripe="false" column-settings-mode="show" :results-visible="!loadError" v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :loading="loading" :total="total" preference-key="overseas-inventory-transactions" row-key="id" empty-text="暂无进销存记录" @update:page="load()" @update:page-size="page = 1; load()">
|
|
<template #toolbar-start><h1>进销存记录</h1></template>
|
|
<template #filters><QueryToolbar v-model="filters" :fields="fields" :loading="loading" ariaLabel="进销存记录筛选" preference-key="overseas-inventory-transactions-query" :search-on-reset="false" @search="search" @reset="reset" /></template>
|
|
<template #notices><template v-if="loadError"><LoadErrorState title="进销存记录加载失败" :message="loadError.message" :loading="loading" @retry="load"><template #details><ApiErrorMeta :details="loadError" /></template></LoadErrorState></template>
|
|
</template>
|
|
|
|
<template #toolbar-actions><el-button v-if="access.can(permission.inventoryExport) && access.can('platform:download:list')" plain :loading="exportLoading" @click="exportLedger"><Download :size="16" />导出记录</el-button><el-button class="density-back" link @click="back"><ArrowLeft :size="16" />返回库存管理</el-button></template><template #actions="{ row }"><div class="density-actions row-actions admin-text-actions"><el-button class="density-action" data-tone="neutral" :disabled="(row as InventoryTransactionListItem).inboundCode === '—'" @click="openRelationship(row as InventoryTransactionListItem)">关联数据</el-button></div></template><template #pagination-left>共 {{ total }} 条进销存记录</template></DataTable></section>
|
|
<InboundCodeRelationshipDialog dense v-if="relationshipDialogOpen" v-model="relationshipDialogOpen" :inbound-code="relationshipDialogInboundCode" :can-read-base="access.can('platform:order:list')" :can-read-loading="access.can('platform:firstleg:smart-loading:list')" :can-read-overseas="access.can('platform:overseas-warehouse:inventory:list')" />
|
|
</ListPageLayout></AdminPage></template>
|