This commit is contained in:
parent
a8de74cfd4
commit
9ad01ccce2
|
|
@ -79,5 +79,25 @@ export default {
|
||||||
*/
|
*/
|
||||||
terminate(id, data) {
|
terminate(id, data) {
|
||||||
return post(`/rentals/${id}/terminate`, data)
|
return post(`/rentals/${id}/terminate`, data)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 办理续租
|
||||||
|
* @param {number} id - 租赁记录ID
|
||||||
|
* @param {Object} data - 续租数据
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
renew(id, data) {
|
||||||
|
return post(`/rentals/${id}/renew`, data)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 办理换房
|
||||||
|
* @param {number} id - 租赁记录ID
|
||||||
|
* @param {Object} data - 换房数据
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
changeRoom(id, data) {
|
||||||
|
return post(`/rentals/${id}/change-room`, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
pages.json
12
pages.json
|
|
@ -108,6 +108,18 @@
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/rental-renew/rental-renew",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/rental-change-room/rental-change-room",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/rental-add/rental-add",
|
"path": "pages/rental-add/rental-add",
|
||||||
"style": {
|
"style": {
|
||||||
|
|
|
||||||
|
|
@ -72,17 +72,21 @@
|
||||||
<view class="section-title">费用明细</view>
|
<view class="section-title">费用明细</view>
|
||||||
<view class="price-list">
|
<view class="price-list">
|
||||||
<view class="price-row">
|
<view class="price-row">
|
||||||
<text class="row-label">套餐单价</text>
|
<text class="row-label">套餐价格</text>
|
||||||
<text class="row-value">¥{{order.unitPrice || order.subscriptionPlan?.monthlyPrice || 0}}/月</text>
|
<text class="row-value">{{orderPriceText}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="price-row">
|
<view class="price-row">
|
||||||
<text class="row-label">购买时长</text>
|
<text class="row-label">购买时长</text>
|
||||||
<text class="row-value">{{order.months}} 个月</text>
|
<text class="row-value">{{order.months}} 个月</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="price-row">
|
<view class="price-row">
|
||||||
<text class="row-label">基础费用</text>
|
<text class="row-label">订阅费用</text>
|
||||||
<text class="row-value">¥{{order.amount}}</text>
|
<text class="row-value">¥{{order.amount}}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="price-row" v-if="order.billingCycle">
|
||||||
|
<text class="row-label">计费周期</text>
|
||||||
|
<text class="row-value">{{billingCycleText}}</text>
|
||||||
|
</view>
|
||||||
<view class="price-row" v-if="order.discountAmount > 0">
|
<view class="price-row" v-if="order.discountAmount > 0">
|
||||||
<text class="row-label">优惠金额</text>
|
<text class="row-label">优惠金额</text>
|
||||||
<text class="row-value discount">-¥{{order.discountAmount}}</text>
|
<text class="row-value discount">-¥{{order.discountAmount}}</text>
|
||||||
|
|
@ -133,7 +137,7 @@
|
||||||
<!-- 底部操作栏 -->
|
<!-- 底部操作栏 -->
|
||||||
<view class="bottom-bar safe-area-bottom" v-if="order && order.status === 'pending'">
|
<view class="bottom-bar safe-area-bottom" v-if="order && order.status === 'pending'">
|
||||||
<button class="action-btn cancel" @click="cancelOrder">取消订单</button>
|
<button class="action-btn cancel" @click="cancelOrder">取消订单</button>
|
||||||
<button class="action-btn pay" @click="payOrder">立即支付</button>
|
<button class="action-btn pay" @click="showPaymentInfo">付款说明</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -167,11 +171,26 @@
|
||||||
},
|
},
|
||||||
statusDesc() {
|
statusDesc() {
|
||||||
const map = {
|
const map = {
|
||||||
pending: '请在24小时内完成支付,否则订单将自动取消',
|
pending: '请按平台收款信息付款,管理员确认后套餐生效',
|
||||||
paid: '订单已支付成功,套餐已生效',
|
paid: '订单已支付成功,套餐已生效',
|
||||||
cancelled: '订单已取消,如有疑问请联系客服'
|
cancelled: '订单已取消,如有疑问请联系客服'
|
||||||
}
|
}
|
||||||
return map[this.order?.status] || ''
|
return map[this.order?.status] || ''
|
||||||
|
},
|
||||||
|
orderPriceText() {
|
||||||
|
if (!this.order) return '¥0/月'
|
||||||
|
if (this.order.billingCycle === 'yearly' && this.order.subscriptionPlan?.yearlyPrice) {
|
||||||
|
return `¥${this.order.subscriptionPlan.yearlyPrice}/年`
|
||||||
|
}
|
||||||
|
return `¥${this.order.unitPrice || this.order.subscriptionPlan?.monthlyPrice || 0}/月`
|
||||||
|
},
|
||||||
|
billingCycleText() {
|
||||||
|
const map = {
|
||||||
|
monthly: '月付',
|
||||||
|
yearly: '年付',
|
||||||
|
custom: '自定义周期'
|
||||||
|
}
|
||||||
|
return map[this.order?.billingCycle] || this.order?.billingCycle || '-'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
|
|
@ -246,34 +265,12 @@
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
payOrder() {
|
showPaymentInfo() {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '支付确认',
|
title: '付款说明',
|
||||||
content: `确认支付订单 #${this.order.orderNo},金额 ¥${this.order.actualAmount}?`,
|
content: `订单 #${this.order.orderNo}\n应付金额:¥${this.order.actualAmount}\n请按平台收款信息完成转账,管理员确认后套餐自动生效。`,
|
||||||
success: async (res) => {
|
showCancel: false,
|
||||||
if (res.confirm) {
|
confirmText: '我知道了'
|
||||||
try {
|
|
||||||
uni.showLoading({ title: '支付中...' })
|
|
||||||
const result = await billingApi.payOrder(this.orderId)
|
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
if (result.code === 200) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '支付成功',
|
|
||||||
icon: 'success',
|
|
||||||
duration: 2000
|
|
||||||
})
|
|
||||||
this.loadOrderDetail()
|
|
||||||
} else {
|
|
||||||
uni.showToast({ title: result.message || '支付失败', icon: 'none' })
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
uni.hideLoading()
|
|
||||||
console.error('支付失败:', error)
|
|
||||||
uni.showToast({ title: '支付失败', icon: 'none' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
|
|
||||||
<view class="order-footer" v-if="order.status === 'pending'">
|
<view class="order-footer" v-if="order.status === 'pending'">
|
||||||
<button class="action-btn cancel" @click.stop="cancelOrder(order)">取消订单</button>
|
<button class="action-btn cancel" @click.stop="cancelOrder(order)">取消订单</button>
|
||||||
<button class="action-btn pay" @click.stop="payOrder(order)">去支付</button>
|
<button class="action-btn pay" @click.stop="showPaymentInfo(order)">付款说明</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
@ -223,33 +223,12 @@
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async payOrder(order) {
|
showPaymentInfo(order) {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '支付确认',
|
title: '付款说明',
|
||||||
content: `确认支付订单 #${order.orderNo},金额 ¥${order.actualAmount}?`,
|
content: `订单 #${order.orderNo}\n应付金额:¥${order.actualAmount}\n请按平台收款信息完成转账,管理员确认后套餐自动生效。`,
|
||||||
success: async (res) => {
|
showCancel: false,
|
||||||
if (res.confirm) {
|
confirmText: '我知道了'
|
||||||
uni.showLoading({ title: '支付中...' })
|
|
||||||
try {
|
|
||||||
const result = await billingApi.payOrder(order.id)
|
|
||||||
uni.hideLoading()
|
|
||||||
if (result.code === 200) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '支付成功',
|
|
||||||
icon: 'success',
|
|
||||||
duration: 2000
|
|
||||||
})
|
|
||||||
this.refreshData()
|
|
||||||
} else {
|
|
||||||
uni.showToast({ title: result.message || '支付失败', icon: 'none' })
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
uni.hideLoading()
|
|
||||||
console.error('支付失败:', error)
|
|
||||||
uni.showToast({ title: '支付失败', icon: 'none' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
<view class="plan-price">
|
<view class="plan-price">
|
||||||
<text class="price">¥{{plan.monthlyPrice}}</text>
|
<text class="price">¥{{plan.monthlyPrice}}</text>
|
||||||
<text class="unit">/月</text>
|
<text class="unit">/月</text>
|
||||||
|
<text v-if="plan.yearlyPrice" class="yearly-price">¥{{plan.yearlyPrice}}/年</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
@ -76,20 +77,20 @@
|
||||||
<view class="section-title">费用明细</view>
|
<view class="section-title">费用明细</view>
|
||||||
<view class="price-list">
|
<view class="price-list">
|
||||||
<view class="price-row">
|
<view class="price-row">
|
||||||
<text class="row-label">套餐单价</text>
|
<text class="row-label">套餐价格</text>
|
||||||
<text class="row-value">¥{{selectedPlan?.monthlyPrice || 0}}/月</text>
|
<text class="row-value">{{selectedPriceText}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="price-row">
|
<view class="price-row">
|
||||||
<text class="row-label">购买时长</text>
|
<text class="row-label">购买时长</text>
|
||||||
<text class="row-value">{{selectedMonths}} 个月</text>
|
<text class="row-value">{{selectedMonths}} 个月</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="price-row">
|
<view class="price-row">
|
||||||
<text class="row-label">基础费用</text>
|
<text class="row-label">订阅费用</text>
|
||||||
<text class="row-value">¥{{baseAmount}}</text>
|
<text class="row-value">¥{{baseAmount}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="price-row" v-if="discountAmount > 0">
|
<view class="price-row" v-if="billingCycle">
|
||||||
<text class="row-label">优惠金额</text>
|
<text class="row-label">计费周期</text>
|
||||||
<text class="row-value discount">-¥{{discountAmount}}</text>
|
<text class="row-value">{{billingCycleText}}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="price-row total">
|
<view class="price-row total">
|
||||||
<text class="row-label">合计</text>
|
<text class="row-label">合计</text>
|
||||||
|
|
@ -165,20 +166,36 @@
|
||||||
selectedMonths: 1,
|
selectedMonths: 1,
|
||||||
periods: [
|
periods: [
|
||||||
{ label: '1个月', value: 1, discount: 0 },
|
{ label: '1个月', value: 1, discount: 0 },
|
||||||
{ label: '3个月', value: 3, discount: 5 },
|
{ label: '3个月', value: 3, discount: 0 },
|
||||||
{ label: '6个月', value: 6, discount: 10 },
|
{ label: '6个月', value: 6, discount: 0 },
|
||||||
{ label: '12个月', value: 12, discount: 15 }
|
{ label: '12个月', value: 12, discount: 0 }
|
||||||
],
|
],
|
||||||
paymentSettings: null,
|
paymentSettings: null,
|
||||||
submitting: false,
|
submitting: false,
|
||||||
baseAmount: 0,
|
baseAmount: 0,
|
||||||
discountAmount: 0,
|
discountAmount: 0,
|
||||||
totalAmount: 0
|
totalAmount: 0,
|
||||||
|
billingCycle: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
selectedPlan() {
|
selectedPlan() {
|
||||||
return this.plans.find(p => p.id === this.selectedPlanId)
|
return this.plans.find(p => p.id === this.selectedPlanId)
|
||||||
|
},
|
||||||
|
selectedPriceText() {
|
||||||
|
if (!this.selectedPlan) return '¥0/月'
|
||||||
|
if (this.selectedMonths === 12 && Number(this.selectedPlan.yearlyPrice) > 0) {
|
||||||
|
return `¥${this.selectedPlan.yearlyPrice}/年`
|
||||||
|
}
|
||||||
|
return `¥${this.selectedPlan.monthlyPrice}/月`
|
||||||
|
},
|
||||||
|
billingCycleText() {
|
||||||
|
const map = {
|
||||||
|
monthly: '月付',
|
||||||
|
yearly: '年付',
|
||||||
|
custom: '自定义周期'
|
||||||
|
}
|
||||||
|
return map[this.billingCycle] || this.billingCycle
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
@ -198,8 +215,8 @@
|
||||||
try {
|
try {
|
||||||
const res = await billingApi.getPlans()
|
const res = await billingApi.getPlans()
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
// 过滤掉免费版(monthlyPrice <= 0)和未启用的套餐
|
// 过滤掉免费版和未启用的套餐
|
||||||
this.plans = (res.data || []).filter(p => p.status === 'active' && p.monthlyPrice > 0)
|
this.plans = (res.data || []).filter(p => p.status === 'active' && (Number(p.monthlyPrice) > 0 || Number(p.yearlyPrice) > 0))
|
||||||
// 如果有推荐套餐,默认选中
|
// 如果有推荐套餐,默认选中
|
||||||
const recommended = this.plans.find(p => p.isRecommended)
|
const recommended = this.plans.find(p => p.isRecommended)
|
||||||
if (recommended) {
|
if (recommended) {
|
||||||
|
|
@ -233,25 +250,29 @@
|
||||||
this.selectedMonths = months
|
this.selectedMonths = months
|
||||||
},
|
},
|
||||||
|
|
||||||
calculatePrice() {
|
async calculatePrice() {
|
||||||
if (!this.selectedPlan) {
|
if (!this.selectedPlan) {
|
||||||
this.baseAmount = 0
|
this.baseAmount = 0
|
||||||
this.discountAmount = 0
|
this.discountAmount = 0
|
||||||
this.totalAmount = 0
|
this.totalAmount = 0
|
||||||
|
this.billingCycle = ''
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
const monthlyPrice = this.selectedPlan.monthlyPrice
|
const res = await billingApi.calculatePrice({
|
||||||
const baseAmount = monthlyPrice * this.selectedMonths
|
planId: this.selectedPlanId,
|
||||||
|
months: this.selectedMonths
|
||||||
// 计算折扣
|
})
|
||||||
const period = this.periods.find(p => p.value === this.selectedMonths)
|
if (res.code === 200 && res.data) {
|
||||||
const discountRate = period ? period.discount / 100 : 0
|
this.baseAmount = res.data.baseAmount || 0
|
||||||
const discountAmount = Math.round(baseAmount * discountRate)
|
this.discountAmount = res.data.discountAmount || 0
|
||||||
|
this.totalAmount = res.data.totalAmount || 0
|
||||||
this.baseAmount = baseAmount
|
this.billingCycle = res.data.billingCycle || ''
|
||||||
this.discountAmount = discountAmount
|
}
|
||||||
this.totalAmount = baseAmount - discountAmount
|
} catch (error) {
|
||||||
|
console.error('计算价格失败:', error)
|
||||||
|
uni.showToast({ title: '计算价格失败', icon: 'none' })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async createOrder() {
|
async createOrder() {
|
||||||
|
|
@ -431,6 +452,13 @@
|
||||||
color: #94A3B8;
|
color: #94A3B8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.yearly-price {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #64748B;
|
||||||
|
}
|
||||||
|
|
||||||
.plan-features {
|
.plan-features {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,10 @@
|
||||||
<uni-icons type="refresh-filled" size="20" color="#FFFFFF"></uni-icons>
|
<uni-icons type="refresh-filled" size="20" color="#FFFFFF"></uni-icons>
|
||||||
<text>办理续租</text>
|
<text>办理续租</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="action-btn warning" @click="handleChangeRoom">
|
||||||
|
<uni-icons type="home-filled" size="20" color="#FFFFFF"></uni-icons>
|
||||||
|
<text>办理换房</text>
|
||||||
|
</view>
|
||||||
<view class="action-btn danger" @click="handleTerminate">
|
<view class="action-btn danger" @click="handleTerminate">
|
||||||
<uni-icons type="closeempty" size="20" color="#FFFFFF"></uni-icons>
|
<uni-icons type="closeempty" size="20" color="#FFFFFF"></uni-icons>
|
||||||
<text>办理退租</text>
|
<text>办理退租</text>
|
||||||
|
|
@ -367,6 +371,12 @@
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleChangeRoom() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/rental-change-room/rental-change-room?id=${this.rentalId}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
handleTerminate() {
|
handleTerminate() {
|
||||||
this.terminateForm = {
|
this.terminateForm = {
|
||||||
waterMeterEnd: '',
|
waterMeterEnd: '',
|
||||||
|
|
@ -757,6 +767,11 @@
|
||||||
box-shadow: 0 8rpx 24rpx rgba(37, 99, 235, 0.3);
|
box-shadow: 0 8rpx 24rpx rgba(37, 99, 235, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-btn.warning {
|
||||||
|
background: linear-gradient(135deg, #F59E0B 0%, #D97706 100%);
|
||||||
|
box-shadow: 0 8rpx 24rpx rgba(245, 158, 11, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
.action-btn.danger {
|
.action-btn.danger {
|
||||||
background: linear-gradient(135deg, #EF4444 0%, #DC2626 100%);
|
background: linear-gradient(135deg, #EF4444 0%, #DC2626 100%);
|
||||||
box-shadow: 0 8rpx 24rpx rgba(239, 68, 68, 0.3);
|
box-shadow: 0 8rpx 24rpx rgba(239, 68, 68, 0.3);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue