Authored by 于良

Merge branch 'local' into develop

Showing 42 changed files with 583 additions and 78 deletions
... ... @@ -44,6 +44,7 @@ const styles = StyleSheet.create({
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
width: Dimensions.get('window').width,
height: 44,
},
indicator: {
... ...
... ... @@ -23,7 +23,7 @@ export default class SlicedImage extends React.Component {
width = PixelRatio.getPixelSizeForLayoutSize(width);
height = PixelRatio.getPixelSizeForLayoutSize(height);
let newSrc = src;
if (src.indexOf('imageView') === -1) {
if (src.indexOf('imageView') === -1 && src.indexOf('imageMogr') === -1) {
newSrc = src + '?imageView2/' + mode + '/w/' + width + '/h/' + height;
} else {
newSrc = src.replace('{mode}', mode)
... ...
... ... @@ -36,8 +36,7 @@ export default class ProductFilter extends React.Component {
asc: 's_n_desc',
desc: 's_n_desc',
},
isAsc: true,
selected: false,
isAsc: false,
radio: true,
},
{
... ... @@ -47,8 +46,7 @@ export default class ProductFilter extends React.Component {
asc: 's_t_desc',
desc: 's_t_desc',
},
isAsc: true,
selected: false,
isAsc: false,
radio: true,
},
{
... ... @@ -58,8 +56,7 @@ export default class ProductFilter extends React.Component {
asc: 's_p_asc',
desc: 's_p_desc',
},
isAsc: true,
selected: false,
isAsc: false,
radio: false,
},
{
... ... @@ -69,8 +66,7 @@ export default class ProductFilter extends React.Component {
asc: 'p_d_asc',
desc: 'p_d_desc',
},
isAsc: true,
selected: false,
isAsc: false,
radio: false,
},
],
... ... @@ -105,15 +101,22 @@ export default class ProductFilter extends React.Component {
let colorStyle = rowID == this.state.selectedIndex ? {color: '#444444'} : {color: '#b0b0b0'};
return (
<TouchableOpacity onPress={()=>{
<TouchableOpacity onPress={() => {
let filters = this.state.filters;
let filter = this.state.filters[rowID];
if (filter.radio && this.state.selectedIndex == rowID) {
return;
}
filter.isAsc = !filter.isAsc;
filters[rowID] = filter;
this.setState({
selectedIndex: rowID,
filters,
});
let value = filter.isAsc ? filter.value['asc'] : filter.value['desc'];
this.props.onPressFilter && this.props.onPressFilter(value);
}}>
<View key={'row' + rowID} style={styles.rowContainer}>
<Text style={[styles.name, colorStyle]}>{rowData.name}</Text>
... ... @@ -132,17 +135,18 @@ export default class ProductFilter extends React.Component {
render() {
let {} = this.props;
let {style} = this.props;
return (
<View style={styles.container}>
<View style={[styles.container, style]}>
<ListView
contentContainerStyle={styles.contentContainer}
contentContainerStyle={[styles.contentContainer, style]}
enableEmptySections={true}
dataSource={this.dataSource.cloneWithRows(this.state.filters)}
renderRow={this._renderRow}
renderSeparator={this._renderSeparator}
scrollEnabled={false}
scrollsToTop={false}
/>
</View>
);
... ... @@ -159,9 +163,9 @@ let styles = StyleSheet.create({
marginLeft: -1,
width: width + 2,
height: 37,
borderTopColor: 'transparent',
borderBottomColor: '#e5e5e5',
borderWidth: 0.5,
},
contentContainer: {
flexDirection: 'row',
... ... @@ -177,7 +181,8 @@ let styles = StyleSheet.create({
color: '#b0b0b0',
},
image: {
marginTop: 2,
marginLeft: 2,
},
separator: {
width: 0.5,
... ...
... ... @@ -12,8 +12,10 @@ import ReactNative, {
} from 'react-native';
import SlicedImage from '../../../common/components/SlicedImage';
import LoadingIndicator from '../../../common/components/LoadingIndicator';
import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator';
import ProductListCell from './ProductListCell';
import ProductFilter from './ProductFilter';
import ProductShopCell from './ProductShopCell';
export default class Search extends Component {
... ... @@ -29,27 +31,76 @@ export default class Search extends Component {
}
_renderRow(rowData, sectionID, rowID) {
switch (sectionID) {
case 'shop':
return (
<ProductShopCell
key={'row' + rowID}
data={rowData}
/>
);
case 'placeholder':
return (
<View style={styles.separator}/>
);
case 'filter':
return (
<ProductFilter
style={styles.filterContainer}
onPressFilter={this.props.onPressFilter}
/>
);
case 'list':
let paddingLeft = rowID % 2 == 1 ? rowMarginHorizontal / 2 : rowMarginHorizontal;
let customStyle = rowID == 0 || rowID == 1 ? {paddingLeft, marginTop: 0} : {paddingLeft};
return (
<ProductListCell
style={[styles.listContainer, customStyle]}
key={'row' + rowID}
rowID={rowID}
data={rowData}
/>
);
default:
return null;
}
return (
<ProductListCell
key={'row' + rowID}
rowID={rowID}
data={rowData}
/>
);
}
render() {
let {list} = this.props;
let {shop, list, isFetching, isLoadingMore, endReached} = this.props;
let dataSource = {
shop: shop.toArray(),
filter: ['filter'],
list: list.toArray(),
}
return (
<View style={styles.container}>
<ListView
contentContainerStyle={styles.contentContainer}
enableEmptySections={true}
dataSource={this.dataSource.cloneWithRows(list.toArray())}
dataSource={this.dataSource.cloneWithRowsAndSections(dataSource)}
renderRow={this._renderRow}
keyboardDismissMode={'on-drag'}
onEndReached={() => {
this.props.onEndReached && this.props.onEndReached();
}}
renderFooter={()=>{
if (endReached) {
return <LoadMoreIndicator
isVisible={true}
text={'暂无更多'}
/>
} else {
return <LoadMoreIndicator
isVisible={isLoadingMore}
animating={isFetching}
/>
}
}}
/>
</View>
... ... @@ -66,13 +117,21 @@ let rowMarginHorizontal = (width - rowWidth * 2) / 3;
let styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
contentContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
marginHorizontal: rowMarginHorizontal,
},
filterContainer: {
},
listContainer: {
width: width / 2,
},
separator: {
width,
height: 16,
backgroundColor: '#f0f0f0',
},
});
... ...
... ... @@ -12,7 +12,8 @@ import ReactNative, {
} from 'react-native';
import SlicedImage from '../../../common/components/SlicedImage';
import LoadingIndicator from '../../../common/components/LoadingIndicator';
import Tags from './Tags';
export default class Search extends Component {
... ... @@ -23,12 +24,29 @@ export default class Search extends Component {
render() {
let {rowID, data} = this.props;
let url = data.get('default_images').replace('{width}', rowWidth).replace('{height}', imageHeight);;
let {rowID, data, style} = this.props;
let url = data.get('default_images').replace('{width}', rowWidth).replace('{height}', imageHeight);
url = SlicedImage.getSlicedUrl(data.get('default_images'), 290, 386, 2);
return (
<View style={[styles.container]}>
<Image style={styles.image} source={{uri: url}}/>
<Text>{data.get('product_name')}</Text>
<View style={[styles.container, style]}>
<Tags/>
<View style={styles.imageContainer}>
<Image style={styles.image} source={{uri: url}}>
<Image style={styles.almostSoldOutImage} source={require('../../images/tag/tip_jjsq.png')}/>
<Image style={styles.soldOutImage} source={require('../../images/tag/outlet_sellout_bg.png')}/>
</Image>
</View>
<View style={styles.nameContainer}>
<Text style={styles.name} numberOfLines={2}>{data.get('product_name')}</Text>
</View>
<View style={styles.priceContainer}>
<Text style={styles.nowPrice} numberOfLines={1}>{'¥' + data.get('sales_price')}</Text>
<View style={styles.oldPriceContainer}>
<Text style={styles.oldPrice} numberOfLines={1}>{'¥' + data.get('market_price')}</Text>
<View style={styles.deleteLine}/>
</View>
</View>
</View>
);
}
... ... @@ -36,20 +54,26 @@ export default class Search extends Component {
let {width, height} = Dimensions.get('window');
const WIDTH_RATIO = width / 320;
let rowWidth = Math.ceil(137.5 * WIDTH_RATIO);
let rowHeight = Math.ceil(254 * WIDTH_RATIO);
let rowMarginTop = Math.ceil(10 * WIDTH_RATIO);
const DEVICE_WIDTH_RATIO = width / 320;
let rowWidth = Math.ceil(137.5 * DEVICE_WIDTH_RATIO);
let rowHeight = Math.ceil(254 * DEVICE_WIDTH_RATIO);
let rowMarginTop = Math.ceil(10 * DEVICE_WIDTH_RATIO);
const IMAGE_WIDTH = 145;
const IMAGE_HEIGHT = 193;
const IMAGE_RATIO = IMAGE_HEIGHT / IMAGE_WIDTH;
let imageTop = 14 * WIDTH_RATIO;
let imageTop = 14 * DEVICE_WIDTH_RATIO;
let imageHeight = rowWidth * IMAGE_RATIO;
let almostSoldOutImageHeight = Math.ceil(14 * DEVICE_WIDTH_RATIO);
let almostSoldOutImageTop = imageHeight - almostSoldOutImageHeight;
let nameMarginTop = Math.ceil(7 * DEVICE_WIDTH_RATIO);
let nameHeight = Math.ceil(36 * DEVICE_WIDTH_RATIO);
let styles = StyleSheet.create({
container: {
backgroundColor: 'gray',
// backgroundColor: 'gray',
width: rowWidth,
height: rowHeight,
marginTop: rowMarginTop,
... ... @@ -59,18 +83,70 @@ let styles = StyleSheet.create({
height: rowHeight,
},
imageContainer: {
width: rowWidth,
height: imageHeight,
backgroundColor: '#f0f0f0',
},
image: {
top: imageTop,
// top: imageTop,
width: rowWidth,
height: imageHeight,
backgroundColor: '#f0f0f0',
},
soldOutImage: {
position: 'absolute',
top: 0,
left: 0,
width: rowWidth,
height: imageHeight,
},
separator: {
height: 15,
almostSoldOutImage: {
top: almostSoldOutImageTop,
width: rowWidth,
height: almostSoldOutImageHeight,
backgroundColor: '#ff9e0d',
},
nameContainer: {
justifyContent: 'center',
marginTop: nameMarginTop,
width: rowWidth,
height: nameHeight,
// backgroundColor: 'red',
},
name: {
fontFamily: 'STHeitiSC-Light',
fontSize: 12,
color: '#444444',
},
priceContainer: {
flexDirection: 'row',
},
nowPrice: {
fontSize: 12,
color: '#d0021b',
},
oldPriceContainer: {
// flex: 1,
flexDirection: 'row',
marginLeft: 5,
// backgroundColor: 'red',
},
oldPrice: {
fontSize: 12,
color: '#b0b0b0',
height: 16,
},
line: {
marginHorizontal: 30,
top: 10 ,
height: 1,
backgroundColor: '#e5e5e5',
deleteLine: {
position: 'absolute',
// flex: 1,
top: (16 / 2) - 0.5,
left: 0,
right: 0,
// marginLeft: 0,
// marginRight: 0,
// width: 50,
height: 1,
backgroundColor: '#b0b0b0',
},
});
... ...
'use strict';
import React, {Component} from 'react';
import ReactNative, {
View,
Text,
Image,
StyleSheet,
Dimensions,
TouchableOpacity,
} from 'react-native';
import SlicedImage from '../../../common/components/SlicedImage';
export default class ProductShopCell extends Component {
constructor(props) {
super(props);
}
render() {
let {data} = this.props;
// 品牌
let icon = data.get('brand_ico');
let name = data.get('brand_name');
// 店铺
if (data.get('shops_type') == 2) {
icon = data.get('shop_logo');
name = data.get('shop_name');
}
return (
<View style={styles.container}>
<TouchableOpacity style={styles.content} onPress={() => {
this.props.onPressShop && this.props.onPressShop(data);
}}>
<View style={styles.content}>
<View style={styles.leftContainer}>
<SlicedImage style={styles.icon} source={{uri: icon}}/>
<Text style={styles.title}>{name}</Text>
</View>
<View style={styles.rightContainer}>
<Text style={styles.desc}>进入店铺</Text>
<Image style={styles.arrow} source={require('../../images/shared_next_icon.png')}/>
</View>
</View>
</TouchableOpacity>
<View style={styles.separator}/>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let styles = StyleSheet.create({
container: {
width: width,
height: 65,
},
content: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'flex-start',
justifyContent: 'space-between',
width: width,
height: 49,
},
leftContainer: {
flexDirection: 'row',
alignItems: 'center',
height: 49,
},
icon: {
marginLeft: 5,
width: 50,
height: 49,
resizeMode: 'contain',
},
title: {
marginLeft: 5,
width: 150,
fontSize: 15,
},
rightContainer: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'flex-end',
height: 49,
},
desc: {
marginRight: 10 ,
width: 50,
fontSize: 12,
color: '#b0b0b0',
},
arrow: {
right: 5,
width: 20,
height: 49,
resizeMode: 'contain',
},
separator: {
position: 'absolute',
left: 0,
top: 49,
width,
height: 16,
backgroundColor: '#f0f0f0',
},
});
... ...
... ... @@ -25,7 +25,6 @@ export default class SearchResult extends React.Component {
return (
<View style={styles.container}>
<ProductFilter/>
<ProductList
list={list}
/>
... ...
'use strict';
import React from 'react';
import ReactNative from 'react-native';
const {
View,
Image,
Text,
ListView,
Dimensions,
StyleSheet,
} = ReactNative;
export default class Tags extends React.Component {
constructor(props) {
super (props);
this.config = {
is_discount: {
image: require('../../images/tag/tip_sale.png'),
width: 30,
}, // YH_ProductTagTypeSale
resale: {
image: require('../../images/tag/tip_zdz.png'),
width: 45,
}, // YH_ProductTagTypeReSale
'mid-year': {
image: require('../../images/tag/tip_nzrc.png'),
width: 45,
}, // YH_ProductTagTypeSaleMiddle
'year-end': {
image: require('../../images/tag/tip_nzdc.png'),
width: 45,
}, // YH_ProductTagTypeSaleHot
is_new: {
image: require('../../images/tag/tip_new.png'),
width: 30,
}, // YH_ProductTagTypeNew
is_yohood: {
image: require('../../images/tag/tip_xpj.png'),
width: 45,
}, // YH_ProductTagTypeYohood
is_limited: {
image: require('../../images/tag/tip_xl_product.png'),
width: 30,
}, // YH_ProductTagTypeLimited
is_in_stock: {
image: require('../../images/tag/tip_gnzf.png'),
width: 45,
}, // YH_ProductTagTypeInland
is_deposit_advance: {
image: require('../../images/tag/tip_advance.png'),
width: 30,
}, // YH_ProductTagTypeDeposit
default: {
image: '',
width: 45,
},
};
this._renderRow = this._renderRow.bind(this);
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 != r2,
});
}
_renderRow(rowData, sectionID, rowID) {
let item = this.config[rowData];
if (!item) {
return null;
}
let width = Math.ceil(item.width * DEVICE_WIDTH_RATIO);
let marginLeft = rowID == 0 ? 0 : 2;
let iconStyle = {width, height: tagHeight, marginLeft};
return (
<Image style={[styles.icon, iconStyle]} source={item.image}/>
);
}
render() {
let {style} = this.props;
let tags = ['is_discount', 'resale', ];
return (
<View style={[styles.container]}>
<ListView
style={[styles.container]}
contentContainerStyle={[styles.contentContainer]}
enableEmptySections={true}
dataSource={this.dataSource.cloneWithRows(tags)}
renderRow={this._renderRow}
scrollEnabled={false}
scrollsToTop={false}
horizontal={true}
showsHorizontalScrollIndicator={false}
/>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
const DEVICE_WIDTH_RATIO = width / 320;
let tagHeight = Math.ceil(14 * DEVICE_WIDTH_RATIO);
let styles = StyleSheet.create({
container: {
},
contentContainer: {
height: tagHeight,
},
icon: {
resizeMode: 'contain',
},
});
... ...
... ... @@ -7,11 +7,14 @@ export default keyMirror({
SET_KEYWORD: null,
SET_SEARCH_STATUS: null,
SET_FILTER: null,
SEARCH_REQUEST: null,
SEARCH_SUCCESS: null,
SEARCH_FAILURE: null,
RESET_LIST_PAGE_INFO: null,
JUMP_URL_REQUEST: null,
JUMP_URL_SUCCESS: null,
JUMP_URL_FAILURE: null,
... ...
... ... @@ -18,6 +18,8 @@ import * as searchActions from '../reducers/search/searchActions';
import SearchKeyword from '../components/search/SearchKeyword';
import FuzzySearch from '../components/search/FuzzySearch';
import SearchResult from '../components/search/SearchResult';
import ProductList from '../components/search/ProductList';
import LoadingIndicator from '../../common/components/LoadingIndicator';
const actions = [
searchActions,
... ... @@ -48,6 +50,8 @@ class SearchContainer extends Component {
this._onPressKeyword = this._onPressKeyword.bind(this);
this._onPressClearHistory = this._onPressClearHistory.bind(this);
this._onPressFilter = this._onPressFilter.bind(this);
this._onEndReached = this._onEndReached.bind(this);
this.subscription = NativeAppEventEmitter.addListener(
"SearchKeywordDidChangeEvent",
... ... @@ -59,6 +63,7 @@ class SearchContainer extends Component {
this.subscription2 = NativeAppEventEmitter.addListener(
"SearchButtonDidClickEvent",
(event) => {
this.props.actions.resetListPageInfo();
this.props.actions.searchButtonPressed(event.keyword);
}
);
... ... @@ -76,6 +81,7 @@ class SearchContainer extends Component {
}
_onPressKeyword(keyword) {
this.props.actions.resetListPageInfo();
this.props.actions.searchButtonPressed(keyword);
}
... ... @@ -83,29 +89,47 @@ class SearchContainer extends Component {
this.props.actions.clearSearchHistory();
}
_onPressFilter(value) {
this.props.actions.resetListPageInfo();
this.props.actions.setFilter(value);
this.props.actions.searchProductList(this.props.search.keyword, true);
}
_onEndReached() {
this.props.actions.searchProductList(this.props.search.keyword);
}
_renderSearch() {
let {status, keyword, placeholder, searchHistory, hotKeyword, fuzzySearch, productList} = this.props.search;
let {status, keyword, placeholder, searchHistory, hotKeyword, fuzzySearch, jumpUrl, productList} = this.props.search;
if (status == 0) {
return (
<SearchKeyword
history={searchHistory.list}
hot={hotKeyword.list}
onPressKeyword={this._onPressKeyword}
onPressClearHistory={this._onPressClearHistory}
history={searchHistory.list}
hot={hotKeyword.list}
onPressKeyword={this._onPressKeyword}
onPressClearHistory={this._onPressClearHistory}
/>
);
} else if (status == 1) {
return (
<FuzzySearch
list={fuzzySearch.list}
onPressKeyword={this._onPressKeyword}
list={fuzzySearch.list}
onPressKeyword={this._onPressKeyword}
/>
);
} else if (status == 2) {
console.log('currentPage: ' + productList.currentPage)
console.log('isFetching: ' + productList.isFetching)
let isLoadingMore = productList.isFetching && productList.currentPage > 0;
return (
<SearchResult
list={productList.list}
<ProductList
shop={productList.shopOrBrand}
list={productList.list}
isFetching={productList.isFetching}
isLoadingMore={isLoadingMore}
endReached={productList.endReached}
onPressFilter={this._onPressFilter}
onEndReached={this._onEndReached}
/>
);
}
... ... @@ -114,9 +138,15 @@ class SearchContainer extends Component {
}
render() {
let {jumpUrl, productList} = this.props.search;
let showLoading = jumpUrl.isFetching || (productList.isFetching && productList.currentPage == 0);
return (
<View style={styles.container}>
{this._renderSearch()}
<LoadingIndicator
isVisible={showLoading}
/>
</View>
);
}
... ...
... ... @@ -6,9 +6,11 @@ import SearchService from '../../services/SearchService';
const {
SET_KEYWORD,
SET_SEARCH_STATUS,
SET_FILTER,
SEARCH_REQUEST,
SEARCH_SUCCESS,
SEARCH_FAILURE,
RESET_LIST_PAGE_INFO,
JUMP_URL_REQUEST,
JUMP_URL_SUCCESS,
JUMP_URL_FAILURE,
... ... @@ -31,6 +33,7 @@ const {
export function searchKeywordChanged(keyword) {
return (dispatch, getState) => {
console.log(keyword)
let status = 0;
if (keyword) {
status = 1;
... ... @@ -49,16 +52,13 @@ export function searchButtonPressed(keyword) {
if (!keyword) {
let {app, search} = getState();
keyword = search.placeholder
dispatch(setKeyword(keyword));
}
dispatch(setKeyword(keyword));
dispatch(insertSearchHistory(keyword));
ReactNative.NativeModules.YH_SearchHelper.setSearchKeyword(keyword);
ReactNative.NativeModules.YH_SearchHelper.resignSearchBar();
// let status = 2;
// dispatch(setSearchStatus(status));
dispatch(jumpUrl(keyword));
};
}
... ... @@ -77,6 +77,19 @@ export function setSearchStatus(status) {
};
}
export function setFilter(value) {
return {
type: SET_FILTER,
payload: value
};
}
export function resetListPageInfo() {
return {
type: RESET_LIST_PAGE_INFO,
}
}
export function searchRequest() {
return {
type: SEARCH_REQUEST,
... ... @@ -97,29 +110,45 @@ export function searchFailure(error) {
};
}
export function searchProductList(keyword, uid, sourcePage) {
export function searchProductList(keyword, reload=false) {
return (dispatch, getState) => {
let {app, search} = getState();
// if (search.productList.isFetching) {
// return;
// }
let {productList} = search;
if (reload) {
} else {
if (productList.isFetching || productList.endReached || productList.error) {
return;
}
}
let fetchList = (keyword, order, uid, page, sourcePage) => {
let fetchList = (keyword, order, uid, page, pageSize, sourcePage) => {
dispatch(searchRequest());
return new SearchService(app.host).searchProductList(keyword, order, uid, page, sourcePage)
return new SearchService(app.host).searchProductList(keyword, order, uid, page, pageSize, sourcePage)
.then(json => {
let payload = parseProductList(json);
payload.endReached = payload.currentPage == payload.pageCount;
if (productList.currentPage > 1) {
let oldList = productList.list.toJS();
let list = [...oldList, ...payload.list];
payload.list = list;
}
dispatch(setSearchStatus(2));
dispatch(searchSuccess(json.product_list));
dispatch(searchSuccess(payload));
})
.catch(error => {
dispatch(searchFailure(error));
});
}
let uid = 0;
let sourcePage = '';
let order = 's_n_desc';
let page = 1;
let order = productList.filter;
let page = productList.currentPage + 1;
let pageSize = productList.pageSize;
ReactNative.NativeModules.YH_CommonHelper.sourcePage('YH_SearchProListVC')
.then(data => {
sourcePage = data;
... ... @@ -127,14 +156,43 @@ export function searchProductList(keyword, uid, sourcePage) {
})
.then(data => {
uid = data;
fetchList(keyword, order, uid, page, sourcePage);
fetchList(keyword, order, uid, page, pageSize, sourcePage);
})
.catch(error => {
fetchList(keyword, order, uid, page, sourcePage);
fetchList(keyword, order, uid, page, pageSize, sourcePage);
});
}
}
function parseProductList(json) {
let currentPage = json && json.page ? json.page : 1;
let pageCount = json && json.page_total ? json.page_total : 0;
let total = json && json.total ? json.total : 0;
let shopOrBrand = [];
if (currentPage == 1) {
shopOrBrand = json && json.shop ? json.shop : [];
if (!shopOrBrand || shopOrBrand.length == 0) {
let brand = json && json.brand;
if (brand) {
shopOrBrand.push(brand);
}
}
}
shopOrBrand = shopOrBrand ? shopOrBrand : [];
let list = json && json.product_list ? json.product_list : [];
return {
list,
shopOrBrand,
currentPage,
pageCount,
total,
};
}
export function jumpUrlRequest() {
return {
type: JUMP_URL_REQUEST,
... ... @@ -172,12 +230,12 @@ export function jumpUrl(keyword) {
if (jumpUrl) {
ReactNative.NativeModules.YH_CommonHelper.jumpWithUrl(jumpUrl);
} else {
dispatch(searchProductList(keyword, uid, sourcePage));
dispatch(searchProductList(keyword, true));
}
})
.catch(error => {
dispatch(jumpUrlFailure(error));
dispatch(searchProductList(keyword, uid, sourcePage));
dispatch(searchProductList(keyword, true));
});
}
... ...
... ... @@ -28,6 +28,12 @@ let InitialState = Record({
isFetching: false,
error: null,
list: List(),
shopOrBrand: List(),
filter: 's_n_desc',
currentPage: 0,
pageCount: 0,
pageSize: 6,//60,
total: 0,
endReached: false,
})),
});
... ...
... ... @@ -6,9 +6,11 @@ import Immutable, {Map} from 'immutable';
const {
SET_KEYWORD,
SET_SEARCH_STATUS,
SET_FILTER,
SEARCH_REQUEST,
SEARCH_SUCCESS,
SEARCH_FAILURE,
RESET_LIST_PAGE_INFO,
JUMP_URL_REQUEST,
JUMP_URL_SUCCESS,
JUMP_URL_FAILURE,
... ... @@ -41,15 +43,44 @@ export default function searchReducer(state=initialState, action) {
return state.set('status', action.payload);
}
case SET_FILTER: {
return state.setIn(['productList', 'filter'], action.payload);
}
case RESET_LIST_PAGE_INFO: {
return state.setIn(['productList', 'currentPage'], 0)
.setIn(['productList', 'pageCount'], 0)
.setIn(['productList', 'total'], 0)
.setIn(['productList', 'endReached'], false);
}
case SEARCH_REQUEST: {
return state.setIn(['productList', 'isFetching'], true)
.setIn(['productList', 'error'], null);
}
case SEARCH_SUCCESS: {
return state.setIn(['productList', 'isFetching'], false)
let {
list,
shopOrBrand,
currentPage,
pageCount,
total,
endReached,
} = action.payload;
let newState = state.setIn(['productList', 'isFetching'], false)
.setIn(['productList', 'error'], null)
.setIn(['productList', 'list'], Immutable.fromJS(action.payload));
.setIn(['productList', 'list'], Immutable.fromJS(list))
.setIn(['productList', 'currentPage'], currentPage)
.setIn(['productList', 'pageCount'], pageCount)
.setIn(['productList', 'total'], total)
.setIn(['productList', 'endReached'], endReached);
if (currentPage == 1) {
newState = newState.setIn(['productList', 'shopOrBrand'], Immutable.fromJS(shopOrBrand));
}
return newState;
}
case SEARCH_FAILURE: {
... ...
... ... @@ -63,12 +63,13 @@ export default class SearchService {
});
}
async searchProductList(query='', order='s_n_desc', uid=0, page=1, fromPage='', limit=60, v=7) {
async searchProductList(query='', order='s_n_desc', uid=0, page=1, limit=60, fromPage='', v=7) {
return await this.api.get({
url: '',
body: {
method: 'app.search.li',
query,
order,
uid,
page,
limit,
... ...