88a5d542 by simon

Merge branch 'master' of 120.27.44.69:dev/pingan-life-index-pro

2 parents e4b1fe00 0125693b
NODE_ENV = 'sandbox'
VUE_APP_TITLE = 'sandbox'
REQUEST_DOMAIN= 'https://ow.go.qudone.com'
RSA_PUBLIC_KEY = 'B5FE03847F02046C47292AF0FF2DE88977241483DD40C123046EB39CBE4C48167B120096CFF12CD16559322884A3C56FA92B07B89AB51FC8C91A75127622151DDD730DFF1F993D5A290CEAC0BBA7FC88285D8994ACBAFF50101EDE9A0925AD5DFFAFE96D53C370E9C5B37DF2F871F81C4D7CA6B7EC37FF459C07975AD9A74A95'
RSA_KEY_INDEX = '10001'
\ No newline at end of file
......
......@@ -18,6 +18,7 @@
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="./js/unionrsa.js"></script>
</body>
</html>
......
......@@ -2,7 +2,7 @@
<div id="app">
<v-header></v-header>
<main ref="container" class="main-container">
<router-view/>
<router-view />
</main>
<v-footer></v-footer>
</div>
......@@ -11,6 +11,7 @@
<script>
import { mapGetters, mapActions, mapState } from "vuex";
import { getCookie } from "@utils/utils.js";
import VHeader from "@components/home/header/header.vue";
import VFooter from "@components/home/footer/footer.vue";
var UA = require("ua-device");
......@@ -36,6 +37,15 @@ export default {
let deviceType = output.device.type;
let isMobile = deviceType == "mobile";
this.$store.commit("IS_MOBILE", isMobile);
//
let userInfoStr = decodeURIComponent(getCookie("_user_profile"));
if (userInfoStr) {
try {
let userInfo = JSON.parse(decodeURIComponent(userInfoStr));
this.$store.commit("SET_USER_INFO", userInfo);
} catch (e) {}
}
}
};
</script>
......@@ -44,7 +54,7 @@ export default {
@import "@/styles/_support";
html {
font-family: "Microsoft YaHei","Arial";
font-family: "Microsoft YaHei", "Arial";
font-size: 12px;
word-spacing: 1px;
word-break: break-word;
......
module.exports = {
testListGet: '/xxx/xxx/list'
logout : "/pingan_hklife_webapi/logout",
// 是否显示图形验证码接口
stdIsShowImageVcode : "/pingan_hklife_webapi/auth/stdIsShowImageVcode",
// 刷新图形验证码接口
stdRefreshVcode : "/pingan_hklife_webapi/auth/stdRefreshVcode",
// OTP发送接口
stdSendOTP : "/pingan_hklife_webapi/auth/stdSendOTP",
// OTP验证与验重接口
stdValidateOTPandRepeat : "/pingan_hklife_webapi/auth/stdValidateOTPandRepeat",
// 注册手机号验重接口
gsRegCheck : "/pingan_hklife_webapi/auth/gsRegCheck",
// 账户整合登录接口
gsLogin : "/pingan_hklife_webapi/auth/gsLogin",
// 注册接口
stdRegister : "/pingan_hklife_webapi/auth/stdRegister",
// 找回密码定位用户信息
gsLocateUserV2 : "/pingan_hklife_webapi/auth/gsLocateUserV2",
// 账户整合忘记密码重置用户密码
gsResetPwd : "/pingan_hklife_webapi/auth/gsResetPwd",
// 账户整合修改密码接口
gsModifyPwd : "/pingan_hklife_webapi/auth/gsModifyPwd",
// 短信验证码登录
otpLogin : "/pingan_hklife_webapi/otpLogin",
}
\ No newline at end of file
......
......@@ -11,10 +11,7 @@ function Toast(msg) {
// axios.defaults.baseURL = ""
// 服务器地址
let base = "https://ow.go.qudone.com";
if (location.href.indexOf("//k.wxpai.cn") > 0) {
base = "https://api.k.wxpai.cn/bizproxy"
}
let base = process.env.REQUEST_DOMAIN || "http://localhost:9101";
// let base = COM.baseUrl;
// 请求拦截器
......
......@@ -15,21 +15,25 @@ module.exports = {
list: [{
name: "register",
path: "/register",
type : "noAuth",
value: ""
}, {
name: "login",
path: "/login",
type : "noAuth",
value: ""
},
{
name: "modify password",
path: "",
type : "auth",
value: ""
},
{
name: "logout",
path: "",
value: ""
type : "auth",
value: "logout"
},
]
},
......@@ -133,6 +137,18 @@ module.exports = {
verifyCodeGet: "獲取驗證碼",
},
register: {
mobileOptions: [{
type: "hk",
name: "香港手機號",
placeHolder: "請輸入8位手機號碼",
areaCode: "+852"
}, {
type: "zh",
name: "大陸手機號",
placeHolder: "請輸入11位手機號碼",
areaCode: "+86"
}],
coutTips : "{second}秒後重新獲取",
title: "歡迎註冊一賬通",
title2: "請設置新的密碼",
mobilePlaceholder: "请输入8位手机号码",
......
......@@ -15,23 +15,26 @@ module.exports = {
list: [{
name: "註冊",
path: "/register",
type: "noAuth",
value: ""
}, {
name: "登入",
path: "/login",
type: "noAuth",
value: ""
},
{
name: "修改密碼",
path: "",
type: "auth",
value: ""
},
{
name: "登出",
path: "",
value: ""
},
]
type: "auth",
value: "logout"
}]
},
navList: [{
name: "產品介紹",
......@@ -133,6 +136,18 @@ module.exports = {
verifyCodeGet: "獲取驗證碼",
},
register: {
mobileOptions: [{
type: "hk",
name: "香港手機號",
placeHolder: "請輸入8位手機號碼",
areaCode: "+852"
}, {
type: "zh",
name: "大陸手機號",
placeHolder: "請輸入11位手機號碼",
areaCode: "+86"
}],
coutTips : "{second}秒後重新獲取",
title: "歡迎註冊一賬通",
title2: "請設置新的密碼",
mobilePlaceholder: "請輸入8位手機號碼",
......
......@@ -15,23 +15,26 @@ module.exports = {
list: [{
name: "注册",
path: "/register",
type: "noAuth",
value: ""
}, {
name: "登陆",
path: "/login",
type: "noAuth",
value: ""
},
{
name: "修改密码",
path: "",
type: "auth",
value: ""
},
{
name: "登出",
path: "",
value: ""
},
]
type: "auth",
value: "logout"
}]
},
navList: [{
name: "产品介绍",
......@@ -133,6 +136,18 @@ module.exports = {
verifyCodeGet: "获取验证码",
},
register: {
mobileOptions: [{
type: "hk",
name: "香港手机号",
placeHolder: "请输入8位手机号码",
areaCode: "+852"
}, {
type: "zh",
name: "大陆手机号",
placeHolder: "请输入11位手机号码",
areaCode: "+86"
}],
coutTips : "{second}秒后重新获取",
title: "欢迎注册一账通",
title2: "请设置新的密码",
mobilePlaceholder: "请输入8位手机号码",
......
......@@ -2,6 +2,9 @@ import {
mapState
} from 'vuex'
import api from '@/api/api'
import { httpPost } from '@/api/fetch-api.js'
export default {
name: "DropDownList",
data() {
......@@ -13,25 +16,25 @@ export default {
props: {
type: {
type: String,
default () {
default() {
return "nav";
}
},
dataObj: {
type: Object,
default () {
default() {
return {};
}
},
dataList: {
type: Array,
default () {
default() {
return [];
}
},
labelProperty: {
type: String,
default () {
default() {
return "name";
}
}
......@@ -81,16 +84,32 @@ export default {
this.sTitle = curData.name;
window.location.reload();
} else {
// console.log("curData.value == =", curData.value)
if (curData.value == "logout") {
// this.$store.commit("SET_USER_INFO", null);
this._loginHandler();
} else {
// 不是的话,跳转页面
this.$router.push({
path: curData.path
})
}
}
// console.log("name:", this.dataList[index].name);
// this.$emit("change", {
// index: index,
// value: this.dataList[index]
// });
},
_loginHandler() {
httpPost({ url: api.logout }).then(() => {
this.$store.commit("SET_USER_INFO", null);
this._showLogoutTip();
});
},
_showLogoutTip() {
// 登出后的提示
alert("登出成功");
}
},
computed: {
......
......@@ -57,6 +57,13 @@
justify-content: center;
color: #ffffff;
span {
max-width: 4.25rem ;/* 51/12 */
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.icon-img {
margin: 0 .5rem;
}
......
......@@ -4,7 +4,8 @@
<!-- 登陆下拉样式 -->
<template v-if="type=='login'">
<div class="user">
<img class="icon-img" src="@/assets/images/home/icon-user.png"> {{dataObj.name}}
<img class="icon-img" src="@/assets/images/home/icon-user.png">
<span>{{dataObj.name}}</span>
</div>
</template>
<!-- 其他下拉样式 -->
......
......@@ -46,7 +46,8 @@ export default {
},
computed: {
...mapState({
isSmallScreen: state => state.isSmallScreen
isSmallScreen: state => state.isSmallScreen,
userInfo: state => state.userInfo
})
},
methods: {
......@@ -65,10 +66,33 @@ export default {
},
initData() {
let i18n = this.$i18n.messages[this.$i18n.locale] || {};
this.loginData = i18n.nav.loginData;
// this.loginData = i18n.nav.loginData;
this._buildLoginMenu();
this.navList = i18n.nav.navList;
let curLang = getObjByListKeyValue(this.$i18n.locale, "value", this.langData.list)
this.langData.name = curLang.name;
},
_buildLoginMenu() {
// 构建登录页
let i18n = this.$i18n.messages[this.$i18n.locale] || {};
let menuData = JSON.parse(JSON.stringify(i18n.nav.loginData));
let list = [];
if (this.userInfo && this.userInfo.name) {
menuData.name = this.userInfo.name;
menuData.list.forEach(element => {
if (element.type == "auth") {
list.push(element);
}
});
} else {
menuData.list.forEach(element => {
if (element.type == "noAuth") {
list.push(element);
}
});
}
menuData.list = list;
this.$set(this, 'loginData', menuData);
}
},
mounted() {
......@@ -78,6 +102,11 @@ export default {
self.checkIsSmallScreen();
}
},
watch: {
userInfo(val) {
this._buildLoginMenu();
}
},
created() {
this.initData();
},
......
......@@ -7,7 +7,7 @@ import store from './store/index';
import VueAwesomeSwiper from 'vue-awesome-swiper'
// require styles
import 'swiper/dist/css/swiper.css'
Vue.use(VueAwesomeSwiper, /* { default global options } */ )
Vue.use(VueAwesomeSwiper)
import Mock from './mock'
......
import { mapGetters, mapActions, mapState } from "vuex";
import api from '@/api/api'
import {
httpGet,
httpPost
} from '@/api/fetch-api.js'
let PK = 'B5FE03847F02046C47292AF0FF2DE88977241483DD40C123046EB39CBE4C48167B120096CFF12CD16559322884A3C56FA92B07B89AB51FC8C91A75127622151DDD730DFF1F993D5A290CEAC0BBA7FC88285D8994ACBAFF50101EDE9A0925AD5DFFAFE96D53C370E9C5B37DF2F871F81C4D7CA6B7EC37FF459C07975AD9A74A95';
let E = '10001';
export default {
data() {
return {
key: 'value',
type: 1, // 1:帐密登陆 2:OTP登陆
type: 1, // 1:帐密登陆 2:OTP登陆,
values: {
// 返回的token,串连整个流程,后台安全校验使用
token: "",
deviceId: "",
vcodeuuid: "",
token: "",
deviceId: "",
imageBase64: "",
password: "",
passwordRepeat: ""
},
times: {
interval: 0, // 索引
remain: 0, // 剩余时间
tip: "" // 显示的文字
},
loginForm: {
// userId: "18334783910",
// password: "qweqwe123"
userId: "",
password: "",
imageValue: "",
mobileNo: "",
otp: ""
},
loginCheck: {
showImageCode: false,
agreeProtocol: false
},
PK: process.env.RSA_PUBLIC_KEY || PK,
E: process.env.RSA_KEY_INDEX || E,
}
},
components: {},
computed: {
...mapState({
userInfo: state => state.userInfo
}),
locale() {
return this.$i18n.locale || 'tc';
},
......@@ -43,8 +84,254 @@ export default {
onLoginTypeHandler(val) {
this.type = val;
},
initData() {}
initData() { },
handlerIsShowImageVcode() {
return new Promise((resolve, reject) => {
httpPost({
url: api.stdIsShowImageVcode,
data: {
deviceId: this.values.deviceId,
userId: this.loginForm.userId
}
}).then(response => {
// 判断是否显示图形验证码
if (this._handlerIsShowImageVcodeResponse(response)) {
resolve(response);
}
})
});
},
_handlerIsShowImageVcodeResponse(response) {
if (response.returnCode == "0" && response.data.isShowVcode == "N") {
return true;
}
this.values.token = response.data.token;
return false;
},
handlerRefreshVcode() {
// 刷新图形二维码
},
handlerLogin() {
this.refreshDeviceId();
if (!this.loginCheck.agreeProtocol) {
this._showAgreeProtocalTips();
return;
}
if (this.type == 1) {
this._passwordLogin();
} else {
this._otpLogin();
}
},
_passwordLogin() {
// 刷新图形二维码
this.handlerIsShowImageVcode().then(() => {
httpPost({
url: api.gsLogin,
data: {
deviceId: this.values.deviceId,
loginName: this.loginForm.userId,
loginPwd: this._passwordEncrypt(this.loginForm.password)
}
}).then(response => {
this._handlerLoginResponse(response);
})
});
},
// 处理登录结果
_handlerLoginResponse(response) {
// let res = response.content;
if (response.returnCode == 0 || response.resultCode == "0") {
this.$store.commit("SET_USER_INFO", response.data);
this._redirectTo();
} else {
let msg = response.returnMsg;
this._showLoginErrorMessage(msg);
}
},
_showAgreeProtocalTips() {
alert("请同意《平安一账通会员服务协议》");
},
_showLoginErrorMessage(message) {
alert(message);
},
_redirectTo() {
let path = this.$route.query.callback || "/index";
this.$router.push({
path: path
});
},
_otpLogin() {
this._checkOptParams().then(() => {
let data = {
mobileNo: this.loginForm.mobileNo,
token: this.values.token,
otp: this.loginForm.otp,
deviceId: this.refreshDeviceId()
};
httpPost({
url: api.otpLogin,
data: data
}).then(response => {
this._handlerLoginResponse(response);
});
});
},
_checkOptParams() {
return new Promise((resolve, reject) => {
this._checkMobileLegal().then(() => {
if (!this.loginForm.otp) {
this._showOtpEmptyTips();
return;
}
if (!this.values.token) {
this._showGetOptTips();
return;
}
resolve();
});
})
},
_showGetOptTips() {
alert('请先获取短信验证码');
},
_showImageValueTip() {
alert("请输入图片验证码")
},
_showOtpEmptyTips() {
alert('请输入短信验证码');
},
handlerStdSendOTP() {
// 发送短信验证码
this._checkMobileLegal().then(() => {
if (this.times.remain > 0) {
return;
}
if (this.values.vcodeuuid && !this.loginForm.imageValue) {
this._showImageValueTip();
return;
}
this._handlerIsShowImageVcode().then(() => {
this._startStdSendOTP();
this._startTimeClick();
});
});
},
handlerRefreshImageValue() {
httpPost({
url: api.stdRefreshVcode,
data: {
vcodeuuid: this.values.vcodeuuid
}
}).then(response => {
this.values.imageBase64 = response.data.image;
})
},
_checkMobileLegal() {
// 检测手机号是否正确
return new Promise((resolve, reject) => {
let mobile = this.loginForm.mobileNo;
if (mobile.length != 8 && mobile.length != 11) {
this._showMobileNoIllegalTip()
return;
}
resolve(true);
});
},
_handlerIsShowImageVcode() {
return new Promise((resolve, reject) => {
// 如果这个值不为空,标识出现了图片验证码,不需要重新询问是否需要图像验证码了
if (this.values.vcodeuuid) {
resolve();
return;
}
httpPost({
url: api.stdIsShowImageVcode,
data: {
deviceId: this.values.deviceId,
userId: this.loginForm.mobileNo
}
}).then(response => {
// 判断是否显示图形验证码
if (response.returnCode == "0") {
this.values.token = response.data.token;
if (response.data.isShowVcode == "N") {
// if (!this.values.vcodeuuid) {
// this.loginCheck.showImageCode = true;
// this.values.vcodeuuid = "123456";
// return;
// }
this.values.vcodeuuid = null;
resolve(response);
} else {
// image 值:
this.loginCheck.showImageCode = true;
this.values.vcodeuuid = response.data.vcodeuuid;
this.values.imageBase64 = response.data.image;
}
}
return false;
})
});
},
_showMobileNoIllegalTip() {
alert("手机号不正确");
},
_startStdSendOTP() {
// 正式发送OTP信号
let data = {
mobileNo: this.loginForm.mobileNo,
token: this.values.token,
signFactor: new Date().getTime(),
scene: "otpLogin",
deviceId: this.refreshDeviceId()
}
if (this.values.vcodeuuid) {
data["vcodeuuid"] = this.values.vcodeuuid;
data["imageValue"] = this.loginForm.imageValue;
}
httpPost({ url: api.stdSendOTP, data: data });
},
_startTimeClick() {
this.times.remain = 120;
let _this = this;
let i18n = this.$i18n.messages[this.$i18n.locale] || {};
let msg = i18n.register.coutTips;
_this.times.tip = msg.replace("{second}", _this.times.remain);
this.times.interval = setInterval(function () {
if (_this.times.remain <= 0) {
clearInterval(_this.times.interval);
_this.times.interval = 0;
_this.times.remain = 0;
return;
}
_this.times.remain--;
_this.times.tip = msg.replace("{second}", _this.times.remain);
_this.$set(_this, 'times', _this.times);
}, 1000);
},
refreshDeviceId() {
if (!this.values.deviceId) {
this.values.deviceId = (Math.random() + "").substring(2)
}
return this.values.deviceId
},
_passwordEncrypt(rawPwd) {
let rsa = new RSAKey();
rsa.setPublic(this.PK, this.E);
let res = rsa.encrypt(rawPwd);
if (res == null) return rawPwd;
return res;
}
},
watch: {
type() {
this.loginCheck.showImageCode = false;
}
},
mounted() {
// console.log("PK === ", this.PK)
// console.log("E === ", this.E)
},
mounted() {},
created() {}
created() { }
}
......
......@@ -124,6 +124,15 @@
justify-content: space-between;
flex-wrap: wrap;
.vcode {
background-color: transparent !important;
padding: 0 !important;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
&-item {
position: relative;
......@@ -160,6 +169,8 @@
border-radius: 3.5rem;
padding: 0 1.75rem;
flex: 1;
font-size: 1.166667rem; /* 14/12 */
letter-spacing: .1rem;/* 1.2/12 */
}
// 长文本
......@@ -187,6 +198,7 @@
color: #4c4948;
}
// 框内按钮
.ipt2 {
display: flex;
......@@ -202,13 +214,12 @@
color: #f05a23;
text-decoration: underline;
}
}
.veri-btn-default {
color: #aaaaaa;
}
}
}
}
}
......
......@@ -24,7 +24,7 @@
<img src="@/assets/images/login/icon-login-user.png"> {{$t('login.account')}}
</div>
<div class="ipt-wrap">
<input :placeholder="$t('login.accountPlaceholder')" class="ipt" type="text">
<input v-model="loginForm.userId" :placeholder="$t('login.accountPlaceholder')" class="ipt" type="text">
</div>
</div>
<div class="pure-u-1 form-item">
......@@ -32,21 +32,25 @@
<img src="@/assets/images/login/icon-login-password.png"> {{$t('login.password')}}
</div>
<div class="ipt-wrap">
<input :placeholder="$t('login.passwordPlaceholder')" class="ipt" type="text">
<input v-model="loginForm.password" :placeholder="$t('login.passwordPlaceholder')" class="ipt" type="password">
</div>
</div>
<div class="pure-u-1 form-item">
<div class="pure-u-1 form-item" v-if="type == 1 && loginCheck.showImageCode">
<div class="ipt-wrap">
<input :placeholder="$t('login.verifyPlaceholder')" class="ipt ipt-verify" type="text">
<div class="ipt verify-btn pointer">5136</div>
<input :placeholder="$t('login.verifyPlaceholder')" class="ipt ipt-verify" type="text" v-model="loginForm.imageValue">
<div class="ipt verify-btn pointer vcode" @click="handlerRefreshImageValue">
<img :src="values.imageBase64">
</div>
</div>
</div>
</div>
<div class="login-protocol">
<img @click="onCheckHandler()" class="check pointer" src="@/assets/images/login/login-check.png"> {{$t('login.agree')}}
<div class="login-protocol pointer" @click="loginCheck.agreeProtocol = !loginCheck.agreeProtocol" >
<img v-if="!loginCheck.agreeProtocol" class="check" src="@/assets/images/login/un-check.png">
<img v-if="loginCheck.agreeProtocol" class="check" src="@/assets/images/login/check.png">
{{$t('login.agree')}}
<span @click="onProtocolHandler()" class="protocol pointer">{{$t('login.protocol')}}</span>
</div>
<div @click="onSubmitHandler()" class="login-submit pointer">{{$t('login.login')}}</div>
<div @click="handlerLogin()" class="login-submit pointer">{{$t('login.login')}}</div>
<div class="login-func">
<div @click="onRegisterHandler()" class="login-func-btn pointer">{{$t('login.register')}}</div>
<div @click="onForgetHandler()" class="login-func-btn pointer">{{$t('login.forget')}}</div>
......@@ -71,7 +75,15 @@
<img src="@/assets/images/login/icon-login-phone.png"> {{$t('login.mobile')}}
</div>
<div class="ipt-wrap">
<input :placeholder="$t('login.mobilePlaceholder')" class="ipt" type="text">
<input :placeholder="$t('login.mobilePlaceholder')" class="ipt" type="text" v-model="loginForm.mobileNo">
</div>
</div>
<div class="pure-u-1 form-item" v-if="type == 2 && loginCheck.showImageCode">
<div class="ipt-wrap">
<input :placeholder="$t('login.verifyPlaceholder')" class="ipt ipt-verify" type="text" v-model="loginForm.imageValue">
<div class="ipt verify-btn pointer vcode" @click="handlerRefreshImageValue">
<img :src="values.imageBase64">
</div>
</div>
</div>
<div class="pure-u-1 form-item">
......@@ -80,17 +92,20 @@
</div>
<div class="ipt-wrap">
<div class="ipt ipt2">
<input :placeholder="$t('login.verifyCodePlaceholder')" class="ipt-code" type="text">
<div class="veri-btn pointer"> {{$t('login.verifyCodeGet')}}</div>
<input :placeholder="$t('login.verifyCodePlaceholder')" class="ipt-code" type="text" v-model="loginForm.otp">
<div v-if="times.remain == 0" class="veri-btn pointer" @click="handlerStdSendOTP" >{{$t('register.verifyCodeGet')}}</div>
<div v-else class="veri-btn-default">{{times.tip}}</div>
</div>
</div>
</div>
</div>
<div class="login-protocol">
<img @click="onCheckHandler()" class="check pointer" src="@/assets/images/login/login-check.png"> {{$t('login.agree')}}
<div class="login-protocol pointer" @click="loginCheck.agreeProtocol = !loginCheck.agreeProtocol" >
<img v-if="!loginCheck.agreeProtocol" class="check" src="@/assets/images/login/un-check.png">
<img v-if="loginCheck.agreeProtocol" class="check" src="@/assets/images/login/check.png">
{{$t('login.agree')}}
<span @click="onProtocolHandler()" class="protocol pointer">{{$t('login.protocol')}}</span>
</div>
<div @click="onSubmitHandler()" class="login-submit pointer">{{$t('login.login')}}</div>
<div @click="handlerLogin()" class="login-submit pointer">{{$t('login.login')}}</div>
<div class="login-func">
<div @click="onRegisterHandler()" class="login-func-btn pointer">{{$t('login.register')}}</div>
<div @click="onForgetHandler()" class="login-func-btn pointer">{{$t('login.forget')}}</div>
......
......@@ -4,11 +4,43 @@ import {
httpPost
} from '@/api/fetch-api.js'
let PK = 'B5FE03847F02046C47292AF0FF2DE88977241483DD40C123046EB39CBE4C48167B120096CFF12CD16559322884A3C56FA92B07B89AB51FC8C91A75127622151DDD730DFF1F993D5A290CEAC0BBA7FC88285D8994ACBAFF50101EDE9A0925AD5DFFAFE96D53C370E9C5B37DF2F871F81C4D7CA6B7EC37FF459C07975AD9A74A95';
let E = '10001';
export default {
data() {
return {
key: 'value',
type: 1, // 1:手机验证 2:输入密码
mobileNoType: "hk",// 选择的手机好类型
mobileTip: {},
mobileOptions: [],
registerCheck: {
showImageCode: false,
agreeProtocol: false
},
values: {
// 返回的token,串连整个流程,后台安全校验使用
vcodeuuid: "",
token: "",
deviceId: "",
imageBase64: "",
password: "",
passwordRepeat: ""
},
registerForm: {
imageValue: "",
mobileNo: "",
otp: ""
},
times: {
interval: 0, // 索引
remain: 0, // 剩余时间
tip: "" // 显示的文字
},
PK: process.env.RSA_PUBLIC_KEY || PK,
E: process.env.RSA_KEY_INDEX || E,
}
},
components: {},
......@@ -21,19 +53,324 @@ export default {
}
},
methods: {
onCheckHandler() {
},
onProtocolHandler() {
this.$router.push({
path: "/protocol"
})
},
handlerStdSendOTP() {
// 发送短信验证码
this._checkMobileLegal().then(() => {
if (this.times.remain > 0) {
return;
}
if (this.values.vcodeuuid && !this.registerForm.imageValue) {
this._showImageValueTip();
return;
}
this._handlerIsShowImageVcode().then(() => {
this._startStdSendOTP();
this._startTimeClick();
});
});
},
_checkMobileLegal() {
// 检测手机号是否正确
return new Promise((resolve, reject) => {
let mobile = this.registerForm.mobileNo;
if (this.mobileNoType == "hk") {
if (mobile.length != 8) {
this._showMobileNoIllegalTip()
return;
}
} else {
if (mobile.length != 11) {
this._showMobileNoIllegalTip()
return;
}
}
resolve(true);
});
},
_handlerIsShowImageVcode() {
return new Promise((resolve, reject) => {
// 如果这个值不为空,标识出现了图片验证码,不需要重新询问是否需要图像验证码了
if (this.values.vcodeuuid) {
resolve();
return;
}
httpPost({
url: api.stdIsShowImageVcode,
data: {
deviceId: this.values.deviceId,
userId: this.registerForm.mobileNo
}
}).then(response => {
// 判断是否显示图形验证码
if (response.returnCode == "0") {
this.values.token = response.data.token;
if (response.data.isShowVcode == "N") {
// 测试代码
// if (!this.values.vcodeuuid) {
// this.registerCheck.showImageCode = true;
// this.values.vcodeuuid = "123456";
// return;
// }
this.values.vcodeuuid = null;
resolve(response);
} else {
// image 值:
this.registerCheck.showImageCode = true;
this.values.vcodeuuid = response.data.vcodeuuid;
this.values.imageBase64 = response.data.image;
}
}
return false;
})
});
},
_showMobileNoIllegalTip() {
alert("手机号不正确");
},
_startStdSendOTP() {
// 正式发送OTP信号
let data = {
mobileNo: this.registerForm.mobileNo,
token: this.values.token,
signFactor: new Date().getTime(),
scene: "register",
}
if (this.values.vcodeuuid) {
data["vcodeuuid"] = this.values.vcodeuuid;
data["imageValue"] = this.registerForm.imageValue;
}
httpPost({ url: api.stdSendOTP, data: data });
},
_startTimeClick() {
this.times.remain = 120;
let _this = this;
let i18n = this.$i18n.messages[this.$i18n.locale] || {};
let msg = i18n.register.coutTips;
_this.times.tip = msg.replace("{second}", _this.times.remain);
this.times.interval = setInterval(function () {
if (_this.times.remain <= 0) {
clearInterval(_this.times.interval);
_this.times.interval = 0;
_this.times.remain = 0;
return;
}
_this.times.remain--;
_this.times.tip = msg.replace("{second}", _this.times.remain);
_this.$set(_this, 'times', _this.times);
}, 1000);
},
onSubmitHandler() {
// this.type = 2;
this._checkParams().then(() => {
this._regCheck().then(() => {
// 验证短信验证码
this._validateOTPandRepeat().then(() => {
this.type = 2;
});
});
});
},
_validateOTPandRepeat() {
return new Promise((resolve, reject) => {
let data = {
mobileNo: this.registerForm.mobileNo,
token: this.values.token,
signFactor: new Date().getTime(),
otp: this.registerForm.opt
};
httpPost({
url: api.stdValidateOTPandRepeat,
data: data
}).then(response => {
if (response.returnCode != "0") {
this._showCheckOTPErrTip(response.returnMsg);
// TODO 测试代码
// resolve();
} else {
// this.type = 2;
resolve();
}
})
});
},
_regCheck() {
// 检测手机号注册情况
return new Promise((resolve, reject) => {
let data = {
mobileNo: this.registerForm.mobileNo,
};
httpPost({
url: api.gsRegCheck,
data: data
}).then(response => {
if (response.returnCode == "0") {
if (response.data.mobileStatus == "N") {
resolve();
} else {
// 重复注册
this._showDuplicateRegistrationTip();
}
} else {
// 错误提示
this._showCheckOTPErrTip(response.returnMsg);
}
})
});
},
_checkParams() {
return new Promise((resolve, reject) => {
if (!this.registerCheck.agreeProtocol) {
this._showAgreeProtocolTip();
return;
}
if (!this.values.token) {
this._showTokenTip();
return;
}
if (this.values.vcodeuuid && !this.registerForm.imageValue) {
this._showImageValueTip();
return;
}
if (!this.registerForm.opt) {
this._showOTPTip();
return;
}
this._checkMobileLegal().then(() => {
resolve();
})
});
},
_showAgreeProtocolTip() {
alert("请同意协议")
},
_showOTPTip() {
alert("请填写短信验证码")
},
_showTokenTip() {
alert("请先请求短信验证码")
},
_showDuplicateRegistrationTip() {
alert("手机号已经被注册,请使用其他手机号重新注册")
},
_showImageValueTip() {
alert("请输入图片验证码")
},
_showCheckOTPErrTip(msg) {
alert(msg);
},
onRegisterHandler() {
this._checkPassword().then(() => {
let data = {
token: this.values.token,
mobileNo: this.registerForm.mobileNo,
loginPwd: this._passwordEncrypt(this.values.password)
};
httpPost({
url: api.stdRegister,
data: data
}).then(response => {
if (response.returnCode != 0) {
this._showRegisterFailure(response);
this.type = 1;
} else {
this._showSuccessMessage();
this.$router.push({
path: "/login"
});
}
})
});
},
_checkPassword() {
return new Promise((resolve, reject) => {
let password = this.values.password;
if (password.length < 8) {
this._showPasswordLenthNotEnouth();
return;
}
// 匹配字母
let m1 = /([a-z])+/.test(password);
let m2 = /([A-Z])+/.test(password);
// 匹配数字
let m3 = /([0-9])+/.test(password);
// 匹配特殊字符
let m4 = /[^a-zA-Z0-9]+/.test(password);
console.log(m1, m2, m3, m4)
if ((m1 | m2) & m3 & m4) {
if (password != this.values.passwordRepeat) {
this._showPasswordNotTheSameTips();
} else {
resolve();
}
} else {
this._showPasswordComplexityTips();
}
});
},
_showPasswordLenthNotEnouth() {
alert("密码长度不能少于8位")
},
_showPasswordComplexityTips() {
alert("密码必须同时包含数字、字母、特殊字符")
},
_showPasswordNotTheSameTips() {
alert("两次输入的密码不一致")
},
_showRegisterFailure(response) {
if ("COMMON_ERROR_052" == response.returnCode) {
this._resetRegisterParam();
this.handlerRefreshImageVcode();
alert("验证码过期,请重新申请验证码");
} else {
this._resetAllParams();
alert("注册失败,请联系工作人员");
}
},
_resetAllParams() {
this.values.vcodeuuid = "";
this.values.token = "";
this.values.imageBase64 = "";
this.values.password = "";
this.values.passwordRepeat = "";
this.registerForm.imageValue = "";
this.registerForm.mobileNo = "";
this.registerForm.otp = "";
this.times.interval = "";
this.times.remain = "";
this.times.tip = "";
},
_resetRegisterParam() {
this.values.token = "";
this.registerForm.otp = "";
this.times.interval = "";
this.times.remain = "";
this.times.tip = "";
},
handlerRefreshImageVcode() {
if (this.values.vcodeuuid) {
let data = {
vcodeuuid: this.values.vcodeuuid
}
httpPost({
url: api.stdRefreshVcode,
data: data
}).then(response => {
this.$set(this.values, 'imageBase64', response.data.image);
})
}
},
_showSuccessMessage() {
alert("注册成功")
},
onForgetHandler() {
......@@ -41,8 +378,31 @@ export default {
onLoginTypeHandler(val) {
},
initData() {}
_passwordEncrypt(rawPwd) {
let rsa = new RSAKey();
rsa.setPublic(this.PK, this.E);
let res = rsa.encrypt(rawPwd);
if (res == null) return rawPwd;
return res;
},
mounted() {},
created() {}
initData() {
let i18n = this.$i18n.messages[this.$i18n.locale] || {};
let mobileOptions = JSON.parse(JSON.stringify(i18n.register.mobileOptions));
this.mobileOptions = mobileOptions;
this.mobileTip = this.mobileOptions[0];
}
},
mounted() { },
watch: {
mobileNoType() {
this.mobileOptions.forEach(element => {
if (element.type == this.mobileNoType) {
this.$set(this, 'mobileTip', element);
}
})
}
},
created() {
this.initData();
}
}
......
......@@ -120,6 +120,20 @@
justify-content: space-between;
flex-wrap: wrap;
.vcode {
background-color: transparent !important;
padding: 0 !important;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
input {
font-size: 1.166667rem; /* 14/12 */
letter-spacing: .1rem;/* 1.2/12 */
}
&-item {
position: relative;
......@@ -206,6 +220,9 @@
color: #f05a23;
text-decoration: underline;
}
.veri-btn-default {
color: #aaaaaa;
}
}
}
......
......@@ -16,36 +16,44 @@
<div class="pure-u-1 form-item">
<div class="ipt-wrap">
<img class="down-arrow" src="@/assets/images/reservation/re-down-arrow.png" alt="">
<select class="ipt">
<template v-if="locale == 'zh'">
<option>香港手机号</option>
</template>
<template v-else>
<option>香港手機號</option>
</template>
<select class="ipt" v-model="mobileNoType">
<option v-for="(item,index) in mobileOptions" :key="index" :value="item.type">{{item.name}}</option>
</select>
</div>
</div>
<div class="pure-u-1 form-item">
<div class="ipt-wrap">
<div class="ipt ipt2">
<div class="region-tel">+852</div>
<input :placeholder="$t('register.mobilePlaceholder')" class="ipt-tel" type="text">
<div class="region-tel">{{mobileTip.areaCode}}</div>
<input :placeholder="mobileTip.placeHolder" class="ipt-tel" type="text" v-model="registerForm.mobileNo">
</div>
</div>
</div>
<div class="pure-u-1 form-item" v-if="registerCheck.showImageCode">
<div class="ipt-wrap">
<input :placeholder="$t('login.verifyPlaceholder')" class="ipt ipt-verify" type="text" v-model="registerForm.imageValue">
<div class="ipt verify-btn pointer vcode" @click="handlerRefreshImageVcode">
<img :src="values.imageBase64">
</div>
</div>
</div>
<div class="pure-u-1 form-item">
<div class="ipt-wrap">
<div class="ipt ipt2">
<input :placeholder="$t('register.verifyCodePlaceholder')" class="ipt-code" type="text">
<div class="veri-btn pointer">{{$t('register.verifyCodeGet')}}</div>
<input :placeholder="$t('register.verifyCodePlaceholder')" class="ipt-code" type="text" v-model="registerForm.opt">
<div v-if="times.remain == 0" class="veri-btn pointer" @click="handlerStdSendOTP" >{{$t('register.verifyCodeGet')}}</div>
<div v-else class="veri-btn-default">{{times.tip}}</div>
</div>
</div>
</div>
</div>
<div class="login-protocol">
<img @click="onCheckHandler()" class="check pointer" src="@/assets/images/login/login-check.png">{{$t('register.agree')}}
<span @click="onProtocolHandler()" class="protocol pointer">{{$t('register.protocol')}}</span>
<div class="login-protocol pointer" @click="registerCheck.agreeProtocol = !registerCheck.agreeProtocol" >
<img v-if="!registerCheck.agreeProtocol" class="check" src="@/assets/images/login/un-check.png">
<img v-if="registerCheck.agreeProtocol" class="check" src="@/assets/images/login/check.png">
{{$t('login.agree')}}
<span @click="onProtocolHandler()" class="protocol pointer">{{$t('login.protocol')}}</span>
</div>
<div @click="onSubmitHandler()" class="login-submit pointer">{{$t('register.register')}}</div>
</div>
......@@ -57,7 +65,7 @@
<img src="@/assets/images/register/icon-register-lock.png"> {{$t('register.newPassword')}}
</div>
<div class="ipt-wrap">
<input :placeholder="$t('register.newPasswordPlaceholder')" class="ipt" type="text">
<input :placeholder="$t('register.newPasswordPlaceholder')" class="ipt" type="password" v-model="values.password">
</div>
</div>
<div class="pure-u-1 form-item">
......@@ -65,11 +73,11 @@
<img src="@/assets/images/register/icon-register-lock.png"> {{$t('register.newPasswordSure')}}
</div>
<div class="ipt-wrap">
<input :placeholder="$t('register.newPasswordSurePlaceholder')" class="ipt" type="text">
<input :placeholder="$t('register.newPasswordSurePlaceholder')" class="ipt" type="password" v-model="values.passwordRepeat">
</div>
</div>
</div>
<div @click="onSubmitHandler()" class="login-submit pointer">{{$t('register.sure')}}</div>
<div @click="onRegisterHandler()" class="login-submit pointer">{{$t('register.sure')}}</div>
</div>
</div>
</div>
......
import { setCookie, getCookie } from '@/utils/utils.js'
import { stat } from 'fs';
export function INCREMENT(state) {
state.counter++
}
......@@ -9,3 +12,13 @@ export function IS_MOBILE(state, bool) {
export function IS_SMALL_SCREEN(state, bool) {
state.isSmallScreen = bool
}
export function SET_USER_INFO(state, val) {
if (val) {
setCookie("_user_profile", encodeURIComponent(JSON.stringify(val)), 7200);
state.userInfo = val;
} else {
setCookie("_user_profile", "", 1);
state.userInfo = null;
}
}
\ No newline at end of file
......
......@@ -2,4 +2,10 @@ export default {
counter: 2, // 例子
isMobile: false, //是否手机访问
isSmallScreen: false, // 是否小屏幕 (PC时,小屏幕机导航栏会改变))
userInfo : {
sid : "",
name : "",
hadFullInfo: ""
}
}
......
......@@ -40,10 +40,10 @@ export function getCookie(name) {
}
//设置cookie
export function setCookie(c_name, value, expiredays) {
export function setCookie(c_name, value, second) {
var exdate = new Date();
exdate.setDate(exdate.getDate() + expiredays);
document.cookie = c_name + "=" + escape(value) + ((expiredays == null) ? "" : ";expires=" + exdate.toGMTString());
exdate.setTime(exdate.getTime() + second * 1000);
document.cookie = c_name + "=" + escape(value) + ((second == null) ? "" : ";expires=" + exdate.toGMTString());
};
//删除cookie
......