Commit 681244f3 by wusiyi

feat: 备货计划页面1000860

parent 38d2938d
......@@ -10,6 +10,8 @@ import {
AnyObject,
InterProductList,
ExportInWarehouseInfo,
stockingPlanSearchForm,
InterStackingPlanDetail
} from '@/types/api/warehouse'
export interface LogListData {
createTime: string
......@@ -596,3 +598,96 @@ export function deleteWarehouseOutRecordApi(ids: string) {
},
)
}
// 备货计划 树状图
export function getStackingPlanStatusTree() {
return axios.get<never, BaseRespData<InterWarehouseTree[]>>(
'factoryStockingPlanRecord/status_tree',
)
}
// 备货计划 列表
export function getStackingPlanListPage(data: stockingPlanSearchForm, currentPage: number,
pageSize: number,) {
return axios.post<never, BasePaginationData<InterWarehousePage>>(
'factoryStockingPlanRecord/list_page',
{
...data,
currentPage,
pageSize,
},
)
}
// 备货计划 新增
export function addStackingPlanApi(data: InterWarehouseDetail) {
return axios.post<never, BaseRespData<never>>(
'factoryStockingPlanRecord/add',
data,
)
}
// 备货计划 编辑
export function updateStackingPlanApi(data: InterStackingPlanDetail) {
return axios.post<never, BaseRespData<never>>(
'factoryStockingPlanRecord/update',
data,
)
}
// 备货计划 详情
export function getStackingPlanDetailApi(id: number | undefined) {
return axios.get<never, BaseRespData<InterStackingPlanDetail>>(
'factoryStockingPlanRecord/get',
{
params: {
id,
},
},
)
}
// 备货计划 日志
export function getStackingPlanLogApi(stockingPlanRecordId?: number) {
return axios.get<never, BaseRespData<LogListData[]>>(
`factoryStockingPlanRecord/log/${stockingPlanRecordId}`,
)
}
// 备货计划 驳回
export function rejectStackingPlanApi({
list,
rejectReason,
status,
}: {
list: WarehouseParams[]
rejectReason: string
status: string
}) {
return axios.post<never, BaseRespData<never>>(
'factoryStockingPlanRecord/reject',
{
list,
rejectReason,
status,
},
)
}
// 备货计划 删除
export function deleteStackingPlanApi(ids: string) {
return axios.get<never, BaseRespData<never>>(
'factoryStockingPlanRecord/delete',
{
params: { ids },
},
)
}
// 备货计划 审核
export function auditStackingPlanApi(data: WarehouseParams) {
return axios.post<never, BaseRespData<never>>(
'factoryStockingPlanRecord/audit',
{ data },
)
}
\ No newline at end of file
......@@ -118,11 +118,17 @@ export interface ILocation {
locationCode?: string | null
}
export interface stockingPlanSearchForm {
warehouseId?: number | string
warehouseSku?: string
outNo?: string
// 备货计划 查询
export interface stockingPlanSearchForm extends InterWarehouseBase {
timeType?: string
startTime?: string
endTime?: string
startDate?: string
endDate?: string
dateStr?: string
warehouseSku?: string
}
// 备货计划 新增编辑
export interface InterStackingPlanDetail extends InterWarehouseDetail {
boxSum?: number
checkBoxSum?: number
}
......@@ -30,23 +30,20 @@
<splitDiv size="50">
<template #top>
<div class="header-filter-form">
<ElForm :model="searchForm" inline ref="searchFormRef">
<ElFormItem label="仓库">
<ElSelect
v-model="searchForm.warehouseId"
<ElForm ref="searchFormRef" :model="searchForm" inline>
<ElFormItem>
<el-select
v-model="searchForm.dateStr"
clearable
placeholder="请选择仓库"
style="width: 160px"
:teleported="false"
placeholder="时间类型"
style="width: 100px; margin-right: 5px"
>
<ElOption
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="出库时间">
<el-option value="createTime" label="创建时间" />
<el-option value="auditTime" label="审核时间" />
<el-option value="deliveryTime" label="发货时间" />
<el-option value="warehouseTime" label="入库时间" />
</el-select>
<el-date-picker
v-model="tradingTime"
:shortcuts="pickerOptions.shortcuts"
......@@ -63,43 +60,64 @@
value-format="YYYY-MM-DD HH:mm:ss"
/>
</ElFormItem>
<ElFormItem label="出库单号">
<ElFormItem label="备货单号">
<ElInput
v-model.trim="searchForm.outNo"
v-model.trim="searchForm.inNo"
clearable
placeholder="请输入出库单号"
placeholder="请输入备货单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem label="备货仓库">
<ElSelect
v-model="searchForm.warehouseId"
clearable
placeholder="请选择仓库"
style="width: 160px"
>
<ElOption
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem style="margin-right: 10px" label="库存SKU">
<ElInput
v-model.trim="searchForm.warehouseSku"
v-model="searchForm.warehouseSku"
clearable
placeholder="请输入库存SKU"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem style="margin-right: 10px" label="出库单ID">
<ElFormItem style="margin-right: 10px" label="物流单号">
<ElInput
v-model.trim="searchForm.id"
v-model.trim="searchForm.shipmentNumber"
clearable
placeholder="请输入出库单ID"
placeholder="请输入物流单号"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search" ref="searchBtnRef"
>查询</ElButton
>
<ElButton ref="searchBtnRef" type="primary" @click="search">
查询
</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton>
</ElFormItem>
<ElFormItem>
<el-button type="success" @click="handleExport">
导出</el-button
>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_SUBMIT'">
<el-button type="primary" @click="addDialog(1, null)">
新增
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_AUDIT'">
<el-button type="danger" @click="rejectedInRecord">
驳回
......@@ -110,36 +128,26 @@
删除
</el-button>
</ElFormItem>
<ElFormItem>
<el-button type="success" @click="handleExport">
导出
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_AUDIT'">
<el-button type="warning" @click="auditOrder('audit')">
审核
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_SUBMIT'">
<el-button type="success" @click="auditOrder('submitAudit')">
提交审核
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'PENDING_AUDIT'">
<el-button type="danger" @click="auditOrder('invalid')">
作废
</el-button>
</ElFormItem>
<ElFormItem v-if="nodeCode === 'COMPLETED'">
<el-button type="success" @click="auditOrder('archiving')">
归档
</el-button>
</ElFormItem>
<ElFormItem>
<el-button type="primary" @click="printProductTag">
打印库存SKU标签
</el-button>
</ElFormItem>
<ElFormItem>
<el-button
v-if="nodeCode === 'COMPLETED'"
type="success"
@click="auditOrder('archiving')"
>
归档
</el-button>
</ElFormItem>
</ElForm>
</div>
<div
......@@ -162,7 +170,7 @@
width="70"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
type="index"
label="序号"
......@@ -170,30 +178,30 @@
fixed="left"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
label="出库单号"
label="备货单号"
show-overflow-tooltip
prop="outNo"
prop="inNo"
width="130"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
label="单据状态"
width="130"
width="100"
prop="billStatusTxt"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
label="仓库名称"
label="备货仓库"
show-overflow-tooltip
prop="warehouseName"
width="130"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
label="工厂编号"
show-overflow-tooltip
......@@ -201,7 +209,15 @@
width="90"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
label="物流单号"
show-overflow-tooltip
prop="shipmentNumber"
width="200"
header-align="center"
align="center"
/>
<ElTableColumn
label="币种"
show-overflow-tooltip
......@@ -209,7 +225,7 @@
prop="currencyName"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
label="总金额"
show-overflow-tooltip
......@@ -217,7 +233,23 @@
prop="totalPrice"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
label="箱数"
header-align="center"
prop="boxSum"
width="90"
align="center"
show-overflow-tooltip
/>
<ElTableColumn
label="盘点箱数"
header-align="center"
prop="checkBoxSum"
width="90"
align="center"
show-overflow-tooltip
/>
<ElTableColumn
label="SKU数量"
header-align="center"
......@@ -225,42 +257,83 @@
width="90"
align="center"
show-overflow-tooltip
>
</ElTableColumn>
/>
<ElTableColumn
label="总数量"
label="备货总数量"
header-align="center"
prop="total"
width="90"
align="center"
show-overflow-tooltip
>
</ElTableColumn>
/>
<ElTableColumn
label="创建时间"
header-align="center"
prop="makeTime"
width="130"
align="center"
show-overflow-tooltip
/>
<ElTableColumn
label="审核时间"
header-align="center"
prop="auditTime"
width="130"
align="center"
show-overflow-tooltip
/>
<ElTableColumn
label="发货时间"
header-align="center"
prop="shipmentTime"
width="130"
align="center"
show-overflow-tooltip
/>
<ElTableColumn
label="入库时间"
header-align="center"
prop="deliveryTime"
width="130"
align="center"
show-overflow-tooltip
/>
<ElTableColumn
label="驳回原因"
show-overflow-tooltip
prop="rejectReason"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
label="备注"
show-overflow-tooltip
prop="remark"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
v-if="nodeCode === 'PENDING_SUBMIT'"
width="100"
align="center"
header-align="center"
label="操作"
fixed="right"
>
<template #default="{ row }">
<ElButton type="primary" link @click="addDialog(2, row)"
<ElButton
v-if="nodeCode === 'PENDING_SUBMIT'"
type="primary"
link
@click="addDialog(2, row)"
>编辑
</ElButton>
<ElButton
v-if="nodeCode === 'PENDING_AUDIT'"
type="warning"
link
@click="addDialog(3, row)"
>审核
</ElButton>
</template>
</ElTableColumn>
</ElTable>
......@@ -280,7 +353,7 @@
</template>
<template #bottom>
<el-tabs v-model="tabsValue" @tab-click="tabsClick">
<el-tab-pane name="0" label="库商品">
<el-tab-pane name="0" label="库商品">
<div class="table-wrap">
<ElTable size="small" :data="detailList" height="100%" border>
<ElTableColumn
......@@ -309,14 +382,14 @@
show-overflow-tooltip
align="center"
label="库存SKU"
prop="warehouseSku"
width="180"
prop="warehouseSku"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="库存SKU"
label="商品名称"
prop="skuName"
/>
<ElTableColumn
......@@ -328,8 +401,9 @@
<ElTableColumn
show-overflow-tooltip
align="center"
label="出库数量"
prop="outCount"
width="90"
label="备货数量"
prop="stockUpStored"
/>
<ElTableColumn
show-overflow-tooltip
......@@ -411,7 +485,7 @@
</div>
<ElDialog
v-model="importDialogVisible"
title="导入库单"
title="导入库单"
width="500px"
:close-on-click-modal="false"
>
......@@ -420,8 +494,8 @@
<UploadExcel
v-model="importedFileUrl"
:import-type="'localAndXlsx'"
:import-name="'库单'"
:import-url="'/files/outboundOrder.xlsx'"
:import-name="'库单'"
:import-url="'/files/warehousingEntry.xlsx'"
@imported="handleLocalImport"
/>
</div>
......@@ -429,7 +503,7 @@
</ElDialog>
<ElDialog
v-model="newDialogVisible"
:title="formId ? '编辑' : '新增'"
:title="actionMap[currentAction - 1].label + '备货计划'"
width="80%"
:close-on-click-modal="false"
>
......@@ -441,18 +515,18 @@
inline
label-width="90px"
>
<ElFormItem label="出库单号" prop="account">
<ElInput v-model.trim="editForm.outNo" clearable disabled />
<ElFormItem label="备货单号" prop="account">
<ElInput v-model.trim="editForm.inNo" clearable disabled />
</ElFormItem>
<ElFormItem label="工厂:" prop="factoryCode">
<ElFormItem label="工厂编号:" prop="factoryCode">
<span>{{ editForm.factoryCode }}</span>
</ElFormItem>
<ElFormItem label="仓库" prop="warehouseId" required>
<ElFormItem label="备货仓库" prop="warehouseId" required>
<ElSelect
v-model="editForm.warehouseId"
clearable
:disabled="formId"
placeholder="请选择仓库"
placeholder="请选择备货仓库"
style="width: 160px"
@change="handleWarehouseChange(editForm.warehouseId)"
>
......@@ -464,10 +538,21 @@
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="备注" prop="remark" style="width: 45%">
<ElFormItem label="箱数" prop="boxSum">
<ElInput
v-model.trim="editForm.boxSum"
placeholder="请输入箱数"
:disabled="currentAction === 3"
style="width: 160px"
clearable
/>
</ElFormItem>
<ElFormItem label="备注" prop="remark">
<ElInput
v-model.trim="editForm.remark"
:disabled="currentAction === 3"
placeholder="请输入备注"
style="width: 160px"
clearable
/>
</ElFormItem>
......@@ -484,14 +569,14 @@
width="70"
header-align="center"
align="center"
></ElTableColumn>
/>
<ElTableColumn
show-overflow-tooltip
width="60"
align="center"
label="序号"
type="index"
></ElTableColumn>
/>
<ElTableColumn
show-overflow-tooltip
align="center"
......@@ -522,17 +607,12 @@
label="款号"
prop="productNo"
/>
<ElTableColumn
show-overflow-tooltip
align="center"
label="可用库存数量"
prop="usableInventory"
/>
<ElTableColumn align="center" label="出库数量" prop="outCount">
<ElTableColumn align="center" label="备货数量" prop="stockUpStored">
<template #default="{ row }">
<el-input
v-model.number="row.outCount"
placeholder="出库数量"
v-model.number="row.stockUpStored"
:disabled="currentAction === 3"
placeholder="备货数量"
style="width: 120px"
clearable
size="small"
......@@ -541,8 +621,8 @@
</template>
</ElTableColumn>
<ElTableColumn
width="80"
align="center"
width="80"
label="币种"
prop="currencyName"
/>
......@@ -560,12 +640,12 @@
/>
<ElTableColumn align="center" label="库位" prop="locationCode">
<template #default="{ row }">
<span v-if="row.locationCode">{{ row.locationCode }}</span>
<!-- <span v-if="formId&&row.locationCode">{{ row.locationCode }}</span> -->
<ElSelect
v-else
v-model="row.locationId"
clearable
placeholder="请输入库位"
:disabled="currentAction === 3"
style="width: 120px"
filterable
@change="handleLocationChange(row.locationId, row)"
......@@ -587,14 +667,19 @@
prop="remark"
>
<template #default="{ row }">
<ElInput v-model.trim="row.remark" clearable size="small" />
<ElInput
v-model.trim="row.remark"
clearable
size="small"
:disabled="currentAction === 3"
/>
</template>
</ElTableColumn>
</ElTable>
</div>
<template #footer>
<div class="product-dialog-footer">
<div>
<div v-if="currentAction !== 3">
<el-input
v-model.trim="selectSku"
placeholder="库存SKU"
......@@ -604,7 +689,7 @@
></el-input>
<el-popover placement="top-start" width="1000" trigger="click">
<div v-if="skuData.length > 0" style="height: 50vh">
<ElTable size="small" :data="skuData" height="100%" border>
<ElTable size="small" :data="filterSkuData" height="100%" border>
<ElTableColumn
show-overflow-tooltip
width="60"
......@@ -636,7 +721,7 @@
align="center"
width="200"
label="库存SKU"
prop="warehouseSku"
prop="sku"
/>
<ElTableColumn
show-overflow-tooltip
......@@ -656,7 +741,7 @@
align="center"
label="成本价"
width="80"
prop="price"
prop="factoryPrice"
/>
<ElTableColumn
show-overflow-tooltip
......@@ -671,9 +756,9 @@
label="操作"
>
<template #default="{ row }">
<el-icon :size="32" color="#67C23A" class="cursor-pointer"
><CirclePlusFilled @click="skudblclick(row)"
/></el-icon>
<el-icon :size="32" color="#67C23A" class="cursor-pointer">
<CirclePlusFilled @click="skudblclick(row)" />
</el-icon>
</template>
</ElTableColumn>
</ElTable>
......@@ -714,15 +799,23 @@
导入
</el-button>
</div>
<div>
<div :style="{ margin: currentAction === 3 ? '0 auto' : '' }">
<el-button size="small" @click="newDialogVisible = false">
取消
</el-button>
<el-button
v-if="currentAction === 3"
type="danger"
size="small"
style="margin-left: 10px"
@click="newDialogVisible = false"
@click="rejectInAudit"
>
取消
驳回
</el-button>
<el-button type="primary" size="small" @click="addOtherCurrency()">
<el-button
type="primary"
size="small"
@click="currentAction === 2 ? addOtherCurrency : handleOudit"
>
保存
</el-button>
</div>
......@@ -744,7 +837,7 @@
</el-radio-group>
</el-form-item>
<el-form-item label="">
<el-checkbox v-model="exportForm.delivery"> 包含详情 </el-checkbox>
<el-checkbox v-model="exportForm.delivery"> 包含详情</el-checkbox>
</el-form-item>
</el-form>
<template #footer>
......@@ -836,42 +929,43 @@ import usePageList from '@/utils/hooks/usePageList'
import { checkUpdateParams, AnyObject } from '@/utils/hooks/commonUtil'
import { useValue } from '@/utils/hooks/useValue'
import {
getOutRecordStatusTree,
warehouseOutRecordListPage,
getWarehouseOutRecordDetailApi,
getItemListByIdApi,
getBySkuAndWarehouseIdApi,
getStackingPlanStatusTree,
getStackingPlanListPage,
getStackingPlanDetailApi,
getBySkuApi,
warehouseInfoGetAll,
getByWareHouseIdAndCodeApi,
addOutRecordApi,
updateOutRecordApi,
deleteWarehouseOutRecordApi,
addStackingPlanApi,
updateStackingPlanApi,
deleteStackingPlanApi,
auditOrderApi,
getOutRecordLogApi,
rejectOutRecordApi,
getStackingPlanLogApi,
rejectStackingPlanApi,
LogListData,
warehouseInfo,
warehouseOutRecordExport,
InRecordBatchCheckPrintApi,
factoryWarehouseInventoryPrint,
OutRecordBatchCheckPrintApi,
warehouseInRecordExport,
auditStackingPlanApi,
} from '@/api/warehouse'
import { filePath } from '@/api/axios'
import { filePath } from '@/api/axios.ts'
import BigNumber from 'bignumber.js'
import { ref, onMounted, watch, nextTick } from 'vue'
import 'element-plus/dist/index.css'
import {
warehouseSearchForm,
stockingPlanSearchForm,
InterWarehousePage,
InterWarehouseTree,
InterProductList,
InterskuList,
ILocation,
InterWarehouseDetail,
InterStackingPlanDetail,
} from '@/types/api/warehouse'
import ImageView from '@/components/ImageView.vue'
import { useEnterKeyTrigger } from '@/utils/hooks/useEnterKeyTrigger.ts'
import UploadExcel from '@/components/UploadExcel.vue'
// import { debounce } from 'lodash-es'
import { useEnterKeyTrigger } from '@/utils/hooks/useEnterKeyTrigger.ts'
const warehouseList = ref<warehouseInfo[]>([])
const pickerOptions = {
shortcuts: [
......@@ -983,6 +1077,7 @@ const pickerOptions = {
},
],
}
function getStartTime() {
const date = new Date()
const year = date.getFullYear()
......@@ -992,7 +1087,7 @@ function getStartTime() {
}
const selectSku = ref('')
const treeData = ref<InterWarehouseTree[]>()
const [searchForm, resetSearchForm] = useValue<warehouseSearchForm>({})
const [searchForm, resetSearchForm] = useValue<stockingPlanSearchForm>({})
const tradingTime = ref<string[]>([])
const selections = ref<InterWarehousePage[]>([])
......@@ -1024,12 +1119,12 @@ const {
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) =>
warehouseOutRecordListPage(
getStackingPlanListPage(
{
...searchForm.value,
billStatus: nodeCode.value == 'all' ? 'all' : nodeCode.value,
startTime: tradingTime.value && tradingTime.value[0],
endTime: tradingTime.value && tradingTime.value[1],
startDate: tradingTime.value && tradingTime.value[0],
endDate: tradingTime.value && tradingTime.value[1],
},
page,
pageSize,
......@@ -1042,15 +1137,15 @@ const setCostPrice = (item: InterProductList) => {
return
}
if (item) {
const outCount = item.outCount ?? 0
const buyStored = item.buyStored ?? 0
const costPrice = item.costPrice ?? 0
const amount = new BigNumber(outCount).multipliedBy(costPrice).toFixed(2)
const amount = new BigNumber(buyStored).multipliedBy(costPrice).toFixed(2)
item.totalPrice = Number(amount)
}
}
const getTreeNum = async () => {
try {
const res = await getOutRecordStatusTree()
const res = await getStackingPlanStatusTree()
res.data = [{ code: 'all', name: '全部', children: res.data }]
treeData.value = res.data
await nextTick(() => {
......@@ -1068,7 +1163,7 @@ const printProductTag = async () => {
}
const str = selections.value.map((el: InterWarehousePage) => el.id).join(',')
try {
const res = await OutRecordBatchCheckPrintApi(str)
const res = await InRecordBatchCheckPrintApi(str)
if (res.code === 200) {
printData.value = res.data
showPrintDialog.value = true
......@@ -1079,6 +1174,7 @@ const printProductTag = async () => {
console.error(e)
}
}
async function handlePrintProductTag() {
const flag = printData.value.every(
(el: InterWarehousePage) => el.number && el.number != '0',
......@@ -1108,13 +1204,14 @@ async function handlePrintProductTag() {
showPrintDialog.value = false
window.open(filePath + res.message, '_blank')
}
const batchAddCommodity = async (sku: string): Promise<InterskuList[]> => {
if (!editForm.value.warehouseId) {
ElMessage.error('请选择仓库')
return []
}
try {
const res = await getBySkuAndWarehouseIdApi(editForm.value.warehouseId, sku)
const res = await getBySkuApi(editForm.value.warehouseId, sku)
const arr: InterskuList[] = res.data || []
const ids: Record<string, boolean> = {}
// 过滤掉商品列表已经加了的
......@@ -1125,9 +1222,7 @@ const batchAddCommodity = async (sku: string): Promise<InterskuList[]> => {
}
// 使用 filter 方法过滤掉已经存在的 SKU
const filteredArr = arr.filter((currentItem: InterskuList) => {
return (
currentItem.warehouseSku === undefined || !ids[currentItem.warehouseSku]
)
return currentItem.sku === undefined || !ids[currentItem.sku]
})
return filteredArr
} catch (e) {
......@@ -1135,30 +1230,32 @@ const batchAddCommodity = async (sku: string): Promise<InterskuList[]> => {
return []
}
}
interface InterImportData {
warehouseSku: string
remark?: string | null
outCount?: string | number | null | object // 扩大 outCount 类型,以兼容原始数据
[propName: string]: string | number | boolean | undefined | unknown
[key: string]: unknown
}
// 前端导入Excel
const excelFieldMap: Record<string, keyof InterImportData> = {
const excelFieldMap: Record<string, keyof InterProductList> = {
// SKU图片: 'skuImage',
库存SKU: 'warehouseSku',
// SKU名称: 'skuName',
出库数量: 'outCount',
// 可用库存数量: 'usableInventory',
备货数量: 'stockUpStored',
// '成本价(¥)': 'costPrice',
// '总成本(¥)': 'totalPrice',
// 库位: 'locationCode',
库位编码: 'locationCode',
备注: 'remark',
}
const handleLocalImport = async ({
path,
data,
}: {
path: string
data: Record<string, unknown>[]
data: InterImportData[]
}) => {
// 1. 将原始导入数据映射到 InterImportData[]
const importedData: InterImportData[] = data
......@@ -1177,15 +1274,15 @@ const handleLocalImport = async ({
: value === null || value === undefined
? null
: String(value)
} else if (field === 'outCount') {
// 处理 outCount: 确保它是一个数字、数字字符串,否则设置为 null
if (typeof value === 'number') {
obj[field] = String(value) // 将数字转换为字符串
} else if (typeof value === 'string' && !isNaN(Number(value))) {
obj[field] = value // 保持有效的数字字符串
} else if (field === 'buyStored') {
// 确保 value 是一个有效的数字或数字字符串,否则设置为 null
if (
typeof value === 'number' ||
(typeof value === 'string' && !isNaN(Number(value)))
) {
obj[field] = String(value) // 转换为字符串
} else {
// 如果不是数字或有效的数字字符串,则设置为 null
obj[field] = null
obj[field] = null // 无效值设置为 null
}
} else {
obj[field] = value
......@@ -1194,77 +1291,51 @@ const handleLocalImport = async ({
return obj
})
.filter((item) => item.warehouseSku)
// console.log('@', importedData, data)
if (importedData.length === 0) {
ElMessage.warning('导入数据中没有有效的库存SKU')
ElMessage.warning('导入数据中没有有效的商品SKU')
importDialogVisible.value = false
return
}
// 2. 提取导入的 SKU 列表
const importedSkus = importedData.map((item) => item.warehouseSku).join(',')
// 3. 调用 batchAddCommodity 获取商品的完整信息并过滤掉已有的 SKU
const filteredSkusList = await batchAddCommodity(importedSkus)
const filteredSkusList = await batchAddCommodity(importedSkus) // 使用 await 等待结果
if (filteredSkusList.length === 0) {
ElMessage.warning('导入的库存SKU已存在或无效')
ElMessage.warning('导入的商品SKU已存在或无效')
importedFileUrl.value = path
importDialogVisible.value = false
return
}
// 4. 将备注信息合并到获取到的商品列表中
const mergedProductList = filteredSkusList.map((skuItem) => {
// 在导入数据中找到匹配的备注信息
const importedItem = importedData.find(
(item) => item.warehouseSku === skuItem.warehouseSku,
(item) => item.warehouseSku === skuItem.sku,
)
let outCountValueForBigNumber: string | number = '0' // 初始化为安全默认值
console.log(importedItem)
if (
importedItem?.outCount !== null &&
importedItem?.outCount !== undefined
) {
if (
typeof importedItem.outCount === 'string' &&
!isNaN(Number(importedItem.outCount))
) {
outCountValueForBigNumber = importedItem.outCount
} else if (typeof importedItem.outCount === 'number') {
outCountValueForBigNumber = importedItem.outCount
} else {
// 如果是对象或其他意外类型,则默认为 '0'
outCountValueForBigNumber = '0'
}
}
const calculatedOutCount = new BigNumber(
outCountValueForBigNumber,
).toNumber()
const target = locationList.value.find((item: InterProductList) => {
return item.locationCode == importedItem?.locationCode
})
return {
skuImage: skuItem.image,
warehouseSku: skuItem.warehouseSku,
warehouseSku: skuItem.sku,
skuName: skuItem.skuName,
productNo: skuItem.productNumber,
locationCode: skuItem.locationCode ?? '',
locationId: skuItem.locationId ?? null,
costPrice: skuItem.price,
outCount: calculatedOutCount,
totalPrice: new BigNumber(calculatedOutCount)
.multipliedBy(skuItem.price ?? 0)
productNo: skuItem.productNo,
locationCode: target?.locationCode ?? '',
locationId: target?.locationId,
costPrice: skuItem.factoryPrice,
buyStored: importedItem?.buyStored ?? null,
totalPrice: new BigNumber(
(importedItem?.buyStored ?? 0) as number | string,
)
.multipliedBy(skuItem.factoryPrice ?? 0)
.toNumber(),
usableInventory: skuItem.usableInventory,
inventoryId: skuItem.id,
remark: importedItem?.remark ?? skuItem.remark ?? null,
} as InterProductList
remark: importedItem?.remark ?? null,
} as InterProductList // 明确类型
})
// 5. 更新 otherPurchaseData
otherPurchaseData.value = [...otherPurchaseData.value, ...mergedProductList]
importedFileUrl.value = path
importDialogVisible.value = false
}
......@@ -1280,20 +1351,20 @@ const submitExportForm = async () => {
if (exportForm.value.resource === '') {
return ElMessage.error('请选择导出类型')
}
let purchaseIds: number[] = []
let purchaseIds = ''
let exportTotal: number | undefined = undefined
const params: AnyObject = {}
const resourceType = Number(exportForm.value.resource)
if (resourceType === 0) {
purchaseIds = (tableData.value as InterWarehousePage[]).map(
(el: InterWarehousePage) => Number(el.id),
)
purchaseIds = tableData.value
.map((el: InterWarehousePage) => el.id)
.join(',')
} else if (resourceType === 1) {
purchaseIds = selections.value.map((el: InterWarehousePage) =>
Number(el.id),
)
purchaseIds = selections.value
.map((el: InterWarehousePage) => el.id)
.join(',')
} else if (resourceType === 2) {
purchaseIds = []
purchaseIds = ''
exportTotal = total.value
params.billStatus = nodeCode.value == 'all' ? 'all' : nodeCode.value
}
......@@ -1302,7 +1373,7 @@ const submitExportForm = async () => {
params.total = exportTotal
}
try {
const res = await warehouseOutRecordExport({
const res = await warehouseInRecordExport({
showDetail: exportForm.value.delivery,
...params,
...searchForm.value,
......@@ -1335,29 +1406,8 @@ const skuData = ref<InterskuList[]>([])
const selectbySku = async () => {
if (!editForm.value.warehouseId) return ElMessage.error('请选择仓库')
try {
const res = await getBySkuAndWarehouseIdApi(
editForm.value.warehouseId,
selectSku.value,
)
const arr: InterskuList[] = res.data || []
const ids: Record<string, boolean> = {}
// 过滤掉商品列表已经加了的
for (const item of otherPurchaseData.value) {
if (item.warehouseSku !== undefined) {
ids[item.warehouseSku] = true
}
}
for (let i = 0; i < arr.length; i++) {
const currentItem: InterskuList = arr[i]
if (
currentItem.warehouseSku !== undefined &&
ids[currentItem.warehouseSku]
) {
arr.splice(i, 1)
i--
}
}
skuData.value = arr || []
const res = await getBySkuApi(editForm.value.warehouseId, selectSku.value)
skuData.value = res.data || []
} catch (e) {
console.error(e)
}
......@@ -1366,16 +1416,14 @@ const skudblclick = (val: InterskuList) => {
// 使用可选链和空值合并运算符处理可能的null值
const {
locationCode = '',
price = null,
factoryPrice = null,
productNo = '',
warehouseSku = '',
sku = '',
skuName = '',
image = '',
locationId = null,
usableInventory = null,
id = null,
currencyName = '',
currencyCode = '',
currencyCode = null,
} = val || {}
// 币种一致性校验
......@@ -1387,31 +1435,29 @@ const skudblclick = (val: InterskuList) => {
return
}
}
otherPurchaseData.value = [
...otherPurchaseData.value,
{
skuImage: image,
warehouseSku,
warehouseSku: sku,
skuName,
productNo,
locationCode: locationCode ?? '', // 确保空值处理
locationId: locationId ?? null, // 确保空值处理
costPrice: price,
outCount: null, //出库数量
costPrice: factoryPrice,
buyStored: null,
totalPrice: null,
usableInventory, //可用库存数量
inventoryId: id,
currencyName,
currencyCode,
},
]
// 使用filter代替forEach+splice,时间复杂度从O(n^2)降到O(n)
const skuSet = new Set(
otherPurchaseData.value.map((item: InterProductList) => item.warehouseSku),
)
skuData.value = skuData.value.filter(
(item: InterskuList) => !skuSet.has(item.warehouseSku),
(item: InterskuList) => !skuSet.has(item.sku),
)
}
const tabsClick = async () => {
......@@ -1427,8 +1473,8 @@ const tabsClick = async () => {
getLogList()
}
}
const [editForm, resetEditForm] = useValue<InterWarehouseDetail>({
outNo: '',
const [editForm, resetEditForm] = useValue<InterStackingPlanDetail>({
inNo: '',
warehouseId: '',
warehouseName: '',
remark: '',
......@@ -1440,9 +1486,16 @@ const newDialogVisible = ref(false)
const editFormRef = ref()
const editForm2 = ref({})
const formId = ref<number | undefined>(undefined)
const actionMap = [
{ label: '新增', value: 1 },
{ label: '编辑', value: 2 },
{ label: '审核', value: 3 },
]
const currentAction = ref<number>(1)
const otherPurchaseData = ref<InterProductList[]>([])
const addDialog = async (i: number, v: InterWarehousePage | null) => {
if (i === 2) {
currentAction.value = i
if (i === 2 || i === 3) {
if (v) formId.value = v.id
if (v) getProduct(v.id)
if (!formId.value) return ElMessage('请勾选至少一条记录')
......@@ -1477,22 +1530,9 @@ const addDialog = async (i: number, v: InterWarehousePage | null) => {
}
const getProduct = async (id: number | undefined) => {
try {
const res = await getWarehouseOutRecordDetailApi(id)
const productList = res.data?.productList
const newProductList = (Array.isArray(productList) ? productList : []).map(
(item: InterProductList) => {
const { inventory, ...rest } = item
return {
...rest,
usableInventory: inventory?.usableInventory ?? null,
}
},
)
if (res.data) {
res.data.productList = newProductList
}
const res = await getStackingPlanDetailApi(id)
editForm.value = JSON.parse(JSON.stringify(res.data))
otherPurchaseData.value = newProductList || []
otherPurchaseData.value = res.data?.productList || []
} catch (e) {
console.error(e)
}
......@@ -1511,27 +1551,16 @@ const auditOrder = (key: string) => {
let url = ''
let text = ''
switch (key) {
case 'invalid':
url = 'factory/warehouseOutRecord/invalid'
text = '作废'
break
case 'archiving':
url = 'factory/warehouseOutRecord/archive'
url = 'factory/warehouseInRecord/archive'
text = '归档'
break
case 'submitAudit':
url = 'factory/warehouseOutRecord/submitAudit'
url = 'factoryStockingPlanRecord/submit_audit'
text = '提交审核'
break
case 'audit':
url = 'factory/warehouseOutRecord/audit'
text = '审核'
break
}
const confimText =
key === 'audit'
? '确定进行审核?点"确定"将会直接更改库存数量,请在审核前确认数量是否正确。'
: `确定对选中的信息进行${text}?`
const confimText = `确定对选中的信息进行${text}?`
ElMessageBox.confirm(confimText, '重要提示', {
confirmButtonText: '确定',
type: 'warning',
......@@ -1548,6 +1577,43 @@ const auditOrder = (key: string) => {
await getTreeNum()
})
}
const handleOudit = async () => {
await auditStackingPlanApi({
id: currentRow.value?.id,
dataVersion: currentRow.value?.dataVersion,
})
ElMessage.success('操作成功')
search()
await getTreeNum()
}
const rejectInAudit = () => {
ElMessageBox.prompt('请输入驳回原因', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
inputPattern: /.+/,
customClass: 'reject',
inputErrorMessage: '请输入驳回原因',
inputPlaceholder: '驳回原因',
}).then(async ({ value }: { value: string }) => {
const data = [currentRow.value as InterProductList]
try {
await rejectStackingPlanApi({
list: data,
rejectReason: value,
status: nodeCode.value,
})
ElMessage.success('操作成功')
newDialogVisible.value = false
search()
await getTreeNum()
} catch (e) {
console.error(e)
}
})
}
const rejectedInRecord = () => {
if (selections.value.length === 0) {
return ElMessage.warning('请选择要操作的数据')
......@@ -1568,7 +1634,11 @@ const rejectedInRecord = () => {
}),
)
try {
await rejectOutRecordApi({ list: data, rejectReason: value })
await rejectStackingPlanApi({
list: data,
rejectReason: value,
status: nodeCode.value,
})
ElMessage.success('操作成功')
search()
await getTreeNum()
......@@ -1591,7 +1661,6 @@ watch(
},
{ immediate: true },
)
watch(
() => editForm.value.warehouseId,
(newVal: number | string | undefined) => {
......@@ -1611,57 +1680,42 @@ const addOtherCurrency = async () => {
ElMessage.error('请至少选择一条数据')
return
}
for (let i = 0; i < arr.length; i++) {
if (!arr[i].outCount) {
ElMessage.error('请输入出库数量')
return
}
const usableInventory = arr[i].usableInventory || 0
if ((arr[i].outCount as number) > usableInventory) {
ElMessage.error('出库数量不能大于可用库存数量')
if (!arr[i].stockUpStored) {
ElMessage.error('请输入备货数量')
return
}
if (!arr[i].locationId) {
ElMessage.error('请选择库位')
return
}
const found = locationList.value.find(
(item: InterProductList) => item.locationId === arr[i].locationId,
)
if (!arr[i].locationCode) {
arr[i].locationCode = found ? found?.locationCode : ''
}
}
// 看新增后要不要打印标签
// try {
// if (!editId.value) {
// await addUserApi({
// ...editForm.value,
// supperMark: Number(editForm.value.supperMark),
// status: Number(editForm.value.status),
// })
// } else {
// await updateUserApi({
// ...editForm.value,
// supperMark: Number(editForm.value.supperMark),
// status: Number(editForm.value.status),
// })
// }
// ElMessage({
// message: '保存成功',
// type: 'success',
// offset: window.innerHeight / 2,
// })
// newDialogVisible.value = false
// search()
// } catch (e) {
// return
// }
if (!formId.value) {
addSection()
} else {
upSection()
}
}
const filterSkuData = computed(() => {
const skuList = otherPurchaseData.value.map((el) => el.warehouseSku)
// console.log(skuList, skuData.value)
return skuData.value.filter((el) => !skuList.includes(el.sku))
})
const addSection = async () => {
const params = { ...editForm.value }
params.productList = otherPurchaseData.value
try {
await addOutRecordApi(params)
await addStackingPlanApi({
...params,
productList: otherPurchaseData.value,
})
ElMessage.success('保存成功')
newDialogVisible.value = false
search()
......@@ -1669,45 +1723,21 @@ const addSection = async () => {
} catch (e) {
console.error(e)
}
// post(url, params).then((res: any) => {
// if (res.code === 200) {
// otherDialogVisible.value = false;
// ElConfirm('保存成功,是否打印标签?', '提示', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
// type: 'warning',
// })
// .then(() => {
// if (res.message) {
// getPrintData(res.message, true);
// } else {
// ElMessage.warning('入口单号为空,无法打印');
// }
// })
// .catch((e: any) => {
// console.error(e);
// });
// getList();
// getStatusAmount();
// } else {
// ElAlert(res.message, '错误提示', {
// dangerouslyUseHTMLString: true,
// });
// }
// });
}
const upSection = async () => {
const params = { ...editForm.value }
// params.productList = otherPurchaseData.value
const result = checkUpdateParams(
{ ...params, productList: otherPurchaseData.value },
editForm.value as unknown as AnyObject,
'id',
{
productList: 'id',
productList: 'warehouseSku',
},
)
try {
await updateOutRecordApi(result)
await updateStackingPlanApi(result as InterStackingPlanDetail)
newDialogVisible.value = false
ElMessage.success('修改成功')
search()
......@@ -1717,9 +1747,10 @@ const upSection = async () => {
}
}
const addPurchaseVisible = ref(false)
const purchaseTextarea = ref(null)
const purchaseTextarea = ref('')
const addPurchase = async () => {
addPurchaseVisible.value = true
purchaseTextarea.value = ''
}
const submitPurchase = async () => {
if (!purchaseTextarea.value) {
......@@ -1730,16 +1761,15 @@ const submitPurchase = async () => {
const mergedProductList = filteredSkusList.map((skuItem) => {
return {
skuImage: skuItem.image,
warehouseSku: skuItem.warehouseSku,
warehouseSku: skuItem.sku,
skuName: skuItem.skuName,
productNo: skuItem.productNumber,
productNo: skuItem.productNo,
locationCode: skuItem.locationCode ?? '',
locationId: skuItem.locationId ?? null,
costPrice: skuItem.price,
outCount: null,
costPrice: skuItem.factoryPrice,
stockUpStored: null,
totalPrice: null,
usableInventory: skuItem.usableInventory,
inventoryId: skuItem.id,
remark: null,
} as InterProductList
})
......@@ -1770,7 +1800,7 @@ const handleBatchDelete = async () => {
type: 'warning',
})
const str = selections.value.map((el: InterWarehousePage) => el.id).join(',')
await deleteWarehouseOutRecordApi(str)
await deleteStackingPlanApi(str)
ElMessage.success('删除成功')
search()
await getTreeNum()
......@@ -1782,15 +1812,15 @@ const nodeClick = (data: InterWarehouseTree) => {
}
const searchDetail = async () => {
try {
const res = await getItemListByIdApi(currentRow.value?.id)
detailList.value = res.data || []
const res = await getStackingPlanDetailApi(currentRow.value?.id)
detailList.value = res.data?.productList || []
} catch (e) {
console.error(e)
}
}
const getLogList = async () => {
try {
const res = await getOutRecordLogApi(currentRow.value?.id)
const res = await getStackingPlanLogApi(currentRow.value?.id)
logList.value = res.data
} catch (e) {
console.error(e)
......@@ -1800,6 +1830,10 @@ const locationList = ref<ILocation[]>([])
const locationLoading = ref(false)
const fetchLocationList = async (query: string) => {
// if (!query) {
// locationList.value = []
// return
// }
if (!editForm.value.warehouseId) return
locationLoading.value = true
try {
......@@ -1814,6 +1848,27 @@ const fetchLocationList = async (query: string) => {
locationCode: item.locationCode,
}
})
if (otherPurchaseData.value?.length > 0) {
//const importedSkus = otherPurchaseData.value.map((item) => item.warehouseSku).join(',')
// // 3. 调用 batchAddCommodity 获取商品的完整信息并过滤掉已有的 SKU
// const filteredSkusList = await batchAddCommodity(importedSkus)
// console.log('filteredSkusList', otherPurchaseData.value)
// 新增时切换仓库将重新匹配表格库位,确保该商品的库位和仓库一一对应
otherPurchaseData.value = otherPurchaseData.value.map(
(item: InterProductList) => {
const foundItem = locationList.value.find(
(locationItem: ILocation) =>
locationItem.locationCode === item.locationCode,
)
// 创建新对象而不是修改原对象
return {
...item,
locationCode: foundItem ? foundItem.locationCode : '',
locationId: foundItem ? foundItem.locationId : null,
}
},
)
}
} catch (e) {
locationList.value = []
} finally {
......@@ -1863,20 +1918,24 @@ onMounted(() => {
width: 500px;
text-align: center;
}
.cursor-pointer {
cursor: pointer;
}
.header-filter-form {
:deep(.el-form-item) {
margin-right: 14px;
margin-bottom: 10px;
}
}
.product-dialog-footer {
display: flex;
justify-content: space-between;
margin: 8px 0;
}
$border: solid 1px #ddd;
.send-order-list {
......@@ -1924,10 +1983,12 @@ $border: solid 1px #ddd;
.left {
width: 160px;
:deep(.el-tree-node__content) {
height: 30px;
line-height: 30px;
}
:deep(.el-tree-node__label) {
font-size: 13px;
cursor: pointer;
......@@ -2019,6 +2080,7 @@ $border: solid 1px #ddd;
height: 5px;
background: #eff3f6;
}
.btn-list {
margin-bottom: 10px;
}
......@@ -2050,6 +2112,7 @@ $border: solid 1px #ddd;
}
}
}
.delivery-note-page {
:deep(#top) {
height: 100%;
......
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