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' { ...@@ -23,6 +23,7 @@ declare module 'vue' {
ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
ElDialog: typeof import('element-plus/es')['ElDialog'] ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
......
...@@ -5,6 +5,7 @@ import type { ...@@ -5,6 +5,7 @@ import type {
FactoryOrderNewListData, FactoryOrderNewListData,
LogListData, LogListData,
operateOrderListData, operateOrderListData,
OrderInventoryData,
PickCompleteData, PickCompleteData,
ProductListData, ProductListData,
RestockData, RestockData,
...@@ -661,3 +662,21 @@ export function interceptSuccessApi( ...@@ -661,3 +662,21 @@ export function interceptSuccessApi(
data, 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 { ...@@ -12,6 +12,9 @@ import {
InspectionData, InspectionData,
PaymentForm, PaymentForm,
RejectParams, RejectParams,
SortingList,
SortingRuleDetail,
OperatorList,
} from '@/types/api/order' } from '@/types/api/order'
import { import {
apiSubmitPodOrderForm, apiSubmitPodOrderForm,
...@@ -22,7 +25,8 @@ import { ...@@ -22,7 +25,8 @@ import {
ProductionOrder, ProductionOrder,
ShipmentOrderDetailData, ShipmentOrderDetailData,
updatePriceForm, updatePriceForm,
IUpdatePrice, PodUsDetailData, IUpdatePrice,
PodUsDetailData,
} from '@/types/api/deliveryNote' } from '@/types/api/deliveryNote'
import { import {
AccountStatementNote, AccountStatementNote,
...@@ -30,7 +34,9 @@ import { ...@@ -30,7 +34,9 @@ import {
BillOrderDetailData, BillOrderDetailData,
ConfirmOrderForm, ConfirmOrderForm,
CountStatus, CountStatus,
LogList, OrderDetails, ProductDetails, LogList,
OrderDetails,
ProductDetails,
} from '@/types/api/billOrder' } from '@/types/api/billOrder'
export function getOrderList( export function getOrderList(
...@@ -152,7 +158,7 @@ export function apiSetCraftData({ ...@@ -152,7 +158,7 @@ export function apiSetCraftData({
craftTotalPrice, craftTotalPrice,
recNumber, recNumber,
craftPriceList, craftPriceList,
}: { }: {
id: number | undefined id: number | undefined
craftTotalPrice: number | undefined craftTotalPrice: number | undefined
recNumber: string | undefined recNumber: string | undefined
...@@ -509,7 +515,7 @@ export function getPodUsDetailData(id?: number | string) { ...@@ -509,7 +515,7 @@ export function getPodUsDetailData(id?: number | string) {
export function delPodUsOrderData(ids?: number | string[]) { export function delPodUsOrderData(ids?: number | string[]) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
'pod_us/reconciliation/delItem', 'pod_us/reconciliation/delItem',
{ids}, { ids },
) )
} }
...@@ -555,7 +561,10 @@ export function updateRecPrice(data: updatePriceForm) { ...@@ -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>>( return axios.post<never, BaseRespData<never>>(
'pod_us/reconciliation/updateCarriage', 'pod_us/reconciliation/updateCarriage',
data, data,
...@@ -563,11 +572,11 @@ export function updatePodUsCarriageAmount(data: { ids: number[], carriage_amount ...@@ -563,11 +572,11 @@ export function updatePodUsCarriageAmount(data: { ids: number[], carriage_amount
} }
interface BatchUpdatePrice { interface BatchUpdatePrice {
info_id?: number |string | undefined, info_id?: number | string | undefined
itemList: { itemList: {
id: number |string, id: number | string
craft_price: number |string, craft_price: number | string
template_price: number |string template_price: number | string
}[] }[]
} }
...@@ -650,7 +659,7 @@ export function apiRejectionOfReview({ ...@@ -650,7 +659,7 @@ export function apiRejectionOfReview({
ids, ids,
description, description,
recNumbers, recNumbers,
}: { }: {
ids: string ids: string
recNumbers: string recNumbers: string
description: string description: string
...@@ -676,7 +685,7 @@ export function rejectOrderApi({ ...@@ -676,7 +685,7 @@ export function rejectOrderApi({
ids, ids,
description, description,
pass, pass,
}: { }: {
ids: string ids: string
pass: number pass: number
description: string description: string
...@@ -687,3 +696,87 @@ export function rejectOrderApi({ ...@@ -687,3 +696,87 @@ export function rejectOrderApi({
pass, 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( ...@@ -263,9 +263,10 @@ export function getPodBoxListApi(
url: string, url: string,
factoryNo: number | string | undefined, factoryNo: number | string | undefined,
warehouseId: number | string, warehouseId: number | string,
sortingAreaId?: number | string,
) { ) {
return axios.get<never, BaseRespData<PodMakeOrderData[]>>(url, { return axios.get<never, BaseRespData<PodMakeOrderData[]>>(url, {
params: { factoryNo, warehouseId }, params: { factoryNo, warehouseId, packingId: sortingAreaId },
}) })
} }
...@@ -276,9 +277,10 @@ export function submitInspectionApi( ...@@ -276,9 +277,10 @@ export function submitInspectionApi(
}, },
boxIndex: number | null, boxIndex: number | null,
warehouseId: number | string, warehouseId: number | string,
sortingAreaId?: number | string,
) { ) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
`${url}?box=${boxIndex}&warehouseId=${warehouseId}`, `${url}?box=${boxIndex}&warehouseId=${warehouseId}&packingId=${sortingAreaId}`,
params, params,
) )
} }
...@@ -287,18 +289,20 @@ export function clearBoxApi( ...@@ -287,18 +289,20 @@ export function clearBoxApi(
factoryNo: number, factoryNo: number,
box: number | null, box: number | null,
warehouseId: number | string, warehouseId: number | string,
sortingAreaId?: number | string,
) { ) {
return axios.get<never, BaseRespData<never>>(url, { return axios.get<never, BaseRespData<never>>(url, {
params: { factoryNo, box, warehouseId }, params: { factoryNo, box, warehouseId, packingId: sortingAreaId },
}) })
} }
export function clearAllBoxApi( export function clearAllBoxApi(
url: string, url: string,
warehouseId: string | number, warehouseId: string | number,
factoryNo: string | number | undefined, factoryNo: string | number | undefined,
sortingAreaId?: number | string,
) { ) {
return axios.get<never, BaseRespData<never>>(url, { return axios.get<never, BaseRespData<never>>(url, {
params: { warehouseId, factoryNo }, params: { warehouseId, factoryNo, packingId: sortingAreaId },
}) })
} }
export function updateRemarkApi(id: number, content: string) { export function updateRemarkApi(id: number, content: string) {
......
...@@ -103,16 +103,22 @@ const router = createRouter({ ...@@ -103,16 +103,22 @@ const router = createRouter({
meta: { meta: {
title: '工厂订单(NEW)', title: '工厂订单(NEW)',
}, },
component: () => component: () => import('@/views/order/factoryOrderNew/index.vue'),
import('@/views/order/factoryOrderNew/index.vue'),
}, },
{ {
path:'/order/cancel-order-process', path: '/order/cancel-order-process',
meta: { meta: {
title: '取消后订单处理', title: '取消后订单处理',
}, },
component: () => import('@/views/order/cancelOrderProcess/index.vue'),
},
{
path: '/order/allocation-sorting-rule',
meta: {
title: '配货分拣规则',
},
component: () => component: () =>
import('@/views/order/cancelOrderProcess/index.vue'), import('@/views/order/allocationSortingRule/index.vue'),
}, },
{ {
path: '/pod-cn-order/orderTracking', path: '/pod-cn-order/orderTracking',
......
...@@ -156,6 +156,11 @@ const menu: MenuItem[] = [ ...@@ -156,6 +156,11 @@ const menu: MenuItem[] = [
id: 13, id: 13,
label: '取消后订单处理', label: '取消后订单处理',
}, },
{
index: '/order/allocation-sorting-rule',
id: 14,
label: '配货分拣规则',
},
], ],
}, },
{ {
......
...@@ -278,3 +278,22 @@ export type CardLayoutListFetcher = ( ...@@ -278,3 +278,22 @@ export type CardLayoutListFetcher = (
currentPage: number, currentPage: number,
pageSize: number, pageSize: number,
) => Promise<PaginationData<operateOrderListData>> ) => 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 { ...@@ -292,3 +292,49 @@ export interface RejectParams {
ids?: string ids?: string
pass?: number 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 { ...@@ -4,6 +4,9 @@ export interface PodMakeOrderData {
fromUser?: number | string fromUser?: number | string
box?: number box?: number
addDate?: string addDate?: string
packingId?: number | string
factoryNo?: number | string
autoPrint?: boolean
} }
export interface OrderData { export interface OrderData {
......
...@@ -56,3 +56,12 @@ export function isPermissionBtn(key: string) { ...@@ -56,3 +56,12 @@ export function isPermissionBtn(key: string) {
if (!permissionBtns) return false if (!permissionBtns) return false
return permissionBtns.includes(key) 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>
<ElDialog
v-model="visible"
:title="isEdit ? '编辑配货区' : '新增配货区'"
:close-on-click-modal="false"
width="800px"
>
<el-form ref="formRef" label-width="170px" :model="form" :rules="rules">
<el-form-item label="配货区说明" prop="areaDesc">
<el-input
v-model="form.areaDesc"
style="width: 100%"
clearable
maxlength="100"
show-word-limit
:disabled="isDisabled"
placeholder="请输入配货区说明"
/>
</el-form-item>
<el-form-item label="配货区" prop="areaCode">
<el-select
v-model="form.areaCode"
:disabled="isDisabled"
style="width: 200px"
placeholder="请选择配货区"
>
<el-option
v-for="item in areaList"
:key="item.code"
:label="item.desc"
:value="item.code"
/>
</el-select>
</el-form-item>
<el-form-item label="配货规则" prop="conditions">
<div class="picking-rules">
<div class="header">
<span class="mr-10">满足条件</span>
<el-radio-group v-model="form.matchType" :disabled="isDisabled">
<el-radio :value="1">满足以下所有条件</el-radio>
<el-radio :value="2">满足以下任一条件</el-radio>
</el-radio-group>
</div>
<div
v-for="(item, index) in form.conditions"
:key="index"
class="content"
>
<el-select
v-model="item.conditionType"
style="width: 160px"
:disabled="isDisabled"
placeholder="请选择配货规则"
@change="handleConditionTypeChange(item)"
>
<el-option
v-for="rule in getAvailablePickingRules(index)"
:key="rule.code"
:label="rule.desc"
:value="rule.code"
/>
</el-select>
<el-select
v-model="item.operator"
style="width: 160px"
:disabled="isDisabled"
placeholder="请选择关系"
>
<el-option
v-for="operator in getAvailableOperators(item.conditionType)"
:key="operator.code"
:label="operator.desc"
:value="operator.code"
/>
</el-select>
<template v-if="item.conditionType === 'order_platform'">
<el-select
v-model="item.conditionValue"
class="platform-select"
style="width: 160px"
:disabled="isDisabled"
placeholder="请选择平台"
filterable
multiple
collapse-tags
collapse-tags-tooltip
:max-collapse-tags="1"
clearable
popper-class="customize-select-style"
>
<el-option
v-for="platform in platformList"
:key="platform.type"
:label="platform.type"
:value="platform.type"
style="width: 160px"
>
<img
:src="`/images/icon/${platform.icon.split('/').pop()}`"
style="height: 20px; margin: 5px 10px 0 0"
/>
<span :title="platform.type">{{ platform.type }}</span>
</el-option>
</el-select>
</template>
<template v-else>
<el-input-number
v-model="item.conditionValue"
style="width: 160px"
:min="1"
:max="999"
:disabled="isDisabled"
placeholder="请输入数字"
/>
</template>
<el-button
v-if="form.conditions.length < (pickingRuleList?.length ?? 0)"
type="primary"
class="rule-action-btn"
:icon="Plus"
size="small"
circle
:disabled="isDisabled"
@click="addPickingRuleItem"
/>
<el-button
v-if="form.conditions.length > 1"
color="#F56C6C"
class="rule-action-btn"
:icon="Minus"
size="small"
circle
plain
:disabled="isDisabled"
@click="removePickingRuleItem(index)"
/>
</div>
</div>
</el-form-item>
<el-form-item label="自动打单" prop="autoPrint">
<el-switch
v-model="form.autoPrint"
size="large"
placeholder="请选择是否自动打单"
/>
</el-form-item>
<el-form-item>
<span v-if="form.autoPrint" class="item-info">
开启后,配货分拣订单配齐时,自动打单,打单后订单状态转为待发货。
</span>
<span v-else class="item-info">
关闭后,配货分拣订单配齐后仍在待配货状态,经过配货打单后订单状态转为待发货。
</span>
</el-form-item>
<el-form-item label="是否对接二次扫码设备" prop="secondScan">
<el-select
v-model="form.secondScan"
style="width: 200px"
placeholder="请选择是否对接二次扫码设备"
>
<el-option label="是" :value="true" />
<el-option label="否" :value="false" />
</el-select>
</el-form-item>
<el-form-item label="序号" prop="sortNo">
<el-input-number
v-model="form.sortNo"
:min="1"
:max="999"
style="width: 200px"
step-strictly
controls-position="right"
:disabled="isDisabled"
placeholder="请输入序号"
/>
</el-form-item>
<el-form-item>
<span class="item-info">配货规则逻辑冲突时,优先执行更小的序号</span>
</el-form-item>
</el-form>
<template #footer>
<div class="flex flex-center">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</div>
</template>
</ElDialog>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { Plus, Minus } from '@element-plus/icons-vue'
import type { FormInstance } from 'element-plus'
import platformJson from '@/json/platform.json'
import type {
OperatorList,
SortingRuleCondition,
SortingRuleDetail,
} from '@/types/api/order'
import {
getAreaListApi,
getConditionTypeListApi,
getOperatorListApi,
addAreaApi,
editAreaApi,
} from '@/api/order'
// 配货规则条件
const pickingRuleList = ref<OperatorList[]>()
// 配货规则操作符
const operatorList = ref<OperatorList[]>()
const props = defineProps<{
modelValue: boolean
isEdit?: boolean
editData?: SortingRuleDetail
warehouseId: number
warehouseName: string
isDisabled?: boolean
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void
(e: 'submit'): void
}>()
const visible = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
},
})
const formRef = ref<FormInstance>()
const areaList = ref<OperatorList[]>([])
const form = ref<SortingRuleDetail>({
areaDesc: '',
areaCode: '',
matchType: 1,
conditions: [
{
conditionType: '',
operator: '',
conditionValue: undefined,
},
],
secondScan: false,
sortNo: 1,
autoPrint: false,
warehouseId: 0,
warehouseName: '',
defaultFlag: false,
})
// 获取可用的配货规则条件 (剔除已选中的配货规则)
const getAvailablePickingRules = (currentIndex: number) => {
const selectedFields = form.value.conditions
.filter((_, index) => index !== currentIndex)
.map((item) => item.conditionType)
return pickingRuleList.value?.filter(
(rule) => !selectedFields.includes(rule.code),
)
}
// 根据配货规则类型获取可用的操作符
const getAvailableOperators = (conditionType: string) => {
const list = operatorList.value ?? []
if (conditionType === 'order_total_num') {
return list.filter((operator) => operator.code !== 'in')
} else if (conditionType === 'order_platform') {
return list.filter((operator) => operator.code === 'in')
}
return list
}
// 配货规则条件改变
const handleConditionTypeChange = (item: SortingRuleCondition) => {
// 平台 只能选 in属于
if (item.conditionType === 'order_platform') {
item.conditionValue = undefined
item.operator = 'in'
}
// 订单总件数 清空字段
else if (item.conditionType === 'order_total_num') {
item.conditionValue = undefined
item.operator = 'gt'
}
}
// 配货规则
const createPickingRuleItem = (): SortingRuleCondition => ({
conditionType: '',
operator: '',
conditionValue: undefined,
})
// 配货规则校验
const validateConditions = (
_rule: unknown,
_value: unknown,
callback: (error?: Error) => void,
) => {
const items = form.value.conditions
for (let i = 0; i < items.length; i++) {
const item = items[i]
const isValueValid =
item.conditionType === 'order_platform'
? Array.isArray(item.conditionValue) && item.conditionValue.length > 0
: item.conditionValue !== null && item.conditionValue !== undefined
if (!item.conditionType || !isValueValid || !item.operator) {
callback(new Error('请完善配货规则'))
return
}
}
callback()
}
const rules = computed(() => {
const base = {
areaDesc: [
{ required: true, message: '请输入配货区说明', trigger: 'blur' },
],
areaCode: [{ required: true, message: '请选择配货区', trigger: 'change' }],
autoPrint: [
{ required: true, message: '请选择是否自动打单', trigger: 'change' },
],
secondScan: [
{
required: true,
message: '请选择是否对接二次扫码设备',
trigger: 'change',
},
],
sortNo: [{ required: true, message: '请输入序号', trigger: 'blur' }],
}
if (form.value.areaCode === 'AREA_0') return base
return {
...base,
conditions: [
{ validator: validateConditions, trigger: 'blur' },
{ required: true, message: '请完善配货规则', trigger: 'change' },
],
}
})
const platformList = platformJson
const formatConditionsForForm = (conditions: SortingRuleCondition[]) =>
conditions.map((item) => ({
...item,
conditionValue:
typeof item.conditionValue === 'string'
? item.conditionValue.split(',').filter(Boolean)
: item.conditionValue,
}))
// 添加配货规则
const addPickingRuleItem = () => {
form.value.conditions.push(createPickingRuleItem())
formRef.value?.validateField('conditions')
}
// 删除配货规则
const removePickingRuleItem = (index: number) => {
form.value.conditions.splice(index, 1)
formRef.value?.validateField('conditions')
}
// 加载配货区列表
// 新增:剔除已选配货区
// 编辑:剔除已选配货区,但包含当前配货区
// 编辑配货区0:列表包含配货区0(def === true)
const loadAreaList = async () => {
const res = await getAreaListApi(props.warehouseId)
if (res.code !== 200) return
areaList.value = res.data
// 新增
if (!props.isEdit) {
areaList.value = areaList.value.filter((item) => item.used === false)
}
// 编辑配货区0
else if (props.editData?.areaCode === 'AREA_0') {
areaList.value = areaList.value.filter((item) => item.def === true)
}
// 编辑其他配货区
else {
areaList.value = areaList.value.filter(
(item) => item.used === false || item.code === props.editData?.areaCode,
)
}
}
// 获取配货规则条件
const getConditionTypeList = async () => {
const res = await getConditionTypeListApi()
if (res.code !== 200) return
pickingRuleList.value = res.data
}
// 获取配货规则操作符
const getOperatorList = async () => {
const res = await getOperatorListApi()
if (res.code !== 200) return
operatorList.value = res.data
}
// 提交
const handleSubmit = async () => {
form.value.warehouseId = props.warehouseId
form.value.warehouseName = props.warehouseName
if (props.editData?.areaCode !== 'AREA_0') {
await formRef.value?.validate()
}
const submitData = {
...form.value,
// 格式化配货规则
conditions: form.value.conditions.map(
(item): SortingRuleCondition => ({
...item,
conditionValue: Array.isArray(item.conditionValue)
? item.conditionValue.join(',')
: item.conditionValue,
}),
),
}
const res = props.isEdit
? await editAreaApi(submitData)
: await addAreaApi(submitData)
if (res.code !== 200) return
ElMessage.success(props.isEdit ? '编辑成功' : '新增成功')
visible.value = false
emit('submit')
}
onMounted(async () => {
await Promise.all([loadAreaList(), getConditionTypeList(), getOperatorList()])
if (props.editData) {
form.value = {
...props.editData,
conditions: formatConditionsForForm(props.editData.conditions),
}
}
})
</script>
<style scoped lang="scss">
.item-info {
font-size: 12px;
color: #666;
line-height: 1;
margin-top: -15px;
}
.picking-rules {
background-color: #eee;
border-radius: 3px;
padding: 5px 15px;
width: 100%;
.header {
font-size: 12px;
font-weight: 500;
display: flex;
align-items: center;
:deep(.el-radio__label) {
font-size: 12px;
}
}
.content {
display: flex;
align-items: center;
gap: 10px;
margin-top: 8px;
&:first-of-type {
margin-top: 6px;
}
}
.rule-action-btn {
font-size: 16px;
}
.platform-select {
:deep(.el-select__wrapper) {
height: var(--el-component-size);
min-height: var(--el-component-size);
box-sizing: border-box;
}
:deep(.el-select__selection) {
flex-wrap: nowrap;
overflow: hidden;
}
:deep(.el-select__selected-item) {
flex-shrink: 1;
min-width: 0;
overflow: hidden;
}
:deep(.el-tag) {
max-width: 100%;
.el-tag__content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
</style>
<style lang="scss">
.customize-select-style {
.el-select-dropdown__list {
width: 500px;
display: flex;
flex-wrap: wrap;
}
}
</style>
<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 }) ...@@ -532,6 +532,14 @@ defineExpose({ clearSelection, getSelectedIds, refresh })
.operation-number { .operation-number {
font-size: 12px; font-size: 12px;
cursor: pointer; 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 { .quantity-badge {
...@@ -657,4 +665,25 @@ defineExpose({ clearSelection, getSelectedIds, refresh }) ...@@ -657,4 +665,25 @@ defineExpose({ clearSelection, getSelectedIds, refresh })
.flex-row-gap6 { .flex-row-gap6 {
gap: 6px; 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> </style>
...@@ -325,11 +325,11 @@ const addOtherCurrency = async () => { ...@@ -325,11 +325,11 @@ const addOtherCurrency = async () => {
ElMessage.error('请输入出库数量') ElMessage.error('请输入出库数量')
return return
} }
const usableInventory = arr[i].usableInventory || 0 // const usableInventory = arr[i].usableInventory || 0
if ((arr[i].outCount as number) > usableInventory) { // if ((arr[i].outCount as number) > usableInventory) {
ElMessage.error('出库数量不能大于可用库存数量') // ElMessage.error('出库数量不能大于可用库存数量')
return // return
} // }
if (!arr[i].locationId) { if (!arr[i].locationId) {
ElMessage.error('请选择库位') ElMessage.error('请选择库位')
return 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 @@ ...@@ -152,7 +152,7 @@
> >
<ElInput <ElInput
v-model.trim="searchForm.operationNo" v-model.trim="searchForm.operationNo"
placeholder="操作单号" placeholder="多个操作单号,分隔"
clearable clearable
style="width: 140px" style="width: 140px"
/> />
...@@ -512,11 +512,6 @@ ...@@ -512,11 +512,6 @@
转至待排单 转至待排单
</ElButton> </ElButton>
</span> </span>
<!-- <span v-if="status === 'PENDING_RECEIVE'" class="item">
<ElButton type="warning" @click="handleTransferOldFlow"
>转旧流程</ElButton
>
</span> -->
<span v-if="status === 'PENDING_SCHEDULE'" class="item"> <span v-if="status === 'PENDING_SCHEDULE'" class="item">
<ElButton type="primary" @click="handleArrange">排单</ElButton> <ElButton type="primary" @click="handleArrange">排单</ElButton>
</span> </span>
...@@ -580,8 +575,19 @@ ...@@ -580,8 +575,19 @@
>补胚失败</ElButton >补胚失败</ElButton
> >
</span> </span>
<span v-if="status === 'PENDING_PACKING'" class="item"> <span v-if="status === 'IN_PRODUCTION' && isEnableSorting" class="item">
<ElButton type="success" @click="handleSeedingWall" <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 >配货打单</ElButton
> >
</span> </span>
...@@ -605,7 +611,7 @@ ...@@ -605,7 +611,7 @@
> >
</span> </span>
<span v-if="status === 'IN_PRODUCTION'" class="item"> <span v-if="status === 'IN_PRODUCTION'" class="item">
<ElButton type="success" @click="handleProductionComplete" <ElButton type="warning" @click="handleProductionComplete"
>生产完成</ElButton >生产完成</ElButton
> >
</span> </span>
...@@ -705,6 +711,17 @@ ...@@ -705,6 +711,17 @@
>刷新商品信息</ElButton >刷新商品信息</ElButton
> >
</span> </span>
<span
v-if="
status === 'PENDING_RECEIVE' &&
pendingAcceptSubTab === 'ACCEPT_FAIL_OUT_OF_STOCK'
"
class="item"
>
<ElButton type="success" @click="handleGetOrderInventoryDetail"
>订单库存明细</ElButton
>
</span>
</div> </div>
<div v-if="status === 'SUSPEND'" class="status-subtabs"> <div v-if="status === 'SUSPEND'" class="status-subtabs">
<div <div
...@@ -1039,9 +1056,15 @@ ...@@ -1039,9 +1056,15 @@
v-model="podOrderVisible" v-model="podOrderVisible"
:print-order="printOrder" :print-order="printOrder"
:warehouse-list="warehouseList" :warehouse-list="warehouseList"
:title="wallType === 'print' ? '配货打单' : '配货分拣'"
:is-new-order="true" :is-new-order="true"
ws-open-code="STARTORDERNEWPOD" :wall-type="wallType"
ws-close-code="ENDORDERNEWPOD" :ws-open-code="
wallType === 'print' ? 'STARTORDERNEWPOD' : 'STARTORDERNEWPODTOP'
"
:ws-close-code="
wallType === 'print' ? 'ENDORDERNEWPOD' : 'ENDORDERNEWPODTOP'
"
init-url="factory/podOrderPacking/local/getPodBoxOrderDetails" init-url="factory/podOrderPacking/local/getPodBoxOrderDetails"
@set-printer="handlePrinterChange" @set-printer="handlePrinterChange"
@set-warehouse-id="handleWarehouseIdChange" @set-warehouse-id="handleWarehouseIdChange"
...@@ -1150,6 +1173,11 @@ ...@@ -1150,6 +1173,11 @@
</span> </span>
</template> </template>
</ElDialog> </ElDialog>
<OrderInventoryDetailDialog
v-model:visible="orderInventoryDetailVisible"
:warehouse-list="warehouseList"
:selected-rows="selectedRows"
/>
</div> </div>
</template> </template>
...@@ -1209,6 +1237,7 @@ import { ...@@ -1209,6 +1237,7 @@ import {
interceptUpdateApi, interceptUpdateApi,
interceptSuccessApi, interceptSuccessApi,
} from '@/api/factoryOrderNew' } from '@/api/factoryOrderNew'
import { getConfigApi } from '@/api/order'
import { getLogisticsWayApi } from '@/api/podUsOrder' import { getLogisticsWayApi } from '@/api/podUsOrder'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import { filePath } from '@/api/axios' import { filePath } from '@/api/axios'
...@@ -1243,7 +1272,9 @@ import { useOrderSearchForm } from './hooks/useOrderSearchForm' ...@@ -1243,7 +1272,9 @@ import { useOrderSearchForm } from './hooks/useOrderSearchForm'
import { useOrderStatusTree } from './hooks/useOrderStatusTree' import { useOrderStatusTree } from './hooks/useOrderStatusTree'
import { useOrderListAndDetail } from './hooks/useOrderListAndDetail' import { useOrderListAndDetail } from './hooks/useOrderListAndDetail'
import { useOrderBatchActions } from './hooks/useOrderBatchActions' 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 resultInfo = ref<ResultInfoDataItem[]>([])
const resultRefs = ref() const resultRefs = ref()
...@@ -1252,7 +1283,7 @@ const statusSidebarCollapsed = ref(false) ...@@ -1252,7 +1283,7 @@ const statusSidebarCollapsed = ref(false)
const toggleStatusSidebar = () => { const toggleStatusSidebar = () => {
statusSidebarCollapsed.value = !statusSidebarCollapsed.value statusSidebarCollapsed.value = !statusSidebarCollapsed.value
} }
const orderInventoryDetailVisible = ref(false)
const batchManageRef = ref<InstanceType<typeof BatchManageTable>>() const batchManageRef = ref<InstanceType<typeof BatchManageTable>>()
const waitingRestockRef = ref<InstanceType<typeof WaitingRestockTable>>() const waitingRestockRef = ref<InstanceType<typeof WaitingRestockTable>>()
const cardLayoutRef = ref<InstanceType<typeof CardLayout>>() const cardLayoutRef = ref<InstanceType<typeof CardLayout>>()
...@@ -2521,8 +2552,16 @@ const handlePrinterChange = (value: string) => { ...@@ -2521,8 +2552,16 @@ const handlePrinterChange = (value: string) => {
sheetPrinter.value = value sheetPrinter.value = value
localStorage.setItem('sheetPrinter', JSON.stringify(value)) localStorage.setItem('sheetPrinter', JSON.stringify(value))
} }
const handleWarehouseIdChange = (value: string) => { const handleWarehouseIdChange = (
value:
| string
| { warehouseId: string | number; sortingAreaId: string | number },
) => {
if (wallType.value === 'print') {
localStorage.setItem('localNewWarehouseId', JSON.stringify(value)) localStorage.setItem('localNewWarehouseId', JSON.stringify(value))
} else if (wallType.value === 'sort') {
localStorage.setItem('localSortingAreaId', JSON.stringify(value))
}
} }
const mapOrderParamListToSubmitItems = ( const mapOrderParamListToSubmitItems = (
orderParamList: { id: number; dataVersion?: number }[], orderParamList: { id: number; dataVersion?: number }[],
...@@ -2543,7 +2582,9 @@ const getPrintLogisticLabelFactory = (id?: number) => ...@@ -2543,7 +2582,9 @@ const getPrintLogisticLabelFactory = (id?: number) =>
getfaceSimplexFileApi([id ?? 0]) getfaceSimplexFileApi([id ?? 0])
const { getCLodop } = useLodop() const { getCLodop } = useLodop()
const handleSeedingWall = () => { const wallType = ref<'print' | 'sort'>('print')
const handleSeedingWall = (type: 'print' | 'sort') => {
wallType.value = type
const lodop = getCLodop(null, null) const lodop = getCLodop(null, null)
if (!lodop) return if (!lodop) return
sheetPrinter.value = lodop.GET_PRINTER_NAME(0) sheetPrinter.value = lodop.GET_PRINTER_NAME(0)
...@@ -2760,7 +2801,10 @@ const handleDownloadMaterial = async () => { ...@@ -2760,7 +2801,10 @@ const handleDownloadMaterial = async () => {
? await downloadMaterialApi(ids as number[]) ? await downloadMaterialApi(ids as number[])
: await downloadOperationMaterialApi(ids as number[]) : await downloadOperationMaterialApi(ids as number[])
if (res.code !== 200) return if (res.code !== 200) return
window.open(filePath + res.message, '_blank') downloadByUrl(
filePath + res.message,
res.message?.split('/').pop() || 'download',
)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} finally { } finally {
...@@ -2776,7 +2820,10 @@ const handleDownloadMaterialByProduct = async (row: ProductListData) => { ...@@ -2776,7 +2820,10 @@ const handleDownloadMaterialByProduct = async (row: ProductListData) => {
try { try {
const res = await downloadOperationMaterialApi([row.id]) const res = await downloadOperationMaterialApi([row.id])
if (res.code !== 200) return if (res.code !== 200) return
window.open(filePath + res.message, '_blank') downloadByUrl(
filePath + res.message,
res.message?.split('/').pop() || 'download',
)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} finally { } finally {
...@@ -3116,12 +3163,23 @@ const handleInterceptionFail = async (row?: FactoryOrderNewListData) => { ...@@ -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(() => { onMounted(() => {
loadStatusTreeCounts() loadStatusTreeCounts()
loadAllDictionaries() loadAllDictionaries()
getLogisticsWay() getLogisticsWay()
getReceiverCountryList() getReceiverCountryList()
loadWarehouseList() loadWarehouseList()
getFunctionSwitch()
void treeRef.value void treeRef.value
void tableRef.value void tableRef.value
if (status.value === 'PENDING_RECEIVE') { if (status.value === 'PENDING_RECEIVE') {
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
> >
<template #header> <template #header>
<div class="title"> <div class="title">
<span>{{ isNewOrder ? '配货打单' : '播种墙配货' }}</span> <span>{{ props.title }}</span>
<span v-if="socketConnect === 'online'" class="online">[在线]</span> <span v-if="socketConnect === 'online'" class="online">[在线]</span>
<span v-else class="offline">[离线]</span> <span v-else class="offline">[离线]</span>
<ElButton <ElButton
...@@ -47,6 +47,21 @@ ...@@ -47,6 +47,21 @@
</div> </div>
<div class="form-item"> <div class="form-item">
<ElSelect <ElSelect
v-if="props.wallType === 'sort'"
v-model="sortingAreaId"
placeholder="请选择配货区"
style="width: 250px"
@change="handleSortingAreaChange"
>
<ElOption
v-for="item in sortingAreaList"
:key="item.id"
:label="item.areaName + ' - ' + item.warehouseName"
:value="item.id"
/>
</ElSelect>
<ElSelect
v-else
v-model="warehouseId" v-model="warehouseId"
placeholder="请选择仓库" placeholder="请选择仓库"
style="width: 200px" style="width: 200px"
...@@ -65,7 +80,11 @@ ...@@ -65,7 +80,11 @@
ref="productionOrderRef" ref="productionOrderRef"
v-model="productionOrder" v-model="productionOrder"
:placeholder=" :placeholder="
props.isNewOrder ? '请输入操作单号' : '请输入生产单号' props.wallType === 'us'
? '请输入生产单号'
: props.wallType === 'sort'
? '请输入操作单号/生产单号'
: '请输入操作单号'
" "
clearable clearable
style="width: 100%" style="width: 100%"
...@@ -124,14 +143,14 @@ ...@@ -124,14 +143,14 @@
> >
<template #image="{ row }"> <template #image="{ row }">
<div <div
style="display: flex; flex-wrap: nowrap"
v-if="row.previewImgs?.length" v-if="row.previewImgs?.length"
style="display: flex; flex-wrap: nowrap"
> >
<div <div
v-for="img in row.previewImgs" v-for="img in row.previewImgs"
:key="img" :key="img"
@click.stop="handleCurrentChange(img.url)"
style="cursor: pointer; margin-right: 5px; flex: 1" style="cursor: pointer; margin-right: 5px; flex: 1"
@click.stop="handleCurrentChange(img.url)"
> >
<img v-if="img.url" :src="img.url" alt="" /> <img v-if="img.url" :src="img.url" alt="" />
</div> </div>
...@@ -147,16 +166,27 @@ ...@@ -147,16 +166,27 @@
</TableView> </TableView>
</div> </div>
</div> </div>
<div class="right-panel">
<div v-if="props.wallType === 'sort'" class="sorting-area-content">
{{
(sortingAreaList.find((item) => item.id === sortingAreaId)
?.areaName || '') +
' - ' +
(sortingAreaList.find((item) => item.id === sortingAreaId)
?.warehouseName || '')
}}
</div>
<div class="flex right-panel-body">
<div class="middle-content"> <div class="middle-content">
<div class="box-top"> <div class="box-top">
<div class="box-top-item" v-if="boxIndex !== 0"> <div v-if="boxIndex !== 0" class="box-top-item">
<span class="box-top-item-box-index"> <span class="box-top-item-box-index">
{{ boxIndex }} {{ boxIndex }}
</span> </span>
<span class="box-top-item-box-index-text">号箱</span> <span class="box-top-item-box-index-text">号箱</span>
<span style="font-size: 30px">放入第</span> <span style="font-size: 30px; white-space: nowrap">放入第</span>
<div <div
class="box-top-item-box-index-number" class="box-top-item-box-index-number"
:style="{ :style="{
...@@ -176,7 +206,7 @@ ...@@ -176,7 +206,7 @@
podOrderDetailsData.pickingNumber === podOrderDetailsData.pickingNumber ===
podOrderDetailsData.purchaseNumber podOrderDetailsData.purchaseNumber
" "
style="font-size: 30px" style="font-size: 30px; white-space: nowrap"
>件已配齐</span >件已配齐</span
> >
<span v-else style="font-size: 30px">件商品</span> <span v-else style="font-size: 30px">件商品</span>
...@@ -188,6 +218,7 @@ ...@@ -188,6 +218,7 @@
<div class="box-top-item-status"> <div class="box-top-item-status">
<span <span
v-if=" v-if="
isAutoPrint &&
podOrderDetailsData?.pickingNumber && podOrderDetailsData?.pickingNumber &&
podOrderDetailsData?.purchaseNumber && podOrderDetailsData?.purchaseNumber &&
podOrderDetailsData?.pickingNumber === podOrderDetailsData?.pickingNumber ===
...@@ -195,7 +226,9 @@ ...@@ -195,7 +226,9 @@
" "
> >
<span v-if="podOrderDetailsData?.printResult"> <span v-if="podOrderDetailsData?.printResult">
面单{{ renderPrintResult(podOrderDetailsData?.printResult) }} 面单{{
renderPrintResult(podOrderDetailsData?.printResult)
}}
</span> </span>
<span v-else>面单打印中。。。</span> <span v-else>面单打印中。。。</span>
</span> </span>
...@@ -204,10 +237,15 @@ ...@@ -204,10 +237,15 @@
<div class="box-top-item-btn"> <div class="box-top-item-btn">
<ElButton <ElButton
type="primary" type="primary"
@click="podOrderDetailsData && print(podOrderDetailsData, true)" @click="
podOrderDetailsData && print(podOrderDetailsData, true)
"
>手动打印</ElButton >手动打印</ElButton
> >
<ElButton v-if="!isNewOrder" type="primary" @click="printNormal" <ElButton
v-if="wallType === 'us'"
type="primary"
@click="printNormal"
>普货拣货 >普货拣货
</ElButton> </ElButton>
<ElButton type="success" @click="handlePrintFinish" <ElButton type="success" @click="handlePrintFinish"
...@@ -270,6 +308,8 @@ ...@@ -270,6 +308,8 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</ElDialog> </ElDialog>
</template> </template>
...@@ -292,6 +332,7 @@ import { ...@@ -292,6 +332,7 @@ import {
submitInspectionApi, submitInspectionApi,
printNormalPickPdfApi, printNormalPickPdfApi,
} from '@/api/podUsOrder' } from '@/api/podUsOrder'
import { getSortingRuleListApi } from '@/api/order'
import useUserStore from '@/store/user' import useUserStore from '@/store/user'
import { Check, Refresh } from '@element-plus/icons-vue' import { Check, Refresh } from '@element-plus/icons-vue'
import socket from '@/utils/websocket' import socket from '@/utils/websocket'
...@@ -299,6 +340,7 @@ import { WarehouseListData } from '@/types/index' ...@@ -299,6 +340,7 @@ import { WarehouseListData } from '@/types/index'
import { filePath } from '@/api/axios.ts' import { filePath } from '@/api/axios.ts'
import { ElButton, ElIcon, ElTag } from 'element-plus' import { ElButton, ElIcon, ElTag } from 'element-plus'
import { BaseRespData } from '@/types/api' import { BaseRespData } from '@/types/api'
import type { SortingList } from '@/types/api/order'
const { getCLodop } = useLodop() const { getCLodop } = useLodop()
...@@ -311,12 +353,16 @@ const props = withDefaults( ...@@ -311,12 +353,16 @@ const props = withDefaults(
wsOpenCode?: string wsOpenCode?: string
wsCloseCode?: string wsCloseCode?: string
initUrl?: string initUrl?: string
wallType?: 'print' | 'sort' | 'us'
title?: string
}>(), }>(),
{ {
isNewOrder: false, isNewOrder: false,
wsOpenCode: 'STARTORDER', wsOpenCode: 'STARTORDER',
wsCloseCode: 'ENDORDER', wsCloseCode: 'ENDORDER',
initUrl: 'factory/podJomallOrderUs/local/getPodBoxOrderDetails', initUrl: 'factory/podJomallOrderUs/local/getPodBoxOrderDetails',
wallType: 'us',
title: '播种墙配货',
}, },
) )
const emit = defineEmits([ const emit = defineEmits([
...@@ -402,14 +448,14 @@ const podOrderDetailsColumns = computed(() => [ ...@@ -402,14 +448,14 @@ const podOrderDetailsColumns = computed(() => [
align: 'center', align: 'center',
}, },
{ {
label: props.isNewOrder ? '操作单号' : '生产单号', label: props.wallType === 'us' ? '生产单号' : '操作单号',
prop: props.isNewOrder ? 'operationNos' : 'podJomallUsNo', prop: props.wallType === 'us' ? 'podJomallUsNo' : 'operationNos',
width: props.isNewOrder ? 180 : 150, width: props.wallType === 'us' ? 150 : 180,
align: 'center', align: 'center',
render: (row: ProductList) => { render: (row: ProductList) => {
return ( return (
<div> <div>
{props.isNewOrder && {props.wallType !== 'us' &&
row.operationNos?.split(',').map((item) => { row.operationNos?.split(',').map((item) => {
const { operationNo, status, statusText } = parseOperationNo(item) const { operationNo, status, statusText } = parseOperationNo(item)
const { type, style } = operationStatusTagMap[status] || {} const { type, style } = operationStatusTagMap[status] || {}
...@@ -428,7 +474,7 @@ const podOrderDetailsColumns = computed(() => [ ...@@ -428,7 +474,7 @@ const podOrderDetailsColumns = computed(() => [
</div> </div>
) )
})} })}
{!props.isNewOrder && row.podJomallUsNo} {props.wallType === 'us' && row.podJomallUsNo}
</div> </div>
) )
}, },
...@@ -490,14 +536,43 @@ watch(visible, async (value: boolean) => { ...@@ -490,14 +536,43 @@ watch(visible, async (value: boolean) => {
if (value) { if (value) {
podOrderDetailsData.value = {} podOrderDetailsData.value = {}
currentCode = '' currentCode = ''
const localRaw = props.isNewOrder if (props.wallType === 'sort') {
? localStorage.getItem('localNewWarehouseId') await getSortingAreaList()
: localStorage.getItem('locaclWarehouseId') }
const localId = localRaw ? JSON.parse(localRaw) : '' let localRaw = ''
switch (props.wallType) {
case 'us':
localRaw = localStorage.getItem('locaclWarehouseId') || ''
break
case 'print':
localRaw = localStorage.getItem('localNewWarehouseId') || ''
break
case 'sort':
localRaw = localStorage.getItem('localSortingAreaId') || ''
break
}
const localData = localRaw ? JSON.parse(localRaw) : ''
// 配货分拣 存仓库+配货区
if (props.wallType === 'sort') {
const localSortingAreaId = localData.sortingAreaId
const localWarehouseId = localData.warehouseId
const hit = sortingAreaList.value.find(
(item) =>
item.id === localSortingAreaId &&
item.warehouseId === localWarehouseId,
)
if (hit) {
sortingAreaId.value = hit.id
warehouseId.value = hit.warehouseId
isAutoPrint.value = hit.autoPrint
}
} else {
/* 先找一次,确认本地值是否存在于列表 */ /* 先找一次,确认本地值是否存在于列表 */
const hit = props.warehouseList.find((w) => w.id == localId) const hit = props.warehouseList.find((w) => w.id == localData)
warehouseId.value = hit ? localId : props.warehouseList[0]?.id warehouseId.value = hit ? localData : props.warehouseList[0]?.id
_warehouseId.value = hit ? localId : props.warehouseList[0]?.id _warehouseId.value = hit ? localData : props.warehouseList[0]?.id
}
if (userStore.user?.factory.id) { if (userStore.user?.factory.id) {
try { try {
...@@ -512,6 +587,8 @@ watch(visible, async (value: boolean) => { ...@@ -512,6 +587,8 @@ watch(visible, async (value: boolean) => {
code: props.wsOpenCode, code: props.wsOpenCode,
factoryNo: userStore.user?.factory.id, factoryNo: userStore.user?.factory.id,
warehouseId: warehouseId.value, warehouseId: warehouseId.value,
packingId:
props.wallType === 'sort' ? sortingAreaId.value : undefined,
}) })
} catch (error) { } catch (error) {
console.error(error) console.error(error)
...@@ -519,6 +596,7 @@ watch(visible, async (value: boolean) => { ...@@ -519,6 +596,7 @@ watch(visible, async (value: boolean) => {
} }
initOrderDetailBox() initOrderDetailBox()
initPrintDevice() initPrintDevice()
const locaclPrinter = localStorage.getItem('sheetPrinter') const locaclPrinter = localStorage.getItem('sheetPrinter')
if (locaclPrinter) sheetPrinter.value = JSON.parse(locaclPrinter) if (locaclPrinter) sheetPrinter.value = JSON.parse(locaclPrinter)
emit('set-printer', sheetPrinter.value) emit('set-printer', sheetPrinter.value)
...@@ -528,14 +606,14 @@ watch(visible, async (value: boolean) => { ...@@ -528,14 +606,14 @@ watch(visible, async (value: boolean) => {
code: props.wsCloseCode, code: props.wsCloseCode,
factoryNo: userStore.user?.factory.id, factoryNo: userStore.user?.factory.id,
warehouseId: warehouseId.value, warehouseId: warehouseId.value,
packingId: sortingAreaId.value,
}) })
socket.close() socket.close()
} }
} }
}) })
watch(boxIndex, (value: number | null) => { watch(boxIndex, () => {
// if (value) { // if (value) {
console.log('boxIndex11111', value)
const bool = !boxChange.value const bool = !boxChange.value
boxChange.value = false boxChange.value = false
...@@ -597,7 +675,6 @@ const renderItemBox = (bool: boolean) => { ...@@ -597,7 +675,6 @@ const renderItemBox = (bool: boolean) => {
renderLock = true renderLock = true
let boxItem = podBoxList.value?.find((item) => item.box === boxIndex.value) let boxItem = podBoxList.value?.find((item) => item.box === boxIndex.value)
console.log(boxItem, 'boxItem')
if (!boxItem) boxItem = { data: { productList: [] } } if (!boxItem) boxItem = { data: { productList: [] } }
const { data } = boxItem const { data } = boxItem
data?.productList?.forEach((el) => { data?.productList?.forEach((el) => {
...@@ -652,13 +729,32 @@ const renderItemBox = (bool: boolean) => { ...@@ -652,13 +729,32 @@ const renderItemBox = (bool: boolean) => {
} }
} }
currentCode = '' currentCode = ''
} else {
// 切换箱子,默认展示第一张图片
coverImage.value = productList[0]?.previewImgs?.[0]?.url || ''
} }
podOrderDetailsData.value = data podOrderDetailsData.value = data
if (productList.every((item) => item.power)) { if (productList.every((item) => item.power)) {
if (userStore.user?.id !== boxItem.fromUser) return if (userStore.user?.id !== boxItem.fromUser) return
// 配货分拣 非自动打单的配货区: 不打印 不打单完成; 自动打单的配货区: 打印成功后打单完成
if (props.wallType === 'sort' && !isAutoPrint.value) {
renderLock = false
return
}
print(data, false, () => { print(data, false, () => {
if (
props.wallType === 'sort' &&
isAutoPrint.value &&
data.printResult === 'printSuccess'
) {
submitInspection(() => {
renderLock = false
})
return
}
renderLock = false renderLock = false
}) })
} else { } else {
...@@ -669,7 +765,12 @@ const messageChange = (data: WebSocketMessage) => { ...@@ -669,7 +765,12 @@ const messageChange = (data: WebSocketMessage) => {
if (!data) return if (!data) return
const { code, ...more } = data const { code, ...more } = data
if (code === 'POD_PRINT_ORDER' || code === 'FACTORY_POD_ORDER_PRINT_ORDER') { // 扫码进箱
if (
code === 'POD_PRINT_ORDER' ||
code === 'FACTORY_POD_ORDER_PRINT_ORDER' ||
code === 'FACTORY_POD_ORDER_TOP_PRINT_ORDER'
) {
try { try {
if (typeof more.txt === 'string') { if (typeof more.txt === 'string') {
console.log( console.log(
...@@ -684,15 +785,17 @@ const messageChange = (data: WebSocketMessage) => { ...@@ -684,15 +785,17 @@ const messageChange = (data: WebSocketMessage) => {
console.log('WebSocketMessage', more) console.log('WebSocketMessage', more)
setPodBoxList(more) setPodBoxList(more)
} else if ( }
// 清空箱子
else if (
code === 'POD_BOX_FLUSH' || code === 'POD_BOX_FLUSH' ||
code === 'FACTORY_POD_ORDER_BOX_FLUSH' code === 'FACTORY_POD_ORDER_BOX_FLUSH' ||
code === 'FACTORY_POD_ORDER_TOP_BOX_FLUSH'
) { ) {
initOrderDetailBox() initOrderDetailBox()
} }
} }
const setPodBoxList = (data: WebSocketMessage) => { const setPodBoxList = (data: WebSocketMessage) => {
console.log(data, 'datatatata')
const obj = data.txt const obj = data.txt
if (obj && typeof obj === 'string') { if (obj && typeof obj === 'string') {
const parsedData = JSON.parse(obj) const parsedData = JSON.parse(obj)
...@@ -746,6 +849,10 @@ const handleSearch = () => { ...@@ -746,6 +849,10 @@ const handleSearch = () => {
const everyPower = podOrderDetailsData.value?.productList?.every( const everyPower = podOrderDetailsData.value?.productList?.every(
(item) => item.power, (item) => item.power,
) )
if (props.wallType === 'sort' && !isAutoPrint.value) {
getPackingData(code)
return
}
if (everyPower) { if (everyPower) {
/** /**
* printSuccess 打印成功 * printSuccess 打印成功
...@@ -753,7 +860,12 @@ const handleSearch = () => { ...@@ -753,7 +860,12 @@ const handleSearch = () => {
* printIng 打印中 * printIng 打印中
* notPrintSuccess 未能获取打印状态 * notPrintSuccess 未能获取打印状态
*/ */
if (podOrderDetailsData.value?.printResult === 'printSuccess') { // 非配货分拣 打印成功提示;配货分拣:开启自动打单且打印成功,提交;配货分拣:不开启自动打单,不提示
if (
podOrderDetailsData.value?.printResult === 'printSuccess' &&
(props.wallType !== 'sort' ||
(props.wallType === 'sort' && isAutoPrint.value))
) {
submitInspection(() => { submitInspection(() => {
getPackingData(code) getPackingData(code)
}) })
...@@ -781,23 +893,38 @@ const getPackingData = async (code: string) => { ...@@ -781,23 +893,38 @@ const getPackingData = async (code: string) => {
productionOrder.value = '' productionOrder.value = ''
return return
} }
if (!warehouseId.value) { if (props.wallType !== 'sort' && !warehouseId.value) {
return ElMessage.warning('请选择仓库') return ElMessage.warning('请选择仓库')
} }
const url = props.isNewOrder let url = ''
? 'factory/podOrderPacking/local/putPackingSafe' switch (props.wallType) {
: 'factory/podJomallOrderUs/local/putPackingSafe' case 'us':
url = 'factory/podJomallOrderUs/local/putPackingSafe'
break
case 'print':
url = 'factory/podOrderPacking/local/putPackingSafe'
break
case 'sort':
url = 'factory/podOrderPacking/top/putPackingSafe'
break
}
let params = {} let params = {}
if (props.isNewOrder) { if (props.wallType === 'us') {
params = { params = {
podOperationNo: code, podJomallUsNo: code,
box: boxIndex.value, box: boxIndex.value,
factoryNo, factoryNo,
warehouseId: warehouseId.value, warehouseId: warehouseId.value,
} }
} else if (props.wallType === 'sort') {
params = {
podOperationNo: code,
box: boxIndex.value,
factoryNo,
}
} else { } else {
params = { params = {
podJomallUsNo: code, podOperationNo: code,
box: boxIndex.value, box: boxIndex.value,
factoryNo, factoryNo,
warehouseId: warehouseId.value, warehouseId: warehouseId.value,
...@@ -811,12 +938,26 @@ const getPackingData = async (code: string) => { ...@@ -811,12 +938,26 @@ const getPackingData = async (code: string) => {
productionOrder.value = '' productionOrder.value = ''
return return
} }
const { box, data } = res.data const { box, data, packingId, factoryNo: respFactoryNo } = res.data
console.log('box', box)
// 配货分拣 扫码
if (props.wallType === 'sort') {
const area = sortingAreaList.value.find((item) => item.id == packingId)
const areaChanged =
sortingAreaId.value != packingId ||
(!!area && warehouseId.value != area.warehouseId)
handleSortingAreaChange(
packingId as number,
respFactoryNo ?? factoryNo,
'scan',
)
if (areaChanged) {
await initOrderDetailBox('scan')
}
}
// if (box) { boxChange.value = true
boxIndex.value = box as number boxIndex.value = box as number
// }
if (boxIndex.value == 0) { if (boxIndex.value == 0) {
podOrderDetailsData.value = data as OrderData podOrderDetailsData.value = data as OrderData
podOrderDetailsData.value.fromUser = userStore.user?.id podOrderDetailsData.value.fromUser = userStore.user?.id
...@@ -835,11 +976,6 @@ const getPackingData = async (code: string) => { ...@@ -835,11 +976,6 @@ const getPackingData = async (code: string) => {
}) })
} }
} }
// renderItemBox(true)
console.log('podBoxList', podBoxList.value)
// }
} catch (error) { } catch (error) {
const err = error as BaseRespData<{ const err = error as BaseRespData<{
inventory: number inventory: number
...@@ -847,7 +983,7 @@ const getPackingData = async (code: string) => { ...@@ -847,7 +983,7 @@ const getPackingData = async (code: string) => {
availableInventory: number availableInventory: number
thirdSkuCode?: string thirdSkuCode?: string
}> }>
if (props.isNewOrder && err?.code === 301) { if (props.wallType !== 'us' && err?.code === 301) {
loading.close() loading.close()
await ElMessageBox.alert( await ElMessageBox.alert(
`${err.data?.thirdSkuCode}库存不足,无法进入生产!请联系仓库管理人员核对库存。<br/> `${err.data?.thirdSkuCode}库存不足,无法进入生产!请联系仓库管理人员核对库存。<br/>
...@@ -873,17 +1009,19 @@ const submitInspection = async (callback: () => void) => { ...@@ -873,17 +1009,19 @@ const submitInspection = async (callback: () => void) => {
return return
} }
try { try {
const url = props.isNewOrder const url =
? 'factory/podOrderPacking/podPrintOrderComplete' props.wallType === 'us'
: 'factory/podJomallOrderUs/podPrintOrderComplete' ? 'factory/podJomallOrderUs/podPrintOrderComplete'
: 'factory/podOrderPacking/podPrintOrderComplete'
let params = {} let params = {}
if (props.isNewOrder) { if (props.wallType === 'us') {
params = { params = {
orderParamList: [{ id: podOrderDetailsData.value?.id }], orderId: podOrderDetailsData.value?.id,
} }
} else { } else {
params = { params = {
orderId: podOrderDetailsData.value?.id, orderParamList: [{ id: podOrderDetailsData.value?.id }],
} }
} }
const res = await submitInspectionApi( const res = await submitInspectionApi(
...@@ -891,8 +1029,9 @@ const submitInspection = async (callback: () => void) => { ...@@ -891,8 +1029,9 @@ const submitInspection = async (callback: () => void) => {
params, params,
boxIndex.value, boxIndex.value,
warehouseId.value, warehouseId.value,
sortingAreaId.value,
) )
if (res.code !== 200) return // if (res.code !== 200) return
ElMessage.warning(res.message) ElMessage.warning(res.message)
isLock.value = false isLock.value = false
coverImage.value = '' coverImage.value = ''
...@@ -902,17 +1041,18 @@ const submitInspection = async (callback: () => void) => { ...@@ -902,17 +1041,18 @@ const submitInspection = async (callback: () => void) => {
callback && callback() callback && callback()
} catch (error) { } catch (error) {
isLock.value = false isLock.value = false
renderLock = false
productionOrderRef.value.focus() productionOrderRef.value.focus()
console.error(error) console.error(error)
} }
} }
const isBillLading = ref<boolean>(false) const isBillLading = ref<boolean>(false)
const initOrderDetailBox = async () => { const initOrderDetailBox = async (type: 'scan' | 'manual' = 'manual') => {
const factoryNo = userStore.user?.factory.id const factoryNo = userStore.user?.factory.id
if (!factoryNo) { if (!factoryNo) {
return return
} }
if (!warehouseId.value) { if (props.wallType !== 'sort' && !warehouseId.value) {
return ElMessage.warning('请选择仓库') return ElMessage.warning('请选择仓库')
} }
const loading = ElLoading.service({ const loading = ElLoading.service({
...@@ -922,11 +1062,17 @@ const initOrderDetailBox = async () => { ...@@ -922,11 +1062,17 @@ const initOrderDetailBox = async () => {
}) })
try { try {
const url = props.initUrl const url = props.initUrl
const res = await getPodBoxListApi(url, factoryNo, warehouseId.value) const res = await getPodBoxListApi(
url,
factoryNo,
warehouseId.value,
sortingAreaId.value,
)
if (res.code !== 200) { if (res.code !== 200) {
ElMessage.warning(res.message) ElMessage.warning(res.message)
return return
} }
orderStore.setPodBoxList({ orderStore.setPodBoxList({
url, url,
boxList: res.data, boxList: res.data,
...@@ -956,9 +1102,14 @@ const initOrderDetailBox = async () => { ...@@ -956,9 +1102,14 @@ const initOrderDetailBox = async () => {
} }
return item return item
}) })
podOrderDetailsData.value = const currentBox = boxIndex.value
boxList.find((item) => item.data)?.data || undefined const currentBoxItem = currentBox
boxIndex.value = boxList.find((item) => item.data)?.box || null ? boxList.find((item) => item.box === currentBox && item.data)
: undefined
const fallbackItem = boxList.find((item) => item.data)
const targetItem = currentBoxItem || fallbackItem
podOrderDetailsData.value = targetItem?.data || undefined
boxIndex.value = targetItem?.box || null
podOrderDetailsData.value?.productList?.forEach((el) => { podOrderDetailsData.value?.productList?.forEach((el) => {
if (!el.previewImgs) { if (!el.previewImgs) {
...@@ -984,9 +1135,15 @@ const initOrderDetailBox = async () => { ...@@ -984,9 +1135,15 @@ const initOrderDetailBox = async () => {
const pickFinished = boxList.filter((item) => { const pickFinished = boxList.filter((item) => {
return item.data?.productList?.every((product) => product.power) return item.data?.productList?.every((product) => product.power)
}) })
// 配货分拣 扫码切换配货区且配货完成 不提示
const boxs = pickFinished.map((item) => item.box) const boxs = pickFinished.map((item) => item.box)
if (boxs.length > 0) {
if (type === 'manual' && boxs.length > 0) {
nextTick(async () => { nextTick(async () => {
// 切换箱子至验货完成的箱子
boxChange.value = true
boxIndex.value = boxs[0] as number
try { try {
await ElMessageBox.alert( await ElMessageBox.alert(
`检测到${boxs.join(',')}号箱验货完成,请及时处理`, `检测到${boxs.join(',')}号箱验货完成,请及时处理`,
...@@ -1045,12 +1202,16 @@ const nextStep = async (callback: () => void) => { ...@@ -1045,12 +1202,16 @@ const nextStep = async (callback: () => void) => {
) )
if ( if (
everyPicked && everyPicked &&
((props.wallType === 'sort' && isAutoPrint.value) ||
props.wallType !== 'sort') &&
(podOrderDetailsData.value?.printResult === 'printSuccess' || (podOrderDetailsData.value?.printResult === 'printSuccess' ||
podOrderDetailsData.value?.printResult === 'notPrintSuccess') podOrderDetailsData.value?.printResult === 'notPrintSuccess')
) { ) {
try { try {
await ElMessageBox.alert( await ElMessageBox.alert(
'当前订单验货完成并打印面单成功,是否转至已完成', `当前订单验货完成并打印面单成功,是否转至${
props.wallType === 'sort' ? '待发货' : '已完成'
}`,
'提示', '提示',
{ {
confirmButtonText: '确定', confirmButtonText: '确定',
...@@ -1101,14 +1262,17 @@ const handleClearBox = async () => { ...@@ -1101,14 +1262,17 @@ const handleClearBox = async () => {
} }
try { try {
const url = props.isNewOrder const url =
? 'factory/podOrderPacking/local/delPodBoxOrderDetailsByBox' props.wallType === 'us'
: 'factory/podJomallOrderUs/local/delPodBoxOrderDetailsByBox' ? 'factory/podJomallOrderUs/local/delPodBoxOrderDetailsByBox'
: 'factory/podOrderPacking/local/delPodBoxOrderDetailsByBox'
const res = await clearBoxApi( const res = await clearBoxApi(
url, url,
factoryNo, factoryNo,
boxIndex.value || null, boxIndex.value || null,
warehouseId.value, warehouseId.value,
sortingAreaId.value,
) )
if (res.code !== 200) { if (res.code !== 200) {
ElMessage.warning(res.message) ElMessage.warning(res.message)
...@@ -1219,13 +1383,15 @@ const clearAllBox = async () => { ...@@ -1219,13 +1383,15 @@ const clearAllBox = async () => {
return return
} }
try { try {
const url = props.isNewOrder const url =
? 'factory/podOrderPacking/local/delPodBoxOrderDetails' props.wallType === 'us'
: 'factory/podJomallOrderUs/local/delPodBoxOrderDetails' ? 'factory/podJomallOrderUs/local/delPodBoxOrderDetails'
: 'factory/podOrderPacking/local/delPodBoxOrderDetails'
const res = await clearAllBoxApi( const res = await clearAllBoxApi(
url, url,
warehouseId.value, warehouseId.value,
userStore.user?.factory.id, userStore.user?.factory.id,
sortingAreaId.value,
) )
if (res.code !== 200) return if (res.code !== 200) return
productionOrderRef.value.focus() productionOrderRef.value.focus()
...@@ -1249,6 +1415,43 @@ const handleCurrentChange = (url: string) => { ...@@ -1249,6 +1415,43 @@ const handleCurrentChange = (url: string) => {
} }
const warehouseId = ref<string | number>('') const warehouseId = ref<string | number>('')
const _warehouseId = ref<string | number>('') const _warehouseId = ref<string | number>('')
const sortingAreaList = ref<SortingList[]>([])
const sortingAreaId = ref<number | string>('')
const isAutoPrint = ref<boolean>(false) // 当前配货区是否自动打单
// 配货分拣 更新配货区
const syncSortingArea = (
packingId: number | string,
factoryNo: number | string,
) => {
const currentArea = sortingAreaList.value.find((item) => item.id == packingId)
if (!currentArea) return
warehouseId.value = currentArea.warehouseId
sortingAreaId.value = packingId
isAutoPrint.value = currentArea.autoPrint
socket.send({
code: props.wsOpenCode,
factoryNo,
warehouseId: warehouseId.value,
packingId: sortingAreaId.value,
})
}
// 配货分拣 手动切换配货区
const handleSortingAreaChange = (
value: string | number,
factoryNo?: number | string,
type: 'scan' | 'manual' = 'manual',
) => {
const no = factoryNo ?? userStore.user?.factory.id
if (!no) return
syncSortingArea(value, no)
emit('set-warehouseId', {
warehouseId: warehouseId.value,
sortingAreaId: sortingAreaId.value,
})
initOrderDetailBox(type)
}
// 手动切换仓库
const handleWarehouseChange = (value: string | number) => { const handleWarehouseChange = (value: string | number) => {
if (!value) return if (!value) return
if (_warehouseId.value !== warehouseId.value) { if (_warehouseId.value !== warehouseId.value) {
...@@ -1309,12 +1512,31 @@ const reconnectWebSocket = async () => { ...@@ -1309,12 +1512,31 @@ const reconnectWebSocket = async () => {
code: props.wsOpenCode, code: props.wsOpenCode,
factoryNo: userStore.user?.factory.id, factoryNo: userStore.user?.factory.id,
warehouseId: warehouseId.value, warehouseId: warehouseId.value,
packingId: sortingAreaId.value,
}) })
} catch (error) { } catch (error) {
console.error('WebSocket 重连失败:', error) console.error('WebSocket 重连失败:', error)
ElMessage.error('WebSocket 重连失败,请稍后重试') ElMessage.error('WebSocket 重连失败,请稍后重试')
} }
} }
// 配货分拣 获取配货区列表
const getSortingAreaList = async () => {
const res = await getSortingRuleListApi({})
if (res.code !== 200) return
sortingAreaList.value = res.data.records
const defaultArea =
sortingAreaList.value.find(
(item) => item.defaultWarehouse === 1 && item.areaCode === 'AREA_0',
) || sortingAreaList.value[0]
sortingAreaId.value = defaultArea.id
warehouseId.value = defaultArea.warehouseId
isAutoPrint.value = defaultArea.autoPrint || false
emit('set-warehouseId', {
warehouseId: warehouseId.value,
sortingAreaId: sortingAreaId.value,
})
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
...@@ -1354,6 +1576,30 @@ const reconnectWebSocket = async () => { ...@@ -1354,6 +1576,30 @@ const reconnectWebSocket = async () => {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
.right-panel {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
overflow: hidden;
}
.right-panel-body {
min-height: 0;
overflow: hidden;
}
.sorting-area-content {
border: 2px solid #666;
padding: 10px;
margin-bottom: 10px;
width: 100%;
height: 80px;
font-size: 35px;
color: red;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
}
.middle-content { .middle-content {
width: 500px; width: 500px;
display: flex; display: flex;
...@@ -1423,19 +1669,21 @@ const reconnectWebSocket = async () => { ...@@ -1423,19 +1669,21 @@ const reconnectWebSocket = async () => {
font-size: 60px; font-size: 60px;
color: red; color: red;
text-align: center; text-align: center;
width: 80px; flex: 1;
font-weight: 600; font-weight: 600;
white-space: nowrap;
} }
.box-top-item-box-index-text { .box-top-item-box-index-text {
margin-right: 15px; margin-right: 15px;
font-size: 30px; font-size: 30px;
white-space: nowrap;
} }
.box-top-item-box-index-number { .box-top-item-box-index-number {
font-size: 60px; font-size: 60px;
color: red; color: red;
display: inline-block; display: inline-block;
text-align: center; text-align: center;
width: 80px; flex: 1;
font-weight: 600; font-weight: 600;
} }
.box-top-item-status { .box-top-item-status {
...@@ -1443,7 +1691,7 @@ const reconnectWebSocket = async () => { ...@@ -1443,7 +1691,7 @@ const reconnectWebSocket = async () => {
} }
.order-image { .order-image {
flex: 1; flex: 1;
overflow: hidden; overflow: auto;
border: 1px solid #ddd; border: 1px solid #ddd;
background: #eee; background: #eee;
} }
......
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