gaoluyang
2026-06-16 e65bfa1d46d255f307eaa057665f01c8bde0e122
src/views/productionManagement/workOrderManagement/index.vue
@@ -1,6 +1,6 @@
<template>
  <div class="app-container">
    <div class="search_form">
    <div class="search_form mb20">
      <div class="search-row">
        <div class="search-item">
          <span class="search_title">工单编号:</span>
@@ -13,7 +13,7 @@
        </div>
        <div class="search-item">
          <span class="search_title">生产订单号:</span>
          <el-input v-model="searchForm.productOrderNpsNo"
          <el-input v-model="searchForm.npsNo"
                    style="width: 240px"
                    placeholder="请输入"
                    @change="handleQuery"
@@ -23,6 +23,11 @@
        <div class="search-item">
          <el-button type="primary"
                     @click="handleQuery">搜索</el-button>
        </div>
        <div class="search-item">
          <el-switch v-model="filterMine"
                     active-text="仅看我的"
                     @change="handleQuery" />
        </div>
      </div>
    </div>
@@ -57,7 +62,7 @@
              <span class="info-value">{{ transferCardRowData.productName }}</span>
            </div>
            <div class="info-item">
              <span class="info-label">产品规格</span>
              <span class="info-label">规格型号</span>
              <span class="info-value">{{ transferCardRowData.model }}</span>
            </div>
            <div class="info-item">
@@ -115,9 +120,9 @@
                   @click="printTransferCard">打印流转卡</el-button>
      </div>
    </el-dialog>
    <!-- 报工弹窗 -->
    <!-- 报工弹窗(结束报工用) -->
    <el-dialog v-model="reportDialogVisible"
               title="报工"
               title="结束报工"
               width="500px">
      <el-form ref="reportFormRef"
               :model="reportForm"
@@ -128,14 +133,14 @@
                    readonly
                    style="width: 300px" />
        </el-form-item>
        <el-form-item label="本次生产数量"
        <el-form-item label="生产合格数量"
                      prop="quantity">
          <el-input v-model.number="reportForm.quantity"
                    type="number"
                    min="1"
                    min="0"
                    step="1"
                    style="width: 300px"
                    placeholder="请输入本次生产数量"
                    placeholder="请输入生产合格数量"
                    @input="handleQuantityInput" />
        </el-form-item>
        <el-form-item label="报废数量"
@@ -160,6 +165,16 @@
                       :label="user.nickName"
                       :value="user.userId" />
          </el-select>
        </el-form-item>
        <el-form-item label="工时"
                      v-if="currentReportRowData?.type == 0"
                      prop="workHour">
          <el-input v-model.number="reportForm.workHour"
                    type="number"
                    min="0"
                    style="width: 280px"
                    placeholder="请输入工时" /><span style="margin-left:10px"
                class="param-unit">h</span>
        </el-form-item>
        <div v-if="params.length > 0"
             class="param-grid"
@@ -234,7 +249,7 @@
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
                     @click="handleReport">确定</el-button>
                     @click="handleFinishWork">确定</el-button>
          <el-button @click="reportDialogVisible = false">取消</el-button>
        </span>
      </template>
@@ -242,7 +257,11 @@
    <MaterialDialog v-model="materialDialogVisible"
                    :row-data="currentMaterialOrderRow"
                    @refresh="getList" />
    <FilesDia ref="workOrderFilesRef" />
    <FileList v-if="fileDialogVisible"
              v-model:visible="fileDialogVisible"
              :editable="!currentWorkOrderRow?.endOrder"
              :record-type="'production_operation_task'"
              :record-id="currentWorkOrderId" />
  </div>
</template>
@@ -253,6 +272,7 @@
  import {
    productWorkOrderPage,
    addProductMain,
    startWork,
    downProductWorkOrder,
  } from "@/api/productionManagement/workOrder.js";
  import { findProcessParamListOrder } from "@/api/productionManagement/productProcessRoute.js";
@@ -260,125 +280,79 @@
  import { getDicts } from "@/api/system/dict/data";
  import QRCode from "qrcode";
  import { getCurrentInstance, reactive, toRefs } from "vue";
  import FilesDia from "./components/filesDia.vue";
  import MaterialDialog from "./components/MaterialDialog.vue";
  const FileList = defineAsyncComponent(() =>
    import("@/components/Dialog/FileList.vue")
  );
  import useUserStore from "@/store/modules/user";
  const { proxy } = getCurrentInstance();
  const userStore = useUserStore();
  const isCompleted = row => {
    const status = Number(row?.completionStatus);
    return Number.isFinite(status) && status >= 100;
  };
  const canOperate = row => !row.endOrder && !isCompleted(row);
  const tableColumn = ref([
    { label: "工单类型", prop: "workOrderType", width: "80" },
    { label: "工单编号", prop: "workOrderNo", width: "140" },
    { label: "生产订单号", prop: "npsNo", width: "140" },
    { label: "产品名称", prop: "productName", width: "140" },
    { label: "规格", prop: "model" },
    { label: "单位", prop: "unit" },
    { label: "工序名称", prop: "operationName", width: "100" },
    { label: "需求数量", prop: "planQuantity", width: "140" },
    { label: "完成数量", prop: "completeQuantity", width: "140" },
    { label: "完成进度", prop: "completionStatus", dataType: "slot", slot: "completionStatus", width: "140" },
    { label: "计划开始时间", prop: "planStartTime", width: "140" },
    { label: "计划结束时间", prop: "planEndTime", width: "140" },
    { label: "实际开始时间", prop: "actualStartTime", width: "140" },
    { label: "实际结束时间", prop: "actualEndTime", width: "140" },
    {
      label: "工单类型",
      prop: "workOrderType",
      width: "80",
    },
    {
      label: "工单编号",
      prop: "workOrderNo",
      width: "140",
    },
    {
      label: "生产订单号",
      prop: "npsNo",
      width: "140",
    },
    {
      label: "产品名称",
      prop: "productName",
      width: "140",
    },
    {
      label: "规格",
      prop: "model",
    },
    {
      label: "单位",
      prop: "unit",
    },
    {
      label: "工序名称",
      prop: "operationName",
      width: "100",
    },
    {
      label: "需求数量",
      prop: "planQuantity",
      width: "140",
    },
    {
      label: "完成数量",
      prop: "completeQuantity",
      width: "140",
    },
    {
      label: "完成进度",
      prop: "completionStatus",
      dataType: "slot",
      slot: "completionStatus",
      width: "140",
    },
    {
      label: "计划开始时间",
      prop: "planStartTime",
      width: "140",
    },
    {
      label: "计划结束时间",
      prop: "planEndTime",
      width: "140",
    },
    {
      label: "实际开始时间",
      prop: "actualStartTime",
      width: "140",
    },
    {
      label: "实际结束时间",
      prop: "actualEndTime",
      width: "140",
    },
    {
      label: "操作",
      width: "260",
      align: "center",
      dataType: "action",
      fixed: "right",
      label: "操作", width: "260", align: "center", dataType: "action", fixed: "right",
      operation: [
        {
          name: "流转卡",
          clickFun: row => {
            downloadAndPrintWorkOrder(row);
          },
          clickFun: row => { downloadAndPrintWorkOrder(row); },
        },
        {
          name: "附件",
          clickFun: row => {
            openWorkOrderFiles(row);
          },
          clickFun: row => { openWorkOrderFiles(row); },
        },
        // {
        //   name: "物料",
        //   clickFun: row => {
        //     openMaterialDialog(row);
        //   },
        // },
        {
          name: "报工",
          clickFun: row => {
            showReportDialog(row);
          name: "开始报工",
          showHide: row => canOperate(row) && !row.actualStartTime,
          disabled: row => {
            if (row.planQuantity <= 0) return true;
            if (!row.userIds) return false;
            try {
              const userIds = typeof row.userIds === "string" ? JSON.parse(row.userIds) : row.userIds;
              if (Array.isArray(userIds)) {
                return !userIds.some(id => String(id) === String(userStore.id));
              }
              return true;
            } catch (e) { return true; }
          },
          disabled: row => row.planQuantity <= 0,
          clickFun: row => { handleStartWork(row); },
        },
        {
          name: "结束报工",
          showHide: row => canOperate(row) && !!row.actualStartTime,
          clickFun: row => { showReportDialog(row); },
        },
      ],
    },
  ]);
  const tableData = ref([]);
  const tableLoading = ref(false);
  const transferCardVisible = ref(false);
  const transferCardData = ref([]);
  const transferCardQrUrl = ref("");
  const transferCardRowData = ref(null);
  const reportDialogVisible = ref(false);
  const workOrderFilesRef = ref(null);
  const fileDialogVisible = ref(false);
  const currentWorkOrderId = ref(null);
  const reportFormRef = ref(null);
  const userOptions = ref([]);
  const reportForm = reactive({
@@ -393,6 +367,7 @@
    productMainId: null,
    productionOrderRoutingOperationId: "",
    productionOrderId: "",
    workHour: 0,
    paramGroups: {},
  });
@@ -400,118 +375,75 @@
  const dictOptions = ref({});
  const paramLoading = ref(false);
  // 本次生产数量验证规则
  const validateQuantity = (rule, value, callback) => {
    if (value === null || value === undefined || value === "") {
      callback(new Error("请输入本次生产数量"));
      callback(new Error("请输入生产合格数量"));
      return;
    }
    const num = Number(value);
    // 整数且大于等于1
    if (isNaN(num) || !Number.isInteger(num) || num < 1) {
      callback(new Error("本次生产数量必须大于等于1"));
    if (isNaN(num) || !Number.isInteger(num) || num < 0) {
      callback(new Error("生产合格数量必须大于等于0"));
      return;
    }
    callback();
  };
  // 报废数量验证规则
  const validateScrapQty = (rule, value, callback) => {
    if (value === null || value === undefined || value === "") {
      callback();
      return;
    }
    const num = Number(value);
    // 整数且大于等于0
    if (isNaN(num) || !Number.isInteger(num) || num < 0) {
      callback(new Error("报废数量必须大于等于0"));
      return;
    }
    callback();
  };
  // 验证规则
  const reportFormRules = {
    quantity: [{ required: true, validator: validateQuantity, trigger: "blur" }],
    scrapQty: [{ validator: validateScrapQty, trigger: "blur" }],
  };
  // 处理本次生产数量输入,限制必须大于等于1
  const handleQuantityInput = value => {
    if (value === "" || value === null || value === undefined) {
      reportForm.quantity = null;
      return;
    }
    if (value === "" || value === null || value === undefined) { reportForm.quantity = null; return; }
    const num = Number(value);
    if (isNaN(num)) {
      return;
    }
    // 如果小于1,清除
    if (num < 1) {
      reportForm.quantity = null;
      return;
    }
    // 如果是小数取整数部分
    if (isNaN(num)) return;
    if (num < 0) { reportForm.quantity = null; return; }
    if (!Number.isInteger(num)) {
      const intValue = Math.floor(num);
      // 如果取整后小于1,清除
      if (intValue < 1) {
        reportForm.quantity = null;
        return;
      }
      if (intValue < 0) { reportForm.quantity = null; return; }
      reportForm.quantity = intValue;
      return;
    }
    reportForm.quantity = num;
  };
  // 处理报废数量
  const handleScrapQtyInput = value => {
    if (value === "" || value === null || value === undefined) {
      reportForm.scrapQty = null;
      return;
    }
    if (value === "" || value === null || value === undefined) { reportForm.scrapQty = null; return; }
    const num = Number(value);
    // 如果是NaN,保持原值
    if (isNaN(num)) {
      return;
    }
    // 如果是负数,清除输入
    if (num < 0) {
      reportForm.scrapQty = null;
      return;
    }
    // 如果是小数,取整数部分
    if (!Number.isInteger(num)) {
      reportForm.scrapQty = Math.floor(num);
      return;
    }
    // 有效的非负整数(包括0)
    if (isNaN(num)) return;
    if (num < 0) { reportForm.scrapQty = null; return; }
    if (!Number.isInteger(num)) { reportForm.scrapQty = Math.floor(num); return; }
    reportForm.scrapQty = num;
  };
  const filterMine = ref(false);
  const currentReportRowData = ref(null);
  const materialDialogVisible = ref(false);
  const currentMaterialOrderRow = ref(null);
  const page = reactive({
    current: 1,
    size: 100,
    total: 0,
  });
  const page = reactive({ current: 1, size: 100, total: 0 });
  const data = reactive({
    searchForm: {
      workOrderNo: "",
      productOrderNpsNo: "",
    },
    searchForm: { workOrderNo: "", npsNo: "" },
  });
  const { searchForm } = toRefs(data);
  const toProgressPercentage = val => {
    const n = Number(val);
    if (!Number.isFinite(n)) return 0;
    if (n <= 0) return 0;
    if (n >= 100) return 100;
    return Math.round(n);
    return parseFloat(n.toFixed(2));
  };
  const progressColor = percentage => {
    const p = toProgressPercentage(percentage);
@@ -521,78 +453,41 @@
    return "#67c23a";
  };
  // 查询列表
  /** 搜索按钮操作 */
  const handleQuery = () => {
    page.current = 1;
    getList();
  };
  const pagination = obj => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  };
  const handleQuery = () => { page.current = 1; getList(); };
  const pagination = obj => { page.current = obj.page; page.size = obj.limit; getList(); };
  const getList = () => {
    tableLoading.value = true;
    const params = { ...searchForm.value, ...page };
    if (filterMine.value) { params.filterMine = true; }
    productWorkOrderPage(params)
      .then(res => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        page.total = res.data.total;
      })
      .catch(() => {
        tableLoading.value = false;
      });
      .catch(() => { tableLoading.value = false; });
  };
  // 下载并打印工单流转卡(文件流)
  const downloadAndPrintWorkOrder = async row => {
    if (!row || !row.id) {
      proxy.$modal.msgError("缺少工单ID,无法下载流转卡");
      return;
    }
    const fileName = row.workOrderNo
      ? `工单流转卡_${row.workOrderNo}.xlsx`
      : "工单流转卡.xlsx";
    try {
      // 调用接口,以 responseType: 'blob' 获取文件流
      const blob = await downProductWorkOrder(row.id);
      if (!blob) {
        proxy.$modal.msgError("未获取到流转卡文件");
        return;
      }
      // 创建 Blob URL
      const fileBlob =
        blob instanceof Blob
          ? blob
          : new Blob([blob], { type: blob.type || "application/octet-stream" });
      if (!blob) { proxy.$modal.msgError("未获取到流转卡文件"); return; }
      const fileBlob = blob instanceof Blob ? blob : new Blob([blob], { type: blob.type || "application/octet-stream" });
      const url = window.URL.createObjectURL(fileBlob);
      // 创建隐藏 iframe,用于触发浏览器打印
      const iframe = document.createElement("iframe");
      iframe.style.position = "fixed";
      iframe.style.right = "0";
      iframe.style.bottom = "0";
      iframe.style.width = "0";
      iframe.style.height = "0";
      iframe.style.border = "0";
      iframe.style.right = "0"; iframe.style.bottom = "0";
      iframe.style.width = "0"; iframe.style.height = "0"; iframe.style.border = "0";
      iframe.src = url;
      document.body.appendChild(iframe);
      iframe.onload = () => {
        try {
          iframe.contentWindow?.focus();
          iframe.contentWindow?.print();
        } catch (e) {
          console.error("自动调用打印失败", e);
          // 退而求其次,打开新窗口由用户手动打印
          window.open(url);
        }
        try { iframe.contentWindow?.focus(); iframe.contentWindow?.print(); }
        catch (e) { window.open(url); }
      };
    } catch (e) {
      console.error("下载工单流转卡失败", e);
@@ -600,52 +495,66 @@
    }
  };
  const showTransferCard = async row => {
    transferCardRowData.value = row;
    const qrContent = String(row.id);
    transferCardQrUrl.value = await QRCode.toDataURL(qrContent);
    transferCardVisible.value = true;
  };
  const printTransferCard = () => {
    window.print();
  };
  const printTransferCard = () => { window.print(); };
  const currentWorkOrderRow = ref(null);
  const openWorkOrderFiles = row => {
    workOrderFilesRef.value?.openDialog(row);
    currentWorkOrderId.value = row.id;
    currentWorkOrderRow.value = row;
    fileDialogVisible.value = true;
  };
  const showReportDialog = row => {
  const handleStartWork = row => {
    proxy.$modal
      .confirm("确认开始报工?", "提示", { type: "info" })
      .then(async () => {
        try {
          await startWork({
            productionOperationTaskId: row.id,
            userId: userStore.id,
          });
          proxy.$modal.msgSuccess("开始报工成功");
          getList();
        } catch (e) {
          proxy.$modal.msgError("开始报工失败");
        }
      })
      .catch(() => {});
  };
  const showReportDialog = async row => {
    currentReportRowData.value = row;
    reportForm.planQuantity = row.planQuantity;
    reportForm.quantity =
      row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
    const planQuantity = Number(row.planQuantity || 0);
    const completeQuantity = Number(row.completeQuantity || 0);
    const remainingQuantity = Math.max(0, planQuantity - completeQuantity);
    reportForm.planQuantity = remainingQuantity;
    reportForm.quantity = row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
    reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
    reportForm.workOrderId = row.id;
    reportForm.reportWork = row.reportWork;
    reportForm.productMainId = row.productMainId;
    reportForm.scrapQty =
      row.scrapQty !== undefined && row.scrapQty !== null ? row.scrapQty : null;
    reportForm.productionOrderRoutingOperationId =
      row.productionOrderRoutingOperationId;
    reportForm.scrapQty = row.scrapQty !== undefined && row.scrapQty !== null ? row.scrapQty : null;
    reportForm.productionOrderRoutingOperationId = row.productionOrderRoutingOperationId;
    reportForm.productionOrderId = row.productionOrderId;
    reportForm.workHour = row.type == 0 ? (row.workHour || 0) : 0;
    nextTick(() => {
      reportFormRef.value?.clearValidate();
      if (row.productionOrderRoutingOperationId && row.productionOrderId) {
        loadParams(row.productionOrderRoutingOperationId, row.productionOrderId);
      }
    });
    if (userStore.id) {
      reportForm.userId = userStore.id;
      reportForm.userName = userStore.name || userStore.nickName || "";
    }
    getUserProfile()
      .then(res => {
        if (res.code === 200) {
        if (res.code === 200 && res.data) {
          reportForm.userId = res.data.userId;
          reportForm.userName = res.data.nickName;
          reportForm.userName = res.data.nickName || res.data.userName || "";
        }
      })
      .catch(err => {
        console.error("获取用户信息失败", err);
      });
      .catch(err => { console.error("获取用户信息失败", err); });
    reportDialogVisible.value = true;
  };
@@ -655,60 +564,26 @@
    materialDialogVisible.value = true;
  };
  const handleReport = () => {
  const handleFinishWork = () => {
    reportFormRef.value?.validate(valid => {
      if (!valid) {
        return false;
      }
      if (!valid) return;
      if (reportForm.planQuantity <= 0) {
        ElMessageBox.alert("待生产数量为0,无法报工", "提示", {
          confirmButtonText: "确定",
        });
        ElMessageBox.alert("待生产数量为0,无法报工", "提示", { confirmButtonText: "确定" });
        return;
      }
      // 验证本次生产数量
      if (
        reportForm.quantity === null ||
        reportForm.quantity === undefined ||
        reportForm.quantity === ""
      ) {
        ElMessageBox.alert("请输入本次生产数量", "提示", {
          confirmButtonText: "确定",
        });
      if (reportForm.quantity === null || reportForm.quantity === undefined || reportForm.quantity === "") {
        ElMessageBox.alert("请输入生产合格数量", "提示", { confirmButtonText: "确定" });
        return;
      }
      const quantity = Number(reportForm.quantity);
      if (isNaN(quantity) || quantity <= 0) {
        ElMessageBox.alert("本次生产数量必须大于0", "提示", {
          confirmButtonText: "确定",
        });
      if (isNaN(quantity) || quantity < 0) {
        ElMessageBox.alert("生产合格数量必须大于等于0", "提示", { confirmButtonText: "确定" });
        return;
      }
      if (quantity > reportForm.planQuantity) {
        ElMessageBox.alert("本次生产数量不能超过待生产数量", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      // 验证报废数量
      const scrapQty = Number(reportForm.scrapQty);
      if (!isNaN(scrapQty) && scrapQty < 0) {
        ElMessageBox.alert("报废数量不能小于0", "提示", {
          confirmButtonText: "确定",
        });
        return;
      }
      if (!isNaN(scrapQty) && scrapQty > quantity) {
        ElMessageBox.alert("报废数量不能大于本次生产数量", "提示", {
          confirmButtonText: "确定",
        });
        ElMessageBox.alert("报废数量不能小于0", "提示", { confirmButtonText: "确定" });
        return;
      }
@@ -717,8 +592,8 @@
        inputValue: reportForm.paramGroups[param.id] ?? "",
      }));
      const submitParams = {
        quantity: quantity,
      addProductMain({
        quantity,
        scrapQty: isNaN(scrapQty) ? 0 : scrapQty,
        userId: reportForm.userId,
        userName: reportForm.userName,
@@ -726,22 +601,18 @@
        productProcessRouteItemId: reportForm.productProcessRouteItemId,
        reportWork: reportForm.reportWork,
        productMainId: reportForm.productMainId,
        productionOrderRoutingOperationId:
          reportForm.productionOrderRoutingOperationId,
        productionOrderRoutingOperationId: reportForm.productionOrderRoutingOperationId,
        productionOrderId: reportForm.productionOrderId,
        workHour: reportForm.workHour,
        productionOperationParamList: productionOperationParamList,
      };
      addProductMain(submitParams)
        .then(res => {
          proxy.$modal.msgSuccess("报工成功");
      })
        .then(() => {
          proxy.$modal.msgSuccess("结束报工成功");
          reportDialogVisible.value = false;
          getList();
        })
        .catch(() => {
          ElMessageBox.alert("报工失败", "提示", {
            confirmButtonText: "确定",
          });
          ElMessageBox.alert("结束报工失败", "提示", { confirmButtonText: "确定" });
        });
    });
  };
@@ -756,220 +627,81 @@
    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;
      }
      if (res.code === 200) { dictOptions.value[dictType] = res.data; return res.data; }
      return [];
    } catch (error) {
      console.error("获取字典数据失败:", error);
      return [];
    }
    } catch (error) { console.error("获取字典数据失败:", error); return []; }
  };
  const loadParams = (productionOrderRoutingOperationId, productionOrderId) => {
    paramLoading.value = true;
    findProcessParamListOrder({
      productionOrderRoutingOperationId,
      productionOrderId,
    })
    findProcessParamListOrder({ productionOrderRoutingOperationId, productionOrderId })
      .then(res => {
        if (res.code === 200) {
          const paramList = res.data || [];
          params.value = paramList;
          reportForm.paramGroups = {};
          paramList.forEach(param => {
            if (!reportForm.paramGroups[param.id]) {
              reportForm.paramGroups[param.id] = "";
            }
            if (param.paramType == "3" && param.paramFormat) {
              getDictOptions(param.paramFormat);
            }
            if (!reportForm.paramGroups[param.id]) { reportForm.paramGroups[param.id] = ""; }
            if (param.paramType == "3" && param.paramFormat) { getDictOptions(param.paramFormat); }
          });
        }
      })
      .catch(err => {
        console.error("获取工序参数失败:", err);
      })
      .finally(() => {
        paramLoading.value = false;
      });
      .catch(err => { console.error("获取工序参数失败:", err); })
      .finally(() => { paramLoading.value = false; });
  };
  onMounted(() => {
    userStore.getInfo();
    getList();
    // 获取用户列表
    userListNoPageByTenantId().then(res => {
      if (res.code === 200) {
        userOptions.value = res.data;
      }
      if (res.code === 200) { userOptions.value = res.data; }
    });
  });
</script>
<style scoped lang="scss">
  .search-row {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  .search-item {
    display: flex;
    align-items: center;
  }
  .search_title {
    margin-right: 8px;
    font-size: 14px;
    color: #606266;
  }
  .transfer-card-title {
    text-align: center;
    font-size: 24px;
    font-weight: bold;
    margin-bottom: 20px;
    color: #303133;
  }
  .transfer-card-container {
    display: flex;
    justify-content: space-between;
    padding: 20px;
  }
  .transfer-card-info {
    flex: 1;
    margin-right: 20px;
  }
  .info-group {
    margin-bottom: 20px;
  }
  .info-item {
    display: flex;
    margin-bottom: 10px;
  }
  .info-label {
    width: 100px;
    font-weight: bold;
    color: #606266;
  }
  .info-value {
    flex: 1;
    color: #303133;
  }
  .transfer-card-qr {
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  .qr-container {
    text-align: center;
  }
  .print-button-container {
    text-align: center;
    margin-top: 20px;
  }
  .param-grid {
    margin-top: 10px;
    border-top: 1px solid #ebe9f3;
    padding-top: 10px;
  }
  .param-item {
    margin-bottom: 12px;
  }
  .param-input-group {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .param-input {
    flex: 1;
  }
  .param-select {
    flex: 1;
  }
  .param-unit {
    color: #909399;
    font-size: 12px;
    min-width: 30px;
  }
  .search-row { display: flex; align-items: center; gap: 12px; }
  .search-item { display: flex; align-items: center; }
  .search_title { margin-right: 8px; font-size: 14px; color: #606266; }
  .transfer-card-title { text-align: center; font-size: 24px; font-weight: bold; margin-bottom: 20px; color: #303133; }
  .transfer-card-container { display: flex; justify-content: space-between; padding: 20px; }
  .transfer-card-info { flex: 1; margin-right: 20px; }
  .info-group { margin-bottom: 20px; }
  .info-item { display: flex; margin-bottom: 10px; }
  .info-label { width: 100px; font-weight: bold; color: #606266; }
  .info-value { flex: 1; color: #303133; }
  .transfer-card-qr { display: flex; flex-direction: column; align-items: center; }
  .qr-container { text-align: center; }
  .print-button-container { text-align: center; margin-top: 20px; }
  .param-grid { margin-top: 10px; border-top: 1px solid #ebe9f3; padding-top: 10px; }
  .param-item { margin-bottom: 12px; }
  .param-input-group { display: flex; align-items: center; gap: 8px; }
  .param-input { flex: 1; }
  .param-select { flex: 1; }
  .param-unit { color: #909399; font-size: 12px; min-width: 30px; }
</style>
<style  lang="scss">
<style lang="scss">
  @media print {
    @page {
      size: landscape;
    }
    body * {
      visibility: hidden;
    }
    .el-dialog__wrapper,
    .el-dialog,
    .el-dialog__body,
    .transfer-card-title,
    .transfer-card-container,
    .transfer-card-container *,
    .info-item,
    .info-label,
    .info-value {
      visibility: visible;
    }
    .print-button-container {
      visibility: hidden;
    }
    .el-dialog__wrapper {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      margin: 0;
    }
    .el-dialog {
      width: 100% !important;
      max-width: 800px;
      margin: 0 auto !important;
    }
    .el-dialog__header,
    .el-dialog__footer {
      display: none;
    }
    .el-dialog__body {
      padding: 20px;
    }
    .transfer-card-container {
      height: auto;
      display: flex;
      gap: 20px;
    }
    @page { size: landscape; }
    body * { visibility: hidden; }
    .el-dialog__wrapper, .el-dialog, .el-dialog__body,
    .transfer-card-title, .transfer-card-container, .transfer-card-container *,
    .info-item, .info-label, .info-value { visibility: visible; }
    .print-button-container { visibility: hidden; }
    .el-dialog__wrapper { position: absolute; top: 0; left: 0; right: 0; margin: 0; }
    .el-dialog { width: 100% !important; max-width: 800px; margin: 0 auto !important; }
    .el-dialog__header, .el-dialog__footer { display: none; }
    .el-dialog__body { padding: 20px; }
    .transfer-card-container { height: auto; display: flex; gap: 20px; }
    .transfer-card-info {
      flex: 1;
      .info-group {
        width: 100%;
        float: none;
        margin-bottom: 20px;
      }
      .info-item {
        display: flex;
        margin-bottom: 10px;
        .info-label {
          width: 100px;
          font-weight: bold;
          margin-right: 15px;
          white-space: nowrap;
        }
        .info-value {
          flex: 1;
          word-break: break-word;
        }
      .info-group { width: 100%; float: none; margin-bottom: 20px; }
      .info-item { display: flex; margin-bottom: 10px;
        .info-label { width: 100px; font-weight: bold; margin-right: 15px; white-space: nowrap; }
        .info-value { flex: 1; word-break: break-word; }
      }
    }
    .transfer-card-qr {
      width: 160px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: flex-start;
    }
    .qr-container img {
      width: 140px !important;
      height: 140px !important;
    }
    .transfer-card-qr { width: 160px; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; }
    .qr-container img { width: 140px !important; height: 140px !important; }
  }
</style>