github-actions commited on
Commit ·
7ad8558
0
Parent(s):
Sync from GitHub de3ca9b6f57913ea7bbc4e8a3b73a8d5f7844d2d
Browse files- .dockerignore +17 -0
- .gitattributes +5 -0
- .gitignore +27 -0
- Dockerfile +26 -0
- README.md +88 -0
- backend/app/__init__.py +1 -0
- backend/app/cadastro_base.py +393 -0
- backend/app/crud.py +72 -0
- backend/app/database.py +72 -0
- backend/app/main.py +186 -0
- backend/app/models.py +46 -0
- backend/app/schemas.py +87 -0
- backend/data/base/cadastro_base_space_filtrada.db +3 -0
- backend/requirements.txt +8 -0
- backend/scripts/rebuild_cadastro_base.py +13 -0
- frontend/index.html +13 -0
- frontend/package-lock.json +1729 -0
- frontend/package.json +23 -0
- frontend/src/App.tsx +1172 -0
- frontend/src/api.ts +79 -0
- frontend/src/assets/cdA_logo.png +3 -0
- frontend/src/assets/cdA_logo_transparent.png +3 -0
- frontend/src/main.tsx +11 -0
- frontend/src/styles.css +789 -0
- frontend/src/types.ts +78 -0
- frontend/src/vite-env.d.ts +1 -0
- frontend/tsconfig.json +22 -0
- frontend/vite.config.ts +11 -0
- run-dev.ps1 +57 -0
.dockerignore
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.git
|
| 2 |
+
.gitignore
|
| 3 |
+
frontend/node_modules
|
| 4 |
+
frontend/dist
|
| 5 |
+
backend/.venv
|
| 6 |
+
backend/data/results
|
| 7 |
+
backend/data/app.db
|
| 8 |
+
backend/data/base/cadastro_base.db
|
| 9 |
+
backend-dev.log
|
| 10 |
+
backend-dev.err.log
|
| 11 |
+
frontend-dev.log
|
| 12 |
+
frontend-dev.err.log
|
| 13 |
+
cloudflared.log
|
| 14 |
+
cloudflared.err.log
|
| 15 |
+
tmp_mesa_react.html
|
| 16 |
+
tmp_mesa_react.css
|
| 17 |
+
**/__pycache__/
|
.gitattributes
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.jpg filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.webp filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.db filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.pyc
|
| 4 |
+
*.pyo
|
| 5 |
+
*.pyd
|
| 6 |
+
*.sqlite3
|
| 7 |
+
*.db
|
| 8 |
+
!backend/data/base/cadastro_base_space_filtrada.db
|
| 9 |
+
.pytest_cache/
|
| 10 |
+
.mypy_cache/
|
| 11 |
+
node_modules/
|
| 12 |
+
dist/
|
| 13 |
+
.env
|
| 14 |
+
backend/uploads/
|
| 15 |
+
backend/data/app.db
|
| 16 |
+
backend/data/results/
|
| 17 |
+
backend/data/base/AUXILIAR_INSCRICOES.txt
|
| 18 |
+
backend/data/base/cadastro_base.db
|
| 19 |
+
cloudflared.log
|
| 20 |
+
cloudflared.err.log
|
| 21 |
+
tmp_mesa_react.html
|
| 22 |
+
tmp_mesa_react.css
|
| 23 |
+
backend-dev.log
|
| 24 |
+
backend-dev.err.log
|
| 25 |
+
frontend-dev.log
|
| 26 |
+
frontend-dev.err.log
|
| 27 |
+
**/__pycache__/
|
Dockerfile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM node:20-bookworm-slim AS frontend-builder
|
| 2 |
+
WORKDIR /app/frontend
|
| 3 |
+
|
| 4 |
+
COPY frontend/package*.json ./
|
| 5 |
+
RUN npm ci
|
| 6 |
+
|
| 7 |
+
COPY frontend/ ./
|
| 8 |
+
RUN npm run build
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
FROM python:3.13-slim AS runtime
|
| 12 |
+
WORKDIR /app
|
| 13 |
+
|
| 14 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 15 |
+
ENV PYTHONUNBUFFERED=1
|
| 16 |
+
ENV PORT=7860
|
| 17 |
+
|
| 18 |
+
COPY backend/requirements.txt /app/backend/requirements.txt
|
| 19 |
+
RUN pip install --no-cache-dir -r /app/backend/requirements.txt
|
| 20 |
+
|
| 21 |
+
COPY backend/ /app/backend/
|
| 22 |
+
COPY --from=frontend-builder /app/frontend/dist /app/frontend/dist
|
| 23 |
+
|
| 24 |
+
EXPOSE 7860
|
| 25 |
+
|
| 26 |
+
CMD ["sh", "-c", "uvicorn backend.app.main:app --host 0.0.0.0 --port ${PORT}"]
|
README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: cda
|
| 3 |
+
emoji: 🏢
|
| 4 |
+
colorFrom: red
|
| 5 |
+
colorTo: blue
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# Cadastro Imobiliario
|
| 11 |
+
|
| 12 |
+
Estrutura inicial para um sistema de cadastro de dados imobiliarios com:
|
| 13 |
+
|
| 14 |
+
- Backend em FastAPI
|
| 15 |
+
- Frontend em React + Vite
|
| 16 |
+
- Banco local SQLite para desenvolvimento
|
| 17 |
+
- Upload inicial de planilha para preview e importacao futura
|
| 18 |
+
|
| 19 |
+
## Estrutura
|
| 20 |
+
|
| 21 |
+
- `backend/`: API e persistencia
|
| 22 |
+
- `frontend/`: interface web
|
| 23 |
+
- `run-dev.ps1`: sobe backend e frontend em desenvolvimento
|
| 24 |
+
|
| 25 |
+
## Bases de dados locais
|
| 26 |
+
|
| 27 |
+
- `backend/data/base/AUXILIAR_INSCRICOES.txt`: base cadastral bruta, somente leitura
|
| 28 |
+
- `backend/data/base/cadastro_base.db`: base otimizada em SQLite, gerada automaticamente a partir do TXT
|
| 29 |
+
- `backend/data/results/`: area reservada para planilhas e arquivos gerados pelo sistema
|
| 30 |
+
|
| 31 |
+
## Atualizacao da base cadastral
|
| 32 |
+
|
| 33 |
+
Quando o `AUXILIAR_INSCRICOES.txt` for atualizado, o sistema recria automaticamente o `cadastro_base.db` na proxima inicializacao da API.
|
| 34 |
+
|
| 35 |
+
Se quiser forcar a reconstrucao manualmente:
|
| 36 |
+
|
| 37 |
+
```powershell
|
| 38 |
+
cd backend
|
| 39 |
+
.\.venv\Scripts\python.exe scripts\rebuild_cadastro_base.py
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
## Campos iniciais
|
| 43 |
+
|
| 44 |
+
- `titulo`
|
| 45 |
+
- `finalidade`
|
| 46 |
+
- `area_total`
|
| 47 |
+
- `area_privativa`
|
| 48 |
+
- `valor`
|
| 49 |
+
- `anuncio`
|
| 50 |
+
- `origem`
|
| 51 |
+
- `observacoes`
|
| 52 |
+
|
| 53 |
+
## Como rodar
|
| 54 |
+
|
| 55 |
+
No Windows PowerShell:
|
| 56 |
+
|
| 57 |
+
```powershell
|
| 58 |
+
Set-ExecutionPolicy -Scope Process Bypass
|
| 59 |
+
.\run-dev.ps1
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
Se quiser instalar dependencias automaticamente:
|
| 63 |
+
|
| 64 |
+
```powershell
|
| 65 |
+
Set-ExecutionPolicy -Scope Process Bypass
|
| 66 |
+
.\run-dev.ps1 -Install
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
## URLs padrao
|
| 70 |
+
|
| 71 |
+
- Frontend: `http://localhost:5173`
|
| 72 |
+
- Backend: `http://localhost:8000`
|
| 73 |
+
- Docs da API: `http://localhost:8000/docs`
|
| 74 |
+
|
| 75 |
+
## Deploy no Hugging Face Space
|
| 76 |
+
|
| 77 |
+
O projeto esta preparado para rodar em `Docker Space`, com o frontend buildado e servido pelo backend em porta unica.
|
| 78 |
+
|
| 79 |
+
- Space: `https://huggingface.co/spaces/ESJL/cda`
|
| 80 |
+
- Porta exposta no container: `7860`
|
| 81 |
+
- Arquivo principal de deploy: `Dockerfile`
|
| 82 |
+
|
| 83 |
+
## Proximos passos
|
| 84 |
+
|
| 85 |
+
- Ajustar o layout da planilha que voce vai enviar
|
| 86 |
+
- Adicionar mais campos do cadastro
|
| 87 |
+
- Implementar validacoes de negocio
|
| 88 |
+
- Criar autenticacao e perfis, se necessario
|
backend/app/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
backend/app/cadastro_base.py
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import csv
|
| 2 |
+
import sqlite3
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
from .schemas import CadastroBaseRecord
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
BASE_FILE = Path(__file__).resolve().parent.parent / "data" / "base" / "AUXILIAR_INSCRICOES.txt"
|
| 9 |
+
SQLITE_FILE = Path(__file__).resolve().parent.parent / "data" / "base" / "cadastro_base.db"
|
| 10 |
+
SQLITE_SPACE_FILE = (
|
| 11 |
+
Path(__file__).resolve().parent.parent / "data" / "base" / "cadastro_base_space_filtrada.db"
|
| 12 |
+
)
|
| 13 |
+
BASE_COLUMNS = [
|
| 14 |
+
"NUM_BLOCO",
|
| 15 |
+
"NUM_INSCRICAO",
|
| 16 |
+
"COD_ENDLOC_LOGRADOURO",
|
| 17 |
+
"NME_ENDLOC_LOGRADOURO",
|
| 18 |
+
"NUM_ENDLOC_ENDERECO",
|
| 19 |
+
"NUM_ENDLOC_UNIDADE",
|
| 20 |
+
"NME_ENDLOC_BAIRRO_CDL",
|
| 21 |
+
"DES_FINALIDADE",
|
| 22 |
+
"RH_NOME",
|
| 23 |
+
"RH_VALOR",
|
| 24 |
+
"COORD_X",
|
| 25 |
+
"COORD_Y",
|
| 26 |
+
"ANO_EXERCICIO",
|
| 27 |
+
"NUM_VERSAO",
|
| 28 |
+
"IDF_REG_REGIAO_HOMOGENEA",
|
| 29 |
+
"AREA_TERRITORIAL",
|
| 30 |
+
"AREA_CONSTRUIDA",
|
| 31 |
+
"LATITUDE",
|
| 32 |
+
"LONGITUDE",
|
| 33 |
+
]
|
| 34 |
+
|
| 35 |
+
BASE_REQUIRED_COLUMNS = {
|
| 36 |
+
"num_bloco",
|
| 37 |
+
"num_inscricao",
|
| 38 |
+
"cod_endloc_logradouro",
|
| 39 |
+
"nme_endloc_logradouro",
|
| 40 |
+
"num_endloc_endereco",
|
| 41 |
+
"num_endloc_unidade",
|
| 42 |
+
"nme_endloc_bairro_cdl",
|
| 43 |
+
"des_finalidade",
|
| 44 |
+
"rh_nome",
|
| 45 |
+
"rh_valor",
|
| 46 |
+
"coord_x",
|
| 47 |
+
"coord_y",
|
| 48 |
+
"ano_exercicio",
|
| 49 |
+
"num_versao",
|
| 50 |
+
"idf_reg_regiao_homogenea",
|
| 51 |
+
"area_territorial",
|
| 52 |
+
"area_construida",
|
| 53 |
+
"latitude",
|
| 54 |
+
"longitude",
|
| 55 |
+
"search_inscricao",
|
| 56 |
+
"search_address",
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
SPACE_REQUIRED_COLUMNS = {
|
| 60 |
+
"num_bloco",
|
| 61 |
+
"num_inscricao",
|
| 62 |
+
"cod_endloc_logradouro",
|
| 63 |
+
"nme_endloc_logradouro",
|
| 64 |
+
"num_endloc_endereco",
|
| 65 |
+
"num_endloc_unidade",
|
| 66 |
+
"nme_endloc_bairro_cdl",
|
| 67 |
+
"des_finalidade",
|
| 68 |
+
"rh_nome",
|
| 69 |
+
"rh_valor",
|
| 70 |
+
"area_territorial",
|
| 71 |
+
"area_construida",
|
| 72 |
+
"latitude",
|
| 73 |
+
"longitude",
|
| 74 |
+
"search_inscricao",
|
| 75 |
+
"search_address",
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def _parse_decimal(value: str | None) -> float | None:
|
| 80 |
+
if value is None or value == "":
|
| 81 |
+
return None
|
| 82 |
+
try:
|
| 83 |
+
return float(str(value).replace(".", "").replace(",", "."))
|
| 84 |
+
except ValueError:
|
| 85 |
+
try:
|
| 86 |
+
return float(str(value).replace(",", "."))
|
| 87 |
+
except ValueError:
|
| 88 |
+
return None
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def _normalize_text(value: str | None) -> str:
|
| 92 |
+
return (value or "").strip().upper()
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def _to_record(row: dict[str, str | None]) -> CadastroBaseRecord:
|
| 96 |
+
logradouro = row.get("nme_endloc_logradouro") or None
|
| 97 |
+
numero = row.get("num_endloc_endereco") or None
|
| 98 |
+
bairro = row.get("nme_endloc_bairro_cdl") or None
|
| 99 |
+
finalidade = row.get("des_finalidade") or None
|
| 100 |
+
unidade = row.get("num_endloc_unidade") or None
|
| 101 |
+
num_inscricao = row.get("num_inscricao") or ""
|
| 102 |
+
|
| 103 |
+
endereco_base = " ".join(part for part in [logradouro, numero] if part)
|
| 104 |
+
titulo_sugerido = endereco_base or f"Inscricao {num_inscricao}"
|
| 105 |
+
label_parts = [f"Inscricao {num_inscricao}"]
|
| 106 |
+
if endereco_base:
|
| 107 |
+
label_parts.append(endereco_base)
|
| 108 |
+
if unidade:
|
| 109 |
+
label_parts.append(f"Unidade {unidade}")
|
| 110 |
+
if bairro:
|
| 111 |
+
label_parts.append(bairro)
|
| 112 |
+
|
| 113 |
+
return CadastroBaseRecord(
|
| 114 |
+
num_bloco=row.get("num_bloco") or None,
|
| 115 |
+
num_inscricao=num_inscricao,
|
| 116 |
+
cod_endloc_logradouro=row.get("cod_endloc_logradouro") or None,
|
| 117 |
+
nme_endloc_logradouro=logradouro,
|
| 118 |
+
num_endloc_endereco=numero,
|
| 119 |
+
num_endloc_unidade=unidade,
|
| 120 |
+
nme_endloc_bairro_cdl=bairro,
|
| 121 |
+
des_finalidade=finalidade,
|
| 122 |
+
rh_nome=row.get("rh_nome") or None,
|
| 123 |
+
rh_valor=_parse_decimal(row.get("rh_valor")),
|
| 124 |
+
coord_x=_parse_decimal(row.get("coord_x")),
|
| 125 |
+
coord_y=_parse_decimal(row.get("coord_y")),
|
| 126 |
+
ano_exercicio=_parse_decimal(row.get("ano_exercicio")),
|
| 127 |
+
num_versao=_parse_decimal(row.get("num_versao")),
|
| 128 |
+
idf_reg_regiao_homogenea=_parse_decimal(row.get("idf_reg_regiao_homogenea")),
|
| 129 |
+
area_territorial=_parse_decimal(row.get("area_territorial")),
|
| 130 |
+
area_construida=_parse_decimal(row.get("area_construida")),
|
| 131 |
+
latitude=_parse_decimal(row.get("latitude")),
|
| 132 |
+
longitude=_parse_decimal(row.get("longitude")),
|
| 133 |
+
titulo_sugerido=titulo_sugerido,
|
| 134 |
+
display_label=" | ".join(label_parts),
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def _connect_sqlite() -> sqlite3.Connection:
|
| 139 |
+
connection = sqlite3.connect(_get_active_sqlite_file())
|
| 140 |
+
connection.row_factory = sqlite3.Row
|
| 141 |
+
return connection
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def _get_sqlite_columns(path: Path) -> set[str]:
|
| 145 |
+
connection = sqlite3.connect(path)
|
| 146 |
+
connection.row_factory = sqlite3.Row
|
| 147 |
+
try:
|
| 148 |
+
return {row["name"] for row in connection.execute("PRAGMA table_info(cadastro_base)").fetchall()}
|
| 149 |
+
finally:
|
| 150 |
+
connection.close()
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def _get_active_sqlite_file() -> Path:
|
| 154 |
+
if SQLITE_SPACE_FILE.exists():
|
| 155 |
+
try:
|
| 156 |
+
existing_columns = _get_sqlite_columns(SQLITE_SPACE_FILE)
|
| 157 |
+
if SPACE_REQUIRED_COLUMNS.issubset(existing_columns):
|
| 158 |
+
return SQLITE_SPACE_FILE
|
| 159 |
+
except sqlite3.DatabaseError:
|
| 160 |
+
pass
|
| 161 |
+
return SQLITE_FILE
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def _needs_rebuild() -> bool:
|
| 165 |
+
if SQLITE_SPACE_FILE.exists():
|
| 166 |
+
try:
|
| 167 |
+
existing_columns = _get_sqlite_columns(SQLITE_SPACE_FILE)
|
| 168 |
+
if SPACE_REQUIRED_COLUMNS.issubset(existing_columns):
|
| 169 |
+
return False
|
| 170 |
+
except sqlite3.DatabaseError:
|
| 171 |
+
pass
|
| 172 |
+
|
| 173 |
+
if not BASE_FILE.exists():
|
| 174 |
+
raise FileNotFoundError(f"Base auxiliar nao encontrada em {BASE_FILE}")
|
| 175 |
+
if not SQLITE_FILE.exists():
|
| 176 |
+
return True
|
| 177 |
+
try:
|
| 178 |
+
existing_columns = _get_sqlite_columns(SQLITE_FILE)
|
| 179 |
+
except sqlite3.DatabaseError:
|
| 180 |
+
return True
|
| 181 |
+
|
| 182 |
+
if not BASE_REQUIRED_COLUMNS.issubset(existing_columns):
|
| 183 |
+
return True
|
| 184 |
+
return SQLITE_FILE.stat().st_mtime < BASE_FILE.stat().st_mtime
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
def ensure_cadastro_base_sqlite(force_rebuild: bool = False) -> tuple[Path, int]:
|
| 188 |
+
if not force_rebuild and not _needs_rebuild():
|
| 189 |
+
active_file = _get_active_sqlite_file()
|
| 190 |
+
connection = sqlite3.connect(active_file)
|
| 191 |
+
connection.row_factory = sqlite3.Row
|
| 192 |
+
with connection:
|
| 193 |
+
row = connection.execute("SELECT COUNT(*) AS total FROM cadastro_base").fetchone()
|
| 194 |
+
return active_file, int(row["total"])
|
| 195 |
+
|
| 196 |
+
SQLITE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
| 197 |
+
temp_db = SQLITE_FILE.with_suffix(".tmp")
|
| 198 |
+
if temp_db.exists():
|
| 199 |
+
temp_db.unlink()
|
| 200 |
+
|
| 201 |
+
connection = sqlite3.connect(temp_db)
|
| 202 |
+
try:
|
| 203 |
+
connection.execute(
|
| 204 |
+
"""
|
| 205 |
+
CREATE TABLE cadastro_base (
|
| 206 |
+
num_bloco TEXT,
|
| 207 |
+
num_inscricao TEXT,
|
| 208 |
+
cod_endloc_logradouro TEXT,
|
| 209 |
+
nme_endloc_logradouro TEXT,
|
| 210 |
+
num_endloc_endereco TEXT,
|
| 211 |
+
num_endloc_unidade TEXT,
|
| 212 |
+
nme_endloc_bairro_cdl TEXT,
|
| 213 |
+
des_finalidade TEXT,
|
| 214 |
+
rh_nome TEXT,
|
| 215 |
+
rh_valor TEXT,
|
| 216 |
+
coord_x TEXT,
|
| 217 |
+
coord_y TEXT,
|
| 218 |
+
ano_exercicio TEXT,
|
| 219 |
+
num_versao TEXT,
|
| 220 |
+
idf_reg_regiao_homogenea TEXT,
|
| 221 |
+
area_territorial TEXT,
|
| 222 |
+
area_construida TEXT,
|
| 223 |
+
latitude TEXT,
|
| 224 |
+
longitude TEXT,
|
| 225 |
+
search_inscricao TEXT,
|
| 226 |
+
search_address TEXT
|
| 227 |
+
)
|
| 228 |
+
"""
|
| 229 |
+
)
|
| 230 |
+
|
| 231 |
+
insert_sql = """
|
| 232 |
+
INSERT INTO cadastro_base (
|
| 233 |
+
num_bloco,
|
| 234 |
+
num_inscricao,
|
| 235 |
+
cod_endloc_logradouro,
|
| 236 |
+
nme_endloc_logradouro,
|
| 237 |
+
num_endloc_endereco,
|
| 238 |
+
num_endloc_unidade,
|
| 239 |
+
nme_endloc_bairro_cdl,
|
| 240 |
+
des_finalidade,
|
| 241 |
+
rh_nome,
|
| 242 |
+
rh_valor,
|
| 243 |
+
coord_x,
|
| 244 |
+
coord_y,
|
| 245 |
+
ano_exercicio,
|
| 246 |
+
num_versao,
|
| 247 |
+
idf_reg_regiao_homogenea,
|
| 248 |
+
area_territorial,
|
| 249 |
+
area_construida,
|
| 250 |
+
latitude,
|
| 251 |
+
longitude,
|
| 252 |
+
search_inscricao,
|
| 253 |
+
search_address
|
| 254 |
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
| 255 |
+
"""
|
| 256 |
+
|
| 257 |
+
batch: list[tuple[str, ...]] = []
|
| 258 |
+
total = 0
|
| 259 |
+
with BASE_FILE.open("r", encoding="utf-8", newline="") as handle:
|
| 260 |
+
reader = csv.DictReader(handle, delimiter="|")
|
| 261 |
+
for source_row in reader:
|
| 262 |
+
row = {column: source_row.get(column, "") for column in BASE_COLUMNS}
|
| 263 |
+
search_inscricao = _normalize_text(row["NUM_INSCRICAO"])
|
| 264 |
+
search_address = " ".join(
|
| 265 |
+
part
|
| 266 |
+
for part in [
|
| 267 |
+
_normalize_text(row["NME_ENDLOC_LOGRADOURO"]),
|
| 268 |
+
_normalize_text(row["NUM_ENDLOC_ENDERECO"]),
|
| 269 |
+
_normalize_text(row["NUM_ENDLOC_UNIDADE"]),
|
| 270 |
+
]
|
| 271 |
+
if part
|
| 272 |
+
)
|
| 273 |
+
batch.append(
|
| 274 |
+
(
|
| 275 |
+
row["NUM_BLOCO"],
|
| 276 |
+
row["NUM_INSCRICAO"],
|
| 277 |
+
row["COD_ENDLOC_LOGRADOURO"],
|
| 278 |
+
row["NME_ENDLOC_LOGRADOURO"],
|
| 279 |
+
row["NUM_ENDLOC_ENDERECO"],
|
| 280 |
+
row["NUM_ENDLOC_UNIDADE"],
|
| 281 |
+
row["NME_ENDLOC_BAIRRO_CDL"],
|
| 282 |
+
row["DES_FINALIDADE"],
|
| 283 |
+
row["RH_NOME"],
|
| 284 |
+
row["RH_VALOR"],
|
| 285 |
+
row["COORD_X"],
|
| 286 |
+
row["COORD_Y"],
|
| 287 |
+
row["ANO_EXERCICIO"],
|
| 288 |
+
row["NUM_VERSAO"],
|
| 289 |
+
row["IDF_REG_REGIAO_HOMOGENEA"],
|
| 290 |
+
row["AREA_TERRITORIAL"],
|
| 291 |
+
row["AREA_CONSTRUIDA"],
|
| 292 |
+
row["LATITUDE"],
|
| 293 |
+
row["LONGITUDE"],
|
| 294 |
+
search_inscricao,
|
| 295 |
+
search_address,
|
| 296 |
+
)
|
| 297 |
+
)
|
| 298 |
+
if len(batch) >= 10000:
|
| 299 |
+
connection.executemany(insert_sql, batch)
|
| 300 |
+
total += len(batch)
|
| 301 |
+
batch.clear()
|
| 302 |
+
|
| 303 |
+
if batch:
|
| 304 |
+
connection.executemany(insert_sql, batch)
|
| 305 |
+
total += len(batch)
|
| 306 |
+
|
| 307 |
+
connection.execute(
|
| 308 |
+
"CREATE INDEX idx_cadastro_base_inscricao ON cadastro_base(search_inscricao)"
|
| 309 |
+
)
|
| 310 |
+
connection.execute(
|
| 311 |
+
"CREATE INDEX idx_cadastro_base_endereco ON cadastro_base(search_address)"
|
| 312 |
+
)
|
| 313 |
+
connection.commit()
|
| 314 |
+
finally:
|
| 315 |
+
connection.close()
|
| 316 |
+
|
| 317 |
+
try:
|
| 318 |
+
temp_db.replace(SQLITE_FILE)
|
| 319 |
+
except PermissionError as exc:
|
| 320 |
+
if temp_db.exists():
|
| 321 |
+
temp_db.unlink(missing_ok=True)
|
| 322 |
+
raise PermissionError(
|
| 323 |
+
"Nao foi possivel substituir cadastro_base.db. Feche a API antes de rodar o rebuild manual."
|
| 324 |
+
) from exc
|
| 325 |
+
return SQLITE_FILE, total
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
def search_cadastro_base(mode: str, query: str, limit: int = 20) -> list[CadastroBaseRecord]:
|
| 329 |
+
if mode not in {"inscricao", "endereco"}:
|
| 330 |
+
raise ValueError("Modo de busca invalido.")
|
| 331 |
+
|
| 332 |
+
cleaned_query = _normalize_text(query)
|
| 333 |
+
if len(cleaned_query) < 2:
|
| 334 |
+
return []
|
| 335 |
+
|
| 336 |
+
ensure_cadastro_base_sqlite()
|
| 337 |
+
|
| 338 |
+
with _connect_sqlite() as connection:
|
| 339 |
+
available_columns = _get_sqlite_columns(_get_active_sqlite_file())
|
| 340 |
+
select_candidates = [
|
| 341 |
+
"num_bloco",
|
| 342 |
+
"num_inscricao",
|
| 343 |
+
"cod_endloc_logradouro",
|
| 344 |
+
"nme_endloc_logradouro",
|
| 345 |
+
"num_endloc_endereco",
|
| 346 |
+
"num_endloc_unidade",
|
| 347 |
+
"nme_endloc_bairro_cdl",
|
| 348 |
+
"des_finalidade",
|
| 349 |
+
"rh_nome",
|
| 350 |
+
"rh_valor",
|
| 351 |
+
"coord_x",
|
| 352 |
+
"coord_y",
|
| 353 |
+
"ano_exercicio",
|
| 354 |
+
"num_versao",
|
| 355 |
+
"idf_reg_regiao_homogenea",
|
| 356 |
+
"area_territorial",
|
| 357 |
+
"area_construida",
|
| 358 |
+
"latitude",
|
| 359 |
+
"longitude",
|
| 360 |
+
]
|
| 361 |
+
selected_columns = ",\n ".join(
|
| 362 |
+
column for column in select_candidates if column in available_columns
|
| 363 |
+
)
|
| 364 |
+
if mode == "inscricao":
|
| 365 |
+
rows = connection.execute(
|
| 366 |
+
"""
|
| 367 |
+
SELECT
|
| 368 |
+
"""
|
| 369 |
+
+ selected_columns
|
| 370 |
+
+ """
|
| 371 |
+
FROM cadastro_base
|
| 372 |
+
WHERE search_inscricao LIKE ?
|
| 373 |
+
LIMIT ?
|
| 374 |
+
""",
|
| 375 |
+
(f"%{cleaned_query}%", limit),
|
| 376 |
+
).fetchall()
|
| 377 |
+
else:
|
| 378 |
+
terms = [term for term in cleaned_query.split() if term]
|
| 379 |
+
where_clause = " AND ".join(["search_address LIKE ?"] * len(terms))
|
| 380 |
+
params = [f"%{term}%" for term in terms]
|
| 381 |
+
params.append(limit)
|
| 382 |
+
rows = connection.execute(
|
| 383 |
+
f"""
|
| 384 |
+
SELECT
|
| 385 |
+
{selected_columns}
|
| 386 |
+
FROM cadastro_base
|
| 387 |
+
WHERE {where_clause}
|
| 388 |
+
LIMIT ?
|
| 389 |
+
""",
|
| 390 |
+
params,
|
| 391 |
+
).fetchall()
|
| 392 |
+
|
| 393 |
+
return [_to_record(dict(row)) for row in rows]
|
backend/app/crud.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sqlalchemy import select
|
| 2 |
+
from sqlalchemy.orm import Session
|
| 3 |
+
|
| 4 |
+
from . import models, schemas
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def list_properties(db: Session) -> list[models.Property]:
|
| 8 |
+
return list(db.scalars(select(models.Property).order_by(models.Property.id.desc())))
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def create_property(db: Session, payload: schemas.PropertyCreate) -> models.Property:
|
| 12 |
+
data = payload.model_dump()
|
| 13 |
+
if not data.get("titulo"):
|
| 14 |
+
endereco = " ".join(
|
| 15 |
+
part
|
| 16 |
+
for part in [data.get("nme_endloc_logradouro"), data.get("num_endloc_endereco")]
|
| 17 |
+
if part
|
| 18 |
+
).strip()
|
| 19 |
+
data["titulo"] = endereco or data.get("num_inscricao") or "Novo registro"
|
| 20 |
+
item = models.Property(**data)
|
| 21 |
+
db.add(item)
|
| 22 |
+
db.commit()
|
| 23 |
+
db.refresh(item)
|
| 24 |
+
return item
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def delete_property(db: Session, property_id: int) -> bool:
|
| 28 |
+
item = db.get(models.Property, property_id)
|
| 29 |
+
if item is None:
|
| 30 |
+
return False
|
| 31 |
+
db.delete(item)
|
| 32 |
+
db.commit()
|
| 33 |
+
return True
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def export_properties(db: Session) -> list[dict]:
|
| 37 |
+
items = list_properties(db)
|
| 38 |
+
return [
|
| 39 |
+
{
|
| 40 |
+
"id": item.id,
|
| 41 |
+
"num_bloco": item.num_bloco,
|
| 42 |
+
"num_inscricao": item.num_inscricao,
|
| 43 |
+
"cod_endloc_logradouro": item.cod_endloc_logradouro,
|
| 44 |
+
"logradouro": item.nme_endloc_logradouro,
|
| 45 |
+
"numero": item.num_endloc_endereco,
|
| 46 |
+
"unidade": item.num_endloc_unidade,
|
| 47 |
+
"bairro": item.nme_endloc_bairro_cdl,
|
| 48 |
+
"finalidade": item.finalidade,
|
| 49 |
+
"rh_nome": item.rh_nome,
|
| 50 |
+
"rh_valor": item.rh_valor,
|
| 51 |
+
"area_total_separada": item.area_total_detalhe,
|
| 52 |
+
"area_total_soma": item.area_total,
|
| 53 |
+
"area_privativa_separada": item.area_privativa_detalhe,
|
| 54 |
+
"area_privativa_soma": item.area_privativa,
|
| 55 |
+
"finalidade_oferta": item.finalidade_oferta,
|
| 56 |
+
"area_total_oferta": item.area_total_oferta,
|
| 57 |
+
"area_privativa_oferta": item.area_privativa_oferta,
|
| 58 |
+
"valor_oferta": item.valor_oferta,
|
| 59 |
+
"latitude": item.latitude,
|
| 60 |
+
"longitude": item.longitude,
|
| 61 |
+
"descricao_oferta": item.descricao_oferta,
|
| 62 |
+
"observacao": item.observacao,
|
| 63 |
+
"url": item.url,
|
| 64 |
+
"imobiliaria": item.imobiliaria,
|
| 65 |
+
"codigo": item.codigo,
|
| 66 |
+
"infra": item.infra,
|
| 67 |
+
"padrao": item.padrao,
|
| 68 |
+
"conservacao": item.conservacao,
|
| 69 |
+
"vaga": item.vaga,
|
| 70 |
+
}
|
| 71 |
+
for item in items
|
| 72 |
+
]
|
backend/app/database.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
|
| 3 |
+
from sqlalchemy import create_engine, inspect, text
|
| 4 |
+
from sqlalchemy.orm import DeclarativeBase, sessionmaker
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
BASE_DIR = Path(__file__).resolve().parent.parent
|
| 8 |
+
DATA_DIR = BASE_DIR / "data"
|
| 9 |
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
| 10 |
+
DATABASE_URL = f"sqlite:///{DATA_DIR / 'app.db'}"
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class Base(DeclarativeBase):
|
| 14 |
+
pass
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
| 18 |
+
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def get_db():
|
| 22 |
+
db = SessionLocal()
|
| 23 |
+
try:
|
| 24 |
+
yield db
|
| 25 |
+
finally:
|
| 26 |
+
db.close()
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def ensure_property_schema() -> None:
|
| 30 |
+
inspector = inspect(engine)
|
| 31 |
+
if "properties" not in inspector.get_table_names():
|
| 32 |
+
return
|
| 33 |
+
|
| 34 |
+
existing_columns = {column["name"] for column in inspector.get_columns("properties")}
|
| 35 |
+
migrations = {
|
| 36 |
+
"num_bloco": "ALTER TABLE properties ADD COLUMN num_bloco VARCHAR(30)",
|
| 37 |
+
"num_inscricao": "ALTER TABLE properties ADD COLUMN num_inscricao VARCHAR(30)",
|
| 38 |
+
"cod_endloc_logradouro": "ALTER TABLE properties ADD COLUMN cod_endloc_logradouro VARCHAR(30)",
|
| 39 |
+
"nme_endloc_logradouro": "ALTER TABLE properties ADD COLUMN nme_endloc_logradouro VARCHAR(150)",
|
| 40 |
+
"num_endloc_endereco": "ALTER TABLE properties ADD COLUMN num_endloc_endereco VARCHAR(30)",
|
| 41 |
+
"num_endloc_unidade": "ALTER TABLE properties ADD COLUMN num_endloc_unidade VARCHAR(30)",
|
| 42 |
+
"nme_endloc_bairro_cdl": "ALTER TABLE properties ADD COLUMN nme_endloc_bairro_cdl VARCHAR(120)",
|
| 43 |
+
"rh_nome": "ALTER TABLE properties ADD COLUMN rh_nome VARCHAR(80)",
|
| 44 |
+
"rh_valor": "ALTER TABLE properties ADD COLUMN rh_valor FLOAT",
|
| 45 |
+
"coord_x": "ALTER TABLE properties ADD COLUMN coord_x FLOAT",
|
| 46 |
+
"coord_y": "ALTER TABLE properties ADD COLUMN coord_y FLOAT",
|
| 47 |
+
"ano_exercicio": "ALTER TABLE properties ADD COLUMN ano_exercicio FLOAT",
|
| 48 |
+
"num_versao": "ALTER TABLE properties ADD COLUMN num_versao FLOAT",
|
| 49 |
+
"idf_reg_regiao_homogenea": "ALTER TABLE properties ADD COLUMN idf_reg_regiao_homogenea FLOAT",
|
| 50 |
+
"area_total_detalhe": "ALTER TABLE properties ADD COLUMN area_total_detalhe VARCHAR(1000)",
|
| 51 |
+
"area_privativa_detalhe": "ALTER TABLE properties ADD COLUMN area_privativa_detalhe VARCHAR(1000)",
|
| 52 |
+
"latitude": "ALTER TABLE properties ADD COLUMN latitude FLOAT",
|
| 53 |
+
"longitude": "ALTER TABLE properties ADD COLUMN longitude FLOAT",
|
| 54 |
+
"finalidade_oferta": "ALTER TABLE properties ADD COLUMN finalidade_oferta VARCHAR(50)",
|
| 55 |
+
"area_total_oferta": "ALTER TABLE properties ADD COLUMN area_total_oferta FLOAT",
|
| 56 |
+
"area_privativa_oferta": "ALTER TABLE properties ADD COLUMN area_privativa_oferta FLOAT",
|
| 57 |
+
"valor_oferta": "ALTER TABLE properties ADD COLUMN valor_oferta FLOAT",
|
| 58 |
+
"descricao_oferta": "ALTER TABLE properties ADD COLUMN descricao_oferta TEXT",
|
| 59 |
+
"observacao": "ALTER TABLE properties ADD COLUMN observacao TEXT",
|
| 60 |
+
"url": "ALTER TABLE properties ADD COLUMN url TEXT",
|
| 61 |
+
"imobiliaria": "ALTER TABLE properties ADD COLUMN imobiliaria VARCHAR(150)",
|
| 62 |
+
"codigo": "ALTER TABLE properties ADD COLUMN codigo VARCHAR(80)",
|
| 63 |
+
"infra": "ALTER TABLE properties ADD COLUMN infra TEXT",
|
| 64 |
+
"padrao": "ALTER TABLE properties ADD COLUMN padrao VARCHAR(80)",
|
| 65 |
+
"conservacao": "ALTER TABLE properties ADD COLUMN conservacao VARCHAR(80)",
|
| 66 |
+
"vaga": "ALTER TABLE properties ADD COLUMN vaga VARCHAR(80)",
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
with engine.begin() as connection:
|
| 70 |
+
for column_name, statement in migrations.items():
|
| 71 |
+
if column_name not in existing_columns:
|
| 72 |
+
connection.execute(text(statement))
|
backend/app/main.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
from io import BytesIO
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import pandas as pd
|
| 7 |
+
from fastapi import Depends, FastAPI, File, HTTPException, UploadFile
|
| 8 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 9 |
+
from fastapi.responses import FileResponse, HTMLResponse
|
| 10 |
+
from fastapi.staticfiles import StaticFiles
|
| 11 |
+
from sqlalchemy.orm import Session
|
| 12 |
+
|
| 13 |
+
from . import crud, models, schemas
|
| 14 |
+
from .cadastro_base import ensure_cadastro_base_sqlite, search_cadastro_base
|
| 15 |
+
from .database import BASE_DIR, Base, engine, ensure_property_schema, get_db
|
| 16 |
+
|
| 17 |
+
logger = logging.getLogger(__name__)
|
| 18 |
+
|
| 19 |
+
Base.metadata.create_all(bind=engine)
|
| 20 |
+
ensure_property_schema()
|
| 21 |
+
RESULTS_DIR = BASE_DIR / "data" / "results"
|
| 22 |
+
RESULTS_DIR.mkdir(parents=True, exist_ok=True)
|
| 23 |
+
FRONTEND_DIST_DIR = BASE_DIR.parent / "frontend" / "dist"
|
| 24 |
+
FRONTEND_ASSETS_DIR = FRONTEND_DIST_DIR / "assets"
|
| 25 |
+
|
| 26 |
+
app = FastAPI(
|
| 27 |
+
title="Cadastro Imobiliario API",
|
| 28 |
+
version="0.1.0",
|
| 29 |
+
description="API inicial para cadastro e importacao de dados imobiliarios.",
|
| 30 |
+
)
|
| 31 |
+
|
| 32 |
+
app.add_middleware(
|
| 33 |
+
CORSMiddleware,
|
| 34 |
+
allow_origins=["http://localhost:5173", "http://127.0.0.1:5173"],
|
| 35 |
+
allow_credentials=True,
|
| 36 |
+
allow_methods=["*"],
|
| 37 |
+
allow_headers=["*"],
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
@app.on_event("startup")
|
| 42 |
+
def prepare_cadastro_base():
|
| 43 |
+
try:
|
| 44 |
+
ensure_cadastro_base_sqlite()
|
| 45 |
+
except FileNotFoundError:
|
| 46 |
+
logger.warning("Base auxiliar nao encontrada. A busca cadastral ficara indisponivel.")
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
@app.get("/health")
|
| 50 |
+
def healthcheck():
|
| 51 |
+
return {"status": "ok"}
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
@app.get("/properties", response_model=list[schemas.PropertyRead])
|
| 55 |
+
def get_properties(db: Session = Depends(get_db)):
|
| 56 |
+
return crud.list_properties(db)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
@app.post("/properties", response_model=schemas.PropertyRead, status_code=201)
|
| 60 |
+
def post_property(payload: schemas.PropertyCreate, db: Session = Depends(get_db)):
|
| 61 |
+
return crud.create_property(db, payload)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
@app.delete("/properties/{property_id}", status_code=204)
|
| 65 |
+
def delete_property(property_id: int, db: Session = Depends(get_db)):
|
| 66 |
+
deleted = crud.delete_property(db, property_id)
|
| 67 |
+
if not deleted:
|
| 68 |
+
raise HTTPException(status_code=404, detail="Registro nao encontrado.")
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
@app.get("/properties/export")
|
| 72 |
+
def export_properties(db: Session = Depends(get_db)):
|
| 73 |
+
rows = crud.export_properties(db)
|
| 74 |
+
file_name = f"cadastro_imobiliario_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
|
| 75 |
+
file_path = RESULTS_DIR / file_name
|
| 76 |
+
|
| 77 |
+
df = pd.DataFrame(rows)
|
| 78 |
+
if df.empty:
|
| 79 |
+
df = pd.DataFrame(
|
| 80 |
+
columns=[
|
| 81 |
+
"id",
|
| 82 |
+
"num_bloco",
|
| 83 |
+
"num_inscricao",
|
| 84 |
+
"cod_endloc_logradouro",
|
| 85 |
+
"logradouro",
|
| 86 |
+
"numero",
|
| 87 |
+
"unidade",
|
| 88 |
+
"bairro",
|
| 89 |
+
"finalidade",
|
| 90 |
+
"rh_nome",
|
| 91 |
+
"rh_valor",
|
| 92 |
+
"area_total_separada",
|
| 93 |
+
"area_total_soma",
|
| 94 |
+
"area_privativa_separada",
|
| 95 |
+
"area_privativa_soma",
|
| 96 |
+
"finalidade_oferta",
|
| 97 |
+
"area_total_oferta",
|
| 98 |
+
"area_privativa_oferta",
|
| 99 |
+
"valor_oferta",
|
| 100 |
+
"latitude",
|
| 101 |
+
"longitude",
|
| 102 |
+
"descricao_oferta",
|
| 103 |
+
"observacao",
|
| 104 |
+
"url",
|
| 105 |
+
"imobiliaria",
|
| 106 |
+
"codigo",
|
| 107 |
+
"infra",
|
| 108 |
+
"padrao",
|
| 109 |
+
"conservacao",
|
| 110 |
+
"vaga",
|
| 111 |
+
]
|
| 112 |
+
)
|
| 113 |
+
df.to_excel(file_path, index=False)
|
| 114 |
+
|
| 115 |
+
return FileResponse(
|
| 116 |
+
path=Path(file_path),
|
| 117 |
+
filename=file_name,
|
| 118 |
+
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
| 119 |
+
)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
@app.get("/cadastro-base/search", response_model=schemas.CadastroBaseSearchResponse)
|
| 123 |
+
def get_cadastro_base_search(mode: str, q: str, limit: int = 20):
|
| 124 |
+
try:
|
| 125 |
+
items = search_cadastro_base(mode=mode, query=q, limit=limit)
|
| 126 |
+
except FileNotFoundError as exc:
|
| 127 |
+
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
| 128 |
+
except ValueError as exc:
|
| 129 |
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
| 130 |
+
|
| 131 |
+
return schemas.CadastroBaseSearchResponse(mode=mode, total=len(items), items=items)
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
@app.post("/properties/import-preview", response_model=schemas.SpreadsheetPreview)
|
| 135 |
+
async def import_preview(file: UploadFile = File(...)):
|
| 136 |
+
if not file.filename:
|
| 137 |
+
raise HTTPException(status_code=400, detail="Arquivo invalido.")
|
| 138 |
+
|
| 139 |
+
content = await file.read()
|
| 140 |
+
suffix = file.filename.lower()
|
| 141 |
+
|
| 142 |
+
try:
|
| 143 |
+
if suffix.endswith(".csv"):
|
| 144 |
+
df = pd.read_csv(BytesIO(content))
|
| 145 |
+
elif suffix.endswith(".xlsx") or suffix.endswith(".xls"):
|
| 146 |
+
df = pd.read_excel(BytesIO(content))
|
| 147 |
+
else:
|
| 148 |
+
raise HTTPException(status_code=400, detail="Formato nao suportado. Use CSV ou XLSX.")
|
| 149 |
+
except HTTPException:
|
| 150 |
+
raise
|
| 151 |
+
except Exception as exc:
|
| 152 |
+
raise HTTPException(status_code=400, detail=f"Falha ao ler planilha: {exc}") from exc
|
| 153 |
+
|
| 154 |
+
df = df.where(pd.notnull(df), None)
|
| 155 |
+
preview_rows = df.head(10).to_dict(orient="records")
|
| 156 |
+
|
| 157 |
+
return schemas.SpreadsheetPreview(
|
| 158 |
+
file_name=file.filename,
|
| 159 |
+
columns=[str(column) for column in df.columns.tolist()],
|
| 160 |
+
rows=preview_rows,
|
| 161 |
+
total_rows=len(df),
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
if FRONTEND_ASSETS_DIR.exists():
|
| 166 |
+
app.mount("/assets", StaticFiles(directory=FRONTEND_ASSETS_DIR), name="assets")
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
@app.get("/", response_class=HTMLResponse, include_in_schema=False)
|
| 170 |
+
def serve_frontend_index():
|
| 171 |
+
if FRONTEND_DIST_DIR.exists():
|
| 172 |
+
return FileResponse(FRONTEND_DIST_DIR / "index.html")
|
| 173 |
+
raise HTTPException(status_code=404, detail="Frontend build nao encontrado.")
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
@app.get("/{full_path:path}", response_class=HTMLResponse, include_in_schema=False)
|
| 177 |
+
def serve_frontend_app(full_path: str):
|
| 178 |
+
if full_path.startswith(("properties", "cadastro-base", "health", "docs", "openapi.json")):
|
| 179 |
+
raise HTTPException(status_code=404, detail="Recurso nao encontrado.")
|
| 180 |
+
|
| 181 |
+
requested_path = FRONTEND_DIST_DIR / full_path
|
| 182 |
+
if FRONTEND_DIST_DIR.exists() and requested_path.is_file():
|
| 183 |
+
return FileResponse(requested_path)
|
| 184 |
+
if FRONTEND_DIST_DIR.exists():
|
| 185 |
+
return FileResponse(FRONTEND_DIST_DIR / "index.html")
|
| 186 |
+
raise HTTPException(status_code=404, detail="Frontend build nao encontrado.")
|
backend/app/models.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sqlalchemy import Float, String, Text
|
| 2 |
+
from sqlalchemy.orm import Mapped, mapped_column
|
| 3 |
+
|
| 4 |
+
from .database import Base
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class Property(Base):
|
| 8 |
+
__tablename__ = "properties"
|
| 9 |
+
|
| 10 |
+
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
| 11 |
+
titulo: Mapped[str] = mapped_column(String(1000), nullable=False)
|
| 12 |
+
finalidade: Mapped[str] = mapped_column(String(1000), nullable=False)
|
| 13 |
+
num_bloco: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
| 14 |
+
num_inscricao: Mapped[str | None] = mapped_column(String(1000), nullable=True, index=True)
|
| 15 |
+
cod_endloc_logradouro: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
| 16 |
+
nme_endloc_logradouro: Mapped[str | None] = mapped_column(String(1000), nullable=True, index=True)
|
| 17 |
+
num_endloc_endereco: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
| 18 |
+
num_endloc_unidade: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
| 19 |
+
nme_endloc_bairro_cdl: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
| 20 |
+
rh_nome: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
| 21 |
+
rh_valor: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 22 |
+
coord_x: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 23 |
+
coord_y: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 24 |
+
ano_exercicio: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 25 |
+
num_versao: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 26 |
+
idf_reg_regiao_homogenea: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 27 |
+
area_total_detalhe: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
| 28 |
+
area_total: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 29 |
+
area_privativa_detalhe: Mapped[str | None] = mapped_column(String(1000), nullable=True)
|
| 30 |
+
area_privativa: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 31 |
+
finalidade_oferta: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
| 32 |
+
area_total_oferta: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 33 |
+
area_privativa_oferta: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 34 |
+
valor_oferta: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 35 |
+
latitude: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 36 |
+
longitude: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| 37 |
+
descricao_oferta: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| 38 |
+
observacao: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| 39 |
+
url: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| 40 |
+
imobiliaria: Mapped[str | None] = mapped_column(String(150), nullable=True)
|
| 41 |
+
codigo: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
| 42 |
+
infra: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| 43 |
+
padrao: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
| 44 |
+
conservacao: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
| 45 |
+
vaga: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
| 46 |
+
origem: Mapped[str] = mapped_column(String(30), default="manual", nullable=False)
|
backend/app/schemas.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pydantic import BaseModel, ConfigDict, Field
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class PropertyBase(BaseModel):
|
| 5 |
+
titulo: str | None = Field(default=None, min_length=2, max_length=1000)
|
| 6 |
+
finalidade: str = Field(min_length=2, max_length=1000)
|
| 7 |
+
num_bloco: str | None = Field(default=None, max_length=1000)
|
| 8 |
+
num_inscricao: str | None = Field(default=None, max_length=1000)
|
| 9 |
+
cod_endloc_logradouro: str | None = Field(default=None, max_length=1000)
|
| 10 |
+
nme_endloc_logradouro: str | None = Field(default=None, max_length=1000)
|
| 11 |
+
num_endloc_endereco: str | None = Field(default=None, max_length=1000)
|
| 12 |
+
num_endloc_unidade: str | None = Field(default=None, max_length=1000)
|
| 13 |
+
nme_endloc_bairro_cdl: str | None = Field(default=None, max_length=1000)
|
| 14 |
+
rh_nome: str | None = Field(default=None, max_length=1000)
|
| 15 |
+
rh_valor: float | None = Field(default=None, ge=0)
|
| 16 |
+
coord_x: float | None = None
|
| 17 |
+
coord_y: float | None = None
|
| 18 |
+
ano_exercicio: float | None = Field(default=None, ge=0)
|
| 19 |
+
num_versao: float | None = Field(default=None, ge=0)
|
| 20 |
+
idf_reg_regiao_homogenea: float | None = Field(default=None, ge=0)
|
| 21 |
+
area_total_detalhe: str | None = Field(default=None, max_length=1000)
|
| 22 |
+
area_total: float | None = Field(default=None, ge=0)
|
| 23 |
+
area_privativa_detalhe: str | None = Field(default=None, max_length=1000)
|
| 24 |
+
area_privativa: float | None = Field(default=None, ge=0)
|
| 25 |
+
finalidade_oferta: str | None = Field(default=None, max_length=50)
|
| 26 |
+
area_total_oferta: float | None = Field(default=None, ge=0)
|
| 27 |
+
area_privativa_oferta: float | None = Field(default=None, ge=0)
|
| 28 |
+
valor_oferta: float | None = Field(default=None, ge=0)
|
| 29 |
+
latitude: float | None = None
|
| 30 |
+
longitude: float | None = None
|
| 31 |
+
descricao_oferta: str | None = None
|
| 32 |
+
observacao: str | None = None
|
| 33 |
+
url: str | None = None
|
| 34 |
+
imobiliaria: str | None = Field(default=None, max_length=150)
|
| 35 |
+
codigo: str | None = Field(default=None, max_length=80)
|
| 36 |
+
infra: str | None = None
|
| 37 |
+
padrao: str | None = Field(default=None, max_length=80)
|
| 38 |
+
conservacao: str | None = Field(default=None, max_length=80)
|
| 39 |
+
vaga: str | None = Field(default=None, max_length=80)
|
| 40 |
+
origem: str = "manual"
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
class PropertyCreate(PropertyBase):
|
| 44 |
+
pass
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
class PropertyRead(PropertyBase):
|
| 48 |
+
id: int
|
| 49 |
+
|
| 50 |
+
model_config = ConfigDict(from_attributes=True)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class SpreadsheetPreview(BaseModel):
|
| 54 |
+
file_name: str
|
| 55 |
+
columns: list[str]
|
| 56 |
+
rows: list[dict]
|
| 57 |
+
total_rows: int
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
class CadastroBaseRecord(BaseModel):
|
| 61 |
+
num_bloco: str | None = None
|
| 62 |
+
num_inscricao: str
|
| 63 |
+
cod_endloc_logradouro: str | None = None
|
| 64 |
+
nme_endloc_logradouro: str | None = None
|
| 65 |
+
num_endloc_endereco: str | None = None
|
| 66 |
+
num_endloc_unidade: str | None = None
|
| 67 |
+
nme_endloc_bairro_cdl: str | None = None
|
| 68 |
+
des_finalidade: str | None = None
|
| 69 |
+
rh_nome: str | None = None
|
| 70 |
+
rh_valor: float | None = None
|
| 71 |
+
coord_x: float | None = None
|
| 72 |
+
coord_y: float | None = None
|
| 73 |
+
ano_exercicio: float | None = None
|
| 74 |
+
num_versao: float | None = None
|
| 75 |
+
idf_reg_regiao_homogenea: float | None = None
|
| 76 |
+
area_territorial: float | None = None
|
| 77 |
+
area_construida: float | None = None
|
| 78 |
+
latitude: float | None = None
|
| 79 |
+
longitude: float | None = None
|
| 80 |
+
titulo_sugerido: str
|
| 81 |
+
display_label: str
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
class CadastroBaseSearchResponse(BaseModel):
|
| 85 |
+
mode: str
|
| 86 |
+
total: int
|
| 87 |
+
items: list[CadastroBaseRecord]
|
backend/data/base/cadastro_base_space_filtrada.db
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3ecdb05ddc8f2bfcf468a35d5456cd33802b5721ad6298103a7431b2b2358c3c
|
| 3 |
+
size 54325248
|
backend/requirements.txt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi==0.118.0
|
| 2 |
+
uvicorn[standard]==0.37.0
|
| 3 |
+
sqlalchemy==2.0.43
|
| 4 |
+
pydantic==2.11.7
|
| 5 |
+
pandas==2.3.3
|
| 6 |
+
openpyxl==3.1.5
|
| 7 |
+
python-multipart==0.0.20
|
| 8 |
+
|
backend/scripts/rebuild_cadastro_base.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
BASE_DIR = Path(__file__).resolve().parents[1]
|
| 5 |
+
if str(BASE_DIR) not in sys.path:
|
| 6 |
+
sys.path.insert(0, str(BASE_DIR))
|
| 7 |
+
|
| 8 |
+
from app.cadastro_base import ensure_cadastro_base_sqlite
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
if __name__ == "__main__":
|
| 12 |
+
db_path, row_count = ensure_cadastro_base_sqlite(force_rebuild=True)
|
| 13 |
+
print(f"Base SQLite atualizada: {db_path} ({row_count} registros)")
|
frontend/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
+
<html lang="pt-BR">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
<title>Cadastro Imobiliario</title>
|
| 7 |
+
</head>
|
| 8 |
+
<body>
|
| 9 |
+
<div id="root"></div>
|
| 10 |
+
<script type="module" src="/src/main.tsx"></script>
|
| 11 |
+
</body>
|
| 12 |
+
</html>
|
| 13 |
+
|
frontend/package-lock.json
ADDED
|
@@ -0,0 +1,1729 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "cadastro-imobiliario-frontend",
|
| 3 |
+
"version": "0.1.0",
|
| 4 |
+
"lockfileVersion": 3,
|
| 5 |
+
"requires": true,
|
| 6 |
+
"packages": {
|
| 7 |
+
"": {
|
| 8 |
+
"name": "cadastro-imobiliario-frontend",
|
| 9 |
+
"version": "0.1.0",
|
| 10 |
+
"dependencies": {
|
| 11 |
+
"react": "^18.3.1",
|
| 12 |
+
"react-dom": "^18.3.1"
|
| 13 |
+
},
|
| 14 |
+
"devDependencies": {
|
| 15 |
+
"@types/react": "^18.3.12",
|
| 16 |
+
"@types/react-dom": "^18.3.1",
|
| 17 |
+
"@vitejs/plugin-react": "^4.3.4",
|
| 18 |
+
"typescript": "^5.6.3",
|
| 19 |
+
"vite": "^5.4.10"
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"node_modules/@babel/code-frame": {
|
| 23 |
+
"version": "7.29.0",
|
| 24 |
+
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
| 25 |
+
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
|
| 26 |
+
"dev": true,
|
| 27 |
+
"license": "MIT",
|
| 28 |
+
"dependencies": {
|
| 29 |
+
"@babel/helper-validator-identifier": "^7.28.5",
|
| 30 |
+
"js-tokens": "^4.0.0",
|
| 31 |
+
"picocolors": "^1.1.1"
|
| 32 |
+
},
|
| 33 |
+
"engines": {
|
| 34 |
+
"node": ">=6.9.0"
|
| 35 |
+
}
|
| 36 |
+
},
|
| 37 |
+
"node_modules/@babel/compat-data": {
|
| 38 |
+
"version": "7.29.0",
|
| 39 |
+
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
|
| 40 |
+
"integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
|
| 41 |
+
"dev": true,
|
| 42 |
+
"license": "MIT",
|
| 43 |
+
"engines": {
|
| 44 |
+
"node": ">=6.9.0"
|
| 45 |
+
}
|
| 46 |
+
},
|
| 47 |
+
"node_modules/@babel/core": {
|
| 48 |
+
"version": "7.29.0",
|
| 49 |
+
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
|
| 50 |
+
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
| 51 |
+
"dev": true,
|
| 52 |
+
"license": "MIT",
|
| 53 |
+
"dependencies": {
|
| 54 |
+
"@babel/code-frame": "^7.29.0",
|
| 55 |
+
"@babel/generator": "^7.29.0",
|
| 56 |
+
"@babel/helper-compilation-targets": "^7.28.6",
|
| 57 |
+
"@babel/helper-module-transforms": "^7.28.6",
|
| 58 |
+
"@babel/helpers": "^7.28.6",
|
| 59 |
+
"@babel/parser": "^7.29.0",
|
| 60 |
+
"@babel/template": "^7.28.6",
|
| 61 |
+
"@babel/traverse": "^7.29.0",
|
| 62 |
+
"@babel/types": "^7.29.0",
|
| 63 |
+
"@jridgewell/remapping": "^2.3.5",
|
| 64 |
+
"convert-source-map": "^2.0.0",
|
| 65 |
+
"debug": "^4.1.0",
|
| 66 |
+
"gensync": "^1.0.0-beta.2",
|
| 67 |
+
"json5": "^2.2.3",
|
| 68 |
+
"semver": "^6.3.1"
|
| 69 |
+
},
|
| 70 |
+
"engines": {
|
| 71 |
+
"node": ">=6.9.0"
|
| 72 |
+
},
|
| 73 |
+
"funding": {
|
| 74 |
+
"type": "opencollective",
|
| 75 |
+
"url": "https://opencollective.com/babel"
|
| 76 |
+
}
|
| 77 |
+
},
|
| 78 |
+
"node_modules/@babel/generator": {
|
| 79 |
+
"version": "7.29.1",
|
| 80 |
+
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
|
| 81 |
+
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
|
| 82 |
+
"dev": true,
|
| 83 |
+
"license": "MIT",
|
| 84 |
+
"dependencies": {
|
| 85 |
+
"@babel/parser": "^7.29.0",
|
| 86 |
+
"@babel/types": "^7.29.0",
|
| 87 |
+
"@jridgewell/gen-mapping": "^0.3.12",
|
| 88 |
+
"@jridgewell/trace-mapping": "^0.3.28",
|
| 89 |
+
"jsesc": "^3.0.2"
|
| 90 |
+
},
|
| 91 |
+
"engines": {
|
| 92 |
+
"node": ">=6.9.0"
|
| 93 |
+
}
|
| 94 |
+
},
|
| 95 |
+
"node_modules/@babel/helper-compilation-targets": {
|
| 96 |
+
"version": "7.28.6",
|
| 97 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
|
| 98 |
+
"integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
|
| 99 |
+
"dev": true,
|
| 100 |
+
"license": "MIT",
|
| 101 |
+
"dependencies": {
|
| 102 |
+
"@babel/compat-data": "^7.28.6",
|
| 103 |
+
"@babel/helper-validator-option": "^7.27.1",
|
| 104 |
+
"browserslist": "^4.24.0",
|
| 105 |
+
"lru-cache": "^5.1.1",
|
| 106 |
+
"semver": "^6.3.1"
|
| 107 |
+
},
|
| 108 |
+
"engines": {
|
| 109 |
+
"node": ">=6.9.0"
|
| 110 |
+
}
|
| 111 |
+
},
|
| 112 |
+
"node_modules/@babel/helper-globals": {
|
| 113 |
+
"version": "7.28.0",
|
| 114 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
|
| 115 |
+
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
|
| 116 |
+
"dev": true,
|
| 117 |
+
"license": "MIT",
|
| 118 |
+
"engines": {
|
| 119 |
+
"node": ">=6.9.0"
|
| 120 |
+
}
|
| 121 |
+
},
|
| 122 |
+
"node_modules/@babel/helper-module-imports": {
|
| 123 |
+
"version": "7.28.6",
|
| 124 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
|
| 125 |
+
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
|
| 126 |
+
"dev": true,
|
| 127 |
+
"license": "MIT",
|
| 128 |
+
"dependencies": {
|
| 129 |
+
"@babel/traverse": "^7.28.6",
|
| 130 |
+
"@babel/types": "^7.28.6"
|
| 131 |
+
},
|
| 132 |
+
"engines": {
|
| 133 |
+
"node": ">=6.9.0"
|
| 134 |
+
}
|
| 135 |
+
},
|
| 136 |
+
"node_modules/@babel/helper-module-transforms": {
|
| 137 |
+
"version": "7.28.6",
|
| 138 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
|
| 139 |
+
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
|
| 140 |
+
"dev": true,
|
| 141 |
+
"license": "MIT",
|
| 142 |
+
"dependencies": {
|
| 143 |
+
"@babel/helper-module-imports": "^7.28.6",
|
| 144 |
+
"@babel/helper-validator-identifier": "^7.28.5",
|
| 145 |
+
"@babel/traverse": "^7.28.6"
|
| 146 |
+
},
|
| 147 |
+
"engines": {
|
| 148 |
+
"node": ">=6.9.0"
|
| 149 |
+
},
|
| 150 |
+
"peerDependencies": {
|
| 151 |
+
"@babel/core": "^7.0.0"
|
| 152 |
+
}
|
| 153 |
+
},
|
| 154 |
+
"node_modules/@babel/helper-plugin-utils": {
|
| 155 |
+
"version": "7.28.6",
|
| 156 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
|
| 157 |
+
"integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
|
| 158 |
+
"dev": true,
|
| 159 |
+
"license": "MIT",
|
| 160 |
+
"engines": {
|
| 161 |
+
"node": ">=6.9.0"
|
| 162 |
+
}
|
| 163 |
+
},
|
| 164 |
+
"node_modules/@babel/helper-string-parser": {
|
| 165 |
+
"version": "7.27.1",
|
| 166 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
| 167 |
+
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
| 168 |
+
"dev": true,
|
| 169 |
+
"license": "MIT",
|
| 170 |
+
"engines": {
|
| 171 |
+
"node": ">=6.9.0"
|
| 172 |
+
}
|
| 173 |
+
},
|
| 174 |
+
"node_modules/@babel/helper-validator-identifier": {
|
| 175 |
+
"version": "7.28.5",
|
| 176 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
|
| 177 |
+
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
|
| 178 |
+
"dev": true,
|
| 179 |
+
"license": "MIT",
|
| 180 |
+
"engines": {
|
| 181 |
+
"node": ">=6.9.0"
|
| 182 |
+
}
|
| 183 |
+
},
|
| 184 |
+
"node_modules/@babel/helper-validator-option": {
|
| 185 |
+
"version": "7.27.1",
|
| 186 |
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
|
| 187 |
+
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
|
| 188 |
+
"dev": true,
|
| 189 |
+
"license": "MIT",
|
| 190 |
+
"engines": {
|
| 191 |
+
"node": ">=6.9.0"
|
| 192 |
+
}
|
| 193 |
+
},
|
| 194 |
+
"node_modules/@babel/helpers": {
|
| 195 |
+
"version": "7.29.2",
|
| 196 |
+
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
|
| 197 |
+
"integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
|
| 198 |
+
"dev": true,
|
| 199 |
+
"license": "MIT",
|
| 200 |
+
"dependencies": {
|
| 201 |
+
"@babel/template": "^7.28.6",
|
| 202 |
+
"@babel/types": "^7.29.0"
|
| 203 |
+
},
|
| 204 |
+
"engines": {
|
| 205 |
+
"node": ">=6.9.0"
|
| 206 |
+
}
|
| 207 |
+
},
|
| 208 |
+
"node_modules/@babel/parser": {
|
| 209 |
+
"version": "7.29.2",
|
| 210 |
+
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz",
|
| 211 |
+
"integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==",
|
| 212 |
+
"dev": true,
|
| 213 |
+
"license": "MIT",
|
| 214 |
+
"dependencies": {
|
| 215 |
+
"@babel/types": "^7.29.0"
|
| 216 |
+
},
|
| 217 |
+
"bin": {
|
| 218 |
+
"parser": "bin/babel-parser.js"
|
| 219 |
+
},
|
| 220 |
+
"engines": {
|
| 221 |
+
"node": ">=6.0.0"
|
| 222 |
+
}
|
| 223 |
+
},
|
| 224 |
+
"node_modules/@babel/plugin-transform-react-jsx-self": {
|
| 225 |
+
"version": "7.27.1",
|
| 226 |
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
|
| 227 |
+
"integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
|
| 228 |
+
"dev": true,
|
| 229 |
+
"license": "MIT",
|
| 230 |
+
"dependencies": {
|
| 231 |
+
"@babel/helper-plugin-utils": "^7.27.1"
|
| 232 |
+
},
|
| 233 |
+
"engines": {
|
| 234 |
+
"node": ">=6.9.0"
|
| 235 |
+
},
|
| 236 |
+
"peerDependencies": {
|
| 237 |
+
"@babel/core": "^7.0.0-0"
|
| 238 |
+
}
|
| 239 |
+
},
|
| 240 |
+
"node_modules/@babel/plugin-transform-react-jsx-source": {
|
| 241 |
+
"version": "7.27.1",
|
| 242 |
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
|
| 243 |
+
"integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
|
| 244 |
+
"dev": true,
|
| 245 |
+
"license": "MIT",
|
| 246 |
+
"dependencies": {
|
| 247 |
+
"@babel/helper-plugin-utils": "^7.27.1"
|
| 248 |
+
},
|
| 249 |
+
"engines": {
|
| 250 |
+
"node": ">=6.9.0"
|
| 251 |
+
},
|
| 252 |
+
"peerDependencies": {
|
| 253 |
+
"@babel/core": "^7.0.0-0"
|
| 254 |
+
}
|
| 255 |
+
},
|
| 256 |
+
"node_modules/@babel/template": {
|
| 257 |
+
"version": "7.28.6",
|
| 258 |
+
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
|
| 259 |
+
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
|
| 260 |
+
"dev": true,
|
| 261 |
+
"license": "MIT",
|
| 262 |
+
"dependencies": {
|
| 263 |
+
"@babel/code-frame": "^7.28.6",
|
| 264 |
+
"@babel/parser": "^7.28.6",
|
| 265 |
+
"@babel/types": "^7.28.6"
|
| 266 |
+
},
|
| 267 |
+
"engines": {
|
| 268 |
+
"node": ">=6.9.0"
|
| 269 |
+
}
|
| 270 |
+
},
|
| 271 |
+
"node_modules/@babel/traverse": {
|
| 272 |
+
"version": "7.29.0",
|
| 273 |
+
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
|
| 274 |
+
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
|
| 275 |
+
"dev": true,
|
| 276 |
+
"license": "MIT",
|
| 277 |
+
"dependencies": {
|
| 278 |
+
"@babel/code-frame": "^7.29.0",
|
| 279 |
+
"@babel/generator": "^7.29.0",
|
| 280 |
+
"@babel/helper-globals": "^7.28.0",
|
| 281 |
+
"@babel/parser": "^7.29.0",
|
| 282 |
+
"@babel/template": "^7.28.6",
|
| 283 |
+
"@babel/types": "^7.29.0",
|
| 284 |
+
"debug": "^4.3.1"
|
| 285 |
+
},
|
| 286 |
+
"engines": {
|
| 287 |
+
"node": ">=6.9.0"
|
| 288 |
+
}
|
| 289 |
+
},
|
| 290 |
+
"node_modules/@babel/types": {
|
| 291 |
+
"version": "7.29.0",
|
| 292 |
+
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
|
| 293 |
+
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
|
| 294 |
+
"dev": true,
|
| 295 |
+
"license": "MIT",
|
| 296 |
+
"dependencies": {
|
| 297 |
+
"@babel/helper-string-parser": "^7.27.1",
|
| 298 |
+
"@babel/helper-validator-identifier": "^7.28.5"
|
| 299 |
+
},
|
| 300 |
+
"engines": {
|
| 301 |
+
"node": ">=6.9.0"
|
| 302 |
+
}
|
| 303 |
+
},
|
| 304 |
+
"node_modules/@esbuild/aix-ppc64": {
|
| 305 |
+
"version": "0.21.5",
|
| 306 |
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
| 307 |
+
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
| 308 |
+
"cpu": [
|
| 309 |
+
"ppc64"
|
| 310 |
+
],
|
| 311 |
+
"dev": true,
|
| 312 |
+
"license": "MIT",
|
| 313 |
+
"optional": true,
|
| 314 |
+
"os": [
|
| 315 |
+
"aix"
|
| 316 |
+
],
|
| 317 |
+
"engines": {
|
| 318 |
+
"node": ">=12"
|
| 319 |
+
}
|
| 320 |
+
},
|
| 321 |
+
"node_modules/@esbuild/android-arm": {
|
| 322 |
+
"version": "0.21.5",
|
| 323 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
| 324 |
+
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
| 325 |
+
"cpu": [
|
| 326 |
+
"arm"
|
| 327 |
+
],
|
| 328 |
+
"dev": true,
|
| 329 |
+
"license": "MIT",
|
| 330 |
+
"optional": true,
|
| 331 |
+
"os": [
|
| 332 |
+
"android"
|
| 333 |
+
],
|
| 334 |
+
"engines": {
|
| 335 |
+
"node": ">=12"
|
| 336 |
+
}
|
| 337 |
+
},
|
| 338 |
+
"node_modules/@esbuild/android-arm64": {
|
| 339 |
+
"version": "0.21.5",
|
| 340 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
| 341 |
+
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
| 342 |
+
"cpu": [
|
| 343 |
+
"arm64"
|
| 344 |
+
],
|
| 345 |
+
"dev": true,
|
| 346 |
+
"license": "MIT",
|
| 347 |
+
"optional": true,
|
| 348 |
+
"os": [
|
| 349 |
+
"android"
|
| 350 |
+
],
|
| 351 |
+
"engines": {
|
| 352 |
+
"node": ">=12"
|
| 353 |
+
}
|
| 354 |
+
},
|
| 355 |
+
"node_modules/@esbuild/android-x64": {
|
| 356 |
+
"version": "0.21.5",
|
| 357 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
| 358 |
+
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
| 359 |
+
"cpu": [
|
| 360 |
+
"x64"
|
| 361 |
+
],
|
| 362 |
+
"dev": true,
|
| 363 |
+
"license": "MIT",
|
| 364 |
+
"optional": true,
|
| 365 |
+
"os": [
|
| 366 |
+
"android"
|
| 367 |
+
],
|
| 368 |
+
"engines": {
|
| 369 |
+
"node": ">=12"
|
| 370 |
+
}
|
| 371 |
+
},
|
| 372 |
+
"node_modules/@esbuild/darwin-arm64": {
|
| 373 |
+
"version": "0.21.5",
|
| 374 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
| 375 |
+
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
| 376 |
+
"cpu": [
|
| 377 |
+
"arm64"
|
| 378 |
+
],
|
| 379 |
+
"dev": true,
|
| 380 |
+
"license": "MIT",
|
| 381 |
+
"optional": true,
|
| 382 |
+
"os": [
|
| 383 |
+
"darwin"
|
| 384 |
+
],
|
| 385 |
+
"engines": {
|
| 386 |
+
"node": ">=12"
|
| 387 |
+
}
|
| 388 |
+
},
|
| 389 |
+
"node_modules/@esbuild/darwin-x64": {
|
| 390 |
+
"version": "0.21.5",
|
| 391 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
| 392 |
+
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
| 393 |
+
"cpu": [
|
| 394 |
+
"x64"
|
| 395 |
+
],
|
| 396 |
+
"dev": true,
|
| 397 |
+
"license": "MIT",
|
| 398 |
+
"optional": true,
|
| 399 |
+
"os": [
|
| 400 |
+
"darwin"
|
| 401 |
+
],
|
| 402 |
+
"engines": {
|
| 403 |
+
"node": ">=12"
|
| 404 |
+
}
|
| 405 |
+
},
|
| 406 |
+
"node_modules/@esbuild/freebsd-arm64": {
|
| 407 |
+
"version": "0.21.5",
|
| 408 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
| 409 |
+
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
| 410 |
+
"cpu": [
|
| 411 |
+
"arm64"
|
| 412 |
+
],
|
| 413 |
+
"dev": true,
|
| 414 |
+
"license": "MIT",
|
| 415 |
+
"optional": true,
|
| 416 |
+
"os": [
|
| 417 |
+
"freebsd"
|
| 418 |
+
],
|
| 419 |
+
"engines": {
|
| 420 |
+
"node": ">=12"
|
| 421 |
+
}
|
| 422 |
+
},
|
| 423 |
+
"node_modules/@esbuild/freebsd-x64": {
|
| 424 |
+
"version": "0.21.5",
|
| 425 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
| 426 |
+
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
| 427 |
+
"cpu": [
|
| 428 |
+
"x64"
|
| 429 |
+
],
|
| 430 |
+
"dev": true,
|
| 431 |
+
"license": "MIT",
|
| 432 |
+
"optional": true,
|
| 433 |
+
"os": [
|
| 434 |
+
"freebsd"
|
| 435 |
+
],
|
| 436 |
+
"engines": {
|
| 437 |
+
"node": ">=12"
|
| 438 |
+
}
|
| 439 |
+
},
|
| 440 |
+
"node_modules/@esbuild/linux-arm": {
|
| 441 |
+
"version": "0.21.5",
|
| 442 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
| 443 |
+
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
| 444 |
+
"cpu": [
|
| 445 |
+
"arm"
|
| 446 |
+
],
|
| 447 |
+
"dev": true,
|
| 448 |
+
"license": "MIT",
|
| 449 |
+
"optional": true,
|
| 450 |
+
"os": [
|
| 451 |
+
"linux"
|
| 452 |
+
],
|
| 453 |
+
"engines": {
|
| 454 |
+
"node": ">=12"
|
| 455 |
+
}
|
| 456 |
+
},
|
| 457 |
+
"node_modules/@esbuild/linux-arm64": {
|
| 458 |
+
"version": "0.21.5",
|
| 459 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
| 460 |
+
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
| 461 |
+
"cpu": [
|
| 462 |
+
"arm64"
|
| 463 |
+
],
|
| 464 |
+
"dev": true,
|
| 465 |
+
"license": "MIT",
|
| 466 |
+
"optional": true,
|
| 467 |
+
"os": [
|
| 468 |
+
"linux"
|
| 469 |
+
],
|
| 470 |
+
"engines": {
|
| 471 |
+
"node": ">=12"
|
| 472 |
+
}
|
| 473 |
+
},
|
| 474 |
+
"node_modules/@esbuild/linux-ia32": {
|
| 475 |
+
"version": "0.21.5",
|
| 476 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
| 477 |
+
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
| 478 |
+
"cpu": [
|
| 479 |
+
"ia32"
|
| 480 |
+
],
|
| 481 |
+
"dev": true,
|
| 482 |
+
"license": "MIT",
|
| 483 |
+
"optional": true,
|
| 484 |
+
"os": [
|
| 485 |
+
"linux"
|
| 486 |
+
],
|
| 487 |
+
"engines": {
|
| 488 |
+
"node": ">=12"
|
| 489 |
+
}
|
| 490 |
+
},
|
| 491 |
+
"node_modules/@esbuild/linux-loong64": {
|
| 492 |
+
"version": "0.21.5",
|
| 493 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
| 494 |
+
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
| 495 |
+
"cpu": [
|
| 496 |
+
"loong64"
|
| 497 |
+
],
|
| 498 |
+
"dev": true,
|
| 499 |
+
"license": "MIT",
|
| 500 |
+
"optional": true,
|
| 501 |
+
"os": [
|
| 502 |
+
"linux"
|
| 503 |
+
],
|
| 504 |
+
"engines": {
|
| 505 |
+
"node": ">=12"
|
| 506 |
+
}
|
| 507 |
+
},
|
| 508 |
+
"node_modules/@esbuild/linux-mips64el": {
|
| 509 |
+
"version": "0.21.5",
|
| 510 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
| 511 |
+
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
| 512 |
+
"cpu": [
|
| 513 |
+
"mips64el"
|
| 514 |
+
],
|
| 515 |
+
"dev": true,
|
| 516 |
+
"license": "MIT",
|
| 517 |
+
"optional": true,
|
| 518 |
+
"os": [
|
| 519 |
+
"linux"
|
| 520 |
+
],
|
| 521 |
+
"engines": {
|
| 522 |
+
"node": ">=12"
|
| 523 |
+
}
|
| 524 |
+
},
|
| 525 |
+
"node_modules/@esbuild/linux-ppc64": {
|
| 526 |
+
"version": "0.21.5",
|
| 527 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
| 528 |
+
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
| 529 |
+
"cpu": [
|
| 530 |
+
"ppc64"
|
| 531 |
+
],
|
| 532 |
+
"dev": true,
|
| 533 |
+
"license": "MIT",
|
| 534 |
+
"optional": true,
|
| 535 |
+
"os": [
|
| 536 |
+
"linux"
|
| 537 |
+
],
|
| 538 |
+
"engines": {
|
| 539 |
+
"node": ">=12"
|
| 540 |
+
}
|
| 541 |
+
},
|
| 542 |
+
"node_modules/@esbuild/linux-riscv64": {
|
| 543 |
+
"version": "0.21.5",
|
| 544 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
| 545 |
+
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
| 546 |
+
"cpu": [
|
| 547 |
+
"riscv64"
|
| 548 |
+
],
|
| 549 |
+
"dev": true,
|
| 550 |
+
"license": "MIT",
|
| 551 |
+
"optional": true,
|
| 552 |
+
"os": [
|
| 553 |
+
"linux"
|
| 554 |
+
],
|
| 555 |
+
"engines": {
|
| 556 |
+
"node": ">=12"
|
| 557 |
+
}
|
| 558 |
+
},
|
| 559 |
+
"node_modules/@esbuild/linux-s390x": {
|
| 560 |
+
"version": "0.21.5",
|
| 561 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
| 562 |
+
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
| 563 |
+
"cpu": [
|
| 564 |
+
"s390x"
|
| 565 |
+
],
|
| 566 |
+
"dev": true,
|
| 567 |
+
"license": "MIT",
|
| 568 |
+
"optional": true,
|
| 569 |
+
"os": [
|
| 570 |
+
"linux"
|
| 571 |
+
],
|
| 572 |
+
"engines": {
|
| 573 |
+
"node": ">=12"
|
| 574 |
+
}
|
| 575 |
+
},
|
| 576 |
+
"node_modules/@esbuild/linux-x64": {
|
| 577 |
+
"version": "0.21.5",
|
| 578 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
| 579 |
+
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
| 580 |
+
"cpu": [
|
| 581 |
+
"x64"
|
| 582 |
+
],
|
| 583 |
+
"dev": true,
|
| 584 |
+
"license": "MIT",
|
| 585 |
+
"optional": true,
|
| 586 |
+
"os": [
|
| 587 |
+
"linux"
|
| 588 |
+
],
|
| 589 |
+
"engines": {
|
| 590 |
+
"node": ">=12"
|
| 591 |
+
}
|
| 592 |
+
},
|
| 593 |
+
"node_modules/@esbuild/netbsd-x64": {
|
| 594 |
+
"version": "0.21.5",
|
| 595 |
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
| 596 |
+
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
| 597 |
+
"cpu": [
|
| 598 |
+
"x64"
|
| 599 |
+
],
|
| 600 |
+
"dev": true,
|
| 601 |
+
"license": "MIT",
|
| 602 |
+
"optional": true,
|
| 603 |
+
"os": [
|
| 604 |
+
"netbsd"
|
| 605 |
+
],
|
| 606 |
+
"engines": {
|
| 607 |
+
"node": ">=12"
|
| 608 |
+
}
|
| 609 |
+
},
|
| 610 |
+
"node_modules/@esbuild/openbsd-x64": {
|
| 611 |
+
"version": "0.21.5",
|
| 612 |
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
| 613 |
+
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
| 614 |
+
"cpu": [
|
| 615 |
+
"x64"
|
| 616 |
+
],
|
| 617 |
+
"dev": true,
|
| 618 |
+
"license": "MIT",
|
| 619 |
+
"optional": true,
|
| 620 |
+
"os": [
|
| 621 |
+
"openbsd"
|
| 622 |
+
],
|
| 623 |
+
"engines": {
|
| 624 |
+
"node": ">=12"
|
| 625 |
+
}
|
| 626 |
+
},
|
| 627 |
+
"node_modules/@esbuild/sunos-x64": {
|
| 628 |
+
"version": "0.21.5",
|
| 629 |
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
| 630 |
+
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
| 631 |
+
"cpu": [
|
| 632 |
+
"x64"
|
| 633 |
+
],
|
| 634 |
+
"dev": true,
|
| 635 |
+
"license": "MIT",
|
| 636 |
+
"optional": true,
|
| 637 |
+
"os": [
|
| 638 |
+
"sunos"
|
| 639 |
+
],
|
| 640 |
+
"engines": {
|
| 641 |
+
"node": ">=12"
|
| 642 |
+
}
|
| 643 |
+
},
|
| 644 |
+
"node_modules/@esbuild/win32-arm64": {
|
| 645 |
+
"version": "0.21.5",
|
| 646 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
| 647 |
+
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
| 648 |
+
"cpu": [
|
| 649 |
+
"arm64"
|
| 650 |
+
],
|
| 651 |
+
"dev": true,
|
| 652 |
+
"license": "MIT",
|
| 653 |
+
"optional": true,
|
| 654 |
+
"os": [
|
| 655 |
+
"win32"
|
| 656 |
+
],
|
| 657 |
+
"engines": {
|
| 658 |
+
"node": ">=12"
|
| 659 |
+
}
|
| 660 |
+
},
|
| 661 |
+
"node_modules/@esbuild/win32-ia32": {
|
| 662 |
+
"version": "0.21.5",
|
| 663 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
| 664 |
+
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
| 665 |
+
"cpu": [
|
| 666 |
+
"ia32"
|
| 667 |
+
],
|
| 668 |
+
"dev": true,
|
| 669 |
+
"license": "MIT",
|
| 670 |
+
"optional": true,
|
| 671 |
+
"os": [
|
| 672 |
+
"win32"
|
| 673 |
+
],
|
| 674 |
+
"engines": {
|
| 675 |
+
"node": ">=12"
|
| 676 |
+
}
|
| 677 |
+
},
|
| 678 |
+
"node_modules/@esbuild/win32-x64": {
|
| 679 |
+
"version": "0.21.5",
|
| 680 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
| 681 |
+
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
| 682 |
+
"cpu": [
|
| 683 |
+
"x64"
|
| 684 |
+
],
|
| 685 |
+
"dev": true,
|
| 686 |
+
"license": "MIT",
|
| 687 |
+
"optional": true,
|
| 688 |
+
"os": [
|
| 689 |
+
"win32"
|
| 690 |
+
],
|
| 691 |
+
"engines": {
|
| 692 |
+
"node": ">=12"
|
| 693 |
+
}
|
| 694 |
+
},
|
| 695 |
+
"node_modules/@jridgewell/gen-mapping": {
|
| 696 |
+
"version": "0.3.13",
|
| 697 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
| 698 |
+
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
| 699 |
+
"dev": true,
|
| 700 |
+
"license": "MIT",
|
| 701 |
+
"dependencies": {
|
| 702 |
+
"@jridgewell/sourcemap-codec": "^1.5.0",
|
| 703 |
+
"@jridgewell/trace-mapping": "^0.3.24"
|
| 704 |
+
}
|
| 705 |
+
},
|
| 706 |
+
"node_modules/@jridgewell/remapping": {
|
| 707 |
+
"version": "2.3.5",
|
| 708 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
|
| 709 |
+
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
|
| 710 |
+
"dev": true,
|
| 711 |
+
"license": "MIT",
|
| 712 |
+
"dependencies": {
|
| 713 |
+
"@jridgewell/gen-mapping": "^0.3.5",
|
| 714 |
+
"@jridgewell/trace-mapping": "^0.3.24"
|
| 715 |
+
}
|
| 716 |
+
},
|
| 717 |
+
"node_modules/@jridgewell/resolve-uri": {
|
| 718 |
+
"version": "3.1.2",
|
| 719 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
| 720 |
+
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
| 721 |
+
"dev": true,
|
| 722 |
+
"license": "MIT",
|
| 723 |
+
"engines": {
|
| 724 |
+
"node": ">=6.0.0"
|
| 725 |
+
}
|
| 726 |
+
},
|
| 727 |
+
"node_modules/@jridgewell/sourcemap-codec": {
|
| 728 |
+
"version": "1.5.5",
|
| 729 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
| 730 |
+
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
| 731 |
+
"dev": true,
|
| 732 |
+
"license": "MIT"
|
| 733 |
+
},
|
| 734 |
+
"node_modules/@jridgewell/trace-mapping": {
|
| 735 |
+
"version": "0.3.31",
|
| 736 |
+
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
| 737 |
+
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
| 738 |
+
"dev": true,
|
| 739 |
+
"license": "MIT",
|
| 740 |
+
"dependencies": {
|
| 741 |
+
"@jridgewell/resolve-uri": "^3.1.0",
|
| 742 |
+
"@jridgewell/sourcemap-codec": "^1.4.14"
|
| 743 |
+
}
|
| 744 |
+
},
|
| 745 |
+
"node_modules/@rolldown/pluginutils": {
|
| 746 |
+
"version": "1.0.0-beta.27",
|
| 747 |
+
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
|
| 748 |
+
"integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
|
| 749 |
+
"dev": true,
|
| 750 |
+
"license": "MIT"
|
| 751 |
+
},
|
| 752 |
+
"node_modules/@rollup/rollup-android-arm-eabi": {
|
| 753 |
+
"version": "4.60.1",
|
| 754 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz",
|
| 755 |
+
"integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==",
|
| 756 |
+
"cpu": [
|
| 757 |
+
"arm"
|
| 758 |
+
],
|
| 759 |
+
"dev": true,
|
| 760 |
+
"license": "MIT",
|
| 761 |
+
"optional": true,
|
| 762 |
+
"os": [
|
| 763 |
+
"android"
|
| 764 |
+
]
|
| 765 |
+
},
|
| 766 |
+
"node_modules/@rollup/rollup-android-arm64": {
|
| 767 |
+
"version": "4.60.1",
|
| 768 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz",
|
| 769 |
+
"integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==",
|
| 770 |
+
"cpu": [
|
| 771 |
+
"arm64"
|
| 772 |
+
],
|
| 773 |
+
"dev": true,
|
| 774 |
+
"license": "MIT",
|
| 775 |
+
"optional": true,
|
| 776 |
+
"os": [
|
| 777 |
+
"android"
|
| 778 |
+
]
|
| 779 |
+
},
|
| 780 |
+
"node_modules/@rollup/rollup-darwin-arm64": {
|
| 781 |
+
"version": "4.60.1",
|
| 782 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz",
|
| 783 |
+
"integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==",
|
| 784 |
+
"cpu": [
|
| 785 |
+
"arm64"
|
| 786 |
+
],
|
| 787 |
+
"dev": true,
|
| 788 |
+
"license": "MIT",
|
| 789 |
+
"optional": true,
|
| 790 |
+
"os": [
|
| 791 |
+
"darwin"
|
| 792 |
+
]
|
| 793 |
+
},
|
| 794 |
+
"node_modules/@rollup/rollup-darwin-x64": {
|
| 795 |
+
"version": "4.60.1",
|
| 796 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz",
|
| 797 |
+
"integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==",
|
| 798 |
+
"cpu": [
|
| 799 |
+
"x64"
|
| 800 |
+
],
|
| 801 |
+
"dev": true,
|
| 802 |
+
"license": "MIT",
|
| 803 |
+
"optional": true,
|
| 804 |
+
"os": [
|
| 805 |
+
"darwin"
|
| 806 |
+
]
|
| 807 |
+
},
|
| 808 |
+
"node_modules/@rollup/rollup-freebsd-arm64": {
|
| 809 |
+
"version": "4.60.1",
|
| 810 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz",
|
| 811 |
+
"integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==",
|
| 812 |
+
"cpu": [
|
| 813 |
+
"arm64"
|
| 814 |
+
],
|
| 815 |
+
"dev": true,
|
| 816 |
+
"license": "MIT",
|
| 817 |
+
"optional": true,
|
| 818 |
+
"os": [
|
| 819 |
+
"freebsd"
|
| 820 |
+
]
|
| 821 |
+
},
|
| 822 |
+
"node_modules/@rollup/rollup-freebsd-x64": {
|
| 823 |
+
"version": "4.60.1",
|
| 824 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz",
|
| 825 |
+
"integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==",
|
| 826 |
+
"cpu": [
|
| 827 |
+
"x64"
|
| 828 |
+
],
|
| 829 |
+
"dev": true,
|
| 830 |
+
"license": "MIT",
|
| 831 |
+
"optional": true,
|
| 832 |
+
"os": [
|
| 833 |
+
"freebsd"
|
| 834 |
+
]
|
| 835 |
+
},
|
| 836 |
+
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
| 837 |
+
"version": "4.60.1",
|
| 838 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz",
|
| 839 |
+
"integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==",
|
| 840 |
+
"cpu": [
|
| 841 |
+
"arm"
|
| 842 |
+
],
|
| 843 |
+
"dev": true,
|
| 844 |
+
"license": "MIT",
|
| 845 |
+
"optional": true,
|
| 846 |
+
"os": [
|
| 847 |
+
"linux"
|
| 848 |
+
]
|
| 849 |
+
},
|
| 850 |
+
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
| 851 |
+
"version": "4.60.1",
|
| 852 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz",
|
| 853 |
+
"integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==",
|
| 854 |
+
"cpu": [
|
| 855 |
+
"arm"
|
| 856 |
+
],
|
| 857 |
+
"dev": true,
|
| 858 |
+
"license": "MIT",
|
| 859 |
+
"optional": true,
|
| 860 |
+
"os": [
|
| 861 |
+
"linux"
|
| 862 |
+
]
|
| 863 |
+
},
|
| 864 |
+
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
| 865 |
+
"version": "4.60.1",
|
| 866 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz",
|
| 867 |
+
"integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==",
|
| 868 |
+
"cpu": [
|
| 869 |
+
"arm64"
|
| 870 |
+
],
|
| 871 |
+
"dev": true,
|
| 872 |
+
"license": "MIT",
|
| 873 |
+
"optional": true,
|
| 874 |
+
"os": [
|
| 875 |
+
"linux"
|
| 876 |
+
]
|
| 877 |
+
},
|
| 878 |
+
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
| 879 |
+
"version": "4.60.1",
|
| 880 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz",
|
| 881 |
+
"integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==",
|
| 882 |
+
"cpu": [
|
| 883 |
+
"arm64"
|
| 884 |
+
],
|
| 885 |
+
"dev": true,
|
| 886 |
+
"license": "MIT",
|
| 887 |
+
"optional": true,
|
| 888 |
+
"os": [
|
| 889 |
+
"linux"
|
| 890 |
+
]
|
| 891 |
+
},
|
| 892 |
+
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
| 893 |
+
"version": "4.60.1",
|
| 894 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz",
|
| 895 |
+
"integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==",
|
| 896 |
+
"cpu": [
|
| 897 |
+
"loong64"
|
| 898 |
+
],
|
| 899 |
+
"dev": true,
|
| 900 |
+
"license": "MIT",
|
| 901 |
+
"optional": true,
|
| 902 |
+
"os": [
|
| 903 |
+
"linux"
|
| 904 |
+
]
|
| 905 |
+
},
|
| 906 |
+
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
| 907 |
+
"version": "4.60.1",
|
| 908 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz",
|
| 909 |
+
"integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==",
|
| 910 |
+
"cpu": [
|
| 911 |
+
"loong64"
|
| 912 |
+
],
|
| 913 |
+
"dev": true,
|
| 914 |
+
"license": "MIT",
|
| 915 |
+
"optional": true,
|
| 916 |
+
"os": [
|
| 917 |
+
"linux"
|
| 918 |
+
]
|
| 919 |
+
},
|
| 920 |
+
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
| 921 |
+
"version": "4.60.1",
|
| 922 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz",
|
| 923 |
+
"integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==",
|
| 924 |
+
"cpu": [
|
| 925 |
+
"ppc64"
|
| 926 |
+
],
|
| 927 |
+
"dev": true,
|
| 928 |
+
"license": "MIT",
|
| 929 |
+
"optional": true,
|
| 930 |
+
"os": [
|
| 931 |
+
"linux"
|
| 932 |
+
]
|
| 933 |
+
},
|
| 934 |
+
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
| 935 |
+
"version": "4.60.1",
|
| 936 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz",
|
| 937 |
+
"integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==",
|
| 938 |
+
"cpu": [
|
| 939 |
+
"ppc64"
|
| 940 |
+
],
|
| 941 |
+
"dev": true,
|
| 942 |
+
"license": "MIT",
|
| 943 |
+
"optional": true,
|
| 944 |
+
"os": [
|
| 945 |
+
"linux"
|
| 946 |
+
]
|
| 947 |
+
},
|
| 948 |
+
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
| 949 |
+
"version": "4.60.1",
|
| 950 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz",
|
| 951 |
+
"integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==",
|
| 952 |
+
"cpu": [
|
| 953 |
+
"riscv64"
|
| 954 |
+
],
|
| 955 |
+
"dev": true,
|
| 956 |
+
"license": "MIT",
|
| 957 |
+
"optional": true,
|
| 958 |
+
"os": [
|
| 959 |
+
"linux"
|
| 960 |
+
]
|
| 961 |
+
},
|
| 962 |
+
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
| 963 |
+
"version": "4.60.1",
|
| 964 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz",
|
| 965 |
+
"integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==",
|
| 966 |
+
"cpu": [
|
| 967 |
+
"riscv64"
|
| 968 |
+
],
|
| 969 |
+
"dev": true,
|
| 970 |
+
"license": "MIT",
|
| 971 |
+
"optional": true,
|
| 972 |
+
"os": [
|
| 973 |
+
"linux"
|
| 974 |
+
]
|
| 975 |
+
},
|
| 976 |
+
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
| 977 |
+
"version": "4.60.1",
|
| 978 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz",
|
| 979 |
+
"integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==",
|
| 980 |
+
"cpu": [
|
| 981 |
+
"s390x"
|
| 982 |
+
],
|
| 983 |
+
"dev": true,
|
| 984 |
+
"license": "MIT",
|
| 985 |
+
"optional": true,
|
| 986 |
+
"os": [
|
| 987 |
+
"linux"
|
| 988 |
+
]
|
| 989 |
+
},
|
| 990 |
+
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
| 991 |
+
"version": "4.60.1",
|
| 992 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz",
|
| 993 |
+
"integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==",
|
| 994 |
+
"cpu": [
|
| 995 |
+
"x64"
|
| 996 |
+
],
|
| 997 |
+
"dev": true,
|
| 998 |
+
"license": "MIT",
|
| 999 |
+
"optional": true,
|
| 1000 |
+
"os": [
|
| 1001 |
+
"linux"
|
| 1002 |
+
]
|
| 1003 |
+
},
|
| 1004 |
+
"node_modules/@rollup/rollup-linux-x64-musl": {
|
| 1005 |
+
"version": "4.60.1",
|
| 1006 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz",
|
| 1007 |
+
"integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==",
|
| 1008 |
+
"cpu": [
|
| 1009 |
+
"x64"
|
| 1010 |
+
],
|
| 1011 |
+
"dev": true,
|
| 1012 |
+
"license": "MIT",
|
| 1013 |
+
"optional": true,
|
| 1014 |
+
"os": [
|
| 1015 |
+
"linux"
|
| 1016 |
+
]
|
| 1017 |
+
},
|
| 1018 |
+
"node_modules/@rollup/rollup-openbsd-x64": {
|
| 1019 |
+
"version": "4.60.1",
|
| 1020 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz",
|
| 1021 |
+
"integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==",
|
| 1022 |
+
"cpu": [
|
| 1023 |
+
"x64"
|
| 1024 |
+
],
|
| 1025 |
+
"dev": true,
|
| 1026 |
+
"license": "MIT",
|
| 1027 |
+
"optional": true,
|
| 1028 |
+
"os": [
|
| 1029 |
+
"openbsd"
|
| 1030 |
+
]
|
| 1031 |
+
},
|
| 1032 |
+
"node_modules/@rollup/rollup-openharmony-arm64": {
|
| 1033 |
+
"version": "4.60.1",
|
| 1034 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz",
|
| 1035 |
+
"integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==",
|
| 1036 |
+
"cpu": [
|
| 1037 |
+
"arm64"
|
| 1038 |
+
],
|
| 1039 |
+
"dev": true,
|
| 1040 |
+
"license": "MIT",
|
| 1041 |
+
"optional": true,
|
| 1042 |
+
"os": [
|
| 1043 |
+
"openharmony"
|
| 1044 |
+
]
|
| 1045 |
+
},
|
| 1046 |
+
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
| 1047 |
+
"version": "4.60.1",
|
| 1048 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz",
|
| 1049 |
+
"integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==",
|
| 1050 |
+
"cpu": [
|
| 1051 |
+
"arm64"
|
| 1052 |
+
],
|
| 1053 |
+
"dev": true,
|
| 1054 |
+
"license": "MIT",
|
| 1055 |
+
"optional": true,
|
| 1056 |
+
"os": [
|
| 1057 |
+
"win32"
|
| 1058 |
+
]
|
| 1059 |
+
},
|
| 1060 |
+
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
| 1061 |
+
"version": "4.60.1",
|
| 1062 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz",
|
| 1063 |
+
"integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==",
|
| 1064 |
+
"cpu": [
|
| 1065 |
+
"ia32"
|
| 1066 |
+
],
|
| 1067 |
+
"dev": true,
|
| 1068 |
+
"license": "MIT",
|
| 1069 |
+
"optional": true,
|
| 1070 |
+
"os": [
|
| 1071 |
+
"win32"
|
| 1072 |
+
]
|
| 1073 |
+
},
|
| 1074 |
+
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
| 1075 |
+
"version": "4.60.1",
|
| 1076 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz",
|
| 1077 |
+
"integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==",
|
| 1078 |
+
"cpu": [
|
| 1079 |
+
"x64"
|
| 1080 |
+
],
|
| 1081 |
+
"dev": true,
|
| 1082 |
+
"license": "MIT",
|
| 1083 |
+
"optional": true,
|
| 1084 |
+
"os": [
|
| 1085 |
+
"win32"
|
| 1086 |
+
]
|
| 1087 |
+
},
|
| 1088 |
+
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
| 1089 |
+
"version": "4.60.1",
|
| 1090 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz",
|
| 1091 |
+
"integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==",
|
| 1092 |
+
"cpu": [
|
| 1093 |
+
"x64"
|
| 1094 |
+
],
|
| 1095 |
+
"dev": true,
|
| 1096 |
+
"license": "MIT",
|
| 1097 |
+
"optional": true,
|
| 1098 |
+
"os": [
|
| 1099 |
+
"win32"
|
| 1100 |
+
]
|
| 1101 |
+
},
|
| 1102 |
+
"node_modules/@types/babel__core": {
|
| 1103 |
+
"version": "7.20.5",
|
| 1104 |
+
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
| 1105 |
+
"integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
|
| 1106 |
+
"dev": true,
|
| 1107 |
+
"license": "MIT",
|
| 1108 |
+
"dependencies": {
|
| 1109 |
+
"@babel/parser": "^7.20.7",
|
| 1110 |
+
"@babel/types": "^7.20.7",
|
| 1111 |
+
"@types/babel__generator": "*",
|
| 1112 |
+
"@types/babel__template": "*",
|
| 1113 |
+
"@types/babel__traverse": "*"
|
| 1114 |
+
}
|
| 1115 |
+
},
|
| 1116 |
+
"node_modules/@types/babel__generator": {
|
| 1117 |
+
"version": "7.27.0",
|
| 1118 |
+
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
|
| 1119 |
+
"integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
|
| 1120 |
+
"dev": true,
|
| 1121 |
+
"license": "MIT",
|
| 1122 |
+
"dependencies": {
|
| 1123 |
+
"@babel/types": "^7.0.0"
|
| 1124 |
+
}
|
| 1125 |
+
},
|
| 1126 |
+
"node_modules/@types/babel__template": {
|
| 1127 |
+
"version": "7.4.4",
|
| 1128 |
+
"resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
|
| 1129 |
+
"integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
|
| 1130 |
+
"dev": true,
|
| 1131 |
+
"license": "MIT",
|
| 1132 |
+
"dependencies": {
|
| 1133 |
+
"@babel/parser": "^7.1.0",
|
| 1134 |
+
"@babel/types": "^7.0.0"
|
| 1135 |
+
}
|
| 1136 |
+
},
|
| 1137 |
+
"node_modules/@types/babel__traverse": {
|
| 1138 |
+
"version": "7.28.0",
|
| 1139 |
+
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
|
| 1140 |
+
"integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
|
| 1141 |
+
"dev": true,
|
| 1142 |
+
"license": "MIT",
|
| 1143 |
+
"dependencies": {
|
| 1144 |
+
"@babel/types": "^7.28.2"
|
| 1145 |
+
}
|
| 1146 |
+
},
|
| 1147 |
+
"node_modules/@types/estree": {
|
| 1148 |
+
"version": "1.0.8",
|
| 1149 |
+
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
| 1150 |
+
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
| 1151 |
+
"dev": true,
|
| 1152 |
+
"license": "MIT"
|
| 1153 |
+
},
|
| 1154 |
+
"node_modules/@types/prop-types": {
|
| 1155 |
+
"version": "15.7.15",
|
| 1156 |
+
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
| 1157 |
+
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
| 1158 |
+
"dev": true,
|
| 1159 |
+
"license": "MIT"
|
| 1160 |
+
},
|
| 1161 |
+
"node_modules/@types/react": {
|
| 1162 |
+
"version": "18.3.28",
|
| 1163 |
+
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz",
|
| 1164 |
+
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
| 1165 |
+
"dev": true,
|
| 1166 |
+
"license": "MIT",
|
| 1167 |
+
"dependencies": {
|
| 1168 |
+
"@types/prop-types": "*",
|
| 1169 |
+
"csstype": "^3.2.2"
|
| 1170 |
+
}
|
| 1171 |
+
},
|
| 1172 |
+
"node_modules/@types/react-dom": {
|
| 1173 |
+
"version": "18.3.7",
|
| 1174 |
+
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
| 1175 |
+
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
| 1176 |
+
"dev": true,
|
| 1177 |
+
"license": "MIT",
|
| 1178 |
+
"peerDependencies": {
|
| 1179 |
+
"@types/react": "^18.0.0"
|
| 1180 |
+
}
|
| 1181 |
+
},
|
| 1182 |
+
"node_modules/@vitejs/plugin-react": {
|
| 1183 |
+
"version": "4.7.0",
|
| 1184 |
+
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
|
| 1185 |
+
"integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
|
| 1186 |
+
"dev": true,
|
| 1187 |
+
"license": "MIT",
|
| 1188 |
+
"dependencies": {
|
| 1189 |
+
"@babel/core": "^7.28.0",
|
| 1190 |
+
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
|
| 1191 |
+
"@babel/plugin-transform-react-jsx-source": "^7.27.1",
|
| 1192 |
+
"@rolldown/pluginutils": "1.0.0-beta.27",
|
| 1193 |
+
"@types/babel__core": "^7.20.5",
|
| 1194 |
+
"react-refresh": "^0.17.0"
|
| 1195 |
+
},
|
| 1196 |
+
"engines": {
|
| 1197 |
+
"node": "^14.18.0 || >=16.0.0"
|
| 1198 |
+
},
|
| 1199 |
+
"peerDependencies": {
|
| 1200 |
+
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
| 1201 |
+
}
|
| 1202 |
+
},
|
| 1203 |
+
"node_modules/baseline-browser-mapping": {
|
| 1204 |
+
"version": "2.10.12",
|
| 1205 |
+
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.12.tgz",
|
| 1206 |
+
"integrity": "sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==",
|
| 1207 |
+
"dev": true,
|
| 1208 |
+
"license": "Apache-2.0",
|
| 1209 |
+
"bin": {
|
| 1210 |
+
"baseline-browser-mapping": "dist/cli.cjs"
|
| 1211 |
+
},
|
| 1212 |
+
"engines": {
|
| 1213 |
+
"node": ">=6.0.0"
|
| 1214 |
+
}
|
| 1215 |
+
},
|
| 1216 |
+
"node_modules/browserslist": {
|
| 1217 |
+
"version": "4.28.1",
|
| 1218 |
+
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
|
| 1219 |
+
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
|
| 1220 |
+
"dev": true,
|
| 1221 |
+
"funding": [
|
| 1222 |
+
{
|
| 1223 |
+
"type": "opencollective",
|
| 1224 |
+
"url": "https://opencollective.com/browserslist"
|
| 1225 |
+
},
|
| 1226 |
+
{
|
| 1227 |
+
"type": "tidelift",
|
| 1228 |
+
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
| 1229 |
+
},
|
| 1230 |
+
{
|
| 1231 |
+
"type": "github",
|
| 1232 |
+
"url": "https://github.com/sponsors/ai"
|
| 1233 |
+
}
|
| 1234 |
+
],
|
| 1235 |
+
"license": "MIT",
|
| 1236 |
+
"dependencies": {
|
| 1237 |
+
"baseline-browser-mapping": "^2.9.0",
|
| 1238 |
+
"caniuse-lite": "^1.0.30001759",
|
| 1239 |
+
"electron-to-chromium": "^1.5.263",
|
| 1240 |
+
"node-releases": "^2.0.27",
|
| 1241 |
+
"update-browserslist-db": "^1.2.0"
|
| 1242 |
+
},
|
| 1243 |
+
"bin": {
|
| 1244 |
+
"browserslist": "cli.js"
|
| 1245 |
+
},
|
| 1246 |
+
"engines": {
|
| 1247 |
+
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
| 1248 |
+
}
|
| 1249 |
+
},
|
| 1250 |
+
"node_modules/caniuse-lite": {
|
| 1251 |
+
"version": "1.0.30001782",
|
| 1252 |
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001782.tgz",
|
| 1253 |
+
"integrity": "sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw==",
|
| 1254 |
+
"dev": true,
|
| 1255 |
+
"funding": [
|
| 1256 |
+
{
|
| 1257 |
+
"type": "opencollective",
|
| 1258 |
+
"url": "https://opencollective.com/browserslist"
|
| 1259 |
+
},
|
| 1260 |
+
{
|
| 1261 |
+
"type": "tidelift",
|
| 1262 |
+
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
| 1263 |
+
},
|
| 1264 |
+
{
|
| 1265 |
+
"type": "github",
|
| 1266 |
+
"url": "https://github.com/sponsors/ai"
|
| 1267 |
+
}
|
| 1268 |
+
],
|
| 1269 |
+
"license": "CC-BY-4.0"
|
| 1270 |
+
},
|
| 1271 |
+
"node_modules/convert-source-map": {
|
| 1272 |
+
"version": "2.0.0",
|
| 1273 |
+
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
| 1274 |
+
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
|
| 1275 |
+
"dev": true,
|
| 1276 |
+
"license": "MIT"
|
| 1277 |
+
},
|
| 1278 |
+
"node_modules/csstype": {
|
| 1279 |
+
"version": "3.2.3",
|
| 1280 |
+
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
| 1281 |
+
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
| 1282 |
+
"dev": true,
|
| 1283 |
+
"license": "MIT"
|
| 1284 |
+
},
|
| 1285 |
+
"node_modules/debug": {
|
| 1286 |
+
"version": "4.4.3",
|
| 1287 |
+
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
| 1288 |
+
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
| 1289 |
+
"dev": true,
|
| 1290 |
+
"license": "MIT",
|
| 1291 |
+
"dependencies": {
|
| 1292 |
+
"ms": "^2.1.3"
|
| 1293 |
+
},
|
| 1294 |
+
"engines": {
|
| 1295 |
+
"node": ">=6.0"
|
| 1296 |
+
},
|
| 1297 |
+
"peerDependenciesMeta": {
|
| 1298 |
+
"supports-color": {
|
| 1299 |
+
"optional": true
|
| 1300 |
+
}
|
| 1301 |
+
}
|
| 1302 |
+
},
|
| 1303 |
+
"node_modules/electron-to-chromium": {
|
| 1304 |
+
"version": "1.5.328",
|
| 1305 |
+
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.328.tgz",
|
| 1306 |
+
"integrity": "sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==",
|
| 1307 |
+
"dev": true,
|
| 1308 |
+
"license": "ISC"
|
| 1309 |
+
},
|
| 1310 |
+
"node_modules/esbuild": {
|
| 1311 |
+
"version": "0.21.5",
|
| 1312 |
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
| 1313 |
+
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
| 1314 |
+
"dev": true,
|
| 1315 |
+
"hasInstallScript": true,
|
| 1316 |
+
"license": "MIT",
|
| 1317 |
+
"bin": {
|
| 1318 |
+
"esbuild": "bin/esbuild"
|
| 1319 |
+
},
|
| 1320 |
+
"engines": {
|
| 1321 |
+
"node": ">=12"
|
| 1322 |
+
},
|
| 1323 |
+
"optionalDependencies": {
|
| 1324 |
+
"@esbuild/aix-ppc64": "0.21.5",
|
| 1325 |
+
"@esbuild/android-arm": "0.21.5",
|
| 1326 |
+
"@esbuild/android-arm64": "0.21.5",
|
| 1327 |
+
"@esbuild/android-x64": "0.21.5",
|
| 1328 |
+
"@esbuild/darwin-arm64": "0.21.5",
|
| 1329 |
+
"@esbuild/darwin-x64": "0.21.5",
|
| 1330 |
+
"@esbuild/freebsd-arm64": "0.21.5",
|
| 1331 |
+
"@esbuild/freebsd-x64": "0.21.5",
|
| 1332 |
+
"@esbuild/linux-arm": "0.21.5",
|
| 1333 |
+
"@esbuild/linux-arm64": "0.21.5",
|
| 1334 |
+
"@esbuild/linux-ia32": "0.21.5",
|
| 1335 |
+
"@esbuild/linux-loong64": "0.21.5",
|
| 1336 |
+
"@esbuild/linux-mips64el": "0.21.5",
|
| 1337 |
+
"@esbuild/linux-ppc64": "0.21.5",
|
| 1338 |
+
"@esbuild/linux-riscv64": "0.21.5",
|
| 1339 |
+
"@esbuild/linux-s390x": "0.21.5",
|
| 1340 |
+
"@esbuild/linux-x64": "0.21.5",
|
| 1341 |
+
"@esbuild/netbsd-x64": "0.21.5",
|
| 1342 |
+
"@esbuild/openbsd-x64": "0.21.5",
|
| 1343 |
+
"@esbuild/sunos-x64": "0.21.5",
|
| 1344 |
+
"@esbuild/win32-arm64": "0.21.5",
|
| 1345 |
+
"@esbuild/win32-ia32": "0.21.5",
|
| 1346 |
+
"@esbuild/win32-x64": "0.21.5"
|
| 1347 |
+
}
|
| 1348 |
+
},
|
| 1349 |
+
"node_modules/escalade": {
|
| 1350 |
+
"version": "3.2.0",
|
| 1351 |
+
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
| 1352 |
+
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
| 1353 |
+
"dev": true,
|
| 1354 |
+
"license": "MIT",
|
| 1355 |
+
"engines": {
|
| 1356 |
+
"node": ">=6"
|
| 1357 |
+
}
|
| 1358 |
+
},
|
| 1359 |
+
"node_modules/fsevents": {
|
| 1360 |
+
"version": "2.3.3",
|
| 1361 |
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
| 1362 |
+
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
| 1363 |
+
"dev": true,
|
| 1364 |
+
"hasInstallScript": true,
|
| 1365 |
+
"license": "MIT",
|
| 1366 |
+
"optional": true,
|
| 1367 |
+
"os": [
|
| 1368 |
+
"darwin"
|
| 1369 |
+
],
|
| 1370 |
+
"engines": {
|
| 1371 |
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
| 1372 |
+
}
|
| 1373 |
+
},
|
| 1374 |
+
"node_modules/gensync": {
|
| 1375 |
+
"version": "1.0.0-beta.2",
|
| 1376 |
+
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
| 1377 |
+
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
|
| 1378 |
+
"dev": true,
|
| 1379 |
+
"license": "MIT",
|
| 1380 |
+
"engines": {
|
| 1381 |
+
"node": ">=6.9.0"
|
| 1382 |
+
}
|
| 1383 |
+
},
|
| 1384 |
+
"node_modules/js-tokens": {
|
| 1385 |
+
"version": "4.0.0",
|
| 1386 |
+
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
| 1387 |
+
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
| 1388 |
+
"license": "MIT"
|
| 1389 |
+
},
|
| 1390 |
+
"node_modules/jsesc": {
|
| 1391 |
+
"version": "3.1.0",
|
| 1392 |
+
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
|
| 1393 |
+
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
|
| 1394 |
+
"dev": true,
|
| 1395 |
+
"license": "MIT",
|
| 1396 |
+
"bin": {
|
| 1397 |
+
"jsesc": "bin/jsesc"
|
| 1398 |
+
},
|
| 1399 |
+
"engines": {
|
| 1400 |
+
"node": ">=6"
|
| 1401 |
+
}
|
| 1402 |
+
},
|
| 1403 |
+
"node_modules/json5": {
|
| 1404 |
+
"version": "2.2.3",
|
| 1405 |
+
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
| 1406 |
+
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
| 1407 |
+
"dev": true,
|
| 1408 |
+
"license": "MIT",
|
| 1409 |
+
"bin": {
|
| 1410 |
+
"json5": "lib/cli.js"
|
| 1411 |
+
},
|
| 1412 |
+
"engines": {
|
| 1413 |
+
"node": ">=6"
|
| 1414 |
+
}
|
| 1415 |
+
},
|
| 1416 |
+
"node_modules/loose-envify": {
|
| 1417 |
+
"version": "1.4.0",
|
| 1418 |
+
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
| 1419 |
+
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
| 1420 |
+
"license": "MIT",
|
| 1421 |
+
"dependencies": {
|
| 1422 |
+
"js-tokens": "^3.0.0 || ^4.0.0"
|
| 1423 |
+
},
|
| 1424 |
+
"bin": {
|
| 1425 |
+
"loose-envify": "cli.js"
|
| 1426 |
+
}
|
| 1427 |
+
},
|
| 1428 |
+
"node_modules/lru-cache": {
|
| 1429 |
+
"version": "5.1.1",
|
| 1430 |
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
| 1431 |
+
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
| 1432 |
+
"dev": true,
|
| 1433 |
+
"license": "ISC",
|
| 1434 |
+
"dependencies": {
|
| 1435 |
+
"yallist": "^3.0.2"
|
| 1436 |
+
}
|
| 1437 |
+
},
|
| 1438 |
+
"node_modules/ms": {
|
| 1439 |
+
"version": "2.1.3",
|
| 1440 |
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
| 1441 |
+
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
| 1442 |
+
"dev": true,
|
| 1443 |
+
"license": "MIT"
|
| 1444 |
+
},
|
| 1445 |
+
"node_modules/nanoid": {
|
| 1446 |
+
"version": "3.3.11",
|
| 1447 |
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
| 1448 |
+
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
| 1449 |
+
"dev": true,
|
| 1450 |
+
"funding": [
|
| 1451 |
+
{
|
| 1452 |
+
"type": "github",
|
| 1453 |
+
"url": "https://github.com/sponsors/ai"
|
| 1454 |
+
}
|
| 1455 |
+
],
|
| 1456 |
+
"license": "MIT",
|
| 1457 |
+
"bin": {
|
| 1458 |
+
"nanoid": "bin/nanoid.cjs"
|
| 1459 |
+
},
|
| 1460 |
+
"engines": {
|
| 1461 |
+
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
| 1462 |
+
}
|
| 1463 |
+
},
|
| 1464 |
+
"node_modules/node-releases": {
|
| 1465 |
+
"version": "2.0.36",
|
| 1466 |
+
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz",
|
| 1467 |
+
"integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==",
|
| 1468 |
+
"dev": true,
|
| 1469 |
+
"license": "MIT"
|
| 1470 |
+
},
|
| 1471 |
+
"node_modules/picocolors": {
|
| 1472 |
+
"version": "1.1.1",
|
| 1473 |
+
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
| 1474 |
+
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
| 1475 |
+
"dev": true,
|
| 1476 |
+
"license": "ISC"
|
| 1477 |
+
},
|
| 1478 |
+
"node_modules/postcss": {
|
| 1479 |
+
"version": "8.5.8",
|
| 1480 |
+
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
|
| 1481 |
+
"integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
|
| 1482 |
+
"dev": true,
|
| 1483 |
+
"funding": [
|
| 1484 |
+
{
|
| 1485 |
+
"type": "opencollective",
|
| 1486 |
+
"url": "https://opencollective.com/postcss/"
|
| 1487 |
+
},
|
| 1488 |
+
{
|
| 1489 |
+
"type": "tidelift",
|
| 1490 |
+
"url": "https://tidelift.com/funding/github/npm/postcss"
|
| 1491 |
+
},
|
| 1492 |
+
{
|
| 1493 |
+
"type": "github",
|
| 1494 |
+
"url": "https://github.com/sponsors/ai"
|
| 1495 |
+
}
|
| 1496 |
+
],
|
| 1497 |
+
"license": "MIT",
|
| 1498 |
+
"dependencies": {
|
| 1499 |
+
"nanoid": "^3.3.11",
|
| 1500 |
+
"picocolors": "^1.1.1",
|
| 1501 |
+
"source-map-js": "^1.2.1"
|
| 1502 |
+
},
|
| 1503 |
+
"engines": {
|
| 1504 |
+
"node": "^10 || ^12 || >=14"
|
| 1505 |
+
}
|
| 1506 |
+
},
|
| 1507 |
+
"node_modules/react": {
|
| 1508 |
+
"version": "18.3.1",
|
| 1509 |
+
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
| 1510 |
+
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
| 1511 |
+
"license": "MIT",
|
| 1512 |
+
"dependencies": {
|
| 1513 |
+
"loose-envify": "^1.1.0"
|
| 1514 |
+
},
|
| 1515 |
+
"engines": {
|
| 1516 |
+
"node": ">=0.10.0"
|
| 1517 |
+
}
|
| 1518 |
+
},
|
| 1519 |
+
"node_modules/react-dom": {
|
| 1520 |
+
"version": "18.3.1",
|
| 1521 |
+
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
| 1522 |
+
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
| 1523 |
+
"license": "MIT",
|
| 1524 |
+
"dependencies": {
|
| 1525 |
+
"loose-envify": "^1.1.0",
|
| 1526 |
+
"scheduler": "^0.23.2"
|
| 1527 |
+
},
|
| 1528 |
+
"peerDependencies": {
|
| 1529 |
+
"react": "^18.3.1"
|
| 1530 |
+
}
|
| 1531 |
+
},
|
| 1532 |
+
"node_modules/react-refresh": {
|
| 1533 |
+
"version": "0.17.0",
|
| 1534 |
+
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
|
| 1535 |
+
"integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
|
| 1536 |
+
"dev": true,
|
| 1537 |
+
"license": "MIT",
|
| 1538 |
+
"engines": {
|
| 1539 |
+
"node": ">=0.10.0"
|
| 1540 |
+
}
|
| 1541 |
+
},
|
| 1542 |
+
"node_modules/rollup": {
|
| 1543 |
+
"version": "4.60.1",
|
| 1544 |
+
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz",
|
| 1545 |
+
"integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==",
|
| 1546 |
+
"dev": true,
|
| 1547 |
+
"license": "MIT",
|
| 1548 |
+
"dependencies": {
|
| 1549 |
+
"@types/estree": "1.0.8"
|
| 1550 |
+
},
|
| 1551 |
+
"bin": {
|
| 1552 |
+
"rollup": "dist/bin/rollup"
|
| 1553 |
+
},
|
| 1554 |
+
"engines": {
|
| 1555 |
+
"node": ">=18.0.0",
|
| 1556 |
+
"npm": ">=8.0.0"
|
| 1557 |
+
},
|
| 1558 |
+
"optionalDependencies": {
|
| 1559 |
+
"@rollup/rollup-android-arm-eabi": "4.60.1",
|
| 1560 |
+
"@rollup/rollup-android-arm64": "4.60.1",
|
| 1561 |
+
"@rollup/rollup-darwin-arm64": "4.60.1",
|
| 1562 |
+
"@rollup/rollup-darwin-x64": "4.60.1",
|
| 1563 |
+
"@rollup/rollup-freebsd-arm64": "4.60.1",
|
| 1564 |
+
"@rollup/rollup-freebsd-x64": "4.60.1",
|
| 1565 |
+
"@rollup/rollup-linux-arm-gnueabihf": "4.60.1",
|
| 1566 |
+
"@rollup/rollup-linux-arm-musleabihf": "4.60.1",
|
| 1567 |
+
"@rollup/rollup-linux-arm64-gnu": "4.60.1",
|
| 1568 |
+
"@rollup/rollup-linux-arm64-musl": "4.60.1",
|
| 1569 |
+
"@rollup/rollup-linux-loong64-gnu": "4.60.1",
|
| 1570 |
+
"@rollup/rollup-linux-loong64-musl": "4.60.1",
|
| 1571 |
+
"@rollup/rollup-linux-ppc64-gnu": "4.60.1",
|
| 1572 |
+
"@rollup/rollup-linux-ppc64-musl": "4.60.1",
|
| 1573 |
+
"@rollup/rollup-linux-riscv64-gnu": "4.60.1",
|
| 1574 |
+
"@rollup/rollup-linux-riscv64-musl": "4.60.1",
|
| 1575 |
+
"@rollup/rollup-linux-s390x-gnu": "4.60.1",
|
| 1576 |
+
"@rollup/rollup-linux-x64-gnu": "4.60.1",
|
| 1577 |
+
"@rollup/rollup-linux-x64-musl": "4.60.1",
|
| 1578 |
+
"@rollup/rollup-openbsd-x64": "4.60.1",
|
| 1579 |
+
"@rollup/rollup-openharmony-arm64": "4.60.1",
|
| 1580 |
+
"@rollup/rollup-win32-arm64-msvc": "4.60.1",
|
| 1581 |
+
"@rollup/rollup-win32-ia32-msvc": "4.60.1",
|
| 1582 |
+
"@rollup/rollup-win32-x64-gnu": "4.60.1",
|
| 1583 |
+
"@rollup/rollup-win32-x64-msvc": "4.60.1",
|
| 1584 |
+
"fsevents": "~2.3.2"
|
| 1585 |
+
}
|
| 1586 |
+
},
|
| 1587 |
+
"node_modules/scheduler": {
|
| 1588 |
+
"version": "0.23.2",
|
| 1589 |
+
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
| 1590 |
+
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
| 1591 |
+
"license": "MIT",
|
| 1592 |
+
"dependencies": {
|
| 1593 |
+
"loose-envify": "^1.1.0"
|
| 1594 |
+
}
|
| 1595 |
+
},
|
| 1596 |
+
"node_modules/semver": {
|
| 1597 |
+
"version": "6.3.1",
|
| 1598 |
+
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
| 1599 |
+
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
| 1600 |
+
"dev": true,
|
| 1601 |
+
"license": "ISC",
|
| 1602 |
+
"bin": {
|
| 1603 |
+
"semver": "bin/semver.js"
|
| 1604 |
+
}
|
| 1605 |
+
},
|
| 1606 |
+
"node_modules/source-map-js": {
|
| 1607 |
+
"version": "1.2.1",
|
| 1608 |
+
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
| 1609 |
+
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
| 1610 |
+
"dev": true,
|
| 1611 |
+
"license": "BSD-3-Clause",
|
| 1612 |
+
"engines": {
|
| 1613 |
+
"node": ">=0.10.0"
|
| 1614 |
+
}
|
| 1615 |
+
},
|
| 1616 |
+
"node_modules/typescript": {
|
| 1617 |
+
"version": "5.9.3",
|
| 1618 |
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
| 1619 |
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
| 1620 |
+
"dev": true,
|
| 1621 |
+
"license": "Apache-2.0",
|
| 1622 |
+
"bin": {
|
| 1623 |
+
"tsc": "bin/tsc",
|
| 1624 |
+
"tsserver": "bin/tsserver"
|
| 1625 |
+
},
|
| 1626 |
+
"engines": {
|
| 1627 |
+
"node": ">=14.17"
|
| 1628 |
+
}
|
| 1629 |
+
},
|
| 1630 |
+
"node_modules/update-browserslist-db": {
|
| 1631 |
+
"version": "1.2.3",
|
| 1632 |
+
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
| 1633 |
+
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
|
| 1634 |
+
"dev": true,
|
| 1635 |
+
"funding": [
|
| 1636 |
+
{
|
| 1637 |
+
"type": "opencollective",
|
| 1638 |
+
"url": "https://opencollective.com/browserslist"
|
| 1639 |
+
},
|
| 1640 |
+
{
|
| 1641 |
+
"type": "tidelift",
|
| 1642 |
+
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
| 1643 |
+
},
|
| 1644 |
+
{
|
| 1645 |
+
"type": "github",
|
| 1646 |
+
"url": "https://github.com/sponsors/ai"
|
| 1647 |
+
}
|
| 1648 |
+
],
|
| 1649 |
+
"license": "MIT",
|
| 1650 |
+
"dependencies": {
|
| 1651 |
+
"escalade": "^3.2.0",
|
| 1652 |
+
"picocolors": "^1.1.1"
|
| 1653 |
+
},
|
| 1654 |
+
"bin": {
|
| 1655 |
+
"update-browserslist-db": "cli.js"
|
| 1656 |
+
},
|
| 1657 |
+
"peerDependencies": {
|
| 1658 |
+
"browserslist": ">= 4.21.0"
|
| 1659 |
+
}
|
| 1660 |
+
},
|
| 1661 |
+
"node_modules/vite": {
|
| 1662 |
+
"version": "5.4.21",
|
| 1663 |
+
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
|
| 1664 |
+
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
|
| 1665 |
+
"dev": true,
|
| 1666 |
+
"license": "MIT",
|
| 1667 |
+
"dependencies": {
|
| 1668 |
+
"esbuild": "^0.21.3",
|
| 1669 |
+
"postcss": "^8.4.43",
|
| 1670 |
+
"rollup": "^4.20.0"
|
| 1671 |
+
},
|
| 1672 |
+
"bin": {
|
| 1673 |
+
"vite": "bin/vite.js"
|
| 1674 |
+
},
|
| 1675 |
+
"engines": {
|
| 1676 |
+
"node": "^18.0.0 || >=20.0.0"
|
| 1677 |
+
},
|
| 1678 |
+
"funding": {
|
| 1679 |
+
"url": "https://github.com/vitejs/vite?sponsor=1"
|
| 1680 |
+
},
|
| 1681 |
+
"optionalDependencies": {
|
| 1682 |
+
"fsevents": "~2.3.3"
|
| 1683 |
+
},
|
| 1684 |
+
"peerDependencies": {
|
| 1685 |
+
"@types/node": "^18.0.0 || >=20.0.0",
|
| 1686 |
+
"less": "*",
|
| 1687 |
+
"lightningcss": "^1.21.0",
|
| 1688 |
+
"sass": "*",
|
| 1689 |
+
"sass-embedded": "*",
|
| 1690 |
+
"stylus": "*",
|
| 1691 |
+
"sugarss": "*",
|
| 1692 |
+
"terser": "^5.4.0"
|
| 1693 |
+
},
|
| 1694 |
+
"peerDependenciesMeta": {
|
| 1695 |
+
"@types/node": {
|
| 1696 |
+
"optional": true
|
| 1697 |
+
},
|
| 1698 |
+
"less": {
|
| 1699 |
+
"optional": true
|
| 1700 |
+
},
|
| 1701 |
+
"lightningcss": {
|
| 1702 |
+
"optional": true
|
| 1703 |
+
},
|
| 1704 |
+
"sass": {
|
| 1705 |
+
"optional": true
|
| 1706 |
+
},
|
| 1707 |
+
"sass-embedded": {
|
| 1708 |
+
"optional": true
|
| 1709 |
+
},
|
| 1710 |
+
"stylus": {
|
| 1711 |
+
"optional": true
|
| 1712 |
+
},
|
| 1713 |
+
"sugarss": {
|
| 1714 |
+
"optional": true
|
| 1715 |
+
},
|
| 1716 |
+
"terser": {
|
| 1717 |
+
"optional": true
|
| 1718 |
+
}
|
| 1719 |
+
}
|
| 1720 |
+
},
|
| 1721 |
+
"node_modules/yallist": {
|
| 1722 |
+
"version": "3.1.1",
|
| 1723 |
+
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
| 1724 |
+
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
| 1725 |
+
"dev": true,
|
| 1726 |
+
"license": "ISC"
|
| 1727 |
+
}
|
| 1728 |
+
}
|
| 1729 |
+
}
|
frontend/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "cadastro-imobiliario-frontend",
|
| 3 |
+
"private": true,
|
| 4 |
+
"version": "0.1.0",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "vite",
|
| 8 |
+
"build": "tsc && vite build",
|
| 9 |
+
"preview": "vite preview"
|
| 10 |
+
},
|
| 11 |
+
"dependencies": {
|
| 12 |
+
"react": "^18.3.1",
|
| 13 |
+
"react-dom": "^18.3.1"
|
| 14 |
+
},
|
| 15 |
+
"devDependencies": {
|
| 16 |
+
"@types/react": "^18.3.12",
|
| 17 |
+
"@types/react-dom": "^18.3.1",
|
| 18 |
+
"@vitejs/plugin-react": "^4.3.4",
|
| 19 |
+
"typescript": "^5.6.3",
|
| 20 |
+
"vite": "^5.4.10"
|
| 21 |
+
}
|
| 22 |
+
}
|
| 23 |
+
|
frontend/src/App.tsx
ADDED
|
@@ -0,0 +1,1172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { FormEvent, useEffect, useState } from "react";
|
| 2 |
+
import {
|
| 3 |
+
createProperty,
|
| 4 |
+
deleteProperty,
|
| 5 |
+
fetchProperties,
|
| 6 |
+
getExportUrl,
|
| 7 |
+
searchCadastroBase
|
| 8 |
+
} from "./api";
|
| 9 |
+
import type { CadastroBaseRecord, Property, PropertyDraft } from "./types";
|
| 10 |
+
import logoCdA from "./assets/cdA_logo_transparent.png";
|
| 11 |
+
|
| 12 |
+
const CONSERVACAO_OPTIONS = [
|
| 13 |
+
{
|
| 14 |
+
categoria: "Otimo",
|
| 15 |
+
classes: ["A", "B"],
|
| 16 |
+
explicacao: [
|
| 17 |
+
"Imovel novo ou quase novo",
|
| 18 |
+
"Sem danos aparentes",
|
| 19 |
+
"Nao precisa de reparos",
|
| 20 |
+
"Tudo funcionando normalmente",
|
| 21 |
+
"Pode exigir no maximo pintura leve"
|
| 22 |
+
]
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
categoria: "Bom",
|
| 26 |
+
classes: ["C", "D"],
|
| 27 |
+
explicacao: [
|
| 28 |
+
"Imovel bem conservado",
|
| 29 |
+
"Apresenta sinais normais de uso",
|
| 30 |
+
"Pode precisar de pequenos reparos pontuais",
|
| 31 |
+
"Pode ter leves fissuras ou desgaste superficial",
|
| 32 |
+
"Nao compromete o uso do imovel"
|
| 33 |
+
]
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
categoria: "Regular",
|
| 37 |
+
classes: ["E"],
|
| 38 |
+
explicacao: [
|
| 39 |
+
"Precisa de manutencao simples mais ampla",
|
| 40 |
+
"Pode necessitar pintura interna e externa",
|
| 41 |
+
"Pode ter fissuras superficiais mais visiveis",
|
| 42 |
+
"Pode exigir revisao hidraulica ou eletrica",
|
| 43 |
+
"Continua funcional para uso"
|
| 44 |
+
]
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
categoria: "Ruim",
|
| 48 |
+
classes: ["F", "G", "H"],
|
| 49 |
+
explicacao: [
|
| 50 |
+
"Precisa de reparos importantes ou generalizados",
|
| 51 |
+
"Pode comprometer estetica, funcionalidade ou seguranca",
|
| 52 |
+
"Pode exigir troca de revestimentos, telhado ou instalacoes",
|
| 53 |
+
"Pode envolver problemas estruturais",
|
| 54 |
+
"Nos casos mais graves, requer reforma pesada ou quase total"
|
| 55 |
+
]
|
| 56 |
+
}
|
| 57 |
+
] as const;
|
| 58 |
+
|
| 59 |
+
const CLASSIFICATION_GUIDES = {
|
| 60 |
+
infra: {
|
| 61 |
+
titulo: "Infra",
|
| 62 |
+
descricao: "Espaco reservado para os criterios de infraestrutura.",
|
| 63 |
+
status: "Em breve",
|
| 64 |
+
blocos: [
|
| 65 |
+
{
|
| 66 |
+
titulo: "Sem guia ainda",
|
| 67 |
+
itens: [
|
| 68 |
+
"As explicacoes de classificacao de Infra serao adicionadas aqui futuramente.",
|
| 69 |
+
"O campo continua disponivel para selecao manual."
|
| 70 |
+
]
|
| 71 |
+
}
|
| 72 |
+
]
|
| 73 |
+
},
|
| 74 |
+
padrao: {
|
| 75 |
+
titulo: "Padrao",
|
| 76 |
+
descricao: "Espaco reservado para os criterios de padrao construtivo.",
|
| 77 |
+
status: "Em breve",
|
| 78 |
+
blocos: [
|
| 79 |
+
{
|
| 80 |
+
titulo: "Sem guia ainda",
|
| 81 |
+
itens: [
|
| 82 |
+
"As explicacoes de classificacao de Padrao serao adicionadas aqui futuramente.",
|
| 83 |
+
"O campo continua disponivel para selecao manual."
|
| 84 |
+
]
|
| 85 |
+
}
|
| 86 |
+
]
|
| 87 |
+
},
|
| 88 |
+
conservacao: {
|
| 89 |
+
titulo: "Conservacao",
|
| 90 |
+
descricao: "Leia os textos e escolha a categoria mais adequada ao estado atual do imovel.",
|
| 91 |
+
status: "Disponivel",
|
| 92 |
+
blocos: CONSERVACAO_OPTIONS.map((option) => ({
|
| 93 |
+
titulo: `${option.categoria} | Classes ${option.classes.join(", ")}`,
|
| 94 |
+
valor: option.categoria,
|
| 95 |
+
itens: option.explicacao
|
| 96 |
+
}))
|
| 97 |
+
},
|
| 98 |
+
vaga: {
|
| 99 |
+
titulo: "Vaga",
|
| 100 |
+
descricao: "Considere a existencia de vaga e a facilidade de estacionamento no entorno.",
|
| 101 |
+
status: "Disponivel",
|
| 102 |
+
blocos: [
|
| 103 |
+
{
|
| 104 |
+
titulo: "Sim",
|
| 105 |
+
valor: "Sim",
|
| 106 |
+
itens: [
|
| 107 |
+
"O imovel possui vaga propria ou vaga disponivel no empreendimento."
|
| 108 |
+
]
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
titulo: "Nao | estacionamento facilitado",
|
| 112 |
+
valor: "Nao - facilidade de estacionamento",
|
| 113 |
+
itens: [
|
| 114 |
+
"O imovel nao possui vaga.",
|
| 115 |
+
"Mesmo assim, a regiao oferece facilidade para estacionar."
|
| 116 |
+
]
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
titulo: "Nao | estacionamento dificil",
|
| 120 |
+
valor: "Nao - dificuldade de estacionamento",
|
| 121 |
+
itens: [
|
| 122 |
+
"O imovel nao possui vaga.",
|
| 123 |
+
"Ha dificuldade de encontrar estacionamento na regiao."
|
| 124 |
+
]
|
| 125 |
+
}
|
| 126 |
+
]
|
| 127 |
+
}
|
| 128 |
+
} as const;
|
| 129 |
+
|
| 130 |
+
const initialForm: PropertyDraft = {
|
| 131 |
+
titulo: null,
|
| 132 |
+
finalidade: "RESIDENCIAL",
|
| 133 |
+
num_bloco: null,
|
| 134 |
+
num_inscricao: null,
|
| 135 |
+
cod_endloc_logradouro: null,
|
| 136 |
+
nme_endloc_logradouro: null,
|
| 137 |
+
num_endloc_endereco: null,
|
| 138 |
+
num_endloc_unidade: null,
|
| 139 |
+
nme_endloc_bairro_cdl: null,
|
| 140 |
+
rh_nome: null,
|
| 141 |
+
rh_valor: null,
|
| 142 |
+
coord_x: null,
|
| 143 |
+
coord_y: null,
|
| 144 |
+
ano_exercicio: null,
|
| 145 |
+
num_versao: null,
|
| 146 |
+
idf_reg_regiao_homogenea: null,
|
| 147 |
+
area_total_detalhe: null,
|
| 148 |
+
area_total: null,
|
| 149 |
+
area_privativa_detalhe: null,
|
| 150 |
+
area_privativa: null,
|
| 151 |
+
finalidade_oferta: null,
|
| 152 |
+
area_total_oferta: null,
|
| 153 |
+
area_privativa_oferta: null,
|
| 154 |
+
valor_oferta: null,
|
| 155 |
+
latitude: null,
|
| 156 |
+
longitude: null,
|
| 157 |
+
descricao_oferta: "",
|
| 158 |
+
observacao: "",
|
| 159 |
+
url: "",
|
| 160 |
+
imobiliaria: "",
|
| 161 |
+
codigo: "",
|
| 162 |
+
infra: "",
|
| 163 |
+
padrao: "",
|
| 164 |
+
conservacao: "",
|
| 165 |
+
vaga: "",
|
| 166 |
+
origem: "manual",
|
| 167 |
+
};
|
| 168 |
+
|
| 169 |
+
function joinUnique(values: Array<string | null | undefined>): string | null {
|
| 170 |
+
const uniqueValues = Array.from(
|
| 171 |
+
new Set(values.map((value) => value?.trim()).filter((value): value is string => Boolean(value)))
|
| 172 |
+
);
|
| 173 |
+
return uniqueValues.length > 0 ? uniqueValues.join(" | ") : null;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
function sumValues(values: Array<number | null | undefined>): number | null {
|
| 177 |
+
const validValues = values.filter((value): value is number => typeof value === "number");
|
| 178 |
+
return validValues.length > 0
|
| 179 |
+
? Number(validValues.reduce((total, value) => total + value, 0).toFixed(2))
|
| 180 |
+
: null;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
function joinNumbers(values: Array<number | null | undefined>): string | null {
|
| 184 |
+
const formattedValues = values
|
| 185 |
+
.filter((value): value is number => typeof value === "number")
|
| 186 |
+
.map((value) => String(value));
|
| 187 |
+
return formattedValues.length > 0 ? formattedValues.join(" | ") : null;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
function firstValue<T>(values: Array<T | null | undefined>): T | null {
|
| 191 |
+
const found = values.find((value): value is T => value !== null && value !== undefined);
|
| 192 |
+
return found ?? null;
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
function buildCadastroFields(records: CadastroBaseRecord[]): Pick<
|
| 196 |
+
PropertyDraft,
|
| 197 |
+
| "finalidade"
|
| 198 |
+
| "num_bloco"
|
| 199 |
+
| "num_inscricao"
|
| 200 |
+
| "cod_endloc_logradouro"
|
| 201 |
+
| "nme_endloc_logradouro"
|
| 202 |
+
| "num_endloc_endereco"
|
| 203 |
+
| "num_endloc_unidade"
|
| 204 |
+
| "nme_endloc_bairro_cdl"
|
| 205 |
+
| "rh_nome"
|
| 206 |
+
| "rh_valor"
|
| 207 |
+
| "coord_x"
|
| 208 |
+
| "coord_y"
|
| 209 |
+
| "ano_exercicio"
|
| 210 |
+
| "num_versao"
|
| 211 |
+
| "idf_reg_regiao_homogenea"
|
| 212 |
+
| "area_total_detalhe"
|
| 213 |
+
| "area_total"
|
| 214 |
+
| "area_privativa_detalhe"
|
| 215 |
+
| "area_privativa"
|
| 216 |
+
| "latitude"
|
| 217 |
+
| "longitude"
|
| 218 |
+
| "origem"
|
| 219 |
+
> {
|
| 220 |
+
return {
|
| 221 |
+
finalidade: joinUnique(records.map((record) => record.des_finalidade)) ?? "RESIDENCIAL",
|
| 222 |
+
num_bloco: joinUnique(records.map((record) => record.num_bloco)),
|
| 223 |
+
num_inscricao: joinUnique(records.map((record) => record.num_inscricao)),
|
| 224 |
+
cod_endloc_logradouro: joinUnique(records.map((record) => record.cod_endloc_logradouro)),
|
| 225 |
+
nme_endloc_logradouro: joinUnique(records.map((record) => record.nme_endloc_logradouro)),
|
| 226 |
+
num_endloc_endereco: joinUnique(records.map((record) => record.num_endloc_endereco)),
|
| 227 |
+
num_endloc_unidade: joinUnique(records.map((record) => record.num_endloc_unidade)),
|
| 228 |
+
nme_endloc_bairro_cdl: joinUnique(records.map((record) => record.nme_endloc_bairro_cdl)),
|
| 229 |
+
rh_nome: firstValue(records.map((record) => record.rh_nome)),
|
| 230 |
+
rh_valor: firstValue(records.map((record) => record.rh_valor)),
|
| 231 |
+
coord_x: firstValue(records.map((record) => record.coord_x)),
|
| 232 |
+
coord_y: firstValue(records.map((record) => record.coord_y)),
|
| 233 |
+
ano_exercicio: firstValue(records.map((record) => record.ano_exercicio)),
|
| 234 |
+
num_versao: firstValue(records.map((record) => record.num_versao)),
|
| 235 |
+
idf_reg_regiao_homogenea: firstValue(records.map((record) => record.idf_reg_regiao_homogenea)),
|
| 236 |
+
area_total_detalhe: joinNumbers(records.map((record) => record.area_territorial)),
|
| 237 |
+
area_total: sumValues(records.map((record) => record.area_territorial)),
|
| 238 |
+
area_privativa_detalhe: joinNumbers(records.map((record) => record.area_construida)),
|
| 239 |
+
area_privativa: sumValues(records.map((record) => record.area_construida)),
|
| 240 |
+
latitude: firstValue(records.map((record) => record.latitude)),
|
| 241 |
+
longitude: firstValue(records.map((record) => record.longitude)),
|
| 242 |
+
origem: "cadastro_base"
|
| 243 |
+
};
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
function App() {
|
| 247 |
+
const [properties, setProperties] = useState<Property[]>([]);
|
| 248 |
+
const [form, setForm] = useState<PropertyDraft>(initialForm);
|
| 249 |
+
const [cadastroRecords, setCadastroRecords] = useState<CadastroBaseRecord[]>([]);
|
| 250 |
+
const [searchMode, setSearchMode] = useState<"inscricao" | "endereco">("inscricao");
|
| 251 |
+
const [searchQuery, setSearchQuery] = useState("");
|
| 252 |
+
const [searchResults, setSearchResults] = useState<CadastroBaseRecord[]>([]);
|
| 253 |
+
const [searching, setSearching] = useState(false);
|
| 254 |
+
const [loading, setLoading] = useState(false);
|
| 255 |
+
const [message, setMessage] = useState<string>("");
|
| 256 |
+
const [error, setError] = useState<string>("");
|
| 257 |
+
const [deleteTarget, setDeleteTarget] = useState<number | null>(null);
|
| 258 |
+
const [activeClassifier, setActiveClassifier] =
|
| 259 |
+
useState<keyof typeof CLASSIFICATION_GUIDES>("conservacao");
|
| 260 |
+
const [openSections, setOpenSections] = useState({
|
| 261 |
+
busca: true,
|
| 262 |
+
cadastro: true,
|
| 263 |
+
oferta: true,
|
| 264 |
+
outras: true,
|
| 265 |
+
tabela: true
|
| 266 |
+
});
|
| 267 |
+
|
| 268 |
+
async function loadProperties() {
|
| 269 |
+
setLoading(true);
|
| 270 |
+
setError("");
|
| 271 |
+
try {
|
| 272 |
+
const data = await fetchProperties();
|
| 273 |
+
setProperties(data);
|
| 274 |
+
} catch (err) {
|
| 275 |
+
setError(err instanceof Error ? err.message : "Erro ao carregar dados.");
|
| 276 |
+
} finally {
|
| 277 |
+
setLoading(false);
|
| 278 |
+
}
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
useEffect(() => {
|
| 282 |
+
void loadProperties();
|
| 283 |
+
}, []);
|
| 284 |
+
|
| 285 |
+
function updateField<K extends keyof PropertyDraft>(field: K, value: PropertyDraft[K]) {
|
| 286 |
+
setForm((current) => ({ ...current, [field]: value }));
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
function applyCadastroBase(record: CadastroBaseRecord) {
|
| 290 |
+
setCadastroRecords((current) => {
|
| 291 |
+
const alreadyAdded = current.some((item) => item.num_inscricao === record.num_inscricao);
|
| 292 |
+
const nextRecords = alreadyAdded ? current : [...current, record];
|
| 293 |
+
setForm((formState) => ({
|
| 294 |
+
...formState,
|
| 295 |
+
...buildCadastroFields(nextRecords)
|
| 296 |
+
}));
|
| 297 |
+
return nextRecords;
|
| 298 |
+
});
|
| 299 |
+
setMessage("Imovel adicionado ao cadastro da oferta. Os campos continuam editaveis.");
|
| 300 |
+
setError("");
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
function removeCadastroRecord(numInscricao: string) {
|
| 304 |
+
setCadastroRecords((current) => {
|
| 305 |
+
const nextRecords = current.filter((record) => record.num_inscricao !== numInscricao);
|
| 306 |
+
setForm((formState) =>
|
| 307 |
+
nextRecords.length > 0
|
| 308 |
+
? {
|
| 309 |
+
...formState,
|
| 310 |
+
...buildCadastroFields(nextRecords)
|
| 311 |
+
}
|
| 312 |
+
: {
|
| 313 |
+
...formState,
|
| 314 |
+
finalidade: initialForm.finalidade,
|
| 315 |
+
num_bloco: null,
|
| 316 |
+
num_inscricao: null,
|
| 317 |
+
cod_endloc_logradouro: null,
|
| 318 |
+
nme_endloc_logradouro: null,
|
| 319 |
+
num_endloc_endereco: null,
|
| 320 |
+
num_endloc_unidade: null,
|
| 321 |
+
nme_endloc_bairro_cdl: null,
|
| 322 |
+
rh_nome: null,
|
| 323 |
+
rh_valor: null,
|
| 324 |
+
coord_x: null,
|
| 325 |
+
coord_y: null,
|
| 326 |
+
ano_exercicio: null,
|
| 327 |
+
num_versao: null,
|
| 328 |
+
idf_reg_regiao_homogenea: null,
|
| 329 |
+
area_total_detalhe: null,
|
| 330 |
+
area_total: null,
|
| 331 |
+
area_privativa_detalhe: null,
|
| 332 |
+
area_privativa: null,
|
| 333 |
+
latitude: null,
|
| 334 |
+
longitude: null,
|
| 335 |
+
origem: "manual"
|
| 336 |
+
}
|
| 337 |
+
);
|
| 338 |
+
return nextRecords;
|
| 339 |
+
});
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
async function handleSubmit(event: FormEvent) {
|
| 343 |
+
event.preventDefault();
|
| 344 |
+
setError("");
|
| 345 |
+
setMessage("");
|
| 346 |
+
|
| 347 |
+
try {
|
| 348 |
+
const created = await createProperty(form);
|
| 349 |
+
setProperties((current) => [created, ...current]);
|
| 350 |
+
setForm(initialForm);
|
| 351 |
+
setCadastroRecords([]);
|
| 352 |
+
setMessage("Imovel cadastrado com sucesso.");
|
| 353 |
+
} catch (err) {
|
| 354 |
+
setError(err instanceof Error ? err.message : "Erro ao salvar cadastro.");
|
| 355 |
+
}
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
async function handleCadastroSearch() {
|
| 359 |
+
setSearching(true);
|
| 360 |
+
setError("");
|
| 361 |
+
setMessage("");
|
| 362 |
+
|
| 363 |
+
try {
|
| 364 |
+
const result = await searchCadastroBase(searchMode, searchQuery);
|
| 365 |
+
setSearchResults(result.items);
|
| 366 |
+
if (result.items.length === 0) {
|
| 367 |
+
setMessage("Nenhum registro encontrado na base cadastral.");
|
| 368 |
+
}
|
| 369 |
+
} catch (err) {
|
| 370 |
+
setError(err instanceof Error ? err.message : "Erro ao consultar base cadastral.");
|
| 371 |
+
} finally {
|
| 372 |
+
setSearching(false);
|
| 373 |
+
}
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
function handleExport() {
|
| 377 |
+
window.open(getExportUrl(), "_blank", "noopener,noreferrer");
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
async function handleDelete(propertyId: number) {
|
| 381 |
+
setError("");
|
| 382 |
+
setMessage("");
|
| 383 |
+
try {
|
| 384 |
+
await deleteProperty(propertyId);
|
| 385 |
+
setProperties((current) => current.filter((item) => item.id !== propertyId));
|
| 386 |
+
setDeleteTarget(null);
|
| 387 |
+
setMessage("Registro excluido com sucesso.");
|
| 388 |
+
} catch (err) {
|
| 389 |
+
setError(err instanceof Error ? err.message : "Erro ao excluir registro.");
|
| 390 |
+
}
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
function toggleSection(section: keyof typeof openSections) {
|
| 394 |
+
setOpenSections((current) => ({ ...current, [section]: !current[section] }));
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
const activeGuide = CLASSIFICATION_GUIDES[activeClassifier];
|
| 398 |
+
|
| 399 |
+
return (
|
| 400 |
+
<div className="page">
|
| 401 |
+
<header className="hero hero-logo-only">
|
| 402 |
+
<img src={logoCdA} alt="cdA" className="hero-logo" />
|
| 403 |
+
<div className="hero-search">
|
| 404 |
+
<div className="hero-search-head">
|
| 405 |
+
<p className="sequence-kicker">Busca cadastral</p>
|
| 406 |
+
<h2>Inscricao ou endereco</h2>
|
| 407 |
+
</div>
|
| 408 |
+
<div className="search-bar">
|
| 409 |
+
<select
|
| 410 |
+
value={searchMode}
|
| 411 |
+
onChange={(event) =>
|
| 412 |
+
setSearchMode(event.target.value as "inscricao" | "endereco")
|
| 413 |
+
}
|
| 414 |
+
>
|
| 415 |
+
<option value="endereco">Endereco</option>
|
| 416 |
+
<option value="inscricao">Inscricao</option>
|
| 417 |
+
</select>
|
| 418 |
+
<input
|
| 419 |
+
value={searchQuery}
|
| 420 |
+
onChange={(event) => setSearchQuery(event.target.value)}
|
| 421 |
+
placeholder={
|
| 422 |
+
searchMode === "inscricao"
|
| 423 |
+
? "Ex.: 2720"
|
| 424 |
+
: "Ex.: RUA AFONSO ARINOS 115 ou RUA AFONSO ARINOS 115 2"
|
| 425 |
+
}
|
| 426 |
+
/>
|
| 427 |
+
<button type="button" onClick={() => void handleCadastroSearch()}>
|
| 428 |
+
{searching ? "Buscando..." : "Buscar"}
|
| 429 |
+
</button>
|
| 430 |
+
</div>
|
| 431 |
+
<p className="hero-search-help">
|
| 432 |
+
Em endereco, informe logradouro e numero. Se existir unidade, ela pode ser
|
| 433 |
+
adicionada ao final da busca.
|
| 434 |
+
</p>
|
| 435 |
+
</div>
|
| 436 |
+
</header>
|
| 437 |
+
|
| 438 |
+
<main className="sequence">
|
| 439 |
+
<section className="panel sequence-panel">
|
| 440 |
+
<div className="sequence-head">
|
| 441 |
+
<div className="sequence-index">01</div>
|
| 442 |
+
<div>
|
| 443 |
+
<p className="sequence-kicker">Etapa inicial</p>
|
| 444 |
+
<h2>Resultados da busca</h2>
|
| 445 |
+
</div>
|
| 446 |
+
<button
|
| 447 |
+
type="button"
|
| 448 |
+
className="collapse-btn secondary"
|
| 449 |
+
onClick={() => toggleSection("busca")}
|
| 450 |
+
>
|
| 451 |
+
{openSections.busca ? "Recolher" : "Expandir"}
|
| 452 |
+
</button>
|
| 453 |
+
</div>
|
| 454 |
+
{openSections.busca ? (
|
| 455 |
+
<div className="section-body">
|
| 456 |
+
<p className="muted">
|
| 457 |
+
Selecione um dos registros retornados para preencher automaticamente o formulario
|
| 458 |
+
abaixo. A edicao continua livre depois disso.
|
| 459 |
+
</p>
|
| 460 |
+
|
| 461 |
+
<div className="result-list">
|
| 462 |
+
{searchResults.length === 0 ? (
|
| 463 |
+
<div className="empty-state">Nenhum resultado carregado ainda.</div>
|
| 464 |
+
) : (
|
| 465 |
+
searchResults.map((item) => (
|
| 466 |
+
<button
|
| 467 |
+
type="button"
|
| 468 |
+
key={`${item.num_inscricao}-${item.num_endloc_endereco ?? ""}`}
|
| 469 |
+
className="result-card"
|
| 470 |
+
onClick={() => applyCadastroBase(item)}
|
| 471 |
+
>
|
| 472 |
+
<strong>{item.display_label}</strong>
|
| 473 |
+
<span className="result-line">
|
| 474 |
+
Finalidade: {item.des_finalidade ?? "-"}
|
| 475 |
+
</span>
|
| 476 |
+
<span className="result-line">
|
| 477 |
+
Area territorial: {item.area_territorial ?? "-"} | Area construida:{" "}
|
| 478 |
+
{item.area_construida ?? "-"}
|
| 479 |
+
</span>
|
| 480 |
+
</button>
|
| 481 |
+
))
|
| 482 |
+
)}
|
| 483 |
+
</div>
|
| 484 |
+
</div>
|
| 485 |
+
) : null}
|
| 486 |
+
</section>
|
| 487 |
+
|
| 488 |
+
<form onSubmit={handleSubmit} className="sequence-form">
|
| 489 |
+
<section className="panel sequence-panel">
|
| 490 |
+
<div className="sequence-head">
|
| 491 |
+
<div className="sequence-index">02</div>
|
| 492 |
+
<div>
|
| 493 |
+
<p className="sequence-kicker">Novo registro</p>
|
| 494 |
+
<h2>Cadastro</h2>
|
| 495 |
+
</div>
|
| 496 |
+
<button
|
| 497 |
+
type="button"
|
| 498 |
+
className="collapse-btn secondary"
|
| 499 |
+
onClick={() => toggleSection("cadastro")}
|
| 500 |
+
>
|
| 501 |
+
{openSections.cadastro ? "Recolher" : "Expandir"}
|
| 502 |
+
</button>
|
| 503 |
+
</div>
|
| 504 |
+
{openSections.cadastro ? (
|
| 505 |
+
<div className="section-body">
|
| 506 |
+
<div className="form-banner">
|
| 507 |
+
Adicione uma ou mais inscricoes para a mesma oferta. A planilha final mantem uma
|
| 508 |
+
linha por oferta, com os dados cadastrais consolidados.
|
| 509 |
+
</div>
|
| 510 |
+
<div className="selected-cadastros">
|
| 511 |
+
<div className="selected-cadastros-head">
|
| 512 |
+
<strong>Imoveis desta oferta</strong>
|
| 513 |
+
<span>{cadastroRecords.length} selecionado(s)</span>
|
| 514 |
+
</div>
|
| 515 |
+
{cadastroRecords.length === 0 ? (
|
| 516 |
+
<p className="muted">Nenhuma inscricao adicionada ainda.</p>
|
| 517 |
+
) : (
|
| 518 |
+
<div className="selected-cadastro-list">
|
| 519 |
+
{cadastroRecords.map((record) => (
|
| 520 |
+
<div className="selected-cadastro-item" key={record.num_inscricao}>
|
| 521 |
+
<div>
|
| 522 |
+
<strong>{record.num_inscricao}</strong>
|
| 523 |
+
<span>
|
| 524 |
+
{[record.nme_endloc_logradouro, record.num_endloc_endereco]
|
| 525 |
+
.filter(Boolean)
|
| 526 |
+
.join(", ") || "-"}
|
| 527 |
+
{record.num_endloc_unidade ? ` / ${record.num_endloc_unidade}` : ""}
|
| 528 |
+
</span>
|
| 529 |
+
</div>
|
| 530 |
+
<button
|
| 531 |
+
type="button"
|
| 532 |
+
className="secondary"
|
| 533 |
+
onClick={() => removeCadastroRecord(record.num_inscricao)}
|
| 534 |
+
>
|
| 535 |
+
Remover
|
| 536 |
+
</button>
|
| 537 |
+
</div>
|
| 538 |
+
))}
|
| 539 |
+
</div>
|
| 540 |
+
)}
|
| 541 |
+
</div>
|
| 542 |
+
<div className="form-grid cadastro-grid">
|
| 543 |
+
<label>
|
| 544 |
+
NUM_BLOCO
|
| 545 |
+
<input
|
| 546 |
+
value={form.num_bloco ?? ""}
|
| 547 |
+
onChange={(event) => updateField("num_bloco", event.target.value || null)}
|
| 548 |
+
/>
|
| 549 |
+
</label>
|
| 550 |
+
|
| 551 |
+
<label>
|
| 552 |
+
NUM_INSCRICAO
|
| 553 |
+
<input
|
| 554 |
+
value={form.num_inscricao ?? ""}
|
| 555 |
+
onChange={(event) => updateField("num_inscricao", event.target.value || null)}
|
| 556 |
+
/>
|
| 557 |
+
</label>
|
| 558 |
+
|
| 559 |
+
<label>
|
| 560 |
+
COD_ENDLOC_LOGRADOURO
|
| 561 |
+
<input
|
| 562 |
+
value={form.cod_endloc_logradouro ?? ""}
|
| 563 |
+
onChange={(event) =>
|
| 564 |
+
updateField("cod_endloc_logradouro", event.target.value || null)
|
| 565 |
+
}
|
| 566 |
+
/>
|
| 567 |
+
</label>
|
| 568 |
+
|
| 569 |
+
<label>
|
| 570 |
+
NME_ENDLOC_LOGRADOURO
|
| 571 |
+
<input
|
| 572 |
+
value={form.nme_endloc_logradouro ?? ""}
|
| 573 |
+
onChange={(event) =>
|
| 574 |
+
updateField("nme_endloc_logradouro", event.target.value || null)
|
| 575 |
+
}
|
| 576 |
+
/>
|
| 577 |
+
</label>
|
| 578 |
+
|
| 579 |
+
<label>
|
| 580 |
+
NUM_ENDLOC_ENDERECO
|
| 581 |
+
<input
|
| 582 |
+
value={form.num_endloc_endereco ?? ""}
|
| 583 |
+
onChange={(event) =>
|
| 584 |
+
updateField("num_endloc_endereco", event.target.value || null)
|
| 585 |
+
}
|
| 586 |
+
/>
|
| 587 |
+
</label>
|
| 588 |
+
|
| 589 |
+
<label>
|
| 590 |
+
NUM_ENDLOC_UNIDADE
|
| 591 |
+
<input
|
| 592 |
+
value={form.num_endloc_unidade ?? ""}
|
| 593 |
+
onChange={(event) =>
|
| 594 |
+
updateField("num_endloc_unidade", event.target.value || null)
|
| 595 |
+
}
|
| 596 |
+
/>
|
| 597 |
+
</label>
|
| 598 |
+
|
| 599 |
+
<label>
|
| 600 |
+
NME_ENDLOC_BAIRRO_CDL
|
| 601 |
+
<input
|
| 602 |
+
value={form.nme_endloc_bairro_cdl ?? ""}
|
| 603 |
+
onChange={(event) =>
|
| 604 |
+
updateField("nme_endloc_bairro_cdl", event.target.value || null)
|
| 605 |
+
}
|
| 606 |
+
/>
|
| 607 |
+
</label>
|
| 608 |
+
|
| 609 |
+
<label>
|
| 610 |
+
DES_FINALIDADE
|
| 611 |
+
<input
|
| 612 |
+
value={form.finalidade}
|
| 613 |
+
onChange={(event) => updateField("finalidade", event.target.value)}
|
| 614 |
+
/>
|
| 615 |
+
</label>
|
| 616 |
+
|
| 617 |
+
<label>
|
| 618 |
+
AREA_TERRITORIAL_SEPARADA
|
| 619 |
+
<input
|
| 620 |
+
value={form.area_total_detalhe ?? ""}
|
| 621 |
+
onChange={(event) =>
|
| 622 |
+
updateField("area_total_detalhe", event.target.value || null)
|
| 623 |
+
}
|
| 624 |
+
/>
|
| 625 |
+
</label>
|
| 626 |
+
|
| 627 |
+
<label>
|
| 628 |
+
AREA_TERRITORIAL_SOMA
|
| 629 |
+
<input
|
| 630 |
+
type="number"
|
| 631 |
+
step="0.01"
|
| 632 |
+
value={form.area_total ?? ""}
|
| 633 |
+
onChange={(event) =>
|
| 634 |
+
updateField(
|
| 635 |
+
"area_total",
|
| 636 |
+
event.target.value ? Number(event.target.value) : null
|
| 637 |
+
)
|
| 638 |
+
}
|
| 639 |
+
/>
|
| 640 |
+
</label>
|
| 641 |
+
|
| 642 |
+
<label>
|
| 643 |
+
AREA_CONSTRUIDA_SEPARADA
|
| 644 |
+
<input
|
| 645 |
+
value={form.area_privativa_detalhe ?? ""}
|
| 646 |
+
onChange={(event) =>
|
| 647 |
+
updateField("area_privativa_detalhe", event.target.value || null)
|
| 648 |
+
}
|
| 649 |
+
/>
|
| 650 |
+
</label>
|
| 651 |
+
|
| 652 |
+
<label>
|
| 653 |
+
AREA_CONSTRUIDA_SOMA
|
| 654 |
+
<input
|
| 655 |
+
type="number"
|
| 656 |
+
step="0.01"
|
| 657 |
+
value={form.area_privativa ?? ""}
|
| 658 |
+
onChange={(event) =>
|
| 659 |
+
updateField(
|
| 660 |
+
"area_privativa",
|
| 661 |
+
event.target.value ? Number(event.target.value) : null
|
| 662 |
+
)
|
| 663 |
+
}
|
| 664 |
+
/>
|
| 665 |
+
</label>
|
| 666 |
+
|
| 667 |
+
<label>
|
| 668 |
+
RH_NOME
|
| 669 |
+
<input
|
| 670 |
+
value={form.rh_nome ?? ""}
|
| 671 |
+
onChange={(event) => updateField("rh_nome", event.target.value || null)}
|
| 672 |
+
/>
|
| 673 |
+
</label>
|
| 674 |
+
|
| 675 |
+
<label>
|
| 676 |
+
RH_VALOR
|
| 677 |
+
<input
|
| 678 |
+
type="number"
|
| 679 |
+
step="0.01"
|
| 680 |
+
value={form.rh_valor ?? ""}
|
| 681 |
+
onChange={(event) =>
|
| 682 |
+
updateField(
|
| 683 |
+
"rh_valor",
|
| 684 |
+
event.target.value ? Number(event.target.value) : null
|
| 685 |
+
)
|
| 686 |
+
}
|
| 687 |
+
/>
|
| 688 |
+
</label>
|
| 689 |
+
|
| 690 |
+
<label>
|
| 691 |
+
LATITUDE
|
| 692 |
+
<input
|
| 693 |
+
type="number"
|
| 694 |
+
step="0.000001"
|
| 695 |
+
value={form.latitude ?? ""}
|
| 696 |
+
onChange={(event) =>
|
| 697 |
+
updateField(
|
| 698 |
+
"latitude",
|
| 699 |
+
event.target.value ? Number(event.target.value) : null
|
| 700 |
+
)
|
| 701 |
+
}
|
| 702 |
+
/>
|
| 703 |
+
</label>
|
| 704 |
+
|
| 705 |
+
<label>
|
| 706 |
+
LONGITUDE
|
| 707 |
+
<input
|
| 708 |
+
type="number"
|
| 709 |
+
step="0.000001"
|
| 710 |
+
value={form.longitude ?? ""}
|
| 711 |
+
onChange={(event) =>
|
| 712 |
+
updateField(
|
| 713 |
+
"longitude",
|
| 714 |
+
event.target.value ? Number(event.target.value) : null
|
| 715 |
+
)
|
| 716 |
+
}
|
| 717 |
+
/>
|
| 718 |
+
</label>
|
| 719 |
+
</div>
|
| 720 |
+
</div>
|
| 721 |
+
) : null}
|
| 722 |
+
</section>
|
| 723 |
+
|
| 724 |
+
<section className="panel sequence-panel">
|
| 725 |
+
<div className="sequence-head">
|
| 726 |
+
<div className="sequence-index">03</div>
|
| 727 |
+
<div>
|
| 728 |
+
<p className="sequence-kicker">Novo registro</p>
|
| 729 |
+
<h2>Oferta</h2>
|
| 730 |
+
</div>
|
| 731 |
+
<button
|
| 732 |
+
type="button"
|
| 733 |
+
className="collapse-btn secondary"
|
| 734 |
+
onClick={() => toggleSection("oferta")}
|
| 735 |
+
>
|
| 736 |
+
{openSections.oferta ? "Recolher" : "Expandir"}
|
| 737 |
+
</button>
|
| 738 |
+
</div>
|
| 739 |
+
{openSections.oferta ? (
|
| 740 |
+
<div className="section-body">
|
| 741 |
+
<div className="form-grid offer-grid">
|
| 742 |
+
<label>
|
| 743 |
+
Finalidade oferta
|
| 744 |
+
<select
|
| 745 |
+
value={form.finalidade_oferta ?? ""}
|
| 746 |
+
onChange={(event) =>
|
| 747 |
+
updateField("finalidade_oferta", event.target.value || null)
|
| 748 |
+
}
|
| 749 |
+
>
|
| 750 |
+
<option value="">Selecione</option>
|
| 751 |
+
<option value="Andar comercial">Andar comercial</option>
|
| 752 |
+
<option value="Casa comercial">Casa comercial</option>
|
| 753 |
+
<option value="Edificio isolado">Edificio isolado</option>
|
| 754 |
+
<option value="Estacionamento">Estacionamento</option>
|
| 755 |
+
<option value="Imovel especial">Imovel especial</option>
|
| 756 |
+
<option value="Loja em conjunto comercial">Loja em conjunto comercial</option>
|
| 757 |
+
<option value="Loja em galeria fechada">Loja em galeria fechada</option>
|
| 758 |
+
<option value="Loja em shopping fechado">Loja em shopping fechado</option>
|
| 759 |
+
<option value="Loja isolada">Loja isolada</option>
|
| 760 |
+
<option value="Loja nao isolada">Loja nao isolada</option>
|
| 761 |
+
<option value="Loja terrea em edificio">Loja terrea em edificio</option>
|
| 762 |
+
<option value="Sala comercial">Sala comercial</option>
|
| 763 |
+
<option value="Terreno">Terreno</option>
|
| 764 |
+
</select>
|
| 765 |
+
</label>
|
| 766 |
+
|
| 767 |
+
<label>
|
| 768 |
+
Area total oferta
|
| 769 |
+
<input
|
| 770 |
+
type="number"
|
| 771 |
+
step="0.01"
|
| 772 |
+
value={form.area_total_oferta ?? ""}
|
| 773 |
+
onChange={(event) =>
|
| 774 |
+
updateField(
|
| 775 |
+
"area_total_oferta",
|
| 776 |
+
event.target.value ? Number(event.target.value) : null
|
| 777 |
+
)
|
| 778 |
+
}
|
| 779 |
+
/>
|
| 780 |
+
</label>
|
| 781 |
+
|
| 782 |
+
<label>
|
| 783 |
+
Area privativa oferta
|
| 784 |
+
<input
|
| 785 |
+
type="number"
|
| 786 |
+
step="0.01"
|
| 787 |
+
value={form.area_privativa_oferta ?? ""}
|
| 788 |
+
onChange={(event) =>
|
| 789 |
+
updateField(
|
| 790 |
+
"area_privativa_oferta",
|
| 791 |
+
event.target.value ? Number(event.target.value) : null
|
| 792 |
+
)
|
| 793 |
+
}
|
| 794 |
+
/>
|
| 795 |
+
</label>
|
| 796 |
+
|
| 797 |
+
<label>
|
| 798 |
+
Valor oferta
|
| 799 |
+
<input
|
| 800 |
+
type="number"
|
| 801 |
+
step="0.01"
|
| 802 |
+
value={form.valor_oferta ?? ""}
|
| 803 |
+
onChange={(event) =>
|
| 804 |
+
updateField(
|
| 805 |
+
"valor_oferta",
|
| 806 |
+
event.target.value ? Number(event.target.value) : null
|
| 807 |
+
)
|
| 808 |
+
}
|
| 809 |
+
/>
|
| 810 |
+
</label>
|
| 811 |
+
|
| 812 |
+
<label className="offer-wide">
|
| 813 |
+
Descricao oferta
|
| 814 |
+
<textarea
|
| 815 |
+
value={form.descricao_oferta ?? ""}
|
| 816 |
+
onChange={(event) =>
|
| 817 |
+
updateField("descricao_oferta", event.target.value || null)
|
| 818 |
+
}
|
| 819 |
+
rows={4}
|
| 820 |
+
/>
|
| 821 |
+
</label>
|
| 822 |
+
|
| 823 |
+
<label className="offer-wide">
|
| 824 |
+
Observacao
|
| 825 |
+
<textarea
|
| 826 |
+
value={form.observacao ?? ""}
|
| 827 |
+
onChange={(event) => updateField("observacao", event.target.value || null)}
|
| 828 |
+
rows={3}
|
| 829 |
+
/>
|
| 830 |
+
</label>
|
| 831 |
+
|
| 832 |
+
<label>
|
| 833 |
+
URL
|
| 834 |
+
<input
|
| 835 |
+
value={form.url ?? ""}
|
| 836 |
+
onChange={(event) => updateField("url", event.target.value || null)}
|
| 837 |
+
/>
|
| 838 |
+
</label>
|
| 839 |
+
|
| 840 |
+
<label>
|
| 841 |
+
Imobiliaria
|
| 842 |
+
<input
|
| 843 |
+
value={form.imobiliaria ?? ""}
|
| 844 |
+
onChange={(event) => updateField("imobiliaria", event.target.value || null)}
|
| 845 |
+
/>
|
| 846 |
+
</label>
|
| 847 |
+
|
| 848 |
+
<label>
|
| 849 |
+
Codigo
|
| 850 |
+
<input
|
| 851 |
+
value={form.codigo ?? ""}
|
| 852 |
+
onChange={(event) => updateField("codigo", event.target.value || null)}
|
| 853 |
+
/>
|
| 854 |
+
</label>
|
| 855 |
+
|
| 856 |
+
</div>
|
| 857 |
+
</div>
|
| 858 |
+
) : null}
|
| 859 |
+
</section>
|
| 860 |
+
|
| 861 |
+
<section className="panel sequence-panel">
|
| 862 |
+
<div className="sequence-head">
|
| 863 |
+
<div className="sequence-index">04</div>
|
| 864 |
+
<div>
|
| 865 |
+
<p className="sequence-kicker">Novo registro</p>
|
| 866 |
+
<h2>Outras Caracteristicas</h2>
|
| 867 |
+
</div>
|
| 868 |
+
<button
|
| 869 |
+
type="button"
|
| 870 |
+
className="collapse-btn secondary"
|
| 871 |
+
onClick={() => toggleSection("outras")}
|
| 872 |
+
>
|
| 873 |
+
{openSections.outras ? "Recolher" : "Expandir"}
|
| 874 |
+
</button>
|
| 875 |
+
</div>
|
| 876 |
+
{openSections.outras ? (
|
| 877 |
+
<div className="section-body">
|
| 878 |
+
<div className="classification-layout">
|
| 879 |
+
<div className="classification-controls">
|
| 880 |
+
<div className="classification-row">
|
| 881 |
+
<label>
|
| 882 |
+
Infra
|
| 883 |
+
<select
|
| 884 |
+
value={form.infra ?? ""}
|
| 885 |
+
onChange={(event) => updateField("infra", event.target.value || null)}
|
| 886 |
+
>
|
| 887 |
+
<option value="">Selecione</option>
|
| 888 |
+
<option value="Minima">Minima</option>
|
| 889 |
+
<option value="Basica">Basica</option>
|
| 890 |
+
<option value="Intermediaria">Intermediaria</option>
|
| 891 |
+
<option value="Completa">Completa</option>
|
| 892 |
+
</select>
|
| 893 |
+
</label>
|
| 894 |
+
<button
|
| 895 |
+
type="button"
|
| 896 |
+
className="secondary classify-btn"
|
| 897 |
+
onClick={() => setActiveClassifier("infra")}
|
| 898 |
+
>
|
| 899 |
+
Classificar
|
| 900 |
+
</button>
|
| 901 |
+
</div>
|
| 902 |
+
|
| 903 |
+
<div className="classification-row">
|
| 904 |
+
<label>
|
| 905 |
+
Padrao
|
| 906 |
+
<select
|
| 907 |
+
value={form.padrao ?? ""}
|
| 908 |
+
onChange={(event) => updateField("padrao", event.target.value || null)}
|
| 909 |
+
>
|
| 910 |
+
<option value="">Selecione</option>
|
| 911 |
+
<option value="Baixo">Baixo</option>
|
| 912 |
+
<option value="Normal">Normal</option>
|
| 913 |
+
<option value="Normal/Alto">Normal/Alto</option>
|
| 914 |
+
<option value="Alto">Alto</option>
|
| 915 |
+
</select>
|
| 916 |
+
</label>
|
| 917 |
+
<button
|
| 918 |
+
type="button"
|
| 919 |
+
className="secondary classify-btn"
|
| 920 |
+
onClick={() => setActiveClassifier("padrao")}
|
| 921 |
+
>
|
| 922 |
+
Classificar
|
| 923 |
+
</button>
|
| 924 |
+
</div>
|
| 925 |
+
|
| 926 |
+
<div className="classification-row">
|
| 927 |
+
<label>
|
| 928 |
+
Conservacao
|
| 929 |
+
<select
|
| 930 |
+
value={form.conservacao ?? ""}
|
| 931 |
+
onChange={(event) =>
|
| 932 |
+
updateField("conservacao", event.target.value || null)
|
| 933 |
+
}
|
| 934 |
+
>
|
| 935 |
+
<option value="">Selecione</option>
|
| 936 |
+
{CONSERVACAO_OPTIONS.map((option) => (
|
| 937 |
+
<option key={option.categoria} value={option.categoria}>
|
| 938 |
+
{option.categoria}
|
| 939 |
+
</option>
|
| 940 |
+
))}
|
| 941 |
+
</select>
|
| 942 |
+
</label>
|
| 943 |
+
<button
|
| 944 |
+
type="button"
|
| 945 |
+
className="secondary classify-btn"
|
| 946 |
+
onClick={() => setActiveClassifier("conservacao")}
|
| 947 |
+
>
|
| 948 |
+
Classificar
|
| 949 |
+
</button>
|
| 950 |
+
</div>
|
| 951 |
+
|
| 952 |
+
<div className="classification-row">
|
| 953 |
+
<label>
|
| 954 |
+
Vaga
|
| 955 |
+
<select
|
| 956 |
+
value={form.vaga ?? ""}
|
| 957 |
+
onChange={(event) => updateField("vaga", event.target.value || null)}
|
| 958 |
+
>
|
| 959 |
+
<option value="">Selecione</option>
|
| 960 |
+
<option value="Sim">Sim</option>
|
| 961 |
+
<option value="Nao - facilidade de estacionamento">
|
| 962 |
+
Nao - facilidade de estacionamento
|
| 963 |
+
</option>
|
| 964 |
+
<option value="Nao - dificuldade de estacionamento">
|
| 965 |
+
Nao - dificuldade de estacionamento
|
| 966 |
+
</option>
|
| 967 |
+
</select>
|
| 968 |
+
</label>
|
| 969 |
+
<button
|
| 970 |
+
type="button"
|
| 971 |
+
className="secondary classify-btn"
|
| 972 |
+
onClick={() => setActiveClassifier("vaga")}
|
| 973 |
+
>
|
| 974 |
+
Classificar
|
| 975 |
+
</button>
|
| 976 |
+
</div>
|
| 977 |
+
</div>
|
| 978 |
+
|
| 979 |
+
<div className="criteria-panel">
|
| 980 |
+
<div className="criteria-head">
|
| 981 |
+
<strong>{activeGuide.titulo}</strong>
|
| 982 |
+
<span>{activeGuide.descricao}</span>
|
| 983 |
+
<span className="criteria-status">{activeGuide.status}</span>
|
| 984 |
+
</div>
|
| 985 |
+
<div className="criteria-grid">
|
| 986 |
+
{activeGuide.blocos.map((bloco) => (
|
| 987 |
+
(() => {
|
| 988 |
+
const blocoValor = "valor" in bloco ? bloco.valor : undefined;
|
| 989 |
+
return (
|
| 990 |
+
<button
|
| 991 |
+
key={bloco.titulo}
|
| 992 |
+
type="button"
|
| 993 |
+
className={`criteria-card${
|
| 994 |
+
blocoValor &&
|
| 995 |
+
((activeClassifier === "conservacao" &&
|
| 996 |
+
form.conservacao === blocoValor) ||
|
| 997 |
+
(activeClassifier === "vaga" && form.vaga === blocoValor))
|
| 998 |
+
? " is-selected"
|
| 999 |
+
: ""
|
| 1000 |
+
}`}
|
| 1001 |
+
onClick={() => {
|
| 1002 |
+
if (!blocoValor) {
|
| 1003 |
+
return;
|
| 1004 |
+
}
|
| 1005 |
+
if (activeClassifier === "conservacao") {
|
| 1006 |
+
updateField("conservacao", blocoValor);
|
| 1007 |
+
}
|
| 1008 |
+
if (activeClassifier === "vaga") {
|
| 1009 |
+
updateField("vaga", blocoValor);
|
| 1010 |
+
}
|
| 1011 |
+
}}
|
| 1012 |
+
>
|
| 1013 |
+
<strong>{bloco.titulo}</strong>
|
| 1014 |
+
<ul>
|
| 1015 |
+
{bloco.itens.map((item) => (
|
| 1016 |
+
<li key={item}>{item}</li>
|
| 1017 |
+
))}
|
| 1018 |
+
</ul>
|
| 1019 |
+
</button>
|
| 1020 |
+
);
|
| 1021 |
+
})()
|
| 1022 |
+
))}
|
| 1023 |
+
</div>
|
| 1024 |
+
</div>
|
| 1025 |
+
</div>
|
| 1026 |
+
</div>
|
| 1027 |
+
) : null}
|
| 1028 |
+
</section>
|
| 1029 |
+
|
| 1030 |
+
<div className="form-actions form-actions-outside">
|
| 1031 |
+
<button type="submit">Salvar registro</button>
|
| 1032 |
+
</div>
|
| 1033 |
+
</form>
|
| 1034 |
+
|
| 1035 |
+
<section className="panel sequence-panel full-width">
|
| 1036 |
+
<div className="sequence-head">
|
| 1037 |
+
<div className="sequence-index">05</div>
|
| 1038 |
+
<div>
|
| 1039 |
+
<p className="sequence-kicker">Base consolidada</p>
|
| 1040 |
+
<h2>Banco de dados</h2>
|
| 1041 |
+
</div>
|
| 1042 |
+
<button
|
| 1043 |
+
type="button"
|
| 1044 |
+
className="collapse-btn secondary"
|
| 1045 |
+
onClick={() => toggleSection("tabela")}
|
| 1046 |
+
>
|
| 1047 |
+
{openSections.tabela ? "Recolher" : "Expandir"}
|
| 1048 |
+
</button>
|
| 1049 |
+
</div>
|
| 1050 |
+
{openSections.tabela ? (
|
| 1051 |
+
<div className="section-body">
|
| 1052 |
+
<div className="section-head">
|
| 1053 |
+
<h2>Tabela final</h2>
|
| 1054 |
+
<div className="actions">
|
| 1055 |
+
<button type="button" className="secondary" onClick={() => void loadProperties()}>
|
| 1056 |
+
Atualizar
|
| 1057 |
+
</button>
|
| 1058 |
+
<button type="button" className="secondary" onClick={handleExport}>
|
| 1059 |
+
Exportar planilha
|
| 1060 |
+
</button>
|
| 1061 |
+
</div>
|
| 1062 |
+
</div>
|
| 1063 |
+
|
| 1064 |
+
{loading ? <p className="muted">Carregando...</p> : null}
|
| 1065 |
+
{message ? <p className="success">{message}</p> : null}
|
| 1066 |
+
{error ? <p className="error">{error}</p> : null}
|
| 1067 |
+
|
| 1068 |
+
<div className="table-wrap">
|
| 1069 |
+
<table>
|
| 1070 |
+
<thead>
|
| 1071 |
+
<tr>
|
| 1072 |
+
<th>ID</th>
|
| 1073 |
+
<th>Inscricao(s)</th>
|
| 1074 |
+
<th>Endereco</th>
|
| 1075 |
+
<th>Cadastro</th>
|
| 1076 |
+
<th>Oferta</th>
|
| 1077 |
+
<th>Outras caracteristicas</th>
|
| 1078 |
+
<th>Acao</th>
|
| 1079 |
+
</tr>
|
| 1080 |
+
</thead>
|
| 1081 |
+
<tbody>
|
| 1082 |
+
{properties.length === 0 ? (
|
| 1083 |
+
<tr>
|
| 1084 |
+
<td colSpan={7} className="empty-cell">
|
| 1085 |
+
Nenhum registro salvo.
|
| 1086 |
+
</td>
|
| 1087 |
+
</tr>
|
| 1088 |
+
) : (
|
| 1089 |
+
properties.map((property) => (
|
| 1090 |
+
<tr key={property.id}>
|
| 1091 |
+
<td>{property.id}</td>
|
| 1092 |
+
<td>{property.num_inscricao ?? "-"}</td>
|
| 1093 |
+
<td>
|
| 1094 |
+
{[property.nme_endloc_logradouro, property.num_endloc_endereco]
|
| 1095 |
+
.filter(Boolean)
|
| 1096 |
+
.join(", ")}
|
| 1097 |
+
{property.num_endloc_unidade ? ` / ${property.num_endloc_unidade}` : ""}
|
| 1098 |
+
{!property.nme_endloc_logradouro && !property.num_endloc_endereco
|
| 1099 |
+
? "-"
|
| 1100 |
+
: ""}
|
| 1101 |
+
</td>
|
| 1102 |
+
<td>
|
| 1103 |
+
{[
|
| 1104 |
+
`Finalidade: ${property.finalidade ?? "-"}`,
|
| 1105 |
+
`Area total: ${property.area_total_detalhe ?? "-"} | Soma: ${
|
| 1106 |
+
property.area_total ?? "-"
|
| 1107 |
+
}`,
|
| 1108 |
+
`Area privativa: ${property.area_privativa_detalhe ?? "-"} | Soma: ${
|
| 1109 |
+
property.area_privativa ?? "-"
|
| 1110 |
+
}`,
|
| 1111 |
+
`Bairro: ${property.nme_endloc_bairro_cdl ?? "-"}`,
|
| 1112 |
+
].join(" | ")}
|
| 1113 |
+
</td>
|
| 1114 |
+
<td>
|
| 1115 |
+
{[
|
| 1116 |
+
`Finalidade: ${property.finalidade_oferta ?? "-"}`,
|
| 1117 |
+
`Valor: ${property.valor_oferta ?? "-"}`,
|
| 1118 |
+
`Imobiliaria: ${property.imobiliaria ?? "-"}`,
|
| 1119 |
+
`Codigo: ${property.codigo ?? "-"}`,
|
| 1120 |
+
].join(" | ")}
|
| 1121 |
+
</td>
|
| 1122 |
+
<td>
|
| 1123 |
+
{[
|
| 1124 |
+
`Infra: ${property.infra ?? "-"}`,
|
| 1125 |
+
`Padrao: ${property.padrao ?? "-"}`,
|
| 1126 |
+
`Conservacao: ${property.conservacao ?? "-"}`,
|
| 1127 |
+
`Vaga: ${property.vaga ?? "-"}`,
|
| 1128 |
+
].join(" | ")}
|
| 1129 |
+
</td>
|
| 1130 |
+
<td className="action-cell">
|
| 1131 |
+
{deleteTarget === property.id ? (
|
| 1132 |
+
<div className="delete-confirm">
|
| 1133 |
+
<button
|
| 1134 |
+
type="button"
|
| 1135 |
+
className="secondary danger-soft"
|
| 1136 |
+
onClick={() => void handleDelete(property.id)}
|
| 1137 |
+
>
|
| 1138 |
+
Confirmar
|
| 1139 |
+
</button>
|
| 1140 |
+
<button
|
| 1141 |
+
type="button"
|
| 1142 |
+
className="secondary"
|
| 1143 |
+
onClick={() => setDeleteTarget(null)}
|
| 1144 |
+
>
|
| 1145 |
+
Cancelar
|
| 1146 |
+
</button>
|
| 1147 |
+
</div>
|
| 1148 |
+
) : (
|
| 1149 |
+
<button
|
| 1150 |
+
type="button"
|
| 1151 |
+
className="secondary danger-soft"
|
| 1152 |
+
onClick={() => setDeleteTarget(property.id)}
|
| 1153 |
+
>
|
| 1154 |
+
Excluir
|
| 1155 |
+
</button>
|
| 1156 |
+
)}
|
| 1157 |
+
</td>
|
| 1158 |
+
</tr>
|
| 1159 |
+
))
|
| 1160 |
+
)}
|
| 1161 |
+
</tbody>
|
| 1162 |
+
</table>
|
| 1163 |
+
</div>
|
| 1164 |
+
</div>
|
| 1165 |
+
) : null}
|
| 1166 |
+
</section>
|
| 1167 |
+
</main>
|
| 1168 |
+
</div>
|
| 1169 |
+
);
|
| 1170 |
+
}
|
| 1171 |
+
|
| 1172 |
+
export default App;
|
frontend/src/api.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import type {
|
| 2 |
+
CadastroBaseSearchResponse,
|
| 3 |
+
Property,
|
| 4 |
+
PropertyDraft,
|
| 5 |
+
SpreadsheetPreview
|
| 6 |
+
} from "./types";
|
| 7 |
+
|
| 8 |
+
const API_URL = window.location.port === "5173" ? "http://localhost:8001" : "";
|
| 9 |
+
|
| 10 |
+
export async function fetchProperties(): Promise<Property[]> {
|
| 11 |
+
const response = await fetch(`${API_URL}/properties`);
|
| 12 |
+
if (!response.ok) {
|
| 13 |
+
throw new Error("Falha ao carregar imoveis.");
|
| 14 |
+
}
|
| 15 |
+
return response.json();
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
export async function createProperty(payload: PropertyDraft): Promise<Property> {
|
| 19 |
+
const response = await fetch(`${API_URL}/properties`, {
|
| 20 |
+
method: "POST",
|
| 21 |
+
headers: {
|
| 22 |
+
"Content-Type": "application/json"
|
| 23 |
+
},
|
| 24 |
+
body: JSON.stringify(payload)
|
| 25 |
+
});
|
| 26 |
+
|
| 27 |
+
if (!response.ok) {
|
| 28 |
+
const errorText = await response.text();
|
| 29 |
+
throw new Error(errorText || "Falha ao salvar imovel.");
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
return response.json();
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
export async function deleteProperty(propertyId: number): Promise<void> {
|
| 36 |
+
const response = await fetch(`${API_URL}/properties/${propertyId}`, {
|
| 37 |
+
method: "DELETE"
|
| 38 |
+
});
|
| 39 |
+
|
| 40 |
+
if (!response.ok) {
|
| 41 |
+
throw new Error("Falha ao excluir registro.");
|
| 42 |
+
}
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
export async function previewSpreadsheet(file: File): Promise<SpreadsheetPreview> {
|
| 46 |
+
const formData = new FormData();
|
| 47 |
+
formData.append("file", file);
|
| 48 |
+
|
| 49 |
+
const response = await fetch(`${API_URL}/properties/import-preview`, {
|
| 50 |
+
method: "POST",
|
| 51 |
+
body: formData
|
| 52 |
+
});
|
| 53 |
+
|
| 54 |
+
if (!response.ok) {
|
| 55 |
+
const errorText = await response.text();
|
| 56 |
+
throw new Error(errorText || "Falha ao ler planilha.");
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
return response.json();
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
export async function searchCadastroBase(
|
| 63 |
+
mode: "inscricao" | "endereco",
|
| 64 |
+
query: string
|
| 65 |
+
): Promise<CadastroBaseSearchResponse> {
|
| 66 |
+
const params = new URLSearchParams({ mode, q: query, limit: "20" });
|
| 67 |
+
const response = await fetch(`${API_URL}/cadastro-base/search?${params.toString()}`);
|
| 68 |
+
|
| 69 |
+
if (!response.ok) {
|
| 70 |
+
const errorText = await response.text();
|
| 71 |
+
throw new Error(errorText || "Falha ao consultar base cadastral.");
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
return response.json();
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
export function getExportUrl(): string {
|
| 78 |
+
return `${API_URL}/properties/export`;
|
| 79 |
+
}
|
frontend/src/assets/cdA_logo.png
ADDED
|
Git LFS Details
|
frontend/src/assets/cdA_logo_transparent.png
ADDED
|
Git LFS Details
|
frontend/src/main.tsx
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React from "react";
|
| 2 |
+
import ReactDOM from "react-dom/client";
|
| 3 |
+
import App from "./App";
|
| 4 |
+
import "./styles.css";
|
| 5 |
+
|
| 6 |
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
| 7 |
+
<React.StrictMode>
|
| 8 |
+
<App />
|
| 9 |
+
</React.StrictMode>
|
| 10 |
+
);
|
| 11 |
+
|
frontend/src/styles.css
ADDED
|
@@ -0,0 +1,789 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@import url("https://fonts.googleapis.com/css2?family=Sora:wght@500;600;700;800&family=Nunito+Sans:wght@400;600;700&family=JetBrains+Mono:wght@500;700&display=swap");
|
| 2 |
+
|
| 3 |
+
:root {
|
| 4 |
+
color-scheme: light;
|
| 5 |
+
font-family: "Nunito Sans", sans-serif;
|
| 6 |
+
--bg-0: #f4f6f8;
|
| 7 |
+
--bg-1: #edf2f6;
|
| 8 |
+
--bg-2: #ffffff;
|
| 9 |
+
--ink-0: #161c24;
|
| 10 |
+
--ink-1: #2f3b4a;
|
| 11 |
+
--ink-2: #5a6b7c;
|
| 12 |
+
--accent: #ff8c00;
|
| 13 |
+
--accent-strong: #e67900;
|
| 14 |
+
--accent-soft: #fff2df;
|
| 15 |
+
--support: #2f80cf;
|
| 16 |
+
--support-soft: #edf5ff;
|
| 17 |
+
--ok: #1e8e49;
|
| 18 |
+
--danger: #b42318;
|
| 19 |
+
--border: #d4dde6;
|
| 20 |
+
--border-soft: #e6edf3;
|
| 21 |
+
--shadow-sm: 0 3px 10px rgba(20, 28, 36, 0.06);
|
| 22 |
+
--shadow-md: 0 10px 26px rgba(20, 28, 36, 0.1);
|
| 23 |
+
--radius-lg: 16px;
|
| 24 |
+
--radius-md: 12px;
|
| 25 |
+
--radius-sm: 9px;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
* {
|
| 29 |
+
box-sizing: border-box;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
html,
|
| 33 |
+
body,
|
| 34 |
+
#root {
|
| 35 |
+
min-height: 100%;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
body {
|
| 39 |
+
margin: 0;
|
| 40 |
+
min-width: 320px;
|
| 41 |
+
color: var(--ink-0);
|
| 42 |
+
background:
|
| 43 |
+
radial-gradient(1000px 430px at -8% -12%, #ffe8cf 0%, transparent 62%),
|
| 44 |
+
radial-gradient(860px 360px at 105% 10%, #dbeaf6 0%, transparent 60%),
|
| 45 |
+
linear-gradient(180deg, var(--bg-1) 0%, var(--bg-0) 35%, #f8fafc 100%);
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
button,
|
| 49 |
+
input,
|
| 50 |
+
select,
|
| 51 |
+
textarea {
|
| 52 |
+
font: inherit;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
.page {
|
| 56 |
+
width: min(1500px, 95vw);
|
| 57 |
+
margin: 18px auto 40px;
|
| 58 |
+
padding: 0;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
.hero {
|
| 62 |
+
display: grid;
|
| 63 |
+
grid-template-columns: 1.65fr 0.95fr;
|
| 64 |
+
gap: 24px;
|
| 65 |
+
align-items: stretch;
|
| 66 |
+
margin-bottom: 24px;
|
| 67 |
+
border: 1px solid var(--border);
|
| 68 |
+
border-radius: var(--radius-lg);
|
| 69 |
+
background: linear-gradient(130deg, #fffdf9, #fff 55%, #f6fbff);
|
| 70 |
+
box-shadow: var(--shadow-md);
|
| 71 |
+
padding: 18px 22px;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
.hero.hero-logo-only {
|
| 75 |
+
display: grid;
|
| 76 |
+
grid-template-columns: minmax(260px, 360px) 1fr;
|
| 77 |
+
justify-content: flex-start;
|
| 78 |
+
align-items: center;
|
| 79 |
+
gap: 22px;
|
| 80 |
+
padding: 8px 18px;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
.hero-logo {
|
| 84 |
+
width: min(340px, 64vw);
|
| 85 |
+
height: auto;
|
| 86 |
+
object-fit: contain;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
.hero-search {
|
| 90 |
+
display: grid;
|
| 91 |
+
gap: 10px;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
.hero-search-head {
|
| 95 |
+
display: grid;
|
| 96 |
+
gap: 4px;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
.hero-search-head h2 {
|
| 100 |
+
margin: 0;
|
| 101 |
+
color: #2b4258;
|
| 102 |
+
font-family: "Sora", sans-serif;
|
| 103 |
+
font-size: 1rem;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
.hero-search-help {
|
| 107 |
+
margin: -2px 2px 0;
|
| 108 |
+
color: #5f758a;
|
| 109 |
+
font-size: 0.82rem;
|
| 110 |
+
line-height: 1.35;
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
.eyebrow {
|
| 114 |
+
margin: 0 0 12px;
|
| 115 |
+
color: #7d4b12;
|
| 116 |
+
font-size: 12px;
|
| 117 |
+
font-weight: 800;
|
| 118 |
+
letter-spacing: 0.12em;
|
| 119 |
+
text-transform: uppercase;
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
.hero h1 {
|
| 123 |
+
margin: 0 0 14px;
|
| 124 |
+
color: var(--ink-0);
|
| 125 |
+
font-family: "Sora", sans-serif;
|
| 126 |
+
font-size: clamp(2rem, 3vw, 3.55rem);
|
| 127 |
+
line-height: 1.02;
|
| 128 |
+
letter-spacing: 0.01em;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
.lead {
|
| 132 |
+
max-width: 72ch;
|
| 133 |
+
margin: 0;
|
| 134 |
+
color: var(--ink-2);
|
| 135 |
+
font-size: 1.02rem;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
.hero-notes {
|
| 139 |
+
display: flex;
|
| 140 |
+
gap: 10px;
|
| 141 |
+
flex-wrap: wrap;
|
| 142 |
+
margin-top: 18px;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
.hero-chip {
|
| 146 |
+
display: inline-flex;
|
| 147 |
+
align-items: center;
|
| 148 |
+
min-height: 32px;
|
| 149 |
+
padding: 6px 11px;
|
| 150 |
+
border: 1px solid #f2cb8f;
|
| 151 |
+
border-radius: 999px;
|
| 152 |
+
background: #fff6e8;
|
| 153 |
+
color: #8a5a15;
|
| 154 |
+
font-size: 0.78rem;
|
| 155 |
+
font-weight: 700;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
.status-card,
|
| 159 |
+
.panel {
|
| 160 |
+
border: 1px solid var(--border);
|
| 161 |
+
border-radius: var(--radius-lg);
|
| 162 |
+
background: rgba(255, 255, 255, 0.92);
|
| 163 |
+
box-shadow: var(--shadow-sm);
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
.status-card {
|
| 167 |
+
display: grid;
|
| 168 |
+
gap: 8px;
|
| 169 |
+
align-content: center;
|
| 170 |
+
padding: 24px;
|
| 171 |
+
background: linear-gradient(180deg, #fff, #f8fbff);
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
.status-card span {
|
| 175 |
+
color: var(--ink-2);
|
| 176 |
+
font-size: 0.78rem;
|
| 177 |
+
font-weight: 800;
|
| 178 |
+
letter-spacing: 0.08em;
|
| 179 |
+
text-transform: uppercase;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
.status-card strong {
|
| 183 |
+
color: var(--ink-1);
|
| 184 |
+
font-family: "Sora", sans-serif;
|
| 185 |
+
font-size: 1.2rem;
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
.grid {
|
| 189 |
+
display: grid;
|
| 190 |
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
| 191 |
+
gap: 24px;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
.sequence {
|
| 195 |
+
display: grid;
|
| 196 |
+
gap: 24px;
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
.sequence-form {
|
| 200 |
+
display: grid;
|
| 201 |
+
gap: 24px;
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
.panel {
|
| 205 |
+
padding: 24px;
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
.panel h2 {
|
| 209 |
+
margin: 0 0 10px;
|
| 210 |
+
color: #2b4258;
|
| 211 |
+
font-family: "Sora", sans-serif;
|
| 212 |
+
font-size: 1.05rem;
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
.sequence-panel {
|
| 216 |
+
position: relative;
|
| 217 |
+
overflow: hidden;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
.sequence-panel::before {
|
| 221 |
+
content: "";
|
| 222 |
+
position: absolute;
|
| 223 |
+
inset: 0 auto 0 0;
|
| 224 |
+
display: block;
|
| 225 |
+
width: 4px;
|
| 226 |
+
background: linear-gradient(180deg, var(--support), var(--accent));
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
.sequence-panel > * {
|
| 230 |
+
position: relative;
|
| 231 |
+
z-index: 1;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
.sequence-head {
|
| 235 |
+
position: relative;
|
| 236 |
+
z-index: 1;
|
| 237 |
+
display: grid;
|
| 238 |
+
grid-template-columns: 58px 1fr auto;
|
| 239 |
+
gap: 14px;
|
| 240 |
+
align-items: start;
|
| 241 |
+
margin-bottom: 18px;
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
.sequence-head h2 {
|
| 245 |
+
margin: 2px 0 0;
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
.sequence-index {
|
| 249 |
+
display: grid;
|
| 250 |
+
place-items: center;
|
| 251 |
+
width: 42px;
|
| 252 |
+
height: 42px;
|
| 253 |
+
border-radius: 999px;
|
| 254 |
+
border: 1px solid #f2cb8f;
|
| 255 |
+
background: linear-gradient(180deg, #ffb14d, #e67900);
|
| 256 |
+
color: #fff;
|
| 257 |
+
font-family: "Sora", sans-serif;
|
| 258 |
+
font-size: 0.9rem;
|
| 259 |
+
font-weight: 800;
|
| 260 |
+
box-shadow: 0 10px 22px rgba(230, 121, 0, 0.22);
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
.sequence-kicker {
|
| 264 |
+
margin: 0;
|
| 265 |
+
color: #7d4b12;
|
| 266 |
+
font-size: 0.76rem;
|
| 267 |
+
font-weight: 800;
|
| 268 |
+
letter-spacing: 0.08em;
|
| 269 |
+
text-transform: uppercase;
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
.section-body {
|
| 273 |
+
position: relative;
|
| 274 |
+
z-index: 1;
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
.full-width,
|
| 278 |
+
.full {
|
| 279 |
+
grid-column: 1 / -1;
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
.form-grid {
|
| 283 |
+
display: grid;
|
| 284 |
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
| 285 |
+
gap: 16px;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
.cadastro-grid {
|
| 289 |
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
.text-half {
|
| 293 |
+
grid-column: span 1;
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
.offer-text-pair {
|
| 297 |
+
grid-column: span 1;
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
.offer-grid {
|
| 301 |
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
.offer-wide {
|
| 305 |
+
grid-column: span 2;
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
.search-bar {
|
| 309 |
+
display: grid;
|
| 310 |
+
grid-template-columns: 280px 1fr 140px;
|
| 311 |
+
gap: 12px;
|
| 312 |
+
align-items: center;
|
| 313 |
+
padding: 12px;
|
| 314 |
+
border: 1px solid #dbe6f1;
|
| 315 |
+
border-radius: 14px;
|
| 316 |
+
background: linear-gradient(180deg, #fff, #f9fbfe);
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
.result-list {
|
| 320 |
+
display: grid;
|
| 321 |
+
gap: 12px;
|
| 322 |
+
margin-top: 18px;
|
| 323 |
+
max-height: 360px;
|
| 324 |
+
overflow: auto;
|
| 325 |
+
padding-right: 2px;
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
.result-card {
|
| 329 |
+
border: 1px solid #d2deea;
|
| 330 |
+
border-radius: 10px;
|
| 331 |
+
background: linear-gradient(180deg, #f7fbff, #edf3fa);
|
| 332 |
+
color: #32475d;
|
| 333 |
+
text-align: left;
|
| 334 |
+
box-shadow: none;
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
.result-card strong {
|
| 338 |
+
font-family: "Sora", sans-serif;
|
| 339 |
+
font-size: 0.92rem;
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
.result-card span {
|
| 343 |
+
display: block;
|
| 344 |
+
margin-top: 6px;
|
| 345 |
+
color: #5f758a;
|
| 346 |
+
font-weight: 400;
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
.result-line {
|
| 350 |
+
font-size: 0.88rem;
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
.selected-cadastros {
|
| 354 |
+
margin-bottom: 18px;
|
| 355 |
+
padding: 14px;
|
| 356 |
+
border: 1px solid #dbe6f1;
|
| 357 |
+
border-radius: 10px;
|
| 358 |
+
background: #f8fbfe;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
.selected-cadastros-head,
|
| 362 |
+
.selected-cadastro-item {
|
| 363 |
+
display: flex;
|
| 364 |
+
align-items: center;
|
| 365 |
+
justify-content: space-between;
|
| 366 |
+
gap: 12px;
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
.selected-cadastros-head {
|
| 370 |
+
margin-bottom: 10px;
|
| 371 |
+
color: #39536d;
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
.selected-cadastros-head span {
|
| 375 |
+
color: #66788a;
|
| 376 |
+
font-size: 0.86rem;
|
| 377 |
+
font-weight: 700;
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
.selected-cadastro-list {
|
| 381 |
+
display: grid;
|
| 382 |
+
gap: 10px;
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
.selected-cadastro-item {
|
| 386 |
+
padding: 10px 12px;
|
| 387 |
+
border: 1px solid #d6e2ec;
|
| 388 |
+
border-radius: 8px;
|
| 389 |
+
background: #fff;
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
.selected-cadastro-item div {
|
| 393 |
+
display: grid;
|
| 394 |
+
gap: 4px;
|
| 395 |
+
min-width: 0;
|
| 396 |
+
}
|
| 397 |
+
|
| 398 |
+
.selected-cadastro-item span {
|
| 399 |
+
color: #66788a;
|
| 400 |
+
font-size: 0.86rem;
|
| 401 |
+
overflow-wrap: anywhere;
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
.selected-cadastro-item button {
|
| 405 |
+
max-width: 120px;
|
| 406 |
+
flex: 0 0 120px;
|
| 407 |
+
}
|
| 408 |
+
|
| 409 |
+
label {
|
| 410 |
+
display: grid;
|
| 411 |
+
gap: 8px;
|
| 412 |
+
color: #39536d;
|
| 413 |
+
font-size: 0.9rem;
|
| 414 |
+
font-weight: 700;
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
input,
|
| 418 |
+
select,
|
| 419 |
+
textarea,
|
| 420 |
+
button {
|
| 421 |
+
width: 100%;
|
| 422 |
+
border-radius: 10px;
|
| 423 |
+
border: 1px solid #d6e2ec;
|
| 424 |
+
padding: 12px 14px;
|
| 425 |
+
background: #fff;
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
input,
|
| 429 |
+
select,
|
| 430 |
+
textarea {
|
| 431 |
+
color: #314b64;
|
| 432 |
+
}
|
| 433 |
+
|
| 434 |
+
input:focus,
|
| 435 |
+
select:focus,
|
| 436 |
+
textarea:focus {
|
| 437 |
+
outline: 2px solid rgba(255, 140, 0, 0.2);
|
| 438 |
+
border-color: #ffba66;
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
textarea {
|
| 442 |
+
resize: vertical;
|
| 443 |
+
min-height: 106px;
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
button {
|
| 447 |
+
cursor: pointer;
|
| 448 |
+
border: 1px solid var(--accent-strong);
|
| 449 |
+
background: linear-gradient(180deg, var(--accent) 0%, var(--accent-strong) 100%);
|
| 450 |
+
color: #fff;
|
| 451 |
+
font-weight: 700;
|
| 452 |
+
box-shadow:
|
| 453 |
+
0 8px 18px rgba(230, 121, 0, 0.22),
|
| 454 |
+
inset 0 0 0 1px rgba(255, 255, 255, 0.15);
|
| 455 |
+
transition:
|
| 456 |
+
transform 0.18s ease,
|
| 457 |
+
box-shadow 0.18s ease,
|
| 458 |
+
border-color 0.18s ease;
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
button:hover {
|
| 462 |
+
transform: translateY(-1px);
|
| 463 |
+
box-shadow:
|
| 464 |
+
0 10px 22px rgba(230, 121, 0, 0.28),
|
| 465 |
+
inset 0 0 0 1px rgba(255, 255, 255, 0.18);
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
button.secondary {
|
| 469 |
+
width: auto;
|
| 470 |
+
border-color: #c8d8e8;
|
| 471 |
+
background: linear-gradient(180deg, #f7fbff, #edf3fa);
|
| 472 |
+
color: #355370;
|
| 473 |
+
box-shadow:
|
| 474 |
+
0 5px 14px rgba(53, 83, 114, 0.1),
|
| 475 |
+
inset 0 0 0 1px rgba(255, 255, 255, 0.22);
|
| 476 |
+
}
|
| 477 |
+
|
| 478 |
+
.section-head {
|
| 479 |
+
display: flex;
|
| 480 |
+
align-items: center;
|
| 481 |
+
justify-content: space-between;
|
| 482 |
+
gap: 16px;
|
| 483 |
+
}
|
| 484 |
+
|
| 485 |
+
.search-help {
|
| 486 |
+
margin: 12px 2px 0;
|
| 487 |
+
color: #5f758a;
|
| 488 |
+
font-size: 0.83rem;
|
| 489 |
+
}
|
| 490 |
+
|
| 491 |
+
.collapse-btn {
|
| 492 |
+
min-width: 110px;
|
| 493 |
+
align-self: center;
|
| 494 |
+
justify-self: end;
|
| 495 |
+
}
|
| 496 |
+
|
| 497 |
+
.form-actions {
|
| 498 |
+
position: relative;
|
| 499 |
+
z-index: 1;
|
| 500 |
+
display: flex;
|
| 501 |
+
justify-content: flex-end;
|
| 502 |
+
}
|
| 503 |
+
|
| 504 |
+
.form-actions-outside {
|
| 505 |
+
margin-top: -6px;
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
.actions {
|
| 509 |
+
display: flex;
|
| 510 |
+
gap: 12px;
|
| 511 |
+
flex-wrap: wrap;
|
| 512 |
+
}
|
| 513 |
+
|
| 514 |
+
.muted {
|
| 515 |
+
color: var(--ink-2);
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
.success {
|
| 519 |
+
color: var(--ok);
|
| 520 |
+
font-weight: 700;
|
| 521 |
+
padding: 8px 10px;
|
| 522 |
+
border-radius: 10px;
|
| 523 |
+
background: #eefaf1;
|
| 524 |
+
border: 1px solid #cbead5;
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
.error {
|
| 528 |
+
color: var(--danger);
|
| 529 |
+
font-weight: 700;
|
| 530 |
+
padding: 8px 10px;
|
| 531 |
+
border-radius: 10px;
|
| 532 |
+
background: #fef0ef;
|
| 533 |
+
border: 1px solid #f7c0bc;
|
| 534 |
+
}
|
| 535 |
+
|
| 536 |
+
.empty-state,
|
| 537 |
+
.empty-cell {
|
| 538 |
+
color: var(--ink-2);
|
| 539 |
+
text-align: center;
|
| 540 |
+
padding: 24px;
|
| 541 |
+
border: 1px dashed var(--border);
|
| 542 |
+
border-radius: 10px;
|
| 543 |
+
background: linear-gradient(180deg, #fbfdff, #f5f9fd);
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
.form-banner {
|
| 547 |
+
margin-bottom: 16px;
|
| 548 |
+
padding: 10px 12px;
|
| 549 |
+
border: 1px solid #dbe6f0;
|
| 550 |
+
border-radius: 12px;
|
| 551 |
+
background: linear-gradient(180deg, #fff, #f8fbff);
|
| 552 |
+
color: #4d6379;
|
| 553 |
+
font-size: 0.88rem;
|
| 554 |
+
line-height: 1.45;
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
.criteria-panel {
|
| 558 |
+
padding: 14px;
|
| 559 |
+
border: 1px solid #dbe6f0;
|
| 560 |
+
border-radius: 14px;
|
| 561 |
+
background: linear-gradient(180deg, #fcfdff, #f5f9fd);
|
| 562 |
+
}
|
| 563 |
+
|
| 564 |
+
.classification-layout {
|
| 565 |
+
display: grid;
|
| 566 |
+
grid-template-columns: minmax(320px, 0.95fr) minmax(0, 1.45fr);
|
| 567 |
+
gap: 18px;
|
| 568 |
+
align-items: start;
|
| 569 |
+
}
|
| 570 |
+
|
| 571 |
+
.classification-controls {
|
| 572 |
+
display: grid;
|
| 573 |
+
gap: 12px;
|
| 574 |
+
}
|
| 575 |
+
|
| 576 |
+
.classification-row {
|
| 577 |
+
display: grid;
|
| 578 |
+
grid-template-columns: minmax(0, 1fr) 120px;
|
| 579 |
+
gap: 10px;
|
| 580 |
+
align-items: end;
|
| 581 |
+
}
|
| 582 |
+
|
| 583 |
+
.classify-btn {
|
| 584 |
+
min-height: 46px;
|
| 585 |
+
}
|
| 586 |
+
|
| 587 |
+
.criteria-head {
|
| 588 |
+
display: grid;
|
| 589 |
+
gap: 4px;
|
| 590 |
+
margin-bottom: 12px;
|
| 591 |
+
}
|
| 592 |
+
|
| 593 |
+
.criteria-head strong {
|
| 594 |
+
color: #2f4a63;
|
| 595 |
+
font-family: "Sora", sans-serif;
|
| 596 |
+
font-size: 0.95rem;
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
.criteria-head span {
|
| 600 |
+
color: #5f758a;
|
| 601 |
+
font-size: 0.84rem;
|
| 602 |
+
}
|
| 603 |
+
|
| 604 |
+
.criteria-status {
|
| 605 |
+
display: inline-flex;
|
| 606 |
+
width: fit-content;
|
| 607 |
+
padding: 4px 8px;
|
| 608 |
+
border-radius: 999px;
|
| 609 |
+
background: #eef5ff;
|
| 610 |
+
color: #45627f !important;
|
| 611 |
+
font-size: 0.74rem !important;
|
| 612 |
+
font-weight: 800;
|
| 613 |
+
text-transform: uppercase;
|
| 614 |
+
letter-spacing: 0.04em;
|
| 615 |
+
}
|
| 616 |
+
|
| 617 |
+
.criteria-grid {
|
| 618 |
+
display: grid;
|
| 619 |
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
| 620 |
+
gap: 12px;
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
.criteria-card {
|
| 624 |
+
border: 1px solid #d2deea;
|
| 625 |
+
border-radius: 12px;
|
| 626 |
+
background: linear-gradient(180deg, #f8fbff, #edf3fa);
|
| 627 |
+
color: #32475d;
|
| 628 |
+
text-align: left;
|
| 629 |
+
box-shadow: none;
|
| 630 |
+
}
|
| 631 |
+
|
| 632 |
+
.criteria-card strong {
|
| 633 |
+
display: flex;
|
| 634 |
+
gap: 12px;
|
| 635 |
+
align-items: baseline;
|
| 636 |
+
font-family: "Sora", sans-serif;
|
| 637 |
+
font-size: 0.92rem;
|
| 638 |
+
}
|
| 639 |
+
|
| 640 |
+
.criteria-card strong span {
|
| 641 |
+
color: #6a8096;
|
| 642 |
+
font-family: "Nunito Sans", sans-serif;
|
| 643 |
+
font-size: 0.78rem;
|
| 644 |
+
font-weight: 700;
|
| 645 |
+
}
|
| 646 |
+
|
| 647 |
+
.criteria-card ul {
|
| 648 |
+
margin: 10px 0 0;
|
| 649 |
+
padding-left: 18px;
|
| 650 |
+
color: #52687d;
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
.criteria-card li + li {
|
| 654 |
+
margin-top: 6px;
|
| 655 |
+
}
|
| 656 |
+
|
| 657 |
+
.criteria-card.is-selected {
|
| 658 |
+
border-color: #ffb14d;
|
| 659 |
+
background: linear-gradient(180deg, #fff6e8, #ffefda);
|
| 660 |
+
box-shadow: 0 8px 20px rgba(230, 121, 0, 0.14);
|
| 661 |
+
}
|
| 662 |
+
|
| 663 |
+
.table-wrap {
|
| 664 |
+
overflow: auto;
|
| 665 |
+
margin-top: 16px;
|
| 666 |
+
border: 1px solid var(--border-soft);
|
| 667 |
+
border-radius: 16px;
|
| 668 |
+
background: #fff;
|
| 669 |
+
}
|
| 670 |
+
|
| 671 |
+
table {
|
| 672 |
+
width: 100%;
|
| 673 |
+
min-width: 720px;
|
| 674 |
+
border-collapse: collapse;
|
| 675 |
+
}
|
| 676 |
+
|
| 677 |
+
th,
|
| 678 |
+
td {
|
| 679 |
+
padding: 12px 14px;
|
| 680 |
+
border-bottom: 1px solid #e1e9f1;
|
| 681 |
+
text-align: left;
|
| 682 |
+
}
|
| 683 |
+
|
| 684 |
+
th {
|
| 685 |
+
background: #f7fbff;
|
| 686 |
+
color: #48627a;
|
| 687 |
+
font-family: "Sora", sans-serif;
|
| 688 |
+
font-size: 0.78rem;
|
| 689 |
+
letter-spacing: 0.04em;
|
| 690 |
+
text-transform: uppercase;
|
| 691 |
+
}
|
| 692 |
+
|
| 693 |
+
td {
|
| 694 |
+
color: #30475e;
|
| 695 |
+
vertical-align: top;
|
| 696 |
+
}
|
| 697 |
+
|
| 698 |
+
.action-cell {
|
| 699 |
+
min-width: 170px;
|
| 700 |
+
}
|
| 701 |
+
|
| 702 |
+
.delete-confirm {
|
| 703 |
+
display: flex;
|
| 704 |
+
gap: 8px;
|
| 705 |
+
flex-wrap: wrap;
|
| 706 |
+
}
|
| 707 |
+
|
| 708 |
+
.danger-soft {
|
| 709 |
+
border-color: #e3adb8 !important;
|
| 710 |
+
background: linear-gradient(180deg, #fff4f6, #fee9ed) !important;
|
| 711 |
+
color: #a63446 !important;
|
| 712 |
+
box-shadow:
|
| 713 |
+
0 5px 14px rgba(178, 47, 64, 0.1),
|
| 714 |
+
inset 0 0 0 1px rgba(255, 255, 255, 0.22) !important;
|
| 715 |
+
}
|
| 716 |
+
|
| 717 |
+
td:nth-child(1),
|
| 718 |
+
td:nth-child(3),
|
| 719 |
+
td:nth-child(4) {
|
| 720 |
+
font-family: "JetBrains Mono", monospace;
|
| 721 |
+
font-size: 0.82rem;
|
| 722 |
+
}
|
| 723 |
+
|
| 724 |
+
::-webkit-scrollbar {
|
| 725 |
+
width: 8px;
|
| 726 |
+
height: 8px;
|
| 727 |
+
}
|
| 728 |
+
|
| 729 |
+
::-webkit-scrollbar-thumb {
|
| 730 |
+
background: #c7d4e2;
|
| 731 |
+
border-radius: 999px;
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
::-webkit-scrollbar-track {
|
| 735 |
+
background: #eef3f8;
|
| 736 |
+
}
|
| 737 |
+
|
| 738 |
+
@media (max-width: 900px) {
|
| 739 |
+
.page {
|
| 740 |
+
width: 97vw;
|
| 741 |
+
margin-top: 10px;
|
| 742 |
+
}
|
| 743 |
+
|
| 744 |
+
.hero,
|
| 745 |
+
.grid,
|
| 746 |
+
.form-grid,
|
| 747 |
+
.search-bar {
|
| 748 |
+
grid-template-columns: 1fr;
|
| 749 |
+
}
|
| 750 |
+
|
| 751 |
+
.hero {
|
| 752 |
+
padding: 10px 14px;
|
| 753 |
+
}
|
| 754 |
+
|
| 755 |
+
.hero.hero-logo-only {
|
| 756 |
+
grid-template-columns: 1fr;
|
| 757 |
+
}
|
| 758 |
+
|
| 759 |
+
.section-head {
|
| 760 |
+
align-items: flex-start;
|
| 761 |
+
flex-wrap: wrap;
|
| 762 |
+
}
|
| 763 |
+
|
| 764 |
+
.sequence-head {
|
| 765 |
+
grid-template-columns: 42px 1fr;
|
| 766 |
+
}
|
| 767 |
+
|
| 768 |
+
.form-grid {
|
| 769 |
+
grid-template-columns: 1fr;
|
| 770 |
+
}
|
| 771 |
+
|
| 772 |
+
.offer-grid {
|
| 773 |
+
grid-template-columns: 1fr;
|
| 774 |
+
}
|
| 775 |
+
|
| 776 |
+
.offer-wide {
|
| 777 |
+
grid-column: span 1;
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
.classification-layout,
|
| 781 |
+
.classification-row,
|
| 782 |
+
.criteria-grid {
|
| 783 |
+
grid-template-columns: 1fr;
|
| 784 |
+
}
|
| 785 |
+
|
| 786 |
+
.classify-btn {
|
| 787 |
+
width: 100%;
|
| 788 |
+
}
|
| 789 |
+
}
|
frontend/src/types.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export type Property = {
|
| 2 |
+
id: number;
|
| 3 |
+
titulo: string | null;
|
| 4 |
+
finalidade: string;
|
| 5 |
+
num_bloco: string | null;
|
| 6 |
+
num_inscricao: string | null;
|
| 7 |
+
cod_endloc_logradouro: string | null;
|
| 8 |
+
nme_endloc_logradouro: string | null;
|
| 9 |
+
num_endloc_endereco: string | null;
|
| 10 |
+
num_endloc_unidade: string | null;
|
| 11 |
+
nme_endloc_bairro_cdl: string | null;
|
| 12 |
+
rh_nome: string | null;
|
| 13 |
+
rh_valor: number | null;
|
| 14 |
+
coord_x: number | null;
|
| 15 |
+
coord_y: number | null;
|
| 16 |
+
ano_exercicio: number | null;
|
| 17 |
+
num_versao: number | null;
|
| 18 |
+
idf_reg_regiao_homogenea: number | null;
|
| 19 |
+
area_total_detalhe: string | null;
|
| 20 |
+
area_total: number | null;
|
| 21 |
+
area_privativa_detalhe: string | null;
|
| 22 |
+
area_privativa: number | null;
|
| 23 |
+
finalidade_oferta: string | null;
|
| 24 |
+
area_total_oferta: number | null;
|
| 25 |
+
area_privativa_oferta: number | null;
|
| 26 |
+
valor_oferta: number | null;
|
| 27 |
+
latitude: number | null;
|
| 28 |
+
longitude: number | null;
|
| 29 |
+
descricao_oferta: string | null;
|
| 30 |
+
observacao: string | null;
|
| 31 |
+
url: string | null;
|
| 32 |
+
imobiliaria: string | null;
|
| 33 |
+
codigo: string | null;
|
| 34 |
+
infra: string | null;
|
| 35 |
+
padrao: string | null;
|
| 36 |
+
conservacao: string | null;
|
| 37 |
+
vaga: string | null;
|
| 38 |
+
origem: string;
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
export type PropertyDraft = Omit<Property, "id">;
|
| 42 |
+
|
| 43 |
+
export type SpreadsheetPreview = {
|
| 44 |
+
file_name: string;
|
| 45 |
+
columns: string[];
|
| 46 |
+
rows: Record<string, unknown>[];
|
| 47 |
+
total_rows: number;
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
export type CadastroBaseRecord = {
|
| 51 |
+
num_bloco: string | null;
|
| 52 |
+
num_inscricao: string;
|
| 53 |
+
cod_endloc_logradouro: string | null;
|
| 54 |
+
nme_endloc_logradouro: string | null;
|
| 55 |
+
num_endloc_endereco: string | null;
|
| 56 |
+
num_endloc_unidade: string | null;
|
| 57 |
+
nme_endloc_bairro_cdl: string | null;
|
| 58 |
+
des_finalidade: string | null;
|
| 59 |
+
rh_nome: string | null;
|
| 60 |
+
rh_valor: number | null;
|
| 61 |
+
coord_x: number | null;
|
| 62 |
+
coord_y: number | null;
|
| 63 |
+
ano_exercicio: number | null;
|
| 64 |
+
num_versao: number | null;
|
| 65 |
+
idf_reg_regiao_homogenea: number | null;
|
| 66 |
+
area_territorial: number | null;
|
| 67 |
+
area_construida: number | null;
|
| 68 |
+
latitude: number | null;
|
| 69 |
+
longitude: number | null;
|
| 70 |
+
titulo_sugerido: string;
|
| 71 |
+
display_label: string;
|
| 72 |
+
};
|
| 73 |
+
|
| 74 |
+
export type CadastroBaseSearchResponse = {
|
| 75 |
+
mode: string;
|
| 76 |
+
total: number;
|
| 77 |
+
items: CadastroBaseRecord[];
|
| 78 |
+
};
|
frontend/src/vite-env.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
/// <reference types="vite/client" />
|
frontend/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
"target": "ES2020",
|
| 4 |
+
"useDefineForClassFields": true,
|
| 5 |
+
"lib": ["DOM", "DOM.Iterable", "ES2020"],
|
| 6 |
+
"allowJs": false,
|
| 7 |
+
"skipLibCheck": true,
|
| 8 |
+
"esModuleInterop": true,
|
| 9 |
+
"allowSyntheticDefaultImports": true,
|
| 10 |
+
"strict": true,
|
| 11 |
+
"forceConsistentCasingInFileNames": true,
|
| 12 |
+
"module": "ESNext",
|
| 13 |
+
"moduleResolution": "Node",
|
| 14 |
+
"resolveJsonModule": true,
|
| 15 |
+
"isolatedModules": true,
|
| 16 |
+
"noEmit": true,
|
| 17 |
+
"jsx": "react-jsx"
|
| 18 |
+
},
|
| 19 |
+
"include": ["src"],
|
| 20 |
+
"references": []
|
| 21 |
+
}
|
| 22 |
+
|
frontend/vite.config.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { defineConfig } from "vite";
|
| 2 |
+
import react from "@vitejs/plugin-react";
|
| 3 |
+
|
| 4 |
+
export default defineConfig({
|
| 5 |
+
plugins: [react()],
|
| 6 |
+
server: {
|
| 7 |
+
host: "0.0.0.0",
|
| 8 |
+
port: 5173
|
| 9 |
+
}
|
| 10 |
+
});
|
| 11 |
+
|
run-dev.ps1
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
param(
|
| 2 |
+
[switch]$Install
|
| 3 |
+
)
|
| 4 |
+
|
| 5 |
+
$ErrorActionPreference = "Stop"
|
| 6 |
+
|
| 7 |
+
$Root = Split-Path -Parent $MyInvocation.MyCommand.Path
|
| 8 |
+
$BackendPath = Join-Path $Root "backend"
|
| 9 |
+
$FrontendPath = Join-Path $Root "frontend"
|
| 10 |
+
$VenvPath = Join-Path $BackendPath ".venv"
|
| 11 |
+
$PythonExe = Join-Path $VenvPath "Scripts\python.exe"
|
| 12 |
+
$PipExe = Join-Path $VenvPath "Scripts\pip.exe"
|
| 13 |
+
$PythonLauncher = "py -3.13"
|
| 14 |
+
|
| 15 |
+
function Ensure-Command($Name) {
|
| 16 |
+
if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) {
|
| 17 |
+
throw "Comando obrigatorio nao encontrado: $Name"
|
| 18 |
+
}
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
Ensure-Command py
|
| 22 |
+
Ensure-Command npm
|
| 23 |
+
|
| 24 |
+
if ($Install -and -not (Test-Path $PythonExe)) {
|
| 25 |
+
Write-Host "Criando ambiente virtual do backend..."
|
| 26 |
+
& py -3.13 -m venv $VenvPath
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
if ($Install) {
|
| 30 |
+
Write-Host "Instalando dependencias do backend..."
|
| 31 |
+
& $PythonExe -m pip install --upgrade pip
|
| 32 |
+
& $PipExe install -r (Join-Path $BackendPath "requirements.txt")
|
| 33 |
+
|
| 34 |
+
Write-Host "Instalando dependencias do frontend..."
|
| 35 |
+
Push-Location $FrontendPath
|
| 36 |
+
npm install
|
| 37 |
+
Pop-Location
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
if (-not (Test-Path $PythonExe)) {
|
| 41 |
+
throw "Ambiente virtual nao encontrado em backend\.venv. Rode .\run-dev.ps1 -Install"
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
if (-not (Test-Path (Join-Path $FrontendPath "node_modules"))) {
|
| 45 |
+
throw "Dependencias do frontend nao encontradas. Rode .\run-dev.ps1 -Install"
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
Write-Host "Subindo backend em http://localhost:8000 ..."
|
| 49 |
+
Start-Process powershell -ArgumentList "-NoExit", "-Command", "Set-Location '$BackendPath'; & '$PythonExe' -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000"
|
| 50 |
+
|
| 51 |
+
Write-Host "Subindo frontend em http://localhost:5173 ..."
|
| 52 |
+
Start-Process powershell -ArgumentList "-NoExit", "-Command", "Set-Location '$FrontendPath'; npm run dev -- --host 0.0.0.0 --port 5173"
|
| 53 |
+
|
| 54 |
+
Write-Host "Ambiente iniciado."
|
| 55 |
+
Write-Host "Frontend: http://localhost:5173"
|
| 56 |
+
Write-Host "Backend: http://localhost:8000"
|
| 57 |
+
Write-Host "Docs: http://localhost:8000/docs"
|