767 lines
19 KiB
Vue
767 lines
19 KiB
Vue
<template>
|
||
<div class="main-box">
|
||
<!-- 背景图片 -->
|
||
<div class="imgStyle" v-if="logoImg">
|
||
<img style="width: 100vw;height: 100vh;" src="../../assets/kyy/register-bg.png" alt="">
|
||
</div>
|
||
<div class="imgStyle" v-else>
|
||
<img style="width: 100vw;height: 100vh;background-position: center center" src="../../assets/kyy/register-bg.png"
|
||
alt="">
|
||
</div>
|
||
|
||
<!-- 头部图标 -->
|
||
<img @click="goHomePage" style="cursor: pointer" class="logo-top1" :src="logoImg" alt="" v-if="isLogo && isShow">
|
||
<img @click="goHomePage" style="cursor: pointer" class="logo-top" src="../../assets/kyy/LOGONew.png" alt=""
|
||
v-else-if="isShow">
|
||
|
||
<!-- 注册表单 -->
|
||
<div class="register-form">
|
||
<div class="regist-container">
|
||
<el-form ref="registForm" :model="registForm" :rules="rules" class="regist-form" autocomplete="on"
|
||
label-position="left" style="z-index: 1">
|
||
<!-- 表单标题区域 -->
|
||
<div class="title-container">
|
||
<span class="title">注册</span>
|
||
<span class="subtitle" @click="handleLogin">前往登录 ></span>
|
||
</div>
|
||
|
||
<!-- 手机号输入区域 -->
|
||
<div class="form-row">
|
||
<el-form-item prop="mobile" class="form-item-custom full-width">
|
||
<div class="form-item">
|
||
<span class="svg-container country-code">
|
||
+86
|
||
</span>
|
||
<el-input ref="mobile" v-model="registForm.mobile" placeholder="请输入手机号" type="text"
|
||
class="custom-input" />
|
||
</div>
|
||
</el-form-item>
|
||
</div>
|
||
|
||
<!-- 验证码输入区域 -->
|
||
<div class="form-row">
|
||
<el-form-item prop="vcode" class="form-item-custom full-width">
|
||
<div class="form-item">
|
||
<span class="svg-container">
|
||
验证码
|
||
</span>
|
||
<el-input ref="vcode" v-model="registForm.vcode" placeholder="请输入验证码" type="text"
|
||
class="custom-input" />
|
||
<span class="get-code-btn" @click="getSmsCode" :class="{ disabled: countdown > 0 }">
|
||
{{ countdown > 0 ? `${countdown}s后重新获取` : '获取验证码' }}
|
||
</span>
|
||
</div>
|
||
</el-form-item>
|
||
</div>
|
||
|
||
<!-- 信息补充区域标题 -->
|
||
<div class="info-supplement">
|
||
<span class="info-title">信息补充(可跳过)</span>
|
||
</div>
|
||
|
||
<!-- 账户名输入区域(非必填) -->
|
||
<div class="form-row">
|
||
<el-form-item class="form-item-custom full-width">
|
||
<div class="form-item">
|
||
<span class="svg-container">
|
||
账户名
|
||
</span>
|
||
<el-input ref="username" v-model="registForm.username" placeholder="请输入账户名(默认手机号)" name="username" type="text"
|
||
class="custom-input" />
|
||
</div>
|
||
</el-form-item>
|
||
</div>
|
||
|
||
<!-- 密码输入区域(非必填) -->
|
||
<div class="form-row">
|
||
<el-form-item class="form-item-custom full-width">
|
||
<div class="form-item">
|
||
<span class="svg-container">
|
||
密码
|
||
</span>
|
||
<el-input :key="passwordType" ref="password" v-model="registForm.password" :type="passwordType"
|
||
placeholder="请输入密码" name="password" class="custom-input" />
|
||
<span class="show-pwd" @click="showPwd">
|
||
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
|
||
</span>
|
||
</div>
|
||
</el-form-item>
|
||
</div>
|
||
|
||
<!-- 用户协议勾选区域 -->
|
||
<div class="agreement">
|
||
<el-checkbox v-model="agreeProtocol">
|
||
我已阅读并同意《用户协议》、《隐私政策》、《产品服务协议》
|
||
</el-checkbox>
|
||
</div>
|
||
|
||
<!-- 注册按钮区域 -->
|
||
<div class="twoBtn">
|
||
<el-button class="register-btn" :loading="loading" type="primary"
|
||
@click.native.prevent="handleRegister('registForm')">
|
||
立即注册
|
||
</el-button>
|
||
</div>
|
||
</el-form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { getLogoAPI, register, sendCode } from "@/api/login";
|
||
import { cityArr } from '@/assets/province.js'
|
||
import { mapState } from "vuex";
|
||
import { getHomePath } from '@/views/setting/tools'
|
||
|
||
export default {
|
||
name: "indexNew",
|
||
data() {
|
||
return {
|
||
// 显示控制
|
||
isShow: false,
|
||
isLogo: false,
|
||
logoUrlOut: '',
|
||
logoImg: require("../../assets/kyy/LOGO.png"),
|
||
logoText: "开元云",
|
||
photosUrl: null,
|
||
|
||
// 用户协议勾选状态
|
||
agreeProtocol: false,
|
||
// 验证码倒计时秒数
|
||
countdown: 0,
|
||
// 倒计时定时器
|
||
countdownTimer: null,
|
||
// 短信验证码的codeid
|
||
codeid: '',
|
||
|
||
// 当前页面URL
|
||
url: window.location.href,
|
||
value: '',
|
||
// 注册表单数据
|
||
registForm: {
|
||
mobile: "", // 手机号(必填)
|
||
vcode: "", // 验证码(必填)
|
||
username: "", // 账户名(非必填,默认手机号)
|
||
password: "", // 密码(非必填)
|
||
org_type: "2", // 机构类型(必填,固定为2)
|
||
wechat_openid: localStorage.getItem('wechat_openid') || "", // 微信openid(默认为空)
|
||
domain_name: "" // 域名
|
||
},
|
||
|
||
// 表单验证规则
|
||
rules: {
|
||
// 手机号验证规则
|
||
mobile: [
|
||
{
|
||
pattern: /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/,
|
||
message: "请输入有效的手机号",
|
||
},
|
||
{ required: true, trigger: "blur", message: "请输入手机号" },
|
||
],
|
||
// 验证码验证规则
|
||
vcode: [
|
||
{ required: true, message: "请输入验证码", trigger: "blur" }
|
||
]
|
||
},
|
||
// 密码显示类型(password/text)
|
||
passwordType: "password",
|
||
// 注册按钮加载状态
|
||
loading: false,
|
||
redirect: undefined,
|
||
otherQuery: {},
|
||
};
|
||
},
|
||
|
||
// 组件创建时调用
|
||
created() {
|
||
this.init();
|
||
},
|
||
|
||
// 组件挂载后调用
|
||
mounted() {
|
||
// 初始化域名
|
||
this.registForm.domain_name = window.location.hostname;
|
||
},
|
||
|
||
computed: {
|
||
// 从Vuex获取微信openid
|
||
...mapState({
|
||
wechat_openid: state => state.login.wechat_openid,
|
||
}),
|
||
},
|
||
|
||
methods: {
|
||
// 跳转到首页
|
||
goHomePage() {
|
||
if (this.logoUrlOut) {
|
||
window.location.href = this.logoUrlOut
|
||
} else {
|
||
window.location.href = 'https://www.opencomputing.cn/';
|
||
}
|
||
},
|
||
|
||
// 获取城市数据
|
||
cityArr() {
|
||
return cityArr;
|
||
},
|
||
|
||
// 初始化函数 - 获取Logo等信息
|
||
init() {
|
||
let params = {
|
||
url_link: this.GetQueryString(this.url)
|
||
};
|
||
|
||
getLogoAPI(params).then((res) => {
|
||
if (res.status == true && res.data && res.data.length) {
|
||
this.$store.commit('setLogoInfo', res.data[0]);
|
||
this.isShow = true
|
||
this.$store.commit('setLogoInfoNew', res.data[0].additional_msg);
|
||
|
||
// 特殊机构处理
|
||
if (res.data[0].orgname == '中关村数智人工智能产业联盟') {
|
||
this.logoUrlOut = 'https://www.ncmatch.cn'
|
||
}
|
||
|
||
this.photosUrl = res.data[0];
|
||
if (this.photosUrl.orgname != '业主机构') {
|
||
this.isLogo = true
|
||
this.logoImg = this.photosUrl.logo;
|
||
this.$store.commit('setLogo', this.photosUrl.logo)
|
||
this.logoText = this.photosUrl.orgname;
|
||
} else {
|
||
this.$store.commit('setLogo', "")
|
||
}
|
||
} else {
|
||
this.$message({
|
||
message: "获取ipc失败~",
|
||
type: "error",
|
||
});
|
||
}
|
||
});
|
||
},
|
||
|
||
// 从URL中获取查询参数
|
||
GetQueryString(name) {
|
||
if (name.indexOf("#") != -1) {
|
||
const params = name.split("#")[0];
|
||
return params;
|
||
}
|
||
},
|
||
|
||
// 显示/隐藏密码
|
||
showPwd() {
|
||
if (this.passwordType === "password") {
|
||
this.passwordType = "";
|
||
} else {
|
||
this.passwordType = "password";
|
||
}
|
||
this.$nextTick(() => {
|
||
this.$refs.password.focus();
|
||
});
|
||
},
|
||
|
||
// 获取短信验证码
|
||
async getSmsCode() {
|
||
// 如果正在倒计时,直接返回
|
||
if (this.countdown > 0) return;
|
||
|
||
// 验证手机号是否为空
|
||
if (!this.registForm.mobile) {
|
||
this.$message({
|
||
message: "请输入手机号",
|
||
type: "error",
|
||
});
|
||
return;
|
||
}
|
||
|
||
const mobileRegex = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
|
||
if (!mobileRegex.test(this.registForm.mobile)) {
|
||
this.$message({
|
||
message: "请输入有效的手机号",
|
||
type: "error",
|
||
});
|
||
return;
|
||
}
|
||
|
||
let params = {
|
||
mobile: this.registForm.mobile,
|
||
action_type: "register",
|
||
};
|
||
|
||
try {
|
||
let res = await sendCode(params)
|
||
console.log('短信验证码完整响应:', res);
|
||
|
||
if (res.status == true) {
|
||
this.$message({
|
||
message: "验证码已发送",
|
||
type: "success",
|
||
});
|
||
let codeid = '';
|
||
|
||
// 尝试从不同的响应结构获取 codeid
|
||
if (res.data && res.data.codeid) {
|
||
// 结构: { data: { codeid: 'xxx' } }
|
||
codeid = res.data.codeid;
|
||
} else if (res.codeid) {
|
||
// 结构: { codeid: 'xxx' }
|
||
codeid = res.codeid;
|
||
} else if (res.data && typeof res.data === 'string') {
|
||
// 结构: { data: 'xxx' } 且 data 直接是 codeid
|
||
codeid = res.data;
|
||
} else if (res.data && res.data.data && res.data.data.codeid) {
|
||
// 结构: { data: { data: { codeid: 'xxx' } } }
|
||
codeid = res.data.data.codeid;
|
||
} else {
|
||
// 如果都没有找到,使用手机号和时间戳生成一个临时的 codeid
|
||
console.warn('无法从响应中获取 codeid,使用临时值。响应结构:', res);
|
||
codeid = `temp_${this.registForm.mobile}_${Date.now()}`;
|
||
}
|
||
|
||
this.codeid = codeid;
|
||
console.log('最终获取的 codeid:', this.codeid);
|
||
|
||
// 开始倒计时
|
||
this.startCountdown();
|
||
} else {
|
||
this.$message({
|
||
message: res.msg,
|
||
type: "error",
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('发送验证码失败:', error);
|
||
|
||
}
|
||
},
|
||
|
||
// 开始验证码倒计时
|
||
startCountdown() {
|
||
this.countdown = 60;
|
||
this.countdownTimer = setInterval(() => {
|
||
this.countdown--;
|
||
if (this.countdown <= 0) {
|
||
clearInterval(this.countdownTimer);
|
||
}
|
||
}, 1000);
|
||
},
|
||
|
||
// 跳转到登录页面
|
||
handleLogin() {
|
||
this.$router.push({ name: "Login" });
|
||
},
|
||
|
||
// 注册处理函数
|
||
handleRegister(formName) {
|
||
// 第一步:检查用户是否同意协议
|
||
if (!this.agreeProtocol) {
|
||
this.$message({
|
||
message: "请先阅读并同意用户协议",
|
||
type: "error",
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 第二步:进行表单验证
|
||
this.$refs[formName].validate((valid) => {
|
||
if (valid) {
|
||
// 表单验证通过,开始注册流程
|
||
this.loading = true;
|
||
|
||
// 第三步:构建注册数据
|
||
const registerData = {
|
||
mobile: this.registForm.mobile, // 手机号(必填)
|
||
vcode: this.registForm.vcode, // 验证码(必填)
|
||
codeid: this.codeid, // 短信接口返回的codeid(必填)
|
||
org_type: "2", // 机构类型(必填,固定为2)
|
||
username: this.registForm.username || this.registForm.mobile, // 用户名(默认手机号)
|
||
password: this.registForm.password, // 密码
|
||
nick_name: this.registForm.mobile, // 显示名(默认手机号)
|
||
wechat_openid: this.registForm.wechat_openid, // 微信openid(默认为空)
|
||
domain_name: this.registForm.domain_name || window.location.hostname // 域名
|
||
};
|
||
|
||
console.log('注册参数:', registerData);
|
||
|
||
// 第四步:调用注册API
|
||
register(registerData).then((res) => {
|
||
this.loading = false;
|
||
console.log('注册返回:', res);
|
||
if (res.status == true) {
|
||
// 注册成功
|
||
this.$message({
|
||
message: "注册成功",
|
||
type: "success",
|
||
});
|
||
// 跳转到登录页面
|
||
this.$router.push({ name: "Login" });
|
||
} else {
|
||
// 注册失败,显示错误信息
|
||
this.$message({
|
||
message: res.message || res.msg || "注册失败",
|
||
type: "error",
|
||
});
|
||
}
|
||
}).catch((error) => {
|
||
// 网络错误处理
|
||
console.error('注册失败:', error);
|
||
this.loading = false;
|
||
this.$message({
|
||
message: "注册失败,请重试",
|
||
type: "error",
|
||
});
|
||
});
|
||
} else {
|
||
// 表单验证失败
|
||
this.$message({
|
||
message: "请填写正确的手机号和验证码",
|
||
type: "error",
|
||
});
|
||
}
|
||
});
|
||
},
|
||
},
|
||
|
||
// 组件销毁前清理定时器
|
||
beforeDestroy() {
|
||
if (this.countdownTimer) {
|
||
clearInterval(this.countdownTimer);
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
// 定义样式变量
|
||
$cursor: black;
|
||
$primary-color: #409EFF;
|
||
$border-color: #E4E7ED;
|
||
$background-color: #F5F7FA;
|
||
$light-gray: #909399;
|
||
|
||
// 主容器样式
|
||
.main-box {
|
||
position: relative;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
overflow: hidden;
|
||
|
||
img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
}
|
||
|
||
// 头部图标样式
|
||
.logo-top {
|
||
width: 200px !important;
|
||
height: 70px !important;
|
||
position: absolute;
|
||
top: 2%;
|
||
left: 2%;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.logo-top1 {
|
||
width: 260px !important;
|
||
height: 80px !important;
|
||
position: absolute;
|
||
top: 3%;
|
||
left: 3%;
|
||
z-index: 1000;
|
||
}
|
||
|
||
// 注册表单容器样式
|
||
.register-form {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 90%;
|
||
max-width: 480px;
|
||
min-height: 560px;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
border-radius: 16px;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||
backdrop-filter: blur(10px);
|
||
overflow: hidden;
|
||
z-index: 999;
|
||
}
|
||
|
||
// 注册内容区域样式
|
||
.regist-container {
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 40px 35px;
|
||
|
||
.regist-form {
|
||
width: 100%;
|
||
}
|
||
|
||
// 标题区域样式
|
||
.title-container {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 30px;
|
||
|
||
.title {
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
}
|
||
|
||
.subtitle {
|
||
font-size: 14px;
|
||
color: $primary-color;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
text-decoration: underline;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 表单行样式
|
||
.form-row {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
// 表单项样式
|
||
.form-item-custom {
|
||
margin-bottom: 0;
|
||
|
||
&.full-width {
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
// 表单项目样式
|
||
.form-item {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
height: 48px;
|
||
background: white;
|
||
border: 1px solid $border-color;
|
||
border-radius: 8px;
|
||
transition: all 0.3s ease;
|
||
position: relative;
|
||
|
||
&:hover {
|
||
border-color: $primary-color;
|
||
}
|
||
|
||
&:focus-within {
|
||
border-color: $primary-color;
|
||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||
}
|
||
}
|
||
|
||
// 图标容器样式
|
||
.svg-container {
|
||
padding: 0 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100%;
|
||
color: #606266;
|
||
font-size: 14px;
|
||
background: #f8f9fa;
|
||
border-right: 1px solid $border-color;
|
||
border-radius: 8px 0 0 8px;
|
||
min-width: 80px;
|
||
|
||
&.country-code {
|
||
min-width: 60px;
|
||
background: transparent;
|
||
border-right: none;
|
||
color: #303133;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
// 自定义输入框样式
|
||
.custom-input {
|
||
flex: 1;
|
||
border: none !important;
|
||
outline: none !important;
|
||
background: transparent;
|
||
height: 100%;
|
||
|
||
::v-deep .el-input__inner {
|
||
border: none !important;
|
||
background: transparent !important;
|
||
height: 46px;
|
||
padding: 0 16px;
|
||
font-size: 14px;
|
||
|
||
&:focus {
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
}
|
||
|
||
&::placeholder {
|
||
color: $light-gray;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获取验证码按钮样式
|
||
.get-code-btn {
|
||
position: absolute;
|
||
right: 12px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
color: $primary-color;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
background: none;
|
||
border: none;
|
||
padding: 4px 8px;
|
||
border-radius: 4px;
|
||
transition: background-color 0.3s ease;
|
||
white-space: nowrap;
|
||
|
||
&:hover {
|
||
background: rgba(64, 158, 255, 0.1);
|
||
}
|
||
|
||
&.disabled {
|
||
color: $light-gray;
|
||
cursor: not-allowed;
|
||
|
||
&:hover {
|
||
background: none;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 显示密码按钮样式
|
||
.show-pwd {
|
||
position: absolute;
|
||
right: 12px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
font-size: 16px;
|
||
color: #909399;
|
||
cursor: pointer;
|
||
z-index: 2;
|
||
}
|
||
|
||
// 信息补充区域样式
|
||
.info-supplement {
|
||
margin: 24px 0 16px 0;
|
||
padding-bottom: 8px;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
|
||
.info-title {
|
||
font-size: 14px;
|
||
color: $light-gray;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
// 协议勾选区域样式
|
||
.agreement {
|
||
margin: 20px 0;
|
||
|
||
::v-deep .el-checkbox {
|
||
.el-checkbox__label {
|
||
font-size: 14px;
|
||
color: #606266;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 按钮区域样式
|
||
.twoBtn {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
margin-top: 30px;
|
||
}
|
||
|
||
// 注册按钮样式
|
||
.register-btn {
|
||
width: 100%;
|
||
height: 48px;
|
||
background: $primary-color;
|
||
border: none;
|
||
border-radius: 8px;
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
color: white;
|
||
transition: all 0.3s ease;
|
||
|
||
&:hover {
|
||
background: #66b1ff;
|
||
transform: translateY(-1px);
|
||
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
|
||
}
|
||
|
||
&:active {
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 响应式设计 - 移动端适配
|
||
@media (max-width: 768px) {
|
||
.register-form {
|
||
width: 95%;
|
||
min-width: unset;
|
||
height: auto;
|
||
max-height: 90vh;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.regist-container {
|
||
padding: 24px 20px;
|
||
}
|
||
|
||
// 移动端调整头部图标大小
|
||
.logo-top {
|
||
width: 150px !important;
|
||
height: 52px !important;
|
||
}
|
||
|
||
.logo-top1 {
|
||
width: 200px !important;
|
||
height: 62px !important;
|
||
}
|
||
}
|
||
|
||
// 动画效果
|
||
.fade-enter-active,
|
||
.fade-leave-active {
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.fade-enter,
|
||
.fade-leave-to {
|
||
opacity: 0;
|
||
}
|
||
|
||
// 自定义滚动条样式
|
||
::-webkit-scrollbar {
|
||
width: 6px;
|
||
}
|
||
|
||
::-webkit-scrollbar-track {
|
||
background: #f1f1f1;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb {
|
||
background: #c1c1c1;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb:hover {
|
||
background: #a8a8a8;
|
||
}
|
||
</style>
|