Merge remote-tracking branch 'origin/wfc-modules-user'
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
import { computed } from 'vue';
|
||||
import type { Component } from 'vue';
|
||||
import { getColorPalette, mixColor } from '@sa/utils';
|
||||
import { $t } from '@/locales';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { loginModuleRecord } from '@/constants/app';
|
||||
import PwdLogin from './modules/pwd-login.vue';
|
||||
@@ -10,14 +9,16 @@ import CodeLogin from './modules/code-login.vue';
|
||||
import Register from './modules/register.vue';
|
||||
import ResetPwd from './modules/reset-pwd.vue';
|
||||
import BindWechat from './modules/bind-wechat.vue';
|
||||
|
||||
import { WifiOutlined } from '@ant-design/icons-vue';
|
||||
import {useI18n} from "vue-i18n";
|
||||
//import { $t } from '@/locales';
|
||||
interface Props {
|
||||
/** The login module */
|
||||
module?: UnionKey.LoginModule;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const {t} = useI18n();
|
||||
const themeStore = useThemeStore();
|
||||
|
||||
interface LoginModule {
|
||||
@@ -54,12 +55,12 @@ const bgColor = computed(() => {
|
||||
<ACard class="relative z-4">
|
||||
<div class="w-400px lt-sm:w-300px">
|
||||
<header class="flex-y-center justify-between">
|
||||
<SystemLogo class="text-64px text-primary lt-sm:text-48px" />
|
||||
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ $t('system.title') }}</h3>
|
||||
<WifiOutlined class="text-64px text-primary lt-sm:text-48px" style="margin-left: 9px"/>
|
||||
<h3 class="text-18px text-primary font-medium">{{ t(activeModule.label) }}</h3>
|
||||
</header>
|
||||
<main class="pt-24px">
|
||||
<h3 class="text-18px text-primary font-medium">{{ $t(activeModule.label) }}</h3>
|
||||
<div class="animation-slide-in-left pt-24px">
|
||||
<main >
|
||||
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ "WANFi" }}</h3>
|
||||
<div class="animation-slide-in-left ">
|
||||
<Transition :name="themeStore.page.animateMode" mode="out-in" appear>
|
||||
<component :is="activeModule.component" />
|
||||
</Transition>
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@/locales';
|
||||
import { loginModuleRecord } from '@/constants/app';
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
import { useAntdForm, useFormRules } from '@/hooks/common/form';
|
||||
import { useAuthStore } from '@/store/modules/auth';
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
|
||||
defineOptions({
|
||||
name: 'PwdLogin'
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
const authStore = useAuthStore();
|
||||
const { toggleLoginModule } = useRouterPush();
|
||||
const { formRef, validate } = useAntdForm();
|
||||
const { patternRules } = useFormRules();
|
||||
const codeImg = ref('');
|
||||
|
||||
|
||||
getCheckCode();
|
||||
|
||||
const model = reactive({
|
||||
username: 'ryadmin',
|
||||
password: 'admin123',
|
||||
username: '123456',
|
||||
password: '123456',
|
||||
code: '',
|
||||
uuid: '',
|
||||
authType: 'sys'
|
||||
@@ -31,11 +33,11 @@ const rules = {
|
||||
};
|
||||
|
||||
async function handleSubmit() {
|
||||
await validate();
|
||||
await validate();//验证表单内容
|
||||
await authStore.login({
|
||||
loginForm: model,
|
||||
loginForm: model,//发送表单的数据
|
||||
onError() {
|
||||
getCheckCode();
|
||||
getCheckCode();//重新获取验证码
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -45,6 +47,9 @@ async function getCheckCode() {
|
||||
if (!error) {
|
||||
codeImg.value = `data:image/png;base64,${data.img}`;
|
||||
model.uuid = data.uuid;
|
||||
if (data?.text) {
|
||||
model.code = data.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -73,18 +78,18 @@ async function getCheckCode() {
|
||||
<ASpace direction="vertical" size="large" class="w-full">
|
||||
<div class="flex-y-center justify-between">
|
||||
<ACheckbox>{{ $t('page.login.pwdLogin.rememberMe') }}</ACheckbox>
|
||||
<AButton type="text" @click="toggleLoginModule('reset-pwd')">{{ $t('page.login.pwdLogin.forgetPassword') }}</AButton>
|
||||
<AButton type="text" @click="toggleLoginModule('reset-pwd')">{{ t('page.login.pwdLogin.forgetPassword') }}</AButton>
|
||||
</div>
|
||||
<AButton type="primary" block size="large" shape="round" :loading="authStore.loginLoading" @click="handleSubmit">
|
||||
{{ $t('common.confirm') }}
|
||||
</AButton>
|
||||
<div class="flex-y-center justify-between">
|
||||
<AButton class="h-34px flex-1" block @click="toggleLoginModule('code-login')">
|
||||
{{ $t(loginModuleRecord['code-login']) }}
|
||||
</AButton>
|
||||
<!-- <AButton class="h-34px flex-1" block @click="toggleLoginModule('code-login')">-->
|
||||
<!-- {{ t(loginModuleRecord['code-login']) }}-->
|
||||
<!-- </AButton>-->
|
||||
<div class="w-12px"></div>
|
||||
<AButton class="h-34px flex-1" block @click="toggleLoginModule('register')">
|
||||
{{ $t(loginModuleRecord.register) }}
|
||||
{{ t(loginModuleRecord.register) }}
|
||||
</AButton>
|
||||
</div>
|
||||
</ASpace>
|
||||
|
||||
@@ -1,86 +1,445 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive } from 'vue';
|
||||
import { $t } from '@/locales';
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
import { useAntdForm, useFormRules } from '@/hooks/common/form';
|
||||
import { useCaptcha } from '@/hooks/business/captcha';
|
||||
import {computed, reactive, ref} from 'vue';
|
||||
import {useI18n} from 'vue-i18n'; // 添加这行
|
||||
import {useAuthStore} from '@/store/modules/auth';
|
||||
import {useRouterPush} from '@/hooks/common/router';
|
||||
import {useAntdForm, useFormRules} from '@/hooks/common/form';
|
||||
import {useCaptcha} from '@/hooks/business/captcha';
|
||||
import {useWindowSize} from '@vueuse/core';
|
||||
import {registerTerms} from '@/views/_builtin/login/modules/terms';
|
||||
import dayjs from 'dayjs';
|
||||
import type {Rule} from 'ant-design-vue/es/form';
|
||||
|
||||
const { t } = useI18n();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
defineOptions({
|
||||
name: 'CodeLogin'
|
||||
name: 'Register'
|
||||
});
|
||||
|
||||
const { toggleLoginModule } = useRouterPush();
|
||||
const { formRef, validate } = useAntdForm();
|
||||
const { label, isCounting, loading, getCaptcha } = useCaptcha();
|
||||
|
||||
interface FormModel {
|
||||
const { width } = useWindowSize();
|
||||
const isMobile = computed(() => width.value <= 640);
|
||||
|
||||
// 当前步骤
|
||||
const currentStep = ref(0);
|
||||
|
||||
// 是否同意协议
|
||||
const agreeTerms = ref(false);
|
||||
// 定义一个统一的数据模型
|
||||
interface RegisterModel {
|
||||
username: string;
|
||||
password: string;
|
||||
email: string;
|
||||
fullName: string;
|
||||
age:0,
|
||||
gender: string;
|
||||
phone: string;
|
||||
address: string;
|
||||
code: string;
|
||||
authType: string;
|
||||
}
|
||||
|
||||
// 使用一个统一的 model
|
||||
const model = reactive<RegisterModel>({
|
||||
username: '',
|
||||
password: '',
|
||||
email: '',
|
||||
fullName: '',
|
||||
age:0,
|
||||
gender: '',
|
||||
phone: '',
|
||||
address: '',
|
||||
code: '',
|
||||
authType: 'u'
|
||||
});
|
||||
|
||||
// 第一步表单数据
|
||||
interface BasicFormModel {
|
||||
username: string;
|
||||
fullName: string;
|
||||
birthDate: string;
|
||||
gender: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
address: string;
|
||||
}
|
||||
|
||||
const basicModel = reactive<BasicFormModel>({
|
||||
username: '',
|
||||
fullName: '',
|
||||
birthDate: '',
|
||||
gender: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
address: ''
|
||||
});
|
||||
|
||||
// 第三表单数据
|
||||
interface SecurityFormModel {
|
||||
email: string;
|
||||
code: string;
|
||||
password: string;
|
||||
confirmPassword: string;
|
||||
}
|
||||
|
||||
const model: FormModel = reactive({
|
||||
phone: '',
|
||||
const securityModel = reactive<SecurityFormModel>({
|
||||
email: '',
|
||||
code: '',
|
||||
password: '',
|
||||
confirmPassword: ''
|
||||
});
|
||||
|
||||
const rules = computed<Record<keyof FormModel, App.Global.FormRule[]>>(() => {
|
||||
const { formRules, createConfirmPwdRule } = useFormRules();
|
||||
|
||||
// 第一步表单验证规则
|
||||
const basicRules = computed<Record<string, Rule | Rule[]>>(() => {
|
||||
const { formRules } = useFormRules();
|
||||
return {
|
||||
phone: formRules.phone,
|
||||
code: formRules.code,
|
||||
password: formRules.pwd,
|
||||
confirmPassword: createConfirmPwdRule(model.password)
|
||||
username: formRules.username,
|
||||
email: formRules.email,
|
||||
birthDate: [{ required: true, message: t('page.login.register.birthDateRequired') }],
|
||||
phone: [{ pattern: /^1[3-9]\d{9}$/, message: t('form.phone.invalid'), trigger: 'blur' }]
|
||||
};
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
await validate();
|
||||
// request to register
|
||||
$message?.success($t('page.login.common.validateSuccess'));
|
||||
// 第三步表单验证规则
|
||||
const securityRules = computed<Record<string, Rule | Rule[]>>(() => {
|
||||
const { formRules, createConfirmPwdRule } = useFormRules();
|
||||
return {
|
||||
code: formRules.code,
|
||||
password: formRules.pwd,
|
||||
confirmPassword: createConfirmPwdRule(securityModel.password)
|
||||
};
|
||||
});
|
||||
|
||||
// 协议内容
|
||||
const terms = computed(() => {
|
||||
const locale = useI18n().locale.value;
|
||||
return registerTerms[locale === 'zh-CN' ? 'zh-CN' : 'en-US'];
|
||||
});
|
||||
|
||||
// 步骤控制函数
|
||||
async function nextStep() {
|
||||
if (currentStep.value === 0) {
|
||||
await validate();
|
||||
// 复制电话号码到第三步
|
||||
securityModel.email = basicModel.email;
|
||||
}
|
||||
if (currentStep.value === 1) {
|
||||
if (!agreeTerms.value) {
|
||||
window.$message?.error(t('page.login.register.agreeTermsFirst'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
currentStep.value += 1;
|
||||
}
|
||||
|
||||
function prevStep() {
|
||||
currentStep.value -= 1;
|
||||
}
|
||||
//注册按钮
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
await validate();
|
||||
|
||||
// 整合表单数据
|
||||
model.username = basicModel.username;
|
||||
model.password = securityModel.password;
|
||||
model.email = securityModel.email;
|
||||
model.fullName = basicModel.fullName;
|
||||
model.gender = basicModel.gender; // 直接使用 gender 值
|
||||
model.phone = basicModel.phone;
|
||||
model.address = basicModel.address;
|
||||
model.code = securityModel.code;
|
||||
|
||||
const success = await authStore.register({
|
||||
...model,
|
||||
age: dayjs().diff(dayjs(basicModel.birthDate), 'year'),
|
||||
sex: model.gender, // 直接使用 gender 值,不需要转换
|
||||
phonenumber: model.phone,
|
||||
});
|
||||
|
||||
if (success) {
|
||||
window.$message?.success(t('page.login.register.registerSuccess'));
|
||||
toggleLoginModule('pwd-login');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Form validation failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 在script setup部分添加一个新的计算属性
|
||||
const showSteps = computed(() => !isMobile.value);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AForm ref="formRef" :model="model" :rules="rules">
|
||||
<AFormItem name="phone">
|
||||
<AInput v-model:value="model.phone" size="large" :placeholder="$t('page.login.common.phonePlaceholder')" />
|
||||
</AFormItem>
|
||||
<AFormItem name="code">
|
||||
<div class="w-full flex-y-center gap-16px">
|
||||
<AInput v-model:value="model.code" size="large" :placeholder="$t('page.login.common.codePlaceholder')" />
|
||||
<AButton size="large" :disabled="isCounting" :loading="loading" @click="getCaptcha(model.phone)">
|
||||
{{ label }}
|
||||
</AButton>
|
||||
<ASteps
|
||||
v-if="showSteps"
|
||||
:current="currentStep"
|
||||
size="small"
|
||||
class="max-w-full mb-16px"
|
||||
direction="horizontal"
|
||||
:responsive="false"
|
||||
>
|
||||
<AStep :title="t('page.login.register.basicInfo')" />
|
||||
<AStep :title="t('page.login.register.terms')" />
|
||||
<AStep :title="t('page.login.register.security')" />
|
||||
</ASteps>
|
||||
|
||||
<div v-else class="mobile-step-indicator mb-16px text-center">
|
||||
{{ currentStep + 1 }}/3: {{
|
||||
currentStep === 0
|
||||
? t('page.login.register.basicInfo')
|
||||
: currentStep === 1
|
||||
? t('page.login.register.terms')
|
||||
: t('page.login.register.security')
|
||||
}}
|
||||
</div>
|
||||
|
||||
<div class="step-content">
|
||||
<!-- 第一步:基本信息 -->
|
||||
<div v-if="currentStep === 0">
|
||||
<AForm
|
||||
ref="formRef"
|
||||
:model="basicModel"
|
||||
:rules="basicRules"
|
||||
:label-wrap="true"
|
||||
:label-col="{ span: 8 }"
|
||||
:wrapper-col="{ span: 16 }"
|
||||
>
|
||||
<ARow :gutter="[8,2]">
|
||||
<ACol :span="24" :lg="24">
|
||||
<AFormItem name="username" :label="t('page.login.register.username')">
|
||||
<AInput v-model:value="basicModel.username" />
|
||||
</AFormItem>
|
||||
</ACol>
|
||||
<ACol :span="24" :lg="24">
|
||||
<AFormItem name="fullName" :label="t('page.login.register.fullName')">
|
||||
<AInput v-model:value="basicModel.fullName" />
|
||||
</AFormItem>
|
||||
</ACol>
|
||||
<ACol :xs="12" :sm="12" :lg="24">
|
||||
<AFormItem name="birthDate" :label="t('page.login.register.birthDate')">
|
||||
<ADatePicker
|
||||
v-model:value="basicModel.birthDate"
|
||||
class="!w-full birth-date-picker"
|
||||
:placeholder="t('page.login.register.birthDatePlaceholder')"
|
||||
:disabled-date="(current: dayjs.Dayjs) => current && current.isAfter(dayjs())"
|
||||
/>
|
||||
</AFormItem>
|
||||
</ACol>
|
||||
<ACol :xs="12" :sm="12" :lg="24">
|
||||
<AFormItem name="gender" :label="t('page.login.register.gender')">
|
||||
<ASelect v-model:value="basicModel.gender">
|
||||
<ASelectOption value="male">{{ t('page.login.register.male') }}</ASelectOption>
|
||||
<ASelectOption value="female">{{ t('page.login.register.female') }}</ASelectOption>
|
||||
</ASelect>
|
||||
</AFormItem>
|
||||
</ACol>
|
||||
<ACol :lg="24" :span="24">
|
||||
<AFormItem name="phone" :label="t('page.login.register.phone')">
|
||||
<AInput v-model:value="basicModel.phone" />
|
||||
</AFormItem>
|
||||
</ACol>
|
||||
<ACol :lg="24" :span="24">
|
||||
<AFormItem name="email" :label="t('page.login.register.email')">
|
||||
<AInput v-model:value="basicModel.email" />
|
||||
</AFormItem>
|
||||
</ACol>
|
||||
<ACol :lg="24" :span="24">
|
||||
<AFormItem name="address" :label="t('page.login.register.address')">
|
||||
<ATextarea v-model:value="basicModel.address" :rows="2" />
|
||||
</AFormItem>
|
||||
</ACol>
|
||||
<ACol :lg="24" :span="24">
|
||||
<ASpace direction="vertical" size="small" class="w-full">
|
||||
<AButton type="primary" block size="small" @click="nextStep">
|
||||
{{ t('page.login.register.next') }}
|
||||
</AButton>
|
||||
<AButton block size="small" @click="toggleLoginModule('pwd-login')">
|
||||
{{ t('page.login.common.back') }}
|
||||
</AButton>
|
||||
</ASpace>
|
||||
</ACol>
|
||||
</ARow>
|
||||
</AForm>
|
||||
</div>
|
||||
|
||||
<!-- 第二步:协议 -->
|
||||
<div v-if="currentStep === 1">
|
||||
<ATextarea
|
||||
:value="terms"
|
||||
:rows="12"
|
||||
readonly
|
||||
class="mb-16px"
|
||||
size="small"
|
||||
:style="{ fontSize: '14px', lineHeight: '1.6' }"
|
||||
/>
|
||||
<div class="mb-16px">
|
||||
<ACheckbox
|
||||
v-model:checked="agreeTerms"
|
||||
class="terms-checkbox"
|
||||
>
|
||||
{{ t('page.login.register.agreeTerms') }}
|
||||
</ACheckbox>
|
||||
</div>
|
||||
</AFormItem>
|
||||
<AFormItem name="password">
|
||||
<AInputPassword
|
||||
v-model:value="model.password"
|
||||
size="large"
|
||||
:placeholder="$t('page.login.common.passwordPlaceholder')"
|
||||
/>
|
||||
</AFormItem>
|
||||
<AFormItem name="confirmPassword">
|
||||
<AInputPassword
|
||||
v-model:value="model.confirmPassword"
|
||||
size="large"
|
||||
:placeholder="$t('page.login.common.confirmPasswordPlaceholder')"
|
||||
/>
|
||||
</AFormItem>
|
||||
<ASpace direction="vertical" size="large" class="w-full">
|
||||
<AButton type="primary" block size="large" shape="round" @click="handleSubmit">
|
||||
{{ $t('common.confirm') }}
|
||||
</AButton>
|
||||
<AButton block size="large" shape="round" @click="toggleLoginModule('pwd-login')">
|
||||
{{ $t('page.login.common.back') }}
|
||||
</AButton>
|
||||
</ASpace>
|
||||
</AForm>
|
||||
<ASpace direction="vertical" size="small" class="w-full">
|
||||
<AButton type="primary" block size="small" :disabled="!agreeTerms" @click="nextStep">
|
||||
{{ t('page.login.register.next') }}
|
||||
</AButton>
|
||||
<AButton block size="small" @click="prevStep">
|
||||
{{ t('page.login.register.prev') }}
|
||||
</AButton>
|
||||
</ASpace>
|
||||
</div>
|
||||
|
||||
<!-- 第三步:安全信息 -->
|
||||
<div v-if="currentStep === 2">
|
||||
<AForm
|
||||
ref="formRef"
|
||||
:model="securityModel"
|
||||
:rules="securityRules"
|
||||
:label-wrap="true"
|
||||
:label-col="{ span: 8 }"
|
||||
:wrapper-col="{ span: 16 }"
|
||||
class="compact-form"
|
||||
>
|
||||
<AFormItem name="email" :label="t('page.login.register.email')">
|
||||
<AInput
|
||||
v-model:value="securityModel.email"
|
||||
:placeholder="t('page.login.common.emailPlaceholder')"
|
||||
/>
|
||||
</AFormItem>
|
||||
<AFormItem name="code" :label="t('page.login.register.code')">
|
||||
<div class="w-full flex-y-center gap-8px">
|
||||
<AInput
|
||||
v-model:value="securityModel.code"
|
||||
:placeholder="t('page.login.common.codePlaceholder')"
|
||||
/>
|
||||
<AButton
|
||||
size="small"
|
||||
:disabled="isCounting"
|
||||
:loading="loading"
|
||||
@click="getCaptcha(securityModel.email)"
|
||||
>
|
||||
{{ label }}
|
||||
</AButton>
|
||||
</div>
|
||||
</AFormItem>
|
||||
<AFormItem name="password" :label="t('page.login.register.password')">
|
||||
<AInputPassword
|
||||
v-model:value="securityModel.password"
|
||||
:placeholder="t('page.login.common.passwordPlaceholder')"
|
||||
/>
|
||||
</AFormItem>
|
||||
<AFormItem name="confirmPassword" :label="t('page.login.register.confirmPassword')">
|
||||
<AInputPassword
|
||||
v-model:value="securityModel.confirmPassword"
|
||||
:placeholder="t('page.login.common.confirmPasswordPlaceholder')"
|
||||
/>
|
||||
</AFormItem>
|
||||
<AFormItem :wrapper-col="{ xs: { span: 24 }, sm: { span: 24 } }">
|
||||
<ASpace direction="vertical" size="small" class="w-full">
|
||||
<AButton type="primary" block size="small" @click="handleSubmit">
|
||||
{{ t('common.confirm') }}
|
||||
</AButton>
|
||||
<AButton block size="small" @click="prevStep">
|
||||
{{ t('page.login.register.prev') }}
|
||||
</AButton>
|
||||
</ASpace>
|
||||
</AFormItem>
|
||||
</AForm>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
@media (max-width: 640px) {
|
||||
:deep(.ant-form) {
|
||||
.ant-form-item {
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
.ant-form-item-label {
|
||||
padding: 0 !important;
|
||||
line-height: 28px !important;
|
||||
|
||||
> label {
|
||||
font-size: 13px !important;
|
||||
height: 28px !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input,
|
||||
.ant-input-password,
|
||||
.ant-select,
|
||||
.ant-input-number,
|
||||
.ant-btn {
|
||||
font-size: 13px !important;
|
||||
height: 28px !important;
|
||||
line-height: 28px !important;
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.ant-select-selector {
|
||||
height: 28px !important;
|
||||
padding: 0 8px !important;
|
||||
|
||||
.ant-select-selection-item {
|
||||
line-height: 26px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input-number {
|
||||
height: 32px !important;
|
||||
|
||||
input {
|
||||
height: 30px !important;
|
||||
padding: 0 8px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-step-indicator {
|
||||
font-size: 13px;
|
||||
padding: 4px 8px;
|
||||
margin-bottom: 8px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
:deep(.ant-space) {
|
||||
gap: 4px !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.terms-checkbox) {
|
||||
.ant-checkbox + span {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-input[readonly]) {
|
||||
background-color: #f5f5f5;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label) {
|
||||
white-space: normal;
|
||||
text-align: left;
|
||||
> label {
|
||||
height: auto !important;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.birth-date-picker {
|
||||
margin-top: 2px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive } from 'vue';
|
||||
import { $t } from '@/locales';
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
import { useAntdForm, useFormRules } from '@/hooks/common/form';
|
||||
import {useCaptcha} from "@/hooks/business/captcha";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
defineOptions({
|
||||
name: 'ResetPwd'
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
const { toggleLoginModule } = useRouterPush();
|
||||
const { formRef, validate } = useAntdForm();
|
||||
const { label, isCounting, loading, getCaptcha } = useCaptcha();
|
||||
|
||||
interface FormModel {
|
||||
phone: string;
|
||||
email: string;
|
||||
code: string;
|
||||
password: string;
|
||||
confirmPassword: string;
|
||||
}
|
||||
|
||||
const model: FormModel = reactive({
|
||||
phone: '',
|
||||
email: '',
|
||||
code: '',
|
||||
password: '',
|
||||
confirmPassword: ''
|
||||
@@ -31,7 +33,9 @@ const rules = computed<RuleRecord>(() => {
|
||||
const { formRules, createConfirmPwdRule } = useFormRules();
|
||||
|
||||
return {
|
||||
phone: formRules.phone,
|
||||
//phone: formRules.phone,
|
||||
email:formRules.email,
|
||||
code:formRules.code,
|
||||
password: formRules.pwd,
|
||||
confirmPassword: createConfirmPwdRule(model.password)
|
||||
};
|
||||
@@ -40,38 +44,48 @@ const rules = computed<RuleRecord>(() => {
|
||||
async function handleSubmit() {
|
||||
await validate();
|
||||
// request to reset password
|
||||
$message?.success($t('page.login.common.validateSuccess'));
|
||||
$message?.success(t('page.login.common.validateSuccess'));
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AForm ref="formRef" :model="model" :rules="rules">
|
||||
<AFormItem name="phone">
|
||||
<AInput v-model:value="model.phone" size="large" :placeholder="$t('page.login.common.phonePlaceholder')" />
|
||||
<AFormItem name="email">
|
||||
<AInput v-model:value="model.email" size="large" :placeholder="t('page.login.common.emailPlaceholder')" />
|
||||
</AFormItem>
|
||||
<AFormItem name="code">
|
||||
<AInput v-model:value="model.code" size="large" :placeholder="$t('page.login.common.codePlaceholder')" />
|
||||
<AFormItem name="code" >
|
||||
<div class="w-full flex-y-center gap-8px">
|
||||
<AInput v-model:value="model.code" size="large" :placeholder="t('page.login.common.codePlaceholder')" />
|
||||
<AButton
|
||||
size="small"
|
||||
:disabled="isCounting"
|
||||
:loading="loading"
|
||||
@click="getCaptcha(model.email)"
|
||||
>
|
||||
{{ label }}
|
||||
</AButton>
|
||||
</div>
|
||||
</AFormItem>
|
||||
<AFormItem name="password">
|
||||
<AInputPassword
|
||||
v-model:value="model.password"
|
||||
size="large"
|
||||
:placeholder="$t('page.login.common.passwordPlaceholder')"
|
||||
:placeholder="t('page.login.common.passwordPlaceholder')"
|
||||
/>
|
||||
</AFormItem>
|
||||
<AFormItem name="confirmPassword">
|
||||
<AInputPassword
|
||||
v-model:value="model.confirmPassword"
|
||||
size="large"
|
||||
:placeholder="$t('page.login.common.confirmPasswordPlaceholder')"
|
||||
:placeholder="t('page.login.common.confirmPasswordPlaceholder')"
|
||||
/>
|
||||
</AFormItem>
|
||||
<ASpace direction="vertical" size="large" class="w-full">
|
||||
<AButton type="primary" block size="large" shape="round" @click="handleSubmit">
|
||||
{{ $t('common.confirm') }}
|
||||
{{ t('common.confirm') }}
|
||||
</AButton>
|
||||
<AButton block size="large" shape="round" @click="toggleLoginModule('pwd-login')">
|
||||
{{ $t('page.login.common.back') }}
|
||||
{{ t('page.login.common.back') }}
|
||||
</AButton>
|
||||
</ASpace>
|
||||
</AForm>
|
||||
|
||||
50
src/views/_builtin/login/modules/terms.ts
Normal file
50
src/views/_builtin/login/modules/terms.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
export const registerTerms = {
|
||||
'zh-CN': `
|
||||
用户协议和隐私政策
|
||||
|
||||
1. 总则
|
||||
本协议是您与我们之间关于使用我们的服务所订立的协议。您注册成为用户,表示您已充分阅读、理解并同意接受本协议的全部内容。
|
||||
|
||||
2. 服务内容
|
||||
2.1 我们将为您提供安全、可靠的服务。
|
||||
2.2 我们保留随时修改或中断服务的权利。
|
||||
|
||||
3. 用户义务
|
||||
3.1 用户应当遵守相关法律法规。
|
||||
3.2 用户应当遵守社区规范和道德准则。
|
||||
3.3 用户应当保护账号安全,不得将账号借给他人使用。
|
||||
|
||||
4. 隐私保护
|
||||
4.1 我们将依法保护您的个人信息安全。
|
||||
4.2 未经您的同意,我们不会向第三方披露您的个人信息。
|
||||
4.3 我们采用业界标准的安全技术来保护您的个人信息。
|
||||
|
||||
5. 免责声明
|
||||
5.1 因不可抗力导致的服务中断,本平台不承担责任。
|
||||
5.2 用户因违反本协议造成的损失由用户自行承担。
|
||||
`,
|
||||
'en-US': `
|
||||
User Agreement and Privacy Policy
|
||||
|
||||
1. General Provisions
|
||||
This agreement is established between you and us regarding the use of our services. By registering as a user, you indicate that you have fully read, understood and agreed to accept all contents of this agreement.
|
||||
|
||||
2. Service Content
|
||||
2.1 We will provide you with secure and reliable services.
|
||||
2.2 We reserve the right to modify or interrupt services at any time.
|
||||
|
||||
3. User Obligations
|
||||
3.1 Users shall comply with relevant laws and regulations.
|
||||
3.2 Users shall comply with community standards and ethical guidelines.
|
||||
3.3 Users shall protect account security and not lend their accounts to others.
|
||||
|
||||
4. Privacy Protection
|
||||
4.1 We will protect your personal information security in accordance with law.
|
||||
4.2 We will not disclose your personal information to third parties without your consent.
|
||||
4.3 We use industry-standard security technology to protect your personal information.
|
||||
|
||||
5. Disclaimer
|
||||
5.1 The platform is not liable for service interruptions caused by force majeure.
|
||||
5.2 Users shall bear losses caused by their violation of this agreement.
|
||||
`
|
||||
};
|
||||
@@ -31,7 +31,7 @@ const pkgJson: PkgJson = {
|
||||
devDependencies: Object.entries(devDependencies).map(item => transformVersionData(item))
|
||||
};
|
||||
|
||||
const latestBuildTime = BUILD_TIME;
|
||||
const latestBuildTime = "----";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script lang="ts" setup>
|
||||
import type {} from 'ant-design-vue';
|
||||
import { generatedRoutes } from '@/router/elegant/routes';
|
||||
import { $t } from '@/locales';
|
||||
import type { MenuModelType } from './form';
|
||||
import { formRules, menuStatusOptions, menuTypeOptions, resetAddForm } from './form';
|
||||
@@ -30,24 +28,6 @@ const title = computed(() => {
|
||||
return titles[props.operateType];
|
||||
});
|
||||
|
||||
// TODO: 根据菜单类型动态加载组件路径、目录类型只允许选择带有子元素的,菜单类型只允许选择没有子元素的
|
||||
const componentOptions = computed(() => {
|
||||
const excludePaths = ['/404', '/403', '/500'];
|
||||
function transformRoutes(routes: any[]): any[] {
|
||||
return routes.filter(route => {
|
||||
if (route.children) {
|
||||
route.children = transformRoutes(route.children);
|
||||
return true;
|
||||
}
|
||||
if (!route.hideInMenu && !excludePaths.includes(route.path) && !route.path.startsWith('/login')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return transformRoutes(generatedRoutes);
|
||||
});
|
||||
|
||||
watch(visible, val => {
|
||||
if (val) {
|
||||
@@ -95,10 +75,6 @@ async function getTreeData() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleTreeSelect(node: any) {
|
||||
model.value.component = node.component;
|
||||
model.value.name = node.name;
|
||||
}
|
||||
|
||||
getTreeData();
|
||||
</script>
|
||||
@@ -139,20 +115,9 @@ getTreeData();
|
||||
</ARadioGroup>
|
||||
</AFormItem>
|
||||
<AFormItem v-if="model.menuType !== 'F'" label="菜单路径" name="path">
|
||||
<div>
|
||||
<!-- @vue-ignore -->
|
||||
<ATreeSelect
|
||||
v-if="model.isFrame === '1'"
|
||||
v-model:value="model.path"
|
||||
show-search
|
||||
:field-names="{ value: 'path', label: 'path' }"
|
||||
allow-clear
|
||||
:tree-data="componentOptions"
|
||||
tree-node-filter-prop="label"
|
||||
@select="(_val, node) => handleTreeSelect(node)"
|
||||
/>
|
||||
<AInput v-else v-model:value="model.path" />
|
||||
</div>
|
||||
path <AInput v-model:value="model.path" />
|
||||
component <AInput v-model:value="model.component" />
|
||||
name <AInput v-model:value="model.name" />
|
||||
</AFormItem>
|
||||
<AFormItem v-if="model.menuType === 'C'" label="隐藏菜单" name="hideInMenu">
|
||||
<ASwitch v-model:checked="model.hideInMenu" checked-value="0" un-checked-value="1" />
|
||||
|
||||
7
src/views/user/vip/index.vue
Normal file
7
src/views/user/vip/index.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div>user_vip</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user