From 77861fcc5ee1c4f8e7c6412b373cb438c7313930 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 03 九月 2025 10:06:26 +0800
Subject: [PATCH] 头部样式修改、适配不同机型

---
 src/pages/sales/salesAccount/detail.vue | 1218 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 964 insertions(+), 254 deletions(-)

diff --git a/src/pages/sales/salesAccount/detail.vue b/src/pages/sales/salesAccount/detail.vue
index 098c609..e082ecb 100644
--- a/src/pages/sales/salesAccount/detail.vue
+++ b/src/pages/sales/salesAccount/detail.vue
@@ -1,279 +1,989 @@
 <template>
   <view class="account-detail">
-    <!-- 椤堕儴鏍囬鏍� -->
-    <view class="header">
-      <up-icon name="arrow-left" size="20" color="#333" @click="goBack" />
-      <text class="title">鍙拌处璇︽儏</text>
-    </view>
+    <!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
+		<PageHeader title="鍙拌处璇︽儏" @back="goBack" />
 
-    <!-- 琛ㄥ崟鍖哄煙 -->
-    <view class="form-section">
-      <van-form ref="formRef" :modelValue="form" :rules="rules" label-width="100px" input-align="right">
-        <van-field label="閿�鍞悎鍚屽彿" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="璇疯緭鍏ラ攢鍞悎鍚屽彿">
-        </van-field>
-				<van-field label="閿�鍞悎鍚屽彿" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="璇疯緭鍏ラ攢鍞悎鍚屽彿">
-				</van-field>
-				<van-field label="閿�鍞悎鍚屽彿" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="璇疯緭鍏ラ攢鍞悎鍚屽彿">
-				</van-field>
-				<van-field label="閿�鍞悎鍚屽彿" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="璇疯緭鍏ラ攢鍞悎鍚屽彿">
-				</van-field>
-				<van-field label="閿�鍞悎鍚屽彿" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="璇疯緭鍏ラ攢鍞悎鍚屽彿">
-				</van-field>
-				<van-field label="閿�鍞悎鍚屽彿" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="璇疯緭鍏ラ攢鍞悎鍚屽彿">
-				</van-field>
-				<van-field label="褰曞叆浜�" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="璇疯緭鍏�" readonly>
-				</van-field>
-				<van-field label="褰曞叆鏃ユ湡" name="salesContractNo" borderBottom="true" v-model="form.salesContractNo" placeholder="璇疯緭鍏�" readonly>
-				</van-field>
-      </van-form>
-    </view>
+         <!-- 琛ㄥ崟鍖哄煙 -->
+		<up-form @submit="onSubmit" label-width="110" ref="formRef" :rules="rules" :model="form">
 
-    <!-- 浜у搧淇℃伅 -->
-    <view class="product-section">
-      <view class="section-header">
-        <text class="section-title">浜у搧淇℃伅</text>
-        <button class="add-btn" @click="addProduct">鏂板</button>
-      </view>
-      <view class="product-card" v-for="(product, idx) in products" :key="idx">
-        <view class="product-row">
-          <text class="product-label">浜у搧绫�</text>
-          <uni-easyinput v-model="product.type" placeholder="璇疯緭鍏ヤ骇鍝佺被" />
-        </view>
-        <view class="product-row">
-          <text class="product-label">鍗曚綅</text>
-          <uni-easyinput v-model="product.unit" placeholder="璇疯緭鍏ュ崟浣�" />
-          <text class="product-label">鏁伴噺</text>
-          <uni-easyinput v-model="product.amount" placeholder="璇疯緭鍏ユ暟閲�" type="number" />
-        </view>
-        <view class="product-row">
-          <text class="product-label">绋庣巼</text>
-          <uni-easyinput v-model="product.taxRate" placeholder="璇疯緭鍏ョ◣鐜�" />
-          <text class="product-label">鍚◣鍗曚环</text>
-          <uni-easyinput v-model="product.taxPrice" placeholder="璇疯緭鍏ュ惈绋庡崟浠�" />
-        </view>
-        <view class="product-row">
-          <text class="product-label">鍚◣鎬讳环</text>
-          <uni-easyinput v-model="product.taxTotal" placeholder="璇疯緭鍏ュ惈绋庢�讳环" />
-          <text class="product-label">鍚堝悓閲戦</text>
-          <uni-easyinput v-model="product.contractAmount" placeholder="璇疯緭鍏ュ悎鍚岄噾棰�" />
-        </view>
-        <view class="product-row">
-          <text class="product-label">鎿嶄綔</text>
-          <uni-easyinput v-model="product.operateDate" placeholder="璇疯緭鍏ユ搷浣滄椂闂�" />
-        </view>
-        <view class="product-row">
-          <text class="product-label">澶囨敞</text>
-          <uni-easyinput v-model="product.remark" placeholder="璇疯緭鍏ュ娉�" />
-        </view>
-        <view class="product-row del-row">
-          <button class="del-btn" @click="removeProduct(idx)">鍒犻櫎</button>
-        </view>
-      </view>
-    </view>
-
-    <!-- 搴曢儴鎸夐挳 -->
-    <view class="footer-btns">
-      <van-button class="cancel-btn" @click="goBack">鍙栨秷</van-button>
-      <van-button class="save-btn" @click="submitForm">淇濆瓨</van-button>
-    </view>
+			<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
+							:rules="productRules"
+						>
+							<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
+							:rules="productRules"
+						>
+							<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="unit"
+							required
+							:rules="productRules"
+						>
+							<up-input
+								v-model="product.unit"
+								placeholder="璇疯緭鍏�"
+							/>
+						</up-form-item>
+						
+						<!-- 绋庣巼 -->
+						<up-form-item
+							label="绋庣巼(%)"
+							prop="taxRate"
+							required
+							:rules="productRules"
+						>
+							<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
+							:rules="productRules"
+						>
+							<up-input
+								v-model="product.taxInclusiveUnitPrice"
+								type="number"
+								placeholder="璇疯緭鍏�"
+								@blur="formatTaxPrice(idx)"
+							/>
+						</up-form-item>
+						
+						<!-- 鏁伴噺 -->
+						<up-form-item
+							label="鏁伴噺"
+							prop="quantity"
+							required
+							:rules="productRules"
+						>
+							<up-input
+								v-model="product.quantity"
+								type="number"
+								placeholder="璇疯緭鍏�"
+								@blur="formatAmount(idx)"
+							/>
+						</up-form-item>
+						
+						<!-- 鍚◣鎬讳环 -->
+						<up-form-item
+							label="鍚◣鎬讳环(鍏�)"
+							prop="taxInclusiveTotalPrice"
+							required
+							:rules="productRules"
+						>
+							<up-input
+								v-model="product.taxInclusiveTotalPrice"
+								type="number"
+								placeholder="璇疯緭鍏�"
+								@blur="formatTaxTotal(idx)"
+							/>
+						</up-form-item>
+						
+						<!-- 涓嶅惈绋庢�讳环 -->
+						<up-form-item
+							label="涓嶅惈绋庢�讳环(鍏�)"
+							prop="taxExclusiveTotalPrice"
+							required
+							:rules="productRules"
+						>
+							<up-input
+								v-model="product.taxExclusiveTotalPrice"
+								type="number"
+								placeholder="璇疯緭鍏�"
+								@blur="formatNoTaxTotal(idx)"
+							/>
+						</up-form-item>
+						
+						<!-- 鍙戠エ绫诲瀷 -->
+						<up-form-item
+							label="鍙戠エ绫诲瀷"
+							prop="invoiceType"
+							required
+							:rules="productRules"
+						>
+							<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 { ref } from 'vue';
-const goBack = () => {
-  uni.navigateBack();
-};
-const formRef = ref();
-const paymentMethods = ['瀵瑰叕杞处', '鐜伴噾', '鍏朵粬'];
+import {onMounted, ref, computed} from 'vue';
+import {userListNoPage} from "@/api/system/user";
+import { formatDateToYMD } from '@/utils/ruoyi'
+import {
+	addOrUpdateSalesLedger,
+	addOrUpdateSalesLedgerProduct,
+	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 formRef = ref(null);
+
+const userStore = useUserStore()
 const form = ref({
+	id: '',
   salesContractNo: '',
-  customerContract: '',
-  projectName: '',
-  contractAmount: '',
-  executionDate: '',
+	customerContractNo: '',
+	customerId: '',
+	customerName: '',
+	projectName: '',
+	executionDate: '',
   paymentMethod: '',
+	entryPerson: '',
+	entryPersonName: '',
+	entryDate: '',
 });
-const rules = {
-  salesContractNo: {
-    rules: [{ required: true, errorMessage: '閿�鍞悎鍚屽彿涓嶈兘涓虹┖' }]
-  },
-  customerContract: {
-    rules: [{ required: true, errorMessage: '瀹㈡埛鍚堝悓涓嶈兘涓虹┖' }]
-  },
-  projectName: {
-    rules: [{ required: true, errorMessage: '椤圭洰鍚嶇О涓嶈兘涓虹┖' }]
-  },
-  contractAmount: {
-    rules: [{ required: true, errorMessage: '鍚堝悓閲戦涓嶈兘涓虹┖' }]
-  },
-  executionDate: {
-    rules: [{ required: true, errorMessage: '绛捐鏃ユ湡涓嶈兘涓虹┖' }]
-  },
-  paymentMethod: {
-    rules: [{ required: true, errorMessage: '璇烽�夋嫨浠樻鏂瑰紡' }]
-  }
+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 (type === 'month') {
+		return `${value}`;
+	}
+	if (type === 'day') {
+		return `${value}`;
+	}
+	return value;
 };
-const products = ref([
-  {
-    type: 'LS-29911',
-    unit: '鍛ㄥ簞闀�',
-    amount: '86590905972612',
-    taxRate: '杩欓噷鏄」鐩悕绉�',
-    taxPrice: '杩欓噷鏄」鐩悕绉�',
-    taxTotal: '杩欓噷鏄」鐩悕绉�',
-    contractAmount: '32011鍏�',
-    operateDate: '2022-02-22 11:30:50',
-    remark: '',
-  },
-  {
-    type: 'LS-29911',
-    unit: '鍛ㄥ簞闀�',
-    amount: '86590905972612',
-    taxRate: '杩欓噷鏄」鐩悕绉�',
-    taxPrice: '杩欓噷鏄」鐩悕绉�',
-    taxTotal: '杩欓噷鏄」鐩悕绉�',
-    contractAmount: '32011鍏�',
-    operateDate: '2022-02-22 11:30:50',
-    remark: '',
-  },
+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
+	}))
+})
+
+// 绋庣巼閫夋嫨鍒楄〃
+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: 'blur' }
+	],
+	customerContractNo: [
+		{ required: true, message: '璇疯緭鍏ュ鎴峰悎鍚屽彿', trigger: 'blur' }
+	],
+	customerName: [
+		{ required: true, message: '璇烽�夋嫨瀹㈡埛鍚嶇О', trigger: 'blur' }
+	],
+	projectName: [
+		{ required: true, message: '璇疯緭鍏ラ」鐩悕绉�', trigger: 'blur' }
+	],
+	executionDate: [
+		{ required: true, message: '璇烽�夋嫨绛捐鏃ユ湡', trigger: 'blur' }
+	]
+};
+
+// 浜у搧淇℃伅鏍¢獙瑙勫垯
+const productRules = {
+	productCategory: [
+		{ required: true, message: '璇烽�夋嫨浜у搧澶х被', trigger: 'blur' }
+	],
+	specificationModel: [
+		{ required: true, message: '璇烽�夋嫨瑙勬牸鍨嬪彿', trigger: 'blur' }
+	],
+	unit: [
+		{ required: true, message: '璇疯緭鍏ュ崟浣�', trigger: 'blur' }
+	],
+	taxRate: [
+		{ required: true, message: '璇烽�夋嫨绋庣巼', trigger: 'blur' }
+	],
+	taxInclusiveUnitPrice: [
+		{ required: true, message: '璇疯緭鍏ュ惈绋庡崟浠�', trigger: 'blur' },
+		{ type: 'number', min: 0, message: '鍚◣鍗曚环蹇呴』澶т簬0', trigger: 'blur' }
+	],
+	quantity: [
+		{ required: true, message: '璇疯緭鍏ユ暟閲�', trigger: 'blur' },
+		{ type: 'number', min: 0, message: '鏁伴噺蹇呴』澶т簬0', trigger: 'blur' }
+	],
+	taxInclusiveTotalPrice: [
+		{ required: true, message: '璇疯緭鍏ュ惈绋庢�讳环', trigger: 'blur' },
+		{ type: 'number', min: 0, message: '鍚◣鎬讳环蹇呴』澶т簬0', trigger: 'blur' }
+	],
+	taxExclusiveTotalPrice: [
+		{ required: true, message: '璇疯緭鍏ヤ笉鍚◣鎬讳环', trigger: 'blur' },
+		{ type: 'number', min: 0, message: '涓嶅惈绋庢�讳环蹇呴』澶т簬0', trigger: 'blur' }
+	],
+	invoiceType: [
+		{ required: true, message: '璇烽�夋嫨鍙戠エ绫诲瀷', trigger: 'blur' }
+	]
+};
+
 const addProduct = () => {
-  products.value.push({
-    type: '',
+	if (productData.value === null) {
+		productData.value = []
+	}
+	productData.value.push({
+    productCategory: '',
+    specificationModel: '',
+		productModelId: '',
     unit: '',
-    amount: '',
     taxRate: '',
-    taxPrice: '',
-    taxTotal: '',
-    contractAmount: '',
-    operateDate: '',
-    remark: '',
+    taxInclusiveUnitPrice: '',
+    quantity: '',
+    taxInclusiveTotalPrice: '',
+    taxExclusiveTotalPrice: '',
+    invoiceType: ''
   });
 };
+// 涓氬姟鍛橀�夋嫨浜嬩欢
+const onSalesmanSelect = (item) => {
+	form.value.salesman = item.name
+}
+
+// 鏃ユ湡纭浜嬩欢
+const onDateConfirm = (e) => {
+	form.value.executionDate = formatDateToYMD(e.value)
+	pickerDateValue.value = formatDateToYMD(e.value)
+	showDatePicker.value = false;
+}
+
+// 瀹㈡埛閫夋嫨浜嬩欢
+const onCustomerSelect = (item) => {
+	form.value.customerName = item.name
+	form.value.customerId = item.value
+}
+
+// 鍘熸湁鐨勭‘璁ゆ柟娉曞凡琚柊鐨刟ction-sheet閫夋嫨鏂规硶鏇夸唬
 const removeProduct = (idx) => {
-  products.value.splice(idx, 1);
+	productData.value.splice(idx, 1);
 };
-const submitForm = () => {
-  formRef.value.validate().then(() => {
-    uni.showToast({ title: '淇濆瓨鎴愬姛', icon: 'success' });
-  });
+
+// 鏄剧ず閫夋嫨鍣�
+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)
+	}
+	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,
+		}));
+	});
+};
+// 瑙勬牸鍨嬪彿閫夋嫨浜嬩欢
+const onSpecificationSelect = (item) => {
+	productData.value[currentProductIndex.value].specificationModel = item.name
+	productData.value[currentProductIndex.value].productModelId = item.value
+	productData.value[currentProductIndex.value].unit = item.unit
+}
+// 绋庣巼閫夋嫨浜嬩欢
+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)
+	}
+};
+
+// 鍙戠エ绫诲瀷閫夋嫨浜嬩欢
+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[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 (!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);
+    }
+  }
+	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);
+    }
+  }
+	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 = 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 errors = validateProduct(productData.value[i], i);
+		if (errors.length > 0) {
+			uni.showToast({
+				title: errors[0],
+				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);
+	});
+};
+// 鍗曚釜浜у搧琛ㄥ崟楠岃瘉鍑芥暟
+const validateProduct = (product, index) => {
+	const errors = [];
+	
+	if (!product.productCategory) {
+		errors.push(`浜у搧${index + 1}锛氳閫夋嫨浜у搧澶х被`);
+	}
+	if (!product.specificationModel) {
+		errors.push(`浜у搧${index + 1}锛氳閫夋嫨瑙勬牸鍨嬪彿`);
+	}
+	if (!product.unit) {
+		errors.push(`浜у搧${index + 1}锛氳杈撳叆鍗曚綅`);
+	}
+	if (!product.taxRate) {
+		errors.push(`浜у搧${index + 1}锛氳閫夋嫨绋庣巼`);
+	}
+	if (!product.taxInclusiveUnitPrice || parseFloat(product.taxInclusiveUnitPrice) <= 0) {
+		errors.push(`浜у搧${index + 1}锛氳杈撳叆鏈夋晥鐨勫惈绋庡崟浠穈);
+	}
+	if (!product.quantity || parseFloat(product.quantity) <= 0) {
+		errors.push(`浜у搧${index + 1}锛氳杈撳叆鏈夋晥鐨勬暟閲廯);
+	}
+	if (!product.taxInclusiveTotalPrice || parseFloat(product.taxInclusiveTotalPrice) <= 0) {
+		errors.push(`浜у搧${index + 1}锛氳杈撳叆鏈夋晥鐨勫惈绋庢�讳环`);
+	}
+	if (!product.taxExclusiveTotalPrice || parseFloat(product.taxExclusiveTotalPrice) <= 0) {
+		errors.push(`浜у搧${index + 1}锛氳杈撳叆鏈夋晥鐨勪笉鍚◣鎬讳环`);
+	}
+	if (!product.invoiceType) {
+		errors.push(`浜у搧${index + 1}锛氳閫夋嫨鍙戠エ绫诲瀷`);
+	}
+	
+	return errors;
+};
+
+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: 80px;
-}
-.header {
-  display: flex;
-  align-items: center;
-  background: #fff;
-  padding: 16px 20px;
-  border-bottom: 1px solid #f0f0f0;
-  position: sticky;
-  top: 0;
-  z-index: 100;
-}
-.title {
-  flex: 1;
-  text-align: center;
-  font-size: 18px;
-  font-weight: 600;
-  color: #333;
-}
-.form-section {
-	margin-top: 16px;
-}
-.van-field {
-	height: 56px;
-	line-height: 36px;
-}
-.product-section {
-  background: #fff;
-  margin: 16px;
-  border-radius: 16px;
-  padding: 20px 16px 8px 16px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
-}
-.section-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-bottom: 12px;
-}
-.section-title {
-  font-size: 16px;
-  font-weight: 600;
-  color: #333;
-}
-.add-btn {
-  background: #2979ff;
-  color: #fff;
-  border-radius: 8px;
-  padding: 4px 16px;
-  font-size: 14px;
-}
-.product-card {
-  background: #f8f9fa;
-  border-radius: 12px;
-  padding: 12px;
-  margin-bottom: 16px;
-  box-shadow: 0 1px 4px rgba(41,121,255,0.06);
-  position: relative;
-}
-.product-row {
-  display: flex;
-  align-items: center;
-  margin-bottom: 8px;
-}
-.product-label {
-  min-width: 60px;
-  color: #888;
-  font-size: 13px;
-}
-.del-row {
-  justify-content: flex-end;
-}
-.del-btn {
-  background: #ff4d4f;
-  color: #fff;
-  border-radius: 8px;
-  padding: 4px 16px;
-  font-size: 13px;
-  margin-top: 4px;
-}
-.footer-btns {
-  position: fixed;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: #fff;
-  display: flex;
-  justify-content: space-around;
-  align-items: center;
-  padding: 12px 0;
-  box-shadow: 0 -2px 8px rgba(0,0,0,0.05);
-  z-index: 1000;
-}
-.cancel-btn {
-	font-weight: 400;
-	font-size: 16px;
-	color: #FFFFFF;
-	width: 102px;
-	background: #C7C9CC;
-	box-shadow: 0px 4px 10px 0px rgba(3,88,185,0.2);
-	border-radius: 40px 40px 40px 40px;
-}
-.save-btn {
-	font-weight: 400;
-	font-size: 16px;
-	color: #FFFFFF;
-	width: 224px;
-	background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%);
-	box-shadow: 0px 4px 10px 0px rgba(3,88,185,0.2);
-	border-radius: 40px 40px 40px 40px;
-}
+<style lang="scss">
+@import '@/static/scss/form-common.scss';
 </style>

--
Gitblit v1.9.3