Authored by 叶弯弯

完成库存统计模块。reviewed by shixiang。

@@ -53,6 +53,7 @@ import LogoutContainer from './containers/LogoutContainer' @@ -53,6 +53,7 @@ import LogoutContainer from './containers/LogoutContainer'
53 import ModifyPasswordContainer from './containers/ModifyPasswordContainer' 53 import ModifyPasswordContainer from './containers/ModifyPasswordContainer'
54 import AccountSettlementContainer from './containers/AccountSettlementContainer' 54 import AccountSettlementContainer from './containers/AccountSettlementContainer'
55 import AboutUsContainer from './containers/AboutUsContainer' 55 import AboutUsContainer from './containers/AboutUsContainer'
  56 +import StockStatsContainer from './containers/StockStatsContainer'
56 57
57 import NavBar from './components/NavBar'; 58 import NavBar from './components/NavBar';
58 import TabIcon from './containers/TabIcon'; 59 import TabIcon from './containers/TabIcon';
@@ -153,7 +154,7 @@ export default function native(platform) { @@ -153,7 +154,7 @@ export default function native(platform) {
153 type='push' 154 type='push'
154 /> 155 />
155 156
156 - <Scene 157 + <Scene
157 key='AccountSettlement' 158 key='AccountSettlement'
158 component={AccountSettlementContainer} 159 component={AccountSettlementContainer}
159 title='对账结算' 160 title='对账结算'
@@ -165,6 +166,17 @@ export default function native(platform) { @@ -165,6 +166,17 @@ export default function native(platform) {
165 /> 166 />
166 167
167 <Scene 168 <Scene
  169 + key='StockStats'
  170 + component={StockStatsContainer}
  171 + title='库存统计'
  172 + hideNavBar={false}
  173 + initial={false}
  174 + navBar={NavBar}
  175 + titleStyle={styles.navTitle}
  176 + type='push'
  177 + />
  178 +
  179 + <Scene
168 key='AboutUs' 180 key='AboutUs'
169 component={AboutUsContainer} 181 component={AboutUsContainer}
170 title='关于我们' 182 title='关于我们'
  1 +'use strict';
  2 +
  3 +import React, {Component} from 'react';
  4 +import PlainTextSection from './PlainTextSection';
  5 +import Placeholder from './Placeholder';
  6 +
  7 +import {
  8 + StyleSheet,
  9 + View,
  10 + Text,
  11 + ListView,
  12 + Image,
  13 + Dimensions,
  14 + TouchableHighlight,
  15 +} from 'react-native';
  16 +
  17 +export default class StockStats extends Component {
  18 +
  19 + constructor(props) {
  20 + super (props);
  21 +
  22 + this.ds = new ListView.DataSource({
  23 + rowHasChanged: (r1, r2) => r1 !== r2,
  24 + });
  25 +
  26 + this._renderRow = this._renderRow.bind(this);
  27 + }
  28 +
  29 + _renderRow(rowData, sectionID, rowID) {
  30 + return (
  31 + <TouchableHighlight underlayColor={'white'} onPress={() => {}}>
  32 + <View style={styles.row}>
  33 + <Image source={{uri: rowData.thumb}} style={styles.thumb}/>
  34 + <View style={styles.detail}>
  35 + <Text style={styles.brand}>{rowData.brand}</Text>
  36 + <Text style={styles.product}>{rowData.product}</Text>
  37 + <Text style={styles.brand}>{'厂家编号:' + rowData.vendor + ' sku:' + rowData.sku}</Text>
  38 + <Text style={styles.product}>{'进货价:' + rowData.importPrice + ' 库存:' + rowData.stockNum}</Text>
  39 + </View>
  40 + </View>
  41 + </TouchableHighlight>
  42 + );
  43 + }
  44 +
  45 + render() {
  46 + return (
  47 + <View style={styles.container}>
  48 + <View style={styles.dateContainer}>
  49 + <Image source={require('../images/date.png')}/>
  50 + <Text style={styles.date}>{this.props.section1}</Text>
  51 + </View>
  52 + <Placeholder />
  53 + <PlainTextSection content={this.props.section2} />
  54 + <Placeholder />
  55 + <ListView
  56 + dataSource={this.ds.cloneWithRows(this.props.section3)}
  57 + renderRow={this._renderRow}
  58 + renderSeparator={(sectionID, rowID) => <View key={`${sectionID}-${rowID}`} style={styles.separator}/>}
  59 + onEndReachedThreshold={-50}
  60 + onEndReached={this.props.requestData}
  61 + enableEmptySections={true} />
  62 + </View>
  63 + );
  64 + }
  65 +
  66 +}
  67 +
  68 +const styles = StyleSheet.create({
  69 + container: {
  70 + flex: 1,
  71 + },
  72 + dateContainer: {
  73 + flexDirection: 'row',
  74 + justifyContent: 'center',
  75 + alignItems: 'center',
  76 + height: 50,
  77 + backgroundColor: 'white',
  78 + },
  79 + date: {
  80 + fontSize: 14,
  81 + color: '#444444',
  82 + textAlign: 'center',
  83 + marginLeft: 10,
  84 + },
  85 + separator: {
  86 + height: 1,
  87 +
  88 + },
  89 + row: {
  90 + flexDirection: 'row',
  91 + paddingLeft: 10,
  92 + paddingRight: 10,
  93 + paddingTop: 10,
  94 + paddingBottom: 10,
  95 + backgroundColor: 'white',
  96 + alignItems: 'center',
  97 + },
  98 + detail: {
  99 + flexDirection: 'column',
  100 + justifyContent: 'center',
  101 + flex: 1,
  102 + paddingLeft: 10,
  103 +
  104 + },
  105 + thumb: {
  106 + width: 60,
  107 + height: 80,
  108 + },
  109 + brand: {
  110 + color: '#B0B0B0',
  111 + fontSize: 12,
  112 + },
  113 + product: {
  114 + color: '#444444',
  115 + fontSize: 12,
  116 + },
  117 +});
@@ -12,12 +12,11 @@ let { @@ -12,12 +12,11 @@ let {
12 TouchableOpacity 12 TouchableOpacity
13 } = React; 13 } = React;
14 14
15 -let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});  
16 -  
17 export default class User extends Component { 15 export default class User extends Component {
18 16
19 constructor(props) { 17 constructor(props) {
20 super(props); 18 super(props);
  19 + this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
21 } 20 }
22 21
23 componentWillMount() { 22 componentWillMount() {
@@ -29,7 +28,7 @@ export default class User extends Component { @@ -29,7 +28,7 @@ export default class User extends Component {
29 28
30 return ( 29 return (
31 <ListView 30 <ListView
32 - dataSource={ds.cloneWithRows(this.props.items)} 31 + dataSource={this.ds.cloneWithRows(this.props.items)}
33 renderRow={this._renderItem} 32 renderRow={this._renderItem}
34 renderSeparator={(sectionID, rowID) => <View key={`${sectionID}-${rowID}`} style={styles.separator}/>} 33 renderSeparator={(sectionID, rowID) => <View key={`${sectionID}-${rowID}`} style={styles.separator}/>}
35 style={styles.listView}/> 34 style={styles.listView}/>
@@ -82,5 +81,5 @@ const styles = StyleSheet.create({ @@ -82,5 +81,5 @@ const styles = StyleSheet.create({
82 separator: { 81 separator: {
83 height: 1, 82 height: 1,
84 83
85 - }, 84 + },
86 }); 85 });
@@ -58,6 +58,10 @@ export default keyMirror({ @@ -58,6 +58,10 @@ export default keyMirror({
58 58
59 SWITCH_SHOP: null, 59 SWITCH_SHOP: null,
60 60
  61 + STOCK_STATS_REQUEST: null,
  62 + STOCK_STATS_SUCCESS: null,
  63 + STOCK_STATS_FAILURE: null,
  64 +
61 /* 65 /*
62 GET_PROFILE_REQUEST: null, 66 GET_PROFILE_REQUEST: null,
63 GET_PROFILE_SUCCESS: null, 67 GET_PROFILE_SUCCESS: null,
  1 +
  2 +'use strict';
  3 +
  4 +import React, { Component } from 'react';
  5 +
  6 +import StockStats from '../components/StockStats'
  7 +
  8 +import {
  9 + StyleSheet,
  10 + View,
  11 + Text,
  12 + ListView,
  13 + Dimensions,
  14 + Platform,
  15 +} from 'react-native';
  16 +
  17 +import {bindActionCreators} from 'redux';
  18 +import {connect} from 'react-redux';
  19 +
  20 +import {Map} from 'immutable';
  21 +
  22 +import * as stockStatsActions from '../reducers/stockStats/stockStatsActions';
  23 +
  24 +const actions = [
  25 + stockStatsActions,
  26 +];
  27 +
  28 +
  29 +function mapStateToProps(state) {
  30 + return {
  31 + ...state
  32 + }
  33 +};
  34 +
  35 +function mapDispatchToProps(dispatch) {
  36 +
  37 + const creators = Map()
  38 + .merge(...actions)
  39 + .filter(value => typeof value === 'function')
  40 + .toObject();
  41 +
  42 + return {
  43 + actions: bindActionCreators(creators, dispatch),
  44 + dispatch
  45 + };
  46 +}
  47 +
  48 +export default class StockStatsContainer extends Component {
  49 +
  50 + constructor(props) {
  51 + super(props);
  52 + this._requestData = this._requestData.bind(this);
  53 + }
  54 +
  55 + componentDidMount() {
  56 + this.props.actions.requestData();
  57 + }
  58 +
  59 + _requestData() {
  60 + this.props.actions.requestData();
  61 + }
  62 +
  63 + render() {
  64 +
  65 + let date = new Date();
  66 + let section1 = date.getFullYear() + '年' + (date.getMonth() + 1) + '月' + date.getDate() + '日';
  67 + let section2 = [
  68 + {
  69 + top: '库存总数',
  70 + bottom: `${this.props.stockStats.sum}`,
  71 + },
  72 + {
  73 + top: '库存总金额(元)',
  74 + bottom: `${this.props.stockStats.totalAmount}`,
  75 + }
  76 + ];
  77 +
  78 + return (
  79 + <View style={styles.container}>
  80 + <StockStats
  81 + section1={section1}
  82 + section2={section2}
  83 + section3={this.props.stockStats.jsonData.toJS()}
  84 + requestData={this._requestData}
  85 + />
  86 + </View>
  87 + );
  88 + }
  89 +}
  90 +
  91 +let {width, height} = Dimensions.get('window');
  92 +let navbarHeight = (Platform.OS === 'android') ? 50 : 64;
  93 +
  94 +let styles = StyleSheet.create({
  95 + container: {
  96 + top: navbarHeight,
  97 + height: height - navbarHeight,
  98 + },
  99 +
  100 +});
  101 +
  102 +export default connect(mapStateToProps, mapDispatchToProps)(StockStatsContainer);
@@ -16,6 +16,7 @@ import home from './home/homeReducer'; @@ -16,6 +16,7 @@ import home from './home/homeReducer';
16 import message from './message/messageReducer'; 16 import message from './message/messageReducer';
17 import user from './user/userReducer'; 17 import user from './user/userReducer';
18 import actStmt from './accountSettlement/accountSettlementReducer' 18 import actStmt from './accountSettlement/accountSettlementReducer'
  19 +import stockStats from './stockStats/stockStatsReducer'
19 20
20 import { combineReducers } from 'redux'; 21 import { combineReducers } from 'redux';
21 22
@@ -32,6 +33,7 @@ const rootReducer = combineReducers({ @@ -32,6 +33,7 @@ const rootReducer = combineReducers({
32 message, 33 message,
33 user, 34 user,
34 actStmt, 35 actStmt,
  36 + stockStats,
35 }); 37 });
36 38
37 export default rootReducer; 39 export default rootReducer;
  1 +'use strict';
  2 +import Request from '../../services/Request';
  3 +import StockStatsService from '../../services/HomeService';
  4 +
  5 +const {
  6 + STOCK_STATS_REQUEST,
  7 + STOCK_STATS_SUCCESS,
  8 + STOCK_STATS_FAILURE,
  9 +
  10 +} = require('../../constants/actionTypes').default;
  11 +
  12 +export function request() {
  13 + return {
  14 + type: STOCK_STATS_REQUEST,
  15 + }
  16 +}
  17 +
  18 +export function success(json) {
  19 + return {
  20 + type: STOCK_STATS_SUCCESS,
  21 + payload: json,
  22 + }
  23 +}
  24 +
  25 +export function failure(error) {
  26 + return {
  27 + type: STOCK_STATS_FAILURE,
  28 + payload: error,
  29 + }
  30 +}
  31 +
  32 +export function requestData() {
  33 + // return dispatch => {
  34 + // dispatch(request());
  35 + // return new StockStatsService()
  36 + // .stockStatsData()
  37 + // .then(json => {
  38 + // dispatch(success(json));
  39 + // })
  40 + // .catch(error => {
  41 + // dispatch(failure(error));
  42 + // })
  43 + // };
  44 + return success(testStockStatsData);
  45 +}
  46 +
  47 +let testStockStatsData = {
  48 + sum: 100,
  49 + totalAmount: 100000.00,
  50 + list: [
  51 + {
  52 + brand: 'vans',
  53 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddddddddddddddddddddddddddd 超清来袭ddddddddddddddddddddddddddddddddddd 超清来袭ddddddddddd',
  54 + vendor: '222222',
  55 + sku: '111111111',
  56 + importPrice: '222',
  57 + stockNum: '70',
  58 + thumb: 'http://www.ruanyifeng.com/blogimg/asset/2015/bg2015071002.png',
  59 + },
  60 + {
  61 + brand: 'vans',
  62 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  63 + vendor: '222222',
  64 + sku: '111111111',
  65 + importPrice: '222',
  66 + stockNum: '71',
  67 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  68 + },
  69 + {
  70 + brand: 'vans',
  71 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  72 + vendor: '222222',
  73 + sku: '111111111',
  74 + importPrice: '222',
  75 + stockNum: '72',
  76 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  77 + },
  78 + {
  79 + brand: 'vans',
  80 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  81 + vendor: '222222',
  82 + sku: '111111111',
  83 + importPrice: '222',
  84 + stockNum: '73',
  85 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  86 + },
  87 + {
  88 + brand: 'vans',
  89 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  90 + vendor: '222222',
  91 + sku: '111111111',
  92 + importPrice: '222',
  93 + stockNum: '74',
  94 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  95 + },
  96 + {
  97 + brand: 'vans',
  98 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  99 + vendor: '222222',
  100 + sku: '111111111',
  101 + importPrice: '222',
  102 + stockNum: '75',
  103 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  104 + },
  105 + {
  106 + brand: 'vans',
  107 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  108 + vendor: '222222',
  109 + sku: '111111111',
  110 + importPrice: '222',
  111 + stockNum: '76',
  112 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  113 + },
  114 + {
  115 + brand: 'vans',
  116 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  117 + vendor: '222222',
  118 + sku: '111111111',
  119 + importPrice: '222',
  120 + stockNum: '77',
  121 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  122 + },
  123 + {
  124 + brand: 'vans',
  125 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  126 + vendor: '222222',
  127 + sku: '111111111',
  128 + importPrice: '222',
  129 + stockNum: '78',
  130 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  131 + },
  132 + {
  133 + brand: 'vans',
  134 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  135 + vendor: '222222',
  136 + sku: '111111111',
  137 + importPrice: '222',
  138 + stockNum: '79',
  139 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  140 + },
  141 + {
  142 + brand: 'vans',
  143 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  144 + vendor: '222222',
  145 + sku: '111111111',
  146 + importPrice: '222',
  147 + stockNum: '80',
  148 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  149 + },
  150 + {
  151 + brand: 'vans',
  152 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  153 + vendor: '222222',
  154 + sku: '111111111',
  155 + importPrice: '222',
  156 + stockNum: '81',
  157 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  158 + },
  159 + {
  160 + brand: 'vans',
  161 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  162 + vendor: '222222',
  163 + sku: '111111111',
  164 + importPrice: '222',
  165 + stockNum: '82',
  166 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  167 + },
  168 + {
  169 + brand: 'vans',
  170 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  171 + vendor: '222222',
  172 + sku: '111111111',
  173 + importPrice: '222',
  174 + stockNum: '83',
  175 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  176 + },
  177 + {
  178 + brand: 'vans',
  179 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  180 + vendor: '222222',
  181 + sku: '111111111',
  182 + importPrice: '222',
  183 + stockNum: '84',
  184 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  185 + },
  186 + {
  187 + brand: 'vans',
  188 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  189 + vendor: '222222',
  190 + sku: '111111111',
  191 + importPrice: '222',
  192 + stockNum: '85',
  193 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  194 + },
  195 + {
  196 + brand: 'vans',
  197 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  198 + vendor: '222222',
  199 + sku: '111111111',
  200 + importPrice: '222',
  201 + stockNum: '86',
  202 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  203 + },
  204 + {
  205 + brand: 'vans',
  206 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  207 + vendor: '222222',
  208 + sku: '111111111',
  209 + importPrice: '222',
  210 + stockNum: '87',
  211 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  212 + },
  213 + {
  214 + brand: 'vans',
  215 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  216 + vendor: '222222',
  217 + sku: '111111111',
  218 + importPrice: '222',
  219 + stockNum: '88',
  220 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  221 + },
  222 + {
  223 + brand: 'vans',
  224 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  225 + vendor: '222222',
  226 + sku: '111111111',
  227 + importPrice: '222',
  228 + stockNum: '89',
  229 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  230 + },
  231 + {
  232 + brand: 'vans',
  233 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  234 + vendor: '222222',
  235 + sku: '111111111',
  236 + importPrice: '222',
  237 + stockNum: '90',
  238 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  239 + },
  240 + {
  241 + brand: 'vans',
  242 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  243 + vendor: '222222',
  244 + sku: '111111111',
  245 + importPrice: '222',
  246 + stockNum: '91',
  247 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  248 + },
  249 + {
  250 + brand: 'vans',
  251 + product: 'dddddddddddddddddddddddd 超清来袭ddddddddddd',
  252 + vendor: '222222',
  253 + sku: '111111111',
  254 + importPrice: '222',
  255 + stockNum: '92',
  256 + thumb: 'https://facebook.github.io/react/img/logo_og.png',
  257 + },
  258 +
  259 + ]
  260 +}
  1 +'use strict';
  2 +
  3 +import {List, Record} from 'immutable';
  4 +
  5 +let InitialState = Record({
  6 + error: null,
  7 + isFetching: false,
  8 + pageCount: 0,
  9 + sum: '0',
  10 + totalAmount: '0',
  11 + jsonData: List([]),
  12 +});
  13 +
  14 +export default InitialState;
  1 +'use strict';
  2 +
  3 +import StockStatsInitialState from './stockStatsInitialState'
  4 +import Immutable, {List, Record} from 'immutable';
  5 +
  6 +const {
  7 + STOCK_STATS_REQUEST,
  8 + STOCK_STATS_SUCCESS,
  9 + STOCK_STATS_FAILURE,
  10 +} = require('../../constants/actionTypes').default;
  11 +
  12 +const initialState = new StockStatsInitialState;
  13 +
  14 +export default function stockStatsReducer(state = initialState, action) {
  15 + if (!(state instanceof StockStatsInitialState)) return initialState.merge(state);
  16 +
  17 + switch (action.type) {
  18 + case STOCK_STATS_REQUEST: {
  19 + let nextState = state.set('isFetching', true).set('error', null);
  20 + return nextState;
  21 + }
  22 + case STOCK_STATS_SUCCESS: {
  23 + const {jsonData} = state;
  24 + let origin = jsonData.toJS();
  25 + let data = [...origin, ...action.payload.list];
  26 + let newPageCount = action.payload.list ? state.pageCount + 1 : state.pageCount;
  27 + let nextState = state.set('isFetching',false)
  28 + .set('sum', action.payload.sum)
  29 + .set('totalAmount', action.payload.totalAmount)
  30 + .set('pageCount', newPageCount)
  31 + .set('jsonData', List(data));
  32 + return nextState;
  33 + }
  34 + case STOCK_STATS_FAILURE: {
  35 + let nextState = state.set('isFetching',false)
  36 + .set('error', action.playload);
  37 + return nextState;
  38 + }
  39 + }
  40 +
  41 + return state;
  42 +}
@@ -36,8 +36,19 @@ export default class UserService { @@ -36,8 +36,19 @@ export default class UserService {
36 throw(error); 36 throw(error);
37 }) 37 })
38 } 38 }
39 -}  
40 39
  40 + async stockStatsData() {
  41 + return await this.api.get({
  42 + url: '/'
  43 + })
  44 + .then((json) => {
  45 + return json;
  46 + })
  47 + .catch((error) => {
  48 + throw(error);
  49 + })
  50 + }
  51 +}
41 52
42 53
43 let testData = [ 54 let testData = [