From cac302f302084ab310d0e35339f30966a4829a4e Mon Sep 17 00:00:00 2001
From: chenhj <1263187585@qq.com>
Date: 星期五, 23 一月 2026 12:18:28 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_New' into dev_New

---
 src/views/productionManagement/workOrder/index.vue |  653 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 653 insertions(+), 0 deletions(-)

diff --git a/src/views/productionManagement/workOrder/index.vue b/src/views/productionManagement/workOrder/index.vue
new file mode 100644
index 0000000..de91893
--- /dev/null
+++ b/src/views/productionManagement/workOrder/index.vue
@@ -0,0 +1,653 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div class="search-row">
+        <div class="search-item">
+          <span class="search_title">宸ュ崟缂栧彿锛�</span>
+          <el-input v-model="searchForm.workOrderNo"
+                    style="width: 240px"
+                    placeholder="璇疯緭鍏�"
+                    @change="handleQuery"
+                    clearable
+                    prefix-icon="Search" />
+        </div>
+        <div class="search-item">
+          <el-button type="primary"
+                     @click="handleQuery">鎼滅储</el-button>
+        </div>
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable rowKey="id"
+                :column="tableColumn"
+                :tableData="tableData"
+                :page="page"
+                :tableLoading="tableLoading"
+                @pagination="pagination">
+                <template #completionStatus="{ row }">
+                  <el-progress :percentage="toProgressPercentage(row?.completionStatus)" :color="progressColor(toProgressPercentage(row?.completionStatus))" :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
+                </template>
+              </PIMTable>
+    </div>
+    <el-dialog v-model="editDialogVisible"
+               title="缂栬緫鏃堕棿"
+               width="500px">
+      <el-form :model="editrow"
+               label-width="120px">
+        <el-form-item label="璁″垝寮�濮嬫椂闂�">
+          <el-date-picker v-model="editrow.planStartTime"
+                          type="date"
+                          placeholder="璇烽�夋嫨"
+                          value-format="YYYY-MM-DD"
+                          style="width: 300px" />
+        </el-form-item>
+        <el-form-item label="璁″垝缁撴潫鏃堕棿">
+          <el-date-picker v-model="editrow.planEndTime"
+                          type="date"
+                          placeholder="璇烽�夋嫨"
+                          value-format="YYYY-MM-DD"
+                          style="width: 300px" />
+        </el-form-item>
+        <el-form-item label="瀹為檯寮�濮嬫椂闂�">
+          <el-date-picker v-model="editrow.actualStartTime"
+                          type="date"
+                          placeholder="璇烽�夋嫨"
+                          value-format="YYYY-MM-DD"
+                          style="width: 300px" />
+        </el-form-item>
+        <el-form-item label="瀹為檯缁撴潫鏃堕棿">
+          <el-date-picker v-model="editrow.actualEndTime"
+                          type="date"
+                          placeholder="璇烽�夋嫨"
+                          value-format="YYYY-MM-DD"
+                          style="width: 300px" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button type="primary"
+                     @click="handleUpdate">纭畾</el-button>
+          <el-button @click="editDialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    <el-dialog v-model="transferCardVisible"
+               title="娴佽浆鍗�"
+               width="1000px">
+      <div class="transfer-card-title">宸ュ崟娴佽浆鍗�</div>
+      <div class="transfer-card-container">
+        <div class="transfer-card-info">
+          <div class="info-group">
+            <div class="info-item">
+              <span class="info-label">宸ュ崟缂栧彿</span>
+              <span class="info-value">{{ transferCardRowData.workOrderNo }}</span>
+            </div>
+            <!-- <div class="info-item">
+              <span class="info-label">浜у搧缂栧彿</span>
+              <span class="info-value">{{ transferCardRowData.productNo }}</span>
+            </div> -->
+            <div class="info-item">
+              <span class="info-label">浜у搧鍚嶇О</span>
+              <span class="info-value">{{ transferCardRowData.productName }}</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">浜у搧瑙勬牸</span>
+              <span class="info-value">{{ transferCardRowData.model }}</span>
+            </div>
+            <!-- <div class="info-item">
+              <span class="info-label">宸ュ崟鐘舵��</span>
+              <span class="info-value">{{ 
+                transferCardRowData.status === 1 ? '寰呯‘璁�' : 
+                transferCardRowData.status === 2 ? '寰呯敓浜�' : 
+                transferCardRowData.status === 3 ? '鐢熶骇涓�' : 
+                transferCardRowData.status === 4 ? '宸茬敓浜�' : 
+                transferCardRowData.status 
+              }}</span>
+            </div> -->
+           
+            <div class="info-item">
+              <span class="info-label">璁″垝寮�濮嬫椂闂�</span>
+              <span class="info-value">{{ transferCardRowData.planStartTime }}</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">璁″垝缁撴潫鏃堕棿</span>
+              <span class="info-value">{{ transferCardRowData.planEndTime }}</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">澶囨敞</span>
+              <span class="info-value">{{ transferCardRowData.remark }}</span>
+            </div>
+          </div>
+          <div class="info-group">
+            <div class="info-item">
+              <span class="info-label">闇�姹傛暟閲�</span>
+              <span class="info-value">{{ transferCardRowData.planQuantity }}</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">瀹屾垚鏁伴噺</span>
+              <span class="info-value">{{ transferCardRowData.completeQuantity }}</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">鑹搧鏁伴噺</span>
+              <span class="info-value">0</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">涓嶈壇鍝佹暟</span>
+              <span class="info-value">0</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">瀹為檯寮�濮嬫椂闂�</span>
+              <span class="info-value">{{ transferCardRowData.actualStartTime }}</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">瀹為檯缁撴潫鏃堕棿</span>
+              <span class="info-value">{{ transferCardRowData.actualEndTime }}</span>
+            </div>
+          </div>
+        </div>
+        <div class="transfer-card-qr">
+          <div class="qr-container">
+            <img :src="transferCardQrUrl"
+                 alt="娴佽浆鍗′簩缁寸爜"
+                 style="width: 200px; height: 200px;" />
+            <!-- <div class="qr-tip"
+                 style="margin-top: 10px; text-align: center;">娴佽浆鍗′簩缁寸爜</div> -->
+          </div>
+        </div>
+      </div>
+      <div class="print-button-container"
+           style=" text-align: center;
+      margin-bottom: 40px;">
+        <el-button type="primary"
+                   style="margin-top: 20px;"
+                   @click="printTransferCard">鎵撳嵃娴佽浆鍗�</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog v-model="reportDialogVisible"
+               title="鎶ュ伐"
+               width="500px">
+      <el-form :model="reportForm"
+               label-width="120px">
+        <el-form-item label="寰呯敓浜ф暟閲�">
+          <el-input v-model="reportForm.planQuantity"
+                    readonly
+                    style="width: 300px" />
+        </el-form-item>
+        <el-form-item label="鏈鐢熶骇鏁伴噺">
+          <el-input v-model.number="reportForm.quantity"
+                    type="number"
+                    min="1"
+                    style="width: 300px"
+                    placeholder="璇疯緭鍏ユ湰娆$敓浜ф暟閲�" />
+        </el-form-item>
+        <el-form-item label="鎶ュ簾鏁伴噺">
+          <el-input v-model.number="reportForm.scrapQty"
+                    type="number"
+                    min="1"
+                    style="width: 300px"
+                    placeholder="璇疯緭鍏ユ姤搴熸暟閲�" />
+        </el-form-item>
+        <el-form-item label="鐝粍淇℃伅">
+          <el-select v-model="reportForm.userId"
+                     style="width: 300px"
+                     placeholder="璇烽�夋嫨鐝粍淇℃伅"
+                     clearable
+                     filterable
+                     @change="handleUserChange">
+            <el-option v-for="user in userOptions"
+                       :key="user.userId"
+                       :label="user.userName"
+                       :value="user.userId" />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button type="primary"
+                     @click="handleReport">纭畾</el-button>
+          <el-button @click="reportDialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { onMounted, ref } from "vue";
+  import { ElMessageBox } from "element-plus";
+  import dayjs from "dayjs";
+  import {
+    productWorkOrderPage,
+    updateProductWorkOrder,
+    addProductMain,
+  } from "@/api/productionManagement/workOrder.js";
+  import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js";
+  import QRCode from "qrcode";
+  import { getCurrentInstance, reactive, toRefs } from "vue";
+  const { proxy } = getCurrentInstance();
+
+  const tableColumn = ref([
+    {
+      label: "宸ュ崟缂栧彿",
+      prop: "workOrderNo",
+      width: "140",
+    },
+    {
+      label: "鐢熶骇璁㈠崟鍙�",
+      prop: "productOrderNpsNo",
+      width: "140",
+    },
+    {
+      label: "浜у搧鍚嶇О",
+      prop: "productName",
+      width: "140",
+    },
+    {
+      label: "瑙勬牸",
+      prop: "model",
+    },
+    {
+      label: "鍗曚綅",
+      prop: "unit",
+    },
+    {
+      label: "宸ュ簭鍚嶇О",
+      prop: "processName",
+    },
+    {
+      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: "200",
+      align: "center",
+      dataType: "action",
+      fixed: "right",
+      operation: [
+        {
+          name: "缂栬緫",
+          clickFun: row => {
+            handleEdit(row);
+          },
+        },
+        {
+          name: "娴佽浆鍗�",
+          clickFun: row => {
+            showTransferCard(row);
+          },
+        },
+        {
+          name: "鎶ュ伐",
+          clickFun: row => {
+            showReportDialog(row);
+          },
+          disabled: row => row.planQuantity <= 0,
+        },
+      ],
+    },
+  ]);
+  const tableData = ref([]);
+  const tableLoading = ref(false);
+  const qrCodeUrl = ref("");
+  const qrRowData = ref(null);
+  const editDialogVisible = ref(false);
+  const transferCardVisible = ref(false);
+  const transferCardData = ref([]);
+  const transferCardQrUrl = ref("");
+  const transferCardRowData = ref(null);
+  const reportDialogVisible = ref(false);
+  const userOptions = ref([]);
+  const reportForm = reactive({
+    planQuantity: 0,
+    quantity: 0,
+    userName: "",
+    workOrderId: "",
+    reportWork: "",
+    productProcessRouteItemId: "",
+    userId: "",
+    productMainId: null,
+  });
+  const currentReportRowData = ref(null);
+  const page = reactive({
+    current: 1,
+    size: 100,
+    total: 0,
+  });
+
+  const data = reactive({
+    searchForm: {
+      workOrderNo: "",
+    },
+  });
+  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);
+  };
+  const progressColor = percentage => {
+    const p = toProgressPercentage(percentage);
+    if (p < 30) return "#f56c6c";
+    if (p < 50) return "#e6a23c";
+    if (p < 80) return "#409eff";
+    return "#67c23a";
+  };
+  let editrow = ref(null);
+
+  // 鏌ヨ鍒楄〃
+  /** 鎼滅储鎸夐挳鎿嶄綔 */
+  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 };
+    productWorkOrderPage(params)
+      .then(res => {
+        tableLoading.value = false;
+        tableData.value = res.data.records;
+        page.total = res.data.total;
+      })
+      .catch(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  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 handleEdit = row => {
+    editrow.value = JSON.parse(JSON.stringify(row));
+    editDialogVisible.value = true;
+  };
+
+  const handleUpdate = () => {
+    updateProductWorkOrder(editrow.value)
+      .then(res => {
+        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+        editDialogVisible.value = false;
+        getList();
+      })
+      .catch(() => {
+        ElMessageBox.alert("淇敼澶辫触", "鎻愮ず", {
+          confirmButtonText: "纭畾",
+        });
+      });
+  };
+
+  const showReportDialog = row => {
+    currentReportRowData.value = row;
+    reportForm.planQuantity = row.planQuantity;
+    reportForm.quantity = row.quantity;
+    reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
+    reportForm.workOrderId = row.id;
+    reportForm.reportWork = row.reportWork;
+    reportForm.productMainId = row.productMainId;
+    reportForm.scrapQty = row.scrapQty;
+    // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅锛岃缃负榛樿閫変腑
+    getUserProfile()
+      .then(res => {
+        if (res.code === 200) {
+          reportForm.userId = res.data.userId;
+          reportForm.userName = res.data.userName;
+        }
+      })
+      .catch(err => {
+        console.error("鑾峰彇鐢ㄦ埛淇℃伅澶辫触", err);
+      });
+
+    reportDialogVisible.value = true;
+  };
+
+  const handleReport = () => {
+    if (reportForm.planQuantity <= 0) {
+      ElMessageBox.alert("寰呯敓浜ф暟閲忎负0锛屾棤娉曟姤宸�", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+      });
+      return;
+    }
+    if (!reportForm.quantity || reportForm.quantity <= 0) {
+      ElMessageBox.alert("璇疯緭鍏ユ湁鏁堢殑鏈鐢熶骇鏁伴噺", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+      });
+      return;
+    }
+    if (reportForm.quantity > reportForm.planQuantity) {
+      ElMessageBox.alert("鏈鐢熶骇鏁伴噺涓嶈兘瓒呰繃寰呯敓浜ф暟閲�", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+      });
+      return;
+    }
+    // console.log(reportForm);
+    addProductMain(reportForm).then(res => {
+      if (res.code === 200) {
+        proxy.$modal.msgSuccess("鎶ュ伐鎴愬姛");
+        reportDialogVisible.value = false;
+        getList();
+      } else {
+        ElMessageBox.alert(res.msg || "鎶ュ伐澶辫触", "鎻愮ず", {
+          confirmButtonText: "纭畾",
+        });
+      }
+    });
+  };
+
+  // 鑾峰彇鐢ㄦ埛鍒楄〃
+  const getUserList = () => {
+    userListNoPageByTenantId()
+      .then(res => {
+        if (res.code === 200) {
+          userOptions.value = res.data || [];
+        }
+      })
+      .catch(err => {
+        console.error("鑾峰彇鐢ㄦ埛鍒楄〃澶辫触", err);
+      });
+  };
+
+  // 鐢ㄦ埛閫夋嫨鍙樺寲鏃舵洿鏂� userName
+  const handleUserChange = (userId) => {
+    if (userId) {
+      const selectedUser = userOptions.value.find(user => user.userId === userId);
+      if (selectedUser) {
+        reportForm.userName = selectedUser.userName;
+      }
+    } else {
+      reportForm.userName = "";
+    }
+  };
+
+  onMounted(() => {
+    getList();
+    getUserList();
+  });
+</script>
+
+<style scoped lang="scss">
+  .search_form {
+    margin-bottom: 20px;
+    .search-row {
+      display: flex;
+      gap: 20px;
+      align-items: center;
+      .search-item {
+        display: flex;
+        align-items: center;
+        gap: 10px;
+      }
+    }
+  }
+
+  .transfer-card-title {
+    font-size: 24px;
+    font-weight: bold;
+    text-align: center;
+    margin-bottom: 20px;
+  }
+
+  .transfer-card-container {
+    display: flex;
+    gap: 20px;
+    height: 350px;
+    .transfer-card-info {
+      flex: 1;
+      overflow: auto;
+      .info-group {
+        width: 50%;
+        float: left;
+      }
+      .info-item {
+        display: flex;
+        margin-bottom: 15px;
+        .info-label {
+          width: 120px;
+          font-weight: bold;
+          margin-right: 20px;
+        }
+        .info-value {
+          flex: 1;
+        }
+      }
+    }
+    .transfer-card-qr {
+      width: 240px;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: flex-start;
+    }
+  }
+</style>
+
+<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;
+    }
+    .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;
+        }
+      }
+    }
+    .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>

--
Gitblit v1.9.3