品类商品列表相关代码 review by 孙凯
Showing
12 changed files
with
803 additions
and
0 deletions
@@ -24,6 +24,7 @@ import productListForShopInitialState from './reducers/productListForShop/produc | @@ -24,6 +24,7 @@ import productListForShopInitialState from './reducers/productListForShop/produc | ||
24 | import ProductListForShopContainer from './containers/ProductListForShopContainer'; | 24 | import ProductListForShopContainer from './containers/ProductListForShopContainer'; |
25 | import ProductListPoolContainer from './containers/ProductListPoolContainer'; | 25 | import ProductListPoolContainer from './containers/ProductListPoolContainer'; |
26 | import ProductListPoolInitialState from './reducers/productListPool/productListPoolInitialState'; | 26 | import ProductListPoolInitialState from './reducers/productListPool/productListPoolInitialState'; |
27 | +import CategoryProListInitialState from './reducers/categoryProList/categoryProListInitialState'; | ||
27 | 28 | ||
28 | import screenInitialState from './reducers/screen/screenInitialState'; | 29 | import screenInitialState from './reducers/screen/screenInitialState'; |
29 | import screenCategoryInitialState from './reducers/screenCategory/screenCategoryInitialState'; | 30 | import screenCategoryInitialState from './reducers/screenCategory/screenCategoryInitialState'; |
@@ -33,6 +34,8 @@ import ScreenContainer from './containers/ScreenContainer'; | @@ -33,6 +34,8 @@ import ScreenContainer from './containers/ScreenContainer'; | ||
33 | import ScreenCategoryContainer from './containers/ScreenCategoryContainer'; | 34 | import ScreenCategoryContainer from './containers/ScreenCategoryContainer'; |
34 | import ScreenSubContainer from './containers/ScreenSubContainer'; | 35 | import ScreenSubContainer from './containers/ScreenSubContainer'; |
35 | 36 | ||
37 | +import CategoryProductListContainer from './containers/CategoryProListContainer' | ||
38 | + | ||
36 | 39 | ||
37 | import { | 40 | import { |
38 | setPlatform, | 41 | setPlatform, |
@@ -56,6 +59,7 @@ function getInitialState() { | @@ -56,6 +59,7 @@ function getInitialState() { | ||
56 | screenSub: (new screenSubInitialState()), | 59 | screenSub: (new screenSubInitialState()), |
57 | productListForShop: (new productListForShopInitialState()), | 60 | productListForShop: (new productListForShopInitialState()), |
58 | productListPool: (new ProductListPoolInitialState()), | 61 | productListPool: (new ProductListPoolInitialState()), |
62 | + categoryProList: (new CategoryProListInitialState()), | ||
59 | }; | 63 | }; |
60 | return _initState; | 64 | return _initState; |
61 | } | 65 | } |
@@ -68,6 +72,7 @@ export default function native(platform) { | @@ -68,6 +72,7 @@ export default function native(platform) { | ||
68 | const store = configureStore(getInitialState()); | 72 | const store = configureStore(getInitialState()); |
69 | store.dispatch(setPlatform(platform)); | 73 | store.dispatch(setPlatform(platform)); |
70 | let {host,serviceHost, channel,type,brand_id,shop_id,dictParams,saleType,activityId} = this.props; | 74 | let {host,serviceHost, channel,type,brand_id,shop_id,dictParams,saleType,activityId} = this.props; |
75 | + | ||
71 | store.dispatch(setHost(host)); | 76 | store.dispatch(setHost(host)); |
72 | store.dispatch(setServiceHost(serviceHost)); | 77 | store.dispatch(setServiceHost(serviceHost)); |
73 | store.dispatch(setChannel(channel)); | 78 | store.dispatch(setChannel(channel)); |
@@ -114,7 +119,14 @@ export default function native(platform) { | @@ -114,7 +119,14 @@ export default function native(platform) { | ||
114 | <ProductListPoolContainer /> | 119 | <ProductListPoolContainer /> |
115 | </Provider> | 120 | </Provider> |
116 | ); | 121 | ); |
122 | + } else if (type == 'YH_CategoryProList') { | ||
123 | + return ( | ||
124 | + <Provider store={store}> | ||
125 | + <CategoryProductListContainer /> | ||
126 | + </Provider> | ||
127 | + ); | ||
117 | } | 128 | } |
129 | + | ||
118 | return null; | 130 | return null; |
119 | } | 131 | } |
120 | }); | 132 | }); |
1 | +'use strict' | ||
2 | +import React, {Component} from 'react'; | ||
3 | + | ||
4 | +import ReactNative, { | ||
5 | + StyleSheet, | ||
6 | + Dimensions, | ||
7 | + NativeAppEventEmitter, | ||
8 | + View, | ||
9 | +} from 'react-native' | ||
10 | + | ||
11 | +import YH_CategoryListHeader from './YH_CategoryListHeader' | ||
12 | + | ||
13 | +export default class CategoryListHeader extends Component { | ||
14 | + constructor(props) { | ||
15 | + super(props); | ||
16 | + this.onClick = this.onClick.bind(this); | ||
17 | + this.clearClick = this.clearClick.bind(this); | ||
18 | + } | ||
19 | + | ||
20 | + onClick(event: Event) { | ||
21 | + let type = event.nativeEvent.type; | ||
22 | + let data = event.nativeEvent.data; | ||
23 | + if (type == 'clear') { | ||
24 | + this.props.clearClick&&this.props.clearClick(data); | ||
25 | + }else if (type == 'click') { | ||
26 | + this.props.onClick&&this.props.onClick(data); | ||
27 | + } | ||
28 | + } | ||
29 | + | ||
30 | + clearClick(event: Event) { | ||
31 | + let item = event.nativeEvent; | ||
32 | + console.log(item); | ||
33 | + } | ||
34 | + | ||
35 | + render() { | ||
36 | + let {dataSource} = this.props; | ||
37 | + return ( | ||
38 | + <View style={styles.container}> | ||
39 | + <YH_CategoryListHeader | ||
40 | + style={styles.header} | ||
41 | + dataSource={dataSource.toJS()} | ||
42 | + onClick={this.onClick} | ||
43 | + /> | ||
44 | + </View> | ||
45 | + ) | ||
46 | + } | ||
47 | +} | ||
48 | + | ||
49 | +let {width} = Dimensions.get('window'); | ||
50 | +const DEVICE_WIDTH_RATIO = width / 375; | ||
51 | +let styles = StyleSheet.create({ | ||
52 | + container: { | ||
53 | + width, | ||
54 | + height: 45, | ||
55 | + backgroundColor: 'white', | ||
56 | + }, | ||
57 | + header: { | ||
58 | + width: width, | ||
59 | + height: 45, | ||
60 | + }, | ||
61 | + | ||
62 | + | ||
63 | + | ||
64 | +}); |
1 | +'use strict' | ||
2 | + | ||
3 | +import React, {Component} from 'react'; | ||
4 | +import ReactNative, { | ||
5 | + StyleSheet, | ||
6 | + Dimensions, | ||
7 | + InteractionManager, | ||
8 | + NativeAppEventEmitter, | ||
9 | + View, | ||
10 | + ListView, | ||
11 | +} from 'react-native' | ||
12 | + | ||
13 | +import LoadingIndicator from '../../../common/components/LoadingIndicator'; | ||
14 | +import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator'; | ||
15 | +import BrandProductFilter from '../cell/BrandProductFilter'; | ||
16 | +import ProductListCell from '../../../common/components/ListCell/ProductListCell'; | ||
17 | +import CategoryListHeader from './CategoryListHeader' | ||
18 | + | ||
19 | +export default class CategoryProList extends Component { | ||
20 | + constructor(props) { | ||
21 | + super(props); | ||
22 | + this.renderRow = this.renderRow.bind(this); | ||
23 | + this.dataSource = new ListView.DataSource({ | ||
24 | + rowHasChanged: (r1, r2) => !Immutable.is(r1, r2), | ||
25 | + sectionHeaderHasChanged: (s1, s2) => !Immutable.is(s1, s2), | ||
26 | + }); | ||
27 | + } | ||
28 | + | ||
29 | + renderRow(rowData, sectionID, rowID, highlightRow) { | ||
30 | + switch(sectionID) { | ||
31 | + case 'productListHeader': { | ||
32 | + let noFilterValue = true; | ||
33 | + this.props.filterFactors.map((value, key) => { | ||
34 | + if (value) { | ||
35 | + noFilterValue = false; | ||
36 | + } | ||
37 | + }); | ||
38 | + let productListIsEmpty = !this.props.productList || !this.props.productList.list || this.props.productList.list.size == 0; | ||
39 | + if (productListIsEmpty && noFilterValue) { | ||
40 | + return null; | ||
41 | + } | ||
42 | + return ( | ||
43 | + <View style={styles.brandFilterContainer} onLayout={(evt) => {yPosition = evt.nativeEvent.layout.y;}}> | ||
44 | + <BrandProductFilter | ||
45 | + onPressFilter={this.props.onPressProductFilter} | ||
46 | + selectOrder={this.props.productList.order} | ||
47 | + /> | ||
48 | + </View> | ||
49 | + ) | ||
50 | + } | ||
51 | + case 'categoryListHeader': { | ||
52 | + let { | ||
53 | + standardFilterList, | ||
54 | + } = this.props; | ||
55 | + return ( | ||
56 | + <CategoryListHeader | ||
57 | + dataSource={standardFilterList} | ||
58 | + onClick={this.props.onClickStandardFilter} | ||
59 | + clearClick={this.props.clearClickStandardFilter} | ||
60 | + /> | ||
61 | + ) | ||
62 | + } | ||
63 | + case 'productList': { | ||
64 | + let similarIndex = this.props.similarIndex; | ||
65 | + let paddingLeft = rowID % 2 == 1 ? rowMarginHorizontal / 2 : rowMarginHorizontal; | ||
66 | + let customStyle = rowID == 0 || rowID == 1 ? {paddingLeft} : {paddingLeft}; | ||
67 | + return ( | ||
68 | + <ProductListCell | ||
69 | + style={[styles.listContainer, customStyle]} | ||
70 | + key={'row' + rowID} | ||
71 | + rowID={rowID} | ||
72 | + data={rowData} | ||
73 | + similarIndex={similarIndex} | ||
74 | + onPressProduct={this.props.onPressProductCell} | ||
75 | + onLongPressProduct={this.props.onLongPressProduct} | ||
76 | + onPressFindSimilar={this.props.onPressFindSimilar} | ||
77 | + onPressDislike={this.props.onPressDislike}/> | ||
78 | + ) | ||
79 | + } | ||
80 | + default: | ||
81 | + return null; | ||
82 | + } | ||
83 | + return null; | ||
84 | + } | ||
85 | + | ||
86 | + | ||
87 | + render() { | ||
88 | + | ||
89 | + let { | ||
90 | + productList, | ||
91 | + standardFilterList, | ||
92 | + } = this.props; | ||
93 | + let isFetching = (productList.isFetching && productList.currentPage == 0); | ||
94 | + let dataSource = {}; | ||
95 | + if (productList.list.toArray().length > 0) { | ||
96 | + if (standardFilterList&&standardFilterList.size > 0) { | ||
97 | + dataSource = { | ||
98 | + productListHeader: ['1'], | ||
99 | + categoryListHeader: ['1'], | ||
100 | + productList: productList.list.toArray(), | ||
101 | + }; | ||
102 | + }else { | ||
103 | + dataSource = { | ||
104 | + productListHeader: ['1'], | ||
105 | + productList: productList.list.toArray(), | ||
106 | + }; | ||
107 | + } | ||
108 | + } | ||
109 | + | ||
110 | + let isLoadingMore = productList.isFetching && productList.currentPage > 0; | ||
111 | + let endReached = productList.endReached; | ||
112 | + | ||
113 | + return ( | ||
114 | + <View style={styles.container}> | ||
115 | + <ListView | ||
116 | + ref='CategoryProList' | ||
117 | + contentContainerStyle={styles.contentContainer} | ||
118 | + enableEmptySections={true} | ||
119 | + dataSource={this.dataSource.cloneWithRowsAndSections(dataSource)} | ||
120 | + renderRow={this.renderRow} | ||
121 | + renderFooter={()=>{ | ||
122 | + if (endReached) { | ||
123 | + return <View style={styles.placeholder} />; | ||
124 | + } else { | ||
125 | + return <LoadMoreIndicator isVisible={isLoadingMore} animating={true}/>; | ||
126 | + } | ||
127 | + }} | ||
128 | + onEndReached={() => { | ||
129 | + if (productList && productList.list && productList.list.size > 0) { | ||
130 | + this.props.onEndReached && this.props.onEndReached(); | ||
131 | + } | ||
132 | + }} | ||
133 | + /> | ||
134 | + <LoadingIndicator | ||
135 | + isVisible={isFetching} | ||
136 | + /> | ||
137 | + </View> | ||
138 | + ); | ||
139 | + } | ||
140 | +} | ||
141 | + | ||
142 | +let {width, height} = Dimensions.get('window'); | ||
143 | +let rowWidth = Math.ceil(137.5 * width / 320); | ||
144 | +let rowHeight = Math.ceil(254 * width / 320); | ||
145 | +let rowMarginTop = Math.ceil(10 * width / 320); | ||
146 | +let rowMarginHorizontal = (width - rowWidth * 2) / 3; | ||
147 | +let yPosition = 0; | ||
148 | + | ||
149 | +let styles = StyleSheet.create({ | ||
150 | + container: { | ||
151 | + flex: 1, | ||
152 | + }, | ||
153 | + contentContainer:{ | ||
154 | + flexDirection: 'row', | ||
155 | + flexWrap: 'wrap', | ||
156 | + }, | ||
157 | + placeholder: { | ||
158 | + width, | ||
159 | + height: 15, | ||
160 | + }, | ||
161 | + listContainer: { | ||
162 | + width: width / 2, | ||
163 | + }, | ||
164 | + brandFilterContainer: { | ||
165 | + marginLeft: -1, | ||
166 | + width: width + 2, | ||
167 | + height: 40, | ||
168 | + }, | ||
169 | + categoryListContainer: { | ||
170 | + width: width, | ||
171 | + height: 45, | ||
172 | + } | ||
173 | +}); |
1 | +import React from 'react'; | ||
2 | +import ReactNative from 'react-native'; | ||
3 | +import ImmutablePropTypes from 'react-immutable-proptypes'; | ||
4 | + | ||
5 | +let { | ||
6 | + requireNativeComponent, | ||
7 | + View | ||
8 | +} = ReactNative; | ||
9 | + | ||
10 | +let YH_CategoryListHeader = requireNativeComponent('YH_CategoryListHeader', null); | ||
11 | + | ||
12 | +export default class CategoryListHeader extends React.Component { | ||
13 | + | ||
14 | + static propTypes = { | ||
15 | + ...View.propTypes // 包含默认的View的属性 | ||
16 | + }; | ||
17 | + | ||
18 | + constructor(props) { | ||
19 | + super(props); | ||
20 | + } | ||
21 | + | ||
22 | + render() { | ||
23 | + return <YH_CategoryListHeader {...this.props} data={this.props.data} />; | ||
24 | + } | ||
25 | +} |
@@ -59,4 +59,6 @@ export default keyMirror({ | @@ -59,4 +59,6 @@ export default keyMirror({ | ||
59 | GET_ACTIVITY_REQUEST: null, | 59 | GET_ACTIVITY_REQUEST: null, |
60 | GET_ACTIVITY_SUCCESS: null, | 60 | GET_ACTIVITY_SUCCESS: null, |
61 | GET_ACTIVITY_FAILURE: null, | 61 | GET_ACTIVITY_FAILURE: null, |
62 | + | ||
63 | + SELECT_STANDARDFILTER_ITEM: null, | ||
62 | }); | 64 | }); |
1 | +'use strict' | ||
2 | + | ||
3 | +import React, {Component} from 'react'; | ||
4 | +import ReactNative, { | ||
5 | + StyleSheet, | ||
6 | + Platform, | ||
7 | + InteractionManager, | ||
8 | + NativeAppEventEmitter, | ||
9 | +} from 'react-native' | ||
10 | + | ||
11 | +import {bindActionCreators} from 'redux'; | ||
12 | +import {connect} from 'react-redux'; | ||
13 | +import {Map} from 'immutable'; | ||
14 | +import * as categoryProListActions from '../reducers/categoryProList/categoryProListActions'; | ||
15 | +import CategoryProList from '../components/category/CategoryProList'; | ||
16 | + | ||
17 | +const actions = [ | ||
18 | + categoryProListActions, | ||
19 | +]; | ||
20 | + | ||
21 | +function mapStateToProps(state) { | ||
22 | + return { | ||
23 | + ...state | ||
24 | + }; | ||
25 | +} | ||
26 | + | ||
27 | +function mapDispatchToProps(dispatch) { | ||
28 | + | ||
29 | + const creators = Map() | ||
30 | + .merge(...actions) | ||
31 | + .filter(value => typeof value === 'function') | ||
32 | + .toObject(); | ||
33 | + | ||
34 | + return { | ||
35 | + actions: bindActionCreators(creators, dispatch), | ||
36 | + dispatch | ||
37 | + }; | ||
38 | +} | ||
39 | + | ||
40 | +class CategoryProductListContainer extends Component { | ||
41 | + constructor(props) { | ||
42 | + super(props); | ||
43 | + this._onEndReached = this._onEndReached.bind(this); | ||
44 | + this._onLongPressProduct = this._onLongPressProduct.bind(this); | ||
45 | + this._onPressFindSimilar = this._onPressFindSimilar.bind(this); | ||
46 | + this._onPressProductCell = this._onPressProductCell.bind(this); | ||
47 | + this._onPressProductFilter = this._onPressProductFilter.bind(this); | ||
48 | + this._onClickStandardFilter = this._onClickStandardFilter.bind(this); | ||
49 | + this._clearClickStandardFilter = this._clearClickStandardFilter.bind(this); | ||
50 | + | ||
51 | + this.subscription = NativeAppEventEmitter.addListener( | ||
52 | + 'updateProductByFilter', | ||
53 | + (array) => { | ||
54 | + if (array.length > 0) { | ||
55 | + this.props.actions.setProductFilterFactors(array); | ||
56 | + this.props.actions.resetListPageInfo(); | ||
57 | + this.props.actions.getProductList(true); | ||
58 | + this.props.actions.setSimilarIndex(-1); | ||
59 | + } | ||
60 | + } | ||
61 | + ); | ||
62 | + } | ||
63 | + | ||
64 | + componentDidMount() { | ||
65 | + this.props.actions.getProductList(); | ||
66 | + } | ||
67 | + | ||
68 | + componentWillUnmount() { | ||
69 | + this.subscription && this.subscription.remove(); | ||
70 | + } | ||
71 | + | ||
72 | + _onPressProductFilter(value) { | ||
73 | + this.props.actions.resetListPageInfo(); | ||
74 | + this.props.actions.setProductListFilter(value); | ||
75 | + this.props.actions.getProductList(true); | ||
76 | + this.props.actions.setSimilarIndex(-1); | ||
77 | + } | ||
78 | + | ||
79 | + _onEndReached() { | ||
80 | + this.props.actions.getProductList(); | ||
81 | + } | ||
82 | + | ||
83 | + _onPressProductCell(product, rowId=0) { | ||
84 | + let productSkn = product && product.get('product_skn', 0); | ||
85 | + if (!productSkn) { | ||
86 | + return; | ||
87 | + } | ||
88 | + let url = `http://m.yohobuy.com?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":"${productSkn}"}}`; | ||
89 | + ReactNative.NativeModules.YH_CommonHelper.jumpWithUrl(url); | ||
90 | + } | ||
91 | + | ||
92 | + _onLongPressProduct(rowID) { | ||
93 | + if (rowID) { | ||
94 | + this.props.actions.setSimilarIndex(rowID); | ||
95 | + } | ||
96 | + } | ||
97 | + | ||
98 | + _onPressFindSimilar(product) { | ||
99 | + if (!product) { | ||
100 | + return; | ||
101 | + } | ||
102 | + | ||
103 | + ReactNative.NativeModules.YH_CommonHelper.jumpFindSimilar(product.toJS()); | ||
104 | + } | ||
105 | + | ||
106 | + _clearClickStandardFilter(standarFilterItem) { | ||
107 | + this.props.actions.clearStandardFilter(standarFilterItem); | ||
108 | + this.props.actions.resetListPageInfo(); | ||
109 | + this.props.actions.getProductList(true); | ||
110 | + this.props.actions.setSimilarIndex(-1); | ||
111 | + } | ||
112 | + | ||
113 | + _onClickStandardFilter(standarFilterItem) { | ||
114 | + this.props.actions.selectStandardFilter(standarFilterItem); | ||
115 | + this.props.actions.resetListPageInfo(); | ||
116 | + this.props.actions.getProductList(true); | ||
117 | + this.props.actions.setSimilarIndex(-1); | ||
118 | + } | ||
119 | + | ||
120 | + render() { | ||
121 | + let { | ||
122 | + productList, | ||
123 | + similarIndex, | ||
124 | + filterFactors, | ||
125 | + filterNameFactors, | ||
126 | + standardFilterList | ||
127 | + } = this.props.categoryProList; | ||
128 | + | ||
129 | + return ( | ||
130 | + <CategoryProList | ||
131 | + similarIndex={similarIndex} | ||
132 | + productList={productList} | ||
133 | + filterFactors={filterFactors} | ||
134 | + filterNameFactors={filterNameFactors} | ||
135 | + standardFilterList={standardFilterList} | ||
136 | + onClickStandardFilter={this._onClickStandardFilter} | ||
137 | + clearClickStandardFilter={this._clearClickStandardFilter} | ||
138 | + onEndReached={this._onEndReached} | ||
139 | + onPressProductCell={this._onPressProductCell} | ||
140 | + onLongPressProduct={this._onLongPressProduct} | ||
141 | + onPressFindSimilar={this._onPressFindSimilar} | ||
142 | + onPressProductFilter={this._onPressProductFilter} | ||
143 | + /> | ||
144 | + ); | ||
145 | + } | ||
146 | +} | ||
147 | + | ||
148 | +let styles = StyleSheet.create({ | ||
149 | + container: { | ||
150 | + flex: 1, | ||
151 | + }, | ||
152 | +}); | ||
153 | + | ||
154 | +export default connect(mapStateToProps, mapDispatchToProps)(CategoryProductListContainer); |
1 | +'use strict'; | ||
2 | + | ||
3 | +import ReactNative from 'react-native'; | ||
4 | +import CategoryProListService from '../../services/CategoryProListService'; | ||
5 | +import * as _ from 'lodash'; | ||
6 | +import Utils from '../../utils/Utils' | ||
7 | + | ||
8 | +const { | ||
9 | + PRODUCT_LIST_REQUEST, | ||
10 | + PRODUCT_LIST_SUCCESS, | ||
11 | + PRODUCT_LIST_FAILURE, | ||
12 | + PRODUCT_FILTER_ACTION, | ||
13 | + RESET_LIST_PAGE_INFO, | ||
14 | + SET_PRODUCT_LIST_FILTER, | ||
15 | + SET_SIMILAR_PRODUCT_INDEX, | ||
16 | + SELECT_STANDARDFILTER_ITEM | ||
17 | +} = require('../../constants/actionTypes').default; | ||
18 | + | ||
19 | +export function productListRequest() { | ||
20 | + return { | ||
21 | + type: PRODUCT_LIST_REQUEST, | ||
22 | + }; | ||
23 | +} | ||
24 | + | ||
25 | +export function productListSuccess(json) { | ||
26 | + return { | ||
27 | + type: PRODUCT_LIST_SUCCESS, | ||
28 | + payload: json | ||
29 | + } | ||
30 | +} | ||
31 | + | ||
32 | +export function productListFailure(error) { | ||
33 | + return { | ||
34 | + type: PRODUCT_LIST_FAILURE, | ||
35 | + payload: error | ||
36 | + } | ||
37 | +} | ||
38 | + | ||
39 | +export function getProductList(reload=false) { | ||
40 | + return (dispatch, getState) => { | ||
41 | + | ||
42 | + let {app, categoryProList} = getState(); | ||
43 | + let {productList, filterFactors, standardFilterList} = categoryProList; | ||
44 | + let {originParams} = app; | ||
45 | + | ||
46 | + if (reload) { | ||
47 | + | ||
48 | + } else { | ||
49 | + if (productList.isFetching || productList.endReached || productList.error) { | ||
50 | + return; | ||
51 | + } | ||
52 | + } | ||
53 | + let page = productList.currentPage + 1; | ||
54 | + let pageSize = productList.pageSize; | ||
55 | + let order = productList.order; | ||
56 | + | ||
57 | + let bSelectedFilterFactor,allFilterFactors; | ||
58 | + allFilterFactors = filterFactors.toJS(); | ||
59 | + | ||
60 | + for (let prop in allFilterFactors) { | ||
61 | + if (allFilterFactors.hasOwnProperty(prop)) { | ||
62 | + if (allFilterFactors[prop] === '' || !allFilterFactors[prop]) { | ||
63 | + delete allFilterFactors[prop]; | ||
64 | + } | ||
65 | + if (prop == 'sizeKey' && allFilterFactors[prop]) { | ||
66 | + allFilterFactors['size'] = allFilterFactors[prop]; | ||
67 | + delete allFilterFactors[prop]; | ||
68 | + } | ||
69 | + } | ||
70 | + } | ||
71 | + | ||
72 | + let standard = ''; | ||
73 | + let standardList = standardFilterList.toJS(); | ||
74 | + | ||
75 | + for (var i = 0; i < standardList.length; i++) { | ||
76 | + let filterItem = standardList[i] | ||
77 | + if (filterItem.isSelect) { | ||
78 | + let selectFilter = filterItem.selectFilter; | ||
79 | + if (standard.length == 0) { | ||
80 | + standard = filterItem.standard_id + '_' + selectFilter.standard_id; | ||
81 | + } else { | ||
82 | + standard = standard + ',' + filterItem.standard_id + '_' + selectFilter.standard_id; | ||
83 | + } | ||
84 | + } | ||
85 | + } | ||
86 | + | ||
87 | + allFilterFactors['standard'] = standard; | ||
88 | + | ||
89 | + console.log(allFilterFactors); | ||
90 | + | ||
91 | + dispatch(productListRequest()); | ||
92 | + return new CategoryProListService(app.host).productList(page, pageSize, originParams, allFilterFactors, order, '') | ||
93 | + .then(json => { | ||
94 | + let payload = Utils.parseProductList(json); | ||
95 | + payload.endReached = payload.currentPage == payload.pageCount; | ||
96 | + | ||
97 | + if (payload.currentPage > 1) { | ||
98 | + let oldList = productList.list.toJS(); | ||
99 | + let list = [...oldList, ...payload.list]; | ||
100 | + payload.list = list; | ||
101 | + } | ||
102 | + | ||
103 | + let categoryFilterList = payload.categoryFilterList; | ||
104 | + let filterCategoryDetailFilterList = payload.filterCategoryDetailFilterList; | ||
105 | + let filters = Utils.parsecategoryFilter({categoryFilterList,filterCategoryDetailFilterList}); | ||
106 | + ReactNative.NativeModules.YH_ProductListRNViewHelper.setFilterData(filters); | ||
107 | + ReactNative.NativeModules.YH_ScreenCategoryViewHelper.enableBrandFilter(); | ||
108 | + dispatch(productListSuccess(payload)); | ||
109 | + }) | ||
110 | + .catch(error => { | ||
111 | + dispatch(productListFailure(error)); | ||
112 | + }); | ||
113 | + }; | ||
114 | +} | ||
115 | + | ||
116 | + | ||
117 | +export function resetListPageInfo() { | ||
118 | + return { | ||
119 | + type: RESET_LIST_PAGE_INFO, | ||
120 | + } | ||
121 | +} | ||
122 | + | ||
123 | +export function setProductListFilter(value) { | ||
124 | + return { | ||
125 | + type: SET_PRODUCT_LIST_FILTER, | ||
126 | + payload: value | ||
127 | + } | ||
128 | +} | ||
129 | + | ||
130 | +export function setSimilarIndex(rowID) { | ||
131 | + return { | ||
132 | + type: SET_SIMILAR_PRODUCT_INDEX, | ||
133 | + payload: rowID | ||
134 | + } | ||
135 | +} | ||
136 | + | ||
137 | +export function setProductFilterFactors(array) { | ||
138 | + return (dispatch, getState) => { | ||
139 | + let {app, categoryProList} = getState(); | ||
140 | + let {filterFactors} = categoryProList; | ||
141 | + filterFactors = filterFactors.toJS(); | ||
142 | + | ||
143 | + for (var i = 0; i < array.length; i++) { | ||
144 | + let item = array[i]; | ||
145 | + filterFactors[item._key] = item._value; | ||
146 | + } | ||
147 | + dispatch({ | ||
148 | + type: PRODUCT_FILTER_ACTION, | ||
149 | + payload: filterFactors | ||
150 | + }); | ||
151 | + }; | ||
152 | +} | ||
153 | + | ||
154 | +export function selectStandardFilter(item) { | ||
155 | + return (dispatch, getState) => { | ||
156 | + let {categoryProList} = getState(); | ||
157 | + let {standardFilterList} = categoryProList; | ||
158 | + standardFilterList = standardFilterList ? standardFilterList.toJS() : []; | ||
159 | + for (var i = 0; i < standardFilterList.length; i++) { | ||
160 | + let filterItem = standardFilterList[i]; | ||
161 | + if (filterItem.standard_id == item.standard_id) { | ||
162 | + filterItem.isSelect = true; | ||
163 | + filterItem.selectFilter = item.selectFilter; | ||
164 | + break | ||
165 | + } | ||
166 | + } | ||
167 | + dispatch({ | ||
168 | + type: SELECT_STANDARDFILTER_ITEM, | ||
169 | + payload: standardFilterList | ||
170 | + }) | ||
171 | + } | ||
172 | +} | ||
173 | + | ||
174 | +export function clearStandardFilter(item) { | ||
175 | + return (dispatch, getState) => { | ||
176 | + let {categoryProList} = getState(); | ||
177 | + let {standardFilterList} = categoryProList; | ||
178 | + standardFilterList = standardFilterList ? standardFilterList.toJS() : []; | ||
179 | + for (var i = 0; i < standardFilterList.length; i++) { | ||
180 | + let filterItem = standardFilterList[i]; | ||
181 | + if (filterItem.standard_id == item.standard_id) { | ||
182 | + filterItem.isSelect = false; | ||
183 | + filterItem.selectFilter = { | ||
184 | + standard_id: '', | ||
185 | + standard_name: '', | ||
186 | + }; | ||
187 | + break | ||
188 | + } | ||
189 | + } | ||
190 | + dispatch({ | ||
191 | + type: SELECT_STANDARDFILTER_ITEM, | ||
192 | + payload: standardFilterList | ||
193 | + }) | ||
194 | + } | ||
195 | +} |
1 | +'use strict'; | ||
2 | + | ||
3 | +import {Record, List, Map} from 'immutable'; | ||
4 | + | ||
5 | + | ||
6 | +let InitialState = Record({ | ||
7 | + similarIndex : -1, | ||
8 | + productList: new (Record({ | ||
9 | + isFetching: false, | ||
10 | + error: null, | ||
11 | + list: List(), | ||
12 | + order: '', | ||
13 | + currentPage: 0, | ||
14 | + pageCount: 0, | ||
15 | + pageSize: 60,//60, | ||
16 | + total: 0, | ||
17 | + endReached: false, | ||
18 | + sourceType: 0, // 0 - 默认,1 - 购,全球2 - 奥莱 | ||
19 | + })), | ||
20 | + categoryFilterList: List(), | ||
21 | + filterCategoryDetailFilterList: List(), | ||
22 | + standardFilterList: List(), | ||
23 | + filterFactors: new (Record({ | ||
24 | + gender: '', //性别 | ||
25 | + color: '', //颜色 | ||
26 | + price: '', //价格 | ||
27 | + sizeKey: '', //尺码 | ||
28 | + p_d: '', //折扣 | ||
29 | + sort: '', //品类 | ||
30 | + brand: '', //品牌 | ||
31 | + })), | ||
32 | + filterNameFactors: new (Record({ | ||
33 | + gender: '所有性别', //性别 | ||
34 | + color: '所有颜色', //颜色 | ||
35 | + price: '所有价格', //价格 | ||
36 | + sizeKey: '所有尺码', //尺码 | ||
37 | + p_d: '所有折扣', //折扣 | ||
38 | + sort: '所有品类', //品类 | ||
39 | + brand: '所有品牌', //品牌 | ||
40 | + })), | ||
41 | +}); | ||
42 | + | ||
43 | +export default InitialState; |
1 | +'use strict'; | ||
2 | + | ||
3 | +import InitialState from './categoryProListInitialState'; | ||
4 | +import Immutable, {Map} from 'immutable'; | ||
5 | + | ||
6 | +const { | ||
7 | + RESET_LIST_PAGE_INFO, | ||
8 | + SET_PRODUCT_LIST_FILTER, | ||
9 | + PRODUCT_LIST_REQUEST, | ||
10 | + PRODUCT_LIST_SUCCESS, | ||
11 | + PRODUCT_LIST_FAILURE, | ||
12 | + PRODUCT_FILTER_ACTION, | ||
13 | + SET_SIMILAR_PRODUCT_INDEX, | ||
14 | + SELECT_STANDARDFILTER_ITEM | ||
15 | +} = require('../../constants/actionTypes').default; | ||
16 | + | ||
17 | + | ||
18 | +const initialState = new InitialState; | ||
19 | + | ||
20 | +export default function categoryProListReducer(state=initialState, action) { | ||
21 | + switch(action.type) { | ||
22 | + case RESET_LIST_PAGE_INFO: { | ||
23 | + return state.setIn(['productList', 'currentPage'], 0) | ||
24 | + .setIn(['productList', 'pageCount'], 0) | ||
25 | + .setIn(['productList', 'total'], 0) | ||
26 | + .setIn(['productList', 'endReached'], false); | ||
27 | + } | ||
28 | + case SET_PRODUCT_LIST_FILTER: { | ||
29 | + return state.setIn(['productList', 'order'], action.payload); | ||
30 | + } | ||
31 | + case PRODUCT_LIST_REQUEST: { | ||
32 | + return state.setIn(['productList', 'isFetching'], true) | ||
33 | + .setIn(['productList', 'error'], null); | ||
34 | + } | ||
35 | + case PRODUCT_LIST_SUCCESS: { | ||
36 | + | ||
37 | + let { | ||
38 | + list, | ||
39 | + categoryFilterList, | ||
40 | + filterCategoryDetailFilterList, | ||
41 | + standard, | ||
42 | + currentPage, | ||
43 | + pageCount, | ||
44 | + total, | ||
45 | + recId, | ||
46 | + endReached, | ||
47 | + } = action.payload; | ||
48 | + | ||
49 | + let newState = state.setIn(['productList', 'isFetching'], false) | ||
50 | + .setIn(['productList', 'error'], null) | ||
51 | + .setIn(['productList', 'list'], Immutable.fromJS(list)) | ||
52 | + .setIn(['productList', 'currentPage'], currentPage) | ||
53 | + .setIn(['productList', 'pageCount'], pageCount) | ||
54 | + .setIn(['productList', 'total'], total) | ||
55 | + .setIn(['productList', 'endReached'], endReached); | ||
56 | + | ||
57 | + if (currentPage == 1 && state.categoryFilterList.size == 0 && state.filterCategoryDetailFilterList.size == 0) { | ||
58 | + newState = newState.set('categoryFilterList', Immutable.fromJS(categoryFilterList)) | ||
59 | + .set('filterCategoryDetailFilterList', Immutable.fromJS(filterCategoryDetailFilterList)); | ||
60 | + } | ||
61 | + | ||
62 | + if (currentPage == 1 && state.standardFilterList.size == 0) { | ||
63 | + newState = newState.set('standardFilterList', Immutable.fromJS(standard)); | ||
64 | + } | ||
65 | + return newState; | ||
66 | + } | ||
67 | + case PRODUCT_LIST_FAILURE: { | ||
68 | + return state.setIn(['productList', 'isFetching'], false) | ||
69 | + .setIn(['productList', 'error'], action.payload); | ||
70 | + } | ||
71 | + case PRODUCT_FILTER_ACTION: { | ||
72 | + return state.set('filterFactors', Immutable.fromJS(action.payload)); | ||
73 | + } | ||
74 | + case SET_SIMILAR_PRODUCT_INDEX: { | ||
75 | + return state.set('similarIndex', action.payload); | ||
76 | + } | ||
77 | + case SELECT_STANDARDFILTER_ITEM: { | ||
78 | + return state.set('standardFilterList', Immutable.fromJS(action.payload)); | ||
79 | + } | ||
80 | + } | ||
81 | + | ||
82 | + return state; | ||
83 | +} |
@@ -8,6 +8,8 @@ import productForBrand from './productListForBrand/productListForBrandReducer'; | @@ -8,6 +8,8 @@ import productForBrand from './productListForBrand/productListForBrandReducer'; | ||
8 | import productListForShop from './productListForShop/productListForShopReducer'; | 8 | import productListForShop from './productListForShop/productListForShopReducer'; |
9 | import productListPool from './productListPool/productListPoolReducer'; | 9 | import productListPool from './productListPool/productListPoolReducer'; |
10 | 10 | ||
11 | +import categoryProList from './categoryProList/categoryProListReducer'; | ||
12 | + | ||
11 | const rootReducer = combineReducers({ | 13 | const rootReducer = combineReducers({ |
12 | app, | 14 | app, |
13 | productForBrand, | 15 | productForBrand, |
@@ -16,6 +18,7 @@ const rootReducer = combineReducers({ | @@ -16,6 +18,7 @@ const rootReducer = combineReducers({ | ||
16 | screenSub, | 18 | screenSub, |
17 | productListForShop, | 19 | productListForShop, |
18 | productListPool, | 20 | productListPool, |
21 | + categoryProList, | ||
19 | }); | 22 | }); |
20 | 23 | ||
21 | export default rootReducer; | 24 | export default rootReducer; |
1 | +'use strict'; | ||
2 | + | ||
3 | +import Request from '../../common/services/Request'; | ||
4 | + | ||
5 | +export default class CategoryProListService { | ||
6 | + constructor(host) { | ||
7 | + let baseURL = 'http://api.yoho.cn'; | ||
8 | + if(host){ | ||
9 | + baseURL = host; | ||
10 | + } | ||
11 | + this.api = new Request(baseURL); | ||
12 | + } | ||
13 | + | ||
14 | + async productList(page=1, limit=60, originParams={}, filterFactors={}, order, firstProductSkn='') { | ||
15 | + | ||
16 | + return await this.api.get({ | ||
17 | + url: '', | ||
18 | + body: { | ||
19 | + method: 'app.search.category', | ||
20 | + page, | ||
21 | + limit, | ||
22 | + ...originParams, | ||
23 | + ...filterFactors, | ||
24 | + fromPage: 'iFP_CategoryProList', | ||
25 | + order, | ||
26 | + firstProductSkn | ||
27 | + } | ||
28 | + }) | ||
29 | + .then((json) => { | ||
30 | + return json; | ||
31 | + }) | ||
32 | + .catch((error) => { | ||
33 | + throw(error); | ||
34 | + }); | ||
35 | + } | ||
36 | +} |
@@ -262,10 +262,23 @@ function parseProductList(json) { | @@ -262,10 +262,23 @@ function parseProductList(json) { | ||
262 | } | 262 | } |
263 | 263 | ||
264 | let recId = randomString(40); | 264 | let recId = randomString(40); |
265 | + | ||
266 | + let standard = json && json.standard ? json.standard : []; | ||
267 | + | ||
268 | + for (var i = 0; i < standard.length; i++) { | ||
269 | + let standardItem = standard[i] | ||
270 | + standardItem.isSelect = false; | ||
271 | + standardItem.selectFilter = { | ||
272 | + standard_id: '', | ||
273 | + standard_name: '', | ||
274 | + } | ||
275 | + } | ||
276 | + | ||
265 | return { | 277 | return { |
266 | list, | 278 | list, |
267 | categoryFilterList, | 279 | categoryFilterList, |
268 | filterCategoryDetailFilterList, | 280 | filterCategoryDetailFilterList, |
281 | + standard, | ||
269 | currentPage, | 282 | currentPage, |
270 | pageCount, | 283 | pageCount, |
271 | total, | 284 | total, |
-
Please register or login to post a comment