Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f113ae5b7c |
@@ -0,0 +1,17 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
ij_typescript_use_double_quotes = false
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/mcp.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
__screenshots__/
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.html",
|
||||
"options": {
|
||||
"parser": "angular"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||
"recommendations": ["angular.ng-template"]
|
||||
}
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ng serve",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: start",
|
||||
"url": "http://localhost:4200/"
|
||||
},
|
||||
{
|
||||
"name": "ng test",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: test",
|
||||
"url": "http://localhost:9876/debug.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
// For more information, visit: https://angular.dev/ai/mcp
|
||||
"servers": {
|
||||
"angular-cli": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@angular/cli", "mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "Changes detected"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation (complete|failed)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "Changes detected"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation (complete|failed)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -1,270 +1,59 @@
|
||||
# <div align="center">V-Aguatech – Automatic Technical Report Generator</div>
|
||||
# VAguatechAngular
|
||||
|
||||
---
|
||||
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.2.9.
|
||||
|
||||
## <div align="center">Overview</div>
|
||||
## Development server
|
||||
|
||||
V-Aguatech is a desktop application developed in Python for the automatic generation of technical inspection reports in Microsoft Word format.
|
||||
|
||||
The platform was designed to streamline field inspection workflows by allowing investigators and technicians to:
|
||||
|
||||
- Fill structured inspection data
|
||||
- Attach photographs
|
||||
- Document applied inspection techniques
|
||||
- Register participants during inspections
|
||||
- Automatically generate professional DOCX reports from templates
|
||||
|
||||
The application uses a dynamic Word template system with automatic placeholder replacement and image insertion.
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Main Features</div>
|
||||
|
||||
## Automatic DOCX Report Generation
|
||||
|
||||
- Dynamic placeholder replacement
|
||||
- Automatic generation of timestamped reports
|
||||
- Structured technical documentation
|
||||
|
||||
---
|
||||
|
||||
## Image Processing
|
||||
|
||||
- Single image insertion
|
||||
- Multiple image insertion
|
||||
- Automatic image conversion to PNG
|
||||
- Automatic image resizing inside reports
|
||||
|
||||
---
|
||||
|
||||
## Technical Inspection Management
|
||||
|
||||
The system allows the user to document:
|
||||
|
||||
- Visual inspection techniques
|
||||
- Humidity measurements
|
||||
- Thermal camera inspections
|
||||
- Endoscopic camera analysis
|
||||
- Pressure testing
|
||||
- Color dye testing
|
||||
- Obstruction testing
|
||||
|
||||
Each technique supports:
|
||||
- Description field
|
||||
- Multiple attached photographs
|
||||
|
||||
---
|
||||
|
||||
## Presence Registration
|
||||
|
||||
The application supports recording:
|
||||
|
||||
- Insured individuals
|
||||
- Injured parties
|
||||
- Other participants
|
||||
|
||||
Including:
|
||||
- Names
|
||||
- Statements
|
||||
- Presence tracking during inspections
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Technologies Used</div>
|
||||
|
||||
| Technology | Purpose |
|
||||
|:---:|:---:|
|
||||
| Python | Main programming language |
|
||||
| Tkinter | Desktop graphical interface |
|
||||
| python-docx | Microsoft Word manipulation |
|
||||
| Pillow (PIL) | Image processing |
|
||||
| io / tempfile | Temporary image stream handling |
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Project Structure</div>
|
||||
|
||||
```txt
|
||||
.
|
||||
├── vaguatechrelatorios_VF1.py
|
||||
├── Corpus.docx
|
||||
├── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Requirements</div>
|
||||
|
||||
## Python Version
|
||||
|
||||
```txt
|
||||
Python 3.10+
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Required Libraries</div>
|
||||
|
||||
Install dependencies:
|
||||
To start a local development server, run:
|
||||
|
||||
```bash
|
||||
pip install python-docx pillow
|
||||
ng serve
|
||||
```
|
||||
|
||||
---
|
||||
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
|
||||
|
||||
# <div align="center">Running the Application</div>
|
||||
## Code scaffolding
|
||||
|
||||
Execute:
|
||||
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||
|
||||
```bash
|
||||
python vaguatechrelatorios_VF1.py
|
||||
ng generate component component-name
|
||||
```
|
||||
|
||||
---
|
||||
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||
|
||||
# <div align="center">Required Template</div>
|
||||
|
||||
The application requires the following template file in the same directory:
|
||||
|
||||
```txt
|
||||
Corpus.docx
|
||||
```bash
|
||||
ng generate --help
|
||||
```
|
||||
|
||||
This template contains placeholders used for automatic replacement.
|
||||
## Building
|
||||
|
||||
---
|
||||
To build the project run:
|
||||
|
||||
# <div align="center">Supported Placeholders</div>
|
||||
|
||||
## Text Placeholders
|
||||
|
||||
| Placeholder | Description |
|
||||
|:---:|:---:|
|
||||
| `{{nproc}}` | Process number |
|
||||
| `{{segurado}}` | Insured person |
|
||||
| `{{comp}}` | Insurance company |
|
||||
| `{{terceiro}}` | Third party |
|
||||
| `{{data}}` | Inspection date |
|
||||
| `{{local da visita}}` | Inspection location |
|
||||
| `{{descriçãoimovel}}` | Property description |
|
||||
| `{{anoconstr}}` | Construction year |
|
||||
| `{{descricao}}` | Inspection description |
|
||||
| `{{area}}` | Area inspected |
|
||||
|
||||
---
|
||||
|
||||
## Image Placeholders
|
||||
|
||||
| Placeholder | Description |
|
||||
|:---:|:---:|
|
||||
| `{{foto1}}` | Main inspection image |
|
||||
| `{{foto2}}` | Multiple inspection images |
|
||||
|
||||
---
|
||||
|
||||
## Technical Sections
|
||||
|
||||
| Placeholder | Description |
|
||||
|:---:|:---:|
|
||||
| `{{tecnicasutilizadas}}` | Inspection techniques |
|
||||
| `{{iniciopesquisa}}` | Initial investigation methods |
|
||||
| `{{metodosutilizados}}` | Combined methods list |
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Generated Output</div>
|
||||
|
||||
Reports are automatically generated with timestamp naming:
|
||||
|
||||
```txt
|
||||
YYYY-MM-DD_HH-MM-SS.docx
|
||||
```bash
|
||||
ng build
|
||||
```
|
||||
|
||||
Example:
|
||||
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
|
||||
|
||||
```txt
|
||||
2026-05-21_15-30-00.docx
|
||||
## Running unit tests
|
||||
|
||||
To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command:
|
||||
|
||||
```bash
|
||||
ng test
|
||||
```
|
||||
|
||||
---
|
||||
## Running end-to-end tests
|
||||
|
||||
# <div align="center">User Interface</div>
|
||||
For end-to-end (e2e) testing, run:
|
||||
|
||||
The application provides:
|
||||
```bash
|
||||
ng e2e
|
||||
```
|
||||
|
||||
- Structured inspection form
|
||||
- Dynamic participant management
|
||||
- Multi-image selection
|
||||
- Technique management windows
|
||||
- Automatic validation popups
|
||||
- Error handling interface
|
||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||
|
||||
---
|
||||
## Additional Resources
|
||||
|
||||
# <div align="center">Error Handling</div>
|
||||
|
||||
The application automatically handles:
|
||||
|
||||
- Missing templates
|
||||
- Invalid image formats
|
||||
- Missing placeholders
|
||||
- DOCX generation failures
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Main Functionalities</div>
|
||||
|
||||
## Automatic Image Conversion
|
||||
|
||||
All images are automatically converted to PNG streams before insertion into Word documents.
|
||||
|
||||
---
|
||||
|
||||
## Dynamic Report Sections
|
||||
|
||||
The system dynamically builds:
|
||||
|
||||
- Participant summaries
|
||||
- Technical method sections
|
||||
- Inspection conclusions
|
||||
- Multi-image layouts
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Intended Use Cases</div>
|
||||
|
||||
- Insurance inspections
|
||||
- Technical damage assessments
|
||||
- Building inspections
|
||||
- Water damage investigations
|
||||
- Field technical reports
|
||||
- Evidence documentation
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Future Improvements</div>
|
||||
|
||||
- PDF export
|
||||
- Database integration
|
||||
- Digital signatures
|
||||
- Multi-user system
|
||||
- Cloud synchronization
|
||||
- OCR integration
|
||||
- AI-assisted report writing
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Disclaimer</div>
|
||||
|
||||
This software is intended for technical documentation and inspection support purposes.
|
||||
|
||||
Users remain responsible for validating generated reports before official submission.
|
||||
|
||||
---
|
||||
|
||||
# <div align="center">Author</div>
|
||||
|
||||
José Garcia
|
||||
Data Scientist
|
||||
PhD Researcher – Digitalization Engineering
|
||||
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['vaguatechrelatorios.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[('Corpus.docx', '.')],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='V-aguatech_Reportcrator',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['icon.ico'],
|
||||
)
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"cli": {
|
||||
"packageManager": "npm",
|
||||
"analytics": "9e434f1a-9bba-4713-a4e8-c59e9943824f"
|
||||
},
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"v-aguatech-angular": {
|
||||
"projectType": "application",
|
||||
"schematics": {},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular/build:application",
|
||||
"options": {
|
||||
"browser": "src/main.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "4kB",
|
||||
"maximumError": "8kB"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular/build:dev-server",
|
||||
"options": {
|
||||
"port": 4201
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "v-aguatech-angular:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "v-aguatech-angular:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular/build:unit-test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,171 +0,0 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean these modules are required for running your program. Both
|
||||
Python's standard library and 3rd-party Python packages often conditionally
|
||||
import optional modules, some of which may be available only on certain
|
||||
platforms.
|
||||
|
||||
Types of import:
|
||||
* top-level: imported at the top-level - look at these first
|
||||
* conditional: imported within an if-statement
|
||||
* delayed: imported within a function
|
||||
* optional: imported within a try-except-statement
|
||||
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), http.server (delayed, optional), psutil (optional), netrc (delayed, conditional), getpass (delayed)
|
||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional)
|
||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||
missing module named fcntl - imported by subprocess (optional), psutil._compat (delayed, optional), xmlrpc.server (optional)
|
||||
missing module named urllib.urlopen - imported by urllib (delayed, optional), lxml.html (delayed, optional)
|
||||
missing module named urllib.urlencode - imported by urllib (delayed, optional), lxml.html (delayed, optional)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named posix - imported by os (conditional, optional), shutil (conditional), importlib._bootstrap_external (conditional), posixpath (optional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named termios - imported by tty (top-level), psutil._compat (delayed, optional), getpass (optional)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named _winreg - imported by platform (delayed, optional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named pyimod02_importers - imported by C:\Users\garci\AppData\Roaming\Python\Python312\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named collections.Callable - imported by collections (optional), bs4.element (optional), bs4.builder._lxml (optional)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named annotationlib - imported by typing_extensions (conditional)
|
||||
missing module named htmlentitydefs - imported by lxml.html.soupparser (optional)
|
||||
missing module named BeautifulSoup - imported by lxml.html.soupparser (optional)
|
||||
missing module named chardet - imported by bs4.dammit (optional)
|
||||
missing module named cchardet - imported by bs4.dammit (optional)
|
||||
missing module named bs4.builder.HTMLParserTreeBuilder - imported by bs4.builder (top-level), bs4 (top-level)
|
||||
missing module named 'html5lib.treebuilders' - imported by bs4.builder._html5lib (optional), lxml.html._html5builder (top-level), lxml.html.html5parser (top-level)
|
||||
missing module named 'html5lib.constants' - imported by bs4.builder._html5lib (top-level)
|
||||
missing module named html5lib - imported by bs4.builder._html5lib (top-level), lxml.html.html5parser (top-level)
|
||||
missing module named urlparse - imported by lxml.ElementInclude (optional), lxml.html.html5parser (optional)
|
||||
missing module named urllib2 - imported by lxml.ElementInclude (optional), lxml.html.html5parser (optional)
|
||||
missing module named lxml_html_clean - imported by lxml.html.clean (optional)
|
||||
missing module named readline - imported by cmd (delayed, conditional, optional), code (delayed, conditional, optional), pdb (delayed, optional)
|
||||
missing module named cssselect - imported by lxml.cssselect (optional)
|
||||
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
|
||||
missing module named _dummy_thread - imported by numpy.core.arrayprint (optional)
|
||||
missing module named dummy_threading - imported by psutil._compat (optional)
|
||||
missing module named numpy.core.result_type - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.float_ - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.number - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.object_ - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.max - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.all - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.errstate - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.bool_ - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.inf - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.isnan - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.array2string - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.imag - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.real - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.lib.iscomplexobj - imported by numpy.lib (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.signbit - imported by numpy.core (delayed), numpy.testing._private.utils (delayed)
|
||||
missing module named numpy.core.isscalar - imported by numpy.core (delayed), numpy.testing._private.utils (delayed), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.array - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.isnat - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.ndarray - imported by numpy.core (top-level), numpy.testing._private.utils (top-level), numpy.lib.utils (top-level)
|
||||
missing module named numpy.core.array_repr - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.arange - imported by numpy.core (top-level), numpy.testing._private.utils (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.empty - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.float32 - imported by numpy.core (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.intp - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.core.linspace - imported by numpy.core (top-level), numpy.lib.index_tricks (top-level)
|
||||
missing module named numpy.core.iinfo - imported by numpy.core (top-level), numpy.lib.twodim_base (top-level)
|
||||
missing module named numpy.core.transpose - imported by numpy.core (top-level), numpy.lib.function_base (top-level)
|
||||
missing module named numpy.uint - imported by numpy (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.core.asarray - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.utils (top-level), numpy.fft._pocketfft (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.integer - imported by numpy.core (top-level), numpy.fft.helper (top-level)
|
||||
missing module named numpy.core.sqrt - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.conjugate - imported by numpy.core (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.swapaxes - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.zeros - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy.core.reciprocal - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sort - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.argsort - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sign - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.count_nonzero - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.divide - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.matmul - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.asanyarray - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.atleast_2d - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.prod - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.amax - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.amin - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.moveaxis - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.geterrobj - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.finfo - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.isfinite - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.sum - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.multiply - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.add - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.dot - imported by numpy.core (top-level), numpy.linalg.linalg (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.Inf - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.newaxis - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.complexfloating - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.inexact - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.cdouble - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.csingle - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.double - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.single - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.intc - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named numpy.core.empty_like - imported by numpy.core (top-level), numpy.linalg.linalg (top-level)
|
||||
missing module named pyodide_js - imported by threadpoolctl (delayed, optional)
|
||||
missing module named numpy.core.ufunc - imported by numpy.core (top-level), numpy.lib.utils (top-level)
|
||||
missing module named numpy.core.ones - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.hstack - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.atleast_1d - imported by numpy.core (top-level), numpy.lib.polynomial (top-level)
|
||||
missing module named numpy.core.atleast_3d - imported by numpy.core (top-level), numpy.lib.shape_base (top-level)
|
||||
missing module named numpy.core.vstack - imported by numpy.core (top-level), numpy.lib.shape_base (top-level)
|
||||
missing module named pickle5 - imported by numpy.compat.py3k (optional)
|
||||
missing module named numpy.eye - imported by numpy (delayed), numpy.core.numeric (delayed)
|
||||
missing module named numpy.recarray - imported by numpy (top-level), numpy.lib.recfunctions (top-level), numpy.ma.mrecords (top-level)
|
||||
missing module named numpy.expand_dims - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.array - imported by numpy (top-level), numpy.ma.core (top-level), numpy.ma.extras (top-level), numpy.ma.mrecords (top-level)
|
||||
missing module named numpy.iscomplexobj - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.amin - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.amax - imported by numpy (top-level), numpy.ma.core (top-level)
|
||||
missing module named numpy.isinf - imported by numpy (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.isnan - imported by numpy (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.isfinite - imported by numpy (top-level), numpy.testing._private.utils (top-level)
|
||||
missing module named numpy.float64 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.float32 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.uint64 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._philox (top-level), numpy.random._sfc64 (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.uint32 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._generator (top-level), numpy.random._mt19937 (top-level)
|
||||
missing module named numpy.uint16 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.uint8 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int64 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int32 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int16 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.int8 - imported by numpy (top-level), numpy.array_api._typing (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.bytes_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.str_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.void - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.object_ - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.datetime64 - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.timedelta64 - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.number - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.complexfloating - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.floating - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.integer - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.unsignedinteger - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.bool_ - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ma.core (top-level), numpy.ma.mrecords (top-level), numpy.random.mtrand (top-level), numpy.random._generator (top-level)
|
||||
missing module named numpy.generic - imported by numpy (top-level), numpy._typing._array_like (top-level)
|
||||
missing module named numpy.dtype - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.array_api._typing (top-level), numpy.ma.mrecords (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._philox (top-level), numpy.random._sfc64 (top-level), numpy.random._generator (top-level), numpy.random._mt19937 (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.ndarray - imported by numpy (top-level), numpy._typing._array_like (top-level), numpy.ma.core (top-level), numpy.ma.extras (top-level), numpy.lib.recfunctions (top-level), numpy.ma.mrecords (top-level), numpy.random.mtrand (top-level), numpy.random.bit_generator (top-level), numpy.random._philox (top-level), numpy.random._sfc64 (top-level), numpy.random._generator (top-level), numpy.random._mt19937 (top-level), numpy.ctypeslib (top-level)
|
||||
missing module named numpy.ufunc - imported by numpy (top-level), numpy._typing (top-level), numpy.testing.overrides (top-level)
|
||||
missing module named numpy.histogramdd - imported by numpy (delayed), numpy.lib.twodim_base (delayed)
|
||||
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional)
|
||||
missing module named numpy._typing._ufunc - imported by numpy._typing (conditional)
|
||||
missing module named xmlrpclib - imported by defusedxml.xmlrpc (conditional)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,247 +0,0 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean these modules are required for running your program. Both
|
||||
Python's standard library and 3rd-party Python packages often conditionally
|
||||
import optional modules, some of which may be available only on certain
|
||||
platforms.
|
||||
|
||||
Types of import:
|
||||
* top-level: imported at the top-level - look at these first
|
||||
* conditional: imported within an if-statement
|
||||
* delayed: imported within a function
|
||||
* optional: imported within a try-except-statement
|
||||
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (optional), netrc (delayed, optional), http.server (delayed, optional), psutil (optional)
|
||||
missing module named grp - imported by subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (optional)
|
||||
missing module named 'collections.abc' - imported by tracemalloc (top-level), typing (top-level), traceback (top-level), _colorize (top-level), selectors (top-level), logging (top-level), http.client (top-level), importlib.resources.readers (top-level), inspect (top-level), typing_extensions (top-level), asyncio.base_events (top-level), multiprocessing.managers (top-level), asyncio.coroutines (top-level), PIL.Image (top-level), PIL._typing (top-level), numpy._typing._array_like (top-level), numpy._typing._nested_sequence (conditional), numpy._typing._shape (top-level), numpy._typing._dtype_like (top-level), numpy.lib._function_base_impl (top-level), _pyrepl.types (top-level), numpy.lib._npyio_impl (top-level), numpy.random._common (top-level), numpy.random._generator (top-level), numpy.random.bit_generator (top-level), numpy.random.mtrand (top-level), numpy.polynomial._polybase (top-level), xml.etree.ElementTree (top-level), PIL.TiffImagePlugin (top-level), PIL.ImageOps (top-level), PIL.ImagePalette (top-level), PIL.GimpGradientFile (conditional), PIL.ImageFilter (top-level), PIL.ImageQt (conditional), PIL.ImageMath (conditional), PIL.ImageSequence (conditional), PIL.PngImagePlugin (conditional), lxml.html (top-level), lxml.html._setmixin (optional), PIL.Jpeg2KImagePlugin (conditional)
|
||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||
missing module named fcntl - imported by subprocess (optional), pathlib._os (optional)
|
||||
missing module named urllib.urlopen - imported by urllib (delayed, optional), lxml.html (delayed, optional)
|
||||
missing module named urllib.urlencode - imported by urllib (delayed, optional), lxml.html (delayed, optional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), pathlib._os (optional), _pyrepl.trace (conditional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.forkserver (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named pyimod02_importers - imported by C:\Users\garci\AppData\Local\Python\pythoncore-3.14-64\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named htmlentitydefs - imported by lxml.html.soupparser (optional)
|
||||
missing module named BeautifulSoup - imported by lxml.html.soupparser (optional)
|
||||
missing module named cchardet - imported by bs4.dammit (optional)
|
||||
missing module named 'html5lib.treebuilders' - imported by bs4.builder._html5lib (top-level), lxml.html._html5builder (top-level), lxml.html.html5parser (top-level)
|
||||
missing module named 'html5lib.constants' - imported by bs4.builder._html5lib (top-level)
|
||||
missing module named html5lib - imported by bs4.builder._html5lib (top-level), lxml.html.html5parser (top-level)
|
||||
missing module named urlparse - imported by lxml.ElementInclude (optional), lxml.html.html5parser (optional)
|
||||
missing module named urllib2 - imported by lxml.ElementInclude (optional), lxml.html.html5parser (optional)
|
||||
missing module named 'cython.cimports' - imported by lxml.html.diff (optional)
|
||||
missing module named cython - imported by lxml.html.diff (optional), lxml.html._difflib (optional)
|
||||
missing module named lxml_html_clean - imported by lxml.html.clean (optional)
|
||||
missing module named cgi - imported by lxml.doctestcompare (optional)
|
||||
missing module named termios - imported by tty (top-level), _pyrepl.pager (delayed, optional)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named readline - imported by cmd (delayed, conditional, optional), code (delayed, conditional, optional), pdb (delayed, conditional, optional), rlcompleter (optional)
|
||||
missing module named cssselect - imported by lxml.cssselect (optional)
|
||||
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
|
||||
missing module named _dummy_thread - imported by numpy._core.arrayprint (optional)
|
||||
missing module named 'numpy_distutils.cpuinfo' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.fcompiler' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.command' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named numpy_distutils - imported by numpy.f2py.diagnose (delayed, optional)
|
||||
missing module named _typeshed - imported by numpy.random.bit_generator (top-level)
|
||||
missing module named numpy.random.RandomState - imported by numpy.random (top-level), numpy.random._generator (top-level)
|
||||
missing module named threadpoolctl - imported by numpy.lib._utils_impl (delayed, optional)
|
||||
missing module named numpy._core.zeros - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.vstack - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.void - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.vecmat - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.vecdot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.ushort - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.unsignedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ulonglong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ulong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uintp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uintc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uint64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ubyte - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.trunc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.true_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._function_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.trace - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.timedelta64 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.tensordot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.tanh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.tan - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.swapaxes - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.sum - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.subtract - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.str_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.square - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.sqrt - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.spacing - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.sort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.sinh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.single - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.signedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.signbit - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.sign - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.short - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.rint - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.right_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.result_type - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.remainder - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.reciprocal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.radians - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.rad2deg - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.prod - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.power - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.positive - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.pi - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.outer - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.ones - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.object_ - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.number - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.not_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.nextafter - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.newaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.negative - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ndarray - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy.lib._utils_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.multiply - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.moveaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.modf - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.mod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.minimum - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.maximum - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.max - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.matvec - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.matrix_transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.matmul - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.longlong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.longdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.long - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_or - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_not - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_and - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logaddexp2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logaddexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log10 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log1p - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.linspace - imported by numpy._core (top-level), numpy.lib._index_tricks_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.less_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.less - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.left_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ldexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.lcm - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.isscalar - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.isnat - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||
missing module named numpy._core.isnan - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.isfinite - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.intp - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.integer - imported by numpy._core (conditional), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.intc - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.int64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int8 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.inf - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.inexact - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.iinfo - imported by numpy._core (top-level), numpy.lib._twodim_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.hypot - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.hstack - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.heaviside - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.half - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.greater_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.greater - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.gcd - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.frompyfunc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.frexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmin - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmax - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floor_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floating - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.float_power - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.float32 - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.float16 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.finfo - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.fabs - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.expm1 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.exp2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.exp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.euler_gamma - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.errstate - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.empty_like - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.empty - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.e - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.double - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.dot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.divmod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.divide - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.diagonal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.degrees - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.deg2rad - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.datetime64 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.csingle - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cross - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.count_nonzero - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cosh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.cos - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.copysign - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.conjugate - imported by numpy._core (conditional), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.conj - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.complexfloating - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.complex64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.clongdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.character - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ceil - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.cdouble - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cbrt - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bytes_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.byte - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bool_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_or - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_count - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_and - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.atleast_3d - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.atleast_2d - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.atleast_1d - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.asarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._array_utils_impl (top-level), numpy (conditional), numpy.fft._helper (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.asanyarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.array_repr - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||
missing module named numpy._core.array2string - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.array - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.argsort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.arctanh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arctan2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arctan - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arcsinh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arcsin - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arccosh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arccos - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arange - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.amin - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.amax - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.all - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.add - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named yaml - imported by numpy.__config__ (delayed)
|
||||
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional)
|
||||
missing module named defusedxml - imported by PIL.Image (optional)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,247 +0,0 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean these modules are required for running your program. Both
|
||||
Python's standard library and 3rd-party Python packages often conditionally
|
||||
import optional modules, some of which may be available only on certain
|
||||
platforms.
|
||||
|
||||
Types of import:
|
||||
* top-level: imported at the top-level - look at these first
|
||||
* conditional: imported within an if-statement
|
||||
* delayed: imported within a function
|
||||
* optional: imported within a try-except-statement
|
||||
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (optional), netrc (delayed, optional), http.server (delayed, optional), psutil (optional)
|
||||
missing module named grp - imported by subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (optional)
|
||||
missing module named 'collections.abc' - imported by tracemalloc (top-level), typing (top-level), traceback (top-level), _colorize (top-level), selectors (top-level), logging (top-level), http.client (top-level), importlib.resources.readers (top-level), inspect (top-level), typing_extensions (top-level), asyncio.base_events (top-level), multiprocessing.managers (top-level), asyncio.coroutines (top-level), PIL.Image (top-level), PIL._typing (top-level), numpy._typing._array_like (top-level), numpy._typing._nested_sequence (conditional), numpy._typing._shape (top-level), numpy._typing._dtype_like (top-level), numpy.lib._function_base_impl (top-level), _pyrepl.types (top-level), numpy.lib._npyio_impl (top-level), numpy.random._common (top-level), numpy.random._generator (top-level), numpy.random.bit_generator (top-level), numpy.random.mtrand (top-level), numpy.polynomial._polybase (top-level), xml.etree.ElementTree (top-level), PIL.TiffImagePlugin (top-level), PIL.ImageOps (top-level), PIL.ImagePalette (top-level), PIL.GimpGradientFile (conditional), PIL.ImageFilter (top-level), PIL.ImageQt (conditional), PIL.ImageMath (conditional), PIL.ImageSequence (conditional), PIL.PngImagePlugin (conditional), lxml.html (top-level), lxml.html._setmixin (optional), PIL.Jpeg2KImagePlugin (conditional)
|
||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||
missing module named fcntl - imported by subprocess (optional), pathlib._os (optional)
|
||||
missing module named urllib.urlopen - imported by urllib (delayed, optional), lxml.html (delayed, optional)
|
||||
missing module named urllib.urlencode - imported by urllib (delayed, optional), lxml.html (delayed, optional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), pathlib._os (optional), _pyrepl.trace (conditional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.forkserver (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named pyimod02_importers - imported by C:\Users\garci\AppData\Local\Python\pythoncore-3.14-64\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named htmlentitydefs - imported by lxml.html.soupparser (optional)
|
||||
missing module named BeautifulSoup - imported by lxml.html.soupparser (optional)
|
||||
missing module named cchardet - imported by bs4.dammit (optional)
|
||||
missing module named 'html5lib.treebuilders' - imported by bs4.builder._html5lib (top-level), lxml.html._html5builder (top-level), lxml.html.html5parser (top-level)
|
||||
missing module named 'html5lib.constants' - imported by bs4.builder._html5lib (top-level)
|
||||
missing module named html5lib - imported by bs4.builder._html5lib (top-level), lxml.html.html5parser (top-level)
|
||||
missing module named urlparse - imported by lxml.ElementInclude (optional), lxml.html.html5parser (optional)
|
||||
missing module named urllib2 - imported by lxml.ElementInclude (optional), lxml.html.html5parser (optional)
|
||||
missing module named 'cython.cimports' - imported by lxml.html.diff (optional)
|
||||
missing module named cython - imported by lxml.html.diff (optional), lxml.html._difflib (optional)
|
||||
missing module named lxml_html_clean - imported by lxml.html.clean (optional)
|
||||
missing module named cgi - imported by lxml.doctestcompare (optional)
|
||||
missing module named termios - imported by tty (top-level), _pyrepl.pager (delayed, optional)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named readline - imported by cmd (delayed, conditional, optional), code (delayed, conditional, optional), pdb (delayed, conditional, optional), rlcompleter (optional)
|
||||
missing module named cssselect - imported by lxml.cssselect (optional)
|
||||
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
|
||||
missing module named _dummy_thread - imported by numpy._core.arrayprint (optional)
|
||||
missing module named 'numpy_distutils.cpuinfo' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.fcompiler' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.command' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named numpy_distutils - imported by numpy.f2py.diagnose (delayed, optional)
|
||||
missing module named _typeshed - imported by numpy.random.bit_generator (top-level)
|
||||
missing module named numpy.random.RandomState - imported by numpy.random (top-level), numpy.random._generator (top-level)
|
||||
missing module named threadpoolctl - imported by numpy.lib._utils_impl (delayed, optional)
|
||||
missing module named numpy._core.zeros - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.vstack - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.void - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.vecmat - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.vecdot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.ushort - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.unsignedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ulonglong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ulong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uintp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uintc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.uint64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.uint - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ubyte - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.trunc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.true_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._function_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.trace - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.timedelta64 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.tensordot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.tanh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.tan - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.swapaxes - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.sum - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.subtract - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.str_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.square - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.sqrt - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.spacing - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.sort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.sinh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.single - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.signedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.signbit - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.sign - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.short - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.rint - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.right_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.result_type - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.remainder - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.reciprocal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.radians - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.rad2deg - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.prod - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.power - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.positive - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.pi - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.outer - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.ones - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.object_ - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.number - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.not_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.nextafter - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.newaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.negative - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ndarray - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy.lib._utils_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.multiply - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.moveaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.modf - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.mod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.minimum - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.maximum - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.max - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.matvec - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.matrix_transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.matmul - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.longlong - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.longdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.long - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_or - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_not - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logical_and - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logaddexp2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.logaddexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log10 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log1p - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.log - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.linspace - imported by numpy._core (top-level), numpy.lib._index_tricks_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.less_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.less - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.left_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ldexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.lcm - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.isscalar - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.isnat - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||
missing module named numpy._core.isnan - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.isfinite - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.intp - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.integer - imported by numpy._core (conditional), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.intc - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.int64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.int8 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.inf - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.inexact - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.iinfo - imported by numpy._core (top-level), numpy.lib._twodim_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.hypot - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.hstack - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.heaviside - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.half - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.greater_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.greater - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.gcd - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.frompyfunc - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.frexp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmin - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.fmax - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floor_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.floating - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.float_power - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.float32 - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.float16 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.finfo - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.fabs - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.expm1 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.exp2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.exp - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.euler_gamma - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.errstate - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.equal - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.empty_like - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.empty - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.e - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.double - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.dot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.divmod - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.divide - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.diagonal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.degrees - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.deg2rad - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.datetime64 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.csingle - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cross - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.count_nonzero - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cosh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.cos - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.copysign - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.conjugate - imported by numpy._core (conditional), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.conj - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.complexfloating - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.complex64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||
missing module named numpy._core.clongdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.character - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.ceil - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.cdouble - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.cbrt - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bytes_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.byte - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bool_ - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_or - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_count - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.bitwise_and - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.atleast_3d - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.atleast_2d - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.atleast_1d - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.asarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._array_utils_impl (top-level), numpy (conditional), numpy.fft._helper (top-level), numpy.fft._pocketfft (top-level)
|
||||
missing module named numpy._core.asanyarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.array_repr - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||
missing module named numpy._core.array2string - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.array - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.argsort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.arctanh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arctan2 - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arctan - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arcsinh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arcsin - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arccosh - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arccos - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.arange - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||
missing module named numpy._core.amin - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.amax - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.all - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.add - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named yaml - imported by numpy.__config__ (delayed)
|
||||
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional)
|
||||
missing module named defusedxml - imported by PIL.Image (optional)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,35 +0,0 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
if not exist "icon.png" (
|
||||
echo ERRO: "icon.png" nao encontrado na pasta atual.
|
||||
echo Coloque a imagem do logo como "icon.png" nesta pasta e execute novamente.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo A gerar icon.ico...
|
||||
python -c "from PIL import Image; img=Image.open('icon.png'); img.save('icon.ico', sizes=[(256,256)])"
|
||||
if errorlevel 1 (
|
||||
echo ERRO: Falha ao gerar icon.ico. Verifique se o Pillow esta instalado.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo A instalar/atualizar PyInstaller...
|
||||
python -m pip install --upgrade pyinstaller
|
||||
if errorlevel 1 (
|
||||
echo ERRO: Falha ao instalar PyInstaller.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo A compilar o executavel...
|
||||
python -m PyInstaller --noconsole --onefile --name "V-aguatech_Reportcrator" --icon "icon.ico" --add-data "Corpus.docx;." vaguatechrelatorios.py
|
||||
if errorlevel 1 (
|
||||
echo ERRO: Falha ao compilar o executavel.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo SUCESSO: Executavel gerado em "dist\V-aguatech_Reportcrator.exe"
|
||||
endlocal
|
||||
@@ -1,28 +0,0 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
if not exist "icon.ico" (
|
||||
echo ERRO: "icon.ico" nao encontrado na pasta atual.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if not exist "Corpus.docx" (
|
||||
echo ERRO: "Corpus.docx" nao encontrado na pasta atual.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo A compilar o executavel VF1...
|
||||
python -m PyInstaller --clean "vaguatechrelatorios_VF1.spec"
|
||||
if errorlevel 1 (
|
||||
echo ERRO: Falha ao compilar o executavel VF1.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
copy /Y "Corpus.docx" "dist\\Corpus.docx" >nul
|
||||
|
||||
echo.
|
||||
echo SUCESSO: Executavel gerado em "dist\vaguatechrelatorios_VF1.exe"
|
||||
echo SUCESSO: Template copiado para "dist\Corpus.docx"
|
||||
endlocal
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Generated
+8795
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "v-aguatech-angular",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"private": true,
|
||||
"packageManager": "npm@10.9.2",
|
||||
"dependencies": {
|
||||
"@angular/common": "^21.2.0",
|
||||
"@angular/compiler": "^21.2.0",
|
||||
"@angular/core": "^21.2.0",
|
||||
"@angular/forms": "^21.2.0",
|
||||
"@angular/platform-browser": "^21.2.0",
|
||||
"@angular/router": "^21.2.0",
|
||||
"docx": "^9.6.1",
|
||||
"docx-preview": "^0.3.7",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "^21.2.9",
|
||||
"@angular/cli": "^21.2.9",
|
||||
"@angular/compiler-cli": "^21.2.0",
|
||||
"jsdom": "^28.0.0",
|
||||
"prettier": "^3.8.1",
|
||||
"typescript": "~5.9.2",
|
||||
"vitest": "^4.0.8"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 146 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="https://v-aguatech.com" TargetMode="External"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image2.jpeg"/></Relationships>
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideBrowserGlobalErrorListeners(),
|
||||
provideRouter(routes)
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
@@ -0,0 +1,439 @@
|
||||
<main class="workspace">
|
||||
<aside class="workspace__controls" (input)="queuePreviewRender()" (change)="queuePreviewRender()">
|
||||
<div class="panel-head">
|
||||
<p class="eyebrow">V-aguatech Report Creator</p>
|
||||
</div>
|
||||
|
||||
<div class="action-row">
|
||||
<button
|
||||
class="button button--primary"
|
||||
type="button"
|
||||
(click)="downloadWord()"
|
||||
[disabled]="isExporting"
|
||||
>
|
||||
{{ isExporting ? 'A gerar Word...' : 'Gerar Word' }}
|
||||
</button>
|
||||
<button class="button button--ghost" type="button" (click)="resetForm()">Limpar</button>
|
||||
</div>
|
||||
|
||||
<p
|
||||
class="status"
|
||||
[class.is-success]="statusTone === 'success'"
|
||||
[class.is-error]="statusTone === 'error'"
|
||||
>
|
||||
{{ statusMessage }}
|
||||
</p>
|
||||
|
||||
<section class="form-card">
|
||||
<div class="section-head">
|
||||
<h2>Dados base</h2>
|
||||
</div>
|
||||
|
||||
<div class="field-grid">
|
||||
<label class="field">
|
||||
<span>N do processo</span>
|
||||
<input [(ngModel)]="form.nproc" placeholder="Ex. 2026/12345" />
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>Segurado</span>
|
||||
<input [(ngModel)]="form.segurado" placeholder="Nome do segurado" />
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>Companhia</span>
|
||||
<input [(ngModel)]="form.companhia" placeholder="Companhia seguradora" />
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>Terceiro</span>
|
||||
<input [(ngModel)]="form.terceiro" placeholder="Entidade terceira" />
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>Data da visita</span>
|
||||
<input [(ngModel)]="form.dataVisita" type="date" />
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>Local da visita</span>
|
||||
<input [(ngModel)]="form.localVisita" placeholder="Morada ou local" />
|
||||
</label>
|
||||
|
||||
<label class="field field--full">
|
||||
<span>Descricao do imovel</span>
|
||||
<textarea
|
||||
[(ngModel)]="form.descricaoImovel"
|
||||
rows="4"
|
||||
placeholder="Caracterizacao do imovel e enquadramento."
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>Ano de construcão</span>
|
||||
<input [(ngModel)]="form.anoConstrucao" placeholder="Ex. 1998" />
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>Área do espaço (m2)</span>
|
||||
<input [(ngModel)]="form.area" placeholder="Ex. 82" />
|
||||
</label>
|
||||
|
||||
<label class="field field--full">
|
||||
<span>Descrição da pesquisa</span>
|
||||
<textarea
|
||||
[(ngModel)]="form.descricaoPesquisa"
|
||||
rows="5"
|
||||
placeholder="Descrição do levantamento efetuado, constatações e enquadramento."
|
||||
></textarea>
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="form-card">
|
||||
<div class="section-head">
|
||||
<h2>Fotografias</h2>
|
||||
<p>Imagem principal do imovel e das pesquisas.</p>
|
||||
</div>
|
||||
|
||||
<div class="upload-block">
|
||||
<div class="upload-row">
|
||||
<div>
|
||||
<strong>Imagem do imovel</strong>
|
||||
<p>Substitui o bloco principal do documento.</p>
|
||||
</div>
|
||||
<label class="button button--soft">
|
||||
Carregar imagem
|
||||
<input
|
||||
class="sr-only"
|
||||
type="file"
|
||||
accept=".png,.jpg,.jpeg,.gif,.bmp"
|
||||
(change)="onMainPhotoSelected($event)"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@if (form.fotoImovel; as photo) {
|
||||
<div class="thumb-list thumb-list--single">
|
||||
<article class="thumb-card">
|
||||
<img [src]="photo.objectUrl" [alt]="photo.name" />
|
||||
<div class="thumb-card__meta">
|
||||
<strong>{{ photo.name }}</strong>
|
||||
<button class="link-button" type="button" (click)="clearMainPhoto()">Remover</button>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="upload-block">
|
||||
<div class="upload-row">
|
||||
<div>
|
||||
<strong>Imagens da pesquisa</strong>
|
||||
<p>Usadas na seccão descritiva do relatório.</p>
|
||||
</div>
|
||||
<label class="button button--soft">
|
||||
Adicionar imagens
|
||||
<input
|
||||
class="sr-only"
|
||||
type="file"
|
||||
accept=".png,.jpg,.jpeg,.gif,.bmp"
|
||||
multiple
|
||||
(change)="onResearchPhotosSelected($event)"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@if (form.fotosPesquisa.length) {
|
||||
<div class="thumb-list">
|
||||
@for (photo of form.fotosPesquisa; track photo.id) {
|
||||
<article class="thumb-card">
|
||||
<img [src]="photo.objectUrl" [alt]="photo.name" />
|
||||
<div class="thumb-card__meta">
|
||||
<strong>{{ photo.name }}</strong>
|
||||
<button class="link-button" type="button" (click)="removeResearchPhoto(photo.id)">
|
||||
Remover
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="form-card">
|
||||
<div class="section-head">
|
||||
<h2>Presenças</h2>
|
||||
<p>Lista de pessoas presentes durante a pesquisa, adicionar tantas quanto necessárias</p>
|
||||
</div>
|
||||
|
||||
@for (section of presenceSections; track section.type) {
|
||||
<div class="presence-group">
|
||||
<div class="group-head">
|
||||
<div>
|
||||
<h3>{{ section.title }}</h3>
|
||||
<p>Adicionar ou remover {{ section.singularLabel }}s conforme necessário.</p>
|
||||
</div>
|
||||
<button
|
||||
class="button button--ghost button--small"
|
||||
type="button"
|
||||
(click)="addPresence(section.type)"
|
||||
>
|
||||
{{ section.buttonLabel }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (!getPresenceEntries(section.type).length) {
|
||||
<p class="empty-state">Sem entradas neste grupo.</p>
|
||||
}
|
||||
|
||||
@for (presence of getPresenceEntries(section.type); track presence.id) {
|
||||
<article class="presence-card">
|
||||
<label class="field">
|
||||
<span>Nome</span>
|
||||
<input [(ngModel)]="presence.name" placeholder="Nome da pessoa presente" />
|
||||
</label>
|
||||
|
||||
<label class="field field--full">
|
||||
<span>Declaracões</span>
|
||||
<textarea
|
||||
[(ngModel)]="presence.info"
|
||||
rows="3"
|
||||
placeholder="O que esta pessoa informou durante a pesquisa."
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<button
|
||||
class="link-button link-button--danger"
|
||||
type="button"
|
||||
(click)="removePresence(presence.id)"
|
||||
>
|
||||
Remover entrada
|
||||
</button>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
|
||||
<section class="form-card">
|
||||
<div class="section-head">
|
||||
<h2>Inicio da pesquisa</h2>
|
||||
<p>Linhas adicionaveis com combobox para escolher o metodo.</p>
|
||||
</div>
|
||||
|
||||
<div class="group-head group-head--section">
|
||||
<div>
|
||||
<h3>Métodos do inicio</h3>
|
||||
<p>Escolhe uma opcao da lista e completa a descrição se necessario.</p>
|
||||
</div>
|
||||
<button
|
||||
class="button button--ghost button--small"
|
||||
type="button"
|
||||
(click)="addTechniqueBlock('inicioPesquisa')"
|
||||
>
|
||||
Adicionar linha
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tech-grid">
|
||||
@for (item of form.inicioPesquisa; track item.id) {
|
||||
<article class="tech-card" [class.is-selected]="!!item.name">
|
||||
<div class="tech-card__top">
|
||||
<label class="field field--full">
|
||||
<span>Metodo</span>
|
||||
<select [(ngModel)]="item.name">
|
||||
<option value="">Escolher metodo...</option>
|
||||
@for (option of techniqueOptions; track option) {
|
||||
<option [value]="option">{{ option }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<button
|
||||
class="link-button link-button--danger"
|
||||
type="button"
|
||||
(click)="removeTechniqueBlock('inicioPesquisa', item.id)"
|
||||
>
|
||||
Remover linha
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<label class="field field--full">
|
||||
<span>Descricao</span>
|
||||
<textarea
|
||||
[(ngModel)]="item.description"
|
||||
rows="3"
|
||||
[disabled]="!item.name"
|
||||
placeholder="Descricao desta etapa inicial."
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<div class="upload-row">
|
||||
<div>
|
||||
<strong>Fotografias</strong>
|
||||
<p>Galeria para este metodo.</p>
|
||||
</div>
|
||||
<label class="button button--soft" [class.is-disabled]="!item.name">
|
||||
Adicionar
|
||||
<input
|
||||
class="sr-only"
|
||||
type="file"
|
||||
accept=".png,.jpg,.jpeg,.gif,.bmp"
|
||||
multiple
|
||||
[disabled]="!item.name"
|
||||
(change)="onTechniquePhotosSelected($event, item)"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@if (item.photos.length) {
|
||||
<div class="thumb-list">
|
||||
@for (photo of item.photos; track photo.id) {
|
||||
<article class="thumb-card">
|
||||
<img [src]="photo.objectUrl" [alt]="photo.name" />
|
||||
<div class="thumb-card__meta">
|
||||
<strong>{{ photo.name }}</strong>
|
||||
<button
|
||||
class="link-button"
|
||||
type="button"
|
||||
(click)="removeTechniquePhoto(item, photo.id)"
|
||||
>
|
||||
Remover
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="form-card">
|
||||
<div class="section-head">
|
||||
<h2>Levantamento de danos</h2>
|
||||
<p>Linhas adicionaveis com combobox para escolher o metodo.</p>
|
||||
</div>
|
||||
|
||||
<div class="group-head group-head--section">
|
||||
<div>
|
||||
<h3>Metodos do levantamento</h3>
|
||||
<p>Escolhe uma opcao da lista e completa a descricao se necessario.</p>
|
||||
</div>
|
||||
<button
|
||||
class="button button--ghost button--small"
|
||||
type="button"
|
||||
(click)="addTechniqueBlock('tecnicas')"
|
||||
>
|
||||
Adicionar linha
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tech-grid">
|
||||
@for (item of form.tecnicas; track item.id) {
|
||||
<article class="tech-card" [class.is-selected]="!!item.name">
|
||||
<div class="tech-card__top">
|
||||
<label class="field field--full">
|
||||
<span>Metodo</span>
|
||||
<select [(ngModel)]="item.name">
|
||||
<option value="">Escolher metodo...</option>
|
||||
@for (option of techniqueOptions; track option) {
|
||||
<option [value]="option">{{ option }}</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<button
|
||||
class="link-button link-button--danger"
|
||||
type="button"
|
||||
(click)="removeTechniqueBlock('tecnicas', item.id)"
|
||||
>
|
||||
Remover linha
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<label class="field field--full">
|
||||
<span>Descricao</span>
|
||||
<textarea
|
||||
[(ngModel)]="item.description"
|
||||
rows="3"
|
||||
[disabled]="!item.name"
|
||||
placeholder="Descricao deste metodo usado no levantamento."
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<div class="upload-row">
|
||||
<div>
|
||||
<strong>Fotografias</strong>
|
||||
<p>Galeria para este metodo.</p>
|
||||
</div>
|
||||
<label class="button button--soft" [class.is-disabled]="!item.name">
|
||||
Adicionar
|
||||
<input
|
||||
class="sr-only"
|
||||
type="file"
|
||||
accept=".png,.jpg,.jpeg,.gif,.bmp"
|
||||
multiple
|
||||
[disabled]="!item.name"
|
||||
(change)="onTechniquePhotosSelected($event, item)"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@if (item.photos.length) {
|
||||
<div class="thumb-list">
|
||||
@for (photo of item.photos; track photo.id) {
|
||||
<article class="thumb-card">
|
||||
<img [src]="photo.objectUrl" [alt]="photo.name" />
|
||||
<div class="thumb-card__meta">
|
||||
<strong>{{ photo.name }}</strong>
|
||||
<button
|
||||
class="link-button"
|
||||
type="button"
|
||||
(click)="removeTechniquePhoto(item, photo.id)"
|
||||
>
|
||||
Remover
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
<section class="workspace__preview">
|
||||
<div class="preview-head">
|
||||
<div>
|
||||
<p class="eyebrow">Preview</p>
|
||||
<h2>Relatório em tempo real</h2>
|
||||
</div>
|
||||
<p class="preview-note"></p>
|
||||
</div>
|
||||
|
||||
<div class="word-preview-shell">
|
||||
<div #wordPreviewStyles class="word-preview-styles" aria-hidden="true"></div>
|
||||
|
||||
@if (isPreviewRendering) {
|
||||
<div class="preview-banner">
|
||||
<span class="preview-dot"></span>
|
||||
A atualizar o documento Word...
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (previewErrorMessage) {
|
||||
<div class="preview-banner preview-banner--error">
|
||||
{{ previewErrorMessage }}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div #wordPreview class="word-preview-host"></div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@@ -0,0 +1,3 @@
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
export const routes: Routes = [];
|
||||
@@ -0,0 +1,25 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { App } from './app';
|
||||
|
||||
describe('App', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [App],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(App);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render workspace title and primary action', async () => {
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('.eyebrow')?.textContent).toContain('V-aguatech Report Creator');
|
||||
expect(compiled.querySelector('.button--primary')?.textContent).toContain('Gerar Word');
|
||||
});
|
||||
});
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import {
|
||||
createInitialReportForm,
|
||||
createPresenceEntry,
|
||||
createTechniqueBlock,
|
||||
PresenceEntry,
|
||||
PresenceType,
|
||||
PRESENCE_SECTIONS,
|
||||
ReportFormModel,
|
||||
TECHNIQUE_OPTIONS,
|
||||
TechniqueBlock,
|
||||
UploadedImage
|
||||
} from './report.models';
|
||||
|
||||
type TechniqueCollectionKey = 'inicioPesquisa' | 'tecnicas';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [FormsModule],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.css'
|
||||
})
|
||||
export class App implements AfterViewInit, OnDestroy {
|
||||
readonly presenceSections = PRESENCE_SECTIONS;
|
||||
readonly techniqueOptions = TECHNIQUE_OPTIONS;
|
||||
|
||||
@ViewChild('wordPreview') private readonly wordPreviewRef?: ElementRef<HTMLDivElement>;
|
||||
@ViewChild('wordPreviewStyles') private readonly wordPreviewStylesRef?: ElementRef<HTMLDivElement>;
|
||||
|
||||
form: ReportFormModel = createInitialReportForm();
|
||||
statusMessage = 'Word interativo a medida que preenche o formulario.';
|
||||
statusTone: 'info' | 'success' | 'error' = 'info';
|
||||
isExporting = false;
|
||||
isPreviewRendering = false;
|
||||
previewErrorMessage = '';
|
||||
|
||||
private readonly supportedExtensions = new Set(['png', 'jpg', 'jpeg', 'gif', 'bmp']);
|
||||
private readonly supportedMimeTypes = new Set([
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
'image/gif',
|
||||
'image/bmp'
|
||||
]);
|
||||
|
||||
private previewRenderTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
private previewRenderRequestId = 0;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.queuePreviewRender(0);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.previewRenderTimer) {
|
||||
clearTimeout(this.previewRenderTimer);
|
||||
this.previewRenderTimer = null;
|
||||
}
|
||||
|
||||
this.previewRenderRequestId += 1;
|
||||
this.revokeFormImages(this.form);
|
||||
}
|
||||
|
||||
queuePreviewRender(delay = 250): void {
|
||||
if (this.previewRenderTimer) {
|
||||
clearTimeout(this.previewRenderTimer);
|
||||
}
|
||||
|
||||
this.previewRenderTimer = setTimeout(() => {
|
||||
this.previewRenderTimer = null;
|
||||
void this.renderWordPreview();
|
||||
}, delay);
|
||||
}
|
||||
|
||||
getPresenceEntries(type: PresenceType): PresenceEntry[] {
|
||||
return this.form.presencas.filter((item) => item.type === type);
|
||||
}
|
||||
|
||||
addPresence(type: PresenceType): void {
|
||||
this.form.presencas = [...this.form.presencas, createPresenceEntry(type)];
|
||||
this.queuePreviewRender();
|
||||
}
|
||||
|
||||
removePresence(id: string): void {
|
||||
this.form.presencas = this.form.presencas.filter((item) => item.id !== id);
|
||||
this.queuePreviewRender();
|
||||
}
|
||||
|
||||
addTechniqueBlock(section: TechniqueCollectionKey): void {
|
||||
this.form[section] = [...this.form[section], createTechniqueBlock()];
|
||||
this.queuePreviewRender();
|
||||
}
|
||||
|
||||
removeTechniqueBlock(section: TechniqueCollectionKey, id: string): void {
|
||||
const block = this.form[section].find((item) => item.id === id);
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.revokeImages(block.photos);
|
||||
this.form[section] = this.form[section].filter((item) => item.id !== id);
|
||||
this.queuePreviewRender();
|
||||
}
|
||||
|
||||
async onMainPhotoSelected(event: Event): Promise<void> {
|
||||
try {
|
||||
const files = this.extractFiles(event);
|
||||
if (!files.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [image] = await this.readImages(files);
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.revokeImage(this.form.fotoImovel);
|
||||
this.form.fotoImovel = image;
|
||||
this.setStatus(`Fotografia principal carregada: ${image.name}`, 'success');
|
||||
this.queuePreviewRender();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.setStatus('Nao foi possivel carregar a fotografia principal.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async onResearchPhotosSelected(event: Event): Promise<void> {
|
||||
try {
|
||||
const files = this.extractFiles(event);
|
||||
if (!files.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const images = await this.readImages(files);
|
||||
this.form.fotosPesquisa = [...this.form.fotosPesquisa, ...images];
|
||||
this.setStatus(`${images.length} fotografia(s) adicionadas a pesquisa.`, 'success');
|
||||
this.queuePreviewRender();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.setStatus('Nao foi possivel carregar as fotografias da pesquisa.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async onTechniquePhotosSelected(event: Event, block: TechniqueBlock): Promise<void> {
|
||||
try {
|
||||
const files = this.extractFiles(event);
|
||||
if (!files.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const images = await this.readImages(files);
|
||||
block.photos = [...block.photos, ...images];
|
||||
this.setStatus(`${images.length} fotografia(s) adicionadas a "${block.name}".`, 'success');
|
||||
this.queuePreviewRender();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.setStatus(`Nao foi possivel carregar as fotografias de "${block.name}".`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
clearMainPhoto(): void {
|
||||
this.revokeImage(this.form.fotoImovel);
|
||||
this.form.fotoImovel = null;
|
||||
this.setStatus('Fotografia principal removida.', 'info');
|
||||
this.queuePreviewRender();
|
||||
}
|
||||
|
||||
removeResearchPhoto(photoId: string): void {
|
||||
const photo = this.form.fotosPesquisa.find((item) => item.id === photoId);
|
||||
if (!photo) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.revokeImage(photo);
|
||||
this.form.fotosPesquisa = this.form.fotosPesquisa.filter((item) => item.id !== photoId);
|
||||
this.setStatus('Fotografia removida da descricao da pesquisa.', 'info');
|
||||
this.queuePreviewRender();
|
||||
}
|
||||
|
||||
removeTechniquePhoto(block: TechniqueBlock, photoId: string): void {
|
||||
const photo = block.photos.find((item) => item.id === photoId);
|
||||
if (!photo) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.revokeImage(photo);
|
||||
block.photos = block.photos.filter((item) => item.id !== photoId);
|
||||
this.setStatus(`Fotografia removida de "${block.name}".`, 'info');
|
||||
this.queuePreviewRender();
|
||||
}
|
||||
|
||||
resetForm(): void {
|
||||
this.revokeFormImages(this.form);
|
||||
this.form = createInitialReportForm();
|
||||
this.setStatus('Formulario limpo. A pre-visualizacao foi reiniciada.', 'info');
|
||||
this.queuePreviewRender(0);
|
||||
}
|
||||
|
||||
async downloadWord(): Promise<void> {
|
||||
this.isExporting = true;
|
||||
|
||||
try {
|
||||
const { buildOutputFilename, buildReportBlob } = await import('./report-docx');
|
||||
const blob = await buildReportBlob(this.form, 'download');
|
||||
const filename = buildOutputFilename();
|
||||
this.saveBlob(blob, filename);
|
||||
this.setStatus(`Documento Word gerado: ${filename}`, 'success');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.setStatus('Nao foi possivel gerar o ficheiro Word.', 'error');
|
||||
} finally {
|
||||
this.isExporting = false;
|
||||
}
|
||||
}
|
||||
|
||||
private extractFiles(event: Event): File[] {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const files = Array.from(input.files ?? []);
|
||||
input.value = '';
|
||||
return files;
|
||||
}
|
||||
|
||||
private async readImages(files: File[]): Promise<UploadedImage[]> {
|
||||
return Promise.all(files.map((file) => this.readImage(file)));
|
||||
}
|
||||
|
||||
private async readImage(file: File): Promise<UploadedImage> {
|
||||
this.assertSupportedImage(file);
|
||||
|
||||
const objectUrl = URL.createObjectURL(file);
|
||||
|
||||
try {
|
||||
const dimensions = await this.measureImage(objectUrl);
|
||||
return {
|
||||
id: this.createUiId(file.name),
|
||||
file,
|
||||
name: file.name,
|
||||
objectUrl,
|
||||
width: dimensions.width,
|
||||
height: dimensions.height
|
||||
};
|
||||
} catch (error) {
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private measureImage(objectUrl: string): Promise<{ width: number; height: number }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new Image();
|
||||
|
||||
image.onload = () => {
|
||||
resolve({
|
||||
width: image.naturalWidth || 1200,
|
||||
height: image.naturalHeight || 900
|
||||
});
|
||||
};
|
||||
|
||||
image.onerror = () => {
|
||||
reject(new Error('Nao foi possivel ler uma das imagens selecionadas.'));
|
||||
};
|
||||
|
||||
image.src = objectUrl;
|
||||
});
|
||||
}
|
||||
|
||||
private async renderWordPreview(): Promise<void> {
|
||||
const bodyContainer = this.wordPreviewRef?.nativeElement;
|
||||
const styleContainer = this.wordPreviewStylesRef?.nativeElement;
|
||||
if (!bodyContainer || !styleContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const requestId = ++this.previewRenderRequestId;
|
||||
this.isPreviewRendering = true;
|
||||
this.previewErrorMessage = '';
|
||||
|
||||
try {
|
||||
const [{ buildReportBlob }, { renderAsync }] = await Promise.all([
|
||||
import('./report-docx'),
|
||||
import('docx-preview')
|
||||
]);
|
||||
const blob = await buildReportBlob(this.form, 'preview');
|
||||
|
||||
if (requestId !== this.previewRenderRequestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
bodyContainer.replaceChildren();
|
||||
styleContainer.replaceChildren();
|
||||
|
||||
await renderAsync(blob, bodyContainer, styleContainer, {
|
||||
className: 'docx',
|
||||
inWrapper: true,
|
||||
ignoreWidth: false,
|
||||
ignoreHeight: false,
|
||||
breakPages: true,
|
||||
useBase64URL: true
|
||||
});
|
||||
|
||||
if (requestId !== this.previewRenderRequestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isPreviewRendering = false;
|
||||
} catch (error) {
|
||||
if (requestId !== this.previewRenderRequestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
bodyContainer.replaceChildren();
|
||||
styleContainer.replaceChildren();
|
||||
this.previewErrorMessage = 'Nao foi possivel renderizar o documento Word.';
|
||||
this.isPreviewRendering = false;
|
||||
}
|
||||
}
|
||||
|
||||
private revokeFormImages(form: ReportFormModel): void {
|
||||
this.revokeImage(form.fotoImovel);
|
||||
this.revokeImages(form.fotosPesquisa);
|
||||
|
||||
for (const block of [...form.inicioPesquisa, ...form.tecnicas]) {
|
||||
this.revokeImages(block.photos);
|
||||
}
|
||||
}
|
||||
|
||||
private revokeImage(image: UploadedImage | null): void {
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
URL.revokeObjectURL(image.objectUrl);
|
||||
}
|
||||
|
||||
private revokeImages(images: UploadedImage[]): void {
|
||||
for (const image of images) {
|
||||
this.revokeImage(image);
|
||||
}
|
||||
}
|
||||
|
||||
private saveBlob(blob: Blob, filename: string): void {
|
||||
const objectUrl = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = objectUrl;
|
||||
link.download = filename;
|
||||
link.click();
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
}
|
||||
|
||||
private createUiId(prefix: string): string {
|
||||
const base = prefix.toLowerCase().replace(/\s+/g, '-');
|
||||
const generated =
|
||||
globalThis.crypto?.randomUUID?.() ??
|
||||
`${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
||||
|
||||
return `${base}-${generated}`;
|
||||
}
|
||||
|
||||
private setStatus(message: string, tone: 'info' | 'success' | 'error'): void {
|
||||
this.statusMessage = message;
|
||||
this.statusTone = tone;
|
||||
}
|
||||
|
||||
private assertSupportedImage(file: File): void {
|
||||
const mimeType = file.type.toLowerCase();
|
||||
const extension = file.name.toLowerCase().split('.').pop() ?? '';
|
||||
|
||||
if (this.supportedMimeTypes.has(mimeType) || this.supportedExtensions.has(extension)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Formato de imagem nao suportado. Use PNG, JPG, GIF ou BMP.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,760 @@
|
||||
import {
|
||||
AlignmentType,
|
||||
BorderStyle,
|
||||
Document,
|
||||
ExternalHyperlink,
|
||||
Footer,
|
||||
Header,
|
||||
ImageRun,
|
||||
Packer,
|
||||
PageNumber,
|
||||
Paragraph,
|
||||
Table,
|
||||
TableCell,
|
||||
TableLayoutType,
|
||||
TableRow,
|
||||
TextRun,
|
||||
WidthType
|
||||
} from 'docx';
|
||||
|
||||
import {
|
||||
buildPresenceNarrative,
|
||||
collectSelectedMethods,
|
||||
CONCLUSION_PARAGRAPHS,
|
||||
ReportFormModel,
|
||||
splitParagraphs,
|
||||
TECHNICIAN_NAME,
|
||||
TECHNICIAN_NOTE,
|
||||
TechniqueBlock,
|
||||
UploadedImage
|
||||
} from './report.models';
|
||||
|
||||
type SupportedImageType = 'jpg' | 'png' | 'gif' | 'bmp';
|
||||
export type ReportBuildMode = 'preview' | 'download';
|
||||
|
||||
const HEADER_LOGO_PATH = 'brand-header.png';
|
||||
const HEADER_LOGO_SIZE = { width: 176, height: 33 };
|
||||
const FOOTER_PAGE_DROP_PATH = 'footer-page-drop-cropped.png';
|
||||
const FOOTER_PAGE_DROP_SIZE = { width: 31, height: 46 };
|
||||
const TEMPLATE_FOOTER_XML_PATH = 'template-footer1.xml';
|
||||
const TEMPLATE_FOOTER_RELS_PATH = 'template-footer1.xml.rels';
|
||||
const TEMPLATE_FOOTER_IMAGE_PATH = 'footer-page-drop.jpeg';
|
||||
const FOOTER_SITE_URL = 'https://v-aguatech.com';
|
||||
const FOOTER_LINK_CELL_WIDTH = 91;
|
||||
const FOOTER_PAGE_CELL_WIDTH = 9;
|
||||
const FOOTER_PAGE_NUMBER_OFFSET = -560;
|
||||
|
||||
let headerLogoDataPromise: Promise<ArrayBuffer> | null = null;
|
||||
let footerPageDropDataPromise: Promise<ArrayBuffer> | null = null;
|
||||
let templateFooterXmlPromise: Promise<string> | null = null;
|
||||
let templateFooterRelsPromise: Promise<string> | null = null;
|
||||
|
||||
export async function buildReportBlob(
|
||||
form: ReportFormModel,
|
||||
mode: ReportBuildMode = 'preview'
|
||||
): Promise<Blob> {
|
||||
const [header, footer] = await Promise.all([
|
||||
createDocumentHeader(),
|
||||
createDocumentFooter()
|
||||
]);
|
||||
const children: Array<Paragraph | Table> = [];
|
||||
const presenceNarrative = buildPresenceNarrative(form.presencas);
|
||||
|
||||
children.push(createSummaryTable(form));
|
||||
children.push(createSpacer(240));
|
||||
children.push(createTitle('Relatório da pesquisa não destrutiva de fugas'));
|
||||
|
||||
children.push(createSectionHeading('Descrição do imóvel'));
|
||||
children.push(
|
||||
createBodyParagraph(form.descricaoImovel || 'Sem descrição do imóvel preenchida.')
|
||||
);
|
||||
children.push(
|
||||
createLeadParagraph('Ano de construção: ', form.anoConstrucao || 'Por preencher')
|
||||
);
|
||||
|
||||
if (form.fotoImovel) {
|
||||
children.push(await createMainImageParagraph(form.fotoImovel));
|
||||
}
|
||||
|
||||
children.push(createSectionHeading('Presentes aquando da pesquisa'));
|
||||
|
||||
if (presenceNarrative.header) {
|
||||
children.push(createBodyParagraph(presenceNarrative.header));
|
||||
} else {
|
||||
children.push(createBodyParagraph('Sem presenças registadas.'));
|
||||
}
|
||||
|
||||
for (const detail of presenceNarrative.details) {
|
||||
children.push(createBodyParagraph(detail));
|
||||
}
|
||||
|
||||
children.push(createSectionHeading('Descrição da pesquisa'));
|
||||
|
||||
const descriptionParagraphs = splitParagraphs(form.descricaoPesquisa);
|
||||
if (descriptionParagraphs.length) {
|
||||
for (const paragraph of descriptionParagraphs) {
|
||||
children.push(createBodyParagraph(paragraph));
|
||||
}
|
||||
} else {
|
||||
children.push(createBodyParagraph('Sem descrição da pesquisa preenchida.'));
|
||||
}
|
||||
|
||||
if (form.fotosPesquisa.length) {
|
||||
children.push(...(await createImageGalleryParagraphs(form.fotosPesquisa, 260, 180)));
|
||||
}
|
||||
|
||||
children.push(createLeadParagraph('Área do espaço: ', `${form.area || 'Por preencher'} m²`));
|
||||
|
||||
children.push(createSectionHeading('Início da pesquisa'));
|
||||
const introBlocks = form.inicioPesquisa.filter((item) => !!item.name.trim());
|
||||
if (introBlocks.length) {
|
||||
children.push(...(await createTechniqueParagraphs(introBlocks)));
|
||||
} else {
|
||||
children.push(createBodyParagraph('Nenhum item selecionado.'));
|
||||
}
|
||||
|
||||
children.push(createSectionHeading('Levantamento de danos'));
|
||||
const damageBlocks = form.tecnicas.filter((item) => !!item.name.trim());
|
||||
if (damageBlocks.length) {
|
||||
children.push(...(await createTechniqueParagraphs(damageBlocks)));
|
||||
} else {
|
||||
children.push(createBodyParagraph('Nenhum item selecionado.'));
|
||||
}
|
||||
|
||||
children.push(createSectionHeading('Conclusão'));
|
||||
for (const paragraph of CONCLUSION_PARAGRAPHS) {
|
||||
children.push(createBodyParagraph(paragraph));
|
||||
}
|
||||
|
||||
children.push(createSectionHeading('Informações gerais do técnico'));
|
||||
children.push(createBodyParagraph(TECHNICIAN_NOTE));
|
||||
|
||||
children.push(createSectionHeading('Métodos utilizados'));
|
||||
const methods = collectSelectedMethods(form);
|
||||
if (methods.length) {
|
||||
for (const method of methods) {
|
||||
children.push(createMethodParagraph(method));
|
||||
}
|
||||
} else {
|
||||
children.push(createBodyParagraph('Sem métodos assinalados.'));
|
||||
}
|
||||
|
||||
children.push(createSectionHeading('Técnico'));
|
||||
children.push(createLeadParagraph('', TECHNICIAN_NAME));
|
||||
|
||||
const wordDocument = new Document({
|
||||
creator: 'Codex',
|
||||
title: 'Relatório V-aguatech',
|
||||
description: 'Relatório da pesquisa não destrutiva de fugas',
|
||||
styles: {
|
||||
default: {
|
||||
document: {
|
||||
run: {
|
||||
font: 'Verdana',
|
||||
size: 20,
|
||||
color: '666666'
|
||||
},
|
||||
paragraph: {
|
||||
spacing: {
|
||||
line: 276
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
sections: [
|
||||
{
|
||||
properties: {
|
||||
page: {
|
||||
margin: {
|
||||
top: 1417,
|
||||
right: 1701,
|
||||
bottom: 1417,
|
||||
left: 1701,
|
||||
header: 708,
|
||||
footer: 708
|
||||
}
|
||||
}
|
||||
},
|
||||
headers: {
|
||||
default: header
|
||||
},
|
||||
footers: {
|
||||
default: footer
|
||||
},
|
||||
children
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const blob = await Packer.toBlob(wordDocument);
|
||||
if (mode === 'download') {
|
||||
return applyTemplateFooter(blob);
|
||||
}
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
export function buildOutputFilename(): string {
|
||||
const now = new Date();
|
||||
const date = [
|
||||
now.getFullYear(),
|
||||
pad(now.getMonth() + 1),
|
||||
pad(now.getDate())
|
||||
].join('-');
|
||||
const time = [pad(now.getHours()), pad(now.getMinutes()), pad(now.getSeconds())].join('-');
|
||||
|
||||
return `${date}_${time}.docx`;
|
||||
}
|
||||
|
||||
function createSummaryTable(form: ReportFormModel): Table {
|
||||
return new Table({
|
||||
width: {
|
||||
size: 100,
|
||||
type: WidthType.PERCENTAGE
|
||||
},
|
||||
layout: TableLayoutType.FIXED,
|
||||
borders: createTableBorders(),
|
||||
rows: [
|
||||
createSummaryRow('Nº do Processo', form.nproc, 'Segurado', form.segurado),
|
||||
createSummaryRow('Companhia', form.companhia, 'Terceiro', form.terceiro),
|
||||
createSummaryRow('Data da visita', form.dataVisita, 'Local da visita', form.localVisita)
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function createSummaryRow(
|
||||
leftLabel: string,
|
||||
leftValue: string,
|
||||
rightLabel: string,
|
||||
rightValue: string
|
||||
): TableRow {
|
||||
return new TableRow({
|
||||
children: [
|
||||
createSummaryCell(leftLabel, leftValue),
|
||||
createSummaryCell(rightLabel, rightValue)
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function createSummaryCell(label: string, value: string): TableCell {
|
||||
return new TableCell({
|
||||
width: {
|
||||
size: 50,
|
||||
type: WidthType.PERCENTAGE
|
||||
},
|
||||
children: [
|
||||
new Paragraph({
|
||||
spacing: {
|
||||
before: 120,
|
||||
after: 120
|
||||
},
|
||||
children: [
|
||||
new TextRun({
|
||||
text: `${label}: `,
|
||||
bold: true,
|
||||
color: '808080'
|
||||
}),
|
||||
new TextRun({
|
||||
text: value || 'Por preencher',
|
||||
color: value ? '666666' : '9A9A9A'
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function createTitle(text: string): Paragraph {
|
||||
return new Paragraph({
|
||||
spacing: {
|
||||
after: 240
|
||||
},
|
||||
children: [
|
||||
new TextRun({
|
||||
text,
|
||||
bold: true,
|
||||
color: '4A66AC',
|
||||
size: 28
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function createSectionHeading(text: string): Paragraph {
|
||||
return new Paragraph({
|
||||
spacing: {
|
||||
before: 220,
|
||||
after: 120
|
||||
},
|
||||
children: [
|
||||
new TextRun({
|
||||
text,
|
||||
bold: true,
|
||||
italics: true,
|
||||
color: '4A66AC'
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function createLeadParagraph(label: string, value: string): Paragraph {
|
||||
return new Paragraph({
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
children: [
|
||||
new TextRun({
|
||||
text: label,
|
||||
bold: !!label,
|
||||
color: label ? '4A66AC' : '666666'
|
||||
}),
|
||||
new TextRun({
|
||||
text: value,
|
||||
color: value === 'Por preencher' ? '9A9A9A' : '666666'
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function createBodyParagraph(text: string): Paragraph {
|
||||
return new Paragraph({
|
||||
alignment: AlignmentType.JUSTIFIED,
|
||||
spacing: {
|
||||
after: 80
|
||||
},
|
||||
children: [
|
||||
new TextRun({
|
||||
text,
|
||||
color: '666666'
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function createMethodParagraph(text: string): Paragraph {
|
||||
return new Paragraph({
|
||||
bullet: {
|
||||
level: 0
|
||||
},
|
||||
spacing: {
|
||||
after: 50
|
||||
},
|
||||
children: [
|
||||
new TextRun({
|
||||
text,
|
||||
color: '666666'
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async function createDocumentHeader(): Promise<Header> {
|
||||
const logoData = await loadHeaderLogoData();
|
||||
|
||||
return new Header({
|
||||
children: [
|
||||
new Paragraph({
|
||||
alignment: AlignmentType.RIGHT,
|
||||
spacing: {
|
||||
after: 0
|
||||
},
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: 'png',
|
||||
data: logoData,
|
||||
transformation: HEADER_LOGO_SIZE
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async function createDocumentFooter(): Promise<Footer> {
|
||||
const pageDropData = await loadFooterPageDropData();
|
||||
|
||||
return new Footer({
|
||||
children: [
|
||||
new Table({
|
||||
width: {
|
||||
size: 100,
|
||||
type: WidthType.PERCENTAGE
|
||||
},
|
||||
layout: TableLayoutType.FIXED,
|
||||
borders: createBorderlessTableBorders(),
|
||||
rows: [
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
width: {
|
||||
size: FOOTER_LINK_CELL_WIDTH,
|
||||
type: WidthType.PERCENTAGE
|
||||
},
|
||||
borders: createBorderlessTableBorders(),
|
||||
children: [
|
||||
new Paragraph({
|
||||
spacing: {
|
||||
before: 0,
|
||||
after: 0
|
||||
},
|
||||
children: [
|
||||
new ExternalHyperlink({
|
||||
link: FOOTER_SITE_URL,
|
||||
children: [
|
||||
new TextRun({
|
||||
text: FOOTER_SITE_URL,
|
||||
color: '4A66AC',
|
||||
size: 18
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
}),
|
||||
new TableCell({
|
||||
width: {
|
||||
size: FOOTER_PAGE_CELL_WIDTH,
|
||||
type: WidthType.PERCENTAGE
|
||||
},
|
||||
borders: createBorderlessTableBorders(),
|
||||
children: [
|
||||
new Paragraph({
|
||||
alignment: AlignmentType.CENTER,
|
||||
spacing: {
|
||||
before: 0,
|
||||
after: 0
|
||||
},
|
||||
children: [
|
||||
new ImageRun({
|
||||
type: 'png',
|
||||
data: pageDropData,
|
||||
transformation: FOOTER_PAGE_DROP_SIZE
|
||||
})
|
||||
]
|
||||
}),
|
||||
new Paragraph({
|
||||
alignment: AlignmentType.CENTER,
|
||||
spacing: {
|
||||
before: FOOTER_PAGE_NUMBER_OFFSET,
|
||||
after: 0
|
||||
},
|
||||
children: [
|
||||
new TextRun({
|
||||
color: 'FFFFFF',
|
||||
bold: true,
|
||||
size: 20,
|
||||
children: [PageNumber.CURRENT]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async function createMainImageParagraph(image: UploadedImage): Promise<Paragraph> {
|
||||
const imageRun = await createImageRun(image, 620, 360);
|
||||
return new Paragraph({
|
||||
alignment: AlignmentType.CENTER,
|
||||
spacing: {
|
||||
before: 120,
|
||||
after: 160
|
||||
},
|
||||
children: [imageRun]
|
||||
});
|
||||
}
|
||||
|
||||
async function createTechniqueParagraphs(blocks: TechniqueBlock[]): Promise<Paragraph[]> {
|
||||
const paragraphs: Paragraph[] = [];
|
||||
|
||||
for (const block of blocks) {
|
||||
paragraphs.push(
|
||||
new Paragraph({
|
||||
spacing: {
|
||||
before: 140,
|
||||
after: 60
|
||||
},
|
||||
children: [
|
||||
new TextRun({
|
||||
text: block.name,
|
||||
bold: true,
|
||||
color: '4A66AC',
|
||||
size: 22
|
||||
})
|
||||
]
|
||||
})
|
||||
);
|
||||
|
||||
if (block.description.trim()) {
|
||||
for (const paragraph of splitParagraphs(block.description)) {
|
||||
paragraphs.push(createBodyParagraph(paragraph));
|
||||
}
|
||||
}
|
||||
|
||||
if (block.photos.length) {
|
||||
paragraphs.push(...(await createImageGalleryParagraphs(block.photos, 240, 180)));
|
||||
}
|
||||
}
|
||||
|
||||
return paragraphs;
|
||||
}
|
||||
|
||||
async function createImageGalleryParagraphs(
|
||||
images: UploadedImage[],
|
||||
maxWidth: number,
|
||||
maxHeight: number
|
||||
): Promise<Paragraph[]> {
|
||||
const paragraphs: Paragraph[] = [];
|
||||
|
||||
for (let index = 0; index < images.length; index += 2) {
|
||||
const currentRow = images.slice(index, index + 2);
|
||||
const children: Array<TextRun | ImageRun> = [];
|
||||
|
||||
for (let imageIndex = 0; imageIndex < currentRow.length; imageIndex += 1) {
|
||||
const image = currentRow[imageIndex];
|
||||
if (!image) {
|
||||
continue;
|
||||
}
|
||||
|
||||
children.push(await createImageRun(image, maxWidth, maxHeight));
|
||||
|
||||
if (imageIndex < currentRow.length - 1) {
|
||||
children.push(
|
||||
new TextRun({
|
||||
text: ' '
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
paragraphs.push(
|
||||
new Paragraph({
|
||||
alignment: AlignmentType.CENTER,
|
||||
spacing: {
|
||||
before: 80,
|
||||
after: 120
|
||||
},
|
||||
children
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return paragraphs;
|
||||
}
|
||||
|
||||
async function createImageRun(
|
||||
image: UploadedImage,
|
||||
maxWidth: number,
|
||||
maxHeight: number
|
||||
): Promise<ImageRun> {
|
||||
const data = await image.file.arrayBuffer();
|
||||
const size = scaleDimensions(image.width, image.height, maxWidth, maxHeight);
|
||||
const type = getImageType(image.file);
|
||||
|
||||
return new ImageRun({
|
||||
type,
|
||||
data,
|
||||
transformation: size
|
||||
});
|
||||
}
|
||||
|
||||
function scaleDimensions(
|
||||
width: number,
|
||||
height: number,
|
||||
maxWidth: number,
|
||||
maxHeight: number
|
||||
): { width: number; height: number } {
|
||||
if (width <= maxWidth && height <= maxHeight) {
|
||||
return { width, height };
|
||||
}
|
||||
|
||||
const ratio = Math.min(maxWidth / width, maxHeight / height);
|
||||
return {
|
||||
width: Math.max(1, Math.round(width * ratio)),
|
||||
height: Math.max(1, Math.round(height * ratio))
|
||||
};
|
||||
}
|
||||
|
||||
function createSpacer(after: number): Paragraph {
|
||||
return new Paragraph({
|
||||
spacing: {
|
||||
after
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createTableBorders() {
|
||||
return {
|
||||
top: { style: BorderStyle.SINGLE, size: 4, color: '4A66AC' },
|
||||
bottom: { style: BorderStyle.SINGLE, size: 4, color: '4A66AC' },
|
||||
left: { style: BorderStyle.SINGLE, size: 4, color: '4A66AC' },
|
||||
right: { style: BorderStyle.SINGLE, size: 4, color: '4A66AC' },
|
||||
insideHorizontal: { style: BorderStyle.SINGLE, size: 4, color: '4A66AC' },
|
||||
insideVertical: { style: BorderStyle.SINGLE, size: 4, color: '4A66AC' }
|
||||
};
|
||||
}
|
||||
|
||||
function createBorderlessTableBorders() {
|
||||
return {
|
||||
top: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
|
||||
bottom: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
|
||||
left: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
|
||||
right: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
|
||||
insideHorizontal: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
|
||||
insideVertical: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' }
|
||||
};
|
||||
}
|
||||
|
||||
function pad(value: number): string {
|
||||
return value.toString().padStart(2, '0');
|
||||
}
|
||||
|
||||
async function loadHeaderLogoData(): Promise<ArrayBuffer> {
|
||||
if (!headerLogoDataPromise) {
|
||||
headerLogoDataPromise = loadPublicAssetData(HEADER_LOGO_PATH, 'logo do cabecalho').catch(
|
||||
(error) => {
|
||||
headerLogoDataPromise = null;
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return headerLogoDataPromise;
|
||||
}
|
||||
|
||||
async function loadFooterPageDropData(): Promise<ArrayBuffer> {
|
||||
if (!footerPageDropDataPromise) {
|
||||
footerPageDropDataPromise = loadPublicAssetData(
|
||||
FOOTER_PAGE_DROP_PATH,
|
||||
'imagem do footer'
|
||||
).catch((error) => {
|
||||
footerPageDropDataPromise = null;
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
return footerPageDropDataPromise;
|
||||
}
|
||||
|
||||
async function loadTemplateFooterXml(): Promise<string> {
|
||||
if (!templateFooterXmlPromise) {
|
||||
templateFooterXmlPromise = loadPublicTextAsset(
|
||||
TEMPLATE_FOOTER_XML_PATH,
|
||||
'template XML do footer'
|
||||
).catch((error) => {
|
||||
templateFooterXmlPromise = null;
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
return templateFooterXmlPromise;
|
||||
}
|
||||
|
||||
async function loadTemplateFooterRels(): Promise<string> {
|
||||
if (!templateFooterRelsPromise) {
|
||||
templateFooterRelsPromise = loadPublicTextAsset(
|
||||
TEMPLATE_FOOTER_RELS_PATH,
|
||||
'template de relacoes do footer'
|
||||
).catch((error) => {
|
||||
templateFooterRelsPromise = null;
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
return templateFooterRelsPromise;
|
||||
}
|
||||
|
||||
async function loadPublicAssetData(assetPath: string, assetLabel: string): Promise<ArrayBuffer> {
|
||||
const baseUri = globalThis.document?.baseURI ?? globalThis.location?.href;
|
||||
if (!baseUri) {
|
||||
throw new Error(`Nao foi possivel resolver ${assetLabel}.`);
|
||||
}
|
||||
|
||||
const assetUrl = new URL(assetPath, baseUri).toString();
|
||||
const response = await fetch(assetUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Nao foi possivel carregar ${assetLabel} (${response.status}).`);
|
||||
}
|
||||
|
||||
return response.arrayBuffer();
|
||||
}
|
||||
|
||||
async function loadPublicTextAsset(assetPath: string, assetLabel: string): Promise<string> {
|
||||
const baseUri = globalThis.document?.baseURI ?? globalThis.location?.href;
|
||||
if (!baseUri) {
|
||||
throw new Error(`Nao foi possivel resolver ${assetLabel}.`);
|
||||
}
|
||||
|
||||
const assetUrl = new URL(assetPath, baseUri).toString();
|
||||
const response = await fetch(assetUrl);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Nao foi possivel carregar ${assetLabel} (${response.status}).`);
|
||||
}
|
||||
|
||||
return response.text();
|
||||
}
|
||||
|
||||
async function applyTemplateFooter(blob: Blob): Promise<Blob> {
|
||||
const [{ default: JSZip }, footerXml, footerRels, footerImage] = await Promise.all([
|
||||
import('jszip'),
|
||||
loadTemplateFooterXml(),
|
||||
loadTemplateFooterRels(),
|
||||
loadPublicAssetData(TEMPLATE_FOOTER_IMAGE_PATH, 'imagem original do footer')
|
||||
]);
|
||||
|
||||
const zip = await JSZip.loadAsync(await blob.arrayBuffer());
|
||||
zip.file('word/footer1.xml', footerXml);
|
||||
zip.file('word/_rels/footer1.xml.rels', footerRels);
|
||||
zip.file('word/media/image2.jpeg', footerImage);
|
||||
|
||||
const contentTypesEntry = zip.file('[Content_Types].xml');
|
||||
if (contentTypesEntry) {
|
||||
const contentTypesXml = await contentTypesEntry.async('string');
|
||||
if (!contentTypesXml.includes('Extension="jpeg"')) {
|
||||
const patchedContentTypesXml = contentTypesXml.replace(
|
||||
'</Types>',
|
||||
'<Default Extension="jpeg" ContentType="image/jpeg"/></Types>'
|
||||
);
|
||||
zip.file('[Content_Types].xml', patchedContentTypesXml);
|
||||
}
|
||||
}
|
||||
|
||||
return zip.generateAsync({ type: 'blob' });
|
||||
}
|
||||
|
||||
function getImageType(file: File): SupportedImageType {
|
||||
const mimeType = file.type.toLowerCase();
|
||||
if (mimeType === 'image/png') {
|
||||
return 'png';
|
||||
}
|
||||
if (mimeType === 'image/jpeg' || mimeType === 'image/jpg') {
|
||||
return 'jpg';
|
||||
}
|
||||
if (mimeType === 'image/gif') {
|
||||
return 'gif';
|
||||
}
|
||||
if (mimeType === 'image/bmp') {
|
||||
return 'bmp';
|
||||
}
|
||||
|
||||
const extension = file.name.toLowerCase().split('.').pop();
|
||||
if (extension === 'png') {
|
||||
return 'png';
|
||||
}
|
||||
if (extension === 'jpg' || extension === 'jpeg') {
|
||||
return 'jpg';
|
||||
}
|
||||
if (extension === 'gif') {
|
||||
return 'gif';
|
||||
}
|
||||
if (extension === 'bmp') {
|
||||
return 'bmp';
|
||||
}
|
||||
|
||||
throw new Error('Formato de imagem não suportado. Use PNG, JPG, GIF ou BMP.');
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
export type PresenceType = 'segurado' | 'lesado';
|
||||
|
||||
export interface UploadedImage {
|
||||
id: string;
|
||||
file: File;
|
||||
name: string;
|
||||
objectUrl: string;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface TechniqueBlock {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
photos: UploadedImage[];
|
||||
}
|
||||
|
||||
export interface PresenceEntry {
|
||||
id: string;
|
||||
type: PresenceType;
|
||||
name: string;
|
||||
info: string;
|
||||
}
|
||||
|
||||
export interface ReportFormModel {
|
||||
nproc: string;
|
||||
segurado: string;
|
||||
companhia: string;
|
||||
terceiro: string;
|
||||
dataVisita: string;
|
||||
localVisita: string;
|
||||
descricaoImovel: string;
|
||||
anoConstrucao: string;
|
||||
descricaoPesquisa: string;
|
||||
area: string;
|
||||
fotoImovel: UploadedImage | null;
|
||||
fotosPesquisa: UploadedImage[];
|
||||
presencas: PresenceEntry[];
|
||||
inicioPesquisa: TechniqueBlock[];
|
||||
tecnicas: TechniqueBlock[];
|
||||
}
|
||||
|
||||
export interface PresenceNarrative {
|
||||
header: string | null;
|
||||
details: string[];
|
||||
}
|
||||
|
||||
export interface PresenceSection {
|
||||
type: PresenceType;
|
||||
title: string;
|
||||
buttonLabel: string;
|
||||
singularLabel: string;
|
||||
}
|
||||
|
||||
export const PRESENCE_SECTIONS: PresenceSection[] = [
|
||||
{
|
||||
type: 'segurado',
|
||||
title: 'Segurados',
|
||||
buttonLabel: 'Adicionar segurado',
|
||||
singularLabel: 'segurado'
|
||||
},
|
||||
{
|
||||
type: 'lesado',
|
||||
title: 'Lesados',
|
||||
buttonLabel: 'Adicionar lesado',
|
||||
singularLabel: 'lesado'
|
||||
}
|
||||
];
|
||||
|
||||
export const TECHNIQUE_OPTIONS = [
|
||||
'Controlo Visual',
|
||||
'Medição de humidade',
|
||||
'Câmara térmica',
|
||||
'Câmara endoscópica',
|
||||
'Obturação',
|
||||
'Teste de pressão',
|
||||
'Teste com corantes'
|
||||
];
|
||||
|
||||
export const CONCLUSION_PARAGRAPHS = [
|
||||
'Resumo breve e sucinto das constatações e resultados.',
|
||||
'Visto que as tubagens passam em calhas/galerias/coretes, é difícil determinar a localização exata da fuga, uma vez que o gás se expande pelas calhas/galerias/coretes.',
|
||||
'As vibrações acústicas que resultam da fuga propagam-se pelas calhas/galerias/coretes.',
|
||||
'O ruído da fuga é demasiadamente baixo para ser detetado com o Detector Electroacústico.',
|
||||
'Existe uma perda de pressão entre 1 e 1,5 bar por dia; serão necessárias algumas horas para se efetuar uma deteção via Aquaphon/câmara térmica.'
|
||||
];
|
||||
|
||||
export const TECHNICIAN_NOTE =
|
||||
'Assim que a causa da fuga esteja reparada, recomenda-se uma espera de tempo adequado, de acordo com as especificações dos materiais utilizados, antes de se avançar com as reparações dos danos, tendo em conta os tempos de secagem.';
|
||||
|
||||
export const TECHNICIAN_NAME = 'Vítor Gomes';
|
||||
|
||||
export function createInitialReportForm(): ReportFormModel {
|
||||
return {
|
||||
nproc: '',
|
||||
segurado: '',
|
||||
companhia: '',
|
||||
terceiro: '',
|
||||
dataVisita: '',
|
||||
localVisita: '',
|
||||
descricaoImovel: '',
|
||||
anoConstrucao: '',
|
||||
descricaoPesquisa: '',
|
||||
area: '',
|
||||
fotoImovel: null,
|
||||
fotosPesquisa: [],
|
||||
presencas: [createPresenceEntry('segurado')],
|
||||
inicioPesquisa: [createTechniqueBlock()],
|
||||
tecnicas: [createTechniqueBlock()]
|
||||
};
|
||||
}
|
||||
|
||||
export function createPresenceEntry(type: PresenceType): PresenceEntry {
|
||||
return {
|
||||
id: createId(type),
|
||||
type,
|
||||
name: '',
|
||||
info: ''
|
||||
};
|
||||
}
|
||||
|
||||
export function splitParagraphs(value: string): string[] {
|
||||
return value
|
||||
.split(/\r?\n+/)
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
export function buildPresenceNarrative(presences: PresenceEntry[]): PresenceNarrative {
|
||||
const details: string[] = [];
|
||||
const presentPeople: string[] = [];
|
||||
|
||||
for (const item of presences) {
|
||||
const name = item.name.trim();
|
||||
const info = item.info.trim();
|
||||
|
||||
if (!name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.type === 'segurado') {
|
||||
presentPeople.push(`o segurado, ${name}`);
|
||||
if (info) {
|
||||
details.push(`O segurado, ${name} informou que ${info}.`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.type === 'lesado') {
|
||||
presentPeople.push(`o lesado, ${name}`);
|
||||
if (info) {
|
||||
details.push(`O lesado, ${name} informou que ${info}.`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!presentPeople.length) {
|
||||
return {
|
||||
header: null,
|
||||
details
|
||||
};
|
||||
}
|
||||
|
||||
const joined = joinPeople(presentPeople);
|
||||
const header =
|
||||
presentPeople.length === 1
|
||||
? `${joined} esteve presente aquando a pesquisa.`
|
||||
: `${joined} estiveram presentes aquando a pesquisa.`;
|
||||
|
||||
return {
|
||||
header,
|
||||
details
|
||||
};
|
||||
}
|
||||
|
||||
export function collectSelectedMethods(form: ReportFormModel): string[] {
|
||||
const methods: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
|
||||
for (const group of [form.inicioPesquisa, form.tecnicas]) {
|
||||
for (const item of group) {
|
||||
const name = item.name.trim();
|
||||
if (!name || seen.has(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seen.add(name);
|
||||
methods.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
export function createTechniqueBlock(name = ''): TechniqueBlock {
|
||||
return {
|
||||
id: createId(name || 'metodo'),
|
||||
name,
|
||||
description: '',
|
||||
photos: []
|
||||
};
|
||||
}
|
||||
|
||||
function createId(prefix: string): string {
|
||||
const safePrefix = (prefix || 'item').toLowerCase().replace(/\s+/g, '-');
|
||||
const generated =
|
||||
globalThis.crypto?.randomUUID?.() ??
|
||||
`${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
||||
|
||||
return `${safePrefix}-${generated}`;
|
||||
}
|
||||
|
||||
function joinPeople(items: string[]): string {
|
||||
if (items.length === 1) {
|
||||
return items[0];
|
||||
}
|
||||
|
||||
return `${items.slice(0, -1).join(', ')} e ${items.at(-1)}`;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>VAguatechAngular</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { appConfig } from './app/app.config';
|
||||
import { App } from './app/app';
|
||||
|
||||
bootstrapApplication(App, appConfig)
|
||||
.catch((err) => console.error(err));
|
||||
+679
@@ -0,0 +1,679 @@
|
||||
:root {
|
||||
--bg: #ede8dc;
|
||||
--panel: rgba(250, 247, 239, 0.92);
|
||||
--paper: #fffdfa;
|
||||
--line: rgba(102, 102, 102, 0.16);
|
||||
--ink: #27313a;
|
||||
--muted: #66707a;
|
||||
--accent: #4a66ac;
|
||||
--accent-soft: rgba(74, 102, 172, 0.12);
|
||||
--accent-strong: #39518d;
|
||||
--gold: #d1ad66;
|
||||
--success: #357756;
|
||||
--error: #a04637;
|
||||
--shadow: 0 28px 60px rgba(30, 42, 68, 0.14);
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(209, 173, 102, 0.32), transparent 32%),
|
||||
radial-gradient(circle at top right, rgba(74, 102, 172, 0.18), transparent 28%),
|
||||
linear-gradient(180deg, #f4efe5 0%, #ebe5d7 100%);
|
||||
color: var(--ink);
|
||||
font-family: 'Bahnschrift', 'Trebuchet MS', 'Segoe UI', sans-serif;
|
||||
}
|
||||
|
||||
app-root {
|
||||
display: block;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
textarea,
|
||||
select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.workspace {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(340px, 1fr) minmax(0, 2fr);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.workspace__controls,
|
||||
.workspace__preview {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.workspace__controls {
|
||||
background: linear-gradient(180deg, rgba(255, 253, 248, 0.95), rgba(246, 240, 226, 0.94));
|
||||
border-right: 1px solid rgba(74, 102, 172, 0.14);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.workspace__preview {
|
||||
overflow-y: auto;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(74, 102, 172, 0.08), transparent 40%),
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.48), rgba(250, 246, 237, 0.82));
|
||||
}
|
||||
|
||||
.panel-head {
|
||||
margin-bottom: 1.5rem;
|
||||
max-width: 30rem;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 0.4rem;
|
||||
color: var(--accent-strong);
|
||||
font-size: 0.8rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.panel-head h1,
|
||||
.preview-head h2 {
|
||||
margin: 0;
|
||||
font-size: clamp(2rem, 1.3rem + 2vw, 3.25rem);
|
||||
font-weight: 800;
|
||||
line-height: 0.96;
|
||||
letter-spacing: -0.05em;
|
||||
}
|
||||
|
||||
.intro,
|
||||
.preview-note,
|
||||
.section-head p,
|
||||
.upload-row p,
|
||||
.group-head p,
|
||||
.status,
|
||||
.empty-state {
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.action-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.85rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
min-height: 2.9rem;
|
||||
padding: 0.8rem 1.15rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.01em;
|
||||
transition:
|
||||
transform 160ms ease,
|
||||
box-shadow 160ms ease,
|
||||
background-color 160ms ease,
|
||||
border-color 160ms ease;
|
||||
}
|
||||
|
||||
.button:hover:not(:disabled) {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.button:disabled,
|
||||
.button.is-disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.button--primary {
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-strong));
|
||||
box-shadow: 0 14px 28px rgba(74, 102, 172, 0.24);
|
||||
}
|
||||
|
||||
.button--ghost {
|
||||
color: var(--accent-strong);
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
border-color: rgba(74, 102, 172, 0.2);
|
||||
}
|
||||
|
||||
.button--soft {
|
||||
position: relative;
|
||||
color: var(--accent-strong);
|
||||
background: var(--accent-soft);
|
||||
}
|
||||
|
||||
.button--small {
|
||||
min-height: 2.3rem;
|
||||
padding-inline: 0.95rem;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 0.9rem 1rem;
|
||||
border: 1px solid rgba(74, 102, 172, 0.12);
|
||||
border-radius: 1rem;
|
||||
background: rgba(255, 255, 255, 0.58);
|
||||
}
|
||||
|
||||
.status.is-success {
|
||||
color: var(--success);
|
||||
border-color: rgba(53, 119, 86, 0.18);
|
||||
background: rgba(53, 119, 86, 0.08);
|
||||
}
|
||||
|
||||
.status.is-error {
|
||||
color: var(--error);
|
||||
border-color: rgba(160, 70, 55, 0.18);
|
||||
background: rgba(160, 70, 55, 0.08);
|
||||
}
|
||||
|
||||
.form-card {
|
||||
max-width: 30rem;
|
||||
margin-bottom: 1rem;
|
||||
padding: 1.2rem;
|
||||
border: 1px solid rgba(74, 102, 172, 0.12);
|
||||
border-radius: 1.3rem;
|
||||
background: var(--panel);
|
||||
box-shadow: 0 14px 30px rgba(38, 52, 80, 0.06);
|
||||
}
|
||||
|
||||
.section-head {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.section-head h2,
|
||||
.group-head h3 {
|
||||
margin: 0 0 0.2rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.field-grid,
|
||||
.tech-grid {
|
||||
display: grid;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
.field-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.field {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.field span {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.field--full {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.field input,
|
||||
.field textarea,
|
||||
.field select {
|
||||
width: 100%;
|
||||
border: 1px solid rgba(74, 102, 172, 0.16);
|
||||
border-radius: 0.95rem;
|
||||
padding: 0.85rem 0.95rem;
|
||||
color: var(--ink);
|
||||
background: rgba(255, 255, 255, 0.78);
|
||||
transition:
|
||||
border-color 150ms ease,
|
||||
box-shadow 150ms ease,
|
||||
background-color 150ms ease;
|
||||
}
|
||||
|
||||
.field textarea {
|
||||
min-height: 6rem;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.field select {
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.field input:focus,
|
||||
.field textarea:focus,
|
||||
.field select:focus {
|
||||
outline: none;
|
||||
border-color: rgba(74, 102, 172, 0.55);
|
||||
box-shadow: 0 0 0 4px rgba(74, 102, 172, 0.12);
|
||||
background: white;
|
||||
}
|
||||
|
||||
.upload-block + .upload-block,
|
||||
.presence-group + .presence-group {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.upload-block,
|
||||
.presence-card,
|
||||
.tech-card {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 1rem;
|
||||
background: rgba(255, 255, 255, 0.66);
|
||||
}
|
||||
|
||||
.upload-block,
|
||||
.presence-card {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.upload-row,
|
||||
.group-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.upload-row strong,
|
||||
.thumb-card__meta strong {
|
||||
display: block;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.thumb-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.75rem;
|
||||
margin-top: 0.9rem;
|
||||
}
|
||||
|
||||
.thumb-list--single {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.thumb-card {
|
||||
overflow: hidden;
|
||||
border-radius: 0.9rem;
|
||||
border: 1px solid rgba(74, 102, 172, 0.12);
|
||||
background: white;
|
||||
}
|
||||
|
||||
.thumb-card img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.thumb-card__meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 0.8rem;
|
||||
align-items: center;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.link-button {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--accent-strong);
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.link-button--danger {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.presence-card {
|
||||
display: grid;
|
||||
gap: 0.8rem;
|
||||
margin-top: 0.85rem;
|
||||
}
|
||||
|
||||
.group-head--section {
|
||||
margin-bottom: 1rem;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tech-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.tech-card {
|
||||
display: grid;
|
||||
gap: 0.95rem;
|
||||
width: 100%;
|
||||
padding: 1.1rem;
|
||||
transition:
|
||||
border-color 160ms ease,
|
||||
transform 160ms ease,
|
||||
box-shadow 160ms ease;
|
||||
}
|
||||
|
||||
.tech-card.is-selected {
|
||||
border-color: rgba(74, 102, 172, 0.32);
|
||||
box-shadow: 0 18px 36px rgba(74, 102, 172, 0.1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.tech-card__top {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 0.9rem;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.tech-card__top .link-button {
|
||||
justify-self: end;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tech-card .upload-row {
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tech-card .thumb-list {
|
||||
grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
|
||||
}
|
||||
|
||||
.preview-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
align-items: end;
|
||||
max-width: 72rem;
|
||||
margin: 0 auto 1.5rem;
|
||||
}
|
||||
|
||||
.word-preview-shell {
|
||||
max-width: 72rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.word-preview-styles {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.preview-banner {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.7rem;
|
||||
margin: 0 0 1rem;
|
||||
padding: 0.85rem 1rem;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.82);
|
||||
color: var(--accent-strong);
|
||||
font-weight: 700;
|
||||
box-shadow: 0 12px 24px rgba(38, 52, 80, 0.08);
|
||||
}
|
||||
|
||||
.preview-banner--error {
|
||||
color: var(--error);
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
}
|
||||
|
||||
.preview-dot {
|
||||
inline-size: 0.7rem;
|
||||
block-size: 0.7rem;
|
||||
border-radius: 999px;
|
||||
background: var(--accent);
|
||||
animation: preview-pulse 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.word-preview-host {
|
||||
min-height: 75vh;
|
||||
}
|
||||
|
||||
.word-preview-host .docx-wrapper {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.word-preview-host .docx-wrapper .docx {
|
||||
margin-bottom: 1.75rem;
|
||||
box-shadow: 0 28px 60px rgba(30, 42, 68, 0.14);
|
||||
}
|
||||
|
||||
.page {
|
||||
max-width: 54rem;
|
||||
margin: 0 auto;
|
||||
padding: 2.75rem 3rem;
|
||||
border-radius: 1.6rem;
|
||||
background: linear-gradient(180deg, #fffefb, #fffdfa);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.report-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(74, 102, 172, 0.28);
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.summary-cell {
|
||||
padding: 1rem 1.1rem;
|
||||
border-right: 1px solid rgba(74, 102, 172, 0.16);
|
||||
border-bottom: 1px solid rgba(74, 102, 172, 0.16);
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(244, 248, 255, 0.8));
|
||||
}
|
||||
|
||||
.summary-cell:nth-child(2n) {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.summary-cell:nth-last-child(-n + 2) {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.summary-cell span {
|
||||
display: block;
|
||||
margin-bottom: 0.25rem;
|
||||
color: #788194;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.summary-cell strong {
|
||||
display: block;
|
||||
color: var(--ink);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.report-header {
|
||||
margin: 2rem 0 1.6rem;
|
||||
}
|
||||
|
||||
.report-kicker {
|
||||
margin: 0 0 0.45rem;
|
||||
color: var(--gold);
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.report-header h3 {
|
||||
margin: 0;
|
||||
color: var(--accent);
|
||||
font-size: clamp(1.8rem, 1.2rem + 1.7vw, 2.5rem);
|
||||
line-height: 1.04;
|
||||
letter-spacing: -0.05em;
|
||||
}
|
||||
|
||||
.report-section {
|
||||
margin-top: 1.8rem;
|
||||
color: #5f646c;
|
||||
font-family: 'Palatino Linotype', 'Book Antiqua', Georgia, serif;
|
||||
}
|
||||
|
||||
.report-section h4,
|
||||
.method-block h5 {
|
||||
margin: 0 0 0.75rem;
|
||||
color: var(--accent);
|
||||
font-family: 'Bahnschrift', 'Trebuchet MS', 'Segoe UI', sans-serif;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.report-section h4 {
|
||||
font-size: 1.1rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.method-block {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.method-block h5 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.report-section p,
|
||||
.report-section li {
|
||||
margin: 0 0 0.8rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1.78;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.report-figure,
|
||||
.report-gallery__item {
|
||||
margin: 1rem 0 0;
|
||||
}
|
||||
|
||||
.report-figure img,
|
||||
.report-gallery__item img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-radius: 1rem;
|
||||
object-fit: cover;
|
||||
box-shadow: 0 18px 30px rgba(18, 26, 44, 0.1);
|
||||
}
|
||||
|
||||
.report-gallery {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 1rem;
|
||||
margin: 1rem 0 1.2rem;
|
||||
}
|
||||
|
||||
.method-list {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
|
||||
.report-section--signature p {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.is-placeholder {
|
||||
color: #9c9c9c;
|
||||
}
|
||||
|
||||
@media (max-width: 1220px) {
|
||||
.workspace {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.workspace__controls {
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid rgba(74, 102, 172, 0.14);
|
||||
}
|
||||
|
||||
.preview-head,
|
||||
.page {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.workspace__controls,
|
||||
.workspace__preview {
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
.field-grid,
|
||||
.thumb-list,
|
||||
.report-gallery,
|
||||
.report-summary {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.tech-card__top {
|
||||
grid-template-columns: 1fr;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.tech-card__top .link-button {
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.summary-cell {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.summary-cell:not(:last-child) {
|
||||
border-bottom: 1px solid rgba(74, 102, 172, 0.16);
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 1.5rem;
|
||||
border-radius: 1.2rem;
|
||||
}
|
||||
|
||||
.preview-head,
|
||||
.upload-row,
|
||||
.group-head {
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes preview-pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 0.35;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
|
||||
class App(tk.Tk):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.title("Navegacao entre Modulos")
|
||||
self.geometry("900x550")
|
||||
|
||||
sidebar = ttk.Frame(self, padding=10)
|
||||
sidebar.pack(side="left", fill="y")
|
||||
|
||||
self.content = ttk.Frame(self, padding=16)
|
||||
self.content.pack(side="left", fill="both", expand=True)
|
||||
|
||||
self.frames = {
|
||||
"Modulo 1": self._build_page("Modulo 1", "Conteudo do modulo 1"),
|
||||
"Modulo 2": self._build_page("Modulo 2", "Conteudo do modulo 2"),
|
||||
"Modulo 3": self._build_page("Modulo 3", "Conteudo do modulo 3"),
|
||||
}
|
||||
|
||||
for nome in self.frames:
|
||||
ttk.Button(sidebar, text=nome, command=lambda n=nome: self.show_page(n)).pack(
|
||||
fill="x", pady=4
|
||||
)
|
||||
|
||||
self.show_page("Modulo 1")
|
||||
|
||||
def _build_page(self, titulo: str, texto: str) -> ttk.Frame:
|
||||
frame = ttk.Frame(self.content)
|
||||
ttk.Label(frame, text=titulo, font=("Segoe UI", 16, "bold")).pack(anchor="w")
|
||||
ttk.Label(frame, text=texto).pack(anchor="w", pady=(10, 0))
|
||||
return frame
|
||||
|
||||
def show_page(self, nome: str):
|
||||
for frame in self.frames.values():
|
||||
frame.pack_forget()
|
||||
self.frames[nome].pack(fill="both", expand=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
App().mainloop()
|
||||
@@ -0,0 +1,15 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"src/**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"isolatedModules": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "preserve"
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
},
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": [
|
||||
"vitest/globals"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,778 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from datetime import datetime
|
||||
from docx import Document
|
||||
from tkinter import filedialog
|
||||
from PIL import Image
|
||||
import tempfile
|
||||
from docx.shared import Inches, Pt, RGBColor
|
||||
import io
|
||||
|
||||
|
||||
TEMPLATE_DOCX = "Corpus.docx"
|
||||
|
||||
def resource_path(relative_path: str) -> str:
|
||||
try:
|
||||
base_path = sys._MEIPASS
|
||||
except Exception:
|
||||
base_path = os.path.abspath(".")
|
||||
return os.path.join(base_path, relative_path)
|
||||
|
||||
def image_to_png_stream(image_path: str) -> io.BytesIO:
|
||||
with Image.open(image_path) as img:
|
||||
if img.mode not in ("RGB", "RGBA"):
|
||||
img = img.convert("RGB")
|
||||
bio = io.BytesIO()
|
||||
img.save(bio, format="PNG")
|
||||
bio.seek(0)
|
||||
return bio
|
||||
|
||||
|
||||
def insert_image_at_placeholder(doc: Document, placeholder: str, image_path: str, width_inches: float = 6.20) -> bool:
|
||||
if not image_path or not os.path.exists(image_path):
|
||||
return False
|
||||
try:
|
||||
img_stream = image_to_png_stream(image_path)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Não consegui abrir/convert a imagem:\n{image_path}\n\nDetalhes:\n{e}")
|
||||
|
||||
def replace_in_paragraph(p) -> bool:
|
||||
full_text = "".join(run.text for run in p.runs)
|
||||
if placeholder not in full_text:
|
||||
return False
|
||||
for r in p.runs:
|
||||
r.text = ""
|
||||
run = p.add_run()
|
||||
run.add_picture(img_stream, width=Inches(width_inches))
|
||||
return True
|
||||
for p in doc.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for section in doc.sections:
|
||||
for p in section.header.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for p in section.footer.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def insert_images_at_placeholders(doc: Document, placeholders: dict, width_inches: float = 6.20) -> list:
|
||||
missing = []
|
||||
for placeholder, image_path in placeholders.items():
|
||||
if not image_path:
|
||||
continue
|
||||
ok = insert_image_at_placeholder(doc, placeholder, image_path, width_inches=width_inches)
|
||||
if not ok:
|
||||
missing.append(placeholder)
|
||||
return missing
|
||||
|
||||
def insert_tecnicas_utilizadas(doc: Document, placeholder: str, tecnicas: list) -> bool:
|
||||
def replace_in_paragraph(p) -> bool:
|
||||
full_text = "".join(run.text for run in p.runs)
|
||||
if placeholder not in full_text:
|
||||
return False
|
||||
for r in p.runs:
|
||||
r.text = ""
|
||||
|
||||
first_block = True
|
||||
for t in tecnicas:
|
||||
if not t.get("selected"):
|
||||
continue
|
||||
nome = (t.get("name") or "").strip()
|
||||
desc = (t.get("desc") or "").strip()
|
||||
fotos = t.get("photos") or []
|
||||
|
||||
if not nome:
|
||||
continue
|
||||
if not first_block:
|
||||
p.add_run().add_break()
|
||||
p.add_run().add_break()
|
||||
|
||||
run_title = p.add_run(nome)
|
||||
run_title.font.name = "Verdana"
|
||||
run_title.font.size = Pt(11)
|
||||
run_title.font.color.rgb = RGBColor(0x4A, 0x66, 0xAC)
|
||||
p.add_run().add_break()
|
||||
|
||||
if desc:
|
||||
run_desc = p.add_run(desc)
|
||||
run_desc.font.name = "Verdana"
|
||||
run_desc.font.size = Pt(10)
|
||||
run_desc.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
|
||||
p.add_run().add_break()
|
||||
|
||||
if fotos:
|
||||
for i, image_path in enumerate(fotos):
|
||||
if not image_path or not os.path.exists(image_path):
|
||||
continue
|
||||
try:
|
||||
img_stream = image_to_png_stream(image_path)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Não consegui abrir/convert a imagem:\n{image_path}\n\nDetalhes:\n{e}")
|
||||
run_img = p.add_run()
|
||||
run_img.add_picture(img_stream, width=Inches(2.80))
|
||||
is_last = i == len(fotos) - 1
|
||||
if not is_last:
|
||||
if i % 2 == 0:
|
||||
p.add_run(" ")
|
||||
else:
|
||||
p.add_run().add_break()
|
||||
p.add_run().add_break()
|
||||
|
||||
first_block = False
|
||||
|
||||
return True
|
||||
|
||||
for p in doc.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for section in doc.sections:
|
||||
for p in section.header.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for p in section.footer.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def insert_metodos_utilizados(doc: Document, placeholder: str, values: dict) -> bool:
|
||||
items = []
|
||||
seen = set()
|
||||
for group_key in ("inicio_pesquisa", "tecnicas"):
|
||||
for t in values.get(group_key) or []:
|
||||
if not t.get("selected"):
|
||||
continue
|
||||
name = (t.get("name") or "").strip()
|
||||
if not name or name in seen:
|
||||
continue
|
||||
seen.add(name)
|
||||
items.append(name)
|
||||
|
||||
if not items:
|
||||
return False
|
||||
|
||||
def replace_in_paragraph(p) -> bool:
|
||||
full_text = "".join(run.text for run in p.runs)
|
||||
if placeholder not in full_text:
|
||||
return False
|
||||
for r in p.runs:
|
||||
r.text = ""
|
||||
|
||||
for i, name in enumerate(items):
|
||||
run = p.add_run(f"- {name}")
|
||||
run.font.name = "Verdana"
|
||||
run.font.size = Pt(10)
|
||||
run.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
|
||||
if i < len(items) - 1:
|
||||
p.add_run().add_break()
|
||||
return True
|
||||
|
||||
for p in doc.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for section in doc.sections:
|
||||
for p in section.header.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for p in section.footer.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
return False
|
||||
def insert_multiple_images_at_placeholder(doc: Document, placeholder: str, image_paths: list, width_inches: float = 2.80) -> bool:
|
||||
if not image_paths:
|
||||
return False
|
||||
|
||||
def replace_in_paragraph(p) -> bool:
|
||||
full_text = "".join(run.text for run in p.runs)
|
||||
if placeholder not in full_text:
|
||||
return False
|
||||
for r in p.runs:
|
||||
r.text = ""
|
||||
for i, image_path in enumerate(image_paths):
|
||||
if not image_path or not os.path.exists(image_path):
|
||||
continue
|
||||
try:
|
||||
img_stream = image_to_png_stream(image_path)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Não consegui abrir/convert a imagem:\n{image_path}\n\nDetalhes:\n{e}")
|
||||
run = p.add_run()
|
||||
run.add_picture(img_stream, width=Inches(width_inches))
|
||||
is_last = i == len(image_paths) - 1
|
||||
if not is_last:
|
||||
if i % 2 == 0:
|
||||
p.add_run(" ")
|
||||
else:
|
||||
p.add_run().add_break()
|
||||
return True
|
||||
|
||||
for p in doc.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for section in doc.sections:
|
||||
for p in section.header.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for p in section.footer.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def fatal_popup_and_exit(title: str, msg: str, exit_code: int = 1):
|
||||
win = tk.Tk()
|
||||
win.title(title)
|
||||
win.geometry("520x260")
|
||||
win.resizable(False, False)
|
||||
frm = ttk.Frame(win, padding=14)
|
||||
frm.pack(fill="both", expand=True)
|
||||
ttk.Label(frm, text=title, font=("Segoe UI", 12, "bold")).pack(anchor="w", pady=(0, 8))
|
||||
txt = tk.Text(frm, height=8, wrap="word")
|
||||
txt.pack(fill="both", expand=True)
|
||||
txt.insert("1.0", msg)
|
||||
txt.config(state="disabled")
|
||||
def close_and_exit():
|
||||
win.destroy()
|
||||
raise SystemExit(exit_code)
|
||||
ttk.Button(frm, text="OK", command=close_and_exit).pack(anchor="e", pady=(10, 0))
|
||||
win.protocol("WM_DELETE_WINDOW", close_and_exit)
|
||||
win.mainloop()
|
||||
|
||||
def info_popup(title: str, msg: str):
|
||||
win = tk.Toplevel()
|
||||
win.title(title)
|
||||
win.geometry("520x240")
|
||||
win.resizable(False, False)
|
||||
frm = ttk.Frame(win, padding=14)
|
||||
frm.pack(fill="both", expand=True)
|
||||
ttk.Label(frm, text=title, font=("Segoe UI", 12, "bold")).pack(anchor="w", pady=(0, 8))
|
||||
txt = tk.Text(frm, height=7, wrap="word")
|
||||
txt.pack(fill="both", expand=True)
|
||||
txt.insert("1.0", msg)
|
||||
txt.config(state="disabled")
|
||||
def close():
|
||||
win.destroy()
|
||||
ttk.Button(frm, text="OK", command=close).pack(anchor="e", pady=(10, 0))
|
||||
win.grab_set()
|
||||
win.focus_force()
|
||||
|
||||
def replace_placeholders_in_doc(doc: Document, mapping: dict) -> None:
|
||||
for p in doc.paragraphs:
|
||||
text = p.text
|
||||
new_text = text
|
||||
for k, v in mapping.items():
|
||||
new_text = new_text.replace(k, v)
|
||||
if new_text != text:
|
||||
p.text = new_text
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
text = p.text
|
||||
new_text = text
|
||||
for k, v in mapping.items():
|
||||
new_text = new_text.replace(k, v)
|
||||
if new_text != text:
|
||||
p.text = new_text
|
||||
|
||||
def generate_output_filename() -> str:
|
||||
stamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
||||
return f"{stamp}.docx"
|
||||
|
||||
def build_presence_text(values: dict) -> str:
|
||||
parts = []
|
||||
present_people = []
|
||||
|
||||
presencas = values.get("presencas") or []
|
||||
|
||||
# Retrocompatibilidade com o formato antigo (um item por tipo)
|
||||
if not presencas:
|
||||
if values.get("segurado_presente"):
|
||||
presencas.append(
|
||||
{
|
||||
"tipo": "segurado",
|
||||
"nome": values.get("segurado_nome"),
|
||||
"info": values.get("segurado_info"),
|
||||
}
|
||||
)
|
||||
if values.get("lesado_presente"):
|
||||
presencas.append(
|
||||
{
|
||||
"tipo": "lesado",
|
||||
"nome": values.get("lesado_nome"),
|
||||
"info": values.get("lesado_info"),
|
||||
}
|
||||
)
|
||||
if values.get("outro_presente"):
|
||||
presencas.append(
|
||||
{
|
||||
"tipo": "outro",
|
||||
"nome": values.get("outro_nome"),
|
||||
"info": values.get("outro_info"),
|
||||
}
|
||||
)
|
||||
|
||||
def join_people(items: list) -> str:
|
||||
if not items:
|
||||
return ""
|
||||
if len(items) == 1:
|
||||
return items[0]
|
||||
return ", ".join(items[:-1]) + " e " + items[-1]
|
||||
|
||||
for item in presencas:
|
||||
tipo = (item.get("tipo") or "").strip().lower()
|
||||
nome = (item.get("nome") or "").strip()
|
||||
info = (item.get("info") or "").strip()
|
||||
if not nome:
|
||||
continue
|
||||
|
||||
if tipo == "segurado":
|
||||
present_people.append(f"o segurado, {nome}")
|
||||
if info:
|
||||
parts.append(f"O segurado, {nome} informou que {info}.")
|
||||
elif tipo == "lesado":
|
||||
present_people.append(f"o lesado, {nome}")
|
||||
if info:
|
||||
parts.append(f"O lesado, {nome} informou que {info}.")
|
||||
else:
|
||||
present_people.append(nome)
|
||||
if info:
|
||||
parts.append(f"{nome} informou que {info}.")
|
||||
|
||||
header = ""
|
||||
if present_people:
|
||||
joined = join_people(present_people)
|
||||
if len(present_people) == 1:
|
||||
header = f"{joined} esteve presente aquando a pesquisa."
|
||||
else:
|
||||
header = f"{joined} estiveram presentes aquando a pesquisa."
|
||||
|
||||
if header and parts:
|
||||
return header + "\n\n" + "\n".join(parts)
|
||||
if header:
|
||||
return header
|
||||
if parts:
|
||||
return "\n".join(parts)
|
||||
return ""
|
||||
|
||||
def run_generation(values: dict, root: tk.Tk):
|
||||
mapping = {
|
||||
"{{nproc}}": (values.get("nproc") or "").strip(),
|
||||
"{{segurado}}": (values.get("segurado") or "").strip(),
|
||||
"{{comp}}": (values.get("comp") or "").strip(),
|
||||
"{{terceiro}}": (values.get("terceiro") or "").strip(),
|
||||
"{{data}}": (values.get("data") or "").strip(),
|
||||
"{{local da visita}}": (values.get("local") or "").strip(),
|
||||
"{{descriçãoimovel}}": (values.get("descriçãoimovel") or "").strip(),
|
||||
"{{anoconstr}}": (values.get("anoconstr") or "").strip(),
|
||||
"{{presencas}}": build_presence_text(values),
|
||||
"{{descricao}}": (values.get("descricao") or "").strip(),
|
||||
"{{area}}": (values.get("area") or "").strip(),
|
||||
}
|
||||
|
||||
template_path = resource_path(TEMPLATE_DOCX)
|
||||
if not os.path.exists(template_path):
|
||||
try:
|
||||
root.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
fatal_popup_and_exit(
|
||||
"Erro: template não encontrado",
|
||||
f"Não encontrei o template '{TEMPLATE_DOCX}'.\n\n"
|
||||
f"Coloca o ficheiro '{TEMPLATE_DOCX}' na mesma pasta do executável e volta a executar."
|
||||
)
|
||||
return
|
||||
|
||||
output_docx = generate_output_filename()
|
||||
|
||||
try:
|
||||
doc = Document(template_path)
|
||||
replace_placeholders_in_doc(doc, mapping)
|
||||
foto1_path = (values.get("foto1_path") or "").strip()
|
||||
fotos2_paths = values.get("fotos2_paths") or []
|
||||
placeholders = {
|
||||
"{{foto1}}": foto1_path,
|
||||
}
|
||||
missing = insert_images_at_placeholders(doc, placeholders, width_inches=6.20)
|
||||
if missing:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei os placeholders no template (corpo/cabeçalho/rodapé):\n"
|
||||
+ ", ".join(missing)
|
||||
)
|
||||
if fotos2_paths:
|
||||
ok_multi = insert_multiple_images_at_placeholder(doc, "{{foto2}}", fotos2_paths, width_inches=2.80)
|
||||
if not ok_multi:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei o placeholder {{foto2}} no template (corpo/cabeçalho/rodapé)."
|
||||
)
|
||||
tecnicas = values.get("tecnicas") or []
|
||||
if tecnicas:
|
||||
ok_tecnicas = insert_tecnicas_utilizadas(doc, "{{tecnicasutilizadas}}", tecnicas)
|
||||
if not ok_tecnicas:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei o placeholder {{tecnicasutilizadas}} no template (corpo/cabeçalho/rodapé)."
|
||||
)
|
||||
inicio_pesquisa = values.get("inicio_pesquisa") or []
|
||||
if inicio_pesquisa:
|
||||
ok_inicio = insert_tecnicas_utilizadas(doc, "{{iniciopesquisa}}", inicio_pesquisa)
|
||||
if not ok_inicio:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei o placeholder {{iniciopesquisa}} no template (corpo/cabeçalho/rodapé)."
|
||||
)
|
||||
if values.get("inicio_pesquisa") or values.get("tecnicas"):
|
||||
ok_metodos = insert_metodos_utilizados(doc, "{{metodosutilizados}}", values)
|
||||
if not ok_metodos:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei o placeholder {{metodosutilizados}} no template (corpo/cabeçalho/rodapé)."
|
||||
)
|
||||
doc.save(output_docx)
|
||||
info_popup("Sucesso", f"Documento gerado com sucesso:\n\n{output_docx}")
|
||||
|
||||
except Exception as e:
|
||||
try:
|
||||
root.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
fatal_popup_and_exit(
|
||||
"Erro ao gerar documento",
|
||||
f"Falhou ao gerar o documento.\n\nDetalhes:\n{e}"
|
||||
)
|
||||
|
||||
def choose_image(foto_var):
|
||||
path = filedialog.askopenfilename(
|
||||
title="Selecionar fotografia",
|
||||
filetypes=[
|
||||
("Imagens", "*.png *.jpg *.jpeg *.bmp"),
|
||||
("Todos os ficheiros", "*.*"),
|
||||
],
|
||||
)
|
||||
if path:
|
||||
foto_var.set(path)
|
||||
|
||||
def choose_images(fotos_var, label_var):
|
||||
paths = filedialog.askopenfilenames(
|
||||
title="Selecionar fotografias",
|
||||
filetypes=[
|
||||
("Imagens", "*.png *.jpg *.jpeg *.bmp"),
|
||||
("Todos os ficheiros", "*.*"),
|
||||
],
|
||||
)
|
||||
if paths:
|
||||
fotos_var.set(list(paths))
|
||||
label_var.set(f"{len(paths)} imagem(ns)")
|
||||
|
||||
def main():
|
||||
root = tk.Tk()
|
||||
root.title("Preencher Corpus (Word)")
|
||||
root.geometry("1120x640")
|
||||
root.resizable(False, False)
|
||||
|
||||
outer = ttk.Frame(root)
|
||||
outer.pack(fill="both", expand=True)
|
||||
|
||||
canvas = tk.Canvas(outer, highlightthickness=0)
|
||||
scrollbar = ttk.Scrollbar(outer, orient="vertical", command=canvas.yview)
|
||||
canvas.configure(yscrollcommand=scrollbar.set)
|
||||
|
||||
scrollbar.pack(side="right", fill="y")
|
||||
canvas.pack(side="left", fill="both", expand=True)
|
||||
|
||||
frm = ttk.Frame(canvas, padding=16)
|
||||
canvas_window = canvas.create_window((0, 0), window=frm, anchor="nw")
|
||||
|
||||
def _update_scrollregion(_event=None):
|
||||
canvas.configure(scrollregion=canvas.bbox("all"))
|
||||
|
||||
def _fit_inner_width(event):
|
||||
canvas.itemconfigure(canvas_window, width=event.width)
|
||||
|
||||
def _on_mousewheel(event):
|
||||
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
|
||||
|
||||
frm.bind("<Configure>", _update_scrollregion)
|
||||
canvas.bind("<Configure>", _fit_inner_width)
|
||||
canvas.bind_all("<MouseWheel>", _on_mousewheel)
|
||||
|
||||
fields = [("Nº do Processo:", "nproc"),("Segurado:", "segurado"),
|
||||
("Companhia:", "comp"),
|
||||
("Terceiro:", "terceiro"),
|
||||
("Data da visita:", "data"),
|
||||
("Local da visita:", "local"),
|
||||
("Descrição do imóvel:", "descriçãoimovel"),
|
||||
("Ano de Construção:", "anoconstr"),
|
||||
("Descrição da pesquisa:", "descricao"),
|
||||
("Área do do espaço:", "area")
|
||||
]
|
||||
|
||||
entries = {}
|
||||
foto_var = tk.StringVar(value="")
|
||||
fotos2_var = tk.Variable(value=[])
|
||||
fotos2_label = tk.StringVar(value="")
|
||||
tecnicas_data = []
|
||||
inicio_data = []
|
||||
|
||||
for i, (label, key) in enumerate(fields):
|
||||
ttk.Label(frm, text=label).grid(row=i, column=0, sticky="w", pady=6)
|
||||
ent = ttk.Entry(frm, width=80)
|
||||
ent.grid(row=i, column=1, sticky="w", pady=6)
|
||||
entries[key] = ent
|
||||
if key == "descriçãoimovel":
|
||||
ttk.Button(
|
||||
frm,
|
||||
text="Escolher imagem…",
|
||||
command=lambda: choose_image(foto_var)
|
||||
).grid(row=i, column=2, sticky="w", padx=8)
|
||||
|
||||
ttk.Label(
|
||||
frm,
|
||||
textvariable=foto_var,
|
||||
width=28
|
||||
).grid(row=i, column=4, sticky="w")
|
||||
if key == "descricao":
|
||||
ttk.Button(
|
||||
frm,
|
||||
text="Escolher imagens…",
|
||||
command=lambda: choose_images(fotos2_var, fotos2_label)
|
||||
).grid(row=i, column=2, sticky="w", padx=8)
|
||||
|
||||
ttk.Label(
|
||||
frm,
|
||||
textvariable=fotos2_label,
|
||||
width=14
|
||||
).grid(row=i, column=4, sticky="w")
|
||||
|
||||
def build_tecnicas_window(title: str, data_list: list):
|
||||
win = tk.Toplevel(root)
|
||||
win.title(title)
|
||||
win.geometry("980x520")
|
||||
win.resizable(False, False)
|
||||
|
||||
container = ttk.Frame(win, padding=16)
|
||||
container.pack(fill="both", expand=True)
|
||||
|
||||
if not data_list:
|
||||
tecnicas_list = [
|
||||
"Controlo Visual",
|
||||
"Medição de humidade",
|
||||
"Câmara térmica",
|
||||
"Câmara endoscópica",
|
||||
"Obturação",
|
||||
"Teste de pressão",
|
||||
"Teste com corantes",
|
||||
]
|
||||
for nome in tecnicas_list:
|
||||
data_list.append({
|
||||
"name": nome,
|
||||
"var": tk.BooleanVar(value=False),
|
||||
"desc": tk.StringVar(value=""),
|
||||
"photos": tk.Variable(value=[]),
|
||||
"label": tk.StringVar(value=""),
|
||||
})
|
||||
|
||||
def set_row_state(row_widgets, enabled: bool):
|
||||
state = "normal" if enabled else "disabled"
|
||||
for w in row_widgets:
|
||||
w.configure(state=state)
|
||||
|
||||
for idx, item in enumerate(data_list):
|
||||
row = ttk.Frame(container)
|
||||
row.pack(fill="x", pady=6)
|
||||
|
||||
chk = ttk.Checkbutton(
|
||||
row,
|
||||
text=item["name"],
|
||||
variable=item["var"],
|
||||
command=lambda it=item: set_row_state(it["widgets"], it["var"].get())
|
||||
)
|
||||
chk.grid(row=0, column=0, sticky="w")
|
||||
|
||||
ttk.Label(row, text="Descrição:").grid(row=0, column=1, sticky="w", padx=(12, 4))
|
||||
entry = ttk.Entry(row, textvariable=item["desc"], width=50)
|
||||
entry.grid(row=0, column=2, sticky="w")
|
||||
|
||||
btn = ttk.Button(
|
||||
row,
|
||||
text="Escolher fotos…",
|
||||
command=lambda it=item: choose_images(it["photos"], it["label"])
|
||||
)
|
||||
btn.grid(row=0, column=3, sticky="w", padx=10)
|
||||
|
||||
lbl = ttk.Label(row, textvariable=item["label"], width=18)
|
||||
lbl.grid(row=0, column=4, sticky="w")
|
||||
|
||||
item["widgets"] = [entry, btn]
|
||||
set_row_state(item["widgets"], item["var"].get())
|
||||
|
||||
ttk.Button(container, text="Fechar", command=win.destroy).pack(anchor="e", pady=(12, 0))
|
||||
win.grab_set()
|
||||
win.focus_force()
|
||||
|
||||
ttk.Button(
|
||||
frm,
|
||||
text="Técnicas utilizadas…",
|
||||
command=lambda: build_tecnicas_window("Técnicas utilizadas", tecnicas_data)
|
||||
).grid(row=len(fields), column=0, sticky="w", pady=(14, 0))
|
||||
|
||||
ttk.Button(
|
||||
frm,
|
||||
text="Início da pesquisa…",
|
||||
command=lambda: build_tecnicas_window("Início da pesquisa", inicio_data)
|
||||
).grid(row=len(fields), column=1, sticky="w", pady=(14, 0), padx=(12, 0))
|
||||
|
||||
presence_frame = ttk.LabelFrame(frm, text="Presenças na pesquisa", padding=12)
|
||||
presence_frame.grid(row=len(fields) + 1, column=0, columnspan=4, sticky="w", pady=(12, 6))
|
||||
|
||||
presenca_rows = {
|
||||
"segurado": [],
|
||||
"lesado": [],
|
||||
"outro": [],
|
||||
}
|
||||
type_frames = {}
|
||||
type_labels = {
|
||||
"segurado": "segurado",
|
||||
"lesado": "lesado",
|
||||
"outro": "outro",
|
||||
}
|
||||
|
||||
def remove_presence_row(tipo: str, row_data: dict):
|
||||
row_data["frame"].destroy()
|
||||
presenca_rows[tipo] = [r for r in presenca_rows[tipo] if r is not row_data]
|
||||
|
||||
def add_presence_row(tipo: str):
|
||||
container = type_frames[tipo]
|
||||
row = ttk.Frame(container)
|
||||
row.pack(fill="x", pady=3)
|
||||
|
||||
nome_var = tk.StringVar(value="")
|
||||
info_var = tk.StringVar(value="")
|
||||
|
||||
ttk.Label(row, text=f"Nome do {type_labels[tipo]}:").grid(row=0, column=0, sticky="w")
|
||||
ttk.Entry(row, textvariable=nome_var, width=30).grid(row=0, column=1, sticky="w", padx=6)
|
||||
ttk.Label(row, text="Declaraçoes:").grid(row=0, column=2, sticky="w", padx=(12, 0))
|
||||
ttk.Entry(row, textvariable=info_var, width=42).grid(row=0, column=3, sticky="w", padx=6)
|
||||
|
||||
row_data = {
|
||||
"frame": row,
|
||||
"nome": nome_var,
|
||||
"info": info_var,
|
||||
}
|
||||
|
||||
ttk.Button(
|
||||
row,
|
||||
text="Remover",
|
||||
command=lambda t=tipo, d=row_data: remove_presence_row(t, d)
|
||||
).grid(row=0, column=4, sticky="w", padx=(8, 0))
|
||||
|
||||
presenca_rows[tipo].append(row_data)
|
||||
|
||||
def build_presence_section(parent, row_index: int, tipo: str, titulo: str):
|
||||
sec = ttk.Frame(parent)
|
||||
sec.grid(row=row_index, column=0, sticky="w", pady=4)
|
||||
ttk.Label(sec, text=titulo).grid(row=0, column=0, sticky="w")
|
||||
ttk.Button(
|
||||
sec,
|
||||
text=f"Adicionar {type_labels[tipo]}",
|
||||
command=lambda t=tipo: add_presence_row(t)
|
||||
).grid(row=0, column=1, sticky="w", padx=(10, 0))
|
||||
|
||||
container = ttk.Frame(sec)
|
||||
container.grid(row=1, column=0, columnspan=2, sticky="w", pady=(6, 0))
|
||||
type_frames[tipo] = container
|
||||
|
||||
build_presence_section(presence_frame, 0, "segurado", "Segurados")
|
||||
build_presence_section(presence_frame, 1, "lesado", "Lesados")
|
||||
build_presence_section(presence_frame, 2, "outro", "Outros")
|
||||
|
||||
add_presence_row("segurado")
|
||||
|
||||
|
||||
def on_generate():
|
||||
values = {k: e.get() for k, e in entries.items()}
|
||||
values["foto1_path"] = foto_var.get()
|
||||
values["fotos2_paths"] = list(fotos2_var.get()) if fotos2_var.get() else []
|
||||
values["tecnicas"] = [
|
||||
{
|
||||
"name": t["name"],
|
||||
"selected": t["var"].get(),
|
||||
"desc": t["desc"].get(),
|
||||
"photos": list(t["photos"].get()) if t["photos"].get() else [],
|
||||
}
|
||||
for t in tecnicas_data
|
||||
]
|
||||
values["inicio_pesquisa"] = [
|
||||
{
|
||||
"name": t["name"],
|
||||
"selected": t["var"].get(),
|
||||
"desc": t["desc"].get(),
|
||||
"photos": list(t["photos"].get()) if t["photos"].get() else [],
|
||||
}
|
||||
for t in inicio_data
|
||||
]
|
||||
values["presencas"] = []
|
||||
for tipo in ("segurado", "lesado", "outro"):
|
||||
for row in presenca_rows[tipo]:
|
||||
values["presencas"].append(
|
||||
{
|
||||
"tipo": tipo,
|
||||
"nome": row["nome"].get(),
|
||||
"info": row["info"].get(),
|
||||
}
|
||||
)
|
||||
run_generation(values, root)
|
||||
|
||||
|
||||
btns = ttk.Frame(frm)
|
||||
btns.grid(row=len(fields) + 2, column=0, columnspan=2, sticky="w", pady=(18, 0))
|
||||
|
||||
ttk.Button(btns, text="Gerar Word", command=on_generate).pack(side="left")
|
||||
ttk.Button(btns, text="Sair", command=root.destroy).pack(side="left", padx=10)
|
||||
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,39 +0,0 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['d:\\Trabalhos\\V-aguatech\\Vitor\\vaguatechrelatorios.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='vaguatechrelatorios',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['d:\\Trabalhos\\V-aguatech\\Vitor\\icon.ico'],
|
||||
)
|
||||
@@ -1,754 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from datetime import datetime
|
||||
from docx import Document
|
||||
from tkinter import filedialog
|
||||
from PIL import Image
|
||||
import tempfile
|
||||
from docx.shared import Inches, Pt, RGBColor
|
||||
import io
|
||||
|
||||
|
||||
TEMPLATE_DOCX = "Corpus.docx"
|
||||
|
||||
def resource_path(relative_path: str) -> str:
|
||||
try:
|
||||
base_path = sys._MEIPASS
|
||||
except Exception:
|
||||
base_path = os.path.abspath(".")
|
||||
return os.path.join(base_path, relative_path)
|
||||
|
||||
def image_to_png_stream(image_path: str) -> io.BytesIO:
|
||||
with Image.open(image_path) as img:
|
||||
if img.mode not in ("RGB", "RGBA"):
|
||||
img = img.convert("RGB")
|
||||
bio = io.BytesIO()
|
||||
img.save(bio, format="PNG")
|
||||
bio.seek(0)
|
||||
return bio
|
||||
|
||||
|
||||
def insert_image_at_placeholder(doc: Document, placeholder: str, image_path: str, width_inches: float = 6.20) -> bool:
|
||||
if not image_path or not os.path.exists(image_path):
|
||||
return False
|
||||
try:
|
||||
img_stream = image_to_png_stream(image_path)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Não consegui abrir/convert a imagem:\n{image_path}\n\nDetalhes:\n{e}")
|
||||
|
||||
def replace_in_paragraph(p) -> bool:
|
||||
full_text = "".join(run.text for run in p.runs)
|
||||
if placeholder not in full_text:
|
||||
return False
|
||||
for r in p.runs:
|
||||
r.text = ""
|
||||
run = p.add_run()
|
||||
run.add_picture(img_stream, width=Inches(width_inches))
|
||||
return True
|
||||
for p in doc.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for section in doc.sections:
|
||||
for p in section.header.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for p in section.footer.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def insert_images_at_placeholders(doc: Document, placeholders: dict, width_inches: float = 6.20) -> list:
|
||||
missing = []
|
||||
for placeholder, image_path in placeholders.items():
|
||||
if not image_path:
|
||||
continue
|
||||
ok = insert_image_at_placeholder(doc, placeholder, image_path, width_inches=width_inches)
|
||||
if not ok:
|
||||
missing.append(placeholder)
|
||||
return missing
|
||||
|
||||
def insert_tecnicas_utilizadas(doc: Document, placeholder: str, tecnicas: list) -> bool:
|
||||
def replace_in_paragraph(p) -> bool:
|
||||
full_text = "".join(run.text for run in p.runs)
|
||||
if placeholder not in full_text:
|
||||
return False
|
||||
for r in p.runs:
|
||||
r.text = ""
|
||||
|
||||
first_block = True
|
||||
for t in tecnicas:
|
||||
if not t.get("selected"):
|
||||
continue
|
||||
nome = (t.get("name") or "").strip()
|
||||
desc = (t.get("desc") or "").strip()
|
||||
fotos = t.get("photos") or []
|
||||
|
||||
if not nome:
|
||||
continue
|
||||
if not first_block:
|
||||
p.add_run().add_break()
|
||||
p.add_run().add_break()
|
||||
|
||||
run_title = p.add_run(nome)
|
||||
run_title.font.name = "Verdana"
|
||||
run_title.font.size = Pt(11)
|
||||
run_title.font.color.rgb = RGBColor(0x4A, 0x66, 0xAC)
|
||||
p.add_run().add_break()
|
||||
|
||||
if desc:
|
||||
run_desc = p.add_run(desc)
|
||||
run_desc.font.name = "Verdana"
|
||||
run_desc.font.size = Pt(10)
|
||||
run_desc.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
|
||||
p.add_run().add_break()
|
||||
|
||||
if fotos:
|
||||
for i, image_path in enumerate(fotos):
|
||||
if not image_path or not os.path.exists(image_path):
|
||||
continue
|
||||
try:
|
||||
img_stream = image_to_png_stream(image_path)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Não consegui abrir/convert a imagem:\n{image_path}\n\nDetalhes:\n{e}")
|
||||
run_img = p.add_run()
|
||||
run_img.add_picture(img_stream, width=Inches(2.80))
|
||||
is_last = i == len(fotos) - 1
|
||||
if not is_last:
|
||||
if i % 2 == 0:
|
||||
p.add_run(" ")
|
||||
else:
|
||||
p.add_run().add_break()
|
||||
p.add_run().add_break()
|
||||
|
||||
first_block = False
|
||||
|
||||
return True
|
||||
|
||||
for p in doc.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for section in doc.sections:
|
||||
for p in section.header.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for p in section.footer.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def insert_metodos_utilizados(doc: Document, placeholder: str, values: dict) -> bool:
|
||||
items = []
|
||||
seen = set()
|
||||
for group_key in ("inicio_pesquisa", "tecnicas"):
|
||||
for t in values.get(group_key) or []:
|
||||
if not t.get("selected"):
|
||||
continue
|
||||
name = (t.get("name") or "").strip()
|
||||
if not name or name in seen:
|
||||
continue
|
||||
seen.add(name)
|
||||
items.append(name)
|
||||
|
||||
if not items:
|
||||
return False
|
||||
|
||||
def replace_in_paragraph(p) -> bool:
|
||||
full_text = "".join(run.text for run in p.runs)
|
||||
if placeholder not in full_text:
|
||||
return False
|
||||
for r in p.runs:
|
||||
r.text = ""
|
||||
|
||||
for i, name in enumerate(items):
|
||||
run = p.add_run(f"- {name}")
|
||||
run.font.name = "Verdana"
|
||||
run.font.size = Pt(10)
|
||||
run.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
|
||||
if i < len(items) - 1:
|
||||
p.add_run().add_break()
|
||||
return True
|
||||
|
||||
for p in doc.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for section in doc.sections:
|
||||
for p in section.header.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for p in section.footer.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
return False
|
||||
def insert_multiple_images_at_placeholder(doc: Document, placeholder: str, image_paths: list, width_inches: float = 2.80) -> bool:
|
||||
if not image_paths:
|
||||
return False
|
||||
|
||||
def replace_in_paragraph(p) -> bool:
|
||||
full_text = "".join(run.text for run in p.runs)
|
||||
if placeholder not in full_text:
|
||||
return False
|
||||
for r in p.runs:
|
||||
r.text = ""
|
||||
for i, image_path in enumerate(image_paths):
|
||||
if not image_path or not os.path.exists(image_path):
|
||||
continue
|
||||
try:
|
||||
img_stream = image_to_png_stream(image_path)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Não consegui abrir/convert a imagem:\n{image_path}\n\nDetalhes:\n{e}")
|
||||
run = p.add_run()
|
||||
run.add_picture(img_stream, width=Inches(width_inches))
|
||||
is_last = i == len(image_paths) - 1
|
||||
if not is_last:
|
||||
if i % 2 == 0:
|
||||
p.add_run(" ")
|
||||
else:
|
||||
p.add_run().add_break()
|
||||
return True
|
||||
|
||||
for p in doc.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
for section in doc.sections:
|
||||
for p in section.header.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
for p in section.footer.paragraphs:
|
||||
if replace_in_paragraph(p):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def fatal_popup_and_exit(title: str, msg: str, exit_code: int = 1):
|
||||
win = tk.Tk()
|
||||
win.title(title)
|
||||
win.geometry("520x260")
|
||||
win.resizable(False, False)
|
||||
frm = ttk.Frame(win, padding=14)
|
||||
frm.pack(fill="both", expand=True)
|
||||
ttk.Label(frm, text=title, font=("Segoe UI", 12, "bold")).pack(anchor="w", pady=(0, 8))
|
||||
txt = tk.Text(frm, height=8, wrap="word")
|
||||
txt.pack(fill="both", expand=True)
|
||||
txt.insert("1.0", msg)
|
||||
txt.config(state="disabled")
|
||||
def close_and_exit():
|
||||
win.destroy()
|
||||
raise SystemExit(exit_code)
|
||||
ttk.Button(frm, text="OK", command=close_and_exit).pack(anchor="e", pady=(10, 0))
|
||||
win.protocol("WM_DELETE_WINDOW", close_and_exit)
|
||||
win.mainloop()
|
||||
|
||||
def info_popup(title: str, msg: str):
|
||||
win = tk.Toplevel()
|
||||
win.title(title)
|
||||
win.geometry("520x240")
|
||||
win.resizable(False, False)
|
||||
frm = ttk.Frame(win, padding=14)
|
||||
frm.pack(fill="both", expand=True)
|
||||
ttk.Label(frm, text=title, font=("Segoe UI", 12, "bold")).pack(anchor="w", pady=(0, 8))
|
||||
txt = tk.Text(frm, height=7, wrap="word")
|
||||
txt.pack(fill="both", expand=True)
|
||||
txt.insert("1.0", msg)
|
||||
txt.config(state="disabled")
|
||||
def close():
|
||||
win.destroy()
|
||||
ttk.Button(frm, text="OK", command=close).pack(anchor="e", pady=(10, 0))
|
||||
win.grab_set()
|
||||
win.focus_force()
|
||||
|
||||
def replace_placeholders_in_doc(doc: Document, mapping: dict) -> None:
|
||||
for p in doc.paragraphs:
|
||||
text = p.text
|
||||
new_text = text
|
||||
for k, v in mapping.items():
|
||||
new_text = new_text.replace(k, v)
|
||||
if new_text != text:
|
||||
p.text = new_text
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for p in cell.paragraphs:
|
||||
text = p.text
|
||||
new_text = text
|
||||
for k, v in mapping.items():
|
||||
new_text = new_text.replace(k, v)
|
||||
if new_text != text:
|
||||
p.text = new_text
|
||||
|
||||
def generate_output_filename() -> str:
|
||||
stamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
||||
return f"{stamp}.docx"
|
||||
|
||||
def build_presence_text(values: dict) -> str:
|
||||
parts = []
|
||||
present_people = []
|
||||
|
||||
presencas = values.get("presencas") or []
|
||||
|
||||
if not presencas:
|
||||
if values.get("segurado_presente"):
|
||||
presencas.append(
|
||||
{
|
||||
"tipo": "segurado",
|
||||
"nome": values.get("segurado_nome"),
|
||||
"info": values.get("segurado_info"),
|
||||
}
|
||||
)
|
||||
if values.get("lesado_presente"):
|
||||
presencas.append(
|
||||
{
|
||||
"tipo": "lesado",
|
||||
"nome": values.get("lesado_nome"),
|
||||
"info": values.get("lesado_info"),
|
||||
}
|
||||
)
|
||||
if values.get("outro_presente"):
|
||||
presencas.append(
|
||||
{
|
||||
"tipo": "outro",
|
||||
"nome": values.get("outro_nome"),
|
||||
"info": values.get("outro_info"),
|
||||
}
|
||||
)
|
||||
|
||||
def join_people(items: list) -> str:
|
||||
if not items:
|
||||
return ""
|
||||
if len(items) == 1:
|
||||
return items[0]
|
||||
return ", ".join(items[:-1]) + " e " + items[-1]
|
||||
|
||||
for item in presencas:
|
||||
tipo = (item.get("tipo") or "").strip().lower()
|
||||
nome = (item.get("nome") or "").strip()
|
||||
info = (item.get("info") or "").strip()
|
||||
if not nome:
|
||||
continue
|
||||
|
||||
if tipo == "segurado":
|
||||
present_people.append(f"o segurado, {nome}")
|
||||
if info:
|
||||
parts.append(f"O segurado, {nome} informou que {info}.")
|
||||
elif tipo == "lesado":
|
||||
present_people.append(f"o lesado, {nome}")
|
||||
if info:
|
||||
parts.append(f"O lesado, {nome} informou que {info}.")
|
||||
else:
|
||||
present_people.append(nome)
|
||||
if info:
|
||||
parts.append(f"{nome} informou que {info}.")
|
||||
|
||||
header = ""
|
||||
if present_people:
|
||||
joined = join_people(present_people)
|
||||
if len(present_people) == 1:
|
||||
header = f"{joined} esteve presente aquando a pesquisa."
|
||||
else:
|
||||
header = f"{joined} estiveram presentes aquando a pesquisa."
|
||||
|
||||
if header and parts:
|
||||
return header + "\n\n" + "\n".join(parts)
|
||||
if header:
|
||||
return header
|
||||
if parts:
|
||||
return "\n".join(parts)
|
||||
return ""
|
||||
|
||||
def run_generation(values: dict, root: tk.Tk):
|
||||
mapping = {
|
||||
"{{nproc}}": (values.get("nproc") or "").strip(),
|
||||
"{{segurado}}": (values.get("segurado") or "").strip(),
|
||||
"{{comp}}": (values.get("comp") or "").strip(),
|
||||
"{{terceiro}}": (values.get("terceiro") or "").strip(),
|
||||
"{{data}}": (values.get("data") or "").strip(),
|
||||
"{{local da visita}}": (values.get("local") or "").strip(),
|
||||
"{{descriçãoimovel}}": (values.get("descriçãoimovel") or "").strip(),
|
||||
"{{anoconstr}}": (values.get("anoconstr") or "").strip(),
|
||||
"{{presencas}}": build_presence_text(values),
|
||||
"{{descricao}}": (values.get("descricao") or "").strip(),
|
||||
"{{area}}": (values.get("area") or "").strip(),
|
||||
}
|
||||
|
||||
template_path = resource_path(TEMPLATE_DOCX)
|
||||
if not os.path.exists(template_path):
|
||||
try:
|
||||
root.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
fatal_popup_and_exit(
|
||||
"Erro: template não encontrado",
|
||||
f"Não encontrei o template '{TEMPLATE_DOCX}'.\n\n"
|
||||
f"Coloca o ficheiro '{TEMPLATE_DOCX}' na mesma pasta do executável e volta a executar."
|
||||
)
|
||||
return
|
||||
|
||||
output_docx = generate_output_filename()
|
||||
|
||||
try:
|
||||
doc = Document(template_path)
|
||||
replace_placeholders_in_doc(doc, mapping)
|
||||
foto1_path = (values.get("foto1_path") or "").strip()
|
||||
fotos2_paths = values.get("fotos2_paths") or []
|
||||
placeholders = {
|
||||
"{{foto1}}": foto1_path,
|
||||
}
|
||||
missing = insert_images_at_placeholders(doc, placeholders, width_inches=6.20)
|
||||
if missing:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei os placeholders no template (corpo/cabeçalho/rodapé):\n"
|
||||
+ ", ".join(missing)
|
||||
)
|
||||
if fotos2_paths:
|
||||
ok_multi = insert_multiple_images_at_placeholder(doc, "{{foto2}}", fotos2_paths, width_inches=2.80)
|
||||
if not ok_multi:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei o placeholder {{foto2}} no template (corpo/cabeçalho/rodapé)."
|
||||
)
|
||||
tecnicas = values.get("tecnicas") or []
|
||||
if tecnicas:
|
||||
ok_tecnicas = insert_tecnicas_utilizadas(doc, "{{tecnicasutilizadas}}", tecnicas)
|
||||
if not ok_tecnicas:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei o placeholder {{tecnicasutilizadas}} no template (corpo/cabeçalho/rodapé)."
|
||||
)
|
||||
inicio_pesquisa = values.get("inicio_pesquisa") or []
|
||||
if inicio_pesquisa:
|
||||
ok_inicio = insert_tecnicas_utilizadas(doc, "{{iniciopesquisa}}", inicio_pesquisa)
|
||||
if not ok_inicio:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei o placeholder {{iniciopesquisa}} no template (corpo/cabeçalho/rodapé)."
|
||||
)
|
||||
if values.get("inicio_pesquisa") or values.get("tecnicas"):
|
||||
ok_metodos = insert_metodos_utilizados(doc, "{{metodosutilizados}}", values)
|
||||
if not ok_metodos:
|
||||
info_popup(
|
||||
"Aviso",
|
||||
"Não encontrei o placeholder {{metodosutilizados}} no template (corpo/cabeçalho/rodapé)."
|
||||
)
|
||||
doc.save(output_docx)
|
||||
info_popup("Sucesso", f"Documento gerado com sucesso:\n\n{output_docx}")
|
||||
|
||||
except Exception as e:
|
||||
try:
|
||||
root.destroy()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
fatal_popup_and_exit(
|
||||
"Erro ao gerar documento",
|
||||
f"Falhou ao gerar o documento.\n\nDetalhes:\n{e}"
|
||||
)
|
||||
|
||||
def choose_image(foto_var):
|
||||
path = filedialog.askopenfilename(
|
||||
title="Selecionar fotografia",
|
||||
filetypes=[
|
||||
("Imagens", "*.png *.jpg *.jpeg *.bmp"),
|
||||
("Todos os ficheiros", "*.*"),
|
||||
],
|
||||
)
|
||||
if path:
|
||||
foto_var.set(path)
|
||||
|
||||
def choose_images(fotos_var, label_var):
|
||||
paths = filedialog.askopenfilenames(
|
||||
title="Selecionar fotografias",
|
||||
filetypes=[
|
||||
("Imagens", "*.png *.jpg *.jpeg *.bmp"),
|
||||
("Todos os ficheiros", "*.*"),
|
||||
],
|
||||
)
|
||||
if paths:
|
||||
fotos_var.set(list(paths))
|
||||
label_var.set(f"{len(paths)} imagem(ns)")
|
||||
|
||||
def main():
|
||||
root = tk.Tk()
|
||||
root.title("Preencher Corpus (Word)")
|
||||
root.geometry("1120x640")
|
||||
root.resizable(False, False)
|
||||
|
||||
frm = ttk.Frame(root, padding=16)
|
||||
frm.pack(fill="both", expand=True)
|
||||
|
||||
fields = [("Nº do Processo:", "nproc"),("Segurado:", "segurado"),
|
||||
("Companhia:", "comp"),
|
||||
("Terceiro:", "terceiro"),
|
||||
("Data da visita:", "data"),
|
||||
("Local da visita:", "local"),
|
||||
("Descrição do imóvel:", "descriçãoimovel"),
|
||||
("Ano de Construção:", "anoconstr"),
|
||||
("Descrição da pesquisa:", "descricao"),
|
||||
("Área do do espaço:", "area")
|
||||
]
|
||||
|
||||
entries = {}
|
||||
foto_var = tk.StringVar(value="")
|
||||
fotos2_var = tk.Variable(value=[])
|
||||
fotos2_label = tk.StringVar(value="")
|
||||
tecnicas_data = []
|
||||
inicio_data = []
|
||||
|
||||
for i, (label, key) in enumerate(fields):
|
||||
ttk.Label(frm, text=label).grid(row=i, column=0, sticky="w", pady=6)
|
||||
ent = ttk.Entry(frm, width=80)
|
||||
ent.grid(row=i, column=1, sticky="w", pady=6)
|
||||
entries[key] = ent
|
||||
if key == "descriçãoimovel":
|
||||
ttk.Button(
|
||||
frm,
|
||||
text="Escolher imagem…",
|
||||
command=lambda: choose_image(foto_var)
|
||||
).grid(row=i, column=2, sticky="w", padx=8)
|
||||
|
||||
ttk.Label(
|
||||
frm,
|
||||
textvariable=foto_var,
|
||||
width=28
|
||||
).grid(row=i, column=4, sticky="w")
|
||||
if key == "descricao":
|
||||
ttk.Button(
|
||||
frm,
|
||||
text="Escolher imagens…",
|
||||
command=lambda: choose_images(fotos2_var, fotos2_label)
|
||||
).grid(row=i, column=2, sticky="w", padx=8)
|
||||
|
||||
ttk.Label(
|
||||
frm,
|
||||
textvariable=fotos2_label,
|
||||
width=14
|
||||
).grid(row=i, column=4, sticky="w")
|
||||
|
||||
def build_tecnicas_window(title: str, data_list: list):
|
||||
win = tk.Toplevel(root)
|
||||
win.title(title)
|
||||
win.geometry("980x520")
|
||||
win.resizable(False, False)
|
||||
|
||||
container = ttk.Frame(win, padding=16)
|
||||
container.pack(fill="both", expand=True)
|
||||
|
||||
if not data_list:
|
||||
tecnicas_list = [
|
||||
"Controlo Visual",
|
||||
"Medição de humidade",
|
||||
"Câmara térmica",
|
||||
"Câmara endoscópica",
|
||||
"Obturação",
|
||||
"Teste de pressão",
|
||||
"Teste com corantes",
|
||||
]
|
||||
for nome in tecnicas_list:
|
||||
data_list.append({
|
||||
"name": nome,
|
||||
"var": tk.BooleanVar(value=False),
|
||||
"desc": tk.StringVar(value=""),
|
||||
"photos": tk.Variable(value=[]),
|
||||
"label": tk.StringVar(value=""),
|
||||
})
|
||||
|
||||
def set_row_state(row_widgets, enabled: bool):
|
||||
state = "normal" if enabled else "disabled"
|
||||
for w in row_widgets:
|
||||
w.configure(state=state)
|
||||
|
||||
for idx, item in enumerate(data_list):
|
||||
row = ttk.Frame(container)
|
||||
row.pack(fill="x", pady=6)
|
||||
|
||||
chk = ttk.Checkbutton(
|
||||
row,
|
||||
text=item["name"],
|
||||
variable=item["var"],
|
||||
command=lambda it=item: set_row_state(it["widgets"], it["var"].get())
|
||||
)
|
||||
chk.grid(row=0, column=0, sticky="w")
|
||||
|
||||
ttk.Label(row, text="Descrição:").grid(row=0, column=1, sticky="w", padx=(12, 4))
|
||||
entry = ttk.Entry(row, textvariable=item["desc"], width=50)
|
||||
entry.grid(row=0, column=2, sticky="w")
|
||||
|
||||
btn = ttk.Button(
|
||||
row,
|
||||
text="Escolher fotos…",
|
||||
command=lambda it=item: choose_images(it["photos"], it["label"])
|
||||
)
|
||||
btn.grid(row=0, column=3, sticky="w", padx=10)
|
||||
|
||||
lbl = ttk.Label(row, textvariable=item["label"], width=18)
|
||||
lbl.grid(row=0, column=4, sticky="w")
|
||||
|
||||
item["widgets"] = [entry, btn]
|
||||
set_row_state(item["widgets"], item["var"].get())
|
||||
|
||||
ttk.Button(container, text="Fechar", command=win.destroy).pack(anchor="e", pady=(12, 0))
|
||||
win.grab_set()
|
||||
win.focus_force()
|
||||
|
||||
ttk.Button(
|
||||
frm,
|
||||
text="Técnicas utilizadas…",
|
||||
command=lambda: build_tecnicas_window("Técnicas utilizadas", tecnicas_data)
|
||||
).grid(row=len(fields), column=0, sticky="w", pady=(14, 0))
|
||||
|
||||
ttk.Button(
|
||||
frm,
|
||||
text="Início da pesquisa…",
|
||||
command=lambda: build_tecnicas_window("Início da pesquisa", inicio_data)
|
||||
).grid(row=len(fields), column=1, sticky="w", pady=(14, 0), padx=(12, 0))
|
||||
|
||||
presence_frame = ttk.LabelFrame(frm, text="Presencas na pesquisa", padding=12)
|
||||
presence_frame.grid(row=len(fields) + 1, column=0, columnspan=4, sticky="w", pady=(12, 6))
|
||||
|
||||
presenca_rows = {
|
||||
"segurado": [],
|
||||
"lesado": [],
|
||||
"outro": [],
|
||||
}
|
||||
type_frames = {}
|
||||
type_labels = {
|
||||
"segurado": "segurado",
|
||||
"lesado": "lesado",
|
||||
"outro": "outro",
|
||||
}
|
||||
|
||||
def remove_presence_row(tipo: str, row_data: dict):
|
||||
row_data["frame"].destroy()
|
||||
presenca_rows[tipo] = [r for r in presenca_rows[tipo] if r is not row_data]
|
||||
|
||||
def add_presence_row(tipo: str):
|
||||
container = type_frames[tipo]
|
||||
row = ttk.Frame(container)
|
||||
row.pack(fill="x", pady=3)
|
||||
|
||||
nome_var = tk.StringVar(value="")
|
||||
info_var = tk.StringVar(value="")
|
||||
|
||||
ttk.Label(row, text=f"Nome do {type_labels[tipo]}:").grid(row=0, column=0, sticky="w")
|
||||
ttk.Entry(row, textvariable=nome_var, width=30).grid(row=0, column=1, sticky="w", padx=6)
|
||||
ttk.Label(row, text="Declaracoes:").grid(row=0, column=2, sticky="w", padx=(12, 0))
|
||||
ttk.Entry(row, textvariable=info_var, width=42).grid(row=0, column=3, sticky="w", padx=6)
|
||||
|
||||
row_data = {
|
||||
"frame": row,
|
||||
"nome": nome_var,
|
||||
"info": info_var,
|
||||
}
|
||||
|
||||
ttk.Button(
|
||||
row,
|
||||
text="Remover",
|
||||
command=lambda t=tipo, d=row_data: remove_presence_row(t, d)
|
||||
).grid(row=0, column=4, sticky="w", padx=(8, 0))
|
||||
|
||||
presenca_rows[tipo].append(row_data)
|
||||
|
||||
def build_presence_section(parent, row_index: int, tipo: str, titulo: str):
|
||||
sec = ttk.Frame(parent)
|
||||
sec.grid(row=row_index, column=0, sticky="w", pady=4)
|
||||
ttk.Label(sec, text=titulo).grid(row=0, column=0, sticky="w")
|
||||
ttk.Button(
|
||||
sec,
|
||||
text=f"Adicionar {type_labels[tipo]}",
|
||||
command=lambda t=tipo: add_presence_row(t)
|
||||
).grid(row=0, column=1, sticky="w", padx=(10, 0))
|
||||
|
||||
container = ttk.Frame(sec)
|
||||
container.grid(row=1, column=0, columnspan=2, sticky="w", pady=(6, 0))
|
||||
type_frames[tipo] = container
|
||||
|
||||
build_presence_section(presence_frame, 0, "segurado", "Segurados")
|
||||
build_presence_section(presence_frame, 1, "lesado", "Lesados")
|
||||
build_presence_section(presence_frame, 2, "outro", "Outros")
|
||||
|
||||
add_presence_row("segurado")
|
||||
|
||||
|
||||
def on_generate():
|
||||
values = {k: e.get() for k, e in entries.items()}
|
||||
values["foto1_path"] = foto_var.get()
|
||||
values["fotos2_paths"] = list(fotos2_var.get()) if fotos2_var.get() else []
|
||||
values["tecnicas"] = [
|
||||
{
|
||||
"name": t["name"],
|
||||
"selected": t["var"].get(),
|
||||
"desc": t["desc"].get(),
|
||||
"photos": list(t["photos"].get()) if t["photos"].get() else [],
|
||||
}
|
||||
for t in tecnicas_data
|
||||
]
|
||||
values["inicio_pesquisa"] = [
|
||||
{
|
||||
"name": t["name"],
|
||||
"selected": t["var"].get(),
|
||||
"desc": t["desc"].get(),
|
||||
"photos": list(t["photos"].get()) if t["photos"].get() else [],
|
||||
}
|
||||
for t in inicio_data
|
||||
]
|
||||
values["presencas"] = []
|
||||
for tipo in ("segurado", "lesado", "outro"):
|
||||
for row in presenca_rows[tipo]:
|
||||
values["presencas"].append(
|
||||
{
|
||||
"tipo": tipo,
|
||||
"nome": row["nome"].get(),
|
||||
"info": row["info"].get(),
|
||||
}
|
||||
)
|
||||
run_generation(values, root)
|
||||
|
||||
|
||||
btns = ttk.Frame(frm)
|
||||
btns.grid(row=len(fields) + 2, column=0, columnspan=2, sticky="w", pady=(18, 0))
|
||||
|
||||
ttk.Button(btns, text="Gerar Word", command=on_generate).pack(side="left")
|
||||
ttk.Button(btns, text="Sair", command=root.destroy).pack(side="left", padx=10)
|
||||
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,39 +0,0 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['vaguatechrelatorios_VF1.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[('Corpus.docx', '.')],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='vaguatechrelatorios_VF1',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['icon.ico'],
|
||||
)
|
||||
Reference in New Issue
Block a user