gaoluyang
2026-07-10 57295febd254991c01eff2345ba293b89287689d
银川
1.仓储物流页面开发、联调
2.项目配置修改
已添加2个文件
已修改16个文件
714 ■■■■ 文件已修改
.idea/mom-pro2-before.iml 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mes/wm/arrivalnotice/index.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mes/wm/itemreceipt/index.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mes/wm/returnvendor/index.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes/modules/mes.ts 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/md/vendor/components/select.vue 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/arrivalnotice/data.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/arrivalnotice/index.vue 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/arrivalnotice/modules/po-select-dialog.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/barcode/components/detail.vue 139 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/itemreceipt/index.vue 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/itemreceipt/modules/an-select-dialog.vue 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/itemreceipt/modules/form.vue 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/returnvendor/data.ts 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/warehouse/area/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/warehouse/index.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/warehouse/location/index.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/mom-pro2-before.iml
@@ -1,7 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
  <component name="NewModuleRootManager">
    <content url="file://$MODULE_DIR$" />
    <content url="file://$MODULE_DIR$">
      <excludeFolder url="file://$MODULE_DIR$/node_modules" />
      <excludeFolder url="file://$MODULE_DIR$/.pnpm" />
      <excludeFolder url="file://$MODULE_DIR$/.vite" />
      <excludeFolder url="file://$MODULE_DIR$/.cache" />
      <excludeFolder url="file://$MODULE_DIR$/dist" />
      <excludeFolder url="file://$MODULE_DIR$/build" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
src/api/mes/wm/arrivalnotice/index.ts
@@ -62,3 +62,10 @@
    params,
  });
}
/** æ ¹æ®é‡‡è´­è®¢å•生成到货通知单 */
export function generateArrivalNoticeFromPurchaseOrder(purchaseOrderId: number) {
  return requestClient.post<number>(
    `/mes/wm/arrival-notice/generate-from-purchase-order?purchaseOrderId=${purchaseOrderId}`,
  );
}
src/api/mes/wm/itemreceipt/index.ts
@@ -84,3 +84,20 @@
    params,
  });
}
/** æ ¹æ®åˆ°è´§é€šçŸ¥å•生成采购入库单 */
export function generateItemReceiptFromArrivalNotice(arrivalNoticeId: number) {
  return requestClient.post<number>(
    `/mes/wm/item-receipt/generate-from-arrival-notice?arrivalNoticeId=${arrivalNoticeId}`,
  );
}
/** æäº¤é‡‡è´­å…¥åº“单审批 */
export function submitItemReceiptApproval(
  id: number,
  processDefinitionKey: string,
) {
  return requestClient.put(
    `/mes/wm/item-receipt/submit-approval?id=${id}&processDefinitionKey=${processDefinitionKey}`,
  );
}
src/api/mes/wm/returnvendor/index.ts
@@ -8,6 +8,7 @@
    id?: number; // é€€è´§å•编号
    code?: string; // é€€è´§å•编号
    name?: string; // é€€è´§å•名称
    purchaseOrderId?: number; // é‡‡è´­è®¢å•编号
    purchaseOrderCode?: string; // é‡‡è´­è®¢å•号
    vendorId?: number; // ä¾›åº”商编号
    vendorCode?: string; // ä¾›åº”商编码
src/router/routes/modules/mes.ts
@@ -12,33 +12,6 @@
    },
    children: [
      {
        path: 'wm/warehouse/location',
        name: 'MesWmLocation',
        meta: {
          title: '库区设置',
          activePath: '/mes/wm/warehouse',
        },
        component: () => import('#/views/mes/wm/warehouse/location/index.vue'),
      },
      {
        path: 'wm/warehouse/area',
        name: 'MesWmArea',
        meta: {
          title: '库位设置',
          activePath: '/mes/wm/warehouse',
        },
        component: () => import('#/views/mes/wm/warehouse/area/index.vue'),
      },
      {
        path: 'wm/barcode/config',
        name: 'MesWmBarcodeConfig',
        meta: {
          title: '条码配置',
          activePath: '/mes/wm/barcode',
        },
        component: () => import('#/views/mes/wm/barcode/config/index.vue'),
      },
      {
        path: 'pro/task/gantt-edit',
        name: 'MesProTaskGanttEdit',
        meta: {
src/views/mes/md/vendor/components/select.vue
@@ -1,13 +1,11 @@
<script lang="ts" setup>
import type { MesMdVendorApi } from '#/api/mes/md/vendor';
import { computed, ref, useAttrs, watch } from 'vue';
import { computed, ref, useAttrs } from 'vue';
import { IconifyIcon } from '../../../../../packages/icons/src';
import { Input, Tooltip } from 'ant-design-vue';
import { getVendor } from '#/api/mes/md/vendor';
import MdVendorSelectDialog from './select-dialog.vue';
@@ -19,24 +17,26 @@
    disabled?: boolean;
    modelValue?: number;
    placeholder?: string;
    vendorName?: string;
  }>(),
  {
    allowClear: true,
    disabled: false,
    modelValue: undefined,
    placeholder: '请选择供应商',
    vendorName: undefined,
  },
);
const emit = defineEmits<{
  change: [item: MesMdVendorApi.Vendor | undefined];
  'update:modelValue': [value: number | undefined];
}>();
const attrs = useAttrs(); // é€ä¼ å±žæ€§
const dialogRef = ref<InstanceType<typeof MdVendorSelectDialog>>(); // ä¾›åº”商选择弹窗
const hovering = ref(false); // æ˜¯å¦æ‚¬åœ
const selectedItem = ref<MesMdVendorApi.Vendor>(); // å½“前选中供应商
const attrs = useAttrs();
const dialogRef = ref<InstanceType<typeof MdVendorSelectDialog>>();
const hovering = ref(false);
const selectedItem = ref<MesMdVendorApi.Vendor>();
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // é€‰æ‹©å™¨å±•示名称
const displayLabel = computed(() => props.vendorName || selectedItem.value?.name || '');
const showClear = computed(
  () =>
    props.allowClear &&
@@ -45,34 +45,12 @@
    props.modelValue !== null,
);
/** æ ¹æ®ä¾›åº”商编号回显选择器 */
async function resolveItemById(id: number | undefined) {
  if (!id) {
    selectedItem.value = undefined;
    return;
  }
  if (selectedItem.value?.id === id) {
    return;
  }
  selectedItem.value = await getVendor(id);
}
watch(
  () => props.modelValue,
  (value) => {
    resolveItemById(value);
  },
  { immediate: true },
);
/** æ¸…空已选供应商 */
function clearSelected() {
  selectedItem.value = undefined;
  emit('update:modelValue', undefined);
  emit('change', undefined);
}
/** æ‰“开供应商选择弹窗 */
function handleClick(event: MouseEvent) {
  if (props.disabled) {
    return;
@@ -89,7 +67,6 @@
  dialogRef.value?.open(selectedIds, { multiple: false });
}
/** å›žå¡«é€‰ä¸­çš„供应商 */
function handleSelected(rows: MesMdVendorApi.Vendor[]) {
  const item = rows[0];
  if (!item) {
src/views/wls/arrivalnotice/data.ts
@@ -77,11 +77,26 @@
      rules: 'required',
    },
    {
      fieldName: 'vendorName',
      label: '',
      component: 'Input',
      dependencies: {
        triggerFields: [''],
        show: () => false,
      },
    },
    {
      fieldName: 'purchaseOrderId',
      label: '采购订单',
      component: markRaw(ErpPurchaseOrderSelect),
      componentProps: {
        placeholder: '请选择采购订单',
        onChange: (item: any) => {
          if (item?.supplierId && formApi) {
            formApi.setFieldValue('vendorId', item.supplierId);
            formApi.setFieldValue('vendorName', item.supplierName);
          }
        },
      },
    },
    {
@@ -90,6 +105,15 @@
      component: markRaw(MdVendorSelect),
      componentProps: {
        placeholder: '请选择供应商',
        disabled: true,
      },
      dependencies: {
        triggerFields: ['vendorName'],
        componentProps: (values) => ({
          placeholder: '请选择供应商',
          disabled: true,
          vendorName: values.vendorName as string,
        }),
      },
      rules: 'selectRequired',
    },
src/views/wls/arrivalnotice/index.vue
@@ -2,9 +2,9 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesWmArrivalNoticeApi } from '#/api/mes/wm/arrivalnotice';
import { Page, useVbenModal } from '../../../packages/effects/common-ui/src';
import { MesWmArrivalNoticeStatusEnum } from '../../../packages/constants/src';
import { downloadFileFromBlobPart } from '../../../packages/utils/src';
import { Page, useVbenModal } from '@vben/common-ui';
import { MesWmArrivalNoticeStatusEnum } from '@vben/constants';
import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, message } from 'ant-design-vue';
@@ -12,15 +12,22 @@
import {
  deleteArrivalNotice,
  exportArrivalNotice,
  generateArrivalNoticeFromPurchaseOrder,
  getArrivalNoticePage,
} from '#/api/mes/wm/arrivalnotice';
import { $t } from '#/locales';
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
import PoSelectDialog from './modules/po-select-dialog.vue';
const [FormModal, formModalApi] = useVbenModal({
  connectedComponent: Form,
  destroyOnClose: true,
});
const [PoSelectModal, poSelectModalApi] = useVbenModal({
  connectedComponent: PoSelectDialog,
  destroyOnClose: true,
});
@@ -69,6 +76,28 @@
  message.info('请前往【仓库管理 - é‡‡è´­å…¥åº“】中进行入库操作');
}
/** ä»Žé‡‡è´­è®¢å•生成到货通知单 */
async function handleGenerateFromPO() {
  poSelectModalApi.open();
}
/** é‡‡è´­è®¢å•选择回调 */
async function handlePurchaseOrderSelected(purchaseOrderId: number) {
  const hideLoading = message.loading({
    content: '正在生成到货通知单...',
    duration: 0,
  });
  try {
    const id = await generateArrivalNoticeFromPurchaseOrder(purchaseOrderId);
    message.success('到货通知单生成成功');
    // è·³è½¬åˆ°ç¼–辑页
    formModalApi.setData({ formType: 'update', id }).open();
    handleRefresh();
  } finally {
    hideLoading();
  }
}
/** å¯¼å‡ºè¡¨æ ¼ */
async function handleExport() {
  const data = await exportArrivalNotice(await gridApi.formApi.getValues());
@@ -107,7 +136,9 @@
</script>
<template>
  <Page auto-content-height><FormModal @success="handleRefresh" />
  <Page auto-content-height>
    <FormModal @success="handleRefresh" />
    <PoSelectModal @selected="handlePurchaseOrderSelected" />
    <Grid table-title="到货通知单列表">
      <template #toolbar-tools>
@@ -121,6 +152,13 @@
              onClick: handleCreate,
            },
            {
              label: '从采购订单生成',
              type: 'primary',
              icon: ACTION_ICON.ADD,
              auth: ['mes:wm-arrival-notice:create'],
              onClick: handleGenerateFromPO,
            },
            {
              label: $t('ui.actionTitle.export'),
              type: 'primary',
              icon: ACTION_ICON.DOWNLOAD,
src/views/wls/arrivalnotice/modules/po-select-dialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
<script lang="ts" setup>
import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { Page, useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getPurchaseOrderPage } from '#/api/erp/purchase/order';
const emit = defineEmits<{
  selected: [purchaseOrderId: number];
}>();
const [Grid, gridApi] = useVbenVxeGrid({
  formOptions: {
    schema: [
      {
        fieldName: 'no',
        label: '订单号',
        component: 'Input',
        componentProps: {
          allowClear: true,
          placeholder: '请输入订单号',
        },
      },
      {
        fieldName: 'supplierName',
        label: '供应商',
        component: 'Input',
        componentProps: {
          allowClear: true,
          placeholder: '请输入供应商名称',
        },
      },
    ],
  },
  gridOptions: {
    columns: [
      {
        type: 'radio',
        width: 60,
      },
      {
        field: 'no',
        title: '订单号',
        minWidth: 160,
      },
      {
        field: 'supplierName',
        title: '供应商名称',
        minWidth: 120,
      },
      {
        field: 'orderTime',
        title: '订单日期',
        width: 180,
        formatter: 'formatDate',
      },
      {
        field: 'totalPrice',
        title: '总金额',
        width: 120,
        formatter: 'formatMoney',
      },
      {
        field: 'status',
        title: '状态',
        width: 100,
        cellRender: {
          name: 'CellDict',
          props: { type: 'erp_purchase_order_status' },
        },
      },
    ],
    height: 'auto',
    keepSource: true,
    proxyConfig: {
      ajax: {
        query: async ({ page }, formValues) => {
          return await getPurchaseOrderPage({
            pageNo: page.currentPage,
            pageSize: page.pageSize,
            ...formValues,
          });
        },
      },
    },
    rowConfig: {
      keyField: 'id',
      isHover: true,
    },
    toolbarConfig: {
      refresh: true,
      search: true,
    },
  } as VxeTableGridOptions<ErpPurchaseOrderApi.PurchaseOrder>,
});
const [Modal, modalApi] = useVbenModal({
  async onConfirm() {
    const selectedRows = gridApi.grid.getRadioRecord();
    if (!selectedRows) {
      message.warning('请选择采购订单');
      return;
    }
    emit('selected', selectedRows.id);
    await modalApi.close();
  },
  async onOpenChange(isOpen: boolean) {
    if (isOpen) {
      await gridApi.query();
    }
  },
});
</script>
<template>
  <Modal title="选择采购订单" class="w-2/3">
    <Grid table-title="采购订单列表" />
  </Modal>
</template>
src/views/wls/barcode/components/detail.vue
@@ -24,6 +24,7 @@
  column: 1,
  schema: useBarcodeDetailSchema(),
  useCard: false,
  labelStyle: { width: '80px', whiteSpace: 'nowrap' },
});
function openModal(row: Partial<MesWmBarcodeApi.Barcode>) {
@@ -98,11 +99,86 @@
    message.warning('条码生成失败,无法下载');
    return;
  }
  const link = document.createElement('a');
  link.href = base64;
  link.download = `barcode_${barcodeData.value.bizCode || 'unknown'}_${Date.now()}.png`;
  link.click();
  message.success('下载成功');
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  if (!ctx) {
    message.error('Canvas åˆå§‹åŒ–失败');
    return;
  }
  const img = new Image();
  img.onload = () => {
    const padding = 20;
    const infoX = img.width + padding * 2;
    const infoWidth = 320;
    canvas.width = infoX + infoWidth + padding;
    canvas.height = Math.max(img.height + padding * 2, 360);
    ctx.fillStyle = '#ffffff';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(img, padding, padding);
    ctx.fillStyle = '#000000';
    let y = padding + 10;
    const lineHeight = 26;
    // èŽ·å–å­—å…¸æ–‡æœ¬çš„è¾…åŠ©å‡½æ•°
    const getFormatText = (val?: number) => {
      const map: Record<number, string> = { 1: 'QR_CODE', 2: 'CODE_128', 3: 'CODE_39', 4: 'EAN_13', 5: 'UPC_A' };
      return map[val || 1] || 'QR_CODE';
    };
    const getBizTypeText = (val?: number) => {
      const map: Record<number, string> = { 1: '仓库', 2: '库区', 3: '库位', 4: '物料', 5: '客户', 6: '供应商', 7: '工单', 8: '设备', 9: '工具', 10: '人员', 11: '工作站', 12: '车间', 13: '库存', 14: '流转卡', 15: '装箱单', 16: '批次' };
      return map[val || 1] || '-';
    };
    const getStatusText = (val?: number) => val === 0 ? '禁用' : '启用';
    const items = [
      { label: '条码格式', value: getFormatText(barcodeData.value.format) },
      { label: '业务类型', value: getBizTypeText(barcodeData.value.bizType) },
      { label: '业务编码', value: barcodeData.value.bizCode },
      { label: '业务名称', value: barcodeData.value.bizName },
      { label: '条码内容', value: barcodeData.value.content },
      { label: '状态', value: getStatusText(barcodeData.value.status) },
    ];
    items.forEach((item) => {
      ctx.font = 'bold 13px Arial, sans-serif';
      ctx.fillText(`${item.label}:`, infoX, y);
      y += 18;
      ctx.font = '13px Arial, sans-serif';
      const text = item.value || '-';
      // å¤„理长文本换行
      const maxWidth = infoWidth - 10;
      if (ctx.measureText(text).width > maxWidth) {
        let currentText = text;
        while (currentText.length > 0) {
          let line = '';
          for (let i = 0; i < currentText.length; i++) {
            const testLine = line + currentText[i];
            if (ctx.measureText(testLine).width > maxWidth) break;
            line = testLine;
          }
          ctx.fillText(line, infoX + 5, y);
          y += 16;
          currentText = currentText.slice(line.length);
        }
        y += 6;
      } else {
        ctx.fillText(text, infoX + 5, y);
        y += lineHeight;
      }
    });
    const link = document.createElement('a');
    link.href = canvas.toDataURL('image/png');
    link.download = `barcode_${barcodeData.value.bizCode || 'unknown'}_${Date.now()}.png`;
    link.click();
    message.success('下载成功');
  };
  img.src = base64;
}
async function handleGenerate() {
@@ -126,36 +202,35 @@
</script>
<template>
  <Modal v-model:open="open" title="查看条码" width="500px">
  <Modal v-model:open="open" title="查看条码" width="750px">
    <div>
      <div
        class="mb-5 flex min-h-50 items-center justify-center rounded bg-gray-100 p-5"
      >
        <div
          v-if="barcodeData.content"
          class="flex items-center justify-center"
        >
          <WlsBarcode
            ref="barcodeRef"
            :content="barcodeData.content"
            :format="barcodeData.format"
            :height="150"
            :width="400"
          />
      <div class="mb-5 flex min-h-50 items-center rounded bg-gray-100 p-5">
        <div v-if="barcodeData.content" class="flex w-full items-center gap-6">
          <div class="flex-shrink-0">
            <WlsBarcode
              ref="barcodeRef"
              :content="barcodeData.content"
              :format="barcodeData.format"
              :height="150"
              :width="280"
            />
          </div>
          <div class="flex-1">
            <Descriptions :data="barcodeData">
              <template #content>
                <Tooltip :title="barcodeData.content">
                  <span
                    class="inline-block max-w-60 overflow-hidden text-ellipsis whitespace-nowrap"
                  >
                    {{ barcodeData.content }}
                  </span>
                </Tooltip>
              </template>
            </Descriptions>
          </div>
        </div>
        <Empty v-else description="暂无条码数据" />
        <Empty v-else description="暂无条码数据" class="flex-1" />
      </div>
      <Descriptions :data="barcodeData">
        <template #content>
          <Tooltip :title="barcodeData.content">
            <span
              class="inline-block max-w-75 overflow-hidden text-ellipsis whitespace-nowrap"
            >
              {{ barcodeData.content }}
            </span>
          </Tooltip>
        </template>
      </Descriptions>
    </div>
    <template #footer>
      <Button v-if="!barcodeData.content" @click="handleGenerate">
src/views/wls/itemreceipt/index.vue
@@ -2,9 +2,9 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesWmItemReceiptApi } from '#/api/mes/wm/itemreceipt';
import { Page, useVbenModal } from '../../../packages/effects/common-ui/src';
import { MesWmItemReceiptStatusEnum } from '../../../packages/constants/src';
import { downloadFileFromBlobPart } from '../../../packages/utils/src';
import { Page, useVbenModal } from '@vben/common-ui';
import { MesWmItemReceiptStatusEnum } from '@vben/constants';
import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, message } from 'ant-design-vue';
@@ -13,15 +13,22 @@
  cancelItemReceipt,
  deleteItemReceipt,
  exportItemReceipt,
  generateItemReceiptFromArrivalNotice,
  getItemReceiptPage,
} from '#/api/mes/wm/itemreceipt';
import { $t } from '#/locales';
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
import AnSelectDialog from './modules/an-select-dialog.vue';
const [FormModal, formModalApi] = useVbenModal({
  connectedComponent: Form,
  destroyOnClose: true,
});
const [AnSelectModal, anSelectModalApi] = useVbenModal({
  connectedComponent: AnSelectDialog,
  destroyOnClose: true,
});
@@ -77,6 +84,28 @@
  handleRefresh();
}
/** ä»Žåˆ°è´§é€šçŸ¥ç”Ÿæˆé‡‡è´­å…¥åº“单 */
async function handleGenerateFromAN() {
  anSelectModalApi.open();
}
/** åˆ°è´§é€šçŸ¥é€‰æ‹©å›žè°ƒ */
async function handleArrivalNoticeSelected(arrivalNoticeId: number) {
  const hideLoading = message.loading({
    content: '正在生成采购入库单...',
    duration: 0,
  });
  try {
    const id = await generateItemReceiptFromArrivalNotice(arrivalNoticeId);
    message.success('采购入库单生成成功');
    // è·³è½¬åˆ°ç¼–辑页
    formModalApi.setData({ formType: 'update', id }).open();
    handleRefresh();
  } finally {
    hideLoading();
  }
}
/** å¯¼å‡ºè¡¨æ ¼ */
async function handleExport() {
  const data = await exportItemReceipt(await gridApi.formApi.getValues());
@@ -115,7 +144,9 @@
</script>
<template>
  <Page auto-content-height><FormModal @success="handleRefresh" />
  <Page auto-content-height>
    <FormModal @success="handleRefresh" />
    <AnSelectModal @selected="handleArrivalNoticeSelected" />
    <Grid table-title="采购入库单列表">
      <template #toolbar-tools>
@@ -129,6 +160,13 @@
              onClick: handleCreate,
            },
            {
              label: '从到货通知生成',
              type: 'primary',
              icon: ACTION_ICON.ADD,
              auth: ['mes:wm-item-receipt:create'],
              onClick: handleGenerateFromAN,
            },
            {
              label: $t('ui.actionTitle.export'),
              type: 'primary',
              icon: ACTION_ICON.DOWNLOAD,
src/views/wls/itemreceipt/modules/an-select-dialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,129 @@
<script lang="ts" setup>
import type { MesWmArrivalNoticeApi } from '#/api/mes/wm/arrivalnotice';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { Page, useVbenModal } from '@vben/common-ui';
import { MesWmArrivalNoticeStatusEnum } from '@vben/constants';
import { message } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getArrivalNoticePage } from '#/api/mes/wm/arrivalnotice';
const emit = defineEmits<{
  selected: [arrivalNoticeId: number];
}>();
const [Grid, gridApi] = useVbenVxeGrid({
  formOptions: {
    schema: [
      {
        fieldName: 'code',
        label: '通知单号',
        component: 'Input',
        componentProps: {
          allowClear: true,
          placeholder: '请输入通知单号',
        },
      },
      {
        fieldName: 'vendorName',
        label: '供应商',
        component: 'Input',
        componentProps: {
          allowClear: true,
          placeholder: '请输入供应商名称',
        },
      },
    ],
  },
  gridOptions: {
    columns: [
      {
        type: 'radio',
        width: 60,
      },
      {
        field: 'code',
        title: '通知单号',
        minWidth: 160,
      },
      {
        field: 'name',
        title: '通知单名称',
        minWidth: 150,
      },
      {
        field: 'vendorName',
        title: '供应商名称',
        minWidth: 120,
      },
      {
        field: 'purchaseOrderNo',
        title: '采购订单号',
        minWidth: 140,
      },
      {
        field: 'arrivalDate',
        title: '到货日期',
        width: 180,
        formatter: 'formatDate',
      },
      {
        field: 'status',
        title: '状态',
        width: 100,
        cellRender: {
          name: 'CellDict',
          props: { type: 'mes_wm_arrival_notice_status' },
        },
      },
    ],
    height: 'auto',
    keepSource: true,
    proxyConfig: {
      ajax: {
        query: async ({ page }, formValues) => {
          return await getArrivalNoticePage({
            pageNo: page.currentPage,
            pageSize: page.pageSize,
            status: MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT,
            ...formValues,
          });
        },
      },
    },
    rowConfig: {
      keyField: 'id',
      isHover: true,
    },
    toolbarConfig: {
      refresh: true,
      search: true,
    },
  } as VxeTableGridOptions<MesWmArrivalNoticeApi.ArrivalNotice>,
});
const [Modal, modalApi] = useVbenModal({
  async onConfirm() {
    const selectedRows = gridApi.grid.getRadioRecord();
    if (!selectedRows) {
      message.warning('请选择到货通知单');
      return;
    }
    emit('selected', selectedRows.id);
    await modalApi.close();
  },
  async onOpenChange(isOpen: boolean) {
    if (isOpen) {
      await gridApi.query();
    }
  },
});
</script>
<template>
  <Modal title="选择到货通知单" class="w-2/3">
    <Grid table-title="到货通知单列表" />
  </Modal>
</template>
src/views/wls/itemreceipt/modules/form.vue
@@ -5,8 +5,8 @@
import { computed, ref } from 'vue';
import { confirm, useVbenModal } from '../../../../packages/effects/common-ui/src';
import { MesWmItemReceiptStatusEnum } from '../../../../packages/constants/src';
import { confirm, useVbenModal } from '@vben/common-ui';
import { MesWmItemReceiptStatusEnum } from '@vben/constants';
import { Button, Divider, message, Popconfirm } from 'ant-design-vue';
@@ -17,6 +17,7 @@
  getItemReceipt,
  stockItemReceipt,
  submitItemReceipt,
  submitItemReceiptApproval,
  updateItemReceipt,
} from '#/api/mes/wm/itemreceipt';
import { $t } from '#/locales';
@@ -37,6 +38,12 @@
const canSubmit = computed(
  () =>
    // æ˜¯å¦å¯æäº¤
    formType.value === 'update' &&
    formData.value?.status === MesWmItemReceiptStatusEnum.PREPARE,
);
const canSubmitApproval = computed(
  () =>
    // æ˜¯å¦å¯æäº¤å®¡æ‰¹
    formType.value === 'update' &&
    formData.value?.status === MesWmItemReceiptStatusEnum.PREPARE,
);
@@ -118,6 +125,24 @@
  try {
    await finishItemReceipt(formData.value.id);
    message.success('入库成功');
    await modalApi.close();
    emit('success');
  } finally {
    modalApi.unlock();
  }
}
/** æäº¤å®¡æ‰¹ */
async function handleSubmitApproval() {
  if (!formData.value?.id) {
    return;
  }
  modalApi.lock();
  try {
    // ä½¿ç”¨é»˜è®¤æµç¨‹key,实际项目中可能需要弹窗选择
    const processDefinitionKey = 'item_receipt_approval';
    await submitItemReceiptApproval(formData.value.id, processDefinitionKey);
    message.success('提交审批成功');
    await modalApi.close();
    emit('success');
  } finally {
@@ -230,6 +255,9 @@
        >
          <Button type="primary">提交</Button>
        </Popconfirm>
        <Button v-if="canSubmitApproval" type="primary" @click="handleSubmitApproval">
          æäº¤å®¡æ‰¹
        </Button>
        <Button v-if="isStock" type="primary" @click="confirmStock">
          æ‰§è¡Œä¸Šæž¶
        </Button>
src/views/wls/returnvendor/data.ts
@@ -14,6 +14,7 @@
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdVendorSelect } from '#/views/mes/md/vendor/components';
import { ErpPurchaseOrderSelect } from '#/views/erp/purchase/order/components';
import { WmBatchSelect } from '#/views/wls/batch/components';
import { WmMaterialStockSelect } from '#/views/wls/materialstock/components';
import {
@@ -87,11 +88,26 @@
      rules: 'required',
    },
    {
      fieldName: 'purchaseOrderCode',
      label: '采购订单号',
      fieldName: 'vendorName',
      label: '',
      component: 'Input',
      dependencies: {
        triggerFields: [''],
        show: () => false,
      },
    },
    {
      fieldName: 'purchaseOrderId',
      label: '采购订单',
      component: markRaw(ErpPurchaseOrderSelect),
      componentProps: {
        placeholder: '请输入采购订单号',
        placeholder: '请选择采购订单',
        onChange: (item: any) => {
          if (item?.supplierId && formApi) {
            formApi.setFieldValue('vendorId', item.supplierId);
            formApi.setFieldValue('vendorName', item.supplierName);
          }
        },
      },
    },
    {
@@ -100,6 +116,15 @@
      component: markRaw(MdVendorSelect),
      componentProps: {
        placeholder: '请选择供应商',
        disabled: true,
      },
      dependencies: {
        triggerFields: ['vendorName'],
        componentProps: (values) => ({
          placeholder: '请选择供应商',
          disabled: true,
          vendorName: values.vendorName as string,
        }),
      },
      rules: 'selectRequired',
    },
src/views/wls/warehouse/area/index.vue
@@ -22,6 +22,8 @@
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
defineOptions({ name: 'WlsArea' });
const route = useRoute();
const [FormModal, formModalApi] = useVbenModal({
src/views/wls/warehouse/index.vue
@@ -18,6 +18,8 @@
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
defineOptions({ name: 'WlsWarehouse' });
const router = useRouter();
const [FormModal, formModalApi] = useVbenModal({
@@ -65,7 +67,7 @@
/** è·³è½¬åº“区列表 */
function handleOpenLocation(row: MesWmWarehouseApi.Warehouse) {
  router.push({
    name: 'WlsLocation',
    path: '/wls/location',
    query: { warehouseId: String(row.id) },
  });
}
src/views/wls/warehouse/location/index.vue
@@ -22,6 +22,8 @@
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
defineOptions({ name: 'WlsLocation' });
const route = useRoute();
const router = useRouter();
@@ -99,7 +101,7 @@
/** è·³è½¬åº“位列表 */
function handleOpenArea(row: MesWmWarehouseLocationApi.WarehouseLocation) {
  router.push({
    name: 'WlsArea',
    path: '/wls/area',
    query: { locationId: String(row.id) },
  });
}
vite.config.ts
@@ -7,6 +7,40 @@
      oxc: {
        enable: false,
      },
      optimizeDeps: {
        include: [
          "vue",
          "vue-router",
          "pinia",
          "ant-design-vue",
          "dayjs",
          "@vueuse/core",
          "axios",
        ],
        exclude: [
          "dhtmlx-gantt",
          "tinymce",
          "bpmn-js",
          "bpmn-js-properties-panel",
          "video.js",
        ],
      },
      build: {
        rollupOptions: {
          output: {
            manualChunks: {
              "vendor-vue": ["vue", "vue-router", "pinia"],
              "vendor-ui": ["ant-design-vue", "@vueuse/core"],
              "vendor-utils": ["dayjs", "axios", "@vee-validate/zod", "zod"],
              "vendor-editor": [
                "tinymce",
                "@tinymce/tinymce-vue",
                "@form-create/ant-design-vue",
              ],
            },
          },
        },
      },
      server: {
        allowedHosts: true,
        watch: {