Để sử dụng toàn bộ tiện ích nâng cao của Hệ Thống Pháp Luật vui lòng lựa chọn và đăng ký gói cước.
BỘ NỘI VỤ | CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM |
Số: 6139/BNV-TCBC | Hà Nội, ngày 20 tháng 10 năm 2023 |
Kính gửi: | - Các Bộ, cơ quan ngang Bộ, cơ quan thuộc Chính phủ; |
Căn cứ Nghị định số 62/2020/NĐCP ngày 01/6/2020 của Chính phủ về vị trí việc làm và biên chế công chức; Nghị định số 106/2020/NĐ-CP ngày 10/9/2020 của Chính phủ về vị trí việc làm và số lượng người làm việc trong đơn vị sự nghiệp công lập; Thông tư hướng dẫn của các Bộ quản lý ngành, lĩnh vực1. Chỉ đạo các cơ quan, tổ chức hành chính, đơn vị sự nghiệp công lập thuộc phạm vi quản lý xây dựng Đề án vị trí việc làm và cơ cấu ngạch công chức, cơ cấu viên chức theo chức danh nghề nghiệp.
2. Phê duyệt vị trí việc làm và cơ cấu ngạch công chức trong các cơ quan, tổ chức hành chính; vị trí việc làm và cơ cấu viên chức theo chức danh nghề nghiệp trong các đơn vị sự nghiệp công lập thuộc phạm vi quản lý theo phân cấp của Chính phủ, bảo đảm hoàn thành trong năm 2023.
Đề nghị các Bộ, ngành, địa phương quan tâm thực hiện./.
| KT. BỘ TRƯỞNG |
lồng nhau (bên trong) hay không
const memberID = 0;
const vbID = '0248ab0e47e62e67e858c430b3d7241c';
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 && $element.find('.badge-phan-tich').length === 0) {
// Sau khi CTTD load xong, set position: relative cho không còn ảnh hưởng
$element.css('position', 'relative');
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());
const $badge = $('Phân tích');
$element.append($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) {
// 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) {
// Kiểm tra đã có badge chưa
if ($p.find('.badge-phan-tich').length === 0) {
// Set relative cho (lúc này CTTD đã render xong)
$p.css('position', 'relative');
// Lưu address vào data attribute để dùng sau
const address = $parent.attr('address');
$p.attr('data-address', address);
// Lấy tên loại thẻ cho tooltip
const parentType = getParentTypeName($parent.prop('tagName').toLowerCase());
const $badge = $('Phân tích');
$p.append($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, ' ' + para.replace(/\n/g, ' Đang phân tích... Đang phân tích... Đang phân tích... - ĐƠN GIẢN
function showPhanTichBadgeForP($p) {
const $badge = $p.find('.badge-phan-tich');
if ($badge.length === 0) return;
$badge.stop(true, true).fadeIn(200);
const $parent = $p.closest('phan, chuong, muc, tieumuc, dieu, khoan, diem');
if ($parent.length > 0) {
$parent.addClass('highlight-border');
}
}
function hidePhanTichBadgeForP($p) {
const $badge = $p.find('.badge-phan-tich');
if ($badge.length === 0) return;
$badge.stop(true, true).fadeOut(200);
const $parent = $p.closest('phan, chuong, muc, tieumuc, dieu, khoan, diem');
if ($parent.length > 0) {
$parent.removeClass('highlight-border');
}
}
// Event delegation cho hover vào p (bao gồm cả khi hover vào bất kỳ element nào trong p)
$(document).on('mouseenter', '#tab_noi_dung_vb p[data-address], #tab_noi_dung_vb p[data-address] *', function(e) {
const $p = $(this).is('p') ? $(this) : $(this).closest('p[data-address]');
if ($p.length) {
showPhanTichBadgeForP($p);
}
});
// Event delegation cho hover ra khỏi p → ẩn badge và xóa viền thẻ cha
$(document).on('mouseleave', '#tab_noi_dung_vb p[data-address]', function(e) {
// Chỉ ẩn khi thực sự rời khỏi p, không phải chỉ di chuyển giữa các child
const $p = $(this);
setTimeout(() => {
if (!$p.is(':hover')) {
hidePhanTichBadgeForP($p);
}
}, 50);
});
// Event delegation cho hover vào badge (cả gốc và fixed) → hiện tooltip
$(document).on('mouseenter', '.badge-phan-tich, .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 (cả gốc và fixed) → ẩn tooltip
$(document).on('mouseleave', '.badge-phan-tich, .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 (cả gốc và fixed) → mở modal
$(document).on('click', '.badge-phan-tich, .badge-phan-tich-fixed', function(e) {
e.stopPropagation();
let address;
if ($(this).hasClass('badge-phan-tich-fixed')) {
// Badge fixed: lấy address từ data-for
address = $(this).attr('data-for');
} else {
// Badge gốc: lấy từ cha
const $p = $(this).closest('p');
address = $p.attr('data-address');
}
if (address && vbID) {
openPhanTichPanel(address, vbID);
} else {
alert('Không tìm thấy địa chỉ điều luật hoặc ID văn bản!');
}
});
// Attach cho các p đã có sẵn khi hover lần đầu
$(document).on('mouseenter', '#tab_noi_dung_vb p', function() {
const $p = $(this);
if ($p.find('.badge-phan-tich').length === 0 && !$p.attr('data-address')) {
const $parent = $p.closest('phan, chuong, muc, tieumuc, dieu, khoan, diem');
if ($parent.length > 0) {
attachPhanTichBadge($p.parent());
}
}
});
}
});
$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
');
// Lists (ordered)
html = html.replace(/^\d+\. (.*$)/gim, '
') + '' + 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 += '
Vui lòng thử lại sau.
Chi tiết: ${escapeHtml(errorMsg)}
' + 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 += '
Vui lòng thử lại sau.
Chi tiết: ${escapeHtml(errorMsg)}