Hệ thống pháp luật

BẢO HIỂM XÃ HỘI VIỆT NAM
-------

CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM
Độc lập - Tự do - Hạnh phúc
---------------

Số: 3452/BHXH-CSYT
V/v triển khai thực hiện Nghị định số 75/2023/NĐ-CP

Hà Nội, ngày 24 tháng 10 năm 2023

 

Kính gửi:

- Bảo hiểm xã hội tỉnh, thành phố trực thuộc Trung ương;
- Bảo hiểm xã hội Bộ Quốc phòng;
- Bảo hiểm xã hội Công an nhân dân.
(sau đây gọi chung là Bảo hiểm xã hội các tỉnh)

Ngày 23/10/2023, Bảo hiểm xã hội (BHXH) Việt Nam nhận được Nghị định số 75/2023/NĐ-CP ngày 19/10/2023 của Chính phủ sửa đổi, bổ sung một số điều của Nghị định số 146/2018/NĐ-CP ngày 17 tháng 10 năm 2018 của Chính phủ quy định chi tiết và hướng dẫn biện pháp thi hành một số điều của Luật Bảo hiểm y tế (BHYT). Để kịp thời triển khai thực hiện Nghị định số 75/2023/NĐ-CP, BHXH Việt Nam đề nghị BHXH các tỉnh thực hiện một số nội dung như sau:

1. Cấp thẻ, đổi thẻ BHYT theo quy định tại Nghị định số 75/2023/NĐ-CP

1.1. Chuyển đổi mã mức hưởng BHYT theo quy định tại khoản 5 Điều 1 Nghị định số 75/2023/NĐ-CP, cụ thể:

- Đổi mức hưởng BHYT từ mã 4 sang mã 2 đối với Người tham gia kháng chiến và bảo vệ Tổ quốc (có mã đối tượngkhoản 5 Điều 3 Nghị định số 146/2018/NĐ-CP.

- Đổi mức hưởng BHYT từ mã 4 sang mã 3 đối với Người phục vụ người có công với cách mạng sống ở gia đình (có mã đối tượng PV) quy định tại khoản 19 Điều 3 Nghị định số 146/2018/NĐ-CP1.2. Bổ sung mã đối tượng và mã mức hưởng BHYT ghi trên thẻ BHYT đối với người tham gia BHYT mới được quy định tại Nghị định số 75/2023/NĐ-CP và Nghị định số 131/2021/NĐ-CP

Trong thời gian chờ sửa đổi, bổ sung Quyết định số 1351/QĐ-BHXH ngày 16/11/2015 của Tổng Giám đốc BHXH Việt Nam quy định về mã số ghi trên thẻ BHYT, BHXH các tỉnh phối hợp với đơn vị quản lý đối tượng rà soát, lập danh sách và cấp thẻ BHYT của các đối tượng được bổ sung tại Nghị định 75/2023/NĐ-CP, như sau:

- Vợ hoặc chồng liệt sĩ lấy chồng hoặc vợ khác đang hưởng trợ cấp hằng tháng theo quy định tại điểm a khoản 10 Điều 16 của Pháp lệnh ưu đãi người có công với cách mạng- Người dân các xã an toàn khu, vùng an toàn khu cách mạng trong kháng chiến chống Pháp và chống Mỹ hiện đang thường trú tại các xã an toàn khu cách mạng trong kháng chiến chống Pháp và chống Mỹ đã được cập nhật thông tin trong Cơ sở dữ liệu quốc gia về dân cư, Cơ sở dữ liệu về cư trú- Người dân tộc thiểu số đang sinh sống tại địa bàn các xã khu vực II, khu vực III, thôn đặc biệt khó khăn thuộc vùng đồng bào dân tộc thiểu số và miền núi giai đoạn 2016-2020 mà các xã này không còn trong danh sách các xã khu vực II, khu vực III, thôn đặc biệt khó khăn thuộc vùng đồng bào dân tộc thiểu số và miền núi giai đoạn 2021-2025 theo quyết định của Thủ tướng Chính phủ1.3. Trường hợp người tham gia BHYT đồng thời thuộc nhiều đối tượng khác nhau, BHXH các tỉnh rà soát, đối chiếu dữ liệu đang quản lý với các trường hợp có tên trong hồ sơ đổi mức hưởng và danh sách đối tượng đổi thẻ mới, nếu thẻ BHYT cũ cấp theo đối tượng khác có mức hưởng thấp hơn so với quy định mới, thì theo mức hưởng cao nhất.

2. Thủ tục KCB BHYT thực hiện theo quy định sửa đổi, bổ sung tại khoản 6 Điều 1 Nghị định số 75/2023/NĐ-CP:

Người tham gia BHYT khi KCB phải xuất trình thẻ BHYT có ảnh hoặc căn cước công dân; trường hợp xuất trình thẻ BHYT chưa có ảnh thì phải xuất trình thêm một trong các giấy tờ tùy thân có ảnh do cơ quan, tổ chức có thẩm quyền cấp hoặc giấy xác nhận của công an cấp xã hoặc giấy tờ khác có xác nhận của cơ sở giáo dục nơi quản lý học sinh, sinh viên; các giấy tờ chứng minh nhân thân hợp pháp khác hoặc giấy tờ được định danh điện tử mức độ 2 theo quy định tại Nghị định số 59/2022/NĐ-CP ngày 05 tháng 9 năm 2022 của Chính phủ quy định về định danh và xác thực điện tử.

3. Thanh toán chi phí KCB BHYT trong giai đoạn chuyển tiếp thực hiện theo quy định tại Điều 4 Nghị định số 75/2023/NĐ-CP:

Người tham gia bảo hiểm y tế vào cơ sở khám bệnh, chữa bệnh để điều trị trước ngày Nghị định này có hiệu lực nhưng ra viện từ ngày Nghị định này có hiệu lực thì được quỹ bảo hiểm y tế thanh toán trong phạm vi được hưởng và mức hưởng theo quy định của Luật Bảo hiểm y tế, theo quy định tại các điểm b, c, d, đ, g và h khoản 1, các khoản 2, 3, 4 và 5 Điều 14 Nghị định số 146/2018/NĐ-CP và quy định tại khoản 5 Điều 1 Nghị định này.

4. Tổ chức thực hiện

4.1. BHXH các tỉnh chủ động phối hợp với các Sở, ngành, các đơn vị liên quan tại địa phương rà soát, cấp thẻ BHYT, chuyển đổi mã mức hưởng BHYT đúng đối tượng và thực hiện các quy định tại Nghị định số 75/2023/NĐ-CP.

4.2. Trung tâm Công nghệ thông tin hỗ trợ BHXH các tỉnh đáp ứng việc cấp thẻ, chuyển đổi mã mức hưởng BHYT theo hướng dẫn tại văn bản này.

Yêu cầu Thủ trưởng các đơn vị trực thuộc BHXH Việt Nam, Giám đốc BHXH các tỉnh tổ chức thực hiện, trong quá trình thực hiện nếu có vướng mắc, kịp thời báo cáo BHXH Việt Nam xem xét, giải quyết./.

 


Nơi nhận:
- Như trên;
- Văn phòng Chính phủ;
- Bộ Y tế, Bộ Tài chính;
- UBND các tỉnh, thành phố trực thuộc Trung ương;
- Tổng Giám đốc (để b/c);
- Các Phó Tổng Giám đốc;
- Các đơn vị trực thuộc BHXH VN (để t/h);
- Lưu: VT, CSYT.

KT. TỔNG GIÁM ĐỐC
PHÓ TỔNG GIÁM ĐỐC




Nguyễn Đức Hòa

 



lồng nhau (bên trong) hay không const memberID = 0; const vbID = '91b640bff292a9429c8bd13d40720250'; // State management cho phân tích let isAnalyzing = false; // Có đang phân tích không let currentAnalyzingAddress = null; // Address đang được phân tích let currentAnalyzingElement = null; // Element đang được phân tích let currentAnalyzingBadge = null; // Badge của element đang phân tích console.log('Tiện ích loaded - memberID:', memberID, 'vbID:', vbID); function isInViewportAndTabNoiDung(element) { const rect = element.getBoundingClientRect(); const buffer = 1500; // Buffer to preload content below the viewport (approx. 50+ lines) const viewHeight = window.innerHeight || document.documentElement.clientHeight; const isInViewport = rect.top < viewHeight + buffer && rect.bottom >= 0; const isInTabNoiDung = $(element).closest('#tab_noi_dung_vb').length > 0; return isInViewport && isInTabNoiDung; } function getAddress(element) { const validTags = ['trichyeu', 'cancu', 'phan', 'chuong', 'muc', 'tieumuc', 'dieu', 'khoan', 'diem']; const $parent = $(element).closest(validTags.join(',')); if (!$parent.length) { return null; } let addr = $parent.attr('address'); if (!addr && $parent.prop('tagName').toLowerCase() === 'trichyeu') { addr = 'trichyeu'; $parent.attr('address', addr); } return addr || null; } function processTnplClasses($element) { const tnplKeysInLine = new Set(); // key = slug hoặc text (thường là slug) $element.find('tnpl').each(function () { const $tnpl = $(this); const tnplSlug = ($tnpl.attr('slug') || '').trim().toLowerCase(); const tnplKey = tnplSlug || $tnpl.text().trim().toLowerCase(); // Đã xử lý trong cùng dòng => bỏ if (tnplKeysInLine.has(tnplKey)) { return; } tnplKeysInLine.add(tnplKey); let tnplExists = false; // Chỉ duyệt các tnpl đã được tô màu (class on) $('tnpl.on').each(function () { const $existingTnpl = $(this); const existingSlug = ($existingTnpl.attr('slug') || '').trim().toLowerCase(); const existingKey = existingSlug || $existingTnpl.text().trim().toLowerCase(); if ( existingKey === tnplKey && isInViewportAndTabNoiDung($existingTnpl[0]) ) { tnplExists = true; return false; // break each } }); if (!tnplExists) { $tnpl.addClass('on'); } }); } function processQueue() { while (pendingRequests < maxConcurrentRequests && requestQueue.length > 0) { const task = requestQueue.shift(); pendingRequests++; task() .always(() => { pendingRequests--; processQueue(); }); } } function processVisibleParagraphs() { try { $('#tab_noi_dung_vb p:not([is-posted="1"])').each(function () { let $element = $(this); if (isInViewportAndTabNoiDung(this)) { $element.attr('is-posted', '1'); $element.addClass('loading-content'); let p_innerHTML = $element.html(); let address = null; if (cac_cau_hinh.loai_noi_dung.includes('docs')) { address = getAddress($element); } const isSubP = $element.parents('p').length > 0; if (isSubP && !allow_sub_p) { $element.removeClass('loading-content'); return; // Không gửi nếu không cho phép } const postData = { p_content: p_innerHTML, cac_cau_hinh, address }; if (isSubP && allow_sub_p) { postData.sub_p = 1; } requestQueue.push(() => $.ajax({ url: '//tnpl' + (Math.floor(Math.random() * 10) + 1) + '.hethongphapluat.com/tien-ich/tim.tien.ich.php', type: 'POST', data: postData, success: function(response) { $element.html(response); processTnplClasses($element); // Đợi CTTD và các tiện ích load xong rồi mới attach badge if (memberID === 4 && typeof attachPhanTichBadge === 'function') { setTimeout(function() { // $element chính là thẻ p, kiểm tra và attach badge trực tiếp const $parent = $element.closest('phan, chuong, muc, tieumuc, dieu, khoan, diem'); if ($parent.length > 0 && $parent.find('.badge-phan-tich[data-for="' + $parent.attr('address') + '"]').length === 0) { const address = $parent.attr('address'); $element.attr('data-address', address); // Lấy tên loại thẻ cho tooltip const parentType = getParentTypeName($parent.prop('tagName').toLowerCase()); // Append badge VÀO PARENT (dieu, khoan,...) thay vì vào

để tránh xung đột CTTD const $badge = $('Phân tích'); $parent.append($badge); // Thêm class để CSS set position: relative CHỈ cho element có badge $parent.addClass('has-phan-tich-badge'); } // Xử lý các p con (nếu có sub-p) attachPhanTichBadge($element); }, 300); // Đợi 300ms để CTTD render xong } }, complete: function() { $element.removeClass('loading-content'); } }) ); processQueue(); } }); } catch(e) { console.error('Lỗi processVisibleParagraphs:', e); } } $(window).on('scroll resize', function () { processVisibleParagraphs(); }); console.log('Bắt đầu processVisibleParagraphs lần đầu...'); processVisibleParagraphs(); console.log('processVisibleParagraphs lần đầu hoàn thành'); // Chức năng phân tích điều luật (chỉ cho member_id = 4) if (memberID === 4) { // Modal cảnh báo function showWarningModal(message) { // Tạo modal nếu chưa có if ($('#warningModal').length === 0) { const modalHTML = `

`; $('body').append(modalHTML); } $('#warningModalBody').html('

' + message + '

'); $('#warningModal').modal('show'); } // Hàm lấy tên tiếng Việt của thẻ function getParentTypeName(tagName) { const typeNames = { 'phan': 'Phần', 'chuong': 'Chương', 'muc': 'Mục', 'tieumuc': 'Tiểu mục', 'dieu': 'Điều', 'khoan': 'Khoản', 'diem': 'Điểm' }; return typeNames[tagName] || 'Nội dung'; } function attachPhanTichBadge($container) { const validTags = 'phan, chuong, muc, tieumuc, dieu, khoan, diem'; $container.find('p').each(function() { const $p = $(this); const $parent = $p.closest(validTags); if ($parent.length > 0) { const address = $parent.attr('address'); // Kiểm tra đã có badge cho parent này chưa if ($parent.find('.badge-phan-tich[data-for="' + address + '"]').length === 0) { // Lưu address vào data attribute $p.attr('data-address', address); // Lấy tên loại thẻ cho tooltip const parentType = getParentTypeName($parent.prop('tagName').toLowerCase()); // Append badge vào PARENT, không vào

const $badge = $('Phân tích'); $parent.append($badge); // Thêm class để CSS set position: relative CHỈ cho element có badge $parent.addClass('has-phan-tich-badge'); } } }); } // Helper: Escape HTML entities function escapeHtml(text) { const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return String(text).replace(/[&<>"']/g, function(m) { return map[m]; }); } // Helper: Convert Markdown to HTML (đơn giản) function markdownToHtml(markdown) { if (!markdown) return ''; let html = markdown; // Headers html = html.replace(/^### (.*$)/gim, '

$1
'); html = html.replace(/^## (.*$)/gim, '

$1

'); html = html.replace(/^# (.*$)/gim, '

$1

'); // Bold html = html.replace(/\*\*(.*?)\*\*/g, '$1'); // Italic html = html.replace(/\*(.*?)\*/g, '$1'); // Blockquote html = html.replace(/^> (.*$)/gim, '
$1
'); html = html.replace(/^> (.*$)/gim, '
$1
'); // Lists (unordered) html = html.replace(/^\- (.*$)/gim, '
  • $1
  • '); html = html.replace(/(
  • .*<\/li>)/s, '
      $1
    '); // Lists (ordered) html = html.replace(/^\d+\. (.*$)/gim, '
  • $1
  • '); // Line breaks và paragraphs html = html.split('\n\n').map(para => { para = para.trim(); if (para.startsWith('')) { return para; } if (para) { return '

    ' + para.replace(/\n/g, '
    ') + '

    '; } return ''; }).join('\n'); // Clean up multiple line breaks html = html.replace(/\n{3,}/g, '\n\n'); return html; } // Panel trượt đè lên #rightdocinfo để hiển thị phân tích điều luật function closePhanTichPanel() { const $panel = $('#phanTichPanel'); if ($panel.length) { $panel.removeClass('show'); setTimeout(() => $panel.remove(), 300); } // Reset highlight và badge khi đóng panel if (currentAnalyzingElement) { currentAnalyzingElement.removeClass('highlight-border-persistent'); } if (currentAnalyzingBadge) { currentAnalyzingBadge.text('Phân tích').removeClass('analyzing'); currentAnalyzingBadge.data('analyzing', false); currentAnalyzingBadge.data('hovering', false); currentAnalyzingBadge.css({display: 'none'}); // Ẩn badge khi đóng } // Reset tất cả các element khác (trong trường hợp có nhiều) $('#tab_noi_dung_vb .highlight-border-persistent').removeClass('highlight-border-persistent'); $('#tab_noi_dung_vb .badge-phan-tich-container.analyzing').each(function() { $(this).text('Phân tích').removeClass('analyzing').data('analyzing', false); }); // Reset state isAnalyzing = false; currentAnalyzingAddress = null; currentAnalyzingElement = null; currentAnalyzingBadge = null; } function openPhanTichPanel(address, vbID) { console.log('openPhanTichPanel called with address:', address); console.log('Current state - isAnalyzing:', isAnalyzing, 'currentAnalyzingAddress:', currentAnalyzingAddress); // Kiểm tra nếu đang phân tích element khác if (isAnalyzing && currentAnalyzingAddress && currentAnalyzingAddress !== address) { const currentName = getElementDisplayName(currentAnalyzingAddress); console.warn('Already analyzing:', currentAnalyzingAddress, 'Cannot analyze:', address); showWarningModal('Vui lòng chờ phân tích ' + currentName + ' hoàn tất...'); return; } // Nếu đang phân tích cùng element → không làm gì if (isAnalyzing && currentAnalyzingAddress === address) { console.log('Already analyzing this element, ignoring duplicate request'); return; } // ĐÓNG tất cả CTTD pointer đang mở để tránh xung đột z-index const $cttdPointers = $('.pointer.pointy.zindex'); const $cttdCanvas = $('canvas.pointy.zindex'); if ($cttdPointers.length > 0 || $cttdCanvas.length > 0) { console.log('Found CTTD pointers:', $cttdPointers.length, 'canvas:', $cttdCanvas.length, '- closing...'); $('.close_pointy').trigger('click'); // Đóng trực tiếp nếu còn $cttdPointers.fadeOut(200, function() { $(this).remove(); }); $cttdCanvas.fadeOut(200, function() { $(this).remove(); }); console.log('CTTD pointers and canvas removed'); } const $container = $('#rightdocinfo'); if ($container.length === 0) { // Fallback: nếu không có rightdocinfo, dùng modal cũ return openPhanTichModal(address, vbID); } // XÓA highlight persistent của TẤT CẢ elements cũ trước $('#tab_noi_dung_vb .highlight-border-persistent').removeClass('highlight-border-persistent'); console.log('Removed all previous highlight-border-persistent'); // Tìm element đang được phân tích và badge của nó const $element = $('[address="' + address + '"]'); const $badge = $element.find('.badge-phan-tich-container[data-for="' + address + '"]').first(); // Set state isAnalyzing = true; currentAnalyzingAddress = address; currentAnalyzingElement = $element; currentAnalyzingBadge = $badge; console.log('State set:', { isAnalyzing: isAnalyzing, currentAnalyzingAddress: currentAnalyzingAddress, elementFound: $element.length > 0, badgeFound: $badge.length > 0 }); // Thêm highlight persistent cho element MỚI này $element.addClass('highlight-border-persistent'); // Thay đổi badge thành "Đang phân tích..." và giữ hiển thị if ($badge.length > 0) { $badge.text('Đang phân tích...').addClass('analyzing'); // Giữ badge hiển thị và ở đúng vị trí $badge.data('analyzing', true); $badge.data('hovering', true); // Prevent auto-hide console.log('Badge set to analyzing state'); // Đảm bảo badge hiển thị ở đúng vị trí (vì dùng position: fixed) showPhanTichBadgeForParent($element); } // Tạo panel nếu chưa có if ($('#phanTichPanel').length === 0) { const panelHTML = `
    Phân tích điều luật
    Đang phân tích...

    Đang phân tích...

    `; // Đảm bảo container có position relative if ($container.css('position') === 'static') { $container.css('position', 'relative'); } $container.append(panelHTML); // Trigger slide-in với force z-index setTimeout(() => { const $panel = $('#phanTichPanel'); $panel.addClass('show'); $panel.css('z-index', '10001'); // Force z-index console.log('Panel created and shown with z-index:', $panel.css('z-index')); }, 10); } else { $('#phanTichPanelBody').html(`
    Đang phân tích...

    Đang phân tích...

    `); const $panel = $('#phanTichPanel'); $panel.addClass('show'); $panel.css('z-index', '10001'); // Force z-index console.log('Panel re-shown with z-index:', $panel.css('z-index')); } // Bind nút đóng và ESC $(document).off('click.closePhanTich').on('click.closePhanTich', '.close-phan-tich', function() { closePhanTichPanel(); }); $(document).off('keyup.closePhanTich').on('keyup.closePhanTich', function(e) { if (e.key === 'Escape') closePhanTichPanel(); }); // Gọi API phân tích const randomServer = Math.floor(Math.random() * 10) + 1; $.ajax({ url: '//tnpl' + randomServer + '.hethongphapluat.com/tien-ich/phan.tich.dieu.luat.php', type: 'POST', contentType: 'application/json', timeout: 300000, // 5 phút data: JSON.stringify({ address: address, vb_id: vbID }), success: function(response) { console.log('Analysis complete for:', address, response); // Reset badge về trạng thái bình thường (nhưng vẫn hiển thị) if (currentAnalyzingBadge) { currentAnalyzingBadge.text('Phân tích').removeClass('analyzing'); currentAnalyzingBadge.data('analyzing', false); console.log('Badge reset to normal state'); } // Reset state analyzing để có thể phân tích element khác isAnalyzing = false; console.log('State reset: isAnalyzing = false, can analyze other elements now'); if (response.ok) { // Render kết quả phân tích let html = ''; html += '
    '; html += '
    ' + escapeHtml(response.ten_van_ban) + '
    '; if (response.so_hieu) { html += 'Số hiệu: ' + escapeHtml(response.so_hieu) + '
    '; } html += 'Điều khoản: ' + escapeHtml(response.address) + ''; html += '
    '; html += '
    ' + markdownToHtml(response.phan_tich) + '
    '; if (response.usage) { html += '
    '; html += 'Thống kê: '; html += 'Input tokens: ' + (response.usage.promptTokenCount || 0) + ', '; html += 'Output tokens: ' + (response.usage.candidatesTokenCount || 0); html += '
    '; } $('#phanTichPanelBody').html(html); } else { $('#phanTichPanelBody').html(` `); } }, error: function(xhr, status, error) { console.error('Analysis error:', error); // Reset badge về trạng thái bình thường if (currentAnalyzingBadge) { currentAnalyzingBadge.text('Phân tích').removeClass('analyzing'); currentAnalyzingBadge.data('analyzing', false); } // Reset state analyzing isAnalyzing = false; let errorMsg = error; if (xhr.responseJSON && xhr.responseJSON.error) { errorMsg = xhr.responseJSON.error; } $('#phanTichPanelBody').html(` `); } }); } // Helper: Lấy tên hiển thị của element từ address function getElementDisplayName(address) { if (!address) return 'nội dung'; const $element = $('[address="' + address + '"]'); if ($element.length === 0) return address; const tagName = $element.prop('tagName').toLowerCase(); const parentType = getParentTypeName(tagName); // Lấy số thứ tự từ address let displayText = parentType; // Parse address: vd "khoan_3_dieu_4" -> "Khoản 3 Điều 4" const parts = address.split('_'); for (let i = 0; i < parts.length; i += 2) { if (i + 1 < parts.length) { const type = getParentTypeName(parts[i]); const num = parts[i + 1]; displayText = type + ' ' + num; } } return displayText; } function openPhanTichModal(address, vbID) { // Tạo modal nếu chưa có if ($('#modalPhanTich').length === 0) { const modalHTML = ` `; $('body').append(modalHTML); } // Reset và hiển thị modal với loading $('#modalPhanTichBody').html(`
    Đang phân tích...

    Đang phân tích...

    `); $('#modalPhanTich').modal('show'); // AJAX request const randomServer = Math.floor(Math.random() * 10) + 1; $.ajax({ url: '//tnpl' + randomServer + '.hethongphapluat.com/tien-ich/phan.tich.dieu.luat.php', type: 'POST', contentType: 'application/json', data: JSON.stringify({ address: address, vb_id: vbID }), success: function(response) { if (response.ok) { // Render kết quả phân tích let html = ''; // Header thông tin văn bản html += '
    '; html += '
    ' + escapeHtml(response.ten_van_ban) + '
    '; if (response.so_hieu) { html += 'Số hiệu: ' + escapeHtml(response.so_hieu) + '
    '; } html += 'Điều khoản: ' + escapeHtml(response.address) + ''; html += '
    '; // Nội dung phân tích (Markdown -> HTML) html += '
    '; html += markdownToHtml(response.phan_tich); html += '
    '; // Thông tin usage (nếu có) if (response.usage) { html += '
    '; html += 'Thống kê: '; html += 'Input tokens: ' + (response.usage.promptTokenCount || 0) + ', '; html += 'Output tokens: ' + (response.usage.candidatesTokenCount || 0); html += '
    '; } $('#modalPhanTichBody').html(html); } else { $('#modalPhanTichBody').html(` `); } }, error: function(xhr, status, error) { let errorMsg = error; if (xhr.responseJSON && xhr.responseJSON.error) { errorMsg = xhr.responseJSON.error; } $('#modalPhanTichBody').html(` `); } }); } // Helpers: show/hide badge cho parent element (dieu, khoan,...) với position: fixed function showPhanTichBadgeForParent($parent) { // Lấy badge CỦA CHÍNH parent này (match data-for với address của parent) const parentAddress = $parent.attr('address'); const $badge = $parent.find('.badge-phan-tich-container[data-for="' + parentAddress + '"]').first(); if ($badge.length === 0) { console.warn('No badge found for parent:', parentAddress); return; } // Ẩn TẤT CẢ các badge khác để tránh overlap $('.badge-phan-tich-container').not($badge).each(function() { const $otherBadge = $(this); // Chỉ ẩn badge KHÔNG đang analyzing if (!$otherBadge.data('analyzing')) { $otherBadge.css({display: 'none'}); } }); // Show badge tạm để tính width $badge.css({display: 'inline-block', opacity: 0, visibility: 'hidden'}); const badgeWidth = $badge.outerWidth(); // Tính toán vị trí fixed dựa trên offset của parent const offset = $parent.offset(); const scrollTop = $(window).scrollTop(); const scrollLeft = $(window).scrollLeft(); // Position badge top-right của parent và show $badge.css({ display: 'inline-block', visibility: 'visible', opacity: 1, top: (offset.top - scrollTop) + 'px', left: (offset.left + $parent.outerWidth() - badgeWidth - scrollLeft - 5) + 'px' // -5px padding }); console.log('Showing badge for:', parentAddress, 'at position:', $badge.css('top'), $badge.css('left')); $parent.addClass('highlight-border'); } function hidePhanTichBadgeForParent($parent) { const $badge = $parent.find('.badge-phan-tich-container').first(); if ($badge.length === 0) return; $badge.css({display: 'none', opacity: 0}); $parent.removeClass('highlight-border'); } // Event delegation cho hover vào parent elements (dieu, khoan,...) - attach badge nếu chưa có, rồi show $(document).on('mouseenter', '#tab_noi_dung_vb phan, #tab_noi_dung_vb chuong, #tab_noi_dung_vb muc, #tab_noi_dung_vb tieumuc, #tab_noi_dung_vb dieu, #tab_noi_dung_vb khoan, #tab_noi_dung_vb diem', function(e) { // Stop propagation để tránh highlight parent khi hover vào child e.stopPropagation(); const $parent = $(this); const address = $parent.attr('address'); // Set flag hovering $parent.data('hovering', true); // Cancel timeout nếu có const timeoutId = $parent.data('hideTimeout'); if (timeoutId) { clearTimeout(timeoutId); } // Ẩn highlight của tất cả parent elements khác (trừ element đang analyzing) $('#tab_noi_dung_vb phan, #tab_noi_dung_vb chuong, #tab_noi_dung_vb muc, #tab_noi_dung_vb tieumuc, #tab_noi_dung_vb dieu, #tab_noi_dung_vb khoan, #tab_noi_dung_vb diem') .not($parent) .each(function() { const $el = $(this); // Chỉ xóa highlight-border, KHÔNG xóa highlight-border-persistent $el.removeClass('highlight-border'); // Ẩn badge nếu KHÔNG đang analyzing const $badge = $el.find('.badge-phan-tich-container'); if ($badge.length && !$badge.data('analyzing')) { $badge.css({display: 'none'}); } }); // Attach badge nếu chưa có - badge phải có data-for = address của PARENT, không phải child if (address && $parent.find('.badge-phan-tich-container[data-for="' + address + '"]').length === 0) { const parentType = getParentTypeName($parent.prop('tagName').toLowerCase()); // Tạo badge với data-for = address của PARENT element này const $badge = $('Phân tích'); console.log('Creating badge for address:', address, 'parentType:', parentType); $parent.append($badge); $parent.addClass('has-phan-tich-badge'); } // Show badge cho element này if ($parent.find('.badge-phan-tich-container').length > 0) { showPhanTichBadgeForParent($parent); } }); // Event delegation cho hover ra khỏi parent $(document).on('mouseleave', '#tab_noi_dung_vb phan, #tab_noi_dung_vb chuong, #tab_noi_dung_vb muc, #tab_noi_dung_vb tieumuc, #tab_noi_dung_vb dieu, #tab_noi_dung_vb khoan, #tab_noi_dung_vb diem', function(e) { const $parent = $(this); const parentAddress = $parent.attr('address'); const $badge = $parent.find('.badge-phan-tich-container[data-for="' + parentAddress + '"]').first(); // Set flag parent not hovering $parent.data('hovering', false); // Nếu badge đang analyzing thì KHÔNG ẩn, GIỮ hiển thị if ($badge.length > 0 && $badge.data('analyzing')) { console.log('Badge is analyzing, keep visible'); return; } // Delay để có thời gian di chuột vào badge const timeoutId = setTimeout(() => { // Chỉ ẩn nếu cả parent và badge đều không hover và không analyzing if ($badge.length > 0 && !$parent.data('hovering') && !$badge.data('hovering') && !$badge.data('analyzing')) { hidePhanTichBadgeForParent($parent); } }, 300); // Tăng lên 300ms $parent.data('hideTimeout', timeoutId); }); // Hover vào badge → giữ hiển thị $(document).on('mouseenter', '.badge-phan-tich-container', function(e) { e.stopPropagation(); const $badge = $(this); const $parent = $badge.parent(); $badge.data('hovering', true); // Cancel timeout của parent const timeoutId = $parent.data('hideTimeout'); if (timeoutId) { clearTimeout(timeoutId); } }); // Hover ra khỏi badge → ẩn nếu không hover parent $(document).on('mouseleave', '.badge-phan-tich-container', function(e) { const $badge = $(this); $badge.data('hovering', false); const $parent = $badge.parent(); // Nếu badge đang analyzing thì KHÔNG ẩn, GIỮ hiển thị if ($badge.data('analyzing') || $badge.hasClass('analyzing')) { console.log('Badge is analyzing on mouseleave, keep visible'); return; } setTimeout(() => { // Chỉ ẩn nếu cả parent và badge đều không hover và không analyzing if (!$parent.data('hovering') && !$badge.data('hovering') && !$badge.data('analyzing') && !$badge.hasClass('analyzing')) { hidePhanTichBadgeForParent($parent); } }, 300); }); // Event delegation cho hover vào badge → hiện tooltip $(document).on('mouseenter', '.badge-phan-tich, .badge-phan-tich-container, .badge-phan-tich-fixed', function() { const $badge = $(this); const parentType = $badge.attr('data-parent-type') || 'Nội dung'; if ($badge.find('.badge-tooltip').length === 0) { const $tooltip = $('Phân tích chi tiết nội dung ' + parentType + ' này'); $badge.append($tooltip); setTimeout(() => $tooltip.addClass('show'), 10); } }); // Event delegation cho hover ra khỏi badge → ẩn tooltip $(document).on('mouseleave', '.badge-phan-tich, .badge-phan-tich-container, .badge-phan-tich-fixed', function() { const $tooltip = $(this).find('.badge-tooltip'); if ($tooltip.length > 0) { $tooltip.removeClass('show'); setTimeout(() => $tooltip.remove(), 300); } }); // Event delegation cho click badge → mở panel $(document).on('click', '.badge-phan-tich, .badge-phan-tich-container, .badge-phan-tich-fixed', function(e) { e.preventDefault(); e.stopPropagation(); const $badge = $(this); console.log('Badge clicked! Element:', $badge[0]); console.log('Badge parent:', $badge.parent().prop('tagName'), $badge.parent().attr('address')); console.log('Badge data-for:', $badge.attr('data-for')); console.log('Badge data-parent-type:', $badge.attr('data-parent-type')); // Nếu badge đang analyzing thì không cho click if ($badge.hasClass('analyzing') || $badge.data('analyzing')) { console.log('Badge is analyzing, click ignored'); return; } // Lấy address từ data-for attribute const address = $badge.attr('data-for'); console.log('Will analyze address:', address, 'vbID:', vbID); if (address && vbID) { openPhanTichPanel(address, vbID); } else { console.error('Missing address or vbID', {address, vbID}); showWarningModal('Không tìm thấy địa chỉ điều luật hoặc ID văn bản!'); } }); // Ẩn badge khi click vào CTTD để tránh xung đột UI $(document).on('click', 'cttd.chuthichtudong span, dctk span, dctd span', function(e) { console.log('CTTD clicked'); // Ẩn TẤT CẢ badge KHÔNG đang analyzing (không chỉ badge của parent) $('.badge-phan-tich-container').each(function() { const $badge = $(this); // Chỉ ẩn nếu KHÔNG đang analyzing if (!$badge.data('analyzing') && !$badge.hasClass('analyzing')) { $badge.css({display: 'none'}); console.log('Hiding badge:', $badge.attr('data-for')); } else { console.log('Keeping badge visible (analyzing):', $badge.attr('data-for')); // Đảm bảo badge analyzing vẫn visible và ở đúng vị trí const $parent = $badge.parent(); setTimeout(() => { if ($badge.data('analyzing') || $badge.hasClass('analyzing')) { showPhanTichBadgeForParent($parent); console.log('Re-showing analyzing badge after CTTD click'); } }, 100); } }); }); // Update badge position khi scroll hoặc resize (vì dùng position: fixed) function updateBadgePositions() { $('.badge-phan-tich-container:visible').each(function() { const $badge = $(this); const $parent = $badge.parent(); // Cập nhật position nếu parent đang hover HOẶC badge đang analyzing if ($parent.length && ($parent.is(':hover') || $badge.data('analyzing'))) { // Re-calculate position const offset = $parent.offset(); const scrollTop = $(window).scrollTop(); const scrollLeft = $(window).scrollLeft(); const badgeWidth = $badge.outerWidth(); $badge.css({ top: (offset.top - scrollTop) + 'px', left: (offset.left + $parent.outerWidth() - badgeWidth - scrollLeft - 5) + 'px' }); } }); } $(window).on('scroll', updateBadgePositions); $(window).on('resize', updateBadgePositions); } });