Compare commits

..

14 Commits

Author SHA1 Message Date
4d62d1bd04 添加储值卡消费 2026-05-08 10:41:30 +08:00
aed08c445e 开通套餐之前,需要阅读服务协议 2026-05-08 10:41:14 +08:00
d897df444b 修改套餐列表样式 2026-04-23 17:45:07 +08:00
81bc063586 修改拨打电话的时候,灯光支付未0的问题 2026-04-23 14:54:20 +08:00
a4e9fa5daf 完善功能 2026-04-23 14:38:53 +08:00
5edfca8ff2 完善功能 2026-04-13 01:53:05 +08:00
f8ac363bcd 优化页面 2026-04-12 15:04:01 +08:00
74aa8d8ac4 完善功能 2026-04-11 23:00:20 +08:00
be1ce34a74 完善套餐购买、人脸拍照功能 2026-04-11 18:33:23 +08:00
2a95c0e176 完善购买详情 2026-04-11 00:23:57 +08:00
2e568f8f8d 创建套餐订单 2026-04-10 11:28:42 +08:00
c9c1d74957 添加套餐管理 2026-04-10 00:16:04 +08:00
8854cdd32d 添加篮球套餐功能 2026-04-07 16:07:36 +08:00
bd461f3e18 完善功能 2026-03-02 17:08:36 +08:00
30 changed files with 3825 additions and 62 deletions

126
bundle/combo/combo-list.vue Normal file
View File

@ -0,0 +1,126 @@
<template>
<view>
<navbar title="套餐卡"></navbar>
<view style="margin-top: 20px;">
<!-- 青年卡 -->
<view class="pr d-c-c mb-20" v-for="item in list" :key="item.id" @click="jumpPage(`/bundle/combo/details?id=${item.id}`)">
<view class="pr">
<image :src="item.img" style="width: 690rpx; height: 300rpx;" />
<view class="kt-eg-name">
{{ item.eg_name }}
</view>
<view class="kt-name">{{ item.name }}</view>
<view class="kt-btn-bg">
<view :class="item.order ? 'kt-txt2' : 'kt-txt1'">{{ item.order ? '续费' : '立即开通' }}</view>
</view>
<view class="kt-price-box" style="position: absolute; right: 40rpx; bottom: 22rpx; display: flex; align-items: center;">
<view class="kt-price" v-if="item.month_price && item.month_price > 0" style="color: #977A5D; font-size: 28rpx; font-weight: bold; margin-right: 20rpx;">月卡 {{ item.month_price }}</view>
<view class="kt-price" v-if="item.seasonal_price && item.seasonal_price > 0" style="color: #977A5D; font-size: 28rpx; font-weight: bold;">季卡 {{ item.seasonal_price }}</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import navbar from '@/components/navbar.vue';
export default {
components: {
navbar,
},
data() {
return {
list: [],
}
},
onShow() {
this.handleGetList();
},
methods: {
handleGetList() {
// 获取套餐卡列表
let self = this;
self._post(
'ground.group/getGroupList',
null,
result => {
self.list = result.data;
},
false,
() => {
}
);
},
/*跳转页面*/
jumpPage(path) {
this.gotoPage(path);
},
}
}
</script>
<style lang="scss">
page {
background-color: #fff;
}
.kt-eg-name {
position: absolute;
left: 46rpx;
top: 52rpx;
color: #C2863E;
font-size: 36rpx;
font-weight: 400;
}
.kt-name {
position: absolute;
left: 64rpx;
top: 118rpx;
color: #C2863E;
font-size: 36rpx;
font-weight: 400;
}
.kt-btn-bg {
position: absolute;
left: 34rpx;
bottom: 44rpx;
background-image: url(https://xh.stnav.com/uploads/sport/kt-btn.png);
background-size: 100% 100%;
width: 258rpx;
height: 56rpx;
line-height: 56rpx;
color: #F62036;
font-size: 30rpx;
font-weight: bold;
& .kt-txt1 {
padding-left: 60rpx;
}
& .kt-txt2 {
padding-left: 80rpx;
}
.kt-price {
color: #C2863E;
margin-left: 10rpx;
font-size: 24rpx;
}
}
.mb-20 {
margin-bottom: 20px;
}
</style>

111
bundle/combo/desc.vue Normal file
View File

@ -0,0 +1,111 @@
<template>
<view class="container">
<view class="main-title">秀湖公园篮球场会员卡注意事项</view>
<view class="section">
<view class="section-title">1. 实名制使用</view>
<view class="section-content">会员卡实行一人一卡/实名绑定制仅限登记本人或绑定家庭成员使用严禁转借共用倒卖一经核实立即停用会员资格且不予退费</view>
</view>
<view class="section">
<view class="section-title">2. 有效期规则</view>
<view class="section-content"> 月卡有效期30天季卡有效期90天自开卡激活当日起算到期自动失效</view>
<view class="section-content"> 会员卡一经办理不予暂停不予延期不可折算退费</view>
</view>
<view class="section">
<view class="section-title">3. 入场使用规范</view>
<view class="section-content"> 仅限球场正常开放时段入场散客运动不支持预约包场占场</view>
<view class="section-content"> 入场须主动出示会员卡或会员码配合工作人员核验</view>
<view class="section-content"> 未成年人入场须有监护人陪同自觉遵守球场安全管理规定</view>
</view>
<view class="section">
<view class="section-title">4. 场地与安全责任</view>
<view class="section-content"> 运动前请做好热身量力而行避免运动损伤球场仅提供场地不承担意外运动伤害责任</view>
<view class="section-content"> 爱护场地设施篮板地面座椅等人为损坏需照价赔偿</view>
<view class="section-content"> 严禁穿黑底鞋高跟鞋钉鞋入场严禁携带宠物玻璃制品尖锐物品入场</view>
</view>
<view class="section">
<view class="section-title">5. 文明运动要求</view>
<view class="section-content"> 禁止在场内追逐打闹争吵斗殴恶意犯规高空抛物等危险行为</view>
<view class="section-content"> 禁止随地吐痰乱扔垃圾保持场地整洁</view>
<view class="section-content"> 服从现场管理人员引导对违规劝阻不听者有权劝离或取消会员资格</view>
</view>
<view class="section">
<view class="section-title">6. 天气与场地调整</view>
<view class="section-content">遇雨雪大风高温雷电等恶劣天气或场地维护市政活动等情况球场可临时关闭不另行补偿天数或费用</view>
</view>
<view class="section">
<view class="section-title">7. 遗失与补办</view>
<view class="section-content">会员卡遗失损坏请及时到服务台挂失补办补办需缴纳工本费补办后原卡作废会员权益不变</view>
</view>
<view class="section">
<view class="section-title">8. 退费与终止</view>
<view class="section-content"> 会员卡一经售出非球场方重大故障原因概不退费</view>
<view class="section-content"> 会员严重违反管理规定屡教不改或造成不良影响的管理方有权直接终止会员权益不予退款</view>
</view>
<view class="section">
<view class="section-title">9. 其他说明</view>
<view class="section-content">会员权益仅限散客入场使用不含教学培训装备租赁饮品停车等其他附加服务</view>
<view class="section-content">本球场保留根据运营需要调整会员规则的权利调整内容将在现场公示后生效</view>
</view>
</view>
</template>
<style lang="scss">
page {
background-color: #f7f8fa;
}
.container {
padding: 40rpx 30rpx 60rpx;
background-color: #fff;
margin: 20rpx;
border-radius: 20rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
}
.main-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
text-align: center;
margin-bottom: 50rpx;
line-height: 1.4;
}
.section {
margin-bottom: 40rpx;
&:last-child {
margin-bottom: 0;
}
}
.section-title {
font-size: 30rpx;
font-weight: bold;
color: #834B08;
margin-bottom: 16rpx;
display: flex;
align-items: center;
}
.section-content {
font-size: 28rpx;
color: #666;
line-height: 1.8;
margin-bottom: 12rpx;
text-align: justify;
&:last-child {
margin-bottom: 0;
}
}
</style>

1157
bundle/combo/details.vue Normal file

File diff suppressed because it is too large Load Diff

257
bundle/combo/face-list.vue Normal file
View File

@ -0,0 +1,257 @@
<template>
<view>
<!-- 青年卡 -->
<view v-if="id == 1"
@click="handleTakePhoto('youth')"
class="photo-item" style="display: flex; align-items: center; justify-content: space-between; padding: 30rpx; background-color: #ffffff; border-radius: 12rpx; margin: 20rpx;">
<view style="display: flex; align-items: center;">
<image src="https://xh.stnav.com/uploads/sport/face2.png" style="width: 90rpx; height: 90rpx; margin-right: 20rpx;"></image>
<view>人脸录入</view>
</view>
<view style="display: flex; align-items: center;">
<text style="color: #666; font-size: 28rpx; margin-right: 10rpx;">{{ youthFace ? '已录入' : '去录入' }}</text>
<image src="/static/icon/right.png" style="width: 32rpx; height: 32rpx;"></image>
</view>
</view>
<!-- 成人卡 -->
<view v-if="id == 2"
@click="handleTakePhoto('adult')"
class="photo-item" style="display: flex; align-items: center; justify-content: space-between; padding: 30rpx; background-color: #ffffff; border-radius: 12rpx; margin: 20rpx;">
<view style="display: flex; align-items: center;">
<image src="https://xh.stnav.com/uploads/sport/face2.png" style="width: 90rpx; height: 90rpx; margin-right: 20rpx;"></image>
<view>人脸录入</view>
</view>
<view style="display: flex; align-items: center;">
<text style="color: #666; font-size: 28rpx; margin-right: 10rpx;">{{ adultFace ? '已录入' : '去录入' }}</text>
<image src="/static/icon/right.png" style="width: 32rpx; height: 32rpx;"></image>
</view>
</view>
<!-- 子女1 -->
<view v-if="id == 3 || id == 4"
@click="handleTakePhoto('child1')"
class="photo-item" style="display: flex; align-items: center; justify-content: space-between; padding: 30rpx; background-color: #ffffff; border-radius: 12rpx; margin: 20rpx;">
<view style="display: flex; align-items: center;">
<image src="https://xh.stnav.com/uploads/sport/face2.png" style="width: 90rpx; height: 90rpx; margin-right: 20rpx;"></image>
<view>子女1录入</view>
</view>
<view style="display: flex; align-items: center;">
<text style="color: #666; font-size: 28rpx; margin-right: 10rpx;">{{ child1Face ? '已录入' : '去录入' }}</text>
<image src="/static/icon/right.png" style="width: 32rpx; height: 32rpx;"></image>
</view>
</view>
<!-- 子女2 -->
<view v-if="id == 4"
@click="handleTakePhoto('child2')"
class="photo-item" style="display: flex; align-items: center; justify-content: space-between; padding: 30rpx; background-color: #ffffff; border-radius: 12rpx; margin: 20rpx;">
<view style="display: flex; align-items: center;">
<image src="https://xh.stnav.com/uploads/sport/face2.png" style="width: 90rpx; height: 90rpx; margin-right: 20rpx;"></image>
<view>子女2录入</view>
</view>
<view style="display: flex; align-items: center;">
<text style="color: #666; font-size: 28rpx; margin-right: 10rpx;">{{ child2Face ? '已录入' : '去录入' }}</text>
<image src="/static/icon/right.png" style="width: 32rpx; height: 32rpx;"></image>
</view>
</view>
<!-- 亲子卡1 -->
<view v-if="id == 3 || id == 4"
@click="handleTakePhoto('parent1')"
class="photo-item" style="display: flex; align-items: center; justify-content: space-between; padding: 30rpx; background-color: #ffffff; border-radius: 12rpx; margin: 20rpx;">
<view style="display: flex; align-items: center;">
<image src="https://xh.stnav.com/uploads/sport/face2.png" style="width: 90rpx; height: 90rpx; margin-right: 20rpx;"></image>
<view>家长1录入</view>
</view>
<view style="display: flex; align-items: center;">
<text style="color: #666; font-size: 28rpx; margin-right: 10rpx;">{{ parent1Face ? '已录入' : '去录入' }}</text>
<image src="/static/icon/right.png" style="width: 32rpx; height: 32rpx;"></image>
</view>
</view>
<!-- 亲子卡2 -->
<view v-if="id == 3 || id == 4"
@click="handleTakePhoto('parent2')"
class="photo-item" style="display: flex; align-items: center; justify-content: space-between; padding: 30rpx; background-color: #ffffff; border-radius: 12rpx; margin: 20rpx;">
<view style="display: flex; align-items: center;">
<image src="https://xh.stnav.com/uploads/sport/face2.png" style="width: 90rpx; height: 90rpx; margin-right: 20rpx;"></image>
<view>家长2录入</view>
</view>
<view style="display: flex; align-items: center;">
<text style="color: #666; font-size: 28rpx; margin-right: 10rpx;">{{ parent2Face ? '已录入' : '去录入' }}</text>
<image src="/static/icon/right.png" style="width: 32rpx; height: 32rpx;"></image>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
id: 0,
order_id: 0,
youthFace: '',
adultFace: '',
child1Face: '',
child2Face: '',
parent1Face: '',
parent2Face: '',
}
},
onLoad(args) {
this.id = args.id
this.order_id = args.order_id
this.handleGetGroupData()
},
methods: {
/*获取开通会员信息*/
handleGetGroupData() {
let self = this;
self._post(
'ground.group/getGroupData',
{group_id: self.id},
result => {
if (result.data && result.data.face_url) {
self.youthFace = result.data.face_url;
self.adultFace = result.data.face_url;
}
if (result.data && result.data.face_url) {
self.child1Face = result.data.face_url;
}
if (result.data && result.data.face_url1) {
self.child2Face = result.data.face_url1;
}
if (result.data && result.data.parent.length > 0) {
self.parent1Face = result.data.parent[0].face_url;
if (result.data.parent.length > 1) {
self.parent2Face = result.data.parent[1].face_url;
}
}
},
false,
() => {
}
);
},
/*去拍照*/
handleTakePhoto(type) {
if (type === 'youth' && this.youthFace) {
uni.previewImage({
urls: [this.youthFace]
});
return false;
}
if (type === 'adult' && this.adultFace) {
uni.previewImage({
urls: [this.adultFace]
});
return false;
}
if (type === 'child1' && this.child1Face) {
uni.previewImage({
urls: [this.child1Face]
});
return false;
}
if (type === 'child2' && this.child2Face) {
uni.previewImage({
urls: [this.child2Face]
});
return false;
}
if (type === 'parent1' && this.parent1Face) {
uni.previewImage({
urls: [this.parent1Face]
});
return false;
}
if (type === 'parent2' && this.parent2Face) {
uni.previewImage({
urls: [this.parent2Face]
});
return false;
}
let self = this
uni.navigateTo({
url: `/bundle/combo/face-photo?type=${type}`,
events:{
data: (e) => {
self.uploadFile(e.path, e.type)
}
}
});
},
/*上传图片*/
uploadFile: function(filePath, type) {
console.log("🚀 ~ filePath:", filePath)
let self = this;
let params = {
token: uni.getStorageSync('token'),
app_id: self.getAppId()
};
uni.showLoading({
title: '图片上传中'
});
uni.uploadFile({
url: self.websiteUrl + '/index.php?s=/api/file.upload/image',
filePath: filePath,
name: 'iFile',
formData: params,
success: function(res) {
uni.hideLoading();
let result = typeof res.data === 'object' ? res.data : JSON.parse(res.data);
if (result.code === 1) {
setTimeout(() => {
uni.showLoading({
title: '人脸录入中...'
});
}, 100);
self._post(
'ground.group/hikCreate',
{
app_id: self.getAppId(),
face_url: result.data.file_path,
order_id: self.order_id,
group_id: self.id,
},
function(res) {
console.log("🚀 ~ res:", res)
uni.hideLoading();
setTimeout(() => {
self.handleGetGroupData()
uni.showToast({
title: '操作成功',
duration: 1500,
icon: 'success'
});
}, 100);
}
);
} else {
}
},
complete: function() {
uni.hideLoading();
}
});
},
}
}
</script>

View File

@ -0,0 +1,36 @@
<template>
<!-- <@devicePosition: 摄像头位置 前置或后置摄像头值为front, back
@quality: 成像质量值为high高质量normal普通质量low低质量 -->
<view>
<hao-camera
:devicePosition="back"
:quality="low"
@confirmPhoto="confirmPhoto"
></hao-camera>
</view>
</template>
<script>
import haoCamera from '@/uni_modules/hao-camera/components/hao-camera/hao-camera.vue';
export default {
components: {
haoCamera
},
data() {
return {
type: '',
}
},
onLoad(args) {
this.type = args.type || '';
},
methods: {
confirmPhoto(filePath){
console.log("🚀 ~ filePath:", filePath)
let self = this
uni.navigateBack()
this.getOpenerEventChannel().emit('data',{path: filePath, type: self.type});
}
}
}
</script>

792
bundle/combo/info.vue Normal file
View File

@ -0,0 +1,792 @@
<template>
<view class="page-bg">
<navbar title="完善信息" bg="#F6F7F8"></navbar>
<view class="container" style="padding-top: 20px;">
<!-- 青年卡-基本信息 -->
<view class="form-card" v-if="id == 1">
<view class="section-title">
基本信息 <text class="required">*</text>
</view>
<view class="form-item">
<view class="label">姓名</view>
<input class="input" type="text" placeholder="请填写姓名" placeholder-class="placeholder-style"
v-model="formData.youth.name" />
</view>
<view class="form-item">
<view class="label">出生年月</view>
<picker mode="date" :end="endDate" @change="onYouthDateChange">
<view class="picker-view" :class="{ 'has-value': formData.youth.both }">
<text>{{ formData.youth.both || '请选择出生年月' }}</text>
<image src="https://xh.stnav.com/uploads/sport/icon_down.png"
style="width: 36rpx; height: 36rpx;" mode="aspectFit"></image>
</view>
</picker>
</view>
<view class="form-item no-border">
<view class="label">身份证号</view>
<input class="input" type="idcard" placeholder="请输入身份证号码" placeholder-class="placeholder-style"
v-model="formData.youth.card" />
</view>
</view>
<!-- 成人卡-基本信息 -->
<view class="form-card" v-if="id == 2">
<view class="section-title">
基本信息 <text class="required">*</text>
</view>
<view class="form-item">
<view class="label">姓名</view>
<input class="input" type="text" placeholder="请填写姓名" placeholder-class="placeholder-style"
v-model="formData.adult.name" />
</view>
<view class="form-item">
<view class="label">出生年月</view>
<picker mode="date" :end="endDate" @change="onAdultDateChange">
<view class="picker-view" :class="{ 'has-value': formData.adult.both }">
<text>{{ formData.adult.both || '请选择出生年月' }}</text>
<image src="https://xh.stnav.com/uploads/sport/icon_down.png"
style="width: 36rpx; height: 36rpx;" mode="aspectFit"></image>
</view>
</picker>
</view>
<view class="form-item no-border">
<view class="label">身份证号</view>
<input class="input" type="idcard" placeholder="请输入身份证号码" placeholder-class="placeholder-style"
v-model="formData.adult.card" />
</view>
</view>
<!-- 家长1基本信息 -->
<view class="form-card" v-if="id == 3 || id == 4">
<view class="section-title">
家长1基本信息 <text class="required">*</text>
</view>
<view class="form-item">
<view class="label">姓名</view>
<input class="input" type="text" placeholder="请填写姓名" placeholder-class="placeholder-style"
v-model="formData.parents[0].name" />
</view>
<view class="form-item">
<view class="label">出生年月</view>
<picker mode="date" :end="endDate" @change="(e) => onParentDateChange(e, 0)">
<view class="picker-view" :class="{ 'has-value': formData.parents[0].both }">
<text>{{ formData.parents[0].both || '请选择出生年月' }}</text>
<image src="https://xh.stnav.com/uploads/sport/icon_down.png"
style="width: 36rpx; height: 36rpx;" mode="aspectFit"></image>
</view>
</picker>
</view>
<view class="form-item no-border">
<view class="label">身份证号</view>
<input class="input" type="idcard" placeholder="请输入身份证号码" placeholder-class="placeholder-style"
v-model="formData.parents[0].card" />
</view>
</view>
<!-- 家长基本信息2 -->
<view class="form-card" v-if="id == 3 || id == 4">
<view class="section-title">
家长2基本信息 <text class="required">*</text>
</view>
<view class="form-item">
<view class="label">姓名</view>
<input class="input" type="text" placeholder="请填写姓名" placeholder-class="placeholder-style"
v-model="formData.parents[1].name" />
</view>
<view class="form-item">
<view class="label">出生年月</view>
<picker mode="date" :end="endDate" @change="(e) => onParentDateChange(e, 1)">
<view class="picker-view" :class="{ 'has-value': formData.parents[1].both }">
<text>{{ formData.parents[1].both || '请选择出生年月' }}</text>
<image src="https://xh.stnav.com/uploads/sport/icon_down.png"
style="width: 36rpx; height: 36rpx;" mode="aspectFit"></image>
</view>
</picker>
</view>
<view class="form-item no-border">
<view class="label">身份证号</view>
<input class="input" type="idcard" placeholder="请输入身份证号码" placeholder-class="placeholder-style"
v-model="formData.parents[1].card" />
</view>
</view>
<!-- 随行子女1信息 -->
<view class="form-card" v-if="id == 3 || id == 4">
<view class="section-title">
随行子女1信息 <text class="required">*</text>
</view>
<view class="form-item">
<view class="label">姓名</view>
<input class="input" type="text" placeholder="请填写姓名" placeholder-class="placeholder-style"
v-model="formData.child[0].name" />
</view>
<view class="form-item">
<view class="label">出生年月</view>
<picker mode="date" :end="endDate" @change="(e) => onChildDateChange(e, 0)">
<view class="picker-view" :class="{ 'has-value': formData.child[0].both }">
<text>{{ formData.child[0].both || '请选择出生年月' }}</text>
<image src="https://xh.stnav.com/uploads/sport/icon_down.png"
style="width: 36rpx; height: 36rpx;" mode="aspectFit"></image>
</view>
</picker>
</view>
<view class="form-item no-border">
<view class="label">身份证号</view>
<input class="input" type="idcard" placeholder="请输入身份证号码" placeholder-class="placeholder-style"
v-model="formData.child[0].card" />
</view>
</view>
<!-- 随行子女2信息 -->
<view class="form-card" v-if="id == 4">
<view class="section-title">
随行子女2信息 <text class="required">*</text>
</view>
<view class="form-item">
<view class="label">姓名</view>
<input class="input" type="text" placeholder="请填写姓名" placeholder-class="placeholder-style"
v-model="formData.child[1].name" />
</view>
<view class="form-item">
<view class="label">出生年月</view>
<picker mode="date" :end="endDate" @change="(e) => onChildDateChange(e, 1)">
<view class="picker-view" :class="{ 'has-value': formData.child[1].both }">
<text>{{ formData.child[1].both || '请选择出生年月' }}</text>
<image src="https://xh.stnav.com/uploads/sport/icon_down.png"
style="width: 36rpx; height: 36rpx;" mode="aspectFit"></image>
</view>
</picker>
</view>
<view class="form-item no-border">
<view class="label">身份证号</view>
<input class="input" type="idcard" placeholder="请输入身份证号码" placeholder-class="placeholder-style"
v-model="formData.child[1].card" />
</view>
</view>
<!-- 联系方式 -->
<view class="form-card">
<view class="section-title">
联系方式 <text class="required">*</text>
</view>
<view class="form-item-row no-border">
<view class="label">联系电话</view>
<input class="input-grey" type="number" placeholder="请填写联系方式"
placeholder-class="placeholder-style-small" v-model="formData.mobile" />
</view>
</view>
<!-- 提示信息 -->
<view class="tips">
*提交表单申请工作人员将在3个工作日内进行审核如需及时了解请直接电话咨询我们将在第一时间解答
</view>
<!-- 底部按钮 -->
<view class="footer-bar">
<view class="btn btn-default" @click="contactUs">联系我们</view>
<view class="btn btn-primary" @click="submitForm">提交申请</view>
</view>
<!-- 提交成功弹窗 -->
<view class="modal-container" v-if="showSuccessPopup">
<view class="modal-mask" @click="confirmSuccess"></view>
<view class="modal-content">
<!-- 根据设计图比例此处设为280rpx猜测28rpx属于笔误 -->
<image class="modal-icon" src="https://xh.stnav.com/uploads/sport/add-success.png"
style="width: 280rpx; height: 280rpx;"></image>
<view class="modal-title">信息提交成功</view>
<view class="modal-desc">请您耐心等候我们将尽快为您审核</view>
<view class="modal-btn" @click="confirmSuccess">好的</view>
</view>
</view>
</view>
</view>
</template>
<script>
import navbar from '@/components/navbar.vue';
export default {
components: {
navbar,
},
computed: {
endDate() {
const date = new Date();
date.setDate(date.getDate() - 1);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
},
data() {
return {
showSuccessPopup: false,
comboType: 'adult', // 套餐类型adult(成人卡) youth(青年卡) family(亲子卡)
formData: {
youth: {
name: '',
both: '',
card: '',
},
adult: {
name: '',
both: '',
card: '',
},
parents: [
{ id: 0, name: '', both: '', card: '' },
{ id: 0, name: '', both: '', card: '' }
],
child: [
{ id: 0, name: '', both: '', card: '' },
{ id: 0, name: '', both: '', card: '' }
],
phone: '',
group_id: 0
},
id: 0,
isSubmitting: false,
setting: {
company: {}
},
info: {}, // 用户信息数据
}
},
onLoad(args) {
this.comboType = args.type || 'adult'
this.id = args.id
this.formData.group_id = this.id
this.handleInit()
this.handleGetSetting()
},
methods: {
handleInit() {
let self = this;
self._post(
'ground.group/getGroupData',
{
group_id: self.id
},
result => {
if (result.code && result.data) {
const data = result.data;
self.info = data;
self.formData.mobile = data.mobile || '';
if (data.group_id == 1 ) {
// 青年卡
self.formData.youth = {
name: data.name,
both: data.both,
card: data.card,
}
}
if (data.group_id == 2) {
// 成人卡
self.formData.adult = {
name: data.name,
both: data.both,
card: data.card,
}
}
if (data.group_id == 3 || data.group_id == 4) {
// 亲子卡
if (data.parent && data.parent.length > 0) {
self.$set(self.formData.parents, 0, {
id: data.parent[0].id,
name: data.parent[0].name,
both: data.parent[0].both,
card: data.parent[0].card,
});
}
if (data.parent && data.parent.length > 1) {
self.$set(self.formData.parents, 1, {
id: data.parent[1].id,
name: data.parent[1].name,
both: data.parent[1].both,
card: data.parent[1].card,
});
}
if (data.child && data.child.length > 0) {
self.$set(self.formData.child, 0, {
id: data.child[0].id,
name: data.child[0].name,
both: data.child[0].both,
card: data.child[0].card,
});
} else {
self.$set(self.formData.child, 0, {
id: 0,
name: data.name || '',
both: data.both || '',
card: data.card || '',
});
}
if (data.child && data.child.length > 1) {
self.$set(self.formData.child, 1, {
id: data.child[1].id,
name: data.child[1].name,
both: data.child[1].both,
card: data.child[1].card,
});
}
}
}
},
false,
() => {
}
);
},
handleGetSetting() {
let self = this;
self._post(
'ground.ground/groundSetting',
{
app_id: self.getAppId()
},
function(res) {
if (res.code) {
self.setting = res.data;
}
}
)
},
onYouthDateChange(e) {
this.formData.youth.both = e.detail.value;
},
onAdultDateChange(e) {
this.formData.adult.both = e.detail.value;
},
onParentDateChange(e, index) {
this.formData.parents[index].both = e.detail.value;
},
onChildDateChange(e, index) {
this.formData.child[index].both = e.detail.value;
},
contactUs() {
uni.makePhoneCall({
phoneNumber: this.setting.lists.company.contact
});
},
submitForm() {
let self = this;
const regex = /^[1-9]\d{5}(18|19|20)?\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
const validateCardAndAgeMatch = (card, both, prefix, ageRule) => {
let idBirthStr = card.length === 15 ? '19' + card.substring(6, 12) : card.substring(6, 14);
let idDateStr = `${idBirthStr.substring(0, 4)}-${idBirthStr.substring(4, 6)}-${idBirthStr.substring(6, 8)}`;
if (idDateStr !== both) {
return `${prefix}出生日期选错了与身份证不符`;
}
if (ageRule) {
const today = new Date();
let age = today.getFullYear() - parseInt(idBirthStr.substring(0, 4));
const m = (today.getMonth() + 1) - parseInt(idBirthStr.substring(4, 6));
if (m < 0 || (m === 0 && today.getDate() < parseInt(idBirthStr.substring(6, 8)))) {
age--;
}
if (ageRule === 'adult' && age < 18) {
return `${prefix}必须满18周岁`;
}
if (ageRule === 'child' && age >= 18) {
return `${prefix}须未满18周岁`;
}
}
return null;
};
// id == 1 验证 youth 属性
if (self.id == 1) {
let youth = self.formData.youth;
if (!youth || !youth.name || !youth.both || !youth.card) {
return uni.showToast({ title: '请填写完整基本信息', icon: 'none' });
}
if (!regex.test(youth.card)) {
return uni.showToast({ title: '请输入正确的身份证号码', icon: 'none' });
}
let err = validateCardAndAgeMatch(youth.card, youth.both, '', 'child');
if (err) return uni.showToast({ title: err, icon: 'none' });
}
// 成人卡
if (self.id == 2) {
// 购买成人卡时,需要验证 adult 属性
let adult = self.formData.adult;
if (!adult || !adult.name || !adult.both || !adult.card) {
return uni.showToast({ title: '请填写完整基本信息', icon: 'none' });
}
if (!regex.test(adult.card)) {
return uni.showToast({ title: '请输入正确的身份证号码', icon: 'none' });
}
let err = validateCardAndAgeMatch(adult.card, adult.both, '', 'adult');
if (err) return uni.showToast({ title: err, icon: 'none' });
}
// id == 3(第一个亲子卡) 或 4 时,验证 parents[0] 和 child 属性
if (self.id == 3 || self.id == 4) {
let p0 = self.formData.parents[0];
if (!p0 || !p0.name || !p0.both || !p0.card) {
return uni.showToast({ title: '请填写完整家长1基本信息', icon: 'none' });
}
if (!regex.test(p0.card)) {
return uni.showToast({ title: '请输入正确的家长1身份证号码', icon: 'none' });
}
let err0 = validateCardAndAgeMatch(p0.card, p0.both, '家长1', 'adult');
if (err0) return uni.showToast({ title: err0, icon: 'none' });
let p1 = self.formData.parents[1];
if (!p1 || !p1.name || !p1.both || !p1.card) {
return uni.showToast({ title: '请填写完整家长2基本信息', icon: 'none' });
}
if (!regex.test(p1.card)) {
return uni.showToast({ title: '请输入正确的家长2身份证号码', icon: 'none' });
}
let err1 = validateCardAndAgeMatch(p1.card, p1.both, '家长2', 'adult');
if (err1) return uni.showToast({ title: err1, icon: 'none' });
let child0 = self.formData.child[0];
if (!child0 || !child0.name || !child0.both || !child0.card) {
return uni.showToast({ title: '请填写完整随行子女1信息', icon: 'none' });
}
if (!regex.test(child0.card)) {
return uni.showToast({ title: '请输入正确的子女1身份证号码', icon: 'none' });
}
let errC0 = validateCardAndAgeMatch(child0.card, child0.both, '子女1', 'child');
if (errC0) return uni.showToast({ title: errC0, icon: 'none' });
// id == 4 时(第二个亲子卡),还需要额外验证 child[1] 属性
if (self.id == 4) {
let child1 = self.formData.child[1];
if (!child1 || !child1.name || !child1.both || !child1.card) {
return uni.showToast({ title: '请填写完整随行子女2信息', icon: 'none' });
}
if (!regex.test(child1.card)) {
return uni.showToast({ title: '请输入正确的子女2身份证号码', icon: 'none' });
}
let errC1 = validateCardAndAgeMatch(child1.card, child1.both, '子女2', 'child');
if (errC1) return uni.showToast({ title: errC1, icon: 'none' });
}
}
// 所有场景必填联系电话
if (!self.formData.mobile) {
return uni.showToast({ title: '请填写联系电话', icon: 'none' });
}
const phoneReg = /^1[3-9]\d{9}$/;
if (!phoneReg.test(self.formData.mobile)) {
return uni.showToast({ title: '请输入正确的手机号码', icon: 'none' });
}
if (self.isSubmitting) return;
self.isSubmitting = true;
uni.showLoading({ title: '提交中...', mask: true });
let submitData = {
...self.formData,
youth: JSON.stringify(self.formData.youth),
adult: JSON.stringify(self.formData.adult),
parents: JSON.stringify(self.formData.parents),
child: JSON.stringify(self.formData.child)
};
self._post(
'ground.group/submitGroupData',
submitData,
result => {
uni.hideLoading();
if (result.code) {
self.formData = {
youth: { name: '', both: '', card: '' },
adult: { name: '', both: '', card: '' },
parents: [
{ name: '', both: '', card: '' },
{ name: '', both: '', card: '' }
],
child: [
{ name: '', both: '', card: '' },
{ name: '', both: '', card: '' }
],
phone: '',
group_id: self.id
};
self.showSuccessPopup = true;
} else {
uni.showToast({ title: '提交失败', icon: 'none' });
}
},
false,
() => {
uni.hideLoading();
self.isSubmitting = false;
}
)
},
confirmSuccess() {
this.showSuccessPopup = false;
// 点击好的之后,可以跳转或返回上一页
uni.navigateBack();
this.getOpenerEventChannel().emit('data', {notice: 'success'});
}
}
}
</script>
<style lang="scss">
page {
background-color: #F6F7F8;
}
.page-bg {
background-color: #F6F7F8;
min-height: 100vh;
}
.container {
padding: 24rpx 30rpx 200rpx;
}
.form-card {
background-color: #FFFFFF;
border-radius: 12rpx;
padding: 40rpx 30rpx;
margin-bottom: 24rpx;
}
.section-title {
font-size: 32rpx;
color: #333333;
font-weight: 500;
margin-bottom: 30rpx;
display: flex;
align-items: center;
.required {
color: #E53935;
margin-left: 8rpx;
font-weight: normal;
}
}
.form-item {
margin-bottom: 10rpx;
border-bottom: 2rpx solid #F5F5F5;
padding-bottom: 16rpx;
&.no-border {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.label {
font-size: 28rpx;
color: #666666;
margin-bottom: 20rpx;
margin-top: 30rpx;
}
.input {
font-size: 30rpx;
color: #333333;
width: 100%;
height: 60rpx;
}
.picker-view {
font-size: 30rpx;
color: #CCCCCC;
height: 60rpx;
display: flex;
align-items: center;
justify-content: space-between;
&.has-value {
color: #333333;
}
.arrow-down {
font-size: 30rpx;
color: #CCCCCC;
margin-left: 10rpx;
transform: scaleY(0.6);
}
}
}
.form-item-row {
display: flex;
align-items: center;
margin-top: 30rpx;
.label {
font-size: 30rpx;
color: #333333;
width: 160rpx;
}
.input-grey {
flex: 1;
background-color: #F6F7F8;
height: 80rpx;
border-radius: 8rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #333333;
}
}
.placeholder-style {
color: #CCCCCC;
font-size: 30rpx;
}
.placeholder-style-small {
color: #CCCCCC;
font-size: 28rpx;
}
.tips {
font-size: 26rpx;
color: #666666;
line-height: 1.6;
padding: 20rpx 10rpx;
}
.footer-bar {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
z-index: 2;
background-color: #F6F7F8;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
display: flex;
justify-content: space-between;
.btn {
flex: 1;
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
border-radius: 8rpx;
}
.btn-default {
background-color: #FFFFFF;
color: #333333;
margin-right: 20rpx;
}
.btn-primary {
background-color: #3B5B9B;
color: #FFFFFF;
}
}
.modal-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100; // 遮罩层要在最上面
display: flex;
align-items: flex-end;
justify-content: center;
}
.modal-mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4); // 半透明黑色背景
}
.modal-content {
position: relative;
width: 100%;
box-sizing: border-box;
background-color: #FFFFFF;
border-radius: 48rpx 48rpx 0 0;
padding: 70rpx 50rpx;
padding-bottom: calc(70rpx + env(safe-area-inset-bottom));
display: flex;
flex-direction: column;
align-items: center;
z-index: 101; // 内容在遮罩层上方
.modal-icon {
margin-bottom: 40rpx;
}
.modal-title {
font-size: 36rpx;
color: #333333;
font-weight: 500;
margin-bottom: 20rpx;
}
.modal-desc {
font-size: 26rpx;
color: #999999;
margin-bottom: 174rpx;
text-align: center;
}
.modal-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
text-align: center;
background-color: #3B5B9B;
color: #FFFFFF;
font-size: 32rpx;
border-radius: 8rpx;
}
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<view>
<face-bio-assay :isDev="false" :action="['StraightenHead']" ref="faceDetect" @detectFailed="photoChange" @photoChange="photoChange">
</face-bio-assay>
</view>
</template>
<script>
import faceBioAssay from '@/uni_modules/face-bio-assay/components/face-bio-assay/face-bio-assay.vue'
export default {
components: {
faceBioAssay,
},
data() {
return {
order_id: 0,
}
},
onLoad(args) {
this.order_id = args.order_id || 0;
this.$refs.faceDetect.initData()
},
methods: {
detectFailed() {
uni.showToast({
title: "人脸核验失败~",
icon: 'none'
})
uni.navigateBack()
},
photoChange(path) {
let self = this
uni.navigateBack()
this.getOpenerEventChannel().emit('data',{path: path, order_id: self.order_id});
}
}
}
</script>
<style>
</style>

View File

@ -267,7 +267,7 @@ export default {
title: '加载中'
});
// 1. 协议文件地址(可替换为实际后端返回的 word 文件 url
const url = 'https://xh.stnav.com/czxy.doc';
const url = 'https://xh.stnav.com/czxy20260205.doc';
// 2. 下载 word 文件
uni.downloadFile({
url,

211
bundle/recharge/record.vue Normal file
View File

@ -0,0 +1,211 @@
<template>
<view class="" style="padding-bottom: 20rpx;">
<navbar title="充值记录"></navbar>
<view v-if="listData.length>0" class="pbenv">
<view class="address-list">
<view class="address bg-white d-b-c" v-for="(item,index) in listData" :key="index">
<view class="">
<view class=" flex-1 mb10">
<view class="user f32 address-info">
<text>充值金额{{ item.order_amount }}</text>
</view>
<view class="pt20 f26 gray3">
订单编号{{ item.order_sn }}
</view>
<view class="pt20 f26 gray3">
订单创建时间{{ item.create_time }}
</view>
</view>
</view>
<view class="d-f a-i-c" @click="toInvoice(item.id)" v-if="item.fp_status == 0">
<image class="add_icon_img" src="/static/icon/edit.png" mode="aspectFill" style="width: 24rpx; height: 24rpx;"></image>
<view class="" style="margin-left: 10rpx;">
开票
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import navbar from '@/components/navbar.vue';
export default {
components: {
navbar,
},
data() {
return {
/*是否加载完成*/
loadding: true,
indicatorDots: true,
autoplay: true,
interval: 2000,
duration: 500,
/*数据*/
listData: [],
/*默认地址id*/
default_id: '0',
options: {}
}
},
onLoad: function(options) {
this.options = options;
},
onShow: function() {
uni.showLoading({
title: '加载中'
});
/*获取地址列表*/
this.getData();
},
methods: {
/*获取数据*/
getData() {
let self = this;
let dataType = self.dataType;
self._get('order.groundOrder/rechangeList', {}, function(res) {
console.log("🚀 ~ res:", res)
self.listData = res.data.lists;
self.loadding = false;
uni.hideLoading();
});
},
// 去开票
toInvoice(order_id) {
console.log("🚀 ~ methods.toInvoice:")
uni.navigateTo({
url: `/pages/order/invoice?order_id=${order_id}&type=2`
});
},
}
}
</script>
<style lang="scss">
page {
background-color: $xh-bg;
}
.address-list {
margin-top: 20rpx;
border-top: 16rpx solid #F2F2F2;
padding: 0 30rpx;
padding-bottom: 90rpx;
}
.foot-btns {
padding: 0;
}
.foot-btns .btn-red {
width: 100%;
height: 90rpx;
line-height: 90rpx;
border-radius: 0;
}
.none_add {
display: flex;
justify-content: center;
align-items: center;
margin-top: 318rpx;
}
.no_add {
width: 292rpx;
height: 202rpx;
}
.no_add_add {
width: 630rpx;
margin: 0 60rpx;
height: 90rpx;
border-radius: 8rpx;
text-align: center;
line-height: 90rpx;
font-size: 32rpx;
font-family: PingFang SC;
font-weight: 500;
background: #365A9A !important;
color: #FFFFFF;
position: fixed;
bottom: 40rpx;
left: 0;
right: 0;
}
.add_add {
height: 64rpx;
line-height: 64rpx;
font-size: 26rpx;
font-family: PingFang SC;
font-weight: 500;
color: #0777CD;
padding: 0 35rpx;
border-bottom: 1rpx solid #D9D9D9;
}
.defaul_add {
padding: 9rpx 14rpx 10rpx 15rpx;
@include background_color('bg-op');
font-size: 22rpx;
font-family: PingFang SC;
font-weight: 500;
color: #F6220C;
@include font_color('font_color');
}
.add_icon_img {
width: 30rpx;
height: 30rpx;
}
.none_line {
width: 1rpx;
height: 44rpx;
background: #D9D9D9;
}
.add_add-btn{
position: fixed;
bottom: 40rpx;
width:690rpx;
margin: 20rpx 30rpx;
box-sizing: border-box;
font-size: 28rpx;
height: 90rpx;
border-radius: 8rpx;
display: flex;
justify-content: center;
align-items: center;
background-color: #365A9A !important;
color: #fff;
}
.pbenv{
padding-bottom: calc(env(safe-area-inset-bottom) + 120rpx);
box-sizing: border-box;
}
.address-info {
font-size: 30rpx;
color: #121212;
line-height: 42rpx;
}
.address {
margin-bottom: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
.info {
padding: 30rpx;
}
}
</style>

View File

@ -190,6 +190,37 @@
</view>
</Popup>
<!-- 储值卡选择弹窗 -->
<Popup :show="storedCardPopup" :width='750' :padding="0" type="bottom" backgroundColor="#fff" radius="32rpx 32rpx 0 0">
<view class="ww100 box-s-b pop-improt typeof pr">
<image style="width: 64rpx;height: 64rpx;position: absolute; top: 26rpx;right: 30rpx;" src="@/static/icon/close2.png" mode="" @click="closeStoredCardPopup"></image>
<view class="d-c-c pt44">
<text class="f34 fb">储值卡选择</text>
</view>
<view class="bg-white card">
<view class="card-item" v-for="item in storedCardList" :key="item.id" :class="currentStoredCardId == item.id ? 'active' : ''" @click="currentStoredCardId = item.id">
<view class="d-f a-i-c">
<view class="card-title">{{ item.name }}</view>
<view class="d-f a-i-c">
<view class="discount">享</view>
<view class="sale">
<text>{{ item.discount }}</text>
<text>折</text>
</view>
</view>
</view>
<view class="d-f a-i-c">
<view class="card-balance">¥{{ formatMoney(item.balance) }}</view>
<view class="icon-box d-c-c card-checkout"><span class="icon iconfont icon-xuanze"></span></view>
</view>
</view>
<view class="card-btn" @click="confirmStoredCard">确定</view>
</view>
</view>
</Popup>
<navbar title="确认订单"></navbar>
<!-- 预约信息 -->
@ -296,19 +327,33 @@
</view>
<view class="icon-box d-c-c"><span class="icon iconfont icon-xuanze"></span></view>
</view>
<view v-if="typeId == 1" :class="payType == 'balance' ? 'item active' : 'item'" @tap="payTypeFunc('balance')">
<view v-if="typeId == 1" :class="payType == 'balance' ? 'item active' : 'item'" @tap="payTypeFunc('balance')" style="padding-bottom: 10rpx;">
<view class="d-s-c">
<view class="icon-box d-c-c mr10"><span class="icon iconfont icon-yue"></span></view>
<text class="key">平台余额</text>
</view>
<view class="d-f a-i-c">
<view class="mr10 dis" v-if="userAccount > 0">
<view class="mr10 dis" v-if="payType == 'balance' && userAccount > 0">
<!-- <text class="key">余额支付(剩余{{balance}})</text> -->
{{ cardType() }} <text style="color: #FF5951;">{{ userDiscount }}</text>
</view>
<view class="icon-box d-c-c"><span class="icon iconfont icon-xuanze"></span></view>
</view>
</view>
<view v-if="typeId == 1" :class="payType == 'storedCard' ? 'item active' : 'item'" @tap="payTypeFunc('storedCard')">
<view class="d-s-c">
<view class="icon-box d-c-c mr10">
<image src="https://xh.stnav.com/uploads/sport/chuzhika.png" mode="heightFix" style="width: 50rpx; height: 50rpx;"></image>
</view>
<text class="key">储值卡支付</text>
</view>
<view class="d-f a-i-c">
<view class="mr10 dis" v-if="payType == 'storedCard' && userAccount > 0">
{{ storedCardName() }} <text style="color: #FF5951;margin-left: 10rpx;">{{ userDiscount }}</text>
</view>
<view class="icon-box d-c-c"><span class="icon iconfont icon-xuanze"></span></view>
</view>
</view>
</view>
</view>
@ -377,11 +422,15 @@
loadding: true,
_submitting: false,
balancePopup: false,
storedCardPopup: false,
balance: {},
userBalance: {},
currentType: '', // 选择的会员卡类型
storedCardList: [],
currentStoredCardId: '',
userAccount: 0,
userDiscount: 0
userDiscount: 0,
storedValueCard: []
};
},
@ -402,7 +451,7 @@
this.typeId = args.typeId || 1; // 网球场1 篮球场2
// this.basketballDate = args.date || null; // 篮球场预约时间
this.getData();
this.getRecharge()
this.getRecharge();
},
onUnload() {
@ -604,17 +653,17 @@
payTypeFunc(n) {
this.payType = n;
if (n == 'balance') {
this.resetPayDiscount();
this.balancePopup = true;
} else {
// 切换到微信支付时还原价格
this.userAccount = 0;
this.userDiscount = 0;
this.currentType = '';
if (typeof this.originalTotal === 'number' && !isNaN(this.originalTotal)) {
this.bill.total = this.originalTotal;
this.bill.dis = 0;
}
this.storedCardPopup = false;
} else if (n == 'storedCard') {
this.resetPayDiscount();
this.balancePopup = false;
this.storedCardPopup = true;
} else {
this.resetPayDiscount();
this.balancePopup = false;
this.storedCardPopup = false;
}
},
@ -656,6 +705,19 @@
};
oldBalancePay.call(this);
setTimeout(finish, 3000);
} else if (this.payType == 'storedCard') {
if (this.currentStoredCardId === '') {
uni.showToast({title: '请选择储值卡', icon: 'none'});
setTimeout(finish, 3000);
return;
}
const oldStoredCardPay = this.storedCardPay;
this.storedCardPay = (...args) => {
oldStoredCardPay.apply(this, args);
this.storedCardPay = oldStoredCardPay;
};
oldStoredCardPay.call(this);
setTimeout(finish, 3000);
} else {
finish();
}
@ -814,6 +876,7 @@
},
function(res) {
self.balance = res.data.lists.balance;
self.storedValueCard = res.data.lists.storedValueCard;
}
)
@ -823,11 +886,43 @@
}, function(res) {
console.log("🚀 ~ res:", res)
self.userBalance = res.data.userInfo;
self.storedCardList = [
{ id: 1, payType: 1, name: '储值卡一', discount: self.storedValueCard.discount1, balance: self.userBalance.card_balance1 },
{ id: 2, payType: 2, name: '储值卡二', discount: self.storedValueCard.discount2, balance: self.userBalance.card_balance2 },
{ id: 3, payType: 3, name: '储值卡三', discount: self.storedValueCard.discount3, balance: self.userBalance.card_balance3 },
];
self.loadding = false;
uni.hideLoading();
});
},
formatMoney(value) {
const amount = Number(value) || 0;
return amount.toFixed(2);
},
getStoredCardInfo() {
return this.storedCardList.find(item => item.id === this.currentStoredCardId);
},
storedCardName() {
const currentCard = this.getStoredCardInfo();
return currentCard ? currentCard.name : '';
},
resetPayDiscount() {
this.userAccount = 0;
this.userDiscount = 0;
this.currentType = '';
this.currentStoredCardId = '';
if (typeof this.originalTotal === 'number' && !isNaN(this.originalTotal)) {
this.bill.total = this.originalTotal;
this.bill.dis = 0;
}
},
cardType() {
if (this.currentType == 1) {
return '白银会员卡'
@ -878,12 +973,144 @@
this.balancePopup = false;
},
confirmStoredCard() {
if (this.currentStoredCardId === '') {
uni.showToast({
title: '请选择储值卡',
icon: 'none'
});
return;
}
const currentCard = this.getStoredCardInfo();
if (!currentCard) {
uni.showToast({
title: '储值卡不存在',
icon: 'none'
});
return;
}
this.userAccount = Number(currentCard.balance);
this.userDiscount = Number(currentCard.discount) || 10;
const baseTotal = Number(this.bill.cdf.total) || 0;
const finalPrice = Number((baseTotal * (this.userDiscount / 10)).toFixed(2));
const payableTotal = Number((finalPrice + Number(this.bill.dgf.total)).toFixed(2));
if (this.userAccount < payableTotal) {
uni.showToast({
title: '储值卡余额不足,请选择其他储值卡',
icon: 'none'
});
return;
}
this.bill.dis = Number((baseTotal - finalPrice).toFixed(2));
this.bill.total = payableTotal;
this.storedCardPopup = false;
},
storedCardPay() {
let self = this
const currentCard = self.getStoredCardInfo();
if (!currentCard) {
uni.showToast({
title: '请选择储值卡',
icon: 'none'
});
return;
}
if (Number(currentCard.balance) < Number(self.bill.total)) {
uni.showToast({
title: '储值卡余额不足',
icon: 'none'
});
return;
}
uni.showLoading({
title: '支付中'
});
try {
self._post(
'ground.ground/yuexnPay',
{
app_id: self.getAppId(),
order_id: self.orderId,
pay_type: currentCard.payType // 传储值卡对应的pay_type
},
function(res) {
if (res.code == 1) {
self.result = 'success'
uni.showToast({
title: '支付成功',
icon: 'none'
});
self.loadding = false;
setTimeout(() => {
uni.navigateBack({delta: 1})
}, 500);
} else {
self.result = 'fail'
self.loadding = false;
uni.showToast({
title: '支付失败',
icon: 'none'
});
setTimeout(() => {
uni.navigateBack({delta: 1})
}, 500);
}
}
)
} catch (error) {
self.result = 'fail'
self.loadding = false;
uni.showToast({
title: '支付失败',
icon: 'none'
});
setTimeout(() => {
uni.navigateBack({delta: 1})
}, 500);
}
// setTimeout(() => {
// currentCard.balance = Number((Number(currentCard.balance) - Number(this.bill.total)).toFixed(2));
// this.userAccount = currentCard.balance;
// this.result = 'success';
// this.loadding = false;
// uni.hideLoading();
// uni.showToast({
// title: '储值卡支付成功',
// icon: 'none'
// });
// setTimeout(() => {
// uni.navigateBack({delta: 1});
// }, 500);
// }, 300);
},
// 关闭余额支付弹窗
closeBalancePopup() {
this.resetPayDiscount();
this.payType = 'wxpay';
this.balancePopup = false;
},
closeStoredCardPopup() {
this.resetPayDiscount();
this.payType = 'wxpay';
this.storedCardPopup = false;
},
},
};

View File

@ -468,11 +468,42 @@ export default {
* @param time
* @param status
*/
handleSelectTime(title, time, status) {
handleSelectTime(title, time, status, room_id, price, light_price) {
let self = this
if (status == 1) {
return;
}
// 新增逻辑:限制只能选择一个场地的免费时间段
const isClickingFree = (Number(price) || 0) <= 0;
const isCurrentlySelected = this.selectedTime[title] && this.selectedTime[title].includes(time);
// 如果是准备选中一个免费时间段(不在已选列表中)
if (isClickingFree && !isCurrentlySelected) {
let hasOtherRoomFree = false;
Object.keys(this.selectedTime).forEach(roomTitle => {
if (roomTitle !== title && this.selectedTime[roomTitle].length > 0) {
const otherRoom = this.cdList.find(cd => cd.title === roomTitle);
if (otherRoom) {
this.selectedTime[roomTitle].forEach(t => {
const tObj = otherRoom.time && otherRoom.time.find(item => item.t === t);
if (tObj && (Number(tObj.price) || 0) <= 0) {
hasOtherRoomFree = true;
}
});
}
}
});
if (hasOtherRoomFree) {
uni.showToast({
title: '只能选择同一场地的免费时间段',
icon: 'none'
});
return;
}
}
// 多选逻辑selectedTime为对象按title区分
if (!this.selectedTime[title]) {
this.$set(this.selectedTime, title, []);
@ -653,9 +684,7 @@ export default {
// 立即预约-提交订单
toReserve() {
let self = this
// 一进来就锁定,彻底防止高频点击
if (self.typeId == 1) {
if (self.selectedReserveTime.length === 0) {
@ -671,10 +700,10 @@ export default {
});
try {
const start = self.selectedReserveTime[0].day_time + ' ' + self.selectedReserveTime[0].start_time;
const end = self.selectedReserveTime[self.selectedReserveTime.length -1].day_time + ' ' + self.selectedReserveTime[self.selectedReserveTime.length -1].end_time;
// 转换为时间戳
const startTimestamp = Math.floor(Date.parse(start.replace(/-/g, '/')) / 1000);
const endTimestamp = Math.floor(Date.parse(end.replace(/-/g, '/')) / 1000);
const endTimestamp = self.getMaxEndTime();
// let p = {
// app_id: self.getAppId(),
// ground_id: self.id,
@ -726,6 +755,11 @@ export default {
uni.navigateTo({
url: `/bundle/reserve/confirm?venueId=${self.venue.id}&roomId=${self.id}&typeId=${self.typeId}&orderId=${res.data.lists.id}`
});
} else {
uni.showToast({
title: res.msg || '订单提交失败,请重试',
icon: 'none'
});
}
}
)
@ -814,6 +848,25 @@ export default {
}
}
},
// 获取选中时间中的最大结束时间
getMaxEndTime() {
if (!this.selectedReserveTime || this.selectedReserveTime.length === 0) return '';
let maxTimestamp = -1;
let maxItem = null;
this.selectedReserveTime.forEach(item => {
// 支持endTime格式为"HH:mm"或"YYYY-MM-DD HH:mm"
let endStr = item.end_time || '';
let dayStr = item.day_time || '';
let fullStr = endStr.length > 5 ? endStr : (dayStr ? dayStr + ' ' + endStr : endStr);
let ts = Date.parse(fullStr.replace(/-/g, '/'));
if (ts >= maxTimestamp) {
maxTimestamp = ts;
maxItem = item;
}
});
return maxItem ? Math.floor(Date.parse((maxItem.day_time + ' ' + maxItem.end_time).replace(/-/g, '/')) / 1000) : '';
},
}
};
</script>

View File

@ -55,7 +55,7 @@
seeOrder() {
uni.navigateTo({
url: '/pages/order/cg-my-order'
url: '/pages/order/cg-my-order?type=' + this.ground_type
});
},

108
bundle/setting/light.vue Normal file
View File

@ -0,0 +1,108 @@
<template>
<view class="light-setting-container">
<view class="fields">
<view v-for="(field, idx) in fields" :key="field.id" class="field-item">
<view class="field-name">{{ field.name }}</view>
<view class="status" :class="{on: field.isOn, off: !field.isOn}">
{{ field.isOn ? '已开启' : '已关闭' }}
</view>
<button
class="toggle-btn"
:class="{on: field.isOn, off: !field.isOn}"
@click="toggleLight(idx)"
>
{{ field.isOn ? '关灯' : '开灯' }}
</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
fields: [
{ id: 1, name: '场地1', isOn: false },
{ id: 2, name: '场地2', isOn: false },
{ id: 3, name: '场地3', isOn: false },
{ id: 4, name: '场地4', isOn: false },
{ id: 5, name: '场地5', isOn: false },
{ id: 6, name: '场地6', isOn: false },
],
};
},
methods: {
toggleLight(idx) {
this.fields[idx].isOn = !this.fields[idx].isOn;
},
},
};
</script>
<style scoped>
.light-setting-container {
padding: 32rpx 24rpx;
background: #f7f9fc;
min-height: 100vh;
}
.title {
font-size: 40rpx;
font-weight: bold;
color: #365A9A;
margin-bottom: 40rpx;
text-align: center;
}
.fields {
display: flex;
flex-direction: column;
gap: 32rpx;
}
.field-item {
background: #fff;
border-radius: 16rpx;
box-shadow: 0 2rpx 8rpx rgba(54,90,154,0.08);
padding: 32rpx 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.field-name {
font-size: 32rpx;
color: #365A9A;
font-weight: 500;
}
.status {
font-size: 28rpx;
margin: 0 24rpx;
padding: 4rpx 20rpx;
border-radius: 24rpx;
background: #e3eaf6;
color: #365A9A;
transition: background 0.2s, color 0.2s;
}
.status.on {
background: #365A9A;
color: #fff;
}
.status.off {
background: #e3eaf6;
color: #365A9A;
}
.toggle-btn {
min-width: 180rpx;
font-size: 28rpx;
border: none;
border-radius: 24rpx;
padding: 8rpx 0;
color: #fff;
background: #365A9A;
transition: background 0.2s;
}
.toggle-btn.on {
background: #e74c3c;
}
.toggle-btn.off {
background: #365A9A;
}
</style>

View File

@ -989,6 +989,12 @@
"subPackages": [{
"root": "bundle",
"pages": [
{
"path": "setting/light",
"style": {
"navigationBarTitleText": "设置灯光"
}
},
{
"path": "reserve/details",
"style": {
@ -1025,6 +1031,12 @@
"navigationStyle": "custom"
}
},
{
"path": "recharge/record",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "face/face-info",
"style": {
@ -1036,6 +1048,42 @@
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "combo/combo-list",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "combo/details",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "combo/info",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "combo/face-photo",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "combo/face-list",
"style": {
"navigationBarTitleText": "人脸列表"
}
},
{
"path": "combo/desc",
"style": {
"navigationBarTitleText": "注意事项"
}
}
]
}],

View File

@ -17,11 +17,37 @@
<image style="width: 40rpx;height: 40rpx;" src="@/static/icon/notice.png" mode=""></image>
<view class="notice-txt">{{ setting.notice }}</view>
</view> -->
<view class="" style="display: flex; justify-content: center;" @click="toRecharge">
<!--
<view style="display: flex; justify-content: center; margin-bottom: 20rpx;" @click="toRecharge">
<image style="width: 690rpx;height: 140rpx;" src="https://xh.stnav.com/uploads/sport/recharge.png" mode=""></image>
</view>
<view style="display: flex; justify-content: center; margin-bottom: 26rpx;" @click="toCombo">
<image style="width: 690rpx;height: 200rpx;" src="https://xh.stnav.com/uploads/sport/to-combo2.png" mode=""></image>
</view> -->
<!-- <view style="display: flex; justify-content: center; margin-bottom: 40rpx;" @click="toCombo">
<image style="width: 690rpx;height: 230rpx;" src="https://xh.stnav.com/uploads/sport/to-combo1.png" mode=""></image>
</view> -->
<view class="card-container">
<view class="card left-card" @click="toRecharge" style="background-image: url('https://xh.stnav.com/uploads/sport/home_image2.png'); background-size: 100% 100%; background-repeat: no-repeat;">
<view class="card-text">
<view class="card-title" style="color: #4693F6;">网球充值卡</view>
<view class="card-subtitle left-subtitle" style="color: #4693F6;">充值立享优惠</view>
<view style="margin-top: 50rpx;"><text class="card-btn" style="background-color: #6A9CFD; color: #fff;">立即抢购</text></view>
</view>
</view>
<view class="card right-card" @click="toCombo" style="background-image: url('https://xh.stnav.com/uploads/sport/home_image1.png'); background-size: 100% 100%; background-repeat: no-repeat;">
<view class="card-text">
<view class="card-title" style="color: #D1834F;">篮球会员卡</view>
<view class="card-subtitle right-subtitle" style="color: #CD9C7B;">青年卡亲子卡成年卡...等你来领</view>
<view><text class="card-btn" style="background-color: #D19A62; color: #fff;">立即抢购</text></view>
</view>
</view>
</view>
<!-- 预约球馆 -->
<view class="info">
<view class="title">
@ -699,11 +725,74 @@ export default {
url: '/bundle/recharge/recharge'
});
},
// 跳转到充值界面
toCombo() {
uni.navigateTo({
url: '/bundle/combo/combo-list'
});
},
}
};
</script>
<style lang="scss">
.card-container {
display: flex;
justify-content: space-between;
padding: 0 30rpx;
margin-bottom: 30rpx;
}
.card {
width: 330rpx;
height: 200rpx;
border-radius: 16rpx;
position: relative;
padding: 24rpx;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-text {
position: relative;
z-index: 2;
}
.card-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.card-subtitle {
font-size: 22rpx;
margin-bottom: 24rpx;
line-height: 1.3;
}
.left-subtitle {
width: 160rpx;
}
.right-subtitle {
width: 250rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.card-btn {
font-size: 20rpx;
padding: 6rpx 24rpx;
border-radius: 30rpx;
}
page {
background-color: $xh-bg;
}

View File

@ -135,7 +135,7 @@
<button class="theme-btn del-btn" @click="onDelOrder(item.id)">删除订单</button>
</block>
<block v-if="item.order_status == 3 && item.fp_status == 0">
<block v-if="item.order_status == 3 && item.fp_status == 0 && item.pay_type == 0">
<button class="theme-btn pay-btn" @click="toInvoice(item.id)">去开票</button>
</block>
@ -606,7 +606,7 @@
toInvoice(order_id) {
console.log("🚀 ~ methods.toInvoice:")
uni.navigateTo({
url: `/pages/order/invoice?order_id=${order_id}`
url: `/pages/order/invoice?order_id=${order_id}&type=1`
});
},

View File

@ -138,19 +138,32 @@
</view>
<view class="icon-box d-c-c"><span class="icon iconfont icon-xuanze"></span></view>
</view>
<view :class="payType == 'balance' ? 'item active' : 'item'" @tap="payTypeFunc('balance')">
<view :class="payType == 'balance' ? 'item active' : 'item'" @tap="payTypeFunc('balance')" style="padding-bottom: 10rpx;">
<view class="d-s-c">
<view class="icon-box d-c-c mr10"><span class="icon iconfont icon-yue"></span></view>
<text class="key">平台余额</text>
</view>
<view class="d-f a-i-c">
<view class="mr10 dis" v-if="userAccount > 0">
<!-- <text class="key">余额支付(剩余{{balance}})</text> -->
<view class="mr10 dis" v-if="payType == 'balance' && userAccount > 0">
{{ cardType() }}
</view>
<view class="icon-box d-c-c"><span class="icon iconfont icon-xuanze"></span></view>
</view>
</view>
<view :class="payType == 'storedCard' ? 'item active' : 'item'" @tap="payTypeFunc('storedCard')">
<view class="d-s-c">
<view class="icon-box d-c-c mr10">
<image src="https://xh.stnav.com/uploads/sport/chuzhika.png" mode="heightFix" style="width: 50rpx; height: 50rpx;"></image>
</view>
<text class="key">储值卡支付</text>
</view>
<view class="d-f a-i-c">
<view class="mr10 dis" v-if="payType == 'storedCard' && userAccount > 0">
{{ storedCardName() }}
</view>
<view class="icon-box d-c-c"><span class="icon iconfont icon-xuanze"></span></view>
</view>
</view>
</view>
<view class="pay-light-btn" @click="getSelectedContent">确定并支付</view>
@ -200,12 +213,12 @@
<text class="cg-copy" @click="copy(detail.order_sn)">复制</text>
</view>
</view>
<view class="cg-order-info d-b-c mt14" v-if="detail.pay_way > 0">
<view class="">交易方式</view>
<view class="">
<text v-if="detail.pay_way == 1">余额支付-{{ cardType(detail.pay_way) }}</text>
<text v-if="detail.pay_way == 1">余额支付-{{ cardType(detail.pay_type) }}</text>
<text v-if="detail.pay_way == 2">微信支付</text>
<text v-if="detail.pay_way == 3">储值卡支付-{{ storedCardType(detail.pay_xntype) }}</text>
</view>
</view>
@ -396,6 +409,30 @@
</view>
</view>
</Popup>
<!-- 储值卡选择弹窗 -->
<Popup :show="storedCardPopup" :width='750' :padding="0" type="bottom" backgroundColor="#fff" radius="32rpx 32rpx 0 0">
<view class="ww100 box-s-b pop-improt typeof pr">
<image style="width: 64rpx;height: 64rpx;position: absolute; top: 26rpx;right: 30rpx;" src="@/static/icon/close2.png" mode="" @click="closeStoredCardPopup"></image>
<view class="d-c-c pt44">
<text class="f34 fb">储值卡选择</text>
</view>
<view class="bg-white card">
<view class="card-item" v-for="item in storedCardList" :key="item.id" :class="currentStoredCardId == item.id ? 'active' : ''" @click="currentStoredCardId = item.id">
<view class="d-f a-i-c">
<view class="card-title">{{ item.name }}</view>
</view>
<view class="d-f a-i-c">
<view class="card-balance">{{ formatMoney(item.balance) }}</view>
<view class="icon-box d-c-c card-checkout"><span class="icon iconfont icon-xuanze"></span></view>
</view>
</view>
<view class="card-btn" @click="confirmStoredCard">确定</view>
</view>
</view>
</Popup>
</view>
</template>
@ -448,6 +485,10 @@
currentType: '', // 选择的会员卡类型
userAccount: 0,
userDiscount: 0,
storedCardPopup: false,
storedCardList: [],
currentStoredCardId: '',
storedValueCard: [],
lightDateTime: '',
lightPrice: 0,
};
@ -670,19 +711,31 @@
// 会员卡类型
cardType(type) {
if (type == 1) {
const t = type || this.currentType;
if (t == 1) {
return '白银会员卡'
} else if (type == 2) {
} else if (t == 2) {
return '黄金会员卡'
} else if (type == 3) {
} else if (t == 3) {
return '铂金会员卡'
} else if (type == 4) {
} else if (t == 4) {
return '钻石会员卡'
} else if (type == 5) {
} else if (t == 5) {
return '至尊会员卡'
}
},
// 储值卡类型
storedCardType(type) {
if (type == 1) {
return '储值卡一'
} else if (type == 2) {
return '储值卡二'
} else if (type == 3) {
return '储值卡三'
}
},
/**
* 购买灯光前置条件
*/
@ -708,13 +761,25 @@
payTypeFunc(n) {
this.payType = n;
if (n == 'balance') {
this.userAccount = 0;
this.userDiscount = 0;
this.currentStoredCardId = '';
this.balancePopup = true;
this.storedCardPopup = false;
} else if (n == 'storedCard') {
this.userAccount = 0;
this.userDiscount = 0;
this.currentType = '';
this.balancePopup = false;
this.storedCardPopup = true;
} else {
// 切换到微信支付时还原价格
this.userAccount = 0;
this.userDiscount = 0;
this.currentType = '';
this.currentStoredCardId = '';
this.balancePopup = false;
this.storedCardPopup = false;
}
},
@ -724,6 +789,49 @@
this.balancePopup = false;
},
closeStoredCardPopup() {
this.payType = 'wxpay';
this.storedCardPopup = false;
},
formatMoney(value) {
const amount = Number(value) || 0;
return amount.toFixed(2);
},
getStoredCardInfo() {
return this.storedCardList.find(item => item.id === this.currentStoredCardId);
},
storedCardName() {
const currentCard = this.getStoredCardInfo();
return currentCard ? currentCard.name : '';
},
confirmStoredCard() {
if (this.currentStoredCardId === '') {
uni.showToast({
title: '请选择储值卡',
icon: 'none'
});
return;
}
const currentCard = this.getStoredCardInfo();
if (!currentCard) {
uni.showToast({
title: '储值卡不存在',
icon: 'none'
});
return;
}
this.userAccount = Number(currentCard.balance);
this.userDiscount = 0;
this.storedCardPopup = false;
},
getRecharge() {
let self = this;
uni.showLoading({
@ -737,6 +845,7 @@
},
function(res) {
self.balance = res.data.lists.balance;
self.storedValueCard = res.data.lists.storedValueCard;
}
)
@ -746,6 +855,13 @@
}, function(res) {
console.log("🚀 ~ res:", res)
self.userBalance = res.data.userInfo;
self.storedCardList = [
{ id: 1, payType: 1, name: '储值卡一', discount: self.storedValueCard.discount1, balance: self.userBalance.card_balance1 },
{ id: 2, payType: 2, name: '储值卡二', discount: self.storedValueCard.discount2, balance: self.userBalance.card_balance2 },
{ id: 3, payType: 3, name: '储值卡三', discount: self.storedValueCard.discount3, balance: self.userBalance.card_balance3 },
];
self.loadding = false;
uni.hideLoading();
});
@ -771,27 +887,13 @@
this.userAccount = this.userBalance['balance' + this.currentType];
this.userDiscount = this.balance['discount' + this.currentType];
this.userDiscount = 0;
// this.payType = this.currentType;
// this.countPrice();
this.balancePopup = false;
},
cardType() {
if (this.currentType == 1) {
return '白银会员卡'
} else if (this.currentType == 2) {
return '黄金会员卡'
} else if (this.currentType == 3) {
return '铂金会员卡'
} else if (this.currentType == 4) {
return '钻石会员卡'
} else if (this.currentType == 5) {
return '至尊会员卡'
}
},
isSelected(groupIdx, idx) {
return this.selectedTimes.some(sel => sel.group === groupIdx && sel.idx === idx);
},
@ -821,8 +923,17 @@
},
function(res) {
console.log("🚀 ~ res:", res)
self.detail.trade[groupIdx][idx].light_price = res.data.lists.set_light_price
self.selectedTimes.push({ group: groupIdx, idx, roomId });
const lightPrice = res.data.lists.set_light_price
self.detail.trade[groupIdx][idx].light_price = lightPrice
self.selectedTimes.push({
group: groupIdx,
idx,
roomId,
light_price: lightPrice,
start_time: self.detail.trade[groupIdx][idx].start_time,
end_time: self.detail.trade[groupIdx][idx].end_time,
day_time: self.detail.trade[groupIdx][idx].day_time
});
}
)
self.loadding = false
@ -844,13 +955,21 @@
self.lightPrice = 0
self.selectedTimes.forEach(sel => {
if (!roomMap[sel.roomId]) roomMap[sel.roomId] = [];
// 获取时间段
// 优先从 selectedTimes 中获取 light_price修复后
if (sel.light_price) {
roomMap[sel.roomId].push(`${sel.start_time}-${sel.end_time}`);
if (!self.lightDateTime && sel.day_time) {
self.lightDateTime = sel.day_time
}
self.lightPrice += parseFloat(sel.light_price)
} else {
// 兼容旧数据:如果 selectedTimes 中没有,从 detail.trade 中获取
const item = trade[sel.group] && trade[sel.group][sel.idx];
console.log("🚀 ~ item:", item)
if (item) {
roomMap[sel.roomId].push(`${item.start_time}-${item.end_time}`);
self.lightDateTime = item.day_time
self.lightPrice += parseFloat(item.light_price)
self.lightPrice += parseFloat(item.light_price || 0)
}
}
});
@ -915,9 +1034,18 @@
return;
}
if (self.payType == 'storedCard' && self.currentStoredCardId === '') {
uni.showToast({
title: '请选择储值卡',
icon: 'none'
});
return;
}
uni.showLoading({
title: '正在处理'
});
console.log('self.payType=', self.payType)
console.log(123123)
self._post(
'order.GroundOrder/addLightStoreOrder', {
@ -1017,6 +1145,54 @@
self.getRecharge();
}, 1500);
} else {
self.openLightPopup = false;
console.log("🚀 ~ pay error res:", res)
self.result = 'fail'
uni.hideLoading();
setTimeout(() => {
uni.showToast({
title: '支付失败',
icon: 'none'
});
}, 200);
setTimeout(() => {
self.getData();
self.getRecharge();
}, 1500);
}
}
)
} else if (self.payType == 'storedCard') {
const currentCard = self.getStoredCardInfo();
console.log("🚀 ~ getStoredCardInfo:", 12312312321)
self._post(
'ground.ground/yuexnLightPay', {
order_id: payId,
pay_type: currentCard.payType
},
function(pay) {
if (pay.code == 1) {
self.openLightPopup = false;
self.selectedTimes = []
self.content = []
self.result = 'success'
uni.hideLoading();
setTimeout(() => {
uni.showToast({
title: '支付成功',
icon: 'none'
});
}, 200);
setTimeout(() => {
self.getData();
self.getRecharge();
}, 1500);
} else {
self.openLightPopup = false;

View File

@ -23,6 +23,7 @@
data() {
return {
order_id: 0,
type: 1, // 1是订单发票 2是充值发票
form: {
gmfnsrsbh: '',
gmfmc: '',
@ -32,7 +33,7 @@
},
onLoad(args) {
this.order_id = args.order_id;
console.log('order_id', this.order_id);
this.type = args.type || 1;
},
methods: {
submit() {
@ -68,6 +69,7 @@
'invoice.invoice/getInvoice',
{
order_id: self.order_id,
type: self.type,
emails: self.form.emials,
gmfmc: self.form.gmfmc,
gmfnsrsbh: self.form.gmfnsrsbh

View File

@ -50,10 +50,17 @@
</view>
</view>
</view> -->
<view style="margin: 0 auto 24rpx; display: flex; justify-content: center;" @click="jumpPage('/bundle/combo/combo-list')">
<view class="pr">
<image src="https://xh.stnav.com/uploads/sport/lqtc.png" style="width: 690rpx; height: 140rpx;"></image>
<view class="kt-btn">立即了解</view>
</view>
</view>
<!-- 我的场馆订单 -->
<view class="my-cg-order my-assets">
<view class="my-assets-all">
<view class="f30 fb">场馆订单</view>
<view class="f30 fb">我的场馆订单</view>
<view class="gray9 f26" @click="jumpPage('/pages/order/cg-my-order?dataType=all')">全部订单<text
class="icon iconfont icon-jiantou"></text></view>
</view>
@ -719,4 +726,19 @@
background: #E5E5E5;
margin-top: 32rpx;
}
.kt-btn {
position: absolute;
right: 32rpx;
bottom: 22rpx;
width: 148rpx;
height: 46rpx;
line-height: 46rpx;
background: linear-gradient( 0deg, #FCF5D8 0%, #FFFFFF 100%);
box-shadow: 0rpx 4rpx 8rpx 2rpx #DCB56D;
border-radius: 23rpx 23rpx 23rpx 23rpx;
font-size: 24rpx;
color: #402201;
text-align: center;
}
</style>

BIN
static/icon/back3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,6 @@
## 1.0.22025-12-22
代码优化
## 1.0.12025-12-22
封面图上传
## 1.0.02025-12-22
组件代码上传

View File

@ -0,0 +1,165 @@
<template>
<view class="content"
style="position: fixed;top: 0;left: 0;z-index: 777;width: 100%;height: 100vh;background-color: #FFFFFF;">
<camera @error="handleCameraError" :device-position="localDevicePosition" flash="off" v-if="!cameraImage"
style="width: 100%; height: 100vh;">
<cover-image src="@/uni_modules/hao-camera/static/person.png"
style="width: 100vw; height: 770rpx; margin:10vh 0vw 0 0vw;"></cover-image>
<view
style="top: 20rpx;left: 40rpx;width: 380rpx;position: fixed;height: 202rpx; border-radius: 20rpx;border: 1px solid rgba(51, 51, 51,0.6);background-color: rgba(51, 51, 51,0.6);">
</view>
<view
style="top: 20rpx;left: 40rpx;width: 380rpx;position: fixed;height: 202rpx; border-radius: 20rpx;font-size: 26rpx;color: white;display: flex;flex-direction: column;box-sizing: border-box;padding:25rpx;">
<text>1. 保持光线充足</text>
<text style="margin-top: 20rpx;">2. 人物轮廓清晰无阴影</text>
<text style="margin-top: 20rpx;">3. 姿势端正眼睛直视镜头</text>
</view>
<!-- 准备拍照 -->
<view v-if="!cameraImage" class="btns"
style="width: 100%;height: 16vh;background-color: rgba(51, 51, 51, 0.5); padding-bottom: 25rpx;position: fixed;bottom: 0;">
<!-- <image class="item" @tap="chooseImage" src="@/uni_modules/hao-camera/static/xiangce.png"></image> -->
<image class="item_center" @tap="takePhotoByHead" src="@/uni_modules/hao-camera/static/cameraImg.png">
</image>
<image class="item" @tap="reverseCamera" src="@/uni_modules/hao-camera/static/fanzhuan.png"></image>
</view>
</camera>
<!-- 确认拍照照片 -->
<image v-if="cameraImage" :src="cameraImage" style="width: 100%; height: 100vh;" mode="aspectFit"></image>
<!-- 拍照完成 -->
<view v-if="cameraImage" class="btns"
style="width: 100%;height: 16vh;background-color: rgba(51, 51, 51, 0.5); padding-bottom: 25rpx;position: fixed;bottom: 0;">
<image class="img_btn" @tap="cameraImage = ''" src="@/uni_modules/hao-camera/static/back.png"></image>
<image class="img_btn"></image>
<image class="img_btn" @tap="confirmPhoto" src="@/uni_modules/hao-camera/static/confirm.png"></image>
</view>
<view class="error-handler" v-if="!authCamera">
<button class="nobtn" openType="openSetting">获取相机权限失败</button>
</view>
</view>
</template>
<script>
export default {
props: {
quality: {
type: String,
default: 'high'
},
devicePosition: {
type: String,
default: 'back'
}
},
data() {
return {
ctxHeader: null,
cameraImage: '',
authCamera: true,
localDevicePosition: this.devicePosition
}
},
watch: {
devicePosition(newVal) {
this.localDevicePosition = newVal;
}
},
beforeCreate() {
// #ifdef MP-WEIXIN
this.checkCameraAuth();
// #endif
},
onShow() {
// #ifdef MP-WEIXIN
this.checkCameraAuth();
// #endif
},
methods: {
checkCameraAuth() {
uni.getSetting({
success: (res) => {
if (res.authSetting["scope.camera"]) {
this.authCamera = true;
} else {
this.authCamera = false;
uni.showToast({
title: '请确认是否允许获取您的相机权限!',
icon: 'none'
});
}
}
});
},
// ...existing code...
//拍摄头像
takePhotoByHead() {
this.ctxHeader = uni.createCameraContext();
this.ctxHeader.takePhoto({
// quality: this.quality,
quality: 'low',
success: (res) => {
this.cameraImage = res.tempImagePath; //图片
},
fail: (err) => {
uni.showToast({
title: '拍照失败',
icon: 'none'
})
}
});
},
handleCameraError() {
uni.showToast({
title: '用户拒绝使用摄像头',
icon: 'none'
})
},
reverseCamera() {
this.localDevicePosition = (("back" === this.localDevicePosition) ? "front" : "back")
console.log("🚀 ~ localDevicePosition:", this.localDevicePosition)
},
confirmPhoto() {
this.$emit('confirmPhoto', this.cameraImage)
}
}
}
</script>
<style lang="scss">
.content {
display: flex;
flex-direction: column;
justify-content: center;
background: #fff;
box-sizing: border-box;
height: 100%;
width: 100vw;
.btns {
display: flex;
justify-content: center;
align-items: center;
.img_btn {
width: 80rpx;
height: 80rpx;
}
.item_center {
width: 130rpx;
height: 130rpx;
}
.item {
width: 90rpx;
height: 90rpx;
position: absolute;
right: 40rpx;
}
}
}
</style>

View File

@ -0,0 +1,99 @@
{
"id": "hao-camera",
"displayName": "小程序证件照、人脸拍照相机",
"version": "1.0.2",
"description": "小程序相机拍照,证件照人脸头像框辅助拍照",
"keywords": [
"人脸拍照",
"相机翻转",
"证件照"
],
"engines": {
"HBuilderX": "^3.1.0",
"uni-app": "^3.6.15",
"uni-app-x": ""
},
"cover": "http://rk-pos.oss-cn-beijing.aliyuncs.com/appupdate/ruipay/lyhStatic/cameraCover.png",
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": "",
"darkmode": "x",
"i18n": "x",
"widescreen": "x"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "√",
"aliyun": "√",
"alipay": "√"
},
"client": {
"uni-app": {
"vue": {
"vue2": {
"extVersion": "1.0.0",
"minVersion": ""
},
"vue3": {
"extVersion": "1.0.0",
"minVersion": ""
}
},
"web": {
"safari": "-",
"chrome": "-"
},
"app": {
"vue": "-",
"nvue": "-",
"android": "-",
"ios": "-",
"harmony": "-"
},
"mp": {
"weixin": {
"extVersion": "1.0.0",
"minVersion": ""
},
"alipay": "-",
"toutiao": "-",
"baidu": "-",
"kuaishou": "-",
"jd": "-",
"harmony": "-",
"qq": "-",
"lark": "-"
},
"quickapp": {
"huawei": "-",
"union": "-"
}
}
}
}
},
"engines": {
"HBuilderX": "^3.1.0",
"uni-app": "^3.6.15",
"uni-app-x": ""
}
}

View File

@ -0,0 +1,32 @@
# hao-camera 证件照相机拍照
**示例使用方法**
```
<template>
<!-- <@devicePosition: 摄像头位置 前置或后置摄像头值为front, back
@quality: 成像质量值为high高质量、normal普通质量、low低质量 -->
<view>
<hao-camera
:devicePosition="back"
:quality="high"
@confirmPhoto="confirmPhoto"
></hao-camera>
</view>
</template>
<script>
import haoCamera from '@/uni_modules/hao-camera/components/hao-camera/hao-camera.vue';
export default {
components: {
haoCamera
},
methods: {
confirmPhoto(filePath){
console.log('图片: ' + filePath);
}
}
}
</script>
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB