查价参考价提示与可选尺寸;下单尺寸必填及查价带入;待排货状态展示;货物属性/启用状态工具化及相关页面更新。 Co-authored-by: Cursor <cursoragent@cursor.com>
735 lines
26 KiB
Vue
735 lines
26 KiB
Vue
<script setup lang="ts">
|
||
import { computed, onMounted, ref, watch } from 'vue'
|
||
import { useRoute } from 'vue-router'
|
||
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 { useTableContainerHeight } from '@/composables/useTableContainerHeight'
|
||
import { useWarehouseAdminCustomer } from '@/composables/useWarehouseAdminCustomer'
|
||
import { getSalesProductList } from '@/api/channel/salesProduct'
|
||
import {
|
||
batchMatchPlatformStoreOrderInventory,
|
||
deletePlatformStoreOrder,
|
||
fetchPlatformStoreOrderLabel,
|
||
getPlatformStoreOrderList,
|
||
getPlatformStoreOrderSummary,
|
||
matchPlatformStoreOrderInventory,
|
||
readyToShipPlatformStoreOrder,
|
||
syncPlatformStoreOrderStatus,
|
||
togglePlatformStoreOrderSuspend,
|
||
} from '@/api/order/platformStore'
|
||
import { getWarehouseList } from '@/api/system/warehouse'
|
||
import { $baseMessage } from '@/utils'
|
||
import { hasPermission } from '@/utils/rbac-permission'
|
||
import {
|
||
buildWarehouseNameMap,
|
||
formatDateTime,
|
||
formatMoney,
|
||
normalizeListRow,
|
||
pickField,
|
||
resolveWarehouseLabel,
|
||
} from '@/utils/warehouseListMapper'
|
||
import { renderWarehouseActionBtn, wrapWarehouseActions } from '@/utils/warehouseActionRenderer'
|
||
import PullOrdersModal from './PullOrdersModal.vue'
|
||
import StoreOrderDetailDrawer from './StoreOrderDetailDrawer.vue'
|
||
import CreateLogisticsModal, { type CreateLogisticsMode } from './CreateLogisticsModal.vue'
|
||
|
||
defineOptions({ name: 'PlatformStoreOrder' })
|
||
|
||
const { t } = useI18n()
|
||
const route = useRoute()
|
||
const { tableContainerRef, tableHeight } = useTableContainerHeight()
|
||
const {
|
||
isAdmin,
|
||
customerId: adminCustomerId,
|
||
customerOptions,
|
||
withCustomerId,
|
||
ensureMutationCustomerId,
|
||
} = useWarehouseAdminCustomer()
|
||
|
||
/** Tab active-key;全部用 'all',请求时再转成不传 fulfillStatus */
|
||
const STATUS_TAB_ALL = 'all'
|
||
const ALLOWED_FULFILL_STATUS = new Set(['pending', 'toShip', 'shipped', 'canceled', 'completed'])
|
||
|
||
function resolveFulfillStatusFromQuery(): string {
|
||
const raw = route.query.fulfillStatus
|
||
const value = Array.isArray(raw) ? raw[0] : raw
|
||
if (typeof value === 'string' && ALLOWED_FULFILL_STATUS.has(value)) {
|
||
return value
|
||
}
|
||
return STATUS_TAB_ALL
|
||
}
|
||
|
||
const fulfillStatus = ref<string>(resolveFulfillStatusFromQuery())
|
||
const keyword = ref('')
|
||
const summary = ref<Record<string, number>>({})
|
||
const warehouseOptions = ref<Array<{ label: string; value: number }>>([])
|
||
const warehouseNameMap = computed(() => buildWarehouseNameMap(warehouseOptions.value))
|
||
const productOptions = ref<Array<{ label: string; value: string }>>([])
|
||
const listLoading = ref(false)
|
||
const tableRows = ref<any[]>([])
|
||
const selectedRows = ref<any[]>([])
|
||
const currentPage = ref(1)
|
||
const pageSize = ref(30)
|
||
const totalCount = ref(0)
|
||
const pullVisible = ref(false)
|
||
const actionLoading = ref(false)
|
||
const matchWarehouseId = ref<number>()
|
||
const matchProductCode = ref<string>()
|
||
const detailDrawerRef = ref<InstanceType<typeof StoreOrderDetailDrawer>>()
|
||
const createModalVisible = ref(false)
|
||
const createModalMode = ref<CreateLogisticsMode>('logistics')
|
||
const createModalIds = ref<number[]>([])
|
||
|
||
const statusTabs = [
|
||
{ value: STATUS_TAB_ALL, labelKey: 'order.platformStoreOrder.status.all', countKey: null },
|
||
{ value: 'pending', labelKey: 'order.platformStoreOrder.status.pending', countKey: 'pending' as const },
|
||
{ value: 'toShip', labelKey: 'order.platformStoreOrder.status.toShip', countKey: 'toShip' as const },
|
||
{ value: 'shipped', labelKey: 'order.platformStoreOrder.status.shipped', countKey: 'shipped' as const },
|
||
]
|
||
|
||
const hotColumns = computed(() => {
|
||
const cols = [
|
||
{ key: 'platformOrderNo', label: t('order.platformStoreOrder.table.orderNo'), width: 160 },
|
||
{ key: 'platformName', label: t('order.platformStoreOrder.table.platform'), width: 90 },
|
||
{ key: 'storeNickname', label: t('order.platformStoreOrder.table.store'), width: 120 },
|
||
{ key: 'orderCountry', label: t('order.platformStoreOrder.table.country'), width: 80 },
|
||
{ key: 'recipientName', label: t('order.platformStoreOrder.table.recipient'), width: 110 },
|
||
{ key: 'fulfillStatus', label: t('order.platformStoreOrder.table.status'), width: 90 },
|
||
{ key: 'itemCount', label: t('order.platformStoreOrder.table.itemCount'), width: 70 },
|
||
{ key: 'totalAmountDisplay', label: t('order.platformStoreOrder.table.amount'), width: 110 },
|
||
{ key: 'linkedServiceNo', label: t('order.platformStoreOrder.table.linkedServiceNo'), width: 150 },
|
||
{ key: 'shippingLabelNo', label: t('order.platformStoreOrder.table.shippingLabel'), width: 140 },
|
||
{ key: 'warehouseName', label: t('order.platformStoreOrder.table.warehouse'), width: 120 },
|
||
{ key: 'platformOrderTime', label: t('order.platformStoreOrder.table.orderTime'), width: 160 },
|
||
{ key: 'lastSyncTime', label: t('order.platformStoreOrder.table.lastSync'), width: 160 },
|
||
]
|
||
if (isAdmin.value) {
|
||
cols.unshift(
|
||
{ key: 'customerName', label: t('order.myOrders.table.customerName'), width: 120 },
|
||
{ key: 'customerCode', label: t('order.myOrders.table.customerCode'), width: 110 },
|
||
)
|
||
}
|
||
return cols
|
||
})
|
||
|
||
function mapRow(raw: Record<string, unknown>) {
|
||
const row = normalizeListRow(raw)
|
||
const status = String(pickField(row, 'fulfillStatus', 'FulfillStatus') ?? '')
|
||
const platformCode = String(pickField(row, 'platformCode', 'PlatformCode') ?? '')
|
||
const whId = pickField<number>(row, 'warehouseId', 'WarehouseId')
|
||
const currency = pickField<string>(row, 'currency', 'Currency')
|
||
const amount = pickField(row, 'totalAmount', 'TotalAmount')
|
||
const suspended = Boolean(pickField(row, 'isSuspended', 'IsSuspended'))
|
||
let statusLabel = t(`order.platformStoreOrder.status.${status}`, status)
|
||
if (suspended) statusLabel = `${statusLabel}(${t('order.platformStoreOrder.status.suspended')})`
|
||
|
||
return {
|
||
id: pickField<number>(row, 'id', 'Id'),
|
||
customerId: pickField<number>(row, 'customerId', 'CustomerId'),
|
||
customerName: pickField(row, 'customerName', 'CustomerName') ?? '',
|
||
customerCode: pickField(row, 'customerCode', 'CustomerCode') ?? '',
|
||
platformOrderNo: pickField(row, 'platformOrderNo', 'PlatformOrderNo') ?? '-',
|
||
platformName: pickField(row, 'platformName', 'PlatformName') ?? platformCode ?? '-',
|
||
storeNickname: pickField(row, 'storeNickname', 'StoreNickname') ?? '-',
|
||
orderCountry: pickField(row, 'orderCountry', 'OrderCountry') ?? '-',
|
||
recipientName: pickField(row, 'recipientName', 'RecipientName') || '-',
|
||
fulfillStatus: statusLabel,
|
||
itemCount: pickField<number>(row, 'itemCount', 'ItemCount') ?? '-',
|
||
totalAmountDisplay: formatMoney(amount, currency),
|
||
linkedServiceNo: pickField(row, 'linkedServiceNo', 'LinkedServiceNo') || '-',
|
||
shippingLabelNo: pickField(row, 'shippingLabelNo', 'ShippingLabelNo') ?? '-',
|
||
warehouseName: resolveWarehouseLabel(whId, warehouseNameMap.value),
|
||
platformOrderTime: formatDateTime(pickField(row, 'platformOrderTime', 'PlatformOrderTime')),
|
||
lastSyncTime: formatDateTime(pickField(row, 'lastSyncTime', 'LastSyncTime')),
|
||
_raw: row,
|
||
_status: status,
|
||
_suspended: suspended,
|
||
_platformCode: platformCode.toLowerCase(),
|
||
}
|
||
}
|
||
|
||
function getSelectedIds(): number[] {
|
||
return selectedRows.value
|
||
.map((row) => Number(row.id ?? pickField(row._raw || row, 'id', 'Id')))
|
||
.filter((id) => Number.isFinite(id) && id > 0)
|
||
}
|
||
|
||
function mutationCustomerId(): number | undefined {
|
||
return ensureMutationCustomerId()
|
||
}
|
||
|
||
async function loadProducts() {
|
||
try {
|
||
const { items } = await getSalesProductList({ page: 1, pageSize: 200, isActive: 2 })
|
||
productOptions.value = (items || [])
|
||
.map((p: any) => {
|
||
const code = p.productCode || p.ProductCode || ''
|
||
const name = p.productName || p.ProductName || code
|
||
return { label: `${name} (${code})`, value: code }
|
||
})
|
||
.filter((p: { value: string }) => !!p.value)
|
||
if (productOptions.value.length && !matchProductCode.value) {
|
||
matchProductCode.value = productOptions.value[0].value
|
||
}
|
||
} catch {
|
||
productOptions.value = []
|
||
}
|
||
}
|
||
|
||
async function loadSummary() {
|
||
try {
|
||
const data = await getPlatformStoreOrderSummary(withCustomerId({}))
|
||
summary.value = {
|
||
pending: data?.pending ?? data?.Pending ?? 0,
|
||
toShip: data?.toShip ?? data?.ToShip ?? 0,
|
||
shipped: data?.shipped ?? data?.Shipped ?? 0,
|
||
suspended: data?.suspended ?? data?.Suspended ?? 0,
|
||
}
|
||
} catch {
|
||
summary.value = {}
|
||
}
|
||
}
|
||
|
||
function resolveFulfillStatusFilter(): string | undefined {
|
||
const status = fulfillStatus.value
|
||
if (!status || status === STATUS_TAB_ALL) return undefined
|
||
return status
|
||
}
|
||
|
||
async function loadList() {
|
||
listLoading.value = true
|
||
selectedRows.value = []
|
||
try {
|
||
const { items, total } = await getPlatformStoreOrderList(
|
||
withCustomerId({
|
||
page: currentPage.value,
|
||
pageSize: pageSize.value,
|
||
fulfillStatus: resolveFulfillStatusFilter(),
|
||
platformOrderNo: keyword.value || undefined,
|
||
}),
|
||
)
|
||
tableRows.value = (items || []).map((item: Record<string, unknown>) => mapRow(item))
|
||
totalCount.value = Number(total || 0)
|
||
} catch (e: any) {
|
||
$baseMessage(e?.message || t('order.platformStoreOrder.message.loadFailed'), 'error')
|
||
} finally {
|
||
listLoading.value = false
|
||
}
|
||
}
|
||
|
||
function handleStatusTabChange(key: string | number) {
|
||
fulfillStatus.value = String(key)
|
||
currentPage.value = 1
|
||
loadList()
|
||
}
|
||
|
||
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()
|
||
}
|
||
|
||
function handleCustomerChange() {
|
||
currentPage.value = 1
|
||
loadSummary()
|
||
loadList()
|
||
}
|
||
|
||
function handleSelectionChange(rows: any[]) {
|
||
selectedRows.value = rows || []
|
||
}
|
||
|
||
async function showDetail(row: any) {
|
||
const id = Number(row._raw?.id || row.id)
|
||
if (!id) return
|
||
detailDrawerRef.value?.open({
|
||
id,
|
||
customerId: withCustomerId({}).customerId,
|
||
})
|
||
}
|
||
|
||
function buildMatchPayload(id: number) {
|
||
const customerId = mutationCustomerId()
|
||
if (isAdmin.value && customerId == null) return null
|
||
return {
|
||
id,
|
||
warehouseId: matchWarehouseId.value,
|
||
productCode: matchProductCode.value || undefined,
|
||
customerId,
|
||
}
|
||
}
|
||
|
||
async function handleMatch(row: any) {
|
||
if (!hasPermission('Order.PlatformStoreOrder.MatchInventory')) return
|
||
if (!matchWarehouseId.value) {
|
||
$baseMessage(t('order.platformStoreOrder.message.warehouseRequired'), 'warning')
|
||
return
|
||
}
|
||
const payload = buildMatchPayload(row._raw?.id || row.id)
|
||
if (!payload) return
|
||
try {
|
||
const result = await matchPlatformStoreOrderInventory(payload)
|
||
$baseMessage(result?.message || t('order.platformStoreOrder.message.matchSuccess'), 'success')
|
||
await loadSummary()
|
||
await loadList()
|
||
} catch (e: any) {
|
||
$baseMessage(e?.message || t('order.platformStoreOrder.message.matchFailed'), 'error')
|
||
}
|
||
}
|
||
|
||
async function handleBatchMatch() {
|
||
if (!hasPermission('Order.PlatformStoreOrder.MatchInventory')) return
|
||
if (!matchWarehouseId.value) {
|
||
$baseMessage(t('order.platformStoreOrder.message.warehouseRequired'), 'warning')
|
||
return
|
||
}
|
||
const customerId = mutationCustomerId()
|
||
if (isAdmin.value && customerId == null) return
|
||
|
||
const pendingIds = tableRows.value
|
||
.filter((row) => row._status === 'pending' && !pickField(row._raw, 'linkedOrderId', 'LinkedOrderId'))
|
||
.map((row) => Number(row.id))
|
||
|
||
if (!pendingIds.length) {
|
||
$baseMessage(t('order.platformStoreOrder.message.batchEmpty'), 'warning')
|
||
return
|
||
}
|
||
|
||
Modal.confirm({
|
||
title: t('order.platformStoreOrder.actions.batchMatch'),
|
||
content: t('order.platformStoreOrder.message.batchConfirm', { count: pendingIds.length }),
|
||
onOk: async () => {
|
||
try {
|
||
const result = await batchMatchPlatformStoreOrderInventory({
|
||
ids: pendingIds,
|
||
warehouseId: matchWarehouseId.value,
|
||
productCode: matchProductCode.value || undefined,
|
||
customerId,
|
||
})
|
||
$baseMessage(
|
||
t('order.platformStoreOrder.message.batchResult', {
|
||
success: result?.successCount ?? 0,
|
||
fail: result?.failCount ?? 0,
|
||
}),
|
||
(result?.failCount ?? 0) > 0 ? 'warning' : 'success',
|
||
)
|
||
await loadSummary()
|
||
await loadList()
|
||
} catch (e: any) {
|
||
$baseMessage(e?.message || t('order.platformStoreOrder.message.matchFailed'), 'error')
|
||
}
|
||
},
|
||
})
|
||
}
|
||
|
||
function resolveCreatableSelectedIds(): number[] | null {
|
||
const selected = selectedRows.value
|
||
if (!selected.length) {
|
||
$baseMessage(t('order.platformStoreOrder.createLogistics.selectRequired'), 'warning')
|
||
return null
|
||
}
|
||
if (selected.length > 50) {
|
||
$baseMessage(t('order.platformStoreOrder.createLogistics.maxLimit'), 'warning')
|
||
return null
|
||
}
|
||
|
||
const invalid = selected.filter((row) => {
|
||
if (row._suspended) return true
|
||
if (row._status !== 'pending') return true
|
||
if (pickField(row._raw || row, 'linkedOrderId', 'LinkedOrderId')) return true
|
||
return false
|
||
})
|
||
if (invalid.length) {
|
||
$baseMessage(
|
||
t('order.platformStoreOrder.createLogistics.invalidSelection', { count: invalid.length }),
|
||
'warning',
|
||
)
|
||
return null
|
||
}
|
||
|
||
return selected.map((row) => Number(row.id)).filter((id) => id > 0)
|
||
}
|
||
|
||
function openCreateModal(mode: CreateLogisticsMode) {
|
||
const perm =
|
||
mode === 'fulfill'
|
||
? 'Order.PlatformStoreOrder.CreateFulfill'
|
||
: 'Order.PlatformStoreOrder.CreateLogistics'
|
||
if (!hasPermission(perm)) return
|
||
const customerId = mutationCustomerId()
|
||
if (isAdmin.value && customerId == null) return
|
||
const ids = resolveCreatableSelectedIds()
|
||
if (!ids) return
|
||
createModalMode.value = mode
|
||
createModalIds.value = ids
|
||
createModalVisible.value = true
|
||
}
|
||
|
||
function openPullModal() {
|
||
if (!hasPermission('Order.PlatformStoreOrder.Pull')) return
|
||
if (isAdmin.value && mutationCustomerId() == null) return
|
||
pullVisible.value = true
|
||
}
|
||
|
||
function handleSyncStatus() {
|
||
if (!hasPermission('Order.PlatformStoreOrder.Sync')) return
|
||
const ids = getSelectedIds()
|
||
if (!ids.length) {
|
||
$baseMessage(t('order.platformStoreOrder.message.selectOrders'), 'warning')
|
||
return
|
||
}
|
||
const customerId = withCustomerId({}).customerId
|
||
Modal.confirm({
|
||
title: t('order.platformStoreOrder.actions.syncStatus'),
|
||
content: t('order.platformStoreOrder.message.syncConfirm', { count: ids.length }),
|
||
onOk: async () => {
|
||
actionLoading.value = true
|
||
try {
|
||
const result = await syncPlatformStoreOrderStatus(ids, customerId)
|
||
$baseMessage(
|
||
result?.message
|
||
|| t('order.platformStoreOrder.message.syncResult', {
|
||
success: result?.successCount ?? 0,
|
||
fail: result?.failCount ?? 0,
|
||
}),
|
||
(result?.failCount ?? 0) > 0 ? 'warning' : 'success',
|
||
)
|
||
await loadSummary()
|
||
await loadList()
|
||
} catch (e: any) {
|
||
$baseMessage(e?.message || t('order.platformStoreOrder.message.actionFailed'), 'error')
|
||
} finally {
|
||
actionLoading.value = false
|
||
}
|
||
},
|
||
})
|
||
}
|
||
|
||
function handleReadyToShip(ids?: number[]) {
|
||
if (!hasPermission('Order.PlatformStoreOrder.Rts')) return
|
||
const targetIds = ids?.length ? ids : getSelectedIds()
|
||
if (!targetIds.length) {
|
||
$baseMessage(t('order.platformStoreOrder.message.selectOrders'), 'warning')
|
||
return
|
||
}
|
||
const customerId = withCustomerId({}).customerId
|
||
Modal.confirm({
|
||
title: t('order.platformStoreOrder.actions.readyToShip'),
|
||
content: t('order.platformStoreOrder.message.rtsConfirm', { count: targetIds.length }),
|
||
onOk: async () => {
|
||
actionLoading.value = true
|
||
try {
|
||
const result = await readyToShipPlatformStoreOrder(targetIds, customerId)
|
||
$baseMessage(
|
||
result?.message
|
||
|| t('order.platformStoreOrder.message.rtsResult', {
|
||
success: result?.successCount ?? 0,
|
||
fail: result?.failCount ?? 0,
|
||
}),
|
||
(result?.failCount ?? 0) > 0 ? 'warning' : 'success',
|
||
)
|
||
await loadSummary()
|
||
await loadList()
|
||
} catch (e: any) {
|
||
$baseMessage(e?.message || t('order.platformStoreOrder.message.actionFailed'), 'error')
|
||
} finally {
|
||
actionLoading.value = false
|
||
}
|
||
},
|
||
})
|
||
}
|
||
|
||
function handleFetchLabel(row: any) {
|
||
if (!hasPermission('Order.PlatformStoreOrder.Label')) return
|
||
const id = Number(row.id ?? pickField(row._raw || row, 'id', 'Id'))
|
||
if (!id) return
|
||
const customerId = withCustomerId({}).customerId
|
||
Modal.confirm({
|
||
title: t('order.platformStoreOrder.actions.fetchLabel'),
|
||
content: t('order.platformStoreOrder.message.labelConfirm'),
|
||
onOk: async () => {
|
||
actionLoading.value = true
|
||
try {
|
||
const result = await fetchPlatformStoreOrderLabel(id, customerId)
|
||
if (result?.success === false) {
|
||
$baseMessage(result?.message || t('order.platformStoreOrder.message.labelFailed'), 'error')
|
||
return
|
||
}
|
||
$baseMessage(result?.message || t('order.platformStoreOrder.message.labelSuccess'), 'success')
|
||
const url = result?.shippingLabelUrl || result?.ShippingLabelUrl
|
||
if (url) window.open(String(url), '_blank')
|
||
await loadList()
|
||
} catch (e: any) {
|
||
$baseMessage(e?.message || t('order.platformStoreOrder.message.labelFailed'), 'error')
|
||
} finally {
|
||
actionLoading.value = false
|
||
}
|
||
},
|
||
})
|
||
}
|
||
|
||
async function handleSuspend(row: any) {
|
||
if (!hasPermission('Order.PlatformStoreOrder.ToggleSuspend')) return
|
||
const customerId = mutationCustomerId()
|
||
if (isAdmin.value && customerId == null) return
|
||
const raw = row._raw || row
|
||
await togglePlatformStoreOrderSuspend({
|
||
id: Number(pickField(raw, 'id', 'Id')),
|
||
isSuspended: !Boolean(pickField(raw, 'isSuspended', 'IsSuspended')),
|
||
customerId,
|
||
})
|
||
$baseMessage(t('order.platformStoreOrder.message.suspendSuccess'), 'success')
|
||
await loadSummary()
|
||
await loadList()
|
||
}
|
||
|
||
function handleDelete(row: any) {
|
||
if (!hasPermission('Order.PlatformStoreOrder.Delete')) return
|
||
const customerId = mutationCustomerId()
|
||
if (isAdmin.value && customerId == null) return
|
||
Modal.confirm({
|
||
title: t('order.platformStoreOrder.actions.delete'),
|
||
content: row.platformOrderNo,
|
||
onOk: async () => {
|
||
await deletePlatformStoreOrder([row.id], customerId)
|
||
$baseMessage(t('order.platformStoreOrder.message.deleteSuccess'), 'success')
|
||
await loadSummary()
|
||
await loadList()
|
||
},
|
||
})
|
||
}
|
||
|
||
function canRts(row: any) {
|
||
if (row._suspended) return false
|
||
if (row._platformCode === 'temu') return false
|
||
return row._status === 'pending' || row._status === 'toShip'
|
||
}
|
||
|
||
function actionRenderer(row: any) {
|
||
const parts = [
|
||
renderWarehouseActionBtn('detail', t('warehouse.common.detail'), 'view'),
|
||
]
|
||
const raw = row._raw || row
|
||
if (
|
||
hasPermission('Order.PlatformStoreOrder.MatchInventory')
|
||
&& row._status === 'pending'
|
||
&& !pickField(raw, 'linkedOrderId', 'LinkedOrderId')
|
||
) {
|
||
parts.push(renderWarehouseActionBtn('match', t('order.platformStoreOrder.actions.match'), 'match'))
|
||
}
|
||
if (hasPermission('Order.PlatformStoreOrder.Rts') && canRts(row)) {
|
||
parts.push(renderWarehouseActionBtn('rts', t('order.platformStoreOrder.actions.readyToShip'), 'ship'))
|
||
}
|
||
if (hasPermission('Order.PlatformStoreOrder.Label') && !row._suspended) {
|
||
parts.push(renderWarehouseActionBtn('label', t('order.platformStoreOrder.actions.fetchLabel'), 'label'))
|
||
}
|
||
if (hasPermission('Order.PlatformStoreOrder.ToggleSuspend')) {
|
||
parts.push(
|
||
row._suspended
|
||
? renderWarehouseActionBtn('suspend', t('order.platformStoreOrder.actions.resume'), 'resume')
|
||
: renderWarehouseActionBtn('suspend', t('order.platformStoreOrder.actions.suspend'), 'suspend'),
|
||
)
|
||
}
|
||
if (hasPermission('Order.PlatformStoreOrder.Delete')) {
|
||
parts.push(renderWarehouseActionBtn('delete', t('warehouse.common.delete')))
|
||
}
|
||
return wrapWarehouseActions(parts)
|
||
}
|
||
|
||
function handleActionClick(row: any, _i: number, action?: string) {
|
||
if (action === 'detail') showDetail(row)
|
||
if (action === 'match') handleMatch(row)
|
||
if (action === 'rts') {
|
||
if (row._platformCode === 'temu') {
|
||
$baseMessage(t('order.platformStoreOrder.message.temuNoRts'), 'warning')
|
||
return
|
||
}
|
||
handleReadyToShip([Number(row.id)])
|
||
}
|
||
if (action === 'label') handleFetchLabel(row)
|
||
if (action === 'suspend') handleSuspend(row)
|
||
if (action === 'delete') handleDelete(row)
|
||
}
|
||
|
||
onMounted(async () => {
|
||
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),
|
||
}))
|
||
if (warehouseOptions.value.length) matchWarehouseId.value = warehouseOptions.value[0].value
|
||
await loadProducts()
|
||
await loadSummary()
|
||
await loadList()
|
||
})
|
||
|
||
watch(
|
||
() => route.query.fulfillStatus,
|
||
() => {
|
||
const next = resolveFulfillStatusFromQuery()
|
||
if (next === fulfillStatus.value) return
|
||
fulfillStatus.value = next
|
||
currentPage.value = 1
|
||
void loadList()
|
||
},
|
||
)
|
||
</script>
|
||
|
||
<template>
|
||
<div class="platform-store-order-container warehouse-list-page">
|
||
<div class="warehouse-list-page-card">
|
||
<a-tabs
|
||
v-model:active-key="fulfillStatus"
|
||
class="status-tabs"
|
||
hide-content
|
||
@change="handleStatusTabChange"
|
||
>
|
||
<a-tab-pane v-for="tab in statusTabs" :key="tab.value">
|
||
<template #title>
|
||
{{ t(tab.labelKey) }}
|
||
<span v-if="tab.countKey" class="tab-count">({{ summary[tab.countKey] ?? 0 }})</span>
|
||
</template>
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
<div class="table-toolbar">
|
||
<div class="toolbar-left">
|
||
<a-space wrap :size="8">
|
||
<a-select
|
||
v-if="isAdmin"
|
||
v-model="adminCustomerId"
|
||
allow-clear
|
||
:placeholder="t('warehouse.common.selectCustomer')"
|
||
:options="customerOptions"
|
||
style="width: 200px"
|
||
@change="handleCustomerChange"
|
||
/>
|
||
<a-select
|
||
v-model="matchWarehouseId"
|
||
:placeholder="t('warehouse.common.warehouse')"
|
||
:options="warehouseOptions"
|
||
style="width: 180px"
|
||
/>
|
||
<a-select
|
||
v-model="matchProductCode"
|
||
allow-clear
|
||
:placeholder="t('order.platformStoreOrder.form.product')"
|
||
:options="productOptions"
|
||
style="width: 220px"
|
||
/>
|
||
<a-input
|
||
v-model="keyword"
|
||
allow-clear
|
||
:placeholder="t('order.platformStoreOrder.search.orderNo')"
|
||
style="width: 180px"
|
||
@press-enter="handleSearch"
|
||
/>
|
||
<a-button type="primary" @click="handleSearch">{{ t('warehouse.common.search') }}</a-button>
|
||
<a-button
|
||
v-if="hasPermission('Order.PlatformStoreOrder.Pull')"
|
||
:loading="actionLoading"
|
||
@click="openPullModal"
|
||
>
|
||
{{ t('order.platformStoreOrder.actions.pullOrders') }}
|
||
</a-button>
|
||
<a-button
|
||
v-if="hasPermission('Order.PlatformStoreOrder.Sync')"
|
||
:loading="actionLoading"
|
||
@click="handleSyncStatus"
|
||
>
|
||
{{ t('order.platformStoreOrder.actions.syncStatus') }}
|
||
</a-button>
|
||
<a-button
|
||
v-if="hasPermission('Order.PlatformStoreOrder.Rts')"
|
||
:loading="actionLoading"
|
||
@click="handleReadyToShip()"
|
||
>
|
||
{{ t('order.platformStoreOrder.actions.readyToShip') }}
|
||
</a-button>
|
||
<a-button v-if="hasPermission('Order.PlatformStoreOrder.MatchInventory')" @click="handleBatchMatch">
|
||
{{ t('order.platformStoreOrder.actions.batchMatch') }}
|
||
</a-button>
|
||
<a-button
|
||
v-if="hasPermission('Order.PlatformStoreOrder.CreateLogistics')"
|
||
type="primary"
|
||
@click="openCreateModal('logistics')"
|
||
>
|
||
{{ t('order.platformStoreOrder.actions.createLogistics') }}
|
||
</a-button>
|
||
<a-button
|
||
v-if="hasPermission('Order.PlatformStoreOrder.CreateFulfill')"
|
||
type="primary"
|
||
status="success"
|
||
@click="openCreateModal('fulfill')"
|
||
>
|
||
{{ t('order.platformStoreOrder.actions.createFulfill') }}
|
||
</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-column-width="200"
|
||
:action-renderer="actionRenderer"
|
||
@action-click="handleActionClick"
|
||
@selection-change="handleSelectionChange"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<StoreOrderDetailDrawer
|
||
ref="detailDrawerRef"
|
||
:warehouse-name-map="warehouseNameMap"
|
||
/>
|
||
|
||
<PullOrdersModal
|
||
v-model:visible="pullVisible"
|
||
:customer-id="withCustomerId({}).customerId"
|
||
@success="() => { loadSummary(); loadList() }"
|
||
/>
|
||
|
||
<CreateLogisticsModal
|
||
v-model:visible="createModalVisible"
|
||
:mode="createModalMode"
|
||
:store-order-ids="createModalIds"
|
||
:product-options="productOptions"
|
||
:warehouse-options="warehouseOptions"
|
||
:default-product-code="matchProductCode"
|
||
:default-warehouse-id="matchWarehouseId"
|
||
:customer-id="withCustomerId({}).customerId"
|
||
@success="() => { loadSummary(); loadList() }"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped lang="less">
|
||
@import '@/styles/warehouse-list-page.less';
|
||
</style>
|