From 30fcde57440391e36b8772d3a1f0383d95104c398fac2242826db555d1c5e3b5 Mon Sep 17 00:00:00 2001 From: AidarKC Date: Fri, 17 Apr 2026 21:18:03 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D1=82=D0=BE=D1=87=D0=BD=D1=91=D0=BD=20?= =?UTF-8?q?=D1=82=D0=B5=D1=80=D0=BC=D0=B8=D0=BD=20close=20friend=20=D0=B8?= =?UTF-8?q?=20=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=20UX=20=D1=81?= =?UTF-8?q?=D0=B2=D1=8F=D0=B7=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Что сделано:\n- В UI возвращён термин «Близкий друг» без пометки про «друга».\n- На графе связей добавлено меню узла с двумя действиями: «Показать информацию» и «Показать связи» (перенос узла в центр).\n- В модалке добавления связи реализован автопоиск логинов: Enter или пауза 2 секунды, до 5 подсказок, выбор кликом.\n- Добавлены стили для меню узла и списка подсказок.\n- В коде добавлены явные пояснения и alias-константы close friend (без изменения кодов 10/11 и логики):\n CONNECTION_CLOSE_FRIEND / CONNECTION_UNCLOSE_FRIEND.\n- Обработчики чтения/записи связей переключены на alias close friend для лучшей читаемости. --- shine-UI/js/pages/network-view.js | 20 ++- shine-UI/js/pages/profile-view.js | 138 +++++++++++++++++- shine-UI/js/services/auth-service.js | 2 + shine-UI/styles/components.css | 40 +++++ .../src/main/java/blockchain/MsgSubType.java | 9 +- .../java/shine/db/DatabaseInitializer.java | 3 + .../src/main/java/shine/db/MsgSubType.java | 14 +- .../Net_AddCloseFriend_Handler.java | 2 +- .../Net_GetFriendsLists_Handler.java | 2 +- .../Net_GetUserConnectionsGraph_Handler.java | 4 +- 10 files changed, 213 insertions(+), 21 deletions(-) diff --git a/shine-UI/js/pages/network-view.js b/shine-UI/js/pages/network-view.js index b831b71..8b840bc 100644 --- a/shine-UI/js/pages/network-view.js +++ b/shine-UI/js/pages/network-view.js @@ -366,7 +366,7 @@ export function render({ navigate }) { const legend = document.createElement('div'); legend.className = 'network-legend'; legend.innerHTML = ` - Друзья + Близкие друзья Родственники Односторонняя связь `; @@ -386,7 +386,12 @@ export function render({ navigate }) { closeNodeMenu(); const menu = document.createElement('div'); menu.className = 'node-menu card'; - menu.innerHTML = ''; + menu.innerHTML = ` +
+ + +
+ `; const rect = node.getBoundingClientRect(); const boardRect = board.getBoundingClientRect(); @@ -396,11 +401,16 @@ export function render({ navigate }) { menu.style.left = `${Math.max(8, Math.min(x - 120, boardRect.width - 248))}px`; menu.style.top = `${Math.max(8, Math.min(y, boardRect.height - 58))}px`; - const btn = menu.querySelector('button'); - btn?.addEventListener('click', () => { + const infoBtn = menu.querySelector('[data-menu-action="show-info"]'); + const graphBtn = menu.querySelector('[data-menu-action="show-graph"]'); + infoBtn?.addEventListener('click', () => { navigate(`user-profile-view/${encodeURIComponent(login)}/network-view`); closeNodeMenu(); }); + graphBtn?.addEventListener('click', async () => { + closeNodeMenu(); + await load(login); + }); board.append(menu); activeMenu = menu; @@ -485,7 +495,7 @@ export function render({ navigate }) { redrawEdges = () => renderEdges(svg, board, nodeElements, layout.edges); requestAnimationFrame(() => redrawEdges()); - note.textContent = 'Тап: информация о пользователе. Долгое нажатие: сделать узел центром. Линия = взаимно, стрелка = в одну сторону.'; + note.textContent = 'Тап по узлу: меню «Показать информацию» или «Показать связи». Долгое нажатие: сделать узел центром.'; } catch (error) { if (requestId !== loadSeq) return; note.textContent = `Ошибка загрузки связей: ${error?.message || 'unknown'}`; diff --git a/shine-UI/js/pages/profile-view.js b/shine-UI/js/pages/profile-view.js index 0bfa2f1..fd1a8a2 100644 --- a/shine-UI/js/pages/profile-view.js +++ b/shine-UI/js/pages/profile-view.js @@ -305,7 +305,6 @@ export function render({ navigate }) { const uniqueContacts = Array.from(new Set(preparedContacts.map((item) => item.toLowerCase()))) .map((key) => preparedContacts.find((item) => item.toLowerCase() === key)) .filter(Boolean); - const datalistId = `profile-relative-contacts-${Math.random().toString(16).slice(2, 9)}`; root.innerHTML = `