Authored by hongyong.zhao

Merge remote-tracking branch 'origin/v6.9.16' into feature/rn_update61

# Conflicts:
#	js/newArrival/components/newArrival/floor/ImageSlider.js
Showing 39 changed files with 3049 additions and 377 deletions
... ... @@ -8,6 +8,7 @@ import QRCode from './qrcode/QRCode';
import BrandStore from './brandStore/BrandStore';
//import Classify from './classify/Classify';
import Seckill from './seckill/Seckill';
import PanicBuying from './panicBuying/PanicBuying'
import Guang from './guang/Guang';
import Message from './message/Message';
import NewArrival from './newArrival/NewArrival';
... ... @@ -41,6 +42,7 @@ export default function native(platform) {
BrandStore(platform);
// Classify(platform);
Seckill(platform);
PanicBuying(platform);
Guang(platform);
Plustar(platform);
Message(platform)
... ...
... ... @@ -18,63 +18,70 @@ export default class ContentFansListCell extends Component {
let resource = data.isMutualAttention ? require('../../images/content_attentioned.png') : require('../../images/content_fan.png');
let userName = data.userName;
let showIcon = (data.authGroupId === 3 || data.authGroupId === 5 || data.authGroupId === 7) ? true : false;
let showIcon = (data.authGroupId === 3 || data.authGroupId === 5 || data.authGroupId === 7 || data.authGroupId === 11) ? true : false;
let source;
switch (data.authGroupId) {
case 3:
source = require('../../images/GF_big_ic.png');
break;
case 5:
source = require('../../images/PP_big_ic.png');
break;
case 7:
source = require('../../images/KING_big_ic.png');
break;
default:
case 3:
source = require('../../images/GF_big_ic.png');
break;
case 5:
source = require('../../images/PP_big_ic.png');
break;
case 7:
source = require('../../images/KING_big_ic.png');
break;
case 11:
source = require('../../images/DR_big_ic.png');
break;
default:
}
return (
<View>
<View style={styles.headerBackground}>
<TouchableOpacity style={{marginLeft: 15, marginRight: 15, flexDirection:'row'}} activeOpacity={1} onPress={()=> this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(data)}>
<View>
<View style={styles.headerBackground}>
<TouchableOpacity style={{marginLeft: 15, marginRight: 15, flexDirection: 'row'}} activeOpacity={1}
onPress={() => this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(data)}>
<YH_Image style={styles.headIcon} url={data.headIco} circle={true}/>
{showIcon ? <Image style={styles.iconImage} resizeMode="contain" source={source}/> : null}
</TouchableOpacity>
</TouchableOpacity>
<View style={styles.textView}>
<TouchableOpacity style={styles.toubleView} activeOpacity={1} onPress={()=> this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(data)}>
<Text style={styles.nicknameText} numberOfLines={1}>{userName}</Text>
<Text style={styles.defaultReplyText}>关注了你</Text>
</TouchableOpacity>
<Text style={styles.startTimeText}>{data.createTime}</Text>
</View>
<TouchableOpacity activeOpacity={1} style={styles.fanContainer} onPress={()=> {this.props.updateAttentionAction && this.props.updateAttentionAction(data)}}>
<Image style={styles.fanImage} resizeMode="contain" source={resource}/>
</TouchableOpacity>
</View>
{ this.props.showLine ? <View style={styles.lineView}/> : null }
</View>
<View style={styles.textView}>
<TouchableOpacity style={styles.toubleView} activeOpacity={1}
onPress={() => this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(data)}>
<Text style={styles.nicknameText} numberOfLines={1}>{userName}</Text>
<Text style={styles.defaultReplyText}>关注了你</Text>
</TouchableOpacity>
<Text style={styles.startTimeText}>{data.createTime}</Text>
</View>
<TouchableOpacity activeOpacity={1} style={styles.fanContainer} onPress={() => {
this.props.updateAttentionAction && this.props.updateAttentionAction(data)
}}>
<Image style={styles.fanImage} resizeMode="contain" source={resource}/>
</TouchableOpacity>
</View>
{this.props.showLine ? <View style={styles.lineView}/> : null}
</View>
);
}
}
let { width, height } = Dimensions.get('window');
let {width, height} = Dimensions.get('window');
const DEVICE_HEIGHT_RATIO = height / 667;
let styles = StyleSheet.create({
headerBackground: {
width: width,
height: 80,
backgroundColor: 'white',
flexDirection: 'row',
width: width,
height: 80,
backgroundColor: 'white',
flexDirection: 'row',
},
headIcon: {
width: 50,
height: 50,
marginTop: 15,
overflow: 'hidden',
borderRadius: 25,
width: 50,
height: 50,
marginTop: 15,
overflow: 'hidden',
borderRadius: 25,
},
iconImage: {
width: 20,
... ... @@ -83,51 +90,51 @@ let styles = StyleSheet.create({
marginTop: 48,
},
textView: {
flexDirection: 'column',
justifyContent: 'space-between',
alignItems: 'flex-start',
marginTop: 15,
marginBottom: 20,
width: width - 160,
flexDirection: 'column',
justifyContent: 'space-between',
alignItems: 'flex-start',
marginTop: 15,
marginBottom: 20,
width: width - 160,
},
toubleView: {
flexDirection: 'row',
overflow:'hidden',
width: width - 160,
flexDirection: 'row',
overflow: 'hidden',
width: width - 160,
},
startTimeText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#B0B0B0',
height: 17
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#B0B0B0',
height: 17
},
nicknameText: {
fontSize: 14,
fontFamily: 'PingFang-SC-Regular',
color: 'black',
maxWidth: width/2 - 30,
fontSize: 14,
fontFamily: 'PingFang-SC-Regular',
color: 'black',
maxWidth: width / 2 - 30,
},
defaultReplyText :{
fontSize: 14,
fontFamily: 'PingFang-SC-Regular',
color: '#b0b0b0',
defaultReplyText: {
fontSize: 14,
fontFamily: 'PingFang-SC-Regular',
color: '#b0b0b0',
},
fanContainer: {
position: 'absolute',
top: 27,
right: 15,
width: 60,
height: 25,
position: 'absolute',
top: 27,
right: 15,
width: 60,
height: 25,
},
fanImage: {
width: 60,
height: 25,
width: 60,
height: 25,
},
lineView: {
marginLeft:15,
marginRight: 0,
width: width-15,
height: 0.5,
backgroundColor: '#e0e0e0'
marginLeft: 15,
marginRight: 0,
width: width - 15,
height: 0.5,
backgroundColor: '#e0e0e0'
},
});
});
... ...
... ... @@ -18,7 +18,7 @@ export default class ContentLikedListCell extends Component {
let rowData = this.props.data;
let resource = rowData.coverImg ? typeof rowData.coverImg === 'string' ? JSON.parse(rowData.coverImg) : rowData.coverImg : '';
let picItem = resource ? typeof resource.data === 'string' ? JSON.parse(resource.data) : resource.data : '';
let picItem = resource ? typeof resource.data === 'string' ? JSON.parse(resource.data) : resource.data : '';
let imageUrl = YH_Image.getSlicedUrl(picItem.src, 50 * DEVICE_HEIGHT_RATIO, 50 * DEVICE_HEIGHT_RATIO, 2);
let userName = rowData.userName;
... ... @@ -35,78 +35,84 @@ export default class ContentLikedListCell extends Component {
break
}
// rowData.businessType === 1000 ? '赞了你' : '收藏了你';
let showIcon = (rowData.authGroupId === 3 || rowData.authGroupId === 5 || rowData.authGroupId === 7) ? true : false;
let showIcon = (rowData.authGroupId === 3 || rowData.authGroupId === 5 || rowData.authGroupId === 7 || rowData.authGroupId === 11) ? true : false;
let source;
switch (rowData.authGroupId) {
case 3:
source = require('../../images/GF_big_ic.png');
break;
case 5:
source = require('../../images/PP_big_ic.png');
break;
case 7:
source = require('../../images/KING_big_ic.png');
break;
default:
case 3:
source = require('../../images/GF_big_ic.png');
break;
case 5:
source = require('../../images/PP_big_ic.png');
break;
case 7:
source = require('../../images/KING_big_ic.png');
break;
case 11:
source = require('../../images/DR_big_ic.png');
break;
default:
}
return (
<View>
<View style={styles.headerBackground}>
<TouchableOpacity style={{marginLeft: 15, marginRight: 10, flexDirection:'row'}} activeOpacity={1} onPress={()=> this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(rowData)}>
<YH_Image style={styles.headIcon} url={rowData.headIco} circle={true}/>
{showIcon ? <Image style={styles.iconImage} resizeMode="contain" source={source}/> : null}
</TouchableOpacity>
<View style={styles.textView}>
<TouchableOpacity activeOpacity={1} onPress={()=> this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(rowData)}>
<Text style={styles.nicknameText} numberOfLines={1}>{userName}</Text>
<View>
<View style={styles.headerBackground}>
<TouchableOpacity style={{marginLeft: 15, marginRight: 10, flexDirection: 'row'}} activeOpacity={1}
onPress={() => this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(rowData)}>
<YH_Image style={styles.headIcon} url={rowData.headIco} circle={true}/>
{showIcon ? <Image style={styles.iconImage} resizeMode="contain" source={source}/> : null}
</TouchableOpacity>
<Text style={styles.subnameText}>{subName}</Text>
</View>
</View>
<TouchableOpacity activeOpacity={1} onPress={() => this.props.jumpToGrassDetailPage && this.props.jumpToGrassDetailPage(rowData)}>
<View style={styles.textView}>
<TouchableOpacity activeOpacity={1}
onPress={() => this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(rowData)}>
<Text style={styles.nicknameText} numberOfLines={1}>{userName}</Text>
</TouchableOpacity>
<Text style={styles.subnameText}>{subName}</Text>
</View>
</View>
{ rowData.isDelete === 'N' ?
<TouchableOpacity activeOpacity={1}
onPress={() => this.props.jumpToGrassDetailPage && this.props.jumpToGrassDetailPage(rowData)}>
<View style={ styles.originView} >
<Text style={styles.copyText}>原文</Text>
{ imageUrl ? <YH_Image url={imageUrl} style={styles.imageStyle} /> : null }
{rowData.isDelete === 'N' ?
{rowData.content ?
<View style={styles.originView}>
<Text style={styles.copyText}>原文</Text>
{imageUrl ? <YH_Image url={imageUrl} style={styles.imageStyle}/> : null}
<Text style={styles.originText} numberOfLines={1}>
<Text>{rowData.content}</Text>
<Text>{'...'}</Text>
</Text>
:
<View style={{height: 5}} />
}
{rowData.content ?
</View>
<Text style={styles.originText} numberOfLines={1}>
<Text>{rowData.content}</Text>
<Text>{'...'}</Text>
</Text>
:
<View style={{height: 5}}/>
}
:
</View>
<View style={ styles.originView} >
<Text style={styles.deleteText} numberOfLines={1}>{'原文已被作者删除'}</Text>
</View> }
:
</TouchableOpacity>
<View style={styles.originView}>
<Text style={styles.deleteText} numberOfLines={1}>{'原文已被作者删除'}</Text>
</View>}
<View style={styles.timeView}>
<Text style={styles.startTimeText}>{rowData.createTime}</Text>
</View>
</TouchableOpacity>
{ this.props.showLine ? <View style={styles.lineView}/> : null }
<View style={styles.timeView}>
<Text style={styles.startTimeText}>{rowData.createTime}</Text>
</View>
</View>
{this.props.showLine ? <View style={styles.lineView}/> : null}
</View>
);
}
}
let { width, height } = Dimensions.get('window');
let {width, height} = Dimensions.get('window');
const DEVICE_HEIGHT_RATIO = height / 667;
let styles = StyleSheet.create({
... ... @@ -140,7 +146,7 @@ let styles = StyleSheet.create({
fontSize: 14,
fontFamily: 'PingFang-SC-Medium',
color: '#222222',
width: width/2,
width: width / 2,
},
subnameText: {
fontSize: 12,
... ... @@ -148,59 +154,59 @@ let styles = StyleSheet.create({
color: '#B0B0B0',
},
originView: {
flex: 1,
marginLeft: 15,
marginRight: 15,
marginBottom: 10,
backgroundColor: '#f0f0f0'
flex: 1,
marginLeft: 15,
marginRight: 15,
marginBottom: 10,
backgroundColor: '#f0f0f0'
},
copyText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#444444',
marginTop: 10,
marginLeft: 10,
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#444444',
marginTop: 10,
marginLeft: 10,
},
imageStyle: {
marginTop: 10,
marginBottom: 4,
marginLeft: 10,
width: 50 * DEVICE_HEIGHT_RATIO,
height: 50 * DEVICE_HEIGHT_RATIO,
marginTop: 10,
marginBottom: 4,
marginLeft: 10,
width: 50 * DEVICE_HEIGHT_RATIO,
height: 50 * DEVICE_HEIGHT_RATIO,
},
originText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#b0b0b0',
marginLeft: 10,
marginRight: 15,
marginBottom: 9,
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#b0b0b0',
marginLeft: 10,
marginRight: 15,
marginBottom: 9,
},
timeView: {
alignItems: 'flex-start',
marginBottom: 10,
marginLeft: 15,
alignItems: 'flex-start',
marginBottom: 10,
marginLeft: 15,
},
startTimeText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#B0B0B0',
height: 17
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#B0B0B0',
height: 17
},
lineView: {
marginLeft:15,
marginRight: 0,
width: width-15,
height: 0.5,
backgroundColor: '#e0e0e0'
marginLeft: 15,
marginRight: 0,
width: width - 15,
height: 0.5,
backgroundColor: '#e0e0e0'
},
deleteText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#b0b0b0',
marginLeft: 9,
marginRight: 16,
marginTop: 10,
marginBottom: 10
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#b0b0b0',
marginLeft: 9,
marginRight: 16,
marginTop: 10,
marginBottom: 10
},
});
});
... ...
... ... @@ -19,104 +19,114 @@ export default class ContentMessageCell extends Component {
let status = rowData.businessType === 1003 ? true : false;
let resource = rowData.coverImg ? typeof rowData.coverImg === 'string' ? JSON.parse(rowData.coverImg) : rowData.coverImg : '';
let picItem = resource ? typeof resource.data === 'string' ? JSON.parse(resource.data) : resource.data : '';
let picItem = resource ? typeof resource.data === 'string' ? JSON.parse(resource.data) : resource.data : '';
let imageUrl = YH_Image.getSlicedUrl(picItem.src, 50 * DEVICE_HEIGHT_RATIO, 50 * DEVICE_HEIGHT_RATIO, 2);
let userName = rowData.userName;
let subName = rowData.businessType === 1002 ? '评论了你' : '回复了你';
let showIcon = (rowData.authGroupId === 3 || rowData.authGroupId === 5 || rowData.authGroupId === 7) ? true : false;
let showIcon = (rowData.authGroupId === 3 || rowData.authGroupId === 5 || rowData.authGroupId === 7 || rowData.authGroupId === 11) ? true : false;
let source;
switch (rowData.authGroupId) {
case 3:
source = require('../../images/GF_big_ic.png');
break;
case 5:
source = require('../../images/PP_big_ic.png');
break;
case 7:
source = require('../../images/KING_big_ic.png');
break;
default:
case 3:
source = require('../../images/GF_big_ic.png');
break;
case 5:
source = require('../../images/PP_big_ic.png');
break;
case 7:
source = require('../../images/KING_big_ic.png');
break;
case 11:
source = require('../../images/DR_big_ic.png');
break;
default:
}
return (
<View>
<View style={styles.headerBackground}>
<TouchableOpacity style={{marginLeft: 15, marginRight: 10, flexDirection:'row'}} activeOpacity={1} onPress={()=> this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(rowData)}>
<YH_Image style={styles.headIcon} url={rowData.headIco} circle={true}/>
{showIcon ? <Image style={styles.iconImage} resizeMode="contain" source={source}/> : null}
</TouchableOpacity>
<View style={styles.textView}>
<TouchableOpacity activeOpacity={1} onPress={()=> this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(rowData)}>
<Text style={styles.nicknameText} numberOfLines={1}>{userName}</Text>
</TouchableOpacity>
<Text style={styles.subnameText}>{subName}</Text>
</View>
<TouchableOpacity activeOpacity={1} style={styles.replyContainer} onPress={()=> this.props.jumpToShowKeyboard && this.props.jumpToShowKeyboard(rowData)}>
<Image style={styles.replyImage} resizeMode="contain" source={require('../../images/content_reply.png')}/>
</TouchableOpacity>
</View>
<View style={styles.replyTextView}>
<Text style={styles.replyText} numberOfLines={2}>{rowData.commentContent}</Text>
</View>
{ status ?
<TouchableOpacity activeOpacity={1} onPress={() => this.props.jumpToGrassDetailPage && this.props.jumpToGrassDetailPage(rowData)}>
<View style={styles.ownerReplyView}>
<Text style={{paddingLeft: 10, paddingTop: 14, paddingRight: 1, paddingBottom: 12}} numberOfLines={3}>
<Text style={styles.replyText}>我的评论:</Text>
<Text style={styles.defaultReplyText}>{rowData.parentCommentContent}</Text>
</Text>
</View>
</TouchableOpacity>
:
<TouchableOpacity activeOpacity={1} onPress={() => this.props.jumpToGrassDetailPage && this.props.jumpToGrassDetailPage(rowData)}>
{ rowData.isDelete === 'N' ?
<View style={ styles.originContainerView} >
<Text style={styles.copyText}>原文</Text>
{ imageUrl ? <YH_Image url={imageUrl} style={styles.imageStyle} /> : null }
{rowData.content ?
<Text style={styles.originText} numberOfLines={1}>
<Text>{rowData.content}</Text>
<Text>{'...'}</Text>
</Text>
:
<View style={{height: 5}} />
}
<View>
<View style={styles.headerBackground}>
<TouchableOpacity style={{marginLeft: 15, marginRight: 10, flexDirection: 'row'}} activeOpacity={1}
onPress={() => this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(rowData)}>
<YH_Image style={styles.headIcon} url={rowData.headIco} circle={true}/>
{showIcon ? <Image style={styles.iconImage} resizeMode="contain" source={source}/> : null}
</TouchableOpacity>
</View>
:
<View style={ styles.originContainerView} >
<Text style={styles.deleteText} numberOfLines={1}>{'原文已被作者删除'}</Text>
<View style={styles.textView}>
<TouchableOpacity activeOpacity={1}
onPress={() => this.props.jumpToPersonalGrassPage && this.props.jumpToPersonalGrassPage(rowData)}>
<Text style={styles.nicknameText} numberOfLines={1}>{userName}</Text>
</TouchableOpacity>
<Text style={styles.subnameText}>{subName}</Text>
</View>
<TouchableOpacity activeOpacity={1} style={styles.replyContainer}
onPress={() => this.props.jumpToShowKeyboard && this.props.jumpToShowKeyboard(rowData)}>
<Image style={styles.replyImage} resizeMode="contain"
source={require('../../images/content_reply.png')}/>
</TouchableOpacity>
</View>
<View style={styles.replyTextView}>
<Text style={styles.replyText} numberOfLines={2}>{rowData.commentContent}</Text>
</View>
{status ?
<TouchableOpacity activeOpacity={1}
onPress={() => this.props.jumpToGrassDetailPage && this.props.jumpToGrassDetailPage(rowData)}>
<View style={styles.ownerReplyView}>
<Text style={{paddingLeft: 10, paddingTop: 14, paddingRight: 1, paddingBottom: 12}}
numberOfLines={3}>
<Text style={styles.replyText}>我的评论:</Text>
<Text style={styles.defaultReplyText}>{rowData.parentCommentContent}</Text>
</Text>
</View>
</TouchableOpacity>
:
<TouchableOpacity activeOpacity={1}
onPress={() => this.props.jumpToGrassDetailPage && this.props.jumpToGrassDetailPage(rowData)}>
{rowData.isDelete === 'N' ?
<View style={styles.originContainerView}>
<Text style={styles.copyText}>原文</Text>
{imageUrl ? <YH_Image url={imageUrl} style={styles.imageStyle}/> : null}
{rowData.content ?
}
<Text style={styles.originText} numberOfLines={1}>
<Text>{rowData.content}</Text>
<Text>{'...'}</Text>
</Text>
:
<View style={{height: 5}}/>
}
</View>
:
<View style={styles.originContainerView}>
<Text style={styles.deleteText} numberOfLines={1}>{'原文已被作者删除'}</Text>
</View>
}
</TouchableOpacity> }
<View style={styles.timeView}>
<Text style={styles.startTimeText}>{rowData.createTime}</Text>
</View>
</TouchableOpacity>}
{ this.props.showLine ? <View style={styles.lineView}/> : null }
<View style={styles.timeView}>
<Text style={styles.startTimeText}>{rowData.createTime}</Text>
</View>
</View>
{this.props.showLine ? <View style={styles.lineView}/> : null}
</View>
);
}
}
let { width, height } = Dimensions.get('window');
let {width, height} = Dimensions.get('window');
const DEVICE_WIDTH_RATIO = width / 375;
const DEVICE_HEIGHT_RATIO = height / 667;
... ... @@ -151,7 +161,7 @@ let styles = StyleSheet.create({
fontSize: 14,
fontFamily: 'PingFang-SC-Medium',
color: '#222222',
width: width/2,
width: width / 2,
},
subnameText: {
fontSize: 12,
... ... @@ -175,77 +185,77 @@ let styles = StyleSheet.create({
marginLeft: 15,
},
replyText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#444444',
},
ownerReplyView : {
flexDirection: 'row',
alignItems: 'center',
width: width - 30,
marginLeft: 15,
backgroundColor: '#F0F0F0',
marginBottom: 10,
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#444444',
},
ownerReplyView: {
flexDirection: 'row',
alignItems: 'center',
width: width - 30,
marginLeft: 15,
backgroundColor: '#F0F0F0',
marginBottom: 10,
},
defaultReplyText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#a8a8a8',
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#a8a8a8',
},
originContainerView: {
flex: 1,
marginLeft: 15,
marginRight: 15,
marginBottom: 10,
backgroundColor: '#f0f0f0'
flex: 1,
marginLeft: 15,
marginRight: 15,
marginBottom: 10,
backgroundColor: '#f0f0f0'
},
copyText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#444444',
marginTop: 10,
marginLeft: 9,
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#444444',
marginTop: 10,
marginLeft: 9,
},
imageStyle: {
marginTop: 10,
marginBottom: 4,
marginLeft: 9,
width: 50 * DEVICE_HEIGHT_RATIO,
height: 50 * DEVICE_HEIGHT_RATIO,
marginTop: 10,
marginBottom: 4,
marginLeft: 9,
width: 50 * DEVICE_HEIGHT_RATIO,
height: 50 * DEVICE_HEIGHT_RATIO,
},
originText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#b0b0b0',
marginLeft: 9,
marginRight: 16,
marginBottom: 9,
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#b0b0b0',
marginLeft: 9,
marginRight: 16,
marginBottom: 9,
},
deleteText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#b0b0b0',
marginLeft: 9,
marginRight: 16,
marginTop: 10,
marginBottom: 10
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#b0b0b0',
marginLeft: 9,
marginRight: 16,
marginTop: 10,
marginBottom: 10
},
timeView: {
alignItems: 'flex-start',
marginBottom: 10,
marginLeft: 15,
alignItems: 'flex-start',
marginBottom: 10,
marginLeft: 15,
},
startTimeText: {
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#B0B0B0',
height: 17
fontFamily: 'PingFang-SC-Regular',
fontSize: 12,
color: '#B0B0B0',
height: 17
},
lineView: {
marginLeft:15,
marginRight: 0,
width: width-15,
height: 0.5,
backgroundColor: '#e0e0e0'
marginLeft: 15,
marginRight: 0,
width: width - 15,
height: 0.5,
backgroundColor: '#e0e0e0'
},
});
});
... ...
... ... @@ -31,7 +31,7 @@ export default class BrandCell extends Component {
shop_logo = YH_Image.getSlicedUrl(shop_logo, 70, 35, 2);
let yh_exposureData = data.get('yh_exposureData');
return (
<TouchableOpacity style={styles.container} yh_exposureData={yh_exposureData} onPress={()=>{this.props.onPressShop&&this.props.onPressShop(data, index);}}>
<TouchableOpacity style={styles.container} yh_exposureData={yh_exposureData} onPress={()=>{this.props.onPressShop&&this.props.onPressShop(data, index, yh_exposureData);}}>
<View style={{flex:1}}>
<Image style={styles.image} source={{uri:shop_logo}}/>
<View style={[styles.footerContainer, {marginTop: shop_logo.length > 0 ? 12 : 52}]}>
... ... @@ -61,7 +61,7 @@ let styles = StyleSheet.create({
resizeMode: 'contain',
},
footerContainer: {
// marginTop: 12,
// marginTop: 12,
marginBottom: 8,
width: 80,
height: 16,
... ...
... ... @@ -146,10 +146,12 @@ export default class NewArrival extends React.PureComponent {
let resourceList = resourceInfo.resourceList ? resourceInfo.resourceList.toArray() : [];
let categoryList;
let template_id = ''
resourceList && resourceList.map((item, i) => {
let template_name = item.get('template_name');
if (template_name === 'guessLike') {
categoryList = item.get('data');
template_id = item.get('template_id');
}
});
... ... @@ -158,7 +160,7 @@ export default class NewArrival extends React.PureComponent {
data={categoryList}
selectedCategoryIndex={productList.selectedCategoryIndex}
onPressCategoryTab={(rowData, rowID) => {
this.props.onPressCategoryTab && this.props.onPressCategoryTab(rowData, rowID);
this.props.onPressCategoryTab && this.props.onPressCategoryTab(rowData, rowID, template_id);
}}
changeCategorySelectorTitle={this._clickCategorySelector}
/>
... ...
... ... @@ -89,6 +89,7 @@ export default class NewArrivalHeader extends Component {
<JointCell
key={'key23_'+i}
data={item.get('data')}
yh_exposedata={item.get('yh_exposureData')}
contentCode={contentCode}
isExtends={item.get('is_extend')}
imageWidth={item.get('image_width')}
... ...
... ... @@ -27,8 +27,10 @@ export default class RecommendCell extends Component {
}
_renderRow(rowData, sectionID, rowID) {
let yh_exposureData = rowData && rowData.get('yh_exposureData') ? rowData.get('yh_exposureData').toJS() : {}
return (
<BrandCell index={rowID} data={rowData} onPressShop={this.props.onPressShop}/>
<BrandCell yh_exposureData={yh_exposureData} index={rowID} data={rowData} onPressShop={this.props.onPressShop}/>
)
}
... ... @@ -41,6 +43,7 @@ export default class RecommendCell extends Component {
<Text style={styles.headerText}>推荐品牌</Text>
</View>
<ListView
yh_viewVisible = {true}
initialListSize={100}
contentContainerStyle={styles.contentContainer}
dataSource={this.dataSource.cloneWithRows(data.toArray())}
... ...
... ... @@ -32,11 +32,11 @@ export default class ImageSlider extends React.Component {
}
}
_handleParamsJumpWithUrl(index, url) {
_handleParamsJumpWithUrl(index, url, yh_exposeData) {
// 为埋点提供参数组装
// 后期请将所有的点击事件由 resourceJumpWithUrl 修改为自己独有的事件
// 由于多数组件都使用的 resourceJumpWithUrl ,埋点传参无法正常进行
let params = {
let params = yh_exposeData ? yh_exposeData : {
I_INDEX: index,
F_URL: url
};
... ... @@ -59,7 +59,7 @@ export default class ImageSlider extends React.Component {
yh_exposureData={data[0].yh_exposureData}
style={{width: sliderWidth, height: sliderHeight}}
onPress={() => {
this._handleParamsJumpWithUrl(1, data[0].url)
this._handleParamsJumpWithUrl(1, data[0].url, data[0].yh_exposureData)
}}
>
<YH_Image
... ... @@ -95,7 +95,7 @@ export default class ImageSlider extends React.Component {
activeOpacity={1}
yh_exposureData={item.yh_exposureData}
onPress={() => {
this._handleParamsJumpWithUrl(i + 1, item.url);
this._handleParamsJumpWithUrl(i + 1, item.url, item.yh_exposureData);
}}
>
<YH_Image
... ...
... ... @@ -37,7 +37,7 @@ export default class JointCell extends React.Component {
}
render() {
let {data, isExtends, imageWidth, imageHeight, floorId, floorName, fIndex, contentCode} = this.props;
let {data, isExtends, imageWidth, imageHeight, floorId, floorName, fIndex, contentCode, yh_exposedata} = this.props;
let source = this.props.data.toJS();
if (!source) {
return null;
... ... @@ -48,7 +48,7 @@ export default class JointCell extends React.Component {
let list = source.urls;
let touchWidth = (width-marginLeft*2) / list.length;
let pageName = Platform.OS === 'android' ? 'aFP_NewArrival': 'iFP_NewArrival';
let exposedata =yh_exposedata && yh_exposedata.toJS()
let ratioHeight = Math.ceil(width * imageHeight / imageWidth);
return (
... ... @@ -56,14 +56,15 @@ export default class JointCell extends React.Component {
<YH_Image url={YH_Image.getSlicedUrl(source.src, width-marginLeft*2, ratioHeight, 2)} resizeMode={'contain'} style={{ width: width-marginLeft*2, height: ratioHeight, marginLeft: marginLeft}} />
<View style={{flexDirection: 'row', position: 'absolute', top: 0, left: marginLeft, bottom: 0, right: marginLeft}}>{
list.map((item, i) => {
let exposureData = {
let exposureData = {
...exposedata,
F_ID: floorId,
P_NAME: pageName,
F_NAME: floorName,
F_URL: item,
F_INDEX: fIndex,
I_INDEX: parseInt(i) + 1 + "",
CONTENT_CODE: contentCode,
CODE: contentCode,
exposureEnd: 1,
}
... ...
... ... @@ -95,7 +95,7 @@ class NewArrivalContainer extends Component {
let data = item.data[0];
let tabName = data.tab_name;
let queryList = data.query;
data && self.props.actions.storeCurrentTabValue(0,tabName,queryList);
data && self.props.actions.storeCurrentTabValue(0,tabName,queryList, item.template_id);
}
})
});
... ... @@ -123,29 +123,30 @@ class NewArrivalContainer extends Component {
let {contentCode} = this.props.app;
let param;
if (type === 'banner' && params) {
param = {
F_ID: this.state.focusFloorId,
F_URL: url,
CONTENT_CODE: contentCode
};
}
let param = {...params};
// if (type === 'banner' && params) {
// param = {
// F_ID: this.state.focusFloorId,
// F_URL: url,
// CONTENT_CODE: contentCode
// };
// }
//
// if (type === 'icon' && params) {
// param = {
// F_ID: this.state.jointFloorId,
// F_URL: url,
// CONTENT_CODE: contentCode
// };
// }
if (type === 'icon' && params) {
param = {
F_ID: this.state.jointFloorId,
F_URL: url,
CONTENT_CODE: contentCode
};
}
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_NEW_ARRIVAL_FLR_C', param);
}
_onPressCategoryTab(data, index) {
_onPressCategoryTab(data, index, template_id) {
let queryList = data.get('query').toJS();
data && this.props.actions.storeCurrentTabValue(index, data.get('tab_name'), queryList);
data && this.props.actions.storeCurrentTabValue(index, data.get('tab_name'), queryList, template_id);
}
_onPressArticle(url, index=0, article_id) {
... ... @@ -265,7 +266,7 @@ class NewArrivalContainer extends Component {
paramsDic = res;
})
InteractionManager.runAfterInteractions(() => {
this.props.actions.getProductList(paramsDic);
this.props.actions.getProductList(paramsDic, this.state.tabFloorId);
});
}
... ... @@ -303,7 +304,7 @@ class NewArrivalContainer extends Component {
}
_onPressShop(data, index=0) {
_onPressShop(data, index=0, yh_exposureData) {
let {
shop_name,
shops_id,
... ... @@ -316,15 +317,18 @@ class NewArrivalContainer extends Component {
if (!shops_id||!shop_name) {
return;
}
let url = `http://m.yohobuy.com?openby:yohobuy={"action":"go.shop","params":{"shop_id":"${shops_id}","shop_template_type":"${shop_template_type}","shop_name":"${shop_name}","is_red_shop":"${is_red_shop}","brand_id":"${brand_id}"}}`;
ReactNative.NativeModules.YH_CommonHelper.jumpWithUrl(url);
let param = {
let param = {}
param = yh_exposureData ? yh_exposureData.toJS() : {
F_ID: this.state.shopFloorId,
F_URL: url,
SHOP_ID: shops_id,
CONTENT_CODE: contentCode,
CODE: contentCode,
}
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_NEW_ARRIVAL_FLR_C', param);
}
... ... @@ -334,21 +338,24 @@ class NewArrivalContainer extends Component {
return;
}
let { selectedTabIndex, selectedTabName } = this.props.newArrival;
let { contentCode } = this.props.app;
let yh_exposeData = product && product.get('yh_exposureData') ? product.get('yh_exposureData').toJS(): {
F_ID: this.state.tabFloorId,
F_URL: url,
PRD_SKN: productSkn,
TAB_ID: selectedTabIndex,
TAB_NAME: selectedTabName,
CODE: contentCode,}
let url = `http://m.yohobuy.com?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":"${productSkn}","from_page_name":"${Platform.OS === 'ios'?'iFP_NewArrival':'aFP_NewArrival'}"}}`;
ReactNative.NativeModules.YH_CommonHelper.jumpWithUrl(url);
let param = {
F_ID: this.state.tabFloorId,
F_URL: url,
PRD_SKN: productSkn,
TAB_ID: selectedTabIndex,
TAB_NAME: selectedTabName,
CONTENT_CODE: contentCode,
}
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_NEW_ARRIVAL_FLR_C', param);
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_NEW_ARRIVAL_FLR_C', yh_exposeData);
}
... ...
... ... @@ -68,7 +68,7 @@ export function setShowSimilarGuider(requestNative, show=false) {
}
}
export function storeCurrentTabValue(index, tabName, queryList) {
export function storeCurrentTabValue(index, tabName, queryList, template_id) {
return (dispatch, getState) => {
dispatch({
type: STORE_CURRENT_TAB_VALUE,
... ... @@ -83,7 +83,7 @@ export function storeCurrentTabValue(index, tabName, queryList) {
}
paramsDic = res;
})
dispatch(getProductList(paramsDic));
dispatch(getProductList(paramsDic, template_id));
};
}
... ... @@ -146,39 +146,83 @@ function exposeResourceInfoData(json, contentCode) {
let floorname = item.template_name
let floorid = item.template_id
if (floorname === 'newFocus') {
let list = item.data;
for (let j = 0; j< list.length; j ++) {
let subitem = list[j]
subitem.yh_exposureData = {
F_ID: floorid,
F_NAME: floorname,
F_INDEX: i + 1,
I_INDEX: parseInt(j) + 1 + "",
P_NAME: pageName,
F_URL: subitem.url,
CONTENT_CODE: contentCode,
exposureEnd: 1,
}
}
}
if (floorname === 'newProductShopListFloor') {
let list = item.list;
for (let j = 0; j< list.length; j ++) {
let subitem = list[j]
subitem.yh_exposureData = {
F_ID: floorid,
F_NAME: floorname,
P_NAME: pageName,
F_INDEX: i + 1,
I_INDEX: parseInt(j) + 1 + "",
SHOP_ID: subitem.shops_id,
CONTENT_CODE: contentCode,
exposureEnd: 1,
}
}
}
switch (floorname) {
case 'newFocus': {
let list = item.data;
for (let j = 0; j< list.length; j ++) {
let subitem = list[j]
subitem.yh_exposureData = {
F_ID: floorid,
F_NAME: floorname,
F_INDEX: i + 1,
I_INDEX: parseInt(j) + 1 + "",
P_NAME: pageName,
F_URL: subitem.url,
CODE: contentCode,
exposureEnd: 1,
}
}
}
break;
case 'newProductShopListFloor': {
let list = item.list;
for (let j = 0; j< list.length; j ++) {
let subitem = list[j]
subitem.yh_exposureData = {
F_ID: floorid,
F_NAME: floorname,
P_NAME: pageName,
F_INDEX: i + 1,
I_INDEX: parseInt(j) + 1 + "",
SHOP_ID: subitem.shops_id,
CODE: contentCode,
exposureEnd: 1,
}
}
}
break;
case 'divideImage': {
let list = item.data
for (let j=0; j< list.length; j++) {
let subitem = list[j]
subitem.yh_exposureData = {
F_ID: floorid,
F_NAME: floorname,
P_NAME: pageName,
F_INDEX: i + 1,
I_INDEX: parseInt(j) + 1 + "",
CODE: contentCode,
F_URL: subitem.url,
exposureEnd: 1,
}
}
}
break;
case 'splitJointImg': {
let url = ''
url = item.urls && item.urls[0] ? item.urls[0] : ''
item.yh_exposureData = {
F_ID: floorid,
F_NAME: floorname,
P_NAME: pageName,
F_INDEX: i + 1,
I_INDEX: 1 + "",
CODE: contentCode,
F_URL: url,
exposureEnd: 1,
}
}
break;
}
}
} catch(error){ }
... ... @@ -216,7 +260,7 @@ export function productListFailure(error) {
/*
* 底部产品列表
*/
export function getProductList(paramsDic) {
export function getProductList(paramsDic, template_id) {
return (dispatch, getState) => {
let {app, newArrival} = getState();
let { productList, filterFactors, searchResourceList, prdFloorId, prdFloorName, prdFloorIndex} = newArrival;
... ... @@ -252,7 +296,7 @@ export function getProductList(paramsDic) {
return new NewArrivalService(app.host).fetchProductList(channel, order, page, pageSize, allFilterFactors, paramsDic)
.then(json => {
let payload = exposeProductListData(json, order, channel, pageSize, tabId, tabName, prdFloorId, prdFloorName, prdFloorIndex);
let payload = exposeProductListData(json, order, channel, pageSize, tabId, tabName, prdFloorId, prdFloorName, prdFloorIndex, app.contentCode);
payload.endReached = payload.currentPage == payload.pageCount;
if (payload.currentPage > 1) {
... ... @@ -286,7 +330,7 @@ function reShuffleJumpList(jumplist, pageindex, pagesize) {
}
}
function exposeProductListData(json, order, channel, pageSize, tabId, tabName, prdFloorId, prdFloorName, prdFloorIndex) {
function exposeProductListData(json, order, channel, pageSize, tabId, tabName, prdFloorId, prdFloorName, prdFloorIndex, contentcode) {
let res = json;
try {
let list = json ? json.product_list : [];
... ... @@ -314,12 +358,13 @@ function exposeProductListData(json, order, channel, pageSize, tabId, tabName, p
PRD_CHANNEL: prdChannel,
RECALL_TYPE: recallType,
PRD_TYPE: prdType,
CODE: contentcode,
F_NAME: prdFloorName,
F_INDEX: prdFloorIndex,
F_ID:prdFloorId,
exposureEnd: 1,
};
}
res.product_list = list;
res.search_resource_list = json.search_resource_list.length> 0 ? json.search_resource_list : []
... ...
'use strict';
import React from 'react';
import ReactNative, {
AppRegistry,
Platform,
StyleSheet,
Dimensions,
TouchableOpacity,
} from 'react-native';
import {
Provider,
connect
} from 'react-redux';
import createReactClass from 'create-react-class';
import configureStore from './store/configureStore';
import appInitialState from './reducers/app/appInitialState';
import panicbuyingInitialState from './reducers/panicbuying/panicbuyingInitialState';
import DiscountProductInitialState from "./reducers/discountProduct/DiscountProductInitialState";
import PanicBuyingContainer from './containers/PanicBuyingContainer';
import {
setPlatform,
setHost,
} from './reducers/app/appActions';
import {
setStartTime,
setContentCode,
} from './reducers/panicbuying/panicbuyingActions';
function getInitialState() {
const _initState = {
app: (new appInitialState()),
panicbuying: (new panicbuyingInitialState()),
discountProduct:(new DiscountProductInitialState())
};
return _initState;
}
export default function native(platform) {
let YH_PanicBuying = createReactClass({
render() {
const store = configureStore(getInitialState());
store.dispatch(setPlatform(platform));
let time = this.props.time;
if (time) {
store.dispatch(setStartTime(time));
}
if(this.props.contentCode){
store.dispatch(setContentCode(this.props.contentCode));
}
store.dispatch(setHost(this.props.host));
return (
<Provider store={store}>
<PanicBuyingContainer />
</Provider>
);
}
});
AppRegistry.registerComponent('YH_PanicBuying', () => YH_PanicBuying);
}
let styles = StyleSheet.create({
});
... ...
'use strict';
import React, {Component} from "react";
import {View, Text, Image, ListView, StyleSheet, Dimensions, TouchableOpacity} from "react-native";
import SlicedImage from "../../../common/components/SlicedImage";
import YH_Image from '../../../common/components/YH_Image';
import * as Progress from 'react-native-progress';
export default class PBProductListView extends Component {
constructor(props) {
super(props);
this.tipMessage = '';
this.state = {
selectedIndex: 0,
};
}
render() {
let {
index,
rowData,
tipMessage,
} = this.props;
this.tipMessage = tipMessage;
let brandIconUrl = SlicedImage.getSlicedUrl(rowData.defaultImages, 152, 203, 2);
let tipState = '';
let btnBgColor = '#d30018';
let btnTextcolor = 'white';
let url = rowData.shopUrl;
if (rowData.over) {
tipState = '已抢光';
btnBgColor = '#b2b2b2';
} else if (rowData.wait) {
if (!rowData.remindFlag) {
tipState = '提醒我';
btnBgColor = '#444444';
} else {
tipState = '取消提醒';
btnBgColor = 'white';
btnTextcolor = '#000000';
}
} else {
tipState = '马上抢';
}
let percent = 0;
let stock = rowData.configStorage?rowData.configStorage:0;
if (rowData.configStorage && rowData.storageSum && stock != 0) {
let sale = rowData.configStorage - rowData.storageSum;
percent = Math.floor(sale/stock*100);
}
let progressText = '';
if (percent < 80) {
progressText = '已抢' + percent + '%';
} else if (percent < 100) {
progressText = '即将售罄';
} else {
progressText = '已售罄';
}
return (
<TouchableOpacity activeOpacity={1.0} yh_exposureData={rowData.yh_exposureData} onPress={() => {
this.props.onPressProductItem && this.props.onPressProductItem(rowData, index);
}}>
<View style={styles.rowContainer}>
<View style={styles.leftImage}>
<YH_Image style={{flex:1}} url={brandIconUrl} />
{rowData.tag &&
<View style={styles.tagView}>
+ <Text style= {styles.tag}>{rowData.tag}</Text>
</View>}
</View>
<View style={styles.rowRight}>
<Text style={styles.productTitle}
numberOfLines={2}>{rowData.productName}</Text>
{tipState == '马上抢' && <View style = {styles.progressBar}>
<Progress.Bar
progress={percent/100}
width={adjustPx(100)}
color={'#D0021B'}
unfilledColor={'#ffffff'}
borderWidth={1}
style={styles.bar}
/>
<Text style = {styles.progressText}>{progressText}</Text>
</View>}
{tipState == '已抢光' && <View style = {styles.progressBar}>
<Progress.Bar
progress={1}
width={adjustPx(100)}
color={'#B0B0B0'}
unfilledColor={'#B0B0B0'}
borderWidth={1}
style={styles.bar}
/>
<Text style = {styles.progressText}>已售罄</Text>
</View> }
{rowData.wait && <View style={styles.limit}>
<Text style={styles.limitText}>限量{stock}</Text>
</View>}
<View style={{
flexDirection: 'row',
flex: 1,
alignItems: 'flex-end',
justifyContent: 'space-between'
}}>
<View style={{ flexDirection : 'row'}}>
<Text
style={styles.seckillPrice}>¥{parseInt(rowData.secKillPrice + "")}</Text>
<Text style={styles.originPrice}>
{'¥' + parseInt(rowData.marketPrice + '')}</Text>
</View>
<View style={{justifyContent: 'center', alignItems: 'flex-end'}}>
{tipState == '已抢光' ?
<TouchableOpacity onPress={()=> {
this.props.onPressProductItem && this.props.onPressProductItem(rowData, index);
// this.props.onPressGuangShopWithURL && this.props.onPressGuangShopWithURL(url);
}} style={[styles.priceClickTipViewRight, {
backgroundColor: '#B2B2B2'
}]}>
<Text style={{color: 'white'}}>已抢完</Text>
</TouchableOpacity>
: null}
{tipState != '已抢光' ? <TouchableOpacity onPress={() => {
if (this.tipMessage == '') {
if (rowData.wait) {
this.props.onPressRemindBtn && this.props.onPressRemindBtn(rowData);
} else {
this.props.onPressProductItem && this.props.onPressProductItem(rowData);
}
}
}}>
{
(tipState == '取消提醒') ?
<View style={[styles.priceClickTipViewRight, {
backgroundColor: btnBgColor,
borderWidth: 1.0
}]}>
<Text style={{color: btnTextcolor}}>{tipState}</Text>
</View>
: <View
style={[styles.priceClickTipViewRight, {backgroundColor: btnBgColor}]}>
<Text style={{color: btnTextcolor}}>{tipState}</Text>
</View>
}
</TouchableOpacity> : null
}
{/* {rowData.wait &&
<Text style={styles.seckillBeginTimeTip}>{rowData.readableTime + ' 开始'}</Text>} */}
</View>
</View>
</View>
</View>
</TouchableOpacity>
);
}
}
let {width, height} = Dimensions.get('window');
let backgroundWidth = width;
let backgroundHeight = 121;
let rowHeight = backgroundHeight;
let WIDTH_RATION = width / 375.0;
let imageWidth = 98;
let imageHeight = 130;
let adjustPx = (number) => Math.round(number * WIDTH_RATION)
let styles = StyleSheet.create({
rowContainer: {
flexDirection: 'row',
paddingLeft: adjustPx(15),
paddingRight: adjustPx(15),
paddingTop: adjustPx(10),
paddingBottom: adjustPx(10),
backgroundColor: 'white',
},
leftImage: {
width: adjustPx(imageWidth),
height: adjustPx(imageHeight),
},
soldOutContainer: {
backgroundColor: '#0000007F',
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
top: 0,
alignItems: 'center',
justifyContent: 'center',
},
rowRight: {
flexDirection: 'column',
marginLeft: 10,
justifyContent: 'space-between',
flex: 1,
},
priceClickTipView: {
flexDirection: 'row',
justifyContent: 'space-between',
width: width - imageWidth - 35,
height: 50,
backgroundColor: 'yellow',
},
priceClickTipViewLeft: {
top: 25,
},
priceClickTipViewRight: {
width: 80,
height: 30,
marginTop: 10,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 3,
backgroundColor: '#d0021b',
},
secKillMarketPriceContainer: {
flexDirection: 'row',
alignItems: 'center'
},
bottomToolBar: {
top: 200,
height: 44,
backgroundColor: '#000',
},
closeScan: {
left: 10,
width: 25,
height: 25,
top: 10,
},
productTitle: {
fontSize: 14,
color: '#444444',
lineHeight: 20,
marginRight: 20,
},
progressText: {
fontSize: 10,
color: '#B0B0B0',
left: 5,
top: -3
},
seckillPrice: {
fontSize: 18,
lineHeight: 30,
fontWeight: 'bold',
color: '#d0021b',
justifyContent: 'center',
},
originPrice: {
textDecorationLine: 'line-through',
color: '#B0B0B0',
fontSize: 12,
height: 17,
left: 5,
top: 10,
},
seckillBeginTimeTip: {
fontSize: 9,
marginTop: 6,
color: '#D0021B',
},
separator: {
position: 'absolute',
left: 15,
right: 0,
bottom: 0,
height: 0.5,
backgroundColor: '#e5e5e5',
},
tagView: {
backgroundColor: '#ff575c',
position: 'absolute',
left: -5,
top: 5,
width: 44,
height: 15,
alignItems: 'center',
justifyContent: 'center',
},
bar: {
height: 6,
},
progressBar: {
flexDirection : 'row',
position: 'absolute',
top: adjustPx(80),
},
tag: {
fontSize: 10,
color: 'white',
},
limit: {
position: 'absolute',
top: adjustPx(80),
},
limitText: {
fontSize: 12,
color: '#B0B0B0',
},
});
... ...
'use strict';
import React, {Component} from 'react';
import ReactNative, {
View,
Text,
StyleSheet,
Dimensions,
} from 'react-native';
import Immutable, {Map} from 'immutable';
// import TimeForWait from './PBTimeForWait';
// import TimeForNow from './PBTimeForNow';
// import TimeForOver from './PBTimeForOver';
export default class PBTimeForFocus extends Component {
constructor(props) {
super(props);
}
render() {
let {
activityDate,
activityHour,
} = this.props;
let text = activityHour + '点抢';
return (
<View style={styles.rowContainerFocus}>
<Text style={styles.title}>{activityDate}</Text>
<View style={styles.subTitleBg}>
<Text style={styles.subTitle}>{text}</Text>
</View>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let backgroundHeight = 70;
let rowContainerFocusWidth = width/3;
let styles = StyleSheet.create({
rowContainerFocus: {
flexDirection: 'column',
alignItems: 'center',
//justifyContent: 'center',
width: rowContainerFocusWidth,
height: backgroundHeight,
backgroundColor:'transparent',
},
title: {
fontSize: 18,
marginTop:5,
fontWeight:'bold',
color: 'white'
},
subTitleBg: {
backgroundColor: 'white',
borderRadius: 8,
width: 48,
height: 16,
top: 5,
alignItems: 'center',
justifyContent:'center',
},
subTitle: {
fontSize: 11,
color: '#585858',
}
});
... ...
'use strict';
import React, {Component} from 'react';
import ReactNative, {
View,
Text,
StyleSheet,
Dimensions,
} from 'react-native';
import Immutable, {Map} from 'immutable';
export default class PBTimeForLostFocus extends Component {
constructor(props) {
super(props);
}
render() {
let {
activityDate,
activityHour,
} = this.props;
let text = activityHour + '点抢';
return (
<View style={styles.rowContainer}>
<Text style={styles.title}>{activityDate}</Text>
<Text style={styles.subTitle}>{text}</Text>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let backgroundHeight = 70;
let rowContainerWidth = width / 3;
let styles = StyleSheet.create({
rowContainer: {
flexDirection: 'column',
alignItems: 'center',
width: rowContainerWidth,
height: backgroundHeight,
backgroundColor:'transparent',
},
title: {
fontSize: 18,
marginTop:5,
fontWeight:'bold',
color: 'white',
opacity: 0.6
},
subTitle: {
fontSize: 11,
marginTop:5,
color: 'white',
opacity: 0.6
}
});
... ...
'use strict';
import React, {Component} from "react";
import ReactNative, {View, Text, Image, ListView, StyleSheet, Dimensions, TouchableOpacity, Platform} from "react-native";
import Immutable from "immutable";
import TimeForFocus from "./PBTimeForFocus";
import TimeForLostFocus from "./PBTimeForLostFocus";
import TimeNumber from './PBTimeNumber';
let diff;
export default class PBTimeListView extends Component {
constructor(props) {
super(props);
this._renderRow = this._renderRow.bind(this);
this._renderSeparator = this._renderSeparator.bind(this);
this._scrollToFocusActivity = this._scrollToFocusActivity.bind(this);
this._caculateTimerState = this._caculateTimerState.bind(this);
this._searchRightNowStartActivity = this._searchRightNowStartActivity.bind(this);
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1.key != r2.key,
});
this.curFocusActivity = Immutable.fromJS({});
this.secKillProductVoList = Immutable.fromJS([]);
this.state = {
tickHour: '00',
tickMinute: '00',
tickSecond: '00',
tickTimeOut: true,
now:this.curFocusActivity.has('now'),
};
this.scrollX = 0;
}
_scrollToFocusActivity = () => {
//focus
if (this.secKillProductVoList.length >= 1) {
let listLength = this.secKillProductVoList.length;
let scrollX;
let currentScrollX = this.listView ? this.listView.scrollProperties.offset : 0;
scrollX = (this.curFocusActivity.get('index') - 1) * (rowContainerWidth + separatorWidth);
if (Platform.OS == 'ios') {
if (scrollX < 0) {
scrollX = 0
} else if (this.listView && (scrollX > this.listView.scrollProperties.contentLength - this.listView.scrollProperties.visibleLength)) {
scrollX = this.listView.scrollProperties.contentLength - this.listView.scrollProperties.visibleLength
}
}
if (this.scrollX == scrollX && ((Math.floor(scrollX) == Math.floor(currentScrollX)) || scrollX != 0)) {
return;
}
this.scrollX = scrollX;
this.listView && this.listView.scrollTo({x: scrollX, y: 0, animated: true});
}
}
_searchRightNowStartActivity() {
this.secKillProductVoList.forEach((activityItem, i) => {
if (activityItem.has('wait')) {
let nowTime = Date.parse(new Date()) / 1000 + diffTime;
let startTime = activityItem.get('startTime') / 1000;
let offsetTime = startTime - nowTime;
if (offsetTime < 0) {
activityItem.focus = true;
this.curFocusActivity = activityItem;
this._scrollToFocusActivity();
this.props.onFocusToCurStartedActivity && this.props.onFocusToCurStartedActivity(activityItem);
}
}
});
}
_caculateTimerState() {
let nextActivity = undefined;
if (this.curFocusActivity.get('index') < this.secKillProductVoList.length - 1) {
nextActivity = this.secKillProductVoList[this.curFocusActivity.get('index') + 1];
}
let nowTime = Date.parse(new Date()) / 1000 + diffTime;
let time = this.curFocusActivity.has('now') ? this.curFocusActivity.get('endTime') / 1000 : this.curFocusActivity.get('startTime') / 1000;
let offsetTime = time - nowTime;
let hour = parseInt(offsetTime / (60 * 60), 10);
let minute = parseInt(offsetTime % (60 * 60) / 60, 10);
let second = offsetTime % 60;
if (offsetTime < 0) {
if (this.state.tickTimeOut) {
return;
}
let wait = this.curFocusActivity.get('wait');
if (!this.state.now) {
this.props.updateStatusCurActivity && this.props.updateStatusCurActivity();
this.props.updateStatusProductList && this.props.updateStatusProductList();
this.state.now = true;
return;
}
if (!this.state.tickTimeOut) {
this.props.updateStatusCurActivity && this.props.updateStatusCurActivity();
this.props.updateStatusProductList && this.props.updateStatusProductList();
this.setState({
tickHour: '',
tickMinute: '',
tickSecond: '',
tickTimeOut: true,
});
}
} else {
this.setState({
tickHour: hour < 0 ? '00' : (hour < 10 ? ('0' + hour) : (hour > 99 ? 99 : hour)),
tickMinute: minute < 0 ? '00' : (minute < 10 ? ('0' + minute) : minute),
tickSecond: second < 0 ? '00' : (second < 10 ? ('0' + second) : second),
tickTimeOut: false,
});
}
}
componentDidMount() {
// this._scrollToFocusActivity();
this.timer = setInterval(function () {
if (!this.curFocusActivity && this.curFocusActivity.size > 0 && !this.curFocusActivity.has('over')) {
return;
}
this._caculateTimerState();
// this._searchRightNowStartActivity();
}.bind(this), 1000);
}
componentWillUnmount() {
this.timer && clearInterval(this.timer);
}
componentWillReceiveProps(nextProps) {
this.curFocusActivity = nextProps.curActivity;
if (this.curFocusActivity) {
// this._scrollToFocusActivity();
}
this._caculateTimerState();
}
_renderRow(rowData, sectionID, rowID) {
rowData = rowData.toJS();
return (
<TouchableOpacity activeOpacity={1.0} onPress={() => {
if (rowData.focus) {
return;
}
rowData.focus = true;
this.curFocusActivity = Immutable.fromJS(rowData);//rowData;
// this._scrollToFocusActivity();
this.props.onPressTimeItem && this.props.onPressTimeItem(rowData);
let P_NAME = 'aFP_PanicBuying';
if (Platform.OS === 'ios') {
P_NAME = 'iFP_PanicBuying';
}
//埋点
let params = {
P_NAME: P_NAME,
TAB_ID: Number(rowID)+1,
TAB_PARAM: rowData.activityDate,
};
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_SECKILL_TAB_LIST_C', params);
}}>
{rowData.focus ? <TimeForFocus
key={'row' + rowID}
time={rowData.time}
endTime={rowData.endTime}
now={rowData.now}
over={rowData.over}
wait={rowData.wait}
activityHour={rowData.activityHour}
activityDate={rowData.activityDate}
tickTimeOut={this.state.tickTimeOut}
tickHour={this.state.tickHour}
tickMinute={this.state.tickMinute}
tickSecond={this.state.tickSecond}
lastNowTime={false}
/> : <TimeForLostFocus
key={'row' + rowID}
time={rowData.time}
now={rowData.now}
over={rowData.over}
wait={rowData.wait}
activityHour={rowData.activityHour}
activityDate={rowData.activityDate}
specialState={
rowData.specialState
}
/>
}
</TouchableOpacity>
);
}
_renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
let listLength = this.secKillProductVoList.length;
if (listLength - 1 == rowID) {
return null;
}
return (
<View key={'sep' + rowID} style={styles.separator}>
</View>
);
}
render() {
let {
resource,
diff,
curActivity,
} = this.props;
diffTime = diff;
this.secKillProductVoList = resource;
this.curFocusActivity = curActivity;
backgroundWidth = Math.max((rowContainerWidth + separatorWidth) * (resource.length - 1) + rowContainerFocusWidth, width);
let cfActivity = this.curFocusActivity.toJS();
let tagText = undefined;
if (cfActivity.wait) {
tagText = '距开始:';
}else if (cfActivity.now) {
tagText = '距结束:';
} else {
tagText = '已结束';
}
let activityHour = this.curFocusActivity.get('activityHour');
return (
<View style={[styles.container]}>
<View style={styles.listContainer}>
<ListView style = {styles.listView}
ref={(ref)=>this.listView = ref}
contentContainerStyle={[styles.contentContainer]}
enableEmptySections={true}
dataSource={this.dataSource.cloneWithRows(resource)}
// renderSeparator={this._renderSeparator}
renderRow={this._renderRow}
showsHorizontalScrollIndicator={false}
scrollEnabled={true}
horizontal={true}
scrollsToTop={false}
/>
</View>
<View style = {styles.timerContainer}>
<Image source={require('../../images/timer_bg.png')} resizeMode="stretch" style={styles.timerbg}></Image>
<View style= {styles.timerContent}>
<Text style={styles.timerText}>每日{activityHour}点开抢,先到先得 </Text>
<View style={styles.tickTimeContainer}>
<Text style={styles.timerText}>{tagText}</Text>
{this.state.tickTimeOut ? null : <View style={{flexDirection:'row'}}>
<TimeNumber text={this.state.tickHour} />
<Text style={styles.symText}>:</Text>
<TimeNumber text={this.state.tickMinute} />
<Text style={styles.symText}>:</Text>
<TimeNumber text={this.state.tickSecond} />
</View>}
</View>
</View>
</View>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let backgroundWidth = width;
let backgroundHeight = 70+18+5;
let diffTime;
let rowContainerWidth = Math.ceil((223 * width) / 750);
let rowContainerFocusWidth = Math.ceil((294 * width) / 750);
let separatorWidth = 1;
let DEVICE_RATE = width/375;
let timerContainerWidth = 328 * DEVICE_RATE;
let timerContainerHeight = 43;
let styles = StyleSheet.create({
container: {
marginLeft: -1,
width: backgroundWidth + 2,
height: backgroundHeight,
alignItems: 'center'
},
listContainer: {
overflow: 'hidden',
width: backgroundWidth,
height: 70,
backgroundColor: '#3F3F3F',
},
symText: {
color:'#CE0B24',
left: 3,
},
listView: {
height: 70,
},
tickTimeContainer: {
alignItems: 'flex-end',
flexDirection: 'row',
},
timerbg: {
width: timerContainerWidth,
height: timerContainerHeight,
},
timerText:{
fontSize: 12,
color: '#222222'
},
timerContainer: {
flexDirection : 'row',
position: 'absolute',
top: 53,
alignItems: 'center',
width: timerContainerWidth,
height: timerContainerHeight,
backgroundColor: 'transparent',
},
timerContent: {
position: "absolute",
left: 10,
top: 11,
flexDirection: 'row',
justifyContent:'space-between',
alignItems: 'center',
width:timerContainerWidth -20,
height: 15,
},
contentContainer: {
flexDirection: 'row',
backgroundColor: '#3F3F3F',
},
bottomToolBar: {
top: 200,
height: 44,
backgroundColor: '#000',
},
closeScan: {
left: 10,
width: 25,
height: 25,
top: 10,
},
separator: {
width: separatorWidth,
top: 11,
height: backgroundHeight - 22,
backgroundColor: '#dfe3e2',
},
});
... ...
'use strict';
import React, {Component} from 'react';
import ReactNative, {
View,
Text,
StyleSheet,
} from 'react-native';
export default class PBTimeNumber extends Component {
constructor(props) {
super(props);
}
render() {
let {
text,
} = this.props;
return (
<View style={styles.tickTime}>
<Text style={styles.tickTimeText}>{text}</Text>
</View>
);
}
}
let styles = StyleSheet.create({
tickTime: {
backgroundColor:'#d30018',
alignItems: 'center',
justifyContent: 'center',
left:0,
marginLeft:5,
width:15,
height:15,
borderRadius:3,
},
tickTimeText: {
color: 'white',
fontSize: 9,
},
});
... ...
'use strict'
import React, {Component} from "react";
import {
StyleSheet,
Dimensions,
Platform,
View,
Text,
Image,
FlatList,
TouchableOpacity,
RefreshControl,
InteractionManager,
SectionList
} from "react-native";
import TimerMixin from "react-timer-mixin";
import Immutable from "immutable";
import ProductListView from "./PBProductListView";
import PBTimeListView from "./PBTimeListView";
import Prompt from "../../../coupon/components/coupon/Prompt";
import ProductListCell from "../../../common/components/ListCell/ProductListCell";
import LoadingIndicator from "../../../common/components/LoadingIndicator";
const SECTION_TYPE_SECKILL = 1;
const SECTION_TYPE_DISCOUNT = 2;
export default class PanicBuying extends Component {
constructor(props) {
super(props);
this.renderItem = this.renderItem.bind(this);
this.renderListHeaderComponent = this.renderListHeaderComponent.bind(this);
this.renderDiscountSection = this.renderDiscountSection.bind(this);
this._onPressTimeItem = this._onPressTimeItem.bind(this);
this.isFetching = false;
this.tipMessage = '';
this.queryActivityInfo = Immutable.fromJS({});
this.firstLaunch = true;
this.renderDiscountProduct = this.renderDiscountProduct.bind(this)
this._updateStatusProductList = this._updateStatusProductList.bind(this);
this.state = {
needUdpate: false,
};
}
componentDidMount() {
if (Platform.OS === 'ios') {
// this.timer = TimerMixin.setTimeout(() => {
// this.listView && this.listView.getScrollResponder().startPullToRefresh();
// }, 0);
this.props.onRefresh && this.props.onRefresh();
} else {
this.props.onRefresh && this.props.onRefresh();
}
}
_updateStatusProductList() {
this.state = {
needUdpate :true,
}
this.props.updateStatusProductList();
}
componentWillUnmount() {
this.timer && TimerMixin.clearTimeout(this.timer);
}
componentWillReceiveProps(nextProps) {
this.firstLaunch = false;
}
_onPressTimeItem(activity) {
this.props.onPressTimeItem(activity);
this.props.onRefresh && this.props.onRefresh();
}
renderHeader() {
if (this.queryActivityInfo && this.queryActivityInfo.secKillProductVoList && this.queryActivityInfo.secKillProductVoList.size > 0) {
return (
<PBTimeListView
resource={this.queryActivityInfo.secKillProductVoList.toArray()}
onPressTimeItem={this._onPressTimeItem}
onFocusToCurStartedActivity={this.props.onFocusToCurStartedActivity}
curActivity={this.props.curActivity}
diff={diff}
updateStatusProductList={this._updateStatusProductList}
updateStatusCurActivity={this.props.updateStatusCurActivity}
/>
);
}
return null
}
renderListHeaderComponent() {
if (this.queryActivityInfo.secKillProductVoList.size == 0 && !this.firstLaunch) {
return (
<View style={styles.seckillEndView}>
<Text style={{fontSize: 16, color: 'black'}}>来晚啦~限时抢购已结束</Text>
</View>
);
} else {
return null;
}
}
renderSectionHeader({section: {type, title}}) {
if (type == SECTION_TYPE_DISCOUNT) {
return <View style={styles.sectionHeaderContainer}>
<View style={styles.sectionLine}/>
<Text style={styles.sectionHeaderText}>{title}</Text>
<View style={{
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
height: 0.5,
backgroundColor: '#E0E0E0'
}}/>
</View>
}
return null
}
renderSectionFooter({section: {type}}) {
if (type == SECTION_TYPE_SECKILL) {
return <View style={styles.descriptionContainer}>
<Text style={[styles.descriptionText, {fontWeight: 'bold'}]}>{'限时抢购活动说明\n'}</Text>
<Text
numberOfLines={0}
style={styles.descriptionText}>
{"1. 限时抢购商品活动开始后,在详情页抢购,提前加入购物车无效;\n2. 限时抢购数量有限,抢完即止;\n3. 限时抢购商品限购5件, 不能使用优惠券或优惠码;\n4. 活动最终解释权归YOHO!BUY有货所有。"}
</Text>
</View>
}
return null
}
renderItem({item, index, section}) {
let {
curActivity,
} = this.props;
curActivity = curActivity.toJS();
let P_NAME = 'aFP_PanicBuying';
if (Platform.OS === 'ios') {
P_NAME = 'iFP_PanicBuying';
}
item.yh_exposureData = {
P_NAME: P_NAME,
PRD_NUM: Number(index)+1,
PRD_SKN: item.productSkn,
TAB_ID: Number(curActivity.index) + 1,
TAB_NAME : curActivity.activityDate,
exposureEnd: 1,
}
if (this.queryActivityInfo.secKillProductVoList.size && item.secKillPrice) {
return (
<ProductListView
index={index}
rowData={item}
onPressGuangShopWithURL={this.props.onPressGuangShopWithURL}
onPressProductItem={this.props.onPressProductItem}
onPressRemindBtn={this.props.onPressRemindBtn}
tipMessage={this.tipMessage}
/>
);
}
return null;
}
renderDiscountProduct({item, index}) {
let paddingLeft = index % 2 === 1 ? rowMarginHorizontal / 2 : rowMarginHorizontal;
let customStyle = index === 0 || index === 1 ? {
paddingLeft
} : {
paddingLeft
};
return <ProductListCell
style={
[styles.listContainer, customStyle]
}
key={'row' + index}
rowID={index}
data={item}
onPressProduct={this.props.onPressProduct}
/>
}
renderDiscountSection({item}) {
return <FlatList
data={item}
style={{backgroundColor: 'white'}}
numColumns={2}
renderItem={this.renderDiscountProduct}
/>
}
_renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
return (
<View key={'separator' + sectionID + rowID} style={styles.separator}/>
);
}
render() {
let {
isFetching,
error,
queryActivityInfo,
queryProductList,
tipMessage,
ptr,
localServerTimeDiff,
curActivity,
discountProduct,
} = this.props;
this.isFetching = isFetching;
this.queryActivityInfo = queryActivityInfo;
this.tipMessage = tipMessage;
diff = localServerTimeDiff;
let isPullToRefresh = ptr && isFetching;
let sections = [
{title: null, type: SECTION_TYPE_SECKILL, data: queryProductList ? queryProductList : []},
];
return (
<View style={styles.container}>
{this.renderHeader()}
<SectionList
renderItem={this.renderItem}
contentContainerStyle={styles.contentContainer}
ListHeaderComponent={this.renderListHeaderComponent}
renderSectionFooter={this.renderSectionFooter}
renderSectionHeader={this.renderSectionHeader}
ItemSeparatorComponent={this._renderSeparator}
stickySectionHeadersEnabled={false}
onRefreshData={() => this.props.onRefresh && this.props.onRefresh()}
sections={sections}
yh_viewVisible={true}
/>
<LoadingIndicator isVisible={isPullToRefresh}/>
{tipMessage != '' ?
<Prompt
text={tipMessage}
duration={800}
onPromptHidden={this.props.onClearTipMessage}
/>
: null
}
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let diff = 0;
let rowWidth = Math.ceil(137.5 * width / 320);
let rowMarginHorizontal = (width - rowWidth * 2) / 3;
let styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'transparent',
},
contentContainer: {
// flexDirection: 'row',
// flexWrap: 'wrap',
},
seckillEndView: {
height: 200,
width: width,
alignItems: 'center',
justifyContent: 'center',
},
listContainer: {
width: width / 2,
backgroundColor: 'white'
},
brandFilterContainer: {
marginLeft: -1,
width: width + 2,
height: 37,
borderTopColor: '#e5e5e5',
borderBottomColor: '#e5e5e5',
borderWidth: 0.5,
},
descriptionContainer: {
paddingTop: 20,
paddingBottom: 10,
paddingLeft: 15,
paddingRight: 15,
},
descriptionText: {
color: '#b0b0b0',
fontSize: 12,
// lineHeight:17,
},
sectionHeaderContainer: {
width: width,
paddingTop: 10,
paddingBottom: 10,
paddingLeft: 15,
backgroundColor: 'white',
alignItems: 'center',
flexDirection: 'row'
},
sectionHeaderText: {
fontSize: 14,
marginLeft: 10,
color: '#444444',
fontFamily: 'PingFang-SC-Medium'
},
separator: {
position: 'absolute',
left: 15,
right: 0,
bottom: 0,
height: 0.5,
backgroundColor: '#e5e5e5',
},
sectionLine: {width: 2, height: 15, backgroundColor: '#444444', marginLeft: 2}
});
... ...
import keyMirror from 'key-mirror';
export default keyMirror({
SET_PLATFORM: null,
SET_HOST: null,
SET_CHANNEL: null,
SET_TYPE: null,
SET_START_TIME: null,
QUERY_ACTIVITY_REQUEST: null,
QUERY_ACTIVITY_SUCCESS: null,
QUERY_ACTIVITY_FAILURE: null,
QUERY_PRODUCT_LIST_REQUEST: null,
QUERY_PRODUCT_LIST_SUCCESS: null,
QUERY_PRODUCT_LIST_FAILURE: null,
QUERY_DISCOUNT_PRODUCT_LIST_REQUEST:null,
QUERY_DISCOUNT_PRODUCT_LIST_SUCCESS:null,
QUERY_DISCOUNT_PRODUCT_LIST_FAILURE:null,
QUERY_PRODUCT_AND_REMIND_LIST_REQUEST: null,
QUERY_PRODUCT_AND_REMIND_LIST_SUCCESS: null,
QUERY_PRODUCT_AND_REMIND_LIST_FAILURE: null,
SHOW_TIP_MESSAGE: null,
CLEAR_TIP_MESSAGE: null,
UPDATE_SECKILL_PRODUCT_VO_LIST: null,
UPDATE_SECKILL_PRODUCT_LIST: null,
});
... ...
'use strict'
import React, {Component} from "react";
import ReactNative, {StyleSheet, Dimensions, Platform, View, NativeModules} from "react-native";
import {bindActionCreators} from "redux";
import {connect} from "react-redux";
import {Map} from "immutable";
import * as panicbuyingActions from "../reducers/panicbuying/panicbuyingActions";
import * as discountProductActions from "../reducers/discountProduct/DiscountProductActions";
import PanicBuying from "../components/panicbuying/PanicBuying";
const actions = [
panicbuyingActions,
discountProductActions
];
function mapStateToProps(state) {
return {
...state
};
}
function mapDispatchToProps(dispatch) {
const creators = Map()
.merge(...actions)
.filter(value => typeof value === 'function')
.toObject();
return {
actions: bindActionCreators(creators, dispatch),
dispatch
};
}
class PanicBuyingContainer extends Component {
constructor(props) {
super(props);
this._onPressTimeItem = this._onPressTimeItem.bind(this);
this._onPressProductItem = this._onPressProductItem.bind(this);
this._onPressRemindBtn = this._onPressRemindBtn.bind(this);
this._onPressGuangShopWithURL = this._onPressGuangShopWithURL.bind(this);
this._onRefresh = this._onRefresh.bind(this);
this._onClearTipMessage = this._onClearTipMessage.bind(this);
this._onFocusToCurStartedActivity = this._onFocusToCurStartedActivity.bind(this);
this._onFetchDiscountProductList = this._onFetchDiscountProductList.bind(this);
this._onEndReached = this._onEndReached.bind(this);
this._onPressProduct = this._onPressProduct.bind(this);
this._updateStatusProductList = this._updateStatusProductList.bind(this);
this._updateStatusCurActivity = this._updateStatusCurActivity.bind(this);
}
_updateStatusProductList() {
this.props.actions.updateStatusProductList();
}
_updateStatusCurActivity() {
this.props.actions.updateStatusCurActivity();
}
_onPressProduct(product) {
this.props.actions.clickProductItem(product);
let productSkn = product && product.get('product_skn', 0);
if (!productSkn) {
return;
}
let pageName = 'iFP_Alliance';
if (Platform.OS === 'android') {
pageName = 'aFP_Alliance';
}
let url = `http://m.yohobuy.com?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":"${productSkn}", "from_page_name":"${pageName}"}}`;
NativeModules.YH_CommonHelper.jumpWithUrl(url);
}
_onPressTimeItem(activity) {
this.props.actions.clickActivityTimeItem(activity);
}
_onPressProductItem(product, index) {
this.props.actions.clickProductItem(product);
let {
curActivity,
} = this.props.panicbuying;
curActivity = curActivity.toJS();
let P_NAME = 'aFP_PanicBuying';
if (Platform.OS === 'ios') {
P_NAME = 'iFP_PanicBuying';
}
//埋点
let params = {
P_NAME: P_NAME,
TAB_ID: Number(curActivity.index) + 1,
TAB_NAME : curActivity.activityDate,
PRD_NUM: Number(index) + 1,
PRD_SKN: product.productSkn
};
ReactNative.NativeModules.YH_CommonHelper.logEvent('YB_SECKILL_TAB_LIST_C', params);
}
_onPressGuangShopWithURL(url) {
if (url && url.length) {
NativeModules.YH_CommonHelper.jumpWithUrl(url);
}
}
_onPressRemindBtn(product) {
this.props.actions.clickRemindBtn(product);
}
_onRefresh(activityId) {
this.props.actions.refreshList(activityId);
}
_onClearTipMessage() {
this.props.actions.clearTipMessage();
}
_onFocusToCurStartedActivity(activity) {
if (this.props.panicbuying.ptr) {
return;
}
this.props.actions.clickActivityTimeItem(activity);
// this.props.actions.getSeckillQueryActivity(activity.startTime / 1000);
}
_onFetchDiscountProductList() {
// this.props.actions.getDiscountProductList()
}
_onEndReached() {
// this.props.actions.getDiscountProductList()
}
render() {
let {
isFetching,
error,
queryActivityInfo,
queryProductList,
queryRemindList,
tipMessage,
ptr,
curActivity,
localServerTimeDiff,
} = this.props.panicbuying;
if (queryProductList) {
queryProductList = queryProductList.toJS();
}
let productList = queryProductList[curActivity.get('activityId')];
let discountProduct = this.props.discountProduct;
return (
<PanicBuying
isFetching={isFetching}
error={error}
ptr={ptr}
queryActivityInfo={queryActivityInfo}
queryProductList={productList}
queryRemindList={queryRemindList}
tipMessage={tipMessage}
curActivity={curActivity}
discountProduct={discountProduct}
localServerTimeDiff={localServerTimeDiff}
onPressTimeItem={this._onPressTimeItem}
onPressProductItem={this._onPressProductItem}
onPressRemindBtn={this._onPressRemindBtn}
onPressGuangShopWithURL={this._onPressGuangShopWithURL}
onRefresh={this._onRefresh}
onEndReached={this._onEndReached}
onFetchDiscountProductList={this._onFetchDiscountProductList}
onClearTipMessage={this._onClearTipMessage}
onFocusToCurStartedActivity={this._onFocusToCurStartedActivity}
onPressProduct={this._onPressProduct}
updateStatusProductList={this._updateStatusProductList}
updateStatusCurActivity={this._updateStatusCurActivity}
/>
);
}
}
let styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default connect(mapStateToProps, mapDispatchToProps)(PanicBuyingContainer);
... ...
'use strict';
import ReactNative from 'react-native';
const {
SET_PLATFORM,
SET_CHANNEL,
SET_HOST,
} = require('../../constants/actionTypes').default;
export function setPlatform(platform) {
return {
type: SET_PLATFORM,
payload: platform
};
}
export function setChannel(channel) {
return {
type: SET_CHANNEL,
payload: channel
};
}
export function setHost(host) {
return {
type: SET_HOST,
payload: host
};
}
... ...
'use strict';
import {Record, List, Map} from 'immutable';
let InitialState = Record({
platform: 'ios', // ios, android
channel: 1, // 1 - boy, 2 - girl, 3 - kid, 4 - lifestyle, 5 - yoho
host:'http://api.yoho.cn',
});
export default InitialState;
... ...
'use strict';
import InitialState from './appInitialState';
const {
SET_PLATFORM,
SET_CHANNEL,
SET_HOST,
} = require('../../constants/actionTypes').default;
const initialState = new InitialState;
export default function appReducer(state = initialState, action) {
if (!(state instanceof InitialState)) return initialState.merge(state);
switch (action.type) {
case SET_PLATFORM:
return state.set('platform', action.payload);
case SET_CHANNEL:
return state.set('channel', action.payload);
case SET_HOST:{
return state.set('host',action.payload);
}
}
return state;
}
... ...
'use strict';
import DiscountProductService from "../../services/DiscountProductService";
import Immutable from "immutable";
const {
QUERY_DISCOUNT_PRODUCT_LIST_REQUEST,
QUERY_DISCOUNT_PRODUCT_LIST_SUCCESS,
QUERY_DISCOUNT_PRODUCT_LIST_FAILURE,
} = require('../../constants/actionTypes').default;
export function queryDiscountProductListRequest() {
return {
type: QUERY_DISCOUNT_PRODUCT_LIST_REQUEST,
}
}
export function queryDiscountProductListSuccess(json) {
return {
type: QUERY_DISCOUNT_PRODUCT_LIST_SUCCESS,
payload: json
}
}
export function queryDiscountProductListFailure(error) {
return {
type: QUERY_DISCOUNT_PRODUCT_LIST_FAILURE,
payload: error
}
}
/*
* 限时热促商品列表
*/
export function getDiscountProductList() {
return (dispatch, getState) => {
let {app, discountProduct} = getState();
let {isFetching, endReached, currentPage, pageSize, type} = discountProduct
if (isFetching || endReached) {
return;
}
let channel = app.channel;
let page = currentPage + 1;
dispatch(queryDiscountProductListRequest());
return new DiscountProductService(app.host).fetchDiscountProductList(type, channel, pageSize, page)
.then(json => {
let payload = {}
if (json.page > 1) {
let oldList = discountProduct.get('list');
let newList = [...oldList, ...(json.product_list != null ? json.product_list.map(item=>Immutable.fromJS(item)) : [])];
payload.list = newList;
} else {
payload.list = json.product_list != null ? json.product_list.map(item=>Immutable.fromJS(item)) : [];
}
payload.endReached = (payload.list.length == 0) || (json.page == json.page_total);
payload.currentPage = json.page;
dispatch(queryDiscountProductListSuccess(payload));
})
.catch(error => {
dispatch(queryDiscountProductListFailure(error));
});
};
}
\ No newline at end of file
... ...
'use strict';
import {Record} from "immutable";
let InitialState = Record({
contentCode: 'b78b32ed81b18dde8ac84fd33602b88b',
isFetching: false,
list: [],
currentPage: 0,
endReached: false,
similarIndex: -1,
total: 0,
type: 'discount',
pageSize: 60,
pageCount: 0,
});
export default InitialState;
... ...
'use strict';
import InitialState from "./DiscountProductInitialState";
import Immutable from "immutable";
const {
QUERY_DISCOUNT_PRODUCT_LIST_REQUEST,
QUERY_DISCOUNT_PRODUCT_LIST_SUCCESS,
QUERY_DISCOUNT_PRODUCT_LIST_FAILURE,
} = require('../../constants/actionTypes').default;
const initialState = new InitialState;
export default function DiscountProductReducer(state = initialState, action) {
switch (action.type) {
case QUERY_DISCOUNT_PRODUCT_LIST_FAILURE: {
return state.set('isFetching', false);
}
case QUERY_DISCOUNT_PRODUCT_LIST_SUCCESS: {
let json = action.payload;
return state.set('isFetching', false)
.set('list', json.list)
.set('currentPage', json.currentPage)
.set('endReached', json.endReached);
}
case QUERY_DISCOUNT_PRODUCT_LIST_REQUEST: {
return state.set('isFetching', true);
}
}
return state;
}
... ...
import {combineReducers} from "redux";
import app from "./app/appReducer";
import panicbuying from "./panicbuying/panicbuyingReducer";
import discountProduct from "./discountProduct/DiscountProductReducer";
const rootReducer = combineReducers({
app,
panicbuying,
discountProduct,
});
export default rootReducer;
... ...
'use strict';
import ReactNative from 'react-native';
import SeckillService from '../../services/PanicbuyingService';
import Immutable, {Map} from 'immutable';
import PanicbuyingService from '../../services/PanicbuyingService';
const Platform = require('Platform');
const moment = require('moment');
const {
SET_START_TIME,
QUERY_ACTIVITY_REQUEST,
QUERY_ACTIVITY_SUCCESS,
QUERY_ACTIVITY_FAILURE,
QUERY_PRODUCT_LIST_REQUEST,
QUERY_PRODUCT_LIST_SUCCESS,
QUERY_PRODUCT_LIST_FAILURE,
QUERY_PRODUCT_AND_REMIND_LIST_REQUEST,
QUERY_PRODUCT_AND_REMIND_LIST_SUCCESS,
QUERY_PRODUCT_AND_REMIND_LIST_FAILURE,
SHOW_TIP_MESSAGE,
CLEAR_TIP_MESSAGE,
UPDATE_SECKILL_PRODUCT_VO_LIST,
UPDATE_SECKILL_PRODUCT_LIST,
} = require('../../constants/actionTypes').default;
/**
* [时间缺0补0]
*/
const _timeFormat = (tick) => {
return tick < 10 ? `0${tick}` : tick;
};
export function queryActivityRequest() {
return {
type: QUERY_ACTIVITY_REQUEST,
};
}
export function queryActivitySuccess(json) {
return {
type: QUERY_ACTIVITY_SUCCESS,
payload: json
};
}
export function queryActivityFailure(error) {
return {
type: QUERY_ACTIVITY_FAILURE,
payload: error
};
}
export function queryProductListRequest(activity) {
return {
type: QUERY_PRODUCT_LIST_REQUEST,
payload: activity
}
}
export function queryProductListSuccess(json) {
return {
type: QUERY_PRODUCT_LIST_SUCCESS,
payload: json
}
}
export function queryProductListFailure(error) {
return {
type: QUERY_PRODUCT_LIST_FAILURE,
payload: error
}
}
export function queryProductAndRemindListRequest(activity) {
return {
type: QUERY_PRODUCT_AND_REMIND_LIST_REQUEST,
payload: activity
}
}
export function queryProductAndRemindListSuccess(json) {
return {
type: QUERY_PRODUCT_AND_REMIND_LIST_SUCCESS,
payload: json
}
}
export function queryProductAndRemindListFailure(error) {
return {
type: QUERY_PRODUCT_AND_REMIND_LIST_FAILURE,
payload: error
}
}
export function showTipMessage(message) {
return {
type: SHOW_TIP_MESSAGE,
payload: message
}
}
export function clearTipMessage() {
return {
type:CLEAR_TIP_MESSAGE,
}
}
export function updateSecKillProductVoList(json) {
return {
type: UPDATE_SECKILL_PRODUCT_VO_LIST,
payload: json
}
}
export function updateSecKillProductList(json) {
return {
type: UPDATE_SECKILL_PRODUCT_LIST,
payload: json
}
}
export function setStartTime(startTime) {
startTime = moment(startTime, 'YYYYMMDDHHmmss').unix();
return {
type: SET_START_TIME,
payload: startTime,
};
}
/*
* 秒杀时间栏
*/
export function getSeckillQueryActivity(cid = 0) {
return (dispatch, getState) => {
let {app, panicbuying} = getState();
dispatch(queryActivityRequest());
return new PanicbuyingService(app.host).fetchQueryActivity()
.then(json => {
if (json.secKillProductVoList && json.secKillProductVoList.length) {
let processedTimeInfo = parseActivityTimeList(json, cid);
let queryActivityInfo = processedTimeInfo.newQueryActivityInfo;
let focusActivity = processedTimeInfo.focusActivity;
dispatch(queryActivitySuccess({queryActivityInfo, focusActivity}));
if (Date.now() < focusActivity.startTime) {
dispatch(getSeckillProductRemindList(focusActivity));
} else {
dispatch(getSeckillProductList(focusActivity));
}
} else {
dispatch(queryActivityFailure({error:'来晚啦~秒杀已结束'}));
}
})
.catch(error => {
dispatch(queryActivityFailure(error));
dispatch(showTipMessage(error.message));
});
};
}
/*
* 秒杀商品列表
*/
export function getSeckillProductList(activity) {
return (dispatch, getState) => {
let {app, panicbuying} = getState();
let {queryRemindList, queryProductList, curActivity} = panicbuying;
if (!activity) {
activity = curActivity.toJS();
}
dispatch(queryProductListRequest(activity));
queryRemindList = queryRemindList.toJS();
return new PanicbuyingService(app.host).fetchQueryProductList(activity.activityId)
.then(json => {
let productList = [];
if (queryRemindList && queryRemindList.length > 0) {
productList = productAddFlag(json, queryRemindList);
} else {
productList = productAddFlag(json);
}
queryProductList = queryProductList.toJS();
queryProductList[activity.activityId] = productList;
dispatch(queryProductListSuccess(queryProductList));
})
.catch(error => {
dispatch(queryProductListFailure(error));
});
};
}
/*
* 秒杀商品列表
*/
export function getSeckillProductRemindList(activity) {
return (dispatch, getState) => {
let queryProductRemindList = (activity, uid) => {
dispatch(queryProductAndRemindListRequest(activity));
let {app, panicbuying} = getState();
let {queryProductList} = panicbuying;
Promise.all([
new PanicbuyingService(app.host).fetchQueryProductList(activity.activityId),
new PanicbuyingService(app.host).fetchQueryRemindList(activity.activityId, uid),
]).then(result => {
let productList = result[0];
let remindList = result[1];
productList = productAddFlag(productList, remindList);
queryProductList = queryProductList.toJS();
queryProductList[activity.activityId] = productList;
dispatch(queryProductAndRemindListSuccess({queryProductList,remindList}));
})
.catch(error => {
dispatch(queryProductAndRemindListFailure(error));
});
}
ReactNative.NativeModules.YH_CommonHelper.uid()
.then(uid => {
queryProductRemindList(activity, uid);
})
.catch(error => {
dispatch(getSeckillProductList(activity));
});
};
}
export function addCancelUserReminder(method='app.seckill.addUserReminder', activityId=0, productSkn=0, uid=0, secKillId=0, okTip='', failTip='') {
return (dispatch, getState) => {
let {app, panicbuying} = getState();
let {queryProductList, curActivity} = panicbuying;
dispatch(clearTipMessage());
return new PanicbuyingService(app.host).addCancelUserReminder(method,activityId,productSkn,uid,secKillId)
.then(json => {
//更新提醒状态
let remindFlag;
if (method === 'app.seckill.addUserReminder') {
remindFlag = true;
} else {
remindFlag = false;
}
queryProductList = queryProductList.toJS();
let curActivity = {};
queryProductList[activityId].forEach((productItem, i) => {
if (productItem.id === secKillId) {
productItem.remindFlag = remindFlag;
}
});
dispatch(showTipMessage(okTip));
dispatch(updateSecKillProductList(queryProductList));
})
.catch(error => {
dispatch(showTipMessage(failTip));
});
};
}
export function clickActivityTimeItem(activity) {
return (dispatch, getState) => {
let {app, panicbuying} = getState();
let {queryActivityInfo} = panicbuying;
queryActivityInfo = queryActivityInfo.toJS();
let curActivity = activity;
queryActivityInfo.secKillProductVoList.forEach((activityTimeItem, i) => {
if (activityTimeItem.activityId === activity.activityId) {
curActivity = activityTimeItem;
activityTimeItem.focus = true;
} else {
activityTimeItem.focus = false;
}
});
let secKillProductVoList = queryActivityInfo.secKillProductVoList;
dispatch(updateSecKillProductVoList({secKillProductVoList, curActivity}));
};
}
export function clickProductItem(product) {
return (dispatch, getState) => {
if (!product.secKillSku || product.secKillSku.length == 0) {
return;
}
let skn = product.secKillSku[0].productSkn;
//
let url = `http://m.yohobuy.com?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":"${skn}", "is_seckill": "Y","tags_filter":"","from_page_name":"${Platform.OS === 'ios'?'iFP_Seckill':'aFP_Seckill'}"}}`;
ReactNative.NativeModules.YH_CommonHelper.jumpWithUrl(url);
}
}
export function clickRemindBtn(product) {
return (dispatch, getState) => {
ReactNative.NativeModules.YH_CommonHelper.uid()
.then(uid => {
queryRemindList(uid);
})
.catch(error => {
ReactNative.NativeModules.YH_CommonHelper.login()
.then(uid => {
dispatch(clickActivityTimeItem(product));
queryRemindList(uid);
})
.catch(error => {
});
});
let queryRemindList = (uid) => {
let {app, panicbuying} = getState();
let {queryProductList} = panicbuying;
if (!product.secKillSku || product.secKillSku.length == 0) {
return;
}
let skn = product.secKillSku[0].productSkn;
let actionName,
action,
params,
on_off,
method;
let okTip,
failTip,
result;
// default
on_off = true;
action = 'go.addSecKill';
method = 'app.seckill.addUserReminder';
params = {
skn: skn,
startTime: product.startTime,
productName: product.productName,
};
okTip = '设置提醒成功,将在开抢3分钟前提醒';
failTip = '设置提醒失败';
if (product.remindFlag) {
on_off = false;
action = 'go.delSecKill';
okTip = '取消提醒成功';
failTip = '取消提醒失败';
method = 'app.seckill.cancelUserReminder';
}
ReactNative.NativeModules.YH_PanicBuyingHelper.remindTip({
method: action,
arguments: params,
})
.then(flag => { //成功
dispatch(addCancelUserReminder(method, product.activityId, skn,uid, product.id, okTip, failTip));
})
.catch(error => {
dispatch(showTipMessage('请到设置中开启日历授权'));
});
};
}
}
export function refreshList() {
return (dispatch, getState) => {
let {app, panicbuying} = getState();
let {queryActivityInfo,queryProductList,curActivity} = panicbuying;
if (curActivity.get('activityId') !== 0 && queryActivityInfo.secKillProductVoList && queryActivityInfo.secKillProductVoList.size > 0) {
queryActivityInfo.secKillProductVoList.forEach((activityInfo, i) => {
if (activityInfo.get('activityId') === curActivity.get('activityId')) {
// dispatch(getSeckillQueryActivity(activityInfo.get('startTime')/1000));
dispatch(getSeckillQueryActivity(activityInfo.get('id')));
}
});
} else {
dispatch(getSeckillQueryActivity());
}
};
}
/**
* 秒杀商品 添加 自定义属性
* ----------------------------------------
* 已开抢
* product.over [APP,H5: 1.已抢光 2.过了endTime]
* product.isSeckill [APP,H5 秒杀中, 与over互斥]
* 抢购中:
* product.over
* product.isSeckill
* 即将开抢:
* product.wait = true
* product.remindFlag = true [APP: 已添加提醒]
* product.remindFalg = false [APP: 默认提醒状态]
* Product.hideRemind = true [APP: queryRemindList接口失败的情况下]
* Product.specialState = 0 1,明天开抢 2.2天后开抢
*/
function productAddFlag(productList, remindList) {
let now = Date.now();
productList
// .sort((a, b) => b.orderBy - a.orderBy)
.forEach(product => {
let startTime = product.startTime * 1000; // s to ms
let endTime = product.endTime * 1000;
product.remindFlag = false;
product.readableTime = moment.unix(product.startTime).format('MM月DD日 HH:mm');
if (now < startTime) { // 未开抢
product.wait = true;
product.isSeckill = true;
if (!remindList) {
product.hideRemind = true;
} else if (remindList.length) {
for (let i = 0, j = remindList.length; i < j; i++) {
if (remindList[i].productSkn === product.productSkn) { // remind on;
product.remindFlag = true;
remindList.splice(i, 1);
break;
}
}
}
} else if (product.secKillStatus === 0 || (now > endTime)) { // 确实已抢光, 过了秒杀时间
product.over = true;
}
});
return productList;
}
function parseActivityTimeList(json, cid=0) {
let currentTime = json && json.currentTime ? json.currentTime * 1000 : Date.new();
let secKillProductVoList = json && json.secKillProductVoList ? json.secKillProductVoList : [];
let newActivityTimeList = [];
let focusIndex = false;
// newActivityTimeList = secKillProductVoList.sort((a,b) => a.startTime - b.startTime);// orderBy startTime ASC
newActivityTimeList = secKillProductVoList;
if (cid) {
focusIndex = newActivityTimeList.findIndex(activityTimeItem=> activityTimeItem.id === cid);
if (focusIndex !== -1) {
newActivityTimeList[focusIndex].focus = true;
focusIndex = true;
} else {
focusIndex = false;
}
}
let now = new Date();
newActivityTimeList.forEach((activityTimeItem, i) => {
let date,
hour = 0,
minute = 0;
activityTimeItem.startTime *= 1000;
activityTimeItem.endTime *= 1000;
activityTimeItem.index = i;
date = new Date(activityTimeItem.startTime);
hour = date.getHours();
minute = date.getMinutes();
activityTimeItem.time = `${_timeFormat(hour)}:${_timeFormat(minute)}`;
let title = (date.getMonth()+1) + '月' + date.getDate() + '日';
activityTimeItem.activityDate = activityTimeItem.tab ? activityTimeItem.tab : title;
activityTimeItem.activityHour = hour;
activityTimeItem.specialState = 0;
let offsetDate = getDiffDays(date, now);
activityTimeItem.specialState = offsetDate < 0 ? 0 : offsetDate;
if (currentTime > activityTimeItem.startTime) {
if(currentTime > activityTimeItem.endTime){
activityTimeItem.over = true;
}else{
activityTimeItem.now = true;
// focusIndex || (activityTimeItem.focus = focusIndex = true);
}
} else {
activityTimeItem.wait = true;
}
});
if (newActivityTimeList.length && newActivityTimeList.findIndex(activityTimeItem => activityTimeItem.focus) < 0) {
// 默认focus第一个
newActivityTimeList[0].focus = true;
}
let focusActivity = newActivityTimeList.find(activityTimeItem => activityTimeItem.focus);
let newQueryActivityInfo = {
currentTime:currentTime,
secKillProductVoList: newActivityTimeList,
}
return {
newQueryActivityInfo,
focusActivity,
};
}
//date1 减去 date2 相差的天数
function getDiffDays(date1, date2){
let nDate1 = new Date();
nDate1 = new Date(date1.getFullYear(),date1.getMonth(),date1.getDate());
let newDate2 = new Date(date2);
newDate2 =new Date(date2.getFullYear(),date2.getMonth(),date2.getDate());
let diffDays = (nDate1 - newDate2) / 1000 / 60 / 60 / 24;
return diffDays;
}
export function updateStatusProductList(activity) {
return (dispatch, getState) => {
let {app, panicbuying} = getState();
let {queryRemindList, queryProductList, curActivity, localServerTimeDiff} = panicbuying;
if (!activity) {
activity = curActivity.toJS();
}
queryProductList = queryProductList.toJS();
let productList = queryProductList[activity.activityId];
productList && productList.forEach((product, i) => {
let nowServerTime = Date.now() + localServerTimeDiff;
let startTime = product.startTime * 1000; // s to ms
let endTime = product.endTime * 1000;
if (nowServerTime < startTime) { // 未开抢
product.wait = true;
product.over = false;
// product.now = false;
} else if (nowServerTime > startTime && nowServerTime < endTime) {
product.wait = false;
// product.now = true;
product.over = false;
} else if (product.secKillStatus === 0 || (nowServerTime > endTime)) { // 确实已抢光, 过了秒杀时间
product.wait = false;
// product.now = false;
product.over = true;
}
});
dispatch(updateSecKillProductList(queryProductList));
};
}
export function updateStatusCurActivity() {
return (dispatch, getState) => {
let {app, panicbuying} = getState();
let {queryRemindList, queryActivityInfo, curActivity, localServerTimeDiff} = panicbuying;
curActivity = curActivity.toJS();
let t = Date.now();
let nowServerTime = Date.now() + localServerTimeDiff;
let startTime = curActivity.startTime;
let endTime = curActivity.endTime;
if (nowServerTime < startTime) {
curActivity.wait = true;
curActivity.now = false;
curActivity.over = false;
} else if (nowServerTime > startTime && nowServerTime < endTime) {
curActivity.wait = false;
curActivity.now = true;
curActivity.over = false;
} else {
curActivity.wait = false;
curActivity.now = false;
curActivity.over = true;
}
let secKillProductVoList = queryActivityInfo.secKillProductVoList;
dispatch(updateSecKillProductVoList({secKillProductVoList, curActivity}));
};
}
\ No newline at end of file
... ...
'use strict';
import {Record, List, Map} from 'immutable';
let InitialState = Record({
ptr: false, // 是否下拉刷新
contentCode: 'b78b32ed81b18dde8ac84fd33602b88b',
isFetching: false,
error: null,
startTime: 0,
localServerTimeDiff: 0,
queryActivityInfo: new (Record({
currentTime: 0,
secKillProductVoList: List(),
})),
curActivity: Map(),
queryProductList: Map(),
queryRemindList: List(),
tipMessage: '',
});
export default InitialState;
... ...
'use strict';
import InitialState from './panicbuyingInitialState';
import Immutable, {Map} from 'immutable';
const {
SET_START_TIME,
QUERY_ACTIVITY_REQUEST,
QUERY_ACTIVITY_SUCCESS,
QUERY_ACTIVITY_FAILURE,
QUERY_PRODUCT_LIST_REQUEST,
QUERY_PRODUCT_LIST_SUCCESS,
QUERY_PRODUCT_LIST_FAILURE,
QUERY_PRODUCT_AND_REMIND_LIST_REQUEST,
QUERY_PRODUCT_AND_REMIND_LIST_SUCCESS,
QUERY_PRODUCT_AND_REMIND_LIST_FAILURE,
SHOW_TIP_MESSAGE,
CLEAR_TIP_MESSAGE,
UPDATE_SECKILL_PRODUCT_VO_LIST,
UPDATE_SECKILL_PRODUCT_LIST,
} = require('../../constants/actionTypes').default;
const initialState = new InitialState;
export default function seckillReducer(state=initialState, action) {
switch(action.type) {
case SET_START_TIME: {
return state.set('startTime',action.payload)
}
case QUERY_ACTIVITY_REQUEST: {
return state.set('isFetching', true)
.set('ptr', true)
.set('error', null);
}
case QUERY_ACTIVITY_SUCCESS: {
let timeListInfo = action.payload.queryActivityInfo;
let focusActivity = action.payload.focusActivity;
let diff = Math.round((timeListInfo.currentTime - Date.now()) / 1000)
let newQueryActivity = state.queryActivityInfo.set('currentTime', timeListInfo.currentTime)
.set('secKillProductVoList', Immutable.fromJS(timeListInfo.secKillProductVoList));
return state.set('queryActivityInfo', newQueryActivity)
.set('localServerTimeDiff', diff)
.set('curActivity', Immutable.fromJS(focusActivity))
.set('error', null);
}
case QUERY_ACTIVITY_FAILURE: {
return state.set('isFetching', false)
.set('ptr', false)
.set('error', action.payload);
}
case QUERY_PRODUCT_LIST_REQUEST: {
return state.set('isFetching', true)
.set('ptr', true)
.set('curActivity', Immutable.fromJS(action.payload))
.set('error', null);
}
case QUERY_PRODUCT_LIST_SUCCESS: {
console.log(action.payload);
return state.set('isFetching', false)
.set('ptr', false)
.set('queryProductList', Immutable.fromJS(action.payload))
.set('error', null);
}
case QUERY_PRODUCT_LIST_FAILURE: {
return state.set('isFetching', false)
.set('ptr', false)
.set('error', action.payload);
}
case QUERY_PRODUCT_AND_REMIND_LIST_REQUEST: {
return state.set('isFetching', true)
.set('ptr', true)
.set('curActivity', Immutable.fromJS(action.payload))
.set('error', null);
}
case QUERY_PRODUCT_AND_REMIND_LIST_SUCCESS: {
return state.set('isFetching', false)
.set('ptr', false)
.set('queryProductList', Immutable.fromJS(action.payload.queryProductList))
.set('queryRemindList', Immutable.fromJS(action.payload.remindList))
.set('error', null);
}
case QUERY_PRODUCT_AND_REMIND_LIST_FAILURE: {
return state.set('isFetching', false)
.set('ptr', false)
.set('error', action.payload);
}
case CLEAR_TIP_MESSAGE: {
return state.set('tipMessage', '');
}
case SHOW_TIP_MESSAGE: {
return state.set('tipMessage', Immutable.fromJS(action.payload));
}
case UPDATE_SECKILL_PRODUCT_VO_LIST: {
return state.setIn(['queryActivityInfo', 'secKillProductVoList'], Immutable.fromJS(action.payload.secKillProductVoList))
.set('ptr', true)
.set('isFetching', false)
.set('curActivity', Immutable.fromJS(action.payload.curActivity))
.set('error', null);
}
case UPDATE_SECKILL_PRODUCT_LIST: {
return state.set('queryProductList', Immutable.fromJS(action.payload))
.set('error', null);
}
}
return state;
}
... ...
'use strict';
import Request from "../../common/services/NativeRequest";
export default class DiscountProductService {
constructor(host) {
let baseURL = 'http://api.yoho.cn';
if (host) {
baseURL = host;
}
this.api = new Request(baseURL);
}
async fetchDiscountProductList(type, channel, pageSize, page) {
return await this.api.get({
url: '',
body: {
method: 'app.search.sales',
page,
limit: pageSize,
yh_channel: channel,
type: type,
}
})
.then((json) => {
return json;
})
.catch((error) => {
throw(error);
});
}
}
... ...
'use strict';
import Request from '../../common/services/NativeRequest';
// export default class SeckillService {
export default class PanicbuyingService {
constructor (host) {
console.log(host);
let baseURL = 'http://api.yoho.cn';
if(host){
baseURL = host;
}
this.api = new Request(baseURL);
}
async fetchQueryActivity() {
let seckill_Type = 2;
return await this.api.get({
url: '',
body: {
method: 'app.seckill.queryActivity',
seckill_Type,
}
})
.then((json) => {
return json;
})
.catch((error) => {
throw(error);
});
}
async fetchQueryProductList(activityId) {
let seckill_Type = 2;
return await this.api.get({
url: '',
body: {
method: 'app.seckill.queryProductList',
activityId,
seckill_Type,
}
})
.then((json) => {
return json;
})
.catch((error) => {
throw(error);
});
}
async fetchQueryRemindList(activityId ,uid) {
return await this.api.get({
url: '',
body: {
method: 'app.seckill.queryRemindList',
activityId,
uid,
}
})
.then((json) => {
return json;
})
.catch((error) => {
throw(error);
});
}
async addCancelUserReminder(method, activity_id, product_skn, uid, sec_kill_id) {
return await this.api.get({
url: '',
body: {
method: method,
activity_id,
product_skn,
uid,
sec_kill_id,
}
})
.then((json) => {
return json;
})
.catch((error) => {
throw(error);
});
}
}
... ...
/**
* # configureStore.js
*
* A Redux boilerplate setup
*
*/
'use strict';
/**
* ## Imports
*
* redux functions
*/
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import {createLogger} from 'redux-logger';
/**
* ## Reducer
* The reducer contains the 4 reducers from
* device, global, auth, profile
*/
import reducer from '../reducers';
const logger = createLogger({
predicate: (getState, action) => process.env.NODE_ENV === `development`
});
/**
* ## creatStoreWithMiddleware
* Like the name...
*/
const createStoreWithMiddleware = applyMiddleware(
thunk,
logger
)(createStore);
/**
* ## configureStore
* @param {Object} the state with for keys:
* device, global, auth, profile
*
*/
export default function configureStore(initialState) {
return createStoreWithMiddleware(reducer, initialState);
};
... ...
... ... @@ -119,7 +119,7 @@ export default class Seckill extends Component {
<Text
numberOfLines={0}
style={styles.descriptionText}>
{"1. 秒杀商品限活动开始后,在详情页抢购,提前加入购物车无效;\n2. 秒杀数量有限,抢完即止;\n3. 秒杀商品限购1件, 不能使用优惠券或优惠码;\n4. 活动最终解释权归YOHO!BUY有货所有。"}
{"1. 秒杀商品限活动开始后,在详情页抢购,提前加入购物车无效;\n2. 秒杀数量有限,抢完即止;\n3. 秒杀商品限购5件, 不能使用优惠券或优惠码;\n4. 活动最终解释权归YOHO!BUY有货所有。"}
</Text>
</View>
}
... ...