| | |
| | | <template> |
| | | <ElDialog |
| | | :model-value="visible" |
| | | :title="dialogTitle" |
| | | width="92%" |
| | | top="4vh" |
| | | destroy-on-close |
| | | @update:model-value="handleVisibleChange" |
| | | @closed="handleClosed" |
| | | > |
| | | <div class="flex flex-col gap-4"> |
| | | <ArtForm |
| | | ref="formRef" |
| | | v-model="form" |
| | | :items="formItems" |
| | | :rules="rules" |
| | | :span="8" |
| | | :gutter="20" |
| | | label-width="110px" |
| | | :show-reset="false" |
| | | :show-submit="false" |
| | | /> |
| | | |
| | | <div class="flex flex-wrap items-center justify-between gap-3"> |
| | | <ElSpace wrap> |
| | | <ElButton type="primary" @click="handleOpenMaterialDialog"> |
| | | {{ t('pages.orders.transfer.dialog.addMaterial') }} |
| | | </ElButton> |
| | | <ElButton |
| | | type="danger" |
| | | plain |
| | | :disabled="isEdit || selectedItemKeys.length === 0" |
| | | @click="handleBatchRemove" |
| | | > |
| | | {{ t('pages.orders.transfer.dialog.deleteSelected') }} |
| | | </ElButton> |
| | | </ElSpace> |
| | | <div class="text-xs text-[var(--art-gray-600)]"> |
| | | {{ t('pages.orders.transfer.dialog.itemCount', { count: itemRows.length }) }} |
| | | </div> |
| | | </div> |
| | | |
| | | <ElTable |
| | | :data="itemRows" |
| | | row-key="__rowKey" |
| | | border |
| | | size="small" |
| | | max-height="420" |
| | | @selection-change="handleItemSelectionChange" |
| | | > |
| | | <ElTableColumn type="selection" width="48" align="center" /> |
| | | <ElTableColumn type="index" :label="t('table.index')" width="72" align="center" /> |
| | | <ElTableColumn |
| | | prop="matnrCode" |
| | | :label="t('table.materialCode')" |
| | | min-width="140" |
| | | show-overflow-tooltip |
| | | /> |
| | | <ElTableColumn |
| | | prop="maktx" |
| | | :label="t('table.materialName')" |
| | | min-width="220" |
| | | show-overflow-tooltip |
| | | /> |
| | | <ElTableColumn |
| | | prop="spec" |
| | | :label="t('pages.orders.transferItem.table.spec')" |
| | | min-width="140" |
| | | show-overflow-tooltip |
| | | /> |
| | | <ElTableColumn |
| | | prop="model" |
| | | :label="t('pages.orders.transferItem.table.model')" |
| | | min-width="140" |
| | | show-overflow-tooltip |
| | | /> |
| | | <ElTableColumn :label="t('table.quantity')" width="150" align="right"> |
| | | <template #default="{ row }"> |
| | | <ElInputNumber |
| | | v-model="row.anfme" |
| | | :min="0" |
| | | :precision="2" |
| | | controls-position="right" |
| | | class="w-full" |
| | | /> |
| | | </template> |
| | | </ElTableColumn> |
| | | <ElTableColumn |
| | | :label="t('pages.orders.transfer.dialog.supplierCode')" |
| | | min-width="150" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="{ row }"> |
| | | <ElInput v-model="row.splrCode" clearable /> |
| | | </template> |
| | | </ElTableColumn> |
| | | <ElTableColumn |
| | | :label="t('pages.orders.transfer.dialog.supplierName')" |
| | | min-width="180" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="{ row }"> |
| | | <ElInput v-model="row.splrName" clearable /> |
| | | </template> |
| | | </ElTableColumn> |
| | | <ElTableColumn :label="t('table.batch')" min-width="140" show-overflow-tooltip> |
| | | <template #default="{ row }"> |
| | | <ElInput v-model="row.batch" clearable /> |
| | | </template> |
| | | </ElTableColumn> |
| | | <ElTableColumn :label="t('table.unit')" width="120" align="center"> |
| | | <template #default="{ row }"> |
| | | <ElInput v-model="row.unit" clearable /> |
| | | </template> |
| | | </ElTableColumn> |
| | | <ElTableColumn |
| | | v-for="field in fieldDefinitions" |
| | | :key="field.fields" |
| | | :label="field.fieldsAlise || field.fields" |
| | | min-width="140" |
| | | > |
| | | <template #default="{ row }"> |
| | | <ElInput v-model="row[field.fields]" clearable /> |
| | | </template> |
| | | </ElTableColumn> |
| | | <ElTableColumn :label="t('table.operation')" fixed="right" width="88" align="center"> |
| | | <template #default="{ row }"> |
| | | <ElButton link type="danger" :disabled="isEdit" @click="handleRemoveRow(row)"> |
| | | {{ t('pages.orders.transfer.actions.delete') }} |
| | | </ElButton> |
| | | </template> |
| | | </ElTableColumn> |
| | | </ElTable> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <ElSpace> |
| | | <ElButton @click="handleVisibleChange(false)">{{ t('common.cancel') }}</ElButton> |
| | | <ElButton type="primary" :loading="submitLoading" @click="handleSubmit"> |
| | | {{ t('common.confirm') }} |
| | | </ElButton> |
| | | </ElSpace> |
| | | </template> |
| | | |
| | | <TransferMaterialDialog |
| | | v-model:visible="materialDialogVisible" |
| | | :org-area-id="form.orgAreaId" |
| | | :field-definitions="fieldDefinitions" |
| | | :selected-matnr-ids="selectedMatnrIds" |
| | | @confirm="handleMaterialConfirm" |
| | | /> |
| | | </ElDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, nextTick, reactive, ref, watch } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { useI18n } from 'vue-i18n' |
| | | import ArtForm from '@/components/core/forms/art-form/index.vue' |
| | | import { |
| | | buildTransferDialogModel, |
| | | createTransferFormState, |
| | | getTransferStatusOptions |
| | | buildTransferManageDialogModel, |
| | | createTransferEditableItemFromMaterial, |
| | | createTransferFormState |
| | | } from '../transferPage.helpers.js' |
| | | import TransferMaterialDialog from './transfer-material-dialog.vue' |
| | | |
| | | const props = defineProps({ |
| | | visible: { type: Boolean, default: false }, |
| | | dialogType: { type: String, default: 'add' }, |
| | | transferData: { type: Object, default: () => ({}) }, |
| | | transferData: { |
| | | type: Object, |
| | | default: () => ({ |
| | | transfer: {}, |
| | | items: [] |
| | | }) |
| | | }, |
| | | typeOptions: { type: Array, default: () => [] }, |
| | | areaOptions: { type: Array, default: () => [] }, |
| | | fieldDefinitions: { type: Array, default: () => [] }, |
| | | submitLoading: { type: Boolean, default: false } |
| | | }) |
| | | |
| | | const emit = defineEmits(['update:visible', 'submit']) |
| | | const { t } = useI18n() |
| | | |
| | | const formRef = ref() |
| | | const form = reactive(createTransferFormState()) |
| | | const { t } = useI18n() |
| | | const itemRows = ref([]) |
| | | const selectedItemKeys = ref([]) |
| | | const materialDialogVisible = ref(false) |
| | | |
| | | const isEdit = computed(() => props.dialogType === 'edit') |
| | | const dialogTitle = computed(() => |
| | | isEdit.value ? t('pages.orders.transfer.dialog.titleEdit') : t('pages.orders.transfer.dialog.titleAdd') |
| | | isEdit.value |
| | | ? t('pages.orders.transfer.dialog.titleEdit') |
| | | : t('pages.orders.transfer.dialog.titleAdd') |
| | | ) |
| | | const selectedMatnrIds = computed(() => |
| | | itemRows.value.map((item) => item.matnrId).filter((item) => item !== undefined && item !== null) |
| | | ) |
| | | |
| | | const rules = computed(() => ({ |
| | | type: [{ required: true, message: t('pages.orders.transfer.dialog.validation.type'), trigger: 'change' }], |
| | | orgAreaId: [{ required: true, message: t('pages.orders.transfer.dialog.validation.orgAreaId'), trigger: 'change' }], |
| | | tarAreaId: [{ required: true, message: t('pages.orders.transfer.dialog.validation.tarAreaId'), trigger: 'change' }] |
| | | type: [ |
| | | { |
| | | required: true, |
| | | message: t('pages.orders.transfer.dialog.validation.type'), |
| | | trigger: 'change' |
| | | } |
| | | ], |
| | | orgAreaId: [ |
| | | { |
| | | required: true, |
| | | message: t('pages.orders.transfer.dialog.validation.orgAreaId'), |
| | | trigger: 'change' |
| | | } |
| | | ], |
| | | tarAreaId: [ |
| | | { |
| | | required: true, |
| | | message: t('pages.orders.transfer.dialog.validation.tarAreaId'), |
| | | trigger: 'change' |
| | | } |
| | | ] |
| | | })) |
| | | |
| | | const formItems = computed(() => [ |
| | |
| | | props: { |
| | | placeholder: t('pages.orders.transfer.dialog.placeholderStatus'), |
| | | clearable: true, |
| | | options: getTransferStatusOptions() |
| | | options: [ |
| | | { label: t('pages.orders.transfer.status.normal'), value: 1 }, |
| | | { label: t('pages.orders.transfer.status.frozen'), value: 0 } |
| | | ] |
| | | } |
| | | }, |
| | | { |
| | |
| | | } |
| | | ]) |
| | | |
| | | const loadFormData = () => { |
| | | Object.assign(form, buildTransferDialogModel(props.transferData)) |
| | | function loadDialogData() { |
| | | const dialogData = buildTransferManageDialogModel(props.transferData, props.fieldDefinitions) |
| | | Object.assign(form, dialogData.transfer) |
| | | itemRows.value = dialogData.items |
| | | selectedItemKeys.value = [] |
| | | } |
| | | |
| | | const resetForm = () => { |
| | | function resetDialogData() { |
| | | Object.assign(form, createTransferFormState()) |
| | | itemRows.value = [] |
| | | selectedItemKeys.value = [] |
| | | materialDialogVisible.value = false |
| | | formRef.value?.clearValidate?.() |
| | | } |
| | | |
| | | const handleSubmit = async () => { |
| | | function handleItemSelectionChange(rows) { |
| | | selectedItemKeys.value = Array.isArray(rows) ? rows.map((item) => item.__rowKey) : [] |
| | | } |
| | | |
| | | function handleRemoveRow(row) { |
| | | itemRows.value = itemRows.value.filter((item) => item.__rowKey !== row.__rowKey) |
| | | selectedItemKeys.value = selectedItemKeys.value.filter((item) => item !== row.__rowKey) |
| | | } |
| | | |
| | | function handleBatchRemove() { |
| | | if (!selectedItemKeys.value.length) return |
| | | const selectedKeySet = new Set(selectedItemKeys.value) |
| | | itemRows.value = itemRows.value.filter((item) => !selectedKeySet.has(item.__rowKey)) |
| | | selectedItemKeys.value = [] |
| | | } |
| | | |
| | | function handleOpenMaterialDialog() { |
| | | if (!form.orgAreaId) { |
| | | ElMessage.warning(t('pages.orders.transfer.dialog.validation.orgAreaId')) |
| | | return |
| | | } |
| | | if (!form.tarAreaId) { |
| | | ElMessage.warning(t('pages.orders.transfer.dialog.validation.tarAreaId')) |
| | | return |
| | | } |
| | | materialDialogVisible.value = true |
| | | } |
| | | |
| | | function handleMaterialConfirm(rows) { |
| | | const existingMatnrIds = new Set(selectedMatnrIds.value) |
| | | const nextRows = rows |
| | | .map((item) => createTransferEditableItemFromMaterial(item, props.fieldDefinitions)) |
| | | .filter((item) => !existingMatnrIds.has(item.matnrId)) |
| | | |
| | | if (!nextRows.length) { |
| | | ElMessage.warning(t('pages.orders.transfer.dialog.materialDuplicate')) |
| | | return |
| | | } |
| | | |
| | | itemRows.value = [...itemRows.value, ...nextRows] |
| | | } |
| | | |
| | | function validateItems() { |
| | | if (!itemRows.value.length) { |
| | | ElMessage.warning(t('pages.orders.transfer.dialog.validation.items')) |
| | | return false |
| | | } |
| | | |
| | | const invalidRow = itemRows.value.find((item) => Number(item.anfme) <= 0) |
| | | if (invalidRow) { |
| | | ElMessage.warning(t('pages.orders.transfer.dialog.validation.anfme')) |
| | | return false |
| | | } |
| | | |
| | | return true |
| | | } |
| | | |
| | | async function handleSubmit() { |
| | | if (!formRef.value) return |
| | | |
| | | try { |
| | | await formRef.value.validate() |
| | | emit('submit', { ...form }) |
| | | } catch { |
| | | return |
| | | } |
| | | |
| | | if (!validateItems()) { |
| | | return |
| | | } |
| | | |
| | | emit('submit', { |
| | | transfer: { ...form }, |
| | | items: itemRows.value.map((item) => ({ ...item })) |
| | | }) |
| | | } |
| | | |
| | | const handleCancel = () => { |
| | | emit('update:visible', false) |
| | | function handleVisibleChange(visible) { |
| | | emit('update:visible', visible) |
| | | } |
| | | |
| | | const handleClosed = () => { |
| | | resetForm() |
| | | function handleClosed() { |
| | | resetDialogData() |
| | | } |
| | | |
| | | watch( |
| | | () => props.visible, |
| | | (visible) => { |
| | | if (visible) { |
| | | loadFormData() |
| | | loadDialogData() |
| | | nextTick(() => { |
| | | formRef.value?.clearValidate?.() |
| | | }) |
| | |
| | | () => props.transferData, |
| | | () => { |
| | | if (props.visible) { |
| | | loadFormData() |
| | | loadDialogData() |
| | | } |
| | | }, |
| | | { deep: true } |
| | | ) |
| | | </script> |
| | | |
| | | <template> |
| | | <ElDialog |
| | | :title="dialogTitle" |
| | | :model-value="visible" |
| | | width="760px" |
| | | align-center |
| | | destroy-on-close |
| | | @update:model-value="handleCancel" |
| | | @closed="handleClosed" |
| | | > |
| | | <div class="mb-3 rounded-lg border border-[var(--art-border-color)] bg-[var(--art-bg-color)] px-3 py-2 text-xs text-[var(--art-text-gray-600)]"> |
| | | {{ t('pages.orders.transfer.dialog.tip') }} |
| | | </div> |
| | | |
| | | <ArtForm |
| | | ref="formRef" |
| | | v-model="form" |
| | | :items="formItems" |
| | | :rules="rules" |
| | | :span="12" |
| | | :gutter="20" |
| | | label-width="110px" |
| | | :show-reset="false" |
| | | :show-submit="false" |
| | | /> |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <ElButton @click="handleCancel">{{ t('common.cancel') }}</ElButton> |
| | | <ElButton type="primary" :loading="submitLoading" @click="handleSubmit">{{ t('common.confirm') }}</ElButton> |
| | | </span> |
| | | </template> |
| | | </ElDialog> |
| | | </template> |