feat: add vue3(element-plus)

This commit is contained in:
xingyu
2022-07-18 19:06:37 +08:00
parent c6b58dca52
commit 80a3ae8d74
423 changed files with 41039 additions and 0 deletions

View File

@ -0,0 +1,281 @@
<script lang="ts" setup>
import { useIcon } from '@/hooks/web/useIcon'
import LoginFormTitle from './LoginFormTitle.vue'
import {
ElForm,
ElFormItem,
ElInput,
ElCheckbox,
ElCol,
ElLink,
ElRow,
ElDivider
} from 'element-plus'
import { reactive, ref, unref, onMounted, computed, watch } from 'vue'
import { getCodeImgApi, getTenantIdByNameApi, loginApi, getAsyncRoutesApi } from '@/api/login'
import { setToken } from '@/utils/auth'
import { useUserStoreWithOut } from '@/store/modules/user'
import { useCache } from '@/hooks/web/useCache'
import { usePermissionStore } from '@/store/modules/permission'
import { useRouter } from 'vue-router'
import { useI18n } from '@/hooks/web/useI18n'
import { required } from '@/utils/formRules'
import { Icon } from '@/components/Icon'
import { LoginStateEnum, useLoginState, useFormValid } from './useLogin'
import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
const { currentRoute, addRoute, push } = useRouter()
const permissionStore = usePermissionStore()
const userStore = useUserStoreWithOut()
const formLogin = ref()
const { validForm } = useFormValid(formLogin)
const { wsCache } = useCache()
const { setLoginState, getLoginState } = useLoginState()
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
const iconSize = 30
const iconColor = '#999'
const redirect = ref<string>('')
const { t } = useI18n()
const iconHouse = useIcon({ icon: 'ep:house' })
const iconAvatar = useIcon({ icon: 'ep:avatar' })
const iconLock = useIcon({ icon: 'ep:lock' })
const iconCircleCheck = useIcon({ icon: 'ep:circle-check' })
const remember = ref(false)
const LoginRules = {
tenantName: [required],
username: [required],
password: [required],
code: [required]
}
const loginLoading = ref(false)
const loginData = reactive({
codeImg: '',
isShowPassword: false,
captchaEnable: true,
tenantEnable: true,
token: '',
loading: {
signIn: false
},
loginForm: {
tenantName: '芋道源码',
username: 'admin',
password: 'admin123',
code: '',
uuid: ''
}
})
// 获取验证码
const getCode = async () => {
const res = await getCodeImgApi()
loginData.codeImg = 'data:image/gif;base64,' + res.img
loginData.loginForm.uuid = res.uuid
}
//获取租户ID
const getTenantId = async () => {
const res = await getTenantIdByNameApi(loginData.loginForm.tenantName)
wsCache.set('tenantId', res)
}
// 登录
const handleLogin = async () => {
await getTenantId()
const data = await validForm()
if (!data) return
loginLoading.value = true
await loginApi(loginData.loginForm)
.then(async (res) => {
setToken(res)
await userStore.getUserInfoAction()
await getRoutes()
})
.catch(() => {
getCode()
})
.finally(() => {
loginLoading.value = false
})
}
// 获取路由
const getRoutes = async () => {
// 后端过滤菜单
const routers = await getAsyncRoutesApi()
wsCache.set('roleRouters', routers)
await permissionStore.generateRoutes(routers).catch(() => {})
permissionStore.getAddRouters.forEach((route) => {
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
})
permissionStore.setIsAddRouters(true)
push({ path: redirect.value || permissionStore.addRouters[0].path })
}
watch(
() => currentRoute.value,
(route: RouteLocationNormalizedLoaded) => {
redirect.value = route?.query?.redirect as string
},
{
immediate: true
}
)
onMounted(() => {
getCode()
})
</script>
<template>
<el-form
:model="loginData.loginForm"
:rules="LoginRules"
label-position="top"
class="login-form"
label-width="120px"
size="large"
v-show="getShow"
ref="formLogin"
>
<el-row style="maring-left: -10px; maring-right: -10px">
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item>
<LoginFormTitle style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item prop="tenantName">
<el-input
type="text"
v-model="loginData.loginForm.tenantName"
:placeholder="t('login.tenantNamePlaceholder')"
:prefix-icon="iconHouse"
/>
</el-form-item>
</el-col>
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item prop="username">
<el-input
v-model="loginData.loginForm.username"
:placeholder="t('login.usernamePlaceholder')"
:prefix-icon="iconAvatar"
/>
</el-form-item>
</el-col>
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item prop="password">
<el-input
v-model="loginData.loginForm.password"
type="password"
:placeholder="t('login.password')"
show-password
@keyup.enter="handleLogin"
:prefix-icon="iconLock"
/>
</el-form-item>
</el-col>
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item prop="code">
<el-row justify="space-between" style="width: 100%">
<el-col :span="14">
<el-input
v-model="loginData.loginForm.code"
:placeholder="t('login.code')"
@keyup.enter="handleLogin"
:prefix-icon="iconCircleCheck"
style="width: 90%"
/>
</el-col>
<el-col :span="10">
<div class="login-code">
<img :src="loginData.codeImg" @click="getCode" class="login-code-img" alt="" />
</div>
</el-col>
</el-row>
</el-form-item>
</el-col>
<el-col
:span="24"
style="padding-left: 10px; padding-right: 10px; margin-top: -20px; margin-bottom: -20px"
>
<el-form-item>
<el-row justify="space-between" style="width: 100%">
<el-col :span="6">
<el-checkbox v-model="remember">{{ t('login.remember') }}</el-checkbox>
</el-col>
<el-col :span="12" :offset="6">
<el-link type="primary" style="float: right">{{ t('login.forgetPassword') }}</el-link>
</el-col>
</el-row>
</el-form-item>
</el-col>
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item>
<el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="handleLogin">{{
t('login.login')
}}</el-button>
</el-form-item>
</el-col>
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item>
<el-row justify="space-between" style="width: 100%" :gutter="5">
<el-col :span="8">
<el-button class="w-[100%]" @click="setLoginState(LoginStateEnum.MOBILE)">{{
t('login.btnMobile')
}}</el-button>
</el-col>
<el-col :span="8">
<el-button class="w-[100%]">{{ t('login.btnQRCode') }}</el-button>
</el-col>
<el-col :span="8">
<el-button class="w-[100%]">{{ t('login.btnRegister') }}</el-button>
</el-col>
</el-row>
</el-form-item>
</el-col>
<el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider>
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item>
<div class="flex justify-between w-[100%]">
<Icon
icon="ant-design:github-filled"
:size="iconSize"
class="cursor-pointer anticon"
:color="iconColor"
/>
<Icon
icon="ant-design:wechat-filled"
:size="iconSize"
class="cursor-pointer anticon"
:color="iconColor"
/>
<Icon
icon="ant-design:alipay-circle-filled"
:size="iconSize"
:color="iconColor"
class="cursor-pointer anticon"
/>
<Icon
icon="ant-design:weibo-circle-filled"
:size="iconSize"
:color="iconColor"
class="cursor-pointer anticon"
/>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<style lang="less" scoped>
.login-code {
width: 100%;
height: 38px;
float: right;
img {
cursor: pointer;
width: 100%;
max-width: 100px;
height: auto;
vertical-align: middle;
}
}
</style>

View File

@ -0,0 +1,279 @@
<script setup lang="ts">
import { reactive, ref, unref, watch, onMounted } from 'vue'
import { Form } from '@/components/Form'
import { useI18n } from '@/hooks/web/useI18n'
import { ElCheckbox, ElLink } from 'element-plus'
import { required } from '@/utils/formRules'
import { useForm } from '@/hooks/web/useForm'
import { getTenantIdByNameApi, getCodeImgApi, loginApi, getAsyncRoutesApi } from '@/api/login'
import { useCache } from '@/hooks/web/useCache'
import { usePermissionStore } from '@/store/modules/permission'
import { useRouter } from 'vue-router'
import { setToken } from '@/utils/auth'
import { useUserStoreWithOut } from '@/store/modules/user'
import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
import { UserLoginVO } from '@/api/login/types'
const { wsCache } = useCache()
const userStore = useUserStoreWithOut()
const permissionStore = usePermissionStore()
const { currentRoute, addRoute, push } = useRouter()
const { t } = useI18n()
const rules = {
tenantName: [required],
username: [required],
password: [required],
code: [required]
}
const loginData = reactive({
codeImg: '',
isShowPassword: false,
captchaEnable: true,
tenantEnable: true,
token: '',
loading: {
signIn: false
},
loginForm: {
tenantName: '芋道源码',
username: 'admin',
password: 'admin123',
code: '',
uuid: ''
}
})
const schema = reactive<FormSchema[]>([
{
field: 'title',
colProps: {
span: 24
}
},
{
field: 'tenantName',
label: t('login.tenantname'),
value: loginData.loginForm.tenantName,
component: 'Input',
colProps: {
span: 24
},
componentProps: {
placeholder: t('login.tenantNamePlaceholder')
}
},
{
field: 'username',
label: t('login.username'),
value: loginData.loginForm.username,
component: 'Input',
colProps: {
span: 24
},
componentProps: {
placeholder: t('login.usernamePlaceholder')
}
},
{
field: 'password',
label: t('login.password'),
value: loginData.loginForm.password,
component: 'InputPassword',
colProps: {
span: 24
},
componentProps: {
style: {
width: '100%'
},
placeholder: t('login.passwordPlaceholder')
}
},
{
field: 'code',
label: t('login.code'),
value: loginData.loginForm.code,
component: 'Input',
colProps: {
span: 12
},
componentProps: {
style: {
width: '100%'
},
placeholder: t('login.codePlaceholder')
}
},
{
field: 'codeImg',
colProps: {
span: 12
}
},
{
field: 'tool',
colProps: {
span: 24
}
},
{
field: 'login',
colProps: {
span: 24
}
},
{
field: 'other',
component: 'Divider',
label: t('login.otherLogin'),
componentProps: {
contentPosition: 'center'
}
},
{
field: 'otherIcon',
colProps: {
span: 24
}
}
])
const iconSize = 30
const remember = ref(false)
const { register, elFormRef, methods } = useForm()
const loading = ref(false)
const iconColor = '#999'
const redirect = ref<string>('')
watch(
() => currentRoute.value,
(route: RouteLocationNormalizedLoaded) => {
redirect.value = route?.query?.redirect as string
},
{
immediate: true
}
)
// 获取验证码
const getCode = async () => {
const res = await getCodeImgApi()
loginData.codeImg = 'data:image/gif;base64,' + res.img
loginData.loginForm.uuid = res.uuid
}
//获取租户ID
const getTenantId = async () => {
const res = await getTenantIdByNameApi(loginData.loginForm.tenantName)
wsCache.set('tenantId', res)
}
// 登录
const signIn = async () => {
await getTenantId()
const formRef = unref(elFormRef)
await formRef?.validate(async (isValid) => {
if (isValid) {
loading.value = true
const { getFormData } = methods
const formData = await getFormData<UserLoginVO>()
formData.uuid = loginData.loginForm.uuid
await loginApi(formData)
.then(async (res) => {
setToken(res)
getRoutes()
await userStore.getUserInfoAction()
})
.catch(() => {
getCode()
})
.finally(() => (loading.value = false))
}
})
}
// 获取路由
const getRoutes = async () => {
// 后端过滤菜单
const routers = await getAsyncRoutesApi()
wsCache.set('roleRouters', routers)
await permissionStore.generateRoutes(routers).catch(() => {})
permissionStore.getAddRouters.forEach((route) => {
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
})
permissionStore.setIsAddRouters(true)
push({ path: redirect.value || permissionStore.addRouters[0].path })
}
onMounted(() => {
getCode()
})
</script>
<template>
<Form
:schema="schema"
:rules="rules"
label-position="top"
hide-required-asterisk
size="large"
@register="register"
v-show="false"
>
<template #header>
<h2 class="text-2xl font-bold text-center w-[100%]">{{ t('login.login') }}</h2>
</template>
<template #codeImg>
<img :src="loginData.codeImg" @click="getCode" alt="" />
</template>
<template #tool>
<div class="flex justify-between items-center w-[100%]">
<ElCheckbox v-model="remember" :label="t('login.remember')" size="small" />
<ElLink type="primary" :underline="false">{{ t('login.forgetPassword') }}</ElLink>
</div>
</template>
<template #login>
<ElButton :loading="loading" type="primary" class="w-[100%]" @click="signIn">
{{ t('login.login') }}
</ElButton>
</template>
<template #otherIcon>
<div class="flex justify-between w-[100%]">
<Icon
icon="ant-design:github-filled"
:size="iconSize"
class="cursor-pointer anticon"
:color="iconColor"
/>
<Icon
icon="ant-design:wechat-filled"
:size="iconSize"
class="cursor-pointer anticon"
:color="iconColor"
/>
<Icon
icon="ant-design:alipay-circle-filled"
:size="iconSize"
:color="iconColor"
class="cursor-pointer anticon"
/>
<Icon
icon="ant-design:weibo-circle-filled"
:size="iconSize"
:color="iconColor"
class="cursor-pointer anticon"
/>
</div>
</template>
</Form>
</template>
<style lang="less" scoped>
:deep(.anticon) {
&:hover {
color: var(--el-color-primary) !important;
}
}
</style>

View File

@ -0,0 +1,25 @@
<script lang="ts" setup>
import { computed, unref } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { LoginStateEnum, useLoginState } from './useLogin'
const { t } = useI18n()
const { getLoginState } = useLoginState()
const getFormTitle = computed(() => {
const titleObj = {
[LoginStateEnum.RESET_PASSWORD]: t('sys.login.forgetFormTitle'),
[LoginStateEnum.LOGIN]: t('sys.login.signInFormTitle'),
[LoginStateEnum.REGISTER]: t('sys.login.signUpFormTitle'),
[LoginStateEnum.MOBILE]: t('sys.login.mobileSignInFormTitle'),
[LoginStateEnum.QR_CODE]: t('sys.login.qrSignInFormTitle')
}
return titleObj[unref(getLoginState)]
})
</script>
<template>
<h2 class="mb-3 text-2xl font-bold text-center xl:text-3xl enter-x xl:text-center">
{{ getFormTitle }}
</h2>
</template>

View File

@ -0,0 +1,248 @@
<script setup lang="ts">
import { useIcon } from '@/hooks/web/useIcon'
import { reactive, ref, unref, watch, onMounted, computed } from 'vue'
import LoginFormTitle from './LoginFormTitle.vue'
import { ElForm, ElFormItem, ElInput, ElRow, ElCol, ElMessage } from 'element-plus'
import { useI18n } from '@/hooks/web/useI18n'
import { required } from '@/utils/formRules'
import {
getTenantIdByNameApi,
getCodeImgApi,
getAsyncRoutesApi,
sendSmsCodeApi,
smsLoginApi
} from '@/api/login'
import { useCache } from '@/hooks/web/useCache'
import { usePermissionStore } from '@/store/modules/permission'
import { useRouter } from 'vue-router'
import { setToken } from '@/utils/auth'
import { useUserStoreWithOut } from '@/store/modules/user'
import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
import { useLoginState, LoginStateEnum, useFormValid } from './useLogin'
const formSmsLogin = ref()
const { validForm } = useFormValid(formSmsLogin)
const { handleBackLogin, getLoginState } = useLoginState()
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.MOBILE)
const iconHouse = useIcon({ icon: 'ep:house' })
const iconCellphone = useIcon({ icon: 'ep:cellphone' })
const iconCircleCheck = useIcon({ icon: 'ep:circle-check' })
const { wsCache } = useCache()
const userStore = useUserStoreWithOut()
const permissionStore = usePermissionStore()
const { currentRoute, addRoute, push } = useRouter()
const loginLoading = ref(false)
const { t } = useI18n()
const rules = {
tenantName: [required],
mobileNumber: [required],
code: [required]
}
const loginData = reactive({
codeImg: '',
// TODO @jinz多余的变量 isShowPassword、captchaEnable
isShowPassword: false,
captchaEnable: true,
tenantEnable: true,
token: '',
loading: {
signIn: false
},
loginForm: {
uuid: '',
tenantName: '芋道源码',
mobileNumber: '',
code: ''
}
})
// TODO @jinzsmsVO 小写哈
const SmsVO = reactive({
smsCode: {
mobile: '',
scene: 21
},
loginSms: {
mobile: '',
code: ''
}
})
const mobileCodeTimer = ref(0)
const redirect = ref<string>('')
const getSmsCode = async () => {
await getTenantId()
SmsVO.smsCode.mobile = loginData.loginForm.mobileNumber
console.log('getSmsCode begin:', SmsVO.smsCode)
await sendSmsCodeApi(SmsVO.smsCode)
.then(async (res) => {
// 提示验证码发送成功
ElMessage({
type: 'success',
message: t('login.SmsSendMsg')
})
console.log('res', res)
// 设置倒计时
mobileCodeTimer.value = 60
let msgTimer = setInterval(() => {
mobileCodeTimer.value = mobileCodeTimer.value - 1
if (mobileCodeTimer.value <= 0) {
clearInterval(msgTimer)
}
}, 1000)
})
.catch(() => {
console.log('error')
})
}
watch(
() => currentRoute.value,
(route: RouteLocationNormalizedLoaded) => {
redirect.value = route?.query?.redirect as string
},
{
immediate: true
}
)
// 获取验证码 TODO @jinz是不是可以去掉手机这里暂时不用验证码
const getCode = async () => {
const res = await getCodeImgApi()
loginData.codeImg = 'data:image/gif;base64,' + res.img
loginData.loginForm.uuid = res.uuid
}
// 获取租户 ID
const getTenantId = async () => {
const res = await getTenantIdByNameApi(loginData.loginForm.tenantName)
wsCache.set('tenantId', res)
}
// 登录
const signIn = async () => {
await getTenantId()
const data = await validForm()
if (!data) return
loginLoading.value = true
SmsVO.loginSms.mobile = loginData.loginForm.mobileNumber
SmsVO.loginSms.code = loginData.loginForm.code
await smsLoginApi(SmsVO.loginSms)
.then(async (res) => {
setToken(res?.token)
await userStore.getUserInfoAction()
getRoutes()
})
.catch(() => {})
.finally(() => {
loginLoading.value = false
})
}
// 获取路由
const getRoutes = async () => {
// 后端过滤菜单
// TODO @jinz这块 getRoutes 的代码,是不是可以统一到 store 里,类似 ruoyi-vue 的做法,可能要找作者沟通下
const routers = await getAsyncRoutesApi()
wsCache.set('roleRouters', routers)
await permissionStore.generateRoutes(routers).catch(() => {})
permissionStore.getAddRouters.forEach((route) => {
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
})
permissionStore.setIsAddRouters(true)
push({ path: redirect.value || permissionStore.addRouters[0].path })
}
onMounted(() => {
getCode()
})
</script>
<template>
<el-form
:model="loginData.loginForm"
:rules="rules"
label-position="top"
class="login-form"
label-width="120px"
size="large"
v-show="getShow"
ref="formSmsLogin"
>
<el-row style="margin-left: -10px; margin-right: -10px">
<!-- 租户名 -->
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item>
<LoginFormTitle style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item prop="tenantName">
<el-input
type="text"
v-model="loginData.loginForm.tenantName"
:placeholder="t('login.tenantNamePlaceholder')"
:prefix-icon="iconHouse"
/>
</el-form-item>
</el-col>
<!-- 手机号 -->
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item prop="mobileNumber">
<el-input
v-model="loginData.loginForm.mobileNumber"
:placeholder="t('login.mobileNumberPlaceholder')"
:prefix-icon="iconCellphone"
/>
</el-form-item>
</el-col>
<!-- 验证码 -->
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item prop="code">
<el-row justify="space-between" style="width: 100%" :gutter="5">
<el-col :span="24">
<el-input
v-model="loginData.loginForm.code"
:placeholder="t('login.codePlaceholder')"
:prefix-icon="iconCircleCheck"
>
<!-- <el-button class="w-[100%]"> -->
<template #append>
<span
v-if="mobileCodeTimer <= 0"
@click="getSmsCode"
class="getMobileCode"
style="cursor: pointer"
>
{{ t('login.getSmsCode') }}
</span>
<span v-if="mobileCodeTimer > 0" class="getMobileCode" style="cursor: pointer">
{{ mobileCodeTimer }}秒后可重新获取
</span>
</template>
</el-input>
<!-- </el-button> -->
</el-col>
</el-row>
</el-form-item>
</el-col>
<!-- 登录按钮 / 返回按钮 -->
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item>
<el-button :loading="loginLoading" type="primary" class="w-[100%]" @click="signIn">
{{ t('login.login') }}
</el-button>
</el-form-item>
</el-col>
<el-col :span="24" style="padding-left: 10px; padding-right: 10px">
<el-form-item>
<el-button :loading="loginLoading" class="w-[100%]" @click="handleBackLogin">
{{ t('login.backLogin') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<style lang="less" scoped>
:deep(.anticon) {
&:hover {
color: var(--el-color-primary) !important;
}
}
.smsbtn {
margin-top: 33px;
}
</style>

View File

@ -0,0 +1,4 @@
export { default as LoginForm } from './LoginForm.vue'
export { default as MobileForm } from './MobileForm.vue'
export { default as LoginFormOld } from './LoginFormOld.vue' // TODO jinzold 是不是可以删除哈git 可以管理的
export { default as LoginFormTitle } from './LoginFormTitle.vue'

View File

@ -0,0 +1,136 @@
import { ref, computed, unref, Ref } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
export enum LoginStateEnum {
LOGIN,
REGISTER,
RESET_PASSWORD,
MOBILE,
QR_CODE
}
const currentState = ref(LoginStateEnum.LOGIN)
export function useLoginState() {
function setLoginState(state: LoginStateEnum) {
currentState.value = state
}
const getLoginState = computed(() => currentState.value)
function handleBackLogin() {
setLoginState(LoginStateEnum.LOGIN)
}
return {
setLoginState,
getLoginState,
handleBackLogin
}
}
export function useFormValid<T extends Object = any>(formRef: Ref<any>) {
async function validForm() {
const form = unref(formRef)
if (!form) return
const data = await form.validate()
return data as T
}
return {
validForm
}
}
// TODO @jinz多余的是不是可以删除哈
export function useFormRules(formData?: Recordable) {
const { t } = useI18n()
const getAccountFormRule = computed(() => createRule(t('sys.login.accountPlaceholder')))
const getPasswordFormRule = computed(() => createRule(t('sys.login.passwordPlaceholder')))
const getSmsFormRule = computed(() => createRule(t('sys.login.smsPlaceholder')))
const getMobileFormRule = computed(() => createRule(t('sys.login.mobilePlaceholder')))
const validatePolicy = async (_: RuleObject, value: boolean) => {
return !value ? Promise.reject(t('sys.login.policyPlaceholder')) : Promise.resolve()
}
const validateConfirmPassword = (password: string) => {
return async (_: RuleObject, value: string) => {
if (!value) {
return Promise.reject(t('sys.login.passwordPlaceholder'))
}
if (value !== password) {
return Promise.reject(t('sys.login.diffPwd'))
}
return Promise.resolve()
}
}
const getFormRules = computed(
(): {
[k: string]: ValidationRule | ValidationRule[]
} => {
const accountFormRule = unref(getAccountFormRule)
const passwordFormRule = unref(getPasswordFormRule)
const smsFormRule = unref(getSmsFormRule)
const mobileFormRule = unref(getMobileFormRule)
const mobileRule = {
sms: smsFormRule,
mobile: mobileFormRule
}
switch (unref(currentState)) {
// register form rules
case LoginStateEnum.REGISTER:
return {
account: accountFormRule,
password: passwordFormRule,
confirmPassword: [
{
validator: validateConfirmPassword(formData?.password),
trigger: 'change'
}
],
policy: [
{
validator: validatePolicy,
trigger: 'change'
}
],
...mobileRule
}
// reset password form rules
case LoginStateEnum.RESET_PASSWORD:
return {
account: accountFormRule,
...mobileRule
}
// mobile form rules
case LoginStateEnum.MOBILE:
return mobileRule
// login form rules
default:
return {
account: accountFormRule,
password: passwordFormRule
}
}
}
)
return {
getFormRules
}
}
function createRule(message: string) {
return [
{
required: true,
message,
trigger: 'change'
}
]
}