From f9daee67bf7a214435960fc6a12f08387f1e5cc2 Mon Sep 17 00:00:00 2001 From: Caffeine Date: Sun, 13 Sep 2026 18:49:32 +0300 Subject: [PATCH] =?UTF-8?q?feat(front):=20=D1=83=D0=B1=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BC=D1=91=D1=80=D1=82=D0=B2=D0=B0=D1=8F=20=D0=BA?= =?UTF-8?q?=D0=BD=D0=BE=D0=BF=D0=BA=D0=B0=20/close,=20=D1=81=D0=BE=D0=B1?= =?UTF-8?q?=D1=8B=D1=82=D0=B8=D1=8F=20=D1=81=D1=82=D0=B0=D0=B2=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=BF=D0=BE=20WebSocket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - блок «Закрытие (POST /close)» -> «Ставка: ход игры»: № ставки, состояние, вход/выход - ручка /close удалена на сервере (404) -> кнопка и gwClose() убраны - ws.onmessage разбирает bet_open / bet_closed: ставка показывается и рассчитывается сама, сервер закрывает её без участия клиента --- index.html | 61 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/index.html b/index.html index 0877dc1..5e0bb0a 100644 --- a/index.html +++ b/index.html @@ -100,12 +100,18 @@
- Закрытие (POST /close) + Ставка: ход игры (сервер закрывает сам)
- - - id заполнится после ставки, либо введите вручную + № ставки: — + состояние: нет ставки
+
+ вход: — + выход: — +
+
Ставку открывает кнопка «Сделать ставку» (HTTP). Итог приходит сам по WebSocket: + bet_open — ставка принята, bet_closed — рассчитана (примерно через 15 с). + Пока ставка открыта, вторую на этот адрес сервер не примет.
@@ -225,7 +231,11 @@ function useWalletAddr(){ log.info('Адрес «'+w+'» подставлен в поле «Адрес» (для ставки и баланса)'); } -let lastBetId = ''; +let liveBetId = ''; +function setLiveBet(field, value){ + const el = document.getElementById(field); + if(el) el.textContent = value; +} async function gwBet(){ try{ const side = document.getElementById('betSide').value; @@ -239,24 +249,33 @@ async function gwBet(){ const address = ADDR(); log.info('POST /bet side='+side+', amountUnits='+units.toString()+(address?' (address='+address+')':' (адрес пуст — шлюз сгенерит новый кошелёк)')); const j = await gwFetch('/bet', {side:side, amountUnits:units.toString(), address:address}); - lastBetId = String(j.id); - document.getElementById('closeId').value = lastBetId; + liveBetId = String(j.id); + setLiveBet('liveBetId', liveBetId); + setLiveBet('liveBetState', 'открыта, ждём закрытия (~15 с)'); + setLiveBet('liveBetEntry', String(j.entryPrice)); + setLiveBet('liveBetExit', '—'); log.ok('Ставка принята: id='+j.id+', bettor='+j.bettor+', entryPrice='+j.entryPrice+(j.tx?' tx='+j.tx:'')); if(!address) log.info('кошелёк шлюза: '+j.bettor+' (скопируйте в поле «Адрес» для дальнейших ставок)'); }catch(e){ log.err('bet: '+e.message); } } -async function gwClose(){ - try{ - const id = document.getElementById('closeId').value.trim(); - if(!id){ log.err('close: нет id ставки (сначала сделайте ставку или введите id вручную)'); return; } - const j = await gwFetch('/close', {id:id}); - const label = {payout_done:'ВЫИГРАЛ (payout_done)', house_won:'ПРОИГРАЛ (house_won)', open:'открыт (open)'}[j.statusName] || ('status='+j.statusName); - const detail = 'exitPrice='+j.exitPrice+(j.note?' — '+j.note:''); - if(j.statusName==='payout_done') log.ok('Закрыт #'+id+': '+label+', '+detail); - else if(j.statusName==='house_won') log.err('Закрыт #'+id+': '+label+', '+detail); - else log.info('Закрыт #'+id+': '+label+', '+detail); - }catch(e){ log.err('close: '+e.message); } +/** Событие WS: ставка открыта. */ +function onBetOpen(m){ + setLiveBet('liveBetId', String(m.id)); + setLiveBet('liveBetState', 'открыта ('+m.side+'), ждём закрытия'); + setLiveBet('liveBetEntry', String(m.entryPrice)); + setLiveBet('liveBetExit', '—'); + log.info('bet_open: #'+m.id+' '+m.side+', сумма='+m.amountUnits+', вход='+m.entryPrice); +} + +/** Событие WS: ставка рассчитана — сервер закрыл её сам. */ +function onBetClosed(m){ + setLiveBet('liveBetId', String(m.id)); + const won = m.statusName === 'payout_done'; + setLiveBet('liveBetState', won ? 'ВЫИГРАЛ (payout_done)' : 'ПРОИГРАЛ (house_won)'); + setLiveBet('liveBetExit', String(m.exitPrice)); + const text = 'bet_closed: #'+m.id+', выход='+m.exitPrice+', '+(won?'ВЫИГРАЛ':'ПРОИГРАЛ'); + if(won) log.ok(text); else log.err(text); } function copyLog(){ const t=document.getElementById('log').innerText; navigator.clipboard?.writeText(t).then(()=>log.ok('лог скопирован')).catch(()=>{}); } @@ -338,7 +357,11 @@ function connectWs(){ ws.onmessage = (ev) => { let m; try{ m = JSON.parse(ev.data); }catch(e){ return; } - if(!m || m.type !== 'price') return; + if(!m || !m.type) return; + // Клиентские события жизненного цикла ставки — сервер закрывает ставку сам. + if(m.type === 'bet_open'){ onBetOpen(m); return; } + if(m.type === 'bet_closed'){ onBetClosed(m); return; } + if(m.type !== 'price') return; wsMsgCount++; document.getElementById('wsMsgCount').textContent = String(wsMsgCount); const fullPrice = String(m.price);