|
|
@@ -0,0 +1,491 @@
|
|
|
+<!-- 编程课注册页 -->
|
|
|
+<template>
|
|
|
+ <!-- 注册输入框 -->
|
|
|
+ <div class="login-content">
|
|
|
+ <!-- 注册输入框 -->
|
|
|
+ <div class="login-wrapper">
|
|
|
+ <!-- 左侧图片背景盒子 -->
|
|
|
+ <div class="login-left">
|
|
|
+ <img :src="registerBG" alt="背景图片" class="bg-image">
|
|
|
+ </div>
|
|
|
+ <!-- 右侧输入框盒子 -->
|
|
|
+ <div class="login-right">
|
|
|
+ <div class="login-input">
|
|
|
+ <span>{{ appTitle }}</span>
|
|
|
+ <el-form
|
|
|
+ ref="loginFormRef"
|
|
|
+ :model="loginForm"
|
|
|
+ :rules="rules"
|
|
|
+ label-width="0px"
|
|
|
+ class="input-item"
|
|
|
+ >
|
|
|
+ <!-- 学校输入框 -->
|
|
|
+ <el-form-item prop="tenantName" v-if="false">
|
|
|
+ <el-input
|
|
|
+ v-model="loginForm.tenantName"
|
|
|
+ :prefix-icon="HomeFilled"
|
|
|
+ placeholder="请输入学校"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="phone">
|
|
|
+ <el-input
|
|
|
+ v-model="loginForm.phone"
|
|
|
+ :prefix-icon="Iphone"
|
|
|
+ placeholder="请输入手机号"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="password">
|
|
|
+ <el-input
|
|
|
+ v-model="loginForm.password"
|
|
|
+ class="password-input"
|
|
|
+ type="password"
|
|
|
+ :prefix-icon="Lock"
|
|
|
+ placeholder="请输入密码"
|
|
|
+ show-password
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="confirmPassword">
|
|
|
+ <el-input
|
|
|
+ v-model="loginForm.confirmPassword"
|
|
|
+ class="password-input"
|
|
|
+ type="password"
|
|
|
+ :prefix-icon="Lock"
|
|
|
+ placeholder="请再次确认密码"
|
|
|
+ show-password
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="inviteCode">
|
|
|
+ <el-input v-model="loginForm.inviteCode" :prefix-icon="Key" placeholder="请输入邀请码" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 注册按钮 -->
|
|
|
+ <el-form-item>
|
|
|
+ <div class="login-btn-container">
|
|
|
+ <router-link to="" @click.prevent="goBackToLogin" class="register-link">已有账号,去登录</router-link>
|
|
|
+ <el-button @click="handleRegister" class="login-btn" type="primary">注册</el-button>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed, watch } from "vue";
|
|
|
+import { Lock, Iphone, Key, HomeFilled } from '@element-plus/icons-vue';
|
|
|
+import { ElMessage } from 'element-plus';
|
|
|
+import { useRouter } from 'vue-router';
|
|
|
+import homeBG from "@/assets/images/homeBG.png";
|
|
|
+import blocklyBG from "@/assets/images/blocklyBG.png";
|
|
|
+import aiCourseBG from "@/assets/images/aiCourseBG.png";
|
|
|
+import { registerSignUp } from '@/api/login/login.js';
|
|
|
+import { getTenantId } from '@/utils/loginUtils.js';
|
|
|
+
|
|
|
+// 获取环境变量
|
|
|
+const appTitle = ref("注册账号");
|
|
|
+
|
|
|
+const router = useRouter();
|
|
|
+
|
|
|
+const loginFormRef = ref(null);
|
|
|
+
|
|
|
+// 获取查询参数
|
|
|
+const bgImageType = computed(() => router.currentRoute.value.query.bgImage || 'homeBG');
|
|
|
+const loginTypePage = computed(() => router.currentRoute.value.query.loginType || 'login');
|
|
|
+
|
|
|
+// 注册表单数据
|
|
|
+const loginForm = ref({
|
|
|
+ tenantName: "编程课租户", // 学校
|
|
|
+ phone: "", // 手机号
|
|
|
+ password: "", // 密码
|
|
|
+ confirmPassword: "", // 确认密码
|
|
|
+ inviteCode: "", // 邀请码
|
|
|
+ rememberMe: false,
|
|
|
+});
|
|
|
+
|
|
|
+// 判断是否为blocklyLogin类型
|
|
|
+const isBlocklyLogin = computed(() => loginTypePage.value === 'blocklyLogin');
|
|
|
+
|
|
|
+// 设置默认值并监听变化
|
|
|
+watch(isBlocklyLogin, (newVal) => {
|
|
|
+ if (newVal) {
|
|
|
+ loginForm.value.tenantName = '编程课租户';
|
|
|
+ }
|
|
|
+}, { immediate: true });
|
|
|
+
|
|
|
+// 动态选择背景图
|
|
|
+const registerBG = computed(() => {
|
|
|
+ switch(bgImageType.value) {
|
|
|
+ case 'blocklyBG':
|
|
|
+ return blocklyBG;
|
|
|
+ case 'aiCourseBG':
|
|
|
+ return aiCourseBG;
|
|
|
+ default:
|
|
|
+ return homeBG;
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 返回登录页
|
|
|
+const goBackToLogin = () => {
|
|
|
+ let loginPath = '/';
|
|
|
+ switch(loginTypePage.value) {
|
|
|
+ case 'blocklyLogin':
|
|
|
+ loginPath = '/blockly-login';
|
|
|
+ break;
|
|
|
+ case 'aiCourseLogin':
|
|
|
+ loginPath = '/ai-login';
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ loginPath = '/';
|
|
|
+ }
|
|
|
+ router.replace(loginPath);
|
|
|
+};
|
|
|
+
|
|
|
+// 表单验证规则
|
|
|
+const rules = ref({
|
|
|
+ tenantName: [
|
|
|
+ { required: true, message: "请输入学校", trigger: "blur" }
|
|
|
+ ],
|
|
|
+ phone: [
|
|
|
+ { required: true, message: "请输入手机号", trigger: "blur" },
|
|
|
+ { pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号格式", trigger: "blur" }
|
|
|
+ ],
|
|
|
+ password: [
|
|
|
+ { required: true, message: "请输入密码", trigger: "blur" },
|
|
|
+ { min: 6, max: 20, message: "密码长度应在6-20位之间", trigger: "blur" }
|
|
|
+ ],
|
|
|
+ confirmPassword: [
|
|
|
+ { required: true, message: "请确认密码", trigger: "blur" },
|
|
|
+ {
|
|
|
+ validator: (rule, value, callback) => {
|
|
|
+ if (value !== loginForm.value.password) {
|
|
|
+ callback(new Error("两次输入的密码不一致"));
|
|
|
+ } else {
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ trigger: "blur"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ inviteCode: [{ required: true, message: "请输入邀请码", trigger: "blur" }],
|
|
|
+});
|
|
|
+
|
|
|
+// 处理注册
|
|
|
+const handleRegister = async () => {
|
|
|
+
|
|
|
+ if (!loginFormRef.value) return
|
|
|
+ await loginFormRef.value.validate(async valid => {
|
|
|
+ if (valid) {
|
|
|
+// 表单验证
|
|
|
+ try {
|
|
|
+ // 获取租户名称
|
|
|
+ const tenantName = loginForm.value.tenantName;
|
|
|
+
|
|
|
+ if (tenantName === import.meta.env.VITE_APP_TITLE) {
|
|
|
+ ElMessage.error('此租户不支持注册!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取租户ID
|
|
|
+ const tenantId = await getTenantId(tenantName);
|
|
|
+ if (!tenantId) {
|
|
|
+ // 租户验证失败
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 准备请求数据
|
|
|
+ const registerData = {
|
|
|
+ username: loginForm.value.phone,
|
|
|
+ nickname: loginForm.value.phone,
|
|
|
+ password: loginForm.value.password,
|
|
|
+ inviteCode: loginForm.value.inviteCode,
|
|
|
+ rememberMe: loginForm.value.rememberMe,
|
|
|
+ tenantId: tenantId
|
|
|
+ };
|
|
|
+ // 调用注册接口
|
|
|
+ const res = await registerSignUp({ 'Tenant-Id': tenantId },registerData);
|
|
|
+ // 注册成功处理
|
|
|
+ if (res && res.code === 0) {
|
|
|
+ ElMessage.success('注册成功,请登录');
|
|
|
+ goBackToLogin();
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res && res.msg);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('注册失败:', error);
|
|
|
+ ElMessage.error('注册失败,请检查输入信息或网络连接');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+};
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+@use "sass:math";
|
|
|
+// 定义rpx转换函数
|
|
|
+@function rpx($px) {
|
|
|
+ @return math.div($px, 750) * 100vw;
|
|
|
+}
|
|
|
+
|
|
|
+.login-content {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center; // 水平居中
|
|
|
+ align-items: center; // 垂直居中
|
|
|
+ background: linear-gradient(to bottom, #001169, #8a78d0);
|
|
|
+}
|
|
|
+
|
|
|
+.login-wrapper {
|
|
|
+ width: rpx(500); // 固定宽度
|
|
|
+ height: rpx(300); // 固定高度
|
|
|
+ max-width: 90%; // 响应式最大宽度
|
|
|
+ padding: 0;
|
|
|
+ border-radius: rpx(15);
|
|
|
+ box-shadow: 0 rpx(5) rpx(15) rgba(0, 0, 0, 0.3);
|
|
|
+ display: flex;
|
|
|
+ overflow: hidden;
|
|
|
+ background-color: white;
|
|
|
+}
|
|
|
+
|
|
|
+/* 左侧图片背景盒子 */
|
|
|
+.login-left {
|
|
|
+ width: 50%;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+/* 背景图片样式 */
|
|
|
+.bg-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+}
|
|
|
+
|
|
|
+/* 右侧输入框盒子 */
|
|
|
+.login-right {
|
|
|
+ width: 50%;
|
|
|
+ padding: rpx(20);
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ background-color: white;
|
|
|
+}
|
|
|
+.login-input {
|
|
|
+ width: 80%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ flex-direction: column;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+.login-input span {
|
|
|
+ color: black;
|
|
|
+ font-size: rpx(12);
|
|
|
+ padding-bottom: rpx(10);
|
|
|
+ letter-spacing: rpx(1);
|
|
|
+}
|
|
|
+.input-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.el-input ::v-deep(.el-input__wrapper) {
|
|
|
+ border-radius: rpx(5);
|
|
|
+}
|
|
|
+.input-item .el-form-item {
|
|
|
+ margin-bottom: 0;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.input-item .el-input {
|
|
|
+ width: 100%;
|
|
|
+ height: rpx(22);
|
|
|
+ margin-bottom: rpx(15);
|
|
|
+ font-size: rpx(8);
|
|
|
+}
|
|
|
+.el-form-item ::v-deep(.el-form-item__error) {
|
|
|
+ top: rpx(25);
|
|
|
+ font-size: rpx(7);
|
|
|
+}
|
|
|
+
|
|
|
+/* 按钮容器,用于控制按钮位置 */
|
|
|
+.login-btn-container {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.register-link {
|
|
|
+ color: black;
|
|
|
+ font-size: rpx(7);
|
|
|
+ text-decoration: none;
|
|
|
+}
|
|
|
+.register-link:hover {
|
|
|
+ text-decoration: underline;
|
|
|
+}
|
|
|
+.login-btn {
|
|
|
+ width: rpx(65); /* 缩小宽度 */
|
|
|
+ height: rpx(20);
|
|
|
+ color: black;
|
|
|
+ font-size: rpx(9);
|
|
|
+ letter-spacing: rpx(4); /* 调整字间距以适应较小宽度 */
|
|
|
+ border-radius: rpx(5);
|
|
|
+ margin: 0;
|
|
|
+ border: none;
|
|
|
+ outline: none;
|
|
|
+ background: linear-gradient(to bottom, #fee78a, #ffce1b);
|
|
|
+ box-shadow: 0 rpx(4) rpx(4) rgb(0, 0, 0, 0.2);
|
|
|
+}
|
|
|
+.check-box {
|
|
|
+ width: 100%;
|
|
|
+ height: rpx(18);
|
|
|
+ margin: rpx(10) 0;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.check-box .el-checkbox {
|
|
|
+ color: white;
|
|
|
+ padding-right: rpx(10);
|
|
|
+ font-size: rpx(7);
|
|
|
+}
|
|
|
+.el-checkbox ::v-deep(.el-checkbox__label) {
|
|
|
+ font-size: rpx(7);
|
|
|
+}
|
|
|
+.el-checkbox ::v-deep(.el-checkbox__label) {
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+// 移动端响应式设计
|
|
|
+@media screen and (max-width: 768px) {
|
|
|
+ .login-content {
|
|
|
+ flex-direction: column;
|
|
|
+ background: url('@/assets/images/homeBG.png') no-repeat center center fixed;
|
|
|
+ background-size: cover;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bg-image-container {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ z-index: -1;
|
|
|
+ background-size: cover;
|
|
|
+ background-position: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-wrapper {
|
|
|
+ flex: none;
|
|
|
+ width: 70%;
|
|
|
+ margin: 0 auto;
|
|
|
+ padding: 30px;
|
|
|
+ border-radius: 15px;
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ min-height: 40%;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-left{
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+ .login-right{
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-input {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-input span {
|
|
|
+ font-size: rpx(18);
|
|
|
+ padding-bottom: rpx(20);
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-item {
|
|
|
+ width: 100%;
|
|
|
+ align-items: stretch;
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-item .el-input {
|
|
|
+ width: 100% !important;
|
|
|
+ max-width: none;
|
|
|
+ height: rpx(45) !important;
|
|
|
+ font-size: rpx(14) !important;
|
|
|
+ margin-bottom: rpx(25) !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input ::v-deep(.el-input__wrapper) {
|
|
|
+ height: rpx(45) !important;
|
|
|
+ border-radius: rpx(15);
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input ::v-deep(.el-input__inner) {
|
|
|
+ height: rpx(45) !important;
|
|
|
+ font-size: rpx(14) !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-btn {
|
|
|
+ width: 40% !important;
|
|
|
+ max-width: none;
|
|
|
+ height: rpx(45) !important;
|
|
|
+ font-size: rpx(16) !important;
|
|
|
+ margin: rpx(25) 0 !important;
|
|
|
+ letter-spacing: rpx(15);
|
|
|
+ border-radius: rpx(10);
|
|
|
+ }
|
|
|
+
|
|
|
+ .check-box {
|
|
|
+ width: 100% !important;
|
|
|
+ max-width: none;
|
|
|
+ height: auto;
|
|
|
+ margin: rpx(15) 0 !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .check-box .el-checkbox {
|
|
|
+ font-size: rpx(12) !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-checkbox ::v-deep(.el-checkbox__label) {
|
|
|
+ font-size: rpx(12) !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .sms-code-container {
|
|
|
+ width: 100% !important;
|
|
|
+ max-width: none;
|
|
|
+ height: rpx(45) !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .sms-input {
|
|
|
+ width: calc(100% - rpx(75)) !important;
|
|
|
+ height: rpx(45) !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .get-code-btn {
|
|
|
+ width: rpx(75) !important;
|
|
|
+ height: rpx(45) !important;
|
|
|
+ font-size: rpx(10) !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-form-item ::v-deep(.el-form-item__error) {
|
|
|
+ top: rpx(50) !important;
|
|
|
+ font-size: rpx(10) !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|