diff --git a/src/api/login.ts b/src/api/login.ts index 192c24b..200cc69 100644 --- a/src/api/login.ts +++ b/src/api/login.ts @@ -1,31 +1,46 @@ import request from "@/utils/request"; +// 创建二维码key // /login/qr/key export function getQrKey() { return request.get("/login/qr/key"); } +// 创建二维码 // /login/qr/create export function createQr(key: any) { return request.get("/login/qr/create", { params: { key: key, qrimg: true } }); } +// 获取二维码状态 // /login/qr/check export function checkQr(key: any) { return request.get("/login/qr/check", { params: { key: key } }); } +// 获取登录状态 // /login/status export function getLoginStatus() { return request.get("/login/status"); } +// 获取用户信息 // /user/account export function getUserDetail() { return request.get("/user/account"); } +// 退出登录 // /logout export function logout() { return request.get("/logout"); } + +// 手机号登录 +// /login/cellphone +export function loginByCellphone(phone: any, password: any) { + return request.post("/login/cellphone", { + phone: phone, + password: password, + }); +} diff --git a/src/api/user.ts b/src/api/user.ts new file mode 100644 index 0000000..45ea1cc --- /dev/null +++ b/src/api/user.ts @@ -0,0 +1,11 @@ +import request from "@/utils/request"; + +// /user/detail +export function getUserDetail(uid: number) { + return request.get("/user/detail", { params: { uid } }); +} + +// /user/playlist +export function getUserPlaylist(uid: number) { + return request.get("/user/playlist", { params: { uid } }); +} diff --git a/src/layout/components/SearchBar.vue b/src/layout/components/SearchBar.vue index 536dab8..55f8028 100644 --- a/src/layout/components/SearchBar.vue +++ b/src/layout/components/SearchBar.vue @@ -55,9 +55,13 @@ const loadHotSearchKeyword = async () => { hotSearchKeyword.value = data.data.showKeyword hotSearchValue.value = data.data.realkeyword } + +store.state.user = JSON.parse(localStorage.getItem('user') || '{}') + const loadPage = async () => { const { data } = await getUserDetail() store.state.user = data.profile + localStorage.setItem('user', JSON.stringify(data.profile)) } const toLogin = () => { diff --git a/src/router/home.ts b/src/router/home.ts index 774d60b..382f149 100644 --- a/src/router/home.ts +++ b/src/router/home.ts @@ -29,6 +29,16 @@ const layoutRouter = [ }, component: () => import("@/views/list/index.vue"), }, + { + path: "/user", + name: "user", + mate: { + title: "用户", + keepAlive: true, + icon: "icon-Profile", + }, + component: () => import("@/views/user/index.vue"), + }, ]; export default layoutRouter; diff --git a/src/type/user.ts b/src/type/user.ts new file mode 100644 index 0000000..fc3fc35 --- /dev/null +++ b/src/type/user.ts @@ -0,0 +1,91 @@ +export interface IUserDetail { + level: number; + listenSongs: number; + userPoint: UserPoint; + mobileSign: boolean; + pcSign: boolean; + profile: Profile; + peopleCanSeeMyPlayRecord: boolean; + bindings: Binding[]; + adValid: boolean; + code: number; + createTime: number; + createDays: number; + profileVillageInfo: ProfileVillageInfo; +} + +interface ProfileVillageInfo { + title: string; + imageUrl?: any; + targetUrl: string; +} + +interface Binding { + userId: number; + url: string; + expiresIn: number; + refreshTime: number; + bindingTime: number; + tokenJsonStr?: any; + expired: boolean; + id: number; + type: number; +} + +interface Profile { + avatarDetail?: any; + userId: number; + avatarImgIdStr: string; + backgroundImgIdStr: string; + description: string; + vipType: number; + userType: number; + createTime: number; + nickname: string; + avatarUrl: string; + experts: Experts; + expertTags?: any; + djStatus: number; + accountStatus: number; + birthday: number; + gender: number; + province: number; + city: number; + defaultAvatar: boolean; + avatarImgId: number; + backgroundImgId: number; + backgroundUrl: string; + mutual: boolean; + followed: boolean; + remarkName?: any; + authStatus: number; + detailDescription: string; + signature: string; + authority: number; + followeds: number; + follows: number; + blacklist: boolean; + eventCount: number; + allSubscribedCount: number; + playlistBeSubscribedCount: number; + avatarImgId_str: string; + followTime?: any; + followMe: boolean; + artistIdentity: any[]; + cCount: number; + sDJPCount: number; + playlistCount: number; + sCount: number; + newFollows: number; +} + +interface Experts {} + +interface UserPoint { + userId: number; + balance: number; + updateTime: number; + version: number; + status: number; + blockBalance: number; +} diff --git a/src/views/list/index.vue b/src/views/list/index.vue index bc1556b..84a735c 100644 --- a/src/views/list/index.vue +++ b/src/views/list/index.vue @@ -22,7 +22,6 @@ const selectRecommendItem = async (item: IRecommendItem) => { showMusic.value = true recommendItem.value = item listDetail.value = data - } const closeMusic = () => { showMusic.value = false diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 7f6aca2..9eed3c1 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -2,13 +2,16 @@ import { getQrKey, createQr, checkQr, getLoginStatus } from '@/api/login' import { onMounted } from '@vue/runtime-core'; import { ref } from 'vue'; -import { getUserDetail } from '@/api/login'; +import { getUserDetail, loginByCellphone } from '@/api/login'; import { useStore } from 'vuex'; import { useMessage } from 'naive-ui' +import { setAnimationClass, setAnimationDelay } from "@/utils"; +import { useRouter } from 'vue-router'; + const message = useMessage() - const store = useStore(); +const router = useRouter() const qrUrl = ref() onMounted(() => { @@ -29,8 +32,6 @@ const timerIsQr = (key: string) => { const timer = setInterval(async () => { const { data } = await checkQr(key) - console.log(data); - if (data.code === 800) { clearInterval(timer) } @@ -49,15 +50,53 @@ const timerIsQr = (key: string) => { }, 5000); } + +// 是否扫码登陆 +const isQr = ref(true) +const chooseQr = () => { + isQr.value = !isQr.value +} + +// 手机号登录 +const phone = ref('') +const password = ref('') +const loginPhone = async () => { + const { data } = await loginByCellphone(phone.value, password.value) + if (data.code === 200) { + message.success('登录成功') + store.state.user = data.profile + localStorage.setItem('token', data.cookie) + setTimeout(() => { + router.push('/') + }, 1000); + } +} + @@ -67,13 +106,61 @@ const timerIsQr = (key: string) => { } .login-title { - @apply text-3xl font-bold mb-6; + @apply text-2xl font-bold mb-6; } .text { @apply mt-4 text-green-500 text-xs; } -.qr { +.phone-login { + width: 350px; + height: 550px; + @apply rounded-2xl bg-cover bg-no-repeat relative overflow-hidden; + background-image: url(https://z3.ax1x.com/2021/09/30/4IMyUx.jpg); + background-color: #000; + + .bg { + @apply absolute w-full h-full bg-black opacity-30; + } + + .bottom { + width: 200%; + height: 250px; + bottom: -180px; + border-radius: 50%; + left: 50%; + padding: 10px; + transform: translateX(-50%); + color: #ffffff99; + @apply absolute bg-black flex justify-center text-lg font-bold cursor-pointer; + } + + .content { + @apply absolute w-full h-full p-4 flex flex-col items-center justify-center pb-20 text-center; + .qr-img { + @apply opacity-80 rounded-2xl cursor-pointer; + } + + .phone { + animation-duration: 0.5s; + &-page { + background-color: #ffffffdd; + width: 250px; + @apply rounded-2xl overflow-hidden; + } + + &-input { + height: 40px; + border-bottom: 1px solid #e5e5e5; + @apply w-full text-black px-4 outline-none; + } + } + .btn-login { + width: 250px; + height: 40px; + @apply mt-10 text-white rounded-xl bg-black opacity-60; + } + } } \ No newline at end of file diff --git a/src/views/search/index.vue b/src/views/search/index.vue index fb42424..306ea96 100644 --- a/src/views/search/index.vue +++ b/src/views/search/index.vue @@ -1,10 +1,15 @@ @@ -59,7 +69,9 @@ onMounted(() => { loadHotSearch(); }); +const hotKeyword = ref(route.query.keyword || "搜索列表"); const clickHotKeyword = (keyword: string) => { + hotKeyword.value = keyword; router.push({ path: "/search", query: { @@ -92,7 +104,6 @@ loadSearch(route.query.keyword); watch( () => route.query, async newParams => { - console.log(newParams); loadSearch(newParams.keyword); } ) @@ -108,6 +119,8 @@ watch( } .hot-search { @apply mt-3 mr-4 rounded-xl flex-1 overflow-hidden; + height: 740px; + background-color: #0d0d0d; animation-duration: 0.2s; min-width: 400px; &-item { @@ -122,6 +135,12 @@ watch( } .search-list { - @apply mt-3 flex-1; + @apply mt-3 flex-1 rounded-xl; + height: 740px; + background-color: #0d0d0d; +} + +.title { + @apply text-gray-200 text-xl font-bold my-2 mx-4; } diff --git a/src/views/user/index.vue b/src/views/user/index.vue new file mode 100644 index 0000000..3946ee8 --- /dev/null +++ b/src/views/user/index.vue @@ -0,0 +1,129 @@ + + + + + \ No newline at end of file