zhou zhou
2 天以前 d4e039545c9e97347223eb415fbba85ee01bc263
rsf-design/src/views/orders/transfer/index.vue
@@ -12,7 +12,9 @@
      <ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="refreshData">
        <template #left>
          <ElSpace wrap>
            <ElButton v-if="canCreate" type="primary" @click="showDialog('add')" v-ripple>{{ t('pages.orders.transfer.actions.add') }}</ElButton>
            <ElButton v-if="canCreate" type="primary" @click="showDialog('add')" v-ripple>{{
              t('pages.orders.transfer.actions.add')
            }}</ElButton>
            <ElButton
              v-if="canDelete"
              type="danger"
@@ -57,6 +59,7 @@
        :transfer-data="currentTransferData"
        :type-options="typeOptions"
        :area-options="areaOptions"
        :field-definitions="fieldDefinitions"
        :submit-loading="dialogSubmitting"
        @submit="handleDialogSubmit"
      />
@@ -68,6 +71,7 @@
        :detail="detailData"
        :order-rows="detailOrderRows"
        :order-pagination="detailOrderPagination"
        :on-order-view="handleViewRelatedOrder"
        @size-change="handleDetailSizeChange"
        @current-change="handleDetailCurrentChange"
      />
@@ -90,16 +94,18 @@
  import { guardRequestWithMessage } from '@/utils/sys/requestGuard'
  import { fetchDictDataPage } from '@/api/system-manage'
  import { fetchWarehouseAreasList } from '@/api/warehouse-areas'
  import { fetchTransferItemList } from '@/api/transfer-item'
  import {
    fetchDeleteTransfer,
    fetchEnabledTransferFields,
    fetchExportTransferReport,
    fetchTransferDetail,
    fetchTransferMany,
    fetchSaveTransferItems,
    fetchTransferOrdersPage,
    fetchTransferPage,
    fetchTransferPubOutStock,
    fetchSaveTransfer,
    fetchUpdateTransfer
    fetchUpdateTransferItems
  } from '@/api/transfer'
  import TransferDialog from './modules/transfer-dialog.vue'
  import TransferDetailDrawer from './modules/transfer-detail-drawer.vue'
@@ -107,11 +113,11 @@
  import {
    TRANSFER_REPORT_STYLE,
    buildTransferDetailOrderQueryParams,
    buildTransferDialogModel,
    buildTransferItemsSavePayload,
    buildTransferManageDialogModel,
    buildTransferPageQueryParams,
    buildTransferPrintRows,
    buildTransferReportMeta,
    buildTransferSavePayload,
    buildTransferSearchParams,
    createTransferFormState,
    createTransferSearchState,
@@ -138,6 +144,7 @@
  const searchForm = ref(createTransferSearchState())
  const typeOptions = ref([])
  const areaOptions = ref([])
  const fieldDefinitions = ref([])
  const selectedRows = ref([])
  const detailDrawerVisible = ref(false)
  const detailLoading = ref(false)
@@ -159,8 +166,18 @@
  const reportQueryParams = computed(() => buildTransferSearchParams(searchForm.value))
  const searchItems = computed(() => [
    { label: t('pages.orders.transfer.search.condition'), key: 'condition', type: 'input', props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.condition') } },
    { label: t('pages.orders.transfer.search.code'), key: 'code', type: 'input', props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.code') } },
    {
      label: t('pages.orders.transfer.search.condition'),
      key: 'condition',
      type: 'input',
      props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.condition') }
    },
    {
      label: t('pages.orders.transfer.search.code'),
      key: 'code',
      type: 'input',
      props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.code') }
    },
    {
      label: t('pages.orders.transfer.search.type'),
      key: 'type',
@@ -179,17 +196,94 @@
      type: 'select',
      props: { clearable: true, options: getTransferExceStatusOptions(t) }
    },
    { label: t('pages.orders.transfer.search.orgWareName'), key: 'orgWareName', type: 'input', props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.orgWareName') } },
    { label: t('pages.orders.transfer.search.tarWareName'), key: 'tarWareName', type: 'input', props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.tarWareName') } },
    { label: t('pages.orders.transfer.search.orgAreaName'), key: 'orgAreaName', type: 'input', props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.orgAreaName') } },
    { label: t('pages.orders.transfer.search.tarAreaName'), key: 'tarAreaName', type: 'input', props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.tarAreaName') } },
    {
      label: t('pages.orders.transfer.search.timeStart'),
      key: 'timeStart',
      type: 'date',
      props: { clearable: true, type: 'date', valueFormat: 'YYYY-MM-DD' }
    },
    {
      label: t('pages.orders.transfer.search.timeEnd'),
      key: 'timeEnd',
      type: 'date',
      props: { clearable: true, type: 'date', valueFormat: 'YYYY-MM-DD' }
    },
    {
      label: t('pages.orders.transfer.search.orgWareId'),
      key: 'orgWareId',
      type: 'inputNumber',
      props: {
        clearable: true,
        controlsPosition: 'right',
        placeholder: t('pages.orders.transfer.placeholder.orgWareId')
      }
    },
    {
      label: t('pages.orders.transfer.search.orgWareName'),
      key: 'orgWareName',
      type: 'input',
      props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.orgWareName') }
    },
    {
      label: t('pages.orders.transfer.search.tarWareId'),
      key: 'tarWareId',
      type: 'inputNumber',
      props: {
        clearable: true,
        controlsPosition: 'right',
        placeholder: t('pages.orders.transfer.placeholder.tarWareId')
      }
    },
    {
      label: t('pages.orders.transfer.search.tarWareName'),
      key: 'tarWareName',
      type: 'input',
      props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.tarWareName') }
    },
    {
      label: t('pages.orders.transfer.search.orgAreaId'),
      key: 'orgAreaId',
      type: 'inputNumber',
      props: {
        clearable: true,
        controlsPosition: 'right',
        placeholder: t('pages.orders.transfer.placeholder.orgAreaId')
      }
    },
    {
      label: t('pages.orders.transfer.search.orgAreaName'),
      key: 'orgAreaName',
      type: 'input',
      props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.orgAreaName') }
    },
    {
      label: t('pages.orders.transfer.search.tarAreaId'),
      key: 'tarAreaId',
      type: 'inputNumber',
      props: {
        clearable: true,
        controlsPosition: 'right',
        placeholder: t('pages.orders.transfer.placeholder.tarAreaId')
      }
    },
    {
      label: t('pages.orders.transfer.search.tarAreaName'),
      key: 'tarAreaName',
      type: 'input',
      props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.tarAreaName') }
    },
    {
      label: t('pages.orders.transfer.search.status'),
      key: 'status',
      type: 'select',
      props: { clearable: true, options: getTransferStatusOptions(t) }
    },
    { label: t('pages.orders.transfer.search.memo'), key: 'memo', type: 'input', props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.memo') } }
    {
      label: t('pages.orders.transfer.search.memo'),
      key: 'memo',
      type: 'input',
      props: { clearable: true, placeholder: t('pages.orders.transfer.placeholder.memo') }
    }
  ])
  function handleSelectionChange(rows) {
@@ -211,24 +305,32 @@
    }
  }
  async function loadTransferOrders(code) {
  async function loadTransferOrders(transferId, code) {
    detailOrdersLoading.value = true
    try {
      const response = await guardRequestWithMessage(
        fetchTransferOrdersPage(
          buildTransferDetailOrderQueryParams({
            id: transferId,
            code,
            current: detailOrderPagination.current,
            pageSize: detailOrderPagination.size
          })
        ),
        { records: [], total: 0, current: detailOrderPagination.current, size: detailOrderPagination.size },
        {
          records: [],
          total: 0,
          current: detailOrderPagination.current,
          size: detailOrderPagination.size
        },
        { timeoutMessage: t('pages.orders.transfer.messages.ordersTimeout') }
      )
      const normalized = defaultResponseAdapter(response)
      detailOrderRows.value = normalized.records.map((item) => normalizeTransferOrderRow(item, t))
      detailOrderPagination.total = Number(normalized.total || 0)
      detailOrderPagination.current = Number(normalized.current || detailOrderPagination.current || 1)
      detailOrderPagination.current = Number(
        normalized.current || detailOrderPagination.current || 1
      )
      detailOrderPagination.size = Number(normalized.size || detailOrderPagination.size || 20)
    } catch (error) {
      detailOrderRows.value = []
@@ -249,7 +351,7 @@
    try {
      await loadTransferDetail(row.id)
      activeTransferCode.value = detailData.value.code || row.code || activeTransferCode.value
      await loadTransferOrders(activeTransferCode.value)
      await loadTransferOrders(row.id, activeTransferCode.value)
    } catch (error) {
      detailDrawerVisible.value = false
      detailData.value = {}
@@ -260,12 +362,23 @@
  async function openEditDialog(row) {
    try {
      const detail = await guardRequestWithMessage(
        fetchTransferDetail(row.id),
        {},
        { timeoutMessage: t('pages.orders.transfer.messages.detailTimeout') }
      )
      showDialog('edit', detail)
      const [detail, itemResponse] = await Promise.all([
        guardRequestWithMessage(
          fetchTransferDetail(row.id),
          {},
          { timeoutMessage: t('pages.orders.transfer.messages.detailTimeout') }
        ),
        guardRequestWithMessage(fetchTransferItemList({ transferId: row.id }), [], {
          timeoutMessage: t('pages.orders.transfer.messages.itemsTimeout')
        })
      ])
      const itemRecords = Array.isArray(itemResponse)
        ? itemResponse
        : defaultResponseAdapter(itemResponse).records
      showDialog('edit', {
        transfer: detail,
        items: itemRecords
      })
    } catch (error) {
      ElMessage.error(error?.message || t('pages.orders.transfer.messages.detailLoadFailed'))
    }
@@ -273,21 +386,23 @@
  async function handlePublish(row) {
    try {
      await ElMessageBox.confirm(t('pages.orders.transfer.messages.publishConfirm', { code: row.code || row.id }), t('pages.orders.transfer.messages.publishTitle'), {
        confirmButtonText: t('common.confirm'),
        cancelButtonText: t('common.cancel'),
        type: 'warning'
      })
      const response = await fetchTransferPubOutStock({ id: row.id })
      if (response?.code !== 200 && response?.success !== true) {
        throw new Error(response?.message || t('pages.orders.transfer.messages.publishFailed'))
      }
      ElMessage.success(response?.message || t('pages.orders.transfer.messages.publishSuccess'))
      await ElMessageBox.confirm(
        t('pages.orders.transfer.messages.publishConfirm', { code: row.code || row.id }),
        t('pages.orders.transfer.messages.publishTitle'),
        {
          confirmButtonText: t('common.confirm'),
          cancelButtonText: t('common.cancel'),
          type: 'warning'
        }
      )
      await fetchTransferPubOutStock({ id: row.id })
      ElMessage.success(t('pages.orders.transfer.messages.publishSuccess'))
      await refreshData()
      if (detailDrawerVisible.value && activeTransferId.value === row.id) {
        await loadTransferDetail(row.id)
        await loadTransferOrders(row.code || activeTransferCode.value)
        await loadTransferOrders(row.id, row.code || activeTransferCode.value)
      }
      router.push('/orders/out-stock')
    } catch (error) {
      if (error === 'cancel' || error?.message === 'cancel') return
      ElMessage.error(error?.message || t('pages.orders.transfer.messages.publishFailed'))
@@ -346,10 +461,15 @@
      apiFn: fetchTransferPage,
      apiParams: buildTransferPageQueryParams(searchForm.value),
      paginationKey: getTransferPaginationKey(),
      columnsFactory: () => createTransferTableColumns({ handleActionClick })
      columnsFactory: () =>
        createTransferTableColumns({
          handleActionClick,
          handleViewOrder: handleViewRelatedOrder
        })
    },
    transform: {
      dataTransformer: (records) => (Array.isArray(records) ? records.map((item) => normalizeTransferRow(item, t)) : [])
      dataTransformer: (records) =>
        Array.isArray(records) ? records.map((item) => normalizeTransferRow(item, t)) : []
    }
  })
@@ -357,18 +477,21 @@
    dialogVisible,
    dialogType,
    currentRecord: currentTransferData,
    selectedRows: crudSelectedRows,
    handleSelectionChange: handleCrudSelectionChange,
    showDialog,
    handleDialogSubmit: handleCrudDialogSubmit,
    handleDelete,
    handleBatchDelete
  } = useCrudPage({
    createEmptyModel: () => createTransferFormState(),
    buildEditModel: (record) => buildTransferDialogModel(record),
    buildSavePayload: (formData) => buildTransferSavePayload(formData, areaOptions.value),
    saveRequest: fetchSaveTransfer,
    updateRequest: fetchUpdateTransfer,
    createEmptyModel: () => ({
      transfer: createTransferFormState(),
      items: []
    }),
    buildEditModel: (record) => buildTransferManageDialogModel(record, fieldDefinitions.value),
    buildSavePayload: (formData) =>
      buildTransferItemsSavePayload(formData, areaOptions.value, fieldDefinitions.value),
    saveRequest: fetchSaveTransferItems,
    updateRequest: fetchUpdateTransferItems,
    deleteRequest: fetchDeleteTransfer,
    entityName: t('pages.orders.transfer.entity'),
    resolveRecordLabel: (record) => record?.code || record?.id,
@@ -387,7 +510,12 @@
  async function loadTypeOptions() {
    const response = await guardRequestWithMessage(
      fetchDictDataPage({ current: 1, pageSize: 200, dictTypeCode: 'sys_transfer_type', status: 1 }),
      fetchDictDataPage({
        current: 1,
        pageSize: 200,
        dictTypeCode: 'sys_transfer_type',
        status: 1
      }),
      { records: [] },
      { timeoutMessage: t('pages.orders.transfer.messages.typeOptionsTimeout') }
    )
@@ -403,6 +531,23 @@
    areaOptions.value = resolveTransferAreaOptions(defaultResponseAdapter(response).records)
  }
  async function loadFieldDefinitions() {
    const records = await guardRequestWithMessage(fetchEnabledTransferFields(), [], {
      timeoutMessage: t('pages.orders.transfer.messages.fieldTimeout')
    })
    fieldDefinitions.value = Array.isArray(records) ? records : []
  }
  function handleViewRelatedOrder(row) {
    if (row?.type === 'out') {
      router.push('/orders/out-stock')
      return
    }
    if (row?.type === 'in') {
      router.push('/orders/asn-order')
    }
  }
  function handleSearch(params) {
    searchForm.value = { ...searchForm.value, ...params }
    replaceSearchParams(buildTransferSearchParams(searchForm.value))
@@ -416,13 +561,13 @@
  async function handleDetailCurrentChange(current) {
    detailOrderPagination.current = current
    await loadTransferOrders(activeTransferCode.value)
    await loadTransferOrders(activeTransferId.value, activeTransferCode.value)
  }
  async function handleDetailSizeChange(size) {
    detailOrderPagination.size = size
    detailOrderPagination.current = 1
    await loadTransferOrders(activeTransferCode.value)
    await loadTransferOrders(activeTransferId.value, activeTransferCode.value)
  }
  const resolvePrintRecords = async (payload) => {
@@ -433,7 +578,8 @@
      await fetchTransferPage({
        ...reportQueryParams.value,
        current: 1,
        pageSize: Number(pagination.total) > 0 ? Number(pagination.total) : Number(payload?.pageSize) || 20
        pageSize:
          Number(pagination.total) > 0 ? Number(pagination.total) : Number(payload?.pageSize) || 20
      })
    ).records
  }
@@ -448,11 +594,14 @@
  } = usePrintExportPage({
    downloadFileName: 'transfer.xlsx',
    requestExport: (payload) =>
      fetchExportTransferReport(Array.isArray(payload?.ids) && payload.ids.length > 0 ? reportQueryParams.value : payload, {
        headers: {
          Authorization: userStore.accessToken || ''
      fetchExportTransferReport(
        Array.isArray(payload?.ids) && payload.ids.length > 0 ? reportQueryParams.value : payload,
        {
          headers: {
            Authorization: userStore.accessToken || ''
          }
        }
      }),
      ),
    resolvePrintRecords,
    buildPreviewRows: (records) => buildTransferPrintRows(records, t),
    buildPreviewMeta: (rows) => {
@@ -478,12 +627,13 @@
    buildTransferReportMeta({
      previewMeta: rawPreviewMeta.value,
      count: previewRows.value.length,
      orientation: rawPreviewMeta.value?.reportStyle?.orientation || TRANSFER_REPORT_STYLE.orientation,
      orientation:
        rawPreviewMeta.value?.reportStyle?.orientation || TRANSFER_REPORT_STYLE.orientation,
      t
    })
  )
  onMounted(async () => {
    await Promise.allSettled([loadTypeOptions(), loadAreaOptions()])
    await Promise.allSettled([loadTypeOptions(), loadAreaOptions(), loadFieldDefinitions()])
  })
</script>