import { ref, reactive, watch, onMounted } from 'vue' import { ElMessage } from 'element-plus' import { CrmService } from '@/api/crmApi' import { commonService } from '@/api/commonApi' import { vehicleService } from '@/api/vehicleApi' import { useUploadHeaders } from '@/composables/useUploadHeaders' // 类型定义 export interface BaseForm { pi_no: string biz_date: string clearance_country_id: string clearance_country_snapshot: string customer_source_id: string customer_source_snapshot: string customer_id: string customer_snapshot: string customer_country_id: string customer_country_snapshot: string declarant_name: string eta_ship_date: string shipping_method_id: string shipping_method_snapshot: string domestic_port_id: string domestic_port_snapshot: string trade_term_id: string trade_term_snapshot: string clearance_port_id: string clearance_port_snapshot: string latest_arrival_date: string pick_up_date: string collect_all_date: string contract_exchange_rate: string settlement_currency: string remark: string total_cif: number | undefined total_cif_currency: string total_cif_currency_snapshot: string is_final: string object_id: string | number contract: string contract_url?: string } export interface ItemRow { sku_id: string vin?: string _echo_vin?: boolean mileage?: number listing_price?: number | undefined listing_price_currency: string listing_price_currency_snapshot: string reduction_price?: number | undefined reduction_price_currency: string reduction_price_currency_snapshot: string model_snapshot: string color_interior_code: string color_interior_snapshot: string color_exterior_code: string color_exterior_snapshot: string unit_price: number | undefined handling_fee: string fob_transport_fee: number | undefined port_misc_fee: string ocean_freight: string ocean_freight_currency: string ocean_freight_currency_snapshot: string retrofit_fee: string total_price: number | undefined official_price: number | undefined discount_price: number | undefined fob_fee?: number | undefined fob_fee_currency: string fob_fee_currency_snapshot: string helper_fee?: number | undefined helper_fee_currency: string helper_fee_currency_snapshot: string domestic_freight?: number | undefined domestic_freight_currency: string domestic_freight_currency_snapshot: string port_fee?: number | undefined port_fee_currency: string port_fee_currency_snapshot: string unit_price_currency: string unit_price_currency_snapshot: string total_price_currency: string total_price_currency_snapshot: string guide_price_currency: string guide_price_currency_snapshot: string discount?: number | undefined discount_currency: string discount_currency_snapshot: string contract_rate?: number | undefined profit: number | undefined profit_type_snapshot?: string modify_ids: string[] modify_list: Array<{ option_id: string; option_name_snapshot: string }> modify_fee_currency: string modify_fee_currency_snapshot: string } export interface PaymentItem { remit_country_id: string remit_country_name_snapshot: string remit_date: string currency_code: string currency_name_snapshot: string account_id: string account_name_snapshot: string remitter_name: string amount: number | undefined } export interface DialogState { visible: boolean search: { keyword: string } loading: boolean tableData: any[] pagination: { currentPage: number; pageSize: number; total: number } targetIndex?: number } export function useStockingForm(isFinal = false, stockingId?: string | number) { const { uploadHeaders } = useUploadHeaders() const actionImageUplode = `${import.meta.env.VITE_API_URL}/ticket/upload?scene=stock_orders` // 选项数据 const channelOptions = ref() const countryOptions = ref() const modificationOptions = ref() const currencyOptions = ref() const accountOptions = ref() const customerOptions = ref() const portOptions = ref() const portOptionsall = ref() const wcolorOptions = ref>([]) const ncolorOptions = ref>([]) const transportOptions = ref>([]) const trade_termsOptions = ref>([]) // 表单数据 const baseForm = reactive({ pi_no: '', biz_date: '', clearance_country_id: '', clearance_country_snapshot: '', customer_source_id: '', customer_source_snapshot: '', customer_id: '', customer_snapshot: '', customer_country_id: '', customer_country_snapshot: '', declarant_name: '', eta_ship_date: '', shipping_method_id: '', shipping_method_snapshot: '', domestic_port_id: '', domestic_port_snapshot: '', trade_term_id: '', trade_term_snapshot: '', clearance_port_id: '', clearance_port_snapshot: '', latest_arrival_date: '', contract_exchange_rate: '', settlement_currency: 'CNY', remark: '', total_cif: undefined, total_cif_currency: 'CNY', total_cif_currency_snapshot: '', is_final: isFinal ? '1' : '0', object_id: stockingId || '0', contract: '', contract_url: '', pick_up_date:'', collect_all_date: '' }) // 创建新的订单项 const newItem = (): ItemRow => ({ sku_id: '', model_snapshot: '', _echo_vin: false, mileage: 0, listing_price: undefined, listing_price_currency: 'CNY', listing_price_currency_snapshot: '', reduction_price: undefined, reduction_price_currency: 'CNY', reduction_price_currency_snapshot: '', color_interior_code: '', color_interior_snapshot: '', color_exterior_code: '', color_exterior_snapshot: '', unit_price: undefined, handling_fee: '', fob_transport_fee: undefined, port_misc_fee: '', ocean_freight: '', ocean_freight_currency: 'CNY', ocean_freight_currency_snapshot: '', retrofit_fee: '', total_price: undefined, official_price: undefined, discount_price: undefined, fob_fee: undefined, fob_fee_currency: 'CNY', fob_fee_currency_snapshot: '', helper_fee: undefined, helper_fee_currency: 'CNY', helper_fee_currency_snapshot: '', domestic_freight: undefined, domestic_freight_currency: 'CNY', domestic_freight_currency_snapshot: '', port_fee: undefined, port_fee_currency: 'CNY', port_fee_currency_snapshot: '', unit_price_currency: 'CNY', unit_price_currency_snapshot: '', total_price_currency: 'CNY', total_price_currency_snapshot: '', guide_price_currency: 'CNY', guide_price_currency_snapshot: '', discount: undefined, discount_currency: 'CNY', discount_currency_snapshot: '', contract_rate: 7.16, profit: undefined, modify_ids: [], modify_list: [], modify_fee_currency: 'CNY', modify_fee_currency_snapshot: '' }) // 创建新的收款项 const newPaymentItem = (): PaymentItem => ({ remit_country_id: '', remit_country_name_snapshot: '', remit_date: '', currency_code: 'CNY', currency_name_snapshot: '', account_id: '', account_name_snapshot: '', remitter_name: '', amount: undefined }) const items = ref([newItem()]) const paymentItems = ref([newPaymentItem()]) const contractFile = ref<{ name: string; url: string; file_name: string } | null>(null) // 弹框状态 const customerDialog = reactive({ visible: false, search: { keyword: '' }, loading: false, tableData: [], pagination: { currentPage: 1, pageSize: 10, total: 0 } }) const vehicleDialog = reactive({ visible: false, search: { keyword: '' }, loading: false, tableData: [], pagination: { currentPage: 1, pageSize: 10, total: 0 }, targetIndex: -1 }) // 数据加载方法 const getgetChannel = async () => { const res = await CrmService.getChannel() channelOptions.value = res || [] } const getcustomer = async () => { const res = await commonService.getCustomerSelect() customerOptions.value = res || [] } const getarea = async () => { const res = await CrmService.getCountry() res.forEach((item: any) => { item.cn_addrs = item.cn_addr + '(' + item.en_addr + ')' }) // console.log(res) countryOptions.value = res || [] } const getmodification = async () => { const res = await commonService.getModificationSelect() modificationOptions.value = res || [] } const loadColorOptions = async () => { try { const res = await commonService.getColorSelect({ type: 1 }) wcolorOptions.value = res const response = await commonService.getColorSelect({ type: 2 }) ncolorOptions.value = response } catch (error) { console.error('获取颜色列表失败:', error) ElMessage.error('获取颜色列表失败') } } const loadAccountOptions = async () => { try { const res = await commonService.getAccountSelect() accountOptions.value = res } catch (error) { console.error('获取账户列表失败:', error) ElMessage.error('获取账户列表失败') } } const loadCurrencyOptions = async () => { try { const res = await commonService.getCurrencySelect() currencyOptions.value = res } catch (error) { console.error('获取币种列表失败:', error) ElMessage.error('获取币种列表失败') } } const loadPortOptions = async () => { try { const res = await commonService.getPortSelect({ scene: 'domestic' }) const resall = await commonService.getPortSelect({}) portOptions.value = res portOptionsall.value = resall } catch (error) { console.error('获取港口列表失败:', error) ElMessage.error('获取港口列表失败') } } const loadDictOptions = async () => { const response = await commonService.getDictSelect({ scope: '2,15' }) transportOptions.value = response.transport trade_termsOptions.value = response.trade_terms } // 币种相关方法 const getCurrencyRate = (code: string): string => { try { const found = (currencyOptions?.value || []).find((c: any) => c.currency_code === code) return found?.rate || found?.exchange_rate || '' } catch (e) { return '' } } const getCurrencyBounds = (code: string): { min: number; max: number; base: number } => { const found: any = (currencyOptions?.value || []).find((c: any) => c.currency_code === code) || {} const base = Number(found?.rate || found?.exchange_rate || 0) || 0 const up = Number(found?.float_percent_up) const down = Number(found?.float_percent_down) if (!Number.isNaN(up) || !Number.isNaN(down)) { const upPct = (Number.isNaN(up) ? 0 : up) / 100 const downPct = (Number.isNaN(down) ? 0 : down) / 100 return { min: base * (1 - downPct), max: base * (1 + upPct), base } } return { min: base * 0.9, max: base * 1.1, base } } const validateContractRate = () => { const code = baseForm.settlement_currency || items.value[0]?.unit_price_currency || 'USD' const { min, max } = getCurrencyBounds(code) const val = Number(baseForm.contract_exchange_rate) if (Number.isNaN(val)) return if (val < min) { baseForm.contract_exchange_rate = String(Number(min.toFixed(6))) ElMessage?.warning?.('合同汇率已按币种浮动下限自动纠正') } else if (val > max) { baseForm.contract_exchange_rate = String(Number(max.toFixed(6))) ElMessage?.warning?.('合同汇率已按币种浮动上限自动纠正') } } // 金额包装方法 const wrapMoney = (amount: any, currency: string, remark: string) => ({ currency: currency || '', amount: amount === undefined || amount === null ? '' : String(amount), rate: getCurrencyRate(currency), remark }) // 利润计算方法 const getRateNumber = (code: string): number => { const r = Number(getCurrencyRate(code)) return Number.isNaN(r) ? 0 : r } const convertCurrency = (amount: any, fromCode?: string, toCode?: string): number => { const val = amount === undefined || amount === null || amount === '' ? 0 : Number(amount) if (Number.isNaN(val)) return 0 const from = fromCode || 'USD' const to = toCode || 'USD' if (from === to) return val const rateFrom = getRateNumber(from) const rateTo = getRateNumber(to) || 1 if (!rateFrom) return 0 return (val * rateFrom) / rateTo } const calcProfit = (it: any): number => { const targetCurrency = baseForm.settlement_currency || 'USD' const unit = convertCurrency(it.unit_price, it.unit_price_currency, targetCurrency) const retrofit = convertCurrency(it.retrofit_fee, (it as any).modify_fee_currency, targetCurrency) const fob = convertCurrency( it.fob_transport_fee ?? (it as any).fob_fee, (it as any).fob_fee_currency, targetCurrency ) const handling = convertCurrency( it.handling_fee ?? (it as any).helper_fee, (it as any).helper_fee_currency, targetCurrency ) const port = convertCurrency( it.port_misc_fee ?? (it as any).port_fee, (it as any).port_fee_currency, targetCurrency ) const ocean = convertCurrency( it.ocean_freight ?? (it as any).ocean_freight, (it as any).ocean_freight_currency, targetCurrency ) const mileageVal = Number(it.mileage ?? 0) if (mileageVal > 0) { // 二手车:用挂牌价与二手减价替代官方指导价与优惠 const listing = convertCurrency( it.listing_price ?? (it as any).listing_price, (it as any).listing_price_currency, targetCurrency ) const reduction = convertCurrency( it.reduction_price ?? (it as any).reduction_price, (it as any).reduction_price_currency, targetCurrency ) return unit - (retrofit + fob + listing + reduction + handling + port + ocean) } // 新车/里程<=0:保持原有计算(官方指导价与优惠) const guide = convertCurrency( it.official_price ?? (it as any).guide_price, (it as any).guide_price_currency, targetCurrency ) const discount = convertCurrency( it.discount_price ?? (it as any).discount, (it as any).discount_currency, targetCurrency ) return unit - (retrofit + fob + guide + discount + handling + port + ocean) } // 合同文件相关方法 const isImageFile = (file: { name: string; url: string; file_name: string }) => { return /\.(jpg|jpeg|png|gif)$/i.test(file.name) || file.file_name.startsWith('image/') } const beforeContractUpload = (file: File) => { const isValidType = /\.(jpg|jpeg|png|gif|pdf|doc|docx|xls|xlsx|txt)$/i.test(file.name) if (!isValidType) { ElMessage.error('只能上传图片或文档文件!') return false } const isLt10M = file.size / 1024 / 1024 < 10 if (!isLt10M) { ElMessage.error('文件大小不能超过 10MB!') return false } return true } const handleContractUpload = (response: any) => { if (response.code === 200) { const fileInfo = { name: response.data.original_name || '合同文件', url: response.data.file_url, file_name: response.data.file_name } contractFile.value = fileInfo baseForm.contract = response.data.file_name ElMessage.success('合同上传成功!') } else { ElMessage.error(response.message || '合同上传失败!') } } const removeContractFile = () => { contractFile.value = null baseForm.contract = '' ElMessage.success('合同文件已删除') } // 订单项操作方法 const copyRow = (idx: number) => { const copied = JSON.parse(JSON.stringify(items.value[idx])) as ItemRow items.value.splice(idx + 1, 0, copied) } const addRowAfter = (idx: number) => { items.value.splice(idx + 1, 0, newItem()) } const removeRow = (idx: number) => { items.value.splice(idx, 1) } // 收款项操作方法 const addPaymentItem = () => { paymentItems.value.push(newPaymentItem()) } const removePaymentItem = (idx: number) => { if (paymentItems.value.length > 1) { paymentItems.value.splice(idx, 1) } } // 客户选择相关方法 const openCustomerDialog = () => { customerDialog.visible = true customerDialog.pagination.currentPage = 1 getCustomerList() } const getCustomerList = async () => { customerDialog.loading = true try { const { currentPage, pageSize } = customerDialog.pagination const params = { current: currentPage, size: pageSize, keyword: customerDialog.search.keyword } const { data, current, size, total } = await CrmService.getcustomerList(params as any) customerDialog.tableData = data || [] Object.assign(customerDialog.pagination, { currentPage: current, pageSize: size, total }) } catch (e) { } finally { customerDialog.loading = false } } const handleCustomerSizeChange = (size: number) => { customerDialog.pagination.pageSize = size getCustomerList() } const handleCustomerCurrentChange = (page: number) => { customerDialog.pagination.currentPage = page getCustomerList() } const chooseCustomer = (row: any) => { baseForm.customer_id = row.id || '' baseForm.customer_snapshot = row.contacts || row.name || '' baseForm.customer_country_id = row.country_id || '' baseForm.customer_country_snapshot = row.country_name || '' baseForm.customer_source_id = row.channel_id || '' baseForm.customer_source_snapshot = row.channel_name || '' customerDialog.visible = false } // 车辆选择相关方法 const openVehicleDialog = (index: number) => { vehicleDialog.targetIndex = index vehicleDialog.visible = true vehicleDialog.pagination.currentPage = 1 getVehicleList() } const getVehicleList = async () => { vehicleDialog.loading = true try { const { currentPage, pageSize } = vehicleDialog.pagination const params = { current: currentPage, size: pageSize, keyword: vehicleDialog.search.keyword } const { records, current, size, total } = await vehicleService.getVehicleList(params) vehicleDialog.tableData = records || [] Object.assign(vehicleDialog.pagination, { currentPage: current, pageSize: size, total }) } catch { ElMessage.error('获取车辆列表失败') } finally { vehicleDialog.loading = false } } const handleVehicleSizeChange = (size: number) => { vehicleDialog.pagination.pageSize = size getVehicleList() } const handleVehicleCurrentChange = (page: number) => { vehicleDialog.pagination.currentPage = page getVehicleList() } const chooseVehicle = (row: any) => { const idx = vehicleDialog.targetIndex if (idx !== undefined && idx >= 0 && idx < items.value.length) { const target = items.value[idx] target.sku_id = row.id || '' target.model_snapshot = row.model_name || row.name || '' target.color_exterior_code = row.color_exterior_code || '' target.color_exterior_snapshot = row.color_exterior_text || '' target.color_interior_code = row.color_interior_code || '' target.color_interior_snapshot = row.color_interior_text || '' target.official_price = row.msrp ?? target.official_price if (row.currency) { target.guide_price_currency = row.currency } } vehicleDialog.visible = false } // 数据回显方法 const populateFromDetail = (res: any) => { if (!res) return // 基础信息 baseForm.pick_up_date = res.pick_up_date || '' baseForm.collect_all_date = res.collect_all_date || '' baseForm.pi_no = res.pi_no || '' baseForm.contract = res.contract || '' baseForm.biz_date = res.biz_date || '' baseForm.clearance_country_id = res.clearance_country_id || '' baseForm.clearance_country_snapshot = res.clearance_country_snapshot || '' baseForm.customer_source_id = res.customer_source_id || '' baseForm.customer_source_snapshot = res.customer_source_snapshot || '' baseForm.customer_id = res.customer_id || '' baseForm.customer_snapshot = res.customer_snapshot || '' baseForm.customer_country_id = res.customer_country_id || '' baseForm.customer_country_snapshot = res.customer_country_snapshot || '' baseForm.declarant_name = res.declarant_name || '' baseForm.eta_ship_date = res.eta_ship_date || '' baseForm.shipping_method_id = res.shipping_method_id ? String(res.shipping_method_id) : '' baseForm.shipping_method_snapshot = res.shipping_method_snapshot || '' baseForm.domestic_port_id = res.domestic_port_id || '' baseForm.domestic_port_snapshot = res.domestic_port_snapshot || '' baseForm.trade_term_id = res.trade_term_id || '' baseForm.trade_term_snapshot = res.trade_term_snapshot || '' baseForm.clearance_port_id = res.clearance_port_id || '' baseForm.clearance_port_snapshot = res.clearance_port_snapshot || '' baseForm.latest_arrival_date = res.latest_arrival_date || '' baseForm.remark = res.remark || '' baseForm.settlement_currency = res.settlement_currency || 'CNY' // 合计与汇率 baseForm.total_cif = res.cif_total_amount ? Number(res.cif_total_amount) : undefined baseForm.total_cif_currency = res.settlement_currency || baseForm.total_cif_currency baseForm.contract_exchange_rate = res.contract_exchange_rate || getCurrencyRate(baseForm.total_cif_currency) // 明细 const list = Array.isArray(res.veh_list) ? res.veh_list : [] items.value = list.map((it: any) => ({ sku_id: it.sku_id ? String(it.sku_id) : '', vin: it.vin || '', _echo_vin: Boolean(it.vin), mileage: it.mileage ?? 0, model_snapshot: it.model_snapshot || '', listing_price: it.listing_price?.amount ? Number(it.listing_price.amount) : undefined, listing_price_currency: it.listing_price?.currency || 'CNY', listing_price_currency_snapshot: '', reduction_price: it.reduction_price?.amount ? Number(it.reduction_price.amount) : undefined, reduction_price_currency: it.reduction_price?.currency || 'CNY', reduction_price_currency_snapshot: '', color_interior_code: it.color_interior_code || '', color_interior_snapshot: it.color_interior_snapshot || '', color_exterior_code: it.color_exterior_code || '', color_exterior_snapshot: it.color_exterior_snapshot || '', unit_price: it.unit_price?.amount ? Number(it.unit_price.amount) : undefined, handling_fee: it.handling_fee?.amount ?? '', fob_transport_fee: it.fob_transport_fee?.amount ? Number(it.fob_transport_fee.amount) : undefined, port_misc_fee: it.port_misc_fee?.amount ?? '', ocean_freight: it.ocean_freight?.amount ?? '', ocean_freight_currency: it.ocean_freight?.currency || 'CNY', ocean_freight_currency_snapshot: '', retrofit_fee: it.retrofit_fee?.amount ?? '', total_price: it.total_price?.amount ? Number(it.total_price.amount) : undefined, official_price: it.official_price?.amount ? Number(it.official_price.amount) : undefined, discount_price: it.discount_price?.amount ? Number(it.discount_price.amount) : undefined, fob_fee: undefined, fob_fee_currency: it.fob_transport_fee?.currency || 'CNY', fob_fee_currency_snapshot: '', helper_fee: undefined, helper_fee_currency: it.handling_fee?.currency || 'CNY', helper_fee_currency_snapshot: '', domestic_freight: undefined, domestic_freight_currency: it.domestic_freight?.currency || 'CNY', domestic_freight_currency_snapshot: '', port_fee: undefined, port_fee_currency: it.port_misc_fee?.currency || 'CNY', port_fee_currency_snapshot: '', unit_price_currency: it.unit_price?.currency || 'CNY', unit_price_currency_snapshot: '', total_price_currency: it.total_price?.currency || 'CNY', total_price_currency_snapshot: '', guide_price_currency: it.official_price?.currency || 'CNY', guide_price_currency_snapshot: '', discount: undefined, discount_currency: it.discount_price?.currency || 'CNY', discount_currency_snapshot: '', contract_rate: baseForm.contract_exchange_rate ? Number(baseForm.contract_exchange_rate) : undefined, profit: undefined, profit_type_snapshot: '', modify_ids: Array.isArray(it.modify_list) ? it.modify_list.map((m: any) => Number(m.option_id)) : [], modify_list: Array.isArray(it.modify_list) ? it.modify_list.map((m: any) => ({ option_id: String(m.option_id), option_name_snapshot: m.option_name_snapshot })) : [], modify_fee_currency: it.retrofit_fee?.currency || 'CNY', modify_fee_currency_snapshot: '' })) // 计划收款 const pays = Array.isArray(res.account_list) ? res.account_list : [] paymentItems.value = pays.map((p: any) => ({ remit_country_id: p.remit_country_id ? Number(p.remit_country_id) : '', remit_country_name_snapshot: p.remit_country_name_snapshot || '', remit_date: p.remit_date || '', currency_code: p.currency_code || '', currency_name_snapshot: p.currency_name_snapshot || '', account_id: p.account_id ? p.account_id : '', account_name_snapshot: p.account_name_snapshot || '', remitter_name: p.remitter_name || '', amount: p.amount ? Number(p.amount) : undefined })) // 合同文件回显 if (res.contract) { contractFile.value = { name: '合同文件', url: res.contract_url || res.contract, file_name: res.contract } } } // 提交方法 const handleSubmit = async (type: number, edit?: string, isfinal?: string) => { // 提交校验:最终提交且为提交动作时(type=1),必须填写 VIN const isFinalFlag = isfinal === '1' || (isfinal as any) === true if (isFinalFlag && type === 1) { const hasEmptyVin = (items.value || []).some((it) => !it.vin || String(it.vin).trim() === '') if (hasEmptyVin) { ElMessage.error('存在未填写车架号(VIN)的明细,请补全后再提交') return } } const mappedItems = items.value.map((it) => ({ sku_id: it.sku_id, vin: it.vin || '', mileage: it.mileage, model_snapshot: it.model_snapshot, color_interior_code: it.color_interior_code, color_interior_snapshot: it.color_interior_snapshot, color_exterior_code: it.color_exterior_code, color_exterior_snapshot: it.color_exterior_snapshot, unit_price: wrapMoney(it.unit_price, (it as any).unit_price_currency, '单价'), handling_fee: wrapMoney(it.handling_fee, (it as any).helper_fee_currency, '手续费'), fob_transport_fee: wrapMoney( it.fob_transport_fee ?? (it as any).fob_fee, (it as any).fob_fee_currency, 'FOB运输费' ), port_misc_fee: wrapMoney( it.port_misc_fee ?? (it as any).port_fee, (it as any).port_fee_currency, '港杂费' ), ocean_freight: wrapMoney(it.ocean_freight, (it as any).ocean_freight_currency, '海运费'), retrofit_fee: wrapMoney((it as any).retrofit_fee, (it as any).modify_fee_currency, '改装费'), modify_list: it.modify_list, // total_price: wrapMoney(it.total_price, (it as any).total_price_currency, '总价'), total_price: wrapMoney(it.unit_price, (it as any).unit_price_currency, '总价'), official_price: wrapMoney( (it as any).official_price ?? (it as any).guide_price, (it as any).guide_price_currency, '官方指导价' ), discount_price: wrapMoney( (it as any).discount_price ?? (it as any).discount, (it as any).discount_currency, '优惠额' ), listing_price: wrapMoney(it.listing_price, (it as any).listing_price_currency, '挂牌价'), reduction_price: wrapMoney(it.reduction_price, (it as any).reduction_price_currency, '二手减价') })) // 从提交参数中移除 settlement_currency const baseFormWithoutCur = { ...(baseForm as any) } delete (baseFormWithoutCur as any).total_cif delete (baseFormWithoutCur as any).total_cif_currency delete (baseFormWithoutCur as any).total_cif_currency_snapshot delete (baseFormWithoutCur as any).contract_url const payload = { ...baseFormWithoutCur, veh_list: mappedItems, account_list: paymentItems.value, approval_status: type } try { if (edit) { const { message } = await CrmService.editStock({ ...payload, id: edit } as any) ElMessage.success(message || '保存成功') } else { const { message } = await CrmService.addStock(payload as any) ElMessage.success(message || '保存成功') } setTimeout(() => { if (isfinal == '1') { window.location.href = '/crmpc/stocking/final_list' } else { window.location.href = '/crmpc/stocking/stocking_list' } }, 1000) } catch (e) { ElMessage.error('保存失败') } } // 监听器 watch( () => baseForm.settlement_currency, (newCurrency) => { if (newCurrency) { baseForm.contract_exchange_rate = getCurrencyRate(newCurrency) if (typeof validateContractRate === 'function') { validateContractRate() } // 结算币种变化时,按新币种重算所有行利润 (items.value || []).forEach((it: any, index: number) => { const profit = calcProfit(it) if (items.value[index]) items.value[index].profit = isNaN(profit) ? 0 : Number(profit.toFixed(2)) }) } } ) watch( () => baseForm.contract_exchange_rate, (newCurrency) => { if (newCurrency) { if (typeof validateContractRate === 'function') { validateContractRate() } } } ) watch( items, (val) => { val.forEach((it: any, index: number) => { const profit = calcProfit(it) if (items.value[index]) items.value[index].profit = isNaN(profit) ? 0 : Number(profit.toFixed(2)) }) // 合计到岸价 = 所有单价相加 const sum = (val || []).reduce((acc: number, cur: any) => { const n = cur?.unit_price === undefined || cur?.unit_price === null || cur?.unit_price === '' ? 0 : Number(cur.unit_price) return acc + (isNaN(n) ? 0 : n) }, 0) baseForm.total_cif = Number(sum.toFixed(2)) // 同步合计币种为第一行单价币种(若有) if (items.value.length > 0) { const c = items.value[0]?.unit_price_currency if (c) baseForm.total_cif_currency = c } }, { deep: true } ) // 初始化方法 const initializeForm = async () => { await Promise.all([ getcustomer(), loadCurrencyOptions(), getgetChannel(), getarea(), getmodification(), loadColorOptions(), loadAccountOptions(), loadPortOptions(), loadDictOptions() ]) // 设置默认汇率 baseForm.contract_exchange_rate = getCurrencyRate('CNY') // 设置预计发送日默认为当天 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') baseForm.biz_date = `${year}-${month}-${day}` } return { // 数据 baseForm, items, paymentItems, contractFile, customerDialog, vehicleDialog, // 选项数据 channelOptions, countryOptions, modificationOptions, currencyOptions, accountOptions, customerOptions, portOptions, portOptionsall, wcolorOptions, ncolorOptions, transportOptions, trade_termsOptions, // 上传相关 actionImageUplode, uploadHeaders, // 方法 initializeForm, populateFromDetail, handleSubmit, getCurrencyRate, validateContractRate, wrapMoney, calcProfit, // 合同文件方法 isImageFile, beforeContractUpload, handleContractUpload, removeContractFile, // 订单项方法 copyRow, addRowAfter, removeRow, newItem, // 收款项方法 addPaymentItem, removePaymentItem, newPaymentItem, // 客户选择方法 openCustomerDialog, getCustomerList, handleCustomerSizeChange, handleCustomerCurrentChange, chooseCustomer, // 车辆选择方法 openVehicleDialog, getVehicleList, handleVehicleSizeChange, handleVehicleCurrentChange, chooseVehicle } }