| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { FormType } from '../data'; |
| | | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder'; |
| | | import type { MesProWorkOrderProcessApi } from '#/api/mes/pro/workorder/process'; |
| | | |
| | | import { computed, nextTick, onUnmounted, ref, watch } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | import { MesProWorkOrderStatusEnum } from '@vben/constants'; |
| | | import { IconifyIcon } from '@vben/icons'; |
| | | |
| | | import { useSortable } from '@vueuse/integrations/useSortable'; |
| | | import { message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteWorkOrderProcess, |
| | | getWorkOrderProcessListByWorkOrderId, |
| | | } from '#/api/mes/pro/workorder/process'; |
| | | import { getRouteProcessListByProduct } from '#/api/mes/pro/route/process'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useProcessGridColumns } from '../data'; |
| | | import ProcessForm from './process-form.vue'; |
| | | |
| | | const props = defineProps<{ |
| | | formType: FormType; |
| | | workOrder: MesProWorkOrderApi.WorkOrder; |
| | | workOrderId?: number; |
| | | productId?: number; |
| | | }>(); |
| | | |
| | | const emit = defineEmits<{ |
| | | processListChange: [list: MesProWorkOrderProcessApi.WorkOrderProcess[]]; |
| | | }>(); |
| | | |
| | | // å·¥åºåè¡¨æ°æ® |
| | | const list = ref<MesProWorkOrderProcessApi.WorkOrderProcess[]>([]); |
| | | |
| | | const isEditable = computed(() => |
| | | ['create', 'update'].includes(props.formType) && |
| | | (props.workOrder?.status === MesProWorkOrderStatusEnum.PREPARE || |
| | | props.formType === 'create'), |
| | | ); |
| | | |
| | | const isCreateMode = computed(() => props.formType === 'create'); |
| | | |
| | | // ææ½æåº |
| | | const sortableInstance = ref<any>(null); |
| | | |
| | | const [ProcessFormModal, processFormModalApi] = useVbenModal({ |
| | | connectedComponent: ProcessForm, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | autoResize: true, |
| | | border: true, |
| | | columns: useProcessGridColumns(isEditable.value), |
| | | data: [], |
| | | minHeight: 240, |
| | | pagerConfig: { enabled: false }, |
| | | rowConfig: { isHover: true, keyField: 'processId' }, |
| | | showOverflow: true, |
| | | toolbarConfig: { enabled: false }, |
| | | } as VxeTableGridOptions<MesProWorkOrderProcessApi.WorkOrderProcess>, |
| | | }); |
| | | |
| | | /** åå§å/éæ¯ææ½æåº */ |
| | | async function initSortable() { |
| | | destroySortable(); |
| | | if (!isEditable.value || list.value.length === 0) return; |
| | | await nextTick(); |
| | | sortableInstance.value = useSortable( |
| | | '.workorder-process-list .vxe-table--body-wrapper:not(.fixed-right--wrapper) .vxe-table--body tbody', |
| | | list.value, |
| | | { |
| | | animation: 150, |
| | | draggable: '.vxe-body--row', |
| | | handle: '.drag-handle', |
| | | onEnd: ({ newDraggableIndex, oldDraggableIndex }) => { |
| | | if ( |
| | | newDraggableIndex !== undefined && |
| | | oldDraggableIndex !== undefined && |
| | | oldDraggableIndex !== newDraggableIndex |
| | | ) { |
| | | // éæ°æåºæ°ç» |
| | | list.value.splice( |
| | | newDraggableIndex, |
| | | 0, |
| | | list.value.splice(oldDraggableIndex, 1)[0]!, |
| | | ); |
| | | // æ´æ° sort åæ®µ |
| | | list.value.forEach((item, index) => { |
| | | item.sort = index + 1; |
| | | }); |
| | | gridApi.setGridOptions({ data: list.value }); |
| | | emit('processListChange', list.value); |
| | | } |
| | | }, |
| | | }, |
| | | ); |
| | | } |
| | | |
| | | /** éæ¯ææ½æåºå®ä¾ */ |
| | | function destroySortable() { |
| | | if (sortableInstance.value) { |
| | | sortableInstance.value.stop?.(); |
| | | sortableInstance.value = null; |
| | | } |
| | | } |
| | | |
| | | /** å 载工åºå表 */ |
| | | async function getList() { |
| | | gridApi.setLoading(true); |
| | | try { |
| | | if (isCreateMode.value) { |
| | | // æ°å¢æ¨¡å¼ï¼ä»å·¥èºè·¯çº¿è·å |
| | | if (!props.productId) { |
| | | list.value = []; |
| | | } else { |
| | | // è°ç¨å·¥èºè·¯çº¿æ¥å£è·åå·¥åºå表 |
| | | const routeProcessList = await getRouteProcessListByProduct(props.productId); |
| | | // 转æ¢ä¸ºå·¥åå·¥åºæ ¼å¼ |
| | | list.value = routeProcessList.map((item) => ({ |
| | | processId: item.processId, |
| | | processCode: item.processCode, |
| | | processName: item.processName, |
| | | sort: item.sort, |
| | | nextProcessId: item.nextProcessId, |
| | | nextProcessName: item.nextProcessName, |
| | | linkType: item.linkType, |
| | | prepareTime: item.prepareTime, |
| | | waitTime: item.waitTime, |
| | | colorCode: item.colorCode, |
| | | keyFlag: item.keyFlag, |
| | | checkFlag: item.checkFlag, |
| | | backflushFlag: item.backflushFlag, |
| | | outputItemId: item.outputItemId, |
| | | outputItemCode: item.outputItemCode, |
| | | outputItemName: item.outputItemName, |
| | | remark: item.remark, |
| | | })); |
| | | } |
| | | } else { |
| | | // ç¼è¾æ¨¡å¼ï¼ä»å·¥åå·¥åºè·å |
| | | if (!props.workOrderId) { |
| | | list.value = []; |
| | | } else { |
| | | list.value = await getWorkOrderProcessListByWorkOrderId(props.workOrderId); |
| | | } |
| | | } |
| | | gridApi.setGridOptions({ data: list.value }); |
| | | emit('processListChange', list.value); |
| | | // åå§åææ½æåº |
| | | initSortable(); |
| | | } finally { |
| | | gridApi.setLoading(false); |
| | | } |
| | | } |
| | | |
| | | /** æ·»å å·¥åº */ |
| | | function handleCreate() { |
| | | processFormModalApi |
| | | .setData({ |
| | | workOrderId: props.workOrderId, |
| | | productId: props.productId || props.workOrder?.productId, |
| | | processList: list.value, |
| | | }) |
| | | .open(); |
| | | } |
| | | |
| | | /** ç¼è¾å·¥åº */ |
| | | function handleEdit(row: MesProWorkOrderProcessApi.WorkOrderProcess) { |
| | | processFormModalApi |
| | | .setData({ |
| | | id: row.id, |
| | | workOrderId: props.workOrderId, |
| | | productId: props.productId || props.workOrder?.productId, |
| | | row, |
| | | processList: list.value, |
| | | }) |
| | | .open(); |
| | | } |
| | | |
| | | /** æ°å¢/ç¼è¾æååè° */ |
| | | function handleFormSuccess(data: MesProWorkOrderProcessApi.WorkOrderProcess, isEdit: boolean) { |
| | | if (isCreateMode.value) { |
| | | if (isEdit) { |
| | | const index = list.value.findIndex((item) => item.processId === data.processId); |
| | | if (index > -1) { |
| | | list.value[index] = data; |
| | | } |
| | | } else { |
| | | list.value.push(data); |
| | | } |
| | | gridApi.setGridOptions({ data: list.value }); |
| | | emit('processListChange', list.value); |
| | | initSortable(); |
| | | } else { |
| | | getList(); |
| | | } |
| | | } |
| | | |
| | | /** å é¤å·¥åº */ |
| | | function handleDelete(row: MesProWorkOrderProcessApi.WorkOrderProcess) { |
| | | if (isCreateMode.value) { |
| | | // æ°å¢æ¨¡å¼ï¼ä»å表å é¤ |
| | | const index = list.value.findIndex((item) => item.processId === row.processId); |
| | | if (index > -1) { |
| | | list.value.splice(index, 1); |
| | | // æ´æ° sort åæ®µ |
| | | list.value.forEach((item, idx) => { |
| | | item.sort = idx + 1; |
| | | }); |
| | | gridApi.setGridOptions({ data: list.value }); |
| | | emit('processListChange', list.value); |
| | | initSortable(); |
| | | } |
| | | } else { |
| | | // ç¼è¾æ¨¡å¼ï¼è°ç¨æ¥å£å é¤ |
| | | deleteWorkOrderProcess(row.id!).then(() => { |
| | | message.success($t('ui.actionMessage.deleteSuccess', [row.processName])); |
| | | getList(); |
| | | }); |
| | | } |
| | | } |
| | | |
| | | // ç»ä»¶å¸è½½æ¶éæ¯æåºå®ä¾ |
| | | onUnmounted(() => { |
| | | destroySortable(); |
| | | }); |
| | | |
| | | // çå¬äº§å/å·¥ååå |
| | | watch( |
| | | () => [props.productId, props.workOrderId], |
| | | () => { |
| | | getList(); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | </script> |
| | | |
| | | <template> |
| | | <div class="workorder-process-list"> |
| | | <ProcessFormModal @success="handleFormSuccess" /> |
| | | <div v-if="isEditable" class="mb-3 flex items-center justify-start"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'æ·»å å·¥åº', |
| | | type: 'primary', |
| | | onClick: handleCreate, |
| | | }, |
| | | ]" |
| | | /> |
| | | </div> |
| | | <Grid class="w-full" table-title="å·¥åº"> |
| | | <template #dragHandle> |
| | | <IconifyIcon |
| | | icon="ic:round-drag-indicator" |
| | | class="drag-handle cursor-move text-xl text-gray-400" |
| | | /> |
| | | </template> |
| | | <template #keyFlag="{ row }"> |
| | | <Tag v-if="row.keyFlag" color="red">å
³é®</Tag> |
| | | <span v-else>-</span> |
| | | </template> |
| | | <template #checkFlag="{ row }"> |
| | | <Tag v-if="row.checkFlag" color="blue">è´¨æ£</Tag> |
| | | <span v-else>-</span> |
| | | </template> |
| | | <template #backflushFlag="{ row }"> |
| | | <Tag v-if="row.backflushFlag" color="green">æ¯</Tag> |
| | | <Tag v-else color="default">å¦</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | ifShow: isEditable, |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | ifShow: isEditable, |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.processName]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </div> |
| | | </template> |