swagger 推广后台 优化对战百佳历史接口
This commit is contained in:
@@ -1,14 +1,10 @@
|
||||
import request from '@/axios'
|
||||
import type { RegisterUserType, SmsLoginType, UserLoginType, UserType } from './types'
|
||||
import type { RegisterUserType, SmsLoginType, UserType } from './types'
|
||||
|
||||
interface RoleParams {
|
||||
roleName: string
|
||||
}
|
||||
|
||||
export const loginApi = (data: UserLoginType): Promise<IResponse<UserType>> => {
|
||||
return request.post({ url: '/promo/login', data })
|
||||
}
|
||||
|
||||
export const smsLoginApi = (data: SmsLoginType): Promise<IResponse<UserType>> => {
|
||||
return request.post({ url: '/promo/smsLogin', data })
|
||||
}
|
||||
@@ -34,6 +30,20 @@ export const getCodeApi = (
|
||||
})
|
||||
}
|
||||
|
||||
/** 点「获取验证码」时的账号前置校验:无推广后台权限的号在这一步就被拒绝,不用先拖滑块 */
|
||||
export const precheckPhoneApi = (
|
||||
phoneNumber: string,
|
||||
parentInvitationCode?: string
|
||||
): Promise<IResponse<UserType>> => {
|
||||
return request.post({
|
||||
url: '/promo/sms/precheck',
|
||||
data: {
|
||||
phoneNumber: phoneNumber,
|
||||
parentInvitationCode
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const loginOutApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: '/mock/user/loginOut' })
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="tsx">
|
||||
import { getAdminRoleApi, getCodeApi, smsLoginApi } from '@/api/login'
|
||||
import { getAdminRoleApi, getCodeApi, precheckPhoneApi, smsLoginApi } from '@/api/login'
|
||||
import type { SmsLoginType, UserType } from '@/api/login/types'
|
||||
import { getMyMenus } from '@/api/permission'
|
||||
import { PATH_URL } from '@/axios/service'
|
||||
@@ -35,6 +35,7 @@ const loading = ref(false)
|
||||
const redirect = ref('')
|
||||
const getCodeTime = ref(60)
|
||||
const getCodeLoading = ref(false)
|
||||
const captchaCode = ref('')
|
||||
let tacInstance: any = null
|
||||
let codeTimer: ReturnType<typeof setInterval> | undefined
|
||||
|
||||
@@ -107,8 +108,17 @@ const schema = reactive<FormSchema[]>([
|
||||
if (event.key === 'Enter') signIn()
|
||||
}}
|
||||
/>
|
||||
<ElButton class="login-code-btn" disabled={unref(getCodeLoading)} onClick={getCode}>
|
||||
{unref(getCodeLoading) ? `${unref(getCodeTime)}s` : '获取验证码'}
|
||||
<ElButton
|
||||
class="login-code-btn"
|
||||
disabled={unref(getCodeLoading)}
|
||||
loading={unref(getCodeLoading) && !unref(captchaCode)}
|
||||
onClick={getCode}
|
||||
>
|
||||
{unref(getCodeLoading)
|
||||
? unref(captchaCode)
|
||||
? `${unref(getCodeTime)}s`
|
||||
: '发送中'
|
||||
: '获取验证码'}
|
||||
</ElButton>
|
||||
</div>
|
||||
)
|
||||
@@ -165,6 +175,32 @@ onBeforeUnmount(() => {
|
||||
if (codeTimer) clearInterval(codeTimer)
|
||||
})
|
||||
|
||||
// 点下按钮就开始倒计时:短信网关往返通常 1~3 秒,等接口返回再倒计时会像卡死
|
||||
const startCountdown = () => {
|
||||
if (codeTimer) clearInterval(codeTimer)
|
||||
captchaCode.value = ''
|
||||
getCodeTime.value = 60
|
||||
getCodeLoading.value = true
|
||||
codeTimer = setInterval(() => {
|
||||
getCodeTime.value--
|
||||
if (getCodeTime.value <= 0) {
|
||||
clearInterval(codeTimer)
|
||||
codeTimer = undefined
|
||||
getCodeTime.value = 60
|
||||
getCodeLoading.value = false
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 发送失败(限流/验证码失效/发送异常):解禁按钮,让用户能立刻重试
|
||||
const resetCountdown = () => {
|
||||
if (codeTimer) clearInterval(codeTimer)
|
||||
codeTimer = undefined
|
||||
getCodeTime.value = 60
|
||||
getCodeLoading.value = false
|
||||
captchaCode.value = ''
|
||||
}
|
||||
|
||||
const getCode = async () => {
|
||||
if (getCodeLoading.value) return
|
||||
const { username, parentInvitationCode } = await getFormData<SmsLoginType>()
|
||||
@@ -172,6 +208,10 @@ const getCode = async () => {
|
||||
ElMessage.error('请输入正确的手机号')
|
||||
return
|
||||
}
|
||||
// 先验账号再弹滑块:不是推广后台用户(与后台账号校验同一份规则)直接拒绝,
|
||||
// 避免用户白拖一次滑块才被告知没权限;接口失败/被限流时放行走原流程,发送时后端还会再验一次
|
||||
const phoneCheck = await precheckPhoneApi(username, parentInvitationCode).catch(() => null)
|
||||
if (!phoneCheck) return
|
||||
if (typeof window.TAC === 'undefined' || typeof window.CaptchaConfig === 'undefined') {
|
||||
ElMessage.error('滑块验证码未加载,请刷新页面')
|
||||
return
|
||||
@@ -187,19 +227,18 @@ const getCode = async () => {
|
||||
validSuccess: (_res: unknown, _config: unknown, tac: any) => {
|
||||
tac.destroyWindow()
|
||||
tacInstance = null
|
||||
getCodeApi(username, captchaId, '2', parentInvitationCode).then(() => {
|
||||
ElMessage.success('验证码已发送')
|
||||
getCodeLoading.value = true
|
||||
codeTimer = setInterval(() => {
|
||||
getCodeTime.value--
|
||||
if (getCodeTime.value <= 0) {
|
||||
clearInterval(codeTimer)
|
||||
codeTimer = undefined
|
||||
getCodeTime.value = 60
|
||||
getCodeLoading.value = false
|
||||
startCountdown()
|
||||
getCodeApi(username, captchaId, '2', parentInvitationCode)
|
||||
.then((res: any) => {
|
||||
// 业务失败(限流/验证码失效)响应拦截器已弹过错误提示,这里只释放倒计时
|
||||
if (res?.code !== 0 && res?.code !== 200) {
|
||||
resetCountdown()
|
||||
return
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
captchaCode.value = captchaId
|
||||
ElMessage.success('验证码已发送')
|
||||
})
|
||||
.catch(() => resetCountdown())
|
||||
},
|
||||
validFail: (_res: unknown, _config: unknown, tac: any) => {
|
||||
ElMessage.error('滑块验证失败,请重试')
|
||||
|
||||
@@ -10,7 +10,7 @@ import { RegisterUserType } from '@/api/login/types'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { completeLogin } from '../completeLogin'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { registerApi, getCodeApi } from '@/api/login'
|
||||
import { registerApi, getCodeApi, precheckPhoneApi } from '@/api/login'
|
||||
import { PATH_URL } from '@/axios/service'
|
||||
|
||||
declare global {
|
||||
@@ -38,12 +38,38 @@ const { required } = useValidator()
|
||||
const getCodeTime = ref(60)
|
||||
const getCodeLoading = ref(false)
|
||||
let tacInstance: any = null
|
||||
let codeTimer: ReturnType<typeof setInterval> | undefined
|
||||
|
||||
// 点下按钮就开始倒计时:短信网关往返通常 1~3 秒,等接口返回再倒计时会像卡死
|
||||
const startCountdown = () => {
|
||||
if (codeTimer) clearInterval(codeTimer)
|
||||
getCodeTime.value = 60
|
||||
getCodeLoading.value = true
|
||||
codeTimer = setInterval(() => {
|
||||
getCodeTime.value--
|
||||
if (getCodeTime.value <= 0) {
|
||||
clearInterval(codeTimer)
|
||||
codeTimer = undefined
|
||||
getCodeTime.value = 60
|
||||
getCodeLoading.value = false
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 发送失败(限流/验证码失效/发送异常):解禁按钮,让用户能立刻重试
|
||||
const resetCountdown = () => {
|
||||
if (codeTimer) clearInterval(codeTimer)
|
||||
codeTimer = undefined
|
||||
getCodeTime.value = 60
|
||||
getCodeLoading.value = false
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (tacInstance) {
|
||||
tacInstance.destroyWindow()
|
||||
tacInstance = null
|
||||
}
|
||||
if (codeTimer) clearInterval(codeTimer)
|
||||
})
|
||||
|
||||
const getCode = async () => {
|
||||
@@ -52,6 +78,12 @@ const getCode = async () => {
|
||||
ElMessage.error('手机号不能为空')
|
||||
return
|
||||
}
|
||||
// 先验账号再弹滑块,与登录页同一份规则(注册页无账号时靠招商邀请码放行);接口失败/被限流时放行走原流程
|
||||
const phoneCheck = await precheckPhoneApi(
|
||||
formData.username,
|
||||
(formData as any).parentInvitationCode
|
||||
).catch(() => null)
|
||||
if (!phoneCheck) return
|
||||
|
||||
// 判断TAC是否加载
|
||||
if (typeof window.TAC === 'undefined' || typeof window.CaptchaConfig === 'undefined') {
|
||||
@@ -71,23 +103,18 @@ const getCode = async () => {
|
||||
tac.destroyWindow()
|
||||
tacInstance = null
|
||||
const captchaId = window._captchaId
|
||||
// 滑块验证成功,发送短信验证码
|
||||
// 滑块验证成功,立刻进入倒计时,再等短信接口返回
|
||||
startCountdown()
|
||||
getCodeApi(formData.username, captchaId)
|
||||
.then(() => {
|
||||
.then((res: any) => {
|
||||
// 业务失败(限流/验证码失效)响应拦截器已弹过错误提示,这里只释放倒计时
|
||||
if (res?.code !== 0 && res?.code !== 200) {
|
||||
resetCountdown()
|
||||
return
|
||||
}
|
||||
ElMessage.success('获取验证码成功')
|
||||
getCodeLoading.value = true
|
||||
const timer = setInterval(() => {
|
||||
getCodeTime.value--
|
||||
if (getCodeTime.value <= 0) {
|
||||
clearInterval(timer)
|
||||
getCodeTime.value = 60
|
||||
getCodeLoading.value = false
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage.error('获取验证码失败')
|
||||
})
|
||||
.catch(() => resetCountdown())
|
||||
},
|
||||
validFail: (res: any, c: any, tac: any) => {
|
||||
ElMessage.error('滑块验证失败,请重试')
|
||||
|
||||
@@ -255,12 +255,15 @@
|
||||
<ElTableColumn prop="id" label="ID" width="60" />
|
||||
<ElTableColumn prop="templateName" label="模板名称" min-width="150" />
|
||||
<ElTableColumn prop="ornamentCount" label="饰品数" width="80" />
|
||||
<ElTableColumn prop="createBy" label="创建人" width="100" />
|
||||
<ElTableColumn prop="createBy" label="创建人" width="100">
|
||||
<template #default="{ row }">{{ row.createBy || '其他主播' }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="createTime" label="创建时间" width="170" />
|
||||
<ElTableColumn label="操作" width="140">
|
||||
<template #default="{ row }">
|
||||
<ElButton type="primary" link size="small" @click="handleLoadTemplate(row)">加载</ElButton>
|
||||
<ElButton type="danger" link size="small" @click="handleDeleteTemplate(row.id)">删除</ElButton>
|
||||
<!-- 后端只允许创建者本人或超管删除;共享模板 createBy 会被置空,这里不给别人显示删除按钮 -->
|
||||
<ElButton v-if="row.createBy" type="danger" link size="small" @click="handleDeleteTemplate(row.id)">删除</ElButton>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
|
||||
Reference in New Issue
Block a user