Authored by 郁健超

有货有赚新增商品轮播楼层 reviewed by hy

... ... @@ -7,6 +7,7 @@ import ListView from 'deprecated-react-native-listview'
import {Immutable, default as Immutables} from 'immutable';
import GuideModal from "./GuideModal";
import Focus from './floor/Focus';
import ProductFocus from './floor/ProductFocus';
import SingleImage from './floor/SingleImage';
import ImageFour from "./cell/ImageFour";
import ImageTwo from "./cell/ImageTwo";
... ... @@ -130,7 +131,11 @@ export default class Home extends Component {
}
_floorCellRender(rowData, rowID) {
let {
floorProductInfo
} = this.props;
let floorProductInfoData = floorProductInfo && floorProductInfo ? floorProductInfo.toJS() : {}
let floorProductInfoList = floorProductInfoData && floorProductInfoData.resourceProductList;
if (!rowData || !rowData.get('data')) {
return null;
}
... ... @@ -183,6 +188,21 @@ export default class Home extends Component {
/>
)
}
case 'pusherGoodsRoll': {
if (!floorProductInfoList || floorProductInfoList.length == 0) {
return null;
}else {
return (
<ProductFocus
data={floorProductInfoList}
floorData={rowData.get('data')}
jumpWithUrl={this.props.jumpWithUrl}
onPressProduct={this.props.onPressProduct}
/>
);
}
}
default:
return null;
}
... ...
/**
* HomeBanner.js
*@author Alex
*@createtime 2020/6/3
*@description product banner images for allicance home page
*/
import React from 'react'
import {
Text,
View,
StyleSheet,
TouchableOpacity,
NativeModules,
DeviceEventEmitter,
FlatList,
Dimensions
} from 'react-native'
const IS_IOS = Platform.OS == 'ios' ? true : false
import SingleFocusProduct from './SingleFocusProduct';
export const DEVICE_WIDTH = Dimensions.get('window').width;
const {UIManager} = NativeModules
UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true);
export default class ProductFocus extends React.Component {
constructor(props) {
super(props)
this.pageControl = null;
try {
this.isTouching = false;
this.alreadyRendered = false;
this.scrollingRight = true;
let _total = props.data && props.data.length || 0;
this._total = _total;
let _data = props.data;
if (_total > 1) {
let tail = [_data[_total - 2], _data[_total - 1]];
let head = [_data[0], _data[1]];
_data = tail.concat(_data, head);
}
this.state = {
scrollEnabled: _total > 1 ? true : false,
contentOffset: {y: 0, x: _total > 1 ? 2 * (DEVICE_WIDTH-30) : 0},
currentPage: 0,
data: _data
}
this.lastx = _total > 1 ? 2 * (DEVICE_WIDTH-30) : 0;
} catch (e) {
}
}
componentWillReceiveProps(nextProps) {
try {
if (this.props.data && nextProps.data && !_.isEqual(this.props.data, nextProps.data)) {
this.stopAutoScroll();
let _total = nextProps.data && nextProps.data.length || 0;
this._total = _total;
let _data = nextProps.data;
if (_total > 1) {
let tail = [_data[_total - 2], _data[_total - 1]];
let head = [_data[0], _data[1]];
_data = tail.concat(_data, head);
} else {
this.setState({scrollEnabled: false});
}
this.setState({data: _data});
}
} catch (e) {
}
}
componentDidMount() {
this.subscription = DeviceEventEmitter.addListener('startAutoScroll', () => this.startAutoScroll('startAutoScroll'));
this.subscription1 = DeviceEventEmitter.addListener('stopAutoScroll', () => this.stopAutoScroll('stopAutoScroll'));
}
componentDidUpdate(prevProps, prevState) {
try {
if (this.props.data && prevProps.data && !_.isEqual(this.props.data, prevProps.data)) {
this.setState({contentOffset: {y: 0, x: this._total > 1 ? 2 * (DEVICE_WIDTH-30) : 0}});
this.startAutoScroll('componentDidUpdate');
}
} catch (e) {
}
}
componentWillUnmount() {
this.subscription && this.subscription.remove();
this.subscription1 && this.subscription1.remove();
this.stopAutoScroll()
}
startAutoScroll = (fromEvent) => {
let floorData = this.props.floorData.toJS();
let timeout = Number(floorData.speed) && Number(floorData.speed)>500?Number(floorData.speed):2500;
let _data = this.state.data || this.props.data || [];
this.stopAutoScroll()
this.bannerInterval = setInterval(() => {
let interval = DEVICE_WIDTH-30; // WIDTH OF 1 CHILD COMPONENT
let index = this.lastx / interval;
let floor = Math.floor(index);
let decimal = index - floor;
if (decimal < 0.001 || decimal > 0.999) {
index = Math.round(index);
}
let snapTo = this.lastx ? Math.ceil(index) + 1 : 1;
let maxLength = _data.length;
if (snapTo < maxLength && snapTo >= 0) {
this.snapScroll && this.snapScroll.scrollToIndex({index:snapTo, animated: true, viewPosition: 0});
} else {
this.snapScroll && this.snapScroll.scrollToIndex({index:0, animated: true, viewPosition: 0});
}
if (snapTo > 1+this._total) {
this.setState({
currentPage: 0
})
}else {
this.setState({
currentPage: snapTo-2
})
}
}, timeout)
}
stopAutoScroll = () => {
clearInterval(this.bannerInterval)
}
renderItem = (item) => {
let rowData = item.item
return (
<View style={styles.productRow}>
{rowData.map((unit) => {
return (
<SingleFocusProduct
data={unit}
onPressProduct={this.props.onPressProduct}
/>
)
})}
</View>
)
}
_onMomentumScrollEnd = e => {
try {
if (IS_IOS) {
let { x } = e.nativeEvent.contentOffset;
let index = x / (DEVICE_WIDTH-30);
if (Number.isInteger(index) && this._total > 1) {
if (index > 1 + this._total) {
this.stopAutoScroll();
this.snapScroll.scrollToIndex({index:(index - this._total), animated: false, viewPosition: 0});
this.startAutoScroll('_onMomentumScrollEnd');
} else if (index < 2) {
this.stopAutoScroll();
this.snapScroll.scrollToIndex({index:(index + this._total), animated: false, viewPosition: 0});
this.startAutoScroll('_onMomentumScrollEnd');
}
if (!this.state.scrollEnabled) {
this.setState({scrollEnabled: true});
}
}
}
} catch (error) {
}
}
_onLayout = e => {
try {
if (!this.alreadyRendered && this._total > 1) {
this.snapScroll.scrollToIndex({index: 2, animated: false, viewPosition: 0});
this.alreadyRendered = true;
}
this.startAutoScroll('_onLayout');
} catch (error) {
}
}
render() {
let floorData = this.props.floorData.toJS();
return (
<View style={[this.props.style, styles.container]} >
<View style={styles.headerContainer}>
<Text style={styles.textNormal}>{floorData.title?floorData.title:'推手精选'}</Text>
<View style={styles.indexContainer}>
<Text style={styles.textNormal}>{this.state.currentPage+1}</Text>
<Text style={styles.textSmall}>{'/'+this._total}</Text>
</View>
</View>
<FlatList
ref={(ref)=>{
this.snapScroll = ref;
}}
style={{flex: 1}}
contentOffset={this.state.contentOffset}
onLayout={this._onLayout}
renderItem={this.renderItem}
horizontal={true}
showsHorizontalScrollIndicator={false}
yh_viewVisible={true}
data={this.state.data || this.props.data}
decelerationRate={0}
onScrollBeginDrag = {()=> {
this.isTouching = true;
this.stopAutoScroll()
}}
keyExtractor={(item, index) => '' + index}
scrollEnabled={this.state.scrollEnabled}
onScrollEndDrag = {() => {
this.isTouching = false;
let _data = this.state.data || this.props.data || [];
var interval = DEVICE_WIDTH-30;
var snapTo = (this.scrollingRight)? Math.ceil(this.lastx / interval) :
Math.floor(this.lastx / interval);
let maxLength = _data.length;
if (snapTo < maxLength && snapTo >= 0) {
this.snapScroll.scrollToIndex({index:snapTo, animated: true, viewPosition: 0});
}
if (snapTo > 1 + this._total) {
this.setState({
currentPage: (snapTo - this._total-2)
})
}else if (snapTo < 2) {
this.setState({
currentPage: (snapTo + this._total-2)
})
}else {
this.setState({
currentPage: (snapTo - 2)
})
}
if (snapTo < 1 || snapTo > this._total + 2) {
this.setState({scrollEnabled: false});
}
this.startAutoScroll('onScrollEndDrag');
}}
onScroll={(event)=>{
var nextx = event.nativeEvent.contentOffset.x;
if (!IS_IOS || this.alreadyScrolled) {
this.scrollingRight = (nextx > this.lastx);
this.lastx = nextx;
}
try {
if (!IS_IOS && !this.isTouching) {
let { x } = event.nativeEvent.contentOffset;
let index = x / (DEVICE_WIDTH-30);
let floor = Math.floor(index);
let decimal = index - floor;
if (decimal < 0.001 || decimal > 0.999) {
index = Math.round(index);
}
if (Number.isInteger(index) && this._total > 1) {
if (this.lastIndex == index) return;
this.lastIndex = index;
if (index > 1 + this._total) {
this.stopAutoScroll();
this.snapScroll.scrollToIndex({index:(index-this._total), animated: false, viewPosition: 0});
this.lastx = (DEVICE_WIDTH-30) * (index - this._total);
this.startAutoScroll('onScroll');
} else if (index < 2) {
this.stopAutoScroll();
this.snapScroll.scrollToIndex({index:(index + this._total), animated: false, viewPosition: 0});
this.lastx = (DEVICE_WIDTH-30) * (index + this._total);
this.startAutoScroll('onScroll');
}
if (!this.state.scrollEnabled) {
this.setState({scrollEnabled: true});
}
}
}
if (!IS_IOS && (nextx < 5 || nextx > (this._total + 3) * (DEVICE_WIDTH-30) - 5)) {
this.setState({scrollEnabled: false});
this.isTouching = false;
}
if (IS_IOS && !this.alreadyScrolled) {
this.alreadyScrolled = true;
return
}
if (IS_IOS && (nextx < (DEVICE_WIDTH-30) || nextx > (this._total + 2) * (DEVICE_WIDTH-30))) {
this.setState({scrollEnabled: false});
}
} catch (e) {
}
}}
onMomentumScrollEnd={this._onMomentumScrollEnd}
/>
</View>
)
}
}
let {width} = Dimensions.get('window');
const DEVICE_WIDTH_RATIO = width / 375;
let styles = StyleSheet.create({
container: {
width: DEVICE_WIDTH-30,
height: 250*DEVICE_WIDTH_RATIO,
flexDirection: 'column',
marginLeft:15,
marginRight:15,
},
headerContainer: {
height: 40,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
},
indexContainer: {
flexDirection: 'row',
alignItems: 'center'
},
textNormal: {
fontSize: 16,
color: '#222222',
fontFamily: 'PingFang-SC-Medium',
},
textSmall: {
fontSize: 12,
color: '#222222',
fontFamily: 'PingFang-SC-Medium',
},
itemImg : {
width: DEVICE_WIDTH - 40,
height: 210,
marginHorizontal: 5,
overflow: 'hidden',
},
pageControl: {
bottom: 6,
width: DEVICE_WIDTH,
height: 11,
position: 'absolute',
},
productRow:{
width: DEVICE_WIDTH-30,
flexDirection: 'row',
justifyContent: 'space-between',
}
})
\ No newline at end of file
... ...
'use strict';
import React from 'react';
import ReactNative, {StyleSheet,View,TouchableOpacity,Text,Image} from 'react-native';
import Immutable from 'immutable';
import YH_Image from '../../../common/components/YH_Image';
const {Dimensions} = ReactNative;
export default class SingleFocusProduct extends React.Component {
constructor(props) {
super(props);
}
shouldComponentUpdate(nextProps) {
if (Immutable.is(nextProps.data, this.props.data)) {
return false;
} else {
return true;
}
}
render() {
let {data} = this.props;
let prdImage = YH_Image.getSlicedUrl(data.default_images, 107, 142, 2);
return (
<View style={styles.container}>
<TouchableOpacity activeOpacity={1} style={styles.prdImage} onPress={() => {
this.props.onPressProduct && this.props.onPressProduct(Immutable.fromJS(data),null);
}}>
<YH_Image style={styles.prdImage} url={prdImage}/>
</TouchableOpacity>
<Text style={styles.nowPrice} numberOfLines={1}>¥{data.sales_price || '-'}</Text>
<View style={styles.priceReturnContainer}>
<Image source={require('../../images/money_back.png')} />
<Text style={styles.returnPrice} numberOfLines={1}>¥{data.rebates_amount || '-'}</Text>
</View>
</View>
)
}
}
let {width} = Dimensions.get('window');
const DEVICE_WIDTH_RATIO = width / 375;
let styles = StyleSheet.create({
container: {
height: 210*DEVICE_WIDTH_RATIO,
width: 107*DEVICE_WIDTH_RATIO,
flexDirection: 'column',
},
prdImage: {
width: 107*DEVICE_WIDTH_RATIO,
height: 142*DEVICE_WIDTH_RATIO
},
nowPrice: {
fontSize: 12,
color: '#222222',
fontFamily: 'PingFang-SC-Regular',
marginTop: 10*DEVICE_WIDTH_RATIO,
},
priceReturnContainer: {
flexDirection: 'row',
marginTop: 10*DEVICE_WIDTH_RATIO,
},
returnPrice: {
fontSize: 16,
color: '#d0021b',
marginLeft: 3,
fontWeight: 'bold',
}
})
\ No newline at end of file
... ...
... ... @@ -197,4 +197,7 @@ export default keyMirror({
GET_LOCATION_REQUEST: null,
GET_LOCATION_SUCCESS: null,
GET_LOCATION_FAILURE: null,
GET_GOODSROLLFLOOR_PRODUCTLIST_SUCCESS: null,
GET_GOODSROLLFLOOR_PRODUCTLIST_FAILURE: null,
});
... ...
... ... @@ -206,6 +206,7 @@ class HomeContainer extends Component {
let {
resourceInfo,
src,
floorProductInfo,
} = this.props.alliance;
let {productList} = this.props.app;
let isShowGuide = this.state.firstFlag === '1';
... ... @@ -214,6 +215,7 @@ class HomeContainer extends Component {
<View style={styles.container}>
<Home
resourceInfo={resourceInfo}
floorProductInfo={floorProductInfo}
data={this.props.app}
jumpWithUrl={this._jumpWithUrl}
resourceJumpWithUrl={this._resourceJumpWithUrl}
... ...
... ... @@ -149,6 +149,8 @@ const {
GET_LOCATION_SUCCESS,
GET_LOCATION_FAILURE,
GET_GOODSROLLFLOOR_PRODUCTLIST_SUCCESS,
GET_GOODSROLLFLOOR_PRODUCTLIST_FAILURE,
} = require('../../constants/actionTypes').default;
... ... @@ -834,6 +836,20 @@ export function hideToastMessage() {
};
}
export function getGoodsRollFloorProductListInfoSuccess(json) {
return {
type: GET_GOODSROLLFLOOR_PRODUCTLIST_SUCCESS,
payload: json
};
}
export function getGoodsRollFloorProductListInfoFailure(error) {
return {
type: GET_GOODSROLLFLOOR_PRODUCTLIST_FAILURE,
payload: error
};
}
export function getSettlementInfo() {
return (dispatch, getState) => {
let {app} = getState();
... ... @@ -916,6 +932,31 @@ export function checkSettlementInfo() {
};
}
export function getGoodsRollFloorProductListInfo(productSkn) {
return (dispatch, getState) => {
let {app} = getState();
let funGetProductListInfo = (uid) => {
return new AllianceService(app.host).getGoodsRollFloorProductList(productSkn)
.then(json => {
dispatch(getGoodsRollFloorProductListInfoSuccess(json));
})
.catch(error => {
dispatch(getGoodsRollFloorProductListInfoFailure(error));
});
};
let uid = 0;
ReactNative.NativeModules.YH_CommonHelper.uid()
.then(uid => {
funGetProductListInfo(uid)
})
.catch(error => {
funGetProductListInfo(uid)
});
};
}
export function getResourceInfo(callback) {
return (dispatch, getState) => {
let {app} = getState();
... ... @@ -933,6 +974,10 @@ export function getResourceInfo(callback) {
dispatch(setproductPool(productPool));
dispatch(setSkns(skns));
}
if (item.template_name === 'pusherGoodsRoll' && item.data) {
let skns = item.data.productSkns;
dispatch(getGoodsRollFloorProductListInfo(skns));
}
})
})
.catch(error => {
... ...
... ... @@ -246,7 +246,13 @@ let InitialState = Record({
cityError: null,
provinceList: List(),
cityList: List(),
}))
})),
floorProductInfo: new (Record({
isFetching: false,
error: null,
resourceProductList: List(),
})),
});
... ...
... ... @@ -145,6 +145,8 @@ const {
GET_LOCATION_SUCCESS,
GET_LOCATION_FAILURE,
GET_GOODSROLLFLOOR_PRODUCTLIST_SUCCESS,
GET_GOODSROLLFLOOR_PRODUCTLIST_FAILURE,
} = require('../../constants/actionTypes').default;
const initialState = new InitialState;
... ... @@ -799,7 +801,31 @@ export default function couponReducer(state = initialState, action) {
.setIn(['cityLocationInfo', 'cityList'], Immutable.fromJS([]))
}
}
case GET_GOODSROLLFLOOR_PRODUCTLIST_SUCCESS: {
let {
product_list,
} = action.payload;
if (!product_list || product_list.length === 0) {
return
}
let unitMap = [];
let rowId = 0;
unitMap[rowId] = [];
product_list.slice(0, 18).map((data, index) => {
if (parseInt(index / 3) == rowId) {
unitMap[rowId].push(data);
} else {
rowId += 1;
unitMap[rowId] = [];
unitMap[rowId].push(data);
}
});
return state.setIn(['floorProductInfo', 'resourceProductList'], Immutable.fromJS(unitMap));
}
case GET_GOODSROLLFLOOR_PRODUCTLIST_FAILURE: {
return state.setIn(['floorProductInfo', 'error'], action.payload);
}
}
return state;
}
... ...
... ... @@ -529,5 +529,20 @@ export default class AllianceService {
});
}
// 获取推手轮播商品列表信息
async getGoodsRollFloorProductList(productSkn) {
return await this.api.get({
url: '',
body: {
productSkn,
method: 'app.search.cpsResource.productList',
}
})
.then((json) => {
return json;
})
.catch((error) => {
throw(error);
});
}
}
... ...