完善套餐购买、人脸拍照功能

This commit is contained in:
wangxiaowei
2026-04-11 18:33:23 +08:00
parent 2a95c0e176
commit be1ce34a74
6 changed files with 390 additions and 27 deletions

View File

@ -81,7 +81,8 @@
<!-- Bottom Button --> <!-- Bottom Button -->
<view class="bottom-bar"> <view class="bottom-bar">
<view class="btn-submit" @click="handleSubmit">立即开通</view> <view class="btn-submit" @click="hanldeTakePhoto" v-if="info.order.end_time && id == info.order.group_id">录入人脸</view>
<view class="btn-submit" @click="handleSubmit" v-else>立即开通</view>
</view> </view>
<!-- 完善信息提示弹窗 --> <!-- 完善信息提示弹窗 -->
@ -125,9 +126,8 @@
</view> </view>
<view class="buy-modal-tips"> <view class="buy-modal-tips">
提示文字在此处显示提示文字在此处显示提示文字在此处显示提示文字在此处显示提示文字在此处显示 开通成功之后需要录入人脸信息
</view> </view>
<view class="buy-modal-btn" @click="confirmBuy">立即开通</view> <view class="buy-modal-btn" @click="confirmBuy">立即开通</view>
</view> </view>
</view> </view>
@ -162,6 +162,7 @@ export default {
selectedPlan: 1, // 选择的套餐 1-月卡 2-季卡 selectedPlan: 1, // 选择的套餐 1-月卡 2-季卡
info: { info: {
order: { order: {
id: 0,
group_id: 0, // 套餐ID group_id: 0, // 套餐ID
end_time: '', // 会员到期时间 end_time: '', // 会员到期时间
}, },
@ -204,20 +205,22 @@ export default {
let self = this; let self = this;
// 判断之前是否开通过任意一张会员卡,如果开通过且没有过期,提示"您已购买过套餐卡,无需重复购买" // 判断之前是否开通过任意一张会员卡,如果开通过且没有过期,提示"您已购买过套餐卡,无需重复购买"
if (self.info.order.end_time) { if (self.info.order?.end_time) {
uni.showToast({ title: '您已购买过套餐卡,无需重复购买', icon: 'none' }); uni.showToast({ title: '您已购买过套餐卡,无需重复购买', icon: 'none' });
return false; return false;
} }
//TODO 如果信息审核没有通过uni.showToast提示"信息审核没通过,请耐心等待" //TODO 如果信息审核没有通过uni.showToast提示"信息审核没通过,请耐心等待"
// 成人卡不需要提交资料 // 成人卡不需要提交资料
if (self.id == 2) { // if (self.id == 2) {
self.showBuyModal = true; // self.showBuyModal = true;
} else { // } else {
// 其他卡需要先判断是否提交过资料,如果没有提交过资料,弹出提示完善信息的弹窗;如果提交过资料,根据审核状态提示不同的消息或者弹窗
self._post( self._post(
'ground.group/getGroupData', 'ground.group/getGroupData',
null, null,
result => { result => {
console.log("🚀 ~ result.data:", result.data)
if (!result.data) { if (!result.data) {
// 没有填写过信息,弹出完善信息提示弹窗 // 没有填写过信息,弹出完善信息提示弹窗
self.showInfoModal = true; self.showInfoModal = true;
@ -225,23 +228,32 @@ export default {
} }
if (result.data.status == 0) { if (result.data.status == 0) {
uni.showToast({ title: '信息审核中,请耐心等待', icon: 'none' }); setTimeout(() => {
uni.showToast({ title: '信息审核中,请耐心等待', icon: 'none' });
}, 100);
return false;
} }
if (result.data.status == 2) { if (result.data.status == 2) {
uni.showToast({ title: '审核失败,请重新提交', icon: 'none' }); setTimeout(() => {
uni.showToast({ title: '审核失败,请重新提交', icon: 'none' });
}, 100);
// 没有填写过信息,弹出完善信息提示弹窗
self.showInfoModal = true;
return false;
} }
if (result.data.status == 1) { if (result.data.status == 1) {
// 已经审核通过,弹出开通会员弹窗 // 已经审核通过,弹出开通会员弹窗
self.showBuyModal = true; self.showBuyModal = true;
return false;
} }
}, },
false, false,
() => { () => {
} }
); );
} // }
}, },
closeInfoModal() { closeInfoModal() {
this.showInfoModal = false; this.showInfoModal = false;
@ -291,6 +303,7 @@ export default {
success: res => { success: res => {
uni.hideLoading(); uni.hideLoading();
setTimeout(() => { setTimeout(() => {
self.handleGetDetails();
self.showSuccessModal = true; self.showSuccessModal = true;
}, 1000); }, 1000);
}, },
@ -317,6 +330,15 @@ export default {
}, },
closeSuccessModal() { closeSuccessModal() {
this.showSuccessModal = false; this.showSuccessModal = false;
uni.navigateTo({
url: '/bundle/combo/face-list?id=' + this.id + '&order_id=' + this.info.order.id
});
},
hanldeTakePhoto() {
uni.navigateTo({
url: '/bundle/combo/face-list?id=' + this.id + '&order_id=' + this.info.order.id
});
} }
} }
} }
@ -390,8 +412,6 @@ page {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
} }
} }

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

@ -0,0 +1,227 @@
<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>
<!-- 子女 -->
<view v-if="id == 3 || id == 4"
@click="handleTakePhoto('child')"
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;">{{ childFace ? '已录入' : '去录入' }}</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 == 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: '',
childFace: '',
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',
null,
result => {
if (result.data && result.data.face_url) {
self.youthFace = result.data.face_url;
self.adultFace = result.data.face_url;
self.childFace = result.data.face_url;
}
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 === 'child' && this.childFace) {
uni.previewImage({
urls: [this.childFace]
});
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,
},
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>

View File

@ -3,7 +3,7 @@
<navbar title="完善信息" bg="#F6F7F8"></navbar> <navbar title="完善信息" bg="#F6F7F8"></navbar>
<view class="container" style="padding-top: 20px;"> <view class="container" style="padding-top: 20px;">
<!-- 基本信息 --> <!-- 青年卡-基本信息 -->
<view class="form-card" v-if="id == 1"> <view class="form-card" v-if="id == 1">
<view class="section-title"> <view class="section-title">
基本信息 <text class="required">*</text> 基本信息 <text class="required">*</text>
@ -33,6 +33,37 @@
</view> </view>
</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基本信息 --> <!-- 家长1基本信息 -->
<view class="form-card" v-if="id == 3 || id == 4"> <view class="form-card" v-if="id == 3 || id == 4">
<view class="section-title"> <view class="section-title">
@ -185,15 +216,20 @@ export default {
showSuccessPopup: false, showSuccessPopup: false,
comboType: 'adult', // 套餐类型adult(成人卡) youth(青年卡) family(亲子卡) comboType: 'adult', // 套餐类型adult(成人卡) youth(青年卡) family(亲子卡)
formData: { formData: {
parents: [
{ name: '', both: '', card: '' },
{ name: '', both: '', card: '' }
],
youth: { youth: {
name: '', name: '',
both: '', both: '',
card: '', card: '',
}, },
adult: {
name: '',
both: '',
card: '',
},
parents: [
{ name: '', both: '', card: '' },
{ name: '', both: '', card: '' }
],
child: { child: {
name: '', name: '',
both: '', both: '',
@ -216,6 +252,10 @@ export default {
this.formData.youth.both = e.detail.value; this.formData.youth.both = e.detail.value;
}, },
onAdultDateChange(e) {
this.formData.adult.both = e.detail.value;
},
onParentDateChange(e, index) { onParentDateChange(e, index) {
this.formData.parents[index].both = e.detail.value; this.formData.parents[index].both = e.detail.value;
}, },
@ -230,6 +270,7 @@ export default {
submitForm() { submitForm() {
let self = this; 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]$/;
// id == 1 验证 youth 属性 // id == 1 验证 youth 属性
if (self.id == 1) { if (self.id == 1) {
@ -237,6 +278,21 @@ export default {
if (!youth || !youth.name || !youth.both || !youth.card) { if (!youth || !youth.name || !youth.both || !youth.card) {
return uni.showToast({ title: '请填写完整基本信息', icon: 'none' }); return uni.showToast({ title: '请填写完整基本信息', icon: 'none' });
} }
if (!regex.test(youth.card)) {
return uni.showToast({ title: '请输入正确的身份证号码', 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' });
}
} }
// id == 3(第一个亲子卡) 或 4 时,验证 parents[0] 和 child 属性 // id == 3(第一个亲子卡) 或 4 时,验证 parents[0] 和 child 属性
@ -245,18 +301,27 @@ export default {
if (!p0 || !p0.name || !p0.both || !p0.card) { if (!p0 || !p0.name || !p0.both || !p0.card) {
return uni.showToast({ title: '请填写完整家长1基本信息', icon: 'none' }); return uni.showToast({ title: '请填写完整家长1基本信息', icon: 'none' });
} }
if (!regex.test(p0.card)) {
return uni.showToast({ title: '请输入正确的家长1身份证号码', icon: 'none' });
}
// id == 4 时(第二个亲子卡),还需要额外验证 parents[1] 属性
if (self.id == 4) {
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 child = self.formData.child; let child = self.formData.child;
if (!child || !child.name || !child.both || !child.card) { if (!child || !child.name || !child.both || !child.card) {
return uni.showToast({ title: '请填写完整随行子女信息', icon: 'none' }); return uni.showToast({ title: '请填写完整随行子女信息', icon: 'none' });
} }
} if (!regex.test(child.card)) {
return uni.showToast({ title: '请输入正确的子女身份证号码', icon: 'none' });
// id == 4 时(第二个亲子卡),还需要额外验证 parents[1] 属性
if (self.id == 4) {
let p1 = self.formData.parents[1];
if (!p1 || !p1.name || !p1.both || !p1.card) {
return uni.showToast({ title: '请填写完整家长2基本信息', icon: 'none' });
} }
} }
@ -276,8 +341,9 @@ export default {
let submitData = { let submitData = {
...self.formData, ...self.formData,
parents: JSON.stringify(self.formData.parents),
youth: JSON.stringify(self.formData.youth), youth: JSON.stringify(self.formData.youth),
adult: JSON.stringify(self.formData.adult),
parents: JSON.stringify(self.formData.parents),
child: JSON.stringify(self.formData.child) child: JSON.stringify(self.formData.child)
}; };
@ -288,11 +354,12 @@ export default {
uni.hideLoading(); uni.hideLoading();
if (result.code) { if (result.code) {
self.formData = { self.formData = {
youth: { name: '', both: '', card: '' },
adult: { name: '', both: '', card: '' },
parents: [ parents: [
{ name: '', both: '', card: '' }, { name: '', both: '', card: '' },
{ name: '', both: '', card: '' } { name: '', both: '', card: '' }
], ],
youth: { name: '', both: '', card: '' },
child: { name: '', both: '', card: '' }, child: { name: '', both: '', card: '' },
phone: '', phone: '',
group_id: self.id group_id: self.id

View File

@ -1066,6 +1066,18 @@
"style": { "style": {
"navigationStyle": "custom" "navigationStyle": "custom"
} }
},
{
"path": "combo/face-photo",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "combo/face-list",
"style": {
"navigationBarTitleText": "人脸列表"
}
} }
] ]
}], }],

View File

@ -157,8 +157,9 @@ export default {
.item { .item {
width: 90rpx; width: 90rpx;
height: 90rpx; height: 90rpx;
position: absolute;
right: 40rpx;
} }
} }
} }
</style> </style>