优化
This commit is contained in:
9
client/shared/model/__all__.ts
Normal file
9
client/shared/model/__all__.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export * as common from './common';
|
||||
export * as config from './config';
|
||||
export * as converse from './converse';
|
||||
export * as friend from './friend';
|
||||
export * as group from './group';
|
||||
export * as message from './message';
|
||||
export * as plugin from './plugin';
|
||||
export * as user from './user';
|
||||
export * as inbox from './inbox';
|
||||
19
client/shared/model/common.ts
Normal file
19
client/shared/model/common.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { request } from '../api/request';
|
||||
import { buildCachedRequest } from '../cache/utils';
|
||||
|
||||
/**
|
||||
* 获取可用的微服务列表
|
||||
*/
|
||||
export const fetchAvailableServices = buildCachedRequest(
|
||||
'fetchAvailableServices',
|
||||
async (): Promise<string[]> => {
|
||||
const { data } = await request.get<{
|
||||
nodeID: string;
|
||||
cpu: unknown;
|
||||
memory: unknown;
|
||||
services: string[];
|
||||
}>('/api/gateway/health');
|
||||
|
||||
return data.services;
|
||||
}
|
||||
);
|
||||
94
client/shared/model/config.ts
Normal file
94
client/shared/model/config.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { request } from '../api/request';
|
||||
import { useGlobalConfigStore } from '../store/globalConfig';
|
||||
import { defaultGlobalConfig } from '../utils/consts';
|
||||
|
||||
/**
|
||||
* 后端的全局设置
|
||||
*/
|
||||
export interface GlobalConfig {
|
||||
/**
|
||||
* Tianji 配置
|
||||
*/
|
||||
tianji: {
|
||||
scriptUrl?: string;
|
||||
websiteId?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* 上传文件体积
|
||||
* 默认1m
|
||||
*/
|
||||
uploadFileLimit: number;
|
||||
/**
|
||||
* 是否在注册时校验邮箱
|
||||
*/
|
||||
emailVerification: boolean;
|
||||
|
||||
/**
|
||||
* 服务器名
|
||||
*/
|
||||
serverName?: string;
|
||||
|
||||
/**
|
||||
* 服务器入口背景图
|
||||
*/
|
||||
serverEntryImage?: string;
|
||||
|
||||
/**
|
||||
* 是否禁用 Socketio 的 Msgpack 解析器
|
||||
*/
|
||||
disableMsgpack?: boolean;
|
||||
|
||||
/**
|
||||
* 是否禁用注册功能
|
||||
*/
|
||||
disableUserRegister?: boolean;
|
||||
|
||||
/**
|
||||
* 是否禁用游客登录
|
||||
*/
|
||||
disableGuestLogin?: boolean;
|
||||
|
||||
/**
|
||||
* 是否禁用创建群组功能
|
||||
*/
|
||||
disableCreateGroup?: boolean;
|
||||
|
||||
/**
|
||||
* 是否禁用插件中心
|
||||
*/
|
||||
disablePluginStore?: boolean;
|
||||
|
||||
/**
|
||||
* 是否禁用添加好友功能
|
||||
*/
|
||||
disableAddFriend?: boolean;
|
||||
|
||||
/**
|
||||
* 是否禁用遥测
|
||||
*/
|
||||
disableTelemetry?: boolean;
|
||||
|
||||
announcement?:
|
||||
| false
|
||||
| {
|
||||
id: string;
|
||||
text: string;
|
||||
link?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function getGlobalConfig(): GlobalConfig {
|
||||
return useGlobalConfigStore.getState();
|
||||
}
|
||||
|
||||
export async function fetchGlobalClientConfig(): Promise<GlobalConfig> {
|
||||
const { data: config } = await request.get('/api/config/client');
|
||||
|
||||
useGlobalConfigStore.setState({
|
||||
...defaultGlobalConfig,
|
||||
...config,
|
||||
});
|
||||
|
||||
return config;
|
||||
}
|
||||
144
client/shared/model/converse.ts
Normal file
144
client/shared/model/converse.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { request } from '../api/request';
|
||||
import {
|
||||
createAutoMergedRequest,
|
||||
createAutoSplitRequest,
|
||||
} from '../utils/request';
|
||||
import _uniq from 'lodash/uniq';
|
||||
import _flatten from 'lodash/flatten';
|
||||
import _zipObject from 'lodash/zipObject';
|
||||
|
||||
export enum ChatConverseType {
|
||||
DM = 'DM', // 单人会话
|
||||
Multi = 'Multi', // 多人会话
|
||||
Group = 'Group', // 群组会话(暂时无用)
|
||||
}
|
||||
|
||||
export interface ChatConverseInfo {
|
||||
_id: string;
|
||||
name: string;
|
||||
type: ChatConverseType;
|
||||
members: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试创建私聊会话
|
||||
* 如果已创建则返回之前的
|
||||
*/
|
||||
export async function createDMConverse(
|
||||
memberIds: string[]
|
||||
): Promise<ChatConverseInfo> {
|
||||
const { data } = await request.post('/api/chat/converse/createDMConverse', {
|
||||
memberIds,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在多人会话中添加成员
|
||||
*/
|
||||
export async function appendDMConverseMembers(
|
||||
converseId: string,
|
||||
memberIds: string[]
|
||||
) {
|
||||
const { data } = await request.post(
|
||||
'/api/chat/converse/appendDMConverseMembers',
|
||||
{
|
||||
converseId,
|
||||
memberIds,
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会话信息
|
||||
* @param converseId 会话ID
|
||||
*/
|
||||
export async function fetchConverseInfo(
|
||||
converseId: string
|
||||
): Promise<ChatConverseInfo> {
|
||||
const { data } = await request.get('/api/chat/converse/findConverseInfo', {
|
||||
params: {
|
||||
converseId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会话已读
|
||||
* @param converseId 会话ID
|
||||
* @param lastMessageId 最后一条消息ID
|
||||
*/
|
||||
export async function updateAck(converseId: string, lastMessageId: string) {
|
||||
await request.post('/api/chat/ack/update', { converseId, lastMessageId });
|
||||
}
|
||||
|
||||
interface AckInfo {
|
||||
userId: string;
|
||||
converseId: string;
|
||||
lastMessageId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户存储在远程的会话信息
|
||||
*/
|
||||
export async function fetchUserAck(): Promise<AckInfo[]> {
|
||||
const { data } = await request.get('/api/chat/ack/all');
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户存储在远程的会话信息
|
||||
*/
|
||||
export async function fetchUserAckList(
|
||||
converseIds: string[]
|
||||
): Promise<(AckInfo | null)[]> {
|
||||
const { data } = await request.post('/api/chat/ack/list', {
|
||||
converseIds,
|
||||
});
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const _fetchConverseAckInfo = createAutoMergedRequest<
|
||||
string[],
|
||||
(AckInfo | null)[]
|
||||
>(
|
||||
createAutoSplitRequest(
|
||||
async (converseIdsList) => {
|
||||
const uniqList = _uniq(_flatten(converseIdsList));
|
||||
const infoList = await fetchUserAckList(uniqList);
|
||||
|
||||
const map = _zipObject<AckInfo | null>(uniqList, infoList);
|
||||
|
||||
// 将请求结果根据传输来源重新分组
|
||||
return converseIdsList.map((converseIds) =>
|
||||
converseIds.map((converseId) => map[converseId] ?? null)
|
||||
);
|
||||
},
|
||||
'serial',
|
||||
100
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* 获取会话信息
|
||||
*/
|
||||
export async function getConverseAckInfo(
|
||||
converseIds: string[]
|
||||
): Promise<(AckInfo | null)[]> {
|
||||
return _fetchConverseAckInfo(converseIds);
|
||||
}
|
||||
74
client/shared/model/friend.ts
Normal file
74
client/shared/model/friend.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { request } from '../api/request';
|
||||
|
||||
export interface FriendRequest {
|
||||
_id: string;
|
||||
from: string;
|
||||
to: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送好友请求
|
||||
* @param targetId 目标用户id
|
||||
*/
|
||||
export async function addFriendRequest(
|
||||
targetId: string
|
||||
): Promise<FriendRequest> {
|
||||
const { data } = await request.post('/api/friend/request/add', {
|
||||
to: targetId,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同意好友请求
|
||||
* @param requestId 好友请求ID
|
||||
*/
|
||||
export async function acceptFriendRequest(requestId: string): Promise<void> {
|
||||
await request.post('/api/friend/request/accept', {
|
||||
requestId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝好友请求
|
||||
* @param requestId 好友请求ID
|
||||
*/
|
||||
export async function denyFriendRequest(requestId: string): Promise<void> {
|
||||
await request.post('/api/friend/request/deny', {
|
||||
requestId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消好友请求
|
||||
* @param requestId 好友请求ID
|
||||
*/
|
||||
export async function cancelFriendRequest(requestId: string): Promise<void> {
|
||||
await request.post('/api/friend/request/cancel', {
|
||||
requestId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除好友(单项)
|
||||
*/
|
||||
export async function removeFriend(friendUserId: string): Promise<void> {
|
||||
await request.post('/api/friend/removeFriend', {
|
||||
friendUserId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置好友昵称
|
||||
*/
|
||||
export async function setFriendNickname(
|
||||
targetId: string,
|
||||
nickname: string
|
||||
): Promise<void> {
|
||||
await request.post('/api/friend/setFriendNickname', {
|
||||
targetId,
|
||||
nickname,
|
||||
});
|
||||
}
|
||||
480
client/shared/model/group.ts
Normal file
480
client/shared/model/group.ts
Normal file
@@ -0,0 +1,480 @@
|
||||
import { request } from '../api/request';
|
||||
import {
|
||||
GroupPanelType,
|
||||
GroupPanel,
|
||||
GroupRole,
|
||||
GroupInfo as IGroupInfo,
|
||||
GroupBasicInfo,
|
||||
GroupInvite,
|
||||
} from 'tailchat-types';
|
||||
|
||||
export { GroupPanelType };
|
||||
export type { GroupPanel, GroupRole, GroupBasicInfo, GroupInvite };
|
||||
|
||||
export const groupConfigNames = [
|
||||
// 隐藏群组成员标识位
|
||||
'hideGroupMemberDiscriminator',
|
||||
|
||||
// 禁止从群组中发起私信
|
||||
'disableCreateConverseFromGroup',
|
||||
|
||||
// 群组背景图
|
||||
'groupBackgroundImage',
|
||||
] as const;
|
||||
|
||||
export type GroupConfigNames = (typeof groupConfigNames)[number] | string; // string is plugin config
|
||||
|
||||
export interface GroupMember {
|
||||
roles: string[]; // 角色组
|
||||
userId: string;
|
||||
/**
|
||||
* 日期字符串 禁言到xxx
|
||||
*/
|
||||
muteUntil?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 群组面板特性
|
||||
*/
|
||||
export type GroupPanelFeature =
|
||||
| 'subscribe' // 订阅事件变更状态,用于加入socket.io群组
|
||||
| 'ack'; // 是否包含已读未读检查,如果包含的话需要同时开启 subscribe 特性
|
||||
|
||||
export interface GroupInfo extends Omit<IGroupInfo, 'config'> {
|
||||
config?: Partial<Record<GroupConfigNames, any>>;
|
||||
pinnedPanelId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群组设置信息
|
||||
*/
|
||||
export function getGroupConfigWithInfo(
|
||||
groupInfo: GroupInfo | null | undefined
|
||||
): {
|
||||
hideGroupMemberDiscriminator: boolean;
|
||||
disableCreateConverseFromGroup: boolean;
|
||||
[key: string]: unknown;
|
||||
} {
|
||||
const config = groupInfo?.config ?? {};
|
||||
|
||||
return {
|
||||
...config,
|
||||
hideGroupMemberDiscriminator: config.hideGroupMemberDiscriminator ?? false,
|
||||
disableCreateConverseFromGroup:
|
||||
config.disableCreateConverseFromGroup ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建群组
|
||||
* @param name 群组名
|
||||
* @param panels 初始面板
|
||||
*/
|
||||
export async function createGroup(
|
||||
name: string,
|
||||
panels: GroupPanel[]
|
||||
): Promise<GroupInfo> {
|
||||
const { data } = await request.post('/api/group/createGroup', {
|
||||
name,
|
||||
panels,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群组基本信息
|
||||
*/
|
||||
export async function getGroupBasicInfo(
|
||||
groupId: string
|
||||
): Promise<GroupBasicInfo | null> {
|
||||
const { data } = await request.get('/api/group/getGroupBasicInfo', {
|
||||
params: {
|
||||
groupId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改群组属性
|
||||
* @param groupId 群组ID
|
||||
* @param fieldName 要修改的群组属性
|
||||
* @param fieldValue 要修改的属性的值
|
||||
*/
|
||||
type AllowedModifyField =
|
||||
| 'name'
|
||||
| 'avatar'
|
||||
| 'description'
|
||||
| 'panels'
|
||||
| 'roles'
|
||||
| 'fallbackPermissions';
|
||||
export async function modifyGroupField(
|
||||
groupId: string,
|
||||
fieldName: AllowedModifyField,
|
||||
fieldValue: unknown
|
||||
) {
|
||||
await request.post('/api/group/updateGroupField', {
|
||||
groupId,
|
||||
fieldName,
|
||||
fieldValue,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改群组配置
|
||||
* @param groupId 群组ID
|
||||
* @param configName 要修改的群组属性
|
||||
* @param configValue 要修改的属性的值
|
||||
*/
|
||||
export async function modifyGroupConfig(
|
||||
groupId: string,
|
||||
configName: GroupConfigNames,
|
||||
configValue: unknown
|
||||
) {
|
||||
await request.post('/api/group/updateGroupConfig', {
|
||||
groupId,
|
||||
configName,
|
||||
configValue,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出群组(群组拥有者是解散群组)
|
||||
* 这里必须是一个socket请求因为后端需要进行房间的退出操作
|
||||
* @param groupId 群组ID
|
||||
*/
|
||||
export async function quitGroup(groupId: string) {
|
||||
await request.post('/api/group/quitGroup', {
|
||||
groupId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前用户是否是群组成员
|
||||
* @param groupId 群组ID
|
||||
*/
|
||||
export async function isMember(groupId: string): Promise<boolean> {
|
||||
const { data } = await request.post('/api/group/isMember', {
|
||||
groupId,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户所在的权限组
|
||||
* @param groupId 群组ID
|
||||
* @param memberIds 成员信息
|
||||
* @param roles 权限组名
|
||||
*/
|
||||
export async function appendGroupMemberRoles(
|
||||
groupId: string,
|
||||
memberIds: string[],
|
||||
roles: string[]
|
||||
) {
|
||||
await request.post('/api/group/appendGroupMemberRoles', {
|
||||
groupId,
|
||||
memberIds,
|
||||
roles,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户所在的权限组
|
||||
* @param groupId 群组ID
|
||||
* @param memberIds 成员信息
|
||||
* @param roles 权限组名
|
||||
*/
|
||||
export async function removeGroupMemberRoles(
|
||||
groupId: string,
|
||||
memberIds: string[],
|
||||
roles: string[]
|
||||
) {
|
||||
await request.post('/api/group/removeGroupMemberRoles', {
|
||||
groupId,
|
||||
memberIds,
|
||||
roles,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建群组邀请码
|
||||
* 邀请码默认 7天有效期
|
||||
* @param groupId 群组id
|
||||
*/
|
||||
export async function createGroupInviteCode(
|
||||
groupId: string,
|
||||
inviteType: 'normal' | 'permanent'
|
||||
): Promise<GroupInvite> {
|
||||
const { data } = await request.post('/api/group/invite/createGroupInvite', {
|
||||
groupId,
|
||||
inviteType,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑群组邀请链接
|
||||
* @param groupId 群组ID
|
||||
* @param code 邀请码
|
||||
* @param expiredAt 过期时间,是一个时间戳,单位ms,为undefined则为不限制
|
||||
* @param usageLimit 最大使用次数,为undefined则不限制
|
||||
*/
|
||||
export async function editGroupInvite(
|
||||
groupId: string,
|
||||
code: string,
|
||||
expiredAt?: number,
|
||||
usageLimit?: number
|
||||
) {
|
||||
await request.post('/api/group/invite/editGroupInvite', {
|
||||
groupId,
|
||||
code,
|
||||
expiredAt,
|
||||
usageLimit,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群组所有邀请码
|
||||
* @param groupId 群组ID
|
||||
*/
|
||||
export async function getAllGroupInviteCode(
|
||||
groupId: string
|
||||
): Promise<GroupInvite[]> {
|
||||
const { data } = await request.get(
|
||||
'/api/group/invite/getAllGroupInviteCode',
|
||||
{
|
||||
params: {
|
||||
groupId,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据邀请码查找邀请信息
|
||||
* @param inviteCode 邀请码
|
||||
*/
|
||||
export async function findGroupInviteByCode(
|
||||
inviteCode: string
|
||||
): Promise<GroupInvite | null> {
|
||||
const { data } = await request.get('/api/group/invite/findInviteByCode', {
|
||||
params: {
|
||||
code: inviteCode,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用群组邀请
|
||||
* 即通过群组邀请加入群组
|
||||
*/
|
||||
export async function applyGroupInvite(inviteCode: string): Promise<void> {
|
||||
await request.post('/api/group/invite/applyInvite', {
|
||||
code: inviteCode,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除群组邀请
|
||||
*/
|
||||
export async function deleteGroupInvite(
|
||||
groupId: string,
|
||||
inviteId: string
|
||||
): Promise<void> {
|
||||
await request.post('/api/group/invite/deleteInvite', {
|
||||
groupId,
|
||||
inviteId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建群组面板
|
||||
*/
|
||||
export async function createGroupPanel(
|
||||
groupId: string,
|
||||
options: {
|
||||
name: string;
|
||||
type: number;
|
||||
parentId?: string;
|
||||
provider?: string;
|
||||
pluginPanelName?: string;
|
||||
meta?: Record<string, unknown>;
|
||||
}
|
||||
) {
|
||||
await request.post('/api/group/createGroupPanel', {
|
||||
...options,
|
||||
groupId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建群组面板
|
||||
*/
|
||||
export async function modifyGroupPanel(
|
||||
groupId: string,
|
||||
panelId: string,
|
||||
options: {
|
||||
name: string;
|
||||
type: number;
|
||||
parentId?: string;
|
||||
provider?: string;
|
||||
pluginPanelName?: string;
|
||||
meta?: Record<string, unknown>;
|
||||
}
|
||||
) {
|
||||
await request.post('/api/group/modifyGroupPanel', {
|
||||
...options,
|
||||
groupId,
|
||||
panelId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除群组面板
|
||||
* @param groupId 群组Id
|
||||
* @param panelId 面板Id
|
||||
*/
|
||||
export async function deleteGroupPanel(groupId: string, panelId: string) {
|
||||
await request.post('/api/group/deleteGroupPanel', {
|
||||
groupId,
|
||||
panelId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建群组身份组
|
||||
* @param groupId 群组id
|
||||
* @param roleName 群组名
|
||||
* @param permissions 初始权限
|
||||
*/
|
||||
export async function createGroupRole(
|
||||
groupId: string,
|
||||
roleName: string,
|
||||
permissions: string[]
|
||||
) {
|
||||
await request.post('/api/group/createGroupRole', {
|
||||
groupId,
|
||||
roleName,
|
||||
permissions,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除群组身份组
|
||||
* @param groupId 群组Id
|
||||
* @param roleId 身份组Id
|
||||
*/
|
||||
export async function deleteGroupRole(groupId: string, roleId: string) {
|
||||
await request.post('/api/group/deleteGroupRole', {
|
||||
groupId,
|
||||
roleId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除群组身份组
|
||||
* @param groupId 群组Id
|
||||
* @param roleId 身份组Id
|
||||
* @param roleName 新身份组名
|
||||
*/
|
||||
export async function updateGroupRoleName(
|
||||
groupId: string,
|
||||
roleId: string,
|
||||
roleName: string
|
||||
) {
|
||||
await request.post('/api/group/updateGroupRoleName', {
|
||||
groupId,
|
||||
roleId,
|
||||
roleName,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除群组身份组
|
||||
* @param groupId 群组Id
|
||||
* @param roleId 身份组Id
|
||||
* @param permissions 全量权限列表
|
||||
*/
|
||||
export async function updateGroupRolePermission(
|
||||
groupId: string,
|
||||
roleId: string,
|
||||
permissions: string[]
|
||||
) {
|
||||
await request.post('/api/group/updateGroupRolePermission', {
|
||||
groupId,
|
||||
roleId,
|
||||
permissions,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁言群组成员
|
||||
* @param groupId 群组ID
|
||||
* @param memberId 成员ID
|
||||
* @param muteMs 禁言到xxx, 精确到毫秒
|
||||
*/
|
||||
export async function muteGroupMember(
|
||||
groupId: string,
|
||||
memberId: string,
|
||||
muteMs: number
|
||||
) {
|
||||
await request.post('/api/group/muteGroupMember', {
|
||||
groupId,
|
||||
memberId,
|
||||
muteMs,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 移出群组成员
|
||||
* @param groupId 群组ID
|
||||
* @param memberId 成员ID
|
||||
*/
|
||||
export async function deleteGroupMember(groupId: string, memberId: string) {
|
||||
await request.post('/api/group/deleteGroupMember', {
|
||||
groupId,
|
||||
memberId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Group Panel Data from group.extra service
|
||||
*/
|
||||
export async function getGroupPanelExtraData(
|
||||
groupId: string,
|
||||
panelId: string,
|
||||
name: string
|
||||
): Promise<string | null> {
|
||||
const { data } = await request.post('/api/group/extra/getPanelData', {
|
||||
groupId,
|
||||
panelId,
|
||||
name,
|
||||
});
|
||||
|
||||
return data.data ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Group Panel Data to group.extra service
|
||||
*/
|
||||
export async function saveGroupPanelExtraData(
|
||||
groupId: string,
|
||||
panelId: string,
|
||||
name: string,
|
||||
data: any
|
||||
): Promise<void> {
|
||||
await request.post('/api/group/extra/savePanelData', {
|
||||
groupId,
|
||||
panelId,
|
||||
name,
|
||||
data: typeof data === 'string' ? data : JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
23
client/shared/model/inbox.ts
Normal file
23
client/shared/model/inbox.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { request } from '../api/request';
|
||||
export type {
|
||||
BasicInboxItem,
|
||||
MessageInboxItem,
|
||||
MarkdownInboxItem,
|
||||
InboxItem,
|
||||
} from 'tailchat-types';
|
||||
|
||||
/**
|
||||
* 设置收件箱某条记录已读
|
||||
*/
|
||||
export async function setInboxAck(inboxItemIds: string[]) {
|
||||
await request.post('/api/chat/inbox/ack', {
|
||||
inboxItemIds,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空收件箱
|
||||
*/
|
||||
export async function clearInbox() {
|
||||
await request.post('/api/chat/inbox/clear');
|
||||
}
|
||||
204
client/shared/model/message.ts
Normal file
204
client/shared/model/message.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
import { request } from '../api/request';
|
||||
import type { ChatMessageReaction, ChatMessage } from 'tailchat-types';
|
||||
import {
|
||||
createAutoMergedRequest,
|
||||
createAutoSplitRequest,
|
||||
} from '../utils/request';
|
||||
import _uniq from 'lodash/uniq';
|
||||
import _flatten from 'lodash/flatten';
|
||||
import _zipObject from 'lodash/zipObject';
|
||||
|
||||
export { ChatMessageReaction, ChatMessage };
|
||||
|
||||
export interface LocalChatMessage extends ChatMessage {
|
||||
/**
|
||||
* 本地添加消息的标识,用于标记该条消息尚未确定已经发送到服务端
|
||||
*/
|
||||
isLocal?: boolean;
|
||||
/**
|
||||
* 判断是否发送失败
|
||||
*/
|
||||
sendFailed?: boolean;
|
||||
}
|
||||
|
||||
export interface SimpleMessagePayload {
|
||||
groupId?: string;
|
||||
converseId: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface SendMessagePayloadMeta {
|
||||
mentions?: string[];
|
||||
}
|
||||
|
||||
export interface SendMessagePayload extends SimpleMessagePayload {
|
||||
/**
|
||||
* content的plain内容
|
||||
* 用于inbox
|
||||
*/
|
||||
plain?: string;
|
||||
meta?: SendMessagePayloadMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会话消息
|
||||
* @param converseId 会话ID
|
||||
* @param startId 开始ID
|
||||
*/
|
||||
export async function fetchConverseMessage(
|
||||
converseId: string,
|
||||
startId?: string
|
||||
): Promise<ChatMessage[]> {
|
||||
const { data } = await request.get('/api/chat/message/fetchConverseMessage', {
|
||||
params: {
|
||||
converseId,
|
||||
startId,
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @param payload 消息体
|
||||
*/
|
||||
export async function sendMessage(
|
||||
payload: SendMessagePayload
|
||||
): Promise<ChatMessage> {
|
||||
const { data } = await request.post('/api/chat/message/sendMessage', payload);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回消息
|
||||
* @param messageId 消息ID
|
||||
*/
|
||||
export async function recallMessage(messageId: string): Promise<ChatMessage> {
|
||||
const { data } = await request.post('/api/chat/message/recallMessage', {
|
||||
messageId,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function deleteMessage(messageId: string): Promise<boolean> {
|
||||
const { data } = await request.post('/api/chat/message/deleteMessage', {
|
||||
messageId,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索聊天记录
|
||||
* @param converseId 会话id
|
||||
* @param messageText 聊天文本
|
||||
*/
|
||||
export async function searchMessage(
|
||||
text: string,
|
||||
converseId: string,
|
||||
groupId?: string
|
||||
): Promise<ChatMessage[]> {
|
||||
const { data } = await request.post('/api/chat/message/searchMessage', {
|
||||
text,
|
||||
converseId,
|
||||
groupId,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
interface LastMessageInfo {
|
||||
converseId: string;
|
||||
lastMessageId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于会话id获取会话最后一条消息的id
|
||||
*/
|
||||
async function fetchConverseLastMessages(
|
||||
converseIds: string[]
|
||||
): Promise<{ converseId: string; lastMessageId: string }[]> {
|
||||
const { data } = await request.post(
|
||||
'/api/chat/message/fetchConverseLastMessages',
|
||||
{
|
||||
converseIds,
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export const _fetchConverseLastMessageInfo = createAutoMergedRequest<
|
||||
string[],
|
||||
(LastMessageInfo | null)[]
|
||||
>(
|
||||
createAutoSplitRequest(
|
||||
async (converseIdsList) => {
|
||||
const uniqList = _uniq(_flatten(converseIdsList));
|
||||
const infoList = await fetchConverseLastMessages(uniqList);
|
||||
|
||||
const map = _zipObject<LastMessageInfo | null>(uniqList, infoList);
|
||||
|
||||
// 将请求结果根据传输来源重新分组
|
||||
return converseIdsList.map((converseIds) =>
|
||||
converseIds.map((converseId) => map[converseId] ?? null)
|
||||
);
|
||||
},
|
||||
'serial',
|
||||
100
|
||||
)
|
||||
);
|
||||
export function getConverseLastMessageInfo(converseIds: string[]) {
|
||||
return _fetchConverseLastMessageInfo(converseIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param converseId 会话ID
|
||||
* @param messageId 消息ID
|
||||
* @returns 消息附近的信息
|
||||
*/
|
||||
export async function fetchNearbyMessage(params: {
|
||||
groupId?: string;
|
||||
converseId: string;
|
||||
messageId: string;
|
||||
}): Promise<ChatMessage[]> {
|
||||
const { data } = await request.post(
|
||||
'/api/chat/message/fetchNearbyMessage',
|
||||
params
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加表情行为
|
||||
*/
|
||||
export async function addReaction(
|
||||
messageId: string,
|
||||
emoji: string
|
||||
): Promise<boolean> {
|
||||
const { data } = await request.post('/api/chat/message/addReaction', {
|
||||
messageId,
|
||||
emoji,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除表情行为
|
||||
*/
|
||||
export async function removeReaction(
|
||||
messageId: string,
|
||||
emoji: string
|
||||
): Promise<boolean> {
|
||||
const { data } = await request.post('/api/chat/message/removeReaction', {
|
||||
messageId,
|
||||
emoji,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
93
client/shared/model/plugin.ts
Normal file
93
client/shared/model/plugin.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { request } from '../api/request';
|
||||
|
||||
export interface PluginManifest {
|
||||
/**
|
||||
* 插件用于显示的名称
|
||||
* @example 网页面板插件
|
||||
*/
|
||||
label: string;
|
||||
'label.zh-CN'?: string;
|
||||
|
||||
/**
|
||||
* 插件名, 插件唯一标识
|
||||
* @example com.msgbyte.webview
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* 插件地址
|
||||
*/
|
||||
url: string;
|
||||
|
||||
/**
|
||||
* 插件图标
|
||||
* 推荐大小: 128x128
|
||||
*/
|
||||
icon?: string;
|
||||
|
||||
/**
|
||||
* 插件版本号
|
||||
* 遵循 semver 规则
|
||||
*
|
||||
* major.minor.patch
|
||||
* @example 1.0.0
|
||||
*/
|
||||
version: string;
|
||||
|
||||
/**
|
||||
* 插件维护者
|
||||
*/
|
||||
author: string;
|
||||
|
||||
/**
|
||||
* 插件描述
|
||||
*/
|
||||
description: string;
|
||||
'description.zh-CN'?: string;
|
||||
|
||||
/**
|
||||
* 是否需要重启才能应用插件
|
||||
*/
|
||||
requireRestart: boolean;
|
||||
|
||||
/**
|
||||
* 文档的链接
|
||||
* 如果是markdown则解析, 如果是html则使用iframe
|
||||
*/
|
||||
documentUrl?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务端插件中心的插件列表
|
||||
*
|
||||
* 后端动态
|
||||
*/
|
||||
export async function fetchRegistryPlugins(): Promise<PluginManifest[]> {
|
||||
const { data } = await request.get('/api/plugin/registry/list');
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务器安装的插件列表
|
||||
*
|
||||
* 后端固定
|
||||
*/
|
||||
export async function fetchServiceRegistryPlugins(): Promise<PluginManifest[]> {
|
||||
const { data } = await request.get('/registry-be.json');
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地固定的registry
|
||||
*
|
||||
* 前端固定
|
||||
*/
|
||||
export async function fetchLocalStaticRegistryPlugins(): Promise<
|
||||
PluginManifest[]
|
||||
> {
|
||||
const { data } = await request.get('/registry.json', { baseURL: '' });
|
||||
|
||||
return data;
|
||||
}
|
||||
435
client/shared/model/user.ts
Normal file
435
client/shared/model/user.ts
Normal file
@@ -0,0 +1,435 @@
|
||||
import { request } from '../api/request';
|
||||
import { buildCachedRequest } from '../cache/utils';
|
||||
import { sharedEvent } from '../event';
|
||||
import { SYSTEM_USERID } from '../utils/consts';
|
||||
import {
|
||||
createAutoMergedRequest,
|
||||
createAutoSplitRequest,
|
||||
} from '../utils/request';
|
||||
import _pick from 'lodash/pick';
|
||||
import _uniq from 'lodash/uniq';
|
||||
import _flatten from 'lodash/flatten';
|
||||
import _zipObject from 'lodash/zipObject';
|
||||
import { t } from '../i18n';
|
||||
import type { UserBaseInfo } from 'tailchat-types';
|
||||
import { isObjectId } from '../utils/string-helper';
|
||||
|
||||
export type { UserBaseInfo };
|
||||
|
||||
export interface UserLoginInfo extends UserBaseInfo {
|
||||
token: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface UserSettings {
|
||||
/**
|
||||
* 消息列表虚拟化
|
||||
*/
|
||||
messageListVirtualization?: boolean;
|
||||
|
||||
/**
|
||||
* 消息通知免打扰(静音)
|
||||
*/
|
||||
messageNotificationMuteList?: string[];
|
||||
|
||||
/**
|
||||
* 群组排序, 内容为群组id
|
||||
*/
|
||||
groupOrderList?: string[];
|
||||
|
||||
/**
|
||||
* 是否关闭消息右键菜单
|
||||
*/
|
||||
disableMessageContextMenu?: boolean;
|
||||
|
||||
/**
|
||||
* 其他的设置项
|
||||
*/
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export function pickUserBaseInfo(userInfo: UserLoginInfo): UserBaseInfo {
|
||||
return _pick(userInfo, [
|
||||
'_id',
|
||||
'email',
|
||||
'nickname',
|
||||
'discriminator',
|
||||
'avatar',
|
||||
'temporary',
|
||||
'type',
|
||||
'emailVerified',
|
||||
'banned',
|
||||
]);
|
||||
}
|
||||
|
||||
// 内置用户信息
|
||||
const builtinUserInfo: Record<string, () => UserBaseInfo> = {
|
||||
[SYSTEM_USERID]: () => ({
|
||||
_id: SYSTEM_USERID,
|
||||
email: 'admin@msgbyte.com',
|
||||
nickname: t('系统'),
|
||||
discriminator: '0000',
|
||||
avatar: null,
|
||||
temporary: false,
|
||||
type: 'normalUser',
|
||||
emailVerified: false,
|
||||
banned: false,
|
||||
}),
|
||||
'': () => ({
|
||||
// dummy
|
||||
_id: '',
|
||||
email: '',
|
||||
nickname: '',
|
||||
discriminator: '0000',
|
||||
avatar: null,
|
||||
temporary: false,
|
||||
type: 'normalUser',
|
||||
emailVerified: false,
|
||||
banned: false,
|
||||
}),
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户私信列表
|
||||
*/
|
||||
export interface UserDMList {
|
||||
userId: string;
|
||||
converseIds: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱登录
|
||||
* @param email 邮箱
|
||||
* @param password 密码
|
||||
*/
|
||||
export async function loginWithEmail(
|
||||
email: string,
|
||||
password: string
|
||||
): Promise<UserLoginInfo> {
|
||||
const { data } = await request.post('/api/user/login', {
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
sharedEvent.emit('loginSuccess', pickUserBaseInfo(data));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 Token 登录
|
||||
* @param token JWT令牌
|
||||
*/
|
||||
export async function loginWithToken(token: string): Promise<UserLoginInfo> {
|
||||
const { data } = await request.post('/api/user/resolveToken', {
|
||||
token,
|
||||
});
|
||||
|
||||
sharedEvent.emit('loginSuccess', pickUserBaseInfo(data));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮箱校验码
|
||||
* @param email 邮箱
|
||||
*/
|
||||
export async function verifyEmail(email: string): Promise<UserLoginInfo> {
|
||||
const { data } = await request.post('/api/user/verifyEmail', {
|
||||
email,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查邮箱校验码并更新用户字段
|
||||
* @param email 邮箱
|
||||
*/
|
||||
export async function verifyEmailWithOTP(
|
||||
emailOTP: string
|
||||
): Promise<UserLoginInfo> {
|
||||
const { data } = await request.post('/api/user/verifyEmailWithOTP', {
|
||||
emailOTP,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱注册账号
|
||||
* @param email 邮箱
|
||||
* @param password 密码
|
||||
*/
|
||||
export async function registerWithEmail({
|
||||
email,
|
||||
password,
|
||||
nickname,
|
||||
emailOTP,
|
||||
}: {
|
||||
email: string;
|
||||
password: string;
|
||||
nickname?: string;
|
||||
emailOTP?: string;
|
||||
}): Promise<UserLoginInfo> {
|
||||
const { data } = await request.post('/api/user/register', {
|
||||
email,
|
||||
nickname,
|
||||
password,
|
||||
emailOTP,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*/
|
||||
export async function modifyUserPassword(
|
||||
oldPassword: string,
|
||||
newPassword: string
|
||||
): Promise<void> {
|
||||
await request.post('/api/user/modifyPassword', {
|
||||
oldPassword,
|
||||
newPassword,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 忘记密码
|
||||
* @param email 邮箱
|
||||
*/
|
||||
export async function forgetPassword(email: string) {
|
||||
await request.post('/api/user/forgetPassword', {
|
||||
email,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 忘记密码
|
||||
* @param email 邮箱
|
||||
*/
|
||||
export async function resetPassword(
|
||||
email: string,
|
||||
password: string,
|
||||
otp: string
|
||||
) {
|
||||
await request.post('/api/user/resetPassword', {
|
||||
email,
|
||||
password,
|
||||
otp,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建访客账号
|
||||
* @param nickname 访客昵称
|
||||
*/
|
||||
export async function createTemporaryUser(
|
||||
nickname: string
|
||||
): Promise<UserLoginInfo> {
|
||||
const { data } = await request.post('/api/user/createTemporaryUser', {
|
||||
nickname,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 认领访客账号
|
||||
*/
|
||||
export async function claimTemporaryUser(
|
||||
userId: string,
|
||||
email: string,
|
||||
password: string,
|
||||
emailOTP?: string
|
||||
): Promise<UserLoginInfo> {
|
||||
const { data } = await request.post('/api/user/claimTemporaryUser', {
|
||||
userId,
|
||||
email,
|
||||
password,
|
||||
emailOTP,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用唯一标识名搜索用户
|
||||
* @param uniqueName 唯一标识用户昵称: 用户昵称#0000
|
||||
*/
|
||||
export async function searchUserWithUniqueName(
|
||||
uniqueName: string
|
||||
): Promise<UserBaseInfo> {
|
||||
const { data } = await request.post('/api/user/searchUserWithUniqueName', {
|
||||
uniqueName,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const _fetchUserInfo = createAutoMergedRequest<string, UserBaseInfo>(
|
||||
createAutoSplitRequest(
|
||||
async (userIds) => {
|
||||
// 这里用post是为了防止一次性获取的userId过多超过url限制
|
||||
const { data } = await request.post('/api/user/getUserInfoList', {
|
||||
userIds,
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
'serial',
|
||||
1000
|
||||
)
|
||||
);
|
||||
/**
|
||||
* 获取用户基本信息
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
export async function fetchUserInfo(userId: string): Promise<UserBaseInfo> {
|
||||
if (
|
||||
builtinUserInfo[userId] &&
|
||||
typeof builtinUserInfo[userId] === 'function'
|
||||
) {
|
||||
return builtinUserInfo[userId]();
|
||||
}
|
||||
|
||||
if (!isObjectId(userId)) {
|
||||
throw new Error(`Invalid userId: ${userId}`);
|
||||
}
|
||||
|
||||
const userInfo = await _fetchUserInfo(userId);
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
const _fetchUserOnlineStatus = createAutoMergedRequest<string[], boolean[]>(
|
||||
createAutoSplitRequest(
|
||||
async (userIdsList) => {
|
||||
const uniqList = _uniq(_flatten(userIdsList));
|
||||
// 这里用post是为了防止一次性获取的userId过多超过url限制
|
||||
const { data } = await request.post('/api/gateway/checkUserOnline', {
|
||||
userIds: uniqList,
|
||||
});
|
||||
|
||||
const map = _zipObject<boolean>(uniqList, data);
|
||||
|
||||
// 将请求结果根据传输来源重新分组
|
||||
return userIdsList.map((userIds) =>
|
||||
userIds.map((userId) => map[userId] ?? false)
|
||||
);
|
||||
},
|
||||
'serial',
|
||||
1000
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* 获取用户在线状态
|
||||
*/
|
||||
export async function getUserOnlineStatus(
|
||||
userIds: string[]
|
||||
): Promise<boolean[]> {
|
||||
return _fetchUserOnlineStatus(userIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将会话添加到用户私信列表
|
||||
* 如果已添加则后端忽略
|
||||
*/
|
||||
export async function appendUserDMConverse(
|
||||
converseId: string
|
||||
): Promise<UserDMList> {
|
||||
const { data } = await request.post<UserDMList>(
|
||||
'/api/user/dmlist/addConverse',
|
||||
{
|
||||
converseId,
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除会话列表
|
||||
*/
|
||||
export async function removeUserDMConverse(
|
||||
converseId: string
|
||||
): Promise<UserDMList> {
|
||||
const { data } = await request.post<UserDMList>(
|
||||
'/api/user/dmlist/removeConverse',
|
||||
{
|
||||
converseId,
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户属性
|
||||
* @param fieldName 要修改的属性名
|
||||
* @param fieldValue 要修改的属性的值
|
||||
*/
|
||||
type AllowedModifyField = 'nickname' | 'avatar';
|
||||
export async function modifyUserField(
|
||||
fieldName: AllowedModifyField,
|
||||
fieldValue: unknown
|
||||
): Promise<UserBaseInfo> {
|
||||
const { data } = await request.post('/api/user/updateUserField', {
|
||||
fieldName,
|
||||
fieldValue,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function modifyUserExtra(
|
||||
fieldName: string,
|
||||
fieldValue: unknown
|
||||
): Promise<UserBaseInfo> {
|
||||
const { data } = await request.post('/api/user/updateUserExtra', {
|
||||
fieldName,
|
||||
fieldValue,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户设置
|
||||
*/
|
||||
export async function getUserSettings(): Promise<UserSettings> {
|
||||
const { data } = await request.get('/api/user/getUserSettings');
|
||||
|
||||
sharedEvent.emit('userSettingsUpdate', data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户设置
|
||||
*/
|
||||
export async function setUserSettings(
|
||||
settings: UserSettings
|
||||
): Promise<UserSettings> {
|
||||
const { data } = await request.post('/api/user/setUserSettings', {
|
||||
settings,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查Token是否可用
|
||||
*/
|
||||
export const checkTokenValid = buildCachedRequest(
|
||||
'tokenValid',
|
||||
async (token: string): Promise<boolean> => {
|
||||
const { data } = await request.post<boolean>('/api/user/checkTokenValid', {
|
||||
token,
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user