Authored by 盖剑秋

Part of order detail UI. reviewed by Boss Hai

... ... @@ -7,6 +7,8 @@ import AddressCell from './AddressCell'
import OrderInfoCell from './OrderInfoCell'
import Footer from './Footer'
import PaymentInfoCell from './PaymentInfoCell'
import ExpressCell from './ExpressCell'
import ProductListCell from './ProductListCell'
import ReactNative, {
View,
... ... @@ -34,10 +36,16 @@ export default class Detail extends Component {
switch (sectionID) {
case 'address':
return (<AddressCell channel={this.props.channel} data={rowData}/>);
break
break;
case 'orderInfo':
return (<OrderInfoCell data={rowData}/>);
break
break;
case 'express':
return (<ExpressCell data={rowData}/>);
break;
case 'productList':
return (<ProductListCell data={rowData}/>);
break;
case 'paymentInfo':
return (<PaymentInfoCell data={rowData}/>);
break;
... ... @@ -46,7 +54,7 @@ export default class Detail extends Component {
}
render() {
let {order_code, detail} = this.props.resource;
let {order_code, detail, expressType, expressName, acceptTime, accept_address} = this.props.resource;
console.log('aaaaaa');
console.log(this.props.resource
? this.props.resource.toJS()
... ... @@ -59,11 +67,20 @@ export default class Detail extends Component {
'address': data && data.get('area') + data.get('address')
}
let expressBlob;
if (expressType == 1 && data) {//OrderDetailExpressTypeOnDeliver
expressBlob = ['物流公司:' + expressName, '快递单号:' + data.get('express_number') ];
} else if (expressType == 0 && data) {//OrderDetailExpressTypeOnRecive
expressBlob = [accept_address, acceptTime];
}
let orderInfoBlob = {
orderCode: order_code,
orderStatus: data && data.get('status_str'),
orderTime: data && data.get('create_time'),
payWay: data && data.get('payment_name')
payWay: data && data.get('payment_name'),
expressExisted: expressBlob,
}
let paymentInfoBlob = {
... ... @@ -72,6 +89,18 @@ export default class Detail extends Component {
type: data && data.get('payment_type'),
}
let isVirtualOrder = false;
let isPresaleOrder = false;
if (data) {
isVirtualOrder = data.get('attribute') == '3';
isPresaleOrder = data.get('attribute') == '9';
}
let productListBlob = {
isVirtualOrder,
isPresaleOrder,
list: data && data.get('order_goods'),
}
let dataSource = {
'address': data
? [addressBlob]
... ... @@ -79,6 +108,12 @@ export default class Detail extends Component {
'orderInfo': data
? [orderInfoBlob]
: [],
'express': expressBlob
? [expressBlob]
: [],
'productList': data
? [productListBlob]
: [],
'paymentInfo': data
? [paymentInfoBlob]
: []
... ... @@ -98,7 +133,7 @@ export default class Detail extends Component {
dataSource={this.dataSource.cloneWithRowsAndSections(dataSource)}
renderRow={this.renderRow}
/>
{buttonArray.length? <Footer/>: null}
{buttonArray.length? <Footer buttonArray={buttonArray} onPressFooterAction={this.props.onPressFooterAction}/>: null}
</View>
: <LoadingIndicator isVisible={isFetching}/>}
</View>
... ...
'use strict';
import React, {Component} from 'react';
import Immutable, {Map} from 'immutable';
import ReactNative, {
View,
Text,
Image,
ListView,
StyleSheet,
Dimensions,
TouchableOpacity,
InteractionManager,
Platform
} from 'react-native';
export default class ExpressCell extends Component {
constructor(props) {
super(props);
}
render() {
return (
<TouchableOpacity style={styles.container}>
<View style={styles.leftPart}>
<Image style={{
width: 22,
height: 22
}} source={require('../../image/icon_wuliu.png')}/>
</View>
<View style={styles.rightPart}>
<View style={styles.topPart}>
<Text style={styles.codeText}>物流信息</Text>
</View>
{
this.props.data.map((item, index) => {
return <Text key={index} style={styles.otherText}>{item}</Text>
})
}
</View>
<Image style={{
width: 15,
height: 15
}} source={require('../../image/shared_next_icon.png')}/>
</TouchableOpacity>
);
}
}
let {width, height} = Dimensions.get('window');
let styles = StyleSheet.create({
container: {
width: width,
flexDirection: 'row',
backgroundColor: 'white',
borderColor: '#f0f0f0',
alignItems: 'center',
borderBottomWidth: 10
},
topPart: {
width: width - 45,
height: 20,
flexDirection: 'row',
alignItems: 'center',
marginTop: 13,
marginBottom: 2
},
codeText: {
fontSize: 14,
marginBottom: 0,
color: '#444444'
},
copyButton: {
marginLeft: 10,
width: 44,
height: 18,
borderColor: '#444444',
borderWidth: 1,
justifyContent: 'center',
alignItems: 'center'
},
leftPart: {
width: 45,
justifyContent: 'center',
alignItems: 'center'
},
rightPart: {
width: width - 45 - 30,
flexDirection: 'column',
paddingBottom: 10
},
otherText: {
fontSize: 12,
marginBottom: 3,
color: '#b0b0b0',
}
});
... ...
... ... @@ -26,13 +26,67 @@ export default class Detail extends Component {
return (
<View style={styles.footer}>
{this.props.buttonArray.map((item, index) => {
let buttonText = '';
let buttonStyle = styles.commonButton;
let textStyle = styles.commonText;
switch (item) {
case 'buyNow':
buttonText = '立即付款';
buttonStyle = styles.redButton;
textStyle = styles.whiteText;
break;
case 'closeOrder':
buttonText = '取消订单';
break;
case 'confirm':
buttonText = '确认收货';
buttonStyle = styles.redButton;
textStyle = styles.whiteText;
break;
case 'getExpress':
buttonText = '查看物流';
break;
case 'shareOrder':
buttonText = '晒单评价';
buttonStyle = [styles.commonButton, {backgroundColor: '#444444'}];
textStyle = styles.whiteText;
break;
case 'delOrder':
buttonText = '删除订单';
break;
case 'lookQrcode':
buttonText = '查看二维码';
break;
case 'afterService':
buttonText = '申请售后';
break;
case 'readd':
buttonText = '再次购买';
break;
case 'modifyAddress':
buttonText = '修改地址';
break;
case 'refundApply':
buttonText = '申请退款';
break;
default:
}
return (
<TouchableOpacity key={index} style={buttonStyle} onPress={() => {
this.props.onPressFooterAction && this.props.onPressFooterAction(item)
}}>
<Text style={textStyle}>{buttonText}</Text>
</TouchableOpacity>
);
})}
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let buttonPadding = 6;
let styles = StyleSheet.create({
footer: {
... ... @@ -42,39 +96,56 @@ let styles = StyleSheet.create({
borderTopWidth: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end',
backgroundColor: 'white'
},
detailButton: {
position: 'absolute',
width: 100,
height: 44,
top: 7,
left: width - 15 - 100,
commonButton: {
marginRight: 15,
marginLeft: 0,
paddingLeft: buttonPadding,
paddingRight: buttonPadding,
backgroundColor: 'white',
borderColor: '#444444',
borderRadius: 3,
borderWidth: 1,
alignItems: 'center',
height: 30,
justifyContent: 'center'
},
redButton: {
marginRight: 15,
marginLeft: 0,
paddingLeft: buttonPadding,
paddingRight: buttonPadding,
backgroundColor: '#d0021b',
borderRadius: 4,
alignItems: 'center'
borderRadius: 3,
alignItems: 'center',
height: 30,
justifyContent: 'center'
},
detailButtonText: {
marginTop: 4,
height: 36,
color: 'white',
paddingTop: 10,
textAlign: 'center',
fontSize: 15
redFrameButton: {
marginRight: 15,
marginLeft: 0,
paddingLeft: buttonPadding,
paddingRight: buttonPadding,
backgroundColor: 'white',
borderColor: '#d0021b',
borderRadius: 3,
borderWidth: 1,
alignItems: 'center',
height: 30,
justifyContent: 'center'
},
favoriteButton: {
width: 100,
height: 40
commonText: {
fontSize: 14,
color: '#444444'
},
favIcon: {
width: 17,
height: 16,
marginLeft: 20,
marginRight: 0
whiteText: {
fontSize: 14,
color: 'white'
},
favText: {
fontSize: 13,
color: '#b0b0b0',
marginLeft: 5
redText: {
fontSize: 14,
color: '#d0021b'
}
});
... ...
'use strict';
import React, {Component} from 'react';
import Immutable, {Map} from 'immutable';
import ReactNative, {
View,
Text,
Image,
ListView,
StyleSheet,
Dimensions,
TouchableOpacity,
InteractionManager,
Platform
} from 'react-native';
export default class PaymentInfoCell extends Component {
constructor(props) {
super(props);
this.renderCell = this.renderCell.bind(this);
}
renderCell(left, right, last = false) {
let color = last
? '#d0021b'
: 'black';
return (
<View style={styles.cellContainer}>
<View style={styles.leftPart}>
<Text style={styles.text}>{left}</Text>
</View>
<View style={styles.rightPart}>
<Text style={[styles.text, {
color
}]}>{right}</Text>
</View>
</View>
)
}
render() {
let {promotionAry, total, type} = this.props.data;
let payment_desc = type == '2' ? '应付金额' : '实付金额' ;
return (
<View style={styles.container}>
{promotionAry.toJS().map((item, i) => {
let {promotion, promotion_amount} = item;
return (
<View style={styles.cellContainer} key={i}>
<View style={styles.leftPart}>
<Text style={styles.text}>{promotion}</Text>
</View>
<View style={styles.rightPart}>
<Text style={[
styles.text, {
color: 'black'
}
]}>{promotion_amount}</Text>
</View>
</View>
)
})}
{this.renderCell(payment_desc, '¥' + total, true)}
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let styles = StyleSheet.create({
container: {
width: width,
flexDirection: 'column',
backgroundColor: 'white',
alignItems: 'center',
borderColor: '#f0f0f0',
borderBottomWidth: 10,
paddingTop: 9,
paddingBottom: 9
},
cellContainer: {
width: width - 30,
height: 20,
flexDirection: 'row'
},
leftPart: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
flexDirection: 'row'
},
rightPart: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
flexDirection: 'row'
},
text: {
fontSize: 14,
color: '#444444'
}
});
... ...
... ... @@ -22,7 +22,9 @@ export default class OrderInfoCell extends Component {
}
render() {
let {orderCode, orderStatus, orderTime, payWay} = this.props.data;
let {orderCode, orderStatus, orderTime, payWay, expressExisted} = this.props.data;
let containerSeparator = expressExisted? {borderBottomWidth:0}:{};
let rightSeparator = expressExisted?{borderBottomWidth:0.5}:{};
let timeInt = parseInt(orderTime) * 1000;
let date = new Date(timeInt);
let timeStr = date.getFullYear() + '.' + ((date.getMonth() + 1) > 9
... ... @@ -37,14 +39,14 @@ export default class OrderInfoCell extends Component {
? date.getSeconds()
: '0' + date.getSeconds());
return (
<View style={styles.container}>
<View style={[styles.container, containerSeparator]}>
<View style={styles.leftPart}>
<Image style={{
width: 22,
height: 22
}} source={require('../../image/icon_dingdan.png')}/>
</View>
<View style={styles.rightPart}>
<View style={[styles.rightPart, rightSeparator]}>
<View style={styles.topPart}>
<Text style={styles.codeText}>订单编号:{orderCode}</Text>
<TouchableOpacity style={styles.copyButton}>
... ... @@ -108,6 +110,7 @@ let styles = StyleSheet.create({
rightPart: {
width: width - 45,
flexDirection: 'column',
borderColor: '#ededed',
paddingBottom: 10
},
... ...
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
Dimensions,
TouchableOpacity,
} from 'react-native';
export default class PresaleFooter extends Component {
constructor(props){
super(props);
}
render(){
let height = this.props.height;
let src = {uri:''};
if (height > 0) {
src = require('../../image/delay_delivery_warning_icon.png')
}
return(
<View style={[styles.container,{height}]}>
<Text style={styles.dateStyles}>
{this.props.date}
</Text>
<TouchableOpacity
onPress={() => {
this._onPressDelayNotice && this._onPressDelayNotice();
}}
>
<View style={styles.noticeStyle}>
<Image source={src}/>
<Text style={{fontSize: 10,color: '#444444',marginLeft:2,height:height}}>
延迟发货提醒
</Text>
</View>
</TouchableOpacity>
</View>
);
}
}
let {width,height} = Dimensions.get('window');
const styles = StyleSheet.create({
container : {
flex: 1,
width: width,
backgroundColor: 'green',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
dateStyles: {
backgroundColor: 'transparent',
marginLeft: 15,
fontSize: 12,
color: '#b0b0b0'
},
noticeStyle: {
flexDirection: 'row',
backgroundColor: 'transparent',
marginRight: 15
}
});
... ...
'use strict';
import React, {Component} from 'react';
import ReactNative, {
View,
Text,
Image,
StyleSheet,
Dimensions,
TouchableOpacity,
Platform,
} from 'react-native';
import YH_Image from '../../../common/components/YH_Image';
export default class ProductCell extends Component {
constructor(props) {
super(props);
}
render(){
let {width,height} = Dimensions.get('window');
let scale = width/320;
let goodsData = this.props.goodsData;
let goodsImageURL = YH_Image.getSlicedUrl(goodsData.get('goods_image',''),90*scale,120*scale,2);
let goodsName = goodsData.get('product_name','');
let goodsSize = goodsData.get('size_name','');
let goodsColor = goodsData.get('color_name','');
let goodsPrice = goodsData.get('goods_price','');
let goodsCount = goodsData.get('buy_number','');
let arrivalTime = goodsData.get('expect_arrival_time');
let goodsSKN = goodsData.get('product_skn','');
let colorString = '';
let sizeString = '';
let refundExchangeImagePath = {uri:''};
if (this.props.isVritualOrder) {
if (goodsSKN == this.props.yohoodTicketsSkn) {
colorString = '日期:'+goodsColor;
sizeString = '区域:'+goodsSize;
}else if (goodsSKN == this.props.yohoodTicketSkn) {
colorString = '日期:'+goodsColor;
}else {
colorString = '颜色:'+goodsColor;
}
}else {
colorString = '颜色:'+goodsColor;
sizeString = '尺码:'+goodsSize;
let goodsStatus = goodsData.get('goods_status','');
if (goodsStatus == '已退货') {
refundExchangeImagePath=require('../../image/has_refunded.png')
}else if (goodsStatus == '已换货') {
refundExchangeImagePath=require('../../image/had_exchanged.png')
}else if (goodsStatus == '已退换') {
refundExchangeImagePath=require('../../image/has_refundedExchange.png')
}
}
let goodsTyle = goodsData.get('goods_type',0)//商品类型,默认0为普通商品
let typeTipColor = 'transparent';
let typeTipString = '';
switch (goodsTyle) {
case 'gift':{
typeTipString='赠品';
typeTipColor='rgba(133, 196, 91, 1.0)'
}
break;
case 'price_gift':{
typeTipString='加价购';
typeTipColor='rgba(245, 91, 144, 1.0)'
}
break;
case 'outlet':{
typeTipString='OUTLET';
typeTipColor='#ff9900'
}
break;
default:
}
return (
<View style={styles.container}>
<View style={styles.leftMiddleContainer}>
<View style={styles.leftContainer}>
<YH_Image style={styles.goodsImageStyle}
url={goodsImageURL}
/>
<Text style={[styles.goodsTypeStyle,{backgroundColor:typeTipColor}]}>
{typeTipString}
</Text>
</View>
<View style={styles.middleContainer}>
<Text style={styles.nameStyle}>
{goodsName}
</Text>
<Text style={styles.colorStyle}>
{(colorString)+' '+(sizeString)}
</Text>
</View>
</View>
<View style={styles.rightContainer}>
<Text style={styles.priceStyle}>
{'¥'+(goodsPrice)}
</Text>
<Text style={styles.countStyle}>
{'x'+(goodsCount)}
</Text>
<TouchableOpacity
onPress={() => {
this.props._onPressRefundExchange && this.props._onPressRefundExchange()
}}
>
<Image style={styles.refundImageStyle}
source={refundExchangeImagePath}
/>
</TouchableOpacity>
</View>
</View>
);
}
}
let {width,height} = Dimensions.get('window');
let styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
height: 82,
backgroundColor: 'transparent',
},
leftMiddleContainer:{
flexDirection:'row',
},
leftContainer: {
backgroundColor: 'transparent',
flexDirection:'column',
marginLeft: 15,
marginTop: 10,
width: 45,
height: 60,
},
middleContainer: {
flexDirection: 'column',
justifyContent : 'flex-start',
marginLeft: 10,
},
rightContainer: {
flexDirection: 'column',
marginRight: 15,
alignItems: 'flex-end',
},
goodsImageStyle: {
width: 45,
height: 60,
},
goodsTypeStyle: {
position: 'absolute',
marginBottom: 0,
height: 10,
fontSize: 8,
},
nameStyle: {
fontSize: 14,
color: '#444444',
backgroundColor: 'transparent',
marginTop: 13,
},
colorSizeContainer: {
flexDirection: 'row',
},
colorStyle:{
fontSize: 11,
color: '#b0b0b0',
},
sizeStyle: {
fontSize: 11,
color: '#b0b0b0',
},
priceStyle: {
fontSize: 14,
color: '#d0021b',
backgroundColor: 'transparent',
marginTop: 13,
marginRight: 0,
},
countStyle: {
fontSize: 12,
color: '#b0b0b0',
backgroundColor: 'transparent',
marginTop: 4,
},
taxImageStyle:{
},
taxInfoStyle:{
},
refundImageStyle:{
marginTop:10,
},
refundInfoStyle:{
fontSize: 10,
color: '#b0b0b0',
},
lineStyle: {
color: "#e5e5e5",
height: 0.5,
}
});
... ...
'use strict';
import React, {Component} from 'react';
import Immutable, {Map} from 'immutable';
import ProductCell from './ProductCell'
import PresaleFooter from './PresaleFooter'
import ReactNative, {
View,
Text,
Image,
ListView,
StyleSheet,
Dimensions,
TouchableOpacity,
InteractionManager,
Platform
} from 'react-native';
export default class ProductListCell extends Component {
constructor(props) {
super(props);
this.renderRow = this.renderRow.bind(this);
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => !Immutable.is(r1, r2),
});
}
renderRow(rowData, sectionID, rowID, highlightRow) {
let {
isVirtualOrder,
isPresaleOrder,
} = this.props.data;
let arrivalTime = rowData.get('expect_arrival_time','');
let showFooter = isPresaleOrder && arrivalTime.length;
return (
<View style={{backgroundColor: 'white'}}>
<ProductCell goodsData={rowData} isVirtualOrder={isVirtualOrder} isPresaleOrder={isPresaleOrder}/>
{showFooter?<PresaleFooter/>:null}
</View>
)
}
render() {
let {
list,
} = this.props.data;
return (
<View style={styles.container}>
<ListView
contentContainerStyle={styles.contentContainer}
enableEmptySections={true}
showsVerticalScrollIndicator={false}
dataSource={this.dataSource.cloneWithRows(list.toArray())}
renderRow={this.renderRow}
/>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let styles = StyleSheet.create({
container: {
width: width,
flexDirection: 'column',
backgroundColor: 'white',
borderColor: '#f0f0f0',
alignItems: 'center',
borderBottomWidth: 10
},
});
... ...
... ... @@ -46,6 +46,7 @@ function mapDispatchToProps(dispatch) {
class DetailContainer extends Component {
constructor(props) {
super(props);
this.onPressFooterAction = this.onPressFooterAction.bind(this);
this.subscription = NativeAppEventEmitter.addListener(
'YHNotificationChangeOnLinePayToCodPay',
(reminder) => {
... ... @@ -62,6 +63,9 @@ class DetailContainer extends Component {
this.subscription && this.subscription.remove();
}
onPressFooterAction(buttonType) {
}
render() {
let {detail, app} = this.props;
... ... @@ -69,6 +73,7 @@ class DetailContainer extends Component {
<Detail
resource={detail}
channel={app.channel}
onPressFooterAction={this.onPressFooterAction}
/>
);
}
... ...
... ... @@ -28,6 +28,26 @@ export function getDetail() {
dispatch(getDetailRequest());
return new DetailService(app.host).getDetailWithOrderCode(order_code)
.then(json => {
//Get first product skn.
if (json.order_goods && json.order_goods.length) {
json.firstProductSKN = json.order_goods[0].product_skn;
}
//Get express type.
let type = 2;
if (json.express_detail && json.express_detail.length) {
let {accept_address, acceptTime} = json.express_detail[0];
type = acceptTime && accept_address ? 0 : 2;
json.acceptTime = acceptTime;
json.accept_address = accept_address;
} else if (json.express_number && json.express_number.length) {
type = 1;
}
json.expressType = type;
if (json.express_company) {
let {caption} = json.express_company;
json.expressName = caption;
}
// console.log(product_skn);
// console.log(json);
dispatch(getDetailSuccess(json));
... ...
'use strict';
import { Record, List, Map } from 'immutable';
/**
Note:
1. expressType
typedef NS_ENUM(NSInteger, OrderDetailExpressType) {
OrderDetailExpressTypeOnDeliver, 0
OrderDetailExpressTypeOnRecive, 1
OrderDetailExpressTypeNone, 2
};
2.firstProductSKN
For drill to express detail view controller...
*/
let InitialState = Record({
order_code: '',
detail: new (Record(
... ... @@ -9,7 +19,12 @@ let InitialState = Record({
isFetching: false,
error: null,
data: null
}))
})),
firstProductSKN: '',
expressType: 2,
expressName: '',
acceptTime: '',
accept_address: '',
});
export default InitialState;
... ...
... ... @@ -22,8 +22,23 @@ export default function detailReducer(state=initialState, action) {
return state.setIn(['detail', 'isFetching'], true);
}
case GET_DETAIL_SUCCESS: {
let {
firstProductSKN,
expressType,
expressName,
acceptTime,
accept_address,
} = action.payload;
if (!firstProductSKN) {
firstProductSKN = '';
}
return state.setIn(['detail', 'isFetching'], false)
.setIn(['detail', 'data'], Immutable.fromJS(action.payload))
.set('firstProductSKN', firstProductSKN)
.set('expressType', expressType)
.set('expressName', expressName)
.set('acceptTime', acceptTime)
.set('accept_address', accept_address)
.setIn(['detail', 'error'], null);
}
case GET_DETAIL_FAILURE: {
... ...