Commit c4dae162 by haojie

1

parent c7ebc749
<?php
namespace App\Http\Controllers\Web;
use Inertia\Inertia;
class AuthController
{
public function index()
{
$title = '登录';
return Inertia::render('Login/index', [
'info' => [
'title' => $title,
]
]);
}
}
......@@ -2,7 +2,10 @@
"name": "laravel/laravel",
"type": "project",
"description": "The Laravel Framework.",
"keywords": ["framework", "laravel"],
"keywords": [
"framework",
"laravel"
],
"license": "MIT",
"require": {
"php": "^8.0.2",
......@@ -56,6 +59,7 @@
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"platform-check": false,
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true
......
......@@ -7,9 +7,11 @@
"devDependencies": {
"@inertiajs/react": "^1.0.7",
"@reduxjs/toolkit": "^1.9.5",
"@types/js-cookie": "^3.0.3",
"@types/react": "^18.2.8",
"@vitejs/plugin-react": "^4.0.0",
"axios": "^1.1.2",
"js-cookie": "^3.0.5",
"laravel-vite-plugin": "^0.7.2",
"less": "^4.1.3",
"less-loader": "^11.1.2",
......@@ -1127,6 +1129,12 @@
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/js-cookie": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.3.tgz",
"integrity": "sha512-Xe7IImK09HP1sv2M/aI+48a20VX+TdRJucfq4vfRVy6nWN8PYPOEnlMRSgxJAgYQIXJVL8dZ4/ilAM7dWNaOww==",
"dev": true
},
"node_modules/@types/json-schema": {
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
......@@ -2188,6 +2196,15 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/js-cookie": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
"dev": true,
"engines": {
"node": ">=14"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
......@@ -4196,6 +4213,12 @@
"hoist-non-react-statics": "^3.3.0"
}
},
"@types/js-cookie": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.3.tgz",
"integrity": "sha512-Xe7IImK09HP1sv2M/aI+48a20VX+TdRJucfq4vfRVy6nWN8PYPOEnlMRSgxJAgYQIXJVL8dZ4/ilAM7dWNaOww==",
"dev": true
},
"@types/json-schema": {
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
......@@ -5037,6 +5060,12 @@
}
}
},
"js-cookie": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
"dev": true
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
......
......@@ -8,9 +8,11 @@
"devDependencies": {
"@inertiajs/react": "^1.0.7",
"@reduxjs/toolkit": "^1.9.5",
"@types/js-cookie": "^3.0.3",
"@types/react": "^18.2.8",
"@vitejs/plugin-react": "^4.0.0",
"axios": "^1.1.2",
"js-cookie": "^3.0.5",
"laravel-vite-plugin": "^0.7.2",
"less": "^4.1.3",
"less-loader": "^11.1.2",
......
location / {
try_files $uri $uri/ /index.php?$query_string;
}
\ No newline at end of file
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M6.5 10.9984C5.75827 10.9967 5.02862 10.8144 4.37671 10.4677C3.7248 10.1211 3.1711 9.62104 2.76545 9.01263H1.58364C2.03747 9.91005 2.7383 10.6653 3.60702 11.1932C4.47574 11.7211 5.47777 12.0005 6.5 12C7.88607 11.9883 9.21737 11.4682 10.2314 10.5423C11.2453 9.61631 11.8684 8.35173 11.9777 6.99789H13L11.4991 5.00053L9.99818 6.99789H10.9732C10.8624 8.08784 10.3444 9.09923 9.51875 9.83768C8.69306 10.5761 7.61793 10.9895 6.5 10.9984ZM6.5 1C5.20355 1.01004 3.9519 1.46599 2.96366 2.2882C1.97541 3.11041 1.31338 4.24663 1.09318 5.49842H0L1.50091 7.50158L3.00182 5.49842H2.10955C2.33169 4.51785 2.88702 3.64021 3.68461 3.00916C4.48221 2.37811 5.47483 2.03103 6.5 2.02474C7.14541 2.02578 7.7829 2.16401 8.36848 2.42988C8.95407 2.69576 9.4738 3.08295 9.89182 3.56474L10.0868 3.51842H11.1032C10.6157 2.75166 9.93781 2.11848 9.13281 1.67806C8.32781 1.23764 7.42199 1.00436 6.5 1Z"
fill="#1E2329"/>
</svg>
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M11.3721 1.99365H5.96033C5.84939 1.99365 5.74296 2.03713 5.66351 2.11358L2.94714 4.75799C2.86618 4.83745 2.81821 4.94838 2.81821 5.06231L2.80322 12.5863C2.80322 12.7002 2.8467 12.8067 2.92765 12.8876C3.0086 12.9686 3.11504 13.012 3.22897 13.012H5.60654C5.78943 13.012 5.93634 12.8651 5.93634 12.6822C5.93634 12.4993 5.78943 12.3524 5.60654 12.3524H3.46283L3.47632 5.50155H6.31861C6.56297 5.50155 6.76085 5.30367 6.76085 5.05931V2.65326H11.1382V12.3974H9.09944C8.91655 12.3974 8.76964 12.5443 8.76964 12.7272C8.76964 12.9101 8.91655 13.057 9.09944 13.057H11.3721C11.6074 13.057 11.7978 12.8666 11.7978 12.6313V2.4194C11.7978 2.18404 11.6074 1.99365 11.3721 1.99365ZM6.10124 4.84194H3.80612L6.05627 2.65326H6.10274V4.84194H6.10124ZM10.4486 6.76079C10.4486 6.5779 10.3017 6.43099 10.1188 6.43099H4.78204C4.59914 6.43099 4.45223 6.5779 4.45223 6.76079C4.45223 6.94368 4.59914 7.09059 4.78204 7.09059H10.1188C10.3017 7.09059 10.4486 6.94368 10.4486 6.76079ZM10.4486 7.88512C10.4486 7.70223 10.3017 7.55531 10.1188 7.55531H4.78204C4.59914 7.55531 4.45223 7.70223 4.45223 7.88512C4.45223 8.06801 4.59914 8.21492 4.78204 8.21492H10.1188C10.3017 8.21492 10.4486 8.06801 10.4486 7.88512ZM10.4486 9.02443C10.4486 8.84154 10.3017 8.69463 10.1188 8.69463H4.78204C4.59914 8.69463 4.45223 8.84154 4.45223 9.02443C4.45223 9.20732 4.59914 9.35424 4.78204 9.35424H10.1188C10.3017 9.35424 10.4486 9.20732 10.4486 9.02443ZM7.35299 9.89991C7.33051 9.87742 7.29303 9.87892 7.27204 9.90141L6.46852 10.7724C6.43554 10.8084 6.46103 10.8668 6.5105 10.8668H7.03069V12.168C7.03069 12.201 7.05767 12.231 7.09065 12.231H7.63033C7.66331 12.231 7.69029 12.201 7.69029 12.168V10.8683H8.21048C8.26145 10.8683 8.28693 10.8069 8.24945 10.7709L7.35299 9.89991Z"
fill="#272636"/>
</svg>
......@@ -17,6 +17,7 @@
.custom-layout-content_mobile {
overflow-x: hidden;
background: white;
.real-content {
width: 100vw;
......
......@@ -18,6 +18,11 @@
.t-table__body {
max-height: 120px;
td {
font-weight: 500;
font-size: 12px;
}
}
}
}
......@@ -2,69 +2,79 @@ import './index.less'
import {Component} from "react";
import CustomTable from '@/js/components/Table/index';
import {isMobile} from '@/js/utils/tool';
import {ContractUserList} from "@/js/utils/api/contract";
import {getAdminUserList, getUserName} from '@/js/utils/local';
class ContractAccount extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
list: [],
name: 'aa'
loading: false,
}
this.columns = [
{
colKey: 'ddd',
title: '用户名',
align: 'center'
align: 'center',
cell: ({rowIndex, row}) => {
if (row.exchange_users_id) {
return getUserName(row.exchange_users_id)
}
return 'null'
},
},
{
colKey: 'd2',
colKey: 'exchange',
title: '交易所',
align: 'center'
align: 'center',
},
{
colKey: 'd4',
title: '现货余额',
colKey: 'margin_balance',
title: '保证金余额',
align: 'center'
},
{
colKey: 'd6',
colKey: 'available_balance',
title: '可用余额',
align: 'center'
align: 'center',
cell: ({rowIndex, row}) => {
return (
<span style={{
color: '#12B981'
}}>{row.available_balance}</span>
)
},
},
];
}
changeList = () => {
changeLoding(value: boolean) {
this.setState({
list: [{
ddd: '111',
d2: '222',
d3: '333',
d4: '444',
d5: '555',
}]
loading: value,
})
setTimeout(() => {
this.setState({
list: [{
ddd: '111',
d2: '222',
d3: '333',
d4: '444',
d5: '555',
}, {
ddd: '111',
d2: '222',
d3: '333',
d4: '444',
d5: '555',
},]
})
}, 3000)
}
componentDidMount() {
// this.changeList();
async changeList() {
try {
this.changeLoding(true);
const res: any = await ContractUserList();
if (res.code == 0) {
this.setState({
list: res.data.data
})
}
this.changeLoding(false);
} catch (e) {
console.log(e)
}
}
async componentDidMount() {
// 获取用户列表
await getAdminUserList();
this.changeList();
}
render() {
......@@ -72,7 +82,8 @@ class ContractAccount extends Component<any, any> {
<div className={['contract-account-table', isMobile() ? 'contract-account-table__mobile' : ""].join(' ')}>
<div className='contract-account-label'>合约账户</div>
<div className='contract-account-table-box'>
<CustomTable columns={this.columns} data={this.state.list}></CustomTable>
<CustomTable columns={this.columns} data={this.state.list}
loading={this.state.loading}></CustomTable>
</div>
</div>
)
......
......@@ -101,7 +101,6 @@
.table-direction {
font-weight: 400;
font-size: 14px;
color: #0E9D6D;
}
.table-col-left {
......
......@@ -11,7 +11,8 @@ import {getDomRect} from '@/js/utils/dom';
import {isMobile} from '@/js/utils/tool';
import CustomButton from '@/js/components/Button';
import CustomDialog from '../TradeDialog/index';
import {getContractHelpList} from '@/js/utils/local';
import {ClosePosition} from '@/js/utils/api/multipleUse';
// 定义常量
const dom_id = 'contract-trade';
......@@ -94,13 +95,23 @@ class ContractTrade extends Component<any, any> {
store.dispatch({type: 'count', data: 1,});
}
componentDidMount() {
async componentDidMount() {
this.getTableHeight();
// store.subscribe(() => {
// this.setState({
// num: store.getState().count,
// })
// })
// 获取辅助列表
await getContractHelpList();
}
// 一键平仓
onClosePosition() {
ClosePosition({
ids: [],
});
}
// 打开弹窗
......@@ -129,7 +140,7 @@ class ContractTrade extends Component<any, any> {
return (
<div className='hold-position-extension'>
<CustomButton onClick={this.openDialog}>开始交易</CustomButton>
<CustomButton>一键平仓</CustomButton>
<CustomButton onClick={this.onClosePosition}>一键平仓</CustomButton>
</div>
)
case table_CurrentConsignment:
......@@ -193,6 +204,7 @@ class ContractTrade extends Component<any, any> {
}></HistoryTransaction>
</div>
<CustomDialog visible={this.state.dialog_visible} onClose={this.closeDialog}></CustomDialog>
</div>
)
}
......
......@@ -4,6 +4,9 @@ import CustomTable from '@/js/components/Table/index';
import {isMobile} from '@/js/utils/tool';
import Pagination from '@/js/components/Pagination';
import CustomButton from '@/js/components/Button';
import {ContractCurrentEntrustment} from '@/js/utils/api/contract';
import {getDirectionColor} from '@/js/utils/trade';
import {getLocalContractHelper, getUserName} from '@/js/utils/local';
// 当前委托
class CurrentConsignment extends Component<any, any> {
......@@ -14,6 +17,7 @@ class CurrentConsignment extends Component<any, any> {
pageNum: 1,
pageSize: 10,
total: 0,
isFirst: true,
}
this.columns = [
{
......@@ -66,22 +70,24 @@ class CurrentConsignment extends Component<any, any> {
];
}
pageChange(value: number) {
pageChange = (value: number) => {
this.setState({
pageNum: value
})
// 请求接口
this.getTableList();
}
// pc表格
pcTable() {
return (
<CustomTable columns={this.columns} data={this.state.list} pageNum={this.state.pageNum}
pageSize={this.state.pageSize} total={this.state.total} pagination={true}
className={props.className}
onPageChange={this.pageChange}
></CustomTable>
)
// return (
// <CustomTable columns={this.columns} data={this.state.list} pageNum={this.state.pageNum}
// pageSize={this.state.pageSize} total={this.state.total} pagination={true}
// className={props.className}
// onPageChange={this.pageChange}
// ></CustomTable>
// )
return '';
}
// 手机表格
......@@ -93,15 +99,17 @@ class CurrentConsignment extends Component<any, any> {
<div key={index} className='table-row'>
<div className='table-row-line'>
<div className={'table-pairs'}>
BTCUSDT
{item.symbol}
</div>
<div className={'table-time'}>
2022/07/01 08:33:45
{item.working_time}
</div>
</div>
<div className='table-row-line'>
<div className={['table-direction', true ? 'green' : ''].join(' ')}>
限价/开多
<div className={['table-direction'].join(' ')} style={{
color: getDirectionColor(item.position_side)
}}>
{getLocalContractHelper('position_side', item.position_side)}
</div>
<CustomButton>撤销</CustomButton>
</div>
......@@ -112,7 +120,7 @@ class CurrentConsignment extends Component<any, any> {
用户
</div>
<div className={'table-col-value'}>
{item.ddd}
{getUserName(item.exchange_users_id)}
</div>
</div>
<div className={'table-col__line'}>
......@@ -120,15 +128,15 @@ class CurrentConsignment extends Component<any, any> {
开仓价格
</div>
<div className={'table-col-value'}>
{item.d6}
{item.price}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
成交数量
交易方向
</div>
<div className={'table-col-value'}>
{item.d5}
{item.side}
</div>
</div>
</div>
......@@ -138,7 +146,7 @@ class CurrentConsignment extends Component<any, any> {
交易所
</div>
<div className={'table-col-value'}>
Binance
{item.exchange}
</div>
</div>
<div className={'table-col__line'}>
......@@ -146,7 +154,7 @@ class CurrentConsignment extends Component<any, any> {
数量
</div>
<div className={'table-col-value'}>
27120.00
{item.qty}
</div>
</div>
<div className={'table-col__line'}>
......@@ -154,7 +162,7 @@ class CurrentConsignment extends Component<any, any> {
状态
</div>
<div className={['table-col-value', 'green'].join(' ')}>
+100 USDT
{item.status}
</div>
</div>
</div>
......@@ -177,7 +185,35 @@ class CurrentConsignment extends Component<any, any> {
}
</div>
)
}
async getTableList() {
try {
let params = {
page: this.state.pageNum,
limit: this.state.pageSize,
}
const res: any = await ContractCurrentEntrustment(params);
if (res.code == 0) {
this.setState({
list: res.data.data,
total: res.data.total,
})
}
} catch (e) {
console.log(e)
}
}
shouldComponentUpdate(nextProps: Readonly<any>, nextState: Readonly<any>, nextContext: any) {
if (nextProps['v-if'] && nextState.isFirst) {
this.setState({
isFirst: false,
})
// 请求接口
this.getTableList();
}
return true;
}
render() {
......
......@@ -3,15 +3,20 @@ import {Component} from "react";
import CustomTable from '@/js/components/Table/index';
import {isMobile} from '@/js/utils/tool';
import Pagination from '@/js/components/Pagination';
import {ContractHistoryTransaction} from '@/js/utils/api/contract';
import {getDirectionColor, getSuccessColor} from '@/js/utils/trade';
import {getLocalContractHelper, getUserName} from '@/js/utils/local';
class HistoryTransaction extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
list: [{}],
list: [],
pageNum: 1,
pageSize: 10,
total: 0,
isFirst: true,
}
this.columns = [
{
......@@ -74,21 +79,23 @@ class HistoryTransaction extends Component<any, any> {
];
}
pageChange(value: number) {
pageChange = (value: number) => {
this.setState({
pageNum: value
})
// 请求接口
this.getTableList();
}
// pc表格
pcTable() {
return (
<CustomTable columns={this.columns} data={this.state.list} pageNum={this.state.pageNum}
pageSize={this.state.pageSize} total={this.state.total} pagination={true}
className={props.className}
onPageChange={this.pageChange}></CustomTable>
)
// return (
// <CustomTable columns={this.columns} data={this.state.list} pageNum={this.state.pageNum}
// pageSize={this.state.pageSize} total={this.state.total} pagination={true}
// className={props.className}
// onPageChange={this.pageChange}></CustomTable>
// )
return ''
}
// 手机表格
......@@ -100,19 +107,21 @@ class HistoryTransaction extends Component<any, any> {
<div key={index} className='table-row'>
<div className='table-row-line'>
<div className={'table-pairs'}>
BTCUSDT
{item.symbol}
</div>
<div className={'table-time'}>
2022/07/01 08:33:45
{item.trading_time}
</div>
</div>
<div className='table-row-line'>
<div className={['table-direction', true ? 'green' : ''].join(' ')}>
限价/开多
<div className={['table-direction'].join(' ')} style={{
color: getDirectionColor(item.position_side)
}}>
{getLocalContractHelper('position_side', item.position_side)}
</div>
<div className={'table-time'}>
<span>更新时间 </span>
2022/07/01 08:33:45
{item.updated_at}
</div>
</div>
<div className='table-row-line'>
......@@ -122,7 +131,7 @@ class HistoryTransaction extends Component<any, any> {
用户
</div>
<div className={'table-col-value'}>
{item.ddd}
{getUserName(item.exchange_users_id)}
</div>
</div>
<div className={'table-col__line'}>
......@@ -130,7 +139,7 @@ class HistoryTransaction extends Component<any, any> {
开仓价格
</div>
<div className={'table-col-value'}>
{item.d6}
{item.price}
</div>
</div>
<div className={'table-col__line'}>
......@@ -138,7 +147,7 @@ class HistoryTransaction extends Component<any, any> {
成交数量
</div>
<div className={'table-col-value'}>
{item.d5}
{parseFloat(item.quantity + '')}
</div>
</div>
</div>
......@@ -148,23 +157,27 @@ class HistoryTransaction extends Component<any, any> {
交易所
</div>
<div className={'table-col-value'}>
Binance
{item.exchange}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
数量
买卖方向
</div>
<div className={'table-col-value'}>
27120.00
{getLocalContractHelper('side', item.side)}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
状态
</div>
<div className={['table-col-value', 'green'].join(' ')}>
+100 USDT
<div className={['table-col-value'].join(' ')} style={{
color: getSuccessColor(item.result.code)
}}>
{
item.result.code === '200' ? '成功' : '失败'
}
</div>
</div>
</div>
......@@ -190,6 +203,36 @@ class HistoryTransaction extends Component<any, any> {
}
shouldComponentUpdate(nextProps: Readonly<any>, nextState: Readonly<any>, nextContext: any) {
if (nextProps['v-if'] && nextState.isFirst) {
this.setState({
isFirst: false,
})
// 请求接口
this.getTableList();
}
return true;
}
async getTableList() {
try {
let params = {
page: this.state.pageNum,
limit: this.state.pageSize,
}
const res: any = await ContractHistoryTransaction(params);
if (res.code == 0) {
console.log(res.data.data[0])
this.setState({
list: res.data.data,
total: res.data.total,
})
}
} catch (e) {
console.log(e)
}
}
render() {
const props = this.props;
if (props['v-if']) {
......
......@@ -4,26 +4,19 @@ import CustomTable from '@/js/components/Table/index';
import {isMobile} from '@/js/utils/tool';
import CustomButton from '@/js/components/Button';
import Pagination from '@/js/components/Pagination';
import {ContractHoldingPosition} from '@/js/utils/api/contract';
import {getLocalContractHelper, getUserName} from '@/js/utils/local';
import {isRise, isPlus, getDirectionColor} from '@/js/utils/trade';
import {ClosePosition} from '@/js/utils/api/multipleUse'
class HoldingPosition extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
list: [{
ddd: '用户名',
d2: "交易所",
d3: '交易对',
d4: '持仓方向',
d5: '策略',
d6: '开仓价格',
d7: '标记价格',
d8: '未实现盈亏',
d9: '操作',
time: '2022/07/01 08:33:45'
}],
list: [],
pageNum: 1,
pageSize: 10,
total: 20,
total: 0,
}
this.columns = [
{
......@@ -77,21 +70,23 @@ class HoldingPosition extends Component<any, any> {
}
// 页码改变
pageChange(value: number) {
pageChange = (value: number) => {
this.setState({
pageNum: value
})
// 请求接口
this.getTableList();
}
// pc表格
pcTable() {
return (
<CustomTable columns={this.columns} data={this.state.list} pageNum={this.state.pageNum}
pageSize={this.state.pageSize} total={this.state.total} pagination={true}
className={props.className}
onPageChange={this.pageChange}></CustomTable>
)
return '';
// return (
// <CustomTable columns={this.columns} data={this.state.list} pageNum={this.state.pageNum}
// pageSize={this.state.pageSize} total={this.state.total} pagination={true}
// className={props.className}
// onPageChange={this.pageChange}></CustomTable>
// )
}
// 手机表格
......@@ -103,18 +98,22 @@ class HoldingPosition extends Component<any, any> {
<div key={index} className='table-row'>
<div className='table-row-line'>
<div className={'table-pairs'}>
{item.d3}
<span>x3</span>
{item.symbol}
<span> x{item.leverage}</span>
</div>
<div className={'table-time'}>
{item.time}
{item.created_at}
</div>
</div>
<div className='table-row-line'>
<div className={'table-direction'}>
{item.d4}
<div className={'table-direction'} style={{
color: getDirectionColor(item.position_side)
}}>
{getLocalContractHelper('position_side', item.position_side)}
</div>
<CustomButton>平仓</CustomButton>
<CustomButton onClick={ClosePosition.bind(this, {
ids: [item.id]
})}>平仓</CustomButton>
</div>
<div className='table-row-line'>
<div className={'table-col-left'}>
......@@ -123,7 +122,7 @@ class HoldingPosition extends Component<any, any> {
用户
</div>
<div className={'table-col-value'}>
{item.ddd}
{getUserName(item.exchange_users_id)}
</div>
</div>
<div className={'table-col__line'}>
......@@ -131,7 +130,7 @@ class HoldingPosition extends Component<any, any> {
开仓价格
</div>
<div className={'table-col-value'}>
{item.d6}
{item.entry_price}
</div>
</div>
<div className={'table-col__line'}>
......@@ -139,7 +138,7 @@ class HoldingPosition extends Component<any, any> {
策略
</div>
<div className={'table-col-value'}>
{item.d5}
{item.strategy}
</div>
</div>
</div>
......@@ -149,7 +148,7 @@ class HoldingPosition extends Component<any, any> {
交易所
</div>
<div className={'table-col-value'}>
Binance
{item.exchange}
</div>
</div>
<div className={'table-col__line'}>
......@@ -157,7 +156,7 @@ class HoldingPosition extends Component<any, any> {
标记价格
</div>
<div className={'table-col-value'}>
27120.00
{item.market_price}
</div>
</div>
<div className={'table-col__line'}>
......@@ -165,7 +164,7 @@ class HoldingPosition extends Component<any, any> {
盈亏
</div>
<div className={['table-col-value', 'green'].join(' ')}>
+100 USDT
{isPlus(item.unrealized_profit)} USDT
</div>
</div>
</div>
......@@ -191,6 +190,28 @@ class HoldingPosition extends Component<any, any> {
}
async getTableList() {
try {
let params = {
page: this.state.pageNum,
limit: this.state.pageSize,
}
const res: any = await ContractHoldingPosition(params);
if (res.code == 0) {
this.setState({
list: res.data.data,
total: res.data.total,
})
}
} catch (e) {
console.log(e)
}
}
componentDidMount() {
this.getTableList();
}
render() {
const props = this.props;
if (props['v-if']) {
......
......@@ -17,7 +17,15 @@
.trade-form-item__label {
text-align: right;
width: 60px;
width: 70px;
}
.required {
&:before {
content: '*';
color: red;
padding-right: 2px;
}
}
.trade-form-item__value {
......@@ -25,6 +33,14 @@
box-sizing: border-box;
margin-left: 12px;
.trade-form-submit {
float: right;
& > :nth-child(1) {
margin-right: 12px;
}
}
.trade-form-input-suffix {
background: #EAECEF;
width: 32px;
......
......@@ -2,29 +2,17 @@ import './index.less'
import {Component} from "react";
import CustomSelect from "@/js/components/Select";
import CustomButton from '@/js/components/Button';
import {isMobile} from '@/js/utils/tool'
import {isMobile} from '@/js/utils/tool';
import {getLocalUserList} from '@/js/utils/local';
class TradeSelect extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
userSelect: {
label: '全部',
label: '用户',
value: '',
options: [
{
label: '全部',
value: 'all'
},
{
label: '公司账户',
value: '1'
},
{
label: '卫总',
value: '2'
}
],
options: getLocalUserList(),
},
pairsSelect: {
label: '交易对',
......
......@@ -21,7 +21,6 @@ class Index extends Component<MyProps, MyState> {
componentDidMount() {
console.log(isMobile())
// 请求接口
}
shouldComponentUpdate(next: any, old: any): boolean {
......
.login-page {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
.label {
color: #C99400;
font-size: 16px;
font-weight: 600;
margin: 20px 0;
}
.login-form-submit-btn {
background: #C99400;
border: none;
--ripple-color: #C99400 !important;
&:hover {
background: #C99400;
border: none;
--ripple-color: #C99400 !important;
}
}
}
import './index.less';
import {Component} from "react";
import {Head} from "@inertiajs/react";
import {show_message} from "@/js/utils/tdesign";
import {Form, Button} from 'tdesign-react';
import {DesktopIcon, LockOnIcon} from 'tdesign-icons-react';
import CustomInput from '@/js/components/Input';
import {useLogin} from '@/js/utils/api/auth';
import Cookies from "js-cookie";
const {FormItem} = Form;
export default class Login extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
code: ''
}
}
async login() {
try {
const res: any = await useLogin({
username: this.state.username,
password: this.state.password,
})
if (res.code == 0) {
show_message('登录成功', 'success');
Cookies.set('token', res.data.access_token);
window.location.replace('/');
}
} catch (e) {
console.log(e)
}
}
onSubmit = (e) => {
const {username, password, code} = this.state;
if (!username || !password || !code) {
show_message('请填写完整表单', 'error');
return;
}
// 可以提交
this.login();
};
onReset = (e) => {
console.log(e);
show_message('重置成功', 'success');
};
inputChange = (value: string, name: string) => {
this.setState({
[name]: value
})
}
render() {
return (
<div>
<Head title={this.props.info.title}></Head>
<div className='login-page'>
<div className='label'>登录</div>
<div style={
{
width: '80vw'
}
}>
<Form statusIcon={true} onSubmit={this.onSubmit} onReset={this.onReset} colon={true}
labelWidth={0}>
<FormItem name="account">
<CustomInput name='username' value={this.state.username} clearable={false}
prefixIcon={<DesktopIcon/>}
placeholder="请输入账户名" onChange={this.inputChange}></CustomInput>
</FormItem>
<FormItem name="password">
<CustomInput name='password' value={this.state.password} type="password"
prefixIcon={<LockOnIcon/>}
clearable={false}
placeholder="请输入密码" onChange={this.inputChange}></CustomInput>
</FormItem>
<FormItem name="code">
<CustomInput name='code' value={this.state.code} clearable={false}
prefixIcon={<DesktopIcon/>}
placeholder="请输入验证码" onChange={this.inputChange}></CustomInput>
</FormItem>
<FormItem>
<Button className={"login-form-submit-btn"} theme="primary" type="submit" block>
登录
</Button>
</FormItem>
</Form>
</div>
</div>
</div>
);
}
}
......@@ -7,4 +7,8 @@
border: none;
height: 24px;
--ripple-color: #C99400 !important;
svg {
padding-right: 4px;
}
}
......@@ -2,14 +2,15 @@ import './index.less'
import {Button as TButton} from 'tdesign-react'
export default function (props) {
const {onClick, className} = props;
const {onClick, className, icon} = props;
const realIcon = icon ?? '';
const btnClick = () => {
if (onClick) {
onClick()
}
}
return (
<TButton onClick={btnClick}
<TButton onClick={btnClick} icon={realIcon}
className={['custom-reset-t-button', className ?? ''].join(' ')}>{props.children}</TButton>
)
}
.c-reset-input {
.t-is-focused {
border-color: #C99400;
box-shadow: none;
.t-input__prefix-icon {
.t-icon {
color: #C99400;
}
}
&:hover {
border-color: #C99400;
box-shadow: none;
......
import './index.less';
import {useState} from 'react';
import {Input} from 'tdesign-react';
export default function (props) {
const {align, className, type, suffixIcon} = props;
const {align, className, type, suffixIcon, name, value, prefixIcon, placeholder} = props;
const realAlign = align ?? 'left';
const realType = type ?? 'text';
const realName = name ?? '';
const realSuffixIcon = suffixIcon ?? '';
const [value, setValue] = useState('');
const realPrefixIcon = prefixIcon ?? '';
const realPlaceholder = placeholder ?? '';
// 通知父组件
const inputChange = (value: number) => {
if (props.onChange) {
props.onChange(value);
props.onChange(value, realName);
}
}
return (
<Input
className={['c-reset-input', className].join('')}
placeholder=''
placeholder={realPlaceholder}
value={value}
type={realType}
align={realAlign}
suffixIcon={realSuffixIcon}
prefixIcon={realPrefixIcon}
clearable
onChange={(value) => {
setValue(value);
inputChange(value);
}}
onClear={() => {
......
......@@ -8,6 +8,7 @@ class InputNumber extends Component<any, any> {
this.state = {
value: 0,
}
this.name = props.name ?? '';
}
onSet = (value: number) => {
......@@ -26,10 +27,11 @@ class InputNumber extends Component<any, any> {
}
inputChange = (value: number) => {
if (typeof value === 'number') {
// 提交输入框的值
if (this.props.onChange) {
this.props.onChange(value);
this.props.onChange(value, this.name);
}
}
......@@ -52,7 +54,7 @@ class InputNumber extends Component<any, any> {
onChange={this.inputChange}
theme="normal"
defaultValue={1}
value={this.state.value}
value={this.props.value}
max={1000} min={0}/>
{
realAddAndSubtract && (
......
......@@ -22,3 +22,14 @@
}
}
}
.reset-t-pagination__mobile {
padding: 12px;
.t-pagination__number {
&:hover {
color: white;
}
}
}
import './index.less';
import {Pagination as TPagination} from 'tdesign-react';
import {Component} from "react";
import {isMobile} from '@/js/utils/tool'
class Pagination extends Component<any, any> {
constructor(props) {
......@@ -15,9 +16,11 @@ class Pagination extends Component<any, any> {
render() {
const props = this.props;
return (
<div className='reset-t-pagination-box'>
<div className={['reset-t-pagination-box', isMobile() ? 'reset-t-pagination__mobile' : ''].join(' ')}>
<TPagination
className={'reset-t-pagination'}
foldedMaxPageBtn={2}
maxPageBtn={3}
className={['reset-t-pagination'].join(' ')}
defaultCurrent={props.pageNum}
defaultPageSize={props.pageSize}
pageSizeOptions={[]}
......
import './index.less';
import React, {useState} from 'react';
import {Select as TSelect} from 'tdesign-react';
export default function (props) {
const {options, className, clearable, multiple, autoWidth, popupProps} = props;
const {options, className, clearable, multiple, autoWidth, popupProps, name, value} = props;
// autoWidth默认为true
const propsAutoWidth = autoWidth ?? true;
const propsPopupProps = popupProps ?? {};
const [value, setValue] = useState('');
const [list, setList] = useState([]);
const realName = name ?? '';
const onChange = (value) => {
if (multiple) {
setList(value);
} else {
setValue(value);
if (props.onChange) {
props.onChange(value, realName);
}
};
return (
<TSelect
className={className}
value={multiple ? list : value}
value={value}
clearable={clearable}
autoWidth={propsAutoWidth}
popupProps={propsPopupProps}
......
import './index.less';
import {Loading as TLoading} from 'tdesign-react'
const isShow = (value: boolean) => {
if (typeof value === 'boolean') {
return value ? '' : 'none';
}
return ''
}
export default function (props) {
return (
<TLoading style={{
display: isShow(props['v-show'])
}}></TLoading>
)
}
......@@ -4,5 +4,10 @@
font-weight: 500;
font-size: 12px;
color: #707A8A;
}
td {
white-space: nowrap;
}
}
......@@ -17,7 +17,7 @@ class Index extends Component<any, any> {
const {columns, data, style, pagination, pageNum, pageSize, total, className, maxHeight} = this.props;
return (
<div style={style ?? null} className={className}>
<TTable rowKey={'index'} columns={columns} data={data}
<TTable rowKey={'index'} loading={this.props.loading ?? false} columns={columns} data={data}
className={['reset-t-table'].join(' ')}
maxHeight={maxHeight ?? ''}
>
......
......@@ -4,3 +4,22 @@
export const table_HoldingPosition = '1';
export const table_CurrentConsignment = '2';
export const table_HistoryTransaction = '3';
/**
* 合约交易字段
*/
export const ContractTradeField = {
users: 'user_id', // 用户
pairs: 'symbol', // 交易对
contract_strategy_id: 'contract_strategy_id', // 策略
side: 'side', // 方向
levers: 'leverage', // 杠杆
amount: 'amount', // 买入金额
stop_surplus: 'stop_surplus', // 止盈
stop_loss: 'stop_loss', // 止损
quantity_rate: 'quantity_rate', // 数量百分比
position_side: 'position_side', // 买卖类型
order_type: 'order_type', // 交易类型
limit_price: 'limit_price', // 限价价格
}
import request from '../request';
import {getHeaders} from './index'
// 登录
export const useLogin = (data: any) => {
return request.post('/admin-api/api/login', data);
}
// 获取用户列表
export const getUserList = () => {
return request.get('/admin-api/api/users', {
headers: getHeaders(),
});
}
import request from '../request';
import {getHeaders} from './index'
// 合约交易
// 持有列表
export const ContractUserList = () => {
return request.get('/admin-api/api/contract/assets', {
headers: getHeaders(),
});
}
// 持有仓位
export const ContractHoldingPosition = (data: any) => {
return request.get('/admin-api/api/contract/position', {
params: data,
headers: getHeaders(),
});
}
// 当前委托
export const ContractCurrentEntrustment = (data: any) => {
return request.get('/admin-api/api/contract/entrust', {
params: data,
headers: getHeaders(),
});
}
// 历史成交
export const ContractHistoryTransaction = (data: any) => {
return request.get('/admin-api/api/contract/history', {
params: data,
headers: getHeaders(),
});
}
// 平仓
export const ContractClosePosition = (data: any) => {
return request.post('/admin-api/api/contract/close', data, {
headers: getHeaders(),
});
}
// 合约辅助
export const ContractAssist = () => {
return request.get('/admin-api/api/helper/contracts', {
headers: getHeaders(),
});
}
import cookie from 'js-cookie';
// api公共配置
// 用户token
export const getUserCookie = () => {
return cookie.get('token');
};
// 获取请求头
export const getHeaders = () => {
return {
'Authorization': 'Bearer ' + getUserCookie()
}
}
import {getHeaders} from './index';
import {ContractClosePosition} from './contract';
import {show_message} from "../tdesign";
import {loading} from 'tdesign-react'
/**
* 复用的接口
*/
// 平仓
export const ClosePosition = async (data: any, needLoading: boolean = true) => {
try {
let loadingInstance: any = null;
if (needLoading) {
loadingInstance = loading({
size: '20px',
loading: true,
});
}
const res: any = await ContractClosePosition(data);
if (needLoading && loadingInstance) {
loadingInstance.hide()
}
if (res.code == 0) {
show_message('平仓成功', 'success');
// 刷新页面
window.location.reload();
}
} catch (e) {
console.log(e)
}
}
import {getUserList} from './api/auth';
import {ContractAssist} from './api/contract';
// 用户列表key
export const localUserKey = 'trade_user';
// 合约辅助列表key
export const localContractHelpKey = 'contract_help';
// 本地缓存是否到期
export const isLocalUserExpire = (key: string, expired: number) => {
let users = window.localStorage.getItem(key);
if (users) {
users = JSON.parse(users);
const time = users.time;
const now = new Date().valueOf();
if (now - time > expired) {
return true;
}
} else {
return true;
}
return false;
}
// 数据存本地
export const setLocalData = (key: string, users: any[]) => {
let params = {
time: new Date().valueOf(),
list: users
}
window.localStorage.setItem(key, JSON.stringify(params));
}
// 取本地的用户名
export const getUserName = (id: number | string) => {
let users = window.localStorage.getItem(localUserKey);
if (users) {
users = JSON.parse(users);
const list = users.list;
let obj = list.find((item: any) => item.id == id);
if (obj) {
return obj.name;
}
}
return 'Null';
}
// 取本地的用户列表
export const getLocalUserList = (change: boolean = true, add: boolean = true) => {
let users = window.localStorage.getItem(localUserKey);
if (users) {
users = JSON.parse(users);
const list = users.list;
if (list && list.length) {
// 是否转换数据,用作select
if (change) {
let newList: any[] = list.map((item: any) => {
return {
label: item.name,
value: item.id,
}
});
if (add) {
// 头部添加
newList.unshift({
label: '全部',
value: '',
})
}
return newList
}
return list;
}
}
return [];
}
// 获取接口数据并存本地
export const getAdminUserList = async () => {
// 清空
// window.localStorage.setItem(localUserKey, '')
if (isLocalUserExpire(localUserKey, 60 * 60 * 1000)) {
try {
const res: any = await getUserList();
if (res.code == 0) {
// 存本地
setLocalData(localUserKey, res.data.data);
}
console.log(res);
} catch (e) {
console.log(e)
}
}
}
// 获取合约辅助列表
export const getContractHelpList = async (skip: boolean = false) => {
// 清空
// window.localStorage.setItem(localContractHelpKey, '')
if (isLocalUserExpire(localContractHelpKey, 24 * 60 * 60 * 1000) || skip) {
try {
const res: any = await ContractAssist();
if (res.code == 0) {
// 存本地
setLocalData(localContractHelpKey, res.data);
}
} catch (e) {
console.log(e)
}
} else {
// 打印本地数据
// const data = window.localStorage.getItem(localContractHelpKey);
// console.log(JSON.parse(data));
}
}
// 获取合约辅助列表中字段值
export const getLocalContractHelper = (key: string, value: string) => {
let users = window.localStorage.getItem(localContractHelpKey);
if (users) {
users = JSON.parse(users);
const data = users.list;
let list = []
if (key == 'order_type') {
list = data.order_type;
} else if (key == 'position_side') {
list = data.position_side;
} else if (key == 'side') {
list = data.side;
}
const obj = list.find((item: any) => item.value == value);
return obj ? obj.label : 'error';
}
}
import axios from 'axios';
import {show_message} from './tdesign';
const mode = import.meta.env.MODE;
const getBaseUrl = () => {
return 'http://dexnav-main.test';
if (mode == 'app') {
return 'http://video_publish.test';
} else {
// 打包
return '';
}
};
const instance = axios.create({
baseURL: getBaseUrl(),
timeout: 60000,
// withCredentials: mode == 'development' ? false : true,
withCredentials: false,
});
// 请求头
instance.interceptors.request.use((config: any) => {
return config;
});
instance.defaults.timeout = 60000;
instance.interceptors.response.use(
(response) => {
const {data} = response;
if (data.code === 0 || data.code == 201 || data.code == 1) {
return data;
} else {
show_message(data.msg || '请求错误', 'error');
return Promise.reject(data.msg);
}
},
(err) => {
if ('response' in err) {
const {message: msg, status} = err.response;
if (status == 401) {
show_message('请登录');
window.location.replace("/login");
return;
}
show_message(msg || '请求错误', 'error');
return err.response;
}
}
);
export default instance;
import {MessagePlugin} from 'tdesign-react'
export const show_message = (
value: string,
type: 'warning' | 'success' | 'info' | 'error' = 'warning',
close: boolean = true
) => {
if (close) {
MessagePlugin.closeAll();
}
if (type == 'warning') {
MessagePlugin.warning(value);
} else if (type == 'success') {
MessagePlugin.success(value);
} else if (type == 'info') {
MessagePlugin.info(value);
} else if (type == 'error') {
MessagePlugin.error(value);
}
// 类型报错-所以用上面的方法
// MessagePlugin[type](value);
};
......@@ -8,3 +8,19 @@ export const isMobile = () => {
export const getRoute = () => {
return window.location;
}
// 表单必填项校验
export const formValidate = (fields: string[], data: any) => {
for (let i = 0; i < fields.length; i++) {
const item = fields[i];
// 字符
if (typeof data[item] === 'string' && !data[item]) {
return false;
}
// 数组
if (Array.isArray(data[item]) && !data[item].length) {
return false;
}
}
return true;
}
// 判断涨跌颜色
export const isRise = (num: number | string) => {
let newNum = num + '';
if (newNum[0] == '-') {
return '#D95E71'
}
return '#0E9D6D'
}
// 是否需要加+
export const isPlus = (num: number | string) => {
let newNum = num + '';
if (newNum[0] != '-' && newNum[0] != '+') {
return '+' + newNum;
}
return newNum;
}
// 方向的颜色
export const getDirectionColor = (direction: string) => {
if (direction == 'LONG') {
return '#0E9D6D'
}
return '#D95E71'
}
// 成功失败的颜色
export const getSuccessColor = (status: string) => {
if (status == '200') {
return '#0E9D6D'
}
return '#D95E71'
}
......@@ -16,6 +16,8 @@
Route::group([
'namespace' => '\App\Http\Controllers\Web',
], function () {
// 登录
Route::get('/login', 'AuthController@index')->name('auth.index');
// 现货交易
Route::get('/', 'TradeController@spot')->name('trade.spot');
// 合约交易
......
......@@ -9,7 +9,9 @@ export default defineConfig({
input: ['resources/js/app.jsx'], refresh: true, // 构建ssr
ssr: 'resources/js/ssr.jsx',
}), React(), viteCompression(), svgr()], server: {
port: 3008, host: '127.0.0.1', proxy: {},
port: 3008, host: '127.0.0.1', proxy: {
'/admin-api': 'http://dexnav-main.test'
},
}, optimizeDeps: {
esbuildOptions: {
loader: {'.tsx': 'jsx'}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment