buhuazhen
9 天以前 faa1b4e58a3b9ff41e446687b2d3a31e6709bd4b
feat(productionProcess): 添加工序机台选择功能到编辑表单

- 移除工序编号输入框,替换为远程搜索和分页加载的机台选择器
- 新增设备列表查询、滚动加载和防抖搜索逻辑
- 表单数据同步时确保已选设备在选项列表中
- 清理组件卸载时的监听器和定时器
已修改1个文件
212 ■■■■ 文件已修改
src/views/productionManagement/productionProcess/Edit.vue 212 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionProcess/Edit.vue
@@ -22,8 +22,42 @@
            ]">
          <el-input v-model="formState.name" />
        </el-form-item>
        <el-form-item label="工序编号" prop="no">
        <!-- <el-form-item label="工序编号" prop="no">
          <el-input v-model="formState.no"  />
        </el-form-item> -->
        <el-form-item
            label="工序机台"
            prop="deviceId"
            :rules="[
                {
                required: true,
                message: '请选择工序类型',
              }
            ]"
        >
          <el-select
              v-model="formState.deviceId"
              placeholder="请选择工序机台"
              filterable
              remote
              clearable
              reserve-keyword
              :remote-method="handleDeviceRemoteSearch"
              :loading="deviceLoading"
              @clear="handleDeviceClear"
              @change="handleDeviceChange"
              @visible-change="handleDeviceDropdownVisible"
              popper-class="device-select-popper"
          >
            <el-option v-for="item in equipmentList" :key="item.id" :label="item.deviceName" :value="item.id" />
            <el-option
                v-if="equipmentList.length > 0 && deviceHasMore"
                :value="__deviceLoadMoreSentinel"
                label="加载更多…"
                disabled
            />
          </el-select>
        </el-form-item>
        <el-form-item
            label="工序类型"
@@ -61,8 +95,9 @@
</template>
<script setup>
import { ref, computed, getCurrentInstance, watch } from "vue";
import { ref, computed, getCurrentInstance, watch, reactive, nextTick, onBeforeUnmount } from "vue";
import {update} from "@/api/productionManagement/productionProcess.js";
import { getLedgerPage } from "@/api/equipmentManagement/ledger.js";
const props = defineProps({
  visible: {
@@ -84,10 +119,36 @@
  name: props.record.name,
  type: props.record.type,
  no: props.record.no,
  deviceId: props.record.deviceId,
  deviceName: props.record.deviceName,
  remark: props.record.remark,
  salaryQuota: props.record.salaryQuota,
  isQuality: props.record.isQuality,
});
const page = reactive({
  current: 1,
  size: 10,
  total: 0,
});
const equipmentList = ref([]);
const deviceLoading = ref(false);
const deviceQuery = ref("");
const deviceScrollWrap = ref(null);
const __deviceLoadMoreSentinel = "__deviceLoadMoreSentinel";
const deviceHasMore = computed(() => {
  const total = Number(page.total ?? 0);
  if (!total) {
    return false;
  }
  return equipmentList.value.length < total;
});
const handleDeviceChange = (val) => {
  formState.value.deviceName = equipmentList.value.find(item => item.id === val)?.deviceName || "";
};
const isShow = computed({
  get() {
@@ -98,33 +159,133 @@
  },
});
// 监听 record 变化,更新表单数据
const ensureSelectedDeviceOption = () => {
  const currentDeviceId = formState.value.deviceId;
  if (!currentDeviceId || !props.record?.deviceName) {
    return;
  }
  const exists = equipmentList.value.some(item => item.id === currentDeviceId);
  if (!exists) {
    equipmentList.value.unshift({
      id: currentDeviceId,
      deviceName: props.record.deviceName,
    });
  }
};
const getLedgerPageS = async ({ reset = false } = {}) => {
  if (deviceLoading.value) return;
  deviceLoading.value = true;
  try {
    const res = await getLedgerPage({
      current: page.current,
      size: page.size,
      deviceName: deviceQuery.value ? deviceQuery.value : undefined,
    });
    const data = res?.data || {};
    const records = Array.isArray(data.records) ? data.records : [];
    page.total = Number(data.total ?? page.total ?? 0);
    page.current = Number(data.current ?? page.current);
    page.size = Number(data.size ?? page.size);
    equipmentList.value = reset ? records : [...equipmentList.value, ...records];
    ensureSelectedDeviceOption();
  } finally {
    deviceLoading.value = false;
  }
};
const resetDeviceOptions = async () => {
  page.current = 1;
  page.size = 10;
  page.total = 0;
  equipmentList.value = [];
  await getLedgerPageS({ reset: true });
};
const loadMoreDevices = async () => {
  if (deviceLoading.value) return;
  if (!deviceHasMore.value) return;
  page.current += 1;
  await getLedgerPageS();
};
let remoteTimer = null;
const handleDeviceRemoteSearch = (query) => {
  const nextQuery = (query ?? "").trim();
  deviceQuery.value = nextQuery;
  if (remoteTimer) clearTimeout(remoteTimer);
  remoteTimer = setTimeout(() => {
    resetDeviceOptions();
  }, 300);
};
const handleDeviceClear = () => {
  deviceQuery.value = "";
  resetDeviceOptions();
};
const onDeviceDropdownScroll = (e) => {
  const el = e.target;
  if (!el) return;
  if (el.scrollHeight - el.scrollTop - el.clientHeight <= 20) {
    loadMoreDevices();
  }
};
const unbindDeviceDropdownScroll = () => {
  if (deviceScrollWrap.value) {
    deviceScrollWrap.value.removeEventListener("scroll", onDeviceDropdownScroll);
    deviceScrollWrap.value = null;
  }
};
const bindDeviceDropdownScroll = () => {
  unbindDeviceDropdownScroll();
  const wrap =
      document.querySelector(".device-select-popper .el-scrollbar__wrap") ||
      document.querySelector(".device-select-popper .el-select-dropdown__wrap");
  if (wrap) {
    deviceScrollWrap.value = wrap;
    wrap.addEventListener("scroll", onDeviceDropdownScroll);
  }
};
const handleDeviceDropdownVisible = async (visible) => {
  if (!visible) {
    unbindDeviceDropdownScroll();
    return;
  }
  if (equipmentList.value.length === 0) {
    await resetDeviceOptions();
  }
  await nextTick();
  bindDeviceDropdownScroll();
};
const applyRecordToForm = (record) => {
  formState.value = {
    id: record.id,
    name: record.name || "",
    no: record.no || "",
    type: record.type,
    deviceId: record.deviceId,
    deviceName: record.deviceName || "",
    remark: record.remark || "",
    salaryQuota: record.salaryQuota || "",
    isQuality: record.isQuality,
  };
  ensureSelectedDeviceOption();
};
watch(() => props.record, (newRecord) => {
  if (newRecord && isShow.value) {
    formState.value = {
      id: newRecord.id,
      name: newRecord.name || '',
      no: newRecord.no || '',
      type: newRecord.type,
      remark: newRecord.remark || '',
      salaryQuota: newRecord.salaryQuota || '',
      isQuality: props.record.isQuality,
    };
    applyRecordToForm(newRecord);
  }
}, { immediate: true, deep: true });
// 监听弹窗打开,重新初始化表单数据
watch(() => props.visible, (visible) => {
  if (visible && props.record) {
    formState.value = {
      id: props.record.id,
      name: props.record.name || '',
      no: props.record.no || '',
      type: props.record.type,
      remark: props.record.remark || '',
      salaryQuota: props.record.salaryQuota || '',
      isQuality: props.record.isQuality,
    };
    applyRecordToForm(props.record);
  }
});
@@ -137,7 +298,7 @@
const handleSubmit = () => {
  proxy.$refs["formRef"].validate(valid => {
    if (valid) {
      update(formState.value).then(res => {
      update(formState.value).then(() => {
        // 关闭模态框
        isShow.value = false;
        // 告知父组件已完成
@@ -153,4 +314,9 @@
  handleSubmit,
  isShow,
});
onBeforeUnmount(() => {
  unbindDeviceDropdownScroll();
  if (remoteTimer) clearTimeout(remoteTimer);
});
</script>