chuangte_bike_newxcx/page_shanghu/guanli/kajuan_peie_add.vue
2026-01-28 18:00:39 +08:00

552 lines
12 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" back-icon-color="#111827" title-color='#111827'
title-size='34' title-bold height='44'>
</u-navbar>
<!-- 表单区域 -->
<view class="form-container">
<!-- 用户手机号 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">用户手机号</text>
<text class="label-hint">必填</text>
</view>
<view class="form-input">
<input type="text" v-model="formData.userPhone" placeholder="请输入用户手机号" maxlength="11" />
</view>
</view>
<!-- 选择卡券 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">选择卡券</text>
<text class="label-hint">必填</text>
</view>
<view class="form-select" @click="openCouponPicker">
<text :class="[selectedCoupon ? '' : 'placeholder']">
{{ selectedCoupon ? selectedCoupon.name : '请选择卡券' }}
</text>
<u-icon name="arrow-right" size="28" color="#999"></u-icon>
</view>
</view>
<!-- 配额数量 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">配额数量</text>
<text class="label-hint">必填</text>
</view>
<view class="form-input">
<input type="number" v-model="formData.count" placeholder="请输入配额数量" />
</view>
</view>
<!-- 开始时间 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">开始时间</text>
<text class="label-hint">必填</text>
</view>
<picker mode="date" :value="formData.startTime" @change="onStartTimeChange">
<view class="form-select">
<text :class="[formData.startTime ? '' : 'placeholder']">
{{ formData.startTime || '请选择开始时间' }}
</text>
<u-icon name="arrow-right" size="28" color="#999"></u-icon>
</view>
</picker>
</view>
<!-- 结束时间 -->
<view class="form-item">
<view class="form-label">
<text class="label-text">结束时间</text>
<text class="label-hint">必填</text>
</view>
<picker mode="date" :value="formData.endTime" @change="onEndTimeChange" :start="formData.startTime">
<view class="form-select">
<text :class="[formData.endTime ? '' : 'placeholder']">
{{ formData.endTime || '请选择结束时间' }}
</text>
<u-icon name="arrow-right" size="28" color="#999"></u-icon>
</view>
</picker>
</view>
</view>
<!-- 底部占位 -->
<view class="footer-placeholder"></view>
<!-- 底部按钮 -->
<view class="footer-container">
<view class="add-btn-wrap" @click="handleSave">
<view class="btn-shadow"></view>
<view class="btn-content">
<text>确认分配</text>
</view>
</view>
</view>
<!-- 卡券选择弹窗 -->
<view class="coupon-popup" v-if="showCouponPicker">
<view class="popup-mask" @click="closeCouponPicker"></view>
<view class="popup-content">
<view class="popup-header">
<text class="popup-title">选择卡券</text>
<text class="popup-close" @click="closeCouponPicker">×</text>
</view>
<!-- 搜索框 -->
<view class="search-box">
<u-icon name="search" size="28" color="#999"></u-icon>
<input type="text" v-model="couponSearchKey" placeholder="搜索卡券名称" @input="filterCoupons" />
</view>
<!-- 卡券列表 -->
<scroll-view scroll-y class="coupon-list">
<view class="coupon-item"
v-for="coupon in filteredCouponList"
:key="coupon.id"
@click="selectCoupon(coupon)"
:class="[selectedCoupon && selectedCoupon.id === coupon.id ? 'selected' : '']">
<view class="coupon-info">
<text class="coupon-name">{{ coupon.name }}</text>
<text class="coupon-desc">有效期:{{ coupon.validDays }}天 | ¥{{ coupon.price }}</text>
</view>
<view class="check-box" :class="[selectedCoupon && selectedCoupon.id === coupon.id ? 'checked' : '']">
<u-icon v-if="selectedCoupon && selectedCoupon.id === coupon.id" name="checkmark" size="24" color="#fff"></u-icon>
</view>
</view>
<u-empty v-if="filteredCouponList.length === 0" mode="search" text="暂无卡券" margin-top="60"></u-empty>
</scroll-view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
bgc: {
backgroundColor: "#F7F8FA",
},
areaId: '',
formData: {
userPhone: '',
vipId: '',
count: '',
startTime: '',
endTime: ''
},
showCouponPicker: false,
couponList: [], // 所有卡券列表
filteredCouponList: [], // 过滤后的卡券列表
selectedCoupon: null, // 已选择的卡券
couponSearchKey: ''
}
},
onLoad(option) {
this.areaId = option.areaId || ''
this.getCouponList()
},
methods: {
// 获取卡券列表
getCouponList() {
this.$u.get('/bst/vip/list', {
areaId: this.areaId,
pageNum: 1,
pageSize: 999
}).then(res => {
if (res.code === 200) {
const rows = res.rows || []
this.couponList = rows
this.filteredCouponList = JSON.parse(JSON.stringify(this.couponList))
}
})
},
// 打开卡券选择器
openCouponPicker() {
this.couponSearchKey = ''
this.filterCoupons()
this.showCouponPicker = true
},
// 关闭卡券选择器
closeCouponPicker() {
this.showCouponPicker = false
},
// 过滤卡券
filterCoupons() {
let list = []
if (!this.couponSearchKey) {
list = JSON.parse(JSON.stringify(this.couponList))
} else {
const key = this.couponSearchKey.toLowerCase()
list = this.couponList.filter(item => item.name.toLowerCase().indexOf(key) > -1)
}
this.filteredCouponList = list
},
// 选择卡券
selectCoupon(coupon) {
this.selectedCoupon = coupon
this.formData.vipId = coupon.id
this.showCouponPicker = false
},
// 开始时间选择
onStartTimeChange(e) {
this.formData.startTime = e.detail.value
},
// 结束时间选择
onEndTimeChange(e) {
this.formData.endTime = e.detail.value
},
// 保存
handleSave() {
// 验证手机号
if (!this.formData.userPhone) {
uni.showToast({
title: '请输入用户手机号',
icon: 'none'
})
return
}
if (!/^1[3-9]\d{9}$/.test(this.formData.userPhone)) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
})
return
}
// 验证卡券
if (!this.formData.vipId || !this.selectedCoupon) {
uni.showToast({
title: '请选择卡券',
icon: 'none'
})
return
}
// 验证配额数量
if (!this.formData.count) {
uni.showToast({
title: '请输入配额数量',
icon: 'none'
})
return
}
const count = parseInt(this.formData.count, 10)
if (isNaN(count) || count <= 0) {
uni.showToast({
title: '配额数量必须大于0',
icon: 'none'
})
return
}
// 验证开始时间
if (!this.formData.startTime) {
uni.showToast({
title: '请选择开始时间',
icon: 'none'
})
return
}
// 验证结束时间
if (!this.formData.endTime) {
uni.showToast({
title: '请选择结束时间',
icon: 'none'
})
return
}
// 验证结束时间必须大于开始时间
if (new Date(this.formData.endTime) <= new Date(this.formData.startTime)) {
uni.showToast({
title: '结束时间必须大于开始时间',
icon: 'none'
})
return
}
const submitData = {
userPhone: this.formData.userPhone,
vipId: this.formData.vipId,
count: count,
startTime: this.formData.startTime + ' 00:00:00',
endTime: this.formData.endTime + ' 23:59:59'
}
this.$u.post('/bst/vipQuota', submitData).then(res => {
if (res.code === 200) {
uni.showToast({
title: '分配成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
uni.showToast({
title: res.msg || '分配失败',
icon: 'none'
})
}
}).catch(() => {
uni.showToast({
title: '网络错误',
icon: 'none'
})
})
}
}
}
</script>
<style lang="scss">
page {
background-color: #F7F8FA;
min-height: 100vh;
}
.page {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.form-container {
padding: 24rpx 32rpx;
}
.form-item {
background: #FFFFFF;
border-radius: 20rpx;
padding: 32rpx;
margin-bottom: 24rpx;
.form-label {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.label-text {
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.label-hint {
font-size: 24rpx;
color: #999;
margin-left: 12rpx;
}
}
.form-input {
background: #F7F8FA;
border-radius: 12rpx;
padding: 24rpx;
input {
width: 100%;
font-size: 28rpx;
color: #333;
}
}
.form-select {
background: #F7F8FA;
border-radius: 12rpx;
padding: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
text {
font-size: 28rpx;
color: #333;
}
.placeholder {
color: #999;
}
}
}
.footer-placeholder {
height: 200rpx;
}
.footer-container {
position: fixed;
bottom: 60rpx;
left: 0;
right: 0;
display: flex;
justify-content: center;
z-index: 100;
padding: 0 32rpx;
.add-btn-wrap {
position: relative;
width: 100%;
height: 100rpx;
.btn-content {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #4297F3 0%, #2B76E5 100%);
border-radius: 100rpx;
display: flex;
align-items: center;
justify-content: center;
color: #FFFFFF;
font-size: 32rpx;
font-weight: bold;
z-index: 2;
box-shadow: 0 10rpx 20rpx rgba(66, 151, 243, 0.3);
}
.btn-shadow {
position: absolute;
top: 20rpx;
left: 10%;
width: 80%;
height: 100%;
background: #4297F3;
filter: blur(20rpx);
opacity: 0.4;
border-radius: 100rpx;
z-index: 1;
}
}
}
// 卡券选择弹窗
.coupon-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
.popup-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
}
.popup-content {
position: absolute;
left: 0;
right: 0;
bottom: 0;
background: #FFFFFF;
border-radius: 40rpx 40rpx 0 0;
max-height: 70vh;
display: flex;
flex-direction: column;
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx;
border-bottom: 1rpx solid #F0F0F0;
.popup-title {
font-size: 34rpx;
font-weight: 600;
color: #333;
}
.popup-close {
font-size: 48rpx;
color: #999;
line-height: 1;
}
}
.search-box {
display: flex;
align-items: center;
margin: 24rpx 32rpx;
padding: 20rpx 24rpx;
background: #F7F8FA;
border-radius: 40rpx;
input {
flex: 1;
margin-left: 16rpx;
font-size: 28rpx;
color: #333;
}
}
.coupon-list {
width: 720rpx;
margin: auto;
max-height: 50vh;
overflow: scroll;
.coupon-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 28rpx 24rpx;
background: #F9FAFB;
border-radius: 16rpx;
margin-bottom: 16rpx;
.coupon-info {
flex: 1;
.coupon-name {
font-size: 30rpx;
font-weight: 500;
color: #333;
display: block;
margin-bottom: 8rpx;
}
.coupon-desc {
font-size: 24rpx;
color: #999;
}
}
.check-box {
width: 44rpx;
height: 44rpx;
border: 2rpx solid #D9D9D9;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.checked {
background: #4297F3;
border-color: #4297F3;
}
}
.selected {
background: linear-gradient(135deg, #E8F4FD 0%, #D4ECFD 100%);
border: 2rpx solid #4297F3;
}
}
}
}
</style>