diff --git a/resources/views/sales/price-simulator/index.blade.php b/resources/views/sales/price-simulator/index.blade.php index c9b44091..cbf42ea4 100644 --- a/resources/views/sales/price-simulator/index.blade.php +++ b/resources/views/sales/price-simulator/index.blade.php @@ -736,6 +736,37 @@ class="w-4 h-4 rounded border-gray-300 text-emerald-600 focus:ring-emerald-500"> + {{-- 개발비-구독료 연동 --}} +
+
+
+
+ + + +
+
+ 개발비-구독료 연동 +

개발비를 조정하면 구독료가 비율에 맞춰 자동 연동됩니다

+
+
+ +
+
+
+ + + + 각 상품의 개발비(할인가) : 구독료 비율을 유지합니다. 슬라이더로 개발비를 낮추면 구독료도 같은 비율로 낮아집니다. (최저 구독료 이하로는 내려가지 않습니다) +
+
+
+ {{-- 선택된 카테고리의 상품 목록 --}} @foreach($categories as $category)
@@ -777,7 +808,17 @@ class="w-4 h-4 rounded border-gray-300 text-emerald-600 focus:ring-emerald-500"
개발비: {{ number_format($product->development_fee) }}원 개발비: {{ number_format($product->registration_fee) }}원 - 구독료: {{ number_format($product->subscription_fee) }}원/월 + 구독료: + + +
{{-- 선택 시 가격 조정 슬라이더 --}} @@ -816,6 +857,18 @@ class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-e 최저 {{ number_format($product->min_development_fee) }}원 이하 불가
@endif + {{-- 연동 구독료 표시 --}} + @@ -1026,9 +1079,14 @@ class="w-full py-2 text-xs text-gray-500 bg-gray-50 hover:bg-gray-100 rounded-lg
+ {{-- 원래 구독료 (연동 시에만 표시) --}} +
+ 월 구독료 (원래) + +
{{-- 월 구독료 --}}
- 월 구독료 (정가) +
@@ -1223,6 +1281,9 @@ function buildRequiredSelected(catId) { selectedCategoryId: firstCategoryId, selected: buildRequiredSelected(firstCategoryId), + // 개발비-구독료 연동 + linkedPricing: false, + // 프로모션/할인 promoRegistrationType: 'percent', // 'percent' | 'amount' promoRegistrationAmount: 0, @@ -1277,10 +1338,28 @@ function buildRequiredSelected(catId) { if (!this.selected[id]) return; const p = productMap[id]; const minFee = p ? p.minDevFee : 0; - this.selected = { - ...this.selected, - [id]: { ...this.selected[id], adjustedFee: Math.max(minFee, value) } - }; + const clampedFee = Math.max(minFee, value); + const update = { ...this.selected[id], adjustedFee: clampedFee }; + + // 연동 모드: 개발비 비율에 맞춰 구독료 자동 조정 + if (this.linkedPricing && p) { + const baseRegFee = Number(p.registration_fee) || 1; + const baseSub = Number(p.subscription_fee); + const ratio = baseSub / baseRegFee; + const linkedSub = Math.round(clampedFee * ratio / 10000) * 10000; // 만원 단위 반올림 + const minSub = p.minSubFee || 0; + update.adjustedSubFee = Math.max(minSub, linkedSub); + } + + this.selected = { ...this.selected, [id]: update }; + }, + + getAdjustedSubFee(id) { + if (!this.selected[id]) return 0; + if (this.selected[id].adjustedSubFee !== undefined) { + return this.selected[id].adjustedSubFee; + } + return Number(productMap[id]?.subscription_fee || 0); }, getDiscountRate(id, devFee) { @@ -1304,7 +1383,8 @@ function buildRequiredSelected(catId) { categoryName: p.categoryName, developmentFee: Number(p.development_fee), adjustedFee: this.selected[id].adjustedFee, - subscriptionFee: Number(p.subscription_fee), + subscriptionFee: this.getAdjustedSubFee(id), + originalSubFee: Number(p.subscription_fee), }; }); }, @@ -1322,6 +1402,12 @@ function buildRequiredSelected(catId) { }, totalSubscriptionFee() { + return Object.keys(this.selected).reduce((sum, id) => { + return sum + this.getAdjustedSubFee(id); + }, 0); + }, + + totalOriginalSubscriptionFee() { return Object.keys(this.selected).reduce((sum, id) => { return sum + Number(productMap[id].subscription_fee); }, 0); @@ -1486,9 +1572,35 @@ function buildRequiredSelected(catId) { return Number(value).toLocaleString('ko-KR') + '원'; }, + toggleLinkedPricing() { + this.linkedPricing = !this.linkedPricing; + if (this.linkedPricing) { + // 연동 ON: 현재 조정된 개발비 기준으로 구독료 재계산 + Object.keys(this.selected).forEach(id => { + const p = productMap[id]; + if (!p) return; + const baseRegFee = Number(p.registration_fee) || 1; + const baseSub = Number(p.subscription_fee); + const ratio = baseSub / baseRegFee; + const linkedSub = Math.round(this.selected[id].adjustedFee * ratio / 10000) * 10000; + const minSub = p.minSubFee || 0; + this.selected[id] = { ...this.selected[id], adjustedSubFee: Math.max(minSub, linkedSub) }; + }); + this.selected = { ...this.selected }; + } else { + // 연동 OFF: 구독료를 원래값으로 복원 + Object.keys(this.selected).forEach(id => { + delete this.selected[id].adjustedSubFee; + }); + this.selected = { ...this.selected }; + } + this.$nextTick(() => this.clampPromoValues()); + }, + resetAll() { this.signupType = 'individual'; this.hasReferrer = false; + this.linkedPricing = false; this.selectedCategoryId = firstCategoryId; this.selected = buildRequiredSelected(firstCategoryId); this.resetPromo();