From f2770f03e7251b32eb576113c522bfbe96e5e385 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 16 六月 2026 13:46:16 +0800
Subject: [PATCH] 君歌app 1.依照web端功能修改

---
 src/pages/productionDesign/processManagement/index.vue                        |   68 +
 src/api/productionManagement/workOrder.js                                     |    9 
 src/api/personnelManagement/staffOnJob.js                                     |   63 ++
 src/pages/works.vue                                                           |  103 ---
 src/pages/productionManagement/productionReport/index.vue                     |   13 
 src/api/productionManagement/productionProcess.js                             |  104 ++++
 src/pages/productionManagement/productionReport/components/filesDia.vue       |  262 ++++++++++
 src/config.js                                                                 |    4 
 src/pages/productionManagement/workOrder/index.vue                            |  186 ++++---
 src/pages/productionManagement/productionReport/components/MaterialDialog.vue |  437 +++++++++++++++++
 src/pages/productionDesign/processManagement/edit.vue                         |  231 +++++---
 11 files changed, 1,191 insertions(+), 289 deletions(-)

diff --git a/src/api/personnelManagement/staffOnJob.js b/src/api/personnelManagement/staffOnJob.js
new file mode 100644
index 0000000..7a14391
--- /dev/null
+++ b/src/api/personnelManagement/staffOnJob.js
@@ -0,0 +1,63 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鍦ㄨ亴鍛樺伐鍙拌处
+export function staffOnJobListPage(query) {
+    return request({
+        url: '/staff/staffOnJob/listPage',
+        method: 'get',
+        params: query,
+    })
+}
+// 鏌ヨ鍛樺伐鍏ヨ亴淇℃伅
+export function staffOnJobInfo(id, query) {
+    return request({
+        url: '/staff/staffOnJob/' + id,
+        method: 'get',
+        params: query,
+    })
+}
+
+// 鏌ヨ鍛樺伐鍏ヨ亴淇℃伅
+export function getStaffOnJobInfoByUserName(query) {
+    return request({
+        url: '/staff/staffOnJob/byUserName',
+        method: 'get',
+        params: query,
+    })
+}
+
+// 鏂板鍛樺伐
+export function createStaffOnJob(params) {
+    return request({
+        url: "/staff/staffOnJob",
+        method: "post",
+        data: params,
+    });
+}
+
+// 淇敼鍛樺伐
+export function updateStaffOnJob(id, params) {
+    return request({
+        url: "/staff/staffOnJob/" + id,
+        method: "put",
+        data: params,
+    });
+}
+
+// 鍒犻櫎鍛樺伐
+export function batchDeleteStaffOnJobs(query) {
+    return request({
+        url: "/staff/staffOnJob/del",
+        method: "delete",
+        data: query,
+    });
+}
+
+// 缁鍚堝悓
+export function renewContract(id, params) {
+    return request({
+        url: "/staff/staffOnJob/renewContract/" + id,
+        method: "post",
+        data: params,
+    });
+}
diff --git a/src/api/productionManagement/productionProcess.js b/src/api/productionManagement/productionProcess.js
new file mode 100644
index 0000000..783f584
--- /dev/null
+++ b/src/api/productionManagement/productionProcess.js
@@ -0,0 +1,104 @@
+// 宸ュ簭椤甸潰鎺ュ彛
+import request from "@/utils/request";
+
+// 鍒嗛〉鏌ヨ
+export function listPage(query) {
+  return request({
+    url: "/technologyOperation/listPage",
+    method: "get",
+    params: query,
+  });
+}
+
+export function processList(query) {
+  return request({
+    url: "/technologyOperation/listPage",
+    method: "get",
+    params: query,
+  });
+}
+
+// 宸ュ簭鏌ヨ
+export function list(query) {
+  return request({
+    url: "/technologyOperation/listPage",
+    method: "get",
+    params: query,
+  });
+}
+export function add(data) {
+  return request({
+    url: "/technologyOperation/add",
+    method: "post",
+    data: data,
+  });
+}
+
+export function del(data) {
+  return request({
+    url: "/technologyOperation/batchDelete",
+    method: "delete",
+    data: data,
+  });
+}
+
+export function update(data) {
+  return request({
+    url: "/technologyOperation/update",
+    method: "put",
+    data: data,
+  });
+}
+
+// 瀵煎叆鏁版嵁
+export function importData(data) {
+  return request({
+    url: "/technologyOperation/importData",
+    method: "post",
+    data: data,
+  });
+}
+
+// 涓嬭浇妯℃澘
+export function downloadTemplate() {
+  return request({
+    url: "/technologyOperation/downloadTemplate",
+    method: "post",
+    responseType: "blob",
+  });
+}
+
+// 鑾峰彇宸ュ簭鍙傛暟鍒楄〃
+export function getProcessParamList(params) {
+  return request({
+    url: `/technologyOperationParam/list`,
+    method: "get",
+    params,
+  });
+}
+
+// 娣诲姞宸ュ簭鍙傛暟
+export function addProcessParam(data) {
+  return request({
+    url: "/technologyOperationParam/",
+    method: "post",
+    data: data,
+  });
+}
+
+// 缂栬緫宸ュ簭鍙傛暟
+export function editProcessParam(data) {
+  return request({
+    url: "/technologyOperationParam/",
+    method: "post",
+    data: data,
+  });
+}
+
+// 鍒犻櫎宸ュ簭鍙傛暟
+export function deleteProcessParam(id) {
+  return request({
+    url: `/technologyOperationParam/batchDelete/${id}`,
+    method: "delete",
+  });
+}
diff --git a/src/api/productionManagement/workOrder.js b/src/api/productionManagement/workOrder.js
index d3e0033..33ab462 100644
--- a/src/api/productionManagement/workOrder.js
+++ b/src/api/productionManagement/workOrder.js
@@ -42,6 +42,15 @@
   });
 }
 
+// 寮�濮嬫姤宸�
+export function startWork(data) {
+  return request({
+    url: "/productionProductMain/startWork",
+    method: "post",
+    data: data,
+  });
+}
+
 // 鑾峰彇宸ュ簭缁熻鏁版嵁
 export function getOperationStatistics(query) {
   return request({
diff --git a/src/config.js b/src/config.js
index 27244b3..e2f8ff4 100644
--- a/src/config.js
+++ b/src/config.js
@@ -1,7 +1,7 @@
 // 搴旂敤鍏ㄥ眬閰嶇疆
 const config = {
-  baseUrl: "http://1.15.17.182:9048",
-  fileUrl: "http://1.15.17.182:9049",
+  baseUrl: "http://1.15.17.182:9098",
+  fileUrl: "http://1.15.17.182:9097",
   // 搴旂敤淇℃伅
   appInfo: {
     // 搴旂敤鍚嶇О
diff --git a/src/pages/productionDesign/processManagement/edit.vue b/src/pages/productionDesign/processManagement/edit.vue
index 425be43..c3eaac4 100644
--- a/src/pages/productionDesign/processManagement/edit.vue
+++ b/src/pages/productionDesign/processManagement/edit.vue
@@ -6,36 +6,59 @@
              :model="form"
              :rules="rules"
              :errorType="['none']"
-             label-width="110">
-      <up-form-item label="宸ュ簭缂栫爜"
-                    prop="no">
-        <up-input v-model="form.no"
-                  placeholder="璇疯緭鍏ュ伐搴忕紪鐮�"
-                  clearable />
-      </up-form-item>
-      <up-form-item label="宸ュ簭鍚嶇О"
+             label-width="130">
+      <up-form-item label="閮ㄤ欢"
                     prop="name"
                     required>
         <up-input v-model="form.name"
-                  placeholder="璇疯緭鍏ュ伐搴忓悕绉�"
+                  placeholder="璇疯緭鍏ラ儴浠�"
                   clearable />
       </up-form-item>
-      <up-form-item label="宸ヨ祫瀹氶"
+      <up-form-item label="宸ュ簭缂栧彿"
+                    prop="no">
+        <up-input v-model="form.no"
+                  placeholder="璇疯緭鍏ュ伐搴忕紪鍙�"
+                  clearable />
+      </up-form-item>
+      <up-form-item label="宸ュ簭绫诲瀷"
+                    prop="processType"
+                    required>
+        <up-input v-model="processTypeText"
+                  placeholder="璇烽�夋嫨宸ュ簭绫诲瀷"
+                  readonly
+                  @click="showProcessTypeSheet = true" />
+        <template #right>
+          <up-icon name="arrow-right"
+                   @click="showProcessTypeSheet = true"></up-icon>
+        </template>
+      </up-form-item>
+      <up-form-item label="璁″垝宸ユ椂(灏忔椂)"
                     prop="salaryQuota">
         <up-input v-model="form.salaryQuota"
                   type="number"
-                  placeholder="璇疯緭鍏ュ伐璧勫畾棰�"
+                  placeholder="璇疯緭鍏ヨ鍒掑伐鏃�"
                   clearable />
       </up-form-item>
-      <up-form-item label="璁¤垂绫诲瀷"
-                    prop="type">
-        <up-input v-model="typeText"
-                  placeholder="璇烽�夋嫨璁¤垂绫诲瀷"
+      <up-form-item label="璁″垝浜哄憳"
+                    prop="planPerson">
+        <up-input v-model="planPersonText"
+                  placeholder="璇烽�夋嫨璁″垝浜哄憳"
                   readonly
-                  @click="showTypeSheet = true" />
+                  @click="showPlanPersonSheet = true" />
         <template #right>
           <up-icon name="arrow-right"
-                   @click="showTypeSheet = true"></up-icon>
+                   @click="showPlanPersonSheet = true"></up-icon>
+        </template>
+      </up-form-item>
+      <up-form-item label="璁″垝鎵ц浜哄憳"
+                    prop="executor">
+        <up-input v-model="executorText"
+                  placeholder="璇烽�夋嫨璁″垝鎵ц浜哄憳"
+                  readonly
+                  @click="showExecutorSheet = true" />
+        <template #right>
+          <up-icon name="arrow-right"
+                   @click="showExecutorSheet = true"></up-icon>
         </template>
       </up-form-item>
       <up-form-item label="鏄惁璐ㄦ"
@@ -44,27 +67,22 @@
           <up-switch v-model="form.isQuality" />
         </view>
       </up-form-item>
-      <up-form-item label="鏄惁鐢熶骇"
-                    prop="isProduction">
+      <up-form-item label="鏄惁鍏ュ簱"
+                    prop="inbound">
         <view style="display: flex; justify-content: flex-end; width: 100%;">
-          <up-switch v-model="form.isProduction" />
+          <up-switch v-model="form.inbound" />
         </view>
       </up-form-item>
-      <up-form-item label="鍏宠仈璁惧"
-                    prop="deviceLedgerId">
-        <up-input v-model="deviceText"
-                  placeholder="璇烽�夋嫨鍏宠仈璁惧"
-                  readonly
-                  @click="showDeviceSheet = true" />
-        <template #right>
-          <up-icon name="arrow-right"
-                   @click="showDeviceSheet = true"></up-icon>
-        </template>
+      <up-form-item label="鏄惁鎶ュ伐"
+                    prop="reportWork">
+        <view style="display: flex; justify-content: flex-end; width: 100%;">
+          <up-switch v-model="form.reportWork" />
+        </view>
       </up-form-item>
-      <up-form-item label="宸ュ簭鎻忚堪"
+      <up-form-item label="澶囨敞"
                     prop="remark">
         <up-textarea v-model="form.remark"
-                     placeholder="璇疯緭鍏ュ伐搴忔弿杩�"
+                     placeholder="璇疯緭鍏ュ娉�"
                      autoHeight />
       </up-form-item>
     </up-form>
@@ -72,18 +90,24 @@
                    :confirmText="processId ? '淇濆瓨' : '鏂板'"
                    @cancel="goBack"
                    @confirm="handleSubmit" />
-    <!-- 璁¤垂绫诲瀷閫夋嫨 -->
-    <up-action-sheet :show="showTypeSheet"
-                     title="閫夋嫨璁¤垂绫诲瀷"
-                     :actions="typeActions"
-                     @select="onSelectType"
-                     @close="showTypeSheet = false" />
-    <!-- 璁惧閫夋嫨 -->
-    <up-action-sheet :show="showDeviceSheet"
-                     title="閫夋嫨鍏宠仈璁惧"
-                     :actions="deviceActions"
-                     @select="onSelectDevice"
-                     @close="showDeviceSheet = false" />
+    <!-- 宸ュ簭绫诲瀷閫夋嫨 -->
+    <up-action-sheet :show="showProcessTypeSheet"
+                     title="閫夋嫨宸ュ簭绫诲瀷"
+                     :actions="processTypeActions"
+                     @select="onSelectProcessType"
+                     @close="showProcessTypeSheet = false" />
+    <!-- 璁″垝浜哄憳閫夋嫨 -->
+    <up-action-sheet :show="showPlanPersonSheet"
+                     title="閫夋嫨璁″垝浜哄憳"
+                     :actions="employeeActions"
+                     @select="onSelectPlanPerson"
+                     @close="showPlanPersonSheet = false" />
+    <!-- 璁″垝鎵ц浜哄憳閫夋嫨 -->
+    <up-action-sheet :show="showExecutorSheet"
+                     title="閫夋嫨璁″垝鎵ц浜哄憳"
+                     :actions="employeeActions"
+                     @select="onSelectExecutor"
+                     @close="showExecutorSheet = false" />
   </view>
 </template>
 
@@ -91,35 +115,49 @@
   import { reactive, ref, computed, onMounted } from "vue";
   import { onLoad, onReady } from "@dcloudio/uni-app";
   import FooterButtons from "@/components/FooterButtons.vue";
-  import {
-    add,
-    update,
-    getDeviceLedger,
-  } from "@/api/productionManagement/processManagement";
+  import { add, update } from "@/api/productionManagement/processManagement";
+  import { staffOnJobListPage } from "@/api/personnelManagement/onboarding";
 
   const formRef = ref(null);
   const loading = ref(false);
   const processId = ref(null);
   const pageTitle = computed(() => (processId.value ? "缂栬緫宸ュ簭" : "鏂板宸ュ簭"));
 
+  const processTypeOptions = [
+    "鏈哄姞宸�",
+    "鍒澘鍐疯姱鍒朵綔",
+    "绠¤矾缁勫",
+    "缃愪綋杩炴帴鍙婅皟璇�",
+    "娴嬭瘯鎵撳帇",
+    "鍏朵粬",
+  ];
+
+  const employeeList = ref([]);
+
   const form = ref({
     no: "",
     name: "",
+    processType: "",
     salaryQuota: "",
+    planPerson: null,
+    executor: null,
     isQuality: false,
-    isProduction: false,
+    inbound: false,
+    reportWork: false,
     remark: "",
-    deviceLedgerId: null,
-    type: 0,
   });
 
   const rules = {
-    name: [{ required: true, message: "璇疯緭鍏ュ伐搴忓悕绉�" }],
+    name: [
+      { required: true, message: "璇疯緭鍏ラ儴浠�" },
+      { max: 100, message: "鏈�澶�100涓瓧绗�" },
+    ],
+    processType: [{ required: true, message: "璇烽�夋嫨宸ュ簭绫诲瀷" }],
     salaryQuota: [
       {
         validator: (rule, value, callback) => {
           if (value !== "" && value !== null && (isNaN(value) || value < 0)) {
-            callback(new Error("宸ヨ祫瀹氶蹇呴』鏄潪璐熸暟瀛�"));
+            callback(new Error("璁″垝宸ユ椂蹇呴』鏄潪璐熸暟瀛�"));
           } else {
             callback();
           }
@@ -128,46 +166,60 @@
     ],
   };
 
-  const showTypeSheet = ref(false);
-  const typeActions = [
-    { name: "璁℃椂", value: 0 },
-    { name: "璁′欢", value: 1 },
-  ];
-  const typeText = computed(() => {
-    const action = typeActions.find(a => a.value === form.value.type);
-    return action ? action.name : "";
-  });
+  const showProcessTypeSheet = ref(false);
+  const processTypeActions = processTypeOptions.map(item => ({ name: item, value: item }));
+  const processTypeText = ref("");
 
-  const showDeviceSheet = ref(false);
-  const deviceActions = ref([]);
-  const deviceText = ref("");
+  const showPlanPersonSheet = ref(false);
+  const showExecutorSheet = ref(false);
+  const planPersonText = ref("");
+  const executorText = ref("");
 
-  const onSelectType = e => {
-    form.value.type = e.value;
-    showTypeSheet.value = false;
+  const employeeActions = computed(() =>
+    employeeList.value.map(item => ({
+      name: item.staffName,
+      id: item.id,
+    }))
+  );
+
+  const onSelectProcessType = e => {
+    form.value.processType = e.value;
+    processTypeText.value = e.name;
+    showProcessTypeSheet.value = false;
   };
 
-  const onSelectDevice = e => {
-    form.value.deviceLedgerId = e.id;
-    deviceText.value = e.name;
-    showDeviceSheet.value = false;
+  const onSelectPlanPerson = e => {
+    form.value.planPerson = e.id;
+    planPersonText.value = e.name;
+    showPlanPersonSheet.value = false;
   };
 
-  const loadDevices = async () => {
+  const onSelectExecutor = e => {
+    form.value.executor = e.id;
+    executorText.value = e.name;
+    showExecutorSheet.value = false;
+  };
+
+  const loadEmployees = async () => {
     try {
-      const { data } = await getDeviceLedger();
-      deviceActions.value = (data || []).map(item => ({
-        name: item.deviceName,
-        id: item.id,
-      }));
-      if (form.value.deviceLedgerId) {
-        const device = deviceActions.value.find(
-          d => d.id === Number(form.value.deviceLedgerId)
-        );
-        if (device) deviceText.value = device.name;
-      }
+      const res = await staffOnJobListPage({ current: -1, size: -1, staffState: 1 });
+      employeeList.value = res.data?.records || [];
     } catch (error) {
-      console.error("鍔犺浇璁惧澶辫触", error);
+      console.error("鍔犺浇鍛樺伐鍒楄〃澶辫触", error);
+    }
+  };
+
+  const resolveDisplayTexts = () => {
+    if (form.value.processType) {
+      processTypeText.value = form.value.processType;
+    }
+    if (form.value.planPerson) {
+      const emp = employeeList.value.find(e => e.id === form.value.planPerson);
+      if (emp) planPersonText.value = emp.staffName;
+    }
+    if (form.value.executor) {
+      const emp = employeeList.value.find(e => e.id === form.value.executor);
+      if (emp) executorText.value = emp.staffName;
     }
   };
 
@@ -210,10 +262,9 @@
       const item = JSON.parse(decodeURIComponent(option.item));
       processId.value = item.id;
       Object.assign(form.value, item);
-      // 澶勭悊绫诲瀷杞崲锛岀‘淇濇槸鏁板瓧
-      form.value.type = Number(form.value.type);
       form.value.isQuality = !!form.value.isQuality;
-      form.value.isProduction = !!form.value.isProduction;
+      form.value.inbound = !!form.value.inbound;
+      form.value.reportWork = !!form.value.reportWork;
     }
   });
 
@@ -222,7 +273,7 @@
   });
 
   onMounted(() => {
-    loadDevices();
+    loadEmployees().then(() => resolveDisplayTexts());
   });
 </script>
 
diff --git a/src/pages/productionDesign/processManagement/index.vue b/src/pages/productionDesign/processManagement/index.vue
index 6ca2f76..9fd6d5d 100644
--- a/src/pages/productionDesign/processManagement/index.vue
+++ b/src/pages/productionDesign/processManagement/index.vue
@@ -7,7 +7,7 @@
         <view class="search-input">
           <up-input class="search-text"
                     v-model="queryParams.name"
-                    placeholder="璇疯緭鍏ュ伐搴忓悕绉�"
+                    placeholder="璇疯緭鍏ラ儴浠跺悕绉�"
                     clearable
                     @change="handleSearch" />
         </view>
@@ -38,35 +38,38 @@
         <up-divider></up-divider>
         <view class="item-details">
           <view class="detail-row">
+            <text class="detail-label">閮ㄤ欢绫诲瀷</text>
+            <text class="detail-value">{{ item.processType || "-" }}</text>
+          </view>
+          <view class="detail-row">
             <text class="detail-label">鍏宠仈璁惧</text>
             <text class="detail-value">{{ getDeviceName(item.deviceLedgerId) }}</text>
           </view>
           <view class="detail-row">
-            <text class="detail-label">宸ヨ祫瀹氶</text>
-            <text class="detail-value highlight">楼{{ item.salaryQuota || 0 }}</text>
+            <text class="detail-label">璁″垝宸ユ椂</text>
+            <text class="detail-value highlight">{{ item.salaryQuota || 0 }}灏忔椂</text>
           </view>
           <view class="detail-row">
-            <text class="detail-label">宸ュ簭鐘舵��</text>
-            <view class="detail-value">
-              <up-tag :text="item.isQuality ? '璐ㄦ' : '闈炶川妫�'"
-                      :type="item.isQuality ? 'warning' : 'info'"
-                      size="mini"
-                      style="margin-left: 8rpx" />
-              <up-tag :text="item.isProduction ? '鐢熶骇' : '涓嶇敓浜�'"
-                      :type="item.isProduction ? 'warning' : 'info'"
-                      size="mini"
-                      style="margin-left: 8rpx" />
-              <up-tag v-if="item.type !== null && item.type !== undefined"
-                      :text="item.type == 0 ? '璁℃椂' : '璁′欢'"
-                      :type="item.type == 1 ? 'primary' : 'success'"
-                      size="mini"
-                      style="margin-left: 8rpx" />
-            </view>
+            <text class="detail-label">璁″垝浜哄憳</text>
+            <text class="detail-value">{{ getEmployeeName(item.planPerson) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">璁″垝鎵ц浜哄憳</text>
+            <text class="detail-value">{{ getEmployeeName(item.executor) }}</text>
           </view>
           <view class="detail-row">
             <text class="detail-label">澶囨敞</text>
             <text class="detail-value">{{ item.remark || "-" }}</text>
           </view>
+        </view>
+        <view class="status-tags">
+          <up-tag :text="item.isQuality ? '璐ㄦ' : '闈炶川妫�'"
+                  :type="item.isQuality ? 'warning' : 'info'"
+                  size="mini" />
+          <up-tag :text="item.isProduction ? '鐢熶骇' : '涓嶇敓浜�'"
+                  :type="item.isProduction ? 'warning' : 'info'"
+                  size="mini"
+                  style="margin-left: 8rpx" />
         </view>
         <view class="action-buttons">
           <up-button class="action-btn"
@@ -87,7 +90,7 @@
     </view>
     <view v-else
           class="no-data">
-      <text>鏆傛棤宸ュ簭鏁版嵁</text>
+      <text>鏆傛棤閮ㄤ欢鏁版嵁</text>
     </view>
     <view class="fab-button"
           @click="goAdd">
@@ -106,12 +109,14 @@
     del,
     getDeviceLedger,
   } from "@/api/productionManagement/processManagement";
+  import { staffOnJobListPage } from "@/api/personnelManagement/onboarding";
 
   const queryParams = reactive({
     name: "",
   });
   const list = ref([]);
   const deviceOptions = ref([]);
+  const employeeOptions = ref([]);
   const pageStatus = ref("loadmore");
 
   const page = reactive({
@@ -130,12 +135,27 @@
     return device?.deviceName || "鏈叧鑱�";
   };
 
+  const getEmployeeName = employeeId => {
+    if (!employeeId) return "鏈寚瀹�";
+    const emp = employeeOptions.value.find(item => item.id === Number(employeeId));
+    return emp?.staffName || "鏈寚瀹�";
+  };
+
   const loadDevices = async () => {
     try {
       const { data } = await getDeviceLedger();
       deviceOptions.value = data || [];
     } catch (error) {
       console.error("鍔犺浇璁惧鍒楄〃澶辫触", error);
+    }
+  };
+
+  const loadEmployees = async () => {
+    try {
+      const res = await staffOnJobListPage({ current: -1, size: -1, staffState: 1 });
+      employeeOptions.value = res.data?.records || [];
+    } catch (error) {
+      console.error("鍔犺浇鍛樺伐鍒楄〃澶辫触", error);
     }
   };
 
@@ -217,7 +237,7 @@
   });
 
   onShow(async () => {
-    await loadDevices();
+    await Promise.all([loadDevices(), loadEmployees()]);
     handleSearch();
   });
 </script>
@@ -232,6 +252,12 @@
     font-size: 28rpx;
   }
 
+  .status-tags {
+    display: flex;
+    align-items: center;
+    padding-bottom: 16rpx;
+  }
+
   .action-buttons {
     display: flex;
     justify-content: flex-end;
diff --git a/src/pages/productionManagement/productionReport/components/MaterialDialog.vue b/src/pages/productionManagement/productionReport/components/MaterialDialog.vue
new file mode 100644
index 0000000..e9eddc9
--- /dev/null
+++ b/src/pages/productionManagement/productionReport/components/MaterialDialog.vue
@@ -0,0 +1,437 @@
+<template>
+  <view>
+    <!-- 涓荤墿鏂欏脊绐� -->
+    <view v-if="dialogVisible" class="material-overlay">
+      <view class="material-container">
+        <view class="material-header">
+          <text class="material-title">鐗╂枡</text>
+          <view class="close-btn" @click="dialogVisible = false">
+            <up-icon name="close" size="20" color="#666" />
+          </view>
+        </view>
+        <scroll-view class="material-body" scroll-y>
+          <view v-if="materialTableData.length === 0" class="empty-tip">
+            <text>鏆傛棤鐗╂枡鏁版嵁</text>
+          </view>
+          <view v-for="item in materialTableData" :key="item.id" class="material-card">
+            <view class="material-row">
+              <text class="mc-label">宸ュ簭鍚嶇О</text>
+              <text class="mc-value">{{ item.processName || '-' }}</text>
+            </view>
+            <view class="material-row">
+              <text class="mc-label">鍘熸枡鍚嶇О</text>
+              <text class="mc-value">{{ item.materialName || '-' }}</text>
+            </view>
+            <view class="material-row">
+              <text class="mc-label">鍘熸枡鍨嬪彿</text>
+              <text class="mc-value">{{ item.materialModel || '-' }}</text>
+            </view>
+            <view class="material-row">
+              <text class="mc-label">璁¢噺鍗曚綅</text>
+              <text class="mc-value">{{ item.unit || '-' }}</text>
+            </view>
+            <view class="material-row">
+              <text class="mc-label">绾胯竟浠撴暟閲�</text>
+              <text class="mc-value">{{ item.pickQty || 0 }}</text>
+            </view>
+            <view class="material-row">
+              <text class="mc-label">琛ユ枡鏁伴噺</text>
+              <text class="mc-value">{{ item.supplementQty || 0 }}</text>
+            </view>
+            <view class="material-row">
+              <text class="mc-label">瀹為檯鏁伴噺</text>
+              <view class="mc-value">
+                <up-input v-model="item.actualQty"
+                          type="number"
+                          placeholder="璇疯緭鍏ュ疄闄呮暟閲�"
+                          clearable
+                          style="width: 200rpx" />
+              </view>
+            </view>
+            <view class="material-actions">
+              <up-button size="small" type="primary" @click="openSupplementDialog(item)">琛ユ枡</up-button>
+              <up-button size="small" type="info" @click="openSupplementRecordDialog(item)">琛ユ枡璁板綍</up-button>
+            </view>
+          </view>
+        </scroll-view>
+        <view class="material-footer">
+          <up-button type="primary" :loading="pickSubmitting" @click="handleSubmitPick">棰嗙敤</up-button>
+          <up-button @click="dialogVisible = false">鍙栨秷</up-button>
+        </view>
+      </view>
+    </view>
+
+    <!-- 琛ユ枡寮圭獥 -->
+    <view v-if="supplementDialogVisible" class="material-overlay">
+      <view class="material-container supplement-container">
+        <view class="material-header">
+          <text class="material-title">琛ユ枡</text>
+          <view class="close-btn" @click="supplementDialogVisible = false">
+            <up-icon name="close" size="20" color="#666" />
+          </view>
+        </view>
+        <view class="material-body">
+          <up-form :model="supplementForm" ref="supplementFormRef" label-width="140">
+            <up-form-item label="琛ユ枡鏁伴噺" prop="supplementQty" required>
+              <up-input v-model="supplementForm.supplementQty"
+                        type="number"
+                        placeholder="璇疯緭鍏ヨˉ鏂欐暟閲�"
+                        clearable />
+            </up-form-item>
+            <up-form-item label="琛ユ枡鍘熷洜" prop="supplementReason" required>
+              <up-textarea v-model="supplementForm.supplementReason"
+                           placeholder="璇疯緭鍏ヨˉ鏂欏師鍥�"
+                           :maxlength="200"
+                           autoHeight />
+            </up-form-item>
+          </up-form>
+        </view>
+        <view class="material-footer">
+          <up-button type="primary" :loading="supplementSubmitting" @click="handleSubmitSupplement">纭畾</up-button>
+          <up-button @click="supplementDialogVisible = false">鍙栨秷</up-button>
+        </view>
+      </view>
+    </view>
+
+    <!-- 琛ユ枡璁板綍寮圭獥 -->
+    <view v-if="supplementRecordDialogVisible" class="material-overlay">
+      <view class="material-container supplement-record-container">
+        <view class="material-header">
+          <text class="material-title">琛ユ枡璁板綍</text>
+          <view class="close-btn" @click="supplementRecordDialogVisible = false">
+            <up-icon name="close" size="20" color="#666" />
+          </view>
+        </view>
+        <scroll-view class="material-body" scroll-y>
+          <view v-if="supplementRecordTableData.length === 0" class="empty-tip">
+            <text>鏆傛棤琛ユ枡璁板綍</text>
+          </view>
+          <view v-for="item in supplementRecordTableData" :key="item.id" class="record-card">
+            <view class="material-row">
+              <text class="mc-label">琛ユ枡鏁伴噺</text>
+              <text class="mc-value">{{ item.supplementQty }}</text>
+            </view>
+            <view class="material-row">
+              <text class="mc-label">琛ユ枡鍘熷洜</text>
+              <text class="mc-value">{{ item.supplementReason }}</text>
+            </view>
+            <view class="material-row">
+              <text class="mc-label">琛ユ枡浜�</text>
+              <text class="mc-value">{{ item.supplementUserName }}</text>
+            </view>
+            <view class="material-row">
+              <text class="mc-label">琛ユ枡鏃ユ湡</text>
+              <text class="mc-value">{{ item.supplementTime }}</text>
+            </view>
+          </view>
+        </scroll-view>
+        <view class="material-footer">
+          <up-button @click="supplementRecordDialogVisible = false">鍏抽棴</up-button>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { computed, nextTick, reactive, ref, watch } from "vue";
+  import {
+    listWorkOrderMaterialLedger,
+    addWorkOrderMaterialSupplement,
+    listWorkOrderMaterialSupplementRecord,
+    pickWorkOrderMaterial,
+  } from "@/api/productionManagement/workOrder.js";
+
+  const props = defineProps({
+    modelValue: {
+      type: Boolean,
+      default: false,
+    },
+    rowData: {
+      type: Object,
+      default: () => null,
+    },
+  });
+
+  const emit = defineEmits(["update:modelValue", "refresh"]);
+
+  const dialogVisible = computed({
+    get: () => props.modelValue,
+    set: val => emit("update:modelValue", val),
+  });
+
+  const materialTableLoading = ref(false);
+  const materialTableData = ref([]);
+  const currentMaterialRow = ref(null);
+  const currentMaterialOrderRow = ref(null);
+  const pickSubmitting = ref(false);
+
+  const supplementDialogVisible = ref(false);
+  const supplementSubmitting = ref(false);
+  const supplementFormRef = ref(null);
+  const supplementForm = reactive({
+    supplementQty: null,
+    supplementReason: "",
+  });
+
+  const supplementRecordDialogVisible = ref(false);
+  const supplementRecordLoading = ref(false);
+  const supplementRecordTableData = ref([]);
+
+  const loadMaterialTable = async row => {
+    if (!row?.id) return;
+    currentMaterialOrderRow.value = row;
+    materialTableLoading.value = true;
+    materialTableData.value = [];
+    try {
+      const res = await listWorkOrderMaterialLedger({
+        workOrderId: row.id,
+        processId: row.processId,
+        productProcessRouteItemId: row.productProcessRouteItemId,
+      });
+      materialTableData.value = res.data || [];
+    } catch (e) {
+      console.error("鑾峰彇鐗╂枡鍙拌处澶辫触", e);
+      uni.showToast({ title: "鑾峰彇鐗╂枡鍙拌处澶辫触", icon: "error" });
+    } finally {
+      materialTableLoading.value = false;
+    }
+  };
+
+  watch(
+    () => props.modelValue,
+    visible => {
+      if (visible && props.rowData) {
+        loadMaterialTable(props.rowData);
+      }
+    }
+  );
+
+  const resetSupplementForm = () => {
+    supplementForm.supplementQty = null;
+    supplementForm.supplementReason = "";
+  };
+
+  const openSupplementDialog = row => {
+    currentMaterialRow.value = row;
+    resetSupplementForm();
+    supplementDialogVisible.value = true;
+  };
+
+  const handleSubmitSupplement = () => {
+    if (!supplementForm.supplementQty) {
+      uni.showToast({ title: "璇疯緭鍏ヨˉ鏂欐暟閲�", icon: "none" });
+      return;
+    }
+    if (!supplementForm.supplementReason) {
+      uni.showToast({ title: "璇疯緭鍏ヨˉ鏂欏師鍥�", icon: "none" });
+      return;
+    }
+    if (!currentMaterialRow.value?.id) {
+      uni.showToast({ title: "缂哄皯鐗╂枡鏄庣粏ID", icon: "none" });
+      return;
+    }
+    supplementSubmitting.value = true;
+    addWorkOrderMaterialSupplement({
+      materialLedgerId: currentMaterialRow.value.id,
+      supplementQty: Number(supplementForm.supplementQty),
+      supplementReason: supplementForm.supplementReason,
+      workOrderId: currentMaterialOrderRow.value?.id,
+    })
+      .then(async () => {
+        supplementDialogVisible.value = false;
+        await loadMaterialTable(currentMaterialOrderRow.value);
+        uni.showToast({ title: "琛ユ枡鎴愬姛" });
+        emit("refresh");
+      })
+      .catch(e => {
+        console.error("琛ユ枡澶辫触", e);
+        uni.showToast({ title: "琛ユ枡澶辫触", icon: "error" });
+      })
+      .finally(() => {
+        supplementSubmitting.value = false;
+      });
+  };
+
+  const openSupplementRecordDialog = async row => {
+    supplementRecordDialogVisible.value = true;
+    supplementRecordLoading.value = true;
+    supplementRecordTableData.value = [];
+    try {
+      const res = await listWorkOrderMaterialSupplementRecord({
+        materialLedgerId: row.id,
+      });
+      supplementRecordTableData.value = res.data || [];
+    } catch (e) {
+      console.error("鑾峰彇琛ユ枡璁板綍澶辫触", e);
+      uni.showToast({ title: "鑾峰彇琛ユ枡璁板綍澶辫触", icon: "error" });
+    } finally {
+      supplementRecordLoading.value = false;
+    }
+  };
+
+  const validatePickRows = () => {
+    if (materialTableData.value.length === 0) {
+      return { valid: false, message: "鏆傛棤鍙鐢ㄧ墿鏂�" };
+    }
+    const invalidRow = materialTableData.value.find(
+      item =>
+        item.actualQty === null ||
+        item.actualQty === undefined ||
+        item.actualQty === ""
+    );
+    if (invalidRow) {
+      return { valid: false, message: "璇峰~鍐欏疄闄呮暟閲忓悗鍐嶉鐢�" };
+    }
+    const exceedRow = materialTableData.value.find(item => {
+      const maxQty = Number(item.pickQty || 0) + Number(item.supplementQty || 0);
+      return Number(item.actualQty || 0) > maxQty;
+    });
+    if (exceedRow) {
+      return { valid: false, message: "瀹為檯鏁伴噺涓嶈兘澶т簬棰嗙敤鏁伴噺+琛ユ枡鏁伴噺" };
+    }
+    return { valid: true, message: "" };
+  };
+
+  const handleSubmitPick = async () => {
+    if (!currentMaterialOrderRow.value?.id) return;
+    const validateResult = validatePickRows();
+    if (!validateResult.valid) {
+      uni.showToast({ title: validateResult.message, icon: "none" });
+      return;
+    }
+    pickSubmitting.value = true;
+    try {
+      await pickWorkOrderMaterial({
+        workOrderId: currentMaterialOrderRow.value.id,
+        items: materialTableData.value.map(item => ({
+          materialLedgerId: item.id,
+          actualQty: Number(item.actualQty || 0),
+        })),
+      });
+      uni.showToast({ title: "棰嗙敤鎴愬姛" });
+      await loadMaterialTable(currentMaterialOrderRow.value);
+      emit("refresh");
+    } catch (e) {
+      console.error("棰嗙敤澶辫触", e);
+      uni.showToast({ title: "棰嗙敤澶辫触", icon: "error" });
+    } finally {
+      pickSubmitting.value = false;
+    }
+  };
+</script>
+
+<style scoped lang="scss">
+  .material-overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.5);
+    z-index: 999;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .material-container {
+    width: 92%;
+    max-height: 85vh;
+    background: #fff;
+    border-radius: 16rpx;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+  }
+
+  .supplement-container {
+    max-height: 60vh;
+  }
+
+  .supplement-record-container {
+    max-height: 75vh;
+  }
+
+  .material-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 24rpx 32rpx;
+    border-bottom: 1px solid #f0f0f0;
+    flex-shrink: 0;
+  }
+
+  .material-title {
+    font-size: 32rpx;
+    font-weight: 600;
+    color: #303133;
+  }
+
+  .close-btn {
+    padding: 8rpx;
+  }
+
+  .material-body {
+    flex: 1;
+    padding: 16rpx 24rpx;
+    overflow-y: auto;
+  }
+
+  .empty-tip {
+    text-align: center;
+    padding: 60rpx 0;
+    color: #999;
+    font-size: 28rpx;
+  }
+
+  .material-card {
+    background: #f9fafb;
+    border-radius: 12rpx;
+    padding: 20rpx;
+    margin-bottom: 16rpx;
+  }
+
+  .material-row {
+    display: flex;
+    align-items: center;
+    padding: 10rpx 0;
+  }
+
+  .mc-label {
+    width: 160rpx;
+    font-size: 26rpx;
+    color: #909399;
+    flex-shrink: 0;
+  }
+
+  .mc-value {
+    flex: 1;
+    font-size: 26rpx;
+    color: #303133;
+  }
+
+  .material-actions {
+    display: flex;
+    gap: 16rpx;
+    margin-top: 16rpx;
+    padding-top: 16rpx;
+    border-top: 1px solid #ebeef5;
+  }
+
+  .record-card {
+    background: #f9fafb;
+    border-radius: 12rpx;
+    padding: 20rpx;
+    margin-bottom: 16rpx;
+  }
+
+  .material-footer {
+    display: flex;
+    justify-content: flex-end;
+    gap: 16rpx;
+    padding: 20rpx 32rpx;
+    border-top: 1px solid #f0f0f0;
+    flex-shrink: 0;
+  }
+</style>
diff --git a/src/pages/productionManagement/productionReport/components/filesDia.vue b/src/pages/productionManagement/productionReport/components/filesDia.vue
new file mode 100644
index 0000000..66b7725
--- /dev/null
+++ b/src/pages/productionManagement/productionReport/components/filesDia.vue
@@ -0,0 +1,262 @@
+<template>
+  <view v-if="visible" class="files-overlay">
+    <view class="files-container">
+      <view class="files-header">
+        <text class="files-title">宸ュ崟闄勪欢</text>
+        <view class="close-btn" @click="closeDia">
+          <up-icon name="close" size="20" color="#666" />
+        </view>
+      </view>
+      <view class="files-toolbar">
+        <up-button type="primary" size="small" @click="handleUpload">涓婁紶鍥剧墖</up-button>
+        <up-button type="error" size="small" plain @click="handleDelete">鍒犻櫎</up-button>
+      </view>
+      <scroll-view class="files-list" scroll-y>
+        <view v-if="tableData.length === 0" class="empty-tip">
+          <text>鏆傛棤闄勪欢</text>
+        </view>
+        <view v-for="item in tableData" :key="item.id" class="file-item">
+          <view class="file-left" @click="toggleSelect(item)">
+            <up-icon :name="selectedIds.includes(item.id) ? 'checkbox-mark' : 'checkbox'"
+                     size="20"
+                     :color="selectedIds.includes(item.id) ? '#2979ff' : '#c0c4cc'" />
+          </view>
+          <view class="file-info" @click="handlePreview(item)">
+            <text class="file-name">{{ item.name }}</text>
+          </view>
+          <view class="file-actions">
+            <text class="action-link" @click="handleDownload(item)">涓嬭浇</text>
+            <text class="action-link" @click="handlePreview(item)">棰勮</text>
+          </view>
+        </view>
+      </scroll-view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { ref, getCurrentInstance } from "vue";
+  import { getToken } from "@/utils/auth.js";
+  import {
+    productWorkOrderFileAdd,
+    productWorkOrderFileDel,
+    productWorkOrderFileListPage,
+  } from "@/api/productionManagement/productWorkOrderFile.js";
+
+  const { proxy } = getCurrentInstance();
+
+  const visible = ref(false);
+  const currentWorkOrderId = ref("");
+  const selectedIds = ref([]);
+  const tableData = ref([]);
+  const tableLoading = ref(false);
+
+  const uploadUrl = import.meta.env.VITE_APP_BASE_API + "/file/upload";
+
+  const openDialog = row => {
+    visible.value = true;
+    currentWorkOrderId.value = row.id;
+    selectedIds.value = [];
+    getList();
+  };
+
+  const closeDia = () => {
+    visible.value = false;
+  };
+
+  const getList = () => {
+    tableLoading.value = true;
+    productWorkOrderFileListPage({
+      workOrderId: currentWorkOrderId.value,
+      current: 1,
+      size: 100,
+    })
+      .then(res => {
+        tableData.value = res.data.records || [];
+      })
+      .finally(() => {
+        tableLoading.value = false;
+      });
+  };
+
+  const toggleSelect = item => {
+    const idx = selectedIds.value.indexOf(item.id);
+    if (idx > -1) {
+      selectedIds.value.splice(idx, 1);
+    } else {
+      selectedIds.value.push(item.id);
+    }
+  };
+
+  const handleUpload = () => {
+    uni.chooseImage({
+      count: 1,
+      sizeType: ["compressed"],
+      sourceType: ["album", "camera"],
+      success: res => {
+        const tempFilePath = res.tempFilePaths[0];
+        uni.showLoading({ title: "涓婁紶涓�..." });
+        uni.uploadFile({
+          url: uploadUrl,
+          filePath: tempFilePath,
+          name: "file",
+          header: {
+            Authorization: "Bearer " + getToken(),
+          },
+          success: uploadRes => {
+            const data = JSON.parse(uploadRes.data);
+            if (data.code === 200) {
+              const fileRow = {
+                name: data.data.originalName,
+                url: data.data.tempPath,
+                workOrderId: currentWorkOrderId.value,
+              };
+              productWorkOrderFileAdd(fileRow).then(() => {
+                uni.showToast({ title: "涓婁紶鎴愬姛" });
+                getList();
+              });
+            } else {
+              uni.showToast({ title: "涓婁紶澶辫触", icon: "error" });
+            }
+          },
+          fail: () => {
+            uni.showToast({ title: "涓婁紶澶辫触", icon: "error" });
+          },
+          complete: () => {
+            uni.hideLoading();
+          },
+        });
+      },
+    });
+  };
+
+  const handleDelete = () => {
+    if (selectedIds.value.length === 0) {
+      uni.showToast({ title: "璇烽�夋嫨鏁版嵁", icon: "none" });
+      return;
+    }
+    uni.showModal({
+      title: "鍒犻櫎",
+      content: "閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�",
+      success: res => {
+        if (res.confirm) {
+          productWorkOrderFileDel(selectedIds.value).then(() => {
+            uni.showToast({ title: "鍒犻櫎鎴愬姛" });
+            selectedIds.value = [];
+            getList();
+          });
+        }
+      },
+    });
+  };
+
+  const handleDownload = row => {
+    proxy.$download.byUrl(row.url, row.originalFilename);
+  };
+
+  const handlePreview = row => {
+    uni.previewImage({
+      urls: [row.url],
+      current: row.url,
+    });
+  };
+
+  defineExpose({
+    openDialog,
+  });
+</script>
+
+<style scoped lang="scss">
+  .files-overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.5);
+    z-index: 999;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .files-container {
+    width: 90%;
+    max-height: 80vh;
+    background: #fff;
+    border-radius: 16rpx;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+  }
+
+  .files-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 24rpx 32rpx;
+    border-bottom: 1px solid #f0f0f0;
+  }
+
+  .files-title {
+    font-size: 32rpx;
+    font-weight: 600;
+    color: #303133;
+  }
+
+  .close-btn {
+    padding: 8rpx;
+  }
+
+  .files-toolbar {
+    display: flex;
+    justify-content: flex-end;
+    gap: 16rpx;
+    padding: 16rpx 32rpx;
+    border-bottom: 1px solid #f0f0f0;
+  }
+
+  .files-list {
+    flex: 1;
+    padding: 16rpx 32rpx;
+    overflow-y: auto;
+  }
+
+  .empty-tip {
+    text-align: center;
+    padding: 60rpx 0;
+    color: #999;
+    font-size: 28rpx;
+  }
+
+  .file-item {
+    display: flex;
+    align-items: center;
+    padding: 20rpx 0;
+    border-bottom: 1px solid #f5f5f5;
+  }
+
+  .file-left {
+    margin-right: 16rpx;
+  }
+
+  .file-info {
+    flex: 1;
+  }
+
+  .file-name {
+    font-size: 28rpx;
+    color: #303133;
+  }
+
+  .file-actions {
+    display: flex;
+    gap: 24rpx;
+    flex-shrink: 0;
+  }
+
+  .action-link {
+    font-size: 26rpx;
+    color: #2979ff;
+  }
+</style>
diff --git a/src/pages/productionManagement/productionReport/index.vue b/src/pages/productionManagement/productionReport/index.vue
index ac92038..9adbd6d 100644
--- a/src/pages/productionManagement/productionReport/index.vue
+++ b/src/pages/productionManagement/productionReport/index.vue
@@ -164,6 +164,8 @@
     reportWork: "",
     productionOrderRoutingOperationId: "",
     productionOrderId: "",
+    productMainId: null,
+    productProcessRouteItemId: "",
     workHour: 0,
     type: null,
     paramGroups: {},
@@ -352,11 +354,13 @@
 
     const submitData = {
       quantity: quantity,
-      scrapQty: scrapQty,
+      scrapQty: isNaN(scrapQty) ? 0 : 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,
@@ -429,7 +433,14 @@
         Math.max(0, planQuantity - completeQuantity)
       );
       form.value.workOrderId = orderRow.id || "";
+      form.value.productProcessRouteItemId =
+        orderRow.productProcessRouteItemId || "";
       form.value.reportWork = orderRow.reportWork || "";
+      form.value.productMainId = orderRow.productMainId || null;
+      form.value.scrapQty =
+        orderRow.scrapQty !== undefined && orderRow.scrapQty !== null
+          ? orderRow.scrapQty
+          : "";
       form.value.productionOrderRoutingOperationId =
         orderRow.productionOrderRoutingOperationId || "";
       form.value.productionOrderId = orderRow.productionOrderId || "";
diff --git a/src/pages/productionManagement/workOrder/index.vue b/src/pages/productionManagement/workOrder/index.vue
index 5360a11..c1c7aa9 100644
--- a/src/pages/productionManagement/workOrder/index.vue
+++ b/src/pages/productionManagement/workOrder/index.vue
@@ -1,27 +1,34 @@
 <template>
   <view class="work-order">
-    <!-- 閫氱敤椤甸潰澶撮儴 -->
     <PageHeader title="鐢熶骇宸ュ崟" @back="goBack" />
-    
+
     <!-- 鎼滅储鍖哄煙 -->
     <view class="search-section">
       <view class="search-bar">
         <view class="search-input">
-          <up-input
-            class="search-text"
-            placeholder="璇疯緭鍏ュ伐鍗曠紪鍙锋悳绱�"
-            v-model="searchForm.workOrderNo"
-            @confirm="handleQuery"
-            clearable
-          />
+          <up-input class="search-text"
+                    v-model="data.searchForm.workOrderNo"
+                    placeholder="宸ュ崟缂栧彿"
+                    @confirm="handleQuery"
+                    clearable />
         </view>
-        
+        <view class="search-input">
+          <up-input class="search-text"
+                    v-model="data.searchForm.npsNo"
+                    placeholder="鐢熶骇璁㈠崟鍙�"
+                    @confirm="handleQuery"
+                    clearable />
+        </view>
         <view class="filter-button" @click="handleQuery">
           <up-icon name="search" size="24" color="#999"></up-icon>
         </view>
       </view>
+      <view class="switch-row">
+        <text class="switch-label">浠呯湅鎴戠殑</text>
+        <up-switch v-model="filterMine" @change="handleQuery" size="18" />
+      </view>
     </view>
-    
+
     <!-- 宸ュ崟鍒楄〃 -->
     <scroll-view scroll-y class="ledger-list" v-if="tableData.length > 0" @scrolltolower="loadMore">
       <view v-for="(item, index) in tableData" :key="item.id || index" class="ledger-item">
@@ -36,10 +43,14 @@
             <text class="item-tag tag-type">{{ item.workOrderType }}</text>
           </view>
         </view>
-        
+
         <up-divider></up-divider>
-        
+
         <view class="item-details">
+          <view class="detail-row">
+            <text class="detail-label">鐢熶骇璁㈠崟鍙�</text>
+            <text class="detail-value">{{ item.npsNo || '-' }}</text>
+          </view>
           <view class="detail-row">
             <text class="detail-label">浜у搧鍚嶇О</text>
             <text class="detail-value">{{ item.productName }}</text>
@@ -50,24 +61,24 @@
           </view>
           <view class="detail-row">
             <text class="detail-label">宸ュ簭鍚嶇О</text>
-            <text class="detail-value">{{ item.processName }}</text>
+            <text class="detail-value">{{ item.operationName }}</text>
           </view>
           <view class="detail-row">
             <text class="detail-label">闇�姹�/瀹屾垚鏁伴噺</text>
             <text class="detail-value">{{ item.planQuantity }} / {{ item.completeQuantity }} {{ item.unit }}</text>
           </view>
-          
+
           <view class="progress-section">
             <text class="detail-label">瀹屾垚杩涘害</text>
             <view class="progress-bar">
-              <up-line-progress 
-                :percentage="toProgressPercentage(item.completionStatus)" 
+              <up-line-progress
+                :percentage="toProgressPercentage(item.completionStatus)"
                 activeColor="#2979ff"
                 :showText="true"
               ></up-line-progress>
             </view>
           </view>
-          
+
           <view class="detail-row">
             <text class="detail-label">璁″垝寮�濮�</text>
             <text class="detail-value">{{ item.planStartTime }}</text>
@@ -76,51 +87,52 @@
             <text class="detail-label">璁″垝缁撴潫</text>
             <text class="detail-value">{{ item.planEndTime }}</text>
           </view>
+          <view class="detail-row">
+            <text class="detail-label">瀹為檯寮�濮�</text>
+            <text class="detail-value">{{ item.actualStartTime || '-' }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">瀹為檯缁撴潫</text>
+            <text class="detail-value">{{ item.actualEndTime || '-' }}</text>
+          </view>
+        </view>
+
+        <view class="item-actions">
+          <up-button v-if="showStartReport(item)"
+                     class="action-btn"
+                     size="small"
+                     type="primary"
+                     @click="handleStartWork(item)">寮�濮嬫姤宸�</up-button>
+          <up-button v-if="showEndReport(item)"
+                     class="action-btn"
+                     size="small"
+                     type="success"
+                     @click="goReport(item)">缁撴潫鎶ュ伐</up-button>
         </view>
       </view>
       <up-loadmore :status="loadStatus" />
     </scroll-view>
-    
+
     <view v-else-if="!loading" class="no-data">
       <up-empty mode="data" text="鏆傛棤宸ュ崟鏁版嵁"></up-empty>
     </view>
 
-    <!-- 娴佽浆鍗″脊绐� -->
-    <up-popup :show="transferCardVisible" mode="center" @close="transferCardVisible = false" round="10">
-      <view class="qr-popup">
-        <text class="qr-title">宸ュ崟娴佽浆鍗′簩缁寸爜</text>
-        <view class="qr-box">
-          <geek-qrcode
-            v-if="transferCardRowData"
-            :val="String(transferCardRowData.id)"
-            :size="200"
-          />
-        </view>
-        <text class="qr-info" v-if="transferCardRowData">{{ transferCardRowData.workOrderNo }}</text>
-        <up-button text="鍏抽棴" @click="transferCardVisible = false" style="margin-top: 20px;"></up-button>
-      </view>
-    </up-popup>
-
-    <!-- 闄勪欢缁勪欢 -->
-    <FilesDia ref="workOrderFilesRef" />
   </view>
 </template>
 
 <script setup>
-import { ref, reactive, toRefs, getCurrentInstance } from "vue";
+import { ref, reactive } from "vue";
 import { onShow } from '@dcloudio/uni-app';
-import { productWorkOrderPage } from "@/api/productionManagement/workOrder.js";
+import { productWorkOrderPage, startWork } from "@/api/productionManagement/workOrder.js";
 import PageHeader from "@/components/PageHeader.vue";
-import FilesDia from "./components/filesDia.vue";
+import useUserStore from "@/store/modules/user";
 
-const { proxy } = getCurrentInstance();
+const userStore = useUserStore();
 
 const loading = ref(false);
 const tableData = ref([]);
 const loadStatus = ref('loadmore');
-const transferCardVisible = ref(false);
-const transferCardRowData = ref(null);
-const workOrderFilesRef = ref(null);
+const filterMine = ref(false);
 
 const page = reactive({
   current: 1,
@@ -131,9 +143,20 @@
 const data = reactive({
   searchForm: {
     workOrderNo: "",
+    npsNo: "",
   },
 });
-const { searchForm } = toRefs(data);
+
+const isCompleted = row => {
+  const status = Number(row?.completionStatus);
+  return Number.isFinite(status) && status >= 100;
+};
+
+const canOperate = row => !row.endOrder && !isCompleted(row);
+
+const showStartReport = row => canOperate(row) && !row.actualStartTime;
+
+const showEndReport = row => canOperate(row) && !!row.actualStartTime;
 
 const goBack = () => {
   uni.navigateBack();
@@ -148,15 +171,18 @@
 const getList = () => {
   if (loading.value) return;
   loading.value = true;
-  
-  const params = { ...searchForm.value, ...page };
-  
+
+  const params = { ...data.searchForm, ...page };
+  if (filterMine.value) {
+    params.filterMine = true;
+  }
+
   productWorkOrderPage(params).then((res) => {
     loading.value = false;
     const records = res.data.records || [];
     tableData.value = page.current === 1 ? records : [...tableData.value, ...records];
     page.total = res.data.total;
-    
+
     if (tableData.value.length >= page.total) {
       loadStatus.value = 'nomore';
     } else {
@@ -182,13 +208,34 @@
   return Math.round(n);
 };
 
-const showTransferCard = (row) => {
-  transferCardRowData.value = row;
-  transferCardVisible.value = true;
+const handleStartWork = (row) => {
+  uni.showModal({
+    title: "鎻愮ず",
+    content: "纭寮�濮嬫姤宸ワ紵",
+    success: res => {
+      if (res.confirm) {
+        startWork({
+          productionOperationTaskId: row.id,
+          userId: userStore.id,
+        })
+          .then(() => {
+            uni.showToast({ title: "寮�濮嬫姤宸ユ垚鍔�" });
+            handleQuery();
+          })
+          .catch(() => {
+            uni.showToast({ title: "寮�濮嬫姤宸ュけ璐�", icon: "error" });
+          });
+      }
+    },
+  });
 };
 
-const openWorkOrderFiles = (row) => {
-  workOrderFilesRef.value?.openDialog(row);
+const goReport = (row) => {
+  uni.navigateTo({
+    url: `/pages/productionManagement/productionReport/index?orderRow=${encodeURIComponent(
+      JSON.stringify(row)
+    )}`,
+  });
 };
 
 onShow(() => {
@@ -228,37 +275,10 @@
   gap: 10px;
   padding: 12px 0;
   border-top: 1px solid #f5f5f5;
-  
-  :deep(.up-button) {
+
+  .action-btn {
     margin: 0;
     width: auto;
-  }
-}
-
-.qr-popup {
-  padding: 30px;
-  background-color: #fff;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  
-  .qr-title {
-    font-size: 18px;
-    font-weight: bold;
-    margin-bottom: 20px;
-  }
-  
-  .qr-box {
-    padding: 20px;
-    background-color: #fff;
-    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
-    border-radius: 8px;
-    margin-bottom: 15px;
-  }
-  
-  .qr-info {
-    font-size: 14px;
-    color: #666;
   }
 }
 
diff --git a/src/pages/works.vue b/src/pages/works.vue
index 9e89ddf..1b77038 100644
--- a/src/pages/works.vue
+++ b/src/pages/works.vue
@@ -306,7 +306,6 @@
 <script setup>
   import { ref, onMounted, nextTick, reactive, computed } from "vue";
   import { userLoginFacotryList } from "@/api/login";
-  import { getProductWorkOrderById } from "@/api/productionManagement/productionReporting";
   import DownloadProgressMask from "@/components/DownloadProgressMask.vue";
   import modal from "@/plugins/modal";
   import useUserStore from "@/store/modules/user";
@@ -343,10 +342,10 @@
       icon: "/static/images/icon/gongxuguanli.svg",
       label: "宸ュ簭绠$悊",
     },
-    {
-      icon: "/static/images/icon/bom.svg",
-      label: "BOM",
-    },
+    // {
+    //   icon: "/static/images/icon/bom.svg",
+    //   label: "BOM",
+    // },
     {
       icon: "/static/images/icon/gongyiluxian.svg",
       label: "宸ヨ壓璺嚎",
@@ -359,10 +358,10 @@
       icon: "/static/images/icon/kehudangan.svg",
       label: "瀹㈡埛妗f",
     },
-    {
-      icon: "/static/images/icon/xiaoshoubaojia.svg",
-      label: "閿�鍞姤浠�",
-    },
+    // {
+    //   icon: "/static/images/icon/xiaoshoubaojia.svg",
+    //   label: "閿�鍞姤浠�",
+    // },
     {
       icon: "/static/images/icon/xiaoshoutaizhang.svg",
       label: "閿�鍞彴璐�",
@@ -912,7 +911,9 @@
         });
         break;
       case "鐢熶骇鎶ュ伐":
-        getcode();
+        uni.navigateTo({
+          url: "/pages/productionManagement/workOrder/index",
+        });
         break;
       case "鎶ュ伐鍙拌处":
         uni.navigateTo({
@@ -1120,88 +1121,6 @@
         factoryList.value = [];
       });
   }
-  const getcode = async () => {
-    uni.scanCode({
-      success: async res => {
-        // 瑙f瀽浜岀淮鐮佸唴瀹�
-        const scanResult = res.result;
-        let orderRow = "";
-
-        // 鍒ゆ柇鎵弿缁撴灉鏄惁涓虹函鏁板瓧锛坕d锛�
-        const isNumericId = /^\d+$/.test(scanResult.trim());
-
-        if (isNumericId) {
-          // 濡傛灉鏄函鏁板瓧锛屾牴鎹� id 鑾峰彇宸ュ崟鏁版嵁
-          const workOrderId = scanResult.trim();
-          modal.loading("姝e湪鑾峰彇宸ュ崟淇℃伅...");
-          try {
-            const workRes = await getProductWorkOrderById({ id: workOrderId });
-            modal.closeLoading();
-
-            console.log("宸ュ崟鏌ヨ缁撴灉:", workRes);
-
-            if (workRes.code === 200 && workRes.data) {
-              // 鏂版帴鍙h繑鍥炵殑鏄崟涓璞★紝涓嶆槸鏁扮粍
-              const workData = workRes.data;
-              console.log("宸ュ崟鏁版嵁:", workData);
-
-              if (workData.endOrder === true) {
-                modal.msgError("璇ヨ鍗曞凡缁撴潫锛屾棤娉曟姤宸�");
-                return;
-              }
-
-              orderRow = JSON.stringify(workData);
-
-              console.log("鏋勯�犵殑orderRow:", orderRow);
-            } else {
-              modal.msgError("鏈壘鍒板搴旂殑宸ュ崟淇℃伅");
-              return;
-            }
-          } catch (error) {
-            modal.closeLoading();
-            console.error("鑾峰彇宸ュ崟淇℃伅澶辫触:", error);
-            modal.msgError("鑾峰彇宸ュ崟淇℃伅澶辫触: " + (error.message || "鏈煡閿欒"));
-            return;
-          }
-        } else {
-          // 濡傛灉涓嶆槸绾暟瀛楋紝灏濊瘯浠庢壂鐮佺粨鏋滀腑鎻愬彇orderRow鍙傛暟
-          try {
-            // 澶勭悊娣峰悎鏍煎紡: http://...?orderRow={...}
-            const orderRowStart = scanResult.indexOf("orderRow={");
-            if (orderRowStart !== -1) {
-              // 鎻愬彇浠巓rderRow={寮�濮嬬殑JSON鍐呭
-              const jsonPart = scanResult.substring(orderRowStart + 9); // 9鏄�"orderRow=".length
-              orderRow = jsonPart;
-            } else {
-              // 濡傛灉鐩存帴鏄疛SON瀛楃涓诧紝灏濊瘯瑙f瀽
-              orderRow = scanResult;
-            }
-          } catch (e) {
-            console.error(e, "瑙f瀽澶辫触====????=====");
-            orderRow = "";
-          }
-
-          // 楠岃瘉鏄惁涓烘湁鏁堢殑JSON
-          try {
-            JSON.parse(orderRow);
-          } catch (error) {
-            modal.msgError("璁㈠崟瑙f瀽澶辫触锛岃妫�鏌ヤ簩缁寸爜鏍煎紡");
-            return;
-          }
-        }
-        // 鎵爜鎴愬姛鍚庤烦杞埌鐢熶骇鎶ュ伐椤甸潰锛屽苟浼犻�抩rderRow鍙傛暟
-        uni.navigateTo({
-          url: `/pages/productionManagement/productionReport/index?orderRow=${orderRow}`,
-        });
-      },
-      fail: err => {
-        uni.showToast({
-          title: "鎵爜澶辫触",
-          icon: "none",
-        });
-      },
-    });
-  };
   const changeFactory = async arr => {
     show.value = false;
     const factoryId = factoryListTem.value[arr.indexs[0]].deptId;

--
Gitblit v1.9.3