ỦY BAN NHÂN DÂN TỈNH BẾN TRE -------
CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM Độc lập - Tự do - Hạnh phúc ---------------
Số: 1549/QĐ-UBND
Bến Tre, ngày 20 tháng 7 năm 2023
QUYẾT ĐỊNH
VỀ VIỆC CÔNG BỐ DANH MỤC 01 THỦ TỤC HÀNH CHÍNH BAN HÀNH MỚI; 01 THỦ TỤC HÀNH CHÍNH ĐƯỢC SỬA ĐỔI, BỔ SUNG; 02 THỦ TỤC HÀNH CHÍNH BỊ BÃI BỎ TRONG LĨNH VỰC GIÁM ĐỊNH TƯ PHÁP XÂY DỰNG THUỘC THẨM QUYỀN GIẢI QUYẾT CỦA SỞ XÂY DỰNG TỈNH BẾN TRE
CHỦ TỊCH ỦY BAN NHÂN DÂN TỈNH BẾN TRE
Căn cứ Luật Tổ chức chính quyền địa phương ngày 19 tháng 6 năm 2015;
Căn cứ Luật sửa đổi, bổ sung một số điều của Luật Tổ chức Chính phủ và Luật Tổ chức chính quyền địa phương ngày 22 tháng 11 năm 2019;
Căn cứ Nghị định số 63/2010/NĐ-CP ngày 08 tháng 6 năm 2010 của Chính phủ về kiểm soát thủ tục hành chính và Nghị định số 92/2017/NĐ-CP ngày 07 tháng 8 năm 2017 của Chính phủ sửa đổi, bổ sung một số điều của các nghị định liên quan đến kiểm soát thủ tục hành chính;
Căn cứ Thông tư số 02/2017/TT-VPCP ngày 31 tháng 10 năm 2017 của Văn phòng Chính phủ hướng dẫn về nghiệp vụ kiểm soát thủ tục hành chính;
Căn cứ Thông tư số 01/2023/TT-VPCP ngày 05 tháng 4 năm 2023 của Văn phòng Chính phủ quy định một số nội dung và biện pháp thi hành trong số hóa hồ sơ, kết quả giải quyết thủ tục hành chính trên môi trường điện tử;
Căn cứ Quyết định số 694/QĐ-BXD ngày 03 tháng 7 năm 2023 của Bộ Xây dựng về việc công bố thủ tục hành chính mới ban hành; thủ tục hành chính được sửa đổi, bổ sung hoặc thay thế; thủ tục hành chính bị hủy bỏ hoặc bãi bỏ trong lĩnh vực giám định tư pháp xây dựng thuộc phạm vi và chức năng quản lý nhà nước của Bộ Xây dựng;
Theo đề nghị của Giám đốc Sở Xây dựng tại Tờ trình số 1539/TTr-SXD ngày 07 tháng 7 năm 2023.
QUYẾT ĐỊNH:
Điều 1. Công bố kèm theo Quyết định này 01 thủ tục hành chính ban hành mới; 01 thủ tục hành chính được sửa đổi, bổ sung; 02 thủ tục hành chính bị bãi bỏ trong lĩnh vực giám định tư pháp xây dựng thuộc thẩm quyền giải quyết của Sở Xây dựng tỉnh Bến Tre (Phụ lục kèm theo).
Điều 2. Quyết định này có hiệu lực kể từ ngày ký. Bãi bỏ 03 thủ tục hành chính trong lĩnh vực giám định tư pháp xây dựng (thứ tự số 7, 8 và 9 danh mục thủ tục hành chính ban hành mới) ban hành kèm theo Quyết định số 555/QĐ-UBND ngày 16 tháng 3 năm 2017 của Ủy ban nhân dân tỉnh về công bố 10 thủ tục hành chính ban hành mới, 08 thủ tục hành chính bị bãi bỏ thuộc thẩm quyền giải quyết của Sở Xây dựng.
Điều 3. Giao Sở Xây dựng tham mưu dự thảo Quyết định phê duyệt 01 quy trình ban hành mới và sửa đổi, bổ sung 01 quy trình nội bộ (số 28) lĩnh vực giám định tư pháp xây dựng ban hành kèm theo Quyết định số 1233/QĐ-UBND ngày 15 tháng 6 năm 2022 của Ủy ban nhân dân tỉnh phê duyệt 02 quy trình nội bộ được sửa đổi, bổ sung trong lĩnh vực quản lý chất lượng công trình xây dựng, 03 quy trình nội bộ được sửa đổi, bổ sung trong lĩnh vực giám định tư pháp xây dựng và 08 quy trình nội bộ được sửa đổi, bổ sung trong lĩnh vực nhà ở thuộc thẩm quyền tiếp nhận và giải quyết định của Sở Xây dựng tỉnh Bến Tre, trình Chủ tịch Ủy ban nhân dân tỉnh phê duyệt.
Điều 4. Bãi bỏ 02 quy trình nội bộ (số 29 và 30) lĩnh vực giám định tư pháp xây dựng ban hành kèm theo Quyết định số 1233/QĐ-UBND ngày 15 tháng 6 năm 2022 của Ủy ban nhân dân tỉnh phê duyệt 02 quy trình nội bộ được sửa đổi, bổ sung trong lĩnh vực quản lý chất lượng công trình xây dựng, 03 quy trình nội bộ được sửa đổi, bổ sung trong lĩnh vực giám định tư pháp xây dựng và 08 quy trình nội bộ được sửa đổi, bổ sung trong lĩnh vực nhà ở thuộc thẩm quyền tiếp nhận và giải quyết định của Sở Xây dựng tỉnh Bến Tre.
Điều 5. Chánh Văn phòng Ủy ban nhân dân tỉnh, Giám đốc Sở Xây dựng và tổ chức, cá nhân có liên quan chịu trách nhiệm thi hành Quyết định này./.
Nơi nhận: - Như Điều 5; - Bộ Xây dựng; - Cục Kiểm soát TTHC - VPCP; - Chủ tịch, các PCT.UBND tỉnh; - Các PCVP.UBND tỉnh; - Sở Xây dựng; - Phòng KSTT, TCĐT, TTPVHCC; - Cổng Thông tin điện tử tỉnh; - Lưu: VT, Nghị.
CHỦ TỊCH Trần Ngọc Tam
PHỤ LỤC I
DANH MỤC THỦ TỤC HÀNH CHÍNH THUỘC THẨM QUYỀN GIẢI QUYẾT CỦA SỞ XÂY DỰNG TỈNH BẾN TRE (Kèm theo Quyết định số 1549/QĐ-UBND ngày 20 tháng 7 năm 2023 của Ủy ban nhân dân tỉnh Bến Tre)
1. Danh mục thủ tục hành chính ban hành mới:
Số TT
Tên thủ tục hành chính
Thời hạn giải quyết
Địa điểm thực hiện
Phí, lệ phí
Căn cứ pháp lý
Lĩnh vực: Giám định tư pháp xây dựng
1
Miễn nhiệm và thu hồi thẻ giám định viên tư pháp xây dựng ở địa phương
10 ngày
Trung tâm Phục vụ hành chính công tỉnh Bến Tre, số 126A, đường Nguyễn Thị Định, phường Phú Tân, thành phố Bến Tre, tỉnh Bến Tre
Không có
- Luật Giám định tư pháp số 13/2012/QH13: Luật số 56/2020/QH14 sửa đổi, bổ sung một số điều của Luật Giám định tư pháp;
- Nghị định số 35/2023/NĐ-CP ngày 20/6/2023 của Chính phủ sửa đổi, bổ sung một số điều của các Nghị định thuộc lĩnh vực quản lý nhà nước của Bộ Xây dựng;
- Thông tư số 17/2021/TT-BXD ngày 22/12/2021 của Bộ Xây dựng quy định một số nội dung về hoạt động giám định tư pháp trong lĩnh vực xây dựng.
2. Danh mục thủ tục hành chính được sửa đổi, bổ sung
STT
Mã TTHC
Tên thủ tục hành chính
Tên văn bản quy định nội dung sửa đổi, bổ sung
Lĩnh vực: Giám định tư pháp xây dựng
1
2.001116
Bổ nhiệm và cấp thẻ giám định viên tư pháp xây dựng ở địa phương
- Luật Giám định tư pháp số 13/2012/QH13.
- Nghị định số 35/2023/NĐ-CP ngày 20/6/2023 của Chính phủ sửa đổi, bổ sung một số điều của các Nghị định thuộc lĩnh vực quản lý nhà nước của Bộ Xây dựng.
- Thông tư số 17/2021/TT-BXD ngày 22/12/2021 của Bộ Xây dựng quy định một số nội dung về hoạt động giám định tư pháp trong lĩnh vực xây dựng.
- Thông tư số 11/2020/TT-BTP ngày 31/12/2020 của Bộ Tư pháp quy định về mẫu thẻ, trình tự, thủ tục cấp mới, cấp lại thẻ giám định viên tư pháp.
3. Danh mục thủ tục hành chính bị bãi bỏ
STT
Mã TTHC
Tên thủ tục hành chính
Tên văn bản quy phạm pháp luật quy định việc bãi bỏ thủ tục hành chính
Lĩnh vực: Giám định tư pháp xây dựng
1
1.002515
Đăng ký công bố thông tin người giám định tư pháp xây dựng theo vụ việc, tổ chức giám định tư pháp xây dựng theo vụ việc đối với các cá nhân, tổ chức không thuộc thẩm quyền của Bộ Xây dựng, văn phòng giám định tư pháp xây dựng trên địa bàn được Ủy ban nhân dân tỉnh cho phép hoạt động
- Luật Giám định tư pháp số 13/2012/QH13;
- Điều 9 Thông tư số 04/2014/TT-BXD ngày 22/4/2014 của Bộ Xây dựng hướng dẫn một số nội dung về giám định tư pháp trong hoạt động đầu tư xây dựng;
- Điều 2, Điều 3, Điều 4 Nghị định số 62/2016/NĐ-CP (quy định này thay thế Điều 5, Điều 6, Điều 7 Thông tư số 04/2014/TT-BXD đã bị bãi bỏ bởi Thông tư số 23/2016/TT-BXD ngày 01/7/2016 của Bộ Xây dựng bãi bỏ toàn bộ hoặc một phần văn bản quy phạm pháp luật có quy định về điều kiện đầu tư kinh doanh do Bộ Xây dựng ban hành).
2
1.002621
Điều chỉnh, thay đổi thông tin cá nhân, tổ chức giám định tư pháp xây dựng đối với cá nhân, tổ chức do Ủy ban nhân dân cấp tỉnh đã tiếp nhận đăng ký, công bố thông tin
PHỤ LỤC II
NỘI DUNG THỦ TỤC HÀNH CHÍNH THUỘC THẨM QUYỀN GIẢI QUYẾT CỦA SỞ XÂY DỰNG (Kèm theo Quyết định số 1549/QĐ-UBND ngày 20 tháng 7 năm 2023 của Ủy ban nhân dân tỉnh Bến Tre)
LĨNH VỰC: GIÁM ĐỊNH TƯ PHÁP XÂY DỰNG
I. THỦ TỤC HÀNH CHÍNH BAN HÀNH MỚI
1. Thủ tục: Miễn nhiệm, thu hồi thẻ giám định viên tư pháp xây dựng ở địa phương - Mã TTHC: 1.011675
- Trình tự thực hiện:
+ Cơ quan, tổ chức quản lý giám định viên tư pháp lập hồ sơ miễn nhiệm và thu hồi thẻ giám định viên tư pháp xây dựng gửi 01 bộ hồ sơ trực tiếp tại Trung tâm Phục vụ hành chính công tỉnh (địa chỉ: Số 126A, Nguyễn Thị Định, Phường Phú Tân, thành phố Bến Tre, tỉnh Bến Tre) hoặc qua đường bưu điện hoặc trực tuyến. Thời gian tiếp nhận hồ sơ: Từ thứ Hai đến thứ Sáu hàng tuần vào giờ hành chính (sáng 07 giờ đến 11 giờ, chiều 13 giờ đến 17 giờ) (trừ ngày lễ, tết).
+ Sở Xây dựng chủ trì phối hợp với Sở Tư pháp tiếp nhận, kiểm tra hồ sơ đề nghị miễn nhiệm và thu hồi thẻ giám định viên tư pháp, trình Chủ tịch Ủy ban nhân dân cấp tỉnh xem xét, quyết định;
+ Trong vòng 10 ngày kể từ khi nhận được hồ sơ hợp lệ theo quy định, Chủ tịch Ủy ban nhân dân cấp tỉnh ra quyết định miễn nhiệm và thu hồi thẻ giám định viên tư pháp xây dựng;
+ Đến ngày hẹn tổ chức, cá nhân mang phiếu hẹn đến Trung tâm Phục vụ hành chính công để nhận kết quả hoặc trả kết quả qua đường bưu điện (nếu tổ chức, cá nhân có yêu cầu).
- Cách thức thực hiện:
Nộp hồ sơ theo 01 trong 03 cách thức sau:
+ Nộp trực tiếp tại Bộ phận Một cửa;
+ Gửi qua đường bưu điện;
+ Nộp trực tuyến trên Cổng Dịch vụ công của tỉnh tại địa chỉ https://dichvucong.bentre.gov.vn/ hoặc Cổng dịch vụ công quốc gia tại địa chỉ https://dichvucong.gov.vn/
- Thành phần, số lượng hồ sơ:
a) Thành phần hồ sơ:
+ Văn bản đề nghị miễn nhiệm giám định viên tư pháp của cơ quan, tổ chức quản lý giám định viên tư pháp hoặc đơn xin miễn nhiệm của giám định viên tư pháp (theo mẫu số 01 kèm theo Quyết định này)+ Văn bản, giấy tờ chứng minh giám định viên tư pháp thuộc một trong các trường hợp quy định tại khoản 1 Điều 10 Luật Giám định tư pháp được sửa đổi, bổ sung tại khoản 6 Điều 1 Luật số 56/2020/QH14*, cụ thể như sau:
• Không còn đủ tiêu chuẩn quy định tại khoản 1 Điều 7 của Luật Giám định tư pháp;
• Thuộc một trong các trường hợp quy định tại khoản 2 Điều 7 của Luật Giám định tư pháp;
• Bị xử lý kỷ luật từ hình thức cảnh cáo trở lên hoặc bị xử phạt vi phạm hành chính do cố ý vi phạm quy định của pháp luật về giám định tư pháp;
• Thực hiện một trong các hành vi quy định tại Điều 6 của Luật Giám định tư pháp;
• Có quyết định nghỉ hưu hoặc quyết định thôi việc, trừ trường hợp có văn bản thể hiện nguyện vọng tiếp tục tham gia hoạt động giám định tư pháp và cơ quan, tổ chức quản lý trực tiếp có nhu cầu sử dụng phù hợp với quy định của pháp luật;
• Chuyển đổi vị trí công tác hoặc chuyển công tác sang cơ quan, tổ chức khác mà không còn điều kiện phù hợp để tiếp tục thực hiện giám định tư pháp;
• Theo đề nghị của giám định viên tư pháp. Trường hợp giám định viên tư pháp là công chức, viên chức, sĩ quan quân đội, sĩ quan công an nhân dân, quân nhân chuyên nghiệp, công nhân quốc phòng thì phải được sự chấp thuận của cơ quan, tổ chức quản lý trực tiếp;
• Giám định viên tư pháp được bổ nhiệm để thành lập Văn phòng giám định tư pháp nhưng sau thời hạn 01 năm, kể từ ngày được bổ nhiệm không thành lập Văn phòng hoặc sau thời hạn 01 năm, kể từ ngày có quyết định cho phép thành lập Văn phòng mà không đăng ký hoạt động.
b) Số lượng hồ sơ: 01 bộ.
- Thời hạn giải quyết: Trong thời hạn 10 ngày, kể từ ngày nhận được hồ sơ hợp lệ.
- Đối tượng thực hiện thủ tục hành chính: Cá nhân ở địa phương.
- Cơ quan thực hiện thủ tục hành chính:
+ Cơ quan có thẩm quyền quyết định: Ủy ban nhân dân cấp tỉnh.
+ Cơ quan đầu mối giải quyết: Sở Xây dựng chủ trì phối hợp với Sở Tư pháp.
- Kết quả thực hiện thủ tục hành chính: Quyết định miễn nhiệm và thu hồi thẻ giám định viên tư pháp xây dựng.
- Phí, lệ phí: Không.
- Tên mẫu đơn, mẫu tờ khai: Văn bản đề nghị miễn nhiệm, thu hồi thẻ giám định viên tư pháp xây dựng (theo Mẫu số 01. Văn bản đề nghị miễn nhiệm, thu hồi thẻ giám định viên tư pháp xây dựng).
- Yêu cầu, điều kiện thực hiện thủ tục hành chính: Khoản 1 Điều 10 Luật Giám định tư pháp được sửa đổi, bổ sung tại khoản 6 Điều 1 Luật số 56/2020/QH14, cụ thể như sau:
+ Không còn đủ tiêu chuẩn quy định tại khoản 1 Điều 7 của Luật Giám định tư pháp;
+ Thuộc một trong các trường hợp quy định tại khoản 2 Điều 7 của Luật Giám định tư pháp;
+ Bị xử lý kỷ luật từ hình thức cảnh cáo trở lên hoặc bị xử phạt vi phạm hành chính do cố ý vi phạm quy định của pháp luật về giám định tư pháp;
+ Thực hiện một trong các hành vi quy định tại Điều 6 của Luật Giám định tư pháp;
+ Có quyết định nghỉ hưu hoặc quyết định thôi việc, trừ trường hợp có văn bản thể hiện nguyện vọng tiếp tục tham gia hoạt động giám định tư pháp và cơ quan, tổ chức quản lý trực tiếp có nhu cầu sử dụng phù hợp với quy định của pháp luật;
+ Chuyển đổi vị trí công tác hoặc chuyển công tác sang cơ quan, tổ chức khác mà không còn điều kiện phù hợp để tiếp tục thực hiện giám định tư pháp;
+ Theo đề nghị của giám định viên tư pháp. Trường hợp giám định viên tư pháp là công chức, viên chức, sĩ quan quân đội, sĩ quan công an nhân dân, quân nhân chuyên nghiệp, công nhân quốc phòng thì phải được sự chấp thuận của cơ quan, tổ chức quản lý trực tiếp;
+ Giám định viên tư pháp được bổ nhiệm để thành lập Văn phòng giám định tư pháp nhưng sau thời hạn 01 năm, kể từ ngày được bổ nhiệm không thành lập Văn phòng hoặc sau thời hạn 01 năm, kể từ ngày có quyết định cho phép thành lập Văn phòng mà không đăng ký hoạt động.
- Căn cứ pháp lý của thủ tục hành chính:
+ Luật Giám định tư pháp số 13/2012/QH13: Luật số 56/2020/QH14 sửa đổi, bổ sung một số điều của Luật Giám định tư pháp;
+ Nghị định số 35/2023/NĐ-CP ngày 20/6/2023 của Chính phủ sửa đổi, bổ sung một số điều của các Nghị định thuộc lĩnh vực quản lý nhà nước của Bộ Xây dựng;
+ Thông tư số 17/2021/TT-BXD ngày 22/12/2021 của Bộ Xây dựng quy định một số nội dung về hoạt động giám định tư pháp trong lĩnh vực xây dựng.
Mẫu số 01. Văn bản đề nghị miễn nhiệm, thu hồi thẻ giám định viên tư pháp xây dựng
(Ban hành kèm theo Thông tư số 17/2021/TT-BTP ngày 22 tháng 12 năm 2021 của Bộ trưởng Bộ Xây dựng)
……(1)….. -------
CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM Độc lập - Tự do - Hạnh phúc ---------------
Số: ………..
….., ngày .... tháng .... năm 20....
VĂN BẢN ĐỀ NGHỊ MIỄN NHIỆM, THU HỒI THẺ GIÁM ĐỊNH VIÊN TƯ PHÁP XÂY DỰNG
Kính gửi: Chủ tịch Ủy ban nhân dân tỉnh ………….
Sau khi xem xét hồ sơ đề nghị miễn nhiệm, thu hồi thẻ của các cá nhân, đáp ứng tiêu chuẩn của giám định viên tư pháp xây dựng theo quy định, …..(1).... đề nghị Chủ tịch Ủy ban nhân dân tỉnh miễn nhiệm, thu hồi thẻ giám định viên tư pháp xây dựng cho các cá nhân như sau:
TT
Họ và tên
Mã số định danh/ Căn cước công dân/ Chứng minh nhân dân/
(2)
Đăng ký đối tượng, nội dung giám định
(3)
Ghi chú
(4)
1
……..
……..
……..
……..
2
……..
……..
……..
……..
Hồ sơ cá nhân đề nghị miễn nhiệm, thu hồi thẻ kèm theo văn bản này.
………(1)…….. (Ghi rõ họ tên, chữ ký, chức vụ, dấu pháp nhân)
____________________
(1) Tên tổ chức đề nghị miễn nhiệm giám định viên tư pháp xây dựng
(2) Chứng minh nhân dân/căn cước công dân (ghi số, ngày cấp, nơi cấp)
(3) Nội dung giám định (ghi nội dung giám định theo quy định lại Điều 3 Thông tư này); đối tượng giám định (kê khai loại, cấp công trình)
(4) Tên, địa chỉ, số điện thoại liên hệ của tổ chức, cá nhân đề nghị.
II. THỦ TỤC HÀNH CHÍNH ĐƯỢC SỬA ĐỔI, BỔ SUNG
1. Thủ tục: Bổ nhiệm và cấp thẻ giám định viên tư pháp xây dựng ở địa phương - Mã TTHC: 2.001116
- Trình tự thực hiện:
+ Cơ quan, tổ chức quản lý giám định viên tư pháp gửi hồ sơ đề nghị bổ nhiệm, cấp thẻ giám định viên tư pháp xây dựng trực tiếp tại Trung tâm Phục vụ hành chính công tỉnh (địa chỉ: Số 126A, Nguyễn Thị Định, Phường Phú Tân, thành phố Bến Tre, tỉnh Bến Tre) hoặc qua đường bưu điện hoặc trực tuyến. Thời gian tiếp nhận hồ sơ: Từ thứ Hai đến thứ Sáu hàng tuần vào giờ hành chính (sáng 07 giờ đến 11 giờ, chiều 13 giờ đến 17 giờ) (trừ ngày lễ, tết).
+ Sở Xây dựng chủ trì, phối hợp với Sở Tư pháp lựa chọn người có đủ tiêu chuẩn, đề nghị Chủ tịch Ủy ban nhân dân cấp tỉnh bổ nhiệm, cấp thẻ giám định viên tư pháp theo quy định;
+ Trong vòng 20 ngày kể từ khi nhận được hồ sơ hợp lệ theo quy định, Chủ tịch Ủy ban nhân dân cấp tỉnh ra quyết định bổ nhiệm giám định viên tư pháp xây dựng. Trường hợp từ chối phải thông báo cho người đề nghị bằng văn bản và nêu rõ lý do;
+ Trong thời hạn 10 ngày, kể từ ngày nhận được quyết định bổ nhiệm và cấp thẻ giám định viên tư pháp kèm theo hồ sơ, Chủ tịch Ủy ban nhân dân cấp tỉnh cấp thẻ giám định viên tư pháp.
+ Đến ngày hẹn tổ chức, cá nhân mang phiếu hẹn đến Trung tâm Phục vụ hành chính công để nhận kết quả hoặc trả kết quả qua đường bưu điện (nếu tổ chức, cá nhân có yêu cầu).
- Cách thức thực hiện:
Nộp hồ sơ theo 01 trong 03 cách thức sau:
+ Nộp trực tiếp tại Bộ phận Một cửa;
+ Gửi qua đường bưu điện;
+ Nộp trực tuyến trên Cổng Dịch vụ công của tỉnh tại địa chỉ https://dichvucong.bentre.gov.vn/ hoặc Cổng dịch vụ công quốc gia tại địa chỉ https://dichvucong.gov.vn/
- Thành phần hồ sơ, số lượng hồ sơ:
a) Thành phần hồ sơ:
+ Văn bản đề nghị bổ nhiệm, cấp thẻ giám định viên tư pháp xây dựng hoặc đơn đề nghị bổ nhiệm giám định viên tư pháp của cá nhân đã là giám định viên tư pháp nhưng bị miễn nhiệm do nghỉ hưu hoặc thôi việc để thành lập Văn phòng giám định tư pháp (theo mẫu số 02 kèm theo Quyết định này+ Bản sao bằng tốt nghiệp đại học trở lên phù hợp với lĩnh vực chuyên môn được đề nghị bổ nhiệm*;
+ Sơ yếu lý lịch và Phiếu lý lịch tư pháp. Trường hợp người được đề nghị bổ nhiệm giám định viên tư pháp đang là công chức, viên chức thì không cần có Phiếu lý lịch tư pháp*;
+ Giấy xác nhận về thời gian thực tế hoạt động chuyên môn của cơ quan, tổ chức nơi người được đề nghị bổ nhiệm làm việc*;
+ Bản sao Chứng chỉ hành nghề hoạt động xây dựng hoặc bản kê khai điều kiện năng lực phù hợp với tiêu chuẩn giám định viên tư pháp xây dựng quy định (nếu có)*.
+ 02 ảnh màu chân dung cỡ 2cm x 3cm (chụp trong vòng 06 tháng gần nhất).
b) Số lượng hồ sơ: 01 bộ.
- Thời hạn giải quyết: Trong thời hạn 30 ngày, kể từ ngày nhận được hồ sơ hợp lệ (bao gồm 20 ngày quyết định bổ nhiệm giám định viên tư pháp và 10 ngày cấp thẻ giám định viên tư pháp)
- Đối tượng thực hiện thủ tục hành chính: Cá nhân ở địa phương.
- Cơ quan thực hiện thủ tục hành chính:
+ Cơ quan có thẩm quyền quyết định: Ủy ban nhân dân cấp tỉnh;
+ Cơ quan đầu mối giải quyết: Sở Xây dựng phối hợp với Sở Tư pháp.
- Kết quả thực hiện thủ tục hành chính: Quyết định bổ nhiệm giám định viên tư pháp xây dựng và thẻ giám định viên tư pháp xây dựng.
- Phí, lệ phí: Không
- Tên mẫu đơn, mẫu tờ khai: Văn bản đề nghị bổ nhiệm, cấp thẻ giám định viên tư pháp xây dựng (theo mẫu số 02 kèm theo Quyết định này)
- Yêu cầu, điều kiện thực hiện thủ tục hành chính:
Giám định viên tư pháp xây dựng phải đáp ứng tiêu chuẩn quy định tại khoản 1 Điều 7 Luật Giám định tư pháp số 13/2012/QH13; trong đó, tiêu chuẩn hoạt động chuyên môn phù hợp được quy định như sau:
1. Trường hợp giám định tư pháp về sự tuân thủ các quy định của pháp luật
a) Đối với giám định sự tuân thủ các quy định của pháp luật về quy hoạch xây dựng: phải có chứng chỉ hành nghề thiết kế quy hoạch xây dựng theo quy định của pháp luật về xây dựng hoặc có kinh nghiệm quản lý nhà nước đủ 05 năm trở lên về quy hoạch xây dựng, phù hợp với đối tượng và nội dung giám định;
b) Đối với giám định sự tuân thủ các quy định của pháp luật về hoạt động đầu tư xây dựng: phải đáp ứng điều kiện năng lực hoạt động xây dựng theo quy định của pháp luật về xây dựng để thực hiện một trong các công việc khảo sát xây dựng, thiết kế xây dựng, giám sát thi công xây dựng, định giá xây dựng, quản lý dự án đầu tư xây dựng, kiểm định xây dựng hoặc có kinh nghiệm quản lý nhà nước đủ 05 năm trở lên về hoạt động xây dựng, phù hợp với đối tượng và nội dung giám định;
c) Đối với giám định sự tuân thủ các quy định của pháp luật về nhà ở và kinh doanh bất động sản: phải có kinh nghiệm quản lý nhà nước đủ 05 năm trở lên về nhà ở và thị trường bất động sản, phù hợp với đối tượng và nội dung giám định.
2. Trường hợp giám định tư pháp về chất lượng xây dựng công trình
a) Đối với giám định chất lượng khảo sát xây dựng hoặc thiết kế xây dựng: phải có chứng chỉ hành nghề khảo sát xây dựng hoặc thiết kế xây dựng theo quy định của pháp luật về xây dựng, phù hợp với đối tượng và nội dung giám định;
b) Đối với giám định chất lượng công trình xây dựng, bộ phận công trình xây dựng; giám định nguyên nhân sự cố công trình xây dựng, nguyên nhân hư hỏng công trình xây dựng: phải đáp ứng điều kiện hành nghề kiểm định xây dựng theo quy định của pháp luật về xây dựng, phù hợp với đối tượng và nội dung giám định.
3. Trường hợp giám định chi phí xây dựng công trình, giá trị nhà ở và bất động sản: phải có chứng chỉ hành nghề định giá xây dựng theo quy định của pháp luật về xây dựng hoặc có kinh nghiệm quản lý nhà nước đủ 05 năm trở lên, phù hợp với đối tượng và nội dung giám định.
- Căn cứ pháp lý của thủ tục hành chính:
+ Luật Giám định tư pháp số 13/2012/QH13; Luật số 56/2020/QH14 sửa đổi, bổ sung một số điều của Luật Giám định tư pháp;
+ Nghị định số 35/2023/NĐ-CP ngày 20/6/2023 của Chính phủ sửa đổi, bổ sung một số điều của các Nghị định thuộc lĩnh vực quản lý nhà nước của Bộ Xây dựng;
+ Thông tư số 17/2021/TT-BXD ngày 22/12/2021 của Bộ Xây dựng quy định một số nội dung về hoạt động giám định tư pháp trong lĩnh vực xây dựng;
+ Thông tư số 11/2020/TT-BTP ngày 31/12/2020 của Bộ Tư pháp quy định về mẫu thêm, trình tự, thủ tục cấp mới, cấp lại thẻ giám định viên tư pháp.
Ghi chú: Phần chữ in nghiêng không đậm là nội dung được sửa đổi, bổ sung.
Mẫu số 02. Văn bản đề nghị miễn nhiệm, thu hồi thẻ giám định viên tư pháp xây dựng
(Ban hành kèm theo Thông tư số 17/2021/TT-BTP ngày 22 tháng 12 năm 2021 của Bộ trưởng Bộ Xây dựng)
……(1)….. -------
CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM Độc lập - Tự do - Hạnh phúc ---------------
Số: ………..
….., ngày .... tháng .... năm 20....
VĂN BẢN ĐỀ NGHỊ MIỄN NHIỆM, THU HỒI THẺ GIÁM ĐỊNH VIÊN TƯ PHÁP XÂY DỰNG
Kính gửi: Chủ tịch Ủy ban nhân dân tỉnh ……….
Sau khi xem xét hồ sơ đề nghị miễn nhiệm, thu hồi thẻ của các cá nhân, đáp ứng tiêu chuẩn của giám định viên tư pháp xây dựng theo quy định, ……(1)...... đề nghị Chủ tịch Ủy ban nhân dân tỉnh miễn nhiệm, thu hồi thẻ giám định viên tư pháp xây dựng cho các cá nhân như sau:
TT
Họ và tên
Mã số định danh/ Căn cước công dân/ Chứng minh nhân dân/
(2)
Đăng ký đối tượng, nội dung giám định
(3)
Ghi chú
(4)
1
…………….
…………….
…………….
…………….
2
…………….
…………….
…………….
…………….
Hồ sơ cá nhân đề nghị miễn nhiệm, thu hồi thẻ kèm theo văn bản này.
………(1)…….. (Ghi rõ họ tên, chữ ký, chức vụ, dấu pháp nhân)
____________________
(1) Tên tổ chức đề nghị miễn nhiệm giám định viên tư pháp xây dựng
(2) Chứng minh nhân dân/căn cước công dân (ghi số, ngày cấp, nơi cấp)
(3) Nội dung giám định (ghi nội dung giám định theo quy định tại Điều 3 Thông tư này); đối tượng giám định (kê khai loại, cấp công trình)
(4) Tên, địa chỉ, số điện thoại liên hệ của tổ chức, cá nhân đề nghị.
lồng nhau (bên trong) hay không
const memberID = 0;
const isVIP = false;
const vbID = '7a1857f4f78e0d68dc4b9aeae0c79f7b';
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
// Detect touch device - chỉ true khi thiết bị CHÍNH sử dụng touch (không có mouse chính xác)
const isTouchDevice = () => {
// Nếu USE_THREE_DOTS_BUTTON = true, luôn trả về true (hiện trên mọi thiết bị)
if (USE_THREE_DOTS_BUTTON === true) return true;
// Ưu tiên: Kiểm tra pointer: coarse (thiết bị chính sử dụng touch, không có mouse/trackpad)
if (window.matchMedia) {
// pointer: coarse = thiết bị chính sử dụng touch (mobile/tablet)
// pointer: fine = thiết bị có mouse/trackpad chính xác (desktop/laptop)
const hasCoarsePointer = window.matchMedia('(pointer: coarse)').matches;
if (hasCoarsePointer) return true;
}
// Fallback: Kiểm tra touch support (không chính xác lắm vì laptop cũng có thể có touch)
// Chỉ dùng khi không support matchMedia
if (!window.matchMedia) {
return (('ontouchstart' in window) ||
(navigator.maxTouchPoints > 0) ||
(navigator.msMaxTouchPoints > 0));
}
return false;
};
const isTouch = isTouchDevice();
// State for dropdown menu on touch devices
let currentOpenDropdown = null;
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-20 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/menu
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/menu trực tiếp
const $parent = $element.closest('phan, chuong, muc, tieumuc, dieu, khoan, diem');
if ($parent.length > 0) {
const address = $parent.attr('address');
const parentType = getParentTypeName($parent.prop('tagName').toLowerCase());
const extraClass = (unlockAllPhanTich && memberID <= 0) ? ' upgrade-require' : '';
if (isTouch) {
// Touch device: Thêm nút 3 chấm (append vào body)
if ($('body').find('.menu-button-phan-tich[data-for="' + address + '"]').length === 0) {
const $menuButton = $('');
$('body').append($menuButton); // Append vào body
$parent.addClass('has-phan-tich-menu');
// Trigger update positions sau khi thêm
setTimeout(function() {
if (typeof window.updateMenuButtonPositions === 'function') {
window.updateMenuButtonPositions();
}
}, 10);
}
} else {
// Desktop: Append badge vào parent
if ($parent.find('.badge-phan-tich[data-for="' + address + '"]').length === 0) {
$element.attr('data-address', address);
const $badge = $('');
$parent.append($badge);
$parent.addClass('has-phan-tich-badge');
}
}
}
// Xử lý các p con (nếu có sub-p)
attachPhanTichBadge($element);
}, 3); // Đợi 3ms để 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');
// Trên touch device: Thêm nút 3 chấm dọc (append vào body vì dùng fixed position)
if (isTouch) {
// Kiểm tra đã có nút 3 chấm chưa (trong body)
if ($('body').find('.menu-button-phan-tich[data-for="' + address + '"]').length === 0) {
const parentType = getParentTypeName($parent.prop('tagName').toLowerCase());
const extraClass = (unlockAllPhanTich && memberID <= 0) ? ' upgrade-require' : '';
// Tạo nút 3 chấm với dropdown và append vào body
const $menuButton = $('');
$('body').append($menuButton); // Append vào body, không vào parent
$parent.addClass('has-phan-tich-menu');
}
} else {
// Desktop: Giữ nguyên badge hover như cũ (append vào parent)
if ($parent.find('.badge-phan-tich[data-for="' + address + '"]').length === 0) {
$p.attr('data-address', address);
const parentType = getParentTypeName($parent.prop('tagName').toLowerCase());
const extraClass = (unlockAllPhanTich && memberID <= 0) ? ' upgrade-require' : '';
const $badge = $('');
$parent.append($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 + 8) + 'px',
left: (offset.left + $parent.outerWidth() - badgeWidth - scrollLeft - 4) + '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) {
// Bỏ logic ẩn badge khi hover vào tnpl - bây giờ badge luôn hiển thị
// Badge "Phân tích" sẽ luôn hiện kể cả khi di chuột vào tnpl
// Tìm element gần nhất (phan, chuong, muc, tieumuc, 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) {
// Nếu di chuột sang menu button thì KHÔNG clear currentHoveredElement
if (e.relatedTarget && $(e.relatedTarget).closest('.menu-button-phan-tich').length > 0) {
return;
}
// 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');
// Nếu di chuột sang menu button của chính nó thì KHÔNG xử lý mouseleave
if (e.relatedTarget && $(e.relatedTarget).closest('.menu-button-phan-tich[data-for="' + parentAddress + '"]').length > 0) {
return;
}
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 (typeof memberID !== 'undefined' && memberID !== 4 && !isVIP) {
e.preventDefault();
e.stopPropagation();
openModal(this, '/ajax/member/m-register/new/1');
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!');
}
});
// Xử lý click vào CTTD/DCTD
$(document).on('click', 'cttd, dctk, dctd, .chuthichtudong', function(e) {
// Khách (non-VIP): mở modal đăng ký
if (typeof memberID !== 'undefined' && memberID !== 4 && !isVIP) {
e.preventDefault();
e.stopImmediatePropagation();
openModal(this, '/ajax/member/m-register/new/1');
return false;
}
// VIP: Đảm bảo các thuộc tính kích hoạt modal có sẵn
var $this = $(this);
if (!$this.attr('data-toggle')) {
$this.attr('data-toggle', 'modal');
$this.attr('data-target', '#ct_modal');
}
// Force mở modal #ct_modal an toàn (Logic từ fallback cũ)
var $ctModal = $('#ct_modal');
if ($ctModal.length > 0) {
if (typeof $ctModal.modal === 'function') {
$ctModal.modal('show');
} else if (window.jQuery && typeof window.jQuery('#ct_modal').modal === 'function') {
window.jQuery('#ct_modal').modal('show');
} else {
// Fallback load bootstrap if missing
console.warn('Bootstrap modal not loaded. Attempting to load local fallback...');
var loadBootstrap = function() {
$.getScript('/libs/jquery/bootstrap/dist/js/bootstrap.js', function() {
if (typeof $('#ct_modal').modal === 'function') {
$('#ct_modal').modal('show');
} else if (window.jQuery && typeof window.jQuery('#ct_modal').modal === 'function') {
window.jQuery('#ct_modal').modal('show');
}
});
};
if (typeof window.Tether === 'undefined') {
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js', loadBootstrap);
} else {
loadBootstrap();
}
}
}
});
// Ẩ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);
// Function để update vị trí nút 3 chấm (fixed position) - exposed globally
window.updateMenuButtonPositions = function() {
if (!isTouch) return; // Chỉ chạy trên touch device
$('.menu-button-phan-tich').each(function() {
const $menuButton = $(this);
const address = $menuButton.attr('data-for');
const $parent = $('[address="' + address + '"]').first();
if ($parent.length > 0) {
const parentOffset = $parent.offset();
const parentWidth = $parent.outerWidth();
const parentHeight = $parent.outerHeight();
const scrollTop = $(window).scrollTop();
const windowHeight = $(window).innerHeight();
const viewportTop = scrollTop;
const viewportBottom = scrollTop + windowHeight;
// Kiểm tra parent có trong viewport không
const parentTop = parentOffset.top;
const parentBottom = parentOffset.top + parentHeight;
const inViewport = (parentBottom > viewportTop && parentTop < viewportBottom);
if (inViewport) {
const scrollLeft = $(window).scrollLeft();
// Tính vị trí: góc phải của parent element
// Canh chỉnh top để tâm của nút 3 chấm (cao ~36px) ngang hàng với tâm của badge (cao ~21px, top 8px)
// Badge center: 8 + 10.5 = 18.5px
// Button center: Top + 18px
// => Top = 18.5 - 18 = 0.5px -> Lấy tròn 1px
const topOffset = 3;
topPosition = parentOffset.top - scrollTop + topOffset;
// Left = left của parent + width của parent - khoảng 30px (chiều rộng icon + padding)
// Để nút nằm bên trong parent, góc phải
// Trừ scrollLeft vì position: fixed tính theo viewport
const leftPosition = parentOffset.left + parentWidth - 2 - scrollLeft;
$menuButton.css({
top: topPosition + 'px',
left: leftPosition + 'px',
right: 'auto', // Reset right
display: 'block'
});
} else {
// Ẩn nếu parent không trong viewport
$menuButton.css({display: 'none'});
}
}
});
};
// Highlight parent khi hover/touch vào nút 3 chấm
$(document).on('mouseenter touchstart', '.menu-button-phan-tich', function() {
const address = $(this).attr('data-for');
const $parent = $('[address="' + address + '"]').first();
if ($parent.length) {
$parent.addClass('highlight-border');
$parent.data('hovering', true); // Mark as hovering
currentHoveredElement = $parent; // Update global tracker
// Attach badge nếu chưa có (logic tương tự như khi hover vào parent)
if ($parent.find('.badge-phan-tich-container[data-for="' + address + '"]').length === 0) {
const parentType = getParentTypeName($parent.prop('tagName').toLowerCase());
const extraClass = (unlockAllPhanTich && memberID <= 0) ? ' upgrade-require' : '';
const $badge = $('');
$parent.append($badge);
$parent.addClass('has-phan-tich-badge');
}
// Show badge tương ứng
if (typeof showPhanTichBadgeForParent === 'function') {
showPhanTichBadgeForParent($parent);
}
}
});
$(document).on('mouseleave touchend', '.menu-button-phan-tich', function(e) {
const address = $(this).attr('data-for');
const $parent = $('[address="' + address + '"]').first();
// Nếu di chuột sang parent thì không remove highlight
if (e.relatedTarget && $(e.relatedTarget).closest('[address="' + address + '"]').length > 0) {
return;
}
// Nếu di chuột ra ngoài hoàn toàn (không vào parent)
currentHoveredElement = null;
if ($parent.length) {
$parent.removeClass('highlight-border');
$parent.data('hovering', false);
// Hide badge
if (typeof hidePhanTichBadgeForParent === 'function') {
hidePhanTichBadgeForParent($parent);
}
}
});
// ===== Event handlers cho touch device =====
if (isTouch) {
// Update positions khi scroll hoặc resize
$(window).on('scroll resize', function() {
window.updateMenuButtonPositions();
});
// Initial update
setTimeout(window.updateMenuButtonPositions, 500);
// Xử lý click nút Phân tích (badge hoặc dropdown item)
$(document).on('click', '.badge-phan-tich, .dropdown-item-phan-tich[data-action="analyze"]', function(e) {
e.preventDefault();
e.stopPropagation();
if (typeof memberID !== 'undefined' && memberID !== 4 && !isVIP) {
openModal(this, '/ajax/member/m-register/new/1');
return;
}
const $btn = $(this);
let address = $btn.attr('data-for');
// Nếu click từ dropdown item, cần lấy address từ parent menu button
if (!address) {
const $menuBtn = $btn.closest('.menu-button-phan-tich');
address = $menuBtn.attr('data-for');
}
if (address) {
// Đóng dropdown menu nếu đang mở (trên mobile)
if (currentOpenDropdown) {
currentOpenDropdown.removeClass('show');
currentOpenDropdown = null;
}
openPhanTichPanel(address, vbID);
}
});
// Click vào nút 3 chấm -> mở panel phân tích luôn (không cần dropdown)
$(document).on('click', '.btn-three-dots', function(e) {
e.preventDefault();
e.stopPropagation();
const $button = $(this);
const $menuContainer = $button.closest('.menu-button-phan-tich');
const address = $menuContainer.attr('data-for');
// Kiểm tra nếu là khách (chưa đăng nhập)
if (unlockAllPhanTich && memberID <= 0) {
if (!$menuContainer.hasClass('upgrade-require')) {
$menuContainer.addClass('upgrade-require');
}
// Trigger event để modal.content.php bắt và mở modal đăng nhập
$menuContainer.trigger('click');
return;
}
// Thành viên -> mở panel phân tích trực tiếp
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!');
}
});
// Update positions khi scroll hoặc resize
$(window).on('scroll resize', function() {
window.updateMenuButtonPositions();
});
}
}
});
Tra cứu thuật ngữ với từ hoặc cụm từ đã chọn?
×
Quyết định 1549/QĐ-UBND năm 2023 công bố danh mục 01 thủ tục hành chính mới; 01 thủ tục hành chính được sửa đổi, bổ sung; 02 thủ tục hành chính bị bãi bỏ trong lĩnh vực giám định tư pháp xây dựng thuộc thẩm quyền giải quyết của Sở Xây dựng tỉnh Bến Tre