diff --git a/frontend/web/src/assets/default_avatar.png b/frontend/web/src/assets/default_avatar.png new file mode 100644 index 0000000..a21d544 Binary files /dev/null and b/frontend/web/src/assets/default_avatar.png differ diff --git a/frontend/web/src/router/index.js b/frontend/web/src/router/index.js index e966e63..e39fea8 100644 --- a/frontend/web/src/router/index.js +++ b/frontend/web/src/router/index.js @@ -11,6 +11,23 @@ const routes = [ { path: '/', component: MainView, + children: [ + { + path: '/messages', + name: 'userMessages', + component: () => import('@/views/messages/MessageList.vue'), + children: [ + { + path: '/messages/chat/:id', + name: '/msgChat', + component: () => import('@/views/messages/MessageContent.vue'), + props: true + } + ] + }, + { path: '/contacts', name: 'userContacts', component: () => import('@/views/contact/ContactList.vue') }, + { path: '/settings', name: 'userSettings', component: () => import('@/views/settings/SettingMenu.vue') } + ], meta: { requiresAuth: true } diff --git a/frontend/web/src/services/auth.js b/frontend/web/src/services/auth.js index 0df0456..e3f62e5 100644 --- a/frontend/web/src/services/auth.js +++ b/frontend/web/src/services/auth.js @@ -7,5 +7,11 @@ export const authService = { * @returns */ login: (data) => request.post('/auth/login', data), + + /** + * 用户注册 + * @param {*} data + * @returns + */ register: (data) => request.post('/auth/register', data) } \ No newline at end of file diff --git a/frontend/web/src/stores/auth.js b/frontend/web/src/stores/auth.js index 093b0a1..2193a06 100644 --- a/frontend/web/src/stores/auth.js +++ b/frontend/web/src/stores/auth.js @@ -3,7 +3,8 @@ import { defineStore } from 'pinia' export const useAuthStore = defineStore('auth', () => { const token = ref(localStorage.getItem('user_token') || ''); - const userInfo = ref(null); + const refreshToken = ref(localStorage.getItem('refresh_token') || ''); + const userInfo = ref(localStorage.getItem('user_info') || ''); //判断是否已登录 const isLoggedIn = computed(() => !!token.value); @@ -13,10 +14,13 @@ export const useAuthStore = defineStore('auth', () => { * @param {String} newToken 用户凭证 * @param {*} user 用户信息 */ - function setLoginInfo(newToken, user) { + function setLoginInfo(newToken, newRefreshToken, user) { token.value = newToken; + refreshToken.value = newRefreshToken userInfo.value = user; localStorage.setItem('user_token', newToken); + localStorage.setItem('refresh_token', refreshToken) + localStorage.setItem('user_info', user) } /** @@ -26,6 +30,8 @@ export const useAuthStore = defineStore('auth', () => { token.value = ''; userInfo.value = null; localStorage.removeItem('user_token'); + localStorage.removeItem('refresh_token') + localStorage.removeItem('user_info') } return { token, userInfo, isLoggedIn, setLoginInfo, logout }; diff --git a/frontend/web/src/views/Main.vue b/frontend/web/src/views/Main.vue index ab5d6b7..0036541 100644 --- a/frontend/web/src/views/Main.vue +++ b/frontend/web/src/views/Main.vue @@ -1,477 +1,226 @@ + +.send-row { display: flex; justify-content: flex-end; } +.send-btn { + background: #f5f5f5; + color: #07c160; + border: 1px solid #e0e0e0; + padding: 5px 20px; + border-radius: 4px; + cursor: pointer; + font-size: 13px; +} +.send-btn:hover { background: #e2e2e2; } + +/* 列表美化 */ +.list-item { display: flex; padding: 12px; gap: 12px; cursor: pointer; } +.list-item.active { background: #c6c6c6; } +.list-item:hover:not(.active) { background: #ddd; } +.info { flex: 1; overflow: hidden; } +.name-row { display: flex; justify-content: space-between; align-items: center; } +.name { font-size: 14px; font-weight: 500; } +.time { font-size: 11px; color: #999; } +.last-msg { font-size: 12px; color: #888; margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + +.nav-item { font-size: 24px; cursor: pointer; opacity: 0.5; } +.nav-item.active { opacity: 1; } + \ No newline at end of file diff --git a/frontend/web/src/views/auth/Login.vue b/frontend/web/src/views/auth/Login.vue index ab81d33..97f7b57 100644 --- a/frontend/web/src/views/auth/Login.vue +++ b/frontend/web/src/views/auth/Login.vue @@ -87,7 +87,7 @@ const handleLogin = async () => { const res = await authService.login(form); if(res.code === 0){ message.success('登陆成功。') - authStore.setLoginInfo(res.data.token, res.data.userInfo); + authStore.setLoginInfo(res.data.token, res.data.refreshToken, res.data.userInfo); loading.value = false; router.push('/index') }else{ diff --git a/frontend/web/src/views/contact/ContactList.vue b/frontend/web/src/views/contact/ContactList.vue new file mode 100644 index 0000000..101df6f --- /dev/null +++ b/frontend/web/src/views/contact/ContactList.vue @@ -0,0 +1,315 @@ + + + + + \ No newline at end of file diff --git a/frontend/web/src/views/contact/UserInfoContent.vue b/frontend/web/src/views/contact/UserInfoContent.vue new file mode 100644 index 0000000..41a40c8 --- /dev/null +++ b/frontend/web/src/views/contact/UserInfoContent.vue @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/web/src/views/messages/MessageContent.vue b/frontend/web/src/views/messages/MessageContent.vue new file mode 100644 index 0000000..8b5293a --- /dev/null +++ b/frontend/web/src/views/messages/MessageContent.vue @@ -0,0 +1,234 @@ + + + + + \ No newline at end of file diff --git a/frontend/web/src/views/messages/MessageList.vue b/frontend/web/src/views/messages/MessageList.vue new file mode 100644 index 0000000..820d049 --- /dev/null +++ b/frontend/web/src/views/messages/MessageList.vue @@ -0,0 +1,245 @@ + + + + + \ No newline at end of file diff --git a/frontend/web/src/views/settings/SettingMenu.vue b/frontend/web/src/views/settings/SettingMenu.vue new file mode 100644 index 0000000..41a40c8 --- /dev/null +++ b/frontend/web/src/views/settings/SettingMenu.vue @@ -0,0 +1 @@ + \ No newline at end of file