598 lines
22 KiB
Vue
598 lines
22 KiB
Vue
<script setup lang="ts">
|
||
import { computed, onMounted, reactive, ref } from 'vue'
|
||
import { useI18n } from 'vue-i18n'
|
||
import { Modal } from '@arco-design/web-vue'
|
||
import HandsontablePro from '@/components/HandsontablePro/index.vue'
|
||
import PaginationPro from '@/components/PaginationPro/index.vue'
|
||
import ModalPro from '@/components/ModalPro/index.vue'
|
||
import useModal from '@/components/ModalPro/useModal'
|
||
import { useTableContainerHeight } from '@/composables/useTableContainerHeight'
|
||
import {
|
||
deleteWarehouseInbound,
|
||
getWarehouseInboundDetail,
|
||
getWarehouseInboundList,
|
||
getWarehouseInboundSummary,
|
||
saveWarehouseInbound,
|
||
} from '@/api/warehouse'
|
||
import { getWarehouseList } from '@/api/system/warehouse'
|
||
import { getWarehouseSkuList } from '@/api/warehouse'
|
||
import { $baseMessage } from '@/utils'
|
||
import { hasPermission } from '@/utils/rbac-permission'
|
||
import {
|
||
buildWarehouseNameMap,
|
||
formatDateTime,
|
||
normalizeListRow,
|
||
pickField,
|
||
resolveWarehouseLabel,
|
||
} from '@/utils/warehouseListMapper'
|
||
|
||
defineOptions({ name: 'WarehouseInboundNotice' })
|
||
|
||
interface InboundLineForm {
|
||
skuId?: number
|
||
skuCode: string
|
||
plannedQty: number
|
||
}
|
||
|
||
interface InboundBoxForm {
|
||
key: string
|
||
boxSeqNo: string
|
||
markBoxNo: string
|
||
weightG?: number
|
||
lengthCm?: number
|
||
widthCm?: number
|
||
heightCm?: number
|
||
lines: InboundLineForm[]
|
||
}
|
||
|
||
const { t } = useI18n()
|
||
const { tableContainerRef, tableHeight } = useTableContainerHeight()
|
||
|
||
const receiptStatus = ref<string>()
|
||
const summary = ref({ forecasted: 0, received: 0, completed: 0 })
|
||
const keyword = ref('')
|
||
const warehouseId = ref<number>()
|
||
const warehouseOptions = ref<Array<{ label: string; value: number }>>([])
|
||
const warehouseNameMap = computed(() => buildWarehouseNameMap(warehouseOptions.value))
|
||
const skuOptions = ref<Array<{ label: string; value: number; code: string }>>([])
|
||
const listLoading = ref(false)
|
||
const tableRows = ref<any[]>([])
|
||
const currentPage = ref(1)
|
||
const pageSize = ref(30)
|
||
const totalCount = ref(0)
|
||
const selectedBoxKeys = ref<string[]>([])
|
||
const activeBoxKey = ref('')
|
||
|
||
const statusTabs = [
|
||
{ value: undefined, labelKey: 'warehouse.inbound.status.all', countKey: null },
|
||
{ value: 'forecasted', labelKey: 'warehouse.inbound.status.forecasted', countKey: 'forecasted' as const },
|
||
{ value: 'received', labelKey: 'warehouse.inbound.status.received', countKey: 'received' as const },
|
||
{ value: 'completed', labelKey: 'warehouse.inbound.status.completed', countKey: 'completed' as const },
|
||
]
|
||
|
||
const detailVisible = ref(false)
|
||
const detailData = ref<any>(null)
|
||
|
||
const [registerFormModal, { openModal, closeModal }] = useModal() as any
|
||
const saving = ref(false)
|
||
const formModel = reactive({
|
||
id: 0,
|
||
warehouseId: undefined as number | undefined,
|
||
markReference: '',
|
||
inboundType: 'normal',
|
||
remark: '',
|
||
})
|
||
const boxRows = ref<InboundBoxForm[]>([])
|
||
|
||
const modalWarehouseName = computed(() => {
|
||
const wh = warehouseOptions.value.find((w) => w.value === formModel.warehouseId)
|
||
return wh?.label || ''
|
||
})
|
||
|
||
const boxCount = computed(() => boxRows.value.length)
|
||
const totalSkuCount = computed(() =>
|
||
boxRows.value.reduce((sum, box) => sum + box.lines.filter((l) => l.skuId).length, 0),
|
||
)
|
||
const totalPlannedQty = computed(() =>
|
||
boxRows.value.reduce(
|
||
(sum, box) => sum + box.lines.reduce((s, line) => s + (Number(line.plannedQty) || 0), 0),
|
||
0,
|
||
),
|
||
)
|
||
|
||
const hotColumns = computed(() => [
|
||
{ key: 'noticeNo', label: t('warehouse.inbound.table.noticeNo'), width: 180 },
|
||
{ key: 'markReference', label: t('warehouse.inbound.table.markReference'), width: 120 },
|
||
{ key: 'warehouseName', label: t('warehouse.inbound.table.warehouse'), width: 140 },
|
||
{ key: 'inboundType', label: t('warehouse.inbound.table.inboundType'), width: 100 },
|
||
{ key: 'receiptStatus', label: t('warehouse.inbound.table.receiptStatus'), width: 100 },
|
||
{ key: 'boxCount', label: t('warehouse.inbound.table.boxCount'), width: 80 },
|
||
{ key: 'plannedQty', label: t('warehouse.inbound.table.plannedQty'), width: 90 },
|
||
{ key: 'expectedArrivalTime', label: t('warehouse.inbound.table.expectedArrival'), width: 160 },
|
||
{ key: 'createTime', label: t('warehouse.inbound.table.createTime'), width: 160 },
|
||
])
|
||
|
||
function createBox(seq: number): InboundBoxForm {
|
||
return {
|
||
key: `box-${Date.now()}-${seq}`,
|
||
boxSeqNo: String(seq),
|
||
markBoxNo: `BOX-${String(seq).padStart(3, '0')}`,
|
||
lines: [{ skuId: undefined, skuCode: '', plannedQty: 1 }],
|
||
}
|
||
}
|
||
|
||
function resetBoxes() {
|
||
const first = createBox(1)
|
||
boxRows.value = [first]
|
||
selectedBoxKeys.value = []
|
||
activeBoxKey.value = first.key
|
||
}
|
||
|
||
function addBox() {
|
||
const next = boxRows.value.length + 1
|
||
const box = createBox(next)
|
||
boxRows.value = [...boxRows.value, box]
|
||
activeBoxKey.value = box.key
|
||
}
|
||
|
||
function addBoxes(count: number) {
|
||
const start = boxRows.value.length
|
||
const added = Array.from({ length: count }, (_, i) => createBox(start + i + 1))
|
||
boxRows.value = [...boxRows.value, ...added]
|
||
if (added.length) activeBoxKey.value = added[added.length - 1].key
|
||
}
|
||
|
||
function removeActiveBox() {
|
||
if (boxRows.value.length <= 1) return
|
||
const key = activeBoxKey.value
|
||
const remain = boxRows.value.filter((b) => b.key !== key)
|
||
boxRows.value = remain
|
||
selectedBoxKeys.value = selectedBoxKeys.value.filter((k) => k !== key)
|
||
activeBoxKey.value = remain[remain.length - 1]?.key || ''
|
||
}
|
||
|
||
function removeSelectedBoxes() {
|
||
if (!selectedBoxKeys.value.length) {
|
||
removeActiveBox()
|
||
return
|
||
}
|
||
const remain = boxRows.value.filter((b) => !selectedBoxKeys.value.includes(b.key))
|
||
boxRows.value = remain.length ? remain : [createBox(1)]
|
||
selectedBoxKeys.value = []
|
||
activeBoxKey.value = boxRows.value[boxRows.value.length - 1].key
|
||
}
|
||
|
||
function addLine(box: InboundBoxForm) {
|
||
box.lines.push({ skuId: undefined, skuCode: '', plannedQty: 1 })
|
||
}
|
||
|
||
function removeLine(box: InboundBoxForm, index: number) {
|
||
if (box.lines.length <= 1) return
|
||
box.lines.splice(index, 1)
|
||
}
|
||
|
||
function onSkuChange(line: InboundLineForm, skuId?: number) {
|
||
const sku = skuOptions.value.find((s) => s.value === skuId)
|
||
line.skuId = skuId
|
||
line.skuCode = sku?.code || ''
|
||
}
|
||
|
||
function mapRow(raw: Record<string, unknown>) {
|
||
const row = normalizeListRow(raw)
|
||
const status = String(pickField(row, 'receiptStatus', 'ReceiptStatus') ?? '')
|
||
const inboundType = String(pickField(row, 'inboundType', 'InboundType') ?? 'normal')
|
||
const whId = pickField<number>(row, 'warehouseId', 'WarehouseId')
|
||
return {
|
||
id: pickField<number>(row, 'id', 'Id'),
|
||
noticeNo: pickField(row, 'noticeNo', 'NoticeNo') ?? '-',
|
||
markReference: pickField(row, 'markReference', 'MarkReference') ?? '-',
|
||
warehouseName: resolveWarehouseLabel(whId, warehouseNameMap.value),
|
||
inboundType: t(`warehouse.inbound.type.${inboundType}`, inboundType),
|
||
receiptStatus: t(`warehouse.inbound.status.${status}`, status),
|
||
boxCount: pickField<number>(row, 'boxCount', 'BoxCount') ?? 0,
|
||
plannedQty: pickField<number>(row, 'plannedQty', 'PlannedQty') ?? 0,
|
||
expectedArrivalTime: formatDateTime(pickField(row, 'expectedArrivalTime', 'ExpectedArrivalTime')),
|
||
createTime: formatDateTime(pickField(row, 'createTime', 'CreateTime')),
|
||
_raw: row,
|
||
_status: status,
|
||
}
|
||
}
|
||
|
||
async function loadWarehouses() {
|
||
const { items } = await getWarehouseList({ page: 1, pageSize: 200 }).catch(() => ({ items: [] }))
|
||
warehouseOptions.value = (items || []).map((w: any) => ({
|
||
label: w.warehouseName || `#${w.id}`,
|
||
value: Number(w.id),
|
||
}))
|
||
}
|
||
|
||
async function loadSkus() {
|
||
const { items } = await getWarehouseSkuList({ page: 1, pageSize: 500 }).catch(() => ({ items: [] }))
|
||
skuOptions.value = (items || []).map((s: any) => ({
|
||
label: `${s.skuCode || s.SkuCode} - ${s.skuName || s.SkuName}`,
|
||
value: Number(s.id || s.Id),
|
||
code: s.skuCode || s.SkuCode,
|
||
}))
|
||
}
|
||
|
||
async function loadSummary() {
|
||
try {
|
||
const data = await getWarehouseInboundSummary({ warehouseId: warehouseId.value })
|
||
summary.value = {
|
||
forecasted: data?.forecasted ?? data?.Forecasted ?? 0,
|
||
received: data?.received ?? data?.Received ?? 0,
|
||
completed: data?.completed ?? data?.Completed ?? 0,
|
||
}
|
||
} catch {
|
||
summary.value = { forecasted: 0, received: 0, completed: 0 }
|
||
}
|
||
}
|
||
|
||
async function loadList() {
|
||
listLoading.value = true
|
||
try {
|
||
const { items, total } = await getWarehouseInboundList({
|
||
page: currentPage.value,
|
||
pageSize: pageSize.value,
|
||
receiptStatus: receiptStatus.value,
|
||
keyword: keyword.value || undefined,
|
||
warehouseId: warehouseId.value,
|
||
})
|
||
tableRows.value = (items || []).map((item: Record<string, unknown>) => mapRow(item))
|
||
totalCount.value = Number(total || 0)
|
||
} catch (e: any) {
|
||
$baseMessage(e?.message || t('warehouse.inbound.message.loadFailed'), 'error')
|
||
} finally {
|
||
listLoading.value = false
|
||
}
|
||
}
|
||
|
||
function handlePageChange(page: number) {
|
||
currentPage.value = page
|
||
loadList()
|
||
}
|
||
|
||
function handlePageSizeChange(size: number) {
|
||
pageSize.value = size
|
||
currentPage.value = 1
|
||
loadList()
|
||
}
|
||
|
||
function handleSearch() {
|
||
currentPage.value = 1
|
||
loadList()
|
||
}
|
||
|
||
async function showDetail(row: any) {
|
||
try {
|
||
detailData.value = await getWarehouseInboundDetail(row._raw?.id || row.id)
|
||
detailVisible.value = true
|
||
} catch (e: any) {
|
||
$baseMessage(e?.message || t('warehouse.inbound.message.detailFailed'), 'error')
|
||
}
|
||
}
|
||
|
||
function handleAdd() {
|
||
if (!hasPermission('Warehouse.InboundNotice.Save')) return
|
||
formModel.id = 0
|
||
formModel.warehouseId = warehouseId.value
|
||
formModel.markReference = ''
|
||
formModel.remark = ''
|
||
formModel.inboundType = 'normal'
|
||
resetBoxes()
|
||
openModal(true)
|
||
}
|
||
|
||
async function handleSave() {
|
||
if (!formModel.warehouseId) {
|
||
$baseMessage(t('warehouse.inbound.message.required'), 'warning')
|
||
return
|
||
}
|
||
const boxes = boxRows.value
|
||
.map((box) => ({
|
||
boxSeqNo: box.boxSeqNo,
|
||
markBoxNo: box.markBoxNo,
|
||
weightG: box.weightG,
|
||
lengthCm: box.lengthCm,
|
||
widthCm: box.widthCm,
|
||
heightCm: box.heightCm,
|
||
lines: box.lines
|
||
.filter((line) => line.skuId)
|
||
.map((line) => ({
|
||
skuId: line.skuId!,
|
||
skuCode: line.skuCode,
|
||
plannedQty: Number(line.plannedQty) || 1,
|
||
})),
|
||
}))
|
||
.filter((box) => box.lines.length > 0)
|
||
|
||
if (!boxes.length) {
|
||
$baseMessage(t('warehouse.inbound.message.boxRequired'), 'warning')
|
||
return
|
||
}
|
||
|
||
saving.value = true
|
||
try {
|
||
await saveWarehouseInbound({
|
||
id: formModel.id,
|
||
warehouseId: formModel.warehouseId,
|
||
markReference: formModel.markReference,
|
||
inboundType: formModel.inboundType,
|
||
remark: formModel.remark,
|
||
boxes,
|
||
})
|
||
$baseMessage(t('warehouse.inbound.message.saveSuccess'), 'success')
|
||
closeModal()
|
||
await loadSummary()
|
||
await loadList()
|
||
} catch (e: any) {
|
||
$baseMessage(e?.message || t('warehouse.inbound.message.saveFailed'), 'error')
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
function handleDelete(row: any) {
|
||
if (!hasPermission('Warehouse.InboundNotice.Delete')) return
|
||
Modal.confirm({
|
||
title: t('warehouse.inbound.actions.delete'),
|
||
content: row.noticeNo,
|
||
onOk: async () => {
|
||
await deleteWarehouseInbound(row._raw?.id || row.id)
|
||
$baseMessage(t('warehouse.inbound.message.deleteSuccess'), 'success')
|
||
await loadSummary()
|
||
await loadList()
|
||
},
|
||
})
|
||
}
|
||
|
||
function actionRenderer(row: any) {
|
||
const parts = [`<button type="button" class="hot-action-btn" data-action="detail">${t('warehouse.common.detail')}</button>`]
|
||
if (hasPermission('Warehouse.InboundNotice.Delete') && row._status === 'forecasted') {
|
||
parts.push(`<button type="button" class="hot-action-btn" data-action="delete">${t('warehouse.common.delete')}</button>`)
|
||
}
|
||
return parts.join('')
|
||
}
|
||
|
||
function handleActionClick(row: any, _i: number, action?: string) {
|
||
if (action === 'detail') showDetail(row)
|
||
if (action === 'delete') handleDelete(row)
|
||
}
|
||
|
||
onMounted(async () => {
|
||
await loadWarehouses()
|
||
await loadSkus()
|
||
await loadSummary()
|
||
await loadList()
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div class="warehouse-inbound-container warehouse-list-page">
|
||
<div class="warehouse-list-page-card">
|
||
<a-tabs
|
||
v-model:active-key="receiptStatus"
|
||
class="status-tabs"
|
||
@change="() => { currentPage = 1; loadList() }"
|
||
>
|
||
<a-tab-pane v-for="tab in statusTabs" :key="tab.value ?? 'all'">
|
||
<template #title>
|
||
{{ t(tab.labelKey) }}
|
||
<span v-if="tab.countKey" class="tab-count">({{ summary[tab.countKey] }})</span>
|
||
</template>
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
<div class="table-toolbar">
|
||
<div class="toolbar-left">
|
||
<a-space wrap :size="8">
|
||
<a-select
|
||
v-model="warehouseId"
|
||
allow-clear
|
||
:placeholder="t('warehouse.common.warehouse')"
|
||
:options="warehouseOptions"
|
||
style="width: 200px"
|
||
@change="() => { loadSummary(); handleSearch() }"
|
||
/>
|
||
<a-input
|
||
v-model="keyword"
|
||
allow-clear
|
||
:placeholder="t('warehouse.inbound.search.keyword')"
|
||
style="width: 200px"
|
||
@press-enter="handleSearch"
|
||
/>
|
||
<a-button type="primary" @click="handleSearch">{{ t('warehouse.common.search') }}</a-button>
|
||
<a-button v-if="hasPermission('Warehouse.InboundNotice.Save')" type="primary" @click="handleAdd">
|
||
{{ t('warehouse.common.add') }}
|
||
</a-button>
|
||
</a-space>
|
||
</div>
|
||
<div class="toolbar-right">
|
||
<PaginationPro
|
||
:total-count="totalCount"
|
||
v-model:current-page="currentPage"
|
||
v-model:page-size="pageSize"
|
||
:page-sizes="[10, 30, 50, 100]"
|
||
@page-change="handlePageChange"
|
||
@page-size-change="handlePageSizeChange"
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div ref="tableContainerRef" class="list-wrap">
|
||
<HandsontablePro
|
||
:columns="hotColumns"
|
||
:data="tableRows"
|
||
:height="tableHeight"
|
||
:loading="listLoading"
|
||
:stretch-columns="true"
|
||
show-action-column
|
||
:action-renderer="actionRenderer"
|
||
@action-click="handleActionClick"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<a-drawer v-model:visible="detailVisible" :title="t('warehouse.inbound.drawer.detail')" :width="640">
|
||
<template v-if="detailData">
|
||
<p>{{ t('warehouse.inbound.table.noticeNo') }}: {{ detailData.noticeNo }}</p>
|
||
<p>{{ t('warehouse.inbound.table.markReference') }}: {{ detailData.markReference || '-' }}</p>
|
||
<div v-for="box in detailData.boxes || []" :key="box.id" class="box-block">
|
||
<div class="box-title">{{ t('warehouse.inbound.box') }}: {{ box.markBoxNo || box.boxSeqNo }}</div>
|
||
<a-table :data="box.lines || []" :pagination="false" size="small">
|
||
<template #columns>
|
||
<a-table-column :title="t('warehouse.inbound.line.skuCode')" data-index="skuCode" />
|
||
<a-table-column :title="t('warehouse.inbound.line.plannedQty')" data-index="plannedQty" />
|
||
<a-table-column :title="t('warehouse.inbound.line.receivedQty')" data-index="receivedQty" />
|
||
</template>
|
||
</a-table>
|
||
</div>
|
||
</template>
|
||
</a-drawer>
|
||
|
||
<ModalPro
|
||
:title="t('warehouse.inbound.modal.add')"
|
||
:width="800"
|
||
:mask-closable="false"
|
||
:body-style="{ maxHeight: '70vh', overflow: 'auto' }"
|
||
@register="registerFormModal"
|
||
@cancel="closeModal"
|
||
>
|
||
<div class="wh-form-modal">
|
||
<a-form
|
||
:model="formModel"
|
||
layout="horizontal"
|
||
:label-col-props="{ span: 6 }"
|
||
:wrapper-col-props="{ span: 16 }"
|
||
>
|
||
<a-form-item :label="t('warehouse.common.warehouse')" required>
|
||
<a-select v-model="formModel.warehouseId" :options="warehouseOptions" allow-search />
|
||
</a-form-item>
|
||
<a-form-item :label="t('warehouse.inbound.form.markReference')">
|
||
<a-input v-model="formModel.markReference" :placeholder="t('warehouse.inbound.form.markPlaceholder')" allow-clear />
|
||
</a-form-item>
|
||
<a-form-item :label="t('warehouse.inbound.table.inboundType')">
|
||
<a-select v-model="formModel.inboundType">
|
||
<a-option value="normal">{{ t('warehouse.inbound.type.normal') }}</a-option>
|
||
<a-option value="return">{{ t('warehouse.inbound.type.return') }}</a-option>
|
||
</a-select>
|
||
</a-form-item>
|
||
<a-form-item :label="t('warehouse.parcel.form.remark')">
|
||
<a-input v-model="formModel.remark" allow-clear />
|
||
</a-form-item>
|
||
</a-form>
|
||
|
||
<a-divider class="wh-form-divider" />
|
||
|
||
<div class="wh-form-section__head">
|
||
<div class="wh-form-section__title">{{ t('warehouse.inbound.form.boxSkuDetail') }}</div>
|
||
<div class="wh-form-meta">
|
||
<a-tag color="arcoblue">{{ t('warehouse.inbound.form.boxCount', { n: boxCount }) }}</a-tag>
|
||
<a-tag color="green">{{ t('warehouse.inbound.form.skuCount', { n: totalSkuCount }) }}</a-tag>
|
||
<a-tag color="purple">{{ t('warehouse.inbound.form.totalQty', { n: totalPlannedQty }) }}</a-tag>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wh-form-toolbar">
|
||
<a-button type="primary" size="small" @click="addBox">{{ t('warehouse.inbound.actions.addBox') }}</a-button>
|
||
<a-button size="small" @click="addBoxes(5)">{{ t('warehouse.inbound.actions.addBox5') }}</a-button>
|
||
<a-button size="small" status="danger" @click="removeSelectedBoxes">{{ t('warehouse.inbound.actions.removeBox') }}</a-button>
|
||
</div>
|
||
|
||
<a-tabs v-model:active-key="activeBoxKey" type="rounded" size="small">
|
||
<a-tab-pane v-for="box in boxRows" :key="box.key" :title="`${t('warehouse.inbound.box')} ${box.boxSeqNo}`">
|
||
<div class="wh-form-box-panel">
|
||
<a-row :gutter="12">
|
||
<a-col :span="8">
|
||
<a-form-item :label="t('warehouse.inbound.form.markBoxNo')" :label-col-props="{ span: 24 }">
|
||
<a-input v-model="box.markBoxNo" allow-clear />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="4">
|
||
<a-form-item :label="t('warehouse.inbound.form.boxWeight')" :label-col-props="{ span: 24 }">
|
||
<a-input-number v-model="box.weightG" :min="0" style="width: 100%" />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="4">
|
||
<a-form-item :label="t('warehouse.inbound.form.boxLength')" :label-col-props="{ span: 24 }">
|
||
<a-input-number v-model="box.lengthCm" :min="0" style="width: 100%" />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="4">
|
||
<a-form-item :label="t('warehouse.inbound.form.boxWidth')" :label-col-props="{ span: 24 }">
|
||
<a-input-number v-model="box.widthCm" :min="0" style="width: 100%" />
|
||
</a-form-item>
|
||
</a-col>
|
||
<a-col :span="4">
|
||
<a-form-item :label="t('warehouse.inbound.form.boxHeight')" :label-col-props="{ span: 24 }">
|
||
<a-input-number v-model="box.heightCm" :min="0" style="width: 100%" />
|
||
</a-form-item>
|
||
</a-col>
|
||
</a-row>
|
||
|
||
<div class="wh-form-toolbar">
|
||
<a-button type="primary" size="small" @click="addLine(box)">{{ t('warehouse.inbound.actions.addSku') }}</a-button>
|
||
</div>
|
||
|
||
<a-table :data="box.lines" :pagination="false" size="small" :bordered="{ cell: true }">
|
||
<template #columns>
|
||
<a-table-column :title="t('warehouse.inbound.form.sku')">
|
||
<template #cell="{ record }">
|
||
<a-select
|
||
v-model="record.skuId"
|
||
:options="skuOptions"
|
||
allow-search
|
||
:placeholder="t('warehouse.inbound.form.selectSku')"
|
||
@change="(v: number) => onSkuChange(record, v)"
|
||
/>
|
||
</template>
|
||
</a-table-column>
|
||
<a-table-column :title="t('warehouse.inbound.line.plannedQty')" :width="130">
|
||
<template #cell="{ record }">
|
||
<a-input-number v-model="record.plannedQty" :min="1" style="width: 100%" />
|
||
</template>
|
||
</a-table-column>
|
||
<a-table-column :title="t('warehouse.common.delete')" :width="72" align="center">
|
||
<template #cell="{ rowIndex }">
|
||
<a-button type="text" status="danger" size="small" @click="removeLine(box, rowIndex)">
|
||
{{ t('warehouse.common.delete') }}
|
||
</a-button>
|
||
</template>
|
||
</a-table-column>
|
||
</template>
|
||
</a-table>
|
||
</div>
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
|
||
<a-alert
|
||
v-if="formModel.warehouseId && modalWarehouseName"
|
||
type="info"
|
||
:show-icon="true"
|
||
class="wh-form-divider"
|
||
>
|
||
{{ t('warehouse.common.warehouse') }}:{{ modalWarehouseName }}
|
||
</a-alert>
|
||
</div>
|
||
|
||
<template #footer>
|
||
<a-space :size="8">
|
||
<a-button @click="closeModal">{{ t('warehouse.common.cancel') }}</a-button>
|
||
<a-button type="primary" :loading="saving" @click="handleSave">{{ t('warehouse.common.save') }}</a-button>
|
||
</a-space>
|
||
</template>
|
||
</ModalPro>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped lang="less">
|
||
@import '@/styles/warehouse-list-page.less';
|
||
@import '@/styles/warehouse-form-modal.less';
|
||
|
||
.box-block {
|
||
margin-bottom: 16px;
|
||
}
|
||
.box-title {
|
||
font-weight: 500;
|
||
margin-bottom: 8px;
|
||
}
|
||
</style>
|