新增钱包地址,充值记录

This commit is contained in:
vancekk 2022-06-20 14:40:37 +08:00
parent 25af48a219
commit 8fa974f0b5
11 changed files with 15264 additions and 11947 deletions

View File

@ -56,12 +56,16 @@
"@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",
"@walletconnect/client": "^1.7.1",
"@walletconnect/qrcode-modal": "^1.7.1",
"ahooks": "^2.10.14", "ahooks": "^2.10.14",
"antd": "^4.17.2", "antd": "^4.17.2",
"axios": "^0.24.0", "axios": "^0.24.0",
"braft-editor": "^2.3.9", "braft-editor": "^2.3.9",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"js-md5": "^0.7.3",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"moment": "^2.25.3", "moment": "^2.25.3",
"omit.js": "^2.0.2", "omit.js": "^2.0.2",
@ -71,12 +75,10 @@
"react-dev-inspector": "^1.1.1", "react-dev-inspector": "^1.1.1",
"react-dom": "^17.0.0", "react-dom": "^17.0.0",
"react-helmet-async": "^1.0.4", "react-helmet-async": "^1.0.4",
"tronweb": "^4.2.0",
"umi": "^3.5.0", "umi": "^3.5.0",
"umi-serve": "^1.9.10", "umi-serve": "^1.9.10",
"web3": "^1.7.0", "web3": "^1.7.0"
"@metamask/detect-provider": "^1.2.0",
"@walletconnect/client": "^1.7.1",
"@walletconnect/qrcode-modal": "^1.7.1"
}, },
"devDependencies": { "devDependencies": {
"@ant-design/pro-cli": "^2.0.2", "@ant-design/pro-cli": "^2.0.2",

View File

@ -16,7 +16,7 @@ const Login: React.FC = () => {
await initWeb3(); await initWeb3();
const signInfo = await walletSign(); const signInfo = await walletSign();
const res: any = await login({ data: signInfo.raw, sign: signInfo.sign }); const res: any = await login({ data: signInfo.raw, sign: signInfo.sign });
localStorage.setItem(CACHE_TOKEN, res.token); localStorage.setItem(CACHE_TOKEN, res);
// const res: any = await login({ ...values }); // const res: any = await login({ ...values });
// localStorage.setItem(CACHE_TOKEN, res.token); // localStorage.setItem(CACHE_TOKEN, res.token);
/** 此方法会跳转到 redirect 参数所在的位置 */ /** 此方法会跳转到 redirect 参数所在的位置 */

View File

@ -0,0 +1,185 @@
import React, { useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import { Modal, Spin, message } from 'antd';
import DetailPageContainer from '@/components/DetailPageContainer';
import md5 from 'js-md5';
import {
Form,
FormItem,
Input,
Select,
Submit,
FormGrid,
ArrayItems,
Editable,
Switch,
ArrayTable,
FormButtonGroup,
NumberPicker,
} from '@formily/antd';
import { creatTronAddress, getAddressList } from '@/services/address';
import { createForm } from '@formily/core';
import { createSchemaField } from '@formily/react';
// import { web3 } from '@/utils/web3';
import { fetchTronTableData } from '@/utils/table';
// import { getTronBalance, getTronTokenBalance, setTronRpc } from '@/utils/tronweb';
// import { useIntl, history, FormattedMessage, useModel } from 'umi';
const Address: React.FC = () => {
const tableRef = useRef<ActionType>();
const [visible, setVisible] = useState(false);
const form = createForm({});
const [loading, setLoading] = useState(false);
const state = {
formRef: null,
confirmKey: '',
tokenList: [],
token: '',
form: {
coin_type: 'tron',
alias: '',
key: '',
num: 1,
},
queryForm: {
page: 1,
size: 20,
coinType: 'tron',
},
};
const SchemaField = createSchemaField({
components: {
FormItem,
FormGrid,
Input,
Select,
ArrayTable,
Switch,
ArrayItems,
NumberPicker,
Editable,
},
});
// const addAddress = () => {
// setVisible(true);
// };
const handleSubmit = async (val) => {
const params = { ...val };
setLoading(true);
params.cointype = 'tron';
params.key = md5(params.key);
const res = await creatTronAddress(params);
// if(res.code == 200){
// }
tableRef.current?.reload();
message.success('操作成功');
setLoading(false);
// history.back();
// } catch (e) {
// setLoading(false);
// }
};
// const save = async () => {
// const res = await makeTronAddress(state.form);
// };
// const featchdata = async (item) => {
// const res = await getAddressList(state.form);
// const ret = item
// };
const columns: ProColumns<any>[] = [
{
title: '备注',
dataIndex: 'alias',
width: '10%',
hideInSearch: true,
},
{
title: '地址',
dataIndex: 'address',
hideInSearch: true,
width: '20%',
},
{
title: '余额',
dataIndex: 'balance',
hideInSearch: true,
},
{
title: 'key',
dataIndex: 'key',
width: 150,
hideInSearch: true,
},
];
return (
<div>
<Table
columns={columns}
rowKey="id"
actionRef={tableRef}
toolBarActions={[
{
type: 'add',
onConfirm: () => {
setVisible(true);
},
},
]}
request={async (params) => {
return fetchTronTableData(getAddressList, params);
}}
/>
<Modal
title="添加地址"
centered
visible={visible}
onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
width={800}
>
<DetailPageContainer>
<Spin spinning={loading}>
<Form form={form} labelCol={4} wrapperCol={18} onAutoSubmit={handleSubmit}>
<SchemaField>
<SchemaField.String
name="alias"
title="备注名"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.String
name="key"
title="密码"
required
x-component-props={{ maxLength: 100, showCount: true }}
x-decorator="FormItem"
x-component="Input.TextArea"
/>
<SchemaField.Number
name="num"
title="数量"
required
x-validator="number"
x-decorator="FormItem"
x-component="NumberPicker"
/>
</SchemaField>
<FormButtonGroup.FormItem>
<Submit block size="large">
</Submit>
</FormButtonGroup.FormItem>
</Form>
</Spin>
</DetailPageContainer>
</Modal>
</div>
);
};
export default Address;

View File

@ -0,0 +1,100 @@
import React, { useRef } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import { Button } from 'antd';
import { Link } from 'umi';
import RoutePath from '@/routes/routePath';
import { fetchTronTableData } from '@/utils/table';
import { getTronRecord } from '@/services/address';
import { PlusCircleOutlined } from '@ant-design/icons';
const Address: React.FC = () => {
const tableRef = useRef<ActionType>();
const addAddress = () => {};
const columns: ProColumns<any>[] = [
{
title: '交易哈希',
dataIndex: 'tx',
width: '10%',
hideInSearch: true,
},
{
title: '金额',
dataIndex: 'amount',
hideInSearch: true,
width: '20%',
},
{
title: '链名称',
dataIndex: 'chain',
ellipsis: true,
},
{
title: '转换后的数量',
dataIndex: 'symbol',
width: 150,
},
{
title: '位数',
dataIndex: 'rpcUrl',
width: 150,
},
{
title: '发送地址',
dataIndex: 'decimals',
width: 150,
},
{
title: '通知地址',
dataIndex: 'browser',
width: 150,
},
{
title: '时间',
dataIndex: 'timesTamp',
width: 150,
},
{
title: '合约地址',
dataIndex: 'toAddress',
width: 150,
},
{
title: 'Token名称',
dataIndex: 'contract',
width: 150,
},
{
title: '状态',
dataIndex: 'contract',
width: 150,
},
];
return (
<div>
<div>
<Button type="primary" icon={<PlusCircleOutlined />} onClick={addAddress}>
</Button>
</div>
<Table
columns={columns}
// indexColumn
rowKey="id"
actionRef={tableRef}
// toolBarActions={[
// {
// type: 'add',
// onConfirm: () => {
// history.push(RoutePath.WORK.EDIT);
// },
// },
// ]}
request={async (params) => {
return fetchTronTableData(getTronRecord, params);
}}
/>
</div>
);
};
export default Address;

View File

@ -0,0 +1,214 @@
import React, { useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import { Button, Modal, Spin, message } from 'antd';
import { PlusCircleOutlined } from '@ant-design/icons';
import { createSchemaField } from '@formily/react';
import { createForm } from '@formily/core';
import DetailPageContainer from '@/components/DetailPageContainer';
// import { fetchTronTableData } from '@/utils/table';
import {
Form,
FormItem,
Input,
Select,
Submit,
FormGrid,
ArrayItems,
Editable,
Switch,
ArrayTable,
FormButtonGroup,
NumberPicker,
} from '@formily/antd';
// import { useIntl, history, FormattedMessage, useModel } from 'umi';
const Address: React.FC = () => {
const tableRef = useRef<ActionType>();
const addAddress = () => {};
const form = createForm({});
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
const SchemaField = createSchemaField({
components: {
FormItem,
FormGrid,
Input,
Select,
ArrayTable,
Switch,
ArrayItems,
NumberPicker,
Editable,
},
});
const state = {
queryForm: {
page: 1,
size: 20,
coin_type: 'tron',
},
};
const columns: ProColumns<any>[] = [
{
title: '网络名称',
dataIndex: 'network',
width: '10%',
hideInSearch: true,
},
{
title: '地址',
dataIndex: 'address',
hideInSearch: true,
width: '20%',
},
{
title: 'API Key',
dataIndex: 'apiKey',
ellipsis: true,
},
{
title: '代币符号',
dataIndex: 'symbol',
width: 150,
},
{
title: 'RPC URL',
dataIndex: 'rpcUrl',
width: 150,
},
{
title: '精度',
dataIndex: 'decimals',
width: 150,
},
{
title: '区块浏览器',
dataIndex: 'browser',
width: 150,
},
{
title: '代币合约地址',
dataIndex: 'contract',
width: 150,
},
];
const handleSubmit = async (val) => {
const params = { ...val };
setLoading(true);
params.cointype = 'tron';
// const res = await makeTronAddress(params);
// if(res.code == 200){
// }
tableRef.current?.reload();
message.success('操作成功');
setLoading(false);
// history.back();
// } catch (e) {
// setLoading(false);
// }
};
return (
<div>
<div>
<Button type="primary" icon={<PlusCircleOutlined />} onClick={addAddress}>
</Button>
</div>
<Table
columns={columns}
// indexColumn
rowKey="id"
actionRef={tableRef}
toolBarActions={[
{
type: 'add',
onConfirm: () => {
setVisible(true);
},
},
]}
// request={async (params) => {
// return fetchTronTableData(queryWorkList, state.queryForm);
// }}
/>
<Modal
title="添加地址"
centered
visible={visible}
onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
width={800}
>
<DetailPageContainer>
<Spin spinning={loading}>
<Form form={form} labelCol={4} wrapperCol={18} onAutoSubmit={handleSubmit}>
<SchemaField>
<SchemaField.String
name="network"
title="网络名称"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.String
name="rpcUrl"
title="RPC URL"
required
x-component-props={{ maxLength: 100, showCount: true }}
x-decorator="FormItem"
x-component="Input.TextArea"
/>
<SchemaField.String
name="apiKey"
title="API Key"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.Number
name="contract"
title="代币合约地址(放空则查找主代币"
required
x-validator="number"
x-decorator="FormItem"
x-component="NumberPicker"
/>
<SchemaField.String
name="symbol"
title="代币符号"
required
x-decorator="FormItem"
x-component="Editor"
/>
<SchemaField.String
name="decimals"
title="精度"
required
x-decorator="FormItem"
x-component="Editor"
/>
<SchemaField.String
name="browser"
title="区块浏览器"
required
x-decorator="FormItem"
x-component="Editor"
/>
</SchemaField>
<FormButtonGroup.FormItem>
<Submit block size="large">
</Submit>
</FormButtonGroup.FormItem>
</Form>
</Spin>
</DetailPageContainer>
</Modal>
</div>
);
};
export default Address;

View File

@ -54,6 +54,32 @@ export default [
}, },
], ],
}, },
{
name: 'TRON',
path: RoutePath.TRON,
routes: [
{
path: RoutePath.TRON,
redirect: RoutePath.TRONRECORD.LIST,
hideInMenu: true,
},
{
name: 'TRON地址管理',
path: RoutePath.TRONADDRESS.LIST,
component: './Tron/Address/List',
},
{
name: 'TRON充值记录',
path: RoutePath.TRONRECORD.LIST,
component: './Tron/Record/List',
},
{
name: 'TRON币种类型',
path: RoutePath.TRONTOKEN.LIST,
component: './Tron/Token/List',
},
],
},
{ {
name: '设置', name: '设置',
path: RoutePath.SETTING, path: RoutePath.SETTING,

View File

@ -1,5 +1,6 @@
const SETTING = '/setting'; const SETTING = '/setting';
const ETH = '/eth'; const ETH = '/eth';
const TRON = '/tron';
const RoutePath = { const RoutePath = {
LOGIN: '/login', LOGIN: '/login',
ETH: ETH, ETH: ETH,
@ -15,6 +16,19 @@ const RoutePath = {
LIST: `${ETH}/currency`, LIST: `${ETH}/currency`,
EDIT: `${ETH}/currency/edit`, EDIT: `${ETH}/currency/edit`,
}, },
TRON: TRON,
TRONADDRESS: {
LIST: `${TRON}/tron/address/list`,
EDIT: `${TRON}/tron/address/edit`,
},
TRONRECORD: {
LIST: `${TRON}/tron/record`,
EDIT: `${TRON}/tron/record/edit`,
},
TRONTOKEN: {
LIST: `${TRON}/token`,
EDIT: `${TRON}/token/edit`,
},
SETTING: SETTING, SETTING: SETTING,
WORK: { WORK: {
LIST: `${SETTING}/work`, LIST: `${SETTING}/work`,

31
src/services/address.ts Normal file
View File

@ -0,0 +1,31 @@
import request from '@/utils/request';
// export const login = (data) => {
// return request.request({
// url: '/admin/login',
// method: 'post',
// data,
// });
// };
export const getAddressList = (data) => {
return request.request({
url: '/admin/api/v1/address/get',
method: 'post',
data,
});
};
export const getTronRecord = (data) => {
return request.request({
url: 'admin/api/v1/records/get',
method: 'post',
data,
});
};
export const creatTronAddress = (data) => {
return request.request({
url: 'admin/api/v1/address/mask',
method: 'post',
data,
});
};

View File

@ -1,4 +1,5 @@
// 格式化表格获取数据接口的返回 // 格式化表格获取数据接口的返回
import { getTronBalance } from './tronweb';
export const fetchTableData = async ( export const fetchTableData = async (
fetch: (params: any) => Promise<any>, fetch: (params: any) => Promise<any>,
params: any, params: any,
@ -22,3 +23,29 @@ export const fetchTableData = async (
total: res.total, total: res.total,
}; };
}; };
export const fetchTronTableData = async (
fetch: (params: any) => Promise<any>,
params: any,
formatObj: any = {},
) => {
params.page = params.page;
params.size = params.size;
params.coinType = 'tron';
// delete params.current;
// delete params.pageSize;
const res = (await fetch(params)) || {};
const data = res;
data?.forEach((n: any) => {
for (const key in formatObj) {
n[key] = n[formatObj[key]];
n.balance = getTronBalance(n.address);
console.log(n.balance);
}
});
return {
success: true,
data: data,
total: res.total,
};
};

30
src/utils/tronweb.ts Normal file
View File

@ -0,0 +1,30 @@
//@ts-ignore
import TronWeb from 'tronweb';
let tronWeb: any;
export function getTronWeb() {
return tronWeb;
}
//
// window.setTronRpc = setTronRpc;
export function setTronRpc(rpcUrl = 'https://api.trongrid.io', apiKey = '') {
const HttpProvider = TronWeb.providers.HttpProvider;
const fullNode = new HttpProvider(rpcUrl);
const solidityNode = new HttpProvider(rpcUrl);
const eventServer = new HttpProvider(rpcUrl);
// 这个私钥是随机生成的,可以自己生成
tronWeb = new TronWeb(
fullNode,
solidityNode,
eventServer,
'5B1E0F83361AD79F8B676CE205B50A6A036876D25F969F290F8017F87CAA9BA3',
);
tronWeb.setHeader({ 'TRON-PRO-API-KEY': apiKey });
}
export async function getTronBalance(account: any) {
return await tronWeb.trx.getBalance(account);
}

26572
yarn.lock

File diff suppressed because it is too large Load Diff