|
@@ -0,0 +1,373 @@
|
|
|
|
+<template>
|
|
|
|
+ <van-dialog
|
|
|
|
+ class="bind-phone-dialog"
|
|
|
|
+ v-model="show"
|
|
|
|
+ :show-confirm-button="false"
|
|
|
|
+ >
|
|
|
|
+ <div class="bind-header">
|
|
|
|
+ <van-image
|
|
|
|
+ :id="getConfig.id"
|
|
|
|
+ class="reveal-box"
|
|
|
|
+ :src="getConfig.pic"
|
|
|
|
+ :alt="getConfig.name"
|
|
|
|
+ :style="getStyle"
|
|
|
|
+ error-icon="https://cdn-ali2.jianyu360.cn/qmxupload/2024/05/06/202405061855550056F9KON1T.png"
|
|
|
|
+ @click.stop="openAD(getConfig.link)"
|
|
|
|
+ >
|
|
|
|
+ <div class="tag-text">广告</div>
|
|
|
|
+ <van-icon class="dialog-close" name="cross" @click.stop="onClose" />
|
|
|
|
+ </van-image>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="bind-form">
|
|
|
|
+ <van-field
|
|
|
|
+ v-model.trim="info.phone"
|
|
|
|
+ label="手机号"
|
|
|
|
+ type="tel"
|
|
|
|
+ maxlength="11"
|
|
|
|
+ placeholder="请输入手机号码"
|
|
|
|
+ :error-message="errorMessage.phone"
|
|
|
|
+ @blur="checkPhoneRegPass"
|
|
|
|
+ ></van-field>
|
|
|
|
+ <van-field
|
|
|
|
+ v-show="picCode.show"
|
|
|
|
+ v-model.trim="info.picCode"
|
|
|
|
+ label=""
|
|
|
|
+ maxlength="6"
|
|
|
|
+ placeholder="图形验证码"
|
|
|
|
+ :error-message="errorMessage.picCode"
|
|
|
|
+ >
|
|
|
|
+ <template #button>
|
|
|
|
+ <div class="pic-code" @click="refreshCaptcha">
|
|
|
|
+ <img :src="imgBase64Complete" v-if="picCode.imgBase64" />
|
|
|
|
+ <van-loading size="24" v-else></van-loading>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </van-field>
|
|
|
|
+ <van-field
|
|
|
|
+ v-model.trim="info.code"
|
|
|
|
+ label="验证码"
|
|
|
|
+ maxlength="6"
|
|
|
|
+ placeholder="请输入验证码"
|
|
|
|
+ :error-message="errorMessage.code"
|
|
|
|
+ >
|
|
|
|
+ <template #button>
|
|
|
|
+ <van-button
|
|
|
|
+ class="send-code"
|
|
|
|
+ :class="{ active: info.phone }"
|
|
|
|
+ size="small"
|
|
|
|
+ :disabled="sendCodeButtonDisabled"
|
|
|
|
+ @click="sendVerifyCode"
|
|
|
|
+ >{{ sendCodeButtonText }}</van-button
|
|
|
|
+ >
|
|
|
|
+ </template>
|
|
|
|
+ </van-field>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="bind-footer">
|
|
|
|
+ <div class="j-button-group">
|
|
|
|
+ <button
|
|
|
|
+ class="j-button-confirm clickable"
|
|
|
|
+ @click="onConfirm"
|
|
|
|
+ :disabled="confirmButtonDisabled"
|
|
|
|
+ >
|
|
|
|
+ 绑定
|
|
|
|
+ </button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </van-dialog>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+import Vue from 'vue'
|
|
|
|
+import { Dialog, Button, Loading, Field, Icon, Image } from 'vant'
|
|
|
|
+import { getPhoneCaptcha, setPhoneBind, ajaxGetAD } from '../api/api'
|
|
|
|
+import { adConfigFormatter, px2viewport } from '../utils/utils'
|
|
|
|
+export default {
|
|
|
|
+ name: 'BindPhoneDialog',
|
|
|
|
+ components: {
|
|
|
|
+ [Dialog.name]: Dialog,
|
|
|
|
+ [Button.name]: Button,
|
|
|
|
+ [Loading.name]: Loading,
|
|
|
|
+ [Field.name]: Field,
|
|
|
|
+ [Icon.name]: Icon,
|
|
|
|
+ [Image.name]: Image
|
|
|
|
+ },
|
|
|
|
+ props: {
|
|
|
|
+ visible: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: false
|
|
|
|
+ },
|
|
|
|
+ adCode: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: ''
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ show: this.visible,
|
|
|
|
+ info: {
|
|
|
|
+ phone: '',
|
|
|
|
+ picCode: '',
|
|
|
|
+ code: ''
|
|
|
|
+ },
|
|
|
|
+ errorMessage: {
|
|
|
|
+ phone: '',
|
|
|
|
+ picCode: '',
|
|
|
|
+ code: ''
|
|
|
|
+ },
|
|
|
|
+ sendCodeButton: {
|
|
|
|
+ timerId: 0,
|
|
|
|
+ timeStartDefault: 60,
|
|
|
|
+ defaultValue: '发送验证码',
|
|
|
|
+ count: 0
|
|
|
|
+ },
|
|
|
|
+ picCode: {
|
|
|
|
+ show: false,
|
|
|
|
+ imgBase64: '',
|
|
|
|
+ cacheShow: false,
|
|
|
|
+ cacheImgBase64: ''
|
|
|
|
+ },
|
|
|
|
+ conf: {
|
|
|
|
+ phoneReg: /^1[3-9]\d{9}$/
|
|
|
|
+ },
|
|
|
|
+ info: {}
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ computed: {
|
|
|
|
+ confirmButtonDisabled() {
|
|
|
|
+ let hasEmpty = false
|
|
|
|
+ if (this.picCode.show) {
|
|
|
|
+ hasEmpty = !this.info.phone || !this.info.code || !this.info.picCode
|
|
|
|
+ } else {
|
|
|
|
+ hasEmpty = !this.info.phone || !this.info.code
|
|
|
|
+ }
|
|
|
|
+ const pass = this.conf.phoneReg.test(this.info.phone)
|
|
|
|
+ return hasEmpty || !pass
|
|
|
|
+ },
|
|
|
|
+ sendCodeButtonText() {
|
|
|
|
+ const dText = this.sendCodeButton.defaultValue
|
|
|
|
+ return this.sendCodeButton.count <= 0
|
|
|
|
+ ? dText
|
|
|
|
+ : `重新发送(${this.sendCodeButton.count}s)`
|
|
|
|
+ },
|
|
|
|
+ sendCodeButtonDisabled() {
|
|
|
|
+ return this.sendCodeButton.count > 0
|
|
|
|
+ },
|
|
|
|
+ imgBase64Complete() {
|
|
|
|
+ return 'data:image/png;base64,' + this.picCode.imgBase64
|
|
|
|
+ },
|
|
|
|
+ getStyle() {
|
|
|
|
+ return {
|
|
|
|
+ width: this.getConfig?.extend?.width
|
|
|
|
+ ? px2viewport(this.getConfig?.extend?.width)
|
|
|
|
+ : '',
|
|
|
|
+ height: this.getConfig?.extend?.height
|
|
|
|
+ ? px2viewport(this.getConfig?.extend?.height)
|
|
|
|
+ : ''
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ getConfig() {
|
|
|
|
+ if (this.info?.pic) {
|
|
|
|
+ return this.info
|
|
|
|
+ } else {
|
|
|
|
+ return {
|
|
|
|
+ pic: '',
|
|
|
|
+ link: '',
|
|
|
|
+ name: '内容区域广告',
|
|
|
|
+ extend: {
|
|
|
|
+ width: '',
|
|
|
|
+ height: '',
|
|
|
|
+ type: ''
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ mounted() {
|
|
|
|
+ if (!this.adCode) {
|
|
|
|
+ const code = this.$envs.inWX
|
|
|
|
+ ? 'wx-bind-phone-dialog'
|
|
|
|
+ : 'app-bind-phone-dialog'
|
|
|
|
+ this.getAd([code])
|
|
|
|
+ } else {
|
|
|
|
+ this.getAd([this.adCode])
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ watch: {
|
|
|
|
+ visible(val) {
|
|
|
|
+ console.log(val, 'visible')
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ showToast(message) {
|
|
|
|
+ this.$toast({
|
|
|
|
+ duration: 1500,
|
|
|
|
+ forbidClick: true,
|
|
|
|
+ message: message
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ showLoading() {
|
|
|
|
+ return this.$toast.loading({
|
|
|
|
+ duration: 0,
|
|
|
|
+ forbidClick: true,
|
|
|
|
+ message: 'loading...'
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ async getAdInfoFromRequest(codes) {
|
|
|
|
+ const {
|
|
|
|
+ error_code: code,
|
|
|
|
+ error_msg: msg,
|
|
|
|
+ data = {}
|
|
|
|
+ } = await ajaxGetAD({ codes })
|
|
|
|
+ if (code === 0 && data) {
|
|
|
|
+ const info = adConfigFormatter(Object.values(data).flat()[0])
|
|
|
|
+ return { info }
|
|
|
|
+ } else {
|
|
|
|
+ console.warn(msg)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ afterGetConfig() {
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
+ // 计算高度过小,给个占位类名
|
|
|
|
+ const image = this.$refs.image
|
|
|
|
+ if (image) {
|
|
|
|
+ const $el = image?.$el
|
|
|
|
+ if ($el) {
|
|
|
|
+ const height = $el.clientHeight
|
|
|
|
+ if (height < 10) {
|
|
|
|
+ this.mgb = true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ async getAd(codes) {
|
|
|
|
+ try {
|
|
|
|
+ const { info = {} } = await this.getAdInfoFromRequest(codes)
|
|
|
|
+ this.info = info || {}
|
|
|
|
+ } catch (e) {
|
|
|
|
+ console.warn('获取广告位信息异常:', e)
|
|
|
|
+ } finally {
|
|
|
|
+ this.afterGetConfig()
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ async getImgCaptcha(needCache) {
|
|
|
|
+ if (this.picCode.cacheImgBase64) {
|
|
|
|
+ this.picCode.show = this.picCode.cacheShow
|
|
|
|
+ this.picCode.imgBase64 = this.picCode.cacheImgBase64
|
|
|
|
+ this.picCode.cacheImgBase64 = ''
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ const { error_code: code, error_msg: msg, data } = await getPhoneCaptcha()
|
|
|
|
+ if (code === 0 && data) {
|
|
|
|
+ // 是否缓存图片
|
|
|
|
+ if (needCache == 'cache') {
|
|
|
|
+ // 将下一张图片的状态缓存
|
|
|
|
+ this.picCode.cacheShow = data.needVerify
|
|
|
|
+ this.picCode.cacheImgBase64 = data.imageData
|
|
|
|
+ } else {
|
|
|
|
+ this.picCode.show = data.needVerify
|
|
|
|
+ this.picCode.imgBase64 = data.imageData
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ this.showToast(msg)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ refreshCaptcha() {
|
|
|
|
+ this.picCode.imgBase64 = ''
|
|
|
|
+ this.getImgCaptcha()
|
|
|
|
+ },
|
|
|
|
+ checkPhoneRegPass() {
|
|
|
|
+ let pass = this.conf.phoneReg.test(this.info.phone)
|
|
|
|
+ if (this.info.phone) {
|
|
|
|
+ if (pass) {
|
|
|
|
+ this.errorMessage.phone = ''
|
|
|
|
+ } else {
|
|
|
|
+ this.errorMessage.phone = '手机号格式不正确'
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ this.errorMessage.phone = ''
|
|
|
|
+ }
|
|
|
|
+ return pass
|
|
|
|
+ },
|
|
|
|
+ startSendCodeTimer(t) {
|
|
|
|
+ this.sendCodeButton.count = t || this.sendCodeButton.timeStartDefault
|
|
|
|
+ this.sendCodeButton.timerId = setInterval(() => {
|
|
|
|
+ this.sendCodeButton.count--
|
|
|
|
+ if (this.sendCodeButton.count <= 0) {
|
|
|
|
+ // 倒计时结束
|
|
|
|
+ clearInterval(this.sendCodeButton.timerId)
|
|
|
|
+ // 倒计时结束,刷新验证码
|
|
|
|
+ if (this.picCode.cacheImgBase64) {
|
|
|
|
+ this.picCode.show = this.picCode.cacheShow
|
|
|
|
+ this.picCode.imgBase64 = this.picCode.cacheImgBase64
|
|
|
|
+ this.picCode.cacheImgBase64 = ''
|
|
|
|
+ } else {
|
|
|
|
+ this.refreshCaptcha()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }, 1000)
|
|
|
|
+ },
|
|
|
|
+ // 发送验证码
|
|
|
|
+ async sendVerifyCode() {
|
|
|
|
+ const pass = this.checkPhoneRegPass()
|
|
|
|
+ if (!pass) return
|
|
|
|
+ const loading = this.showLoading()
|
|
|
|
+ const params = {
|
|
|
|
+ phone: this.info.phone,
|
|
|
|
+ code: this.info.picCode,
|
|
|
|
+ step: 1
|
|
|
|
+ }
|
|
|
|
+ const {
|
|
|
|
+ error_code: code,
|
|
|
|
+ error_msg: msg,
|
|
|
|
+ data
|
|
|
|
+ } = await setPhoneBind(params, 'bind')
|
|
|
|
+ loading.clear()
|
|
|
|
+ if (code === 0 && data?.state === 1) {
|
|
|
|
+ this.startSendCodeTimer()
|
|
|
|
+ this.showToast('验证码发送成功')
|
|
|
|
+ this.getImgCaptcha('cache')
|
|
|
|
+ } else {
|
|
|
|
+ this.showToast(msg || '验证码发送失败')
|
|
|
|
+ this.refreshCaptcha()
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ async onConfirm() {
|
|
|
|
+ const pass = this.checkPhoneRegPass()
|
|
|
|
+ if (!pass) return
|
|
|
|
+ const loading = this.showLoading()
|
|
|
|
+ const params = {
|
|
|
|
+ phone: this.info.phone,
|
|
|
|
+ code: this.info.code,
|
|
|
|
+ step: 2
|
|
|
|
+ }
|
|
|
|
+ const {
|
|
|
|
+ error_code: code,
|
|
|
|
+ error_msg: msg,
|
|
|
|
+ data
|
|
|
|
+ } = await setPhoneBind(params, 'bind')
|
|
|
|
+ loading.clear()
|
|
|
|
+ if (code === 0 && data) {
|
|
|
|
+ // 绑定成功
|
|
|
|
+ this.$emit('bound')
|
|
|
|
+ } else {
|
|
|
|
+ this.$toast(msg || '请求失败')
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ onClose() {
|
|
|
|
+ this.$emit('close')
|
|
|
|
+ this.show = false
|
|
|
|
+ },
|
|
|
|
+ close() {
|
|
|
|
+ this.show = false
|
|
|
|
+ },
|
|
|
|
+ open() {
|
|
|
|
+ this.show = true
|
|
|
|
+ },
|
|
|
|
+ openAD(link) {
|
|
|
|
+ if (!link) return
|
|
|
|
+ location.href = link
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</script>
|