Authored by LakeR

修复秒杀bug 与UI review by chenlin

... ... @@ -3,7 +3,6 @@
import React, {Component} from "react";
import {View, Text, Image, ListView, StyleSheet, Dimensions, TouchableOpacity} from "react-native";
import SlicedImage from "../../../common/components/SlicedImage";
import DeleteLineText from "../../../common/components/DeleteLineText";
export default class ProductListView extends Component {
... ... @@ -26,7 +25,7 @@ export default class ProductListView extends Component {
let tipState = '';
let btnBgColor = '#d30018';
let btnTextcolor = 'white';
let url = rowData.url;
let url = rowData.shopUrl;
if (rowData.over) {
tipState = '已抢光';
btnBgColor = '#b2b2b2';
... ... @@ -47,64 +46,48 @@ export default class ProductListView extends Component {
this.props.onPressProductItem && this.props.onPressProductItem(rowData);
}}>
<View style={styles.rowContainer}>
<View style = {
styles.leftImage
} >
<Image style={
{
flex: 1,
}
}
source={
{
uri: brandIconUrl
}
}/>
<View style={styles.leftImage}>
<Image style={{flex: 1,}}
source={{uri: brandIconUrl}}/>
{tipState == '已抢光' ?
<View style={
[styles.imageBottomTag, {
backgroundColor: btnBgColor,
position: 'absolute',
}]
} >
<Text style={{color: btnTextcolor}} > {tipState} </Text>
<View style={styles.soldOutContainer}>
<Image source={require('../../images/yqg.png')}/>
</View>
:null }
: null }
</View>
<View style={styles.rowRight}>
<View style={styles.productTitlePrice}>
<Text style={styles.productTitle}
numberOfLines={2}>{rowData.productName}</Text>
<View style={[styles.secKillMarketPriceContainer, {marginTop: 5}]}>
<Text style={styles.productTitle}
numberOfLines={2}>{rowData.productName}</Text>
<View style={{
flexDirection: 'row',
flex: 1,
alignItems: 'flex-end',
justifyContent: 'space-between'
}}>
<View style={{}}>
<Text
style={styles.seckillPrice}>¥{rowData.secKillPrice}</Text>
<DeleteLineText style={{top: 3, left: 8}} text={'¥' + rowData.marketPrice}/>
</View>
</View>
<View style={styles.priceClickTipView}>
<View style={styles.priceClickTipViewLeft}>
{rowData.wait ?
<View style={[styles.secKillMarketPriceContainer, {marginTop: 2}]}>
<Image style={{top: 1.5, marginRight: 2}}
source={require('../../images/time_icon.png')}/>
<Text style={styles.seckillBeginTimeTip}>{rowData.readableTime}开始</Text>
</View>
: null }
style={styles.seckillPrice}>¥{parseFloat(rowData.secKillPrice + "").toFixed(2)}</Text>
<Text style={styles.originPrice}>
{'¥' + parseFloat(rowData.marketPrice + '').toFixed(2)}</Text>
</View>
{tipState == '已抢光' && url && url.length?
<View onPress={()=>{
this.props.onPressGuangShopWithURL && this.props.onPressGuangShopWithURL(url);
}} style={[styles.priceClickTipViewRight, {backgroundColor: 'white', borderColor:'black', borderWidth: 1}]}>
<Text style={{color: 'black'}}>进店逛逛</Text>
</View>
:null}
{tipState != '已抢光'? <TouchableOpacity onPress={() => {
<View style={{justifyContent: 'center'}}>
{tipState == '已抢光' && url && url.length ?
<TouchableOpacity onPress={()=> {
this.props.onPressGuangShopWithURL && this.props.onPressGuangShopWithURL(url);
}} style={[styles.priceClickTipViewRight, {
backgroundColor: 'white',
borderColor: 'black',
borderWidth: 1
}]}>
<Text style={{color: 'black'}}>进店逛逛</Text>
</TouchableOpacity>
: null}
{tipState != '已抢光' ? <TouchableOpacity onPress={() => {
if (this.tipMessage == '') {
if (rowData.wait) {
this.props.onPressRemindBtn && this.props.onPressRemindBtn(rowData);
... ... @@ -128,8 +111,12 @@ export default class ProductListView extends Component {
</View>
}
</TouchableOpacity>:null
}
</TouchableOpacity> : null
}
{rowData.wait &&
<Text style={styles.seckillBeginTimeTip}>{rowData.readableTime + ' 开始'}</Text>}
</View>
</View>
</View>
<View style={styles.separator}/>
... ... @@ -162,30 +149,30 @@ let styles = StyleSheet.create({
leftImage: {
width: adjustPx(imageWidth),
height: adjustPx(imageHeight),
marginRight: adjustPx(10),
resizeMode: 'cover',
},
imageBottomTag: {
width: adjustPx(imageWidth),
height: 30,
marginRight: 10,
marginTop: adjustPx(imageHeight) - 30,
soldOutContainer: {
backgroundColor: '#0000007F',
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
top: 0,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 3,
backgroundColor: '#d0021b',
},
rowRight: {
flexDirection: 'column',
marginLeft: 10,
justifyContent: 'space-between',
flex: 1,
},
priceClickTipView: {
flexDirection: 'row',
justifyContent: 'space-between',
width: width - imageWidth - 35,
height: 50,
// backgroundColor: 'white',
backgroundColor: 'yellow',
},
priceClickTipViewLeft: {
top: 25,
... ... @@ -200,10 +187,7 @@ let styles = StyleSheet.create({
borderRadius: 3,
backgroundColor: '#d0021b',
},
productTitlePrice: {
width: width - imageWidth - 30,
flexDirection: 'column',
},
secKillMarketPriceContainer: {
flexDirection: 'row',
alignItems: 'center'
... ... @@ -227,11 +211,20 @@ let styles = StyleSheet.create({
},
seckillPrice: {
fontSize: 18,
lineHeight: 21,
fontWeight: 'bold',
color: '#d0021b',
},
originPrice: {
textDecorationLine: 'line-through',
color: '#B0B0B0',
fontSize: 12,
lineHeight: 17
},
seckillBeginTimeTip: {
fontSize: 11,
color: '#b0b0b0',
fontSize: 9,
marginTop: 6,
color: '#D0021B',
},
separator: {
position: 'absolute',
... ...
... ... @@ -19,9 +19,8 @@ import Immutable from "immutable";
import ProductListView from "./ProductListView";
import TimeListView from "./TimeListView";
import Prompt from "../../../coupon/components/coupon/Prompt";
import YH_PtrRefresh from "../../../common/components/YH_PtrRefresh";
import ProductListCell from "../../../common/components/ListCell/ProductListCell";
import LoadingIndicator from '../../../common/components/LoadingIndicator';
import LoadingIndicator from "../../../common/components/LoadingIndicator";
const SECTION_TYPE_SECKILL = 1;
const SECTION_TYPE_DISCOUNT = 2;
... ... @@ -82,7 +81,7 @@ export default class Seckill extends Component {
} else if (this.queryActivityInfo.secKillProductVoList.size == 0 && !this.firstLaunch) {
return (
<View style={styles.seckillEndView}>
<Text style={{fontSize: 16,color:'black'}}>来晚啦~秒杀已结束</Text>
<Text style={{fontSize: 16, color: 'black'}}>来晚啦~秒杀已结束</Text>
</View>
);
} else {
... ... @@ -132,17 +131,17 @@ export default class Seckill extends Component {
renderDiscountProduct({item, index}) {
let paddingLeft = index % 2 === 1 ? rowMarginHorizontal / 2 : rowMarginHorizontal;
let customStyle = index === 0 || index === 1 ? {
paddingLeft
} : {
paddingLeft
};
let paddingLeft = index % 2 === 1 ? rowMarginHorizontal / 2 : rowMarginHorizontal;
let customStyle = index === 0 || index === 1 ? {
paddingLeft
} : {
paddingLeft
};
return <ProductListCell
style={
[styles.listContainer, customStyle]
}
style={
[styles.listContainer, customStyle]
}
key={'row' + index}
rowID={index}
data={item}
... ... @@ -153,7 +152,7 @@ export default class Seckill extends Component {
renderDiscountSection({item}) {
return <FlatList
data={item}
style={{backgroundColor:'white'}}
style={{backgroundColor: 'white'}}
numColumns={2}
renderItem={this.renderDiscountProduct}
/>
... ... @@ -178,6 +177,17 @@ export default class Seckill extends Component {
this.tipMessage = tipMessage;
diff = localServerTimeDiff;
let isPullToRefresh = ptr && isFetching;
let sections = [
{title: null, type: SECTION_TYPE_SECKILL, data: queryProductList ? queryProductList : []},
];
if (discountProduct.list && discountProduct.list.length > 0) {
sections.push({
title: '限时热促',
type: SECTION_TYPE_DISCOUNT,
data: discountProduct.list ? [discountProduct.list] : [[]],
renderItem: this.renderDiscountSection
})
}
return (
<View style={styles.container}>
<SectionList
... ... @@ -191,17 +201,9 @@ export default class Seckill extends Component {
onEndReached={() => {
this.props.onEndReached && this.props.onEndReached();
}}
sections={[
{title: null, type: SECTION_TYPE_SECKILL, data: queryProductList ? queryProductList : []},
{
title: '限时热促',
type: SECTION_TYPE_DISCOUNT,
data: discountProduct.list ? [discountProduct.list] : [[]],
renderItem: this.renderDiscountSection
},
]}
sections={sections}
/>
<LoadingIndicator isVisible={isPullToRefresh} />
<LoadingIndicator isVisible={isPullToRefresh}/>
{tipMessage != '' ?
<Prompt
text={tipMessage}
... ... @@ -240,7 +242,7 @@ let styles = StyleSheet.create({
},
listContainer: {
width: width / 2,
backgroundColor:'white'
backgroundColor: 'white'
},
brandFilterContainer: {
marginLeft: -1,
... ...
... ... @@ -35,12 +35,9 @@ export default class TimeForFocus extends Component {
let TimeComponent = null;
if (now) {
TimeComponent = TimeForNow;
}
// else if (over) {
// TimeComponent = TimeForOver;
// } else
if (wait) {
} else if (over) {
TimeComponent = TimeForOver;
} else if (wait) {
TimeComponent = TimeForWait;
}
... ...
... ... @@ -29,14 +29,14 @@ export default class TimeForLostFocus extends Component {
if (now) {
text = '抢购中';
} else if (over) {
text = '已开抢';
text = '已结束';
} else if (wait && !specialState) {
text = '即将开抢';
} else if (specialState) {
if (specialState == 1) {
text = '明天开抢';
} else {
text = '2天后开抢';
text = specialState + '天后开抢';
}
}
... ...
... ... @@ -24,8 +24,8 @@ export default class TimeForOver extends Component {
return (
<View style={styles.rowContainerFocus}>
<Text style={[colorStyle, {fontSize: 13, marginTop: 15, fontWeight: 'bold'}]}>{time} 已开抢</Text>
<Text style={[colorStyle,{fontSize: 10, marginTop: 1}]}>还有商品可以继续抢购</Text>
<Text style={[colorStyle, {fontSize: 13, marginTop: 15, fontWeight: 'bold'}]}>{time} 已结束</Text>
<Text style={[colorStyle,{fontSize: 10, marginTop: 1}]}>数量有限 抢完为止</Text>
</View>
);
}
... ...
... ... @@ -73,7 +73,18 @@ export default class SeckillTimeListView extends Component {
}
_caculateTimerState() {
if (this.curFocusActivity.get('index') == this.secKillProductVoList.length - 1 && this.curFocusActivity.has('now')) {
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) {
this.setState({
tickHour: '',
... ... @@ -81,47 +92,27 @@ export default class SeckillTimeListView extends Component {
tickSecond: '',
tickTimeOut: true,
});
this.props.onRefresh && this.props.onRefresh();
}
} else {
let nextActivity = this.secKillProductVoList[this.curFocusActivity.get('index') + 1];
let nowTime = Date.parse(new Date()) / 1000 + diffTime;
let time = this.curFocusActivity.has('now') ? nextActivity.get('startTime')/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) {
this.setState({
tickHour: '',
tickMinute: '',
tickSecond: '',
tickTimeOut: true,
});
if (this.curFocusActivity.has('now')) {
nextActivity = nextActivity.toJS();
nextActivity.focus = true;
this.curFocusActivity= Immutable.fromJS(nextActivity);
this._scrollToFocusActivity();
this.props.onFocusToCurStartedActivity && this.props.onFocusToCurStartedActivity(nextActivity);
if (this.curFocusActivity.has('now') && nextActivity != undefined) {
nextActivity = nextActivity.toJS();
nextActivity.focus = true;
this.curFocusActivity = Immutable.fromJS(nextActivity);
this._scrollToFocusActivity();
this.props.onFocusToCurStartedActivity && this.props.onFocusToCurStartedActivity(nextActivity);
} else {
this.props.onFocusToCurStartedActivity && this.props.onFocusToCurStartedActivity(this.curFocusActivity.toJS());
}
} else {
this.props.onFocusToCurStartedActivity && this.props.onFocusToCurStartedActivity(this.curFocusActivity.toJS());
}
} 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,
});
}
} 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() {
... ... @@ -139,7 +130,7 @@ export default class SeckillTimeListView extends Component {
componentWillUnmount() {
this.timer && clearInterval(this.timer);
}
}
componentWillReceiveProps(nextProps) {
this.curFocusActivity = nextProps.curActivity;
... ... @@ -151,7 +142,7 @@ export default class SeckillTimeListView extends Component {
_renderRow(rowData, sectionID, rowID) {
rowData = rowData.toJS();
return (
<TouchableOpacity activeOpacity={1.0} onPress={() => {
if (rowData.focus) {
... ... @@ -164,9 +155,10 @@ export default class SeckillTimeListView extends Component {
this.props.onPressTimeItem && this.props.onPressTimeItem(rowData);
}}>
{rowData.focus ? <TimeForFocus
{rowData.focus ? <TimeForFocus
key={'row' + rowID}
time={rowData.time}
endTime={rowData.endTime}
now={rowData.now}
over={rowData.over}
wait={rowData.wait}
... ... @@ -174,18 +166,18 @@ export default class SeckillTimeListView extends Component {
tickHour={this.state.tickHour}
tickMinute={this.state.tickMinute}
tickSecond={this.state.tickSecond}
lastNowTime={(rowID == this.secKillProductVoList.length -1) ? true : false}
lastNowTime={false}
/> : <TimeForLostFocus
key={'row' + rowID}
time={rowData.time}
now={rowData.now}
over={rowData.over}
wait={rowData.wait}
specialState = {
specialState={
rowData.specialState
}
/>
}
}
</TouchableOpacity>
);
... ... @@ -213,9 +205,9 @@ export default class SeckillTimeListView extends Component {
return (
<View style={[styles.container]}>
<View style={{width: width,height: 0.5,backgroundColor: '#e5e5e5',}}/>
<View style={{width: width, height: 0.5, backgroundColor: '#e5e5e5',}}/>
<ListView
ref={(ref)=>this.listView=ref}
ref={(ref)=>this.listView = ref}
contentContainerStyle={[styles.contentContainer]}
enableEmptySections={true}
dataSource={this.dataSource.cloneWithRows(resource)}
... ... @@ -226,14 +218,14 @@ export default class SeckillTimeListView extends Component {
horizontal={true}
scrollsToTop={false}
/>
<View style={{width: width,height: 0.5,backgroundColor: '#e5e5e5',}}/>
<View style={{width: width, height: 0.5, backgroundColor: '#e5e5e5',}}/>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let backgroundWidth= width;
let backgroundWidth = width;
let backgroundHeight = 61;
let diffTime;
let rowContainerWidth = Math.ceil((223 * width) / 750);
... ... @@ -245,11 +237,11 @@ let styles = StyleSheet.create({
marginLeft: -1,
width: backgroundWidth + 2,
height: backgroundHeight,
backgroundColor:'white',
backgroundColor: 'white',
},
contentContainer: {
flexDirection: 'row',
backgroundColor:'white',
backgroundColor: 'white',
},
bottomToolBar: {
top: 200,
... ...
... ... @@ -456,6 +456,7 @@ function parseActivityTimeLsit(json, focusTime=0) {
minute = 0;
activityTimeItem.startTime *= 1000;
activityTimeItem.endTime *= 1000;
activityTimeItem.index = i;
date = new Date(activityTimeItem.startTime);
hour = date.getHours();
... ... @@ -468,24 +469,15 @@ function parseActivityTimeLsit(json, focusTime=0) {
let startDays = Math.floor(now / 1000 / 60 / 60 / 24);
let endDate = Math.floor(activityTimeItem.startTime / 1000 / 60 / 60 / 24);
let offsetDate = endDate - startDays;
if (offsetDate <= 2) {
activityTimeItem.specialState = offsetDate;
}
activityTimeItem.specialState = offsetDate < 0 ? 0 : offsetDate;
if (currentTime > activityTimeItem.startTime) {
if (i < newActivityTimeList.length - 1) {
let nextTime = newActivityTimeList[i + 1].startTime * 1000;
if (currentTime < nextTime) { // 下一个时间段与当前时间来区别是否正在抢购
activityTimeItem.now = true;
focusIndex || (activityTimeItem.focus = focusIndex = true);
} else {
activityTimeItem.over = true;
}
} else {// 大于这个时间段但是后面没有秒抢时间端了,则依然显示抢购中
if(currentTime > activityTimeItem.endTime){
activityTimeItem.over = true;
}else{
activityTimeItem.now = true;
focusIndex || (activityTimeItem.focus = focusIndex = true);
}
... ...
... ... @@ -60,8 +60,7 @@ export default function seckillReducer(state=initialState, action) {
.set('error', null);
}
case QUERY_PRODUCT_LIST_SUCCESS: {
console.log('wwwwwwwwww');
console.log(action.payload);
return state.set('isFetching', false)
... ... @@ -101,7 +100,7 @@ export default function seckillReducer(state=initialState, action) {
case UPDATE_SECKILL_PRODUCT_VO_LIST: {
return state.setIn(['queryActivityInfo', 'secKillProductVoList'], Immutable.fromJS(action.payload.secKillProductVoList))
.set('ptr', true)
.set('isFetching', true)
.set('isFetching', false)
.set('curActivity', Immutable.fromJS(action.payload.curActivity))
.set('error', null);
}
... ...