index.vue 5.55 KB
<template>
	<text class="zui-amount" :class="{ numerical: !isCapital }">
		<slot v-if="$slots.prefix" name="prefix"></slot>
		<template v-else-if="prefix">
			{{ prefix }}
		</template>
		<template v-if="!isCapital">
			{{ Number(value || 0) | doPrecision(precision > 0 ? precision : 0, isRoundUp) | doFormat(hasSeparator, separator) }}
		</template>
		<template v-else>
			{{ Number(value || 0) | doPrecision(4, isRoundUp) | doCapital }}
		</template>
	</text>
</template>

<script>
/* istanbul ignore file */
var formatValueByGapStep = function(step, value, gap, direction, range, isAdd, oldValue) {
	var gap = gap || ' ';
	var direction = direction || 'right';
	var isAdd = isAdd || 1;
	var oldValue = oldValue || 0;
	if (value.length == 0) {
		return { value: value, range: range };
	}
	var arr = value && value.split('');
	var _range = range;
	var showValue = '';
	if (direction == 'right') {
		for (var j = arr.length - 1, k = 0; j >= 0; j--, k++) {
			var m = arr[j];
			showValue = k > 0 && k % step == 0 ? m + gap + showValue : m + '' + showValue;
		}
		if (isAdd == 1) {
			// 在添加的情况下,如果添加前字符串的长度减去新的字符串的长度为2,说明多了一个间隔符,需要调整range
			if (oldValue.length - showValue.length == -2) {
				_range = range + 1;
			}
		} else {
			// 在删除情况下,如果删除前字符串的长度减去新的字符串的长度为2,说明少了一个间隔符,需要调整range
			if (oldValue.length - showValue.length == 2) {
				_range = range - 1;
			}
			// 删除到最开始,range 保持 0
			if (_range <= 0) {
				_range = 0;
			}
		}
	} else {
		arr.some(function(n, i) {
			showValue = i > 0 && i % step == 0 ? showValue + gap + n : showValue + '' + n;
		});
		var adapt = range % (step + 1) == 0 ? 1 * isAdd : 0;
		_range = typeof range !== 'undefined' ? (range == 0 ? 0 : range + adapt) : showValue.length;
	}
	return { value: showValue, range: _range };
};
var numberCapital = function(number) {
	var cnNums = ['\u96f6', '\u58f9', '\u8d30', '\u53c1', '\u8086', '\u4f0d', '\u9646', '\u67d2', '\u634c', '\u7396'];
	// 拾 \u62fe 佰 \u4f70 仟 \u4edf
	var cnIntRadice = ['', '\u62fe', '\u4f70', '\u4edf'];
	// 万 \u4e07 亿 \u4ebf 兆 \u5146
	var cnIntUnits = ['', '\u4e07', '\u4ebf', '兆'];
	// 角 \u89d2 分 \u5206 毫 \u6beb 厘 \u5398
	var cnDecUnits = ['\u89d2', '\u5206', '\u6beb', '\u5398'];
	var cnInteger = '\u6574'; // 整 \u6574
	var cnIntLast = '\u5143'; // 元 \u5143
	var cnNegative = '\u8d1f'; // 负
	// Maximum number
	var maxNum = 999999999999999.9999;
	var negative;
	// Integral part
	var integerNum;
	// Decimal part
	var decimalNum;
	// Capital number
	var capitalStr = '';
	var parts;
	/* istanbul ignore if  */
	if (number == '') {
		return '';
	}
	number = parseFloat(number);
	if (number < 0) {
		negative = true;
		number = Math.abs(number);
	}
	/* istanbul ignore if  */
	if (number >= maxNum) {
		return '';
	}
	/* istanbul ignore if  */
	if (number == 0) {
		capitalStr = cnNums[0] + cnIntLast + cnInteger;
		return capitalStr;
	}
	// Convert to String
	number += '';
	if (number.indexOf('.') == -1) {
		integerNum = number;
		decimalNum = '';
	} else {
		parts = number.split('.');
		integerNum = parts[0];
		decimalNum = parts[1].substr(0, 4);
	}
	// Convert integer part
	if (parseInt(integerNum, 10) > 0) {
		var zeroCount = 0;
		for (var i = 0, IntLen = integerNum.length; i < IntLen; i++) {
			var n = integerNum.substr(i, 1);
			var p = IntLen - i - 1;
			var q = p / 4;
			var m = p % 4;
			if (n == '0') {
				zeroCount++;
			} else {
				if (zeroCount > 0) {
					capitalStr += cnNums[0];
				}
				zeroCount = 0;
				capitalStr += cnNums[parseInt(n)] + cnIntRadice[m];
			}
			if (m == 0 && zeroCount < 4) {
				capitalStr += cnIntUnits[q];
			}
		}
		capitalStr += cnIntLast;
	}
	// Convert decimal part
	if (decimalNum !== '') {
		for (var i = 0, decLen = decimalNum.length; i < decLen; i++) {
			var n = decimalNum.substr(i, 1);
			if (n !== '0') {
				capitalStr += cnNums[Number(n)] + cnDecUnits[i];
			}
		}
	}
	/* istanbul ignore if  */
	if (capitalStr == '') {
		capitalStr += cnNums[0] + cnIntLast + cnInteger;
	} else if (decimalNum == '') {
		capitalStr += cnInteger;
	}
	if (negative) {
		capitalStr = '' + cnNegative + capitalStr;
	}
	return capitalStr;
};
export default {
	name: 'zui-amount',
	filters: {
		doPrecision: function(value, precision, isRoundUp) {
			var exponentialForm = Number(value + 'e' + precision);
			var rounded = isRoundUp ? Math.round(exponentialForm) : Math.floor(exponentialForm);
			return Number(rounded + 'e-' + precision).toFixed(precision);
		},
		doFormat: function(value, hasSeparator, separator) {
			if (!hasSeparator) {
				return value;
			}
			var numberParts = value.split('.');
			var integerValue = numberParts[0];
			var decimalValue = numberParts[1] || '';
			var sign = '';
			if (integerValue.startsWith('-')) {
				integerValue = integerValue.substring(1);
				sign = '-';
			}
			var formateValue = formatValueByGapStep(3, integerValue, separator, 'right', 0, 1);
			return decimalValue ? '' + sign + formateValue.value + '.' + decimalValue : '' + sign + formateValue.value;
		},
		doCapital: function(value) {
			return numberCapital(value);
		}
	},
	props: {
		value: {
			type: [Number, String],
			default: 0
		},
		precision: {
			type: Number,
			default: 2
		},
		isRoundUp: {
			type: Boolean,
			default: true
		},
		hasSeparator: {
			type: Boolean,
			default: false
		},
		separator: {
			type: String,
			default: ','
		},
		isCapital: {
			type: Boolean,
			default: false
		},
		prefix: String
	},
};
</script>

<style lang="scss">
@import './index.scss';
</style>