| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- <template>
- <div>
- <h3 text-center m-0 mb-20px>{{ t("login.reg") }}</h3>
- <el-form ref="formRef" :model="model" :rules="rules" size="large" label-suffix=":">
- <!-- 邀请码 -->
- <!-- <el-form-item prop="invite_code">
- <el-input v-model.trim="model.invite_code" placeholder="请输入邀请码" clearable>
- <template #prefix>
- <el-icon><SetUp /></el-icon>
- </template>
- </el-input>
- </el-form-item> -->
- <el-form-item prop="mobile">
- <el-input v-model.trim="model.mobile" placeholder="请输入手机号" clearable>
- <template #prefix>
- <el-icon><Iphone /></el-icon>
- </template>
- </el-input>
- </el-form-item>
- <el-form-item prop="sms_code">
- <div class="flex gap-10px">
- <el-input v-model.trim="model.sms_code" placeholder="请输入验证码" clearable class="flex-1"
- @keyup.enter="">
- <template #prefix>
- <el-icon>
- <Message />
- </el-icon>
- </template>
- </el-input>
- <el-button :disabled="smsCountdown > 0 || !model.mobile" :loading="smsCodeLoading" class="w-32"
- @click="getSmsCode">
- {{ smsCountdown > 0 ? `${smsCountdown}s` : '获取验证码' }}
- </el-button>
- </div>
- </el-form-item>
- <!-- 账号 -->
- <!-- <el-form-item prop="username">
- <el-input v-model.trim="model.username" :placeholder="t('login.username')" clearable>
- <template #prefix>
- <el-icon><User /></el-icon>
- </template>
- </el-input>
- </el-form-item> -->
- <!-- 密码 -->
- <el-tooltip :visible="isCapsLock" :content="t('login.capsLock')" placement="right">
- <el-form-item prop="password">
- <el-input v-model.trim="model.password" :placeholder="t('login.password')" type="password" show-password
- clearable @keyup="checkCapsLock" @keyup.enter="submit">
- <template #prefix>
- <el-icon>
- <Lock />
- </el-icon>
- </template>
- </el-input>
- </el-form-item>
- </el-tooltip>
- <!-- 确认密码 -->
- <el-tooltip :visible="isCapsLock" :content="t('login.capsLock')" placement="right">
- <el-form-item prop="confirmPassword">
- <el-input v-model.trim="model.confirmPassword" :placeholder="t('login.message.password.confirm')"
- type="password" show-password clearable @keyup="checkCapsLock" @keyup.enter="submit">
- <template #prefix>
- <el-icon>
- <Lock />
- </el-icon>
- </template>
- </el-input>
- </el-form-item>
- </el-tooltip>
- <el-form-item>
- <div class="flex-y-center w-full gap-10px">
- <el-checkbox v-model="isRead">{{ t("login.agree") }}</el-checkbox>
- <el-link type="primary" underline="never" :href="configStore.configData.sys_web_clause.config_value"
- target="_blank">
- {{ t("login.userAgreement") }}
- </el-link>
- </div>
- </el-form-item>
- <!-- 注册按钮 -->
- <el-form-item>
- <el-button :loading="loading" type="primary" class="w-full" @click="submit">
- {{ t("login.register") }}
- </el-button>
- </el-form-item>
- </el-form>
- <div flex-center gap-10px>
- <el-text size="default">{{ t("login.haveAccount") }}</el-text>
- <el-link type="primary" underline="never" @click="toLogin">{{ t("login.login") }}</el-link>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import type { FormInstance } from "element-plus";
- import { Lock } from "@element-plus/icons-vue";
- import UserAPI, { type RegisterForm } from "@/api/module_system/user";
- import { useConfigStore } from "@/store";
- import { useI18n } from "vue-i18n";
- import AuthAPI, {
- } from "@/api/module_system/auth";
- import { Auth } from "@/utils/auth";
- const { t } = useI18n();
- // 使用 defineModel 简化具名 v-model 绑定
- const modelValue = defineModel<string>();
- const presetUsername = defineModel<string>("presetUsername");
- const presetPassword = defineModel<string>("presetPassword");
- const toLogin = () => {
- modelValue.value = "login";
- };
- const configStore = useConfigStore();
- const formRef = ref<FormInstance>();
- const loading = ref(false); // 按钮 loading 状态
- const isCapsLock = ref(false); // 是否大写锁定
- const isRead = ref(false);
- const smsLoading = ref(false);
- const smsCodeLoading = ref(false);
- const smsCountdown = ref(0);
- const model = ref<RegisterForm>({
- mobile: "",
- sms_code: "",
- username: "",
- password: "",
- confirmPassword: "",
- });
- const rules = computed(() => {
- return {
- // invite_code: [
- // {
- // required: true,
- // trigger: "blur",
- // message: "请输入邀请码",
- // },
- // ],
- // 验证国内手机号格式
- mobile: [
- {
- required: true,
- trigger: "blur",
- message: "请输入手机号",
- },
- {
- pattern: /^1[3456789]\d{9}$/,
- trigger: "blur",
- message: "请输入正确的手机号格式",
- },
- ],
- sms_code: [
- {
- required: true,
- trigger: "blur",
- message: "请输入验证码",
- },
- ],
- username: [
- {
- required: true,
- trigger: "blur",
- message: t("login.message.username.required"),
- },
- ],
- password: [
- {
- required: true,
- trigger: "blur",
- message: t("login.message.password.required"),
- },
- {
- min: 6,
- message: t("login.message.password.min"),
- trigger: "blur",
- },
- ],
- confirmPassword: [
- {
- required: true,
- trigger: "blur",
- message: t("login.message.password.required"),
- },
- {
- min: 6,
- message: t("login.message.password.min"),
- trigger: "blur",
- },
- {
- validator: (_: any, value: string) => {
- return value === model.value.password;
- },
- trigger: "blur",
- message: t("login.message.password.inconformity"),
- },
- ],
- };
- });
- // 检查输入大小写
- function checkCapsLock(event: KeyboardEvent) {
- // 防止浏览器密码自动填充时报错
- if (event instanceof KeyboardEvent) {
- isCapsLock.value = event.getModifierState("CapsLock");
- }
- }
- const submit = async () => {
- try {
- // 0. 检查是否已勾选协议
- if (!isRead.value) {
- ElMessage.warning(t("login.message.agree.required"));
- return;
- }
- // 1. 表单验证
- const valid = await formRef.value?.validate();
- if (!valid) return;
- loading.value = true;
- model.value.username = model.value.mobile;
- await UserAPI.registerUser(model.value);
- // 注册成功后,双向绑定回写父容器的用户名和密码,并切回登录
- presetUsername.value = model.value.username;
- presetPassword.value = model.value.password;
- toLogin();
- } catch (error) {
- console.error(error);
- } finally {
- loading.value = false;
- }
- };
- // 获取短信验证码
- async function getSmsCode() {
- try {
- const valid = await formRef.value?.validateField("mobile");
- if (!valid) return;
- smsCodeLoading.value = true;
- // 调用后端API获取短信验证码
- await AuthAPI.getSmsCode({ mobile: model.value.mobile, template_name: "verify" });
- // 开始倒计时
- smsCountdown.value = 60;
- const timer = setInterval(() => {
- smsCountdown.value--;
- if (smsCountdown.value <= 0) {
- clearInterval(timer);
- }
- }, 1000);
- // ElMessage.success("验证码已发送");
- } catch (error: any) {
- // ElMessage.error(error?.response?.data?.msg || "获取验证码失败");
- } finally {
- smsCodeLoading.value = false;
- }
- }
- onMounted(() => {});
- </script>
|