mirror of
https://github.com/HuLaSpark/HuLa.git
synced 2026-10-24 23:23:38 +08:00
fix(view): 🐛 修复一些功能漏洞问题 (#38)
* fix(view): 🐛 修复打开独立窗口后主窗口消息窗口无法打开问题 * fix(service): 🐛 修复请求参数错误问题 * feat(view): ✨ 优化登录 增加账号密码登录功能 请求增加中断 优化自动登录 简化请求接口 --------- Co-authored-by: ZOL4789 <44133469+ZOL4789@users.noreply.github.com>
This commit is contained in:
committed by
nongyehong
co-authored by
ZOL4789
parent
06435c8d58
commit
f626a96c1a
+2
-2
@@ -1,7 +1,7 @@
|
||||
# 后端服务地址
|
||||
VITE_SERVICE_URL="https://hulaspark.com"
|
||||
VITE_SERVICE_URL="http://localhost:9190"
|
||||
# websocket服务地址
|
||||
VITE_WEBSOCKET_URL="wss://hulaspark.com/websocket"
|
||||
VITE_WEBSOCKET_URL="ws://localhost:8090/websocket"
|
||||
# 项目标题
|
||||
VITE_APP_TITLE="HuLa—IM"
|
||||
# 项目名称
|
||||
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "tauri:build:debug",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"label": "npm: tauri:build:debug",
|
||||
"detail": "tauri build --debug"
|
||||
}
|
||||
]
|
||||
}
|
||||
+6
-4
@@ -21,13 +21,15 @@ export enum RCodeEnum {
|
||||
/**URL*/
|
||||
export enum URLEnum {
|
||||
/**用户*/
|
||||
USER = '/api/user',
|
||||
USER = '/user',
|
||||
/**Token*/
|
||||
TOKEN = '/token',
|
||||
/**聊天*/
|
||||
CHAT = '/api/chat',
|
||||
CHAT = '/chat',
|
||||
/**房间*/
|
||||
ROOM = '/api/room',
|
||||
ROOM = '/room',
|
||||
/**oss*/
|
||||
OSS = '/api/oss'
|
||||
OSS = '/oss'
|
||||
}
|
||||
|
||||
/** tauri原生跨窗口通信时传输的类型 */
|
||||
|
||||
@@ -2,9 +2,13 @@ import { useWindow } from '@/hooks/useWindow.ts'
|
||||
import { MittEnum, ModalEnum, PluginEnum } from '@/enums'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { useLogin } from '@/hooks/useLogin.ts'
|
||||
import { useSettingStore } from '@/stores/setting.ts'
|
||||
import apis from '@/services/apis.ts'
|
||||
|
||||
const { createWebviewWindow } = useWindow()
|
||||
const { logout } = useLogin()
|
||||
const settingStore = useSettingStore()
|
||||
const { login } = storeToRefs(settingStore)
|
||||
/**
|
||||
* 这里的顶部的操作栏使用pinia写入了localstorage中
|
||||
*/
|
||||
@@ -89,7 +93,15 @@ const moreList = ref<OPT.L.MoreList[]>([
|
||||
label: '退出账号',
|
||||
icon: 'power',
|
||||
click: async () => {
|
||||
await logout()
|
||||
await apis
|
||||
.logout()
|
||||
.then(async () => {
|
||||
await logout()
|
||||
login.value.accountInfo.token = ''
|
||||
})
|
||||
.catch(() => {
|
||||
window.$message.error('退出账号失败')
|
||||
})
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface User {
|
||||
id: number
|
||||
name: string
|
||||
account: string
|
||||
password: string
|
||||
avatar: string
|
||||
sex: number
|
||||
openId: string
|
||||
activeStatus: number
|
||||
lastOptTime: string
|
||||
itemId: number
|
||||
status: number
|
||||
createTime: string
|
||||
updateTime: string
|
||||
}
|
||||
@@ -8,6 +8,11 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: 'login',
|
||||
component: () => import('@/views/loginWindow/Login.vue')
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
name: 'register',
|
||||
component: () => import('@/views/registerWindow/Register.vue')
|
||||
},
|
||||
{
|
||||
path: '/qrCode',
|
||||
name: 'qrCode',
|
||||
|
||||
+29
-8
@@ -22,10 +22,10 @@ import type {
|
||||
|
||||
import request from '@/services/request'
|
||||
|
||||
const GET = <T>(url: string, params?: any) => request.get<T>(url, params)
|
||||
const POST = <T>(url: string, params?: any) => request.post<T>(url, params)
|
||||
const PUT = <T>(url: string, params?: any) => request.put<T>(url, params)
|
||||
const DELETE = <T>(url: string, params?: any) => request.delete<T>(url, params)
|
||||
const GET = <T>(url: string, params?: any, abort?: AbortController) => request.get<T>(url, params, abort)
|
||||
const POST = <T>(url: string, params?: any, abort?: AbortController) => request.post<T>(url, params, abort)
|
||||
const PUT = <T>(url: string, params?: any, abort?: AbortController) => request.put<T>(url, params, abort)
|
||||
const DELETE = <T>(url: string, params?: any, abort?: AbortController) => request.delete<T>(url, params, abort)
|
||||
|
||||
export default {
|
||||
/** 获取用户信息 */
|
||||
@@ -67,9 +67,9 @@ export default {
|
||||
/** 删除id */
|
||||
deleteEmoji: (params: { id: number }) => DELETE<EmojiItem[]>(urls.deleteEmoji, params),
|
||||
/** 获取联系人列表 */
|
||||
getContactList: (params?: any) => GET<ListResponse<ContactItem>>(urls.getContactList, { params }),
|
||||
getContactList: (params?: any) => GET<ListResponse<ContactItem>>(urls.getContactList, params),
|
||||
/** 获取好友申请列表 */
|
||||
requestFriendList: (params?: any) => GET<ListResponse<RequestFriendItem>>(urls.requestFriendList, { params }),
|
||||
requestFriendList: (params?: any) => GET<ListResponse<RequestFriendItem>>(urls.requestFriendList, params),
|
||||
/** 发送添加好友请求 */
|
||||
sendAddFriendRequest: (params: { targetUid: number; msg: string }) =>
|
||||
POST<EmojiItem[]>(urls.sendAddFriendRequest, params),
|
||||
@@ -96,7 +96,7 @@ export default {
|
||||
/** 群组详情 */
|
||||
groupDetail: (params: { id: number }) => GET<GroupDetailReq>(urls.groupDetail, params),
|
||||
/** 会话详情 */
|
||||
sessionDetail: (params: { id: number }) => GET<SessionItem>(urls.sessionDetail, { params }),
|
||||
sessionDetail: (params: { id: number }) => GET<SessionItem>(urls.sessionDetail, params),
|
||||
/** 会话详情(联系人列表发消息用) */
|
||||
sessionDetailWithFriends: (params: { uid: number }) => GET<SessionItem>(urls.sessionDetailWithFriends, params),
|
||||
/** 添加群管理 */
|
||||
@@ -115,5 +115,26 @@ export default {
|
||||
exitGroup: ({ roomId }: { roomId: number }) =>
|
||||
DELETE<boolean>(urls.exitGroup, {
|
||||
roomId
|
||||
})
|
||||
}),
|
||||
/** 账号密码登录 */
|
||||
login: (user: User, abort?: AbortController) =>
|
||||
POST<string>(
|
||||
urls.login,
|
||||
{
|
||||
account: user.account,
|
||||
password: user.password
|
||||
},
|
||||
abort
|
||||
),
|
||||
/** 退出登录 */
|
||||
logout: (abort?: AbortController) => POST<string>(urls.logout, abort),
|
||||
/** 注册 */
|
||||
register: (user: User) =>
|
||||
POST<string>(urls.register, {
|
||||
name: user.name,
|
||||
account: user.account,
|
||||
password: user.password
|
||||
}),
|
||||
/** 检查token是否有效 */
|
||||
checkToken: () => POST<string>(urls.checkToken)
|
||||
}
|
||||
|
||||
@@ -24,12 +24,14 @@ export type HttpParams = {
|
||||
* @param {string} url 请求地址
|
||||
* @param {HttpParams} options 请求参数
|
||||
* @param {boolean} [fullResponse=false] 是否返回完整响应
|
||||
* @param {AbortController} abort 中断器
|
||||
* @returns {Promise<T | { data: Promise<T>; resp: Response }>} 请求结果
|
||||
*/
|
||||
async function Http<T>(
|
||||
url: string,
|
||||
options: HttpParams,
|
||||
fullResponse?: true
|
||||
fullResponse?: true,
|
||||
abort?: AbortController
|
||||
): Promise<{ data: Promise<T>; resp: Response }> {
|
||||
// 构建请求头
|
||||
const httpHeaders = new Headers(options.headers || {})
|
||||
@@ -37,7 +39,8 @@ async function Http<T>(
|
||||
// 构建 fetch 请求选项
|
||||
const fetchOptions: RequestInit = {
|
||||
method: options.method,
|
||||
headers: httpHeaders
|
||||
headers: httpHeaders,
|
||||
signal: abort?.signal
|
||||
}
|
||||
|
||||
// 判断是否需要添加请求体
|
||||
|
||||
+12
-11
@@ -26,7 +26,8 @@ const responseInterceptor = async <T>(
|
||||
url: string,
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
||||
query: any,
|
||||
body: any
|
||||
body: any,
|
||||
abort?: AbortController
|
||||
): Promise<T> => {
|
||||
const token = useSettingStore().login.accountInfo.token
|
||||
|
||||
@@ -54,11 +55,11 @@ const responseInterceptor = async <T>(
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await Http(url, httpParams, true)
|
||||
const data = await Http(url, httpParams, true, abort)
|
||||
|
||||
const resp = data.resp
|
||||
const serviceData = (await data.data) as ServiceResponse
|
||||
console.log(data)
|
||||
console.log(url, data)
|
||||
//检查发送请求是否成功
|
||||
if (resp.status > 400) {
|
||||
let message = ''
|
||||
@@ -116,20 +117,20 @@ const responseInterceptor = async <T>(
|
||||
}
|
||||
}
|
||||
|
||||
const get = async <T>(url: string, query: T): Promise<T> => {
|
||||
return responseInterceptor(url, 'GET', query, {})
|
||||
const get = async <T>(url: string, query: T, abort?: AbortController): Promise<T> => {
|
||||
return responseInterceptor(url, 'GET', query, {}, abort)
|
||||
}
|
||||
|
||||
const post = async <T>(url: string, params: any): Promise<T> => {
|
||||
return responseInterceptor(url, 'POST', {}, params)
|
||||
const post = async <T>(url: string, params: any, abort?: AbortController): Promise<T> => {
|
||||
return responseInterceptor(url, 'POST', {}, params, abort)
|
||||
}
|
||||
|
||||
const put = async <T>(url: string, params: any): Promise<T> => {
|
||||
return responseInterceptor(url, 'PUT', {}, params)
|
||||
const put = async <T>(url: string, params: any, abort?: AbortController): Promise<T> => {
|
||||
return responseInterceptor(url, 'PUT', {}, params, abort)
|
||||
}
|
||||
|
||||
const del = async <T>(url: string, params: any): Promise<T> => {
|
||||
return responseInterceptor(url, 'DELETE', {}, params)
|
||||
const del = async <T>(url: string, params: any, abort?: AbortController): Promise<T> => {
|
||||
return responseInterceptor(url, 'DELETE', {}, params, abort)
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -135,6 +135,10 @@ export type UserInfoType = {
|
||||
/** 用户唯一标识 */
|
||||
uid: number
|
||||
/** 用户头像 */
|
||||
account: string
|
||||
/** 用户头像 */
|
||||
password: string
|
||||
/** 用户头像 */
|
||||
avatar: string
|
||||
/** 用户名 */
|
||||
name: string
|
||||
|
||||
+12
-1
@@ -5,6 +5,7 @@ const { VITE_SERVICE_URL } = import.meta.env
|
||||
const prefix = VITE_SERVICE_URL
|
||||
|
||||
export default {
|
||||
// 用户相关
|
||||
getUserInfo: `${prefix + URLEnum.USER}/userInfo`, // 获取用户信息
|
||||
getBadgeList: `${prefix + URLEnum.USER}/badges`, // 获取徽章列表
|
||||
getMemberStatistic: `${prefix + URLEnum.CHAT}/public/member/statistic`,
|
||||
@@ -43,5 +44,15 @@ export default {
|
||||
revokeAdmin: `${prefix + URLEnum.ROOM}/group/admin`, // 添加管理员
|
||||
groupDetail: `${prefix + URLEnum.ROOM}/public/group`, // 群组详情
|
||||
sessionDetail: `${prefix + URLEnum.CHAT}/public/contact/detail`, // 会话详情
|
||||
sessionDetailWithFriends: `${prefix + URLEnum.CHAT}/public/contact/detail/friend` // 会话详情(联系人列表发消息用)
|
||||
sessionDetailWithFriends: `${prefix + URLEnum.CHAT}/public/contact/detail/friend`, // 会话详情(联系人列表发消息用)
|
||||
|
||||
// token相关
|
||||
// 注册
|
||||
register: `${prefix + URLEnum.TOKEN}/register`,
|
||||
// 登录
|
||||
login: `${prefix + URLEnum.TOKEN}/login`,
|
||||
// 退出登录
|
||||
logout: `${prefix + URLEnum.TOKEN}/logout`,
|
||||
// 检查token是否有效
|
||||
checkToken: `${prefix + URLEnum.TOKEN}/check`
|
||||
}
|
||||
|
||||
+2
-4
@@ -188,10 +188,8 @@ export const useChatStore = defineStore('chat', () => {
|
||||
sessionOptions.isLoading = true
|
||||
const response = await apis
|
||||
.getSessionList({
|
||||
params: {
|
||||
pageSize: sessionList.length > pageSize ? sessionList.length : pageSize,
|
||||
cursor: isFresh || !sessionOptions.cursor ? undefined : sessionOptions.cursor
|
||||
}
|
||||
pageSize: sessionList.length > pageSize ? sessionList.length : pageSize,
|
||||
cursor: isFresh || !sessionOptions.cursor ? '' : sessionOptions.cursor
|
||||
})
|
||||
.catch(() => {
|
||||
sessionOptions.isLoading = false
|
||||
|
||||
@@ -25,7 +25,7 @@ export const useContactStore = defineStore('contact', () => {
|
||||
.getContactList({
|
||||
// TODO 先写 100,稍后优化
|
||||
pageSize: 100,
|
||||
cursor: isFresh || !contactsOptions.cursor ? undefined : contactsOptions.cursor
|
||||
cursor: isFresh || !contactsOptions.cursor ? '' : contactsOptions.cursor
|
||||
})
|
||||
.catch(() => {
|
||||
contactsOptions.isLoading = false
|
||||
@@ -62,7 +62,7 @@ export const useContactStore = defineStore('contact', () => {
|
||||
const res = await apis
|
||||
.requestFriendList({
|
||||
pageSize,
|
||||
cursor: isFresh || !requestFriendsOptions.cursor ? undefined : requestFriendsOptions.cursor
|
||||
cursor: isFresh || !requestFriendsOptions.cursor ? '' : requestFriendsOptions.cursor
|
||||
})
|
||||
.catch(() => {
|
||||
requestFriendsOptions.isLoading = false
|
||||
|
||||
+3
-5
@@ -88,11 +88,9 @@ export const useGroupStore = defineStore('group', () => {
|
||||
// 获取群成员
|
||||
const getGroupUserList = async (refresh = false) => {
|
||||
const res = await apis.getGroupList({
|
||||
params: {
|
||||
pageSize,
|
||||
cursor: refresh ? undefined : userListOptions.cursor,
|
||||
roomId: currentRoomId.value
|
||||
}
|
||||
pageSize: pageSize,
|
||||
cursor: refresh ? '' : userListOptions.cursor,
|
||||
roomId: currentRoomId.value
|
||||
})
|
||||
if (!res) return
|
||||
const data = res
|
||||
|
||||
@@ -7,8 +7,8 @@ export const useLoginHistoriesStore = defineStore(
|
||||
() => {
|
||||
const loginHistories = ref<STO.Setting['login']['accountInfo'][]>([
|
||||
{
|
||||
account: 'hula',
|
||||
password: '123456',
|
||||
account: 'admin',
|
||||
password: 'admin',
|
||||
name: '超级GG帮',
|
||||
avatar: 'https://picsum.photos/140?1',
|
||||
uid: 123456,
|
||||
@@ -16,7 +16,7 @@ export const useLoginHistoriesStore = defineStore(
|
||||
},
|
||||
{
|
||||
account: 'hula1',
|
||||
password: '123456',
|
||||
password: 'hula1',
|
||||
name: '二狗子',
|
||||
avatar: 'https://picsum.photos/140?2',
|
||||
uid: 123456,
|
||||
@@ -24,7 +24,7 @@ export const useLoginHistoriesStore = defineStore(
|
||||
},
|
||||
{
|
||||
account: 'hula2',
|
||||
password: '123456',
|
||||
password: 'hula2',
|
||||
name: '李山离',
|
||||
avatar: 'https://picsum.photos/140?3',
|
||||
uid: 123456,
|
||||
@@ -32,7 +32,7 @@ export const useLoginHistoriesStore = defineStore(
|
||||
},
|
||||
{
|
||||
account: 'hula3',
|
||||
password: '123456',
|
||||
password: 'hula3',
|
||||
name: '牛什么呢',
|
||||
avatar: 'https://picsum.photos/140?4',
|
||||
uid: 123456,
|
||||
|
||||
Vendored
-2
@@ -36,7 +36,6 @@ declare module 'vue' {
|
||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||
NFlex: typeof import('naive-ui')['NFlex']
|
||||
NGradientText: typeof import('naive-ui')['NGradientText']
|
||||
NIcon: typeof import('naive-ui')['NIcon']
|
||||
NIconWrapper: typeof import('naive-ui')['NIconWrapper']
|
||||
NImage: typeof import('naive-ui')['NImage']
|
||||
@@ -60,7 +59,6 @@ declare module 'vue' {
|
||||
NTab: typeof import('naive-ui')['NTab']
|
||||
NTabPane: typeof import('naive-ui')['NTabPane']
|
||||
NTabs: typeof import('naive-ui')['NTabs']
|
||||
NText: typeof import('naive-ui')['NText']
|
||||
NTooltip: typeof import('naive-ui')['NTooltip']
|
||||
NVirtualList: typeof import('naive-ui')['NVirtualList']
|
||||
RenderMessage: typeof import('./../components/rightBox/renderMessage/index.vue')['default']
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<ActionBar :max-w="false" :shrink="false" />
|
||||
|
||||
<!-- 手动登录样式 -->
|
||||
<n-flex vertical :size="25" v-if="!isAutoLogin" data-tauri-drag-region>
|
||||
<n-flex vertical :size="25" v-if="!login.autoLogin || !login.accountInfo.token" data-tauri-drag-region>
|
||||
<!-- 头像 -->
|
||||
<n-flex justify="center" class="w-full pt-35px" data-tauri-drag-region>
|
||||
<img
|
||||
@@ -87,9 +87,9 @@
|
||||
:loading="loading"
|
||||
:disabled="loginDisabled"
|
||||
class="w-full mt-8px mb-50px"
|
||||
@click="loginWin"
|
||||
@click="normalLogin"
|
||||
color="#13987f">
|
||||
{{ loginText }}
|
||||
<span>{{ loginText }}</span>
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
@@ -99,7 +99,6 @@
|
||||
<n-flex justify="center" class="mt-15px">
|
||||
<img src="@/assets/logo/hula.png" class="w-140px h-60px" alt="" />
|
||||
</n-flex>
|
||||
|
||||
<n-flex :size="30" vertical>
|
||||
<!-- 头像 -->
|
||||
<n-flex justify="center">
|
||||
@@ -132,13 +131,17 @@
|
||||
<n-flex justify="center" class="text-14px" id="bottomBar" data-tauri-drag-region>
|
||||
<div class="color-#13987f cursor-pointer" @click="router.push('/qrCode')">扫码登录</div>
|
||||
<div class="w-1px h-14px bg-#ccc"></div>
|
||||
<div v-if="isAutoLogin" class="color-#13987f cursor-pointer">移除账号</div>
|
||||
<div v-if="login.autoLogin" class="color-#13987f cursor-pointer" @click="removeToken">移除账号</div>
|
||||
<n-popover v-else trigger="click" :show-checkmark="false" :show-arrow="false">
|
||||
<template #trigger>
|
||||
<div class="color-#13987f cursor-pointer">更多选项</div>
|
||||
</template>
|
||||
<n-flex vertical :size="2">
|
||||
<div class="text-14px cursor-pointer hover:bg-#f3f3f3 hover:rounded-6px p-8px">注册账号</div>
|
||||
<div
|
||||
class="text-14px cursor-pointer hover:bg-#f3f3f3 hover:rounded-6px p-8px"
|
||||
@click="router.push('/register')">
|
||||
注册账号
|
||||
</div>
|
||||
<div class="text-14px cursor-pointer hover:bg-#f3f3f3 hover:rounded-6px p-8px">忘记密码</div>
|
||||
</n-flex>
|
||||
</n-popover>
|
||||
@@ -154,6 +157,7 @@ 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'
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const loginHistoriesStore = useLoginHistoriesStore()
|
||||
@@ -167,6 +171,7 @@ const info = ref({
|
||||
name: '',
|
||||
uid: 0
|
||||
})
|
||||
|
||||
/** 是否中断登录 */
|
||||
const interruptLogin = ref(false)
|
||||
/** 协议 */
|
||||
@@ -174,7 +179,6 @@ const protocol = ref(true)
|
||||
const loginDisabled = ref(false)
|
||||
const loading = ref(false)
|
||||
const arrowStatus = ref(false)
|
||||
const isAutoLogin = ref(false)
|
||||
const { setLoginState } = useLogin()
|
||||
const accountPH = ref('输入HuLa账号')
|
||||
const passwordPH = ref('输入HuLa密码')
|
||||
@@ -190,6 +194,8 @@ watchEffect(() => {
|
||||
}
|
||||
if (interruptLogin.value) {
|
||||
loginDisabled.value = false
|
||||
loading.value = false
|
||||
interruptLogin.value = false
|
||||
}
|
||||
})
|
||||
|
||||
@@ -222,35 +228,61 @@ const giveAccount = (item: STO.Setting['login']['accountInfo']) => {
|
||||
}
|
||||
|
||||
/**登录后创建主页窗口*/
|
||||
const loginWin = () => {
|
||||
if (interruptLogin.value) return
|
||||
const normalLogin = async () => {
|
||||
loading.value = true
|
||||
delay(async () => {
|
||||
await createWebviewWindow('HuLa', 'home', 960, 720, 'login', true)
|
||||
loading.value = false
|
||||
if (!login.value.autoLogin || login.value.accountInfo.password === '') {
|
||||
const account = {
|
||||
...info.value,
|
||||
token: 'test'
|
||||
}
|
||||
settingStore.setAccountInfo(account)
|
||||
loginHistoriesStore.addLoginHistory(account)
|
||||
await setLoginState()
|
||||
}
|
||||
}, 1000)
|
||||
apis
|
||||
.login({ ...info.value } as unknown as User)
|
||||
.then((token) => {
|
||||
window.$message.success('登录成功,正在跳转首页')
|
||||
delay(async () => {
|
||||
if (interruptLogin.value) return
|
||||
login.value.accountInfo.token = token
|
||||
// 获取用户信息
|
||||
const userDetail = await apis.getUserDetail()
|
||||
const account = {
|
||||
...userDetail,
|
||||
token
|
||||
}
|
||||
loading.value = false
|
||||
settingStore.setAccountInfo(account)
|
||||
loginHistoriesStore.addLoginHistory(account)
|
||||
// 打开主界面
|
||||
await openHomeWindow()
|
||||
}, 1000)
|
||||
})
|
||||
.catch(() => {
|
||||
window.$message.error('登录失败')
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const openHomeWindow = async () => {
|
||||
await createWebviewWindow('HuLa', 'home', 960, 720, 'login', true)
|
||||
}
|
||||
|
||||
/** 自动登录 */
|
||||
const autoLogin = () => {
|
||||
interruptLogin.value = false
|
||||
isAutoLogin.value = true
|
||||
loading.value = true
|
||||
// TODO 检查用户网络是否连接 (nyh -> 2024-03-16 12:06:59)
|
||||
loginText.value = '网络连接中'
|
||||
delay(async () => {
|
||||
loginWin()
|
||||
loginText.value = '登录'
|
||||
await setLoginState()
|
||||
}, 1000)
|
||||
apis
|
||||
.checkToken()
|
||||
.then(() => {
|
||||
window.$message.success('登录成功,正在跳转首页')
|
||||
delay(async () => {
|
||||
loading.value = false
|
||||
await openHomeWindow()
|
||||
await setLoginState()
|
||||
}, 1000)
|
||||
})
|
||||
.catch(() => {
|
||||
window.$message.error('登录失败')
|
||||
login.value.accountInfo.token = ''
|
||||
router.push('/login')
|
||||
loading.value = false
|
||||
loginText.value = '登录'
|
||||
})
|
||||
}
|
||||
|
||||
const closeMenu = (event: MouseEvent) => {
|
||||
@@ -258,11 +290,30 @@ const closeMenu = (event: MouseEvent) => {
|
||||
if (!target.matches('.account-box, .account-box *, .down')) {
|
||||
arrowStatus.value = false
|
||||
}
|
||||
if (target.matches('#bottomBar *') && isAutoLogin.value) {
|
||||
if (target.matches('#bottomBar *') && login.value.autoLogin) {
|
||||
interruptLogin.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 移除已登录账号
|
||||
const removeToken = () => {
|
||||
login.value.accountInfo = {
|
||||
account: '',
|
||||
password: '',
|
||||
avatar: '/logo.png',
|
||||
name: '',
|
||||
uid: 0,
|
||||
token: ''
|
||||
}
|
||||
login.value.autoLogin = false
|
||||
}
|
||||
|
||||
const enterKey = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Enter') {
|
||||
normalLogin()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 判断是否需要马上跳转到二维码登录页面
|
||||
if (localStorage.getItem('isToQrcode')) {
|
||||
@@ -272,15 +323,19 @@ onMounted(async () => {
|
||||
})
|
||||
}
|
||||
await getCurrentWebviewWindow().show()
|
||||
if (login.value.autoLogin && login.value.accountInfo.password !== '') {
|
||||
// 自动登录
|
||||
if (login.value.autoLogin && login.value.accountInfo.token) {
|
||||
autoLogin()
|
||||
} else {
|
||||
loginHistories.length > 0 && giveAccount(loginHistories[0])
|
||||
}
|
||||
loginHistories.length > 0 && giveAccount(loginHistories[0])
|
||||
window.addEventListener('click', closeMenu, true)
|
||||
window.addEventListener('keyup', enterKey)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('click', closeMenu, true)
|
||||
window.removeEventListener('keyup', enterKey)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<n-flex justify="center" class="text-14px mt-48px" data-tauri-drag-region>
|
||||
<div class="color-#13987f cursor-pointer" @click="router.push('/login')">账密登录</div>
|
||||
<div class="w-1px h-14px bg-#ccc"></div>
|
||||
<div class="color-#13987f cursor-pointer">注册账号</div>
|
||||
<div class="color-#13987f cursor-pointer" @click="router.push('/register')">注册账号</div>
|
||||
</n-flex>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<!-- todo 这里设置了 data-tauri-drag-region但是有部分区域不可以拖动 -->
|
||||
<!-- 单独使用n-config-provider来包裹不需要主题切换的界面 -->
|
||||
<n-config-provider :theme="lightTheme" data-tauri-drag-region class="login-box size-full rounded-8px select-none">
|
||||
<!--顶部操作栏-->
|
||||
<ActionBar :max-w="false" :shrink="false" />
|
||||
|
||||
<!-- 手动登录样式 -->
|
||||
<n-flex vertical :size="25" data-tauri-drag-region>
|
||||
<!-- 头像 -->
|
||||
<n-flex justify="center" class="w-full pt-20px" data-tauri-drag-region>
|
||||
<img class="w-32px h-32px rounded-50% bg-#b6d6d9ff border-(2px solid #fff)" src="/logo.png" alt="" />
|
||||
</n-flex>
|
||||
|
||||
<!-- 登录菜单 -->
|
||||
<n-flex class="ma text-center h-full w-260px" vertical :size="16" data-tauri-drag-region>
|
||||
<n-input
|
||||
maxlength="16"
|
||||
minlength="6"
|
||||
size="large"
|
||||
v-model:value="info.name"
|
||||
type="text"
|
||||
:placeholder="namePH"
|
||||
@focus="namePH = ''"
|
||||
@blur="namePH = '输入HuLa昵称'"
|
||||
clearable />
|
||||
|
||||
<n-input
|
||||
size="large"
|
||||
maxlength="16"
|
||||
minlength="6"
|
||||
v-model:value="info.account"
|
||||
type="text"
|
||||
:placeholder="accountPH"
|
||||
@focus="accountPH = ''"
|
||||
@blur="accountPH = '输入HuLa账号'"
|
||||
clearable>
|
||||
</n-input>
|
||||
|
||||
<n-input
|
||||
maxlength="16"
|
||||
minlength="6"
|
||||
size="large"
|
||||
v-model:value="info.password"
|
||||
type="password"
|
||||
:placeholder="passwordPH"
|
||||
@focus="passwordPH = ''"
|
||||
@blur="passwordPH = '输入HuLa密码'"
|
||||
clearable />
|
||||
|
||||
<!-- 协议 -->
|
||||
<n-flex justify="center" :size="6">
|
||||
<n-checkbox v-model:checked="protocol" />
|
||||
<div class="text-12px color-#909090 cursor-default lh-14px">
|
||||
<span>已阅读并同意</span>
|
||||
<span class="color-#13987f cursor-pointer">服务协议</span>
|
||||
<span>和</span>
|
||||
<span class="color-#13987f cursor-pointer">HuLa隐私保护指引</span>
|
||||
</div>
|
||||
</n-flex>
|
||||
|
||||
<n-button
|
||||
:loading="loading"
|
||||
:disabled="btnEnable"
|
||||
class="w-full mt-8px mb-50px"
|
||||
@click="register"
|
||||
color="#13987f">
|
||||
{{ btnText }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<n-flex justify="center" class="text-14px" id="bottomBar" data-tauri-drag-region>
|
||||
<div class="color-#13987f cursor-pointer" @click="router.push('/login')">账号登录</div>
|
||||
<div class="w-1px h-14px bg-#ccc"></div>
|
||||
<div class="color-#13987f cursor-pointer" @click="router.push('/qrCode')">扫码登录</div>
|
||||
</n-flex>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import router from '@/router'
|
||||
import { lightTheme } from 'naive-ui'
|
||||
import apis from '@/services/apis.ts'
|
||||
|
||||
/** 账号信息 */
|
||||
const info = ref({
|
||||
account: '',
|
||||
password: '',
|
||||
name: ''
|
||||
})
|
||||
/** 是否中断登录 */
|
||||
const interruptLogin = ref(false)
|
||||
/** 协议 */
|
||||
const protocol = ref(true)
|
||||
const btnEnable = ref(false)
|
||||
const loading = ref(false)
|
||||
const namePH = ref('输入HuLa昵称')
|
||||
const accountPH = ref('输入HuLa账号')
|
||||
const passwordPH = ref('输入HuLa密码')
|
||||
/** 登录按钮的文本内容 */
|
||||
const btnText = ref('注册')
|
||||
|
||||
const register = async () => {
|
||||
interruptLogin.value = true
|
||||
loading.value = true
|
||||
btnText.value = '注册中...'
|
||||
// 注册
|
||||
await apis
|
||||
.register({ ...info.value } as User)
|
||||
.then(() => {
|
||||
window.$message.success('注册成功')
|
||||
btnText.value = '注册'
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
interruptLogin.value = false
|
||||
btnText.value = '注册'
|
||||
})
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
btnEnable.value = !(info.value.account && info.value.password && protocol.value)
|
||||
if (interruptLogin.value) {
|
||||
btnEnable.value = false
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(async () => {})
|
||||
|
||||
onUnmounted(() => {})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use '@/styles/scss/global/login-bg';
|
||||
@use '@/styles/scss/login';
|
||||
</style>
|
||||
+1
-1
@@ -96,7 +96,7 @@ export default defineConfig(({ mode }: ConfigEnv) => {
|
||||
// “/api” 以及前置字符串会被替换为真正域名
|
||||
target: config.VITE_SERVICE_URL, // 请求域名
|
||||
changeOrigin: true, // 是否跨域
|
||||
rewrite: (path) => path.replace(/^\/api/, '/api')
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
}
|
||||
},
|
||||
hmr: true, // 热更新
|
||||
|
||||
Reference in New Issue
Block a user