zhangwencui
2026-04-29 8d172bf41d2b802d5782df559e236a71a3d31c2c
扫码报工模块重构
已添加1个文件
已修改3个文件
345 ■■■■ 文件已修改
src/api/productionManagement/productProcessRoute.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productionReporting.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/productionManagement/productionReport/index.vue 322 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/works.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productProcessRoute.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
// ç”Ÿäº§æŠ¥å·¥é¡µé¢æŽ¥å£
import request from "@/utils/request";
// èŽ·å–å·¥åºå‚æ•°åˆ—è¡¨-生产订单
export function findProcessParamListOrder(query) {
  return request({
    url: `/productionOrderRoutingOperationParam/list`,
    method: "get",
    params: query,
  });
}
src/api/productionManagement/productionReporting.js
@@ -20,9 +20,8 @@
// æ ¹æ®ID获取工单详情
export function getProductWorkOrderById(query) {
  return request({
    url: "/productWorkOrder/getProductWorkOrderById",
    url: "/productionOperationTask/" + query.id,
    method: "get",
    params: query,
  });
}
// ç”Ÿäº§æŠ¥å·¥
src/pages/productionManagement/productionReport/index.vue
@@ -41,6 +41,58 @@
                   suffix-icon="arrow-down" />
        </u-form-item>
      </view>
      <!-- åŠ¨æ€å‚æ•°åŒºåŸŸ -->
      <view class="form-section"
            v-if="params.length > 0">
        <view class="section-title">工序参数</view>
        <u-form-item v-for="param in params"
                     :key="param.id"
                     :label="param.paramName"
                     :label-width="110"
                     :required="param.required === '1'">
          <!-- æ•°å­—类型 -->
          <template v-if="param.paramType == '1'">
            <u-input v-model="form.paramGroups[param.id]"
                     type="number"
                     :placeholder="'请输入' + param.paramName"
                     :key="param.id" />
            <text v-if="param.unit && param.unit != '/'"
                  class="param-unit">{{ param.unit }}</text>
          </template>
          <!-- æ–‡æœ¬ç±»åž‹ -->
          <template v-else-if="param.paramType == '2'">
            <u-input v-model="form.paramGroups[param.id]"
                     :placeholder="'请输入' + param.paramName"
                     :key="param.id" />
            <text v-if="param.unit && param.unit != '/'"
                  class="param-unit">{{ param.unit }}</text>
          </template>
          <!-- é€‰æ‹©ç±»åž‹ -->
          <template v-else-if="param.paramType == '3'">
            <u-input v-model="form.paramGroups[param.id]"
                     readonly
                     :placeholder="'请选择' + param.paramName"
                     @click="openParamSelect(param)"
                     suffix-icon="arrow-down" />
          </template>
          <!-- æ—¥æœŸç±»åž‹ -->
          <template v-else-if="param.paramType == '4'">
            <u-input v-model="form.paramGroups[param.id]"
                     readonly
                     :placeholder="'请选择' + param.paramName"
                     @click="openDateParamPicker(param)"
                     suffix-icon="arrow-down" />
            <text v-if="param.unit && param.unit != '/'"
                  class="param-unit">{{ param.unit }}</text>
          </template>
          <!-- é»˜è®¤æ–‡æœ¬ -->
          <template v-else>
            <u-input v-model="form.paramGroups[param.id]"
                     :placeholder="'请输入' + param.paramName"
                     :key="param.id" />
          </template>
        </u-form-item>
      </view>
      <!-- ä½¿ç”¨FooterButtons组件 -->
      <FooterButtons @cancel="goBack"
                     @confirm="submitForm"
@@ -54,6 +106,18 @@
                     title="选择生产人"
                     @select="onProducerConfirm"
                     @close="showProducerPicker = false" />
    <!-- å‚数选择器 -->
    <up-action-sheet :show="showParamSelect"
                     :actions="paramOptions"
                     :title="currentParam?.paramName || '选择'"
                     @select="onParamConfirm"
                     @close="showParamSelect = false" />
    <!-- æ—¥æœŸé€‰æ‹©å™¨ -->
    <up-datetime-picker :show="showDatePicker"
                        v-model="datePickerValue"
                        :mode="datePickerMode"
                        @confirm="onDateConfirm"
                        @cancel="showDatePicker = false" />
  </view>
</template>
@@ -71,11 +135,12 @@
  import { addProductMain } from "@/api/productionManagement/productionReporting";
  import { getInfo } from "@/api/login";
  import { userListNoPageByTenantId } from "@/api/system/user";
  import { findProcessParamListOrder } from "@/api/productionManagement/productProcessRoute.js";
  import { getDicts } from "@/api/system/dict/data";
  import { formatDateToYMD, parseTime } from "@/utils/ruoyi";
  // è¡¨å•引用
  const formRef = ref();
  // è¡¨å•数据
  let form = ref({
    planQuantity: "",
    quantity: "",
@@ -85,20 +150,32 @@
    productProcessRouteItemId: "",
    userId: "",
    schedulingUserId: "",
    reportWork: "",
    productMainId: null,
    productionOrderRoutingOperationId: "",
    productionOrderId: "",
    paramGroups: {},
  });
  // ç”Ÿäº§äººé€‰æ‹©å™¨çŠ¶æ€
  const showProducerPicker = ref(false);
  const producerList = ref([]);
  // æ‰“开生产人选择器
  const params = ref([]);
  const dictOptions = ref({});
  const showParamSelect = ref(false);
  const currentParam = ref(null);
  const paramOptions = ref([]);
  const showDatePicker = ref(false);
  const datePickerValue = ref(Date.now());
  const datePickerMode = ref("date");
  const currentDateParam = ref(null);
  const openProducerPicker = async () => {
    if (producerList.value.length === 0) {
      // å¦‚果列表为空,先加载用户列表
      try {
        const res = await userListNoPageByTenantId();
        const users = res.data || [];
        // è½¬æ¢ä¸º action-sheet éœ€è¦çš„æ ¼å¼
        producerList.value = users.map(user => ({
          name: user.nickName || user.userName,
          value: user.userId,
@@ -112,102 +189,236 @@
    showProducerPicker.value = true;
  };
  // ç”Ÿäº§äººé€‰æ‹©ç¡®è®¤
  const onProducerConfirm = e => {
    form.value.schedulingUserId = e.value;
    form.value.userName = e.name;
    form.value.userId = e.value; // åŒæ—¶æ›´æ–° userId
    form.value.userId = e.value;
    showProducerPicker.value = false;
  };
  // æäº¤çŠ¶æ€
  const openParamSelect = async param => {
    currentParam.value = param;
    if (param.paramType == "3" && param.paramFormat) {
      const options = await getDictOptions(param.paramFormat);
      paramOptions.value = options.map(opt => ({
        name: opt.dictLabel,
        value: opt.dictLabel,
      }));
    }
    showParamSelect.value = true;
  };
  const onParamConfirm = e => {
    if (currentParam.value) {
      form.value.paramGroups[currentParam.value.id] = e.value;
    }
    showParamSelect.value = false;
  };
  const openDateParamPicker = param => {
    currentDateParam.value = param;
    const currentValue = form.value.paramGroups[param.id];
    datePickerValue.value = currentValue
      ? new Date(currentValue).getTime()
      : Date.now();
    // å‚ç…§ PC ç«¯é€»è¾‘:如果格式是 yyyy-MM-dd åˆ™ä¸º date æ¨¡å¼ï¼Œå¦åˆ™ä¸º datetime æ¨¡å¼
    datePickerMode.value =
      param.paramFormat === "yyyy-MM-dd" ? "date" : "datetime";
    showDatePicker.value = true;
  };
  const onDateConfirm = e => {
    if (currentDateParam.value) {
      const format =
        currentDateParam.value.paramFormat === "yyyy-MM-dd"
          ? "{y}-{m}-{d}"
          : "{y}-{m}-{d} {h}:{i}:{s}";
      form.value.paramGroups[currentDateParam.value.id] = parseTime(
        e.value,
        format
      );
    }
    showDatePicker.value = false;
  };
  const getDictOptions = async dictType => {
    if (!dictType) return [];
    if (dictOptions.value[dictType]) return dictOptions.value[dictType];
    try {
      const res = await getDicts(dictType);
      if (res.code === 200) {
        dictOptions.value[dictType] = res.data;
        return res.data;
      }
      return [];
    } catch (error) {
      console.error("获取字典数据失败:", error);
      return [];
    }
  };
  const loadParams = (productionOrderRoutingOperationId, productionOrderId) => {
    findProcessParamListOrder({
      productionOrderRoutingOperationId,
      productionOrderId,
    })
      .then(res => {
        if (res.code === 200) {
          console.log(res.data, "res.data========");
          const paramList = res.data || [];
          params.value = paramList;
          form.value.paramGroups = {};
          paramList.forEach(param => {
            if (!form.value.paramGroups[param.id]) {
              form.value.paramGroups[param.id] = "";
            }
            if (param.paramType == "3" && param.paramFormat) {
              getDictOptions(param.paramFormat);
            }
          });
        }
      })
      .catch(err => {
        console.error("获取工序参数失败:", err);
      });
  };
  const submitting = ref(false);
  // è¿”回上一页
  const goBack = () => {
    uni.navigateBack();
  };
  // æäº¤è¡¨å•
  const submitForm = async () => {
    submitting.value = true;
    // æ ¡éªŒè¡¨å•
    if (!form.value.quantity) {
      submitting.value = false;
      showToast("请输入本次生产数量");
      return;
    }
    if (!form.value.schedulingUserId) {
      submitting.value = false;
      showToast("请选择生产人");
      return;
    }
    // è½¬æ¢ä¸ºæ•°å­—进行比较
    const quantity = Number(form.value.quantity) || 0;
    const scrapQty = Number(form.value.scrapQty) || 0;
    const planQuantity = Number(form.value.planQuantity);
    // éªŒè¯ç”Ÿäº§æ•°é‡å’ŒæŠ¥åºŸæ•°é‡çš„和不能超过待生产数量
    if (quantity <= 0) {
      submitting.value = false;
      showToast("本次生产数量必须大于0");
      return;
    }
    if (quantity + scrapQty > planQuantity) {
      submitting.value = false;
      showToast("生产数量和报废数量的和不能超过待生产数量");
      return;
    }
    if (quantity > planQuantity) {
    if (scrapQty < 0) {
      submitting.value = false;
      showToast("本次生产数量不能大于待生产数量");
      showToast("报废数量不能小于0");
      return;
    }
    // å‡†å¤‡æäº¤æ•°æ®ï¼Œç¡®ä¿æ•°é‡å­—段为数字类型
    if (scrapQty > quantity) {
      submitting.value = false;
      showToast("报废数量不能大于本次生产数量");
      return;
    }
    const productionOperationParamList = params.value.map(param => ({
      ...param,
      inputValue: form.value.paramGroups[param.id] ?? "",
    }));
    const submitData = {
      ...form.value,
      quantity: Number(form.value.quantity),
      scrapQty: Number(form.value.scrapQty) || 0,
      planQuantity: Number(form.value.planQuantity) || 0,
      quantity: quantity,
      scrapQty: scrapQty,
      userId: form.value.userId,
      userName: form.value.userName,
      productionOperationTaskId: form.value.workOrderId,
      productProcessRouteItemId: form.value.productProcessRouteItemId,
      reportWork: form.value.reportWork,
      productMainId: form.value.productMainId,
      productionOrderRoutingOperationId:
        form.value.productionOrderRoutingOperationId,
      productionOrderId: form.value.productionOrderId,
      productionOperationParamList: productionOperationParamList,
    };
    console.log(submitData, "submitData");
    addProductMain(submitData).then(res => {
      if (res.code === 200) {
        showToast("报工成功");
    addProductMain(submitData)
      .then(res => {
        if (res.code === 200) {
          showToast("报工成功");
          submitting.value = false;
          setTimeout(() => {
            goBack();
          }, 1000);
        } else {
          showToast(res.msg || "报工失败");
          submitting.value = false;
        }
      })
      .catch(() => {
        showToast("报工失败");
        submitting.value = false;
        setTimeout(() => {
          goBack();
        }, 1000);
      } else {
        showToast(res.msg || "报工失败");
        submitting.value = false;
      }
    });
      });
  };
  // é¡µé¢åŠ è½½æ—¶åˆå§‹åŒ–æ•°æ®
  onLoad(options => {
    console.log(options, "options");
    // å¦‚果没有 orderRow å‚数,说明是从首页直接跳转,需要用户手动选择订单
    if (!options.orderRow) {
      console.log("从首页跳转,无订单数据");
      getInfo().then(res => {
        // é»˜è®¤ä½¿ç”¨å½“前登录用户
        form.value.userId = res.user.userId;
        form.value.userName = res.user.userName;
        form.value.userName = res.user.nickName || res.user.userName;
        form.value.schedulingUserId = res.user.userId;
      });
      return;
    }
    try {
      const orderRow = JSON.parse(options.orderRow);
      const orderRow = JSON.parse(decodeURIComponent(options.orderRow));
      console.log("构造的orderRow:", orderRow);
      console.log(orderRow, "orderRow======########");
      // ç¡®ä¿ planQuantity è½¬æ¢ä¸ºå­—符串,以便在 u-input ä¸­æ­£ç¡®æ˜¾ç¤º
      form.value.planQuantity = orderRow.planQuantity != null ? String(orderRow.planQuantity) : "";
      form.value.productProcessRouteItemId = orderRow.productProcessRouteItemId || "";
      form.value.planQuantity =
        orderRow.planQuantity != null ? String(orderRow.planQuantity) : "";
      form.value.productProcessRouteItemId =
        orderRow.productProcessRouteItemId || "";
      form.value.workOrderId = orderRow.id || "";
      form.value.reportWork = orderRow.reportWork || "";
      form.value.productMainId = orderRow.productMainId || null;
      form.value.productionOrderRoutingOperationId =
        orderRow.productionOrderRoutingOperationId || "";
      form.value.productionOrderId = orderRow.productionOrderId || "";
      getInfo().then(res => {
        // é»˜è®¤ä½¿ç”¨å½“前登录用户,但允许用户修改
        form.value.userId = res.user.userId;
        form.value.userName = res.user.userName;
        form.value.userName = res.user.nickName || res.user.userName;
        form.value.schedulingUserId = res.user.userId;
      });
      // ä½¿ç”¨ nextTick ç¡®ä¿ DOM æ›´æ–°
      console.log(orderRow, "orderRow=====");
      if (
        orderRow.productionOrderRoutingOperationId &&
        orderRow.productionOrderId
      ) {
        nextTick(() => {
          loadParams(
            orderRow.productionOrderRoutingOperationId,
            orderRow.productionOrderId
          );
        });
      }
      nextTick(() => {
        console.log("form.value after assignment:", form.value);
      });
@@ -215,13 +426,30 @@
      console.error("订单解析失败:", error);
      showToast("订单解析失败");
      goBack();
      return;
    }
  });
</script>
<style scoped lang="scss">
  @import "@/static/scss/form-common.scss";
  .form-section {
    background: #fff;
    margin-bottom: 12px;
    padding: 0 16px;
  }
  .section-title {
    font-size: 28rpx;
    font-weight: bold;
    color: #303133;
    padding: 24rpx 0 16rpx;
    border-bottom: 1px solid #f0f0f0;
  }
  .param-unit {
    margin-left: 8rpx;
    color: #909399;
    font-size: 24rpx;
  }
</style>
src/pages/works.vue
@@ -1062,14 +1062,7 @@
              const workData = workRes.data;
              console.log("工单数据:", workData);
              orderRow = JSON.stringify({
                id: workData.id || workOrderId,
                planQuantity: workData.planQuantity - workData.completeQuantity,
                productProcessRouteItemId:
                  workData.productProcessRouteItemId ||
                  workData.产品工艺路线项ID ||
                  "",
              });
              orderRow = JSON.stringify(workData);
              console.log("构造的orderRow:", orderRow);
            } else {