Community list

This commit is contained in:
saplf
2019-09-04 15:15:40 +08:00
parent ff5a431f43
commit 254cc52585
8 changed files with 400 additions and 96 deletions

View File

@@ -17,6 +17,8 @@ body {
@purple-two: #7483f6; @purple-two: #7483f6;
@blue-one: #21b4fc; @blue-one: #21b4fc;
@blue-two: #7483f6; @blue-two: #7483f6;
@orange-one: #f5b92e;
@orange-two: #eaa900;
@header-height: 54px; @header-height: 54px;

View File

@@ -70,6 +70,13 @@ export default {
'home.fund.type2': '社区奖励', 'home.fund.type2': '社区奖励',
'home.fund.type3': '提币', 'home.fund.type3': '提币',
'home.community.total': '累计社区奖励',
'home.community.totalInvited': '成功邀请:{num}人',
'home.community.totalAll': '社区总数:{num}人',
'home.community.invite': '邀请新人加入我的社区',
'home.community.title': '成功直推名单',
'home.community.time': '注册时间:',
'estate.tab1': '买卖记录', 'estate.tab1': '买卖记录',
'estate.tab2': '地块介绍', 'estate.tab2': '地块介绍',
'estate.title1': '买入信息', 'estate.title1': '买入信息',

View File

@@ -70,6 +70,13 @@ export default {
'home.fund.type2': '社区奖励', 'home.fund.type2': '社区奖励',
'home.fund.type3': '提币', 'home.fund.type3': '提币',
'home.community.total': '累计社区奖励',
'home.community.totalInvited': '成功邀请:{num}人',
'home.community.totalAll': '社区总数:{num}人',
'home.community.invite': '邀请新人加入我的社区',
'home.community.title': '成功直推名单',
'home.community.time': '注册时间:',
'estate.tab1': '买卖记录', 'estate.tab1': '买卖记录',
'estate.tab2': '地块介绍', 'estate.tab2': '地块介绍',
'estate.title1': '买入信息', 'estate.title1': '买入信息',

View File

@@ -1,17 +1,117 @@
import React from 'react'; import React, { useEffect } from 'react';
import { connect, DispatchProp, routerRedux } from 'dva';
import { Spin, Icon } from 'antd';
import { formatMessage } from 'umi-plugin-locale';
import FittedImage from 'react-fitted-image'; import FittedImage from 'react-fitted-image';
import banner from '@/assets/m_banner.jpg'; import { HomeCommunityModelState } from './model';
import { Inviter } from '@/types/common';
import Label from '@/components/Label';
import List from '@/components/List';
import { dispatch } from '@/utils/utils';
import styles from './style.less'; import styles from './style.less';
const MarketPage: React.FC = () => { const CommunityPage: React.FC<HomeCommunityModelState & DispatchProp> = ({
return ( dispatch,
<div className={styles.container}> refreshingList,
<div className={styles.banner}> loadingList,
<FittedImage src={banner} fit="cover" /> loadingFinished,
errorList,
data,
refreshingBasic,
errorBasic,
info,
}) => {
useEffect(() => {
if (!data || errorList) {
dispatch({ type: 'homeCommunity/loadList', payload: true });
}
if (!info || errorBasic) {
dispatch({ type: 'homeCommunity/loadBasic' });
}
}, []);
const onRefresh = () => {
if (refreshingBasic || refreshingList) return;
dispatch({ type: 'homeCommunity/loadList', payload: true });
dispatch({ type: 'homeCommunity/loadBasic' });
};
const renderBanner = (
<div className={styles.banner}>
<div className="bg" />
<span className="title">{formatMessage({ id: 'home.community.total' })}</span>
<span className="content">
<span className="large">+{info ? info.rewardAll : 0} USDT</span>
</span>
<div className={styles.card}>
<div className="left">
<span className="line">
{formatMessage({
id: 'home.community.totalInvited',
}, {
num: info ? info.followerNumber : 0,
})}
</span>
<span className="line">
{formatMessage({
id: 'home.community.totalAll',
}, {
num: info ? info.communeNumber : 0,
})}
</span>
</div>
<div
className="right app-btn"
>
{formatMessage({ id: 'home.community.invite' })}
</div>
</div> </div>
</div> </div>
); );
}
export default MarketPage; const renderItem = (it: Inviter) => (
<div className={styles.item} key={it.id}>
<div className="avatar">
{it.avatar ? <FittedImage
src={it.avatar}
fit="cover"
/> : <div className="fake">{(it.nickname && it.nickname[0]) || 'F'}</div>}
</div>
<div className="line">
<span>{it.nickname}</span>
<span className="time">{formatMessage({ id: 'home.community.time' })}{it.registryTime}</span>
</div>
</div>
);
return (
<div className={styles.container}>
{renderBanner}
<Label
className={styles.controller}
name={formatMessage({ id: 'home.community.title' })}
/>
<List
className={styles.list}
data={data || []}
renderItem={renderItem}
refreshing={refreshingList}
onRefresh={onRefresh}
loading={loadingList}
enableLoading={!loadingFinished}
onLoadMore={() => dispatch({ type: 'homeCommunity/loadList' })}
itemKey={data => data.id}
itemSize={60}
/>
</div>
);
};
export default connect(
({ homeCommunity } : any) => ({ ...homeCommunity }),
)(CommunityPage);

View File

@@ -1,104 +1,108 @@
import { Model, routerRedux } from 'dva'; import { Model, routerRedux } from 'dva';
import { message } from 'antd'; import { message } from 'antd';
import { EstateType, Estates } from '@/types/common'; import { Journal, CommunityBasic } from '@/types/common';
import { getEstateList, EstateList } from './service'; import { getCommunityList, getCommunityBasic } from './service';
export interface HomeMarketModelState { export interface HomeCommunityModelState {
refreshing: boolean; refreshingList: boolean;
loading: boolean; loadingList: boolean;
loadingFinished: boolean; loadingFinished: boolean;
data: Estates; errorList: boolean;
num: number; data: Journal[] | null;
pageIndex: number;
tab: EstateType; refreshingBasic: boolean;
errorBasic: boolean;
info: CommunityBasic | null;
pageIndex: number;
} }
const MarketModel: Model = { const CommunityModel: Model = {
namespace: 'homeMarket', namespace: 'homeCommunity',
state: { state: {
refreshing: false, refreshingList: false,
loading: false, loadingList: false,
enableLoad: true,
loadingFinished: false, loadingFinished: false,
data: [], errorList: false,
num: 0, data: null,
refreshingBasic: false,
errorBasic: false,
info: null,
pageIndex: 1, pageIndex: 1,
pageSize: 10, } as HomeCommunityModelState,
tab: EstateType.Hold,
} as HomeMarketModelState,
effects: { effects: {
*refresh(_, { put, call, select }) { *loadList({ payload: refresh }, { put, call, select }) {
const {
pageSize,
tab,
} = yield select((state: any) => state.homeEstate);
yield put({ type: 'onUpdateState', payload: { refreshing: true, loading: false } });
try {
const { total, list }: EstateList = yield call(getEstateList, 1, pageSize, tab);
const { tab: newTab } = yield select((state: any) => state.homeEstate);
if (tab === newTab) {
yield put({
type: 'onUpdateState',
payload: {
refreshing: false,
pageIndex: 2,
data: list,
num: total,
},
});
}
} catch (e) {
message.error(e.message);
yield put({ type: 'onUpdateState', payload: { refreshing: false, pageIndex: 1 } });
}
},
*loadMore(_, { put, call, select }) {
const { const {
refreshingList,
loadingList,
pageIndex, pageIndex,
pageSize,
tab,
data, data,
} = yield select((state: any) => state.homeEstate); } = yield select((state: any) => state.homeCommunity);
yield put({ type: 'onUpdateState', payload: { loading: true, refreshing: false } }); if (refreshingList || loadingList) return;
yield put({
type: 'onUpdateState',
refreshingList: refresh,
loadingList: !refresh,
errorList: false,
});
try { try {
const { total, list }: EstateList = yield call(getEstateList, pageIndex, pageSize, tab); const pageSize = 10;
const { tab: newTab } = yield select((state: any) => state.homeEstate); const page = refresh ? 1 : pageIndex + 1;
if (tab === newTab) { const list = yield call(getCommunityList, page, pageSize);
yield put({ yield put({
type: 'onUpdateState', type: 'onUpdateState',
payload: { data: refresh ? list : [...data, ...list],
loading: false, refreshingList: false,
pageIndex: pageIndex + 1, loadingList: false,
data: [...data, ...list], pageIndex: page,
num: total, errorList: false,
enableLoad: list.length === pageSize, loadingFinished: list.length !== pageSize,
}, });
});
}
} catch (e) { } catch (e) {
message.error(e.message); message.error(e.message);
yield put({ type: 'onUpdateState', payload: { loading: false } }); yield put({
type: 'onUpdateState',
refreshingList: false,
loadingList: false,
errorList: true,
});
} }
}, },
*changeTab({ payload: tab }, { put }) { *loadBasic(_, { put, call, select }) {
yield put({ type: 'onUpdateState', payload: { tab, pageIndex: 1, data: [], num: 0 } }); const { refreshingBasic } = yield select((state: any) => state.homeCommunity);
yield put({ type: 'refresh' }); if (refreshingBasic) return;
},
*gotoDetail({ payload }, { put }) { yield put({
if (!payload) return; type: 'onUpdateState',
yield put(routerRedux.push('/estate')); refreshingBasic: true,
yield put({ type: 'ext/onUpdateState', payload: { estateExt: payload } }); errorBasic: false,
});
try {
const info = yield call(getCommunityBasic);
yield put({
type: 'onUpdateState',
info,
refreshingBasic: false,
errorBasic: false,
});
} catch (e) {
yield put({
type: 'onUpdateState',
refreshingBasic: false,
errorBasic: true,
});
}
}, },
}, },
reducers: { reducers: {
onUpdateState(state, { payload } : any) { onUpdateState(state, payload) {
return { return {
...state, ...state,
...payload, ...payload,
@@ -107,4 +111,4 @@ const MarketModel: Model = {
}, },
}; };
export default MarketModel; export default CommunityModel;

View File

@@ -1,21 +1,28 @@
import http from '@/utils/http'; import http from '@/utils/http';
import { Estates, EstateType } from '@/types/common'; import { Inviters, CommunityBasic } from '@/types/common';
import { calcEstate } from '@/utils/transform';
export interface EstateList { export async function getCommunityBasic(): Promise<CommunityBasic> {
total: number;
list: Estates;
}
export async function getEstateList(pageIndex: number, pageSize: number, type: EstateType) {
const { const {
ok, ok,
data, data,
msg, msg,
} = await http.get<EstateList>('/estateorder/list', { type, pageIndex, pageSize }); } = await http.get<CommunityBasic>('/commune/basic');
if (ok && data) {
return data;
}
throw Error(msg);
}
export async function getCommunityList(pageIndex: number, pageSize: number): Promise<Inviters> {
const {
ok,
data,
msg,
} = await http.get<Inviters>('/commune/list', {
pageIndex,
pageSize,
});
if (ok && data) { if (ok && data) {
data.list.forEach(it => it.type = type);
data.list.forEach(calcEstate);
return data; return data;
} }
throw Error(msg); throw Error(msg);

View File

@@ -1,8 +1,156 @@
@import '../../../global.less';
.container { .container {
width: 100%;
height: 100%; height: 100%;
display: flex;
flex-direction: column;
align-items: stretch;
}
.message {
text-align: center;
margin-top: 20px;
} }
.banner { .banner {
flex-shrink: 0;
position: relative;
width: 100%; width: 100%;
height: 240px; display: flex;
flex-direction: column;
align-items: center;
:global {
.bg {
z-index: -1;
position: absolute;
left: 0;
right: 0;
width: 100%;
height: 90%;
background: linear-gradient(to bottom, @orange-one, @orange-two);
}
.title, .content {
color: white;
font-weight: lighter;
}
.title {
margin-top: 40px;
}
.content {
margin: 10px 0 24px;
}
.content .large {
font-size: 1.6rem;
margin-right: 6px;
font-weight: normal;
}
}
.card {
flex-shrink: 0;
align-self: stretch;
background-color: white;
padding: 20px;
margin: 0 10px;
box-shadow: 1px 1px 8px rgba(0,0,0,.1);
display: flex;
flex-direction: column;
align-items: stretch;
:global {
.left {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: space-between;
}
.right {
flex-shrink: 0;
margin-top: 8px;
}
.line {
margin: 4px 0;
font-weight: lighter;
}
.app-btn {
user-select: none;
white-space: nowrap;
text-align: center;
background-color: @orange-one;
@btn-height: 32px;
height: @btn-height;
line-height: @btn-height;
padding: 0;
border-radius: 6px;
color: white;
font-size: 0.8rem;
box-shadow: 1px 1px 8px rgba(0,0,0,.2);
transition: background-color .18s;
&:active {
background-color: lighten(@orange-one, 10%);
}
}
}
}
}
.controller {
flex-shrink: 0;
margin: 10px;
}
.list {
flex-grow: 1;
}
.item {
height: 98%;
margin: 0 10px;
display: flex;
align-items: center;
border: 1px solid @bg-color;
padding: 8px 10px;
font-size: 0.9rem;
:global {
@size: 38px;
.avatar {
height: @size;
width: @size;
}
.fake {
width: 100%;
height: 100%;
line-height: @size;
background-color: @bg-color;
font-size: 1.2rem;
border-radius: @size / 2;
text-align: center;
}
.line {
margin: 0 8px;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.time {
font-weight: lighter;
font-size: 0.8rem;
}
}
} }

View File

@@ -210,6 +210,35 @@ export interface Journal {
timestamp: string; timestamp: string;
} }
export interface CommunityBasic {
/**
* 累计奖励总额的数字
*/
rewardAll: string;
/**
* 直接邀请人数
*/
followerNumber: string;
/**
* 社区总人数
*/
communeNumber: string;
}
export interface Inviter {
id: string;
avatar: string;
nickname: string;
registryTime: string;
}
export type Inviters = Inviter[];
export enum MarketEstateAvailable { export enum MarketEstateAvailable {
No = 0, No = 0,
Yes = 1, Yes = 1,