Authored by 于良

新品到着优化 review by 孙凯

... ... @@ -18,6 +18,7 @@ import DeleteLineText from '../DeleteLineText';
import YH_Image from '../YH_Image';
import SimilarProductAnim from './SimilarProductAnim';
import SimilarProductGuider from './SimilarProductGuider';
import Immutable, {Map} from 'immutable';
export default class ProductListCell extends Component {
... ... @@ -29,6 +30,16 @@ export default class ProductListCell extends Component {
this._renderPrice = this._renderPrice.bind(this);
}
shouldComponentUpdate(nextProps){
if (Immutable.is(nextProps.data, this.props.data)
&& nextProps.similarIndex == this.props.similarIndex
&& nextProps.rowID == this.props.rowID) {
return false;
} else {
return true;
}
}
_renderTags() {
let {data, sourceType} = this.props;
let isGlobalProduct = data.get('is_global') && data.get('is_global') == 'Y'; // 是否全球购商品
... ... @@ -135,7 +146,7 @@ export default class ProductListCell extends Component {
render() {
let {data, sourceType, similarIndex, rowID, style} = this.props;
let name = data.get('product_name') ? data.get('product_name') : '';
let yh_exposureData = data.get('yh_exposureData') ? data.get('yh_exposureData') : null;
let yh_exposureData = data.get('yh_exposureData', null);
return (
<TouchableOpacity
... ...
'use strict';
import React, {Component} from 'react';
import ReactNative, {
View,
Text,
Image,
Platform,
ListView,
StyleSheet,
Dimensions,
TouchableOpacity,
} from 'react-native';
import SlicedImage from '../../../common/components/SlicedImage';
import FeaturedView from './FeaturedView';
export default class FeatureCell extends Component {
constructor(props) {
super(props);
this.renderSingleImage = this.renderSingleImage.bind(this);
this.renderTwoImage = this.renderTwoImage.bind(this);
this.renderCarouselImage = this.renderCarouselImage.bind(this);
this.images = [];
}
renderSingleImage() {
let item = this.props.data.get(0);
let yh_exposureData = item.get('yh_exposureData', null);
return (
<View style={{
width,
height: Platform.OS === 'ios'? featuredHigh + 50 : featuredHigh + 65,
marginBottom: 15,
alignItems: 'center',
}}>
<Text style={styles.headerText} >
精选抢先看
</Text>
<TouchableOpacity
yh_exposureData={yh_exposureData}
activeOpacity={0.8}
onPress={() => {
let url = item.get('url');
this.props.onPressCarouselItem&&this.props.onPressCarouselItem(url);
}}
>
<Image
style={styles.carouselSectionImage}
source={{uri: this.images[0]}}
resizeMode={'cover'}
/>
</TouchableOpacity>
<View style={styles.separator}/>
</View>
)
}
renderTwoImage() {
let item1 = this.props.data.get(0);
let item2 = this.props.data.get(1);
let yh_exposureData0 = item1.get('yh_exposureData', null);
let yh_exposureData1 = item2.get('yh_exposureData', null);
return (
<View style={{
width,
height: Platform.OS === 'ios'? (((width-48) / 2)*220)/330+58 : (((width-48) / 2)*220)/330+64,
}}>
<Text style={styles.headerText} >
精选抢先看
</Text>
<View style={{
width,
height: (((width-48) / 2)*220)/330,
flexDirection:'row',
marginLeft:8,
marginRight:8,
marginBottom:8,
}}>
<TouchableOpacity
activeOpacity={0.8}
yh_exposureData={yh_exposureData0}
onPress={() => {
let url = item1.get('url');
this.props.onPressCarouselItem&&this.props.onPressCarouselItem(url);
}}
>
<Image
style={styles.carouselSection2Image}
source={{uri: this.images[0]}}
resizeMode={'cover'}
/>
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.8}
yh_exposureData={yh_exposureData1}
onPress={() => {
let url = item2.get('url');
this.props.onPressCarouselItem&&this.props.onPressCarouselItem(url);
}}
>
<Image
style={styles.carouselSection2Image}
source={{uri: this.images[1]}}
resizeMode={'cover'}
/>
</TouchableOpacity>
</View>
<View style={styles.separator}/>
</View>
)
}
renderCarouselImage() {
let featurelist = this.props.data;
return (
<View style={{
width,
height: 181,
}}>
<FeaturedView
style={styles.carouselSection}
items={featurelist.toJS()}
onClick={(info) => {
if (!this.props.data) {
return;
}
let item = this.props.data.get(info.index);
if (!item) {
return;
}
let url = item.get('url');
this.props.onPressCarouselItem&&this.props.onPressCarouselItem(url);
}}
/>
<View style={styles.separator}/>
</View>
)
}
render() {
let {data} = this.props;
console.log(data.toJS())
for (var i = 0; i < data.size; i++) {
let src = data.get(i).get('src');
if (src) {
src = src.replace('{width}', width).replace('{height}', height).replace('{mode}',2);
this.images.push(src);
}
}
if (this.images.length == 1) {
return this.renderSingleImage();
} else if (this.images.length == 2) {
return this.renderTwoImage();
} else if (this.images.length > 2) {
return this.renderCarouselImage();
}
return null;
}
}
let {width, height} = Dimensions.get('window');
let featuredHight = Math.ceil(((width-30)*220)/690);
let styles = StyleSheet.create({
headerText: {
fontSize: 14,
color: 'black',
width: width,
textAlign: 'center',
marginTop:10,
marginBottom:10,
},
carouselSection: {
width,
height: 166,
},
carouselSectionImage:{
width:width-30,
height: featuredHight,
marginLeft:8,
marginRight:8,
marginBottom:8,
borderRadius:3,
},
carouselSection2Image:{
width:(width-48) / 2,
height: (((width-48) / 2)*220)/330,
flex:1,
marginLeft:8,
marginRight:8,
borderRadius:3,
},
separator: {
width: width,
height: 15,
backgroundColor: '#f0f0f0',
},
});
... ...
... ... @@ -16,15 +16,13 @@ import ReactNative, {
import LoadingIndicator from '../../../common/components/LoadingIndicator';
import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator';
import Immutable, {Map} from 'immutable';
import RecommendCell from './RecommendCell'
import BrandProductListCell from '../../../common/components/ListCell/ProductListCell';
import NewArrivalFilter from './NewArrivalFilter'
import NewArrivalCategoryList from './NewArrivalCategoryList'
import TagsCell from './TagsCell'
import ShopCell from './ShopCell'
import ArticleCell from './ArticleCell'
import FeaturedView from './FeaturedView'
import BannerCell from './BannerCell'
import NewArrivalHeader from './NewArrivalHeader';
export default class NewArrival extends Component {
... ... @@ -34,6 +32,7 @@ export default class NewArrival extends Component {
this._renderRow = this._renderRow.bind(this);
this._renderSectionHeader = this._renderSectionHeader.bind(this);
this._onPressProductFilter = this._onPressProductFilter.bind(this);
this._renderHeader = this._renderHeader.bind(this);
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => !Immutable.is(r1, r2),
... ... @@ -62,148 +61,25 @@ export default class NewArrival extends Component {
}
_renderHeader() {
let {
isFetching,
topPart,
} = this.props;
return (
<NewArrivalHeader
data={topPart}
onPressBanner={this.props.onPressBanner}
onPressShop={this.props.onPressShop}
goToRecommendForYou={this.props.goToRecommendForYou}
onPressCarouselItem={this.props.onPressCarouselItem}
/>
);
}
_renderRow(rowData, sectionID, rowID) {
switch (sectionID) {
case 'banner': {
return (
<View style={{width,height:132}}>
<BannerCell
style={styles.bannerImage}
width={width}
height={117}
data={rowData}
onPress={this.props.onPressBanner}
/>
<View style={styles.separator}/>
</View>
);
}
break;
case 'recommend': {
return (
<RecommendCell
data={rowData}
onPressShop={this.props.onPressShop}
goToRecommendForYou={this.props.goToRecommendForYou}
/>
)
}
break;
case 'featured': {
let data = [];
for (var i = 0; i < rowData.size; i++) {
let src = rowData.get(i).get('src');
if (src) {
src = src.replace('{width}', width).replace('{height}', height).replace('{mode}',2);
data.push(src);
}
}
let featurelist = rowData?rowData.toJS():[];
if(data.length==1){
let yh_exposureData = list[0].yh_exposureData;
return (
<View style={{
width,
height: Platform.OS === 'ios'? featuredHigh + 50 : featuredHigh + 65,
marginBottom: 15,
alignItems: 'center',
}}>
<Text style={styles.headerText} >
精选抢先看
</Text>
<TouchableOpacity
yh_exposureData={yh_exposureData}
activeOpacity={0.8}
onPress={() => {
let item = rowData.get(0);
let url = item.get('url');
this.props.onPressCarouselItem&&this.props.onPressCarouselItem(url);
}}
>
<Image
style={styles.carouselSectionImage}
source={{uri: data[0]}}
resizeMode={'cover'}
/>
</TouchableOpacity>
<View style={styles.separator}/>
</View>
)
}else if(data.length==2){
let yh_exposureData0 = list[0].yh_exposureData;
let yh_exposureData1 = list[1].yh_exposureData;
return (
<View style={{
width,
height: Platform.OS === 'ios'? (((width-48) / 2)*220)/330+58 : (((width-48) / 2)*220)/330+64,
}}>
<Text style={styles.headerText} >
精选抢先看
</Text>
<View style={{
width,
height: (((width-48) / 2)*220)/330,
flexDirection:'row',
marginLeft:8,
marginRight:8,
marginBottom:8,
}}>
<TouchableOpacity
activeOpacity={0.8}
yh_exposureData={yh_exposureData0}
onPress={() => {
let item = rowData.get(0);
let url = item.get('url');
this.props.onPressCarouselItem&&this.props.onPressCarouselItem(url);
}}
>
<Image
style={styles.carouselSection2Image}
source={{uri: data[0]}}
resizeMode={'cover'}
/>
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.8}
yh_exposureData={yh_exposureData1}
onPress={() => {
let item = rowData.get(1);
let url = item.get('url');
this.props.onPressCarouselItem&&this.props.onPressCarouselItem(url);
}}
>
<Image
style={styles.carouselSection2Image}
source={{uri: data[1]}}
resizeMode={'cover'}
/>
</TouchableOpacity>
</View>
<View style={styles.separator}/>
</View>
)
}else{
return (
<View style={{
width,
height: 181,
}}>
<FeaturedView
style={styles.carouselSection}
items={featurelist}
onClick={(info) => {
let item = rowData.get(info.index);
let url = item.get('url');
this.props.onPressCarouselItem&&this.props.onPressCarouselItem(url);
}}
/>
<View style={styles.separator}/>
</View>
)
}
}
break;
case 'latest': {
if (this.props.topPart.isFetching||!rowData) {
... ... @@ -322,18 +198,9 @@ export default class NewArrival extends Component {
recommendForYou,
} = this.props;
let banner = topPart.get('topList')&&topPart.get('topList').size?[topPart.get('topList')]:[];
let latest = productList.get('list')&&productList.get('list').size?productList.get('list').toArray():[0];
let recommend = [];
if (topPart.get('brandList')&&topPart.get('brandList').size) {
recommend = [topPart.get('brandList')];
}
let featured = topPart.get('featuredList')&&topPart.get('featuredList').size?[topPart.get('featuredList')]:[];
let dataSource = {
banner,
recommend,
featured,
latest,
}
let isLoadingMore = productList.isFetching && productList.currentPage > 0;
... ... @@ -351,6 +218,7 @@ export default class NewArrival extends Component {
renderRow={this._renderRow}
enableEmptySections={true}
renderSectionHeader={this._renderSectionHeader}
renderHeader={this._renderHeader}
renderFooter={()=>{
if (endReached) {
return <View style={styles.placeholder} />;
... ... @@ -376,7 +244,6 @@ export default class NewArrival extends Component {
this.setState({showBackToTopButton: true});
}
}}
onEndReachedThreshold={2000}
/>
{productList.isFilter ?
<NewArrivalCategoryList
... ... @@ -421,13 +288,12 @@ export default class NewArrival extends Component {
let {width, height} = Dimensions.get('window');
width = Math.ceil(width);
height = Math.ceil(height);
let bannerHeight = Math.ceil((363 / 750) * width);
let yPosition = 0;
let rowWidth = Math.ceil(137.5 * width / 320);
let rowHeight = Math.ceil(254 * width / 320);
let rowMarginTop = Math.ceil(10 * width / 320);
let rowMarginHorizontal = (width - rowWidth * 2) / 3;
let featuredHigh=Math.ceil(((width-30)*220)/690);
let styles = StyleSheet.create({
container: {
... ... @@ -435,16 +301,6 @@ let styles = StyleSheet.create({
width: width,
height: height - 64,
},
bannerImage: {
width: width,
height: 117,
backgroundColor: 'gray',
},
separator: {
width: width,
height: 15,
backgroundColor: '#f0f0f0',
},
placeholder: {
width,
height: 15,
... ... @@ -456,26 +312,6 @@ let styles = StyleSheet.create({
flexDirection: 'row',
flexWrap: 'wrap',
},
carouselSection: {
width,
height: 166,
},
carouselSectionImage:{
width:width-30,
height: featuredHigh,
marginLeft:8,
marginRight:8,
marginBottom:8,
borderRadius:3,
},
carouselSection2Image:{
width:(width-48) / 2,
height: (((width-48) / 2)*220)/330,
flex:1,
marginLeft:8,
marginRight:8,
borderRadius:3,
},
brandFilterContainer: {
marginLeft: -1,
width: width + 2,
... ... @@ -488,12 +324,4 @@ let styles = StyleSheet.create({
width: 44,
height: 44,
},
headerText: {
fontSize: 14,
color: 'black',
width: width,
textAlign: 'center',
marginTop:10,
marginBottom:10,
},
});
... ...
'use strict';
import React, {Component} from 'react';
import ReactNative, {
View,
Text,
Image,
Platform,
ListView,
StyleSheet,
Dimensions,
TouchableOpacity,
} from 'react-native';
import SlicedImage from '../../../common/components/SlicedImage';
import Immutable, {Map, List} from 'immutable';
import RecommendCell from './RecommendCell';
import BannerCell from './BannerCell';
import FeatureCell from './FeatureCell';
export default class NewArrivalHeader extends Component {
constructor(props) {
super(props);
this.renderBanner = this.renderBanner.bind(this);
this.renderRecommend = this.renderRecommend.bind(this);
this.renderFeature = this.renderFeature.bind(this);
}
shouldComponentUpdate(nextProps){
if (Immutable.is(nextProps.data, this.props.data)) {
return false;
} else {
return true;
}
}
renderBanner() {
let banner = this.props.data.get('topList', List());
if (banner && banner.size > 0) {
return (
<View style={{width,height:132}}>
<BannerCell
style={styles.bannerImage}
width={width}
height={117}
data={banner}
onPress={this.props.onPressBanner}
/>
<View style={styles.separator}/>
</View>
);
}
return null;
}
renderRecommend() {
let recommend = this.props.data.get('brandList', List());
if (recommend && recommend.size > 0) {
return (
<RecommendCell
data={recommend}
onPressShop={this.props.onPressShop}
goToRecommendForYou={this.props.goToRecommendForYou}
/>
);
}
return null;
}
renderFeature() {
let feature = this.props.data.get('featuredList', List());
if (feature && feature.size > 0) {
return (
<FeatureCell
data={feature}
onPressCarouselItem={this.props.onPressCarouselItem}
/>
);
}
return null;
}
render() {
let {data} = this.props;
let banner = data.get('topList', List());
let recommend = data.get('brandList', List());
let feature = data.get('featuredList', List());
let containerHeight = 0;
if (banner && banner.size > 0) {
containerHeight = containerHeight + 132;
}
if (recommend && recommend.size > 0) {
containerHeight = containerHeight + 180;
}
if (feature && feature.size > 0) {
let realHeight = 0;
if (feature.size = 1) {
realHeight = Platform.OS === 'ios'? featuredHight + 50 : featuredHight + 65;
}
if (feature.size = 2) {
realHeight = Platform.OS === 'ios'? (((width-48) / 2)*220)/330+58 : (((width-48) / 2)*220)/330+64;
}
if (feature.size > 2) {
realHeight = 181;
}
containerHeight = containerHeight + realHeight;
}
return (
<View style={[styles.container, {height: containerHeight}]}>
{this.renderBanner()}
{this.renderRecommend()}
{this.renderFeature()}
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let featuredHight = Math.ceil(((width-30)*220)/690);
let styles = StyleSheet.create({
container: {
backgroundColor: 'white',
},
bannerImage: {
width: width,
height: 117,
backgroundColor: 'gray',
},
separator: {
width: width,
height: 15,
backgroundColor: '#f0f0f0',
},
});
... ...
... ... @@ -117,6 +117,43 @@ export function getTopInfo() {
/**
数据曝光
*/
dispatch(topInfoExpose(newJson));
})
.catch(error => {
dispatch(topInfoFailure(error));
});
}
}
export function topInfoRequest() {
return {
type: RECOMMEND_SHOP_REQUEST,
};
}
export function topInfoSuccess(json) {
return {
type: RECOMMEND_SHOP_SUCCESS,
payload: json
}
}
export function topInfoFailure(error) {
return {
type: RECOMMEND_SHOP_FAILURE,
payload: error
}
}
function topInfoExpose(data) {
return (dispatch, getState) => {
try {
let {
first_part,
shop_list,
second_part,
} = data;
let logData = [];
let F_INDEX = 1;
if (first_part&&first_part.length) {
... ... @@ -184,32 +221,15 @@ export function getTopInfo() {
});
F_INDEX ++;
}
dispatch(newArrivalExposure(logData));
})
.catch(error => {
dispatch(topInfoFailure(error));
});
}
}
export function topInfoRequest() {
return {
type: RECOMMEND_SHOP_REQUEST,
};
}
export function topInfoSuccess(json) {
return {
type: RECOMMEND_SHOP_SUCCESS,
payload: json
}
}
let params = {
DATA: logData,
};
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_SHOW_NEW_ARRIVAL', params);
} catch (e) {
export function topInfoFailure(error) {
return {
type: RECOMMEND_SHOP_FAILURE,
payload: error
}
}
};
}
/*
... ... @@ -227,6 +247,9 @@ export function getProductList(reload=false) {
return;
}
}
dispatch(productListRequest());
let order = productList.order;
let page = productList.currentPage + 1;
let pageSize = productList.pageSize;
... ... @@ -245,13 +268,33 @@ export function getProductList(reload=false) {
}
}
}
dispatch(productListRequest());
return new NewArrivalService(app.host).fetchProductList(channel, order, page, pageSize, allFilterFactors)
.then(json => {
let payload = parseProductList(json,order,channel);
payload.endReached = payload.currentPage == payload.pageCount;
if (payload.currentPage > 1) {
let oldList = productList.list.toJS();
let list = [...oldList, ...payload.list];
payload.list = list;
}
dispatch(productListSuccess(payload));
dispatch(productListExpose(payload, productList, topPart, allFilterFactors));
})
.catch(error => {
dispatch(productListFailure(error));
});
};
}
function productListExpose(payload, productList, topPart, allFilterFactors) {
return (dispatch, getState) => {
try {
let LIST = [];
for (var i = 0; i < payload.list.length; i++) {
let length = payload.list.length;
for (var i = 0; i < length; i++) {
let item = payload.list[i]
let ListItem = {
I_INDEX: productList.list.size + i + 1,
... ... @@ -272,7 +315,8 @@ export function getProductList(reload=false) {
let CATE_ID = '';
if (item.recommend_type == 'seasonSort' && item.data.length) {
let tempAry = [];
for (var i = 0; i < item.data.length; i++) {
let itemLength = item.data.length;
for (var i = 0; i < itemLength; i++) {
let {categoryId} = item.data[i];
categoryId = categoryId.toString();
tempAry.push(categoryId);
... ... @@ -317,7 +361,7 @@ export function getProductList(reload=false) {
SORT_NM = '折扣';
}
let FILTER_VALUE = JSON.stringify(allFilterFactors);
let logData = [{
let data = [{
F_ID: 1004,
F_NM: '最新上架',
F_INDEX,
... ... @@ -325,28 +369,13 @@ export function getProductList(reload=false) {
FILTER_VALUE,
LIST,
}];
// console.log(logData);
dispatch(newArrivalExposure(logData));
if (payload.currentPage > 1) {
let oldList = productList.list.toJS();
let list = [...oldList, ...payload.list];
payload.list = list;
}
dispatch(productListSuccess(payload));
})
.catch(error => {
dispatch(productListFailure(error));
});
};
}
let params = {
DATA: data,
};
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_SHOW_NEW_ARRIVAL', params);
} catch(e) {
function newArrivalExposure(data) {
return (dispatch, getState) => {
let params = {
DATA: data,
};
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_SHOW_NEW_ARRIVAL', params);
}
};
}
... ... @@ -471,9 +500,20 @@ export function getRecommendBrand() {
let browseBrandList = json.browse_brand_list;
let hotBrandList = json.hot_brand_list;
let newBrandList = json.new_brand_list;
/**
数据曝光
*/
dispatch(recommendBrandSuccess({hotBrandList, browseBrandList, newBrandList}));
dispatch(recommendBrandExpose({hotBrandList, browseBrandList, newBrandList}))
})
.catch(error => {
dispatch(recommendBrandFailure(error));
});
};
}
function recommendBrandExpose(data) {
return (dispatch) => {
try {
let {hotBrandList, browseBrandList, newBrandList} = data;
let logData = [];
let F_INDEX = 1;
if (browseBrandList && browseBrandList.length) {
... ... @@ -554,12 +594,9 @@ export function getRecommendBrand() {
DATA: logData,
};
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_SHOW_NEW_ARRIVAL_RECOMMEND', params);
} catch(e) {
dispatch(recommendBrandSuccess({hotBrandList, browseBrandList, newBrandList}));
})
.catch(error => {
dispatch(recommendBrandFailure(error));
});
}
};
}
... ... @@ -601,6 +638,15 @@ function parseProductList(json,order,channel) {
let pageCount = json && json.page_total ? json.page_total : 0;
let total = json && json.total ? json.total : 0;
if (currentPage > 1) {
return {
list,
currentPage,
pageCount,
total,
};
}
let filter = json && json.filter ? json.filter : {};
let filterCategoryDetailFilterList = {};
let categoryFilterList = [];
... ...