添加管理端和移动端的多个新功能模块,包括文件上传、在线地图、用户认证、系统设置等,优化代码结构,提升可维护性和用户体验。
This commit is contained in:
169
client/mobile/utils.ts
Normal file
169
client/mobile/utils.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { EnableStatus, DeleteStatus, AuditStatus } from '../share/types.ts';
|
||||
|
||||
// 日期格式化
|
||||
export const formatDate = (date: string | Date, format = 'YYYY-MM-DD HH:mm:ss'): string => {
|
||||
if (!date) return '-';
|
||||
return dayjs(date).format(format);
|
||||
};
|
||||
|
||||
// 格式化时间为相对时间(如:3小时前)
|
||||
export const formatRelativeTime = (date: string | Date): string => {
|
||||
if (!date) return '-';
|
||||
const now = dayjs();
|
||||
const dateObj = dayjs(date);
|
||||
const diffInSeconds = now.diff(dateObj, 'second');
|
||||
|
||||
if (diffInSeconds < 60) {
|
||||
return `${diffInSeconds}秒前`;
|
||||
} else if (diffInSeconds < 3600) {
|
||||
return `${Math.floor(diffInSeconds / 60)}分钟前`;
|
||||
} else if (diffInSeconds < 86400) {
|
||||
return `${Math.floor(diffInSeconds / 3600)}小时前`;
|
||||
} else if (diffInSeconds < 2592000) {
|
||||
return `${Math.floor(diffInSeconds / 86400)}天前`;
|
||||
} else {
|
||||
return formatDate(date, 'YYYY-MM-DD');
|
||||
}
|
||||
};
|
||||
|
||||
// 获取枚举的选项(用于下拉菜单等)
|
||||
export const getEnumOptions = (enumObj: Record<string | number, string | number>) => {
|
||||
return Object.entries(enumObj)
|
||||
.filter(([key]) => !isNaN(Number(key))) // 过滤掉映射对象中的字符串键
|
||||
.map(([value, label]) => ({
|
||||
value: Number(value),
|
||||
label: String(label)
|
||||
}));
|
||||
};
|
||||
|
||||
// 获取启用状态选项
|
||||
export const getEnableStatusOptions = () => {
|
||||
return [
|
||||
{ value: EnableStatus.ENABLED, label: '启用' },
|
||||
{ value: EnableStatus.DISABLED, label: '禁用' }
|
||||
];
|
||||
};
|
||||
|
||||
// 获取删除状态选项
|
||||
export const getDeleteStatusOptions = () => {
|
||||
return [
|
||||
{ value: DeleteStatus.NOT_DELETED, label: '未删除' },
|
||||
{ value: DeleteStatus.DELETED, label: '已删除' }
|
||||
];
|
||||
};
|
||||
|
||||
// 获取审核状态选项
|
||||
export const getAuditStatusOptions = () => {
|
||||
return [
|
||||
{ value: AuditStatus.PENDING, label: '待审核' },
|
||||
{ value: AuditStatus.APPROVED, label: '已通过' },
|
||||
{ value: AuditStatus.REJECTED, label: '已拒绝' }
|
||||
];
|
||||
};
|
||||
|
||||
// 格式化文件大小
|
||||
export const formatFileSize = (bytes: number): string => {
|
||||
if (bytes === 0) return '0 B';
|
||||
|
||||
const k = 1024;
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
};
|
||||
|
||||
// 处理API错误
|
||||
export const handleApiError = (error: any): string => {
|
||||
if (error.response) {
|
||||
// 服务器响应错误
|
||||
const status = error.response.status;
|
||||
const data = error.response.data;
|
||||
|
||||
if (status === 401) {
|
||||
return '您的登录已过期,请重新登录';
|
||||
} else if (status === 403) {
|
||||
return '您没有权限执行此操作';
|
||||
} else if (status === 404) {
|
||||
return '请求的资源不存在';
|
||||
} else if (status === 422) {
|
||||
// 表单验证错误
|
||||
return data.message || '输入数据无效';
|
||||
} else {
|
||||
return data.message || `服务器错误 (${status})`;
|
||||
}
|
||||
} else if (error.request) {
|
||||
// 请求发送成功但没有收到响应
|
||||
return '网络连接错误,请检查您的网络连接';
|
||||
} else {
|
||||
// 请求设置错误
|
||||
return '应用程序错误,请稍后再试';
|
||||
}
|
||||
};
|
||||
|
||||
// 复制文本到剪贴板
|
||||
export const copyToClipboard = async (text: string): Promise<boolean> => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('复制到剪贴板失败:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 防抖函数
|
||||
export const debounce = <T extends (...args: any[]) => any>(
|
||||
func: T,
|
||||
wait: number
|
||||
): ((...args: Parameters<T>) => void) => {
|
||||
let timeout: number | null = null;
|
||||
|
||||
return (...args: Parameters<T>) => {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
func(...args);
|
||||
}, wait) as unknown as number;
|
||||
};
|
||||
};
|
||||
|
||||
// 生成随机颜色
|
||||
export const getRandomColor = (): string => {
|
||||
const letters = '0123456789ABCDEF';
|
||||
let color = '#';
|
||||
for (let i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)];
|
||||
}
|
||||
return color;
|
||||
};
|
||||
|
||||
// 获取本地存储值,带过期检查
|
||||
export const getLocalStorageWithExpiry = (key: string) => {
|
||||
const itemStr = localStorage.getItem(key);
|
||||
|
||||
if (!itemStr) return null;
|
||||
|
||||
const item = JSON.parse(itemStr);
|
||||
const now = new Date();
|
||||
|
||||
if (item.expiry && now.getTime() > item.expiry) {
|
||||
localStorage.removeItem(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
return item.value;
|
||||
};
|
||||
|
||||
// 设置本地存储值,带过期时间
|
||||
export const setLocalStorageWithExpiry = (key: string, value: any, expiryHours = 24) => {
|
||||
const now = new Date();
|
||||
const item = {
|
||||
value: value,
|
||||
expiry: now.getTime() + expiryHours * 60 * 60 * 1000
|
||||
};
|
||||
|
||||
localStorage.setItem(key, JSON.stringify(item));
|
||||
};
|
||||
Reference in New Issue
Block a user