From b973bcee308e99b5fd8a69640f11069e810346f4 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期二, 27 一月 2026 16:37:55 +0800
Subject: [PATCH] 采购台账重构

---
 src/pages/sales/salesAccount/detail.vue | 1804 +++++++++++++++++++++++++++++----------------------------
 1 files changed, 927 insertions(+), 877 deletions(-)

diff --git a/src/pages/sales/salesAccount/detail.vue b/src/pages/sales/salesAccount/detail.vue
index 56c92a9..6e7f811 100644
--- a/src/pages/sales/salesAccount/detail.vue
+++ b/src/pages/sales/salesAccount/detail.vue
@@ -1,896 +1,946 @@
 <template>
   <view class="account-detail">
-    <!-- 椤堕儴鏍囬鏍� -->
-    <view class="header">
-      <up-icon name="arrow-left" size="20" color="#333" @click="goBack" />
-      <text class="title">鍙拌处璇︽儏</text>
-    </view>
-
-         <!-- 琛ㄥ崟鍖哄煙 -->
-		<van-form @submit="onSubmit" label-width="110px" input-align="right" style="margin-top: 10px" error-message-align="right" scroll-to-error scroll-to-error-position="center">
-			<van-field label="閿�鍞悎鍚屽彿" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="鑷姩鐢熸垚" disabled>
-			</van-field>
-			<van-field
-				v-model="form.salesman"
-				is-link
-				readonly
-				name="salesman"
-				label="涓氬姟鍛�"
-				required
-				placeholder="鐐瑰嚮閫夋嫨涓氬姟鍛�"
-				:rules="[{ required: true, message: '璇烽�夋嫨涓氬姟鍛�' }]"
-				@click="showPicker = true"
-			/>
-			<van-field label="瀹㈡埛鍚堝悓鍙�" name="customerContractNo" borderBottom="true"
-								 v-model="form.customerContractNo" required
-								 placeholder="璇疯緭鍏ュ鎴峰悎鍚屽彿" :rules="[{ required: true, message: '瀹㈡埛鍚堝悓鍙蜂笉鑳戒负绌�' }]">
-			</van-field>
-			<van-field
-				v-model="form.customerName"
-				is-link
-				readonly
-				required
-				name="customerName"
-				label="瀹㈡埛鍚嶇О"
-				placeholder="鐐瑰嚮閫夋嫨瀹㈡埛"
-				:rules="[{ required: true, message: '璇烽�夋嫨瀹㈡埛' }]"
-				@click="showCustomerPicker = true"
-			/>
-			<van-field label="椤圭洰鍚嶇О" name="projectName" borderBottom="true" v-model="form.projectName" placeholder="璇疯緭鍏ラ」鐩悕绉�" :rules="[{ required: true, message: '椤圭洰鍚嶇О涓嶈兘涓虹┖' }]" required>
-			</van-field>
-			<van-field
-				v-model="form.executionDate"
-				is-link
-				readonly
-				required
-				name="executionDate"
-				label="绛捐鏃ユ湡"
-				placeholder="鐐瑰嚮閫夋嫨鏃堕棿"
-				:rules="[{ required: true, message: '绛捐鏃ユ湡涓嶈兘涓虹┖' }]"
-				@click="showDatePicker = true"
-			/>
-			<van-popup v-model:show="showDatePicker" destroy-on-close position="bottom">
-				<van-date-picker
-					v-model="pickerDateValue"
-					@confirm="onDateConfirm"
-					@cancel="showDatePicker = false"
-				/>
-			</van-popup>
-			<van-field label="浠樻鏂瑰紡" name="paymentMethod" borderBottom="true" v-model="form.paymentMethod" placeholder="璇疯緭鍏ヤ粯娆炬柟寮�">
-			</van-field>
-			<van-field label="褰曞叆浜�" name="entryPersonName" borderBottom="true" v-model="form.entryPersonName" placeholder="璇疯緭鍏�" readonly>
-			</van-field>
-			<van-field label="褰曞叆鏃ユ湡" name="entryDate" borderBottom="true" v-model="form.entryDate" placeholder="璇疯緭鍏�" readonly>
-			</van-field>
-			<van-popup v-model:show="showPicker" destroy-on-close position="bottom">
-				<van-picker
-					:columns="userList"
-					v-model="pickerValue"
-					@confirm="onConfirm"
-					@cancel="showPicker = false"
-				/>
-			</van-popup>
-			<van-popup v-model:show="showCustomerPicker" destroy-on-close position="bottom">
-				<van-picker
-					:columns="customerOption"
-					v-model="pickerCustomerValue"
-					@confirm="onCustomerConfirm"
-					@cancel="showCustomerPicker = false"
-				/>
-			</van-popup>
-			
-			<!-- 浜у搧澶х被閫夋嫨鍣� -->
-			<van-popup v-model:show="showCategoryPicker" destroy-on-close position="bottom">
-				<!-- 澶撮儴鎸夐挳鍖哄煙 -->
-				<view class="popup-header">
-					<view @click="showCategoryPicker = false" class="cancelButton">鍙栨秷</view>
-					<view @click="confirmCategorySelection" class="confirmButton">纭畾</view>
-				</view>
-				<up-tree
-					:data="productOptions"
-					:props="defaultProps"
-					show-checkbox
-					default-expand-all
-					check-strictly
-					@check-change="onCategoryConfirm"
-				/>
-			</van-popup>
-			
-			<!-- 瑙勬牸鍨嬪彿閫夋嫨鍣� -->
-			<van-popup v-model:show="showSpecificationPicker" destroy-on-close position="bottom">
-				<van-picker
-					:columns="modelOptions"
-					v-model="pickerSpecificationValue"
-					@confirm="onSpecificationConfirm"
-					@cancel="showSpecificationPicker = false"
-				/>
-			</van-popup>
-			
-			<!-- 绋庣巼閫夋嫨鍣� -->
-			<van-popup v-model:show="showTaxRatePicker" destroy-on-close position="bottom">
-				<van-picker
-					:columns="taxRateOptions"
-					v-model="pickerTaxRateValue"
-					@confirm="onTaxRateConfirm"
-					@cancel="showTaxRatePicker = false"
-				/>
-			</van-popup>
-			
-			<!-- 鍙戠エ绫诲瀷閫夋嫨鍣� -->
-			<van-popup v-model:show="showInvoiceTypePicker" destroy-on-close position="bottom">
-				<van-picker
-					:columns="invoiceTypeOptions"
-					v-model="pickerInvoiceTypeValue"
-					@confirm="onInvoiceTypeConfirm"
-					@cancel="showInvoiceTypePicker = false"
-				/>
-			</van-popup>
-			<!-- 浜у搧淇℃伅 -->
-			<view class="product-section">
-				<view class="section-header">
-					<text class="section-title">浜у搧淇℃伅</text>
-					<van-button type="primary" size="small" @click="addProduct" class="add-btn" icon="plus">鏂板</van-button>
-				</view>
-				<view class="product-card" v-for="(product, idx) in productData" :key="idx">
-					<!-- 浜у搧绫� -->
-					<view class="product-header">
-						<view class="product-title">
-							<van-icon name="description" color="#2979ff" size="15" />
-							<text class="product-productCategory">浜у搧 {{ idx + 1 }}</text>
-						</view>
-						<!-- 鎿嶄綔鎸夐挳 -->
-						<view class="product-actions">
-							<van-button type="danger" size="mini" @click="removeProduct(idx)" class="del-btn" icon="delete">鍒犻櫎</van-button>
-						</view>
-					</view>
-					
-					<!-- 浜у搧淇℃伅琛ㄥ崟 -->
-					<view class="product-form">
-						<!-- 浜у搧澶х被 -->
-						<van-field
-							v-model="product.productCategory"
-							is-link
-							readonly
-							name="productCategory"
-							label="浜у搧澶х被"
+    <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+    <PageHeader title="鍙拌处璇︽儏"
+                @back="goBack" />
+    <!-- 琛ㄥ崟鍖哄煙 -->
+    <up-form @submit="onSubmit"
+             label-width="110"
+             ref="formRef"
+             :rules="rules"
+             :model="form">
+      <up-form-item label="閿�鍞悎鍚屽彿"
+                    prop="salesContractNo">
+        <up-input v-model="form.salesContractNo"
+                  placeholder="鑷姩鐢熸垚"
+                  disabled />
+      </up-form-item>
+      <up-form-item label="涓氬姟鍛�"
+                    prop="salesman"
+                    required
+                    @click="showPicker = true">
+        <up-input v-model="form.salesman"
+                  readonly
+                  @click="showPicker = true"
+                  placeholder="鐐瑰嚮閫夋嫨涓氬姟鍛�" />
+        <template #right>
+          <up-icon name="arrow-right"
+                   @click="showPicker = true"></up-icon>
+        </template>
+      </up-form-item>
+      <up-form-item label="瀹㈡埛鍚堝悓鍙�"
+                    prop="customerContractNo"
+                    required>
+        <up-input v-model="form.customerContractNo"
+                  placeholder="璇疯緭鍏ュ鎴峰悎鍚屽彿" />
+      </up-form-item>
+      <up-form-item label="瀹㈡埛鍚嶇О"
+                    prop="customerName"
+                    required>
+        <up-input v-model="form.customerName"
+                  readonly
+                  placeholder="鐐瑰嚮閫夋嫨瀹㈡埛"
+                  @click="showCustomerPicker = true" />
+        <template #right>
+          <up-icon name="arrow-right"
+                   @click="showCustomerPicker = true"></up-icon>
+        </template>
+      </up-form-item>
+      <up-form-item label="椤圭洰鍚嶇О"
+                    prop="projectName"
+                    required>
+        <up-input v-model="form.projectName"
+                  placeholder="璇疯緭鍏ラ」鐩悕绉�" />
+      </up-form-item>
+      <up-form-item label="绛捐鏃ユ湡"
+                    prop="executionDate"
+                    required>
+        <up-input v-model="form.executionDate"
+                  readonly
+                  placeholder="鐐瑰嚮閫夋嫨鏃堕棿"
+                  @click="showDatePicker = true" />
+        <template #right>
+          <up-icon name="arrow-right"
+                   @click="showDatePicker = true"></up-icon>
+        </template>
+      </up-form-item>
+      <up-form-item label="浠樻鏂瑰紡"
+                    prop="paymentMethod">
+        <up-input v-model="form.paymentMethod"
+                  placeholder="璇疯緭鍏ヤ粯娆炬柟寮�" />
+      </up-form-item>
+      <up-form-item label="褰曞叆浜�"
+                    prop="entryPersonName">
+        <up-input v-model="form.entryPersonName"
+                  placeholder="璇疯緭鍏�"
+                  disabled />
+      </up-form-item>
+      <up-form-item label="褰曞叆鏃ユ湡"
+                    prop="entryDate">
+        <up-input v-model="form.entryDate"
+                  placeholder="璇疯緭鍏�"
+                  disabled />
+      </up-form-item>
+      <!-- 涓氬姟鍛橀�夋嫨 -->
+      <up-action-sheet :show="showPicker"
+                       :actions="userActionList"
+                       title="閫夋嫨涓氬姟鍛�"
+                       @select="onSalesmanSelect"
+                       @close="showPicker = false" />
+      <!-- 鏃ユ湡閫夋嫨 -->
+      <up-popup :show="showDatePicker"
+                mode="bottom"
+                @close="showDatePicker = false">
+        <up-datetime-picker :show="true"
+                            v-model="pickerDateValue"
+                            @confirm="onDateConfirm"
+                            @cancel="showDatePicker = false"
+                            mode="date" />
+      </up-popup>
+      <!-- 瀹㈡埛閫夋嫨 -->
+      <up-action-sheet :show="showCustomerPicker"
+                       :actions="customerActionList"
+                       title="閫夋嫨瀹㈡埛"
+                       @select="onCustomerSelect"
+                       @close="showCustomerPicker = false" />
+      <!-- 浜у搧澶х被閫夋嫨鍣� -->
+      <up-popup :show="showCategoryPicker"
+                mode="bottom">
+        <!-- 澶撮儴鎸夐挳鍖哄煙 -->
+        <view class="popup-header">
+          <view @click="showCategoryPicker = false"
+                class="cancelButton">鍙栨秷</view>
+          <view @click="confirmCategorySelection"
+                class="confirmButton">纭畾</view>
+        </view>
+        <u-tree :data="productOptions"
+                :props="defaultProps"
+                show-checkbox
+                default-expand-all
+                check-strictly
+                @check-change="onCategoryConfirm" />
+      </up-popup>
+      <!-- 瑙勬牸鍨嬪彿閫夋嫨鍣� -->
+      <up-action-sheet :show="showSpecificationPicker"
+                       :actions="specificationActionList"
+                       title="閫夋嫨瑙勬牸鍨嬪彿"
+                       @select="onSpecificationSelect"
+                       @close="showSpecificationPicker = false" />
+      <!-- 绋庣巼閫夋嫨鍣� -->
+      <up-action-sheet :show="showTaxRatePicker"
+                       :actions="taxRateActionList"
+                       title="閫夋嫨绋庣巼"
+                       @select="onTaxRateSelect"
+                       @close="showTaxRatePicker = false" />
+      <!-- 鍙戠エ绫诲瀷閫夋嫨鍣� -->
+      <up-action-sheet :show="showInvoiceTypePicker"
+                       :actions="invoiceTypeActionList"
+                       title="閫夋嫨鍙戠エ绫诲瀷"
+                       @select="onInvoiceTypeSelect"
+                       @close="showInvoiceTypePicker = false" />
+      <!-- 浜у搧淇℃伅 -->
+      <view class="product-section">
+        <view class="section-header">
+          <view>
+            <text class="section-title">浜у搧淇℃伅</text>
+          </view>
+          <view>
+            <up-button type="primary"
+                       size="small"
+                       @click="addProduct"
+                       class="add-btn"
+                       v-if="operationType !== 'view'">
+              鏂板
+            </up-button>
+          </view>
+        </view>
+        <view class="product-card"
+              v-for="(product, idx) in productData"
+              :key="idx">
+          <!-- 浜у搧绫� -->
+          <view class="product-header">
+            <view class="product-title">
+              <view class="document-icon">
+                <up-icon name="file-text"
+                         size="16"
+                         color="#ffffff"></up-icon>
+              </view>
+              <text class="product-productCategory">浜у搧 {{ idx + 1 }}</text>
+            </view>
+            <!-- 鎿嶄綔鎸夐挳 -->
+            <view class="product-actions"
+                  v-if="operationType !== 'view'">
+              <up-button type="error"
+                         size="mini"
+                         @click="removeProduct(idx)"
+                         class="del-btn">
+                鍒犻櫎
+              </up-button>
+            </view>
+          </view>
+          <!-- 浜у搧淇℃伅琛ㄥ崟 -->
+          <view class="product-form">
+            <!-- 浜у搧澶х被 -->
+            <up-form-item label="浜у搧澶х被"
+                          prop="productCategory"
+                          required>
+              <up-input v-model="product.productCategory"
+                        readonly
+                        placeholder="璇烽�夋嫨"
+                        @click="openCategoryPicker(idx)" />
+              <template #right>
+                <up-icon name="arrow-right"
+                         @click="showCategoryPicker = true"></up-icon>
+              </template>
+            </up-form-item>
+            <!-- 瑙勬牸鍨嬪彿 -->
+            <up-form-item label="瑙勬牸鍨嬪彿"
+                          prop="specificationModel"
+                          required>
+              <up-input v-model="product.specificationModel"
+                        readonly
+                        placeholder="璇烽�夋嫨"
+                        @click="openSpecificationPicker(idx)" />
+              <template #right>
+                <up-icon name="arrow-right"
+                         @click="showSpecificationPicker = true"></up-icon>
+              </template>
+            </up-form-item>
+            <!-- 缁戝畾鏈哄櫒 -->
+            <!-- <up-form-item
+							label="缁戝畾鏈哄櫒"
+							prop="speculativeTradingName"
 							required
-							placeholder="璇烽�夋嫨"
-							:rules="[{ required: true, message: '璇烽�夋嫨' }]"
-							@click="openCategoryPicker(idx)"
-						/>
-						
-						<!-- 瑙勬牸鍨嬪彿 -->
-						<van-field
-							v-model="product.specificationModel"
-							is-link
-							readonly
-							name="specificationModel"
-							label="瑙勬牸鍨嬪彿"
-							required
-							:rules="[{ required: true, message: '璇烽�夋嫨' }]"
-							placeholder="璇烽�夋嫨"
-							@click="openSpecificationPicker(idx)"
-						/>
-						
-						<!-- 鍗曚綅 -->
-						<van-field
-							v-model="product.unit"
-							name="unit"
-							label="鍗曚綅"
-							required
-							:rules="[{ required: true, message: '璇疯緭鍏�' }]"
-							placeholder="璇疯緭鍏�"
-						/>
-						
-						<!-- 绋庣巼 -->
-						<van-field
-							v-model="product.taxRate"
-							is-link
-							readonly
-							name="taxRate"
-							label="绋庣巼(%)"
-							required
-							:rules="[{ required: true, message: '璇烽�夋嫨' }]"
-							placeholder="璇烽�夋嫨"
-							@click="openTaxRatePicker(idx)"
-						/>
-						
-						<!-- 鍚◣鍗曚环 -->
-						<van-field
-							v-model="product.taxInclusiveUnitPrice"
-							name="taxInclusiveUnitPrice"
-							label="鍚◣鍗曚环(鍏�)"
-							type="number"
-							required
-							:rules="[{ required: true, message: '璇疯緭鍏�' }]"
-							placeholder="璇疯緭鍏�"
-							@blur="formatTaxPrice(idx)"
-						/>
-						
-						<!-- 鏁伴噺 -->
-						<van-field
-							v-model="product.quantity"
-							name="quantity"
-							label="鏁伴噺"
-							type="number"
-							:rules="[{ required: true, message: '璇疯緭鍏�' }]"
-							required
-							placeholder="璇疯緭鍏�"
-							@blur="formatAmount(idx)"
-						/>
-						
-						<!-- 鍚◣鎬讳环 -->
-						<van-field
-							v-model="product.taxInclusiveTotalPrice"
-							name="taxInclusiveTotalPrice"
-							label="鍚◣鎬讳环(鍏�)"
-							type="number"
-							:rules="[{ required: true, message: '璇疯緭鍏�' }]"
-							required
-							placeholder="璇疯緭鍏�"
-							@blur="formatTaxTotal(idx)"
-						/>
-						
-						<!-- 涓嶅惈绋庢�讳环 -->
-						<van-field
-							v-model="product.taxExclusiveTotalPrice"
-							name="taxExclusiveTotalPrice"
-							label="涓嶅惈绋庢�讳环(鍏�)"
-							type="number"
-							required
-							:rules="[{ required: true, message: '璇疯緭鍏�' }]"
-							placeholder="璇疯緭鍏�"
-							@blur="formatNoTaxTotal(idx)"
-						/>
-						
-						<!-- 鍙戠エ绫诲瀷 -->
-						<van-field
-							v-model="product.invoiceType"
-							is-link
-							readonly
-							name="invoiceType"
-							label="鍙戠エ绫诲瀷"
-							:rules="[{ required: true, message: '璇烽�夋嫨' }]"
-							required
-							placeholder="璇烽�夋嫨"
-							@click="openInvoiceTypePicker(idx)"
-						/>
-					</view>
-				</view>
-			</view>
-			<view class="footer-btns">
-				<van-button class="cancel-btn" @click="goBack">鍙栨秷</van-button>
-				<van-button class="save-btn" native-type="submit" form-type="submit">淇濆瓨</van-button>
-			</view>
-		</van-form>
+						>
+							<up-input
+							disabled
+								v-model="product.speculativeTradingName"
+								placeholder="璇疯緭鍏�"
+							/>
+						</up-form-item> -->
+            <!-- 鍗曚綅 -->
+            <up-form-item label="鍗曚綅"
+                          prop="unit"
+                          required>
+              <up-input v-model="product.unit"
+                        placeholder="璇疯緭鍏�" />
+            </up-form-item>
+            <!-- 绋庣巼 -->
+            <up-form-item label="绋庣巼(%)"
+                          prop="taxRate"
+                          required>
+              <up-input v-model="product.taxRate"
+                        readonly
+                        placeholder="璇烽�夋嫨"
+                        @click="openTaxRatePicker(idx)" />
+              <template #right>
+                <up-icon name="arrow-right"
+                         @click="showTaxRatePicker = true"></up-icon>
+              </template>
+            </up-form-item>
+            <!-- 鍚◣鍗曚环 -->
+            <up-form-item label="鍚◣鍗曚环(鍏�)"
+                          prop="taxInclusiveUnitPrice"
+                          required>
+              <up-input v-model="product.taxInclusiveUnitPrice"
+                        type="number"
+                        placeholder="璇疯緭鍏�"
+                        @blur="formatTaxPrice(idx)" />
+            </up-form-item>
+            <!-- 鏁伴噺 -->
+            <up-form-item label="鏁伴噺"
+                          prop="quantity"
+                          required>
+              <up-input v-model="product.quantity"
+                        type="number"
+                        placeholder="璇疯緭鍏�"
+                        @blur="formatAmount(idx)" />
+            </up-form-item>
+            <!-- 鍚◣鎬讳环 -->
+            <up-form-item label="鍚◣鎬讳环(鍏�)"
+                          prop="taxInclusiveTotalPrice"
+                          required>
+              <up-input v-model="product.taxInclusiveTotalPrice"
+                        type="number"
+                        placeholder="璇疯緭鍏�"
+                        @blur="formatTaxTotal(idx)" />
+            </up-form-item>
+            <!-- 涓嶅惈绋庢�讳环 -->
+            <up-form-item label="涓嶅惈绋庢�讳环(鍏�)"
+                          prop="taxExclusiveTotalPrice"
+                          required>
+              <up-input v-model="product.taxExclusiveTotalPrice"
+                        type="number"
+                        placeholder="璇疯緭鍏�"
+                        @blur="formatNoTaxTotal(idx)" />
+            </up-form-item>
+            <!-- 鍙戠エ绫诲瀷 -->
+            <up-form-item label="鍙戠エ绫诲瀷"
+                          prop="invoiceType"
+                          required>
+              <up-input v-model="product.invoiceType"
+                        readonly
+                        placeholder="璇烽�夋嫨"
+                        @click="openInvoiceTypePicker(idx)" />
+              <template #right>
+                <up-icon name="arrow-right"
+                         @click="showInvoiceTypePicker = true"></up-icon>
+              </template>
+            </up-form-item>
+          </view>
+        </view>
+      </view>
+    </up-form>
+    <!-- 浣跨敤鍏叡搴曢儴鎸夐挳缁勪欢 -->
+    <FooterButtons :show="operationType !== 'view'"
+                   cancelText="鍙栨秷"
+                   confirmText="淇濆瓨"
+                   @cancel="goBack"
+                   @confirm="onSubmit" />
   </view>
 </template>
 
 <script setup>
-import {onMounted, ref} from 'vue';
-import {userListNoPage} from "@/api/system/user";
-import {
-	addOrUpdateSalesLedger,
-	addOrUpdateSalesLedgerProduct,
-	customerList,
-	getSalesLedgerWithProducts,
-	modelList,
-	productTreeList
-} from "@/api/salesManagement/salesLedger";
-import useUserStore from "@/store/modules/user";
-import {calculateTaxExclusiveTotalPrice} from "@/utils/summarizeTable";
+  import { onMounted, ref, computed } from "vue";
+  import { userListNoPage } from "@/api/system/user";
+  import { formatDateToYMD } from "@/utils/ruoyi";
+  import {
+    addOrUpdateSalesLedger,
+    customerList,
+    getSalesLedgerWithProducts,
+    modelList,
+    productTreeList,
+  } from "@/api/salesManagement/salesLedger";
+  import useUserStore from "@/store/modules/user";
+  import { calculateTaxExclusiveTotalPrice } from "@/utils/summarizeTable";
+  import PageHeader from "@/components/PageHeader.vue";
+  import FooterButtons from "@/components/FooterButtons.vue";
 
-// 鑾峰彇椤甸潰鍙傛暟
-const operationType = ref('');
-const editData = ref(null);
+  // 鑾峰彇椤甸潰鍙傛暟
+  const operationType = ref("");
+  const editData = ref(null);
+  const formRef = ref(null);
 
-const userStore = useUserStore()
-const form = ref({
-	id: '',
-  salesContractNo: '',
-	customerContractNo: '',
-	customerId: '',
-	customerName: '',
-	projectName: '',
-	executionDate: '',
-  paymentMethod: '',
-	entryPerson: '',
-	entryPersonName: '',
-	entryDate: '',
-});
-const pickerValue = ref(['']);
-const pickerDateValue = ref([]);
-const showPicker = ref(false);
-const showDatePicker = ref(false);
-const pickerCustomerValue = ref(['']);
-const showCustomerPicker = ref(false);
-const userList = ref([]);
-const customerOption = ref([]);
-const productData = ref([]);
-
-// 閫夋嫨鍣ㄧ浉鍏冲彉閲�
-const showCategoryPicker = ref(false);
-const showSpecificationPicker = ref(false);
-const showTaxRatePicker = ref(false);
-const showInvoiceTypePicker = ref(false);
-const pickerCategoryValue = ref(['']);
-const pickerSpecificationValue = ref(['']);
-const pickerTaxRateValue = ref(['']);
-const pickerInvoiceTypeValue = ref(['']);
-const currentProductIndex = ref(0);
-
-// 閫夐」鏁版嵁
-const productOptions = ref([]);
-const selectedCategoryNode = ref(null);
-const defaultProps = ref({
-	children: 'children',
-	label: 'label',
-	nodeKey: 'id'
-});
-
-const modelOptions = ref([]);
-// 闃叉寰幆璁$畻鐨勬爣蹇�
-// const isCalculating = ref(false);
-const taxRateOptions = ref([
-  { text: '1', value: '1' },
-  { text: '6', value: '6' },
-  { text: '13', value: '13' },
-]);
-
-const invoiceTypeOptions = ref([
-  { text: '澧炴櫘绁�', value: '澧炴櫘绁�' },
-  { text: '澧炰笓绁�', value: '澧炰笓绁�' },
-]);
-
-const addProduct = () => {
-	productData.value.push({
-    productCategory: '',
-    specificationModel: '',
-		productModelId: '',
-    unit: '',
-    taxRate: '',
-    taxInclusiveUnitPrice: '',
-    quantity: '',
-    taxInclusiveTotalPrice: '',
-    taxExclusiveTotalPrice: '',
-    invoiceType: ''
+  const userStore = useUserStore();
+  const form = ref({
+    id: "",
+    salesContractNo: "",
+    customerContractNo: "",
+    customerId: "",
+    customerName: "",
+    projectName: "",
+    executionDate: "",
+    paymentMethod: "",
+    entryPerson: "",
+    entryPersonName: "",
+    entryDate: "",
   });
-};
-const onConfirm = ({ selectedValues, selectedOptions }) => {
-	form.value.salesman = selectedOptions[0]?.text;
-	pickerValue.value = [selectedValues[0]];
-	showPicker.value = false;
-};
-const onCustomerConfirm = ({ selectedValues, selectedOptions }) => {
-	form.value.customerName = selectedOptions[0]?.text;
-	form.value.customerId = selectedOptions[0]?.value;
-	pickerCustomerValue.value = [selectedValues[0]];
-	showCustomerPicker.value = false;
-};
-const onDateConfirm = ({ selectedValues }) => {
-	form.value.executionDate = selectedValues.join('-');
-	pickerDateValue.value = selectedValues;
-	showDatePicker.value = false;
-};
-const removeProduct = (idx) => {
-	productData.value.splice(idx, 1);
-};
-
-// 鏄剧ず閫夋嫨鍣�
-const openCategoryPicker = (idx) => {
-  currentProductIndex.value = idx;
-  showCategoryPicker.value = true;
-};
-
-const openSpecificationPicker = (idx) => {
-  currentProductIndex.value = idx;
-  showSpecificationPicker.value = true;
-};
-
-const openTaxRatePicker = (idx) => {
-  currentProductIndex.value = idx;
-  showTaxRatePicker.value = true;
-};
-
-const openInvoiceTypePicker = (idx) => {
-  currentProductIndex.value = idx;
-  showInvoiceTypePicker.value = true;
-};
-
-// 閫夋嫨鍣ㄧ‘璁や簨浠�
-const onCategoryConfirm = (node) => {
-	// 鑾峰彇閫変腑鐨勮妭鐐逛俊鎭�
-	console.log('selected node---', node);
-	// 瀛樺偍閫変腑鐨勮妭鐐癸紝鐢ㄤ簬纭鏃惰幏鍙栨暟鎹�
-	selectedCategoryNode.value = node;
-};
-
-// 纭浜у搧澶х被閫夋嫨
-const confirmCategorySelection = () => {
-	if (selectedCategoryNode.value) {
-		// 璁剧疆閫変腑鐨勪骇鍝佸ぇ绫�
-		productData.value[currentProductIndex.value].productCategory = selectedCategoryNode.value.label;
-		const id = selectedCategoryNode.value.id
-		// 閲嶇疆閫変腑鐨勮妭鐐�
-		selectedCategoryNode.value = null;
-		productData.value[currentProductIndex.value].specificationModel = ''
-		productData.value[currentProductIndex.value].productModelId = ''
-		productData.value[currentProductIndex.value].pickerSpecificationValue = ['']
-		getModels(id)
-	}
-	showCategoryPicker.value = false;
-};
-// 鑾峰彇瑙勬牸鍨嬪彿
-const getModels = (value) => {
-	modelList({ id: value }).then((res) => {
-		modelOptions.value = res.map(user => ({
-			text: user.model,
-			value: user.id
-		}));
-	});
-};
-// 閫夋嫨瑙勬牸鍨嬪彿
-const onSpecificationConfirm = ({ selectedValues, selectedOptions }) => {
-	productData.value[currentProductIndex.value].specificationModel = selectedOptions[0]?.text;
-	productData.value[currentProductIndex.value].productModelId = selectedOptions[0]?.value;
-	productData.value[currentProductIndex.value].unit = selectedOptions[0]?.unit;
-  pickerSpecificationValue.value = [selectedValues[0]];
-  showSpecificationPicker.value = false;
-};
-// 閫夋嫨绋庣巼
-const onTaxRateConfirm = ({ selectedValues, selectedOptions }) => {
-	productData.value[currentProductIndex.value].taxRate = selectedOptions[0]?.value;
-  pickerTaxRateValue.value = [selectedValues[0]];
-  showTaxRatePicker.value = false;
-	// if (isCalculating.value) return;
-	const inclusiveTotalPrice = parseFloat(productData.value[currentProductIndex.value].taxInclusiveTotalPrice);
-	const taxRate = parseFloat(productData.value[currentProductIndex.value].taxRate);
-	if (!inclusiveTotalPrice || !taxRate) {
-		return;
-	}
-	// isCalculating.value = true;
-	// 璁$畻涓嶅惈绋庢�讳环
-	productData.value[currentProductIndex.value].taxExclusiveTotalPrice =
-		calculateTaxExclusiveTotalPrice(
-			inclusiveTotalPrice,
-			taxRate
-		);
-	// isCalculating.value = false;
-};
-
-const onInvoiceTypeConfirm = ({ selectedValues, selectedOptions }) => {
-	productData.value[currentProductIndex.value].invoiceType = selectedOptions[0]?.text;
-  pickerInvoiceTypeValue.value = [selectedValues[0]];
-  showInvoiceTypePicker.value = false;
-};
-
-// 鏍煎紡鍖栧嚱鏁� - 鍥哄畾涓や綅灏忔暟
-const formatTaxPrice = (idx) => {
-  if (productData.value[idx].taxInclusiveUnitPrice) {
-    const value = parseFloat(productData.value[idx].taxInclusiveUnitPrice);
-    if (!isNaN(value)) {
-			productData.value[idx].taxInclusiveUnitPrice = value.toFixed(2);
+  const showPicker = ref(false);
+  const showDatePicker = ref(false);
+  const pickerDateValue = ref(Date.now());
+  const showCustomerPicker = ref(false);
+  const userList = ref([]);
+  const customerOption = ref([]);
+  const userActionList = computed(() => {
+    return userList.value.map(user => ({
+      name: user.text,
+      value: user.value,
+    }));
+  });
+  const formatter = (type, value) => {
+    if (type === "year") {
+      return `${value}`;
     }
-  }
-	if (!productData.value[currentProductIndex.value].taxRate) {
-		uni.showToast({
-			title: '璇峰厛閫夋嫨绋庣巼',
-			icon: 'none'
-		});
-		return;
-	}
-	const quantity = parseFloat(productData.value[currentProductIndex.value].quantity);
-	const unitPrice = parseFloat(productData.value[currentProductIndex.value].taxInclusiveUnitPrice);
-	
-	if (!quantity || quantity <= 0 || !unitPrice) {
-		return;
-	}
-	// 璁$畻鍚◣鎬讳环
-	productData.value[currentProductIndex.value].taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
-	
-	// 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
-	if (productData.value[currentProductIndex.value].taxRate) {
-		productData.value[currentProductIndex.value].taxExclusiveTotalPrice =
-			calculateTaxExclusiveTotalPrice(
-				productData.value[currentProductIndex.value].taxInclusiveTotalPrice,
-				productData.value[currentProductIndex.value].taxRate
-			);
-	}
-};
-// 鏁伴噺杈撳叆妗嗗け鐒�
-const formatAmount = (idx) => {
-  if (productData.value[idx].quantity) {
-    const value = parseFloat(productData.value[idx].quantity);
-    if (!isNaN(value)) {
-			productData.value[idx].quantity = value.toFixed(2);
+    if (type === "month") {
+      return `${value}`;
     }
-  }
-	if (!productData.value[currentProductIndex.value].taxRate) {
-		uni.showToast({
-			title: '璇峰厛閫夋嫨绋庣巼',
-			icon: 'none'
-		});
-		return;
-	}
-	const quantity = parseFloat(productData.value[currentProductIndex.value].quantity);
-	const unitPrice = parseFloat(productData.value[currentProductIndex.value].taxInclusiveUnitPrice);
-	
-	if (!quantity || quantity <= 0 || !unitPrice) {
-		return;
-	}
-	// 璁$畻鍚◣鎬讳环
-	productData.value[currentProductIndex.value].taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
-	// 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
-	if (productData.value[currentProductIndex.value].taxRate) {
-		productData.value[currentProductIndex.value].taxExclusiveTotalPrice =
-			calculateTaxExclusiveTotalPrice(
-				productData.value[currentProductIndex.value].taxInclusiveTotalPrice,
-				productData.value[currentProductIndex.value].taxRate
-			);
-	}
-};
-// 鍚◣鎬讳环澶辩劍锛屾牴鎹惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
-const formatTaxTotal = (idx) => {
-  if (productData.value[idx].taxInclusiveTotalPrice) {
-    const value = parseFloat(productData.value[idx].taxInclusiveTotalPrice);
-    if (!isNaN(value)) {
-			productData.value[idx].taxInclusiveTotalPrice = value.toFixed(2);
+    if (type === "day") {
+      return `${value}`;
     }
-  }
-	const totalPrice = parseFloat(productData.value[currentProductIndex.value].taxInclusiveTotalPrice);
-	const quantity = parseFloat(productData.value[currentProductIndex.value].quantity);
-	
-	if (!totalPrice || !quantity || quantity <= 0) {
-		return;
-	}
-	// 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
-	productData.value[currentProductIndex.value].taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2);
-	// 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
-	if (productData.value[currentProductIndex.value].taxRate) {
-		productData.value[currentProductIndex.value].taxExclusiveTotalPrice =
-			calculateTaxExclusiveTotalPrice(
-				totalPrice,
-				productData.value[currentProductIndex.value].taxRate
-			);
-	}
-};
-// 涓嶅惈绋庢�讳环澶辩劍, 鏍规嵁涓嶅惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
-const formatNoTaxTotal = (idx) => {
-  if (productData.value[idx].taxExclusiveTotalPrice) {
-    const value = parseFloat(productData.value[idx].taxExclusiveTotalPrice);
-    if (!isNaN(value)) {
-			productData.value[idx].taxExclusiveTotalPrice = value.toFixed(2);
+    return value;
+  };
+  const customerActionList = computed(() => {
+    return customerOption.value.map(customer => ({
+      name: customer.text,
+      value: customer.value,
+    }));
+  });
+
+  // 鏃ユ湡閫夋嫨鍒楄〃宸茬Щ闄わ紝鏀圭敤 up-datetime-picker
+
+  // 浜у搧澶х被閫夋嫨鍒楄〃
+  const categoryActionList = computed(() => {
+    const flattenCategories = (categories, result = []) => {
+      categories.forEach(category => {
+        result.push({
+          name: category.label,
+          value: category.id,
+        });
+        if (category.children && category.children.length > 0) {
+          flattenCategories(category.children, result);
+        }
+      });
+      return result;
+    };
+    return flattenCategories(productOptions.value);
+  });
+
+  // 瑙勬牸鍨嬪彿閫夋嫨鍒楄〃
+  const specificationActionList = computed(() => {
+    return modelOptions.value.map(model => ({
+      name: model.text,
+      value: model.value,
+      unit: model.unit,
+      speculativeTradingName: model.speculativeTradingName,
+    }));
+  });
+
+  // 绋庣巼閫夋嫨鍒楄〃
+  const taxRateActionList = computed(() => {
+    return taxRateOptions.value.map(rate => ({
+      name: rate.text,
+      value: rate.value,
+    }));
+  });
+
+  // 鍙戠エ绫诲瀷閫夋嫨鍒楄〃
+  const invoiceTypeActionList = computed(() => {
+    return invoiceTypeOptions.value.map(type => ({
+      name: type.text,
+      value: type.value,
+    }));
+  });
+  const productData = ref([]);
+
+  // 閫夋嫨鍣ㄧ浉鍏冲彉閲�
+  const showCategoryPicker = ref(false);
+  const showSpecificationPicker = ref(false);
+  const showTaxRatePicker = ref(false);
+  const showInvoiceTypePicker = ref(false);
+  // 閫夋嫨鍣ㄦ樉绀虹姸鎬佸彉閲忓凡鍦ㄤ笂闈㈠畾涔�
+
+  // 涓存椂鍙橀噺宸蹭笉鍐嶉渶瑕�
+  const currentProductIndex = ref(0);
+
+  // 閫夐」鏁版嵁
+  const productOptions = ref([]);
+  const selectedCategoryNode = ref(null);
+  const defaultProps = ref({
+    children: "children",
+    label: "label",
+    nodeKey: "id",
+  });
+
+  const modelOptions = ref([]);
+  // 闃叉寰幆璁$畻鐨勬爣蹇�
+  // const isCalculating = ref(false);
+  const taxRateOptions = ref([
+    { text: "1", value: "1" },
+    { text: "6", value: "6" },
+    { text: "13", value: "13" },
+  ]);
+
+  const invoiceTypeOptions = ref([
+    { text: "澧炴櫘绁�", value: "澧炴櫘绁�" },
+    { text: "澧炰笓绁�", value: "澧炰笓绁�" },
+  ]);
+
+  // 琛ㄥ崟鏍¢獙瑙勫垯
+  const rules = {
+    salesman: [{ required: true, message: "璇烽�夋嫨涓氬姟鍛�", trigger: "change" }],
+    customerContractNo: [
+      { required: true, message: "璇疯緭鍏ュ鎴峰悎鍚屽彿", trigger: "blur" },
+    ],
+    customerName: [
+      { required: true, message: "璇烽�夋嫨瀹㈡埛鍚嶇О", trigger: "change" },
+    ],
+    projectName: [{ required: true, message: "璇疯緭鍏ラ」鐩悕绉�", trigger: "blur" }],
+    executionDate: [
+      { required: true, message: "璇烽�夋嫨绛捐鏃ユ湡", trigger: "change" },
+    ],
+  };
+
+  const addProduct = () => {
+    if (productData.value === null) {
+      productData.value = [];
     }
-  }
-	if (!productData.value[currentProductIndex.value].taxRate) {
-		uni.showToast({
-			title: '璇峰厛閫夋嫨绋庣巼',
-			icon: 'none'
-		});
-		return;
-	}
-	const exclusiveTotalPrice = parseFloat(productData.value[currentProductIndex.value].taxExclusiveTotalPrice);
-	const quantity = parseFloat(productData.value[currentProductIndex.value].quantity);
-	const taxRate = parseFloat(productData.value[currentProductIndex.value].taxRate);
-	if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
-		return;
-	}
-	// 鍏堣绠楀惈绋庢�讳环 = 涓嶅惈绋庢�讳环 / (1 - 绋庣巼/100)
-	const taxRateDecimal = taxRate / 100;
-	const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
-	productData.value[currentProductIndex.value].taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
-	// 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
-	productData.value[currentProductIndex.value].taxInclusiveUnitPrice = (inclusiveTotalPrice / quantity).toFixed(2);
-};
-const goBack = () => {
-	// 娓呯悊鏈湴瀛樺偍鐨勬暟鎹�
-	uni.removeStorageSync('operationType');
-	uni.removeStorageSync('editData');
-	uni.navigateBack();
-};
-const onSubmit = () => {
-	if (productData.value !== null && productData.value.length > 0) {
-		form.value.productData = JSON.parse(JSON.stringify(productData.value));
-	} else {
-		uni.showToast({
-			title: '璇锋坊鍔犱骇鍝佷俊鎭�',
-			icon: 'none'
-		});
-	}
-	form.value.type = 1;
-	addOrUpdateSalesLedger(form.value).then((res) => {
-		uni.showToast({
-			title: '鎻愪氦鎴愬姛',
-			icon: 'success',
-		});
-		goBack();
-	});
-};
-const setUserInfo = () => {
-	form.value.entryPerson = userStore.id;
-	form.value.entryPersonName = userStore.name;
-	// 璁剧疆褰撳ぉ鏃ユ湡
-	const today = new Date()
-	const year = today.getFullYear()
-	const month = String(today.getMonth() + 1).padStart(2, '0')
-	const day = String(today.getDate()).padStart(2, '0')
-	form.value.entryDate = `${year}-${month}-${day}`
-	pickerDateValue.value = [year.toString(), month.toString(), day.toString()]
-}
-// 濉厖琛ㄥ崟鏁版嵁锛堢紪杈戞ā寮忥級
-const fillFormData = () => {
-  if (!editData.value) return;
-	getSalesLedgerWithProducts({ id: editData.value.id, type: 1 }).then((res) => {
-		productData.value = res.productData;
-	});
-	console.log(editData.value)
-  // 濉厖鍩烘湰淇℃伅
-  form.value.salesContractNo = editData.value.salesContractNo || '';
-  form.value.customerContractNo = editData.value.customerContractNo || '';
-  form.value.customerName = editData.value.customerName || '';
-  form.value.projectName = editData.value.projectName || '';
-  form.value.executionDate = editData.value.executionDate || '';
-  form.value.paymentMethod = editData.value.paymentMethod || '';
-  form.value.salesman = editData.value.salesman || '';
-  form.value.entryPerson = editData.value.entryPerson || '';
-  form.value.entryPersonName = editData.value.entryPersonName || '';
-  form.value.entryDate = editData.value.entryDate || '';
-  form.value.id = editData.value.id || '';
-  form.value.customerId = editData.value.customerId || '';
-	
-  // 璁剧疆涓氬姟鍛橀�夋嫨鍣ㄧ殑鍊�
-  if (editData.value.salesman) {
-    const salesmanIndex = userList.value.findIndex(user => user.text === editData.value.salesman);
-    if (salesmanIndex !== -1) {
-      pickerValue.value = [userList.value[salesmanIndex].value];
+    productData.value.push({
+      productCategory: "",
+      specificationModel: "",
+      productModelId: "",
+      unit: "",
+      speculativeTradingName: "",
+      taxRate: "",
+      taxInclusiveUnitPrice: "",
+      quantity: "",
+      taxInclusiveTotalPrice: "",
+      taxExclusiveTotalPrice: "",
+      invoiceType: "",
+    });
+  };
+  // 涓氬姟鍛橀�夋嫨浜嬩欢
+  const onSalesmanSelect = item => {
+    form.value.salesman = item.name;
+  };
+
+  // 鏃ユ湡纭浜嬩欢
+  const onDateConfirm = e => {
+    form.value.executionDate = formatDateToYMD(e.value);
+    // 淇濇寔pickerDateValue涓烘椂闂存埑鏍煎紡锛岃�屼笉鏄牸寮忓寲鐨勫瓧绗︿覆
+    pickerDateValue.value = e.value;
+    showDatePicker.value = false;
+  };
+
+  // 瀹㈡埛閫夋嫨浜嬩欢
+  const onCustomerSelect = item => {
+    form.value.customerName = item.name;
+    form.value.customerId = item.value;
+  };
+
+  // 鍘熸湁鐨勭‘璁ゆ柟娉曞凡琚柊鐨刟ction-sheet閫夋嫨鏂规硶鏇夸唬
+  const removeProduct = idx => {
+    productData.value.splice(idx, 1);
+  };
+
+  // 鏄剧ず閫夋嫨鍣�
+  const openCategoryPicker = idx => {
+    currentProductIndex.value = idx;
+    showCategoryPicker.value = true;
+  };
+
+  const openSpecificationPicker = idx => {
+    currentProductIndex.value = idx;
+    showSpecificationPicker.value = true;
+  };
+
+  const openTaxRatePicker = idx => {
+    currentProductIndex.value = idx;
+    showTaxRatePicker.value = true;
+  };
+
+  const openInvoiceTypePicker = idx => {
+    currentProductIndex.value = idx;
+    showInvoiceTypePicker.value = true;
+  };
+
+  // 閫夋嫨鍣ㄧ‘璁や簨浠�
+  const onCategoryConfirm = node => {
+    // 鑾峰彇閫変腑鐨勮妭鐐逛俊鎭�
+    console.log("selected node---", node);
+    // 瀛樺偍閫変腑鐨勮妭鐐癸紝鐢ㄤ簬纭鏃惰幏鍙栨暟鎹�
+    selectedCategoryNode.value = node;
+  };
+
+  // 纭浜у搧澶х被閫夋嫨
+  const confirmCategorySelection = () => {
+    if (selectedCategoryNode.value) {
+      // 璁剧疆閫変腑鐨勪骇鍝佸ぇ绫�
+      productData.value[currentProductIndex.value].productCategory =
+        selectedCategoryNode.value.label;
+      const id = selectedCategoryNode.value.id;
+      // 閲嶇疆閫変腑鐨勮妭鐐�
+      selectedCategoryNode.value = null;
+      productData.value[currentProductIndex.value].specificationModel = "";
+      productData.value[currentProductIndex.value].productModelId = "";
+      getModels(id);
     }
-  }
-  
-  // 璁剧疆瀹㈡埛閫夋嫨鍣ㄧ殑鍊�
-  if (editData.value.customerName) {
-    const customerIndex = customerOption.value.findIndex(customer => customer.text === editData.value.customerName);
-    if (customerIndex !== -1) {
-      pickerCustomerValue.value = [customerOption.value[customerIndex].value]
+    showCategoryPicker.value = false;
+  };
+  // 鑾峰彇瑙勬牸鍨嬪彿
+  const getModels = value => {
+    modelList({ id: value }).then(res => {
+      modelOptions.value = res.map(user => ({
+        text: user.model,
+        value: user.id,
+        unit: user.unit,
+        speculativeTradingName: user.speculativeTradingName,
+      }));
+    });
+  };
+  // 瑙勬牸鍨嬪彿閫夋嫨浜嬩欢
+  const onSpecificationSelect = item => {
+    console.log("selected item---", item);
+    productData.value[currentProductIndex.value].specificationModel = item.name;
+    productData.value[currentProductIndex.value].productModelId = item.value;
+    productData.value[currentProductIndex.value].unit = item.unit;
+    productData.value[currentProductIndex.value].speculativeTradingName =
+      item.speculativeTradingName;
+  };
+  // 绋庣巼閫夋嫨浜嬩欢
+  const onTaxRateSelect = item => {
+    productData.value[currentProductIndex.value].taxRate = item.value;
+    // 閲嶆柊璁$畻涓嶅惈绋庢�讳环
+    const inclusiveTotalPrice = parseFloat(
+      productData.value[currentProductIndex.value].taxInclusiveTotalPrice
+    );
+    const taxRate = parseFloat(item.value);
+    if (inclusiveTotalPrice && taxRate) {
+      productData.value[currentProductIndex.value].taxExclusiveTotalPrice =
+        calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate);
     }
-  }
-  
-  // 璁剧疆鏃ユ湡閫夋嫨鍣ㄧ殑鍊�
-  if (editData.value.executionDate) {
-		pickerDateValue.value = editData.value.executionDate.split('-').map(num => parseInt(num, 10))
-		console.log(pickerDateValue.value)
-	}
-};
-const getUserList = () => {
-	userListNoPage().then((res) => {
-		// 灏嗙敤鎴锋暟鎹粍瑁呮垚 picker 闇�瑕佺殑鏍煎紡
-		userList.value = res.data.map(user => ({
-			text: user.nickName,
-			value: user.nickName
-		}));
-	})
-}
-const getCustomerList = () => {
-	customerList().then((res) => {
-		// 灏嗙敤鎴锋暟鎹粍瑁呮垚 picker 闇�瑕佺殑鏍煎紡
-		customerOption.value = res.map(item => ({
-			text: item.customerName,
-			value: item.id
-		}));
-	})
-}
-const convertIdToValue = (data) => {
-	// 濡傛灉浼犲叆鐨勪笉鏄暟缁勶紝鍒欒繑鍥炵┖鏁扮粍
-	if (!Array.isArray(data)) {
-		return [];
-	}
-	// 閫掑綊鏄犲皠鍑芥暟
-	return data.map(item => {
-		// 鍒涘缓鏂板璞★紝鏄犲皠瀛楁
-		const mappedItem = {
-			label: item.label, // 鍏抽敭锛氬皢 label 鏄犲皠涓� text
-			id: item.id,       // 淇濈暀 id
-		};
-		// 濡傛灉瀛樺湪 children 鏁扮粍锛屽垯閫掑綊澶勭悊
-		if (item.children && Array.isArray(item.children) && item.children.length > 0) {
-			mappedItem.children = convertIdToValue(item.children);
-		}
-		return mappedItem;
-	});
-};
-// 鑾峰彇浜у搧澶х被tree鏁版嵁
-const getProductOptions = () => {
-	productTreeList().then((res) => {
-		productOptions.value = convertIdToValue(res);
-	});
-};
-onMounted(() => {
-	// 鑾峰彇椤甸潰鍙傛暟
-	operationType.value = uni.getStorageSync('operationType') || '';
-	
-	// 鑾峰彇浜哄憳鍒楄〃
-	getUserList()
-	// 鑾峰彇瀹㈡埛鍒楄〃
-	getCustomerList()
-	// 鑾峰彇浜у搧澶х被tree鏁版嵁
-	getProductOptions()
-	// 璧嬪�奸粯璁や俊鎭�
-	if (operationType.value === 'add') {
-		setUserInfo()
-	}
-	
-	// 鑾峰彇缂栬緫鏁版嵁骞跺~鍏呰〃鍗�
-	const editDataStr = uni.getStorageSync('editData');
-	if (editDataStr) {
-		try {
-			editData.value = JSON.parse(editDataStr);
-			// 濡傛灉鏄紪杈戞ā寮忥紝绛夊緟鏁版嵁鍔犺浇瀹屾垚鍚庡~鍏呰〃鍗曟暟鎹�
-			if (operationType.value === 'edit' && editData.value) {
-				// 浣跨敤 nextTick 纭繚鏁版嵁鍔犺浇瀹屾垚鍚庡啀濉厖
-				setTimeout(() => {
-					fillFormData();
-				}, 100);
-			}
-		} catch (error) {
-			console.error('瑙f瀽缂栬緫鏁版嵁澶辫触:', error);
-		}
-	}
-});
+  };
+
+  // 鍙戠エ绫诲瀷閫夋嫨浜嬩欢
+  const onInvoiceTypeSelect = item => {
+    productData.value[currentProductIndex.value].invoiceType = item.name;
+  };
+
+  // 鏍煎紡鍖栧嚱鏁� - 鍥哄畾涓や綅灏忔暟
+  const formatTaxPrice = idx => {
+    if (productData.value[idx].taxInclusiveUnitPrice) {
+      const value = parseFloat(productData.value[idx].taxInclusiveUnitPrice);
+      if (!isNaN(value)) {
+        productData.value[idx].taxInclusiveUnitPrice = value.toFixed(2);
+      }
+    }
+    if (!productData.value[idx].taxRate) {
+      uni.showToast({
+        title: "璇峰厛閫夋嫨绋庣巼",
+        icon: "none",
+      });
+      return;
+    }
+    const quantity = parseFloat(productData.value[idx].quantity);
+    const unitPrice = parseFloat(productData.value[idx].taxInclusiveUnitPrice);
+
+    if (!quantity || quantity <= 0 || !unitPrice) {
+      return;
+    }
+    // 璁$畻鍚◣鎬讳环
+    productData.value[idx].taxInclusiveTotalPrice = (
+      unitPrice * quantity
+    ).toFixed(2);
+
+    // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+    if (productData.value[idx].taxRate) {
+      productData.value[idx].taxExclusiveTotalPrice =
+        calculateTaxExclusiveTotalPrice(
+          productData.value[idx].taxInclusiveTotalPrice,
+          productData.value[idx].taxRate
+        );
+    }
+  };
+  // 鏁伴噺杈撳叆妗嗗け鐒�
+  const formatAmount = idx => {
+    if (productData.value[idx].quantity) {
+      const value = parseFloat(productData.value[idx].quantity);
+      if (!isNaN(value)) {
+        productData.value[idx].quantity = value.toFixed(2);
+      }
+    }
+    if (!productData.value[idx].taxRate) {
+      uni.showToast({
+        title: "璇峰厛閫夋嫨绋庣巼",
+        icon: "none",
+      });
+      return;
+    }
+    const quantity = parseFloat(productData.value[idx].quantity);
+    const unitPrice = parseFloat(productData.value[idx].taxInclusiveUnitPrice);
+
+    if (!quantity || quantity <= 0 || !unitPrice) {
+      return;
+    }
+    // 璁$畻鍚◣鎬讳环
+    productData.value[idx].taxInclusiveTotalPrice = (
+      unitPrice * quantity
+    ).toFixed(2);
+    // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+    if (productData.value[idx].taxRate) {
+      productData.value[idx].taxExclusiveTotalPrice =
+        calculateTaxExclusiveTotalPrice(
+          productData.value[idx].taxInclusiveTotalPrice,
+          productData.value[idx].taxRate
+        );
+    }
+  };
+  // 鍚◣鎬讳环澶辩劍锛屾牴鎹惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
+  const formatTaxTotal = idx => {
+    if (productData.value[idx].taxInclusiveTotalPrice) {
+      const value = parseFloat(productData.value[idx].taxInclusiveTotalPrice);
+      if (!isNaN(value)) {
+        productData.value[idx].taxInclusiveTotalPrice = value.toFixed(2);
+      }
+    }
+    const totalPrice = parseFloat(productData.value[idx].taxInclusiveTotalPrice);
+    const quantity = parseFloat(productData.value[idx].quantity);
+
+    if (!totalPrice || !quantity || quantity <= 0) {
+      return;
+    }
+    // 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
+    productData.value[idx].taxInclusiveUnitPrice = (
+      totalPrice / quantity
+    ).toFixed(2);
+    // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+    if (productData.value[idx].taxRate) {
+      productData.value[idx].taxExclusiveTotalPrice =
+        calculateTaxExclusiveTotalPrice(
+          totalPrice,
+          productData.value[idx].taxRate
+        );
+    }
+  };
+  // 涓嶅惈绋庢�讳环澶辩劍, 鏍规嵁涓嶅惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
+  const formatNoTaxTotal = idx => {
+    if (productData.value[idx].taxExclusiveTotalPrice) {
+      const value = parseFloat(productData.value[idx].taxExclusiveTotalPrice);
+      if (!isNaN(value)) {
+        productData.value[idx].taxExclusiveTotalPrice = value.toFixed(2);
+      }
+    }
+    if (!productData.value[idx].taxRate) {
+      uni.showToast({
+        title: "璇峰厛閫夋嫨绋庣巼",
+        icon: "none",
+      });
+      return;
+    }
+    const exclusiveTotalPrice = parseFloat(
+      productData.value[idx].taxExclusiveTotalPrice
+    );
+    const quantity = parseFloat(productData.value[idx].quantity);
+    const taxRate = parseFloat(productData.value[idx].taxRate);
+    if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
+      return;
+    }
+    // 鍏堣绠楀惈绋庢�讳环 = 涓嶅惈绋庢�讳环 / (1 - 绋庣巼/100)
+    const taxRateDecimal = taxRate / 100;
+    const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
+    productData.value[idx].taxInclusiveTotalPrice =
+      inclusiveTotalPrice.toFixed(2);
+    // 璁$畻鍚◣鍗曚环 = 鍚◣鎬讳环 / 鏁伴噺
+    productData.value[idx].taxInclusiveUnitPrice = (
+      inclusiveTotalPrice / quantity
+    ).toFixed(2);
+  };
+  const goBack = () => {
+    // 娓呯悊鏈湴瀛樺偍鐨勬暟鎹�
+    uni.removeStorageSync("operationType");
+    uni.removeStorageSync("editData");
+    uni.navigateBack();
+  };
+  const onSubmit = async () => {
+    // 棣栧厛鏍¢獙鍩烘湰琛ㄥ崟
+    const formValid = await formRef.value.validate().catch(() => false);
+    if (!formValid) {
+      return;
+    }
+
+    // 鏍¢獙浜у搧淇℃伅
+    if (!productData.value || productData.value.length === 0) {
+      uni.showToast({
+        title: "璇锋坊鍔犱骇鍝佷俊鎭�",
+        icon: "none",
+      });
+      return;
+    }
+
+    // 妫�鏌ユ瘡涓骇鍝佹槸鍚﹀~鍐欏畬鏁�
+    for (let i = 0; i < productData.value.length; i++) {
+      const product = productData.value[i];
+      // 浼樺寲鏁板瓧瀛楁楠岃瘉锛屽鐞嗗彲鑳界殑瀛楃涓叉牸寮忔暟鍊�
+      const taxInclusiveUnitPrice = parseFloat(product.taxInclusiveUnitPrice);
+      const quantity = parseFloat(product.quantity);
+      const taxInclusiveTotalPrice = parseFloat(product.taxInclusiveTotalPrice);
+      const taxExclusiveTotalPrice = parseFloat(product.taxExclusiveTotalPrice);
+
+      if (!product.productCategory) {
+        uni.showToast({
+          title: `浜у搧${i + 1}锛氳閫夋嫨浜у搧澶х被`,
+          icon: "none",
+        });
+        return;
+      }
+      if (!product.specificationModel) {
+        uni.showToast({
+          title: `浜у搧${i + 1}锛氳閫夋嫨瑙勬牸鍨嬪彿`,
+          icon: "none",
+        });
+        return;
+      }
+      if (!product.unit) {
+        uni.showToast({
+          title: `浜у搧${i + 1}锛氳杈撳叆鍗曚綅`,
+          icon: "none",
+        });
+        return;
+      }
+      if (!product.taxRate) {
+        uni.showToast({
+          title: `浜у搧${i + 1}锛氳閫夋嫨绋庣巼`,
+          icon: "none",
+        });
+        return;
+      }
+      if (isNaN(taxInclusiveUnitPrice) || taxInclusiveUnitPrice <= 0) {
+        uni.showToast({
+          title: `浜у搧${i + 1}锛氳杈撳叆鏈夋晥鐨勫惈绋庡崟浠穈,
+          icon: "none",
+        });
+        return;
+      }
+      if (isNaN(quantity) || quantity <= 0) {
+        uni.showToast({
+          title: `浜у搧${i + 1}锛氳杈撳叆鏈夋晥鐨勬暟閲廯,
+          icon: "none",
+        });
+        return;
+      }
+      if (isNaN(taxInclusiveTotalPrice) || taxInclusiveTotalPrice <= 0) {
+        uni.showToast({
+          title: `浜у搧${i + 1}锛氳杈撳叆鏈夋晥鐨勫惈绋庢�讳环`,
+          icon: "none",
+        });
+        return;
+      }
+      if (isNaN(taxExclusiveTotalPrice) || taxExclusiveTotalPrice <= 0) {
+        uni.showToast({
+          title: `浜у搧${i + 1}锛氳杈撳叆鏈夋晥鐨勪笉鍚◣鎬讳环`,
+          icon: "none",
+        });
+        return;
+      }
+      if (!product.invoiceType) {
+        uni.showToast({
+          title: `浜у搧${i + 1}锛氳閫夋嫨鍙戠エ绫诲瀷`,
+          icon: "none",
+        });
+        return;
+      }
+    }
+
+    // 琛ㄥ崟鏍¢獙閫氳繃锛屾彁浜ゆ暟鎹�
+    form.value.productData = JSON.parse(JSON.stringify(productData.value));
+    form.value.type = 1;
+    addOrUpdateSalesLedger(form.value).then(res => {
+      uni.showToast({
+        title: "鎻愪氦鎴愬姛",
+        icon: "success",
+      });
+      goBack();
+    });
+  };
+  const setUserInfo = () => {
+    form.value.entryPerson = userStore.id;
+    form.value.entryPersonName = userStore.nickName;
+    // 璁剧疆褰撳ぉ鏃ユ湡
+    const today = new Date();
+    const year = today.getFullYear();
+    const month = String(today.getMonth() + 1).padStart(2, "0");
+    const day = String(today.getDate()).padStart(2, "0");
+    form.value.entryDate = `${year}-${month}-${day}`;
+    // 璁剧疆鏃ユ湡閫夋嫨鍣ㄩ粯璁ゅ�间负浠婂ぉ
+    pickerDateValue.value = `${year}-${month}-${day}`;
+  };
+  // 濉厖琛ㄥ崟鏁版嵁锛堢紪杈戞ā寮忥級
+  const fillFormData = () => {
+    if (!editData.value) return;
+    getSalesLedgerWithProducts({ id: editData.value.id, type: 1 }).then(res => {
+      productData.value = res.productData;
+    });
+    console.log(editData.value);
+    // 濉厖鍩烘湰淇℃伅
+    form.value.salesContractNo = editData.value.salesContractNo || "";
+    form.value.customerContractNo = editData.value.customerContractNo || "";
+    form.value.customerName = editData.value.customerName || "";
+    form.value.projectName = editData.value.projectName || "";
+    form.value.executionDate = editData.value.executionDate || "";
+    form.value.paymentMethod = editData.value.paymentMethod || "";
+    form.value.salesman = editData.value.salesman || "";
+    form.value.entryPerson = editData.value.entryPerson || "";
+    form.value.entryPersonName = editData.value.entryPersonName || "";
+    form.value.entryDate = editData.value.entryDate || "";
+    form.value.id = editData.value.id || "";
+    form.value.customerId = editData.value.customerId || "";
+
+    // 璁剧疆鏃ユ湡閫夋嫨鍣ㄧ殑鍊�
+    if (editData.value.executionDate) {
+      pickerDateValue.value = editData.value.executionDate;
+    }
+  };
+  const getUserList = () => {
+    userListNoPage().then(res => {
+      // 绉婚櫎澶氫綑鐨勬暟缁勫寘瑁�
+      userList.value = res.data.map(user => ({
+        text: user.nickName,
+        value: user.nickName,
+      }));
+    });
+  };
+  const getCustomerList = () => {
+    customerList().then(res => {
+      // 绉婚櫎澶氫綑鐨勬暟缁勫寘瑁�
+      customerOption.value = res.map(item => ({
+        text: item.customerName,
+        value: item.id,
+      }));
+    });
+  };
+  const convertIdToValue = data => {
+    // 濡傛灉浼犲叆鐨勪笉鏄暟缁勶紝鍒欒繑鍥炵┖鏁扮粍
+    if (!Array.isArray(data)) {
+      return [];
+    }
+    // 閫掑綊鏄犲皠鍑芥暟
+    return data.map(item => {
+      // 鍒涘缓鏂板璞★紝鏄犲皠瀛楁
+      const mappedItem = {
+        label: item.label, // 鍏抽敭锛氬皢 label 鏄犲皠涓� text
+        id: item.id, // 淇濈暀 id
+      };
+      // 濡傛灉瀛樺湪 children 鏁扮粍锛屽垯閫掑綊澶勭悊
+      if (
+        item.children &&
+        Array.isArray(item.children) &&
+        item.children.length > 0
+      ) {
+        mappedItem.children = convertIdToValue(item.children);
+      }
+      return mappedItem;
+    });
+  };
+  // 鑾峰彇浜у搧澶х被tree鏁版嵁
+  const getProductOptions = () => {
+    productTreeList().then(res => {
+      productOptions.value = convertIdToValue(res);
+    });
+  };
+
+  onMounted(() => {
+    // 鑾峰彇椤甸潰鍙傛暟
+    operationType.value = uni.getStorageSync("operationType") || "";
+
+    // 鑾峰彇浜哄憳鍒楄〃
+    getUserList();
+    // 鑾峰彇瀹㈡埛鍒楄〃
+    getCustomerList();
+    // 鑾峰彇浜у搧澶х被tree鏁版嵁
+    getProductOptions();
+    // 璧嬪�奸粯璁や俊鎭�
+    if (operationType.value === "add") {
+      setUserInfo();
+    }
+
+    // 鑾峰彇缂栬緫鏁版嵁骞跺~鍏呰〃鍗�
+    const editDataStr = uni.getStorageSync("editData");
+    if (editDataStr) {
+      try {
+        editData.value = JSON.parse(editDataStr);
+        // 濡傛灉鏄紪杈戞ā寮忥紝绛夊緟鏁版嵁鍔犺浇瀹屾垚鍚庡~鍏呰〃鍗曟暟鎹�
+        if (operationType.value !== "add" && editData.value) {
+          // 浣跨敤 nextTick 纭繚鏁版嵁鍔犺浇瀹屾垚鍚庡啀濉厖
+          setTimeout(() => {
+            fillFormData();
+          }, 100);
+        }
+      } catch (error) {
+        console.error("瑙f瀽缂栬緫鏁版嵁澶辫触:", error);
+      }
+    }
+  });
 </script>
 
-<style scoped lang="scss">
-.account-detail {
-  min-height: 100vh;
-  background: #f8f9fa;
-  padding-bottom: 5rem;
-}
-.header {
-  display: flex;
-  align-items: center;
-  background: #fff;
-  padding: 1rem 1.25rem;
-  border-bottom: 0.0625rem solid #f0f0f0;
-  position: sticky;
-  top: 0;
-  z-index: 100;
-	/* 鍏煎 iOS 鍒樻捣/鐏靛姩宀涘畨鍏ㄥ尯 */
-	padding-top: env(safe-area-inset-top);
-}
-.title {
-  flex: 1;
-  text-align: center;
-  font-size: 1.125rem;
-  font-weight: 600;
-  color: #333;
-}
-.form-section {
-	margin-top: 1rem;
-}
-.van-field {
-	height: 3.4rem;
-}
-.van-cell {
-	align-items: center;
-}
-.product-section {
-  background: #fff;
-	margin-top: 1rem;
-  padding: 1rem;
-  box-shadow: 0 0.125rem 0.5rem rgba(0,0,0,0.04);
-}
-.section-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-bottom: 1rem;
-}
-.section-title {
-  font-size: 1rem;
-  font-weight: 600;
-  color: #333;
-}
-.add-btn {
-  border-radius: 0.25rem;
-}
-.product-card {
-	background: #FFFFFF;
-	box-shadow: 0 0 1.25rem 0 rgba(0,57,117,0.08);
-	border-radius: 0.5rem 0.5rem 0.5rem 0.5rem;
-  padding: 1rem 0.5rem 0 0.5rem;
-  position: relative;
-}
-.product-header {
-  display: flex;
-  align-items: center;
-	justify-content: space-between;
-  padding: 0 0.5rem 0.75rem 0.5rem;
-  border-bottom: 0.0625rem solid #e8e8e8;
-}
-.product-productCategory {
-  margin-left: 0.5rem;
-  font-size: 0.875rem;
-  font-weight: 500;
-  color: #333;
-}
-.info-grid {
-  display: grid;
-  grid-template-columns: 1fr 1fr;
-  gap: 0.75rem;
-  margin-bottom: 1rem;
-}
-.info-item {
-  display: flex;
-  flex-direction: column;
-  gap: 0.25rem;
-}
-.info-label {
-  font-size: 0.75rem;
-  color: #666;
-  font-weight: 400;
-}
-.info-value {
-  font-size: 0.875rem;
-  color: #333;
-  font-weight: 500;
-}
-.info-value.highlight {
-  color: #2979ff;
-  font-weight: 600;
-}
-.product-form {
-  margin-bottom: 1rem;
-}
-.del-btn {
-  border-radius: 0.25rem;
-}
-.footer-btns {
-  position: fixed;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: #fff;
-  display: flex;
-  justify-content: space-around;
-  align-items: center;
-  padding: 0.75rem 0;
-  box-shadow: 0 -0.125rem 0.5rem rgba(0,0,0,0.05);
-  z-index: 1000;
-}
-.cancel-btn {
-	font-weight: 400;
-	font-size: 1rem;
-	color: #FFFFFF;
-	width: 6.375rem;
-	background: #C7C9CC;
-	box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2);
-	border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
-}
-.save-btn {
-	font-weight: 400;
-	font-size: 1rem;
-	color: #FFFFFF;
-	width: 14rem;
-	background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%);
-	box-shadow: 0 0.25rem 0.625rem 0 rgba(3,88,185,0.2);
-	border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
-}
-
-.popup-header {
-	display: flex;
-	justify-content: space-between;
-	align-items: center;
-	padding: 1rem;
-	background: #fff;
-	position: sticky;
-	top: 0;
-	z-index: 10;
-}
-.cancelButton {
-	color: #969799
-}
-.confirmButton {
-	color: #1989FA
-}
-.u-tree {
-	height: 13rem;
-}
+<style lang="scss">
+  @import "@/static/scss/form-common.scss";
 </style>

--
Gitblit v1.9.3