Commit 618e46b5 by haojie

1

parent 303affeb
...@@ -21,5 +21,6 @@ ...@@ -21,5 +21,6 @@
.real-content { .real-content {
width: 100vw; width: 100vw;
border: none;
} }
} }
...@@ -34,6 +34,8 @@ class ContractTrade extends Component<any, any> { ...@@ -34,6 +34,8 @@ class ContractTrade extends Component<any, any> {
[table_CurrentConsignment]: false, [table_CurrentConsignment]: false,
[table_HistoryTransaction]: false, [table_HistoryTransaction]: false,
}, },
// 筛选条件
filter: {}
} }
} }
...@@ -133,6 +135,11 @@ class ContractTrade extends Component<any, any> { ...@@ -133,6 +135,11 @@ class ContractTrade extends Component<any, any> {
return ['spread-out-table', isMobile() ? "spread-out-table__mobile" : ""].join(' ') return ['spread-out-table', isMobile() ? "spread-out-table__mobile" : ""].join(' ')
} }
// 撤销委托
onCancelEntrust = () => {
this.currentConsignment.tableContractRevoke();
}
// 当前显示的按钮-根据对应的表格显示 // 当前显示的按钮-根据对应的表格显示
currentExtensionButtons() { currentExtensionButtons() {
switch (this.state.currentGroupButton) { switch (this.state.currentGroupButton) {
...@@ -146,7 +153,7 @@ class ContractTrade extends Component<any, any> { ...@@ -146,7 +153,7 @@ class ContractTrade extends Component<any, any> {
case table_CurrentConsignment: case table_CurrentConsignment:
return ( return (
<div className='hold-position-extension'> <div className='hold-position-extension'>
<CustomButton>一键撤销</CustomButton> <CustomButton onClick={this.onCancelEntrust}>多选撤销</CustomButton>
</div> </div>
) )
case table_HistoryTransaction: case table_HistoryTransaction:
...@@ -154,6 +161,31 @@ class ContractTrade extends Component<any, any> { ...@@ -154,6 +161,31 @@ class ContractTrade extends Component<any, any> {
} }
} }
FilterChange = (params: any) => {
this.setState({
filter: params,
})
this.getChildTableList(params);
}
// 请求子组件的表格
getChildTableList = (params: any) => {
if (this.state.currentGroupButton === '1') {
this.holdingPositionRef.getTableList(params);
} else if (this.state.currentGroupButton === '2') {
this.currentConsignment.getTableList(params);
} else if (this.state.currentGroupButton === '3') {
this.historyTransaction.getTableList(params);
}
}
// 更新total
updateTotal = (total: number) => {
this.setState({
currentEntrustNum: total,
})
}
render() { render() {
const obj = store.getState(); const obj = store.getState();
return ( return (
...@@ -171,7 +203,7 @@ class ContractTrade extends Component<any, any> { ...@@ -171,7 +203,7 @@ class ContractTrade extends Component<any, any> {
)) ))
} }
</div> </div>
<TradeSelect> <TradeSelect FilterChange={this.FilterChange}>
{ {
this.currentExtensionButtons() this.currentExtensionButtons()
} }
...@@ -182,22 +214,31 @@ class ContractTrade extends Component<any, any> { ...@@ -182,22 +214,31 @@ class ContractTrade extends Component<any, any> {
minHeight: this.state.minHeight minHeight: this.state.minHeight
}}> }}>
{/*持有仓位*/} {/*持有仓位*/}
<HoldingPosition v-if={this.state.tableStatus[table_HoldingPosition]} <HoldingPosition
className={this.getTableClass()} style={ v-if={this.state.tableStatus[table_HoldingPosition]}
className={this.getTableClass()}
ref={dom => this.holdingPositionRef = dom}
style={
{ {
'display': isShow(this.state.currentGroupButton === table_HoldingPosition), 'display': isShow(this.state.currentGroupButton === table_HoldingPosition),
} }
}></HoldingPosition> }></HoldingPosition>
{/*当前委托*/} {/*当前委托*/}
<CurrentConsignment v-if={this.state.tableStatus[table_CurrentConsignment]} <CurrentConsignment
className={this.getTableClass()} style={ v-if={this.state.tableStatus[table_CurrentConsignment]}
className={this.getTableClass()}
ref={dom => this.currentConsignment = dom}
style={
{ {
'display': isShow(this.state.currentGroupButton === table_CurrentConsignment), 'display': isShow(this.state.currentGroupButton === table_CurrentConsignment),
} }
}></CurrentConsignment> } updateTotal={this.updateTotal}></CurrentConsignment>
{/*历史成交*/} {/*历史成交*/}
<HistoryTransaction v-if={this.state.tableStatus[table_HistoryTransaction]} <HistoryTransaction
className={this.getTableClass()} style={ v-if={this.state.tableStatus[table_HistoryTransaction]}
className={this.getTableClass()}
ref={dom => this.historyTransaction = dom}
style={
{ {
'display': isShow(this.state.currentGroupButton === table_HistoryTransaction), 'display': isShow(this.state.currentGroupButton === table_HistoryTransaction),
} }
......
...@@ -7,6 +7,10 @@ import CustomButton from '@/js/components/Button'; ...@@ -7,6 +7,10 @@ import CustomButton from '@/js/components/Button';
import {ContractCurrentEntrustment} from '@/js/utils/api/contract'; import {ContractCurrentEntrustment} from '@/js/utils/api/contract';
import {getDirectionColor} from '@/js/utils/trade'; import {getDirectionColor} from '@/js/utils/trade';
import {getLocalContractHelper, getUserName} from '@/js/utils/local'; import {getLocalContractHelper, getUserName} from '@/js/utils/local';
import {open_loading} from '@/js/utils/tdesign';
import {ContractRevoke} from '@/js/utils/api/multipleUse';
import {show_message} from "@/js/utils/tdesign";
import CustomCheckBox from '@/js/components/CheckBox';
// 当前委托 // 当前委托
class CurrentConsignment extends Component<any, any> { class CurrentConsignment extends Component<any, any> {
...@@ -96,7 +100,7 @@ class CurrentConsignment extends Component<any, any> { ...@@ -96,7 +100,7 @@ class CurrentConsignment extends Component<any, any> {
<div className='contract-real-table__mobile'> <div className='contract-real-table__mobile'>
{ {
this.state.list.map((item, index) => ( this.state.list.map((item, index) => (
<div key={index} className='table-row'> <div key={new Date().valueOf() + index} className='table-row'>
<div className='table-row-line'> <div className='table-row-line'>
<div className={'table-pairs'}> <div className={'table-pairs'}>
{item.symbol} {item.symbol}
...@@ -111,9 +115,14 @@ class CurrentConsignment extends Component<any, any> { ...@@ -111,9 +115,14 @@ class CurrentConsignment extends Component<any, any> {
}}> }}>
{getLocalContractHelper('position_side', item.position_side)} {getLocalContractHelper('position_side', item.position_side)}
</div> </div>
<CustomButton>撤销</CustomButton> <CustomButton onClick={this.tableContractRevoke.bind(this, item)}>撤销</CustomButton>
</div> </div>
<div className='table-row-line'> <div className='table-row-line'>
<CustomCheckBox checked={item.is_checked} onChange={
(value: boolean) => {
item.is_checked = value;
}
}></CustomCheckBox>
<div className={'table-col-left'}> <div className={'table-col-left'}>
<div className={'table-col__line'}> <div className={'table-col__line'}>
<div className={'table-col-label'}> <div className={'table-col-label'}>
...@@ -176,6 +185,37 @@ class CurrentConsignment extends Component<any, any> { ...@@ -176,6 +185,37 @@ class CurrentConsignment extends Component<any, any> {
) )
} }
// 撤销委托
async tableContractRevoke(row?: any) {
let params: any = {};
if (row) {
params = {
ids: [row.id],
}
} else {
// 获取选中的行--is_checked
const list = this.state.list;
const ids: any[] = [];
list.forEach((item: any) => {
if (item.is_checked) {
ids.push(item.id);
}
})
if (!ids.length) {
show_message('未选择行');
return;
}
params = {
ids: ids,
}
}
const status = await ContractRevoke(params);
if (status) {
// 更新表格数据
this.getTableList();
}
}
// 当前表格 // 当前表格
currentTable() { currentTable() {
return ( return (
...@@ -187,21 +227,43 @@ class CurrentConsignment extends Component<any, any> { ...@@ -187,21 +227,43 @@ class CurrentConsignment extends Component<any, any> {
) )
} }
async getTableList() {
async getTableList(filterParams?: any) {
let loading = null;
try { try {
let params = { let params = {
page: this.state.pageNum, page: this.state.pageNum,
limit: this.state.pageSize, limit: this.state.pageSize,
} }
if (filterParams) {
params = {
...params,
...filterParams,
}
}
loading = open_loading();
const res: any = await ContractCurrentEntrustment(params); const res: any = await ContractCurrentEntrustment(params);
if (res.code == 0) { if (res.code == 0) {
res.data.data.forEach((item: any) => {
item.is_checked = false;
})
this.setState({ this.setState({
list: res.data.data, list: JSON.parse(JSON.stringify(res.data.data)),
total: res.data.total, total: res.data.total,
}) })
// 通知父组件更新total
if (this.props.updateTotal) {
this.props.updateTotal(res.data.total);
}
}
if (loading) {
loading.hide();
} }
} catch (e) { } catch (e) {
console.log(e) console.log(e)
if (loading) {
loading.hide();
}
} }
} }
......
...@@ -4,8 +4,9 @@ import CustomTable from '@/js/components/Table/index'; ...@@ -4,8 +4,9 @@ import CustomTable from '@/js/components/Table/index';
import {isMobile} from '@/js/utils/tool'; import {isMobile} from '@/js/utils/tool';
import Pagination from '@/js/components/Pagination'; import Pagination from '@/js/components/Pagination';
import {ContractHistoryTransaction} from '@/js/utils/api/contract'; import {ContractHistoryTransaction} from '@/js/utils/api/contract';
import {getDirectionColor, getSuccessColor} from '@/js/utils/trade'; import {getDirectionColor, getSuccessColor, getSuccessText} from '@/js/utils/trade';
import {getLocalContractHelper, getUserName} from '@/js/utils/local'; import {getLocalContractHelper, getUserName} from '@/js/utils/local';
import {open_loading} from '@/js/utils/tdesign';
class HistoryTransaction extends Component<any, any> { class HistoryTransaction extends Component<any, any> {
...@@ -173,10 +174,10 @@ class HistoryTransaction extends Component<any, any> { ...@@ -173,10 +174,10 @@ class HistoryTransaction extends Component<any, any> {
状态 状态
</div> </div>
<div className={['table-col-value'].join(' ')} style={{ <div className={['table-col-value'].join(' ')} style={{
color: getSuccessColor(item.result.code) color: getSuccessColor(item.result?.code)
}}> }}>
{ {
item.result.code === '200' ? '成功' : '失败' getSuccessText(item.result)
} }
</div> </div>
</div> </div>
...@@ -214,12 +215,20 @@ class HistoryTransaction extends Component<any, any> { ...@@ -214,12 +215,20 @@ class HistoryTransaction extends Component<any, any> {
return true; return true;
} }
async getTableList() { async getTableList(filterParams?: any) {
let loading = null;
try { try {
loading = open_loading();
let params = { let params = {
page: this.state.pageNum, page: this.state.pageNum,
limit: this.state.pageSize, limit: this.state.pageSize,
} }
if (filterParams) {
params = {
...params,
...filterParams,
}
}
const res: any = await ContractHistoryTransaction(params); const res: any = await ContractHistoryTransaction(params);
if (res.code == 0) { if (res.code == 0) {
console.log(res.data.data[0]) console.log(res.data.data[0])
...@@ -228,8 +237,14 @@ class HistoryTransaction extends Component<any, any> { ...@@ -228,8 +237,14 @@ class HistoryTransaction extends Component<any, any> {
total: res.data.total, total: res.data.total,
}) })
} }
if (loading) {
loading.hide();
}
} catch (e) { } catch (e) {
console.log(e) console.log(e)
if (loading) {
loading.hide();
}
} }
} }
......
import './index.less'; import './index.less';
import {Component} from "react"; import {Component} from "react";
import CustomTable from '@/js/components/Table/index'; import CustomTable from '@/js/components/Table/index';
import {isMobile} from '@/js/utils/tool'; import {isMobile, isEqual} from '@/js/utils/tool';
import CustomButton from '@/js/components/Button'; import CustomButton from '@/js/components/Button';
import Pagination from '@/js/components/Pagination'; import Pagination from '@/js/components/Pagination';
import {ContractHoldingPosition} from '@/js/utils/api/contract'; import {ContractHoldingPosition} from '@/js/utils/api/contract';
import {getLocalContractHelper, getUserName} from '@/js/utils/local'; import {getLocalContractHelper, getUserName} from '@/js/utils/local';
import {isRise, isPlus, getDirectionColor} from '@/js/utils/trade'; import {isRise, isPlus, getDirectionColor} from '@/js/utils/trade';
import {ClosePosition} from '@/js/utils/api/multipleUse' import {ClosePosition} from '@/js/utils/api/multipleUse';
import {open_loading} from '@/js/utils/tdesign';
class HoldingPosition extends Component<any, any> { class HoldingPosition extends Component<any, any> {
constructor(props) { constructor(props) {
...@@ -190,12 +191,24 @@ class HoldingPosition extends Component<any, any> { ...@@ -190,12 +191,24 @@ class HoldingPosition extends Component<any, any> {
} }
async getTableList() { shouldComponentUpdate(nextProps: Readonly<any>, nextState: Readonly<any>, nextContext: any): boolean {
return true;
}
async getTableList(filterParams?: any) {
let loading = null;
try { try {
loading = open_loading();
let params = { let params = {
page: this.state.pageNum, page: this.state.pageNum,
limit: this.state.pageSize, limit: this.state.pageSize,
} }
if (filterParams) {
params = {
...params,
...filterParams,
}
}
const res: any = await ContractHoldingPosition(params); const res: any = await ContractHoldingPosition(params);
if (res.code == 0) { if (res.code == 0) {
this.setState({ this.setState({
...@@ -203,8 +216,14 @@ class HoldingPosition extends Component<any, any> { ...@@ -203,8 +216,14 @@ class HoldingPosition extends Component<any, any> {
total: res.data.total, total: res.data.total,
}) })
} }
if (loading) {
loading.hide();
}
} catch (e) { } catch (e) {
console.log(e) console.log(e);
if (loading) {
loading.hide();
}
} }
} }
......
...@@ -10,12 +10,17 @@ import {ReactComponent as ResetSvg} from '@/assets/svg/trade/reset.svg'; ...@@ -10,12 +10,17 @@ import {ReactComponent as ResetSvg} from '@/assets/svg/trade/reset.svg';
import {ReactComponent as SubmitSvg} from '@/assets/svg/trade/submit.svg'; import {ReactComponent as SubmitSvg} from '@/assets/svg/trade/submit.svg';
import {ContractTradeField} from '@/js/constants/trade'; import {ContractTradeField} from '@/js/constants/trade';
import {show_message} from '@/js/utils/tdesign'; import {show_message} from '@/js/utils/tdesign';
import {getLocalUserList, getLocalContractHelperSelect} from '@/js/utils/local';
import {ContractStrategy, ContractBatchOperation} from '@/js/utils/api/contract';
import {open_loading} from '@/js/utils/tdesign';
import {isShow} from '@/js/utils/dom';
const users = 'user_ids';
export default class TradeDialog extends Component<any, any> { export default class TradeDialog extends Component<any, any> {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
[ContractTradeField.users]: [], [users]: [],
[ContractTradeField.pairs]: '', [ContractTradeField.pairs]: '',
[ContractTradeField.contract_strategy_id]: '', [ContractTradeField.contract_strategy_id]: '',
[ContractTradeField.side]: '', [ContractTradeField.side]: '',
...@@ -25,17 +30,18 @@ export default class TradeDialog extends Component<any, any> { ...@@ -25,17 +30,18 @@ export default class TradeDialog extends Component<any, any> {
[ContractTradeField.levers]: null, [ContractTradeField.levers]: null,
[ContractTradeField.stop_surplus]: null, [ContractTradeField.stop_surplus]: null,
[ContractTradeField.stop_loss]: null, [ContractTradeField.stop_loss]: null,
// 限价价格
[ContractTradeField.limit_price]: null,
} }
this.userOptions = [ this.userOptions = getLocalUserList(true, false);
{ // 交易策略options
label: '卫总', this.strategyOptions = [];
value: '1' // 方向options
}, this.sideOptions = getLocalContractHelperSelect('side', false);
{ // 买卖类型options
label: '卫总2', this.positionSideOptions = getLocalContractHelperSelect('position_side', false);
value: '2' // 订单类型options
} this.orderTypeOptions = getLocalContractHelperSelect('order_type', false);
]
} }
// 重置 // 重置
...@@ -61,9 +67,9 @@ export default class TradeDialog extends Component<any, any> { ...@@ -61,9 +67,9 @@ export default class TradeDialog extends Component<any, any> {
} }
// 提交 // 提交
onSubmit = () => { onSubmit = async () => {
// 必填项 // 必填项
const requiredFields = [ContractTradeField.users, ContractTradeField.pairs, ContractTradeField.side, const requiredFields = [users, ContractTradeField.pairs, ContractTradeField.side,
ContractTradeField.amount, ContractTradeField.position_side, ContractTradeField.order_type]; ContractTradeField.amount, ContractTradeField.position_side, ContractTradeField.order_type];
// 判断必填项是否为空 // 判断必填项是否为空
const status = formValidate(requiredFields, this.state); const status = formValidate(requiredFields, this.state);
...@@ -71,8 +77,28 @@ export default class TradeDialog extends Component<any, any> { ...@@ -71,8 +77,28 @@ export default class TradeDialog extends Component<any, any> {
show_message('请填写必填项'); show_message('请填写必填项');
return; return;
} }
console.log('可以提交'); // 限价单时,限价价格必填
console.log(this.state); if (this.state[ContractTradeField.order_type] === 'LIMIT' && !this.state[ContractTradeField.limit_price]) {
show_message('限价单价格必填');
return;
}
let loading = null;
try {
loading = open_loading();
const res: any = await ContractBatchOperation(this.state);
if (res.code == 0) {
show_message('提交成功', 'success');
this.onClose();
}
if (loading) {
loading.hide();
}
} catch (e) {
console.log(e);
if (loading) {
loading.hide();
}
}
} }
// 子组件的值变化 // 子组件的值变化
...@@ -91,6 +117,21 @@ export default class TradeDialog extends Component<any, any> { ...@@ -91,6 +117,21 @@ export default class TradeDialog extends Component<any, any> {
} }
} }
getStrategy = async () => {
try {
const res: any = await ContractStrategy();
if (res.code == 0) {
this.strategyOptions = res.data;
}
} catch (e) {
console.log(e)
}
}
componentDidMount() {
this.getStrategy()
}
render() { render() {
const {visible} = this.props; const {visible} = this.props;
const state = this.state; const state = this.state;
...@@ -101,7 +142,7 @@ export default class TradeDialog extends Component<any, any> { ...@@ -101,7 +142,7 @@ export default class TradeDialog extends Component<any, any> {
<div className='trade-form-item'> <div className='trade-form-item'>
<div className='trade-form-item__label required'>用户</div> <div className='trade-form-item__label required'>用户</div>
<div className='trade-form-item__value'> <div className='trade-form-item__value'>
<CustomSelect value={state[ContractTradeField.users]} name={ContractTradeField.users} <CustomSelect value={state[users]} name={users}
options={this.userOptions} options={this.userOptions}
className={"trade-dialog-select"} className={"trade-dialog-select"}
clearable={true} multiple={true} autoWidth={false} clearable={true} multiple={true} autoWidth={false}
...@@ -113,20 +154,24 @@ export default class TradeDialog extends Component<any, any> { ...@@ -113,20 +154,24 @@ export default class TradeDialog extends Component<any, any> {
<div className='trade-form-item'> <div className='trade-form-item'>
<div className='trade-form-item__label required'>交易对</div> <div className='trade-form-item__label required'>交易对</div>
<div className='trade-form-item__value'> <div className='trade-form-item__value'>
<CustomSelect value={state[ContractTradeField.pairs]} name={ContractTradeField.pairs} {/*<CustomSelect value={state[ContractTradeField.pairs]} name={ContractTradeField.pairs}*/}
options={this.userOptions} {/* options={this.userOptions}*/}
className={"trade-dialog-select"} {/* className={"trade-dialog-select"}*/}
clearable={true} autoWidth={false} {/* clearable={true} autoWidth={false}*/}
popupProps={{ {/* popupProps={{*/}
overlayClassName: 'trade-dialog-select__overlay' {/* overlayClassName: 'trade-dialog-select__overlay'*/}
}} onChange={this.onValueChange}></CustomSelect> {/* }} onChange={this.onValueChange}></CustomSelect>*/}
<CustomInput value={state[ContractTradeField.pairs]} name={ContractTradeField.pairs}
align={'center'} type={"text"}
onChange={this.onValueChange}>
</CustomInput>
</div> </div>
</div> </div>
<div className='trade-form-item'> <div className='trade-form-item'>
<div className='trade-form-item__label'>策略</div> <div className='trade-form-item__label'>策略</div>
<div className='trade-form-item__value'> <div className='trade-form-item__value'>
<CustomSelect value={state[ContractTradeField.contract_strategy_id]} <CustomSelect value={state[ContractTradeField.contract_strategy_id]}
name={ContractTradeField.contract_strategy_id} options={this.userOptions} name={ContractTradeField.contract_strategy_id} options={this.strategyOptions}
className={"trade-dialog-select"} className={"trade-dialog-select"}
clearable={true} autoWidth={false} clearable={true} autoWidth={false}
popupProps={{ popupProps={{
...@@ -138,7 +183,7 @@ export default class TradeDialog extends Component<any, any> { ...@@ -138,7 +183,7 @@ export default class TradeDialog extends Component<any, any> {
<div className='trade-form-item__label required'>方向</div> <div className='trade-form-item__label required'>方向</div>
<div className='trade-form-item__value'> <div className='trade-form-item__value'>
<CustomSelect value={state[ContractTradeField.side]} <CustomSelect value={state[ContractTradeField.side]}
name={ContractTradeField.side} options={this.userOptions} name={ContractTradeField.side} options={this.sideOptions}
className={"trade-dialog-select"} className={"trade-dialog-select"}
clearable={true} autoWidth={false} clearable={true} autoWidth={false}
popupProps={{ popupProps={{
...@@ -151,7 +196,7 @@ export default class TradeDialog extends Component<any, any> { ...@@ -151,7 +196,7 @@ export default class TradeDialog extends Component<any, any> {
<div className='trade-form-item__value'> <div className='trade-form-item__value'>
<CustomSelect value={state[ContractTradeField.position_side]} <CustomSelect value={state[ContractTradeField.position_side]}
name={ContractTradeField.position_side} name={ContractTradeField.position_side}
options={this.userOptions} options={this.positionSideOptions}
className={"trade-dialog-select"} className={"trade-dialog-select"}
clearable={true} autoWidth={false} clearable={true} autoWidth={false}
popupProps={{ popupProps={{
...@@ -163,7 +208,7 @@ export default class TradeDialog extends Component<any, any> { ...@@ -163,7 +208,7 @@ export default class TradeDialog extends Component<any, any> {
<div className='trade-form-item__label required'>交易类型</div> <div className='trade-form-item__label required'>交易类型</div>
<div className='trade-form-item__value'> <div className='trade-form-item__value'>
<CustomSelect value={state[ContractTradeField.order_type]} <CustomSelect value={state[ContractTradeField.order_type]}
name={ContractTradeField.order_type} options={this.userOptions} name={ContractTradeField.order_type} options={this.orderTypeOptions}
className={"trade-dialog-select"} className={"trade-dialog-select"}
clearable={true} autoWidth={false} clearable={true} autoWidth={false}
popupProps={{ popupProps={{
...@@ -171,6 +216,16 @@ export default class TradeDialog extends Component<any, any> { ...@@ -171,6 +216,16 @@ export default class TradeDialog extends Component<any, any> {
}} onChange={this.onValueChange}></CustomSelect> }} onChange={this.onValueChange}></CustomSelect>
</div> </div>
</div> </div>
<div className='trade-form-item' style={{
display: isShow(state[ContractTradeField.order_type] === 'LIMIT')
}}>
<div className='trade-form-item__label required'>限价价格</div>
<div className='trade-form-item__value'>
<CustomInput type={"number"} value={state[ContractTradeField.limit_price]} align={'center'}
name={ContractTradeField.limit_price}
onChange={this.onValueChange}></CustomInput>
</div>
</div>
<div className='trade-form-item'> <div className='trade-form-item'>
<div className='trade-form-item__label'>杠杆</div> <div className='trade-form-item__label'>杠杆</div>
<div className='trade-form-item__value'> <div className='trade-form-item__value'>
......
...@@ -14,6 +14,25 @@ ...@@ -14,6 +14,25 @@
margin-left: 12px; margin-left: 12px;
} }
.custom-trade-input {
display: flex;
align-items: center;
font-size: 12px;
white-space: nowrap;
.label {
margin-right: 10px;
}
.t-input {
height: 24px;
.t-input__inner {
font-size: 12px;
}
}
}
.custom-trade-select { .custom-trade-select {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -23,6 +42,7 @@ ...@@ -23,6 +42,7 @@
.label { .label {
} }
.real-trade-select { .real-trade-select {
.t-input__wrap { .t-input__wrap {
......
...@@ -3,103 +3,92 @@ import {Component} from "react"; ...@@ -3,103 +3,92 @@ import {Component} from "react";
import CustomSelect from "@/js/components/Select"; import CustomSelect from "@/js/components/Select";
import CustomButton from '@/js/components/Button'; import CustomButton from '@/js/components/Button';
import {isMobile} from '@/js/utils/tool'; import {isMobile} from '@/js/utils/tool';
import {getLocalUserList} from '@/js/utils/local'; import {getLocalUserList, getLocalContractHelperSelect} from '@/js/utils/local';
import CustomInput from '@/js/components/Input';
class TradeSelect extends Component<any, any> { class TradeSelect extends Component<any, any> {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
user: '',
pairs: '',
direction: '',
exchange: '',
userSelect: { userSelect: {
label: '用户', label: '用户',
value: '',
options: getLocalUserList(), options: getLocalUserList(),
}, },
pairsSelect: { directionSelect: {
label: '交易对',
value: '',
options: [
{
label: '全部',
value: 'all'
},
{
label: 'usdt/bsc',
value: '1'
},
{
label: 'usdt/eth',
value: '2'
}
]
},
direction: {
label: '方向', label: '方向',
value: '', options: getLocalContractHelperSelect('position_side')
options: [
{
label: '全部',
value: 'all'
},
{
label: 'usdt/bsc',
value: '1'
}, },
{ exchangeSelect: {
label: 'usdt/eth',
value: '2'
}
]
},
exchange: {
label: '交易所', label: '交易所',
value: '', options: getLocalContractHelperSelect('exchange')
options: [
{
label: '全部',
value: 'all'
}, },
{
label: 'usdt/bsc',
value: '1'
},
{
label: 'usdt/eth',
value: '2'
} }
]
}, }
onFilter(params: any) {
// 请求表格
if (this.props.FilterChange) {
this.props.FilterChange(params)
}
} }
valueChange = (value: string | number, name: string) => {
this.setState({
[name]: value,
})
} }
onFilter(value: string) { onRefresh() {
console.log(value) // 刷新表格
} }
render() { render() {
const {userSelect, pairsSelect, direction, exchange} = this.state; const {userSelect, exchange, directionSelect, exchangeSelect} = this.state;
return ( return (
<div className={[isMobile() ? 'custom-trade-select-box__mobile' : ''].join(' ')}> <div className={[isMobile() ? 'custom-trade-select-box__mobile' : ''].join(' ')}>
<div <div
className={['custom-trade-select-box'].join(' ')}> className={['custom-trade-select-box'].join(' ')}>
<div className='custom-trade-select'> <div className='custom-trade-select'>
<span className='label'>{userSelect.label}</span> <span className='label'>{userSelect.label}</span>
<CustomSelect className='real-trade-select' options={userSelect.options}></CustomSelect> <CustomSelect className='real-trade-select' name={'user'} value={this.state.user}
options={userSelect.options} onChange={this.valueChange}></CustomSelect>
</div> </div>
<div className='custom-trade-select'>
<span className='label'>{pairsSelect.label}</span> <div className='custom-trade-input'>
<CustomSelect className='real-trade-select' options={pairsSelect.options}></CustomSelect> <span className='label'>交易对</span>
<CustomInput name={'pairs'}
value={this.state.pairs} onChange={this.valueChange}></CustomInput>
{/*<CustomSelect className='real-trade-select' options={pairsSelect.options}></CustomSelect>*/}
</div> </div>
<div className='custom-trade-select'> <div className='custom-trade-select'>
<span className='label'>{direction.label}</span> <span className='label'>{directionSelect.label}</span>
<CustomSelect className='real-trade-select' options={direction.options}></CustomSelect> <CustomSelect name={'direction'} value={this.state.direction} className='real-trade-select'
options={directionSelect.options} onChange={this.valueChange}></CustomSelect>
</div> </div>
<div className='custom-trade-select'> <div className='custom-trade-select'>
<span className='label'>{exchange.label}</span> <span className='label'>{exchangeSelect.label}</span>
<CustomSelect className='real-trade-select' options={exchange.options}></CustomSelect> <CustomSelect name={'exchange'} value={exchange} className='real-trade-select'
options={exchangeSelect.options} onChange={this.valueChange}></CustomSelect>
</div> </div>
<CustomButton onClick={this.onFilter.bind(this, 'test')}>查询</CustomButton> <CustomButton onClick={this.onFilter.bind(this, {
<CustomButton>刷新</CustomButton> exchange_users_id: this.state.user,
symbol: this.state.pairs,
position_side: this.state.direction,
exchange: this.state.exchange,
})}>查询</CustomButton>
<CustomButton onClick={this.onFilter.bind(this, {
exchange_users_id: this.state.user,
symbol: this.state.pairs,
position_side: this.state.direction,
exchange: this.state.exchange,
})}>刷新</CustomButton>
</div> </div>
{this.props.children} {this.props.children}
</div> </div>
......
.contract-account-table {
.contract-account-label {
padding: 24px 12px 6px 12px;
font-weight: 600;
font-size: 14px;
color: #000000;
border-bottom: 1px solid #EAECEF;
}
.contract-account-table-box {
padding: 0 30px;
}
}
.contract-account-table__mobile {
.contract-account-table-box {
padding: 0;
.t-table__body {
max-height: 120px;
td {
font-weight: 500;
font-size: 12px;
}
}
}
}
import './index.less'
import {Component} from "react";
import CustomTable from '@/js/components/Table/index';
import {isMobile} from '@/js/utils/tool';
import {SpotAssets} from "@/js/utils/api/spot";
import {getAdminUserList, getUserName} from '@/js/utils/local';
import {getUserList} from '@/js/utils/api/auth';
class ContractAccount extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
list: [],
loading: false,
}
this.columns = [
{
colKey: 'ddd',
title: '用户名',
align: 'center',
cell: ({rowIndex, row}) => {
if (row.id) {
return getUserName(row.id)
}
return 'null'
},
},
{
colKey: 'exchange',
title: '交易所',
align: 'center',
},
{
colKey: 'spot_asset',
title: '现货资产',
align: 'center',
cell: ({rowIndex, row}) => {
return (
<span>{(parseFloat(row.spot_asset + '')).toFixed(4)}</span>
)
},
},
{
colKey: 'contract_asset',
title: '合约资产',
align: 'center',
cell: ({rowIndex, row}) => {
return (
<span>{(parseFloat(row.contract_asset + '')).toFixed(4)}</span>
)
},
},
{
colKey: 'total',
title: '总资产',
align: 'center',
cell: ({rowIndex, row}) => {
return (
<span>{(parseFloat(row.spot_asset + '') + parseFloat(row.contract_asset + '')).toFixed(4)}</span>
)
},
},
{
colKey: 'principal',
title: '本金',
align: 'center',
cell: ({rowIndex, row}) => {
return (
<span style={{
color: '#C99400'
}}>{parseFloat(row.principal + '')}</span>
)
},
},
];
}
changeLoding(value: boolean) {
this.setState({
loading: value,
})
}
async changeList() {
try {
this.changeLoding(true);
const res: any = await getUserList();
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() {
return (
<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}
loading={this.state.loading}></CustomTable>
</div>
</div>
)
}
}
export default ContractAccount;
.contract-trade-table {
flex: 1;
display: flex;
flex-direction: column;
.contract-trade-label {
padding: 24px 12px 6px 12px;
font-weight: 600;
font-size: 16px;
color: #000000;
border-bottom: 1px solid #EAECEF;
}
.contract-trade-table-box {
padding: 0 30px;
flex: 1;
.spread-out-table {
display: flex;
flex-direction: column;
& > :first-child {
flex: 1;
}
}
.spread-out-table__mobile {
}
}
.contract-trade-group {
display: flex;
align-items: center;
height: 37px;
font-weight: 600;
font-size: 14px;
& > * {
cursor: pointer;
transition: all 0.3s;
}
& > :nth-child(1) {
margin-left: 12px;
}
& > :not(:nth-child(1)) {
margin-left: 20px;
}
.group-active {
color: #C99400;
transition: all 0.3s;
}
}
}
.c-table-height {
height: 100%;
}
// 三张表格样式
.contract-trade-table__mobile {
padding: 0 12px !important;
padding-top: 6px !important;
.contract-real-table__mobile {
min-height: 100%;
display: flex;
flex-direction: column;
.table-row {
padding-bottom: 12px;
border-bottom: 1px solid #F0F0F0;
.table-row-line {
margin-top: 6px;
display: flex;
justify-content: space-between;
align-items: center;
.table-btns {
& > :not(:first-child) {
margin-left: 12px;
}
}
.table-pairs {
font-weight: 400;
font-size: 16px;
color: #222222;
span {
color: #C99400;
}
}
.table-time {
font-weight: 400;
font-size: 12px;
color: #848E9C;
}
.table-direction {
font-weight: 400;
font-size: 14px;
}
.table-col-left {
width: 44%;
& > :not(:first-child) {
margin-top: 4px;
}
.table-col__line {
display: flex;
justify-content: space-between;
.table-col-label {
font-weight: 400;
font-size: 13px;
color: #848E9C;
}
.table-col-value {
font-weight: 400;
font-size: 14px;
color: #222222;
}
.green {
color: #0E9D6D;
}
}
}
}
}
.reset-t-pagination-box {
margin-top: auto;
}
}
}
.hold-position-extension {
padding: 0 12px;
display: flex;
justify-content: flex-end;
margin-top: 6px;
& > :first-child {
margin-right: 6px;
}
& > :only-child {
margin-right: 0;
}
.custom-reset-t-button {
color: #C99400 !important;
}
}
import './index.less'
import {Component} from 'react';
import HoldingPosition from '../HoldingPosition/index';
import CurrentConsignment from '../CurrentConsignment/index';
import HistoryTransaction from '../HistoryTransaction/index';
import {isShow} from "@/js/utils/dom";
import {table_HoldingPosition, table_CurrentConsignment, table_HistoryTransaction} from '@/js/constants/trade';
import store from '@/js/redux/store';
import TradeSelect from '../TradeSelect/index';
import {getDomRect} from '@/js/utils/dom';
import {isMobile} from '@/js/utils/tool';
import CustomButton from '@/js/components/Button';
import CustomDialog from '../TradeDialog/index';
import {setLocalSpotHelper} from '@/js/utils/local';
import {ClosePosition} from '@/js/utils/api/multipleUse';
// 定义常量
const dom_id = 'contract-trade';
class ContractTrade extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
// 弹窗状态
dialog_visible: false,
minHeight: '',
// 当前委托数量
currentEntrustNum: 0,
// 当前选择的按钮
currentGroupButton: '1',
// 三个表格的状态
tableStatus: {
[table_HoldingPosition]: true,
[table_CurrentConsignment]: false,
[table_HistoryTransaction]: false,
},
// 筛选条件
filter: {}
}
}
// 计算属性
get ComputedGroupButtons() {
return [
{
label: '持有仓位',
value: '1',
},
{
label: `当前委托(${this.state.currentEntrustNum})`,
value: '2',
},
{
label: '历史成交',
value: '3',
}
];
}
// 改变表格显示状态
changeTableStatus = (value: string) => {
const tableStatus = Object.keys(this.state.tableStatus);
for (let i = 0; i < tableStatus.length; i++) {
const item = tableStatus[i];
if (item === value) {
if (!this.state.tableStatus[item]) {
this.state.tableStatus[item] = true;
}
break;
}
}
}
// 切换按钮
changeGroupButton = (value: string) => {
this.changeTableStatus(value);
this.setState({
currentGroupButton: value
})
}
// 获取表格最低高度
getTableHeight = () => {
const dom: HTMLElement = document.getElementById(dom_id);
if (dom) {
const rect = getDomRect(dom);
const wid = document.documentElement.clientHeight;
const height = wid - rect.top;
this.setState({
minHeight: height + 'px'
})
}
}
storeChange = () => {
store.dispatch({type: 'count', data: 1,});
}
async componentDidMount() {
this.getTableHeight();
// store.subscribe(() => {
// this.setState({
// num: store.getState().count,
// })
// })
// 获取现货辅助列表
await setLocalSpotHelper();
}
// 打开弹窗
openDialog = () => {
this.setState({
dialog_visible: true,
})
}
// 关闭弹窗
closeDialog = () => {
this.setState({
dialog_visible: false,
})
}
// table-class
getTableClass() {
return ['spread-out-table', isMobile() ? "spread-out-table__mobile" : ""].join(' ')
}
// 撤销委托
onCancelEntrust = () => {
this.currentConsignment.tableContractRevoke();
}
// 当前显示的按钮-根据对应的表格显示
currentExtensionButtons() {
switch (this.state.currentGroupButton) {
case table_HoldingPosition:
return (
<div className='hold-position-extension'>
<CustomButton onClick={this.openDialog}>开始交易</CustomButton>
</div>
)
case table_CurrentConsignment:
return (
<div className='hold-position-extension'>
<CustomButton onClick={this.onCancelEntrust}>多选撤销</CustomButton>
</div>
)
case table_HistoryTransaction:
return '';
}
}
FilterChange = (params: any) => {
this.setState({
filter: params,
})
this.getChildTableList(params);
}
// 请求子组件的表格
getChildTableList = (params: any) => {
if (this.state.currentGroupButton === '1') {
this.holdingPositionRef.getTableList(params);
} else if (this.state.currentGroupButton === '2') {
this.currentConsignment.getTableList(params);
} else if (this.state.currentGroupButton === '3') {
this.historyTransaction.getTableList(params);
}
}
// 更新total
updateTotal = (total: number) => {
this.setState({
currentEntrustNum: total,
})
}
render() {
const obj = store.getState();
return (
<div className={'contract-trade-table'} id={this.props.id} style={this.props.style}>
<div className='contract-trade-label'>现货交易</div>
<div className='contract-trade-group'>
{
this.ComputedGroupButtons.map((item, index) => (
<div key={item.value}
className={item.value === this.state.currentGroupButton ? 'group-active' : ''}
onClick={this.changeGroupButton.bind(this, item.value)}
>
{item.label}
</div>
))
}
</div>
<TradeSelect FilterChange={this.FilterChange} tableType={this.state.currentGroupButton}>
{
this.currentExtensionButtons()
}
</TradeSelect>
<div
className={['contract-trade-table-box', isMobile() ? 'contract-trade-table__mobile' : ''].join(' ')}
id={dom_id} style={{
minHeight: this.state.minHeight
}}>
{/*持有仓位*/}
<HoldingPosition
v-if={this.state.tableStatus[table_HoldingPosition]}
className={this.getTableClass()}
ref={dom => this.holdingPositionRef = dom}
style={
{
'display': isShow(this.state.currentGroupButton === table_HoldingPosition),
}
}></HoldingPosition>
{/*当前委托*/}
<CurrentConsignment
v-if={this.state.tableStatus[table_CurrentConsignment]}
className={this.getTableClass()}
ref={dom => this.currentConsignment = dom}
style={
{
'display': isShow(this.state.currentGroupButton === table_CurrentConsignment),
}
} updateTotal={this.updateTotal}></CurrentConsignment>
{/*历史成交*/}
<HistoryTransaction
v-if={this.state.tableStatus[table_HistoryTransaction]}
className={this.getTableClass()}
ref={dom => this.historyTransaction = dom}
style={
{
'display': isShow(this.state.currentGroupButton === table_HistoryTransaction),
}
}></HistoryTransaction>
</div>
<CustomDialog visible={this.state.dialog_visible} onClose={this.closeDialog}></CustomDialog>
</div>
)
}
}
export default ContractTrade;
import './index.less'
import {Component} from "react";
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 {getBuySellColor, getBuySellText} from '@/js/utils/trade';
import {getLocalSpotHelper, getUserName} from '@/js/utils/local';
import {open_loading} from '@/js/utils/tdesign';
import {onSpotRevoke} from '@/js/utils/api/multipleUse';
import {show_message} from "@/js/utils/tdesign";
import CustomCheckBox from '@/js/components/CheckBox';
import {SpotCurrentEntrustment} from '@/js/utils/api/spot';
// 当前委托
class CurrentConsignment extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
list: [{}],
pageNum: 1,
pageSize: 10,
total: 0,
isFirst: true,
}
this.columns = [
{
colKey: 'ddd',
title: '用户名',
},
{
colKey: 'd2',
title: '交易所',
},
{
colKey: 'd3',
title: '交易对',
},
{
colKey: 'd4',
title: '交易类型',
align: 'center'
},
{
colKey: 'd5',
title: '持仓方向',
align: 'center'
},
{
colKey: 'd6',
title: '开仓价格',
align: 'center'
},
{
colKey: 'd7',
title: '数量',
align: 'center'
},
{
colKey: 'd8',
title: '成交数量USDT',
align: 'center'
},
{
colKey: 'd9',
title: '时间',
align: 'center'
},
{
colKey: 'd10',
title: '操作',
align: 'center'
},
];
}
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 '';
}
// 手机表格
mobileTable() {
return (
<div className='contract-real-table__mobile'>
{
this.state.list.map((item, index) => (
<div key={new Date().valueOf() + index} className='table-row'>
<div className='table-row-line'>
<div className={'table-pairs'}>
{item.symbol}
</div>
<div className={'table-time'}>
{item.working_time}
</div>
</div>
<div className='table-row-line'>
<div className={['table-direction'].join(' ')} style={{
color: getBuySellColor(item.side)
}}>
{getLocalSpotHelper('order_type', item.type)}/{getBuySellText(item.side)}
</div>
<CustomButton onClick={this.tableContractRevoke.bind(this, item)}>撤销</CustomButton>
</div>
<div className='table-row-line'>
<CustomCheckBox checked={item.is_checked} onChange={
(value: boolean) => {
item.is_checked = value;
}
}></CustomCheckBox>
<div className={'table-col-left'}>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
用户
</div>
<div className={'table-col-value'}>
{getUserName(item.exchange_users_id)}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
开仓价格
</div>
<div className={'table-col-value'}>
{item.price}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
订单id
</div>
<div className={'table-col-value'}>
{item.order_id}
</div>
</div>
</div>
<div className={'table-col-left'}>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
交易所
</div>
<div className={'table-col-value'}>
{item.exchange}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
数量
</div>
<div className={'table-col-value'}>
{item.qty}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
状态
</div>
<div className={['table-col-value', 'green'].join(' ')}>
{item.status}
</div>
</div>
</div>
</div>
</div>
))
}
<Pagination onChange={this.pageChange} pageNum={this.state.pageNum}
pageSize={this.state.pageSize} total={this.state.total}></Pagination>
</div>
)
}
// 撤销委托
async tableContractRevoke(row?: any) {
let params: any = {};
if (row) {
params = {
ids: [row.id],
}
} else {
// 获取选中的行--is_checked
const list = this.state.list;
const ids: any[] = [];
list.forEach((item: any) => {
if (item.is_checked) {
ids.push(item.id);
}
})
if (!ids.length) {
show_message('未选择行');
return;
}
params = {
ids: ids,
}
}
const status = await onSpotRevoke(params);
if (status) {
// 更新表格数据
this.getTableList();
}
}
// 当前表格
currentTable() {
return (
<div style={this.props.style ?? null} className='c-table-height'>
{
isMobile() ? this.mobileTable() : this.pcTable()
}
</div>
)
}
async getTableList(filterParams?: any) {
let loading = null;
try {
let params = {
page: this.state.pageNum,
limit: this.state.pageSize,
}
if (filterParams) {
params = {
...params,
...filterParams,
}
}
loading = open_loading();
const res: any = await SpotCurrentEntrustment(params);
if (res.code == 0) {
res.data.data.forEach((item: any) => {
item.is_checked = false;
})
this.setState({
list: JSON.parse(JSON.stringify(res.data.data)),
total: res.data.total,
})
// 通知父组件更新total
if (this.props.updateTotal) {
this.props.updateTotal(res.data.total);
}
}
if (loading) {
loading.hide();
}
} catch (e) {
console.log(e)
if (loading) {
loading.hide();
}
}
}
shouldComponentUpdate(nextProps: Readonly<any>, nextState: Readonly<any>, nextContext: any) {
if (nextProps['v-if'] && nextState.isFirst) {
this.setState({
isFirst: false,
})
// 请求接口
this.getTableList();
}
return true;
}
render() {
const props = this.props;
if (props['v-if']) {
return this.currentTable();
} else {
return <></>;
}
}
}
export default CurrentConsignment;
import './index.less';
import {Component} from "react";
import CustomTable from '@/js/components/Table/index';
import {isMobile} from '@/js/utils/tool';
import Pagination from '@/js/components/Pagination';
import {getBuySellColor, getStatusColor} from '@/js/utils/trade';
import {getUserName, getLocalSpotHelper} from '@/js/utils/local';
import {open_loading} from '@/js/utils/tdesign';
import {SpotHistoryTransaction} from '@/js/utils/api/spot';
import {TradeDirection} from '@/js/constants/trade';
class HistoryTransaction extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
list: [],
pageNum: 1,
pageSize: 10,
total: 0,
isFirst: true,
}
this.columns = [
{
colKey: 'ddd',
title: '用户名',
},
{
colKey: 'd2',
title: '交易所',
},
{
colKey: 'd3',
title: '交易对',
},
{
colKey: 'd4',
title: '交易类型',
align: 'center'
},
{
colKey: 'd5',
title: '持仓方向',
align: 'center'
},
{
colKey: 'd6',
title: '开仓价格',
align: 'center'
},
{
colKey: 'd7',
title: '数量',
align: 'center'
},
{
colKey: 'd8',
title: '成交数量USDT',
align: 'center'
},
{
colKey: 'd9',
title: '状态',
align: 'center'
},
{
colKey: 'd10',
title: '交易时间',
align: 'center'
},
{
colKey: 'd11',
title: '更新时间',
align: 'center'
},
{
colKey: 'd12',
title: '返回值',
align: 'center'
},
];
}
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 ''
}
// 手机表格
mobileTable() {
return (
<div className='contract-real-table__mobile'>
{
this.state.list.map((item, index) => (
<div key={index} className='table-row'>
<div className='table-row-line'>
<div className={'table-pairs'}>
{item.symbol}
</div>
<div className={'table-time'}>
{item.created_at}
</div>
</div>
<div className='table-row-line'>
<div className={['table-direction'].join(' ')} style={{
color: getBuySellColor(item.direction)
}}>
{getLocalSpotHelper('order_type', item.order_type)}/{TradeDirection[item.direction]}
</div>
<div className={'table-time'}>
<span>更新时间 </span>
{item.updated_at}
</div>
</div>
<div className='table-row-line'>
<div className={'table-col-left'}>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
用户
</div>
<div className={'table-col-value'}>
{getUserName(item.exchange_users_id)}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
开始价格
</div>
<div className={'table-col-value'}>
{item.target_price}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
成交金额
</div>
<div className={'table-col-value'}>
{parseFloat(item.quantity + '')}
</div>
</div>
</div>
<div className={'table-col-left'}>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
交易所
</div>
<div className={'table-col-value'}>
{item.exchange}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
成交数量
</div>
<div className={'table-col-value'}>
{item.quantity}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
状态
</div>
<div className={['table-col-value'].join(' ')} style={{
color: getStatusColor(item.status)
}}>
{
getLocalSpotHelper('status', item.status)
}
</div>
</div>
</div>
</div>
</div>
))
}
<Pagination onChange={this.pageChange} pageNum={this.state.pageNum}
pageSize={this.state.pageSize} total={this.state.total}></Pagination>
</div>
)
}
// 当前表格
currentTable() {
return (
<div style={this.props.style ?? null} className='c-table-height'>
{
isMobile() ? this.mobileTable() : this.pcTable()
}
</div>
)
}
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(filterParams?: any) {
let loading = null;
try {
loading = open_loading();
let params = {
page: this.state.pageNum,
limit: this.state.pageSize,
}
if (filterParams) {
params = {
...params,
...filterParams,
}
}
const res: any = await SpotHistoryTransaction(params);
if (res.code == 0) {
console.log(res.data.data[0])
this.setState({
list: res.data.data,
total: res.data.total,
})
}
if (loading) {
loading.hide();
}
} catch (e) {
console.log(e)
if (loading) {
loading.hide();
}
}
}
render() {
const props = this.props;
if (props['v-if']) {
return this.currentTable();
} else {
return <></>;
}
}
}
export default HistoryTransaction;
import './index.less';
import {Component} from "react";
import CustomTable from '@/js/components/Table/index';
import {isMobile, isEqual} from '@/js/utils/tool';
import CustomButton from '@/js/components/Button';
import Pagination from '@/js/components/Pagination';
import {getUserName} from '@/js/utils/local';
import {open_loading} from '@/js/utils/tdesign';
import {SpotAssets} from "@/js/utils/api/spot";
class HoldingPosition extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
list: [],
pageNum: 1,
pageSize: 10,
total: 0,
// 交易弹窗
trade_dialog: false,
// 策略弹窗
strategy_dialog: false,
}
this.columns = [
{
colKey: 'ddd',
title: '用户名',
cell: ({rowIndex, row}) => {
return (
<div>{row.d9}</div>
);
},
},
{
colKey: 'd2',
title: '交易所',
},
{
colKey: 'd3',
title: '交易对',
},
{
colKey: 'd4',
title: '持仓方向',
align: 'center'
},
{
colKey: 'd5',
title: '策略',
align: 'center'
},
{
colKey: 'd6',
title: '开仓价格',
align: 'center'
},
{
colKey: 'd7',
title: '标记价格',
align: 'center'
},
{
colKey: 'd8',
title: '未实现盈亏',
align: 'center'
},
{
colKey: 'd9',
title: '操作',
align: 'center'
},
];
}
// 页码改变
pageChange = (value: number) => {
this.setState({
pageNum: value
})
// 请求接口
this.getTableList();
}
// pc表格
pcTable() {
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>
// )
}
// 打开交易弹窗
openTradeModal = (item) => {
this.setState({
trade_dialog: true
})
}
// 手机表格
mobileTable() {
return (
<div className='contract-real-table__mobile'>
{
this.state.list.map((item, index) => (
<div key={index} className='table-row'>
<div className='table-row-line'>
<div className={'table-pairs'}>
{item.symbol}
</div>
<div className='table-btns'>
{/*<CustomButton onClick={this.openTradeModal}>交易</CustomButton>*/}
{/*<CustomButton>策略</CustomButton>*/}
</div>
</div>
<div className='table-row-line'>
<div className={'table-col-left'}>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
用户
</div>
<div className={'table-col-value'}>
{getUserName(item.exchange_users_id)}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
BTC估值
</div>
<div className={'table-col-value'}>
{item.btc_valuation}
</div>
</div>
{/*<div className={'table-col__line'}>*/}
{/* <div className={'table-col-label'}>*/}
{/* 策略*/}
{/* </div>*/}
{/* <div className={'table-col-value'}>*/}
{/* {item.spot_strategy_id}*/}
{/* </div>*/}
{/*</div>*/}
</div>
<div className={'table-col-left'}>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
交易所
</div>
<div className={'table-col-value'}>
{item.exchange}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
价值
</div>
<div className={'table-col-value'}>
{item.quantity}
</div>
</div>
<div className={'table-col__line'}>
<div className={'table-col-label'}>
更新
</div>
<div className={['table-col-value'].join(' ')} style={{
fontSize: '12px'
}}>
{item.updated_at}
</div>
</div>
</div>
</div>
</div>
))
}
<Pagination onChange={this.pageChange} pageNum={this.state.pageNum}
pageSize={this.state.pageSize} total={this.state.total}></Pagination>
</div>
)
}
// 当前表格
currentTable() {
return (
<div style={this.props.style ?? null} className='c-table-height'>
{
isMobile() ? this.mobileTable() : this.pcTable()
}
{/* dialog */}
{/*<TradeDialog visible={this.state.trade_dialog} onClose={() => {*/}
{/* this.setState({*/}
{/* trade_dialog: false,*/}
{/* })*/}
{/*}}></TradeDialog>*/}
</div>
)
}
shouldComponentUpdate(nextProps: Readonly<any>, nextState: Readonly<any>, nextContext: any): boolean {
return true;
}
async getTableList(filterParams?: any) {
let loading = null;
try {
loading = open_loading();
let params = {
page: this.state.pageNum,
limit: this.state.pageSize,
}
if (filterParams) {
params = {
...params,
...filterParams,
}
}
const res: any = await SpotAssets(params);
if (res.code == 0) {
this.setState({
list: res.data.data,
total: res.data.total,
})
}
if (loading) {
loading.hide();
}
} catch (e) {
console.log(e);
if (loading) {
loading.hide();
}
}
}
componentDidMount() {
this.getTableList();
}
render() {
const props = this.props;
if (props['v-if']) {
return this.currentTable();
} else {
return <></>;
}
}
}
export default HoldingPosition;
.trade-dialog__mobile {
.t-dialog {
width: 90vw;
padding: 20px;
}
.custom-trade-form {
padding-right: 20px;
& > :not(:first-child) {
margin-top: 12px;
}
.trade-form-item {
display: flex;
align-items: center;
.trade-form-item__label {
text-align: right;
width: 70px;
}
.required {
&:before {
content: '*';
color: red;
padding-right: 2px;
}
}
.trade-form-item__value {
flex: 1;
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;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
margin-right: -8px;
}
.trade-dialog-select {
.t-select {
.t-input__wrap {
width: 100% !important;
.t-input {
&:hover {
border-color: #C99400;
}
}
}
.t-input--focused {
box-shadow: none;
border-color: #C99400;
}
.t-fake-arrow--active {
color: #C99400;
}
.t-input__prefix {
.t-tag {
background-color: #C99400;
color: #fff;
font-weight: 600;
font-size: 11px;
.t-icon {
color: #fff;
}
}
}
}
}
}
}
}
}
.trade-dialog-select__overlay {
.t-select-option {
color: #C99400;
.t-checkbox__input {
border-color: #C99400 !important;
}
}
.t-is-selected {
background-color: white;
.t-checkbox__input {
background-color: #C99400;
border-color: #C99400;
&:hover, &:focus, &:active {
background-color: #C99400;
border-color: #C99400;
}
}
.t-checkbox__label {
color: #C99400;
}
&:hover {
background-color: white;
}
.t-is-checked {
background-color: white;
color: #fff;
}
}
}
import './index.less'
import {Component} from "react";
import {Dialog} from "tdesign-react";
import {isMobile, formValidate} from '@/js/utils/tool';
import CustomSelect from "@/js/components/Select";
import CustomInputNumber from '@/js/components/InputNumber';
import CustomInput from '@/js/components/Input';
import CustomButton from '@/js/components/Button';
import {ReactComponent as ResetSvg} from '@/assets/svg/trade/reset.svg';
import {ReactComponent as SubmitSvg} from '@/assets/svg/trade/submit.svg';
import {SpotTradeField} from '@/js/constants/trade';
import {show_message} from '@/js/utils/tdesign';
import {getLocalSpotHelperSelect, getLocalUserList, getLocalSymbolList} from '@/js/utils/local';
import {open_loading} from '@/js/utils/tdesign';
import {isShow} from '@/js/utils/dom';
import {SpotStrategy, SpotBatchOperation} from '@/js/utils/api/spot';
const users = 'user_ids';
const symbols = 'symbols';
export default class TradeDialog extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
[users]: [],
[symbols]: [],
// 买卖类型
[SpotTradeField.direction]: '',
// 交易类型
[SpotTradeField.order_type]: '',
// 限价价格
[SpotTradeField.limit_price]: '',
}
// 交易对列表
this.symbolOptions = [];
// 交易策略options
this.strategyOptions = [];
// 用户options
this.userOptions = getLocalUserList(true, false);
// 买卖类型options
this.positionSideOptions = getLocalSpotHelperSelect('direction', false);
// 订单类型options
this.orderTypeOptions = getLocalSpotHelperSelect('order_type', false);
}
// 重置
onReset = () => {
const items = Object.keys(this.state);
items.forEach((item: any) => {
if (typeof this.state[item] === 'string') {
this.setState({
[item]: ''
})
} else if (typeof this.state[item] === 'number') {
this.setState({
[item]: 0,
})
} else {
this.setState({
[item]: []
})
}
})
}
// 提交
onSubmit = async () => {
// 必填项
const requiredFields = [users, symbols, SpotTradeField.spot_strategy_id, SpotTradeField.direction, SpotTradeField.order_type];
// 判断必填项是否为空
const status = formValidate(requiredFields, this.state);
if (!status) {
show_message('请填写必填项');
return;
}
// 限价单时,限价价格必填
if (this.state[SpotTradeField.order_type] === 'LIMIT' && !this.state[SpotTradeField.limit_price]) {
show_message('限价单价格必填');
return;
}
let loading = null;
try {
// 现价交易提交
loading = open_loading();
const res: any = await SpotBatchOperation(this.state);
if (res.code == 0) {
show_message('提交成功', 'success');
this.onClose();
}
if (loading) {
loading.hide();
}
} catch (e) {
console.log(e);
if (loading) {
loading.hide();
}
}
}
// 子组件的值变化
onValueChange = (value: string | number | any[], name: string) => {
if (name) {
this.setState({
[name]: value
})
}
}
getStrategy = async () => {
try {
const res: any = await SpotStrategy();
if (res.code == 0) {
this.strategyOptions = res.data;
}
} catch (e) {
console.log(e)
}
}
SymbolList = async () => {
try {
this.symbolOptions = await getLocalSymbolList();
} catch (e) {
console.log(e)
}
}
componentDidMount() {
// 获取交易策略
this.getStrategy()
// 获取交易对列表
this.SymbolList();
}
onClose = () => {
const {onClose} = this.props;
if (onClose) {
onClose();
}
}
render() {
const {visible} = this.props;
const state = this.state;
return (
<Dialog visible={visible} placement={"center"} onClose={this.onClose} footer={false}
className={[isMobile() ? 'trade-dialog__mobile' : ''].join(' ')}>
<div className='custom-trade-form'>
<div className='trade-form-item'>
<div className='trade-form-item__label required'>用户</div>
<div className='trade-form-item__value'>
<CustomSelect value={state[users]} name={users}
options={this.userOptions}
className={"trade-dialog-select"}
clearable={true} multiple={true} autoWidth={false}
popupProps={{
overlayClassName: 'trade-dialog-select__overlay'
}} onChange={this.onValueChange}></CustomSelect>
</div>
</div>
<div className='trade-form-item'>
<div className='trade-form-item__label required'>交易对</div>
<div className='trade-form-item__value'>
<CustomSelect value={state[symbols]} name={symbols}
options={this.symbolOptions}
filterable={true}
className={"trade-dialog-select"}
clearable={true} multiple={true} autoWidth={false}
popupProps={{
overlayClassName: 'trade-dialog-select__overlay'
}} onChange={this.onValueChange}></CustomSelect>
{/*<CustomInput value={state[SpotTradeField.symbol]} name={SpotTradeField.symbol}*/}
{/* align={'center'} type={"text"}*/}
{/* onChange={this.onValueChange}>*/}
{/*</CustomInput>*/}
</div>
</div>
<div className='trade-form-item'>
<div className='trade-form-item__label'>策略</div>
<div className='trade-form-item__value'>
<CustomSelect value={state[SpotTradeField.spot_strategy_id]}
name={SpotTradeField.spot_strategy_id} options={this.strategyOptions}
className={"trade-dialog-select"}
clearable={true} autoWidth={false}
popupProps={{
overlayClassName: 'trade-dialog-select__overlay'
}} onChange={this.onValueChange}></CustomSelect>
</div>
</div>
<div className='trade-form-item'>
<div className='trade-form-item__label required'>买卖类型</div>
<div className='trade-form-item__value'>
<CustomSelect value={state[SpotTradeField.direction]}
name={SpotTradeField.direction}
options={this.positionSideOptions}
className={"trade-dialog-select"}
clearable={true} autoWidth={false}
popupProps={{
overlayClassName: 'trade-dialog-select__overlay'
}} onChange={this.onValueChange}></CustomSelect>
</div>
</div>
<div className='trade-form-item'>
<div className='trade-form-item__label required'>交易类型</div>
<div className='trade-form-item__value'>
<CustomSelect value={state[SpotTradeField.order_type]}
name={SpotTradeField.order_type} options={this.orderTypeOptions}
className={"trade-dialog-select"}
clearable={true} autoWidth={false}
popupProps={{
overlayClassName: 'trade-dialog-select__overlay'
}} onChange={this.onValueChange}></CustomSelect>
</div>
</div>
<div className='trade-form-item' style={{
display: isShow(state[SpotTradeField.order_type] === 'LIMIT')
}}>
<div className='trade-form-item__label required'>限价价格</div>
<div className='trade-form-item__value'>
<CustomInput type={"number"} value={state[SpotTradeField.limit_price]} align={'center'}
name={SpotTradeField.limit_price}
onChange={this.onValueChange}></CustomInput>
</div>
</div>
<div className='trade-form-item'>
<div className='trade-form-item__value'>
<div className='trade-form-submit'>
<CustomButton icon={<ResetSvg/>} onClick={this.onReset}>重置</CustomButton>
<CustomButton icon={<SubmitSvg/>} onClick={this.onSubmit}>提交</CustomButton>
</div>
</div>
</div>
</div>
</Dialog>
);
}
}
.custom-trade-select-box {
display: flex;
flex-wrap: wrap;
row-gap: 6px;
align-items: center;
padding: 0 12px;
margin-left: -12px;
& > :not(:first-child) {
margin-left: 12px;
}
& > * {
margin-left: 12px;
}
.custom-trade-input {
display: flex;
align-items: center;
font-size: 12px;
white-space: nowrap;
.label {
margin-right: 10px;
}
.trade-dialog-select {
.t-select {
.t-input__wrap {
width: 100% !important;
.t-input {
&:hover {
border-color: #C99400;
}
}
}
.t-input--focused {
box-shadow: none;
border-color: #C99400;
}
.t-fake-arrow--active {
color: #C99400;
}
.t-input__prefix {
.t-tag {
background-color: #C99400;
color: #fff;
font-weight: 600;
font-size: 11px;
.t-icon {
color: #fff;
}
}
}
}
}
.t-input {
height: 24px;
.t-input__inner {
font-size: 12px;
}
}
}
.custom-trade-select {
display: flex;
align-items: center;
white-space: nowrap;
font-size: 12px;
.label {
}
.real-trade-select {
.t-input__wrap {
.t-input {
font-size: 12px;
border: none;
}
.t-input--focused {
box-shadow: none;
}
}
}
}
}
.custom-trade-select-box__mobile {
border-bottom: 1px solid #EAECEF;
padding-bottom: 6px;
}
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 {getLocalUserList, getLocalSymbolList} from '@/js/utils/local';
import CustomInput from '@/js/components/Input';
import {isShow} from '@/js/utils/dom';
class TradeSelect extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
user: '',
status: '',
userSelect: {
label: '用户',
options: getLocalUserList(),
},
}
// 交易对options
this.SymbolOptions = [];
}
onFilter(params: any) {
// 请求表格
if (this.props.FilterChange) {
this.props.FilterChange(params)
}
}
valueChange = (value: string | number, name: string) => {
this.setState({
[name]: value,
})
}
getSymb = async () => {
this.SymbolOptions = await getLocalSymbolList();
}
componentDidMount() {
// 获取交易对
this.getSymb();
}
render() {
const {userSelect} = this.state;
return (
<div className={[isMobile() ? 'custom-trade-select-box__mobile' : ''].join(' ')}>
<div
className={['custom-trade-select-box'].join(' ')}>
<div className='custom-trade-select'>
<span className='label'>{userSelect.label}</span>
<CustomSelect className='real-trade-select' name={'user'} value={this.state.user}
options={userSelect.options} onChange={this.valueChange}></CustomSelect>
</div>
<div className='custom-trade-input'>
<span className='label'>交易对</span>
<CustomSelect value={this.state.pairs} name={'pairs'}
options={this.SymbolOptions}
filterable={true}
className={"trade-dialog-select"}
clearable={true} multiple={false} autoWidth={false}
popupProps={{
overlayClassName: 'trade-dialog-select__overlay'
}} onChange={this.valueChange}></CustomSelect>
</div>
<div className='custom-trade-input' style={{
display: isShow(this.props.tableType === '2')
}}>
<span className='label'>状态</span>
<CustomInput name={'status'} type={'text'} onChange={this.valueChange}
value={this.state.status}></CustomInput>
</div>
<CustomButton onClick={this.onFilter.bind(this, {
exchange_users_id: this.state.user,
symbol: this.state.pairs,
status: this.state.status,
})}>查询</CustomButton>
<CustomButton onClick={this.onFilter.bind(this, {
exchange_users_id: this.state.user,
symbol: this.state.pairs,
status: this.state.status,
})}>刷新</CustomButton>
</div>
{this.props.children}
</div>
);
}
}
export default TradeSelect;
.contract-trade-page {
display: flex;
flex-direction: column;
height: 100%;
}
import './index.less'
import {Head} from '@inertiajs/react'; import {Head} from '@inertiajs/react';
import {Component} from 'react'; import {Component} from 'react';
import Layout from '@/js/Layout'; import Layout from '@/js/Layout';
import {ReactComponent as Logo} from '@/assets/svg/add.svg'; import {isMobile} from '@/js/utils/tool';
import {isMobile} from '@/js/utils/tool' import Content from "../../Layout/Content";
import Content from "@/js/Layout/Content"; import ContractAccount from "./components/ContractAccount";
import ContractTrade from './components/ContractTrade';
interface MyProps { interface MyProps {
info: any info: any
...@@ -15,17 +17,10 @@ interface MyState { ...@@ -15,17 +17,10 @@ interface MyState {
class Index extends Component<MyProps, MyState> { class Index extends Component<MyProps, MyState> {
constructor(props) { constructor(props) {
super(props); super(props);
this.name = '你好'
} }
// componentWillUnmount() {
// console.log('我先执行')
// }
componentDidMount() { componentDidMount() {
console.log(isMobile()) console.log(isMobile())
// 请求接口
console.log('我先执行')
} }
shouldComponentUpdate(next: any, old: any): boolean { shouldComponentUpdate(next: any, old: any): boolean {
...@@ -37,9 +32,10 @@ class Index extends Component<MyProps, MyState> { ...@@ -37,9 +32,10 @@ class Index extends Component<MyProps, MyState> {
<Layout> <Layout>
<Head title={this.props.info.title}></Head> <Head title={this.props.info.title}></Head>
<Content> <Content>
<h1>我是详情页面</h1> <div className='contract-trade-page'>
<div>{this.name}</div> <ContractAccount></ContractAccount>
<Logo></Logo> <ContractTrade></ContractTrade>
</div>
</Content> </Content>
</Layout> </Layout>
) )
......
...@@ -3,21 +3,31 @@ import '../css/app.css'; ...@@ -3,21 +3,31 @@ import '../css/app.css';
import '../css/ui.less'; import '../css/ui.less';
// tdesign // tdesign
import 'tdesign-react/es/style/index.css'; // 少量公共样式 import 'tdesign-react/es/style/index.css'; // 少量公共样式
import {createInertiaApp} from '@inertiajs/react' import {createInertiaApp} from '@inertiajs/react'
import {createRoot} from 'react-dom/client' import {createRoot} from 'react-dom/client'
import {Provider} from 'react-redux' import {Provider} from 'react-redux'
import store from './redux/store' import store from './redux/store'
async function initPage(fun) {
let result = null;
const res = await fun();
console.log(res)
return result;
}
createInertiaApp({ createInertiaApp({
resolve: name => { resolve: name => {
// 不代码拆分
const pages = import.meta.glob('./Pages/**/*.tsx', { const pages = import.meta.glob('./Pages/**/*.tsx', {
// 是否拆分代码(懒加载) eager: true,
eager: false,
}) })
return pages[`./Pages/${name}.tsx`] return pages[`./Pages/${name}.tsx`]
// 代码拆分
// const pages = import.meta.glob('./Pages/**/*.tsx')
// return pages[`./Pages/${name}.tsx`]()
}, setup({el, App, props}) { }, setup({el, App, props}) {
// props.initialComponent = initPage(props.initialComponent);
createRoot(el).render(<Provider store={store}> createRoot(el).render(<Provider store={store}>
<App {...props} /> <App {...props} />
</Provider>) </Provider>)
......
.reset-t-checkbox {
.t-checkbox__input {
border-color: #C99400 !important;
}
}
.t-is-checked {
.t-checkbox__input {
background-color: #C99400 !important;
border-color: #C99400 !important;
}
&:hover {
.t-checkbox__input {
border-color: #C99400;
}
}
}
import './index.less';
import {Checkbox as TCheckbox} from 'tdesign-react';
import {useState} from 'react'
export default function (props) {
const {checked} = props;
const [myChecked, setChecked] = useState(checked ?? false);
const onChange = (value: boolean) => {
setChecked(value);
if (props.onChange) {
props.onChange(value);
}
}
return (
<TCheckbox className={'reset-t-checkbox'} checked={myChecked} onChange={onChange}></TCheckbox>
)
}
...@@ -55,7 +55,7 @@ class InputNumber extends Component<any, any> { ...@@ -55,7 +55,7 @@ class InputNumber extends Component<any, any> {
theme="normal" theme="normal"
defaultValue={1} defaultValue={1}
value={this.props.value} value={this.props.value}
max={1000} min={0}/> />
{ {
realAddAndSubtract && ( realAddAndSubtract && (
<div className='add' onClick={this.onAdd}>+</div> <div className='add' onClick={this.onAdd}>+</div>
......
...@@ -26,10 +26,11 @@ ...@@ -26,10 +26,11 @@
.reset-t-pagination__mobile { .reset-t-pagination__mobile {
padding: 12px; padding: 12px;
.t-pagination__number { .t-pagination__number.t-is-current {
&:hover { &:hover, &:active {
color: white; color: white;
} }
} }
} }
...@@ -2,10 +2,11 @@ import './index.less'; ...@@ -2,10 +2,11 @@ import './index.less';
import {Select as TSelect} from 'tdesign-react'; import {Select as TSelect} from 'tdesign-react';
export default function (props) { export default function (props) {
const {options, className, clearable, multiple, autoWidth, popupProps, name, value} = props; const {options, className, clearable, multiple, filterable, autoWidth, popupProps, name, value} = props;
// autoWidth默认为true // autoWidth默认为true
const propsAutoWidth = autoWidth ?? true; const propsAutoWidth = autoWidth ?? true;
const propsPopupProps = popupProps ?? {}; const propsPopupProps = popupProps ?? {};
const propsFilterable = filterable ?? false;
const realName = name ?? ''; const realName = name ?? '';
const onChange = (value) => { const onChange = (value) => {
if (props.onChange) { if (props.onChange) {
...@@ -18,6 +19,7 @@ export default function (props) { ...@@ -18,6 +19,7 @@ export default function (props) {
className={className} className={className}
value={value} value={value}
clearable={clearable} clearable={clearable}
filterable={propsFilterable}
autoWidth={propsAutoWidth} autoWidth={propsAutoWidth}
popupProps={propsPopupProps} popupProps={propsPopupProps}
multiple={multiple} multiple={multiple}
......
...@@ -23,3 +23,25 @@ export const ContractTradeField = { ...@@ -23,3 +23,25 @@ export const ContractTradeField = {
order_type: 'order_type', // 交易类型 order_type: 'order_type', // 交易类型
limit_price: 'limit_price', // 限价价格 limit_price: 'limit_price', // 限价价格
} }
/**
* 现货交易字段
*/
export const SpotTradeField = {
user_id: 'user_id', // 用户
'symbol': 'symbol', // 交易对
spot_strategy_id: 'spot_strategy_id', // 策略
direction: 'direction', // 买卖类型
amount: 'amount', // 买入金额
stop_surplus: 'stop_surplus', // 止盈
stop_loss: 'stop_loss', // 止损
quantity_ratio: 'quantity_ratio', // 卖出比例
order_type: 'order_type', // 交易类型
limit_price: 'limit_price', // 限价价格
}
// 买卖类型
export const TradeDirection = {
'1': '买入',
'2': '卖出'
}
...@@ -46,3 +46,24 @@ export const ContractAssist = () => { ...@@ -46,3 +46,24 @@ export const ContractAssist = () => {
headers: getHeaders(), headers: getHeaders(),
}); });
} }
// 交易策略
export const ContractStrategy = () => {
return request.get('/admin-api/api/contract/strategy', {
headers: getHeaders(),
});
}
// 批量操作(发起交易)
export const ContractBatchOperation = (data: any) => {
return request.post('/admin-api/api/contract/operation', data, {
headers: getHeaders(),
})
}
// 撤销委托
export const onContractRevoke = (data: any) => {
return request.post('/admin-api/api/contract/cancel', data, {
headers: getHeaders(),
})
}
import cookie from 'js-cookie'; import cookie from 'js-cookie';
import request from '../request';
// api公共配置 // api公共配置
...@@ -13,3 +14,10 @@ export const getHeaders = () => { ...@@ -13,3 +14,10 @@ export const getHeaders = () => {
'Authorization': 'Bearer ' + getUserCookie() 'Authorization': 'Bearer ' + getUserCookie()
} }
} }
// 获取交易对列表
export const getSymbolList = () => {
return request.get('/admin-api/api/helper/symbols', {
headers: getHeaders(),
})
}
import {getHeaders} from './index'; import {getHeaders} from './index';
import {ContractClosePosition} from './contract'; import {ContractClosePosition, onContractRevoke} from './contract';
import {show_message} from "../tdesign"; import {show_message, open_loading} from "../tdesign";
import {loading} from 'tdesign-react' import {loading} from 'tdesign-react';
import {SpotCancel} from './spot';
/** /**
* 复用的接口 * 复用的接口
*/ */
// 平仓 // 合约平仓
export const ClosePosition = async (data: any, needLoading: boolean = true) => { export const ClosePosition = async (data: any, needLoading: boolean = true) => {
try { try {
let loadingInstance: any = null; let loadingInstance: any = null;
if (needLoading) { if (needLoading) {
loadingInstance = loading({ loadingInstance = open_loading();
size: '20px',
loading: true,
});
} }
const res: any = await ContractClosePosition(data); const res: any = await ContractClosePosition(data);
if (needLoading && loadingInstance) { if (needLoading && loadingInstance) {
...@@ -30,3 +28,49 @@ export const ClosePosition = async (data: any, needLoading: boolean = true) => { ...@@ -30,3 +28,49 @@ export const ClosePosition = async (data: any, needLoading: boolean = true) => {
console.log(e) console.log(e)
} }
} }
// 合约撤销
export const ContractRevoke = async (data: any, needLoading: boolean = true) => {
let loadingInstance: any = null;
try {
if (needLoading) {
loadingInstance = open_loading();
}
const res: any = await onContractRevoke(data);
if (loadingInstance) {
loadingInstance.hide()
}
if (res.code == 0) {
show_message('撤销成功', 'success');
return true;
}
return false;
} catch (e) {
console.log(e);
loadingInstance && loadingInstance.hide();
return false;
}
}
// 现货撤销
export const onSpotRevoke = async (data: any, needLoading: boolean = true) => {
let loadingInstance: any = null;
try {
if (needLoading) {
loadingInstance = open_loading();
}
const res: any = await SpotCancel(data);
if (loadingInstance) {
loadingInstance.hide()
}
if (res.code == 0) {
show_message('撤销成功', 'success');
return true;
}
return false;
} catch (e) {
console.log(e);
loadingInstance && loadingInstance.hide();
return false;
}
}
import request from '../request';
import {getHeaders} from './index';
// 获取用户列表
export const SpotUserList = () => {
return request.get('/admin-api/api/spot/assets', {
headers: getHeaders(),
});
}
// 现货辅助列表
export const SpotAssist = () => {
return request.get('/admin-api/api/helper/spots', {
headers: getHeaders(),
});
}
// 持有资产(仓位)
export const SpotAssets = () => {
return request.get('/admin-api/api/spot/assets', {
headers: getHeaders(),
});
}
// 获取交易策略
export const SpotStrategy = () => {
return request.get('/admin-api/api/spot/strategy', {
headers: getHeaders(),
});
}
// 批量操作,开始交易
export const SpotBatchOperation = (data: any) => {
return request.post('/admin-api/api/spot/operation', data, {
headers: getHeaders(),
});
}
// 获取当前委托
export const SpotCurrentEntrustment = (data: any) => {
return request.get('/admin-api/api/spot/entrust', {
params: data,
headers: getHeaders(),
});
}
// 撤销
export const SpotCancel = (data: any) => {
return request.post('/admin-api/api/spot/cancel', data, {
headers: getHeaders(),
});
}
// 历史成交
export const SpotHistoryTransaction = (data: any) => {
return request.get('/admin-api/api/spot/history', {
params: data,
headers: getHeaders(),
});
}
import {getUserList} from './api/auth'; import {getUserList} from './api/auth';
import {ContractAssist} from './api/contract'; import {ContractAssist} from './api/contract';
import {SpotAssist} from './api/spot';
import {getSymbolList} from './api';
// 用户列表key // 用户列表key
export const localUserKey = 'trade_user'; export const localUserKey = 'trade_user';
// 合约辅助列表key // 合约辅助列表key
export const localContractHelpKey = 'contract_help'; export const localContractHelpKey = 'contract_help';
// 现货辅助列表key
export const localSpotHelpKey = 'spot_help';
// 交易对的key
export const localSymbolKey = 'symbol_list';
// 本地缓存是否到期 // 本地缓存是否到期
export const isLocalUserExpire = (key: string, expired: number) => { export const isLocalUserExpire = (key: string, expired: number) => {
...@@ -94,13 +100,14 @@ export const getAdminUserList = async () => { ...@@ -94,13 +100,14 @@ export const getAdminUserList = async () => {
} }
// 获取合约辅助列表 // 请求合约辅助列表
export const getContractHelpList = async (skip: boolean = false) => { export const getContractHelpList = async (skip: boolean = false) => {
// 清空 // 清空
// window.localStorage.setItem(localContractHelpKey, '') // window.localStorage.setItem(localContractHelpKey, '')
if (isLocalUserExpire(localContractHelpKey, 24 * 60 * 60 * 1000) || skip) { if (isLocalUserExpire(localContractHelpKey, 24 * 60 * 60 * 1000) || skip) {
try { try {
const res: any = await ContractAssist(); const res: any = await ContractAssist();
// console.log(res.data)
if (res.code == 0) { if (res.code == 0) {
// 存本地 // 存本地
setLocalData(localContractHelpKey, res.data); setLocalData(localContractHelpKey, res.data);
...@@ -115,8 +122,8 @@ export const getContractHelpList = async (skip: boolean = false) => { ...@@ -115,8 +122,8 @@ export const getContractHelpList = async (skip: boolean = false) => {
} }
} }
// 获取合约辅助列表中字段值 // 合约辅助指定字段的列表
export const getLocalContractHelper = (key: string, value: string) => { export const getLocalContractHelperList = (key: string) => {
let users = window.localStorage.getItem(localContractHelpKey); let users = window.localStorage.getItem(localContractHelpKey);
if (users) { if (users) {
users = JSON.parse(users); users = JSON.parse(users);
...@@ -128,8 +135,144 @@ export const getLocalContractHelper = (key: string, value: string) => { ...@@ -128,8 +135,144 @@ export const getLocalContractHelper = (key: string, value: string) => {
list = data.position_side; list = data.position_side;
} else if (key == 'side') { } else if (key == 'side') {
list = data.side; list = data.side;
} else if (key == 'exchange') {
list = data.exchange;
}
return list;
} }
return [];
}
// 获取合约辅助列表中字段
export const getLocalContractHelper = (key: string, value: string) => {
const list = getLocalContractHelperList(key);
if (list.length) {
const obj = list.find((item: any) => item.value == value); const obj = list.find((item: any) => item.value == value);
return obj ? obj.label : 'error'; return obj ? obj.label : 'error';
} }
} }
// 获取合约辅助列表select列表
export const getLocalContractHelperSelect = (key: string, add: boolean = true) => {
const list = getLocalContractHelperList(key);
if (list.length) {
let newList: any[] = list.map((item: any) => {
return {
label: item.label,
value: item.value,
}
})
if (add) {
// 头部添加
newList.unshift({
label: '全部',
value: ''
})
}
return newList;
}
return [];
}
// 现货辅助列表-存本地
export const setLocalSpotHelper = async (data: any, skip: boolean = false) => {
// 清空
window.localStorage.setItem(localSpotHelpKey, '')
if (isLocalUserExpire(localSpotHelpKey, 24 * 60 * 60 * 1000) || skip) {
try {
const res: any = await SpotAssist();
console.log(res.data);
if (res.code == 0) {
// 存本地
setLocalData(localSpotHelpKey, res.data);
}
} catch (e) {
console.log(e)
}
} else {
// 打印本地数据
// const data = window.localStorage.getItem(localSpotHelpKey);
// console.log(JSON.parse(data));
}
}
// 现货辅助列表-指定字段
export const getLocalSpotHelperList = (key: string) => {
let users = window.localStorage.getItem(localSpotHelpKey);
if (users) {
users = JSON.parse(users);
const data = users.list;
let list = []
if (key == 'direction') {
list = data.direction;
} else if (key == 'order_type') {
list = data.order_type;
} else if (key == 'status') {
list = data.status;
}
return list;
}
return [];
}
// 获取现货辅助列表中字段
export const getLocalSpotHelper = (key: string, value: string) => {
const list = getLocalSpotHelperList(key);
if (list.length) {
const obj = list.find((item: any) => item.value == value);
if (obj) {
return obj.label;
}
return value;
}
return value;
}
// 获取现货辅助select列表
export const getLocalSpotHelperSelect = (key: string, add: boolean = true) => {
const list = getLocalSpotHelperList(key);
if (list.length) {
let newList: any[] = list.map((item: any) => {
return {
label: item.label,
value: item.value,
}
})
if (add) {
// 头部添加
newList.unshift({
label: '全部',
value: ''
})
}
return newList;
}
return [];
}
// 获取交易对列表--5分钟更新一次
export const getLocalSymbolList = async (priorityLocal: boolean = true) => {
// 优先获取本地的交易对
if (priorityLocal) {
let localData = window.localStorage.getItem(localSymbolKey);
// 存在数据且没有到期
if (localData && !isLocalUserExpire(localSymbolKey, 5 * 60 * 1000)) {
const data = JSON.parse(localData);
return data.list;
}
}
// 请求接口
try {
const res: any = await getSymbolList();
if (res.code == 0) {
// 存本地
setLocalData(localSymbolKey, res.data);
return res.data;
}
return [];
} catch (e) {
console.log(e)
return [];
}
}
import {MessagePlugin} from 'tdesign-react' import {MessagePlugin, loading} from 'tdesign-react'
export const show_message = ( export const show_message = (
value: string, value: string,
...@@ -20,3 +20,11 @@ export const show_message = ( ...@@ -20,3 +20,11 @@ export const show_message = (
// 类型报错-所以用上面的方法 // 类型报错-所以用上面的方法
// MessagePlugin[type](value); // MessagePlugin[type](value);
}; };
// 打开全局loading
export const open_loading = () => {
return loading({
size: '20px',
loading: true,
});
}
...@@ -24,3 +24,10 @@ export const formValidate = (fields: string[], data: any) => { ...@@ -24,3 +24,10 @@ export const formValidate = (fields: string[], data: any) => {
} }
return true; return true;
} }
// 判断两个对象里的值是否相等
export const isEqual = (object1: any, object2: any) => {
const keys1 = Object.keys(object1);
const keys2 = Object.keys(object2);
return true;
}
...@@ -30,3 +30,47 @@ export const getSuccessColor = (status: string) => { ...@@ -30,3 +30,47 @@ export const getSuccessColor = (status: string) => {
} }
return '#D95E71' return '#D95E71'
} }
// 成功失败的文字
export const getSuccessText = (status: any) => {
if (!status) {
return 'Null'
}
if (status.code === '200') {
return '成功'
} else if (!status.code) {
return 'null'
} else {
return '失败'
}
}
// 买入卖出颜色
export const getBuySellColor = (direction: string) => {
if (direction == 'SELL' || direction == '2') {
return '#D95E71'
} else if (direction == 'BUY' || direction == '1') {
return '#0E9D6D';
}
return 'blue';
}
// 买入卖出文字
export const getBuySellText = (direction: string) => {
if (direction == 'SELL') {
return '卖出'
} else if (direction == 'BUY') {
return '买入';
}
return direction;
}
// status对应的颜色
export const getStatusColor = (status: number) => {
let greenStatus = [1, 2, 3];
if (greenStatus.includes(status)) {
return '#0E9D6D'
} else {
return '#D95E71'
}
}
...@@ -6,7 +6,8 @@ import svgr from 'vite-plugin-svgr'; ...@@ -6,7 +6,8 @@ import svgr from 'vite-plugin-svgr';
export default defineConfig({ export default defineConfig({
plugins: [laravel({ plugins: [laravel({
input: ['resources/js/app.jsx'], refresh: true, // 构建ssr input: ['resources/js/app.jsx'], refresh: false,
// 构建ssr
ssr: 'resources/js/ssr.jsx', ssr: 'resources/js/ssr.jsx',
}), React(), viteCompression(), svgr()], server: { }), React(), viteCompression(), svgr()], server: {
port: 3008, host: '127.0.0.1', proxy: { port: 3008, host: '127.0.0.1', proxy: {
......
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