From a9709377bb20bac5f9cd15f6779d6c040617d74c Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 31 Oct 2026 12:13:57 +0800 Subject: [PATCH] fix(admin): make ticket "view latest" jump reliably Co-Authored-By: Claude Fable 5 --- assets/css/admin/tickets.css | 2 +- assets/js/admin-tickets.js | 35 +++++++++++++++----- src/Admin/Native/UsersMenusTicketsDetail.php | 2 +- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/assets/css/admin/tickets.css b/assets/css/admin/tickets.css index 66798b5f..aab900db 100644 --- a/assets/css/admin/tickets.css +++ b/assets/css/admin/tickets.css @@ -85,7 +85,7 @@ html.aksrt-ticket-modal-open { overflow: hidden; scrollbar-gutter: stable; } .aksrt-ticket-conversation > .aksrt-ticket-section-head { margin: 0; padding: 12px 16px; border-bottom: 1px solid var(--an-border-soft); } /* 会话时间线:用户在左、客服在右、系统事件居中。 */ -.aksrt-ticket-conversation__scroll { max-height: 52vh; padding: 20px 16px; overflow-y: auto; overscroll-behavior: contain; scroll-behavior: smooth; } +.aksrt-ticket-conversation__scroll { max-height: 52vh; padding: 20px 16px; overflow-y: auto; overscroll-behavior: contain; } .aksrt-ticket-detail__thread { display: flex; flex-direction: column; gap: 18px; margin: 0; padding: 0; list-style: none; } .aksrt-ticket-detail__message { display: flex; align-items: flex-start; gap: 10px; max-width: 86%; margin: 0; } .aksrt-ticket-detail__message.is-admin { flex-direction: row-reverse; align-self: flex-end; } diff --git a/assets/js/admin-tickets.js b/assets/js/admin-tickets.js index 2ff771e8..4cbc6538 100644 --- a/assets/js/admin-tickets.js +++ b/assets/js/admin-tickets.js @@ -126,6 +126,27 @@ active.querySelectorAll('[data-aksrt-ticket-assign]').forEach(function (button) { button.disabled = true; }); } + /** 会话已在底部或无需滚动时隐藏「查看最新记录」,避免点击无反应。 */ + function syncLatest() { + var conversation = panel.querySelector('.aksrt-ticket-conversation__scroll'); + var button = panel.querySelector('[data-aksrt-ticket-latest]'); + if (!conversation || !button) return; + button.hidden = conversation.scrollHeight - conversation.clientHeight - conversation.scrollTop <= 8; + } + + /** 会话内滚到底部;手动触发时同时让弹窗正文露出会话底部。 */ + function showLatest(manual) { + var conversation = panel.querySelector('.aksrt-ticket-conversation__scroll'); + if (!conversation) return; + conversation.scrollTop = conversation.scrollHeight; + if (manual) { + var gap = conversation.getBoundingClientRect().bottom - panel.getBoundingClientRect().bottom; + if (gap > 0) panel.scrollTop += gap; + conversation.focus({ preventScroll: true }); + } + syncLatest(); + } + function updateUrl(id, page) { var url = new URL(window.location.href); if (id) url.searchParams.set('id', String(id)); @@ -180,10 +201,7 @@ if (typeof data.list === 'string') list.innerHTML = data.list; updateUrl(id, data.page); setupForms(panel, restore); - if (message === strings.reply) { - var conversation = panel.querySelector('.aksrt-ticket-conversation__scroll'); - if (conversation) conversation.scrollTop = conversation.scrollHeight; - } + showLatest(false); stale = false; savedDrafts = {}; savedMessage = ''; @@ -260,11 +278,7 @@ syncStatus(statusForm); statusForm.querySelector('[type="submit"]').focus(); } - if (event.target.closest('[data-aksrt-ticket-latest]')) { - var conversation = panel.querySelector('.aksrt-ticket-conversation__scroll'); - conversation.scrollTop = conversation.scrollHeight; - conversation.focus(); - } + if (event.target.closest('[data-aksrt-ticket-latest]')) showLatest(true); }); root.addEventListener('input', function (event) { @@ -389,6 +403,9 @@ }); }); + // scroll 不冒泡,用捕获监听会话容器。 + panel.addEventListener('scroll', syncLatest, true); + window.addEventListener('beforeunload', function (event) { if (!saving && !dirty()) return; event.preventDefault(); diff --git a/src/Admin/Native/UsersMenusTicketsDetail.php b/src/Admin/Native/UsersMenusTicketsDetail.php index 040ee285..8a84575b 100644 --- a/src/Admin/Native/UsersMenusTicketsDetail.php +++ b/src/Admin/Native/UsersMenusTicketsDetail.php @@ -30,7 +30,7 @@ trait UsersMenusTicketsDetail { $html = '
'; $html .= '

' . esc_html__('沟通记录', 'aksrt') . ' ' . esc_html(sprintf(__('%d 条记录', 'aksrt'), count($replies))) . '

'; if ($replies !== []) { - $html .= ''; + $html .= ''; } $html .= '
    '; $html .= $this->ticket_message('origin', (int) $ticket['user_id'], (string) $ticket['user_name'], !empty($ticket['post_admin_id']) ? __('代客提交', 'aksrt') : __('提交了工单', 'aksrt'), (string) $ticket['post_time'], (string) $ticket['content'], (array) $ticket['attachment']);