| | |
| | | import type { FormType } from '../data'; |
| | | |
| | | import type { MesProRouteApi } from '#/api/mes/pro/route'; |
| | | import type { MesProRouteProductApi } from '#/api/mes/pro/route/product'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | import { confirm, useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message, TabPane, Tabs } from 'ant-design-vue'; |
| | | import { Button, Divider, message, Select } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { createRoute, getRoute, updateRoute } from '#/api/mes/pro/route'; |
| | | import { |
| | | deleteRouteProduct, |
| | | getRouteProductListByRoute, |
| | | } from '#/api/mes/pro/route/product'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | import ProcessList from './process-list.vue'; |
| | | import ProductList from './product-list.vue'; |
| | | import ProductForm from './product-form.vue'; |
| | | import Workbench from './workbench.vue'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formType = ref<FormType>('create'); // 表单模式 |
| | | const subTab = ref('process'); // 当前激活的子表 Tab |
| | | const formData = ref<MesProRouteApi.Route>(); |
| | | |
| | | const isDetail = computed(() => formType.value === 'detail'); // 是否查看模式 |
| | |
| | | : $t('ui.actionTitle.create', ['工艺路线']); |
| | | }); |
| | | |
| | | // ==================== 产品绑定 ==================== |
| | | const products = ref<MesProRouteProductApi.RouteProduct[]>([]); // 关联产品列表 |
| | | const selectedProductItemId = ref<number>(); // 当前选中的产品物料编号 |
| | | const selectedProduct = computed(() => |
| | | products.value.find((item) => item.itemId === selectedProductItemId.value), |
| | | ); |
| | | const productOptions = computed(() => |
| | | products.value.map((item) => ({ label: item.itemName, value: item.itemId })), |
| | | ); |
| | | |
| | | async function loadProducts() { |
| | | const routeId = formData.value?.id; |
| | | if (!routeId) { |
| | | products.value = []; |
| | | return; |
| | | } |
| | | products.value = (await getRouteProductListByRoute(routeId)) || []; |
| | | if ( |
| | | !products.value.some((item) => item.itemId === selectedProductItemId.value) |
| | | ) { |
| | | selectedProductItemId.value = products.value[0]?.itemId; |
| | | } |
| | | } |
| | | |
| | | const [ProductFormModal, productFormModalApi] = useVbenModal({ |
| | | connectedComponent: ProductForm, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** 打开产品弹窗(绑定 / 编辑) */ |
| | | function openProductForm(row?: MesProRouteProductApi.RouteProduct) { |
| | | if (!formData.value?.id) { |
| | | return; |
| | | } |
| | | productFormModalApi |
| | | .setData( |
| | | row |
| | | ? { id: row.id, routeId: formData.value.id } |
| | | : { |
| | | routeId: formData.value.id, |
| | | boundItemIds: products.value |
| | | .map((item) => item.itemId) |
| | | .filter((id): id is number => id != null), |
| | | }, |
| | | ) |
| | | .open(); |
| | | } |
| | | |
| | | /** 移除产品(会级联删除该产品的投入物料配置) */ |
| | | async function handleRemoveProduct() { |
| | | if (!selectedProduct.value?.id) { |
| | | return; |
| | | } |
| | | try { |
| | | await confirm( |
| | | `确认将产品「${selectedProduct.value.itemName}」从该工艺路线移除?其全部投入物料配置将一并删除。`, |
| | | ); |
| | | } catch { |
| | | return; |
| | | } |
| | | await deleteRouteProduct(selectedProduct.value.id); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | await loadProducts(); |
| | | } |
| | | |
| | | // ==================== 基本信息表单 ==================== |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { class: 'w-full' }, |
| | |
| | | const data = (await formApi.getValues()) as MesProRouteApi.Route; |
| | | try { |
| | | if (formType.value === 'create') { |
| | | // 新增成功后切到编辑模式,方便继续维护组成工序、关联产品 |
| | | // 新增成功后切到编辑模式,进入「产品与工序配置」工作台 |
| | | const id = await createRoute(data); |
| | | formData.value = { ...data, id }; |
| | | await formApi.setFieldValue('id', id); |
| | | formType.value = 'update'; |
| | | await loadProducts(); |
| | | } else { |
| | | await updateRoute(data); |
| | | formData.value = { ...formData.value, ...data }; |
| | |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | products.value = []; |
| | | selectedProductItemId.value = undefined; |
| | | return; |
| | | } |
| | | formApi.setState({ schema: useFormSchema(formApi) }); |
| | | subTab.value = 'process'; |
| | | // 加载数据 |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | |
| | | formData.value = await getRoute(data.id); |
| | | // 设置到 values |
| | | await formApi.setValues(formData.value); |
| | | await loadProducts(); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-4/5"> |
| | | <Modal :title="getTitle" class="w-11/12"> |
| | | <Form class="mx-4" /> |
| | | <!-- 编辑/详情模式下展示子表 Tab,新增模式下隐藏 --> |
| | | <Tabs |
| | | v-if="formType !== 'create' && formData?.id" |
| | | v-model:active-key="subTab" |
| | | class="mx-4 mt-4" |
| | | > |
| | | <TabPane key="process" tab="组成工序"> |
| | | <ProcessList :form-type="formType" :route-id="formData.id" /> |
| | | </TabPane> |
| | | <TabPane key="product" tab="关联产品"> |
| | | <ProductList :form-type="formType" :route-id="formData.id" /> |
| | | </TabPane> |
| | | </Tabs> |
| | | <!-- 编辑/详情模式下展示「产品与工序配置」工作台,新增模式下隐藏 --> |
| | | <template v-if="formData?.id"> |
| | | <div class="mx-4 mt-4"> |
| | | <Divider class="!my-2" orientation="left"> |
| | | <span class="text-sm">产品与工序配置</span> |
| | | </Divider> |
| | | <div class="flex flex-wrap items-center gap-3"> |
| | | <span class="shrink-0 text-sm font-medium">生产产品</span> |
| | | <Select |
| | | v-model:value="selectedProductItemId" |
| | | class="!w-64" |
| | | allow-clear |
| | | :disabled="isDetail" |
| | | placeholder="请选择或绑定产品" |
| | | :options="productOptions" |
| | | /> |
| | | <template v-if="!isDetail"> |
| | | <Button type="primary" @click="openProductForm()"> 绑定产品 </Button> |
| | | <Button |
| | | :disabled="!selectedProduct" |
| | | @click="openProductForm(selectedProduct)" |
| | | > |
| | | 编辑产品 |
| | | </Button> |
| | | <Button danger :disabled="!selectedProduct" @click="handleRemoveProduct"> |
| | | 移除产品 |
| | | </Button> |
| | | </template> |
| | | </div> |
| | | <p v-if="products.length === 0" class="mt-2 text-xs text-gray-400"> |
| | | 先绑定要生产的物料,再为每道工序配置「投入 + 产出」 |
| | | </p> |
| | | <div class="mt-3"> |
| | | <Workbench |
| | | :form-type="formType" |
| | | :product="selectedProduct" |
| | | :route-id="formData.id" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </Modal> |
| | | </template> |
| | | <ProductFormModal @success="loadProducts" /> |
| | | </template> |