maralvic commited on
Commit
dc0dd5f
·
verified ·
1 Parent(s): 6bf1857

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +238 -188
index.html CHANGED
@@ -13,126 +13,83 @@
13
  font-family: 'Arial Rounded MT', sans-serif;
14
  }
15
 
16
- <!-- Pesquisa Dropdown Section -->
17
-
18
- .container {
19
- background: white;
20
- padding: 40px;
21
- border-radius: 15px;
22
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
23
- text-align: center;
24
- max-width: 500px;
25
- width: 100%;
26
- }
27
-
28
- .search-form {
29
  margin-bottom: 20px;
30
- }
31
-
32
- .input-group {
33
  display: flex;
34
- gap: 10px;
35
- margin-bottom: 20px;
36
  }
37
-
38
- input[type="text"] {
39
- flex: 1;
40
- padding: 15px;
41
- border: 2px solid #e0e0e0;
42
- border-radius: 8px;
43
  font-size: 16px;
44
- transition: border-color 0.3s ease;
45
  }
46
-
47
- input[type="text"]:focus {
48
- outline: none;
49
- border-color: #667eea;
50
- }
51
-
52
- .btn-acessar {
53
- background: #5466DD;
54
  color: white;
55
  border: none;
56
- padding: 15px 30px;
57
- border-radius: 25px;
58
- font-size: 18px;
59
  cursor: pointer;
60
- transition: transform 0.2s ease;
 
61
  }
62
-
63
- .btn-acessar:hover {
64
- transform: translateY(-2px);
65
  }
66
-
67
- .help-text {
68
- color: #666;
69
- font-size: 14px;
70
- margin-top: 10px;
 
71
  }
72
-
73
- /* Modal styles */
74
- .modal {
75
- display: none;
76
- position: fixed;
77
- z-index: 1000;
78
- left: 0;
79
- top: 0;
80
- width: 100%;
81
- height: 100%;
82
- background-color: rgba(0, 0, 0, 0.5);
83
  }
84
-
85
- .modal-content {
86
- background-color: white;
87
- margin: 15% auto;
88
- padding: 30px;
89
- border-radius: 10px;
90
- width: 90%;
91
- max-width: 400px;
92
- text-align: center;
93
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
94
  }
95
-
96
- .modal-header {
97
- font-size: 1.5em;
98
- font-weight: bold;
99
- color: #333;
100
- margin-bottom: 20px;
101
  }
102
-
103
- .modal-body {
 
 
104
  color: #666;
105
- margin-bottom: 25px;
106
- font-size: 16px;
107
  }
108
-
109
- .btn-ok {
110
- background: #6778EE;
111
- color: white;
112
- border: none;
113
- padding: 12px 25px;
114
- border-radius: 6px;
115
- font-size: 16px;
116
- cursor: pointer;
117
- transition: background-color 0.3s ease;
118
  }
119
-
120
- .btn-ok:hover {
121
- background: #5b68c7;
122
  }
123
-
124
- @media (max-width: 600px) {
125
- .container {
126
- padding: 30px 20px;
127
- }
128
-
129
- h1 {
130
- font-size: 1.8em;
131
- }
132
-
133
- .input-group {
134
- flex-direction: column;
135
- }
136
  }
137
 
138
  <!-- Original Section -->
@@ -214,112 +171,205 @@
214
  <!-- Content Section -->
215
  <section class="container mx-auto px-4 py-12 max-w-4xl">
216
  <div class="bg-white rounded-lg shadow-lg p-8">
217
- <div class="container">
218
- <h1 style="text-align: center;">Acessar as Negociações de Débitos Inscritos em Dívida Ativa - Procuradorias das Fazendas dos Estados e DF</h1>
219
- <br>
220
-
221
- <form class="search-form" onsubmit="buscarEstado(event)">
222
- <div class="input-group">
223
- <input
224
- type="text"
225
- id="estadoInput"
226
- placeholder="Digite a sigla (ex: SP) ou nome do estado (ex: São Paulo)"
227
- autocomplete="off"
228
- >
229
- <button type="submit" class="btn-acessar"> <i class="fas fa-search"></i> Pesquisar</button>
230
- </div>
231
- </form>
232
-
233
  </div>
234
-
235
- <!-- Modal -->
236
- <div id="errorModal" class="modal">
237
- <div class="modal-content">
238
- <div class="modal-header">Resultado da pesquisa</div>
239
- <div class="modal-body">Unidade não encontrada. Tente novamente</div>
240
- <button class="btn-ok" onclick="fecharModal()">OK</button>
241
- </div>
242
  </div>
243
 
244
  <script>
245
- // Dados dos estados brasileiros
246
- const statesData = {
247
- 'AC': 'www.pge.ac.gov.br/', 'ACRE': 'www.pge.ac.gov.br/',
248
- 'AL': 'http://www.pge.al.gov.br/', 'ALAGOAS': 'http://www.pge.al.gov.br/',
249
- 'AM': 'http://www.pge.am.gov.br/', 'AMAZONAS': 'http://www.pge.am.gov.br/',
250
- 'AP': 'http://www.pge.ap.gov.br/', 'AMAPÁ': 'http://www.pge.ap.gov.br/', 'AMAPA': 'http://www.pge.ap.gov.br/',
251
- 'BA': 'http://www.pge.ba.gov.br/', 'BAHIA': 'http://www.pge.ba.gov.br/',
252
- 'CE': 'http://www.pge.ce.gov.br/', 'CEARÁ': 'http://www.pge.ce.gov.br/', 'CEARA': 'http://www.pge.ce.gov.br/',
253
- 'DF': 'http://www.pg.df.gov.br/', 'DISTRITO FEDERAL': 'http://www.pg.df.gov.br/',
254
- 'ES': 'http://www.pge.es.gov.br/', 'ESPÍRITO SANTO': 'http://www.pge.es.gov.br/', 'ESPIRITO SANTO': 'http://www.pge.es.gov.br/',
255
- 'GO': 'http://www.procuradoria.go.gov.br/', 'GOIÁS': 'http://www.procuradoria.go.gov.br/', 'GOIAS': 'http://www.procuradoria.go.gov.br/',
256
- 'MA': 'http://www.pge.ma.gov.br/', 'MARANHÃO': 'http://www.pge.ma.gov.br/', 'MARANHAO': 'http://www.pge.ma.gov.br/',
257
- 'MG': 'http://www.pge.mg.gov.br/', 'MINAS GERAIS': 'http://www.pge.mg.gov.br/',
258
- 'MS': 'http://www.pge.ms.gov.br/', 'MATO GROSSO DO SUL': 'http://www.pge.ms.gov.br/',
259
- 'MT': 'http://www.pge.mt.gov.br/', 'MATO GROSSO': 'http://www.pge.mt.gov.br/',
260
- 'PA': 'http://www.pge.pa.gov.br/', 'PARÁ': 'http://www.pge.pa.gov.br/', 'PARA': 'http://www.pge.pa.gov.br/',
261
- 'PB': 'http://www.pge.pb.gov.br/', 'PARAÍBA': 'http://www.pge.pb.gov.br/', 'PARAIBA': 'http://www.pge.pb.gov.br/',
262
- 'PE': 'http://www.pge.pe.gov.br/', 'PERNAMBUCO': 'http://www.pge.pe.gov.br/',
263
- 'PI': 'http://www.pge.pi.gov.br/', 'PIAUÍ': 'http://www.pge.pi.gov.br/', 'PIAUI': 'http://www.pge.pi.gov.br/',
264
- 'PR': 'http://www.pge.pr.gov.br/', 'PARANÁ': 'http://www.pge.pr.gov.br/', 'PARANA': 'http://www.pge.pr.gov.br/',
265
- 'RJ': 'http://www.pge.rj.gov.br/', 'RIO DE JANEIRO': 'http://www.pge.rj.gov.br/',
266
- 'RN': 'http://www.pge.rn.gov.br/', 'RIO GRANDE DO NORTE': 'http://www.pge.rn.gov.br/',
267
- 'RO': 'http://www.pge.ro.gov.br/', 'RONDÔNIA': 'http://www.pge.ro.gov.br/', 'RONDONIA': 'http://www.pge.ro.gov.br/',
268
- 'RR': 'http://www.pge.rn.gov.br/', 'RORAIMA': 'http://www.pge.rn.gov.br/',
269
- 'RS': 'http://www.pge.rs.gov.br/', 'RIO GRANDE DO SUL': 'http://www.pge.rs.gov.br/',
270
- 'SC': 'http://www.pge.sc.gov.br/', 'SANTA CATARINA': 'http://www.pge.sc.gov.br/',
271
- 'SE': 'http://www.pge.se.gov.br/', 'SERGIPE': 'http://www.pge.se.gov.br/',
272
- 'SP': 'http://www.pge.sp.gov.br/', 'SÃO PAULO': 'http://www.pge.sp.gov.br/', 'SAO PAULO': 'http://www.pge.sp.gov.br/',
273
- 'TO': 'http://www.pge.to.gov.br/', 'TOCANTINS': 'http://www.pge.to.gov.br/'
274
- };
275
 
276
- function buscarEstado(event) {
277
- event.preventDefault();
 
 
 
 
 
278
 
279
- const input = document.getElementById('estadoInput');
280
- const busca = input.value.trim().toUpperCase();
 
281
 
282
- if (!busca) {
283
- mostrarModal();
 
 
 
 
 
 
 
 
284
  return;
285
  }
286
-
287
- const url = statesData[busca];
288
-
289
- if (url) {
290
- // Adiciona protocolo se não existir
291
- const urlCompleta = url.startsWith('http') ? url : 'http://' + url;
292
- window.open(urlCompleta, '_blank');
293
- input.value = ''; // Limpa o campo após busca bem-sucedida
294
- } else {
295
- mostrarModal();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  }
297
  }
298
 
299
- function mostrarModal() {
300
- document.getElementById('errorModal').style.display = 'block';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  }
302
 
303
- function fecharModal() {
304
- document.getElementById('errorModal').style.display = 'none';
 
 
305
  }
306
 
307
- // Fechar modal ao clicar fora dele
308
- window.onclick = function(event) {
309
- const modal = document.getElementById('errorModal');
310
- if (event.target === modal) {
311
- fecharModal();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  }
 
 
313
  }
314
 
315
- // Permitir busca ao pressionar Enter
316
- document.getElementById('estadoInput').addEventListener('keypress', function(event) {
317
- if (event.key === 'Enter') {
318
- buscarEstado(event);
 
 
 
 
 
 
 
 
 
319
  }
320
- });
321
- </script>
322
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  <span style="display: inline-block; height: 0;">
324
  </span>
325
  <!-- Torne-se um Expert Section -->
 
13
  font-family: 'Arial Rounded MT', sans-serif;
14
  }
15
 
16
+ .search-container {
17
+ background-color: white;
18
+ padding: 20px;
19
+ border-radius: 8px;
20
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
 
 
 
 
 
 
 
 
21
  margin-bottom: 20px;
 
 
 
22
  display: flex;
 
 
23
  }
24
+ input {
25
+ padding: 10px;
26
+ flex-grow: 1;
27
+ border: 1px solid #ddd;
28
+ border-radius: 4px;
 
29
  font-size: 16px;
 
30
  }
31
+ button {
32
+ padding: 10px 15px;
33
+ background-color: #4CAF50;
 
 
 
 
 
34
  color: white;
35
  border: none;
36
+ border-radius: 4px;
 
 
37
  cursor: pointer;
38
+ font-size: 16px;
39
+ margin-left: 10px;
40
  }
41
+ button:hover {
42
+ background-color: #45a049;
 
43
  }
44
+ .result {
45
+ background-color: white;
46
+ padding: 20px;
47
+ border-radius: 8px;
48
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
49
+ margin-top: 20px;
50
  }
51
+ .city-item {
52
+ margin: 10px 0;
53
+ padding: 10px;
54
+ border-bottom: 1px solid #eee;
55
+ display: flex;
56
+ justify-content: space-between;
57
+ align-items: center;
 
 
 
 
58
  }
59
+ .access-btn {
60
+ background-color: #2196F3;
61
+ padding: 5px 10px;
62
+ color: white;
63
+ text-decoration: none;
64
+ border-radius: 4px;
65
+ font-size: 14px;
 
 
 
66
  }
67
+ .access-btn:hover {
68
+ background-color: #0b7dda;
 
 
 
 
69
  }
70
+ .error {
71
+ color: #f44336;
72
+ }
73
+ .loading {
74
  color: #666;
75
+ font-style: italic;
 
76
  }
77
+ .loader {
78
+ border: 4px solid #f3f3f3;
79
+ border-top: 4px solid #3498db;
80
+ border-radius: 50%;
81
+ width: 30px;
82
+ height: 30px;
83
+ animation: spin 1s linear infinite;
84
+ margin: 20px auto;
 
 
85
  }
86
+ @keyframes spin {
87
+ 0% { transform: rotate(0deg); }
88
+ 100% { transform: rotate(360deg); }
89
  }
90
+ .loading-container {
91
+ text-align: center;
92
+ padding: 20px;
 
 
 
 
 
 
 
 
 
 
93
  }
94
 
95
  <!-- Original Section -->
 
171
  <!-- Content Section -->
172
  <section class="container mx-auto px-4 py-12 max-w-4xl">
173
  <div class="bg-white rounded-lg shadow-lg p-8">
174
+ <div class="search-container">
175
+ <input type="text" id="cityInput" placeholder="Digite o nome de uma cidade e pressione Enter">
176
+ <button id="searchBtn">Buscar</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  </div>
178
+
179
+ <div id="resultContainer" class="result" style="display: none;">
180
+ <div id="resultContent"></div>
 
 
 
 
 
181
  </div>
182
 
183
  <script>
184
+ let cachedMunicipios = null;
185
+ let currentSearchController = null;
186
+
187
+ // Adiciona evento de tecla no input
188
+ document.getElementById('cityInput').addEventListener('keypress', function(e) {
189
+ if (e.key === 'Enter') {
190
+ searchCity();
191
+ }
192
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
+ document.getElementById('searchBtn').addEventListener('click', searchCity);
195
+
196
+ async function searchCity() {
197
+ // Cancela a pesquisa anterior se existir
198
+ if (currentSearchController) {
199
+ currentSearchController.abort();
200
+ }
201
 
202
+ const input = document.getElementById('cityInput').value.trim();
203
+ const resultContainer = document.getElementById('resultContainer');
204
+ const resultContent = document.getElementById('resultContent');
205
 
206
+ resultContainer.style.display = 'block';
207
+ resultContent.innerHTML = `
208
+ <div class="loading-container">
209
+ <div class="loader"></div>
210
+ <p>Buscando cidades...</p>
211
+ </div>
212
+ `;
213
+
214
+ if (!input) {
215
+ resultContent.innerHTML = '<p class="error">Por favor, digite o nome de uma cidade.</p>';
216
  return;
217
  }
218
+
219
+ try {
220
+ // Cria um novo AbortController para esta pesquisa
221
+ const controller = new AbortController();
222
+ currentSearchController = controller;
223
+
224
+ if (!cachedMunicipios) {
225
+ const response = await fetch('https://servicodados.ibge.gov.br/api/v1/localidades/municipios', {
226
+ signal: controller.signal
227
+ });
228
+ cachedMunicipios = await response.json();
229
+ }
230
+
231
+ const normalizedInput = normalizeString(input).toLowerCase();
232
+ const matchedCities = cachedMunicipios.filter(municipio =>
233
+ normalizeString(municipio.nome).toLowerCase().includes(normalizedInput)
234
+ ).map(municipio => ({
235
+ name: municipio.nome,
236
+ state: municipio.microrregiao.mesorregiao.UF.sigla
237
+ }));
238
+
239
+ if (controller.signal.aborted) return;
240
+
241
+ if (matchedCities.length === 0) {
242
+ resultContent.innerHTML = `<p class="error">O nome "${input}" não corresponde a nenhuma cidade brasileira. Tente outro.</p>`;
243
+ return;
244
+ }
245
+
246
+ resultContent.innerHTML = `
247
+ <div class="loading-container">
248
+ <div class="loader"></div>
249
+ <p>Aguarde enquanto os acessos estão sendo gerados...</p>
250
+ </div>
251
+ `;
252
+
253
+ await displayResults(matchedCities, input, resultContent, controller);
254
+
255
+ } catch (error) {
256
+ if (error.name !== 'AbortError') {
257
+ resultContent.innerHTML = '<p class="error">Erro ao carregar dados das cidades. Tente novamente mais tarde.</p>';
258
+ console.error("Erro na busca:", error);
259
+ }
260
+ } finally {
261
+ currentSearchController = null;
262
  }
263
  }
264
 
265
+ async function displayResults(matchedCities, input, resultElement, controller) {
266
+ if (controller.signal.aborted) return;
267
+
268
+ if (matchedCities.length === 1) {
269
+ const city = matchedCities[0];
270
+ const cityUrl = await generateAccessibleUrl(city.name, city.state, controller);
271
+
272
+ if (controller.signal.aborted) return;
273
+
274
+ resultElement.innerHTML = `
275
+ <p>Você está procurando pela cidade de ${city.name}, ${city.state}?</p>
276
+ <div class="city-item">
277
+ <span>${city.name}, ${city.state}</span>
278
+ ${cityUrl ?
279
+ `<a href="${cityUrl}" class="access-btn" target="_blank">Acessar</a>` :
280
+ `<span class="error">Acesso não disponível</span>`}
281
+ </div>
282
+ `;
283
+ } else {
284
+ resultElement.innerHTML = `<p>Foram encontradas ${matchedCities.length} cidades com o nome "${input}":</p>`;
285
+
286
+ for (const city of matchedCities) {
287
+ if (controller.signal.aborted) return;
288
+
289
+ const cityUrl = await generateAccessibleUrl(city.name, city.state, controller);
290
+ const cityElement = document.createElement('div');
291
+ cityElement.className = 'city-item';
292
+ cityElement.innerHTML = `
293
+ <span>${city.name}, ${city.state}</span>
294
+ ${cityUrl ?
295
+ `<a href="${cityUrl}" class="access-btn" target="_blank">Acessar</a>` :
296
+ `<span class="error">Acesso não disponível</span>`}
297
+ `;
298
+ resultElement.appendChild(cityElement);
299
+ }
300
+ }
301
  }
302
 
303
+ function normalizeString(str) {
304
+ return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
305
+ .replace(/ç/g, 'c')
306
+ .replace(/Ç/g, 'C');
307
  }
308
 
309
+ async function generateAccessibleUrl(cityName, state, controller) {
310
+ const baseVariations = [
311
+ normalizeString(cityName).toLowerCase().replace(/[\s-]/g, ''),
312
+ normalizeString(cityName).toLowerCase().replace(/(\sde|\sdo|\sda|\sdos|\sdas|\s)/g, ''),
313
+ getCommonShortName(cityName)
314
+ ];
315
+
316
+ const prefixVariations = ['', 'portal.', 'www.portal.', 'prefeitura.'];
317
+
318
+ const testedUrls = new Set();
319
+ const validUrls = [];
320
+
321
+ for (const base of baseVariations) {
322
+ for (const prefix of prefixVariations) {
323
+ if (controller.signal.aborted) return null;
324
+
325
+ const url = `https://${prefix}${base}.${state.toLowerCase()}.gov.br`;
326
+
327
+ if (!testedUrls.has(url)) {
328
+ testedUrls.add(url);
329
+ const isAccessible = await checkUrlAccessibility(url, controller);
330
+ if (isAccessible) {
331
+ validUrls.push(url);
332
+ }
333
+ }
334
+ }
335
  }
336
+
337
+ return validUrls.length > 0 ? validUrls[0] : null;
338
  }
339
 
340
+ async function checkUrlAccessibility(url, controller) {
341
+ try {
342
+ const response = await fetch(url, {
343
+ method: 'HEAD',
344
+ mode: 'no-cors',
345
+ signal: controller.signal
346
+ });
347
+ return true;
348
+ } catch (e) {
349
+ if (e.name !== 'AbortError') {
350
+ console.warn(`URL não acessível: ${url}`);
351
+ }
352
+ return false;
353
  }
354
+ }
355
+
356
+ function getCommonShortName(cityName) {
357
+ const commonShortNames = {
358
+ 'são paulo': 'sp',
359
+ 'rio de janeiro': 'rj',
360
+ 'belo horizonte': 'bh',
361
+ 'porto alegre': 'poa',
362
+ 'são bernardo do campo': 'saobernardo',
363
+ 'santo andré': 'santoandre',
364
+ 'são josé dos campos': 'sjc',
365
+ 'são josé do rio preto': 'riopreto'
366
+ };
367
+
368
+ const lowerName = cityName.toLowerCase();
369
+ return commonShortNames[lowerName] ||
370
+ normalizeString(cityName).toLowerCase().replace(/[\s-]/g, '').slice(0, 10);
371
+ }
372
+ </script>
373
  <span style="display: inline-block; height: 0;">
374
  </span>
375
  <!-- Torne-se um Expert Section -->