442 lines
17 KiB
Vue
442 lines
17 KiB
Vue
<template>
|
||
<view class="monthly-payment-container">
|
||
<!-- 顶部标题 -->
|
||
<view class="header">
|
||
<text class="header-title">{{ headerTitle }}</text>
|
||
<u-icon :name="isDropdownOpen ? 'arrow-up' : 'arrow-down'" size="28" @tap="toggleDropdown"></u-icon>
|
||
</view>
|
||
|
||
<!-- 下拉停车场列表 -->
|
||
<view v-if="isDropdownOpen" class="parking-list">
|
||
<!-- 搜索框 -->
|
||
<view class="search-box">
|
||
<u-icon name="search" size="40" color="#999" class="search-icon" />
|
||
<input type="text" placeholder="搜索停车场" class="search-input" />
|
||
</view>
|
||
|
||
<!-- 停车场列表 -->
|
||
<view class="parking-items">
|
||
<view class="parking-item" v-for="(park, index) in parkingLots" :key="index"
|
||
@tap="selectParkingLot(park)">
|
||
<view class="parking-item-left">
|
||
<view class="parking-spaces">
|
||
<text class="spaces-label">剩余车位</text>
|
||
<text class="spaces-number">{{ park.space_count }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="parking-item-right">
|
||
<text class="parking-name">{{ park.parking_name }}</text>
|
||
<text class="parking-distance">{{ getParkDistance(park.lng, park.lat) }}km</text>
|
||
<text class="parking-address">{{ park.address }}</text>
|
||
</view>
|
||
<view class="parking-selected" v-if="park.isSelected">✔</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="options-list">
|
||
<view class="overlay" v-if="isDropdownOpen"></view>
|
||
<!-- 车辆信息 -->
|
||
<view class="car-info">
|
||
<image class="car-image" src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/park/car.png"
|
||
mode="aspectFit" />
|
||
</view>
|
||
|
||
<!-- 停车场信息 -->
|
||
<view class="park-info" v-if="headerTitle != '请选择停车场'">
|
||
<text class="park-name">{{ headerTitle }}</text>
|
||
<text class="park-type">{{ selectedParkType == 1 ? '地上' : '地下' }}</text>
|
||
</view>
|
||
|
||
<!-- 支付金额 -->
|
||
<view class="payment-amount">
|
||
<text class="amount-label">支付金额</text>
|
||
<text class="amount-value">¥{{ paymentAmount.toFixed(2) }}</text>
|
||
</view>
|
||
|
||
<!-- 选项列表 -->
|
||
<!-- 选择车牌 -->
|
||
<view class="option-item" @tap="selectCarPlate">
|
||
<view v-if="selectedCarPlate" class="option-box">
|
||
<view class="option-label option-val">{{ selectedCarPlate }}</view>
|
||
<view class="option-right">
|
||
<image class="option-image"
|
||
src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/park/park_refresh.png"
|
||
mode="aspectFit" />
|
||
<image class="option-image"
|
||
src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/park/park_finish.png"
|
||
mode="aspectFit" />
|
||
</view>
|
||
</view>
|
||
<view v-else class="option-box">
|
||
<text class="option-label">请选择车牌</text>
|
||
<u-icon name="arrow-right" size="30" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 计费规则 -->
|
||
<view class="option-item" @tap="showPriceRule">
|
||
<view v-if="monthPrice !== ''" class="option-box">
|
||
<view class="option-label option-val2">{{ monthPrice + '元/月' }}</view>
|
||
</view>
|
||
<view v-else class="option-box">
|
||
<text class="option-label">计费规则</text>
|
||
<u-icon name="arrow-right" size="30" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 包月月数 -->
|
||
<view class="option-item" @tap="selectMonthCount">
|
||
<view v-if="monthCount" class="option-box">
|
||
<view class="option-label option-val">{{ monthCount + '个月' }}</view>
|
||
<view class="option-right">
|
||
<image class="option-image"
|
||
src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/park/park_refresh.png"
|
||
mode="aspectFit" />
|
||
<image class="option-image"
|
||
src="https://wechat-img-file.oss-cn-beijing.aliyuncs.com/park/park_finish.png"
|
||
mode="aspectFit" />
|
||
</view>
|
||
</view>
|
||
<view v-else class="option-box">
|
||
<text class="option-label">包月月数</text>
|
||
<u-icon name="arrow-right" size="30" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 开始时间 -->
|
||
<view class="option-item">
|
||
<view class="option-box">
|
||
<text class="option-label">开始时间</text>
|
||
<text class="option-value">{{ startTime }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 结束时间 -->
|
||
<view class="option-item">
|
||
<view class="option-box">
|
||
<text class="option-label">结束时间</text>
|
||
<text class="option-value">{{ endTime || '--年--月--日' }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 下一步按钮 -->
|
||
<view class="next-step-btn" @tap="goToNextStep">
|
||
<text class="next-step-text">下一步</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单记录 -->
|
||
<view class="order-record" @tap="viewOrderRecords">
|
||
<text class="order-record-text">订单记录>></text>
|
||
</view>
|
||
|
||
<!-- 车牌选择弹窗 -->
|
||
<u-popup :show="showCarPlatePopup" :round="30" mode="bottom" :closeable="true" close-icon-position="top-right"
|
||
@close="onCloseCarPlatePopup">
|
||
<view class="car-plate-popup">
|
||
<view class="popup-header">
|
||
<text class="popup-title">选择车牌</text>
|
||
</view>
|
||
<view class="car-plate-list">
|
||
<view class="car-plate-item" v-for="(plate, index) in carPlateList" :key="index"
|
||
@tap="onSelectCarPlate(plate)" :class="{ 'selected': selectedCarPlate === plate }">
|
||
<text class="plate-number">{{ plate.car_number }}</text>
|
||
<u-icon v-if="selectedCarPlate === plate" name="checkmark-circle" size="28"
|
||
color="#ff4219"></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-popup>
|
||
|
||
<!-- 计费规则弹窗 -->
|
||
<u-popup :show="billingRulesPopup" :round="30" mode="bottom" :closeable="true" close-icon-position="top-right"
|
||
@close="onCloseBillingRulesPopup">
|
||
<view class="car-plate-popup">
|
||
<view class="popup-header">
|
||
<text class="popup-title">计费规则</text>
|
||
</view>
|
||
<view class="car-plate-list">
|
||
<view class="car-plate-item" v-for="(rule, index) in billingRulesList" :key="index"
|
||
@tap="onSelectBillingRule(rule)" :class="{ 'selected': monthPrice === rule.price }">
|
||
<text class="plate-number">{{ rule.billing_rule_name }}</text>
|
||
<text class="rule-price">¥{{ rule.month_price }}/月</text>
|
||
<u-icon v-if="monthPrice === rule.month_price" name="checkmark-circle" size="28"
|
||
color="#ff4219"></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-popup>
|
||
|
||
<!-- 包月月数选择弹窗 -->
|
||
<u-popup :show="showMonthCountPopup" :round="30" mode="bottom" :closeable="true" close-icon-position="top-right"
|
||
@close="onCloseMonthCountPopup">
|
||
<view class="car-plate-popup">
|
||
<view class="popup-header">
|
||
<text class="popup-title">选择包月月数</text>
|
||
</view>
|
||
<view class="car-plate-list">
|
||
<view class="car-plate-item" v-for="(month, index) in monthList" :key="index"
|
||
@tap="onSelectMonthCount(month)" :class="{ 'selected': monthCount === month.value }">
|
||
<text class="plate-number">{{ month.label }}</text>
|
||
<u-icon v-if="monthCount === month.value" name="checkmark-circle" size="28"
|
||
color="#ff4219"></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
isPhone,
|
||
picUrl,
|
||
request,
|
||
upload,
|
||
NavgateTo
|
||
} from '../../../utils';
|
||
import { apiArr } from '@/api/park.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
// 页面数据
|
||
selectedCarPlate: '',
|
||
monthCount: '',
|
||
startTime: '',
|
||
endTime: '',
|
||
paymentAmount: 2400.00,
|
||
monthPrice: '',
|
||
// 下拉列表相关
|
||
isDropdownOpen: false,
|
||
headerTitle: '请选择停车场',
|
||
selectedParkType: '',
|
||
selectedParkId: '',//停车场id
|
||
parkingLots: [],
|
||
// 选中车牌
|
||
showCarPlatePopup: false,
|
||
carPlateList: [],
|
||
selectedCarPlateId: '',//选中的车牌id
|
||
//计费规则
|
||
billingRulesPopup: false,
|
||
billingRulesList: [],
|
||
selectedBillingRule: '',// 选中的计费规则
|
||
// 包月月数
|
||
showMonthCountPopup: false,
|
||
monthList: Array.from({ length: 12 }, (_, i) => ({
|
||
value: i + 1,
|
||
label: (i + 1) + '个月'
|
||
}))
|
||
}
|
||
},
|
||
computed: {
|
||
isAllFilled() {
|
||
return this.selectedParkId && this.selectedCarPlateId && this.monthCount > 0 && this.startTime;
|
||
}
|
||
},
|
||
methods: {
|
||
// 切换下拉列表显示状态
|
||
toggleDropdown() {
|
||
this.isDropdownOpen = !this.isDropdownOpen;
|
||
},
|
||
|
||
// 选择停车场
|
||
selectParkingLot(park) {
|
||
// 取消所有选中状态
|
||
this.parkingLots.forEach(item => {
|
||
item.isSelected = false;
|
||
});
|
||
// 设置当前选中
|
||
park.isSelected = true;
|
||
this.$set(this, 'headerTitle', park.parking_name);
|
||
this.$set(this, 'selectedParkType', park.space_type);
|
||
this.selectedParkId = park.id;
|
||
this.isDropdownOpen = false;
|
||
},
|
||
|
||
selectCarPlate() {
|
||
this.showCarPlatePopup = true;
|
||
},
|
||
|
||
onCloseCarPlatePopup() {
|
||
this.showCarPlatePopup = false;
|
||
},
|
||
|
||
// 选择车牌
|
||
onSelectCarPlate(plate) {
|
||
this.selectedCarPlate = plate.car_number;
|
||
this.selectedCarPlateId = plate.id;
|
||
this.showCarPlatePopup = false;
|
||
},
|
||
|
||
// 显示计费规则
|
||
showPriceRule() {
|
||
if (!this.selectedParkId) {
|
||
uni.showToast({
|
||
title: '请选择停车场',
|
||
icon: 'none'
|
||
})
|
||
return;
|
||
}
|
||
this.getBillingRulesList();
|
||
this.billingRulesPopup = true;
|
||
},
|
||
|
||
// 关闭计费规则弹窗
|
||
onCloseBillingRulesPopup() {
|
||
this.billingRulesPopup = false;
|
||
},
|
||
|
||
// 选择计费规则
|
||
onSelectBillingRule(rule) {
|
||
this.selectedBillingRule = rule.billing_rule_name;
|
||
this.monthPrice = rule.month_price;
|
||
this.paymentAmount = this.monthCount * this.monthPrice;
|
||
this.billingRulesPopup = false;
|
||
},
|
||
|
||
// 选择包月月数
|
||
selectMonthCount() {
|
||
this.showMonthCountPopup = true;
|
||
},
|
||
|
||
// 关闭包月月数弹窗
|
||
onCloseMonthCountPopup() {
|
||
this.showMonthCountPopup = false;
|
||
},
|
||
|
||
// 选择具体月数
|
||
onSelectMonthCount(month) {
|
||
this.monthCount = month.value;
|
||
|
||
if (this.startTime) {
|
||
const startDate = new Date(this.startTime);
|
||
// 正确计算结束日期:从开始日期加上指定月数
|
||
const endDate = new Date(startDate);
|
||
endDate.setMonth(endDate.getMonth() + this.monthCount);
|
||
// 减去一天,确保是完整的月份
|
||
endDate.setDate(endDate.getDate() - 1);
|
||
// 设置为最后一天的 23:59:59
|
||
endDate.setHours(23, 59, 59, 999);
|
||
// 使用手动构建日期字符串的方式,避免时区问题
|
||
const endYear = endDate.getFullYear();
|
||
const endMonth = String(endDate.getMonth() + 1).padStart(2, '0');
|
||
const endDay = String(endDate.getDate()).padStart(2, '0');
|
||
const endHours = String(endDate.getHours()).padStart(2, '0');
|
||
const endMinutes = String(endDate.getMinutes()).padStart(2, '0');
|
||
const endSeconds = String(endDate.getSeconds()).padStart(2, '0');
|
||
this.endTime = `${endYear}-${endMonth}-${endDay} ${endHours}:${endMinutes}:${endSeconds}`;
|
||
}
|
||
|
||
this.paymentAmount = this.monthCount * this.monthPrice;
|
||
this.showMonthCountPopup = false;
|
||
},
|
||
|
||
// 下一步
|
||
goToNextStep() {
|
||
if (!this.isAllFilled) {
|
||
uni.showModal({
|
||
title: "提示",
|
||
content: "请填写完整信息",
|
||
showCancel: false,
|
||
});
|
||
return;
|
||
}
|
||
// 构建跳转参数
|
||
const params = {
|
||
headerTitle: this.headerTitle,
|
||
selectedParkType: this.selectedParkType,
|
||
selectedParkId: this.selectedParkId,
|
||
selectedCarPlateId: this.selectedCarPlateId,
|
||
selectedCarPlate: this.selectedCarPlate,
|
||
monthPrice: this.monthPrice,
|
||
monthCount: this.monthCount,
|
||
startTime: this.startTime,
|
||
endTime: this.endTime,
|
||
paymentAmount: this.paymentAmount,
|
||
selectedBillingRule: this.selectedBillingRule,
|
||
};
|
||
NavgateTo(`../parkOrderDetail/index?item=${encodeURIComponent(JSON.stringify(params))}`);
|
||
},
|
||
|
||
// 查看订单记录
|
||
viewOrderRecords() {
|
||
NavgateTo('../monthlyPaymentOrder/index');
|
||
},
|
||
|
||
// 获取停车场列表
|
||
getParkList() {
|
||
request(apiArr.parkList, "POST", {}).then((res) => {
|
||
this.parkingLots = res.parking_list;
|
||
})
|
||
},
|
||
// 获取车牌列表
|
||
getCarPlateList() {
|
||
request(apiArr.carList, "POST", {}).then((res) => {
|
||
this.carPlateList = res.car_list;
|
||
})
|
||
},
|
||
|
||
// 获取计费规则列表
|
||
getBillingRulesList() {
|
||
const params = {
|
||
parking_id: this.selectedParkId,
|
||
}
|
||
request(apiArr.billingRulesList, "POST", params).then((res) => {
|
||
this.billingRulesList = res.billing_rules_list;
|
||
})
|
||
},
|
||
|
||
// 根据经纬度计算距离
|
||
getParkDistance(parkLng, parkLat) {
|
||
try {
|
||
let locationData = uni.getStorageSync('location');
|
||
if (!locationData) {
|
||
return '未知';
|
||
}
|
||
|
||
let location= locationData;
|
||
|
||
const userLat = location.lat;
|
||
const userLng = location.lng;
|
||
|
||
// 使用Haversine公式计算距离(单位:千米)
|
||
const R = 6371; // 地球半径(千米)
|
||
const dLat = (parkLat - userLat) * Math.PI / 180;
|
||
const dLng = (parkLng - userLng) * Math.PI / 180;
|
||
const a =
|
||
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||
Math.cos(userLat * Math.PI / 180) * Math.cos(parkLat * Math.PI / 180) *
|
||
Math.sin(dLng / 2) * Math.sin(dLng / 2);
|
||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||
const distance = R * c;
|
||
|
||
// 保留一位小数
|
||
return distance.toFixed(1);
|
||
} catch (error) {
|
||
console.error('计算距离时出错:', error);
|
||
return '未知';
|
||
}
|
||
},
|
||
},
|
||
onLoad() {
|
||
// 设置开始时间为今天的 0:00:00
|
||
const today = new Date();
|
||
const year = today.getFullYear();
|
||
const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
|
||
const day = String(today.getDate()).padStart(2, '0');
|
||
// 直接构建格式为 'YYYY-MM-DD HH:mm:ss' 的字符串
|
||
this.startTime = `${year}-${month}-${day} 00:00:00`;
|
||
|
||
// 初始化支付金额
|
||
this.paymentAmount = this.monthCount * this.monthPrice;
|
||
this.getParkList();
|
||
this.getCarPlateList();
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
@import url('./index.css');
|
||
</style> |