2025-09-08 19:09:55 +08:00
|
|
|
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
|
2025-09-10 18:11:39 +08:00
|
|
|
pick_up_date: string
|
|
|
|
|
collect_all_date: string
|
2025-09-08 19:09:55 +08:00
|
|
|
contract_exchange_rate: string
|
2025-09-11 17:44:37 +08:00
|
|
|
settlement_currency: string
|
2025-09-08 19:09:55 +08:00
|
|
|
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
|
2025-09-15 17:14:38 +08:00
|
|
|
_echo_vin?: boolean
|
2025-09-08 19:09:55 +08:00
|
|
|
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
|
2025-09-10 18:11:39 +08:00
|
|
|
ocean_freight: string
|
|
|
|
|
ocean_freight_currency: string
|
|
|
|
|
ocean_freight_currency_snapshot: string
|
2025-09-08 19:09:55 +08:00
|
|
|
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<any>()
|
|
|
|
|
const countryOptions = ref<any>()
|
|
|
|
|
const modificationOptions = ref<any>()
|
|
|
|
|
const currencyOptions = ref<any>()
|
|
|
|
|
const accountOptions = ref<any>()
|
|
|
|
|
const customerOptions = ref<any>()
|
|
|
|
|
const portOptions = ref<any>()
|
|
|
|
|
const portOptionsall = ref<any>()
|
|
|
|
|
const wcolorOptions = ref<Array<any>>([])
|
|
|
|
|
const ncolorOptions = ref<Array<any>>([])
|
|
|
|
|
const transportOptions = ref<Array<any>>([])
|
|
|
|
|
const trade_termsOptions = ref<Array<any>>([])
|
|
|
|
|
|
|
|
|
|
// 表单数据
|
|
|
|
|
const baseForm = reactive<BaseForm>({
|
|
|
|
|
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: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
settlement_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
remark: '',
|
|
|
|
|
total_cif: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
total_cif_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
total_cif_currency_snapshot: '',
|
|
|
|
|
is_final: isFinal ? '1' : '0',
|
|
|
|
|
object_id: stockingId || '0',
|
|
|
|
|
contract: '',
|
2025-09-10 18:11:39 +08:00
|
|
|
contract_url: '',
|
|
|
|
|
pick_up_date:'',
|
|
|
|
|
collect_all_date: ''
|
2025-09-08 19:09:55 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 创建新的订单项
|
|
|
|
|
const newItem = (): ItemRow => ({
|
|
|
|
|
sku_id: '',
|
|
|
|
|
model_snapshot: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
_echo_vin: false,
|
2025-09-08 19:09:55 +08:00
|
|
|
mileage: 0,
|
|
|
|
|
listing_price: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
listing_price_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
listing_price_currency_snapshot: '',
|
|
|
|
|
reduction_price: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
reduction_price_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
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: '',
|
2025-09-10 18:11:39 +08:00
|
|
|
ocean_freight: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
ocean_freight_currency: 'CNY',
|
2025-09-10 18:11:39 +08:00
|
|
|
ocean_freight_currency_snapshot: '',
|
2025-09-08 19:09:55 +08:00
|
|
|
retrofit_fee: '',
|
|
|
|
|
total_price: undefined,
|
|
|
|
|
official_price: undefined,
|
|
|
|
|
discount_price: undefined,
|
|
|
|
|
fob_fee: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
fob_fee_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
fob_fee_currency_snapshot: '',
|
|
|
|
|
helper_fee: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
helper_fee_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
helper_fee_currency_snapshot: '',
|
|
|
|
|
domestic_freight: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
domestic_freight_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
domestic_freight_currency_snapshot: '',
|
|
|
|
|
port_fee: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
port_fee_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
port_fee_currency_snapshot: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
unit_price_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
unit_price_currency_snapshot: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
total_price_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
total_price_currency_snapshot: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
guide_price_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
guide_price_currency_snapshot: '',
|
|
|
|
|
discount: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
discount_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
discount_currency_snapshot: '',
|
|
|
|
|
contract_rate: 7.16,
|
|
|
|
|
profit: undefined,
|
|
|
|
|
modify_ids: [],
|
|
|
|
|
modify_list: [],
|
2025-09-15 17:14:38 +08:00
|
|
|
modify_fee_currency: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
modify_fee_currency_snapshot: ''
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 创建新的收款项
|
|
|
|
|
const newPaymentItem = (): PaymentItem => ({
|
|
|
|
|
remit_country_id: '',
|
|
|
|
|
remit_country_name_snapshot: '',
|
|
|
|
|
remit_date: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
currency_code: 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
currency_name_snapshot: '',
|
|
|
|
|
account_id: '',
|
|
|
|
|
account_name_snapshot: '',
|
|
|
|
|
remitter_name: '',
|
|
|
|
|
amount: undefined
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const items = ref<ItemRow[]>([newItem()])
|
|
|
|
|
const paymentItems = ref<PaymentItem[]>([newPaymentItem()])
|
|
|
|
|
const contractFile = ref<{ name: string; url: string; file_name: string } | null>(null)
|
|
|
|
|
|
|
|
|
|
// 弹框状态
|
|
|
|
|
const customerDialog = reactive<DialogState>({
|
|
|
|
|
visible: false,
|
|
|
|
|
search: { keyword: '' },
|
|
|
|
|
loading: false,
|
|
|
|
|
tableData: [],
|
|
|
|
|
pagination: { currentPage: 1, pageSize: 10, total: 0 }
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const vehicleDialog = reactive<DialogState>({
|
|
|
|
|
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()
|
2025-09-12 17:49:07 +08:00
|
|
|
res.forEach((item: any) => {
|
|
|
|
|
item.cn_addrs = item.cn_addr + '(' + item.en_addr + ')'
|
|
|
|
|
})
|
2025-09-15 17:14:38 +08:00
|
|
|
// console.log(res)
|
2025-09-08 19:09:55 +08:00
|
|
|
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 = () => {
|
2025-09-11 17:44:37 +08:00
|
|
|
const code = baseForm.settlement_currency || items.value[0]?.unit_price_currency || 'USD'
|
2025-09-08 19:09:55 +08:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-15 17:14:38 +08:00
|
|
|
const convertCurrency = (amount: any, fromCode?: string, toCode?: string): number => {
|
2025-09-08 19:09:55 +08:00
|
|
|
const val = amount === undefined || amount === null || amount === '' ? 0 : Number(amount)
|
|
|
|
|
if (Number.isNaN(val)) return 0
|
2025-09-15 17:14:38 +08:00
|
|
|
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
|
2025-09-08 19:09:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const calcProfit = (it: any): number => {
|
2025-09-15 17:14:38 +08:00
|
|
|
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
|
|
|
|
|
)
|
2025-09-08 19:09:55 +08:00
|
|
|
const mileageVal = Number(it.mileage ?? 0)
|
|
|
|
|
if (mileageVal > 0) {
|
|
|
|
|
// 二手车:用挂牌价与二手减价替代官方指导价与优惠
|
2025-09-15 17:14:38 +08:00
|
|
|
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
|
|
|
|
|
)
|
2025-09-10 18:11:39 +08:00
|
|
|
return unit - (retrofit + fob + listing + reduction + handling + port + ocean)
|
2025-09-08 19:09:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 新车/里程<=0:保持原有计算(官方指导价与优惠)
|
2025-09-15 17:14:38 +08:00
|
|
|
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
|
|
|
|
|
)
|
2025-09-10 18:11:39 +08:00
|
|
|
return unit - (retrofit + fob + guide + discount + handling + port + ocean)
|
2025-09-08 19:09:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 合同文件相关方法
|
|
|
|
|
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 || ''
|
2025-09-10 18:11:39 +08:00
|
|
|
baseForm.customer_country_id = row.country_id || ''
|
|
|
|
|
baseForm.customer_country_snapshot = row.country_name || ''
|
2025-09-12 17:49:07 +08:00
|
|
|
baseForm.customer_source_id = row.channel_id || ''
|
|
|
|
|
baseForm.customer_source_snapshot = row.channel_name || ''
|
2025-09-08 19:09:55 +08:00
|
|
|
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
|
|
|
|
|
// 基础信息
|
2025-09-10 18:11:39 +08:00
|
|
|
baseForm.pick_up_date = res.pick_up_date || ''
|
|
|
|
|
baseForm.collect_all_date = res.collect_all_date || ''
|
2025-09-08 19:09:55 +08:00
|
|
|
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 || ''
|
2025-09-15 17:14:38 +08:00
|
|
|
baseForm.shipping_method_id = res.shipping_method_id ? String(res.shipping_method_id) : ''
|
2025-09-08 19:09:55 +08:00
|
|
|
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 || ''
|
2025-09-15 17:14:38 +08:00
|
|
|
baseForm.settlement_currency = res.settlement_currency || 'CNY'
|
2025-09-08 19:09:55 +08:00
|
|
|
// 合计与汇率
|
|
|
|
|
baseForm.total_cif = res.cif_total_amount ? Number(res.cif_total_amount) : undefined
|
|
|
|
|
baseForm.total_cif_currency = res.settlement_currency || baseForm.total_cif_currency
|
2025-09-15 17:14:38 +08:00
|
|
|
baseForm.contract_exchange_rate =
|
|
|
|
|
res.contract_exchange_rate || getCurrencyRate(baseForm.total_cif_currency)
|
2025-09-08 19:09:55 +08:00
|
|
|
// 明细
|
|
|
|
|
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 || '',
|
2025-09-15 17:14:38 +08:00
|
|
|
_echo_vin: Boolean(it.vin),
|
2025-09-08 19:09:55 +08:00
|
|
|
mileage: it.mileage ?? 0,
|
|
|
|
|
model_snapshot: it.model_snapshot || '',
|
|
|
|
|
listing_price: it.listing_price?.amount ? Number(it.listing_price.amount) : undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
listing_price_currency: it.listing_price?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
listing_price_currency_snapshot: '',
|
|
|
|
|
reduction_price: it.reduction_price?.amount ? Number(it.reduction_price.amount) : undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
reduction_price_currency: it.reduction_price?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
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 ?? '',
|
2025-09-10 18:11:39 +08:00
|
|
|
ocean_freight: it.ocean_freight?.amount ?? '',
|
2025-09-15 17:14:38 +08:00
|
|
|
ocean_freight_currency: it.ocean_freight?.currency || 'CNY',
|
2025-09-10 18:11:39 +08:00
|
|
|
ocean_freight_currency_snapshot: '',
|
2025-09-08 19:09:55 +08:00
|
|
|
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,
|
2025-09-15 17:14:38 +08:00
|
|
|
fob_fee_currency: it.fob_transport_fee?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
fob_fee_currency_snapshot: '',
|
|
|
|
|
helper_fee: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
helper_fee_currency: it.handling_fee?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
helper_fee_currency_snapshot: '',
|
|
|
|
|
domestic_freight: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
domestic_freight_currency: it.domestic_freight?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
domestic_freight_currency_snapshot: '',
|
|
|
|
|
port_fee: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
port_fee_currency: it.port_misc_fee?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
port_fee_currency_snapshot: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
unit_price_currency: it.unit_price?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
unit_price_currency_snapshot: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
total_price_currency: it.total_price?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
total_price_currency_snapshot: '',
|
2025-09-15 17:14:38 +08:00
|
|
|
guide_price_currency: it.official_price?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
guide_price_currency_snapshot: '',
|
|
|
|
|
discount: undefined,
|
2025-09-15 17:14:38 +08:00
|
|
|
discount_currency: it.discount_price?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
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 }))
|
|
|
|
|
: [],
|
2025-09-15 17:14:38 +08:00
|
|
|
modify_fee_currency: it.retrofit_fee?.currency || 'CNY',
|
2025-09-08 19:09:55 +08:00
|
|
|
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 || '',
|
2025-09-15 17:14:38 +08:00
|
|
|
account_id: p.account_id ? p.account_id : '',
|
2025-09-08 19:09:55 +08:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 提交方法
|
2025-09-15 17:14:38 +08:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-08 19:09:55 +08:00
|
|
|
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,
|
|
|
|
|
'港杂费'
|
|
|
|
|
),
|
2025-09-10 18:11:39 +08:00
|
|
|
ocean_freight: wrapMoney(it.ocean_freight, (it as any).ocean_freight_currency, '海运费'),
|
2025-09-08 19:09:55 +08:00
|
|
|
retrofit_fee: wrapMoney((it as any).retrofit_fee, (it as any).modify_fee_currency, '改装费'),
|
|
|
|
|
modify_list: it.modify_list,
|
2025-09-15 17:14:38 +08:00
|
|
|
// total_price: wrapMoney(it.total_price, (it as any).total_price_currency, '总价'),
|
|
|
|
|
total_price: wrapMoney(it.unit_price, (it as any).unit_price_currency, '总价'),
|
2025-09-08 19:09:55 +08:00
|
|
|
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, '二手减价')
|
|
|
|
|
}))
|
|
|
|
|
|
2025-09-11 17:44:37 +08:00
|
|
|
// 从提交参数中移除 settlement_currency
|
2025-09-10 18:11:39 +08:00
|
|
|
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
|
2025-09-08 19:09:55 +08:00
|
|
|
const payload = {
|
2025-09-10 18:11:39 +08:00
|
|
|
...baseFormWithoutCur,
|
2025-09-08 19:09:55 +08:00
|
|
|
veh_list: mappedItems,
|
2025-09-10 18:11:39 +08:00
|
|
|
account_list: paymentItems.value,
|
|
|
|
|
approval_status: type
|
2025-09-08 19:09:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2025-09-10 18:11:39 +08:00
|
|
|
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 || '保存成功')
|
|
|
|
|
}
|
2025-09-08 19:09:55 +08:00
|
|
|
setTimeout(() => {
|
2025-09-15 17:14:38 +08:00
|
|
|
if (isfinal == '1') {
|
|
|
|
|
window.location.href = '/crmpc/stocking/final_list'
|
|
|
|
|
} else {
|
|
|
|
|
window.location.href = '/crmpc/stocking/stocking_list'
|
|
|
|
|
}
|
2025-09-08 19:09:55 +08:00
|
|
|
}, 1000)
|
|
|
|
|
} catch (e) {
|
|
|
|
|
ElMessage.error('保存失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 监听器
|
|
|
|
|
watch(
|
2025-09-11 17:44:37 +08:00
|
|
|
() => baseForm.settlement_currency,
|
2025-09-08 19:09:55 +08:00
|
|
|
(newCurrency) => {
|
|
|
|
|
if (newCurrency) {
|
|
|
|
|
baseForm.contract_exchange_rate = getCurrencyRate(newCurrency)
|
2025-09-15 17:14:38 +08:00
|
|
|
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))
|
|
|
|
|
})
|
2025-09-08 19:09:55 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => baseForm.contract_exchange_rate,
|
|
|
|
|
(newCurrency) => {
|
|
|
|
|
if (newCurrency) {
|
2025-09-15 17:14:38 +08:00
|
|
|
if (typeof validateContractRate === 'function') {
|
|
|
|
|
validateContractRate()
|
|
|
|
|
}
|
2025-09-08 19:09:55 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
// 设置默认汇率
|
2025-09-15 17:14:38 +08:00
|
|
|
baseForm.contract_exchange_rate = getCurrencyRate('CNY')
|
2025-09-12 17:49:07 +08:00
|
|
|
|
|
|
|
|
// 设置预计发送日默认为当天
|
|
|
|
|
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}`
|
2025-09-08 19:09:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|