Browse Source

新增股票页面

master
liaoxinyu 3 weeks ago
parent
commit
aa9d510b50
  1. 15
      src/api/exchange.js
  2. 14
      src/api/market.js
  3. 7
      src/api/option.js
  4. 22
      src/api/order.js
  5. 3
      src/components/CommonHeader.vue
  6. 461
      src/components/StockKline.vue
  7. 16
      src/i18n/en.json
  8. 16
      src/i18n/tw.json
  9. 6
      src/index.html
  10. 9
      src/router/index.js
  11. 1
      src/utils/consts.js
  12. 390
      src/views/exchangeStock/book-trades.vue
  13. 618
      src/views/exchangeStock/chart-deal.vue
  14. 706
      src/views/exchangeStock/index.vue
  15. 824
      src/views/exchangeStock/make-deal.vue
  16. 54
      src/views/exchangeStock/market-news.vue
  17. 358
      src/views/exchangeStock/order-list.vue
  18. 260
      src/views/exchangeStock/symbols.vue

15
src/api/exchange.js

@ -11,6 +11,16 @@ class Exchange {
static storeEntrust(data) {
return server.post(`/exchange/storeEntrust`, data);
}
// 获取账户余额
static getstockUserBalance(symbol) {
return server.get(`/stock/getUserCoinBalance?symbol=${encodeURIComponent(symbol)}`);
}
// 提交订单
static stockstoreEntrust(data) {
return server.post(`/stock/storeEntrust`, data);
}
// 获取币种基本信息
static getSymbolInfo(data) {
@ -26,6 +36,11 @@ class Exchange {
static getCurrencyExCny(data){
return server.get('/market/getCurrencyExCny',{params:data})
}
// 获取持仓
static stockholdPosition(data, config) {
return server.get('/stock/holdPosition', {params:data,config} )
}
}
export default Exchange;

14
src/api/market.js

@ -50,7 +50,19 @@ class Market {
static getCoinInfo(params) {
return server.get(`/exchange/getCoinInfo`,{ params });
}
// 初始化查询市场行情
static getstockMarketList() {
return server.get(`/stock/getMarketList`);
}
// 初始化买卖盘数据
static getstockMarketInfo(symbol) {
return server.get(`/stock/getMarketInfo?symbol=${symbol}`);
}
// 币种信息
static getstockCoinInfo(params) {
return server.get(`/stock/getCoinInfo`,{ params });
}
}
export default Market;

7
src/api/option.js

@ -33,6 +33,13 @@ class Option {
params: data
})
}
static getStockKline(data) {
// let url = `https://api.hadax.com/market/history/kline`;
let url = `/option/getStockKline`;
return server.get(url, {
params: data
})
}
/**
* 获取可用于期权交易的币种列表
*/

22
src/api/order.js

@ -26,6 +26,12 @@ class Order {
params:data
});
}
static getstockHistoryEntrust(data) {
return server.get(`/stock/getHistoryEntrust`,{
params:data
});
}
/**
* 获取当前委托
* @param {object} data
@ -39,6 +45,12 @@ class Order {
params:data
});
}
static getstockCurrentEntrust(data) {
return server.get(`/stock/getCurrentEntrust`,{
params:data
});
}
// 获取止盈止损单
static getConditionEntrust(data) {
@ -60,6 +72,11 @@ class Order {
params:data
});
}
static getstockEntrustTradeRecord(data) {
return server.get(`/stock/getEntrustTradeRecord`,{
params:data
});
}
/**
* 撤单
@ -72,6 +89,11 @@ class Order {
static cancelEntrust(data) {
return server.post(`/exchange/cancelEntrust`,data);
}
static stockcancelEntrust(data) {
return server.post(`/stock/cancelEntrust`,data);
}
/**
* 批量撤单
* @param {object} data

3
src/components/CommonHeader.vue

@ -42,6 +42,9 @@
<li class="nav-item">
<router-link class="nav-link" :to="contract.url">{{ contract.label }}</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" to="/exchangestock">{{ $t('exchange.a1') }}</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" :to="learn.url">{{ learn.label }}</router-link>
</li>

461
src/components/StockKline.vue

@ -0,0 +1,461 @@
<template>
<div class="main-chart mb5" style="height: 100%;">
<!-- TradingView Widget BEGIN -->
<div class="tradingview-widget-container" style="height: 100%;">
<div id="tradingview_lautin" style="height: 100%;">
<!-- 存放图表库容器 -->
</div>
</div>
<!-- TradingView Widget END -->
</div>
</template>
<script>
import Model from "@/api/custom/Model";
import Option from "@/api/option";
import Exchange from "@/api/exchange";
import tvStyle from "@/assets/js/tvStyle.js";
import { mapState } from "vuex";
import bus from "@/components/bus.js";
export default {
props: ["socket", "symbol", "priceDecimals"],
data() {
return {
model: null, //
interval: "D" ,// []TVresolution
// interval: "60" ,// []TVresolution
theme:localStorage.getItem('theme')||'dark',
intertime: ''
};
},
computed: {
lang() {
let local;
// console.log(localStorage.lang)
if (localStorage.lang) {
if (localStorage.lang == "tw") {
local = "zh_TW";
} else if (localStorage.lang == "cn") {
local = "zh";
} else if (localStorage.lang == "kor") {
local = "ko";
} else if (localStorage.lang == "jp") {
local = "ja";
} else if (localStorage.lang == "de") {
local = "de_DE";
} else if (localStorage.lang == "fra") {
local = "fr";
} else if (localStorage.lang == "it") {
local = "it";
} else if (localStorage.lang == "pt") {
local = "pt";
} else if (localStorage.lang == "spa") {
local = "es";
} else if (localStorage.lang == "en") {
local = "en";
}else {
local = "en";
}
}
return local;
},
// ...mapState({
// theme: "theme"
// })
},
methods: {
translateInterval2Period() {
let period;
switch (this.interval) {
case "1":
period = "1min";
break;
case "5":
period = "5min";
break;
case "15":
period = "15min";
break;
case "30":
period = "30min";
break;
case "60":
period = "60min";
break;
case "D":
case "1D":
period = "1day";
break;
case "W":
case "1W":
period = "1week";
break;
case "M":
case "1M":
period = "1mon";
break;
}
return period;
},
translateInterval2Period1() {
let period1;
switch (this.intertime) {
case "1":
period1 = "1min";
break;
case "5":
period1 = "5min";
break;
case "15":
period1 = "15min";
break;
case "30":
period1 = "30min";
break;
case "60":
period1 = "60min";
break;
case "D":
case "1D":
period1 = "1day";
break;
case "W":
case "1W":
period1 = "1week";
break;
case "M":
case "1M":
period1 = "1mon";
break;
}
return period1;
},
//
createBtns() {
const model = this.model;
const widget = this.model.widget;
// widget.createButton()
// .addClass("my-theme")
// .text("")
// .on("click", function () {
// console.log(widget);
// widget.changeTheme("aa");
// }).parent().addClass('my-aa')
//
const resolutions = [
// {
// title: 'Time',
// resolution: '1',
// chartType: 3
// }, // 123
{
title: "1" + this.$t("exchange.min"),
resolution: "1",
chartType: 1
},
{
title: "5" + this.$t("exchange.min"),
resolution: "5",
chartType: 1
},
{
title: "15" + this.$t("exchange.min"),
resolution: "15",
chartType: 1
},
{
title: "30" + this.$t("exchange.min"),
resolution: "30",
chartType: 1
},
{
title: "1" + this.$t("exchange.hour"),
resolution: "60",
chartType: 1
},
{
title: "1" + this.$t("exchange.day"),
resolution: "D",
chartType: 1
},
{
title: "1" + this.$t("exchange.week"),
resolution: "W",
chartType: 1
},
{
title: "1" + this.$t("exchange.month"),
resolution: "M",
chartType: 1
}
];
let btns = [], //
parents = [];
resolutions.forEach(item => {
//
let $parent = widget
.createButton()
.attr("title", item.title)
.addClass("my-date")
.css({
background: (index, value) => {
if (this.interval == item.resolution) {
return this.theme=='dark'?'#ccc':'#091722';
}
},
color: () => {
if (this.interval == item.resolution) {
return "#758696";
}
}
})
.text(item.title)
.on("click", function(e) {
const btns = this.parentNode.parentNode.querySelectorAll(
".my-date"
);
btns.forEach(btn => {
if (btn === this) {
btn.style.cssText = `background : ${this.theme=='dark'?'#ccc':'#091722'};
color:#758696;`;
} else btn.style.cssText = ``;
});
// widget.chart().setResolution(item.resolution, function onReadyCallback() {});
model.setResolution(item.resolution, function onReadyCallback() {});
})
.parent()
.addClass("my-group");
parents.push($parent[0]); //
});
widget.chart()
.createStudy(
"Moving Average",
false,
true,
[5, "close", 0],
null,
{
"Plot.color": "#e843da",
}
);
widget.chart()
.createStudy(
"Moving Average",
false,
true,
[10, "close", 0],
null,
{
"Plot.color": "#53b987",
}
);
widget.chart()
.createStudy(
"Moving Average",
false,
true,
[30, "close", 0],
null,
{
"Plot.color": "#ff231f",
}
);
// setTimeout(function () {
// // my-groupDIV
// const resolution_container = document.createElement("div");
// resolution_container.className = "resolution_container";
// $(resolution_container).append($(parents).clone());
// $(resolution_container).replaceAll($(parents[0]));
// //
// }, 50)
},
//
getSymbol() {
if (this.priceDecimals) {
return Promise.resolve({
pair_name: this.priceDecimals
});
} else {
return Exchange.getSymbolInfo({
symbol: this.symbol
});
}
},
//
unzip(b64Data) {
let u8 = window.atob(b64Data);
let jiya = window.pako.inflate(u8)
let str = this.Uint8ArrayToString(jiya);
return JSON.parse(str);
},
Uint8ArrayToString(fileData) {
var dataString = "";
for (var i = 0; i < fileData.length; i++) {
dataString += String.fromCharCode(fileData[i]);
}
return dataString;
},
//
getHistoryCallback(onLoadCallback) {
// solution
this.intertime = this.interval;
this.interval = this.model.interval;
// period
let period1 = this.translateInterval2Period1();
let period = this.translateInterval2Period();
if(this.intertime!==this.model.interval){
this.model.subscribe([
{
cmd: "unsub",
msg: `Kline_${this.symbol}_${period1}`
},
{
cmd: "sub",
msg: `Kline_${this.symbol}_${period}`
}
]);
// symbol getSymbolgetBar
this.model.setSymbol(this.symbol);
}
Option.getStockKline({
symbol: this.symbol,
period,
size: 500,
zip:1
})
.then(data => {
let list = [];
// tv
for (let item of this.unzip(data.data)) {
list.push({
time: item.id * 1000,
open: item.open,
high: item.high,
low: item.low,
close: item.close,
volume: item.amount
});
}
let lastTime = list[list.length - 1].time;
// console.log(lastTime,'--------')
onLoadCallback(list, lastTime);
})
.catch(err => {});
},
//
initTV() {
//
let period = this.translateInterval2Period();
this.model.subscribe([
{
cmd: "sub",
msg: `Kline_${this.symbol}_${period}`
}
]);
// console.log(this.lang)
this.model.init(
{
//
symbol: this.symbol,
interval: this.interval,
container_id: "tradingview_lautin", //
height: 1000,
locale: this.lang, //
priceDecimals: this.priceDecimals,
disabled_features:['header_resolutions','header_symbol_search', "volume_force_overlay"],
enabled_features:['header_indicators'],
overrides: tvStyle[this.theme],
// toolbar_bg: this.theme == "dark" ? "#222e3d" : "#f1f3f6",#121212
toolbar_bg: this.theme == "dark" ? "#121212" : "#f1f3f6",
custom_css_url: `/static/Kline/charting_library/static/css/tradingview_${
this.theme == "dark" ? "black" : "white"
}.css`,
debug:false,
},
this.getHistoryCallback
);
//
this.model.widget.onChartReady(this.createBtns.bind(this));
}
},
watch: {
//
symbol(newVal, oldVal) {
if (!oldVal) {
//
this.initTV();
} else {
//
let period = this.translateInterval2Period();
this.model.subscribe([
{
cmd: "unsub",
msg: `Kline_${oldVal}_${period}`
},
{
cmd: "sub",
msg: `Kline_${newVal}_${period}`
}
]);
// symbol getSymbolgetBar
this.model.setSymbol(newVal);
}
},
},
created() {
bus.$on('sendMsg', msg => {
// console.info(msg)
// this.model = new Model(msg, this);
this.model.conglian(msg)
let period = this.translateInterval2Period();
this.model.subscribe([
{
cmd: "sub",
msg: `Kline_${this.symbol}_${period}`
}
]);
});
},
mounted() {
// console.Info(this.socket)
// ws
this.model = new Model(this.socket, this);
//
if (this.symbol) this.initTV(); // mounted tv
}
};
</script>
<style lang="scss">
#tradingview_lautin {
height: 550px;
}
//
#tradingview_878d2 .my-group {
cursor: pointer !important;
border: 1px solid red !important;
}
</style>

16
src/i18n/en.json

@ -36,7 +36,9 @@
"c7": "White paper address",
"c8": "Official website address",
"c9": "brief introduction",
"c10": "Minimum recharge amount: {num}. Recharge less than the minimum amount will not be posted and cannot be returned."
"c10": "Minimum recharge amount: {num}. Recharge less than the minimum amount will not be posted and cannot be returned.",
"c11": "Stocks",
"c12": "Spot goods"
},
"common": {
"million": "million",
@ -242,7 +244,17 @@
"hour": "hour",
"day": "day",
"week": "week",
"month": "month"
"month": "month",
"a1": "Stock",
"a2": "Current Holdings",
"a3": "Code/Name",
"a4": "Market Value of Holdings",
"a5": "Quantity",
"a6": "Latest Price",
"a7": "Cost",
"a8": "Today's Profit/Loss",
"a9": "Position Profit/Loss",
"a10": "Position Profit/Loss Ratio"
},
"login": {
"resend": "Resend",

16
src/i18n/tw.json

@ -36,7 +36,9 @@
"c7": "白皮書地址",
"c8": "官網地址",
"c9": "簡介",
"c10": "最小充值金額:{num},小於最小金額的充值將不會上帳且無法返回。"
"c10": "最小充值金額:{num},小於最小金額的充值將不會上帳且無法返回。",
"c11": "股票",
"c12": "現貨"
},
"common": {
"million": "幾百萬",
@ -243,7 +245,17 @@
"hour": "小時",
"day": "天",
"week": "周",
"month": "月"
"month": "月",
"a1": "股票",
"a2": "当前持倉",
"a3": "代碼/名稱",
"a4": "持倉市值",
"a5": "數量",
"a6": "最新價",
"a7": "成本",
"a8": "今日盈虧",
"a9": "持倉盈虧",
"a10": "持倉盈虧比例"
},
"login": {
"confirm-password": "確認密碼",

6
src/index.html

@ -69,13 +69,13 @@
<script src="/static/libs/jquery.mCustomScrollbar.js"></script>
<script src="/static/js/custom.js"></script>
<script src="/static/libs/skroll.min.js"></script>
<script src="https://seee.moabwalletss.com/newlink/pako.min.js"></script>
<script src="https://adm.moabwalletss.com/newlink/pako.min.js"></script>
<script>
window.custom = "dark"; // 默认主题
window.api_path = "<%= htmlWebpackPlugin.options.isProduct ? 'https://seee.moabwalletss.com/api/sliderVerify' : 'https://seee.moabwalletss.com/api/sliderVerify' %>";
window.api_path = "<%= htmlWebpackPlugin.options.isProduct ? 'https://adm.moabwalletss.com/api/sliderVerify' : 'https://adm.moabwalletss.com/api/sliderVerify' %>";
// window.api_path = "<%= htmlWebpackPlugin.options.isProduct ? 'http://qkladmin2.ruanmeng.top/api/sliderVerify' : 'http://qkladmin2.ruanmeng.top/api/sliderVerify' %>";
// window.ws_path = "<%= htmlWebpackPlugin.options.isProduct ? 'wss://guanli.coin.amatak.net/ws1' : 'wss://guanli.coin.amatak.net/ws1' %>";
window.ws_path = "<%= htmlWebpackPlugin.options.isProduct ? 'https://seee.moabwalletss.com/api' : 'https://seee.moabwalletss.com/api' %>";
window.ws_path = "<%= htmlWebpackPlugin.options.isProduct ? 'https://adm.moabwalletss.com/api' : 'https://adm.moabwalletss.com/api' %>";
// window.ws_path = "<%= htmlWebpackPlugin.options.isProduct ? 'ws://qkladmin2.ruanmeng.top:2346' : 'ws://qkladmin2.ruanmeng.top:2346' %>";

9
src/router/index.js

@ -43,6 +43,8 @@ import Otc from "./otc";
import Notice from '@/views/notice'
import NoticeDetail from '@/views/notice/detail'
import ExchangeStock from '@/views/exchangeStock'
Vue.use(VueRouter);
// 将多文件路由合并到一起
@ -141,7 +143,12 @@ const routes = [{
path: "/notice/:id",
component: NoticeDetail,
props:true
}
},
{
name: "exchangeStock",
path: "/exchangestock/:symbol?",
component: ExchangeStock
},
]
const router = new VueRouter({

1
src/utils/consts.js

@ -27,6 +27,7 @@ export default {
WS: isProduct ? `wss://adm.moabwalletss.com/ws1` : `wss://adm.moabwalletss.com/ws1`,
// WS1: isProduct ? `wss://guanli.coin.amatak.net/ws2` : `wss://guanli.coin.amatak.net/ws2`,
WS1: isProduct ? `wss://adm.moabwalletss.com/ws2` : `wss://adm.moabwalletss.com/ws2`,
WS2: isProduct ? `wss://adm.moabwalletss.com/ws3` : `wss://adm.moabwalletss.com/ws3`,
}
}
};

390
src/views/exchangeStock/book-trades.vue

@ -0,0 +1,390 @@
<template>
<div class="col-md-3" style="background-color: #121212;padding-left: 0px;padding-right: 0px;margin-right: 8px;">
<div class="mb15"><!-- order-book -->
<div class="d-flex">
<div class="heading" :class="tabcolor == 1 ?'textcolor':''" @click="tabcolor = 1">{{ $t("exchange.order-book") }}</div>
<div class="heading" :class="tabcolor == 2 ?'textcolor':''" @click="tabcolor = 2">{{ $t("exchange.recent-trades") }}</div>
</div>
<table class="table" v-if="tabcolor == 1">
<thead>
<tr style="display:block;">
<th class="w-33">{{ $t("exchange.price") }}({{pair.to}})</th>
<th class="w-33 text-right">{{ $t("exchange.amount") }}
<!-- ({{pair.from}}) -->
({{pair.to}})
</th>
<th class="w-33 text-right">{{ $t("exchange.total") }}({{pair.from}})</th>
</tr>
</thead>
<tbody class="sell-orders" v-if="symbol!='gitpusdt'">
<div class="order-item" v-for="item in sellList" :key="item.id">
<el-progress class="progress" type="line" :stroke-width="39" :percentage="getValue(item.amount)" :show-text="false" color="rgba(216,43,43,0.15)">
</el-progress>
<!-- 卖单 使用弹性盒子倒序排列 -->
<tr style="display:block;" class="tb-cells" @click.stop="handleOrder(item.price)">
<td class="w-33 red" title="pick this price to sell">{{ item.price|omitTo(priceDecimals) }}</td>
<td class="w-33 text-right">{{ item.amount|omitTo(qtyDecimals) }}</td>
<td class="w-33 text-right">{{ item.price|multiple(item.amount, priceDecimals) }}</td>
</tr>
</div>
</tbody>
<tbody class="ob-heading">
<tr style="display:block;" v-if="newTrade">
<td class="w-33">
<span>{{ $t("exchange.last-price") }}</span>
<i :class="newTrade.changeRate > 0 ? 'tri-inc' : 'tri-dec'"></i>
<b :class="newTrade.changeRate > 0 ? 'increace' : 'decreace'">{{ newTrade.price}}</b>
</td>
<td class="w-33 text-right">
<span v-if="langs=='cn'">CNY</span>
<span v-else>$</span>
<!-- {{omitTo(newTrade.price*price_cny)}} -->
<span v-if="langs=='cn'"> {{newTrade.price*priceCny|omitTo(2)}}</span>
<span v-else> {{newTrade.price|omitTo(2)}}</span>
</td>
<td class="w-33 text-right" :class="changeRate.startsWith('+') ? 'increace' : 'decreace'">
<span>{{ $t("exchange.change") }}</span>
{{ changeRate }}
</td>
</tr>
<tr style="display:block;" v-else>
<td class="w-33"><span>{{ $t("exchange.last-price") }}</span> -</td>
<td class="w-33 text-right">
<span>CNY</span> -
</td>
<td class="w-33 text-right"><span>{{ $t("exchange.change") }}</span> -</td>
</tr>
</tbody>
<tbody class="buy-orders" :style="[{'height':symbol!='gitpusdt'?'':'470px!important'}]">
<!-- 买单 反序数值 -->
<div class="order-item" v-for="item in reversed" :key="item.id">
<el-progress class="progress" type="line" :stroke-width="39" :percentage="getValue(item.amount)" :show-text="false" color="rgba(37, 188, 103, 0.15)">
</el-progress>
<!-- 卖单 使用弹性盒子倒序排列 -->
<tr style="display:block;" class="tb-cells" @click.stop="handleOrder(item.price)">
<td class="w-33 green" title="pick this price to buy">{{ item.price|omitTo(priceDecimals) }}</td>
<td class="w-33 text-right">{{ item.amount|omitTo(qtyDecimals) }}</td>
<td class="w-33 text-right">{{ item.price|multiple(item.amount, priceDecimals) }}</td>
</tr>
</div>
</tbody>
</table>
</div>
<div class="market-history" style="border: 0px;" v-if="tabcolor == 2">
<ul class="nav nav-pills" role="tablist" v-if="0">
<li class="nav-item">
<a class="nav-link active" data-toggle="pill" href="#recent-trades" role="tab" aria-selected="true">
{{ $t("exchange.recent-trades") }}
</a>
</li>
<!-- <li class="nav-item">
<a class="nav-link" data-toggle="pill" href="#market-depth" role="tab" aria-selected="false">Market
Depth</a>
</li> -->
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="recent-trades" role="tabpanel">
<table class="table trade-list">
<thead>
<tr>
<th style="display:block;width:100%;">
<div class="w-33">
{{ $t("exchange.price") }}({{pair.to}})
</div>
<div class="w-33 text-right">
{{ $t("exchange.amount") }}({{pair.from}})
</div>
<div class="w-33 text-right">
{{ $t("exchange.time") }}
</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in tradeList" :key="index">
<td style="display:block;width:100%">
<div class="w-33" :style="{color : item.color}">{{ item.price }}</div>
<div class="w-33 text-right">{{ item.amount }}</div>
<div class="w-33 text-right">{{ item.time }}</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- <div class="tab-pane fade" id="market-depth" role="tabpanel">
<div class="depth-chart-container">
<div class="depth-chart-inner">
<div id="lightDepthChart"></div>
</div>
</div>
</div> -->
</div>
</div>
</div>
</template>
<script>
import Market from "@/api/market";
export default {
// props : ["priceDecimals", "qtyDecimals"],
props:[
'priceCny'
],
data() {
return this.$parent;
},
computed: {
langs(){
return localStorage.getItem('lang')||'en'
},
reversed() {
//
if (this.buyList && this.buyList.length) return this.buyList;
else return [];
},
changeRate() {
// 0 0
if (!this.marketInfo || !this.marketInfo.open) return `+0.00%`;
let val = Math.division(
Math.subtr(this.newTrade.price, this.marketInfo.open),
this.marketInfo.open);
// +
let sign = val >= 0 ? '+' : '';
let percentage = `${sign}${Math.multiple(val, 100, 2)}%`;
return percentage;
},
tradeList() {
let count = 0;
// 1~(n-1)绿
if (this.trade && this.trade.length) {
return this.trade.sort((m, n) => {
let dm = Number(m.price),
dn = Number(n.price);
if (dn >= dm) {
n.color = "#53b987";
n.changeRate = 1;
} else {
n.color = "#ff231f";
n.changeRate = -1;
}
n.price = Math.omitTo(n.price, this.priceDecimals);
n.amount = Math.omitTo(n.amount, this.qtyDecimals);
n.time = Date.parseTime(n.ts, false, "{h}:{i}:{s}");
//
if (++count == this.trade.length - 1) {
m.color = "#53b987";
m.changeRate = 1;
m.price = Math.omitTo(m.price, this.priceDecimals);
m.amount = Math.omitTo(m.amount, this.qtyDecimals);
m.time = Date.parseTime(m.ts, false, "{h}:{i}:{s}");
}
});
} else {
return this.trade;
}
}
},
methods: {
// /
getValue(amount) {
const arr = this.buyList.concat(this.sellList).map(item => item.amount);
let max = Math.max(...arr);
return Math.division(amount, max, 2) * 100;
},
//
handleOrder(price, ordertype) {
// order
if (this.passOrderPrice) {
this.buyorder.entrust_price = Math.omitTo(price, this.priceDecimals);
this.sellorder.entrust_price = Math.omitTo(price, this.priceDecimals);
}
},
// progress
format(item) {
return function (percentage) {
return `<span>${Math.omitTo(item.price, this.priceDecimals)}</span>
<span>${Math.omitTo(item.qty, this.qtyDecimals)}</span>
<span>${Math.multiple(item.price, item.qty, this.priceDecimals)}</span>`;
}
},
bookTrades() {
Market.getstockMarketInfo(this.symbol).then(response => {
//
this.sellList = response.sellList.sort((a, b) => b.price - a.price);
this.buyList = response.buyList;
this.trade = response.tradeList;
}).catch(err => {
});
}
},
mounted() {
// mounted[]created []ajax
this.bookTrades();
},
}
</script>
<style lang="scss">
.w-33 {
width: 32% !important;
display: inline-block !important;
vertical-align: text-top !important;
box-sizing: border-box !important;
}
.buy-orders {
height: 235px !important;
overflow: hidden !important;
td {
@include ff(OpenSans-Regular);
}
}
.sell-orders {
@extend .buy-orders;
@include flexible(column-reverse, flex-start, flex-start, wrap);
// flex-shrink: 0; //
display: flex !important;
overflow-x: hidden; //
}
.order-item {
position: relative;
z-index: 1;
width: 100%;
height: 39px;
.progress {
height: 100%;
border-radius: 0;
background: none;
}
.tb-cells {
position: absolute;
left: 0;
top: 0;
height: 100%;
z-index: 100;
cursor: pointer;
&:hover {
background: none;
}
}
//
&:nth-child(even) .progress .el-progress-bar__outer {
background: #F8F8FF;
// background: #f6f8f9;
}
&:nth-child(odd) .progress .el-progress-bar__outer {
background: #ffffff;
}
}
.el-progress {
.el-progress-bar {
/**重构progress的背景色 */
.el-progress-bar__outer {
//
border-radius: 0 !important;
// background: #fff;
.el-progress-bar__inner {
border-radius: 0 !important;
right: 0; //
left: auto;
&::after {}
}
}
}
}
.trade-list {
tbody {
// height: 279px;
height: 505px;
tr {
// @include flexible();
// td:nth-last-child {
// flex-grow: 1;
// }
td {
cursor: text !important;
}
}
}
}
#darkDepthChart,
#lightDepthChart {
height: 305px;
}
</style>
<style lang="scss" scoped>
.ob-heading {
border: 1px solid #333;
box-shadow: 0 0 5px #555;
}
.textcolor{
color: #007bff;
}
</style>

618
src/views/exchangeStock/chart-deal.vue

@ -0,0 +1,618 @@
<template>
<div class="col-md-8">
<!-- 生成K线图 -->
<k-line :symbol="symbol" :marketId="marketId" :priceDecimals="priceDecimals"></k-line>
<!-- 交易处理 -->
<div class="market-trade">
<ul class="nav nav-pills">
<li class="nav-item">
<a href :class="[`nav-link`, {active:!isCondition&&!isMarket}]" @click.prevent="isCondition=false;isMarket=false;">Limit</a>
</li>
<li class="nav-item">
<a href :class="[`nav-link`, {active:!isCondition&&isMarket}]" @click.prevent="isCondition=false;isMarket=true;">Market</a>
</li>
<li class="nav-item">
<a href :class="[`nav-link`, {active:isCondition&&!isMarket}]" @click.prevent="isCondition=true;isMarket=false;">Stop Limit</a>
</li>
<li class="nav-item">
<a href :class="[`nav-link`, {active:isCondition&&isMarket}]" @click.prevent="isCondition=true;isMarket=true;">Stop Market</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active">
<div class="d-flex justify-content-between">
<!------------- Buy Order -------------->
<div class="market-trade-buy">
<!-- Trigger Price -->
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.trigger">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.buy[0] }}
</span>
<div class="input-group" v-if="isCondition" slot="reference">
<input type="number" v-model="buyorder.trigger_price" class="form-control" placeholder="请输入触发价格">
<div class="input-group-append">
<span class="input-group-text">{{pair.from}}</span>
</div>
</div>
</el-popover>
<template v-if="isMarket">
<div class="input-group">
<!-- Market Price -->
<input type="text" class="form-control" disabled placeholder="在最佳市场价格成交">
</div>
</template>
<template v-else>
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.limitPrice">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.buy[1] }}
</span>
<div class="input-group" slot="reference">
<!-- Entrust Price -->
<input type="number" v-model="buyorder.entrust_price" class="form-control" placeholder="请输入价格">
<div class="input-group-append">
<span class="input-group-text">{{pair.from}}</span>
</div>
</div>
</el-popover>
</template>
<!-- Amount/Total -->
<template v-if="isMarket">
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.marketTotal">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.buy[3] }}
</span>
<div class="input-group" slot="reference">
<input type="number" v-model="buyTotal" class="form-control" min=0 placeholder="请输入总值">
<div class="input-group-append">
<span class="input-group-text">{{pair.to}}</span>
</div>
</div>
</el-popover>
</template>
<template v-else>
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.limitAmount">
<!-- 提示框的内容 -->
<span class="content">
<!-- 图标 -->
<i class="el-icon-warning-outline"></i>
<!-- 提示 -->
{{ msgList.buy[2] }}
</span>
<div class="input-group" slot="reference">
<input type="number" v-model="buyorder.amount" class="form-control" min=0 placeholder="请输入数量">
<div class="input-group-append">
<span class="input-group-text">{{pair.to}}</span>
</div>
</div>
</el-popover>
</template>
<!-- Percent -->
<ul class="market-trade-list">
<li v-for="(item,index) in percentage" :key="index" :class="{buyPercentActive:index == buyPercentIndex}" @click="renderBuyAmount(item.value, index)">
<a href="javascript:void 0">{{ item.label }}</a>
</li>
</ul>
<!-- Total -->
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.orderTotal">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.buy[5] }}
</span>
<p slot="reference">
{{$t('exchange.order-total')}}:
<span> <b>{{buyTotal}}</b> {{pair.from}} </span>
</p>
</el-popover>
<!-- Available -->
<p>{{$t('otc.j3')}}:
<span> {{toBalance}} {{pair.to}}</span><br />
<span> {{fromBalance}} {{pair.from}}</span>
</p>
<button class="btn buy" @click="handleBuyOrder">Buy {{pair.to}}</button>
</div>
<!------------ Sell Order ----------->
<div class="market-trade-sell">
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.sell.trigger">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.sell[0] }}
</span>
<!-- Trigger Price -->
<div class="input-group" v-if="isCondition" slot="reference">
<input type="number" v-model="sellorder.trigger_price" class="form-control" min=0 placeholder="请输入触发价格">
<div class="input-group-append">
<span class="input-group-text">{{pair.from}}</span>
</div>
</div>
</el-popover>
<template v-if="isMarket">
<div class="input-group">
<!-- Market Price -->
<input type="text" class="form-control" disabled placeholder="在最佳市场价格成交">
</div>
</template>
<template v-else>
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.sell.limitPrice">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.sell[1] }}
</span>
<div class="input-group" slot="reference">
<!-- Entrust Price -->
<input type="number" v-model="sellorder.entrust_price" class="form-control" min=0 placeholder="请输入价格">
<div class="input-group-append">
<span class="input-group-text">{{pair.from}}</span>
</div>
</div>
</el-popover>
</template>
<!-- Amount -->
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.sell.marketAmount">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.sell[4] }}
</span>
<div class="input-group" slot="reference">
<input type="number" v-model="sellorder.amount" class="form-control" min=0 placeholder="请输入数量">
<div class="input-group-append">
<span class="input-group-text">{{pair.to}}</span>
</div>
</div>
</el-popover>
<ul class="market-trade-list">
<li v-for="(item,index) in percentage" :key="index" :class="{sellPercentActive:index == sellPercentIndex}" @click="renderSellAmount(item.value, index)">
<a href="javascript:void 0">{{ item.label }}</a>
</li>
</ul>
<!-- Total -->
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.sell.orderTotal">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.sell[5] }}
</span>
<p slot="reference">
{{$t('exchange.order-total')}}:
<span>
<b>{{sellTotal}}</b> {{pair.from}} </span>
</p>
</el-popover>
<p>{{$t('otc.j3')}}:
<span> {{toBalance}} {{pair.to}} </span><br />
<span> {{fromBalance}} {{pair.from}}</span>
</p>
<button class="btn sell" @click="handleSellOrder">Sell {{pair.to}}</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Exchange from "@/api/exchange";
export default {
props: ["pair", "buyorder", "marketId", "sellorder", "fromBalance", "toBalance", "symbol", "newTrade", "minQty", "minTotal", "priceDecimals", "qtyDecimals"],
data() {
return {
isMarket: false,
isCondition: false,
userBanlance: null,
cacheTotal: 0, //
cachePrice: null, //
//
visibles: {
"buy": {
limitPrice: false, //
limitAmount: false, //
marketTotal: false, //
marketAmount: false, //
trigger: false, //
orderTotal: false, //
},
"sell": {
limitPrice: false,
limitAmount: false,
marketTotal: false,
marketAmount: false,
trigger: false,
orderTotal: false,
},
},
msgList: {
"buy": Array(6).fill(''), // 5
"sell": Array(6).fill('')
},
//
percentage: [{
label: "25%",
value: 0.25
},
{
label: "50%",
value: 0.5
},
{
label: "75%",
value: 0.75
},
{
label: "100%",
value: 1
},
],
//
buyPercentIndex: null,
sellPercentIndex: null,
}
},
computed: {
// type
type() {
if (!this.isCondition) {
return this.isMarket ? 2 : 1;
} else {
return this.isMarket ? 4 : 3;
}
},
theme() {
return localStorage.theme ? localStorage.theme : "light";
},
buyTotal: {
get() {
if (!this.isMarket) {
return Math.multiple(this.buyorder.entrust_price, this.buyorder.amount);
} else {
return this.cacheTotal;
}
},
set(val) {
//
if (!this.isMarket) {
this.buyorder.amount = Math.division(val, this.buyorder.entrust_price);
} else { //
this.cacheTotal = val;
}
}
},
sellTotal: {
get() {
return Math.multiple(this.sellorder.entrust_price, this.sellorder.amount);
}
},
//
lang() {
let browser_Lang = navigator.language.includes('zh') ? 'zh' : 'en';
return localStorage.lang || browser_Lang;
},
},
watch: {
custom(newVal) {
// console.log(newVal)
},
type() {
//
// percentage
this.reset();
},
//
newTrade(newVal, oldVal) {
if (!this.isMarket) {
// trade
if (!oldVal && newVal) { //
// orderprice
this.cachePrice = newVal.price;
this.reset();
}
//
if (oldVal && !newVal) { //
this.cachePrice = null;
this.reset();
}
}
},
},
methods: {
renderBuyAmount(val, index) {
if (!this.buyorder.entrust_price) {
this.visibles.buy.limitPrice = true;
this.msgList.buy[1] = this.$t('nav.tips');
this.clearAll();
return;
}
this.buyPercentIndex = index;
this.buyTotal = Math.multiple(this.fromBalance, val);
},
renderSellAmount(val, index) {
if (!this.sellorder.entrust_price) {
this.visibles.sell.limitPrice = true;
this.msgList.sell[1] = this.$t('nav.tips');
this.clearAll();
return;
}
this.sellPercentIndex = index;
this.sellorder.amount = Math.multiple(this.toBalance, val);
},
handleBuyOrder() {
//
if (!this.chkValidate(this.buyorder, this.buyTotal, "buy")) return;
const baseArgs = {
symbol: this.symbol,
type: this.type,
};
//
// 1
// 2
// 3
// 4
Exchange.storeEntrust(Object.assign(this.buyorder, {
total: this.buyTotal,
}, baseArgs)).then(data => {
//
this.$emit('update');
//
this.reset();
}).catch(err => {
});
},
handleSellOrder() {
//
if (!this.chkValidate(this.sellorder, this.sellTotal, "sell")) return;
const baseArgs = {
symbol: this.symbol,
type: this.type,
};
Exchange.storeEntrust(Object.assign(this.sellorder, {
total: this.sellTotal
}, baseArgs)).then(data => {
//
this.$emit('update');
//
this.reset();
}).catch(err => {
});
},
reset() {
// newTrade 0
//
let price = this.cachePrice || 0;
this.buyorder.entrust_price = Math.omitTo(price, this.priceDecimals);
this.buyorder.trigger_price = Math.omitTo(price, this.priceDecimals);
this.sellorder.entrust_price = Math.omitTo(price, this.priceDecimals);
this.sellorder.trigger_price = Math.omitTo(price, this.priceDecimals);
//
this.buyorder.amount = 0;
this.sellorder.amount = 0;
// totalset
// this.buyTotal = 0;
// this.cacheTotal = 0;
//
this.buyPercentIndex = -1;
this.sellPercentIndex = -1;
},
clearAll() {
// 5s
setTimeout(function () {
Object.keys(this.visibles.buy).forEach(key => this.visibles.buy[key] = false);
Object.keys(this.visibles.sell).forEach(key => this.visibles.sell[key] = false);
}.bind(this), 5000);
},
empty(val) {
let ret;
switch (typeof val) {
case "number":
ret = val == 0;
break;
case "string":
ret = val == "0" || /^\s?$/.test(val);
break;
case "boolean":
ret = val;
break;
default:
ret = Boolean(val);
break;
}
return ret;
},
chkValidate(order, total, orderType) {
let flag = true;
switch (this.type) {
case 1: // limit
if (this.empty(order.entrust_price)) {
flag = false;
this.visibles[orderType].limitPrice = true;
this.msgList[orderType][1] = this.$t('nav.a1');
} else if (this.empty(order.amount)) {
flag = false;
this.visibles[orderType].limitAmount = true;
this.msgList[orderType][2] = this.$t('nav.a2');
} else {
if (order.amount < this.minQty) {
flag = false;
this.visibles[orderType].limitAmount = true;
this.msgList[orderType][2] = this.$t('nav.a3')+`${this.minQty}`;
}
if (total < this.minTotal) {
flag = false;
this.visibles[orderType].orderTotal = true;
this.msgList[orderType][5] = this.$t('nav.b8')+`${this.minTotal}`;
}
}
break;
case 2: // market
if (order.direction == "buy") { //
if (this.empty(total)) {
flag = false;
this.visibles[orderType].marketTotal = true;
this.msgList[orderType][3] = this.$t('nav.a4');
} else if (this.total < this.minTotal) {
flag = false;
this.visibles.marketTotal = true;
this.msgList[3] = this.$t('nav.a5')+`${this.minTotal}`;
}
}
if (order.direction == "sell") { //
if (this.empty(order.amount)) {
flag = false;
this.visibles[orderType].marketAmount = true;
this.msgList[orderType][4] = this.$t('nav.a6');
} else if (order.amount < this.minQty) {
flag = false;
this.visibles[orderType].marketAmount = true;
this.msgList[orderType][4] = this.$t('nav.a7')+` ${this.minQty}`;
}
}
break;
case 3: // stop-limit
if (this.empty(order.trigger_price)) {
flag = false;
this.visibles[orderType].trigger = true;
this.msgList[orderType][0] = this.$t('nav.a8')
} else if (this.empty(order.entrust_price)) {
flag = false;
this.visibles[orderType].limitPrice = true;
this.msgList[orderType][1] = this.$t('nav.a9')
} else if (this.empty(order.amount)) {
flag = false;
this.visibles[orderType].limitAmount = true;
this.msgList[orderType][2] = this.$t('nav.b1')
}
break;
case 4: // stop-market
if (this.empty(order.trigger_price)) {
flag = false;
this.visibles[orderType].trigger = true;
this.msgList[orderType][0] = this.$t('nav.b2')
} else {
if (order.direction == "buy") {
if (this.empty(total)) {
flag = false;
this.visibles[orderType].marketTotal = true;
this.msgList[orderType][3] = this.$t('nav.b3')
} else if (total < this.minTotal) {
flag = false;
this.visibles[orderType].marketTotal = true;
this.msgList[orderType][3] = this.$t('nav.b5')+` ${this.minTotal}`
}
}
if (order.direction == "sell") {
if (this.empty(order.amount)) {
flag = false;
this.visibles[orderType].marketAmount = true;
this.msgList[orderType][4] = this.$t('nav.b6')
} else if (order.amount < this.minQty) {
flag = false;
this.visibles[orderType].marketAmount = true;
this.msgList[orderType][4] = this.$t('nav.b7')+` ${this.minQty}`
}
}
}
break;
}
//
this.clearAll();
//
return flag;
},
},
created() {
},
}
</script>
<style lang="scss" scoped>
.buyPercentActive {
a:link {
font-weight: bold;
background: #26a69a;
color: #fff;
}
}
.sellPercentActive {
a:link {
font-weight: bold;
background: #ef5350;
color: #fff;
}
}
.input-group-text {
width: 68px;
@include flexible(row, center, center);
}
</style>

706
src/views/exchangeStock/index.vue

@ -0,0 +1,706 @@
<template>
<!-- <div> -->
<!-- <div class="banner-block col-xs-8">-->
<!-- <el-carousel :interval="6000" height="450px">-->
<!-- <el-carousel-item v-for="item in pcBannerList" :key="item.id">-->
<!-- <img :src="item.imgurl" width="100%" height="100%" />-->
<!-- </el-carousel-item>-->
<!-- </el-carousel>-->
<!-- </div>-->
<!-- <div class="container-fluid mtb15 no-fluid">
<div class="row sm-gutters"> -->
<!-- symbols -->
<!-- <symbols :marketList="marketList" :marketId="marketId" :isLogin="isLogin" :symbol.sync="symbol">
</symbols> -->
<!-- kline -->
<!-- <stock-kline :symbol="symbol" :socket="ws.socket" :priceDecimals="priceDecimals"></stock-kline> -->
<!-- order book -->
<!-- <book-trades :priceCny="price_cny"></book-trades> -->
<!-- 交易布局 -->
<!-- <make-deal :isLogin="isLogin" :pair="pair" :socket="ws.socket" :symbol="symbol" :buyorder="buyorder"
:sellorder="sellorder" :fromBalance="fromBalance" :toBalance="toBalance" :newTrade="newTrade"
:minQty="minQty" :minTotal="minTotal" :priceDecimals="priceDecimals" :qtyDecimals="qtyDecimals"
@update="update"></make-deal> -->
<!-- market news -->
<!-- <market-news></market-news> -->
<!-- order list -->
<!-- <order-list ref="Order" :ordersOpen="ordersOpen" :conditionOrders="conditionOrders"
:ordersHistory="ordersHistory" :holdPositionList="holdPositionList" :priceDecimals="priceDecimals" :qtyDecimals="qtyDecimals"
:isLogin="isLogin" :pair="pair" @change="currentTab = $event" @update="update"
@Pagination="page = $event" @Pagination1="page1 = $event"></order-list> -->
<!-- </div>
</div>
</div> -->
<div class="contract-page" style="background-color: #000;">
<div class="coin-change d-flex align-items-center py-2 pl-4 heading justify-content-between" style="background-color: #121212;">
<div class="d-flex align-items-center">
<div class="coin d-flex align-items-center">
<el-popover
placement="bottom"
ref="popover"
width="400"
trigger="click"
>
<div slot="reference">
{{ activeContract.pair_name }}
<el-button size="mini">
<i class="el-icon-arrow-down"></i>
</el-button>
</div>
<div
class="markets-pair-list"
style="max-height:300px;overflow:auto;"
>
<template v-for="parent in marketList">
<div class="px-3 text-primary" :key="parent.coin_name">
{{ parent.coin_name }}
</div>
<table class="table" :key="parent.coin_name + 1">
<thead>
<tr class="text-secondary">
<th class="w-10/24">{{ $t("contract.h5") }}</th>
<th class="w-7/24">{{ $t("contract.g3") }}</th>
<th class="w-7/24 text-right">
{{ $t("contract.h6") }}
</th>
</tr>
</thead>
<tbody>
<!-- @click="symbol = item.symbol" -->
<tr
v-for="item in parent.marketInfoList"
:key="item.symbol"
:class="{ active: item.symbol == symbol }"
@click="ispopover1(item.symbol)"
>
<td class="w-10/24">
{{ item.symbol }}/{{ parent.coin_name }}
</td>
<td
class="w-7/24 "
:class="item.increase < 0 ? 'decreace' : 'increace'"
>
{{item.price}}
<!-- item.symbol == symbol ? price1 : -->
</td>
<td
class="w-7/24"
:class="item.increase < 0 ? 'decreace' : 'increace'"
>
{{ item.increaseStr }}
</td>
</tr>
</tbody>
</table>
</template>
</div>
</el-popover>
</div>
<div
class="price px-3 border-right"
:class="{
decreace: activeContract.increase < 0,
increace: activeContract.increase >= 0
}"
>
<span class="current">{{ activeContract.price }}$</span>
<!-- <span class="current">{{price1}}$</span> -->
&nbsp;
<span class="zf">{{ activeContract.increaseStr }}</span>
</div>
<!-- 币种价值数据 -->
<div class="d-flex fn-12">
<div class="item px-2">
<div class="title mb-1 text-secondary">
24h {{ $t("contract.h7") }}
</div>
<div>
{{ activeContract.high }}
</div>
</div>
<div class="item px-2">
<div class="title mb-1 text-secondary">
24h {{ $t("contract.h8") }}
</div>
<div>
{{ activeContract.low }}
</div>
</div>
<div class="item px-2">
<div class="title mb-1 text-secondary">
24h {{ $t("contract.h9") }}
<!-- {{ $t("contract.e2") }} -->
<!-- (USDT) -->
</div>
<div>
{{ activeContract.vol }}
</div>
</div>
</div>
</div>
<!-- <div><theme-change /></div> -->
</div>
<div class="page-top d-flex pt-2">
<div class="kline-box flex-fill mr-2">
<stock-kline :symbol="symbol" :socket="ws.socket" :priceDecimals="priceDecimals"></stock-kline>
</div>
<!-- 盘口 -->
<book-trades :priceCny="price_cny"></book-trades>
<!-- 交易 -->
<make-deal :isLogin="isLogin" :pair="pair" :socket="ws.socket" :symbol="symbol" :buyorder="buyorder"
:sellorder="sellorder" :fromBalance="fromBalance" :toBalance="toBalance" :newTrade="newTrade"
:minQty="minQty" :minTotal="minTotal" :priceDecimals="priceDecimals" :qtyDecimals="qtyDecimals"
@update="update"></make-deal>
</div>
<order-list ref="Order" :ordersOpen="ordersOpen" :conditionOrders="conditionOrders"
:ordersHistory="ordersHistory" :holdPositionList="holdPositionList" :priceDecimals="priceDecimals" :qtyDecimals="qtyDecimals"
:isLogin="isLogin" :pair="pair" @change="currentTab = $event" @update="update"
@Pagination="page = $event" @Pagination1="page1 = $event"></order-list>
</div>
</div>
</template>
<script>
import Socket from '@/api/server/Socket.js';
import Market from '@/api/market.js';
import Exchange from "@/api/exchange";
import Order from "@/api/order"
import Home from "@/api/home";
import bus from "@/components/bus.js";
export default {
components: {
"Symbols": () => import( /* webpackChunkName:"symbols" */ "./symbols"),
"MakeDeal": () => import( /* webpackChunkName:"chart-deal" */ "./make-deal"),
"BookTrades": () => import( /* webpackChunkName:"order-book" */ "./book-trades"),
"MarketNews": () => import( /* webpackChunkName:"market-news" */ "./market-news"),
"OrderList": () => import( /* webpackChunkName:"order-list" */ "./order-list")
},
beforeCreate() {
// this.ws = new Socket(`${this.Globals.Server.Path.WS}`);
},
data() {
return {
tabcolor:1,
price1:0,
isLianjie: false,
// `btcusdt` `/`
symbol: this.$route.params.symbol || null,
marketId: null,
marketInfo: null, //
pair: {
from: '-',
to: '-',
},
marketList: [], // symbol
trade: [],
pcBannerList: [],
newTrade: null,
//
buyList: [],
sellList: [],
//
priceDecimals: 0,
qtyDecimals: 0,
minQty: 0,
minTotal: 0,
now: null,
// orderbook
buyorder: {
trigger_price: '', //
entrust_price: '', //
amount: 0, //
direction: "buy", //
},
sellorder: {
entrust_price: '',
trigger_price: '',
amount: 0,
direction: "sell",
},
// orderprice
passOrderPrice: true,
//
ordersOpen: {
total: 0,
},
ordersHistory: {
total: 0,
},
holdPositionList: {
total: 0,
},
conditionOrders: {
total: 0,
},
//
fromBalance: 0,
toBalance: 0,
// socket
ws: null,
//
transPwdEnabled: false,
currentTab: "stockholdPosition", // orderstab
price_cny: 0,
page: 1,
page1: 1,
timer: null
}
},
computed: {
//
lang() {
let browser_Lang = navigator.language.includes('zh') ? 'cn' : 'en',
lang = localStorage.lang || browser_Lang;
return lang;
},
isLogin() {
return Boolean(this.userAuth);
},
userAuth() {
const auth = localStorage.getItem("auth");
let ret = "";
if (auth) {
let {
memberId,
accessToken
} = JSON.parse(auth);
ret = `?${accessToken}&${memberId}`;
}
return ret;
},
userInfo() {
if (this.isLogin) {
return JSON.parse(localStorage.getItem("auth"));
} else {
return {
user_id: 0,
};
}
},
activeContract(val) {
let marketList=this.marketList
.map(item => item.marketInfoList)
.flat()
.find(item => item.symbol == this.symbol) || {}
if(val.price){
delete marketList.price
}
return marketList;
},
},
watch: {
// symbol
symbol(newVal, oldVal) {
//
if (oldVal) this.unsub(oldVal);
//
this.trade = [];
this.sellList = [];
this.buyList = [];
this.newTrade = null;
//
this.buyorder = {
trigger_price: '',
entrust_price: '',
amount: 0,
direction: "buy",
};
this.sellorder = {
trigger_price: '',
entrust_price: '',
amount: 0,
direction: "sell",
};
//
if (newVal) this.$router.push(`/exchangestock/${newVal}`);
},
marketInfo(newVal, oldVal) {
if (newVal && !oldVal) { // marketInfo
this.update();
}
},
//
$route( /*newRouter, oldRouter*/ ) {
this.addSub();
// market
this.findMarketBySymbol();
//
this.update();
},
currentTab() {
// tab
this.getOrders();
},
page() {
if (this.currentTab == "histories") { //
this.getHistories();
}
},
// page1() {
// if (this.currentTab == "stockholdPosition") { //
// this.stockholdPosition()
// }
// }
},
methods: {
ispopover1(item){
this.symbol=item;
},
initMarket() {
// marketList
this.ws.send({
"cmd": "sub",
"msg": 'exchangeMarketList',
})
},
// symbol
addSub() {
this.ws.send([{
cmd: 'sub',
msg: `sellList_${this.symbol}`
}, {
cmd: 'sub',
msg: `buyList_${this.symbol}`
}, {
cmd: 'req',
msg: `tradeList_${this.symbol}`
}, {
cmd: 'sub',
msg: `tradeList_${this.symbol}`
}]);
},
// symbol
unsub(symbol) {
this.ws.send([{
cmd: 'unsub',
msg: `sellList_${symbol}`
}, {
cmd: 'unsub',
msg: `buyList_${symbol}`
}, {
cmd: 'unsub',
msg: `tradeList_${symbol}`
}]);
},
// id
// 便 使
findMarketBySymbol() {
let isKeep = true; // 退
for (let coin of this.marketList) {
for (let market of coin.marketInfoList) {
//
if (market.symbol === this.symbol) {
// pair 便
this.pair = {
to: market.coin_name, //
from: coin.coin_name //
};
// marketId
this.marketId = market.pair_id;
// market
this.marketInfo = market;
// Tab now
if (!this.now) this.now = coin.coin_name;
//
this.priceDecimals = market.price_decimals;
this.qtyDecimals = market.qty_decimals;
//
this.minTotal = market.min_total;
this.minQty = market.min_qty;
isKeep = false;
//
break;
}
}
//
if (!isKeep) break;
}
},
getBalance() {
if (this.isLogin) {
Exchange.getstockUserBalance(this.marketInfo.pair_name).then(data => {
this.fromBalance = data[this.pair.from.toUpperCase()].usable_balance;
this.toBalance = data[this.pair.to.toUpperCase()].usable_balance;
}).catch(err => {
});
}
},
//
update() {
this.getBalance();
this.getOrders();
this.getCurrencyExCny();
},
//
getCurrencyExCny() {
if (!this.pair.from || this.pair.from == '-') return;
Exchange.getCurrencyExCny({
coin_name: this.pair.from
}).then(res => {
this.price_cny = res.price_cny
})
},
getOrders() {
if (this.currentTab == "opens") { //
this.getOpens();
} else if (this.currentTab == "conditions") { //
this.getConditions();
} else if (this.currentTab == "histories") { //
this.getHistories();
} else if (this.currentTab == "stockholdPosition") {
this.stockholdPosition()
this.timer = setInterval(()=>{
this.stockholdPosition()
}, 3000)
}
// console.log("------");
},
getOpens() {
if (this.isLogin) {
Order.getstockCurrentEntrust({
symbol: this.marketInfo.pair_name,
}).then(data => {
this.ordersOpen = data
}).catch(err => {
// console.log(err)
})
}
},
getConditions() {
if (this.isLogin) {
Order.getConditionEntrust({
symbol: this.marketInfo.pair_name,
}).then(data => {
this.conditionOrders = data;
}).catch(err => {
// console.log(err)
})
}
},
getHistories() {
if (this.isLogin) {
Order.getstockHistoryEntrust({
symbol: this.marketInfo.pair_name,
page:this.page
})
.then(data => {
this.ordersHistory = data;
})
.catch(err => {})
}
},
stockholdPosition(){
if (this.isLogin) {
let data = {
symbol: this.marketInfo.pair_name,
page:this.page1
};
Exchange.stockholdPosition(data ,{ loading: false }).then(data => {
this.holdPositionList = data;
}).catch(err => {})
}
},
indexList() {
Home.indexList().then((res) => {
this.pcBannerList = res.pcBannerList
setTimeout(() => {
this.skroll();
}, 100);
}).catch((res) => {});
},
initWs() {
// this.ws = new Socket(`${this.Globals.Server.Path.WS}`);
this.ws = new Socket(`${this.Globals.Server.Path.WS2}`);
this.ws.on("open", () => {
if (this.isLianjie) {
bus.$emit('sendMsg', this.ws.socket);
this.isLianjie = false
}
//
this.initMarket();
// id
if (this.symbol) this.addSub();
})
this.ws.on("message", (response) => {
let {
data, //
sub, //
type, //
msg, //
code, //
} = response;
//
if (type == "ping") this.ws.send({
type: "pong"
});
switch (sub) {
case "exchangeMarketList":
this.marketList = data;
if (!this.symbol) { // symbol
this.symbol = _.nth(data).marketInfoList[0].symbol;
} else { // symbol
this.findMarketBySymbol();
}
break;
case `buyList_${this.symbol}`:
this.buyList = data;
break;
case `sellList_${this.symbol}`:
this.sellList = data;
break;
case `tradeList_${this.symbol}`:
if (type == "history") { //
this.trade = this.trade.concat(data);
} else if (type == "dynamic") { //
this.trade.unshift(data);
}
//
this.newTrade = _.nth(this.trade);
if (this.newTrade && this.newTrade.buy_user_id === this.userInfo.user_id || this
.newTrade.sell_user_id == this.userInfo.user_id) this.update();
break;
}
});
this.ws.on("close", () => {
// this.$message({
// type: "error",
// message: this.$t("nav.b8"),
// duration: 2000,
// });
this.isLianjie = true
this.initWs()
// if (this.symbol) this.getCurrencyExCny();
// this.indexList()
});
}
},
created() {
this.initWs()
if (this.symbol) this.getCurrencyExCny();
this.indexList()
Market.getstockMarketList().then(data => {
this.marketList = data;
}).catch(err => {});
// this.update();
},
beforeDestroy() {
clearInterval(this.timer);
},
mounted() {
// if (this.symbol) this.update();
},
}
</script>
<style>
.el-popover{
background-color: #121212;
}
</style>

824
src/views/exchangeStock/make-deal.vue

@ -0,0 +1,824 @@
<template>
<div class="col-md-3" style="background-color: #121212;">
<div class="px-4 py-2 heading">
<!-- <theme-change/> -->
<el-tooltip placement="bottom" effect="light">
<div slot="content" class="market">
<div class="coin p-md color-light fn-20">
<img :src="detail.coin_icon" width="20" height="20" alt="">
{{detail.full_name}}
</div>
<div class="list">
<div class="d-flex justify-between p-x-md p-y-xs">
<div>{{$t('nav.c3')}}</div>
<div class="color-light">
{{detail.total_issuance}}
</div>
</div>
<div class="d-flex justify-between p-x-md p-y-xs">
<div>{{$t('nav.c4')}}</div>
<div class="color-light">
{{detail.total_circulation}}
</div>
</div>
<div class="d-flex justify-between p-x-md p-y-xs">
<div>{{$t('nav.c5')}}</div>
<div class="color-light">
{{detail.crowdfunding_price}}
</div>
</div>
<div class="d-flex justify-between p-x-md p-y-xs">
<div>{{$t('nav.c6')}}</div>
<div class="color-light">
{{detail.publish_time}}
</div>
</div>
<div class=" p-x-md p-y-xs">
<div>{{$t('nav.c7')}}</div>
<div class="color-light ov">
{{detail.white_paper_link}}
</div>
</div>
<div class=" p-x-md p-y-xs">
<div>{{$t('nav.c8')}}</div>
<div class="color-light ov">
{{detail.official_website_link}}
</div>
</div>
</div>
<div class="p-md">
<div class="fn-20 color-light">
{{$t('nav.c9')}}
</div>
<div class="p-y-md edit-content" v-html="detail.coin_content">
</div>
</div>
</div>
<!-- <el-button><img src="../../assets/img/shuoming.png" width="20" height="20" alt=""></el-button> -->
</el-tooltip>
</div>
<!-- 生成K线图 -->
<!-- <stock-kline :symbol="symbol" :socket="socket" :priceDecimals="priceDecimals"></stock-kline> -->
<!-- 交易处理 -->
<div class="market-trade ">
<h4 style="text-align: center;">{{$t('nav.c12')}}</h4>
<div class="d-flex" style="margin: 14px;justify-content: space-around;border: 1px solid #b9b9b9;border-radius: 40px;">
<div :class="Tab_buysell == 1?'Tab_buy':'Tab_buy1'" @click="Tab_buysell=1">{{$t('order.buy')}}</div>
<div :class="Tab_buysell == 2?'Tab_sell':'Tab_sell1'" @click="Tab_buysell=2">{{$t('order.sell')}}</div>
</div>
<ul class="nav nav-pills">
<li class="nav-item">
<a href :class="[`nav-link`, {active:!isCondition&&isMarket}]" @click.prevent="isCondition=false;isMarket=true;" style="background-color: transparent;">
{{ $t("common.market") }}
</a>
</li>
<li class="nav-item">
<a href :class="[`nav-link`, {active:!isCondition&&!isMarket}]" @click.prevent="isCondition=false;isMarket=false;" style="background-color: transparent;">
{{ $t("common.limit") }}</a>
</li>
<!-- <li class="nav-item">
<a href :class="[`nav-link`, {active:isCondition&&!isMarket}]" @click.prevent="isCondition=true;isMarket=false;">
{{ $t("common.stop-limit") }}</a>
</li>
<li class="nav-item">
<a href :class="[`nav-link`, {active:isCondition&&isMarket}]" @click.prevent="isCondition=true;isMarket=true;">
{{ $t("common.stop-market") }}</a>
</li> -->
</ul>
<div class="tab-content">
<div class="tab-pane fade show active">
<div class="d-flex justify-content-between">
<!------------- Buy Order -------------->
<div class="market-trade-buy" v-if="Tab_buysell == 1">
<!-- Trigger Price -->
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.trigger">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.buy[0] }}
</span>
<div class="input-group" v-if="isCondition" slot="reference">
<input type="number" style="background-color: #121212;" v-model="buyorder.trigger_price" class="form-control" :placeholder="$t('exchange.trigger-price')">
<div class="input-group-append">
<span class="input-group-text">{{pair.from}}</span>
</div>
</div>
</el-popover>
<template v-if="isMarket">
<div class="input-group">
<!-- Market Price -->
<input type="text" class="form-control" disabled :placeholder="$t('exchange.at-best-price')">
</div>
</template>
<template v-else>
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.limitPrice">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.buy[1] }}
</span>
<div class="input-group" slot="reference">
<!-- Entrust Price -->
<input type="number" v-model="buyorder.entrust_price" class="form-control" :placeholder="$t('exchange.enter-price')">
<div class="input-group-append">
<span class="input-group-text">{{pair.from}}</span>
</div>
</div>
</el-popover>
</template>
<!-- Amount/Total -->
<template v-if="isMarket">
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.marketTotal">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.buy[3] }}
</span>
<div class="input-group" slot="reference">
<!-- <input type="number" v-model="buyTotal" class="form-control" min=0 :placeholder="$t('exchange.enter-total')"> -->
<input type="number" v-model="buyorder.amount" class="form-control" min=0 :placeholder="$t('exchange.enter-total')">
<div class="input-group-append">
<!-- <span class="input-group-text">{{pair.from}}</span> -->
<span class="input-group-text">{{pair.to}}</span>
</div>
</div>
</el-popover>
</template>
<template v-else>
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.limitAmount">
<!-- 提示框的内容 -->
<span class="content">
<!-- 图标 -->
<i class="el-icon-warning-outline"></i>
<!-- 提示 -->
{{ msgList.buy[2] }}
</span>
<div class="input-group" slot="reference">
<input type="number" v-model="buyorder.amount" class="form-control" min=0 :placeholder="$t('exchange.enter-amount')">
<div class="input-group-append">
<span class="input-group-text">{{pair.to}}</span>
</div>
</div>
</el-popover>
</template>
<!-- Percent -->
<ul class="market-trade-list">
<li v-for="(item,index) in percentage" :key="index" :class="{buyPercentActive:index == buyPercentIndex}" @click="renderBuyAmount(item.value, index)">
<a href="javascript:void 0">{{ item.label }}</a>
</li>
</ul>
<!-- Total -->
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.buy.orderTotal">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.buy[5] }}
</span>
<p slot="reference">
{{$t('exchange.order-total')}}
<span> <b>{{buyTotal}}</b> {{pair.from}} </span>
</p>
</el-popover>
<!-- Available -->
<p>
{{ $t('exchange.amount') }}
<span> {{toBalance}} {{pair.to}}</span><br />
{{ $t('exchange.balance') }}
<span> {{fromBalance}} {{pair.from}}</span>
</p>
<button class="btn buy" @click="handleBuyOrder">{{ $t("common.buy") }} {{pair.to}}</button>
</div>
<!-- Sell Order -->
<div class="market-trade-buy" v-if="Tab_buysell == 2">
<!-- class="market-trade-sell" -->
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.sell.trigger">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.sell[0] }}
</span>
<!-- Trigger Price -->
<div class="input-group" v-if="isCondition" slot="reference">
<input type="number" v-model="sellorder.trigger_price" class="form-control" min=0 :placeholder="$t('exchange.trigger-price')">
<div class="input-group-append">
<span class="input-group-text">{{pair.from}}</span>
</div>
</div>
</el-popover>
<template v-if="isMarket">
<div class="input-group">
<!-- Market Price -->
<input type="text" class="form-control" disabled :placeholder="$t('exchange.at-best-price')">
</div>
</template>
<template v-else>
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.sell.limitPrice">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.sell[1] }}
</span>
<div class="input-group" slot="reference">
<!-- Entrust Price -->
<input type="number" v-model="sellorder.entrust_price" class="form-control" min=0 :placeholder="$t('exchange.enter-price')">
<div class="input-group-append">
<span class="input-group-text">{{pair.from}}</span>
</div>
</div>
</el-popover>
</template>
<!-- Amount -->
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.sell.limitAmount">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.sell[2] }}
</span>
<div class="input-group" slot="reference">
<input type="number" v-model="sellorder.amount" class="form-control" min=0 :placeholder="$t('exchange.enter-amount')">
<div class="input-group-append">
<span class="input-group-text">{{pair.to}}</span>
</div>
</div>
</el-popover>
<ul class="market-trade-list">
<li v-for="(item,index) in percentage" :key="index" :class="{sellPercentActive:index == sellPercentIndex}" @click="renderSellAmount(item.value, index)">
<a href="javascript:void 0">{{ item.label }}</a>
</li>
</ul>
<!-- Total -->
<el-popover popper-class='popover-tips' placement="top-start" trigger="manual" v-model="visibles.sell.orderTotal">
<span class="content">
<i class="el-icon-warning-outline"></i>
{{ msgList.sell[5] }}
</span>
<p slot="reference">
{{ $t('exchange.order-total') }}
<span>
<b>{{sellTotal}}</b> {{pair.from}} </span>
</p>
</el-popover>
<p>
{{$t('exchange.amount')}}
<span> {{toBalance}} {{pair.to}} </span><br />
{{ $t('exchange.balance') }}
<span> {{fromBalance}} {{pair.from}}</span>
</p>
<button class="btn sell" @click="handleSellOrder">{{ $t("common.sell") }} {{pair.to}}</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Exchange from "@/api/exchange";
import Market from "@/api/market";
export default {
props: ["isLogin", "socket", "symbol", "pair", "buyorder", "sellorder", "fromBalance", "toBalance", "newTrade", "minQty", "minTotal", "priceDecimals", "qtyDecimals"],
data() {
return {
Tab_buysell:1,
detail:[],
isMarket: true,
isCondition: false,
userBanlance: null,
cacheTotal: 0, //
cachePrice: null, //
//
visibles: {
"buy": {
limitPrice: false, //
limitAmount: false, //
marketTotal: false, //
marketAmount: false, //
trigger: false, //
orderTotal: false, //
},
"sell": {
limitPrice: false,
limitAmount: false,
marketTotal: false,
marketAmount: false,
trigger: false,
orderTotal: false,
},
},
msgList: {
"buy": Array(6).fill(''), // 5
"sell": Array(6).fill('')
},
//
percentage: [{
label: "25%",
value: 0.25
},
{
label: "50%",
value: 0.5
},
{
label: "75%",
value: 0.75
},
{
label: "100%",
value: 1
},
],
//
buyPercentIndex: null,
sellPercentIndex: null,
}
},
computed: {
// type
type() {
if (!this.isCondition) {
return this.isMarket ? 2 : 1;
} else {
return this.isMarket ? 4 : 3;
}
},
theme() {
return localStorage.theme ? localStorage.theme : "light";
},
buyTotal: {
get() {
if (!this.isMarket) {
return Math.multiple(this.buyorder.entrust_price, this.buyorder.amount);
} else {
// return this.cacheTotal;
return Math.multiple(this.buyorder.entrust_price, this.buyorder.amount);
}
},
set(val) {
//
if (!this.isMarket) {
this.buyorder.amount = Math.division(val, this.buyorder.entrust_price);
} else { //
this.cacheTotal = val;
this.buyorder.amount = this.cacheTotal
}
}
},
sellTotal: {
get() {
return Math.multiple(this.sellorder.entrust_price, this.sellorder.amount);
}
},
//
lang() {
let browser_Lang = navigator.language.includes('zh') ? 'zh' : 'en';
return localStorage.lang || browser_Lang;
},
},
watch: {
custom(newVal) {
// console.log(newVal)
},
type() {
//
// percentage
this.reset();
},
//
newTrade(newVal, oldVal) {
// if (!this.isMarket ) {
// trade
if (!oldVal && newVal) { //
// orderprice
this.cachePrice = newVal.price;
this.reset();
}
//
if (oldVal && !newVal) { //
this.cachePrice = null;
this.reset();
}
// }
},
symbol(){
this.getCoinInfo()
}
},
methods: {
getCoinInfo(){
// console.log(this.symbol.indexOf('usdt')!=-1)
// if(!this.symbol){
// return;
// }
if(this.symbol.indexOf('usdt')!=-1){
var market=this.symbol.substring(0,this.symbol.length-4);
}else{
var market=this.symbol.substring(0,this.symbol.length-3);
}
// console.log(market)
let data = {
coin_name:market,
// coin_name:this.symbol,
lang:this.lang
}
Market.getstockCoinInfo(data).then(res => {
this.detail = res
}).catch(err => {
});
},
renderBuyAmount(val, index) {
// console.Info(val)
// console.Info(this.buyorder)
if (!this.buyorder.entrust_price) {
this.visibles.buy.limitPrice = true;
this.msgList.buy[1] = this.$t('nav.set');
this.clearAll();
return;
}
this.buyPercentIndex = index;
this.buyTotal = Math.multiple(this.fromBalance, val);
},
renderSellAmount(val, index) {
if (!this.sellorder.entrust_price) {
this.visibles.sell.limitPrice = true;
this.msgList.sell[1] = this.$t('nav.set');
this.clearAll();
return;
}
this.sellPercentIndex = index;
this.sellorder.amount = Math.multiple(this.toBalance, val);
},
handleBuyOrder() {
//
if (!this.chkValidate(this.buyorder, this.buyTotal, "buy")) return;
const baseArgs = {
symbol: this.pair.to.concat('/', this.pair.from),
type: this.type,
};
//
// 1
// 2
// 3
// 4
Exchange.stockstoreEntrust(Object.assign(this.buyorder, {
total: this.buyTotal,
}, baseArgs)).then(data => {
this.$message({
message:'success',
type: "success"
});
//
this.$emit('update');
//
this.reset();
}).catch(err => {
});
},
handleSellOrder() {
//
if (!this.chkValidate(this.sellorder, this.sellTotal, "sell")) return;
// console.info(this.sellTotal)
const baseArgs = {
symbol: this.pair.to.concat('/', this.pair.from),
type: this.type,
};
Exchange.stockstoreEntrust(Object.assign(this.sellorder, {
total: this.sellTotal
}, baseArgs)).then(data => {
this.$message({
message:'success',
type: "success"
});
//
this.$emit('update');
//
this.reset();
}).catch(err => {
});
},
reset() {
// newTrade 0
//
let price = this.cachePrice || 0;
// console.info(price)
// console.info(this.priceDecimals)
this.buyorder.entrust_price = Math.omitTo(price, this.priceDecimals);
this.buyorder.trigger_price = Math.omitTo(price, this.priceDecimals);
this.sellorder.entrust_price = Math.omitTo(price, this.priceDecimals);
// console.info(this.sellorder.entrust_price)
this.sellorder.trigger_price = Math.omitTo(price, this.priceDecimals);
//
this.buyorder.amount = 0;
this.sellorder.amount = 0;
// totalset
// this.buyTotal = 0;
// this.cacheTotal = 0;
//
this.buyPercentIndex = -1;
this.sellPercentIndex = -1;
},
clearAll() {
// 5s
setTimeout(function () {
Object.keys(this.visibles.buy).forEach(key => this.visibles.buy[key] = false);
Object.keys(this.visibles.sell).forEach(key => this.visibles.sell[key] = false);
}.bind(this), 5000);
},
empty(val) {
let ret;
switch (typeof val) {
case "number":
ret = val == 0;
break;
case "string":
ret = val == "0" || /^\s?$/.test(val);
break;
case "boolean":
ret = val;
break;
default:
ret = Boolean(val);
break;
}
return ret;
},
chkValidate(order, total, orderType) {
//
//
if (!this.isLogin) {
this.$confirm(this.$t('nav.login'), {
confirmButtonText:this.$t('common.confirmBtn'),
cancelButtonText: this.$t('common.cancelBtn'),
type: 'warning'
}).then(() => {
this.$router.push(`/sign-in`);
}).catch();
return;
}
let flag = true;
switch (this.type) {
case 1: // limit
if (this.empty(order.entrust_price)) {
flag = false;
this.visibles[orderType].limitPrice = true;
this.msgList[orderType][1] = this.$t('nav.a1');
} else if (this.empty(order.amount)) {
flag = false;
this.visibles[orderType].limitAmount = true;
this.msgList[orderType][2] = this.$t('nav.a2');
} else {
if (order.amount < this.minQty) {
flag = false;
this.visibles[orderType].limitAmount = true;
this.msgList[orderType][2] = this.$t('nav.a3')+`${this.minQty}`;
}
if (total < this.minTotal) {
flag = false;
this.visibles[orderType].orderTotal = true;
this.msgList[orderType][5] = this.$t('exchange.total')+`${this.minTotal}`;
}
}
break;
case 2: // market
if (order.direction == "buy") { //
if (this.empty(total)) {
flag = false;
this.visibles[orderType].marketTotal = true;
this.msgList[orderType][3] = this.$t('nav.a4');
} else if (this.total < this.minTotal) {
flag = false;
this.visibles.marketTotal = true;
this.msgList[3] = this.$t('nav.a5')+` ${this.minTotal}`;
}
}
if (order.direction == "sell") { //
if (this.empty(order.amount)) {
flag = false;
this.visibles[orderType].marketAmount = true;
this.msgList[orderType][4] = this.$t('nav.a6');
} else if (order.amount < this.minQty) {
flag = false;
this.visibles[orderType].marketAmount = true;
this.msgList[orderType][4] = this.$t('nav.a7')+` ${this.minQty}`;
}
}
break;
case 3: // stop-limit
if (this.empty(order.trigger_price)) {
flag = false;
this.visibles[orderType].trigger = true;
this.msgList[orderType][0] = this.$t('nav.a8')
} else if (this.empty(order.entrust_price)) {
flag = false;
this.visibles[orderType].limitPrice = true;
this.msgList[orderType][1] = this.$t('nav.a9')
} else if (this.empty(order.amount)) {
flag = false;
this.visibles[orderType].limitAmount = true;
this.msgList[orderType][2] = this.$t('nav.b1')
}
break;
case 4: // stop-market
if (this.empty(order.trigger_price)) {
flag = false;
this.visibles[orderType].trigger = true;
this.msgList[orderType][0] = this.$t('nav.b2')
} else {
if (order.direction == "buy") {
if (this.empty(total)) {
flag = false;
this.visibles[orderType].marketTotal = true;
this.msgList[orderType][3] = this.$t('nav.b3')
} else if (total < this.minTotal) {
flag = false;
this.visibles[orderType].marketTotal = true;
this.msgList[orderType][3] = this.$t('nav.b5')+` ${this.minTotal}`
}
}
if (order.direction == "sell") {
if (this.empty(order.amount)) {
flag = false;
this.visibles[orderType].marketAmount = true;
this.msgList[orderType][4] = this.$t('nav.b6')
} else if (order.amount < this.minQty) {
flag = false;
this.visibles[orderType].marketAmount = true;
this.msgList[orderType][4] =this.$t('nav.b7')+ ` ${this.minQty}`
}
}
}
break;
}
//
this.clearAll();
//
return flag;
},
},
created() {
this.getCoinInfo()
this.reset();
},
}
</script>
<style lang="scss" scoped>
.buyPercentActive {
a:link {
font-weight: bold;
background: #26a69a;
color: #fff;
}
}
.sellPercentActive {
a:link {
font-weight: bold;
background: #ef5350;
color: #fff;
}
}
.input-group-text {
width: 68px;
@include flexible(row, center, center);
}
.market-trade {
border: none;
border-color: transparent;
}
.market{
width: 300px;
height: 500px;
overflow: scroll;
display: flex;
flex-wrap: wrap;
padding: 10px;
display: -webkit-box;
color: black;
.ov{
width: 100%;
table-layout:fixed;
word-break:break-all;
overflow:hidden;
}
}
.p-y-xs{
padding: 5px 0;
}
.el-button{
padding: 0!important;
background: transparent!important;
}
.Tab_buy{
width: 50%;
height: 40px;
color: #ffffff;
line-height: 40px;
text-align: center;
border-radius: 40px;
background-color: #25a750;
}
.Tab_buy1{
width: 50%;
height: 40px;
color: #ffffff;
line-height: 40px;
text-align: center;
border-radius: 40px;
}
.Tab_sell{
width: 50%;
height: 40px;
color: #ffffff;
line-height: 40px;
text-align: center;
border-radius: 40px;
background-color: #ca3f64;
}
.Tab_sell1{
width: 50%;
height: 40px;
color: #ffffff;
line-height: 40px;
text-align: center;
border-radius: 40px;
}
.market-trade input{
border: 1px solid #404040;
}
.input-group-text{
border: 1px solid #404040;
background-color: #121212;
}
.form-control{
background-color: #121212;
}
.market-trade p{
color: #e7e7e7;
}
</style>

54
src/views/exchangeStock/market-news.vue

@ -0,0 +1,54 @@
<template>
<div class="col-md-3">
<div class="market-news mt15">
<h2 class="heading">{{ $t("common.news") }}</h2>
<ul>
<li v-for="item in records" :key="item.id">
<router-link :to="`/college/detail/${item.category_id}/${item.id}`">
<strong>{{ truncate(item.title, 25) }}</strong>
{{ truncate(item.excerpt, 50) }}
<span>{{ item.updated_at }}</span>
</router-link>
</li>
</ul>
</div>
</div>
</template>
<script>
import Exchange from "@/api/exchange";
export default {
data() {
return {
records: [], //
}
},
methods: {
getDynamic() {
Exchange.newTrends(10).then(data => {
this.records = data;
}).catch(err => {
});
},
truncate(str, length) {
return _.truncate(str, {
length
});
}
},
created() {
this.getDynamic();
},
}
</script>
<style>
</style>

358
src/views/exchangeStock/order-list.vue

@ -0,0 +1,358 @@
<template>
<div class="col-md-9">
<div class="exchange-history order-history market-order mt15">
<ul class="nav nav-pills" role="tablist">
<li class="nav-item" @click="toggle('stockholdPosition')">
<a class="nav-link active" data-toggle="pill" href="#stock-holdPosition" role="tab" aria-selected="true">{{$t("exchange.a2")}}</a>
</li>
<li class="nav-item" @click="toggle('opens')">
<a class="nav-link" data-toggle="pill" href="#open-orders" role="tab" aria-selected="true">
{{ $t("common.open-orders") }}</a>
</li>
<!-- <li class="nav-item" @click="toggle('conditions')">
<a class="nav-link" data-toggle="pill" href="#stop-orders" role="tab" aria-selected="false">
{{ $t("common.condition-orders") }}</a>
</li> -->
<li class="nav-item" @click="toggle('histories')">
<a class="nav-link" data-toggle="pill" href="#order-history" role="tab" aria-selected="false">
{{ $t("common.history-orders") }}</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="open-orders" role="tabpanel">
<table class="table" v-if="ordersOpen.total">
<thead>
<tr class="text-nowrap">
<th>{{ $t("common.created") }}</th>
<th>{{ $t("common.pair") }}</th>
<th>{{ $t("common.direction") }}</th>
<th>{{ $t("common.order-type") }}</th>
<th>{{ $t("common.order-price") }}</th>
<th>{{ $t("common.order-amount") }}</th>
<th>{{ $t("common.executed-amount") }}</th>
<th>{{ $t("common.executed-total") }}</th>
<th>{{ $t("common.outstanding") }}</th>
<th>{{ $t("common.order-total") }}</th>
<!-- <th>状态</th> -->
<th class="text-right">{{ $t("common.action") }}</th>
</tr>
</thead>
<tbody class="order-tbody">
<tr v-for="(item,idx) in ordersOpen.data" :key="item.id" class="text-nowrap">
<td>{{item.created_at}}</td>
<td>{{item.symbol}}</td>
<template v-if="item.entrust_type == 1">
<td class="green">{{$t("common.buy-in")}}</td>
</template>
<template v-else-if="item.entrust_type == 2">
<td class="red">{{$t("common.sell-out")}}</td>
</template>
<td>
<template v-if="item.type==1">{{ $t("common.limit-type") }}</template>
<template v-if="item.type==2">{{ $t("common.market-type") }}</template>
</td>
<td>{{item.entrust_price|omitTo(priceDecimals)}}</td>
<td>{{item.amount|omitTo(qtyDecimals)}}</td>
<td>{{item.traded_amount|omitTo(priceDecimals)}}</td>
<td>{{item.traded_money|omitTo(priceDecimals)}}</td>
<td>{{item.surplus_amount||omitTo(qtyDecimals)}}</td>
<td>{{item.money ? Math.omitTo(item.money, priceDecimals) : '-'}}</td>
<!-- <td>完成</td> -->
<td class="text-nowrap">
<button type="button" class="btn btn-sm btn-outline-danger"
@click="delOrder(item,idx)">{{ $t("common.cancel") }}</button>
</td>
</tr>
</tbody>
</table>
<div class="no-data" v-else>
<span>
<i class="icon ion-md-document"></i>
{{ $t("common.notData") }}
</span>
</div>
</div>
<div class="tab-pane fade" id="stock-holdPosition" role="tabpanel">
<table class="table" v-if="holdPositionList.length>0">
<thead>
<tr class="text-nowrap">
<th>{{$t("exchange.a3")}}</th>
<th>{{$t("exchange.a4")}}</th>
<th>{{$t("exchange.a5")}}</th>
<th>{{$t("exchange.a6")}}</th>
<th>{{$t("exchange.a7")}}</th>
<th>{{$t("exchange.a8")}}</th>
<th>{{$t("exchange.a9")}}</th>
<th>{{$t("exchange.a10")}}</th>
</tr>
</thead>
<tbody class="order-tbody">
<tr v-for="(item,idx) in holdPositionList" :key="item.id" class="text-nowrap">
<td>{{item.pair_name}}</td>
<td>{{item.market}}</td>
<td>{{item.usable_balance}}</td>
<td>{{item.realtimePrice}}</td>
<td>{{item.cost_price}}</td>
<td>{{item.dayProfit}}</td>
<td>{{item.unRealProfit}}</td>
<td>{{item.profitRate}}</td>
</tr>
</tbody>
</table>
<span class="no-data" v-else>
<i class="icon ion-md-document"></i>
{{ $t("common.notData") }}
</span>
<!-- <div class="p-2">
<el-pagination layout="prev, pager, next" :page-size="holdPositionList.per_page"
@current-change="changePagination1" :total="holdPositionList.total">
</el-pagination>
</div> -->
</div>
<div class="tab-pane fade" id="stop-orders" role="tabpanel">
<!-- <ul class="d-flex justify-content-between market-order-item">
<li>{{ $t("common.created") }}</li>
<li>{{ $t("common.pair") }}</li>
<li>{{ $t("common.direction") }}</li>
<li>{{ $t("common.order-type") }}</li>
<li>{{ $t("common.avg-price") }}</li>
<li>{{ $t("common.executed") }}</li>
<li>{{ $t("common.order-total") }}</li>
<li>{{ $t("common.price-total") }}</li>
</ul>
<span class="no-data">
<i class="icon ion-md-document"></i>
{{ $t("common.notData") }}
</span> -->
</div>
<div class="tab-pane fade" id="order-history" role="tabpanel">
<table class="table" v-if="ordersHistory.total">
<thead>
<tr class="text-nowrap">
<th>{{ $t("common.created") }}</th>
<th>{{ $t("common.pair") }}</th>
<th>{{ $t("common.direction") }}</th>
<th>{{ $t("common.order-type") }}</th>
<th>{{ $t("common.order-price") }}</th>
<th>{{ $t("common.order-amount") }}</th>
<th>{{ $t("common.executed-amount") }}</th>
<th>{{ $t("common.avg-price") }}</th>
<th>{{ $t("common.order-total") }}</th>
<th>{{ $t("common.status") }}</th>
<th>{{ $t("common.details") }}</th>
</tr>
</thead>
<tbody>
<template v-for="(item,index) in ordersHistory.data">
<tr class="text-nowrap" :key="item.id" :name="item.entrust_type+'_'+item.id+'_'+index"
slot="title" @click="handleChange(item)">
<td>{{item.created_at}}</td>
<td>{{item.symbol}}</td>
<template v-if="item.entrust_type == 1">
<td class="green">{{$t("common.buy-in")}}</td>
</template>
<template v-else-if="item.entrust_type == 2">
<td class="red">{{$t("common.sell-out")}}</td>
</template>
<td>
<template v-if="item.type==1">{{ $t("common.limit-type") }}</template>
<template v-if="item.type==2">{{ $t("common.market-type") }}</template>
</td>
<td>{{item.entrust_price ? Math.omitTo(item.entrust_price, priceDecimals) : '-'}}
</td>
<td>{{item.amount|omitTo(qtyDecimals)}}</td>
<td>{{ item.traded_amount|omitTo(qtyDecimals) }}</td>
<td v-if="item.status">
{{Math.division(item.traded_money,item.traded_amount,priceDecimals)}}
</td>
<td v-else>-</td>
<td>{{item.traded_money|omitTo(priceDecimals)}}</td>
<template v-if="item.status">
<td v-if="item.status == 3">
{{ $t("common.completed") }}
</td>
</template>
<template v-else>
<td>{{ $t("common.canceled") }}</td>
</template>
<td>
<i v-if="item.show" class="el-icon-arrow-down"></i>
<i v-else class="el-icon-arrow-right"></i>
</td>
</tr>
<tr :key="item.id+'t'" v-if="item.show">
<td colspan="11">
<template v-if="item.children && item.children.length">
<div v-for="rec in item.children" :key="rec.order_id">
<span>
<span class="text-secondary">
{{ $t("common.id") }}
</span>{{ rec.order_id}} &emsp;
</span>
<span><span class="text-secondary">
{{ $t("common.created") }}</span>{{ rec.created_at}}
&emsp;</span>
<span><span class="text-secondary">
{{ $t("common.filled-price") }}</span>{{ rec.unit_price|omitTo(priceDecimals)}}
&emsp;</span>
<span><span class="text-secondary">
{{ $t("common.filled-amount") }}</span>{{ rec.trade_amount|omitTo(qtyDecimals)}}
&emsp;</span>
<span><span class="text-secondary">
{{ $t("common.filled-total") }}</span>{{ rec.trade_money|omitTo(priceDecimals)}}
&emsp;</span>
<span><span class="text-secondary">
{{ $t("common.fee") }}</span>{{ rec.trade_fee|omitTo(priceDecimals)}}
&emsp;</span>
<span v-if="rec.total_profit>=0"><span class="text-secondary">
{{ $t("common.d23") }}</span>{{rec.total_profit}}
&emsp;</span>
</div>
</template>
<div class="text-center text-secondary" v-else>
Loading...
</div>
</td>
</tr>
</template>
</tbody>
</table>
<span class="no-data" v-else>
<i class="icon ion-md-document"></i>
{{ $t("common.notData") }}
</span>
<div class="p-2">
<el-pagination layout="prev, pager, next" :page-size="ordersHistory.per_page"
@current-change="changePagination" :total="ordersHistory.total">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Order from "@/api/order";
import math from "@/utils/class/math.js";
export default {
props: [
"ordersOpen",
"ordersHistory",
"holdPositionList",
"conditionOrders",
"priceDecimals",
"qtyDecimals",
"isLogin",
"pair"
],
data() {
return {
currentTab: "stockholdPosition",
activeItems: []
};
},
methods: {
omitTo: math.omitTo,
toggle(name) {
this.currentTab = name;
//
this.$emit("change", name);
},
update() {
this.$emit("update");
},
//
delOrder(item, idx) {
let data = {
entrust_id: item.id,
entrust_type: item.entrust_type,
symbol: item.symbol
};
this.$confirm(this.$t("order.ifCancel", {
confirmButtonText: this.$t('common.confirmBtn'),
cancelButtonText: this.$t('common.cancelBtn'),
}))
.then(res => {
Order.stockcancelEntrust(data)
.then(res => {
this.$message.success(this.$t("order.cancelSuccess"));
this.update();
})
.catch(() => {});
})
.catch(err => {});
},
handleChange(item) {
this.$set(item, "show", !item.show);
if (item.children) return;
if (this.isLogin) {
Order.getstockEntrustTradeRecord({
entrust_type: item.entrust_type,
entrust_id: item.id
})
.then(data => {
this.$set(item, "children", data);
})
.catch(err => {});
}
},
changePagination(idx) {
// console.log(idx);
this.$emit("Pagination", idx);
},
changePagination1(idx) {
// console.log(idx);
this.$emit("Pagination1", idx);
}
},
created() {
// console.log(this.ordersHistory);
}
};
</script>
<style scoped>
.market-order{
border: 1px solid #404040;
}
</style>
<style lang="scss">
.exchange-history {
.nav {
background: #121212;
}
.nav-link.active {
color: #007bff;
background: transparent;
}
}
.order-tbody {
display: table-row-group !important;
tr {
float: none;
}
}
</style>

260
src/views/exchangeStock/symbols.vue

@ -0,0 +1,260 @@
<template>
<div class="col-md-3">
<div class="market-pairs">
<!-- 搜索框区域 -->
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-sm">
<i class="icon ion-md-search"></i>
</span>
</div>
<input type="text" class="form-control" v-model="keyword" :placeholder="$t('exchange.search')" aria-describedby="inputGroup-sizing-sm">
</div>
<!-- 币种列表 -->
<ul class="nav nav-pills" role="tablist" ref="navList">
<li class="nav-item" v-for="(coin, index) in markets" :key="index">
<a :class="[`nav-link`, {active:currentCoinIdx == index}]" href @click.prevent="currentCoinIdx = index">
<!-- 查看收藏交易对 -->
<template v-if="coin.coin_name == 'fav'">
<i class="icon ion-md-star"></i>
</template>
<template v-else>
{{ coin.coin_name }}
</template>
</a>
</li>
</ul>
<!-- 币种行情信息不同的交易对价值 -->
<div class="tab-content">
<div v-for="(coin, index) in markets" :key="index">
<table class="table" v-if="currentCoinIdx == index">
<thead>
<tr style="display:block">
<th class="w-33">{{ $t("exchange.pair") }}</th>
<th class="w-33 text-right">{{ $t("exchange.last-price") }}</th>
<th class="w-33 text-right">{{ $t("exchange.change") }}</th>
</tr>
</thead>
<tbody>
<tr style="display:block" :class="{highlight : item.pair_id == marketId}" @click="$emit('update:symbol', item.symbol)" v-for="(item, key) in coin.marketInfoList" :key="key" v-show="isShow(item)">
<td class="w-33" style="white-space:nowrap">
<i class="icon ion-md-star h6" :class="{ active: isCoolect(item) }" @click.self="handleFav(item)"></i>
{{ coin.coin_name == 'fav' ? item.pair_name : item.coin_name + '/' + coin.coin_name}}
</td>
<td class="w-33 text-right">
{{ coin.coin_name == 'fav' ? item.close : item.price}}
</td>
<!-- <td class="w-33 text-right" :class="item.increaseStr.startsWith('-') ? 'red' : 'green'"> -->
<td class="w-33 text-right" :class="increaseStrColor(item)">
{{ item.increaseStr }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</template>
<script>
import Market from "@/api/market";
import Home from "@/api/home";
import { symbolCircle } from "d3";
export default {
props: {
marketList: {
type: Array,
//
default: Array(5).fill({
coin_name: "-",
marketInfoList: Array(10).fill({
coin_name: "-",
price: "-",
increace: 0,
increaseStr: "+0.00%",
}),
})
},
isLogin: {
type: Boolean,
default: false,
},
marketId: {
type: Number,
default: null,
},
firstEnter: true,
},
data() {
return {
keyword: '', //
current: "fav",
//
favList: {
coinName: "fav",
marketInfoList: Array(10).fill({
pair: "-",
price: "-",
increace: 0,
increaseStr: "+0.00%",
}),
},
//
favList: {
coin_name: "fav",
image: require("@/assets/img/waiting.png"),
marketInfoList: [],
},
currentCoinIdx: 0, //
cacheMarketList : [],
collect:[]
}
},
computed: {
markets() {
// 便
return [...this.cacheMarketList, this.favList];
},
},
watch : {
marketList (list) {
if (list.length) this.cacheMarketList = list;
}
},
methods: {
/*
* 询问用户是否登录
* 如果已经登录 返回true
* 如果没有登录 询问用户是否登录进行操作
*/
inquiryLogin() {
if (!this.isLogin) {
this.$confirm(this.$t('nav.login'), this.$t('nav.tips'), {
confirmButtonText: this.$t('home.Login'),
cancelButtonText: this.$t('home.Cancel'),
type: "info",
})
.then(() => {
location.href = "/login";
})
.catch(() => {});
return false;
} else {
return true;
}
},
//
isShow(symbol) {
const reg = new RegExp(this.keyword, "gi");
if (!this.keyword) return true;
else {
let name = symbol.pair_name || symbol.coin_name;
return name.search(reg) >= 0;
}
// return !this.keyword || symbol.coinName.concat(symbol.pair).search(reg) >= 0;
},
//
isCoolect(i) {
// console.log(this.markets[this.currentCoinIdx].marketInfoList)
return this.favList.marketInfoList.map((item) => item.pair_name).includes(i.pair_name);
},
//
handleFav(item) {
let data = {
pair_name: item.pair_name,
};
Home.option(data)
.then((res) => {
this.getCollect();
if (res) {
this.$message.success(this.$t("home.add"));
} else {
this.$message.success(this.$t("home.cancel"));
}
})
.catch((err) => {});
},
getCollect() {
Home.getCollect()
.then((res) => {
this.favList.marketInfoList = res||[];
})
.catch((err) => {});
},
increaseStrColor(item){
if (item && item.increaseStr && item.increaseStr.startsWith('-')) {
return 'red'
} else {
return 'green'
}
}
},
created() {
},
mounted() {
// []
Market.getstockMarketList().then(data => {
this.cacheMarketList = data;
}).catch(err => {});
// console.log(this.isLogin)
//
if (this.isLogin) {
this.getCollect()
}
}
}
</script>
<style lang="scss">
.highlight {
background: #f6f8f9;
background: #F8F8FF;
td:first-child {
color: #007bff !important;
}
}
.w-33 {
display: inline-block !important;
vertical-align: top !important;
width: 32% !important;
}
.active{
color: #326AEB!important;
}
</style>
Loading…
Cancel
Save