CVNSS commited on
Commit
c724619
·
verified ·
1 Parent(s): cebdc8c

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +77 -106
index.html CHANGED
@@ -2,48 +2,46 @@
2
  <html lang="vi">
3
  <head>
4
  <meta charset="UTF-8">
5
- <title>Tra cứu Đơn vị Hành chính - Sáp nhập 3321</title>
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <!-- Bootstrap 5 CDN -->
8
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
9
- <!-- Choices.js cho select tìm kiếm nhanh -->
10
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css" />
11
  <style>
 
12
  .choices__inner { min-height: 42px !important; }
13
  .loading-spinner {
14
- width: 1.5rem;
15
- height: 1.5rem;
16
  border: .25em solid #0d6efd;
17
  border-right-color: transparent;
18
  border-radius: 50%;
19
- display: inline-block;
20
- animation: spin 1s linear infinite;
21
  }
22
  @keyframes spin { 100% { transform: rotate(360deg); } }
23
  </style>
24
  </head>
25
- <body class="bg-light">
26
  <div class="container py-5">
27
  <h2 class="mb-4 text-primary">🔎 Tra cứu Đơn vị Hành chính Sáp nhập 3321</h2>
28
  <div class="card shadow p-4 mb-4">
29
  <form id="searchForm" autocomplete="off">
30
  <div class="row mb-3">
31
  <div class="col-md-4 mb-2">
32
- <label for="province" class="form-label">Tỉnh/Thành phố cũ</label>
33
- <select class="form-select" id="province" required>
34
  <option value="">-- Chọn/Tìm tỉnh/thành phố --</option>
35
  </select>
36
  </div>
37
  <div class="col-md-4 mb-2">
38
- <label for="district" class="form-label">Quận/Huyện cũ</label>
39
- <select class="form-select" id="district">
40
- <option value="">-- Chọn/Tìm quận/huyện --</option>
41
  </select>
42
  </div>
43
  <div class="col-md-4 mb-2">
44
- <label for="ward" class="form-label">Phường/Xã cũ</label>
45
- <select class="form-select" id="ward">
46
- <option value="">-- Chọn/Tìm phường/xã --</option>
47
  </select>
48
  </div>
49
  </div>
@@ -56,139 +54,112 @@
56
  </div>
57
  <div id="resultArea"></div>
58
  </div>
59
- <!-- Choices.js: Tìm kiếm nhanh select -->
60
  <script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
61
  <script>
62
- // Dùng corsproxy.io để vượt lỗi CORS trên Hugging Face
63
- function apiUrl(path) {
64
- // Sử dụng dạng encodeURL để tránh lỗi CORS
65
- return 'https://corsproxy.io/?' + encodeURIComponent('https://api.luat.ai' + path);
66
- }
67
- const apiBase = "/administrative";
68
- const provinceSel = document.getElementById("province");
69
- const districtSel = document.getElementById("district");
70
- const wardSel = document.getElementById("ward");
71
  const resultArea = document.getElementById("resultArea");
72
  const searchForm = document.getElementById("searchForm");
73
  const loading = document.getElementById("loading");
74
  const resetBtn = document.getElementById("resetBtn");
75
 
76
- // Choices.js: Giao diện và tìm nhanh select
77
- let provinceChoices = new Choices(provinceSel, { searchEnabled: true, itemSelectText: '', shouldSort: false });
78
- let districtChoices = new Choices(districtSel, { searchEnabled: true, itemSelectText: '', shouldSort: false });
79
- let wardChoices = new Choices(wardSel, { searchEnabled: true, itemSelectText: '', shouldSort: false });
 
 
 
 
 
 
 
 
 
80
 
81
- async function loadProvinces() {
82
- let res = await fetch(apiUrl(apiBase + '/provinces'));
83
- let data = await res.json();
84
- let opts = data.map(p => ({ value: p, label: p }));
85
- provinceChoices.setChoices([{ value: '', label: '-- Chọn/Tìm tỉnh/thành phố --', selected: true, disabled: true }, ...opts], 'value', 'label', true);
86
  }
87
 
88
- provinceSel.addEventListener("change", async function() {
89
- districtChoices.clearStore(); wardChoices.clearStore();
90
- districtChoices.setChoices([{ value: '', label: '-- Chọn/Tìm quận/huyện --', selected: true, disabled: true }], 'value', 'label', true);
91
- wardChoices.setChoices([{ value: '', label: '-- Chọn/Tìm phường/xã --', selected: true, disabled: true }], 'value', 'label', true);
 
 
92
  if (!this.value) return;
93
- let res = await fetch(apiUrl(apiBase + '/districts?province=' + encodeURIComponent(this.value)));
94
- let data = await res.json();
95
- let opts = data.map(d => ({ value: d, label: d }));
96
- districtChoices.setChoices([{ value: '', label: '-- Chọn/Tìm quận/huyện --', selected: true, disabled: true }, ...opts], 'value', 'label', true);
97
  });
98
 
99
- districtSel.addEventListener("change", async function() {
 
100
  wardChoices.clearStore();
101
- wardChoices.setChoices([{ value: '', label: '-- Chọn/Tìm phường/xã --', selected: true, disabled: true }], 'value', 'label', true);
102
- if (!this.value || !provinceSel.value) return;
103
- let res = await fetch(apiUrl(apiBase + '/wards?province=' + encodeURIComponent(provinceSel.value) + '&district=' + encodeURIComponent(this.value)));
104
- let data = await res.json();
105
- let opts = data.map(w => ({ value: w, label: w }));
106
- wardChoices.setChoices([{ value: '', label: '-- Chọn/Tìm phường/xã --', selected: true, disabled: true }, ...opts], 'value', 'label', true);
107
  });
108
 
109
  // Tra cứu
110
- searchForm.addEventListener("submit", async function(e) {
111
  e.preventDefault();
112
  resultArea.innerHTML = "";
113
  loading.style.display = "inline";
114
- let params = [];
115
- if (provinceSel.value) params.push('oldProvince=' + encodeURIComponent(provinceSel.value));
116
- if (districtSel.value) params.push('oldDistrict=' + encodeURIComponent(districtSel.value));
117
- if (wardSel.value) params.push('oldWard=' + encodeURIComponent(wardSel.value));
118
- let url = apiUrl(apiBase + '/search?' + params.join('&'));
119
- try {
120
- let res = await fetch(url);
121
- let data = await res.json();
122
- // Nếu trả về mảng (nhiều kết quả)
123
- if (Array.isArray(data)) {
124
- if (data.length === 0) return showError("Không tìm thấy dữ liệu, vui lòng kiểm tra lại thông tin.");
125
- renderMultiResult(data);
126
- }
127
- // Nếu trả về object (1 kết quả)
128
- else if (data && data.id) renderResult(data);
129
- else showError("Không tìm thấy dữ liệu, vui lòng kiểm tra lại thông tin.");
130
- } catch (err) {
131
- showError(err.message || "Lỗi hệ thống hoặc API.");
132
- }
133
  loading.style.display = "none";
134
  });
135
 
136
  resetBtn.addEventListener("click", function() {
137
  provinceChoices.setChoiceByValue('');
138
- districtChoices.clearStore(); districtChoices.setChoices([{ value: '', label: '-- Chọn/Tìm quận/huyện --', selected: true, disabled: true }], 'value', 'label', true);
139
- wardChoices.clearStore(); wardChoices.setChoices([{ value: '', label: '-- Chọn/Tìm phường/xã --', selected: true, disabled: true }], 'value', 'label', true);
140
  resultArea.innerHTML = "";
141
  });
142
 
143
- // Hiển thị kết quả 1 dòng
144
- function renderResult(data) {
145
- resultArea.innerHTML = `
146
- <div class="card shadow p-3">
147
- <h5 class="mb-3 text-success">Kết quả tra cứu:</h5>
148
- <table class="table table-bordered align-middle">
149
- <tbody>
150
- <tr><th>Tỉnh/TP cũ</th><td>${data.oldProvince || ''}</td></tr>
151
- <tr><th>Quận/Huyện cũ</th><td>${data.oldDistrict || ''}</td></tr>
152
- <tr><th>Phường/Xã cũ</th><td>${data.oldWard || ''}</td></tr>
153
- <tr class="table-secondary"><th>Tỉnh/TP mới</th><td>${data.newProvince || ''}</td></tr>
154
- <tr class="table-secondary"><th>Phường/Xã mới</th><td>${data.newWard || ''}</td></tr>
155
- <tr><th>Cấp hành chính mới</th><td>${data.newLevel || ''}</td></tr>
156
- </tbody>
157
- </table>
158
- </div>
159
- `;
160
- }
161
- // Hiển thị nhiều kết quả
162
- function renderMultiResult(list) {
163
  resultArea.innerHTML = `
164
- <div class="card shadow p-3">
165
- <h5 class="mb-3 text-success"> ${list.length} kết quả:</h5>
166
- <div style="max-height:350px;overflow:auto;">
167
  <table class="table table-bordered table-hover align-middle small">
168
  <thead class="table-light"><tr>
169
- <th>Tỉnh/TP cũ</th><th>Quận/Huyện cũ</th><th>Phường/Xã cũ</th>
170
- <th>Tỉnh/TP mới</th><th>Phường/Xã mới</th><th>Cấp mới</th>
171
  </tr></thead>
172
  <tbody>
173
  ${list.map(d=>`
174
  <tr>
175
- <td>${d.oldProvince||''}</td>
176
- <td>${d.oldDistrict||''}</td>
177
- <td>${d.oldWard||''}</td>
178
- <td>${d.newProvince||''}</td>
179
- <td>${d.newWard||''}</td>
180
- <td>${d.newLevel||''}</td>
181
  </tr>
182
  `).join('')}
183
  </tbody>
184
- </table></div>
 
185
  </div>
186
  `;
187
  }
188
  function showError(msg) {
189
  resultArea.innerHTML = `<div class="alert alert-danger"><b>Lỗi:</b> ${msg}</div>`;
190
  }
191
- loadProvinces();
 
 
192
  </script>
193
  </body>
194
  </html>
 
2
  <html lang="vi">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <title>Tra cứu Đơn vị Hành chính Sáp nhập 3321</title>
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <!-- Bootstrap 5 & Choices.js CDN -->
8
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
9
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
 
10
  <style>
11
+ body { background: #f6fafd; }
12
  .choices__inner { min-height: 42px !important; }
13
  .loading-spinner {
14
+ width: 1.5rem; height: 1.5rem;
 
15
  border: .25em solid #0d6efd;
16
  border-right-color: transparent;
17
  border-radius: 50%;
18
+ display: inline-block; animation: spin 1s linear infinite;
 
19
  }
20
  @keyframes spin { 100% { transform: rotate(360deg); } }
21
  </style>
22
  </head>
23
+ <body>
24
  <div class="container py-5">
25
  <h2 class="mb-4 text-primary">🔎 Tra cứu Đơn vị Hành chính Sáp nhập 3321</h2>
26
  <div class="card shadow p-4 mb-4">
27
  <form id="searchForm" autocomplete="off">
28
  <div class="row mb-3">
29
  <div class="col-md-4 mb-2">
30
+ <label for="province_new" class="form-label">Tỉnh/Thành phố mới</label>
31
+ <select class="form-select" id="province_new">
32
  <option value="">-- Chọn/Tìm tỉnh/thành phố --</option>
33
  </select>
34
  </div>
35
  <div class="col-md-4 mb-2">
36
+ <label for="district_old" class="form-label">Quận/Huyện cũ</label>
37
+ <select class="form-select" id="district_old">
38
+ <option value="">-- Chọn/Tìm quận/huyện (cũ) --</option>
39
  </select>
40
  </div>
41
  <div class="col-md-4 mb-2">
42
+ <label for="ward_new" class="form-label">Phường/Xã mới</label>
43
+ <select class="form-select" id="ward_new">
44
+ <option value="">-- Chọn/Tìm phường/xã mới --</option>
45
  </select>
46
  </div>
47
  </div>
 
54
  </div>
55
  <div id="resultArea"></div>
56
  </div>
 
57
  <script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
58
  <script>
59
+ // ====== Đọc file JSON ======
60
+ let allData = [];
61
+ const dataUrl = 'data_3321.json'; // Đổi tên nếu file bạn khác!
62
+
63
+ const provinceNewSel = document.getElementById("province_new");
64
+ const districtOldSel = document.getElementById("district_old");
65
+ const wardNewSel = document.getElementById("ward_new");
 
 
66
  const resultArea = document.getElementById("resultArea");
67
  const searchForm = document.getElementById("searchForm");
68
  const loading = document.getElementById("loading");
69
  const resetBtn = document.getElementById("resetBtn");
70
 
71
+ // Choices.js
72
+ let provinceChoices = new Choices(provinceNewSel, { searchEnabled: true, itemSelectText: '', shouldSort: false });
73
+ let districtChoices = new Choices(districtOldSel, { searchEnabled: true, itemSelectText: '', shouldSort: false });
74
+ let wardChoices = new Choices(wardNewSel, { searchEnabled: true, itemSelectText: '', shouldSort: false });
75
+
76
+ async function loadData() {
77
+ loading.style.display = "inline";
78
+ let res = await fetch(dataUrl);
79
+ allData = await res.json();
80
+
81
+ // Lấy danh sách tỉnh mới duy nhất
82
+ let provinces = [...new Set(allData.map(e => e.province_new))].sort();
83
+ provinceChoices.setChoices([{ value: '', label: '-- Chọn/Tìm tỉnh/thành phố --', selected: true, disabled: true }, ...provinces.map(p => ({value: p, label: p}))], 'value', 'label', true);
84
 
85
+ loading.style.display = "none";
 
 
 
 
86
  }
87
 
88
+ // Tỉnh mới -> Lọc Quận/Huyện cũ
89
+ provinceNewSel.addEventListener("change", function() {
90
+ districtChoices.clearStore();
91
+ wardChoices.clearStore();
92
+ districtChoices.setChoices([{ value: '', label: '-- Chọn/Tìm quận/huyện (cũ) --', selected: true, disabled: true }], 'value', 'label', true);
93
+ wardChoices.setChoices([{ value: '', label: '-- Chọn/Tìm phường/xã mới --', selected: true, disabled: true }], 'value', 'label', true);
94
  if (!this.value) return;
95
+ let districts = allData.filter(e => e.province_new === this.value).map(e => e.district_old);
96
+ districts = [...new Set(districts)].sort();
97
+ districtChoices.setChoices([{ value: '', label: '-- Chọn/Tìm quận/huyện (cũ) --', selected: true, disabled: true }, ...districts.map(d => ({value: d, label: d}))], 'value', 'label', true);
 
98
  });
99
 
100
+ // Quận/huyện -> Lọc phường/xã mới
101
+ districtOldSel.addEventListener("change", function() {
102
  wardChoices.clearStore();
103
+ wardChoices.setChoices([{ value: '', label: '-- Chọn/Tìm phường/xã mới --', selected: true, disabled: true }], 'value', 'label', true);
104
+ if (!this.value || !provinceNewSel.value) return;
105
+ let wards = allData.filter(e => e.province_new === provinceNewSel.value && e.district_old === this.value).map(e => e.ward_new);
106
+ wards = [...new Set(wards)].sort();
107
+ wardChoices.setChoices([{ value: '', label: '-- Chọn/Tìm phường/xã mới --', selected: true, disabled: true }, ...wards.map(w => ({value: w, label: w}))], 'value', 'label', true);
 
108
  });
109
 
110
  // Tra cứu
111
+ searchForm.addEventListener("submit", function(e) {
112
  e.preventDefault();
113
  resultArea.innerHTML = "";
114
  loading.style.display = "inline";
115
+ // Lọc kết quả (có thể chọn 1 hoặc nhiều field)
116
+ let rs = allData.filter(e =>
117
+ (!provinceNewSel.value || e.province_new === provinceNewSel.value) &&
118
+ (!districtOldSel.value || e.district_old === districtOldSel.value) &&
119
+ (!wardNewSel.value || e.ward_new === wardNewSel.value)
120
+ );
121
+ if (rs.length === 0) showError("Không tìm thấy dữ liệu.");
122
+ else renderResult(rs);
 
 
 
 
 
 
 
 
 
 
 
123
  loading.style.display = "none";
124
  });
125
 
126
  resetBtn.addEventListener("click", function() {
127
  provinceChoices.setChoiceByValue('');
128
+ districtChoices.clearStore(); districtChoices.setChoices([{ value: '', label: '-- Chọn/Tìm quận/huyện (cũ) --', selected: true, disabled: true }], 'value', 'label', true);
129
+ wardChoices.clearStore(); wardChoices.setChoices([{ value: '', label: '-- Chọn/Tìm phường/xã mới --', selected: true, disabled: true }], 'value', 'label', true);
130
  resultArea.innerHTML = "";
131
  });
132
 
133
+ // Kết quả
134
+ function renderResult(list) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  resultArea.innerHTML = `
136
+ <div class="card shadow p-3 mt-2">
137
+ <h5 class="mb-3 text-success">Kết quả đối chiếu: <span class="text-dark small">${list.length} kết quả</span></h5>
138
+ <div style="max-height:380px;overflow:auto;">
139
  <table class="table table-bordered table-hover align-middle small">
140
  <thead class="table-light"><tr>
141
+ <th>Tỉnh/TP mới</th><th>Quận/Huyện cũ</th><th>Phường/Xã mới</th>
 
142
  </tr></thead>
143
  <tbody>
144
  ${list.map(d=>`
145
  <tr>
146
+ <td>${d.province_new||''}</td>
147
+ <td>${d.district_old||''}</td>
148
+ <td>${d.ward_new||''}</td>
 
 
 
149
  </tr>
150
  `).join('')}
151
  </tbody>
152
+ </table>
153
+ </div>
154
  </div>
155
  `;
156
  }
157
  function showError(msg) {
158
  resultArea.innerHTML = `<div class="alert alert-danger"><b>Lỗi:</b> ${msg}</div>`;
159
  }
160
+
161
+ // Tải dữ liệu
162
+ loadData();
163
  </script>
164
  </body>
165
  </html>