diff --git a/package-lock.json b/package-lock.json
index 11757d64d18c6d86d0762896b72369febfb7b80c..051231706d92efdaac854b597e3e9c332b24f35e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
         "colorthief": "^2.4.0",
         "core-js": "^3.38.1",
         "element-plus": "^2.8.2",
+        "js-md5": "^0.8.3",
         "pinia": "^2.2.2",
         "swiper": "^11.1.14",
         "tippy.js": "^6.3.7",
@@ -11167,6 +11168,11 @@
         "@sideway/pinpoint": "^2.0.0"
       }
     },
+    "node_modules/js-md5": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz",
+      "integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="
+    },
     "node_modules/js-message": {
       "version": "1.0.7",
       "resolved": "https://repo.huaweicloud.com/repository/npm/js-message/-/js-message-1.0.7.tgz",
@@ -26017,6 +26023,11 @@
         "@sideway/pinpoint": "^2.0.0"
       }
     },
+    "js-md5": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz",
+      "integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="
+    },
     "js-message": {
       "version": "1.0.7",
       "resolved": "https://repo.huaweicloud.com/repository/npm/js-message/-/js-message-1.0.7.tgz",
diff --git a/package.json b/package.json
index 0062ab5fd2f86db67b59d73184fd312a866a51ab..190843cc65d8fff7490decaf252b95ef5d97e29d 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
     "colorthief": "^2.4.0",
     "core-js": "^3.38.1",
     "element-plus": "^2.8.2",
+    "js-md5": "^0.8.3",
     "pinia": "^2.2.2",
     "swiper": "^11.1.14",
     "tippy.js": "^6.3.7",
diff --git a/src/api/resolve.js b/src/api/resolve.js
index 6be4c21f2c6b3916c436eba146c9037b6c54afea..cf539a9843073c1ceae3767310f0953dbdb4254a 100644
--- a/src/api/resolve.js
+++ b/src/api/resolve.js
@@ -1,5 +1,5 @@
 import {axios} from "@/utils/request";
-import {PLAYLIST_MODULE, RESOLVE_MODULE, SONG_MODULE, USER_MODULE} from "@/api/_prefix";
+import {ARTIST_MODULE, PLAYLIST_MODULE, RESOLVE_MODULE, SONG_MODULE, USER_MODULE} from "@/api/_prefix";
 
 /*
     // TODO: newly added
@@ -35,4 +35,12 @@ export const getPlaylistById = (playlistId) => {
         .then(res => {
             return res;
         });
+}
+
+export const getArtistById = (artistId) => {
+    console.log(artistId)
+    return axios.get(`${ARTIST_MODULE}/${artistId}`)
+        .then(res => {
+            return res;
+        });
 }
\ No newline at end of file
diff --git a/src/api/song.js b/src/api/song.js
index 2e4f8fe525b27330240ae059db6c327c5b3999a0..100cc9733c07392eb6fb1c5c08aa2080a25c3c1b 100644
--- a/src/api/song.js
+++ b/src/api/song.js
@@ -37,4 +37,17 @@ export const getSongsByEpisode = (episodeInfo) => {
         .then(res => {
             return res;
         });
-}
\ No newline at end of file
+}
+
+export const getRecommendedSongs = (params) => {
+    console.log("params" +  params.currentSongIds)
+    return axios.post(`${SONG_MODULE}/recommendations`, null,{
+        params: {
+            currentSongIds: params.currentSongIds.join(","),
+            limit: params.limit,
+        }
+    })
+        .then(res => {
+            return res;
+        });
+};
\ No newline at end of file
diff --git a/src/api/user.js b/src/api/user.js
index 56b48273fd04f8a0834cb7a1f97ae791fb64e935..fa4c3861e7982ca35d5880c7cfd88de3f5246f54 100644
--- a/src/api/user.js
+++ b/src/api/user.js
@@ -1,32 +1,66 @@
 import { axios } from '../utils/request';
 import { USER_MODULE } from './_prefix';
 
-
 /*
-    email: string
+    phone: string,
     password: string
  */
 export const userLogin = (loginInfo) => {
-    console.log(loginInfo)
-    return axios.post(`${USER_MODULE}/login`, loginInfo,
-        { headers: { 'Content-Type': 'application/json' } })
-        .then(res => {
-            return res;
-        });
+    return axios.post(`${USER_MODULE}/login`, null, {params: loginInfo})
+        .then((res) => {
+            return res
+        })
 }
 
 /*
-    user_name: string
-    email: string
-    password: string
+    name: string,
+    phone: string,
+    password: string,
+    captcha: string
  */
 export const userRegister = (registerInfo) => {
-    console.log(registerInfo)
-    return axios.post(`${USER_MODULE}/register`, registerInfo,
-        { headers: { 'Content-Type': 'application/json' } })
-        .then(res => {
-            return res;
-        });
+    return axios.post(`${USER_MODULE}/register?`, null, {params: registerInfo})
+        .then((res) => {
+            return res
+        })
+}
+
+/*
+    phone: string
+ */
+export const userSendCaptcha = (captchaInfo) => {
+    console.log(captchaInfo.phone)
+    return axios.post(`${USER_MODULE}/send`, null, {
+        params: {
+            phone: captchaInfo.phone
+        }
+    })
+        .then((res) => {
+            return res
+        })
+}
+
+/*
+    phone?: string,
+    password?: string,
+    captcha?: string,
+ */
+export const userReset = (resetInfo) => {
+    console.log(resetInfo)
+    return axios.post(`${USER_MODULE}/reset`, resetInfo, {headers: {'Content-Type': 'application/json'}})
+        .then((res) => {
+            return res
+        })
+}
+
+/*
+    phone:string
+ */
+export const getUserByPhone = (phone) => {
+    return axios.get(`${USER_MODULE}/getUserByPhone`, {params: phone})
+        .then((res) => {
+            return res
+        })
 }
 
 /*
diff --git a/src/assets/videos/3.mp4 b/src/assets/videos/3.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..3fb3ebe9f7f1e5b4e15272daa19f33e308e04f5b
Binary files /dev/null and b/src/assets/videos/3.mp4 differ
diff --git a/src/components/ArtistView.vue b/src/components/ArtistView.vue
index b2b786848d8c6cdc9fe61de18001283c7c390dff..df16920d597ae859ac2d8257b59203309b76fda2 100644
--- a/src/components/ArtistView.vue
+++ b/src/components/ArtistView.vue
@@ -10,9 +10,8 @@ import {addSongToPlaylist, removeSongFromPlaylist} from "../api/playlist";
 import {getSongsByPlaylist} from "../api/song";
 import {formatTime} from '../utils/formatTime';
 import {loadSongDurations} from '../utils/loadSongDurations';
-import {userFollowArtist} from "@/api/user";
 
-const emit = defineEmits(['playSong', 'pauseSong', 'back', 'updateSongs']);
+const emit = defineEmits(['playSong', 'pauseSong', 'back', 'updateSongs', 'toggleFollow']);
 const props = defineProps({
   artistName: {
     type: String,
@@ -24,6 +23,9 @@ const props = defineProps({
   currentSongId: {
     type: Number,
     required: true
+  },
+  isFollowed: {
+    type: Boolean
   }
 });
 
@@ -40,22 +42,12 @@ let musicClickedIndex = ref(null);
 let musicPlayIndex = ref(null);
 let musicPauseIndex = ref(null);
 
-// 娣诲姞鍏虫敞鐘舵€�
-const isFollowing = ref(false);
-
 // 鐢ㄦ埛绗竴娆℃挱鏀捐鑹轰汉姝屾洸鐨勬爣蹇�
 const isFirstPlay = ref(true);
 
 // 鍏虫敞/鍙栨秷鍏虫敞閫昏緫
 const toggleFollow = () => {
-  userFollowArtist({
-    user_id: currentUserId.value,
-    artist_id: artist.value.id,
-    isFollowed: isFollowing.value
-  }).catch(error => {
-    console.error("Failed to update artist follow status:", error);
-  })
-  isFollowing.value = !isFollowing.value;
+  emit('toggleFollow',artist.value.id,props.isFollowed);
 };
 
 // 娣诲姞鍠滄姝屾洸鐨勭姸鎬佺鐞�
@@ -155,12 +147,8 @@ const getRandomListeners = () => {
 
 const monthlyListeners = ref(getRandomListeners());
 
-const followedArtistIds = ref([]);
 
 onMounted(() => {
-  getUserById({userId: currentUserId.value}).then(res => {
-    followedArtistIds.value = res.data.result.followedArtistIds;
-  })
   // 鍒濆鍖栧枩娆㈢殑姝屾洸闆嗗悎
   initializeLikedSongs();
 
@@ -190,11 +178,6 @@ watch(() => props.artistName, async (newValue) => {
     const artistResponse = await getArtistInfo(newValue);
     artist.value = artistResponse.data.result;
     
-    if (!followedArtistIds.value.length) {
-      const userResponse = await getUserById({ userId: currentUserId.value });
-      followedArtistIds.value = userResponse.data.result.followedArtistIds;
-    }
-    isFollowing.value = followedArtistIds.value.includes(artist.value.id);
     updateBackground(artist.value.avatarUrl);
 
     const songPromises = artist.value.songIds.map(songId =>
@@ -372,9 +355,9 @@ const isCurrentSongInList = computed(() => {
         </div>
         <!-- 鏇挎崲鍘熸潵鐨別l-popover涓哄叧娉ㄦ寜閽� -->
         <button class="follow-button" 
-                :class="{ 'following': isFollowing }"
+                :class="{ 'following': props.isFollowed }"
                 @click="toggleFollow">
-          {{ isFollowing ? '宸插叧娉�' : '鍏虫敞' }}
+          {{ props.isFollowed ? '宸插叧娉�' : '鍏虫敞' }}
         </button>
       </div>
 
diff --git a/src/components/EpisodeView.vue b/src/components/EpisodeView.vue
index bf326f1f41f526b4812c3c533c1194c8d29b4c6d..6cc32220a8155a4e40053137bb4ef15e82f1a80f 100644
--- a/src/components/EpisodeView.vue
+++ b/src/components/EpisodeView.vue
@@ -292,7 +292,12 @@ const pauseMusic = (musicId) => {
 
 <template>
 	<div class="album-content" :style="{backgroundImage: gradientColor}" @mousewheel="handelScroll">
-		<div class="header">
+    <div class="back-button" data-tooltip="杩斿洖" @click="$emit('back')">
+      <svg height="16" width="16" viewBox="0 0 16 16" fill="currentColor">
+        <path d="M11.03.47a.75.75 0 0 1 0 1.06L4.56 8l6.47 6.47a.75.75 0 1 1-1.06 1.06L2.44 8 9.97.47a.75.75 0 0 1 1.06 0z"></path>
+      </svg>
+    </div>
+    <div class="header">
 			<img :src="episodeInfo.picPath" alt="" class="album-image" @load="updateBackground(episodeInfo.picPath)"/>
 			<div class="header-content">
 				<p style="text-align: left;margin:20px 0 0 15px">涓撹緫EP</p>
@@ -836,5 +841,40 @@ h1 {
   color: #fff;
   text-align: left;
 }
+.back-button {
+  z-index: 3;
+  position: relative;
+  margin: 24px 0 0 24px;
+  width: 32px;
+  height: 32px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  border-radius: 50%;
+  color: #fff;
+  transition: all 0.2s ease;
+
+  &:hover {
+    transform: scale(1.1);
+    background-color: rgba(0, 0, 0, .8);
+  }
+}
+
+.back-button[data-tooltip]:hover::after {
+  content: attr(data-tooltip);
+  position: absolute;
+  top: 38px;
+  left: 50%;
+  transform: translateX(-50%);
+  background-color: #282828;
+  color: white;
+  padding: 4px 8px;
+  border-radius: 4px;
+  font-size: 12px;
+  white-space: nowrap;
+  z-index: 1000;
+  pointer-events: none;
+}
 
 </style>
diff --git a/src/components/MusicAlbumView.vue b/src/components/MusicAlbumView.vue
index d6c53a6e084628032b6a5fa71d0d89555c8ff8a6..cb0d40df782be82d31cfc2f006e841076883be17 100644
--- a/src/components/MusicAlbumView.vue
+++ b/src/components/MusicAlbumView.vue
@@ -10,8 +10,7 @@ import pauseButton from "../icon/pauseButton.vue";
 import {addSongToPlaylist, modifyPlaylist, removePlaylist, removeSongFromPlaylist} from "../api/playlist";
 import {formatTime} from "@/utils/formatTime";
 import { loadSongDurations } from '../utils/loadSongDurations';
-import {getPlaylistById, getSongById} from "../api/resolve";
-import {getSongsByPlaylist} from "../api/song";
+import { getRecommendedSongs } from "../api/song";
 
 
 /*
@@ -48,9 +47,8 @@ const edit_title = ref("");
 const edit_description = ref("");
 const edit_cover_path = ref("");
 
-// let musicList = ref([])
-// 闅忔満姝屾洸
-const recMusicList = ref([])
+//鎺ㄨ崘姝屾洸
+const recMusicList = ref([]);
 
 let musicHoveredIndex = ref(null);
 let musicClickedIndex = ref(null);
@@ -64,7 +62,7 @@ const gradientColor = computed(() => `linear-gradient(to bottom, ${backgroundCol
 const songDurations = ref(new Map());
 watch(() => props.musicList, (newSongs) => {
   loadSongDurations(newSongs, songDurations);
-}, { immediate: true });
+}, { immediate: true ,deep: true});
 
 // 鏀剧缉鏃剁殑缁勪欢澶勭悊
 const handleResize = () => {
@@ -126,19 +124,6 @@ const debounce = (fn, delay) => {
 
 
 onMounted(() => {
-  let randomMusicIds =[];
-  for (let i = 0; i < 8; i++) {
-    let num = Math.floor(Math.random()*54+69);
-    if(randomMusicIds.indexOf(num) === -1)
-      randomMusicIds.push(num);
-    else i--;
-  }
-  randomMusicIds.forEach((id)=>{
-    getSongById({song_id:id}).then(res => {
-      recMusicList.value.push(res.data.result);
-    })
-  });
-
 	resizeObserver.value = new ResizeObserver(debounce(handleResize, 50));
 	console.log(resizeObserver.value)
 	nextTick(() => {
@@ -225,7 +210,7 @@ const removeAlbum = (albumId) => {
 const playFromId = (musicId) => {
 	if (musicId === null) {
 		// 浠庡ご寮€濮嬫挱鏀�
-		musicPlayIndex.value  = props.musicList[0].id;
+		musicPlayIndex  = props.musicList[0].id;
 	} else {
 		musicPlayIndex  = musicId;
 	}
@@ -234,6 +219,13 @@ const playFromId = (musicId) => {
 	musicPauseIndex = null;
 }
 
+const playRecommendedSongFromId = (musicId) => {
+  musicPlayIndex  = musicId;
+  const songToPlay = recMusicList.value.find(song => song.id === musicId);
+	emit('playRecommendedSong', songToPlay)
+  musicPauseIndex = null;
+}
+
 const addToFavorite = (musicId, albumId) => {
   addSongToPlaylist({
     user_id: currentUserId.value,
@@ -294,10 +286,6 @@ const quitEdit = () => {
 	const editDesc = document.querySelector(".edit-desc");
 	editDesc.style.visibility = "hidden";
 }
-// watch(()=>props.musicList,()=>{
-//   musicList.value = props.musicList
-// })
-
 const addRecommendMusic = (musicId) => {
 	console.log(musicId);
 	//TODO:娣诲姞姝屾洸鍒版寚瀹氱殑姝屽崟
@@ -346,6 +334,28 @@ const isCurrentSongInList = computed(() => {
   return props.musicList.some(song => song.id === musicPlayIndex);
 });
 
+// 娣诲姞鑾峰彇鎺ㄨ崘姝屾洸鐨勬柟娉�
+const getRecommendations = async () => {
+  try {
+    const currentSongIds = props.musicList.map(song => song.id);
+
+    const response = await getRecommendedSongs({
+      currentSongIds: currentSongIds,
+      limit: 3
+    });
+
+    recMusicList.value = response.data.result;
+  } catch (error) {
+    console.error("Failed to fetch recommendations:", error);
+  }
+};
+
+watch(() => props.musicList, () => {
+  if (props.musicList.length > 0) {
+    getRecommendations();
+  }
+}, { immediate: true });
+
 </script>
 
 <template>
@@ -639,7 +649,7 @@ const isCurrentSongInList = computed(() => {
 					     @mouseenter="()=>{musicHoveredIndex = music.id;}"
 					     @mouseleave="()=>{musicHoveredIndex = null}"
 					     @click="musicClickedIndex=music.id"
-					     @dblclick="playFromId(music.id)"
+					     @dblclick="playRecommendedSongFromId(music.id)"
 					     :style="{backgroundColor: musicClickedIndex===music.id? '#404040':
 				     musicHoveredIndex === music.id ? 'rgba(54,54,54,0.7)' :'rgba(0,0,0,0)',
 				   }">
@@ -651,14 +661,14 @@ const isCurrentSongInList = computed(() => {
 								recMusicList.indexOf(music) + 1
 							}}
 						</div>
-						<play-button @click="playFromId(music.id)" style="position: absolute;left: 14px;cursor: pointer"
+						<play-button @click="playRecommendedSongFromId(music.id)" style="position: absolute;left: 14px;cursor: pointer"
 						             v-if="(musicHoveredIndex === music.id&&musicPlayIndex!==music.id)||musicPauseIndex===music.id"
 						             :style="{color: musicPauseIndex===music.id ? '#1ed660' : 'white'}"/>
 						<pause-button @click="pauseMusic(music.id)"
-						              style="color:#1ed660 ;position: absolute;left: 14px;cursor: pointer"
+						              style="color:#1ed660 ;position: absolute;left: 17px;cursor: pointer"
 						              v-if="musicPlayIndex===music.id&&musicHoveredIndex === music.id&&musicPauseIndex!==music.id"/>
 						<img width="17" height="17" alt=""
-						     style="position: absolute;left: 20px;"
+						     style="position: absolute;left: 24px;"
 						     v-if="musicPlayIndex===music.id&&musicHoveredIndex !== music.id&&musicPauseIndex!==music.id"
 						     src="https://open.spotifycdn.com/cdn/images/equaliser-animated-green.f5eb96f2.gif">
 
@@ -679,6 +689,7 @@ const isCurrentSongInList = computed(() => {
 						</div>
 
 						<div class="music-album-info"
+                 @click="emit('openEpisodeView',music.album)"
 						     :style="{color:musicHoveredIndex === music.id? 'white' : '#b2b2b2'}">
 							{{ music.album }}
 						</div>
diff --git a/src/components/NotificationToast.vue b/src/components/NotificationToast.vue
new file mode 100644
index 0000000000000000000000000000000000000000..806a1cd94ca6b96c7611c06e1e1f30ec74a952f8
--- /dev/null
+++ b/src/components/NotificationToast.vue
@@ -0,0 +1,135 @@
+<template>
+  <Transition name="toast">
+    <div v-if="show" 
+         class="toast-container"
+         :class="type">
+      <div class="toast-content">
+        <div class="toast-message">{{ message }}</div>
+      </div>
+    </div>
+  </Transition>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from 'vue';
+
+const props = defineProps({
+  message: {
+    type: String,
+    required: true
+  },
+  type: {
+    type: String,
+    default: 'info'
+  },
+  duration: {
+    type: Number,
+    default: 3000
+  }
+});
+
+const show = ref(false);
+let timer = null;
+
+onMounted(() => {
+  show.value = true;
+  if (props.duration > 0) {
+    timer = setTimeout(() => {
+      show.value = false;
+    }, props.duration);
+  }
+});
+
+onUnmounted(() => {
+  if (timer) clearTimeout(timer);
+});
+</script>
+
+<style scoped>
+.toast-container {
+  position: fixed;
+  top: 8%;
+  left: 50%;
+  transform: translateX(-50%);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 16px 24px;
+  color: white;
+  z-index: 9999;
+  width: 350px;
+  border-radius: 8px;
+  backdrop-filter: blur(8px);
+}
+
+.toast-icon {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  margin-right: 12px;
+  width: 24px;
+}
+
+.error-icon, .success-icon {
+  font-size: 20px;
+  font-weight: bold;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.success {
+  background: rgba(76, 175, 80, 0.95);
+}
+
+.error {
+  background: rgb(227, 30, 35);
+}
+
+.info {
+  background: rgba(33, 150, 243, 0.95);
+}
+
+.toast-content {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.toast-message {
+  font-size: 14px;
+  line-height: 1.4;
+  font-weight: 500;
+  text-align: center;
+  margin: 0 auto;
+}
+
+.toast-enter-active,
+.toast-leave-active {
+  transition: all 0.3s ease;
+}
+
+.toast-enter-from {
+  opacity: 0;
+  transform: translate(-50%, -20px);
+}
+
+.toast-leave-to {
+  opacity: 0;
+  transform: translate(-50%, -20px);
+}
+
+.success .toast-message {
+  color: #E8F5E9;
+}
+
+.error .toast-message {
+  color: #ffffff;
+}
+
+.toast-container {
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
+}
+</style> 
\ No newline at end of file
diff --git a/src/components/NowPlayingView.vue b/src/components/NowPlayingView.vue
index 3738ef8ee95062bdb3aa44ebeef1ed7d2d9fb791..26241fee71c9f0a5d145cdf1353bb6d3fe19766e 100644
--- a/src/components/NowPlayingView.vue
+++ b/src/components/NowPlayingView.vue
@@ -1,36 +1,36 @@
 <script setup>
-import {defineProps, defineEmits, ref, computed, watch} from 'vue';
+import {defineProps, defineEmits, ref, computed, watch, onMounted} from 'vue';
 import {getArtistInfo} from "@/api/artist";
 
 const props = defineProps({
   isVisible: Boolean,
   currentSong: Object,
   nextSong: Object,
+  followedArtistIds:Array
 });
 
-const isFollowing = ref(false);
+const userToken = ref(JSON.parse(sessionStorage.getItem('user-token')));
+const currentUserId = ref(userToken.value.id);
+
+const artistsInfo = ref([]);
 
 const artists = computed(() => {
   if (!props.currentSong?.artist) return [];
   return props.currentSong.artist.split('/').map(name => name.trim());
 });
 
-const artistImage = ref([]);
 
 const setArtistInfo = async () => {
-  artistImage.value = [];
-  
-  console.log('Artists:', artists.value)
+  artistsInfo.value = [];
+
   for (const artist of artists.value) {
     try {
       const artistInfo = await getArtistInfo(artist);
-      artistImage.value.push(artistInfo.data.result.avatarUrl);
+      artistsInfo.value.push(artistInfo.data.result);
     } catch (error) {
       console.error('Failed to fetch artist info:', error);
     }
   }
-  
-  console.log('Artist Images:', artistImage.value)
 };
 
 watch(artists, () => {
@@ -39,16 +39,12 @@ watch(artists, () => {
   }
 }, { immediate: true });
 
-const toggleFollow = () => {
-  isFollowing.value = !isFollowing.value;
-  // TODO: 璋冪敤鍚庣API瀹炵幇鍏虫敞/鍙栨秷鍏虫敞
-  // followArtist({
-  //   artistId: artist.value.id,
-  //   isFollow: isFollowing.value
-  // });
+const toggleFollow = async (index) => {
+  const artist = artistsInfo.value[index];
+  emit('toggleFollow',artist.id,props.followedArtistIds.includes(artistsInfo.value[index].id));
 };
 
-const emit = defineEmits(['playNext', 'toggleQueue', 'enterAuthorDescription']);
+const emit = defineEmits(['playNext', 'toggleQueue', 'enterAuthorDescription', 'toggleFollow']);
 
 const playNext = () => {
   emit('playNext');
@@ -61,6 +57,7 @@ const toggleQueue = () => {
 const enterAuthorDescription = (artistName) => {
   emit('enterAuthorDescription', artistName);
 }
+
 </script>
 
 <template>
@@ -81,16 +78,16 @@ const enterAuthorDescription = (artistName) => {
         <div v-for="(artist, index) in artists"
              :key="artist" 
              class="artist-info">
-          <img :src="artistImage[index]"
+          <img :src="artistsInfo[index]?.avatarUrl"
                class="artist-image" 
                alt="鑹烘湳瀹�"
                @click="enterAuthorDescription(artist)"/>
           <div class="artist-details">
             <h4>{{ artist }}</h4>
             <button class="follow-button"
-                    :class="{ 'following': isFollowing }"
-                    @click="toggleFollow">
-              {{ isFollowing ? '宸插叧娉�' : '鍏虫敞' }}
+                    :class="{ 'following': props.followedArtistIds.includes(artistsInfo[index]?.id) }"
+                    @click="toggleFollow(index)">
+              {{ props.followedArtistIds.includes(artistsInfo[index]?.id) ? '宸插叧娉�' : '鍏虫敞' }}
             </button>
           </div>
         </div>
diff --git a/src/components/SearchView.vue b/src/components/SearchView.vue
index 5bb929648535659fa6e6720a1afb67815791dea4..cc51928487d7c52523f7922c10f61ead995685fd 100644
--- a/src/components/SearchView.vue
+++ b/src/components/SearchView.vue
@@ -1,19 +1,108 @@
 <script setup>
-import {ref} from "vue";
+import {nextTick, onMounted, onUnmounted, ref, watch} from "vue";
 import Empty from "./Empty.vue";
+import {formatTime} from "@/utils/formatTime";
+import {ElMessage, ElPopover} from "element-plus";
+import {loadSongDurations} from "@/utils/loadSongDurations";
+import {addSongToPlaylist} from "@/api/playlist";
+import playButton from "../icon/playButton.vue";
+import checkMark from "../icon/checkMark.vue";
+import pauseButton from "../icon/pauseButton.vue";
 
-const emit = defineEmits(['back']);
-
-const {songResult, playlistResult} = defineProps({
-	songResult: Array,
-	playlistResult: Array
-})
-
+const emit = defineEmits(['pauseSong', 'switchSong', 'back', 'switchToArtist']);
+const props = defineProps({
+  songResult: {
+    type: Array,
+    required: true,
+  },
+  playlistResult: {
+    type: Array,
+    required: true,
+  },
+  playList: { //鎸囧綋鍓嶆敹钘忕殑姝屽崟鍒楄〃
+    type: Array,
+    required: true,
+  },
+  currentSongId: {
+    type: Number,
+    // required: true
+  },
+  isPaused: {
+    type: Boolean,
+  }
+});
 const currentTab = ref('songs')
 
 const handleTabClick = (tab) => {
-	currentTab.value = tab
+  currentTab.value = tab
+}
+const songDurations = ref(new Map());
+watch(() => props.musicList, (newSongs) => {
+  loadSongDurations(newSongs, songDurations);
+}, { immediate: true });
+
+let musicHoveredIndex = ref(null);
+let musicClickedIndex = ref(null);
+let musicPlayIndex = ref(null);
+let musicPauseIndex = ref(null);
+
+const playFromId = (musicId) => {
+  if (musicId === null || musicId === undefined) {
+    // 浠庡ご寮€濮嬫挱鏀�
+    musicPlayIndex  = props.currentSongId;
+  } else {
+    musicPlayIndex  = musicId;
+  }
+  emit('switchSong', musicPlayIndex, true);
+  musicPauseIndex = null;
+}
+
+const pauseMusic = (musicId) => {
+  musicPauseIndex = musicId;
+  emit('pauseSong');
+}
+
+const enterArtistDescription = (artistName) => {
+  emit('switchToArtist', artistName);
+}
+const addToFavorite = (musicId, albumId) => {
+  addSongToPlaylist({
+    user_id: currentUserId.value,
+    playlist_id: albumId,
+    song_id: musicId,
+  }).then(() => {
+    ElMessage({
+      message: "娣诲姞鑷�: " + props.albumInfo.title,
+      grouping: true,
+      type: 'info',
+      offset: 16,
+      customClass: "reco-message",
+      duration: 4000,
+    })
+  })
 }
+
+const popovers = ref([])
+const getPopoverIndex = (popover) => {
+  if (popover) {
+    popovers.value.push(popover);
+  }
+}
+const closePopover = (e) => {
+  popovers.value.forEach((item) => {
+    item.hide();
+  })
+}
+
+onMounted(() => {
+  musicPlayIndex = props.currentSongId;
+  musicClickedIndex = props.currentSongId;
+  musicPauseIndex = props.isPaused ? props.currentSongId : null;
+})
+
+onUnmounted(() => {
+  popovers.value = null;
+})
 </script>
 
 <template>
@@ -37,20 +126,120 @@ const handleTabClick = (tab) => {
 			>姝屽崟</button>
 		</div>
 		<div class="search-results">
-			<ul v-if="currentTab === 'songs'">
-				<li v-for="(song, index) in songResult" :key="song.id">
-					<div class="song-item">
-						<span class="song-index">{{ index + 1 }}</span>
-						<img :src="song.picPath" class="song-pic pic" alt=""/>
-						<div class="song-info info">
-							<h3 class="song-title">{{ song.title }}</h3>
-							<p class="song-artist">{{ song.artist }}</p>
-							<p class="song-album">{{ song.album }}</p>
-						</div>
-					</div>
-				</li>
-			
-			</ul>
+			<div v-if="currentTab === 'songs'">
+        <div class="tips">
+          <p style="position:absolute; left:25px">#</p>
+          <p style="position:absolute; left:140px">鏍囬</p>
+          <p style="margin-left: auto; margin-right:30px">鏀惰棌</p>
+        </div>
+        <div class="musicList">
+          <div class="music-item"
+               v-for="music in songResult"
+               :key="music.id"
+               :aria-selected="musicClickedIndex === music.id ? 'True':'False'"
+               @mouseenter="()=>{musicHoveredIndex = music.id;}"
+               @mouseleave="()=>{musicHoveredIndex = -1}"
+               @click="musicClickedIndex=music.id"
+               @dblclick="playFromId(music.id)"
+               :style="{backgroundColor: musicClickedIndex===music.id? '#404040':
+				     musicHoveredIndex === music.id ? 'rgba(54,54,54,0.7)' :'rgba(0,0,0,0)',
+				   }"> <!--@click浜嬩欢鍐欏湪script涓殑鍑芥暟閲� 鏃犳硶鍙婃椂瑙﹀彂:style涓殑鏍峰紡!!!-->
+
+            <div
+                :style="{visibility: musicHoveredIndex === music.id||musicPlayIndex === music.id ? 'hidden' : 'visible' }">
+              {{
+                songResult.indexOf(music) + 1
+              }}
+            </div>
+            <play-button @click="playFromId(music.id)" style="position: absolute;left: 14px;cursor: pointer"
+                         v-if="(musicHoveredIndex === music.id&&musicPlayIndex!==music.id)||musicPauseIndex===music.id"
+                         :style="{color: musicPauseIndex===music.id ? '#1ed660' : 'white'}"/>
+
+            <pause-button @click="pauseMusic(music.id)"
+                          style="color:#1ed660 ;position: absolute;left: 17px;cursor: pointer"
+                          v-if="musicPlayIndex===music.id&&musicHoveredIndex === music.id&&musicPauseIndex!==music.id"/>
+            <img width="17" height="17" alt=""
+                 style="position: absolute;left: 24px;"
+                 v-if="musicPlayIndex===music.id&&musicHoveredIndex !== music.id&&musicPauseIndex!==music.id"
+                 src="https://open.spotifycdn.com/cdn/images/equaliser-animated-green.f5eb96f2.gif">
+
+            <div class="music-detailed-info">
+              <img class="music-image"
+                   :src="music.picPath"
+                   alt="姝屾洸鍥剧墖"/>
+              <div class="music-name-author" style="padding-left: 5px;">
+                <p class="music-name"
+                   :style="{color : musicPlayIndex ===music.id? '#1ED660':''}"
+                   :class="[musicPlayIndex === music.id ? 'music-after-click' : '']"
+                >{{ music.title }} </p>
+                <p class="music-author" @click="enterArtistDescription(music.artist)"
+                   :style="{color:musicHoveredIndex === music.id? 'white' : '#b2b2b2'}">
+                  {{ music.artist }}</p>
+              </div>
+            </div>
+            <div class="music-right-info">
+              <el-popover
+                  :ref="getPopoverIndex"
+                  class="music-dropdown-options"
+                  popper-class="my-popover"
+                  :width="400"
+                  trigger="click"
+                  :hide-after=0
+
+              >
+                <template #reference>
+                  <check-mark class="check-mark" v-tippy="'鍔犲叆姝屽崟'"
+                              :style="{visibility: musicHoveredIndex === music.id ? 'visible' : 'hidden'}"/>
+                </template>
+
+                <ul @click="closePopover" style="overflow: scroll;max-height: 400px;">
+                  <div style="padding: 6px 0 6px 10px;font-weight: bold;color:darkgrey;font-size:16px">
+                    閫夋嫨姝屽崟鏀惰棌
+                  </div>
+                  <hr style="    border: 0;padding-top: 1px;background: linear-gradient(to right, transparent, #98989b, transparent);">
+
+                  <li class="album-to-add" @click="addToFavorite(music.id,album.id)"
+                      v-for="album in playList">
+                    <div style="
+										height:40px;
+										display: flex;
+										align-items: center;
+										justify-content: space-between;
+										font-size: 20px;
+										font-weight:400"
+                    >
+                      <div style="display: flex; flex-direction: row">
+                        <img :src="album.picPath" style="height: 40px; width:40px; border-radius: 4px" alt=""/>
+                        <div style="
+												margin-left: 10px;
+												font-size: 18px;
+											">{{ album.title }}</div>
+                      </div>
+                      <div style="font-size: 14px; color: #a4a4a4">{{ album.songNum }}棣�</div>
+                    </div>
+
+                  </li>
+                </ul>
+              </el-popover>
+              <div style="margin-left: auto;margin-right: 15px; color: #b2b2b2"
+                   :style="{color:musicHoveredIndex === music.id? 'white' : '#b2b2b2'}"
+                   v-show="songDurations.get(music.id) !== undefined">
+                {{ formatTime(songDurations.get(music.id)) }}
+              </div>
+              <el-popover
+                  :ref="getPopoverIndex"
+                  class="music-dropdown-options"
+                  popper-class="my-popover"
+                  :width="400"
+                  trigger="click"
+                  :hide-after=0
+              >
+
+              </el-popover>
+            </div>
+          </div>
+        </div>
+			</div>
 			<ul v-if="currentTab === 'playlists'">
 				<li v-for="(playlist, index) in playlistResult" :key="playlist.id">
 					<div class="playlist-item">
@@ -74,6 +263,7 @@ const handleTabClick = (tab) => {
 <style scoped>
 .search-view {
 	padding: 0;
+  width: 100%;
 }
 
 .back-button {
@@ -144,6 +334,119 @@ const handleTabClick = (tab) => {
 .search-results {
 	list-style-type: none;
 	padding: 0;
+  width: 100%;
+}
+
+.tips {
+  z-index: 0;
+  display: flex;
+  position: relative;
+  padding: 5px 8px 5px 8px;
+  width: 100%;
+  box-sizing: border-box;
+  user-select: none;
+  color: #fff;
+}
+
+.musicList {
+  border-top: 1px solid #363636;
+  margin-top: 10px;
+}
+
+/*姣忚闊充箰鐨勬牱寮�*/
+.music-item {
+  position: relative;
+  border-radius: 10px;
+  display: flex;
+  align-items: center;
+  padding: 10px 0 10px 25px;
+  flex-grow: 1;
+  min-width: 0;
+  color: #fff;
+}
+
+/*宸︿晶淇℃伅*/
+.music-detailed-info {
+  display: flex;
+  flex-direction: row;
+}
+
+.music-image {
+  display: flex;
+  align-items: center;
+  padding-left: 30px;
+  height: 50px;
+  width: 50px; /* Adjust as needed */
+  border-radius: 10px;
+}
+
+.music-name {
+  padding-bottom: 5px;
+  font-size: 18px
+}
+
+.music-name:hover {
+  cursor: pointer;
+  text-decoration: underline;
+}
+
+.music-author {
+  color: #b2b2b2;
+  font-size: 15px
+}
+
+.music-author:hover {
+  cursor: pointer;
+  text-decoration: underline;
+}
+
+/*鍙充晶淇℃伅*/
+.music-right-info {
+  margin-left: auto;
+  display: flex;
+  align-items: center;
+  flex-direction: row;
+  color:white;
+}
+
+.check-mark {
+  width: 20px;
+  height: auto;
+  margin-right: 40px;
+  color: white;
+  font-weight: bolder;
+  border-radius: 50%;
+}
+
+.check-mark:hover {
+  cursor: pointer;
+}
+
+.check-mark:focus {
+  outline: none;
+}
+
+.album-to-add {
+  padding: 8px;
+}
+
+.music-more-info {
+  margin-right: 14px;
+  font-size: 22px;
+  transition: width 0.1s ease-in-out;
+}
+
+.music-more-info:focus {
+  outline: none;
+  transform: scale(1.05);
+}
+
+.music-more-info:hover {
+  cursor: pointer;
+}
+
+.music-dropdown-options {
+  border-radius: 6px;
 }
 
 .info h3 {
diff --git a/src/router/index.js b/src/router/index.js
index 5a74422b6ae1afa256e79a35e76170b75a01c38a..3bf55af34e83c3124058c375e32a710bd46a766d 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -49,4 +49,23 @@ const router = createRouter({
     ]
 })
 
+router.beforeEach((to, _, next) => {
+    const token = sessionStorage.getItem('token');
+    console.log(token)
+
+    if (to.meta.title) {
+        document.title = to.meta.title
+    }
+
+    if ( token == null) {
+        if(to.path !== '/login'){
+            next('/login')
+        }else {
+            next()
+        }
+    }else {
+        next()
+    }
+})
+
 export {router}
diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue
index edc8adba19073863e5eeeaf55c2f310ffd217257..7fdcdd88c0fff5b6b35821a61d1ca3d3006be4c5 100644
--- a/src/views/HomePage.vue
+++ b/src/views/HomePage.vue
@@ -1,7 +1,7 @@
 /* eslint-disable */
 <script setup>
 // Vue Basics
-import {computed, onMounted, ref, watch} from "vue"
+import {computed, onMounted, ref, watch, onUnmounted} from "vue"
 
 // Assets
 import defaultBg from '../assets/pictures/Eason.png'
@@ -27,7 +27,8 @@ import {useTheme} from "../store/theme";
 import {parseLrc} from "../utils/parseLyrics"
 import {updateBackground} from "../utils/getBackgroundColor";
 import { formatTime } from '../utils/formatTime';
-import {getPlaylistById} from "../api/resolve";
+import {getArtistById, getPlaylistById, getUserById} from "../api/resolve";
+import {userFollowArtist} from "@/api/user";
 
 
 /*
@@ -421,8 +422,9 @@ const switchToPlaylist = (playlist, songId) => {
 	getSongsByPlaylist({
 		playlist_id: currentPlaylistId.value,
 	}).then((res) => {
-		songs.value = res.data.result;
-		displayingSongs.value = res.data.result;
+    const songsList = res.data.result;
+    songs.value = [...songsList];
+    displayingSongs.value = [...songsList];
 		currentSongId.value = songId;
 		for (let i = 0; i < songs.value.length; i++) {
 			if (songs.value[i].id === songId) {
@@ -439,6 +441,30 @@ const switchToPlaylist = (playlist, songId) => {
 	});
 }
 
+const handleRecommendedSong = (songToPlay) => {
+  const songExists = songs.value.some(song => song.id === songToPlay.id);
+  if (songExists) {
+    const songIndex = songs.value.findIndex(song => song.id === songToPlay.id);
+    songs.value.splice(songIndex, 1)
+  }
+  songs.value.unshift(songToPlay);
+  currentSongIndex.value = 0;
+  currentSongId.value = songToPlay.id;
+  if (song) {
+    controlIcons.forEach(controlIcon => {
+      controlIcon.src = PLAY;
+    });
+    song.src = songToPlay.filePath;
+    parseLrc(songToPlay.lyricsPath).then(res => {
+      lyrics.value = res;
+    });
+    song.load();
+    song.play();
+    theme.change(songToPlay.picPath);
+    isPaused.value = false;
+  }
+};
+
 
 /*
     PLAYLISTS
@@ -534,31 +560,59 @@ function receiveDataFromHome() {
  */
 const midComponents = ref(0);
 const currentArtist = ref(null);
-const backStack = ref([]);
+const navigationHistory = ref([]);
+
+const setMidComponents = (index, props = null) => {
+  console.log("from" + midComponents.value + " to " + index)
+  navigationHistory.value.push({
+    index: midComponents.value,
+    props: {
+      artistName: currentArtist?.value,
+      albumInfo: displayingPlaylist?.value,
+      musicList: displayingSongs?.value,
+      playList: playlists?.value,
+      songResult: songResult?.value,
+      playlistResult: playlistResult?.value,
+      episodeInfo: displayingEpisode?.value,
+      playFromLeftBar: playFromLeftBarAlbum?.value,
+      playlistInfo: currentPlaylist?.value,
+    }
+  });
 
-const setMidComponents = (val, prop = null, isBack = false) => {
-  console.log("from" + midComponents.value + " to " + val)
-  if (val !== midComponents.value && !isBack) {
-    backStack.value.push(midComponents.value);
-  }
-  
-  midComponents.value = val;
-
-  
-  if (val === 5) {
-    currentArtist.value = prop;
-  } else if (val === 6) {
-    displayingMusicId.value = prop;
+  midComponents.value = index;
+
+  switch(index) {
+    case 5: // ArtistView
+      if (props) {
+        currentArtist.value = props;
+      }
+      break;
+    case 6:
+      if (props) {
+        displayingMusicId.value = props;
+      }
+      break;
   }
 };
 
 const goBack = () => {
-	if (backStack.value.length > 0) {
-		const lastIndex = backStack.value.pop();
-		setMidComponents(lastIndex, currentArtist.value, true);
-	} else {
-		setMidComponents(0, null);
-	}
+  if (navigationHistory.value.length > 0) {
+    const previousState = navigationHistory.value.pop();
+    midComponents.value = previousState.index;
+    if (previousState.props) {
+      currentArtist.value = previousState.props.artistName;
+      displayingPlaylist.value = previousState.props.albumInfo;
+      displayingSongs.value = previousState.props.musicList;
+      playlists.value = previousState.props.playList;
+      songResult.value = previousState.props.songResult;
+      playlistResult.value = previousState.props.playlistResult;
+      displayingEpisode.value = previousState.props.episodeInfo;
+      playFromLeftBarAlbum.value = previousState.props.playFromLeftBar;
+      currentPlaylist.value = previousState.props.playlistInfo;
+    }
+  } else {
+    midComponents.value = 0;
+  }
 };
 
 /*
@@ -597,7 +651,39 @@ const playNextSong = () => {
 	switchSongs(1);
 };
 
+/*
+    followInfo
+ */
+const followedArtistInfo = ref([]);
+const toggleFollow = async (artistId, isFollowed) => {
+  try {
+    await userFollowArtist({
+      user_id: currentUserId.value,
+      artist_id: artistId,
+      isFollowed: isFollowed
+    });
+
+    if (!isFollowed) {
+      const artistResponse = await getArtistById(artistId);
+      followedArtistInfo.value.push(artistResponse.data.result);
+    } else {
+      const artistIndex = followedArtistInfo.value.findIndex(artist => artist.id === artistId);
+      if (artistIndex > -1) {
+        followedArtistInfo.value.splice(artistIndex, 1);
+      }
+    }
+  } catch (error) {
+    console.error("Failed to update artist follow status:", error);
+  }
+};
+
 onMounted(() => {
+  getUserById({ userId: currentUserId.value }).then(async res => {
+    const artistPromises = res.data.result.followedArtistIds.map(id =>
+      getArtistById(id).then(res => res.data.result)
+    );
+    followedArtistInfo.value = await Promise.all(artistPromises);
+  });
 	/*
         DOMS & EVENTS
 	 */
@@ -686,7 +772,6 @@ const updateSongs = (newSongs) => {
 	songs.value = newSongs;
 	displayingSongs.value = newSongs;
 };
-
 </script>
 
 <template>
@@ -717,6 +802,7 @@ const updateSongs = (newSongs) => {
                           :playFromLeftBar="playFromLeftBarAlbum"
                           :is-paused="isPaused"
                           @switchSongs="switchToPlaylist"
+                          @playRecommendedSong="handleRecommendedSong"
                           @switchToArtist="(name) => setMidComponents(5, name)"
                           @pauseSong="pauseCurrentSong"
                           @back="goBack"
@@ -731,7 +817,14 @@ const updateSongs = (newSongs) => {
 				</el-container>
 				<el-container v-if="midComponents === 3" class="playlist-container"
 				              style="overflow: auto; height: 730px ;border-radius: 12px">
-					<SearchView :songResult="songResult" :playlistResult="playlistResult"
+					<SearchView :songResult="songResult"
+                      :playlistResult="playlistResult"
+                      :play-list="playlists"
+                      :current-song-id="currentSongId"
+                      :is-paused="isPaused"
+                      @switchSong="switchToSong"
+                      @pauseSong="pauseCurrentSong"
+                      @switchToArtist="(name) => setMidComponents(5, name)"
                       @back="goBack"/>
 				</el-container>
 				<div v-if="midComponents === 4" class="playlist-container"
@@ -754,10 +847,12 @@ const updateSongs = (newSongs) => {
           <ArtistView :artist-name="currentArtist"
                       :is-paused="isPaused"
                       :current-song-id="currentSongId"
+                      :is-followed="followedArtistInfo.some(artist => artist.name === currentArtist)"
                       @playSong="playArtistSong"
                       @pauseSong="pauseCurrentSong"
                       @back="goBack"
-                      @updateSongs="updateSongs"/>
+                      @updateSongs="updateSongs"
+                      @toggleFollow="toggleFollow"/>
 				</div>
 			</div>
 			<div v-if="showRightContent" class="right-content">
@@ -821,9 +916,11 @@ const updateSongs = (newSongs) => {
 					:is-visible="showNowPlaying"
 					:current-song="songs[currentSongIndex]"
 					:next-song="getNextSong()"
+          :followed-artist-ids="followedArtistInfo.map(artist => artist.id)"
 					@play-next="playNextSong"
 					@toggle-queue="toggleQueue"
 					@enter-author-description="(name) => setMidComponents(5, name)"
+          @toggleFollow="toggleFollow"
 				/>
 			</div>
 		</div>
diff --git a/src/views/LoginPage.vue b/src/views/LoginPage.vue
index f2d54a9f08a3c1387fbc403917c51af799c02367..b85882d2f84fc85b1ebbb7d695b04ce404dfd4a2 100644
--- a/src/views/LoginPage.vue
+++ b/src/views/LoginPage.vue
@@ -1,154 +1,407 @@
 <script setup>
-import {onMounted, ref} from "vue";
-import {userInfo, userLogin, userRegister} from "../api/user.js";
+import {computed, onMounted, ref, onUnmounted} from "vue";
+import {userInfo, userLogin, userRegister, userReset, userSendCaptcha} from "../api/user.js";
 import {useTheme} from "../store/theme";
 import {router} from "../router";
+import {ElMessage} from "element-plus";
+import {md5} from "js-md5";
+import NotificationToast from '../components/NotificationToast.vue';
 
 const theme = useTheme()
 
-const login_email = ref("cossky@outlook.com")
-const login_password = ref("1145141919810")
-const login_prompt = ref("")
+const loginPhone = ref('');
+const registerPhone = ref('');
+const resetPasswordPhone = ref('');
+const loginPassword = ref('');
+const registerPassword = ref('');
+const registerPasswordConfirm = ref('');
+const resetPassword = ref('');
+const resetPasswordConfirm = ref('');//鍐嶆杈撳叆瀵嗙爜
+const registerCaptcha = ref('');
+const resetPasswordCaptcha = ref('');
+const name = ref('');
+const reset = ref(false);
+const sendingCaptcha = ref(false);
 
-const register_name = ref("CosSky")
-const register_email = ref("cossky@outlook.com")
-const register_password = ref("1145141919810")
-const register_prompt = ref("")
+// 鐢佃瘽鍙风爜鐨勮鍒�
+const chinaMobileRegex = /^(?:(?:\+|00)86)?1(?:3\d|4[5-79]|5[0-35-9]|6[5-7]|7[0-8]|8\d|9[01256789])\d{8}$/
+
+const toasts = ref([]);
+let toastId = 0;
+
+const showToast = (message, type = 'info') => {
+  const id = toastId++;
+  toasts.value.push({
+    id,
+    message,
+    type
+  });
+  
+  setTimeout(() => {
+    toasts.value = toasts.value.filter(toast => toast.id !== id);
+  }, 3000);
+};
+
+// 淇敼琛ㄥ崟楠岃瘉鍜屾彁绀�
+const validatePhone = (phone) => {
+  if (!phone) {
+    showToast('璇疯緭鍏ユ墜鏈哄彿鐮�', 'error');
+    return false;
+  }
+  if (!chinaMobileRegex.test(phone)) {
+    showToast('璇疯緭鍏ユ纭殑鎵嬫満鍙风爜鏍煎紡', 'error');
+    return false;
+  }
+  return true;
+};
+
+onMounted(() => {
+  theme.reset();
+
+  let switchCtn = document.querySelector("#switch-cnt");
+  let switchC1 = document.querySelector("#switch-c1");
+  let switchC2 = document.querySelector("#switch-c2");
+  let switchCircle = document.querySelectorAll(".switch_circle");
+  let switchBtn = document.querySelectorAll(".switch-btn");
+  let aContainer = document.querySelector("#a-container");
+  let bContainer = document.querySelector("#b-container");
+  let allButtons = document.querySelectorAll(".submit");
+
+  const initializeLoginForm = () => {
+    // 璁剧疆鍒濆鐘舵€佷负鐧诲綍琛ㄥ崟
+    switchCtn.classList.add("is-txr");
+    switchCircle[0].classList.add("is-txr");
+    switchCircle[1].classList.add("is-txr");
+
+    switchC1.classList.add("is-hidden");
+    switchC2.classList.remove("is-hidden");
+    aContainer.classList.add("is-txl");
+    bContainer.classList.add("is-txl");
+    bContainer.classList.add("is-z");
+  }
+
+  let getButtons = (e) => e.preventDefault()
+  let changeForm = () => {
+    // 淇敼绫诲悕
+    switchCtn.classList.add("is-gx");
+    setTimeout(function () {
+      switchCtn.classList.remove("is-gx");
+    }, 1500)
+    switchCtn.classList.toggle("is-txr");
+    switchCircle[0].classList.toggle("is-txr");
+    switchCircle[1].classList.toggle("is-txr");
+
+    switchC1.classList.toggle("is-hidden");
+    switchC2.classList.toggle("is-hidden");
+    aContainer.classList.toggle("is-txl");
+    bContainer.classList.toggle("is-txl");
+    bContainer.classList.toggle("is-z");
+  }
+
+  // 鐐瑰嚮鍒囨崲
+  const setupEventListeners = () => {
+    allButtons.forEach(button => {
+      button.addEventListener("click", getButtons);
+    });
+    switchBtn.forEach(btn => {
+      btn.addEventListener("click", changeForm);
+    });
+  }
+
+  initializeLoginForm();
+  setupEventListeners();
+
+  onUnmounted(() => {
+    allButtons.forEach(button => {
+      button.removeEventListener("click", getButtons);
+    });
+    switchBtn.forEach(btn => {
+      btn.removeEventListener("click", changeForm);
+    });
+  });
+})
 
 function handleLogin() {
-	userLogin({
-		email: login_email.value,
-		password: login_password.value,
-	}).then(res => {
-		if (res.data.code === '000' || res.data.code === '200') {
-			sessionStorage.setItem('token', res.data.result)
-            userInfo().then(res => {
-                sessionStorage.setItem('user-token', JSON.stringify(res.data.result))
-	            console.log("Storing session: ", res.data.result);
-	            router.push({path: "/home"})
-	            // document.documentElement.requestFullscreen();
-            })
-		} else if (res.data.code === '400') {
+  if (!validatePhone(loginPhone.value)) return;
   
-		}
-	}).catch(() => {
-        login_prompt.value = "Wrong email or password! :(";
-    })
+  if (!loginPassword.value) {
+    showToast('璇疯緭鍏ュ瘑鐮�', 'error');
+    return;
+  }
+
+  const hashedPassword = md5.create().update(loginPassword.value);
+  userLogin({
+    phone: loginPhone.value,
+    password: hashedPassword.hex()
+  }).then(res => {
+    if (res.data.code === '000' || res.data.code === '200') {
+      showToast('鐧诲綍鎴愬姛', 'success');
+      const token = res.data.result;
+      sessionStorage.setItem('token', token);
+      userInfo().then(res => {
+        sessionStorage.setItem('user-token', JSON.stringify(res.data.result));
+        router.push({path: "/home"});
+      });
+    } else if (res.data.code === '400') {
+      showToast(res.data.msg || '鎵嬫満鍙锋垨瀵嗙爜閿欒', 'error');
+      loginPassword.value = '';
+    }
+  }).catch(() => {
+    showToast('鐧诲綍澶辫触锛岃绋嶅悗閲嶈瘯', 'error');
+  });
 }
+
+// 娣诲姞琛ㄥ崟楠岃瘉鏂规硶
+const validateRegisterForm = () => {
+  if (!name.value) {
+    showToast('璇疯緭鍏ョ敤鎴峰悕', 'error');
+    return false;
+  }
+  if (!validatePhone(registerPhone.value)) return false;
+  if (!registerCaptcha.value) {
+    showToast('璇疯緭鍏ラ獙璇佺爜', 'error');
+    return false;
+  }
+  if (!registerPassword.value) {
+    showToast('璇疯緭鍏ュ瘑鐮�', 'error');
+    return false;
+  }
+  if (!registerPasswordConfirm.value) {
+    showToast('璇风‘璁ゅ瘑鐮�', 'error');
+    return false;
+  }
+  if (registerPassword.value !== registerPasswordConfirm.value) {
+    showToast('涓ゆ杈撳叆鐨勫瘑鐮佷笉涓€鑷�', 'error');
+    return false;
+  }
+  return true;
+};
+
+const validateResetForm = () => {
+  if (!validatePhone(resetPasswordPhone.value)) return false;
+  if (!resetPasswordCaptcha.value) {
+    showToast('璇疯緭鍏ラ獙璇佺爜', 'error');
+    return false;
+  }
+  if (!resetPassword.value) {
+    showToast('璇疯緭鍏ユ柊瀵嗙爜', 'error');
+    return false;
+  }
+  if (!resetPasswordConfirm.value) {
+    showToast('璇风‘璁ゆ柊瀵嗙爜', 'error');
+    return false;
+  }
+  if (resetPassword.value !== resetPasswordConfirm.value) {
+    showToast('涓ゆ杈撳叆鐨勫瘑鐮佷笉涓€鑷�', 'error');
+    return false;
+  }
+  return true;
+};
+
+const validateSendCaptcha = (phone) => {
+  if (!phone) {
+    showToast('璇疯緭鍏ユ墜鏈哄彿鐮�', 'error');
+    return false;
+  }
+  if (!chinaMobileRegex.test(phone)) {
+    showToast('璇疯緭鍏ユ纭殑鎵嬫満鍙风爜鏍煎紡', 'error');
+    return false;
+  }
+  return true;
+};
+
 function handleRegister() {
-	userRegister({
-		username: register_name.value,
-		email: register_email.value,
-		password: register_password.value,
-	}).then(res => {
-		if (res.data.code === '000' || res.data.code === '200') {
-            let userForms = document.getElementById('user_options-forms')
-            userForms.classList.remove('bounceLeft')
-            userForms.classList.add('bounceRight')
-		} else if (res.data.code === '400') {
-
-		}
-	}).catch(() => {
-        register_prompt.value = "Email already taken! :(";
-    })
+  if (!validateRegisterForm()) return;
+  
+  const hashedPassword = md5.create().update(registerPassword.value);
+  userRegister({
+    name: name.value,
+    phone: registerPhone.value,
+    password: hashedPassword.hex(),
+    captcha: registerCaptcha.value
+  }).then(res => {
+    if (res.data.code === '000' || res.data.code === '200') {
+      showToast('娉ㄥ唽鎴愬姛', 'success');
+      location.reload();
+    } else if (res.data.code === '400') {
+      showToast(res.data.msg || '娉ㄥ唽澶辫触锛岃閲嶈瘯', 'error');
+    }
+  }).catch(() => {
+    showToast('娉ㄥ唽澶辫触锛岃绋嶅悗閲嶈瘯', 'error');
+  });
 }
 
-onMounted(() => {
-	theme.reset();
-	
-	/**
-	 * Variables
-	 */
-	const signupButton = document.getElementById('signup-button'),
-		loginButton = document.getElementById('login-button'),
-		userForms = document.getElementById('user_options-forms')
-
-	/**
-	 * Add event listener to the "Sign Up" button
-	 */
-	signupButton.addEventListener('click', () => {
-		userForms.classList.remove('bounceRight')
-		userForms.classList.add('bounceLeft')
-        register_prompt.value = "";
-	}, false)
-
-	/**
-	 * Add event listener to the "Login" button
-	 */
-	loginButton.addEventListener('click', () => {
-		userForms.classList.remove('bounceLeft')
-		userForms.classList.add('bounceRight')
-        login_prompt.value = "";
-	}, false)
-})
+function handleResetPassword() {
+  if (!validateResetForm()) return;
+
+  const hashedPassword = md5.create().update(resetPassword.value);
+  userReset({
+    phone: resetPasswordPhone.value,
+    password: hashedPassword.hex(),
+    captcha: resetPasswordCaptcha.value
+  }).then(res => {
+    if (res.data.code === '000' || res.data.code === '200') {
+      showToast('瀵嗙爜閲嶇疆鎴愬姛', 'success');
+      location.reload();
+    } else if (res.data.code === '400') {
+      showToast(res.data.msg || '閲嶇疆澶辫触锛岃閲嶈瘯', 'error');
+    }
+  }).catch(() => {
+    showToast('閲嶇疆澶辫触锛岃绋嶅悗閲嶈瘯', 'error');
+  });
+}
+
+function handleSendCaptcha(phone) {
+  if (!validateSendCaptcha(phone)) return;
+  if (sendingCaptcha.value) {
+    showToast('璇风瓑寰呭€掕鏃剁粨鏉熷悗鍐嶆鍙戦€�', 'info');
+    return;
+  }
+
+  userSendCaptcha({
+    phone: phone
+  }).then(res => {
+    if (res.data.code === '000' || res.data.code === '200') {
+      showToast('楠岃瘉鐮佸彂閫佹垚鍔�', 'success');
+      startCountdown();
+    } else if (res.data.code === '400') {
+      showToast(res.data.msg || '鍙戦€佸け璐ワ紝璇烽噸璇�', 'error');
+    }
+  }).catch(() => {
+    showToast('鍙戦€佸け璐ワ紝璇风◢鍚庨噸璇�', 'error');
+  });
+}
+
+function startCountdown() {
+  const sendCaptchaButton = document.getElementById('sendCaptcha');
+  sendingCaptcha.value = true;
+  let seconds = 60;
+  const countdown = setInterval(() => {
+    seconds--;
+    sendCaptchaButton.textContent = `${seconds}s RETRY`;
+    if (seconds <= 0) {
+      clearInterval(countdown);
+      sendCaptchaButton.textContent = 'SEND CAPTCHA';
+      sendingCaptcha.value = false;
+    }
+  }, 1000);
+}
 
 </script>
 
 <template>
 	<body>
 		<video autoplay muted loop id="video-background">
-			<source src="../assets/videos/1.mp4" type="video/mp4">
+			<source src="../assets/videos/3.mp4" type="video/mp4">
 			Your browser does not support the video tag.
 		</video>
 		<img class="logo" src="../assets/pictures/logos/logo1.png" alt="">
-		<section class="user">
-			<div class="user_options-container">
-				<div class="user_options-text">
-					<div class="user_options-unregistered">
-						<h2 class="user_registered-title">娆㈣繋鍥炴潵锛岄煶涔愯揪浜猴紒</h2>
-						<p class="user_registered-text">杈撳叆浣犵殑璐﹀彿鍜屽瘑鐮侊紝缁х画璺熼殢鑺傛媿鍓嶈銆傝繕璁板緱浣犱笂娆″湪鈥滄垜鐨勬瓕鍗曗€濋噷鏀惰棌浜嗗摢浜涙瓕鏇插悧锛熷揩鏉ュ拰鎴戜滑涓€璧烽噸娓╅偅浜涚編濡欑殑鏃嬪緥鍚э紒濡傛灉杩樻病鏈夎处鎴凤紝鍙互鐐瑰嚮涓嬫柟娉ㄥ唽鍝</p>
-						<button class="user_unregistered-signup" id="signup-button">Sign up</button>
-					</div>
-
-					<div class="user_options-registered">
-						<h2 class="user_unregistered-title">浣犲拰鎴愪负闊充箰杈句汉鍙湁涓€姝ヤ箣閬ワ紒</h2>
-						<p class="user_unregistered-text">娉ㄥ唽涓€涓处鎴凤紝瑙i攣鏃犻檺鏇插簱銆佷釜鎬у寲姝屽崟鍜屾洿澶氱濂囧姛鑳斤紒濉啓浠ヤ笅淇℃伅锛岄┈涓婂紑濮嬩綘鐨勯煶涔愪箣鏃咃紒濡傛灉宸叉湁璐︽埛锛岀偣鍑讳笅鏂圭櫥褰曞惂锛�</p>
-						<button class="user_registered-login" id="login-button">Login</button>
-					</div>
-				</div>
-
-				<div class="user_options-forms" id="user_options-forms">
-					<div class="user_forms-login">
-						<h2 class="forms_title">Login</h2>
-						<form class="forms_form">
-							<fieldset class="forms_fieldset">
-								<div class="forms_field">
-									<input type="email" v-model="login_email" placeholder="Email" class="forms_field-input" required autofocus />
-								</div>
-								<div class="forms_field">
-									<input type="password" v-model="login_password" placeholder="Password" class="forms_field-input" required />
-								</div>
-							</fieldset>
-                            <p style="font-family: 'Comic Sans MS', serif; color: red">{{ login_prompt }}</p>
-							<div class="forms_buttons">
-								<button type="button" class="forms_buttons-forgot">蹇樿瀵嗙爜?</button>
-								<input @click="handleLogin" type="submit" value="Log In" class="forms_buttons-action">
-							</div>
-						</form>
-					</div>
-					<div class="user_forms-signup">
-						<h2 class="forms_title">Sign Up</h2>
-						<form class="forms_form">
-							<fieldset class="forms_fieldset">
-								<div class="forms_field">
-									<input type="text" v-model="register_name" placeholder="Username" class="forms_field-input" required />
-								</div>
-								<div class="forms_field">
-									<input type="email" v-model="register_email" placeholder="Email" class="forms_field-input" required />
-								</div>
-								<div class="forms_field">
-									<input type="password" v-model="register_password" placeholder="Password" class="forms_field-input" required />
-								</div>
-							</fieldset>
-                            <p style="font-family: 'Comic Sans MS', serif; color: red">{{ register_prompt }}</p>
-							<div class="forms_buttons">
-								<input @click="handleRegister" type="submit" value="Sign up" class="forms_buttons-action">
-							</div>
-						</form>
-					</div>
-				</div>
-			</div>
-		</section>
+    <div class="shell">
+      <div v-if="!reset" class="container a-container" id="a-container">
+        <div class="toast-list">
+          <NotificationToast
+            v-for="toast in toasts"
+            :key="toast.id"
+            :message="toast.message"
+            :type="toast.type"
+          />
+        </div>
+        <form action="" method="" class="form" id="a-form">
+          <h2 class="form_title title">鍒涘缓璐﹀彿</h2>
+          <input type="text" class="form_input"
+                 placeholder="Name" v-model="name">
+          <input type="text" class="form_input"
+                 placeholder="Phone" v-model="registerPhone">
+          <input type="text" class="form_input"
+                 placeholder="Captcha" v-model="registerCaptcha">
+          <input type="password" class="form_input"
+                 placeholder="Password" v-model="registerPassword">
+          <input type="password" class="form_input" :class = "{ 'error': registerPassword !==  registerPasswordConfirm}"
+                 placeholder="Confirm Password" v-model="registerPasswordConfirm">
+          <div style="display:flex; justify-content: space-between">
+            <button style="margin-right: 10px" class="form_button button submit" @click="handleRegister">
+              SIGN UP
+            </button>
+            <button id="sendCaptcha" style="margin-left: 10px"
+                    class="form_button button submit"
+                    @click="handleSendCaptcha(registerPhone)">
+              SEND CAPTCHA
+            </button>
+          </div>
+
+        </form>
+      </div>
+
+      <div v-if="reset" class="container a-container" id="a-container">
+        <div class="toast-list">
+          <NotificationToast
+            v-for="toast in toasts"
+            :key="toast.id"
+            :message="toast.message"
+            :type="toast.type"
+          />
+        </div>
+        <form action="" method="" class="form" id="a-form">
+          <h2 class="form_title title">閲嶇疆瀵嗙爜</h2>
+          <input type="text" class="form_input"
+                 placeholder="Phone" v-model="resetPasswordPhone">
+          <input type="text" class="form_input"
+                 placeholder="Captcha" v-model="resetPasswordCaptcha">
+          <input type="password" class="form_input"
+                 placeholder="Password" v-model="resetPassword">
+          <input type="password" class="form_input" :class = "{ 'error': resetPassword !==  resetPasswordConfirm}"
+                 placeholder="Confirm Password" v-model="resetPasswordConfirm">
+          <div style="display: flex; justify-content: space-between ">
+            <button style="margin-right: 10px" class="form_button button submit" @click="handleResetPassword">
+              RESET
+            </button>
+            <button id="sendCaptcha" style="margin-left: 10px"
+                    class="form_button button submit"
+                    @click="handleSendCaptcha(registerPhone)">
+              SEND CAPTCHA
+            </button>
+          </div>
+        </form>
+      </div>
+
+      <div class="container b-container" id="b-container">
+        <div class="toast-list">
+          <NotificationToast
+            v-for="toast in toasts"
+            :key="toast.id"
+            :message="toast.message"
+            :type="toast.type"
+          />
+        </div>
+        <form action="" method="" class="form" id="b-form">
+          <h2 class="form_title title">鐧诲綍璐﹀彿</h2>
+          <input type="text" class="form_input"
+                 placeholder="Phone" v-model="loginPhone">
+          <input type="password" class="form_input"
+                 placeholder="Password" v-model="loginPassword">
+          <button class="switch_button button switch-btn" @click="() => {reset = true}">FORGET PASSWORD?</button >
+          <button class="form_button button submit" @click="handleLogin">
+            SIGN IN
+          </button>
+        </form>
+      </div>
+
+      <div class="switch" id="switch-cnt">
+        <div class="switch_circle"></div>
+        <div class="switch_circle switch_circle-t"></div>
+        <div class="switch_container" id="switch-c1">
+          <h2 class="switch_title title" style="letter-spacing: 0;">Welcome Back锛�</h2>
+          <p class="switch_description description">宸茬粡鏈夎处鍙蜂簡鍢涳紝鍘荤櫥褰曡处鍙风户缁窡闅忚妭鎷嶅墠琛屽惂锛侊紒锛�</p >
+          <button class="switch_button button switch-btn" @click="reset = false">SIGN IN</button>
+        </div>
+
+        <div class="switch_container is-hidden" id="switch-c2">
+          <h2 class="switch_title title" style="letter-spacing: 0;">Hello Friend锛�</h2>
+          <p class="switch_description description">鍘绘敞鍐屼竴涓处鍙凤紝鎴愪负灏婅吹鐨勭矇涓濅細鍛橈紝璁╂垜浠笍鍏ュ濡欑殑鏃呴€旓紒</p >
+          <button class="switch_button button switch-btn">SIGN UP</button>
+        </div>
+      </div>
+    </div>
 	</body>
 </template>
 
@@ -165,352 +418,314 @@ onMounted(() => {
 	box-sizing: border-box;
 	padding: 0;
 	margin: 0;
+  user-select: none;
 }
 
 body {
-    margin: 0;
-    padding: 0;
-    height: 100%;
-	font-family: "Nunito", sans-serif;
-	display: flex;
-	align-items: center;
-	justify-content: center;
-	background-image: url("../assets/videos/1.mp4");
-	background-repeat: no-repeat;
-	background-size: cover;
+  width: 100%;
+  height: 100vh;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  font-size: 12px;
+  color: #a0a5a8;
 }
 
-.logo {
-	position: absolute;
-	top: -10px;
-	left: -10px;
-	width: 150px;
-	height: 150px;
+.shell {
+  position: relative;
+  width: 1000px;
+  min-width: 1000px;
+  min-height: 600px;
+  height: 600px;
+  padding: 25px;
+  background-color: #ecf0f3;
+  box-shadow: 10px 10px 10px #d1d9e6, -10px -10px 10px #f9f9f9;
+  border-radius: 12px;
+  overflow: hidden;
 }
 
-#video-background {
-	position: absolute;
-	top: 0;
-	left: 0;
-	width: 100%;
-	height: 100%;
-	object-fit: cover; /* 纭繚瑙嗛濉厖鏁翠釜瑙嗗彛 */
-	z-index: -1; /* 灏嗚棰戠疆浜庡唴瀹瑰悗闈� */
+/* 璁剧疆鍝嶅簲寮� */
+@media (max-width: 1200px) {
+  .shell {
+    transform: scale(0.7);
+  }
 }
 
-button {
-	background-color: transparent;
-	padding: 0;
-	border: 0;
-	outline: 0;
-	cursor: pointer;
+@media (max-width: 1000px) {
+  .shell {
+    transform: scale(0.6);
+  }
 }
 
-input {
-	background-color: transparent;
-	padding: 0;
-	border: 0;
-	outline: 0;
-}
-input[type=submit] {
-	cursor: pointer;
-}
-input::-moz-placeholder {
-	font-size: 0.85rem;
-	font-family: "Montserrat", sans-serif;
-	font-weight: 300;
-	letter-spacing: 0.1rem;
-	color: #ccc;
-}
-input:-ms-input-placeholder {
-	font-size: 0.85rem;
-	font-family: "Montserrat", sans-serif;
-	font-weight: 300;
-	letter-spacing: 0.1rem;
-	color: #ccc;
-}
-input::placeholder {
-	font-size: 0.85rem;
-	font-family: "Montserrat", sans-serif;
-	font-weight: 300;
-	letter-spacing: 0.1rem;
-	color: #ccc;
+@media (max-width: 800px) {
+  .shell {
+    transform: scale(0.5);
+  }
 }
 
-/**
- * * Bounce to the left side
- * */
-@-webkit-keyframes bounceLeft {
-	0% {
-		transform: translate3d(100%, -50%, 0);
-	}
-	50% {
-		transform: translate3d(-30px, -50%, 0);
-	}
-	100% {
-		transform: translate3d(0, -50%, 0);
-	}
-}
-@keyframes bounceLeft {
-	0% {
-		transform: translate3d(100%, -50%, 0);
-	}
-	50% {
-		transform: translate3d(-30px, -50%, 0);
-	}
-	100% {
-		transform: translate3d(0, -50%, 0);
-	}
+@media (max-width: 600px) {
+  .shell {
+    transform: scale(0.4);
+  }
 }
-/**
- * * Bounce to the left side
- * */
-@-webkit-keyframes bounceRight {
-	0% {
-		transform: translate3d(0, -50%, 0);
-	}
-	50% {
-		transform: translate3d(calc(100% + 30px), -50%, 0);
-	}
-	100% {
-		transform: translate3d(100%, -50%, 0);
-	}
-}
-@keyframes bounceRight {
-	0% {
-		transform: translate3d(0, -50%, 0);
-	}
-	50% {
-		transform: translate3d(calc(100% + 30px), -50%, 0);
-	}
-	100% {
-		transform: translate3d(100%, -50%, 0);
-	}
+
+.container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  position: absolute;
+  top: 0;
+  width: 600px;
+  height: 100%;
+  padding: 25px;
+  background-color: #ecf0f3;
+  transition: 1.25s;
 }
-/**
- * * Show Sign Up form
- * */
-@-webkit-keyframes showSignUp {
-	100% {
-		opacity: 1;
-		visibility: visible;
-		transform: translate3d(0, 0, 0);
-	}
-}
-@keyframes showSignUp {
-	100% {
-		opacity: 1;
-		visibility: visible;
-		transform: translate3d(0, 0, 0);
-	}
+
+.form {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+  width: 100%;
+  height: 100%;
 }
-/**
- * * Page background
- * */
-.user {
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	width: 100%;
-	height: 100vh;
-	background-size: cover;
+
+.iconfont {
+  margin: 0 5px;
+  border: rgba(0, 0, 0, 0.5) 2px solid;
+  border-radius: 50%;
+  font-size: 25px;
+  padding: 3px;
+  opacity: 0.5;
+  transition: 0.1s;
 }
-.user_options-container {
-	position: relative;
-	width: 80%;
+
+.iconfont:hover {
+  opacity: 1;
+  transition: 0.15s;
+  cursor: pointer;
 }
-.user_options-text {
-	display: flex;
-	justify-content: space-between;
-	width: 100%;
-	background-color: rgba(34, 34, 34, 0.85);
-	border-radius: 3px;
+
+.form_input {
+  width: 350px;
+  height: 40px;
+  margin: 4px 0;
+  padding-left: 25px;
+  font-size: 13px;
+  color: black;
+  letter-spacing: 0.15px;
+  border: none;
+  outline: none;
+  background-color: #ecf0f3;
+  transition: 0.25s ease;
+  border-radius: 8px;
+  box-shadow: inset 2px 2px 4px #d1d9e6, inset -2px -2px 4px #f9f9f9;
 }
 
-/**
- * * Registered and Unregistered user box and text
- * */
-.user_options-registered,
-.user_options-unregistered {
-	width: 50%;
-	padding: 75px 45px;
-	color: #fff;
-	font-weight: 300;
+.form_input:focus {
+  box-shadow: inset 4px 4px 4px #d1d9e6, inset -4px -4px 4px #f9f9f9;
 }
 
-.user_registered-title,
-.user_unregistered-title {
-	margin-bottom: 15px;
-	font-size: 1.66rem;
-	line-height: 1em;
+.error {
+  color: red; /* 閿欒杈规棰滆壊 */
 }
 
-.user_unregistered-text,
-.user_registered-text {
-	font-size: 0.83rem;
-	line-height: 1.4em;
+.form_span {
+  margin-top: 30px;
+  margin-bottom: 12px;
 }
 
-.user_registered-login,
-.user_unregistered-signup {
-	margin-top: 30px;
-	border: 1px solid #ccc;
-	border-radius: 3px;
-	padding: 10px 30px;
-	color: #fff;
-	text-transform: uppercase;
-	line-height: 1em;
-	letter-spacing: 0.2rem;
-	transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
+.form_link {
+  color: #181818;
+  font-size: 15px;
+  margin-top: 25px;
+  border-bottom: 1px solid #a0a5a8;
+  line-height: 2;
 }
-.user_registered-login:hover,
-.user_unregistered-signup:hover {
-	color: rgba(34, 34, 34, 0.85);
-	background-color: #ccc;
+
+.title {
+  font-size: 34px;
+  font-weight: 700;
+  line-height: 3;
+  color: #181818;
+  letter-spacing: 10px;
 }
 
-/**
- * * Login and signup forms
- * */
-.user_options-forms {
-	position: absolute;
-	top: 50%;
-	left: 30px;
-	width: calc(50% - 30px);
-	min-height: 420px;
-	background-color: #fff;
-	border-radius: 3px;
-	box-shadow: 2px 0 15px rgba(0, 0, 0, 0.25);
-	overflow: hidden;
-	transform: translate3d(100%, -50%, 0);
-	transition: transform 0.4s ease-in-out;
-}
-.user_options-forms .user_forms-login {
-	transition: opacity 0.4s ease-in-out, visibility 0.4s ease-in-out;
-}
-.user_options-forms .forms_title {
-	margin-bottom: 45px;
-	font-size: 1.5rem;
-	font-weight: 500;
-	line-height: 1em;
-	text-transform: uppercase;
-	color: #e8716d;
-	letter-spacing: 0.1rem;
-}
-.user_options-forms .forms_field:not(:last-of-type) {
-	margin-bottom: 20px;
-}
-.user_options-forms .forms_field-input {
-	width: 100%;
-	border-bottom: 1px solid #ccc;
-	padding: 6px 20px 6px 6px;
-	font-family: "Montserrat", sans-serif;
-	font-size: 1rem;
-	font-weight: 300;
-	color: gray;
-	letter-spacing: 0.1rem;
-	transition: border-color 0.2s ease-in-out;
-}
-.user_options-forms .forms_field-input:focus {
-	border-color: gray;
-}
-.user_options-forms .forms_buttons {
-	display: flex;
-	justify-content: space-between;
-	align-items: center;
-	margin-top: 35px;
-}
-.user_options-forms .forms_buttons-forgot {
-	font-family: "Montserrat", sans-serif;
-	letter-spacing: 0.1rem;
-	color: #ccc;
-	text-decoration: underline;
-	transition: color 0.2s ease-in-out;
-}
-.user_options-forms .forms_buttons-forgot:hover {
-	color: #b3b3b3;
-}
-.user_options-forms .forms_buttons-action {
-	background-color: #e8716d;
-	border-radius: 3px;
-	padding: 10px 35px;
-	font-size: 1rem;
-	font-family: "Montserrat", sans-serif;
-	font-weight: 300;
-	color: #fff;
-	text-transform: uppercase;
-	letter-spacing: 0.1rem;
-	transition: background-color 0.2s ease-in-out;
-}
-.user_options-forms .forms_buttons-action:hover {
-	background-color: #e14641;
-}
-.user_options-forms .user_forms-signup,
-.user_options-forms .user_forms-login {
-	position: absolute;
-	top: 70px;
-	left: 40px;
-	width: calc(100% - 80px);
-	opacity: 0;
-	visibility: hidden;
-	transition: opacity 0.4s ease-in-out, visibility 0.4s ease-in-out, transform 0.5s ease-in-out;
+.description {
+  font-size: 14px;
+  letter-spacing: 0.25px;
+  text-align: center;
+  line-height: 1.6;
 }
-.user_options-forms .user_forms-signup {
-	transform: translate3d(120px, 0, 0);
+
+.button {
+  width: 180px;
+  height: 50px;
+  border-radius: 25px;
+  margin-top: 50px;
+  font-weight: 700;
+  font-size: 14px;
+  letter-spacing: 1.15px;
+  background-color: #4B70E2;
+  color: #f9f9f9;
+  box-shadow: 8px 8px 16px #d1d9e6, -8px -8px 16px #f9f9f9;
+  border: none;
+  outline: none;
 }
-.user_options-forms .user_forms-signup .forms_buttons {
-	justify-content: flex-end;
+
+.a-container {
+  z-index: 100;
+  left: calc(100% - 600px);
 }
-.user_options-forms .user_forms-login {
-	transform: translate3d(0, 0, 0);
-	opacity: 1;
-	visibility: visible;
+
+.b-container {
+  left: calc(100% - 600px);
+  z-index: 0;
 }
 
-/**
- * * Triggers
- * */
-.user_options-forms.bounceLeft {
-	-webkit-animation: bounceLeft 1s forwards;
-	animation: bounceLeft 1s forwards;
+.switch {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  position: absolute;
+  top: 0;
+  left: 0;
+  height: 100%;
+  width: 400px;
+  padding: 50px;
+  z-index: 200;
+  transition: 1.25s;
+  background-color: #ecf0f3;
+  overflow: hidden;
+  box-shadow: 4px 4px 10px #d1d9e6, -4px -4px 10px #d1d9e6;
 }
-.user_options-forms.bounceLeft .user_forms-signup {
-	-webkit-animation: showSignUp 1s forwards;
-	animation: showSignUp 1s forwards;
+
+.switch_circle {
+  position: absolute;
+  width: 500px;
+  height: 500px;
+  border-radius: 50%;
+  background-color: #ecf0f3;
+  box-shadow: inset 8px 8px 12px #b8bec7, inset -8px -8px 12px #fff;
+  bottom: -60%;
+  left: -60%;
+  transition: 1.25s;
 }
-.user_options-forms.bounceLeft .user_forms-login {
-	opacity: 0;
-	visibility: hidden;
-	transform: translate3d(-120px, 0, 0);
+
+.switch_circle-t {
+  top: -30%;
+  left: 60%;
+  width: 300px;
+  height: 300px;
 }
-.user_options-forms.bounceRight {
-	-webkit-animation: bounceRight 1s forwards;
-	animation: bounceRight 1s forwards;
+
+.switch_container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+  position: absolute;
+  width: 400px;
+  padding: 50px 55px;
+  transition: 1.25s;
 }
 
-/**
- * * Responsive 990px
- * */
-@media screen and (max-width: 990px) {
-	.user_options-forms {
-		min-height: 350px;
-	}
-	.user_options-forms .forms_buttons {
-		flex-direction: column;
-	}
-	.user_options-forms .user_forms-login .forms_buttons-action {
-		margin-top: 30px;
-	}
-	.user_options-forms .user_forms-signup,
-	.user_options-forms .user_forms-login {
-		top: 40px;
-	}
-
-	.user_options-registered,
-	.user_options-unregistered {
-		padding: 50px 45px;
-	}
+.switch_button {
+  cursor: pointer;
 }
 
+.switch_button:hover,
+.submit:hover {
+  box-shadow: 6px 6px 10px #d1d9e6, -6px -6px 10px #f9f9f9;
+  transform: scale(0.985);
+  transition: 0.25s;
+}
 
+.switch_button:active,
+.switch_button:focus {
+  box-shadow: 2px 2px 6px #d1d9e6, -2px -2px 6px #f9f9f9;
+  transform: scale(0.97);
+  transition: 0.25s;
+}
+
+.is-txr {
+  left: calc(100% - 400px);
+  transition: 1.25s;
+  transform-origin: left;
+}
+
+.is-txl {
+  left: 0;
+  transition: 1.25s;
+  transform-origin: right;
+}
+
+.is-z {
+  z-index: 200;
+  transition: 1.25s;
+}
+
+.is-hidden {
+  visibility: hidden;
+  opacity: 0;
+  position: absolute;
+  transition: 1.25s;
+}
+
+.is-gx {
+  animation: is-gx 1.25s;
+}
+
+@keyframes is-gx {
+
+  0%,
+  10%,
+  100% {
+    width: 400px;
+  }
+
+  30%,
+  50% {
+    width: 500px;
+  }
+}
+
+.iconfont {
+  position: absolute;
+  right: 10px;
+  top: 50%;
+  transform: translateY(-50%);
+  cursor: pointer;
+}
+
+.logo {
+	position: absolute;
+	top: -10px;
+	left: -10px;
+	width: 150px;
+	height: 150px;
+}
+
+#video-background {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	object-fit: cover; /* 纭繚瑙嗛濉厖鏁翠釜瑙嗗彛 */
+	z-index: -1; /* 灏嗚棰戠疆浜庡唴瀹瑰悗闈� */
+}
+
+.toast-list {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  z-index: 9999;
+  pointer-events: none;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
 </style>
\ No newline at end of file