u
This commit is contained in:
1 parent
6277fb2f9e
commit
8ecac0d7dd
270 files changed
+40438
-529
No files matched your search
@@ -0,0 +1,26 @@
|
||||
// utils/math.ts
|
||||
import Big from 'big.js'
|
||||
|
||||
/**
|
||||
* 加法(保留两位小数)
|
||||
*/
|
||||
export function add(a: string | number, b: string | number): string {
|
||||
try {
|
||||
return new Big(a).plus(new Big(b)).toFixed(2) // ⭐ 保留两位
|
||||
}
|
||||
catch {
|
||||
return '0.00'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 减法(保留两位小数)
|
||||
*/
|
||||
export function sub(a: string | number, b: string | number): string {
|
||||
try {
|
||||
return new Big(a).minus(new Big(b)).toFixed(2) // ⭐ 保留两位
|
||||
}
|
||||
catch {
|
||||
return '0.00'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
/**
|
||||
* 获取当前日期,默认格式: YYYY-MM-DD
|
||||
*/
|
||||
export function getCurrentDate(format = 'YYYY-MM-DD'): string {
|
||||
return dayjs().format(format)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期时间,默认格式: YYYY-MM-DD HH:mm:ss
|
||||
*/
|
||||
export function getCurrentDateTime(format = 'YYYY-MM-DD HH:mm:ss'): string {
|
||||
return dayjs().format(format)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间,默认格式: HH:mm:ss
|
||||
*/
|
||||
export function getCurrentTime(format = 'HH:mm:ss'): string {
|
||||
return dayjs().format(format)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前年月,默认格式: YYYY-MM
|
||||
*/
|
||||
export function getCurrentYearMonth(format = 'YYYY-MM'): string {
|
||||
return dayjs().format(format)
|
||||
}
|
||||
|
||||
/** 字符串 / 数字 / Date → Date(无效返回 null) */
|
||||
export function toDate(input: string | number | Date | undefined | null): Date {
|
||||
if (!input)
|
||||
return new Date()
|
||||
if (input instanceof Date)
|
||||
return input
|
||||
|
||||
const d = dayjs(input)
|
||||
return d.isValid() ? d.toDate() : new Date()
|
||||
}
|
||||
|
||||
/** Date → YYYY-MM-DD */
|
||||
export function toDateString(date: string | number | Date): string {
|
||||
const d = dayjs(toDate(date))
|
||||
return d.isValid() ? d.format('YYYY-MM-DD') : ''
|
||||
}
|
||||
|
||||
/** Date → YYYY-MM */
|
||||
export function toYearMonthString(date: string | number | Date): string {
|
||||
const d = dayjs(toDate(date))
|
||||
return d.isValid() ? d.format('YYYY-MM') : ''
|
||||
}
|
||||
|
||||
/** Date → HH:mm:ss */
|
||||
export function toTimeString(date: string | number | Date): string {
|
||||
const d = dayjs(toDate(date))
|
||||
return d.isValid() ? d.format('HH:mm:ss') : ''
|
||||
}
|
||||
|
||||
/** Date → YYYY-MM-DD HH:mm:ss */
|
||||
export function toDateTimeString(date: string | number | Date): string {
|
||||
const d = dayjs(toDate(date))
|
||||
return d.isValid() ? d.format('YYYY-MM-DD HH:mm:ss') : ''
|
||||
}
|
||||
|
||||
export function isInMonth(date: string, month: string): boolean {
|
||||
// date 形如 "2025-01-12"
|
||||
// month 形如 "2025-01"
|
||||
return dayjs(date).format('YYYY-MM') === month
|
||||
}
|
||||
|
||||
export function formatRelativeTime(date: string | Date | number): string {
|
||||
if (typeof date === 'string' && !date.trim()) {
|
||||
return '暂无活跃'
|
||||
}
|
||||
|
||||
const d = dayjs(date)
|
||||
if (!d.isValid())
|
||||
return '暂无活跃'
|
||||
|
||||
const now = dayjs()
|
||||
const diff = now.diff(d, 'second') // 相差秒数
|
||||
|
||||
if (diff < 60) {
|
||||
return '刚刚'
|
||||
}
|
||||
else if (diff < 3600) {
|
||||
const minutes = Math.floor(diff / 60)
|
||||
return `${minutes}分钟前`
|
||||
}
|
||||
else if (diff < 86400) {
|
||||
const hours = Math.floor(diff / 3600)
|
||||
return `${hours}小时前`
|
||||
}
|
||||
else if (diff < 2592000) { // 30天以内
|
||||
const days = Math.floor(diff / 86400)
|
||||
return `${days}天前`
|
||||
}
|
||||
else if (diff < 31536000) { // 1年以内
|
||||
const months = Math.floor(diff / 2592000)
|
||||
return `${months}个月前`
|
||||
}
|
||||
else {
|
||||
const years = Math.floor(diff / 31536000)
|
||||
return `${years}年前`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import type { IToastProps } from '@gluestack-ui/core/lib/esm/toast/creator/types'
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { Toast, ToastDescription, ToastTitle, useToast as useGluestackToast } from '@/components/ui/toast'
|
||||
|
||||
type ToastVariant = 'solid' | 'outline'
|
||||
type ToastAction = 'error' | 'warning' | 'success' | 'info' | 'muted'
|
||||
|
||||
interface ShowToastOptions extends IToastProps {
|
||||
title?: React.ReactNode
|
||||
description?: React.ReactNode
|
||||
variant?: ToastVariant
|
||||
type?: ToastAction
|
||||
}
|
||||
|
||||
// 全局 toast 实例
|
||||
let globalToast: {
|
||||
show: (options: ShowToastOptions) => string
|
||||
close: (id: string) => void
|
||||
closeAll: () => void
|
||||
isActive: (id: string) => boolean
|
||||
} | null = null
|
||||
|
||||
export function ToastProviderWrapper({ children }: { children: React.ReactNode }) {
|
||||
const toast = useGluestackToast()
|
||||
const toastRef = useRef(toast)
|
||||
toastRef.current = toast
|
||||
|
||||
useEffect(() => {
|
||||
globalToast = {
|
||||
show: (options: ShowToastOptions) => {
|
||||
const id = Math.random().toString()
|
||||
toast.show({
|
||||
id,
|
||||
placement: options.placement ?? 'top',
|
||||
duration: options.duration ?? 3000,
|
||||
avoidKeyboard: options.avoidKeyboard ?? false,
|
||||
containerStyle: options.containerStyle,
|
||||
onCloseComplete: options.onCloseComplete,
|
||||
render: options.render
|
||||
? () => options.render!({ id })
|
||||
: ({ id }) => (
|
||||
<Toast
|
||||
nativeID={`toast-${id}`}
|
||||
variant={options.variant ?? 'solid'}
|
||||
action={options.type ?? 'muted'}
|
||||
>
|
||||
{options.title && <ToastTitle className="font-blod">{options.title}</ToastTitle>}
|
||||
{options.description && <ToastDescription>{options.description}</ToastDescription>}
|
||||
</Toast>
|
||||
),
|
||||
})
|
||||
return id
|
||||
},
|
||||
close: (id: string) => {
|
||||
toast.close(id)
|
||||
},
|
||||
closeAll: () => {
|
||||
toast.closeAll()
|
||||
},
|
||||
isActive: (id: string) => toast.isActive(id),
|
||||
}
|
||||
}, [toast])
|
||||
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局 toast 对象,组件内外都可以使用
|
||||
*/
|
||||
export const toast = {
|
||||
show: (options: ShowToastOptions) => {
|
||||
if (!globalToast) {
|
||||
console.warn('Toast not initialized. Make sure ToastProviderWrapper is rendered.')
|
||||
return ''
|
||||
}
|
||||
return globalToast.show(options)
|
||||
},
|
||||
close: (id: string) => {
|
||||
if (globalToast)
|
||||
globalToast.close(id)
|
||||
},
|
||||
closeAll: () => {
|
||||
if (globalToast)
|
||||
globalToast.closeAll()
|
||||
},
|
||||
isActive: (id: string) => {
|
||||
return globalToast ? globalToast.isActive(id) : false
|
||||
},
|
||||
}
|
||||
Reference in new issue
Block a user