修复:
生产领料后的退料应该是选择领料的记录,不是选择库存的记录(同时库存数据需要根据领料退料变动,比如库存100,领用80,然后领用80中退料30,库存应由原来的20变成50)
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | export { default as WmProductIssueLineSelect } from './select.vue'; |
| | | export { default as WmProductIssueLineSelectDialog } from './select-dialog.vue'; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesWmProductIssueLineApi } from '#/api/mes/wm/productissue/line'; |
| | | |
| | | import { nextTick, ref } from 'vue'; |
| | | |
| | | import { message, Modal } from 'ant-design-vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getReturnableIssueLines } from '#/api/mes/wm/productissue/line'; |
| | | |
| | | const props = defineProps<{ |
| | | workOrderId?: number; |
| | | }>(); |
| | | |
| | | const emit = defineEmits<{ |
| | | selected: [rows: MesWmProductIssueLineApi.ProductIssueLine[]]; |
| | | }>(); |
| | | |
| | | const open = ref(false); |
| | | const selectedRows = ref<MesWmProductIssueLineApi.ProductIssueLine[]>([]); |
| | | |
| | | const columns: VxeTableGridOptions<MesWmProductIssueLineApi.ProductIssueLine>['columns'] = [ |
| | | { type: 'radio', width: 60 }, |
| | | { field: 'itemCode', title: 'ç©æç¼ç ', minWidth: 120 }, |
| | | { field: 'itemName', title: 'ç©æåç§°', minWidth: 140 }, |
| | | { field: 'specification', title: 'è§æ ¼åå·', minWidth: 120 }, |
| | | { field: 'unitMeasureName', title: 'åä½', width: 80 }, |
| | | { field: 'quantity', title: 'å¯éæ°é', width: 100 }, |
| | | { field: 'batchCode', title: 'æ¹æ¬¡å·', minWidth: 120 }, |
| | | ]; |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | columns, |
| | | height: 480, |
| | | keepSource: true, |
| | | radioConfig: { highlight: true, trigger: 'row' }, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async () => { |
| | | if (!props.workOrderId) { |
| | | return { list: [], total: 0 }; |
| | | } |
| | | const list = await getReturnableIssueLines(props.workOrderId); |
| | | return { list, total: list.length }; |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | }, |
| | | } as VxeTableGridOptions<MesWmProductIssueLineApi.ProductIssueLine>, |
| | | gridEvents: { |
| | | radioChange: ({ row }: { row: MesWmProductIssueLineApi.ProductIssueLine }) => { |
| | | selectedRows.value = [row]; |
| | | }, |
| | | cellDblclick: async ({ row }: { row: MesWmProductIssueLineApi.ProductIssueLine }) => { |
| | | selectedRows.value = [row]; |
| | | await gridApi.grid.setRadioRow(row); |
| | | handleConfirm(); |
| | | }, |
| | | }, |
| | | }); |
| | | |
| | | async function openModal() { |
| | | open.value = true; |
| | | selectedRows.value = []; |
| | | await nextTick(); |
| | | await gridApi.grid.clearRadioRow(); |
| | | await gridApi.query(); |
| | | } |
| | | |
| | | function closeModal() { |
| | | open.value = false; |
| | | selectedRows.value = []; |
| | | } |
| | | |
| | | function handleConfirm() { |
| | | if (selectedRows.value.length === 0) { |
| | | message.warning('è¯·éæ©ä¸æ¡é¢æè®°å½'); |
| | | return; |
| | | } |
| | | emit('selected', selectedRows.value); |
| | | open.value = false; |
| | | } |
| | | |
| | | defineExpose({ open: openModal }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal |
| | | v-model:open="open" |
| | | :destroy-on-close="true" |
| | | title="éæ©é¢æè®°å½" |
| | | width="70%" |
| | | @cancel="closeModal" |
| | | @ok="handleConfirm" |
| | | > |
| | | <Grid table-title="å¯éæçé¢æè®°å½" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MesWmProductIssueLineApi } from '#/api/mes/wm/productissue/line'; |
| | | |
| | | import { computed, ref, useAttrs, watch } from 'vue'; |
| | | |
| | | import { IconifyIcon } from '@vben/icons'; |
| | | |
| | | import { Input, Tooltip } from 'ant-design-vue'; |
| | | |
| | | import { getProductIssueLine } from '#/api/mes/wm/productissue/line'; |
| | | |
| | | import ProductIssueLineSelectDialog from './select-dialog.vue'; |
| | | |
| | | defineOptions({ name: 'WmProductIssueLineSelect', inheritAttrs: false }); |
| | | |
| | | const props = withDefaults( |
| | | defineProps<{ |
| | | allowClear?: boolean; |
| | | disabled?: boolean; |
| | | modelValue?: number; |
| | | placeholder?: string; |
| | | workOrderId?: number; |
| | | }>(), |
| | | { |
| | | allowClear: true, |
| | | disabled: false, |
| | | modelValue: undefined, |
| | | placeholder: 'è¯·éæ©é¢æè®°å½', |
| | | workOrderId: undefined, |
| | | }, |
| | | ); |
| | | |
| | | const emit = defineEmits<{ |
| | | change: [item: MesWmProductIssueLineApi.ProductIssueLine | undefined]; |
| | | 'update:modelValue': [value: number | undefined]; |
| | | }>(); |
| | | |
| | | const attrs = useAttrs(); |
| | | const dialogRef = ref<InstanceType<typeof ProductIssueLineSelectDialog>>(); |
| | | const hovering = ref(false); |
| | | const selectedItem = ref<MesWmProductIssueLineApi.ProductIssueLine>(); |
| | | |
| | | const displayLabel = computed(() => { |
| | | const item = selectedItem.value; |
| | | if (!item) { |
| | | return ''; |
| | | } |
| | | return `${item.itemCode || '-'} | ${item.itemName || '-'} | æ°é:${item.quantity}`; |
| | | }); |
| | | |
| | | const showClear = computed( |
| | | () => |
| | | props.allowClear && |
| | | !props.disabled && |
| | | hovering.value && |
| | | props.modelValue !== null, |
| | | ); |
| | | |
| | | async function resolveItemById(id: number | undefined) { |
| | | if (!id) { |
| | | selectedItem.value = undefined; |
| | | return; |
| | | } |
| | | if (selectedItem.value?.id === id) { |
| | | return; |
| | | } |
| | | selectedItem.value = await getProductIssueLine(id); |
| | | } |
| | | |
| | | watch(() => props.modelValue, resolveItemById, { immediate: true }); |
| | | |
| | | function clearSelected() { |
| | | selectedItem.value = undefined; |
| | | emit('update:modelValue', undefined); |
| | | emit('change', undefined); |
| | | } |
| | | |
| | | function handleClick(event: MouseEvent) { |
| | | if (props.disabled) { |
| | | return; |
| | | } |
| | | const target = event.target as HTMLElement; |
| | | if (showClear.value && target.closest('.ant-input-suffix')) { |
| | | event.stopPropagation(); |
| | | clearSelected(); |
| | | return; |
| | | } |
| | | dialogRef.value?.open(); |
| | | } |
| | | |
| | | function handleSelected(rows: MesWmProductIssueLineApi.ProductIssueLine[]) { |
| | | const item = rows[0]; |
| | | if (!item) { |
| | | return; |
| | | } |
| | | selectedItem.value = item; |
| | | emit('update:modelValue', item.id); |
| | | emit('change', item); |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <div |
| | | v-bind="attrs" |
| | | class="w-full" |
| | | :class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'" |
| | | @click="handleClick" |
| | | @mouseenter="hovering = true" |
| | | @mouseleave="hovering = false" |
| | | > |
| | | <Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false"> |
| | | <template #title> |
| | | <div v-if="selectedItem" class="leading-6"> |
| | | <div>ç©æç¼ç ï¼{{ selectedItem.itemCode || '-' }}</div> |
| | | <div>ç©æåç§°ï¼{{ selectedItem.itemName || '-' }}</div> |
| | | <div>è§æ ¼åå·ï¼{{ selectedItem.specification || '-' }}</div> |
| | | <div>å¯éæ°éï¼{{ selectedItem.quantity ?? '-' }}</div> |
| | | <div>æ¹æ¬¡å·ï¼{{ selectedItem.batchCode || '-' }}</div> |
| | | </div> |
| | | </template> |
| | | <Input |
| | | :disabled="disabled" |
| | | :placeholder="placeholder" |
| | | :value="displayLabel" |
| | | readonly |
| | | > |
| | | <template #suffix> |
| | | <IconifyIcon |
| | | class="size-4" |
| | | :icon="showClear ? 'lucide:circle-x' : 'lucide:search'" |
| | | /> |
| | | </template> |
| | | </Input> |
| | | </Tooltip> |
| | | </div> |
| | | <ProductIssueLineSelectDialog |
| | | ref="dialogRef" |
| | | :work-order-id="workOrderId" |
| | | @selected="handleSelected" |
| | | /> |
| | | </template> |