This commit is contained in:
Timi
2026-07-30 18:28:25 +08:00
parent 8b24804b22
commit f0d1090932
21 changed files with 915 additions and 268 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ import { axios } from "./BaseAPI";
* @param id 文章 ID
* @returns 文章数据
*/
async function view(id: number): Promise<ArticleView<any>> {
async function view(id: string): Promise<ArticleView<any>> {
return axios.get(`/article/${id}`);
}
@@ -17,7 +17,7 @@ async function view(id: number): Promise<ArticleView<any>> {
* @param id 文章 ID
* @returns 最新喜欢数量
*/
async function like(id: number): Promise<number> {
async function like(id: string): Promise<number> {
return axios.get(`/article/like/${id}`);
}
+58
View File
@@ -0,0 +1,58 @@
import {Attachment, BizUpdateReq, TempFileResp} from "../types";
import {axios} from "./BaseAPI";
import CommonAPI from "./CommonAPI";
const BASE_URI = "/attach";
/**
* 上传临时附件
*
* @param file 文件或文件列表
* @param ttl 有效期
* @returns 临时附件列表
*/
async function uploadTemp(file: File | File[], ttl?: string): Promise<TempFileResp[]> {
const formData = new FormData();
const fileList = Array.isArray(file) ? file : [file];
for (const item of fileList) {
formData.append("file", item);
}
if (ttl) {
formData.append("ttl", ttl);
}
return await axios.post(`${BASE_URI}/temp/upload`, formData);
}
/**
* 按业务差分更新附件
*
* @param req 更新请求
*/
async function updateByBiz(req: BizUpdateReq): Promise<void> {
return await axios.post(`${BASE_URI}/update/biz`, req);
}
/**
* 按业务查询附件列表
*
* @param bizType 业务类型
* @param bizId 业务 ID
* @param attachTypeList 附件类型列表
*/
async function listByBiz(bizType: string, bizId: string, attachTypeList?: string[]): Promise<Attachment[]> {
return await axios.get(`${BASE_URI}/list/biz`, {
params: {
bizType,
bizId,
attachTypeList
}
});
}
export default {
uploadTemp,
updateByBiz,
listByBiz,
getReadURL: CommonAPI.getAttachmentReadAPI,
getTempReadURL: CommonAPI.getAttachmentTempReadAPI
};
+19 -3
View File
@@ -1,9 +1,23 @@
import {Setting, TemplateBizType} from "../types";
import {CaptchaResult, Setting, TemplateBizType} from "../types";
import {axios} from "./BaseAPI";
const getCaptchaAPI = () => axios.defaults.baseURL + "/captcha";
function getBaseURI(): string {
const baseURL = axios.defaults.baseURL;
if (!baseURL || baseURL === "undefined") {
return "";
}
return baseURL.replace(/\/$/, "");
}
const getAttachmentReadAPI = (mongoId: string) => `${axios.defaults.baseURL}/attachment/read/${mongoId}`;
const getCaptchaAPI = () => `${getBaseURI()}/captcha`;
async function captcha(width: number, height: number): Promise<CaptchaResult> {
return await axios.get(`/captcha?width=${width}&height=${height}`);
}
const getAttachmentReadAPI = (id: string) => `${getBaseURI()}/attach/read/${id}`;
const getAttachmentTempReadAPI = (id: string) => `${getBaseURI()}/attach/temp/read?id=${id}`;
async function getTemplate(bizType: TemplateBizType, code: string): Promise<string> {
return axios.get(`/template?bizType=${bizType}&bizCode=${code}`);
@@ -30,7 +44,9 @@ async function settingMap(map: Record<string, string[]>): Promise<Map<string, Ma
export default {
getCaptchaAPI,
captcha,
getAttachmentReadAPI,
getAttachmentTempReadAPI,
getTemplate,
settingMap
};
+29
View File
@@ -0,0 +1,29 @@
import { axios } from "./BaseAPI";
import type { Page, PageResult, Permission, PermissionPayload } from "../types";
const BASE_URI = "/user/permission";
async function list(req: Page<Permission>): Promise<PageResult<Permission>> {
return axios.post(`${BASE_URI}/list`, req);
}
async function create(req: PermissionPayload): Promise<void> {
return axios.post(`${BASE_URI}/create`, req);
}
async function update(req: PermissionPayload): Promise<void> {
return axios.post(`${BASE_URI}/update`, req);
}
async function remove(id: string): Promise<void> {
return axios.post(`${BASE_URI}/delete`, undefined, {
params: { id }
});
}
export default {
list,
create,
update,
remove
};
+55
View File
@@ -0,0 +1,55 @@
import { axios } from "./BaseAPI";
import type { Page, PageResult, Permission, Role, RolePayload, UserRoleAuthorizeReq } from "../types";
const BASE_URI = "/user/role";
async function list(req: Page<Role>): Promise<PageResult<Role>> {
return axios.post(`${BASE_URI}/list`, req);
}
async function detail(id: string): Promise<Role> {
return axios.post(`${BASE_URI}/detail`, undefined, {
params: { id }
});
}
async function create(req: RolePayload): Promise<void> {
return axios.post(`${BASE_URI}/create`, req);
}
async function update(req: RolePayload): Promise<void> {
return axios.post(`${BASE_URI}/update`, req);
}
async function remove(id: string): Promise<void> {
return axios.post(`${BASE_URI}/delete`, undefined, {
params: { id }
});
}
async function authorizedList(userId: string): Promise<Role[]> {
return axios.post(`${BASE_URI}/authorized/list`, undefined, {
params: { userId }
});
}
async function authorize(req: UserRoleAuthorizeReq): Promise<void> {
return axios.post(`${BASE_URI}/authorized/create`, req);
}
async function authorizedPermission(userId: string): Promise<Permission[]> {
return axios.post(`${BASE_URI}/authorized/permission`, undefined, {
params: { userId }
});
}
export default {
list,
detail,
create,
update,
remove,
authorizedList,
authorize,
authorizedPermission
};
+33 -33
View File
@@ -1,30 +1,21 @@
import {
Attachment,
CaptchaData,
LoginRequest,
LoginResponse,
RegisterRequest,
UserAttachType,
UserProfileView,
UserView
} from "../types";
import { axios } from "./BaseAPI";
import {Attachment, CaptchaData, LoginRequest, LoginResponse, RegisterRequest, UpdatePasswordRequest, User, UserAttachType} from "../types";
import {axios} from "./BaseAPI";
import CommonAPI from "./CommonAPI";
const BASE_URI = "/user";
async function register(captchaData: CaptchaData<RegisterRequest>): Promise<LoginResponse> {
return axios.post(`${BASE_URI}/register`, captchaData);
async function register(req: CaptchaData<RegisterRequest>): Promise<LoginResponse> {
return await axios.post(`${BASE_URI}/register`, req);
}
/**
* 登录
*
* @param captchaData 验证码登录对象
* @param req 验证码登录对象
* @returns LoginResponse
*/
async function login(captchaData: CaptchaData<LoginRequest>): Promise<LoginResponse> {
return axios.post(`${BASE_URI}/login`, captchaData);
async function login(req: CaptchaData<LoginRequest>): Promise<LoginResponse> {
return await axios.post(`${BASE_URI}/login`, req);
}
/**
@@ -32,12 +23,20 @@ async function login(captchaData: CaptchaData<LoginRequest>): Promise<LoginRespo
*
* @returns true 为已登录
*/
async function login4Token(): Promise<LoginResponse> {
return axios.post(`${BASE_URI}/login/token`);
async function loginByToken(): Promise<LoginResponse> {
return await axios.post(`${BASE_URI}/login/token`);
}
async function logout(): Promise<void> {
return axios.post(`${BASE_URI}/logout`);
return await axios.post(`${BASE_URI}/logout`);
}
async function updateCurrent(req: User): Promise<LoginResponse> {
return await axios.post(`${BASE_URI}/current/update`, req);
}
async function updatePassword(req: UpdatePasswordRequest): Promise<void> {
return await axios.post(`${BASE_URI}/update/password`, req);
}
/**
@@ -46,29 +45,28 @@ async function logout(): Promise<void> {
* @param id 用户 ID
* @returns 用户数据
*/
async function view(id: number): Promise<UserView> {
return axios.post(`${BASE_URI}/view/${id}`);
async function view(id: string): Promise<User> {
return await axios.post(`${BASE_URI}/view/${id}`);
}
function getAvatarURL(profile?: UserProfileView) {
if (profile && profile.attachmentList) {
return findAttachmentByType(profile.attachmentList, [UserAttachType.AVATAR, UserAttachType.DEFAULT_AVATAR]);
function getAvatarURL(user?: User) {
if (user?.attachmentList) {
return findAttachmentByType(user.attachmentList, [UserAttachType.AVATAR, UserAttachType.DEFAULT_AVATAR]);
}
}
function getWrapperURL(profile?: UserProfileView) {
if (profile && profile.attachmentList) {
return findAttachmentByType(profile.attachmentList, [UserAttachType.WRAPPER, UserAttachType.DEFAULT_WRAPPER]);
function getWrapperURL(user?: User) {
if (user?.attachmentList) {
return findAttachmentByType(user.attachmentList, [UserAttachType.WRAPPER, UserAttachType.DEFAULT_WRAPPER]);
}
}
function findAttachmentByType(attachmentList: Attachment[], types: UserAttachType[]) {
for (let i = 0; i < attachmentList.length; i++) {
const attachType = (<any>UserAttachType)[attachmentList[i].attachType!];
for (let type of types) {
if (attachType === type) {
return CommonAPI.getAttachmentReadAPI(attachmentList[i].mongoId);
}
const attachType = attachmentList[i].attachType as UserAttachType | undefined;
const id = attachmentList[i].id;
if (id && attachType && types.includes(attachType)) {
return CommonAPI.getAttachmentReadAPI(id);
}
}
}
@@ -76,8 +74,10 @@ function findAttachmentByType(attachmentList: Attachment[], types: UserAttachTyp
export default {
register,
login,
login4Token,
loginByToken,
logout,
updateCurrent,
updatePassword,
view,
getAvatarURL,
+3
View File
@@ -1,5 +1,8 @@
export { default as ArticleAPI } from "./ArticleAPI";
export { default as AttachmentAPI } from "./AttachmentAPI";
export { default as CommentAPI } from "./CommentAPI";
export { default as CommonAPI } from "./CommonAPI";
export { default as DeveloperAPI } from "./DeveloperAPI";
export { default as PermissionAPI } from "./PermissionAPI";
export { default as RoleAPI } from "./RoleAPI";
export { default as UserAPI } from "./UserAPI";
+78 -21
View File
@@ -1,46 +1,103 @@
<template>
<img
<button
class="tui-captcha ir-pixelated"
v-if="src"
:width="width"
:height="height"
:src="src"
alt="验证码"
@click="update()"
/>
type="button"
:style="captchaStyle"
:disabled="isLoading"
:title="title"
@click="update"
>
<img v-if="src" :src="src" :alt="title" />
<span v-else v-text="placeholder" />
</button>
</template>
<script lang="ts" setup>
import Toolkit from "../../utils/Toolkit";
import {CommonAPI} from "../../api";
import type {CaptchaResult} from "../../types";
defineOptions({
name: "Captcha"
});
const props = withDefaults(defineProps<{
width: number,
height: number,
from: string,
api: string,
}>(), {});
const { width, height, from, api } = toRefs(props);
width?: number,
height?: number,
title?: string,
placeholder?: string,
}>(), {
width: 90,
height: 40,
title: "验证码",
placeholder: "刷新"
});
const emit = defineEmits<{
update: [result: CaptchaResult],
error: [error: unknown]
}>();
const { width, height, title, placeholder } = toRefs(props);
const src = ref("");
function update() {
src.value = `${api.value}?from=${from.value}&width=${width.value}&height=${height.value}&r=${Toolkit.random(0, 999999)}`;
const captchaId = ref("");
const isLoading = ref(false);
const captchaStyle = computed(() => {
return {
width: `${width.value / 16}rem`,
height: `${height.value / 16}rem`
};
});
async function update(): Promise<void> {
isLoading.value = true;
try {
const result = await CommonAPI.captcha(width.value, height.value);
captchaId.value = result.id;
src.value = result.data;
emit("update", result);
} catch (error) {
emit("error", error);
} finally {
isLoading.value = false;
}
}
onMounted(update);
onMounted(async () => {
await update();
});
defineExpose({
captchaId,
src,
isLoading,
update
});
</script>
<style lang="less" scoped>
.tui-captcha {
cursor: var(--tui-cur-pointer);
border: 1px solid gray;
display: block;
margin: 0;
border: 0;
padding: 0;
display: grid;
background: #f8fafc;
overflow: hidden;
cursor: pointer;
color: #64748b;
flex: 0 0 auto;
pointer-events: all;
place-items: center;
border-radius: .5rem;
&:disabled {
cursor: not-allowed;
opacity: .64;
}
img {
width: 100%;
height: 100%;
display: block;
}
}
</style>
+180 -64
View File
@@ -1,79 +1,195 @@
import { LoginResponse, LoginToken, LoginUser, UserToken } from "../types";
import {defineStore} from "pinia";
import {computed, reactive, readonly, ref} from "vue";
import {CaptchaData, LoginRequest, LoginResponse, LoginUser} from "../types";
import Cooker from "../utils/Cooker";
import Storage from "../utils/Storage";
import UserAPI from "../api/UserAPI";
import {UserAPI} from "../api";
const loginUser = reactive<LoginUser>({
token: undefined,
user: undefined
});
function isLogged(): boolean {
return !!loginUser.user;
/** 用户 Store 配置项 */
interface UserStoreOptions {
/** localStorage 储存 key,默认 "loginUser" */
storageKey?: string;
}
async function login4Token(token: LoginToken): Promise<LoginResponse | null> {
loginUser.token = token;
// 未过期
try {
const resp = await UserAPI.login4Token();
await updateToken(resp);
return resp;
} catch (e) {
await logout();
/** 访问控制匹配模式 */
export type AccessMatchMode = "and" | "or";
let _storageKey = "loginUser";
function normalizeAccessList(list?: string[]): string[] {
if (!list?.length) {
return [];
}
return null;
return list
.map(item => item?.trim())
.filter((item): item is string => !!item);
}
async function login4Storage(): Promise<LoginResponse | null> {
if (!loginUser.user && (loginUser.token || Storage.has("token"))) {
// 未登录,储存有令牌
const token = Storage.getJSON("token") as UserToken;
if (new Date().getTime() < token.expireAt) {
return await login4Token(token);
function matchAccess(sourceList?: string[], targetList?: string | string[], mode: AccessMatchMode = "or"): boolean {
const normalizedTargetList = normalizeAccessList(Array.isArray(targetList) ? targetList : [targetList || ""]);
if (!normalizedTargetList.length) {
return true;
}
const sourceSet = new Set(normalizeAccessList(sourceList));
if (!sourceSet.size) {
return false;
}
if (mode === "and") {
return normalizedTargetList.every(item => sourceSet.has(item));
}
return normalizedTargetList.some(item => sourceSet.has(item));
}
/**
* 配置用户 Store,应在使用 useUserStore 之前调用
* @param options 配置项
*/
function configureUserStore(options: UserStoreOptions): void {
if (options.storageKey) {
_storageKey = options.storageKey;
}
}
const useUserStore = defineStore("user", () => {
type LoginUserState = LoginUser & Record<string, unknown>;
const loginUser = reactive<LoginUserState>({});
const isRestored = ref(false);
const token = computed(() => loginUser.token ?? "");
const isLoggedIn = computed(() => isValidLoginUser(loginUser));
function resetLoginUser(nextUser?: LoginUserState): void {
Object.keys(loginUser).forEach((key) => {
delete loginUser[key];
});
if (nextUser) {
Object.assign(loginUser, nextUser);
}
}
return null;
}
async function updateToken(loginResponse: LoginResponse): Promise<void> {
loginUser.token = {
id: loginResponse.id,
value: loginResponse.token,
expireAt: loginResponse.expireAt
};
loginUser.user = await UserAPI.view(loginResponse.id);
Storage.setJSON("token", {
value: loginUser.token.value,
expireAt: loginUser.token.expireAt
} as UserToken);
}
async function logout(): Promise<void> {
await UserAPI.logout();
loginUser.token = undefined;
loginUser.user = undefined;
Storage.remove("token");
}
async function reloadProfile() {
if (loginUser.token && loginUser.token.id) {
loginUser.user = await UserAPI.view(loginUser.token.id);
function isValidLoginUser(user?: LoginUserState | null): user is LoginResponse {
return !!user?.token && !!user.expireAt && new Date().getTime() < user.expireAt;
}
}
const userStore = {
loginUser,
isLogged,
login4Token,
login4Storage,
updateToken,
logout,
reloadProfile
};
function isLogged(): boolean {
return isLoggedIn.value;
}
function getLoginUser<T extends LoginUser = LoginUser>(): T | null {
if (!isLogged()) {
return null;
}
return loginUser as T;
}
function getRoleList(): string[] {
return normalizeAccessList(loginUser.user?.roleList);
}
function getPermissionList(): string[] {
return normalizeAccessList(loginUser.user?.permissionList);
}
function hasRoles(roleList: string | string[], mode: AccessMatchMode = "or"): boolean {
return matchAccess(getRoleList(), roleList, mode);
}
function hasPermissions(permissionList: string | string[], mode: AccessMatchMode = "or"): boolean {
return matchAccess(getPermissionList(), permissionList, mode);
}
async function login<T extends LoginUser = LoginUser>(req: CaptchaData<LoginRequest>): Promise<T> {
const result = await UserAPI.login(req);
const nextUser = result as unknown as T;
await updateLoginUser(nextUser);
return nextUser;
}
async function loginByToken<T extends LoginUser = LoginUser>(token: string): Promise<T | null> {
loginUser.token = token;
// 未过期
try {
const result = await UserAPI.loginByToken();
if (!result) {
return null;
}
const nextUser = result as unknown as T;
await updateLoginUser(nextUser);
return nextUser;
} catch (e) {
console.error(e);
clearLoginUser();
}
return null;
}
async function loginByStorage<T extends LoginUser = LoginUser>(): Promise<T | null> {
if (loginUser.token) {
isRestored.value = true;
return getLoginUser<T>();
}
if (!Storage.has(_storageKey)) {
isRestored.value = true;
return null;
}
// 未登录,储存有令牌。
const storageUser = Storage.getJSON(_storageKey) as T;
if (isValidLoginUser(storageUser)) {
const result = await loginByToken<T>(storageUser.token);
isRestored.value = true;
return result;
}
clearLoginUser();
isRestored.value = true;
return null;
}
async function updateLoginUser<T extends LoginUser = LoginUser>(user: T): Promise<void> {
resetLoginUser(user as LoginUserState);
Storage.setJSON(_storageKey, user);
}
function clearLoginUser(): void {
resetLoginUser();
Cooker.remove("Token");
Storage.remove(_storageKey);
}
async function logout(): Promise<void> {
try {
await UserAPI.logout();
} finally {
clearLoginUser();
}
}
return {
token,
isLoggedIn,
isRestored,
getRoleList,
getPermissionList,
hasRoles,
hasPermissions,
isLogged,
loginUser: readonly(loginUser),
getLoginUser,
login,
loginByToken,
loginByStorage,
updateLoginUser,
clearLoginUser,
logout
};
});
export {
userStore
useUserStore,
configureUserStore
};
+2 -2
View File
@@ -1,4 +1,4 @@
import type { AttachmentView } from "./Attachment";
import type { Attachment } from "./Attachment";
import type { Model } from "./Model";
// 文章
@@ -17,7 +17,7 @@ export type Article<E extends ArticleMusicExtendData | ArticleSoftwareExtendData
export type ArticleView<E extends ArticleMusicExtendData | ArticleSoftwareExtendData> = {
comments?: number;
attachmentList: AttachmentView[];
attachmentList: Attachment[];
} & Article<E>;
export enum ArticleType {
+29 -11
View File
@@ -2,23 +2,41 @@ import { Model } from "./Model";
export type Attachment = {
bizType: AttachmentBizType;
bizId: number;
bizId: string;
attachType?: string;
mongoId: string;
lidTitle?: number;
name?: string;
size: number;
} & Model
export type AttachmentView = {
title?: string;
} & Attachment
name?: string;
mimeType?: string;
metadata?: unknown;
size?: number;
md5?: string;
uploaderIp?: string;
isDestroyed?: boolean;
destroyAt?: number;
tempFileId?: string;
} & Model;
export type TempFileResp = {
id: string;
expireAt?: number;
};
export type BizUpdateReq = {
bizType: AttachmentBizType;
bizId: string;
items: Partial<Attachment>[];
};
export enum AttachmentBizType {
GIT_ISSUE,
USER = "USER",
GIT_MERGE,
GAO_CUSTOMER = "GAO_CUSTOMER",
GIT_RELEASE
GAO_REGISTER_RECORD = "GAO_REGISTER_RECORD",
TEMP_FILE = "TEMP_FILE",
MIRROR = "MIRROR"
}
+4 -4
View File
@@ -1,5 +1,5 @@
import { Model, Page } from "./Model";
import { UserView } from "./User";
import { User } from "./User";
/** 评论 */
export type Comment = {
@@ -10,7 +10,7 @@ export type Comment = {
content?: string;
/** 所属用户 */
user?: UserView;
user?: User;
/** 回复列表 */
replies?: CommentReply[];
@@ -41,8 +41,8 @@ export type CommentReply = {
content?: string;
comment?: Comment;
sender?: UserView;
receiver?: UserView;
sender?: User;
receiver?: User;
} & Model;
export enum CommentReplyBizType {
+6 -19
View File
@@ -6,7 +6,7 @@ export enum RunEnv {
// 基本实体模型
export type Model = {
id?: number;
id?: string;
createdAt?: number;
updatedAt?: number;
@@ -39,28 +39,15 @@ export type PageResult<T> = {
// 携带验证码的请求体
export type CaptchaData<T> = {
from: string;
captchaId: string;
captcha: string;
data: T;
}
export enum CaptchaFrom {
LOGIN = "LOGIN",
REGISTER = "REGISTER",
/** 评论 */
COMMENT = "COMMENT",
/** 评论回复 */
COMMENT_REPLY = "COMMENT_REPLY",
/** Git 反馈 */
GIT_ISSUE = "GIT_ISSUE",
/** Git 合并请求 */
GIT_MERGE = "GIT_MERGE",
// 图形验证码
export type CaptchaResult = {
id: string;
data: string;
}
export enum ImageType {
+17
View File
@@ -0,0 +1,17 @@
export type ModuleCode = "CORE" | "GAO";
export interface Permission {
id: string;
moduleCode: ModuleCode;
code: string;
nameLangId?: string;
name?: string;
description?: string;
createdAt?: number;
updatedAt?: number;
deletedAt?: number;
}
export type PermissionPayload = Pick<Permission, "moduleCode" | "code" | "nameLangId" | "name" | "description"> & {
id?: string;
};
+31
View File
@@ -0,0 +1,31 @@
import type { ModuleCode, Permission } from "./Permission";
export interface Role {
id: string;
moduleCode: ModuleCode;
code: string;
nameLangId?: string;
name?: string;
description?: string;
permissionList?: Permission[];
allPermissionList?: Permission[];
childRoleList?: Role[];
permissionIdList?: string[];
childRoleIdList?: string[];
createdAt?: number;
updatedAt?: number;
deletedAt?: number;
}
export type RolePayload = Pick<Role, "moduleCode" | "code" | "nameLangId" | "name" | "description"> & {
id?: string;
permissionIdList?: string[];
childRoleIdList?: string[];
};
export interface UserRoleAuthorizeReq {
userId: string;
moduleCode?: ModuleCode;
roleIdList?: string[];
roleCodeList?: string[];
}
+48 -47
View File
@@ -1,79 +1,80 @@
import { ImageType, Model } from "./Model";
import { AttachmentView } from "./Attachment";
import { Attachment } from "./Attachment";
import type { Setting } from "./Setting";
export type User = {
name: string;
nick?: string;
password?: string;
email?: string;
emailVerifyAt: number;
unmuteAt?: number;
unbanAt?: number;
} & Model;
export type UserView = {
profile: UserProfileView
} & User;
export enum UserAttachType {
AVATAR,
WRAPPER,
DEFAULT_AVATAR,
DEFAULT_WRAPPER,
}
export type UserProfile = {
userId: number;
avatarType: ImageType;
wrapperType: ImageType;
exp: number;
emailVerifyAt?: number;
phoneNo?: string;
phoneNoVerifyAt?: number;
wrapperType?: ImageType;
avatarType?: ImageType;
exp?: number;
sex?: number;
birthdate?: number;
qq?: string;
description: string;
description?: string;
lastLoginIP?: string;
lastLoginAt?: number;
updatedAt?: number;
}
unmuteAt?: number;
unbanAt?: number;
roleList?: string[];
permissionList?: string[];
attachmentList?: Attachment[];
settingList?: Setting[];
tempFileIdList?: string[];
muting?: boolean;
banning?: boolean;
emailVerified?: boolean;
phoneNoVerified?: boolean;
} & Model;
export type UserProfileView = {
attachmentList?: AttachmentView[]
} & UserProfile
export enum UserAttachType {
export type UserToken = {
value: string;
expireAt: number;
AVATAR = "AVATAR",
WRAPPER = "WRAPPER",
LICENSE = "LICENSE",
DEFAULT_AVATAR = "DEFAULT_AVATAR",
DEFAULT_WRAPPER = "DEFAULT_WRAPPER"
}
export type RegisterRequest = {
name: string;
password: string;
email?: string;
}
};
export type LoginRequest = {
user: string;
password: string;
}
};
export type UpdatePasswordRequest = {
oldValue: string;
newValue: string;
};
// 登录返回
export type LoginResponse = {
id: number;
id: string;
token: string;
expireAt: number;
}
user?: User;
};
export type LoginUser = {
token?: LoginToken;
user?: UserView
}
export type LoginToken = {
id?: number;
} & UserToken;
id?: string;
token?: string;
expireAt?: number;
user?: User;
};
export enum LoginType {
ALERT,
+2
View File
@@ -5,6 +5,8 @@ export * from "./Article";
export * from "./Setting";
export * from "./Attachment";
export * from "./Model";
export * from "./Permission";
export * from "./Role";
export * from "./User";
export * from "./Template";
export * from "./Comment";