Merge branch 'dev' into user-zzy-dev

This commit is contained in:
zzy 2022-08-24 15:21:00 +08:00
commit a5040d8541
22 changed files with 13031 additions and 12028 deletions

View File

@ -56,6 +56,7 @@
"@formily/antd": "^2.0.7", "@formily/antd": "^2.0.7",
"@formily/core": "^2.0.7", "@formily/core": "^2.0.7",
"@formily/react": "^2.0.7", "@formily/react": "^2.0.7",
"@metamask/detect-provider": "^1.2.0",
"@umijs/route-utils": "^2.0.3", "@umijs/route-utils": "^2.0.3",
"ahooks": "^2.10.14", "ahooks": "^2.10.14",
"antd": "^4.17.2", "antd": "^4.17.2",
@ -63,6 +64,8 @@
"bignumber.js": "^9.0.0", "bignumber.js": "^9.0.0",
"braft-editor": "^2.3.9", "braft-editor": "^2.3.9",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"echarts": "^5.3.3",
"echarts-for-react": "^3.0.2",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"moment": "^2.29.4", "moment": "^2.29.4",
"omit.js": "^2.0.2", "omit.js": "^2.0.2",
@ -73,7 +76,8 @@
"react-dom": "^17.0.0", "react-dom": "^17.0.0",
"react-helmet-async": "^1.0.4", "react-helmet-async": "^1.0.4",
"umi": "^3.5.0", "umi": "^3.5.0",
"umi-serve": "^1.9.10" "umi-serve": "^1.9.10",
"web3": "^1.7.5"
}, },
"devDependencies": { "devDependencies": {
"@ant-design/pro-cli": "^2.0.2", "@ant-design/pro-cli": "^2.0.2",

View File

@ -0,0 +1,6 @@
export enum TimeType {
DAY = 'day',
WEEK = 'week',
MONTH = 'month',
}
export default TimeType;

View File

@ -0,0 +1,102 @@
import React, { useRef, useState } from 'react';
import echarts from 'echarts/lib/echarts';
import {
getActiveData,
getMonthUserData,
getOldUserData,
getTodayUserData,
getWeekUserData,
} from '@/services/dataBorad/activeAnalysis';
import MoreData from '@/widget/MoreData';
import ReactEcharts from 'echarts-for-react';
import { Card, Col, Row, Select } from 'antd';
const ActiveAnalysis: React.FC = () => {
const { Option } = Select;
const [timeType, setTimeType] = useState('day');
const getData = async (func) => {
const res = await func({});
return res.data;
};
const [data, setData] = useState(getData(getTodayUserData));
const [oldUserData, setOldUserData] = useState(getData(getOldUserData));
const [weekData, setWeekData] = useState(getData(getWeekUserData));
const [monthData, setMonthData] = useState(getData(getMonthUserData));
const getOption = async (item = 'day') => {
const res = await getActiveData({ time_type: item });
const xData: any = [];
const seriesData: any = [];
res.data.foreach((item: any) => {
xData.push(item.time);
seriesData.push(item.dwn);
});
const option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
// data: xData,
},
yAxis: {
type: 'value',
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 360],
// data: seriesData.reverse(),
type: 'line',
},
],
};
return option;
};
const [option, setOption] = useState(getOption);
const setTimeOption = (val: any) => {
setTimeType(val);
setOption(getOption(val));
};
return (
<div>
<Row gutter={24} justify="space-between" style={{ marginBottom: 10 }}>
<Col span={6}>
<Card style={{ height: '200px' }}>{MoreData(data, '今日活跃用户数')}</Card>
</Col>
<Col span={6}>
<Card style={{ height: '200px' }}>{MoreData(oldUserData, '今日登录老用户数')}</Card>
</Col>
<Col span={6}>
<Card style={{ height: '200px' }}>{MoreData(weekData, 'WAU(本周去重人数)')}</Card>
</Col>
<Col span={6}>
<Card style={{ height: '200px' }}>{MoreData(monthData, 'MAU(本月去重人数)')}</Card>
</Col>
</Row>
<Card style={{ width: '100%' }}>
<Row gutter={32} style={{ marginBottom: 10 }}>
<Col span={6}>
<h1></h1>
<Select
defaultValue="lucy"
value={timeType}
style={{ width: 100 }}
bordered={false}
onChange={(val) => {
setTimeOption(val);
}}
>
<Option value="day"></Option>
<Option value="week"></Option>
<Option value="month"></Option>
</Select>
</Col>
<Col span={18}>
<ReactEcharts option={option} />
</Col>
</Row>
</Card>
</div>
);
};
export default ActiveAnalysis;

View File

@ -0,0 +1,145 @@
import React, { useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import moment from 'moment';
import TimeType from '@/constants/enum/timeType';
import { getData } from '@/utils/getData';
import MoreData from '@/widget/MoreData';
import {
getCoreData,
getPayData,
getTodayUserData,
getMonthPayData,
getNewUserData,
} from '@/services/dataBorad/coreData';
import { Card, Col, Row, Select } from 'antd';
const CoreData: React.FC = () => {
const tableRef = useRef<ActionType>();
const [timeType, setTimeType] = useState(TimeType.DAY);
// const [date, setDate] = useState(getData);
const [userDate, setUserDate] = useState(getData(getTodayUserData));
const [newUserdate, setNewUserDate] = useState(getData(getNewUserData));
const [payData, setPayDate] = useState(getData(getMonthPayData));
const [allPay, setAllPayDate] = useState(getData(getPayData));
const columns: ProColumns<any>[] = [
{
title: '时间类型',
dataIndex: 'coinType',
hideInTable: true,
initialValue: TimeType.DAY,
renderFormItem: (item, { type, defaultRender, ...rest }, form) => {
return (
<Select
options={[
{
label: '每日',
value: TimeType.DAY,
},
{
label: '每周',
value: TimeType.WEEK,
},
{
label: '每月',
value: TimeType.MONTH,
},
]}
onChange={(val) => {
setTimeType(val);
}}
/>
);
},
},
{
title: '日期',
dataIndex: 'time',
hideInSearch: true,
width: '10%',
},
{
title: '时间',
dataIndex: 'select_time',
valueType: 'dateRange',
width: '20%',
hideInTable: true,
ellipsis: true,
},
{
title: '活跃用户数',
dataIndex: 'address',
hideInSearch: true,
width: '20%',
},
{
title: '新用户数量',
dataIndex: 'new_user',
width: 150,
hideInSearch: true,
},
{
title: '当日充值总额',
dataIndex: 'address',
hideInSearch: true,
width: '20%',
},
{
title: '付费用户数',
dataIndex: 'address',
hideInSearch: true,
width: '20%',
},
{
title: '付费率',
dataIndex: 'address',
hideInSearch: true,
width: '20%',
},
{
title: 'ARPU',
dataIndex: 'arpu',
hideInSearch: true,
width: '20%',
},
{
title: 'ARPPU',
dataIndex: 'arppu',
hideInSearch: true,
width: '20%',
},
];
return (
<div>
<Row gutter={24} style={{ marginBottom: 10 }}>
<Col span={6}>
<Card style={{ height: '200px' }}>{MoreData(userDate, '今日活跃用户数', '人')}</Card>
</Col>
<Col span={6}>
<Card style={{ height: '200px' }}>{MoreData(newUserdate, '今日新增人数', '人')}</Card>
</Col>
<Col span={6}>
<Card style={{ height: '200px' }}>{MoreData(payData, '本月充值总额', '万元')}</Card>
</Col>
<Col span={6}>
<Card style={{ height: '200px' }}>{MoreData(allPay, '充值总额', '万元')}</Card>
</Col>
</Row>
<Table
columns={columns}
rowKey="id"
actionRef={tableRef}
request={async (params) => {
if ((params.select_time ?? '') !== '') {
params.start_time = moment(params.select_time[0]).valueOf() / 1000;
params.end_time = moment(params.select_time[1]).valueOf() / 1000;
}
return getCoreData(params);
}}
/>
</div>
);
};
export default CoreData;

View File

@ -0,0 +1,116 @@
import React, { useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import { getRententionData } from '@/services/dataBorad/rechargeAnalysis';
import { Select } from 'antd';
import moment from 'moment';
import TimeType from '@/constants/enum/timeType';
const Address: React.FC = () => {
const tableRef = useRef<ActionType>();
const [timeType, setTimeType] = useState(TimeType.DAY);
const columns: ProColumns<any>[] = [
{
title: '时间类型',
dataIndex: 'time_type',
hideInTable: true,
initialValue: TimeType.DAY,
renderFormItem: (item, { type, defaultRender, ...rest }, form) => {
return (
<Select
options={[
{
label: '每日',
value: TimeType.DAY,
},
{
label: '每周',
value: TimeType.WEEK,
},
{
label: '每月',
value: TimeType.MONTH,
},
]}
onChange={(val) => {
setTimeType(val);
}}
/>
);
},
},
{
title: '日期',
dataIndex: 'time',
width: '10%',
hideInSearch: true,
},
{
title: '时间筛选',
dataIndex: 'timeData',
hideInTable: true,
width: '20%',
},
{
title: '时间',
dataIndex: 'select_time',
valueType: 'dateRange',
width: '20%',
hideInTable: true,
ellipsis: true,
},
{
title: '付费次数',
dataIndex: 'pay_num',
hideInSearch: true,
width: '20%',
},
{
title: '付费用户数',
dataIndex: 'pay_user',
width: 150,
hideInSearch: true,
},
{
title: '付费金额',
dataIndex: 'pay_price',
hideInSearch: true,
width: '20%',
},
{
title: '付费率',
dataIndex: 'rate',
hideInSearch: true,
width: '20%',
},
{
title: 'ARPU',
dataIndex: 'arpu',
hideInSearch: true,
width: '20%',
},
{
title: 'ARPPU',
dataIndex: 'arppu',
hideInSearch: true,
width: '20%',
},
];
return (
<Table
columns={columns}
rowKey="id"
actionRef={tableRef}
// search={false}
request={async (params) => {
if ((params.select_time ?? '') !== '') {
params.start_time = moment(params.select_time[0]).valueOf() / 1000;
params.end_time = moment(params.select_time[1]).valueOf() / 1000;
}
return getRententionData(params);
}}
/>
);
};
export default Address;

View File

@ -0,0 +1,86 @@
import React, { useRef } from 'react';
import Modal, { ModalProps } from '@/components/Modal';
import { fetchTableData } from '@/utils/table';
import Table, { ProColumns, ActionType } from '@/components/Table';
import TimeText from '@/components/Typography/TimeText';
import { getChannelData } from '@/services/dataBorad/retentionAnalysis';
interface TableModalPropsType extends ModalProps {
modalData: any;
onCancel: () => void;
}
const TableModal = ({ onCancel, modalData, ...rest }: TableModalPropsType) => {
const tableRef = useRef<ActionType>();
const columns: ProColumns<any>[] = [
{
title: '时间',
dataIndex: 'time',
hideInSearch: true,
width: '20%',
render: (_, row) => [<TimeText value={row} format={'YYYY-MM-DD'} />],
},
{
title: '渠道类型',
dataIndex: 'channel_name',
hideInSearch: true,
ellipsis: true,
},
{
title: '登录用户数',
dataIndex: 'login_user',
hideInSearch: true,
ellipsis: true,
},
{
title: '第一日',
dataIndex: 'day_one',
hideInSearch: true,
},
{
title: '第二日',
dataIndex: 'day_two',
hideInSearch: true,
},
{
title: '第四日',
dataIndex: 'day_three',
hideInSearch: true,
},
{
title: '第五日',
dataIndex: 'day_four',
hideInSearch: true,
},
{
title: '第六日',
dataIndex: 'day_five',
hideInSearch: true,
},
{
title: '第七日',
dataIndex: 'day_seven',
hideInSearch: true,
},
];
const handleCancel = () => {
onCancel();
};
return (
<Modal title="渠道活跃分析" onCancel={handleCancel} width={800} {...rest}>
<Table
columns={columns}
rowKey="id"
search={false}
actionRef={tableRef}
request={async (params) => {
params.time = modalData;
return fetchTableData(getChannelData, params);
}}
/>
</Modal>
);
};
export default TableModal;

View File

@ -0,0 +1,107 @@
import React, { useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import moment from 'moment';
import { fetchTableData } from '@/utils/table';
import { getRententionData } from '@/services/dataBorad/retentionAnalysis';
import TableModal from './components/TableModal';
const RetentionAnalysis = () => {
const [visible, setVisible] = useState(false);
const [requestData, setRequestData] = useState();
const sendData = (row: any) => {
setVisible(true);
setRequestData(row.time);
};
const tableRef = useRef<ActionType>();
const columns: ProColumns<any>[] = [
{
title: '时间',
dataIndex: 'time',
},
{
title: '时间',
dataIndex: 'select_time',
valueType: 'dateRange',
width: '20%',
hideInTable: true,
ellipsis: true,
},
{
title: '登录用户数',
dataIndex: 'login_user',
hideInSearch: true,
ellipsis: true,
},
{
title: '第一日',
dataIndex: 'day_one',
hideInSearch: true,
},
{
title: '第二日',
dataIndex: 'day_two',
hideInSearch: true,
},
{
title: '第四日',
dataIndex: 'day_three',
hideInSearch: true,
},
{
title: '第五日',
dataIndex: 'day_four',
hideInSearch: true,
},
{
title: '第六日',
dataIndex: 'day_five',
hideInSearch: true,
},
{
title: '第七日',
dataIndex: 'day_seven',
hideInSearch: true,
},
{
title: '操作',
valueType: 'option',
width: 150,
render: (_, row) => [
<button
key="edit"
onClick={() => {
sendData(row);
}}
>
</button>,
],
},
];
return (
<div>
<Table
columns={columns}
rowKey="id"
actionRef={tableRef}
request={async (params) => {
if ((params.select_time ?? '') !== '') {
params.start_time = moment(params.select_time[0]).valueOf() / 1000;
params.end_time = moment(params.select_time[1]).valueOf() / 1000;
}
return await fetchTableData(getRententionData, params);
}}
/>
<TableModal
visible={visible}
modalData={requestData}
onCancel={function () {
setVisible(false);
}}
/>
</div>
);
};
export default RetentionAnalysis;

View File

@ -0,0 +1,63 @@
import React, { useRef } from 'react';
import { createForm } from '@formily/core';
import { createSchemaField } from '@formily/react';
import Modal, { ModalProps } from '@/components/Modal';
// import { fetchTableData } from '@/utils/table';
import { Form, FormItem, Input, NumberPicker } from '@formily/antd';
interface AddNftContractModalPropsType extends ModalProps {
onOk: (val: any) => void;
onCancel: () => void;
}
const SchemaField = createSchemaField({
components: {
FormItem,
Input,
NumberPicker,
},
});
const form = createForm({});
const AddNftContractModal = ({ onOk, onCancel, ...rest }: AddNftContractModalPropsType) => {
const handleOk = () => {
const formState = form.getFormState();
onOk(formState.values);
};
const handleCancel = () => {
onCancel();
};
return (
<Modal title="添加合约" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}>
<Form form={form} labelCol={4} wrapperCol={18}>
<SchemaField>
<SchemaField.String
name="contract_name"
title="名称"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.Number
name="contract_address"
title="合约"
required
x-decorator="FormItem"
x-component="NumberPicker"
/>
<SchemaField.Number
name="description"
title=""
required
x-decorator="FormItem"
x-component="NumberPicker"
/>
</SchemaField>
</Form>
</Modal>
);
};
export default AddNftContractModal;

View File

@ -0,0 +1,73 @@
import React, { useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import { message } from 'antd';
// import { fetchTableData } from '@/utils/table';
import AddNftContractModal from './components/AddNftContract';
const Address: React.FC = () => {
const tableRef = useRef<ActionType>();
const [NftModal, setNftModal] = useState(false);
const [visible, setVisible] = useState(false);
const columns: ProColumns<any>[] = [
{
title: '合约名称',
dataIndex: 'time',
width: '10%',
hideInSearch: true,
},
{
title: '合约地址',
dataIndex: 'address',
hideInSearch: true,
width: '20%',
},
{
title: 'NFT数量',
dataIndex: 'nft_num',
width: 150,
hideInSearch: true,
},
];
return (
<div>
<Table
columns={columns}
rowKey="id"
actionRef={tableRef}
toolBarActions={[
{
type: 'add',
text: '新建NFT合约',
onConfirm: () => {
setVisible(true);
},
},
]}
// request={async (params) => {
// // return fetchTableData(, params);
// }}
/>
<AddNftContractModal
visible={NftModal}
onCancel={function () {
setNftModal(false);
}}
onOk={async function (val: any): Promise<void> {
try {
const params = { ...val };
// await creatNftAddress(params);
message.success('添加成功');
} catch (e) {
console.log(e);
message.success('发生错误');
setVisible(false);
}
}}
/>
</div>
);
};
export default Address;

View File

@ -0,0 +1,70 @@
import React, { useRef } from 'react';
import { createForm } from '@formily/core';
import { createSchemaField } from '@formily/react';
import Modal, { ModalProps } from '@/components/Modal';
// import { fetchTableData } from '@/utils/table';
import { Form, FormItem, Input, NumberPicker } from '@formily/antd';
interface AddNftModalPropsType extends ModalProps {
onOk: (val: any) => void;
onCancel: () => void;
}
const SchemaField = createSchemaField({
components: {
FormItem,
Input,
NumberPicker,
},
});
const form = createForm({});
const AddNftModal = ({ onOk, onCancel, ...rest }: AddNftModalPropsType) => {
const handleOk = () => {
const formState = form.getFormState();
onOk(formState.values);
};
const handleCancel = () => {
onCancel();
};
return (
<Modal title="添加NFT" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}>
<Form form={form} labelCol={4} wrapperCol={18}>
<SchemaField>
<SchemaField.String
name="nft_name"
title="名称"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.Number
name="contract"
title="合约"
required
x-decorator="FormItem"
x-component="NumberPicker"
/>
<SchemaField.Number
name="description"
title="描述"
required
x-decorator="FormItem"
x-component="NumberPicker"
/>
<SchemaField.Number
name="img"
title="图片"
required
x-decorator="FormItem"
x-component="NumberPicker"
/>
</SchemaField>
</Form>
</Modal>
);
};
export default AddNftModal;

View File

@ -0,0 +1,101 @@
import React, { useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import { message } from 'antd';
// import { fetchTableData } from '@/utils/table';
import AddNftModal from './components/AddNftModel';
import PaySelectModal from '@/widget/PaySelectModal';
const Address: React.FC = () => {
const tableRef = useRef<ActionType>();
const [NftModal, setNftModal] = useState(false);
const [visible, setVisible] = useState(false);
const [payVisible, setPayVisible] = useState(false);
const columns: ProColumns<any>[] = [
{
title: '合约名称',
dataIndex: 'time',
width: '10%',
hideInSearch: true,
},
{
title: 'NFT名称',
dataIndex: 'address',
hideInSearch: true,
width: '20%',
},
{
title: 'TokenId',
dataIndex: 'token_id',
width: 150,
hideInSearch: true,
},
];
return (
<div>
<Table
columns={columns}
rowKey="id"
actionRef={tableRef}
toolBarActions={[
{
type: 'add',
text: '添加NFT',
onConfirm: () => {
setVisible(true);
},
},
{
type: 'add',
text: '分发NFT',
onConfirm: () => {
setNftModal(true);
},
},
]}
// request={async (params) => {
// // return fetchTableData(, params);
// }}
/>
<AddNftModal
visible={visible}
onCancel={function () {
setVisible(false);
}}
onOk={async function (val: any): Promise<void> {
try {
const params = { ...val };
// await creatNftAddress(params);
message.success('添加成功');
} catch (e) {
console.log(e);
message.success('发生错误');
setVisible(false);
}
}}
/>
<PaySelectModal
visible={payVisible}
onCancel={function () {
setVisible(false);
}}
onOk={async function (val: any): Promise<void> {
try {
const params = { ...val };
// await creatNftAddress(params);
console.log(params);
message.success('添加成功');
} catch (e) {
console.log(e);
message.success('发生错误');
setVisible(false);
}
}}
/>
</div>
);
};
export default Address;

View File

@ -93,33 +93,62 @@ export default [
}, },
], ],
}, },
// { {
// name: '设置', name: '数据看板',
// path: RoutePath.SETTING, path: RoutePath.DATABOARD,
// routes: [ routes: [
// { {
// path: RoutePath.SETTING, path: RoutePath.DATABOARD,
// redirect: RoutePath.WORK.LIST, redirect: RoutePath.COREDATA.LIST,
// hideInMenu: true, hideInMenu: true,
// }, },
// { {
// name: '作品', name: '核心看板',
// path: RoutePath.WORK.LIST, path: RoutePath.COREDATA.LIST,
// component: './Work/List', component: './DataBoard/CoreData/List',
// }, },
// { {
// name: '作品详情', name: '活跃分析',
// path: RoutePath.WORK.EDIT, path: RoutePath.ACTIVEANALYSIS.LIST,
// hideInMenu: true, component: './DataBoard/ActiveAnalysis/List',
// component: './Work/Edit', },
// }, {
// ], name: '留存分析',
// }, path: RoutePath.RETENTIONANALYSIS.LIST,
component: './DataBoard/RetentionAnalysis/List',
},
{
name: '用户充值分析',
path: RoutePath.RECHARGEANALYSIS.LIST,
component: './DataBoard/RechargeAnalysis/List',
},
],
},
{
name: 'NFT',
path: RoutePath.NFT,
routes: [
{
path: RoutePath.NFT,
redirect: RoutePath.NFTCONTRACT.LIST,
hideInMenu: true,
},
{
name: 'NFT合约管理',
path: RoutePath.NFTCONTRACT.LIST,
component: './NFT/NftContract/List',
},
{
name: 'NFT管理',
path: RoutePath.NFTTOKEN.LIST,
component: './NFT/NftToken/List',
},
],
},
{ {
path: '/', path: '/',
redirect: RoutePath.RECORD.LIST, redirect: RoutePath.RECORD.LIST,
}, },
{ {
component: './404', component: './404',
}, },

View File

@ -2,6 +2,8 @@ const SETTING = '/setting';
const RECHARGE = '/recharge'; const RECHARGE = '/recharge';
const USER = '/user'; const USER = '/user';
const SYSTEM = '/system'; const SYSTEM = '/system';
const DATABOARD = '/databoard';
const NFT = '/nft';
const RoutePath = { const RoutePath = {
LOGIN: '/login', LOGIN: '/login',
RECHARGE: RECHARGE, RECHARGE: RECHARGE,
@ -34,6 +36,26 @@ const RoutePath = {
NOTICE: { NOTICE: {
LIST: `${SYSTEM}/notice`, LIST: `${SYSTEM}/notice`,
}, },
NFT: NFT,
NFTCONTRACT: {
LIST: `${NFT}/nftcontract`,
},
NFTTOKEN: {
LIST: `${NFT}/nfttoken`,
},
DATABOARD: DATABOARD,
COREDATA: {
LIST: `${DATABOARD}/coredata`,
},
ACTIVEANALYSIS: {
LIST: `${DATABOARD}/activeanalysis`,
},
RETENTIONANALYSIS: {
LIST: `${DATABOARD}/retentionanalysis`,
},
RECHARGEANALYSIS: {
LIST: `${DATABOARD}/rechargeanalysis`,
},
SECRET_KEY: `${SYSTEM}/secret_key`, SECRET_KEY: `${SYSTEM}/secret_key`,
// SETTING: SETTING, // SETTING: SETTING,
// WORK: { // WORK: {

View File

@ -0,0 +1,41 @@
import request from '@/utils/request';
//获取基础数据报表
export const getActiveData = (data) => {
return request.request({
url: '/tgb/api/v1/data/get',
method: 'post',
data,
});
};
// 获取今日登陆人数接口
export const getTodayUserData = (params) => {
return request.request({
url: '/tgb/api/v1/data/user/today',
method: 'get',
params,
});
};
//获取本日新用户人数
export const getMonthUserData = (params) => {
return request.request({
url: '/tgb/api/v1/data/user/month',
method: 'get',
params,
});
};
// 获取本周登录人数
export const getWeekUserData = (params) => {
return request.request({
url: '/tgb/api/v1/data/user/week',
method: 'get',
params,
});
};
// 获取本日老用户登录人数
export const getOldUserData = (params) => {
return request.request({
url: '/tgb/api/v1/data/user/old',
method: 'get',
params,
});
};

View File

@ -0,0 +1,41 @@
import request from '@/utils/request';
//获取基础数据报表
export const getCoreData = (data) => {
return request.request({
url: '/tgb/api/v1/data/get',
method: 'post',
data,
});
};
// 获取今日登陆人数接口
export const getTodayUserData = (params) => {
return request.request({
url: '/tgb/api/v1/data/user/today',
method: 'get',
params,
});
};
//获取今日新用户
export const getNewUserData = (params) => {
return request.request({
url: '/tgb/api/v1/data/user/new',
method: 'get',
params,
});
};
// 获取充值总额
export const getPayData = (params) => {
return request.request({
url: '/tgb/api/v1/data/pay/all',
method: 'get',
params,
});
};
// 获取本月充值总额
export const getMonthPayData = (params) => {
return request.request({
url: '/tgb/api/v1/data/pay/month',
method: 'get',
params,
});
};

View File

@ -0,0 +1,9 @@
import request from '@/utils/request';
//获取基础数据报表
export const getRententionData = (data) => {
return request.request({
url: '/tgb/api/v1/data/get',
method: 'post',
data,
});
};

View File

@ -0,0 +1,17 @@
import request from '@/utils/request';
//获取基础数据报表
export const getRententionData = (data) => {
return request.request({
url: '/tgb/api/v1/data/get',
method: 'post',
data,
});
};
//获取渠道
export const getChannelData = (data) => {
return request.request({
url: '/tgb/api/v1/data/get',
method: 'post',
data,
});
};

View File

@ -0,0 +1,42 @@
import Web3 from 'web3';
import detectEthereumProvider from '@metamask/detect-provider';
import { message } from 'antd';
let provider: any;
export const web3 = new Web3();
if (typeof window.ethereum !== 'undefined') {
web3.eth.defaultAccount = window.ethereum.selectedAddress;
}
export async function initWeb3() {
provider = await detectEthereumProvider();
if (!provider) {
console.log('请安装MetaMask');
return false;
}
try {
web3.setProvider(provider);
const accounts = await provider.request({
method: 'eth_requestAccounts',
});
web3.eth.defaultAccount = accounts[0];
return true;
} catch (reason) {
switch (reason) {
case 'Already processing eth_requestAccounts. Please wait.': // 已有请求存在
message.warning('请打开MetaMask完成授权');
break;
case 'User rejected provider access': //如果用户拒绝了登录请求
message.warning('请同意登录请求');
break;
default:
// 本不该执行到这里,但是真到这里了,说明发生了意外
message.warning('登录出错err:' + reason);
break;
}
}
return false;
}

4
src/utils/getData.ts Normal file
View File

@ -0,0 +1,4 @@
export const getData = async (fetch: any) => {
const res = (await fetch()) || {};
return res.data;
};

45
src/widget/MoreData.tsx Normal file
View File

@ -0,0 +1,45 @@
import { Col, Row, Statistic } from 'antd';
import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
const MoreData = (props: any, title: string, company = '人') => {
return (
<div>
<p>{title}</p>
<h2>{props.time}</h2>
<h1>
{props.mon_user}
{company}
</h1>
<div>
<Row>
<Col span={12}>
<Statistic
title="较环比"
value={props.day_proportion}
valueStyle={
props.week_proportion > 0
? { color: '#3f8600', fontSize: 15 }
: { color: '#cf1322', fontSize: 15 }
}
prefix={props.week_proportion > 0 ? <ArrowDownOutlined /> : <ArrowUpOutlined />}
suffix="%"
/>
</Col>
<Col span={12}>
<Statistic
title="较同比"
value={Math.abs(props.week_proportion)}
valueStyle={
props.week_proportion > 0
? { color: '#3f8600', fontSize: 15 }
: { color: '#cf1322', fontSize: 15 }
}
prefix={props.week_proportion > 0 ? <ArrowDownOutlined /> : <ArrowUpOutlined />}
suffix="%"
/>
</Col>
</Row>
</div>
</div>
);
};
export default MoreData;

View File

@ -0,0 +1,67 @@
import React, { useRef, useState } from 'react';
import { createForm, onFieldChange } from '@formily/core';
import { createSchemaField } from '@formily/react';
import Modal, { ModalProps } from '@/components/Modal';
// import { fetchTableData } from '@/utils/table';
import { Form, FormItem, Input, Select, Radio, Switch } from '@formily/antd';
interface PaySelectModalPropsType extends ModalProps {
onOk: (val: any) => void;
onCancel: () => void;
// modalData: any;
}
const SchemaField = createSchemaField({
components: {
FormItem,
Input,
Select,
Radio,
Switch,
},
});
const form = createForm({});
const PaySelectModal = ({ onOk, onCancel, ...rest }: PaySelectModalPropsType) => {
const [send, useSend] = useState(true);
const handleOk = () => {
const formState = form.getFormState();
onOk(formState.values);
};
const handleCancel = () => {
onCancel();
};
return (
<Modal title="选择方式" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}>
<Form form={form} labelCol={4} wrapperCol={18}>
<SchemaField>
<SchemaField.Number
name="type"
title="支付方式"
required
x-decorator="FormItem"
x-component="Radio.Group"
enum={[
{ label: '秘钥支付', value: 1 },
{ label: '小狐狸钱包支付', value: 2 },
]}
/>
<SchemaField.String
name="key"
title="秘钥"
x-decorator="FormItem"
x-component="Input"
x-component-props={{
placeholder: '请输入秘钥,若使用小狐狸支付则不需要输入',
}}
/>
</SchemaField>
</Form>
</Modal>
);
};
export default PaySelectModal;

23821
yarn.lock

File diff suppressed because it is too large Load Diff