declare let window: any; import moment from 'moment'; import { default as _ } from 'lodash'; import * as live_api from '@/api/live_api'; const updateStore: any = [ ['match_list_all', 'updateMatchListAll'], // ['match_list_fixture', 'updateMatchListFixture'], 赛程无开打比赛,不更新 ['match_list_result', 'updateMatchListResult'], ['match_list_attention', 'updateMatchListAttention'], ]; const paramList: any = [ // 初始化 { "type": "connection_init", "payload": {} }, // 请求数据 { "id": 1, "type": "start", "payload": { "query": "subscription{nm_live_message}", "variables": null } }, // 停止请求 { "id": 1, "type": "stop" } ]; function nm_live_message (context: any) { if (window.heartCheck) window.heartCheck.reset(); if (window.ws) { window.ws.close(); window.ws = null; } let id = moment().valueOf(); paramList[1].id = id; paramList[2].id = id; window.paramListId = id; let origin = window.location.origin; let wsUrl: any = null; if(origin.indexOf('https') > -1){ wsUrl = `wss://${window.location.host}/subscriptions`; }else{ wsUrl = 'ws://134.175.212.205/subscriptions'; } createWebSocket(wsUrl); function createWebSocket (url: any) { // 创建WebSocket 对象 , 判断当前浏览器是否支持WebSocket window.ws = new WebSocket(url, "graphql-ws"); // 连接成功时,触发事件 window.ws.onopen = () => { // console.log('【1-1】ws当前客户端可用!'); // 请求参数 window.ws.send(JSON.stringify(paramList[0])); }; // 接收到服务端响应的数据时,触发事件 window.ws.onmessage = (evt: any) => { let data = JSON.parse(evt.data); if (data.type == "connection_ack") { // console.log('【1-2】ws连接成功!'); // 开始检测心跳 // console.log('----------开始检测心跳'); window.heartCheck.start(); window.ws.send(JSON.stringify(paramList[1])); } if (data.type == "data") { // console.log('【2-1】ws接收数据!'); // 重置心跳 // console.log('----------重置心跳'); window.heartCheck.start(); if (!context.state.live_timer_switch) return; let new_live: any = {}; let liveData = _.clone(context.state.nm_live_message) || {}; let ws_live = data.payload.data.nm_live_message.list; let updateWsTime = data.payload.data.nm_live_message.update_time; if (context.state.updateWsTime && moment(updateWsTime).valueOf() < moment(context.state.updateWsTime).valueOf()) return; let d_time = moment(updateWsTime).valueOf() + 1000 - moment().valueOf(); context.commit('updateDifferenceTime', d_time); for (let i = 0; i < ws_live.length; i++) { let item = ws_live[i]; let id = item.id; if (!liveData[id]) liveData[id] = {}; // 比分更新 if (!liveData[id].score || (liveData[id].score && JSON.stringify(JSON.stringify(liveData[id].score)) !== JSON.stringify(JSON.stringify(item.score)))) { new_live[id] = item.score; } liveData[id] = item; } context.commit('updateNmLiveMessage', liveData); context.commit('updateUpdateWsTime', updateWsTime); // 更新赛事列表 updateMatchDate(context, new_live, d_time); } if (data.type == "complete") { // console.log('【3-1】ws已关闭!'); window.ws.close(); } }; window.ws.onerror = () => { // console.log("【1-3】ws连接错误!"); if (context.state.live_timer_switch) window.heartCheck.reconnect(); }; // 断开 web socket 连接成功触发事件 window.ws.onclose = (event: any) => { if (event.wasClean) { // console.log('【2-2】ws主动关闭!'); window.heartCheck.reset(); window.ws = null; } else { // console.log("【2-3】ws异常关闭!"); window.heartCheck.reconnect(); } }; } // 心跳检测 window.heartCheck = { timer: null, timer1: null, reset: () => { if (window.heartCheck.timer1) { clearTimeout(window.heartCheck.timer1); window.heartCheck.timer1 = null; } if (window.heartCheck.timer) { clearTimeout(window.heartCheck.timer); window.heartCheck.timer = null; } }, start: () => { window.heartCheck.reset(); window.heartCheck.timer = setTimeout(() => { // console.log('----------心跳检测超时'); window.ws.send(JSON.stringify(paramList[0])); window.heartCheck.timer1 = setTimeout(() => { // 如果超过一定时间还没重置,说明后端主动断开了 nm_live_message(context); }, 3000); }, 1 * 60 * 1000); }, reconnect: async () => { // 重连 10秒一次 window.heartCheck.reset(); // console.log('----------重新连接'); window.heartCheck.timer1 = setTimeout(async () => { await updateLive(context); nm_live_message(context); }, 10000); } }; } // 更新赛事列表 function updateMatchDate (context: any, new_live: any, d_time: any, init: any = false) { // init = true时,不更新高亮 只更新列表数据 try { for (let i = 0; i < updateStore.length; i++) { let keys: any = updateStore[i]; let match_list: any; if (updateStore[i][0] == 'match_list_attention') { let key = moment(context.state.server_time).format('YYYY-MM-DD'); match_list = _.clone(context.state[keys[0]][key]) || []; } else { match_list = _.clone(context.state[keys[0]]) || []; } if (Object.keys(new_live).length > 0 && match_list.length > 0) { let isChange = false, update_hl = false; let highLight = _.clone(context.state.high_light); for (let index = 0; index < match_list.length; index++) { let item = match_list[index]; // match_list.forEach((item: any) => { if (updateStore[i][0] == 'match_list_all' && item.status >= 8) break; let liveData = new_live[item?.id] || null; let is_type = []; if (liveData) { // 比赛状态 if (item.status != liveData[1]) { item.status = liveData[1]; isChange = true; } // 比分(常规时间) if (item.score[0] != liveData[2][0] || item.score[1] != liveData[3][0]) { // 取消进球未处理 if (liveData[1] < 5 && !init) { if (item.score[0] < liveData[2][0]) is_type.push({ type: 'score', ranks: 0 }); else if (item.score[1] < liveData[3][0]) is_type.push({ type: 'score', ranks: 1 }); } item.score = [liveData[2][0], liveData[3][0]]; isChange = true; } // 半场比分 if (item.half[0] != liveData[2][1] || item.half[1] != liveData[3][1]) { item.half = [liveData[2][1], liveData[3][1]]; isChange = true; } // 红牌 if (item.red_card[0] != liveData[2][2] || item.red_card[1] != liveData[3][2]) { if (liveData[1] < 5 && !init) { if (item.red_card[0] < liveData[2][2]) is_type.push({ type: 'red', ranks: 0 }); else if (item.red_card[1] < liveData[3][2]) is_type.push({ type: 'red', ranks: 1 }); } item.red_card = [liveData[2][2], liveData[3][2]]; isChange = true; } // 黄牌 if (item.yellow_card[0] != liveData[2][3] || item.yellow_card[1] != liveData[3][3]) { if (liveData[1] < 5 && !init) { if (item.yellow_card[0] < liveData[2][3]) is_type.push({ type: 'yellow', ranks: 0 }); else if (item.yellow_card[1] < liveData[3][3]) is_type.push({ type: 'yellow', ranks: 1 }); } item.yellow_card = [liveData[2][3], liveData[3][3]]; isChange = true; } // 角球,-1表示没有角球数据; if ((liveData[2][4] > -1 && item.corner_kicks[0] != liveData[2][4]) || (liveData[3][4] > -1 && item.corner_kicks[1] != liveData[3][4])) { item.corner_kicks = [liveData[2][4], liveData[3][4]]; isChange = true; } // 加时比分(120分钟,即包括常规时间比分),加时赛才有 if (item.score_all[0] != liveData[2][5] || item.score_all[1] != liveData[3][5]) { item.score_all = [liveData[2][5], liveData[3][5]]; isChange = true; } // 点球大战比分(不包含常规时间及加时赛比分),点球大战才有 if (item.score_point[0] != liveData[2][6] || item.score_point[1] != liveData[3][6]) { item.score_point = [liveData[2][6], liveData[3][6]]; isChange = true; } } if (is_type.length > 0) { update_hl = true; for (let x = 0; x < is_type.length; x++) { let iItem = is_type[x]; let itemData = _.clone(item); itemData.time = moment().valueOf() + d_time; itemData.ranksBackground = iItem.ranks; highLight[iItem.type][item.id] = itemData; } } match_list[index] = item; } // }); if (isChange) { // console.log('更新列表'); if (updateStore[i][0] == 'match_list_attention') { let key = moment(context.state.server_time).format('YYYY-MM-DD'); let obj = _.clone(context.state[keys[0]]); obj[key] = match_list; context.commit(keys[1], obj); } else { context.commit(keys[1], match_list); } } // console.log('更新高亮'); if (update_hl) context.commit('updateHighLight', highLight); } } } catch (error) { console.info('【updateMatchDate】:' + error); } } // 初始化列表(初始化 | ws异常重连 | 主动断开ws重启) async function updateLiveDate (context: any) { try { if (context.state.init) { // 有本地存储 // 列表更新 if (context.state.match_list_all?.length < 50) { await updateListAll(context, true); } else if (!context.state.updateListTime || moment(context.state.updateListTime).add(1, 'days') < moment(context.state.server_time)) { // 超过一天 await updateListAll(context); } else { await updateNewList(context); } // async loading other data const timer = setTimeout(async() => { // ws更新(测试 6 小时更新) if (!context.state.updateWsTime || moment(context.state.updateWsTime).add(6, 'h') < moment(context.state.server_time)) { // 超过2小时 context.commit('updateInit', false); context.commit('updateNmLiveMessage', {}); await updateListAddLive(context); } else { // 2小时以内 await updateLive(context); } if (context.state.match_list_all_cache) { context.commit('updateMatchListAllCache', []); context.commit('updateNmLiveMessageCache', {}); } clearTimeout(timer); }, 1); } else { // 无本地存储 await updateListAddLive(context); } } catch (error) { console.info('【updateLiveDate】:', error); } } // 更新ws(本地ws数据未超过2小时更新) async function updateLive (context: any) { try { let nm_match_live: any = await live_api.nm_match_live(); if (nm_match_live?.data?.data?.nm_match_live) { let data = nm_match_live.data.data.nm_match_live; let liveData = _.clone(context.state.nm_live_message) || {}; let ws_live = data.list; let new_live: any = {}; for (let i = 0; i < ws_live.length; i++) { let item = ws_live[i]; let id = item.id || null; if (!id) continue; if (!liveData[id]) liveData[id] = {}; // 比分更新 if (!liveData[id].score || (liveData[id].score && JSON.stringify(JSON.stringify(liveData[id].score)) !== JSON.stringify(JSON.stringify(item.score)))) { new_live[id] = item.score; } liveData[id] = item; } let updateWsTime = data.update_time; let d_time = moment(updateWsTime).valueOf() + 1000 - moment().valueOf(); context.commit('updateNmLiveMessage', liveData); context.commit('updateDifferenceTime', d_time); context.commit('updateUpdateWsTime', updateWsTime); updateMatchDate(context, new_live, d_time, true); } } catch (error) { console.info('【updateLive】:', error); } } // 排序 const gameSort = (arr: any) => { const order_end: any = { 8: 1, 9: 2, 10: 3, 11: 4, 12: 5, 13: 6, 0: 7 }; return arr.sort((a: any, b: any) => { const aSortIndex = order_end[a.status] || 0; const bSortIndex = order_end[b.status] || 0; return aSortIndex - bSortIndex || a.match_time - b.match_time; }); }; // 更新list(下拉刷新 | 本地列表数据超过1天时重置) async function updateListAll (context: any, isError: any = false) { if (window.getListAll) return; if (isError) window.getListAll = true; try { if (!isError && context.state.updateListTime && moment(context.state.updateListTime).add(2, 'h') > moment(context.state.server_time)) { await updateNewList(context); } else { let game_list_date: any = await live_api.nm_match_list({}); if (game_list_date?.data?.data?.nm_match_list?.length > 0) { let nm_match_list: any = gameSort(game_list_date.data.data.nm_match_list); context.commit('updateMatchListAll', nm_match_list); context.commit('updateUpdateListTime', moment(context.state.server_time).format('YYYY-MM-DD HH:mm:ss')); } } await correctLiveAttention(context); window.repairrReset = true; window.getListAll = false; } catch (error) { window.getListAll = false; console.info('【updateListAll】:', error); } } // 更新list&ws(初始化 | 本地ws数据超过2小时重置) async function updateListAddLive (context: any) { let p1: any = live_api.nm_match_list({}); let p2: any = live_api.nm_match_live(); try { Promise.all([p1, p2]).then(async (result: any) => { let [game_list_date, nm_match_live] = result; if (game_list_date?.data?.data?.nm_match_list?.length > 0) { let nm_match_list: any = gameSort(game_list_date.data.data.nm_match_list); context.commit('updateMatchListAll', nm_match_list); context.commit('updateUpdateListTime', moment(context.state.server_time).format('YYYY-MM-DD HH:mm:ss')); await correctLiveAttention(context); } if (nm_match_live?.data?.data?.nm_match_live) { let data = nm_match_live.data.data.nm_match_live; let liveData = _.clone(context.state.nm_live_message) || {}; let ws_live = data.list; let new_live: any = {}; for (let i = 0; i < ws_live.length; i++) { let item = ws_live[i]; let id = item.id; if (!liveData[id]) liveData[id] = {}; // 比分更新 if (!liveData[id].score || (liveData[id].score && JSON.stringify(JSON.stringify(liveData[id].score)) !== JSON.stringify(JSON.stringify(item.score)))) { new_live[id] = item.score; } liveData[id] = item; } let updateWsTime = data.update_time; let d_time = moment(updateWsTime).valueOf() + 1000 - moment().valueOf(); context.commit('updateNmLiveMessage', liveData); context.commit('updateDifferenceTime', d_time); context.commit('updateUpdateWsTime', updateWsTime); updateMatchDate(context, new_live, d_time, true); } context.commit('updateInit', true); window.repairrReset = true; }); } catch (error) { console.info('【updateListAddLive】:', error); } } // 单场赛事修复数据 window.repairSingle = async function (context: any, id: any) { let timer: any; if (window.repairrReset) { window.repairSingleingArr = []; window.repairSingleing = false; window.repairrReset = false; clearTimeout(timer); timer = null; return; } if (!window.repairSingleingArr) window.repairSingleingArr = []; if (!window.repairSingleingArr.includes(id)) window.repairSingleingArr.push(id); if (window.repairSingleing) return; window.repairSingleing = true; timer = setTimeout(async () => { try { let game_list_date: any = await live_api.nm_match_list({ is_sample: 1 }); if (game_list_date?.data?.data?.nm_match_list?.length > 0) { let list = game_list_date.data.data.nm_match_list; let match_list_all = _.clone(context.state.match_list_all); // console.log('单场赛事修复数据', window.repairSingleingArr); for (let i = 0; i < match_list_all.length; i++) { let id = match_list_all[i].id || null; if (id && window.repairSingleingArr.includes(id)) { match_list_all[i] = _.find(list, { id }); } } match_list_all = gameSort(match_list_all); window.repairSingleingArr = []; window.repairSingleing = false; context.commit('updateMatchListAll', match_list_all); if (context.state.attention_id_list.inCludes(id)) correctLiveAttention(context); } else { window.repairSingleing = false; } } catch (error) { window.repairSingleing = false; console.info('【repairSingle】:', error); } clearTimeout(timer); timer = null; }, 5000); }; // 更正关注赛事 async function correctLiveAttention (context: any) { try { // 登录且有关注赛事 if (context.state.attention_id_list.length > 0) { let match_list_attention = _.clone(context.state.match_list_attention); if (JSON.stringify(match_list_attention) == '{}') return; let list = _.clone(context.state.match_list_all); let delArr = []; for (let i = 0; i < Object.keys(match_list_attention).length; i++) { let key = Object.keys(match_list_attention)[i]; let item = match_list_attention[key]; let isDel = item.length > 0 ? false : true; for (let a = 0; a < item.length; a++) { let id = item[a].id; let item_a = _.find(list, { id }); if (!item_a) isDel = true; else item[a] = item_a; } if (isDel) delArr.push(key); } for (let y = 0; y < delArr.length; y++) { delete match_list_attention[delArr[y]]; } context.commit('updateMatchListAttention', match_list_attention); } } catch (error) { console.info('【correctLiveAttention】:', error); } } // 更新最近几个小时的赛事 async function updateNewList (context: any) { try { let game_list_date: any = await live_api.nm_match_list({ is_sample: 1 }); if (game_list_date?.data?.data?.nm_match_list?.length > 0) { let game_list = game_list_date.data.data.nm_match_list; for (let i = 0; i < updateStore.length; i++) { let keys: any = updateStore[i]; let match_list: any; if (updateStore[i][0] == 'match_list_attention') { let key = moment(context.state.server_time).format('YYYY-MM-DD'); match_list = _.clone(context.state[keys[0]][key]) || []; } else { match_list = _.clone(context.state[keys[0]]) || []; } if (match_list.length < 1) continue; for (let x = 0; x < match_list.length; x++) { let id = match_list[x]?.id || null; if (!id) continue; let newData = _.find(game_list, { id }); if (newData) match_list[x] = newData; } if (updateStore[i][0] == 'match_list_attention') { let key = moment(context.state.server_time).format('YYYY-MM-DD'); let obj = _.clone(context.state[keys[0]]); obj[key] = match_list; context.commit(keys[1], obj); } else { context.commit(keys[1], match_list); } } } window.repairrReset = true; } catch (error) { console.info('【updateNewList】:' + error); } } export { nm_live_message, updateMatchDate, updateLiveDate, updateListAll };