Browse Source

first

master
mac 6 months ago
parent
commit
e1228b5759
  1. BIN
      .DS_Store
  2. 2
      .env
  3. 48112
      package-lock.json
  4. 5
      package.json
  5. 2
      src/App.tsx
  6. 27
      src/api/index.ts
  7. 5
      src/assets/js/publicFunc.ts
  8. 3
      src/components/MyTable/index.tsx
  9. 2
      src/components/TabPanes/index.tsx
  10. 10
      src/config/index.ts
  11. 26
      src/package/SimpleTrade/api/admin-permission.ts
  12. 33
      src/package/SimpleTrade/api/admin-user.ts
  13. 105
      src/package/SimpleTrade/api/client.ts
  14. 40
      src/package/SimpleTrade/api/index.ts
  15. 68
      src/package/SimpleTrade/config/layout.ts
  16. 117
      src/package/SimpleTrade/config/menu.ts
  17. 53
      src/package/SimpleTrade/pages/admininvite/chart/data.ts
  18. 131
      src/package/SimpleTrade/pages/admininvite/chart/index.tsx
  19. 268
      src/package/SimpleTrade/pages/adminpermission/list/index.tsx
  20. 43
      src/package/SimpleTrade/pages/adminupload/uploadapk/index.tsx
  21. 3
      src/package/SimpleTrade/pages/adminuser/adminuser.less
  22. 211
      src/package/SimpleTrade/pages/adminuser/edit/index.tsx
  23. 250
      src/package/SimpleTrade/pages/adminuser/list/index.tsx
  24. 61
      src/package/SimpleTrade/pages/client/mt4history/index.tsx
  25. 110
      src/package/SimpleTrade/pages/client/mt4order/index.tsx
  26. 47
      src/package/SimpleTrade/pages/client/mt4settlementorder/index.tsx
  27. 236
      src/package/SimpleTrade/pages/client/user/index.tsx
  28. 128
      src/package/SimpleTrade/pages/client/withdraw/index.tsx
  29. 352
      src/package/SimpleTrade/pages/home/index.tsx
  30. 177
      src/package/SimpleTrade/route/routes.ts
  31. 38
      src/package/SimpleTrade/types/enum.ts
  32. 0
      src/pages/home/index.css
  33. 0
      src/pages/home/index.less
  34. 114
      src/pages/home/index.tsx
  35. 0
      src/pages/home/vector.png
  36. 75
      src/pages/interest/index.tsx
  37. 2
      src/pages/login/index.tsx
  38. 120
      src/pages/order/index.tsx
  39. 52
      src/pages/recharge/index.tsx
  40. 92
      src/pages/withdraw/index.tsx
  41. 60
      src/route/routes.ts
  42. 4
      src/utils/axios.ts
  43. 13420
      yarn.lock

BIN
.DS_Store

2
.env

@ -0,0 +1,2 @@
REACT_APP_BASE_URL=http://192.168.124.20:3009/api/v1
SKIP_PREFLIGHT_CHECK=true

48112
package-lock.json
File diff suppressed because it is too large
View File

5
package.json

@ -37,14 +37,13 @@
"redux": "^4.0.4",
"redux-persist": "^6.0.0",
"redux-promise": "^0.6.0",
"typescript": "^3.8.3"
"typescript": "^4.8.3"
},
"scripts": {
"start": "cross-env PORT=3000 react-app-rewired start",
"test": "react-app-rewired test",
"build": "react-app-rewired build",
"deploy:dev": "npm run build && scp -r ./build/* vps:/home/ubuntu/pzy/simple",
"deploy:prod": "npm run build && scp -r ./build/* metatrader_prod:/data/wwwroot/admin-simple"
"deploy:dev": "npm run build && scp -r ./build/* vps:/home/ubuntu/pzy/filpool"
},
"eslintConfig": {
"extends": "react-app"

2
src/App.tsx

@ -9,7 +9,7 @@ const App: FC = () => (
<Route
path="/"
key="container"
render={(props: unknown) => <Container {...props} />}
render={(props:any) => <Container {...props} />}
/>
</Router>
)

27
src/api/index.ts

@ -9,5 +9,30 @@ export default {
// 登录
login(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/login', params)
}
},
home_info(): Promise<CommonObjectType<string>> {
return $axios.post('/admin/index')
},
withdraw_list(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/withdraw/list', params)
},
recharge_list(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/deposit/list', params)
},
order_list(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/product/list', params)
},
income_list(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/income/list', params)
},
withdraw(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/withdraw', params)
},
}

5
src/assets/js/publicFunc.ts

@ -297,7 +297,10 @@ export const setUserInfo = (
oldToken?: string
) => {
const { permission, userName, token } = userInfo
const permissionArray = permission.reduce(
console.log(permission);
const permissionArray = permission.reduce(
(prev: CommonObjectType<string>[], next: CommonObjectType<string>) => [
...prev,
next.code

3
src/components/MyTable/index.tsx

@ -116,6 +116,9 @@ const MyTable: FC<TableProps> = forwardRef(
tableData = validData;
total = validData.length;
}
console.log(validData);
if (validData.rows) {
tableData = validData.rows;
total = validData.total;

2
src/components/TabPanes/index.tsx

@ -8,7 +8,7 @@ import React, {
} from 'react'
import { useHistory, useLocation } from 'react-router-dom'
import { Tabs, Alert, Dropdown, Menu } from 'antd'
import Home from '@/package/SimpleTrade/pages/home'
import Home from '@/pages/home'
import { getKeyName, isAuthorized } from '@/assets/js/publicFunc'
import { SyncOutlined } from '@ant-design/icons'
import { connect } from 'react-redux'

10
src/config/index.ts

@ -1,10 +0,0 @@
export const httpIp = {
simpleTradeKey: {
dev: 'http://125.94.244.254:30303/api/v1',
prod: 'https://simpletrade.site/api/v1'
}
}
export const getBaseURL = () => {
return httpIp.simpleTradeKey.dev
}

26
src/package/SimpleTrade/api/admin-permission.ts

@ -1,26 +0,0 @@
import $axios from '@/utils/axios'
export default {
getAdminPermissions(params?: object): Promise<CommonObjectType<string>> {
return $axios.get('/admin/adminpermissions', params)
},
getAdminPermission(id: number | string): Promise<CommonObjectType<string>> {
return $axios.get(`/admin/adminpermissions/${id}`)
},
addAdminPermission(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/adminpermissions', params)
},
updateAdminPermission(
id: number,
params: object
): Promise<CommonObjectType<string>> {
return $axios.put(`/admin/adminpermissions/${id}`, params)
},
deleteAdminPermission(params: object): Promise<CommonObjectType<string>> {
return $axios.delete('/admin/adminpermissions', params)
}
}

33
src/package/SimpleTrade/api/admin-user.ts

@ -1,33 +0,0 @@
import $axios from '@/utils/axios'
export default {
getAdminUserList(params?: object): Promise<CommonObjectType<string>> {
return $axios.get('/admin/adminusers', params)
},
getAdminUser(id: number | string): Promise<CommonObjectType<string>> {
return $axios.get(`/admin/adminusers/${id}`)
},
addAdminUser(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/adminusers', params)
},
updateAdminUser(
id: number | string,
params: object
): Promise<CommonObjectType<string>> {
return $axios.put(`/admin/adminusers/${id}`, params)
},
updateAdminUserPwd(
id: number,
params: object
): Promise<CommonObjectType<string>> {
return $axios.put(`/admin/adminusers/pwd/${id}`, params)
},
deleteAdminUser(params: object): Promise<CommonObjectType<string>> {
return $axios.delete('/admin/adminusers', params)
}
}

105
src/package/SimpleTrade/api/client.ts

@ -1,105 +0,0 @@
import $axios from '@/utils/axios'
export default {
/**
* @description
* @param {page}
* @param {page_size}
*/
user_list(params?: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/user/list', params);
},
/**
* @description
* @param {page}
* @param {page_size}
*/
withdraw_list(params?: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/chain/withdraw', params);
},
/**
* @description
* @param {page}
* @param {page_size}
*/
recharge_list(params?: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/chain/deposit', params);
},
/**
* @description
*/
user_relation(): Promise<CommonObjectType<string>> {
return $axios.post('/admin/user/relation');
},
/**
* @description
*/
add_relation(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/user/relation/add', params);
},
/**
* @description MT4历史记录
*/
mt4_history(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/forex/mt4/history', params);
},
/**
* @description MT4下单列表
*/
mt4_order_list(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/forex/order/list', params);
},
/**
* @description MT4结算列表
*/
mt4_settle_list(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/forex/settle/list', params);
},
/**
* @description
*/
up_levle(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/debug/upLevel', params);
},
/**
* @description
*/
add_debug_user(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/debug/addDebugUser', params);
},
/**
* @description
*/
withdraw_check(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/chain/withdraw/check', params);
},
/**
* @description
*/
close_order(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/forex/orderClose', params);
},
/**
* @description
*/
user_rename(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/user/upRemark', params);
},
/**
* @description
*/
user_deactivate(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/user/upDeactivate', params);
}
}

40
src/package/SimpleTrade/api/index.ts

@ -1,40 +0,0 @@
import $axios from '@/utils/axios'
export default {
// 获取数据
getList(params?: object): Promise<CommonObjectType<string>> {
return $axios.get('https://randomuser.me/api', params)
},
// 登录
login(params: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/login', params)
},
// 首页用户统计
user_statistics(): Promise<CommonObjectType<string>> {
return $axios.post('/admin/userAmount')
},
// 首页充值提现统计
recharge_withdraw_statistics(): Promise<CommonObjectType<string>> {
return $axios.post('/admin/depositWithdrawal', { type: 1 })
},
// 首页周期充值提现统计
week_recharge_withdraw_statistics(
params: object
): Promise<CommonObjectType<string>> {
return $axios.post('/admin/depositWithdrawal', params)
},
/**
* @description
* @param {number} end_time
* @param {number} start_time
* @param {number} type 1. 2.
*/
transaction_statistics(params?: object): Promise<CommonObjectType<string>> {
return $axios.post('/admin/prodruct', params)
}
}

68
src/package/SimpleTrade/config/layout.ts

@ -1,68 +0,0 @@
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 3 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 17 }
}
}
const wrapperCol = {
xs: { span: 24, offset: 0 },
sm: { span: 16, offset: 3 }
}
const modalLayoutSm = {
labelCol: {
xs: { span: 4 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 20 },
sm: { span: 20 }
}
}
const modalLayoutSm5 = {
labelCol: {
xs: { span: 5 },
sm: { span: 5 }
},
wrapperCol: {
xs: { span: 20 },
sm: { span: 20 }
}
}
const modalLayoutMd = {
labelCol: {
xs: { span: 6 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 18 },
sm: { span: 18 }
}
}
const modalLayoutLg = {
labelCol: {
xs: { span: 8 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 16 },
sm: { span: 16 }
}
}
export {
formItemLayout,
wrapperCol,
modalLayoutSm,
modalLayoutSm5,
modalLayoutMd,
modalLayoutLg
}

117
src/package/SimpleTrade/config/menu.ts

@ -1,117 +0,0 @@
import { HomeOutlined, UserOutlined, AuditOutlined } from '@ant-design/icons'
const menus = [
{
path: '/',
name: '首页',
key: 'home',
icon: HomeOutlined,
routes: [],
},
{
path: '/adminuser',
name: '用户管理',
key: 'adminuser',
type: 'subMenu',
icon: UserOutlined,
iconfont: 'icon-xiaoshouzongjian',
routes: [
{
path: '/adminuser/list',
name: '用户列表',
key: 'adminuser:list:view'
}
]
},
{
path: '/adminpermission',
name: '权限管理',
key: 'adminpermission',
type: 'subMenu',
icon: AuditOutlined,
routes: [
{
path: '/adminpermission/list',
name: '权限列表',
key: 'adminpermission:list:view',
remove: true
}
]
},
{
path: '/admininvite',
name: '邀请',
key: 'admininvite',
type: 'subMenu',
icon: AuditOutlined,
routes: [
{
path: '/admininvite/chart',
name: '关联图',
key: 'admininvite:list:chart'
}
]
},
{
path: '/adminupload',
name: '上传管理',
key: 'adminupload',
type: 'subMenu',
icon: AuditOutlined,
routes: [
{
path: '/adminupload/uploadapk',
name: '上传APK',
key: 'admininvite:list:uploadapk'
}
]
},
{
path: '/client',
name: '客户端',
key: 'client',
type: 'subMenu',
icon: AuditOutlined,
routes: [
{
path: '/client/userlist',
name: '用户列表',
exact: true,
key: 'client:userlist:view',
remove: true
},
{
path: '/client/recharge',
name: '充值记录',
exact: true,
key: 'client:recharge:view',
},
{
path: '/client/withdraw',
name: '提现记录',
exact: true,
key: 'client:withdraw:view',
},
{
path: '/client/mt4history',
name: 'MT4历史记录',
exact: true,
key: 'client:mt4history:view',
},
{
path: '/client/mt4order',
name: 'MT4订单列表',
exact: true,
key: 'client:mt4order:view',
},
{
path: '/client/mt4settlementorder',
name: 'MT4结算订单列表',
exact: true,
key: 'client:mt4settlementorder:view',
}
]
}
]
export default menus

53
src/package/SimpleTrade/pages/admininvite/chart/data.ts

@ -1,53 +0,0 @@
import dagre from 'dagre';
const edgeType = 'smoothstep';
export const flattenTree = (tree) => {
let stack = [tree];
let nodes = [];
let edges = [];
while (stack.length > 0) {
let node = stack.pop();
nodes.push({ id: node.id, data: { ...node.data, label: `${node.data.name}` }, position: node.position });
if (node.children && node.children.length > 0) {
node.children.map(item => {
edges.push({ source: node.id, target: item.id, id: item.id, type: edgeType, animated: true });
stack.unshift(item);
});
};
};
return { nodes, edges };
};
export const getLayoutedElements = (nodes, edges, direction = 'TB') => {
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
const nodeWidth = 172;
const nodeHeight = 36;
const isHorizontal = direction === 'LR';
dagreGraph.setGraph({ rankdir: direction });
nodes.forEach((node: any) => {
dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
});
edges.forEach((edge: any) => {
dagreGraph.setEdge(edge.source, edge.target);
});
dagre.layout(dagreGraph);
nodes.forEach((node: any) => {
const nodeWithPosition = dagreGraph.node(node.id);
node.targetPosition = isHorizontal ? 'left' : 'top';
node.sourcePosition = isHorizontal ? 'right' : 'bottom';
node.position = {
x: nodeWithPosition.x - nodeWidth / 2,
y: nodeWithPosition.y - nodeHeight / 2,
};
return node;
});
return { nodes, edges };
};

131
src/package/SimpleTrade/pages/admininvite/chart/index.tsx

@ -1,131 +0,0 @@
import React, { useCallback, FC, useEffect, useState, useRef } from 'react';
import ReactFlow, {
addEdge,
ConnectionLineType,
useNodesState,
useEdgesState,
Controls
} from 'react-flow-renderer';
import { getLayoutedElements, flattenTree } from './data';
import { Button, Input, Modal, notification } from 'antd';
import clientApi from '@/package/SimpleTrade/api/client';
const InviteChart: FC = () => {
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const [isOpenModal, setIsOpenModal] = useState(false)
const [loading, setLoading] = useState(false)
const [inviteCode, setInviteCode] = useState('')
const [address, setAddress] = useState('')
const onConnect = useCallback(
(params: any) => {
setEdges((eds) =>
addEdge({ ...params, type: ConnectionLineType.SmoothStep, animated: true }, eds)
)
},
[]
);
const onLayout = useCallback(
(direction: any) => {
const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(
nodes,
edges,
direction
);
setNodes([...layoutedNodes]);
setEdges([...layoutedEdges]);
},
[nodes, edges]
);
// 获取节点
const getNodes = async () => {
const res: any = await clientApi.user_relation();
if (res.code === 0 && Object.keys(res.data).length > 0) {
let { nodes, edges } = flattenTree(res.data) // 处理节点及连接线
let { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(nodes, edges)//计算节点位置
setNodes(layoutedNodes)
setEdges(layoutedEdges)
};
};
// 添加
const addNodes = async () => {
if (!address) {
notification.error({
message: '请输入地址'
})
return;
}
setLoading(true)
try {
const res: any = await clientApi.add_debug_user({
address,
invite_code: inviteCode
});
setLoading(false)
if (res.code === 0) {
notification.success({
message: '创建成功'
})
getNodes()
setIsOpenModal(false)
// let { nodes, edges } = flattenTree(res.data) // 处理节点及连接线
// let { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(nodes, edges)//计算节点位置
// setNodes(layoutedNodes)
// setEdges(layoutedEdges)
}
} catch (error) {
setLoading(false)
}
}
useEffect(() => {
getNodes();
}, []);
useEffect(() => {
if (!isOpenModal) {
setInviteCode('')
setAddress('')
}
}, [isOpenModal])
return (
<div>
<Button type='primary' onClick={() => onLayout('TB')}></Button>
<Button type='primary' onClick={() => onLayout('LR')}></Button>
<div style={{ width: '100%', height: window.innerHeight - 165 }}>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
connectionLineType={ConnectionLineType.SmoothStep}
fitView
onNodeClick={(e, node) => {
setInviteCode(node.data.invite_code)
setIsOpenModal(true)
}}
>
<Controls />
</ReactFlow>
</div>
<Modal
visible={isOpenModal}
onCancel={() => setIsOpenModal(false)}
onOk={addNodes}
title="创建模拟账号"
confirmLoading={loading}
>
<Input value={address} onChange={e => setAddress(e.target.value)} placeholder="请输入地址" />
</Modal>
</div>
);
};
export default InviteChart;

268
src/package/SimpleTrade/pages/adminpermission/list/index.tsx

@ -1,268 +0,0 @@
import React, { FC, useEffect, useRef, useState } from 'react'
import {
isAuthorized,
makeTree,
makeTreeSelectData
} from '@/assets/js/publicFunc'
import {
Button,
Table,
Modal,
Form,
Switch,
Input,
TreeSelect,
message,
Spin
} from 'antd'
import { modalLayoutSm } from '@/package/SimpleTrade/config/layout'
import AdminPermissionApi from '@/package/SimpleTrade/api/admin-permission'
import SearchForm from '@/components/SearchForm'
interface AdminPermission {
id: number;
name: string;
code: string;
isHelp: boolean;
parentId: number;
updateTime: string;
createTime: string;
}
const AdminPermissionList: FC = () => {
const [loading, setLoading] = useState<boolean>(false)
const [btnLoading, setBtnLoading] = useState<boolean>(false)
const [visible, setVisible] = useState<boolean>(false)
const [title, setTitle] = useState<string>('新增权限')
const [permissionId, setPermissionId] = useState<number>(0)
const [permissionList, setPermissionList] = useState<Array<any>>([])
const [treeSelectList, setTreeSelectList] = useState<Array<any>>([])
const [form] = Form.useForm()
const { setFieldsValue, getFieldsValue, resetFields } = form
const searchForm = useRef()
const getAdminPermissions = (search: object = {}) => {
AdminPermissionApi.getAdminPermissions(search).then((res: any) => {
const permissions = res.data ? res.data : []
const adminPermissionsTree = makeTree(permissions)
setPermissionList(adminPermissionsTree)
})
}
const setTreeSelectData = () => {
const root = [{ value: 0, title: '根所属' }]
const treeSelectData = root.concat(
makeTreeSelectData(permissionList, 'id', 'name')
)
setTreeSelectList(treeSelectData)
}
useEffect(() => {
getAdminPermissions()
// eslint-disable-next-line
}, [])
const add = () => {
resetFields()
setPermissionId(0)
setVisible(true)
setTitle('新增权限')
setFieldsValue({ parentId: 0, code: '' })
setTreeSelectData()
}
const edit = (record: any) => {
setPermissionId(record.id)
setFieldsValue({ ...record })
setVisible(true)
setTitle('编辑权限')
setTreeSelectData()
}
const handleSearch = (values) => {
getAdminPermissions(values)
}
const cancelModel = () => {
setVisible(false)
}
const delAdminPermission = (record: AdminPermission) => {
setBtnLoading(true)
const ids = [record.id]
AdminPermissionApi.deleteAdminPermission(ids)
.then((res) => {
message.success(res.message)
getAdminPermissions()
})
.finally(() => {
setBtnLoading(false)
})
}
const handleSubmit = () => {
setLoading(true)
if (permissionId) {
AdminPermissionApi.updateAdminPermission(permissionId, getFieldsValue())
.then((res) => {
message.success(res.message)
setVisible(false)
getAdminPermissions()
})
.finally(() => {
setLoading(false)
})
} else {
AdminPermissionApi.addAdminPermission(getFieldsValue())
.then((res) => {
message.success(res.message)
setVisible(false)
getAdminPermissions()
})
.finally(() => {
setLoading(false)
})
}
}
const AddBtn = () => (
<Button className="fr" onClick={add} type="primary">
</Button>
)
const columns: any = [
{
title: '名称',
dataIndex: 'name'
},
{
title: '权限标识',
dataIndex: 'code'
},
{
title: '操作',
dataIndex: 'operations',
align: 'center',
render: (text, record) => (
<>
{isAuthorized('adminpermission:list:del') && (
<Button
className="btn mr-5"
onClick={() => delAdminPermission(record)}
size="small"
type="primary"
loading={btnLoading}
danger
>
</Button>
)}
{isAuthorized('adminpermission:list:edit') && (
<Button
className="btn"
onClick={() => edit(record)}
size="small"
type="primary"
>
</Button>
)}
</>
)
}
]
// 搜索栏配置项
const searchConfigList = [
{
key: 'name',
slot: <Input placeholder="名称" allowClear />,
initialValue: ''
}
]
const nameValidator = (rule, value) => {
if (!value) {
return Promise.reject(new Error('请输入名称'))
}
return Promise.resolve()
}
const codeValidator = (rule, value) => {
const parentId = form.getFieldValue('parentId')
const isHelp = form.getFieldValue('isHelp')
if (isHelp) {
return Promise.resolve()
}
if (!parentId && !value) {
return Promise.reject(new Error('请输入权限标识'))
}
if (!parentId && !/^[a-zA-Z0-9:]+$/.test(value)) {
return Promise.reject(new Error('权限标识格式不正确'))
}
return Promise.resolve()
}
return (
<>
{isAuthorized('adminpermission:list:add') && <AddBtn />}
{visible && (
<Modal
title={title}
visible={visible}
onCancel={cancelModel}
footer={null}
>
<Spin spinning={loading}>
<Form {...modalLayoutSm} form={form} onFinish={handleSubmit}>
<Form.Item label="所属" name="parentId">
<TreeSelect
style={{ width: '100%' }}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={treeSelectList}
placeholder="请选择"
/>
</Form.Item>
<Form.Item label="辅助信息" name="isHelp" valuePropName="checked">
<Switch />
</Form.Item>
<Form.Item
label="名称"
name="name"
rules={[{ validator: nameValidator }]}
>
<Input placeholder="请输入名称" />
</Form.Item>
<Form.Item
label="权限标识"
name="code"
rules={[{ validator: codeValidator }]}
>
<Input placeholder="格式(字母数字:组合):abc:cde" />
</Form.Item>
<Form.Item
wrapperCol={{
xs: { span: 20, offset: 4 },
sm: { span: 20, offset: 4 }
}}
>
<Button type="primary" htmlType="submit">
</Button>
</Form.Item>
</Form>
</Spin>
</Modal>
)}
<SearchForm
ref={searchForm}
handleSearch={handleSearch}
config={searchConfigList}
/>
<Table
rowKey={(record) => record.id}
columns={columns}
dataSource={permissionList}
pagination={false}
/>
</>
)
}
export default AdminPermissionList

43
src/package/SimpleTrade/pages/adminupload/uploadapk/index.tsx

@ -1,43 +0,0 @@
import React, { FC } from 'react';
import { InboxOutlined } from '@ant-design/icons';
import { message, Upload } from 'antd';
const props = {
name: 'file',
multiple: true,
action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
onChange(info) {
const { status } = info.file;
if (status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (status === 'done') {
message.success(`${info.file.name} file uploaded successfully.`);
} else if (status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
},
onDrop(e) {
console.log('Dropped files', e.dataTransfer.files);
},
};
const { Dragger } = Upload;
const UploadAPK: FC = () => {
return (
<div style={{ height: '50vh' }}>
<div style={{ width: '100%' }}>
<Dragger {...props}>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text"></p>
<p className="ant-upload-hint"></p>
</Dragger>
</div>
</div>
)
}
export default UploadAPK;

3
src/package/SimpleTrade/pages/adminuser/adminuser.less

@ -1,3 +0,0 @@
.mr-5 {
margin-right: 5px;
}

211
src/package/SimpleTrade/pages/adminuser/edit/index.tsx

@ -1,211 +0,0 @@
import React, { useState, FC, useEffect } from 'react'
import { useHistory } from 'react-router-dom'
import { Form, Input, Button, message, Spin, Tree } from 'antd'
import { formItemLayout, wrapperCol } from '@/package/SimpleTrade/config/layout'
import {
closeTabAction,
getQuery,
makeTree,
makeTreeData,
treeFindParentById,
diffArray
} from '@/assets/js/publicFunc'
import MySelect from '@/components/MySelect'
import AdminUserApi from '@/package/SimpleTrade/api/admin-user'
import AdminPermissionApi from '@/package/SimpleTrade/api/admin-permission'
const FormView: FC = () => {
const query = getQuery()
const { id } = query
// 原始权限tree
let originalTreeData: Array<any> = []
const [form] = Form.useForm()
const { setFieldsValue, getFieldsValue, resetFields } = form
const [loading, setLoading] = useState<boolean>(false)
const [treeData, setTreeData] = useState<Array<any>>([])
const [checkedKeys, setCheckedKeys] = useState<Array<number | string>>([])
const history: CommonObjectType = useHistory()
// 获取权限列表数据
const getPermissions = async () => {
await AdminPermissionApi.getAdminPermissions().then((res: any) => {
const data: Array<any> = res.data ? res.data : []
originalTreeData = makeTree(data)
const treeDataTemp = makeTreeData(originalTreeData, 'id', 'name')
setTreeData(treeDataTemp)
})
}
useEffect(() => {
getPermissions()
if (id) {
AdminUserApi.getAdminUser(id).then((res) => {
const data: any = res.data ? res.data : {}
const adminUsers = data.adminUser ? data.adminUser : {}
const permissions = data.permissions ? data.permissions : []
const permissionIds = permissions.map((item) => {
return item.permissionId
})
// tree父子受控回显需要过滤掉父级ID
let parents: Array<number | string> = []
permissionIds.forEach((item: number | string) => {
const temp: Array<number | string> = treeFindParentById(
originalTreeData,
item
)
parents = parents.concat(temp)
})
const checkIds: Array<number | string> = diffArray(
permissionIds,
parents
)
setCheckedKeys(checkIds)
adminUsers.status = adminUsers.status.toString()
resetFields()
setFieldsValue({ ...adminUsers })
})
} else {
setFieldsValue({ status: '1' })
}
// eslint-disable-next-line
}, [id])
const onCheck = (checkedKeysValue: any) => {
setCheckedKeys(checkedKeysValue)
setFieldsValue({ permissions: checkedKeysValue })
}
const handleSubmit = () => {
setLoading(true)
const submitForm: any = { ...getFieldsValue() }
if (typeof submitForm.status === 'string') {
submitForm.status = parseInt(submitForm.status, 0)
}
if (id) {
AdminUserApi.updateAdminUser(id, submitForm)
.then((res) => {
message.success(res.message)
})
.finally(() => {
setLoading(false)
})
} else {
AdminUserApi.addAdminUser(submitForm)
.then((res) => {
setLoading(false)
message.success(res.message)
const returnUrl = '/adminuser/list'
closeTabAction(history, returnUrl)
})
.catch(() => {
setLoading(false)
})
}
}
const nameValidator = (rule, value) => {
if (value.length < 4) {
return Promise.reject(new Error('用户名最少4个字符'))
}
if (!/^[a-zA-Z0-9]{4,}$/.test(value)) {
return Promise.reject(new Error('用户名只能是数字字母下划线组合'))
}
return Promise.resolve()
}
const repasswordValidator = (rule, value) => {
const password = form.getFieldValue('password')
if (password && password !== value) {
return Promise.reject(new Error('两次密码输入不一致'))
}
return Promise.resolve()
}
return (
<Spin spinning={loading}>
<Form {...formItemLayout} form={form} onFinish={handleSubmit}>
<Form.Item
label="用户名"
name="name"
rules={[
{
required: true,
validator: nameValidator
}
]}
>
<Input placeholder="请输入用户名" />
</Form.Item>
{!id && (
<Form.Item
label="密码"
name="password"
rules={[
{
required: true,
message: '请输入密码'
},
{
min: 6
}
]}
>
<Input placeholder="请输入密码" />
</Form.Item>
)}
{!id && (
<Form.Item
label="确认密码"
name="repassword"
rules={[
{
required: true,
validator: repasswordValidator
}
]}
>
<Input placeholder="请输入确认密码" />
</Form.Item>
)}
<Form.Item
label="状态"
name="status"
rules={[
{
required: true,
message: '请选择状态'
}
]}
>
<MySelect
data={[{ key: '0', name: '冻结' }, { key: '1', name: '正常' }]}
placeholder="请选择状态"
/>
</Form.Item>
<Form.Item label="权限" name="permissions">
<Tree
checkable
onCheck={onCheck}
checkedKeys={checkedKeys}
treeData={treeData}
/>
</Form.Item>
<Form.Item wrapperCol={wrapperCol}>
<Button type="primary" htmlType="submit">
</Button>
</Form.Item>
</Form>
</Spin>
)
}
export default FormView

250
src/package/SimpleTrade/pages/adminuser/list/index.tsx

@ -1,250 +0,0 @@
import React, { useRef, FC, useState } from 'react'
import { useHistory } from 'react-router-dom'
import { Button, Form, Input, Modal, Tag, Spin, message } from 'antd'
import MyTable from '@/components/MyTable'
import { isAuthorized } from '@/assets/js/publicFunc'
import MySelect from '@/components/MySelect'
import AdminUserApi from '@/package/SimpleTrade/api/admin-user'
import { modalLayoutSm5 } from '@/package/SimpleTrade/config/layout'
import '../adminuser.less'
interface AdminUser {
id: number;
name: string;
status: number;
updateTime: string;
createTime: string;
}
const StatusArr: Array<string> = ['冻结', '正常']
const StatusTagArr: Array<string> = ['gold', 'blue']
const AdminUserList: FC = () => {
const tableRef: RefType = useRef()
const history = useHistory()
const [form] = Form.useForm()
const { getFieldsValue, resetFields } = form
const [loading, setLoading] = useState<boolean>(false)
const [btnLoading, setBtnLoading] = useState<boolean>(false)
const [visible, setVisible] = useState<boolean>(false)
const [id, setId] = useState<number>(0)
const [delIds, setDelIds] = useState<Array<string | number>>([])
const [delDisabeld, setDelDisabeld] = useState<boolean>(true)
const addAdminUser = () => {
history.push('/adminuser/list/add')
}
const editAdminUserPwd = (record: AdminUser) => {
resetFields()
setVisible(true)
setId(record.id)
}
const cancelModel = () => {
setVisible(false)
}
const editAdminUser = (record: AdminUser) => {
history.push(`/adminuser/list/edit?id=${record.id}`)
}
const onSelectRow = (rowKeys: Array<string | number>) => {
setDelIds(rowKeys)
if (rowKeys.length > 0) {
setDelDisabeld(false)
} else {
setDelDisabeld(true)
}
}
const repasswordValidator = (rule, value) => {
const password = form.getFieldValue('password')
if (password && password !== value) {
return Promise.reject(new Error('两次密码输入不一致'))
}
return Promise.resolve()
}
const delAdminUser = () => {
setBtnLoading(true)
AdminUserApi.deleteAdminUser(delIds)
.then((res: any) => {
message.success(res.message)
tableRef.current.update()
})
.finally(() => {
setBtnLoading(false)
})
}
const handleSubmit = () => {
setLoading(true)
const submitForm = { ...getFieldsValue() }
AdminUserApi.updateAdminUserPwd(id, submitForm)
.then((res: any) => {
message.success(res.message)
})
.finally(() => {
setLoading(false)
})
}
// 搜索栏配置项
const searchConfigList = [
{
key: 'name',
slot: <Input placeholder="用户名" allowClear />,
initialValue: ''
},
{
key: 'status',
slot: (
<MySelect
data={[{ name: '正常', key: '1' }, { name: '冻结', key: '0' }]}
placeholder="状态"
/>
)
}
]
const columns = [
{
title: '用户名',
dataIndex: 'name'
},
{
title: '状态',
dataIndex: 'status',
render: (status: number) => (
<>
<Tag color={StatusTagArr[status]}>{StatusArr[status]}</Tag>
</>
)
},
{
title: '更新时间',
dataIndex: 'updateTime'
},
{
title: '创建时间',
dataIndex: 'createTime'
},
{
title: '操作',
dataIndex: 'operations',
align: 'center',
render: (text, record) => (
<>
{isAuthorized('adminuser:list:edit') && (
<div>
<Button
className="btn mr-5"
onClick={() => editAdminUserPwd(record)}
size="small"
type="primary"
danger
>
</Button>
<Button
className="btn"
onClick={() => editAdminUser(record)}
size="small"
type="primary"
>
</Button>
</div>
)}
</>
)
}
]
const delAdminUserEl = (
<Button
className="fr mr-5"
onClick={delAdminUser}
type="primary"
disabled={delDisabeld}
loading={btnLoading}
danger
>
</Button>
)
const addAdminUserEl = (
<Button className="fr" onClick={addAdminUser} type="primary">
</Button>
)
return (
<>
{visible && (
<Modal
title="修改密码"
visible={visible}
onCancel={cancelModel}
footer={null}
>
<Spin spinning={loading}>
<Form {...modalLayoutSm5} form={form} onFinish={handleSubmit}>
<Form.Item
label="新密码"
name="password"
rules={[
{
required: true,
message: '请输入新密码'
},
{
min: 6,
message: '新密码长度最少6个字符'
}
]}
>
<Input placeholder="请输入新密码" />
</Form.Item>
<Form.Item
label="确认新密码"
name="repassword"
rules={[
{
required: true,
validator: repasswordValidator
}
]}
>
<Input placeholder="请输入确认新密码" />
</Form.Item>
<Form.Item
wrapperCol={{
xs: { span: 20, offset: 5 },
sm: { span: 20, offset: 5 }
}}
>
<Button type="primary" htmlType="submit">
</Button>
</Form.Item>
</Form>
</Spin>
</Modal>
)}
{isAuthorized('adminuser:list:add') && addAdminUserEl}
{isAuthorized('adminuser:list:del') && delAdminUserEl}
<MyTable
apiFun={AdminUserApi.getAdminUserList}
columns={columns}
ref={tableRef}
onSelectRow={onSelectRow}
searchConfigList={searchConfigList}
/>
</>
)
}
export default AdminUserList

61
src/package/SimpleTrade/pages/client/mt4history/index.tsx

@ -1,61 +0,0 @@
import MyTable from "@/components/MyTable";
import React, { FC } from "react";
import clientApi from "@/package/SimpleTrade/api/client";
import { Input } from "antd";
const MT4History: FC = () => {
const column = [
{
title: '订单号',
dataIndex: 'ticket',
align: 'center'
},
{
title: '手数',
dataIndex: 'volume',
align: 'center'
},
{
title: '开仓价格',
dataIndex: 'open_price',
align: 'center'
},
{
title: '开仓时间',
dataIndex: 'open_time',
align: 'center'
},
{
title: '平仓价格',
dataIndex: 'close_price',
align: 'center'
},
{
title: '平仓时间',
dataIndex: 'close_time',
align: 'center'
},
]
const searchConfigList = [
{
key: 'login',
slot: <Input placeholder="输入MT4账号" allowClear />,
initialValue: '',
}
]
return (
<div>
<MyTable
apiFun={clientApi.mt4_history}
columns={column}
rowKey="ticket"
searchConfigList={searchConfigList}
/>
</div>
)
}
export default MT4History;

110
src/package/SimpleTrade/pages/client/mt4order/index.tsx

@ -1,110 +0,0 @@
import React, { FC, useState, useMemo, useRef } from "react";
import MyTable from "@/components/MyTable";
import clientApi from "@/package/SimpleTrade/api/client";
import { Button, Modal, notification } from "antd";
const MT4Order: FC = () => {
const tableRefs = useRef<any>()
const [visible, setVisible] = useState(false)
const [currentItem, setCurrentItem] = useState({} as { [key: string]: any })
const statusText = useMemo(() => (
{
'-2': '创建订单失败',
'-1': '取消订单',
'0': '发送前',
'1': '挂单中',
'2': '寻找B仓',
'3': '止盈止损设置',
'4': '持仓中',
'5': '已结算',
}
), [])
const column = useMemo(() => [
{
title: '订单ID',
dataIndex: 'order'
},
{
title: '账号',
dataIndex: 'login'
},
{
title: '开仓价格',
dataIndex: 'open_price'
},
{
title: '开仓时间',
dataIndex: 'open_time',
render: (_time) => (<div>{_time}</div>)
},
{
title: '平仓价格',
dataIndex: 'close_price',
},
{
title: '平仓时间',
dataIndex: 'close_time',
render: (time) => <div>{time.indexOf('1970-01-01') < 0 && time}</div>
},
{
title: '状态',
dataIndex: 'handle_status',
render: (status) => (
<div>{statusText[`${status}`] || ''}</div>
)
},
// {
// title: '操作',
// dataIndex: 'operations',
// align: 'center',
// key: Date.now(),
// render: (text, record) => (
// <div>
// {record.account_forex_type === 1 && record.handle_status === 4 && (
// <Button type='primary' size='small' onClick={() => {
// setVisible(true)
// setCurrentItem(record)
// }}>平仓</Button>
// )}
// </div>
// )
// }
], [])
// const closePosition = async () => {
// let params = {
// login: currentItem.login,
// ticket: `${currentItem.order}`,
// volume: currentItem.volume
// }
// setVisible(false)
// const res: any = await clientApi.close_order(params)
// if (res.code === 0) {
// notification.success({
// message: '平仓成功'
// })
// setCurrentItem({})
// setTimeout(() => {
// tableRefs.current?.update()
// }, 1000)
// }
// }
return (
<div>
<MyTable
ref={tableRefs}
apiFun={clientApi.mt4_order_list}
columns={column}
rowKey="order"
/>
{/* <Modal visible={visible} onCancel={() => setVisible(false)} title='' onOk={closePosition}>
<div></div>
</Modal> */}
</div>
)
}
export default MT4Order;

47
src/package/SimpleTrade/pages/client/mt4settlementorder/index.tsx

@ -1,47 +0,0 @@
import MyTable from "@/components/MyTable";
import React, { FC } from "react";
import clientApi from "@/package/SimpleTrade/api/client";
const MT4SettlementOrder: FC = () => {
const columns = [
{
title: '订单ID',
dataIndex: 'ticket'
},
{
title: '用户ID',
dataIndex: 'user_id',
align: 'center'
},
{
title: '手数',
dataIndex: 'volume',
align: 'center',
render: (volume) => (
<div>{Number(volume) / 100}</div>
)
},
{
title: '开仓价格',
dataIndex: 'open_price',
align: 'center'
},
{
title: '开仓时间',
dataIndex: 'open_time',
align: 'center'
},
]
return (
<div>
<MyTable
apiFun={clientApi.mt4_settle_list}
columns={columns}
/>
</div>
)
}
export default MT4SettlementOrder;

236
src/package/SimpleTrade/pages/client/user/index.tsx

@ -1,236 +0,0 @@
import React, { FC, useEffect, useMemo, useRef, useState } from "react";
import clientApi from "@/package/SimpleTrade/api/client";
import MyTable from "@/components/MyTable";
import { Button, Input, Modal, notification, Popconfirm, Select } from "antd";
import { copy, splitAddress } from "@/utils";
import { CopyOutlined } from "@ant-design/icons";
const UserList: FC = () => {
const [currentItem, setCurrentItem] = useState({} as any)
const [isModalOpen, setIsModalOpen] = useState(false)
const [lv, setLv] = useState(0);
const tableRefs = useRef<any>()
const options = useMemo(() => [
{ value: 0, label: 'R' },
{ value: 1, label: 'G' },
{ value: 2, label: 'G1' },
{ value: 3, label: 'G2' },
{ value: 4, label: 'G3' },
{ value: 5, label: 'G4' },
{ value: 6, label: 'G5' },
], [])
const columns = [
{
title: '邮箱',
dataIndex: 'email'
},
{
title: '备注昵称',
dataIndex: 'remark'
},
{
title: '地址',
dataIndex: 'address',
render: (address) => (
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>{splitAddress(address, 5)}</div>
<div style={{ marginLeft: 5, cursor: 'pointer' }} onClick={() => copy(address)}>
<CopyOutlined />
</div>
</div>
)
},
{
title: 'A账号',
dataIndex: 'a_mt4_login'
},
{
title: 'A仓余额',
dataIndex: 'a_mt4_balance'
},
{
title: 'A仓订单数量',
dataIndex: 'a_product'
},
{
title: 'B账号',
dataIndex: 'b_mt4_login'
},
{
title: 'B仓余额',
dataIndex: 'b_mt4_balance'
},
{
title: 'B仓订单数量',
dataIndex: 'b_product'
},
{
title: '手数',
dataIndex: 'volume'
},
{
title: '级别',
dataIndex: 'level',
render: (level) => (
<div>{options[level] ? options[level].label : level}</div>
)
},
{
title: '保险开关',
dataIndex: 'insurance',
render: (status) => (
<div>{status === 1 ? '开' : '关'}</div>
)
},
{
title: '邀请码',
dataIndex: 'invite_code'
},
{
title: '推荐人',
dataIndex: 'referrer'
},
{
title: '操作',
dataIndex: 'operations',
align: 'center',
fixed: 'right',
key: Date.now(),
width: 180,
render: (text, record) => {
return (
<div>
<div>
<Button type="primary" className="btn" size="small" onClick={() => {
setCurrentItem(record)
setIsModalOpen(true)
setLv(record.level)
}}></Button>
<Button style={{ marginLeft: 10 }} type="primary" className="btn" size="small" onClick={() => rename(record.remark, record.invite_code)}></Button>
</div>
<div style={{ marginTop: 10 }}>
<Popconfirm title={`确认${!record.deactivate?'停用':'启用'}账号?`} onConfirm={()=>deactivateAccount(record.invite_code,record.deactivate)}>
<Button type="primary" className="btn" size="small" danger={!record.deactivate}>{!record.deactivate ? '停用账号' :'启用账号'}</Button>
</Popconfirm>
</div>
</div>
)
}
}
]
// 搜索栏配置项
const searchConfigList = [
{
key: 'name',
slot: <Input placeholder="用户名" allowClear />,
initialValue: ''
}
]
const nicknameRefs = useRef(null)
const deactivateAccount = async (code:string,status:boolean)=>{
const res:any = await clientApi.user_deactivate({
invite_code:code,
deactivate:!status
})
if(res.code === 0){
notification.success({
message: !status ? '停用成功' : '启用成功'
})
tableRefs.current?.update()
}
}
const rename = async (name: string, code: string) => {
Modal.confirm({
title: '修改昵称',
content: (
<Input ref={nicknameRefs} placeholder="请输入昵称" />
),
onOk: async () => {
let _name = nicknameRefs.current.state.value
const res: any = await clientApi.user_rename({
invite_code: code,
remark: _name
})
if (res.code === 0) {
notification.success({
message: '设置成功'
})
tableRefs.current?.update()
}
},
onCancel: () => {
nicknameRefs.current && nicknameRefs.current.setValue('')
},
})
setTimeout(() => {
nicknameRefs.current && nicknameRefs.current.setValue(name)
}, 100)
}
const setLevel = async () => {
if (currentItem.level === lv) {
notification.error({
message: '设置等级相同',
})
return;
}
let res: any = await clientApi.up_levle({
level: lv,
invite_code: currentItem.invite_code
})
if (res.code === 0) {
notification.success({
message: '设置成功'
})
setIsModalOpen(false)
tableRefs.current?.update()
}
}
const handleChange = (_, e) => {
setLv(e.value)
}
useEffect(() => {
if (!isModalOpen) {
setCurrentItem({})
setLv(0)
}
}, [isModalOpen])
return (
<div>
<MyTable
ref={tableRefs}
columns={columns}
apiFun={clientApi.user_list}
searchConfigList={searchConfigList}
rowKey="invite_code"
/>
<Modal
title="设置等级"
visible={isModalOpen}
onOk={setLevel}
onCancel={() => setIsModalOpen(false)}
>
{
isModalOpen && (
<Select
defaultValue={currentItem.level || 0}
options={options}
style={{ width: '100%' }}
onChange={handleChange}
/>
)
}
</Modal>
</div>
)
};
export default UserList;

128
src/package/SimpleTrade/pages/client/withdraw/index.tsx

@ -1,128 +0,0 @@
import React, { FC, useRef } from "react";
import clientApi from "@/package/SimpleTrade/api/client";
import MyTable from "@/components/MyTable";
import { Button, Input, notification, Popconfirm } from "antd";
import { CopyOutlined } from "@ant-design/icons";
import { copy, getTime, splitAddress } from "@/utils";
import { Withdraw_Check } from "@/package/SimpleTrade/types/enum";
const WithdrawRecord: FC = () => {
const tableRefs = useRef(null)
const columns = [
{
title: '账号ID',
dataIndex: 'a_mt4_login'
},
{
title: '备注昵称',
dataIndex: 'remark'
},
{
title: '交易ID',
dataIndex: 'tx_hash',
render: (tx_hash) => (
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>{splitAddress(tx_hash, 5)}</div>
<div style={{ marginLeft: 5, cursor: 'pointer' }} onClick={() => copy(tx_hash)}>
<CopyOutlined />
</div>
</div>
)
},
{
title: '链ID',
dataIndex: 'chain_id'
},
{
title: '提币地址',
dataIndex: 'to_address',
render: (to_address) => (
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>{splitAddress(to_address, 5)}</div>
<div style={{ marginLeft: 5, cursor: 'pointer' }} onClick={() => copy(to_address)}>
<CopyOutlined />
</div>
</div>
)
},
{
title: '数量',
dataIndex: 'amount'
},
{
title: '币种',
dataIndex: 'symbol'
},
{
title: '提现状态',
dataIndex: 'status'
},
{
title: '处理时间',
dataIndex: 'handle_time',
render: (time) => (
<div>{getTime(time * 1000)}</div>
)
},
{
title: '操作',
dataIndex: 'operations',
align: 'center',
key: Date.now(),
render: (_, item) => {
return item.check_status === 1 ? (<div>
<Popconfirm
title="确认拒绝吗?"
onConfirm={() => handleOrder(item, Withdraw_Check.WithdrawCheckReject)}
>
<Button size="small" type="primary" danger style={{ marginRight: 20 }}></Button>
</Popconfirm>
<Popconfirm
title="确认同意吗?"
onConfirm={() => handleOrder(item, Withdraw_Check.WithdrawCheckAgree)}
>
<Button size="small" type="primary"></Button>
</Popconfirm>
</div>) : (<></>)
}
}
]
// 搜索栏配置项
const searchConfigList = [
{
key: 'name',
slot: <Input placeholder="用户名" allowClear />,
initialValue: ''
}
]
const handleOrder = async (item, type: Withdraw_Check) => {
const res: any = await clientApi.withdraw_check({
id: item.id,
status: type
})
if (res.code === 0) {
notification.success({
message: type === Withdraw_Check.WithdrawCheckAgree ? '已同意' : '已拒绝'
})
tableRefs.current?.update()
}
}
return (
<div>
<MyTable
ref={tableRefs}
columns={columns}
apiFun={clientApi.withdraw_list}
searchConfigList={searchConfigList}
rowKey="id"
/>
</div>
)
};
export default WithdrawRecord;

352
src/package/SimpleTrade/pages/home/index.tsx

@ -1,352 +0,0 @@
import React, { FC, useEffect, useState } from 'react'
import './index.less'
import { useSelector } from 'react-redux'
import api from '@/package/SimpleTrade/api'
import { DatePicker } from 'antd';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import weekday from "dayjs/plugin/weekday"
import localeData from "dayjs/plugin/localeData"
dayjs.extend(customParseFormat);
dayjs.extend(weekday);
dayjs.extend(localeData);
const { RangePicker } = DatePicker;
const dateFormat = 'YYYY-MM-DD';
const Home: FC = () => {
const theme = useSelector((state: any) => state.storeData.theme)
const [userTable, setUserTable] = useState([])
const [newToDay, setNewToDay] = useState(0) //今日新增
const [userTotal, setUserTotal] = useState(0) //用户统计
const start_time = dayjs().subtract(7, 'days')
const end_time = dayjs()
const [defaultValue, setDefaultValue] = useState([start_time, end_time] as any) //周期合约时间
const [withdrawTime, setWithdrawTime] = useState([start_time, end_time] as any) //周期充值提现时间
const [toDayTx, setToDayTx] = useState([
{ title: '今日订单金额', value: '0' },
{ title: '今日订单数量', value: '0' },
{ title: 'A仓盈利订单数量', value: '0', color: '#3BB900' },
{ title: 'B仓盈利订单数量', value: '0', color: '#3BB900' },
{ title: 'A仓亏损订单数量', value: '0', color: '#F4002C' },
{ title: 'B仓亏损订单数量', value: '0', color: '#F4002C' },
{ title: '盈利订单金额', value: '0', color: '#3BB900' },
{ title: '亏损订单金额', value: '0', color: '#F4002C' },
])
const [weekTx, setWeekTx] = useState([
{ title: '订单总金额', value: '0' },
{ title: '订单总数量', value: '0' },
{ title: 'A仓盈利订单数量', value: '0', color: '#3BB900' },
{ title: 'B仓盈利订单数量', value: '0', color: '#3BB900' },
{ title: 'A仓亏损订单数量', value: '0', color: '#F4002C' },
{ title: 'B仓亏损订单数量', value: '0', color: '#F4002C' },
{ title: '盈利订单金额', value: '0', color: '#3BB900' },
{ title: '亏损订单金额', value: '0', color: '#F4002C' },
])
const [transaction, setTransaction] = useState([])
const [weekTransaction, setWeekTransaction] = useState([])
// 用户统计
const getUserData = async () => {
const res: any = await api.user_statistics()
if (res.code === 0) {
setNewToDay(res.data.NewToday)
setUserTotal(res.data.total_amount)
setUserTable(res.data.AdminUserAmountList)
}
}
// 周期合约交易订单统计
const getWeekTxOrderStatic = async () => {
const start = Math.floor(defaultValue[0].valueOf() / 1000)
const end = Math.floor(defaultValue[1].valueOf() / 1000)
const res: any = await api.transaction_statistics({
end_time: end,
start_time: start,
type: 2
})
if (res.code === 0) {
weekTx[0].value = res.data.product_amount
weekTx[1].value = res.data.product_num
weekTx[2].value = res.data.a_profit_num
weekTx[3].value = res.data.b_profit_num
weekTx[4].value = res.data.a_loss_num
weekTx[5].value = res.data.b_loss_num
weekTx[6].value = res.data.profit_amount
weekTx[7].value = res.data.loss_amount
setWeekTx([...weekTx])
}
}
// 周期充值提现
const getWeekTransaction = async () => {
const start = Math.floor(withdrawTime[0].valueOf() / 1000)
const end = Math.floor(withdrawTime[1].valueOf() / 1000)
const res: any = await api.week_recharge_withdraw_statistics({
end_time: end,
start_time: start,
type: 2
})
if (res.code === 0 && res.data) {
setWeekTransaction(res.data)
}
}
// 今日合约交易订单统计
const getDayTxOrderStatic = async () => {
const res: any = await api.transaction_statistics({
type: 1
})
if (res.code === 0) {
toDayTx[0].value = res.data.product_amount
toDayTx[1].value = res.data.product_num
toDayTx[2].value = res.data.a_profit_num
toDayTx[3].value = res.data.b_profit_num
toDayTx[4].value = res.data.a_loss_num
toDayTx[5].value = res.data.b_loss_num
toDayTx[6].value = res.data.profit_amount
toDayTx[7].value = res.data.loss_amount
setToDayTx([...toDayTx])
}
}
// 充值提现统计
const getRechargeAndWithdraw = async () => {
const res: any = await api.recharge_withdraw_statistics()
if (res.code === 0) {
setTransaction(res.data)
}
}
useEffect(() => {
getUserData()
getDayTxOrderStatic()
getRechargeAndWithdraw()
}, [])
useEffect(() => {
getWeekTxOrderStatic()
}, [defaultValue])
useEffect(() => {
getWeekTransaction()
}, [withdrawTime])
return (
<div className='home' style={{ minHeight: '80vh', backgroundColor: theme && '#fff' }}>
<h3>Hello, Randy!</h3>
<div>Today is a good day to start trading crypto assets!</div>
{/* */}
<div className='box' style={{ backgroundColor: theme ? '#f5f5f5' : '#333' }}>
<div style={{ fontWeight: 'bold' }}></div>
<div className='row'>
<div style={{ flex: 3, marginTop: 30 }}>
<h2>{userTotal.toLocaleString()}</h2>
<div className='row-items' style={{ marginTop: 20 }}>
<div className='img-box'>
<img src={require('./vector.png')} alt="" />
</div>
<div style={{ marginLeft: 10 }}>
<div style={{ fontWeight: 'bold' }}>+{newToDay.toLocaleString()}</div>
<div style={{ fontSize: 12, marginTop: 5 }}></div>
</div>
</div>
</div>
<div className='solid' style={{ backgroundColor: theme ? '#e8e8e8' : '#555' }}></div>
<div style={{ flex: 4, marginLeft: 20 }}>
<div className='row' style={{ textAlign: 'center' }}>
<div style={{ flex: 1 }}></div>
<div style={{ flex: 1 }}></div>
<div style={{ flex: 1 }}></div>
</div>
<div>
{
userTable.map((item, index) => (
<div key={index} className='row' style={{ textAlign: 'center', marginTop: 20 }}>
<div style={{ flex: 1 }}>{item.type}</div>
<div style={{ flex: 1 }}>
<div>{Number(item.yesterday_amount).toLocaleString()}</div>
<div>{item.yesterday_percentage}</div>
</div>
<div style={{ flex: 1, color: '#44D600' }}>
<div>{Number(item.new_today_amount).toLocaleString()}</div>
<div>{item.new_today_percentage}</div>
</div>
</div>
))
}
</div>
</div>
</div>
</div>
{/* */}
<div className='box row' style={{ backgroundColor: theme ? '#f5f5f5' : '#333', marginTop: 30 }}>
<div style={{ flex: 3 }}>
<div style={{ fontWeight: 'bold', fontSize: 14 }}></div>
<div style={{ marginTop: 20, textAlign: 'center', flexWrap: 'wrap' }} className='row-items'>
{
toDayTx.map((item, index) => (
<div key={index} style={{ width: '50%', marginTop: 10 }}>
<div style={{ fontSize: 14 }}>{item.title}</div>
<div style={{ fontWeight: 'bold', fontSize: 14, color: item.color }}>{Number(item.value).toLocaleString()}</div>
</div>
))
}
</div>
</div>
<div className='solid' style={{ backgroundColor: theme ? '#e8e8e8' : '#555', margin: '0 20px' }}></div>
<div style={{ flex: 4 }}>
<div className='row-between'>
<div className='row-items'>
<div style={{ fontWeight: 'bold', fontSize: 14 }}></div>
<div style={{ marginLeft: 10 }}>
<RangePicker
defaultValue={defaultValue}
onChange={setDefaultValue}
format={dateFormat}
/>
</div>
</div>
<div className='row-items'>
{/* <div>导出</div> */}
</div>
</div>
<div style={{ marginTop: 20, textAlign: 'center', flexWrap: 'wrap' }} className='row-items'>
{
weekTx.map((item, index) => (
<div key={index} style={{ width: '50%', marginTop: 10 }}>
<div style={{ fontSize: 14 }}>{item.title}</div>
<div style={{ fontWeight: 'bold', fontSize: 14, color: item.color }}>{Number(item.value).toLocaleString()}</div>
</div>
))
}
</div>
</div>
</div>
{/* */}
{transaction[0] && transaction[1] && <div className='box row' style={{ backgroundColor: theme ? '#f5f5f5' : '#333', marginTop: 30 }}>
<div style={{ flex: 4 }}>
<div style={{ fontWeight: 'bold', fontSize: 14 }}>{transaction[0].symbol} </div>
{/* <div style={{ fontSize: 14, marginTop: 30 }}><span style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>2131223</span></div>
<div style={{ fontSize: 14, marginTop: 30 }}><span style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>150%</span></div> */}
<div className='row' style={{ textAlign: 'center', marginTop: 30 }}>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(transaction[0].deposit_amount).toLocaleString()}</div>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{transaction[0].deposit_num}</div>
</div>
</div>
<div className='row' style={{ textAlign: 'center', marginTop: 20 }}>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(transaction[0].withdrawal_amount).toLocaleString()}</div>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{transaction[0].withdrawal_num}</div>
</div>
</div>
</div>
<div className='solid' style={{ backgroundColor: theme ? '#e8e8e8' : '#555', margin: '0 20px' }}></div>
<div style={{ flex: 4 }}>
<div style={{ fontWeight: 'bold', fontSize: 14 }}>{transaction[1].symbol} </div>
<div className='row' style={{ textAlign: 'center', marginTop: 30 }}>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(transaction[1].deposit_amount).toLocaleString()}</div>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{transaction[1].deposit_num}</div>
</div>
</div>
<div className='row' style={{ textAlign: 'center', marginTop: 20 }}>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(transaction[1].withdrawal_amount).toLocaleString()}</div>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{transaction[1].withdrawal_num}</div>
</div>
</div>
</div>
</div>}
{/* */}
{weekTransaction[0] && weekTransaction[1] && (
<div className='box' style={{ marginTop: 30, backgroundColor: theme ? '#f5f5f5' : '#333' }}>
<div>
<RangePicker
defaultValue={withdrawTime}
onChange={setWithdrawTime}
format={dateFormat}
/>
</div>
<div className='row' style={{ marginTop: 20 }}>
<div style={{ flex: 4 }}>
<div style={{ fontWeight: 'bold', fontSize: 14 }}>{weekTransaction[0].symbol} </div>
{/* <div style={{ fontSize: 14, marginTop: 30 }}><span style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>2131223</span></div>
<div style={{ fontSize: 14, marginTop: 30 }}><span style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>150%</span></div> */}
<div className='row' style={{ textAlign: 'center', marginTop: 30 }}>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(weekTransaction[0].deposit_amount).toLocaleString()}</div>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{weekTransaction[0].deposit_num}</div>
</div>
</div>
<div className='row' style={{ textAlign: 'center', marginTop: 20 }}>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(weekTransaction[0].withdrawal_amount).toLocaleString()}</div>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{weekTransaction[0].withdrawal_num}</div>
</div>
</div>
</div>
<div className='solid' style={{ backgroundColor: theme ? '#e8e8e8' : '#555', margin: '0 20px' }}></div>
<div style={{ flex: 4 }}>
<div style={{ fontWeight: 'bold', fontSize: 14 }}>{weekTransaction[1].symbol} </div>
<div className='row' style={{ textAlign: 'center', marginTop: 30 }}>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(weekTransaction[1].deposit_amount).toLocaleString()}</div>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{weekTransaction[1].deposit_num}</div>
</div>
</div>
<div className='row' style={{ textAlign: 'center', marginTop: 20 }}>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(weekTransaction[1].withdrawal_amount).toLocaleString()}</div>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{weekTransaction[1].withdrawal_num}</div>
</div>
</div>
</div>
</div>
</div>
)}
<div style={{ display: 'block', height: 30 }}></div>
</div >
)
}
export default Home

177
src/package/SimpleTrade/route/routes.ts

@ -1,177 +0,0 @@
import Home from '@/package/SimpleTrade/pages/home'
import ErrorPage from '@/pages/public/errorPage'
import AdminUserList from '@/package/SimpleTrade/pages/adminuser/list'
import AdminUserEdit from '@/package/SimpleTrade/pages/adminuser/edit'
import AdminPermissionList from '@/package/SimpleTrade/pages/adminpermission/list'
import InviteChart from '@/package/SimpleTrade/pages/admininvite/chart'
import UploadAPK from '@/package/SimpleTrade/pages/adminupload/uploadapk'
import UserList from '@/package/SimpleTrade/pages/client/user'
import WithdrawRecord from '@/package/SimpleTrade/pages/client/withdraw'
import RechargeRecord from '@/package/SimpleTrade/pages/client/recharge'
import MT4History from '@/package/SimpleTrade/pages/client/mt4history'
import MT4Order from '@/package/SimpleTrade/pages/client/mt4order'
import MT4SettlementOrder from '@/package/SimpleTrade/pages/client/mt4settlementorder'
import { HomeOutlined, UserOutlined, AuditOutlined } from '@ant-design/icons'
/**
* path
* component
* exact true的时候则精确匹配
*/
const menus = [
{
path: '/',
name: '首页',
exact: true,
key: 'home',
icon: HomeOutlined,
component: Home,
routes: []
},
{
path: '/adminuser',
name: '用户管理',
key: 'adminuser',
type: 'subMenu',
icon: UserOutlined,
iconfont: 'icon-xiaoshouzongjian',
routes: [
{
path: '/adminuser/list',
name: '用户列表',
exact: true,
key: 'adminuser:list:view',
component: AdminUserList
},
{
path: '/adminuser/list/add',
name: '新增用户',
exact: true,
key: 'adminuser:list:add',
component: AdminUserEdit,
remove: true
},
{
path: '/adminuser/list/edit',
name: '编辑用户',
exact: true,
key: 'adminuser:list:edit',
component: AdminUserEdit,
remove: true
}
]
},
{
path: '/adminpermission',
name: '权限管理',
key: 'adminpermission',
type: 'subMenu',
icon: AuditOutlined,
routes: [
{
path: '/adminpermission/list',
name: '权限列表',
exact: true,
key: 'adminpermission:list:view',
component: AdminPermissionList
}
]
},
{
path: '/admininvite',
name: '邀请',
key: 'admininvite',
type: 'subMenu',
icon: AuditOutlined,
routes: [
{
path: '/admininvite/chart',
name: '关联图',
exact: true,
key: 'admininvite:chart:view',
component: InviteChart
}
]
},
{
path: '/adminupload',
name: '上传管理',
key: 'adminupload',
type: 'subMenu',
icon: AuditOutlined,
routes: [
{
path: '/adminupload/uploadapk',
name: '上传APK',
exact: true,
key: 'adminupload:uploadapk:view',
component: UploadAPK
}
]
},
{
path: '/client',
name: '客户端',
key: 'client',
type: 'subMenu',
icon: AuditOutlined,
routes: [
{
path: '/client/userlist',
name: '用户列表',
exact: true,
key: 'client:userlist:view',
component: UserList
},
{
path: '/client/recharge',
name: '充值记录',
exact: true,
key: 'client:recharge:view',
component: RechargeRecord
},
{
path: '/client/withdraw',
name: '提现记录',
exact: true,
key: 'client:withdraw:view',
component: WithdrawRecord
},
{
path: '/client/mt4history',
name: 'MT4历史记录',
exact: true,
key: 'client:mt4history:view',
component: MT4History
},
{
path: '/client/mt4order',
name: 'MT4订单列表',
exact: true,
key: 'client:mt4order:view',
component: MT4Order
},
{
path: '/client/mt4settlementorder',
name: 'MT4结算订单列表',
exact: true,
key: 'client:mt4settlementorder:view',
component: MT4SettlementOrder
}
]
},
{
path: '/403',
name: '暂无权限',
exact: true,
key: '/403',
component: ErrorPage,
remove: true
}
]
export default menus

38
src/package/SimpleTrade/types/enum.ts

@ -1,38 +0,0 @@
// 提币状态
export enum Withdraw_Status {
WithdrawStatusFail = -1, //链上错误
WithdrawStatusInit = 0, //初始状态
WithdrawStatusCheck = 1, //审核
WithdrawStatusHex = 2, //生成签名数据
WithdrawStatusSend = 3, //已发送
WithdrawStatusConfirm = 4, //确认中
WithdrawStatusEnd = 5, //完成
}
export enum Withdraw_Check {
WithdrawCheckNIL =0, // 无需审核0
WithdrawCheckWait =1, // 审核中1
WithdrawCheckReject =2, // 审核 驳回2
WithdrawCheckAgree =3, // 审核同意完成3
}
// 提现状态
export enum Recharge_Status {
TxStatusErr = -1 ,//业务错误
TxStatusFail = -2, //链上错误
TxStatusInit = 0, //初始记录
TxStatusConfirm = 1, //确认数到账 100块后 转入到账户中
TxStatusNotify = 2, //允许交易
}
// 用户状态
export enum User_Status{
EmailUserStatusRoot = 0, //根邀请人
EmailUserStatusInit = 1, //H5注册
EmailUserStatusUse = 2, //提交激活信息
EmailUserStatusAMT4 = 3, //创建A仓账号
EmailUserStatusBMT4 = 4, //创建B仓账号
EmailUserStatusCopy = 5, //A->B账号关联反向下单
EmailUserStatusSendEmail = 6, //仓位账号初始化完成进行邮件发送
EmailUserStatusActivated = 7, //完成激活
}

0
src/package/SimpleTrade/pages/home/index.css → src/pages/home/index.css

0
src/package/SimpleTrade/pages/home/index.less → src/pages/home/index.less

114
src/pages/home/index.tsx

@ -0,0 +1,114 @@
import React, { FC, useEffect, useRef, useState } from 'react'
import './index.less'
import api from '@/api'
import { useSelector } from 'react-redux'
import { Button, Form, Input, Modal, notification } from 'antd'
const Home: FC = () => {
const theme = useSelector((state: any) => state.storeData.theme)
const [userData, setUserData] = useState({} as any)
const [visible, setVisible] = useState(false)
const amountRef = useRef(null)
const addressRef = useRef(null)
const typeRef = useRef(0)
// 充值提现统计
const getRechargeAndWithdraw = async () => {
const res: any = await api.home_info()
if (res.code === 0) {
setUserData(res.data)
}
}
// 1.利息 2.已到期质押提现
const withdraw = async () => {
const params = {
address: addressRef.current.state.value,
amount: amountRef.current.state.value,
type: typeRef.current
}
setVisible(false)
const res: any = await api.withdraw(params)
if (res.code === 0) {
getRechargeAndWithdraw()
notification.success({
message: '提现成功'
})
}
}
const openModal = (type: number) => {
typeRef.current = type
setVisible(true)
}
useEffect(() => {
getRechargeAndWithdraw()
}, [])
useEffect(() => {
const resetQuery = () => {
addressRef.current && (amountRef.current.state.value = '')
addressRef.current && (addressRef.current.state.value = '')
typeRef.current = 0
}
!visible && resetQuery()
}, [visible])
return (
<div className='home' style={{ minHeight: '80vh', backgroundColor: theme && '#fff' }}>
<h3>Hello, Randy!</h3>
<div>Today is a good day to start trading crypto assets!</div>
{/* */}
<div className='box row' style={{ backgroundColor: theme ? '#f5f5f5' : '#333', marginTop: 30 }}>
<div style={{ flex: 4 }}>
{/* <div style={{ fontSize: 14, marginTop: 30 }}><span style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>2131223</span></div>
<div style={{ fontSize: 14, marginTop: 30 }}><span style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>150%</span></div> */}
<div className='row' style={{ textAlign: 'center', marginTop: 30 }}>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(userData.pledge_amount).toLocaleString()}</div>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(userData.interest_balance).toLocaleString()}</div>
<Button type='primary' onClick={() => openModal(1)}></Button>
</div>
<div style={{ flex: 1 }}>
<div></div>
<div style={{ fontSize: 20, color: '#3BB900', fontWeight: 'bold' }}>{Number(userData.expired_pledge_balance).toLocaleString()}</div>
<Button type='primary' onClick={() => openModal(2)}></Button>
</div>
</div>
</div>
</div>
<div style={{ display: 'block', height: 30 }}></div>
<Modal visible={visible} onCancel={() => setVisible(false)} onOk={withdraw}>
<div style={{ marginTop: 40 }}>
<Form>
<Form.Item label="地址">
<Input placeholder='输入提现地址' ref={addressRef} />
</Form.Item>
<Form.Item label="数量">
<Input placeholder='输入提现数量' ref={amountRef} />
</Form.Item>
</Form>
</div>
</Modal>
</div >
)
}
export default Home

0
src/package/SimpleTrade/pages/home/vector.png → src/pages/home/vector.png

Before

Width: 90  |  Height: 90  |  Size: 589 B

After

Width: 90  |  Height: 90  |  Size: 589 B

75
src/pages/interest/index.tsx

@ -0,0 +1,75 @@
import React, { FC } from "react";
import MyTable from "@/components/MyTable";
import { Button, Input } from "antd";
import { copy, getTime, splitAddress } from "@/utils";
import { CopyOutlined } from "@ant-design/icons";
import api from "@/api";
import { store } from "@/store";
import { RootStateOrAny, useSelector } from "react-redux";
const Interest: FC = () => {
const { storeData } = useSelector((state: RootStateOrAny) => state)
const columns = [
// {
// title: '地址',
// dataIndex: 'to_address',
// render: (address) => (
// <div style={{ display: 'flex', alignItems: 'center' }}>
// <div>{splitAddress(address, 5)}</div>
// <div style={{ marginLeft: 5, cursor: 'pointer' }} onClick={() => copy(address)}>
// <CopyOutlined />
// </div>
// </div>
// )
// },
{
title: 'ID',
dataIndex: 'id'
},
{
title: '利息',
dataIndex: 'amount',
width: 350
},
{
title: '类型',
dataIndex: 'type'
},
{
title: '币种',
dataIndex: 'symbol'
},
{
title: '创建时间',
dataIndex: 'created_time',
render: (_time) => (<div>{getTime(_time * 1000)}</div>)
},
]
// 搜索栏配置项
// const searchConfigList = [
// {
// key: 'name',
// slot: <Input placeholder="用户名" allowClear />,
// initialValue: ''
// }
// ]
return (
<div>
<MyTable
columns={columns}
apiFun={api.income_list}
// searchConfigList={searchConfigList}
rowKey="id"
/>
</div>
)
};
export default Interest;

2
src/pages/login/index.tsx

@ -36,7 +36,7 @@ const LoginForm: FC<Props> = ({
const resData = {
userName: username,
token: res.data.token,
permission: res.data.permissions
permission: res.data.permissions || []
}
setUserInfo(resData, setStoreData)
history.push('/')

120
src/pages/order/index.tsx

@ -0,0 +1,120 @@
import React, { FC } from "react";
import MyTable from "@/components/MyTable";
import { Button, Input } from "antd";
import { copy, getTime, splitAddress } from "@/utils";
import { CopyOutlined } from "@ant-design/icons";
import api from "@/api";
import { store } from "@/store";
import { RootStateOrAny, useSelector } from "react-redux";
const Order: FC = () => {
const { storeData } = useSelector((state: RootStateOrAny) => state)
const columns = [
{
title: 'ID',
dataIndex: 'id'
},
{
title: '质押数量',
dataIndex: 'product_amount'
},
{
title: '产品总天数',
dataIndex: 'product_day'
},
{
title: '产品当前天数',
dataIndex: 'released_day'
},
{
title: '年化',
dataIndex: 'annualized'
},
{
title: '状态',
dataIndex: 'status_name'
},
{
title: '总利息',
dataIndex: 'amount'
},
{
title: '已释放利息',
dataIndex: 'available'
},
{
title: '未释放利息',
dataIndex: 'hold'
},
{
title: '币种',
dataIndex: 'symbol'
},
{
title: '订单创建时间',
dataIndex: 'time',
render: (_time) => (<div>{getTime(_time * 1000)}</div>)
},
{
title: '订单生效时间',
dataIndex: 'start_time',
render: (_time) => (<div>{getTime(_time * 1000)}</div>)
},
{
title: '订单结束时间',
dataIndex: 'end_time',
render: (_time) => (<div>{getTime(_time * 1000)}</div>)
},
]
// 搜索栏配置项
// const searchConfigList = [
// {
// key: 'name',
// slot: <Input placeholder="用户名" allowClear />,
// initialValue: ''
// }
// ]
const exprotExcel = async () => {
// window.open(`${process.env.REACT_APP_BASE_URL}/admin/product/excel`)
const { token = '' } = storeData.userInfo || {}
const res = await fetch(`${process.env.REACT_APP_BASE_URL}/admin/product/excel`, {
headers: {
Token: token
},
method: 'get',
})
const blob = await res.blob()
const url = window.URL.createObjectURL(blob)
window.open(url)
}
return (
<div>
<MyTable
columns={columns}
apiFun={api.order_list}
// searchConfigList={searchConfigList}
rowKey="id"
/>
<div style={{ marginBottom: 20 }} >
<Button onClick={exprotExcel}>(excel)</Button>
</div>
</div>
)
};
export default Order;

52
src/package/SimpleTrade/pages/client/recharge/index.tsx → src/pages/recharge/index.tsx

@ -1,19 +1,15 @@
import React, { FC } from "react";
import clientApi from "@/package/SimpleTrade/api/client";
import MyTable from "@/components/MyTable";
import { Input } from "antd";
import { copy, getTime, splitAddress } from "@/utils";
import { CopyOutlined } from "@ant-design/icons";
import api from "@/api";
const RechargeRecord: FC = () => {
const Recharge: FC = () => {
const columns = [
{
title: '账号ID',
dataIndex: 'a_mt4_login'
},
{
title: '备注昵称',
dataIndex: 'remark'
title: 'ID',
dataIndex: 'id'
},
{
title: 'from地址',
@ -40,8 +36,16 @@ const RechargeRecord: FC = () => {
)
},
{
title: '充值状态',
dataIndex: 'status'
title: '交易Hash',
dataIndex: 'tx_hash',
render: (hash) => (
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>{splitAddress(hash, 5)}</div>
<div style={{ marginLeft: 5, cursor: 'pointer' }} onClick={() => copy(hash)}>
<CopyOutlined />
</div>
</div>
)
},
{
title: '链ID',
@ -53,7 +57,7 @@ const RechargeRecord: FC = () => {
},
{
title: '数量',
dataIndex: 'balance_real'
dataIndex: 'amount'
},
{
title: '币种',
@ -61,30 +65,30 @@ const RechargeRecord: FC = () => {
},
{
title: '时间',
dataIndex: 'create_time',
dataIndex: 'created_time',
render: (_time) => (<div>{getTime(_time * 1000)}</div>)
}
},
]
// 搜索栏配置项
const searchConfigList = [
{
key: 'name',
slot: <Input placeholder="用户名" allowClear />,
initialValue: ''
}
]
// const searchConfigList = [
// {
// key: 'name',
// slot: <Input placeholder="用户名" allowClear />,
// initialValue: ''
// }
// ]
return (
<div>
<MyTable
columns={columns}
apiFun={clientApi.recharge_list}
searchConfigList={searchConfigList}
rowKey="ID"
apiFun={api.recharge_list}
// searchConfigList={searchConfigList}
rowKey="id"
/>
</div>
)
};
export default RechargeRecord;
export default Recharge;

92
src/pages/withdraw/index.tsx

@ -0,0 +1,92 @@
import React, { FC, useRef } from "react";
import MyTable from "@/components/MyTable";
import { Button, Input, notification, Popconfirm } from "antd";
import { CopyOutlined } from "@ant-design/icons";
import { copy, getTime, splitAddress } from "@/utils";
import api from "@/api";
const Withdraw: FC = () => {
const tableRefs = useRef(null)
const columns = [
{
title: 'ID',
dataIndex: 'id'
},
{
title: '提币地址',
dataIndex: 'to_address',
render: (to_address) => (
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>{splitAddress(to_address, 5)}</div>
<div style={{ marginLeft: 5, cursor: 'pointer' }} onClick={() => copy(to_address)}>
<CopyOutlined />
</div>
</div>
)
},
{
title: '交易ID',
dataIndex: 'tx_hash',
render: (tx_hash) => (
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>{splitAddress(tx_hash, 5)}</div>
<div style={{ marginLeft: 5, cursor: 'pointer' }} onClick={() => copy(tx_hash)}>
<CopyOutlined />
</div>
</div>
)
},
{
title: '链ID',
dataIndex: 'chain_id'
},
{
title: '数量',
dataIndex: 'amount'
},
{
title: '币种',
dataIndex: 'symbol'
},
{
title: '提现状态',
dataIndex: 'status_name'
},
{
title: '提现类型',
dataIndex: 'type'
},
{
title: '处理时间',
dataIndex: 'created_time',
render: (time) => (
<div>{getTime(time * 1000)}</div>
)
}
]
// 搜索栏配置项
// const searchConfigList = [
// {
// key: 'name',
// slot: <Input placeholder="用户名" allowClear />,
// initialValue: ''
// }
// ]
return (
<div>
<MyTable
ref={tableRefs}
columns={columns}
apiFun={api.withdraw_list}
// searchConfigList={searchConfigList}
rowKey="id"
/>
</div>
)
};
export default Withdraw;

60
src/route/routes.ts

@ -1,9 +1,57 @@
import SimpleTradeRoutes from '@/package/SimpleTrade/route/routes'
import Home from "@/pages/home"
import Interest from "@/pages/interest"
import Order from "@/pages/order"
import Recharge from "@/pages/recharge"
import Withdraw from "@/pages/withdraw"
import { HomeOutlined, SolutionOutlined } from "@ant-design/icons"
const routes = {
simpleTradeKey: [...SimpleTradeRoutes],
}
const routes = [
{
path: '/',
name: '首页',
exact: true,
key: 'home',
icon: HomeOutlined,
component: Home,
routes: []
},
{
path: '/recharge',
name: '充值',
exact: true,
key: 'recharge',
icon: SolutionOutlined,
component: Recharge,
routes: []
},
{
path: '/withdraw',
name: '提现',
exact: true,
key: 'withdraw',
icon: SolutionOutlined,
component: Withdraw,
routes: []
},
{
path: '/order',
name: '订单',
exact: true,
key: 'order',
icon: SolutionOutlined,
component: Order,
routes: []
},
{
path: '/interest',
name: '利息',
exact: true,
key: 'interest',
icon: SolutionOutlined,
component: Interest,
routes: []
}
]
const currentItem = routes.simpleTradeKey
export default currentItem
export default routes

4
src/utils/axios.ts

@ -2,7 +2,6 @@ import Axios from 'axios'
import { message } from 'antd'
import { store } from '@/store'
import { HashRouter } from 'react-router-dom'
import { getBaseURL } from '@/config'
interface AxiosConfig {
baseURL: string;
@ -12,9 +11,8 @@ interface AxiosConfig {
};
}
const config: AxiosConfig = {
baseURL: getBaseURL(),
baseURL: process.env.REACT_APP_BASE_URL,
timeout: 60 * 1000,
headers: {
'Content-Type': 'application/json'

13420
yarn.lock
File diff suppressed because it is too large
View File

Loading…
Cancel
Save