feat: 仓储/售后物料改用 MDM
选择器;首页隐藏生产模块并恢复质量/设备卡片;产品入库行去除库存记录

- 物料选择器:wls/* 与 aftersales/ticket 由 mes 的 MdItemSelect 换为 basicData 的
MdmItemSelect
(MesMdItemApi → MdmItemApi);views/mes 保持不动
- 首页 /analytics:隐藏 AI 分析 / 生产趋势 /
预警面板,及快捷操作中的生产项(生产工单、

报工、排程、工艺路线、数据报表);销售/采购金额概览改为前端按订单表聚合(官方统计接口
501);
恢复「质量合格率」「设备运行率」两张卡片(kpi-cards 精简为两张,重新调用
getHomeSummary)
- 产品入库单行移除「库存记录」字段,仅保留 物料 / 入库数量 / 批次号 / 备注
- .gitignore 忽略 .playwright-mcp/ 及 dist.zip、根目录 png 等本地临时产物
已修改24个文件
398 ■■■■■ 文件已修改
.gitignore 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/aftersales/ticket/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/analytics/index.vue 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/analytics/modules/kpi-cards.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dashboard/analytics/modules/quick-actions.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/barcode/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/batch/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/itemreceipt/data.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/materialstock/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/miscreceipt/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/outsourceissue/data.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/outsourcereceipt/data.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/packages/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/productissue/data.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/productreceipt/data.ts 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/productreceipt/modules/line-form.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/productsales/data.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/returnsales/data.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/returnvendor/data.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/salesnotice/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/sn/data.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/stocktaking/plan/components/condition-value-input.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/stocktaking/task/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/transfer/data.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -30,4 +30,11 @@
# Cache
.cache/
.temp/
.temp/
# Playwright MCP artifacts (screenshots / snapshots)
.playwright-mcp/
# Local scratch artifacts
dist.zip
/*.png
src/views/aftersales/ticket/data.ts
@@ -13,7 +13,7 @@
import { z } from '#/adapter/form';
import CrmCustomerSelect from '#/components/crm-customer-select.vue';
import { ErpSaleOrderSelect } from '#/views/erp/sale/order/components';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { WmBatchSelect } from '#/views/wls/batch/components';
import { UserSelect } from '#/views/system/user/components';
@@ -383,7 +383,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: hasOrderItems ? 'Select' : markRaw(MdItemSelect),
      component: hasOrderItems ? 'Select' : markRaw(MdmItemSelect),
      componentProps: hasOrderItems
        ? {
            placeholder: '请选择物料',
src/views/dashboard/analytics/index.vue
@@ -1,25 +1,31 @@
<script lang="ts" setup>
import type { PageParam, PageResult } from '@vben/request';
import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order';
import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
import type { MesHomeApi } from '#/api/mes/home';
import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import { Card, Col, Row } from 'ant-design-vue';
import { Col, Row } from 'ant-design-vue';
import { getPurchaseOrderPage } from '#/api/erp/purchase/order';
import { getSaleOrderPage } from '#/api/erp/sale/order';
import { getHomeSummary } from '#/api/mes/home';
import SummaryCard from '#/views/erp/home/modules/summary-card.vue';
import { defaultSummary } from './data';
import AiInsights from './modules/ai-insights.vue';
import AlertPanel from './modules/alert-panel.vue';
import BizCards from './modules/biz-cards.vue';
import KpiCards from './modules/kpi-cards.vue';
import ProductionTrend from './modules/production-trend.vue';
import QuickActions from './modules/quick-actions.vue';
defineOptions({ name: 'DashboardAnalytics' });
const router = useRouter();
const summary = ref(defaultSummary);
const greeting = computed(() => {
  const hour = new Date().getHours();
@@ -41,12 +47,104 @@
  router.push({ name });
}
async function loadSummary() {
  summary.value = await getHomeSummary();
interface PriceSummary {
  monthPrice: number;
  todayPrice: number;
  yearPrice: number;
  yesterdayPrice: number;
}
const saleSummary = ref<PriceSummary>();
const purchaseSummary = ref<PriceSummary>();
const homeSummary = ref<MesHomeApi.Summary>(defaultSummary);
const PAGE_SIZE = 200;
/** 逐页拉取全部分页数据(后端 pageSize 上限 200) */
async function fetchAllPages<T>(
  fetcher: (params: PageParam) => Promise<PageResult<T>>,
): Promise<T[]> {
  const first = await fetcher({ pageNo: 1, pageSize: PAGE_SIZE });
  const list: T[] = [...(first.list ?? [])];
  const total = first.total ?? list.length;
  const pageCount = Math.ceil(total / PAGE_SIZE);
  for (let pageNo = 2; pageNo <= pageCount; pageNo++) {
    const res = await fetcher({ pageNo, pageSize: PAGE_SIZE });
    list.push(...(res.list ?? []));
  }
  return list;
}
function toDayStr(time?: Date | string): string {
  if (!time) return '';
  if (typeof time === 'string') return time.slice(0, 10);
  const d = new Date(time);
  if (Number.isNaN(d.getTime())) return '';
  const m = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  return `${d.getFullYear()}-${m}-${day}`;
}
/** 按订单时间聚合金额:今日 / 昨日 / 本月 / 今年 */
function aggregatePrice(
  orders: Array<{ orderTime?: Date | string; totalPrice?: number }>,
): PriceSummary {
  const now = new Date();
  const today = toDayStr(now);
  const yesterdayDate = new Date(now);
  yesterdayDate.setDate(now.getDate() - 1);
  const yesterday = toDayStr(yesterdayDate);
  const month = today.slice(0, 7);
  const year = today.slice(0, 4);
  const summary: PriceSummary = {
    monthPrice: 0,
    todayPrice: 0,
    yearPrice: 0,
    yesterdayPrice: 0,
  };
  for (const order of orders) {
    const day = toDayStr(order.orderTime);
    if (!day) continue;
    const price = order.totalPrice ?? 0;
    if (day === today) summary.todayPrice += price;
    if (day === yesterday) summary.yesterdayPrice += price;
    if (day.startsWith(month)) summary.monthPrice += price;
    if (day.startsWith(year)) summary.yearPrice += price;
  }
  return summary;
}
async function loadStatistics() {
  try {
    const saleOrders = await fetchAllPages<ErpSaleOrderApi.SaleOrder>(
      getSaleOrderPage,
    );
    saleSummary.value = aggregatePrice(saleOrders);
  } catch {
    /* 接口异常或无权限 */
  }
  try {
    const purchaseOrders = await fetchAllPages<ErpPurchaseOrderApi.PurchaseOrder>(
      getPurchaseOrderPage,
    );
    purchaseSummary.value = aggregatePrice(purchaseOrders);
  } catch {
    /* 接口异常或无权限 */
  }
}
async function loadHomeSummary() {
  try {
    homeSummary.value = await getHomeSummary();
  } catch {
    /* 接口异常或无权限 */
  }
}
onMounted(() => {
  loadSummary();
  loadHomeSummary();
  loadStatistics();
});
</script>
@@ -71,35 +169,19 @@
      </div>
    </div>
    <!-- MES 生产 KPI -->
    <KpiCards :summary="summary" @navigate="handleNavigate" />
    <!-- 质量 / 设备 KPI -->
    <KpiCards :summary="homeSummary" @navigate="handleNavigate" />
    <!-- ERP/WMS/BPM 经营 KPI -->
    <BizCards @navigate="handleNavigate" />
    <!-- AI 智能分析 -->
    <AiInsights
      :active-order-count="summary.workOrderActiveCount"
      @navigate="handleNavigate"
    />
    <!-- 生产趋势 + 预警面板 -->
    <Row :gutter="16" class="mb-4">
      <Col :lg="14" :md="24" :sm="24" :xl="14" :xs="24" class="mb-4">
        <div class="glass-card rounded-2xl p-5">
          <h3 class="mb-4 text-base font-semibold text-gray-800 dark:text-gray-100">
            生产趋势(近7天)
          </h3>
          <ProductionTrend />
        </div>
      </Col>
      <Col :lg="10" :md="24" :sm="24" :xl="10" :xs="24" class="mb-4">
        <AlertPanel
          :repair-active-count="summary.repairActiveCount"
          @navigate="handleNavigate"
        />
      </Col>
    </Row>
    <!-- 销售 / 采购 金额概览 -->
    <div class="mb-4">
      <SummaryCard
        :purchase-summary="purchaseSummary"
        :sale-summary="saleSummary"
      />
    </div>
    <!-- 快捷操作 -->
    <Row :gutter="16" class="mb-4">
src/views/dashboard/analytics/modules/kpi-cards.vue
@@ -58,70 +58,8 @@
<template>
  <Row :gutter="16">
    <!-- 生产订单 -->
    <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
      <div
        class="glass-tilt group cursor-pointer overflow-hidden rounded-2xl border-0"
        :style="tiltStyle('order')"
        @mousemove="(e: MouseEvent) => onMouseMove(e, 'order')"
        @mouseleave="onMouseLeave('order')"
        @click="emit('navigate', 'MesProWorkOrder')"
      >
        <div class="relative z-10 flex items-center gap-4 p-5">
          <div class="flex size-12 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-blue-500 to-cyan-400 shadow-lg shadow-blue-500/25 transition-transform duration-300 group-hover:scale-110">
            <IconifyIcon class="size-6 text-white" icon="lucide:clipboard-list" />
          </div>
          <div class="min-w-0 flex-1">
            <div class="mb-1 text-xs font-medium text-gray-500 dark:text-gray-400">生产订单</div>
            <div class="flex items-baseline gap-1">
              <CountTo class="text-2xl font-bold leading-tight text-blue-600 dark:text-blue-400" :end-val="summary.workOrderActiveCount" :duration="1200" />
              <span class="text-xs text-gray-400">进行中</span>
            </div>
            <div class="mt-1 flex items-center gap-1 text-xs text-gray-400">
              <span class="inline-block size-1.5 rounded-full bg-amber-400" /> 待排产 {{ summary.workOrderPrepareCount }}
              <span class="mx-1">|</span>
              <span class="inline-block size-1.5 rounded-full bg-emerald-400" /> 已完成 {{ summary.workOrderFinishedCount }}
            </div>
          </div>
        </div>
        <div class="absolute inset-0 -z-0 bg-gradient-to-br from-blue-500/5 to-cyan-500/5 opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
        <div class="absolute -right-6 -top-6 size-24 rounded-full bg-blue-400/10 blur-xl transition-all duration-300 group-hover:scale-150" />
      </div>
    </Col>
    <!-- 今日产量 -->
    <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
      <div
        class="glass-tilt group cursor-pointer overflow-hidden rounded-2xl border-0"
        :style="tiltStyle('output')"
        @mousemove="(e: MouseEvent) => onMouseMove(e, 'output')"
        @mouseleave="onMouseLeave('output')"
        @click="emit('navigate', 'MesProFeedback')"
      >
        <div class="relative z-10 flex items-center gap-4 p-5">
          <div class="flex size-12 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-emerald-500 to-green-400 shadow-lg shadow-emerald-500/25 transition-transform duration-300 group-hover:scale-110">
            <IconifyIcon class="size-6 text-white" icon="lucide:trending-up" />
          </div>
          <div class="min-w-0 flex-1">
            <div class="mb-1 text-xs font-medium text-gray-500 dark:text-gray-400">今日产量</div>
            <div class="flex items-baseline gap-1">
              <CountTo class="text-2xl font-bold leading-tight text-emerald-600 dark:text-emerald-400" :end-val="summary.todayOutput" :duration="1200" />
              <span class="text-xs text-gray-400">件</span>
            </div>
            <div class="mt-1 text-xs text-gray-400">
              昨日 {{ summary.yesterdayOutput }} 件
              <span v-if="summary.yesterdayOutput > 0 && summary.todayOutput >= summary.yesterdayOutput" class="text-emerald-500">↑</span>
              <span v-else-if="summary.yesterdayOutput > 0" class="text-red-500">↓</span>
            </div>
          </div>
        </div>
        <div class="absolute inset-0 -z-0 bg-gradient-to-br from-emerald-500/5 to-green-500/5 opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
        <div class="absolute -right-6 -top-6 size-24 rounded-full bg-emerald-400/10 blur-xl transition-all duration-300 group-hover:scale-150" />
      </div>
    </Col>
    <!-- 质量合格率 -->
    <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
    <Col :lg="12" :md="12" :sm="12" :xl="12" :xs="24" class="mb-4">
      <div
        class="glass-tilt group cursor-pointer overflow-hidden rounded-2xl border-0"
        :style="tiltStyle('quality')"
@@ -154,7 +92,7 @@
    </Col>
    <!-- 设备运行率 -->
    <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
    <Col :lg="12" :md="12" :sm="12" :xl="12" :xs="24" class="mb-4">
      <div
        class="glass-tilt group cursor-pointer overflow-hidden rounded-2xl border-0"
        :style="tiltStyle('equip')"
@@ -204,7 +142,7 @@
  border: 1px solid rgba(255,255,255,0.08);
  box-shadow:
    0 4px 24px rgba(0,0,0,0.3),
    0 1px 4px rgba(0,0,0,0.2),
    0 2px 8px rgba(0,0,0,0.2),
    inset 0 1px 0 rgba(255,255,255,0.04);
}
</style>
src/views/dashboard/analytics/modules/quick-actions.vue
@@ -16,14 +16,9 @@
}
const actions: QuickAction[] = [
  { title: '生产工单', icon: 'lucide:file-text', route: 'MesProWorkOrder', gradient: 'from-blue-500 to-cyan-500', shadow: 'shadow-blue-500/15' },
  { title: '生产报工', icon: 'lucide:check-square', route: 'MesProFeedback', gradient: 'from-emerald-500 to-green-500', shadow: 'shadow-emerald-500/15' },
  { title: '质检管理', icon: 'lucide:clipboard-check', route: 'MesQcRecord', gradient: 'from-orange-500 to-amber-500', shadow: 'shadow-orange-500/15' },
  { title: '设备点检', icon: 'lucide:settings', route: 'MesDvMachinery', gradient: 'from-violet-500 to-purple-500', shadow: 'shadow-violet-500/15' },
  { title: '生产排程', icon: 'lucide:calendar-range', route: 'MesProScheduling', gradient: 'from-cyan-500 to-teal-500', shadow: 'shadow-cyan-500/15' },
  { title: '物料库存', icon: 'lucide:package-search', route: 'WlsMaterialStock', gradient: 'from-indigo-500 to-blue-500', shadow: 'shadow-indigo-500/15' },
  { title: '工艺路线', icon: 'lucide:route', route: 'MesPdRouting', gradient: 'from-teal-500 to-emerald-500', shadow: 'shadow-teal-500/15' },
  { title: '数据报表', icon: 'lucide:bar-chart-big', route: 'MesHomeIndex', gradient: 'from-pink-500 to-rose-500', shadow: 'shadow-pink-500/15' },
];
</script>
src/views/wls/barcode/data.ts
@@ -20,7 +20,7 @@
import { DictTag } from '#/components/dict-tag';
import { DvMachinerySelect } from '#/views/mes/dv/machinery/components';
import { MdClientSelect } from '#/views/mes/md/client/components';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { MdVendorSelect } from '#/views/mes/md/vendor/components';
import {
  MdWorkshopSelect,
@@ -249,7 +249,7 @@
    {
      fieldName: 'bizId',
      label: '产品物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        onChange: (item: any) => syncBizDetail(formApi, item),
      },
src/views/wls/batch/data.ts
@@ -12,7 +12,7 @@
import { DictTag } from '#/components/dict-tag';
import { getRangePickerDefaultProps } from '#/utils';
import { MdClientSelect } from '#/views/mes/md/client/components';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { MdVendorSelect } from '#/views/mes/md/vendor/components';
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
import { ProTaskSelect } from '#/views/mes/pro/task/components';
@@ -34,7 +34,7 @@
    {
      fieldName: 'itemId',
      label: '产品物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择产品物料',
      },
src/views/wls/itemreceipt/data.ts
@@ -1,7 +1,7 @@
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MdmItemModelApi } from '#/api/mdm/item-model';
import type { MesMdItemApi } from '#/api/mes/md/item';
import type { MdmItemApi } from '#/api/mdm/item';
import type { MesWmArrivalNoticeApi } from '#/api/mes/wm/arrivalnotice';
import type { MesWmArrivalNoticeLineApi } from '#/api/mes/wm/arrivalnotice/line';
import type { MesWmItemReceiptApi } from '#/api/mes/wm/itemreceipt';
@@ -23,7 +23,7 @@
import { getItemModelListByItem } from '#/api/mdm/item-model';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { SrmSupplierSelect } from '#/views/srm/supplier/components';
import {
  WmArrivalNoticeLineSelect,
@@ -585,11 +585,11 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择物料',
        // 切换物料后,型号、录入单位与数量都要重新选
        onChange: (item?: MesMdItemApi.Item) => handleItemChange(item?.id),
        onChange: (item?: MdmItemApi.Item) => handleItemChange(item?.id),
      },
      rules: 'selectRequired',
      dependencies: {
@@ -839,7 +839,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },
src/views/wls/materialstock/data.ts
@@ -7,7 +7,7 @@
import { useAccess } from '@vben/access';
import { DICT_TYPE } from '@vben/constants';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import {
  WmWarehouseAreaSelect,
@@ -21,7 +21,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择物料',
      },
src/views/wls/miscreceipt/data.ts
@@ -12,7 +12,7 @@
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import {
  WmWarehouseAreaSelect,
  WmWarehouseLocationSelect,
@@ -330,7 +330,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择物料',
      },
src/views/wls/outsourceissue/data.ts
@@ -1,6 +1,6 @@
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesMdItemApi } from '#/api/mes/md/item';
import type { MdmItemApi } from '#/api/mdm/item';
import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder';
import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock';
import type { MesWmOutsourceIssueApi } from '#/api/mes/wm/outsourceissue';
@@ -20,7 +20,7 @@
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { MdVendorSelect } from '#/views/mes/md/vendor/components';
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
import {
@@ -313,11 +313,11 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择物料',
        // 切换物料后,重新记录物料主单位并清空型号、录入单位口径
        onChange: async (item?: MesMdItemApi.Item) => {
        onChange: async (item?: MdmItemApi.Item) => {
          await unitHandlers.handleItemChange(item?.id);
        },
      },
@@ -424,7 +424,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },
src/views/wls/outsourcereceipt/data.ts
@@ -20,7 +20,7 @@
import { z } from '#/adapter/form';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { MdVendorSelect } from '#/views/mes/md/vendor/components';
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
import {
@@ -328,7 +328,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择物料',
      },
@@ -448,7 +448,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },
src/views/wls/packages/data.ts
@@ -17,7 +17,7 @@
import { getSimpleUserList } from '#/api/system/user';
import { ErpSaleOrderSelect } from '#/views/erp/sale/order/components';
import { MdClientSelect } from '#/views/mes/md/client/components';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { MdUnitMeasureSelect } from '#/views/mes/md/unitmeasure/components';
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
@@ -456,7 +456,7 @@
    {
      fieldName: 'itemId',
      label: '产品物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择产品物料',
      },
src/views/wls/productissue/data.ts
@@ -1,6 +1,6 @@
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesMdItemApi } from '#/api/mes/md/item';
import type { MdmItemApi } from '#/api/mdm/item';
import type { MesProTaskApi } from '#/api/mes/pro/task';
import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock';
import type { MesWmProductIssueApi } from '#/api/mes/wm/productissue';
@@ -20,7 +20,7 @@
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
import { ProTaskSelect } from '#/views/mes/pro/task/components';
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
@@ -336,11 +336,11 @@
    {
      fieldName: 'itemId',
      label: '产品物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择产品物料',
        // 切换物料后,重新记录物料主单位并清空型号、录入单位口径
        onChange: async (item?: MesMdItemApi.Item) => {
        onChange: async (item?: MdmItemApi.Item) => {
          await unitHandlers.handleItemChange(item?.id);
        },
      },
@@ -426,7 +426,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },
src/views/wls/productreceipt/data.ts
@@ -1,6 +1,5 @@
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock';
import type { MesWmProductReceiptApi } from '#/api/mes/wm/productreceipt';
import type { MesWmProductReceiptDetailApi } from '#/api/mes/wm/productreceipt/detail';
import type { MesWmProductReceiptLineApi } from '#/api/mes/wm/productreceipt/line';
@@ -17,9 +16,8 @@
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
import { WmMaterialStockSelect } from '#/views/wls/materialstock/components';
import {
  WmWarehouseAreaSelect,
  WmWarehouseLocationSelect,
@@ -255,34 +253,16 @@
}
/** 入库单行新增/修改的表单 */
export function useLineFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
export function useLineFormSchema(): VbenFormSchema[] {
  return [
    {
      fieldName: 'materialStockId',
      label: '库存记录',
      component: markRaw(WmMaterialStockSelect),
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdmItemSelect),
      componentProps: {
        // 选择库存记录后,自动回填物料/批次/数量
        onChange: async (stock?: MesWmMaterialStockApi.MaterialStock) => {
          await formApi?.setValues({
            batchCode: stock?.batchCode,
            batchId: stock?.batchId,
            itemId: stock?.itemId,
            quantity: stock?.quantity,
            quantityMax: stock?.quantity,
          });
        },
        virtualFilter: 'only',
        placeholder: '请选择物料',
      },
      rules: 'selectRequired',
    },
    {
      fieldName: 'quantityMax',
      component: 'Input',
      dependencies: {
        triggerFields: [''],
        show: () => false,
      },
    },
    {
      fieldName: 'quantity',
@@ -295,32 +275,13 @@
        precision: 2,
      },
      rules: 'required',
      dependencies: {
        triggerFields: ['quantityMax'],
        componentProps: (values) => ({
          class: '!w-full',
          max: values.quantityMax,
          min: 0,
          placeholder: '请输入入库数量',
          precision: 2,
        }),
      },
    },
    {
      fieldName: 'batchCode',
      label: '批次号',
      component: 'Input',
      componentProps: {
        disabled: true,
        placeholder: '选择库存后自动带出',
      },
    },
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      componentProps: {
        disabled: true,
        placeholder: '请输入批次号(可选)',
      },
    },
    {
@@ -380,7 +341,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },
src/views/wls/productreceipt/modules/line-form.vue
@@ -69,7 +69,7 @@
      formData.value = undefined;
      return;
    }
    formApi.setState({ schema: useLineFormSchema(formApi) });
    formApi.setState({ schema: useLineFormSchema() });
    // 加载数据
    const data = modalApi.getData<{ id?: number; receiptId: number }>();
    receiptId.value = data.receiptId;
src/views/wls/productsales/data.ts
@@ -1,6 +1,6 @@
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesMdItemApi } from '#/api/mes/md/item';
import type { MdmItemApi } from '#/api/mdm/item';
import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock';
import type { MesWmProductSalesApi } from '#/api/mes/wm/productsales';
import type { MesWmProductSalesDetailApi } from '#/api/mes/wm/productsales/detail';
@@ -24,7 +24,7 @@
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { ErpSaleOrderSelect } from '#/views/erp/sale/order/components';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { WmMaterialStockSelect } from '#/views/wls/materialstock/components';
import {
  buildItemUnitSchema,
@@ -530,11 +530,11 @@
    {
      fieldName: 'itemId',
      label: '产品',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择产品',
        // 切换产品后,重新记录物料主单位并清空型号、录入单位口径
        onChange: async (item?: MesMdItemApi.Item) => {
        onChange: async (item?: MdmItemApi.Item) => {
          await unitHandlers.handleItemChange(item?.id);
        },
      },
@@ -641,7 +641,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },
src/views/wls/returnsales/data.ts
@@ -16,7 +16,7 @@
import CrmCustomerSelect from '#/components/crm-customer-select.vue';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { ErpSaleOrderSelect } from '#/views/erp/sale/order/components';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { WmBatchSelect } from '#/views/wls/batch/components';
import {
  WmWarehouseAreaSelect,
@@ -354,7 +354,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: hasItems ? 'Select' : markRaw(MdItemSelect),
      component: hasItems ? 'Select' : markRaw(MdmItemSelect),
      componentProps: hasItems
        ? {
            placeholder: '请选择物料',
@@ -370,7 +370,6 @@
          }
        : {
            placeholder: '请选择物料',
            productIds: [],
          },
      rules: 'selectRequired',
    },
@@ -499,7 +498,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },
src/views/wls/returnvendor/data.ts
@@ -1,6 +1,6 @@
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesMdItemApi } from '#/api/mes/md/item';
import type { MdmItemApi } from '#/api/mdm/item';
import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock';
import type { MesWmReturnVendorApi } from '#/api/mes/wm/returnvendor';
import type { MesWmReturnVendorDetailApi } from '#/api/mes/wm/returnvendor/detail';
@@ -13,7 +13,7 @@
import { Button } from 'ant-design-vue';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { MdVendorSelect } from '#/views/mes/md/vendor/components';
import { ErpPurchaseOrderSelect } from '#/views/erp/purchase/order/components';
import { WmBatchSelect } from '#/views/wls/batch/components';
@@ -358,11 +358,11 @@
    {
      fieldName: 'itemId',
      label: '产品物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择产品物料',
        // 切换产品后,重新记录物料主单位并清空型号、录入单位口径
        onChange: async (item?: MesMdItemApi.Item) => {
        onChange: async (item?: MdmItemApi.Item) => {
          await unitHandlers.handleItemChange(item?.id);
        },
      },
@@ -470,7 +470,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },
src/views/wls/salesnotice/data.ts
@@ -16,7 +16,7 @@
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import CrmCustomerSelect from '#/components/crm-customer-select.vue';
import { ErpSaleOrderSelect } from '#/views/erp/sale/order/components';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'update';
@@ -355,7 +355,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择物料',
      },
src/views/wls/sn/data.ts
@@ -5,7 +5,7 @@
import { markRaw } from 'vue';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
/** 生成 SN 码的表单 */
export function useFormSchema(): VbenFormSchema[] {
@@ -13,7 +13,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择物料',
      },
@@ -59,7 +59,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择物料',
      },
src/views/wls/stocktaking/plan/components/condition-value-input.vue
@@ -10,7 +10,7 @@
import { getWarehouseArea } from '#/api/mes/wm/warehouse/area';
import { getWarehouseLocation } from '#/api/mes/wm/warehouse/location';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { WmBatchSelect } from '#/views/wls/batch/components';
import {
  WmWarehouseAreaSelect,
@@ -195,7 +195,7 @@
      @change="handleSelectorChange"
    />
  </div>
  <MdItemSelect
  <MdmItemSelect
    v-else-if="type === WlsStockTakingParamTypeEnum.ITEM"
    :model-value="effectiveValue"
    @change="handleSelectorChange"
src/views/wls/stocktaking/task/data.ts
@@ -20,7 +20,7 @@
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { StockTakingPlanSelect } from '#/views/wls/stocktaking/plan/components';
import {
  WmWarehouseAreaSelect,
@@ -498,7 +498,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择物料',
      },
src/views/wls/transfer/data.ts
@@ -18,7 +18,7 @@
import { z } from '#/adapter/form';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { WmMaterialStockSelect } from '#/views/wls/materialstock/components';
import {
  WmWarehouseAreaSelect,
@@ -446,7 +446,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },
@@ -576,7 +576,7 @@
    {
      fieldName: 'itemId',
      label: '物料',
      component: markRaw(MdItemSelect),
      component: markRaw(MdmItemSelect),
      componentProps: {
        disabled: true,
      },