Commit 4c093b77 by qinjianhui

Merge branch 'dev_new_order_inventory_detail' into 'dev'

Dev new order inventory detail

See merge request !218
parents 3221af81 8cb02fca
......@@ -23,6 +23,7 @@ declare module 'vue' {
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
......
......@@ -5,6 +5,7 @@ import type {
FactoryOrderNewListData,
LogListData,
operateOrderListData,
OrderInventoryData,
PickCompleteData,
ProductListData,
RestockData,
......@@ -661,3 +662,21 @@ export function interceptSuccessApi(
data,
)
}
export function getOrderInventoryListApi(
data: Record<string, unknown>,
currentPage: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<OrderInventoryData>>(
'factory/podOrder/outOfStock/stock-out-statistics',
{ ...data, currentPage, pageSize },
)
}
export function exportOrderInventoryApi(data: Record<string, unknown>) {
return axios.post<never, BaseRespData<never>>(
'factory/podOrder/outOfStock/export-stock-out-statistics',
data,
)
}
......@@ -12,6 +12,9 @@ import {
InspectionData,
PaymentForm,
RejectParams,
SortingList,
SortingRuleDetail,
OperatorList,
} from '@/types/api/order'
import {
apiSubmitPodOrderForm,
......@@ -22,7 +25,8 @@ import {
ProductionOrder,
ShipmentOrderDetailData,
updatePriceForm,
IUpdatePrice, PodUsDetailData,
IUpdatePrice,
PodUsDetailData,
} from '@/types/api/deliveryNote'
import {
AccountStatementNote,
......@@ -30,7 +34,9 @@ import {
BillOrderDetailData,
ConfirmOrderForm,
CountStatus,
LogList, OrderDetails, ProductDetails,
LogList,
OrderDetails,
ProductDetails,
} from '@/types/api/billOrder'
export function getOrderList(
......@@ -148,11 +154,11 @@ export function qaFinishedApi(data: InspectionData[]) {
}
export function apiSetCraftData({
id,
craftTotalPrice,
recNumber,
craftPriceList,
}: {
id,
craftTotalPrice,
recNumber,
craftPriceList,
}: {
id: number | undefined
craftTotalPrice: number | undefined
recNumber: string | undefined
......@@ -509,7 +515,7 @@ export function getPodUsDetailData(id?: number | string) {
export function delPodUsOrderData(ids?: number | string[]) {
return axios.post<never, BaseRespData<never>>(
'pod_us/reconciliation/delItem',
{ids},
{ ids },
)
}
......@@ -555,7 +561,10 @@ export function updateRecPrice(data: updatePriceForm) {
)
}
export function updatePodUsCarriageAmount(data: { ids: number[], carriage_amount: number }) {
export function updatePodUsCarriageAmount(data: {
ids: number[]
carriage_amount: number
}) {
return axios.post<never, BaseRespData<never>>(
'pod_us/reconciliation/updateCarriage',
data,
......@@ -563,11 +572,11 @@ export function updatePodUsCarriageAmount(data: { ids: number[], carriage_amount
}
interface BatchUpdatePrice {
info_id?: number |string | undefined,
info_id?: number | string | undefined
itemList: {
id: number |string,
craft_price: number |string,
template_price: number |string
id: number | string
craft_price: number | string
template_price: number | string
}[]
}
......@@ -647,10 +656,10 @@ export function confirmPodUsOrderApi(data: ConfirmOrderForm) {
}
export function apiRejectionOfReview({
ids,
description,
recNumbers,
}: {
ids,
description,
recNumbers,
}: {
ids: string
recNumbers: string
description: string
......@@ -673,10 +682,10 @@ export function apiBillPodPayment(data: PaymentForm) {
}
export function rejectOrderApi({
ids,
description,
pass,
}: {
ids,
description,
pass,
}: {
ids: string
pass: number
description: string
......@@ -687,3 +696,87 @@ export function rejectOrderApi({
pass,
})
}
// 配货分拣 获取功能开关
export function getConfigApi() {
return axios.get<never, BaseRespData<{ enable: boolean; id: number }>>(
'allocation-sorting-rule/config',
)
}
// 配货分拣 更新功能开关
export function updateConfighApi(data: { id: number; enable: boolean }) {
return axios.get<never, BaseRespData<never>>(
'allocation-sorting-rule/enable-config',
{ params: data },
)
}
// 配货分拣 列表
export function getSortingRuleListApi(data?: { warehouseId?: number }) {
return axios.post<never, BasePaginationData<SortingList>>(
'allocation-sorting-rule/list_page',
data,
)
}
// 配货分拣 详情
export function getAreaInfoApi(id: number) {
return axios.get<never, BaseRespData<SortingRuleDetail>>(
'allocation-sorting-rule/get',
{ params: { id } },
)
}
// 配货分拣 新增
export function addAreaApi(data: SortingRuleDetail) {
return axios.post<never, BaseRespData<never>>(
'allocation-sorting-rule/add',
data,
)
}
// 配货分拣 编辑
export function editAreaApi(data: SortingRuleDetail) {
return axios.post<never, BaseRespData<never>>(
'allocation-sorting-rule/update',
data,
)
}
// 配货分拣 删除
export function deleteAreaApi(id: number) {
return axios.get<never, BaseRespData<never>>(
'allocation-sorting-rule/delete',
{ params: { id } },
)
}
// 配货分拣 查询可用配货区
export function getAreaListApi(warehouseId: number) {
return axios.get<never, BaseRespData<OperatorList[]>>(
'allocation-sorting-rule/area-list',
{ params: { warehouseId } },
)
}
// 配货分拣 配货规则 条件
export function getConditionTypeListApi() {
return axios.get<never, BaseRespData<OperatorList[]>>(
'allocation-sorting-rule/condition-type',
)
}
// 配货分拣 配货规则 操作符
export function getOperatorListApi() {
return axios.get<never, BaseRespData<OperatorList[]>>(
'allocation-sorting-rule/operator-list',
)
}
// 配货分拣 操作日志
export function getSortingLogApi(id: number) {
return axios.get<never, BaseRespData<LogListData[]>>('sorting/getLog', {
params: { id },
})
}
......@@ -263,9 +263,10 @@ export function getPodBoxListApi(
url: string,
factoryNo: number | string | undefined,
warehouseId: number | string,
sortingAreaId?: number | string,
) {
return axios.get<never, BaseRespData<PodMakeOrderData[]>>(url, {
params: { factoryNo, warehouseId },
params: { factoryNo, warehouseId, packingId: sortingAreaId },
})
}
......@@ -276,9 +277,10 @@ export function submitInspectionApi(
},
boxIndex: number | null,
warehouseId: number | string,
sortingAreaId?: number | string,
) {
return axios.post<never, BaseRespData<never>>(
`${url}?box=${boxIndex}&warehouseId=${warehouseId}`,
`${url}?box=${boxIndex}&warehouseId=${warehouseId}&packingId=${sortingAreaId}`,
params,
)
}
......@@ -287,18 +289,20 @@ export function clearBoxApi(
factoryNo: number,
box: number | null,
warehouseId: number | string,
sortingAreaId?: number | string,
) {
return axios.get<never, BaseRespData<never>>(url, {
params: { factoryNo, box, warehouseId },
params: { factoryNo, box, warehouseId, packingId: sortingAreaId },
})
}
export function clearAllBoxApi(
url: string,
warehouseId: string | number,
factoryNo: string | number | undefined,
sortingAreaId?: number | string,
) {
return axios.get<never, BaseRespData<never>>(url, {
params: { warehouseId, factoryNo },
params: { warehouseId, factoryNo, packingId: sortingAreaId },
})
}
export function updateRemarkApi(id: number, content: string) {
......
......@@ -103,16 +103,22 @@ const router = createRouter({
meta: {
title: '工厂订单(NEW)',
},
component: () =>
import('@/views/order/factoryOrderNew/index.vue'),
component: () => import('@/views/order/factoryOrderNew/index.vue'),
},
{
path:'/order/cancel-order-process',
path: '/order/cancel-order-process',
meta: {
title: '取消后订单处理',
},
component: () => import('@/views/order/cancelOrderProcess/index.vue'),
},
{
path: '/order/allocation-sorting-rule',
meta: {
title: '配货分拣规则',
},
component: () =>
import('@/views/order/cancelOrderProcess/index.vue'),
import('@/views/order/allocationSortingRule/index.vue'),
},
{
path: '/pod-cn-order/orderTracking',
......
......@@ -156,6 +156,11 @@ const menu: MenuItem[] = [
id: 13,
label: '取消后订单处理',
},
{
index: '/order/allocation-sorting-rule',
id: 14,
label: '配货分拣规则',
},
],
},
{
......
......@@ -278,3 +278,22 @@ export type CardLayoutListFetcher = (
currentPage: number,
pageSize: number,
) => Promise<PaginationData<operateOrderListData>>
export interface OrderInventoryData {
id?: number
image?: string
warehouseName?: string
locationCode?: string
warehouseSku?: string
productNo?: string
skuName?: string
shortageQuantity?: number
salesNum?: number
demandQuantity?: number
usableQuantity?: number
inventory?: number
occupyInventory?: number
freezeInventory?: number
variantImage?: string
inventoryStatus?: number
}
......@@ -292,3 +292,49 @@ export interface RejectParams {
ids?: string
pass?: number
}
// 配货分拣 列表
export interface SortingList {
id: number
sortNo: number
areaDesc: string
areaName: string
areaCode: string
warehouseId: number
warehouseName: string
autoPrint: boolean
defaultWarehouse: 0 | 1
}
// 配货分拣 详情
export interface SortingRuleDetail {
id?: number
sortNo: number // 分拣序号
areaDesc: string // 分拣区描述
areaCode: string // 分拣区编码
areaName?: string // 分拣区名称
warehouseId: number
warehouseName: string
matchType: 1 | 2 //匹配类型:1=所有条件(且) 2=任一条件(或)
autoPrint: boolean // 自动打单
defaultFlag: boolean // 默认分拣区
secondScan: boolean // 二次扫码
conditions: SortingRuleCondition[] // 配货规则
}
// 配货分拣 配货规则
export interface SortingRuleCondition {
id?: number
ruleId?: number
conditionType: string // 条件
operator: string // 操作符
conditionValue?: string | number | string[]
}
// 配货分拣 配货区/操作符/条件
export interface OperatorList {
desc: string
code: string
used?: boolean
def?: boolean
}
......@@ -4,6 +4,9 @@ export interface PodMakeOrderData {
fromUser?: number | string
box?: number
addDate?: string
packingId?: number | string
factoryNo?: number | string
autoPrint?: boolean
}
export interface OrderData {
......
......@@ -56,3 +56,12 @@ export function isPermissionBtn(key: string) {
if (!permissionBtns) return false
return permissionBtns.includes(key)
}
export function downloadByUrl(url: string, filename?: string) {
const a = document.createElement('a')
a.href = url
a.download = filename || url.split('/').pop() || 'download'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
<template>
<div class="page card h-100 flex-gap-10 overflow-hidden flex">
<div class="search-form flex flex-column w-100 flex-1 overflow-hidden">
<el-form :model="searchForm" inline>
<el-form-item label="仓库">
<el-select
v-model="searchForm.warehouseId"
placeholder="请选择仓库"
style="width: 180px"
filterable
@change="handleWarehouseChange"
>
<el-option
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<ElFormItem>
<ElButton type="primary" @click="() => search()"> 查询 </ElButton>
</ElFormItem>
</el-form>
<div class="picking-sort-info flex flex-align-center">
<el-switch
v-model="isEnableSorting"
size="large"
class="mr-10"
:before-change="updateConfig"
/>
<div class="text-xs">配货分拣</div>
<el-divider direction="vertical" />
<div v-if="!isEnableSorting" class="info">
关闭时,直接使用配货打单功能配货
</div>
<div v-else class="info">
开启时,支持设置分拣规则,根据分拣规则分配配货区,使用配货分拣功能配货。
</div>
</div>
<div v-if="isEnableSorting" class="sorting-content mt-10 w-100">
<el-button type="success" @click="addArea()">新增</el-button>
<div
v-loading="loading"
element-loading-text="加载中..."
class="table-container"
>
<TableView :paginated-data="sortingList" :columns="columns">
<template #autoPrint="{ row }">
{{ row.autoPrint ? '开启' : '关闭' }}
</template>
<template #operation="{ row }">
<el-button type="primary" link @click="addArea(row)">
编辑
</el-button>
<el-button
v-if="row.areaCode !== 'AREA_0'"
type="danger"
link
@click="deleteArea(row.id)"
>
删除
</el-button>
<!-- <el-button type="success" link @click="viewLog(row.id)">
查看日志
</el-button> -->
</template>
</TableView>
</div>
</div>
</div>
<AddAreaDialog
v-if="addAreaDialogVisible"
v-model="addAreaDialogVisible"
:is-edit="isEdit"
:is-disabled="isDisabled"
:edit-data="editData"
:warehouse-id="searchForm.warehouseId"
:warehouse-name="searchForm.warehouseName"
@submit="getSortingRuleList"
/>
<el-dialog
v-model="logVisible"
title="操作日志"
width="1000px"
:close-on-click-modal="false"
>
<LogList :log-list="logList" />
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { loadWarehouseListApi } from '@/api/common'
import type { WarehouseListData } from '@/types'
import type {
LogListData,
SortingList,
SortingRuleDetail,
} from '@/types/api/order'
import type { CustomColumn } from '@/types/table'
import {
getSortingRuleListApi,
deleteAreaApi,
getConfigApi,
updateConfighApi,
getAreaInfoApi,
} from '@/api/order'
import TableView from '@/components/TableView.vue'
import LogList from '@/components/LogList.vue'
import AddAreaDialog from './components/addDialog.vue'
const columns: CustomColumn<SortingList>[] = [
{
key: 'sortNo',
prop: 'sortNo',
label: '序号',
width: 80,
align: 'center',
},
{
key: 'conditionsText',
prop: 'conditionsText',
label: '配货规则',
minWidth: 250,
align: 'left',
},
{
key: 'areaName',
prop: 'areaName',
label: '配货区',
width: 100,
align: 'center',
},
{
key: 'areaDesc',
prop: 'areaDesc',
label: '配货区说明',
minWidth: 200,
align: 'left',
},
{
key: 'autoPrint',
prop: 'autoPrint',
label: '自动打单',
width: 100,
align: 'center',
slot: 'autoPrint',
},
{
key: 'warehouseName',
prop: 'warehouseName',
label: '仓库',
width: 180,
align: 'center',
},
{
key: 'operation',
label: '操作',
width: 140,
align: 'center',
slot: 'operation',
},
]
const warehouseList = ref<WarehouseListData[]>([]) // 仓库列表
const sortingList = ref<SortingList[]>([]) // 规则列表
const isEnableSorting = ref(false) // 是否开启配货分拣
const currentId = ref(0) // 当前操作id
const isEdit = ref(false) // 是否编辑
const isDisabled = ref(false) // 是否可编辑 (0号配货区禁止编辑)
const editData = ref<SortingRuleDetail>()
const addAreaDialogVisible = ref(false)
const logVisible = ref(false)
const logList = ref<LogListData[]>([])
const loading = ref(false)
const searchForm = ref({
warehouseId: 0,
warehouseName: '',
})
// 加载仓库列表
const loadWarehouseList = async () => {
try {
const res = await loadWarehouseListApi()
if (res.code !== 200) return
warehouseList.value = res.data || []
// 默认选中默认仓库
searchForm.value.warehouseId =
warehouseList.value.find((item) => item.defaulted === 1)?.id ?? 0
} catch (e) {
console.error(e)
}
}
const handleWarehouseChange = (warehouseId: number) => {
searchForm.value.warehouseId = warehouseId
if (!isEnableSorting.value) return
getSortingRuleList()
}
const search = () => {
getSortingRuleList()
}
// 获取功能开关
const getFunctionSwitch = async () => {
const res = await getConfigApi()
if (res.code !== 200) return
isEnableSorting.value = res.data.enable
currentId.value = res.data.id
}
// 切换功能
const updateConfig = async () => {
try {
ElMessageBox.confirm('是否确定切换功能?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const res = await updateConfighApi({
id: currentId.value,
enable: !isEnableSorting.value,
})
if (res.code !== 200) return
isEnableSorting.value = !isEnableSorting.value
await getSortingRuleList()
})
} catch (e) {
console.error(e)
}
}
// 查询列表
const getSortingRuleList = async () => {
loading.value = true
const res = await getSortingRuleListApi({
warehouseId: searchForm.value.warehouseId,
})
if (res.code !== 200) return
sortingList.value = res.data.records
loading.value = false
}
// 新增/编辑
const addArea = async (row?: SortingList) => {
searchForm.value.warehouseName =
warehouseList.value.find((item) => item.id === searchForm.value.warehouseId)
?.name ?? ''
if (row) {
isEdit.value = true
isDisabled.value = row.areaCode === 'AREA_0'
const res = await getAreaInfoApi(row.id)
if (res.code !== 200) return
editData.value = res.data
} else {
isDisabled.value = false
isEdit.value = false
editData.value = undefined
}
addAreaDialogVisible.value = true
}
// 删除配货区
const deleteArea = async (id: number) => {
await ElMessageBox.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
loading.value = true
const res = await deleteAreaApi(id)
if (res.code !== 200) return
ElMessage.success('删除成功')
await getSortingRuleList()
})
.finally(() => {
loading.value = false
})
}
// 查看日志
// const viewLog = async (id: number) => {
// try {
// const res = await getSortingLogApi(id)
// logList.value = res.data
// logVisible.value = true
// } catch (e) {
// console.error(e)
// }
// }
onMounted(async () => {
await loadWarehouseList()
await getFunctionSwitch()
await getSortingRuleList()
})
</script>
<style scoped lang="scss">
.search-form {
min-height: 0;
}
.picking-sort-info {
font-size: 14px;
color: #555;
font-weight: 500;
.info {
font-size: 12px;
color: #999;
}
}
.sorting-content {
flex: 1;
min-height: 0;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: flex-start;
.table-container {
width: 100%;
flex: 1;
min-height: 0;
overflow: hidden;
margin-top: 10px;
}
}
</style>
......@@ -532,6 +532,14 @@ defineExpose({ clearSelection, getSelectedIds, refresh })
.operation-number {
font-size: 12px;
cursor: pointer;
background: rgba(255, 255, 255, 0.75);
padding: 2px 6px;
border-radius: 4px;
max-width: 100%;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.quantity-badge {
......@@ -657,4 +665,25 @@ defineExpose({ clearSelection, getSelectedIds, refresh })
.flex-row-gap6 {
gap: 6px;
}
@media (max-width: 1920px) {
.card-grid {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
}
@media (max-width: 1750px) {
.card-grid {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.card-info-grid {
grid-template-columns: 1fr 180px;
}
}
@media (max-width: 1550px) {
.card-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.card-info-grid {
grid-template-columns: 1fr 200px;
}
}
</style>
......@@ -325,11 +325,11 @@ const addOtherCurrency = async () => {
ElMessage.error('请输入出库数量')
return
}
const usableInventory = arr[i].usableInventory || 0
if ((arr[i].outCount as number) > usableInventory) {
ElMessage.error('出库数量不能大于可用库存数量')
return
}
// const usableInventory = arr[i].usableInventory || 0
// if ((arr[i].outCount as number) > usableInventory) {
// ElMessage.error('出库数量不能大于可用库存数量')
// return
// }
if (!arr[i].locationId) {
ElMessage.error('请选择库位')
return
......
<template>
<ElDialog
v-model="visible"
title="订单库存明细"
width="1500px"
:close-on-click-modal="false"
>
<div class="inventory-dialog-content">
<div class="search-bar">
<ElForm
:inline="true"
:model="filterForm"
size="default"
class="search-form"
>
<ElFormItem label="仓库">
<ElSelect
v-model="filterForm.warehouseId"
placeholder="请选择仓库"
clearable
style="width: 150px"
>
<ElOption
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</ElSelect>
</ElFormItem>
<ElFormItem label="库存SKU">
<ElInput
v-model="filterForm.warehouseSku"
placeholder="请输入库存SKU"
clearable
style="width: 160px"
/>
</ElFormItem>
<ElFormItem label="款号">
<ElInput
v-model="filterForm.productNo"
placeholder="请输入款号"
clearable
style="width: 150px"
/>
</ElFormItem>
<ElFormItem label="库存状况">
<ElSelect
v-model="filterForm.inventoryStatus"
placeholder="请选择库存状况"
clearable
style="width: 160px"
>
<ElOption
v-for="item in stockStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="handleSearch">查询</ElButton>
<ElButton type="success" @click="handleExport"> 导出 </ElButton>
</ElFormItem>
</ElForm>
</div>
<div v-loading="loading" class="inventory-table">
<TableView
:paginated-data="data"
:columns="columns"
serial-numberable
selectionable
/>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[20, 50, 100, 200]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="margin: 10px auto 0"
@size-change="onPageSizeChange"
@current-change="onCurrentPageChange"
/>
</div>
</ElDialog>
</template>
<script setup lang="tsx">
import { ElMessage } from 'element-plus'
import type { WarehouseListData } from '@/types'
import type {
FactoryOrderNewListData,
OrderInventoryData,
} from '@/types/api/factoryOrderNew'
import TableView from '@/components/TableView.vue'
import usePageList from '@/utils/hooks/usePageList'
import {
getOrderInventoryListApi,
exportOrderInventoryApi,
} from '@/api/factoryOrderNew'
import BigNumber from 'bignumber.js'
const props = defineProps<{
visible: boolean
selectedRows: FactoryOrderNewListData[]
warehouseList: WarehouseListData[]
}>()
const stockStatusOptions = [
{ label: '缺货商品', value: 1 },
{ label: '不缺货商品', value: 2 },
{ label: '未入过库的商品', value: 3 },
]
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void
}>()
const visible = computed({
get() {
return props.visible
},
set(value: boolean) {
emit('update:visible', value)
},
})
watch(visible, (newVal) => {
if (newVal) {
filterForm.value = {
warehouseId: undefined,
warehouseSku: '',
productNo: '',
inventoryStatus: undefined,
}
refresh()
}
})
const filterForm = ref({
warehouseId: undefined as number | undefined,
warehouseSku: '',
productNo: '',
inventoryStatus: undefined as number | undefined,
})
const buildQueryParams = () => ({
orderIds: props.selectedRows.map((row) => row.id),
warehouseId: filterForm.value.warehouseId || undefined,
warehouseSku: filterForm.value.warehouseSku || undefined,
productNo: filterForm.value.productNo || undefined,
inventoryStatus: filterForm.value.inventoryStatus || undefined,
})
const {
loading,
currentPage,
pageSize,
total,
data,
onCurrentPageChange,
onPageSizeChange,
refresh,
} = usePageList<OrderInventoryData>({
initPageSize: 20,
initLoad: false,
query: async (current, size) => {
const res = await getOrderInventoryListApi(
buildQueryParams(),
current,
size,
)
return res.data
},
})
/** 可用数量 = 库存数量 - 占用数量 - 冻结数量 */
function getAvailableQuantity(row: OrderInventoryData): number {
return new BigNumber(row.inventory ?? 0)
.minus(row.occupyInventory ?? 0)
.minus(row.freezeInventory ?? 0)
.toNumber()
}
function getShortageQuantity(row: OrderInventoryData): number {
const shortage = new BigNumber(row.salesNum ?? 0)
.minus(getAvailableQuantity(row))
.toNumber()
return Math.max(0, shortage)
}
const columns = [
{
label: '图片',
width: 70,
align: 'center',
render: (row: OrderInventoryData) => (
<el-image
src={row.variantImage ?? ''}
style={{ width: '40px', height: '40px' }}
preview-src-list={row.variantImage ? [row.variantImage] : []}
preview-teleported
fit="cover"
/>
),
},
{
prop: 'warehouseName',
label: '仓库名称',
minWidth: 120,
},
{
prop: 'locationCode',
label: '库位',
width: 100,
align: 'center',
},
{
prop: 'warehouseSku',
label: '库存SKU',
minWidth: 180,
align: 'center',
},
{
prop: 'productNo',
label: '款号',
width: 100,
align: 'center',
},
{
prop: 'skuName',
label: '商品名称',
minWidth: 140,
showOverflowTooltip: true,
},
{
label: '缺货数量',
width: 100,
align: 'right',
render: (row: OrderInventoryData) => {
const v = getShortageQuantity(row)
if (v > 0) {
return <span style="color: #f56c6c; font-weight: bold">{v}</span>
}
return <span>{v}</span>
},
},
{
prop: 'salesNum',
label: '需求数量',
width: 100,
align: 'right',
render: (row: OrderInventoryData) => {
return (
<span
style={{
color: !row.locationCode ? '#E6A23C' : '',
fontWeight: !row.locationCode ? 'bold' : '',
}}
>
{row.salesNum || 0}
</span>
)
},
},
{
prop: 'usableQuantity',
label: '可用数量',
width: 100,
align: 'right',
render: (row: OrderInventoryData) => {
return <span>{getAvailableQuantity(row)}</span>
},
},
{
prop: 'inventory',
label: '库存数量',
width: 100,
align: 'right',
},
{
prop: 'occupyInventory',
label: '占用数量',
width: 100,
align: 'right',
render: (row: OrderInventoryData) => {
return <span>{row.occupyInventory || 0}</span>
},
},
{
prop: 'freezeInventory',
label: '冻结数量',
width: 100,
align: 'right',
},
]
const handleSearch = () => {
refresh()
}
const handleExport = async () => {
try {
await exportOrderInventoryApi(buildQueryParams())
ElMessage.success('请求成功,请稍后到右上角[我的下载]中查看')
} catch (e) {
console.error(e)
}
}
</script>
<style scoped lang="scss">
.inventory-dialog-content {
display: flex;
flex-direction: column;
height: 68vh;
}
.search-bar {
flex-shrink: 0;
padding-bottom: 10px;
}
.search-form {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0;
:deep(.el-form-item) {
margin-right: 10px;
margin-bottom: 10px;
}
}
.inventory-table {
flex: 1;
overflow: hidden;
}
</style>
......@@ -152,7 +152,7 @@
>
<ElInput
v-model.trim="searchForm.operationNo"
placeholder="操作单号"
placeholder="多个操作单号,分隔"
clearable
style="width: 140px"
/>
......@@ -512,11 +512,6 @@
转至待排单
</ElButton>
</span>
<!-- <span v-if="status === 'PENDING_RECEIVE'" class="item">
<ElButton type="warning" @click="handleTransferOldFlow"
>转旧流程</ElButton
>
</span> -->
<span v-if="status === 'PENDING_SCHEDULE'" class="item">
<ElButton type="primary" @click="handleArrange">排单</ElButton>
</span>
......@@ -580,8 +575,19 @@
>补胚失败</ElButton
>
</span>
<span v-if="status === 'PENDING_PACKING'" class="item">
<ElButton type="success" @click="handleSeedingWall"
<span v-if="status === 'IN_PRODUCTION' && isEnableSorting" class="item">
<ElButton type="primary" @click="handleSeedingWall('sort')"
>配货分拣</ElButton
>
</span>
<span
v-if="
status === 'PENDING_PACKING' ||
(status === 'IN_PRODUCTION' && !isEnableSorting)
"
class="item"
>
<ElButton type="success" @click="handleSeedingWall('print')"
>配货打单</ElButton
>
</span>
......@@ -605,7 +611,7 @@
>
</span>
<span v-if="status === 'IN_PRODUCTION'" class="item">
<ElButton type="success" @click="handleProductionComplete"
<ElButton type="warning" @click="handleProductionComplete"
>生产完成</ElButton
>
</span>
......@@ -705,6 +711,17 @@
>刷新商品信息</ElButton
>
</span>
<span
v-if="
status === 'PENDING_RECEIVE' &&
pendingAcceptSubTab === 'ACCEPT_FAIL_OUT_OF_STOCK'
"
class="item"
>
<ElButton type="success" @click="handleGetOrderInventoryDetail"
>订单库存明细</ElButton
>
</span>
</div>
<div v-if="status === 'SUSPEND'" class="status-subtabs">
<div
......@@ -1039,9 +1056,15 @@
v-model="podOrderVisible"
:print-order="printOrder"
:warehouse-list="warehouseList"
:title="wallType === 'print' ? '配货打单' : '配货分拣'"
:is-new-order="true"
ws-open-code="STARTORDERNEWPOD"
ws-close-code="ENDORDERNEWPOD"
:wall-type="wallType"
:ws-open-code="
wallType === 'print' ? 'STARTORDERNEWPOD' : 'STARTORDERNEWPODTOP'
"
:ws-close-code="
wallType === 'print' ? 'ENDORDERNEWPOD' : 'ENDORDERNEWPODTOP'
"
init-url="factory/podOrderPacking/local/getPodBoxOrderDetails"
@set-printer="handlePrinterChange"
@set-warehouse-id="handleWarehouseIdChange"
......@@ -1150,6 +1173,11 @@
</span>
</template>
</ElDialog>
<OrderInventoryDetailDialog
v-model:visible="orderInventoryDetailVisible"
:warehouse-list="warehouseList"
:selected-rows="selectedRows"
/>
</div>
</template>
......@@ -1209,6 +1237,7 @@ import {
interceptUpdateApi,
interceptSuccessApi,
} from '@/api/factoryOrderNew'
import { getConfigApi } from '@/api/order'
import { getLogisticsWayApi } from '@/api/podUsOrder'
import BigNumber from 'bignumber.js'
import { filePath } from '@/api/axios'
......@@ -1243,7 +1272,9 @@ import { useOrderSearchForm } from './hooks/useOrderSearchForm'
import { useOrderStatusTree } from './hooks/useOrderStatusTree'
import { useOrderListAndDetail } from './hooks/useOrderListAndDetail'
import { useOrderBatchActions } from './hooks/useOrderBatchActions'
import { ElTag } from 'element-plus'
import { ElButton, ElTag } from 'element-plus'
import OrderInventoryDetailDialog from './component/OrderInventoryDialog.vue'
import { downloadByUrl } from '@/utils/index.ts'
const resultInfo = ref<ResultInfoDataItem[]>([])
const resultRefs = ref()
......@@ -1252,7 +1283,7 @@ const statusSidebarCollapsed = ref(false)
const toggleStatusSidebar = () => {
statusSidebarCollapsed.value = !statusSidebarCollapsed.value
}
const orderInventoryDetailVisible = ref(false)
const batchManageRef = ref<InstanceType<typeof BatchManageTable>>()
const waitingRestockRef = ref<InstanceType<typeof WaitingRestockTable>>()
const cardLayoutRef = ref<InstanceType<typeof CardLayout>>()
......@@ -2521,8 +2552,16 @@ const handlePrinterChange = (value: string) => {
sheetPrinter.value = value
localStorage.setItem('sheetPrinter', JSON.stringify(value))
}
const handleWarehouseIdChange = (value: string) => {
localStorage.setItem('localNewWarehouseId', JSON.stringify(value))
const handleWarehouseIdChange = (
value:
| string
| { warehouseId: string | number; sortingAreaId: string | number },
) => {
if (wallType.value === 'print') {
localStorage.setItem('localNewWarehouseId', JSON.stringify(value))
} else if (wallType.value === 'sort') {
localStorage.setItem('localSortingAreaId', JSON.stringify(value))
}
}
const mapOrderParamListToSubmitItems = (
orderParamList: { id: number; dataVersion?: number }[],
......@@ -2543,7 +2582,9 @@ const getPrintLogisticLabelFactory = (id?: number) =>
getfaceSimplexFileApi([id ?? 0])
const { getCLodop } = useLodop()
const handleSeedingWall = () => {
const wallType = ref<'print' | 'sort'>('print')
const handleSeedingWall = (type: 'print' | 'sort') => {
wallType.value = type
const lodop = getCLodop(null, null)
if (!lodop) return
sheetPrinter.value = lodop.GET_PRINTER_NAME(0)
......@@ -2760,7 +2801,10 @@ const handleDownloadMaterial = async () => {
? await downloadMaterialApi(ids as number[])
: await downloadOperationMaterialApi(ids as number[])
if (res.code !== 200) return
window.open(filePath + res.message, '_blank')
downloadByUrl(
filePath + res.message,
res.message?.split('/').pop() || 'download',
)
} catch (e) {
console.error(e)
} finally {
......@@ -2776,7 +2820,10 @@ const handleDownloadMaterialByProduct = async (row: ProductListData) => {
try {
const res = await downloadOperationMaterialApi([row.id])
if (res.code !== 200) return
window.open(filePath + res.message, '_blank')
downloadByUrl(
filePath + res.message,
res.message?.split('/').pop() || 'download',
)
} catch (e) {
console.error(e)
} finally {
......@@ -3116,12 +3163,23 @@ const handleInterceptionFail = async (row?: FactoryOrderNewListData) => {
},
})
}
const handleGetOrderInventoryDetail = async () => {
orderInventoryDetailVisible.value = true
}
const isEnableSorting = ref(false)
// 获取功能开关
const getFunctionSwitch = async () => {
const res = await getConfigApi()
if (res.code !== 200) return
isEnableSorting.value = res.data.enable
}
onMounted(() => {
loadStatusTreeCounts()
loadAllDictionaries()
getLogisticsWay()
getReceiverCountryList()
loadWarehouseList()
getFunctionSwitch()
void treeRef.value
void tableRef.value
if (status.value === 'PENDING_RECEIVE') {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment