银川
1.销售订单生产状态不匹配,
2.采购订单中没有退货状态字段,筛选项有退货状态
3.采购申请添加查看订单、查看审批功能
4.物料管理与mes产品管理的联动逻辑修改
| | |
| | | productNames?: string; // 产品名称列表 |
| | | orderId?: number; // 生成的采购订单编号 |
| | | orderNo?: string; // 生成的采购订单号 |
| | | processInstanceId?: number; // 审批流程实例编号 |
| | | items?: PurchaseRequestItem[]; // 申请明细 |
| | | createTime?: string; // 创建时间 |
| | | } |
| | |
| | | createTime?: string; |
| | | // 同步相关字段 |
| | | syncMes?: boolean; |
| | | syncedMes?: boolean; // 是否已同步到 MES |
| | | // 批次属性配置字段 |
| | | produceDateFlag?: boolean; |
| | | expireDateFlag?: boolean; |
| | |
| | | colorCode?: string; // 甘特图显示颜色 |
| | | status?: number; // 任务状态 |
| | | checkFlag?: boolean; // 是否质检(派生自工艺路线工序) |
| | | backflushFlag?: boolean; // 是否倒冲(派生自工艺路线工序) |
| | | remark?: string; // 备注 |
| | | } |
| | | |
| | |
| | | const VueOfficeExcel = defineAsyncComponent(() => import('@vue-office/excel')); |
| | | const VueOfficePptx = defineAsyncComponent(() => import('@vue-office/pptx')); |
| | | |
| | | // @vue-office/excel 需要额外导入 CSS |
| | | import '@vue-office/excel/lib/v3/style.css'; |
| | | // @vue-office/excel CSS 通过 vite.config.ts 的 css.preprocessorOptions 注入 |
| | | |
| | | const props = withDefaults( |
| | | defineProps<{ |
| | |
| | | rules: z.boolean().default(false), |
| | | }, |
| | | { |
| | | component: "Switch", |
| | | fieldName: "syncMes", |
| | | label: "同步到 MES", |
| | | componentProps: { |
| | | class: "w-auto", |
| | | checkedChildren: "是", |
| | | unCheckedChildren: "否", |
| | | }, |
| | | rules: z.boolean().default(false), |
| | | }, |
| | | { |
| | | component: "InputNumber", |
| | | fieldName: "expiryDay", |
| | | label: "有效期(天)", |
| | |
| | | }, |
| | | }, |
| | | { |
| | | field: "isBatchManaged", |
| | | title: "批次管理", |
| | | minWidth: 80, |
| | | slots: { default: "isBatchManaged" }, |
| | | }, |
| | | { |
| | | field: "status", |
| | | title: "状态", |
| | | minWidth: 80, |
| | | cellRender: { |
| | | name: "CellDict", |
| | | props: { type: DICT_TYPE.COMMON_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | field: "createTime", |
| | | title: "创建时间", |
| | | minWidth: 180, |
| | | formatter: "formatDateTime", |
| | | }, |
| | | { |
| | | field: "isBatchManaged", |
| | | title: "批次管理", |
| | | width: 80, |
| | | fixed: "right", |
| | | slots: { default: "isBatchManaged" }, |
| | | }, |
| | | { |
| | | field: "syncedMes", |
| | | title: "同步状态", |
| | | width: 90, |
| | | fixed: "right", |
| | | slots: { default: "syncedMes" }, |
| | | }, |
| | | { |
| | | field: "status", |
| | | title: "状态", |
| | | width: 80, |
| | | fixed: "right", |
| | | cellRender: { |
| | | name: "CellDict", |
| | | props: { type: DICT_TYPE.COMMON_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | title: "操作", |
| | | width: 180, |
| | | fixed: "right", |
| | |
| | | <Tag v-if="row.isBatchManaged" color="success">是</Tag> |
| | | <Tag v-else>否</Tag> |
| | | </template> |
| | | <template #syncedMes="{ row }"> |
| | | <Tag v-if="row.syncedMes" color="success">已同步</Tag> |
| | | <Tag v-else color="default">未同步</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'returnStatus', |
| | | label: '退货状态', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: [ |
| | | { label: '未退货', value: 0 }, |
| | | { label: '部分退货', value: 1 }, |
| | | { label: '全部退货', value: 2 }, |
| | | ], |
| | | placeholder: '请选择退货状态', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order'; |
| | | |
| | | import { ref } from 'vue'; |
| | | import { onMounted, ref } from 'vue'; |
| | | import { useRoute } from 'vue-router'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; |
| | |
| | | |
| | | /** ERP 采购订单列表 */ |
| | | defineOptions({ name: 'ErpPurchaseOrder' }); |
| | | |
| | | const route = useRoute(); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | |
| | | checkboxChange: handleRowCheckboxChange, |
| | | }, |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | const id = route.query.id; |
| | | if (id) { |
| | | formModalApi.setData({ formType: 'detail', id: Number(id) }).open(); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | import type { ErpPurchaseRequestApi } from '#/api/erp/purchase/request'; |
| | | |
| | | import { ref } from 'vue'; |
| | | import { useRouter } from 'vue-router'; |
| | | |
| | | import { confirm, Page, useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart, isEmpty } from '@vben/utils'; |
| | |
| | | |
| | | /** ERP 采购申请列表 */ |
| | | defineOptions({ name: 'ErpPurchaseRequest' }); |
| | | |
| | | const router = useRouter(); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | |
| | | /** 查看详情 */ |
| | | function handleDetail(row: ErpPurchaseRequestApi.PurchaseRequest) { |
| | | formModalApi.setData({ formType: 'detail', id: row.id }).open(); |
| | | } |
| | | |
| | | /** 查看审批详情 */ |
| | | function handleViewProcess(row: ErpPurchaseRequestApi.PurchaseRequest) { |
| | | router.push({ name: 'BpmProcessInstanceDetail', query: { id: row.processInstanceId } }); |
| | | } |
| | | |
| | | /** 查看采购订单 */ |
| | | function handleViewOrder(row: ErpPurchaseRequestApi.PurchaseRequest) { |
| | | router.push({ name: 'ErpPurchaseOrder', query: { id: row.orderId } }); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | |
| | | onClick: handleGenerateOrder.bind(null, row), |
| | | }, |
| | | { |
| | | label: '查看审批', |
| | | type: 'link', |
| | | ifShow: () => row.status !== 0, |
| | | onClick: handleViewProcess.bind(null, row), |
| | | }, |
| | | { |
| | | label: '查看订单', |
| | | type: 'link', |
| | | ifShow: () => !!row.orderId, |
| | | onClick: handleViewOrder.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: [ |
| | | { label: '无需生产', value: -1 }, |
| | | { label: '未完成', value: 0 }, |
| | | { label: '已完成', value: 1 }, |
| | | ], |
| | | placeholder: '请选择生产状态', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'returnStatus', |
| | | label: '退货状态', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: [ |
| | | { label: '未退货', value: 0 }, |
| | | { label: '部分退货', value: 1 }, |
| | | { label: '全部退货', value: 2 }, |
| | | ], |
| | | placeholder: '请选择退货状态', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | // 生产状态搜索参数转换:-1(无需生产) → needProduction=0 |
| | | const { productionStatus, ...rest } = formValues; |
| | | const params: Record<string, any> = { ...rest }; |
| | | if (productionStatus === -1) { |
| | | params.needProduction = 0; |
| | | } else if (productionStatus != null) { |
| | | params.productionStatus = productionStatus; |
| | | params.needProduction = 1; |
| | | } |
| | | return await getSaleOrderPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | ...params, |
| | | }); |
| | | }, |
| | | }, |
| | |
| | | import type { MesProTaskApi } from '#/api/mes/pro/task'; |
| | | import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder'; |
| | | |
| | | import type { Ref } from 'vue'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | |
| | | }, |
| | | { |
| | | title: '操作', |
| | | width: 100, |
| | | width: 160, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | |
| | | } |
| | | |
| | | /** 生产任务新增/修改的表单 */ |
| | | export function useTaskFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { |
| | | export function useTaskFormSchema(formApi?: VbenFormApi, workOrderQuantity?: Ref<number | undefined>): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'workstationId', |
| | |
| | | fieldName: 'quantity', |
| | | label: '排产数量', |
| | | component: 'InputNumber', |
| | | description: () => workOrderQuantity?.value != null ? `订单数量:${workOrderQuantity.value}` : '', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | min: 0.01, |
| | |
| | | ifShow: row.status === MesProWorkOrderStatusEnum.CONFIRMED, |
| | | onClick: handleSchedule.bind(null, row), |
| | | }, |
| | | { |
| | | label: '一键排产', |
| | | type: 'link', |
| | | auth: ['mes:pro-task:create'], |
| | | ifShow: row.status === MesProWorkOrderStatusEnum.CONFIRMED, |
| | | onClick: handleAutoSchedulePreview.bind(null, row), |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | |
| | | :process-id="rp.processId!" |
| | | :route-id="currentRouteId" |
| | | :work-order-id="workOrder.id!" |
| | | :work-order-quantity="workOrder.quantity" |
| | | /> |
| | | </Card> |
| | | </template> |
| | |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<MesProTaskApi.Task>(); |
| | | const workOrderQuantity = ref<number>(); // 订单数量(用于提示) |
| | | const context = ref<{ |
| | | colorCode?: string; |
| | | itemId?: number; |
| | |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | workOrderQuantity.value = undefined; |
| | | context.value = {}; |
| | | return; |
| | | } |
| | | formApi.setState({ schema: useTaskFormSchema(formApi) }); |
| | | formApi.setState({ schema: useTaskFormSchema(formApi, workOrderQuantity) }); |
| | | // 加载数据 |
| | | const data = modalApi.getData<{ |
| | | colorCode?: string; |
| | | id?: number; |
| | | itemId?: number; |
| | | processId?: number; |
| | | quantity?: number; |
| | | routeId?: number; |
| | | workOrderId?: number; |
| | | }>(); |
| | |
| | | routeId: data.routeId, |
| | | workOrderId: data.workOrderId, |
| | | }; |
| | | workOrderQuantity.value = data.quantity; |
| | | await formApi.setValues({ |
| | | colorCode: data.colorCode || '#00AEF3', |
| | | duration: 1, |
| | | quantity: data.quantity, |
| | | }); |
| | | }, |
| | | }); |
| | |
| | | processId: number; |
| | | routeId: number; |
| | | workOrderId: number; |
| | | workOrderQuantity?: number; |
| | | }>(); |
| | | |
| | | const editable = computed(() => !props.disabled); // 是否可维护任务 |
| | |
| | | colorCode: props.colorCode, |
| | | itemId: props.itemId, |
| | | processId: props.processId, |
| | | quantity: props.workOrderQuantity, |
| | | routeId: props.routeId, |
| | | workOrderId: props.workOrderId, |
| | | }) |
| | |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [SchedulePreviewModal, schedulePreviewModalApi] = useVbenModal({ |
| | | const [SchedulePreviewModalWrap, schedulePreviewModalApi] = useVbenModal({ |
| | | connectedComponent: SchedulePreviewModal, |
| | | destroyOnClose: true, |
| | | }); |
| | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <QuickFeedbackModal @success="handleFeedbackSuccess" /> |
| | | <SchedulePreviewModal @success="handleRefresh" /> |
| | | <SchedulePreviewModalWrap @success="handleRefresh" /> |
| | | |
| | | <Grid table-title="工单中心"> |
| | | <template #toolbar-tools> |
| | |
| | | ? '确认' |
| | | : isFinish.value |
| | | ? '完成' |
| | | : undefined, |
| | | : isCreateMode.value |
| | | ? '新增' |
| | | : undefined, |
| | | }); |
| | | } |
| | | |
| | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesQcIqcApi } from '#/api/mes/qc/iqc'; |
| | | |
| | | import { onMounted } from 'vue'; |
| | | import { useRoute } from 'vue-router'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { MesQcStatusEnum } from '@vben/constants'; |
| | | import { downloadFileFromBlobPart } from '@vben/utils'; |
| | |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | defineOptions({ name: 'MesQcIqc' }); |
| | | |
| | | const route = useRoute(); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | |
| | | }, |
| | | } as VxeTableGridOptions<MesQcIqcApi.Iqc>, |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | const id = route.query.id; |
| | | if (id) { |
| | | formModalApi.setData({ formType: 'detail', id: Number(id) }).open(); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | |
| | | const searchKeyword = ref(''); |
| | | |
| | | /** 先按工作站工序过滤,再按搜索关键字匹配 */ |
| | | const filteredList = computed(() => { |
| | | const kw = searchKeyword.value.trim().toLowerCase(); |
| | | if (!kw) return props.list; |
| | | return props.list.filter((row) => { |
| | | const fields = [ |
| | | row.code, |
| | | row.name, |
| | | row.workOrderCode, |
| | | row.workOrderName, |
| | | row.itemCode, |
| | |
| | | > |
| | | 质检 |
| | | </Tag> |
| | | <Tag |
| | | v-if="item.backflushFlag" |
| | | color="purple" |
| | | class="task-card__check-tag" |
| | | > |
| | | 倒冲 |
| | | </Tag> |
| | | <span |
| | | class="task-card__rate" |
| | | :style="{ color: getProgressColor(item.feedbackRate) }" |
| | |
| | | /** 跳转 IQC 检验单详情 */ |
| | | function handleOpenIqc(row: MesWmArrivalNoticeLineApi.ArrivalNoticeLine) { |
| | | if (row.iqcId) { |
| | | router.push({ path: '/mes/qc/iqc', query: { id: row.iqcId } }); |
| | | router.push({ name: 'MesQcIqc', query: { id: row.iqcId } }); |
| | | } |
| | | } |
| | | |