@etsoo/appscript 1.5.63 → 1.5.65
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/.github/workflows/main.yml +6 -5
- package/README.md +97 -71
- package/__tests__/app/CoreApp.ts +141 -143
- package/__tests__/app/Culture.ts +23 -23
- package/__tests__/app/TestApp.ts +107 -105
- package/__tests__/business/BusinessUtils.ts +37 -37
- package/__tests__/result/ActionResult.ts +14 -14
- package/__tests__/tsconfig.json +16 -16
- package/babel.config.json +8 -8
- package/lib/cjs/address/AddressAutocomplete.d.ts +1 -1
- package/lib/cjs/address/AddressPlace.d.ts +3 -3
- package/lib/cjs/address/AddressPlaceBase.d.ts +1 -1
- package/lib/cjs/address/AddressRegion.d.ts +2 -2
- package/lib/cjs/address/AddressRegion.js +12 -12
- package/lib/cjs/address/AddressUtils.d.ts +1 -1
- package/lib/cjs/api/AuthApi.d.ts +14 -14
- package/lib/cjs/api/AuthApi.js +17 -17
- package/lib/cjs/api/BaseApi.d.ts +1 -1
- package/lib/cjs/api/EntityApi.d.ts +8 -8
- package/lib/cjs/api/EntityApi.js +4 -4
- package/lib/cjs/api/dto/AuditLineDto.d.ts +24 -0
- package/lib/cjs/api/dto/AuditLineDto.js +2 -0
- package/lib/cjs/api/dto/IdLabelDto.d.ts +1 -1
- package/lib/cjs/api/dto/IdLabelPrimaryDto.d.ts +1 -1
- package/lib/cjs/api/dto/PinDto.d.ts +61 -0
- package/lib/cjs/api/dto/PinDto.js +2 -0
- package/lib/cjs/api/dto/ResultPayload.d.ts +2 -2
- package/lib/cjs/api/rq/AuthRequest.d.ts +1 -1
- package/lib/cjs/api/rq/LoginRQ.d.ts +2 -2
- package/lib/cjs/api/rq/MergeRQ.d.ts +1 -1
- package/lib/cjs/api/rq/QueryRQ.d.ts +2 -2
- package/lib/cjs/api/rq/StatusQueryRQ.d.ts +3 -3
- package/lib/cjs/api/rq/UpdateModel.d.ts +2 -2
- package/lib/cjs/api/rq/UpdateStatusRQ.d.ts +2 -2
- package/lib/cjs/app/AppSettings.d.ts +3 -3
- package/lib/cjs/bridges/FlutterHost.d.ts +2 -2
- package/lib/cjs/bridges/FlutterHost.js +11 -11
- package/lib/cjs/business/BusinessTax.js +6 -6
- package/lib/cjs/business/BusinessUtils.d.ts +2 -2
- package/lib/cjs/business/BusinessUtils.js +5 -5
- package/lib/cjs/business/Currency.d.ts +1 -1
- package/lib/cjs/business/Currency.js +10 -10
- package/lib/cjs/business/ProductUnit.d.ts +1 -1
- package/lib/cjs/business/ShoppingCart.d.ts +9 -9
- package/lib/cjs/business/ShoppingCart.js +11 -11
- package/lib/cjs/custom/CustomField.d.ts +1 -1
- package/lib/cjs/custom/CustomFieldData.d.ts +2 -2
- package/lib/cjs/i18n/Culture.d.ts +31 -0
- package/lib/cjs/i18n/Culture.js +51 -0
- package/lib/cjs/index.d.ts +3 -4
- package/lib/cjs/index.js +3 -4
- package/lib/cjs/result/ActionResult.d.ts +1 -1
- package/lib/cjs/result/ActionResultError.d.ts +1 -1
- package/lib/cjs/result/ActionResultError.js +3 -3
- package/lib/cjs/result/InitCallResult.d.ts +1 -1
- package/lib/cjs/state/Culture.d.ts +2 -2
- package/lib/cjs/state/User.d.ts +1 -1
- package/lib/mjs/address/AddressAutocomplete.d.ts +1 -1
- package/lib/mjs/address/AddressPlace.d.ts +3 -3
- package/lib/mjs/address/AddressPlaceBase.d.ts +1 -1
- package/lib/mjs/address/AddressRegion.d.ts +2 -2
- package/lib/mjs/address/AddressRegion.js +13 -13
- package/lib/mjs/address/AddressUtils.d.ts +1 -1
- package/lib/mjs/address/AddressUtils.js +1 -1
- package/lib/mjs/api/AuthApi.d.ts +14 -14
- package/lib/mjs/api/AuthApi.js +19 -19
- package/lib/mjs/api/BaseApi.d.ts +1 -1
- package/lib/mjs/api/EntityApi.d.ts +8 -8
- package/lib/mjs/api/EntityApi.js +5 -5
- package/lib/mjs/api/dto/AuditLineDto.d.ts +24 -0
- package/lib/mjs/api/dto/AuditLineDto.js +1 -0
- package/lib/mjs/api/dto/IdLabelDto.d.ts +1 -1
- package/lib/mjs/api/dto/IdLabelPrimaryDto.d.ts +1 -1
- package/lib/mjs/api/dto/PinDto.d.ts +61 -0
- package/lib/mjs/api/dto/PinDto.js +1 -0
- package/lib/mjs/api/dto/ResultPayload.d.ts +2 -2
- package/lib/mjs/api/rq/AuthRequest.d.ts +1 -1
- package/lib/mjs/api/rq/LoginRQ.d.ts +2 -2
- package/lib/mjs/api/rq/MergeRQ.d.ts +1 -1
- package/lib/mjs/api/rq/QueryRQ.d.ts +2 -2
- package/lib/mjs/api/rq/StatusQueryRQ.d.ts +3 -3
- package/lib/mjs/api/rq/UpdateModel.d.ts +2 -2
- package/lib/mjs/api/rq/UpdateStatusRQ.d.ts +2 -2
- package/lib/mjs/app/AppSettings.d.ts +3 -3
- package/lib/mjs/bridges/FlutterHost.d.ts +2 -2
- package/lib/mjs/bridges/FlutterHost.js +13 -13
- package/lib/mjs/business/BusinessTax.js +6 -6
- package/lib/mjs/business/BusinessUtils.d.ts +2 -2
- package/lib/mjs/business/BusinessUtils.js +5 -5
- package/lib/mjs/business/Currency.d.ts +1 -1
- package/lib/mjs/business/Currency.js +10 -10
- package/lib/mjs/business/ProductUnit.d.ts +1 -1
- package/lib/mjs/business/ProductUnit.js +1 -1
- package/lib/mjs/business/ShoppingCart.d.ts +9 -9
- package/lib/mjs/business/ShoppingCart.js +12 -12
- package/lib/mjs/custom/CustomField.d.ts +1 -1
- package/lib/mjs/custom/CustomFieldData.d.ts +2 -2
- package/lib/mjs/i18n/Culture.d.ts +31 -0
- package/lib/mjs/i18n/Culture.js +48 -0
- package/lib/mjs/index.d.ts +3 -4
- package/lib/mjs/index.js +3 -4
- package/lib/mjs/result/ActionResult.d.ts +1 -1
- package/lib/mjs/result/ActionResult.js +1 -1
- package/lib/mjs/result/ActionResultError.d.ts +1 -1
- package/lib/mjs/result/ActionResultError.js +3 -3
- package/lib/mjs/result/InitCallResult.d.ts +1 -1
- package/lib/mjs/state/Culture.d.ts +2 -2
- package/lib/mjs/state/User.d.ts +1 -1
- package/package.json +1 -1
- package/src/address/AddressAutocomplete.ts +16 -16
- package/src/address/AddressCity.ts +12 -12
- package/src/address/AddressContinent.ts +35 -35
- package/src/address/AddressDistrict.ts +12 -12
- package/src/address/AddressLocation.ts +8 -8
- package/src/address/AddressPlace.ts +23 -23
- package/src/address/AddressPlaceBase.ts +31 -31
- package/src/address/AddressRegion.ts +286 -286
- package/src/address/AddressState.ts +12 -12
- package/src/address/AddressUtils.ts +27 -27
- package/src/api/AuthApi.ts +194 -194
- package/src/api/BaseApi.ts +13 -13
- package/src/api/EntityApi.ts +181 -194
- package/src/api/dto/AntiforgeryRequestToken.ts +15 -15
- package/src/api/dto/ApiRefreshTokenDto.ts +16 -16
- package/src/api/dto/AuditLineDto.ts +27 -0
- package/src/api/dto/IdLabelDto.ts +3 -3
- package/src/api/dto/IdLabelPrimaryDto.ts +7 -7
- package/src/api/dto/InitCallDto.ts +12 -12
- package/src/api/dto/PinDto.ts +71 -0
- package/src/api/dto/ResultPayload.ts +6 -6
- package/src/api/rq/ApiRefreshTokenRQ.ts +8 -8
- package/src/api/rq/AuthRequest.ts +40 -40
- package/src/api/rq/GetLogInUrlRQ.ts +8 -8
- package/src/api/rq/LoginIdRQ.ts +12 -12
- package/src/api/rq/LoginRQ.ts +18 -18
- package/src/api/rq/MergeRQ.ts +13 -13
- package/src/api/rq/QueryPagingData.ts +16 -16
- package/src/api/rq/QueryRQ.ts +22 -22
- package/src/api/rq/RefreshTokenRQ.ts +4 -4
- package/src/api/rq/ResetPasswordRQ.ts +20 -20
- package/src/api/rq/SignoutRQ.ts +8 -8
- package/src/api/rq/StatusQueryRQ.ts +11 -11
- package/src/api/rq/SwitchOrgRQ.ts +8 -8
- package/src/api/rq/TokenRQ.ts +4 -4
- package/src/api/rq/UpdateModel.ts +12 -12
- package/src/api/rq/UpdateStatusRQ.ts +10 -10
- package/src/app/AppSettings.ts +27 -27
- package/src/app/UserRole.ts +44 -44
- package/src/bridges/FlutterHost.ts +92 -97
- package/src/bridges/IBridgeHost.ts +49 -51
- package/src/business/ApiService.ts +25 -25
- package/src/business/BusinessTax.ts +63 -63
- package/src/business/BusinessUtils.ts +75 -75
- package/src/business/CultureItem.ts +43 -43
- package/src/business/Currency.ts +11 -11
- package/src/business/DataPrivacy.ts +35 -35
- package/src/business/EntityStatus.ts +44 -44
- package/src/business/ProductUnit.ts +58 -58
- package/src/business/RepeatOption.ts +50 -50
- package/src/business/ShoppingCart.ts +696 -706
- package/src/custom/CustomField.ts +20 -20
- package/src/custom/CustomFieldData.ts +43 -43
- package/src/def/ListItem.ts +12 -12
- package/src/i18n/Culture.ts +60 -0
- package/src/i18n/en.json +244 -244
- package/src/i18n/zh-Hans.json +244 -244
- package/src/i18n/zh-Hant.json +244 -244
- package/src/index.ts +3 -4
- package/src/result/ActionResult.ts +19 -19
- package/src/result/ActionResultError.ts +30 -30
- package/src/result/InitCallResult.ts +21 -21
- package/src/state/Culture.ts +3 -3
- package/src/state/State.ts +5 -5
- package/src/state/User.ts +92 -92
- package/tsconfig.cjs.json +17 -17
- package/tsconfig.json +17 -17
- package/lib/cjs/i18n/CultureUtils.d.ts +0 -13
- package/lib/cjs/i18n/CultureUtils.js +0 -32
- package/lib/cjs/i18n/en.d.ts +0 -6
- package/lib/cjs/i18n/en.js +0 -12
- package/lib/cjs/i18n/zhHans.d.ts +0 -6
- package/lib/cjs/i18n/zhHans.js +0 -12
- package/lib/cjs/i18n/zhHant.d.ts +0 -6
- package/lib/cjs/i18n/zhHant.js +0 -12
- package/lib/mjs/i18n/CultureUtils.d.ts +0 -13
- package/lib/mjs/i18n/CultureUtils.js +0 -29
- package/lib/mjs/i18n/en.d.ts +0 -6
- package/lib/mjs/i18n/en.js +0 -8
- package/lib/mjs/i18n/zhHans.d.ts +0 -6
- package/lib/mjs/i18n/zhHans.js +0 -8
- package/lib/mjs/i18n/zhHant.d.ts +0 -6
- package/lib/mjs/i18n/zhHant.js +0 -8
- package/src/i18n/CultureUtils.ts +0 -36
- package/src/i18n/en.ts +0 -10
- package/src/i18n/zhHans.ts +0 -10
- package/src/i18n/zhHant.ts +0 -10
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from
|
|
8
|
-
import { Currency } from
|
|
2
|
+
DataTypes,
|
|
3
|
+
IStorage,
|
|
4
|
+
IdType,
|
|
5
|
+
NumberUtils,
|
|
6
|
+
WindowStorage
|
|
7
|
+
} from "@etsoo/shared";
|
|
8
|
+
import { Currency } from "./Currency";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Shopping cart owner
|
|
12
12
|
* 购物篮所有人
|
|
13
13
|
*/
|
|
14
14
|
export type ShoppingCartOwner = DataTypes.IdNameItem & {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
culture?: string;
|
|
16
|
+
currency?: Currency;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -21,13 +21,13 @@ export type ShoppingCartOwner = DataTypes.IdNameItem & {
|
|
|
21
21
|
* 购物篮数据
|
|
22
22
|
*/
|
|
23
23
|
export type ShoppingCartData<T extends ShoppingCartItem> = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
culture: string;
|
|
25
|
+
currency: Currency;
|
|
26
|
+
owner: ShoppingCartOwner;
|
|
27
|
+
items: T[];
|
|
28
|
+
promotions: ShoppingPromotion[];
|
|
29
|
+
formData?: any;
|
|
30
|
+
cache?: Record<string, unknown>;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -35,23 +35,23 @@ export type ShoppingCartData<T extends ShoppingCartItem> = {
|
|
|
35
35
|
* 购物促销
|
|
36
36
|
*/
|
|
37
37
|
export type ShoppingPromotion = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Promotion id
|
|
40
|
+
* 促销编号
|
|
41
|
+
*/
|
|
42
|
+
id: number;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Promotion title
|
|
46
|
+
* 促销标题
|
|
47
|
+
*/
|
|
48
|
+
title: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Discount amount
|
|
52
|
+
* 折扣金额
|
|
53
|
+
*/
|
|
54
|
+
amount: number;
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
/**
|
|
@@ -59,40 +59,40 @@ export type ShoppingPromotion = {
|
|
|
59
59
|
* 购物篮基础项目
|
|
60
60
|
*/
|
|
61
61
|
export type ShoppingCartItemBase = {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Product id
|
|
64
|
+
* 产品编号
|
|
65
|
+
*/
|
|
66
|
+
id: IdType;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Product title, default is name
|
|
70
|
+
* 产品标题,默认为name
|
|
71
|
+
*/
|
|
72
|
+
title?: string;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Sale price
|
|
76
|
+
* 销售价格
|
|
77
|
+
*/
|
|
78
|
+
price: number;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Qty
|
|
82
|
+
* 数量
|
|
83
|
+
*/
|
|
84
|
+
qty: number;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Asset qty
|
|
88
|
+
*/
|
|
89
|
+
assetQty?: number;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Product level promotions
|
|
93
|
+
* 产品层次促销
|
|
94
|
+
*/
|
|
95
|
+
promotions: ShoppingPromotion[];
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
/**
|
|
@@ -100,29 +100,29 @@ export type ShoppingCartItemBase = {
|
|
|
100
100
|
* 购物篮项目
|
|
101
101
|
*/
|
|
102
102
|
export type ShoppingCartItem = ShoppingCartItemBase & {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Product name
|
|
105
|
+
* 产品名称
|
|
106
|
+
*/
|
|
107
|
+
name: string;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Current price for cache
|
|
111
|
+
* 当前缓存价格
|
|
112
|
+
*/
|
|
113
|
+
currentPrice?: number;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Subtotal
|
|
117
|
+
* 小计
|
|
118
|
+
*/
|
|
119
|
+
subtotal: number;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Total discount amount
|
|
123
|
+
* 总折扣金额
|
|
124
|
+
*/
|
|
125
|
+
discount: number;
|
|
126
126
|
};
|
|
127
127
|
|
|
128
128
|
/**
|
|
@@ -130,628 +130,618 @@ export type ShoppingCartItem = ShoppingCartItemBase & {
|
|
|
130
130
|
* 购物篮改变原因
|
|
131
131
|
*/
|
|
132
132
|
export type ShoppingCartChangeReason =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
133
|
+
| "add"
|
|
134
|
+
| "clear"
|
|
135
|
+
| "remove"
|
|
136
|
+
| "title"
|
|
137
|
+
| "update";
|
|
138
138
|
|
|
139
|
-
const ShoppingCartKeyField =
|
|
139
|
+
const ShoppingCartKeyField = "ETSOO-CART-KEYS";
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
142
|
* Shopping cart
|
|
143
143
|
* 购物篮
|
|
144
144
|
*/
|
|
145
145
|
export class ShoppingCart<T extends ShoppingCartItem> {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
) {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
try {
|
|
567
|
-
if (persisted) {
|
|
568
|
-
this.storage.setPersistedData(this.identifier, data);
|
|
569
|
-
|
|
570
|
-
const keys = this.keys;
|
|
571
|
-
if (!keys.includes(this.identifier)) {
|
|
572
|
-
keys.push(this.identifier);
|
|
573
|
-
this.keys = keys;
|
|
574
|
-
}
|
|
575
|
-
} else {
|
|
576
|
-
this.storage.setData(this.identifier, data);
|
|
577
|
-
}
|
|
578
|
-
} catch (error) {
|
|
579
|
-
console.warn(`ShoppingCart save ${this.identifier} error`, error);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
return data;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
/**
|
|
586
|
-
* Trigger update
|
|
587
|
-
* 触发更新
|
|
588
|
-
*/
|
|
589
|
-
update() {
|
|
590
|
-
this.doChange('update', []);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* Update discount
|
|
595
|
-
* @param item Shopping cart item
|
|
596
|
-
*/
|
|
597
|
-
updateDiscount(item: ShoppingCartItem) {
|
|
598
|
-
item.discount = item.promotions.sum('amount');
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
/**
|
|
602
|
-
* Update asset item
|
|
603
|
-
* 更新资产项目
|
|
604
|
-
* @param id Product id
|
|
605
|
-
* @param qty Asset qty
|
|
606
|
-
* @param itemCreator New item creator
|
|
607
|
-
* @returns Updated or not
|
|
608
|
-
*/
|
|
609
|
-
updateAssetItem(
|
|
610
|
-
id: T['id'],
|
|
611
|
-
assetQty: number | undefined,
|
|
612
|
-
itemCreator?: () => Omit<
|
|
613
|
-
T,
|
|
614
|
-
'id' | 'price' | 'assetQty' | 'subtotal' | 'discount' | 'promotions'
|
|
615
|
-
>
|
|
616
|
-
) {
|
|
617
|
-
if (assetQty == null || assetQty <= 0) assetQty = 1;
|
|
618
|
-
|
|
619
|
-
const index = this.items.findIndex((item) => item.id === id);
|
|
620
|
-
if (index === -1) {
|
|
621
|
-
// New
|
|
622
|
-
if (itemCreator) {
|
|
623
|
-
const price = this.prices[id];
|
|
624
|
-
const data = itemCreator();
|
|
625
|
-
const qty = data.qty;
|
|
626
|
-
const newItem = {
|
|
627
|
-
...data,
|
|
628
|
-
id,
|
|
629
|
-
price,
|
|
630
|
-
assetQty,
|
|
631
|
-
subtotal: price * qty * assetQty,
|
|
632
|
-
discount: 0,
|
|
633
|
-
promotions: Array<ShoppingPromotion>()
|
|
634
|
-
} as T;
|
|
635
|
-
this.addItem(newItem);
|
|
636
|
-
}
|
|
637
|
-
return false;
|
|
638
|
-
} else {
|
|
639
|
-
// Update
|
|
640
|
-
const item = this.items[index];
|
|
641
|
-
|
|
642
|
-
// Price may be cached first
|
|
643
|
-
const price = this.prices[id] ?? item.price;
|
|
644
|
-
const qty = item.qty;
|
|
645
|
-
|
|
646
|
-
const newItem = {
|
|
647
|
-
...item,
|
|
648
|
-
price,
|
|
649
|
-
assetQty,
|
|
650
|
-
subtotal: price * qty * assetQty,
|
|
651
|
-
discount: 0
|
|
652
|
-
};
|
|
653
|
-
this.items.splice(index, 1, newItem);
|
|
654
|
-
this.doChange('update', [item, newItem]);
|
|
146
|
+
/**
|
|
147
|
+
* Create identifier key
|
|
148
|
+
* 创建识别键
|
|
149
|
+
* @param currency Currency
|
|
150
|
+
* @param culture Culture
|
|
151
|
+
* @param key Additional key
|
|
152
|
+
* @returns Result
|
|
153
|
+
*/
|
|
154
|
+
static createKey(currency: Currency, culture: string, key: string) {
|
|
155
|
+
return `ETSOO-CART-${culture}-${key}-${currency}`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Clear shopping cart
|
|
160
|
+
* 清除购物篮
|
|
161
|
+
* @param identifier Identifier
|
|
162
|
+
* @param storage Storage
|
|
163
|
+
*/
|
|
164
|
+
static clear(identifier: string, storage: IStorage) {
|
|
165
|
+
try {
|
|
166
|
+
storage.setData(identifier, null);
|
|
167
|
+
storage.setPersistedData(identifier, null);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.warn(`ShoppingCart clear ${identifier} error`, error);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get cart data
|
|
175
|
+
* 获取购物篮数据
|
|
176
|
+
* @param storage Storage
|
|
177
|
+
* @param id Cart id
|
|
178
|
+
* @returns Result
|
|
179
|
+
*/
|
|
180
|
+
static getCartData<D extends ShoppingCartItem>(
|
|
181
|
+
storage: IStorage,
|
|
182
|
+
id: string
|
|
183
|
+
) {
|
|
184
|
+
try {
|
|
185
|
+
return (
|
|
186
|
+
storage.getPersistedObject<ShoppingCartData<D>>(id) ??
|
|
187
|
+
storage.getObject<ShoppingCartData<D>>(id)
|
|
188
|
+
);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.warn(`ShoppingCart getCartData ${id} error`, error);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Owner data
|
|
196
|
+
* 所有者信息
|
|
197
|
+
*/
|
|
198
|
+
owner?: ShoppingCartOwner;
|
|
199
|
+
|
|
200
|
+
_currency!: Currency;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* ISO currency id
|
|
204
|
+
* 标准货币编号
|
|
205
|
+
*/
|
|
206
|
+
get currency() {
|
|
207
|
+
return this._currency;
|
|
208
|
+
}
|
|
209
|
+
private set currency(value: Currency) {
|
|
210
|
+
this._currency = value;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
_culture!: string;
|
|
214
|
+
/**
|
|
215
|
+
* ISO culture id, like zh-Hans
|
|
216
|
+
* 标准语言文化编号
|
|
217
|
+
*/
|
|
218
|
+
get culture() {
|
|
219
|
+
return this._culture;
|
|
220
|
+
}
|
|
221
|
+
private set culture(value: string) {
|
|
222
|
+
this._culture = value;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
_items: T[] = [];
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Items
|
|
229
|
+
* 项目
|
|
230
|
+
*/
|
|
231
|
+
get items() {
|
|
232
|
+
return this._items;
|
|
233
|
+
}
|
|
234
|
+
private set items(value) {
|
|
235
|
+
this._items = value;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
_promotions: ShoppingPromotion[] = [];
|
|
239
|
+
/**
|
|
240
|
+
* Order level promotions
|
|
241
|
+
* 订单层面促销
|
|
242
|
+
*/
|
|
243
|
+
get promotions() {
|
|
244
|
+
return this._promotions;
|
|
245
|
+
}
|
|
246
|
+
private set promotions(value) {
|
|
247
|
+
this._promotions = value;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Related form data
|
|
252
|
+
* 关联的表单数据
|
|
253
|
+
*/
|
|
254
|
+
formData: any;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Cache
|
|
258
|
+
* 缓存对象
|
|
259
|
+
*/
|
|
260
|
+
cache?: Record<string, unknown>;
|
|
261
|
+
|
|
262
|
+
_symbol: string | undefined;
|
|
263
|
+
/**
|
|
264
|
+
* Currency symbol
|
|
265
|
+
* 币种符号
|
|
266
|
+
*/
|
|
267
|
+
get symbol() {
|
|
268
|
+
return this._symbol;
|
|
269
|
+
}
|
|
270
|
+
private set symbol(value: string | undefined) {
|
|
271
|
+
this._symbol = value;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Key for identifier
|
|
276
|
+
*/
|
|
277
|
+
readonly key: string;
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Cart identifier
|
|
281
|
+
* 购物篮标识
|
|
282
|
+
*/
|
|
283
|
+
get identifier() {
|
|
284
|
+
const o = this.owner;
|
|
285
|
+
return ShoppingCart.createKey(this.currency, this.culture, this.key);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* All data keys
|
|
290
|
+
* 所有的数据键
|
|
291
|
+
*/
|
|
292
|
+
get keys() {
|
|
293
|
+
return this.storage.getPersistedData<string[]>(ShoppingCartKeyField, []);
|
|
294
|
+
}
|
|
295
|
+
set keys(items: string[]) {
|
|
296
|
+
this.storage.setPersistedData(ShoppingCartKeyField, items);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Lines count
|
|
301
|
+
* 项目数量
|
|
302
|
+
*/
|
|
303
|
+
get lines() {
|
|
304
|
+
return this.items.length;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Total qty
|
|
309
|
+
* 总数量
|
|
310
|
+
*/
|
|
311
|
+
get totalQty() {
|
|
312
|
+
return this.items.map((item) => item.qty).sum();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Total amount
|
|
317
|
+
* 总金额
|
|
318
|
+
*/
|
|
319
|
+
get totalAmount() {
|
|
320
|
+
const subtotal = this.items
|
|
321
|
+
.map((item) => item.subtotal - item.discount)
|
|
322
|
+
.sum();
|
|
323
|
+
|
|
324
|
+
const discount = this.promotions.sum("amount");
|
|
325
|
+
|
|
326
|
+
return subtotal - discount;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Total amount string
|
|
331
|
+
* 总金额字符串
|
|
332
|
+
*/
|
|
333
|
+
get totalAmountStr() {
|
|
334
|
+
return this.formatAmount(this.totalAmount);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Cached prices
|
|
339
|
+
* 缓存的价格
|
|
340
|
+
*/
|
|
341
|
+
private prices = <Record<T["id"], number>>{};
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Onchange callback
|
|
345
|
+
* 改变时回调
|
|
346
|
+
*/
|
|
347
|
+
onChange?: (reason: ShoppingCartChangeReason, changedItems: T[]) => void;
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Constructor
|
|
351
|
+
* 构造函数
|
|
352
|
+
* @param key Key for identifier
|
|
353
|
+
* @param init Currency & culture ISO code array
|
|
354
|
+
* @param storage Data storage
|
|
355
|
+
*/
|
|
356
|
+
constructor(key: string, init: [Currency, string], storage?: IStorage);
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Constructor
|
|
360
|
+
* 构造函数
|
|
361
|
+
* @param key Key for identifier
|
|
362
|
+
* @param state Initialization state
|
|
363
|
+
* @param storage Data storage
|
|
364
|
+
*/
|
|
365
|
+
constructor(key: string, state: ShoppingCartData<T>, storage?: IStorage);
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Constructor
|
|
369
|
+
* 构造函数
|
|
370
|
+
* @param key Key for identifier
|
|
371
|
+
* @param currency Currency ISO code
|
|
372
|
+
* @param storage Data storage
|
|
373
|
+
*/
|
|
374
|
+
constructor(
|
|
375
|
+
key: string,
|
|
376
|
+
currencyOrState: [Currency, string] | ShoppingCartData<T>,
|
|
377
|
+
private readonly storage: IStorage = new WindowStorage()
|
|
378
|
+
) {
|
|
379
|
+
this.key = key;
|
|
380
|
+
|
|
381
|
+
if (Array.isArray(currencyOrState)) {
|
|
382
|
+
this.reset(currencyOrState[0], currencyOrState[1]);
|
|
383
|
+
} else {
|
|
384
|
+
this.setCartData(currencyOrState);
|
|
385
|
+
this.changeCurrency(currencyOrState.currency);
|
|
386
|
+
this.changeCulture(currencyOrState.culture);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
private getCartData(): ShoppingCartData<T> | undefined {
|
|
390
|
+
return (
|
|
391
|
+
this.storage.getPersistedObject(this.identifier) ??
|
|
392
|
+
this.storage.getObject(this.identifier)
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
private setCartData(state: ShoppingCartData<T> | undefined) {
|
|
397
|
+
const { owner, items = [], promotions = [], formData, cache } = state ?? {};
|
|
398
|
+
this.owner = owner;
|
|
399
|
+
this.items = items;
|
|
400
|
+
this.promotions = promotions;
|
|
401
|
+
this.formData = formData;
|
|
402
|
+
this.cache = cache;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private doChange(reason: ShoppingCartChangeReason, changedItems: T[]) {
|
|
406
|
+
if (this.onChange) this.onChange(reason, changedItems);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Add item
|
|
411
|
+
* 添加项目
|
|
412
|
+
* @param item New item
|
|
413
|
+
*/
|
|
414
|
+
addItem(item: T) {
|
|
415
|
+
this.addItems([item]);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Add items
|
|
420
|
+
* @param items New items
|
|
421
|
+
*/
|
|
422
|
+
addItems(items: T[]) {
|
|
423
|
+
this.items.push(...items);
|
|
424
|
+
this.doChange("add", items);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Cache price
|
|
429
|
+
* @param id Item id
|
|
430
|
+
* @param price Price
|
|
431
|
+
* @param overrideExisting Override existing price
|
|
432
|
+
*/
|
|
433
|
+
cachePrice(id: T["id"], price: number, overrideExisting: boolean = false) {
|
|
434
|
+
if (overrideExisting || this.prices[id] == null) this.prices[id] = price;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Change currency
|
|
439
|
+
* @param currency Currency
|
|
440
|
+
*/
|
|
441
|
+
changeCurrency(currency: Currency) {
|
|
442
|
+
this.currency = currency;
|
|
443
|
+
this.symbol = NumberUtils.getCurrencySymbol(this.currency);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Change culture
|
|
448
|
+
* @param culture Culture
|
|
449
|
+
*/
|
|
450
|
+
changeCulture(culture: string) {
|
|
451
|
+
this.culture = culture;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Clear storage
|
|
456
|
+
* @param keepOwner Keep owner data
|
|
457
|
+
*/
|
|
458
|
+
clear(keepOwner?: boolean) {
|
|
459
|
+
this.items.length = 0;
|
|
460
|
+
this.promotions.length = 0;
|
|
461
|
+
this.prices = <Record<T["id"], number>>{};
|
|
462
|
+
this.cache = undefined;
|
|
463
|
+
|
|
464
|
+
if (keepOwner) {
|
|
465
|
+
this.save();
|
|
466
|
+
} else {
|
|
467
|
+
ShoppingCart.clear(this.identifier, this.storage);
|
|
468
|
+
this.keys.remove(this.identifier);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
this.doChange("clear", []);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Format amount
|
|
476
|
+
* @param amount Amount
|
|
477
|
+
* @returns Result
|
|
478
|
+
*/
|
|
479
|
+
formatAmount(amount: number) {
|
|
480
|
+
return NumberUtils.formatMoney(amount, this.currency);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Get item
|
|
485
|
+
* @param id Item id
|
|
486
|
+
* @returns Result
|
|
487
|
+
*/
|
|
488
|
+
getItem(id: T["id"]) {
|
|
489
|
+
return this.items.find((item) => item.id === id);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Push item
|
|
494
|
+
* 推送项目
|
|
495
|
+
* @param data Item data
|
|
496
|
+
* @returns Added or not
|
|
497
|
+
*/
|
|
498
|
+
pushItem(data: T) {
|
|
499
|
+
if (this.items.some((item) => item.id === data.id)) {
|
|
500
|
+
return false;
|
|
501
|
+
} else {
|
|
502
|
+
this.addItem(data);
|
|
503
|
+
return true;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Reset currency and culture
|
|
509
|
+
* @param currency New currency
|
|
510
|
+
* @param culture New culture
|
|
511
|
+
*/
|
|
512
|
+
reset(currency: Currency, culture: string) {
|
|
513
|
+
this.changeCurrency(currency);
|
|
514
|
+
this.changeCulture(culture);
|
|
515
|
+
this.setCartData(this.getCartData());
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Remove item from the index
|
|
520
|
+
* @param index Item index
|
|
521
|
+
*/
|
|
522
|
+
removeItem(index: number) {
|
|
523
|
+
const removedItems = this.items.splice(index, 1);
|
|
524
|
+
this.doChange("remove", removedItems);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Reset item
|
|
529
|
+
* @param item Shopping cart item
|
|
530
|
+
*/
|
|
531
|
+
resetItem(item: ShoppingCartItem) {
|
|
532
|
+
item.discount = 0;
|
|
533
|
+
item.currentPrice = undefined;
|
|
534
|
+
item.promotions = [];
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Save cart data
|
|
539
|
+
* @param persisted For persisted storage
|
|
540
|
+
*/
|
|
541
|
+
save(persisted: boolean = true) {
|
|
542
|
+
if (this.owner == null) return;
|
|
543
|
+
|
|
544
|
+
const { currency, culture, owner, items, promotions, formData, cache } =
|
|
545
|
+
this;
|
|
546
|
+
const data: ShoppingCartData<T> = {
|
|
547
|
+
currency,
|
|
548
|
+
culture,
|
|
549
|
+
owner,
|
|
550
|
+
items,
|
|
551
|
+
promotions,
|
|
552
|
+
formData,
|
|
553
|
+
cache
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
try {
|
|
557
|
+
if (persisted) {
|
|
558
|
+
this.storage.setPersistedData(this.identifier, data);
|
|
559
|
+
|
|
560
|
+
const keys = this.keys;
|
|
561
|
+
if (!keys.includes(this.identifier)) {
|
|
562
|
+
keys.push(this.identifier);
|
|
563
|
+
this.keys = keys;
|
|
655
564
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
565
|
+
} else {
|
|
566
|
+
this.storage.setData(this.identifier, data);
|
|
567
|
+
}
|
|
568
|
+
} catch (error) {
|
|
569
|
+
console.warn(`ShoppingCart save ${this.identifier} error`, error);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return data;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Trigger update
|
|
577
|
+
* 触发更新
|
|
578
|
+
*/
|
|
579
|
+
update() {
|
|
580
|
+
this.doChange("update", []);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Update discount
|
|
585
|
+
* @param item Shopping cart item
|
|
586
|
+
*/
|
|
587
|
+
updateDiscount(item: ShoppingCartItem) {
|
|
588
|
+
item.discount = item.promotions.sum("amount");
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Update asset item
|
|
593
|
+
* 更新资产项目
|
|
594
|
+
* @param id Product id
|
|
595
|
+
* @param qty Asset qty
|
|
596
|
+
* @param itemCreator New item creator
|
|
597
|
+
* @returns Updated or not
|
|
598
|
+
*/
|
|
599
|
+
updateAssetItem(
|
|
600
|
+
id: T["id"],
|
|
601
|
+
assetQty: number | undefined,
|
|
602
|
+
itemCreator?: () => Omit<
|
|
603
|
+
T,
|
|
604
|
+
"id" | "price" | "assetQty" | "subtotal" | "discount" | "promotions"
|
|
605
|
+
>
|
|
606
|
+
) {
|
|
607
|
+
if (assetQty == null || assetQty <= 0) assetQty = 1;
|
|
608
|
+
|
|
609
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
610
|
+
if (index === -1) {
|
|
611
|
+
// New
|
|
612
|
+
if (itemCreator) {
|
|
613
|
+
const price = this.prices[id];
|
|
614
|
+
const data = itemCreator();
|
|
615
|
+
const qty = data.qty;
|
|
616
|
+
const newItem = {
|
|
617
|
+
...data,
|
|
618
|
+
id,
|
|
619
|
+
price,
|
|
620
|
+
assetQty,
|
|
621
|
+
subtotal: price * qty * assetQty,
|
|
622
|
+
discount: 0,
|
|
623
|
+
promotions: Array<ShoppingPromotion>()
|
|
624
|
+
} as T;
|
|
625
|
+
this.addItem(newItem);
|
|
626
|
+
}
|
|
627
|
+
return false;
|
|
628
|
+
} else {
|
|
629
|
+
// Update
|
|
630
|
+
const item = this.items[index];
|
|
631
|
+
|
|
632
|
+
// Price may be cached first
|
|
633
|
+
const price = this.prices[id] ?? item.price;
|
|
634
|
+
const qty = item.qty;
|
|
635
|
+
|
|
636
|
+
const newItem = {
|
|
637
|
+
...item,
|
|
638
|
+
price,
|
|
639
|
+
assetQty,
|
|
640
|
+
subtotal: price * qty * assetQty,
|
|
641
|
+
discount: 0
|
|
642
|
+
};
|
|
643
|
+
this.items.splice(index, 1, newItem);
|
|
644
|
+
this.doChange("update", [item, newItem]);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
return true;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Update item
|
|
652
|
+
* 更新项目
|
|
653
|
+
* @param id Product id
|
|
654
|
+
* @param qty Qty
|
|
655
|
+
* @param itemCreator New item creator
|
|
656
|
+
* @returns Updated or not
|
|
657
|
+
*/
|
|
658
|
+
updateItem(
|
|
659
|
+
id: T["id"],
|
|
660
|
+
qty: number | undefined,
|
|
661
|
+
itemCreator?: () => Omit<
|
|
662
|
+
T,
|
|
663
|
+
"id" | "price" | "qty" | "subtotal" | "discount" | "promotions"
|
|
664
|
+
>
|
|
665
|
+
) {
|
|
666
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
667
|
+
if (qty == null) {
|
|
668
|
+
// Remove the item
|
|
669
|
+
if (index !== -1) {
|
|
670
|
+
this.removeItem(index);
|
|
671
|
+
}
|
|
672
|
+
} else if (index === -1) {
|
|
673
|
+
// New
|
|
674
|
+
if (itemCreator) {
|
|
675
|
+
const price = this.prices[id];
|
|
676
|
+
const data = itemCreator();
|
|
677
|
+
const newItem = {
|
|
678
|
+
...data,
|
|
679
|
+
id,
|
|
680
|
+
price,
|
|
681
|
+
qty,
|
|
682
|
+
subtotal: price * qty * (data.assetQty || 1),
|
|
683
|
+
discount: 0,
|
|
684
|
+
promotions: Array<ShoppingPromotion>()
|
|
685
|
+
} as T;
|
|
686
|
+
this.addItem(newItem);
|
|
687
|
+
}
|
|
688
|
+
return false;
|
|
689
|
+
} else {
|
|
690
|
+
// Update
|
|
691
|
+
const item = this.items[index];
|
|
692
|
+
|
|
693
|
+
// Price may be cached first
|
|
694
|
+
const price = this.prices[id] ?? item.price;
|
|
695
|
+
const newItem = {
|
|
696
|
+
...item,
|
|
697
|
+
qty,
|
|
698
|
+
price,
|
|
699
|
+
subtotal: price * qty * (item.assetQty || 1),
|
|
700
|
+
discount: 0
|
|
701
|
+
};
|
|
702
|
+
this.items.splice(index, 1, newItem);
|
|
703
|
+
this.doChange("update", [item, newItem]);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Update price
|
|
711
|
+
* @param id Item id
|
|
712
|
+
* @param price New price
|
|
713
|
+
*/
|
|
714
|
+
updatePrice(id: T["id"], price: number) {
|
|
715
|
+
this.cachePrice(id, price, true);
|
|
716
|
+
|
|
717
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
718
|
+
if (index !== -1) {
|
|
719
|
+
const item = this.items[index];
|
|
720
|
+
const qty = item.qty;
|
|
721
|
+
const assetQty = item.assetQty || 1;
|
|
722
|
+
const newItem = {
|
|
723
|
+
...item,
|
|
724
|
+
price,
|
|
725
|
+
subtotal: price * qty * assetQty
|
|
726
|
+
};
|
|
727
|
+
this.items.splice(index, 1, newItem);
|
|
728
|
+
this.doChange("update", [item, newItem]);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Update title
|
|
734
|
+
* @param id Item id
|
|
735
|
+
* @param title New title
|
|
736
|
+
*/
|
|
737
|
+
updateTitle(id: T["id"], title: string) {
|
|
738
|
+
const index = this.items.findIndex((item) => item.id === id);
|
|
739
|
+
if (index !== -1) {
|
|
740
|
+
const item = this.items[index];
|
|
741
|
+
const newItem: T = { ...item, title };
|
|
742
|
+
if (newItem.name === newItem.title) newItem.title = undefined;
|
|
743
|
+
this.items.splice(index, 1, newItem);
|
|
744
|
+
this.doChange("title", [item, newItem]);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
757
747
|
}
|