import { computed, type Ref } from 'vue' import type { ChargeMode, ListingPublishOptions, PublishSalePriceConfig, QuantityKey, ScreenshotKey, } from '@/features/listings/api/listingOptions' import type { PublishForm } from '@/shared/types/publish' import { buildDepositBreakdownItems, calculateConsumablePrice, calculateDailyLossRatioAdjustment, calculatePlatformPricing, calculateRecommendedDeposit, calculateSellerReferenceRatio, formatNumber, hasAcceleratedSaleRatioInput as hasAcceleratedSaleRatioValue, isQuantityItemDisabledForInsurance, readFinalSaleRatio, applySiteReceiveCostDelta, roundMoney, roundRatio, } from '@/shared/utils/pricing' export function usePricingCalculator(options: { publishOptions: Ref salePriceConfig: Ref form: PublishForm quantityValues: Record quantityModes: Record screenshotFiles: Record selectedSkins: Ref isDistribution?: Ref receiveRatioDelta?: Ref receiveCostDelta?: Ref }) { const serverOptions = computed(() => options.publishOptions.value.server_options) const faceOptions = computed(() => options.publishOptions.value.face_options) const rankOptions = computed(() => options.publishOptions.value.rank_options) const insuranceOptions = computed(() => options.publishOptions.value.insurance_options) const levelOptions = computed(() => options.publishOptions.value.level_options) const loginMethodOptions = computed(() => options.publishOptions.value.login_method_options) const regionOptions = computed(() => options.publishOptions.value.region_options) const banRecordOptions = computed(() => options.publishOptions.value.ban_record_options) const banEvidenceOptions = computed(() => options.publishOptions.value.ban_evidence_options) const skinGroups = computed(() => options.publishOptions.value.skin_groups) const quantityItems = computed(() => options.publishOptions.value.quantity_items) const screenshotSlots = computed(() => options.publishOptions.value.screenshot_slots) const priceConfig = computed(() => options.publishOptions.value.price_config) const depositRecommendConfig = computed( () => options.publishOptions.value.deposit_recommend_config ) const fireLevelMin = computed(() => options.publishOptions.value.fire_level_min || 38) const fireLevelPlaceholder = computed(() => `等级低于${fireLevelMin.value}级的号无法发布`) const coinMAmount = computed(() => Number(options.form.haf_coin_amount || 0)) const coinWanAmount = computed(() => coinMAmount.value * 100) const dailyLossMAmount = computed(() => Number(options.form.daily_loss_m || 10)) const dailyLossRatioAdjustment = computed(() => calculateDailyLossRatioAdjustment(dailyLossMAmount.value) ) const screenshotUrls = computed(() => screenshotSlots.value .flatMap(item => options.screenshotFiles?.[item.key] || []) .filter(url => Boolean(url)) ) function hasAcceleratedSaleRatioInput() { return hasAcceleratedSaleRatioValue(options.form.accelerated_sale_ratio) } function isQuantityItemDisabled(item: { key: string; label: string }) { return isQuantityItemDisabledForInsurance(item, options.form.season_insurance) } const calculatedSellerReferenceRatio = computed(() => calculateSellerReferenceRatio({ coinMAmount: coinMAmount.value, form: options.form, ratioConfig: options.publishOptions.value.ratio_config, skinGroups: skinGroups.value, selectedSkins: options.selectedSkins.value, levelOptions: levelOptions.value, dailyLossRatioAdjustment: dailyLossRatioAdjustment.value, }) ) const calculatedDefaultSaleRatio = computed(() => calculatedSellerReferenceRatio.value) const maxAcceleratedSaleRatio = computed(() => calculatedDefaultSaleRatio.value > 0 ? roundRatio(calculatedDefaultSaleRatio.value + 10) : 0 ) const siteReceiveRatioDelta = computed(() => Math.max(0, Number(options.receiveRatioDelta?.value || 0)) ) const siteReceiveCostDelta = computed(() => Math.max(0, Number(options.receiveCostDelta?.value || 0)) ) // 分站新口径:收号价按「R + 压价点数」计算(压价收号);买家定价仍按主站口径推导。 // 买卖两侧解耦:calculatedRatio 决定号主收号价,anchorRatio 决定买家价基准。 const calculatedRatio = computed(() => { if (calculatedDefaultSaleRatio.value <= 0) return 0 if (options.isDistribution?.value) { return applySiteReceiveCostDelta(calculatedDefaultSaleRatio.value, siteReceiveCostDelta.value) } return readFinalSaleRatio( calculatedDefaultSaleRatio.value, options.form.accelerated_sale_ratio, maxAcceleratedSaleRatio.value ) }) const anchorRatio = computed(() => { if (calculatedDefaultSaleRatio.value <= 0) return 0 if (options.isDistribution?.value) return calculatedDefaultSaleRatio.value return calculatedRatio.value }) const calculatedCoinBasePrice = computed(() => { if (calculatedRatio.value <= 0) return 0 return roundMoney(coinWanAmount.value / calculatedRatio.value) }) const anchorCoinBasePrice = computed(() => { if (anchorRatio.value <= 0) return 0 return roundMoney(coinWanAmount.value / anchorRatio.value) }) const calculatedConsumablePrice = computed(() => calculateConsumablePrice({ quantityItems: quantityItems.value, quantityValues: options.quantityValues, quantityModes: options.quantityModes, seasonInsurance: options.form.season_insurance, }) ) const calculatedSellerPrice = computed(() => calculatedRatio.value > 0 ? roundMoney(calculatedCoinBasePrice.value + calculatedConsumablePrice.value) : 0 ) const anchorSellerPrice = computed(() => anchorRatio.value > 0 ? roundMoney(anchorCoinBasePrice.value + calculatedConsumablePrice.value) : 0 ) const calculatedPlatformPricing = computed(() => calculatePlatformPricing({ coinMAmount: coinMAmount.value, coinWanAmount: coinWanAmount.value, sellerRatio: anchorRatio.value, sellerCoinBasePrice: anchorCoinBasePrice.value, sellerTotalPrice: anchorSellerPrice.value, consumablePrice: calculatedConsumablePrice.value, salePriceConfig: options.salePriceConfig.value, }) ) const calculatedFinalPrice = computed(() => calculatedPlatformPricing.value.buyerTotalPrice) const calculatedRatioText = computed(() => calculatedRatio.value > 0 ? `1:${formatNumber(calculatedRatio.value)}` : '--' ) const calculatedDefaultSaleRatioText = computed(() => calculatedDefaultSaleRatio.value > 0 ? `1:${formatNumber(calculatedDefaultSaleRatio.value)}` : '--' ) const saleRatioRangeText = computed(() => { if (calculatedDefaultSaleRatio.value <= 0) return '完成基础信息后自动计算参考比例' if (options.isDistribution?.value) { return `主站参考 1:${formatNumber(calculatedDefaultSaleRatio.value)},本站收号 1:${formatNumber(calculatedRatio.value)}` } return `可设置 1:${formatNumber(calculatedDefaultSaleRatio.value)} ~ 1:${formatNumber(maxAcceleratedSaleRatio.value)}` }) const acceleratedSaleRatioPlaceholder = computed(() => { if (calculatedDefaultSaleRatio.value <= 0) return '填写资料后自动生成可设置范围' return `默认 ${formatNumber(calculatedDefaultSaleRatio.value)},最高 ${formatNumber(maxAcceleratedSaleRatio.value)}` }) const recommendedDepositAmount = computed(() => calculateRecommendedDeposit({ depositRecommendConfig: depositRecommendConfig.value, skinGroups: skinGroups.value, selectedSkins: options.selectedSkins.value, }) ) const depositBreakdownItems = computed(() => buildDepositBreakdownItems({ depositRecommendConfig: depositRecommendConfig.value, skinGroups: skinGroups.value, selectedSkins: options.selectedSkins.value, }) ) const platformRuleLabel = computed(() => { const labels: Record = { fixed_markup: '固定加价', ratio_subtract: '比例修正', none: '无加价', } return ( labels[calculatedPlatformPricing.value.ruleType] || calculatedPlatformPricing.value.ruleType ) }) const publishTitle = computed(() => { const parts = [ options.form.server_region, options.form.rank_level, coinMAmount.value ? `${coinMAmount.value}M哈夫币` : '', ].filter(Boolean) return parts.length ? parts.join(' ') : '待完善账号信息' }) return { serverOptions, faceOptions, rankOptions, insuranceOptions, levelOptions, loginMethodOptions, regionOptions, banRecordOptions, banEvidenceOptions, skinGroups, quantityItems, screenshotSlots, priceConfig, depositRecommendConfig, fireLevelMin, fireLevelPlaceholder, coinMAmount, coinWanAmount, dailyLossMAmount, dailyLossRatioAdjustment, screenshotUrls, calculatedSellerReferenceRatio, calculatedDefaultSaleRatio, maxAcceleratedSaleRatio, siteReceiveRatioDelta, siteReceiveCostDelta, calculatedRatio, calculatedCoinBasePrice, calculatedConsumablePrice, calculatedSellerPrice, calculatedPlatformPricing, calculatedFinalPrice, calculatedRatioText, calculatedDefaultSaleRatioText, saleRatioRangeText, acceleratedSaleRatioPlaceholder, recommendedDepositAmount, depositBreakdownItems, platformRuleLabel, publishTitle, hasAcceleratedSaleRatioInput, isQuantityItemDisabled, } }