提交1 bmad搭建与项目启动 - ok

This commit is contained in:
2025-10-17 17:24:56 +08:00
commit ec58562661
686 changed files with 149750 additions and 0 deletions

218
crop-x/src/lib/utils.ts Normal file
View File

@@ -0,0 +1,218 @@
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
// 合并 Tailwind CSS 类名的工具函数
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
// 格式化日期
export function formatDate(date: Date | string | number): string {
const d = new Date(date)
return d.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
}
// 格式化时间
export function formatTime(date: Date | string | number): string {
const d = new Date(date)
return d.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
})
}
// 格式化日期时间
export function formatDateTime(date: Date | string | number): string {
return `${formatDate(date)} ${formatTime(date)}`
}
// 相对时间格式化
export function formatRelativeTime(date: Date | string | number): string {
const now = new Date()
const target = new Date(date)
const diffMs = now.getTime() - target.getTime()
const diffSecs = Math.floor(diffMs / 1000)
const diffMins = Math.floor(diffSecs / 60)
const diffHours = Math.floor(diffMins / 60)
const diffDays = Math.floor(diffHours / 24)
if (diffSecs < 60) {
return '刚刚'
} else if (diffMins < 60) {
return `${diffMins}分钟前`
} else if (diffHours < 24) {
return `${diffHours}小时前`
} else if (diffDays < 7) {
return `${diffDays}天前`
} else {
return formatDate(date)
}
}
// 数字格式化
export function formatNumber(num: number, precision = 2): string {
return num.toLocaleString('zh-CN', {
minimumFractionDigits: precision,
maximumFractionDigits: precision,
})
}
// 货币格式化
export function formatCurrency(amount: number): string {
return new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: 'CNY',
}).format(amount)
}
// 百分比格式化
export function formatPercentage(value: number, precision = 1): string {
return `${(value * 100).toFixed(precision)}%`
}
// 文件大小格式化
export function formatFileSize(bytes: number): string {
const units = ['B', 'KB', 'MB', 'GB', 'TB']
let size = bytes
let unitIndex = 0
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024
unitIndex++
}
return `${formatNumber(size, unitIndex === 0 ? 0 : 2)} ${units[unitIndex]}`
}
// 农机状态映射
export const machineryStatusMap = {
running: { label: '运行中', color: 'status-running' },
idle: { label: '空闲中', color: 'status-idle' },
maintenance: { label: '维护中', color: 'status-maintenance' },
error: { label: '故障中', color: 'status-error' },
offline: { label: '离线', color: 'status-offline' },
} as const
// 获取农机状态信息
export function getMachineryStatus(status: keyof typeof machineryStatusMap) {
return machineryStatusMap[status] || { label: '未知', color: 'status-idle' }
}
// 农作物类型映射
export const cropTypeMap = {
rice: { label: '水稻', icon: '🌾' },
wheat: { label: '小麦', icon: '🌾' },
corn: { label: '玉米', icon: '🌽' },
soybean: { label: '大豆', icon: '🫘' },
vegetable: { label: '蔬菜', icon: '🥬' },
fruit: { label: '水果', icon: '🍎' },
} as const
// 获取农作物信息
export function getCropInfo(type: keyof typeof cropTypeMap) {
return cropTypeMap[type] || { label: '未知', icon: '🌱' }
}
// 防抖函数
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeout: NodeJS.Timeout | null = null
return (...args: Parameters<T>) => {
if (timeout !== null) {
clearTimeout(timeout)
}
timeout = setTimeout(() => func(...args), wait)
}
}
// 节流函数
export function throttle<T extends (...args: any[]) => any>(
func: T,
limit: number
): (...args: Parameters<T>) => void {
let inThrottle: boolean = false
return (...args: Parameters<T>) => {
if (!inThrottle) {
func(...args)
inThrottle = true
setTimeout(() => (inThrottle = false), limit)
}
}
}
// 深拷贝
export function deepClone<T>(obj: T): T {
if (obj === null || typeof obj !== 'object') {
return obj
}
if (obj instanceof Date) {
return new Date(obj.getTime()) as T
}
if (obj instanceof Array) {
return obj.map(item => deepClone(item)) as T
}
if (typeof obj === 'object') {
const clonedObj = {} as T
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key])
}
}
return clonedObj
}
return obj
}
// 生成随机ID
export function generateId(length = 8): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
let result = ''
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length))
}
return result
}
// 验证邮箱
export function isValidEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
return emailRegex.test(email)
}
// 验证手机号
export function isValidPhone(phone: string): boolean {
const phoneRegex = /^1[3-9]\d{9}$/
return phoneRegex.test(phone)
}
// 计算两个日期之间的天数差
export function daysBetween(date1: Date | string, date2: Date | string): number {
const d1 = new Date(date1)
const d2 = new Date(date2)
const diffTime = Math.abs(d2.getTime() - d1.getTime())
return Math.ceil(diffTime / (1000 * 60 * 60 * 24))
}
// 获取季节
export function getSeason(date: Date | string = new Date()): string {
const d = new Date(date)
const month = d.getMonth() + 1
if (month >= 3 && month <= 5) return '春季'
if (month >= 6 && month <= 8) return '夏季'
if (month >= 9 && month <= 11) return '秋季'
return '冬季'
}