Browse Source

修改合约ws断掉后自动重新获取ws数据

master
liaoxinyu 1 month ago
parent
commit
6e704996eb
  1. 4
      src/api/contract.js
  2. 345
      src/api/server/Socket.js
  3. 10
      src/components/CommonFooter.vue
  4. 14
      src/components/CommonHeader.vue
  5. 322
      src/views/contract/handicap.vue
  6. 556
      src/views/contract/index.vue
  7. 198
      src/views/option/kline.vue

4
src/api/contract.js

@ -11,14 +11,14 @@ class Contract {
}
static getMarketInfo(data) {
return server.get(`/contract/getMarketInfo`, {params:data})
return server.get(`/contract/getMarketInfo`, {params:data,config:{loading:false}})
}
/**
* 获取合约市场
*/
static getMarketList(data) {
return server.get('/contract/getMarketList', {params:data})
return server.get('/contract/getMarketList', {params:data,config:{loading:false}})
}
/**

345
src/api/server/Socket.js

@ -1,52 +1,217 @@
// class Socket {
// constructor(link, ...args) {
// // 初始化socket
// if (link.constructor === WebSocket) {
// this.socket = link;
// } else {
// this.socket = new WebSocket(link);
// }
// // this.socket.binaryType = 'arraybuffer';
// this.doOpen();
// // 连接状态的标识符
// this.readyState = this.socket.readyState;
// // 订阅/发布模型
// this._events = {
// // 订阅的事件 : 发布的方法
// };
// // 定时验证的标识符
// this.heartBeatTimer = null;
// }
// // 执行socket并发布事件
// doOpen() {
// this.afterOpenEmit = [];
// // 执行socket连接 并初始化验证请求
// this.socket.addEventListener("open", evt => this.onOpen(evt));
// // 接收socket数据
// this.socket.addEventListener("message", evt => this.onMessage(evt));
// // 关闭socket连接
// this.socket.addEventListener("close", evt => this.onClose(evt));
// // 请求发生错误
// this.socket.addEventListener("error", err => this.onError(err));
// }
// // 发布后通知订阅者
// Notify(entry) {
// // 检查是否有订阅者 返回队列
// const cbQueue = this._events[entry.Event];
// if (cbQueue && cbQueue.length) {
// for (let callback of cbQueue) {
// if (callback instanceof Function) callback(entry.Data);
// }
// }
// }
// // 请求数据的方法
// onOpen(evt) {
// // 每隔20s检查连接
// // this.heartBeatTimer = setInterval(() => this.send({
// // 'cmd': 'ping',
// // 'args': ''
// // }), 20000);
// // 通知订阅
// this.Notify({Event: 'open', Data : evt});
// }
// /**
// * 订阅所有的数据
// * @param {array|object} datas 订阅参数集合
// */
// send(datas) {
// if (datas.constructor != Array) {
// datas = [datas];
// }
// for (let item of datas) {
// this.socket.send(JSON.stringify(item));
// }
// }
// onMessage(evt) {
// try {
// // 解析推送的数据
// const data = JSON.parse(evt.data);
// // 通知订阅者
// this.Notify({
// Event: 'message',
// Data: data
// });
// } catch (err) {
// console.error(' >> Data parsing error:', err);
// // 通知订阅者
// this.Notify({
// Event: 'error',
// Data: err
// });
// }
// }
// // 添加事件监听
// on(name, handler) {
// this.subscribe(name, handler);
// }
// // 取消订阅事件
// off(name, handler) {
// this.unsubscribe(name, handler);
// }
// // 订阅事件的方法
// subscribe(name, handler) {
// if (this._events.hasOwnProperty(name)) {
// this._events[name].push(handler); // 追加事件
// } else {
// this._events[name] = [handler]; // 添加事件
// }
// }
// // 取消订阅事件
// unsubscribe(name, handler) {
// let start = this._events[name].findIndex(item => item === handler);
// // 删除该事件
// this._events[name].splice(start, 1);
// }
// checkOpen() {
// return this.readyState >= 2;
// }
// onClose(evt) {
// this.Notify({Event: 'close', Data : evt});
// }
// onError(err) {
// this.Notify({Event: 'error', Data : err});
// }
// emit(data) {
// return new Promise((resolve) => {
// this.send(JSON.stringify(data));
// this.on('message', function (data) {
// resolve(data);
// });
// });
// }
// doClose() {
// this.socket.close();
// }
// destroy() {
// if (this.heartBeatTimer) {
// clearInterval(this.heartBeatTimer);
// this.heartBeatTimer = null;
// }
// this.doClose();
// this._events = {};
// this.readyState = 0;
// this.socket = null;
// }
// }
// export default Socket
class Socket {
constructor(link, ...args) {
// 初始化socket
// 修复1:确保 this.link 存的是字符串,方便后面断线重连
if (link.constructor === WebSocket) {
this.socket = link;
this.link = link.url;
} else {
this.socket = new WebSocket(link);
this.link = link;
}
// this.socket.binaryType = 'arraybuffer';
this.doOpen();
// 连接状态的标识符
this.readyState = this.socket.readyState;
// 订阅/发布模型
this._events = {
// 订阅的事件 : 发布的方法
};
// 定时验证的标识符
this._events = {};
this.heartBeatTimer = null;
// 新增:重连相关的标识符
this.reconnectTimer = null;
this.isReconnecting = false;
this.manualClose = false; // 判断是否是用户主动退出页面
}
// 执行socket并发布事件
doOpen() {
this.afterOpenEmit = [];
// 执行socket连接 并初始化验证请求
this.socket.addEventListener("open", evt => this.onOpen(evt));
// 接收socket数据
this.socket.addEventListener("message", evt => this.onMessage(evt));
// 关闭socket连接
this.socket.addEventListener("close", evt => this.onClose(evt));
// 请求发生错误
this.socket.addEventListener("error", err => this.onError(err));
}
// 发布后通知订阅者
Notify(entry) {
// 检查是否有订阅者 返回队列
const cbQueue = this._events[entry.Event];
if (cbQueue && cbQueue.length) {
for (let callback of cbQueue) {
@ -55,118 +220,152 @@ class Socket {
}
}
// 请求数据的方法
onOpen(evt) {
// 连接成功,重置状态
this.isReconnecting = false;
this.manualClose = false;
// 每次连上先清空旧的心跳,防止重复
if (this.heartBeatTimer) clearInterval(this.heartBeatTimer);
// 每隔20s发送心跳
this.heartBeatTimer = setInterval(() => {
this.send({
'cmd': 'ping',
'args': ''
});
}, 20000);
// 每隔20s检查连接
// this.heartBeatTimer = setInterval(() => this.send({
// 'cmd': 'ping',
// 'args': ''
// }), 20000);
// 通知订阅
this.Notify({Event: 'open', Data : evt});
}
/**
* 订阅所有的数据
* @param {array|object} datas 订阅参数集合
*/
send(datas) {
if (datas.constructor != Array) {
datas = [datas];
datas = [datas];
}
for (let item of datas) {
this.socket.send(JSON.stringify(item));
// 修复2:发送前必须检查状态,彻底解决 "CLOSING or CLOSED state" 报错!
if (this.socket && this.socket.readyState === 1) {
this.socket.send(JSON.stringify(item));
} else {
console.warn("WebSocket未连接,已拦截发送请求");
}
}
}
onMessage(evt) {
try {
// 解析推送的数据
const data = JSON.parse(evt.data);
// 通知订阅者
this.Notify({
Event: 'message',
Data: data
});
this.Notify({ Event: 'message', Data: data });
} catch (err) {
console.error(' >> Data parsing error:', err);
// 通知订阅者
this.Notify({
Event: 'error',
Data: err
});
this.Notify({ Event: 'error', Data: err });
}
}
// 添加事件监听
on(name, handler) {
this.subscribe(name, handler);
}
// 取消订阅事件
off(name, handler) {
this.unsubscribe(name, handler);
}
// 订阅事件的方法
subscribe(name, handler) {
if (this._events.hasOwnProperty(name)) {
this._events[name].push(handler); // 追加事件
this._events[name].push(handler);
} else {
this._events[name] = [handler]; // 添加事件
this._events[name] = [handler];
}
}
// 取消订阅事件
unsubscribe(name, handler) {
if (!this._events[name]) return;
let start = this._events[name].findIndex(item => item === handler);
// 删除该事件
this._events[name].splice(start, 1);
if (start > -1) {
this._events[name].splice(start, 1);
}
}
checkOpen() {
return this.readyState >= 2;
}
// 修复3:核心重连逻辑
reconnect() {
// 如果是手动关闭(退出页面),或者正在重连中,则放弃重连
if (this.manualClose || this.isReconnecting) return;
this.isReconnecting = true;
// 断网了,立刻停止发心跳
if (this.heartBeatTimer) {
clearInterval(this.heartBeatTimer);
this.heartBeatTimer = null;
}
console.log("WebSocket 掉线,3秒后尝试重新连接...");
this.reconnectTimer = setTimeout(() => {
try {
this.socket = new WebSocket(this.link);
this.doOpen();
} catch (e) {
console.error("重连失败", e);
// 即使抛出异常也解除锁,等待下一次重连尝试
this.isReconnecting = false;
this.reconnect();
return;
}
}, 3000);
}
onClose(evt) {
this.Notify({Event: 'close', Data : evt});
// 触发关闭时,只要不是主动退出的,就去重连
if (!this.manualClose) this.reconnect();
}
onError(err) {
this.Notify({Event: 'error', Data : err});
// 发生错误断开时,去重连
if (!this.manualClose) this.reconnect();
}
// 修复4:解决内存泄漏,用完立刻注销
emit(data) {
return new Promise((resolve) => {
this.send(JSON.stringify(data));
this.on('message', function (data) {
resolve(data);
});
const handler = (resData) => {
resolve(resData);
this.off('message', handler); // 立刻注销,释放内存
};
this.on('message', handler);
});
}
doClose() {
this.socket.close();
this.manualClose = true; // 标记为主动关闭,防止变成僵尸无限重连
if (this.socket) {
this.socket.close();
}
}
destroy() {
this.manualClose = true;
if (this.heartBeatTimer) {
clearInterval(this.heartBeatTimer);
this.heartBeatTimer = null;
}
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
this.doClose();
this._events = {};
this.readyState = 0;
@ -174,4 +373,4 @@ class Socket {
}
}
export default Socket
export default Socket;

10
src/components/CommonFooter.vue

@ -352,11 +352,11 @@ export default {
label: "Turkey",
url: require("../assets/img/tr.jpg"),
},
{
value: 'ar',
label: 'عربي',
url:require('../assets/img/polski.png')
},
// {
// value: 'ar',
// label: 'عربي',
// url:require('../assets/img/polski.png')
// },
{
value: "tw", // zh-TW
label: "繁体中文",

14
src/components/CommonHeader.vue

@ -42,9 +42,9 @@
<li class="nav-item">
<router-link class="nav-link" :to="contract.url">{{ contract.label }}</router-link>
</li>
<li class="nav-item">
<!-- <li class="nav-item">
<router-link class="nav-link" to="/exchangestock">{{ $t('exchange.a1') }}</router-link>
</li>
</li> -->
<li class="nav-item">
<router-link class="nav-link" :to="learn.url">{{ learn.label }}</router-link>
</li>
@ -419,11 +419,11 @@ export default {
label: "Turkey",
url: require("../assets/img/tr.jpg"),
},
{
value: 'ar',
label: 'عربي',
url:require('../assets/img/polski.png')
},
// {
// value: 'ar',
// label: 'عربي',
// url:require('../assets/img/polski.png')
// },
{
value: "tw", // zh-TW
label: "繁体中文",

322
src/views/contract/handicap.vue

@ -134,6 +134,18 @@ export default {
buyList: [],
tradeList: [],
newPriceObj: {},
//
wsOpenHandler: null,
wsMessageHandler: null,
collapseHandler: null,
//
isRetrying: false,
lastMessageTime: 0, //
watchdogTimer: null, //
watchdogTimeout: 5000 // 5
};
},
props: {
@ -192,29 +204,75 @@ export default {
if (this.symbol) {
this.getMarketInfo();
this.linkSocket();
this.startWatchdog();
}
bus.$on('collapse', msg => {
this.newPriceObj.price =this.symbol=='BTC'? (msg.close).toFixed(1):(msg.close).toFixed(3);
this.newPriceObj.price = msg.close;
this.$emit("input", this.newPriceObj);
localStorage.setItem("price",this.newPriceObj.price)
});
},
beforeDestroy() {
this.unLink(this.symbol);
this.removeSocketListeners();
this.stopWatchdog();
},
//
methods: {
parseTime: date.parseTime,
omitTo: math.omitTo,
// getMarketInfo() {
// let data = {
// symbol: this.symbol
// };
// Contract.getMarketInfo(data).then(res => {
// this.sellList = res.swapSellList;
// this.buyList = res.swapBuyList;
// this.tradeList = res.swapTradeList;
// this.newPriceObj = this.tradeList[0];
// this.$emit("input", this.newPriceObj);
// localStorage.setItem("price",this.newPriceObj.price)
// });
// },
// .catch
getMarketInfo() {
let data = {
symbol: this.symbol
};
Contract.getMarketInfo(data).then(res => {
this.sellList = res.swapSellList;
this.buyList = res.swapBuyList;
this.tradeList = res.swapTradeList;
this.newPriceObj = this.tradeList[0];
this.$emit("input", this.newPriceObj);
localStorage.setItem("price",this.newPriceObj.price)
});
if (!this.symbol) return;
let data = { symbol: this.symbol };
Contract.getMarketInfo(data).then(res => {
this.isRetrying = false; //
this.sellList = res.swapSellList;
this.buyList = res.swapBuyList;
this.tradeList = res.swapTradeList;
if(this.tradeList && this.tradeList.length > 0){
this.newPriceObj = this.tradeList[0];
}
this.$emit("input", this.newPriceObj);
localStorage.setItem("price", this.newPriceObj.price);
}).catch(err => {
// (Uncaught in promise)
console.error("盘口接口请求失败/超时,3秒后自动重试...", err);
//
if (!this.isRetrying) {
this.isRetrying = true;
setTimeout(() => {
this.isRetrying = false;
this.getMarketInfo(); //
// 便 WS
if (this.ws && !this.ws.checkOpen()) {
console.log("检测到网络较差,尝试重连 WebSocket...");
this.ws.reconnect();
}
}, 3000); // 3
}
});
},
//
getValue(amount) {
@ -224,74 +282,182 @@ export default {
let max = Math.max(...arr);
return math.division(amount, max, 2) * 100;
},
// socket
linkSocket() {
if (this.ws.socket.readyState == 1) {
this.ws.send({
cmd: "sub",
msg: this.msg.buy
});
this.ws.send({
cmd: "sub",
msg: this.msg.sell
});
this.ws.send({
cmd: "sub",
msg: this.msg.trade
});
} else {
this.ws.on("open", () => {
this.ws.send({
cmd: "sub",
msg: this.msg.buy
});
this.ws.send({
cmd: "sub",
msg: this.msg.sell
});
this.ws.send({
cmd: "sub",
msg: this.msg.trade
});
});
}
this.ws.on("message", res => {
let { data, msg, code, sub, type, status, cmd } = res;
if (sub == this.msg.buy) {
this.buyList = data;
} else if (sub == this.msg.sell) {
this.sellList = data;
} else if (sub == this.msg.trade) {
this.tradeList.unshift(data);
this.tradeList.pop();
// this.newPriceObj = data;
// this.$emit("input", this.newPriceObj);
} else if (type == "ping" ||cmd == "ping") {
this.ws.send({
cmd: "pong"
});
}
});
//
sendSubscribe() {
if (!this.ws || !this.ws.socket || this.ws.socket.readyState !== 1) return;
this.ws.send({ cmd: "sub", msg: this.msg.buy });
this.ws.send({ cmd: "sub", msg: this.msg.sell });
this.ws.send({ cmd: "sub", msg: this.msg.trade });
},
//
removeSocketListeners() {
if (this.wsOpenHandler && this.ws) {
this.ws.off("open", this.wsOpenHandler);
}
if (this.wsMessageHandler && this.ws) {
this.ws.off("message", this.wsMessageHandler);
}
},
// WebSocket
startWatchdog() {
this.stopWatchdog();
this.lastMessageTime = Date.now();
this.watchdogTimer = setInterval(() => {
const now = Date.now();
if (now - this.lastMessageTime > this.watchdogTimeout) {
console.error(`[看门狗报警] 已经 ${this.watchdogTimeout/1000} 秒没收到推送了!判定为后端假死!正在强行掐断并新建 WebSocket...`);
// 1. HTTP
this.getMarketInfo();
// 2. Socket
if (this.ws) {
//
if (this.ws.socket) {
this.ws.socket.close();
}
// reconnect
this.ws.isReconnecting = false;
this.ws.manualClose = false;
this.ws.reconnect();
}
// 3.
this.lastMessageTime = Date.now();
}
}, 5000); // 5
},
// 🔥
stopWatchdog() {
if (this.watchdogTimer) {
clearInterval(this.watchdogTimer);
this.watchdogTimer = null;
}
},
// WebSocket
linkSocket() {
if (!this.ws) return;
this.removeSocketListeners();
// open
this.wsOpenHandler = () => {
this.sendSubscribe();
};
this.ws.on("open", this.wsOpenHandler);
//
this.wsMessageHandler = res => {
let { data, msg, code, sub, type, status, cmd } = res;
if (sub == this.msg.buy || sub == this.msg.sell || sub == this.msg.trade) {
this.lastMessageTime = Date.now();
}
if (sub == this.msg.buy) {
this.buyList = data;
} else if (sub == this.msg.sell) {
this.sellList = data;
} else if (sub == this.msg.trade) {
this.tradeList.unshift(data);
this.tradeList.pop();
} else if (type == "ping" || cmd == "ping") {
this.ws.send({ cmd: "pong" });
}
};
this.ws.on("message", this.wsMessageHandler);
//
if (this.ws.socket && this.ws.socket.readyState === 1) {
this.sendSubscribe();
}
this.startWatchdog(); //
},
unLink(symbol) {
if (!this.ws || !this.ws.socket || this.ws.socket.readyState !== 1) return;
this.ws.send({ cmd: "unsub", msg: `swapBuyList_${symbol}` });
this.ws.send({ cmd: "unsub", msg: `swapSellList_${symbol}` });
this.ws.send({ cmd: "unsub", msg: `swapTradeList_${symbol}` });
}
// // socket
// linkSocket() {
// if (this.ws.socket.readyState == 1) {
// this.ws.send({
// cmd: "sub",
// msg: this.msg.buy
// });
// this.ws.send({
// cmd: "sub",
// msg: this.msg.sell
// });
// this.ws.send({
// cmd: "sub",
// msg: this.msg.trade
// });
// } else {
// this.ws.on("open", () => {
// this.ws.send({
// cmd: "sub",
// msg: this.msg.buy
// });
// this.ws.send({
// cmd: "sub",
// msg: this.msg.sell
// });
// this.ws.send({
// cmd: "sub",
// msg: this.msg.trade
// });
// });
// }
// this.ws.on("message", res => {
// let { data, msg, code, sub, type, status, cmd } = res;
// if (sub == this.msg.buy) {
// this.buyList = data;
// } else if (sub == this.msg.sell) {
// this.sellList = data;
// } else if (sub == this.msg.trade) {
// this.tradeList.unshift(data);
// this.tradeList.pop();
// // this.newPriceObj = data;
// // this.$emit("input", this.newPriceObj);
// } else if (type == "ping" ||cmd == "ping") {
// this.ws.send({
// cmd: "pong"
// });
// }
// });
},
//
unLink(symbol) {
// 线
this.ws.send({
cmd: "unsub",
msg: `swapBuyList_${symbol}`
});
// 线
this.ws.send({
cmd: "unsub",
msg: `swapSellList_${symbol}`
});
//
this.ws.send({
cmd: "unsub",
msg: `swapTradeList_${symbol}`
});
}
// },
// //
// unLink(symbol) {
// // 线
// this.ws.send({
// cmd: "unsub",
// msg: `swapBuyList_${symbol}`
// });
// // 线
// this.ws.send({
// cmd: "unsub",
// msg: `swapSellList_${symbol}`
// });
// //
// this.ws.send({
// cmd: "unsub",
// msg: `swapTradeList_${symbol}`
// });
// }
}
};
</script>

556
src/views/contract/index.vue

@ -206,6 +206,271 @@
</div>
</template>
<script>
// import kline from "../option/kline";
// import handicap from "./handicap.vue";
// import account from "./account.vue";
// import exchangeStore from "./exchange-store.vue";
// import pageBottom from "./page-bottom.vue";
// import Contract from "../../api/contract";
// import Socket from "@/api/server/Socket.js";
// import Home from "@/api/home";
// import bus from "@/components/bus.js";
// export default {
// components: {
// kline,
// handicap,
// account,
// exchangeStore,
// pageBottom
// },
// data() {
// return {
// contractList: [],
// activeSymbol: "",
// holdPositionAll: false,
// holdPositionList: [],
// newPriceObj: {},
// pcBannerList:[],
// accountInfo: {},
// defaultPrice: "",
// wsUrl: this.Globals.Server.Path.WS1,
// ws: new Socket(this.Globals.Server.Path.WS1),
// _time: null,
// contractOpen: false,
// contractAgreement: {},
// symbolDetail:{},
// currentIcon: '',
// filterCoin: "",
// contractListFilter: [],
// Liste:[],
// price1:0,
// intervalId:''
// };
// },
// computed: {
// activeContract(val) {
// let contractList=this.contractList
// .map(item => item.marketInfoList)
// .flat()
// .find(item => item.symbol == this.activeSymbol) || {}
// if(val.price){
// delete contractList.price
// }
// return contractList;
// },
// isLogin() {
// return Boolean(localStorage.token);
// },
// // contractListFilter(){
// // return this.contractList.map((item1, index1)=>{
// // item1.marketInfoList.filter(item2=>{
// // return item2.symbol.indexOf(this.filterCoin)!=-1
// // })
// // return item1;
// // })
// // }
// },
// watch: {
// activeSymbol() {
// this.holdPosition();
// },
// // filterCoin: {
// // handler(n,o){
// // if(!n){
// // this.contractListFilter = this.contractList;
// // }else{
// // this.contractListFilter = this.contractList.map((item1, index1)=>{
// // let arr = item1;
// // arr.marketInfoList = item1.marketInfoList.filter(item2=>{
// // return item2.symbol.indexOf(n.toUpperCase())!=-1
// // })
// // return arr;
// // })
// // }
// // },
// // immediate: true
// // }
// },
// destroyed() {
// clearInterval(this._time);
// },
// created() {
// // this.openStatus();
// this.getMarketList();
// this.holdPosition();
// this.indexList();
// this._time = setInterval(() => {
// if (this.contractOpen) {
// this.holdPosition();
// }
// }, 3000);
// this.ws.on("open", () => {
// this.swapMarketList();
// });
// // console.info(this.$refs)
// bus.$on('collapse', msg => {
// this.activeContract.price =this.activeContract.symbol=='BTC'? (msg.close).toFixed(1):(msg.close).toFixed(3);
// this.holdPositionList.map(item=>{
// if(item.symbol==this.activeContract.symbol) item.realtimePrice=this.activeContract.price
// })
// });
// this.startWatchingPrice()
// },
// //
// mounted: function () {
// setInterval(() => {
// this.holdPosition();
// }, 2000)
// },
// methods: {
// startWatchingPrice(){
// this.intervalId = setInterval(() => {
// let newPrice = localStorage.getItem('price');
// this.price1 = newPrice;
// }, 10); //
// },
// ispopover1(item){
// this.activeSymbol=item;
// // this.$refs.popover.showPopper = false;
// this.getMarketList();
// },
// swapMarketList() {
// let msg = "swapMarketList";
// this.ws.send({
// cmd: "sub",
// msg: msg
// });
// this.ws.on("message", res => {
// let { data, sub,cmd } = res;
// if (sub == msg) {
// if( data.symbol=='BTC' )(data.price).toFixed(1)
// this.contractList = data;
// if(this.filterCoin==''){
// this.contractListFilter = data;
// }
// }else if (cmd == "ping") {
// this.ws.send({
// cmd: "pong"
// });
// }
// });
// this.ws.on('close',()=>{
// this.ws= new Socket(this.Globals.Server.Path.WS1),
// console.log('');
// this.wsOpen();
// })
// },
// wsOpen(){
// this.ws.on("open", () => {
// this.swapMarketList();
// this.$refs.handicap.linkSocket()
// });
// },
// //
// getMarketList() {
// this.currentIcon = "";
// Contract.getMarketList().then(res => {
// if(this.activeSymbol==''){
// //
// this.contractList = res;
// if(this.filterCoin==''){
// this.contractListFilter = res;
// this.Listes();
// }
// //
// let firstParent = res[0];
// if (firstParent) {
// let first = firstParent.marketInfoList[0];
// if (first) this.activeSymbol = first.symbol;
// this.currentIcon = res[0].marketInfoList[0].icon;
// }
// }else{
// // icon
// for(let item of res[0].marketInfoList){
// if(this.activeSymbol==item.symbol){
// this.currentIcon = item.icon;
// }
// }
// }
// });
// },
// Listes(){
// this.Liste = []
// this.contractListFilter[0].marketInfoList.map(item=>{
// this.Liste.push({
// pair_name: item.pair_name,
// symbol: item.symbol,
// icon:item.icon
// })
// })
// },
// //
// holdPosition() {
// if (!this.isLogin) return;
// let data = {
// symbol: (this.holdPositionAll && this.activeSymbol) || ""
// };
// Contract.holdPosition(data, { loading: false }).then(res => {
// // console.info(res)
// res.map(item=>{
// if(item.symbol==this.activeContract.symbol) item.realtimePrice=this.activeContract.price
// })
// this.holdPositionList = res;
// });
// },
// //
// openStatus() {
// if(!this.isLogin) return;
// Contract.openStatus().then(res => {
// this.contractOpen = res.open;
// if (!this.contractOpen) {
// this.contractAgreement = res.contractAgreement;
// $("#openContract").modal("show");
// }
// });
// },
// //
// opening() {
// Contract.opening().then(res => {
// $("#openContract").modal("hide");
// this.contractOpen = true;
// this.$message.success(this.$t('contract.j9'));
// });
// },
// indexList() {
// Home.indexList().then((res) => {
// this.pcBannerList = res.pcBannerList
// // setTimeout(() => {
// // this.skroll();
// // }, 100);
// }).catch((res) => {});
// },
// //
// setactiveItem(index=0){
// this.accountInfo=this.holdPositionList[index]
// },
// enterFilter(){
// },
// isShow(symbol) {
// const reg = new RegExp(this.filterCoin, "gi");
// if (!this.filterCoin) return true;
// else {
// // let name = symbol.coinName || symbol.pair;
// // return name.search(reg) >= 0;
// let name = symbol.pair_name || symbol.symbol;
// return name.search(reg) >= 0;
// }
// // return !this.keyword || symbol.coinName.concat(symbol.pair).search(reg) >= 0;
// },
// }
// };
import kline from "../option/kline";
import handicap from "./handicap.vue";
import account from "./account.vue";
@ -215,6 +480,7 @@ import Contract from "../../api/contract";
import Socket from "@/api/server/Socket.js";
import Home from "@/api/home";
import bus from "@/components/bus.js";
export default {
components: {
kline,
@ -233,18 +499,32 @@ export default {
pcBannerList:[],
accountInfo: {},
defaultPrice: "",
// Socket
wsUrl: this.Globals.Server.Path.WS1,
ws: new Socket(this.Globals.Server.Path.WS1),
ws: null,
_time: null,
holdTimer: null, //
contractOpen: false,
contractAgreement: {},
symbolDetail:{},
currentIcon: '',
filterCoin: "",
contractListFilter: [],
Liste:[],
price1:0,
intervalId:''
Liste:[],
price1:0,
intervalId:'',
//
swapMarketHandler: null,
wsOpenHandler: null,
collapseHandler: null,
// 🔥
lastMessageTime: 0,
watchdogTimer: null,
watchdogTimeout: 15000 // 15
};
},
computed: {
@ -261,152 +541,203 @@ export default {
isLogin() {
return Boolean(localStorage.token);
},
// contractListFilter(){
// return this.contractList.map((item1, index1)=>{
// item1.marketInfoList.filter(item2=>{
// return item2.symbol.indexOf(this.filterCoin)!=-1
// })
// return item1;
// })
// }
set_price() {
return this.$store.getters.set_price;
}
},
watch: {
activeSymbol() {
this.holdPosition();
},
// filterCoin: {
// handler(n,o){
// if(!n){
// this.contractListFilter = this.contractList;
// }else{
// this.contractListFilter = this.contractList.map((item1, index1)=>{
// let arr = item1;
// arr.marketInfoList = item1.marketInfoList.filter(item2=>{
// return item2.symbol.indexOf(n.toUpperCase())!=-1
// })
// return arr;
// })
// }
// },
// immediate: true
// }
},
destroyed() {
clearInterval(this._time);
},
created() {
// this.openStatus();
// Socket
this.ws = new Socket(this.wsUrl);
this.getMarketList();
this.holdPosition();
this.indexList();
this._time = setInterval(() => {
if (this.contractOpen) {
this.holdPosition();
}
}, 3000);
this.ws.on("open", () => {
this.swapMarketList();
});
// console.info(this.$refs)
bus.$on('collapse', msg => {
this.activeContract.price =this.activeContract.symbol=='BTC'? (msg.close).toFixed(1):(msg.close).toFixed(3);
//
this.collapseHandler = msg => {
this.activeContract.price = this.activeContract.symbol=='BTC'? (msg.close).toFixed(1):(msg.close).toFixed(3);
this.holdPositionList.map(item=>{
if(item.symbol==this.activeContract.symbol) item.realtimePrice=this.activeContract.price
})
});
this.startWatchingPrice()
};
bus.$on('collapse', this.collapseHandler);
// 🔥 WebSocket Open
this.wsOpenHandler = () => {
console.log("PC主页面 WebSocket 连上/重连成功,请求市场列表...");
this.swapMarketList();
};
this.ws.on("open", this.wsOpenHandler);
this.startWatchingPrice();
this.startWatchdog(); //
},
//
mounted: function () {
setInterval(() => {
mounted() {
//
this.holdTimer = setInterval(() => {
this.holdPosition();
}, 2000)
}, 2000);
},
//
beforeDestroy() {
clearInterval(this._time);
clearInterval(this.intervalId);
if (this.holdTimer) clearInterval(this.holdTimer);
this.stopWatchdog();
if (this.collapseHandler) {
bus.$off('collapse', this.collapseHandler);
}
if (this.ws) {
if (this.wsOpenHandler) this.ws.off("open", this.wsOpenHandler);
if (this.swapMarketHandler) this.ws.off("message", this.swapMarketHandler);
this.ws.send({ cmd: "unsub", msg: "swapMarketList" });
this.ws.destroy();
this.ws = null;
}
},
methods: {
startWatchingPrice(){
this.intervalId = setInterval(() => {
let newPrice = localStorage.getItem('price');
this.price1 = newPrice;
}, 10); //
},
startWatchingPrice(){
// 10 100 CPU
this.intervalId = setInterval(() => {
let newPrice = localStorage.getItem('price');
this.price1 = newPrice;
}, 100);
},
ispopover1(item){
this.activeSymbol=item;
// this.$refs.popover.showPopper = false;
this.getMarketList();
},
// 🔥
startWatchdog() {
this.stopWatchdog();
this.lastMessageTime = Date.now();
this.watchdogTimer = setInterval(() => {
if (Date.now() - this.lastMessageTime > this.watchdogTimeout) {
console.error("[PC市场列表看门狗] 超过15秒未收到推送数据,判定后端假死!正在强行掐断并新建 WS...");
// HTTP
this.getMarketList();
//
if (this.ws) {
if (this.ws.socket) this.ws.socket.close();
this.ws.isReconnecting = false;
this.ws.manualClose = false;
this.ws.reconnect();
}
this.lastMessageTime = Date.now(); //
}
}, 5000);
},
stopWatchdog() {
if (this.watchdogTimer) {
clearInterval(this.watchdogTimer);
this.watchdogTimer = null;
}
},
swapMarketList() {
let msg = "swapMarketList";
this.ws.send({
cmd: "sub",
msg: msg
});
this.ws.on("message", res => {
let { data, sub,cmd } = res;
//
if (this.ws && this.ws.checkOpen()) {
this.ws.send({ cmd: "sub", msg: msg });
}
//
if (this.swapMarketHandler) {
this.ws.off("message", this.swapMarketHandler);
}
//
this.swapMarketHandler = res => {
let { data, sub, cmd } = res;
//
if (sub == msg || cmd == "ping") {
this.lastMessageTime = Date.now();
}
if (sub == msg) {
if( data.symbol=='BTC' )(data.price).toFixed(1)
this.contractList = data;
if(this.filterCoin==''){
this.contractListFilter = data;
this.Listes();
}
}else if (cmd == "ping") {
this.ws.send({
cmd: "pong"
});
} else if (cmd == "ping") {
this.ws.send({ cmd: "pong" });
}
});
this.ws.on('close',()=>{
this.ws= new Socket(this.Globals.Server.Path.WS1),
console.log('链接关闭');
this.wsOpen();
})
},
wsOpen(){
this.ws.on("open", () => {
this.swapMarketList();
this.$refs.handicap.linkSocket()
});
};
this.ws.on("message", this.swapMarketHandler);
},
//
getMarketList() {
this.currentIcon = "";
Contract.getMarketList().then(res => {
if(this.activeSymbol==''){
//
this.contractList = res;
if(this.filterCoin==''){
this.contractListFilter = res;
this.Listes();
this.Listes();
}
//
let firstParent = res[0];
if (firstParent) {
let first = firstParent.marketInfoList[0];
if (first) this.activeSymbol = first.symbol;
this.currentIcon = res[0].marketInfoList[0].icon;
}
}else{
// icon
for(let item of res[0].marketInfoList){
if(this.activeSymbol==item.symbol){
this.currentIcon = item.icon;
}
} else {
if (res && res[0]) {
for(let item of res[0].marketInfoList){
if(this.activeSymbol==item.symbol){
this.currentIcon = item.icon;
}
}
}
}
});
},
Listes(){
this.Liste = []
this.contractListFilter[0].marketInfoList.map(item=>{
this.Liste.push({
pair_name: item.pair_name,
symbol: item.symbol,
icon:item.icon
})
})
},
Listes(){
this.Liste = [];
if (!this.contractListFilter || !this.contractListFilter[0] || !this.contractListFilter[0].marketInfoList) return;
this.contractListFilter[0].marketInfoList.map(item => {
this.Liste.push({
pair_name: item.pair_name,
symbol: item.symbol,
icon: item.icon
});
});
},
//
holdPosition() {
if (!this.isLogin) return;
@ -414,14 +745,13 @@ export default {
symbol: (this.holdPositionAll && this.activeSymbol) || ""
};
Contract.holdPosition(data, { loading: false }).then(res => {
// console.info(res)
res.map(item=>{
if(item.symbol==this.activeContract.symbol) item.realtimePrice=this.activeContract.price
})
this.holdPositionList = res;
});
},
//
openStatus() {
if(!this.isLogin) return;
Contract.openStatus().then(res => {
@ -432,7 +762,7 @@ export default {
}
});
},
//
opening() {
Contract.opening().then(res => {
$("#openContract").modal("hide");
@ -440,36 +770,32 @@ export default {
this.$message.success(this.$t('contract.j9'));
});
},
indexList() {
Home.indexList().then((res) => {
this.pcBannerList = res.pcBannerList
// setTimeout(() => {
// this.skroll();
// }, 100);
}).catch((res) => {});
},
//
setactiveItem(index=0){
this.accountInfo=this.holdPositionList[index]
this.accountInfo = this.holdPositionList[index];
},
enterFilter(){
isShow(symbol) {
const reg = new RegExp(this.filterCoin, "gi");
if (!this.filterCoin) return true;
else {
let name = symbol.pair_name || symbol.symbol;
return name.search(reg) >= 0;
}
},
isShow(symbol) {
const reg = new RegExp(this.filterCoin, "gi");
if (!this.filterCoin) return true;
else {
// let name = symbol.coinName || symbol.pair;
// return name.search(reg) >= 0;
let name = symbol.pair_name || symbol.symbol;
return name.search(reg) >= 0;
}
// return !this.keyword || symbol.coinName.concat(symbol.pair).search(reg) >= 0;
},
enterFilter(){
//
}
}
};
</script>
<style lang="scss" scoped>
.justify-content-between ::v-deep .dark-app .theme-switch .theme-switch-button .left, .dark-app .theme-switch .theme-switch-button .right{

198
src/views/option/kline.vue

@ -65,6 +65,12 @@ export default {
this.unsub(this.ajaxTv.getSymbol(o), this.timer);
}
},
periodCurrent(n,o){
if(n != o && o){
console.log('切换周期,页数为第一页')
this.page[this.symbol] = 1;//
}
}
},
computed: {
lang() {
@ -122,60 +128,156 @@ data() {
sub: "",
isCreateSocket: false,
page: {},
tt:undefined
tt:undefined,
periodCurrent: '',
//
wsOpenHandler: null,
wsMessageHandler: null,
// K线
lastMessageTime: 0,
watchdogTimer: null,
watchdogTimeout: 5000 // 5
};
},
// Socket
beforeDestroy() {
if (this.ws) {
this.stopWatchdog();
if (this.sub) this.unsub(this.ajaxTv.getSymbol(this.symbol), this.timer);
this.ws.destroy(); // destroy
this.ws = null;
}
},
methods: {
reconnect() {
if(this.isCreateSocket) {
return;
};
let msgObj = {
cmd: "sub",
msg: this.sub,
};
this.isCreateSocket = true;
//
this.tt && clearTimeout(this.tt);
let th=this
th.tt = setTimeout(function () {
th.isCreateSocket = false;
th.linkSocket(() => {
th.ws.send(msgObj);
});
// reconnect() {
// if(this.isCreateSocket) {
// return;
// };
// let msgObj = {
// cmd: "sub",
// msg: this.sub,
// };
// this.isCreateSocket = true;
// //
// this.tt && clearTimeout(this.tt);
// let th=this
// th.tt = setTimeout(function () {
// th.isCreateSocket = false;
// th.linkSocket(() => {
// th.ws.send(msgObj);
// });
}, 4000);
},
// socket
linkSocket(call) {
const ws = new Socket(this.wsUrl);
ws.on("open", () => {
this.ws = ws;
call && call();
});
// }, 4000);
// },
// // socket
// linkSocket(call) {
// const ws = new Socket(this.wsUrl);
// ws.on("open", () => {
// this.ws = ws;
// call && call();
// });
ws.on("message", (res) => {
let { data, msg, code, sub, type, status, req, cmd } = res;
if (sub == this.sub && this.onRealtimeCallback) {
if(sub.indexOf("BTC")!= -1) (data.close).toFixed(1)
this.onRealtimeCallback(this.getMap(data));
bus.$emit('collapse', data);
} else if (type == "ping" || cmd == "ping") {
this.ws.send({
cmd: "pong",
});
}
});
ws.on('close',()=>{
console.log('链接关闭');
this.reconnect();
})
ws.on('error',()=>{
console.log('发生异常了');
this.reconnect();
})
// ws.on("message", (res) => {
// let { data, msg, code, sub, type, status, req, cmd } = res;
// if (sub == this.sub && this.onRealtimeCallback) {
// if(sub.indexOf("BTC")!= -1) (data.close).toFixed(1)
// this.onRealtimeCallback(this.getMap(data));
// bus.$emit('collapse', data);
// } else if (type == "ping" || cmd == "ping") {
// this.ws.send({
// cmd: "pong",
// });
// }
// });
// ws.on('close',()=>{
// console.log('');
// this.reconnect();
// })
// ws.on('error',()=>{
// console.log('');
// this.reconnect();
// })
},
// },
// K线 15 WS
startWatchdog() {
this.stopWatchdog();
this.lastMessageTime = Date.now();
this.watchdogTimer = setInterval(() => {
if (Date.now() - this.lastMessageTime > this.watchdogTimeout) {
console.warn("[K线报警] 15秒没收到K线数据,强制重启底层WebSocket!");
if (this.ws) {
if (this.ws.socket) this.ws.socket.close();
this.ws.isReconnecting = false;
this.ws.manualClose = false;
this.ws.reconnect();
}
this.lastMessageTime = Date.now(); //
}
}, 5000);
},
stopWatchdog() {
if (this.watchdogTimer) {
clearInterval(this.watchdogTimer);
this.watchdogTimer = null;
}
},
// reconnect Socket.js
linkSocket(call) {
// WS
if (!this.ws) {
this.ws = new Socket(this.wsUrl);
// open线
this.ws.on("open", () => {
console.log("K线 WebSocket 连接/重连成功!");
//
if (call) {
call();
call = null; //
}
//
if (this.sub) {
this.ws.send({ cmd: "sub", msg: this.sub });
}
});
this.ws.on("message", (res) => {
let { data, sub, type, cmd } = res;
//
if (sub == this.sub || type == "ping" || cmd == "ping") {
this.lastMessageTime = Date.now();
}
if (sub == this.sub && this.onRealtimeCallback) {
if(sub.indexOf("BTC") != -1) (data.close).toFixed(1);
this.onRealtimeCallback(this.getMap(data));
bus.$emit('collapse', data);
} else if (type == "ping" || cmd == "ping") {
this.ws.send({ cmd: "pong" });
}
});
} else {
//
if (call) call();
if (this.ws.checkOpen() && this.sub) {
this.ws.send({ cmd: "sub", msg: this.sub });
}
}
this.startWatchdog(); //
},
//
unsub(pair_id, timer) {
let msgObj = {

Loading…
Cancel
Save