From 173855b299e89930b5ea2ff9a9295fde9d0f55b5 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期六, 07 十一月 2026 08:51:43 +0800
Subject: [PATCH] feat: 同步质检、生产、销售、财务与人事前端功能

---
 src/views/mes/pro/feedback/modules/form.vue |  175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 171 insertions(+), 4 deletions(-)

diff --git a/src/views/mes/pro/feedback/modules/form.vue b/src/views/mes/pro/feedback/modules/form.vue
index 0b5594d..c2ee010 100644
--- a/src/views/mes/pro/feedback/modules/form.vue
+++ b/src/views/mes/pro/feedback/modules/form.vue
@@ -1,7 +1,9 @@
 <script lang="ts" setup>
-import type { FormType } from '../data';
+import type { FormType, FeedbackFormHooks } from '../data';
 
 import type { MesProFeedbackApi } from '#/api/mes/pro/feedback';
+import type { MesProTaskApi } from '#/api/mes/pro/task';
+import type { MesProFeedbackWagePreviewApi } from '#/api/mes/pro/wage';
 
 import { computed, ref } from 'vue';
 
@@ -11,7 +13,7 @@
 import { MesAutoCodeRuleCode, MesProFeedbackStatusEnum } from '@vben/constants';
 import { useUserStore } from '@vben/stores';
 
-import { Button, Input, message, Popconfirm, Tabs } from 'ant-design-vue';
+import { Alert, Button, Input, message, Popconfirm, Tabs } from 'ant-design-vue';
 
 import { useVbenForm } from '#/adapter/form';
 import { generateAutoCode } from '#/api/mes/md/autocode/record';
@@ -25,6 +27,7 @@
   updateFeedback,
 } from '#/api/mes/pro/feedback';
 import { getWorkOrder } from '#/api/mes/pro/workorder';
+import { previewFeedbackWage } from '#/api/mes/pro/wage';
 import { $t } from '#/locales';
 
 import { useFormSchema } from '../data';
@@ -32,6 +35,7 @@
 import BatchInputDialog from './batch-input-dialog.vue';
 import ItemConsumeList from './item-consume-list.vue';
 import ProductProduceList from './product-produce-list.vue';
+import WorktimeAuxInput from './worktime-aux-input.vue';
 
 const emit = defineEmits(['success']);
 const formType = ref<FormType>('create');
@@ -40,6 +44,65 @@
 const userStore = useUserStore();
 const subTabsName = ref('itemConsume');
 const originalSnapshot = ref(''); // 琛ㄥ崟鍘熷鏁版嵁蹇収锛岀敤浜� submit 鏃惰烦杩囨湭鍙樻洿鐨勪繚瀛樿姹�
+/** 褰撳墠閫変腑鐨勭敓浜т换鍔★紝鐢ㄤ簬杈呭姪宸ユ椂缁勪欢鎸夊伐搴�/鏈哄彴鍔犺浇閰嶇疆 */
+const currentTask = ref<Partial<MesProTaskApi.Task>>();
+const productionLength = ref<number>();
+const workHours = ref<number>();
+const auxRef = ref<InstanceType<typeof WorktimeAuxInput>>();
+/** 鍚庣宸ヨ祫璇曠畻缁撴灉锛堝惈杈呭姪宸ヨ祫銆佽川閲忚皟鏁达級 */
+const wagePreview = ref<MesProFeedbackWagePreviewApi.PreviewResp>();
+let previewTimer: ReturnType<typeof setTimeout> | undefined;
+
+/** 璋冪敤鍚庣璇曠畻宸ヨ祫锛氭湭鎸囧畾璁惧鏃舵寜宸ュ簭榛樿鍗曚环锛屾寚瀹氳澶囨寜璁惧缁村害瑙勫垯 */
+async function refreshWagePreview() {
+  if (!isEditable.value) {
+    wagePreview.value = undefined;
+    return;
+  }
+  const values = (await formApi.getValues()) as MesProFeedbackApi.Feedback;
+  if (!values.taskId) {
+    wagePreview.value = undefined;
+    return;
+  }
+  try {
+    wagePreview.value = await previewFeedbackWage({
+      taskId: values.taskId,
+      machineryId: values.machineryId,
+      workHours: values.workHours,
+      feedbackQuantity: values.feedbackQuantity,
+      productionLength: values.productionLength,
+      auxList: auxRef.value?.getAuxList(),
+    });
+  } catch {
+    // 璇曠畻澶辫触涓嶉樆鏂綍鍏ワ紝淇濆瓨鏃跺悗绔細缁欏嚭绮剧‘鏍¢獙鎻愮ず
+    wagePreview.value = undefined;
+  }
+}
+
+/** 闃叉姈瑙﹀彂宸ヨ祫璇曠畻锛岄伩鍏嶈繛缁綍鍏ユ椂棰戠箒璇锋眰 */
+function schedulePreview() {
+  if (previewTimer) {
+    clearTimeout(previewTimer);
+  }
+  previewTimer = setTimeout(() => {
+    refreshWagePreview();
+  }, 500);
+}
+
+const formHooks: FeedbackFormHooks = {
+  onTaskChange: (task) => {
+    currentTask.value = task;
+    productionLength.value = undefined;
+    workHours.value = undefined;
+  },
+  onProductionLengthChange: (value) => {
+    productionLength.value = value;
+  },
+  onWorkHoursChange: (value) => {
+    workHours.value = value;
+  },
+  onPreviewWage: () => schedulePreview(),
+};
 
 const isEditable = computed(() =>
   ['create', 'submit', 'update'].includes(formType.value),
@@ -101,6 +164,10 @@
   const data = (await formApi.getValues()) as MesProFeedbackApi.Feedback;
   syncParamValues(data);
   alignQuantity(data);
+  // 杈呭姪椤规鏁扮敱宸ユ椂缁勪欢缁存姢锛涙爣鍑嗗伐鏃朵互鍚庣淇濆瓨鏃堕噸绠椾负鍑�
+  if (isEditable.value && auxRef.value) {
+    data.auxList = auxRef.value.getAuxList();
+  }
   return data;
 }
 
@@ -124,7 +191,9 @@
         status: MesProFeedbackStatusEnum.PREPARE,
       };
       formType.value = 'update';
-      formApi.setState({ schema: useFormSchema(formType.value, formApi) });
+      formApi.setState({
+        schema: useFormSchema(formType.value, formApi, formHooks),
+      });
       await formApi.setFieldValue('id', id);
       message.success($t('common.createSuccess'));
     } else {
@@ -305,13 +374,23 @@
       subTabsName.value = 'itemConsume';
       originalSnapshot.value = '';
       paramDetails.value = [];
+      currentTask.value = undefined;
+      productionLength.value = undefined;
+      workHours.value = undefined;
+      wagePreview.value = undefined;
+      if (previewTimer) {
+        clearTimeout(previewTimer);
+        previewTimer = undefined;
+      }
       return;
     }
     // 鍔犺浇鏁版嵁
     const data = modalApi.getData<{ formType: FormType; id?: number; showSubmitButton?: boolean }>();
     formType.value = data.formType;
     showSubmitButton.value = data.showSubmitButton !== false;
-    formApi.setState({ schema: useFormSchema(formType.value, formApi) });
+    formApi.setState({
+        schema: useFormSchema(formType.value, formApi, formHooks),
+      });
     // 瀹℃壒/璇︽儏鏁磋〃绂佺敤锛岄伩鍏嶅鏍镐汉璇敼鏈彁浜ょ殑瀛楁
     formApi.setDisabled(
       formType.value === 'approve' || formType.value === 'detail',
@@ -342,8 +421,17 @@
       await loadParamDetails(formData.value.taskId);
       // 璁剧疆鍒� values
       await formApi.setValues({ ...formData.value });
+      // 鍚屾宸ユ椂缁勪欢鎵�闇�鐨勪笂涓嬫枃锛岀紪杈戞椂鎸夊凡鏈夋鏁板洖鏄�
+      currentTask.value = {
+        id: formData.value.taskId,
+        processId: formData.value.processId,
+        workstationId: formData.value.workstationId,
+      };
+      productionLength.value = formData.value.productionLength;
+      workHours.value = formData.value.workHours;
       // 璁板綍鍒濆蹇収锛堝惈鏁伴噺瀵归綈缁撴灉锛夛紝submit 鏃剁敤浜庤烦杩囨棤鍙樻洿鐨勪繚瀛樿姹�
       originalSnapshot.value = JSON.stringify(await getAlignedData());
+      schedulePreview();
     } finally {
       modalApi.unlock();
     }
@@ -353,7 +441,86 @@
 
 <template>
   <Modal :title="getTitle" class="w-3/5">
+    <Alert
+      v-if="formData?.standardWarnFlag && formData?.standardWarnMessage"
+      class="mx-4 mb-3"
+      :description="formData.standardWarnMessage"
+      message="宸ユ椂瓒呭嚭鑰冩牳闃堝��"
+      show-icon
+      type="warning"
+    />
     <Form class="mx-4" />
+    <div
+      v-if="isEditable && wagePreview"
+      class="mx-4 mt-4 rounded border border-gray-200 p-4"
+    >
+      <div class="mb-2 flex items-center justify-between">
+        <div class="font-medium">
+          宸ヨ祫璇曠畻
+          <span class="ml-2 text-xs font-normal text-gray-400">
+            鍚緟鍔╁伐璧勪笌璐ㄩ噺璋冩暣锛屼繚瀛�/瀹℃壒鏃朵互绯荤粺閲嶇畻缁撴灉涓哄噯
+          </span>
+        </div>
+        <Button size="small" @click="refreshWagePreview">鍒锋柊璇曠畻</Button>
+      </div>
+      <div class="flex flex-wrap gap-x-6 gap-y-1 text-sm">
+        <span>
+          璁¤柂鏂瑰紡锛�<b>{{ wagePreview.billingType === 1 ? '璁℃椂' : '璁′欢' }}</b>
+        </span>
+        <span>
+          鍗曚环锛�<b>{{ wagePreview.wageRate ?? 0 }}</b>
+          {{ wagePreview.billingType === 1 ? '鍏�/灏忔椂' : '鍏�/浠�' }}
+        </span>
+        <span v-if="wagePreview.billingType === 1">
+          宸ユ椂锛�<b>{{ wagePreview.workHours ?? 0 }}</b> 灏忔椂
+        </span>
+        <span v-else>
+          璁′欢鏁伴噺锛�<b>{{ wagePreview.pieceQuantity ?? 0 }}</b>
+        </span>
+        <span>涓诲伐璧勶細<b>{{ wagePreview.mainWage ?? 0 }}</b> 鍏�</span>
+        <span>
+          杈呭姪宸ヨ祫锛�<b>{{ wagePreview.auxWage ?? 0 }}</b> 鍏�
+          <span class="text-xs text-gray-400">
+            锛坽{ wagePreview.auxPaidHours ?? 0 }} 灏忔椂锛�
+          </span>
+        </span>
+        <span v-if="wagePreview.quality?.passRate !== undefined">
+          鍚堟牸鐜囷細<b>{{ wagePreview.quality?.passRate }}</b>%
+        </span>
+        <span>
+          鏈�缁堝伐璧勶細<b class="text-blue-600">{{ wagePreview.finalWage ?? 0 }}</b> 鍏�
+        </span>
+      </div>
+      <div
+        v-if="wagePreview.fields?.length"
+        class="mt-2 text-xs text-gray-500"
+      >
+        宸ヨ祫瀛楁锛�
+        <span v-for="(field, index) in wagePreview.fields" :key="field.code">
+          {{ index > 0 ? '锛�' : '' }}{{ field.name }}={{ field.value ?? '-' }}
+          <template v-if="field.amount !== undefined">
+            锛坽{ field.amount }} 鍏冿級
+          </template>
+        </span>
+      </div>
+      <Alert
+        v-if="wagePreview.warnings?.length"
+        class="mt-2"
+        :message="wagePreview.warnings.join('锛�')"
+        show-icon
+        type="warning"
+      />
+    </div>
+    <WorktimeAuxInput
+      v-if="isEditable && (currentTask?.id || formData?.taskId)"
+      ref="auxRef"
+      :initial-aux-list="formData?.auxList"
+      :process-id="currentTask?.processId ?? formData?.processId"
+      :production-length="productionLength ?? formData?.productionLength"
+      :task-id="currentTask?.id ?? formData?.taskId"
+      :work-hours="workHours ?? formData?.workHours"
+      :workstation-id="currentTask?.workstationId ?? formData?.workstationId"
+    />
     <div v-if="paramDetails.length" class="mx-4 mt-4 rounded border border-gray-200 p-4">
       <div class="mb-3 font-medium">宸ヨ壓鍙傛暟</div>
       <div class="grid grid-cols-2 gap-3">

--
Gitblit v1.9.3