矿场列表
This commit is contained in:
@@ -13,6 +13,9 @@ body {
|
|||||||
@bg-primary-color: #ffded8;
|
@bg-primary-color: #ffded8;
|
||||||
@hint-color: gray;
|
@hint-color: gray;
|
||||||
|
|
||||||
|
@purple-one: #c17ffe;
|
||||||
|
@purple-two: #7483f6;
|
||||||
|
|
||||||
@header-height: 54px;
|
@header-height: 54px;
|
||||||
|
|
||||||
.ant-btn {
|
.ant-btn {
|
||||||
|
|||||||
@@ -14,9 +14,11 @@ export default {
|
|||||||
'common.releaseToRefresh': 'Release to refresh',
|
'common.releaseToRefresh': 'Release to refresh',
|
||||||
'common.refreshing': 'Refreshing',
|
'common.refreshing': 'Refreshing',
|
||||||
'common.loading': 'Loading',
|
'common.loading': 'Loading',
|
||||||
|
'common.loadError': 'Load Failed',
|
||||||
'common.loadFinished': 'Finished',
|
'common.loadFinished': 'Finished',
|
||||||
'common.cancel': 'Cancel',
|
'common.cancel': 'Cancel',
|
||||||
'common.ok': 'Ok',
|
'common.ok': 'Ok',
|
||||||
|
'common.modify': 'Modify',
|
||||||
|
|
||||||
'check.login': 'Sign In',
|
'check.login': 'Sign In',
|
||||||
'check.register': 'Sign Up',
|
'check.register': 'Sign Up',
|
||||||
@@ -46,15 +48,17 @@ export default {
|
|||||||
'home.home.statistic': 'Total',
|
'home.home.statistic': 'Total',
|
||||||
'home.home.header': '精选市场',
|
'home.home.header': '精选市场',
|
||||||
|
|
||||||
'home.estate.hold': 'Hold',
|
'home.mine.lastday': '昨日挖矿收益',
|
||||||
'home.estate.sold': 'Sold',
|
'home.mine.acc': '累计挖矿收益:',
|
||||||
'home.estate.holdTitle': 'Hold amount: {num}',
|
'home.mine.valid': '当前有效矿晶:',
|
||||||
'home.estate.soldTitle': 'Sold amount: {num}',
|
'home.mine.retrieve': '获取矿晶',
|
||||||
'home.estate.timeDue': 'Due {time}',
|
'home.mine.refresh': 'refresh',
|
||||||
'home.estate.timeSold': 'Sold {time}',
|
'home.mine.validTime': '获赠日期:',
|
||||||
'home.estate.cost': 'Cost',
|
'home.mine.invalidTime': '有效期至:',
|
||||||
'home.estate.profit': 'Profit',
|
'home.mine.status': 'status: ',
|
||||||
'home.estate.profit2': 'Profit: ',
|
'home.mine.status0': 'Pending',
|
||||||
|
'home.mine.status1': '正在挖矿',
|
||||||
|
'home.mine.status2': '已耗尽能源',
|
||||||
|
|
||||||
'estate.tab1': '买卖记录',
|
'estate.tab1': '买卖记录',
|
||||||
'estate.tab2': '地块介绍',
|
'estate.tab2': '地块介绍',
|
||||||
|
|||||||
@@ -14,9 +14,11 @@ export default {
|
|||||||
'common.releaseToRefresh': '释放以刷新',
|
'common.releaseToRefresh': '释放以刷新',
|
||||||
'common.refreshing': '刷新中',
|
'common.refreshing': '刷新中',
|
||||||
'common.loading': '加载中',
|
'common.loading': '加载中',
|
||||||
|
'common.loadError': '加载失败',
|
||||||
'common.loadFinished': '已经到底了~',
|
'common.loadFinished': '已经到底了~',
|
||||||
'common.cancel': '取消',
|
'common.cancel': '取消',
|
||||||
'common.ok': '确定',
|
'common.ok': '确定',
|
||||||
|
'common.modify': '修改',
|
||||||
|
|
||||||
'check.login': '登录',
|
'check.login': '登录',
|
||||||
'check.register': '注册',
|
'check.register': '注册',
|
||||||
@@ -46,15 +48,17 @@ export default {
|
|||||||
'home.home.statistic': '累计收益',
|
'home.home.statistic': '累计收益',
|
||||||
'home.home.header': '精选市场',
|
'home.home.header': '精选市场',
|
||||||
|
|
||||||
'home.estate.hold': '当前持有',
|
'home.mine.lastday': '昨日挖矿收益',
|
||||||
'home.estate.sold': '已经卖出',
|
'home.mine.acc': '累计挖矿收益:',
|
||||||
'home.estate.holdTitle': '当前持有地产数:{num}',
|
'home.mine.valid': '当前有效矿晶:',
|
||||||
'home.estate.soldTitle': '已经卖出地产数:{num}',
|
'home.mine.retrieve': '获取矿晶',
|
||||||
'home.estate.timeDue': '{time} 将到期',
|
'home.mine.refresh': '刷新',
|
||||||
'home.estate.timeSold': '{time} 已卖出',
|
'home.mine.validTime': '获赠日期:',
|
||||||
'home.estate.cost': '成本',
|
'home.mine.invalidTime': '有效期至:',
|
||||||
'home.estate.profit': '收益',
|
'home.mine.status': '状态:',
|
||||||
'home.estate.profit2': '预期收益:',
|
'home.mine.status0': '等待确认',
|
||||||
|
'home.mine.status1': '正在挖矿',
|
||||||
|
'home.mine.status2': '已耗尽能源',
|
||||||
|
|
||||||
'estate.tab1': '买卖记录',
|
'estate.tab1': '买卖记录',
|
||||||
'estate.tab2': '地块介绍',
|
'estate.tab2': '地块介绍',
|
||||||
|
|||||||
@@ -6,16 +6,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect, DispatchProp } from 'dva';
|
import { connect, DispatchProp } from 'dva';
|
||||||
import { formatMessage } from 'umi-plugin-locale';
|
import { formatMessage } from 'umi-plugin-locale';
|
||||||
import { Button, Modal } from 'antd';
|
import { Button, Modal, Input } from 'antd';
|
||||||
import Header from '@/components/Header';
|
import Header from '@/components/Header';
|
||||||
import AccountItem from '@/components/AccountItem';
|
import AccountItem from '@/components/AccountItem';
|
||||||
import { UserModelState } from '@/models/user';
|
import { UserModelState } from '@/models/user';
|
||||||
|
|
||||||
import styles from './style.less';
|
import styles from './style.less';
|
||||||
|
import { AccountModelState } from './model';
|
||||||
|
|
||||||
const AccountPage: React.FC<DispatchProp & UserModelState> = ({
|
const AccountPage: React.FC<DispatchProp & UserModelState & AccountModelState> = ({
|
||||||
dispatch,
|
dispatch,
|
||||||
user,
|
user,
|
||||||
|
nameEditable,
|
||||||
|
nameInput,
|
||||||
|
nameSubmitting,
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const onLogout = () => {
|
const onLogout = () => {
|
||||||
@@ -28,6 +32,25 @@ const AccountPage: React.FC<DispatchProp & UserModelState> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const editNameModal = (
|
||||||
|
<Modal
|
||||||
|
title={formatMessage({ id: 'common.modify' })}
|
||||||
|
visible={nameEditable}
|
||||||
|
onCancel={() => dispatch({ type: 'account/onUpdateState', nameEditable: false })}
|
||||||
|
onOk={() => dispatch({ type: 'account/changeName' })}
|
||||||
|
okText={formatMessage({ id: 'common.ok' })}
|
||||||
|
cancelText={formatMessage({ id: 'common.cancel' })}
|
||||||
|
confirmLoading={nameSubmitting}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
size="large"
|
||||||
|
placeholder={formatMessage({ id: 'account.nickname' })}
|
||||||
|
value={nameInput}
|
||||||
|
onChange={e => dispatch({ type: 'account/onUpdateState', nameInput: e.target.value })}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<Header
|
<Header
|
||||||
@@ -40,6 +63,7 @@ const AccountPage: React.FC<DispatchProp & UserModelState> = ({
|
|||||||
title="account.nickname"
|
title="account.nickname"
|
||||||
message={user.nickname}
|
message={user.nickname}
|
||||||
showGo={false}
|
showGo={false}
|
||||||
|
onClick={() => dispatch({ type: 'account/onUpdateState', nameEditable: true })}
|
||||||
/>
|
/>
|
||||||
<AccountItem
|
<AccountItem
|
||||||
className="group"
|
className="group"
|
||||||
@@ -71,10 +95,11 @@ const AccountPage: React.FC<DispatchProp & UserModelState> = ({
|
|||||||
{formatMessage({ id: 'account.logout' })}
|
{formatMessage({ id: 'account.logout' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>}
|
</div>}
|
||||||
|
{editNameModal}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
({ user }: any) => ({ ...user }),
|
({ user, account }: any) => ({ ...user, ...account }),
|
||||||
)(AccountPage);
|
)(AccountPage);
|
||||||
|
|||||||
50
src/pages/account/model.ts
Normal file
50
src/pages/account/model.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { Model } from 'dva';
|
||||||
|
import { changeName } from './service';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export interface AccountModelState {
|
||||||
|
nameEditable: boolean;
|
||||||
|
nameInput: string;
|
||||||
|
nameSubmitting: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const model: Model = {
|
||||||
|
namespace: 'account',
|
||||||
|
|
||||||
|
state: {
|
||||||
|
nameEditable: false,
|
||||||
|
nameInput: '',
|
||||||
|
nameSubmitting: false,
|
||||||
|
} as AccountModelState,
|
||||||
|
|
||||||
|
effects: {
|
||||||
|
*changeName(_, { put, all, call, select }) {
|
||||||
|
const { nameInput } = yield select((state: any) => state.account);
|
||||||
|
if (!nameInput) return;
|
||||||
|
|
||||||
|
yield put({ type: 'onUpdateState', nameSubmitting: true });
|
||||||
|
try {
|
||||||
|
yield call(changeName, nameInput);
|
||||||
|
yield all([
|
||||||
|
put({ type: 'onUpdateState', nameInput: '', nameEditable: false }),
|
||||||
|
put({ type: 'user/updateUser', payload: { nickname: nameInput } }),
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(e.message);
|
||||||
|
} finally {
|
||||||
|
yield put({ type: 'onUpdateState', nameSubmitting: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
reducers: {
|
||||||
|
onUpdateState(state, payload) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default model;
|
||||||
9
src/pages/account/service.ts
Normal file
9
src/pages/account/service.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import http from '@/utils/http';
|
||||||
|
|
||||||
|
export async function changeName(nickname: string) {
|
||||||
|
const { ok, msg } = await http.post('/user/chnickname', { nickname });
|
||||||
|
if (ok) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw Error(msg);
|
||||||
|
}
|
||||||
@@ -1,103 +1,103 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Radio } from 'antd';
|
|
||||||
import FittedImage from 'react-fitted-image';
|
|
||||||
import { connect, DispatchProp } from 'dva';
|
import { connect, DispatchProp } from 'dva';
|
||||||
|
import { Spin, Icon } from 'antd';
|
||||||
import { formatMessage } from 'umi-plugin-locale';
|
import { formatMessage } from 'umi-plugin-locale';
|
||||||
import List from '@/components/List';
|
import { HomeMineModelState } from './model';
|
||||||
import Label from '@/components/Label';
|
import { MineStatus, Mine } from '@/types/common';
|
||||||
import { HomeEstateModelState } from './model';
|
|
||||||
import { EstateType, Estate } from '@/types/common';
|
|
||||||
import { dispatch } from '@/utils/utils';
|
import { dispatch } from '@/utils/utils';
|
||||||
|
|
||||||
import styles from './style.less';
|
import styles from './style.less';
|
||||||
|
|
||||||
const RadioGroup = Radio.Group;
|
const MinePage: React.FC<HomeMineModelState & DispatchProp> = ({
|
||||||
const RadioButton = Radio.Button;
|
|
||||||
|
|
||||||
const renderItem = (data: Estate) => {
|
|
||||||
const holdTab = data.type === EstateType.Hold;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={styles.item}
|
|
||||||
onClick={() => dispatch({ type: 'homeEstate/gotoDetail', payload: data })}
|
|
||||||
>
|
|
||||||
<div className="avatar">
|
|
||||||
<FittedImage src={data.image || ''} fit="cover" />
|
|
||||||
</div>
|
|
||||||
<div className="content">
|
|
||||||
<span className="name">{data.name}</span>
|
|
||||||
<span className="desc">
|
|
||||||
{
|
|
||||||
holdTab ?
|
|
||||||
formatMessage({ id: 'home.estate.timeDue' }, { time: data.lockTime }) :
|
|
||||||
formatMessage({ id: 'home.estate.timeSold' }, { time: data.outTime })
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="postfix">
|
|
||||||
<span className={`cost-msg ${holdTab ? 'primary' : ''}`}>
|
|
||||||
{formatMessage({ id: 'home.estate.cost' })} <span>{data.inPrice}</span> LOG
|
|
||||||
</span>
|
|
||||||
{!holdTab && <span className="sold-msg">
|
|
||||||
{formatMessage({ id: 'home.estate.profit' })} {data.profitPrice} LOG
|
|
||||||
</span>}
|
|
||||||
{holdTab && <span className="hold-msg">
|
|
||||||
{formatMessage({ id: 'home.estate.profit2' })}{data.profitShow}
|
|
||||||
</span>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const EstatePage: React.FC<HomeEstateModelState & DispatchProp> = ({
|
|
||||||
dispatch,
|
dispatch,
|
||||||
loading,
|
refreshingList,
|
||||||
refreshing,
|
errorList,
|
||||||
tab,
|
|
||||||
data,
|
data,
|
||||||
num,
|
refreshingBasic,
|
||||||
|
errorBasic,
|
||||||
|
info,
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data.length) {
|
if (!data || errorList) {
|
||||||
dispatch({ type: 'homeEstate/refresh' });
|
dispatch({ type: 'homeMine/loadList' });
|
||||||
|
}
|
||||||
|
if (!info || errorBasic) {
|
||||||
|
dispatch({ type: 'homeMine/loadBasic' });
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const onRefresh = () => {
|
||||||
|
if (refreshingBasic || refreshingList) return;
|
||||||
|
dispatch({ type: 'homeMine/loadList', payload: true });
|
||||||
|
dispatch({ type: 'homeMine/loadBasic' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderBanner = (
|
||||||
|
<div className={styles.banner}>
|
||||||
|
<div className="bg" />
|
||||||
|
<span className="title">{formatMessage({ id: 'home.mine.lastday' })}</span>
|
||||||
|
<span className="content">
|
||||||
|
<span className="large">+{info ? info.revenueLastday : 0}</span>
|
||||||
|
VIC
|
||||||
|
</span>
|
||||||
|
<div className={styles.card}>
|
||||||
|
<div className="left">
|
||||||
|
<span className="line">
|
||||||
|
<span className="title2">{formatMessage({ id: 'home.mine.acc' })}</span>
|
||||||
|
<span className="value">{info ? info.revenueAll : 0} VIC</span>
|
||||||
|
</span>
|
||||||
|
<span className="line">
|
||||||
|
<span className="title2">{formatMessage({ id: 'home.mine.valid' })}</span>
|
||||||
|
<span className="value">{info ? info.stoneAll : 0} KG</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="right app-btn">
|
||||||
|
{formatMessage({ id: 'home.mine.retrieve' })}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderItem = (it: Mine) => (
|
||||||
|
<div className={styles.item} key={it.id}>
|
||||||
|
<div className="line">
|
||||||
|
<div>{formatMessage({ id: 'home.mine.validTime' })}{it.validTime}</div>
|
||||||
|
<div className="amount">+{it.amount} KG</div>
|
||||||
|
</div>
|
||||||
|
<div className="line">
|
||||||
|
<div>
|
||||||
|
{formatMessage({ id: 'home.mine.status' })}
|
||||||
|
{formatMessage({ id: `home.mine.status${it.status}` })}
|
||||||
|
</div>
|
||||||
|
<div className="small">{formatMessage({ id: 'home.mine.invalidTime' })}{it.invalidTime}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.header}>
|
{renderBanner}
|
||||||
<RadioGroup
|
|
||||||
buttonStyle="solid"
|
<div className={styles.controller}>
|
||||||
value={tab}
|
<div className="content" onClick={onRefresh}>
|
||||||
onChange={e => dispatch({ type: 'homeEstate/changeTab', payload: e.target.value })}
|
<Icon type="sync" spin={refreshingBasic || refreshingList} />
|
||||||
>
|
<span className="desc">{formatMessage({ id: 'home.mine.refresh' })}</span>
|
||||||
<RadioButton value={EstateType.Hold}>{formatMessage({ id: 'home.estate.hold' })}</RadioButton>
|
</div>
|
||||||
<RadioButton value={EstateType.Sold}>{formatMessage({ id: 'home.estate.sold' })}</RadioButton>
|
|
||||||
</RadioGroup>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Label
|
<Spin className={styles.list} spinning={refreshingList}>
|
||||||
name={formatMessage({
|
{!data ? (
|
||||||
id: tab === EstateType.Hold ? 'home.estate.holdTitle' : 'home.estate.soldTitle',
|
<div className={styles.message}>
|
||||||
}, { num })}
|
{formatMessage({ id: errorList ? 'common.loadError' : 'common.loading' })}
|
||||||
className={styles.label}
|
</div>
|
||||||
/>
|
) : data.map(renderItem)}
|
||||||
|
</Spin>
|
||||||
<List
|
|
||||||
className={styles.list}
|
|
||||||
data={data}
|
|
||||||
renderItem={renderItem}
|
|
||||||
refreshing={refreshing}
|
|
||||||
onRefresh={() => dispatch({ type: 'homeEstate/refresh' })}
|
|
||||||
loading={loading}
|
|
||||||
onLoadMore={() => dispatch({ type: 'homeEstate/loadMore' })}
|
|
||||||
itemKey={data => data.id}
|
|
||||||
itemSize={80}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
({ homeEstate } : any) => ({ ...homeEstate }),
|
({ homeMine } : any) => ({ ...homeMine }),
|
||||||
)(EstatePage);
|
)(MinePage);
|
||||||
|
|||||||
@@ -1,104 +1,88 @@
|
|||||||
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 { Mines, MineBasic } from '@/types/common';
|
||||||
import { getEstateList, EstateList } from './service';
|
import { getMineList, getMineBasic } from './service';
|
||||||
|
|
||||||
export interface HomeEstateModelState {
|
export interface HomeMineModelState {
|
||||||
refreshing: boolean;
|
refreshingList: boolean;
|
||||||
loading: boolean;
|
errorList: boolean;
|
||||||
loadingFinished: boolean;
|
data: Mines | null;
|
||||||
data: Estates;
|
|
||||||
num: number;
|
|
||||||
pageIndex: number;
|
|
||||||
|
|
||||||
tab: EstateType;
|
refreshingBasic: boolean;
|
||||||
|
errorBasic: boolean;
|
||||||
|
info: MineBasic | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EstateModel: Model = {
|
const MineModel: Model = {
|
||||||
namespace: 'homeEstate',
|
namespace: 'homeMine',
|
||||||
|
|
||||||
state: {
|
state: {
|
||||||
refreshing: false,
|
refreshingList: false,
|
||||||
loading: false,
|
errorList: false,
|
||||||
enableLoad: true,
|
data: null,
|
||||||
loadingFinished: false,
|
|
||||||
data: [],
|
refreshingBasic: false,
|
||||||
num: 0,
|
errorBasic: false,
|
||||||
pageIndex: 1,
|
info: null,
|
||||||
pageSize: 10,
|
} as HomeMineModelState,
|
||||||
tab: EstateType.Hold,
|
|
||||||
} as HomeEstateModelState,
|
|
||||||
|
|
||||||
effects: {
|
effects: {
|
||||||
*refresh(_, { put, call, select }) {
|
*loadList({ payload: refresh }, { put, call, select }) {
|
||||||
const {
|
const { refreshingList } = yield select((state: any) => state.homeMine);
|
||||||
pageSize,
|
if (refreshingList) return;
|
||||||
tab,
|
|
||||||
} = yield select((state: any) => state.homeEstate);
|
yield put({
|
||||||
yield put({ type: 'onUpdateState', payload: { refreshing: true, loading: false } });
|
type: 'onUpdateState',
|
||||||
|
refreshingList: true,
|
||||||
|
errorList: false,
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
const { total, list }: EstateList = yield call(getEstateList, 1, pageSize, tab);
|
const data = yield call(getMineList, refresh);
|
||||||
const { tab: newTab } = yield select((state: any) => state.homeEstate);
|
yield put({
|
||||||
if (tab === newTab) {
|
type: 'onUpdateState',
|
||||||
yield put({
|
data,
|
||||||
type: 'onUpdateState',
|
refreshingList: false,
|
||||||
payload: {
|
errorList: false,
|
||||||
refreshing: false,
|
});
|
||||||
pageIndex: 2,
|
|
||||||
data: list,
|
|
||||||
num: total,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
message.error(e.message);
|
yield put({
|
||||||
yield put({ type: 'onUpdateState', payload: { refreshing: false, pageIndex: 1 } });
|
type: 'onUpdateState',
|
||||||
|
refreshingList: false,
|
||||||
|
errorList: true,
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
*loadMore(_, { put, call, select }) {
|
*loadBasic(_, { put, call, select }) {
|
||||||
const {
|
const { refreshingBasic } = yield select((state: any) => state.homeMine);
|
||||||
pageIndex,
|
if (refreshingBasic) return;
|
||||||
pageSize,
|
|
||||||
tab,
|
yield put({
|
||||||
data,
|
type: 'onUpdateState',
|
||||||
} = yield select((state: any) => state.homeEstate);
|
refreshingBasic: true,
|
||||||
yield put({ type: 'onUpdateState', payload: { loading: true, refreshing: false } });
|
errorBasic: false,
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
const { total, list }: EstateList = yield call(getEstateList, pageIndex, pageSize, tab);
|
const info = yield call(getMineBasic);
|
||||||
const { tab: newTab } = yield select((state: any) => state.homeEstate);
|
yield put({
|
||||||
if (tab === newTab) {
|
type: 'onUpdateState',
|
||||||
yield put({
|
info,
|
||||||
type: 'onUpdateState',
|
refreshingBasic: false,
|
||||||
payload: {
|
errorBasic: false,
|
||||||
loading: false,
|
});
|
||||||
pageIndex: pageIndex + 1,
|
|
||||||
data: [...data, ...list],
|
|
||||||
num: total,
|
|
||||||
enableLoad: list.length === pageSize,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
message.error(e.message);
|
yield put({
|
||||||
yield put({ type: 'onUpdateState', payload: { loading: false } });
|
type: 'onUpdateState',
|
||||||
|
refreshingBasic: false,
|
||||||
|
errorBasic: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
*changeTab({ payload: tab }, { put }) {
|
|
||||||
yield put({ type: 'onUpdateState', payload: { tab, pageIndex: 1, data: [], num: 0 } });
|
|
||||||
yield put({ type: 'refresh' });
|
|
||||||
},
|
|
||||||
|
|
||||||
*gotoDetail({ payload }, { put }) {
|
|
||||||
if (!payload) return;
|
|
||||||
yield put(routerRedux.push('/estate'));
|
|
||||||
yield put({ type: 'ext/onUpdateState', payload: { estateExt: payload } });
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
reducers: {
|
reducers: {
|
||||||
onUpdateState(state, { payload } : any) {
|
onUpdateState(state, payload) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
...payload,
|
...payload,
|
||||||
@@ -107,4 +91,4 @@ const EstateModel: Model = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EstateModel;
|
export default MineModel;
|
||||||
|
|||||||
@@ -1,21 +1,34 @@
|
|||||||
import http from '@/utils/http';
|
import http from '@/utils/http';
|
||||||
import { Estates, EstateType } from '@/types/common';
|
import { Mines, MineBasic } from '@/types/common';
|
||||||
import { calcEstate } from '@/utils/transform';
|
import { loadMineList, storeMineList } from '@/utils/storage';
|
||||||
|
|
||||||
export interface EstateList {
|
export async function getMineBasic(): Promise<MineBasic> {
|
||||||
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<MineBasic>('/mine/basic');
|
||||||
if (ok && data) {
|
if (ok && data) {
|
||||||
data.list.forEach(it => it.type = type);
|
return data;
|
||||||
data.list.forEach(calcEstate);
|
}
|
||||||
|
throw Error(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMineList(refresh = false): Promise<Mines> {
|
||||||
|
if (!refresh) {
|
||||||
|
const dataCached = loadMineList();
|
||||||
|
if (dataCached && dataCached.length) {
|
||||||
|
return dataCached;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
ok,
|
||||||
|
data,
|
||||||
|
msg,
|
||||||
|
} = await http.get<Mines>('/mine/list');
|
||||||
|
if (ok && data) {
|
||||||
|
storeMineList(data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
throw Error(msg);
|
throw Error(msg);
|
||||||
|
|||||||
@@ -7,90 +7,157 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
height: @header-height;
|
|
||||||
line-height: @header-height;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
margin: 0;
|
|
||||||
padding: 10px;
|
|
||||||
background-color: @bg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: stretch;
|
|
||||||
padding: 0 10px;
|
|
||||||
transition: background-color .2s;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background-color: @bg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global {
|
:global {
|
||||||
.avatar {
|
.ant-spin-nested-loading {
|
||||||
flex-shrink: 0;
|
flex-grow: 1;
|
||||||
align-self: center;
|
|
||||||
@size: 56px;
|
|
||||||
width: @size;
|
|
||||||
height: @size;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 4px;
|
}
|
||||||
|
|
||||||
|
.ant-spin-container {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner {
|
||||||
|
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, @purple-one, @purple-two);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title, .content {
|
||||||
|
color: white;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-top: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
margin: 0 10px;
|
margin: 10px 0 24px;
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.desc {
|
|
||||||
font-weight: lighter;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.postfix {
|
.content .large {
|
||||||
flex-shrink: 0;
|
font-size: 1.6rem;
|
||||||
display: flex;
|
margin-right: 6px;
|
||||||
flex-direction: column;
|
font-weight: normal;
|
||||||
justify-content: center;
|
}
|
||||||
align-items: flex-end;
|
}
|
||||||
font-size: 0.8rem;
|
|
||||||
font-weight: lighter;
|
|
||||||
|
|
||||||
.cost-msg {
|
.card {
|
||||||
margin-bottom: 6px;
|
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;
|
||||||
|
|
||||||
&.primary {
|
:global {
|
||||||
color: @primary-color;
|
.left {
|
||||||
}
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
> span {
|
flex-direction: column;
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hold-msg {
|
.right {
|
||||||
background-color: @bg-primary-color;
|
flex-shrink: 0;
|
||||||
color: @primary-color;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sold-msg {
|
.line {
|
||||||
color: @primary-color;
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title2 {
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-btn {
|
||||||
|
user-select: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
background-color: @purple-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(@purple-one, 10%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.controller {
|
||||||
|
background-color: @bg-color;
|
||||||
|
margin: 10px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.desc {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: lighter;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 4px 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin: 4px 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
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 {
|
||||||
|
color: @purple-one;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small {
|
||||||
|
font-weight: lighter;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -92,6 +92,55 @@ export interface Estate {
|
|||||||
|
|
||||||
export type Estates = Estate[];
|
export type Estates = Estate[];
|
||||||
|
|
||||||
|
export interface MineBasic {
|
||||||
|
/**
|
||||||
|
* 昨日收益
|
||||||
|
*/
|
||||||
|
revenueLastday: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总收益
|
||||||
|
*/
|
||||||
|
revenueAll: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前有效矿晶
|
||||||
|
*/
|
||||||
|
stoneAll: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum MineStatus {
|
||||||
|
Pending = 0, // 等待确认
|
||||||
|
Working = 1, // 正在挖矿
|
||||||
|
RunOut = 2, // 耗尽能源
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 矿
|
||||||
|
*/
|
||||||
|
export interface Mine {
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
amount: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获赠日期
|
||||||
|
*/
|
||||||
|
validTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 到期日期
|
||||||
|
*/
|
||||||
|
invalidTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 矿晶状态
|
||||||
|
*/
|
||||||
|
status: MineStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Mines = Mine[];
|
||||||
|
|
||||||
export enum MarketEstateAvailable {
|
export enum MarketEstateAvailable {
|
||||||
No = 0,
|
No = 0,
|
||||||
Yes = 1,
|
Yes = 1,
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ const successLabel = 'color:white;background-color:green;padding: 1px 2px';
|
|||||||
const failureLabel = 'color:white;background-color:red;padding: 1px 2px';
|
const failureLabel = 'color:white;background-color:red;padding: 1px 2px';
|
||||||
const originLabel = 'color:unset;background-color:unset;padding:unset';
|
const originLabel = 'color:unset;background-color:unset;padding:unset';
|
||||||
|
|
||||||
const baseURL = 'https://server.fiv.tacever.org/v1';
|
// const baseURL = 'https://server.fiv.tacever.org/v1';
|
||||||
// const baseURL = '//yapi.faronear.org/mock/20/v1';
|
const baseURL = '//yapi.faronear.org/mock/20/v1';
|
||||||
const instance = axios.create({
|
const instance = axios.create({
|
||||||
baseURL,
|
baseURL,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
|
||||||
const userKey = 'user-key';
|
const userKey = 'user-key';
|
||||||
const areaCodeKey = 'area-code-key';
|
const areaCodeKey = 'area-code-key';
|
||||||
|
const mineListKey = 'mine-list-key';
|
||||||
|
|
||||||
|
// user info from now on
|
||||||
function storeUser(user: any = undefined) {
|
function storeUser(user: any = undefined) {
|
||||||
if (user === undefined) {
|
if (user === undefined) {
|
||||||
localStorage.removeItem(userKey);
|
localStorage.removeItem(userKey);
|
||||||
@@ -20,6 +22,8 @@ function loadUser() {
|
|||||||
|
|
||||||
const clearUser = storeUser;
|
const clearUser = storeUser;
|
||||||
|
|
||||||
|
|
||||||
|
// area code info from now on
|
||||||
function storeAreaCode(codes: any) {
|
function storeAreaCode(codes: any) {
|
||||||
localStorage.setItem(areaCodeKey, JSON.stringify(codes));
|
localStorage.setItem(areaCodeKey, JSON.stringify(codes));
|
||||||
}
|
}
|
||||||
@@ -32,6 +36,20 @@ function loadAreaCode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// mine list info from now on
|
||||||
|
function storeMineList(list: any) {
|
||||||
|
localStorage.setItem(mineListKey, JSON.stringify(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadMineList() {
|
||||||
|
try {
|
||||||
|
return JSON.parse(localStorage.getItem(mineListKey) || 'null');
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
storeUser,
|
storeUser,
|
||||||
loadUser,
|
loadUser,
|
||||||
@@ -39,4 +57,7 @@ export {
|
|||||||
|
|
||||||
storeAreaCode,
|
storeAreaCode,
|
||||||
loadAreaCode,
|
loadAreaCode,
|
||||||
|
|
||||||
|
storeMineList,
|
||||||
|
loadMineList,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user