2025-09-01 11:36:01 +08:00

442 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>