From dc63a926bd3fff4fda282b88b203072a8874962a Mon Sep 17 00:00:00 2001 From: gaoluyang <2820782392@qq.com> Date: 星期二, 12 八月 2025 17:45:05 +0800 Subject: [PATCH] 1.销售台账列表开发联调 2.新增、编辑销售台账页面开发联调 --- src/pages/sales/salesAccount/detail.vue | 983 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 800 insertions(+), 183 deletions(-) diff --git a/src/pages/sales/salesAccount/detail.vue b/src/pages/sales/salesAccount/detail.vue index 098c609..56c92a9 100644 --- a/src/pages/sales/salesAccount/detail.vue +++ b/src/pages/sales/salesAccount/detail.vue @@ -6,244 +6,841 @@ <text class="title">鍙拌处璇︽儏</text> </view> - <!-- 琛ㄥ崟鍖哄煙 --> - <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> - - <!-- 浜у搧淇℃伅 --> - <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> + <!-- 琛ㄥ崟鍖哄煙 --> + <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="浜у搧澶х被" + 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> </view> </template> <script setup> -import { ref } from 'vue'; -const goBack = () => { - uni.navigateBack(); -}; -const formRef = ref(); -const paymentMethods = ['瀵瑰叕杞处', '鐜伴噾', '鍏朵粬']; +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"; + +// 鑾峰彇椤甸潰鍙傛暟 +const operationType = ref(''); +const editData = 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 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 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 = () => { - products.value.push({ - type: '', + productData.value.push({ + productCategory: '', + specificationModel: '', + productModelId: '', unit: '', - amount: '', taxRate: '', - taxPrice: '', - taxTotal: '', - contractAmount: '', - operateDate: '', - remark: '', + taxInclusiveUnitPrice: '', + quantity: '', + taxInclusiveTotalPrice: '', + taxExclusiveTotalPrice: '', + invoiceType: '' }); +}; +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) => { - 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 = '' + 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); + } + } + 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 = () => { + 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]; + } + } + + // 璁剧疆瀹㈡埛閫夋嫨鍣ㄧ殑鍊� + if (editData.value.customerName) { + const customerIndex = customerOption.value.findIndex(customer => customer.text === editData.value.customerName); + if (customerIndex !== -1) { + pickerCustomerValue.value = [customerOption.value[customerIndex].value] + } + } + + // 璁剧疆鏃ユ湡閫夋嫨鍣ㄧ殑鍊� + 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); + } + } +}); </script> <style scoped lang="scss"> .account-detail { min-height: 100vh; background: #f8f9fa; - padding-bottom: 80px; + padding-bottom: 5rem; } .header { display: flex; align-items: center; background: #fff; - padding: 16px 20px; - border-bottom: 1px solid #f0f0f0; + 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: 18px; + font-size: 1.125rem; font-weight: 600; color: #333; } .form-section { - margin-top: 16px; + margin-top: 1rem; } .van-field { - height: 56px; - line-height: 36px; + height: 3.4rem; +} +.van-cell { + align-items: center; } .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); + 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: 12px; + margin-bottom: 1rem; } .section-title { - font-size: 16px; + font-size: 1rem; font-weight: 600; color: #333; } .add-btn { - background: #2979ff; - color: #fff; - border-radius: 8px; - padding: 4px 16px; - font-size: 14px; + border-radius: 0.25rem; } .product-card { - background: #f8f9fa; - border-radius: 12px; - padding: 12px; - margin-bottom: 16px; - box-shadow: 0 1px 4px rgba(41,121,255,0.06); + 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-row { +.product-header { display: flex; align-items: center; - margin-bottom: 8px; + justify-content: space-between; + padding: 0 0.5rem 0.75rem 0.5rem; + border-bottom: 0.0625rem solid #e8e8e8; } -.product-label { - min-width: 60px; - color: #888; - font-size: 13px; +.product-productCategory { + margin-left: 0.5rem; + font-size: 0.875rem; + font-weight: 500; + color: #333; } -.del-row { - justify-content: flex-end; +.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 { - background: #ff4d4f; - color: #fff; - border-radius: 8px; - padding: 4px 16px; - font-size: 13px; - margin-top: 4px; + border-radius: 0.25rem; } .footer-btns { position: fixed; @@ -254,26 +851,46 @@ display: flex; justify-content: space-around; align-items: center; - padding: 12px 0; - box-shadow: 0 -2px 8px rgba(0,0,0,0.05); + 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: 16px; + font-size: 1rem; color: #FFFFFF; - width: 102px; + width: 6.375rem; background: #C7C9CC; - box-shadow: 0px 4px 10px 0px rgba(3,88,185,0.2); - border-radius: 40px 40px 40px 40px; + 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: 16px; + font-size: 1rem; color: #FFFFFF; - width: 224px; + width: 14rem; 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; + 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> -- Gitblit v1.9.3