Compare commits
39 Commits
master
...
user-zzy-d
| Author | SHA1 | Date |
|---|---|---|
|
|
4f4edf580e | |
|
|
c9046ac173 | |
|
|
0df3015576 | |
|
|
dd30202a7f | |
|
|
4cffaf367e | |
|
|
cac5714935 | |
|
|
fd840d4eed | |
|
|
9b8188a288 | |
|
|
514d0db8f3 | |
|
|
9b71639ff9 | |
|
|
447ace2c80 | |
|
|
1423de8769 | |
|
|
149675a7e0 | |
|
|
55b6eb931c | |
|
|
a5040d8541 | |
|
|
1cfda3b5b3 | |
|
|
b1ba349063 | |
|
|
494b7b467a | |
|
|
566bbd8e35 | |
|
|
144152bafc | |
|
|
d8f099d7fd | |
|
|
ca87af0bdc | |
|
|
827d10360c | |
|
|
8a8c69b8ad | |
|
|
f6a6d7ba96 | |
|
|
9ac71cf6e5 | |
|
|
b2e43272d9 | |
|
|
9f74a89073 | |
|
|
d13aab8aa4 | |
|
|
377e21b87a | |
|
|
65c09c20e6 | |
|
|
afcaddcc0f | |
|
|
d2991a5ddd | |
|
|
2d06115a4e | |
|
|
31198544d7 | |
|
|
43c2cdb98b | |
|
|
3d6c3b873c | |
|
|
2294e72882 | |
|
|
53ca93a288 |
13
README.md
13
README.md
|
|
@ -7,7 +7,7 @@ This project is initialized with [Ant Design Pro](https://pro.ant.design). Follo
|
|||
Install `node_modules`:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
yarn install
|
||||
```
|
||||
|
||||
or
|
||||
|
|
@ -55,3 +55,14 @@ npm test
|
|||
## More
|
||||
|
||||
You can view full document on our [official website](https://pro.ant.design). And welcome any feedback in our [github](https://github.com/ant-design/ant-design-pro).
|
||||
|
||||
### 参考文档
|
||||
|
||||
1. [ts 入门](https://ts.xcatliu.com/)
|
||||
1. [react hook 入门](https://www.ruanyifeng.com/blog/2019/09/react-hooks.html)
|
||||
1. [antd4.0](https://ant-design.gitee.io/components/overview-cn/)
|
||||
1. [@ant-design/pro-layout](https://procomponents.ant.design/components/layout)
|
||||
1. [@ant-design/icons](https://ant.design/components/icon-cn/#API)
|
||||
1. [@ant-design/pro-table](https://procomponents.ant.design/components/table)
|
||||
1. [@formily/antd-components](https://formilyjs.org/#/zoi8i0/ZrsYs6hytQ)
|
||||
1. [@formily](https://formilyjs.org)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const Settings: LayoutSettings & {
|
|||
fixedHeader: false,
|
||||
fixSiderbar: true,
|
||||
colorWeak: false,
|
||||
title: 'Pro',
|
||||
title: 'TBG',
|
||||
pwa: false,
|
||||
logo: '/pro_icon.svg',
|
||||
iconfontUrl: '',
|
||||
|
|
|
|||
|
|
@ -9,9 +9,11 @@
|
|||
export default {
|
||||
dev: {
|
||||
// localhost:8000/api/** -> https://preview.pro.ant.design/api/**
|
||||
'/admin/': {
|
||||
'/tbg/api/v1': {
|
||||
// 要代理的地址
|
||||
target: '',
|
||||
target: 'http://81.71.13.173:9080',
|
||||
// target: 'http://192.168.88.238:9999',
|
||||
// target: 'http://127.0.0.1:9999',
|
||||
// 配置了这个可以从 http 代理到 https
|
||||
// 依赖 origin 的功能可能需要这个,比如 cookie
|
||||
changeOrigin: true,
|
||||
|
|
|
|||
11
package.json
11
package.json
|
|
@ -56,14 +56,18 @@
|
|||
"@formily/antd": "^2.0.7",
|
||||
"@formily/core": "^2.0.7",
|
||||
"@formily/react": "^2.0.7",
|
||||
"@metamask/detect-provider": "^1.2.0",
|
||||
"@umijs/route-utils": "^2.0.3",
|
||||
"ahooks": "^2.10.14",
|
||||
"antd": "^4.17.2",
|
||||
"axios": "^0.24.0",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"braft-editor": "^2.3.9",
|
||||
"classnames": "^2.2.6",
|
||||
"echarts": "^5.3.3",
|
||||
"echarts-for-react": "^3.0.2",
|
||||
"lodash": "^4.17.11",
|
||||
"moment": "^2.25.3",
|
||||
"moment": "^2.29.4",
|
||||
"omit.js": "^2.0.2",
|
||||
"rc-menu": "^9.0.13",
|
||||
"rc-util": "^5.14.0",
|
||||
|
|
@ -72,7 +76,10 @@
|
|||
"react-dom": "^17.0.0",
|
||||
"react-helmet-async": "^1.0.4",
|
||||
"umi": "^3.5.0",
|
||||
"umi-serve": "^1.9.10"
|
||||
"umi-serve": "^1.9.10",
|
||||
"web3": "^1.7.5",
|
||||
"@metamask/detect-provider": "^1.2.0"
|
||||
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ant-design/pro-cli": "^2.0.2",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,26 @@
|
|||
/**
|
||||
* @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 {
|
||||
canAdmin: currentUser && currentUser.access === 'admin',
|
||||
normalRouteFilter: (route: any) => {
|
||||
if (routeList == null || routeList == undefined || routeList.length == 0) {
|
||||
return true;
|
||||
}
|
||||
return routeList.includes(route.code);
|
||||
},
|
||||
canShowButton: (buttonCode) => {
|
||||
// return true;
|
||||
if (routeList == null || routeList == undefined || routeList.length == 0) {
|
||||
return true;
|
||||
}
|
||||
return routeList.includes(buttonCode);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
11
src/app.tsx
11
src/app.tsx
|
|
@ -4,8 +4,19 @@ import { history } from 'umi';
|
|||
import RightContent from '@/components/RightContent';
|
||||
import RoutePath from '@/routes/routePath';
|
||||
import { CACHE_TOKEN } from '@/constants/cacheKey';
|
||||
import { getAccounPermission } from './services/system/accountManage';
|
||||
|
||||
// ProLayout 支持的api https://procomponents.ant.design/components/layout
|
||||
|
||||
export async function getInitialState() {
|
||||
if (localStorage.getItem(CACHE_TOKEN)) {
|
||||
const res = await getAccounPermission({});
|
||||
return {
|
||||
routeList: res,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const layout: RunTimeLayoutConfig = ({ initialState }) => {
|
||||
return {
|
||||
rightContentRender: () => <RightContent />,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// 创建弹窗
|
||||
import React, { useRef } from 'react';
|
||||
import { createForm } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, Select } from '@formily/antd';
|
||||
import { modifyPassword } from '@/services/login';
|
||||
|
||||
interface ModifyPasswordModalPropsType extends ModalProps {
|
||||
onCancel: () => void;
|
||||
onOk: () => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
Select,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const ModifyPasswordModal = ({ onOk, onCancel, ...rest }: ModifyPasswordModalPropsType) => {
|
||||
const handleOk = async () => {
|
||||
onOk();
|
||||
const formState = form.getFormState();
|
||||
await modifyPassword(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="password"
|
||||
title="旧密码"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
x-component-props={{
|
||||
placeholder: '请输入旧密码',
|
||||
}}
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="new_password"
|
||||
title="新密码"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
x-component-props={{
|
||||
placeholder: '请输入新密码',
|
||||
}}
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModifyPasswordModal;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { LogoutOutlined, SettingOutlined, UserOutlined, EditOutlined } from '@ant-design/icons';
|
||||
import { Avatar, Menu, Spin } from 'antd';
|
||||
import { history } from 'umi';
|
||||
import { stringify } from 'querystring';
|
||||
|
|
@ -7,7 +7,8 @@ import HeaderDropdown from '../HeaderDropdown';
|
|||
import styles from './index.less';
|
||||
import type { MenuInfo } from 'rc-menu/lib/interface';
|
||||
import RoutePath from '@/routes/routePath';
|
||||
import { CACHE_TOKEN } from '@/constants/cacheKey';
|
||||
import { CACHE_TOKEN, CACHE_USERNAME } from '@/constants/cacheKey';
|
||||
import ModifyPasswordModal from '@/components/ModifyPassword/ModifyPasswordModal';
|
||||
|
||||
export type GlobalHeaderRightProps = {
|
||||
menu?: boolean;
|
||||
|
|
@ -22,6 +23,7 @@ const loginOut = async () => {
|
|||
// Note: There may be security issues, please note
|
||||
if (window.location.pathname !== RoutePath.LOGIN && !redirect) {
|
||||
localStorage.removeItem(CACHE_TOKEN);
|
||||
localStorage.removeItem(CACHE_USERNAME);
|
||||
history.replace({
|
||||
pathname: RoutePath.LOGIN,
|
||||
search: stringify({
|
||||
|
|
@ -32,8 +34,18 @@ const loginOut = async () => {
|
|||
};
|
||||
|
||||
const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
|
||||
const modifyPassword = async () => {
|
||||
setIsModalVisible(true);
|
||||
};
|
||||
|
||||
const onMenuClick = useCallback((event: MenuInfo) => {
|
||||
const { key } = event;
|
||||
if (key === 'modify') {
|
||||
modifyPassword();
|
||||
return;
|
||||
}
|
||||
if (key === 'logout') {
|
||||
loginOut();
|
||||
return;
|
||||
|
|
@ -55,7 +67,7 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
|
|||
|
||||
const currentUser = {
|
||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
|
||||
name: 'admin',
|
||||
name: localStorage.getItem(CACHE_USERNAME),
|
||||
};
|
||||
|
||||
if (!currentUser || !currentUser.name) {
|
||||
|
|
@ -77,7 +89,10 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
|
|||
</Menu.Item>
|
||||
)}
|
||||
{menu && <Menu.Divider />}
|
||||
|
||||
<Menu.Item key="modify">
|
||||
<EditOutlined />
|
||||
修改密码
|
||||
</Menu.Item>
|
||||
<Menu.Item key="logout">
|
||||
<LogoutOutlined />
|
||||
退出登录
|
||||
|
|
@ -85,12 +100,24 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
|
|||
</Menu>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<HeaderDropdown overlay={menuHeaderDropdown}>
|
||||
<span className={`${styles.action} ${styles.account}`}>
|
||||
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
|
||||
<span className={`${styles.name} anticon`}>{currentUser.name}</span>
|
||||
</span>
|
||||
</HeaderDropdown>
|
||||
<ModifyPasswordModal
|
||||
visible={isModalVisible}
|
||||
onCancel={function () {
|
||||
setIsModalVisible(false);
|
||||
}}
|
||||
onOk={function () {
|
||||
console.log('onOk');
|
||||
setIsModalVisible(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
.disabled {
|
||||
color: @disabled-color;
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
color: @disabled-color !important;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
color: @success-color;
|
||||
&:hover {
|
||||
color: @success-color !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import React from 'react';
|
||||
import { Popconfirm } from 'antd';
|
||||
import styles from './index.less';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface PropsType {
|
||||
onConfirm: () => void;
|
||||
title?: string;
|
||||
buttonName?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
const ConfirmButton: React.FC<PropsType> = ({
|
||||
onConfirm,
|
||||
disabled = false,
|
||||
title = '',
|
||||
buttonName = '',
|
||||
}) => {
|
||||
return (
|
||||
<Popconfirm title={title} disabled={disabled} onConfirm={onConfirm} okText="是" cancelText="否">
|
||||
<a className={classNames(styles.confirmBtn, disabled ? styles.disabled : '')}>{buttonName}</a>
|
||||
</Popconfirm>
|
||||
);
|
||||
};
|
||||
export default ConfirmButton;
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
.disabled {
|
||||
color: @disabled-color;
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
color: @disabled-color !important;
|
||||
}
|
||||
}
|
||||
|
||||
.reject-btn {
|
||||
color: @error-color;
|
||||
&:hover {
|
||||
color: @error-color !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import React from 'react';
|
||||
import { Popconfirm } from 'antd';
|
||||
import styles from './index.less';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface PropsType {
|
||||
onConfirm: () => void;
|
||||
title?: string;
|
||||
buttonName?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
const ConfirmButton: React.FC<PropsType> = ({
|
||||
onConfirm,
|
||||
disabled = false,
|
||||
title = '',
|
||||
buttonName = '',
|
||||
}) => {
|
||||
return (
|
||||
<Popconfirm title={title} disabled={disabled} onConfirm={onConfirm} okText="是" cancelText="否">
|
||||
<a className={classNames(styles.rejectBtn, disabled ? styles.disabled : '')}>{buttonName}</a>
|
||||
</Popconfirm>
|
||||
);
|
||||
};
|
||||
export default ConfirmButton;
|
||||
|
|
@ -12,9 +12,11 @@ import {
|
|||
} from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import ProTable, { ProColumns, ActionType, ProTableProps } from '@ant-design/pro-table';
|
||||
import { Access, useAccess } from 'umi';
|
||||
|
||||
export interface toolBarActionsItem {
|
||||
type: 'add' | 'batchDelete';
|
||||
permission?: string;
|
||||
text?: string;
|
||||
onConfirm: (val?: string[]) => void;
|
||||
}
|
||||
|
|
@ -29,6 +31,8 @@ type Record<K extends keyof any, T> = {
|
|||
};
|
||||
|
||||
const Table = <T extends Record<string, any>>(props: PropsType) => {
|
||||
const access = useAccess();
|
||||
|
||||
const {
|
||||
columns: columnsProps = [],
|
||||
search: searchProps = {},
|
||||
|
|
@ -88,7 +92,9 @@ const Table = <T extends Record<string, any>>(props: PropsType) => {
|
|||
const optionRender = (_: any, val: any, ...rest: any) => {
|
||||
return (
|
||||
<Space size={0} split={<Divider type="vertical" />}>
|
||||
{(item.render && (item.render(_, val, ...rest) as []))?.map((item2) => item2)}
|
||||
{(item.render && (item.render(_, val, ...rest) as []))?.map((item2) => {
|
||||
return item2;
|
||||
})}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
|
@ -142,6 +148,7 @@ const Table = <T extends Record<string, any>>(props: PropsType) => {
|
|||
],
|
||||
};
|
||||
}, [searchProps, columnsProps]);
|
||||
|
||||
const handleBatchDelete = (action: any) => {
|
||||
if (selectedRows.length === 0) {
|
||||
message.warn('请选择要操作的项');
|
||||
|
|
@ -164,6 +171,7 @@ const Table = <T extends Record<string, any>>(props: PropsType) => {
|
|||
toolBarActions.forEach((item) => {
|
||||
if (item.type === 'add') {
|
||||
buttonList.push(
|
||||
<Access accessible={access.canShowButton(item.permission)}>
|
||||
<Button
|
||||
key="add"
|
||||
type="primary"
|
||||
|
|
@ -172,11 +180,13 @@ const Table = <T extends Record<string, any>>(props: PropsType) => {
|
|||
}}
|
||||
>
|
||||
<PlusOutlined />
|
||||
{item.text || '新建'}
|
||||
</Button>,
|
||||
{item.text || '添加'}
|
||||
</Button>
|
||||
</Access>,
|
||||
);
|
||||
} else if (item.type === 'batchDelete') {
|
||||
buttonList.push(
|
||||
<Access accessible={access.canShowButton(item.permission)}>
|
||||
<Button
|
||||
key="del"
|
||||
danger
|
||||
|
|
@ -185,7 +195,8 @@ const Table = <T extends Record<string, any>>(props: PropsType) => {
|
|||
}}
|
||||
>
|
||||
{item.text || '批量删除'}
|
||||
</Button>,
|
||||
</Button>
|
||||
</Access>,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,449 @@
|
|||
export default [
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'address',
|
||||
name: 'owner',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'address',
|
||||
name: 'approved',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'Approval',
|
||||
type: 'event',
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'address',
|
||||
name: 'owner',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'address',
|
||||
name: 'operator',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: 'bool',
|
||||
name: 'approved',
|
||||
type: 'bool',
|
||||
},
|
||||
],
|
||||
name: 'ApprovalForAll',
|
||||
type: 'event',
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'address',
|
||||
name: 'previousOwner',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'address',
|
||||
name: 'newOwner',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
name: 'OwnershipTransferred',
|
||||
type: 'event',
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'address',
|
||||
name: 'from',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'address',
|
||||
name: 'to',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'Transfer',
|
||||
type: 'event',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'to',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'approve',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'Burn',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'to',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'GTransfer',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'to',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'bytes',
|
||||
name: 'signature',
|
||||
type: 'bytes',
|
||||
},
|
||||
],
|
||||
name: 'Mint',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: 'renounceOwnership',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'from',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'to',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'safeTransferFrom',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'from',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'to',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
{
|
||||
internalType: 'bytes',
|
||||
name: 'data',
|
||||
type: 'bytes',
|
||||
},
|
||||
],
|
||||
name: 'safeTransferFrom',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'operator',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'bool',
|
||||
name: 'approved',
|
||||
type: 'bool',
|
||||
},
|
||||
],
|
||||
name: 'setApprovalForAll',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'from',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'to',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'transferFrom',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'newOwner',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
name: 'transferOwnership',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'string',
|
||||
name: 'tokenName',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
internalType: 'string',
|
||||
name: 'tokenSymbol',
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'constructor',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'owner',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
name: 'balanceOf',
|
||||
outputs: [
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: '',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'getApproved',
|
||||
outputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: '',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'owner',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
internalType: 'address',
|
||||
name: 'operator',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
name: 'isApprovedForAll',
|
||||
outputs: [
|
||||
{
|
||||
internalType: 'bool',
|
||||
name: '',
|
||||
type: 'bool',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: 'name',
|
||||
outputs: [
|
||||
{
|
||||
internalType: 'string',
|
||||
name: '',
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: 'owner',
|
||||
outputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: '',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'ownerOf',
|
||||
outputs: [
|
||||
{
|
||||
internalType: 'address',
|
||||
name: '',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'bytes4',
|
||||
name: 'interfaceId',
|
||||
type: 'bytes4',
|
||||
},
|
||||
],
|
||||
name: 'supportsInterface',
|
||||
outputs: [
|
||||
{
|
||||
internalType: 'bool',
|
||||
name: '',
|
||||
type: 'bool',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: 'symbol',
|
||||
outputs: [
|
||||
{
|
||||
internalType: 'string',
|
||||
name: '',
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: 'uint256',
|
||||
name: 'tokenId',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
name: 'tokenURI',
|
||||
outputs: [
|
||||
{
|
||||
internalType: 'string',
|
||||
name: '',
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
];
|
||||
|
|
@ -1 +1,2 @@
|
|||
export const CACHE_TOKEN = 'token';
|
||||
export const CACHE_USERNAME = 'name';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
export enum ContractType {
|
||||
ERC20 = '20',
|
||||
NFT721 = '721',
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
export enum NoticeType {
|
||||
RECHARGE = 10000,
|
||||
WITHDRAW = 20000,
|
||||
NFTCREATE = 30000,
|
||||
NFTTRANSFER = 30010,
|
||||
NFTTDISPOSE = 30020,
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
export enum TimeType {
|
||||
DAY = '1',
|
||||
WEEK = '2',
|
||||
MONTH = '3',
|
||||
}
|
||||
export default TimeType;
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export enum WithdrawType {
|
||||
SUCCESS = 10000,
|
||||
FAILED = 20000,
|
||||
PENDDING = 30000,
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
import React, { useRef, useState } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import moment from 'moment';
|
||||
import TimeType from '@/constants/enum/timeType';
|
||||
import MoreData from '@/widget/MoreData';
|
||||
import { getCoreData, getListData } from '@/services/dataBorad/coreData';
|
||||
import { Card, Col, Row, Select } from 'antd';
|
||||
import { fetchTableData } from '@/utils/table';
|
||||
const CoreData: React.FC = () => {
|
||||
const tableRef = useRef<ActionType>();
|
||||
|
||||
const TimeTypeList = [
|
||||
{
|
||||
label: '每日',
|
||||
value: TimeType.DAY,
|
||||
},
|
||||
{
|
||||
label: '每周',
|
||||
value: TimeType.WEEK,
|
||||
},
|
||||
{
|
||||
label: '每月',
|
||||
value: TimeType.MONTH,
|
||||
},
|
||||
];
|
||||
|
||||
const [coreData, setCoreData] = useState({
|
||||
today_active_user: '',
|
||||
today_new_user: '',
|
||||
month_recharge: '',
|
||||
recharge_sum: '',
|
||||
});
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '时间类型',
|
||||
dataIndex: 'code',
|
||||
hideInTable: true,
|
||||
initialValue: TimeType.DAY,
|
||||
valueEnum: () => {
|
||||
const options = {};
|
||||
TimeTypeList.forEach((item) => {
|
||||
options[item.value] = { text: item.label };
|
||||
});
|
||||
return options;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '日期',
|
||||
dataIndex: 'start_time',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
dataIndex: 'select_time',
|
||||
valueType: 'dateRange',
|
||||
hideInTable: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '活跃用户数',
|
||||
dataIndex: 'active_user',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '当日充值总额',
|
||||
dataIndex: 'today_recharge',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '付费用户数',
|
||||
dataIndex: 'pay_user',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '付费率',
|
||||
dataIndex: 'pay_ratio',
|
||||
hideInSearch: true,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={24} style={{ marginBottom: 10 }}>
|
||||
<Col span={6}>
|
||||
<Card style={{ height: '120px' }}>
|
||||
{MoreData(null, '今日活跃用户数', coreData.today_active_user + '人')}
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Card style={{ height: '120px' }}>
|
||||
{MoreData(null, '今日新增人数', coreData.today_new_user + '人')}
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Card style={{ height: '120px' }}>
|
||||
{MoreData(null, '本月充值总额', coreData.month_recharge + '万元')}
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Card style={{ height: '120px' }}>
|
||||
{MoreData(null, '充值总额', coreData.recharge_sum + '万元')}
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
params.code = parseInt(params.code);
|
||||
if ((params.select_time ?? '') !== '') {
|
||||
params.start_time = moment(params.select_time[0]).valueOf() / 1000;
|
||||
params.end_time = moment(params.select_time[1]).valueOf() / 1000;
|
||||
}
|
||||
const data = await getCoreData({});
|
||||
setCoreData(data as any);
|
||||
const res = await fetchTableData(getListData, params);
|
||||
console.log('res', res);
|
||||
for (const key in res.data) {
|
||||
if (Object.prototype.hasOwnProperty.call(res.data, key)) {
|
||||
const element = res.data[key];
|
||||
if (
|
||||
element.start_time != '' &&
|
||||
element.start_time != undefined &&
|
||||
element.start_time != null
|
||||
) {
|
||||
element.start_time = moment(element.start_time * 1000).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CoreData;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -53,3 +53,7 @@
|
|||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-style {
|
||||
padding: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,20 +5,24 @@ import { useIntl, history, FormattedMessage, useModel } from 'umi';
|
|||
import { login } from '@/services/login';
|
||||
import defaultSettings from '../../../config/defaultSettings';
|
||||
import styles from './index.less';
|
||||
import { CACHE_TOKEN } from '@/constants/cacheKey';
|
||||
import { CACHE_TOKEN, CACHE_USERNAME } from '@/constants/cacheKey';
|
||||
import access from '@/access';
|
||||
|
||||
const Login: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
const { initialState, refresh } = useModel('@@initialState');
|
||||
const handleSubmit = async (values: API.LoginParams) => {
|
||||
// 登录
|
||||
const res: any = await login({ ...values });
|
||||
localStorage.setItem(CACHE_TOKEN, res.token);
|
||||
localStorage.setItem(CACHE_USERNAME, values.name);
|
||||
/** 此方法会跳转到 redirect 参数所在的位置 */
|
||||
if (!history) return;
|
||||
const { query } = history.location;
|
||||
const { redirect } = query as { redirect: string };
|
||||
history.push(redirect || '/');
|
||||
refresh();
|
||||
access(initialState);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -35,7 +39,7 @@ const Login: React.FC = () => {
|
|||
}}
|
||||
>
|
||||
<ProFormText
|
||||
name="username"
|
||||
name="name"
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <UserOutlined className={styles.prefixIcon} />,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
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 = () => {
|
||||
form.submit(async () => {
|
||||
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="token_name"
|
||||
title="合约名称"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="token_symbol"
|
||||
title="合约单位"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="description"
|
||||
title="描述"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddNftContractModal;
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import React, { useRef, useState } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import { message } from 'antd';
|
||||
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 tableRef = useRef<ActionType>();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [contractData, setContractData] = useState({});
|
||||
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '合约名称',
|
||||
dataIndex: 'token_name',
|
||||
width: '15%',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '合约单位',
|
||||
dataIndex: 'token_symbol',
|
||||
width: '15%',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '合约地址',
|
||||
dataIndex: 'address',
|
||||
hideInSearch: true,
|
||||
width: '50%',
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
search={false}
|
||||
actionRef={tableRef}
|
||||
toolBarActions={[
|
||||
{
|
||||
type: 'add',
|
||||
text: '新建NFT合约',
|
||||
permission: 'nft_contract_create',
|
||||
onConfirm: async () => {
|
||||
const res = await getContractInfo({ erc: ContractType.NFT721 });
|
||||
if ((res as any).bin != '') {
|
||||
setContractData(res);
|
||||
setVisible(true);
|
||||
} else {
|
||||
message.success('已有NFT合约');
|
||||
}
|
||||
},
|
||||
},
|
||||
]}
|
||||
request={async (params) => {
|
||||
const res = await fetchTableData(getNFTContractList, params);
|
||||
if (res.data == null) {
|
||||
return [];
|
||||
}
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
<AddNftContractModal
|
||||
visible={visible}
|
||||
onCancel={function () {
|
||||
setVisible(false);
|
||||
}}
|
||||
onOk={async function (val: any): Promise<void> {
|
||||
try {
|
||||
await initWeb3();
|
||||
const res = await deployContract((contractData as any).abi, (contractData as any).bin, [
|
||||
val.token_name,
|
||||
val.token_symbol,
|
||||
]);
|
||||
val.address = res;
|
||||
await createNFTContract(val);
|
||||
message.success('添加成功');
|
||||
setVisible(false);
|
||||
} catch (e) {
|
||||
message.success('发生错误');
|
||||
setVisible(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Address;
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
import React, { useRef, useState } from 'react';
|
||||
import { createForm } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, NumberPicker } from '@formily/antd';
|
||||
import { Button, message } from 'antd';
|
||||
import { initWeb3, NFTMint, web3 } from '@/utils/web3';
|
||||
import { getContractInfo } from '@/services/contract';
|
||||
import { checkAssetID, getNFTContractList, getSignature, mintNFT } from '@/services/nft';
|
||||
import { ContractType } from '@/constants/enum/contract';
|
||||
|
||||
interface AddNftModalPropsType extends ModalProps {
|
||||
onOk: () => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
NumberPicker,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const AddNftModal = ({ onOk, onCancel, ...rest }: AddNftModalPropsType) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleOk = async () => {
|
||||
form.submit(async () => {
|
||||
const formState = form.getFormState();
|
||||
await checkAssetID({ assetid: formState.values.assetid });
|
||||
setLoading(true);
|
||||
const isInit = await initWeb3();
|
||||
if (isInit) {
|
||||
const contractInfo = (await getContractInfo({ erc: ContractType.NFT721 })) as any;
|
||||
const res = (await getNFTContractList()) as any;
|
||||
const signature = (await getSignature({
|
||||
address: web3.eth.defaultAccount,
|
||||
assetid: formState.values.assetid,
|
||||
})) as any;
|
||||
console.log('signature = ', signature);
|
||||
let tx_hash = '';
|
||||
try {
|
||||
tx_hash = await NFTMint({
|
||||
abi: contractInfo.abi,
|
||||
address: res.items[0].address,
|
||||
toAddress: formState.values.address,
|
||||
sign: signature,
|
||||
});
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
message.error('创建失败');
|
||||
onCancel();
|
||||
return;
|
||||
}
|
||||
formState.values.tx_hash = tx_hash;
|
||||
await mintNFT(formState.values);
|
||||
setLoading(false);
|
||||
onOk();
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
onCancel();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="添加NFT"
|
||||
width={800}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={handleCancel}>
|
||||
取消
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" loading={loading} onClick={handleOk}>
|
||||
确认
|
||||
</Button>,
|
||||
]}
|
||||
onCancel={handleCancel}
|
||||
{...rest}
|
||||
>
|
||||
<Form form={form} labelCol={4} wrapperCol={18}>
|
||||
<SchemaField>
|
||||
<SchemaField.String
|
||||
name="address"
|
||||
title="所有者地址"
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="assetid"
|
||||
title="assetID"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddNftModal;
|
||||
|
|
@ -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;
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
import React, { useRef, useState } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import { fetchTableData } from '@/utils/table';
|
||||
import AddNftModal from './components/AddNftModel';
|
||||
import { getNFTList } from '@/services/nft';
|
||||
|
||||
const Address: React.FC = () => {
|
||||
const tableRef = useRef<ActionType>();
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '所有者地址',
|
||||
dataIndex: 'address',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: 'NFT名称',
|
||||
dataIndex: 'name',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '图片',
|
||||
dataIndex: 'image',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '缩略图',
|
||||
dataIndex: 'avatar',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
hideInSearch: true,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="tx_hash"
|
||||
search={false}
|
||||
actionRef={tableRef}
|
||||
toolBarActions={[
|
||||
{
|
||||
type: 'add',
|
||||
text: '添加NFT',
|
||||
permission: 'nft_add',
|
||||
onConfirm: () => {
|
||||
setVisible(true);
|
||||
},
|
||||
},
|
||||
]}
|
||||
request={async (params) => {
|
||||
const res = await fetchTableData(getNFTList, params);
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
<AddNftModal
|
||||
visible={visible}
|
||||
onCancel={function () {
|
||||
setVisible(false);
|
||||
}}
|
||||
onOk={async function (): Promise<void> {
|
||||
tableRef.current?.reload();
|
||||
setVisible(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Address;
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
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) => {
|
||||
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;
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
import React, { useState, useRef } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import { addCoinType, getCoinTypeList, modifyCoinType } from '@/services/recharge/coinType';
|
||||
import { getContractInfo } from '@/services/contract';
|
||||
import { fetchTableData } from '@/utils/table';
|
||||
import AddCoinTypeModal from '../components/AddCoinTypeModal';
|
||||
import EditCoinTypeModal from '../components/EditCoinTypeModal';
|
||||
import { initWeb3, deployContract, transfer } from '@/utils/web3';
|
||||
import { ContractType } from '@/constants/enum/contract';
|
||||
import { Access, useAccess } from 'umi';
|
||||
import { message } from 'antd';
|
||||
|
||||
const CoinTypeList = () => {
|
||||
const access = useAccess();
|
||||
const tableRef = useRef<ActionType>();
|
||||
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [isEditModalVisible, setIsEditModalVisible] = useState(false);
|
||||
const [modalData, setModalData] = useState({});
|
||||
|
||||
const handleEdit = (row: any) => {
|
||||
setModalData(row);
|
||||
setIsEditModalVisible(true);
|
||||
tableRef.current?.reload();
|
||||
};
|
||||
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '游戏币名称',
|
||||
dataIndex: 'name',
|
||||
hideInSearch: true,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: 'usdt比例',
|
||||
dataIndex: 'usdt_price',
|
||||
hideInSearch: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'eth比例',
|
||||
dataIndex: 'eth_price',
|
||||
hideInSearch: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '合约地址',
|
||||
dataIndex: 'address',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '代币发行总量',
|
||||
dataIndex: 'total',
|
||||
hideInSearch: true,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 150,
|
||||
render: (_, row) => [
|
||||
<Access accessible={access.canShowButton('coin_type_edit')}>
|
||||
<a
|
||||
key="edit"
|
||||
onClick={() => {
|
||||
handleEdit(row);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</a>
|
||||
</Access>,
|
||||
],
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="uuid"
|
||||
search={false}
|
||||
toolBarActions={[
|
||||
{
|
||||
type: 'add',
|
||||
permission: 'coin_type_add',
|
||||
onConfirm: () => {
|
||||
setIsModalVisible(true);
|
||||
},
|
||||
},
|
||||
]}
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
const res = await fetchTableData(getCoinTypeList, params);
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
<AddCoinTypeModal
|
||||
visible={isModalVisible}
|
||||
onCancel={function () {
|
||||
setIsModalVisible(false);
|
||||
}}
|
||||
onOk={async function (val: any): Promise<void> {
|
||||
const res = await getContractInfo({ erc: ContractType.ERC20 });
|
||||
await initWeb3();
|
||||
const result = await deployContract((res as any).abi, (res as any).bin, [
|
||||
val.num,
|
||||
val.tokenName,
|
||||
val.tokenSymbol,
|
||||
]);
|
||||
val.address = result;
|
||||
await addCoinType(val);
|
||||
message.success('代币添加成功');
|
||||
setIsModalVisible(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
<EditCoinTypeModal
|
||||
visible={isEditModalVisible}
|
||||
editModalData={modalData}
|
||||
onCancel={function () {
|
||||
setIsEditModalVisible(false);
|
||||
}}
|
||||
onOk={async function (val: any): Promise<void> {
|
||||
await modifyCoinType(val);
|
||||
message.success('代币修改成功');
|
||||
setIsEditModalVisible(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CoinTypeList;
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// 添加代币类型弹窗
|
||||
import React, { useRef } from 'react';
|
||||
import { createForm } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, NumberPicker } from '@formily/antd';
|
||||
|
||||
interface AddCoinTypeModalPropsType extends ModalProps {
|
||||
onOk: (val: any) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
NumberPicker,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const AddCoinTypeModal = ({ onOk, onCancel, ...rest }: AddCoinTypeModalPropsType) => {
|
||||
const handleOk = async () => {
|
||||
form.submit(async () => {
|
||||
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="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="代币名称"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="tokenSymbol"
|
||||
title="代币单位"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.Number
|
||||
name="num"
|
||||
title="数量"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="NumberPicker"
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddCoinTypeModal;
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// 修改弹窗
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import { createForm } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, NumberPicker } from '@formily/antd';
|
||||
|
||||
interface EditCoinTypeModalPropsType extends ModalProps {
|
||||
editModalData: any;
|
||||
onOk: (val: any) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
NumberPicker,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const EditCoinTypeModal = ({
|
||||
onOk,
|
||||
onCancel,
|
||||
editModalData,
|
||||
...rest
|
||||
}: EditCoinTypeModalPropsType) => {
|
||||
useEffect(() => {
|
||||
form.setInitialValues(editModalData);
|
||||
});
|
||||
|
||||
const handleOk = () => {
|
||||
form.submit(async () => {
|
||||
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="name"
|
||||
title="游戏币名称"
|
||||
x-disabled
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.Number
|
||||
name="usdt_price"
|
||||
title="usdt比例"
|
||||
x-decorator="FormItem"
|
||||
x-component="NumberPicker"
|
||||
/>
|
||||
<SchemaField.Number
|
||||
name="eth_price"
|
||||
title="eth比例"
|
||||
x-decorator="FormItem"
|
||||
x-component="NumberPicker"
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditCoinTypeModal;
|
||||
|
|
@ -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 RecordList = () => {
|
||||
const tableRef = useRef<ActionType>();
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '时间',
|
||||
dataIndex: 'searchTime',
|
||||
hideInTable: true,
|
||||
valueType: 'dateRange',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '交易哈希',
|
||||
dataIndex: 'tx_hash',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
dataIndex: 'price',
|
||||
width: '10%',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '游戏币类型',
|
||||
dataIndex: 'name',
|
||||
width: '10%',
|
||||
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="tx_hash"
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
if ((params.searchTime ?? '') !== '') {
|
||||
const start = Date.parse(params.searchTime[0] + ' 00:00:00');
|
||||
const end = Date.parse(params.searchTime[1] + ' 23:59:59');
|
||||
params.start_time = start / 1000;
|
||||
params.end_time = end / 1000;
|
||||
}
|
||||
params.erc = ContractType.ERC20;
|
||||
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 RecordList;
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
import React, { useState, useRef } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import {
|
||||
getAddressList,
|
||||
deleteAddress,
|
||||
createAddress,
|
||||
modifyAddress,
|
||||
} from '@/services/recharge/wallet';
|
||||
|
||||
import { fetchTableData } from '@/utils/table';
|
||||
import DeleteButton from '@/components/Table/DeleteButton';
|
||||
import AddWalletModal from '../components/AddWalletModal';
|
||||
import EditWalletModal from '../components/EditWalletModal';
|
||||
import { Access, useAccess } from 'umi';
|
||||
import { message } from 'antd';
|
||||
|
||||
const CollectionAddressList = () => {
|
||||
const tableRef = useRef<ActionType>();
|
||||
const access = useAccess();
|
||||
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [isEditModalVisible, setIsEditModalVisible] = useState(false);
|
||||
const [modalData, setModalData] = useState({});
|
||||
|
||||
const handleEdit = (row: any) => {
|
||||
row.new_address = '';
|
||||
setModalData(row);
|
||||
setIsEditModalVisible(true);
|
||||
};
|
||||
|
||||
const handleDelete = async (address: any) => {
|
||||
await deleteAddress({ address: address });
|
||||
tableRef.current?.reload();
|
||||
};
|
||||
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '收款地址',
|
||||
dataIndex: 'address',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '收款游戏币名称',
|
||||
dataIndex: 'name',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 150,
|
||||
render: (_, row) => [
|
||||
<Access accessible={access.canShowButton('wallet_edit')}>
|
||||
<a
|
||||
key="edit"
|
||||
onClick={() => {
|
||||
handleEdit(row);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</a>
|
||||
</Access>,
|
||||
<Access accessible={access.canShowButton('wallet_delete')}>
|
||||
<DeleteButton
|
||||
key="delete"
|
||||
onDelete={() => {
|
||||
handleDelete(row.address);
|
||||
}}
|
||||
/>
|
||||
</Access>,
|
||||
],
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
search={false}
|
||||
rowKey="address"
|
||||
toolBarActions={[
|
||||
{
|
||||
type: 'add',
|
||||
permission: 'wallet_add',
|
||||
onConfirm: () => {
|
||||
setIsModalVisible(true);
|
||||
},
|
||||
},
|
||||
]}
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
const res = await fetchTableData(getAddressList, params);
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
<AddWalletModal
|
||||
visible={isModalVisible}
|
||||
onCancel={function () {
|
||||
setIsModalVisible(false);
|
||||
}}
|
||||
onOk={async function (val: any): Promise<void> {
|
||||
await createAddress(val);
|
||||
setIsModalVisible(false);
|
||||
message.success('收款地址添加成功');
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
<EditWalletModal
|
||||
visible={isEditModalVisible}
|
||||
editModalData={modalData}
|
||||
onCancel={function () {
|
||||
setIsEditModalVisible(false);
|
||||
}}
|
||||
onOk={async function (val: any): Promise<void> {
|
||||
await modifyAddress(val);
|
||||
message.success('收款地址修改成功');
|
||||
setIsEditModalVisible(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CollectionAddressList;
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// 创建弹窗
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { createForm, onFieldReact, FormPathPattern, Field } from '@formily/core';
|
||||
import { FormProvider, createSchemaField } from '@formily/react';
|
||||
import { getCoinTypeList } from '@/services/recharge/coinType';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, Select } from '@formily/antd';
|
||||
import { action } from '@formily/reactive';
|
||||
|
||||
interface AddWalletModalPropsType extends ModalProps {
|
||||
onOk: (val: any) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
Select,
|
||||
},
|
||||
});
|
||||
|
||||
const AddWalletModal = ({ onOk, onCancel, ...rest }: AddWalletModalPropsType) => {
|
||||
const [coinTypeData, setCoinTypeData] = useState({});
|
||||
const getSelectData = async () => {
|
||||
const list = await getCoinTypeList({ page: 1, size: 10 });
|
||||
setCoinTypeData(list);
|
||||
};
|
||||
|
||||
const UseAsyncDataSource = (
|
||||
pattern: FormPathPattern,
|
||||
service: (field: Field) => Promise<{ label: string; value: any }[]>,
|
||||
) => {
|
||||
onFieldReact(pattern, (field) => {
|
||||
service(field).then(
|
||||
action.bound((data) => {
|
||||
field.dataSource = data;
|
||||
}),
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const form = createForm({
|
||||
effects: () => {
|
||||
UseAsyncDataSource('name', async (field) => {
|
||||
const list = coinTypeData;
|
||||
const option = [];
|
||||
for (let index = 0; index < list.items.length; index++) {
|
||||
const element = list.items[index];
|
||||
const item = {
|
||||
label: element.name,
|
||||
value: element.name,
|
||||
};
|
||||
option.push(item);
|
||||
}
|
||||
return option;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
getSelectData();
|
||||
}, []);
|
||||
|
||||
const handleOk = () => {
|
||||
form.submit(async () => {
|
||||
const formState = form.getFormState();
|
||||
onOk(formState.values);
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
onCancel();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal title="创建收款地址" onOk={handleOk} onCancel={handleCancel} width={800} {...rest}>
|
||||
<FormProvider form={form}>
|
||||
<SchemaField>
|
||||
<SchemaField.String
|
||||
name="name"
|
||||
title="游戏币名称"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Select"
|
||||
x-component-props={{
|
||||
placeholder: '',
|
||||
}}
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="address"
|
||||
title="收款地址"
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
x-component-props={{
|
||||
placeholder: '不传则后台生成',
|
||||
}}
|
||||
/>
|
||||
</SchemaField>
|
||||
</FormProvider>
|
||||
{/* <Form form={form} labelCol={4} wrapperCol={18}> */}
|
||||
|
||||
{/* </Form> */}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddWalletModal;
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// 修改弹窗
|
||||
import React, { useRef, useEffect, useState } from 'react';
|
||||
import { createForm, onFieldReact, FormPathPattern, Field } from '@formily/core';
|
||||
import { getCoinTypeList } from '@/services/recharge/coinType';
|
||||
import { FormProvider, createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, Select } from '@formily/antd';
|
||||
import { action } from '@formily/reactive';
|
||||
|
||||
interface EditWalletModalPropsType extends ModalProps {
|
||||
editModalData: any;
|
||||
onOk: (val: any) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
Select,
|
||||
},
|
||||
});
|
||||
|
||||
const EditWalletModal = ({ onOk, onCancel, editModalData, ...rest }: EditWalletModalPropsType) => {
|
||||
const UseAsyncDataSource = (
|
||||
pattern: FormPathPattern,
|
||||
service: (field: Field) => Promise<{ label: string; value: any }[]>,
|
||||
) => {
|
||||
onFieldReact(pattern, (field) => {
|
||||
service(field).then(
|
||||
action.bound((data) => {
|
||||
field.dataSource = data;
|
||||
}),
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const form = createForm({
|
||||
effects: () => {
|
||||
UseAsyncDataSource('name', async (field) => {
|
||||
const list = await getCoinTypeList({ page: 1, size: 10 });
|
||||
const option = [];
|
||||
for (let index = 0; index < list.items.length; index++) {
|
||||
const element = list.items[index];
|
||||
const item = {
|
||||
label: element.name,
|
||||
value: element.name,
|
||||
};
|
||||
option.push(item);
|
||||
}
|
||||
return option;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
form.setInitialValues(editModalData);
|
||||
});
|
||||
|
||||
const handleOk = () => {
|
||||
form.submit(async () => {
|
||||
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="address"
|
||||
title="旧收款地址"
|
||||
x-disabled
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="name"
|
||||
title="游戏币名称"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Select"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="new_address"
|
||||
title="新收款地址"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditWalletModal;
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
import React, { useRef } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import { getWithdrawList, solveWithdraw } from '@/services/recharge/withdraw';
|
||||
import { fetchTableData } from '@/utils/table';
|
||||
import ConfirmButton from '@/components/Table/ConfirmButton';
|
||||
import moment from 'moment';
|
||||
import { WithdrawType } from '@/constants/enum/withdraw';
|
||||
import RejectButton from '@/components/Table/RejectButton';
|
||||
import { Access, useAccess } from 'umi';
|
||||
|
||||
const WithdrawList = () => {
|
||||
const tableRef = useRef<ActionType>();
|
||||
const access = useAccess();
|
||||
|
||||
const handleClick = async (uuid, status) => {
|
||||
await solveWithdraw({ uuid: uuid, status: status });
|
||||
tableRef.current?.reload();
|
||||
};
|
||||
|
||||
const WithdrawTypeList = [
|
||||
{
|
||||
label: '成功',
|
||||
value: WithdrawType.SUCCESS,
|
||||
status: 'Success',
|
||||
},
|
||||
{
|
||||
label: '失败',
|
||||
value: WithdrawType.FAILED,
|
||||
status: 'Error',
|
||||
},
|
||||
{
|
||||
label: '待处理',
|
||||
value: WithdrawType.PENDDING,
|
||||
status: 'Warning',
|
||||
},
|
||||
];
|
||||
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '提现订单号',
|
||||
dataIndex: 'uuid',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
dataIndex: 'price',
|
||||
width: '10%',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '接收地址',
|
||||
dataIndex: 'to_address',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'type',
|
||||
hideInSearch: true,
|
||||
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: '时间',
|
||||
dataIndex: 'time',
|
||||
valueType: 'dateRange',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 150,
|
||||
render: (_, row) => [
|
||||
row.status === 30000 ? (
|
||||
<Access accessible={access.canShowButton('withdraw_pass')}>
|
||||
<ConfirmButton
|
||||
key="confirm"
|
||||
title="确认通过提现?"
|
||||
buttonName="通过"
|
||||
onConfirm={() => {
|
||||
handleClick(row.uuid, WithdrawType.SUCCESS);
|
||||
}}
|
||||
/>
|
||||
</Access>
|
||||
) : null,
|
||||
row.status === 30000 ? (
|
||||
<Access accessible={access.canShowButton('withdraw_refuse')}>
|
||||
<RejectButton
|
||||
key="confirm"
|
||||
title="确认拒绝提现?"
|
||||
buttonName="拒绝"
|
||||
onConfirm={() => {
|
||||
handleClick(row.uuid, WithdrawType.FAILED);
|
||||
}}
|
||||
/>
|
||||
</Access>
|
||||
) : null,
|
||||
],
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="uuid"
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
params.status = params.status == null ? 0 : parseInt(params.status);
|
||||
const res = await fetchTableData(getWithdrawList, 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;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WithdrawList;
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
import React, { useState, useRef } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import {
|
||||
getAccountList,
|
||||
deleteUser,
|
||||
updateUser,
|
||||
changeUserStatus,
|
||||
} from '@/services/system/accountManage';
|
||||
import { fetchTableData } from '@/utils/table';
|
||||
import DeleteButton from '@/components/Table/DeleteButton';
|
||||
import { Popover, Switch } from 'antd';
|
||||
import AddAccountModal from '../components/AddAccountModal';
|
||||
import EditAccountModal from '../components/EditAccountModal';
|
||||
import { getRoleList } from '@/services/system/role';
|
||||
import { Access, useAccess } from 'umi';
|
||||
|
||||
const AccountManageList = () => {
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [isEditModal, setIsEditModal] = useState(false);
|
||||
const [modalData, setModalData] = useState({});
|
||||
|
||||
const handleEdit = (row: any) => {
|
||||
setModalData(row);
|
||||
setIsEditModal(true);
|
||||
};
|
||||
|
||||
const handleDelete = async (name: any) => {
|
||||
await deleteUser({ name: name });
|
||||
};
|
||||
const tableRef = useRef<ActionType>();
|
||||
const access = useAccess();
|
||||
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '账号',
|
||||
dataIndex: 'name',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '角色',
|
||||
dataIndex: 'role',
|
||||
hideInSearch: true,
|
||||
valueType: 'select',
|
||||
request: async () => {
|
||||
const res = await getRoleList({ page: 1, size: 10 });
|
||||
const options = new Array();
|
||||
(res as any).items.forEach((element) => {
|
||||
options.push({ label: element.role_name, value: element.id });
|
||||
});
|
||||
return options;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 180,
|
||||
render: (_, row) => [
|
||||
<Access accessible={access.canShowButton('account_edit')}>
|
||||
<a
|
||||
key="edit"
|
||||
placeholder=""
|
||||
onClick={() => {
|
||||
handleEdit(row);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</a>
|
||||
</Access>,
|
||||
<Access accessible={access.canShowButton('account_disabled')}>
|
||||
<Popover
|
||||
content={
|
||||
<div>
|
||||
<p>账号启用/禁用</p>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Switch
|
||||
key="switch"
|
||||
defaultChecked={row.status}
|
||||
size="small"
|
||||
onChange={async (checked) => {
|
||||
await changeUserStatus({ name: row.name, status: checked });
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
</Access>,
|
||||
<Access accessible={access.canShowButton('account_delete')}>
|
||||
<DeleteButton
|
||||
key="delete"
|
||||
onDelete={() => {
|
||||
handleDelete(row.name);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</Access>,
|
||||
],
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="name"
|
||||
search={false}
|
||||
toolBarActions={[
|
||||
{
|
||||
type: 'add',
|
||||
permission: 'account_add',
|
||||
onConfirm: () => {
|
||||
setIsModalVisible(true);
|
||||
},
|
||||
},
|
||||
]}
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
const res = await fetchTableData(getAccountList, params);
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
<AddAccountModal
|
||||
visible={isModalVisible}
|
||||
onCancel={function () {
|
||||
setIsModalVisible(false);
|
||||
}}
|
||||
onOk={async function (): Promise<void> {
|
||||
setIsModalVisible(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
<EditAccountModal
|
||||
visible={isEditModal}
|
||||
editModalData={modalData}
|
||||
onCancel={function () {
|
||||
setIsEditModal(false);
|
||||
}}
|
||||
onOk={async function (): Promise<void> {
|
||||
setIsEditModal(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountManageList;
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
// 创建弹窗
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { createForm, Field, FormPathPattern, onFieldReact } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, Select } from '@formily/antd';
|
||||
import { addUser } from '@/services/system/accountManage';
|
||||
import { action } from '@formily/reactive';
|
||||
import { getRoleList } from '@/services/system/role';
|
||||
|
||||
interface AddAccountModalPropsType extends ModalProps {
|
||||
onOk: () => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
Select,
|
||||
},
|
||||
});
|
||||
|
||||
const AddAccountModal = ({ onOk, onCancel, ...rest }: AddAccountModalPropsType) => {
|
||||
const [roleListData, setRoleListData] = useState({});
|
||||
|
||||
const UseAsyncDataSource = (
|
||||
pattern: FormPathPattern,
|
||||
service: (field: Field) => Promise<{ label: string; value: any }[]>,
|
||||
) => {
|
||||
onFieldReact(pattern, (field) => {
|
||||
service(field).then(
|
||||
action.bound((data) => {
|
||||
field.dataSource = data;
|
||||
}),
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const form = createForm({
|
||||
effects: () => {
|
||||
UseAsyncDataSource('role', async (field) => {
|
||||
const list = roleListData as any;
|
||||
const option = [] as any;
|
||||
for (let index = 0; index < list.items.length; index++) {
|
||||
const element = list.items[index];
|
||||
const item = {
|
||||
label: element.role_name,
|
||||
value: element.id,
|
||||
};
|
||||
option.push(item);
|
||||
}
|
||||
return option;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const getSelectData = async () => {
|
||||
const list = await getRoleList({ page: 1, size: 10 });
|
||||
setRoleListData(list);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getSelectData();
|
||||
}, []);
|
||||
|
||||
const handleOk = async () => {
|
||||
form.submit(async () => {
|
||||
onOk();
|
||||
const formState = form.getFormState();
|
||||
await addUser(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="name"
|
||||
title="账号名"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
x-component-props={{
|
||||
placeholder: '请输入账号名',
|
||||
}}
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="password"
|
||||
title="密码"
|
||||
required
|
||||
x-validator={{
|
||||
required: true,
|
||||
}}
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
x-component-props={{
|
||||
placeholder: '请输入密码',
|
||||
}}
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="role"
|
||||
title="角色"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Select"
|
||||
x-component-props={{
|
||||
mode: 'multiple',
|
||||
placeholder: '请选择角色',
|
||||
}}
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddAccountModal;
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
// 创建弹窗
|
||||
import React, { useRef, useEffect, useState } from 'react';
|
||||
import { createForm, FormPathPattern, onFieldReact } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, Select } from '@formily/antd';
|
||||
import { updateUser } from '@/services/system/accountManage';
|
||||
import { getRoleList } from '@/services/system/role';
|
||||
import { action } from '@formily/reactive';
|
||||
|
||||
interface EditAccountModalPropsType extends ModalProps {
|
||||
editModalData: any;
|
||||
onCancel: () => void;
|
||||
onOk: () => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
Select,
|
||||
},
|
||||
});
|
||||
|
||||
const EditAccountModal = ({
|
||||
onOk,
|
||||
onCancel,
|
||||
editModalData,
|
||||
...rest
|
||||
}: EditAccountModalPropsType) => {
|
||||
// const [roleListData, setRoleListData] = useState({});
|
||||
|
||||
// const getSelectData = async () => {
|
||||
// const list =
|
||||
// setRoleListData(list);
|
||||
// };
|
||||
|
||||
const UseAsyncDataSource = (
|
||||
pattern: FormPathPattern,
|
||||
service: (field: Field) => Promise<{ label: string; value: any }[]>,
|
||||
) => {
|
||||
onFieldReact(pattern, (field) => {
|
||||
service(field).then(
|
||||
action.bound((data) => {
|
||||
field.dataSource = data;
|
||||
}),
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const form = createForm({
|
||||
effects: () => {
|
||||
UseAsyncDataSource('role', async (field) => {
|
||||
const list = await getRoleList({ page: 1, size: 10 });
|
||||
const option = [];
|
||||
for (let index = 0; index < list.items.length; index++) {
|
||||
const element = list.items[index];
|
||||
const item = {
|
||||
label: element.role_name,
|
||||
value: element.id,
|
||||
};
|
||||
option.push(item);
|
||||
}
|
||||
return option;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
form.setInitialValues(editModalData);
|
||||
});
|
||||
|
||||
const handleOk = async () => {
|
||||
form.submit(async () => {
|
||||
onOk();
|
||||
const formState = form.getFormState();
|
||||
await updateUser(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="name"
|
||||
title="账号名"
|
||||
required
|
||||
x-disabled
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
x-component-props={{
|
||||
placeholder: '请输入账号名',
|
||||
}}
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="password"
|
||||
title="密码"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
x-component-props={{
|
||||
placeholder: '请输入密码',
|
||||
}}
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="role"
|
||||
title="角色"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Select"
|
||||
x-component-props={{
|
||||
placeholder: '请选择角色',
|
||||
}}
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditAccountModal;
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
import React, { useState, useRef } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import { getNoticeList, createNotice, updateNotice, deleteNotice } from '@/services/system/notice';
|
||||
import { fetchTableData } from '@/utils/table';
|
||||
import DeleteButton from '@/components/Table/DeleteButton';
|
||||
import { Popover, Switch } from 'antd';
|
||||
import AddNoticeModal from '../components/AddNoticeModal';
|
||||
import EditNoticeModal from '../components/EditNoticeModal';
|
||||
import { NoticeType } from '@/constants/enum/notice';
|
||||
import { Access, useAccess } from 'umi';
|
||||
|
||||
const NoticeList = () => {
|
||||
const tableRef = useRef<ActionType>();
|
||||
const access = useAccess();
|
||||
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [isEditModalVisible, setIsEditModalVisible] = useState(false);
|
||||
const [modalData, setModalData] = useState({});
|
||||
|
||||
const handleEdit = (row: any) => {
|
||||
setModalData(row);
|
||||
setIsEditModalVisible(true);
|
||||
tableRef.current?.reload();
|
||||
};
|
||||
|
||||
const handleDelete = async (code: any) => {
|
||||
await deleteNotice({ code: code });
|
||||
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>[] = [
|
||||
{
|
||||
title: '通知码',
|
||||
dataIndex: 'code',
|
||||
valueEnum: () => {
|
||||
const options = {};
|
||||
noticeTypeList.forEach((item) => {
|
||||
options[item.value] = item.label;
|
||||
});
|
||||
return options;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '通知地址',
|
||||
dataIndex: 'addr',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 180,
|
||||
render: (_, row) => [
|
||||
<Access accessible={access.canShowButton('notice_edit')}>
|
||||
<a
|
||||
key="edit"
|
||||
onClick={() => {
|
||||
handleEdit(row);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</a>
|
||||
</Access>,
|
||||
<Access accessible={access.canShowButton('notice_disabled')}>
|
||||
<Popover
|
||||
content={
|
||||
<div>
|
||||
<p>通知启用/禁用</p>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Switch
|
||||
key="switch"
|
||||
defaultChecked={row.status}
|
||||
size="small"
|
||||
onChange={async (checked) => {
|
||||
row.status = checked;
|
||||
await updateNotice(row);
|
||||
}}
|
||||
/>
|
||||
,
|
||||
</Popover>
|
||||
</Access>,
|
||||
<Access accessible={access.canShowButton('notice_delete')}>
|
||||
<DeleteButton
|
||||
key="delete"
|
||||
onDelete={() => {
|
||||
handleDelete(row.code);
|
||||
}}
|
||||
/>
|
||||
</Access>,
|
||||
],
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="code"
|
||||
search={false}
|
||||
toolBarActions={[
|
||||
{
|
||||
type: 'add',
|
||||
permission: 'notice_add',
|
||||
onConfirm: () => {
|
||||
setIsModalVisible(true);
|
||||
},
|
||||
},
|
||||
]}
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
const res = await fetchTableData(getNoticeList, params);
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
<AddNoticeModal
|
||||
visible={isModalVisible}
|
||||
onCancel={function () {
|
||||
setIsModalVisible(false);
|
||||
}}
|
||||
onOk={async function (val: any): Promise<void> {
|
||||
await createNotice(val);
|
||||
setIsModalVisible(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
<EditNoticeModal
|
||||
visible={isEditModalVisible}
|
||||
editModalData={modalData}
|
||||
onCancel={function () {
|
||||
setIsEditModalVisible(false);
|
||||
}}
|
||||
onOk={async function (val: any): Promise<void> {
|
||||
await updateNotice(val);
|
||||
setIsEditModalVisible(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NoticeList;
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// 添加代币类型弹窗
|
||||
import React, { useRef } from 'react';
|
||||
import { createForm } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
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 {
|
||||
onOk: (val: any) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
Select,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const AddNoticeModal = ({ onOk, onCancel, ...rest }: AddNoticeModalPropsType) => {
|
||||
const handleOk = () => {
|
||||
form.submit(async () => {
|
||||
const formState = form.getFormState();
|
||||
formState.values.code = parseInt(formState.values.code);
|
||||
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="code"
|
||||
title="通知码"
|
||||
required
|
||||
x-component-props={{
|
||||
options: noticeTypeList,
|
||||
}}
|
||||
x-decorator="FormItem"
|
||||
x-component="Select"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="addr"
|
||||
title="通知地址"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.Boolean
|
||||
name="status"
|
||||
title="状态"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Select"
|
||||
enum={[
|
||||
{ label: '启用', value: true },
|
||||
{ label: '禁用', value: false },
|
||||
]}
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddNoticeModal;
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// 修改弹窗
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import { createForm } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, Select } from '@formily/antd';
|
||||
import { NoticeType } from '@/constants/enum/notice';
|
||||
|
||||
interface EditNoticeModalPropsType extends ModalProps {
|
||||
editModalData: any;
|
||||
onOk: (val: any) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
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 SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
Select,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const EditNoticeModal = ({ onOk, onCancel, editModalData, ...rest }: EditNoticeModalPropsType) => {
|
||||
useEffect(() => {
|
||||
form.setInitialValues(editModalData);
|
||||
});
|
||||
|
||||
const handleOk = () => {
|
||||
form.submit(async () => {
|
||||
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="code"
|
||||
title="通知码"
|
||||
required
|
||||
x-component-props={{
|
||||
options: noticeTypeList,
|
||||
}}
|
||||
x-decorator="FormItem"
|
||||
x-component="Select"
|
||||
x-disabled
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="addr"
|
||||
title="通知地址"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditNoticeModal;
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
import React, { useState, useRef } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import routes from '@/routes';
|
||||
import DeleteButton from '@/components/Table/DeleteButton';
|
||||
import { getPermission, upsertPermission } from '@/services/system/permission';
|
||||
import AddPermissionModal from '../components/AddPermissionModal';
|
||||
import EditPermissionModal from '../components/EditPermissionModal';
|
||||
import { message } from 'antd';
|
||||
import { Access, useAccess } from 'umi';
|
||||
|
||||
const PermissionsList = () => {
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [isEditModalVisible, setIsEditModalVisible] = useState(false);
|
||||
|
||||
const [permissionsData, setPermissionsData] = useState(Array);
|
||||
const [isAddFirst, setIsAddFirst] = useState(false);
|
||||
const [modalData, setModalData] = useState({});
|
||||
const [rowData, setRowData] = useState({} as any);
|
||||
|
||||
const tableRef = useRef<ActionType>();
|
||||
const access = useAccess();
|
||||
|
||||
const handleAdd = (row: any) => {
|
||||
setRowData(row);
|
||||
setIsModalVisible(true);
|
||||
};
|
||||
const handleEdit = (row: any) => {
|
||||
setRowData(row);
|
||||
setIsEditModalVisible(true);
|
||||
};
|
||||
|
||||
const deleteLoopChildren = (rowData, children) => {
|
||||
for (let index = 0; index < children.length; index++) {
|
||||
const childrenElement = children[index];
|
||||
if (rowData.code == childrenElement.code) {
|
||||
if (children.length == 1) {
|
||||
return 1;
|
||||
}
|
||||
children.splice(index, 1);
|
||||
return true;
|
||||
} else {
|
||||
if (Object.prototype.hasOwnProperty.call(childrenElement, 'children')) {
|
||||
const childrenLength = deleteLoopChildren(rowData, childrenElement.children);
|
||||
if (childrenLength == 1) {
|
||||
delete childrenElement.children;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (row: any) => {
|
||||
for (let index = 0; index < permissionsData.length; index++) {
|
||||
const element = permissionsData[index];
|
||||
if (row.code == (element as any).code) {
|
||||
permissionsData.splice(index, 1);
|
||||
break;
|
||||
} else {
|
||||
const result = deleteLoopChildren(row, (element as any).children);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
await upsertPermission(permissionsData);
|
||||
message.success('删除权限成功');
|
||||
tableRef.current?.reload();
|
||||
};
|
||||
|
||||
const addLoopChildren = (rowData, children) => {
|
||||
for (let index = 0; index < children.length; index++) {
|
||||
let childrenElement = children[index];
|
||||
if (rowData.code == childrenElement.code) {
|
||||
if (Object.prototype.hasOwnProperty.call(childrenElement, 'children')) {
|
||||
childrenElement = rowData;
|
||||
} else {
|
||||
childrenElement.children = rowData;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (Object.prototype.hasOwnProperty.call(childrenElement, 'children')) {
|
||||
addLoopChildren(rowData, childrenElement.children);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const editLoopChildren = (val, rowData, children) => {
|
||||
for (let index = 0; index < children.length; index++) {
|
||||
const childrenElement = children[index];
|
||||
if (rowData.code == childrenElement.code) {
|
||||
childrenElement.code = val.code;
|
||||
return true;
|
||||
} else {
|
||||
if (Object.prototype.hasOwnProperty.call(childrenElement, 'children')) {
|
||||
editLoopChildren(val, rowData, childrenElement.children);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '权限名',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 180,
|
||||
render: (_, row) => [
|
||||
<Access accessible={access.canShowButton('permission_add')}>
|
||||
<a
|
||||
key="add"
|
||||
onClick={() => {
|
||||
setIsAddFirst(false);
|
||||
handleAdd(row);
|
||||
}}
|
||||
>
|
||||
添加
|
||||
</a>
|
||||
</Access>,
|
||||
<Access accessible={access.canShowButton('permission_edit')}>
|
||||
<a
|
||||
key="edit"
|
||||
onClick={() => {
|
||||
setModalData(row);
|
||||
handleEdit(row);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</a>
|
||||
</Access>,
|
||||
Object.prototype.hasOwnProperty.call(row, 'children') ? null : (
|
||||
<Access accessible={access.canShowButton('permission_delete')}>
|
||||
<DeleteButton
|
||||
key="delete"
|
||||
onDelete={() => {
|
||||
handleDelete(row);
|
||||
}}
|
||||
/>
|
||||
</Access>
|
||||
),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
search={false}
|
||||
rowKey="name"
|
||||
actionRef={tableRef}
|
||||
toolBarActions={[
|
||||
{
|
||||
type: 'add',
|
||||
permission: 'permission_add',
|
||||
onConfirm: () => {
|
||||
setIsAddFirst(true);
|
||||
setIsModalVisible(true);
|
||||
},
|
||||
},
|
||||
]}
|
||||
request={async (params) => {
|
||||
const res = await getPermission({});
|
||||
const data = JSON.parse((res as any).items);
|
||||
setPermissionsData(data);
|
||||
return { data: data };
|
||||
}}
|
||||
/>
|
||||
<AddPermissionModal
|
||||
visible={isModalVisible}
|
||||
onCancel={function () {
|
||||
setIsModalVisible(false);
|
||||
}}
|
||||
onOk={async function (val) {
|
||||
if (isAddFirst) {
|
||||
permissionsData.push(val);
|
||||
} else {
|
||||
if (Object.prototype.hasOwnProperty.call(rowData, 'children')) {
|
||||
const result = rowData.children.find(function (value, index, arr) {
|
||||
return value.code === val.code;
|
||||
});
|
||||
if (!result) {
|
||||
rowData.children.push(val);
|
||||
} else {
|
||||
message.warning('已有改权限名');
|
||||
}
|
||||
} else {
|
||||
rowData.children = [val];
|
||||
}
|
||||
for (let index = 0; index < permissionsData.length; index++) {
|
||||
const element = permissionsData[index] as any;
|
||||
if (rowData.code == element.code) {
|
||||
permissionsData[index] = rowData;
|
||||
break;
|
||||
} else {
|
||||
const result = addLoopChildren(rowData, element.children);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await upsertPermission(permissionsData);
|
||||
message.success('添加权限成功');
|
||||
setIsModalVisible(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
<EditPermissionModal
|
||||
visible={isEditModalVisible}
|
||||
editModalData={modalData}
|
||||
onCancel={function () {
|
||||
setIsEditModalVisible(false);
|
||||
}}
|
||||
onOk={async function (val) {
|
||||
for (let index = 0; index < permissionsData.length; index++) {
|
||||
const element = permissionsData[index] as any;
|
||||
if (rowData.code == element.code) {
|
||||
(permissionsData[index] as any).code = val.code;
|
||||
break;
|
||||
} else {
|
||||
const result = editLoopChildren(val, rowData, element.children);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
await upsertPermission(permissionsData);
|
||||
setIsEditModalVisible(false);
|
||||
message.success('编辑权限成功');
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PermissionsList;
|
||||
|
|
@ -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 { Form, FormItem, Input } from '@formily/antd';
|
||||
|
||||
interface AddPermissionModalPropsType extends ModalProps {
|
||||
onCancel: () => void;
|
||||
onOk: (val: any) => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const AddPermissionModal = ({ onOk, onCancel, ...rest }: AddPermissionModalPropsType) => {
|
||||
const handleOk = async () => {
|
||||
form.submit(async () => {
|
||||
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="name"
|
||||
title="权限名"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="code"
|
||||
title="权限码"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPermissionModal;
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// 创建弹窗
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { createForm } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input } from '@formily/antd';
|
||||
|
||||
interface EditPermissionModalPropsType extends ModalProps {
|
||||
editModalData: any;
|
||||
onCancel: () => void;
|
||||
onOk: (val: any) => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const EditPermissionModal = ({
|
||||
onOk,
|
||||
onCancel,
|
||||
editModalData,
|
||||
...rest
|
||||
}: EditPermissionModalPropsType) => {
|
||||
useEffect(() => {
|
||||
form.setInitialValues(editModalData);
|
||||
});
|
||||
|
||||
const handleOk = async () => {
|
||||
form.submit(async () => {
|
||||
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="name"
|
||||
title="权限名"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="code"
|
||||
title="权限码"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditPermissionModal;
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
import React, { useRef, useState } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import { getRoleList, deleteRole, createRole, updateRole } from '@/services/system/role';
|
||||
import { fetchTableData } from '@/utils/table';
|
||||
import DeleteButton from '@/components/Table/DeleteButton';
|
||||
import AddRoleModal from '../components/AddRoleModal';
|
||||
import EditRoleModal from '../components/EditRoleModal';
|
||||
import AuthPermissionsDrawer from '../components/AuthPermissionsDrawer';
|
||||
import { Access, useAccess } from 'umi';
|
||||
|
||||
const RoleList = () => {
|
||||
const tableRef = useRef<ActionType>();
|
||||
const access = useAccess();
|
||||
|
||||
const [isDrawerVisible, setIsDrawerVisible] = useState(false);
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [isEditModal, setIsEditModal] = useState(false);
|
||||
const [modalData, setModalData] = useState({});
|
||||
const [rowData, setRowData] = useState({});
|
||||
|
||||
const handleEdit = (row: any) => {
|
||||
setModalData(row);
|
||||
setIsEditModal(true);
|
||||
};
|
||||
const handleAuth = (row: any) => {
|
||||
setRowData(row);
|
||||
setIsDrawerVisible(true);
|
||||
};
|
||||
const handleDelete = async (id: any) => {
|
||||
await deleteRole({ id: id });
|
||||
tableRef.current?.reload();
|
||||
};
|
||||
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '角色名称',
|
||||
dataIndex: 'role_name',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 180,
|
||||
render: (_, row) => [
|
||||
<Access accessible={access.canShowButton('role_edit')}>
|
||||
<a
|
||||
key="edit"
|
||||
onClick={() => {
|
||||
handleEdit(row);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</a>
|
||||
</Access>,
|
||||
<Access accessible={access.canShowButton('role_authorization')}>
|
||||
<a
|
||||
key="auth"
|
||||
onClick={() => {
|
||||
handleAuth(row);
|
||||
}}
|
||||
>
|
||||
授权
|
||||
</a>
|
||||
</Access>,
|
||||
<Access accessible={access.canShowButton('role_delete')}>
|
||||
<DeleteButton
|
||||
key="delete"
|
||||
onDelete={() => {
|
||||
handleDelete(row.id);
|
||||
}}
|
||||
/>
|
||||
</Access>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
search={false}
|
||||
toolBarActions={[
|
||||
{
|
||||
type: 'add',
|
||||
permission: 'role_add',
|
||||
onConfirm: () => {
|
||||
setIsModalVisible(true);
|
||||
},
|
||||
},
|
||||
]}
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
const res = await fetchTableData(getRoleList, params);
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
<AddRoleModal
|
||||
visible={isModalVisible}
|
||||
onCancel={function () {
|
||||
setIsModalVisible(false);
|
||||
}}
|
||||
onOk={async function (val): Promise<void> {
|
||||
await createRole(val);
|
||||
setIsModalVisible(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
<EditRoleModal
|
||||
visible={isEditModal}
|
||||
editModalData={modalData}
|
||||
onCancel={function () {
|
||||
setIsEditModal(false);
|
||||
}}
|
||||
onOk={async function (val): Promise<void> {
|
||||
await updateRole(val);
|
||||
setIsEditModal(false);
|
||||
tableRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
<AuthPermissionsDrawer
|
||||
visible={isDrawerVisible}
|
||||
rowData={rowData}
|
||||
onCancel={function () {
|
||||
setIsDrawerVisible(false);
|
||||
}}
|
||||
onOk={async function (val) {
|
||||
await updateRole(val);
|
||||
setIsDrawerVisible(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RoleList;
|
||||
|
|
@ -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 { Form, FormItem, Input } from '@formily/antd';
|
||||
|
||||
interface AddRoleModalPropsType extends ModalProps {
|
||||
onCancel: () => void;
|
||||
onOk: (val: any) => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const AddRoleModal = ({ onOk, onCancel, ...rest }: AddRoleModalPropsType) => {
|
||||
const handleOk = async () => {
|
||||
form.submit(async () => {
|
||||
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="role_name"
|
||||
title="角色名"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="remark"
|
||||
title="备注"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddRoleModal;
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
// 创建弹窗
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Button, Drawer, DrawerProps, message, Space } from 'antd';
|
||||
import { ActionType, ProColumns } from '@ant-design/pro-table';
|
||||
import Table from '@/components/Table';
|
||||
import { TableRowSelection } from 'antd/lib/table/interface';
|
||||
import { getPermission } from '@/services/system/permission';
|
||||
import { useModel } from '@/.umi/plugin-model/useModel';
|
||||
|
||||
interface AuthPermissionsDrawerPropsType extends DrawerProps {
|
||||
onCancel: () => void;
|
||||
onOk: (val: any) => void;
|
||||
rowData: any;
|
||||
}
|
||||
|
||||
const divStyle: React.CSSProperties = {
|
||||
padding: 0,
|
||||
};
|
||||
|
||||
const columnsPermissions: ProColumns<any>[] = [
|
||||
{
|
||||
title: '权限名',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
];
|
||||
|
||||
const valueMap = new Map();
|
||||
const loops = (list, parent) => {
|
||||
return (list || []).map(({ children, name, code }) => {
|
||||
const node = (valueMap[code] = {
|
||||
parent,
|
||||
name,
|
||||
code,
|
||||
}) as any;
|
||||
node.children = loops(children, node);
|
||||
return node;
|
||||
});
|
||||
};
|
||||
|
||||
const getPath = (code) => {
|
||||
const path = [] as any;
|
||||
let current = valueMap[code];
|
||||
while (current) {
|
||||
path.unshift(current.code);
|
||||
current = current.parent;
|
||||
}
|
||||
return path;
|
||||
};
|
||||
|
||||
const mergeArray = (arr1, arr2) => {
|
||||
const _arr = new Array();
|
||||
for (let i = 0; i < arr1.length; i++) {
|
||||
_arr.push(arr1[i]);
|
||||
}
|
||||
for (let i = 0; i < arr2.length; i++) {
|
||||
let flag = true;
|
||||
for (let j = 0; j < arr1.length; j++) {
|
||||
if (arr2[i] == arr1[j]) {
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
_arr.push(arr2[i]);
|
||||
}
|
||||
}
|
||||
return _arr;
|
||||
};
|
||||
|
||||
const AuthPermissionsDrawer = ({
|
||||
onOk,
|
||||
onCancel,
|
||||
rowData,
|
||||
...rest
|
||||
}: AuthPermissionsDrawerPropsType) => {
|
||||
const tableRef = useRef<ActionType>();
|
||||
const [selectedKeys, setSelectedKeys] = useState(new Array());
|
||||
const [tempValue, setTempValue] = useState(new Map());
|
||||
|
||||
const rowSelection: TableRowSelection<DataType> = {
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
console.log('selectedRowKeys = ', selectedRowKeys);
|
||||
setSelectedKeys(selectedRowKeys);
|
||||
},
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
let postSelectedKeys = new Array();
|
||||
selectedKeys.forEach((element) => {
|
||||
const path = getPath(element);
|
||||
postSelectedKeys = mergeArray(postSelectedKeys, path);
|
||||
});
|
||||
if (postSelectedKeys.length == 0) {
|
||||
message.warning('请选择权限。');
|
||||
return;
|
||||
}
|
||||
onOk({ id: rowData.id, permission: postSelectedKeys });
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
onCancel();
|
||||
};
|
||||
useEffect(() => {
|
||||
const parentArray = new Array();
|
||||
let newPermission = new Array();
|
||||
for (const key in tempValue) {
|
||||
if (Object.prototype.hasOwnProperty.call(tempValue, key)) {
|
||||
const element = tempValue[key];
|
||||
if (element.children.length != 0) {
|
||||
parentArray.push(element.code);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
rowData.permission != undefined &&
|
||||
rowData.permission.length != 0 &&
|
||||
rowData.permission != null
|
||||
) {
|
||||
newPermission = rowData.permission.filter((item) => !parentArray.includes(item));
|
||||
}
|
||||
setSelectedKeys(newPermission);
|
||||
}, [rowData.permission, tempValue]);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
onClose={handleCancel}
|
||||
width={600}
|
||||
{...rest}
|
||||
bodyStyle={divStyle}
|
||||
extra={
|
||||
<Space>
|
||||
<Button onClick={handleCancel}>取消</Button>
|
||||
<Button type="primary" onClick={handleOk}>
|
||||
确定
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
columns={columnsPermissions}
|
||||
rowKey="code"
|
||||
key="code"
|
||||
search={false}
|
||||
pagination={false}
|
||||
rowSelection={{
|
||||
...rowSelection,
|
||||
hideSelectAll: true,
|
||||
checkStrictly: false,
|
||||
selectedRowKeys: selectedKeys,
|
||||
}}
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
const res = (await getPermission({})) as any;
|
||||
const treeData = JSON.parse(res.items);
|
||||
loops(treeData, null);
|
||||
setTempValue(valueMap);
|
||||
return { data: treeData };
|
||||
}}
|
||||
/>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthPermissionsDrawer;
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// 创建弹窗
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import { createForm } from '@formily/core';
|
||||
import { createSchemaField } from '@formily/react';
|
||||
import Modal, { ModalProps } from '@/components/Modal';
|
||||
import { Form, FormItem, Input, Select } from '@formily/antd';
|
||||
import { addUser, updateUser } from '@/services/system/accountManage';
|
||||
|
||||
interface EditRoleModalPropsType extends ModalProps {
|
||||
editModalData: any;
|
||||
onCancel: () => void;
|
||||
onOk: (val: any) => void;
|
||||
}
|
||||
|
||||
const SchemaField = createSchemaField({
|
||||
components: {
|
||||
FormItem,
|
||||
Input,
|
||||
Select,
|
||||
},
|
||||
});
|
||||
|
||||
const form = createForm({});
|
||||
|
||||
const EditRoleModal = ({ onOk, onCancel, editModalData, ...rest }: EditRoleModalPropsType) => {
|
||||
useEffect(() => {
|
||||
form.setInitialValues(editModalData);
|
||||
});
|
||||
|
||||
const handleOk = async () => {
|
||||
form.submit(async () => {
|
||||
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="role_name"
|
||||
title="角色名"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
x-component-props={{
|
||||
placeholder: '请输入账号名',
|
||||
}}
|
||||
/>
|
||||
<SchemaField.String
|
||||
name="remark"
|
||||
title="备注"
|
||||
required
|
||||
x-decorator="FormItem"
|
||||
x-component="Input"
|
||||
x-component-props={{
|
||||
placeholder: '请输入密码',
|
||||
}}
|
||||
/>
|
||||
</SchemaField>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditRoleModal;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
@import '~antd/es/style/themes/default.less';
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
padding: 20px;
|
||||
overflow: auto;
|
||||
background: white;
|
||||
:global {
|
||||
.ant-pro-form-login-header {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.textarea {
|
||||
width: 600px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
import React, { useState, useEffect, ChangeEvent } from 'react';
|
||||
import { Button, Input, message, Popconfirm } from 'antd';
|
||||
import styles from './index.less';
|
||||
import { createAppID, createSecretKey, getAppID, getSecretKey } from '@/services/system/secretKey';
|
||||
import { Access, useAccess } from 'umi';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
const SecretKey: React.FC = () => {
|
||||
const access = useAccess();
|
||||
const [secretKey, setSecretKey] = useState('');
|
||||
const [appIDString, setAppIDString] = useState('');
|
||||
|
||||
const create = async () => {
|
||||
const data = await createSecretKey({});
|
||||
message.success('密钥创建成功');
|
||||
setSecretKey(data + '');
|
||||
};
|
||||
|
||||
const appIDCreate = async () => {
|
||||
if (appIDString == '') {
|
||||
message.warning('请填写AppID');
|
||||
return;
|
||||
}
|
||||
await createAppID({ appid: appIDString });
|
||||
message.success('AppID创建成功');
|
||||
};
|
||||
|
||||
const getAppIDString = async () => {
|
||||
const data = await getAppID();
|
||||
setAppIDString(data + '');
|
||||
};
|
||||
|
||||
const getUserSecretKey = async () => {
|
||||
const data = await getSecretKey();
|
||||
setSecretKey(data + '');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getAppIDString();
|
||||
getUserSecretKey();
|
||||
}, [secretKey]);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Access accessible={access.canShowButton('secret_create')}>
|
||||
<Popconfirm title="确定创建密钥?" onConfirm={create} okText="确定" cancelText="取消">
|
||||
<Button className={styles.button} type="primary">
|
||||
创建密钥
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Access>
|
||||
|
||||
<TextArea className={styles.textarea} rows={16} value={secretKey} />
|
||||
<br />
|
||||
<br />
|
||||
<Input.Group compact>
|
||||
<Input
|
||||
style={{ width: 'calc(50% - 160px)' }}
|
||||
value={appIDString}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
setAppIDString(event.target.value);
|
||||
}}
|
||||
placeholder="请输入AppID"
|
||||
/>
|
||||
<Access accessible={access.canShowButton('AppID_create')}>
|
||||
<Popconfirm
|
||||
title="确定创建AppID?"
|
||||
onConfirm={appIDCreate}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button className={styles.button} type="primary">
|
||||
创建AppID
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Access>
|
||||
</Input.Group>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SecretKey;
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import React, { useState, useRef } from 'react';
|
||||
import Table, { ProColumns, ActionType } from '@/components/Table';
|
||||
import { getUserList } from '@/services/user/user';
|
||||
import { fetchTableData } from '@/utils/table';
|
||||
import moment from 'moment';
|
||||
|
||||
const UserManageList = () => {
|
||||
const tableRef = useRef<ActionType>();
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
title: '钱包地址',
|
||||
dataIndex: 'address',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '注册时间',
|
||||
dataIndex: 'create_time',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '登陆时间',
|
||||
dataIndex: 'last_time',
|
||||
hideInSearch: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="address"
|
||||
actionRef={tableRef}
|
||||
request={async (params) => {
|
||||
const res = await fetchTableData(getUserList, params);
|
||||
console.log('res = ', res);
|
||||
for (const key in res.data) {
|
||||
if (Object.prototype.hasOwnProperty.call(res.data, key)) {
|
||||
const element = res.data[key];
|
||||
if (
|
||||
element.create_time != '' &&
|
||||
element.create_time != undefined &&
|
||||
element.create_time != null
|
||||
) {
|
||||
element.create_time = moment(element.create_time * 1000).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
);
|
||||
}
|
||||
if (
|
||||
element.last_time != '' &&
|
||||
element.last_time != undefined &&
|
||||
element.last_time != null
|
||||
) {
|
||||
element.last_time = moment(element.last_time * 1000).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res.data == null) {
|
||||
return [];
|
||||
}
|
||||
return res;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserManageList;
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
|
||||
/>
|
||||
<title>Pro</title>
|
||||
<title>TBG</title>
|
||||
<link rel="icon" href="<%= context.config.publicPath +'logo.png'%>" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
|||
|
|
@ -11,33 +11,172 @@ export default [
|
|||
component: './Login',
|
||||
},
|
||||
{
|
||||
name: '设置',
|
||||
path: RoutePath.SETTING,
|
||||
name: '充值系统',
|
||||
path: RoutePath.RECHARGE,
|
||||
code: 'recharge_system',
|
||||
access: 'normalRouteFilter',
|
||||
routes: [
|
||||
{
|
||||
path: RoutePath.SETTING,
|
||||
redirect: RoutePath.WORK.LIST,
|
||||
path: RoutePath.RECHARGE,
|
||||
redirect: RoutePath.RECORD.LIST,
|
||||
hideInMenu: true,
|
||||
},
|
||||
|
||||
{
|
||||
name: '作品',
|
||||
path: RoutePath.WORK.LIST,
|
||||
component: './Work/List',
|
||||
name: '充值订单',
|
||||
path: RoutePath.RECORD.LIST,
|
||||
code: 'recharge_record',
|
||||
access: 'normalRouteFilter',
|
||||
component: './Recharge/Record/List',
|
||||
},
|
||||
{
|
||||
name: '作品详情',
|
||||
path: RoutePath.WORK.EDIT,
|
||||
name: '收款地址',
|
||||
path: RoutePath.WALLET.LIST,
|
||||
code: 'wallet_address',
|
||||
access: 'normalRouteFilter',
|
||||
component: './Recharge/Wallet/List',
|
||||
},
|
||||
{
|
||||
name: '代币种类',
|
||||
path: RoutePath.COIN_TYPE.LIST,
|
||||
code: 'coin_type',
|
||||
access: 'normalRouteFilter',
|
||||
component: './Recharge/CoinType/List',
|
||||
},
|
||||
{
|
||||
name: '提现管理',
|
||||
path: RoutePath.WITHDRAW.LIST,
|
||||
code: 'withdraw_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './Recharge/Withdraw/List',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '用户账号',
|
||||
path: RoutePath.USER,
|
||||
code: 'user_account',
|
||||
access: 'normalRouteFilter',
|
||||
routes: [
|
||||
{
|
||||
path: RoutePath.USER,
|
||||
redirect: RoutePath.USER_LIST.LIST,
|
||||
hideInMenu: true,
|
||||
component: './Work/Edit',
|
||||
},
|
||||
{
|
||||
name: '用户账号管理',
|
||||
path: RoutePath.USER_LIST.LIST,
|
||||
code: 'user_account_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './User/List',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '系统设置',
|
||||
path: RoutePath.SYSTEM,
|
||||
code: 'system_setting',
|
||||
access: 'normalRouteFilter',
|
||||
routes: [
|
||||
{
|
||||
path: RoutePath.SYSTEM,
|
||||
redirect: RoutePath.ACCOUNT.LIST,
|
||||
hideInMenu: true,
|
||||
},
|
||||
{
|
||||
name: '账号管理',
|
||||
path: RoutePath.ACCOUNT.LIST,
|
||||
code: 'account_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './System/Account/List',
|
||||
},
|
||||
{
|
||||
name: '角色管理',
|
||||
path: RoutePath.ROLE.LIST,
|
||||
code: 'role_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './System/Role/List',
|
||||
},
|
||||
{
|
||||
name: '权限管理',
|
||||
path: RoutePath.PERMISSIONS.LIST,
|
||||
code: 'permission_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './System/Permissions/List',
|
||||
},
|
||||
{
|
||||
name: '通知管理',
|
||||
path: RoutePath.NOTICE.LIST,
|
||||
code: 'notice_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './System/Notice/List',
|
||||
},
|
||||
{
|
||||
name: '密钥管理',
|
||||
path: RoutePath.SECRET_KEY,
|
||||
code: 'secret_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './System/SecretKey',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '数据看板',
|
||||
access: 'normalRouteFilter',
|
||||
code: 'data_board',
|
||||
path: RoutePath.DATABOARD,
|
||||
routes: [
|
||||
{
|
||||
path: RoutePath.DATABOARD,
|
||||
redirect: RoutePath.COREDATA.LIST,
|
||||
hideInMenu: true,
|
||||
},
|
||||
{
|
||||
name: '核心看板',
|
||||
path: RoutePath.COREDATA.LIST,
|
||||
code: 'core_ata_board',
|
||||
access: 'normalRouteFilter',
|
||||
component: './DataBoard/CoreData/List',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'NFT',
|
||||
path: RoutePath.NFT,
|
||||
code: 'nft',
|
||||
access: 'normalRouteFilter',
|
||||
routes: [
|
||||
{
|
||||
path: RoutePath.NFT,
|
||||
redirect: RoutePath.NFTCONTRACT.LIST,
|
||||
hideInMenu: true,
|
||||
},
|
||||
{
|
||||
name: 'NFT合约管理',
|
||||
path: RoutePath.NFTCONTRACT.LIST,
|
||||
code: 'nft_contract_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './NFT/NftContract/List',
|
||||
},
|
||||
{
|
||||
name: 'NFT管理',
|
||||
path: RoutePath.NFTTOKEN.LIST,
|
||||
code: 'nft_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './NFT/NftToken/List',
|
||||
},
|
||||
{
|
||||
name: 'NFT交易',
|
||||
path: RoutePath.NFTTRADE.LIST,
|
||||
code: 'nft_trade_manage',
|
||||
access: 'normalRouteFilter',
|
||||
component: './NFT/NftTrade/List',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
redirect: RoutePath.WORK.LIST,
|
||||
redirect: RoutePath.RECORD.LIST,
|
||||
},
|
||||
|
||||
{
|
||||
component: './404',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,11 +1,62 @@
|
|||
const SETTING = '/setting';
|
||||
const RECHARGE = '/recharge';
|
||||
const USER = '/user';
|
||||
const SYSTEM = '/system';
|
||||
const DATABOARD = '/databoard';
|
||||
const NFT = '/nft';
|
||||
const RoutePath = {
|
||||
LOGIN: '/login',
|
||||
SETTING: SETTING,
|
||||
WORK: {
|
||||
LIST: `${SETTING}/work`,
|
||||
EDIT: `${SETTING}/work/edit`,
|
||||
RECHARGE: RECHARGE,
|
||||
RECORD: {
|
||||
LIST: `${RECHARGE}/record`,
|
||||
},
|
||||
WALLET: {
|
||||
LIST: `${RECHARGE}/wallet`,
|
||||
},
|
||||
COIN_TYPE: {
|
||||
LIST: `${RECHARGE}/coin_type`,
|
||||
},
|
||||
WITHDRAW: {
|
||||
LIST: `${RECHARGE}/withdraw`,
|
||||
},
|
||||
USER: USER,
|
||||
USER_LIST: {
|
||||
LIST: `${USER}/user`,
|
||||
},
|
||||
SYSTEM: SYSTEM,
|
||||
ACCOUNT: {
|
||||
LIST: `${SYSTEM}/account`,
|
||||
},
|
||||
ROLE: {
|
||||
LIST: `${SYSTEM}/role`,
|
||||
},
|
||||
PERMISSIONS: {
|
||||
LIST: `${SYSTEM}/permissions`,
|
||||
},
|
||||
NOTICE: {
|
||||
LIST: `${SYSTEM}/notice`,
|
||||
},
|
||||
NFT: NFT,
|
||||
NFTCONTRACT: {
|
||||
LIST: `${NFT}/nftcontract`,
|
||||
},
|
||||
NFTTOKEN: {
|
||||
LIST: `${NFT}/nfttoken`,
|
||||
},
|
||||
NFTTRADE: {
|
||||
LIST: `${NFT}/NFT_trade`,
|
||||
},
|
||||
DATABOARD: DATABOARD,
|
||||
COREDATA: {
|
||||
LIST: `${DATABOARD}/coredata`,
|
||||
},
|
||||
|
||||
SECRET_KEY: `${SYSTEM}/secret_key`,
|
||||
// SETTING: SETTING,
|
||||
// WORK: {
|
||||
// LIST: `${SETTING}/work`,
|
||||
// EDIT: `${SETTING}/work/edit`,
|
||||
// },
|
||||
};
|
||||
|
||||
export default RoutePath;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
};
|
||||
|
|
@ -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,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import request from '@/utils/request';
|
||||
// 获取核心列表数据
|
||||
export const getCoreData = (data) => {
|
||||
return request.request({
|
||||
url: '/coredata/get',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
// 数据库列表
|
||||
export const getListData = (data) => {
|
||||
return request.request({
|
||||
url: '/data/get',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -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,
|
||||
});
|
||||
};
|
||||
|
|
@ -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,
|
||||
});
|
||||
};
|
||||
|
|
@ -7,3 +7,18 @@ export const login = (data) => {
|
|||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
* @param data
|
||||
* password 用户旧密码
|
||||
* new_password 用户新密码
|
||||
* @returns
|
||||
*/
|
||||
export const modifyPassword = (data) => {
|
||||
return request.request({
|
||||
url: '/admin/update',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
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,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取NFT列表
|
||||
* @param {object} params
|
||||
*
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const getNFTList = (params) => {
|
||||
return request.request({
|
||||
url: '/nft/get',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建完NFT后通知后端
|
||||
* @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 getSignature = (data) => {
|
||||
return request.request({
|
||||
url: '/nft/sign/get',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查assetID是否存在
|
||||
* @param {object} data
|
||||
*
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const checkAssetID = (data) => {
|
||||
return request.request({
|
||||
url: '/nft/assetid/check',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新NFT信息
|
||||
* @param {object} data
|
||||
*
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const updateNFTInfo = (data) => {
|
||||
return request.request({
|
||||
url: '/nft/update',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取代币种类列表
|
||||
* @param {object} params
|
||||
* type 代币种类
|
||||
* @returns {array} dat
|
||||
* name 游戏币名称
|
||||
* type 游戏币类型
|
||||
* usdt_price 游戏货币与usdt的比例
|
||||
* eth_price 游戏货币与eth的比例
|
||||
*/
|
||||
export const getCoinTypeList = (params) => {
|
||||
return request.request({
|
||||
url: '/erc20/get',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取代币种类列表
|
||||
* @param {object} params
|
||||
* name 游戏币名称
|
||||
* usdt_price 游戏货币与usdt的比例
|
||||
* eth_price 游戏货币与eth的比例
|
||||
* num 代币数量
|
||||
* @returns {object} data
|
||||
*/
|
||||
export const addCoinType = (data) => {
|
||||
return request.request({
|
||||
url: '/erc20/create',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取代币种类列表
|
||||
* @param {object} params
|
||||
* name 游戏币名称
|
||||
* type 游戏币类型
|
||||
* usdt_price 游戏货币与usdt的比例
|
||||
* eth_price 游戏货币与eth的比例
|
||||
* @returns {object} data
|
||||
*/
|
||||
export const modifyCoinType = (data) => {
|
||||
return request.request({
|
||||
url: '/erc20/update',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取充值列表
|
||||
* @param {object} data
|
||||
* page 页码
|
||||
* pageSize 页码大小
|
||||
* start_time 开始时间
|
||||
* end_time 结束时间
|
||||
* @returns {array} data
|
||||
* type 游戏币类型
|
||||
* address 地址
|
||||
*/
|
||||
export const getRecordList = (data) => {
|
||||
return request.request({
|
||||
url: '/recharge/record',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取开发商收款地址列表
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
* type 游戏币类型
|
||||
* address 地址
|
||||
*/
|
||||
export const getAddressList = (params) => {
|
||||
return request.request({
|
||||
url: '/wallet/get',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建开发商收款地址
|
||||
* @param {Object} data
|
||||
* type 游戏币类型
|
||||
* address 地址(不传则后台生成)
|
||||
* @returns
|
||||
*/
|
||||
export const createAddress = (data) => {
|
||||
return request.request({
|
||||
url: '/wallet/create',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除开发商收款地址
|
||||
* @param {Object} data
|
||||
* address 地址
|
||||
* @returns
|
||||
*/
|
||||
export const deleteAddress = (data) => {
|
||||
return request.request({
|
||||
url: '/wallet/delete',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改开发商收款地址
|
||||
* @param {Object} data
|
||||
* address 旧地址
|
||||
* type 游戏币类型
|
||||
* new_address 新地址
|
||||
* @returns
|
||||
*/
|
||||
export const modifyAddress = (data) => {
|
||||
return request.request({
|
||||
url: '/wallet/update',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取提现列表
|
||||
* @param {object} params
|
||||
*
|
||||
* @returns {array} data
|
||||
* uuid 提现订单id
|
||||
* to_addrss 接收地址
|
||||
* from_address 发送地址
|
||||
* time 提现时间
|
||||
* price 提现金额
|
||||
*/
|
||||
export const getWithdrawList = (data) => {
|
||||
return request.request({
|
||||
url: '/withdrawal/get',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 通过提现申请
|
||||
* @param {object} params
|
||||
* uuid 提现订单id
|
||||
* @returns {object} data
|
||||
*/
|
||||
export const solveWithdraw = (data) => {
|
||||
return request.request({
|
||||
url: 'withdrawal/update',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取后台用户列表
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const getAccountList = (params) => {
|
||||
return request.request({
|
||||
url: '/user/get',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 添加后台用户
|
||||
* @param {object} data
|
||||
* name 账号名称
|
||||
* password 密码
|
||||
* role 权限角色
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const addUser = (data) => {
|
||||
return request.request({
|
||||
url: '/user/create',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改后台用户
|
||||
* @param {object} data
|
||||
* name 账号名称
|
||||
* password 密码
|
||||
* role 权限角色
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const updateUser = (data) => {
|
||||
return request.request({
|
||||
url: '/user/update',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改后台用户状态
|
||||
* @param {object} data
|
||||
* name 账号名称
|
||||
* status 用户状态
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const changeUserStatus = (data) => {
|
||||
return request.request({
|
||||
url: '/user/status',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除后台用户
|
||||
* @param {object} data
|
||||
* name 用户名
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const deleteUser = (data) => {
|
||||
return request.request({
|
||||
url: '/user/delete',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取后台用户权限
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const getAccounPermission = (params) => {
|
||||
return request.request({
|
||||
url: '/user/role/get',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取通知管理列表
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const getNoticeList = (params) => {
|
||||
return request.request({
|
||||
url: '/notice/get',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建通知
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const createNotice = (data) => {
|
||||
return request.request({
|
||||
url: '/notice/create',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 配置通知
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const updateNotice = (data) => {
|
||||
return request.request({
|
||||
url: '/notice/update',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 配置通知
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const deleteNotice = (data) => {
|
||||
return request.request({
|
||||
url: '/notice/delete',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取后台权限列表
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const getPermission = (params) => {
|
||||
return request.request({
|
||||
url: '/permission/get',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新后台权限列表
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const upsertPermission = (data) => {
|
||||
return request.request({
|
||||
url: '/permission/upsert',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取后台角色列表
|
||||
* @param {object} params
|
||||
* @returns {array} data
|
||||
* role_name 角色名称
|
||||
* role 角色类型
|
||||
*/
|
||||
export const getRoleList = (params) => {
|
||||
return request.request({
|
||||
url: '/role/get',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建后台角色
|
||||
* @param {object} params
|
||||
* role_name 角色名称
|
||||
* remark 备注
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const createRole = (data) => {
|
||||
return request.request({
|
||||
url: '/role/create',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新后台角色
|
||||
* @param {object} params
|
||||
* role_name 角色名称
|
||||
* remark 备注
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const updateRole = (data) => {
|
||||
return request.request({
|
||||
url: '/role/update',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除后台角色
|
||||
* @param {object} params
|
||||
* role 角色类型
|
||||
* @returns {array} data
|
||||
*/
|
||||
export const deleteRole = (data) => {
|
||||
return request.request({
|
||||
url: '/role/delete',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取密钥
|
||||
* @param {object} params
|
||||
* @returns {array} data 密钥
|
||||
*/
|
||||
export const getSecretKey = () => {
|
||||
return request.request({
|
||||
url: '/key/get',
|
||||
method: 'get',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建密钥
|
||||
* @param {object} data
|
||||
* @returns {array} data 密钥
|
||||
*/
|
||||
export const createSecretKey = (data) => {
|
||||
return request.request({
|
||||
url: '/key/create',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取AppID
|
||||
* @param {object} params
|
||||
* @returns {array} data 密钥
|
||||
*/
|
||||
export const getAppID = () => {
|
||||
return request.request({
|
||||
url: '/appid/get',
|
||||
method: 'get',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建AppID
|
||||
* @param {object} data
|
||||
* @returns {array} data 密钥
|
||||
*/
|
||||
export const createAppID = (data) => {
|
||||
return request.request({
|
||||
url: '/appid/create',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取后台角色列表
|
||||
* @param {object} data
|
||||
* @returns {array} data
|
||||
* role_name 角色名称
|
||||
* role 角色类型
|
||||
*/
|
||||
export const getUserList = (data) => {
|
||||
return request.request({
|
||||
url: '/account/get',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import BigNumber from 'bignumber.js';
|
||||
|
||||
export const BIG_ZERO = new BigNumber(0);
|
||||
export const BIG_ONE = new BigNumber(1);
|
||||
export const BIG_NINE = new BigNumber(9);
|
||||
export const BIG_TEN = new BigNumber(10);
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import BigNumber from 'bignumber.js';
|
||||
import { BIG_TEN } from './bigNumber';
|
||||
|
||||
export const getBalanceAmount = (amount: BigNumber, decimals = 18) => {
|
||||
return new BigNumber(amount).dividedBy(BIG_TEN.pow(decimals));
|
||||
};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export const getData = async (fetch: any) => {
|
||||
const res = (await fetch()) || {};
|
||||
return res.data;
|
||||
};
|
||||
|
|
@ -6,13 +6,13 @@ import { CACHE_TOKEN } from '@/constants/cacheKey';
|
|||
|
||||
// create an axios instance
|
||||
const request = axios.create({
|
||||
baseURL: '', //
|
||||
baseURL: '/tbg/api/v1', //
|
||||
timeout: 10000, // request timeout
|
||||
});
|
||||
// request interceptor
|
||||
request.interceptors.request.use(
|
||||
(memo: any) => {
|
||||
memo.headers.token = localStorage.getItem(CACHE_TOKEN);
|
||||
memo.headers.Authorization = localStorage.getItem(CACHE_TOKEN);
|
||||
return memo;
|
||||
},
|
||||
(error) => {
|
||||
|
|
@ -24,7 +24,7 @@ request.interceptors.response.use(
|
|||
(response) => {
|
||||
const res: any = response.data;
|
||||
if (res.code !== 200) {
|
||||
if (res.code === 401) {
|
||||
if (res.code === 401 || res.code === 10001) {
|
||||
notification.error({
|
||||
message: '错误信息',
|
||||
description: '登录失效',
|
||||
|
|
|
|||
|
|
@ -5,12 +5,11 @@ export const fetchTableData = async (
|
|||
formatObj: any = {},
|
||||
) => {
|
||||
params.page = params.current;
|
||||
params.num = params.pageSize;
|
||||
params.size = params.pageSize;
|
||||
delete params.current;
|
||||
delete params.pageSize;
|
||||
const res = (await fetch(params)) || {};
|
||||
const data = res.data;
|
||||
|
||||
const data = res.items || [];
|
||||
data?.forEach((n: any) => {
|
||||
for (const key in formatObj) {
|
||||
n[key] = n[formatObj[key]];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
import Web3 from 'web3';
|
||||
import detectEthereumProvider from '@metamask/detect-provider';
|
||||
import { message } from 'antd';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import abi from '@/constants/abi';
|
||||
|
||||
let provider: any;
|
||||
|
||||
export const web3 = new Web3();
|
||||
if (typeof window.ethereum !== 'undefined') {
|
||||
web3.eth.defaultAccount = (window.ethereum as any).selectedAddress;
|
||||
}
|
||||
|
||||
export async function initWeb3() {
|
||||
provider = await detectEthereumProvider();
|
||||
|
||||
if (!provider) {
|
||||
message.warning('请安装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 as any)._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, gas: 3000000 }, function (error, transactionHash) {
|
||||
if (!error) {
|
||||
console.log('transactionHash is ' + transactionHash);
|
||||
} else {
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// NFT创建
|
||||
/**
|
||||
*
|
||||
* @param abi 合约ABI
|
||||
* @param address 合约地址
|
||||
* @param toAddress 转账地址
|
||||
* @param sign 签名
|
||||
*/
|
||||
|
||||
export async function NFTMint(params: any) {
|
||||
if (params.toAddress == '' || params.toAddress == null || params.toAddress == undefined) {
|
||||
params.toAddress = web3.eth.defaultAccount;
|
||||
}
|
||||
let tx_hash = '';
|
||||
const contract = new web3.eth.Contract(eval('(' + params.abi + ')'), params.address);
|
||||
await contract.methods
|
||||
.Mint(params.toAddress, params.sign)
|
||||
.send({ from: web3.eth.defaultAccount, gas: 3000000 }, function (error, transactionHash) {
|
||||
if (!error) {
|
||||
tx_hash = transactionHash;
|
||||
} else {
|
||||
console.log('error = ', error);
|
||||
return tx_hash;
|
||||
}
|
||||
});
|
||||
return tx_hash;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
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>
|
||||
<h1>{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;
|
||||
|
|
@ -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;
|
||||
Loading…
Reference in New Issue