From 35280c7f8c9aad04507edcb65c058c5724f7c078 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期六, 29 八月 2026 01:46:19 +0800
Subject: [PATCH] feat(mes): 报工表单只填写报工数量并展示可报工数量,工作台报工支持工艺参数填写

---
 src/views/mes/workbench/components/tabs/FeedbackTab.vue |  268 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 240 insertions(+), 28 deletions(-)

diff --git a/src/views/mes/workbench/components/tabs/FeedbackTab.vue b/src/views/mes/workbench/components/tabs/FeedbackTab.vue
index 367c822..86b6e25 100644
--- a/src/views/mes/workbench/components/tabs/FeedbackTab.vue
+++ b/src/views/mes/workbench/components/tabs/FeedbackTab.vue
@@ -1,8 +1,10 @@
 <script lang="ts" setup>
-import type { PendingTask } from '../../../types';
+import type { PendingTask } from '../../types';
 import type { FormType } from '../../../pro/feedback/data';
 
 import { computed, ref, watch } from 'vue';
+
+import dayjs from 'dayjs';
 
 import {
   MesAutoCodeRuleCode,
@@ -10,14 +12,15 @@
 } from '@vben/constants';
 import { useUserStore } from '@vben/stores';
 
-import { Button, message, Popconfirm } from 'ant-design-vue';
+import { Button, Input, message, Modal, Popconfirm } from 'ant-design-vue';
 
 import { useVbenForm } from '#/adapter/form';
 import { generateAutoCode } from '#/api/mes/md/autocode/record';
 import {
   approveFeedback,
-  createFeedback,
+  createFeedback, getBatchRequirements,
   getFeedback,
+  getFeedbackPage,
   rejectFeedback,
   submitFeedback,
   updateFeedback,
@@ -26,7 +29,14 @@
 import { $t } from '#/locales';
 
 import { useFormSchema } from '../../../pro/feedback/data';
-
+import {
+  loadParamDetails,
+  paramDetails,
+} from '../../../pro/feedback/param-state';
+import BatchInputDialog from '../../../pro/feedback/modules/batch-input-dialog.vue';
+const batchDialogRef = ref<InstanceType<typeof BatchInputDialog>>();
+const batchActionType = ref<'' | 'submit' | 'approve'>('');
+const pendingSubmitMode = ref<'saveAndSubmit' | 'submit'>('submit');
 defineOptions({ name: 'WorkbenchFeedbackTab' });
 
 const props = defineProps<{
@@ -67,26 +77,29 @@
   wrapperClass: 'grid-cols-3',
 });
 
-/** 鏍规嵁 checkFlag 瀵归綈鏁伴噺 */
+/** 鎻愪氦鍓嶅榻愭暟閲忥細鎶ュ伐鍙~鍐欐姤宸ユ暟閲忥紝鍚堟牸/涓嶈壇/搴熷搧鏁伴噺鐢辫川妫�纭畾锛屾姤宸ョ幆鑺備笉閲囬泦 */
 function alignQuantity(data: any) {
-  if (data.checkFlag) {
-    data.uncheckQuantity = data.feedbackQuantity;
-    data.qualifiedQuantity = 0;
-    data.unqualifiedQuantity = 0;
-    data.laborScrapQuantity = 0;
-    data.materialScrapQuantity = 0;
-    data.otherScrapQuantity = 0;
-  } else {
-    data.feedbackQuantity =
-      (data.qualifiedQuantity || 0) + (data.unqualifiedQuantity || 0);
-    data.uncheckQuantity = 0;
-  }
+  data.uncheckQuantity = data.checkFlag ? data.feedbackQuantity : 0;
+  delete data.qualifiedQuantity;
+  delete data.unqualifiedQuantity;
+  delete data.laborScrapQuantity;
+  delete data.materialScrapQuantity;
+  delete data.otherScrapQuantity;
 }
 
 async function getAlignedData() {
   const data = (await formApi.getValues()) as any;
+  syncParamValues(data);
   alignQuantity(data);
   return data;
+}
+
+/** 鍚屾宸ヨ壓鍙傛暟鍊煎埌鎶ュ伐鏁版嵁锛堜笌鎻愪氦鏁版嵁涓�鍚屽彂閫佺粰鍚庣锛� */
+function syncParamValues(data: any) {
+  data.paramValues = paramDetails.value.map((detail) => ({
+    detailId: detail.id,
+    value: detail.paramValue,
+  }));
 }
 
 /** 鍔犺浇 checkFlag */
@@ -111,11 +124,13 @@
 
   const code = await generateAutoCode(MesAutoCodeRuleCode.PRO_FEEDBACK_CODE);
   const checkFlag = await resolveCheckFlag(task.routeId, task.processId);
+  // 鍔犺浇浠诲姟缁戝畾鐨勫伐鑹哄弬鏁帮紙蹇呭~鍙傛暟鏍¢獙 + 鍙傛暟鍊煎洖鏄撅級
+  await loadParamDetails(task.id);
 
   await formApi.setValues({
     code,
     type: 1,
-    feedbackTime: Date.now(),
+    feedbackTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
     feedbackUserId: userStore.userInfo?.id,
     taskId: task.id,
     workOrderId: task.workOrderId,
@@ -127,10 +142,11 @@
     itemName: task.itemName,
     itemSpecification: task.itemSpecification,
     unitMeasureName: task.unitMeasureName,
+    reportableQuantity: task.reportableQuantity,
     scheduledQuantity: task.quantity,
+    feedbackApprove: task.feedbackApprove,
     checkFlag,
   });
-
   originalSnapshot.value = JSON.stringify(await getAlignedData());
 }
 
@@ -140,6 +156,7 @@
   if (!valid) return;
 
   const data = await getAlignedData();
+  const code = data.code as string;
 
   if (formType.value === 'create') {
     const id = await createFeedback(data);
@@ -148,12 +165,78 @@
     formType.value = 'update';
     formApi.setState({ schema: useFormSchema(formType.value, formApi) });
     await formApi.setFieldValue('id', id);
-    message.success($t('common.createSuccess'));
   } else {
     await updateFeedback(data);
-    message.success($t('common.updateSuccess'));
   }
   originalSnapshot.value = JSON.stringify(data);
+
+  // 鏄剧ず鏄剧溂鐨勬垚鍔熸彁绀�
+  Modal.success({
+    title: '淇濆瓨鎴愬姛',
+    content: `鎶ュ伐鍗� ${code} 宸蹭繚瀛榒,
+    centered: true,
+  });
+
+  // 閲嶇疆琛ㄥ崟涓烘柊寤烘ā寮忥紝閲嶆柊鐢熸垚鎶ヨ鍗曞彿
+  if (props.task) {
+    await resetForTask(props.task);
+  }
+
+  emit('reported');
+}
+
+/** 淇濆瓨骞舵彁浜わ紙鍏堜繚瀛橈紝鍐嶆煡璇㈠苟鎻愪氦锛� */
+async function handleSaveAndSubmit() {
+  const { valid } = await formApi.validate();
+  if (!valid) return;
+
+  const data = await getAlignedData();
+  const code = data.code as string;
+
+  // 1. 鍏堜繚瀛�
+  if (formType.value === 'create') {
+    const id = await createFeedback(data);
+    feedbackId.value = id;
+    feedbackStatus.value = MesProFeedbackStatusEnum.PREPARE;
+    formType.value = 'update';
+    formApi.setState({ schema: useFormSchema(formType.value, formApi) });
+    await formApi.setFieldValue('id', id);
+  } else {
+    await updateFeedback(data);
+  }
+  originalSnapshot.value = JSON.stringify(data);
+
+  // 2. 鏌ヨ鎶ュ伐璁板綍锛屽尮閰嶈鎶ュ伐鍗曞彿
+  const pageResult = await getFeedbackPage({ code, pageNo: 1, pageSize: 1 });
+  const record = pageResult.list?.[0];
+
+  // 3. 妫�鏌ユ槸鍚﹀彲鎻愪氦锛堣崏绋跨姸鎬侊級
+  if (!record || record.status !== MesProFeedbackStatusEnum.PREPARE) {
+    message.warning('淇濆瓨鎴愬姛锛屼絾褰撳墠鎶ュ伐鍗曠姸鎬佷笉鍙彁浜�');
+    emit('reported');
+    return;
+  }
+
+  pendingSubmitMode.value = 'saveAndSubmit';
+
+  // 4. 璋冪敤鎻愪氦鎺ュ彛
+  const isDone = await handleOnSubmit(feedbackId.value!,props.task?.feedbackApprove);
+  if (!isDone) return;
+
+  feedbackId.value = record.id;
+  feedbackStatus.value = record.status;
+
+  // 鏄剧ず鏄剧溂鐨勬垚鍔熸彁绀�
+  Modal.success({
+    title: '淇濆瓨骞舵彁浜ゆ垚鍔�',
+    content: `鎶ュ伐鍗� ${code} 宸叉彁浜,
+    centered: true,
+  });
+
+  // 閲嶇疆琛ㄥ崟涓烘柊寤烘ā寮忥紝閲嶆柊鐢熸垚鎶ヨ鍗曞彿
+  if (props.task) {
+    await resetForTask(props.task);
+  }
   emit('reported');
 }
 
@@ -167,8 +250,12 @@
     await updateFeedback(data);
     originalSnapshot.value = JSON.stringify(data);
   }
-  await submitFeedback(feedbackId.value!);
-  message.success('鎶ヨ鍗曞凡鎻愪氦');
+
+  pendingSubmitMode.value = 'submit';
+  const isDone = await handleOnSubmit(feedbackId.value!,props.task?.feedbackApprove);
+  if (!isDone) return;
+
+  message.success('鎶ュ伐鍗曞凡鎻愪氦');
   // 閲嶇疆琛ㄥ崟涓烘柊寤烘ā寮�
   if (props.task) {
     await resetForTask(props.task);
@@ -176,10 +263,53 @@
   emit('reported');
 }
 
+
+/** 鎻愪氦鏂规硶 */
+async function handleOnSubmit(id:any,feedbackRate:any): Promise<boolean> {
+  if (feedbackRate&&feedbackRate==true){
+    await submitFeedback({ id: feedbackId.value! });
+    return true;
+  }
+
+  const checkResult = await getBatchRequirements(id);
+  if (checkResult?.needBatchInput) {
+    batchActionType.value = 'submit';
+    batchDialogRef.value?.open({ checkResult });
+    return false;
+  } else {
+    await submitFeedback({ id: feedbackId.value! });
+    return true;
+  }
+}
+
+/** 鎵规纭鍥炶皟 */
+async function handleBatchConfirm(batchData: Record<string, unknown>) {
+  if (batchActionType.value === 'submit') {
+    await submitFeedback({ id: feedbackId.value!, ...batchData });
+    
+    if (pendingSubmitMode.value === 'saveAndSubmit') {
+      const data = await getAlignedData();
+      const code = data.code as string;
+      Modal.success({
+        title: '淇濆瓨骞舵彁浜ゆ垚鍔�',
+        content: `鎶ュ伐鍗� ${code} 宸叉彁浜,
+        centered: true,
+      });
+    } else {
+      message.success('鎶ュ伐鍗曞凡鎻愪氦');
+    }
+
+    if (props.task) {
+      await resetForTask(props.task);
+    }
+    emit('reported');
+  }
+}
+
 /** 瀹℃壒閫氳繃 */
 async function handleApprove() {
   if (!feedbackId.value) return;
-  const finished = await approveFeedback(feedbackId.value);
+  const finished = await approveFeedback({ id: feedbackId.value });
   message.success(
     finished ? '鎶ヨ鍗曞凡瀹℃壒瀹屾垚' : '鎶ュ伐鎴愬姛锛岃绛夊緟璐ㄩ噺妫�楠屽畬鎴愶紒',
   );
@@ -208,16 +338,18 @@
   formType.value = 'update';
   formApi.setState({ schema: useFormSchema(formType.value, formApi) });
   const checkFlag = await resolveCheckFlag(data.routeId, data.processId);
+  await loadParamDetails(data.taskId);
   await formApi.setValues({ ...data, checkFlag });
   originalSnapshot.value = JSON.stringify(await getAlignedData());
 }
 
-// 鐩戝惉浠诲姟鍙樻洿
+// 鐩戝惉浠诲姟鍙樻洿锛氫换鍔″璞″彉鍖栵紙閫夋嫨浠诲姟 / 鍒楄〃鍒锋柊鍚庡悓姝ョ殑鏈�鏂版暟鎹級鏃堕噸缃〃鍗曪紝
+// 纭繚"鍙姤宸ユ暟閲�"绛変换鍔℃淳鐢熷瓧娈靛缁堝睍绀烘渶鏂板��
 watch(
   () => props.task,
-  (task) => {
-    if (task) {
-      resetForTask(task);
+  () => {
+    if (props.task) {
+      resetForTask(props.task);
     }
   },
   { immediate: true },
@@ -229,6 +361,7 @@
 
 <template>
   <div class="feedback-tab">
+    <BatchInputDialog ref="batchDialogRef" @confirm="handleBatchConfirm" />
     <div v-if="!task" class="feedback-tab__empty">
       璇蜂粠宸︿晶宸ュ崟鍒楄〃閫夋嫨涓�鏉′换鍔�
     </div>
@@ -244,6 +377,34 @@
 
       <Form class="feedback-tab__form" />
 
+      <!-- 宸ヨ壓鍙傛暟锛堜换鍔$粦瀹氬弬鏁版椂灞曠ず锛屽繀濉弬鏁版湭濉細琚悗绔嫤鎴級 -->
+      <div v-if="paramDetails.length" class="feedback-tab__params">
+        <div class="feedback-tab__params-title">宸ヨ壓鍙傛暟</div>
+        <div class="feedback-tab__params-grid">
+          <div
+            v-for="detail in paramDetails"
+            :key="detail.id"
+            class="feedback-tab__params-item"
+          >
+            <span class="feedback-tab__params-label">
+              <span v-if="detail.required" class="feedback-tab__params-required"
+                >*&nbsp;</span
+              >
+              {{ detail.paramName || detail.paramCode
+              }}{{
+                detail.unitMeasureName ? `锛�${detail.unitMeasureName}锛塦 : ''
+              }}
+            </span>
+            <Input
+              v-model:value="detail.paramValue"
+              :disabled="!isEditable"
+              placeholder="璇疯緭鍏ュ弬鏁板��"
+              class="feedback-tab__params-input"
+            />
+          </div>
+        </div>
+      </div>
+
       <div class="feedback-tab__actions">
         <Button
           v-if="isEditable"
@@ -251,6 +412,13 @@
           @click="handleSave"
         >
           淇濆瓨
+        </Button>
+        <Button
+          v-if="isEditable"
+          type="primary"
+          @click="handleSaveAndSubmit"
+        >
+          淇濆瓨骞舵彁浜�
         </Button>
         <Popconfirm
           v-if="canSubmit"
@@ -328,4 +496,48 @@
   border-top: 1px solid #f0f0f0;
   margin-top: 16px;
 }
+
+.feedback-tab__params {
+  margin-top: 16px;
+  padding: 14px 16px;
+  border: 1px solid #f0f0f0;
+  border-radius: 8px;
+  background: #fafbfc;
+}
+
+.feedback-tab__params-title {
+  margin-bottom: 12px;
+  font-size: 15px;
+  font-weight: 600;
+  color: #1a1a1a;
+}
+
+.feedback-tab__params-grid {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  gap: 12px 20px;
+}
+
+.feedback-tab__params-item {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.feedback-tab__params-label {
+  flex-shrink: 0;
+  width: 176px;
+  text-align: right;
+  font-size: 14px;
+  color: #595959;
+}
+
+.feedback-tab__params-required {
+  color: #ff4d4f;
+}
+
+.feedback-tab__params-input {
+  flex: 1;
+  min-width: 0;
+}
 </style>

--
Gitblit v1.9.3