123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621 |
- <template>
- <div class="payment">
- <header>课程缴费</header>
- <div class="section">
- <h2 class="title">课程</h2>
- <div class="options">
- <div v-for="s in classInfo" :key="s.courseId">
- <div class="item" v-if="s.classType == 2">
- <div class="option" @click="onSelect(s)">
- <div class="0_hd"><i class="check_default" :class="[s.status ? 'check_active' : '']"></i></div>
- <div class="o_bd">乐团课</div>
- <span class="o_ft">价格:¥{{ s.buyCount * s.price }}</span>
- </div>
- <p class="timer">开课周期:{{ s.startCycel }}</p>
- <!-- <input class="inputAmount" type="number" @keyup="calcAmount" v-model="s.inputNumber" pattern="[0-9]" placeholder="输入金额"> -->
- </div>
- </div>
- </div>
- </div>
- <div v-for="c in classInfo" :key="c.courseId">
- <div class="section" v-if="c.classType != 2">
- <div class="options">
- <div class="option" @click="onSelect(c)">
- <div class="0_hd"><i class="check_default" :class="[c.status ? 'check_active' : '']"></i></div>
- <div class="o_bd">个别提高课</div>
- <span class="o_ft">
- 现价:¥{{ c.smallAmount }}
- </span>
- </div>
- </div>
- <div class="classInfo">
- <div class="class" v-if="c.memo">
- <p style="color: #FA101D;">{{ c.memo }}</p>
- </div>
- </div>
- <div class="classInfo" :class="[c.memo? 'classStatus' : '']">
- <div class="class">
- <p>学习科目:{{ c.subNames }}</p>
- <p>指导老师:{{ c.teaNames }}</p>
- </div>
- <div class="class">
- <p>开课周期:{{ c.startCycel }}</p>
- <!-- <p>计划开课周期:{{ c.planCycle }}</p> -->
- <p>每课时长:{{ c.duration }}分钟</p>
- </div>
- </div>
-
- <div class="classTime">
- <p class="title">购买次数:</p>
- <div class="ct_button_group">
- <span @click="fixationTimer(t, c)" v-for="t in classTimer" :key="t.timer" :class="[t.status?'active':'']">{{ t.timer }}次</span>
- </div>
- <input type="number" placeholder="输入次数" min="1" max="20" @keyup="onInputCheck(c)" v-model="c.inputNumber" class="inputTime" pattern="[0-9]">
- </div>
- </div>
- </div>
- <div class="buy">
- <div class="price">
- <!-- <p class="oldprice">
- <del class="text">原价</del>
- <del>¥{{ orderInfo.marketPrice }}</del>
- </p> -->
- <p class="now_price">
- <span class="text">仅需支付</span>
- <span>¥{{ orderInfo.referencePrice }}</span>
- </p>
- </div>
- <a @click="onCheckSubmit">购买</a>
- <!-- <a @click="buy">购买</a> -->
- </div>
- <van-popup id="protocolPopup" v-model="popupStatus" position="bottom">
- <small-protocol :proto="protocolData" @popupClose="onPopupClose"></small-protocol>
- </van-popup>
- </div>
- </template>
- <script>
- import smallProtocol from './smallProtocol'
- import qs from 'qs'
- import { Dialog } from 'vant'
- export default {
- name: 'payment',
- components: { smallProtocol, Dialog },
- data() {
- return {
- popupStatus: false, // 协议弹窗样式
- protocolData: {}, // 协议参数
- type: true,
- classInfo: [],
- memo: null,
- inputTimes: 0, // 输入次数
- // mainSubject: [], // 主课程
- // 金额列表,金额计算
- orderInfo: {
- marketPrice: 0, // 原价总金额
- referencePrice: 0, // 现价总金额
- }, // 信息列表
- classTimer: [{
- status: true,
- timer: 10
- },{
- status: false,
- timer: 20
- }]
- }
- },
- mounted() {
- let userId = this.$route.query.userId
- axios.post('/user/queryUserCourse', qs.stringify({ userId: userId })).then((res) => {
- let data = res.data.data.courses
- // let data = res.data.data
- if(!data) {
- throw '数据为空'
- }
- this.memo = res.data.data.memo // 特殊描述
- let tempClassForm = {}
- if(this.memo) {
- let tempMemo = this.memo.split('&')
- tempMemo.forEach(me => {
- var memoItem = me.split('^')
- tempClassForm[memoItem[0]] = memoItem[1]
- })
- }
- /**
- * 过滤数据
- * 乐团课同一个乐团只需要显示一个乐团(价格高的)
- * 如果有多个乐团课则显示多个
- */
- let subjectStatus = {}
- let paymentConfig = sessionStorage.getItem('paymentConfig')
- if(paymentConfig) {
- paymentConfig = JSON.parse(paymentConfig)
- sessionStorage.removeItem('homeConfig') // 用完就不要了
- }
- data.forEach(el => {
- el.status = false // 状态
- el.inputNumber = null // 输入的内容
- el.smallAmount = 0 // 小课金额
- if(tempClassForm[this.classFormToCN(el.classForm)]) {
- el.memo = tempClassForm[this.classFormToCN(el.classForm)]
- } else if(tempClassForm['default']) {
- el.memo = tempClassForm['default']
- } else {
- el.memo = ''
- }
- // 开课周期
- if(el.planCycle) {
- el.startCycel = this.weekSelect(el.planCycle) + ' ' + el.planBegin.split(' ')[1]
- } else {
- el.startCycel = '不上课'
- }
- // 课程
- let searchClassId = subjectStatus[el.classId], // 查询Id是否存在
- countAmount = el.buyCount * el.price // 总价
- if(!searchClassId && el.classType == 2) {
- this.classInfo.push(el)
- subjectStatus[el.classId] = {
- price: countAmount
- }
- } else if(searchClassId && el.classType == 2 && searchClassId.price < countAmount) {
- for(let i = 0; i < this.classInfo.length; i++) {
- if(this.classInfo[i].classId == el.classId) {
- this.classInfo[i] = el
- }
- }
- subjectStatus[el.classId] = {
- price: countAmount
- }
- }
- // 小课
- if(el.classType == 1) {
- this.classInfo.push(el)
- }
- //
- if(paymentConfig && paymentConfig.config == el.courseId) {
- el.status = true
- }
- })
- this.calcAmount() // 计算金额
- })
- },
- methods: {
- buy() {
- let [record, timer] = [0, 0] // 购买课次数据
- let params = {
- userId: this.$route.query.userId
- }
- this.classTimer.forEach(ct => {
- if(ct.status) {
- timer = ct.timer
- }
- })
- let cour = {}
- let configIndex, inputCount // 课程编号(唯一) 输入的次数
- // 拼接参数
- this.classInfo.forEach(c => {
- if(c.classType == 2 && c.status) {
- cour = {
- courseId: c.courseId,
- buyCount: c.buyCount,
- price: c.price
- }
- }
- if(c.classType == 1 && c.status) {
- cour = {
- courseId: c.courseId,
- buyCount: parseInt(this.inputTimes),
- price: c.price
- }
- if(timer) {
- cour.buyCount = timer
- }
- }
- if(c.status) {
- record++
- configIndex = c.courseId
- }
- })
- params.courses = JSON.stringify(cour)
- if(!record) {
- Dialog.alert({
- title: '提示',
- message: '请选择续费课程',
- confirmButtonColor: '#269a93'
- })
- return false
- }
- // 保存用户选择信息保存本地
- sessionStorage.setItem('paymentConfig', JSON.stringify({
- config: configIndex
- }))
- axios.post('/yqpay/renewalsPay', qs.stringify(params)).then(res => {
- let result = res.data
- if(result.status) {
- document.querySelector('#onSubmit').action = result.data.host
- document.querySelector('#apiContent').value = result.data.apiContent
- document.querySelector('#merNo').value = result.data.merNo
- document.querySelector('#notifyUrl').value = result.data.notifyUrl
- document.querySelector('#sign').value = result.data.sign
- document.querySelector('#signType').value = result.data.signType
- document.querySelector('#timestamp').value = result.data.timestamp
- document.querySelector('#version').value = result.data.version
- document.querySelector('#onSubmit').submit()
- } else {
- Dialog.alert({
- title: '提示',
- message: result.msg,
- confirmButtonColor: '#269a93'
- })
- }
- })
- },
- onSelect(item) { // 选中哪个课程(大课还是小课)
-
- this.classInfo.forEach(e => {
- e.status = false
- })
- item.status = true
- this.calcAmount()
- },
- // 固定次数计算
- fixationTimer(t, item) {
- item.inputNumber = null
- this.classTimer.forEach(e => {
- e.status = false
- })
- t.status = true
- let amount = t.timer * item.price
- item.smallAmount = amount
- // 如果当前课程选中则需要重新计算金额
- if(item.status) {
- this.orderInfo.referencePrice = amount
- }
- },
- onInputCheck(item) {
- if(item.inputNumber <= 1 ) {
- item.inputNumber = 1
- }
- if(item.inputNumber > 20) {
- item.inputNumber = 20
- }
- this.inputTimes = item.inputNumber
- this.calcAmount(item)
- },
- // 计算总金额
- calcAmount(item) {
- let timer, c = this.classInfo
- this.classTimer.forEach(ct => {
- // 判断是否从 Input 里面输入的
- if(item && item.inputNumber) {
- ct.status = false
- }
- if(ct.status) {
- timer = ct.timer
- }
- })
- c.forEach(e => {
- // 小课现价
- let amount = timer ? (timer * e.price) : e.inputNumber * e.price
- e.smallAmount = amount
- if(e.status) {
- if(e.classType == 2) {
- this.orderInfo.referencePrice = e.price * e.buyCount
- } else {
- // 判断是否有选中固定次数
- this.orderInfo.referencePrice = amount
- }
- }
- })
- },
- weekSelect(num) {
- // 计算是周几
- let res = num.toString(2).split('').reverse() // 转换成二进制 并分割成数组 反转
- let strArr = []
- parseInt(res[0]) ? strArr.push('周一') : ''
- parseInt(res[1]) ? strArr.push('周二') : ''
- parseInt(res[2]) ? strArr.push('周三') : ''
- parseInt(res[3]) ? strArr.push('周四') : ''
- parseInt(res[4]) ? strArr.push('周五') : ''
- parseInt(res[5]) ? strArr.push('周六') : ''
- parseInt(res[6]) ? strArr.push('周七') : ''
- strArr = strArr.join('和')
- return strArr
- },
- onCheckSubmit() {
- // 小课需要弹出协议
- let buyTimer
- this.classTimer.forEach(e => {
- if(e.status) {
- buyTimer = e.timer
- }
- })
- let item
- this.classInfo.forEach(c => {
- if(c.status) {
- item = c
- }
- })
- let tempBuyCount
- if(item.classType == 2) {
- tempBuyCount = item.buyCount
- } else {
- tempBuyCount = buyTimer ? buyTimer : parseInt(this.inputTimes)
- }
- this.protocolData = {
- userId: this.$route.query.userId,
- price: item.price,
- buyCount: tempBuyCount,
- classForm: item.classForm,
- className: item.className,
- subNames: item.subNames,
- classType: item.classType
- }
- this.popupStatus = true
- },
- onPopupClose(status) {
- // document.querySelector('#protocolPopup').scroll(0, 0)
- // this.popupStatus = false
- this.buy()
- },
- classFormToCN(number) { // 小课课程类型
- let resultStr
- switch(number) {
- case 1001:
- resultStr = '1V1'
- break;
- case 2002:
- resultStr = '1V2'
- break;
- case 3003:
- resultStr = '1V3'
- break;
- case 4004:
- resultStr = '1V4'
- break;
- case 5005:
- resultStr = '1V5'
- break;
- case 6020:
- resultStr = '小组课'
- break;
- case 21099:
- resultStr = '大课'
- break;
- case 999999:
- resultStr = '团体课'
- break;
- }
- return resultStr
- }
- }
- }
- </script>
- <style lang="less" scoped>
- .payment {
- margin-bottom: .7rem;
- }
- .classStatus {
- border-top:0 !important;
- margin-top: 0 !important;
- padding-top: 0 !important;
- }
- header {
- height: .40rem;
- line-height: .40rem;
- color: #000;
- font-size: .17rem;
- background: #fff;
- box-shadow: 0px 1px 8px 0px rgba(0,0,0,0.07);
- text-align: center;
- margin-bottom: .06rem;
- }
- .section {
- padding: .16rem .22rem .1rem;
- background: #fff;
- margin-bottom: .1rem;
- .line_bottom {
- border-bottom: 1px solid #ededed;
- }
- > .title {
- font-size: .2rem;
- line-height: .28rem;
- font-weight: bold;
- &::before {
- content: ' ';
- width: .04rem;
- height: 0.15rem;
- background: #14928a;
- display: inline-block;
- margin-right: .07rem;
- border-radius: 8px;
- }
- }
- }
- .options {
- // padding-top: .08rem;
- .option {
- line-height: .26rem;
- font-size: .15rem;
- display: flex;
- align-items: center;
- position: relative;
- .o_bd {
- flex: 1;
- .protocol {
- font-size: .1rem;
- line-height: .14rem;
- }
- }
- .o_ft {
- font-size: .12rem;
- color: #FA101D;
- del {
- color: #AAAAAA;
- font-size: .11rem;
- }
- }
- .check_default {
- position: relative;
- margin-right: .08rem;
- display: block;
- width: .14rem;
- height: .14rem;
- border-radius: 50%;
- border: .01rem solid #D0CFCF;
- &::before {
- position: absolute;
- top: .01rem;
- left: .01rem;
- content: ' ';
- display: inline-block;
- width: .12rem;
- height: .12rem;
- background: #D0CFCF;
- border-radius: 50%;
- }
- &.check_active {
- border: .01rem solid #F1111B;
- &::before {
- background: #F1111B;
- border-radius: 50%;
- }
- }
- }
- }
- }
- .item {
- position: relative;
- border-top: 1px solid #ededed;
- padding: .2rem 0;
- // &:last-child {
- // border-bottom: 0;
- // }
- .timer {
- font-size: .14rem;
- color: #ACACAC;
- }
- .inputAmount {
- position: absolute;
- top: .2rem;
- right: 0;
- width: 1.08rem;
- height: .4rem;
- border-radius: 5px;
- border: 1px solid rgba(238,238,238,1);
- padding-left: .08rem;
- }
- }
- .classInfo {
- color: #ACACAC;
- font-size: .12rem;
- display: flex;
- justify-content: space-between;
- border-top: 1px solid #ededed;
- margin-top: .08rem;
- padding-top: .08rem;
- line-height: .22rem;
- }
- .classTime {
- color: #ACACAC;
- font-size: .12rem;
- .ct_button_group {
- padding-top: .08rem;
- padding-bottom: .15rem;
- display: flex;
- justify-content: space-between;
- span {
- width: 1.6rem;
- line-height: .36rem;
- text-align: center;
- background:rgba(255,255,255,1);
- border-radius:5px;
- font-size: .14rem;
- color: #444444;
- border:1px solid rgba(226,224,224,1);
- &.active {
- background: #14928A;
- color: #fff;
- }
- }
- }
- .inputTime {
- width: calc(100% - .08rem);
- height: .4rem;
- border-radius:5px;
- border:1px solid rgba(238,238,238,1);
- padding-left: .08rem;
- font-size: .14rem;
- color: #444;
- }
- }
- .buy {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- height: .6rem;
- display: flex;
- align-items: center;
- padding: 0 .2rem;
- border-top: 1px solid #FFE9E9E9;
- color: #000000;
- font-size: .12rem;
- background: #fff;
- .price {
- flex: 1;
- font-size: .16rem;
-
- }
- font-size: .16rem;
- span {
- color: #FA101D;
- }
- .text {
- font-size: .12rem;
- width: .55rem;
- display: inline-block;
- color: #000;
- }
- del {
- color: #B5B5B5;
- &.text {
- color: #B5B5B5;
- }
- }
- a {
- display: inline-block;
- font-size: .18rem;
- color: #fff;
- background: #F1111B;
- border-radius: .04rem;
- box-shadow:0px 2px 4px 0px rgba(0,0,0,0.19);
- padding: .08rem .28rem;
- }
- }
- </style>
|