6 |
7 |
8 |
9 |
10 | {shops.map((n, i) =>
11 |
12 |
{n.title}
13 |
15 | TOP {i + 1}
16 |
17 |
18 | )}
19 |
20 |
--------------------------------------------------------------------------------
/app/components/User/Address/Edit/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from 'components/Header';
3 | import {List, InputItem, TextareaItem, Button} from 'antd-mobile';
4 |
5 | export default ({address, onAddressChange, onSave}) =>
6 |
7 |
8 | onAddressChange(value, 'realname')}
12 | >收货人
13 | onAddressChange(value, 'mobile')}
18 | >联系电话
19 | onAddressChange(value, 'address')}
26 | />
27 |
28 |
29 | 保存
30 |
31 |
--------------------------------------------------------------------------------
/app/containers/Home/Citys/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from 'react';
2 | import City from 'components/City';
3 | import {getApi, setTitle} from 'utils';
4 |
5 | export default class extends PureComponent {
6 | state = {
7 | isFetching: false,
8 | isFetched: false,
9 | areas: []
10 | }
11 |
12 | componentDidMount() {
13 | setTitle(`城市选择`)
14 | this.fetchCitys()
15 | }
16 |
17 | fetchCitys = () => {
18 | this.setState({
19 | isFetching: true
20 | }, () => {
21 | return getApi('/city').then(response => {
22 | this.setState({
23 | isFetching: false,
24 | isFetched: true,
25 | areas: response.records
26 | })
27 | })
28 | })
29 | }
30 | onSearch = (keyword) => {
31 |
32 | }
33 |
34 | render() {
35 | const {isFetching, isFetched, areas} = this.state
36 | return
41 | }
42 | }
--------------------------------------------------------------------------------
/app/actions/notice.js:
--------------------------------------------------------------------------------
1 | import {CALL_API} from "../middleware/api";
2 | import * as cache from "../utils/cache";
3 |
4 | export const NOTICES_REQUEST = 'NOTICES_REQUEST'
5 | export const NOTICES_SUCCESS = 'NOTICES_SUCCESS'
6 | export const NOTICES_FAIL = 'NOTICES_FAIL'
7 |
8 | export const getNotices = (fullName) => (dispatch, getState) => {
9 | const repo = getState().notice[fullName]
10 | if (repo && repo.isFetched) {
11 | return null
12 | }
13 | cache.get(`${fullName}_notices`) && dispatch({
14 | type: NOTICES_SUCCESS,
15 | response: cache.get(`${fullName}_notices`),
16 | fullName: fullName
17 | })
18 | const types = {index: 1}
19 | return dispatch({
20 | [CALL_API]: {
21 | types: [NOTICES_REQUEST, NOTICES_SUCCESS, NOTICES_FAIL],
22 | endpoint: `/notice`,
23 | body: {typeid: types[fullName]}
24 | },
25 | fullName: fullName
26 | }).then(action => {
27 | action.response.code == 'SUCCESS' && cache.set(`${fullName}_notices`, action.response)
28 | return action
29 | })
30 | }
--------------------------------------------------------------------------------
/app/containers/Search/Home/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import BuyingItem from 'components/Buying/List/Item';
3 | import ShopItem from 'components/Shop/List/Item';
4 | import {getApi} from 'utils';
5 |
6 | export default class extends PureComponent {
7 | state = {
8 | buyings: [],
9 | shops: []
10 | }
11 |
12 | componentDidMount() {
13 | this.fetchResult()
14 | }
15 |
16 | fetchResult = () => {
17 | const {location} = this.props
18 | getApi(`/search`, {
19 | keyword: location.query.keyword
20 | }).then(response => {
21 | this.setState(state => ({
22 | buyings: response.buyings || [],
23 | shops: response.shops || []
24 | }))
25 | })
26 | }
27 |
28 | render() {
29 | const {shops, buyings} = this.state
30 | return
31 | {shops && shops.map((n, i) => )}
34 | {buyings && buyings.map((n, i) => )}
37 |
38 | }
39 | }
--------------------------------------------------------------------------------
/app/actions/focus.js:
--------------------------------------------------------------------------------
1 | import {CALL_API} from "../middleware/api";
2 | import * as cache from "../utils/cache";
3 | export const FOCUSS_REQUEST = 'FOCUSS_REQUEST'
4 | export const FOCUSS_SUCCESS = 'FOCUSS_SUCCESS'
5 | export const FOCUSS_FAIL = 'FOCUSS_FAIL'
6 |
7 | export const getFocuss = (fullName) => (dispatch, getState) => {
8 | const repo = getState().focus[fullName]
9 | if (repo && repo.isFetched) {
10 | return null
11 | }
12 | cache.get(`${fullName}_focuss`) && dispatch({
13 | type: FOCUSS_SUCCESS,
14 | response: cache.get(`${fullName}_focuss`),
15 | fullName: fullName
16 | })
17 | const types = {index: 1, shop: 2, buying: 3}
18 | return dispatch({
19 | [CALL_API]: {
20 | types: [FOCUSS_REQUEST, FOCUSS_SUCCESS, FOCUSS_FAIL],
21 | endpoint: `/focus`,
22 | body: {
23 | typeid: types[fullName]
24 | }
25 | },
26 | fullName: fullName
27 | }).then(action => {
28 | action.response.code == 'SUCCESS' && cache.set(`${fullName}_focuss`, action.response)
29 | return action
30 | })
31 | }
--------------------------------------------------------------------------------
/app/components/Category/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Carousel} from 'antd-mobile';
3 | import Link from 'components/Link'
4 | import p from 'assets/images/s.gif';
5 | const group = (categories, limit) => {
6 | return categories.map((item, index) => {
7 | return categories.slice(index * limit, index * limit + limit)
8 | }).filter(item => {
9 | return item.length > 0
10 | })
11 | }
12 | export default ({categories, limit = 8}) =>
1}>
14 | {group(categories, limit).map((item, index) =>
15 | {item.map((n, i) =>
17 |
18 |
{n.title}
19 | )}
20 |
)}
21 |
--------------------------------------------------------------------------------
/app/reducers/gift.js:
--------------------------------------------------------------------------------
1 | import {
2 | FETCH_GIFTS_REQUEST, FETCH_GIFTS_SUCCESS, FETCH_GIFTS_FAIL,
3 | } from "actions/gift";
4 | const initialState = {
5 | gifts: [],
6 | isFetching: false,
7 | isMore: true,
8 | isRefreshing: false,
9 | filter: {
10 | limit: 10
11 | }
12 | }
13 | export default (state = initialState, action) => {
14 | switch (action.type) {
15 | case FETCH_GIFTS_REQUEST:
16 | return Object.assign({}, state, {
17 | filter: action.filter,
18 | isFetching: true,
19 | isRefreshing: action.isRefreshing,
20 | }, action.isRefreshing ? {
21 | gifts: []
22 | } : {})
23 | case FETCH_GIFTS_SUCCESS:
24 | return Object.assign({}, state, {
25 | isFetching: false,
26 | isRefreshing: false,
27 | isMore: action.response.gifts && action.response.gifts.length >= action.filter.limit,
28 | gifts: action.isRefreshing ? action.response.gifts || [] : state.gifts.concat(action.response.gifts || []),
29 | })
30 | default:
31 | return state
32 | }
33 | }
--------------------------------------------------------------------------------
/app/components/Vip/Priviege/Detail/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from 'components/Header';
3 | import p from 'assets/images/s.gif';
4 |
5 | export default ({priviege}) =>
6 |
7 |
8 |
9 |
10 |
11 |
{priviege.title}
12 |
{priviege.desc}
13 |
14 |
15 |
权益详情
16 |
{
20 | return `:${b * 0.02}rem`
21 | })
22 | }}/>
23 |
24 |
--------------------------------------------------------------------------------
/app/components/Rim/List/Item/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from 'components/Link';
3 | import s from './style.scss';
4 |
5 | export default ({rim}) =>
6 |
7 |
8 |
9 | {rim.title}
10 |
11 |
12 | {rim.desc}
13 |
14 |
15 |
16 |
17 |
18 |
{rim.target}
19 |
{rim.time_start} 出发
20 |
21 |
¥ {rim.adult_price} 起
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/actions/filter.js:
--------------------------------------------------------------------------------
1 | import {CALL_API} from "../middleware/api";
2 | import * as cache from "../utils/cache";
3 |
4 | export const FILTERS_REQUEST = 'FILTERS_REQUEST'
5 | export const FILTERS_SUCCESS = 'FILTERS_SUCCESS'
6 | export const FILTERS_FAIL = 'FILTERS_FAIL'
7 |
8 | export const getFilters = (fullName = 'shop') => (dispatch, getState) => {
9 | const repo = getState().filter[fullName]
10 | if (repo && repo.isFetched) {
11 | return null
12 | }
13 | cache.get(`${fullName}_filters`) && dispatch({
14 | type: FILTERS_SUCCESS,
15 | response: cache.get(`${fullName}_filters`),
16 | fullName: fullName
17 | })
18 | const types = {shop: 1, coupon: 2, gift: 5}
19 | return dispatch({
20 | [CALL_API]: {
21 | types: [FILTERS_REQUEST, FILTERS_SUCCESS, FILTERS_FAIL],
22 | endpoint: `/filter`,
23 | body: {
24 | typeid: types[fullName]
25 | }
26 | },
27 | fullName: fullName
28 | }).then(action => {
29 | action.response.code == 'SUCCESS' && cache.set(`${fullName}_filters`, action.response)
30 | return action
31 | })
32 | }
--------------------------------------------------------------------------------
/app/actions/navlink.js:
--------------------------------------------------------------------------------
1 | import {CALL_API} from "../middleware/api";
2 | import * as cache from "../utils/cache";
3 |
4 | export const NAVLINKS_REQUEST = 'NAVLINKS_REQUEST'
5 | export const NAVLINKS_SUCCESS = 'NAVLINKS_SUCCESS'
6 | export const NAVLINKS_FAIL = 'NAVLINKS_FAIL'
7 |
8 | export const getNavLinks = (fullName) => (dispatch, getState) => {
9 | const repo = getState().navlink[fullName]
10 | if (repo && repo.isFetched) {
11 | return null
12 | }
13 | cache.get(`${fullName}_navlinks`) && dispatch({
14 | type: NAVLINKS_SUCCESS,
15 | response: cache.get(`${fullName}_navlinks`),
16 | fullName: fullName
17 | })
18 | const types = {index: 1, rim: 4}
19 | return dispatch({
20 | [CALL_API]: {
21 | types: [NAVLINKS_REQUEST, NAVLINKS_SUCCESS, NAVLINKS_FAIL],
22 | endpoint: `/navlink`,
23 | body: {
24 | typeid: types[fullName]
25 | }
26 | },
27 | fullName: fullName
28 | }).then(action => {
29 | action.response.code == 'SUCCESS' && cache.set(`${fullName}_navlinks`, action.response)
30 | return action
31 | })
32 | }
--------------------------------------------------------------------------------
/app/components/User/Address/List/Item/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {SwipeAction} from 'antd-mobile';
3 |
4 | export default ({address, isManage, onEdit, onDelete, onRowClick}) =>
onRowClick(e, address)}>
6 |
onEdit(e, address),
12 | style: {backgroundColor: '#ddd', color: 'white'},
13 | },
14 | {
15 | text: '删除',
16 | onPress: e => onDelete(e, address),
17 | style: {backgroundColor: '#F4333C', color: 'white'},
18 | },
19 | ]}
20 | >
21 |
22 |
23 |
{address.realname}
24 |
{address.mobile}
25 |
26 |
{address.address}
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/actions/category.js:
--------------------------------------------------------------------------------
1 | import {CALL_API} from "../middleware/api";
2 | import * as cache from "../utils/cache";
3 |
4 | export const CATEGORYS_REQUEST = 'CATEGORYS_REQUEST'
5 | export const CATEGORYS_SUCCESS = 'CATEGORYS_SUCCESS'
6 | export const CATEGORYS_FAIL = 'CATEGORYS_FAIL'
7 |
8 | export const getCategorys = (fullName) => (dispatch, getState) => {
9 | const repo = getState().category[fullName]
10 | if (repo && repo.isFetched) {
11 | return null
12 | }
13 | cache.get(`${fullName}_categorys`) && dispatch({
14 | type: CATEGORYS_SUCCESS,
15 | response: cache.get(`${fullName}_categorys`),
16 | fullName: fullName
17 | })
18 | const types = {coupon: 2, rim: 3}
19 | return dispatch({
20 | [CALL_API]: {
21 | types: [CATEGORYS_REQUEST, CATEGORYS_SUCCESS, CATEGORYS_FAIL],
22 | endpoint: `/category`,
23 | body: {
24 | typeid: types[fullName]
25 | }
26 | },
27 | fullName: fullName
28 | }).then(action => {
29 | action.response.code == 'SUCCESS' && cache.set(`${fullName}_categorys`, action.response)
30 | return action
31 | })
32 | }
--------------------------------------------------------------------------------
/app/actions/gift.js:
--------------------------------------------------------------------------------
1 | import {CALL_API} from "../middleware/api";
2 |
3 | export const GIFT_REQUEST = 'GIFT_REQUEST'
4 | export const GIFT_SUCCESS = 'GIFT_SUCCESS'
5 | export const GIFT_FAIL = 'GIFT_FAIL'
6 |
7 | export const FETCH_GIFTS_REQUEST = 'FETCH_GIFTS_REQUEST'
8 | export const FETCH_GIFTS_SUCCESS = 'FETCH_GIFTS_SUCCESS'
9 | export const FETCH_GIFTS_FAIL = 'FETCH_GIFTS_FAIL'
10 |
11 | export const getGifts = (filter = {}) => ({
12 | [CALL_API]: {
13 | types: [GIFTS_REQUEST, GIFTS_SUCCESS, GIFTS_FAIL],
14 | endpoint: `/gift`,
15 | body: filter
16 | }
17 | })
18 |
19 | export const fetchGifts = (filter) => (dispatch, getState) => {
20 | const {gift} = getState()
21 | filter = Object.assign(gift.filter, filter)
22 | if ((!gift.isMore && !filter.isRefreshing) || gift.isFetching) {
23 | return null
24 | }
25 | return dispatch({
26 | isRefreshing: filter.isRefreshing,
27 | filter: filter,
28 | [CALL_API]: {
29 | types: [FETCH_GIFTS_REQUEST, FETCH_GIFTS_SUCCESS, FETCH_GIFTS_FAIL],
30 | endpoint: `/gift`,
31 | body: filter
32 | }
33 | })
34 | }
35 |
--------------------------------------------------------------------------------
/app/containers/User/About/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import {connect} from "react-redux";
3 | import Header from "components/Header";
4 | import Loading from "components/Loading";
5 | import {getApi, setTitle} from "utils";
6 |
7 | @connect(state => ({
8 | config: state.config
9 | }))
10 | export default class extends PureComponent {
11 | state = {
12 | isLoading: true,
13 | aboutus: ''
14 | }
15 |
16 | componentDidMount() {
17 | const {config} = this.props
18 | setTitle(`${config.siteConfig.sitename}-关于我们`)
19 | getApi(`/info`).then(response => {
20 | if (response.code == 'SUCCESS') {
21 | this.setState({
22 | aboutus: response.aboutus || '',
23 | isLoading: false
24 | })
25 | }
26 | })
27 | }
28 |
29 | render() {
30 | const {aboutus, isLoading} = this.state
31 | return
32 |
33 | {aboutus &&
}
34 | {isLoading &&
}
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/reducers/rim.js:
--------------------------------------------------------------------------------
1 | import {
2 | RIM_REQUEST, RIM_SUCCESS, RIM_FAIL,
3 | RIMS_REQUEST, RIMS_SUCCESS, RIMS_FAIL,
4 | FETCH_RIMS_REQUEST, FETCH_RIMS_SUCCESS, FETCH_RIMS_FAIL,
5 | } from 'actions/rim';
6 | const initialState = {
7 | rims: [],
8 | isFetching: false,
9 | isMore: true,
10 | isRefreshing: false,
11 | filter: {
12 | limit: 10
13 | }
14 | }
15 | export default (state = initialState, action) => {
16 | switch (action.type) {
17 | case FETCH_RIMS_REQUEST:
18 | return Object.assign({}, state, {
19 | filter: action.filter,
20 | isFetching: true,
21 | isRefreshing: action.isRefreshing,
22 | }, action.isRefreshing ? {
23 | rims: []
24 | } : {})
25 | case FETCH_RIMS_SUCCESS:
26 | return Object.assign({}, state, {
27 | isFetching: false,
28 | isRefreshing: false,
29 | isMore: action.response.rims && action.response.rims.length >= action.filter.limit,
30 | rims: action.isRefreshing ? action.response.rims || [] : state.rims.concat(action.response.rims || []),
31 | })
32 | default:
33 | return state
34 | }
35 | }
--------------------------------------------------------------------------------
/app/components/Swiper/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Carousel} from 'antd-mobile';
3 | import Link from 'components/Link'
4 | import p from 'assets/images/s.gif';
5 |
6 | export default ({imgs}) =>
1} dragging={imgs.length > 1} swiping={imgs.length > 1}
7 | infinite dots={imgs.length > 1}>
8 | {imgs.map((n, i) =>
14 |
)}
15 |
--------------------------------------------------------------------------------
/app/actions/buying.js:
--------------------------------------------------------------------------------
1 | import {CALL_API} from "../middleware/api";
2 |
3 | export const BUYINGS_REQUEST = 'BUYINGS_REQUEST'
4 | export const BUYINGS_SUCCESS = 'BUYINGS_SUCCESS'
5 | export const BUYINGS_FAIL = 'BUYINGS_FAIL'
6 |
7 | export const FETCH_BUYINGS_REQUEST = 'FETCH_BUYINGS_REQUEST'
8 | export const FETCH_BUYINGS_SUCCESS = 'FETCH_BUYINGS_SUCCESS'
9 | export const FETCH_BUYINGS_FAIL = 'FETCH_BUYINGS_FAIL'
10 |
11 | export const getBuyings = (filter = {}) => ({
12 | [CALL_API]: {
13 | types: [BUYINGS_REQUEST, BUYINGS_SUCCESS, BUYINGS_FAIL],
14 | endpoint: `/buying`,
15 | body: filter
16 | }
17 | })
18 | export const fetchBuyings = (filter) => (dispatch, getState) => {
19 | const {buying} = getState()
20 | filter = Object.assign(buying.filter, filter)
21 | if ((!buying.isMore && !filter.isRefreshing) || buying.isFetching) {
22 | return null
23 | }
24 | return dispatch({
25 | isRefreshing: filter.isRefreshing,
26 | filter: filter,
27 | [CALL_API]: {
28 | types: [FETCH_BUYINGS_REQUEST, FETCH_BUYINGS_SUCCESS, FETCH_BUYINGS_FAIL],
29 | endpoint: `/buying`,
30 | body: filter
31 | }
32 | })
33 | }
--------------------------------------------------------------------------------
/app/containers/App.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from 'react'
2 | import {connect} from 'react-redux'
3 | import Loading from 'components/Loading';
4 | import TabBar from 'components/TabBar';
5 | import {getUser} from 'actions/user'
6 |
7 | import "assets/scss/fonts.scss";
8 | import "assets/scss/antd.scss";
9 | import "assets/scss/app.scss";
10 |
11 | @connect(state => ({
12 | user: state.user,
13 | config: state.config
14 | }), {
15 | getUser
16 | })
17 | export default class extends PureComponent {
18 | componentDidMount() {
19 | const {getUser} = this.props
20 | getUser()
21 | }
22 |
23 | render() {
24 | const {config, user, children, location} = this.props
25 | if (user.isFetching || !user.isFetched) {
26 | return
27 | }
28 | if (user.auth == -1) {
29 | window.location.href = user.authUrl + '&backurl=' + encodeURIComponent(window.location.href)
30 | }
31 | if (user.auth == 1) {
32 | return
33 | {children}
34 | {config.navs.find((n) => n.link == location.pathname) && }
35 |
36 | }
37 | return
38 | }
39 | }
--------------------------------------------------------------------------------
/app/components/Vip/Gift/List/Item/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from 'components/Link';
3 | import p from 'assets/images/s.gif';
4 | import s from './style.scss';
5 |
6 | export default ({gift}) =>
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
{gift.vip_info.fee > 0 ? `${gift.vip_info.fee}积分` : '免费兑换'}
17 |
18 |
19 |
20 |
{gift.fee}积分
21 |
22 |
剩余{gift.stock}份
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/containers/Buying/Home/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import {connect} from 'react-redux';
3 | import BuyingHome from 'components/Buying/Home';
4 | import {fetchBuyings} from 'actions/buying';
5 | import {setTitle, wx} from 'utils';
6 |
7 | @connect((state) => ({
8 | config: state.config,
9 | buying: state.buying
10 | }), {
11 | fetchBuyings
12 | })
13 | export default class extends PureComponent {
14 | componentDidMount() {
15 | const {config} = this.props
16 | wx.setShare(config.shareConfig.buying)
17 | setTitle(config.siteConfig.sitename + '-大牌抢购')
18 | }
19 |
20 | loadBuyings = (e, refresh = false, filter = {}) => {
21 | const {buying, fetchBuyings} = this.props
22 | fetchBuyings({
23 | ...filter,
24 | offset: refresh ? 0 : buying.buyings.length,
25 | isRefreshing: refresh
26 | })
27 | }
28 | onSwitch = (status) => {
29 | this.loadBuyings(null, true, {
30 | typeid: status
31 | })
32 | }
33 |
34 | render() {
35 | const {buying} = this.props
36 | return
41 | }
42 | }
--------------------------------------------------------------------------------
/app/components/Shop/Join/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from 'components/Link';
3 | import p from 'assets/images/s.gif';
4 | import {Carousel} from 'antd-mobile';
5 | import s from './style.scss';
6 |
7 | export default ({config}) =>
8 |
15 | {config.slides.map((n, i) =>
16 |
18 | {i == 0 &&
19 |
20 | {config.agent_name}
}
21 |
22 |
)}
23 |
24 |
25 |
^
26 |
申请入驻
27 |
28 |
--------------------------------------------------------------------------------
/app/reducers/buying.js:
--------------------------------------------------------------------------------
1 | import {
2 | BUYING_REQUEST, BUYING_SUCCESS, BUYING_FAIL,
3 | BUYINGS_REQUEST, BUYINGS_SUCCESS, BUYINGS_FAIL,
4 | FETCH_BUYINGS_REQUEST, FETCH_BUYINGS_SUCCESS, FETCH_BUYINGS_FAIL,
5 | } from 'actions/buying';
6 | const initialState = {
7 | buyings: [],
8 | isFetching: false,
9 | isMore: true,
10 | isRefreshing: false,
11 | filter: {
12 | typeid: 2,
13 | limit: 10
14 | }
15 | }
16 | export default (state = initialState, action) => {
17 | switch (action.type) {
18 | case FETCH_BUYINGS_REQUEST:
19 | return Object.assign({}, state, {
20 | filter: action.filter,
21 | isFetching: true,
22 | isRefreshing: action.isRefreshing,
23 | }, action.isRefreshing ? {
24 | buyings: []
25 | } : {})
26 | case FETCH_BUYINGS_SUCCESS:
27 | return Object.assign({}, state, {
28 | isFetching: false,
29 | isRefreshing: false,
30 | isMore: action.response.buyings && action.response.buyings.length >= action.filter.limit,
31 | buyings: action.isRefreshing ? action.response.buyings || [] : state.buyings.concat(action.response.buyings || []),
32 | })
33 | default:
34 | return state
35 | }
36 | }
--------------------------------------------------------------------------------
/app/components/User/Favorite/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from 'components/Link';
3 | import {Tabs} from 'antd-mobile';
4 | import p from 'assets/images/s.gif';
5 | import s from './style.scss';
6 |
7 | export default ({sections}) =>
8 | {sections && sections.map((item, index) =>
12 | {item.items && item.items.map((n, i) =>
13 |
14 | {item.type == "shop" &&
15 |
{n.title}
16 |
{n.tag}
17 |
{n.distance.number}{n.distance.unit}
18 | }
19 | {item.type == "buying" &&
20 |
{n.title}
21 |
¥{n.price} 元
22 | }
23 |
)}
24 | )}
25 |
--------------------------------------------------------------------------------
/app/components/Home/JoinBox/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Carousel} from 'antd-mobile';
3 | import Link from 'components/Link';
4 | export default ({shops, limit = 2}) => {
5 | const group = shops.map((item, index) => {
6 | return shops.slice(index * limit, index * limit + limit)
7 | }).filter(item => {
8 | return item.length > 0
9 | })
10 | return
11 |
12 |
13 |
14 |
1} dragging={false} swiping={false} infinite vertical
15 | className="flex-item pl30 pt10">
16 | {group.map((item, index) =>
17 | {item.map((n, i) =>
19 | 恭喜{n.title}入驻好店
20 | )}
21 |
)}
22 |
23 |
24 |
25 |
立即入驻
26 |
27 |
28 | }
--------------------------------------------------------------------------------
/app/components/Rim/Home/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from 'components/Header';
3 | import List from '../List';
4 |
5 | export default ({config, category, rim, fetchRims, onSearch, onFilter}) =>
6 |
7 | {category && category.categorys && category.categorys.length > 0 &&
8 |
9 | {category.categorys.map((n, i) =>
onFilter('cid', n.id)} key={i}
10 | className="flex-wrp flex-item flex-cell flex-center">
11 |
12 |
{n.title}
13 |
)}
14 |
}
15 | {category && category.locals && category.locals.length > 0 &&
16 | {category.locals.map((n, i) =>
onFilter('local_id', n.id)} key={i}
17 | className="flex-wrp flex-center ptb30 border-r size28" style={{width: '25%'}}>
18 | {n.title}
)}
19 |
}
20 |
24 |
--------------------------------------------------------------------------------
/app/routes.js:
--------------------------------------------------------------------------------
1 | export default {
2 | component: require('./containers/Boot').default,
3 | childRoutes: [
4 | {
5 | path: '/',
6 | component: require('./containers/App').default,
7 | indexRoute: {
8 | getComponent(state, cb){
9 | require.ensure([], require => cb(null, require('./containers/Home').default))
10 | }
11 | },
12 | childRoutes: [
13 | require('./containers/Shop/routes').default,
14 | require('./containers/Buying/routes').default,
15 | require('./containers/Pay/routes').default,
16 | require('./containers/User/routes').default,
17 | require('./containers/Weal/routes').default,
18 | require('./containers/Rim/routes').default,
19 | require('./containers/Vip/routes').default,
20 | require('./containers/Gift/routes').default,
21 | require('./containers/Search/routes').default,
22 | require('./containers/Lottery/routes').default,
23 | require('./containers/Home/routes').default,
24 | ]
25 | },
26 | {
27 | path: '*',
28 | getComponent(state, cb){
29 | require.ensure([], require => cb(null, require('./containers/NotFound').default))
30 | }
31 | }
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/app/components/Gift/List/Item/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from 'components/Link';
3 | import p from 'assets/images/s.gif';
4 | import s from './style.scss';
5 |
6 | export default ({gift, user}) =>
8 |
9 |
10 |
{gift.title}
11 |
12 | {gift.vip_info &&
13 |
VIP专享
14 |
{gift.vip_info.fee}积分
15 |
}
16 |
{gift.fee}积分
17 |
18 |
19 | {gift.shop &&
{gift.shop.title}
}
20 |
剩余{gift.stock}份
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/containers/Vip/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import {connect} from "react-redux";
3 | import {setTitle, wx} from 'utils';
4 | import Loading from 'components/Loading';
5 | import ResultFail from 'components/Result/Fail';
6 | import {Toast} from 'antd-mobile';
7 | import {getVip, setInvite} from 'actions/vip';
8 |
9 | @connect(state => ({
10 | config: state.config,
11 | vip: state.vip
12 | }), {
13 | getVip,
14 | setInvite
15 | })
16 | export default class extends PureComponent {
17 | componentDidMount() {
18 | const {config, getVip, location, setInvite} = this.props
19 | location.query.invite_from && setInvite({invite_from: location.query.invite_from})
20 | location.query.invite_from_id && setInvite({invite_from_id: location.query.invite_from_id})
21 | setTitle(config.siteConfig.sitename + '-会员中心')
22 | wx.setShare(config.shareConfig.vip || {})
23 | getVip()
24 | }
25 |
26 | render() {
27 | const {children, vip} = this.props
28 | if (vip.isFetching || !vip.isFetched) {
29 | return
30 | }
31 | if (!vip.isOpen) {
32 |
36 | }
37 | return children
38 | }
39 | }
--------------------------------------------------------------------------------
/app/components/Header/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import PropTypes from 'prop-types';
3 | import SearchBar from "./SearchBar";
4 |
5 | export default class extends PureComponent {
6 | static SearchBar = SearchBar
7 | static contextTypes = {
8 | router: PropTypes.object.isRequired
9 | }
10 | onLeftClick = () => {
11 | const {router} = this.context
12 | const {leftClick} = this.props
13 | if (leftClick) {
14 | return leftClick()
15 | }
16 | if (history.state) {
17 | return history.back()
18 | }
19 | router.push({
20 | pathname: ''
21 | })
22 | }
23 |
24 | render() {
25 | const {right, title, children, className, color} = this.props
26 | return
27 |
28 |
29 |
30 | {children}
31 | {!children &&
{title}
}
32 |
{right}
33 |
34 | }
35 | }
--------------------------------------------------------------------------------
/app/components/Home/AdBox/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Carousel} from 'antd-mobile';
3 | import Link from 'components/Link';
4 | import p from 'assets/images/s.gif';
5 | import s from './style.scss';
6 | export default ({items, limit = 4}) => {
7 | const group = items.map((item, index) => {
8 | return items.slice(index * limit, index * limit + limit)
9 | }).filter(item => {
10 | return item.length > 0
11 | })
12 | return
13 |
1} swiping={false} infinite vertical>
14 | {group.map((item, index) =>
15 | {item.map((n, i) =>
16 |
25 |
26 | )}
27 |
)}
28 |
29 |
30 | }
--------------------------------------------------------------------------------
/app/containers/Vip/Help/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import {connect} from 'react-redux';
3 | import VipHelp from 'components/Vip/Help';
4 |
5 | @connect(state => ({
6 | vip: state.vip
7 | }))
8 | export default class extends PureComponent {
9 | state = {
10 | helpers: []
11 | }
12 |
13 | componentDidMount() {
14 | const {vip} = this.props
15 | this.setState({
16 | helpers: [
17 | {
18 | title: '什么是VIP会员',
19 | content: vip.what_is_vip,
20 | icon: 'i-help-o'
21 | },
22 | {
23 | title: '如何开通VIP会员',
24 | content: vip.how_join_vip,
25 | icon: 'i-kttq'
26 | },
27 | {
28 | title: 'VIP会员权益',
29 | content: vip.privilege.map((n, i) =>
{n.desc}
),
30 | icon: 'i-qy'
31 | },
32 | {
33 | title: '会员卡如何使用',
34 | content: vip.how_to_use,
35 | icon: 'i-sysm'
36 | },
37 | {
38 | title: '服务热线',
39 | content: vip.service_call,
40 | icon: 'i-fwrx'
41 | }
42 | ]
43 | })
44 | }
45 |
46 | render() {
47 | const {helpers} = this.state
48 | return
51 | }
52 | }
--------------------------------------------------------------------------------
/app/components/User/Coupon/Home/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from 'components/Header';
3 | import Link from 'components/Link';
4 | import List from '../List';
5 | import s from './style.scss'
6 |
7 | export default ({user, onSwitch, coupon, fetchCoupons, onDelete}) =>
8 |
9 |
10 |
onSwitch(0)}>未使用({user.weal.coupon.count[0]})
12 |
13 |
onSwitch(1)}>已使用({user.weal.coupon.count[1]})
15 |
16 |
onSwitch(-1)}>已过期({user.weal.coupon.count[-1]})
18 |
19 |
20 |
25 |
26 |
领取更多好券
28 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "react",
4 | "es2015",
5 | "stage-0"
6 | ],
7 | "plugins": [
8 | "babel-plugin-transform-decorators-legacy",
9 | [
10 | "import",
11 | {
12 | "style":"css",
13 | "libraryName": "antd-mobile"
14 | }
15 | ],
16 | [
17 | "module-alias",
18 | [
19 | {
20 | "src": "./app",
21 | "expose": "app"
22 | },
23 | {
24 | "src": "./app/actions",
25 | "expose": "actions"
26 | },
27 | {
28 | "src": "./app/utils",
29 | "expose": "utils"
30 | },
31 | {
32 | "src": "./app/components",
33 | "expose": "components"
34 | },
35 | {
36 | "src": "./assets",
37 | "expose": "assets"
38 | }
39 | ]
40 | ]
41 | ],
42 | "env": {
43 | // only enable it when process.env.NODE_ENV is 'development' or undefined
44 | "development": {
45 | "plugins": [
46 | "react-hot-loader/babel",
47 | [
48 | "transform-runtime",
49 | {
50 | "helpers": false,
51 | "polyfill": false,
52 | "regenerator": true,
53 | "moduleName": "babel-runtime"
54 | }
55 | ]
56 | ]
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/app/containers/User/Favorites/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import {connect} from 'react-redux';
3 | import {setTitle, getApi} from "utils";
4 | import Header from 'components/Header';
5 | import Loading from 'components/Loading';
6 | import ResultFail from 'components/Result/Fail';
7 | import UserFavorite from 'components/User/Favorite';
8 |
9 | @connect(state => ({
10 | config: state.config
11 | }))
12 | export default class extends PureComponent {
13 | state = {
14 | sections: [],
15 | isFetched: false
16 | }
17 |
18 | componentDidMount() {
19 | const {config} = this.props
20 | setTitle(config.siteConfig.sitename)
21 | this.fetchFavorites()
22 | }
23 |
24 | fetchFavorites = () => {
25 | getApi('/user/favorite').then(response => {
26 | this.setState({
27 | sections: response.sections || [],
28 | isFetched: true
29 | })
30 | })
31 | }
32 |
33 | render() {
34 | const {sections, isFetched} = this.state
35 | if (!isFetched) {
36 | return
37 | }
38 | return
39 |
40 | {sections.length > 0 &&
}
43 | {sections.length == 0 &&
您还没有收藏商品
}
44 |
45 | }
46 | }
--------------------------------------------------------------------------------
/app/containers/Gift/Rule/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import {connect} from 'react-redux';
3 | import Header from 'components/Header';
4 | import {setTitle, wx, getApi} from 'utils';
5 |
6 | @connect((state) => ({
7 | config: state.config
8 | }))
9 | export default class extends PureComponent {
10 | state = {
11 | rules: [
12 | {
13 | title: ' ',
14 | content: ' '
15 | }
16 | ],
17 | }
18 |
19 | componentDidMount() {
20 | const {config} = this.props
21 | wx.setShare(config.shareConfig.gift)
22 | setTitle(config.siteConfig.sitename + '-积分商城')
23 | this.fetchRule()
24 | }
25 |
26 | fetchRule = () => {
27 | getApi(`/gift/rule`).then(response => {
28 | this.setState({
29 | rules: response.rules
30 | })
31 | })
32 | }
33 |
34 | render() {
35 | const {rules} = this.state
36 | return
37 |
38 | {rules.map((n, i) =>
)}
45 |
46 | }
47 | }
--------------------------------------------------------------------------------
/app/components/Comment/List/Item/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import moment from 'moment';
3 | import Rate from 'components/Rate';
4 | import {wx} from 'utils';
5 | import p from 'assets/images/s.gif';
6 |
7 | export default ({comment}) =>
8 |
9 |
11 |
12 |
{comment.user.nickname}
13 |
14 |
15 | {moment(comment.create_at).format('MM-DD HH:mm')}
16 |
17 |
18 |
19 |
20 | {comment.content &&
{comment.content}
}
21 | {comment.pics && comment.pics.length > 0 &&
22 | {comment.pics.map((n, i) =>
{
23 | wx.previewImage(n, comment.pics)
24 | }} src={p} className="img-160 bg-cover mr10 mb5" style={{backgroundImage: `url(${n})`}} key={i}/>)}
25 |
}
26 |
27 | {comment.reply &&
28 | 商家回复:
29 | {comment.reply}
30 |
}
31 |
--------------------------------------------------------------------------------
/app/components/Buying/Detail/Header/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from 'components/Header'
3 | import p from 'assets/images/s.gif';
4 | import s from './style.scss';
5 | export default ({buying, toggleFavor, onShowPhotos}) =>
6 |
}
12 | />
13 | {buying.thumb &&
14 |
16 |
17 | {buying.title &&
{buying.title}
}
18 |
19 |
20 |
21 |
22 | {buying.invitation ? '需预约' : '免预约'}
23 |
24 |
25 |
26 |
27 | {buying.views}人在关注
28 |
29 |
30 |
31 |
}
32 |
--------------------------------------------------------------------------------
/app/containers/Rim/Home/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import {connect} from 'react-redux';
3 | import {fetchRims, getRims} from 'actions/rim';
4 | import {getCategorys} from 'actions/category';
5 | import RimHome from 'components/Rim/Home';
6 |
7 | @connect(state => ({
8 | rim: state.rim,
9 | config: state.config,
10 | category: state.category
11 | }), {
12 | fetchRims,
13 | getCategorys
14 | })
15 | export default class extends PureComponent {
16 | componentDidMount() {
17 | const {getCategorys} = this.props
18 | getCategorys('rim')
19 | }
20 |
21 | onSearch = (keyword) => {
22 | const {router} = this.props
23 | router.push({
24 | pathname: `/search`,
25 | query: {
26 | keyword: keyword
27 | }
28 | })
29 | }
30 | fetchRims = (e, refresh = false, filter = {}) => {
31 | const {rim, fetchRims} = this.props
32 | fetchRims({
33 | ...filter,
34 | offset: refresh ? 0 : rim.rims.length,
35 | isRefreshing: refresh
36 | })
37 | }
38 | onFilter = (key, value) => {
39 | this.fetchRims(null, true, {
40 | [key]: value
41 | })
42 | }
43 |
44 | render() {
45 | const {rim, config, category} = this.props
46 | return
54 | }
55 | }
--------------------------------------------------------------------------------
/app/containers/Shop/Buying/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import Header from 'components/Header';
3 | import BuyingList from 'components/Buying/List';
4 | import {getApi} from 'utils';
5 |
6 | export default class extends PureComponent {
7 | state = {
8 | isFetching: false,
9 | isMore: true,
10 | filter: {
11 | limit: 10
12 | },
13 | buyings: []
14 | }
15 |
16 | componentDidMount() {
17 |
18 | }
19 |
20 | fetchBuyings = () => {
21 | const {location} = this.props
22 | if (!this.state.isMore || this.state.isFetching) {
23 | return
24 | }
25 | this.setState(state => ({
26 | isFetching: true
27 | }), () => {
28 | getApi(`/buying`, Object.assign({}, this.state.filter, {
29 | shop_id: location.query.shop_id,
30 | offset: this.state.buyings.length
31 | })).then(response => {
32 | this.setState(state => ({
33 | isFetching: false,
34 | isMore: (response.buyings || []).length >= state.filter.limit,
35 | buyings: state.buyings.concat(response.buyings || [])
36 | }))
37 | })
38 | })
39 | }
40 |
41 | render() {
42 | const {isFetching, isMore, buyings} = this.state
43 | return
44 |
45 |
53 |
54 | }
55 | }
--------------------------------------------------------------------------------
/app/components/Header/SearchBar/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from 'react';
2 | import Link from 'components/Link';
3 | import s from './style.scss';
4 | export default class extends PureComponent {
5 | onKeydown = (e) => {
6 | const {onSearch} = this.props
7 | if (e.key == 'Enter') {
8 | e.currentTarget.value && onSearch(e.currentTarget.value)
9 | }
10 | }
11 |
12 | render() {
13 | const {currentCity, children, mode, className} = this.props
14 | return
15 | {mode == 'dark' &&
}
16 |
17 |
19 |
{currentCity.title}
20 |
▼
21 |
22 |
30 |
31 | {children}
32 |
33 | }
34 | }
--------------------------------------------------------------------------------
/app/containers/User/Finance/Result/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from 'react'
2 | import Header from 'components/Header';
3 | import {Button} from 'antd-mobile'
4 | import s from './style.scss';
5 |
6 | export default class extends PureComponent {
7 | state = {
8 | success: true,
9 | message: ''
10 | }
11 |
12 | componentDidMount() {
13 | const {location} = this.props
14 | this.setState(location.state)
15 | }
16 |
17 | render() {
18 | const {router} = this.props
19 | const {success, message} = this.state
20 | return
21 |
22 |
23 |
24 |
25 |
{message}
26 |
27 | {
31 | history.back()
32 | }}
33 | activeStyle={false}
34 | >查看我的余额
35 | {
39 | router.push({
40 | pathname: `/`
41 | })
42 | }}
43 | activeStyle={false}
44 | >返回首页
45 |
46 |
47 |
48 | }
49 | }
--------------------------------------------------------------------------------
/app/middleware/api.js:
--------------------------------------------------------------------------------
1 | import 'isomorphic-fetch'
2 | import {callApi, is_Android, setWxConfig} from 'utils'
3 | export const CALL_API = Symbol('Call API')
4 | export default store => next => action => {
5 | if (action.type == '@@router/LOCATION_CHANGE') {
6 | is_Android && setWxConfig()
7 | return next(action)
8 | }
9 | const callAPI = action[CALL_API]
10 | if (typeof callAPI === 'undefined') {
11 | return next(action)
12 | }
13 | let {endpoint} = callAPI
14 | const {types, body, method} = callAPI
15 | if (typeof endpoint === 'function') {
16 | endpoint = endpoint(store.getState())
17 | }
18 | if (typeof endpoint !== 'string') {
19 | throw new Error('Specify a string endpoint URL.')
20 | }
21 | if (!Array.isArray(types) || types.length !== 3) {
22 | throw new Error('Expected an array of three action types.')
23 | }
24 | if (!types.every(type => typeof type === 'string')) {
25 | throw new Error('Expected action types to be strings.')
26 | }
27 | const actionWith = (data) => {
28 | const finalAction = Object.assign({}, action, data)
29 | delete finalAction[CALL_API]
30 | return finalAction
31 | }
32 | const [requestType, successType, failureType] = types
33 | next(actionWith({
34 | type: requestType
35 | }))
36 | return callApi(endpoint, body, method).then(response => next(actionWith({
37 | response,
38 | type: successType
39 | })), error => next(actionWith({
40 | type: failureType,
41 | error: error.message || 'Something bad happened'
42 | })))
43 | }
--------------------------------------------------------------------------------
/app/containers/Vip/Level/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from 'react'
2 | import {connect} from 'react-redux';
3 | import VipLevel from 'components/Vip/Level';
4 |
5 | @connect(state => ({
6 | user: state.user,
7 | vip: state.vip
8 | }))
9 | export default class extends PureComponent {
10 | state = {
11 | tabIndex: 0,
12 | priviegies: [
13 | {
14 | title: '积分回馈',
15 | icon: 'i-jfhk'
16 | }
17 | ],
18 | unpriviegies: [
19 | {
20 | title: '积分回馈',
21 | icon: 'i-jfhk'
22 | },
23 | {
24 | title: '会员抢购',
25 | icon: 'i-buying-v'
26 | },
27 | {
28 | title: '会员优惠',
29 | icon: 'i-coupon-v'
30 | }, {
31 | title: '会员礼品',
32 | icon: 'i-gift-v'
33 | }, {
34 | title: '会员折扣',
35 | icon: 'i-vipdis'
36 | }
37 | ]
38 |
39 | }
40 |
41 | componentDidMount() {
42 | const {user} = this.props
43 | {
44 | user.is_vip &&
45 | this.setState({
46 | tabIndex: 1
47 | })
48 | }
49 | }
50 |
51 | onSwitchTab = (tabIndex) => {
52 | this.setState({
53 | tabIndex
54 | })
55 | }
56 |
57 | render() {
58 | const {user, vip} = this.props
59 | const {tabIndex, priviegies, unpriviegies} = this.state
60 | return
68 | }
69 | }
--------------------------------------------------------------------------------
/app/components/Weal/Redpacket/List/Item/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import p from 'assets/images/s.gif';
3 | import s from './style.scss';
4 | import {setTitle, date_obj, getApi} from "utils";
5 |
6 | export default ({redpacket, onClickRedpacket}) =>
7 |
8 |
{date_obj(redpacket.start_time).first_time} {date_obj(redpacket.start_time).secend_time}
10 |
11 |
12 |
13 |
14 |
15 |
16 |
{redpacket.shop.title}
17 |
onClickRedpacket(redpacket)}>
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
{redpacket.title}
26 |
27 |
领取现金红包
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/reducers/coupon.js:
--------------------------------------------------------------------------------
1 | import {
2 | COUPONS_FAIL, COUPONS_REQUEST, COUPONS_SUCCESS,
3 | FETCH_COUPONS_FAIL, FETCH_COUPONS_REQUEST, FETCH_COUPONS_SUCCESS
4 | } from "actions/coupon";
5 |
6 | const initialState = {
7 | coupons: [],
8 | isFetching: false,
9 | isMore: true,
10 | isRefreshing: false,
11 | filter: {
12 | limit: 10
13 | }
14 | }
15 | export default (state = initialState, action) => {
16 | switch (action.type) {
17 | case COUPONS_REQUEST:
18 | return Object.assign({}, state, {
19 | [action.fullName]: {
20 | isFetching: true
21 | }
22 | })
23 | case COUPONS_SUCCESS:
24 | return Object.assign({}, state, {
25 | [action.fullName]: {
26 | coupons: action.response.coupons || [],
27 | isFetching: false,
28 | isFetched: true
29 | }
30 | })
31 | case FETCH_COUPONS_REQUEST:
32 | return Object.assign({}, state, {
33 | filter: action.filter,
34 | isFetching: true,
35 | isRefreshing: action.isRefreshing,
36 | }, action.isRefreshing ? {
37 | coupons: []
38 | } : {})
39 | case FETCH_COUPONS_SUCCESS:
40 | return Object.assign({}, state, {
41 | isFetching: false,
42 | isRefreshing: false,
43 | isMore: action.response.coupons && action.response.coupons.length >= action.filter.limit,
44 | coupons: action.isRefreshing ? action.response.coupons || [] : state.coupons.concat(action.response.coupons || []),
45 | })
46 | default:
47 | return state
48 | }
49 | }
--------------------------------------------------------------------------------
/app/containers/Shop/Comment/index.js:
--------------------------------------------------------------------------------
1 | import React, {PureComponent} from "react";
2 | import Header from 'components/Header';
3 | import CommentList from 'components/Comment/List';
4 | import {getApi} from 'utils';
5 | export default class extends PureComponent {
6 | state = {
7 | filter: {
8 | limit: 10
9 | },
10 | isFetching: false,
11 | isMore: true,
12 | comments: []
13 | }
14 |
15 | componentDidMount() {
16 |
17 | }
18 |
19 | fetchComments = () => {
20 | const {location} = this.props
21 | if (!this.state.isMore || this.state.isFetching) {
22 | return
23 | }
24 | this.setState(state => ({
25 | isFetching: true,
26 | filter: Object.assign({}, state.filter, {
27 | shop_id: location.query.shop_id,
28 | })
29 | }), () => {
30 | getApi(`/comment`, Object.assign({}, this.state.filter, {
31 | offset: this.state.comments.length
32 | })).then(response => {
33 | this.setState({
34 | comments: this.state.comments.concat(response.comments || []),
35 | isMore: (response.comments || []).length >= this.state.filter.limit,
36 | isFetching: false
37 | })
38 | })
39 | })
40 | }
41 |
42 | render() {
43 | const {isFetching, isMore, comments} = this.state
44 | return
45 |
46 |
54 |
55 | }
56 | }
--------------------------------------------------------------------------------
/app/components/User/Comment/Add/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {List, TextareaItem, ImagePicker} from 'antd-mobile';
3 | import Header from 'components/Header';
4 | import Rate from 'components/Rate';
5 |
6 | export default ({comment, onSubmit, onCommentChange, onAddImage, onChangeImage}) =>
7 |
}/>
8 |
9 |
11 | onCommentChange(value, 'score')}/>
12 |
}
13 | >
14 | 整体评价
15 |
16 |
18 | onCommentChange(value, 'score_service')}/>
19 | }
20 | >
21 | 服务评价
22 |
23 |