Преглед изворни кода

feat(mobile-oa-h5): integrate sample payment panel into protocol form

Validate and persist samplePayments on cell_storage protocol save.

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu пре 4 недеља
родитељ
комит
a7b8560f5f
1 измењених фајлова са 52 додато и 0 уклоњено
  1. 52 0
      mobile-oa-h5/src/views/market/MarketModuleForm.vue

+ 52 - 0
mobile-oa-h5/src/views/market/MarketModuleForm.vue

@@ -25,6 +25,14 @@
         @field-change="handleFieldChange"
       />
 
+      <ProtocolSamplePaymentPanel
+        v-if="context.module === 'protocol' && formData.source === 'cell_storage'"
+        v-model="formData.samplePayments"
+        :samples="formData.samples || []"
+        :disabled="formBusy"
+        @update:model-value="onSamplePaymentsChange"
+      />
+
       <section v-if="context.module === 'freight' && action !== 'edit'" class="market-form-section">
         <h2>关联样本</h2>
         <van-search
@@ -82,10 +90,18 @@ import {
 } from '../../market/action-policy.js'
 import {
   buildMarketActionPayload,
+  mergeProtocolSamplePayments,
   pickConfiguredPayload,
   sanitizeMarketPayload,
   validateRequiredFields
 } from '../../market/form-payload.js'
+import {
+  protocolTotalMismatchHint,
+  sampleScheduleDuesMismatchHint,
+  sampleScheduleRequiredFieldsHint,
+  sumSampleContractAmounts
+} from '../../market/protocol-sample-payment.js'
+import ProtocolSamplePaymentPanel from '../../market/components/ProtocolSamplePaymentPanel.vue'
 import { appendMarketAttachment } from '../../market/attachment-presenter.js'
 import { marketErrorMessage } from '../../market/market-error.js'
 import { canLeaveMarketForm, createAsyncGenerationGuard } from '../../market/form-state.js'
@@ -172,6 +188,11 @@ function setSectionValue(section, value) {
   dirty.value = true
 }
 
+function onSamplePaymentsChange(value) {
+  formData.value = { ...formData.value, samplePayments: value }
+  dirty.value = true
+}
+
 async function handleFieldChange({ section, field, value, index }) {
   if (context.value.module !== 'protocol') return
   if (section.key === 'samples' && field.key === 'sampleCodeId') {
@@ -279,6 +300,7 @@ function initialForm(detail) {
         customer: {},
         collection: {},
         samples: [],
+        samplePayments: [],
         payment: {},
         attachments: {},
         confirm: { confirmed: false }
@@ -293,6 +315,7 @@ function initialForm(detail) {
       customer: detail.customer || {},
       collection: detail.collection || {},
       samples: detail.samples || [],
+      samplePayments: detail.samplePayments || [],
       payment: detail.payment || {},
       attachments: detail.attachments || {},
       confirm: { confirmed: false }
@@ -418,6 +441,10 @@ function buildPayload() {
       ? { ...fields, items: selectedItems() }
       : fields
   }
+  if (context.value.module === 'protocol') {
+    const fields = pickConfiguredPayload(visibleSections.value, formData.value)
+    return mergeProtocolSamplePayments(fields, formData.value.samplePayments)
+  }
   return pickConfiguredPayload(visibleSections.value, formData.value)
 }
 
@@ -428,6 +455,31 @@ async function submit() {
     showToast(validationMessage)
     return
   }
+  if (context.value.module === 'protocol' && formData.value.source === 'cell_storage') {
+    for (const pay of formData.value.samplePayments || []) {
+      const requiredHint = sampleScheduleRequiredFieldsHint(pay)
+      if (requiredHint) {
+        showToast(requiredHint)
+        return
+      }
+      const mismatchHint = sampleScheduleDuesMismatchHint(pay)
+      if (mismatchHint) {
+        showToast(mismatchHint)
+        return
+      }
+    }
+    const totalHint = protocolTotalMismatchHint(
+      formData.value.protocolTotalAmount,
+      sumSampleContractAmounts(formData.value.samplePayments || [])
+    )
+    if (totalHint) {
+      try {
+        await showConfirmDialog({ title: '提示', message: totalHint })
+      } catch {
+        return
+      }
+    }
+  }
   const payload = buildMarketActionPayload(
     context.value.module,
     action.value,