First working example

This commit is contained in:
Nicola Carminati
2019-05-12 19:18:12 +02:00
parent f85f581326
commit 191ce5acbe
19 changed files with 690 additions and 66 deletions
+77 -2
View File
@@ -1,8 +1,83 @@
import { store,AppModel,appModelActions } from "./store/app.store";
import { store,AppModel,appModelActions,machineModel } from "./store/app.store";
var appInfo: AppModel = {name: "",version: "", ipAddress: ""};
var mach1 = {
rowNum: 1,
lastUpdate: new Date("2019-04-03T18:33:14.24"),
idxMacchina: "SIM_DP_01",
codMacchina: "SIMDP1",
nome: "IOB SimDP1",
url: "Steamware.png",
idxODL: 2208,
codArticolo: "027309",
numPezzi: 500,
tCAssegnato: 1.08300000,
dataInizioODL: new Date("2019-04-03T18:33:14.24"),
semaforo: "sVe",
idxStato: 13,
descrizioneStato: "lavorazione",
durata: 557.0,
pezziProd: 20956,
pezziConf: 0,
tempoOn: 0.00000000,
tempoAuto: 0.00000000,
tempoRun: 0.00000000,
tCMedio: 0.00000000,
tCLav: 0.00000000,
tCEff: 0.00000000,
tCMedioRT: 0.00000000,
tCLavRT: 0.00000000,
tCEffRT: 0.00000000,
disegno: ""
} as machineModel
var mach2 = {
rowNum: 1,
lastUpdate: new Date("2019-04-03T18:33:14.24"),
idxMacchina: "SIM_DP_02",
codMacchina: "SIMDP2",
nome: "IOB SimDP2",
url: "Steamware.png",
idxODL: 2208,
codArticolo: "027309",
numPezzi: 500,
tCAssegnato: 1.08300000,
dataInizioODL: new Date("2019-04-03T18:33:14.24"),
semaforo: "sGi",
idxStato: 13,
descrizioneStato: "lavorazione",
durata: 557.0,
pezziProd: 20956,
pezziConf: 0,
tempoOn: 0.00000000,
tempoAuto: 0.00000000,
tempoRun: 0.00000000,
tCMedio: 0.00000000,
tCLav: 0.00000000,
tCEff: 0.00000000,
tCMedioRT: 0.00000000,
tCLavRT: 0.00000000,
tCEffRT: 0.00000000,
disegno: ""
} as machineModel
setInterval(test,300);
function test(){
mach1.durata = Math.random()*100;
}
var appInfo: AppModel = {name: "",version: "", ipAddress: "", copyright: ""};
appInfo.name = "MP MONITOR"
appInfo.version = "v 6.6.1904.1188"
appInfo.ipAddress = "10.74.82.20"
appInfo.copyright = "2007 - 2019 ©"
appInfo.machines = [
mach1,
mach2
]
appModelActions.Setup(store,appInfo);
+1 -3
View File
@@ -20,12 +20,10 @@ import { AppModel,appModelActions } from "./store/app.store";
})
export default class app extends Vue {
beforeMount() {
}
mounted() {
}
};
+172 -3
View File
@@ -16,21 +16,29 @@
.navbar .align-right {
text-align: right;
}
.navbar .nav-link {
color: #FFF !important;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
height: 60px;
line-height: 60px;
height: 40px;
line-height: 40px;
background-color: #000;
color: #FFF;
overflow: hidden;
}
.footer .container {
width: auto;
max-width: 680px;
padding: 0 15px;
margin-right: auto;
margin-left: auto;
display: flex;
justify-content: space-between;
}
.footer .logo-company {
max-height: 85%;
}
.error-container {
height: 100%;
@@ -43,23 +51,182 @@
padding: 20px;
border-radius: 5px;
}
.card-multi {
width: 100%;
height: 18em;
margin: 5px;
color: white;
border-radius: 2px;
padding: 4px;
position: relative;
background-color: rgba(180, 180, 180, 0.6);
-webkit-box-shadow: 0px 0px 8px 0px rgba(51, 51, 51, 0.53);
-moz-box-shadow: 0px 0px 8px 0px rgba(51, 51, 51, 0.53);
box-shadow: 0px 0px 8px 0px rgba(51, 51, 51, 0.53);
overflow-x: hidden;
overflow-y: auto;
}
@media (min-width: 992px) {
.card-multi {
width: 18em;
}
}
@media (max-width: 575.98px) {
.card-multi {
height: 31em;
}
}
.card-multi.sVe {
background-color: rgba(0, 255, 80, 0.6);
}
.card-multi.sGre {
background-color: rgba(180, 180, 180, 0.6);
}
.card-multi.sGi {
background-color: rgba(230, 210, 0, 0.6);
animation-name: YellowStatus;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
@keyframes YellowStatus {
from {
background-color: rgba(230, 210, 0, 0.6);
}
to {
background-color: rgba(255, 255, 0, 0.8);
}
}
.card-multi.sRo {
background-color: rgba(200, 0, 5, 0.6);
animation-name: RedStatus;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
@keyframes RedStatus {
from {
background-color: rgba(200, 0, 5, 0.6);
}
to {
background-color: rgba(255, 60, 80, 0.8);
}
}
.card-multi .name {
width: 100%;
font-size: 3em;
line-height: 2em;
background-color: rgba(61, 61, 61, 0.5);
text-align: center;
text-shadow: 2px 2px 0px #000000;
white-space: nowrap;
}
.card-multi .labelcont {
padding-top: 0;
padding-bottom: 0;
font-weight: bold;
padding-left: 0;
display: flex;
align-items: center;
justify-content: flex-end;
}
@media (max-width: 575.98px) {
.card-multi .labelcont {
justify-content: flex-start;
margin-top: 0.8em;
}
}
.card-multi .inpcont {
padding: 0;
display: flex;
align-items: center;
justify-content: flex-start;
}
.card-multi .nodata {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 2em;
text-align: center;
font-weight: bold;
}
.card-multi .baseline {
width: 100%;
position: absolute;
top: calc(92%);
left: 0;
background-color: transparent;
padding: 0px 4px 4px 4px;
}
@media (max-width: 575.98px) {
.card-multi .baseline {
top: calc(95%);
}
}
.card-multi .baseline .cont {
background-color: rgba(61, 61, 61, 0.5);
font-size: 0.8em;
text-align: right;
padding-left: 10px;
padding-right: 10px;
white-space: nowrap;
overflow: hidden;
}
html,
body,
#app {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
font-family: 'Open Sans Condensed', sans-serif;
background-color: #5d5d5d;
background-image: linear-gradient(#808080, #5d5d5d);
}
body ::-webkit-scrollbar {
width: 5px;
height: 5px;
}
body ::-webkit-scrollbar-button {
width: 0px;
height: 0px;
}
body ::-webkit-scrollbar-thumb {
background: #e1e1e1;
border: 0px none #ffffff;
border-radius: 50px;
}
body ::-webkit-scrollbar-thumb:hover {
background: #ffffff;
}
body ::-webkit-scrollbar-thumb:active {
background: #000000;
}
body ::-webkit-scrollbar-track {
background: #666666;
border: 0px none #ffffff;
border-radius: 50px;
}
body ::-webkit-scrollbar-track:hover {
background: #666666;
}
body ::-webkit-scrollbar-track:active {
background: #333333;
}
body ::-webkit-scrollbar-corner {
background: transparent;
}
.container {
max-width: 100%;
padding: 0px 15px;
margin: 0;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
}
.container .row {
max-width: 100%;
@@ -69,6 +236,8 @@ body {
max-width: 100%;
margin: 0;
padding-top: 90px;
display: flex;
flex-flow: row wrap;
}
.container .main-content .content {
background-color: white;
+4 -3
View File
@@ -6,16 +6,17 @@ import { store,AppModel } from "../../store/app.store";
export default class AppFooter extends Vue {
beforeMount() {
}
mounted() {
}
private get appName(){
return (store.state as AppModel).name;
}
private get appVersion(){
return (store.state as AppModel).version;
private get appCopyright(){
return (store.state as AppModel).copyright;
}
};
+4
View File
@@ -2,6 +2,10 @@
<footer class="footer">
<div class="container">
<span>{{appName}}</span>
<span>
{{appCopyright}}
<img src="../../assets/images/logoSteamware.png" class="logo-company">
</span>
</div>
</footer>
</template>
+4 -18
View File
@@ -1,33 +1,19 @@
import Vue from "vue";
import Component from "vue-class-component";
import moment from "moment";
import appInfo from "./sub-components/app-info.vue"
import { store,AppModel } from "../../store/app.store";
@Component({ name: "app-header", components: { } })
@Component({ name: "app-header", components: { appInfo} })
export default class AppHeader extends Vue {
actualTime: string = "";
beforeMount() {
this.setupTime();
}
mounted() {
}
private setupTime(){
moment.locale('it');
this.setTime();
setInterval(this.setTime,10000);
}
private setTime(){
this.actualTime = moment().format('dddd D MMMM YYYY, HH:mm');
}
private get appName(){
return (store.state as AppModel).name;
}
private get appVersion(){
return (store.state as AppModel).version;
}
private get ipAddress(){
return (store.state as AppModel).ipAddress;
}
};
+1 -13
View File
@@ -10,22 +10,10 @@
type="button"
data-toggle="collapse"
data-target="#navbarResponsive"
aria-controls="navbarResponsive"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<span class="nav-link align-right">
{{actualTime}}<br />
{{ipAddress}} | {{appVersion}}
</span>
</li>
</ul>
</div>
<appInfo></appInfo>
</div>
</nav>
</template>
@@ -0,0 +1,35 @@
import Vue from "vue";
import Component from "vue-class-component";
import moment from "moment";
import { store,AppModel } from "../../../store/app.store";
@Component({ name: "app-info", components: { } })
export default class AppInfo extends Vue {
actualTime: string = "";
beforeMount() {
this.setupTime();
}
mounted() {
}
private setupTime(){
moment.locale('it');
this.setTime();
setInterval(this.setTime,10000);
}
private setTime(){
this.actualTime = moment().format('dddd D MMMM YYYY, HH:mm');
}
private get appVersion(){
return (store.state as AppModel).version;
}
private get ipAddress(){
return (store.state as AppModel).ipAddress;
}
};
@@ -0,0 +1,15 @@
<template>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<span class="nav-link align-right">
{{actualTime}}<br />
{{ipAddress}} | {{appVersion}}
</span>
</li>
</ul>
</div>
</template>
<script src="./app-info.ts" lang="ts"></script>
+7 -9
View File
@@ -1,23 +1,21 @@
import Vue from "vue";
import Component from "vue-class-component";
import cardMulti from "./sub-components/card-multi.vue"
import { store,AppModel,MachineGetters } from "../../store/app.store";
@Component({ name: "multi-view", components: { } })
@Component({ name: "multi-view", components: { cardMulti } })
export default class MultiView extends Vue {
obj: string = "Hello World";
intValue:number = 0;
beforeMount() {
}
mounted() {
}
private get machines(){
return (this.$store.getters as MachineGetters).getMachines();
}
private plus(){
this.intValue ++;
}
private minus(){
this.intValue --;
}
};
+12 -10
View File
@@ -1,15 +1,17 @@
<template>
<div class="main-content row">
<div class="col-lg-12 text-center content">
<h1 class="mt-5">{{obj}}</h1>
<div class="row">
<div class="col-sm-6 text-center">
<button type="button" class="btn btn-primary" @click="minus">-</button>
<button type="button" class="btn btn-primary" @click="plus">+</button>
</div>
<div class="col-sm-6 text-left">{{intValue}}</div>
</div>
</div>
<cardMulti v-for="(n, key) in machines" :key="'Mach' + key"
:nome="n.nome"
:semaforo="n.semaforo"
:codArticolo="n.codArticolo"
:descrizioneStato="n.descrizioneStato"
:durata="n.durata"
:tCLav="n.tCLav"
:tCEff="n.tCEff"
:pezziProd="n.pezziProd"
:lastUpdate="n.lastUpdate"
:pezziConf="n.pezziConf"
></cardMulti>
</div>
</template>
<script src="./multi-view.ts" lang="ts"></script>
@@ -0,0 +1,94 @@
import Vue from "vue";
import Component from "vue-class-component";
import { Watch, Prop } from "vue-property-decorator";
import { machineModel } from "../../../store/app.store";
import moment from "moment";
@Component({
name: "card-multi",
components: {},
props:{
nome:
{
type: String,
default: ""
},
semaforo:
{
type: String,
default: "sGre"
},
codArticolo:
{
type: String,
default: ""
},
descrizioneStato:
{
type: String,
default: ""
},
durata:
{
type: Number,
default: 0
},
tCLav:
{
type: Number,
default: 0
},
tCEff:
{
type: Number,
default: 0
},
pezziProd:
{
type: Number,
default: 0
},
pezziConf:
{
type: Number,
default: 0
},
lastUpdate:
{
type: Date,
default: new Date()
},
}
})
export default class cardMulti extends Vue {
colorClass: string = "sGre";
dataOK: boolean = false;
test: machineModel;
beforeMount() {
}
mounted() {
this.elaborateData()
}
@Watch("$props")
propChanged() {
this.elaborateData();
}
elaborateData(){
if(this.$props.nome)
this.dataOK = true;
else
this.dataOK = false;
this.colorClass = this.$props.semaforo;
}
get lastUpdateIT() { //
return moment(this.$props.lastUpdate).format('DD/MM/YYYY HH:mm:ss');
}
};
@@ -0,0 +1,40 @@
<template>
<div class="card-multi" :class="colorClass">
<div v-if="dataOK">
<div class="name">{{$props.nome}}</div>
<div class="form-group row">
<label class="col-lg-6 col-sm-9 col-form-label labelcont">Art:</label>
<label class="col-lg-6 col-sm-3 col-form-label inpcont">{{$props.codArticolo}}</label>
</div>
<div class="form-group row">
<label class="col-lg-6 col-sm-9 col-form-label labelcont">Status</label>
<label class="col-lg-6 col-sm-3 col-form-label inpcont">{{$props.descrizioneStato}}</label>
</div>
<div class="form-group row">
<label class="col-lg-6 col-sm-9 col-form-label labelcont">Durata</label>
<label class="col-lg-6 col-sm-3 col-form-label inpcont">{{$props.durata.toFixed(0)}}</label>
</div>
<div class="form-group row">
<label class="col-lg-6 col-sm-9 col-form-label labelcont">T. CIclo STD:</label>
<label class="col-lg-6 col-sm-3 col-form-label inpcont">{{$props.tCLav.toFixed(0)}}</label>
</div>
<div class="form-group row">
<label class="col-lg-6 col-sm-9 col-form-label labelcont">T. CIclo ACT:</label>
<label class="col-lg-6 col-sm-3 col-form-label inpcont">{{$props.tCEff.toFixed(0)}}</label>
</div>
<div class="form-group row">
<label class="col-lg-6 col-sm-9 col-form-label labelcont">Pezzi</label>
<label class="col-lg-6 col-sm-3 col-form-label inpcont">{{$props.pezziProd.toFixed(0)}} / {{$props.pezziConf.toFixed(0)}}</label>
</div>
<div class="baseline">
<div class="cont">{{lastUpdateIT}}</div>
</div>
</div>
<div v-else class="nodata">Nessun dato da mostrare</div>
</div>
</template>
<script src="./card-multi.ts" lang="ts"></script>
+129
View File
@@ -0,0 +1,129 @@
// out: false, sourceMap: false, main: style.less
.card-multi {
width: 100%;
height: 18em;
@media (min-width: 992px) {
width: 18em;
}
@media (max-width: 575.98px) {
height: 31em;
}
margin: 5px;
color: white;
border-radius: 2px;
padding: 4px;
position: relative;
background-color: rgba(180, 180, 180, 0.6);
-webkit-box-shadow: 0px 0px 8px 0px rgba(51, 51, 51, 0.53);
-moz-box-shadow: 0px 0px 8px 0px rgba(51, 51, 51, 0.53);
box-shadow: 0px 0px 8px 0px rgba(51, 51, 51, 0.53);
overflow-x: hidden;
overflow-y: auto;
&.sVe {
background-color: rgba(0, 255, 80, 0.6);
}
&.sGre {
background-color: rgba(180, 180, 180, 0.6);
}
&.sGi {
background-color: rgba(230, 210, 0, 0.6);
animation-name: YellowStatus;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
@keyframes YellowStatus {
from {
background-color: rgba(230, 210, 0, 0.6);
}
to {
background-color: rgba(255, 255, 0, 0.8);
}
}
&.sRo {
background-color: rgba(200, 0, 5, 0.6);
animation-name: RedStatus;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
@keyframes RedStatus {
from {
background-color: rgba(200, 0, 5, 0.6);
}
to {
background-color: rgba(255, 60, 80, 0.8);
}
}
.name {
width: 100%;
font-size: 3em;
line-height: 2em;
background-color: @color-grey-dark-semi;
text-align: center;
text-shadow: 2px 2px 0px #000000;
white-space: nowrap;
}
.labelcont{
padding-top: 0;
padding-bottom: 0;
font-weight: bold;
padding-left: 0;
display: flex;
align-items: center;
justify-content: flex-end;
@media (max-width: 575.98px) {
justify-content: flex-start;
margin-top: 0.8em;
}
}
.inpcont{
padding: 0;
display: flex;
align-items: center;
justify-content: flex-start;
}
.nodata{
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 2em;
text-align: center;
font-weight: bold;
}
.baseline{
width: 100%;
position: absolute;
top: calc(100% - 8px);
@media (max-width: 575.98px) {
top: calc(100% - 5px);
}
left: 0;
background-color: transparent;
padding: 0px 4px 4px 4px;
.cont{
background-color: @color-grey-dark-semi;
font-size: 0.8em;
text-align: right;
padding-left: 10px;
padding-right: 10px;
white-space: nowrap;
overflow: hidden;
}
}
}
+1
View File
@@ -3,4 +3,5 @@
@color-black-100: #000;
@color-white-100: #FFF;
@color-grey-light: #5d5d5d;
@color-grey-dark-semi: rgba(61, 61, 61, 0.5);
+8 -3
View File
@@ -6,16 +6,21 @@
position: absolute;
bottom: 0;
width: 100%;
height: 60px;
line-height: 60px;
height: 40px;
line-height: 40px;
background-color: @color-black-100;
color: @color-white-100;
overflow: hidden;
.container {
width: auto;
max-width: 680px;
padding: 0 15px;
margin-right: auto;
margin-left: auto;
display: flex;
justify-content: space-between;
}
.logo-company{
max-height: 85%;
}
}
+4
View File
@@ -23,5 +23,9 @@
.align-right{
text-align: right;
}
.nav-link{
color: @color-white-100 !important;
}
}
+41
View File
@@ -4,24 +4,62 @@
@import "header.less";
@import "footer.less";
@import "errorPages.less";
@import "card.less";
html, body,#app {
height:100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body{
font-family: 'Open Sans Condensed', sans-serif;
background-color: @color-grey-light;
background-image: linear-gradient(#808080, #5d5d5d);
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-button {
width: 0px;
height: 0px;
}
::-webkit-scrollbar-thumb {
background: #e1e1e1;
border: 0px none #ffffff;
border-radius: 50px;
}
::-webkit-scrollbar-thumb:hover {
background: #ffffff;
}
::-webkit-scrollbar-thumb:active {
background: #000000;
}
::-webkit-scrollbar-track {
background: #666666;
border: 0px none #ffffff;
border-radius: 50px;
}
::-webkit-scrollbar-track:hover {
background: #666666;
}
::-webkit-scrollbar-track:active {
background: #333333;
}
::-webkit-scrollbar-corner {
background: transparent;
}
}
.container{
max-width: 100%;
padding: 0px 15px;
margin: 0;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
.row{
max-width: 100%;
margin: 0;
@@ -30,9 +68,12 @@ body{
max-width: 100%;
margin: 0;
padding-top: 90px;
display: flex;
flex-flow: row wrap;
.content{
background-color: white;
}
}
}
+41 -2
View File
@@ -4,11 +4,43 @@ import Vuex from 'vuex'
Vue.use(Vuex);
export interface machineModel {
rowNum: number,
lastUpdate: Date,
idxMacchina: string,
codMacchina: string,
nome: string,
url: string,
idxODL: number,
codArticolo: string,
numPezzi: number,
tCAssegnato: number,
dataInizioODL: Date,
semaforo: string,
idxStato: number,
descrizioneStato: string,
durata: number,
pezziProd: number,
pezziConf: number,
tempoOn: number,
tempoAuto: number,
tempoRun: number,
tCMedio: number,
tCLav: number,
tCEff: number,
tCMedioRT: number,
tCLavRT: number,
tCEffRT: number,
disegno: string,
}
// Store Model
export interface AppModel {
name: string;
version: string;
ipAddress: string;
copyright: string;
machines?: Array<machineModel>;
}
// Avaiable Actions for this Store as Interface
@@ -16,18 +48,25 @@ export interface AppModelActionsInterface {
Setup(context, appModel);
}
export interface MachineGetters{
getMachines: () => Array<machineModel>;
}
// Main store declaration
const _store = {
state: {
name: "",
version: "",
ipAddress: ""
ipAddress: "",
copyright: "",
machines: [],
_machines: new Map<string, machineModel>(),
} as AppModel,
getters: {
getMachines: (state) => () : Array<machineModel> => state.machines
},
mutations: {
setup(store, appModel:AppModel) {
for (const key in appModel) {