feat:出入库单据、盘点调拨、盘点执行审核逻辑调整

main
黄伟杰 4 weeks ago
parent de442e9e7e
commit b4460d20ab

@ -84,7 +84,7 @@ export const StockInApi = {
}, },
// 提交入库单审核 // 提交入库单审核
submitStockIn: async (data: { id: string; auditUserId: string; remark?: string }) => { submitStockIn: async (data: { id: string; auditUserId?: string; remark?: string }) => {
return await request.put({ url: `/erp/stock-in/submit`, data }) return await request.put({ url: `/erp/stock-in/submit`, data })
}, },

@ -10,9 +10,23 @@ export interface StockMoveVO {
status: number status: number
auditUserId?: number auditUserId?: number
auditUserName?: string auditUserName?: string
approveRecords?: StockMoveApproveRecordVO[]
remark: string remark: string
} }
export interface StockMoveApproveRecordVO {
id?: number
stockMoveId?: number
actionType?: string
fromStatus?: number
toStatus?: number
targetUserId?: number
targetUserName?: string
remark?: string
creator?: string
creatorName?: string
createTime?: Date | string
}
export const StockMoveApi = { export const StockMoveApi = {
getStockMovePage: async (params: any) => { getStockMovePage: async (params: any) => {
return await request.get({ url: `/erp/stock-move/page`, params }) return await request.get({ url: `/erp/stock-move/page`, params })

@ -83,7 +83,7 @@ export const StockOutApi = {
}) })
}, },
submitStockOut: async (data: { id: string; auditUserId: string; remark?: string }) => { submitStockOut: async (data: { id: string; auditUserId?: string; remark?: string }) => {
return await request.put({ url: `/erp/stock-out/submit`, data }) return await request.put({ url: `/erp/stock-out/submit`, data })
}, },

@ -153,7 +153,7 @@
<el-table-column :label="t('common.operate')" align="center" fixed="right" width="320"> <el-table-column :label="t('common.operate')" align="center" fixed="right" width="320">
<template #default="scope"> <template #default="scope">
<el-button <el-button
v-if="Number(scope.row.status) === 10" v-if="!isAuditDisabled && Number(scope.row.status) === 10 && Number(scope.row.checkStatus) === 1"
link link
type="primary" type="primary"
@click="openAuditDialog(scope.row, 20)" @click="openAuditDialog(scope.row, 20)"
@ -161,7 +161,7 @@
{{ t('ErpStock.Check.auditApprove') }} {{ t('ErpStock.Check.auditApprove') }}
</el-button> </el-button>
<el-button <el-button
v-if="Number(scope.row.status) === 10" v-if="!isAuditDisabled && Number(scope.row.status) === 10 && Number(scope.row.checkStatus) === 1"
link link
type="danger" type="danger"
@click="openAuditDialog(scope.row, 1)" @click="openAuditDialog(scope.row, 1)"
@ -184,7 +184,7 @@
{{ t('action.edit') }} {{ t('action.edit') }}
</el-button> </el-button>
<el-button <el-button
v-if="[0, 1].includes(Number(scope.row.status)) && Number(scope.row.checkStatus) === 1" v-if="(isAuditDisabled ? [0, 1, 10] : [0, 1]).includes(Number(scope.row.status)) && Number(scope.row.checkStatus) === 1"
link link
type="primary" type="primary"
@click="openSubmitDialog(scope.row)" @click="openSubmitDialog(scope.row)"
@ -192,7 +192,7 @@
{{ t('ErpStock.Check.submit') }} {{ t('ErpStock.Check.submit') }}
</el-button> </el-button>
<el-button <el-button
v-if="Number(scope.row.checkStatus) !== 1" v-if="Number(scope.row.checkStatus) !== 1 || Number(scope.row.status) === 1"
link link
type="warning" type="warning"
:disabled="scope.row.status === 20" :disabled="scope.row.status === 20"
@ -221,22 +221,7 @@
</ContentWrap> </ContentWrap>
<Dialog :title="submitActionText" v-model="submitDialogVisible" width="500"> <Dialog :title="submitActionText" v-model="submitDialogVisible" width="500">
<el-form ref="submitFormRef" :model="submitForm" :rules="submitRules" label-width="auto"> <el-form :model="submitForm" label-width="auto">
<el-form-item v-if="!isAuditDisabled" :label="t('ErpStock.Check.auditUserName')" prop="auditUserId">
<el-select
v-model="submitForm.auditUserId"
filterable
:placeholder="t('ErpStock.Check.placeholderAuditUser')"
class="!w-1/1"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.Check.submitRemark')" prop="remark"> <el-form-item :label="t('ErpStock.Check.submitRemark')" prop="remark">
<el-input <el-input
v-model="submitForm.remark" v-model="submitForm.remark"
@ -281,7 +266,7 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter } from '@/utils/formatTime'
import { StockCheckApi, type StockCheckVO } from '@/api/erp/stock/check' import { StockCheckApi, type StockCheckVO } from '@/api/erp/stock/check'
import { WarehouseApi, type WarehouseVO } from '@/api/erp/stock/warehouse' import { WarehouseApi, type WarehouseVO } from '@/api/erp/stock/warehouse'
import * as UserApi from '@/api/system/user'
import * as ConfigApi from '@/api/infra/config' import * as ConfigApi from '@/api/infra/config'
import StockCheckExecutionForm from './components/StockCheckExecutionForm.vue' import StockCheckExecutionForm from './components/StockCheckExecutionForm.vue'
@ -295,24 +280,18 @@ const list = ref<StockCheckVO[]>([])
const total = ref(0) const total = ref(0)
const warehouseList = ref<WarehouseVO[]>([]) const warehouseList = ref<WarehouseVO[]>([])
const selectionList = ref<StockCheckVO[]>([]) const selectionList = ref<StockCheckVO[]>([])
const userList = ref<UserApi.UserVO[]>([])
const queryFormRef = ref() const queryFormRef = ref()
const formRef = ref() const formRef = ref()
const submitFormRef = ref()
const submitDialogVisible = ref(false) const submitDialogVisible = ref(false)
const submitLoading = ref(false) const submitLoading = ref(false)
const submitForm = reactive({ const submitForm = reactive({
id: undefined as number | undefined, id: undefined as number | undefined,
auditUserId: undefined as number | undefined,
remark: undefined as string | undefined remark: undefined as string | undefined
}) })
const isAuditDisabled = ref(false) const isAuditDisabled = ref(false)
const submitActionText = computed(() => const submitActionText = computed(() =>
isAuditDisabled.value ? t('ErpStock.Check.inventoryCheck') : t('ErpStock.Check.submit') t('ErpStock.Check.submit')
) )
const submitRules = computed(() => isAuditDisabled.value ? {} : {
auditUserId: [{ required: true, message: t('ErpStock.Check.validatorAuditUserRequired'), trigger: 'change' }]
})
const auditDialogVisible = ref(false) const auditDialogVisible = ref(false)
const auditLoading = ref(false) const auditLoading = ref(false)
const auditForm = reactive({ const auditForm = reactive({
@ -364,7 +343,7 @@ const resetQuery = () => {
} }
const isEditDisabled = (row: StockCheckVO) => { const isEditDisabled = (row: StockCheckVO) => {
return Number(row.status) === 20 || Number(row.checkStatus) === 1 return Number(row.status) === 20 || (Number(row.checkStatus) === 1 && Number(row.status) !== 1)
} }
const openForm = (type: string, id?: number, row?: StockCheckVO) => { const openForm = (type: string, id?: number, row?: StockCheckVO) => {
@ -400,17 +379,12 @@ const openSubmitDialog = (row: StockCheckVO) => {
return return
} }
submitForm.id = row.id submitForm.id = row.id
submitForm.auditUserId = row.auditUserId
submitForm.remark = undefined submitForm.remark = undefined
submitDialogVisible.value = true submitDialogVisible.value = true
submitFormRef.value?.clearValidate()
} }
const handleSubmit = async () => { const handleSubmit = async () => {
if (!isAuditDisabled.value) { if (!submitForm.id) {
await submitFormRef.value.validate()
}
if (!submitForm.id || (!isAuditDisabled.value && !submitForm.auditUserId)) {
return return
} }
submitLoading.value = true submitLoading.value = true
@ -426,11 +400,10 @@ const handleSubmit = async () => {
await getList() await getList()
return return
} }
const data: { id: number; auditUserId?: number; remark?: string } = { const data: { id: number; remark?: string } = {
id: submitForm.id, id: submitForm.id,
remark: submitForm.remark remark: submitForm.remark
} }
data.auditUserId = submitForm.auditUserId
await StockCheckApi.submitStockCheck(data) await StockCheckApi.submitStockCheck(data)
message.success(t('ErpStock.Check.submitSuccess')) message.success(t('ErpStock.Check.submitSuccess'))
submitDialogVisible.value = false submitDialogVisible.value = false
@ -476,13 +449,11 @@ const getWarehouseNames = (row: StockCheckVO) => {
} }
onMounted(async () => { onMounted(async () => {
const [warehouses, users] = await Promise.all([ const [warehouses] = await Promise.all([
WarehouseApi.getWarehouseSimpleList(), WarehouseApi.getWarehouseSimpleList(),
UserApi.getSimpleUserList(),
loadAuditConfig() loadAuditConfig()
]) ])
warehouseList.value = warehouses || [] warehouseList.value = warehouses || []
userList.value = users || []
await getList() await getList()
}) })
</script> </script>

@ -228,7 +228,7 @@
{{ t('action.edit') }} {{ t('action.edit') }}
</el-button> </el-button>
<el-button <el-button
v-if="[0, 1].includes(Number(scope.row.status))" v-if="(isAuditDisabled ? [0, 1, 10] : [0, 1]).includes(Number(scope.row.status))"
link link
type="primary" type="primary"
@click="openSubmitDialog(scope.row)" @click="openSubmitDialog(scope.row)"
@ -237,7 +237,7 @@
{{ submitActionText }} {{ submitActionText }}
</el-button> </el-button>
<el-button <el-button
v-if="Number(scope.row.status) === 10" v-if="!isAuditDisabled && Number(scope.row.status) === 10"
link link
type="primary" type="primary"
@click="openAuditDialog(scope.row, 20)" @click="openAuditDialog(scope.row, 20)"
@ -246,7 +246,7 @@
{{ t('ErpStock.In.auditApprove') }} {{ t('ErpStock.In.auditApprove') }}
</el-button> </el-button>
<el-button <el-button
v-if="Number(scope.row.status) === 10" v-if="!isAuditDisabled && Number(scope.row.status) === 10"
link link
type="danger" type="danger"
@click="openAuditDialog(scope.row, 1)" @click="openAuditDialog(scope.row, 1)"
@ -279,23 +279,7 @@
<StockInForm v-else ref="formRef" @success="getList" @closed="formVisible = false" /> <StockInForm v-else ref="formRef" @success="getList" @closed="formVisible = false" />
<Dialog :title="submitActionText" v-model="submitDialogVisible" width="520px"> <Dialog :title="submitActionText" v-model="submitDialogVisible" width="520px">
<el-form ref="submitFormRef" :model="submitFormData" :rules="submitFormRules" label-width="90px"> <el-form :model="submitFormData" label-width="90px">
<el-form-item v-if="!isAuditDisabled" :label="t('ErpStock.In.auditUser')" prop="auditUserId">
<el-select
v-model="submitFormData.auditUserId"
clearable
filterable
:placeholder="t('ErpStock.In.placeholderAuditUser')"
class="!w-1/1"
>
<el-option
v-for="item in userList"
:key="String(item.id)"
:label="item.nickname"
:value="String(item.id)"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.In.remark')" prop="remark"> <el-form-item :label="t('ErpStock.In.remark')" prop="remark">
<el-input <el-input
v-model="submitFormData.remark" v-model="submitFormData.remark"
@ -394,16 +378,11 @@ const actionLoading = ref(false)
const isAuditDisabled = ref(false) const isAuditDisabled = ref(false)
const submitActionText = computed(() => isAuditDisabled.value ? '入库' : t('ErpStock.In.submitAudit')) const submitActionText = computed(() => isAuditDisabled.value ? '入库' : t('ErpStock.In.submitAudit'))
const submitDialogVisible = ref(false) const submitDialogVisible = ref(false)
const submitFormRef = ref()
const submitFormData = reactive({ const submitFormData = reactive({
id: '', id: '',
auditUserId: '',
status: '', status: '',
remark: '' remark: ''
}) })
const submitFormRules = computed(() => isAuditDisabled.value ? {} : {
auditUserId: [{ required: true, message: t('ErpStock.In.validatorAuditUserRequired'), trigger: 'change' }]
})
const auditDialogVisible = ref(false) const auditDialogVisible = ref(false)
const auditFormRef = ref() const auditFormRef = ref()
const auditFormData = reactive({ const auditFormData = reactive({
@ -487,17 +466,12 @@ const handleDelete = async (ids: number[]) => {
const openSubmitDialog = (row: StockInVO) => { const openSubmitDialog = (row: StockInVO) => {
submitFormData.id = String(row.id) submitFormData.id = String(row.id)
submitFormData.auditUserId = ''
submitFormData.status = String(row.status) submitFormData.status = String(row.status)
submitFormData.remark = '' submitFormData.remark = ''
submitDialogVisible.value = true submitDialogVisible.value = true
nextTick(() => submitFormRef.value?.clearValidate?.())
} }
const handleSubmitStockIn = async () => { const handleSubmitStockIn = async () => {
if (!isAuditDisabled.value) {
await submitFormRef.value.validate()
}
actionLoading.value = true actionLoading.value = true
try { try {
if (isAuditDisabled.value) { if (isAuditDisabled.value) {
@ -510,7 +484,6 @@ const handleSubmitStockIn = async () => {
} else { } else {
await StockInApi.submitStockIn({ await StockInApi.submitStockIn({
id: submitFormData.id, id: submitFormData.id,
auditUserId: submitFormData.auditUserId,
remark: submitFormData.remark remark: submitFormData.remark
}) })
message.success(t('ErpStock.In.submitSuccess')) message.success(t('ErpStock.In.submitSuccess'))

@ -66,6 +66,34 @@
:disabled="disabled" :disabled="disabled"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="disabled" label="审核记录" name="approveRecords">
<el-table :data="formData.approveRecords || []" border size="small" class="mt-12px">
<el-table-column label="变更前状态" prop="fromStatus" align="center" min-width="110">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.fromStatus" />
</template>
</el-table-column>
<el-table-column label="变更后状态" prop="toStatus" align="center" min-width="110">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.toStatus" />
</template>
</el-table-column>
<el-table-column label="目标审批人" prop="targetUserName" min-width="120" />
<el-table-column label="操作人" prop="creatorName" min-width="120" />
<el-table-column
label="操作时间"
prop="createTime"
:formatter="dateFormatter"
min-width="170"
/>
<el-table-column
:label="t('ErpStock.Move.remark')"
prop="remark"
min-width="160"
show-overflow-tooltip
/>
</el-table>
</el-tab-pane>
</el-tabs> </el-tabs>
</ContentWrap> </ContentWrap>
<template #footer> <template #footer>
@ -79,6 +107,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { StockMoveApi, StockMoveVO } from '@/api/erp/stock/move' import { StockMoveApi, StockMoveVO } from '@/api/erp/stock/move'
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import StockMoveItemForm from './components/StockMoveItemForm.vue' import StockMoveItemForm from './components/StockMoveItemForm.vue'
/** ERP 库存调度单表单 */ /** ERP 库存调度单表单 */
@ -86,6 +115,7 @@ defineOptions({ name: 'StockMoveForm' })
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
const getCurrentTime = () => Date.now()
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('') // const dialogTitle = ref('') //
@ -94,11 +124,12 @@ const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({ const formData = ref({
id: undefined, id: undefined,
customerId: undefined, customerId: undefined,
moveTime: undefined, moveTime: getCurrentTime(),
categoryType: undefined, categoryType: undefined,
remark: undefined, remark: undefined,
fileUrl: '', fileUrl: '',
items: [] items: [],
approveRecords: []
}) })
const formRules = reactive({ const formRules = reactive({
moveTime: [{ required: true, message: t('ErpStock.Move.validatorMoveTimeRequired'), trigger: 'blur' }], moveTime: [{ required: true, message: t('ErpStock.Move.validatorMoveTimeRequired'), trigger: 'blur' }],
@ -116,6 +147,7 @@ const open = async (type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
formType.value = type formType.value = type
subTabsName.value = 'item'
resetForm() resetForm()
// //
if (id) { if (id) {
@ -124,7 +156,8 @@ const open = async (type: string, id?: number) => {
const data = await StockMoveApi.getStockMove(id) const data = await StockMoveApi.getStockMove(id)
formData.value = { formData.value = {
...data, ...data,
categoryType: data.categoryType ?? getDefaultCategoryType() categoryType: data.categoryType ?? getDefaultCategoryType(),
approveRecords: data?.approveRecords || []
} }
} finally { } finally {
formLoading.value = false formLoading.value = false
@ -169,11 +202,12 @@ const resetForm = () => {
formData.value = { formData.value = {
id: undefined, id: undefined,
customerId: undefined, customerId: undefined,
moveTime: undefined, moveTime: getCurrentTime(),
categoryType: getDefaultCategoryType(), categoryType: getDefaultCategoryType(),
remark: undefined, remark: undefined,
fileUrl: undefined, fileUrl: undefined,
items: [] items: [],
approveRecords: []
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }

@ -106,7 +106,7 @@
placeholder="请选择调入仓库" placeholder="请选择调入仓库"
@change="onChangeToWarehouse(row)" @change="onChangeToWarehouse(row)"
> >
<el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in getToWarehouseOptions(row)" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> </template>
@ -141,6 +141,7 @@
:min="0.001" :min="0.001"
:precision="3" :precision="3"
class="!w-100%" class="!w-100%"
@change="handleCountChange(row)"
/> />
</el-form-item> </el-form-item>
</template> </template>
@ -255,7 +256,10 @@ const formRules = reactive({
{ validator: validateDifferentArea, trigger: ['change', 'submit'] } { validator: validateDifferentArea, trigger: ['change', 'submit'] }
], ],
productId: [{ required: true, message: t('ErpStock.Item.validatorProductRequired'), trigger: 'submit' }], productId: [{ required: true, message: t('ErpStock.Item.validatorProductRequired'), trigger: 'submit' }],
count: [{ required: true, message: t('ErpStock.Item.validatorCountRequired'), trigger: 'submit' }] count: [
{ required: true, message: t('ErpStock.Item.validatorCountRequired'), trigger: 'submit' },
{ validator: validateStockMoveCount, trigger: ['change', 'submit'] }
]
}) })
const formRef = ref() const formRef = ref()
const warehouseList = ref<WarehouseVO[]>([]) const warehouseList = ref<WarehouseVO[]>([])
@ -365,6 +369,52 @@ function validateDifferentArea(rule, _value, callback) {
callback() callback()
} }
function getNumberValue(value) {
if (value === undefined || value === null || value === '') return undefined
const numberValue = Number(String(value).replace(/,/g, ''))
return Number.isFinite(numberValue) ? numberValue : undefined
}
function getCountExceededMessage(row) {
const stockCount = getNumberValue(row.stockCount)
return stockCount === undefined
? '调拨数量不能大于库存'
: `调拨数量不能大于库存(当前库存:${erpCountInputFormatter(stockCount)}`
}
function isCountExceeded(row) {
const count = getNumberValue(row.count)
const stockCount = getNumberValue(row.stockCount)
return count !== undefined && stockCount !== undefined && count > stockCount
}
function validateStockMoveCount(rule, _value, callback) {
const rowIndex = Number(String(rule.field || '').split('.')[0])
const row = formData.value[rowIndex]
if (row && isCountExceeded(row)) {
callback(new Error(getCountExceededMessage(row)))
return
}
callback()
}
function warnIfCountExceeded(row) {
if (isCountExceeded(row)) {
ElMessage.warning(getCountExceededMessage(row))
}
}
function validateCountField(row) {
const rowIndex = formData.value.indexOf(row)
if (rowIndex < 0) return
formRef.value?.validateField(`${rowIndex}.count`).catch(() => undefined)
}
function handleCountChange(row) {
warnIfCountExceeded(row)
validateCountField(row)
}
function warnIfSameArea(row) { function warnIfSameArea(row) {
if (isSameMoveArea(row)) { if (isSameMoveArea(row)) {
ElMessage.warning(sameAreaMessage) ElMessage.warning(sameAreaMessage)
@ -374,13 +424,15 @@ function warnIfSameArea(row) {
function validateAreaFields(row) { function validateAreaFields(row) {
const rowIndex = formData.value.indexOf(row) const rowIndex = formData.value.indexOf(row)
if (rowIndex < 0) return if (rowIndex < 0) return
formRef.value?.validateField([`${rowIndex}.fromAreaId`, `${rowIndex}.toAreaId`]) formRef.value?.validateField([`${rowIndex}.fromAreaId`, `${rowIndex}.toAreaId`]).catch(() => undefined)
} }
async function handleFromAreaChange(row) { async function handleFromAreaChange(row) {
await setStockCount(row) await setStockCount(row)
warnIfSameArea(row) warnIfSameArea(row)
validateAreaFields(row) validateAreaFields(row)
warnIfCountExceeded(row)
validateCountField(row)
} }
function handleToAreaChange(row) { function handleToAreaChange(row) {
@ -388,12 +440,14 @@ function handleToAreaChange(row) {
validateAreaFields(row) validateAreaFields(row)
} }
function onChangeFromWarehouse(_warehouseId, row) { async function onChangeFromWarehouse(_warehouseId, row) {
const firstStock = getFromAreaOptions(row)[0] const firstStock = getFromAreaOptions(row)[0]
row.fromAreaId = firstStock ? getStockAreaId(firstStock) : undefined row.fromAreaId = firstStock ? getStockAreaId(firstStock) : undefined
setStockCount(row) await setStockCount(row)
warnIfSameArea(row) warnIfSameArea(row)
validateAreaFields(row) validateAreaFields(row)
warnIfCountExceeded(row)
validateCountField(row)
} }
async function onChangeToWarehouse(row) { async function onChangeToWarehouse(row) {
@ -521,6 +575,8 @@ async function loadProductStockList(row) {
row.fromWarehouseId = firstStock ? getStockWarehouseId(firstStock) : undefined row.fromWarehouseId = firstStock ? getStockWarehouseId(firstStock) : undefined
row.fromAreaId = firstStock ? getStockAreaId(firstStock) : undefined row.fromAreaId = firstStock ? getStockAreaId(firstStock) : undefined
row.stockCount = firstStock ? getStockCount(firstStock) : undefined row.stockCount = firstStock ? getStockCount(firstStock) : undefined
warnIfCountExceeded(row)
validateCountField(row)
} }
async function fillProductStockAreaInfo(stockList) { async function fillProductStockAreaInfo(stockList) {
@ -543,6 +599,12 @@ async function fillProductStockAreaInfo(stockList) {
) )
} }
function appendOptionIfMissing(options, id, option, getId) {
if (id === undefined || id === null || !option) return options
const exists = options.some((item) => String(getId(item)) === String(id))
return exists ? options : [option, ...options]
}
function getFromWarehouseOptions(row) { function getFromWarehouseOptions(row) {
const stockList = row.productStockList || [] const stockList = row.productStockList || []
const warehouseMap = new Map() const warehouseMap = new Map()
@ -552,41 +614,67 @@ function getFromWarehouseOptions(row) {
warehouseMap.set(warehouseId, item) warehouseMap.set(warehouseId, item)
} }
}) })
return Array.from(warehouseMap.values()) return appendOptionIfMissing(
Array.from(warehouseMap.values()),
row.fromWarehouseId,
row.fromWarehouseName ? { warehouseId: row.fromWarehouseId, warehouseName: row.fromWarehouseName } : undefined,
getStockWarehouseId
)
} }
function getFromAreaOptions(row) { function getFromAreaOptions(row) {
if (!row.fromWarehouseId) return [] if (!row.fromWarehouseId) return []
return (row.productStockList || []).filter( const areaOptions = (row.productStockList || []).filter(
(item) => Number(getStockWarehouseId(item)) === Number(row.fromWarehouseId) (item) => Number(getStockWarehouseId(item)) === Number(row.fromWarehouseId)
) )
return appendOptionIfMissing(
areaOptions,
row.fromAreaId,
row.fromAreaName ? { areaId: row.fromAreaId, areaName: row.fromAreaName } : undefined,
getStockAreaId
)
} }
function getStockWarehouseId(stock) { function getStockWarehouseId(stock) {
return stock.warehouseId return stock.warehouseId ?? stock.fromWarehouseId ?? stock.id
} }
function getStockWarehouseName(stock) { function getStockWarehouseName(stock) {
return stock.warehouseName || stock.name || stock.warehouseId return stock.warehouseName || stock.fromWarehouseName || stock.name || getStockWarehouseId(stock)
} }
function getStockAreaId(stock) { function getStockAreaId(stock) {
return stock.areaId return stock.areaId ?? stock.fromAreaId ?? stock.id
} }
function getStockCount(stock) { function getStockCount(stock) {
return stock.stockCount ?? stock.count return stock.stockCount ?? stock.count
} }
function getToWarehouseOptions(row) {
return appendOptionIfMissing(
warehouseList.value,
row.toWarehouseId,
row.toWarehouseName ? { id: row.toWarehouseId, name: row.toWarehouseName } : undefined,
(item) => item.id
)
}
function getToAreaOptions(row) { function getToAreaOptions(row) {
if (Array.isArray(row.toAreaList) && row.toAreaList.length > 0) return row.toAreaList const areaOptions = Array.isArray(row.toAreaList) && row.toAreaList.length > 0
return warehouseList.value.find((item) => Number(item.id) === Number(row.toWarehouseId))?.areaList || [] ? row.toAreaList
: warehouseList.value.find((item) => Number(item.id) === Number(row.toWarehouseId))?.areaList || []
return appendOptionIfMissing(
areaOptions,
row.toAreaId,
row.toAreaName ? { id: row.toAreaId, areaName: row.toAreaName } : undefined,
(item) => item.id
)
} }
function getAreaLabel(item) { function getAreaLabel(item) {
const areaCode = item.areaCode || item.code const areaCode = item.areaCode || item.code
const areaName = item.areaName || item.name const areaName = item.areaName || item.fromAreaName || item.toAreaName || item.name
return areaCode ? `${areaCode} - ${areaName || ''}` : areaName return areaCode ? `${areaCode} - ${areaName || ''}` : areaName
} }
@ -607,6 +695,10 @@ async function setStockCount(row) {
} }
function validate() { function validate() {
const exceededRow = formData.value.find(isCountExceeded)
if (exceededRow) {
ElMessage.warning(getCountExceededMessage(exceededRow))
}
return formRef.value.validate() return formRef.value.validate()
} }
defineExpose({ validate }) defineExpose({ validate })

@ -156,13 +156,13 @@
prop="totalCount" prop="totalCount"
:formatter="erpCountTableColumnFormatter" :formatter="erpCountTableColumnFormatter"
/> />
<el-table-column <!-- <el-table-column
:label="t('ErpStock.Move.price')" :label="t('ErpStock.Move.price')"
align="right" align="right"
sortable sortable
prop="totalPrice" prop="totalPrice"
:formatter="erpPriceTableColumnFormatter" :formatter="erpPriceTableColumnFormatter"
/> /> -->
<el-table-column :label="t('ErpStock.Move.status')" align="center" fixed="right" prop="status" sortable> <el-table-column :label="t('ErpStock.Move.status')" align="center" fixed="right" prop="status" sortable>
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" /> <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" />
@ -187,7 +187,7 @@
{{ t('action.edit') }} {{ t('action.edit') }}
</el-button> </el-button>
<el-button <el-button
v-if="[0, 1].includes(Number(scope.row.status))" v-if="(isAuditDisabled ? [0, 1, 10] : [0, 1]).includes(Number(scope.row.status))"
link link
type="primary" type="primary"
@click="openSubmitDialog(scope.row)" @click="openSubmitDialog(scope.row)"
@ -196,7 +196,7 @@
{{ t('ErpStock.Move.submit') }} {{ t('ErpStock.Move.submit') }}
</el-button> </el-button>
<el-button <el-button
v-if="Number(scope.row.status) === 10" v-if="!isAuditDisabled && Number(scope.row.status) === 10"
link link
type="primary" type="primary"
@click="openAuditDialog(scope.row, 20)" @click="openAuditDialog(scope.row, 20)"
@ -205,7 +205,7 @@
{{ t('ErpStock.Move.auditApprove') }} {{ t('ErpStock.Move.auditApprove') }}
</el-button> </el-button>
<el-button <el-button
v-if="Number(scope.row.status) === 10" v-if="!isAuditDisabled && Number(scope.row.status) === 10"
link link
type="danger" type="danger"
@click="openAuditDialog(scope.row, 1)" @click="openAuditDialog(scope.row, 1)"
@ -236,22 +236,7 @@
<Dialog :title="t('ErpStock.Move.submit')" v-model="submitDialogVisible" width="500"> <Dialog :title="t('ErpStock.Move.submit')" v-model="submitDialogVisible" width="500">
<el-form ref="submitFormRef" :model="submitForm" :rules="submitRules" label-width="auto"> <el-form :model="submitForm" label-width="auto">
<el-form-item v-if="!isAuditDisabled" :label="t('ErpStock.Move.auditUserName')" prop="auditUserId">
<el-select
v-model="submitForm.auditUserId"
filterable
:placeholder="t('ErpStock.Move.placeholderAuditUser')"
class="!w-1/1"
>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.Move.submitRemark')" prop="remark"> <el-form-item :label="t('ErpStock.Move.submitRemark')" prop="remark">
<el-input <el-input
v-model="submitForm.remark" v-model="submitForm.remark"
@ -329,18 +314,13 @@ const exportLoading = ref(false) // 导出的加载中
const productList = ref<ProductVO[]>([]) // const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) // const warehouseList = ref<WarehouseVO[]>([]) //
const userList = ref<UserVO[]>([]) // const userList = ref<UserVO[]>([]) //
const submitFormRef = ref()
const submitDialogVisible = ref(false) const submitDialogVisible = ref(false)
const submitLoading = ref(false) const submitLoading = ref(false)
const isAuditDisabled = ref(false) const isAuditDisabled = ref(false)
const submitForm = reactive({ const submitForm = reactive({
id: undefined as number | undefined, id: undefined as number | undefined,
auditUserId: undefined as number | undefined,
remark: undefined as string | undefined remark: undefined as string | undefined
}) })
const submitRules = computed(() => isAuditDisabled.value ? {} : {
auditUserId: [{ required: true, message: t('ErpStock.Move.validatorAuditUserRequired'), trigger: 'change' }]
})
const auditDialogVisible = ref(false) const auditDialogVisible = ref(false)
const auditLoading = ref(false) const auditLoading = ref(false)
const auditForm = reactive({ const auditForm = reactive({
@ -408,17 +388,12 @@ const handleDelete = async (ids: number[]) => {
const openSubmitDialog = (row: StockMoveVO) => { const openSubmitDialog = (row: StockMoveVO) => {
submitForm.id = row.id submitForm.id = row.id
submitForm.auditUserId = row.auditUserId
submitForm.remark = undefined submitForm.remark = undefined
submitDialogVisible.value = true submitDialogVisible.value = true
nextTick(() => submitFormRef.value?.clearValidate?.())
} }
const handleSubmit = async () => { const handleSubmit = async () => {
if (!isAuditDisabled.value) { if (!submitForm.id) return
await submitFormRef.value.validate()
}
if (!submitForm.id || (!isAuditDisabled.value && !submitForm.auditUserId)) return
submitLoading.value = true submitLoading.value = true
try { try {
if (isAuditDisabled.value) { if (isAuditDisabled.value) {
@ -431,7 +406,6 @@ const handleSubmit = async () => {
} else { } else {
await StockMoveApi.submitStockMove({ await StockMoveApi.submitStockMove({
id: submitForm.id, id: submitForm.id,
auditUserId: submitForm.auditUserId,
remark: submitForm.remark remark: submitForm.remark
}) })
message.success(t('ErpStock.Move.submitSuccess')) message.success(t('ErpStock.Move.submitSuccess'))

@ -228,7 +228,7 @@
{{ t('action.edit') }} {{ t('action.edit') }}
</el-button> </el-button>
<el-button <el-button
v-if="[0, 1].includes(Number(scope.row.status))" v-if="(isAuditDisabled ? [0, 1, 10] : [0, 1]).includes(Number(scope.row.status))"
link link
type="primary" type="primary"
@click="openSubmitDialog(scope.row)" @click="openSubmitDialog(scope.row)"
@ -237,7 +237,7 @@
{{ submitActionText }} {{ submitActionText }}
</el-button> </el-button>
<el-button <el-button
v-if="Number(scope.row.status) === 10" v-if="!isAuditDisabled && Number(scope.row.status) === 10"
link link
type="primary" type="primary"
@click="openAuditDialog(scope.row, 20)" @click="openAuditDialog(scope.row, 20)"
@ -246,7 +246,7 @@
{{ t('ErpStock.Out.auditApprove') }} {{ t('ErpStock.Out.auditApprove') }}
</el-button> </el-button>
<el-button <el-button
v-if="Number(scope.row.status) === 10" v-if="!isAuditDisabled && Number(scope.row.status) === 10"
link link
type="danger" type="danger"
@click="openAuditDialog(scope.row, 1)" @click="openAuditDialog(scope.row, 1)"
@ -279,23 +279,7 @@
<StockOutForm v-else ref="formRef" @success="getList" @closed="formVisible = false" /> <StockOutForm v-else ref="formRef" @success="getList" @closed="formVisible = false" />
<Dialog :title="submitActionText" v-model="submitDialogVisible" width="520px"> <Dialog :title="submitActionText" v-model="submitDialogVisible" width="520px">
<el-form ref="submitFormRef" :model="submitFormData" :rules="submitFormRules" label-width="90px"> <el-form :model="submitFormData" label-width="90px">
<el-form-item v-if="!isAuditDisabled" :label="t('ErpStock.Out.auditUser')" prop="auditUserId">
<el-select
v-model="submitFormData.auditUserId"
clearable
filterable
:placeholder="t('ErpStock.Out.placeholderAuditUser')"
class="!w-1/1"
>
<el-option
v-for="item in userList"
:key="String(item.id)"
:label="item.nickname"
:value="String(item.id)"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.Out.remark')" prop="remark"> <el-form-item :label="t('ErpStock.Out.remark')" prop="remark">
<el-input <el-input
v-model="submitFormData.remark" v-model="submitFormData.remark"
@ -393,16 +377,11 @@ const actionLoading = ref(false)
const isAuditDisabled = ref(false) const isAuditDisabled = ref(false)
const submitActionText = computed(() => isAuditDisabled.value ? '出库' : t('ErpStock.Out.submitAudit')) const submitActionText = computed(() => isAuditDisabled.value ? '出库' : t('ErpStock.Out.submitAudit'))
const submitDialogVisible = ref(false) const submitDialogVisible = ref(false)
const submitFormRef = ref()
const submitFormData = reactive({ const submitFormData = reactive({
id: '', id: '',
auditUserId: '',
status: '', status: '',
remark: '' remark: ''
}) })
const submitFormRules = computed(() => isAuditDisabled.value ? {} : {
auditUserId: [{ required: true, message: t('ErpStock.Out.validatorAuditUserRequired'), trigger: 'change' }]
})
const auditDialogVisible = ref(false) const auditDialogVisible = ref(false)
const auditFormRef = ref() const auditFormRef = ref()
const auditFormData = reactive({ const auditFormData = reactive({
@ -485,17 +464,12 @@ const handleDelete = async (ids: number[]) => {
const openSubmitDialog = (row: StockOutVO) => { const openSubmitDialog = (row: StockOutVO) => {
submitFormData.id = String(row.id) submitFormData.id = String(row.id)
submitFormData.auditUserId = ''
submitFormData.status = String(row.status) submitFormData.status = String(row.status)
submitFormData.remark = '' submitFormData.remark = ''
submitDialogVisible.value = true submitDialogVisible.value = true
nextTick(() => submitFormRef.value?.clearValidate?.())
} }
const handleSubmitStockOut = async () => { const handleSubmitStockOut = async () => {
if (!isAuditDisabled.value) {
await submitFormRef.value.validate()
}
actionLoading.value = true actionLoading.value = true
try { try {
if (isAuditDisabled.value) { if (isAuditDisabled.value) {
@ -508,7 +482,6 @@ const handleSubmitStockOut = async () => {
} else { } else {
await StockOutApi.submitStockOut({ await StockOutApi.submitStockOut({
id: submitFormData.id, id: submitFormData.id,
auditUserId: submitFormData.auditUserId,
remark: submitFormData.remark remark: submitFormData.remark
}) })
message.success(t('ErpStock.Out.submitSuccess')) message.success(t('ErpStock.Out.submitSuccess'))

Loading…
Cancel
Save