You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
besure_web/src/views/erp/warehouselocation/WarehouseLocationForm.vue

355 lines
12 KiB
Vue

<template>
<div class="warehouse-location-panel">
<div class="warehouse-location-panel__header">
<div class="warehouse-location-panel__title">{{ dialogTitle }}</div>
<el-button text @click="closeForm">
<Icon icon="ep:close" />
</el-button>
</div>
<div class="warehouse-location-dialog" v-loading="formLoading">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px">
<section class="warehouse-location-section">
<div class="warehouse-location-section__title">基本信息</div>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.warehouseId')" prop="warehouseId">
<el-select
v-model="formData.warehouseId"
:placeholder="t('ErpStock.WarehouseLocation.placeholderWarehouseId')"
class="!w-full"
@change="handleWarehouseChange"
>
<el-option
v-for="item in warehouseList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.areaId')" prop="areaId">
<el-select
v-model="formData.areaId"
:placeholder="t('ErpStock.WarehouseLocation.placeholderAreaId')"
class="!w-full"
>
<el-option
v-for="item in filteredAreaList"
:key="item.id"
:label="item.areaName"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.code')" prop="code">
<el-row :gutter="10" class="!w-full">
<el-col :span="18">
<el-input v-model="formData.code" :placeholder="t('ErpStock.WarehouseLocation.placeholderCode')" :disabled="formData.isCode == true || formType === 'update'" />
</el-col>
<el-col :span="6">
<el-switch v-model="formData.isCode" :disabled="formType === 'update'" />
</el-col>
</el-row>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.name')" prop="name">
<el-input v-model="formData.name" :placeholder="t('ErpStock.WarehouseLocation.placeholderName')" class="!w-full" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.areaSize')" prop="areaSize">
<el-input-number
v-model="formData.areaSize"
:placeholder="t('ErpStock.WarehouseLocation.placeholderAreaSize')"
:min="0"
:precision="2"
class="!w-full"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.maxLoadWeight')" prop="maxLoadWeight">
<el-input-number
v-model="formData.maxLoadWeight"
:placeholder="t('ErpStock.WarehouseLocation.placeholderMaxLoadWeight')"
:min="0"
:precision="2"
class="!w-full"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.positionX')" prop="positionX">
<el-input-number
v-model="formData.positionX"
:placeholder="t('ErpStock.WarehouseLocation.placeholderPositionX')"
:precision="0"
class="!w-full"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.positionY')" prop="positionY">
<el-input-number
v-model="formData.positionY"
:placeholder="t('ErpStock.WarehouseLocation.placeholderPositionY')"
:precision="0"
class="!w-full"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.positionZ')" prop="positionZ">
<el-input-number
v-model="formData.positionZ"
:placeholder="t('ErpStock.WarehouseLocation.placeholderPositionZ')"
:precision="0"
class="!w-full"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.allowProductMix')" prop="allowProductMix">
<el-switch v-model="formData.allowProductMix" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.allowBatchMix')" prop="allowBatchMix">
<el-switch v-model="formData.allowBatchMix" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="t('ErpStock.WarehouseLocation.status')" prop="status">
<el-switch v-model="formData.status" :active-value="CommonStatusEnum.ENABLE" :inactive-value="CommonStatusEnum.DISABLE" />
</el-form-item>
</el-col>
</el-row>
</section>
</el-form>
</div>
<div class="warehouse-location-footer">
<el-button @click="closeForm">{{ t('common.cancel') }}</el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { WarehouseLocationApi, WarehouseLocationVO } from '@/api/erp/stock/warehouselocation'
import { WarehouseApi } from '@/api/erp/stock/warehouse'
import { WarehouseAreaApi } from '@/api/erp/stock/warehousearea'
import { CommonStatusEnum } from '@/utils/constants'
defineOptions({ name: 'WarehouseLocationForm' })
const { t } = useI18n()
const message = useMessage()
const dialogTitle = ref('')
const formLoading = ref(false)
const formType = ref('')
const formData = ref({
id: undefined,
warehouseId: undefined,
areaId: undefined,
code: undefined,
name: undefined,
areaSize: undefined,
maxLoadWeight: undefined,
positionX: undefined,
positionY: undefined,
positionZ: undefined,
allowProductMix: false,
allowBatchMix: false,
status: undefined,
isCode: true
})
const formRules = reactive({
warehouseId: [{ required: true, message: t('ErpStock.WarehouseLocation.validatorWarehouseIdRequired'), trigger: 'blur' }],
areaId: [{ required: true, message: t('ErpStock.WarehouseLocation.validatorAreaIdRequired'), trigger: 'blur' }],
name: [{ required: true, message: t('ErpStock.WarehouseLocation.validatorNameRequired'), trigger: 'blur' }],
allowProductMix: [{ required: true, message: t('ErpStock.WarehouseLocation.validatorAllowProductMixRequired'), trigger: 'blur' }],
allowBatchMix: [{ required: true, message: t('ErpStock.WarehouseLocation.validatorAllowBatchMixRequired'), trigger: 'blur' }],
status: [{ required: true, message: t('ErpStock.WarehouseLocation.validatorStatusRequired'), trigger: 'blur' }]
})
const formRef = ref()
const warehouseList = ref<any[]>([])
const areaList = ref<any[]>([])
const filteredAreaList = computed(() => {
if (!formData.value.warehouseId) return areaList.value
return areaList.value.filter((item) => item.warehouseId === formData.value.warehouseId)
})
const handleWarehouseChange = () => {
formData.value.areaId = undefined
}
const open = async (type: string, id?: number) => {
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
warehouseList.value = await WarehouseApi.getWarehouseSimpleList()
const areaData = await WarehouseAreaApi.getWarehouseAreaPage({ pageNo: 1, pageSize: 100 })
areaList.value = areaData.list ?? []
if (id) {
formLoading.value = true
try {
formData.value = await WarehouseLocationApi.getWarehouseLocation(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open })
const emit = defineEmits(['success', 'closed'])
const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
const data = { ...formData.value } as unknown as WarehouseLocationVO
if (data.isCode) {
data.code = undefined
}
if (formType.value === 'create') {
await WarehouseLocationApi.createWarehouseLocation(data)
message.success(t('common.createSuccess'))
} else {
await WarehouseLocationApi.updateWarehouseLocation(data)
message.success(t('common.updateSuccess'))
}
closeForm()
emit('success')
} finally {
formLoading.value = false
}
}
const closeForm = () => {
emit('closed')
}
const resetForm = () => {
formData.value = {
id: undefined,
warehouseId: undefined,
areaId: undefined,
code: undefined,
name: undefined,
areaSize: undefined,
maxLoadWeight: undefined,
positionX: undefined,
positionY: undefined,
positionZ: undefined,
allowProductMix: false,
allowBatchMix: false,
status: CommonStatusEnum.ENABLE,
isCode: true
}
formRef.value?.resetFields()
}
</script>
<style lang="scss" scoped>
.warehouse-location-panel {
background: #fff;
border-radius: 12px;
box-shadow: var(--el-box-shadow-light);
}
.warehouse-location-panel__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid #ebeef5;
}
.warehouse-location-panel__title {
color: #1f2937;
font-size: 18px;
font-weight: 600;
}
.warehouse-location-dialog {
max-height: calc(100vh - 220px);
padding: 20px 20px 0;
padding-right: 16px;
overflow-y: auto;
}
.warehouse-location-section {
margin-bottom: 16px;
padding: 16px 18px 8px;
background: #fff;
border: 1px solid #ebeef5;
border-radius: 10px;
box-shadow: 0 4px 14px rgb(15 23 42 / 4%);
}
.warehouse-location-section__title {
position: relative;
margin-bottom: 16px;
padding-left: 10px;
color: #1f2937;
font-size: 15px;
font-weight: 600;
&::before {
position: absolute;
top: 2px;
left: 0;
width: 3px;
height: 16px;
background: var(--el-color-primary);
border-radius: 999px;
content: '';
}
}
.warehouse-location-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
width: 100%;
padding: 16px 20px 20px;
border-top: 1px solid #ebeef5;
}
@media (max-width: 1200px) {
.warehouse-location-dialog :deep(.el-col) {
max-width: 100%;
flex: 0 0 100%;
}
}
@media (max-width: 768px) {
.warehouse-location-panel__header {
padding: 14px 16px;
}
.warehouse-location-dialog {
max-height: none;
padding: 16px 16px 0;
overflow-y: visible;
}
.warehouse-location-footer {
padding: 16px;
}
}
</style>