refactor(mes): stocktaking/plan 盘点条件表单 schema 化(R034)
将盘点方案条件弹窗从手写 <Form> 模板重构为 useVbenForm + schema,提升 antd/ele 复用度,对齐 Vben5「schema 放 data.ts」约定。 - 新增 condition-value-input.vue(antd/ele 各一份):把「条件值」的 7 选 1 (仓库/库区/库位级联、物料、批次、质量状态)+ 级联临时态 + valueCode/ valueName 回写封装为单一 v-model 组件,经 valueChange 事件回填,避免 schema 出现重复 fieldName 的渲染层风险。归 components/,与 pro/route 的 RouteColorPicker 等同类自定义控件保持一致。 - useParamFormSchema 合并进同目录 data.ts,删除临时 param-data.ts; param-form.vue 改为 useVbenForm + setState(schema),onConfirm/onOpenChange 结构与注释(// 提交表单、// 关闭并提示、// 加载数据、// 设置到 values) 对齐 dv/subject 范式。 - 字典 options 用 getDictOptions(..., 'number') + NumberDictDataType 断言, 移除冗余 .map() 转换。 - defineProps/defineEmits 内去掉非 vben 风格的 JSDoc 注释;去掉无谓的 ParamTypeEnum alias,直接使用 MesWmStockTakingParamTypeEnum。 - 质量状态无实体 id,提交校验按 type 区分 valueCode / valueId。 验证: - pnpm exec eslint <stocktaking/plan 改动文件>(antd + ele)通过 - pnpm -F @vben/web-antd / @vben/web-ele exec vue-tsc 过滤 stocktaking/plan 无报错 Ref: project_duibiao/mes/review_vben/INDEX.md (MES-R034)pull/351/MERGE
parent
7e62f9a5ef
commit
1edaf023c2
|
|
@ -0,0 +1,204 @@
|
|||
<script lang="ts" setup>
|
||||
import type { NumberDictDataType } from '@vben/hooks';
|
||||
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import { DICT_TYPE, MesWmStockTakingParamTypeEnum } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
import { Select } from 'ant-design-vue';
|
||||
|
||||
import { getWarehouseArea } from '#/api/mes/wm/warehouse/area';
|
||||
import { getWarehouseLocation } from '#/api/mes/wm/warehouse/location';
|
||||
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||
import { WmBatchSelect } from '#/views/mes/wm/batch/components';
|
||||
import {
|
||||
WmWarehouseAreaSelect,
|
||||
WmWarehouseLocationSelect,
|
||||
WmWarehouseSelect,
|
||||
} from '#/views/mes/wm/warehouse/components';
|
||||
|
||||
defineOptions({ name: 'StockTakingPlanConditionValueInput' });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue?: number;
|
||||
type?: number;
|
||||
valueCode?: string;
|
||||
}>(),
|
||||
{
|
||||
modelValue: undefined,
|
||||
type: undefined,
|
||||
valueCode: undefined,
|
||||
},
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value?: number];
|
||||
valueChange: [
|
||||
payload: { valueCode?: string; valueId?: number; valueName?: string },
|
||||
];
|
||||
}>();
|
||||
|
||||
const qualityStatusOptions = getDictOptions(
|
||||
DICT_TYPE.MES_WM_QUALITY_STATUS,
|
||||
'number',
|
||||
) as NumberDictDataType[];
|
||||
|
||||
const locationWarehouseId = ref<number>(); // 库区选择器临时数据:选仓库后传给库区选择器
|
||||
const areaWarehouseId = ref<number>(); // 库位选择器临时数据:选仓库后传给库区选择器
|
||||
const areaLocationId = ref<number>(); // 库位选择器临时数据:选库区后传给库位选择器
|
||||
|
||||
const qualityStatusValue = ref<number>();
|
||||
|
||||
/** 通用选择器变化:回填条件值编码、名称 */
|
||||
function handleSelectorChange(item?: any) {
|
||||
emit('update:modelValue', item?.id);
|
||||
emit('valueChange', {
|
||||
valueId: item?.id,
|
||||
valueCode: item?.code || '',
|
||||
valueName: item?.name || item?.nickname || '',
|
||||
});
|
||||
}
|
||||
|
||||
/** 批次选择器变化 */
|
||||
function handleBatchChange(batch?: any) {
|
||||
emit('update:modelValue', batch?.id);
|
||||
emit('valueChange', {
|
||||
valueId: batch?.id,
|
||||
valueCode: batch?.code || '',
|
||||
valueName: batch?.code || '',
|
||||
});
|
||||
}
|
||||
|
||||
/** 质量状态选择器变化:无实体编号,仅记录字典编码和文案 */
|
||||
function handleQualityStatusChange(value?: number) {
|
||||
qualityStatusValue.value = value;
|
||||
const selected = qualityStatusOptions.find((item) => item.value === value);
|
||||
emit('update:modelValue', undefined);
|
||||
emit('valueChange', {
|
||||
valueId: undefined,
|
||||
valueCode: value == null ? '' : String(value),
|
||||
valueName: selected?.label || '',
|
||||
});
|
||||
}
|
||||
|
||||
/** 库区仓库选择回调:清空库区 */
|
||||
function handleLocationWarehouseChange() {
|
||||
emit('update:modelValue', undefined);
|
||||
emit('valueChange', { valueId: undefined, valueCode: '', valueName: '' });
|
||||
}
|
||||
|
||||
/** 库位仓库选择回调:清空库区和库位 */
|
||||
function handleAreaWarehouseChange() {
|
||||
areaLocationId.value = undefined;
|
||||
emit('update:modelValue', undefined);
|
||||
emit('valueChange', { valueId: undefined, valueCode: '', valueName: '' });
|
||||
}
|
||||
|
||||
/** 库位库区选择回调:清空库位 */
|
||||
function handleAreaLocationChange() {
|
||||
emit('update:modelValue', undefined);
|
||||
emit('valueChange', { valueId: undefined, valueCode: '', valueName: '' });
|
||||
}
|
||||
|
||||
/** 编辑时回填级联选择器的上级数据(库区所属仓库、库位所属仓库/库区) */
|
||||
async function loadCascadeData() {
|
||||
if (props.type === MesWmStockTakingParamTypeEnum.QUALITY_STATUS) {
|
||||
qualityStatusValue.value = props.valueCode
|
||||
? Number(props.valueCode)
|
||||
: undefined;
|
||||
return;
|
||||
}
|
||||
if (props.modelValue == null) {
|
||||
return;
|
||||
}
|
||||
if (props.type === MesWmStockTakingParamTypeEnum.LOCATION) {
|
||||
const location = await getWarehouseLocation(props.modelValue);
|
||||
locationWarehouseId.value = location?.warehouseId;
|
||||
} else if (props.type === MesWmStockTakingParamTypeEnum.AREA) {
|
||||
const area = await getWarehouseArea(props.modelValue);
|
||||
areaWarehouseId.value = area?.warehouseId;
|
||||
areaLocationId.value = area?.locationId;
|
||||
}
|
||||
}
|
||||
|
||||
// 条件类型变化时重置级联临时数据;编辑回显时按类型加载上级数据
|
||||
watch(
|
||||
() => props.type,
|
||||
() => {
|
||||
locationWarehouseId.value = undefined;
|
||||
areaWarehouseId.value = undefined;
|
||||
areaLocationId.value = undefined;
|
||||
qualityStatusValue.value = undefined;
|
||||
void loadCascadeData();
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WmWarehouseSelect
|
||||
v-if="type === MesWmStockTakingParamTypeEnum.WAREHOUSE"
|
||||
:model-value="modelValue"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
<div
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.LOCATION"
|
||||
class="space-y-2"
|
||||
>
|
||||
<WmWarehouseSelect
|
||||
v-model="locationWarehouseId"
|
||||
placeholder="请选择仓库"
|
||||
@change="handleLocationWarehouseChange"
|
||||
/>
|
||||
<WmWarehouseLocationSelect
|
||||
v-if="locationWarehouseId"
|
||||
:model-value="modelValue"
|
||||
:warehouse-id="locationWarehouseId"
|
||||
placeholder="请选择库区"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.AREA"
|
||||
class="space-y-2"
|
||||
>
|
||||
<WmWarehouseSelect
|
||||
v-model="areaWarehouseId"
|
||||
placeholder="请选择仓库"
|
||||
@change="handleAreaWarehouseChange"
|
||||
/>
|
||||
<WmWarehouseLocationSelect
|
||||
v-if="areaWarehouseId"
|
||||
v-model="areaLocationId"
|
||||
placeholder="请选择库区"
|
||||
:warehouse-id="areaWarehouseId"
|
||||
@change="handleAreaLocationChange"
|
||||
/>
|
||||
<WmWarehouseAreaSelect
|
||||
v-if="areaLocationId"
|
||||
:model-value="modelValue"
|
||||
:location-id="areaLocationId"
|
||||
placeholder="请选择库位"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
</div>
|
||||
<MdItemSelect
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.ITEM"
|
||||
:model-value="modelValue"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
<WmBatchSelect
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.BATCH"
|
||||
:model-value="modelValue"
|
||||
@change="handleBatchChange"
|
||||
/>
|
||||
<Select
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.QUALITY_STATUS"
|
||||
:options="qualityStatusOptions"
|
||||
:value="qualityStatusValue"
|
||||
placeholder="请选择质量状态"
|
||||
class="w-full"
|
||||
@change="(value) => handleQualityStatusChange(value as number)"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
export { default as StockTakingPlanConditionValueInput } from './condition-value-input.vue';
|
||||
export { default as StockTakingPlanSelectDialog } from './select-dialog.vue';
|
||||
export { default as StockTakingPlanSelect } from './select.vue';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import type { NumberDictDataType } from '@vben/hooks';
|
||||
|
||||
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesWmStockTakingPlanApi } from '#/api/mes/wm/stocktaking/plan';
|
||||
import type { MesWmStockTakingPlanParamApi } from '#/api/mes/wm/stocktaking/plan/param';
|
||||
|
||||
import { h } from 'vue';
|
||||
import { h, markRaw } from 'vue';
|
||||
|
||||
import {
|
||||
CommonStatusEnum,
|
||||
|
|
@ -18,6 +20,8 @@ import { Button } from 'ant-design-vue';
|
|||
import { z } from '#/adapter/form';
|
||||
import { generateAutoCode } from '#/api/mes/md/autocode/record';
|
||||
|
||||
import { StockTakingPlanConditionValueInput } from './components';
|
||||
|
||||
/** 表单类型 */
|
||||
export type FormType = 'create' | 'detail' | 'update';
|
||||
|
||||
|
|
@ -292,6 +296,86 @@ export function useParamGridColumns(
|
|||
];
|
||||
}
|
||||
|
||||
/** 盘点方案条件表单 schema */
|
||||
export function useParamFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'type',
|
||||
label: '条件类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: getDictOptions(
|
||||
DICT_TYPE.MES_WM_STOCK_TAKING_PLAN_PARAM_TYPE,
|
||||
'number',
|
||||
) as NumberDictDataType[],
|
||||
placeholder: '请选择条件类型',
|
||||
// 条件类型变化:清空已选条件值,避免残留旧类型的条件值
|
||||
onChange: async () => {
|
||||
await formApi?.setValues({
|
||||
valueCode: '',
|
||||
valueId: undefined,
|
||||
valueName: '',
|
||||
});
|
||||
},
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
fieldName: 'valueId',
|
||||
label: '条件值',
|
||||
component: markRaw(StockTakingPlanConditionValueInput),
|
||||
// 条件值控件内部按条件类型切换选择器,仅选择类型后展示
|
||||
dependencies: {
|
||||
triggerFields: ['type'],
|
||||
if: (values) => values.type != null,
|
||||
componentProps: (values) => ({
|
||||
type: values.type,
|
||||
valueCode: values.valueCode,
|
||||
// 条件值控件回填 valueId / valueCode / valueName
|
||||
onValueChange: async (payload: {
|
||||
valueCode?: string;
|
||||
valueId?: number;
|
||||
valueName?: string;
|
||||
}) => {
|
||||
await formApi?.setValues({
|
||||
valueCode: payload.valueCode ?? '',
|
||||
valueId: payload.valueId,
|
||||
valueName: payload.valueName ?? '',
|
||||
});
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
// 条件值编码:由条件值控件回写,隐藏字段
|
||||
fieldName: 'valueCode',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
// 条件值名称:由条件值控件回写,隐藏字段
|
||||
fieldName: 'valueName',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Textarea',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 选择弹窗的搜索表单 */
|
||||
export function useSelectGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -4,144 +4,68 @@ import type { MesWmStockTakingPlanParamApi } from '#/api/mes/wm/stocktaking/plan
|
|||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { DICT_TYPE, MesWmStockTakingParamTypeEnum } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
import { MesWmStockTakingParamTypeEnum } from '@vben/constants';
|
||||
|
||||
import { Form, message, Select, Textarea } from 'ant-design-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import {
|
||||
createStockTakingPlanParam,
|
||||
getStockTakingPlanParam,
|
||||
updateStockTakingPlanParam,
|
||||
} from '#/api/mes/wm/stocktaking/plan/param';
|
||||
import { getWarehouseArea } from '#/api/mes/wm/warehouse/area';
|
||||
import { getWarehouseLocation } from '#/api/mes/wm/warehouse/location';
|
||||
import { $t } from '#/locales';
|
||||
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||
import { WmBatchSelect } from '#/views/mes/wm/batch/components';
|
||||
import {
|
||||
WmWarehouseAreaSelect,
|
||||
WmWarehouseLocationSelect,
|
||||
WmWarehouseSelect,
|
||||
} from '#/views/mes/wm/warehouse/components';
|
||||
|
||||
import { useParamFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const formData = ref<MesWmStockTakingPlanParamApi.StockTakingPlanParam>({});
|
||||
const planId = ref<number>(); // TODO @AI:这里是不是要尾注释
|
||||
const locationWarehouseId = ref<number>(); // 库区选择器临时数据:选仓库后传给库区选择器
|
||||
const areaWarehouseId = ref<number>(); // 库位选择器临时数据:选仓库后传给库区选择器
|
||||
const areaLocationId = ref<number>(); // 库位选择器临时数据:选库区后传给库位选择器
|
||||
const formId = ref<number>(); // 当前编辑的条件编号
|
||||
const planId = ref<number>(); // 所属盘点方案编号
|
||||
|
||||
// TODO @AI:按照项目的风格,不要 mapping;直接界面那处理掉;简化逻辑;
|
||||
const paramTypeOptions = getDictOptions(
|
||||
DICT_TYPE.MES_WM_STOCK_TAKING_PLAN_PARAM_TYPE,
|
||||
'number',
|
||||
).map(({ label, value }) => ({ label, value: Number(value) }));
|
||||
const qualityStatusOptions = getDictOptions(
|
||||
DICT_TYPE.MES_WM_QUALITY_STATUS,
|
||||
'string',
|
||||
).map(({ label, value }) => ({ label, value: String(value) }));
|
||||
|
||||
// TODO @AI:如果 title 和前面的 const 也是变量,不用空行;
|
||||
const getTitle = computed(() =>
|
||||
formData.value?.id
|
||||
formId.value
|
||||
? $t('ui.actionTitle.edit', ['盘点条件'])
|
||||
: $t('ui.actionTitle.create', ['盘点条件']),
|
||||
);
|
||||
|
||||
/** 条件类型变化:清空已选条件值和级联临时数据 */
|
||||
function handleTypeChange() {
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = '';
|
||||
formData.value.valueName = '';
|
||||
locationWarehouseId.value = undefined;
|
||||
areaWarehouseId.value = undefined;
|
||||
areaLocationId.value = undefined;
|
||||
}
|
||||
|
||||
/** 通用选择器变化:回填条件值编码、名称 */
|
||||
function handleSelectorChange(item?: any) {
|
||||
formData.value.valueId = item?.id;
|
||||
formData.value.valueCode = item?.code || '';
|
||||
formData.value.valueName = item?.name || item?.nickname || '';
|
||||
}
|
||||
|
||||
/** 批次选择器变化 */
|
||||
function handleBatchChange(batch?: any) {
|
||||
formData.value.valueId = batch?.id;
|
||||
formData.value.valueCode = batch?.code || '';
|
||||
formData.value.valueName = batch?.code || '';
|
||||
}
|
||||
|
||||
/** 质量状态选择器变化:无实体编号,仅记录字典编码和文案 */
|
||||
function handleQualityStatusChange(value: any) {
|
||||
const selected = qualityStatusOptions.find((item) => item.value === value);
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = value;
|
||||
formData.value.valueName = selected?.label || '';
|
||||
}
|
||||
|
||||
/** 库区仓库选择回调:清空库区 */
|
||||
function handleLocationWarehouseChange() {
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = '';
|
||||
formData.value.valueName = '';
|
||||
}
|
||||
|
||||
/** 库位仓库选择回调:清空库区和库位 */
|
||||
function handleAreaWarehouseChange() {
|
||||
areaLocationId.value = undefined;
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = '';
|
||||
formData.value.valueName = '';
|
||||
}
|
||||
|
||||
/** 库位库区选择回调:清空库位 */
|
||||
function handleAreaLocationChange() {
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = '';
|
||||
formData.value.valueName = '';
|
||||
}
|
||||
|
||||
/** 编辑时回填级联选择器的上级数据(库区所属仓库、库位所属仓库/库区) */
|
||||
async function loadCascadeData() {
|
||||
if (!formData.value.type || !formData.value.valueId) {
|
||||
return;
|
||||
}
|
||||
const valueId = formData.value.valueId;
|
||||
if (formData.value.type === MesWmStockTakingParamTypeEnum.LOCATION) {
|
||||
const location = await getWarehouseLocation(valueId);
|
||||
locationWarehouseId.value = location?.warehouseId;
|
||||
} else if (formData.value.type === MesWmStockTakingParamTypeEnum.AREA) {
|
||||
const area = await getWarehouseArea(valueId);
|
||||
areaWarehouseId.value = area?.warehouseId;
|
||||
areaLocationId.value = area?.locationId;
|
||||
}
|
||||
}
|
||||
const [Form, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: [],
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-1',
|
||||
});
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
if (!formData.value.type) {
|
||||
message.warning('请选择条件类型');
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
const values =
|
||||
(await formApi.getValues()) as MesWmStockTakingPlanParamApi.StockTakingPlanParam;
|
||||
// 质量状态校验 valueCode,其余类型校验 valueId
|
||||
const valid =
|
||||
formData.value.type === MesWmStockTakingParamTypeEnum.QUALITY_STATUS
|
||||
? !!formData.value.valueCode
|
||||
: formData.value.valueId != null;
|
||||
if (!valid) {
|
||||
const valueValid =
|
||||
values.type === MesWmStockTakingParamTypeEnum.QUALITY_STATUS
|
||||
? !!values.valueCode
|
||||
: values.valueId != null;
|
||||
if (!valueValid) {
|
||||
message.warning('请选择条件值');
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
// 提交表单
|
||||
const data = {
|
||||
...formData.value,
|
||||
...values,
|
||||
id: formId.value,
|
||||
planId: planId.value,
|
||||
} as MesWmStockTakingPlanParamApi.StockTakingPlanParam;
|
||||
try {
|
||||
await (formData.value.id
|
||||
await (formId.value
|
||||
? updateStockTakingPlanParam(data)
|
||||
: createStockTakingPlanParam(data));
|
||||
// 关闭并提示
|
||||
|
|
@ -154,113 +78,31 @@ const [Modal, modalApi] = useVbenModal({
|
|||
},
|
||||
async onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
formData.value = {};
|
||||
locationWarehouseId.value = undefined;
|
||||
areaWarehouseId.value = undefined;
|
||||
areaLocationId.value = undefined;
|
||||
formId.value = undefined;
|
||||
return;
|
||||
}
|
||||
formApi.setState({ schema: useParamFormSchema(formApi) });
|
||||
// 加载数据
|
||||
const data = modalApi.getData<{ id?: number; planId: number }>();
|
||||
planId.value = data.planId;
|
||||
formId.value = data.id;
|
||||
if (!data.id) {
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
try {
|
||||
formData.value = await getStockTakingPlanParam(data.id);
|
||||
await loadCascadeData();
|
||||
const param = await getStockTakingPlanParam(data.id);
|
||||
// 设置到 values
|
||||
await formApi.setValues(param);
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const ParamTypeEnum = MesWmStockTakingParamTypeEnum;
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal :title="getTitle" class="w-3/5">
|
||||
<Form class="mx-4" :label-col="{ span: 4 }">
|
||||
<!-- TODO @AI:可以更加 form schema 么???更好的 antd 和 ele 的复用; -->
|
||||
<Form.Item label="条件类型" required>
|
||||
<Select
|
||||
v-model:value="formData.type"
|
||||
:options="paramTypeOptions"
|
||||
placeholder="请选择条件类型"
|
||||
@change="handleTypeChange"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item v-if="formData.type" label="条件值" required>
|
||||
<WmWarehouseSelect
|
||||
v-if="formData.type === ParamTypeEnum.WAREHOUSE"
|
||||
v-model="formData.valueId"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
<div
|
||||
v-else-if="formData.type === ParamTypeEnum.LOCATION"
|
||||
class="space-y-2"
|
||||
>
|
||||
<WmWarehouseSelect
|
||||
v-model="locationWarehouseId"
|
||||
placeholder="请选择仓库"
|
||||
@change="handleLocationWarehouseChange"
|
||||
/>
|
||||
<WmWarehouseLocationSelect
|
||||
v-if="locationWarehouseId"
|
||||
v-model="formData.valueId"
|
||||
placeholder="请选择库区"
|
||||
:warehouse-id="locationWarehouseId"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="formData.type === ParamTypeEnum.AREA" class="space-y-2">
|
||||
<WmWarehouseSelect
|
||||
v-model="areaWarehouseId"
|
||||
placeholder="请选择仓库"
|
||||
@change="handleAreaWarehouseChange"
|
||||
/>
|
||||
<WmWarehouseLocationSelect
|
||||
v-if="areaWarehouseId"
|
||||
v-model="areaLocationId"
|
||||
placeholder="请选择库区"
|
||||
:warehouse-id="areaWarehouseId"
|
||||
@change="handleAreaLocationChange"
|
||||
/>
|
||||
<WmWarehouseAreaSelect
|
||||
v-if="areaLocationId"
|
||||
v-model="formData.valueId"
|
||||
:location-id="areaLocationId"
|
||||
placeholder="请选择库位"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
</div>
|
||||
<MdItemSelect
|
||||
v-else-if="formData.type === ParamTypeEnum.ITEM"
|
||||
v-model="formData.valueId"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
<WmBatchSelect
|
||||
v-else-if="formData.type === ParamTypeEnum.BATCH"
|
||||
v-model="formData.valueId"
|
||||
@change="handleBatchChange"
|
||||
/>
|
||||
<Select
|
||||
v-else-if="formData.type === ParamTypeEnum.QUALITY_STATUS"
|
||||
v-model:value="formData.valueCode"
|
||||
:options="qualityStatusOptions"
|
||||
placeholder="请选择质量状态"
|
||||
@change="handleQualityStatusChange"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="备注">
|
||||
<Textarea
|
||||
v-model:value="formData.remark"
|
||||
placeholder="请输入备注"
|
||||
:rows="3"
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
<Form class="mx-4" />
|
||||
</Modal>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,372 @@
|
|||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesWmBatchApi } from '#/api/mes/wm/batch';
|
||||
import type { DescriptionItemSchema } from '#/components/description';
|
||||
|
||||
import { h, markRaw } from 'vue';
|
||||
|
||||
import { DICT_TYPE } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
import { formatDate } from '@vben/utils';
|
||||
|
||||
import { DictTag } from '#/components/dict-tag';
|
||||
import { getRangePickerDefaultProps } from '#/utils';
|
||||
import { MdClientSelect } from '#/views/mes/md/client/components';
|
||||
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||
import { MdVendorSelect } from '#/views/mes/md/vendor/components';
|
||||
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
|
||||
import { ProTaskSelect } from '#/views/mes/pro/task/components';
|
||||
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
||||
import { TmToolSelect } from '#/views/mes/tm/tool/components';
|
||||
|
||||
/** 批次选择弹窗的搜索表单 */
|
||||
export function useBatchSelectGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '批次编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入批次编号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'itemId',
|
||||
label: '产品物料',
|
||||
component: markRaw(MdItemSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择产品物料',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'vendorId',
|
||||
label: '供应商',
|
||||
component: markRaw(MdVendorSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择供应商',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'clientId',
|
||||
label: '客户',
|
||||
component: markRaw(MdClientSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择客户',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'workOrderId',
|
||||
label: '生产工单',
|
||||
component: markRaw(ProWorkOrderSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择生产工单',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'workstationId',
|
||||
label: '工作站',
|
||||
component: markRaw(MdWorkstationSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择工作站',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'taskId',
|
||||
label: '生产任务',
|
||||
component: markRaw(ProTaskSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择生产任务',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'toolId',
|
||||
label: '工具',
|
||||
component: markRaw(TmToolSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择工具',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'moldId',
|
||||
label: '模具编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入模具编号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'salesOrderCode',
|
||||
label: '销售订单编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入销售订单编号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'purchaseOrderCode',
|
||||
label: '采购订单编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入采购订单编号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'lotNumber',
|
||||
label: '生产批号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入生产批号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'qualityStatus',
|
||||
label: '质量状态',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
options: getDictOptions(DICT_TYPE.MES_WM_QUALITY_STATUS, 'number'),
|
||||
placeholder: '请选择质量状态',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'produceDate',
|
||||
label: '生产日期',
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
...getRangePickerDefaultProps(),
|
||||
clearable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'expireDate',
|
||||
label: '有效期',
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
...getRangePickerDefaultProps(),
|
||||
clearable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'receiptDate',
|
||||
label: '入库日期',
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
...getRangePickerDefaultProps(),
|
||||
clearable: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 批次选择弹窗的字段 */
|
||||
export function useBatchSelectGridColumns(
|
||||
multiple = false,
|
||||
): VxeTableGridOptions<MesWmBatchApi.Batch>['columns'] {
|
||||
return [
|
||||
{
|
||||
type: multiple ? 'checkbox' : 'radio',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
field: 'code',
|
||||
title: '批次编号',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
field: 'itemCode',
|
||||
title: '物料编码',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
field: 'itemName',
|
||||
title: '物料名称',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
field: 'itemSpecification',
|
||||
title: '规格型号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'unitName',
|
||||
title: '单位',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
field: 'vendorCode',
|
||||
title: '供应商编码',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'vendorName',
|
||||
title: '供应商名称',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'clientCode',
|
||||
title: '客户编码',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
field: 'clientName',
|
||||
title: '客户名称',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
field: 'salesOrderCode',
|
||||
title: '销售订单编号',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'purchaseOrderCode',
|
||||
title: '采购订单编号',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'workOrderCode',
|
||||
title: '工单编码',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'workstationCode',
|
||||
title: '工作站编码',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'taskCode',
|
||||
title: '生产任务编号',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'toolCode',
|
||||
title: '工具编号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'lotNumber',
|
||||
title: '生产批号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'qualityStatus',
|
||||
title: '质量状态',
|
||||
width: 100,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS },
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'produceDate',
|
||||
title: '生产日期',
|
||||
width: 120,
|
||||
formatter: 'formatDate',
|
||||
},
|
||||
{
|
||||
field: 'expireDate',
|
||||
title: '有效期',
|
||||
width: 120,
|
||||
formatter: 'formatDate',
|
||||
},
|
||||
{
|
||||
field: 'receiptDate',
|
||||
title: '入库日期',
|
||||
width: 120,
|
||||
formatter: 'formatDate',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 批次详情的描述字段 */
|
||||
export function useDetailSchema(): DescriptionItemSchema[] {
|
||||
return [
|
||||
{
|
||||
field: 'code',
|
||||
label: '批次编号',
|
||||
},
|
||||
{
|
||||
field: 'itemCode',
|
||||
label: '物料编码',
|
||||
},
|
||||
{
|
||||
field: 'itemName',
|
||||
label: '物料名称',
|
||||
},
|
||||
{
|
||||
field: 'itemSpecification',
|
||||
label: '规格型号',
|
||||
},
|
||||
{
|
||||
field: 'unitName',
|
||||
label: '单位',
|
||||
},
|
||||
{
|
||||
field: 'lotNumber',
|
||||
label: '生产批号',
|
||||
},
|
||||
{
|
||||
field: 'produceDate',
|
||||
label: '生产日期',
|
||||
render: (value) => (value ? formatDate(value, 'YYYY-MM-DD') : '-'),
|
||||
},
|
||||
{
|
||||
field: 'expireDate',
|
||||
label: '有效期',
|
||||
render: (value) => (value ? formatDate(value, 'YYYY-MM-DD') : '-'),
|
||||
},
|
||||
{
|
||||
field: 'receiptDate',
|
||||
label: '入库日期',
|
||||
render: (value) => (value ? formatDate(value, 'YYYY-MM-DD') : '-'),
|
||||
},
|
||||
{
|
||||
field: 'vendorName',
|
||||
label: '供应商',
|
||||
render: (value) => value || '-',
|
||||
},
|
||||
{
|
||||
field: 'clientName',
|
||||
label: '客户',
|
||||
render: (value) => value || '-',
|
||||
},
|
||||
{
|
||||
field: 'workstationCode',
|
||||
label: '工作站',
|
||||
render: (value) => value || '-',
|
||||
},
|
||||
{
|
||||
field: 'purchaseOrderCode',
|
||||
label: '采购订单编号',
|
||||
render: (value) => value || '-',
|
||||
},
|
||||
{
|
||||
field: 'salesOrderCode',
|
||||
label: '销售订单编号',
|
||||
render: (value) => value || '-',
|
||||
},
|
||||
{
|
||||
field: 'workOrderCode',
|
||||
label: '生产工单',
|
||||
render: (value) => value || '-',
|
||||
},
|
||||
{
|
||||
field: 'qualityStatus',
|
||||
label: '质量状态',
|
||||
render: (value) =>
|
||||
value == null
|
||||
? '-'
|
||||
: h(DictTag, { type: DICT_TYPE.MES_WM_QUALITY_STATUS, value }),
|
||||
},
|
||||
{
|
||||
field: 'remark',
|
||||
label: '备注',
|
||||
span: 3,
|
||||
render: (value) => value || '-',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
<script lang="ts" setup>
|
||||
import type { NumberDictDataType } from '@vben/hooks';
|
||||
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import { DICT_TYPE, MesWmStockTakingParamTypeEnum } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
import { ElOption, ElSelect } from 'element-plus';
|
||||
|
||||
import { getWarehouseArea } from '#/api/mes/wm/warehouse/area';
|
||||
import { getWarehouseLocation } from '#/api/mes/wm/warehouse/location';
|
||||
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||
import { WmBatchSelect } from '#/views/mes/wm/batch/components';
|
||||
import {
|
||||
WmWarehouseAreaSelect,
|
||||
WmWarehouseLocationSelect,
|
||||
WmWarehouseSelect,
|
||||
} from '#/views/mes/wm/warehouse/components';
|
||||
|
||||
defineOptions({ name: 'StockTakingPlanConditionValueInput' });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue?: number;
|
||||
type?: number;
|
||||
valueCode?: string;
|
||||
}>(),
|
||||
{
|
||||
modelValue: undefined,
|
||||
type: undefined,
|
||||
valueCode: undefined,
|
||||
},
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value?: number];
|
||||
valueChange: [
|
||||
payload: { valueCode?: string; valueId?: number; valueName?: string },
|
||||
];
|
||||
}>();
|
||||
|
||||
const qualityStatusOptions = getDictOptions(
|
||||
DICT_TYPE.MES_WM_QUALITY_STATUS,
|
||||
'number',
|
||||
) as NumberDictDataType[];
|
||||
|
||||
const locationWarehouseId = ref<number>(); // 库区选择器临时数据:选仓库后传给库区选择器
|
||||
const areaWarehouseId = ref<number>(); // 库位选择器临时数据:选仓库后传给库区选择器
|
||||
const areaLocationId = ref<number>(); // 库位选择器临时数据:选库区后传给库位选择器
|
||||
|
||||
const qualityStatusValue = ref<number>();
|
||||
|
||||
/** 通用选择器变化:回填条件值编码、名称 */
|
||||
function handleSelectorChange(item?: any) {
|
||||
emit('update:modelValue', item?.id);
|
||||
emit('valueChange', {
|
||||
valueId: item?.id,
|
||||
valueCode: item?.code || '',
|
||||
valueName: item?.name || item?.nickname || '',
|
||||
});
|
||||
}
|
||||
|
||||
/** 批次选择器变化 */
|
||||
function handleBatchChange(batch?: any) {
|
||||
emit('update:modelValue', batch?.id);
|
||||
emit('valueChange', {
|
||||
valueId: batch?.id,
|
||||
valueCode: batch?.code || '',
|
||||
valueName: batch?.code || '',
|
||||
});
|
||||
}
|
||||
|
||||
/** 质量状态选择器变化:无实体编号,仅记录字典编码和文案 */
|
||||
function handleQualityStatusChange(value?: number) {
|
||||
qualityStatusValue.value = value;
|
||||
const selected = qualityStatusOptions.find((item) => item.value === value);
|
||||
emit('update:modelValue', undefined);
|
||||
emit('valueChange', {
|
||||
valueId: undefined,
|
||||
valueCode: value == null ? '' : String(value),
|
||||
valueName: selected?.label || '',
|
||||
});
|
||||
}
|
||||
|
||||
/** 库区仓库选择回调:清空库区 */
|
||||
function handleLocationWarehouseChange() {
|
||||
emit('update:modelValue', undefined);
|
||||
emit('valueChange', { valueId: undefined, valueCode: '', valueName: '' });
|
||||
}
|
||||
|
||||
/** 库位仓库选择回调:清空库区和库位 */
|
||||
function handleAreaWarehouseChange() {
|
||||
areaLocationId.value = undefined;
|
||||
emit('update:modelValue', undefined);
|
||||
emit('valueChange', { valueId: undefined, valueCode: '', valueName: '' });
|
||||
}
|
||||
|
||||
/** 库位库区选择回调:清空库位 */
|
||||
function handleAreaLocationChange() {
|
||||
emit('update:modelValue', undefined);
|
||||
emit('valueChange', { valueId: undefined, valueCode: '', valueName: '' });
|
||||
}
|
||||
|
||||
/** 编辑时回填级联选择器的上级数据(库区所属仓库、库位所属仓库/库区) */
|
||||
async function loadCascadeData() {
|
||||
if (props.type === MesWmStockTakingParamTypeEnum.QUALITY_STATUS) {
|
||||
qualityStatusValue.value = props.valueCode
|
||||
? Number(props.valueCode)
|
||||
: undefined;
|
||||
return;
|
||||
}
|
||||
if (props.modelValue == null) {
|
||||
return;
|
||||
}
|
||||
if (props.type === MesWmStockTakingParamTypeEnum.LOCATION) {
|
||||
const location = await getWarehouseLocation(props.modelValue);
|
||||
locationWarehouseId.value = location?.warehouseId;
|
||||
} else if (props.type === MesWmStockTakingParamTypeEnum.AREA) {
|
||||
const area = await getWarehouseArea(props.modelValue);
|
||||
areaWarehouseId.value = area?.warehouseId;
|
||||
areaLocationId.value = area?.locationId;
|
||||
}
|
||||
}
|
||||
|
||||
// 条件类型变化时重置级联临时数据;编辑回显时按类型加载上级数据
|
||||
watch(
|
||||
() => props.type,
|
||||
() => {
|
||||
locationWarehouseId.value = undefined;
|
||||
areaWarehouseId.value = undefined;
|
||||
areaLocationId.value = undefined;
|
||||
qualityStatusValue.value = undefined;
|
||||
void loadCascadeData();
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WmWarehouseSelect
|
||||
v-if="type === MesWmStockTakingParamTypeEnum.WAREHOUSE"
|
||||
:model-value="modelValue"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
<div
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.LOCATION"
|
||||
class="w-full space-y-2"
|
||||
>
|
||||
<WmWarehouseSelect
|
||||
v-model="locationWarehouseId"
|
||||
placeholder="请选择仓库"
|
||||
@change="handleLocationWarehouseChange"
|
||||
/>
|
||||
<WmWarehouseLocationSelect
|
||||
v-if="locationWarehouseId"
|
||||
:model-value="modelValue"
|
||||
:warehouse-id="locationWarehouseId"
|
||||
placeholder="请选择库区"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.AREA"
|
||||
class="w-full space-y-2"
|
||||
>
|
||||
<WmWarehouseSelect
|
||||
v-model="areaWarehouseId"
|
||||
placeholder="请选择仓库"
|
||||
@change="handleAreaWarehouseChange"
|
||||
/>
|
||||
<WmWarehouseLocationSelect
|
||||
v-if="areaWarehouseId"
|
||||
v-model="areaLocationId"
|
||||
placeholder="请选择库区"
|
||||
:warehouse-id="areaWarehouseId"
|
||||
@change="handleAreaLocationChange"
|
||||
/>
|
||||
<WmWarehouseAreaSelect
|
||||
v-if="areaLocationId"
|
||||
:model-value="modelValue"
|
||||
:location-id="areaLocationId"
|
||||
placeholder="请选择库位"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
</div>
|
||||
<MdItemSelect
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.ITEM"
|
||||
:model-value="modelValue"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
<WmBatchSelect
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.BATCH"
|
||||
:model-value="modelValue"
|
||||
@change="handleBatchChange"
|
||||
/>
|
||||
<ElSelect
|
||||
v-else-if="type === MesWmStockTakingParamTypeEnum.QUALITY_STATUS"
|
||||
:model-value="qualityStatusValue"
|
||||
class="!w-full"
|
||||
placeholder="请选择质量状态"
|
||||
@change="(value) => handleQualityStatusChange(value as number)"
|
||||
>
|
||||
<ElOption
|
||||
v-for="dict in qualityStatusOptions"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
export { default as StockTakingPlanConditionValueInput } from './condition-value-input.vue';
|
||||
export { default as StockTakingPlanSelectDialog } from './select-dialog.vue';
|
||||
export { default as StockTakingPlanSelect } from './select.vue';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import type { NumberDictDataType } from '@vben/hooks';
|
||||
|
||||
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesWmStockTakingPlanApi } from '#/api/mes/wm/stocktaking/plan';
|
||||
import type { MesWmStockTakingPlanParamApi } from '#/api/mes/wm/stocktaking/plan/param';
|
||||
|
||||
import { h } from 'vue';
|
||||
import { h, markRaw } from 'vue';
|
||||
|
||||
import {
|
||||
CommonStatusEnum,
|
||||
|
|
@ -18,6 +20,8 @@ import { ElButton } from 'element-plus';
|
|||
import { z } from '#/adapter/form';
|
||||
import { generateAutoCode } from '#/api/mes/md/autocode/record';
|
||||
|
||||
import { StockTakingPlanConditionValueInput } from './components';
|
||||
|
||||
/** 表单类型 */
|
||||
export type FormType = 'create' | 'detail' | 'update';
|
||||
|
||||
|
|
@ -293,6 +297,87 @@ export function useParamGridColumns(
|
|||
];
|
||||
}
|
||||
|
||||
/** 盘点方案条件表单 schema */
|
||||
export function useParamFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'type',
|
||||
label: '条件类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
options: getDictOptions(
|
||||
DICT_TYPE.MES_WM_STOCK_TAKING_PLAN_PARAM_TYPE,
|
||||
'number',
|
||||
) as NumberDictDataType[],
|
||||
placeholder: '请选择条件类型',
|
||||
// 条件类型变化:清空已选条件值,避免残留旧类型的条件值
|
||||
onChange: async () => {
|
||||
await formApi?.setValues({
|
||||
valueCode: '',
|
||||
valueId: undefined,
|
||||
valueName: '',
|
||||
});
|
||||
},
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
fieldName: 'valueId',
|
||||
label: '条件值',
|
||||
component: markRaw(StockTakingPlanConditionValueInput),
|
||||
// 条件值控件内部按条件类型切换选择器,仅选择类型后展示
|
||||
dependencies: {
|
||||
triggerFields: ['type'],
|
||||
if: (values) => values.type != null,
|
||||
componentProps: (values) => ({
|
||||
type: values.type,
|
||||
valueCode: values.valueCode,
|
||||
// 条件值控件回填 valueId / valueCode / valueName
|
||||
onValueChange: async (payload: {
|
||||
valueCode?: string;
|
||||
valueId?: number;
|
||||
valueName?: string;
|
||||
}) => {
|
||||
await formApi?.setValues({
|
||||
valueCode: payload.valueCode ?? '',
|
||||
valueId: payload.valueId,
|
||||
valueName: payload.valueName ?? '',
|
||||
});
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
// 条件值编码:由条件值控件回写,隐藏字段
|
||||
fieldName: 'valueCode',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
// 条件值名称:由条件值控件回写,隐藏字段
|
||||
fieldName: 'valueName',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Textarea',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 选择弹窗的搜索表单 */
|
||||
export function useSelectGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -4,149 +4,68 @@ import type { MesWmStockTakingPlanParamApi } from '#/api/mes/wm/stocktaking/plan
|
|||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { DICT_TYPE, MesWmStockTakingParamTypeEnum } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
import { MesWmStockTakingParamTypeEnum } from '@vben/constants';
|
||||
|
||||
import {
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElInput,
|
||||
ElMessage,
|
||||
ElOption,
|
||||
ElSelect,
|
||||
} from 'element-plus';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import {
|
||||
createStockTakingPlanParam,
|
||||
getStockTakingPlanParam,
|
||||
updateStockTakingPlanParam,
|
||||
} from '#/api/mes/wm/stocktaking/plan/param';
|
||||
import { getWarehouseArea } from '#/api/mes/wm/warehouse/area';
|
||||
import { getWarehouseLocation } from '#/api/mes/wm/warehouse/location';
|
||||
import { $t } from '#/locales';
|
||||
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||
import { WmBatchSelect } from '#/views/mes/wm/batch/components';
|
||||
import {
|
||||
WmWarehouseAreaSelect,
|
||||
WmWarehouseLocationSelect,
|
||||
WmWarehouseSelect,
|
||||
} from '#/views/mes/wm/warehouse/components';
|
||||
|
||||
import { useParamFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const formData = ref<MesWmStockTakingPlanParamApi.StockTakingPlanParam>({});
|
||||
const planId = ref<number>();
|
||||
const locationWarehouseId = ref<number>(); // 库区选择器临时数据:选仓库后传给库区选择器
|
||||
const areaWarehouseId = ref<number>(); // 库位选择器临时数据:选仓库后传给库区选择器
|
||||
const areaLocationId = ref<number>(); // 库位选择器临时数据:选库区后传给库位选择器
|
||||
|
||||
const paramTypeOptions = getDictOptions(
|
||||
DICT_TYPE.MES_WM_STOCK_TAKING_PLAN_PARAM_TYPE,
|
||||
'number',
|
||||
).map(({ label, value }) => ({ label, value: Number(value) }));
|
||||
const qualityStatusOptions = getDictOptions(
|
||||
DICT_TYPE.MES_WM_QUALITY_STATUS,
|
||||
'string',
|
||||
).map(({ label, value }) => ({ label, value: String(value) }));
|
||||
const formId = ref<number>(); // 当前编辑的条件编号
|
||||
const planId = ref<number>(); // 所属盘点方案编号
|
||||
|
||||
const getTitle = computed(() =>
|
||||
formData.value?.id
|
||||
formId.value
|
||||
? $t('ui.actionTitle.edit', ['盘点条件'])
|
||||
: $t('ui.actionTitle.create', ['盘点条件']),
|
||||
);
|
||||
|
||||
/** 条件类型变化:清空已选条件值和级联临时数据 */
|
||||
function handleTypeChange() {
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = '';
|
||||
formData.value.valueName = '';
|
||||
locationWarehouseId.value = undefined;
|
||||
areaWarehouseId.value = undefined;
|
||||
areaLocationId.value = undefined;
|
||||
}
|
||||
|
||||
/** 通用选择器变化:回填条件值编码、名称 */
|
||||
function handleSelectorChange(item?: any) {
|
||||
formData.value.valueId = item?.id;
|
||||
formData.value.valueCode = item?.code || '';
|
||||
formData.value.valueName = item?.name || item?.nickname || '';
|
||||
}
|
||||
|
||||
/** 批次选择器变化 */
|
||||
function handleBatchChange(batch?: any) {
|
||||
formData.value.valueId = batch?.id;
|
||||
formData.value.valueCode = batch?.code || '';
|
||||
formData.value.valueName = batch?.code || '';
|
||||
}
|
||||
|
||||
/** 质量状态选择器变化:无实体编号,仅记录字典编码和文案 */
|
||||
function handleQualityStatusChange(value: any) {
|
||||
const selected = qualityStatusOptions.find((item) => item.value === value);
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = value;
|
||||
formData.value.valueName = selected?.label || '';
|
||||
}
|
||||
|
||||
/** 库区仓库选择回调:清空库区 */
|
||||
function handleLocationWarehouseChange() {
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = '';
|
||||
formData.value.valueName = '';
|
||||
}
|
||||
|
||||
/** 库位仓库选择回调:清空库区和库位 */
|
||||
function handleAreaWarehouseChange() {
|
||||
areaLocationId.value = undefined;
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = '';
|
||||
formData.value.valueName = '';
|
||||
}
|
||||
|
||||
/** 库位库区选择回调:清空库位 */
|
||||
function handleAreaLocationChange() {
|
||||
formData.value.valueId = undefined;
|
||||
formData.value.valueCode = '';
|
||||
formData.value.valueName = '';
|
||||
}
|
||||
|
||||
/** 编辑时回填级联选择器的上级数据(库区所属仓库、库位所属仓库/库区) */
|
||||
async function loadCascadeData() {
|
||||
if (!formData.value.type || !formData.value.valueId) {
|
||||
return;
|
||||
}
|
||||
const valueId = formData.value.valueId;
|
||||
if (formData.value.type === MesWmStockTakingParamTypeEnum.LOCATION) {
|
||||
const location = await getWarehouseLocation(valueId);
|
||||
locationWarehouseId.value = location?.warehouseId;
|
||||
} else if (formData.value.type === MesWmStockTakingParamTypeEnum.AREA) {
|
||||
const area = await getWarehouseArea(valueId);
|
||||
areaWarehouseId.value = area?.warehouseId;
|
||||
areaLocationId.value = area?.locationId;
|
||||
}
|
||||
}
|
||||
const [Form, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: [],
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-1',
|
||||
});
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
if (!formData.value.type) {
|
||||
ElMessage.warning('请选择条件类型');
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
const values =
|
||||
(await formApi.getValues()) as MesWmStockTakingPlanParamApi.StockTakingPlanParam;
|
||||
// 质量状态校验 valueCode,其余类型校验 valueId
|
||||
const valid =
|
||||
formData.value.type === MesWmStockTakingParamTypeEnum.QUALITY_STATUS
|
||||
? !!formData.value.valueCode
|
||||
: formData.value.valueId != null;
|
||||
if (!valid) {
|
||||
const valueValid =
|
||||
values.type === MesWmStockTakingParamTypeEnum.QUALITY_STATUS
|
||||
? !!values.valueCode
|
||||
: values.valueId != null;
|
||||
if (!valueValid) {
|
||||
ElMessage.warning('请选择条件值');
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
// 提交表单
|
||||
const data = {
|
||||
...formData.value,
|
||||
...values,
|
||||
id: formId.value,
|
||||
planId: planId.value,
|
||||
} as MesWmStockTakingPlanParamApi.StockTakingPlanParam;
|
||||
try {
|
||||
await (formData.value.id
|
||||
await (formId.value
|
||||
? updateStockTakingPlanParam(data)
|
||||
: createStockTakingPlanParam(data));
|
||||
// 关闭并提示
|
||||
|
|
@ -159,129 +78,31 @@ const [Modal, modalApi] = useVbenModal({
|
|||
},
|
||||
async onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
formData.value = {};
|
||||
locationWarehouseId.value = undefined;
|
||||
areaWarehouseId.value = undefined;
|
||||
areaLocationId.value = undefined;
|
||||
formId.value = undefined;
|
||||
return;
|
||||
}
|
||||
formApi.setState({ schema: useParamFormSchema(formApi) });
|
||||
// 加载数据
|
||||
const data = modalApi.getData<{ id?: number; planId: number }>();
|
||||
planId.value = data.planId;
|
||||
formId.value = data.id;
|
||||
if (!data.id) {
|
||||
return;
|
||||
}
|
||||
modalApi.lock();
|
||||
try {
|
||||
formData.value = await getStockTakingPlanParam(data.id);
|
||||
await loadCascadeData();
|
||||
const param = await getStockTakingPlanParam(data.id);
|
||||
// 设置到 values
|
||||
await formApi.setValues(param);
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const ParamTypeEnum = MesWmStockTakingParamTypeEnum;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal :title="getTitle" class="w-3/5">
|
||||
<ElForm class="mx-4" label-width="100px">
|
||||
<ElFormItem label="条件类型" required>
|
||||
<ElSelect
|
||||
v-model="formData.type"
|
||||
class="!w-full"
|
||||
placeholder="请选择条件类型"
|
||||
@change="handleTypeChange"
|
||||
>
|
||||
<ElOption
|
||||
v-for="dict in paramTypeOptions"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="formData.type" label="条件值" required>
|
||||
<WmWarehouseSelect
|
||||
v-if="formData.type === ParamTypeEnum.WAREHOUSE"
|
||||
v-model="formData.valueId"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
<div
|
||||
v-else-if="formData.type === ParamTypeEnum.LOCATION"
|
||||
class="w-full space-y-2"
|
||||
>
|
||||
<WmWarehouseSelect
|
||||
v-model="locationWarehouseId"
|
||||
placeholder="请选择仓库"
|
||||
@change="handleLocationWarehouseChange"
|
||||
/>
|
||||
<WmWarehouseLocationSelect
|
||||
v-if="locationWarehouseId"
|
||||
v-model="formData.valueId"
|
||||
placeholder="请选择库区"
|
||||
:warehouse-id="locationWarehouseId"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="formData.type === ParamTypeEnum.AREA"
|
||||
class="w-full space-y-2"
|
||||
>
|
||||
<WmWarehouseSelect
|
||||
v-model="areaWarehouseId"
|
||||
placeholder="请选择仓库"
|
||||
@change="handleAreaWarehouseChange"
|
||||
/>
|
||||
<WmWarehouseLocationSelect
|
||||
v-if="areaWarehouseId"
|
||||
v-model="areaLocationId"
|
||||
placeholder="请选择库区"
|
||||
:warehouse-id="areaWarehouseId"
|
||||
@change="handleAreaLocationChange"
|
||||
/>
|
||||
<WmWarehouseAreaSelect
|
||||
v-if="areaLocationId"
|
||||
v-model="formData.valueId"
|
||||
:location-id="areaLocationId"
|
||||
placeholder="请选择库位"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
</div>
|
||||
<MdItemSelect
|
||||
v-else-if="formData.type === ParamTypeEnum.ITEM"
|
||||
v-model="formData.valueId"
|
||||
@change="handleSelectorChange"
|
||||
/>
|
||||
<WmBatchSelect
|
||||
v-else-if="formData.type === ParamTypeEnum.BATCH"
|
||||
v-model="formData.valueId"
|
||||
@change="handleBatchChange"
|
||||
/>
|
||||
<ElSelect
|
||||
v-else-if="formData.type === ParamTypeEnum.QUALITY_STATUS"
|
||||
v-model="formData.valueCode"
|
||||
class="!w-full"
|
||||
placeholder="请选择质量状态"
|
||||
@change="handleQualityStatusChange"
|
||||
>
|
||||
<ElOption
|
||||
v-for="dict in qualityStatusOptions"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="备注">
|
||||
<ElInput
|
||||
v-model="formData.remark"
|
||||
placeholder="请输入备注"
|
||||
:rows="3"
|
||||
type="textarea"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<Form class="mx-4" />
|
||||
</Modal>
|
||||
</template>
|
||||
|
|
|
|||
Loading…
Reference in New Issue