init
This commit is contained in:
parent
83c0f74bf0
commit
2cb448eccf
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,3 +9,6 @@ docs/_book
|
||||
# TODO: where does this rule come from?
|
||||
test/
|
||||
|
||||
node_modules/
|
||||
|
||||
dist/
|
||||
13
.vscode/tasks.json
vendored
Normal file
13
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"label": "npm: build",
|
||||
"detail": "vite build"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,2 +1,5 @@
|
||||
# unilab-prints
|
||||
# Vue 3 + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support).
|
||||
|
||||
13
index.html
Normal file
13
index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
1566
package-lock.json
generated
Normal file
1566
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
package.json
Normal file
20
package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "vue-spa-export-tmp",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"html2pdf.js": "^0.10.3",
|
||||
"vue": "^3.5.13",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"vite": "^6.3.5"
|
||||
}
|
||||
}
|
||||
14
public/index.html
Normal file
14
public/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Certificato Prova</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script type="module" src="/vue-report/assets/main.js"></script>
|
||||
<link rel="stylesheet" href="/vue-report/assets/index.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
public/report_header.png
Normal file
BIN
public/report_header.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
1
public/vite.svg
Normal file
1
public/vite.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
374
src/App.vue
Normal file
374
src/App.vue
Normal file
@ -0,0 +1,374 @@
|
||||
<template>
|
||||
<div>
|
||||
<button class="pdf-button" @click="exportPdf">Esporta PDF</button>
|
||||
<div class="report" ref="printable" contenteditable="true">
|
||||
<header>
|
||||
<img src="/report_header.png" alt="Intestazione Unilab" class="report-header-image" />
|
||||
</header>
|
||||
|
||||
<h3 class="section-title">{{ intestazione.intest1 }}</h3>
|
||||
|
||||
<div>{{intestazione.modreport}}</div>
|
||||
|
||||
<h3 class="section-title">{{ intestazione.intest2 }}</h3>
|
||||
|
||||
<section class="info-block">
|
||||
<table class="info-table">
|
||||
<tr>
|
||||
<td>Direttore dei Lavori:</td>
|
||||
<td>{{ datiacc_info.directorName }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Indirizzo:</td>
|
||||
<td>{{ datiacc_info.directorAddress }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Proprietà:</td>
|
||||
<td>{{ datiacc_info.propertyName }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Indirizzo:</td>
|
||||
<td>{{ datiacc_info.propertyAddress }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cantiere:</td>
|
||||
<td>{{ datiacc_info.siteName }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Indirizzo:</td>
|
||||
<td>{{ datiacc_info.siteAddress }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Impresa esecutrice:</td>
|
||||
<td>{{ datiacc_info.contractorName }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Natura dei campioni:</td>
|
||||
<td>{{ datiacc_info.sampleNature }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- SEZIONE DINAMICA PER MATERIALE E TIPO CAMPIONE-->
|
||||
|
||||
<div>
|
||||
<component :is="resultComponent" :risult_data="risult_data" :intestazione="intestazione" :datiacc_data="datiacc_data" v-if="resultComponent" />
|
||||
</div>
|
||||
|
||||
|
||||
<!-- NOTE -->
|
||||
|
||||
<section v-if="note && note.length" class="note-section">
|
||||
<table class="note-table">
|
||||
<tr v-for="(n, index) in note" :key="index">
|
||||
<td>{{ n.text }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
|
||||
<footer>
|
||||
<div class="signatures">
|
||||
<p>Lo sperimentatore<br>Dott. Ing. Giacomo Calussi</p>
|
||||
<p>Il Direttore del Laboratorio<br>Dott. Ing. Paolo Neri</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import html2pdf from 'html2pdf.js'
|
||||
import A_CUB from './components/risultati/A_CUB.vue'
|
||||
import A_CIL from './components/risultati/A_CIL.vue'
|
||||
|
||||
const componentMap = {
|
||||
'A_CUB': A_CUB,
|
||||
'A_CIL': A_CIL,
|
||||
'B_BAR':B_BAR
|
||||
}
|
||||
|
||||
const printable = ref(null)
|
||||
|
||||
const intestazione = ref({})
|
||||
const datiacc_info = ref({})
|
||||
const datiacc_data = ref([])
|
||||
const risult_data = ref([])
|
||||
const note = ref([])
|
||||
|
||||
|
||||
const resultComponent = ref(null)
|
||||
|
||||
watch(
|
||||
() => [intestazione.value.tipMat, intestazione.value.tipCam],
|
||||
([tipMat, tipCam]) => {
|
||||
const key = `${(tipMat || '').toUpperCase()}_${(tipCam || '').toUpperCase()}`
|
||||
console.log('Updated key:', key)
|
||||
resultComponent.value = componentMap[key] || null
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const pSERCER = params.get('pSERCER') ?? 'DEFAULT'
|
||||
|
||||
const token = await getLoginToken('servizio_api', 'p0l01nf.'); // credenziali da gestire lato sicurezza
|
||||
const data = await fetchReportDataWithToken(token, pSERCER);
|
||||
|
||||
intestazione.value = data.intestazione
|
||||
datiacc_info.value = capitalizeAllFields(data.datiacc_info)
|
||||
datiacc_data.value = data.datiacc_data
|
||||
risult_data.value = calcolaMediaRcPerGruppo(data.risult_data)
|
||||
note.value = data.note ?? []
|
||||
|
||||
console.log('intestazione', intestazione.value)
|
||||
console.log('datiacc_info', datiacc_info.value)
|
||||
console.log('datiacc_data', datiacc_data.value)
|
||||
console.log('risult_data', risult_data.value)
|
||||
|
||||
} catch (err) {
|
||||
console.error('Errore caricamento dati:', err)
|
||||
}
|
||||
})
|
||||
|
||||
async function getLoginToken(username, password) {
|
||||
const credentials = btoa(`${username}:${password}`); // base64 encoding
|
||||
|
||||
const response = await fetch('/unilab/servlet/oauth/token?scope=logintoken', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Basic ${credentials}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'omit',
|
||||
body: JSON.stringify({ "sp_company": "001" })
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Autenticazione fallita');
|
||||
|
||||
const json = await response.json();
|
||||
return json.access_token;
|
||||
}
|
||||
|
||||
async function fetchReportDataWithToken(token, pSERCER) {
|
||||
const response = await fetch(`/unilab/servlet/api/pi_flabreportapi?pSERCER=${encodeURIComponent(pSERCER)}`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
credentials: 'omit'
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Errore caricamento dati');
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
function capitalizeAllFields(obj) {
|
||||
const result = {}
|
||||
for (const key in obj) {
|
||||
const val = obj[key]
|
||||
result[key] = typeof val === 'string' ? capitalizeEachWord(val) : val
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function capitalizeEachWord(str) {
|
||||
if (!str) return ''
|
||||
return str
|
||||
.toLowerCase()
|
||||
.split(' ')
|
||||
.map(word =>
|
||||
word.length > 0
|
||||
? word[0].toUpperCase() + word.slice(1)
|
||||
: ''
|
||||
)
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
|
||||
function exportPdf() {
|
||||
html2pdf()
|
||||
.from(printable.value)
|
||||
.set({
|
||||
filename: `certificato-prova.pdf`,
|
||||
html2canvas: { scale: 2 },
|
||||
jsPDF: {
|
||||
unit: 'mm',
|
||||
format: [210, 297], // A4
|
||||
orientation: 'portrait'
|
||||
}
|
||||
})
|
||||
.save()
|
||||
}
|
||||
|
||||
function formatDate(dateStr) {
|
||||
const date = new Date(dateStr)
|
||||
return date.toLocaleDateString('it-IT')
|
||||
}
|
||||
|
||||
function formatNumber(value, decimals = 2) {
|
||||
return value != null
|
||||
? Number(value).toLocaleString('it-IT', {
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals
|
||||
})
|
||||
: '—'
|
||||
}
|
||||
|
||||
function calcolaMediaRcPerGruppo(data) {
|
||||
const gruppi = {}
|
||||
|
||||
// Raggruppa per serPre
|
||||
data.forEach(row => {
|
||||
if (!gruppi[row.serPre]) gruppi[row.serPre] = []
|
||||
gruppi[row.serPre].push(row.rc)
|
||||
})
|
||||
|
||||
// Calcola la media per gruppo
|
||||
const medie = {}
|
||||
for (const serPre in gruppi) {
|
||||
const somma = gruppi[serPre].reduce((acc, val) => acc + val, 0)
|
||||
const media = somma / gruppi[serPre].length
|
||||
medie[serPre] = media
|
||||
}
|
||||
|
||||
// Assegna la media a rprelievo per tutte le righe
|
||||
return data.map(row => ({
|
||||
...row,
|
||||
rprelievo: formatNumber(medie[row.serPre],2)
|
||||
}))
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.report-header-image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.report {
|
||||
width: 100%;
|
||||
max-width: 210mm;
|
||||
padding: 4mm;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
header {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
padding: 6px;
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sub-header {
|
||||
padding: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border: 1px solid #000;
|
||||
padding: 2px;
|
||||
font-size: 0.85em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-table {
|
||||
width: 80%;
|
||||
border: 2px solid black;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.info-table th,
|
||||
.info-table td {
|
||||
border: 1px solid black;
|
||||
padding: 2px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.info-table th:first-child,
|
||||
.info-table td:first-child {
|
||||
font-weight: bold;
|
||||
width: 30%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.note-section {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.note-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.note-table td {
|
||||
padding: 1px 1px;
|
||||
font-size: 0.7em;
|
||||
border: none;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.signatures {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 40px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.pdf-button {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background-color: #007BFF;
|
||||
color: white;
|
||||
padding: 10px 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.pdf-button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
27
src/components/ExportButtons.vue
Normal file
27
src/components/ExportButtons.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div class="mt-4 space-x-2">
|
||||
<button @click="downloadPDF" class="bg-blue-500 text-white px-4 py-2 rounded">Export PDF</button>
|
||||
<button @click="downloadExcel" class="bg-green-500 text-white px-4 py-2 rounded">Export Excel</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import html2pdf from 'html2pdf.js';
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
const props = defineProps({
|
||||
report: Object,
|
||||
printRef: Object
|
||||
});
|
||||
|
||||
function downloadPDF() {
|
||||
html2pdf().from(props.printRef.value.$el).save('report.pdf');
|
||||
}
|
||||
|
||||
function downloadExcel() {
|
||||
const ws = XLSX.utils.json_to_sheet(props.report.samples);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Report");
|
||||
XLSX.writeFile(wb, "report.xlsx");
|
||||
}
|
||||
</script>
|
||||
40
src/components/PagePreview.vue
Normal file
40
src/components/PagePreview.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div ref="printArea" class="border p-4 bg-white">
|
||||
<div>
|
||||
<h2 class="font-semibold">Report ID: {{ report.reportId }}</h2>
|
||||
<p><strong>Date:</strong> {{ report.date }}</p>
|
||||
<p><strong>Site:</strong> {{ report.site }}</p>
|
||||
</div>
|
||||
<table class="table-auto w-full mt-4 border">
|
||||
<thead>
|
||||
<tr class="bg-gray-100">
|
||||
<th class="border px-2 py-1">ID</th>
|
||||
<th class="border px-2 py-1">Date</th>
|
||||
<th class="border px-2 py-1">a (mm)</th>
|
||||
<th class="border px-2 py-1">b (mm)</th>
|
||||
<th class="border px-2 py-1">h (mm)</th>
|
||||
<th class="border px-2 py-1">Mass (kg/m³)</th>
|
||||
<th class="border px-2 py-1">Rc (N/mm²)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="sample in report.samples" :key="sample.id">
|
||||
<td class="border px-2 py-1">{{ sample.id }}</td>
|
||||
<td class="border px-2 py-1">{{ sample.date }}</td>
|
||||
<td class="border px-2 py-1">{{ sample.a }}</td>
|
||||
<td class="border px-2 py-1">{{ sample.b }}</td>
|
||||
<td class="border px-2 py-1">{{ sample.h || '-' }}</td>
|
||||
<td class="border px-2 py-1">{{ sample.mass }}</td>
|
||||
<td class="border px-2 py-1">{{ sample.rc }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="mt-4 italic text-sm">{{ report.note }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
report: Object
|
||||
});
|
||||
</script>
|
||||
98
src/components/risultati/A_CIL.vue
Normal file
98
src/components/risultati/A_CIL.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<h3 class="section-title">DATI DICHIARATI ALL’ACCETTAZIONE</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID<br>Provino</th>
|
||||
<th>Contrassegno</th>
|
||||
<th>Verbale<br>di prelievo n.</th>
|
||||
<th>Data<br>prelievo</th>
|
||||
<th>R<sub>CK</sub></th>
|
||||
<th>Area o elemento strutturale</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in datiacc_data" :key="row.idProvino">
|
||||
<td>{{ row.idProvino }}</td>
|
||||
<td>{{ row.contrassegno }}</td>
|
||||
<td>{{ row.verbale }}</td>
|
||||
<td>{{ formatDate(row.dataPrelievo) }}</td>
|
||||
<td>{{ formatNumber(row.rck, 0) }}</td>
|
||||
<td v-if="row.rowspanArea > 0" :rowspan="row.rowspanArea">{{ row.area }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- RISULTATI -->
|
||||
|
||||
<div class="section-title">{{ intestazione.prova1 }}</div>
|
||||
<div class="sub-header">{{ intestazione.prova2 }}</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="5">DATI PRELIMINARI ALLA PROVA</th>
|
||||
<th colspan="5">RESISTENZA ALLA COMPRESSIONE</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th rowspan="3">ID<br>Provino</th>
|
||||
<th rowspan="3">Data<br>prova</th>
|
||||
<th colspan="2">Dimensioni</th>
|
||||
<th rowspan="2">Massa<br>volumica</th>
|
||||
<th rowspan="2">F</th>
|
||||
<th rowspan="2">R<sub>c</sub></th>
|
||||
<th rowspan="2">R<sub>PRELIEVO</sub></th>
|
||||
<th rowspan="3">R**</th>
|
||||
<th rowspan="3">P***</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>D</th>
|
||||
<th>h</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>[mm]</th>
|
||||
<th>[mm]</th>
|
||||
<th>[kg/m³]</th>
|
||||
<th>[kN]</th>
|
||||
<th>[N/mm²]</th>
|
||||
<th>[N/mm²]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in risult_data" :key="row.idProvino">
|
||||
<td>{{ row.idProvino }}</td>
|
||||
<td>{{ formatDate(row.dataProva) }}</td>
|
||||
<td>{{ formatNumber(row.dimA, 2) }}</td>
|
||||
<td>{{ formatNumber(row.dimH, 2) }}</td>
|
||||
<td>{{ formatNumber(row.massaVolumica, 0) }}</td>
|
||||
<td>{{ formatNumber(row.f, 1) }}</td>
|
||||
<td>{{ formatNumber(row.rc, 2) }}</td>
|
||||
<td v-if="row.rowspanRprelievo > 0" :rowspan="row.rowspanRprelievo">{{ row.rprelievo }}</td>
|
||||
<td>{{ row.rType }}</td>
|
||||
<td>{{ row.pType }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
risult_data: Array,
|
||||
datiacc_data: Array,
|
||||
intestazione: Object
|
||||
})
|
||||
|
||||
function formatDate(dateStr) {
|
||||
return new Date(dateStr).toLocaleDateString('it-IT')
|
||||
}
|
||||
|
||||
function formatNumber(val, decimals) {
|
||||
return val != null
|
||||
? Number(val).toLocaleString('it-IT', {
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals
|
||||
})
|
||||
: '—'
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
101
src/components/risultati/A_CUB.vue
Normal file
101
src/components/risultati/A_CUB.vue
Normal file
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<h3 class="section-title">DATI DICHIARATI ALL’ACCETTAZIONE</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID<br>Provino</th>
|
||||
<th>Contrassegno</th>
|
||||
<th>Verbale<br>di prelievo n.</th>
|
||||
<th>Data<br>prelievo</th>
|
||||
<th>R<sub>CK</sub></th>
|
||||
<th>Area o elemento strutturale</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in datiacc_data" :key="row.idProvino">
|
||||
<td>{{ row.idProvino }}</td>
|
||||
<td>{{ row.contrassegno }}</td>
|
||||
<td>{{ row.verbale }}</td>
|
||||
<td>{{ formatDate(row.dataPrelievo) }}</td>
|
||||
<td>{{ formatNumber(row.rck, 0) }}</td>
|
||||
<td v-if="row.rowspanArea > 0" :rowspan="row.rowspanArea">{{ row.area }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- RISULTATI -->
|
||||
|
||||
<div class="section-title">{{ intestazione.prova1 }}</div>
|
||||
<div class="sub-header">{{ intestazione.prova2 }}</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="6">DATI PRELIMINARI ALLA PROVA</th>
|
||||
<th colspan="5">RESISTENZA ALLA COMPRESSIONE</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th rowspan="3">ID<br>Provino</th>
|
||||
<th rowspan="3">Data<br>prova</th>
|
||||
<th colspan="3">Dimensioni</th>
|
||||
<th rowspan="2">Massa<br>volumica</th>
|
||||
<th rowspan="2">F</th>
|
||||
<th rowspan="2">R<sub>c</sub></th>
|
||||
<th rowspan="2">R<sub>PRELIEVO</sub></th>
|
||||
<th rowspan="3">R**</th>
|
||||
<th rowspan="3">P***</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
<th>h</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>[mm]</th>
|
||||
<th>[mm]</th>
|
||||
<th>[mm]</th>
|
||||
<th>[kg/m³]</th>
|
||||
<th>[kN]</th>
|
||||
<th>[N/mm²]</th>
|
||||
<th>[N/mm²]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in risult_data" :key="row.idProvino">
|
||||
<td>{{ row.idProvino }}</td>
|
||||
<td>{{ formatDate(row.dataProva) }}</td>
|
||||
<td>{{ formatNumber(row.dimA, 2) }}</td>
|
||||
<td>{{ formatNumber(row.dimB, 2) }}</td>
|
||||
<td>{{ formatNumber(row.dimH, 2) }}</td>
|
||||
<td>{{ formatNumber(row.massaVolumica, 0) }}</td>
|
||||
<td>{{ formatNumber(row.f, 1) }}</td>
|
||||
<td>{{ formatNumber(row.rc, 2) }}</td>
|
||||
<td v-if="row.rowspanRprelievo > 0" :rowspan="row.rowspanRprelievo">{{ row.rprelievo }}</td>
|
||||
<td>{{ row.rType }}</td>
|
||||
<td>{{ row.pType }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
risult_data: Array,
|
||||
datiacc_data: Array,
|
||||
intestazione: Object
|
||||
})
|
||||
|
||||
function formatDate(dateStr) {
|
||||
return new Date(dateStr).toLocaleDateString('it-IT')
|
||||
}
|
||||
|
||||
function formatNumber(val, decimals) {
|
||||
return val != null
|
||||
? Number(val).toLocaleString('it-IT', {
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals
|
||||
})
|
||||
: '—'
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
98
src/components/risultati/B_BAR.vue
Normal file
98
src/components/risultati/B_BAR.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<h3 class="section-title">DATI PRELIMINARI DI PROVA</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID<br>Provino</th>
|
||||
<th>Contrassegno</th>
|
||||
<th>Verbale<br>di prelievo n.</th>
|
||||
<th>Data<br>prelievo</th>
|
||||
<th>R<sub>CK</sub></th>
|
||||
<th>Area o elemento strutturale</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in datiacc_data" :key="row.idProvino">
|
||||
<td>{{ row.idProvino }}</td>
|
||||
<td>{{ row.contrassegno }}</td>
|
||||
<td>{{ row.verbale }}</td>
|
||||
<td>{{ formatDate(row.dataPrelievo) }}</td>
|
||||
<td>{{ formatNumber(row.rck, 0) }}</td>
|
||||
<td v-if="row.rowspanArea > 0" :rowspan="row.rowspanArea">{{ row.area }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- RISULTATI -->
|
||||
|
||||
<div class="section-title">{{ intestazione.prova1 }}</div>
|
||||
<div class="sub-header">{{ intestazione.prova2 }}</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="5">DATI PRELIMINARI ALLA PROVA</th>
|
||||
<th colspan="5">RESISTENZA ALLA COMPRESSIONE</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th rowspan="3">ID<br>Provino</th>
|
||||
<th rowspan="3">Data<br>prova</th>
|
||||
<th colspan="2">Dimensioni</th>
|
||||
<th rowspan="2">Massa<br>volumica</th>
|
||||
<th rowspan="2">F</th>
|
||||
<th rowspan="2">R<sub>c</sub></th>
|
||||
<th rowspan="2">R<sub>PRELIEVO</sub></th>
|
||||
<th rowspan="3">R**</th>
|
||||
<th rowspan="3">P***</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>D</th>
|
||||
<th>h</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>[mm]</th>
|
||||
<th>[mm]</th>
|
||||
<th>[kg/m³]</th>
|
||||
<th>[kN]</th>
|
||||
<th>[N/mm²]</th>
|
||||
<th>[N/mm²]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in risult_data" :key="row.idProvino">
|
||||
<td>{{ row.idProvino }}</td>
|
||||
<td>{{ formatDate(row.dataProva) }}</td>
|
||||
<td>{{ formatNumber(row.dimA, 2) }}</td>
|
||||
<td>{{ formatNumber(row.dimH, 2) }}</td>
|
||||
<td>{{ formatNumber(row.massaVolumica, 0) }}</td>
|
||||
<td>{{ formatNumber(row.f, 1) }}</td>
|
||||
<td>{{ formatNumber(row.rc, 2) }}</td>
|
||||
<td v-if="row.rowspanRprelievo > 0" :rowspan="row.rowspanRprelievo">{{ row.rprelievo }}</td>
|
||||
<td>{{ row.rType }}</td>
|
||||
<td>{{ row.pType }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
risult_data: Array,
|
||||
datiacc_data: Array,
|
||||
intestazione: Object
|
||||
})
|
||||
|
||||
function formatDate(dateStr) {
|
||||
return new Date(dateStr).toLocaleDateString('it-IT')
|
||||
}
|
||||
|
||||
function formatNumber(val, decimals) {
|
||||
return val != null
|
||||
? Number(val).toLocaleString('it-IT', {
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals
|
||||
})
|
||||
: '—'
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
5
src/main.js
Normal file
5
src/main.js
Normal file
@ -0,0 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import './style.css'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
8
src/style.css
Normal file
8
src/style.css
Normal file
@ -0,0 +1,8 @@
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
color: #1f2937;
|
||||
}
|
||||
17
vite.config.js
Normal file
17
vite.config.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
base: '/vue-report/',
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
rollupOptions: {
|
||||
output: {
|
||||
entryFileNames: 'assets/main.js',
|
||||
chunkFileNames: 'assets/[name].js',
|
||||
assetFileNames: 'assets/[name][extname]'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user