HomeLease/components/renew-modal/renew-modal.vue

418 lines
7.7 KiB
Vue
Raw Normal View History

2025-08-21 18:12:21 +08:00
<template>
<view v-if="visible" class="renew-modal-overlay" @click="handleOverlayClick">
<view class="renew-modal" @click.stop>
<!-- 弹窗头部 -->
<view class="modal-header">
<text class="modal-title">设备续费</text>
<view class="close-btn" @click="handleClose">
<text class="close-icon">×</text>
</view>
</view>
<!-- 设备信息 -->
2025-08-22 09:41:56 +08:00
<view v-if="device" class="device-info">
2025-08-21 18:12:21 +08:00
<view class="device-item">
2025-08-22 09:41:56 +08:00
<image :src="device.image" class="device-image" mode="aspectFill" />
2025-08-21 18:12:21 +08:00
<view class="device-details">
<text class="device-name">{{ device.name }}</text>
2025-08-22 09:41:56 +08:00
<text :class="device.status" class="device-status">
2025-08-21 18:12:21 +08:00
{{ getStatusText(device.status) }}
</text>
2025-08-22 09:41:56 +08:00
<text v-if="device.endTime" class="device-time">
2025-09-13 08:57:42 +08:00
到期时间: {{ uni.$uv.date(device.endTime) }}
2025-08-21 18:12:21 +08:00
</text>
</view>
</view>
</view>
<!-- 套餐列表 -->
<view class="package-section">
<text class="section-title">选择续费套餐</text>
<!-- 加载状态 -->
<view v-if="loading" class="loading-container">
<text class="loading-text">加载中...</text>
</view>
<!-- 套餐列表 -->
<view v-else-if="packageList.length > 0" class="package-list">
<view
v-for="(item, index) in packageList"
:key="index"
:class="{ active: selectedPackage && selectedPackage.id === item.id }"
2025-08-22 09:41:56 +08:00
class="package-item"
2025-08-21 18:12:21 +08:00
@click="handleSelectPackage(item)"
>
<view class="package-info">
<text class="package-name">{{ item.name || `套餐${index + 1}` }}</text>
2025-09-13 08:57:42 +08:00
<!-- <text class="package-desc">{{ item.description || item.period || '暂无描述' }}</text>-->
2025-08-21 18:12:21 +08:00
</view>
<view class="package-price">
<text class="price-symbol">¥</text>
<text class="price-value">{{ item.price || item.amount || '0.00' }}</text>
</view>
2025-08-22 09:41:56 +08:00
<view v-if="selectedPackage && selectedPackage.id === item.id" class="select-icon">
2025-08-21 18:12:21 +08:00
<text class="check-icon"></text>
</view>
</view>
</view>
<!-- 空状态 -->
<view v-else class="empty-state">
<text class="empty-text">暂无可用套餐</text>
</view>
</view>
<!-- 底部按钮 -->
<view class="modal-footer">
<button class="cancel-btn" @click="handleClose">取消</button>
2025-08-22 09:41:56 +08:00
<button :disabled="!selectedPackage" class="confirm-btn" @click="handleConfirm">
2025-08-21 18:12:21 +08:00
确认续费
</button>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'RenewModal',
props: {
visible: {
type: Boolean,
default: false,
},
device: {
type: Object,
default: null,
},
packageList: {
type: Array,
default: () => [],
},
loading: {
type: Boolean,
default: false,
},
},
data() {
return {
selectedPackage: null,
}
},
watch: {
visible(newVal) {
if (!newVal) {
// 当弹窗关闭时,重置选中的套餐
this.selectedPackage = null
}
},
},
methods: {
// 处理遮罩层点击
handleOverlayClick() {
this.handleClose()
},
// 关闭弹窗
handleClose() {
this.$emit('close')
},
// 选择套餐
handleSelectPackage(combo) {
this.selectedPackage = combo
this.$emit('select-package', combo)
},
// 确认续费
handleConfirm() {
if (!this.selectedPackage) {
uni.showToast({
title: '请选择套餐',
icon: 'none',
})
return
}
this.$emit('confirm-renew', this.selectedPackage)
},
// 获取状态文本
getStatusText(status) {
const statusMap = {
available: '可租用',
rented: '已出租',
maintenance: '维护中',
scrapped: '报废',
}
return statusMap[status] || '未知状态'
},
},
}
</script>
<style lang="scss" scoped>
.renew-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
}
.renew-modal {
width: 90%;
max-width: 600rpx;
max-height: 80vh;
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
display: flex;
flex-direction: column;
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.modal-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.close-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: #f5f5f5;
}
.close-icon {
font-size: 40rpx;
color: #999;
line-height: 1;
}
.device-info {
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.device-item {
display: flex;
align-items: center;
}
.device-image {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
margin-right: 20rpx;
}
.device-details {
flex: 1;
display: flex;
flex-direction: column;
}
.device-name {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
}
.device-status {
font-size: 24rpx;
margin-bottom: 8rpx;
&.available {
color: #52c41a;
}
&.rented {
color: #1890ff;
}
&.maintenance {
color: #faad14;
}
&.scrapped {
color: #ff4d4f;
}
&.normal {
color: #52c41a;
}
}
.device-time {
font-size: 24rpx;
color: #666;
}
.package-section {
flex: 1;
padding: 30rpx;
overflow-y: auto;
}
.section-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
display: block;
}
.loading-container {
display: flex;
align-items: center;
justify-content: center;
padding: 60rpx 0;
}
.loading-text {
font-size: 28rpx;
color: #999;
}
.package-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.package-item {
display: flex;
align-items: center;
padding: 24rpx;
border: 2rpx solid #f0f0f0;
border-radius: 12rpx;
position: relative;
transition: all 0.3s ease;
&.active {
border-color: #1890ff;
background-color: #f6ffed;
}
&:active {
transform: scale(0.98);
}
}
.package-info {
flex: 1;
display: flex;
flex-direction: column;
}
.package-name {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
}
.package-desc {
font-size: 24rpx;
color: #666;
}
.package-price {
display: flex;
align-items: baseline;
margin-right: 20rpx;
}
.price-symbol {
font-size: 24rpx;
color: #ff4d4f;
margin-right: 4rpx;
}
.price-value {
font-size: 32rpx;
font-weight: bold;
color: #ff4d4f;
}
.select-icon {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
2025-08-22 09:41:56 +08:00
background-color: #f15a04;
2025-08-21 18:12:21 +08:00
display: flex;
align-items: center;
justify-content: center;
}
.check-icon {
font-size: 24rpx;
color: #fff;
line-height: 1;
}
.empty-state {
display: flex;
align-items: center;
justify-content: center;
padding: 60rpx 0;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
.modal-footer {
display: flex;
gap: 20rpx;
padding: 30rpx;
border-top: 1rpx solid #f0f0f0;
}
.cancel-btn,
.confirm-btn {
flex: 1;
height: 80rpx;
border-radius: 40rpx;
font-size: 28rpx;
border: none;
display: flex;
align-items: center;
justify-content: center;
}
.cancel-btn {
background-color: #f5f5f5;
color: #666;
}
.confirm-btn {
2025-08-22 09:41:56 +08:00
background-color: #f15a04;
2025-08-21 18:12:21 +08:00
color: #fff;
&:disabled {
background-color: #d9d9d9;
color: #999;
}
}
</style>