timeline chart

This commit is contained in:
Giacomo Canonico
2019-03-14 13:04:09 +01:00
parent 002897ec87
commit 7c0816dfc3
19 changed files with 6465 additions and 4488 deletions
+9 -1
View File
@@ -110,6 +110,12 @@
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Security.Claims, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Claims.4.0.1\lib\net46\System.Security.Claims.dll</HintPath>
</Reference>
<Reference Include="System.Security.Principal.Windows, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Principal.Windows.4.0.0\lib\net46\System.Security.Principal.Windows.dll</HintPath>
</Reference>
<Reference Include="System.Web.Cors, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.Cors.5.2.3\lib\net45\System.Web.Cors.dll</HintPath>
</Reference>
@@ -197,7 +203,9 @@
<Compile Include="WebApiUnhandledExceptionHandler.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="App.config" />
<Content Include="App.config">
<SubType>Designer</SubType>
</Content>
<Content Include="App.Debug.config">
<DependentUpon>App.config</DependentUpon>
</Content>
+2
View File
@@ -31,5 +31,7 @@
<package id="Owin" version="1.0" targetFramework="net462" />
<package id="Swashbuckle" version="5.6.0" targetFramework="net462" />
<package id="Swashbuckle.Core" version="5.6.0" targetFramework="net462" />
<package id="System.Security.Claims" version="4.0.1" targetFramework="net462" />
<package id="System.Security.Principal.Windows" version="4.0.0" targetFramework="net462" />
<package id="WebActivatorEx" version="2.2.0" targetFramework="net462" />
</packages>
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -34,6 +34,7 @@
@import "job-editor.less";
@import "scada.less";
@import "report.less";
@import "tooltip.less";
@background-color: rgb(216, 216, 216);
@handle-width: 48px;
@@ -209,7 +210,7 @@ body {
width: @spinner-loading-height;
height: @spinner-loading-width;
top: calc(~'50%' - @spinner-loading-height /2);
left: calc(~'50%' - @spinner-loading-width /2);
left: calc(~'50%' - @spinner-loading-width /2);
text-align: center;
line-height: @spinner-loading-height;
font-size: @spinner-loading-height/2;
@@ -0,0 +1,116 @@
// out: false, sourceMap: false, main: ../style.less
@import "colors.less";
.tooltip {
display: block !important;
z-index: 10000;
.tooltip-inner {
min-width: 288px;
min-height: 220px;
border-radius: 2px;
border: solid 2px @color-clear-blue;
background: white;
color: @color-greyish-brown;
border-radius: 16px;
padding: 5px 10px 4px;
}
.tooltip-arrow {
width: 0;
height: 0;
border-style: solid;
position: absolute;
margin: 5px;
background: transparent;
z-index: 1;
}
&[x-placement^="top"] {
margin-bottom: 5px;
.tooltip-arrow {
border-width: 5px 5px 0 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
bottom: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
}
&[x-placement^="bottom"] {
margin-top: 5px;
.tooltip-arrow {
border-width: 0 5px 5px 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-top-color: transparent !important;
top: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
}
&[x-placement^="right"] {
margin-left: 5px;
.tooltip-arrow {
border-width: 5px 5px 5px 0;
border-left-color: transparent !important;
border-top-color: transparent !important;
border-bottom-color: transparent !important;
left: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
}
&[x-placement^="left"] {
margin-right: 5px;
.tooltip-arrow {
border-width: 5px 0 5px 5px;
border-top-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
right: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
}
&.popover {
color: #f9f9f9;
.popover-inner {
background: $color;
color: @color-greyish-brown;
padding: 24px;
border-radius: 5px;
box-shadow: 0 5px 30px rgba(0, 0, 0, 0.1);
}
.popover-arrow {
border: solid 2px @color-clear-blue;
}
}
&[aria-hidden='true'] {
visibility: hidden;
opacity: 0;
transition: opacity .15s, visibility .15s;
}
&[aria-hidden='false'] {
visibility: visible;
opacity: 1;
transition: opacity .15s;
}
}
+353 -32
View File
@@ -8640,6 +8640,10 @@ footer .container button.big:before {
line-height: 1.11;
color: #4b4b4b;
}
.card-report-production .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown {
position: relative;
margin-top: 2px;
}
.card-report-production .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown header {
height: 64px;
width: 312px;
@@ -9229,6 +9233,10 @@ footer .container button.big:before {
line-height: 1.11;
color: #4b4b4b;
}
.card-report-events .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown {
position: relative;
margin-top: 2px;
}
.card-report-events .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown header {
height: 64px;
width: 312px;
@@ -9869,6 +9877,10 @@ footer .container button.big:before {
line-height: 1.11;
color: #4b4b4b;
}
.card-report-alarms .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown {
position: relative;
margin-top: 2px;
}
.card-report-alarms .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown header {
height: 64px;
width: 312px;
@@ -10412,7 +10424,6 @@ footer .container button.big:before {
.card-report-timeline .reports-box-body-left .body-left-header-machinestatus > div {
display: flex;
flex-flow: column;
height: 70px;
margin-right: 24px;
}
.card-report-timeline .reports-box-body-left .body-left-header > div label,
@@ -10467,40 +10478,78 @@ footer .container button.big:before {
padding-left: 16px;
border: none;
}
.card-report-timeline .reports-box-body-left .body-left-header .zoom-control,
.card-report-timeline .reports-box-body-left .body-left-header-machinestatus .zoom-control {
display: block;
align-items: center;
justify-content: center;
width: 120px;
float: right;
margin: 0px;
position: absolute;
right: 0px;
top: 11px;
}
.card-report-timeline .reports-box-body-left .body-left-header .zoom-control button,
.card-report-timeline .reports-box-body-left .body-left-header-machinestatus .zoom-control button {
width: 48px;
height: 48px;
border-radius: 2px;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.4);
background-image: linear-gradient(to bottom, #f1f1f1, #bbbcbc);
border: none;
}
.card-report-timeline .reports-box-body-left .body-left-header .zoom-control button:first-child,
.card-report-timeline .reports-box-body-left .body-left-header-machinestatus .zoom-control button:first-child {
margin-right: 16px;
}
.card-report-timeline .reports-box-body-left .body-left-header .zoom-control button:active,
.card-report-timeline .reports-box-body-left .body-left-header-machinestatus .zoom-control button:active {
width: 48px;
height: 48px;
border-radius: 2px;
box-shadow: inset 0 1px 3px 0 rgba(0, 0, 0, 0.4);
background-image: linear-gradient(to bottom, #bbbcbc, #f1f1f1);
border: none;
}
.card-report-timeline .reports-box-body-left .body-left-center {
width: 1448px;
max-height: 681px;
display: flex;
flex-flow: column;
border: solid 1px #dddddd;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header {
width: 100%;
height: 104px;
display: flex;
flex-flow: row;
flex: 1 1 auto;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left {
width: 360px;
height: 616px;
height: 100%;
display: flex;
flex-flow: column;
align-items: center;
border: solid 1px #dddddd;
overflow-y: auto;
border-right: solid 1px #dddddd;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .multiselect {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .multiselect {
z-index: 100;
margin-bottom: 24px;
margin-top: 16px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .multiselect label {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .multiselect label {
font-size: 14px;
line-height: 1.29;
color: #878787;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .selectBox {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .selectBox {
position: relative;
width: 328px;
height: 64px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .selectBox select {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .selectBox select {
width: 100%;
padding: 8px;
cursor: pointer;
@@ -10511,37 +10560,38 @@ footer .container button.big:before {
margin-bottom: 0;
margin-top: 0;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .selectBox select option {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .selectBox select option {
display: none;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .overSelect {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .overSelect {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .checkboxes {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .checkboxes {
display: none;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .checkboxesView {
width: calc(100% - 8px);
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .checkboxesView {
position: absolute;
width: 320px;
background-color: #fff;
display: block;
z-index: 100;
padding: 6px 4px;
box-shadow: 0 3px 5px 0 rgba(0, 0, 0, 0.4);
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .checkboxesView label {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .checkboxesView label {
font-size: 18px;
margin: 2px;
display: flex;
flex-flow: row;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .checkboxesView .label-state {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left .checkboxesView .label-state {
margin-left: 12px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div select {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-left div select {
width: 328px;
height: 48px;
border-radius: 2px;
@@ -10553,7 +10603,124 @@ footer .container button.big:before {
line-height: 1.11;
color: #4b4b4b;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown header {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right {
width: 1088px;
height: 100%;
display: block;
position: relative;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header {
width: 100%;
height: 100%;
position: relative;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .timeline-chart-header-title {
width: 100%;
height: 20px;
font-size: 18px;
font-weight: 600;
font-style: normal;
font-stretch: normal;
line-height: 1.11;
letter-spacing: normal;
text-align: center;
color: #4b4b4b;
position: absolute;
top: 24px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .timeline-chart-header-items {
display: flex;
flex-flow: row;
flex-wrap: nowrap;
width: 100%;
height: 100%;
text-align: center;
vertical-align: bottom;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .timeline-chart-header-items .timeline-chart-header-item {
flex: 1 1 auto;
font-size: 12px;
font-weight: normal;
font-style: normal;
font-stretch: normal;
line-height: 1.43;
letter-spacing: normal;
text-align: center;
color: #4b4b4b;
overflow: hidden;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .timeline-chart-header-items .timeline-chart-header-item:first-child {
border-right: solid 1px #dddddd;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .timeline-chart-header-items .timeline-chart-header-item:last-child {
border-left: solid 1px #dddddd;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .timeline-chart-header-items .timeline-chart-header-item label {
position: relative;
line-height: 164px;
display: block;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .timeline-chart-header-items .timeline-chart-header-item label.rotate {
-webkit-transform: rotate(-78deg);
-moz-transform: rotate(-78deg);
-ms-transform: rotate(-78deg);
-o-transform: rotate(-78deg);
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .cursone-gantt {
width: 30px;
height: 618px;
position: absolute;
top: 52px;
margin-left: -15px;
z-index: 100;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .cursone-gantt .oval {
width: 30px;
border-radius: 2px;
color: #002680;
cursor: e-resize;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .cursone-gantt .oval svg {
width: 30px;
height: 30px;
fill: #002680;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .cursone-gantt .line {
width: 2px;
height: 576px;
border-left: solid 4px #002680;
margin-bottom: 4px;
margin-left: 13px;
cursor: e-resize;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .cursone-gantt.active .oval {
background-color: #004990;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-header .body-left-center-right .timeline-chart-header .cursone-gantt.active .line {
border-color: #004990;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container {
width: 100%;
height: 508px;
display: flex;
flex-flow: row;
overflow-x: hidden;
flex: 1 1 auto;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left {
width: 360px;
height: 100%;
display: flex;
flex-flow: column;
align-items: center;
border-right: solid 1px #dddddd;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown {
position: relative;
margin-top: 2px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown header {
height: 64px;
width: 312px;
border-radius: 2px;
@@ -10567,60 +10734,114 @@ footer .container button.big:before {
padding-left: 16px;
cursor: pointer;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown header span {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown header span {
width: 100%;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown header .expander {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown header .expander {
margin: 0 12px;
line-height: 28px;
height: 28px;
width: 28px;
font-size: 28px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown header .row-chart {
position: absolute;
top: 0px;
left: 345px;
width: 1087px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown header .row-chart .timeline-chart-row {
width: 100%;
height: 64px;
background-color: #ddd;
position: relative;
overflow: hidden;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown header .row-chart .timeline-chart-row .timeline-chart-row-item {
background-color: #76baf7;
position: absolute;
top: 8px;
bottom: 8px;
left: 10%;
right: 50%;
border-radius: 2px;
height: 48px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section {
width: 328px;
min-height: 0;
max-height: 0;
transition: max-height 100ms ease-in-out, min-height 200ms ease-in-out;
overflow: hidden;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section.expanded {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section.expanded {
min-height: 64px;
background-color: rgba(255, 255, 255, 0.1);
max-height: 1000px;
overflow: visible;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section .item {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .item {
height: 64px;
width: 100%;
line-height: 64px;
background-color: #f1f1f1;
position: relative;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section .dropdown {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown {
height: 100%;
margin-top: 2px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section .dropdown .filename {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown .filename {
display: flex;
height: 64px;
align-items: center;
cursor: pointer;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section .dropdown .filename i {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown .filename i {
color: #002e6e;
margin: 0 20px 0 20px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section .dropdown .filename span {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown .filename span {
width: 100%;
font-size: 18px;
line-height: 1;
color: #002680;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section .dropdown .filename.selected span,
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section .dropdown .filename.selected i {
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown .filename.selected {
background-color: rgba(255, 255, 255, 0.8);
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown .filename.selected span,
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown .filename.selected i {
color: #4b4b4b;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left div .accordion-dropdown section .dropdown .filename.selected {
background-color: rgba(255, 255, 255, 0.8);
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown .row-chart {
position: absolute;
top: 0px;
left: 345px;
width: 1087px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown .row-chart .timeline-chart-row {
width: 100%;
height: 64px;
background-color: #ddd;
position: relative;
overflow: hidden;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-left .accordion-dropdown section .dropdown .row-chart .timeline-chart-row .timeline-chart-row-item {
background-color: #76baf7;
position: absolute;
top: 8px;
bottom: 8px;
left: 10%;
right: 50%;
border-radius: 2px;
height: 48px;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-container .body-left-center-right {
width: 1088px;
height: 100%;
display: block;
position: relative;
}
.card-report-timeline .reports-box-body-left .body-left-center .body-left-center-footer {
height: 64px;
@@ -11112,6 +11333,8 @@ footer .container button.big:before {
color: @color-greyish-brown;
}
.accordion-dropdown{
position: relative;
margin-top: 2px;
header {
height: 64px;
width: 312px;
@@ -18422,6 +18645,104 @@ footer .container button.big:before {
display: flex;
flex-flow: row;
}
.tooltip {
display: block !important;
z-index: 10000;
}
.tooltip .tooltip-inner {
min-width: 288px;
min-height: 220px;
border-radius: 2px;
border: solid 2px #1791ff;
background: white;
color: #4b4b4b;
border-radius: 16px;
padding: 5px 10px 4px;
}
.tooltip .tooltip-arrow {
width: 0;
height: 0;
border-style: solid;
position: absolute;
margin: 5px;
background: transparent;
z-index: 1;
}
.tooltip[x-placement^="top"] {
margin-bottom: 5px;
}
.tooltip[x-placement^="top"] .tooltip-arrow {
border-width: 5px 5px 0 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
bottom: -5px;
left: calc(45%);
margin-top: 0;
margin-bottom: 0;
}
.tooltip[x-placement^="bottom"] {
margin-top: 5px;
}
.tooltip[x-placement^="bottom"] .tooltip-arrow {
border-width: 0 5px 5px 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-top-color: transparent !important;
top: -5px;
left: calc(45%);
margin-top: 0;
margin-bottom: 0;
}
.tooltip[x-placement^="right"] {
margin-left: 5px;
}
.tooltip[x-placement^="right"] .tooltip-arrow {
border-width: 5px 5px 5px 0;
border-left-color: transparent !important;
border-top-color: transparent !important;
border-bottom-color: transparent !important;
left: -5px;
top: calc(45%);
margin-left: 0;
margin-right: 0;
}
.tooltip[x-placement^="left"] {
margin-right: 5px;
}
.tooltip[x-placement^="left"] .tooltip-arrow {
border-width: 5px 0 5px 5px;
border-top-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
right: -5px;
top: calc(45%);
margin-left: 0;
margin-right: 0;
}
.tooltip.popover {
color: #f9f9f9;
}
.tooltip.popover .popover-inner {
background: $color;
color: #4b4b4b;
padding: 24px;
border-radius: 5px;
box-shadow: 0 5px 30px rgba(0, 0, 0, 0.1);
}
.tooltip.popover .popover-arrow {
border: solid 2px #1791ff;
}
.tooltip[aria-hidden='true'] {
visibility: hidden;
opacity: 0;
transition: opacity .15s, visibility .15s;
}
.tooltip[aria-hidden='false'] {
visibility: visible;
opacity: 1;
transition: opacity .15s;
}
a,
a:visited,
a:hover,
+63 -62
View File
@@ -1,64 +1,65 @@
{
"name": "step",
"version": "1.0.0",
"description": "step",
"author": "Paolo Possanzini <paolo@teamdev.it>",
"private": true,
"scripts": {
"build": "webpack",
"dev": "webpack --watch"
},
"dependencies": {
"axios": "0.17.1",
"brace": "0.11.1",
"chart.js": "^2.7.3",
"izitoast": "1.2.0",
"justgage": "^1.2.2",
"moment": "2.20.1",
"raphael": "^2.2.7",
"sprintf-js": "1.1.1",
"vee-validate": "2.0.3",
"vue": "^2.5.2",
"vue-chartjs": "^3.4.0",
"vue-class-component": "6.1.0",
"vue-drag-drop": "1.1.0",
"vue-property-decorator": "6.0.0",
"vue-router": "^3.0.1",
"vue-smooth-dnd": "0.2.1",
"vue2-ace-editor": "0.0.11",
"vue2-datepicker": "2.6.2",
"vuex": "3.0.1"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.0.0",
"babel-loader": "7.1.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-runtime": "^6.0.0",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.0.0",
"babel-preset-stage-2": "^6.0.0",
"babel-runtime": "^6.0.0",
"babelify": "^7.2.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.0",
"eventsource-polyfill": "^0.9.6",
"file-loader": "^1.1.4",
"url-loader": "^0.5.8",
"ts-loader": "3.1.1",
"typescript": "2.6.1",
"vue-loader": "^13.3.0",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
"name": "step",
"version": "1.0.0",
"description": "step",
"author": "Paolo Possanzini <paolo@teamdev.it>",
"private": true,
"scripts": {
"build": "webpack",
"dev": "webpack --watch"
},
"dependencies": {
"axios": "0.17.1",
"brace": "0.11.1",
"chart.js": "^2.7.3",
"izitoast": "1.2.0",
"justgage": "^1.2.2",
"moment": "2.20.1",
"raphael": "^2.2.7",
"sprintf-js": "1.1.1",
"v-tooltip": "^2.0.0-rc.33",
"vee-validate": "2.0.3",
"vue": "^2.5.2",
"vue-chartjs": "^3.4.0",
"vue-class-component": "6.1.0",
"vue-drag-drop": "1.1.0",
"vue-property-decorator": "6.0.0",
"vue-router": "^3.0.1",
"vue-smooth-dnd": "0.2.1",
"vue2-ace-editor": "0.0.11",
"vue2-datepicker": "2.6.2",
"vuex": "3.0.1"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.0.0",
"babel-loader": "7.1.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-runtime": "^6.0.0",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.0.0",
"babel-preset-stage-2": "^6.0.0",
"babel-runtime": "^6.0.0",
"babelify": "^7.2.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.0",
"eventsource-polyfill": "^0.9.6",
"file-loader": "^1.1.4",
"url-loader": "^0.5.8",
"ts-loader": "3.1.1",
"typescript": "2.6.1",
"vue-loader": "^13.3.0",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
+53 -22
View File
@@ -1,26 +1,57 @@
declare module server {
export interface reportData {
absoluteValue: number;
productedPieces: number;
discardedPieces: number;
}
export interface reportData {
absoluteValue: number,
productedPieces: number,
discardedPieces: number
}
export interface pieChartData {
stop: number;
run: number;
idle: number;
}
export interface pieChartData {
stop: number,
run: number,
idle: number
}
export interface programTableData {
progName: string;
quantity: number;
startDate: Date;
endDate: Date;
actualT: string;
averageT: string;
theoricT: string;
deviation: string;
frequency: number;
}
export interface programTableData {
progName: string,
quantity: number,
startDate: Date,
endDate: Date,
actualT: string,
averageT: string,
theoricT: string,
deviation: string,
frequency: number
}
}
export interface timeLineChartData {
partPrgs: timeLineChartProduzione[];
statusData: timeLineChartStatoMacchina;
}
export interface timeLineChartProduzione {
name: string;
executed: string;
frequency: string;
occurrences: timeLineChartTask[];
}
export interface timeLineChartStatoMacchina {
run: timeLineChartTask[];
idle: timeLineChartTask[];
stop: timeLineChartTask[];
}
export interface timeLineChartTask {
from: string;
to: string;
}
export interface timeLineChartItem {
name: string;
executed: string;
frequency: string;
color: string
from: string,
to: string
}
}
@@ -1,53 +1,150 @@
import Vue from "vue";
import Component from "vue-class-component";
import { cardReport } from "../../../modules/base-components/cards/index";
import accordionDropdown from "../../../modules/base-components/accordion-dropdown.vue";
import modalReportSelectColumn from "../../../modules/base-components/modal-report-select-column.vue";
import { Accordion } from "src/modules/base-components";
import { loginService } from "src/services";
import { Component, Watch } from "vue-property-decorator";
import { cardReport } from "src/modules/base-components/cards/index";
import accordionDropdown from "src/modules/base-components/accordion-dropdown.vue";
import DatePicker from "vue2-datepicker";
import moment from "moment";
import { ModalHelper } from "src/components/modals";
import { ReportGetters } from "../../../store/report.store";
import { Watch } from "vue-property-decorator";
import { ReportGetters } from "src/store/report.store";
import { reportService } from "src/services/reportService";
import { TimeLineChartHeader, TimeLineChartRow } from "src/components/timeline-chart";
declare let $: any;
declare var JustGage: any;
@Component({ components: { datePicker: DatePicker, cardReport: cardReport, accordionDropdown: accordionDropdown } })
@Component({
components: {
datePicker: DatePicker,
cardReport: cardReport,
accordionDropdown: accordionDropdown,
"timeline-chart-row": TimeLineChartRow,
"timeline-chart-header": TimeLineChartHeader
}
})
export default class CardReportTimeline extends Vue {
lang = {
days: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
pickers: ['next 7 days', 'next 30 days', 'previous 7 days', 'previous 30 days'],
days: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
months: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
pickers: [
"next 7 days",
"next 30 days",
"previous 7 days",
"previous 30 days"
],
placeholder: {
date: 'Select Date',
dateRange: 'Select Date Range'
date: "Select Date",
dateRange: "Select Date Range"
}
}
};
get dataPieces() : server.reportData{
return (this.$store.getters as ReportGetters).getReportData();
}
occurrences: any = {
machine_status: {
total: [] as server.timeLineChartItem[],
run: [] as server.timeLineChartItem[],
idle: [] as server.timeLineChartItem[],
stop: [] as server.timeLineChartItem[]
},
programs: {
total: [] as server.timeLineChartItem[],
items: [] as server.timeLineChartItem[]
}
};
private defaultStartDate: Date = new Date(2019, 0, 1); //new Date(new Date().setDate(new Date().getDate() - 6));
private defaultEndDate: Date = new Date(2019, 0, 31); //new Date(new Date().setDate(new Date().getDate() + 1));
filter: {
interval?: Date[],
timelineMacro: Array<string>,
interval?: Date[];
timelineMacro: Array<string>;
currentTime: Date;
} = {
timelineMacro: ["Allarmi", "Stato macchina", "Programmi"],
interval: [new Date(new Date().setDate(new Date().getDate() - 6)), new Date(new Date().setDate(new Date().getDate() + 1))]
timelineMacro: ["Stato macchina", "Programmi"],
interval: [],
currentTime: null
};
interval: {
date?: Date[];
startTime: Date;
endTime: Date;
} = {
date: [new Date(2019, 0, 1), new Date(2019, 0, 31)],
startTime: null,
endTime: null,
};
filterName: string = "";
public searchText: string = "";
async mounted() {
this.filterIntervalChange(this.interval.date, null);
this.buildGage();
await this.getData();
}
@Watch("searchText")
public applyFilter(n) {
this.filterName = n.toLowerCase();
}
mounted() {
this.buildGage();
@Watch("interval.date", { immediate: true })
public filterIntervalChange(n: Date[], o: Date[]) {
if(!n || (n && n.length < 0))
{
this.interval.date = [this.defaultStartDate, this.defaultEndDate]
return;
}
if(n && n.length > 0 && n !== o)
{
// let startDate = n[0];
// let endDate = new Date(n[1].setHours(23, 59, 59));
// this.filter.interval = [startDate, endDate];
this.filter.interval = this.interval.date;
this.filter.currentTime = new Date((this.filter.interval[1].getTime() + this.filter.interval[0].getTime()) / 2);
return;
}
}
get dataPieces(): server.reportData {
return (this.$store.getters as ReportGetters).getReportData();
}
oneDay: number = 24 * 60 * 60 * 1000;
get diffDays(): number {
return Math.round(Math.abs((this.interval.date[1].getTime() - this.interval.date[0].getTime()) / this.oneDay)
);
}
handleZoomIn(){
let interval = (this.interval.date[1].getTime() - this.interval.date[0].getTime()) / 2;
this.setZoom(interval)
}
handleZoomOut(){
let interval = (this.interval.date[1].getTime() - this.interval.date[0].getTime()) * 2;
this.setZoom(interval);
}
private setZoom(interval){
let middle = (interval / 2);
let start = new Date(this.filter.currentTime.getTime() - middle);
let end = new Date(this.filter.currentTime.getTime() + middle);
this.interval.date = [start, end];
}
buildGage() {
@@ -59,15 +156,93 @@ export default class CardReportTimeline extends Vue {
});
}
isVisible(value){
async getData() {
let occurrences = await reportService.TimeLine(this.filter.interval.map(x => x.toString()));
this.occurrences = {
machine_status: {
total: [] as server.timeLineChartItem[],
run: [] as server.timeLineChartItem[],
idle: [] as server.timeLineChartItem[],
stop: [] as server.timeLineChartItem[]
},
programs: {
total: [] as server.timeLineChartItem[],
items: [] as server.timeLineChartItem[]
}
};
(
(occurrences.statusData || ({} as server.timeLineChartStatoMacchina))
.run || ([] as server.timeLineChartTask[])
).forEach(m => {
let elem = {
from: m.from,
to: m.to,
name: "run",
color: "#7ed321"
} as server.timeLineChartItem;
this.occurrences.machine_status.run.push(elem);
this.occurrences.machine_status.total.push(elem);
});
(
(occurrences.statusData || ({} as server.timeLineChartStatoMacchina))
.idle || ([] as server.timeLineChartTask[])
).forEach(m => {
let elem = {
from: m.from,
to: m.to,
name: "idle",
color: "#e3d300"
} as server.timeLineChartItem;
this.occurrences.machine_status.idle.push(elem);
this.occurrences.machine_status.total.push(elem);
});
(
(occurrences.statusData || ({} as server.timeLineChartStatoMacchina))
.stop || ([] as server.timeLineChartTask[])
).forEach(m => {
let elem = {
from: m.from,
to: m.to,
name: "stop",
color: "#ff4a60"
} as server.timeLineChartItem;
this.occurrences.machine_status.stop.push(elem);
this.occurrences.machine_status.total.push(elem);
});
(occurrences.partPrgs || ([] as server.timeLineChartProduzione[])).forEach(
item => {
let elem = {
name: item.name,
occurrences: [] as server.timeLineChartItem[]
};
item.occurrences.forEach(m => {
let oc = {
from: m.from,
to: m.to,
name: item.name,
frequency: item.frequency,
executed: item.executed,
color: "#76baf7"
} as server.timeLineChartItem;
elem.occurrences.push(oc);
this.occurrences.programs.total.push(oc);
});
this.occurrences.programs.items.push(elem);
}
);
}
isVisible(value) {
return this.filter.timelineMacro.some(c => c == value);
}
public openSelectState() {
if (!$('.checkboxes').hasClass('checkboxesView'))
$('.checkboxes').addClass('checkboxesView');
else
$('.checkboxes').removeClass('checkboxesView');
if (!$(".checkboxes").hasClass("checkboxesView"))
$(".checkboxes").addClass("checkboxesView");
else $(".checkboxes").removeClass("checkboxesView");
}
}
@@ -1,153 +1,191 @@
<template>
<div class="card-report-timeline">
<div class="reports-box-body-left">
<div class="body-left-header">
<div>
<label class="intervaldate">{{'reports_body_header_date_range' | localize("Intervallo date")}}</label>
<date-picker v-model="filter.interval" range type="daterange" :lang="lang"></date-picker>
<div class="reports-box-body-left">
<div class="body-left-header">
<div>
<label class="intervaldate">{{'reports_body_header_date_range' | localize("Intervallo date")}}</label>
<date-picker v-model="interval.date" range type="daterange" :lang="lang"></date-picker>
</div>
<div>
<label>{{'reports_body_header_label_hour' | localize("Intervallo orario")}}</label>
<div class="interval-time">
<input type="time" v-model="interval.startTime" />
<input type="time" v-model="interval.endTime"/>
</div>
</div>
<div>
<label>{{'reports_body_header_label_program' | localize("Programma")}}</label>
<input type="text" class="program" v-model="searchText" :placeholder="'reports_body_header_placeholder_program' | localize('Nome del programma')" />
</div>
<div class="zoom-control">
<button @click="handleZoomOut()"
:disabled="((interval.date[1].getFullYear() - interval.date[0].getFullYear()) >= 2)">
<i class="fa fa-search-minus fa-2x"></i></button>
<button @click="handleZoomIn()"
:disabled="((interval.date[1].getTime() - interval.date[0].getTime()) <= oneDay && diffDays == 0)">
<i class="fa fa-search-plus fa-2x"></i></button>
</div>
</div>
<div class="body-left-center">
<div class="body-left-center-header">
<div class="body-left-center-left">
<div class="multiselect">
<div class="selectBox" @click="openSelectState()">
<select id="selectListCheckboxes">
<option>
<span v-for="(item, index) in filter.timelineMacro" :key="item" >
{{'report_state_'+item | localize(item)}}{{(index==filter.timelineMacro.length-1)?'':', '}}
</span>
</option>
<div class="overSelect"></div>
</select>
</div>
<!-- <div>
<label>{{'reports_body_header_label_hour' | localize("Intervallo orario")}}</label>
<div class="interval-time">
<input type="time"/>
<input type="time"/>
<div class="checkboxes">
<div>
<label for="Stato macchina">
<div class="custom-checkbox">
<input type="checkbox" v-model="filter.timelineMacro" value="Stato macchina" id="Stato macchina" />
<label for="Stato macchina"></label>
</div>
<label class="label-state">{{'report_timeline_filter_machine_status' | localize("Stato macchina")}}</label>
</label>
</div>
<div>
<label for="Programmi">
<div class="custom-checkbox">
<input type="checkbox" v-model="filter.timelineMacro" value="Programmi" id="Programmi" />
<label for="Programmi"></label>
</div>
<label class="label-state">{{'report_timeline_filter_programs' | localize("Programmi")}}</label>
</label>
</div>
</div> -->
<div>
<label>{{'reports_body_header_label_program' | localize("Programma")}}</label>
<input type="text" class="program" v-model="searchText" :placeholder="'reports_body_header_placeholder_program' | localize('Nome del programma')" />
</div>
</div>
<div class="body-left-center">
<div class="body-left-center-container">
<div class="body-left-center-left">
<div class="multiselect">
<div class="selectBox" @click="openSelectState()">
<select id="selectListCheckboxes">
<option><span v-for="(item, index) in filter.timelineMacro" :key="item" >{{'report_state_'+item | localize(item)}}{{(index==filter.timelineMacro.length-1)?'':', '}}</span></option>
<div class="overSelect"></div>
</select>
</div>
<div class="checkboxes">
<!-- <div>
<label for="Eventi">
<div class="custom-checkbox">
<input type="checkbox" v-model="filter.timelineMacro" value="Eventi" id="Eventi" />
<label for="Eventi"></label>
</div>
<label class="label-state">{{'report_timeline_filter_events' | localize("Eventi")}}</label>
</label>
</div> -->
<div>
<label for="Allarmi">
<div class="custom-checkbox">
<input type="checkbox" v-model="filter.timelineMacro" value="Allarmi" id="Allarmi" />
<label for="Allarmi"></label>
</div>
<label class="label-state">{{'report_timeline_filter_alarms' | localize("Allarmi")}}</label>
</label>
</div>
<div>
<label for="Stato macchina">
<div class="custom-checkbox">
<input type="checkbox" v-model="filter.timelineMacro" value="Stato macchina" id="Stato macchina" />
<label for="Stato macchina"></label>
</div>
<label class="label-state">{{'report_timeline_filter_machine_status' | localize("Stato macchina")}}</label>
</label>
</div>
<div>
<label for="Programmi">
<div class="custom-checkbox">
<input type="checkbox" v-model="filter.timelineMacro" value="Programmi" id="Programmi" />
<label for="Programmi"></label>
</div>
<label class="label-state">{{'report_timeline_filter_programs' | localize("Programmi")}}</label>
</label>
</div>
</div>
</div>
<div v-if="isVisible('Eventi')">
<accordion-dropdown :title="'reports_body_left_center_left_dropdown_title_events' | localize('Eventi')">
<div class="dropdown">
<div class="item">
<div class="filename"><i class="fa fa-file"></i><span>Test</span></div>
</div>
</div>
</accordion-dropdown>
</div>
<div v-if="isVisible('Allarmi')">
<accordion-dropdown :title="'reports_body_left_center_left_dropdown_title_alarms' | localize('Allarmi')">
<div class="dropdown">
<div class="item">
<div class="filename"><i class="fa fa-file"></i><span>Test</span></div>
</div>
</div>
</accordion-dropdown>
</div>
<div v-if="isVisible('Stato macchina')">
<accordion-dropdown :title="'reports_body_left_center_left_dropdown_title_machine_status' | localize('Stato macchina')">
<div class="dropdown">
<div class="item">
<div class="filename"><i class="fa fa-file"></i><span>Test</span></div>
</div>
</div>
</accordion-dropdown>
</div>
<div v-if="isVisible('Programmi')">
<accordion-dropdown :title="'reports_body_left_center_left_dropdown_title_programs' | localize('Programmi')">
<div class="dropdown">
<div class="item">
<div class="filename"><i class="fa fa-file"></i><span>Test</span></div>
</div>
</div>
</accordion-dropdown>
</div>
</div>
<div class="body-left-center-right">
</div>
</div>
<div class="body-left-center-footer">
<div class="header-title">
<div class="title">
{{'reports_body_left_center_footer_title_time_slider' | localize('Cursore temporale')}}
</div>
<div class="data-temporal">
09 Aprile 2017 - 23:14
</div>
</div>
</div>
<div class="body-left-center-right">
<timeline-chart-header v-if="filter.interval.length == 2" v-model="filter.currentTime"
:start="filter.interval[0]"
:end="filter.interval[1]"
:interval="40"
show-cursor></timeline-chart-header>
</div>
</div>
<div class="body-left-center-container">
<div class="body-left-center-left">
<div v-if="isVisible('Stato macchina')">
<accordion-dropdown>
<template slot="header">
<span>{{'reports_body_left_center_left_dropdown_title_machine_status' | localize('Stato macchina')}}</span>
<div class="row-chart">
<timeline-chart-row v-if="filter.interval.length == 2 && occurrences.machine_status.total.length > 0"
:start="filter.interval[0]"
:end="filter.interval[1]"
:occurrences="occurrences.machine_status.total"></timeline-chart-row>
</div>
</div>
</template>
<div class="dropdown">
<div class="item">
<div class="filename"><i class="fa fa-file"></i><span>run</span></div>
<div class="row-chart">
<timeline-chart-row v-if="filter.interval.length == 2 && occurrences.machine_status.run.length > 0"
:start="filter.interval[0]"
:end="filter.interval[1]"
:occurrences="occurrences.machine_status.run"
:color="'#7ed321'"></timeline-chart-row>
</div>
</div>
</div>
<div class="dropdown">
<div class="item">
<div class="filename"><i class="fa fa-file"></i><span>idle</span></div>
<div class="row-chart">
<timeline-chart-row v-if="filter.interval.length == 2 && occurrences.machine_status.idle.length > 0"
:start="filter.interval[0]"
:end="filter.interval[1]"
:occurrences="occurrences.machine_status.idle"
:color="'#e3d300'"></timeline-chart-row>
</div>
</div>
</div>
<div class="dropdown">
<div class="item">
<div class="filename"><i class="fa fa-file"></i><span>stop</span></div>
<div class="row-chart">
<timeline-chart-row v-if="filter.interval.length == 2 && occurrences.machine_status.stop.length > 0"
:start="filter.interval[0]"
:end="filter.interval[1]"
:occurrences="occurrences.machine_status.stop"
:color="'#ff4a60'"></timeline-chart-row>
</div>
</div>
</div>
</accordion-dropdown>
</div>
<div v-if="isVisible('Programmi')">
<accordion-dropdown>
<template slot="header">
<span>{{'reports_body_left_center_left_dropdown_title_programs' | localize('Programmi')}}</span>
<div class="row-chart">
<timeline-chart-row v-if="filter.interval.length == 2 && occurrences.programs.total.length > 0"
:start="filter.interval[0]"
:end="filter.interval[1]"
:occurrences="occurrences.programs.total"></timeline-chart-row>
</div>
</template>
<div class="dropdown" v-for="(item, index) in occurrences.programs.items" :key="index">
<div class="item">
<div class="filename"><i class="fa fa-file"></i><span>{{item.name}}</span></div>
<div class="row-chart">
<timeline-chart-row v-if="filter.interval.length == 2 && item.occurrences && item.occurrences.length > 0"
:start="filter.interval[0]"
:end="filter.interval[1]"
:occurrences="item.occurrences"></timeline-chart-row>
</div>
</div>
</div>
</accordion-dropdown>
</div>
</div>
<!-- <div class="body-left-center-right"></div> -->
</div>
<div class="body-left-center-footer">
<div class="header-title">
<div class="title">
{{'reports_body_left_center_footer_title_time_slider' | localize('Cursore temporale')}}
</div>
<div class="data-temporal">
{{filter.currentTime | date("DD MMMM YYYY - HH:mm")}}
</div>
</div>
<div class="reports-box-body-right">
<div class="body-right-header">
<div class="body-right-header-right">
<button><i class="fa fa-print fa-2x"></i></button>
<button><i class="fa fa-upload fa-2x"></i></button>
</div>
</div>
<div class="body-right-card">
<card-report :title="'Valore assoluto (%)'">
<div id="gauge" class="gauge"></div>
</card-report>
<card-report :title="'Valore assoluto'">
<div class="rectangle_gray">
<label>{{'reports_body_rectangle_label_pieces produced' | localize("Pezzi prodotti")}}</label>
<!-- <span>10.000</span> -->
<span>{{dataPieces.productedPieces}}</span>
</div>
</card-report>
<card-report :title="'Valore assoluto'">
<div class="rectangle_gray">
<label>{{'reports_body_rectangle_label_discarded_pieces' | localize("Pezzi scartati")}}</label>
<span>{{dataPieces.discardedPieces}}</span>
</div>
</card-report>
</div>
</div>
</div>
</div>
</div>
<div class="reports-box-body-right">
<div class="body-right-header">
<div class="body-right-header-right">
<button><i class="fa fa-print fa-2x"></i></button>
<button><i class="fa fa-upload fa-2x"></i></button>
</div>
</div>
<div class="body-right-card">
<card-report :title="'Valore assoluto (%)'">
<div id="gauge" class="gauge"></div>
</card-report>
<card-report :title="'Valore assoluto'">
<div class="rectangle_gray">
<label>{{'reports_body_rectangle_label_pieces produced' | localize("Pezzi prodotti")}}</label>
<span>{{dataPieces.productedPieces}}</span>
</div>
</card-report>
<card-report :title="'Valore assoluto'">
<div class="rectangle_gray">
<label>{{'reports_body_rectangle_label_discarded_pieces' | localize("Pezzi scartati")}}</label>
<span>{{dataPieces.discardedPieces}}</span>
</div>
</card-report>
</div>
</div>
</div>
</template>
<script src="./card-report-timeline.ts" lang="ts"></script>
<script src="./card-report-timeline.ts" lang="ts"></script>
@@ -0,0 +1,7 @@
import TimeLineChartRow from "./timeline-chart-row.vue";
import TimeLineChartHeader from "./timeline-chart-header.vue";
export {
TimeLineChartRow,
TimeLineChartHeader
}
@@ -0,0 +1,228 @@
import Vue from "vue";
import { Component, Prop, Watch } from "vue-property-decorator";
import moment from "moment";
import { Container, Draggable } from "vue-smooth-dnd";
@Component({
components: {
Container,
Draggable
}
})
export default class TimeLineChartRow extends Vue {
@Prop({ required: true })
value: Date;
@Prop({ required: true })
start: Date;
@Prop({ required: true })
end: Date;
@Prop({ required: false, default: 40 })
interval: number;
@Prop({ required: false, default: true })
showCursor: boolean;
current: Date = this.value;
formatter = {
title: "MMMM YYYY",
titleInterval: false,
interval: "DD",
showTime: false
};
isHandlerDragging: boolean = false;
draggingIn: boolean;
draggingPosition: any;
draggingTool: any;
oneHour: number = 60 * 60 * 1000;
oneDay: number = 24 * this.oneHour;
@Watch("value")
valueChange(value) {
this.current = value;
}
get _start(): Date {
let _startTime = this.start.getTime();
let _endTime = this.end.getTime();
let _diffDays = Math.round(Math.abs((_endTime - _startTime) / this.oneDay));
if(_diffDays == 0)
{
_startTime = (new Date(_startTime).setMinutes(0,0));
_endTime = (new Date(_endTime).setMinutes(59,59));
return new Date(_startTime - this.oneHour);
}
_startTime = (new Date(_startTime).setHours(0,0,0));
_endTime = (new Date(_endTime).setHours(23,59,59));
return new Date(_startTime - this.oneDay);
}
get _end(): Date {
let _startTime = this.start.getTime();
let _endTime = this.end.getTime();
let _diffDays = Math.round(Math.abs((_endTime - _startTime) / this.oneDay));
if(_diffDays == 0)
{
_startTime = (new Date(_startTime).setMinutes(0,0));
_endTime = (new Date(_endTime).setMinutes(59,59));
return new Date(_endTime + this.oneHour);
}
_startTime = (new Date(_startTime).setHours(0,0,0));
_endTime = (new Date(_endTime).setHours(23,59,59));
return new Date(_endTime + this.oneDay);
}
get intervals(): Date[] {
this.bindFormatter()
let result: Date[] = [];
let step = this.oneDay;
let diffDays = this.diffDays;
let diffHours = this.diffHours;
if (diffDays <= 1) {
step = this.oneHour;
let check = Math.ceil(diffHours / this.interval);
if (check > 1) step = this.oneHour * check;
}
else {
step = this.oneDay;
let check = Math.ceil(diffDays / this.interval);
if (check > 1) {
step = this.oneDay * check
};
}
let interval = this.startTime;
while (this.endTime >= interval) {
result.push(new Date(interval + (step / 2)));
interval += step;
}
// if (this._end.setHours(0,0,0,0) != result[result.length - 1].getTime())
// result.push(this._end);
return result;
}
get startTime(): number {
return this.parseToUnixTime(this._start);
}
get endTime(): number {
return this.parseToUnixTime(this._end);
}
get diffTime(): number {
return this.endTime - this.startTime;
}
get diffDays(): number {
return Math.round(Math.abs((this._end.getTime() - this._start.getTime()) / this.oneDay)
);
}
get diffHours(): number {
return Math.round(
Math.abs((this._end.getTime() - this._start.getTime()) / this.oneHour)
);
}
get cursorPosition(): number {
return this.unixTimeToPercent(this.current.getTime());
}
private bindFormatter(): any {
let _startTime = this.start.getTime();
let _endTime = this.end.getTime();
let _diffDays = Math.round(Math.abs((_endTime - _startTime) / this.oneDay));
if(_diffDays == 0){
this.formatter.titleInterval = false;
this.formatter.title = "DD MMMM YYYY";
this.formatter.interval = "HH:mm"
this.formatter.showTime = true;
return new Date(_startTime - this.oneHour);
}
else
{
this.formatter.titleInterval = false;
this.formatter.title = "MMMM YYYY";
this.formatter.interval = "DD"
this.formatter.showTime = false;
let _monthDiff = this.monthDiff(this.start, this.end);
if(_monthDiff > 0)
{
this.formatter.titleInterval = true;
this.formatter.title = "MMMM YYYY";
this.formatter.interval = "DD/MM"
this.formatter.showTime = false;
let _yearDiff = this.yearDiff(this.start, this.end);
if(_yearDiff > 0)
{
this.formatter.titleInterval = true;
if(_monthDiff > 3)
{
this.formatter.title = "MMMM YYYY";
this.formatter.interval = "DD/MM/YY"
this.formatter.showTime = false;
}
}
}
}
}
private monthDiff(start: Date, end: Date) : number {
let months = (end.getFullYear() - start.getFullYear()) * 12;
months -= start.getMonth();
months += end.getMonth();
return months <= 0 ? 0 : months;
}
private yearDiff(start: Date, end: Date) : number {
return end.getFullYear() - start.getFullYear();
}
private _moving: boolean = false;
startMove(evt: PointerEvent) {
this._moving = true;
(this.$refs.cursone as HTMLElement).setPointerCapture(evt.pointerId);
}
moving(evt: PointerEvent) {
if (!this._moving) return;
let w = (this.$refs.header as HTMLElement).clientWidth;
let step = this.diffTime / w;
var ct = this.current.getTime() + step * evt.movementX;
let currentDate = new Date(Math.max(Math.min(ct, this.endTime), this.startTime));
this.$emit("input", currentDate);
}
stopMove(evt: PointerEvent) {
this._moving = false;
(this.$refs.cursone as HTMLElement).releasePointerCapture(evt.pointerId);
}
private parseToUnixTime(date: string | Date): number {
if (typeof date === "object") return date.getTime();
if (typeof date === "string") {
let _date = moment(date, "DD/MM/YYYY").toDate();
if (!isNaN(_date.getTime())) return _date.getTime();
}
return 0;
}
private unixTimeToPercent(unixTime: number): number {
return (
((unixTime - this.parseToUnixTime(this._start)) * 100) / this.diffTime
);
}
}
@@ -0,0 +1,32 @@
<template>
<div class="timeline-chart-header" ref="header" >
<div class="timeline-chart-header-title" v-if="formatter.titleInterval">
<small><i>da</i></small> {{this.start | date(formatter.title)}}
<small><i>a</i></small> {{this.end | date(formatter.title)}}
</div>
<div class="timeline-chart-header-title" v-else>{{this.current | date(formatter.title)}}</div>
<div class="timeline-chart-header-items">
<div :class="'timeline-chart-header-item timeline-chart-header-item-' + index" v-for="(interval, index) in intervals" :key="'timeline-chart-header-item-' + index">
<label :class="{'rotate': formatter.interval.length >= 5 && !formatter.showTime}">{{interval | date(formatter.interval)}}</label>
</div>
</div>
<div class="cursone-gantt" ref="cursone"
@pointerdown="startMove"
@pointermove="moving"
@pointerup="stopMove"
:style="{'left': `${cursorPosition}%`}">
<div class="line"></div>
<div class="oval">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="572.8px" height="572.801px" viewBox="0 0 572.8 572.801" style="enable-background:new 0 0 572.8 572.801;"
xml:space="preserve">
<g>
<path d="M520.25,353.6c0,125-100.5,219.201-233.8,219.201S52.55,478.6,52.55,353.6c0-115.3,164.7-301.5,197.7-337.7
c9.3-10.2,22.4-15.9,36.2-15.9s26.9,5.8,36.2,15.9C355.55,52.1,520.25,238.4,520.25,353.6z"/>
</g>
</svg>
</div>
</div>
</div>
</template>
<script src="./timeline-chart-header.ts" lang="ts"></script>
@@ -0,0 +1,91 @@
import Vue from "vue";
import { Component, Prop } from "vue-property-decorator";
import moment from "moment";
@Component({})
export default class TimeLineChartRow extends Vue {
@Prop({required: true})
start: Date;
@Prop({required: true})
end: Date;
@Prop({required: true, default: [] as server.timeLineChartItem[] })
occurrences: server.timeLineChartItem[];
@Prop({required: false, default: "#c9243f"})
color: string;
oneHour: number = 60 * 60 * 1000;
oneDay: number = 24 * this.oneHour;
get tasks(){
return this.occurrences;
}
get _start(): Date {
let _startTime = this.start.getTime();
let _endTime = this.end.getTime();
let _diffDays = Math.round(Math.abs((_endTime - _startTime) / this.oneDay));
if(_diffDays == 0)
return new Date(_startTime - this.oneHour);
_startTime = (new Date(this.start.getTime()).setHours(0,0,0));
_endTime = (new Date(this.end.getTime()).setHours(23,59,59));
return new Date(_startTime - this.oneDay);
}
get _end(): Date {
let _startTime = this.start.getTime();
let _endTime = this.end.getTime();
let _diffDays = Math.round(Math.abs((_endTime - _startTime) / this.oneDay));
if(_diffDays == 0)
return new Date(_endTime + this.oneHour);
_startTime = (new Date(this.start.getTime()).setHours(0,0,0));
_endTime = (new Date(this.end.getTime()).setHours(23,59,59));
return new Date(_endTime + this.oneDay);
}
get diff() : number{
return this.parseDateTime(this._end) - this.parseDateTime(this._start);
}
from(task: server.timeLineChartItem) : number {
let from = this.parseDateTime(task.from);
return this.computes(from);
}
to(task: server.timeLineChartItem) : number {
let to = this.parseDateTime(task.to);
return 100 - this.computes(to);
}
colorOf(task: server.timeLineChartItem) : string {
if(task.color) return task.color;
return this.color;
}
tooltipOf(task: server.timeLineChartItem) : string {
return `${task.name}!`
}
private parseDateTime(date: string | Date) : number
{
if (typeof (date) === "object")
return date.getTime();
if (typeof (date) === "string")
{
let _date = moment(date, "DD/MM/YYYY").toDate();
if (!isNaN(_date.getTime())) return _date.getTime();
}
return 0;
}
private computes(value: number) : number {
return ((value - this.parseDateTime(this._start)) * 100) / this.diff;
}
}
@@ -0,0 +1,18 @@
<template>
<div class="timeline-chart-row">
<div class="timeline-chart-row-item" v-for="(task, index) in tasks" :key="'timeline-chart-row-item-' + index"
:style="{'left': `${from(task)}%`, 'right': `${to(task)}%`, 'background-color': colorOf(task)}"
v-tooltip="{content: 'Tooltip content here', trigger: 'click'}"></div>
<!-- <svg :width="{endOf}" height="64" :viewBox="`0 0 ${endOf} 64`" xmlns="http://www.w3.org/2000/svg" preserveAspectratio="xMinYMin" class="timeline-chart-row">
<g v-for="(task, index) in tasks"
:key="'timeline-chart-row-item-' + index"
:class="'timeline-chart-row-item timeline-chart-row-item-' + index">
<rect :width="`${widthOf(task)}`" height="60" :x="from(task)" :y="2"
:fill="colorOf"
v-tooltip="{content: tooltipOf(task), trigger: 'hover'}"
style="stroke:black;stroke-width:5;" />
</g>
</svg> -->
</div>
</template>
<script src="./timeline-chart-row.ts" lang="ts"></script>
+39 -36
View File
@@ -1,7 +1,7 @@
import Vue from "vue";
import VueRouter from "vue-router";
import VeeValidate from "vee-validate";
import { store, machineStatusActions,machineInfoStore } from "./store";
import { store, machineStatusActions, machineInfoStore } from "./store";
import "./_base/gestures";
import "./app.business-logic";
import "./app.modules";
@@ -13,7 +13,7 @@ import { Factory, MessageService } from "src/_base";
// var JustGage = require("justgage/justgage.js");
const App = () =>
import("./App.vue");
import ("./App.vue");
import { routes } from "./app.routes";
@@ -22,6 +22,9 @@ Vue.use(VueRouter);
Vue.use(VeeValidate); // forms validation for vuejs
// Vue.use(VueGesture);
import VTooltip from 'v-tooltip'
Vue.use(VTooltip)
let router = new VueRouter({ linkActiveClass: "inpath", linkExactActiveClass: "active" });
router.addRoutes(routes);
@@ -31,29 +34,29 @@ let developerMode = true;
// manipulate the title page
router.beforeEach((to, from, next) => {
console.log("Navigate To:", to);
if (to.meta && to.meta.area) {
// Check if area is enabled
if (!developerMode && !machineStatusActions.isAreaEnabled(store, to.meta.area)) {
next({
path: '/'
})
return;
console.log("Navigate To:", to);
if (to.meta && to.meta.area) {
// Check if area is enabled
if (!developerMode && !machineStatusActions.isAreaEnabled(store, to.meta.area)) {
next({
path: '/'
})
return;
}
}
}
if (to.meta && to.meta.title) {
if (to.meta && to.meta.title) {
if (typeof cmsClient == "undefined")
window.document.title = "CMS Active - " + to.meta.title;
else
window.document.title = to.meta.title;
}
if(store.state.machineInfo.canChangePages)
next();
else{
Factory.Get(MessageService).publishToChannel("show-nochange-page");
next(false);
}
if (typeof cmsClient == "undefined")
window.document.title = "CMS Active - " + to.meta.title;
else
window.document.title = to.meta.title;
}
if (store.state.machineInfo.canChangePages)
next();
else {
Factory.Get(MessageService).publishToChannel("show-nochange-page");
next(false);
}
});
@@ -63,10 +66,10 @@ new LocalizationService().init();
let v = new Vue({
router: router,
store,
el: "app",
render: (h) => h(App),
router: router,
store,
el: "app",
render: (h) => h(App),
});
@@ -80,12 +83,12 @@ import "./filters/isValidMixin";
// polyfills !!
if (!String.prototype.format) {
String.prototype.format = function () {
var args = arguments;
return this.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] != 'undefined' ?
args[number] :
match;
});
};
}
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined' ?
args[number] :
match;
});
};
}
@@ -1,8 +1,10 @@
<template>
<div class="accordion-dropdown">
<header @click="toggleExpander()">
<span>{{title}}</span>
<div class="expander" >
<slot name="header">
<span>{{title}}</span>
</slot>
<div class="expander">
<i class="fa fa-caret-down" v-if="!expanded"></i>
<i class="fa fa-caret-up" v-if="expanded"></i>
</div>
+5 -6
View File
@@ -21,13 +21,15 @@ export class ReportService extends baseRestService {
}
async TimeLine(filterInterval: Array<string>): Promise<any> {
async TimeLine(filterInterval: Array<string>): Promise<server.timeLineChartData> {
let filter = {
name: "",
startDate: filterInterval[0],
endDate: filterInterval[1]
}
return await this.Post<any>('/api/report/timeLine',filter,true);
};
let result = await this.Post<server.timeLineChartData>('/api/report/timeLine',filter,true);
reportActions.updateReportTimeLineChart(store, result);
return result;
}
async ProgramsReport(pageSize: number, page: number, name: string, filterInterval: Array<Date>): Promise<any> {
@@ -42,9 +44,6 @@ export class ReportService extends baseRestService {
reportActions.updateReportTableProduction(store,result.occurrences);
return result;
}
}
export const reportService = new ReportService();
+12 -1
View File
@@ -1,19 +1,22 @@
export interface ReportStoreModel {
reportData: server.reportData
reportPieChart: server.pieChartData
reportPieChart: server.pieChartData,
reportTimeLineChart: server.timeLineChartData,
reportTableDataProd: Array<server.programTableData>
}
export interface ReportActions {
updateReportData(context, model: server.reportData);
updateReportPieChart(context, model: server.pieChartData);
updateReportTimeLineChart(context, model: server.timeLineChartData);
updateReportTableProduction(context, model: server.programTableData[]);
}
export interface ReportGetters{
getReportData: () => server.reportData;
getPieChartData: () => server.pieChartData;
getTimeLineChartData: () => server.timeLineChartData;
getProgramsReportProd: () => server.programTableData[];
}
@@ -23,10 +26,12 @@ export const reportStore = {
_reportTableDataProd:new Map < string, server.programTableData > (),
reportData: {absoluteValue:0,discardedPieces:0,productedPieces:0},
reportPieChart: {idle:0,run:0,stop:0},
reportTimeLineChart: {} as server.timeLineChartData,
} as ReportStoreModel,
getters:{
getReportData: (state) => (): server.reportData => (state as ReportStoreModel).reportData,
getPieChartData: (state) => (): server.pieChartData => (state as ReportStoreModel).reportPieChart,
getTimeLineChartData: (state) => (): server.timeLineChartData => (state as ReportStoreModel).reportTimeLineChart,
getProgramsReportProd: (state) => (): Array<server.programTableData> => (state as ReportStoreModel).reportTableDataProd
},
mutations: {
@@ -38,6 +43,9 @@ export const reportStore = {
},
UpdateReportTableProduction(store, model: server.programTableData[]){
store.reportTableDataProd = model;
},
UpdateReportTimeLineChart(store, model: server.timeLineChartData){
store.reportTimeLineChart = model;
}
},
actions: {
@@ -49,6 +57,9 @@ export const reportStore = {
},
updateReportTableProduction(context, model: server.programTableData[]){
context.commit("UpdateReportTableProduction", model);
},
updateReportTimeLineChart(context, model: server.timeLineChartData){
context.commit("UpdateReportTimeLineChart", model);
}
} as ReportActions
}