diff --git a/shared/api/buildStorage.ts b/shared/api/buildStorage.ts index 5ff39756..de4de5c9 100644 --- a/shared/api/buildStorage.ts +++ b/shared/api/buildStorage.ts @@ -1,6 +1,7 @@ import 'regenerator-runtime/runtime'; // react-native-storage 需要, 确保其存在 import Storage, { NotFoundError } from 'react-native-storage'; import _isNil from 'lodash/isNil'; +import _isUndefined from 'lodash/isUndefined'; /** * 构建一个存储对象 @@ -36,7 +37,7 @@ export function buildStorage(backend: any) { const rnStorage = { set: async (key: string, data: any) => { try { - if (!!key && typeof key === 'string' && !_isNil(data)) { + if (!!key && typeof key === 'string' && !_isUndefined(data)) { await storage.save({ key, data }); } } catch (e) { @@ -51,7 +52,7 @@ export function buildStorage(backend: any) { */ setWithExpires: async (key: string, data: any, expires: number) => { try { - if (!!key && typeof key === 'string' && !_isNil(data)) { + if (!!key && typeof key === 'string' && !_isUndefined(data)) { await storage.save({ key, data, expires }); } } catch (e) { @@ -83,11 +84,10 @@ export function buildStorage(backend: any) { }, /** * 持久化存储, 永不过期 - * TODO: 移除key允许为对象的写法 */ save: async (key: string, data: any) => { try { - if (!!key && typeof key === 'string' && !_isNil(data)) { + if (!!key && typeof key === 'string' && !_isUndefined(data)) { await storage.save({ key, data, diff --git a/shared/i18n/langs/en-US/translation.json b/shared/i18n/langs/en-US/translation.json index 3c44affd..b6df8556 100644 --- a/shared/i18n/langs/en-US/translation.json +++ b/shared/i18n/langs/en-US/translation.json @@ -16,6 +16,7 @@ "k3c7c48f8": "Invite not found", "k3f3597fc": "All", "k42a44318": "Joined", + "k42a98418": "File Service", "k4603baea": "Create Group Panel", "k47489688": "Group Service", "k4d32a754": "Group Name", @@ -71,6 +72,7 @@ "kdd4c838c": "Jump to Group", "kdd6c18f8": "Service exception", "ked5385d5": "Create Panel", + "kf15499b4": "Logout", "kf1eac01c": "Failed to load group information", "kf48ae58": "Group information not found", "kf5d66247": "Panel Name", diff --git a/shared/i18n/langs/zh-CN/translation.json b/shared/i18n/langs/zh-CN/translation.json index 7a631d31..a2f532af 100644 --- a/shared/i18n/langs/zh-CN/translation.json +++ b/shared/i18n/langs/zh-CN/translation.json @@ -16,6 +16,7 @@ "k3c7c48f8": "找不到邀请信息", "k3f3597fc": "全员", "k42a44318": "已加入", + "k42a98418": "文件服务", "k4603baea": "创建群组面板", "k47489688": "群组服务", "k4d32a754": "群组名称", @@ -71,6 +72,7 @@ "kdd4c838c": "跳转到群组", "kdd6c18f8": "服务异常", "ked5385d5": "创建面板", + "kf15499b4": "退出登录", "kf1eac01c": "群组信息加载失败", "kf48ae58": "找不到群组信息", "kf5d66247": "面板名", diff --git a/web/src/components/modals/SettingsView/Account.tsx b/web/src/components/modals/SettingsView/Account.tsx index 3792bbdf..af48a4f5 100644 --- a/web/src/components/modals/SettingsView/Account.tsx +++ b/web/src/components/modals/SettingsView/Account.tsx @@ -4,7 +4,10 @@ import { DefaultFullModalInputEditorRender, FullModalField, } from '@/components/FullModal/Field'; -import React from 'react'; +import { getUserJWT, setUserJWT } from '@/utils/jwt-helper'; +import { Button, Divider } from 'antd'; +import React, { useCallback } from 'react'; +import { useHistory } from 'react-router'; import { modifyUserField, showToasts, @@ -19,6 +22,7 @@ import { export const SettingsAccount: React.FC = React.memo(() => { const userInfo = useUserInfo(); const dispatch = useAppDispatch(); + const history = useHistory(); const [, handleUserAvatarChange] = useAsyncRequest( async (fileInfo: UploadFileResult) => { @@ -48,25 +52,40 @@ export const SettingsAccount: React.FC = React.memo(() => { [] ); + // 登出 + const handleLogout = useCallback(async () => { + await setUserJWT(null); + history.push('/'); + }, []); + if (!userInfo) { return null; } return ( -