From ac00bb7b8eae1bf6aabb7f1ae67c2e5aa5b8ae90 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 12 六月 2026 10:21:12 +0800
Subject: [PATCH] 宝东 1.样式问题

---
 src/views/productionManagement/workOrderEdit/index.vue |  649 +++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 459 insertions(+), 190 deletions(-)

diff --git a/src/views/productionManagement/workOrderEdit/index.vue b/src/views/productionManagement/workOrderEdit/index.vue
index b919973..ead2c1f 100644
--- a/src/views/productionManagement/workOrderEdit/index.vue
+++ b/src/views/productionManagement/workOrderEdit/index.vue
@@ -1,20 +1,29 @@
 <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>
-          <el-input v-model="searchForm.workOrderNo"
-                    style="width: 240px"
+          <span class="search_title">鐢熶骇璁㈠崟鍙凤細</span>
+          <el-input v-model="searchForm.npsNo"
+                    style="width: 200px"
                     placeholder="璇疯緭鍏�"
                     @change="handleQuery"
                     clearable
                     prefix-icon="Search" />
         </div>
         <div class="search-item">
-          <span class="search_title">鐢熶骇璁㈠崟鍙凤細</span>
-          <el-input v-model="searchForm.productOrderNpsNo"
-                    style="width: 240px"
+          <span class="search_title">浜у搧鍚嶇О锛�</span>
+          <el-input v-model="searchForm.productName"
+                    style="width: 200px"
+                    placeholder="璇疯緭鍏�"
+                    @change="handleQuery"
+                    clearable
+                    prefix-icon="Search" />
+        </div>
+        <div class="search-item">
+          <span class="search_title">瑙勬牸锛�</span>
+          <el-input v-model="searchForm.model"
+                    style="width: 200px"
                     placeholder="璇疯緭鍏�"
                     @change="handleQuery"
                     clearable
@@ -27,18 +36,124 @@
       </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>
+      <el-table :data="tableData"
+                border
+                v-loading="tableLoading"
+                :expand-row-keys="expandedRowKeys"
+                :row-key="(row) => row.productionOrderId"
+                @expand-change="expandChange"
+                style="width: 100%"
+                height="calc(100vh - 18.5em)">
+        <el-table-column type="expand"
+                         width="60"
+                         fixed="left">
+          <template #default="props">
+            <el-table :data="props.row.children"
+                      border
+                      v-loading="props.row.childrenLoading">
+              <el-table-column align="center"
+                               label="搴忓彿"
+                               type="index"
+                               width="60" />
+              <el-table-column label="宸ュ崟绫诲瀷"
+                               prop="workOrderType"
+                               width="80" />
+              <el-table-column label="宸ュ崟缂栧彿"
+                               prop="workOrderNo"
+                               width="140"
+                               show-overflow-tooltip />
+              <el-table-column label="宸ュ簭鍚嶇О"
+                               prop="operationName"
+                               width="100"
+                               show-overflow-tooltip />
+              <el-table-column label="闇�姹傛暟閲�"
+                               prop="planQuantity"
+                               width="100" />
+              <el-table-column label="瀹屾垚鏁伴噺"
+                               prop="completeQuantity"
+                               width="100" />
+              <el-table-column label="瀹屾垚杩涘害"
+                               width="140"
+                               align="center">
+                <template #default="{ row }">
+                  <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
+                               :color="progressColor(toProgressPercentage(row?.completionStatus))"
+                               :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
+                </template>
+              </el-table-column>
+              <el-table-column label="璁″垝寮�濮嬫椂闂�"
+                               prop="planStartTime"
+                               width="120" />
+              <el-table-column label="璁″垝缁撴潫鏃堕棿"
+                               prop="planEndTime"
+                               width="120" />
+              <el-table-column label="瀹為檯寮�濮嬫椂闂�"
+                               prop="actualStartTime"
+                               width="120" />
+              <el-table-column label="瀹為檯缁撴潫鏃堕棿"
+                               prop="actualEndTime"
+                               width="120" />
+              <el-table-column label="鎸囧畾鎶ュ伐浜�"
+                               prop="userNames"
+                               width="120"
+                               show-overflow-tooltip />
+              <el-table-column label="鎿嶄綔"
+                               width="210"
+                               align="center"
+                               fixed="right">
+                <template #default="{ row }">
+                  <el-button link
+                             type="primary"
+                             @click="handleEdit(row)">璁″垝鏃堕棿</el-button>
+                  <el-button link
+                             type="primary"
+                             @click="handleAssignReporter(row)">鎸囧畾鎶ュ伐浜�</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </template>
+        </el-table-column>
+        <el-table-column align="center"
+                         label="搴忓彿"
+                         type="index"
+                         width="60" />
+        <el-table-column label="鐢熶骇璁㈠崟鍙�"
+                         prop="npsNo"
+                         width="160"
+                         show-overflow-tooltip />
+        <el-table-column label="浜у搧鍚嶇О"
+                         prop="productName"
+                         width="140"
+                         show-overflow-tooltip />
+        <el-table-column label="瑙勬牸"
+                         prop="model"
+                         show-overflow-tooltip />
+        <el-table-column label="宸ュ簭鍚嶇О"
+                         prop="operationName"
+                         minWidth="160"
+                         show-overflow-tooltip />
+        <el-table-column label="璁″垝鏁伴噺"
+                         prop="planQuantity"
+                         width="100" />
+        <el-table-column label="瀹屾垚鏁伴噺"
+                         prop="completeQuantity"
+                         width="100" />
+        <el-table-column label="瀹屾垚杩涘害"
+                         width="140"
+                         align="center">
+          <template #default="{ row }">
+            <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
+                         :color="progressColor(toProgressPercentage(row?.completionStatus))"
+                         :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination v-show="page.total > 0"
+                  :total="page.total"
+                  layout="total, sizes, prev, pager, next, jumper"
+                  :page="page.current"
+                  :limit="page.size"
+                  @pagination="paginationChange" />
     </div>
     <el-dialog v-model="editDialogVisible"
                title="缂栬緫璁″垝鏃堕棿"
@@ -68,205 +183,359 @@
         </span>
       </template>
     </el-dialog>
+    <!-- 鎸囧畾鎶ュ伐浜哄脊绐� -->
+    <el-dialog v-model="assignReporterDialogVisible"
+               title="鎸囧畾鎶ュ伐浜�"
+               width="800px">
+      <div class="assign-reporter-content">
+        <div class="selected-tags-box"
+             v-if="selectedEmployeeIds.length > 0">
+          <div class="tags-label">宸查�夋嫨锛�</div>
+          <div class="tags-list">
+            <el-tag v-for="id in selectedEmployeeIds"
+                    :key="id"
+                    closable
+                    @close="removeEmployeeTag(id)"
+                    class="employee-tag">
+              {{ getEmployeeNameById(id) }}
+            </el-tag>
+          </div>
+        </div>
+        <div class="employee-list-container"
+             v-loading="employeeTableLoading">
+          <el-checkbox-group v-model="selectedEmployeeIds">
+            <div class="employee-grid">
+              <div v-for="item in employeeTableData"
+                   :key="item.userId"
+                   class="employee-item">
+                <el-checkbox :label="item.userId"
+                             border>
+                  <div class="employee-info">
+                    <span class="name">{{ item.nickName }}</span>
+                    <span class="dept">{{ item.dept?.deptName }}</span>
+                  </div>
+                </el-checkbox>
+              </div>
+            </div>
+          </el-checkbox-group>
+          <div v-if="employeeTableData.length === 0"
+               class="empty-text">
+            鏆傛棤鍖归厤浜哄憳
+          </div>
+        </div>
+      </div>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button type="primary"
+                     @click="handleSaveReporters">纭畾</el-button>
+          <el-button @click="assignReporterDialogVisible = false">鍙栨秷</el-button>
+        </span>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-  import { getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
-  import { ElMessageBox } from "element-plus";
-  import {
-    productWorkOrderPage,
-    updateProductWorkOrder,
-  } from "@/api/productionManagement/workOrder.js";
+import { getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
+import { ElMessageBox } from "element-plus";
+import {
+  productWorkOrderPage,
+  updateProductWorkOrder,
+  assignProductWorkOrder,
+  getWorkOrdersByOrderId,
+} from "@/api/productionManagement/workOrder.js";
+import { listUser } from "@/api/system/user.js";
+import pagination from "@/components/PIMTable/Pagination.vue";
 
-  const { proxy } = getCurrentInstance();
+const { proxy } = getCurrentInstance();
 
-  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: "鎿嶄綔",
-      width: "100",
-      align: "center",
-      dataType: "action",
-      fixed: "right",
-      operation: [
-        {
-          name: "璁″垝鏃堕棿",
-          clickFun: row => {
-            handleEdit(row);
-          },
-        },
-      ],
-    },
-  ]);
+const tableData = ref([]);
+const tableLoading = ref(false);
+const expandedRowKeys = ref([]);
+const editDialogVisible = ref(false);
+const editrow = ref(null);
+const page = reactive({
+  current: 1,
+  size: 10,
+  total: 0,
+});
 
-  const tableData = ref([]);
-  const tableLoading = ref(false);
-  const editDialogVisible = ref(false);
-  const editrow = ref(null);
-  const page = reactive({
-    current: 1,
-    size: 100,
-    total: 0,
-  });
+// 鎸囧畾鎶ュ伐浜虹浉鍏�
+const assignReporterDialogVisible = ref(false);
+const employeeTableLoading = ref(false);
+const employeeTableData = ref([]);
+const employeePage = reactive({
+  current: 1,
+  size: 100,
+  total: 0,
+});
+const employeeSearchForm = reactive({
+  staffName: "",
+});
+const selectedEmployeeIds = ref([]);
+const currentWorkOrder = ref(null);
 
-  const data = reactive({
-    searchForm: {
-      workOrderNo: "",
-      productOrderNpsNo: "",
-    },
-  });
-  const { searchForm } = toRefs(data);
+const data = reactive({
+  searchForm: {
+    npsNo: "",
+    productName: "",
+    model: "",
+  },
+});
+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 toProgressPercentage = val => {
+  const n = Number(val);
+  if (!Number.isFinite(n)) return 0;
+  if (n <= 0) return 0;
+  if (n >= 100) return 100;
+  return parseFloat(n.toFixed(2));
+};
 
-  const progressColor = percentage => {
-    const p = toProgressPercentage(percentage);
-    if (p < 30) return "#f56c6c";
-    if (p < 50) return "#e6a23c";
-    if (p < 80) return "#409eff";
-    return "#67c23a";
-  };
+const progressColor = percentage => {
+  const p = toProgressPercentage(percentage);
+  if (p < 30) return "#f56c6c";
+  if (p < 50) return "#e6a23c";
+  if (p < 80) return "#409eff";
+  return "#67c23a";
+};
 
-  const handleQuery = () => {
-    page.current = 1;
-    getList();
-  };
+const handleQuery = () => {
+  page.current = 1;
+  expandedRowKeys.value = [];
+  getList();
+};
 
-  const pagination = obj => {
-    page.current = obj.page;
-    page.size = obj.limit;
-    getList();
-  };
+const paginationChange = obj => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  expandedRowKeys.value = [];
+  getList();
+};
 
-  const getList = () => {
-    tableLoading.value = true;
-    const params = { ...searchForm.value, ...page };
-    productWorkOrderPage(params)
+const getList = () => {
+  tableLoading.value = true;
+  const params = { ...searchForm.value, current: page.current, size: page.size };
+  productWorkOrderPage(params)
+    .then(res => {
+      tableLoading.value = false;
+      const records = res.data.records || [];
+      records.forEach(item => {
+        item.children = [];
+        item.childrenLoading = false;
+      });
+      tableData.value = records;
+      page.total = res.data.total;
+    })
+    .catch(() => {
+      tableLoading.value = false;
+    });
+};
+
+const expandChange = (row, expandedRows) => {
+  if (expandedRows.length > 0) {
+    expandedRowKeys.value = [];
+    row.childrenLoading = true;
+    getWorkOrdersByOrderId(row.productionOrderId)
       .then(res => {
-        tableLoading.value = false;
-        tableData.value = res.data.records;
-        page.total = res.data.total;
+        row.childrenLoading = false;
+        const idx = tableData.value.findIndex(
+          item => item.productionOrderId === row.productionOrderId
+        );
+        if (idx > -1) {
+          tableData.value[idx].children = res.data || [];
+        }
+        expandedRowKeys.value.push(row.productionOrderId);
       })
       .catch(() => {
-        tableLoading.value = false;
+        row.childrenLoading = false;
       });
-  };
+  } else {
+    expandedRowKeys.value = [];
+  }
+};
 
-  const handleEdit = row => {
-    editrow.value = JSON.parse(JSON.stringify(row));
-    editDialogVisible.value = true;
-  };
+const handleEdit = row => {
+  editrow.value = JSON.parse(JSON.stringify(row));
+  editDialogVisible.value = true;
+};
 
-  const handleUpdate = () => {
-    updateProductWorkOrder(editrow.value)
-      .then(() => {
-        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-        editDialogVisible.value = false;
-        getList();
-      })
-      .catch(() => {
-        ElMessageBox.alert("淇敼澶辫触", "鎻愮ず", {
-          confirmButtonText: "纭畾",
-        });
+const handleUpdate = () => {
+  updateProductWorkOrder(editrow.value)
+    .then(() => {
+      proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      editDialogVisible.value = false;
+      getList();
+    })
+    .catch(() => {
+      ElMessageBox.alert("淇敼澶辫触", "鎻愮ず", {
+        confirmButtonText: "纭畾",
       });
+    });
+};
+
+const handleAssignReporter = row => {
+  currentWorkOrder.value = row;
+  assignReporterDialogVisible.value = true;
+  if (row.userIds) {
+    try {
+      selectedEmployeeIds.value = JSON.parse(row.userIds);
+    } catch (e) {
+      selectedEmployeeIds.value = [];
+    }
+  } else {
+    selectedEmployeeIds.value = [];
+  }
+  employeeSearchForm.staffName = "";
+  getEmployeeList();
+};
+
+const getEmployeeList = () => {
+  employeeTableLoading.value = true;
+  const params = {
+    pageNum: 1,
+    pageSize: 100,
+  };
+  listUser(params)
+    .then(res => {
+      employeeTableLoading.value = false;
+      employeeTableData.value = res.rows;
+      employeePage.total = res.total;
+    })
+    .catch(() => {
+      employeeTableLoading.value = false;
+    });
+};
+
+const getEmployeeNameById = id => {
+  const employee = employeeTableData.value.find(item => item.userId === id);
+  return employee ? employee.nickName : id;
+};
+
+const removeEmployeeTag = id => {
+  selectedEmployeeIds.value = selectedEmployeeIds.value.filter(
+    item => item !== id
+  );
+};
+
+const handleSaveReporters = () => {
+  if (selectedEmployeeIds.value.length === 0) {
+    proxy.$modal.msgWarning("璇烽�夋嫨鎶ュ伐浜�");
+    return;
+  }
+
+  const updateData = {
+    id: currentWorkOrder.value.id,
+    userIds: JSON.stringify(selectedEmployeeIds.value),
   };
 
-  onMounted(() => {
-    getList();
-  });
+  assignProductWorkOrder(updateData)
+    .then(() => {
+      proxy.$modal.msgSuccess("鎸囧畾鎴愬姛");
+      assignReporterDialogVisible.value = false;
+      getList();
+    })
+    .catch(() => {
+      proxy.$modal.msgError("鎸囧畾澶辫触");
+    });
+};
+
+onMounted(() => {
+  getList();
+});
 </script>
 
 <style scoped lang="scss">
-  .search-row {
+.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;
+}
+.assign-reporter-content {
+  .selected-tags-box {
+    margin-bottom: 16px;
+    padding: 12px;
+    background-color: #f5f7fa;
+    border-radius: 4px;
     display: flex;
-    align-items: center;
-    gap: 12px;
+    align-items: flex-start;
+
+    .tags-label {
+      font-size: 14px;
+      color: #606266;
+      margin-right: 8px;
+      white-space: nowrap;
+      margin-top: 4px;
+    }
+
+    .tags-list {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 8px;
+
+      .employee-tag {
+        margin-bottom: 4px;
+      }
+    }
   }
 
-  .search-item {
-    display: flex;
-    align-items: center;
-  }
+  .employee-list-container {
+    max-height: 400px;
+    overflow-y: auto;
+    padding: 10px;
+    border: 1px solid #f0f0f0;
+    border-radius: 4px;
 
-  .search_title {
-    margin-right: 8px;
-    font-size: 14px;
-    color: #606266;
+    .employee-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
+      gap: 12px;
+    }
+
+    .employee-item {
+      :deep(.el-checkbox) {
+        width: 100%;
+        margin-right: 0;
+        height: auto;
+        padding: 8px;
+
+        .el-checkbox__label {
+          width: 100%;
+        }
+      }
+
+      .employee-info {
+        display: flex;
+        flex-direction: column;
+        gap: 4px;
+
+        .name {
+          font-weight: bold;
+          font-size: 14px;
+          color: #303133;
+        }
+
+        .dept {
+          font-size: 12px;
+          color: #909399;
+        }
+      }
+    }
+
+    .empty-text {
+      text-align: center;
+      color: #909399;
+      padding: 20px;
+    }
   }
+}
 </style>

--
Gitblit v1.9.3