admin-vue3/src/views/mes/wm/stocktaking/plan/StockTakingPlanParamList.vue

470 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- MES 盘点方案条件列表子组件 -->
<template>
<div>
<el-button
type="primary"
plain
@click="openForm('create')"
:disabled="disabled || (isRemoteMode && !planId)"
class="mb-10px"
>
<Icon icon="ep:plus" class="mr-5px" /> 添加条件
</el-button>
<el-table
v-loading="loading"
:data="displayList"
:stripe="true"
:show-overflow-tooltip="true"
border
>
<el-table-column label="条件类型" align="center" min-width="120">
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_WM_STOCK_TAKING_PLAN_PARAM_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="条件值编码" align="center" prop="valueCode" min-width="140" />
<el-table-column label="条件值名称" align="center" prop="valueName" min-width="160" />
<el-table-column v-if="!disabled" label="操作" align="center" width="120">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row.id)">编辑</el-button>
<el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<Pagination
v-if="isRemoteMode"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
<!-- 添加/编辑条件弹窗 -->
<Dialog :title="dialogTitle" v-model="dialogVisible" width="900px">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-row>
<el-col :span="12">
<el-form-item label="条件类型" prop="type">
<el-select
v-model="formData.type"
placeholder="请选择条件类型"
class="!w-full"
@change="handleTypeChange"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.MES_WM_STOCK_TAKING_PLAN_PARAM_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="条件值" prop="valueId">
<template v-if="formData.type === BarcodeBizTypeEnum.WAREHOUSE">
<WmWarehouseSelect
v-model="formData.valueId"
@change="(item) => handleSelectorChange(item)"
/>
</template>
<template v-else-if="formData.type === BarcodeBizTypeEnum.LOCATION">
<div class="space-y-2">
<WmWarehouseSelect
v-model="locationWarehouseId"
@change="handleLocationWarehouseChange"
class="!w-1/1"
placeholder="请选择仓库"
/>
<WmWarehouseLocationSelect
v-model="formData.valueId"
:warehouse-id="locationWarehouseId"
@change="(item) => handleSelectorChange(item)"
class="!w-1/1"
placeholder="请选择库区"
/>
</div>
</template>
<template v-else-if="formData.type === BarcodeBizTypeEnum.AREA">
<div class="space-y-2">
<WmWarehouseSelect
v-model="areaWarehouseId"
@change="handleAreaWarehouseChange"
class="!w-1/1"
placeholder="请选择仓库"
/>
<WmWarehouseLocationSelect
v-model="areaLocationId"
:warehouse-id="areaWarehouseId"
@change="handleAreaLocationChange"
class="!w-1/1"
placeholder="请选择库区"
/>
<WmWarehouseAreaSelect
v-model="formData.valueId"
:warehouse-id="areaWarehouseId"
@change="(item) => handleSelectorChange(item)"
class="!w-1/1"
placeholder="请选择库位"
/>
</div>
</template>
<template v-else-if="formData.type === BarcodeBizTypeEnum.ITEM">
<MdItemSelect
v-model="formData.valueId"
@change="(item) => handleSelectorChange(item)"
/>
</template>
<template v-else>
<el-row :gutter="8" class="w-full">
<el-col :span="8">
<el-input v-model="formData.valueId" placeholder="值ID" @change="handleManualChange" />
</el-col>
<el-col :span="8">
<el-input
v-model="formData.valueCode"
placeholder="值编码"
@change="handleManualChange"
/>
</el-col>
<el-col :span="8">
<el-input
v-model="formData.valueName"
placeholder="值名称"
@change="handleManualChange"
/>
</el-col>
</el-row>
</template>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import {
StockTakingPlanParamApi,
type StockTakingPlanParamVO
} from '@/api/mes/wm/stocktaking/plan/param/index'
import { BarcodeBizTypeEnum } from '@/views/mes/utils/constants'
import WmWarehouseSelect from '@/views/mes/wm/warehouse/components/WmWarehouseSelect.vue'
import WmWarehouseLocationSelect from '@/views/mes/wm/warehouse/components/WmWarehouseLocationSelect.vue'
import WmWarehouseAreaSelect from '@/views/mes/wm/warehouse/components/WmWarehouseAreaSelect.vue'
import MdItemSelect from '@/views/mes/md/item/components/MdItemSelect.vue'
import { WmWarehouseLocationApi } from '@/api/mes/wm/warehouse/location'
import { WmWarehouseAreaApi } from '@/api/mes/wm/warehouse/area'
defineOptions({ name: 'StockTakingPlanParamList' })
interface ParamRow extends StockTakingPlanParamVO {
valueId?: number | string
}
const props = withDefaults(
defineProps<{
modelValue?: ParamRow[]
planId?: number
disabled?: boolean
}>(),
{
modelValue: () => [],
planId: undefined,
disabled: false
}
)
const emit = defineEmits<{
'update:modelValue': [value: ParamRow[]]
}>()
const { t } = useI18n()
const message = useMessage()
// ==================== 列表 ====================
const loading = ref(false)
const list = ref<ParamRow[]>([])
const total = ref(0)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
planId: undefined as number | undefined
})
// TODO @AIisRemoteMode 字段不需要?
const isRemoteMode = computed(() => !!props.planId)
const localRows = computed({
get: () => props.modelValue || [],
set: (value) => emit('update:modelValue', value)
})
const displayList = computed(() => (isRemoteMode.value ? list.value : localRows.value))
/** 查询条件列表 */
const getList = async () => {
if (!isRemoteMode.value || !props.planId) {
list.value = []
total.value = 0
return
}
loading.value = true
try {
queryParams.planId = props.planId
const data = await StockTakingPlanParamApi.getStockTakingPlanParamPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 删除 */
const handleDelete = async (row: ParamRow) => {
try {
await message.delConfirm()
if (isRemoteMode.value && row.id) {
await StockTakingPlanParamApi.deleteStockTakingPlanParam(row.id)
message.success(t('common.delSuccess'))
// TODO @AI不用这个
// 如果是最后一条且不是第一页页码减1
if (list.value.length === 1 && queryParams.pageNo > 1) {
queryParams.pageNo -= 1
}
await getList()
return
}
localRows.value = localRows.value.filter((item) => item !== row)
message.success(t('common.delSuccess'))
} catch {}
}
// ==================== 添加/编辑表单 ====================
const dialogVisible = ref(false)
const dialogTitle = ref('')
const formLoading = ref(false)
const formType = ref('')
const formData = ref<ParamRow>({
id: undefined,
planId: undefined,
type: BarcodeBizTypeEnum.WAREHOUSE,
valueId: undefined,
valueCode: '',
valueName: '',
remark: ''
})
const formRules = reactive({
type: [{ required: true, message: '请选择条件类型', trigger: 'change' }],
valueId: [{ required: true, message: '条件值不能为空', trigger: 'change' }]
})
const formRef = ref()
const editingIndex = ref<number>(-1)
const locationWarehouseId = ref<number>() // 库区选择器的临时数据:选择仓库后,传给库区选择器
const areaWarehouseId = ref<number>() // 库位选择器的临时数据:选择仓库后,传给库位选择器
const areaLocationId = ref<number>() // 库位选择器的临时数据:选择库区后,传给库位选择器
const isLoadingData = ref(false) // 标记是否正在加载数据,避免 watch 清空字段
/** 打开表单弹窗 */
const openForm = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
if (id) {
formLoading.value = true
isLoadingData.value = true
try {
formData.value = (await StockTakingPlanParamApi.getStockTakingPlanParam(id)) as ParamRow
// 编辑时,需要回填级联选择器的中间层级数据
await loadCascadeData()
} finally {
formLoading.value = false
isLoadingData.value = false
}
} else if (type === 'update') {
// 本地模式编辑
const row = localRows.value.find((item) => item === id)
if (row) {
formData.value = { ...row }
editingIndex.value = localRows.value.findIndex((item) => item === row)
}
}
}
/** 提交表单 */
const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
const data = {
...formData.value,
planId: props.planId,
valueId: Number(formData.value.valueId)
} as StockTakingPlanParamVO
if (isRemoteMode.value && props.planId) {
if (formType.value === 'create') {
await StockTakingPlanParamApi.createStockTakingPlanParam(data)
message.success(t('common.createSuccess'))
} else {
await StockTakingPlanParamApi.updateStockTakingPlanParam(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
await getList()
return
}
// 本地模式
const nextRows = [...localRows.value]
if (formType.value === 'create') {
nextRows.push({ ...data, planId: undefined })
message.success(t('common.createSuccess'))
} else if (editingIndex.value > -1) {
nextRows.splice(editingIndex.value, 1, { ...data, planId: undefined })
message.success(t('common.updateSuccess'))
}
localRows.value = nextRows
dialogVisible.value = false
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
planId: props.planId,
type: BarcodeBizTypeEnum.WAREHOUSE,
valueId: undefined,
valueCode: '',
valueName: '',
remark: ''
}
editingIndex.value = -1
formRef.value?.resetFields()
}
/** 条件类型变化 */
const handleTypeChange = () => {
// 加载数据时不清空字段
if (isLoadingData.value) {
return
}
formData.value.valueId = undefined
formData.value.valueCode = ''
formData.value.valueName = ''
// 清空仓库层级的临时数据
locationWarehouseId.value = undefined
areaWarehouseId.value = undefined
areaLocationId.value = undefined
}
/** 选择器变化 */
const handleSelectorChange = (item?: any) => {
formData.value.valueId = item?.id
formData.value.valueCode = item?.code || ''
formData.value.valueName = item?.name || item?.nickname || ''
}
/** 手动输入变化 */
const handleManualChange = () => {
if (
formData.value.valueId !== undefined &&
formData.value.valueId !== null &&
formData.value.valueId !== ''
) {
const num = Number(formData.value.valueId)
formData.value.valueId = Number.isNaN(num) ? formData.value.valueId : num
}
}
/** 库区仓库选择回调:清空库区 */
const handleLocationWarehouseChange = () => {
formData.value.valueId = undefined
formData.value.valueCode = ''
formData.value.valueName = ''
}
/** 库位仓库选择回调:清空库区和库位 */
const handleAreaWarehouseChange = () => {
areaLocationId.value = undefined
formData.value.valueId = undefined
formData.value.valueCode = ''
formData.value.valueName = ''
}
/** 库位库区选择回调:清空库位 */
const handleAreaLocationChange = () => {
formData.value.valueId = undefined
formData.value.valueCode = ''
formData.value.valueName = ''
}
/** 加载级联选择器的数据(编辑时回填上级数据) */
const loadCascadeData = async () => {
if (!formData.value.type || !formData.value.valueId) {
return
}
try {
// 库区类型需要查询库区信息获取所属仓库ID
if (formData.value.type === BarcodeBizTypeEnum.LOCATION) {
const location = await WmWarehouseLocationApi.getWarehouseLocation(formData.value.valueId)
if (location?.warehouseId) {
locationWarehouseId.value = location.warehouseId
}
}
// 库位类型需要查询库位信息获取所属仓库ID和库区ID
else if (formData.value.type === BarcodeBizTypeEnum.AREA) {
const area = await WmWarehouseAreaApi.getWarehouseArea(formData.value.valueId)
if (area?.warehouseId) {
areaWarehouseId.value = area.warehouseId
}
if (area?.locationId) {
areaLocationId.value = area.locationId
}
}
} catch (error) {
console.error('加载级联数据失败:', error)
}
}
/** 监听 planId 变化 */
watch(
() => props.planId,
async (value) => {
resetForm()
if (!value) {
queryParams.planId = undefined
queryParams.pageNo = 1
list.value = []
total.value = 0
return
}
queryParams.pageNo = 1
await getList()
},
{ immediate: true }
)
</script>