ipanel-rnapp-ajb-base 1.0.0

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 (155) hide show
  1. package/app/.local_dev/DemoPage.js +46 -0
  2. package/app/.local_dev/env.js +1 -0
  3. package/app/.local_dev/polyfill.js +83 -0
  4. package/app/App.js +485 -0
  5. package/app/api/homedApi.js +42 -0
  6. package/app/api/index.js +2 -0
  7. package/app/api/ipanelCloudApi.js +796 -0
  8. package/app/assets/img/add.png +0 -0
  9. package/app/assets/img/add_img.png +0 -0
  10. package/app/assets/img/album.png +0 -0
  11. package/app/assets/img/album2.png +0 -0
  12. package/app/assets/img/album3.png +0 -0
  13. package/app/assets/img/album@2x.png +0 -0
  14. package/app/assets/img/album@3x.png +0 -0
  15. package/app/assets/img/audioRecordBar.png +0 -0
  16. package/app/assets/img/bootom_bar_bg.png +0 -0
  17. package/app/assets/img/close.png +0 -0
  18. package/app/assets/img/computer.png +0 -0
  19. package/app/assets/img/confirm.png +0 -0
  20. package/app/assets/img/delete_pic.png +0 -0
  21. package/app/assets/img/disabled.png +0 -0
  22. package/app/assets/img/goBack.png +0 -0
  23. package/app/assets/img/goBack2.png +0 -0
  24. package/app/assets/img/ischeck.png +0 -0
  25. package/app/assets/img/launch_bg.png +0 -0
  26. package/app/assets/img/launch_bg_panyu.png +0 -0
  27. package/app/assets/img/launch_logo.png +0 -0
  28. package/app/assets/img/launch_logo_panyu.png +0 -0
  29. package/app/assets/img/launch_text.png +0 -0
  30. package/app/assets/img/launch_text_panyu.png +0 -0
  31. package/app/assets/img/link.png +0 -0
  32. package/app/assets/img/login_bg.png +0 -0
  33. package/app/assets/img/login_bg_new.png +0 -0
  34. package/app/assets/img/login_left.png +0 -0
  35. package/app/assets/img/login_right.png +0 -0
  36. package/app/assets/img/nocheck.png +0 -0
  37. package/app/assets/img/personal.png +0 -0
  38. package/app/assets/img/photo.png +0 -0
  39. package/app/assets/img/photo@2x.png +0 -0
  40. package/app/assets/img/photo@3x.png +0 -0
  41. package/app/assets/img/protocol_checked.png +0 -0
  42. package/app/assets/img/qiehuan.png +0 -0
  43. package/app/assets/img/scan_border_bottom_left.png +0 -0
  44. package/app/assets/img/scan_border_bottom_right.png +0 -0
  45. package/app/assets/img/scan_border_top_left.png +0 -0
  46. package/app/assets/img/scan_border_top_right.png +0 -0
  47. package/app/assets/img/scan_move.png +0 -0
  48. package/app/assets/img/szjt.png +0 -0
  49. package/app/assets/img/tab.png +0 -0
  50. package/app/assets/img/tykz.png +0 -0
  51. package/app/assets/img/update_bg.png +0 -0
  52. package/app/assets/img/video.png +0 -0
  53. package/app/assets/img/video@2x.png +0 -0
  54. package/app/assets/img/video@3x.png +0 -0
  55. package/app/assets/img/worker.png +0 -0
  56. package/app/assets/img/wx.png +0 -0
  57. package/app/assets/img/ykq.png +0 -0
  58. package/app/assets/img/zfb.png +0 -0
  59. package/app/base.js +342 -0
  60. package/app/components/VersionUpdateConfirm.js +117 -0
  61. package/app/components/common/AccordionCell/index.js +67 -0
  62. package/app/components/common/ActionPicker/BasicPicker.js +136 -0
  63. package/app/components/common/ActionPicker/index.js +106 -0
  64. package/app/components/common/AddressPicker/index.js +211 -0
  65. package/app/components/common/Card/index.js +19 -0
  66. package/app/components/common/Cell/index.js +381 -0
  67. package/app/components/common/CustomDialog/index.js +120 -0
  68. package/app/components/common/CustomTabBar/index.js +157 -0
  69. package/app/components/common/CustomTabBar_bak/TabBarInput.js +210 -0
  70. package/app/components/common/CustomTabBar_bak/index.js +832 -0
  71. package/app/components/common/DateTimingPicker/index.js +254 -0
  72. package/app/components/common/Dialog/Notify.js +36 -0
  73. package/app/components/common/Dialog/baseDialog.js +146 -0
  74. package/app/components/common/Dialog/index.js +113 -0
  75. package/app/components/common/Dialog/prompt.js +145 -0
  76. package/app/components/common/Dialog/quickSelect.js +54 -0
  77. package/app/components/common/Dialog/select.js +125 -0
  78. package/app/components/common/Dialog/styles.js +167 -0
  79. package/app/components/common/Loading/index.js +71 -0
  80. package/app/components/common/LoginType/index.js +171 -0
  81. package/app/components/common/LoginType/protocol.js +160 -0
  82. package/app/components/common/Notify/index.js +68 -0
  83. package/app/components/common/OnceTouchable/index.js +33 -0
  84. package/app/components/common/PaymentPicker/index.js +264 -0
  85. package/app/components/common/ProductOrderPicker/index.js +524 -0
  86. package/app/components/common/ScreenBackHeader/index.js +144 -0
  87. package/app/components/common/ScrollPicker/index.js +232 -0
  88. package/app/components/common/SelectPicker/index.js +171 -0
  89. package/app/components/common/SmsCodeInput/index.js +93 -0
  90. package/app/components/common/SmsCodeInput/indexNew.js +101 -0
  91. package/app/components/common/Steps/index.js +126 -0
  92. package/app/components/common/Tag/index.js +17 -0
  93. package/app/components/common/Toast/index.js +103 -0
  94. package/app/components/common/WeekDaysPicker/index.js +196 -0
  95. package/app/components/index.js +8 -0
  96. package/app/components/iot/AddDeviceActionSheet/index.js +934 -0
  97. package/app/components/iot/AddressActionSheet/index.js +91 -0
  98. package/app/components/iot/RoomActionSheet/index.js +205 -0
  99. package/app/components/iot/ViewDeviceActionSheet/index.js +834 -0
  100. package/app/components/sheets.js +30 -0
  101. package/app/eventBus/index.js +54 -0
  102. package/app/hooks/checkLogin.js +30 -0
  103. package/app/hooks/shopMessageManager.js +308 -0
  104. package/app/hooks/useAddress.js +179 -0
  105. package/app/hooks/useAddress2.js +587 -0
  106. package/app/hooks/useDebounceFn.js +6 -0
  107. package/app/hooks/useDynamicPackages.js +22 -0
  108. package/app/hooks/useKeyboard.js +25 -0
  109. package/app/hooks/useLatest.js +10 -0
  110. package/app/hooks/useMessageManager.js +368 -0
  111. package/app/hooks/useNavigationFocus.js +19 -0
  112. package/app/hooks/useUser.js +56 -0
  113. package/app/screens/BaseScreen.js +389 -0
  114. package/app/screens/CommonScreens/BindPhoneScreen/index.js +179 -0
  115. package/app/screens/CommonScreens/BossScreen/index.js +138 -0
  116. package/app/screens/CommonScreens/DeviceAnswerDetailScreen/index.js +50 -0
  117. package/app/screens/CommonScreens/DeviceFeedbackScreen/index.js +365 -0
  118. package/app/screens/CommonScreens/EditInvoiceTitleScreen/index.js +279 -0
  119. package/app/screens/CommonScreens/FamilyDetailScreen/index.js +421 -0
  120. package/app/screens/CommonScreens/InvoiceTitleListScreen/index.js +118 -0
  121. package/app/screens/CommonScreens/OperatorSelectScreen/index.js +315 -0
  122. package/app/screens/CommonScreens/PersonalScreen/index.js +348 -0
  123. package/app/screens/CommonScreens/ScanQRCodeScreen/index.js +407 -0
  124. package/app/screens/CommonScreens/TvAlbumScreen/index.js +407 -0
  125. package/app/screens/LoginScreen/OpenLogSheet.js +241 -0
  126. package/app/screens/LoginScreen/index.js +920 -0
  127. package/app/screens/LoginScreen/indexNew.js +1354 -0
  128. package/app/screens/ResePassword/index.js +364 -0
  129. package/app/screens/SbkScreen.js +19 -0
  130. package/app/screens/WebviewScreen.js +41 -0
  131. package/app/storage/index.js +166 -0
  132. package/app/utils/EventEmitter.js +43 -0
  133. package/app/utils/RootNavigation.js +32 -0
  134. package/app/utils/SBK_plugin/convert.js +90 -0
  135. package/app/utils/SBK_plugin/convertStatus.js +250 -0
  136. package/app/utils/SBK_plugin/eventProcess.js +339 -0
  137. package/app/utils/SBK_plugin/index.js +32 -0
  138. package/app/utils/SBK_plugin/ipanelDeviceToSbkDevice.js +68 -0
  139. package/app/utils/SBK_plugin/sbk_defs.js +191 -0
  140. package/app/utils/StyleComposite.js +37 -0
  141. package/app/utils/applyPermissions.js +251 -0
  142. package/app/utils/bundleUpdater.js +46 -0
  143. package/app/utils/common.js +380 -0
  144. package/app/utils/config.js +47 -0
  145. package/app/utils/errCodes.js +3 -0
  146. package/app/utils/homedData.js +57 -0
  147. package/app/utils/http.js +178 -0
  148. package/app/utils/notice.js +15 -0
  149. package/app/utils/priceConversion.js +30 -0
  150. package/app/utils/registerDialog.js +90 -0
  151. package/app/utils/scaleSize.js +12 -0
  152. package/app/utils/soundPlayer.js +85 -0
  153. package/bin/local-dev.js +7 -0
  154. package/index.js +8 -0
  155. package/package.json +18 -0
@@ -0,0 +1,407 @@
1
+ import React, {useState, useEffect, useMemo, useRef} from 'react';
2
+ import {
3
+ View,
4
+ Button,
5
+ StyleSheet,
6
+ Image,
7
+ Modal,
8
+ FlatList,
9
+ TouchableOpacity,
10
+ Platform,
11
+ } from 'react-native';
12
+ import {CheckBox, Icon, Text} from '@rneui/themed';
13
+ import {
14
+ getCloudInfo,
15
+ getCloudFileList,
16
+ openCloudService,
17
+ deleteCloudFile,
18
+ } from '../../../api';
19
+ import ImageViewer from 'react-native-image-zoom-viewer';
20
+ import {launchImageLibrary} from 'react-native-image-picker';
21
+ import RNFS from 'react-native-fs';
22
+ import {useSafeArea} from 'react-native-safe-area-context';
23
+ import {showLoading, hideLoading} from '../../../utils/notice';
24
+
25
+ const {storage} = global.base;
26
+
27
+ function TvAlbumScreen() {
28
+ const [cloudInfo, setCloudInfo] = useState({});
29
+ const [cloudServiceOpened, setCloudServiceOpened] = useState(true);
30
+ const [list, setList] = useState([]);
31
+ const [isManaging, setIsManaging] = useState(false);
32
+ const [imageViewerVisible, setImageViewerVisible] = useState(false);
33
+ const [token, setToken] = useState('');
34
+ const [contentWidth, setContentWidth] = useState(0);
35
+ const domain = useRef('');
36
+
37
+ const insets = useSafeArea();
38
+
39
+ const imageUrls = useMemo(() => {
40
+ return list.map(item => ({
41
+ url: item.src,
42
+ }));
43
+ }, [list]);
44
+
45
+ const [imgIndex, setImgIndex] = useState(0);
46
+
47
+ useEffect(() => {
48
+ (async () => {
49
+ domain.current = await global.base.getHomedDomain();
50
+ await getToken();
51
+ checkCloudService();
52
+ })();
53
+ }, []);
54
+
55
+ const getToken = async () => {
56
+ const TOKEN = await storage.get('homedAccessToken');
57
+ setToken(TOKEN);
58
+ };
59
+
60
+ const contentLayout = event => {
61
+ setContentWidth(Math.floor(event.nativeEvent.layout.width));
62
+ };
63
+
64
+ const init = async () => {
65
+ showLoading('加载中');
66
+ const result = await getCloudFileList({}).catch(err => {
67
+ console.log(err);
68
+ });
69
+ hideLoading(false);
70
+ if (result && result.ret === 0) {
71
+ const list = (result.list || []).map(item => {
72
+ item.checked = false;
73
+ item.src = `http://izone.${domain.current}/httpdocsdown/${item.highbility_url}`;
74
+ return item;
75
+ });
76
+ setList(list);
77
+ hideLoading();
78
+ }
79
+ console.log(
80
+ '获取照片列表',
81
+ `http://izone.${domain.current}/account/cloud/file/get_list`,
82
+ result,
83
+ );
84
+ };
85
+
86
+ const checkCloudService = async () => {
87
+ showLoading('加载中');
88
+ const result = await getCloudInfo().catch(err => {
89
+ console.log(err);
90
+ });
91
+ console.log(result, 'getCloudInfo');
92
+ if (result && result.ret === 0) {
93
+ // 已开通云空间
94
+ setCloudInfo(result);
95
+ setCloudServiceOpened(true);
96
+ init();
97
+ } else if (result && result.ret === 20000) {
98
+ // 未开通云空间
99
+ setCloudServiceOpened(false);
100
+ showLoading('正在开通相册');
101
+ console.log('未开通云空间,正在自动开通');
102
+
103
+ // 自动开通
104
+ const openRes = await openCloudService({});
105
+ console.log(openRes, 'openRes');
106
+ if (openRes && openRes.ret === 0) {
107
+ setCloudServiceOpened(true);
108
+ init();
109
+ } else {
110
+ console.error('开通云空间失败', openRes);
111
+ setCloudServiceOpened(false);
112
+ }
113
+ } else {
114
+ // 未预期到的异常情况
115
+ setCloudServiceOpened(true);
116
+ }
117
+ hideLoading();
118
+ };
119
+
120
+ const handleDelete = () => {
121
+ showLoading('正在删除');
122
+ const deletingPics = list.filter(item => item.checked);
123
+ const promises = deletingPics.map(pic => {
124
+ return deleteCloudFile({
125
+ fileid: pic.id,
126
+ }).catch(() => {});
127
+ });
128
+
129
+ Promise.all(promises).then(async results => {
130
+ console.log(
131
+ '删除照片',
132
+ deletingPics.map(pic => pic.id),
133
+ results,
134
+ );
135
+
136
+ setIsManaging(false);
137
+ await init();
138
+ hideLoading();
139
+ });
140
+ };
141
+
142
+ const handleCancel = () => {
143
+ setIsManaging(false);
144
+ };
145
+
146
+ // todo 上传图片
147
+ const handleSelectPicture = async () => {
148
+ const result = await launchImageLibrary({
149
+ mediaType: 'mixed',
150
+ selectionLimit: 10,
151
+ });
152
+ if (result.didCancel) {
153
+ console.log('cancel');
154
+ } else if (result.errorCode) {
155
+ console.log('error', result);
156
+ } else {
157
+ console.log(result.assets);
158
+ // getFileMd5(result.assets[0]);
159
+ showLoading('上传中');
160
+ if (Platform.OS === 'ios') {
161
+ const promises = result.assets.map(async item => {
162
+ let source = item.uri.replace('file://', '');
163
+ const md5 = await RNFS.hash(source, 'md5');
164
+ const options = {
165
+ toUrl: `http://izone.${domain.current}/httpdocsup/izone/pic?fileMD5=${md5}&accesstoken=${token}`,
166
+ files: [
167
+ {
168
+ name: 'file',
169
+ filename: item.fileName,
170
+ filepath: source,
171
+ filetype: item.type,
172
+ },
173
+ ],
174
+ background: true,
175
+ method: 'POST',
176
+ begin: res => {
177
+ console.log('begin', res);
178
+ },
179
+ progress: res => {
180
+ console.log('progress', res);
181
+ },
182
+ };
183
+ return RNFS.uploadFiles(options).promise;
184
+ });
185
+ Promise.all(promises).then(res => {
186
+ hideLoading();
187
+ init();
188
+ });
189
+ } else {
190
+ const promises = result.assets.map(async item => {
191
+ const formData = new FormData();
192
+ // item.uri =
193
+ let source = item.uri;
194
+ // if (Platform.OS === 'android') {
195
+ // source = item.uri;
196
+ // } else {
197
+ // source = item.uri.replace('file://', '');
198
+ // }
199
+ formData.append('file', {
200
+ uri: source,
201
+ type: 'application/octet-stream',
202
+ name: item.type,
203
+ });
204
+ const md5 = await RNFS.hash(source, 'md5');
205
+ console.log(md5, 'md5');
206
+ return fetch(
207
+ `http://izone.${domain.current}/httpdocsup/izone/pic?fileMD5=${md5}&accesstoken=${token}`,
208
+ {
209
+ method: 'POST',
210
+ headers: {
211
+ 'Content-Type': 'multipart/form-data',
212
+ },
213
+ body: formData,
214
+ },
215
+ )
216
+ .then(res => {
217
+ return res.json();
218
+ })
219
+ .then(data => {
220
+ console.log(data);
221
+ return data;
222
+ })
223
+ .catch(err => {
224
+ return err;
225
+ });
226
+ });
227
+
228
+ Promise.all(promises).then(res => {
229
+ hideLoading();
230
+ init();
231
+ });
232
+ }
233
+ }
234
+ };
235
+
236
+ const handleManageStatus = () => {
237
+ setIsManaging(true);
238
+ list.forEach(item => {
239
+ item.checked = false;
240
+ });
241
+ setList([...list]);
242
+ };
243
+
244
+ const handleToggleCheck = item => {
245
+ item.checked = !item.checked;
246
+ setList([...list]);
247
+ };
248
+
249
+ const handleToggle = () => {
250
+ const allChecked = list.every(item => item.checked);
251
+ list.forEach(item => {
252
+ item.checked = !allChecked;
253
+ });
254
+ setList([...list]);
255
+ };
256
+
257
+ // todo 预览图片
258
+ const preview = index => {
259
+ setImgIndex(index);
260
+ setImageViewerVisible(true);
261
+ };
262
+
263
+ const renderItem = ({item, index}) => {
264
+ return (
265
+ <View
266
+ style={[
267
+ styles.gridItem,
268
+ {
269
+ width: Math.floor(contentWidth / 3),
270
+ height: Math.floor(contentWidth / 3),
271
+ padding: 5,
272
+ },
273
+ ]}>
274
+ <TouchableOpacity onPress={() => preview(index)}>
275
+ <Image
276
+ source={{
277
+ uri: item.src,
278
+ }}
279
+ style={{
280
+ width: '100%',
281
+ height: '100%',
282
+ }}
283
+ />
284
+ </TouchableOpacity>
285
+ {isManaging && (
286
+ <TouchableOpacity
287
+ style={styles.checkMask}
288
+ onPress={() => handleToggleCheck(item)}
289
+ activeOpacity={1}>
290
+ <CheckBox
291
+ containerStyle={styles.checkbox}
292
+ checked={item.checked}
293
+ checkedIcon={
294
+ <Icon name="radio-button-checked" type="material" size={20} />
295
+ }
296
+ uncheckedIcon={
297
+ <Icon name="radio-button-unchecked" type="material" size={20} />
298
+ }
299
+ />
300
+ </TouchableOpacity>
301
+ )}
302
+ </View>
303
+ );
304
+ };
305
+
306
+ return (
307
+ <View
308
+ style={{
309
+ flex: 1,
310
+ }}>
311
+ {token ? (
312
+ <>
313
+ <View style={styles.toolbar}>
314
+ {isManaging ? (
315
+ <>
316
+ <Button
317
+ title={list.every(item => item.checked) ? '取消全选' : '全选'}
318
+ onPress={handleToggle}
319
+ />
320
+ <Button
321
+ title={'删除'}
322
+ onPress={handleDelete}
323
+ color={'#e53838'}
324
+ />
325
+ <Button title={'取消'} onPress={handleCancel} />
326
+ </>
327
+ ) : (
328
+ <>
329
+ {!isManaging && (
330
+ <Button title={'上传'} onPress={handleSelectPicture} />
331
+ )}
332
+ <Button title={'管理'} onPress={handleManageStatus} />
333
+ </>
334
+ )}
335
+ </View>
336
+ <View style={styles.gridList} onLayout={contentLayout}>
337
+ <FlatList
338
+ horizontal={false}
339
+ numColumns={3}
340
+ data={list}
341
+ keyExtractor={item => item.id}
342
+ renderItem={renderItem}
343
+ columnWrapperStyle={{
344
+ marginVertical: 5,
345
+ }}
346
+ />
347
+ </View>
348
+ </>
349
+ ) : (
350
+ <Text style={{padding: 20}}>当前家庭用户暂未绑定电视业务</Text>
351
+ )}
352
+
353
+ <Modal
354
+ visible={imageViewerVisible}
355
+ onRequestClose={() => setImageViewerVisible(false)}>
356
+ <View
357
+ style={{
358
+ flexDirection: 'row',
359
+ paddingTop: Platform.OS === 'ios' ? insets.top : 0,
360
+ }}>
361
+ <Icon
362
+ name="chevron-back"
363
+ type="ionicon"
364
+ size={30}
365
+ color="#000"
366
+ onPress={() => setImageViewerVisible(false)}
367
+ />
368
+ </View>
369
+ <ImageViewer imageUrls={imageUrls} index={imgIndex} />
370
+ </Modal>
371
+ </View>
372
+ );
373
+ }
374
+
375
+ const styles = StyleSheet.create({
376
+ toolbar: {
377
+ padding: 30,
378
+ justifyContent: 'space-between',
379
+ flexDirection: 'row',
380
+ },
381
+ gridList: {
382
+ // flexWrap: 'wrap',
383
+ // flexDirection: 'row',
384
+ // justifyContent: 'space-around',
385
+ flex: 1,
386
+ },
387
+ gridItem: {
388
+ position: 'relative',
389
+ },
390
+ checkMask: {
391
+ position: 'absolute',
392
+ top: 0,
393
+ left: 0,
394
+ width: '100%',
395
+ height: '100%',
396
+ backgroundColor: 'rgba(255, 255, 255, 0.7)',
397
+ },
398
+ checkbox: {
399
+ position: 'absolute',
400
+ left: 5,
401
+ top: 5,
402
+ backgroundColor: 'transparent',
403
+ padding: 0,
404
+ },
405
+ });
406
+
407
+ export default TvAlbumScreen;
@@ -0,0 +1,241 @@
1
+ import React, {useEffect, useRef, useState, useCallback} from 'react';
2
+ import {
3
+ View,
4
+ StyleSheet,
5
+ TouchableOpacity,
6
+ Text,
7
+ NativeModules,
8
+ FlatList,
9
+ } from 'react-native';
10
+ import {Divider} from '@rneui/themed';
11
+ const {px} = global.base;
12
+ export default ({setVisible}) => {
13
+ const [activeIndex, setActiveIndex] = useState(2); // 1为在线日志、2为本地日志
14
+ const flatListRef = useRef(null);
15
+ const renderColumns = ['', '在线日志', '本地日志', ''];
16
+
17
+ // 打开时定位到默认行
18
+ const onOpen = index => {
19
+ setActiveIndex(index);
20
+ flatListRef.current?.scrollToIndex({
21
+ index: index - 1,
22
+ });
23
+ };
24
+ const getLogReportStatus = val => {
25
+ if (NativeModules?.RNToNativeEmitter?.getLogReportStatus) {
26
+ NativeModules.RNToNativeEmitter.getLogReportStatus(res => {
27
+ console.log('getLogReportStatus', res);
28
+ if (val) {
29
+ global.toast.showToast('设置成功');
30
+ setVisible(false);
31
+ } else {
32
+ if (res === 1) {
33
+ onOpen(1);
34
+ } else {
35
+ onOpen(2);
36
+ }
37
+ }
38
+ });
39
+ }
40
+ };
41
+
42
+ const handleConfirm = async () => {
43
+ console.log(activeIndex);
44
+ if (activeIndex === 1) {
45
+ if (NativeModules?.RNToNativeEmitter?.openLogReport) {
46
+ await NativeModules.RNToNativeEmitter.openLogReport();
47
+ getLogReportStatus(1);
48
+ }
49
+ } else {
50
+ if (NativeModules?.RNToNativeEmitter?.closeLogReport) {
51
+ await NativeModules.RNToNativeEmitter.closeLogReport();
52
+ getLogReportStatus(2);
53
+ }
54
+ }
55
+ };
56
+
57
+ useEffect(() => {
58
+ getLogReportStatus();
59
+ }, []);
60
+
61
+ const renderItem = ({item, index}) => {
62
+ const columnTextStyle =
63
+ index === activeIndex ? styles.activeColumnText : styles.columnText;
64
+ let columnDisabled = false;
65
+ return (
66
+ <TouchableOpacity
67
+ disabled={!item}
68
+ onPress={() => {
69
+ console.log(index);
70
+ flatListRef.current?.scrollToIndex({
71
+ index: index - 1,
72
+ });
73
+ }}
74
+ style={{
75
+ ...styles.column,
76
+ height: item ? px(120) : px(80),
77
+ }}>
78
+ <Text
79
+ style={{
80
+ ...columnTextStyle,
81
+ color: columnDisabled ? '#999' : columnTextStyle.color,
82
+ textDecorationLine: columnDisabled ? 'line-through' : 'none',
83
+ }}>
84
+ {item}
85
+ </Text>
86
+ </TouchableOpacity>
87
+ );
88
+ };
89
+
90
+ // 固定5个数据高度,永远聚焦中间那条 ios可以滚动出视图范围弹性地拉动一截,可能可视区域数量不一定是5个
91
+ const onViewableItemsChanged = useCallback(({viewableItems}) => {
92
+ console.log(viewableItems, 'viewableItems');
93
+ if (
94
+ viewableItems.length >= 3 &&
95
+ viewableItems[viewableItems.length - 2]?.item
96
+ ) {
97
+ const index = viewableItems[viewableItems.length - 2].index;
98
+ setActiveIndex(index);
99
+ }
100
+ }, []);
101
+ return (
102
+ <>
103
+ <TouchableOpacity
104
+ style={styles.mask}
105
+ onPress={() => setVisible(false)}
106
+ activeOpacity={1}
107
+ />
108
+ <View style={styles.container}>
109
+ <View style={styles.columns}>
110
+ <FlatList
111
+ scrollEnabled={true}
112
+ // ref={flatListRef}
113
+ ref={flatListRef}
114
+ showsVerticalScrollIndicator={false}
115
+ horizontal={false}
116
+ // alwaysBounceVertical={false}
117
+ // bounces={false}
118
+ pagingEnabled={false}
119
+ // overScrollMode="never"
120
+ numColumns={1}
121
+ data={renderColumns}
122
+ keyExtractor={(item, index) => index}
123
+ renderItem={renderItem}
124
+ getItemLayout={(data, index) => {
125
+ let itemHeight =
126
+ index === 0
127
+ ? 0
128
+ : index === 1
129
+ ? px(80)
130
+ : index === 2
131
+ ? px(120 + 80)
132
+ : px(120 * 2 + 80);
133
+ let length = index === 0 || index === 3 ? px(80) : px(120);
134
+ return {
135
+ length: length,
136
+ offset: itemHeight,
137
+ index,
138
+ };
139
+ }}
140
+ onViewableItemsChanged={onViewableItemsChanged}
141
+ viewabilityConfig={{
142
+ viewAreaCoveragePercentThreshold: 20,
143
+ }}
144
+ />
145
+ </View>
146
+ <Divider width={1} color="#f5f5f5" />
147
+ <View style={styles.bottomBtnBox}>
148
+ <TouchableOpacity
149
+ style={styles.bottomBtn}
150
+ onPress={() => setVisible(false)}>
151
+ <Text style={styles.bottomBtnText}>取消</Text>
152
+ </TouchableOpacity>
153
+
154
+ <Divider orientation="vertical" width={1} color="#eee" />
155
+ <TouchableOpacity style={styles.bottomBtn} onPress={handleConfirm}>
156
+ <Text
157
+ style={[
158
+ styles.bottomBtnText,
159
+ {
160
+ color: '#ea6000',
161
+ fontWeight: 'bold',
162
+ },
163
+ ]}>
164
+ 确定
165
+ </Text>
166
+ </TouchableOpacity>
167
+ </View>
168
+ </View>
169
+ </>
170
+ );
171
+ };
172
+
173
+ const styles = StyleSheet.create({
174
+ mask: {
175
+ position: 'absolute',
176
+ top: 0,
177
+ bottom: 0,
178
+ left: 0,
179
+ right: 0,
180
+ backgroundColor: 'rgba(0,0,0,0.5)',
181
+ },
182
+ container: {
183
+ position: 'absolute',
184
+ height: px(120) * 2 + px(80) + px(141),
185
+ left: 0,
186
+ right: 0,
187
+ bottom: 0,
188
+ backgroundColor: '#fff',
189
+ borderTopLeftRadius: px(30),
190
+ borderTopRightRadius: px(30),
191
+ },
192
+ btnBox: {
193
+ height: px(141),
194
+ justifyContent: 'center',
195
+ alignItems: 'center',
196
+ },
197
+ btntext: {
198
+ fontSize: px(52),
199
+ color: '#333',
200
+ },
201
+ bottomBtnBox: {
202
+ display: 'flex',
203
+ flexDirection: 'row',
204
+ justifyContent: 'space-evenly',
205
+ alignItems: 'center',
206
+ paddingTop: px(29),
207
+ paddingBottom: px(132),
208
+ },
209
+ bottomBtn: {
210
+ flex: 1,
211
+ },
212
+ bottomBtnText: {
213
+ textAlign: 'center',
214
+ color: '#666',
215
+ fontSize: px(52),
216
+ },
217
+ columns: {
218
+ paddingHorizontal: px(55),
219
+ // maxHeight: Math.floor(deviceHeight / 2),
220
+ height: px(120) * 2 + px(80),
221
+ },
222
+ column: {
223
+ // paddingVertical: px(44),
224
+ height: px(120),
225
+ flexDirection: 'row',
226
+ alignItems: 'center',
227
+ justifyContent: 'center',
228
+ },
229
+ columnText: {
230
+ fontSize: px(40),
231
+ color: '#999',
232
+ textAlign: 'center',
233
+ fontWeight: '500',
234
+ },
235
+ activeColumnText: {
236
+ fontSize: px(69),
237
+ color: '#333',
238
+ textAlign: 'center',
239
+ fontWeight: '500',
240
+ },
241
+ });