feat(mes): 增加产品设计项目审批流程和批次追溯功能
- 添加审批中状态及流程选择弹窗组件
- 实现产品设计项目提交审批和查看审批详情功能
- 集成BPM审批流程接口和流程实例查询
- 新增批次采购来源、销售去向和工序流转追溯功能
- 添加SN码反查批次和多维度追溯展示
- 配置宁夏英泽防锈新材料公司信息
- 更新API接口地址配置
| | |
| | | VITE_BASE=/ |
| | | |
| | | # 请æ±è·¯å¾ |
| | | VITE_BASE_URL=http://42.63.70.90:9003 |
| | | VITE_BASE_URL=http://42.63.70.231:9001 |
| | | # æ¥å£å°å |
| | | VITE_GLOB_API_URL=http://42.63.70.90:9003/admin-api |
| | | VITE_GLOB_API_URL=http://42.63.70.231:9001/admin-api |
| | | # æä»¶ä¸ä¼ ç±»åï¼server - å端ä¸ä¼ ï¼ client - å端ç´è¿ä¸ä¼ ï¼ä»
æ¯æS3æå¡ |
| | | VITE_UPLOAD_TYPE=server |
| | | |
| | |
| | | favicon: '/logos/TEST.ico', |
| | | apiUrl: 'http://42.63.70.90:9003/admin-api', |
| | | }, |
| | | YZFX: { |
| | | name: 'å®å¤è±æ³½é²éæ°æææéå
¬å¸', |
| | | logo: '/logos/TEST.png', |
| | | favicon: '/logos/TEST.ico', |
| | | apiUrl: 'http://42.63.70.231:9001/admin-api', |
| | | }, |
| | | }; |
| | |
| | | remark?: string; |
| | | /** å建æ¶é´ */ |
| | | createTime?: number; |
| | | /** BPM æµç¨å®ä¾ç¼å· */ |
| | | processInstanceId?: string; |
| | | } |
| | | |
| | | export interface PageParams extends PageParam { |
| | |
| | | }); |
| | | } |
| | | |
| | | /** å®¡æ ¸ï¼å¾
å®¡æ ¸âå¾
彿¡£ï¼ */ |
| | | export function auditPdProject(id: number) { |
| | | return requestClient.put('/mes/pd/project/audit', undefined, { |
| | | params: { id }, |
| | | /** æäº¤å®¡æ¹ï¼å¾
å®¡æ ¸â审æ¹ä¸ï¼ */ |
| | | export function submitPdProjectApproval(id: number, processDefinitionKey: string) { |
| | | return requestClient.put('/mes/pd/project/submit-approval', undefined, { |
| | | params: { id, processDefinitionKey }, |
| | | }); |
| | | } |
| | | |
| | | /** è·å¾å®¡æ¹æµç¨å表 */ |
| | | export function getPdProjectApproveProcessList() { |
| | | return requestClient.get<Array<{ id: string; name: string; key: string }>>( |
| | | '/mes/pd/project/approve-process-list', |
| | | ); |
| | | } |
| | | |
| | | /** 彿¡£ï¼å¾
彿¡£â已彿¡£ï¼ï¼å端èªå¨åå»ºå½æ¡£å°è´¦è®°å½ */ |
| | | export function archivePdProject(id: number) { |
| | | return requestClient.put('/mes/pd/project/archive', undefined, { |
| | |
| | | expireDate?: string[]; // è¿ææ¥æ |
| | | receiptDate?: string[]; // å
¥åºæ¥æ |
| | | } |
| | | |
| | | /** MES æ¹æ¬¡éè´æ¥æºï¼éè´å
¥åºå + IQCï¼ */ |
| | | export interface PurchaseSource { |
| | | receiptCode?: string; // éè´å
¥åºåå· |
| | | receiptDate?: Date; // å
¥åºæ¥æ |
| | | purchaseOrderCode?: string; // éè´è®¢åç¼å· |
| | | vendorId?: number; // ä¾åºå ID |
| | | vendorCode?: string; // ä¾åºåç¼ç |
| | | vendorName?: string; // ä¾åºååç§° |
| | | iqcCode?: string; // IQC æ£éªåå· |
| | | checkResult?: number; // IQC æ£éªç»è®ºï¼åå
¸ mes_qc_check_resultï¼ |
| | | itemId?: number; // ç©æ ID |
| | | itemCode?: string; // ç©æç¼ç |
| | | itemName?: string; // ç©æåç§° |
| | | batchCode?: string; // æ¹æ¬¡å· |
| | | receivedQuantity?: number; // å
¥åºæ°é |
| | | } |
| | | |
| | | /** MES æ¹æ¬¡éå®å»åï¼éå®åºåºå + OQCï¼ */ |
| | | export interface SalesTarget { |
| | | salesCode?: string; // éå®åºåºåå· |
| | | salesDate?: Date; // åºåºæ¥æ |
| | | salesOrderCode?: string; // éå®è®¢åç¼å· |
| | | clientId?: number; // å®¢æ· ID |
| | | clientCode?: string; // 客æ·ç¼ç |
| | | clientName?: string; // 客æ·åç§° |
| | | oqcCode?: string; // OQC æ£éªåå· |
| | | checkResult?: number; // OQC æ£éªç»è®ºï¼åå
¸ mes_qc_check_resultï¼ |
| | | itemId?: number; // ç©æ ID |
| | | itemCode?: string; // ç©æç¼ç |
| | | itemName?: string; // ç©æåç§° |
| | | batchCode?: string; // æ¹æ¬¡å· |
| | | quantity?: number; // åºåºæ°é |
| | | qualityStatus?: number; // è´¨éç¶æï¼åå
¸ mes_wm_quality_statusï¼ |
| | | } |
| | | |
| | | /** MES æ¹æ¬¡å·¥åºæµè½¬ï¼äº§åº/æå
¥äºä»¶ï¼ */ |
| | | export interface ProcessTrace { |
| | | eventType?: 'OUT' | 'IN'; // äºä»¶ç±»åï¼OUT-äº§åº / IN-æå
¥ |
| | | workOrderId?: number; // ç产工å ID |
| | | workOrderCode?: string; // ç产工åç¼å· |
| | | processId?: number; // å·¥åº ID |
| | | processCode?: string; // å·¥åºç¼ç |
| | | processName?: string; // å·¥åºåç§° |
| | | batchCode?: string; // æ¹æ¬¡å· |
| | | quantity?: number; // æ°é |
| | | qualityStatus?: number; // è´¨éç¶æï¼åå
¸ mes_wm_quality_statusï¼ï¼ä»
产åºä¾§æå¼ |
| | | eventTime?: Date; // äºä»¶æ¶é´ |
| | | processSort?: number; // å·¥åºåºå· |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢æ¹æ¬¡è¯¦æ
*/ |
| | |
| | | { params: { code } }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¹æ¬¡éè´æ¥æºï¼éè´å
¥åºå + IQCï¼ */ |
| | | export function getPurchaseSourceList(code: string) { |
| | | return requestClient.get<MesWmBatchApi.PurchaseSource[]>( |
| | | '/mes/wm/batch/purchase-sources', |
| | | { params: { code } }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¹æ¬¡éå®å»åï¼éå®åºåºå + OQCï¼ */ |
| | | export function getSalesTargetList(code: string) { |
| | | return requestClient.get<MesWmBatchApi.SalesTarget[]>( |
| | | '/mes/wm/batch/sales-targets', |
| | | { params: { code } }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¹æ¬¡å·¥åºæµè½¬ï¼äº§åº/æå
¥äºä»¶ï¼ */ |
| | | export function getProcessTraceList(code: string) { |
| | | return requestClient.get<MesWmBatchApi.ProcessTrace[]>( |
| | | '/mes/wm/batch/process-trace', |
| | | { params: { code } }, |
| | | ); |
| | | } |
| | | |
| | | /** æ ¹æ® SN ç åæ¥æ¹æ¬¡ */ |
| | | export function getBatchBySn(sn: string) { |
| | | return requestClient.get<MesWmBatchApi.Batch | null>('/mes/wm/batch/get-by-sn', { |
| | | params: { sn }, |
| | | }); |
| | | } |
| | |
| | | RIGHT: 2, // å³è¡¥é½ |
| | | } as const; |
| | | |
| | | /** MES 产å设计项ç®ç¶ææä¸¾ï¼çº¿æ§æµè½¬ï¼å¾
åå¸âå¾
ä¸ä¼ âå¾
å®¡æ ¸âå¾
彿¡£â已彿¡£ï¼ */ |
| | | /** MES 产å设计项ç®ç¶ææä¸¾ï¼çº¿æ§æµè½¬ï¼å¾
åå¸âå¾
ä¸ä¼ âå¾
å®¡æ ¸â审æ¹ä¸âå¾
彿¡£â已彿¡£ï¼ */ |
| | | export const MesPdProjectStatusEnum = { |
| | | PENDING_PUBLISH: 0, // å¾
åå¸ |
| | | PENDING_UPLOAD: 1, // å¾
ä¸ä¼ |
| | | PENDING_AUDIT: 2, // å¾
å®¡æ ¸ |
| | | APPROVING: 5, // 审æ¹ä¸ |
| | | PENDING_ARCHIVE: 3, // å¾
彿¡£ |
| | | ARCHIVED: 4, // 已彿¡£ |
| | | } as const; |
| | |
| | | |
| | | import { |
| | | archivePdProject, |
| | | auditPdProject, |
| | | getPdProject, |
| | | getPdProjectApproveProcessList, |
| | | publishPdProject, |
| | | uploadPdProject, |
| | | } from '#/api/mes/pd/project'; |
| | |
| | | import Form from '../modules/form.vue'; |
| | | import DocumentAuditList from '../modules/document-audit-list.vue'; |
| | | import DocumentList from '../modules/document-list.vue'; |
| | | import ProcessSelectModal from '../modules/process-select-modal.vue'; |
| | | import WorkflowTimeline from '../modules/workflow-timeline.vue'; |
| | | import TaskDraftBanner from '../modules/task-draft-banner.vue'; |
| | | import { useDetailSchema } from './data'; |
| | |
| | | const isPendingArchive = computed( |
| | | () => project.value.status === MesPdProjectStatusEnum.PENDING_ARCHIVE, |
| | | ); |
| | | const isApproving = computed( |
| | | () => project.value.status === MesPdProjectStatusEnum.APPROVING, |
| | | ); |
| | | const isArchived = computed( |
| | | () => project.value.status === MesPdProjectStatusEnum.ARCHIVED, |
| | | ); |
| | |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [ProcessModal, processModalApi] = useVbenModal({ |
| | | connectedComponent: ProcessSelectModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | async function handleAudit() { |
| | | const hideLoading = message.loading({ content: 'å®¡æ ¸ä¸â¦', duration: 0 }); |
| | | /** æäº¤å®¡æ¹ - å
è·åæµç¨å表 */ |
| | | async function handleSubmit() { |
| | | const hideLoading = message.loading({ content: 'è·åå®¡æ¹æµç¨...', duration: 0 }); |
| | | try { |
| | | await auditPdProject(projectId.value); |
| | | message.success('å®¡æ ¸éè¿ï¼è¿å
¥å¾
彿¡£ç¶æ'); |
| | | tabs.closeCurrentTab(); |
| | | router.back(); |
| | | } finally { |
| | | const processList = await getPdProjectApproveProcessList(); |
| | | hideLoading(); |
| | | if (!processList || processList.length === 0) { |
| | | message.warning('ææ å¯ç¨å®¡æ¹æµç¨ï¼è¯·å
é
ç½® BPM æµç¨'); |
| | | return; |
| | | } |
| | | // æå¼æµç¨éæ©å¼¹çª |
| | | processModalApi.setData({ id: projectId.value, processList }).open(); |
| | | } catch { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** æ¥ç审æ¹è¯¦æ
*/ |
| | | function handleProcessDetail() { |
| | | if (!project.value.processInstanceId) { |
| | | message.warning('该项ç®å°æªæäº¤å®¡æ¹'); |
| | | return; |
| | | } |
| | | router.push({ |
| | | name: 'BpmProcessInstanceDetail', |
| | | query: { id: project.value.processInstanceId }, |
| | | }); |
| | | } |
| | | |
| | | /** æäº¤å®¡æ¹æååå·æ°è¯¦æ
*/ |
| | | function handleSubmitSuccess() { |
| | | loadProjectDetail(); |
| | | } |
| | | |
| | | async function handleArchive() { |
| | |
| | | :title="project.taskName || '设计任å¡è¯¦æ
'" |
| | | > |
| | | <FormModal @success="loadProjectDetail" /> |
| | | <ProcessModal @success="handleSubmitSuccess" /> |
| | | |
| | | <template #extra> |
| | | <TableAction |
| | |
| | | onClick: handleUpload, |
| | | }, |
| | | { |
| | | label: 'å®¡æ ¸éè¿', |
| | | label: 'æäº¤å®¡æ¹', |
| | | type: 'primary', |
| | | ifShow: isPendingAudit, |
| | | onClick: handleAudit, |
| | | onClick: handleSubmit, |
| | | }, |
| | | { |
| | | label: 'æ¥ç审æ¹', |
| | | type: 'primary', |
| | | ifShow: isApproving, |
| | | onClick: handleProcessDetail, |
| | | }, |
| | | { |
| | | label: '彿¡£', |
| | |
| | | |
| | | deletePdProject, |
| | | exportPdProject, |
| | | getPdProjectApproveProcessList, |
| | | getPdProjectPage, |
| | | publishPdProject, |
| | | |
| | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import CreateForm from './modules/create-form.vue'; |
| | | import Form from './modules/form.vue'; |
| | | import ProcessSelectModal from './modules/process-select-modal.vue'; |
| | | |
| | | const router = useRouter(); |
| | | |
| | |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [ProcessModal, processModalApi] = useVbenModal({ |
| | | connectedComponent: ProcessSelectModal, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** æäº¤å®¡æ¹ - å
è·åæµç¨å表 */ |
| | | async function handleSubmit(row: MesPdProjectApi.Project) { |
| | | const hideLoading = message.loading({ |
| | | content: 'è·åå®¡æ¹æµç¨...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | const processList = await getPdProjectApproveProcessList(); |
| | | hideLoading(); |
| | | if (!processList || processList.length === 0) { |
| | | message.warning('ææ å¯ç¨å®¡æ¹æµç¨ï¼è¯·å
é
ç½® BPM æµç¨'); |
| | | return; |
| | | } |
| | | // æå¼æµç¨éæ©å¼¹çª |
| | | processModalApi.setData({ id: row.id, processList }).open(); |
| | | } catch { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** æ¥ç审æ¹è¯¦æ
*/ |
| | | function handleProcessDetail(row: MesPdProjectApi.Project) { |
| | | if (!row.processInstanceId) { |
| | | message.warning('该项ç®å°æªæäº¤å®¡æ¹'); |
| | | return; |
| | | } |
| | | router.push({ |
| | | name: 'BpmProcessInstanceDetail', |
| | | query: { id: row.processInstanceId }, |
| | | }); |
| | | } |
| | | |
| | | async function handleArchive(row: MesPdProjectApi.Project) { |
| | |
| | | <Page auto-content-height> |
| | | <CreateFormModal @success="handleCreateSuccess" /> |
| | | <FormModal @success="handleRefresh" /> |
| | | <ProcessModal @success="handleRefresh" /> |
| | | |
| | | <Grid table-title="设计任å¡"> |
| | | <template #toolbar-tools> |
| | |
| | | onClick: () => handleDetail(row), |
| | | }, |
| | | { |
| | | label: 'å®¡æ ¸', |
| | | label: 'æäº¤å®¡æ¹', |
| | | type: 'link', |
| | | auth: ['mes:pd-project:audit'], |
| | | auth: ['mes:pd-project:update'], |
| | | ifShow: row.status === MesPdProjectStatusEnum.PENDING_AUDIT, |
| | | onClick: () => handleDetail(row), |
| | | onClick: handleSubmit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'æ¥ç审æ¹', |
| | | type: 'link', |
| | | auth: ['mes:pd-project:update'], |
| | | ifShow: row.status === MesPdProjectStatusEnum.APPROVING, |
| | | onClick: handleProcessDetail.bind(null, row), |
| | | }, |
| | | { |
| | | label: '彿¡£', |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message, Select } from 'ant-design-vue'; |
| | | |
| | | import { submitPdProjectApproval } from '#/api/mes/pd/project'; |
| | | |
| | | interface ProcessDefinition { |
| | | id: string; |
| | | name: string; |
| | | key: string; |
| | | } |
| | | |
| | | const emit = defineEmits(['success']); |
| | | |
| | | const projectId = ref<number>(); |
| | | const processList = ref<ProcessDefinition[]>([]); |
| | | const selectedProcessKey = ref<string>(''); |
| | | |
| | | const processOptions = computed(() => { |
| | | return processList.value.map((p) => ({ |
| | | label: p.name, |
| | | value: p.key, |
| | | })); |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | if (!selectedProcessKey.value) { |
| | | message.warning('è¯·éæ©å®¡æ¹æµç¨'); |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | await submitPdProjectApproval(projectId.value!, selectedProcessKey.value); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success('æäº¤å®¡æ¹æå'); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | projectId.value = undefined; |
| | | selectedProcessKey.value = ''; |
| | | processList.value = []; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ id: number; processList: ProcessDefinition[] }>(); |
| | | projectId.value = data.id; |
| | | processList.value = data.processList || []; |
| | | // é»è®¤éæ©ç¬¬ä¸ä¸ªæµç¨ |
| | | if (processList.value.length > 0) { |
| | | selectedProcessKey.value = processList.value[0].key; |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal title="éæ©å®¡æ¹æµç¨" class="w-1/3"> |
| | | <div class="mb-4"> |
| | | <span class="mr-2">å®¡æ¹æµç¨ï¼</span> |
| | | <Select |
| | | v-model:value="selectedProcessKey" |
| | | :options="processOptions" |
| | | style="width: 200px" |
| | | placeholder="è¯·éæ©å®¡æ¹æµç¨" |
| | | /> |
| | | </div> |
| | | </Modal> |
| | | </template> |
| | |
| | | |
| | | import { Steps } from 'ant-design-vue'; |
| | | |
| | | const STEPS = ['å¾
åå¸', 'å¾
ä¸ä¼ ', 'å¾
å®¡æ ¸', 'å¾
彿¡£', '已彿¡£'] as const; |
| | | import { MesPdProjectStatusEnum } from '#/packages/constants/src'; |
| | | |
| | | const STEPS = ['å¾
åå¸', 'å¾
ä¸ä¼ ', 'å¾
å®¡æ ¸', '审æ¹ä¸', 'å¾
彿¡£', '已彿¡£'] as const; |
| | | |
| | | // ç¶æå¼ â æ¶é´çº¿æ¥éª¤ç´¢å¼ï¼å®¡æ¹ä¸=5 æå¨å¾
å®¡æ ¸ä¹åï¼ |
| | | const STATUS_ORDER = [ |
| | | MesPdProjectStatusEnum.PENDING_PUBLISH, |
| | | MesPdProjectStatusEnum.PENDING_UPLOAD, |
| | | MesPdProjectStatusEnum.PENDING_AUDIT, |
| | | MesPdProjectStatusEnum.APPROVING, |
| | | MesPdProjectStatusEnum.PENDING_ARCHIVE, |
| | | MesPdProjectStatusEnum.ARCHIVED, |
| | | ]; |
| | | |
| | | const props = defineProps<{ |
| | | /** 项ç®å½åç¶æ (0-4) */ |
| | | /** 项ç®å½åç¶æ */ |
| | | status: number; |
| | | }>(); |
| | | |
| | | const current = computed(() => { |
| | | // ç¶æå¼å³å½å已宿å°ç¬¬å æ¥ï¼0=ç¬¬ä¸æ¥è¿è¡ä¸ï¼4=å
¨é¨å®æ |
| | | return props.status; |
| | | // æ ¹æ®ç¶æå¼æ å°å°æ¶é´çº¿æ¥éª¤ç´¢å¼ |
| | | const index = STATUS_ORDER.indexOf(props.status); |
| | | return index >= 0 ? index : 0; |
| | | }); |
| | | |
| | | const nodes = computed(() => |
| | | STEPS.map((name, index) => ({ |
| | | title: name, |
| | | status: index < props.status ? 'finish' : index === props.status ? 'process' : 'wait', |
| | | status: index < current.value ? 'finish' : index === current.value ? 'process' : 'wait', |
| | | })), |
| | | ); |
| | | </script> |
| | |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | |
| | | import { MdClientSelect } from '#/views/mes/md/client/components'; |
| | | import { MdItemSelect } from '#/views/mes/md/item/components'; |
| | | import { MdVendorSelect } from '#/views/mes/md/vendor/components'; |
| | |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** éè´æ¥æºå表çåæ®µ */ |
| | | export function usePurchaseSourceColumns(): VxeTableGridOptions<MesWmBatchApi.PurchaseSource>['columns'] { |
| | | return [ |
| | | { |
| | | field: 'receiptCode', |
| | | title: 'éè´å
¥åºåå·', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'receiptDate', |
| | | title: 'å
¥åºæ¥æ', |
| | | minWidth: 160, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'purchaseOrderCode', |
| | | title: 'éè´è®¢åç¼å·', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'vendorCode', |
| | | title: 'ä¾åºåç¼ç ', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'vendorName', |
| | | title: 'ä¾åºååç§°', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'itemCode', |
| | | title: 'ç©æç¼ç ', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'itemName', |
| | | title: 'ç©æåç§°', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'iqcCode', |
| | | title: 'IQC æ£éªåå·', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'checkResult', |
| | | title: 'IQC æ£éªç»è®º', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_QC_CHECK_RESULT }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'receivedQuantity', |
| | | title: 'å
¥åºæ°é', |
| | | width: 100, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** éå®å»åå表çåæ®µ */ |
| | | export function useSalesTargetColumns(): VxeTableGridOptions<MesWmBatchApi.SalesTarget>['columns'] { |
| | | return [ |
| | | { |
| | | field: 'salesCode', |
| | | title: 'éå®åºåºåå·', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'salesDate', |
| | | title: 'åºåºæ¥æ', |
| | | minWidth: 160, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | field: 'salesOrderCode', |
| | | title: 'éå®è®¢åç¼å·', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'clientName', |
| | | title: '客æ·åç§°', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'itemCode', |
| | | title: 'ç©æç¼ç ', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'itemName', |
| | | title: 'ç©æåç§°', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'oqcCode', |
| | | title: 'OQC æ£éªåå·', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'checkResult', |
| | | title: 'OQC æ£éªç»è®º', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_QC_CHECK_RESULT }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'quantity', |
| | | title: 'åºåºæ°é', |
| | | width: 100, |
| | | }, |
| | | { |
| | | field: 'qualityStatus', |
| | | title: 'è´¨éç¶æ', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS }, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å·¥åºæµè½¬å表çåæ®µ */ |
| | | export function useProcessTraceColumns(): VxeTableGridOptions<MesWmBatchApi.ProcessTrace>['columns'] { |
| | | return [ |
| | | { |
| | | field: 'eventType', |
| | | title: 'äºä»¶ç±»å', |
| | | width: 90, |
| | | slots: { default: 'eventType' }, |
| | | }, |
| | | { |
| | | field: 'workOrderCode', |
| | | title: 'ç产工åå·', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'processCode', |
| | | title: 'å·¥åºç¼ç ', |
| | | minWidth: 120, |
| | | }, |
| | | { |
| | | field: 'processName', |
| | | title: 'å·¥åºåç§°', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'quantity', |
| | | title: 'æ°é', |
| | | width: 100, |
| | | }, |
| | | { |
| | | field: 'qualityStatus', |
| | | title: 'è´¨éç¶æ', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'eventTime', |
| | | title: 'äºä»¶æ¶é´', |
| | | minWidth: 160, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | ]; |
| | | } |
| | |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { Input, message } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getBatchPage } from '#/api/mes/wm/batch'; |
| | | import { getBatchBySn, getBatchPage } from '#/api/mes/wm/batch'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import TraceDetail from './modules/trace-detail.vue'; |
| | |
| | | /** æå¼æ¹æ¬¡è¿½æº¯è¯¦æ
*/ |
| | | function handleTrace(row: MesWmBatchApi.Batch) { |
| | | detailModalApi.setData(row).open(); |
| | | } |
| | | |
| | | /** æ ¹æ® SN åæ¥æ¹æ¬¡å¹¶æå¼è¯¦æ
*/ |
| | | async function handleSearchBySn(sn: string) { |
| | | if (!sn) { |
| | | return; |
| | | } |
| | | const batch = await getBatchBySn(sn.trim()); |
| | | if (batch) { |
| | | handleTrace(batch); |
| | | } else { |
| | | message.warning(`æªæ¾å° SNã${sn}ã对åºçæ¹æ¬¡`); |
| | | } |
| | | } |
| | | |
| | | const [Grid] = useVbenVxeGrid({ |
| | |
| | | <template> |
| | | <Page auto-content-height><DetailModal /> |
| | | |
| | | <div class="mb-3 w-80"> |
| | | <Input.Search |
| | | placeholder="è¾å
¥ SN åºåå·åæ¥æ¹æ¬¡" |
| | | enter-button="忥" |
| | | allow-clear |
| | | @search="handleSearchBySn" |
| | | /> |
| | | </div> |
| | | |
| | | <Grid table-title="æ¹æ¬¡è¿½æº¯å表"> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesWmBatchApi } from '#/api/mes/wm/batch'; |
| | | |
| | | import { watch } from 'vue'; |
| | | |
| | | import { Tag } from 'ant-design-vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getProcessTraceList } from '#/api/mes/wm/batch'; |
| | | |
| | | import { useProcessTraceColumns } from '../data'; |
| | | |
| | | const props = defineProps<{ |
| | | batchCode?: string; |
| | | }>(); |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | columns: useProcessTraceColumns(), |
| | | minHeight: 240, |
| | | pagerConfig: { |
| | | enabled: false, |
| | | }, |
| | | rowConfig: { |
| | | isHover: true, |
| | | }, |
| | | showOverflow: true, |
| | | toolbarConfig: { |
| | | enabled: false, |
| | | }, |
| | | } as VxeTableGridOptions<MesWmBatchApi.ProcessTrace>, |
| | | }); |
| | | |
| | | /** å è½½å·¥åºæµè½¬å表 */ |
| | | async function getList() { |
| | | if (!props.batchCode) { |
| | | await gridApi.grid?.loadData([]); |
| | | return; |
| | | } |
| | | gridApi.setLoading(true); |
| | | try { |
| | | const list = await getProcessTraceList(props.batchCode); |
| | | await gridApi.grid?.loadData(list); |
| | | } finally { |
| | | gridApi.setLoading(false); |
| | | } |
| | | } |
| | | |
| | | watch( |
| | | () => props.batchCode, |
| | | () => { |
| | | getList(); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | </script> |
| | | |
| | | <template> |
| | | <Grid class="w-full"> |
| | | <template #eventType="{ row }"> |
| | | <Tag v-if="row.eventType === 'OUT'" color="success">产åº</Tag> |
| | | <Tag v-else color="processing">æå
¥</Tag> |
| | | </template> |
| | | </Grid> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesWmBatchApi } from '#/api/mes/wm/batch'; |
| | | |
| | | import { watch } from 'vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getPurchaseSourceList } from '#/api/mes/wm/batch'; |
| | | |
| | | import { usePurchaseSourceColumns } from '../data'; |
| | | |
| | | const props = defineProps<{ |
| | | batchCode?: string; |
| | | }>(); |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | columns: usePurchaseSourceColumns(), |
| | | minHeight: 240, |
| | | pagerConfig: { |
| | | enabled: false, |
| | | }, |
| | | rowConfig: { |
| | | isHover: true, |
| | | }, |
| | | showOverflow: true, |
| | | toolbarConfig: { |
| | | enabled: false, |
| | | }, |
| | | } as VxeTableGridOptions<MesWmBatchApi.PurchaseSource>, |
| | | }); |
| | | |
| | | /** å è½½éè´æ¥æºå表 */ |
| | | async function getList() { |
| | | if (!props.batchCode) { |
| | | await gridApi.grid?.loadData([]); |
| | | return; |
| | | } |
| | | gridApi.setLoading(true); |
| | | try { |
| | | const list = await getPurchaseSourceList(props.batchCode); |
| | | await gridApi.grid?.loadData(list); |
| | | } finally { |
| | | gridApi.setLoading(false); |
| | | } |
| | | } |
| | | |
| | | watch( |
| | | () => props.batchCode, |
| | | () => { |
| | | getList(); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | </script> |
| | | |
| | | <template> |
| | | <Grid class="w-full" /> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesWmBatchApi } from '#/api/mes/wm/batch'; |
| | | |
| | | import { watch } from 'vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getSalesTargetList } from '#/api/mes/wm/batch'; |
| | | |
| | | import { useSalesTargetColumns } from '../data'; |
| | | |
| | | const props = defineProps<{ |
| | | batchCode?: string; |
| | | }>(); |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | columns: useSalesTargetColumns(), |
| | | minHeight: 240, |
| | | pagerConfig: { |
| | | enabled: false, |
| | | }, |
| | | rowConfig: { |
| | | isHover: true, |
| | | }, |
| | | showOverflow: true, |
| | | toolbarConfig: { |
| | | enabled: false, |
| | | }, |
| | | } as VxeTableGridOptions<MesWmBatchApi.SalesTarget>, |
| | | }); |
| | | |
| | | /** å è½½éå®å»åå表 */ |
| | | async function getList() { |
| | | if (!props.batchCode) { |
| | | await gridApi.grid?.loadData([]); |
| | | return; |
| | | } |
| | | gridApi.setLoading(true); |
| | | try { |
| | | const list = await getSalesTargetList(props.batchCode); |
| | | await gridApi.grid?.loadData(list); |
| | | } finally { |
| | | gridApi.setLoading(false); |
| | | } |
| | | } |
| | | |
| | | watch( |
| | | () => props.batchCode, |
| | | () => { |
| | | getList(); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | </script> |
| | | |
| | | <template> |
| | | <Grid class="w-full" /> |
| | | </template> |
| | |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { Tabs } from 'ant-design-vue'; |
| | | import { Tabs, Tooltip } from 'ant-design-vue'; |
| | | |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | import { useDetailSchema } from '../data'; |
| | | import ProcessTraceList from './process-trace-list.vue'; |
| | | import PurchaseSourceList from './purchase-source-list.vue'; |
| | | import SalesTargetList from './sales-target-list.vue'; |
| | | import TraceList from './trace-list.vue'; |
| | | |
| | | const detailData = ref<MesWmBatchApi.Batch>(); // å½åæ¹æ¬¡è¯¦æ
|
| | | const subTabsName = ref<'backward' | 'forward'>('forward'); // å½åæ¿æ´»ç追溯æ¹å |
| | | const subTabsName = ref< |
| | | | 'backward' |
| | | | 'forward' |
| | | | 'purchase' |
| | | | 'sales' |
| | | | 'process' |
| | | >('forward'); // å½åæ¿æ´»çè¿½æº¯é¡µç¾ |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | |
| | | class="mx-4 mt-4" |
| | | type="card" |
| | | > |
| | | <Tabs.TabPane key="forward" tab="åå追溯"> |
| | | <Tabs.TabPane key="forward"> |
| | | <template #tab> |
| | | <Tooltip title="顺çç产æµå¾ä¸æ¸¸æ¥ï¼è¯¥æ¹æ¬¡è¢«åªäºå·¥åæ¶èåï¼äº§åºæäºåªäºæåæ¹æ¬¡"> |
| | | <span>åå追溯</span> |
| | | </Tooltip> |
| | | </template> |
| | | <TraceList :batch-code="detailData.code" direction="forward" /> |
| | | </Tabs.TabPane> |
| | | <Tabs.TabPane key="backward" tab="åå追溯"> |
| | | <Tabs.TabPane key="backward"> |
| | | <template #tab> |
| | | <Tooltip title="éçç产æµå¾ä¸æ¸¸æ¥ï¼çäº§è¯¥æ¹æ¬¡æ¶ï¼æ¶èäºåªäºåææ¹æ¬¡"> |
| | | <span>åå追溯</span> |
| | | </Tooltip> |
| | | </template> |
| | | <TraceList :batch-code="detailData.code" direction="backward" /> |
| | | </Tabs.TabPane> |
| | | <Tabs.TabPane key="purchase"> |
| | | <template #tab> |
| | | <Tooltip title="åæä¾§æ¥æºï¼è¯¥æ¹æ¬¡å¯¹åºçéè´å
¥åºåä¸ IQC æ¥ææ£éªè®°å½"> |
| | | <span>éè´æ¥æº</span> |
| | | </Tooltip> |
| | | </template> |
| | | <PurchaseSourceList :batch-code="detailData.code" /> |
| | | </Tabs.TabPane> |
| | | <Tabs.TabPane key="sales"> |
| | | <template #tab> |
| | | <Tooltip title="æåä¾§å»åï¼è¯¥æ¹æ¬¡å¯¹åºçéå®åºåºåä¸ OQC åºåæ£éªè®°å½"> |
| | | <span>éå®å»å</span> |
| | | </Tooltip> |
| | | </template> |
| | | <SalesTargetList :batch-code="detailData.code" /> |
| | | </Tabs.TabPane> |
| | | <Tabs.TabPane key="process"> |
| | | <template #tab> |
| | | <Tooltip title="åå·¥åºçæå
¥/产åºäºä»¶ï¼è¯¥æ¹æ¬¡å¨åªäºå·¥åºè¢«æå
¥æäº§åºï¼åæ°éåè´¨éç¶æ"> |
| | | <span>å·¥åºæµè½¬</span> |
| | | </Tooltip> |
| | | </template> |
| | | <ProcessTraceList :batch-code="detailData.code" /> |
| | | </Tabs.TabPane> |
| | | </Tabs> |
| | | </Modal> |
| | | </template> |