ỦY BAN NHÂN DÂN TỈNH BẮC KẠN -------
CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM Độc lập - Tự do - Hạnh phúc ---------------
Số: 506/KH-UBND
Bắc Kạn, ngày 28 tháng 7 năm 2023
KẾ HOẠCH
TRIỂN KHAI CHƯƠNG TRÌNH HỖ TRỢ PHỔ CẬP ĐIỆN THOẠI THÔNG MINH CHO NGƯỜI DÂN TRƯỞNG THÀNH TẠI 08 XÃ/PHƯỜNG THỰC HIỆN THÍ ĐIỂM CHUYỂN ĐỔI SỐ NĂM 2023
I. CĂN CỨ XÂY DỰNG KẾ HOẠCH
Nghị định số 07/2021/NĐ-CP ngày 27/01/2021 của Chính phủ quy định chuẩn nghèo đa chiều gia đoạn 2021 - 2025;
Quyết định số 861/QĐ-TTg ngày 04/6/2021 của Thủ tướng Chính phủ phê duyệt danh sách các xã khu vực III, khu vực II, khu vực I thuộc vùng đồng bào dân tộc thiểu số và miền núi giai đoạn 2021 - 2025;
Quyết định số 2269/QĐ-TTg ngày 31/12/2021 của Thủ tướng Chính phủ phê duyệt Chương trình cung cấp dịch vụ viễn thông công ích đến năm 2025;
Thông tư số 14/2022/TT-BTTTT ngày 28/10/2022 của Bộ trưởng Bộ Thông tin và Truyền thông quy định danh mục, chất lượng dịch vụ viễn thông công ích và hướng dẫn thực hiện Chương trình cung cấp dịch vụ viễn thông công ích đến năm 2025;
Quyết định số 1506/QĐ-BTTTT ngày 12/8/2022 của Bộ trưởng Bộ Thông tin và Truyền thông phân bổ máy tính bảng thuộc Chương trình cung cấp dịch vụ viễn thông công ích đến năm 2025 cho các tỉnh, thành phố trực thuộc Trung ương;
Thông báo số 1085-TB/TU ngày 29/6/2023 của Ban Thường vụ Tỉnh ủy về nội dung Hội nghị Ban Thường vụ Tỉnh ủy lần thứ 56 (khóa XII), nhiệm kỳ 2020 - 2025;
Kế hoạch số 369/KH-UBND ngày 14/6/2023 của UBND tỉnh Bắc Kạn về thí điểm triển khai thực hiện chuyển đổi số tại 08 xã/phường/thị trấn trên địa bàn tỉnh Bắc Kạn năm 2023.
II. MỤC ĐÍCH, YÊU CẦU
1. Giúp người dân trưởng thành nói chung và các hộ gia đình nói riêng đang sinh sống tại 8 xã/phường thực hiện thí điểm chuyển đổi số có cơ hội tìm hiểu, tiếp cận với các ứng dụng về thông tin và khoa học công nghệ, các dịch vụ công trực tuyến, qua đó góp phần nâng cao trình độ hiểu biết, kịp thời cập nhật các thông tin tuyên truyền, thực hiện tốt các chủ trương, đường lối của Đảng, chính sách, pháp luật của Nhà nước; nâng cao tỷ lệ sử dụng dịch vụ công trực tuyến, thanh toán không dùng tiền mặt, định danh điện tử… từng bước hình thành “xã hội số”, “công dân số”; nâng cao tỷ lệ dân số trưởng thành có điện thoại thông minh và tỷ lệ hộ gia đình có người có điện thoại thông minh trên địa bàn tỉnh, từ đó thực hiện thành công Chương trình chuyển đổi số quốc gia, Đề án phát triển ứng dụng dữ liệu về dân cư, định danh và xác thực điện tử phục vụ chuyển đổi số quốc gia (Đề án 06) tại địa phương.
2. Phấn đấu 100% người dân trưởng thành3. Điện thoại được hỗ trợ đảm bảo đúng đối tượng, không trùng lặp, không để xảy ra tình trạng tiêu cực, lãng phí trong quá trình thực hiện; cài đặt đầy đủ các ứng dụng, đáp ứng tra cứu thông tin, liên lạc nhanh chóng và trực quan; sử dụng làm phương tiện thanh toán trực tuyến tiện lợi, làm phương tiện học tập và làm việc từ xa hiệu quả...
III. NỘI DUNG
1. Phạm vi thực hiện
Tại 08 đơn vị cấp xã được UBND các huyện, thành phố lựa chọn là đơn vị triển khai thí điểm chuyển đổi số (phường Sông Cầu, thành phố Bắc Kạn; xã Quang Thuận, huyện Bạch Thông; xã Thượng Giáo, huyện Ba Bể; xã Nghĩa Tá, huyện Chợ Đồn; xã Như Cố, huyện Chợ Mới; xã Đức Vân, huyện Ngân Sơn; xã Côn Minh, huyện Na Rì; xã Giáo Hiệu, huyện Pác Nặm).
2. Đối tượng hỗ trợ
Người dân trưởng thành sinh sống tại 8 xã/phường thí điểm chuyển đổi số.
3. Hình thức hỗ trợ
- Hỗ trợ nguyên chiếc điện thoại thông minh từ nguồn tiếp nhận được đối với người dân trưởng thành thuộc hộ nghèo, hộ cận nghèo chưa có điện thoại thông minh theo thứ tự ưu tiên như sau:
Người dân trưởng thành thuộc hộ nghèo, hộ cận nghèo đồng thời là gia đình chính sách người có công với cách mạng.
Người dân trưởng thành thuộc hộ nghèo, hộ cận nghèo đồng thời gia đình chính sách xã hội.
Người dân trưởng thành thuộc hộ nghèo khác
Người dân trưởng thành thuộc hộ cận nghèo khác.
- Hỗ trợ một phần kinh phí từ các nguồn kinh phí huy động được đối với người dân trưởng thành chưa có điện thoại thông minh thuộc các đối tượng theo thứ tự ưu tiên như sau:
Người dân trưởng thành thuộc hộ nghèo chưa có điện thoại thông minh.
Người dân trưởng thành thuộc hộ nghèo có thành viên khác của gia đình đó đã được hỗ trợ nguyên chiếc điện thoại thông minh.
Người dân trưởng thành thuộc hộ cận nghèo chưa có điện thoại thông minh.
Người dân trưởng thành thuộc hộ cận nghèo có thành viên khác của gia đình đó đã được hỗ trợ nguyên chiếc điện thoại thông minh.
- Hỗ trợ của doanh nghiệp, cửa hàng bán điện thoại thông minh (tặng máy điện thoại, giảm giá thành điện thoại, bán điện thoại trả góp hoặc các hình thức hỗ trợ khác): Các đối tượng được hỗ trợ do đơn vị kinh doanh xác định (tỉnh khuyến khích ưu tiên hỗ trợ người dân thuộc hộ nghèo, hộ cận nghèo).
- Hỗ trợ trực tiếp từ các cơ quan, đơn vị, tổ chức, doanh nghiệp, cá nhân: Các đối tượng được hỗ trợ do đơn vị, cá nhân xác định (tỉnh khuyến khích ưu tiên hỗ trợ người dân thuộc hộ nghèo, hộ cận nghèo).
4. Phương thức tiếp nhận hỗ trợ
Có thể lựa chọn một trong các hình thức sau:
- Tại cấp tỉnh: Sở Thông tin và Truyền thông làm đầu mối tiếp nhận hỗ trợ thông qua hình thức hỗ trợ bằng hiện vật điện thoại hoặc bằng tiền mặt từ các cơ quan, đơn vị, tổ chức, doanh nghiệp, cá nhân trong và ngoài tỉnh có nhu cầu hỗ trợ Chương trình; xây dựng phương án phân bổ nguồn hỗ trợ cho các huyện/thành phố, xã/phường thí điểm chuyển đổi số.
- Tại cấp huyện, cấp xã: UBND các huyện/thành phố, UBND các xã/phường thí điểm chuyển đổi số làm đầu mối tiếp nhận hỗ trợ thông qua hình thức hỗ trợ bằng hiện vật điện thoại hoặc bằng tiền mặt từ các đơn vị, tổ chức, doanh nghiệp, cá nhân trong và ngoài tỉnh có nhu cầu hỗ trợ Chương trình. Trên cơ sở nguồn hỗ trợ tiếp nhận hoặc được phân bổ, UBND xã/phường lựa chọn, lập danh sách người dân được hỗ trợ theo thứ tự ưu tiên tại tiểu mục 3, mục III của Kế hoạch này.
- Các đối tượng được hỗ trợ có thể tiếp nhận trực tiếp từ các các đơn vị, tổ chức, doanh nghiệp, cá nhân trong và ngoài tỉnh.
5. Tính năng của điện thoại thông minh
Điện thoại thông minh được hỗ trợ phải được cài đặt, cập nhật đầy đủ các tính năng, ứng dụng cơ bản, đáp ứng tra cứu thông tin liên lạc nhanh chóng và trực quan; cập nhật thông tin nhanh chóng, sử dụng làm phương tiện thanh toán trực tuyến tiện lợi, làm phương tiện học tập và làm việc từ xa hiệu quả và sử dụng được dịch vụ 3G/4G…
IV. KINH PHÍ THỰC HIỆN
Kinh phí triển khai Chương trình hỗ trợ phổ cập điện thoại thông minh cho các hộ nghèo, hộ cận nghèo tại 08 xã/phường thực hiện thí điểm chuyển đổi số năm 2023 chủ yếu từ nguồn huy động xã hội hóa, hỗ trợ của các cơ quan, đơn vị, tổ chức, doanh nghiệp, cá nhân và nguồn ngân sách Trung ương, địa phương (nếu có).
V. TIẾN ĐỘ THỰC HIỆN
- Triển khai công tác tuyên truyền: Ngay khi Kế hoạch được ban hành.
- Tổ chức đợt cao điểm quyên góp, ủng hộ cho Chương trình: Bắt đầu từ tháng 8/2023 đến hết năm 2023.
VI. TỔ CHỨC THỰC HIỆN
1. Sở Thông tin và Truyền thông
- Chủ trì, phối hợp với Ủy ban Mặt trận Tổ quốc Việt Nam tỉnh, các tổ chức đoàn thể, chính trị - xã hội và các đơn vị liên quan tham mưu cho UBND tỉnh tổ chức đợt cao điểm quyên góp, ủng hộ cho Chương trình hỗ trợ phổ cập điện thoại thông minh cho người dân tại 08 xã/phường thực hiện thí điểm chuyển đổi số năm 2023; văn bản trình UBND tỉnh ban hành trước ngày 31/7/2023.
- Tham mưu cho UBND tỉnh mời các địa phương, cơ quan, tổ chức, đơn vị liên quan, doanh nghiệp, cửa hàng kinh doanh điện thoại thông minh trên địa bàn tỉnh tham dự Hội nghị tuyên truyền, phổ biến, quán triệt, trao đổi, thống nhất phương thức tổ chức thực hiện Chương trình.
- Làm đầu mối tiếp nhận hỗ trợ thông qua hình thức hỗ trợ bằng hiện vật điện thoại hoặc bằng tiền mặt từ các đơn vị, tổ chức, doanh nghiệp, cá nhân trong và ngoài tỉnh ủng hộ Chương trình; xây dựng phương án phân bổ nguồn hỗ trợ cho các huyện/thành phố, xã/phường thí điểm chuyển đổi số đảm bảo đúng đối tượng, đúng mục đích, công khai, minh bạch.
- Có trách nhiệm hướng dẫn, hỗ trợ các huyện/thành phố, xã/phường về cách thức tiếp nhận, phân bổ và triển khai; tổng hợp báo cáo tình hình tiếp nhận và phân bổ theo tháng (trước 20 hàng tháng) và tham mưu tổng kết việc thực hiện Chương trình, đánh giá, rút kinh nghiệm để nhân rộng việc phổ cập điện thoại thông minh trên địa bàn tỉnh.
- Chỉ đạo các cơ quan báo chí của tỉnh tăng cường công tác tuyên truyền về mục đích, ý nghĩa của Chương trình đến các tổ chức, doanh nghiệp và Nhân dân được biết, tích cực tham gia ủng hộ.
2. UBND các huyện, thành phố; UBND các xã, phường thí điểm
- Lập và duyệt danh sách người dân thuộc đối tượng hỗ trợ; làm đầu mối tiếp nhận tại cấp huyện, cấp xã và thực hiện việc phân bổ, bàn giao cho các đối tượng được hưởng hỗ trợ đảm bảo đúng đối tượng, đúng mục đích, công khai, minh bạch. Đồng thời tổng hợp số liệu trao tặng, phân bổ, bàn giao gửi Sở Thông tin và Truyền thông tổng hợp báo cáo UBND tỉnh theo quy định.
- UBND các huyện, thành phố chủ động cân đối, bố trí kinh phí hỗ trợ ban đầu cho Chương trình; chỉ đạo UBND tại 08 xã/phường thực hiện thí điểm chuyển đổi số năm 2023 khuyến khích người dân chủ động mua và sử dụng điện thoại thông minh; tổ chức tuyên truyền, vận động người dân/người thân của các hộ dân sinh sống tại địa bàn và các nhà hảo tâm tham gia ủng hộ Chương trình, tặng điện thoại thông minh hoặc hỗ trợ mua điện thoại thông minh cho người dân sống trên địa bàn.
- Tổ chức tuyên truyền hướng dẫn người dân quản lý và sử dụng thiết bị điện thoại thông minh đảm bảo hiệu quả.
3. Các sở, ban, ngành tỉnh
Theo chức năng, nhiệm vụ, triển khai, phối hợp thực hiện Chương trình đảm bảo phù hợp, hiệu quả; vận động, kêu gọi trong toàn ngành ủng hộ, hỗ trợ để thực hiện Chương trình, góp phần hướng tới mục tiêu người dân sinh sống tại địa bàn 8 xã/phường triển khai thí điểm chuyển đổi số có điện thoại thông minh để sử dụng.
4. Đề nghị Ủy ban Mặt trận Tổ quốc Việt Nam tỉnh và các đoàn thể tỉnh
Phối hợp với Sở Thông tin và Truyền thông phát động, ủng hộ Chương trình đến Ủy ban Mặt trận Tổ quốc các cấp và các tổ chức thành viên; phối hợp với các cơ quan, đơn vị liên quan tổ chức quyên góp, vận động, ủng hộ Chương trình.
5. Đề nghị Hiệp hội Doanh nghiệp tỉnh, Hội Doanh nhân trẻ tỉnh
Tổ chức tuyên truyền, vận động các doanh nghiệp trên địa bàn tỉnh hưởng ứng tham gia ủng hộ Chương trình (bằng kinh phí hoặc tặng máy điện thoại thông minh) để giúp người dân sinh sống tại địa bàn 8 xã/phường triển khai thí điểm chuyển đổi số có điện thoại thông minh để sử dụng.
6. Đề nghị các doanh nghiệp viễn thông - CNTT, cửa hàng bán điện thoại thông minh trên địa bàn tỉnh
- Tiếp tục phủ sóng di động băng rộng tại các thôn, bản vùng “lõm” sóng; triển khai hạ tầng băng rộng cố định (cáp quang) để phổ cập mạng băng rộng cáp quang đến 100% các thôn trên địa bàn tỉnh; phối hợp cùng với tỉnh nâng cao tỷ lệ hộ gia đình có kết nối internet.
- Hỗ trợ các gói cước Internet cho đối tượng được hỗ trợ thuộc Chương trình.
- Tham gia ủng hộ nguồn lực (máy điện thoại thông minh, kinh phí...) cho
Chương trình; triển khai các chính sách hỗ trợ giảm giá thành điện thoại, hỗ trợ mua điện thoại trả góp với lãi suất thấp hoặc các hình thức hỗ trợ khác cho các đối tượng được hưởng hỗ trợ tại Kế hoạch này.
- Hỗ trợ cài đặt các ứng dụng trên điện thoại thông minh.
7. Đề nghị các đơn vị, tổ chức, doanh nghiệp, cá nhân, nhà hảo tâm, nhà tài trợ: Quan tâm, tích cực tham gia ủng hộ Chương trình, đồng hành cùng với tỉnh Bắc Kạn đẩy nhanh quá trình chuyển đổi số cho người dân trên địa bàn tỉnh.
Trên đây là Kế hoạch triển khai Chương trình hỗ trợ phổ cập điện thoại thông minh cho người dân tại 08 xã/phường thực hiện thí điểm chuyển đổi số năm 2023. Trong quá trình thực hiện, nếu có khó khăn, vướng mắc, các cơ quan, đơn vị kịp thời báo cáo Ủy ban nhân dân tỉnh (qua Sở Thông tin và Truyền thông) để giải quyết./.
Nơi nhận: - Bộ TT&TT (b/c); - TT Tỉnh ủy (b/c); - CT, các PCT UBND tỉnh; - Ủy ban MTTQ Việt Nam tỉnh; - Các cơ quan tham mưu, giúp việc TU; - Các sở, ban, ngành, đoàn thể tỉnh; - Cơ quan TƯ trên địa bàn tỉnh; - Hiệp hội DN tỉnh; Hội Doanh nhân trẻ; - Các doanh nghiệp viễn thông CNTT trên địa bàn tỉnh; - Cấp uỷ, UBND huyện, thành phố; - Cấp uỷ, UBND 8 xã/phường thuộc Chương trình; - LĐVP; - Phòng HCTC-QTTV; - Lưu: VT, NCTH, Nhung VX
TM. ỦY BAN NHÂN DÂN CHỦ TỊCH Nguyễn Đăng Bình
lồng nhau (bên trong) hay không
const memberID = 0;
const vbID = '0de40be3e37b16357cb388abcd1516d2';
const unlockAllPhanTich = true;
// 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
let isPanelOpen = false; // Panel phân tích có đang mở không
// Typing effect state
let typingTimerId = null;
let typingCancelled = false;
// Thinking GIF state
let thinkingGifIntervalId = null;
let thinkingGifActive = false;
let thinkingGifCurrent = 0; // chỉ số GIF hiện tại 1..10
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, vb_ngaybanhanh: '2023-07-28 00:00:00 AM' };
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 (((unlockAllPhanTich) || memberID === 4 || memberID === 3 || memberID === 2) && 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 extraClass = (unlockAllPhanTich && memberID <= 0) ? ' upgrade-require' : '';
const $badge = $('');
$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);
}, 3); // Đợi 300ms để CTTD render xong
}
},
complete: function() {
$element.removeClass('loading-content');
}
})
);
processQueue();
}
});
} catch(e) {
}
}
$(window).on('scroll resize', function () {
processVisibleParagraphs();
});
processVisibleParagraphs();
// Chức năng phân tích điều luật (mở theo lịch unlockAllPhanTich cho tất cả, nhưng khách click sẽ mở modal đăng nhập/mua gói)
if ((unlockAllPhanTich) || memberID === 4 || memberID === 3 || memberID === 2) {
// 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';
}
// Chuyển Telex -> Unicode cho giá trị (ví dụ: dd->đ, oo->ô, ow->ơ, aa->â, ee->ê, aw->ă, uw->ư)
function telexToUnicode(str) {
if (!str) return str;
// Giữ nguyên số
if (/^\d+$/.test(str)) return str;
let s = String(str);
// dd / ĐĐ
s = s.replace(/dd/g, 'đ');
s = s.replace(/DD/g, 'Đ');
// nguyên âm có mũ/dấu
s = s.replace(/aa/g, 'â').replace(/AA/g, 'Â');
s = s.replace(/ee/g, 'ê').replace(/EE/g, 'Ê');
s = s.replace(/oo/g, 'ô').replace(/OO/g, 'Ô');
s = s.replace(/ow/g, 'ơ').replace(/OW/g, 'Ơ');
s = s.replace(/uw/g, 'ư').replace(/UW/g, 'Ư');
s = s.replace(/aw/g, 'ă').replace(/AW/g, 'Ă');
return s;
}
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 extraClass = (unlockAllPhanTich && memberID <= 0) ? ' upgrade-require' : '';
const $badge = $('');
$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, '');
// 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 fixed position
function closePhanTichPanel() {
const $panel = $('#phanTichPanel');
if ($panel.length) {
$panel.removeClass('show');
setTimeout(() => {
$panel.remove();
}, 300);
}
// Stop typing animation nếu đang chạy
stopThinkingTyping();
// 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);
});
// Check: có CTTD pointer đang mở không?
const $visiblePointers = $('.pointer:visible');
const hadCTTDOpen = $visiblePointers.length > 0;
if (hadCTTDOpen) {
// CÓ CTTD đang mở → giữ rightdocinfo ẩn
} else {
// KHÔNG có CTTD → SHOW lại rightdocinfo
const $rightdocinfo = $('#rightdocinfo');
if ($rightdocinfo.length > 0) {
$rightdocinfo.show();
}
}
// Reset state
isAnalyzing = false;
currentAnalyzingAddress = null;
currentAnalyzingElement = null;
currentAnalyzingBadge = null;
isPanelOpen = false; // Đánh dấu panel đã đóng
}
// Panel đã song song với rightdocinfo → không cần MutationObserver nữa
// Resize event để update panel dimensions khi browser resize
let resizeTimer;
$(window).on('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
if (isPanelOpen && $('#phanTichPanel').length > 0) {
updatePanelDimensions();
if ($('#phanTichPanelBody').hasClass('thinking-mode')) {
updateThinkingGifHeight();
}
}
}, 250); // Debounce 250ms
});
// Function để detect và áp dụng dimensions từ rightdocinfo
function updatePanelDimensions() {
const $panel = $('#phanTichPanel');
const $rightdocinfo = $('#rightdocinfo');
const $docRightCol = $('#doc-right-col');
// Mobile: dùng bottom sheet → để CSS điều khiển, bỏ qua reposition bằng JS
if ($(window).width() <= 768) {
return;
}
if ($panel.length === 0) return;
// Ưu tiên: doc-right-col > rightdocinfo
let $reference = $docRightCol.length > 0 ? $docRightCol : $rightdocinfo;
// Nếu reference bị ẩn (display:none), tạm show để get dimensions
let wasHidden = false;
if ($reference.length > 0 && !$reference.is(':visible')) {
wasHidden = true;
$reference.css('visibility', 'hidden').show();
}
if ($reference.length > 0) {
const refWidth = $reference.outerWidth();
const refOffset = $reference.offset();
if (refWidth && refOffset) {
// Tính vị trí right từ edge màn hình
const windowWidth = $(window).width();
const rightPosition = windowWidth - (refOffset.left + refWidth);
$panel.css({
'width': refWidth + 'px',
'right': rightPosition + 'px'
});
} else {
}
// Restore trạng thái hidden nếu cần
if (wasHidden) {
$reference.hide().css('visibility', '');
}
}
}
// Hiệu ứng typing giả lập đang phân tích trong panel
function stopThinkingTyping() {
typingCancelled = true;
if (typingTimerId) {
clearTimeout(typingTimerId);
typingTimerId = null;
}
// Dừng trình chiếu ảnh khi dừng typing
stopThinkingImages();
}
// Helper GIF: chọn chỉ số ảnh mới 1..10 khác với exclude
function randomGifIndex(exclude) {
let n = exclude;
while (n === exclude) {
n = Math.floor(Math.random() * 10) + 1;
}
return n;
}
// Helper GIF: preload rồi gán src cho img, gọi callback sau khi load xong (hoặc lỗi)
function setGifSrc($img, idx, cb) {
const url = '/assets/images/gif/researching-' + idx + '.gif';
const updateWrapHeight = function(nW, nH){
try {
const $wrap = $img.closest('#thinkingGifWrapper');
if ($wrap.length && nW && nH) {
const wrapW = $wrap.width();
const maxW = wrapW * 0.9; // khớp với CSS max-width:90%
const displayW = Math.min(nW, maxW);
const displayH = nH * (displayW / nW);
$wrap.css('height', displayH + 'px');
}
} catch(e) { /* ignore */ }
};
if ($img.attr('src') === url) {
// Ảnh trùng src -> vẫn cập nhật lại chiều cao wrapper theo kích thước hiển thị hiện tại
const el = $img[0];
if (el && el.naturalWidth && el.naturalHeight) {
updateWrapHeight(el.naturalWidth, el.naturalHeight);
}
if (cb) cb();
return;
}
const pre = new Image();
pre.onload = function() {
$img.attr('src', url);
updateWrapHeight(pre.naturalWidth, pre.naturalHeight);
if (cb) cb();
};
pre.onerror = function() {
$img.attr('src', url);
// Không lấy được kích thước tự nhiên -> để auto
const $wrap = $img.closest('#thinkingGifWrapper');
if ($wrap.length) { $wrap.css('height', 'auto'); }
if (cb) cb();
};
pre.src = url;
}
function updateThinkingGifHeight() {
const $wrap = $('#thinkingGifWrapper');
if ($wrap.length === 0) return;
const $show = $('#thinkingGifA.visible, #thinkingGifB.visible').first();
if ($show.length === 0) return;
const el = $show[0];
if (!el.naturalWidth || !el.naturalHeight) return;
const wrapW = $wrap.width();
const maxW = wrapW * 0.9;
const displayW = Math.min(el.naturalWidth, maxW);
const displayH = el.naturalHeight * (displayW / el.naturalWidth);
$wrap.css('height', displayH + 'px');
}
function startThinkingImages() {
// Nếu body/khung chưa sẵn sàng thì bỏ qua
const $wrap = $('#thinkingGifWrapper');
if ($wrap.length === 0) return;
// Clear trước nếu đang chạy
stopThinkingImages();
thinkingGifActive = true;
const $a = $('#thinkingGifA');
const $b = $('#thinkingGifB');
$a.removeClass('visible');
$b.removeClass('visible');
// Ảnh đầu tiên
thinkingGifCurrent = randomGifIndex(0);
let useA = true; // ảnh A hiển thị trước
setGifSrc($a, thinkingGifCurrent, function(){ $a.addClass('visible'); });
// Mỗi 3s đổi ảnh, crossfade 0.5s qua CSS
thinkingGifIntervalId = setInterval(function(){
if (!thinkingGifActive) return;
const nextIdx = randomGifIndex(thinkingGifCurrent);
const $show = useA ? $b : $a; // show ảnh còn lại
const $hide = useA ? $a : $b;
setGifSrc($show, nextIdx, function(){
// Bắt đầu chuyển ảnh: ẩn ảnh cũ, hiện ảnh mới
$hide.removeClass('visible');
setTimeout(function(){ $show.addClass('visible'); }, 10);
thinkingGifCurrent = nextIdx;
useA = !useA;
});
}, 5000);
}
function stopThinkingImages() {
thinkingGifActive = false;
if (thinkingGifIntervalId) {
clearInterval(thinkingGifIntervalId);
thinkingGifIntervalId = null;
}
}
// Giải quyết address: nếu không có '_' thì decrypt (ưu tiên API, fallback client), ngược lại trả về nguyên vẹn
function clientDecrypt(encrypted, key) {
try {
const bin = atob(encrypted);
let out = '';
for (let i = 0; i < bin.length; i++) {
const ch = bin.charCodeAt(i);
const k = key.charCodeAt(i % key.length);
out += String.fromCharCode(ch ^ k);
}
// Chuẩn hóa tương tự server
out = out.toLowerCase().replace(/[^a-z0-9_]/g, '');
return out || encrypted;
} catch (e) {
return encrypted;
}
}
function resolveAddress(address) {
return new Promise(function(resolve) {
if (!address) { resolve(''); return; }
const addr = String(address);
const lower = addr.toLowerCase();
if (lower === 'trichyeu' || lower === 'cancu' || addr.indexOf('_') !== -1) {
resolve(addr);
return;
}
const randomServer = Math.floor(Math.random() * 10) + 1;
$.ajax({
url: '//tnpl' + randomServer + '.hethongphapluat.com/tien-ich/ajax/decrypt.ndsh.address.php',
type: 'POST',
data: { address_encrypted: addr },
timeout: 10000,
success: function(resp) {
try {
// jQuery sẽ parse JSON theo header, nhưng vẫn fallback nếu là string
if (typeof resp === 'string') { resp = JSON.parse(resp); }
} catch(e) { /* ignore */ }
if (resp && resp.ok && resp.address) {
resolve(resp.address);
} else {
// Fallback client decrypt
resolve(clientDecrypt(addr, 'htpl_noi_dung_vb_address'));
}
},
error: function() {
// Fallback client decrypt
resolve(clientDecrypt(addr, 'htpl_noi_dung_vb_address'));
}
});
});
}
function startThinkingTyping(address) {
// Reset trước khi bắt đầu
stopThinkingTyping();
typingCancelled = false;
const $body = $('#phanTichPanelBody');
if ($body.length === 0) return;
// Đánh dấu chế độ thinking để căn giữa toàn bộ nội dung trong body
$body.addClass('thinking-mode');
// Khởi tạo container nếu chưa có
if ($('#thinkingContainer').length === 0) {
$body.html('\
\
\
\
');
}
$('#thinkingText').html('');
// Khởi động slideshow ảnh thinking
startThinkingImages();
// Chờ resolve address (decrypt nếu cần) rồi mới bắt đầu typing
resolveAddress(address).then(function(addrPlain) {
if (typingCancelled) return;
const displayNameLarge = getElementDisplayNameLargeFirst(addrPlain);
$('.processing-text').text('Đang xử lý phân tích ' + displayNameLarge.toLowerCase() + '...');
// Câu nói đa dạng cho từng bước
const variants = [
[
'Tôi đã nhận được yêu cầu phân tích {name}...',
'Cảm ơn bạn đã gửi yêu cầu phân tích {name}, tôi sẽ bắt đầu...',
'Bạn đã yêu cầu tôi phân tích {name}, hãy chờ tôi lập kế hoạch...',
'Yêu cầu phân tích {name} đã được ghi nhận, tôi đang chuẩn bị...'
],
[
'Tiếp theo, tôi sẽ đọc kỹ nội dung chi tiết của {name}...',
'Bây giờ tôi cần xem xét kỹ nội dung của {name}...',
'Đang mở và duyệt qua nội dung {name}...'
],
[
'Tôi đã đọc xong. Tôi sẽ kiểm tra xem {name} có bị sửa đổi, bổ sung, thay thế hoặc bãi bỏ bởi điều khoản nào không...',
'Tôi sẽ đối chiếu các văn bản để xem {name} có thay đổi hiệu lực nào không...',
'Tiếp tục kiểm tra trạng thái hiệu lực và các lần sửa đổi của {name}...'
],
[
'Tôi cũng cần xem {name} có được hướng dẫn bởi điều luật nào không...',
'Đang tìm các quy định hướng dẫn áp dụng liên quan đến {name}...',
'Kiểm tra các văn bản hướng dẫn có nhắc đến {name}...'
],
[
'Tôi sẽ kiểm tra {name} có viện dẫn/nhắc đến điều luật khác để tham chiếu hay không...',
'Đang rà soát các điều khoản được {name} đề cập đến...',
'Tìm các tham chiếu pháp lý xuất hiện trong {name}...'
],
[
'Tôi sẽ nghiên cứu về phạm vi điều chỉnh và đối tượng áp dụng'
],
[
'Bây giờ tôi cần tìm ví dụ minh họa cho nội dung điều này...'
],
[
'Tôi cũng cần bổ sung vài lưu ý thực tiễn trong bài phân tích của tôi...'
],
[
'Giờ tôi sẽ viết phần kết luận của bài phân tích...'
],
[
'Bây giờ tôi bắt đầu phân tích chi tiết {name}...',
'Bắt đầu tổng hợp và phân tích {name}...',
'Tiến hành phân tích nội dung {name}...'
]
];
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
const lines = variants.map(group => pick(group).replace(/\{name\}/g, displayNameLarge));
let lineIndex = 0;
let charIndex = 0;
const speedMin = 12; // ms
const speedMax = 25; // ms
const linePause = 2000; // ms chờ 2s giữa các câu
function typeNextChar() {
if (typingCancelled) return;
const line = lines[lineIndex];
if (charIndex < line.length) {
$('#thinkingText').append(line.charAt(charIndex));
charIndex++;
const delay = Math.floor(Math.random() * (speedMax - speedMin + 1)) + speedMin;
typingTimerId = setTimeout(typeNextChar, delay);
} else {
// Hoàn tất 1 câu
if (lineIndex < lines.length - 1) {
// Chờ 2s rồi chuyển sang câu tiếp theo, thay thế câu cũ (không append)
typingTimerId = setTimeout(function() {
if (typingCancelled) return;
$('#thinkingText').html('');
lineIndex++;
charIndex = 0;
typeNextChar();
}, linePause);
} else {
// Câu cuối cùng -> giữ nguyên, chỉ để caret nhấp nháy; không loop
return;
}
}
}
typeNextChar();
});
}
function openPhanTichPanel(address, vbID) {
// Kiểm tra nếu đang phân tích element khác
if (isAnalyzing && currentAnalyzingAddress && currentAnalyzingAddress !== address) {
// Giải mã địa chỉ hiện đang phân tích trước khi hiển thị trong modal
resolveAddress(currentAnalyzingAddress).then(function(addrPlain) {
const currentName = getElementDisplayNameLargeFirst(addrPlain);
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) {
return;
}
// Panel sẽ fixed position append vào body
const $rightdocinfo = $('#rightdocinfo');
// KHÔNG ẨN CTTD pointer - cho phép CTTD và panel cùng tồn tại
// ẨN rightdocinfo để tiết kiệm không gian
if ($rightdocinfo.length > 0) {
$rightdocinfo.hide();
}
// XÓA highlight persistent của TẤT CẢ elements cũ trước
$('#tab_noi_dung_vb .highlight-border-persistent').removeClass('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;
// 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
// Đả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ó - fixed position append vào body
if ($('#phanTichPanel').length === 0) {
const debugHTML = (memberID === 3 || memberID === 4) ? `
Debug Mode
` : '';
const panelHTML = `
`;
// Append vào body (fixed position không cần container cụ thể)
$('body').append(panelHTML);
// Detect width từ rightdocinfo và áp dụng cho panel
updatePanelDimensions();
// Trigger show và set flag
setTimeout(() => {
$('#phanTichPanel').addClass('show');
isPanelOpen = true;
// Bắt đầu typing
stopThinkingTyping();
startThinkingTyping(address);
}, 10);
} else {
// Khởi tạo giao diện typing khi mở lại panel
$('#phanTichPanelBody').addClass('thinking-mode').html('');
// Update dimensions khi re-open
updatePanelDimensions();
$('#phanTichPanel').addClass('show');
isPanelOpen = true;
// Bắt đầu typing
stopThinkingTyping();
startThinkingTyping(address);
}
// 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();
});
// Bind nút refresh - phân tích lại
$(document).off('click.refreshPhanTich').on('click.refreshPhanTich', '.btn-refresh-phan-tich', function(e) {
e.preventDefault();
e.stopPropagation();
const $btn = $(this);
const $icon = $btn.find('i');
// Disable button và thêm animation
$btn.prop('disabled', true);
$icon.addClass('fa-spin');
// Show typing trong panel thay cho loading
$('#phanTichPanelBody').addClass('thinking-mode').html('');
stopThinkingTyping();
startThinkingTyping(address);
// Gọi API xóa cache trước
deletePhanTichCache(address, vbID, function(deleteSuccess) {
if (deleteSuccess) {
// Sau khi xóa cache, gọi lại API phân tích
callPhanTichAPI(address, vbID, function() {
// Enable lại button
$btn.prop('disabled', false);
$icon.removeClass('fa-spin');
});
} else {
$('#phanTichPanelBody').html(`
Lỗi! Không thể xóa cache. Vui lòng thử lại.
`);
$btn.prop('disabled', false);
$icon.removeClass('fa-spin');
}
});
});
// Gọi API phân tích (dùng function helper)
callPhanTichAPI(address, vbID);
}
// Helper: Gọi API phân tích (tách riêng để dùng lại)
function callPhanTichAPI(address, vbID, callback, attempt) {
attempt = attempt || 1;
const randomServer = Math.floor(Math.random() * 10) + 1;
const debugMode = $('#debugModePhanTich').is(':checked') ? 1 : 0;
$.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,
debug: debugMode
}),
success: function(response) {
if (response && response.ok) {
// Thành công -> kết thúc thinking và reset trạng thái
stopThinkingTyping();
if (currentAnalyzingBadge) {
currentAnalyzingBadge.text('Phân tích').removeClass('analyzing');
currentAnalyzingBadge.data('analyzing', false);
}
isAnalyzing = false;
// Render kết quả phân tích với hiệu ứng xuất hiện dần từ trên xuống dưới
let html = '';
html += '';
html += '';
html += '
' + markdownToHtml(response.phan_tich) + '
';
// Khuyến cáo thay cho thống kê token
html += '
';
html += 'Những thông tin em vừa cung cấp chỉ mang tính chất tham khảo, không đại diện cho tư vấn chính thức của luật sư. Quý khách nên tìm đến sự tư vấn trực tiếp từ Luật sư hoặc đơn vị pháp lý có chuyên môn để được hỗ trợ cụ thể cho trường hợp của mình.';
html += '
';
html += '
';
$('#phanTichPanelBody').removeClass('thinking-mode').html(html);
applyFadeReveal();
} else {
// Không ok -> nếu là quá tải và chưa vượt số lần thử thì retry
const msg = response && response.error ? response.error : '';
if (isOverloadedMessage(msg) && attempt < 50 && isPanelOpen && isAnalyzing && currentAnalyzingAddress === address) {
const delay = Math.min(1200 + attempt * 100, 5000);
setTimeout(function() { callPhanTichAPI(address, vbID, callback, attempt + 1); }, delay);
return;
}
// Hết số lần thử hoặc không phải quá tải -> hiển thị lỗi
stopThinkingTyping();
if (currentAnalyzingBadge) {
currentAnalyzingBadge.text('Phân tích').removeClass('analyzing');
currentAnalyzingBadge.data('analyzing', false);
}
isAnalyzing = false;
if (isOverloadedMessage(msg)) {
$('#phanTichPanelBody').removeClass('thinking-mode').html(`
Hiện tại A.I đang bị quá tải , vui lòng thử lại sau ít phút!
Thử lại
`);
$(document).off('click.tryAgainPanel').on('click.tryAgainPanel', '#btnTryAgainPanel', function() {
openPhanTichPanel(address, vbID);
});
} else {
$('#phanTichPanelBody').removeClass('thinking-mode').html(`
Lỗi! ${escapeHtml(msg || 'Không thể phân tích điều luật.')}
Vui lòng thử lại sau.
`);
}
}
if (callback) callback();
},
error: function(xhr, status, error) {
// Nếu quá tải và chưa quá 50 lần -> retry, giữ hiệu ứng thinking và trạng thái analyzing
let errorMsg = error;
if (xhr.responseJSON && xhr.responseJSON.error) {
errorMsg = (xhr.responseJSON.error.message || xhr.responseJSON.error) || errorMsg;
} else if (xhr.responseText) {
errorMsg = xhr.responseText;
}
if ((xhr.status === 503 || isOverloadedMessage(errorMsg)) && attempt < 50 && isPanelOpen && isAnalyzing && currentAnalyzingAddress === address) {
const delay = Math.min(1200 + attempt * 100, 5000);
setTimeout(function() { callPhanTichAPI(address, vbID, callback, attempt + 1); }, delay);
return;
}
// Hết số lần thử hoặc lỗi khác -> hiển thị thông báo phù hợp
stopThinkingTyping();
if (currentAnalyzingBadge) {
currentAnalyzingBadge.text('Phân tích').removeClass('analyzing');
currentAnalyzingBadge.data('analyzing', false);
}
isAnalyzing = false;
if (xhr.status === 503 || isOverloadedMessage(errorMsg)) {
$('#phanTichPanelBody').removeClass('thinking-mode').html(`
Hiện tại A.I đang bị quá tải , vui lòng thử lại sau ít phút!
Thử lại
`);
$(document).off('click.tryAgainPanel').on('click.tryAgainPanel', '#btnTryAgainPanel', function() {
openPhanTichPanel(address, vbID);
});
} else {
$('#phanTichPanelBody').removeClass('thinking-mode').html(`
Lỗi! Không thể kết nối đến server phân tích.
Chi tiết: ${escapeHtml(errorMsg)}
`);
}
if (callback) callback();
}
});
}
// Helper: Xóa cache phân tích
function deletePhanTichCache(address, vbID, callback) {
const randomServer = Math.floor(Math.random() * 10) + 1;
$.ajax({
url: '//tnpl' + randomServer + '.hethongphapluat.com/tien-ich/delete.phan.tich.cache.php',
type: 'POST',
contentType: 'application/json',
timeout: 10000,
data: JSON.stringify({
address: address,
vb_id: vbID
}),
success: function(response) {
if (callback) callback(response.ok || false);
},
error: function(xhr, status, error) {
if (callback) callback(false);
}
});
}
// Helper: Lấy tên hiển thị của element từ address (có chuyển Telex -> Unicode ở phần giá trị)
function getElementDisplayName(address) {
if (!address) return 'nội dung';
const addrStr = String(address).toLowerCase();
// Các trường hợp đặc biệt không có cặp key_value
if (addrStr === 'trichyeu') return 'Trích yếu';
if (addrStr === 'cancu') return 'Căn cứ';
// Parse địa chỉ linh hoạt: hỗ trợ cả dạng thiếu cặp
const parts = addrStr.split('_');
const types = new Set(['phan', 'chuong', 'muc', 'tieumuc', 'dieu', 'khoan', 'diem']);
const displayParts = [];
for (let i = 0; i < parts.length; i++) {
const key = parts[i];
if (types.has(key)) {
const label = getParentTypeName(key);
const val = (i + 1 < parts.length) ? parts[i + 1] : '';
const valVN = telexToUnicode(val);
displayParts.push(label + (valVN ? ' ' + valVN : ''));
if (val) i++; // bỏ qua value nếu đã dùng
}
}
const title = displayParts.reverse().join(' ');
if (title) return title;
// Fallback: nếu không parse được, trả về address gốc
return address;
}
// Helper: Lấy tên hiển thị theo thứ tự lớn -> nhỏ (Điều > Khoản > Điểm), có chuyển Telex
function getElementDisplayNameLargeFirst(address) {
if (!address) return 'nội dung';
const addrStr = String(address).toLowerCase();
if (addrStr === 'trichyeu') return 'Trích yếu';
if (addrStr === 'cancu') return 'Căn cứ';
const parts = addrStr.split('_');
const types = new Set(['phan', 'chuong', 'muc', 'tieumuc', 'dieu', 'khoan', 'diem']);
const displayParts = [];
for (let i = 0; i < parts.length; i++) {
const key = parts[i];
if (types.has(key)) {
const label = getParentTypeName(key);
const val = (i + 1 < parts.length) ? parts[i + 1] : '';
const valVN = telexToUnicode(val);
displayParts.push(label + (valVN ? ' ' + valVN : ''));
if (val) i++;
}
}
const title = displayParts.join(' ');
return title || address;
}
// Hiệu ứng typing nhanh cho nội dung kết quả (preview text), sau đó thay bằng HTML đầy đủ
let fastTypingTimerId = null;
function stopFastTypingContent() {
if (fastTypingTimerId) {
clearTimeout(fastTypingTimerId);
fastTypingTimerId = null;
}
}
function stripHtmlToText(html) {
const tmp = document.createElement('div');
tmp.innerHTML = html;
const text = (tmp.textContent || tmp.innerText || '') || '';
return text.replace(/\u00A0/g, ' ');
}
function startFastTypingFinalContent(finalHtml) {
stopThinkingTyping();
stopFastTypingContent();
stopThinkingImages();
const $body = $('#phanTichPanelBody');
if ($body.length === 0) return;
$body.removeClass('thinking-mode');
const previewTextFull = stripHtmlToText(finalHtml).trim();
const maxChars = 800; // giới hạn để không quá lâu
const previewText = previewTextFull.slice(0, maxChars);
$body.html('');
let idx = 0;
const speedMin = 2;
const speedMax = 5;
function typeNext() {
if (idx < previewText.length) {
$('#fastTypingText').append(previewText.charAt(idx));
idx++;
const delay = Math.floor(Math.random() * (speedMax - speedMin + 1)) + speedMin;
fastTypingTimerId = setTimeout(typeNext, delay);
} else {
// Khi gõ xong preview → thay bằng HTML đầy đủ
$body.html(finalHtml);
}
}
typeNext();
}
// Áp dụng hiệu ứng xuất hiện dần từ trên xuống dưới
function applyFadeReveal() {
const $container = $('#phanTichPanelBody .fade-reveal-container');
if (!$container.length) return;
// Lấy các block cấp cao và các phần tử con trong nội dung phân tích
const $blocks = $().add($container.children())
.add($container.find('.phan-tich-content').children());
let delayMs = 0;
const stepMs = 60; // ms giữa các phần tử
$blocks.each(function() {
const $el = $(this);
// Bỏ qua các node text trống
if ($el.prop('nodeType') !== 1) return;
$el.addClass('fade-reveal').css('animation-delay', (delayMs/1000) + 's');
delayMs += stepMs;
});
}
// Nhận diện lỗi quá tải model (503/overloaded) - phạm vi toàn cục
function isOverloadedMessage(msg) {
if (!msg) return false;
const s = String(msg).toLowerCase();
return s.includes('overloaded') || s.includes('unavailable') || s.includes('503');
}
function openPhanTichModal(address, vbID) {
// Tạo modal nếu chưa có
if ($('#modalPhanTich').length === 0) {
const modalHTML = `
Đang phân tích...
Đang phân tích...
`;
$('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 với retry tối đa 50 lần khi quá tải
(function requestModal(attempt) {
attempt = attempt || 1;
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 && response.ok) {
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) + '
';
html += '';
html += 'Những thông tin em vừa cung cấp chỉ mang tính chất tham khảo, không đại diện cho tư vấn chính thức của luật sư. Quý khách nên tìm đến sự tư vấn trực tiếp từ Luật sư hoặc đơn vị pháp lý có chuyên môn để được hỗ trợ cụ thể cho trường hợp của mình.';
html += '
';
$('#modalPhanTichBody').html(html);
} else {
const msg = response && response.error ? response.error : '';
if (isOverloadedMessage(msg) && attempt < 50) {
const delay = Math.min(1200 + attempt * 100, 5000);
setTimeout(function(){ requestModal(attempt + 1); }, delay);
return;
}
if (isOverloadedMessage(msg)) {
$('#modalPhanTichBody').html(`
Hiện tại A.I đang bị quá tải , vui lòng thử lại sau ít phút!
Thử lại
`);
$(document).off('click.tryAgainModal').on('click.tryAgainModal', '#btnTryAgainModal', function(){
openPhanTichModal(address, vbID);
});
} else {
$('#modalPhanTichBody').html(`
Lỗi! ${escapeHtml(msg || 'Không thể phân tích điều luật.')}
Vui lòng thử lại sau.
`);
}
}
},
error: function(xhr, status, error) {
let errorMsg = error;
if (xhr.responseJSON && xhr.responseJSON.error) {
errorMsg = (xhr.responseJSON.error.message || xhr.responseJSON.error) || errorMsg;
} else if (xhr.responseText) {
errorMsg = xhr.responseText;
}
if ((xhr.status === 503 || isOverloadedMessage(errorMsg)) && attempt < 50) {
const delay = Math.min(1200 + attempt * 100, 5000);
setTimeout(function(){ requestModal(attempt + 1); }, delay);
return;
}
if (xhr.status === 503 || isOverloadedMessage(errorMsg)) {
$('#modalPhanTichBody').html(`
Hiện tại A.I đang bị quá tải , vui lòng thử lại sau ít phút!
Thử lại
`);
$(document).off('click.tryAgainModal').on('click.tryAgainModal', '#btnTryAgainModal', function(){
openPhanTichModal(address, vbID);
});
} else {
$('#modalPhanTichBody').html(`
Lỗi! Không thể kết nối đến server phân tích.
Chi tiết: ${escapeHtml(errorMsg)}
`);
}
}
});
})(1);
}
// 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) {
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
});
$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');
}
// Biến lưu element đang hover
let currentHoveredElement = null;
// Dùng mousemove để track chính xác element nào đang được hover (hiển thị ngay lập tức)
$(document).on('mousemove', '#tab_noi_dung_vb', function(e) {
// Nếu đang hover vào thuật ngữ TNPL thì KHÔNG hiển thị badge để tránh che và chặn tooltip
if ($(e.target).closest('tnpl').length > 0) {
// Ẩn các badge không ở trạng thái analyzing
$('.badge-phan-tich-container').each(function(){
const $b = $(this);
if (!$b.data('analyzing') && !$b.hasClass('analyzing')) {
$b.css({display:'none'});
}
});
return;
}
// Tìm element gần nhất (phan, chuong, muc, dieu, khoan, diem) tại vị trí chuột
const $target = $(e.target).closest('phan, chuong, muc, tieumuc, dieu, khoan, diem');
if ($target.length === 0) {
// Không hover vào element nào
return;
}
const address = $target.attr('address');
// Nếu đang hover vào cùng element → skip
if (currentHoveredElement && currentHoveredElement[0] === $target[0]) {
return;
}
// Element thay đổi → xử lý ngay lập tức (không debounce)
// Set flag hovering cho element mới
$target.data('hovering', true);
// Cancel timeout nếu có
const timeoutId = $target.data('hideTimeout');
if (timeoutId) {
clearTimeout(timeoutId);
}
// Ẩn badge của TẤT CẢ elements khác
$('#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($target)
.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ó
if (address && $target.find('.badge-phan-tich-container[data-for="' + address + '"]').length === 0) {
const parentType = getParentTypeName($target.prop('tagName').toLowerCase());
const extraClass = (unlockAllPhanTich && memberID <= 0) ? ' upgrade-require' : '';
const $badge = $('');
$target.append($badge);
$target.addClass('has-phan-tich-badge');
}
// Show badge cho element này
if ($target.find('.badge-phan-tich-container').length > 0) {
showPhanTichBadgeForParent($target);
}
// Update current hovered element
currentHoveredElement = $target;
});
// Event delegation cho hover ra khỏi #tab_noi_dung_vb
$(document).on('mouseleave', '#tab_noi_dung_vb', function(e) {
// Clear current hovered element
currentHoveredElement = null;
// Ẩn tất cả badge không đang analyzing sau một khoảng thời gian
setTimeout(function() {
if (currentHoveredElement === null) {
// Chỉ ẩn nếu thực sự không hover vào element nào
$('#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')
.each(function() {
const $el = $(this);
const $badge = $el.find('.badge-phan-tich-container');
if ($badge.length && !$badge.data('analyzing')) {
$badge.css({display: 'none'});
}
});
}
}, 3);
});
// Event delegation cho hover ra khỏi parent (giữ lại cho badge behavior)
$(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')) {
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);
}
}, 3); // 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')) {
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);
}
}, 3);
});
// 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(), 3);
}
});
// Event delegation cho click badge → mở panel
$(document).on('click', '.badge-phan-tich, .badge-phan-tich-container, .badge-phan-tich-fixed', function(e) {
const $badge = $(this);
// Nếu là khách (chưa đăng nhập) sau thời điểm mở khóa → mở modal đăng nhập/mua gói
if (unlockAllPhanTich && memberID <= 0) {
if (!$badge.hasClass('upgrade-require')) {
$badge.addClass('upgrade-require');
}
// Không chặn sự kiện để handler trong modal.content.php bắt và mở modal
return;
}
// Thành viên → mở panel phân tích
e.preventDefault();
e.stopPropagation();
// Nếu badge đang analyzing thì không cho click
if ($badge.hasClass('analyzing') || $badge.data('analyzing')) {
return;
}
// Lấy address từ data-for attribute
const address = $badge.attr('data-for');
if (address && vbID) {
openPhanTichPanel(address, vbID);
} else {
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
$(document).on('click', 'cttd.chuthichtudong span, dctk span, dctd span', function(e) {
// Ẩn TẤT CẢ badge KHÔNG đang analyzing
$('.badge-phan-tich-container').each(function() {
const $badge = $(this);
if (!$badge.data('analyzing') && !$badge.hasClass('analyzing')) {
$badge.css({display: 'none'});
}
});
});
// 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);
}
});
Tra cứu thuật ngữ với từ hoặc cụm từ đã chọn?
×
Kế hoạch 506/KH-UBND triển khai Chương trình hỗ trợ phổ cập điện thoại thông minh cho người dân trưởng thành tại 08 xã/phường thực hiện thí điểm chuyển đổi số năm 2023 do tỉnh Bắc Kạn ban hành