@ecolovo/uniapp-components 1.0.10 → 2.0.1

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.
Files changed (130) hide show
  1. package/README.md +202 -66
  2. package/components/aspect/aspect.vue +24 -15
  3. package/components/badge/badge.scss +20 -0
  4. package/components/badge/badge.vue +49 -40
  5. package/components/button/button.scss +15 -0
  6. package/components/button/button.vue +121 -177
  7. package/components/checkbox/checkbox.scss +10 -0
  8. package/components/checkbox/checkbox.vue +118 -146
  9. package/components/checkbox-group/checkbox-group.vue +79 -85
  10. package/components/checkbox-group2/checkbox-group2.vue +111 -107
  11. package/components/checkbox-group2/checkbox2.vue +104 -0
  12. package/components/data-list/data-list.scss +9 -0
  13. package/components/data-list/data-list.vue +70 -79
  14. package/components/date-picker/date-picker-view.vue +125 -124
  15. package/components/date-picker/date-picker.vue +145 -146
  16. package/components/dialog/dialog-content.vue +39 -47
  17. package/components/dialog/dialog.scss +11 -0
  18. package/components/dialog/dialog.vue +125 -138
  19. package/components/dropdown/dropdown.scss +11 -0
  20. package/components/dropdown/dropdown.vue +55 -97
  21. package/components/empty/empty.scss +14 -0
  22. package/components/empty/empty.vue +42 -41
  23. package/components/flex/flex.vue +45 -54
  24. package/components/form/form.vue +29 -24
  25. package/components/form-item/form-item.scss +11 -0
  26. package/components/form-item/form-item.vue +43 -40
  27. package/components/icon/icon.vue +70 -85
  28. package/components/image/image.vue +35 -38
  29. package/components/input/input.vue +65 -79
  30. package/components/input/password-input.vue +34 -42
  31. package/components/list-page/list-page.vue +73 -99
  32. package/components/load-more/load-more.scss +12 -0
  33. package/components/load-more/load-more.vue +29 -29
  34. package/components/loading/animations/loading-animation1.vue +8 -8
  35. package/components/loading/animations/loading-animation2.vue +8 -9
  36. package/components/loading/animations/loading-animation3.vue +11 -11
  37. package/components/loading/animations/loading-animation4.vue +8 -8
  38. package/components/loading/loading.vue +19 -20
  39. package/components/message-box/message-box.vue +59 -41
  40. package/components/number-dialog/number-dialog.scss +9 -0
  41. package/components/number-dialog/number-dialog.vue +209 -204
  42. package/components/number-input/number-input.scss +9 -0
  43. package/components/number-input/number-input.vue +233 -232
  44. package/components/numpad/numpad.scss +9 -0
  45. package/components/numpad/numpad.vue +133 -150
  46. package/components/page/page-body.scss +15 -0
  47. package/components/page/page-body.vue +137 -119
  48. package/components/page/page-footer.scss +13 -0
  49. package/components/page/page-footer.vue +31 -33
  50. package/components/page/page-header.scss +17 -0
  51. package/components/page/page-header.vue +89 -94
  52. package/components/page/page.scss +9 -0
  53. package/components/page/page.vue +105 -81
  54. package/components/picker/picker-popup.vue +218 -209
  55. package/components/picker/picker.vue +99 -104
  56. package/components/popover/popover-content.vue +54 -63
  57. package/components/popover/popover-mask.vue +63 -63
  58. package/components/popover/popover.scss +28 -0
  59. package/components/popover/popover.vue +49 -47
  60. package/components/popup/popup-content.vue +49 -53
  61. package/components/popup/popup.scss +11 -0
  62. package/components/popup/popup.vue +117 -132
  63. package/components/price/price.scss +20 -0
  64. package/components/price/price.vue +31 -42
  65. package/components/search/search.scss +12 -0
  66. package/components/search/search.vue +93 -117
  67. package/components/searching/searching.vue +33 -40
  68. package/components/selector/selector.vue +43 -48
  69. package/components/switch/switch.scss +12 -0
  70. package/components/switch/switch.vue +99 -96
  71. package/components/tab/tab.scss +19 -0
  72. package/components/tab/tab.vue +151 -145
  73. package/components/textarea/textarea.vue +104 -101
  74. package/composable/component-name.d.ts +2 -0
  75. package/composable/component-name.js +8 -0
  76. package/composable/component-name.ts +10 -0
  77. package/configs/index.d.ts +25 -10
  78. package/configs/index.js +14 -23
  79. package/configs/index.ts +82 -0
  80. package/easyCom.d.ts +9 -0
  81. package/easyCom.js +1 -2
  82. package/easyCom.ts +31 -0
  83. package/index.d.ts +1 -0
  84. package/index.js +1 -0
  85. package/index.ts +1 -0
  86. package/init.d.ts +4 -7
  87. package/init.js +5 -4
  88. package/init.ts +34 -0
  89. package/package.json +14 -4
  90. package/styles/utils/css-var.scss +12 -15
  91. package/styles/utils/ellipsis.scss +0 -7
  92. package/styles/utils/z-index.scss +1 -1
  93. package/styles/var/component.scss +21 -245
  94. package/utils/date.d.ts +47 -0
  95. package/utils/date.js +23 -43
  96. package/utils/date.ts +153 -0
  97. package/utils/freezeDeep.d.ts +1 -0
  98. package/utils/freezeDeep.js +4 -14
  99. package/utils/freezeDeep.ts +9 -0
  100. package/utils/price.d.ts +24 -0
  101. package/utils/price.js +14 -8
  102. package/utils/price.ts +57 -0
  103. package/utils/round.d.ts +2 -0
  104. package/utils/round.js +2 -14
  105. package/utils/round.ts +11 -0
  106. package/utils/windowInfo.d.ts +24 -0
  107. package/utils/windowInfo.js +8 -36
  108. package/utils/windowInfo.ts +50 -0
  109. package/components/checkbox-group2/checkbox.vue +0 -109
  110. package/components/datetime-picker/datetime-picker-view.vue +0 -209
  111. package/components/datetime-picker/datetime-picker.vue +0 -235
  112. package/components/form/mixin.js +0 -13
  113. package/components/list-page/list-page.js +0 -10
  114. package/components/table/table.vue +0 -112
  115. package/components/time-picker/time-picker-view.vue +0 -127
  116. package/components/time-picker/time-picker.vue +0 -140
  117. package/components/uploader/download.js +0 -81
  118. package/components/uploader/file-uploader.vue +0 -52
  119. package/components/uploader/files.js +0 -225
  120. package/components/uploader/media-uploader.vue +0 -189
  121. package/components/uploader/mixin.js +0 -171
  122. package/components/uploader/uni.js +0 -38
  123. package/components/uploader/upload-button.vue +0 -29
  124. package/components/uploader/uploader copy.vue +0 -547
  125. package/components/uploader/uploader.vue +0 -117
  126. package/mixins/componentName.js +0 -32
  127. package/mixins/listPage.js +0 -1
  128. package/mixins/windowInfo.js +0 -1
  129. package/utils/fileSize.js +0 -39
  130. package/utils/floor.js +0 -20
@@ -1,245 +1,21 @@
1
- @use 'sass:map';
2
- @use '../utils' as *;
3
-
4
- $badge: () !default;
5
- $badge-default: (
6
- // 相对于右上角偏移量
7
- translate: 40% -40%,
8
- // 字号
9
- font-size: UTILS__GLOBAL_VAR(font-size, small),
10
- // 文字颜色
11
- color: #fff,
12
- // 背景色
13
- background: #ff0000,
14
- // 边框
15
- border: none,
16
- // 高度
17
- height: calc(#{UTILS__LOCAL_VAR(font-size)} + 12rpx),
18
- // 圆角
19
- border-radius: 40rpx
20
- );
21
- $badge: map.merge($badge-default, $badge);
22
-
23
- $page-header: () !default;
24
- $page-header-default: (
25
- // 背景色
26
- background: #fff,
27
- // 字体大小
28
- font-size: 28rpx,
29
- // 标题栏下的额外内容高度,有内容时需设置次值
30
- extra-height: 0px,
31
- // 亮色主题下的文本颜色
32
- color-light: #000,
33
- // 暗色主题下的文本颜色
34
- color-dark: #fff
35
- );
36
- $page-header: map.merge($page-header-default, $page-header);
37
-
38
- $page-body: () !default;
39
- $page-body-default: (
40
- // 可视区域背景
41
- background: transparent,
42
- padding: 20rpx,
43
- padding-top: null,
44
- padding-right: null,
45
- padding-bottom: null,
46
- padding-left: null
47
- );
48
- $page-body: map.merge($page-body-default, $page-body);
49
-
50
- $page-footer: () !default;
51
- $page-footer-default: (
52
- // 背景色
53
- background: #fff,
54
- // 高度
55
- height: 100rpx,
56
- // 横向两端间距
57
- spacing-horizontal: 30rpx
58
- );
59
- $page-footer: map.merge($page-footer-default, $page-footer);
60
-
61
- $page: () !default;
62
- $page-default: (
63
- // 页面背景
64
- background: transparent
65
- );
66
- $page: map.merge($page-default, $page);
67
-
68
- $button: () !default;
69
- $button-default: (
70
- // 按钮主题颜色,默认取值组件 props 中的 type
71
- theme: var(--theme-from-prop),
72
- // 按钮文本颜色
73
- text-color: #fff,
74
- // 按钮激活态遮罩颜色
75
- active-mask: #ffffff,
76
- // plain 按钮的边框宽度
77
- border-width: 3rpx
78
- );
79
- $button: map.merge($button-default, $button);
80
-
81
- $data-list: () !default;
82
- $data-list-default: (
83
- // 触发加载更多的区域高度
84
- observer-height: 100vh
85
- );
86
- $data-list: map.merge($data-list-default, $data-list);
87
-
88
- $empty: () !default;
89
- $empty-default: (
90
- image-size: 300rpx,
91
- image-width: UTILS__LOCAL_VAR(image-size),
92
- image-height: UTILS__LOCAL_VAR(image-size),
93
- space: 20rpx,
94
- color: #ccc,
95
- font-size: UTILS__GLOBAL_VAR(font-size, normal),
96
- );
97
- $empty: map.merge($empty-default, $empty);
98
-
99
- $load-more: () !default;
100
- $load-more-default: (
101
- height: 60rpx,
102
- space: 40rpx,
103
- color: #ccc,
104
- font-size: UTILS__GLOBAL_VAR(font-size, normal),
105
- );
106
- $load-more: map.merge($load-more-default, $load-more);
107
-
108
- $checkbox: () !default;
109
- $checkbox-default: (
110
- checked-color: UTILS__GLOBAL_VAR(theme, primary),
111
- unchecked-color: UTILS__GLOBAL_VAR(color, foreground),
112
- );
113
- $checkbox: map.merge($checkbox-default, $checkbox);
114
-
115
- $popover: () !default;
116
- $popover-default: (
117
- // 遮罩层颜色
118
- mask-color: #00000080,
119
- // 背景色
120
- background: #fff,
121
- // 位置,position 为 center 时有效
122
- position: 50% auto auto 50%,
123
- // 宽度,position 为 left 、 right 或 center 时有效
124
- width: 80vw,
125
- // 最小高度,position 为 top 、 bottom 或 center 时有效
126
- min-height: 0px,
127
- // 最大高度,position 为 top 、 bottom 或 center 时有效
128
- max-height: 75vh,
129
- // 内边距
130
- padding: 20rpx,
131
- // 边框圆角
132
- radius: 20rpx,
133
- // 头高度
134
- header-height: 0px,
135
- // 尾高度
136
- footer-height: 0px
137
- );
138
- $popover: map.merge($popover-default, $popover);
139
-
140
- $dialog: () !default;
141
- $dialog-default: (
142
- // 标题栏高度
143
- header-height: 100rpx,
144
- // 操作栏高度
145
- footer-height: 134rpx
146
- );
147
- $dialog: map.merge($dialog-default, $dialog);
148
-
149
- $popup: () !default;
150
- $popup-default: (
151
- // 标题栏高度
152
- header-height: 100rpx,
153
- // 操作栏高度
154
- footer-height: 102rpx
155
- );
156
- $popup: map.merge($popup-default, $popup);
157
-
158
- $form-item: () !default;
159
- $form-item-default: (
160
- // label 宽度
161
- label-width: 6em,
162
- // 高度
163
- height: 80rpx
164
- );
165
- $form-item: map.merge($form-item-default, $form-item);
166
-
167
- $switch: () !default;
168
- $switch-default: (
169
- width: 92rpx,
170
- height: 48rpx,
171
- active-color: UTILS__GLOBAL_VAR(theme, primary),
172
- indicator-size: 42rpx,
173
- );
174
- $switch: map.merge($switch-default, $switch);
175
-
176
- $number-input: () !default;
177
- $number-input-default: (
178
- font-size: inherit,
179
- text-align: center,
180
- );
181
- $number-input: map.merge($number-input-default, $number-input);
182
-
183
- $numpad: () !default;
184
- $numpad-default: (
185
- row-gap: 20rpx,
186
- col-gap: 20rpx,
187
- );
188
- $numpad: map.merge($numpad-default, $numpad);
189
-
190
- $number-dialog: () !default;
191
- $number-dialog-default: (
192
- // 按钮尺寸
193
- button-size: 48rpx
194
- );
195
- $number-dialog: map.merge($number-dialog-default, $number-dialog);
196
-
197
- $tab: () !default;
198
- $tab-default: (
199
- height: 88rpx,
200
- tab-padding: 0 10rpx,
201
- tab-gaps: 0,
202
- color: UTILS__GLOBAL_VAR(color, foreground),
203
- font-size: UTILS__GLOBAL_VAR(font-size, large),
204
- font-weight: 600,
205
- background: #ffffff,
206
- border-radius: 0,
207
- active-color: UTILS__LOCAL_VAR(color),
208
- indicator-color: UTILS__GLOBAL_VAR(theme, primary),
209
- indicator-width: null,
210
- );
211
- $tab: map.merge($tab-default, $tab);
212
-
213
- $search: () !default;
214
- $search-default: (
215
- background: UTILS__GLOBAL_VAR(color, background),
216
- border-radius: 8rpx,
217
- height: 64rpx,
218
- padding: 0 20rpx,
219
- );
220
- $search: map.merge($search-default, $search);
221
-
222
- $price: () !default;
223
- $price-default: (
224
- color: inherit,
225
- font-size: inherit,
226
- font-weight: inherit,
227
- integer-color: UTILS__LOCAL_VAR(color),
228
- integer-font-size: UTILS__LOCAL_VAR(font-size),
229
- integer-font-weight: UTILS__LOCAL_VAR(font-weight),
230
- decimal-color: UTILS__LOCAL_VAR(color),
231
- decimal-font-size: UTILS__LOCAL_VAR(font-size),
232
- decimal-font-weight: UTILS__LOCAL_VAR(font-weight),
233
- unit-color: UTILS__LOCAL_VAR(color),
234
- unit-font-size: UTILS__LOCAL_VAR(font-size),
235
- unit-font-weight: UTILS__LOCAL_VAR(font-weight),
236
- );
237
- $price: map.merge($price-default, $price);
238
-
239
- // $page: () !default;
240
- // $page-default: ();
241
- // $page: map.merge($page-default, $page);
242
-
243
- // $page: () !default;
244
- // $page-default: ();
245
- // $page: map.merge($page-default, $page);
1
+ // @forward '../../components/badge/badge.scss';
2
+ @forward '../../components/button/button.scss';
3
+ // @forward '../../components/checkbox/checkbox.scss';
4
+ // @forward '../../components/data-list/data-list.scss';
5
+ // @forward '../../components/dialog/dialog.scss';
6
+ // @forward '../../components/empty/empty.scss';
7
+ // @forward '../../components/form-item/form-item.scss';
8
+ // @forward '../../components/load-more/load-more.scss';
9
+ // @forward '../../components/number-dialog/number-dialog.scss';
10
+ // @forward '../../components/number-input/number-input.scss';
11
+ // @forward '../../components/numpad/numpad.scss';
12
+ // @forward '../../components/page/page.scss';
13
+ // @forward '../../components/page/page-header.scss';
14
+ // @forward '../../components/page/page-body.scss';
15
+ // @forward '../../components/page/page-footer.scss';
16
+ // @forward '../../components/popover/popover.scss';
17
+ // @forward '../../components/popup/popup.scss';
18
+ // @forward '../../components/price/price.scss';
19
+ // @forward '../../components/search/search.scss';
20
+ // @forward '../../components/switch/switch.scss';
21
+ // @forward '../../components/tab/tab.scss';
@@ -0,0 +1,47 @@
1
+ type ValidDateValue = Date | number | string;
2
+ /**
3
+ * 将Date 对象、时间戳或时间格式字符串转为 Date 对象
4
+ * @param dateValue Date 对象、时间戳或时间格式字符串
5
+ * @returns Date 对象
6
+ */
7
+ export declare function toDate(dateValue: ValidDateValue | null | undefined): Date | null;
8
+ type FormatFn = {
9
+ (date: Date | null | undefined, format?: string): string;
10
+ DATE: string;
11
+ DATE_WITH_YEAR: string;
12
+ TIME: string;
13
+ TIME_MS: string;
14
+ TIME_MINUTE: string;
15
+ DATE_TIME: string;
16
+ DATE_TIME_MS: string;
17
+ DATE_TIME_WITH_YEAR: string;
18
+ DATE_TIME_MS_WITH_YEAR: string;
19
+ DATE_MINUTE: string;
20
+ DATE_MINUTE_WITH_YEAR: string;
21
+ };
22
+ /**
23
+ * 格式化日期
24
+ *
25
+ * format 参数说明:
26
+ * - Y: 年
27
+ * - M: 月
28
+ * - D: 日
29
+ * - H: 时
30
+ * - m: 分
31
+ * - s: 秒
32
+ * - S: 毫秒
33
+ * - w: 星期
34
+ * - W: 星期(中文)
35
+ * @param date 要格式化的日期对象
36
+ * @param format 格式化参数 默认值 YYYY-MM-DD
37
+ * @returns 格式化后的日期
38
+ */
39
+ export declare const formatDate: FormatFn;
40
+ /**
41
+ * 获取两个时间的天数差
42
+ * @param day1 时间1
43
+ * @param day2 时间2
44
+ * @returns 天数差,负数: day1 < day2
45
+ */
46
+ export declare function daysDiff(day1: ValidDateValue, day2: ValidDateValue): number;
47
+ export {};
package/utils/date.js CHANGED
@@ -1,25 +1,18 @@
1
1
  /**
2
2
  * 将Date 对象、时间戳或时间格式字符串转为 Date 对象
3
- * @param {Date | number | string} dateValue Date 对象、时间戳或时间格式字符串
4
- * @returns {Date} Date 对象
3
+ * @param dateValue Date 对象、时间戳或时间格式字符串
4
+ * @returns Date 对象
5
5
  */
6
6
  export function toDate(dateValue) {
7
7
  if (dateValue instanceof Date) return new Date(dateValue);
8
8
  if (typeof dateValue === 'number') return new Date(dateValue);
9
- if (!dateValue) {
10
- return null;
11
- }
12
- if (typeof dateValue !== 'string') {
13
- throw new Error("dateValue's type is invalid");
14
- }
9
+ if (!dateValue) return null;
10
+ if (typeof dateValue !== 'string') throw new Error("dateValue's type is invalid");
15
11
  // 兼容 iOS 日期格式
16
12
  const result = new Date(dateValue.replace(/-/g, '/'));
17
- if (isNaN(result.getTime())) {
18
- throw new Error('dateValue cannot be parsed to Date object');
19
- }
13
+ if (isNaN(result.getTime())) throw new Error('dateValue cannot be parsed to Date object');
20
14
  return result;
21
15
  }
22
-
23
16
  /**
24
17
  * 格式化日期
25
18
  *
@@ -33,14 +26,12 @@ export function toDate(dateValue) {
33
26
  * - S: 毫秒
34
27
  * - w: 星期
35
28
  * - W: 星期(中文)
36
- * @param {Date | undefined} date 要格式化的日期对象
37
- * @param {string} format 格式化参数 默认值 YYYY-MM-DD
38
- * @returns {string} 格式化后的日期
29
+ * @param date 要格式化的日期对象
30
+ * @param format 格式化参数 默认值 YYYY-MM-DD
31
+ * @returns 格式化后的日期
39
32
  */
40
- export function formatDate(date, format = formatDate.DATE_WITH_YEAR) {
41
- if (!date) {
42
- return '';
43
- }
33
+ export const formatDate = (date, format = formatDate.DATE_WITH_YEAR) => {
34
+ if (!date) return '';
44
35
  const fullYear = date.getFullYear().toString();
45
36
  const year = fullYear.substring(fullYear.length - 2);
46
37
  const month = (date.getMonth() + 1).toString();
@@ -74,7 +65,6 @@ export function formatDate(date, format = formatDate.DATE_WITH_YEAR) {
74
65
  weekCN = '六';
75
66
  break;
76
67
  }
77
-
78
68
  const replacement = [
79
69
  { reg: 'Y{3,4}', val: fullYear, pad: 0 },
80
70
  { reg: 'Y{1,2}', val: year, pad: 0 },
@@ -87,16 +77,14 @@ export function formatDate(date, format = formatDate.DATE_WITH_YEAR) {
87
77
  { reg: 'w', val: week, pad: 0 },
88
78
  { reg: 'W', val: weekCN, pad: 0 },
89
79
  ];
90
-
91
80
  for (let i = 0; i < replacement.length; i++) {
92
81
  const r = replacement[i];
93
- format = format.replace(new RegExp(r.reg, 'g'), function (m) {
94
- return r.pad > 0 ? r.val.padStart(Math.min(r.pad, m.length), '0') : r.val;
95
- });
82
+ format = format.replace(new RegExp(r.reg, 'g'), (m) =>
83
+ r.pad > 0 ? r.val.padStart(Math.min(r.pad, m.length), '0') : r.val
84
+ );
96
85
  }
97
86
  return format;
98
- }
99
-
87
+ };
100
88
  /** 月日 */
101
89
  formatDate.DATE = 'MM-DD';
102
90
  /** 年月日 */
@@ -119,32 +107,24 @@ formatDate.DATE_TIME_MS_WITH_YEAR = 'YYYY-MM-DD HH:mm:ss.SSS';
119
107
  formatDate.DATE_MINUTE = 'MM-DD HH:mm';
120
108
  /** 年月日 时分 */
121
109
  formatDate.DATE_MINUTE_WITH_YEAR = 'YYYY-MM-DD HH:mm';
122
-
123
110
  /** 时区差 */
124
111
  const TIMEZONE_OFFSET = new Date().getTimezoneOffset() * 60 * 1000;
125
-
126
112
  /**
127
113
  * 获取时间的UTC相对时间戳
128
- * @param {number | string | Date} date 时间
129
- * @returns {number} 毫秒数
114
+ * @param date 时间
115
+ * @returns 毫秒数
130
116
  */
131
117
  function toDayTimestamp(date) {
132
- let d = null;
133
- if (typeof date === 'number') {
134
- return date - TIMEZONE_OFFSET;
135
- } else if (typeof date === 'string') {
136
- d = toDate(date);
137
- } else if (!(date instanceof Date)) {
138
- d = new Date();
139
- }
140
- return d.getTime() - TIMEZONE_OFFSET;
118
+ if (typeof date === 'number') return date - TIMEZONE_OFFSET;
119
+ if (typeof date === 'string') return toDate(date).getTime() - TIMEZONE_OFFSET;
120
+ if (date instanceof Date) return date.getTime() - TIMEZONE_OFFSET;
121
+ return Date.now() - TIMEZONE_OFFSET;
141
122
  }
142
-
143
123
  /**
144
124
  * 获取两个时间的天数差
145
- * @param {number | string | Date} day1 时间1
146
- * @param {number | string | Date} day2 时间2
147
- * @returns {number} 天数差,负数: day1 < day2
125
+ * @param day1 时间1
126
+ * @param day2 时间2
127
+ * @returns 天数差,负数: day1 < day2
148
128
  */
149
129
  export function daysDiff(day1, day2) {
150
130
  return Math.floor(toDayTimestamp(day1) / 8.64e7) - Math.floor(toDayTimestamp(day2) / 8.64e7);
package/utils/date.ts ADDED
@@ -0,0 +1,153 @@
1
+ type ValidDateValue = Date | number | string;
2
+
3
+ /**
4
+ * 将Date 对象、时间戳或时间格式字符串转为 Date 对象
5
+ * @param dateValue Date 对象、时间戳或时间格式字符串
6
+ * @returns Date 对象
7
+ */
8
+ export function toDate(dateValue: ValidDateValue | null | undefined): Date | null {
9
+ if (dateValue instanceof Date) return new Date(dateValue);
10
+ if (typeof dateValue === 'number') return new Date(dateValue);
11
+ if (!dateValue) return null;
12
+ if (typeof dateValue !== 'string') throw new Error("dateValue's type is invalid");
13
+
14
+ // 兼容 iOS 日期格式
15
+ const result = new Date(dateValue.replace(/-/g, '/'));
16
+ if (isNaN(result.getTime())) throw new Error('dateValue cannot be parsed to Date object');
17
+ return result;
18
+ }
19
+
20
+ type FormatFn = {
21
+ (date: Date | null | undefined, format?: string): string;
22
+ DATE: string;
23
+ DATE_WITH_YEAR: string;
24
+ TIME: string;
25
+ TIME_MS: string;
26
+ TIME_MINUTE: string;
27
+ DATE_TIME: string;
28
+ DATE_TIME_MS: string;
29
+ DATE_TIME_WITH_YEAR: string;
30
+ DATE_TIME_MS_WITH_YEAR: string;
31
+ DATE_MINUTE: string;
32
+ DATE_MINUTE_WITH_YEAR: string;
33
+ };
34
+ /**
35
+ * 格式化日期
36
+ *
37
+ * format 参数说明:
38
+ * - Y: 年
39
+ * - M: 月
40
+ * - D: 日
41
+ * - H: 时
42
+ * - m: 分
43
+ * - s: 秒
44
+ * - S: 毫秒
45
+ * - w: 星期
46
+ * - W: 星期(中文)
47
+ * @param date 要格式化的日期对象
48
+ * @param format 格式化参数 默认值 YYYY-MM-DD
49
+ * @returns 格式化后的日期
50
+ */
51
+ export const formatDate: FormatFn = (date, format = formatDate.DATE_WITH_YEAR) => {
52
+ if (!date) return '';
53
+ const fullYear = date.getFullYear().toString();
54
+ const year = fullYear.substring(fullYear.length - 2);
55
+ const month = (date.getMonth() + 1).toString();
56
+ const day = date.getDate().toString();
57
+ const hour = date.getHours().toString();
58
+ const min = date.getMinutes().toString();
59
+ const sec = date.getSeconds().toString();
60
+ const ms = date.getMilliseconds().toString();
61
+ const week = date.getDay().toString();
62
+ let weekCN = '';
63
+ switch (week) {
64
+ case '0':
65
+ weekCN = '日';
66
+ break;
67
+ case '1':
68
+ weekCN = '一';
69
+ break;
70
+ case '2':
71
+ weekCN = '二';
72
+ break;
73
+ case '3':
74
+ weekCN = '三';
75
+ break;
76
+ case '4':
77
+ weekCN = '四';
78
+ break;
79
+ case '5':
80
+ weekCN = '五';
81
+ break;
82
+ case '6':
83
+ weekCN = '六';
84
+ break;
85
+ }
86
+ const replacement = [
87
+ { reg: 'Y{3,4}', val: fullYear, pad: 0 },
88
+ { reg: 'Y{1,2}', val: year, pad: 0 },
89
+ { reg: 'M{1,2}', val: month, pad: 2 },
90
+ { reg: 'D{1,2}', val: day, pad: 2 },
91
+ { reg: 'H{1,2}', val: hour, pad: 2 },
92
+ { reg: 'm{1,2}', val: min, pad: 2 },
93
+ { reg: 's{1,2}', val: sec, pad: 2 },
94
+ { reg: 'S{1,3}', val: ms, pad: 3 },
95
+ { reg: 'w', val: week, pad: 0 },
96
+ { reg: 'W', val: weekCN, pad: 0 },
97
+ ];
98
+ for (let i = 0; i < replacement.length; i++) {
99
+ const r = replacement[i]!;
100
+ format = format.replace(new RegExp(r.reg, 'g'), (m) =>
101
+ r.pad > 0 ? r.val.padStart(Math.min(r.pad, m.length), '0') : r.val
102
+ );
103
+ }
104
+ return format;
105
+ };
106
+
107
+ /** 月日 */
108
+ formatDate.DATE = 'MM-DD';
109
+ /** 年月日 */
110
+ formatDate.DATE_WITH_YEAR = 'YYYY-MM-DD';
111
+ /** 时分秒 */
112
+ formatDate.TIME = 'HH:mm:ss';
113
+ /** 时分秒.毫秒 */
114
+ formatDate.TIME_MS = 'HH:mm:ss.SSS';
115
+ /** 时分 */
116
+ formatDate.TIME_MINUTE = 'HH:mm';
117
+ /** 月日 时分秒 */
118
+ formatDate.DATE_TIME = 'MM-DD HH:mm:ss';
119
+ /** 月日 时分秒.毫秒 */
120
+ formatDate.DATE_TIME_MS = 'MM-DD HH:mm:ss.SSS';
121
+ /** 年月日 时分秒 */
122
+ formatDate.DATE_TIME_WITH_YEAR = 'YYYY-MM-DD HH:mm:ss';
123
+ /** 年月日 时分秒.毫秒 */
124
+ formatDate.DATE_TIME_MS_WITH_YEAR = 'YYYY-MM-DD HH:mm:ss.SSS';
125
+ /** 月日 时分 */
126
+ formatDate.DATE_MINUTE = 'MM-DD HH:mm';
127
+ /** 年月日 时分 */
128
+ formatDate.DATE_MINUTE_WITH_YEAR = 'YYYY-MM-DD HH:mm';
129
+
130
+ /** 时区差 */
131
+ const TIMEZONE_OFFSET = new Date().getTimezoneOffset() * 60 * 1000;
132
+
133
+ /**
134
+ * 获取时间的UTC相对时间戳
135
+ * @param date 时间
136
+ * @returns 毫秒数
137
+ */
138
+ function toDayTimestamp(date: ValidDateValue): number {
139
+ if (typeof date === 'number') return date - TIMEZONE_OFFSET;
140
+ if (typeof date === 'string') return toDate(date)!.getTime() - TIMEZONE_OFFSET;
141
+ if (date instanceof Date) return date.getTime() - TIMEZONE_OFFSET;
142
+ return Date.now() - TIMEZONE_OFFSET;
143
+ }
144
+
145
+ /**
146
+ * 获取两个时间的天数差
147
+ * @param day1 时间1
148
+ * @param day2 时间2
149
+ * @returns 天数差,负数: day1 < day2
150
+ */
151
+ export function daysDiff(day1: ValidDateValue, day2: ValidDateValue): number {
152
+ return Math.floor(toDayTimestamp(day1) / 8.64e7) - Math.floor(toDayTimestamp(day2) / 8.64e7);
153
+ }
@@ -0,0 +1 @@
1
+ export declare function freezeDeep<T>(obj: T): Readonly<T>;
@@ -1,19 +1,9 @@
1
- /**
2
- * 深度冻结一个对象
3
- *
4
- * 注意:传入的对象和返回的对象是同一个引用,慎用!!
5
- *
6
- * @template T
7
- * @param {T} obj 要被冻结的对象
8
- * @returns {Readonly<T>}
9
- */
10
1
  export function freezeDeep(obj) {
11
2
  if (!(typeof obj === 'object' && obj)) {
12
3
  return obj;
13
- } else {
14
- for (let key in obj) {
15
- freezeDeep(obj[key]);
16
- }
17
- return Object.freeze(obj);
18
4
  }
5
+ for (const key in obj) {
6
+ freezeDeep(obj[key]);
7
+ }
8
+ return Object.freeze(obj);
19
9
  }
@@ -0,0 +1,9 @@
1
+ export function freezeDeep<T>(obj: T): Readonly<T> {
2
+ if (!(typeof obj === 'object' && obj)) {
3
+ return obj;
4
+ }
5
+ for (const key in obj) {
6
+ freezeDeep((obj as Record<string, unknown>)[key]);
7
+ }
8
+ return Object.freeze(obj);
9
+ }
@@ -0,0 +1,24 @@
1
+ interface FormatPriceOption {
2
+ /** 精度,默认为 2 */
3
+ precision: number;
4
+ /** 是否补齐小数部分 0 */
5
+ padDecimal: boolean;
6
+ }
7
+ interface FormatPriceResult {
8
+ /** 格式化的价格字符串 */
9
+ price: string;
10
+ /** 是否负值 */
11
+ negative: boolean;
12
+ /** 整数部分价格 */
13
+ integer: string;
14
+ /** 小数部分价格 */
15
+ decimal: string;
16
+ /** 价格对应数值 */
17
+ number: number;
18
+ }
19
+ /**
20
+ * 格式化价格
21
+ * @param price 价格
22
+ */
23
+ export declare function formatPrice(price: number | string, option?: FormatPriceOption): FormatPriceResult;
24
+ export {};
package/utils/price.js CHANGED
@@ -1,10 +1,9 @@
1
1
  /**
2
2
  * 格式化价格
3
- * @param {number} price 价格
4
- * @returns {FormattedPrice}
3
+ * @param price 价格
5
4
  */
6
- export function formatPrice(price) {
7
- if (isNaN(price)) {
5
+ export function formatPrice(price, option) {
6
+ if (isNaN(Number(price))) {
8
7
  return {
9
8
  price: '',
10
9
  negative: false,
@@ -20,13 +19,20 @@ export function formatPrice(price) {
20
19
  price = -price;
21
20
  }
22
21
  const integer = Math.floor(price).toString();
23
- const decimal = (Math.round(+price + 'e' + 2) % 100).toString().padStart(2, '0');
22
+ const decimalNum = Math.round(Number(price + 'e' + (option?.precision ?? 2))) % 100;
23
+ let decimal;
24
+ if (option?.padDecimal ?? true) {
25
+ decimal = '.' + decimalNum.toString().padStart(option?.precision ?? 2, '0');
26
+ } else {
27
+ if (decimalNum === 0) decimal = '';
28
+ else decimal = decimalNum.toString().slice(1);
29
+ }
24
30
  const formattedPrice = `${negative ? '-' : ''}${integer}.${decimal}`;
25
31
  return {
26
- price: formattedPrice, // 价格字符串
32
+ price: formattedPrice,
27
33
  negative,
28
- integer, // 整数部分
29
- decimal, // 小数部分
34
+ integer,
35
+ decimal,
30
36
  number: Number(formattedPrice),
31
37
  };
32
38
  }