v0.0.23
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
"module": "./dist/timi-web.mjs",
|
"module": "./dist/timi-web.mjs",
|
||||||
"style": "./dist/timi-web.css",
|
"style": "./dist/timi-web.css",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "0.0.22",
|
"version": "0.0.23",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
+9
-5
@@ -1,8 +1,12 @@
|
|||||||
import {Attachment, CaptchaData, LoginRequest, LoginResponse, RegisterRequest, UpdatePasswordRequest, User, UserAttachType} from "../types";
|
import type {Attachment, CaptchaData, LoginRequest, LoginResponse, RegisterRequest, UpdatePasswordRequest, User} from "../types";
|
||||||
|
import {UserAttachType} from "../types";
|
||||||
import {axios} from "./BaseAPI";
|
import {axios} from "./BaseAPI";
|
||||||
import CommonAPI from "./CommonAPI";
|
import CommonAPI from "./CommonAPI";
|
||||||
|
|
||||||
const BASE_URI = "/user";
|
const BASE_URI = "/user";
|
||||||
|
type UserAttachmentOwner = {
|
||||||
|
attachmentList?: readonly Attachment[];
|
||||||
|
};
|
||||||
|
|
||||||
async function register(req: CaptchaData<RegisterRequest>): Promise<LoginResponse> {
|
async function register(req: CaptchaData<RegisterRequest>): Promise<LoginResponse> {
|
||||||
return await axios.post(`${BASE_URI}/register`, req);
|
return await axios.post(`${BASE_URI}/register`, req);
|
||||||
@@ -31,7 +35,7 @@ async function logout(): Promise<void> {
|
|||||||
return await axios.post(`${BASE_URI}/logout`);
|
return await axios.post(`${BASE_URI}/logout`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateCurrent(req: User): Promise<LoginResponse> {
|
async function updateCurrent(req: Partial<User>): Promise<LoginResponse> {
|
||||||
return await axios.post(`${BASE_URI}/current/update`, req);
|
return await axios.post(`${BASE_URI}/current/update`, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,19 +53,19 @@ async function view(id: string): Promise<User> {
|
|||||||
return await axios.post(`${BASE_URI}/view/${id}`);
|
return await axios.post(`${BASE_URI}/view/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAvatarURL(user?: User) {
|
function getAvatarURL(user?: UserAttachmentOwner) {
|
||||||
if (user?.attachmentList) {
|
if (user?.attachmentList) {
|
||||||
return findAttachmentByType(user.attachmentList, [UserAttachType.AVATAR, UserAttachType.DEFAULT_AVATAR]);
|
return findAttachmentByType(user.attachmentList, [UserAttachType.AVATAR, UserAttachType.DEFAULT_AVATAR]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWrapperURL(user?: User) {
|
function getWrapperURL(user?: UserAttachmentOwner) {
|
||||||
if (user?.attachmentList) {
|
if (user?.attachmentList) {
|
||||||
return findAttachmentByType(user.attachmentList, [UserAttachType.WRAPPER, UserAttachType.DEFAULT_WRAPPER]);
|
return findAttachmentByType(user.attachmentList, [UserAttachType.WRAPPER, UserAttachType.DEFAULT_WRAPPER]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function findAttachmentByType(attachmentList: Attachment[], types: UserAttachType[]) {
|
function findAttachmentByType(attachmentList: readonly Attachment[], types: UserAttachType[]) {
|
||||||
for (let i = 0; i < attachmentList.length; i++) {
|
for (let i = 0; i < attachmentList.length; i++) {
|
||||||
const attachType = attachmentList[i].attachType as UserAttachType | undefined;
|
const attachType = attachmentList[i].attachType as UserAttachType | undefined;
|
||||||
const id = attachmentList[i].id;
|
const id = attachmentList[i].id;
|
||||||
|
|||||||
+25
-2
@@ -16,12 +16,35 @@ export type AccessMatchMode = "and" | "or";
|
|||||||
|
|
||||||
let _storageKey = "loginUser";
|
let _storageKey = "loginUser";
|
||||||
|
|
||||||
function normalizeAccessList(list?: string[]): string[] {
|
type AccessItem = string | {
|
||||||
|
moduleCode?: string;
|
||||||
|
code?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function normalizeAccessItem(item?: AccessItem): string {
|
||||||
|
if (!item) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof item === "string") {
|
||||||
|
return item.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = item.code?.trim();
|
||||||
|
if (!code) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleCode = item.moduleCode?.trim();
|
||||||
|
return moduleCode && !code.includes(":") ? `${moduleCode}:${code}` : code;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAccessList(list?: AccessItem[]): string[] {
|
||||||
if (!list?.length) {
|
if (!list?.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
.map(item => item?.trim())
|
.map(normalizeAccessItem)
|
||||||
.filter((item): item is string => !!item);
|
.filter((item): item is string => !!item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -23,8 +23,8 @@ export type Page<T> = {
|
|||||||
index: number;
|
index: number;
|
||||||
size: number;
|
size: number;
|
||||||
orderMap?: { [K in keyof T]?: OrderType };
|
orderMap?: { [K in keyof T]?: OrderType };
|
||||||
equalsExample?: T;
|
equalsExample?: Partial<T>;
|
||||||
likesExample?: T;
|
likesExample?: Partial<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum OrderType {
|
export enum OrderType {
|
||||||
|
|||||||
@@ -7,6 +7,15 @@ export type ScrollListener = {
|
|||||||
bottom: number;
|
bottom: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ScrollBottomListenerOptions = {
|
||||||
|
|
||||||
|
/** 距离底部小于等于该值时触发 */
|
||||||
|
distance?: number;
|
||||||
|
|
||||||
|
/** 返回 true 时才触发 */
|
||||||
|
canLoad?: () => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export default class Scroller {
|
export default class Scroller {
|
||||||
|
|
||||||
private static instance: Scroller;
|
private static instance: Scroller;
|
||||||
@@ -53,6 +62,26 @@ export default class Scroller {
|
|||||||
Scroller.getInstance().listeners.set(name, listener);
|
Scroller.getInstance().listeners.set(name, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加触底监听
|
||||||
|
*
|
||||||
|
* @param name 事件名
|
||||||
|
* @param listener 触底回调
|
||||||
|
* @param options 触底配置
|
||||||
|
*/
|
||||||
|
public static addBottomListener(name: string, listener: (event: ScrollListener) => void | Promise<void>, options: ScrollBottomListenerOptions = {}) {
|
||||||
|
const distance = options.distance ?? 120;
|
||||||
|
Scroller.addListener(name, event => {
|
||||||
|
if (distance < event.bottom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (options.canLoad && !options.canLoad()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void listener(event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除监听
|
* 移除监听
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ export default class Text {
|
|||||||
return template.replace(/\$\{(\w+)}/g, (_, key) => variables[key]);
|
return template.replace(/\$\{(\w+)}/g, (_, key) => variables[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static pad(value: number | string, length = 2, fill = "0"): string {
|
||||||
|
return value.toString().padStart(length, fill);
|
||||||
|
}
|
||||||
|
|
||||||
public static unitCompact(val: number | string | null | undefined, unit: string, fixed = 0): string {
|
public static unitCompact(val: number | string | null | undefined, unit: string, fixed = 0): string {
|
||||||
return this.unit(val, unit, fixed, true);
|
return this.unit(val, unit, fixed, true);
|
||||||
};
|
};
|
||||||
|
|||||||
+25
-6
@@ -1,4 +1,5 @@
|
|||||||
import Toolkit from "./Toolkit";
|
import Toolkit from "./Toolkit";
|
||||||
|
import Text from "./Text";
|
||||||
|
|
||||||
export default class Time {
|
export default class Time {
|
||||||
|
|
||||||
@@ -15,6 +16,25 @@ export default class Time {
|
|||||||
return new Date().getTime();
|
return new Date().getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static toTimestamp(date: Date): number {
|
||||||
|
return date.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static toDateObject(unix?: number): Date | undefined {
|
||||||
|
if (!unix) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return new Date(unix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static formatDate(date: Date): string {
|
||||||
|
return `${date.getFullYear()}-${Text.pad(date.getMonth() + 1)}-${Text.pad(date.getDate())}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static formatDateTime(date: Date): string {
|
||||||
|
return `${this.formatDate(date)} ${Text.pad(date.getHours())}:${Text.pad(date.getMinutes())}`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unix 时间戳转日期
|
* Unix 时间戳转日期
|
||||||
*
|
*
|
||||||
@@ -22,8 +42,7 @@ export default class Time {
|
|||||||
*/
|
*/
|
||||||
public static toDate(unix?: number): string {
|
public static toDate(unix?: number): string {
|
||||||
if (!unix) return "";
|
if (!unix) return "";
|
||||||
const d = new Date(unix);
|
return this.formatDate(new Date(unix));
|
||||||
return `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, "0")}-${d.getDate().toString().padStart(2, "0")}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,13 +53,13 @@ export default class Time {
|
|||||||
public static toTime(unix?: number): string {
|
public static toTime(unix?: number): string {
|
||||||
if (!unix) return "";
|
if (!unix) return "";
|
||||||
const d = new Date(unix);
|
const d = new Date(unix);
|
||||||
return `${d.getHours().toString().padStart(2, "0")}:${d.getMinutes().toString().padStart(2, "0")}`;
|
return `${Text.pad(d.getHours())}:${Text.pad(d.getMinutes())}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static toShortTime(unix?: number): string {
|
public static toShortTime(unix?: number): string {
|
||||||
if (!unix) return "";
|
if (!unix) return "";
|
||||||
const d = new Date(unix);
|
const d = new Date(unix);
|
||||||
return `${d.getMinutes().toString().padStart(2, "0")}:${d.getSeconds().toString().padStart(2, "0")}`;
|
return `${Text.pad(d.getMinutes())}:${Text.pad(d.getSeconds())}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,9 +150,9 @@ export default class Time {
|
|||||||
const minutes = Math.floor((seconds % 3600) / 60);
|
const minutes = Math.floor((seconds % 3600) / 60);
|
||||||
const second = seconds % 60;
|
const second = seconds % 60;
|
||||||
if (0 < hours) {
|
if (0 < hours) {
|
||||||
return `${hours}:${minutes.toString().padStart(2, "0")}:${second.toString().padStart(2, "0")}`;
|
return `${hours}:${Text.pad(minutes)}:${Text.pad(second)}`;
|
||||||
}
|
}
|
||||||
return `${minutes.toString().padStart(2, "0")}:${second.toString().padStart(2, "0")}`;
|
return `${Text.pad(minutes)}:${Text.pad(second)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -398,4 +398,15 @@ export default class Toolkit {
|
|||||||
}
|
}
|
||||||
return JSON.stringify(JSON.parse(jsonStr), null, 4);
|
return JSON.stringify(JSON.parse(jsonStr), null, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static downloadBlob(blob: Blob, fileName: string): void {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = url;
|
||||||
|
link.download = fileName;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
link.remove();
|
||||||
|
window.setTimeout(() => URL.revokeObjectURL(url), 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user