fix(view): 🐛 修复一些功能漏洞问题 (#38)

* fix(view): 🐛 修复打开独立窗口后主窗口消息窗口无法打开问题

* fix(service): 🐛 修复请求参数错误问题

* feat(view): ✨ 优化登录

增加账号密码登录功能
请求增加中断
优化自动登录
简化请求接口

---------

Co-authored-by: ZOL4789 <44133469+ZOL4789@users.noreply.github.com>
This commit is contained in:
Dawn
2024-11-16 02:19:11 +08:00
committed by nongyehong
co-authored by ZOL4789
parent 06435c8d58
commit f626a96c1a
20 changed files with 354 additions and 80 deletions
+2 -2
View File
@@ -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"
# 项目名称
+13
View File
@@ -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
View File
@@ -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原生跨窗口通信时传输的类型 */
+13 -1
View File
@@ -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('退出账号失败')
})
}
}
])
+16
View File
@@ -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
}
+5
View File
@@ -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
View File
@@ -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)
}
+5 -2
View File
@@ -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
View File
@@ -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 {
+4
View File
@@ -135,6 +135,10 @@ export type UserInfoType = {
/** 用户唯一标识 */
uid: number
/** 用户头像 */
account: string
/** 用户头像 */
password: string
/** 用户头像 */
avatar: string
/** 用户名 */
name: string
+12 -1
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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
View File
@@ -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
+5 -5
View File
@@ -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,
-2
View File
@@ -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']
+86 -31
View File
@@ -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>
+1 -1
View File
@@ -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>
+137
View File
@@ -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
View File
@@ -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, // 热更新