|
|
|
|
@ -10,6 +10,20 @@
|
|
|
|
|
>
|
|
|
|
|
<el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px">
|
|
|
|
|
<el-table-column label="序号" type="index" align="center" width="60" />
|
|
|
|
|
<el-table-column :label="productColumnLabel" min-width="180">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
|
|
|
|
|
<el-input
|
|
|
|
|
:model-value="getProductDisplayName(row)"
|
|
|
|
|
readonly
|
|
|
|
|
:clearable="!disabled"
|
|
|
|
|
:placeholder="productPlaceholder"
|
|
|
|
|
@click="handleProductInputClick(row)"
|
|
|
|
|
@clear="handleProductClear(row)"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="调出仓库" min-width="125">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item
|
|
|
|
|
@ -21,57 +35,36 @@
|
|
|
|
|
v-model="row.fromWarehouseId"
|
|
|
|
|
clearable
|
|
|
|
|
filterable
|
|
|
|
|
:disabled="!row.productId"
|
|
|
|
|
placeholder="请选择调出仓库"
|
|
|
|
|
@change="onChangeWarehouse($event, row)"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in warehouseList"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
:label="item.name"
|
|
|
|
|
:value="item.id"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="调入仓库" min-width="125">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item
|
|
|
|
|
:prop="`${$index}.toWarehouseId`"
|
|
|
|
|
:rules="formRules.toWarehouseId"
|
|
|
|
|
class="mb-0px!"
|
|
|
|
|
>
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="row.toWarehouseId"
|
|
|
|
|
clearable
|
|
|
|
|
filterable
|
|
|
|
|
placeholder="请选择调入仓库"
|
|
|
|
|
@change="onChangeFromWarehouse($event, row)"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in warehouseList"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
:label="item.name"
|
|
|
|
|
:value="item.id"
|
|
|
|
|
v-for="item in getFromWarehouseOptions(row)"
|
|
|
|
|
:key="getStockWarehouseId(item)"
|
|
|
|
|
:label="getStockWarehouseName(item)"
|
|
|
|
|
:value="getStockWarehouseId(item)"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="产品名称" min-width="180">
|
|
|
|
|
<el-table-column label="调出库区" min-width="125">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
|
|
|
|
|
<el-form-item :prop="`${$index}.fromAreaId`" :rules="formRules.fromAreaId" class="mb-0px!">
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="row.productId"
|
|
|
|
|
v-model="row.fromAreaId"
|
|
|
|
|
clearable
|
|
|
|
|
filterable
|
|
|
|
|
@change="onChangeProduct($event, row)"
|
|
|
|
|
placeholder="请选择产品"
|
|
|
|
|
:disabled="!row.fromWarehouseId"
|
|
|
|
|
placeholder="请选择调出库区"
|
|
|
|
|
@change="handleFromAreaChange(row)"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in productList"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
:label="item.name"
|
|
|
|
|
:value="item.id"
|
|
|
|
|
v-for="item in getFromAreaOptions(row)"
|
|
|
|
|
:key="getStockAreaId(item)"
|
|
|
|
|
:label="getAreaLabel(item)"
|
|
|
|
|
:value="getStockAreaId(item)"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
@ -90,7 +83,7 @@
|
|
|
|
|
<el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="单位" min-width="80">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<el-form-item class="mb-0px!">
|
|
|
|
|
@ -98,6 +91,47 @@
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="调入仓库" min-width="125">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item
|
|
|
|
|
:prop="`${$index}.toWarehouseId`"
|
|
|
|
|
:rules="formRules.toWarehouseId"
|
|
|
|
|
class="mb-0px!"
|
|
|
|
|
>
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="row.toWarehouseId"
|
|
|
|
|
clearable
|
|
|
|
|
filterable
|
|
|
|
|
:disabled="!row.productId"
|
|
|
|
|
placeholder="请选择调入仓库"
|
|
|
|
|
@change="onChangeToWarehouse(row)"
|
|
|
|
|
>
|
|
|
|
|
<el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="调入库区" min-width="125">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item :prop="`${$index}.toAreaId`" :rules="formRules.toAreaId" class="mb-0px!">
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="row.toAreaId"
|
|
|
|
|
clearable
|
|
|
|
|
filterable
|
|
|
|
|
:disabled="!row.toWarehouseId"
|
|
|
|
|
placeholder="请选择调入库区"
|
|
|
|
|
@change="handleToAreaChange(row)"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in getToAreaOptions(row)"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
:label="getAreaLabel(item)"
|
|
|
|
|
:value="item.id"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="数量" prop="count" fixed="right" min-width="140">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!">
|
|
|
|
|
@ -111,26 +145,6 @@
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="产品单价" fixed="right" min-width="120">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item :prop="`${$index}.productPrice`" class="mb-0px!">
|
|
|
|
|
<el-input-number
|
|
|
|
|
v-model="row.productPrice"
|
|
|
|
|
controls-position="right"
|
|
|
|
|
:min="0.00"
|
|
|
|
|
:precision="2"
|
|
|
|
|
class="!w-100%"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="合计金额" prop="totalPrice" fixed="right" min-width="100">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!">
|
|
|
|
|
<el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="备注" min-width="150">
|
|
|
|
|
<template #default="{ row, $index }">
|
|
|
|
|
<el-form-item :prop="`${$index}.remark`" class="mb-0px!">
|
|
|
|
|
@ -138,74 +152,160 @@
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column align="center" fixed="right" label="操作" width="60">
|
|
|
|
|
<el-table-column v-if="!disabled" align="center" fixed="right" label="操作" width="60">
|
|
|
|
|
<template #default="{ $index }">
|
|
|
|
|
<el-button @click="handleDelete($index)" link>—</el-button>
|
|
|
|
|
<el-button type="danger" @click="handleDelete($index)" link>
|
|
|
|
|
<Icon icon="ep:delete" />
|
|
|
|
|
</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
</el-form>
|
|
|
|
|
<el-row justify="center" class="mt-3" v-if="!disabled">
|
|
|
|
|
<el-button @click="handleAdd" round>+ 添加调度产品</el-button>
|
|
|
|
|
<el-button @click="handleAdd" round>+ 添加调拨产品</el-button>
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
<Dialog :title="productSelectTitle" v-model="productDialogVisible" width="900px" class="stock-move-product-dialog">
|
|
|
|
|
<el-form :model="productQueryParams" :inline="true" class="-mb-15px">
|
|
|
|
|
<el-form-item :label="t('ErpStock.Item.code')">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="productQueryParams.barCode"
|
|
|
|
|
clearable
|
|
|
|
|
:placeholder="t('ErpStock.Item.placeholderCode')"
|
|
|
|
|
@keyup.enter="handleProductDialogQuery"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item :label="t('ErpStock.Item.name')">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="productQueryParams.name"
|
|
|
|
|
clearable
|
|
|
|
|
:placeholder="t('ErpStock.Item.placeholderName')"
|
|
|
|
|
@keyup.enter="handleProductDialogQuery"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-button type="primary" @click="handleProductDialogQuery">
|
|
|
|
|
<Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}
|
|
|
|
|
</el-button>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form>
|
|
|
|
|
<el-table
|
|
|
|
|
v-loading="productDialogLoading"
|
|
|
|
|
:data="productDialogList"
|
|
|
|
|
row-key="id"
|
|
|
|
|
:stripe="true"
|
|
|
|
|
:show-overflow-tooltip="true"
|
|
|
|
|
@row-click="handleProductDialogRowClick"
|
|
|
|
|
>
|
|
|
|
|
<el-table-column width="55" align="center">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<el-radio v-model="selectedProductId" :label="row.id"> </el-radio>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column :label="t('ErpStock.Item.code')" prop="barCode" min-width="160" />
|
|
|
|
|
<el-table-column :label="productColumnLabel" prop="name" min-width="160" />
|
|
|
|
|
<el-table-column :label="t('ErpStock.Item.spec')" prop="standard" min-width="120" />
|
|
|
|
|
<el-table-column :label="t('ErpStock.Item.category')" prop="subCategoryName" min-width="120" />
|
|
|
|
|
<el-table-column :label="t('ErpStock.Item.unit')" prop="unitName" min-width="80" />
|
|
|
|
|
</el-table>
|
|
|
|
|
<div class="product-dialog-pagination">
|
|
|
|
|
<Pagination
|
|
|
|
|
:total="productDialogTotal"
|
|
|
|
|
v-model:page="productQueryParams.pageNo"
|
|
|
|
|
v-model:limit="productQueryParams.pageSize"
|
|
|
|
|
@pagination="getProductDialogList"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<template #footer>
|
|
|
|
|
<el-button type="primary" :disabled="!selectedProductId" @click="confirmProductSelect">
|
|
|
|
|
{{ t('common.ok') }}
|
|
|
|
|
</el-button>
|
|
|
|
|
<el-button @click="productDialogVisible = false">{{ t('common.cancel') }}</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</Dialog>
|
|
|
|
|
</template>
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ProductApi, ProductVO } from '@/api/erp/product/product'
|
|
|
|
|
import { ProductApi } from '@/api/erp/product/product'
|
|
|
|
|
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
|
|
|
|
|
import { StockApi } from '@/api/erp/stock/stock'
|
|
|
|
|
import {
|
|
|
|
|
erpCountInputFormatter,
|
|
|
|
|
erpPriceInputFormatter,
|
|
|
|
|
erpPriceMultiply,
|
|
|
|
|
getSumValue
|
|
|
|
|
} from '@/utils'
|
|
|
|
|
import { StockMoveApi } from '@/api/erp/stock/move'
|
|
|
|
|
import { erpCountInputFormatter, getSumValue } from '@/utils'
|
|
|
|
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
|
|
|
|
|
|
|
|
|
const { t } = useI18n() // 国际化
|
|
|
|
|
const { t } = useI18n()
|
|
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
items: undefined
|
|
|
|
|
disabled: false
|
|
|
|
|
items?: any[]
|
|
|
|
|
categoryType?: number
|
|
|
|
|
disabled?: boolean
|
|
|
|
|
}>()
|
|
|
|
|
const formLoading = ref(false) // 表单的加载中
|
|
|
|
|
const formData = ref([])
|
|
|
|
|
|
|
|
|
|
const formLoading = ref(false)
|
|
|
|
|
const formData = ref<any[]>([])
|
|
|
|
|
const sameAreaMessage = '调出库区和调入库区不能相同'
|
|
|
|
|
const formRules = reactive({
|
|
|
|
|
inId: [{ required: true, message: '调度编号不能为空', trigger: 'blur' }],
|
|
|
|
|
fromWarehouseId: [{ required: true, message: t('ErpStock.Move.item.validatorFromWarehouseRequired'), trigger: 'blur' }],
|
|
|
|
|
toWarehouseId: [{ required: true, message: t('ErpStock.Move.item.validatorToWarehouseRequired'), trigger: 'blur' }],
|
|
|
|
|
productId: [{ required: true, message: t('ErpStock.Item.validatorProductRequired'), trigger: 'blur' }],
|
|
|
|
|
count: [{ required: true, message: t('ErpStock.Item.validatorCountRequired'), trigger: 'blur' }]
|
|
|
|
|
inId: [{ required: true, message: '调度编号不能为空', trigger: 'submit' }],
|
|
|
|
|
fromWarehouseId: [{ required: true, message: t('ErpStock.Move.item.validatorFromWarehouseRequired'), trigger: 'submit' }],
|
|
|
|
|
fromAreaId: [
|
|
|
|
|
{ required: true, message: t('ErpStock.Item.validatorAreaRequired'), trigger: 'submit' },
|
|
|
|
|
{ validator: validateDifferentArea, trigger: ['change', 'submit'] }
|
|
|
|
|
],
|
|
|
|
|
toWarehouseId: [{ required: true, message: t('ErpStock.Move.item.validatorToWarehouseRequired'), trigger: 'submit' }],
|
|
|
|
|
toAreaId: [
|
|
|
|
|
{ required: true, message: t('ErpStock.Item.validatorAreaRequired'), trigger: 'submit' },
|
|
|
|
|
{ validator: validateDifferentArea, trigger: ['change', 'submit'] }
|
|
|
|
|
],
|
|
|
|
|
productId: [{ required: true, message: t('ErpStock.Item.validatorProductRequired'), trigger: 'submit' }],
|
|
|
|
|
count: [{ required: true, message: t('ErpStock.Item.validatorCountRequired'), trigger: 'submit' }]
|
|
|
|
|
})
|
|
|
|
|
const formRef = ref()
|
|
|
|
|
const warehouseList = ref<WarehouseVO[]>([])
|
|
|
|
|
const productList = ref<any[]>([])
|
|
|
|
|
const currentSelectRow = ref<any>()
|
|
|
|
|
const productDialogVisible = ref(false)
|
|
|
|
|
const productDialogLoading = ref(false)
|
|
|
|
|
const productDialogList = ref<any[]>([])
|
|
|
|
|
const productDialogTotal = ref(0)
|
|
|
|
|
const selectedProductId = ref<number>()
|
|
|
|
|
const productQueryParams = reactive({
|
|
|
|
|
pageNo: 1,
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
categoryType: undefined as number | undefined,
|
|
|
|
|
barCode: undefined as string | undefined,
|
|
|
|
|
name: undefined as string | undefined
|
|
|
|
|
})
|
|
|
|
|
const formRef = ref([]) // 表单 Ref
|
|
|
|
|
const productList = ref<ProductVO[]>([]) // 产品列表
|
|
|
|
|
const warehouseList = ref<WarehouseVO[]>([]) // 仓库列表
|
|
|
|
|
const defaultWarehouse = ref<WarehouseVO>(undefined) // 默认仓库
|
|
|
|
|
|
|
|
|
|
/** 初始化设置调度项 */
|
|
|
|
|
const categoryTypeLabel = computed(() => {
|
|
|
|
|
const option = getIntDictOptions(DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE).find(
|
|
|
|
|
(item) => Number(item.value) === Number(props.categoryType)
|
|
|
|
|
)
|
|
|
|
|
return option?.label || t('ErpStock.Item.productName')
|
|
|
|
|
})
|
|
|
|
|
const productColumnLabel = computed(() => categoryTypeLabel.value)
|
|
|
|
|
const productPlaceholder = computed(() => `请选择${productColumnLabel.value}`)
|
|
|
|
|
const productSelectTitle = computed(() => `选择${productColumnLabel.value}`)
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => props.items,
|
|
|
|
|
async (val) => {
|
|
|
|
|
formData.value = val
|
|
|
|
|
(val) => {
|
|
|
|
|
formData.value = val || []
|
|
|
|
|
ensureDefaultRow()
|
|
|
|
|
},
|
|
|
|
|
{ immediate: true }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/** 监听合同产品变化,计算合同产品总价 */
|
|
|
|
|
watch(
|
|
|
|
|
() => formData.value,
|
|
|
|
|
(val) => {
|
|
|
|
|
if (!val || val.length === 0) {
|
|
|
|
|
return
|
|
|
|
|
() => props.categoryType,
|
|
|
|
|
async (val, oldVal) => {
|
|
|
|
|
await loadOptions()
|
|
|
|
|
if (oldVal !== undefined && val !== oldVal) {
|
|
|
|
|
formData.value.forEach(clearRowSelection)
|
|
|
|
|
}
|
|
|
|
|
// 循环处理
|
|
|
|
|
val.forEach((item) => {
|
|
|
|
|
item.totalPrice = erpPriceMultiply(item.productPrice, item.count)
|
|
|
|
|
})
|
|
|
|
|
ensureDefaultRow()
|
|
|
|
|
},
|
|
|
|
|
{ deep: true }
|
|
|
|
|
{ immediate: true }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/** 合计 */
|
|
|
|
|
const getSummaries = (param: SummaryMethodProps) => {
|
|
|
|
|
function getSummaries(param: SummaryMethodProps) {
|
|
|
|
|
const { columns, data } = param
|
|
|
|
|
const sums: string[] = []
|
|
|
|
|
columns.forEach((column, index) => {
|
|
|
|
|
@ -213,82 +313,324 @@ const getSummaries = (param: SummaryMethodProps) => {
|
|
|
|
|
sums[index] = t('common.total')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (['count', 'totalPrice'].includes(column.property)) {
|
|
|
|
|
const sum = getSumValue(data.map((item) => Number(item[column.property])))
|
|
|
|
|
sums[index] =
|
|
|
|
|
column.property === 'count' ? erpCountInputFormatter(sum) : erpPriceInputFormatter(sum)
|
|
|
|
|
if (column.property === 'count') {
|
|
|
|
|
sums[index] = erpCountInputFormatter(getSumValue(data.map((item) => Number(item[column.property]))))
|
|
|
|
|
} else {
|
|
|
|
|
sums[index] = ''
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return sums
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 新增按钮操作 */
|
|
|
|
|
const handleAdd = () => {
|
|
|
|
|
const row = {
|
|
|
|
|
function ensureDefaultRow() {
|
|
|
|
|
if (!props.disabled && formData.value.length === 0) {
|
|
|
|
|
handleAdd()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleAdd() {
|
|
|
|
|
formData.value.push({
|
|
|
|
|
id: undefined,
|
|
|
|
|
fromWarehouseId: defaultWarehouse.value?.id,
|
|
|
|
|
fromWarehouseId: undefined,
|
|
|
|
|
fromAreaId: undefined,
|
|
|
|
|
toWarehouseId: undefined,
|
|
|
|
|
toAreaId: undefined,
|
|
|
|
|
toAreaList: [],
|
|
|
|
|
productId: undefined,
|
|
|
|
|
productUnitName: undefined, // 产品单位
|
|
|
|
|
productBarCode: undefined, // 产品条码
|
|
|
|
|
productPrice: undefined,
|
|
|
|
|
productName: undefined,
|
|
|
|
|
productUnitName: undefined,
|
|
|
|
|
productBarCode: undefined,
|
|
|
|
|
stockCount: undefined,
|
|
|
|
|
productStockList: [],
|
|
|
|
|
count: 1,
|
|
|
|
|
totalPrice: undefined,
|
|
|
|
|
remark: undefined
|
|
|
|
|
}
|
|
|
|
|
formData.value.push(row)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 删除按钮操作 */
|
|
|
|
|
const handleDelete = (index) => {
|
|
|
|
|
function handleDelete(index) {
|
|
|
|
|
formData.value.splice(index, 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 处理仓库变更 */
|
|
|
|
|
const onChangeWarehouse = (warehouseId, row) => {
|
|
|
|
|
// 加载库存
|
|
|
|
|
setStockCount(row)
|
|
|
|
|
function isSameMoveArea(row) {
|
|
|
|
|
return row.fromAreaId !== undefined && row.toAreaId !== undefined && String(row.fromAreaId) === String(row.toAreaId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function validateDifferentArea(rule, _value, callback) {
|
|
|
|
|
const rowIndex = Number(String(rule.field || '').split('.')[0])
|
|
|
|
|
const row = formData.value[rowIndex]
|
|
|
|
|
if (row && isSameMoveArea(row)) {
|
|
|
|
|
callback(new Error(sameAreaMessage))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
callback()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 处理产品变更 */
|
|
|
|
|
const onChangeProduct = (productId, row) => {
|
|
|
|
|
const product = productList.value.find((item) => item.id === productId)
|
|
|
|
|
if (product) {
|
|
|
|
|
row.productUnitName = product.unitName
|
|
|
|
|
row.productBarCode = product.barCode
|
|
|
|
|
row.productPrice = product.minPrice
|
|
|
|
|
function warnIfSameArea(row) {
|
|
|
|
|
if (isSameMoveArea(row)) {
|
|
|
|
|
ElMessage.warning(sameAreaMessage)
|
|
|
|
|
}
|
|
|
|
|
// 加载库存
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function validateAreaFields(row) {
|
|
|
|
|
const rowIndex = formData.value.indexOf(row)
|
|
|
|
|
if (rowIndex < 0) return
|
|
|
|
|
formRef.value?.validateField([`${rowIndex}.fromAreaId`, `${rowIndex}.toAreaId`])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleFromAreaChange(row) {
|
|
|
|
|
await setStockCount(row)
|
|
|
|
|
warnIfSameArea(row)
|
|
|
|
|
validateAreaFields(row)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleToAreaChange(row) {
|
|
|
|
|
warnIfSameArea(row)
|
|
|
|
|
validateAreaFields(row)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onChangeFromWarehouse(_warehouseId, row) {
|
|
|
|
|
const firstStock = getFromAreaOptions(row)[0]
|
|
|
|
|
row.fromAreaId = firstStock ? getStockAreaId(firstStock) : undefined
|
|
|
|
|
setStockCount(row)
|
|
|
|
|
warnIfSameArea(row)
|
|
|
|
|
validateAreaFields(row)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function onChangeToWarehouse(row) {
|
|
|
|
|
row.toAreaId = undefined
|
|
|
|
|
row.toAreaList = []
|
|
|
|
|
if (!row.toWarehouseId) return
|
|
|
|
|
const warehouse = await WarehouseApi.getWarehouse(row.toWarehouseId)
|
|
|
|
|
row.toAreaList = warehouse?.areaList || []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleProductInputClick(row) {
|
|
|
|
|
if (props.disabled) return
|
|
|
|
|
openProductSelectDialog(row)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleProductClear(row) {
|
|
|
|
|
if (props.disabled) return
|
|
|
|
|
clearRowSelection(row)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getProductDisplayName(row) {
|
|
|
|
|
return row.productName || productList.value.find((item) => item.id === row.productId)?.name || ''
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function openProductSelectDialog(row) {
|
|
|
|
|
if (!props.categoryType) return
|
|
|
|
|
currentSelectRow.value = row
|
|
|
|
|
selectedProductId.value = row.productId
|
|
|
|
|
productQueryParams.pageNo = 1
|
|
|
|
|
productQueryParams.categoryType = props.categoryType
|
|
|
|
|
productQueryParams.barCode = undefined
|
|
|
|
|
productQueryParams.name = undefined
|
|
|
|
|
productDialogVisible.value = true
|
|
|
|
|
await getProductDialogList()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function getProductDialogList() {
|
|
|
|
|
productDialogLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
productQueryParams.categoryType = props.categoryType
|
|
|
|
|
const data = await ProductApi.getProductPage(productQueryParams)
|
|
|
|
|
productDialogList.value = data?.list || []
|
|
|
|
|
productDialogTotal.value = data?.total || 0
|
|
|
|
|
} finally {
|
|
|
|
|
productDialogLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleProductDialogQuery() {
|
|
|
|
|
productQueryParams.pageNo = 1
|
|
|
|
|
getProductDialogList()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleProductDialogRowClick(row: any) {
|
|
|
|
|
selectedProductId.value = row.id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function confirmProductSelect() {
|
|
|
|
|
if (props.disabled) return
|
|
|
|
|
const product = productDialogList.value.find((item) => item.id === selectedProductId.value)
|
|
|
|
|
if (!product || !currentSelectRow.value) return
|
|
|
|
|
fillRowByProduct(currentSelectRow.value, product)
|
|
|
|
|
await loadProductStockList(currentSelectRow.value)
|
|
|
|
|
productDialogVisible.value = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function fillRowByProduct(row, product) {
|
|
|
|
|
row.productId = product.id
|
|
|
|
|
row.productName = product.name
|
|
|
|
|
row.productUnitName = product.unitName
|
|
|
|
|
row.productBarCode = product.barCode
|
|
|
|
|
row.fromWarehouseId = undefined
|
|
|
|
|
row.fromAreaId = undefined
|
|
|
|
|
row.toWarehouseId = undefined
|
|
|
|
|
row.toAreaId = undefined
|
|
|
|
|
row.toAreaList = []
|
|
|
|
|
row.stockCount = undefined
|
|
|
|
|
row.productStockList = []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function clearRowSelection(row) {
|
|
|
|
|
row.productId = undefined
|
|
|
|
|
row.productName = undefined
|
|
|
|
|
row.productUnitName = undefined
|
|
|
|
|
row.productBarCode = undefined
|
|
|
|
|
row.stockCount = undefined
|
|
|
|
|
row.productStockList = []
|
|
|
|
|
row.fromWarehouseId = undefined
|
|
|
|
|
row.fromAreaId = undefined
|
|
|
|
|
row.toWarehouseId = undefined
|
|
|
|
|
row.toAreaId = undefined
|
|
|
|
|
row.toAreaList = []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 加载库存 */
|
|
|
|
|
const setStockCount = async (row) => {
|
|
|
|
|
if (!row.productId || !row.fromWarehouseId) {
|
|
|
|
|
async function loadOptions() {
|
|
|
|
|
const params = props.categoryType ? { categoryType: props.categoryType } : undefined
|
|
|
|
|
formLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
const [products, warehouses] = await Promise.all([
|
|
|
|
|
ProductApi.getProductSimpleList(params),
|
|
|
|
|
WarehouseApi.getWarehouseSimpleList(params)
|
|
|
|
|
])
|
|
|
|
|
productList.value = products || []
|
|
|
|
|
warehouseList.value = warehouses || []
|
|
|
|
|
} finally {
|
|
|
|
|
formLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeProductStockList(data) {
|
|
|
|
|
if (Array.isArray(data)) return data
|
|
|
|
|
if (Array.isArray(data?.list)) return data.list
|
|
|
|
|
return []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function loadProductStockList(row) {
|
|
|
|
|
if (!row.productId) {
|
|
|
|
|
row.productStockList = []
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
const stock = await StockApi.getStock2(row.productId, row.fromWarehouseId)
|
|
|
|
|
row.stockCount = stock ? stock.count : 0
|
|
|
|
|
const data = await StockMoveApi.getProductStockList(row.productId)
|
|
|
|
|
row.productStockList = normalizeProductStockList(data)
|
|
|
|
|
await fillProductStockAreaInfo(row.productStockList)
|
|
|
|
|
const firstStock = row.productStockList[0]
|
|
|
|
|
row.fromWarehouseId = firstStock ? getStockWarehouseId(firstStock) : undefined
|
|
|
|
|
row.fromAreaId = firstStock ? getStockAreaId(firstStock) : undefined
|
|
|
|
|
row.stockCount = firstStock ? getStockCount(firstStock) : undefined
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 表单校验 */
|
|
|
|
|
const validate = () => {
|
|
|
|
|
return formRef.value.validate()
|
|
|
|
|
async function fillProductStockAreaInfo(stockList) {
|
|
|
|
|
const warehouseIds = Array.from(
|
|
|
|
|
new Set((stockList || []).map((item) => getStockWarehouseId(item)).filter(Boolean))
|
|
|
|
|
)
|
|
|
|
|
await Promise.all(
|
|
|
|
|
warehouseIds.map(async (warehouseId) => {
|
|
|
|
|
const warehouse = await WarehouseApi.getWarehouse(warehouseId)
|
|
|
|
|
const areaList = warehouse?.areaList || []
|
|
|
|
|
stockList
|
|
|
|
|
.filter((item) => Number(getStockWarehouseId(item)) === Number(warehouseId))
|
|
|
|
|
.forEach((item) => {
|
|
|
|
|
const area = areaList.find((areaItem) => Number(areaItem.id) === Number(getStockAreaId(item)))
|
|
|
|
|
if (!area) return
|
|
|
|
|
item.areaCode = area.areaCode
|
|
|
|
|
item.areaName = area.areaName
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
defineExpose({ validate })
|
|
|
|
|
|
|
|
|
|
/** 初始化 */
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
productList.value = await ProductApi.getProductSimpleList()
|
|
|
|
|
warehouseList.value = await WarehouseApi.getWarehouseSimpleList()
|
|
|
|
|
defaultWarehouse.value = warehouseList.value.find((item) => item.defaultStatus)
|
|
|
|
|
// 默认添加一个
|
|
|
|
|
if (formData.value.length === 0) {
|
|
|
|
|
handleAdd()
|
|
|
|
|
function getFromWarehouseOptions(row) {
|
|
|
|
|
const stockList = row.productStockList || []
|
|
|
|
|
const warehouseMap = new Map()
|
|
|
|
|
stockList.forEach((item) => {
|
|
|
|
|
const warehouseId = getStockWarehouseId(item)
|
|
|
|
|
if (warehouseId !== undefined && !warehouseMap.has(warehouseId)) {
|
|
|
|
|
warehouseMap.set(warehouseId, item)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return Array.from(warehouseMap.values())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getFromAreaOptions(row) {
|
|
|
|
|
if (!row.fromWarehouseId) return []
|
|
|
|
|
return (row.productStockList || []).filter(
|
|
|
|
|
(item) => Number(getStockWarehouseId(item)) === Number(row.fromWarehouseId)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getStockWarehouseId(stock) {
|
|
|
|
|
return stock.warehouseId
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getStockWarehouseName(stock) {
|
|
|
|
|
return stock.warehouseName || stock.name || stock.warehouseId
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getStockAreaId(stock) {
|
|
|
|
|
return stock.areaId
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getStockCount(stock) {
|
|
|
|
|
return stock.stockCount ?? stock.count
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getToAreaOptions(row) {
|
|
|
|
|
if (Array.isArray(row.toAreaList) && row.toAreaList.length > 0) return row.toAreaList
|
|
|
|
|
return warehouseList.value.find((item) => Number(item.id) === Number(row.toWarehouseId))?.areaList || []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAreaLabel(item) {
|
|
|
|
|
const areaCode = item.areaCode || item.code
|
|
|
|
|
const areaName = item.areaName || item.name
|
|
|
|
|
return areaCode ? `${areaCode} - ${areaName || ''}` : areaName
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function setStockCount(row) {
|
|
|
|
|
if (!row.productId || !row.fromWarehouseId || !row.fromAreaId) {
|
|
|
|
|
row.stockCount = undefined
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
if (!Array.isArray(row.productStockList) || row.productStockList.length === 0) {
|
|
|
|
|
await loadProductStockList(row)
|
|
|
|
|
}
|
|
|
|
|
const stock = row.productStockList.find(
|
|
|
|
|
(item) =>
|
|
|
|
|
Number(getStockWarehouseId(item)) === Number(row.fromWarehouseId) &&
|
|
|
|
|
Number(getStockAreaId(item)) === Number(row.fromAreaId)
|
|
|
|
|
)
|
|
|
|
|
row.stockCount = stock ? getStockCount(stock) : 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function validate() {
|
|
|
|
|
return formRef.value.validate()
|
|
|
|
|
}
|
|
|
|
|
defineExpose({ validate })
|
|
|
|
|
</script>
|
|
|
|
|
<style scoped>
|
|
|
|
|
.stock-move-product-dialog :deep(.el-dialog__body) {
|
|
|
|
|
padding-bottom: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stock-move-product-dialog :deep(.el-dialog__footer) {
|
|
|
|
|
border-top: 1px solid var(--el-border-color-lighter);
|
|
|
|
|
padding-top: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.product-dialog-pagination {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
width: 100%;
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
padding-bottom: 12px;
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.product-dialog-pagination :deep(.pagination-container) {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|