mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-16 13:17:46 +00:00
支持登录网易云账号
This commit is contained in:
parent
861125ea8c
commit
5f0ef06786
15 changed files with 734 additions and 153 deletions
|
|
@ -10,8 +10,10 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.20.0",
|
"axios": "^0.20.0",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"crypto-js": "^4.0.0",
|
||||||
"dayjs": "^1.8.36",
|
"dayjs": "^1.8.36",
|
||||||
"howler": "^2.2.0",
|
"howler": "^2.2.0",
|
||||||
|
"js-cookie": "^2.2.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"plyr": "^3.6.2",
|
"plyr": "^3.6.2",
|
||||||
"register-service-worker": "^1.7.1",
|
"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 store from "@/store";
|
||||||
import NProgress from "nprogress";
|
import NProgress from "nprogress";
|
||||||
import "@/assets/css/nprogress.css";
|
import "@/assets/css/nprogress.css";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
|
||||||
NProgress.configure({ showSpinner: false, trickleSpeed: 100 });
|
NProgress.configure({ showSpinner: false, trickleSpeed: 100 });
|
||||||
|
|
||||||
|
|
@ -16,7 +17,21 @@ const routes = [
|
||||||
keepAlive: true,
|
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",
|
path: "/playlist/:id",
|
||||||
name: "playlist",
|
name: "playlist",
|
||||||
|
|
@ -88,11 +103,6 @@ const router = new VueRouter({
|
||||||
routes,
|
routes,
|
||||||
scrollBehavior(to, from, savedPosition) {
|
scrollBehavior(to, from, savedPosition) {
|
||||||
if (savedPosition) {
|
if (savedPosition) {
|
||||||
// return new Promise((resolve) => {
|
|
||||||
// setTimeout(() => {
|
|
||||||
// resolve(savedPosition);
|
|
||||||
// }, 100);
|
|
||||||
// });
|
|
||||||
return savedPosition;
|
return savedPosition;
|
||||||
} else {
|
} else {
|
||||||
return { x: 0, y: 0 };
|
return { x: 0, y: 0 };
|
||||||
|
|
@ -104,6 +114,12 @@ router.beforeEach((to, from, next) => {
|
||||||
if (to.meta.requireLogin) {
|
if (to.meta.requireLogin) {
|
||||||
if (store.state.settings.user.nickname === undefined) {
|
if (store.state.settings.user.nickname === undefined) {
|
||||||
next({ path: "/login" });
|
next({ path: "/login" });
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
Cookies.get("MUSIC_U") === undefined &&
|
||||||
|
Cookies.get("loginMode") === "account"
|
||||||
|
) {
|
||||||
|
next({ path: "/login" });
|
||||||
} else {
|
} else {
|
||||||
next();
|
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 !== 200) {
|
||||||
if (res.code === 401) {
|
if (res.code === 401) {
|
||||||
alert("token expired");
|
alert("token expired");
|
||||||
|
} else if (res.code === 502) {
|
||||||
|
alert(res.msg);
|
||||||
|
} else if (res.code === 301) {
|
||||||
|
alert("required login");
|
||||||
} else {
|
} else {
|
||||||
alert("unknow error");
|
alert("unknow error");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,95 +1,64 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="login">
|
<div class="login">
|
||||||
<div>
|
<div class="section-1">
|
||||||
<div class="title">Login</div>
|
<img src="/img/logos/yesplaymusic.png" />
|
||||||
<div class="step">
|
<svg-icon icon-class="x"></svg-icon>
|
||||||
<div class="search-box">
|
<img src="/img/logos/netease-music.png" />
|
||||||
<div class="container">
|
</div>
|
||||||
<svg-icon icon-class="search" />
|
<div class="section-2">
|
||||||
<div class="input">
|
<div
|
||||||
<input
|
class="card"
|
||||||
placeholder="请输入你的用户名"
|
@mouseover="activeCard = 1"
|
||||||
v-model="keyword"
|
@mouseleave="activeCard = 0"
|
||||||
@keydown.enter="search"
|
@click="goTo('account')"
|
||||||
/>
|
|
||||||
</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="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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapMutations } from "vuex";
|
|
||||||
import NProgress from "nprogress";
|
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 {
|
export default {
|
||||||
name: "Login",
|
name: "Login",
|
||||||
components: {
|
components: {
|
||||||
ButtonTwoTone,
|
SvgIcon,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
keyword: "",
|
activeCard: 0,
|
||||||
result: [],
|
|
||||||
activeUser: {},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(["updateUser"]),
|
goTo(path) {
|
||||||
search() {
|
this.$router.push({ path: "/login/" + path });
|
||||||
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" });
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -98,95 +67,83 @@ export default {
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.login {
|
.login {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: calc(100vh - 192px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.section-1 {
|
||||||
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;
|
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12px 12px 12px 16px;
|
img {
|
||||||
border-radius: 8px;
|
height: 64px;
|
||||||
width: 256px;
|
margin: 20px;
|
||||||
transition: 0.2s;
|
|
||||||
user-select: none;
|
|
||||||
.head {
|
|
||||||
border-radius: 50%;
|
|
||||||
height: 44px;
|
|
||||||
width: 44px;
|
|
||||||
}
|
}
|
||||||
.nickname {
|
.svg-icon {
|
||||||
font-size: 18px;
|
height: 24px;
|
||||||
margin-left: 12px;
|
width: 24px;
|
||||||
}
|
color: rgba(82, 82, 82, 0.28);
|
||||||
&:hover {
|
|
||||||
background: #f5f5f7;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.user.active {
|
.section-2 {
|
||||||
transition: 0.2s;
|
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;
|
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;
|
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>
|
</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"
|
randombytes "^2.0.0"
|
||||||
randomfill "^1.0.3"
|
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:
|
css-color-names@0.0.4, css-color-names@^0.0.4:
|
||||||
version "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"
|
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"
|
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
|
||||||
integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
|
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:
|
js-message@1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.npm.taobao.org/js-message/download/js-message-1.0.5.tgz#2300d24b1af08e89dd095bc1a4c9c9cfcb892d15"
|
resolved "https://registry.npm.taobao.org/js-message/download/js-message-1.0.5.tgz#2300d24b1af08e89dd095bc1a4c9c9cfcb892d15"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue