chuangte_bike_newxcx/page_shanghu/gongzuotai/ChargingDetail.vue
2025-04-28 15:40:26 +08:00

961 lines
23 KiB
Vue
Raw Permalink 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="page">
<u-navbar title="收费模版编辑" :border-bottom="false" :background="bgc" title-color='#000' title-size='36'
height='45'></u-navbar>
<view class="card">
<view class="card_li">
<view class="tops">
<view class="card_left">
套餐名称
</view>
<view class="card_right">
<input type="text" v-model="data.name" placeholder="请输入套餐名称" class="input"
placeholder-style="color:#C7CDD3">
</view>
</view>
</view>
<view class="card_li">
<view class="tops">
<view class="card_left">
显示顺序
</view>
<view class="card_right">
<input type="text" v-model="data.orderNum" placeholder="请输入显示顺序" class="input"
placeholder-style="color:#C7CDD3">
</view>
</view>
<view class="tips">
显示顺序数字越小越靠前
</view>
</view>
<view class="card_li">
<view class="tops">
<view class="card_left">
说明
</view>
<view class="card_right">
<input type="text" v-model="data.instructions" placeholder="请输入说明内容" class="input"
placeholder-style="color:#C7CDD3">
</view>
</view>
</view>
<view class="card_li">
<view class="tops">
<view class="card_left">
免费骑行
</view>
<view class="card_right">
<input type="text" v-model="data.freeRideTime" placeholder="可以免费骑行的时间" class="input"
placeholder-style="color:#C7CDD3">
</view>
</view>
<view class="tips">
可以免费骑行的时间(分钟)
</view>
</view>
<!-- <view class="card_li">
<view class="tops">
<view class="card_left">
还车结算
</view>
<view class="card_right">
<input type="text" v-model="data.autoRefundDeposit" placeholder="多少小时后自动退押金" class="input"
placeholder-style="color:#C7CDD3">
</view>
</view>
<view class="tips">
多少小时后自动退押金(小时)
</view>
</view> -->
<view class="card_li">
<view class="tops">
<view class="card_left">
租赁单位
</view>
<view class="card_right">
<u-radio-group v-model="timevalue" @change="radioGroupChange">
<u-radio v-for="(item, index) in timeList" :key="index" :name="item.name"
:disabled="item.disabled">
{{item.name}}
</u-radio>
</u-radio-group>
</view>
</view>
</view>
<view class="card_li">
<view class="tops">
<view class="card_left">
计费方式
</view>
<view class="card_right">
<u-radio-group v-model="data.ridingRule" @change="chargeTypeChange">
<u-radio :name="1">普通计费</u-radio>
<u-radio :name="2">区间计费</u-radio>
</u-radio-group>
</view>
</view>
</view>
<!-- 普通计费模式 -->
<template v-if="data.ridingRule == 1">
<view class="card_li">
<view class="rule">
起步价
<input type="text" v-model="startingPrice" placeholder=" " class="input"
placeholder-style="color:#C7CDD3">
元 含( <input type="text" v-model="startingTime" placeholder=" " class="input"
placeholder-style="color:#C7CDD3"> {{timevalue}}
</view>
</view>
<view class="card_li">
<view class="rule">
超出价
<input type="text" v-model="timeoutPrice" placeholder=" " class="input"
placeholder-style="color:#C7CDD3">
元 / <input type="text" v-model="timeoutTime" placeholder=" " class="input"
placeholder-style="color:#C7CDD3">{{timevalue}}
</view>
<view class="tips" style="text-align: left;">
超出起步价后
</view>
<view class="tips" style="text-align: left;">
<view class="">
1.为避免免费用户使用,切勿频繁切换
</view>
<view class="" style="padding-left: 48rpx;">
2.不是起步时间的仍按起步时间收取费用;超出起步时间后的均匀计算
</view>
</view>
</view>
</template>
<!-- 区间计费模式 -->
<template v-if="data.ridingRule == 2">
<view class="card_li" v-for="(item, index) in intervalRule" :key="index">
<view class="interval-box">
<view class="interval-title">
<text>区间{{index + 1}}</text>
<text v-if="index > 0" class="delete-btn" @click="deleteRule(index)">删除</text>
</view>
<view class="interval-content">
<view class="time-range">
<text>{{index === 0 ? 0 : intervalRule[index-1].end}}</text>
<text>{{timevalue}} - </text>
<block v-if="index === intervalRule.length - 1">
<text>不限</text>
</block>
<block v-else>
<input type="number" v-model="item.end" class="input" :placeholder="'请输入结束'+timevalue"
@blur="handleEndChange(index)">
<text>{{timevalue}}</text>
</block>
</view>
<view class="unit-price">
<text>每</text>
<input type="number" v-model="item.eachUnit" class="input" placeholder="请输入">
<text>{{timevalue}}收费</text>
<input type="number" v-model="item.fee" class="input" placeholder="请输入">
<text>元</text>
</view>
</view>
</view>
</view>
<view class="card_li" v-if="intervalRule.length < 5">
<view class="add-rule" @click="addRule">
<text class="add-icon">+</text>
<text>添加区间</text>
</view>
</view>
</template>
<!-- <view class="card_li">
<view class="tops">
<view class="card_left">
计费周期
</view>
<view class="card_right">
订单生成后
<input type="text" v-model="data.chargingCycleValue" placeholder="多少小时后自动退押金" class="input"
placeholder-style="color:#C7CDD3" style="width: 100rpx;">小时
</view>
</view>
<view class="tips" style="text-align: left;">
1) 若计费周期为订单生成后X小时每达到X小时订单按规则重新计费各周期内金额总和为订单总费用
2) 若计费周期为自定义时刻,每当达到该时刻,订单按规则重新计费,各周期内金额总和为订单总费用
</view>
</view> -->
<view class="card_li">
<view class="tops">
<view class="card_left">
预存
</view>
<view class="card_right" style="display: flex;align-items: center;">
<input type="text" v-model="data.depositAmount" placeholder="多少小时后自动退押金" class="input"
placeholder-style="color:#C7CDD3" style="width: 100rpx;margin-right: 10rpx;"> 元
</view>
</view>
<view class="tips" style="text-align: left;">
注:在单个计费周期内,达到封顶金额后,则订单费用不再增加;超过计费周期后,在新的周期内重新计费,订单总费用继续增加
</view>
</view>
</view>
<view class="card">
<view class="card_li1">
<view class="card_top" @click="showpart = true">
<view class="card_left">
车型模版
</view>
<view class="card_right">
<view class="iconfont icon-xiangyou1 " style="color: #CBCBCB;">
</view>
</view>
</view>
<view class="taocan" v-if="lists.suitIds">
<view v-for="(name, index) in getAccessoryNames()" :key="index"
style="width: 100%; display: flex;margin-top: 10rpx;">
<view class="tc_li">
{{ name }}
</view>
</view>
</view>
</view>
</view>
<u-mask :show="showpart" :z-index='100' @click="closepart()" />
<view class="choose_part" v-if="showpart">
<view class="tit">
选择车型
</view>
<scroll-view class="part_box" scroll-y>
<view class="part_list">
<view class="part_item" v-for="(item, index) in Accessorylist" :key="index"
@click="chooseAcc(item.id)">
<view class="part" :class="lists.suitIds.includes(item.id) ? 'act' : ''">
{{ item.name }}
<image src="https://lxnapi.ccttiot.com/bike/img/static/uJNlGEGmN0F4AuPJmOZn" mode=""
v-if="lists.suitIds.includes(item.id)">
</image>
</view>
</view>
</view>
</scroll-view>
<view class="btn" @click="subacc()">
确定
</view>
</view>
<view class="btn_box">
<view class="btn1" @click="backpage()">
取消
</view>
<view class="btn2" @click="sub">
保存
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
lists: {
model: "",
fullVoltage: "",
lowVoltage: "",
fullEndurance: "",
suitIds: [],
lowBatteryReminder: '20',
lowBatteryReminderSwitch: false
},
showpart: false,
bgc: {
backgroundColor: "#fff",
},
showpart: false,
list: [],
Accessorylist: [],
chooseIdxArr: [], // 存储选中的索引
timevalue: '分钟',
timeList: [{
name: '分钟',
disabled: false
},
{
name: '小时',
disabled: false
},
{
name: '天',
disabled: false
},
],
startingPrice: "",
startingTime: '',
timeoutPrice: '',
timeoutTime: '',
data: {
name: '',
instructions: '',
orderNum:'',
status: "0",
autoRefundDeposit: '0',
orderExceedMinutes: '',
orderExceedWarn: '',
freeRideTime: '5',
rentalUnit: 'minutes',
ridingRule: '1',
chargingCycle: '1',
chargingCycleValue: '24',
depositAmount: '200',
timeoutTime: '',
startingTime: '',
orderNum:0,
userId:'',
startRule:{},
modellds:[]
},
ruleId: '',
userinfo: {},
intervalRule: [
{
start: 0,
end: '',
fee: '',
eachUnit: '10'
},
{
start: '',
end: '',
fee: '',
eachUnit: '10'
},
{
start: '',
end: null,
fee: '',
eachUnit: '10'
}
]
}
},
onLoad(e) {
if (e.ruleId) {
this.ruleId = e.ruleId
this.getFeeInfo()
}
},
onShow() {
this.getinfo()
},
methods: {
closepart() {
this.showpart = false
},
subacc() {
this.showpart = false
console.log(this.chooseIdxArr)
},
chooseAcc(id) {
const index = this.lists.suitIds.indexOf(id)
if (index > -1) {
// 如果 id 已经存在于 suitIds 中,则从数组中删除
this.lists.suitIds.splice(index, 1)
} else {
// 如果 id 不存在,则添加到 suitIds 中
this.lists.suitIds.push(id)
}
},
getAccessoryNames(accessoryIds) {
const accessoryNames = this.lists.suitIds.map(id => {
const item = this.Accessorylist.find(accessory => accessory.id == id)
return item ? item.name : ''
})
// 过滤掉空值并返回数组
return accessoryNames.filter(name => name)
},
getAccessorylist() {
this.$u.get(`/bst/model/list?pageNum=1&pageSize=999&userId=${this.userinfo.userId}`).then((res) => {
if (res.code == 200) {
this.Accessorylist = res.rows
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 1000
})
}
})
},
getinfo() {
this.$u.get("/getInfo").then((res) => {
if (res.code == 200) {
this.userinfo = res.user
this.getAccessorylist()
this.data.userId = this.userinfo.userId
}
})
},
getFeeInfo() {
this.$u.get(`/bst/suit/${this.ruleId}`).then((res) => {
if (res.code == 200) {
this.data = res.data;
this.lists.suitIds = res.data.modelIds
console.log(this.lists);
if (this.data.rentalUnit == 'minutes') {
this.timevalue='分钟'
} else if (this.data.rentalUnit == 'hours') {
this.timevalue='小时'
} else if (this.data.rentalUnit == 'day') {
this.timevalue='天'
}
if (this.data.area) {
this.returnVerify = this.data.area.returnVerify;
}
if (this.data.ridingRule == 1) {
if (this.data.startRule) {
this.timeoutTime = this.data.startRule.timeoutTime || '';
this.startingPrice = this.data.startRule.startingPrice || '';
this.startingTime = this.data.startRule.startingTime || '';
this.timeoutPrice = this.data.startRule.timeoutPrice || '';
}
} else if (this.data.ridingRule == 2) {
if (this.data.intervalRule && Array.isArray(this.data.intervalRule)) {
this.intervalRule = JSON.parse(JSON.stringify(this.data.intervalRule));
this.more = this.data.intervalRule[this.data.intervalRule.length - 1];
} else {
this.intervalRule = [
{
start: 0,
end: '',
fee: '',
eachUnit: '10'
},
{
start: '',
end: '',
fee: '',
eachUnit: '10'
},
{
start: '',
end: null,
fee: '',
eachUnit: '10'
}
];
}
}
console.log('处理后的数据:', {
data: this.data,
intervalRule: this.intervalRule,
more: this.more
});
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 1000
})
}
})
},
backpage() {
uni.navigateBack()
},
// 选中任一radio时由radio-group触发
radioGroupChange(e) {
if (e == '分钟') {
this.data.rentalUnit = 'minutes'
} else if(e == '小时'){
this.data.rentalUnit = 'hours'
}else {
this.data.rentalUnit = 'day'
}
},
chargeTypeChange(value) {
this.data.ridingRule = value;
if(value === 2) {
this.intervalRule = [
{
start: 0,
end: '',
fee: '',
eachUnit: '10'
},
{
start: '',
end: '',
fee: '',
eachUnit: '10'
},
{
start: '',
end: null,
fee: '',
eachUnit: '10'
}
];
}
},
handleEndChange(index) {
if(index < this.intervalRule.length - 1) {
this.intervalRule[index + 1].start = this.intervalRule[index].end;
}
},
addRule() {
// 移除最后一个元素
const lastRule = this.intervalRule.pop();
// 添加新规则
this.intervalRule.push({
start: this.intervalRule[this.intervalRule.length - 1].end,
end: '',
fee: '',
eachUnit: '10'
});
// 添加回最后一个不限的规则
this.intervalRule.push(lastRule);
},
deleteRule(index) {
if(index === 0 || index === this.intervalRule.length - 1) return;
this.intervalRule.splice(index, 1);
// 更新后续区间的起始值
for(let i = index; i < this.intervalRule.length - 1; i++) {
this.intervalRule[i].start = this.intervalRule[i-1].end;
}
},
sub() {
console.log(this.lists.suitIds,'000');
let data = {
...this.data,
type: 1,
modelIds:this.lists.suitIds
}
console.log(data,'111');
if (this.data.ridingRule == 2) {
// 区间计费时直接使用intervalRule字段
data.intervalRule = this.intervalRule.map((item, index) => ({
start: index === 0 ? 0 : Number(item.start),
end: index === this.intervalRule.length - 1 ? null : Number(item.end),
fee: Number(item.fee),
eachUnit: Number(item.eachUnit)
}));
// 删除startRule字段
delete data.startRule;
} else {
// 普通计费使用startRule
data.startRule = {
timeoutTime: this.timeoutTime,
startingPrice: this.startingPrice,
startingTime: this.startingTime,
timeoutPrice: this.timeoutPrice
}
}
console.log(data, 'mmmmmmmmmmmmm')
if (this.ruleId != '') {
this.$u.put(`/bst/suit`, data).then((res) => {
if (res.code == 200) {
uni.showToast({
title: '修改成功',
icon: 'success',
duration: 1000
})
setTimeout(() => {
uni.navigateBack()
}, 1100)
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
} else {
this.$u.post(`/bst/suit`, data).then((res) => {
if (res.code == 200) {
uni.showToast({
title: '添加成功',
icon: 'success',
duration: 1000
})
setTimeout(() => {
uni.navigateBack()
}, 1100)
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
})
}
})
}
}
}
}
</script>
<style lang="scss">
page {
background-color: #f5f7fa;
}
.choose_part {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 110;
width: 644rpx;
padding: 40rpx 48rpx;
background: #FFFFFF;
border-radius: 26rpx;
.part_box {
margin-top: 40rpx;
max-height: 600rpx;
.part_list {
display: flex;
flex-direction: column;
gap: 20rpx;
.part_item {
width: 100%;
}
.part {
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx;
background: #F0F0F0;
border-radius: 12rpx;
border: 1rpx solid #F0F0F0;
font-size: 32rpx;
color: #3D3D3D;
transition: all 0.3s ease;
image {
position: absolute;
right: 10rpx;
bottom: 10rpx;
width: 34rpx;
height: 34rpx;
}
&.act {
background: #DCEDFF;
border: 1rpx solid #4297F3;
color: #4297F3;
}
&:active {
opacity: 0.8;
}
}
}
}
.tit {
width: 100%;
text-align: center;
font-weight: 600;
font-size: 36rpx;
color: #3D3D3D;
margin-bottom: 20rpx;
}
.btn {
margin-top: 40rpx;
width: 100%;
height: 88rpx;
background: #4C97E7;
border-radius: 10rpx;
font-weight: 600;
font-size: 36rpx;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
&:active {
opacity: 0.9;
}
}
}
.card {
padding: 0 24rpx;
margin: 0 auto;
margin-top: 24rpx;
width: 672rpx;
background: #FFFFFF;
box-shadow: 0rpx 4rpx 22rpx 0rpx rgba(0, 0, 0, 0.07);
border-radius: 10rpx 10rpx 10rpx 10rpx;
.card_li:last-child {
border-bottom: 1rpx solid #fff;
}
.card_li1 {
padding-top: 24rpx;
display: flex;
flex-wrap: wrap;
.taocan {
margin-top: 10rpx;
padding-bottom: 20rpx;
display: flex;
flex-wrap: wrap;
.tc_li {
padding: 8rpx 14rpx;
margin-right: 20rpx;
background: #DCEDFF;
border-radius: 6rpx 6rpx 6rpx 6rpx;
font-weight: 400;
font-size: 26rpx;
color: #4297F3;
}
}
.card_top {
display: flex;
flex-wrap: nowrap;
align-content: center;
justify-content: space-between;
width: 100%;
// border-bottom: 1rpx solid #D8D8D8;
padding-bottom: 18rpx;
.card_left {
font-weight: 400;
font-size: 30rpx;
color: #3D3D3D;
}
.card_right {
display: flex;
flex-wrap: nowrap;
align-items: center;
span {
font-weight: 400;
font-size: 30rpx;
color: #3D3D3D;
}
.input {
text-align: right;
/* 输入框内容靠右显示 */
}
}
}
}
}
.page {
padding: 24rpx;
padding-bottom: 180rpx;
background-color: #f5f7fa;
.card {
margin-bottom: 32rpx;
background: #ffffff;
border-radius: 16rpx;
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.04);
overflow: hidden;
transition: all 0.3s ease;
&:active {
transform: translateY(2rpx);
}
.card_li {
padding: 32rpx;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.tops {
display: flex;
align-items: center;
.card_left {
font-size: 32rpx;
color: #333;
font-weight: 500;
width: 180rpx;
}
.card_right {
flex: 1;
.input {
width: 90%;
padding: 16rpx 24rpx;
background: #f8f9fa;
border-radius: 12rpx;
font-size: 30rpx;
color: #333;
border: 1rpx solid #e6e8eb;
transition: all 0.2s ease;
&:focus {
border-color: #4C97E7;
box-shadow: 0 0 0 2rpx rgba(76, 151, 231, 0.2);
}
}
.u-radio-group {
display: flex;
// gap: 40rpx;
.u-radio {
font-size: 28rpx;
color: #666;
&.is-checked {
color: #4C97E7;
}
}
}
}
}
.rule {
display: flex;
align-items: center;
flex-wrap: wrap;
// gap: 12rpx;
font-size: 30rpx;
color: #333;
.input {
padding: 8rpx 8rpx;
background: #f8f9fa;
border-radius: 8rpx;
border: 1rpx solid #e6e8eb;
width: 120rpx;
text-align: center;
font-size: 28rpx;
color: #333;
}
}
.tips {
margin-top: 16rpx;
font-size: 24rpx;
color: #999;
line-height: 1.6;
&.warning {
color: #faad14;
background: #fffbe6;
padding: 12rpx 16rpx;
border-radius: 8rpx;
margin-top: 16rpx;
}
}
}
}
.btn_box {
position: fixed;
bottom: 32rpx;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 24rpx;
width: 90%;
z-index: 10;
.btn1, .btn2 {
flex: 1;
height: 96rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 34rpx;
font-weight: 500;
border-radius: 48rpx;
transition: all 0.2s ease;
&:active {
transform: scale(0.98);
}
}
.btn1 {
background: #fff;
color: #4C97E7;
border: 1rpx solid #4C97E7;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
}
.btn2 {
background: linear-gradient(90deg, #4C97E7, #6ab0ff);
color: #fff;
box-shadow: 0 8rpx 24rpx rgba(76, 151, 231, 0.3);
}
}
}
.interval-box {
background: #f8f9fa;
border-radius: 12rpx;
padding: 24rpx;
.interval-title {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
font-size: 32rpx;
font-weight: 500;
.delete-btn {
color: #ff4d4f;
font-size: 28rpx;
padding: 4rpx 12rpx;
}
}
.interval-content {
.time-range, .unit-price {
display: flex;
align-items: center;
margin-bottom: 16rpx;
font-size: 28rpx;
color: #333;
.input {
width: 120rpx;
height: 60rpx;
background: #fff;
border: 1rpx solid #e6e8eb;
border-radius: 8rpx;
padding: 0 12rpx;
margin: 0 12rpx;
text-align: center;
}
}
.time-range {
text {
margin: 0 8rpx;
}
}
}
}
.add-rule {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx;
color: #4C97E7;
font-size: 28rpx;
.add-icon {
font-size: 36rpx;
margin-right: 8rpx;
}
}
</style>