mirror of
https://github.com/XiaoDaiGua-Ray/ray-template.git
synced 2025-04-05 07:03:00 +08:00
276 lines
6.2 KiB
TypeScript
276 lines
6.2 KiB
TypeScript
/**
|
||
*
|
||
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||
*
|
||
* @date 2023-06-07
|
||
*
|
||
* @workspace ray-template
|
||
*
|
||
* @remark 今天也是元气满满撸代码的一天
|
||
*/
|
||
|
||
/**
|
||
*
|
||
* 文档地址: <https://currency.js.org/#subtract>
|
||
*
|
||
* Options 默认值
|
||
* - symbol default: `$`(货币符号)
|
||
* - separator default: `,`(数字分隔符, demo: 1234.56 => '1,234.56')
|
||
* - decimal default: `.`(十进制分隔符, demo: 1.23 => '1.23')
|
||
* - precision default: `2`(精度保留位数)
|
||
* - pattern default: `!#`(!: 货币符号代替, #: 货币金额代替)
|
||
* - negativePattern default: `!#`(!: 货币符号代替, #: 货币金额代替)
|
||
* - format default: `null`(默认格式化方法替代, 看文档)
|
||
* - fromCents default: `false`(尊重精度选项)
|
||
* - errorOnInvalid default: `false`(传入 null undefined 直接抛出错误)
|
||
* - increment default: `null`(四舍五入增量值)
|
||
* - useVedic default: `false`(分组格式化值, demo: currency(1234567.89, { useVedic: true }).format() => '12,34,567.89')
|
||
*/
|
||
|
||
import currency from 'currency.js'
|
||
import { cloneDeep } from 'lodash-es'
|
||
import { isValueType } from '@/utils'
|
||
|
||
import type { Options } from 'currency.js'
|
||
import type { AnyFC } from '@/types'
|
||
|
||
export type CurrencyArguments = string | number | currency
|
||
|
||
export type OriginalValueType = 'string' | 'number'
|
||
|
||
export interface CurrencyOptions extends Options {
|
||
type?: OriginalValueType
|
||
}
|
||
|
||
// currency.js 默认配置
|
||
const defaultOptions: Partial<CurrencyOptions> = {
|
||
precision: 8,
|
||
decimal: '.',
|
||
}
|
||
// currency.js 原型属性集合
|
||
const currencyPrototypeKeys = [
|
||
's',
|
||
'intValue',
|
||
'p',
|
||
'value',
|
||
'toJSON',
|
||
'add',
|
||
'cents',
|
||
'distribute',
|
||
'divide',
|
||
'dollars',
|
||
'format',
|
||
'multiply',
|
||
'subtract',
|
||
'toString',
|
||
]
|
||
|
||
/**
|
||
*
|
||
* @param valueOptions 待计算参数列表
|
||
* @param dividend 初始值
|
||
* @param cb 回调方法
|
||
*
|
||
* @description
|
||
* 计算基础方法, 仅限于该处使用。
|
||
*/
|
||
const basic = (
|
||
valueOptions: CurrencyArguments[],
|
||
dividend: CurrencyArguments,
|
||
cb: AnyFC,
|
||
) => {
|
||
if (!valueOptions?.length) {
|
||
return 0
|
||
}
|
||
|
||
if (valueOptions.length === 1) {
|
||
return currency(valueOptions[0], defaultOptions)
|
||
}
|
||
|
||
const result = valueOptions.reduce((pre, curr, idx, arr) => {
|
||
pre = cb?.(pre, curr, idx, arr)
|
||
|
||
return pre
|
||
}, dividend)
|
||
|
||
return result
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param value 待判断值
|
||
*
|
||
* 检查一个对象是否为 currency.js 的对象
|
||
* 当该对象含有 s, intValue, p, value... 属性时, 则认为该对象为 currency.js 的对象
|
||
*
|
||
* @example
|
||
* isCurrency(1.23) // false
|
||
* isCurrency('1.23') // false
|
||
* isCurrency({ s: 1, intValue: 1, p: 1, value: 1 }) // false
|
||
* isCurrency(currency(1)) // true
|
||
*/
|
||
export const isCurrency = (value: unknown) => {
|
||
if (typeof value === 'string' || typeof value === 'number') {
|
||
return false
|
||
}
|
||
|
||
if (isValueType<object>(value, 'Object')) {
|
||
return currencyPrototypeKeys.every((key) => Reflect.has(value, key))
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @description
|
||
* 格式化一个数据值, 并且返回其原始值。
|
||
*
|
||
* 默认以 number 格式返回。
|
||
*
|
||
* 如果需要格式化为其他格式(如: 货币单位、分组、分隔符等), 请使用 currency format 方法格式。
|
||
*
|
||
* @example
|
||
* format(0.1) // 0.1
|
||
* format(0.1, { symbol: '¥' }) // ¥0.1
|
||
*/
|
||
export const format = (value: CurrencyArguments, options?: CurrencyOptions) => {
|
||
const assignOptions = Object.assign({}, defaultOptions, options)
|
||
const v = currency(value, assignOptions)
|
||
const { type = 'number' } = assignOptions
|
||
|
||
return type === 'number' ? v.value : v.toString()
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @description
|
||
* 加法。
|
||
*
|
||
* @example
|
||
* format(add(0.1, 0.2)) // 0.3
|
||
* format(add(0.2, 0.33)) // 0.53
|
||
*/
|
||
export const add = (...args: CurrencyArguments[]) => {
|
||
if (args.length === 1) {
|
||
return currency(args[0], defaultOptions).add(0)
|
||
}
|
||
|
||
return basic(args, 0, (pre, curr) => {
|
||
return currency(pre, defaultOptions).add(curr)
|
||
})
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @description
|
||
* 减法。
|
||
*
|
||
* @example
|
||
* format(subtract(0.1, 0.12312)) // -0.02
|
||
* format(subtract(0.2, 0.33)) // -0.13
|
||
*/
|
||
export const subtract = (...args: CurrencyArguments[]) => {
|
||
if (args.length === 1) {
|
||
return currency(args[0], defaultOptions).subtract(0)
|
||
}
|
||
|
||
if (args.length === 2) {
|
||
const [one, two] = args
|
||
|
||
return currency(one, defaultOptions).subtract(two)
|
||
}
|
||
|
||
const cloneDeepArgs = cloneDeep(args)
|
||
const dividend = cloneDeepArgs.shift() as CurrencyArguments
|
||
|
||
if (!cloneDeepArgs.length) {
|
||
return dividend
|
||
}
|
||
|
||
return basic(cloneDeepArgs, dividend, (pre, curr) => {
|
||
return currency(pre, defaultOptions).subtract(curr)
|
||
})
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @description
|
||
* 乘法。
|
||
*
|
||
* @example
|
||
* format(multiply(1, 0.2)) // 0.2
|
||
* format(multiply(0.2, 0.33)) // 0.07
|
||
*/
|
||
export const multiply = (...args: CurrencyArguments[]) => {
|
||
if (args.length === 1) {
|
||
return currency(args[0], defaultOptions).multiply(1)
|
||
}
|
||
|
||
return basic(args, 1, (pre, curr) => {
|
||
return currency(pre, defaultOptions).multiply(curr)
|
||
})
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @description
|
||
* 除法。
|
||
*
|
||
* @example
|
||
* format(divide(1, 0.2)) // 5
|
||
* format(divide(0.2, 0.33)) // 0.61
|
||
*/
|
||
export const divide = (...args: CurrencyArguments[]) => {
|
||
if (args.length === 1) {
|
||
return currency(args[0], defaultOptions).divide(1)
|
||
}
|
||
|
||
if (args.length === 2) {
|
||
const [one, two] = args
|
||
|
||
return currency(one, defaultOptions).divide(two)
|
||
}
|
||
|
||
const cloneDeepArgs = cloneDeep(args)
|
||
const dividend = cloneDeepArgs.shift() as CurrencyArguments
|
||
|
||
return basic(cloneDeepArgs, dividend, (pre, curr) => {
|
||
return currency(pre, defaultOptions).divide(curr)
|
||
})
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @description
|
||
* 平分(将一个数值平均分配到一个数组中),
|
||
* 如果值为 undefined null 会自动转换为 0
|
||
*
|
||
* @example
|
||
* distribute(0, 1) // [0]
|
||
* distribute(0, 3) // [0, 0, 0]
|
||
*/
|
||
export const distribute = (
|
||
value: CurrencyArguments,
|
||
length: number,
|
||
options?: CurrencyOptions,
|
||
) => {
|
||
if (length <= 1) {
|
||
return [value ? value : 0]
|
||
} else {
|
||
if (!value) {
|
||
return new Array(length).fill(0)
|
||
}
|
||
}
|
||
|
||
const assignOptions = Object.assign({}, defaultOptions, options)
|
||
|
||
const result = currency(value, assignOptions)
|
||
.distribute(length)
|
||
.map((curr) => {
|
||
return format(curr, assignOptions)
|
||
})
|
||
|
||
return result
|
||
}
|