@yorkjs/hive-ui 0.0.7 → 0.0.9
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/package.json +1 -1
- package/src/components/Checkbox/index.tsx +3 -2
- package/src/components/Tag/index.tsx +2 -1
- package/src/config.ts +26 -0
- package/src/index.ts +3 -1
- package/src/item/ProductItem/ProductItem.tsx +440 -0
- package/src/item/ProductItem/config.ts +35 -0
- package/src/item/ProductItem/index.tsx +5 -450
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from 'react'
|
|
2
2
|
import { View, Text } from '@tarojs/components'
|
|
3
3
|
|
|
4
|
+
import { useTheme } from '../../config'
|
|
4
5
|
import { isAndroid, isApp } from '../../util/env'
|
|
5
6
|
import { formatClassNames } from '../../util/function'
|
|
6
7
|
|
|
@@ -18,8 +19,6 @@ export interface CheckboxProps {
|
|
|
18
19
|
className?: string
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
const isDark = false
|
|
22
|
-
|
|
23
22
|
const Checkbox: React.FC<CheckboxProps> = (props) => {
|
|
24
23
|
const {
|
|
25
24
|
label,
|
|
@@ -31,6 +30,8 @@ const Checkbox: React.FC<CheckboxProps> = (props) => {
|
|
|
31
30
|
className,
|
|
32
31
|
} = props
|
|
33
32
|
|
|
33
|
+
const { isDark } = useTheme()
|
|
34
|
+
|
|
34
35
|
const handlePress = (e: any) => {
|
|
35
36
|
if (disabled || readOnly) return
|
|
36
37
|
onChange?.(!checked)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from 'react'
|
|
2
2
|
import { View, Text } from '@tarojs/components'
|
|
3
3
|
|
|
4
|
+
import { useTheme } from '../../config'
|
|
4
5
|
import { formatClassNames } from '../../util/function'
|
|
5
6
|
|
|
6
7
|
import styles from './index.module.styl'
|
|
@@ -30,7 +31,7 @@ const Tag: React.FC<TagProps> = ({
|
|
|
30
31
|
className,
|
|
31
32
|
style
|
|
32
33
|
}) => {
|
|
33
|
-
const themeSelect = (
|
|
34
|
+
const { themeSelect } = useTheme()
|
|
34
35
|
|
|
35
36
|
const tagStyle = useMemo(() => {
|
|
36
37
|
const colors = {
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react'
|
|
2
|
+
|
|
3
|
+
let globalIsDark = false
|
|
4
|
+
const listeners = new Set<(isDark: boolean) => void>()
|
|
5
|
+
|
|
6
|
+
export const setGlobalTheme = (theme: 'light' | 'dark' | string) => {
|
|
7
|
+
globalIsDark = theme === 'dark'
|
|
8
|
+
listeners.forEach((callback) => callback(globalIsDark))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const useTheme = () => {
|
|
12
|
+
const [isDark, setIsDark] = useState(globalIsDark)
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
listeners.add(setIsDark)
|
|
16
|
+
return () => {
|
|
17
|
+
listeners.delete(setIsDark)
|
|
18
|
+
}
|
|
19
|
+
}, [])
|
|
20
|
+
|
|
21
|
+
const themeSelect = <T>(lightValue: T, darkValue: T): T => {
|
|
22
|
+
return isDark ? darkValue : lightValue
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { isDark, themeSelect }
|
|
26
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { setGlobalTheme, useTheme } from './config'
|
|
2
|
+
|
|
1
3
|
export { default as NumberKeyboard } from './components/NumberKeyboard'
|
|
2
4
|
export { default as Cell, setCellConfig } from './components/Cell'
|
|
3
5
|
export { default as Icon } from './components/Icon'
|
|
@@ -5,4 +7,4 @@ export { default as Checkbox } from './components/Checkbox'
|
|
|
5
7
|
export { default as Tag } from './components/Tag'
|
|
6
8
|
|
|
7
9
|
export { default as FlowItem } from './item/FlowItem'
|
|
8
|
-
export { default as ProductItem } from './item/ProductItem'
|
|
10
|
+
export { default as ProductItem, setProductItemConfig } from './item/ProductItem'
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
|
+
import { View, Text, ScrollView, Image, ITouchEvent } from '@tarojs/components'
|
|
3
|
+
|
|
4
|
+
import { formatClassNames, isEmpty } from '../../util/function'
|
|
5
|
+
|
|
6
|
+
import Tag from '../../components/Tag'
|
|
7
|
+
import Icon from '../../components/Icon'
|
|
8
|
+
import Checkbox from '../../components/Checkbox'
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
MALL_PRODUCT_TYPE_REAL,
|
|
12
|
+
MALL_PRODUCT_TYPE_VIRTUAL,
|
|
13
|
+
MALL_PRODUCT_TYPE_SERVICE,
|
|
14
|
+
MALL_PRODUCT_DELIVERY_TYPE_EXPRESS,
|
|
15
|
+
MALL_PRODUCT_DELIVERY_TYPE_SELF,
|
|
16
|
+
MALL_PRODUCT_DELIVERY_TYPE_SHOP,
|
|
17
|
+
MALL_PRODUCT_DELIVERY_TYPE_DINE,
|
|
18
|
+
PROMOTION_ACTIVITY_TYPE_FLASH,
|
|
19
|
+
PROMOTION_ACTIVITY_TYPE_BRAND,
|
|
20
|
+
PROMOTION_ACTIVITY_TYPE_HOT,
|
|
21
|
+
PROMOTION_ACTIVITY_TYPE_PRESENT,
|
|
22
|
+
} from '../../constant/mall'
|
|
23
|
+
import { getProductItemConfig } from './config'
|
|
24
|
+
|
|
25
|
+
import styles from './index.module.styl'
|
|
26
|
+
|
|
27
|
+
export interface IProductCardLabels {
|
|
28
|
+
product_type?: { real: string; virtual: string; service: string }
|
|
29
|
+
delivery_type?: { dine: string; self_pickup: string; delivery: string }
|
|
30
|
+
activity_type?: { flash: string; brand: string; hot: string; present: string }
|
|
31
|
+
present_badge?: string
|
|
32
|
+
stock_label?: string
|
|
33
|
+
sale_label?: string
|
|
34
|
+
multiple_spec?: string
|
|
35
|
+
barcode_label?: string
|
|
36
|
+
spec_label?: string
|
|
37
|
+
sold_out?: string
|
|
38
|
+
offline?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 商品卡片组件属性 */
|
|
42
|
+
export interface IProductCardProps {
|
|
43
|
+
/** 外部样式类 */
|
|
44
|
+
className?: string
|
|
45
|
+
/** 商品图片对象 */
|
|
46
|
+
image: { url: string }
|
|
47
|
+
/** 是否显示售罄标记 */
|
|
48
|
+
showSoldOut?: boolean
|
|
49
|
+
/** 是否显示已下架标记 */
|
|
50
|
+
showOffline?: boolean
|
|
51
|
+
/** 商品标题 */
|
|
52
|
+
title: string
|
|
53
|
+
/** 标题最大显示行数 (默认1) */
|
|
54
|
+
titleMaxLines?: number
|
|
55
|
+
/** 商品类型:实物/虚拟/服务 */
|
|
56
|
+
productType?: number
|
|
57
|
+
/** 是否显示“多规格”标签 */
|
|
58
|
+
showMultipleSpec?: boolean
|
|
59
|
+
/** 库存数量文案 */
|
|
60
|
+
stockCount?: string | number
|
|
61
|
+
/** 销量文案 */
|
|
62
|
+
saleCount?: string | number
|
|
63
|
+
/** 商品条码 */
|
|
64
|
+
barcode?: string
|
|
65
|
+
/** 自定义标签 */
|
|
66
|
+
customTags?: React.ReactNode
|
|
67
|
+
/** 规格描述文案 (如: 红色, 大号) */
|
|
68
|
+
spec?: string
|
|
69
|
+
/** 规格描述最大显示行数 (默认1) */
|
|
70
|
+
specMaxLines?: number
|
|
71
|
+
/** 活动类型:秒杀/品牌/热点/满赠 */
|
|
72
|
+
activityType?: number
|
|
73
|
+
/** 配送方式集合:堂食/自提/外送 */
|
|
74
|
+
deliveryTypes?: number[]
|
|
75
|
+
/** 做法/定制化信息描述 */
|
|
76
|
+
customization?: string
|
|
77
|
+
/** 做法描述最大显示行数 (默认3) */
|
|
78
|
+
customizationMaxLines?: number
|
|
79
|
+
/** 套餐信息描述 */
|
|
80
|
+
combo? : string
|
|
81
|
+
/** 套餐描述最大显示行数 (默认3) */
|
|
82
|
+
comboMaxLines?: number
|
|
83
|
+
/** 售价 */
|
|
84
|
+
salePrice: string | number
|
|
85
|
+
/** 原价 (划线价) */
|
|
86
|
+
originalPrice?: string | number
|
|
87
|
+
/** 已购数量 (显示为 xN) */
|
|
88
|
+
buyCount?: number
|
|
89
|
+
/** 是否显示左侧勾选框 */
|
|
90
|
+
showCheckbox?: boolean
|
|
91
|
+
/** 勾选框是否选中 */
|
|
92
|
+
checkboxChecked?: boolean
|
|
93
|
+
/** 勾选框是否禁用 */
|
|
94
|
+
checkboxDisabled?: boolean
|
|
95
|
+
/** 点击勾选框或卡片触发 (当 checkbox 可用时) */
|
|
96
|
+
onCheckboxClick?: () => void
|
|
97
|
+
/** 是否显示右上角删除按钮 */
|
|
98
|
+
showDelete?: boolean
|
|
99
|
+
/** 点击删除按钮回调 */
|
|
100
|
+
onDelete?: () => void
|
|
101
|
+
/** 右下角自定义操作区域 (与 buyCount 互斥) */
|
|
102
|
+
action?: React.ReactNode
|
|
103
|
+
/** 是否显示底部分边框 */
|
|
104
|
+
showBottomBorder?: boolean
|
|
105
|
+
/** 是否显示底部分割线 */
|
|
106
|
+
showSeparator?: boolean
|
|
107
|
+
// 卡片点击事件
|
|
108
|
+
onClick?: () => void
|
|
109
|
+
children?: React.ReactNode
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const ProductItem: React.FC<IProductCardProps> = (props) => {
|
|
113
|
+
const {
|
|
114
|
+
image,
|
|
115
|
+
title,
|
|
116
|
+
titleMaxLines = 1,
|
|
117
|
+
productType,
|
|
118
|
+
customTags,
|
|
119
|
+
showMultipleSpec,
|
|
120
|
+
stockCount,
|
|
121
|
+
saleCount,
|
|
122
|
+
barcode,
|
|
123
|
+
spec,
|
|
124
|
+
specMaxLines = 1,
|
|
125
|
+
activityType,
|
|
126
|
+
deliveryTypes = [],
|
|
127
|
+
customization,
|
|
128
|
+
customizationMaxLines = 3,
|
|
129
|
+
combo,
|
|
130
|
+
comboMaxLines = 3,
|
|
131
|
+
salePrice,
|
|
132
|
+
originalPrice,
|
|
133
|
+
buyCount,
|
|
134
|
+
showSoldOut = false,
|
|
135
|
+
showOffline = false,
|
|
136
|
+
showCheckbox = false,
|
|
137
|
+
checkboxChecked = false,
|
|
138
|
+
checkboxDisabled = false,
|
|
139
|
+
onCheckboxClick,
|
|
140
|
+
showDelete,
|
|
141
|
+
onDelete,
|
|
142
|
+
action,
|
|
143
|
+
className,
|
|
144
|
+
showBottomBorder = false,
|
|
145
|
+
showSeparator = false,
|
|
146
|
+
onClick,
|
|
147
|
+
children
|
|
148
|
+
} = props
|
|
149
|
+
|
|
150
|
+
const handleCardClick = (e: ITouchEvent) => {
|
|
151
|
+
if (showCheckbox) {
|
|
152
|
+
if (!checkboxDisabled) {
|
|
153
|
+
onCheckboxClick?.()
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
onClick?.()
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const labels = useMemo(() => {
|
|
162
|
+
const globalConfig = getProductItemConfig()
|
|
163
|
+
return {
|
|
164
|
+
...globalConfig,
|
|
165
|
+
}
|
|
166
|
+
}, [])
|
|
167
|
+
|
|
168
|
+
const productTypeTag = useMemo(() => {
|
|
169
|
+
if (productType === undefined) return null
|
|
170
|
+
const colorMap: Record<number, { color: string; text: string | undefined }> = {
|
|
171
|
+
[MALL_PRODUCT_TYPE_REAL]: {
|
|
172
|
+
color: 'var(--primary)',
|
|
173
|
+
text: labels.product_type?.real
|
|
174
|
+
},
|
|
175
|
+
[MALL_PRODUCT_TYPE_VIRTUAL]: {
|
|
176
|
+
color: '#E4B700',
|
|
177
|
+
text: labels.product_type?.virtual
|
|
178
|
+
},
|
|
179
|
+
[MALL_PRODUCT_TYPE_SERVICE]: {
|
|
180
|
+
color: '#03BE02',
|
|
181
|
+
text: labels.product_type?.service
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
const item = colorMap[productType]
|
|
185
|
+
if (!item) return null
|
|
186
|
+
return (
|
|
187
|
+
<View className={styles['product-tag-container']}>
|
|
188
|
+
<Tag
|
|
189
|
+
type='light-warning'
|
|
190
|
+
text={item.text}
|
|
191
|
+
className={styles['product-tag']}
|
|
192
|
+
style={{ backgroundColor: item.color, color: '#fff' }}
|
|
193
|
+
/>
|
|
194
|
+
</View>
|
|
195
|
+
)
|
|
196
|
+
}, [productType, labels])
|
|
197
|
+
|
|
198
|
+
const deliveryTags = useMemo(() => {
|
|
199
|
+
if (isEmpty(deliveryTypes)) return null
|
|
200
|
+
return deliveryTypes.map(type => {
|
|
201
|
+
let tagProps: any = null
|
|
202
|
+
if (type === MALL_PRODUCT_DELIVERY_TYPE_DINE) {
|
|
203
|
+
tagProps = {
|
|
204
|
+
text: labels.delivery_type?.dine,
|
|
205
|
+
color: '#2db7f5',
|
|
206
|
+
bg: 'rgba(145, 213, 255, 0.16)'
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else if (type === MALL_PRODUCT_DELIVERY_TYPE_SELF) {
|
|
210
|
+
tagProps = {
|
|
211
|
+
text: labels.delivery_type?.self_pickup,
|
|
212
|
+
color: '#FF3D15',
|
|
213
|
+
bg: 'rgba(255,61,21,0.16)'
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else if (type === MALL_PRODUCT_DELIVERY_TYPE_EXPRESS || type === MALL_PRODUCT_DELIVERY_TYPE_SHOP) {
|
|
217
|
+
tagProps = {
|
|
218
|
+
text: labels.delivery_type?.delivery,
|
|
219
|
+
color: '#FF8901',
|
|
220
|
+
bg: 'rgba(255,137,1,0.16)'
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (!tagProps) return null
|
|
224
|
+
return (
|
|
225
|
+
<Tag
|
|
226
|
+
key={type}
|
|
227
|
+
text={tagProps.text}
|
|
228
|
+
style={{ color: tagProps.color, backgroundColor: tagProps.bg, borderColor: tagProps.color }}
|
|
229
|
+
className={styles['delivery-tag']}
|
|
230
|
+
/>
|
|
231
|
+
)
|
|
232
|
+
})
|
|
233
|
+
}, [deliveryTypes, labels])
|
|
234
|
+
|
|
235
|
+
const stockAndSaleElem = useMemo(() => {
|
|
236
|
+
if (!stockCount && !saleCount) return null
|
|
237
|
+
return (
|
|
238
|
+
<View className={styles['stock-and-sale']}>
|
|
239
|
+
{stockCount && (
|
|
240
|
+
<View className={styles['stock-box']}>
|
|
241
|
+
<Text className={styles['info-text']}>{labels.stock_label}</Text>
|
|
242
|
+
<Text className={styles['stock-text']}>{stockCount}</Text>
|
|
243
|
+
</View>
|
|
244
|
+
)}
|
|
245
|
+
{saleCount && (
|
|
246
|
+
<Text className={styles['info-text']}>
|
|
247
|
+
{labels.sale_label} {saleCount}
|
|
248
|
+
</Text>
|
|
249
|
+
)}
|
|
250
|
+
</View>
|
|
251
|
+
)
|
|
252
|
+
}, [stockCount, saleCount, labels])
|
|
253
|
+
|
|
254
|
+
return (
|
|
255
|
+
<View
|
|
256
|
+
className={formatClassNames(
|
|
257
|
+
styles['item-container'],
|
|
258
|
+
{
|
|
259
|
+
[styles['show-bottom-border']]: showBottomBorder,
|
|
260
|
+
},
|
|
261
|
+
className
|
|
262
|
+
)}
|
|
263
|
+
onClick={handleCardClick}
|
|
264
|
+
>
|
|
265
|
+
<View className={formatClassNames(
|
|
266
|
+
styles['card-info'],
|
|
267
|
+
{
|
|
268
|
+
[styles['show-separator']]: showSeparator
|
|
269
|
+
}
|
|
270
|
+
)}>
|
|
271
|
+
<View className={styles['card-main-body']}>
|
|
272
|
+
{showCheckbox && (
|
|
273
|
+
<View className={styles['checkbox-container']}>
|
|
274
|
+
<Checkbox
|
|
275
|
+
checked={checkboxChecked}
|
|
276
|
+
disabled={checkboxDisabled}
|
|
277
|
+
readOnly
|
|
278
|
+
/>
|
|
279
|
+
</View>
|
|
280
|
+
)}
|
|
281
|
+
<View className={styles['image-container']}>
|
|
282
|
+
<Image
|
|
283
|
+
src={image?.url}
|
|
284
|
+
className={styles['product-image']}
|
|
285
|
+
mode='aspectFill'
|
|
286
|
+
/>
|
|
287
|
+
{(showSoldOut || showOffline) && (
|
|
288
|
+
<View className={styles['status-overlay']}>
|
|
289
|
+
<Text className={styles['status-text']}>
|
|
290
|
+
{showSoldOut ? labels.sold_out : labels.offline}
|
|
291
|
+
</Text>
|
|
292
|
+
</View>
|
|
293
|
+
)}
|
|
294
|
+
</View>
|
|
295
|
+
<View className={styles['content-container']}>
|
|
296
|
+
<View className={styles['content-body']}>
|
|
297
|
+
<View className={styles['title-row']} style={{ marginRight: showDelete ? '30PX' : '0' }}>
|
|
298
|
+
{productTypeTag}
|
|
299
|
+
<Text className={styles['title']} style={{ WebkitLineClamp: titleMaxLines }}>{title}</Text>
|
|
300
|
+
</View>
|
|
301
|
+
{(showMultipleSpec || stockCount || saleCount || barcode) && (
|
|
302
|
+
<ScrollView scrollX className={styles['second-row']} showScrollbar={false}>
|
|
303
|
+
<View className={styles['second-row-inner']}>
|
|
304
|
+
{showMultipleSpec && <Text className={styles['primary-text']}>{labels.multiple_spec}</Text>}
|
|
305
|
+
{showMultipleSpec && stockAndSaleElem && <View className={styles['info-line']} />}
|
|
306
|
+
{stockAndSaleElem}
|
|
307
|
+
{((showMultipleSpec || stockAndSaleElem) && barcode) && <View className={styles['info-line']} />}
|
|
308
|
+
{barcode && <Text className={styles['info-text']}>{labels.barcode_label} {barcode}</Text>}
|
|
309
|
+
</View>
|
|
310
|
+
</ScrollView>
|
|
311
|
+
)}
|
|
312
|
+
{customTags}
|
|
313
|
+
{(activityType || deliveryTags) && (
|
|
314
|
+
<View className={styles['tag-row']}>
|
|
315
|
+
{activityType && labels.activity_type && (
|
|
316
|
+
<View className={styles['activity-tag']}>
|
|
317
|
+
{activityType === PROMOTION_ACTIVITY_TYPE_PRESENT && <View className={styles['activity-tag-badge']}><Text className={styles['activity-tag-badge-text']}>{labels.present_badge}</Text></View>}
|
|
318
|
+
<View className={styles['activity-tag-content']}>
|
|
319
|
+
<Text className={styles['activity-tag-text']}>
|
|
320
|
+
{activityType === PROMOTION_ACTIVITY_TYPE_FLASH && labels.activity_type.flash}
|
|
321
|
+
{activityType === PROMOTION_ACTIVITY_TYPE_BRAND && labels.activity_type.brand}
|
|
322
|
+
{activityType === PROMOTION_ACTIVITY_TYPE_HOT && labels.activity_type.hot}
|
|
323
|
+
{activityType === PROMOTION_ACTIVITY_TYPE_PRESENT && labels.activity_type.present}
|
|
324
|
+
</Text>
|
|
325
|
+
</View>
|
|
326
|
+
</View>
|
|
327
|
+
)}
|
|
328
|
+
{deliveryTags}
|
|
329
|
+
</View>
|
|
330
|
+
)}
|
|
331
|
+
{
|
|
332
|
+
spec
|
|
333
|
+
? (
|
|
334
|
+
<Text
|
|
335
|
+
className={styles['spec-text']}
|
|
336
|
+
style={{ WebkitLineClamp: specMaxLines }}
|
|
337
|
+
>
|
|
338
|
+
{labels.spec_label}:{spec}
|
|
339
|
+
</Text>
|
|
340
|
+
)
|
|
341
|
+
: undefined
|
|
342
|
+
}
|
|
343
|
+
{
|
|
344
|
+
customization
|
|
345
|
+
? (
|
|
346
|
+
<Text
|
|
347
|
+
className={styles['customization-text']}
|
|
348
|
+
style={{ WebkitLineClamp: customizationMaxLines }}
|
|
349
|
+
>
|
|
350
|
+
{customization}
|
|
351
|
+
</Text>
|
|
352
|
+
)
|
|
353
|
+
: undefined
|
|
354
|
+
}
|
|
355
|
+
{
|
|
356
|
+
combo
|
|
357
|
+
? (
|
|
358
|
+
<Text
|
|
359
|
+
className={styles['customization-text']}
|
|
360
|
+
style={{ WebkitLineClamp: comboMaxLines }}
|
|
361
|
+
>
|
|
362
|
+
{combo}
|
|
363
|
+
</Text>
|
|
364
|
+
)
|
|
365
|
+
: undefined
|
|
366
|
+
}
|
|
367
|
+
</View>
|
|
368
|
+
<View className={styles['content-bottom']}>
|
|
369
|
+
<View className={styles['price-container']}>
|
|
370
|
+
<View className={styles['price-row']}>
|
|
371
|
+
<Text className={styles['price-symbol']}>
|
|
372
|
+
¥
|
|
373
|
+
</Text>
|
|
374
|
+
<Text className={styles['price-value']}>
|
|
375
|
+
{salePrice}
|
|
376
|
+
</Text>
|
|
377
|
+
</View>
|
|
378
|
+
{
|
|
379
|
+
originalPrice
|
|
380
|
+
? (
|
|
381
|
+
<Text className={styles['original-price']}>
|
|
382
|
+
¥{originalPrice}
|
|
383
|
+
</Text>
|
|
384
|
+
)
|
|
385
|
+
: undefined
|
|
386
|
+
}
|
|
387
|
+
</View>
|
|
388
|
+
<View
|
|
389
|
+
className={styles['action-area']}
|
|
390
|
+
>
|
|
391
|
+
{
|
|
392
|
+
buyCount
|
|
393
|
+
? (
|
|
394
|
+
<Text className={styles['buy-count-value']}>
|
|
395
|
+
x{buyCount}
|
|
396
|
+
</Text>
|
|
397
|
+
)
|
|
398
|
+
: action
|
|
399
|
+
}
|
|
400
|
+
</View>
|
|
401
|
+
</View>
|
|
402
|
+
</View>
|
|
403
|
+
</View>
|
|
404
|
+
{
|
|
405
|
+
children
|
|
406
|
+
? (
|
|
407
|
+
<View
|
|
408
|
+
className={styles['card-footer']}
|
|
409
|
+
onClick={e => e.stopPropagation()}
|
|
410
|
+
>
|
|
411
|
+
{children}
|
|
412
|
+
</View>
|
|
413
|
+
)
|
|
414
|
+
: undefined
|
|
415
|
+
}
|
|
416
|
+
</View>
|
|
417
|
+
{
|
|
418
|
+
showDelete
|
|
419
|
+
? (
|
|
420
|
+
<View
|
|
421
|
+
className={styles['delete-container']}
|
|
422
|
+
onClick={(e: ITouchEvent) => {
|
|
423
|
+
e.stopPropagation()
|
|
424
|
+
onDelete?.()
|
|
425
|
+
}}
|
|
426
|
+
>
|
|
427
|
+
<Icon
|
|
428
|
+
name='trash'
|
|
429
|
+
size={13}
|
|
430
|
+
className={styles['delete-icon']}
|
|
431
|
+
/>
|
|
432
|
+
</View>
|
|
433
|
+
)
|
|
434
|
+
: undefined
|
|
435
|
+
}
|
|
436
|
+
</View>
|
|
437
|
+
)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export default React.memo(ProductItem)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { IProductCardLabels } from './ProductItem'
|
|
2
|
+
|
|
3
|
+
// 初始默认文案
|
|
4
|
+
let globalLabels: IProductCardLabels = {
|
|
5
|
+
product_type: {
|
|
6
|
+
real: '实物',
|
|
7
|
+
virtual: '虚拟',
|
|
8
|
+
service: '服务'
|
|
9
|
+
},
|
|
10
|
+
delivery_type: {
|
|
11
|
+
dine: '堂食',
|
|
12
|
+
self_pickup: '到店自取',
|
|
13
|
+
delivery: '送货上门'
|
|
14
|
+
},
|
|
15
|
+
activity_type: {
|
|
16
|
+
flash: '秒杀活动',
|
|
17
|
+
brand: '品牌活动',
|
|
18
|
+
hot: '热点活动',
|
|
19
|
+
present: '买赠活动'
|
|
20
|
+
},
|
|
21
|
+
present_badge: '赠',
|
|
22
|
+
stock_label: '库存',
|
|
23
|
+
sale_label: '销量',
|
|
24
|
+
multiple_spec: '多规格',
|
|
25
|
+
barcode_label: '条码',
|
|
26
|
+
spec_label: '规格',
|
|
27
|
+
sold_out: '售罄',
|
|
28
|
+
offline: '已下架'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const setProductItemConfig = (labels: IProductCardLabels) => {
|
|
32
|
+
globalLabels = { ...globalLabels, ...labels }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const getProductItemConfig = () => globalLabels
|
|
@@ -1,453 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import ProductItemMain from './ProductItem'
|
|
2
|
+
import { setProductItemConfig } from './config'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
export type { IProductCardLabels, IProductCardProps } from './ProductItem'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
import Icon from '../../components/Icon'
|
|
8
|
-
import Checkbox from '../../components/Checkbox'
|
|
6
|
+
export { setProductItemConfig }
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
MALL_PRODUCT_TYPE_REAL,
|
|
14
|
-
MALL_PRODUCT_TYPE_VIRTUAL,
|
|
15
|
-
MALL_PRODUCT_TYPE_SERVICE,
|
|
16
|
-
MALL_PRODUCT_DELIVERY_TYPE_EXPRESS,
|
|
17
|
-
MALL_PRODUCT_DELIVERY_TYPE_SELF,
|
|
18
|
-
MALL_PRODUCT_DELIVERY_TYPE_SHOP,
|
|
19
|
-
MALL_PRODUCT_DELIVERY_TYPE_DINE,
|
|
20
|
-
PROMOTION_ACTIVITY_TYPE_FLASH,
|
|
21
|
-
PROMOTION_ACTIVITY_TYPE_BRAND,
|
|
22
|
-
PROMOTION_ACTIVITY_TYPE_HOT,
|
|
23
|
-
PROMOTION_ACTIVITY_TYPE_PRESENT,
|
|
24
|
-
} from '../../constant/mall'
|
|
25
|
-
|
|
26
|
-
export interface IProductCardLabels {
|
|
27
|
-
product_type?: { real: string; virtual: string; service: string }
|
|
28
|
-
delivery_type?: { dine: string; self_pickup: string; delivery: string }
|
|
29
|
-
activity_type?: { flash: string; brand: string; hot: string; present: string }
|
|
30
|
-
present_badge?: string
|
|
31
|
-
stock_label?: string
|
|
32
|
-
sale_label?: string
|
|
33
|
-
multiple_spec?: string
|
|
34
|
-
barcode_label?: string
|
|
35
|
-
spec_label?: string
|
|
36
|
-
sold_out?: string
|
|
37
|
-
offline?: string
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** 商品卡片组件属性 */
|
|
41
|
-
export interface IProductCardProps {
|
|
42
|
-
/** 外部样式类 */
|
|
43
|
-
className?: string
|
|
44
|
-
/** 商品图片对象 */
|
|
45
|
-
image: { url: string }
|
|
46
|
-
/** 是否显示售罄标记 */
|
|
47
|
-
showSoldOut?: boolean
|
|
48
|
-
/** 是否显示已下架标记 */
|
|
49
|
-
showOffline?: boolean
|
|
50
|
-
/** 商品标题 */
|
|
51
|
-
title: string
|
|
52
|
-
/** 标题最大显示行数 (默认1) */
|
|
53
|
-
titleMaxLines?: number
|
|
54
|
-
/** 商品类型:实物/虚拟/服务 */
|
|
55
|
-
productType?: number
|
|
56
|
-
/** 是否显示“多规格”标签 */
|
|
57
|
-
showMultipleSpec?: boolean
|
|
58
|
-
/** 库存数量文案 */
|
|
59
|
-
stockCount?: string | number
|
|
60
|
-
/** 销量文案 */
|
|
61
|
-
saleCount?: string | number
|
|
62
|
-
/** 商品条码 */
|
|
63
|
-
barcode?: string
|
|
64
|
-
/** 规格描述文案 (如: 红色, 大号) */
|
|
65
|
-
spec?: string
|
|
66
|
-
/** 规格描述最大显示行数 (默认1) */
|
|
67
|
-
specMaxLines?: number
|
|
68
|
-
/** 活动类型:秒杀/品牌/热点/满赠 */
|
|
69
|
-
activityType?: number
|
|
70
|
-
/** 配送方式集合:堂食/自提/外送 */
|
|
71
|
-
deliveryTypes?: number[]
|
|
72
|
-
/** 做法/定制化信息描述 */
|
|
73
|
-
customization?: string
|
|
74
|
-
/** 做法描述最大显示行数 (默认3) */
|
|
75
|
-
customizationMaxLines?: number
|
|
76
|
-
/** 套餐信息描述 */
|
|
77
|
-
combo? : string
|
|
78
|
-
/** 套餐描述最大显示行数 (默认3) */
|
|
79
|
-
comboMaxLines?: number
|
|
80
|
-
/** 售价 */
|
|
81
|
-
salePrice: string | number
|
|
82
|
-
/** 原价 (划线价) */
|
|
83
|
-
originalPrice?: string | number
|
|
84
|
-
/** 已购数量 (显示为 xN) */
|
|
85
|
-
buyCount?: number
|
|
86
|
-
/** 是否显示左侧勾选框 */
|
|
87
|
-
showCheckbox?: boolean
|
|
88
|
-
/** 勾选框是否选中 */
|
|
89
|
-
checkboxChecked?: boolean
|
|
90
|
-
/** 勾选框是否禁用 */
|
|
91
|
-
checkboxDisabled?: boolean
|
|
92
|
-
/** 点击勾选框或卡片触发 (当 checkbox 可用时) */
|
|
93
|
-
onCheckboxClick?: () => void
|
|
94
|
-
/** 是否显示右上角删除按钮 */
|
|
95
|
-
showDelete?: boolean
|
|
96
|
-
/** 点击删除按钮回调 */
|
|
97
|
-
onDelete?: () => void
|
|
98
|
-
/** 右下角自定义操作区域 (与 buyCount 互斥) */
|
|
99
|
-
action?: React.ReactNode
|
|
100
|
-
/** 国际化标签注入 */
|
|
101
|
-
labels?: IProductCardLabels
|
|
102
|
-
/** 是否显示底部分边框 */
|
|
103
|
-
showBottomBorder?: boolean
|
|
104
|
-
/** 是否显示底部分割线 */
|
|
105
|
-
showSeparator?: boolean
|
|
106
|
-
// 卡片点击事件
|
|
107
|
-
onClick?: () => void
|
|
108
|
-
children?: React.ReactNode
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const DEFAULT_LABELS: IProductCardLabels = {
|
|
112
|
-
product_type: { real: '实物', virtual: '虚拟', service: '服务' },
|
|
113
|
-
delivery_type: { dine: '堂食', self_pickup: '到店自取', delivery: '送货上门' },
|
|
114
|
-
activity_type: { flash: '秒杀活动', brand: '品牌活动', hot: '热点活动', present: '买赠活动' },
|
|
115
|
-
present_badge: '赠',
|
|
116
|
-
stock_label: '库存',
|
|
117
|
-
sale_label: '销量',
|
|
118
|
-
multiple_spec: '多规格',
|
|
119
|
-
barcode_label: '条码',
|
|
120
|
-
spec_label: '规格',
|
|
121
|
-
sold_out: '售罄',
|
|
122
|
-
offline: '已下架'
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const ProductItem: React.FC<IProductCardProps> = (props) => {
|
|
126
|
-
const {
|
|
127
|
-
image,
|
|
128
|
-
title,
|
|
129
|
-
titleMaxLines = 1,
|
|
130
|
-
productType,
|
|
131
|
-
showMultipleSpec,
|
|
132
|
-
stockCount,
|
|
133
|
-
saleCount,
|
|
134
|
-
barcode,
|
|
135
|
-
spec,
|
|
136
|
-
specMaxLines = 1,
|
|
137
|
-
activityType,
|
|
138
|
-
deliveryTypes = [],
|
|
139
|
-
customization,
|
|
140
|
-
customizationMaxLines = 3,
|
|
141
|
-
combo,
|
|
142
|
-
comboMaxLines = 3,
|
|
143
|
-
salePrice,
|
|
144
|
-
originalPrice,
|
|
145
|
-
buyCount,
|
|
146
|
-
showSoldOut = false,
|
|
147
|
-
showOffline = false,
|
|
148
|
-
showCheckbox = false,
|
|
149
|
-
checkboxChecked = false,
|
|
150
|
-
checkboxDisabled = false,
|
|
151
|
-
onCheckboxClick,
|
|
152
|
-
showDelete,
|
|
153
|
-
onDelete,
|
|
154
|
-
action,
|
|
155
|
-
className,
|
|
156
|
-
showBottomBorder = false,
|
|
157
|
-
showSeparator = false,
|
|
158
|
-
labels: customLabels,
|
|
159
|
-
onClick,
|
|
160
|
-
children
|
|
161
|
-
} = props
|
|
162
|
-
|
|
163
|
-
const handleCardClick = (e: ITouchEvent) => {
|
|
164
|
-
if (showCheckbox) {
|
|
165
|
-
if (!checkboxDisabled) {
|
|
166
|
-
onCheckboxClick?.()
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
onClick?.()
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const labels = useMemo(() => ({
|
|
175
|
-
...DEFAULT_LABELS,
|
|
176
|
-
...customLabels,
|
|
177
|
-
product_type: { ...DEFAULT_LABELS.product_type, ...customLabels?.product_type },
|
|
178
|
-
delivery_type: { ...DEFAULT_LABELS.delivery_type, ...customLabels?.delivery_type },
|
|
179
|
-
activity_type: { ...DEFAULT_LABELS.activity_type, ...customLabels?.activity_type }
|
|
180
|
-
}), [customLabels])
|
|
181
|
-
|
|
182
|
-
const productTypeTag = useMemo(() => {
|
|
183
|
-
if (productType === undefined) return null
|
|
184
|
-
const colorMap: Record<number, { color: string; text: string | undefined }> = {
|
|
185
|
-
[MALL_PRODUCT_TYPE_REAL]: {
|
|
186
|
-
color: 'var(--primary)',
|
|
187
|
-
text: labels.product_type?.real
|
|
188
|
-
},
|
|
189
|
-
[MALL_PRODUCT_TYPE_VIRTUAL]: {
|
|
190
|
-
color: '#E4B700',
|
|
191
|
-
text: labels.product_type?.virtual
|
|
192
|
-
},
|
|
193
|
-
[MALL_PRODUCT_TYPE_SERVICE]: {
|
|
194
|
-
color: '#03BE02',
|
|
195
|
-
text: labels.product_type?.service
|
|
196
|
-
},
|
|
197
|
-
}
|
|
198
|
-
const item = colorMap[productType]
|
|
199
|
-
if (!item) return null
|
|
200
|
-
return (
|
|
201
|
-
<View className={styles['product-tag-container']}>
|
|
202
|
-
<Tag
|
|
203
|
-
type='light-warning'
|
|
204
|
-
text={item.text}
|
|
205
|
-
className={styles['product-tag']}
|
|
206
|
-
style={{ backgroundColor: item.color, color: '#fff' }}
|
|
207
|
-
/>
|
|
208
|
-
</View>
|
|
209
|
-
)
|
|
210
|
-
}, [productType, labels])
|
|
211
|
-
|
|
212
|
-
const deliveryTags = useMemo(() => {
|
|
213
|
-
if (isEmpty(deliveryTypes)) return null
|
|
214
|
-
return deliveryTypes.map(type => {
|
|
215
|
-
let tagProps: any = null
|
|
216
|
-
if (type === MALL_PRODUCT_DELIVERY_TYPE_DINE) {
|
|
217
|
-
tagProps = {
|
|
218
|
-
text: labels.delivery_type?.dine,
|
|
219
|
-
color: '#2db7f5',
|
|
220
|
-
bg: 'rgba(145, 213, 255, 0.16)'
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
else if (type === MALL_PRODUCT_DELIVERY_TYPE_SELF) {
|
|
224
|
-
tagProps = {
|
|
225
|
-
text: labels.delivery_type?.self_pickup,
|
|
226
|
-
color: '#FF3D15',
|
|
227
|
-
bg: 'rgba(255,61,21,0.16)'
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
else if (type === MALL_PRODUCT_DELIVERY_TYPE_EXPRESS || type === MALL_PRODUCT_DELIVERY_TYPE_SHOP) {
|
|
231
|
-
tagProps = {
|
|
232
|
-
text: labels.delivery_type?.delivery,
|
|
233
|
-
color: '#FF8901',
|
|
234
|
-
bg: 'rgba(255,137,1,0.16)'
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
if (!tagProps) return null
|
|
238
|
-
return (
|
|
239
|
-
<Tag
|
|
240
|
-
key={type}
|
|
241
|
-
text={tagProps.text}
|
|
242
|
-
style={{ color: tagProps.color, backgroundColor: tagProps.bg, borderColor: tagProps.color }}
|
|
243
|
-
className={styles['delivery-tag']}
|
|
244
|
-
/>
|
|
245
|
-
)
|
|
246
|
-
})
|
|
247
|
-
}, [deliveryTypes, labels])
|
|
248
|
-
|
|
249
|
-
const stockAndSaleElem = useMemo(() => {
|
|
250
|
-
if (!stockCount && !saleCount) return null
|
|
251
|
-
return (
|
|
252
|
-
<View className={styles['stock-and-sale']}>
|
|
253
|
-
{stockCount && (
|
|
254
|
-
<View className={styles['stock-box']}>
|
|
255
|
-
<Text className={styles['info-text']}>{labels.stock_label}</Text>
|
|
256
|
-
<Text className={styles['stock-text']}>{stockCount}</Text>
|
|
257
|
-
</View>
|
|
258
|
-
)}
|
|
259
|
-
{saleCount && (
|
|
260
|
-
<Text className={styles['info-text']}>
|
|
261
|
-
{labels.sale_label} {saleCount}
|
|
262
|
-
</Text>
|
|
263
|
-
)}
|
|
264
|
-
</View>
|
|
265
|
-
)
|
|
266
|
-
}, [stockCount, saleCount, labels])
|
|
267
|
-
|
|
268
|
-
return (
|
|
269
|
-
<View
|
|
270
|
-
className={formatClassNames(
|
|
271
|
-
styles['item-container'],
|
|
272
|
-
{
|
|
273
|
-
[styles['show-bottom-border']]: showBottomBorder,
|
|
274
|
-
},
|
|
275
|
-
className
|
|
276
|
-
)}
|
|
277
|
-
onClick={handleCardClick}
|
|
278
|
-
>
|
|
279
|
-
<View className={formatClassNames(
|
|
280
|
-
styles['card-info'],
|
|
281
|
-
{
|
|
282
|
-
[styles['show-separator']]: showSeparator
|
|
283
|
-
}
|
|
284
|
-
)}>
|
|
285
|
-
<View className={styles['card-main-body']}>
|
|
286
|
-
{showCheckbox && (
|
|
287
|
-
<View className={styles['checkbox-container']}>
|
|
288
|
-
<Checkbox
|
|
289
|
-
checked={checkboxChecked}
|
|
290
|
-
disabled={checkboxDisabled}
|
|
291
|
-
readOnly
|
|
292
|
-
/>
|
|
293
|
-
</View>
|
|
294
|
-
)}
|
|
295
|
-
<View className={styles['image-container']}>
|
|
296
|
-
<Image
|
|
297
|
-
src={image?.url}
|
|
298
|
-
className={styles['product-image']}
|
|
299
|
-
mode='aspectFill'
|
|
300
|
-
/>
|
|
301
|
-
{(showSoldOut || showOffline) && (
|
|
302
|
-
<View className={styles['status-overlay']}>
|
|
303
|
-
<Text className={styles['status-text']}>
|
|
304
|
-
{showSoldOut ? labels.sold_out : labels.offline}
|
|
305
|
-
</Text>
|
|
306
|
-
</View>
|
|
307
|
-
)}
|
|
308
|
-
</View>
|
|
309
|
-
<View className={styles['content-container']}>
|
|
310
|
-
<View className={styles['content-body']}>
|
|
311
|
-
<View className={styles['title-row']} style={{ marginRight: showDelete ? '30PX' : '0' }}>
|
|
312
|
-
{productTypeTag}
|
|
313
|
-
<Text className={styles['title']} style={{ WebkitLineClamp: titleMaxLines }}>{title}</Text>
|
|
314
|
-
</View>
|
|
315
|
-
{(showMultipleSpec || stockCount || saleCount || barcode) && (
|
|
316
|
-
<ScrollView scrollX className={styles['second-row']} showScrollbar={false}>
|
|
317
|
-
<View className={styles['second-row-inner']}>
|
|
318
|
-
{showMultipleSpec && <Text className={styles['primary-text']}>{labels.multiple_spec}</Text>}
|
|
319
|
-
{showMultipleSpec && stockAndSaleElem && <View className={styles['info-line']} />}
|
|
320
|
-
{stockAndSaleElem}
|
|
321
|
-
{((showMultipleSpec || stockAndSaleElem) && barcode) && <View className={styles['info-line']} />}
|
|
322
|
-
{barcode && <Text className={styles['info-text']}>{labels.barcode_label} {barcode}</Text>}
|
|
323
|
-
</View>
|
|
324
|
-
</ScrollView>
|
|
325
|
-
)}
|
|
326
|
-
{(activityType || deliveryTags) && (
|
|
327
|
-
<View className={styles['tag-row']}>
|
|
328
|
-
{activityType && labels.activity_type && (
|
|
329
|
-
<View className={styles['activity-tag']}>
|
|
330
|
-
{activityType === PROMOTION_ACTIVITY_TYPE_PRESENT && <View className={styles['activity-tag-badge']}><Text className={styles['activity-tag-badge-text']}>{labels.present_badge}</Text></View>}
|
|
331
|
-
<View className={styles['activity-tag-content']}>
|
|
332
|
-
<Text className={styles['activity-tag-text']}>
|
|
333
|
-
{activityType === PROMOTION_ACTIVITY_TYPE_FLASH && labels.activity_type.flash}
|
|
334
|
-
{activityType === PROMOTION_ACTIVITY_TYPE_BRAND && labels.activity_type.brand}
|
|
335
|
-
{activityType === PROMOTION_ACTIVITY_TYPE_HOT && labels.activity_type.hot}
|
|
336
|
-
{activityType === PROMOTION_ACTIVITY_TYPE_PRESENT && labels.activity_type.present}
|
|
337
|
-
</Text>
|
|
338
|
-
</View>
|
|
339
|
-
</View>
|
|
340
|
-
)}
|
|
341
|
-
{deliveryTags}
|
|
342
|
-
</View>
|
|
343
|
-
)}
|
|
344
|
-
{
|
|
345
|
-
spec
|
|
346
|
-
? (
|
|
347
|
-
<Text
|
|
348
|
-
className={styles['spec-text']}
|
|
349
|
-
style={{ WebkitLineClamp: specMaxLines }}
|
|
350
|
-
>
|
|
351
|
-
{labels.spec_label}:{spec}
|
|
352
|
-
</Text>
|
|
353
|
-
)
|
|
354
|
-
: undefined
|
|
355
|
-
}
|
|
356
|
-
{
|
|
357
|
-
customization
|
|
358
|
-
? (
|
|
359
|
-
<Text
|
|
360
|
-
className={styles['customization-text']}
|
|
361
|
-
style={{ WebkitLineClamp: customizationMaxLines }}
|
|
362
|
-
>
|
|
363
|
-
{customization}
|
|
364
|
-
</Text>
|
|
365
|
-
)
|
|
366
|
-
: undefined
|
|
367
|
-
}
|
|
368
|
-
{
|
|
369
|
-
combo
|
|
370
|
-
? (
|
|
371
|
-
<Text
|
|
372
|
-
className={styles['customization-text']}
|
|
373
|
-
style={{ WebkitLineClamp: comboMaxLines }}
|
|
374
|
-
>
|
|
375
|
-
{combo}
|
|
376
|
-
</Text>
|
|
377
|
-
)
|
|
378
|
-
: undefined
|
|
379
|
-
}
|
|
380
|
-
</View>
|
|
381
|
-
<View className={styles['content-bottom']}>
|
|
382
|
-
<View className={styles['price-container']}>
|
|
383
|
-
<View className={styles['price-row']}>
|
|
384
|
-
<Text className={styles['price-symbol']}>
|
|
385
|
-
¥
|
|
386
|
-
</Text>
|
|
387
|
-
<Text className={styles['price-value']}>
|
|
388
|
-
{salePrice}
|
|
389
|
-
</Text>
|
|
390
|
-
</View>
|
|
391
|
-
{
|
|
392
|
-
originalPrice
|
|
393
|
-
? (
|
|
394
|
-
<Text className={styles['original-price']}>
|
|
395
|
-
¥{originalPrice}
|
|
396
|
-
</Text>
|
|
397
|
-
)
|
|
398
|
-
: undefined
|
|
399
|
-
}
|
|
400
|
-
</View>
|
|
401
|
-
<View
|
|
402
|
-
className={styles['action-area']}
|
|
403
|
-
>
|
|
404
|
-
{
|
|
405
|
-
buyCount
|
|
406
|
-
? (
|
|
407
|
-
<Text className={styles['buy-count-value']}>
|
|
408
|
-
x{buyCount}
|
|
409
|
-
</Text>
|
|
410
|
-
)
|
|
411
|
-
: action
|
|
412
|
-
}
|
|
413
|
-
</View>
|
|
414
|
-
</View>
|
|
415
|
-
</View>
|
|
416
|
-
</View>
|
|
417
|
-
{
|
|
418
|
-
children
|
|
419
|
-
? (
|
|
420
|
-
<View
|
|
421
|
-
className={styles['card-footer']}
|
|
422
|
-
onClick={e => e.stopPropagation()}
|
|
423
|
-
>
|
|
424
|
-
{children}
|
|
425
|
-
</View>
|
|
426
|
-
)
|
|
427
|
-
: undefined
|
|
428
|
-
}
|
|
429
|
-
</View>
|
|
430
|
-
{
|
|
431
|
-
showDelete
|
|
432
|
-
? (
|
|
433
|
-
<View
|
|
434
|
-
className={styles['delete-container']}
|
|
435
|
-
onClick={(e: ITouchEvent) => {
|
|
436
|
-
e.stopPropagation()
|
|
437
|
-
onDelete?.()
|
|
438
|
-
}}
|
|
439
|
-
>
|
|
440
|
-
<Icon
|
|
441
|
-
name='trash'
|
|
442
|
-
size={13}
|
|
443
|
-
className={styles['delete-icon']}
|
|
444
|
-
/>
|
|
445
|
-
</View>
|
|
446
|
-
)
|
|
447
|
-
: undefined
|
|
448
|
-
}
|
|
449
|
-
</View>
|
|
450
|
-
)
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
export default React.memo(ProductItem)
|
|
8
|
+
export default ProductItemMain
|