diff --git a/src/components/List/index.tsx b/src/components/List/index.tsx index e0e4c90..ea7081a 100644 --- a/src/components/List/index.tsx +++ b/src/components/List/index.tsx @@ -30,7 +30,7 @@ export interface ListProps { enableRefresh?: boolean; loading?: boolean; enableLoading?: boolean; - data?: T[]; + data?: T[] | null; onRefresh?: ActionCallback; onLoadMore?: ActionCallback; renderItem?: (item: T, index: number, array: T[]) => React.ReactNode; diff --git a/src/global.less b/src/global.less index 98bee40..17fc28f 100644 --- a/src/global.less +++ b/src/global.less @@ -15,6 +15,8 @@ body { @purple-one: #c17ffe; @purple-two: #7483f6; +@blue-one: #21b4fc; +@blue-two: #7483f6; @header-height: 54px; diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index 75e006b..38b9d5a 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -61,6 +61,15 @@ export default { 'home.mine.status1': '正在挖矿', 'home.mine.status2': '已耗尽能源', + 'home.fund.total': 'Total', + 'home.fund.totalVIC': '当前VIC余额:', + 'home.fund.totalUSDT': '当前USDT余额:', + 'home.fund.draw': 'Draw', + 'home.fund.journal': 'Journals', + 'home.fund.type1': '挖矿收益', + 'home.fund.type2': '社区奖励', + 'home.fund.type3': '提币', + 'estate.tab1': '买卖记录', 'estate.tab2': '地块介绍', 'estate.title1': '买入信息', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index b3fb82c..e05391b 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -61,6 +61,15 @@ export default { 'home.mine.status1': '正在挖矿', 'home.mine.status2': '已耗尽能源', + 'home.fund.total': '总资金', + 'home.fund.totalVIC': '当前VIC余额:', + 'home.fund.totalUSDT': '当前USDT余额:', + 'home.fund.draw': '提币', + 'home.fund.journal': '收支明细', + 'home.fund.type1': '挖矿收益', + 'home.fund.type2': '社区奖励', + 'home.fund.type3': '提币', + 'estate.tab1': '买卖记录', 'estate.tab2': '地块介绍', 'estate.title1': '买入信息', diff --git a/src/pages/home/estate/model.ts b/src/pages/home/estate/model.ts index c13b6ae..53ae02e 100644 --- a/src/pages/home/estate/model.ts +++ b/src/pages/home/estate/model.ts @@ -1,5 +1,4 @@ -import { Model, routerRedux } from 'dva'; -import { message } from 'antd'; +import { Model } from 'dva'; import { Mines, MineBasic } from '@/types/common'; import { getMineList, getMineBasic } from './service'; diff --git a/src/pages/home/fund/index.tsx b/src/pages/home/fund/index.tsx index 9262197..e009895 100644 --- a/src/pages/home/fund/index.tsx +++ b/src/pages/home/fund/index.tsx @@ -1,7 +1,114 @@ -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 { HomeFundModelState } from './model'; +import { Journal, JournalOp } from '@/types/common'; +import Label from '@/components/Label'; +import List from '@/components/List'; +import { dispatch } from '@/utils/utils'; -const FundPage: React.FC = () => { - return
Fund
-} +import styles from './style.less'; -export default FundPage; +const FundPage: React.FC = ({ + dispatch, + refreshingList, + loadingList, + loadingFinished, + errorList, + data, + refreshingBasic, + errorBasic, + info, +}) => { + + useEffect(() => { + if (!data || errorList) { + dispatch({ type: 'homeFund/loadList', payload: true }); + } + if (!info || errorBasic) { + dispatch({ type: 'homeFund/loadBasic' }); + } + }, []); + + const onRefresh = () => { + if (refreshingBasic || refreshingList) return; + dispatch({ type: 'homeFund/loadList', payload: true }); + dispatch({ type: 'homeFund/loadBasic' }); + }; + + const renderBanner = ( +
+
+ {formatMessage({ id: 'home.fund.total' })} + + {info ? info.balanceSum : 0} + VIC + +
+
+ + {formatMessage({ id: 'home.fund.totalVIC' })} + +{info ? info.balanceVIC : 0} VIC + + + {formatMessage({ id: 'home.fund.totalUSDT' })} + +{info ? info.balanceUSDT : 0} USDT + +
+ +
+ {formatMessage({ id: 'home.fund.draw' })} +
+
+
+ ); + + const renderItem = (it: Journal) => ( +
+
+
{formatMessage({ id: `home.fund.type${it.type}` })}
+
+ {it.op === JournalOp.Income ? '+' : '-'}{it.amount}  + {it.coinType.toUpperCase()} +
+
+
+
+ {it.detail} +
+
{it.timestamp}
+
+
+ ); + + return ( +
+ {renderBanner} + +
+ ); +}; + +export default connect( + ({ homeFund } : any) => ({ ...homeFund }), +)(FundPage); diff --git a/src/pages/home/fund/model.ts b/src/pages/home/fund/model.ts new file mode 100644 index 0000000..87754b0 --- /dev/null +++ b/src/pages/home/fund/model.ts @@ -0,0 +1,114 @@ +import { Model, routerRedux } from 'dva'; +import { message } from 'antd'; +import { Journal, FundBasic } from '@/types/common'; +import { getFundList, getFundBasic } from './service'; + +export interface HomeFundModelState { + refreshingList: boolean; + loadingList: boolean; + loadingFinished: boolean; + errorList: boolean; + data: Journal[] | null; + + refreshingBasic: boolean; + errorBasic: boolean; + info: FundBasic | null; + + pageIndex: number; +} + +const FundModel: Model = { + namespace: 'homeFund', + + state: { + refreshingList: false, + loadingList: false, + loadingFinished: false, + errorList: false, + data: null, + + refreshingBasic: false, + errorBasic: false, + info: null, + + pageIndex: 1, + } as HomeFundModelState, + + effects: { + *loadList({ payload: refresh }, { put, call, select }) { + const { + refreshingList, + loadingList, + pageIndex, + data, + } = yield select((state: any) => state.homeFund); + if (refreshingList || loadingList) return; + + yield put({ + type: 'onUpdateState', + refreshingList: refresh, + loadingList: !refresh, + errorList: false, + }); + try { + const pageSize = 10; + const page = refresh ? 1 : pageIndex + 1; + const list = yield call(getFundList, page, pageSize); + yield put({ + type: 'onUpdateState', + data: refresh ? list : [...data, ...list], + refreshingList: false, + loadingList: false, + pageIndex: page, + errorList: false, + loadingFinished: list.length !== pageSize, + }); + } catch (e) { + message.error(e.message); + yield put({ + type: 'onUpdateState', + refreshingList: false, + loadingList: false, + errorList: true, + }); + } + }, + + *loadBasic(_, { put, call, select }) { + const { refreshingBasic } = yield select((state: any) => state.homeFund); + if (refreshingBasic) return; + + yield put({ + type: 'onUpdateState', + refreshingBasic: true, + errorBasic: false, + }); + try { + const info = yield call(getFundBasic); + yield put({ + type: 'onUpdateState', + info, + refreshingBasic: false, + errorBasic: false, + }); + } catch (e) { + yield put({ + type: 'onUpdateState', + refreshingBasic: false, + errorBasic: true, + }); + } + }, + }, + + reducers: { + onUpdateState(state, payload) { + return { + ...state, + ...payload, + }; + }, + }, +}; + +export default FundModel; diff --git a/src/pages/home/fund/service.ts b/src/pages/home/fund/service.ts new file mode 100644 index 0000000..e5afec3 --- /dev/null +++ b/src/pages/home/fund/service.ts @@ -0,0 +1,29 @@ +import http from '@/utils/http'; +import { Journal, FundBasic } from '@/types/common'; + +export async function getFundBasic(): Promise { + const { + ok, + data, + msg, + } = await http.get('/fund/detail'); + if (ok && data) { + return data; + } + throw Error(msg); +} + +export async function getFundList(pageIndex: number, pageSize: number): Promise { + const { + ok, + data, + msg, + } = await http.get('/fund/journals', { + pageIndex, + pageSize, + }); + if (ok && data) { + return data; + } + throw Error(msg); +} diff --git a/src/pages/home/fund/style.less b/src/pages/home/fund/style.less new file mode 100644 index 0000000..bcdee2b --- /dev/null +++ b/src/pages/home/fund/style.less @@ -0,0 +1,154 @@ +@import '../../../global.less'; + +.container { + width: 100%; + height: 100%; + + display: flex; + flex-direction: column; + align-items: stretch; +} + +.message { + text-align: center; + margin-top: 20px; +} + +.banner { + flex-shrink: 0; + position: relative; + width: 100%; + 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, @blue-one, @blue-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; + align-items: center; + + :global { + .left { + flex-grow: 1; + display: flex; + flex-direction: column; + } + + .right { + flex-shrink: 0; + margin-left: 8px; + } + + .line { + margin: 4px 0; + } + + .title2 { + font-weight: lighter; + } + + .app-btn { + user-select: none; + white-space: nowrap; + background-color: @blue-one; + @btn-height: 28px; + height: @btn-height; + line-height: @btn-height; + padding: 0 24px; + border-radius: @btn-height / 2; + color: white; + font-size: 0.8rem; + box-shadow: 1px 1px 8px rgba(0,0,0,.2); + transition: background-color .18s; + + &:active { + background-color: lighten(@blue-one, 10%); + } + } + } + } +} + +.controller { + flex-shrink: 0; + margin: 10px; +} + +.list { + flex-grow: 1; +} + +.item { + height: 98%; + margin: 0 10px; + display: flex; + flex-direction: column; + justify-content: space-evenly; + border: 1px solid @bg-color; + padding: 8px 10px; + font-size: 0.9rem; + line-height: 1.8; + + :global { + .line { + display: flex; + justify-content: space-between; + align-items: center; + } + + .amount { + font-size: 1rem; + } + .amount.active { + color: @blue-one; + } + + .small { + flex-shrink: 0; + font-weight: lighter; + font-size: 0.8rem; + } + + .detail { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } +} diff --git a/src/pages/home/model.ts b/src/pages/home/model.ts index d8c0f3c..8b50c0f 100644 --- a/src/pages/home/model.ts +++ b/src/pages/home/model.ts @@ -30,18 +30,18 @@ const tabItems: TabItemModels = [ icon: estateIcon, iconSelected: estateIconS, }, - { - key: '/home/market', - name: 'home.tabMarket', - icon: marketIcon, - iconSelected: marketIconS, - }, { key: '/home/fund', name: 'home.tabFund', icon: fundIcon, iconSelected: fundIconS, }, + { + key: '/home/market', + name: 'home.tabMarket', + icon: marketIcon, + iconSelected: marketIconS, + }, { key: '/home/profile', name: 'home.tabProfile', diff --git a/src/types/common.ts b/src/types/common.ts index ca2beba..e806b8f 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -153,7 +153,62 @@ export interface CoinAddress { address: string; } -export interface CoinUnion extends CoinSupport, CoinAddress {}; +export interface CoinUnion extends CoinSupport, CoinAddress { }; + +export interface FundBasic { + /** + * 总余额(以VIC计算) + */ + balanceSum: string; + + /** + * 当前VIC余额 + */ + balanceVIC: string; + + /** + * 当前USDT余额 + */ + balanceUSDT: string; +} + +export enum JournalType { + /** + * 挖矿收益 + */ + Mining = 1, + + /** + * 社区奖励 + */ + Award = 2, + + /** + * 提币 + */ + Draw = 3, +} + +export enum JournalOp { + Expenditure = 0, + Income = 1, +} + +export interface Journal { + id: string; + + type: JournalType; + + detail: string; + + amount: string; + + coinType: string; + + op: JournalOp; + + timestamp: string; +} export enum MarketEstateAvailable { No = 0,