login.vue 6.64 KB
<template>
  <van-image width="100%" height="100%" :src="logo_image" />
  <div class="login-header">
    <van-row align="center">
      <van-col span="8">
      </van-col>
      <van-col span="8" class="title">
        <p>登&nbsp;录</p>
      </van-col>
      <van-col span="8">
      </van-col>
    </van-row>
  </div>
  <div class="login-section">
    <van-config-provider :theme-vars="themeVars">
      <van-form ref="form" @submit="onSubmit">
        <van-cell-group inset style="border: 1px solid #EAEAEA;">
          <van-field v-if="use_widget" v-model="phone" name="phone" label="手机号" placeholder="手机号" readonly clickable
            :rules="[{ validator, message: '请输入正确手机号' }]"
            @touchstart.stop="showKeyboard" />
          <van-field v-else v-model="phone" name="validator" label="手机号" placeholder="手机号"
            :rules="[{ validator, message: '请输入正确手机号' }]" />
          <van-field v-model="code" center clearable name="code" type="digit" label="短信验证码" placeholder="请输入短信验证码"
            :formatter="formatter" :rules="[{ required: true, message: '请填写验证码' }]">
            <template #button>
              <van-button @click="sendCode" v-if="countDown.current.value.total === limit" size="small" type="primary" :disabled="disabled">
                <span>发送验证码</span>
              </van-button>
              <van-button v-else size="small" type="primary" :disabled="disabled">
                <span>{{ countDown.current.value.seconds }} 秒重新发送</span>
              </van-button>
            </template>
          </van-field>
        </van-cell-group>
      </van-form>
    </van-config-provider>
  </div>
  <div class="btn" @click="submit">
    登&nbsp;录
  </div>

  <van-number-keyboard v-model="phone" :show="keyboard_show" :maxlength="11" @blur="onBlur" />

  <!-- 图片滑块验证 -->
  <image-slider-verify
    :isShow="sliderShow"
    @done="handleConfirm"
    @on-close="handleClose"
    >
  </image-slider-verify>
</template>

<script setup>
import Cookies from 'js-cookie'
import ImageSliderVerify from '@/components/ImageSliderVerify/index.vue'

import { ref, onMounted } from 'vue';
import { Toast } from 'vant'
import { useRouter } from 'vue-router'
import axios from '@/utils/axios'
import logo_image from '@images/denglu-top@2x.gif'
import { wxInfo } from '@/utils/tools';

import { useCountDown } from '@vant/use';

const $router = useRouter();

// 判断是否显示控件
let use_widget = ref(true);
/**
 * 手机号码校验
 * 函数返回 true 表示校验通过,false 表示不通过
 * @param {*} val 
 */
const validator = (val) => {
  let flag = false;
  // 简单判断手机号位数
  if (/1\d{10}/.test(val) && phone.value.length === 11) {
    disabled.value = false;
    flag = true;
  } else {
    disabled.value = true;
    flag = false;
  }
  return flag
};


const phone = ref('');
const code = ref('');
// TAG: 开发环境测试数据
if (import.meta.env.DEV) {
  phone.value = import.meta.env.VITE_ID
  code.value = import.meta.env.VITE_PIN
}

const form = ref(null);

onMounted(() => {
  /**
   * 判断微信环境看是否弹出控件框
   * 桌面微信直接输入
   * 其他环境弹出输入框
   */
  if (wxInfo().isiOS || wxInfo().isAndroid) {
    use_widget.value = true;
  } else {
    use_widget.value = false;
  }
  // 判断微信授权状态,进入页面时未授权需要授权跳转
  if (!Cookies.get('PHPSESSID')) {
    $router.replace({
      path: '/auth',
      query: {
        href: location.hash,
        userType: 'b'
      }
    });
  }
})

const submit = () => {
  let valid = form.value.validate();
  valid
    .then(() => {
      form.value.submit();
    })
    .catch(error => {
      console.error(error);
      Toast({
        message: '请检查后再次提交',
        icon: 'cross',
      });
    })
}

// 手机号输入控件控制
const keyboard_show = ref(false);
const showKeyboard = () => { // 弹出数字弹框
  keyboard_show.value = true;
};
const onBlur = () => { // 数字键盘失焦回调
  keyboard_show.value = false;
  if (phone.value.length === 11) {
    disabled.value = false;
  }
};

// 设置发送短信倒计时
// const countDown = ref(60);
// const countDownHandle = () => {
//   // 倒计时
//   if (countDown.value === 0) {
//     countDown.value = 60;
//   } else {
//     countDown.value--;
//     setTimeout(() => {
//       countDownHandle()
//     }, 1000)
//   }
// }

// 设置发送短信倒计时
// TAG: vant 自带倒计时函数
const limit = ref(60000); // 配置倒计时秒数
const countDown = useCountDown({
  // 倒计时 24 小时
  time: limit.value,
  onFinish: () => {
    countDown.reset();
  }
});

const sendCode = () => { // 发送验证码
  countDown.start();
  // TODO: 验证码接口
  axios.post('/srv/?a=bind_phone&t=get_code', {
    phone: phone.value
  })
    .then(res => {
      if (res.data.code === 1) {
        Toast.success('发送成功');
      } else {
        console.warn(res.data);
        if (!res.data.show) return false;
        Toast({
          message: res.data.msg,
          icon: 'close',
        });
      }
    })
    .catch(err => {
      console.error(err);
    })
};

const disabled = ref(true);
// 过滤输入的数字 只能四位
const formatter = (value) => value.substring(0, 4);

/**
 * 用户登录
 * @param {*} values 
 */

const onSubmit = (values) => {
  axios.post('/srv/?a=b_login', {
    phone: values.phone,
    pin: values.code,
  })
    .then(res => {
      if (res.data.code === 1) {
        $router.push({
          path: '/business/index'
        });
      } else {
        console.warn(res.data);
        Toast({
          message: res.data.msg,
          icon: 'close',
        });
      }
    })
    .catch(err => {
      console.error(err);
    })
};

const themeVars = {
  buttonPrimaryBackground: '#F9D95C',
  buttonPrimaryBorderColor: '#F9D95C',
  buttonPrimaryColor: '#713610',
  CellVerticalPadding: '14px'
};

// 滑块验证成功后回调
const sliderShow = ref(false);
const handleConfirm = (val) => {
  sliderShow.value = false
  console.warn('验证成功');
}
const handleClose = () => {
  sliderShow.value = false
}
const imageVerify = () => {
  sliderShow.value = true;
}
</script>

<style lang="less" scoped>
body {
  --van-button-primary-background: white;
}

.login-header {
  margin-bottom: 1rem;

  .title {
    text-align: center;
    margin-top: 2vh;

    p {
      font-size: 2.5vh;
      margin: 1vh;
    }
  }
}

.login-section {

  // background-color: #FAFAFA;
}
.btn {
  margin: 16px;
  background-color: @base-color;
  text-align: center;
  color: #713610;
  font-size: 2.25vh;
  padding: 1.5vh;
  border-radius: 5px;
}
</style>