矿场列表
This commit is contained in:
@@ -1,103 +1,103 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Radio } from 'antd';
|
||||
import FittedImage from 'react-fitted-image';
|
||||
import { connect, DispatchProp } from 'dva';
|
||||
import { Spin, Icon } from 'antd';
|
||||
import { formatMessage } from 'umi-plugin-locale';
|
||||
import List from '@/components/List';
|
||||
import Label from '@/components/Label';
|
||||
import { HomeEstateModelState } from './model';
|
||||
import { EstateType, Estate } from '@/types/common';
|
||||
import { HomeMineModelState } from './model';
|
||||
import { MineStatus, Mine } from '@/types/common';
|
||||
import { dispatch } from '@/utils/utils';
|
||||
|
||||
import styles from './style.less';
|
||||
|
||||
const RadioGroup = Radio.Group;
|
||||
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> = ({
|
||||
const MinePage: React.FC<HomeMineModelState & DispatchProp> = ({
|
||||
dispatch,
|
||||
loading,
|
||||
refreshing,
|
||||
tab,
|
||||
refreshingList,
|
||||
errorList,
|
||||
data,
|
||||
num,
|
||||
refreshingBasic,
|
||||
errorBasic,
|
||||
info,
|
||||
}) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (!data.length) {
|
||||
dispatch({ type: 'homeEstate/refresh' });
|
||||
if (!data || errorList) {
|
||||
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 (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<RadioGroup
|
||||
buttonStyle="solid"
|
||||
value={tab}
|
||||
onChange={e => dispatch({ type: 'homeEstate/changeTab', payload: e.target.value })}
|
||||
>
|
||||
<RadioButton value={EstateType.Hold}>{formatMessage({ id: 'home.estate.hold' })}</RadioButton>
|
||||
<RadioButton value={EstateType.Sold}>{formatMessage({ id: 'home.estate.sold' })}</RadioButton>
|
||||
</RadioGroup>
|
||||
{renderBanner}
|
||||
|
||||
<div className={styles.controller}>
|
||||
<div className="content" onClick={onRefresh}>
|
||||
<Icon type="sync" spin={refreshingBasic || refreshingList} />
|
||||
<span className="desc">{formatMessage({ id: 'home.mine.refresh' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Label
|
||||
name={formatMessage({
|
||||
id: tab === EstateType.Hold ? 'home.estate.holdTitle' : 'home.estate.soldTitle',
|
||||
}, { num })}
|
||||
className={styles.label}
|
||||
/>
|
||||
|
||||
<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}
|
||||
/>
|
||||
<Spin className={styles.list} spinning={refreshingList}>
|
||||
{!data ? (
|
||||
<div className={styles.message}>
|
||||
{formatMessage({ id: errorList ? 'common.loadError' : 'common.loading' })}
|
||||
</div>
|
||||
) : data.map(renderItem)}
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(
|
||||
({ homeEstate } : any) => ({ ...homeEstate }),
|
||||
)(EstatePage);
|
||||
({ homeMine } : any) => ({ ...homeMine }),
|
||||
)(MinePage);
|
||||
|
||||
@@ -1,104 +1,88 @@
|
||||
import { Model, routerRedux } from 'dva';
|
||||
import { message } from 'antd';
|
||||
import { EstateType, Estates } from '@/types/common';
|
||||
import { getEstateList, EstateList } from './service';
|
||||
import { Mines, MineBasic } from '@/types/common';
|
||||
import { getMineList, getMineBasic } from './service';
|
||||
|
||||
export interface HomeEstateModelState {
|
||||
refreshing: boolean;
|
||||
loading: boolean;
|
||||
loadingFinished: boolean;
|
||||
data: Estates;
|
||||
num: number;
|
||||
pageIndex: number;
|
||||
export interface HomeMineModelState {
|
||||
refreshingList: boolean;
|
||||
errorList: boolean;
|
||||
data: Mines | null;
|
||||
|
||||
tab: EstateType;
|
||||
refreshingBasic: boolean;
|
||||
errorBasic: boolean;
|
||||
info: MineBasic | null;
|
||||
}
|
||||
|
||||
const EstateModel: Model = {
|
||||
namespace: 'homeEstate',
|
||||
const MineModel: Model = {
|
||||
namespace: 'homeMine',
|
||||
|
||||
state: {
|
||||
refreshing: false,
|
||||
loading: false,
|
||||
enableLoad: true,
|
||||
loadingFinished: false,
|
||||
data: [],
|
||||
num: 0,
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
tab: EstateType.Hold,
|
||||
} as HomeEstateModelState,
|
||||
refreshingList: false,
|
||||
errorList: false,
|
||||
data: null,
|
||||
|
||||
refreshingBasic: false,
|
||||
errorBasic: false,
|
||||
info: null,
|
||||
} as HomeMineModelState,
|
||||
|
||||
effects: {
|
||||
*refresh(_, { put, call, select }) {
|
||||
const {
|
||||
pageSize,
|
||||
tab,
|
||||
} = yield select((state: any) => state.homeEstate);
|
||||
yield put({ type: 'onUpdateState', payload: { refreshing: true, loading: false } });
|
||||
*loadList({ payload: refresh }, { put, call, select }) {
|
||||
const { refreshingList } = yield select((state: any) => state.homeMine);
|
||||
if (refreshingList) return;
|
||||
|
||||
yield put({
|
||||
type: 'onUpdateState',
|
||||
refreshingList: true,
|
||||
errorList: 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,
|
||||
},
|
||||
});
|
||||
}
|
||||
const data = yield call(getMineList, refresh);
|
||||
yield put({
|
||||
type: 'onUpdateState',
|
||||
data,
|
||||
refreshingList: false,
|
||||
errorList: false,
|
||||
});
|
||||
} catch (e) {
|
||||
message.error(e.message);
|
||||
yield put({ type: 'onUpdateState', payload: { refreshing: false, pageIndex: 1 } });
|
||||
yield put({
|
||||
type: 'onUpdateState',
|
||||
refreshingList: false,
|
||||
errorList: true,
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
*loadMore(_, { put, call, select }) {
|
||||
const {
|
||||
pageIndex,
|
||||
pageSize,
|
||||
tab,
|
||||
data,
|
||||
} = yield select((state: any) => state.homeEstate);
|
||||
yield put({ type: 'onUpdateState', payload: { loading: true, refreshing: false } });
|
||||
*loadBasic(_, { put, call, select }) {
|
||||
const { refreshingBasic } = yield select((state: any) => state.homeMine);
|
||||
if (refreshingBasic) return;
|
||||
|
||||
yield put({
|
||||
type: 'onUpdateState',
|
||||
refreshingBasic: true,
|
||||
errorBasic: false,
|
||||
});
|
||||
try {
|
||||
const { total, list }: EstateList = yield call(getEstateList, pageIndex, pageSize, tab);
|
||||
const { tab: newTab } = yield select((state: any) => state.homeEstate);
|
||||
if (tab === newTab) {
|
||||
yield put({
|
||||
type: 'onUpdateState',
|
||||
payload: {
|
||||
loading: false,
|
||||
pageIndex: pageIndex + 1,
|
||||
data: [...data, ...list],
|
||||
num: total,
|
||||
enableLoad: list.length === pageSize,
|
||||
},
|
||||
});
|
||||
}
|
||||
const info = yield call(getMineBasic);
|
||||
yield put({
|
||||
type: 'onUpdateState',
|
||||
info,
|
||||
refreshingBasic: false,
|
||||
errorBasic: false,
|
||||
});
|
||||
} catch (e) {
|
||||
message.error(e.message);
|
||||
yield put({ type: 'onUpdateState', payload: { loading: false } });
|
||||
yield put({
|
||||
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: {
|
||||
onUpdateState(state, { payload } : any) {
|
||||
onUpdateState(state, payload) {
|
||||
return {
|
||||
...state,
|
||||
...payload,
|
||||
@@ -107,4 +91,4 @@ const EstateModel: Model = {
|
||||
},
|
||||
};
|
||||
|
||||
export default EstateModel;
|
||||
export default MineModel;
|
||||
|
||||
@@ -1,21 +1,34 @@
|
||||
import http from '@/utils/http';
|
||||
import { Estates, EstateType } from '@/types/common';
|
||||
import { calcEstate } from '@/utils/transform';
|
||||
import { Mines, MineBasic } from '@/types/common';
|
||||
import { loadMineList, storeMineList } from '@/utils/storage';
|
||||
|
||||
export interface EstateList {
|
||||
total: number;
|
||||
list: Estates;
|
||||
}
|
||||
|
||||
export async function getEstateList(pageIndex: number, pageSize: number, type: EstateType) {
|
||||
export async function getMineBasic(): Promise<MineBasic> {
|
||||
const {
|
||||
ok,
|
||||
data,
|
||||
msg,
|
||||
} = await http.get<EstateList>('/estateorder/list', { type, pageIndex, pageSize });
|
||||
} = await http.get<MineBasic>('/mine/basic');
|
||||
if (ok && data) {
|
||||
data.list.forEach(it => it.type = type);
|
||||
data.list.forEach(calcEstate);
|
||||
return data;
|
||||
}
|
||||
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;
|
||||
}
|
||||
throw Error(msg);
|
||||
|
||||
@@ -7,90 +7,157 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
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 {
|
||||
.avatar {
|
||||
flex-shrink: 0;
|
||||
align-self: center;
|
||||
@size: 56px;
|
||||
width: @size;
|
||||
height: @size;
|
||||
.ant-spin-nested-loading {
|
||||
flex-grow: 1;
|
||||
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 {
|
||||
margin: 0 10px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
.desc {
|
||||
font-weight: lighter;
|
||||
font-size: 0.8rem;
|
||||
margin-top: 6px;
|
||||
}
|
||||
margin: 10px 0 24px;
|
||||
}
|
||||
|
||||
.postfix {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
font-size: 0.8rem;
|
||||
font-weight: lighter;
|
||||
.content .large {
|
||||
font-size: 1.6rem;
|
||||
margin-right: 6px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.cost-msg {
|
||||
margin-bottom: 6px;
|
||||
.card {
|
||||
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 {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
> span {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
:global {
|
||||
.left {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.hold-msg {
|
||||
background-color: @bg-primary-color;
|
||||
color: @primary-color;
|
||||
.right {
|
||||
flex-shrink: 0;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.sold-msg {
|
||||
color: @primary-color;
|
||||
.line {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user