• 第三方登录功能的实现之 QQ登录 - 未绑定


    目录

    QQ登录 - 未绑定 - 有账号

    获取QQ头像和昵称

    表单校验

    发送验证码

    QQ绑定完成

    QQ登录 - 未绑定 - 无账号


    QQ登录 - 未绑定 - 有账号

    如果账号是绑定的状态,手动调用一下解绑接口

    http://pcapi-xiaotuxian-front.itheima.net/login/social/unbind?mobile=手机号

    https://apipc-xiaotuxian-front.itheima.net/login/social/unbind?mobile=手机号

    获取QQ头像和昵称

    如果QQ没绑定过账号,需要绑定已存在的账号或者注册新的账号

    (1)获取QQ信息

    (2)提供数据类型

    1. // QQ信息-用户详情
    2. export interface QQUserInfo {
    3. ret: number
    4. msg: string
    5. is_lost: number
    6. nickname: string
    7. gender: string
    8. gender_type: number
    9. province: string
    10. city: string
    11. year: string
    12. constellation: string
    13. figureurl: string
    14. figureurl_1: string
    15. figureurl_2: string
    16. figureurl_qq_1: string
    17. figureurl_qq_2: string
    18. figureurl_qq: string
    19. figureurl_type: string
    20. is_yellow_vip: string
    21. vip: string
    22. yellow_vip_level: string
    23. level: string
    24. is_yellow_year_vip: string
    25. }
    26. // QQ返回信息
    27. export interface QQUserInfoRes {
    28. status: string
    29. fmt: string
    30. ret: number
    31. code: number
    32. data: QQUserInfo
    33. seq: string
    34. dataText: string
    35. }

     (3)渲染QQ信息 

    1. class="user-info">
    2. <img :src="qqInfo.figureurl_2" alt="" />
    3. <p>
    4. Hi,{{ qqInfo.nickname }}
    5. 欢迎来小兔鲜,完成绑定后可以QQ账号一键登录哦~
    6. p>
  • 表单校验

    (1)提取校验规则 src/utils/validate.ts

    1. export function accountRule(value: string) {
    2. // value是将来使用该规则的表单元素的值
    3. // 1. 必填
    4. // 2. 6-20个字符,需要以字母开头
    5. // 如何反馈校验成功还是失败,返回true才是成功,其他情况失败,返回失败原因。
    6. if (!value) return '请输入用户名'
    7. if (!/^[a-zA-Z]\w{5,19}$/.test(value)) return '字母开头且6-20个字符'
    8. return true
    9. }
    10. export function passwordRule(value: string) {
    11. if (!value) return '请输入密码'
    12. if (!/^\w{6,24}$/.test(value)) return '密码是6-24个字符'
    13. return true
    14. }
    15. export function mobileRule(value: string) {
    16. if (!value) return '请输入手机号'
    17. if (!/^1[3-9]\d{9}$/.test(value)) return '手机号格式错误'
    18. return true
    19. }
    20. export function codeRule(value: string) {
    21. if (!value) return '请输入验证码'
    22. if (!/^\d{6}$/.test(value)) return '验证码是6个数字'
    23. return true
    24. }
    25. export function isAgreeRule(value: string) {
    26. if (!value) return '请勾选同意用户协议'
    27. return true
    28. }

    (2)修改登录功能

    1. import {
    2. accountRule,
    3. mobileRule,
    4. codeRule,
    5. passwordRule,
    6. isAgreeRule
    7. } from '@/utils/validate'
    8. useForm({
    9. validationSchema: {
    10. account: accountRule,
    11. mobile: mobileRule,
    12. code: codeRule,
    13. password: passwordRule,
    14. isAgree: isAgreeRule
    15. },
    16. initialValues: {
    17. mobile: '13666666666',
    18. code: '123456',
    19. account: 'xiaotuxian001',
    20. password: '123456',
    21. isAgree: true
    22. }
    23. })

    (3)在 CallbackBind.vue添加表单校验

    1. // 表单校验
    2. const { validate } = useForm({
    3. validationSchema: {
    4. mobile: mobileRule,
    5. code: codeRule
    6. }
    7. })
    8. const { value: mobile, errorMessage: mobileError } = useField('mobile')
    9. const { value: code, errorMessage: codeError } = useField('code')
    10. class="xtx-form-item">
    11. <div class="field">
    12. <i class="icon iconfont icon-phone">i>
    13. <input
    14. class="input"
    15. v-model="mobile"
    16. type="text"
    17. placeholder="绑定的手机号"
    18. />
    19. div>
    20. <div class="error">{{ mobileError }}div>
  • <div class="xtx-form-item">
  • <div class="field">
  • <i class="icon iconfont icon-code">i>
  • <input
  • v-model="code"
  • class="input"
  • type="text"
  • placeholder="短信验证码"
  • />
  • <span class="code">发送验证码span>
  • div>
  • <div class="error">{{ codeError }}div>
  • div>
  • (4)绑定时完成表单校验

    1. const bind = async () => {
    2. const res = await validate()
    3. if (!res.valid) return
    4. // 如果校验,发送请求进行绑定
    5. }

    发送验证码

     (1)提供actions,用于获取短信绑定QQ

    1. // 绑定qq的短信验证码
    2. async sendQQBindMsg(mobile: string) {
    3. await request.get('/login/social/code', {
    4. params: {
    5. mobile
    6. }
    7. })
    8. }

    (2)点击获取短信验证码时,发送请求获取验证码 

    1. const { time, start } = useCountDown()
    2. const send = async () => {
    3. if (time.value > 0) return
    4. const res = await validateMobile()
    5. console.log(res)
    6. if (!res.valid) return
    7. // 发送请求绑定qq
    8. await user.sendQQBindMsg(mobile.value)
    9. // 开启倒计时
    10. start(10)
    11. }

    (3)渲染倒计时

    1. <span class="code" @click="send">
    2. {{ time === 0 ? '发送验证码' : `${time}s后发送` }}
    3. </span>

    QQ绑定完成

    (1)提供绑定的actions 

    1. async qqBindLogin(openId: string, mobile: string, code: string) {
    2. const res = await request.post<ApiRes<Profile>>('/login/social/bind', {
    3. mobile,
    4. code,
    5. unionId: openId
    6. })
    7. // 1. 保存用户信息到 state 中
    8. this.profile = res.data.result
    9. setProfile(res.data.result)
    10. },

    (2)验证后,发送请求绑定

    1. // 1. 判断QQ是否登录
    2. if (QC.Login.check()) {
    3. // 2. 获取QQ用户信息
    4. QC.api('get_user_info').success((res: QQUserInfoRes) => {
    5. console.log(res)
    6. qqInfo.value = res.data
    7. })
    8. // 3. 获取openId
    9. QC.Login.getMe((id) => {
    10. openId = id
    11. })
    12. }
    13. const bind = async () => {
    14. const res = await validForm()
    15. if (!res.valid) return
    16. // 如果校验,发送请求进行绑定
    17. await user.qqBindLogin(openId, mobile.value, code.value)
    18. Message.success('QQ绑定成功')
    19. router.push('/')
    20. }

    QQ登录 - 未绑定 - 无账号

    (1)增加校验类型

    1. export function rePasswordRule(value: string, { form }: any) {
    2. if (!value) return '请输入确认密码'
    3. if (!/^\w{6,24}$/.test(value)) return '密码是6-24个字符'
    4. // 校验密码是否一致 form表单数据对象
    5. if (value !== form.password) return '两次输入的密码不一致'
    6. return true
    7. }

    (2)提供两个actions

    1. async sendQQPathMsg(mobile: string) {
    2. await request.get('/register/code', {
    3. params: {
    4. mobile
    5. }
    6. })
    7. },
    8. async qqPatchLogin(data: any) {
    9. const res = await request.post<ApiRes<Profile>>(
    10. `/login/social/${data.openId}/complement`,
    11. data
    12. )
    13. // 1. 保存用户信息到 state 中
    14. this.profile = res.data.result
    15. setProfile(res.data.result)
    16. }

    (3)完整代码

    1. <template>
    2. <div class="xtx-form">
    3. <div class="xtx-form-item">
    4. <div class="field">
    5. <i class="icon iconfont icon-user">i>
    6. <input
    7. class="input"
    8. v-model="account"
    9. type="text"
    10. placeholder="请输入用户名"
    11. />
    12. div>
    13. <div class="error">{{ accountError }}div>
    14. div>
    15. <div class="xtx-form-item">
    16. <div class="field">
    17. <i class="icon iconfont icon-phone">i>
    18. <input
    19. class="input"
    20. v-model="mobile"
    21. type="text"
    22. placeholder="请输入手机号"
    23. />
    24. div>
    25. <div class="error">{{ mobileError }}div>
    26. div>
    27. <div class="xtx-form-item">
    28. <div class="field">
    29. <i class="icon iconfont icon-code">i>
    30. <input
    31. class="input"
    32. v-model="code"
    33. type="text"
    34. placeholder="请输入验证码"
    35. />
    36. <span class="code" @click="send">{{
    37. time === 0 ? '发送验证码' : `${time}s后发送`
    38. }}span>
    39. div>
    40. <div class="error">{{ codeError }}div>
    41. div>
    42. <div class="xtx-form-item">
    43. <div class="field">
    44. <i class="icon iconfont icon-lock">i>
    45. <input
    46. class="input"
    47. v-model="password"
    48. type="password"
    49. placeholder="请输入密码"
    50. />
    51. div>
    52. <div class="error">{{ passwordError }}div>
    53. div>
    54. <div class="xtx-form-item">
    55. <div class="field">
    56. <i class="icon iconfont icon-lock">i>
    57. <input
    58. class="input"
    59. v-model="repassword"
    60. type="password"
    61. placeholder="请确认密码"
    62. />
    63. div>
    64. <div class="error">{{ repasswordError }}div>
    65. div>
    66. <a href="javascript:;" class="submit" @click="bind">立即提交a>
    67. div>
    68. template>
    69. <style scoped lang="less">
    70. .code {
    71. position: absolute;
    72. right: 0;
    73. top: 0;
    74. line-height: 50px;
    75. width: 80px;
    76. color: #999;
    77. &:hover {
    78. cursor: pointer;
    79. }
    80. }
    81. style>

  • 相关阅读:
    【电工基础】电路的基本概念与基本定律
    【android 9】【input】【9.发送按键事件3——Inputchannel的创建过程】
    mulesoft Module 6 quiz 解析
    How to code like a pro in 2022 and avoid If-Else
    2022锦江行——非繁城品:疫情之下,存量酒店的突围之道
    基于角度敏感的空间注意力机制的轻量型旋转目标检测器
    Linux|如何查找和删除重复文件
    armbian安装gcc、g++
    4.0 SDK Workshop 纪实:一起体验多人、多屏幕共享新功能
    【LeetCode题目详解】第九章 动态规划part09 198.打家劫舍 213.打家劫舍II 337.打家劫舍III(day48补)
  • 原文地址:https://blog.csdn.net/LJM51200/article/details/126560577