fix(service): 🐛 修复http模块没有设置请求头导致请求报错问题

完善登录逻辑和自动登录逻辑
This commit is contained in:
nongyehong 2024-11-16 17:53:14 +08:00
parent 54ee3ff168
commit 153896480e
16 changed files with 152 additions and 87 deletions

View File

@ -1,13 +1,15 @@
<template>
<!-- 好友详情 -->
<n-flex v-if="content.type === RoomTypeEnum.SINGLE" vertical align="center" :size="30" class="mt-60px select-none">
<n-image
width="146px"
height="146px"
style="border: 2px solid #fff"
class="rounded-50%"
:src="item.avatar"
alt="" />
<n-avatar v-if="item.avatar" class="rounded-50% size-146px border-(2px solid #fff)" :src="item.avatar" />
<n-avatar
v-else
:color="'#909090'"
class="rounded-50% size-146px text-28px border-(2px solid #fff)"
:src="item.avatar">
{{ item.name!.slice(0, 1) }}
</n-avatar>
<span class="text-(20px [--text-color])">{{ item.name }}</span>

View File

@ -56,7 +56,7 @@
</n-virtual-list>
</div>
<!-- 发送按钮 TODO 建议不要放在外面会影响视觉效果可以放在发送按钮里面做提示发送按钮需要修改一下大小 (nyh -> 2024-09-01 23:41:34) -->
<!-- 发送按钮 -->
<n-flex align="center" justify="space-between" :size="12">
<n-config-provider :theme="lightTheme">
<n-button-group size="small" class="pr-20px">

View File

@ -85,16 +85,6 @@
<div class="pl-20px flex flex-col items-end gap-6px">
<MsgInput ref="MsgInputRef" />
</div>
<div v-if="isGuest" class="fuzzy">
<n-flex align="center" :size="0" class="pb-60px text-(14px [--text-color])">
<p>当前为</p>
<p class="color-#c14053 px-2px">游客模式</p>
<p></p>
<p @click="logout(true)" class="color-#13987f px-4px cursor-pointer">扫码登录</p>
<p>后使用</p>
</n-flex>
</div>
</main>
</template>
@ -104,20 +94,12 @@ import { LimitEnum, MsgEnum } from '@/enums'
import { useCommon } from '@/hooks/useCommon.ts'
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
import { emit } from '@tauri-apps/api/event'
import { useLogin } from '@/hooks/useLogin.ts'
import { useSettingStore } from '@/stores/setting.ts'
const { logout } = useLogin()
const { open, onChange, reset } = useFileDialog()
const { login } = useSettingStore()
const MsgInputRef = ref()
const msgInputDom = ref()
const emojiShow = ref()
const { insertNode, triggerInputEvent, getEditorRange, imgPaste, FileOrVideoPaste } = useCommon()
/**
* 是否为游客模式
*/
const isGuest = computed(() => login.accountInfo.token === 'test')
/**
* 选择表情并把表情插入输入框
@ -185,13 +167,6 @@ onMounted(() => {
}
}
.fuzzy {
@apply bg-transparent select-none cursor-default size-full absolute-flex-center;
overflow: hidden;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
:deep(.n-input .n-input-wrapper) {
padding: 0;
}

View File

@ -99,6 +99,7 @@
round
v-if="avatarExists(item.fromUser.uid)"
:size="34"
:color="'#909090'"
@click="selectKey = item.message.id"
class="select-none"
:src="getAvatarSrc(item.fromUser.uid)"

View File

@ -65,6 +65,7 @@
:special-menu="report">
<n-flex @click="selectKey = item.uid" :key="item.uid" :size="10" align="center" class="item">
<n-avatar
v-if="item.avatar"
lazy
round
class="grayscale"
@ -77,6 +78,23 @@
:intersection-observer-options="{
root: '#image-chat-sidebar'
}"></n-avatar>
<n-avatar
v-else
lazy
round
class="grayscale text-10px"
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
:color="'#909090'"
:size="24"
:src="item.avatar"
fallback-src="/logo.png"
:render-placeholder="() => null"
:intersection-observer-options="{
root: '#image-chat-sidebar'
}">
{{ item.name.slice(0, 1) }}
</n-avatar>
<span class="text-12px truncate flex-1">{{ item.name }}</span>
<div v-if="item.uid === 1" class="flex p-4px rounded-4px bg-#f5dadf size-fit select-none">
<span class="text-(10px #d5304f)">群主</span>

View File

@ -16,20 +16,13 @@ export const useLogin = () => {
/**
*
* @param isToQrcode
*/
const logout = async (isToQrcode = false) => {
const logout = async () => {
const { createWebviewWindow } = useWindow()
localStorage.removeItem('USER_INFO')
localStorage.removeItem('TOKEN')
// todo 退出账号 需要关闭其他的全部窗口
await createWebviewWindow('登录', 'login', 320, 448, 'home', false, 320, 448).then(() => {
emit(EventEnum.LOGOUT)
emit('logout_success')
// 用于跳转到二维码页面
if (isToQrcode) {
localStorage.setItem('isToQrcode', '1')
}
})
}

View File

@ -24,7 +24,20 @@
<n-flex :size="20" class="p-22px select-none" vertical>
<!-- 头像 -->
<n-flex justify="center">
<n-avatar :size="80" :src="editInfo.content.avatar" round style="border: 3px solid #fff" />
<n-avatar
v-if="editInfo.content.avatar"
:size="80"
:src="editInfo.content.avatar"
round
style="border: 3px solid #fff" />
<n-avatar
v-else
:size="80"
:color="'#909090'"
:src="editInfo.content.avatar"
round
style="border: 3px solid #fff" />
</n-flex>
<n-flex v-if="currentBadge" align="center" justify="center">
<span class="text-(14px #707070)">当前佩戴的徽章:</span>

View File

@ -4,10 +4,14 @@ import Mitt from '@/utils/Bus.ts'
import { useLogin } from '@/hooks/useLogin.ts'
import { useSettingStore } from '@/stores/setting.ts'
import apis from '@/services/apis.ts'
import { LoginStatus, useWsLoginStore } from '@/stores/ws.ts'
import { useUserStore } from '@/stores/user.ts'
const { createWebviewWindow } = useWindow()
const { logout } = useLogin()
const settingStore = useSettingStore()
const loginStore = useWsLoginStore()
const userStore = useUserStore()
const { login } = storeToRefs(settingStore)
/**
* 使pinia写入了localstorage中
@ -97,7 +101,15 @@ const moreList = ref<OPT.L.MoreList[]>([
.logout()
.then(async () => {
await logout()
login.value.accountInfo.token = ''
// 如果没有设置自动登录,则清除用户信息
if (!login.value.autoLogin) {
login.value.accountInfo.token = ''
userStore.userInfo = {}
localStorage.removeItem('USER_INFO')
localStorage.removeItem('TOKEN')
}
userStore.isSign = false
loginStore.loginStatus = LoginStatus.Init
})
.catch(() => {
window.$message.error('退出账号失败')

View File

@ -47,7 +47,7 @@ export default {
/** 标记消息,点赞等 */
markMsg: (data?: MarkMsgReq) => PUT<void>(urls.markMsg, data),
/** 获取用户详细信息 */
getUserDetail: () => GET<UserInfoType>(urls.getUserInfoDetail, {}),
getUserDetail: () => GET<UserInfoType>(urls.getUserInfoDetail),
/** 获取徽章列表 */
getBadgeList: (): Promise<BadgeType> => GET(urls.getBadgeList),
/** 设置用户勋章 */

View File

@ -33,9 +33,22 @@ async function Http<T>(
fullResponse?: true,
abort?: AbortController
): Promise<{ data: Promise<T>; resp: Response }> {
// 获取token
const token = localStorage.getItem('TOKEN')
// 构建请求头
const httpHeaders = new Headers(options.headers || {})
// 设置Content-Type
if (!httpHeaders.has('Content-Type') && !(options.body instanceof FormData)) {
httpHeaders.set('Content-Type', 'application/json')
}
// 设置Authorization
if (token) {
httpHeaders.set('Authorization', `Bearer ${token}`)
}
// 构建 fetch 请求选项
const fetchOptions: RequestInit = {
method: options.method,

View File

@ -40,11 +40,11 @@ class WS {
worker.postMessage(`{"type":"initWS","value":${token ? `"${token}"` : null}}`)
}
onWorkerMsg = (e: MessageEvent<any>) => {
onWorkerMsg = async (e: MessageEvent<any>) => {
const params: { type: string; value: unknown } = JSON.parse(e.data)
switch (params.type) {
case 'message': {
this.onMessage(params.value as string)
await this.onMessage(params.value as string)
break
}
case 'open': {
@ -100,7 +100,7 @@ class WS {
}
// 收到消息回调
onMessage = (value: string) => {
onMessage = async (value: string) => {
// FIXME 可能需要 try catch,
const params: { type: WsResponseMessageType; data: unknown } = JSON.parse(value)
const loginStore = useWsLoginStore()
@ -148,14 +148,14 @@ class WS {
}
])
// 获取用户详情
chatStore.getSessionList(true)
await chatStore.getSessionList(true)
// 自定义表情列表
emojiStore.getEmojiList()
await emojiStore.getEmojiList()
break
}
// 收到消息
case WsResponseMessageType.ReceiveMessage: {
chatStore.pushMsg(params.data as MessageType)
await chatStore.pushMsg(params.data as MessageType)
Mitt.emit(MittEnum.SEND_MESSAGE, params.data)
break
}

View File

@ -1,6 +1,6 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { StoresEnum } from '../enums'
import { StoresEnum } from '@/enums'
export const useLoginHistoriesStore = defineStore(
StoresEnum.LOGIN_HISTORY,

View File

@ -101,7 +101,7 @@
<n-flex v-if="!isLogining && !isWrongPassword" justify="space-around" align="center" :size="0" class="options">
<p class="text-(14px #fefefe)" @click="isUnlockPage = false">返回</p>
<p class="text-(14px #fefefe)" @click="logout()">退出登录</p>
<p class="text-(14px #fefefe)" @click="logout">退出登录</p>
<p class="text-(14px #fefefe)">忘记密码</p>
<p class="text-(14px #fff)" @click="unlock">进入系统</p>
</n-flex>

View File

@ -29,15 +29,28 @@
:key="item.uid">
<n-flex align="center" :size="10" class="h-75px pl-6px pr-8px flex-1 truncate">
<n-avatar
v-if="useUserInfo(item.uid).value.avatar"
round
bordered
:color="'#fff'"
:size="44"
class="grayscale"
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
:src="useUserInfo(item.uid).value.avatar"
fallback-src="/logo.png" />
<n-avatar
v-else
round
bordered
:color="'#909090'"
:size="44"
class="grayscale"
:class="{ 'grayscale-0': item.activeStatus === OnlineEnum.ONLINE }"
:src="useUserInfo(item.uid).value.avatar"
fallback-src="/logo.png">
{{ useUserInfo(item.uid).value.name?.slice(0, 1) }}
</n-avatar>
<n-flex vertical justify="space-between" class="h-fit flex-1 truncate">
<span class="text-14px leading-tight flex-1 truncate">{{
useUserInfo(item.uid).value.name

View File

@ -17,7 +17,11 @@
@dblclick="handleMsgDblclick(item)"
@select="$event.click(item)">
<n-flex :size="10" align="center" class="h-75px pl-6px pr-8px flex-1">
<n-avatar :color="'#fff'" :size="44" :src="item.avatar" bordered fallback-src="/logo.png" round />
<n-avatar v-if="item.avatar" :size="44" :src="item.avatar" bordered fallback-src="/logo.png" round />
<n-avatar v-else :color="'#909090'" :size="44" :src="item.avatar" bordered fallback-src="/logo.png" round>
{{ item.name.slice(0, 1) }}
</n-avatar>
<n-flex class="h-fit flex-1 truncate" justify="space-between" vertical>
<n-flex :size="4" align="center" class="flex-1 truncate" justify="space-between">

View File

@ -151,15 +151,21 @@
<script setup lang="ts">
import router from '@/router'
import { useWindow } from '@/hooks/useWindow.ts'
import { delay } from 'lodash-es'
import { lightTheme } from 'naive-ui'
import { useSettingStore } from '@/stores/setting.ts'
import { useLogin } from '@/hooks/useLogin.ts'
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
import { useLoginHistoriesStore } from '@/stores/loginHistory.ts'
import apis from '@/services/apis.ts'
import { useUserStore } from '@/stores/user.ts'
import { computedToken } from '@/services/request.ts'
import { useChatStore } from '@/stores/chat.ts'
import { useEmojiStore } from '@/stores/emoji.ts'
const settingStore = useSettingStore()
const userStore = useUserStore()
const chatStore = useChatStore()
const emojiStore = useEmojiStore()
const loginHistoriesStore = useLoginHistoriesStore()
const { loginHistories } = loginHistoriesStore
const { login } = storeToRefs(settingStore)
@ -232,25 +238,48 @@ const normalLogin = async () => {
loading.value = true
apis
.login({ ...info.value } as unknown as User)
.then((token) => {
.then(async (token) => {
loginText.value = '登录成功, 正在跳转'
delay(async () => {
if (interruptLogin.value) return
login.value.accountInfo.token = token
//
// TODO iduiduid
const userDetail = await apis.getUserDetail()
const account = {
...userDetail,
uid: (userDetail as any).id,
token
}
loading.value = false
settingStore.setAccountInfo(account)
loginHistoriesStore.addLoginHistory(account)
//
await openHomeWindow()
}, 1000)
if (interruptLogin.value) return
userStore.isSign = true
login.value.accountInfo.token = token
// localStorage.setItem('USER_INFO', JSON.stringify(rest))
localStorage.setItem('TOKEN', token)
//
if (localStorage.getItem('wsLogin')) {
localStorage.removeItem('wsLogin')
}
// token.
computedToken.clear()
computedToken.get()
//
const userDetail = await apis.getUserDetail()
// 线
// groupStore.batchUpdateUserStatus([
// {
// activeStatus: OnlineEnum.ONLINE,
// avatar: rest.avatar,
// lastOptTime: Date.now(),
// name: rest.name,
// uid: rest.uid
// }
// ])
//
await chatStore.getSessionList(true)
//
await emojiStore.getEmojiList()
// TODO iduiduid
const account = {
...userDetail,
uid: (userDetail as any).id,
token
}
loading.value = false
settingStore.setAccountInfo(account)
loginHistoriesStore.addLoginHistory(account)
await setLoginState()
//
await openHomeWindow()
})
.catch(() => {
window.$message.error('登录失败')
@ -268,15 +297,14 @@ const autoLogin = () => {
loading.value = true
// TODO (nyh -> 2024-03-16 12:06:59)
loginText.value = '网络连接中'
// TODO 退tokencheckToken401
apis
.checkToken()
.then(() => {
window.$message.success('登录成功,正在跳转首页')
delay(async () => {
loading.value = false
await openHomeWindow()
await setLoginState()
}, 1000)
.then(async () => {
loginText.value = '登录成功, 正在跳转'
loading.value = false
await openHomeWindow()
await setLoginState()
})
.catch(() => {
window.$message.error('登录失败')
@ -317,13 +345,6 @@ const enterKey = (e: KeyboardEvent) => {
}
onMounted(async () => {
//
if (localStorage.getItem('isToQrcode')) {
router.push('/qrCode')
await nextTick(() => {
localStorage.removeItem('isToQrcode')
})
}
await getCurrentWebviewWindow().show()
//
if (login.value.autoLogin && login.value.accountInfo.token) {