Commit 1d60ee6b authored by hanfeng zhang's avatar hanfeng zhang

Merge branch 'main' of gitlab.33.cn:HF_web/NFT

parents 134c179e c55c52ba
......@@ -3,3 +3,4 @@
.vscode
package-lock.json
dist/
/NFT/
\ No newline at end of file
......@@ -54,13 +54,13 @@ export default Vue.extend({
name: "App",
mounted() {
this.$service.userService.isPwdSet('13013370014')
// this.$service.userService.isPwdSet('13013370014')
this.routerController();
},
methods: {
routerController() {
if (this.$route.name !== "Home") {
this.$router.push("Home");
// this.$router.push("Home");
}
},
closeNFT(){
......
<template>
<div class="text-xs px-3 py-2 text-center cursor-pointer rounded my-3" :class="getSize && border" @click="eventEmit">
{{text}}
<div class="text-xs px-3 py-2 text-center cursor-pointer rounded my-3 flex items-center justify-center" :class="getSize && border" @click="eventEmit">
{{text}} <slot name="icon-right"></slot>
</div>
</template>
......
<template>
<div class="flex items-center" @click="$emit('change', !checked)">
<img class="w-4 mr-1" :src="checked ? checkedIcon : notCheckedIcon" />
<span>
<slot />
</span>
</div>
</template>
<script>
import Vue from "vue";
const notCheckedIcon = require("@/assets/icons/not_checked_2.png");
const checkedIcon = require("@/assets/icons/checked.png");
export default Vue.extend({
props: ["checked"],
data() {
return {
notCheckedIcon,
checkedIcon,
};
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<Field
class="base-input text-font-white"
:label="label"
:placeholder="placeholder"
:value="value"
@input="handleChange"
:type="getInputType"
:maxlength="maxlength"
autocomplete="off"
>
<template #button>
<div class="flex items-center">
<img
src="@/assets/icons/close.png"
@click="handleClear"
v-if="clearable && value && value.length !== 0"
name="cross"
/>
<slot name="button"></slot>
<img
v-if="type === 'password' && showEye"
:src="showPwd ? eyeOpenIcon : eyeCloseIcon"
@click="handleClickEye"
name="cross"
class="ml-1 eyeIcon"
/>
</div>
</template>
</Field>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import { Field, Icon } from "vant";
import { tType } from "./types";
const eyeOpenIcon = require("@/assets/icons/eye_open.png");
const eyeCloseIcon = require("@/assets/icons/eye_close.png");
export default Vue.extend({
components: {
Field,
Icon,
},
props: {
type: {
type: String as PropType<tType>,
default: "text",
},
placeholder: String,
clearable: {
type: Boolean,
default: false,
},
value: String,
maxlength: Number,
label: {
type: String,
default: "",
},
showEye: {
type: Boolean,
default: true,
},
},
data() {
return {
showPwd: false,
eyeOpenIcon,
eyeCloseIcon,
};
},
computed: {
getInputType(): string {
if (this.type === "password") {
return this.showPwd ? "text" : "password";
} else {
return this.type;
}
},
},
methods: {
handleClickEye() {
this.showPwd = !this.showPwd;
},
handleChange(value: string) {
this.$emit("change", value);
},
handleClear() {
this.$emit("change", "");
},
},
});
</script>
<style scoped lang="less">
@color1: #68739c;
@caretColor: #8899b3;
@textColor: #eef1f6;
.base-input {
background-color: transparent;
// border-bottom: 1px solid @color1;
caret-color: @caretColor;
padding: 10px 0px;
/deep/ input {
color: @textColor;
}
.eyeIcon {
width: 14px;
}
}
.base-input::after {
left: 0;
right: 0;
border-bottom: 1px solid @color1;
}
</style>
\ No newline at end of file
export type tType = "password" | "number" | "text"
\ No newline at end of file
<template>
<div class="drag" ref="dragDiv">
<div class="drag_bg"></div>
<div class="drag_text">{{ confirmWords }}</div>
<div
ref="moveDiv"
@touchstart="mousedownFn($event)"
:class="{ handler_ok_bg: confirmSuccess }"
class="handler handler_bg"
style="position: absolute; top: 0px; left: 0px; bottom: 0px"
></div>
</div>
</template>
<script>
export default {
data() {
return {
beginClientX: 0 /*距离屏幕左端距离*/,
mouseMoveStata: false /*触发拖动状态 判断*/,
maxwidth: "" /*拖动最大宽度,依据滑块宽度算出来的*/,
confirmWords: "拖动滑块验证" /*滑块文字*/,
confirmSuccess: false /*验证成功判断*/,
};
},
methods: {
mousedownFn: function (e) {
if (!this.confirmSuccess) {
e.preventDefault && e.preventDefault(); //阻止文字选中等 浏览器默认事件
this.mouseMoveStata = true;
this.beginClientX = e.changedTouches[0].clientX;
}
}, //mousedoen 事件
successFunction() {
this.confirmSuccess = true;
this.$emit("confirm", true);
this.confirmWords = "验证通过";
if (window.addEventListener) {
document
.getElementsByTagName("html")[0]
.removeEventListener("touchmove", this.mouseMoveFn);
document
.getElementsByTagName("html")[0]
.removeEventListener("touchend", this.moseUpFn);
} else {
document
.getElementsByTagName("html")[0]
.removeEventListener("touchend", () => {});
}
document.getElementsByClassName("drag_text")[0].style.color = "#fff";
document.getElementsByClassName("handler")[0].style.left =
this.maxwidth + "px";
document.getElementsByClassName("drag_bg")[0].style.width =
this.maxwidth + "px";
}, //验证成功函数
mouseMoveFn(e) {
if (this.mouseMoveStata) {
let width = e.changedTouches[0].clientX - this.beginClientX;
if (width > 0 && width <= this.maxwidth) {
document.getElementsByClassName("handler")[0].style.left =
width + "px";
document.getElementsByClassName("drag_bg")[0].style.width =
width + "px";
} else if (width > this.maxwidth) {
this.successFunction();
}
}
}, //mousemove事件
moseUpFn(e) {
this.mouseMoveStata = false;
var width = e.changedTouches[0].clientX - this.beginClientX;
if (width < this.maxwidth) {
document.getElementsByClassName("handler")[0].style.left = 0 + "px";
document.getElementsByClassName("drag_bg")[0].style.width = 0 + "px";
}
}, //mouseup事件
},
mounted() {
this.maxwidth =
this.$refs.dragDiv.clientWidth - this.$refs.moveDiv.clientWidth;
document
.getElementsByTagName("html")[0]
.addEventListener("touchmove", this.mouseMoveFn);
document
.getElementsByTagName("html")[0]
.addEventListener("touchend", this.moseUpFn);
},
beforeDestroy() {
document
.getElementsByTagName("html")[0]
.removeEventListener("touchmove", this.mouseMoveFn);
document
.getElementsByTagName("html")[0]
.removeEventListener("touchend", this.moseUpFn);
},
};
</script>
<style scoped>
.drag {
position: relative;
background-color: #e8e8e8;
width: 100%;
height: 34px;
line-height: 34px;
text-align: center;
}
.handler {
width: 40px;
border: 1px solid #ccc;
cursor: move;
}
.handler_bg {
background: #fff
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==")
no-repeat center;
}
.handler_ok_bg {
background: #fff
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAAASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMCy4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQNTNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgGFMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJggg==")
no-repeat center;
}
.drag_bg {
background-color: #7ac23c;
height: 34px;
width: 0px;
}
.drag_text {
position: absolute;
top: 0px;
width: 100%;
text-align: center;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
-o-user-select: none;
-ms-user-select: none;
}
</style>
\ No newline at end of file
declare module '*.png';
declare module '*.jpg';
\ No newline at end of file
import { token } from '@/util/userInfoUtils'
import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router'
import App from '../App.vue'
......@@ -8,29 +9,59 @@ const routes: Array<RouteConfig> = [
{
path: '/',
name: 'App',
component: App,
children:[
component: App,
children: [
{
path:'/Home',
path: '/Home',
name: 'Home',
component:()=>import('@/view/Home/index.vue')
component: () => import('@/view/Home/index.vue')
},
{
path:'/Mine',
path: '/Mine',
name: 'Mine',
component:()=>import('@/view/Mine/index.vue')
component: () => import('@/view/Mine/index.vue')
}
]
},
{
path:'/Nft/create',
name:'createNft',
component:()=>import('@/view/NFT/Create.vue'),
meta:{
title:'NFT发行'
path: '/Nft/create',
name: 'createNft',
component: () => import('@/view/NFT/Create.vue'),
meta: {
title: 'NFT发行'
}
},
{
path: '/auth',
component: () => import("@/view/Auth/index.vue"),
redirect: { name: 'Login' },
children: [
{
path: '/auth/Login',
name: 'Login',
component: () => import("@/view/Auth/Login/index.vue")
},
// {
// path: '/auth/PwdSetting',
// name: 'PwdSetting',
// component: () => import("@/view/Auth/PwdSetting/index.vue")
// },
// {
// path: '/auth/PwdFind',
// name: 'PwdFind',
// component: () => import("@/view/Auth/PwdFind/index.vue")
// },
// {
// path: '/auth/PwdModify',
// name: 'PwdModify',
// component: () => import("@/view/Auth/PwdModify/index.vue")
// },
]
},
{
path: '*',
redirect: { name: 'Home' }
}
]
......@@ -41,4 +72,12 @@ const router = new VueRouter({
routes
})
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && token.getToken() === null) {
next({ name: 'Login' })
} else {
next()
}
})
export default router
......@@ -2,17 +2,33 @@
import axios, { AxiosInstance } from "axios"
const url = {
development:'http://172.16.101.135:8001',
test:'',
production:''
development: 'http://172.16.101.135:8001',
test: '',
production: ''
}
import { Toast } from "vant"
export class Service {
public service:AxiosInstance ;
constructor(){
public service: AxiosInstance;
constructor() {
this.service = axios.create({
baseURL: process.env.NODE_ENV === 'production'? url.production:url.development,
timeout: 15000
baseURL: process.env.NODE_ENV === 'production' ? url.production : url.development,
timeout: 15000,
})
const get = this.service.get
const post = this.service.post
const resolveData = (ret: any) => {
if (ret.code === 200)
return ret.data;
else {
Toast.fail(ret.message)
throw new Error(ret.message)
}
}
this.service.get = (...res) => get(...res).then(ret => resolveData(ret.data));
this.service.post = (...res) => post(...res).then(ret => resolveData(ret.data)).catch(err => {
resolveData(err.response.data)
});
}
}
\ No newline at end of file
......@@ -29,7 +29,7 @@ export class UserService extends Service {
* @param data
* @returns
*/
async loginAndSign(data:LoginDto){
async loginAndSign(data:LoginDto):Promise<{Authorization: string, user: object}>{
return await this.service.post(this.router.login.path,data)
}
......
import Vue from 'vue'
import {Service} from './service/index'
import {UserService} from './service/userService'
import { Service } from './service/index'
import { UserService } from './service/userService'
import VueRouter, { Route } from 'vue-router'
interface ServiceType {
userService: UserService
......@@ -11,7 +11,8 @@ interface ServiceType {
declare module 'vue/types/vue' {
interface Vue {
$service:ServiceType
$service: ServiceType,
$router: VueRouter
}
}
......@@ -28,6 +28,26 @@ body{
background-color: rgba(10,14,35,.95);
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
/* 可以设置不同的进入和离开动画 */
/* 设置持续时间和动画函数 */
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active for below version 2.1.8 */ {
transform: translateX(10px);
opacity: 0;
}
.step-progress__step--valid span{
font-size: 12px !important;
}
......
......@@ -15,7 +15,7 @@ import { PRODUCT_STATUS } from '@/constant/product'
export interface LoginDto {
codetype: string
email?:string
password:string
password?:string
telephone: string
verificationCode: string
}
......
const KEY_TOKEN = 'KEY_TOKEN'
const KEY_USER = 'KEY_USER'
function setToken(token: string) {
localStorage.setItem(KEY_TOKEN, token)
}
function getToken(): string | null {
return localStorage.getItem(KEY_TOKEN)
}
export const token = {
setToken,
getToken
}
function setUserMsg(user: object) {
localStorage.setItem(KEY_USER, JSON.stringify(user))
}
function getUserMsg(): object | null {
const userStr = localStorage.getItem(KEY_USER)
return userStr ? JSON.parse(userStr) : null
}
export const userMsg = {
setUserMsg,
getUserMsg
}
\ No newline at end of file
This diff is collapsed.
import { iRememberPhonePwd } from "./types";
const KEY_REMEMBER_PWD = 'KEY_REMEMBER_PWD'
export default class LoginService {
static instance: LoginService
static getIntance() {
if (!LoginService.instance) LoginService.instance = new LoginService();
return LoginService.instance;
}
addPhoneWithPwdToStorage(phone: string, pwd: string) {
const list = this.getRememberedPhonePwdList();
const index = list.findIndex(i => i.phone === phone)
if (index === -1) {
list.push({
phone,
pwd
})
} else {
list.splice(index, 1, { phone, pwd })
}
localStorage.setItem(KEY_REMEMBER_PWD, JSON.stringify(list))
}
getRememberedPhonePwdList(): iRememberPhonePwd[] {
const value = localStorage.getItem(KEY_REMEMBER_PWD)
const list = value && JSON.parse(value) || []
return list;
}
deletePhoneInStorage(phone: string) {
const list = this.getRememberedPhonePwdList()
const newList = list.filter(i => i.phone !== phone)
localStorage.setItem(KEY_REMEMBER_PWD, JSON.stringify(newList))
}
}
\ No newline at end of file
<template>
<div class="userAgreement h-full overflow-auto px-5">
<img @click="handleClickClose" :src="closeIcon" alt="close" />
<div class="text-font-white text-sm" v-for="n in 20" :key="n">
这里是协议内容,待产品提供后,开发直接替换上去,这里是协议内容。
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
const closeIcon = require("@/assets/icons/close_large.png");
export default Vue.extend({
props: ["setOverlayShow"],
data() {
return {
closeIcon,
};
},
methods: {
handleClick() {
console.log(123);
},
handleClickClose() {
this.setOverlayShow(false);
},
},
});
</script>
<style>
.userAgreement {
background: #131934;
}
</style>
\ No newline at end of file
<template>
<div class="">
<Input
:placeholder="placeholder"
:clearable="clearable"
:maxlength="maxlength"
:value="value"
:type="type"
@change="handleChange"
>
<template #button>
<div>
<div
v-if="smsCount === 60"
@click="handleClickSendSms"
class="text-font-blue"
:class="{ 'text-font-gray': !phoneValid || smsLock }"
>
获取验证码
</div>
<div v-else class="text-font-blue">已发送 {{ smsCount }} S</div>
</div>
</template>
</Input>
<div
class="mt-2 float-right text-sm text-font-blue"
v-if="voiceActive && sendVoiceFunc"
>
<div
v-if="voiceCount === 60 && !voiceHasSended60Ago"
class="flex items-center"
:class="{ 'text-font-gray': voiceLock }"
>
收不到验证码?试试
<span
class="text-font-blue"
@click="handleClickSendVoice"
:class="{ 'text-font-gray': voiceLock }"
>语音验证</span
>
</div>
<div
@click="handleClickSendVoice"
v-else-if="voiceCount === 60 && voiceHasSended60Ago"
:class="{ 'text-font-gray': voiceLock }"
>
获取语音验证
</div>
<div v-else>请注意接听语音验证电话 ({{ voiceCount }}) S</div>
</div>
<div class="clear-right"></div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Input from "@/components/common/Input/index.vue";
export default Vue.extend({
components: {
Input,
},
props: {
placeholder: String,
clearable: Boolean,
value: String,
type: String,
handleChange: Function,
maxlength: Number,
phone: String,
sendSmsFunc: Function,
sendVoiceFunc: {
type: Function,
required: false,
},
phoneValid: Boolean,
sendSmsAuto: {
type: Boolean,
default: false,
},
},
data() {
return {
smsCount: 60,
voiceCount: 60,
voiceActive: false,
voiceHasSended60Ago: false,
smsLock: false,
voiceLock: false,
timerId1: 0,
timerId2: 0,
};
},
mounted() {
if (this.phoneValid && this.sendSmsAuto) {
this.handleClickSendSms();
}
},
methods: {
async handleClickSendSms() {
if (!this.phoneValid) return;
if (this.smsLock === true) return;
this.smsLock = true;
try {
await this.sendSmsFunc(this.phone);
} catch (err) {
this.smsLock = false;
return;
}
this.smsCount--;
this.timerId1 = window.setInterval(() => {
this.smsCount--;
if (this.smsCount === -1) {
this.smsCount = 60;
this.voiceActive = true;
this.smsLock = false;
window.clearInterval(this.timerId1);
}
}, 1000);
},
async handleClickSendVoice() {
if (!this.phoneValid) return;
if (this.voiceLock === true) return;
this.voiceLock = true;
await this.sendVoiceFunc(this.phone);
this.voiceCount--;
this.timerId2 = window.setInterval(() => {
this.voiceCount--;
if (this.voiceCount === -1) {
this.voiceCount = 60;
this.voiceLock = false;
this.voiceHasSended60Ago = true;
window.clearInterval(this.timerId2);
}
}, 1000);
},
},
beforeDestroy() {
clearInterval(this.timerId1);
clearInterval(this.timerId2);
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<transition name="fade" mode="out-in" :duration="100">
<Button
:key="disabled + text"
:text="text"
class="rounded-full h-8"
@btnClicked="handleCliCkBtn"
border="border-0"
:class="[
disabled ? 'darkBtn' : 'bg-font-blue',
disabled ? 'darkBtn' : ' text-white ',
]"
>
<template #icon-right>
<img
v-if="!disabled"
class="ml-2"
src="@/assets/icons/arrow-right.png"
alt="arrow-right"
/>
<img
v-else
class="ml-2"
src="@/assets/icons/arrow-right-dark.png"
alt="arrow-right"
/>
</template>
</Button>
</transition>
</template>
<script lang="ts">
import Button from "@/components/common/Btn.vue";
import Vue from "vue";
export default Vue.extend({
components: {
Button,
},
props: {
text: String,
disabled: Boolean,
},
methods: {
handleCliCkBtn(e: MouseEvent) {
if (this.disabled) return;
this.$emit("click", e);
},
},
});
</script>
<style>
.darkBtn {
background: #1d2649;
color: #8899b3;
}
</style>
<template>
<div class="w-full phoneInput" ref="phoneInput">
<Input
:placeholder="placeholder"
:maxlength="maxlength"
:clearable="true"
:value="value"
:type="type"
@change="handleChange"
>
<template #button>
<img
:src="arrowDownIcon"
alt=""
ref="arrowImg"
class="ml-2 transform transition-all"
:class="{ 'rotate-180': !arrowDown }"
@click="handleClickArrowIcon"
/>
</template>
</Input>
<div class="w-full relative mt-px">
<div
class="
absolute
left-0
right-0
overflow-auto
h-0
transition-all
z-10
text-font-white
bg-font-light-black
"
:class="{ 'h-24': !arrowDown }"
>
<div
v-for="(item, index) in phonePwdList"
:key="index"
class="
h-8
flex
items-center
justify-between
bg-font-light-black
hover:bg-font-black
"
@click="handleClickPhoneItem(item)"
>
<div class="ml-4">{{ item.phone }}</div>
<img
src="@/assets/icons/close.png"
@click="handleClickDelete(item.phone)"
class="mr-4 closeIcon"
/>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Input from "@/components/common/Input/index.vue";
import LoginService from "../../LoginService";
import { iRememberPhonePwd } from "../../types";
import eyeOpenIcon from "@/assets/icons/eye_open.png";
import eyeCloseIcon from "@/assets/icons/eye_close.png";
import arrowDownIcon from "@/assets/icons/arrow_down.png";
let NotCloseList = [] as Element[];
export default Vue.extend({
components: {
Input,
},
props: {
type: {
type: String,
default: "text",
},
placeholder: String,
clearable: {
type: Boolean,
default: false,
},
value: String,
maxlength: Number,
handlePhoneChange: Function,
},
data() {
return {
showPwd: false,
eyeOpenIcon,
eyeCloseIcon,
phonePwdList: [] as iRememberPhonePwd[],
arrowDownIcon,
arrowDown: true,
};
},
methods: {
handleClickPhoneItem(item: iRememberPhonePwd) {
this.$emit("selectItem", item);
},
handleChange(v: string) {
this.$emit("change", v);
},
handleClickArrowIcon() {
this.arrowDown = !this.arrowDown;
if (!this.arrowDown) {
this.fetchList();
this.$nextTick(() => {
this.initNotCloseList();
document.removeEventListener("click", this.callback);
document.addEventListener("click", this.callback);
});
}
},
callback(e: MouseEvent) {
const notClose = NotCloseList.some((el) => {
return el.contains(e.target as Node);
});
if (!notClose) {
this.arrowDown = true;
}
},
initNotCloseList() {
const phoneInputEle = this.$refs.phoneInput as Element;
const arrowImgEle = this.$refs.arrowImg as Element;
const closeIcons = Array.from(
phoneInputEle.querySelectorAll(".closeIcon")
);
NotCloseList = closeIcons;
NotCloseList.push(arrowImgEle);
},
fetchList() {
const list = LoginService.getIntance().getRememberedPhonePwdList();
this.phonePwdList = list;
},
handleClickDelete(phone: string) {
LoginService.getIntance().deletePhoneInStorage(phone);
this.fetchList();
},
},
});
</script>
<style scoped lang="less">
</style>
\ No newline at end of file
export const phoneConfig = {
maxLen: 11,
placeholder: "请输入手机号",
type: 'number',
validate(value: string) {
return value.length === 11;
}
}
export const codeConfig = {
maxLen: 4,
placeholder: "请输入验证码",
type: 'number',
validate(value: string) {
return value.length === 4;
}
}
export const pwdConfig = {
maxLen: 30,
placeholder: "请输入密码(6-30个字符)",
placeholder2: "请设置新密码(6-30个字符)",
placeholder3: "请输入原密码",
type: 'password',
validate(value: string) {
return value.length >= 6 && value.length <= 30;
},
}
<template>
<div class="px-5">
<Login
title="欢迎来到乐映"
:accountStatusCheckFunc="accountStatusCheckFunc"
:sendSmsFunc="sendSmsFunc"
:registerFunc="registerFunc"
:loginByCodeFunc="loginByCodeFunc"
:loginByPwdFunc="loginByPwdFunc"
/>
</div>
</template>
<script lang="ts">
import Vue, { VueConstructor } from "vue";
import Login from "./Login.vue";
export default (
Vue as VueConstructor<
Vue & {
sendSmsFunc: any;
accountStatusCheckFunc: any;
registerFunc: any;
loginByCodeFunc: any;
loginByPwdFunc: any;
}
>
).extend({
components: { Login },
inject: {
sendSmsFunc: "sendSmsFunc",
accountStatusCheckFunc: "accountStatusCheckFunc",
registerFunc: "registerFunc",
loginByCodeFunc: "loginByCodeFunc",
loginByPwdFunc: "loginByPwdFunc",
},
methods: {},
});
</script>
<style>
</style>
\ No newline at end of file
export enum eAccountType {
NO_REG, // 账号没注册
REG_NOPD, // 账号已注册 为设置密码
REG_PDSET, // 账号已注册 已设置密码
}
export enum eLoginWay {
PWD, // 密码
CODE // 验证码
}
export interface iRememberPhonePwd {
phone: string;
pwd: string;
}
/* 检测账户状态 */
export type tAccountStatusCheckFunc = (phone: string) => Promise<eAccountType>
/* 发送验证码 */
export type tSendSmsFunc = (phone: string) => Promise<any>
/* 发送语音验证码 */
export type tSendVoiceFunc = (phone: string) => Promise<any>
/* 注册,请求成功后的后续操作需要写在本方法中,如保存token、路由转跳*/
export type tRegisterFunc = (phone: string, code: string) => Promise<boolean>
/* 登录 请求成功后的后续操作需要写在本方法, 如保存token、路由转跳*/
export type tLoginByCodeFunc = (phone: string, code: string) => Promise<any>
export type tLoginByPwdFunc = (phone: string, pwd: string) => Promise<any>
export interface iLoginCmpProps {
accountStatusCheckFunc: tAccountStatusCheckFunc;
registerFunc: tRegisterFunc;
loginByCodeFunc: tLoginByCodeFunc;
loginByPwdFunc: tLoginByPwdFunc;
sendSmsFunc: tSendSmsFunc,
sendVoiceFunc: tSendVoiceFunc,
}
<template>
<div class="">
<div class="text-font-white text-2xl mt-16">找回密码</div>
<PhoneInput
class="mt-8"
:placeholder="phoneConfig.placeholder"
:maxlength="phoneConfig.maxLen"
:clearable="true"
:value="phone"
:type="phoneConfig.type"
@change="handlePhoneChange"
>
</PhoneInput>
<CodeInput
:placeholder="codeConfig.placeholder"
:maxlength="codeConfig.maxLen"
:value="code"
:type="codeConfig.type"
:handleChange="handleCodeChange"
:phone="phone"
:sendSmsFunc="sendSmsFunc"
:sendVoiceFunc="sendVoiceFunc"
:phoneValid="phoneValid"
>
</CodeInput>
<Input
:placeholder="pwdConfig.placeholder2"
:maxlength="pwdConfig.maxLen"
:value="pwd"
:type="pwdConfig.type"
@change="handlePwdChange"
>
<template #button> </template>
</Input>
<LoginButton
class="mt-8"
text="确定"
:disabled="getConfirmDisabled"
@click="handleClickConfirm"
></LoginButton>
</div>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import PhoneInput from "../Login/components/PhoneInput/index.vue";
import { phoneConfig, codeConfig, pwdConfig } from "../Login/const";
import { tSendSmsFunc, tSendVoiceFunc } from "../Login/types";
import Input from "@/components/common/Input/index.vue";
import LoginButton from "../Login/components/LoginButton/index.vue";
import CodeInput from "../Login/components/CodeInput/index.vue";
import { tSetPwdFunc } from "../PwdSetting/types";
export default Vue.extend({
components: {
PhoneInput,
Input,
LoginButton,
CodeInput,
},
props: {
sendSmsFunc: {
type: Function as PropType<tSendSmsFunc>,
required: true,
},
sendVoiceFunc: {
type: Function as PropType<tSendVoiceFunc>,
required: true,
},
setPwdFunc: {
type: Function as PropType<tSetPwdFunc>,
required: true,
},
},
data() {
return {
phoneConfig,
codeConfig,
pwdConfig,
phone: "",
code: "",
pwd: "",
};
},
methods: {
handlePhoneChange(value: string) {
this.phone = value;
},
handleCodeChange(v: string) {
this.code = v;
},
sendSms() {
return this.sendSmsFunc(this.phone);
},
sendVoice() {
return this.sendVoiceFunc(this.phone);
},
handlePwdChange(v: string) {
this.pwd = v;
},
handleClickConfirm() {},
},
computed: {
phoneValid(): boolean {
return phoneConfig.validate(this.phone);
},
getConfirmDisabled(): boolean {
return !(
phoneConfig.validate(this.phone) &&
codeConfig.validate(this.code) &&
pwdConfig.validate(this.pwd)
);
},
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="px-5">
<pwd-find
:sendSmsFunc="sendSmsFunc"
:sendVoiceFunc="sendVoiceFunc"
:setPwdFunc="setPwdFunc"
/>
</div>
</template>
<script lang="ts">
import Vue, { VueConstructor } from "vue";
import PwdFind from "./PwdFind.vue";
export default (
Vue as VueConstructor<
Vue & {
sendSmsFunc: any;
setPwdFunc: any;
sendVoiceFunc: any;
}
>
).extend({
components: { PwdFind },
inject: ["sendSmsFunc", "setPwdFunc", "sendVoiceFunc"],
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="text-font-white">
<div class="text-font-white text-2xl mt-16">修改登录密码</div>
<div class="mt-8 mb-9">正在为 {{ phone }} 修改登录密码</div>
<transition name="fade" mode="out-in">
<Input
v-if="modifyWay === eModifyWay.ORIGINAL_PWD"
key="1"
:placeholder="pwdConfig.placeholder3"
:maxlength="pwdConfig.maxLen"
:value="pwd"
:type="pwdConfig.type"
@change="handlePwdChange"
:showEye="false"
></Input>
<CodeInput
v-else-if="modifyWay === eModifyWay.CODE"
:placeholder="codeConfig.placeholder"
:maxlength="codeConfig.maxLen"
:value="code"
:type="codeConfig.type"
:handleChange="handleCodeChange"
:phone="phone"
:sendSmsFunc="sendSmsFunc"
:sendVoiceFunc="sendVoiceFunc"
:phoneValid="phoneValid"
>
</CodeInput>
</transition>
<Input
:placeholder="pwdConfig.placeholder2"
:maxlength="pwdConfig.maxLen"
:value="pwd2"
:type="pwdConfig.type"
@change="handlePwdChange2"
></Input>
<LoginButton
class="mt-20"
text="确定"
:disabled="getConfirmDisabled"
@click="handleClickConfirm"
></LoginButton>
<div class="mt-5 text-center text-font-blue text-sm">
<transition name="fade" mode="out-in">
<div
key="1"
v-if="modifyWay === eModifyWay.ORIGINAL_PWD"
@click="transterModifyWay(eModifyWay.CODE)"
>
验证码修改
</div>
<div key="2" v-else @click="transterModifyWay(eModifyWay.ORIGINAL_PWD)">
原密码修改
</div>
</transition>
</div>
</div>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import Input from "@/components/common/Input/index.vue";
import { pwdConfig, codeConfig, phoneConfig } from "../Login/const";
import LoginButton from "../Login/components/LoginButton/index.vue";
import { tModifyPwdFunc, eModifyWay } from "./types";
import { tSendSmsFunc, tSendVoiceFunc } from "../Login/types";
import CodeInput from "../Login/components/CodeInput/index.vue";
export default Vue.extend({
props: {
phone: {
required: true,
type: String,
},
modifyPwdFunc: {
type: Function as PropType<tModifyPwdFunc>,
required: true,
},
sendSmsFunc: {
type: Function as PropType<tSendSmsFunc>,
required: true,
},
sendVoiceFunc: {
type: Function as PropType<tSendVoiceFunc>,
required: false,
},
},
components: {
Input,
LoginButton,
CodeInput,
},
data() {
return {
pwdConfig,
codeConfig,
pwd: "",
pwd2: "",
code: "",
loading: false,
eModifyWay,
modifyWay: eModifyWay.ORIGINAL_PWD,
};
},
computed: {
getConfirmDisabled(): boolean {
if (this.modifyWay === eModifyWay.ORIGINAL_PWD) {
return (
!(pwdConfig.validate(this.pwd) && pwdConfig.validate(this.pwd2)) ||
this.loading
);
} else if (this.modifyWay === eModifyWay.CODE) {
return (
!(pwdConfig.validate(this.pwd2) && codeConfig.validate(this.code)) ||
this.loading
);
} else {
return false;
}
},
phoneValid(): boolean {
return phoneConfig.validate(this.phone);
},
},
methods: {
handleCodeChange(v: string) {
this.code = v;
},
handlePwdChange(v: string) {
this.pwd = v;
},
transterModifyWay(way: eModifyWay) {
this.modifyWay = way;
},
handlePwdChange2(v: string) {
this.pwd2 = v;
},
async handleClickConfirm() {
const { pwd, pwd2 } = this;
this.loading = true;
// ??????
try {
if (this.modifyWay === eModifyWay.ORIGINAL_PWD) {
await this.modifyPwdFunc(this.phone, this.pwd, this.pwd2);
} else if (this.modifyWay === eModifyWay.CODE) {
}
} catch (err) {}
this.loading = false;
},
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="px-5">
<pwd-modify
:phone="$route.query.phone"
:modifyPwdFunc="modifyPwdFunc"
:sendSmsFunc="sendSmsFunc"
/>
</div>
</template>
<script lang="ts">
import Vue, { VueConstructor } from "vue";
import PwdModify from "./PwdModify.vue";
export default (
Vue as VueConstructor<
Vue & {
modifyPwdFunc: any;
sendVoiceFunc: any;
sendSmsFunc: any;
}
>
).extend({
components: { PwdModify },
inject: ["modifyPwdFunc", "sendSmsFunc"],
});
</script>
<style>
</style>
\ No newline at end of file
export type tModifyPwdFunc = (phone: string, originalPwd: string, newPwd: string) => Promise<any>
export enum eModifyWay {
ORIGINAL_PWD,
CODE
}
\ No newline at end of file
<template>
<div>
<div class="text-font-white text-2xl mt-16">设置密码</div>
<div class="text-font-white mt-8">验证码已发送至 +86 {{ phone }}</div>
<CodeInput
class="mt-8"
:placeholder="codeConfig.placeholder"
:maxlength="codeConfig.maxLen"
:value="code"
:type="codeConfig.type"
:handleChange="handleCodeChange"
:phone="phone"
:sendSmsFunc="sendSmsFunc"
:sendVoiceFunc="sendVoiceFunc"
:phoneValid="phoneValid"
:sendSmsAuto="true"
/>
<Input
:placeholder="pwdConfig.placeholder2"
:maxlength="pwdConfig.maxLen"
:value="pwd"
:type="pwdConfig.type"
@change="handlePwdChange"
>
<template #button> </template>
</Input>
<LoginButton
class="mt-20"
text="确定"
:disabled="getConfirmDisabled"
@click="handleClickConfirm"
></LoginButton>
</div>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import CodeInput from "../Login/components/CodeInput/index.vue";
import { codeConfig, phoneConfig, pwdConfig } from "../Login/const";
import { tSendSmsFunc, tSendVoiceFunc } from "../Login/types";
import Input from "@/components/common/Input/index.vue";
import LoginButton from "../Login/components/LoginButton/index.vue";
import { tSetPwdFunc } from "./types";
export default Vue.extend({
components: { CodeInput, Input, LoginButton },
props: {
phone: {
type: String,
default: "",
},
sendSmsFunc: {
type: Function as PropType<tSendSmsFunc>,
required: true,
},
sendVoiceFunc: {
type: Function as PropType<tSendVoiceFunc>,
},
setPwdFunc: {
type: Function as PropType<tSetPwdFunc>,
required: true,
},
},
data() {
return {
codeConfig,
pwdConfig,
code: "",
pwd: "",
};
},
computed: {
getConfirmDisabled(): boolean {
return (
!(codeConfig.validate(this.code) && pwdConfig.validate(this.pwd)) ||
!this.phoneValid
);
},
phoneValid(): boolean {
return phoneConfig.validate(this.phone);
},
},
methods: {
handleClickConfirm() {
const { phone, code, pwd } = this;
this.setPwdFunc(phone, code, pwd);
},
handleCodeChange(v: string) {
this.code = v;
},
sendSms() {
return this.sendSmsFunc(this.phone);
},
sendVoice() {
return this.sendVoiceFunc(this.phone);
},
handlePwdChange(value: string) {
this.pwd = value;
},
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="px-5">
<pwd-setting
:phone="$route.query.phone"
:sendSmsFunc="sendSmsFunc"
:setPwdFunc="setPwdFunc"
/>
</div>
</template>
<script lang="ts">
import PwdSetting from "./PwdSetting.vue";
import Vue, { VueConstructor } from "vue";
export default (
Vue as VueConstructor<
Vue & {
sendSmsFunc: any;
setPwdFunc: any;
}
>
).extend({
components: { PwdSetting },
inject: ["sendSmsFunc", "setPwdFunc"],
methods: {},
});
</script>
/* 设置密码 */
export type tSetPwdFunc = (phone: string, code: string, pwd: string) => Promise<any>
\ No newline at end of file
<template>
<div class="bg-font-black">
<router-view></router-view>
</div>
</template>
<script lang="ts">
import { token, userMsg } from "@/util/userInfoUtils";
import Vue from "vue";
import { eAccountType } from "./Login/types";
export default Vue.extend({
provide(): object {
return {
sendSmsFunc: this.sendSmsFunc,
accountStatusCheckFunc: this.accountStatusCheckFunc,
registerFunc: this.registerFunc,
loginByCodeFunc: this.loginByCodeFunc,
loginByPwdFunc: undefined,
setPwdFunc: this.setPwdFunc,
modifyPwdFunc: this.modifyPwdFunc,
};
},
methods: {
async sendSmsFunc(phone: string) {
await this.$service.userService.getVerificationCode(phone, "1");
},
async accountStatusCheckFunc(phone: string) {
const isRegisterd = await this.$service.userService.isRegisterd(phone);
if (!isRegisterd) {
return eAccountType.NO_REG;
} else {
const isPwdSet = await this.$service.userService.isPwdSet(phone);
return isPwdSet ? eAccountType.REG_PDSET : eAccountType.REG_NOPD;
}
},
async registerFunc(phone: string, code: string) {
const ret = await this.$service.userService.loginAndSign({
codetype: "sms",
telephone: phone,
verificationCode: code,
});
if (ret) {
const { Authorization, user } = ret;
token.setToken(Authorization);
userMsg.setUserMsg(user);
this.$router.push({
name: "Home",
});
}
},
async loginByCodeFunc(phone: string, code: string) {
return this.registerFunc(phone, code);
},
async loginByPwdFunc(phone: string, pwd: string) {},
async setPwdFunc(phone: string, code: string, pwd: string) {
this.$router.push({
name: "Home",
});
return 1;
},
async modifyPwdFunc(phone: string, originalPwd: string, newPwd: string) {},
},
});
</script>
<style lang="less">
</style>
......@@ -19,6 +19,7 @@ module.exports = {
"app-red":"#ED6F6F",
"icon-bg":"#1C254C",
"font-black":"#1D2649",
"font-light-black": "#2B3661",
"font-white":"#EEF1F6",
"font-dark-blue":"#8899B3",
"font-red":"#ED6F6F",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment