feat: 迁移商务登录品牌和三步找回密码
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import service from '@/utils/request'
|
||||
|
||||
const request = (action, data) => service({ url: `/sw/auth/forgot-password/${action}`, method: 'post', data, donNotShowLoading: true })
|
||||
export const forgotPasswordCheck = (username) => request('check', { username })
|
||||
export const forgotPasswordSendCode = (username) => request('send-code', { username })
|
||||
export const forgotPasswordVerifyCode = (username, smsCode) => request('verify-code', { username, smsCode })
|
||||
export const forgotPasswordReset = (data) => request('reset', data)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 773 KiB |
@@ -2,7 +2,7 @@
|
||||
<div
|
||||
class="kra-bottom-info flex flex-col md:flex-row gap-2 items-center text-sm text-slate-700 dark:text-slate-500 justify-center py-2"
|
||||
>
|
||||
<div class="text-center font-bold text-active">Kra</div>
|
||||
<div class="text-center font-bold text-active">{{ $KRA.appName }}</div>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -17,8 +17,8 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const darkLogoPath = '/logo.svg'
|
||||
const lightLogoPath = '/logo.svg'
|
||||
const darkLogoPath = '/business-logo.png'
|
||||
const lightLogoPath = '/business-logo.png'
|
||||
|
||||
const themeStore = useThemeStore();
|
||||
const { isDark } = storeToRefs(themeStore);
|
||||
@@ -60,10 +60,10 @@ watchEffect(async (onCleanup) => {
|
||||
// 到这里就包没有提供两种 logo 了
|
||||
showTextPlaceholder.value = true;
|
||||
console.error(
|
||||
'错误: 在公共目录中找不到 logo.svg。'
|
||||
'错误: 在公共目录中找不到 business-logo.png。'
|
||||
);
|
||||
console.warn(
|
||||
'解决方案: 请在 public 目录中放置 logo.svg。'
|
||||
'解决方案: 请在 public 目录中放置 business-logo.png。'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -81,15 +81,12 @@ function getSize() {
|
||||
<img v-if="!showTextPlaceholder && logoSrc" :src="logoSrc" :alt="$KRA.appName" class="object-contain"
|
||||
:style="{
|
||||
...getSize()
|
||||
}" :class="{
|
||||
'filter invert-[90%] hue-rotate-180 brightness-110':
|
||||
effectiveDark && logoSrc === '/logo.svg',
|
||||
}" />
|
||||
<div v-else-if="showTextPlaceholder"
|
||||
class="rounded-full bg-gray-300 dark:bg-gray-600 flex items-center justify-center text-gray-700 dark:text-gray-200 font-bold text-xs"
|
||||
:style="{
|
||||
...getSize()
|
||||
}">
|
||||
KRA
|
||||
商务
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
const greenText = (text) => `\x1b[32m${text}\x1b[0m`
|
||||
|
||||
export const config = {
|
||||
appName: 'Kra',
|
||||
appName: '遨游龙翔游戏平台',
|
||||
showViteLogo: true,
|
||||
keepAliveTabs: false,
|
||||
logs: []
|
||||
|
||||
+956
-261
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,143 @@
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useUserStore } from '@/pinia/modules/user'
|
||||
import { captcha } from '@/api/user'
|
||||
import { forgotPasswordCheck, forgotPasswordSendCode, forgotPasswordVerifyCode, forgotPasswordReset } from '@/api/businessPassword'
|
||||
|
||||
export function useBusinessLogin() {
|
||||
const title = '遨游龙翔游戏平台'
|
||||
const currentYear = new Date().getFullYear()
|
||||
const featureList = [
|
||||
{ text: '实时渠道充值与注册趋势看板', icon: 'trend' },
|
||||
{ text: '多级商务层级与游戏 SDK 绑定管理', icon: 'user' },
|
||||
{ text: '智能预警规则与风险监控', icon: 'shield' }
|
||||
]
|
||||
const userStore = useUserStore()
|
||||
const accountKey = 'biz_login_account'
|
||||
let saved = window.localStorage.getItem(accountKey) || ''
|
||||
try { const parsed = JSON.parse(saved); if (typeof parsed === 'string') saved = parsed; else if (parsed && typeof parsed === 'object') saved = parsed.username || '' } catch { /* 兼容旧版直接保存账号字符串 */ }
|
||||
const loginForm = ref({ username: saved, password: '', code: '', rememberMe: Boolean(saved) })
|
||||
const loginRef = ref()
|
||||
const loading = ref(false)
|
||||
const passwordReadonly = ref(true)
|
||||
const captchaEnabled = ref(false)
|
||||
const captchaId = ref('')
|
||||
const captchaLength = ref(6)
|
||||
const codeUrl = ref('')
|
||||
const loginRules = {
|
||||
username: [{ required: true, message: '请输入商务账号', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '请输入登录密码', trigger: 'blur' }],
|
||||
code: [{ validator: (_rule, value, callback) => {
|
||||
if (captchaEnabled.value && !new RegExp(`^\\d{${captchaLength.value}}$`).test(value || '')) callback(new Error('请输入正确的验证码'))
|
||||
else callback()
|
||||
}, trigger: 'blur' }]
|
||||
}
|
||||
const getCode = async () => {
|
||||
const res = await captcha()
|
||||
if (res.code !== 0) return
|
||||
captchaEnabled.value = Boolean(res.data.openCaptcha)
|
||||
captchaId.value = res.data.captchaId
|
||||
captchaLength.value = Number(res.data.captchaLength) || 6
|
||||
codeUrl.value = res.data.picPath
|
||||
loginForm.value.code = ''
|
||||
}
|
||||
const valid = async (form) => Boolean(await form.value?.validate().catch(() => false))
|
||||
const handleLogin = async () => {
|
||||
if (loading.value || !await valid(loginRef)) return
|
||||
loading.value = true
|
||||
try {
|
||||
const success = await userStore.LoginIn({ username: loginForm.value.username.trim(), password: loginForm.value.password, captcha: loginForm.value.code, captchaId: captchaId.value })
|
||||
if (success) {
|
||||
if (loginForm.value.rememberMe) window.localStorage.setItem(accountKey, loginForm.value.username.trim())
|
||||
else window.localStorage.removeItem(accountKey)
|
||||
} else await getCode()
|
||||
} finally { loading.value = false }
|
||||
}
|
||||
|
||||
const forgotPasswordVisible = ref(false)
|
||||
const forgotPasswordStep = ref('account')
|
||||
const forgotAccountRef = ref()
|
||||
const forgotSmsRef = ref()
|
||||
const forgotResetRef = ref()
|
||||
const forgotPasswordForm = ref({ username: '', smsCode: '', newPassword: '', confirmPassword: '' })
|
||||
const forgotAccountError = ref('')
|
||||
const forgotMaskedPhone = ref('')
|
||||
const forgotResetToken = ref('')
|
||||
const forgotSubmitting = ref(false)
|
||||
const smsCountdown = ref(0)
|
||||
let smsTimer
|
||||
const forgotAccountRules = { username: [{ required: true, message: '请输入您注册的商务账号', trigger: 'blur' }] }
|
||||
const forgotSmsRules = { smsCode: [{ required: true, message: '请输入短信验证码', trigger: 'blur' }, { pattern: /^\d{6}$/, message: '请输入 6 位数字验证码', trigger: 'blur' }] }
|
||||
const forgotResetRules = {
|
||||
newPassword: [{ required: true, message: '请输入新密码', trigger: 'blur' }, { min: 6, max: 15, message: '密码长度为 6-15 位字符', trigger: 'blur' }],
|
||||
confirmPassword: [{ required: true, message: '请再次输入新密码', trigger: 'blur' }, { validator: (_rule, value, callback) => {
|
||||
if (value !== forgotPasswordForm.value.newPassword) callback(new Error('两次输入的密码不一致'))
|
||||
else callback()
|
||||
}, trigger: 'blur' }]
|
||||
}
|
||||
const clearSmsTimer = () => { clearInterval(smsTimer); smsTimer = undefined; smsCountdown.value = 0 }
|
||||
const handleForgotPasswordClosed = () => {
|
||||
clearSmsTimer()
|
||||
forgotPasswordStep.value = 'account'
|
||||
forgotPasswordForm.value = { username: '', smsCode: '', newPassword: '', confirmPassword: '' }
|
||||
forgotResetToken.value = ''
|
||||
forgotMaskedPhone.value = ''
|
||||
forgotAccountError.value = ''
|
||||
forgotSubmitting.value = false
|
||||
}
|
||||
const handleOpenForgotPassword = () => {
|
||||
handleForgotPasswordClosed()
|
||||
forgotPasswordForm.value.username = loginForm.value.username
|
||||
forgotPasswordVisible.value = true
|
||||
}
|
||||
const requestSendCode = async () => {
|
||||
const res = await forgotPasswordSendCode(forgotPasswordForm.value.username.trim())
|
||||
if (res.code !== 0) return false
|
||||
forgotMaskedPhone.value = res.data.maskedPhone
|
||||
clearSmsTimer()
|
||||
const deadline = Date.now() + 60000
|
||||
smsCountdown.value = 60
|
||||
smsTimer = setInterval(() => { smsCountdown.value = Math.max(0, Math.ceil((deadline - Date.now()) / 1000)); if (!smsCountdown.value) clearSmsTimer() }, 1000)
|
||||
ElMessage.success(`验证码已发送至 ${forgotMaskedPhone.value}`)
|
||||
return true
|
||||
}
|
||||
const handleForgotAccountNext = async () => {
|
||||
if (forgotSubmitting.value || !await valid(forgotAccountRef)) return
|
||||
forgotSubmitting.value = true
|
||||
try {
|
||||
const res = await forgotPasswordCheck(forgotPasswordForm.value.username.trim())
|
||||
if (res.code !== 0) { forgotAccountError.value = res.msg; return }
|
||||
forgotMaskedPhone.value = res.data.maskedPhone
|
||||
if (await requestSendCode()) forgotPasswordStep.value = 'sms'
|
||||
} finally { forgotSubmitting.value = false }
|
||||
}
|
||||
const handleSendSmsCode = async () => {
|
||||
if (forgotSubmitting.value || smsCountdown.value > 0) return
|
||||
forgotSubmitting.value = true
|
||||
try { await requestSendCode() } finally { forgotSubmitting.value = false }
|
||||
}
|
||||
const handleForgotSmsNext = async () => {
|
||||
if (forgotSubmitting.value || !await valid(forgotSmsRef)) return
|
||||
forgotSubmitting.value = true
|
||||
try {
|
||||
const res = await forgotPasswordVerifyCode(forgotPasswordForm.value.username.trim(), forgotPasswordForm.value.smsCode)
|
||||
if (res.code === 0) { forgotResetToken.value = res.data.resetToken; forgotPasswordStep.value = 'reset' }
|
||||
} finally { forgotSubmitting.value = false }
|
||||
}
|
||||
const handleForgotResetSubmit = async () => {
|
||||
if (forgotSubmitting.value || !await valid(forgotResetRef)) return
|
||||
forgotSubmitting.value = true
|
||||
try {
|
||||
const res = await forgotPasswordReset({ resetToken: forgotResetToken.value, newPassword: forgotPasswordForm.value.newPassword, confirmPassword: forgotPasswordForm.value.confirmPassword })
|
||||
if (res.code === 0) { ElMessage.success('密码重置成功,请使用新密码登录'); loginForm.value.username = forgotPasswordForm.value.username; loginForm.value.password = ''; forgotPasswordVisible.value = false }
|
||||
} finally { forgotSubmitting.value = false }
|
||||
}
|
||||
onMounted(getCode)
|
||||
onBeforeUnmount(clearSmsTimer)
|
||||
return {
|
||||
title, currentYear, featureList, loginRef, loginForm, loginRules, loading, passwordReadonly, captchaEnabled, codeUrl, getCode, handleLogin,
|
||||
forgotPasswordVisible, forgotPasswordStep, forgotAccountRef, forgotSmsRef, forgotResetRef, forgotPasswordForm, forgotAccountError, forgotMaskedPhone,
|
||||
forgotSubmitting, smsCountdown, forgotAccountRules, forgotSmsRules, forgotResetRules, handleOpenForgotPassword, handleForgotPasswordClosed,
|
||||
handleForgotAccountNext, handleSendSmsCode, handleForgotSmsNext, handleForgotResetSubmit
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user