FirstLast.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import { Images } from '@/constants/images';
  2. import { Image, ImageBackground } from 'expo-image';
  3. import React from 'react';
  4. import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
  5. interface FirstLastProps {
  6. data: any;
  7. box: any;
  8. onPrevBox?: () => void;
  9. onNextBox?: () => void;
  10. onChangeBox?: () => void;
  11. onProductClick?: (product: any) => void;
  12. }
  13. export default function FirstLast({ data, box, onPrevBox, onNextBox, onChangeBox, onProductClick }: FirstLastProps) {
  14. // Filter for special prizes: FIRST, LAST, LASTALL
  15. const prizeList = React.useMemo(() => {
  16. if (!box || !box.prizeList) return [];
  17. return box.prizeList.filter((item: any) =>
  18. ['FIRST', 'LAST', 'LASTALL'].includes(item.level)
  19. );
  20. }, [box]);
  21. if (!box) return null;
  22. return (
  23. <View style={styles.container}>
  24. <ImageBackground
  25. source={{ uri: Images.box.detail.firstBoxBg }}
  26. style={styles.bg}
  27. resizeMode="stretch"
  28. >
  29. {/* Title / Remain Info */}
  30. <View style={styles.header}>
  31. <View style={styles.remainInfo}>
  32. <Text style={styles.remainLabel}>当前盒子剩余:</Text>
  33. <Text style={styles.remainValue}>
  34. <Text style={styles.remainNum}>{box.leftQuantity}</Text>
  35. /{box.quantity}发
  36. </Text>
  37. </View>
  38. <Image
  39. source={{ uri: Images.box.detail.playMethod }}
  40. style={styles.ruleBtn}
  41. contentFit="contain"
  42. />
  43. </View>
  44. {/* Prize List (First/Last) */}
  45. <View style={styles.prizeContainer}>
  46. {prizeList.map((item: any, index: number) => (
  47. <TouchableOpacity
  48. key={index}
  49. style={styles.prizeItem}
  50. onPress={() => onProductClick && onProductClick(item.spu)}
  51. >
  52. <ImageBackground
  53. source={{ uri: Images.box.detail.firstItemBg }}
  54. style={styles.prizeItemBg}
  55. resizeMode="contain"
  56. >
  57. <Image source={{ uri: item.cover }} style={styles.prizeImg} contentFit="contain" />
  58. <View style={styles.prizeLabelContainer}>
  59. {item.level === 'FIRST' && (
  60. <Text style={[styles.prizeLabel, { backgroundColor: 'rgba(91, 189, 208, .8)' }]}>抢先赏</Text>
  61. )}
  62. {item.level === 'LAST' && (
  63. <Text style={[styles.prizeLabel, { backgroundColor: 'rgba(246, 44, 113, .8)' }]}>最终赏</Text>
  64. )}
  65. {item.level === 'LASTALL' && (
  66. <Text style={[styles.prizeLabel, { backgroundColor: 'rgba(44, 246, 74, .8)' }]}>全局赏</Text>
  67. )}
  68. </View>
  69. {/* User Avatar if someone won it? Legacy logic: v-if="item.nickname" */}
  70. {item.nickname && (
  71. <View style={styles.winnerBox}>
  72. <Image source={{ uri: item.avatar }} style={styles.winnerAvatar} />
  73. <Text style={styles.winnerName} numberOfLines={1}>{item.nickname}</Text>
  74. </View>
  75. )}
  76. </ImageBackground>
  77. </TouchableOpacity>
  78. ))}
  79. </View>
  80. {/* Controls */}
  81. <ImageBackground
  82. source={{ uri: Images.box.detail.funBoxBg }}
  83. style={styles.controlsBg}
  84. resizeMode="stretch"
  85. >
  86. <TouchableOpacity style={styles.controlBtn} onPress={onPrevBox}>
  87. <Text style={styles.controlText}>上一盒</Text>
  88. </TouchableOpacity>
  89. <TouchableOpacity style={styles.changeBtn} onPress={onChangeBox}>
  90. <Text style={[styles.controlText, { color: '#000' }]}>
  91. 换盒(<Text style={{ fontWeight: 'bold' }}>{box.number}</Text>/{box.lastNumber})
  92. </Text>
  93. </TouchableOpacity>
  94. <TouchableOpacity style={styles.controlBtn} onPress={onNextBox}>
  95. <Text style={styles.controlText}>下一盒</Text>
  96. </TouchableOpacity>
  97. </ImageBackground>
  98. </ImageBackground>
  99. </View>
  100. );
  101. }
  102. const styles = StyleSheet.create({
  103. container: {
  104. paddingHorizontal: 10,
  105. marginBottom: 10,
  106. },
  107. bg: {
  108. width: '100%',
  109. height: 193, // 386rpx / 2
  110. alignItems: 'center',
  111. },
  112. header: {
  113. width: '100%',
  114. flexDirection: 'row',
  115. justifyContent: 'space-between',
  116. paddingHorizontal: 20,
  117. paddingTop: 20,
  118. },
  119. remainInfo: {
  120. flexDirection: 'row',
  121. alignItems: 'center',
  122. },
  123. remainLabel: { color: '#fff', fontSize: 12 },
  124. remainValue: { color: '#fff', fontSize: 12 },
  125. remainNum: { fontSize: 16, fontWeight: 'bold' },
  126. ruleBtn: { width: 41, height: 17 },
  127. prizeContainer: {
  128. flexDirection: 'row',
  129. justifyContent: 'space-around',
  130. width: '80%',
  131. marginTop: 10,
  132. height: 70, // Adjust based on item size
  133. },
  134. prizeItem: {
  135. width: 63, // 126rpx / 2
  136. height: 65,
  137. },
  138. prizeItemBg: {
  139. flex: 1,
  140. alignItems: 'center',
  141. justifyContent: 'center',
  142. },
  143. prizeImg: {
  144. width: 60,
  145. height: 60,
  146. },
  147. prizeLabelContainer: {
  148. position: 'absolute',
  149. bottom: -8,
  150. width: '100%',
  151. alignItems: 'center',
  152. },
  153. prizeLabel: {
  154. fontSize: 10,
  155. color: '#fff',
  156. paddingHorizontal: 4,
  157. paddingVertical: 1,
  158. borderRadius: 4,
  159. overflow: 'hidden',
  160. },
  161. winnerBox: {
  162. position: 'absolute',
  163. top: 0,
  164. left: 0,
  165. right: 0,
  166. bottom: 0,
  167. justifyContent: 'center',
  168. alignItems: 'center',
  169. backgroundColor: 'rgba(0,0,0,0.6)',
  170. borderRadius: 30, // Circleish
  171. },
  172. winnerAvatar: { width: 24, height: 24, borderRadius: 12, borderWidth: 1, borderColor: '#FFE996' },
  173. winnerName: { color: '#FEC433', fontSize: 8, marginTop: 2, maxWidth: 50 },
  174. controlsBg: {
  175. width: 270, // 540rpx / 2
  176. height: 38, // 76rpx / 2
  177. flexDirection: 'row',
  178. alignItems: 'center',
  179. justifyContent: 'center',
  180. marginTop: 25,
  181. },
  182. controlBtn: {
  183. width: 90,
  184. height: '100%',
  185. justifyContent: 'center',
  186. alignItems: 'center',
  187. },
  188. changeBtn: {
  189. width: 110,
  190. height: '100%',
  191. justifyContent: 'center',
  192. alignItems: 'center',
  193. },
  194. controlText: {
  195. color: '#fff',
  196. fontSize: 14,
  197. fontWeight: '500',
  198. }
  199. });