目录
如果账号是绑定的状态,手动调用一下解绑接口
http://pcapi-xiaotuxian-front.itheima.net/login/social/unbind?mobile=手机号
https://apipc-xiaotuxian-front.itheima.net/login/social/unbind?mobile=手机号
如果QQ没绑定过账号,需要绑定已存在的账号或者注册新的账号
(1)获取QQ信息
(2)提供数据类型
- // QQ信息-用户详情
- export interface QQUserInfo {
- ret: number
- msg: string
- is_lost: number
- nickname: string
- gender: string
- gender_type: number
- province: string
- city: string
- year: string
- constellation: string
- figureurl: string
- figureurl_1: string
- figureurl_2: string
- figureurl_qq_1: string
- figureurl_qq_2: string
- figureurl_qq: string
- figureurl_type: string
- is_yellow_vip: string
- vip: string
- yellow_vip_level: string
- level: string
- is_yellow_year_vip: string
- }
- // QQ返回信息
- export interface QQUserInfoRes {
- status: string
- fmt: string
- ret: number
- code: number
- data: QQUserInfo
- seq: string
- dataText: string
- }
(3)渲染QQ信息
- class="user-info">
- <img :src="qqInfo.figureurl_2" alt="" />
- <p>
- Hi,{{ qqInfo.nickname }}
- 欢迎来小兔鲜,完成绑定后可以QQ账号一键登录哦~
- p>
(1)提取校验规则 src/utils/validate.ts
- export function accountRule(value: string) {
- // value是将来使用该规则的表单元素的值
- // 1. 必填
- // 2. 6-20个字符,需要以字母开头
- // 如何反馈校验成功还是失败,返回true才是成功,其他情况失败,返回失败原因。
- if (!value) return '请输入用户名'
- if (!/^[a-zA-Z]\w{5,19}$/.test(value)) return '字母开头且6-20个字符'
- return true
- }
- export function passwordRule(value: string) {
- if (!value) return '请输入密码'
- if (!/^\w{6,24}$/.test(value)) return '密码是6-24个字符'
- return true
- }
- export function mobileRule(value: string) {
- if (!value) return '请输入手机号'
- if (!/^1[3-9]\d{9}$/.test(value)) return '手机号格式错误'
- return true
- }
- export function codeRule(value: string) {
- if (!value) return '请输入验证码'
- if (!/^\d{6}$/.test(value)) return '验证码是6个数字'
- return true
- }
- export function isAgreeRule(value: string) {
- if (!value) return '请勾选同意用户协议'
- return true
- }
(2)修改登录功能
- import {
- accountRule,
- mobileRule,
- codeRule,
- passwordRule,
- isAgreeRule
- } from '@/utils/validate'
-
- useForm({
- validationSchema: {
- account: accountRule,
- mobile: mobileRule,
- code: codeRule,
- password: passwordRule,
- isAgree: isAgreeRule
- },
- initialValues: {
- mobile: '13666666666',
- code: '123456',
- account: 'xiaotuxian001',
- password: '123456',
- isAgree: true
- }
- })
(3)在 CallbackBind.vue添加表单校验
- // 表单校验
- const { validate } = useForm({
- validationSchema: {
- mobile: mobileRule,
- code: codeRule
- }
- })
- const { value: mobile, errorMessage: mobileError } = useField('mobile')
- const { value: code, errorMessage: codeError } = useField('code')
-
-
- class="xtx-form-item">
- <div class="field">
- <i class="icon iconfont icon-phone">i>
- <input
- class="input"
- v-model="mobile"
- type="text"
- placeholder="绑定的手机号"
- />
- div>
- <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)绑定时完成表单校验
-
-
- const bind = async () => {
- const res = await validate()
- if (!res.valid) return
- // 如果校验,发送请求进行绑定
- }
(1)提供actions,用于获取短信绑定QQ
- // 绑定qq的短信验证码
- async sendQQBindMsg(mobile: string) {
- await request.get('/login/social/code', {
- params: {
- mobile
- }
- })
- }
(2)点击获取短信验证码时,发送请求获取验证码
- const { time, start } = useCountDown()
- const send = async () => {
- if (time.value > 0) return
- const res = await validateMobile()
- console.log(res)
- if (!res.valid) return
- // 发送请求绑定qq
- await user.sendQQBindMsg(mobile.value)
- // 开启倒计时
- start(10)
- }
(3)渲染倒计时
- <span class="code" @click="send">
- {{ time === 0 ? '发送验证码' : `${time}s后发送` }}
- </span>
(1)提供绑定的actions
- async qqBindLogin(openId: string, mobile: string, code: string) {
- const res = await request.post<ApiRes<Profile>>('/login/social/bind', {
- mobile,
- code,
- unionId: openId
- })
- // 1. 保存用户信息到 state 中
- this.profile = res.data.result
- setProfile(res.data.result)
- },
(2)验证后,发送请求绑定
- // 1. 判断QQ是否登录
- if (QC.Login.check()) {
- // 2. 获取QQ用户信息
- QC.api('get_user_info').success((res: QQUserInfoRes) => {
- console.log(res)
- qqInfo.value = res.data
- })
- // 3. 获取openId
- QC.Login.getMe((id) => {
- openId = id
- })
- }
-
- const bind = async () => {
- const res = await validForm()
- if (!res.valid) return
- // 如果校验,发送请求进行绑定
- await user.qqBindLogin(openId, mobile.value, code.value)
- Message.success('QQ绑定成功')
- router.push('/')
- }
(1)增加校验类型
- export function rePasswordRule(value: string, { form }: any) {
- if (!value) return '请输入确认密码'
- if (!/^\w{6,24}$/.test(value)) return '密码是6-24个字符'
- // 校验密码是否一致 form表单数据对象
- if (value !== form.password) return '两次输入的密码不一致'
- return true
- }
(2)提供两个actions
- async sendQQPathMsg(mobile: string) {
- await request.get('/register/code', {
- params: {
- mobile
- }
- })
- },
-
- async qqPatchLogin(data: any) {
- const res = await request.post<ApiRes<Profile>>(
- `/login/social/${data.openId}/complement`,
- data
- )
- // 1. 保存用户信息到 state 中
- this.profile = res.data.result
- setProfile(res.data.result)
- }
(3)完整代码
- <template>
- <div class="xtx-form">
- <div class="xtx-form-item">
- <div class="field">
- <i class="icon iconfont icon-user">i>
- <input
- class="input"
- v-model="account"
- type="text"
- placeholder="请输入用户名"
- />
- div>
- <div class="error">{{ accountError }}div>
- div>
- <div class="xtx-form-item">
- <div class="field">
- <i class="icon iconfont icon-phone">i>
- <input
- class="input"
- v-model="mobile"
- type="text"
- placeholder="请输入手机号"
- />
- div>
- <div class="error">{{ mobileError }}div>
- div>
- <div class="xtx-form-item">
- <div class="field">
- <i class="icon iconfont icon-code">i>
- <input
- class="input"
- v-model="code"
- type="text"
- placeholder="请输入验证码"
- />
- <span class="code" @click="send">{{
- time === 0 ? '发送验证码' : `${time}s后发送`
- }}span>
- div>
- <div class="error">{{ codeError }}div>
- div>
- <div class="xtx-form-item">
- <div class="field">
- <i class="icon iconfont icon-lock">i>
- <input
- class="input"
- v-model="password"
- type="password"
- placeholder="请输入密码"
- />
- div>
- <div class="error">{{ passwordError }}div>
- div>
- <div class="xtx-form-item">
- <div class="field">
- <i class="icon iconfont icon-lock">i>
- <input
- class="input"
- v-model="repassword"
- type="password"
- placeholder="请确认密码"
- />
- div>
- <div class="error">{{ repasswordError }}div>
- div>
- <a href="javascript:;" class="submit" @click="bind">立即提交a>
- div>
- template>
-
- <style scoped lang="less">
- .code {
- position: absolute;
- right: 0;
- top: 0;
- line-height: 50px;
- width: 80px;
- color: #999;
- &:hover {
- cursor: pointer;
- }
- }
- style>