You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

800 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="page">
<view class="oinfo" v-if="info">
<!-- 信息 -->
<view class="yycon">
<view class="oscon">
<view class="osrcon">
<view class="ostop">
<view class="osname">门店:{{info.storeName?info.storeName:''}}</view>
<view class="qrimg" v-if="info.qrCode" @click="openQR(info.qrCode)">
<image class="qrimg" :src="'data:image/png;base64,'+info.qrCode" mode="aspectFill"></image>
</view>
</view>
<view class="oscell">
上课课程:
<text class="txt">{{info.courseName }}</text>
</view>
<view v-if="info.claName" class="oscell">
上课班级:
<text class="txt">{{info.claName }}</text>
</view>
<view class="oscell">
预约状态:
<view v-if="info.bookStatus==1" class="ztip">教练确认</view>
<view v-else-if="info.bookStatus==0" class="jtip">预约中</view>
<view v-else-if="info.bookStatus==2" class="htip">待上课</view>
<view v-else-if="info.bookStatus==4" class="wtip">已完成</view>
<view v-else-if="info.bookStatus==3" class="ctip">已取消</view>
</view>
<view class="oscell">
授课教练:
<text class="txt">{{info.teacherName }}</text>
</view>
<view class="oscell">
上课教室:
<text class="txt">{{info.roomName }}</text>
</view>
<view class="oscell">
上课时间:
<text class="txt">{{ (info.claDate?info.claDate:'')+' '+ (info.startTime?info.startTime:'') + (info.endTime?'-'+info.endTime:'') }}</text>
</view>
<view class="oscell" v-if="info.claTimeStatus">
课程状态:
<text class="txt">{{info.claTimeStatus=='1'?'待上课':(info.claTimeStatus=='2'?'已上课':'') }}</text>
</view>
<view class="oscell">
创建日期:
<text class="txt">{{info.createTime }}</text>
</view>
<view class="oscellqr">
<view class="ordtip">预约二维码(扫码签到)</view>
<view class="ordqr">
<image class="imgqr" :src="'data:image/png;base64,'+info.qrCode" mode="aspectFill"></image>
</view>
<view class="ordno">
<view class="txt"> 预约号 {{ info.code }}</view>
<view class="copy" @click="copydo(info.code)">.复制</view> </view>
</view>
</view>
</view>
</view>
<!-- 进度信息 -->
<view class="yycon">
<uni-steps v-if="ifshow" :options="steps" direction="column" :active="cur"></uni-steps>
</view>
</view>
<!-- 二维码 -->
<uni-popup ref="pfDialog" :mask-click="false">
<view class="pcon">
<view class="phtxt">预约二维码</view>
<view class="ptxt">
<image class="qrimg" :src="qr" mode="aspectFill"></image>
</view>
<view class="btn" @click="closeDialog">
</view>
</view>
</uni-popup>
<!-- 是否登录 -->
<openlogin ref="loginId" @getPhoneNumber="getPhoneNumber"></openlogin>
<view v-if="ifscan" class="bottom"></view>
<view v-if="ifscan" class="submitcon">
<button type="primary" class="bbtn" @tap="goSign()"></button>
</view>
</view>
</template>
<script>
import { myCache } from '../../utils/utils.js';
import openlogin from "../components/openlogin.vue";
export default {
components: {
openlogin
},
data() {
return {
openId:"",
phone:"",
userid:"",
id:"",
qr:'',
info: {
"claName": "",
"storeName": "",
"pic": null,
"claDate": "",
"weekDay": null,
"startTime": "",
"endTime": "",
"roomName": null,
"claColor": null,
"claTimeStatus": null,
"bookStatus": null,
"createTime": "",
"code": null,
"courseName": null,
"teacherId": null,
"teacherName": "",
"checkIn": 1,
"statusTime": [
{
"time": "2025-09-02 17:26:18",
"status": 0
},
{
"time": "2025-09-02 17:26:18",
"status": 1
},
{
"time": "2025-09-02 17:26:18",
"status": 2
},
{
"time": "2025-09-02 17:26:18",
"status": 3
}
]
},
cur:0,
steps:
[
// {title:'已付款',desc:'2025-02-05 13:30'},
// {title:'已预约',desc:'2025-02-05 13:30'},
// {title:'教练已确认',desc:''},
// {title:'店长确认,准备上课',desc:''},
// {title:'课程结束',desc:''},
],
ifshow:false,
ifscan:false,
};
},
onLoad(options) {
if(options.type&&options.type=='qd')
{
this.ifscan=true;
this.$forceUpdate();
}
if(options.id)
{
this.id=options.id;
this.getinfo();
}
},
onShow(){
this.openId = myCache('openId');
var user = myCache('user');
this.userid = user.userid? user.userid:'';
this.phone = user.userphone;
if(this.userid==""||this.userid=="0"){
uni.navigateTo({
url: `/pages/login/login`
});
}
},
methods: {
copydo(text){
if (!text) {
uni.showToast({
title: '复制内容为空!',
icon: 'none'
})
return;
}
uni.setClipboardData({
data: text,
success: () => {
uni.showToast({
title: '复制成功',
icon: 'success'
})
}
})
},
openQR(qr){
console.log("openQR")
this.qr='data:image/png;base64,'+qr;
this.$forceUpdate();
this.openDialog();
},
closeDialog(){
this.$refs.pfDialog.close();
},
openDialog(){
this.$refs.pfDialog.open();
},
getPhoneNumber(e){
if(e.phone){
this.phone = e.phone
}
if(e.userid){
this.userid = e.userid
}
},
iflogin(){
this.openId = myCache('openId');
var user = myCache('user');
this.userid = user.userid? user.userid:'';
this.phone = user.userphone;
if(this.userid==""||this.userid=="0"||this.phone==""){
uni.navigateTo({
url: `/pages/login/login`
});
return false;
}
else{
return true;
}
},
goback(){
uni.navigateBack({
delta: 1
});
},
async getinfo() {
uni.showLoading({
title: '数据加载中...'
});
const {data: res} = await uni.$http.post('/api/course/bookCourseDetail', {"bookId":this.id});//"2037434363846811650"
if(res&&res.data){
// 预约信息
this.info=res.data;
this.steps=[
// {title:'已预约',desc:''},
// {title:'教练已确认',desc:''},
// {title:'店长已确认',desc:''},
// {title:'预约已取消',desc:''},
// {title:'课程已结束',desc:''},
];
// 描述预约进度0->预约中1->教练确认2->店长确认/预约成功/待上课 3->已取消;4- >已完成/待评价;
// {title:'已付款',desc:'2025-02-05 13:30'},
// {title:'已预约',desc:'2025-02-05 13:30'},
// {title:'教练已确认',desc:'2025-02-05 13:30'},
// {title:'店长确认,准备上课',desc:''},
// {title:'课程结束',desc:''},
var statusTime=res.data.statusTime?res.data.statusTime:[];
if(statusTime&&statusTime.length>0){
statusTime.forEach(cell=>{
var ii={
title: cell.status==0?'已预约':(cell.status==1?'教练已确认':(cell.status==2?'店长已确认':(cell.status==3?'预约已取消':cell.status==4?'课程已结束':''))),
desc: cell.time
}
this.steps.push(ii);
});
var lastStatus=statusTime[statusTime.length-1].status;
if(lastStatus==0){
this.steps.push({
title:'教练待确认',desc:''
});
this.steps.push({
title:'店长确认,准备上课',desc:''
});
this.steps.push({
title:'课程结束',desc:''
});
}
else if(lastStatus==1){
this.steps.push({
title:'店长确认,准备上课',desc:''
});
this.steps.push({
title:'课程结束',desc:''
});
}
if(lastStatus==2){
this.steps.push({
title:'课程结束',desc:''
});
}
}
else{
this.steps.push({
title:'预约中',desc:''
});
this.steps.push({
title:'教练待确认',desc:''
});
this.steps.push({
title:'店长确认,准备上课',desc:''
});
this.steps.push({
title:'课程结束',desc:''
});
}
this.$forceUpdate();
this.cur=-1;
this.steps.forEach(cell=>{
if(cell.desc){
this.cur++;
this.$forceUpdate();
}
});
this.ifshow=true;
this.$forceUpdate();
}
else{
uni.showModal({
title: '提示',
content: res.message? res.message:'预约详情获取失败!请重试!',
cancelText: '取消',
confirmText: '确定',
success: ress => {
if (ress.confirm) {
// 返回
uni.navigateBack({
delta: 1
});
}
else{
// 返回
uni.navigateBack({
delta: 1
});
}
}
});
}
},
async goSign(){
uni.showLoading({
title: '学员签到中...'
});
const {data: res} = await uni.$http.post('/api/my/checkIn', {"code":this.info.code,"bookId":this.info.bookId});
if(res&&res.success){
uni.showModal({
title: '提示',
content: '学员签到成功!',
cancelText: '取消',
confirmText: '确定',
success: ress => {
//返回
uni.navigateBack({
delta: 1,
});
}
});
}
else{
uni.showModal({
title: '提示',
content: res.message? res.message:'学员签到失败!',
cancelText: '取消',
confirmText: '确定',
success: ress => {
if (ress.confirm) {
}
}
});
}
},
}
}
</script>
<style lang="scss" scoped>
::v-deep .uni-collapse-item__title-box{
padding: 0 !important;
}
::v-deep .uni-collapse-item__title-text{
font-weight: 600;
}
.page{
padding: 0;
position: relative;
background-image: url('@/static/image/bg.jpg');
background-attachment: fixed;
background-size: cover;
background-position: center center;
min-height: calc(100vh - var(--window-top) - var(--window-bottom));
}
.ret{
position: fixed;
top:20rpx;
left:20rpx;
background: rgba(0, 0, 0, .3);
height: 60rpx;
width: 60rpx;
border-radius: 50% 50%;
text-align: center;
line-height: 60rpx;
z-index: 9999;
}
.oscon{
margin:0;
background-color: #f3fafa;
padding: 16rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
.osimg{
width: 120rpx;
height: 120rpx;
border-radius: 10rpx;
}
.osrcon{
display: flex;
flex-direction: column;
flex: 1;
justify-content: flex-start;
margin-left: 20rpx;
}
.ostop{
display: flex;
flex-direction: row;
border-bottom: 1rpx dotted #74defb;
padding-bottom: 15rpx;
.osname{
line-height: 48rpx;
font-size:32rpx;
font-weight: 600;
color:#009999;
display: flex;
flex:1;
}
.qrimg{
width: 50rpx;
height: 50rpx;
}
}
.oscell{
display: flex;
flex-direction: row;
font-size: 28rpx;
color:#333;
padding: 15rpx 0;
border-bottom: 1rpx dotted #74defb;
.txt{
display: flex; flex: 1;
}
}
.oscellqr{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 20rpx 20rpx 10rpx 20rpx;
.ordtip{
font-size: 28rpx;
color:#000;
margin-bottom: 10rpx;
}
.ordqr{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 200rpx;
margin-bottom: 10rpx;
.imgqr{
width: 200rpx;
height: 200rpx;
}
}
.ordno{
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
.txt{
font-size: 28rpx;
color:#000;
}
.copy{
font-size: 28rpx;
color:#1296db;
margin-left: 6rpx;
}
}
}
.ztip{
color:#1296db;
font-size: 26rpx;
padding: 0;
height: 40rpx;
line-height: 40rpx;
}
.jtip{
color:#feb467;
font-size: 26rpx;
padding: 0;
height: 40rpx;
line-height: 40rpx;
}
.htip{
border-radius: 12rpx;
color:#fc6900;
font-size: 26rpx;
padding: 0;
height: 40rpx;
line-height: 40rpx;
}
.hwtip{
color:#FF0000;
font-size: 26rpx;
padding: 0;
height: 40rpx;
line-height: 40rpx;
}
.wtip{
color:#43cca4;
font-size: 26rpx;
padding: 0;
height: 40rpx;
line-height: 40rpx;
}
.gtip{
color:#0036D6;
font-size: 26rpx;
padding: 0;
height: 40rpx;
line-height: 40rpx;
}
.ftip{
color:#6A81F1;
font-size: 26rpx;
padding: 0;
height: 40rpx;
line-height: 40rpx;
}
.ctip{
color:#888;
font-size: 26rpx;
padding: 0;
height: 40rpx;
line-height: 40rpx;
}
}
.oinfo{
padding:20rpx;
position: relative;
margin-bottom: 20rpx;
.ozc{
display: flex;
flex-direction: column;
background-color: #becba0 ;
padding: 20rpx;
border-radius: 16rpx;
.ozstate{
font-size: 28rpx;
color: #333;
width: 100%;
margin: 10rpx 0;
}
.oztip{
font-size: 26rpx;
color: #333;
width: 100%;
margin: 0 0 20rpx;
}
}
.owc{
display: flex;
flex-direction: column;
background-color: #00a89b ;
padding: 20rpx;
border-radius: 16rpx;
.ozstate{
font-size: 28rpx;
color: #FFF;
width: 100%;
margin: 6rpx 0 0;
}
.oztip{
font-size: 26rpx;
color: #FFF;
width: 100%;
margin: 0 0 6rpx;
}
}
.oztgray{
display: flex;
flex-direction: column;
background-color: #ddd;
padding: 20rpx;
border-radius: 16rpx;
.ozstate{
font-size: 28rpx;
color: #333;
width: 100%;
margin: 6rpx 0;
}
.oztip{
font-size: 26rpx;
color: #747474;
width: 100%;
margin: 0 0 20rpx;
}
}
.oztorange{
display: flex;
flex-direction: column;
background-color: #faa755;
padding: 20rpx;
border-radius: 16rpx;
.ozstate{
font-size: 28rpx;
color: #FFF;
width: 100%;
margin: 6rpx 0;
}
.oztip{
font-size: 26rpx;
color: #FFF;
width: 100%;
margin: 0 0 20rpx;
}
}
.yycon{
display: flex;
flex-direction: column;
justify-content: center;
background-color: #FFFFFF;
margin-top: 20rpx;
padding: 20rpx 20rpx;
.atitle{
padding: 10rpx 0 10rpx;
color:#303133;
font-size: 30rpx;
font-weight: 600;
display: flex;
flex-direction: row;
justify-content: space-between;
.price{
font-size: 36rpx;
}
}
.olist{
display: flex;
flex-direction: column;
padding: 0;
width: 100%;
.ocell{
font-size: 26rpx;
color:#747474;
padding: 10rpx 0 10rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.ocell1{
font-size: 26rpx;
color:#747474;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
.sqcon{
padding: 20rpx;
margin: 20rpx 0;
background-color: #f5f5f5;
display: flex;
flex-direction: column;
border-radius: 10rpx;
.sqlist{
display: flex;
flex-direction: row;
justify-content: space-between;
color: #333333;
font-size: 26rpx;
line-height: 50rpx;
}
}
}
}
::v-deep.uni-radio-input-checked{
background-color: #00a89b !important;
border-color: #00a89b !important;
background-clip: content-box!important;
box-sizing: border-box;
}
::v-deep.uni-radio-input-checked::before{
display: none!important;
}
.pcon{
width: 690rpx;
padding-top:30rpx;
padding-bottom:50rpx;
background: #FCFCFD;
box-shadow: 0rpx 128rpx 128rpx 2rpx rgba(31,47,70,0.12);
border-radius: 16rpx 16rpx 16rpx 16rpx;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.phtxt{
width: 600rpx;
margin: 20rpx auto 10rpx;
font-size: 36rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 600;
color: #23262F;
}
.ptxt
{
width: 620rpx;
display: flex;
align-items: center;
justify-content: center;
margin: 30rpx auto;
border-radius: 16rpx 16rpx 16rpx 16rpx;
opacity: 1;
border: 2rpx solid #F7F8FA;
padding: 30rpx;
.qrimg{
width: 400rpx;
height: 400rpx;
}
}
.btn{
width: 520rpx;
height: 80rpx;
line-height: 80rpx;
background: #00A99A;
box-shadow: 0rpx 12rpx 64rpx 2rpx rgba(0,169,154,0.4);
border-radius: 254rpx 254rpx 254rpx 254rpx;
text-align: center;
font-size: 32rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #FCFCFD;
}
}
.bottom{
width: 100%;
margin-bottom: 148rpx;
}
.submitcon{
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 148rpx;
background: #FFFFFF;
box-shadow: 0rpx -4rpx 60rpx 2rpx rgba(1,31,63,0.1);
opacity: 1;
display: flex;
flex-direction: row;
}
.bbtn{
margin: 20rpx 50rpx 50rpx;
font-size: 32rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #FCFCFD;
width: 650rpx;
height: 76rpx;
line-height: 76rpx;
background: #00a89b;
box-shadow: 0rpx 12rpx 64rpx 2rpx rgba(137,150,95,0.4);
border-radius: 10rpx;
opacity: 1;
&::after{
border:none;
}
}
</style>