zhou zhou
昨天 d4e039545c9e97347223eb415fbba85ee01bc263
rsf-design/src/views/orders/transfer/modules/transfer-dialog.vue
@@ -1,36 +1,226 @@
<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(() => [
@@ -84,7 +274,10 @@
      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 }
        ]
      }
    },
    {
@@ -101,38 +294,110 @@
    }
  ])
  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?.()
        })
@@ -145,44 +410,9 @@
    () => 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>