mirror of
https://github.com/qier222/YesPlayMusic.git
synced 2024-11-22 13:36:20 +08:00
支持登录网易云账号
This commit is contained in:
parent
861125ea8c
commit
5f0ef06786
|
@ -10,8 +10,10 @@
|
|||
"dependencies": {
|
||||
"axios": "^0.20.0",
|
||||
"core-js": "^3.6.5",
|
||||
"crypto-js": "^4.0.0",
|
||||
"dayjs": "^1.8.36",
|
||||
"howler": "^2.2.0",
|
||||
"js-cookie": "^2.2.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"plyr": "^3.6.2",
|
||||
"register-service-worker": "^1.7.1",
|
||||
|
|
BIN
public/img/logos/netease-music.png
Normal file
BIN
public/img/logos/netease-music.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
public/img/logos/yesplaymusic.png
Normal file
BIN
public/img/logos/yesplaymusic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
42
src/api/auth.js
Normal file
42
src/api/auth.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
import request from "@/utils/request";
|
||||
|
||||
export function loginWithPhone(params) {
|
||||
//必选参数 :
|
||||
// phone: 手机号码
|
||||
// password: 密码
|
||||
// 可选参数 :
|
||||
// countrycode: 国家码,用于国外手机号登录,例如美国传入:1
|
||||
// md5_password: md5加密后的密码,传入后 password 将失效
|
||||
return request({
|
||||
url: "/login/cellphone",
|
||||
method: "post",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function loginWithEmail(params) {
|
||||
// 必选参数 :
|
||||
// email: 163 网易邮箱
|
||||
// password: 密码
|
||||
// 可选参数 :
|
||||
// md5_password: md5加密后的密码,传入后 password 将失效
|
||||
return request({
|
||||
url: "/login",
|
||||
method: "post",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function loginRefresh() {
|
||||
return request({
|
||||
url: "/login/refresh",
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
return request({
|
||||
url: "/logout",
|
||||
method: "post",
|
||||
});
|
||||
}
|
1
src/assets/icons/lock.svg
Normal file
1
src/assets/icons/lock.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="lock-alt" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="svg-inline--fa fa-lock-alt fa-w-14 fa-7x"><path fill="currentColor" d="M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zM264 392c0 22.1-17.9 40-40 40s-40-17.9-40-40v-48c0-22.1 17.9-40 40-40s40 17.9 40 40v48zm32-168H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z" class=""></path></svg>
|
After Width: | Height: | Size: 550 B |
1
src/assets/icons/mail.svg
Normal file
1
src/assets/icons/mail.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="envelope" class="svg-inline--fa fa-envelope fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"></path></svg>
|
After Width: | Height: | Size: 700 B |
1
src/assets/icons/mobile.svg
Normal file
1
src/assets/icons/mobile.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="mobile-alt" class="svg-inline--fa fa-mobile-alt fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M272 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h224c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM160 480c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm112-108c0 6.6-5.4 12-12 12H60c-6.6 0-12-5.4-12-12V60c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v312z"></path></svg>
|
After Width: | Height: | Size: 516 B |
1
src/assets/icons/x.svg
Normal file
1
src/assets/icons/x.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="times" class="svg-inline--fa fa-times fa-w-11" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 352 512"><path fill="currentColor" d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"></path></svg>
|
After Width: | Height: | Size: 645 B |
|
@ -3,6 +3,7 @@ import VueRouter from "vue-router";
|
|||
import store from "@/store";
|
||||
import NProgress from "nprogress";
|
||||
import "@/assets/css/nprogress.css";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
NProgress.configure({ showSpinner: false, trickleSpeed: 100 });
|
||||
|
||||
|
@ -16,7 +17,21 @@ const routes = [
|
|||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{ path: "/login", name: "login", component: () => import("@/views/login") },
|
||||
{
|
||||
path: "/login",
|
||||
name: "login",
|
||||
component: () => import("@/views/login"),
|
||||
},
|
||||
{
|
||||
path: "/login/username",
|
||||
name: "loginUsername",
|
||||
component: () => import("@/views/loginUsername"),
|
||||
},
|
||||
{
|
||||
path: "/login/account",
|
||||
name: "loginAccount",
|
||||
component: () => import("@/views/loginAccount"),
|
||||
},
|
||||
{
|
||||
path: "/playlist/:id",
|
||||
name: "playlist",
|
||||
|
@ -88,11 +103,6 @@ const router = new VueRouter({
|
|||
routes,
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
if (savedPosition) {
|
||||
// return new Promise((resolve) => {
|
||||
// setTimeout(() => {
|
||||
// resolve(savedPosition);
|
||||
// }, 100);
|
||||
// });
|
||||
return savedPosition;
|
||||
} else {
|
||||
return { x: 0, y: 0 };
|
||||
|
@ -104,6 +114,12 @@ router.beforeEach((to, from, next) => {
|
|||
if (to.meta.requireLogin) {
|
||||
if (store.state.settings.user.nickname === undefined) {
|
||||
next({ path: "/login" });
|
||||
}
|
||||
if (
|
||||
Cookies.get("MUSIC_U") === undefined &&
|
||||
Cookies.get("loginMode") === "account"
|
||||
) {
|
||||
next({ path: "/login" });
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
|
|
12
src/utils/auth.js
Normal file
12
src/utils/auth.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import Cookies from "js-cookie";
|
||||
import { logout } from "@/api/auth";
|
||||
|
||||
export function doLogout() {
|
||||
console.log("logout");
|
||||
logout();
|
||||
Cookies.remove("loginMode");
|
||||
}
|
||||
|
||||
export function isLoggedIn() {
|
||||
return Cookies.get("MUSIC_U") !== undefined ? true : false;
|
||||
}
|
|
@ -12,6 +12,10 @@ service.interceptors.response.use(
|
|||
if (res.code !== 200) {
|
||||
if (res.code === 401) {
|
||||
alert("token expired");
|
||||
} else if (res.code === 502) {
|
||||
alert(res.msg);
|
||||
} else if (res.code === 301) {
|
||||
alert("required login");
|
||||
} else {
|
||||
alert("unknow error");
|
||||
}
|
||||
|
|
|
@ -1,95 +1,64 @@
|
|||
<template>
|
||||
<div class="login">
|
||||
<div>
|
||||
<div class="title">Login</div>
|
||||
<div class="step">
|
||||
<div class="search-box">
|
||||
<div class="container">
|
||||
<svg-icon icon-class="search" />
|
||||
<div class="input">
|
||||
<input
|
||||
placeholder="请输入你的用户名"
|
||||
v-model="keyword"
|
||||
@keydown.enter="search"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="name" v-show="activeUser.nickname === undefined">
|
||||
按Enter搜索
|
||||
</div>
|
||||
<div class="name" v-show="activeUser.nickname !== undefined">
|
||||
在列表中选中你的账号
|
||||
</div>
|
||||
<div class="user-list">
|
||||
<div
|
||||
class="user"
|
||||
v-for="user in result"
|
||||
:key="user.id"
|
||||
:class="{ active: user.nickname === activeUser.nickname }"
|
||||
@click="activeUser = user"
|
||||
>
|
||||
<img class="head" :src="user.avatarUrl | resizeImage" />
|
||||
<div class="nickname">
|
||||
{{ user.nickname }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ButtonTwoTone
|
||||
@click.native="confirm"
|
||||
v-show="activeUser.nickname !== undefined"
|
||||
>确定</ButtonTwoTone
|
||||
<div class="section-1">
|
||||
<img src="/img/logos/yesplaymusic.png" />
|
||||
<svg-icon icon-class="x"></svg-icon>
|
||||
<img src="/img/logos/netease-music.png" />
|
||||
</div>
|
||||
<div class="section-2">
|
||||
<div
|
||||
class="card"
|
||||
@mouseover="activeCard = 1"
|
||||
@mouseleave="activeCard = 0"
|
||||
@click="goTo('account')"
|
||||
>
|
||||
<div class="container" :class="{ active: activeCard === 1 }">
|
||||
<div class="title-info">
|
||||
<div class="title">登录网易云账号</div>
|
||||
<div class="info">可访问全部数据</div>
|
||||
</div>
|
||||
<svg-icon icon-class="arrow-right"></svg-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="card"
|
||||
@mouseover="activeCard = 2"
|
||||
@mouseleave="activeCard = 0"
|
||||
@click="goTo('username')"
|
||||
>
|
||||
<div class="container" :class="{ active: activeCard === 2 }">
|
||||
<div class="title-info">
|
||||
<div class="title">搜索网易云账号</div>
|
||||
<div class="info">只能读取账号公开数据</div>
|
||||
</div>
|
||||
<svg-icon icon-class="arrow-right"></svg-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from "vuex";
|
||||
import NProgress from "nprogress";
|
||||
import { search } from "@/api/others";
|
||||
import { userPlaylist } from "@/api/user";
|
||||
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
import SvgIcon from "@/components/SvgIcon.vue";
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
components: {
|
||||
ButtonTwoTone,
|
||||
SvgIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: "",
|
||||
result: [],
|
||||
activeUser: {},
|
||||
activeCard: 0,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
NProgress.done();
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateUser"]),
|
||||
search() {
|
||||
search({ keywords: this.keyword, limit: 9, type: 1002 }).then((data) => {
|
||||
this.result = data.result.userprofiles;
|
||||
this.activeUser = this.result[0];
|
||||
});
|
||||
},
|
||||
confirm() {
|
||||
this.updateUser(this.activeUser);
|
||||
userPlaylist({
|
||||
uid: this.activeUser.userId,
|
||||
limit: 1,
|
||||
}).then((data) => {
|
||||
this.$store.commit("updateUserInfo", {
|
||||
key: "likedSongPlaylistID",
|
||||
value: data.playlist[0].id,
|
||||
});
|
||||
this.$router.push({ path: "/library" });
|
||||
});
|
||||
goTo(path) {
|
||||
this.$router.push({ path: "/login/" + path });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -98,95 +67,83 @@ export default {
|
|||
<style lang="scss" scoped>
|
||||
.login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: calc(100vh - 192px);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 42px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.step {
|
||||
margin-top: 18px;
|
||||
.name {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
color: rgba(0, 0, 0, 0.78);
|
||||
}
|
||||
}
|
||||
|
||||
.search-box {
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
border-radius: 11px;
|
||||
width: 326px;
|
||||
background: #eaeffd;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
color: #335eea;
|
||||
margin: {
|
||||
left: 12px;
|
||||
right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
font-size: 22px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
width: 100%;
|
||||
font-weight: 600;
|
||||
margin-top: -1px;
|
||||
color: #335eea;
|
||||
&::placeholder {
|
||||
color: #335eeac4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.user {
|
||||
margin-right: 16px;
|
||||
.section-1 {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 12px 12px 16px;
|
||||
border-radius: 8px;
|
||||
width: 256px;
|
||||
transition: 0.2s;
|
||||
user-select: none;
|
||||
.head {
|
||||
border-radius: 50%;
|
||||
height: 44px;
|
||||
width: 44px;
|
||||
img {
|
||||
height: 64px;
|
||||
margin: 20px;
|
||||
}
|
||||
.nickname {
|
||||
font-size: 18px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
&:hover {
|
||||
background: #f5f5f7;
|
||||
.svg-icon {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
color: rgba(82, 82, 82, 0.28);
|
||||
}
|
||||
}
|
||||
|
||||
.user.active {
|
||||
transition: 0.2s;
|
||||
.section-2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.card {
|
||||
cursor: pointer;
|
||||
margin-top: 14px;
|
||||
margin-bottom: 14px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #eaeffd;
|
||||
.name {
|
||||
border-radius: 8px;
|
||||
height: 128px;
|
||||
width: 300px;
|
||||
transition: all 0.3s;
|
||||
|
||||
.active {
|
||||
.title-info {
|
||||
transform: translateX(-8px);
|
||||
}
|
||||
.svg-icon {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translateX(8px);
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
// justify-content: space-around;
|
||||
align-items: center;
|
||||
|
||||
color: #335eea;
|
||||
}
|
||||
|
||||
.title-info {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.info {
|
||||
margin-top: 2px;
|
||||
font-size: 14px;
|
||||
color: rgba(51, 94, 234, 0.78);
|
||||
}
|
||||
.svg-icon {
|
||||
opacity: 0;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
margin-left: 16px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
340
src/views/loginAccount.vue
Normal file
340
src/views/loginAccount.vue
Normal file
|
@ -0,0 +1,340 @@
|
|||
<template>
|
||||
<div class="login">
|
||||
<div class="section-1">
|
||||
<img src="/img/logos/netease-music.png" />
|
||||
</div>
|
||||
<div class="title">登录网易云账号</div>
|
||||
<div class="section-2">
|
||||
<div class="input-box" v-show="mode === 'phone'">
|
||||
<div class="container" :class="{ active: inputFocus === 'phone' }">
|
||||
<svg-icon icon-class="mobile" />
|
||||
<div class="inputs">
|
||||
<input
|
||||
id="countryCode"
|
||||
:placeholder="inputFocus === 'phone' ? '' : '国际区号'"
|
||||
v-model="countryCode"
|
||||
@focus="inputFocus = 'phone'"
|
||||
@blur="inputFocus = ''"
|
||||
/>
|
||||
<input
|
||||
id="phoneNumber"
|
||||
:placeholder="inputFocus === 'phone' ? '' : '手机号'"
|
||||
v-model="phoneNumber"
|
||||
@focus="inputFocus = 'phone'"
|
||||
@blur="inputFocus = ''"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-box" v-show="mode === 'email'">
|
||||
<div class="container" :class="{ active: inputFocus === 'email' }">
|
||||
<svg-icon icon-class="mail" />
|
||||
<div class="inputs">
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
:placeholder="inputFocus === 'email' ? '' : '邮箱'"
|
||||
v-model="email"
|
||||
@focus="inputFocus = 'email'"
|
||||
@blur="inputFocus = ''"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-box">
|
||||
<div class="container" :class="{ active: inputFocus === 'password' }">
|
||||
<svg-icon icon-class="lock" />
|
||||
<div class="inputs">
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
:placeholder="inputFocus === 'password' ? '' : '密码'"
|
||||
v-model="password"
|
||||
@focus="inputFocus = 'password'"
|
||||
@blur="inputFocus = ''"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="confirm">
|
||||
<button @click="login" v-show="!processing">登录</button>
|
||||
<button v-show="processing" class="loading" disabled>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="other-login">
|
||||
<a v-show="mode === 'phone'" @click="mode = 'email'">使用邮箱登录</a>
|
||||
<a v-show="mode === 'email'" @click="mode = 'phone'">使用手机号登录</a>
|
||||
</div>
|
||||
<div class="notice">
|
||||
YesPlayMusic 承诺不会保存你的任何账号信息到云端。<br />
|
||||
你的密码会在本地进行 MD5 加密后再传输到网易云 API。<br />
|
||||
YesPlayMusic 并非网易云官方网站,输入账号信息前请慎重考虑。 你也可以前往
|
||||
<a href="https://github.com/qier222/YesPlayMusic"
|
||||
>YesPlayMusic 的 GitHub 源代码仓库</a
|
||||
>
|
||||
自行构建并使用自托管的网易云 API。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NProgress from "nprogress";
|
||||
import { loginWithPhone, loginWithEmail } from "@/api/auth";
|
||||
import md5 from "crypto-js/md5";
|
||||
import { mapMutations } from "vuex";
|
||||
import { userPlaylist } from "@/api/user";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
return {
|
||||
processing: false,
|
||||
mode: "email",
|
||||
countryCode: "+86",
|
||||
phoneNumber: "",
|
||||
email: "",
|
||||
password: "",
|
||||
smsCode: "",
|
||||
inputFocus: "",
|
||||
};
|
||||
},
|
||||
created() {
|
||||
if (this.$route.query.mode === "phone") {
|
||||
this.mode = "phone";
|
||||
}
|
||||
NProgress.done();
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateUser", "updateUserInfo"]),
|
||||
afterLogin() {
|
||||
Cookies.set("loginMode", "account", { expires: 3650 });
|
||||
userPlaylist({
|
||||
uid: this.$store.state.settings.user.userId,
|
||||
limit: 1,
|
||||
}).then((data) => {
|
||||
this.updateUserInfo({
|
||||
key: "likedSongPlaylistID",
|
||||
value: data.playlist[0].id,
|
||||
});
|
||||
this.$router.push({ path: "/library" });
|
||||
});
|
||||
},
|
||||
login() {
|
||||
this.processing = true;
|
||||
if (this.mode === "phone") {
|
||||
if (
|
||||
this.countrycode === "" ||
|
||||
this.phone === "" ||
|
||||
this.password === ""
|
||||
) {
|
||||
alert("请输入完整的信息");
|
||||
this.processing = false;
|
||||
return;
|
||||
}
|
||||
loginWithPhone({
|
||||
countrycode: this.countryCode.replace("+", "").replaceAll(" ", ""),
|
||||
phone: this.phoneNumber.replaceAll(" ", ""),
|
||||
password: "fakePassword",
|
||||
md5_password: md5(this.password).toString(),
|
||||
})
|
||||
.then((data) => {
|
||||
this.updateUser(data.profile);
|
||||
this.afterLogin();
|
||||
})
|
||||
.catch(() => {
|
||||
this.processing = false;
|
||||
});
|
||||
} else {
|
||||
if (this.email === "" || this.password === "") {
|
||||
alert("请输入完整的信息");
|
||||
this.processing = false;
|
||||
return;
|
||||
}
|
||||
loginWithEmail({
|
||||
email: this.email.replaceAll(" ", ""),
|
||||
password: "fakePassword",
|
||||
md5_password: md5(this.password).toString(),
|
||||
})
|
||||
.then((data) => {
|
||||
this.updateUser(data.profile);
|
||||
this.afterLogin();
|
||||
})
|
||||
.catch(() => {
|
||||
this.processing = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
min-height: calc(100vh - 192px);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.section-1 {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
img {
|
||||
height: 64px;
|
||||
margin: 20px;
|
||||
}
|
||||
.svg-icon {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
color: rgba(82, 82, 82, 0.28);
|
||||
}
|
||||
}
|
||||
|
||||
.section-2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.input-box {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 46px;
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
border-radius: 8px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
color: #aaaaaa;
|
||||
margin: {
|
||||
left: 12px;
|
||||
right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.inputs {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 20px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
width: 96%;
|
||||
font-weight: 600;
|
||||
margin-top: -1px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
}
|
||||
|
||||
input#countryCode {
|
||||
flex: 2;
|
||||
}
|
||||
input#phoneNumber {
|
||||
flex: 14;
|
||||
}
|
||||
|
||||
.active {
|
||||
background: #eaeffd;
|
||||
input,
|
||||
.svg-icon {
|
||||
color: #335eea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.confirm button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
background-color: rgba(51, 94, 234, 0.1);
|
||||
color: #335eea;
|
||||
border-radius: 8px;
|
||||
margin-top: 24px;
|
||||
transition: 0.2s;
|
||||
padding: 8px;
|
||||
width: 100%;
|
||||
width: 300px;
|
||||
&:hover {
|
||||
transform: scale(1.06);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.94);
|
||||
}
|
||||
}
|
||||
|
||||
.other-login {
|
||||
margin-top: 24px;
|
||||
a {
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
}
|
||||
}
|
||||
|
||||
.notice {
|
||||
width: 300px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.18);
|
||||
margin-top: 48px;
|
||||
padding-top: 12px;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.48);
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
0% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
20% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
button.loading {
|
||||
height: 44px;
|
||||
cursor: unset;
|
||||
&:hover {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
.loading span {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: #335eea;
|
||||
border-radius: 50%;
|
||||
margin: 0 2px;
|
||||
animation: loading 1.4s infinite both;
|
||||
}
|
||||
|
||||
.loading span:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.loading span:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
</style>
|
194
src/views/loginUsername.vue
Normal file
194
src/views/loginUsername.vue
Normal file
|
@ -0,0 +1,194 @@
|
|||
<template>
|
||||
<div class="login">
|
||||
<div>
|
||||
<div class="title">用户名登录</div>
|
||||
<div class="sestion">
|
||||
<div class="search-box">
|
||||
<div class="container">
|
||||
<svg-icon icon-class="search" />
|
||||
<div class="input">
|
||||
<input
|
||||
placeholder="请输入你的网易云用户名"
|
||||
v-model="keyword"
|
||||
@keydown.enter="search"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sestion">
|
||||
<div class="name" v-show="activeUser.nickname === undefined">
|
||||
按Enter搜索
|
||||
</div>
|
||||
<div class="name" v-show="activeUser.nickname !== undefined">
|
||||
在列表中选中你的账号
|
||||
</div>
|
||||
<div class="user-list">
|
||||
<div
|
||||
class="user"
|
||||
v-for="user in result"
|
||||
:key="user.id"
|
||||
:class="{ active: user.nickname === activeUser.nickname }"
|
||||
@click="activeUser = user"
|
||||
>
|
||||
<img class="head" :src="user.avatarUrl | resizeImage" />
|
||||
<div class="nickname">
|
||||
{{ user.nickname }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ButtonTwoTone
|
||||
@click.native="confirm"
|
||||
v-show="activeUser.nickname !== undefined"
|
||||
>确定</ButtonTwoTone
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from "vuex";
|
||||
import NProgress from "nprogress";
|
||||
import { search } from "@/api/others";
|
||||
import Cookies from "js-cookie";
|
||||
import { userPlaylist } from "@/api/user";
|
||||
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
|
||||
export default {
|
||||
name: "loginUsername",
|
||||
components: {
|
||||
ButtonTwoTone,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: "",
|
||||
result: [],
|
||||
activeUser: {},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
NProgress.done();
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateUser", "updateUserInfo"]),
|
||||
search() {
|
||||
search({ keywords: this.keyword, limit: 9, type: 1002 }).then((data) => {
|
||||
this.result = data.result.userprofiles;
|
||||
this.activeUser = this.result[0];
|
||||
});
|
||||
},
|
||||
confirm() {
|
||||
this.updateUser(this.activeUser);
|
||||
Cookies.set("loginMode", "username", { expires: 3650 });
|
||||
userPlaylist({
|
||||
uid: this.activeUser.userId,
|
||||
limit: 1,
|
||||
}).then((data) => {
|
||||
this.updateUserInfo({
|
||||
key: "likedSongPlaylistID",
|
||||
value: data.playlist[0].id,
|
||||
});
|
||||
this.$router.push({ path: "/library" });
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.login {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 42px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.sestion {
|
||||
margin-top: 18px;
|
||||
.name {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
color: rgba(0, 0, 0, 0.78);
|
||||
}
|
||||
}
|
||||
|
||||
.search-box {
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
border-radius: 11px;
|
||||
width: 326px;
|
||||
background: #eaeffd;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
color: #335eea;
|
||||
margin: {
|
||||
left: 12px;
|
||||
right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
font-size: 22px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
width: 115%;
|
||||
font-weight: 600;
|
||||
margin-top: -1px;
|
||||
color: #335eea;
|
||||
&::placeholder {
|
||||
color: #335eeac4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.user {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 12px 12px 16px;
|
||||
border-radius: 8px;
|
||||
width: 256px;
|
||||
transition: 0.2s;
|
||||
user-select: none;
|
||||
.head {
|
||||
border-radius: 50%;
|
||||
height: 44px;
|
||||
width: 44px;
|
||||
}
|
||||
.nickname {
|
||||
font-size: 18px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
&:hover {
|
||||
background: #f5f5f7;
|
||||
}
|
||||
}
|
||||
|
||||
.user.active {
|
||||
transition: 0.2s;
|
||||
background: #eaeffd;
|
||||
.name {
|
||||
color: #335eea;
|
||||
}
|
||||
}
|
||||
</style>
|
10
yarn.lock
10
yarn.lock
|
@ -2840,6 +2840,11 @@ crypto-browserify@^3.11.0:
|
|||
randombytes "^2.0.0"
|
||||
randomfill "^1.0.3"
|
||||
|
||||
crypto-js@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.0.0.tgz#2904ab2677a9d042856a2ea2ef80de92e4a36dcc"
|
||||
integrity sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==
|
||||
|
||||
css-color-names@0.0.4, css-color-names@^0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.npm.taobao.org/css-color-names/download/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
|
||||
|
@ -5042,6 +5047,11 @@ js-base64@^2.1.9:
|
|||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
|
||||
integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
|
||||
|
||||
js-cookie@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
|
||||
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
|
||||
|
||||
js-message@1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npm.taobao.org/js-message/download/js-message-1.0.5.tgz#2300d24b1af08e89dd095bc1a4c9c9cfcb892d15"
|
||||
|
|
Loading…
Reference in New Issue
Block a user