index.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <template>
  2. <div style="width: 70%;margin:0 auto">
  3. <div class="fx-row jc-between ai-center pd10 pt10 mb20">
  4. <el-image class="pointer" @click="$router.push('/login')" :src="`${$imgBase}index/login/icon_logo_medium@2x.png`"
  5. fit="contain"
  6. style="width: 152px;"></el-image>
  7. <div>
  8. <img class="icon16" src="../../assets/images/icon_tel2.png"/>
  9. <span class="pl8">服务热线:400-1797-985</span>
  10. </div>
  11. </div>
  12. <el-form ref="form" class="border pd20" :model="form" :rules="rules" label-width="80px" label-position="right">
  13. <p class="f24 pb20 f-primary bold text-left">名学金榜学生卡</p>
  14. <el-row :gutter="20">
  15. <el-col :span="12">
  16. <el-image :src="require('../../assets/images/pay_banner.png')"/>
  17. </el-col>
  18. <el-col :span="12">
  19. <el-form-item label="价格:"><span v-if="cardActive.price" class="bold f-red f18">
  20. ¥{{ cardActive.price / 100 }}</span>
  21. </el-form-item>
  22. <el-form-item label="有效期:">{{ cardActive.outTime }}</el-form-item>
  23. <el-form-item label="入学年份:">
  24. <el-button @click="cardActive = card" :type="card == cardActive ? 'primary' : ''" v-for="card in cardList">
  25. {{ card.year }}
  26. </el-button>
  27. </el-form-item>
  28. <el-form-item label="手机号:" prop="phoneNumber">
  29. <el-input v-model="form.phoneNumber"></el-input>
  30. </el-form-item>
  31. <el-form-item label="验证码:" prop="captcha">
  32. <div class="fx-row">
  33. <el-input class="mr30" v-model="form.captcha"></el-input>
  34. <el-button type="plain" @click="getCode" :disabled="disabled">{{ captchaBtnText }}</el-button>
  35. </div>
  36. </el-form-item>
  37. <el-form-item>
  38. <el-button type="primary" @click="validate">购买</el-button>
  39. </el-form-item>
  40. </el-col>
  41. </el-row>
  42. </el-form>
  43. <div class="tips ">
  44. <p class="f20 bold f-red">购卡须知</p>
  45. <p>1、您将购买的是电子卡,不同的入学年份有效期和价格不同。</p>
  46. <p>2、购买后系统默认激活当前的登录帐号,若忘记账号请联系客服。</p>
  47. <p>3、由于产品特性,本电子卡不适用“7天无理由退换货”。</p>
  48. </div>
  49. <el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false" custom-class="rd8" width="340px">
  50. <template #title>
  51. <div class="fx-column fx-cen-cen">
  52. <div class="f16">使用微信扫码支付</div>
  53. <div class="f-red f18">¥{{ cardActive.price / 100 }}</div>
  54. </div>
  55. </template>
  56. <el-image :src="payQR" style="width: 300px; height: 300px">
  57. <template v-if="isPaySuccess" #error>
  58. <div class="fx-column fx-cen-cen" style="padding-top: 50px">
  59. <el-icon class="f-success" name="success" style="font-size: 96px"/>
  60. <div class="mt20 f-red">支付成功,账号已通过短信发送,请注意查收</div>
  61. <div class="mt8">
  62. <el-link href="/login">点击此处,去登陆</el-link>
  63. </div>
  64. </div>
  65. </template>
  66. <template v-else-if="isPayFailed" #error>
  67. <div class="fx-column fx-cen-cen" style="padding-top: 50px">
  68. <el-icon class="f-danger" name="error" style="font-size: 96px"/>
  69. <div class="mt20 f-red">支付失败,您可以重新发起支付</div>
  70. <el-button type="text" class="mt8 f-666" @click="form.captcha='',dialogVisible=false">关闭</el-button>
  71. </div>
  72. </template>
  73. </el-image>
  74. <template #footer>
  75. <div class="fx-column fx-cen-cen">
  76. <div>名学金榜学习平台({{ cardActive.year }}学年)</div>
  77. <div>有效期至 <span class="bold">{{ cardActive.outTime }}</span></div>
  78. </div>
  79. </template>
  80. </el-dialog>
  81. </div>
  82. </template>
  83. <script>
  84. import { getEcardPrices, getOrderPayStatus, prepayCard, sendSmsNoValidation } from '@/api/webApi/pay'
  85. export default {
  86. name: 'PayIndex',
  87. created() {
  88. this.getEcardPrices()
  89. },
  90. data() {
  91. let checkPhone = (rule, value, callback) => {
  92. let reg = /^1[345789]\d{9}$/
  93. if (!reg.test(value)) {
  94. callback(new Error('手机号格式不正确!'))
  95. } else {
  96. callback()
  97. }
  98. }
  99. return {
  100. rules: {
  101. // required: true 是否必填,如不设置,则会根据校验规则自动生成
  102. phoneNumber: [
  103. { required: true, message: '请输入手机号', trigger: 'blur' },
  104. { type: 'number', validator: checkPhone, message: '请输入11位有效手机号号码', trigger: ['blur', 'change'] }
  105. ],
  106. captcha: { required: true, message: '短信验证码不能为空', trigger: 'change' }
  107. },
  108. form: {
  109. phoneNumber: '',
  110. captcha: ''
  111. },
  112. captchaBtnText: '免费获取',
  113. disabled: false,
  114. spaceTime: 60,
  115. cardActive: {},
  116. cardList: [],
  117. // qr dialog
  118. dialogVisible: false,
  119. payQR: '',
  120. // pay/order status
  121. orderTimer: null,
  122. orderId: '',
  123. isPaySuccess: false,
  124. isPayFailed: false,
  125. isUnPaid: false
  126. }
  127. },
  128. beforeDestroy() {
  129. this.stopOrderStatusTimer()
  130. },
  131. methods: {
  132. getCode() {
  133. this.$refs.form.clearValidate([])
  134. this.$refs.form.validateField('phoneNumber', (res) => {
  135. if (res == '') {
  136. // 通过
  137. sendSmsNoValidation({
  138. mobile: this.form.phoneNumber,
  139. smsType: 1
  140. }).then(res => {
  141. if (res.code == 200) {
  142. this.$message.success('发送成功,请在手机上查收')
  143. // 成功60秒不让点击
  144. this.disabled = true
  145. this.captchaBtnText = `(${this.spaceTime}秒)免费获取`
  146. let clock = window.setInterval(() => {
  147. this.spaceTime--
  148. this.captchaBtnText = `(${this.spaceTime}秒)免费获取`
  149. if (this.spaceTime < 0) {
  150. window.clearInterval(clock)
  151. this.captchaBtnText = '免费获取'
  152. this.totalTime = 60
  153. this.disabled = false
  154. }
  155. }, 1000)
  156. }
  157. })
  158. }
  159. })
  160. },
  161. getEcardPrices() {
  162. getEcardPrices().then(res => {
  163. this.cardList = res.data
  164. this.cardActive = res?.data[0]
  165. })
  166. },
  167. validate() {
  168. this.$refs.form.validate(valid => {
  169. if (!valid) return
  170. prepayCard({
  171. mobile: this.form.phoneNumber,
  172. code: this.form.captcha,
  173. ecardPayId: this.cardActive.id,
  174. id: this.cardActive.id,
  175. amount: 1
  176. }).then(res => {
  177. this.payQR = res.data.qrCode
  178. this.orderId = res.data.orderId
  179. this.dialogVisible = true
  180. this.stopOrderStatusTimer()
  181. this.startOrderStatusTimer()
  182. })
  183. })
  184. },
  185. startOrderStatusTimer() {
  186. if (this.orderTimer) return
  187. this.orderTimer = setInterval(() => {
  188. getOrderPayStatus({ orderId: this.orderId }).then(res => {
  189. const copyStatus = ['isPaySuccess', 'isPayFailed', 'isUnPaid']
  190. copyStatus.forEach(key => this[key] = res.data[key])
  191. const terminateStatus = ['isPaySuccess', 'isPayFailed']
  192. const terminate = terminateStatus.some(key => this[key])
  193. if (terminate) {
  194. this.stopOrderStatusTimer()
  195. this.payQR = ''
  196. }
  197. })
  198. }, 5000)
  199. },
  200. stopOrderStatusTimer() {
  201. if (this.orderTimer) {
  202. clearInterval(this.orderTimer)
  203. this.orderTimer = null
  204. }
  205. }
  206. }
  207. }
  208. </script>
  209. <style scoped>
  210. .border {
  211. border: 1px solid #e2e2e2;
  212. }
  213. >>> .el-form-item {
  214. margin-bottom: 20px;
  215. }
  216. .tips {
  217. padding: 20px 0;
  218. }
  219. .tips > p {
  220. margin-top: 10px;
  221. }
  222. /deep/ .el-dialog__body {
  223. padding-top: 0;
  224. padding-bottom: 0;
  225. }
  226. </style>