import React, { Component, HTMLAttributes } from 'react' import Big from 'big.js' import eventBus from './event_bus' import { Storage } from '../storage' import { symbolKey, unitKey } from './constant' interface PriceProps extends HTMLAttributes { value: number /* 保留几位小数 */ precision?: number /* 是否使用千分符 */ useGrouping?: boolean /* 货币符号缩放大小 */ currencyScale?: number /* 保留小数点后无效的零 */ keepZero?: boolean isFenUnit?: boolean feeType?: string } interface CurrencyListOptions { symbol: string type: string unit: string } let currencyList: CurrencyListOptions[] = [] function getCurrentFromType(type: string): CurrencyListOptions | undefined { return currencyList.find((value) => value.type === type) } let symbol = Storage.get(symbolKey) ?? '¥' let unit = Storage.get(unitKey) ?? '元' class Price extends Component { /** * 设置符号列表 */ static setCurrencyList(list: CurrencyListOptions[]): void { if (!list || !list.length) { return } currencyList = list } /** * 设置符号 */ static setCurrency(_symbol: string): void { if (!_symbol || _symbol === symbol) { return } Storage.set(symbolKey, _symbol) symbol = _symbol eventBus.dispatch('REACT_GM_UPDATE_PRICE') } /** * 获取符号 */ static getCurrency(type = ''): string { const current = type ? getCurrentFromType(type) : null return current ? current.symbol : (symbol as string) } static setUnit(_unit: string): void { if (!_unit || _unit === unit) { return } Storage.set(unitKey, _unit) unit = _unit } static getUnit(type = ''): string { const current = type ? getCurrentFromType(type) : null return current ? current.unit : (unit as string) } static defaultProps = { precision: 2, useGrouping: true, currencyScale: 0.85, keepZero: true, feeType: '', } componentDidMount() { eventBus.add('REACT_GM_UPDATE_PRICE', this._rerender) } componentWillUnmount() { eventBus.remove('REACT_GM_UPDATE_PRICE', this._rerender) } private _rerender = (): void => { this.forceUpdate() } private _formatValue = ( value: number, precision: number, keepZero: boolean, isFenUnit: boolean ): string => { if (isNaN(value)) { console.trace('value can not be NaN') return '' } const divRatio = isFenUnit ? 100 : 1 const result = Big(Math.abs(value)).div(divRatio).toFixed(precision) return keepZero ? result : `${parseFloat(result)}` } /** * 增加千分符 */ private _addComma = (useGrouping: boolean, num: string): string => { if (!useGrouping) { return num } return num.toString().replace(/^\d+/g, (m) => m.replace(/(?=(?!^)(\d{3})+$)/g, ',')) } render() { const { value, useGrouping, precision, currencyScale, keepZero, isFenUnit, feeType, ...rest } = this.props const current = getCurrentFromType(feeType!) return ( {value < 0 ? '-' : ''} 1 ? '1' : currencyScale}em` }}> {current ? current.symbol : symbol} {this._addComma( !!useGrouping, this._formatValue(value, precision!, !!keepZero, !!isFenUnit) )} ) } } export default Price export type { PriceProps, CurrencyListOptions }