Skip to content

Commit 224868e

Browse files
committed
Merge branch 'feat/rmb-numbers' into chore/all-my-stuffs
# Conflicts: # src/tools/index.ts
2 parents a016bb5 + 6530d37 commit 224868e

File tree

6 files changed

+162
-2
lines changed

6 files changed

+162
-2
lines changed

pnpm-lock.yaml

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/tools/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import { tool as qrCodeDecoder } from './qr-code-decoder';
7474
import { tool as markdownToHtml } from './markdown-to-html';
7575
import { tool as nginxFormatter } from './nginx-formatter';
7676
import { tool as potrace } from './potrace';
77+
import { tool as rmbNumbers } from './rmb-numbers';
7778
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
7879
import { tool as numeronymGenerator } from './numeronym-generator';
7980
import { tool as macAddressGenerator } from './mac-address-generator';
@@ -223,6 +224,7 @@ export const toolsByCategory: ToolCategory[] = [
223224
jsonToCsharp,
224225
jsonToGo,
225226
markdownTocGenerator,
227+
rmbNumbers,
226228
],
227229
},
228230
{

src/tools/rmb-numbers/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { CurrencyYen } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'RMB Uppercase Converter',
6+
path: '/rmb-numbers',
7+
description: 'RMB/Renminbi Capitalization Conversion Tool',
8+
keywords: ['rmb', 'renminbi', 'cny', 'number', 'uppercase', '人民币', '大写', '转换'],
9+
component: () => import('./rmb-numbers.vue'),
10+
icon: CurrencyYen,
11+
createdAt: new Date('2024-04-29'),
12+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { rmb } from './rmb-numbers.service';
3+
4+
describe('rmb-case-converter', () => {
5+
it('rmb to convert rmb numbers to uppercase', async () => {
6+
expect(rmb(123)).to.deep.equal([
7+
{
8+
type: 'number',
9+
value: '壹',
10+
},
11+
{
12+
type: 'unit',
13+
value: '佰',
14+
},
15+
{
16+
type: 'number',
17+
value: '贰',
18+
},
19+
{
20+
type: 'unit',
21+
value: '拾',
22+
},
23+
{
24+
type: 'number',
25+
value: '叁',
26+
},
27+
{
28+
type: 'unit',
29+
value: '元',
30+
},
31+
{
32+
type: 'cut',
33+
value: '整',
34+
},
35+
]);
36+
});
37+
});
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
export { rmb };
2+
3+
const numbers = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
4+
const leftUnits = ['元', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟', '万', '拾', '佰', '仟', '万'];
5+
const rightUnits = ['角', '分'];
6+
7+
function rmb(value: number) {
8+
if (Object.prototype.toString.call(value) === '[object Number]' && value >= 0.01) {
9+
const fragment: any = [];
10+
const [leftValues, rightValues] = String(value).split('.').map(part => part.split('').map(i => Number(i)));
11+
12+
const leftValueLength = leftValues.length; // 整数部分位数
13+
const unit1 = leftValueLength - 1; // 元位
14+
const unit5 = leftValueLength - 5; // 万位
15+
const unit9 = leftValueLength - 9; // 亿位
16+
const unit13 = leftValueLength - 13; // 万亿位
17+
const unit17 = leftValueLength - 17; // 万万亿位
18+
const hasLeftValue = leftValueLength > 1 || leftValues[0] > 0; // 整数部分不为0
19+
const hasRightValue = rightValues && (rightValues[0] > 0 || rightValues[1] > 0); // 小数部分不为0
20+
const has678Value = leftValues[unit5 - 1] > 0 || leftValues[unit5 - 2] > 0 || leftValues[unit5 - 3] > 0; // 拾万、佰万或仟万位不为0
21+
const overflowIndex = leftValueLength - leftUnits.length; // 溢出位索引
22+
23+
let leftUnitIndex = 0;
24+
for (let i = leftValueLength - 1; i >= 0; i--) {
25+
if (leftValues[i] === 0 && (i === unit5 || i === unit9 || i === unit13 || i === unit17) && leftValues[i + 1] > 0) {
26+
// 当前位为0,且当前位为万、亿、万亿、万万亿,且低一位不为0
27+
fragment.unshift({ type: 'number', value: numbers[leftValues[i]] });
28+
}
29+
30+
if ((leftValues[i] > 0) || (i === unit1 && hasLeftValue) || (i === unit5 && has678Value) || i === unit9 || i === unit13 || i === unit17) {
31+
// 元、万、亿、万亿、万万亿或当前位不为0
32+
fragment.unshift({ type: 'unit', value: leftUnits[leftUnitIndex] });
33+
}
34+
35+
if (leftValues[i] > 0 || (leftValues[i + 1] > 0 && i !== unit5 && i !== unit9 && i !== unit13 && i !== unit17) || i <= overflowIndex) {
36+
// 当前位不为0,或低一位不为0且当前位非万、亿、万亿、万万亿,或当前为溢出位
37+
fragment.unshift({ type: 'number', value: numbers[leftValues[i]] });
38+
}
39+
40+
leftUnitIndex++;
41+
}
42+
43+
if (hasRightValue) {
44+
// 角
45+
if (rightValues[0] > 0 || hasLeftValue) { // 角位不为0,或整数位不为0
46+
fragment.push({ type: 'number', value: numbers[rightValues[0]] });
47+
}
48+
if (rightValues[0] > 0) { // 角位不为0
49+
fragment.push({ type: 'unit', value: rightUnits[0] });
50+
}
51+
// 分
52+
if (rightValues[1] > 0) {
53+
fragment.push({ type: 'number', value: numbers[rightValues[1]] });
54+
fragment.push({ type: 'unit', value: rightUnits[1] });
55+
}
56+
}
57+
else { // 没有小数位
58+
fragment.push({ type: 'cut', value: '整' });
59+
}
60+
return fragment;
61+
}
62+
return [
63+
{ type: 'number', value: '零' },
64+
{ type: 'unit', value: '元' },
65+
{ type: 'cut', value: '整' },
66+
];
67+
};

src/tools/rmb-numbers/rmb-numbers.vue

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<script setup lang="ts">
2+
import { useThemeVars } from 'naive-ui';
3+
import { rmb } from './rmb-numbers.service';
4+
5+
const themeVars = useThemeVars();
6+
const inputRmb = ref(23);
7+
const outputRmb = computed(() => rmb(inputRmb.value)); ;
8+
</script>
9+
10+
<template>
11+
<div flex flex-col gap-2>
12+
<c-card title="Lower Case Amount">
13+
<n-input-number v-model:value="inputRmb" max="100000000000" min="0" placeholder="Enter the amount in lowercase (example: 1314.52)" :show-button="false" w-full />
14+
</c-card>
15+
16+
<div my-16px divider />
17+
18+
<c-card title="Amount in Capital Letters" flex flex-col>
19+
<div m-0 m-x-auto>
20+
<span
21+
v-for="(item, index) in outputRmb"
22+
:key="index"
23+
:class="item.type"
24+
>
25+
{{ item.value }}
26+
</span>
27+
</div>
28+
</c-card>
29+
</div>
30+
</template>
31+
32+
<style lang="less" scoped>
33+
.unit {
34+
font-size: 1.4em;
35+
color: v-bind('themeVars.successColor');
36+
}
37+
.number {
38+
font-size: 2.4em;
39+
}
40+
.cut {
41+
font-size: 1.4em;
42+
color: v-bind('themeVars.errorColor');
43+
}
44+
</style>

0 commit comments

Comments
 (0)