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