Để 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Ộ XÂY DỰNG | CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM | 
| Số: 2396/BXD-KTXD | Hà Nội, ngày 12 tháng 6 năm 2023 | 
Kính gửi: Sở Xây dựng thành phố Hồ Chí Minh
Bộ Xây dựng nhận được văn bản số 3290/SXD-VLXD ngày 14/3/2023 của Sở Xây dựng thành phố Hồ Chí Minh đề nghị hướng dẫn một số khó khăn, vướng mắc trong công tác công bố giá vật liệu xây dựng là khoáng sản trên địa bàn thành phố Hồ Chí Minh. Sau khi xem xét, Bộ Xây dựng có ý kiến như sau:
1. Theo quy định của pháp luật về việc quản lý giá vật liệu xây dựng tại Điểm a Khoản 3 Điều 8 Thông tư số 11/2021/TT-BXD thì giá vật liệu xây dựng được công bố phải phù hợp với giá thị trường, tiêu chuẩn chất lượng, nguồn gốc xuất xứ, khả năng và phạm vi cung ứng vật liệu tại thời điểm công bố.
2. Theo quy định tại Quy chuẩn kỹ thuật Quốc gia về sản phẩm, hàng hóa vật liệu xây dựng (hiện nay là QCVN 16:2019/BXD-TQC ban hành kèm theo Thông tư số 19/2019/TT-BXD ngày 31/12/2019 của Bộ trưởng Bộ Xây dựng) thì sản phẩm, hàng hóa vật liệu xây dựng nói chung được kinh doanh tại thị trường và sử dụng vào các công trình xây dựng trên lãnh thổ Việt Nam phải đảm bảo tuân thủ các quy định về tiêu chuẩn, yêu cầu quản lýĐề nghị Sở Xây dựng thành phố Hồ Chí Minh nghiên cứu các quy định nêu trên tổ chức rà soát hợp chuẩn, hợp quy vật liệu xây dựng trên thị trường đảm bảo quản lý, công bố giá vật liệu xây dựng theo quy định./.
| 
 | TL. BỘ TRƯỞNG | 
 
 lồng nhau (bên trong) hay không
    const memberID = 0;
    const vbID = 'c16146d2fa6ae667643fdc325677425f';
    
    // 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
    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) {
        }
    }
    $(window).on('scroll resize', function () {
        processVisibleParagraphs();
    });
    
    processVisibleParagraphs();
    // Chức năng phân tích điều luật (chỉ cho member_id = 4)
    if (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 = `
                     ' + message + ' 
                        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, ' ' + para.replace(/\n/g, ' Đang phân tích... Đang phân tích... Đang xóa cache và phân tích lại... Đang phân tích...$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) + '';
                        if (response.from_cache) {
                            html += ' Cache';
                        }
                        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)}
                        
 
              