@tuya-miniapp/smart-ui 2.12.0-beta-4 → 2.12.0-beta-5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/field/index.js +65 -10
- package/dist/field/numberFormat.d.ts +11 -0
- package/dist/field/numberFormat.js +148 -0
- package/lib/field/index.js +65 -10
- package/lib/field/numberFormat.d.ts +11 -0
- package/lib/field/numberFormat.js +154 -0
- package/package.json +1 -1
package/dist/field/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { SmartComponent } from '../common/component';
|
|
|
3
3
|
import { commonProps, inputProps, textareaProps } from './props';
|
|
4
4
|
import Xmark from '@tuya-miniapp/icons/dist/svg/Xmark';
|
|
5
5
|
import tyApi from '../common/ty';
|
|
6
|
+
import { formatNumber, parseFormattedNumber } from './numberFormat';
|
|
6
7
|
SmartComponent({
|
|
7
8
|
field: true,
|
|
8
9
|
classes: ['input-class', 'right-icon-class', 'label-class'],
|
|
@@ -29,6 +30,12 @@ SmartComponent({
|
|
|
29
30
|
}, extraEventParams: {
|
|
30
31
|
type: Boolean,
|
|
31
32
|
value: false,
|
|
33
|
+
}, numberFormat: {
|
|
34
|
+
type: Boolean,
|
|
35
|
+
value: false,
|
|
36
|
+
}, locale: {
|
|
37
|
+
type: String,
|
|
38
|
+
value: '',
|
|
32
39
|
} }),
|
|
33
40
|
data: {
|
|
34
41
|
focused: false,
|
|
@@ -38,18 +45,24 @@ SmartComponent({
|
|
|
38
45
|
watch: {
|
|
39
46
|
value(value) {
|
|
40
47
|
if (value !== this.value) {
|
|
41
|
-
this.setData({ innerValue: value });
|
|
42
48
|
this.value = value;
|
|
49
|
+
this.updateDisplayValue();
|
|
43
50
|
this.setShowClear();
|
|
44
51
|
}
|
|
45
52
|
},
|
|
53
|
+
numberFormat() {
|
|
54
|
+
this.updateDisplayValue();
|
|
55
|
+
},
|
|
56
|
+
locale() {
|
|
57
|
+
this.updateDisplayValue();
|
|
58
|
+
},
|
|
46
59
|
clearTrigger() {
|
|
47
60
|
this.setShowClear();
|
|
48
61
|
},
|
|
49
62
|
},
|
|
50
63
|
created() {
|
|
51
64
|
this.value = this.data.value;
|
|
52
|
-
this.
|
|
65
|
+
this.updateDisplayValue();
|
|
53
66
|
},
|
|
54
67
|
methods: {
|
|
55
68
|
formatValue(value) {
|
|
@@ -59,10 +72,29 @@ SmartComponent({
|
|
|
59
72
|
}
|
|
60
73
|
return value;
|
|
61
74
|
},
|
|
75
|
+
// 更新显示值(根据 numberFormat 决定是否格式化)
|
|
76
|
+
// 聚焦时保留末尾小数点(如 23.)不格式化掉,避免打断用户输入;失焦后再做完整格式化
|
|
77
|
+
updateDisplayValue() {
|
|
78
|
+
const { numberFormat, locale } = this.data;
|
|
79
|
+
let displayValue = this.value || '';
|
|
80
|
+
if (numberFormat && displayValue) {
|
|
81
|
+
const preserveTrailingDecimal = !!this.focused;
|
|
82
|
+
displayValue = formatNumber(displayValue, locale, { preserveTrailingDecimal });
|
|
83
|
+
}
|
|
84
|
+
this.setData({ innerValue: displayValue });
|
|
85
|
+
},
|
|
62
86
|
onInput(event) {
|
|
63
87
|
const { value = '' } = event.detail || {};
|
|
64
|
-
const
|
|
88
|
+
const { numberFormat, locale } = this.data;
|
|
89
|
+
let rawValue = value;
|
|
90
|
+
// 如果启用了数字格式化,需要将格式化后的输入值解析为原始格式
|
|
91
|
+
if (numberFormat) {
|
|
92
|
+
rawValue = parseFormattedNumber(value, locale);
|
|
93
|
+
}
|
|
94
|
+
const formatValue = this.formatValue(rawValue);
|
|
65
95
|
this.value = formatValue;
|
|
96
|
+
// 更新显示值
|
|
97
|
+
this.updateDisplayValue();
|
|
66
98
|
this.setShowClear();
|
|
67
99
|
return this.emitChange(Object.assign(Object.assign({}, event.detail), { value: formatValue }));
|
|
68
100
|
},
|
|
@@ -74,6 +106,23 @@ SmartComponent({
|
|
|
74
106
|
},
|
|
75
107
|
onBlur(event) {
|
|
76
108
|
this.focused = false;
|
|
109
|
+
const { numberFormat, locale } = this.data;
|
|
110
|
+
// 失焦时再做一次完整格式化,去掉多余的小数点(如 23. -> 23),并同步内部 value
|
|
111
|
+
if (numberFormat && this.value) {
|
|
112
|
+
const displayValue = formatNumber(this.value, locale);
|
|
113
|
+
const normalizedValue = parseFormattedNumber(displayValue, locale);
|
|
114
|
+
if (normalizedValue !== this.value) {
|
|
115
|
+
this.value = normalizedValue;
|
|
116
|
+
this.setData({ innerValue: displayValue });
|
|
117
|
+
this.emitChange({ value: this.value });
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.updateDisplayValue();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
this.updateDisplayValue();
|
|
125
|
+
}
|
|
77
126
|
this.setShowClear();
|
|
78
127
|
this.$emit('blur', event.detail);
|
|
79
128
|
},
|
|
@@ -84,8 +133,8 @@ SmartComponent({
|
|
|
84
133
|
this.$emit('click-input', event.detail);
|
|
85
134
|
},
|
|
86
135
|
onClear() {
|
|
87
|
-
this.setData({ innerValue: '' });
|
|
88
136
|
this.value = '';
|
|
137
|
+
this.updateDisplayValue();
|
|
89
138
|
this.setShowClear();
|
|
90
139
|
nextTick(() => {
|
|
91
140
|
this.emitChange({ value: '' });
|
|
@@ -94,16 +143,21 @@ SmartComponent({
|
|
|
94
143
|
},
|
|
95
144
|
onConfirm(event) {
|
|
96
145
|
const { value = '' } = event.detail || {};
|
|
97
|
-
|
|
146
|
+
const { numberFormat, locale } = this.data;
|
|
147
|
+
let rawValue = value;
|
|
148
|
+
// 如果启用了数字格式化,需要解析为原始格式
|
|
149
|
+
if (numberFormat) {
|
|
150
|
+
rawValue = parseFormattedNumber(value, locale);
|
|
151
|
+
}
|
|
152
|
+
this.value = rawValue;
|
|
153
|
+
this.updateDisplayValue();
|
|
98
154
|
this.setShowClear();
|
|
99
|
-
this.$emit('confirm',
|
|
155
|
+
this.$emit('confirm', rawValue);
|
|
100
156
|
},
|
|
101
157
|
setValue(value) {
|
|
102
158
|
this.value = value;
|
|
159
|
+
this.updateDisplayValue();
|
|
103
160
|
this.setShowClear();
|
|
104
|
-
if (value === '') {
|
|
105
|
-
this.setData({ innerValue: '' });
|
|
106
|
-
}
|
|
107
161
|
this.emitChange({ value });
|
|
108
162
|
},
|
|
109
163
|
onLineChange(event) {
|
|
@@ -122,7 +176,8 @@ SmartComponent({
|
|
|
122
176
|
const data = extraEventParams
|
|
123
177
|
? Object.assign(Object.assign({}, detail), { callback: (data) => {
|
|
124
178
|
result = data;
|
|
125
|
-
this.
|
|
179
|
+
this.value = data.value;
|
|
180
|
+
this.updateDisplayValue();
|
|
126
181
|
} }) : detail.value;
|
|
127
182
|
this.$emit('input', data);
|
|
128
183
|
this.$emit('change', data);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface NumberFormatConfig {
|
|
2
|
+
thousandsSeparator: string;
|
|
3
|
+
decimalSeparator: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function getNumberFormatConfig(locale: string): NumberFormatConfig;
|
|
6
|
+
export interface FormatNumberOptions {
|
|
7
|
+
/** 为 true 时保留末尾的小数点(用于聚焦输入中,避免 "23." 被格式成 "23" 打断输入) */
|
|
8
|
+
preserveTrailingDecimal?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function formatNumber(value: string, locale: string, options?: FormatNumberOptions): string;
|
|
11
|
+
export declare function parseFormattedNumber(formattedValue: string, locale: string): string;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { getSystemInfoSync } from '../common/utils';
|
|
2
|
+
// 提取语言代码:从 locale 中提取第一部分(去掉 - 和 _ 后面的所有内容)
|
|
3
|
+
function getLangKey(locale) {
|
|
4
|
+
if (!locale) {
|
|
5
|
+
return '';
|
|
6
|
+
}
|
|
7
|
+
// 转换为小写并去除空格
|
|
8
|
+
const normalized = locale.toLowerCase().trim();
|
|
9
|
+
// 统一将下划线和连字符作为分隔符,取第一部分
|
|
10
|
+
const langKey = normalized.split(/[-_]/)[0];
|
|
11
|
+
return langKey;
|
|
12
|
+
}
|
|
13
|
+
// 根据 locale 获取数字格式化配置
|
|
14
|
+
export function getNumberFormatConfig(locale) {
|
|
15
|
+
// 如果没有指定 locale,尝试从系统获取
|
|
16
|
+
if (!locale) {
|
|
17
|
+
try {
|
|
18
|
+
const systemInfo = getSystemInfoSync();
|
|
19
|
+
// 尝试多个可能的字段名
|
|
20
|
+
locale =
|
|
21
|
+
systemInfo.language ||
|
|
22
|
+
systemInfo.locale ||
|
|
23
|
+
systemInfo.lang ||
|
|
24
|
+
'zh-CN';
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
locale = 'zh-CN';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// 规范化 locale(统一大小写和下划线)
|
|
31
|
+
const normalizedLocale = locale.toLowerCase().trim().replace(/_/g, '-');
|
|
32
|
+
// 只配置非标准格式(非 1,234.56 格式)
|
|
33
|
+
// 默认格式:thousandsSeparator: ',', decimalSeparator: '.' (1,234.56)
|
|
34
|
+
const formatMap = {
|
|
35
|
+
// 德语地区:1.000,1312 (点作为千分位,逗号作为小数)
|
|
36
|
+
de: { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
37
|
+
// 法语地区:1 000,1312 (空格作为千分位,逗号作为小数)
|
|
38
|
+
fr: { thousandsSeparator: ' ', decimalSeparator: ',' },
|
|
39
|
+
// 意大利语:1.000,1312
|
|
40
|
+
it: { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
41
|
+
// 西班牙语:1.000,1312
|
|
42
|
+
es: { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
43
|
+
// 葡萄牙语:1.000,1312
|
|
44
|
+
pt: { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
45
|
+
// 俄语:1 000,1312 (空格作为千分位,逗号作为小数)
|
|
46
|
+
ru: { thousandsSeparator: ' ', decimalSeparator: ',' },
|
|
47
|
+
// 部分阿拉伯国家
|
|
48
|
+
'es-419': { thousandsSeparator: ',', decimalSeparator: '.' },
|
|
49
|
+
'pt-br': { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
50
|
+
'ar-ma': { thousandsSeparator: ' ', decimalSeparator: ',' },
|
|
51
|
+
'ar-tn': { thousandsSeparator: ' ', decimalSeparator: ',' },
|
|
52
|
+
'de-ch': { thousandsSeparator: "'", decimalSeparator: '.' },
|
|
53
|
+
'es-mx': { thousandsSeparator: ',', decimalSeparator: '.' },
|
|
54
|
+
'fr-ch': { thousandsSeparator: "'", decimalSeparator: '.' }, // 瑞士法语
|
|
55
|
+
};
|
|
56
|
+
// 策略1: 先尝试完整匹配(处理特殊国家,如 'de-ch', 'ar-ma', 'ar-tn')
|
|
57
|
+
if (formatMap[normalizedLocale]) {
|
|
58
|
+
return formatMap[normalizedLocale];
|
|
59
|
+
}
|
|
60
|
+
// 策略2: 提取语言代码进行匹配
|
|
61
|
+
const langKey = getLangKey(locale);
|
|
62
|
+
if (langKey && formatMap[langKey]) {
|
|
63
|
+
return formatMap[langKey];
|
|
64
|
+
}
|
|
65
|
+
// 默认使用标准格式:1,234.56 (千分位逗号,小数点)
|
|
66
|
+
return { thousandsSeparator: ',', decimalSeparator: '.' };
|
|
67
|
+
}
|
|
68
|
+
// 格式化数字:将 "1000.1312" 或 "-1000.1312" 格式化为带分隔符的字符串
|
|
69
|
+
export function formatNumber(value, locale, options) {
|
|
70
|
+
if (!value || value === '') {
|
|
71
|
+
return '';
|
|
72
|
+
}
|
|
73
|
+
// 仅保留数字、小数点、减号;连续前导减号按「负负得正」处理
|
|
74
|
+
const raw = value.replace(/[^-0-9.]/g, '');
|
|
75
|
+
let i = 0;
|
|
76
|
+
while (i < raw.length && raw[i] === '-') {
|
|
77
|
+
i++;
|
|
78
|
+
}
|
|
79
|
+
const negative = i % 2 === 1;
|
|
80
|
+
const cleanValue = raw.slice(i).replace(/-/g, '');
|
|
81
|
+
if (!cleanValue) {
|
|
82
|
+
return negative ? '-' : '';
|
|
83
|
+
}
|
|
84
|
+
// 聚焦输入时可能为 "23.",保留末尾小数点以便用户继续输入小数
|
|
85
|
+
const hasTrailingDecimal = (options === null || options === void 0 ? void 0 : options.preserveTrailingDecimal) && /\.$/.test(cleanValue);
|
|
86
|
+
// 分离整数部分和小数部分(处理多个小数点的情况)
|
|
87
|
+
const valueToFormat = hasTrailingDecimal ? cleanValue.slice(0, -1) : cleanValue;
|
|
88
|
+
const parts = valueToFormat.split('.');
|
|
89
|
+
const integerPart = parts[0] || '';
|
|
90
|
+
const decimalPart = parts.length > 1 ? parts.slice(1).join('') : '';
|
|
91
|
+
const config = getNumberFormatConfig(locale);
|
|
92
|
+
// 格式化整数部分(添加千分位分隔符)
|
|
93
|
+
let formattedInteger = '';
|
|
94
|
+
if (integerPart) {
|
|
95
|
+
for (let j = integerPart.length - 1, count = 0; j >= 0; j--) {
|
|
96
|
+
if (count > 0 && count % 3 === 0) {
|
|
97
|
+
formattedInteger = config.thousandsSeparator + formattedInteger;
|
|
98
|
+
}
|
|
99
|
+
formattedInteger = integerPart[j] + formattedInteger;
|
|
100
|
+
count++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const prefix = negative ? '-' : '';
|
|
104
|
+
if (decimalPart) {
|
|
105
|
+
return prefix + formattedInteger + config.decimalSeparator + decimalPart;
|
|
106
|
+
}
|
|
107
|
+
if (hasTrailingDecimal) {
|
|
108
|
+
return prefix + (formattedInteger || '0') + config.decimalSeparator;
|
|
109
|
+
}
|
|
110
|
+
return prefix + (formattedInteger || '0');
|
|
111
|
+
}
|
|
112
|
+
// 解析格式化后的数字:将格式化字符串转换回 "1000.1312" 或 "-1000.1312" 格式
|
|
113
|
+
export function parseFormattedNumber(formattedValue, locale) {
|
|
114
|
+
if (!formattedValue || formattedValue === '') {
|
|
115
|
+
return '';
|
|
116
|
+
}
|
|
117
|
+
let body = formattedValue.trim();
|
|
118
|
+
let negative = false;
|
|
119
|
+
const ch0 = body.charAt(0);
|
|
120
|
+
if (ch0 === '-' || ch0 === '\u2212') {
|
|
121
|
+
negative = true;
|
|
122
|
+
body = body.slice(1).trim();
|
|
123
|
+
}
|
|
124
|
+
if (!body) {
|
|
125
|
+
return negative ? '-' : '';
|
|
126
|
+
}
|
|
127
|
+
const config = getNumberFormatConfig(locale);
|
|
128
|
+
// 移除千分位分隔符(需要转义特殊字符)
|
|
129
|
+
const escapedSeparator = config.thousandsSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
130
|
+
let cleaned = body.replace(new RegExp(escapedSeparator, 'g'), '');
|
|
131
|
+
// 将小数分隔符转换为标准小数点(只替换第一个,因为可能有多个)
|
|
132
|
+
if (config.decimalSeparator !== '.') {
|
|
133
|
+
const decimalIndex = cleaned.indexOf(config.decimalSeparator);
|
|
134
|
+
if (decimalIndex !== -1) {
|
|
135
|
+
cleaned = cleaned.substring(0, decimalIndex) + '.' + cleaned.substring(decimalIndex + 1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// 确保只有一个小数点
|
|
139
|
+
const parts = cleaned.split('.');
|
|
140
|
+
if (parts.length > 2) {
|
|
141
|
+
cleaned = parts[0] + '.' + parts.slice(1).join('');
|
|
142
|
+
}
|
|
143
|
+
const num = cleaned.replace(/[^\d.]/g, '');
|
|
144
|
+
if (!num) {
|
|
145
|
+
return negative ? '-' : '';
|
|
146
|
+
}
|
|
147
|
+
return negative ? '-' + num : num;
|
|
148
|
+
}
|
package/lib/field/index.js
CHANGED
|
@@ -19,6 +19,7 @@ var component_1 = require("../common/component");
|
|
|
19
19
|
var props_1 = require("./props");
|
|
20
20
|
var Xmark_1 = __importDefault(require("@tuya-miniapp/icons/dist/svg/Xmark"));
|
|
21
21
|
var ty_1 = __importDefault(require("../common/ty"));
|
|
22
|
+
var numberFormat_1 = require("./numberFormat");
|
|
22
23
|
(0, component_1.SmartComponent)({
|
|
23
24
|
field: true,
|
|
24
25
|
classes: ['input-class', 'right-icon-class', 'label-class'],
|
|
@@ -45,6 +46,12 @@ var ty_1 = __importDefault(require("../common/ty"));
|
|
|
45
46
|
}, extraEventParams: {
|
|
46
47
|
type: Boolean,
|
|
47
48
|
value: false,
|
|
49
|
+
}, numberFormat: {
|
|
50
|
+
type: Boolean,
|
|
51
|
+
value: false,
|
|
52
|
+
}, locale: {
|
|
53
|
+
type: String,
|
|
54
|
+
value: '',
|
|
48
55
|
} }),
|
|
49
56
|
data: {
|
|
50
57
|
focused: false,
|
|
@@ -54,18 +61,24 @@ var ty_1 = __importDefault(require("../common/ty"));
|
|
|
54
61
|
watch: {
|
|
55
62
|
value: function (value) {
|
|
56
63
|
if (value !== this.value) {
|
|
57
|
-
this.setData({ innerValue: value });
|
|
58
64
|
this.value = value;
|
|
65
|
+
this.updateDisplayValue();
|
|
59
66
|
this.setShowClear();
|
|
60
67
|
}
|
|
61
68
|
},
|
|
69
|
+
numberFormat: function () {
|
|
70
|
+
this.updateDisplayValue();
|
|
71
|
+
},
|
|
72
|
+
locale: function () {
|
|
73
|
+
this.updateDisplayValue();
|
|
74
|
+
},
|
|
62
75
|
clearTrigger: function () {
|
|
63
76
|
this.setShowClear();
|
|
64
77
|
},
|
|
65
78
|
},
|
|
66
79
|
created: function () {
|
|
67
80
|
this.value = this.data.value;
|
|
68
|
-
this.
|
|
81
|
+
this.updateDisplayValue();
|
|
69
82
|
},
|
|
70
83
|
methods: {
|
|
71
84
|
formatValue: function (value) {
|
|
@@ -75,10 +88,29 @@ var ty_1 = __importDefault(require("../common/ty"));
|
|
|
75
88
|
}
|
|
76
89
|
return value;
|
|
77
90
|
},
|
|
91
|
+
// 更新显示值(根据 numberFormat 决定是否格式化)
|
|
92
|
+
// 聚焦时保留末尾小数点(如 23.)不格式化掉,避免打断用户输入;失焦后再做完整格式化
|
|
93
|
+
updateDisplayValue: function () {
|
|
94
|
+
var _a = this.data, numberFormat = _a.numberFormat, locale = _a.locale;
|
|
95
|
+
var displayValue = this.value || '';
|
|
96
|
+
if (numberFormat && displayValue) {
|
|
97
|
+
var preserveTrailingDecimal = !!this.focused;
|
|
98
|
+
displayValue = (0, numberFormat_1.formatNumber)(displayValue, locale, { preserveTrailingDecimal: preserveTrailingDecimal });
|
|
99
|
+
}
|
|
100
|
+
this.setData({ innerValue: displayValue });
|
|
101
|
+
},
|
|
78
102
|
onInput: function (event) {
|
|
79
103
|
var _a = (event.detail || {}).value, value = _a === void 0 ? '' : _a;
|
|
80
|
-
var
|
|
104
|
+
var _b = this.data, numberFormat = _b.numberFormat, locale = _b.locale;
|
|
105
|
+
var rawValue = value;
|
|
106
|
+
// 如果启用了数字格式化,需要将格式化后的输入值解析为原始格式
|
|
107
|
+
if (numberFormat) {
|
|
108
|
+
rawValue = (0, numberFormat_1.parseFormattedNumber)(value, locale);
|
|
109
|
+
}
|
|
110
|
+
var formatValue = this.formatValue(rawValue);
|
|
81
111
|
this.value = formatValue;
|
|
112
|
+
// 更新显示值
|
|
113
|
+
this.updateDisplayValue();
|
|
82
114
|
this.setShowClear();
|
|
83
115
|
return this.emitChange(__assign(__assign({}, event.detail), { value: formatValue }));
|
|
84
116
|
},
|
|
@@ -90,6 +122,23 @@ var ty_1 = __importDefault(require("../common/ty"));
|
|
|
90
122
|
},
|
|
91
123
|
onBlur: function (event) {
|
|
92
124
|
this.focused = false;
|
|
125
|
+
var _a = this.data, numberFormat = _a.numberFormat, locale = _a.locale;
|
|
126
|
+
// 失焦时再做一次完整格式化,去掉多余的小数点(如 23. -> 23),并同步内部 value
|
|
127
|
+
if (numberFormat && this.value) {
|
|
128
|
+
var displayValue = (0, numberFormat_1.formatNumber)(this.value, locale);
|
|
129
|
+
var normalizedValue = (0, numberFormat_1.parseFormattedNumber)(displayValue, locale);
|
|
130
|
+
if (normalizedValue !== this.value) {
|
|
131
|
+
this.value = normalizedValue;
|
|
132
|
+
this.setData({ innerValue: displayValue });
|
|
133
|
+
this.emitChange({ value: this.value });
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
this.updateDisplayValue();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
this.updateDisplayValue();
|
|
141
|
+
}
|
|
93
142
|
this.setShowClear();
|
|
94
143
|
this.$emit('blur', event.detail);
|
|
95
144
|
},
|
|
@@ -101,8 +150,8 @@ var ty_1 = __importDefault(require("../common/ty"));
|
|
|
101
150
|
},
|
|
102
151
|
onClear: function () {
|
|
103
152
|
var _this = this;
|
|
104
|
-
this.setData({ innerValue: '' });
|
|
105
153
|
this.value = '';
|
|
154
|
+
this.updateDisplayValue();
|
|
106
155
|
this.setShowClear();
|
|
107
156
|
(0, utils_1.nextTick)(function () {
|
|
108
157
|
_this.emitChange({ value: '' });
|
|
@@ -111,16 +160,21 @@ var ty_1 = __importDefault(require("../common/ty"));
|
|
|
111
160
|
},
|
|
112
161
|
onConfirm: function (event) {
|
|
113
162
|
var _a = (event.detail || {}).value, value = _a === void 0 ? '' : _a;
|
|
114
|
-
this.
|
|
163
|
+
var _b = this.data, numberFormat = _b.numberFormat, locale = _b.locale;
|
|
164
|
+
var rawValue = value;
|
|
165
|
+
// 如果启用了数字格式化,需要解析为原始格式
|
|
166
|
+
if (numberFormat) {
|
|
167
|
+
rawValue = (0, numberFormat_1.parseFormattedNumber)(value, locale);
|
|
168
|
+
}
|
|
169
|
+
this.value = rawValue;
|
|
170
|
+
this.updateDisplayValue();
|
|
115
171
|
this.setShowClear();
|
|
116
|
-
this.$emit('confirm',
|
|
172
|
+
this.$emit('confirm', rawValue);
|
|
117
173
|
},
|
|
118
174
|
setValue: function (value) {
|
|
119
175
|
this.value = value;
|
|
176
|
+
this.updateDisplayValue();
|
|
120
177
|
this.setShowClear();
|
|
121
|
-
if (value === '') {
|
|
122
|
-
this.setData({ innerValue: '' });
|
|
123
|
-
}
|
|
124
178
|
this.emitChange({ value: value });
|
|
125
179
|
},
|
|
126
180
|
onLineChange: function (event) {
|
|
@@ -140,7 +194,8 @@ var ty_1 = __importDefault(require("../common/ty"));
|
|
|
140
194
|
var data = extraEventParams
|
|
141
195
|
? __assign(__assign({}, detail), { callback: function (data) {
|
|
142
196
|
result = data;
|
|
143
|
-
_this.
|
|
197
|
+
_this.value = data.value;
|
|
198
|
+
_this.updateDisplayValue();
|
|
144
199
|
} }) : detail.value;
|
|
145
200
|
this.$emit('input', data);
|
|
146
201
|
this.$emit('change', data);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface NumberFormatConfig {
|
|
2
|
+
thousandsSeparator: string;
|
|
3
|
+
decimalSeparator: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function getNumberFormatConfig(locale: string): NumberFormatConfig;
|
|
6
|
+
export interface FormatNumberOptions {
|
|
7
|
+
/** 为 true 时保留末尾的小数点(用于聚焦输入中,避免 "23." 被格式成 "23" 打断输入) */
|
|
8
|
+
preserveTrailingDecimal?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function formatNumber(value: string, locale: string, options?: FormatNumberOptions): string;
|
|
11
|
+
export declare function parseFormattedNumber(formattedValue: string, locale: string): string;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseFormattedNumber = exports.formatNumber = exports.getNumberFormatConfig = void 0;
|
|
4
|
+
var utils_1 = require("../common/utils");
|
|
5
|
+
// 提取语言代码:从 locale 中提取第一部分(去掉 - 和 _ 后面的所有内容)
|
|
6
|
+
function getLangKey(locale) {
|
|
7
|
+
if (!locale) {
|
|
8
|
+
return '';
|
|
9
|
+
}
|
|
10
|
+
// 转换为小写并去除空格
|
|
11
|
+
var normalized = locale.toLowerCase().trim();
|
|
12
|
+
// 统一将下划线和连字符作为分隔符,取第一部分
|
|
13
|
+
var langKey = normalized.split(/[-_]/)[0];
|
|
14
|
+
return langKey;
|
|
15
|
+
}
|
|
16
|
+
// 根据 locale 获取数字格式化配置
|
|
17
|
+
function getNumberFormatConfig(locale) {
|
|
18
|
+
// 如果没有指定 locale,尝试从系统获取
|
|
19
|
+
if (!locale) {
|
|
20
|
+
try {
|
|
21
|
+
var systemInfo = (0, utils_1.getSystemInfoSync)();
|
|
22
|
+
// 尝试多个可能的字段名
|
|
23
|
+
locale =
|
|
24
|
+
systemInfo.language ||
|
|
25
|
+
systemInfo.locale ||
|
|
26
|
+
systemInfo.lang ||
|
|
27
|
+
'zh-CN';
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
locale = 'zh-CN';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// 规范化 locale(统一大小写和下划线)
|
|
34
|
+
var normalizedLocale = locale.toLowerCase().trim().replace(/_/g, '-');
|
|
35
|
+
// 只配置非标准格式(非 1,234.56 格式)
|
|
36
|
+
// 默认格式:thousandsSeparator: ',', decimalSeparator: '.' (1,234.56)
|
|
37
|
+
var formatMap = {
|
|
38
|
+
// 德语地区:1.000,1312 (点作为千分位,逗号作为小数)
|
|
39
|
+
de: { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
40
|
+
// 法语地区:1 000,1312 (空格作为千分位,逗号作为小数)
|
|
41
|
+
fr: { thousandsSeparator: ' ', decimalSeparator: ',' },
|
|
42
|
+
// 意大利语:1.000,1312
|
|
43
|
+
it: { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
44
|
+
// 西班牙语:1.000,1312
|
|
45
|
+
es: { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
46
|
+
// 葡萄牙语:1.000,1312
|
|
47
|
+
pt: { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
48
|
+
// 俄语:1 000,1312 (空格作为千分位,逗号作为小数)
|
|
49
|
+
ru: { thousandsSeparator: ' ', decimalSeparator: ',' },
|
|
50
|
+
// 部分阿拉伯国家
|
|
51
|
+
'es-419': { thousandsSeparator: ',', decimalSeparator: '.' },
|
|
52
|
+
'pt-br': { thousandsSeparator: '.', decimalSeparator: ',' },
|
|
53
|
+
'ar-ma': { thousandsSeparator: ' ', decimalSeparator: ',' },
|
|
54
|
+
'ar-tn': { thousandsSeparator: ' ', decimalSeparator: ',' },
|
|
55
|
+
'de-ch': { thousandsSeparator: "'", decimalSeparator: '.' },
|
|
56
|
+
'es-mx': { thousandsSeparator: ',', decimalSeparator: '.' },
|
|
57
|
+
'fr-ch': { thousandsSeparator: "'", decimalSeparator: '.' }, // 瑞士法语
|
|
58
|
+
};
|
|
59
|
+
// 策略1: 先尝试完整匹配(处理特殊国家,如 'de-ch', 'ar-ma', 'ar-tn')
|
|
60
|
+
if (formatMap[normalizedLocale]) {
|
|
61
|
+
return formatMap[normalizedLocale];
|
|
62
|
+
}
|
|
63
|
+
// 策略2: 提取语言代码进行匹配
|
|
64
|
+
var langKey = getLangKey(locale);
|
|
65
|
+
if (langKey && formatMap[langKey]) {
|
|
66
|
+
return formatMap[langKey];
|
|
67
|
+
}
|
|
68
|
+
// 默认使用标准格式:1,234.56 (千分位逗号,小数点)
|
|
69
|
+
return { thousandsSeparator: ',', decimalSeparator: '.' };
|
|
70
|
+
}
|
|
71
|
+
exports.getNumberFormatConfig = getNumberFormatConfig;
|
|
72
|
+
// 格式化数字:将 "1000.1312" 或 "-1000.1312" 格式化为带分隔符的字符串
|
|
73
|
+
function formatNumber(value, locale, options) {
|
|
74
|
+
if (!value || value === '') {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
// 仅保留数字、小数点、减号;连续前导减号按「负负得正」处理
|
|
78
|
+
var raw = value.replace(/[^-0-9.]/g, '');
|
|
79
|
+
var i = 0;
|
|
80
|
+
while (i < raw.length && raw[i] === '-') {
|
|
81
|
+
i++;
|
|
82
|
+
}
|
|
83
|
+
var negative = i % 2 === 1;
|
|
84
|
+
var cleanValue = raw.slice(i).replace(/-/g, '');
|
|
85
|
+
if (!cleanValue) {
|
|
86
|
+
return negative ? '-' : '';
|
|
87
|
+
}
|
|
88
|
+
// 聚焦输入时可能为 "23.",保留末尾小数点以便用户继续输入小数
|
|
89
|
+
var hasTrailingDecimal = (options === null || options === void 0 ? void 0 : options.preserveTrailingDecimal) && /\.$/.test(cleanValue);
|
|
90
|
+
// 分离整数部分和小数部分(处理多个小数点的情况)
|
|
91
|
+
var valueToFormat = hasTrailingDecimal ? cleanValue.slice(0, -1) : cleanValue;
|
|
92
|
+
var parts = valueToFormat.split('.');
|
|
93
|
+
var integerPart = parts[0] || '';
|
|
94
|
+
var decimalPart = parts.length > 1 ? parts.slice(1).join('') : '';
|
|
95
|
+
var config = getNumberFormatConfig(locale);
|
|
96
|
+
// 格式化整数部分(添加千分位分隔符)
|
|
97
|
+
var formattedInteger = '';
|
|
98
|
+
if (integerPart) {
|
|
99
|
+
for (var j = integerPart.length - 1, count = 0; j >= 0; j--) {
|
|
100
|
+
if (count > 0 && count % 3 === 0) {
|
|
101
|
+
formattedInteger = config.thousandsSeparator + formattedInteger;
|
|
102
|
+
}
|
|
103
|
+
formattedInteger = integerPart[j] + formattedInteger;
|
|
104
|
+
count++;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
var prefix = negative ? '-' : '';
|
|
108
|
+
if (decimalPart) {
|
|
109
|
+
return prefix + formattedInteger + config.decimalSeparator + decimalPart;
|
|
110
|
+
}
|
|
111
|
+
if (hasTrailingDecimal) {
|
|
112
|
+
return prefix + (formattedInteger || '0') + config.decimalSeparator;
|
|
113
|
+
}
|
|
114
|
+
return prefix + (formattedInteger || '0');
|
|
115
|
+
}
|
|
116
|
+
exports.formatNumber = formatNumber;
|
|
117
|
+
// 解析格式化后的数字:将格式化字符串转换回 "1000.1312" 或 "-1000.1312" 格式
|
|
118
|
+
function parseFormattedNumber(formattedValue, locale) {
|
|
119
|
+
if (!formattedValue || formattedValue === '') {
|
|
120
|
+
return '';
|
|
121
|
+
}
|
|
122
|
+
var body = formattedValue.trim();
|
|
123
|
+
var negative = false;
|
|
124
|
+
var ch0 = body.charAt(0);
|
|
125
|
+
if (ch0 === '-' || ch0 === '\u2212') {
|
|
126
|
+
negative = true;
|
|
127
|
+
body = body.slice(1).trim();
|
|
128
|
+
}
|
|
129
|
+
if (!body) {
|
|
130
|
+
return negative ? '-' : '';
|
|
131
|
+
}
|
|
132
|
+
var config = getNumberFormatConfig(locale);
|
|
133
|
+
// 移除千分位分隔符(需要转义特殊字符)
|
|
134
|
+
var escapedSeparator = config.thousandsSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
135
|
+
var cleaned = body.replace(new RegExp(escapedSeparator, 'g'), '');
|
|
136
|
+
// 将小数分隔符转换为标准小数点(只替换第一个,因为可能有多个)
|
|
137
|
+
if (config.decimalSeparator !== '.') {
|
|
138
|
+
var decimalIndex = cleaned.indexOf(config.decimalSeparator);
|
|
139
|
+
if (decimalIndex !== -1) {
|
|
140
|
+
cleaned = cleaned.substring(0, decimalIndex) + '.' + cleaned.substring(decimalIndex + 1);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// 确保只有一个小数点
|
|
144
|
+
var parts = cleaned.split('.');
|
|
145
|
+
if (parts.length > 2) {
|
|
146
|
+
cleaned = parts[0] + '.' + parts.slice(1).join('');
|
|
147
|
+
}
|
|
148
|
+
var num = cleaned.replace(/[^\d.]/g, '');
|
|
149
|
+
if (!num) {
|
|
150
|
+
return negative ? '-' : '';
|
|
151
|
+
}
|
|
152
|
+
return negative ? '-' + num : num;
|
|
153
|
+
}
|
|
154
|
+
exports.parseFormattedNumber = parseFormattedNumber;
|