新增代币,NFT等模块功能实现

This commit is contained in:
zzy 2022-09-07 10:40:17 +08:00
parent 9b71639ff9
commit 514d0db8f3
40 changed files with 1044 additions and 222 deletions

View File

@ -11,7 +11,7 @@ export default {
// localhost:8000/api/** -> https://preview.pro.ant.design/api/** // localhost:8000/api/** -> https://preview.pro.ant.design/api/**
'/tbg/api/v1': { '/tbg/api/v1': {
// 要代理的地址 // 要代理的地址
target: 'http://192.168.2.11:9999', target: 'http://192.168.88.238:9999',
// 配置了这个可以从 http 代理到 https // 配置了这个可以从 http 代理到 https
// 依赖 origin 的功能可能需要这个,比如 cookie // 依赖 origin 的功能可能需要这个,比如 cookie
changeOrigin: true, changeOrigin: true,

BIN
dist.zip Normal file

Binary file not shown.

View File

@ -77,7 +77,9 @@
"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" "web3": "^1.7.5",
"@metamask/detect-provider": "^1.2.0"
}, },
"devDependencies": { "devDependencies": {
"@ant-design/pro-cli": "^2.0.2", "@ant-design/pro-cli": "^2.0.2",

View File

@ -1,9 +1,20 @@
/** /**
* @see https://umijs.org/zh-CN/plugins/plugin-access * @see https://umijs.org/zh-CN/plugins/plugin-access
* */ * */
export default function access(initialState: { currentUser?: API.CurrentUser | undefined }) {
const { currentUser } = initialState || {}; export default function access(initialState: {
currentUser?: API.CurrentUser | undefined;
routeList: any;
}) {
const { currentUser, routeList } = initialState || {};
return { return {
canAdmin: currentUser && currentUser.access === 'admin', canAdmin: currentUser && currentUser.access === 'admin',
normalRouteFilter: (route: any) => {
return true;
// if (routeList == null || routeList == undefined || routeList.length == 0) {
// return true;
// }
// return routeList.includes(route.name);
},
}; };
} }

View File

@ -4,8 +4,19 @@ import { history } from 'umi';
import RightContent from '@/components/RightContent'; import RightContent from '@/components/RightContent';
import RoutePath from '@/routes/routePath'; import RoutePath from '@/routes/routePath';
import { CACHE_TOKEN } from '@/constants/cacheKey'; import { CACHE_TOKEN } from '@/constants/cacheKey';
// import { getRoleList } from './services/system/role';
// ProLayout 支持的api https://procomponents.ant.design/components/layout // ProLayout 支持的api https://procomponents.ant.design/components/layout
// export async function getInitialState() {
// if (localStorage.getItem(CACHE_TOKEN)) {
// const res = await getRoleList({});
// return {
// routeList: res,
// };
// }
// }
export const layout: RunTimeLayoutConfig = ({ initialState }) => { export const layout: RunTimeLayoutConfig = ({ initialState }) => {
return { return {
rightContentRender: () => <RightContent />, rightContentRender: () => <RightContent />,

View File

@ -0,0 +1,196 @@
[
{
"inputs": [
{ "internalType": "uint256", "name": "initialSupply", "type": "uint256" },
{ "internalType": "uint8", "name": "initialDecimals", "type": "uint8" },
{ "internalType": "string", "name": "tokenName", "type": "string" },
{ "internalType": "string", "name": "tokenSymbol", "type": "string" }
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "internalType": "address", "name": "sender", "type": "address" },
{ "indexed": true, "internalType": "address", "name": "spender", "type": "address" },
{ "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" }
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "internalType": "address", "name": "from", "type": "address" },
{ "indexed": true, "internalType": "address", "name": "to", "type": "address" },
{ "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" }
],
"name": "Transfer",
"type": "event"
},
{
"constant": true,
"inputs": [
{ "internalType": "address", "name": "owner", "type": "address" },
{ "internalType": "address", "name": "spender", "type": "address" }
],
"name": "allowance",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "internalType": "address", "name": "", "type": "address" },
{ "internalType": "address", "name": "", "type": "address" }
],
"name": "allowed",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "internalType": "address", "name": "spender", "type": "address" },
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
],
"name": "approve",
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "internalType": "address", "name": "", "type": "address" }],
"name": "balances",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [{ "internalType": "string", "name": "", "type": "string" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "internalType": "uint256", "name": "a", "type": "uint256" },
{ "internalType": "uint256", "name": "b", "type": "uint256" }
],
"name": "safeAdd",
"outputs": [{ "internalType": "uint256", "name": "c", "type": "uint256" }],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "internalType": "uint256", "name": "a", "type": "uint256" },
{ "internalType": "uint256", "name": "b", "type": "uint256" }
],
"name": "safeDiv",
"outputs": [{ "internalType": "uint256", "name": "c", "type": "uint256" }],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "internalType": "uint256", "name": "a", "type": "uint256" },
{ "internalType": "uint256", "name": "b", "type": "uint256" }
],
"name": "safeMul",
"outputs": [{ "internalType": "uint256", "name": "c", "type": "uint256" }],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [
{ "internalType": "uint256", "name": "a", "type": "uint256" },
{ "internalType": "uint256", "name": "b", "type": "uint256" }
],
"name": "safeSub",
"outputs": [{ "internalType": "uint256", "name": "c", "type": "uint256" }],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [{ "internalType": "string", "name": "", "type": "string" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "internalType": "address", "name": "to", "type": "address" },
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
],
"name": "transfer",
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "internalType": "address", "name": "from", "type": "address" },
{ "internalType": "address", "name": "to", "type": "address" },
{ "internalType": "uint256", "name": "amount", "type": "uint256" }
],
"name": "transferFrom",
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]

View File

@ -0,0 +1,4 @@
export enum ContractType {
ERC20 = '20',
NFT721 = '721',
}

View File

@ -0,0 +1,7 @@
export enum NoticeType {
RECHARGE = 10000,
WITHDRAW = 20000,
NFTCREATE = 30000,
NFTTRANSFER = 30010,
NFTTDISPOSE = 30020,
}

View File

@ -0,0 +1,5 @@
export enum WithdrawType {
SUCCESS = 10000,
FAILED = 20000,
PENDDING = 30000,
}

View File

@ -6,10 +6,11 @@ import { login } from '@/services/login';
import defaultSettings from '../../../config/defaultSettings'; import defaultSettings from '../../../config/defaultSettings';
import styles from './index.less'; import styles from './index.less';
import { CACHE_TOKEN } from '@/constants/cacheKey'; import { CACHE_TOKEN } from '@/constants/cacheKey';
import access from '@/access';
const Login: React.FC = () => { const Login: React.FC = () => {
const intl = useIntl(); const intl = useIntl();
const { initialState, refresh } = useModel('@@initialState');
const handleSubmit = async (values: API.LoginParams) => { const handleSubmit = async (values: API.LoginParams) => {
// 登录 // 登录
const res: any = await login({ ...values }); const res: any = await login({ ...values });
@ -19,6 +20,8 @@ const Login: React.FC = () => {
const { query } = history.location; const { query } = history.location;
const { redirect } = query as { redirect: string }; const { redirect } = query as { redirect: string };
history.push(redirect || '/'); history.push(redirect || '/');
refresh();
access(initialState);
}; };
return ( return (

View File

@ -22,8 +22,10 @@ const form = createForm({});
const AddNftContractModal = ({ onOk, onCancel, ...rest }: AddNftContractModalPropsType) => { const AddNftContractModal = ({ onOk, onCancel, ...rest }: AddNftContractModalPropsType) => {
const handleOk = () => { const handleOk = () => {
form.submit(async () => {
const formState = form.getFormState(); const formState = form.getFormState();
onOk(formState.values); onOk(formState.values);
});
}; };
const handleCancel = () => { const handleCancel = () => {
onCancel(); onCancel();
@ -34,25 +36,25 @@ const AddNftContractModal = ({ onOk, onCancel, ...rest }: AddNftContractModalPro
<Form form={form} labelCol={4} wrapperCol={18}> <Form form={form} labelCol={4} wrapperCol={18}>
<SchemaField> <SchemaField>
<SchemaField.String <SchemaField.String
name="contract_name" name="token_name"
title="名称" title="合约名称"
required required
x-decorator="FormItem" x-decorator="FormItem"
x-component="Input" x-component="Input"
/> />
<SchemaField.Number <SchemaField.String
name="contract_address" name="token_symbol"
title="合约" title="合约单位"
required required
x-decorator="FormItem" x-decorator="FormItem"
x-component="NumberPicker" x-component="Input"
/> />
<SchemaField.Number <SchemaField.String
name="description" name="description"
title="" title="描述"
required required
x-decorator="FormItem" x-decorator="FormItem"
x-component="NumberPicker" x-component="Input"
/> />
</SchemaField> </SchemaField>
</Form> </Form>

View File

@ -1,32 +1,42 @@
import React, { useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table'; import Table, { ProColumns, ActionType } from '@/components/Table';
import { message } from 'antd'; import { message } from 'antd';
// import { fetchTableData } from '@/utils/table';
import AddNftContractModal from './components/AddNftContract'; import AddNftContractModal from './components/AddNftContract';
import { getContractInfo } from '@/services/contract';
import { ContractType } from '@/constants/enum/contract';
import { deployContract, initWeb3 } from '@/utils/web3';
import { createNFTContract, getNFTContractList } from '@/services/nft';
import { fetchTableData } from '@/utils/table';
const Address: React.FC = () => { const Address: React.FC = () => {
const tableRef = useRef<ActionType>(); const tableRef = useRef<ActionType>();
const [NftModal, setNftModal] = useState(false);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [contractData, setContractData] = useState({});
const columns: ProColumns<any>[] = [ const columns: ProColumns<any>[] = [
{ {
title: '合约名称', title: '合约名称',
dataIndex: 'time', dataIndex: 'token_name',
width: '10%', width: '15%',
hideInSearch: true,
},
{
title: '合约单位',
dataIndex: 'token_symbol',
width: '15%',
hideInSearch: true, hideInSearch: true,
}, },
{ {
title: '合约地址', title: '合约地址',
dataIndex: 'address', dataIndex: 'address',
hideInSearch: true, hideInSearch: true,
width: '20%', width: '50%',
}, },
{ {
title: 'NFT数量', title: '描述',
dataIndex: 'nft_num', dataIndex: 'description',
width: 150,
hideInSearch: true, hideInSearch: true,
ellipsis: true,
}, },
]; ];
@ -35,30 +45,44 @@ const Address: React.FC = () => {
<Table <Table
columns={columns} columns={columns}
rowKey="id" rowKey="id"
search={false}
actionRef={tableRef} actionRef={tableRef}
toolBarActions={[ toolBarActions={[
{ {
type: 'add', type: 'add',
text: '新建NFT合约', text: '新建NFT合约',
onConfirm: () => { onConfirm: async () => {
const res = await getContractInfo({ erc: ContractType.NFT721 });
if (res.bin != '') {
setContractData(res);
setVisible(true); setVisible(true);
} else {
message.success('已有NFT合约');
}
}, },
}, },
]} ]}
// request={async (params) => { request={async (params) => {
// // return fetchTableData(, params); const res = await fetchTableData(getNFTContractList, params);
// }} return res;
}}
/> />
<AddNftContractModal <AddNftContractModal
visible={NftModal} visible={visible}
onCancel={function () { onCancel={function () {
setNftModal(false); setVisible(false);
}} }}
onOk={async function (val: any): Promise<void> { onOk={async function (val: any): Promise<void> {
try { try {
const params = { ...val }; await initWeb3();
// await creatNftAddress(params); const res = await deployContract(contractData.abi, contractData.bin, [
val.token_name,
val.token_symbol,
]);
val.address = res;
await createNFTContract(val);
message.success('添加成功'); message.success('添加成功');
setVisible(false);
} catch (e) { } catch (e) {
console.log(e); console.log(e);
message.success('发生错误'); message.success('发生错误');

View File

@ -22,8 +22,10 @@ const form = createForm({});
const AddNftModal = ({ onOk, onCancel, ...rest }: AddNftModalPropsType) => { const AddNftModal = ({ onOk, onCancel, ...rest }: AddNftModalPropsType) => {
const handleOk = () => { const handleOk = () => {
form.submit(() => {
const formState = form.getFormState(); const formState = form.getFormState();
onOk(formState.values); onOk(formState.values);
});
}; };
const handleCancel = () => { const handleCancel = () => {
onCancel(); onCancel();
@ -33,33 +35,45 @@ const AddNftModal = ({ onOk, onCancel, ...rest }: AddNftModalPropsType) => {
<Modal title="添加NFT" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}> <Modal title="添加NFT" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}>
<Form form={form} labelCol={4} wrapperCol={18}> <Form form={form} labelCol={4} wrapperCol={18}>
<SchemaField> <SchemaField>
<SchemaField.Number
name="token_id"
title="ID"
x-decorator="FormItem"
x-component="NumberPicker"
/>
<SchemaField.String <SchemaField.String
name="nft_name" name="toAddress"
title="所有者地址"
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.String
name="name"
title="名称" title="名称"
required required
x-decorator="FormItem" x-decorator="FormItem"
x-component="Input" x-component="Input"
/> />
<SchemaField.Number <SchemaField.String
name="contract" name="image"
title="合约" title="图片"
required required
x-decorator="FormItem" x-decorator="FormItem"
x-component="NumberPicker" x-component="Input"
/> />
<SchemaField.Number <SchemaField.String
name="avatar"
title="缩略图"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.String
name="description" name="description"
title="描述" title="描述"
required required
x-decorator="FormItem" x-decorator="FormItem"
x-component="NumberPicker" x-component="Input"
/>
<SchemaField.Number
name="img"
title="图片"
required
x-decorator="FormItem"
x-component="NumberPicker"
/> />
</SchemaField> </SchemaField>
</Form> </Form>

View File

@ -0,0 +1,58 @@
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 TransferNFTModelPropsType extends ModalProps {
onOk: (val: any) => void;
onCancel: () => void;
}
const SchemaField = createSchemaField({
components: {
FormItem,
Input,
NumberPicker,
},
});
const form = createForm({});
const TransferNFTModel = ({ onOk, onCancel, ...rest }: TransferNFTModelPropsType) => {
const handleOk = async () => {
form.submit(async () => {
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="token_id"
title="ID"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.String
name="toAddress"
title="发送地址"
required
x-decorator="FormItem"
x-component="Input"
/>
</SchemaField>
</Form>
</Modal>
);
};
export default TransferNFTModel;

View File

@ -1,34 +1,49 @@
import React, { useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table'; import Table, { ProColumns, ActionType } from '@/components/Table';
import { message } from 'antd'; import { message } from 'antd';
// import { fetchTableData } from '@/utils/table'; import { fetchTableData } from '@/utils/table';
import AddNftModal from './components/AddNftModel'; import AddNftModal from './components/AddNftModel';
import PaySelectModal from '@/widget/PaySelectModal'; import { initWeb3, NFTMint } from '@/utils/web3';
import { getContractInfo } from '@/services/contract';
import { ContractType } from '@/constants/enum/contract';
import { checkTokenId, getNFTContractList, getNFTList, mintNFT } from '@/services/nft';
const Address: React.FC = () => { const Address: React.FC = () => {
const tableRef = useRef<ActionType>(); const tableRef = useRef<ActionType>();
const [NftModal, setNftModal] = useState(false);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [payVisible, setPayVisible] = useState(false);
const columns: ProColumns<any>[] = [ const columns: ProColumns<any>[] = [
{ {
title: '合约名称', title: 'TokenId',
dataIndex: 'time', dataIndex: 'token_id',
width: '10%', width: '10%',
hideInSearch: true, hideInSearch: true,
}, },
{ {
title: 'NFT名称', title: '所有者地址',
dataIndex: 'address', dataIndex: 'address',
hideInSearch: true, hideInSearch: true,
width: '20%',
}, },
{ {
title: 'TokenId', title: 'NFT名称',
dataIndex: 'token_id', dataIndex: 'name',
width: 150, hideInSearch: true,
},
{
title: '图片',
dataIndex: 'image',
hideInSearch: true,
ellipsis: true,
},
{
title: '缩略图',
dataIndex: 'avatar',
hideInSearch: true,
ellipsis: true,
},
{
title: '描述',
dataIndex: 'description',
hideInSearch: true, hideInSearch: true,
}, },
]; ];
@ -38,6 +53,7 @@ const Address: React.FC = () => {
<Table <Table
columns={columns} columns={columns}
rowKey="id" rowKey="id"
search={false}
actionRef={tableRef} actionRef={tableRef}
toolBarActions={[ toolBarActions={[
{ {
@ -47,17 +63,11 @@ const Address: React.FC = () => {
setVisible(true); setVisible(true);
}, },
}, },
{
type: 'add',
text: '分发NFT',
onConfirm: () => {
setNftModal(true);
},
},
]} ]}
// request={async (params) => { request={async (params) => {
// // return fetchTableData(, params); const res = await fetchTableData(getNFTList, params);
// }} return res;
}}
/> />
<AddNftModal <AddNftModal
visible={visible} visible={visible}
@ -65,33 +75,20 @@ const Address: React.FC = () => {
setVisible(false); setVisible(false);
}} }}
onOk={async function (val: any): Promise<void> { onOk={async function (val: any): Promise<void> {
try { await checkTokenId({ token_id: val.token_id });
const params = { ...val }; await initWeb3();
// await creatNftAddress(params); const contractInfo = await getContractInfo({ erc: ContractType.NFT721 });
message.success('添加成功'); const res = await getNFTContractList();
} catch (e) { await NFTMint({
console.log(e); abi: contractInfo.abi,
message.success('发生错误'); address: res.items[0].address,
toAddress: val.toAddress,
name: val.name,
token_id: val.token_id,
});
await mintNFT(val);
tableRef.current?.reload();
setVisible(false); 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> </div>

View File

@ -0,0 +1,81 @@
import React, { useRef } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table';
import { getRecordList } from '@/services/recharge/record';
import { fetchTableData } from '@/utils/table';
import moment from 'moment';
import { ContractType } from '@/constants/enum/contract';
const NFTTradeList = () => {
const tableRef = useRef<ActionType>();
const columns: ProColumns<any>[] = [
{
title: '时间',
dataIndex: 'time',
hideInTable: true,
valueType: 'dateRange',
ellipsis: true,
},
{
title: '交易哈希',
dataIndex: 'tx_hash',
hideInSearch: true,
ellipsis: true,
},
{
title: 'TokenID',
dataIndex: 'token_id',
width: '10%',
hideInSearch: true,
},
{
title: '块编号',
dataIndex: 'block_number',
hideInSearch: true,
},
{
title: '发送地址',
dataIndex: 'from_address',
hideInSearch: true,
ellipsis: true,
},
{
title: '接受地址',
dataIndex: 'to_address',
hideInSearch: true,
ellipsis: true,
},
{
title: '充值时间',
dataIndex: 'time',
hideInSearch: true,
ellipsis: true,
},
];
return (
<Table
columns={columns}
rowKey="id"
actionRef={tableRef}
request={async (params) => {
console.log('params = ', params);
if ((params.time ?? '') !== '') {
const start = Date.parse(params.time[0] + ' 00:00:00');
const end = Date.parse(params.time[1] + ' 23:59:59');
params.start_time = start / 1000;
params.end_time = end / 1000;
}
params.erc = ContractType.NFT721;
const res = await fetchTableData(getRecordList, params);
for (const key in res.data) {
if (Object.prototype.hasOwnProperty.call(res.data, key)) {
const element = res.data[key];
element.time = moment(element.time * 1000).format('YYYY-MM-DD hh:mm:ss');
}
}
return res;
}}
/>
);
};
export default NFTTradeList;

View File

@ -1,9 +1,12 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table'; import Table, { ProColumns, ActionType } from '@/components/Table';
import { addCoinType, getCoinTypeList, modifyCoinType } from '@/services/recharge/coinType'; import { addCoinType, getCoinTypeList, modifyCoinType } from '@/services/recharge/coinType';
import { getContractInfo } from '@/services/contract';
import { fetchTableData } from '@/utils/table'; import { fetchTableData } from '@/utils/table';
import AddCoinTypeModal from '../components/AddCoinTypeModal'; import AddCoinTypeModal from '../components/AddCoinTypeModal';
import EditCoinTypeModal from '../components/EditCoinTypeModal'; import EditCoinTypeModal from '../components/EditCoinTypeModal';
import { initWeb3, deployContract, transfer } from '@/utils/web3';
import { ContractType } from '@/constants/enum/contract';
const CoinTypeList = () => { const CoinTypeList = () => {
const tableRef = useRef<ActionType>(); const tableRef = useRef<ActionType>();
@ -39,7 +42,7 @@ const CoinTypeList = () => {
}, },
{ {
title: '代币发行总量', title: '代币发行总量',
dataIndex: 'num', dataIndex: 'total',
hideInSearch: true, hideInSearch: true,
ellipsis: true, ellipsis: true,
}, },
@ -64,6 +67,7 @@ const CoinTypeList = () => {
<Table <Table
columns={columns} columns={columns}
rowKey="id" rowKey="id"
search={false}
toolBarActions={[ toolBarActions={[
{ {
type: 'add', type: 'add',
@ -84,6 +88,14 @@ const CoinTypeList = () => {
setIsModalVisible(false); setIsModalVisible(false);
}} }}
onOk={async function (val: any): Promise<void> { onOk={async function (val: any): Promise<void> {
const res = await getContractInfo({ erc: ContractType.ERC20 });
await initWeb3();
const result = await deployContract(res.abi, res.bin, [
val.num,
val.tokenName,
val.tokenSymbol,
]);
val.address = result;
await addCoinType(val); await addCoinType(val);
setIsModalVisible(false); setIsModalVisible(false);
tableRef.current?.reload(); tableRef.current?.reload();

View File

@ -21,9 +21,11 @@ const SchemaField = createSchemaField({
const form = createForm({}); const form = createForm({});
const AddCoinTypeModal = ({ onOk, onCancel, ...rest }: AddCoinTypeModalPropsType) => { const AddCoinTypeModal = ({ onOk, onCancel, ...rest }: AddCoinTypeModalPropsType) => {
const handleOk = () => { const handleOk = async () => {
form.submit(async () => {
const formState = form.getFormState(); const formState = form.getFormState();
onOk(formState.values); onOk(formState.values);
});
}; };
const handleCancel = () => { const handleCancel = () => {
@ -36,21 +38,35 @@ const AddCoinTypeModal = ({ onOk, onCancel, ...rest }: AddCoinTypeModalPropsType
<SchemaField> <SchemaField>
<SchemaField.String <SchemaField.String
name="name" name="name"
title="货币名称"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.Number
name="usdt_price"
title="usdt比例"
required
x-decorator="FormItem"
x-component="NumberPicker"
/>
<SchemaField.Number
name="eth_price"
title="eth比例"
required
x-decorator="FormItem"
x-component="NumberPicker"
/>
<SchemaField.String
name="tokenName"
title="代币名称" title="代币名称"
required required
x-decorator="FormItem" x-decorator="FormItem"
x-component="Input" x-component="Input"
/> />
<SchemaField.String <SchemaField.String
name="usdt_price" name="tokenSymbol"
title="usdt比例" title="代币单位"
required
x-decorator="FormItem"
x-component="Input"
/>
<SchemaField.String
name="eth_price"
title="eth比例"
required required
x-decorator="FormItem" x-decorator="FormItem"
x-component="Input" x-component="Input"

View File

@ -32,8 +32,10 @@ const EditCoinTypeModal = ({
}); });
const handleOk = () => { const handleOk = () => {
form.submit(async () => {
const formState = form.getFormState(); const formState = form.getFormState();
onOk(formState.values); onOk(formState.values);
});
}; };
const handleCancel = () => { const handleCancel = () => {
@ -51,17 +53,17 @@ const EditCoinTypeModal = ({
x-decorator="FormItem" x-decorator="FormItem"
x-component="Input" x-component="Input"
/> />
<SchemaField.String <SchemaField.Number
name="usdt_price" name="usdt_price"
title="usdt比例" title="usdt比例"
x-decorator="FormItem" x-decorator="FormItem"
x-component="Input" x-component="NumberPicker"
/> />
<SchemaField.String <SchemaField.Number
name="eth_price" name="eth_price"
title="eth比例" title="eth比例"
x-decorator="FormItem" x-decorator="FormItem"
x-component="Input" x-component="NumberPicker"
/> />
</SchemaField> </SchemaField>
</Form> </Form>

View File

@ -2,9 +2,8 @@ import React, { useRef } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table'; import Table, { ProColumns, ActionType } from '@/components/Table';
import { getRecordList } from '@/services/recharge/record'; import { getRecordList } from '@/services/recharge/record';
import { fetchTableData } from '@/utils/table'; import { fetchTableData } from '@/utils/table';
import { getBalanceAmount } from '@/utils/formatBalance';
import BigNumber from 'bignumber.js';
import moment from 'moment'; import moment from 'moment';
import { ContractType } from '@/constants/enum/contract';
const RecordList = () => { const RecordList = () => {
const tableRef = useRef<ActionType>(); const tableRef = useRef<ActionType>();
@ -28,12 +27,6 @@ const RecordList = () => {
width: '10%', width: '10%',
hideInSearch: true, hideInSearch: true,
}, },
{
title: '位数',
dataIndex: 'decimals',
width: '10%',
hideInSearch: true,
},
{ {
title: '游戏币类型', title: '游戏币类型',
dataIndex: 'name', dataIndex: 'name',
@ -62,25 +55,20 @@ const RecordList = () => {
return ( return (
<Table <Table
columns={columns} columns={columns}
rowKey="id" rowKey="tx_hash"
actionRef={tableRef} actionRef={tableRef}
request={async (params) => { request={async (params) => {
console.log('params = ', params);
if ((params.time ?? '') !== '') { if ((params.time ?? '') !== '') {
const start = Date.parse(params.time[0] + ' 00:00:00'); const start = Date.parse(params.time[0] + ' 00:00:00');
const end = Date.parse(params.time[1] + ' 23:59:59'); const end = Date.parse(params.time[1] + ' 23:59:59');
params.start_time = start / 1000; params.start_time = start / 1000;
params.end_time = end / 1000; params.end_time = end / 1000;
} }
params.erc = ContractType.ERC20;
const res = await fetchTableData(getRecordList, params); const res = await fetchTableData(getRecordList, params);
console.log('res = ', res);
for (const key in res.data) { for (const key in res.data) {
if (Object.prototype.hasOwnProperty.call(res.data, key)) { if (Object.prototype.hasOwnProperty.call(res.data, key)) {
const element = res.data[key]; const element = res.data[key];
element.price = getBalanceAmount(
new BigNumber(element.price),
element.decimals,
).toNumber();
element.time = moment(element.time * 1000).format('YYYY-MM-DD hh:mm:ss'); element.time = moment(element.time * 1000).format('YYYY-MM-DD hh:mm:ss');
} }
} }

View File

@ -41,7 +41,6 @@ const CollectionAddressList = () => {
title: '收款游戏币名称', title: '收款游戏币名称',
dataIndex: 'name', dataIndex: 'name',
hideInSearch: true, hideInSearch: true,
ellipsis: true,
}, },
{ {
title: '操作', title: '操作',

View File

@ -37,7 +37,7 @@ const form = createForm({
effects: () => { effects: () => {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
useAsyncDataSource('name', async (field) => { useAsyncDataSource('name', async (field) => {
const list = await getCoinTypeList({ page: 1, page_size: 10 }); const list = await getCoinTypeList({ page: 1, size: 10 });
const option = []; const option = [];
for (let index = 0; index < list.items.length; index++) { for (let index = 0; index < list.items.length; index++) {
const element = list.items[index]; const element = list.items[index];
@ -54,8 +54,10 @@ const form = createForm({
const AddWalletModal = ({ onOk, onCancel, ...rest }: AddWalletModalPropsType) => { const AddWalletModal = ({ onOk, onCancel, ...rest }: AddWalletModalPropsType) => {
const handleOk = () => { const handleOk = () => {
form.submit(async () => {
const formState = form.getFormState(); const formState = form.getFormState();
onOk(formState.values); onOk(formState.values);
});
}; };
const handleCancel = () => { const handleCancel = () => {

View File

@ -39,7 +39,7 @@ const EditWalletModal = ({ onOk, onCancel, editModalData, ...rest }: EditWalletM
effects: () => { effects: () => {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
useAsyncDataSource('name', async (field) => { useAsyncDataSource('name', async (field) => {
const list = await getCoinTypeList({ page: 1, page_size: 10 }); const list = await getCoinTypeList({ page: 1, size: 10 });
const option = []; const option = [];
for (let index = 0; index < list.items.length; index++) { for (let index = 0; index < list.items.length; index++) {
const element = list.items[index]; const element = list.items[index];
@ -59,8 +59,10 @@ const EditWalletModal = ({ onOk, onCancel, editModalData, ...rest }: EditWalletM
}); });
const handleOk = () => { const handleOk = () => {
form.submit(async () => {
const formState = form.getFormState(); const formState = form.getFormState();
onOk(formState.values); onOk(formState.values);
});
}; };
const handleCancel = () => { const handleCancel = () => {

View File

@ -2,16 +2,33 @@ import React, { useRef } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table'; import Table, { ProColumns, ActionType } from '@/components/Table';
import { getWithdrawList, solveWithdraw } from '@/services/recharge/withdraw'; import { getWithdrawList, solveWithdraw } from '@/services/recharge/withdraw';
import { fetchTableData } from '@/utils/table'; import { fetchTableData } from '@/utils/table';
import { getBalanceAmount } from '@/utils/formatBalance';
import BigNumber from 'bignumber.js';
import ConfirmButton from '@/components/Table/ConfirmButton'; import ConfirmButton from '@/components/Table/ConfirmButton';
import moment from 'moment'; import moment from 'moment';
import { WithdrawType } from '@/constants/enum/withdraw';
const WithdrawList = () => { const WithdrawList = () => {
const handleConfirm = async (uuid) => { const handleConfirm = async (uuid) => {
await solveWithdraw({ uuid: uuid }); await solveWithdraw({ uuid: uuid });
}; };
const WithdrawTypeList = [
{
label: '成功',
value: WithdrawType.SUCCESS,
status: 'Success',
},
{
label: '失败',
value: WithdrawType.FAILED,
status: 'Error',
},
{
label: '待处理',
value: WithdrawType.PENDDING,
status: 'Warning',
},
];
const tableRef = useRef<ActionType>(); const tableRef = useRef<ActionType>();
const columns: ProColumns<any>[] = [ const columns: ProColumns<any>[] = [
{ {
@ -36,6 +53,18 @@ const WithdrawList = () => {
dataIndex: 'type', dataIndex: 'type',
width: '10%', width: '10%',
}, },
{
title: '状态',
dataIndex: 'status',
width: '10%',
valueEnum: () => {
const options = {};
WithdrawTypeList.forEach((item) => {
options[item.value] = { text: item.label, status: item.status };
});
return options;
},
},
{ {
title: '时间', title: '时间',
dataIndex: 'time', dataIndex: 'time',
@ -69,10 +98,6 @@ const WithdrawList = () => {
for (const key in res.data) { for (const key in res.data) {
if (Object.prototype.hasOwnProperty.call(res.data, key)) { if (Object.prototype.hasOwnProperty.call(res.data, key)) {
const element = res.data[key]; const element = res.data[key];
element.price = getBalanceAmount(
new BigNumber(element.price),
element.decimals,
).toNumber();
element.time = moment(element.time * 1000).format('YYYY-MM-DD hh:mm:ss'); element.time = moment(element.time * 1000).format('YYYY-MM-DD hh:mm:ss');
} }
} }

View File

@ -74,7 +74,8 @@ const AccountManageList = () => {
<div> <div>
<Table <Table
columns={columns} columns={columns}
rowKey="id" rowKey="name"
search={false}
toolBarActions={[ toolBarActions={[
{ {
type: 'add', type: 'add',

View File

@ -1,10 +1,11 @@
// 创建弹窗 // 创建弹窗
import React, { useRef } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { createForm } from '@formily/core'; import { createForm } from '@formily/core';
import { createSchemaField } from '@formily/react'; import { createSchemaField } from '@formily/react';
import Modal, { ModalProps } from '@/components/Modal'; import Modal, { ModalProps } from '@/components/Modal';
import { Form, FormItem, Input, Select } from '@formily/antd'; import { Form, FormItem, Input, TreeSelect } from '@formily/antd';
import { addUser } from '@/services/system/accountManage'; import { addUser } from '@/services/system/accountManage';
import routes from '@/routes';
interface AddAccountModalPropsType extends ModalProps { interface AddAccountModalPropsType extends ModalProps {
onCancel: () => void; onCancel: () => void;
@ -15,13 +16,15 @@ const SchemaField = createSchemaField({
components: { components: {
FormItem, FormItem,
Input, Input,
Select, TreeSelect,
}, },
}); });
const form = createForm({}); const form = createForm({});
const AddAccountModal = ({ onOk, onCancel, ...rest }: AddAccountModalPropsType) => { const AddAccountModal = ({ onOk, onCancel, ...rest }: AddAccountModalPropsType) => {
const [treeData, setTreeData] = useState({});
const handleOk = async () => { const handleOk = async () => {
form.submit(async () => { form.submit(async () => {
onOk(); onOk();
@ -35,6 +38,30 @@ const AddAccountModal = ({ onOk, onCancel, ...rest }: AddAccountModalPropsType)
onCancel(); onCancel();
}; };
const onChange = (newValue: string[]) => {};
useEffect(() => {
const array = routes;
array.forEach((item: any, index) => {
if (item.name == '' || item.name == null || item.name == undefined) {
array.splice(index, 1);
console.log('array.splice(index, 1);');
}
item.key = index + 1;
if (Object.prototype.hasOwnProperty.call(item, 'routes')) {
item.routes?.forEach((item2: any, index2: number) => {
if (item2.name == '' || item2.name == null || item2.name == undefined) {
item.routes.splice(index2, 1);
console.log('item.routes.splice(index2, 1);');
}
item2.key = parseInt(index + 1 + '' + index2);
});
}
});
console.log('array = ', array);
setTreeData(array);
}, []);
return ( return (
<Modal title="添加管理账号" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}> <Modal title="添加管理账号" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}>
<Form form={form} labelCol={4} wrapperCol={18}> <Form form={form} labelCol={4} wrapperCol={18}>
@ -64,15 +91,19 @@ const AddAccountModal = ({ onOk, onCancel, ...rest }: AddAccountModalPropsType)
/> />
<SchemaField.String <SchemaField.String
name="role" name="role"
title="角色" title="权限"
required required
x-validator={{ x-validator={{
required: true, required: true,
}} }}
x-decorator="FormItem" x-decorator="FormItem"
x-component="Input" x-component="TreeSelect"
x-component-props={{ x-component-props={{
placeholder: '请选择角色', fieldNames: { label: 'name', children: 'routes', value: 'name' },
onChange: onChange,
treeCheckable: true,
treeData: treeData,
placeholder: '请选择权限',
}} }}
/> />
</SchemaField> </SchemaField>

View File

@ -28,10 +28,12 @@ const AddUserModal = ({ onOk, onCancel, editModalData, ...rest }: AddUserModalPr
}); });
const handleOk = async () => { const handleOk = async () => {
form.submit(async () => {
onOk(); onOk();
const formState = form.getFormState(); const formState = form.getFormState();
formState.values.role = parseInt(formState.values.role); formState.values.role = parseInt(formState.values.role);
await updateUser(formState.values); await addUser(formState.values);
});
}; };
const handleCancel = () => { const handleCancel = () => {

View File

@ -6,6 +6,7 @@ import DeleteButton from '@/components/Table/DeleteButton';
import { Switch } from 'antd'; import { Switch } from 'antd';
import AddNoticeModal from '../components/AddNoticeModal'; import AddNoticeModal from '../components/AddNoticeModal';
import EditNoticeModal from '../components/EditNoticeModal'; import EditNoticeModal from '../components/EditNoticeModal';
import { NoticeType } from '@/constants/enum/notice';
const NoticeList = () => { const NoticeList = () => {
const tableRef = useRef<ActionType>(); const tableRef = useRef<ActionType>();
@ -25,12 +26,40 @@ const NoticeList = () => {
tableRef.current?.reload(); tableRef.current?.reload();
}; };
const noticeTypeList = [
{
label: '充值',
value: NoticeType.RECHARGE,
},
{
label: '提现',
value: NoticeType.WITHDRAW,
},
{
label: 'NFT创建',
value: NoticeType.NFTCREATE,
},
{
label: 'NFT转移',
value: NoticeType.NFTTRANSFER,
},
{
label: 'NFT销毁',
value: NoticeType.NFTTDISPOSE,
},
];
const columns: ProColumns<any>[] = [ const columns: ProColumns<any>[] = [
{ {
title: '通知码', title: '通知码',
dataIndex: 'code', dataIndex: 'code',
hideInSearch: true, valueEnum: () => {
ellipsis: true, const options = {};
noticeTypeList.forEach((item) => {
options[item.value] = item.label;
});
return options;
},
}, },
{ {
title: '通知地址', title: '通知地址',
@ -74,6 +103,7 @@ const NoticeList = () => {
<Table <Table
columns={columns} columns={columns}
rowKey="id" rowKey="id"
search={false}
toolBarActions={[ toolBarActions={[
{ {
type: 'add', type: 'add',

View File

@ -5,6 +5,31 @@ import { createSchemaField } from '@formily/react';
import Modal, { ModalProps } from '@/components/Modal'; import Modal, { ModalProps } from '@/components/Modal';
import { Form, FormItem, Input, Select } from '@formily/antd'; import { Form, FormItem, Input, Select } from '@formily/antd';
import { NoticeType } from '@/constants/enum/notice';
const noticeTypeList = [
{
label: '充值',
value: NoticeType.RECHARGE,
},
{
label: '提现',
value: NoticeType.WITHDRAW,
},
{
label: 'NFT创建',
value: NoticeType.NFTCREATE,
},
{
label: 'NFT转移',
value: NoticeType.NFTTRANSFER,
},
{
label: 'NFT销毁',
value: NoticeType.NFTTDISPOSE,
},
];
interface AddNoticeModalPropsType extends ModalProps { interface AddNoticeModalPropsType extends ModalProps {
onOk: (val: any) => void; onOk: (val: any) => void;
onCancel: () => void; onCancel: () => void;
@ -22,9 +47,11 @@ const form = createForm({});
const AddNoticeModal = ({ onOk, onCancel, ...rest }: AddNoticeModalPropsType) => { const AddNoticeModal = ({ onOk, onCancel, ...rest }: AddNoticeModalPropsType) => {
const handleOk = () => { const handleOk = () => {
form.submit(async () => {
const formState = form.getFormState(); const formState = form.getFormState();
formState.values.code = parseInt(formState.values.code); formState.values.code = parseInt(formState.values.code);
onOk(formState.values); onOk(formState.values);
});
}; };
const handleCancel = () => { const handleCancel = () => {
@ -35,12 +62,15 @@ const AddNoticeModal = ({ onOk, onCancel, ...rest }: AddNoticeModalPropsType) =>
<Modal title="添加通知" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}> <Modal title="添加通知" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}>
<Form form={form} labelCol={4} wrapperCol={18}> <Form form={form} labelCol={4} wrapperCol={18}>
<SchemaField> <SchemaField>
<SchemaField.String <SchemaField.Number
name="code" name="code"
title="通知码" title="通知码"
required required
x-component-props={{
options: noticeTypeList,
}}
x-decorator="FormItem" x-decorator="FormItem"
x-component="Input" x-component="Select"
/> />
<SchemaField.String <SchemaField.String
name="addr" name="addr"

View File

@ -27,8 +27,10 @@ const EditNoticeModal = ({ onOk, onCancel, editModalData, ...rest }: EditNoticeM
}); });
const handleOk = () => { const handleOk = () => {
form.submit(async () => {
const formState = form.getFormState(); const formState = form.getFormState();
onOk(formState.values); onOk(formState.values);
});
}; };
const handleCancel = () => { const handleCancel = () => {

View File

@ -1,62 +1,54 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import Table, { ProColumns, ActionType } from '@/components/Table'; import Table, { ProColumns, ActionType } from '@/components/Table';
import { fetchTableData } from '@/utils/table'; import routes from '@/routes';
import DeleteButton from '@/components/Table/DeleteButton';
const PermissionsList = () => { const PermissionsList = () => {
const handleEdit = (row: any) => {};
const handleDelete = async (name: any) => {};
const tableRef = useRef<ActionType>(); const tableRef = useRef<ActionType>();
const columns: ProColumns<any>[] = [ const columns: ProColumns<any>[] = [
{ {
title: '收款地址', title: '路由名称',
dataIndex: 'address', dataIndex: 'name',
hideInSearch: true,
ellipsis: true,
},
{
title: '收款游戏币类型',
dataIndex: 'type',
hideInSearch: true,
ellipsis: true,
},
{
title: '操作',
valueType: 'option',
width: 150,
render: (_, row) => [
<a
key="edit"
onClick={() => {
handleEdit(row);
}}
>
</a>,
<DeleteButton
key="delete"
onDelete={() => {
handleDelete(row.name);
}}
/>,
],
}, },
]; ];
const rowSelection = {
onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
},
};
return ( return (
<div> <div>
<Table <Table
columns={columns} columns={columns}
rowKey="id" search={false}
toolBarActions={[ // rowKey="key"
{ // childrenColumnName="routes"
type: 'add', rowSelection={{
onConfirm: () => {}, ...rowSelection,
}, }}
]} // toolBarActions={[
// {
// type: 'add',
// onConfirm: () => {},
// },
// ]}
actionRef={tableRef} actionRef={tableRef}
request={async (params) => { request={async (params) => {
return {}; const array = routes;
array.forEach((item: any, index) => {
if (item.name == '' || item.name == null || item.name == undefined) {
array.splice(index, 1);
}
item.key = index + 1;
if (Object.prototype.hasOwnProperty.call(item, 'routes')) {
item.routes?.forEach((item2: any, index2: number) => {
if (item2.name == '' || item2.name == null || item2.name == undefined) {
item.routes.splice(index2, 1);
}
item2.key = parseInt(index + 1 + '' + index2);
});
}
});
return { data: array };
}} }}
/> />
</div> </div>

View File

@ -7,7 +7,7 @@ const UserManageList = () => {
const tableRef = useRef<ActionType>(); const tableRef = useRef<ActionType>();
const columns: ProColumns<any>[] = [ const columns: ProColumns<any>[] = [
{ {
title: '用户钱包地址', title: '钱包地址',
dataIndex: 'address', dataIndex: 'address',
ellipsis: true, ellipsis: true,
}, },
@ -22,12 +22,6 @@ const UserManageList = () => {
<Table <Table
columns={columns} columns={columns}
rowKey="id" rowKey="id"
toolBarActions={[
{
type: 'add',
onConfirm: () => {},
},
]}
actionRef={tableRef} actionRef={tableRef}
request={async (params) => { request={async (params) => {
const res = await fetchTableData(getUserList, params); const res = await fetchTableData(getUserList, params);

View File

@ -13,6 +13,7 @@ export default [
{ {
name: '充值系统', name: '充值系统',
path: RoutePath.RECHARGE, path: RoutePath.RECHARGE,
access: 'normalRouteFilter',
routes: [ routes: [
{ {
path: RoutePath.RECHARGE, path: RoutePath.RECHARGE,
@ -22,21 +23,25 @@ export default [
{ {
name: '充值订单', name: '充值订单',
path: RoutePath.RECORD.LIST, path: RoutePath.RECORD.LIST,
access: 'normalRouteFilter',
component: './Recharge/Record/List', component: './Recharge/Record/List',
}, },
{ {
name: '收款地址', name: '收款地址',
path: RoutePath.WALLET.LIST, path: RoutePath.WALLET.LIST,
access: 'normalRouteFilter',
component: './Recharge/Wallet/List', component: './Recharge/Wallet/List',
}, },
{ {
name: '代币种类', name: '代币种类',
path: RoutePath.COIN_TYPE.LIST, path: RoutePath.COIN_TYPE.LIST,
access: 'normalRouteFilter',
component: './Recharge/CoinType/List', component: './Recharge/CoinType/List',
}, },
{ {
name: '提现管理', name: '提现管理',
path: RoutePath.WITHDRAW.LIST, path: RoutePath.WITHDRAW.LIST,
access: 'normalRouteFilter',
component: './Recharge/Withdraw/List', component: './Recharge/Withdraw/List',
}, },
], ],
@ -44,6 +49,7 @@ export default [
{ {
name: '用户账号', name: '用户账号',
path: RoutePath.USER, path: RoutePath.USER,
access: 'normalRouteFilter',
routes: [ routes: [
{ {
path: RoutePath.USER, path: RoutePath.USER,
@ -53,6 +59,7 @@ export default [
{ {
name: '用户账号管理', name: '用户账号管理',
path: RoutePath.USER_LIST.LIST, path: RoutePath.USER_LIST.LIST,
access: 'normalRouteFilter',
component: './User/List', component: './User/List',
}, },
], ],
@ -60,6 +67,7 @@ export default [
{ {
name: '系统设置', name: '系统设置',
path: RoutePath.SYSTEM, path: RoutePath.SYSTEM,
access: 'normalRouteFilter',
routes: [ routes: [
{ {
path: RoutePath.SYSTEM, path: RoutePath.SYSTEM,
@ -69,32 +77,38 @@ export default [
{ {
name: '账号管理', name: '账号管理',
path: RoutePath.ACCOUNT.LIST, path: RoutePath.ACCOUNT.LIST,
access: 'normalRouteFilter',
component: './System/Account/List', component: './System/Account/List',
}, },
{ {
name: '角色管理', name: '角色管理',
path: RoutePath.ROLE.LIST, path: RoutePath.ROLE.LIST,
access: 'normalRouteFilter',
component: './System/Role/List', component: './System/Role/List',
}, },
{ {
name: '权限管理', name: '权限管理',
path: RoutePath.PERMISSIONS.LIST, path: RoutePath.PERMISSIONS.LIST,
access: 'normalRouteFilter',
component: './System/Permissions/List', component: './System/Permissions/List',
}, },
{ {
name: '通知管理', name: '通知管理',
path: RoutePath.NOTICE.LIST, path: RoutePath.NOTICE.LIST,
access: 'normalRouteFilter',
component: './System/Notice/List', component: './System/Notice/List',
}, },
{ {
name: '密钥管理', name: '密钥管理',
path: RoutePath.SECRET_KEY, path: RoutePath.SECRET_KEY,
access: 'normalRouteFilter',
component: './System/SecretKey', component: './System/SecretKey',
}, },
], ],
}, },
{ {
name: '数据看板', name: '数据看板',
access: 'normalRouteFilter',
path: RoutePath.DATABOARD, path: RoutePath.DATABOARD,
routes: [ routes: [
{ {
@ -105,21 +119,25 @@ export default [
{ {
name: '核心看板', name: '核心看板',
path: RoutePath.COREDATA.LIST, path: RoutePath.COREDATA.LIST,
access: 'normalRouteFilter',
component: './DataBoard/CoreData/List', component: './DataBoard/CoreData/List',
}, },
{ {
name: '活跃分析', name: '活跃分析',
path: RoutePath.ACTIVEANALYSIS.LIST, path: RoutePath.ACTIVEANALYSIS.LIST,
access: 'normalRouteFilter',
component: './DataBoard/ActiveAnalysis/List', component: './DataBoard/ActiveAnalysis/List',
}, },
{ {
name: '留存分析', name: '留存分析',
path: RoutePath.RETENTIONANALYSIS.LIST, path: RoutePath.RETENTIONANALYSIS.LIST,
access: 'normalRouteFilter',
component: './DataBoard/RetentionAnalysis/List', component: './DataBoard/RetentionAnalysis/List',
}, },
{ {
name: '用户充值分析', name: '用户充值分析',
path: RoutePath.RECHARGEANALYSIS.LIST, path: RoutePath.RECHARGEANALYSIS.LIST,
access: 'normalRouteFilter',
component: './DataBoard/RechargeAnalysis/List', component: './DataBoard/RechargeAnalysis/List',
}, },
], ],
@ -127,6 +145,7 @@ export default [
{ {
name: 'NFT', name: 'NFT',
path: RoutePath.NFT, path: RoutePath.NFT,
access: 'normalRouteFilter',
routes: [ routes: [
{ {
path: RoutePath.NFT, path: RoutePath.NFT,
@ -136,13 +155,21 @@ export default [
{ {
name: 'NFT合约管理', name: 'NFT合约管理',
path: RoutePath.NFTCONTRACT.LIST, path: RoutePath.NFTCONTRACT.LIST,
access: 'normalRouteFilter',
component: './NFT/NftContract/List', component: './NFT/NftContract/List',
}, },
{ {
name: 'NFT管理', name: 'NFT管理',
path: RoutePath.NFTTOKEN.LIST, path: RoutePath.NFTTOKEN.LIST,
access: 'normalRouteFilter',
component: './NFT/NftToken/List', component: './NFT/NftToken/List',
}, },
{
name: 'NFT交易',
path: RoutePath.NFTTRADE.LIST,
access: 'normalRouteFilter',
component: './NFT/NftTrade/List',
},
], ],
}, },
{ {

View File

@ -43,6 +43,9 @@ const RoutePath = {
NFTTOKEN: { NFTTOKEN: {
LIST: `${NFT}/nfttoken`, LIST: `${NFT}/nfttoken`,
}, },
NFTTRADE: {
LIST: `${NFT}/NFT_trade`,
},
DATABOARD: DATABOARD, DATABOARD: DATABOARD,
COREDATA: { COREDATA: {
LIST: `${DATABOARD}/coredata`, LIST: `${DATABOARD}/coredata`,

15
src/services/contract.ts Normal file
View File

@ -0,0 +1,15 @@
import request from '@/utils/request';
/**
*
* @param {object} params
* erc
* @returns {object} data
*/
export const getContractInfo = (data) => {
return request.request({
url: '/contract/get',
method: 'post',
data,
});
};

87
src/services/nft.ts Normal file
View File

@ -0,0 +1,87 @@
import request from '@/utils/request';
/**
* NFT合约列表
* @param {object} params
* @returns {array} data
* name
* type
* usdt_price usdt的比例
* eth_price eth的比例
*/
export const getNFTContractList = () => {
return request.request({
url: '/erc721/get',
method: 'get',
});
};
/**
* NFT合约
* @param {object} data
*
* @returns {array} data
*/
export const createNFTContract = (data) => {
return request.request({
url: '/erc721/create',
method: 'post',
data,
});
};
/**
* token_Id是否存在
* @param {object} params
*
* @returns {array} data
*/
export const checkTokenId = (params) => {
return request.request({
url: '/nft/check',
method: 'get',
params,
});
};
/**
* NFT列表
* @param {object} params
*
* @returns {array} data
*/
export const getNFTList = (params) => {
return request.request({
url: '/nft/get',
method: 'get',
params,
});
};
/**
* mintNFT
* @param {object} data
*
* @returns {array} data
*/
export const mintNFT = (data) => {
return request.request({
url: '/nft/create',
method: 'post',
data,
});
};
/**
* NFT信息
* @param {object} data
*
* @returns {array} data
*/
export const updateNFTInfo = (data) => {
return request.request({
url: '/nft/update',
method: 'post',
data,
});
};

View File

@ -4,7 +4,7 @@ import request from '@/utils/request';
* *
* @param {object} params * @param {object} params
* type * type
* @returns {array} data * @returns {array} dat
* name * name
* type * type
* usdt_price usdt的比例 * usdt_price usdt的比例
@ -12,7 +12,7 @@ import request from '@/utils/request';
*/ */
export const getCoinTypeList = (params) => { export const getCoinTypeList = (params) => {
return request.request({ return request.request({
url: '/token/get', url: '/erc20/get',
method: 'get', method: 'get',
params, params,
}); });
@ -29,7 +29,7 @@ export const getCoinTypeList = (params) => {
*/ */
export const addCoinType = (data) => { export const addCoinType = (data) => {
return request.request({ return request.request({
url: '/token/create', url: '/erc20/create',
method: 'post', method: 'post',
data, data,
}); });
@ -46,7 +46,7 @@ export const addCoinType = (data) => {
*/ */
export const modifyCoinType = (data) => { export const modifyCoinType = (data) => {
return request.request({ return request.request({
url: '/token/update', url: '/erc20/update',
method: 'post', method: 'post',
data, data,
}); });

View File

@ -9,7 +9,7 @@ import request from '@/utils/request';
*/ */
export const getRoleList = (params) => { export const getRoleList = (params) => {
return request.request({ return request.request({
url: '/user/role', url: '/user/role/get',
method: 'get', method: 'get',
params, params,
}); });

View File

@ -5,7 +5,7 @@ export const fetchTableData = async (
formatObj: any = {}, formatObj: any = {},
) => { ) => {
params.page = params.current; params.page = params.current;
params.page_size = params.pageSize; params.size = params.pageSize;
delete params.current; delete params.current;
delete params.pageSize; delete params.pageSize;
const res = (await fetch(params)) || {}; const res = (await fetch(params)) || {};

147
src/utils/web3.ts Normal file
View File

@ -0,0 +1,147 @@
import Web3 from 'web3';
import detectEthereumProvider from '@metamask/detect-provider';
import { message } from 'antd';
import BigNumber from 'bignumber.js';
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;
}
//发布合约
/**
*
* @param abi ABI
* @param bin
*/
export async function deployContract(abi: string, bin: string, params) {
const contract = new web3.eth.Contract(eval('(' + abi + ')'));
const result = await contract
.deploy({
data: '0x' + bin,
arguments: params,
})
.send({ from: web3.eth.defaultAccount + '', gas: 3000000 }, async function (e, contract) {});
return result._address;
}
// 代币转账
/**
*
* @param abi ABI
* @param address
* @param toAddress
*/
export async function transfer(abi: string, address: string, toAddress: string) {
const contract = new web3.eth.Contract(eval('(' + abi + ')'), address);
await contract.methods
.transfer(toAddress, new BigNumber(1 * Math.pow(10, 18)))
.send({ from: web3.eth.defaultAccount }),
function (error, transactionHash) {
if (!error) {
console.log('transactionHash is ' + transactionHash);
} else {
console.log(error);
}
};
}
// NFT创建
/**
*
* @param abi ABI
* @param address
* @param toAddress
*/
export async function NFTMint(params: any) {
if (params.toAddress == '' || params.toAddress == null || params.toAddress == undefined) {
params.toAddress = web3.eth.defaultAccount;
}
const contract = new web3.eth.Contract(eval('(' + params.abi + ')'), params.address);
await contract.methods
.Mint(params.toAddress, params.token_id)
.send({ from: web3.eth.defaultAccount }),
function (error, transactionHash) {
if (!error) {
return transactionHash;
} else {
console.log(error);
}
};
}
// NFT转移
/**
*
* @param abi ABI
* @param address
* @param toAddress
* @param token_id
*/
export async function transferNFT(params: any) {
const contract = new web3.eth.Contract(eval('(' + params.abi + ')'), params.address);
await contract.methods
.safeTransferFrom(web3.eth.defaultAccount, params.toAddress, params.token_id)
.send({ from: web3.eth.defaultAccount }),
function (error, transactionHash) {
if (!error) {
return transactionHash;
} else {
console.log(error);
}
};
}
// NFT销毁
/**
*
* @param abi ABI
* @param address
* @param token_id
*/
export async function burnNFT(params: any) {
const contract = new web3.eth.Contract(eval('(' + params.abi + ')'), params.address);
await contract.methods.Burn(params.token_id).send({ from: web3.eth.defaultAccount }),
function (error, transactionHash) {
if (!error) {
return transactionHash;
} else {
console.log(error);
}
};
}