- <template>
- <el-dialog :model-value="visible" @update:model-value="$emit('update:visible', $event)"
- :title="isLogin ? '手机号登录' : '手机号注册'" width="500px" :show-close="true" :close-on-click-modal="false" center
- class="login-register-modal">
- <div class="auth-form">
- <div class="phone-input">
- <el-select v-model="countryCode" class="country-code">
- <el-option label="+86" value="+86" />
- <!-- <el-option label="+852" value="+852" />
- <el-option label="+853" value="+853" />
- <el-option label="+886" value="+886" /> -->
- </el-select>
- <el-input v-model="phone" placeholder="手机号" />
- </div>
-
- <div class="verification-input">
- <el-input v-model="verificationCode" placeholder="验证码" />
- <el-button type="primary" :disabled="countdownActive" @click="sendVerificationCode">
- {{ countdownActive ? `${countdown}秒后重发` : '发送验证码' }}
- </el-button>
- </div>
-
- <el-button type="primary" class="submit-button" @click="handleSubmit">
- {{ isLogin ? '登录' : '注册' }}
- </el-button>
-
- <!-- <div class="form-options">
- <span class="switch-auth" @click="switchAuthType">
- {{ isLogin ? '手机号注册' : '已有账号登录' }}
- </span>
- </div> -->
-
- <div class="agreement">
- <el-checkbox v-model="agreeTerms"></el-checkbox>
- <span class="agreement-text">
- 登录即表示您同意 <a href="javascript:void(0)">《用户协议》</a> 和 <a href="javascript:void(0)">《隐私政策》</a>
- </span>
- </div>
- </div>
- </el-dialog>
- </template>
-
- <script>
- import { ref, computed } from 'vue';
- import { ElMessage } from 'element-plus';
- import { useMainStore } from '@/store';
- import { authApi } from '@/api/auth';
-
- export default {
- name: 'LoginRegisterModal',
- props: {
- visible: {
- type: Boolean,
- required: true
- },
- defaultType: {
- type: String,
- default: 'login',
- validator: (val) => ['login', 'register'].includes(val)
- }
- },
- emits: ['update:visible', 'login-success', 'register-success'],
- setup(props, { emit }) {
- const store = useMainStore();
-
- const authType = ref(props.defaultType);
- const isLogin = computed(() => authType.value === 'login');
-
- const countryCode = ref('+86');
- const phone = ref('');
- const verificationCode = ref('');
- const agreeTerms = ref(false);
-
- const countdown = ref(60);
- const countdownActive = ref(false);
-
- const validateForm = () => {
- if (!phone.value) {
- ElMessage.error('请输入手机号');
- return false;
- }
-
- if (!verificationCode.value) {
- ElMessage.error('请输入验证码');
- return false;
- }
-
- if (!agreeTerms.value) {
- ElMessage.error('请同意用户协议和隐私政策');
- return false;
- }
-
- return true;
- };
-
- const sendVerificationCode = async () => {
- if (!phone.value) {
- ElMessage.error('请输入手机号');
- return;
- }
-
- // 简单的手机号格式验证
- const phoneRegex = /^1[3-9]\d{9}$/;
- if (!phoneRegex.test(phone.value)) {
- ElMessage.error('请输入正确的手机号格式');
- return;
- }
-
- try {
- // 调用发送验证码接口
- const response = await authApi.phoneSendCode({
- phone: phone.value
- });
-
- if (response.success) {
- ElMessage.success(`验证码已发送至 ${countryCode.value}${phone.value}`);
-
- // 开始倒计时
- countdownActive.value = true;
- countdown.value = 60;
-
- const timer = setInterval(() => {
- countdown.value--;
- if (countdown.value <= 0) {
- clearInterval(timer);
- countdownActive.value = false;
- }
- }, 1000);
- } else {
- ElMessage.error(response.message || '发送验证码失败,请稍后重试');
- }
- } catch (error) {
- console.error('发送验证码失败:', error);
- ElMessage.error('发送验证码失败,请稍后重试');
- }
- };
-
- const handleSubmit = async () => {
- if (!validateForm()) return;
-
- try {
- if (isLogin.value) {
- // 登录逻辑 - 调用真实API
- const response = await authApi.phoneLogin({
- phone: phone.value,
- code: verificationCode.value
- });
-
- if (response.success && response.result) {
- // 使用store的login方法处理登录成功后的逻辑
- await store.handleLoginSuccess(response.result);
-
- emit('login-success');
- ElMessage.success('登录成功');
- } else {
- throw new Error(response.message || '登录失败');
- }
- } else {
- // 注册逻辑 - 目前使用登录接口,如果后端有单独注册接口可以替换
- const response = await authApi.phoneLogin({
- phone: phone.value,
- code: verificationCode.value
- });
-
- if (response.success && response.result) {
- await store.handleLoginSuccess(response.result);
-
- emit('register-success');
- ElMessage.success('注册成功');
- } else {
- throw new Error(response.message || '注册失败');
- }
- }
-
- // 关闭弹窗
- emit('update:visible', false);
-
- // 重置表单
- resetForm();
- } catch (error) {
- console.error('登录/注册失败:', error);
- ElMessage.error(error.message || '操作失败,请稍后重试');
- }
- };
-
- const switchAuthType = () => {
- authType.value = isLogin.value ? 'register' : 'login';
- };
-
- const resetForm = () => {
- phone.value = '';
- verificationCode.value = '';
- agreeTerms.value = false;
- countdownActive.value = false;
- countdown.value = 60;
- };
-
- return {
- isLogin,
- countryCode,
- phone,
- verificationCode,
- agreeTerms,
- countdown,
- countdownActive,
- sendVerificationCode,
- handleSubmit,
- switchAuthType
- };
- }
- };
- </script>
-
- <style lang="scss" scoped>
- @use '@/assets/styles/variables.scss' as vars;
-
- .login-register-modal {
- // 全局共享样式
- :deep(.el-input__wrapper),
- :deep(.el-input__inner),
- :deep(.el-select .el-input__wrapper),
- :deep(.el-button) {
- height: 44px !important;
- line-height: 44px !important;
- box-sizing: border-box;
- }
-
- :deep(.el-input__wrapper) {
- padding: 0 15px;
- }
-
- :deep(.el-input__inner) {
- font-size: 15px;
- }
-
- // 统一表单控件样式
- :deep(.el-select),
- :deep(.el-input) {
- --el-select-input-focus-border-color: var(--el-color-primary);
- }
-
- // 特别处理select下拉框,使其与输入框完全一致
- :deep(.el-select) {
- width: 100%;
-
- .el-input {
- width: 100%;
- }
- }
-
- // 按钮样式统一
- :deep(.el-button) {
- border: none;
- }
-
- :deep(.el-dialog) {
- border-radius: 8px;
- overflow: hidden;
- }
-
- :deep(.el-dialog__header) {
- padding: 24px 30px;
- text-align: center;
- border-bottom: 1px solid #f0f0f0;
-
- .el-dialog__title {
- font-size: 22px;
- font-weight: bold;
- color: #333;
- }
- }
-
- :deep(.el-dialog__body) {
- padding: 40px 50px;
- }
-
- .auth-form {
- padding: 30px 30px 50px 30px;
- .phone-input {
- display: flex;
- margin-bottom: 24px;
-
- .country-code {
- width: 100px;
- margin-right: 12px;
- flex-shrink: 0;
- }
-
- .el-input {
- flex: 1;
- }
- }
-
- .verification-input {
- display: flex;
- margin-bottom: 30px;
-
- .el-input {
- flex: 1;
- }
-
- .el-button {
- margin-left: 12px;
- width: 120px;
- background-color: vars.$primary-color;
- font-size: 15px;
- padding: 0 15px;
- color: white;
- flex-shrink: 0;
- }
- }
-
- .submit-button {
- width: 100%;
- height: 48px !important;
- line-height: 48px !important;
- background-color: vars.$primary-color;
- margin-bottom: 20px;
- font-size: 16px;
- letter-spacing: 1px;
- }
-
- .form-options {
- display: flex;
- justify-content: center;
- margin-bottom: 25px;
-
- .switch-auth {
- color: vars.$primary-color;
- cursor: pointer;
- font-size: 15px;
-
- &:hover {
- opacity: 0.8;
- text-decoration: underline;
- }
- }
- }
-
- .agreement {
- display: flex;
- align-items: center;
- font-size: 13px;
- color: #666;
- gap: 10px;
-
- a {
- color: vars.$primary-color;
- text-decoration: none;
-
- &:hover {
- text-decoration: underline;
- }
- }
- }
- }
- }
- </style>
|